-
Notifications
You must be signed in to change notification settings - Fork 257
Expand file tree
/
Copy pathpyproject.toml
More file actions
335 lines (311 loc) · 11.2 KB
/
Copy pathpyproject.toml
File metadata and controls
335 lines (311 loc) · 11.2 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
333
334
335
[project]
name = "nooa"
# Version is derived from git tags at build time by uv-dynamic-versioning
# (see [build-system] and [tool.uv-dynamic-versioning] below). On a tag
# `vX.Y.Z` the published wheel is `X.Y.Z`; between tags, dunamai produces
# a PEP 440 dev pre-release like `X.Y.(Z+1).dev<distance-from-tag>`.
dynamic = ["version"]
description = "Code-generating agent orchestration system with event sourcing and serialized execution"
license = {text = "Apache-2.0"}
readme = "README.md"
authors = [
{name = "NVIDIA NeMo Team"}
]
requires-python = ">=3.12,<3.14"
keywords = ["agents", "llm", "codeact", "event-sourcing", "orchestration", "nemo"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
dependencies = [
"pydantic>=2.5.0",
# context_blocks + unifiedllm now ship as nooa.context_blocks /
# nooa.unifiedllm subpackages — pull their formerly-external deps in.
# >=1.84.0: CVE-2026-49468 (Critical, proxy-server RCE) is fixed in 1.84.0;
# also keeps us past the yanked 1.82.7/1.82.8 (March 2026 backdoor).
"litellm>=1.84.0",
# from mcp-nemo-oo-agents (now internal)
"httpx>=0.27.0",
"openinference-instrumentation-litellm>=0.1.30",
]
[project.urls]
Homepage = "https://github.com/NVIDIA-NeMo/labs-OO-Agents"
Repository = "https://github.com/NVIDIA-NeMo/labs-OO-Agents"
Changelog = "https://github.com/NVIDIA-NeMo/labs-OO-Agents/blob/main/CHANGELOG.md"
Issues = "https://github.com/NVIDIA-NeMo/labs-OO-Agents/issues"
[project.scripts]
trace-explorer = "nooa.trace_explorer:main"
[project.entry-points."nooa.skills"]
"nemo.shell" = "nooa.tools.shell_tools:ShellTools"
"nemo.todo" = "nooa.tools.todo:TodoManager"
"nemo.context" = "nooa.runtime.context:ContextApi"
"nemo.events" = "nooa.runtime.events:EventsApi"
"nemo.producers" = "nooa.runtime.producers_skill:ProducersSkill"
"nemo.web" = "nooa.tools.web_publisher:WebPublisher"
"nemo.libwriting" = "nooa.tools.library_writing_lib:SkillWriting"
"nemo.methodwriting" = "nooa.tools.method_writing_lib:MethodWriting"
[tool.uv.sources]
eval_pipeline = { workspace = true }
nooa-cli = { workspace = true }
nooa-acp = { workspace = true }
nooa-memory = { workspace = true }
nooa-bench = { workspace = true }
[tool.uv]
# Extra index URLs to search for packages (in addition to PyPI)
# Ignore packages uploaded less than 7 days ago to mitigate supply-chain attacks
exclude-newer = "2026-07-23T00:00:00Z"
[tool.uv.workspace]
members = [
"util/eval_pipeline",
"packages/nooa-cli",
"packages/nooa-acp",
"packages/nooa-memory",
"packages/nooa-bench",
]
[project.optional-dependencies]
# Convenience aliases for the sibling distributions, so `pip install
# nooa[cli]` does what a user reasonably expects. Without these, that command
# *succeeds* with only a warning and silently installs no CLI.
#
# These are deliberately circular (nooa[cli] -> nooa-cli -> nooa); pip and uv
# both resolve that fine, and it is the standard pattern for a split
# core/plugin distribution. No version floor, matching the existing policy in
# packages/*/pyproject.toml: published wheels declare what they actually need
# rather than being locked to their co-released version.
cli = ["nooa-cli"]
memory = ["nooa-memory"]
bench = ["nooa-bench"]
acp = ["nooa-acp"]
# ARC-AGI-3 example agent (examples/arc_agi_3): the public ARC-AGI-3 SDK + deps.
# Install with `pip install "nooa[arc]"` (or `uv sync --extra arc`).
arc = [
"arc-agi>=0.9.8",
"arcengine>=0.9.3",
"pillow>=10.0", # visual grid-as-image feature (solver_agent)
"rich>=13.0", # live viewer (viewer.py)
]
tracing = [
"opentelemetry-api>=1.20.0",
"opentelemetry-sdk>=1.20.0",
"openinference-instrumentation>=0.1.42",
"openinference-semantic-conventions>=0.1.9",
"openinference-instrumentation-litellm>=0.1.28",
]
viewer = [
"fastapi>=0.100.0",
"uvicorn[standard]>=0.20.0",
"python-dotenv>=1.0.0",
"python-multipart>=0.0.5",
]
# trace_explorer is now nooa.trace_explorer (internal, no extra deps)
sandbox = [
"openshell",
]
# mcp lives at nooa.mcp; install with `uv sync --extra mcp`
# (kept optional so glibc<2.28 hosts can `uv sync` without pulling
# pydantic-core wheels that only target manylinux_2_28). See issue 189.
mcp = [
"mcp>=1.0.0",
]
# NeMo Relay integration (guardrails, intercepts, event subscribers, ATIF
# export).
# See src/nooa/nemo_relay_middleware.py and examples/quickstart/15_nemo_relay.py.
#
# Floor is 0.6: LLM request intercepts must return `LLMRequestInterceptOutcome`
# (0.5+) rather than a `(request, annotated)` tuple, and that type does not
# exist in 0.4 — so there is no single callback shape that spans 0.4 and 0.6.
#
# Ceiling is <0.7: 0.7 changes the LLM sanitizer contract to the two-argument
# form `(payload, directional_context) -> payload | None` with no compatibility
# shim, and makes an implicit `return` mean "omit the payload" (fail-closed).
# Our library code (nemo_relay_middleware.py) registers no sanitizers and is
# unaffected, but tests/test_nemo_relay_middleware.py does — see the sanitizer
# registrations there before lifting this bound.
nemo-relay = [
"nemo-relay>=0.6,<0.7",
]
# CLI ships as a separate package: `uv add nooa-cli`.
# Data-science stack for the LLM REPL: `uv add nooa-cli[datascience]`.
[build-system]
requires = ["hatchling>=1.26.0", "uv-dynamic-versioning>=0.14.0"]
build-backend = "hatchling.build"
[tool.hatch.version]
source = "uv-dynamic-versioning"
[tool.uv-dynamic-versioning]
vcs = "git"
style = "pep440"
# bump = true: between tags, produce `X.Y.(Z+1).dev<distance>` rather than
# `X.Y.Z.post<distance>` — these sort ABOVE the latest stable, so `--pre`
# consumers get the freshest dev rather than something that sorts below a
# release that has already shipped.
bump = true
# metadata = false: drop the `+g<sha>` local segment. PyPI rejects local
# segments; GitLab accepts them. Dropping keeps the wheels portable.
metadata = false
# Used when no tag is reachable yet (initial bootstrap before the first
# `vX.Y.Z` tag is cut). Once a tag exists, this is ignored.
fallback-version = "0.0.6"
[tool.hatch.build.targets.wheel]
packages = ["src/nooa"]
[tool.hatch.build.targets.wheel.force-include]
"THIRD_PARTY_NOTICES.md" = "THIRD_PARTY_NOTICES.md"
[dependency-groups]
trace-viewer = [
"uvicorn>=0.38.0",
"python-dotenv>=1.0.0",
"fastapi>=0.123.4",
"pyyaml>=6.0.0",
"watchfiles>=1.0.0",
"python-multipart>=0.0.20",
]
dev = [
{include-group = "trace-viewer"},
"pytest>=7.4.0",
"pytest-asyncio>=0.21.0",
"pytest-rerunfailures>=14.0",
"pytest-timeout>=2.3.0",
"mypy>=1.7.0",
"ruff>=0.14.14",
"httpx[socks]>=0.28.1",
"opentelemetry-exporter-otlp-proto-http>=1.39.1",
"eval_pipeline",
# Workspace packages — keep acp + bench + cli + memory installed/editable in dev sync
"nooa-cli",
"nooa-acp",
"nooa-memory",
"nooa-bench",
"pre-commit>=4.5.0",
"pyright>=1.1.408",
"pytest-cov>=7.1.0",
# Data-science libs exercised by core tests (REPL scoping, return-type
# adapters, doc adapters). Previously installed transitively via the
# benchmarks package, which moved to nooa-dev.
"pandas>=2.0.0",
"matplotlib>=3.8.0",
]
[tool.pytest.ini_options]
asyncio_mode = "auto"
# A hang is a failure, not a pending result. Without this a test that wedges —
# a lock that never releases, a subprocess prompt that never answers — stalls
# CI instead of reporting, and a stalled job reads as "still running" rather
# than "broken". Deliberately far above any real test: the slowest here is a
# few seconds, so this only ever fires on a genuine hang.
timeout = 300
testpaths = [
"tests",
"tests/agentdoc",
"tests/viewer",
"tests/context_blocks",
"tests/unifiedllm",
"tests/tracing",
"tests/test_mcp",
"packages/nooa-cli/tests",
"packages/nooa-acp/tests",
"packages/nooa-bench/tests",
"tests/trace_explorer",
]
pythonpath = [
"src",
"packages/nooa-cli/src",
]
addopts = "-v --tb=short --import-mode=importlib -m 'not integration and not stress and not sandbox'"
markers = [
"integration: marks tests as integration tests that make real API calls (run with '-m integration')",
"provider_compat_ollama: marks live Ollama provider compatibility tests",
"provider_compat_vllm: marks live vLLM provider compatibility tests",
"sandbox: marks tests that fork a real sandbox worker to exercise OS-level containment (run with '-m sandbox'); no credentials needed, but heavier than unit tests",
"stress: marks tests as stress/load tests that simulate high concurrency (run with '-m stress')",
]
filterwarnings = [
"ignore::DeprecationWarning:litellm.*",
"ignore::DeprecationWarning:aiohttp.*",
"ignore:coroutine.*was never awaited:RuntimeWarning",
"ignore:Pydantic serializer warnings:UserWarning",
"ignore::FutureWarning:nooa.strategies",
]
[tool.coverage.run]
source = ["src/nooa", "packages/nooa-cli/src/nooa_cli"]
omit = [
"*/tests/*",
"*/__pycache__/*",
]
[tool.coverage.report]
show_missing = true
skip_covered = false
precision = 1
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if TYPE_CHECKING:",
"raise NotImplementedError",
"@(abc\\.)?abstractmethod",
"if __name__ == .__main__.:",
"\\.\\.\\.",
]
[tool.coverage.html]
directory = "htmlcov"
[tool.mypy]
python_version = "3.12"
strict = true
warn_no_return = true
warn_unreachable = true
# Disable call-arg errors for __init_subclass__ (PEP 487 keyword arguments)
# return and body errors for ellipsis methods
disable_error_code = ["empty-body", "return", "call-arg"]
[tool.ruff]
line-length = 100
target-version = "py312"
force-exclude = true
extend-exclude = [
"worktrees",
".vscode-server",
".claude",
"notebook_tutorials",
"examples/arc_agi_3/arc_agi_3",
"examples/cybergym/task_artifacts",
]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = [
"E501", # line too long (handled by formatter)
]
[tool.ruff.lint.per-file-ignores]
"*.ipynb" = ["E402"] # Notebooks often have config before imports
# Tests intentionally use legacy typing syntax (Optional[X], Union[X,Y], Generic[T])
# to verify that _get_complex_type() handles those annotation forms correctly.
"tests/test_pure_functions_gl105.py" = ["UP007", "UP045", "UP046"]
[tool.ruff.lint.isort]
known-first-party = ["nooa", "eval_pipeline", "evaluation", "agentdoc"]
[tool.pyright]
pythonVersion = "3.12"
venvPath = "."
venv = ".venv"
# Resolve workspace packages when IDE uses project root (same as pytest pythonpath)
extraPaths = [
"src",
"packages/nooa-cli/src",
]
include = [
"src",
"packages"
]
# Excluded from pyright:
# - cli: pre-existing typing debt that surfaces when CLI is type-checked as
# its own package.
exclude = [
"packages/nooa-cli",
]
# Pydantic discriminated unions require narrowing event_type in subclasses
reportIncompatibleVariableOverride = false