forked from agentdecksdk/agentdeck
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
175 lines (163 loc) · 7.7 KB
/
Copy pathpyproject.toml
File metadata and controls
175 lines (163 loc) · 7.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
[project]
name = "agentdeck-sdk"
version = "6.0.0"
description = "Build agents, tools and workflows as normal software, and serve them through bindings: one Deck, reachable over its own HTTP wire, the terminal and AG-UI, with the same runs and controls everywhere."
license = "MIT"
license-files = ["LICENSE"]
requires-python = ">=3.12"
readme = "README.md"
# No `License ::` classifier: the SPDX `license` field above supersedes it, and hatchling
# rejects a build that declares both.
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Typing :: Typed",
]
dependencies = [
"pydantic>=2.7",
"pydantic-settings>=2.4",
"python-dotenv>=1.0",
"openai-agents==0.17.0",
# pinned pair: openai 2.33+ added required usage fields that agents 0.17.0 doesn't set
"openai==2.32.0",
"httpx>=0.27",
"pyyaml>=6.0",
]
[project.scripts]
agentdeck = "agentdeck.cli:main"
[project.optional-dependencies]
serve = [
"starlette>=0.40",
"uvicorn>=0.30",
]
observability = [
"langfuse>=2.60",
"openinference-instrumentation-openai-agents>=0.1",
"opentelemetry-sdk>=1.27",
]
postgres = [
# the Postgres event log's driver. `[binary]` explicitly: a plain `psycopg` needs a system
# libpq that a fresh CI runner or dev box does not have.
"psycopg[binary]>=3.2",
]
redis = [
# backs both the Redis-backed session adapter (sessions.py) and the Redis event-log
# adapter (adapters/stores/redis) - neither is a default, so the client isn't in base.
"redis>=5.0",
]
agui = [
# the official wire models and SSE encoder (rulings.md 16); starlette is listed directly
# here too, since a standalone `[agui]` install has no `[serve]` to pull it in transitively.
# Floor matches `serve`'s own: two independent installs of the same dependency must not
# silently diverge on what version actually works.
"ag-ui-protocol>=0.1.22,<0.2",
"starlette>=0.40",
]
dev = [
"pytest>=8.0",
# Jack's own server is a FastAPI app (`examples/jack/jack/server.py`), and its test suite is
# part of the gate. Nothing in `agentdeck/` imports FastAPI since the v1 wire was deleted.
"fastapi>=0.115",
"pytest-asyncio>=0.23",
# `make coverage`, not part of `make check`: the deletion waves (#71, #131) need
# per-module coverage as one evidence stream for "nothing imports and nothing
# exercises this". No threshold - it is an audit instrument, not a gate.
"pytest-cov>=5.0",
# an upper bound on a wedged test. The suite has deliberate infinite loops (StallingStore,
# concurrency_worker's file barriers) whose own guards live inside the worker subprocesses, so
# they never fire for the parent: a run found in 2026-08 had been hung for five days, orphaned
# to init and outliving the worktree it was started in.
"pytest-timeout>=2.3",
# not exercised by any default path - installed here so the gate still covers the
# redis session/event-log branches without making `[redis]` a base extra.
"redis>=5.0",
# same reasoning as redis above, for the AG-UI binding's own test suite.
"ag-ui-protocol>=0.1.22,<0.2",
"ruff>=0.6",
"ty>=0.0.1a21",
"pre-commit>=4.0",
# pinned: a contract that passes today must not start failing on a linter upgrade
"import-linter==2.14",
# scripts/repomap.py only: the public-API map agents read before writing new code
"griffe>=1.6",
]
[tool.ruff]
line-length = 120
target-version = "py312"
[tool.ruff.lint]
# ERA, S110/S112, PIE790, PGH003/PGH004, T10/T20: the structural AI-slop set -
# commented-out code, swallowed exceptions, placeholder bodies, blanket
# suppressions, and debug output in library code. RUF100 rejected: it deletes
# noqa markers documenting deliberately non-enabled rules.
select = ["E", "W", "F", "I", "B", "C4", "UP", "N", "SIM", "TC", "TID251", "ERA", "S110", "S112", "PIE790", "PGH003", "PGH004", "T10", "T20"]
ignore = ["E501", "UP046", "UP047"]
[tool.ruff.lint.isort]
known-first-party = ["agentdeck"]
# import-linter can't express this one: `agents.mcp` is a subpackage of an external
# package, which its contracts reject outright. Ruff sees the import statement itself,
# so the ban lands where the SDK is actually named.
[tool.ruff.lint.flake8-tidy-imports.banned-api]
"agents.mcp".msg = "the MCP client is adapters/tools/mcp's alone - take tools off a ToolSet instead"
"asyncio.create_task".msg = "tasks belong to the runtime (docs/patterns/lifecycle.md): a task created elsewhere bypasses cancellation and drain"
[tool.ruff.lint.per-file-ignores]
"agentdeck/adapters/tools/mcp/*" = ["TID251"]
"tests/test_mcp_tool_source.py" = ["TID251"]
# print is the legitimate output mechanism everywhere except library code.
"agentdeck/surfaces/cli/*" = ["T201"]
"tests/*" = ["T201"]
"scripts/*" = ["T201"]
"examples/*" = ["T201"]
# The runtime owns task creation (docs/patterns/lifecycle.md); tests drive it.
# Enumerated rather than tests/*: a blanket TID251 ignore would also un-ban agents.mcp.
"agentdeck/deck.py" = ["TID251"]
"agentdeck/runtime/dispatch.py" = ["TID251"]
"agentdeck/runtime/service.py" = ["TID251"]
# The one executor that runs a body rather than bridging one: a native workflow parks mid-await,
# so its coroutine has to outlive the call that started it. Owned, not loose - the executor holds
# every parked body and `Executor.aclose()` cancels them (docs/patterns/lifecycle.md).
"agentdeck/adapters/executors/native/executor.py" = ["TID251"]
# A channel binding spawns its own tail task per inbound webhook and owns it: tracked in its own
# set, cancelled by its own stop() (docs/design/protocols/rulings.md 32), the same shape as the
# native executor's parked bodies above - never the runtime's, since a binding lives outside it.
"tests/bindings/fixture_plugin/channel.py" = ["TID251"]
"tests/bindings/test_agui_binding.py" = ["TID251"]
"tests/bindings/test_agui_client_conformance.py" = ["TID251"]
"tests/contract/test_store.py" = ["TID251"]
"tests/test_deck.py" = ["TID251"]
"tests/test_run_control.py" = ["TID251"]
"tests/test_runtime_service.py" = ["TID251"]
"tests/test_serve_compat.py" = ["TID251"]
[tool.ruff.lint.flake8-type-checking]
runtime-evaluated-base-classes = [
"pydantic.BaseModel",
"pydantic_settings.BaseSettings",
"agentdeck.runtime.settings.LayeredSettings",
]
[tool.pytest.ini_options]
asyncio_mode = "auto"
# Generous on purpose: a wedge detector, not a performance budget. Above the multiprocess suite's
# own 180s WORKER_TIMEOUT so a slow race never trips it, and `thread` rather than `signal` because
# what hangs here is a blocked `await`, which a signal handler never gets to interrupt.
timeout = 300
timeout_method = "thread"
# tests/contract imports contract_cases, tests/ imports concurrency_worker,
# tests/bindings imports fixture_plugin, and tests/test_generated_reference.py imports
# generate_docs_reference from scripts/; all four basenames are unique across these dirs,
# because a shared one collides on sys.modules. Explicit beats pytest's implicit basedir
# insertion, which would go ambiguous if tests/conftest.py appeared.
pythonpath = ["tests", "tests/contract", "tests/bindings", "scripts"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["agentdeck"]
[tool.ty.rules]
# optional-extra imports carry `ty: ignore[unresolved-import]` - "unused" or not
# depends on which extras the local venv has, so don't police it
unused-ignore-comment = "ignore"