-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathpyproject.toml
More file actions
523 lines (485 loc) · 20.3 KB
/
Copy pathpyproject.toml
File metadata and controls
523 lines (485 loc) · 20.3 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
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "contextweaver"
version = "0.16.0"
description = "Context firewall + tool router for MCP and tool-heavy AI agents"
readme = "README.md"
requires-python = ">=3.10"
license = { text = "Apache-2.0" }
authors = [{ name = "Diogo Santos", email = "diogofcul@hotmail.com" }]
keywords = [
"ai",
"agents",
"context",
"context-engineering",
"context-firewall",
"llm",
"tools",
"tool-routing",
"tool-heavy-agents",
"tool-router",
"mcp",
"mcp-gateway",
"tool-result-firewall",
"choicecards",
"prompt-budgeting",
"agent-infrastructure",
"routing",
]
classifiers = [
"Development Status :: 3 - Alpha",
"Framework :: AsyncIO",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Topic :: Software Development :: Libraries",
"Typing :: Typed",
]
# Core runtime dependencies. contextweaver opted into shipping the MCP SDK
# and ``jsonschema`` as core (rather than gating them behind optional extras)
# when the MCP proxy / gateway runtimes landed in v0.4: both are load-bearing
# for the gateway invocation contract (see ``docs/gateway_spec.md`` §4.4) and
# gating them behind extras forced every caller through a guarded-import
# dance. ``tiktoken``, ``PyYAML``, ``rank-bm25`` are broadly used in GenAI
# stacks (often already pulled in transitively) and unblock default behaviour
# the library would otherwise have to approximate. ``typer`` and ``rich``
# moved into core in v0.5 alongside the Typer CLI rewrite (#221) — the CLI
# is one of the project's primary user touchpoints and the ``_HAS_RICH``
# guarded-import dance had become its own maintenance burden. Other heavy
# or runtime-specific packages remain under [project.optional-dependencies].
dependencies = [
"tiktoken>=0.5",
"PyYAML>=6.0",
"rank-bm25>=0.2",
# Floor 1.19.0 (issue #356 floor-deps proof): mcp <1.19 returns content
# the live gateway suite cannot parse; in-memory transport changed
# wire format between 1.0 and 1.19.
"mcp>=1.19.0",
"jsonschema>=4.0",
# Floor 0.16.0 (issue #356 floor-deps proof): typer <0.16 breaks the
# CLI against modern click (8.2 made breaking changes); 0.16.0 is the
# lowest release that drives the Typer CLI cleanly on current click.
"typer>=0.16.0",
"rich>=13.0",
]
[project.urls]
Homepage = "https://github.com/dgenio/contextweaver"
Documentation = "https://dgenio.github.io/contextweaver"
Repository = "https://github.com/dgenio/contextweaver"
Changelog = "https://github.com/dgenio/contextweaver/blob/main/CHANGELOG.md"
Issues = "https://github.com/dgenio/contextweaver/issues"
Discussions = "https://github.com/dgenio/contextweaver/discussions"
[project.optional-dependencies]
# Dev / test toolchain. Includes weaver_contracts + jsonschema so the
# weaver-spec adapter (#143) and CI conformance check (#145) run on every PR
# without requiring the [weaver-spec] runtime extra. ``crewai`` and ``mem0ai``
# are pulled in so the CrewAI adapter (#193) and Mem0 external-memory backend
# (#195) are exercised against real upstream wire shapes on every CI run.
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.23.8",
"pytest-cov>=5.0",
"ruff>=0.4",
"mypy>=1.10",
"pre-commit>=3.7",
"weaver_contracts>=0.2,<1",
# 4.18 ships ``referencing`` — the conformance script's local $ref
# resolver depends on it (PR #201 review).
"jsonschema>=4.18",
"crewai>=0.80",
"mem0ai>=0.1",
# FastMCP is pulled into [dev] so the CodeMode discovery-tool integration
# test (``tests/test_adapters_fastmcp_discovery.py``) — which spins up a
# real in-memory FastMCP server — runs on every CI matrix cell. The
# ``[fastmcp]`` runtime extra below stays for end users who don't want
# the dev toolchain.
#
# Floor 2.12.0 (issue #356 floor-deps proof): fastmcp <2.12 uses the
# bare ``@server.tool`` (no-call) pattern which was removed in later
# pydantic/mcp releases. 2.12+ requires ``@server.tool()`` and is the
# lowest version compatible with the rest of the transitive stack.
"fastmcp>=2.12.0",
# LangGraph is pulled into [dev] so the LangGraph agent-loop reference
# architecture (``examples/architectures/langgraph_agent_loop``, issue
# #326) exercises the *real* ``StateGraph`` under ``make example`` in CI.
# The example also ships a hand-rolled fallback so it still runs without
# this dependency; the ``[langgraph]`` runtime extra below is for end
# users who want the framework without the dev toolchain.
#
# Floor 0.2.32 (PR #360 floor-deps proof): the langmem adapter test
# (``tests/test_extras_memory_langmem.py``) imports
# ``langgraph.store.memory.InMemoryStore``, which first appears in 0.2.32;
# ``>=0.2`` resolved to 0.2.17 and failed collection at lowest-direct.
"langgraph>=0.2.32",
# Remote-store backends (#426) are exercised in-process on every CI cell:
# fakeredis stands in for a Redis server and moto mocks the S3 API, so the
# conformance suite runs the Redis/S3 stores without a service container.
# ``redis`` / ``boto3`` are the real client libraries the backends import.
"redis>=5.0",
"fakeredis>=2.20",
"boto3>=1.34",
"moto[s3]>=5.0",
]
# weaver-spec contract adapter (https://github.com/dgenio/weaver-spec).
# Runtime extra for end users who want to interoperate with the canonical
# Weaver Stack contracts without pulling the full [dev] toolchain.
weaver-spec = [
"weaver_contracts>=0.2,<1",
]
# FastMCP adapter integration.
# Floor 2.12.0 — see rationale on the [dev] ``fastmcp`` entry (issue #356):
# <2.12 uses bare ``@server.tool`` (no-call) pattern; 2.12+ requires
# ``@server.tool()`` and is the lowest version compatible with the
# rest of the transitive stack.
fastmcp = [
"fastmcp>=2.12.0",
]
# CrewAI adapter integration (issue #193). Pulls the CrewAI runtime so user
# applications can import the live-discovery helper
# (``contextweaver.adapters.crewai.load_crewai_catalog``). The plain-dict
# conversion path (``crewai_tool_to_selectable`` / ``crewai_tools_to_catalog``)
# works without this extra installed.
crewai = [
"crewai>=0.80",
]
# Pydantic AI adapter integration (issue #272, child of #193). Pulls the
# pydantic-ai runtime so user applications can import the live-discovery
# helper ``contextweaver.adapters.pydantic_ai.load_pydantic_ai_catalog`` and
# the message round-trip helpers. Plain-dict / message-dict paths work
# without this extra installed.
pydantic-ai = [
"pydantic-ai>=0.0.20",
]
# smolagents adapter integration (issue #274, child of #193). Pulls the
# Hugging Face smolagents runtime so user applications can import the
# live-discovery helper ``contextweaver.adapters.smolagents.load_smolagents_catalog``
# and the ``from_smolagents_agent`` step-log ingestor. Plain-dict / step-dict
# paths work without this extra installed.
smolagents = [
"smolagents>=1.0",
]
# Agno adapter integration (issue #275, child of #193). Pulls the Agno
# (formerly Phidata) runtime so user applications can import the
# live-discovery helper ``contextweaver.adapters.agno.load_agno_catalog`` and
# the ``from_agno_session`` history ingestor. Plain-dict / message-dict paths
# work without this extra installed.
agno = [
"agno>=1.0",
]
# LangChain integration (issue #502). Pulls ``langchain-core`` so user
# applications can import the live-discovery helper
# ``contextweaver.adapters.langchain.load_langchain_catalog`` and convert real
# ``BaseTool`` instances. The plain-dict conversion path
# (``langchain_tool_to_selectable`` / ``langchain_tools_to_catalog``) works
# without this extra installed.
langchain = [
"langchain-core>=0.3",
]
# OpenAI Agents SDK adapter integration (issue #501). Pulls the
# ``openai-agents`` runtime (import package ``agents``) so user applications can
# import ``contextweaver.adapters.openai_agents.load_openai_agents_catalog`` and
# convert live ``FunctionTool`` instances / run items. The plain-dict and
# item-dict paths work without this extra installed.
openai-agents = [
"openai-agents>=0.1",
]
# Google ADK adapter integration (issue #547). Pulls the ``google-adk``
# runtime (import package ``google.adk``) so user applications can import
# ``contextweaver.adapters.google_adk.load_google_adk_catalog`` and convert live
# tools / session events. The plain-dict and event-dict paths work without this
# extra installed.
google-adk = [
"google-adk>=1.0",
]
# Microsoft Agent Framework adapter integration (issue #430). Pulls the
# ``agent-framework`` runtime (import package ``agent_framework``; successor to
# AutoGen / Semantic Kernel) so user applications can import
# ``contextweaver.adapters.agent_framework.load_agent_framework_catalog`` and
# convert live ``AIFunction`` tools / thread messages. The plain-dict and
# message-dict paths work without this extra installed; the OpenAPI
# (``adapters.openapi``) and Agent Skills (``adapters.agent_skills``) adapters
# need no extra at all — PyYAML and jsonschema are core dependencies.
agent-framework = [
"agent-framework>=1.0",
]
# LangGraph agent-loop reference architecture (issue #326). Pulls the
# LangGraph runtime so ``examples/architectures/langgraph_agent_loop`` can
# drive its route -> execute -> answer loop through a real ``StateGraph``.
# The example ships a hand-rolled fallback, so it runs without this extra;
# install it to exercise the framework path.
# Floor 0.2.32 — the langgraph store API (``langgraph.store.memory.InMemoryStore``)
# the langmem adapter/test relies on first appears in 0.2.32 (PR #360).
langgraph = [
"langgraph>=0.2.32",
]
# Real-time voice agents: Pipecat frame processors composed with the
# contextweaver context engine. Optional because pipecat-ai pulls heavy
# transitive deps (audio codecs, VAD models) — the
# ``examples/architectures/voice_agent`` script runs end-to-end without
# this extra installed; install only when you want to wire contextweaver
# into a real Pipecat ``FrameProcessor`` (see
# ``docs/integration_pipecat.md`` for the worked code).
voice = [
"pipecat-ai>=0.0.50",
]
# Docs site (mkdocs). The mkdocs-material major is pinned (`<10`) so a future
# 10.x breaking change cannot silently regress the docs build on a fresh `pip
# install -e ".[docs]"` (#256). Likewise for the mkdocstrings major. Bump the
# upper bound deliberately when adopting a new major.
docs = [
"mkdocs>=1.6,<2",
"mkdocs-material>=9.5,<10",
"mkdocstrings[python]>=0.25,<2",
"mkdocs-gen-files>=0.5,<1",
"mkdocs-literate-nav>=0.6,<1",
"mkdocs-section-index>=0.3,<1",
]
# Built-in token counting (issue #405). ``tiktoken`` is already a *core*
# dependency (see ``dependencies`` above), so ``contextweaver.tokens.count``
# resolves an exact tokenizer out of the box and degrades to the character
# heuristic when offline. This extras group is intentionally empty — it exists
# so callers can pin the tokenizer contract explicitly
# (``pip install 'contextweaver[tokenizers]'``) without changing the install
# surface, mirroring the no-op ``sqlite`` / ``e2e-eval`` groups.
tokenizers = []
# Fuzzy lexical retrieval backend (rapidfuzz) — supplements the default BM25
# scorer for typo / abbreviation tolerance.
retrieval = [
"rapidfuzz>=3.0",
]
# Embedding-based retrieval backend (#8). Activates
# :class:`contextweaver.extras.embeddings.SentenceTransformerBackend` and the
# Router's ``embedding_backend=`` kwarg. Heavy: pulls torch via
# sentence-transformers, so it stays optional.
embeddings = [
"sentence-transformers>=2.0",
]
# Persistent SQLite-backed stores (issues #174 / #223). The implementations
# rely only on stdlib ``sqlite3``; this extras group exists so installs can
# opt into a future ``aiosqlite``-based async variant or schema-migration
# tooling without changing the public install surface. Empty today on
# purpose — the contract is "if you want the SQLite stores, install this
# extra" even though it currently adds no third-party deps.
sqlite = []
# Redis-backed remote stores (issue #426): RedisEventLog + RedisArtifactStore
# for multi-process / long-lived gateways. Implementations import ``redis``
# lazily and raise a clear ConfigError if the extra is missing.
redis = [
"redis>=5.0",
]
# S3-compatible remote artifact store (issue #426): S3ArtifactStore over the
# S3 API (MinIO / R2 / GCS-interop). Imports ``boto3`` lazily; raises a clear
# ConfigError if the extra is missing.
s3 = [
"boto3>=1.34",
]
# External-memory backend interop (issue #195). Each backend implements the
# existing ``EpisodicStore`` / ``FactStore`` protocols from
# ``contextweaver.store.protocols`` without widening them. Adapters live
# under ``contextweaver.extras.memory.*``. Mem0, Zep, and LangMem are shipped
# against the same protocol surface; see ``docs/integration_memory.md``.
mem0 = [
"mem0ai>=0.1",
]
# Zep Cloud knowledge-graph memory. The adapter wraps a ``zep_cloud.Zep``
# client and persists episodes/facts via the graph API (``graph.add`` /
# ``graph.episode``). Pinned at >=2 because the graph client surface this
# adapter uses (``graph.add(type="json")``, ``graph.episode.get_by_user_id``)
# stabilised in the 2.x line.
zep = [
"zep-cloud>=2.0",
]
# LangMem / LangGraph long-term memory. The adapter wraps any LangGraph
# ``BaseStore`` (``langgraph.store.base``). ``langgraph>=0.2.32`` is pinned
# explicitly because the store API the adapter and its tests bind to — notably
# ``langgraph.store.memory.InMemoryStore`` used as the reference store — first
# appears in 0.2.32 (PR #360 floor-deps proof); a bare ``langmem>=0.0.1`` could
# otherwise resolve a too-old ``langgraph`` transitively.
langmem = [
"langmem>=0.0.1",
"langgraph>=0.2.32",
]
# OpenTelemetry tracing + metrics export with native GenAI semantic
# conventions (#224). Pinned at >=1.27 because the
# ``opentelemetry.semconv.attributes.gen_ai_attributes`` module landed in
# that release — older floors require hand-typing the attribute strings.
otel = [
"opentelemetry-api>=1.27",
"opentelemetry-sdk>=1.27",
"opentelemetry-semantic-conventions>=0.48b0",
]
# End-to-end real-model benchmark hook (issue #269). Empty today on purpose:
# the harness uses ``urllib.request`` against an OpenAI-compatible HTTP
# endpoint and does not need a vendor SDK. The extras group exists so
# callers can ``pip install 'contextweaver[e2e-eval]'`` to opt into the
# capture without changing the public install surface, and future
# additions (a benchmark-only ``openai`` SDK pin or alternative provider
# helpers) can land here without churning the install command in docs.
e2e-eval = []
# Convenience: install every optional capability at once.
all = [
"contextweaver[retrieval]",
"contextweaver[embeddings]",
"contextweaver[otel]",
"contextweaver[weaver-spec]",
"contextweaver[voice]",
"contextweaver[langgraph]",
"contextweaver[langchain]",
"contextweaver[openai-agents]",
"contextweaver[google-adk]",
"contextweaver[agent-framework]",
"contextweaver[e2e-eval]",
"contextweaver[redis]",
"contextweaver[s3]",
]
[project.scripts]
contextweaver = "contextweaver.__main__:main"
[tool.setuptools.packages.find]
where = ["src"]
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
pythonpath = ["."]
# Escalate contextweaver's *own* deprecations to errors so the suite proves
# that no in-repo code path (src, examples exercised under tests, the CLI)
# trips a first-party deprecation, and that intentional legacy-shim tests
# assert the warning explicitly via ``pytest.warns`` (issues #517 / #642).
# The message anchor (``contextweaver deprecation:`` — see ``_deprecation.py``)
# keeps unrelated third-party ``DeprecationWarning``s non-fatal.
filterwarnings = [
"error:contextweaver deprecation:DeprecationWarning",
]
[tool.ruff]
target-version = "py310"
line-length = 100
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "UP", "ANN", "B", "A", "SIM"]
[tool.mypy]
python_version = "3.10"
strict = true
warn_return_any = true
warn_unused_configs = true
mypy_path = "src"
[[tool.mypy.overrides]]
module = "tiktoken"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "fastmcp"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "crewai.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "pydantic_ai.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "smolagents.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "agno.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "mem0.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "zep_cloud.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "langgraph.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "rank_bm25"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "yaml"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "rapidfuzz.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "opentelemetry.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "sentence_transformers"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "rich.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "typer.*"
ignore_missing_imports = true
# ``referencing`` ships with jsonschema>=4.18 (a [dev] dep) and backs the
# weaver-spec conformance script's local $ref resolver; ``langchain_core`` is
# the [langchain] extra used by the LangChain memory demo. Both are optional
# from the type-check's perspective (examples/ and scripts/ are now gated,
# issue #539), so treat their imports as resolvable whether or not the extra
# is installed in the type-check environment.
[[tool.mypy.overrides]]
module = ["referencing", "referencing.*", "langchain_core", "langchain_core.*"]
ignore_missing_imports = true
# Typer's ``@app.command()`` decorator is typed as a generic callable in 0.9-
# 0.12, which trips ``disallow_untyped_decorators`` under strict mypy.
# Carve out the Typer consumers rather than disable the strictness globally.
# ``__main__`` is the top-level CLI; ``_mcp_cli`` backs the ``mcp`` sub-app
# mounted from ``__main__`` (issues #243/#246).
[[tool.mypy.overrides]]
module = ["contextweaver.__main__", "contextweaver._mcp_cli"]
disallow_untyped_decorators = false
# weaver_contracts does not ship a py.typed marker; treat as untyped for mypy
# while still being a real installed package the adapter can import.
[[tool.mypy.overrides]]
module = "weaver_contracts.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "mcp.*"
ignore_missing_imports = true
# numpy is a transitive [dev] dependency (chromadb / langgraph / crewai), not a
# direct one. numpy>=2.5 ships ``.pyi`` stubs that use PEP 695 ``type``
# statements, which mypy rejects under this project's ``python_version = "3.10"``
# target ("Type statement is only supported in Python 3.12 and greater") — a
# hard parse error that aborts the whole run even though no contextweaver code
# is numpy-typed. ``follow_imports = skip`` makes mypy treat numpy as ``Any``;
# ``follow_imports_for_stubs`` is required for the skip to apply to numpy's
# ``.pyi`` stubs (without it mypy still parses them and re-hits the error).
# Decouples the type gate from numpy's stub syntax. Revisit once a committed
# lockfile (#619) pins the dev toolchain.
[[tool.mypy.overrides]]
module = ["numpy", "numpy.*"]
follow_imports = "skip"
follow_imports_for_stubs = true
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "jsonschema.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "redis.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "boto3.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "botocore.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "fakeredis.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "moto.*"
ignore_missing_imports = true
[tool.coverage.run]
source = ["contextweaver"]
branch = true
[tool.coverage.report]
show_missing = true
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"if __name__ == ['\"]__main__['\"]",
]