Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
174 lines (167 loc) · 8.41 KB
/
Copy pathpyproject.toml
File metadata and controls
174 lines (167 loc) · 8.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
[build-system]
requires = ["setuptools>=83.0.0"]
build-backend = "setuptools.build_meta"
[project]
name = "tinyagentos"
version = "1.0.0-beta.56"
description = "Self-hosted AI agent memory system for low-power hardware"
license = { file = "LICENSE" }
# Upper-capped at <3.15 because the proxy extra's litellm (pinned
# >=1.94.2,<1.95 below; uv.lock resolves 1.94.3) declares requires-python
# >=3.10,<3.15 on PyPI (verified 2026-09-25 against litellm 1.94.3).
# A fresh distro that defaults python3 to 3.14 would otherwise build the
# venv on 3.14 and abort with "No matching distribution found for litellm".
# The installer also steers the venv to a supported interpreter; this cap
# makes the constraint explicit to pip and uv.
requires-python = ">=3.11,<3.15"
dependencies = [
# Cap below 0.137: fastapi 0.137.0 regressed include_router so that a
# mounted APIRouter contributes none of its routes to the app, leaving
# create_app() with an empty API surface. 0.136.3 is the last good release.
"fastapi>=0.115.0,<0.137",
"uvicorn[standard]>=0.52.1",
"httpx>=0.27.0",
# Retry loop behind tinyagentos/clients/retry.py — every outbound inference
# call and every adapter /message proxy runs through it. Apache-2.0, pure
# py3-none-any wheel with no runtime dependencies of its own.
"tenacity>=9.1.4",
"jinja2>=3.1.0",
"pyyaml>=6.0",
"aiosqlite>=0.20.0",
"argon2-cffi>=23.1.0",
"sqlcipher3>=0.6.2",
"psutil>=5.9.0",
"python-multipart>=0.0.13", # python_multipart module name (llm_gateway STT parser)
# Project canvas board renders low-fidelity PNG snapshots for vision
# agents (tinyagentos/projects/canvas/render.py).
"Pillow>=10.0",
"lxml>=5.0.0",
"readability-lxml>=0.8.1",
# Memory system — published to PyPI
"taosmd==0.4.0",
# WebSocket client for dashboard proxy (shortcut_proxy.py)
"websockets>=12.0",
# Web Push VAPID signing — pulls in cryptography, http-ece, py-vapid
"pywebpush>=1.14",
# mDNS/Bonjour publisher so the controller is reachable at
# http://taos.local:<port>/ on the LAN without users knowing its IP
# (tinyagentos/services/mdns_publisher.py).
"zeroconf>=0.150.0",
"matrix-nio>=0.26.0",
# Diff/patch for the notes revision log: computes and applies text diffs
# for the Time Machine history layer (tinyagentos/notes/shared_docs_store.py).
"diff-match-patch>=20230430",
# Cron expression parsing for project routines (schedule -> next_fire).
"croniter>=6.2.4",
# Process-shared lock serialising the local-token bindings RMW
# (tinyagentos/auth.py bind_local_token_agent). Previously only present
# transitively; declare it directly so the import is guaranteed.
"filelock>=3.12",
# ES256 signing for APNs JWTs (tinyagentos/push/apns.py), imported at
# startup via app.py. Previously only pulled in transitively through
# pywebpush; declare it directly so the import is guaranteed.
"cryptography>=50.0.0",
# Unicode-aware slugs for agent/handle names (tinyagentos/config.py). The
# ASCII-only regex it replaces deleted every non-Latin code point, so a
# Chinese or Cyrillic agent name could not be created at all.
# NEVER install the "unidecode" extra: it pulls GPL-only Unidecode, which
# we keep out by choice (text-unidecode suffices). See docs/dependency-licences.md.
"python-slugify>=8.0.4",
# PEP 440 version parsing/ordering for the worker update check
# (tinyagentos/worker/update_check.py) and the optional-app catalog
# (tinyagentos/routes/apps.py). Previously only reachable through the
# proxy extra and the dev group, so a bare `uv sync` did not install it.
"packaging>=24",
# YouTube/X knowledge ingestion shells out to the yt-dlp CLI
# (tinyagentos/knowledge_fetchers/{youtube,x}.py). install-server.sh used to
# `pip install yt-dlp` after the editable install, which put a package on
# every production box that uv.lock had never resolved — so an upstream
# relicence or CVE reached users without tripping any gate. Declared here so
# it goes through the lockfile like everything else.
"yt-dlp>=2025.1.15",
"pypdf>=6.17",
]
[project.optional-dependencies]
worker = ["pystray>=0.19.0", "Pillow>=10.0"]
# Model torrent mesh (optional): libtorrent has no PyPI wheel on most platforms
# (OS-level libtorrent-rasterbar / python3-libtorrent), so it must not be a core
# dependency or fresh installs abort. torrent_downloader guards the import and
# falls back to a direct download when it is absent.
torrent = ["libtorrent>=2.0.9"]
# taOSusb Bluetooth pairing (S1): the controller's BLE central talks to a
# board's GATT peripheral via bleak. Not every controller install has (or
# needs) a Bluetooth adapter, so this stays optional -- tinyagentos/cluster/
# ble/transport.py imports bleak lazily and the scan/pair routes answer 503
# bluetooth_unavailable when it (or an adapter) is missing, instead of every
# install failing to boot without it.
ble = ["bleak>=0.22.0"]
# DEPRECATED, intentionally empty. The LiteLLM process is gone (#3313), but the
# updater that RUNS an update is the OLD code already on the box, and before
# #3313 it called `uv sync --frozen --extra proxy`. uv refuses an undefined
# extra, so deleting this name stranded every existing install on the release
# before it. Keep it defined and empty; tests/test_update_extras_compat.py
# pins every extra a shipped updater has ever requested.
proxy = []
e2e = [
"pytest>=9.1.1",
"pytest-playwright>=0.5.0",
]
[dependency-groups]
dev = [
"pytest>=9.1.1",
"pytest-asyncio>=0.23.0",
"pytest-timeout>=2.3.0",
"pytest-xdist>=3.5.0",
# Shards the suite across parallel CI jobs. xdist parallelises WITHIN a job
# and a hosted runner has 2 vCPU, so -n auto caps at 2 workers no matter how
# many tests there are; the only remaining lever is more jobs (#2135).
"pytest-split>=0.9.0",
"httpx",
"respx>=0.21.0",
"websockets>=12.0",
]
[tool.setuptools.packages.find]
include = ["tinyagentos*"]
[tool.setuptools.package-data]
# Vendored MIT price table + its licence notice (scripts/update_model_prices.py regenerates the JSON).
"tinyagentos.llm_usage" = ["data/model_prices.json", "data/NOTICE"]
[project.scripts]
tinyagentos = "tinyagentos.app:main"
tinyagentos-worker = "tinyagentos.worker.__main__:main"
taos = "tinyagentos.app:main"
taos-gui = "tinyagentos.app:gui"
taos-worker-ctl = "tinyagentos.cli.worker:main"
taosctl = "tinyagentos.cli.taosctl.__main__:main"
[tool.pytest.ini_options]
# Per-test timeout: a single hung test fails fast and named instead of
# silently eating the entire 45-minute CI budget. 120 s covers the
# slowest legitimate tests (async DB-heavy flows) with headroom to spare.
# thread method works on all platforms including macOS; signal would be
# faster but requires the main thread.
timeout = 120
timeout_method = "thread"
markers = [
"e2e: End-to-end browser tests (require running server)",
"slow: Tests requiring a live stack (skipped in local CI; run with pytest -m slow)",
# Opt OUT of real CSRF enforcement for this test/class/module. CSRF is ON
# by default (tests/conftest.py); this marker is the only way to disable
# it, and every module carrying it is inventoried in
# tests/test_csrf_bypass_debt.py so the list cannot grow unnoticed.
"csrf_bypass: run this test with verify_csrf stubbed to a no-op (legacy debt)",
# Declares the product function a guard test protects, and the defect it must
# fail on. Checked by scripts/check_non_discriminating.py (guard-discrimination
# workflow); inert in a normal test run.
"guards(target, replace=None, must_kill=None): guard test's protected function; see scripts/check_non_discriminating.py",
"skip_if_no_embed_backend: skip when no embed backend can serve the test (qmd unreachable and onnxruntime absent)",
]
filterwarnings = [
# Asyncio teardown emits unraisable RuntimeError("Event loop is closed")
# warnings when finalisers (httpx clients, aiosqlite connections) fire
# during interpreter shutdown after the loop is gone. Harmless — tests
# have already passed — but trips GitHub Actions log parser into
# ##[error] annotations. Narrow filter: only matches the well-known
# "Exception ignored in:" prefix that pytest uses for these, so
# genuine unraisable exceptions in __del__ or forgotten awaitables
# still surface as test failures.
"ignore:Exception ignored in:pytest.PytestUnraisableExceptionWarning",
]