Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
332 lines (320 loc) · 13.7 KB
/
Copy pathpyproject.toml
File metadata and controls
332 lines (320 loc) · 13.7 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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
[build-system]
requires = ["setuptools==80.10.2", "wheel==0.48.0"]
build-backend = "setuptools.build_meta"
[project]
name = "tofu-agent"
version = "0.18.3"
description = "Embeddable and headless Tofu agent runtime with network and tool capabilities"
readme = "README.md"
requires-python = ">=3.12"
license = "MIT"
authors = [{name = "Tofu contributors"}]
dependencies = [
"quart>=0.20",
"hypercorn>=0.17",
"cryptography>=42.0",
# Generated native ABI bindings use only the backend at runtime.
"cffi>=2.0",
"requests>=2.31",
"urllib3>=1.26.19",
"Jinja2>=3.1.6",
"psutil>=5.9",
# Lazy isolated JavaScript runtime; bundled WASM requires no Node installation.
"wasmtime==49.0.0",
# Pure-Python structural validation also ships in the controlled Desktop Agent.
"pypdf>=6.17,<7",
"beautifulsoup4>=4.12",
"python-dateutil>=2.8",
"mcp>=2,<3",
"httpx>=0.28",
"orjson>=3.9",
"pydantic>=2.7,<3",
"tiktoken>=0.7",
"markdown>=3.5",
"markdown-it-py>=3.0",
"PyYAML>=6.0",
"jsonschema>=4.18",
# repo_map agent tool: tree-sitter-based code outline + PageRank ranking.
# grep-ast is the tag extractor (needs a grammar pack — see full extra),
# networkx runs aider-style reference PageRank over the import graph.
"grep-ast>=0.9",
"networkx>=3.0",
"pathspec>=0.12",
]
[project.urls]
Homepage = "https://github.com/rangehow/ToFu"
Documentation = "https://github.com/rangehow/ToFu#readme"
Repository = "https://github.com/rangehow/ToFu"
Issues = "https://github.com/rangehow/ToFu/issues"
[project.scripts]
tofu-agent = "tofu_agent.cli:main"
[project.optional-dependencies]
# The published default is the slim headless/agent runtime: LLM loop, tools,
# network and MCP — installable fast into eval containers. Document/media/
# search parsing (pymupdf, Office formats, trafilatura, tofu-search, …) is
# lazy-imported by the features that need it and lives in the `full` extra,
# so `pip install tofu-agent` stays light while `tofu-agent[full]` restores
# the complete tool surface. Durable application storage and the updater are
# deliberately separate so embedding Tofu never implies PostgreSQL or a
# checked-out web application.
full = [
"tofu-search>=0.12.17",
"trafilatura>=2.3.1",
"Pillow>=10.0",
"python-pptx>=0.6.21",
"fontTools>=4.40",
"brotli>=1.1",
"lxml>=5.3",
"lxml_html_clean>=0.4",
"python-docx>=1.0",
"openpyxl>=3.1",
"xlrd>=2.0",
"olefile>=0.46",
# pymupdf4llm exact-pins the other two packages; move this trio together.
"pymupdf==1.27.2.3",
"pymupdf_layout==1.27.2.3",
"pymupdf4llm==1.27.2.3",
"zhconv>=1.4",
"qrcode>=7.4",
# tree-sitter grammars for ~200 languages. Required for repo_map on any
# non-Python file; without it the tool silently returns Python-only maps.
"tree-sitter-language-pack>=0.10",
]
storage = [
"psycopg[binary,pool]>=3.2",
]
# Tag releases build without PEP 517 isolation, so the exact backend, wheel
# builder and metadata validator come from uv.lock instead of being resolved
# from the network independently in each publishing job.
release = [
"build>=1.2,<2",
"twine>=6,<7",
"setuptools>=77,<81",
"wheel>=0.45,<1",
]
# The full application needs the complete document/media/search tool
# surface; `full` entries are duplicated here because a project cannot
# depend on its own optional extra in a portable uv lock.
app = [
"psycopg[binary,pool]>=3.2",
"uv>=0.4",
"tofu-search>=0.12.17",
"trafilatura>=2.3.1",
"Pillow>=10.0",
"python-pptx>=0.6.21",
"fontTools>=4.40",
"brotli>=1.1",
"lxml>=5.3",
"lxml_html_clean>=0.4",
"python-docx>=1.0",
"openpyxl>=3.1",
"xlrd>=2.0",
"olefile>=0.46",
"pymupdf==1.27.2.3",
"pymupdf_layout==1.27.2.3",
"pymupdf4llm==1.27.2.3",
"zhconv>=1.4",
"qrcode>=7.4",
# tree-sitter grammars — repo_map on non-Python files (see full extra).
"tree-sitter-language-pack>=0.10",
]
# `test` is the extra CI installs (`pip install -e ".[test]"`). It carries the
# full-app storage dependencies plus the test runner/plugins, but no linters.
# pytest itself lives HERE (it is NOT in requirements.txt), so this extra must
# exist for CI to have a runner at all.
test = [
# Collection imports browser fixtures even when visual tests are deselected.
"playwright>=1.40",
# The repository suite exercises the full application as well as the
# storage-free public runtime.
"psycopg[binary,pool]>=3.2",
"uv>=0.4",
"pytest>=7.0",
"pytest-cov>=4.0",
"requests-mock>=1.12",
# The external mock LLM process in tests/mock_llm_server.py intentionally
# remains a tiny Flask fixture; Flask is not part of the application
# runtime anymore.
"flask>=3.0",
# Parallel test execution across worker processes. The suite is large;
# running it serially is the dominant CI wall-time cost. Each xdist
# worker is its own process → its own session fixtures → its own throwaway
# SQLite DB (conftest mkdtemps per session), so parallelism is isolation-safe.
"pytest-xdist>=3.8",
# Per-test hang guard so one wedged test can't stall the whole job to the
# CI ceiling. Use the `signal` method (default on POSIX) — the `thread`
# method mis-fires on the endpoint-loop tests.
"pytest-timeout>=2.1",
# Property-based testing for boundary logic that example-based tests
# under-specify (currently tests/storage/test_legacy_conversation_tail_window.py).
# Declared as a hard test dep so `@given` suites can never silently skip.
"hypothesis>=6.0",
# In-memory Redis for exercising the redis-backed runtime-state store +
# push bus (Epics B/C/D) against a REAL redis-py client without a live
# server. Test-only; the runtime `redis` dep it pulls is NOT core.
"fakeredis>=2.20",
# Tiny pure-python CSS parser used by tests/frontend/test_frontend_icon_box_alignment.py
# (parses styles.css rules instead of regex). Without it that module died at
# COLLECTION with ModuleNotFoundError in every CI lane (2026-08-05).
"tinycss2>=1.2",
# The repository suite exercises document/media/search parsing too, so it
# needs the `full` surface (duplicated — extras cannot compose).
"tofu-search>=0.12.17",
"trafilatura>=2.3.1",
"Pillow>=10.0",
"python-pptx>=0.6.21",
"fontTools>=4.40",
"brotli>=1.1",
"lxml>=5.3",
"lxml_html_clean>=0.4",
"python-docx>=1.0",
"openpyxl>=3.1",
"xlrd>=2.0",
"olefile>=0.46",
"pymupdf==1.27.2.3",
"pymupdf_layout==1.27.2.3",
"pymupdf4llm==1.27.2.3",
"zhconv>=1.4",
"qrcode>=7.4",
]
dev = [
# Collection imports browser fixtures even when visual tests are deselected.
"playwright>=1.40",
# Superset of `test` plus the linter — kept explicit because a project
# cannot depend on its own optional extra in a portable uv lock.
"pytest>=7.0",
"pytest-cov>=4.0",
"requests-mock>=1.12",
"flask>=3.0",
"pytest-xdist>=3.8",
"pytest-timeout>=2.1",
"hypothesis>=6.0",
"fakeredis>=2.20",
"tinycss2>=1.2",
"psycopg[binary,pool]>=3.2",
"uv>=0.4",
"ruff",
"pyright>=1.1.403",
# Same `full` duplication as `test`.
"tofu-search>=0.12.17",
"trafilatura>=2.3.1",
"Pillow>=10.0",
"python-pptx>=0.6.21",
"fontTools>=4.40",
"brotli>=1.1",
"lxml>=5.3",
"lxml_html_clean>=0.4",
"python-docx>=1.0",
"openpyxl>=3.1",
"xlrd>=2.0",
"olefile>=0.46",
"pymupdf==1.27.2.3",
"pymupdf_layout==1.27.2.3",
"pymupdf4llm==1.27.2.3",
"zhconv>=1.4",
"qrcode>=7.4",
]
# Browser automation is a worker capability. The API image intentionally
# omits both this Python package and the Chromium payload; the personal image
# targets the worker stage and therefore retains the existing feature set.
worker = [
"playwright>=1.40",
]
# Optional horizontal-scale extra: the cross-replica runtime-state backend
# (TOFU_RUNTIME_STATE_BACKEND=redis) + push fan-out. Redis is NOT a core
# dependency — a single-box install runs the inproc default with zero extra
# packages. `pip install tofu-agent[scale]` pulls the client for a multi-replica
# deployment.
scale = [
"redis>=4.3",
]
# The Git repository is the source authority for all first-party Python
# artifacts. Each member keeps independent build metadata and release version;
# workspace resolution only replaces published dependencies in development.
[tool.uv.workspace]
members = ["packages/tofu-search", "plugins/tofu-trading"]
# Optional MCP subprocesses resolve their SDK/dependencies independently.
exclude = ["packages/tofu-overleaf-mcp", "packages/tofu-mtsso-auth", "packages/tofu-environments"]
[tool.uv.sources]
tofu-search = { workspace = true }
[tool.setuptools.packages.find]
# Ship the importable Python packages. The in-process façade (`tofu`) and the
# kernel it calls (`lib.tasks_pkg.entry`) require `lib*` to be importable;
# `tofu*` is the supported public surface. Database/storage authorities and
# HTTP application routes are source-workspace concerns, not wheel contents.
namespaces = false
include = ["tofu*", "lib*", "rootless_vm*", "bootstrap_pkg*"]
exclude = ["tests*", "benchmarks*", "debug*", "clients*", "desktop*",
"browser_extension*", "docs*", "promo*", "propaganda*",
"swebench_rerun_workdir*", "outputs*", "paper*", "tools*",
"routes*", "lib.database*", "lib.storage", "lib.storage.*",
"lib.storage_authority_sql*", "lib.tests*"]
[tool.setuptools]
# These top-level modules are runtime dependencies of the public package;
# declaring them prevents editable installs from hiding a broken wheel.
py-modules = ["runtime_guards", "runtime_path_policy", "tofu_dotenv"]
# The repository has VCS manifest plugins installed in some build environments.
# Never let their broad source list turn excluded application packages into
# accidental package data; every non-Python runtime asset is declared below.
include-package-data = false
[tool.setuptools.package-data]
"lib.repo_map" = ["LICENSE.grep-ast.txt"]
"lib.tools.javascript" = ["bootstrap.js", "assets/*.wasm", "assets/*.json", "assets/*.LICENSE", "assets/NOTICE"]
"tofu_agent" = ["setup_ui/*.html", "setup_ui/*.css", "setup_ui/*.js"]
"lib.model_info" = ["data/*.json", "model_inference_defaults.json"]
"lib.motion_video" = ["guide/*.md", "guide/*.html"]
"lib.slides" = ["guide/*.md"]
"lib.design_sys" = ["bibles/*.md"]
[tool.ruff]
# The legacy in-tree undo store can contain tens of thousands of session
# directories under an explicitly linted `lib/` path. It is mutable user state,
# never Python source, and already has the same scoped Git/project-tool ignore.
# Keep this path exact: user projects may legitimately own another directory
# named `.project_sessions` outside Tofu's runtime authority.
extend-exclude = ["lib/.project_sessions", "packages", "plugins"]
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = "test_*.py"
python_classes = "Test*"
python_functions = "test_*"
# `-p no:napari` blocks an unrelated plugin leaked in by the host Python
# environment. Its napari -> vispy import chain raises ``OSError: GL ES 2.0
# library not found`` on headless machines before Tofu collection begins. Keep
# this in project addopts as well as the Makefile so a direct
# ``python -m pytest`` is equally hermetic.
#
# Policy-critical plugins are loaded explicitly so direct pytest, Make, CI and
# the autoload-disabled affected-test runner all execute the same contract.
# Their entry-point names must be blocked first: pytest otherwise registers the
# same module twice under different names when plugin autoload is enabled.
#
# Distribution mode lives here, not in individual commands. ``worksteal`` is
# the independence contract: tests may be assigned in any order to any worker.
# Bare pytest remains serial because this config intentionally supplies no
# ``-n``; Make/CI/affected-test entry points opt into bounded worker counts.
addopts = "-v --tb=short --strict-markers -p no:napari -p no:timeout -p pytest_timeout -p no:xdist -p xdist.plugin -p no:anyio -p anyio.pytest_plugin -p no:requests_mock -p requests_mock.contrib._pytest_plugin --dist worksteal"
# Per-test hang guard. pytest-timeout has been an installed, DECLARED dep for
# a while, but with no default configured it never fired — measured
# 2026-07-27: a sleep(600) test ran until an EXTERNAL kill stopped the shell,
# with pytest emitting no verdict at all. That silently un-verifies every
# hang-shaped NEUTER in the suite (deleting the agent-loop no-progress
# breaker makes its test HANG rather than fail, because the breaker is the
# only exit from an infinite dispatcher).
#
# 300s is well above the slowest healthy tests here (jsdom harnesses,
# PDF/VLM parsing, live_server boots) and far below any wedged loop.
# `-p pytest_timeout` above is load-bearing: this suite is normally run with
# PYTEST_DISABLE_PLUGIN_AUTOLOAD=1, which turns off entry-point autoloading,
# so without naming the plugin the setting below is inert.
# Use the `signal` method (default on POSIX) — the `thread` method mis-fires
# on the endpoint-loop tests. Override per-test with @pytest.mark.timeout(N).
timeout = 300
markers = [
"unit: Pure unit tests (no server, no DB)",
"api: API integration tests using an isolated application/storage authority",
"visual: Visual E2E tests (requires live server + Chromium)",
"slow: Long-running tests (opt-in)",
"timeout(seconds): Override the default pytest-timeout deadline for a test.",
"serial: Unit tests with a host-global, saturation, or timing constraint that must not overlap the parallel unit lane. test-unit runs them in a dedicated no-xdist phase. Each new use requires an inline resource reason and should be removed once that resource is isolated.",
"live_llm: Hits the real LLM API (costs money, needs creds). Manual-only; gated by TOFU_PARITY_LIVE=1.",
]