A local-first private AI assistant for everyday use. Runs on-device models with encrypted P2P sync, and supports sharing chats publicly on ATProto.
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'main' into build/pkg-build-enhancements

authored by

Anandu Pavanan and committed by
GitHub
fb01df5a cb07a37c

+410 -78
+1
.gitignore
··· 8 8 .DS_Store 9 9 pkgroot/ 10 10 *.pkg 11 + pkgroot_models/
+114
Cargo.lock
··· 544 544 checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 545 545 546 546 [[package]] 547 + name = "axum" 548 + version = "0.8.8" 549 + source = "registry+https://github.com/rust-lang/crates.io-index" 550 + checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" 551 + dependencies = [ 552 + "axum-core", 553 + "bytes", 554 + "form_urlencoded", 555 + "futures-util", 556 + "http", 557 + "http-body", 558 + "http-body-util", 559 + "hyper", 560 + "hyper-util", 561 + "itoa", 562 + "matchit", 563 + "memchr", 564 + "mime", 565 + "percent-encoding", 566 + "pin-project-lite", 567 + "serde_core", 568 + "serde_json", 569 + "serde_path_to_error", 570 + "serde_urlencoded", 571 + "sync_wrapper", 572 + "tokio", 573 + "tower", 574 + "tower-layer", 575 + "tower-service", 576 + "tracing", 577 + ] 578 + 579 + [[package]] 580 + name = "axum-core" 581 + version = "0.5.6" 582 + source = "registry+https://github.com/rust-lang/crates.io-index" 583 + checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" 584 + dependencies = [ 585 + "bytes", 586 + "futures-core", 587 + "http", 588 + "http-body", 589 + "http-body-util", 590 + "mime", 591 + "pin-project-lite", 592 + "sync_wrapper", 593 + "tower-layer", 594 + "tower-service", 595 + "tracing", 596 + ] 597 + 598 + [[package]] 547 599 name = "base-x" 548 600 version = "0.2.11" 549 601 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2636 2688 ] 2637 2689 2638 2690 [[package]] 2691 + name = "matchit" 2692 + version = "0.8.4" 2693 + source = "registry+https://github.com/rust-lang/crates.io-index" 2694 + checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" 2695 + 2696 + [[package]] 2639 2697 name = "memchr" 2640 2698 version = "2.8.0" 2641 2699 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3723 3781 checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" 3724 3782 3725 3783 [[package]] 3784 + name = "scc" 3785 + version = "2.4.0" 3786 + source = "registry+https://github.com/rust-lang/crates.io-index" 3787 + checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" 3788 + dependencies = [ 3789 + "sdd", 3790 + ] 3791 + 3792 + [[package]] 3726 3793 name = "schannel" 3727 3794 version = "0.1.28" 3728 3795 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3761 3828 version = "1.2.0" 3762 3829 source = "registry+https://github.com/rust-lang/crates.io-index" 3763 3830 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 3831 + 3832 + [[package]] 3833 + name = "sdd" 3834 + version = "3.0.10" 3835 + source = "registry+https://github.com/rust-lang/crates.io-index" 3836 + checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" 3764 3837 3765 3838 [[package]] 3766 3839 name = "sec1" ··· 3912 3985 ] 3913 3986 3914 3987 [[package]] 3988 + name = "serde_path_to_error" 3989 + version = "0.1.20" 3990 + source = "registry+https://github.com/rust-lang/crates.io-index" 3991 + checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" 3992 + dependencies = [ 3993 + "itoa", 3994 + "serde", 3995 + "serde_core", 3996 + ] 3997 + 3998 + [[package]] 3915 3999 name = "serde_spanned" 3916 4000 version = "1.0.4" 3917 4001 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3933 4017 ] 3934 4018 3935 4019 [[package]] 4020 + name = "serial_test" 4021 + version = "3.4.0" 4022 + source = "registry+https://github.com/rust-lang/crates.io-index" 4023 + checksum = "911bd979bf1070a3f3aa7b691a3b3e9968f339ceeec89e08c280a8a22207a32f" 4024 + dependencies = [ 4025 + "futures-executor", 4026 + "futures-util", 4027 + "log", 4028 + "once_cell", 4029 + "parking_lot", 4030 + "scc", 4031 + "serial_test_derive", 4032 + ] 4033 + 4034 + [[package]] 4035 + name = "serial_test_derive" 4036 + version = "3.4.0" 4037 + source = "registry+https://github.com/rust-lang/crates.io-index" 4038 + checksum = "0a7d91949b85b0d2fb687445e448b40d322b6b3e4af6b44a29b21d9a5f33e6d9" 4039 + dependencies = [ 4040 + "proc-macro2", 4041 + "quote", 4042 + "syn 2.0.117", 4043 + ] 4044 + 4045 + [[package]] 3936 4046 name = "sha2" 3937 4047 version = "0.10.9" 3938 4048 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4259 4369 dependencies = [ 4260 4370 "anyhow", 4261 4371 "async-std", 4372 + "axum", 4262 4373 "clap", 4263 4374 "futures-util", 4264 4375 "hf-hub", ··· 4271 4382 "semver", 4272 4383 "serde", 4273 4384 "serde_json", 4385 + "serial_test", 4274 4386 "tempfile", 4275 4387 "tilekit", 4276 4388 "tokio", ··· 4447 4559 "tokio", 4448 4560 "tower-layer", 4449 4561 "tower-service", 4562 + "tracing", 4450 4563 ] 4451 4564 4452 4565 [[package]] ··· 4485 4598 source = "registry+https://github.com/rust-lang/crates.io-index" 4486 4599 checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" 4487 4600 dependencies = [ 4601 + "log", 4488 4602 "pin-project-lite", 4489 4603 "tracing-attributes", 4490 4604 "tracing-core",
+13 -10
README.md
··· 1 1 <!-- LOGO --> 2 2 <p align="center"> 3 3 <a href="https://github.com/tileshq/"> 4 - <img 5 - src="https://avatars.githubusercontent.com/u/210493283?s=400&u=1ee6e44b6a683b16bdb6e9e853c7ebd8c7fd4268&v=4" 6 - alt="Tiles Logo" 7 - width="128" 8 - /> 4 + <picture> 5 + <source media="(prefers-color-scheme: dark)" srcset="https://avatars.githubusercontent.com/u/210493283?s=400&u=1ee6e44b6a683b16bdb6e9e853c7ebd8c7fd4268&v=4"> 6 + <source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/677d3d63-a9b0-4e92-8c7d-f39ceffc1b0d"> 7 + <img src="https://github.com/user-attachments/assets/677d3d63-a9b0-4e92-8c7d-f39ceffc1b0d" alt="Tiles Logo" width="128"> 8 + </picture> 9 9 </a> 10 10 </p> 11 11 ··· 30 30 31 31 The CLI is the fastest way to get started and will feel familiar if you have used tools like Ollama or LM Studio. 32 32 33 - Install and run: 33 + Install the signed macOS package: 34 + 35 + https://download.tiles.run/tiles-0.4.3-signed.pkg 36 + 37 + Then run: 34 38 35 39 ```bash 36 - curl -fsSL https://tiles.run/install.sh | sh 37 40 tiles 38 41 ``` 39 42 ··· 42 45 Tilekit is a Rust-based SDK for customizing local models and agent experiences within Tiles. 43 46 44 47 It provides: 45 - - A Modelfile specification for defining and sharing models 46 - - Fast, efficient local deployment across consumer platforms 48 + - Modelfile specification and tooling for working with models 49 + - Fast, efficient local deployment of models across consumer platforms 47 50 - Built on open source specifications such as Open Responses API 48 51 - Model composition and chaining, with MIR support currently in development 49 52 ··· 62 65 63 66 Tiles is built for privacy conscious users who want intelligence without renting their memory to centralized providers. 64 67 65 - We are seeking design partners for training workloads that align with our goal of a verifiable privacy perimeter. Contact us at hello@tiles.run. 68 + We are seeking design partners for TEE based cloud workloads that align with our goal of a verifiable privacy perimeter. Contact us at hello@tiles.run. 66 69 67 70 ## Contributing 68 71
+3 -3
server/stack/requirements/app-server/packages-app-server.txt
··· 7 7 charset-normalizer==3.4.5 8 8 click==8.3.1 9 9 fastapi==0.119.0 10 - filelock==3.25.0 10 + filelock==3.25.2 11 11 fsspec==2026.2.0 12 12 h11==0.16.0 13 - hf-xet==1.3.2 13 + hf-xet==1.4.2 14 14 huggingface-hub==0.35.0 15 15 idna==3.11 16 16 jinja2==3.1.6 17 17 markupsafe==3.0.3 18 18 mlx-lm==0.28.3 19 19 mypy-extensions==1.1.0 20 - numpy==2.4.2 20 + numpy==2.4.3 21 21 openai-harmony==0.0.8 22 22 openresponses-types==2.3.0.post1 23 23 packaging==26.0
+2 -2
server/stack/requirements/app-server/pylock.app-server.meta.json
··· 1 1 { 2 2 "lock_input_hash": "sha256:c836d5cfb697330a57241b2b8f275a804178488ec906b19866809ef33c95ba81", 3 3 "lock_version": 1, 4 - "locked_at": "2026-03-08T15:32:49.822954+00:00", 4 + "locked_at": "2026-03-13T17:42:07.680623+00:00", 5 5 "other_inputs_hash": "sha256:63b3c2cfe2ec414938e81dace7aac779c7b902bae681618cd8827e9f16880985", 6 - "requirements_hash": "sha256:579ae09437373494896b65ca902382b680f2d42170dfa57c62618ca7d5d3457a", 6 + "requirements_hash": "sha256:641adc25f61b50b1a2c832d6e2bca50ff879f623e3956bb04a5792ee8679ed57", 7 7 "version_inputs_hash": "sha256:58db986b7cd72eeded675f7c9afd8138fe024fb51451131b5562922bbde3cf43" 8 8 }
+63 -63
server/stack/requirements/app-server/pylock.app-server.toml
··· 138 138 139 139 [[packages]] 140 140 name = "filelock" 141 - version = "3.25.0" 141 + version = "3.25.2" 142 142 index = "https://pypi.org/simple" 143 143 144 144 [[packages.wheels]] 145 - url = "https://files.pythonhosted.org/packages/f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/filelock-3.25.0-py3-none-any.whl" 146 - upload-time = 2026-03-01T15:08:44Z 147 - size = 26427 145 + url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl" 146 + upload-time = 2026-03-11T20:45:37Z 147 + size = 26759 148 148 149 149 [packages.wheels.hashes] 150 - sha256 = "5ccf8069f7948f494968fc0713c10e5c182a9c9d9eef3a636307a20c2490f047" 150 + sha256 = "ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70" 151 151 152 152 [[packages]] 153 153 name = "fsspec" ··· 177 177 178 178 [[packages]] 179 179 name = "hf-xet" 180 - version = "1.3.2" 180 + version = "1.4.2" 181 181 index = "https://pypi.org/simple" 182 182 183 183 [[packages.wheels]] 184 - url = "https://files.pythonhosted.org/packages/35/56/987b0537ddaf88e17192ea09afa8eca853e55f39a4721578be436f8409df/hf_xet-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl" 185 - upload-time = 2026-02-27T17:25:47Z 186 - size = 3521565 184 + url = "https://files.pythonhosted.org/packages/66/d4/b73ebab01cbf60777323b7de9ef05550790451eb5172a220d6b9845385ec/hf_xet-1.4.2-cp313-cp313t-macosx_11_0_arm64.whl" 185 + upload-time = 2026-03-13T06:58:31Z 186 + size = 3555985 187 187 188 188 [packages.wheels.hashes] 189 - sha256 = "c1ae4d3a716afc774e66922f3cac8206bfa707db13f6a7e62dfff74bfc95c9a8" 189 + sha256 = "6d2f8ee39fa9fba9af929f8c0d0482f8ee6e209179ad14a909b6ad78ffcb7c81" 190 190 191 191 [[packages.wheels]] 192 - url = "https://files.pythonhosted.org/packages/a8/5c/7e4a33a3d689f77761156cc34558047569e54af92e4d15a8f493229f6767/hf_xet-1.3.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" 193 - upload-time = 2026-02-27T17:25:40Z 194 - size = 4176494 192 + url = "https://files.pythonhosted.org/packages/ff/e7/ded6d1bd041c3f2bca9e913a0091adfe32371988e047dd3a68a2463c15a2/hf_xet-1.4.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" 193 + upload-time = 2026-03-13T06:58:24Z 194 + size = 4212085 195 195 196 196 [packages.wheels.hashes] 197 - sha256 = "d6dbdf231efac0b9b39adcf12a07f0c030498f9212a18e8c50224d0e84ab803d" 197 + sha256 = "4642a6cf249c09da8c1f87fe50b24b2a3450b235bf8adb55700b52f0ea6e2eb6" 198 198 199 199 [[packages.wheels]] 200 - url = "https://files.pythonhosted.org/packages/e2/e1/3af961f71a40e09bf5ee909842127b6b00f5ab4ee3817599dc0771b79893/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl" 201 - upload-time = 2026-02-27T17:25:58Z 202 - size = 4394161 200 + url = "https://files.pythonhosted.org/packages/21/a6/cbd4188b22abd80ebd0edbb2b3e87f2633e958983519980815fb8314eae5/hf_xet-1.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl" 201 + upload-time = 2026-03-13T06:58:42Z 202 + size = 4428287 203 203 204 204 [packages.wheels.hashes] 205 - sha256 = "35b855024ca37f2dd113ac1c08993e997fbe167b9d61f9ef66d3d4f84015e508" 205 + sha256 = "fca58a2ae4e6f6755cc971ac6fcdf777ea9284d7e540e350bb000813b9a3008d" 206 206 207 207 [[packages.wheels]] 208 - url = "https://files.pythonhosted.org/packages/e4/71/b99aed3823c9d1795e4865cf437d651097356a3f38c7d5877e4ac544b8e4/hf_xet-1.3.2-cp37-abi3-macosx_11_0_arm64.whl" 209 - upload-time = 2026-02-27T17:25:50Z 210 - size = 3526171 208 + url = "https://files.pythonhosted.org/packages/64/2e/af4475c32b4378b0e92a587adb1aa3ec53e3450fd3e5fe0372a874531c00/hf_xet-1.4.2-cp37-abi3-macosx_11_0_arm64.whl" 209 + upload-time = 2026-03-13T06:58:34Z 210 + size = 3559664 211 211 212 212 [packages.wheels.hashes] 213 - sha256 = "a85d3d43743174393afe27835bde0cd146e652b5fcfdbcd624602daef2ef3259" 213 + sha256 = "e9b38d876e94d4bdcf650778d6ebbaa791dd28de08db9736c43faff06ede1b5a" 214 214 215 215 [[packages.wheels]] 216 - url = "https://files.pythonhosted.org/packages/9d/ca/907890ce6ef5598b5920514f255ed0a65f558f820515b18db75a51b2f878/hf_xet-1.3.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" 217 - upload-time = 2026-02-27T17:25:43Z 218 - size = 4180750 216 + url = "https://files.pythonhosted.org/packages/3c/4c/781267da3188db679e601de18112021a5cb16506fe86b246e22c5401a9c4/hf_xet-1.4.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" 217 + upload-time = 2026-03-13T06:58:27Z 218 + size = 4217422 219 219 220 220 [packages.wheels.hashes] 221 - sha256 = "7c2a054a97c44e136b1f7f5a78f12b3efffdf2eed3abc6746fc5ea4b39511633" 221 + sha256 = "77e8c180b7ef12d8a96739a4e1e558847002afe9ea63b6f6358b2271a8bdda1c" 222 222 223 223 [[packages.wheels]] 224 - url = "https://files.pythonhosted.org/packages/00/b3/7bc1ff91d1ac18420b7ad1e169b618b27c00001b96310a89f8a9294fe509/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_x86_64.whl" 225 - upload-time = 2026-02-27T17:26:03Z 226 - size = 4398020 224 + url = "https://files.pythonhosted.org/packages/54/75/07f6aa680575d9646c4167db6407c41340cbe2357f5654c4e72a1b01ca14/hf_xet-1.4.2-cp37-abi3-musllinux_1_2_x86_64.whl" 225 + upload-time = 2026-03-13T06:58:46Z 226 + size = 4432751 227 227 228 228 [packages.wheels.hashes] 229 - sha256 = "06cdbde243c85f39a63b28e9034321399c507bcd5e7befdd17ed2ccc06dfe14e" 229 + sha256 = "6b0932eb8b10317ea78b7da6bab172b17be03bbcd7809383d8d5abd6a2233e04" 230 230 231 231 [[packages]] 232 232 name = "huggingface-hub" ··· 358 358 359 359 [[packages]] 360 360 name = "numpy" 361 - version = "2.4.2" 361 + version = "2.4.3" 362 362 index = "https://pypi.org/simple" 363 363 364 364 [[packages.wheels]] 365 - url = "https://files.pythonhosted.org/packages/09/f0/817d03a03f93ba9c6c8993de509277d84e69f9453601915e4a69554102a1/numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl" 366 - upload-time = 2026-01-31T23:11:19Z 367 - size = 14688322 365 + url = "https://files.pythonhosted.org/packages/27/d9/4e7c3f0e68dfa91f21c6fb6cf839bc829ec920688b1ce7ec722b1a6202fb/numpy-2.4.3-cp313-cp313-macosx_11_0_arm64.whl" 366 + upload-time = 2026-03-09T07:56:54Z 367 + size = 14691853 368 368 369 369 [packages.wheels.hashes] 370 - sha256 = "bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979" 370 + sha256 = "2629289168f4897a3c4e23dc98d6f1731f0fc0fe52fb9db19f974041e4cc12b9" 371 371 372 372 [[packages.wheels]] 373 - url = "https://files.pythonhosted.org/packages/da/b4/f805ab79293c728b9a99438775ce51885fd4f31b76178767cfc718701a39/numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl" 374 - upload-time = 2026-01-31T23:11:22Z 375 - size = 5198157 373 + url = "https://files.pythonhosted.org/packages/3a/66/bd096b13a87549683812b53ab211e6d413497f84e794fb3c39191948da97/numpy-2.4.3-cp313-cp313-macosx_14_0_arm64.whl" 374 + upload-time = 2026-03-09T07:56:57Z 375 + size = 5198435 376 376 377 377 [packages.wheels.hashes] 378 - sha256 = "8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98" 378 + sha256 = "bb2e3cf95854233799013779216c57e153c1ee67a0bf92138acca0e429aefaee" 379 379 380 380 [[packages.wheels]] 381 - url = "https://files.pythonhosted.org/packages/04/dc/46066ce18d01645541f0186877377b9371b8fa8017fa8262002b4ef22612/numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" 382 - upload-time = 2026-01-31T23:11:28Z 383 - size = 16607311 381 + url = "https://files.pythonhosted.org/packages/7e/eb/7daecbea84ec935b7fc732e18f532073064a3816f0932a40a17f3349185f/numpy-2.4.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" 382 + upload-time = 2026-03-09T07:57:04Z 383 + size = 16608916 384 384 385 385 [packages.wheels.hashes] 386 - sha256 = "d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499" 386 + sha256 = "d5f51900414fc9204a0e0da158ba2ac52b75656e7dce7e77fb9f84bfa343b4cc" 387 387 388 388 [[packages.wheels]] 389 - url = "https://files.pythonhosted.org/packages/b7/20/adb6e6adde6d0130046e6fdfb7675cc62bc2f6b7b02239a09eb58435753d/numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl" 390 - upload-time = 2026-01-31T23:11:33Z 391 - size = 18334210 389 + url = "https://files.pythonhosted.org/packages/4a/ca/627a828d44e78a418c55f82dd4caea8ea4a8ef24e5144d9e71016e52fb40/numpy-2.4.3-cp313-cp313-musllinux_1_2_x86_64.whl" 390 + upload-time = 2026-03-09T07:57:09Z 391 + size = 18334581 392 392 393 393 [packages.wheels.hashes] 394 - sha256 = "c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7" 394 + sha256 = "22654fe6be0e5206f553a9250762c653d3698e46686eee53b399ab90da59bd92" 395 395 396 396 [[packages.wheels]] 397 - url = "https://files.pythonhosted.org/packages/25/a1/9510aa43555b44781968935c7548a8926274f815de42ad3997e9e83680dd/numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl" 398 - upload-time = 2026-01-31T23:11:42Z 399 - size = 14815866 397 + url = "https://files.pythonhosted.org/packages/62/09/d96b02a91d09e9d97862f4fc8bfebf5400f567d8eb1fe4b0cc4795679c15/numpy-2.4.3-cp313-cp313t-macosx_11_0_arm64.whl" 398 + upload-time = 2026-03-09T07:57:18Z 399 + size = 14819570 400 400 401 401 [packages.wheels.hashes] 402 - sha256 = "5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262" 402 + sha256 = "7aa4e54f6469300ebca1d9eb80acd5253cdfa36f2c03d79a35883687da430875" 403 403 404 404 [[packages.wheels]] 405 - url = "https://files.pythonhosted.org/packages/36/30/6bbb5e76631a5ae46e7923dd16ca9d3f1c93cfa8d4ed79a129814a9d8db3/numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl" 406 - upload-time = 2026-01-31T23:11:44Z 407 - size = 5325631 405 + url = "https://files.pythonhosted.org/packages/b5/ca/0b1aba3905fdfa3373d523b2b15b19029f4f3031c87f4066bd9d20ef6c6b/numpy-2.4.3-cp313-cp313t-macosx_14_0_arm64.whl" 406 + upload-time = 2026-03-09T07:57:21Z 407 + size = 5326113 408 408 409 409 [packages.wheels.hashes] 410 - sha256 = "d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913" 410 + sha256 = "d1b90d840b25874cf5cd20c219af10bac3667db3876d9a495609273ebe679070" 411 411 412 412 [[packages.wheels]] 413 - url = "https://files.pythonhosted.org/packages/ea/5c/08887c54e68e1e28df53709f1893ce92932cc6f01f7c3d4dc952f61ffd4e/numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" 414 - upload-time = 2026-01-31T23:11:50Z 415 - size = 16655398 413 + url = "https://files.pythonhosted.org/packages/66/f1/d1c2bf1161396629701bc284d958dc1efa3a5a542aab83cf11ee6eb4cba5/numpy-2.4.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" 414 + upload-time = 2026-03-09T07:57:27Z 415 + size = 16657164 416 416 417 417 [packages.wheels.hashes] 418 - sha256 = "2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f" 418 + sha256 = "22c31dc07025123aedf7f2db9e91783df13f1776dc52c6b22c620870dc0fab22" 419 419 420 420 [[packages.wheels]] 421 - url = "https://files.pythonhosted.org/packages/2a/d5/cbade46ce97c59c6c3da525e8d95b7abe8a42974a1dc5c1d489c10433e88/numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl" 422 - upload-time = 2026-01-31T23:11:55Z 423 - size = 18379680 421 + url = "https://files.pythonhosted.org/packages/b9/c5/9602b0cbb703a0936fb40f8a95407e8171935b15846de2f0776e08af04c7/numpy-2.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl" 422 + upload-time = 2026-03-09T07:57:33Z 423 + size = 18380290 424 424 425 425 [packages.wheels.hashes] 426 - sha256 = "0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257" 426 + sha256 = "a97cbf7e905c435865c2d939af3d93f99d18eaaa3cabe4256f4304fb51604349" 427 427 428 428 [[packages]] 429 429 name = "openai-harmony"
+2
tiles/Cargo.toml
··· 20 20 rusqlite = { version = "0.38.0", features = ["bundled"] } 21 21 rusqlite_migration = "2.4.1" 22 22 uuid = {version = "1.21.0", features = ["v7"]} 23 + axum = "0.8.8" 23 24 24 25 [dev-dependencies] 25 26 tempfile = "3" 26 27 keyring = { version = "3", features = ["apple-native"] } 27 28 wiremock = "0.6.5" 28 29 async-std = { version = "1.12", features = ["attributes"] } 30 + serial_test = "3.4.0"
+172
tiles/src/daemon.rs
··· 1 + //! The Demon that runs the core with his spear 2 + 3 + use std::{ 4 + process::{Command, Stdio}, 5 + sync::Arc, 6 + time::Duration, 7 + }; 8 + 9 + use anyhow::{Result, anyhow}; 10 + use axum::{Router, extract::State, routing::get}; 11 + use reqwest::Client; 12 + use std::fs::OpenOptions; 13 + use std::sync::Mutex; 14 + use tokio::sync::oneshot::{self, Receiver}; 15 + 16 + use crate::utils::config::{ConfigProvider, DefaultProvider}; 17 + 18 + struct AppState { 19 + pub shutdown_sender: Mutex<Option<oneshot::Sender<bool>>>, 20 + } 21 + 22 + pub async fn start_cmd() -> Result<()> { 23 + if cfg!(debug_assertions) { 24 + start_server().await 25 + } else { 26 + start_daemon().await 27 + } 28 + } 29 + 30 + pub async fn stop_cmd() -> Result<()> { 31 + stop_server().await 32 + } 33 + async fn root() -> &'static str { 34 + "Its me luttappi" 35 + } 36 + 37 + // allow zombie, since this process is expected to be 38 + // running in background and have commands to stop if needed 39 + #[allow(clippy::zombie_processes)] 40 + async fn start_daemon() -> Result<()> { 41 + if (ping().await).is_ok() { 42 + return Ok(()); 43 + } 44 + let data_dir = DefaultProvider.get_data_dir()?; 45 + let stdout_log = OpenOptions::new() 46 + .create(true) 47 + .append(true) 48 + .open(data_dir.join("logs/daemon.out.log"))?; 49 + let stderr_log = OpenOptions::new() 50 + .create(true) 51 + .append(true) 52 + .open(data_dir.join("logs/daemon.err.log"))?; 53 + // let _process = Command::new("target/debug/tiles") 54 + let _process = Command::new("tiles") 55 + .arg("daemon") 56 + .stdin(Stdio::null()) 57 + .stdout(Stdio::from(stdout_log)) 58 + .stderr(Stdio::from(stderr_log)) 59 + .spawn() 60 + .expect("Failed to start daemon"); 61 + 62 + wait_until_server_is_up().await 63 + } 64 + 65 + pub async fn start_server() -> Result<()> { 66 + let (shutdown_tx, shutdown_rx) = oneshot::channel::<bool>(); 67 + 68 + let state = AppState { 69 + shutdown_sender: Mutex::new(Some(shutdown_tx)), 70 + }; 71 + let shared_state = Arc::new(state); 72 + let app = Router::new() 73 + .route("/", get(root)) 74 + .route("/shutdown", get(shutdown)) 75 + .with_state(shared_state); 76 + 77 + let listener = tokio::net::TcpListener::bind("127.0.0.1:1729").await?; 78 + 79 + println!("Daemon server started at 1729"); 80 + let _ = axum::serve(listener, app) 81 + .with_graceful_shutdown(shutdown_signal(shutdown_rx)) 82 + .await; 83 + 84 + Ok(()) 85 + } 86 + 87 + async fn shutdown_signal(rx: Receiver<bool>) { 88 + rx.await.expect("shutdown receiver paniced"); 89 + } 90 + 91 + async fn shutdown(State(state): State<Arc<AppState>>) { 92 + println!("Daemon server shutting down"); 93 + let mut sender = state.shutdown_sender.lock().unwrap(); 94 + let sender_real = sender.take().unwrap(); 95 + let _ = sender_real.send(true); 96 + } 97 + 98 + async fn stop_server() -> Result<()> { 99 + let client = Client::new(); 100 + let res = client.get("http://127.0.0.1:1729/shutdown").send().await; 101 + 102 + match res { 103 + Err(err) => Err(anyhow!("Daemon shutdown failed due to {:?}", err)), 104 + _ => Ok(()), 105 + } 106 + } 107 + pub async fn ping() -> Result<(), String> { 108 + let client = Client::new(); 109 + let res = client.get("http://127.0.0.1:1729").send().await; 110 + 111 + match res { 112 + Err(err) => Err(format!("Pong failed: {:?}", err)), 113 + _ => Ok(()), 114 + } 115 + } 116 + 117 + async fn wait_until_server_is_up() -> Result<()> { 118 + let mut retry_count = 5; 119 + let mut error: String = String::new(); 120 + loop { 121 + if retry_count < 1 { 122 + if !cfg!(debug_assertions) { 123 + println!("{:?}", error); 124 + } 125 + return Err(anyhow!(error)); 126 + } 127 + match ping().await { 128 + Ok(()) => return Ok(()), 129 + Err(err) => { 130 + retry_count -= 1; 131 + error = err; 132 + tokio::time::sleep(Duration::from_secs(2)).await; 133 + } 134 + } 135 + } 136 + } 137 + 138 + #[cfg(test)] 139 + mod tests { 140 + use anyhow::Result; 141 + use serial_test::serial; 142 + 143 + use crate::daemon::{ping, start_server, stop_server, wait_until_server_is_up}; 144 + 145 + #[tokio::test] 146 + #[serial] 147 + async fn test_sever_process_started_not_server() -> Result<()> { 148 + tokio::spawn(async move { 149 + let _ = start_server().await; 150 + }); 151 + assert!(ping().await.is_err()); 152 + stop_server().await 153 + } 154 + 155 + #[tokio::test] 156 + #[serial] 157 + async fn test_sever_process_and_server_started() -> Result<()> { 158 + tokio::spawn(async move { 159 + let _ = start_server().await; 160 + }); 161 + wait_until_server_is_up().await?; 162 + assert!(ping().await.is_ok()); 163 + 164 + stop_server().await 165 + } 166 + 167 + #[tokio::test] 168 + #[serial] 169 + async fn stop_server_but_server_not_up() { 170 + assert!(stop_server().await.is_err()) 171 + } 172 + }
+1
tiles/src/lib.rs
··· 1 1 pub mod core; 2 + pub mod daemon; 2 3 pub mod runtime; 3 4 pub mod utils; 4 5 #[cfg(test)]
+39
tiles/src/main.rs
··· 2 2 3 3 use clap::{Args, Parser, Subcommand}; 4 4 use tiles::{ 5 + daemon::{start_cmd, start_server, stop_cmd}, 5 6 runtime::{RunArgs, build_runtime}, 6 7 utils::installer, 7 8 }; 9 + 8 10 mod commands; 9 11 #[derive(Debug, Parser)] 10 12 #[command(name = "tiles")] ··· 55 57 56 58 /// Update Tiles to latest version 57 59 Update, 60 + 61 + /// Daemon configurations 62 + Daemon(DaemonArgs), 58 63 } 59 64 60 65 #[derive(Debug, Args)] ··· 118 123 SetNickname { nickname: String }, 119 124 } 120 125 126 + #[derive(Debug, Args)] 127 + #[command(args_conflicts_with_subcommands = true)] 128 + #[command(flatten_help = true)] 129 + struct DaemonArgs { 130 + #[command(subcommand)] 131 + command: Option<DaemonCommands>, 132 + } 133 + 134 + #[derive(Debug, Subcommand)] 135 + enum DaemonCommands { 136 + /// Start the daemon 137 + Start, 138 + 139 + /// Stops the daemon 140 + Stop, 141 + } 121 142 #[tokio::main] 122 143 pub async fn main() -> Result<(), Box<dyn Error>> { 123 144 let cli = Cli::parse(); ··· 133 154 commands::run_setup_for_ftue(&run_args) 134 155 .inspect_err(|e| eprintln!("Failed to setup Tiles due to {:?}", e))?; 135 156 let _ = commands::try_app_update().await; 157 + 158 + // trying to run the tiles daemon in background concurrently 159 + if !cfg!(debug_assertions) { 160 + tokio::spawn(async move { 161 + let _ = start_cmd().await; 162 + }); 163 + } 164 + 136 165 commands::run(&runtime, run_args) 137 166 .await 138 167 .inspect_err(|e| eprintln!("Tiles failed to run due to {:?}", e))?; ··· 180 209 .inspect_err(|e| eprintln!("Failed in update process due to {:?}", e))?; 181 210 println!("{}", res); 182 211 } 212 + Some(Commands::Daemon(daemon_args)) => match daemon_args.command { 213 + Some(DaemonCommands::Start) => start_cmd() 214 + .await 215 + .inspect_err(|e| eprintln!("Daemon starting failed, reason: {:?}", e))?, 216 + Some(DaemonCommands::Stop) => stop_cmd() 217 + .await 218 + .inspect_err(|e| eprintln!("{:?}", e)) 219 + .inspect(|_| println!("Daemon stopped successfully"))?, 220 + _ => start_server().await?, 221 + }, 183 222 } 184 223 Ok(()) 185 224 }