-
Notifications
You must be signed in to change notification settings - Fork 714
Expand file tree
/
Copy pathpyproject.toml
More file actions
311 lines (290 loc) · 10.8 KB
/
Copy pathpyproject.toml
File metadata and controls
311 lines (290 loc) · 10.8 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
[project]
name = "intentkit"
version = "0.0.0"
description = "Intent-based AI Agent Platform - Core Package"
authors = [
{ name = "Ruihua", email = "ruihua@crestal.network" },
]
requires-python = "==3.13.*"
readme = "intentkit/README.md"
license = { file = "intentkit/LICENSE" }
dependencies = [
# AWS
"aws-secretsmanager-caching>=1.1.3",
"boto3>=1.37.23,<2.0.0",
"botocore>=1.35.97",
"mypy-boto3-s3>=1.37.24,<2.0.0",
# Web framework
"fastapi>=0.115.8",
"starlette>=0.47.1",
"httpx>=0.28.1",
# Only for the MCP transports: mcp 2.x is built on httpx2, so the client we
# hand to streamable_http_client has to be an httpx2 one. Everything else in
# the codebase stays on httpx.
"httpx2>=2.5.0",
"httpcore>=1.0.9",
"aiohttp>=3.14.0",
# Database
"psycopg>=3.2.9",
"psycopg-pool>=3.2.4",
"asyncpg>=0.30.0",
"aiosqlite>=0.21.0",
"sqlalchemy[asyncio]>=2.0.37",
# Schema migrations run automatically at startup (config/migration.py)
"alembic>=1.14.0",
# 8.x defaults socket_timeout/socket_connect_timeout to 5s and RESP3; we set
# both timeouts explicitly in config/redis.py so the bump changes nothing.
"redis>=8.0.1,<9.0.0",
# LangChain & LLM
"langchain>=1.3,<2",
"langchain-community>=0.4,<1",
"langchain-core>=1.4,<2",
"langchain-openai>=1.2,<2",
"langchain-text-splitters>=1.1,<2",
"langchain-deepseek>=1.0,<2",
"langchain-google-genai>=4.2,<5",
"langchain-anthropic>=1.4,<2",
"langchain-openrouter>=0.2.5,<1",
# Used directly for image generation (tools/image, core/avatar) and for its
# typed error classes; chat and usage accounting go through
# langchain-openrouter. Deliberately uncapped: langchain-openrouter already
# caps it at <1.0.0, so lifting that cap upstream lets us follow the 1.x
# line without editing this line.
"openrouter>=0.11.46",
"google-genai>=2.8.0",
"langgraph>=1.2,<2",
"langgraph-checkpoint>=4.1,<5",
"langgraph-checkpoint-postgres>=3.1,<4",
"langgraph-prebuilt>=1.1,<2",
"openai>=1.59.6",
"ormsgpack>=1.12.2",
# Blockchain / Web3
"cdp-sdk>=1.31.1",
"web3>=7.10.0",
"eth-abi>=5.0.0",
"eth-account>=0.13.7",
"eth-typing>=6.0.0",
"eth-utils>=2.1.0",
"hexbytes>=1.3.1",
"x402>=2.0.0",
# Social platforms
"slack-sdk>=3.34.0",
# Utilities
"cron-validator>=1.0.8,<2.0.0",
"epyxid>=0.3.3",
"filetype>=1.2.0,<2.0.0",
"pillow>=11.1.0,<13.0.0",
"pydantic>=2.10.6",
"python-dotenv>=1.0.1",
"pytz>=2025.1",
"pyyaml>=6.0.2",
# Scheduling (core/scheduler.py)
"apscheduler>=3.11.0",
# Utilities (direct imports of pydantic/web3 companions)
"cryptography>=48.0.0",
# Declared only because tools/base.py imports PydanticUndefined directly
# (deptry DEP003). pydantic pins pydantic-core exactly, so a tight floor
# here silently becomes a floor on pydantic itself and can outrank an AI
# SDK's own pydantic ceiling — keep it as loose as the API we use allows.
"pydantic-core>=2.33.1",
# MCP (Model Context Protocol)
# 2.x carries the 2026-07-28 spec revision, but keeps the pre-revision
# protocols alongside it (SUPPORTED_PROTOCOL_VERSIONS still spans
# 2024-11-05..2026-07-28) and keeps the SSE transport. ClientSession.
# initialize() deliberately negotiates LATEST_HANDSHAKE_VERSION, so our
# clients stay on the legacy handshake and old servers keep working.
"mcp>=2.0.0",
# Chinese A-share market data (cn_stock tool)
"akshare>=1.16.0",
"langfuse>=4.7,<5",
]
keywords = ["ai", "agent", "intent", "blockchain", "crypto"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
[project.optional-dependencies]
# PDF rendering (utils/pdf.py imports these lazily; weasyprint needs system
# pango/cairo, so it stays out of the default install)
pdf = [
"weasyprint>=63.0",
"markdown>=3.7",
"pymdown-extensions>=10.0",
]
# Ollama provider support (models/llm.py imports langchain_ollama lazily)
ollama = [
"langchain-ollama>=1.1,<2",
]
[project.urls]
Homepage = "https://github.com/crestalnetwork/intentkit"
Repository = "https://github.com/crestalnetwork/intentkit"
Documentation = "https://github.com/crestalnetwork/intentkit/tree/main/docs"
"Bug Tracker" = "https://github.com/crestalnetwork/intentkit/issues"
[dependency-groups]
# App runtime dependencies (app/ folder needs these beyond intentkit)
app = [
"gunicorn>=23.0.0",
"uvicorn>=0.34.0,<1.0.0",
"pydantic-settings>=2.8.1",
"python-multipart>=0.0.20",
"sentry-sdk[fastapi]>=2.20.0",
# PDF generation (the pdf extra, pinned identically)
"weasyprint>=63.0",
"markdown>=3.7",
"pymdown-extensions>=10.0",
"pyjwt>=2.13.0",
]
# Development-only dependencies (testing, linting, local dev tools)
dev = [
# Include app dependencies for local development
{ include-group = "app" },
# Testing
"pytest>=8.4.0",
"pytest-asyncio>=1.2.0",
"testing.postgresql",
# Linting and code quality (lint config inherits ruff 0.16's default rule set)
"ruff>=0.16.0",
"deptry>=0.23.0",
# Local LLM testing
"langchain-ollama>=1.1,<2",
"basedpyright>=1.39.7",
"import-linter>=2.11",
]
[tool.uv]
package = true
default-groups = ["dev"]
# Override bcl to >=3.0.0 because 2.x lacks Linux ARM64 (aarch64) wheels,
# causing source builds to fail on Python 3.13 (pkgutil.ImpImporter removed).
# bcl 3.0.0 has manylinux_2_17_aarch64 wheels that work on ARM64 Docker builds.
override-dependencies = ["bcl>=3.0.0"]
[tool.basedpyright]
# scripts/ holds one-off ops/migration scripts with loose typing; the
# autogenerated migration revisions are in the same category; not worth checking
exclude = ["scripts", "intentkit/migrations/versions", "**/node_modules", "**/__pycache__", "**/.*", "dist", "build"]
reportAny = false
reportExplicitAny = false
reportMissingTypeStubs = false
reportCallInDefaultInitializer = false
reportUnknownMemberType = false
reportUnknownVariableType = false
reportUnknownArgumentType = false
reportImplicitStringConcatenation = false
reportUnusedCallResult = false
reportMissingParameterType = false
reportUnknownParameterType = false
reportImplicitOverride = false
reportUnusedParameter = false
reportUnannotatedClassAttribute = false
reportUnknownLambdaType = false
reportMissingTypeArgument = false
reportUnnecessaryIsInstance = false
reportUnnecessaryComparison = false
# Tests legitimately reach into private members; keep those rules library-only
[[tool.basedpyright.executionEnvironments]]
root = "tests"
reportPrivateUsage = false
reportPrivateLocalImportUsage = false
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["intentkit"]
[tool.hatch.build.targets.sdist]
include = [
"intentkit",
"pyproject.toml",
]
[tool.ruff.format]
# Ruff 0.16 formats Python code blocks inside Markdown by default. Our docs use
# illustrative fragments (bare kwargs, partial function bodies), which the
# formatter rewrites into misleading full-module style — so keep .md as authored.
exclude = ["*.md"]
[tool.ruff.lint]
# Ruff 0.16 replaced the old E4/E7/E9/F default with a curated 413-rule set
# (partial-prefix subsets across ~35 groups). We inherit that default instead of
# pinning: new defaults from future ruff versions are adopted on upgrade, and
# anything we can't pass goes into `ignore` below with a reason.
extend-select = [
# The pre-0.16 pycodestyle baseline, no longer part of ruff's defaults.
"E4", "E7", "E9",
# Full isort (defaults only carry I001).
"I",
# Blocking subprocess/os calls in async defs; adopted pre-0.16 but not in
# the curated default set.
"ASYNC240", "ASYNC250",
]
ignore = [
# Broad `except Exception` is deliberate resilience in a tool-execution
# platform: agent/tool failures must degrade, never crash the run loop.
"BLE001",
# The whole repo (credit system, pricing, tools, tests — 300+ sites)
# uniformly uses the str constructor for Decimal (`Decimal("100")` and
# `Decimal("0.0001")` alike). FURB157 would rewrite only the int-valued
# ones, splitting the style in financial code.
"FURB157",
]
[tool.ruff.lint.flake8-bugbear]
# FastAPI's parameter markers are designed to be called in defaults.
extend-immutable-calls = [
"fastapi.Body",
"fastapi.Depends",
"fastapi.File",
"fastapi.Path",
"fastapi.Query",
]
[tool.ruff.lint.per-file-ignores]
# One-off ops/migration scripts run interactively from a shell; blocking I/O,
# prompts on the event loop, and naive local timestamps are fine there
# (scripts/ is likewise out of scope for deptry and basedpyright).
"scripts/*" = ["ASYNC", "LOG015", "DTZ"]
# Nested `with patch(...)` stacks mirror decorator stacking and read better
# than one parenthesized mega-with; naive datetimes are fine for fixture data;
# silently swallowed exceptions in best-effort test cleanup are fine too.
"tests/*" = ["SIM117", "DTZ", "S110", "S112"]
[tool.ruff.lint.isort]
force-single-line = false
known-first-party = ["intentkit"]
known-local-folder = ["app"]
section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"]
[tool.deptry]
known_first_party = ["intentkit"]
# scripts/ are one-off ops tools run in the dev env; tests run under dev deps;
# .claude may hold throwaway git worktrees (separate checkouts of this repo)
exclude = ["scripts", "tests", "frontend", "docs", "\\.venv", "\\.claude"]
[tool.deptry.per_rule_ignores]
# asyncpg/aiosqlite are loaded dynamically by SQLAlchemy as DB drivers;
# pymdown-extensions is loaded by name through the markdown extension registry
DEP002 = ["asyncpg", "aiosqlite", "pymdown-extensions"]
# app/ legitimately uses the app dependency group (deptry treats groups as dev)
DEP004 = ["sentry_sdk", "jwt"]
# Enforces the import dependency order documented in CLAUDE.md.
# Each layer may import the ones below it, never above.
[tool.importlinter]
root_package = "intentkit"
[[tool.importlinter.contracts]]
name = "intentkit layered architecture"
type = "layers"
layers = [
"intentkit.core",
"intentkit.tools",
"intentkit.wallets",
"intentkit.clients",
"intentkit.abstracts",
"intentkit.models",
"intentkit.config",
"intentkit.utils",
]
[tool.pytest.ini_options]
pythonpath = ["."]
testpaths = ["tests"]
markers = [
"bdd: mark test as BDD integration test",
"integration: hits live external APIs; excluded from the default CI run",
]
asyncio_default_fixture_loop_scope = "session"
asyncio_default_test_loop_scope = "session"