feat: add ChainAnalyzer for offline schema-compatibility analysis (#77)#161
Open
dgenio wants to merge 1 commit into
Open
feat: add ChainAnalyzer for offline schema-compatibility analysis (#77)#161dgenio wants to merge 1 commit into
ChainAnalyzer for offline schema-compatibility analysis (#77)#161dgenio wants to merge 1 commit into
Conversation
) Closes #77. Introduces chainweaver/analyzer.py — the static "what *could* be compiled?" companion to the deterministic runtime. Given a set of Tool objects, ChainAnalyzer answers: - Pairwise compatibility — for each tool, which tools can directly follow it? (compatibility_matrix) - Chain enumeration — what N-step sequences are valid, optionally filtered by start/end tool? (find_chains) - Flow suggestion — promote discovered chains to ready-to-register Flow objects with auto-wired input_mapping. (suggest_flows) Compatibility rule: Tool A → Tool B is compatible iff every required field of B's input_schema appears in A's output_schema with an equal type annotation. Optional consumer fields (those with a Pydantic default) are tolerated when missing from A's output. Conservative by design — no coercion, no subtype inference. Invariants (mirrors the executor's three hard rules): - No LLM, no network, no randomness — pure-Python static pass. - Cycle-free enumeration: a tool may appear at most once per chain. - Depth-bounded: every traversal entry point requires max_depth. Public API additions (exported in __init__.py __all__): - ChainAnalyzer - ToolChain = tuple[str, ...] Tests: 23 cases in tests/test_analyzer.py covering compatibility matrix (empty / single / pair / 3-tool / type mismatch / optional vs required fields / duplicate-name rejection), find_chains (length-1, length-2/3, start/end filters, cycle guard, validation), suggest_flows (min_depth, auto-wiring, validation), and a performance sanity check (50 tools, max_depth=3 → 100k+ chains, <5s budget). Example: examples/chain_analyzer.py is runnable standalone and prints compatibility matrix + chain list + auto-suggested Flow for a 3-tool toy set. Docs: - AGENTS.md repo map gains chainweaver/analyzer.py. - docs/agent-context/architecture.md module-boundaries table adds the new module; Planned modules section moves #77 to delivered. Verification: $ ruff check chainweaver/ tests/ examples/ # All checks passed $ ruff format --check chainweaver/ tests/ ... # 54 files already formatted $ python -m mypy chainweaver/ tests/ # Success: no issues $ python -m pytest tests/ -q --no-cov # 527 passed in 2.01s Stacked on top of #160 (diff CLI); chains through #160 → #159 → #158 → #157 → main as those merge. The next PR in the cluster (#155 chainweaver suggest CLI) extends this module with suggest_optimizations() and adds the CLI surface. https://claude.ai/code/session_01QcSJ3NWhe5B4k1EP25Hx3n
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
chainweaver/analyzer.py— the static "what could be compiled?" companion to the deterministic runtime. Given a set ofToolobjects,ChainAnalyzeranswers three questions: pairwise compatibility, chain enumeration, and flow suggestion. Pure-Python, no LLM, no I/O.This is the foundation for the next PR in the cluster (#155
chainweaver suggestCLI), which extends this module withsuggest_optimizations()and adds a CLI verb.Stacked on top of #160 (diff CLI); base cascades through
#160 → #159 → #158 → #157 → mainas those merge.Closes #77.
Changes
chainweaver/analyzer.py— new module (~260 LoC).ChainAnalyzerclass +ToolChaintype alias + three private helpers (_schema_field_types,_is_compatible,_auto_input_mapping). Replaces the entry inarchitecture.md§ Planned modules.chainweaver/__init__.py— exportsChainAnalyzerandToolChainvia__all__.tests/test_analyzer.py— new, 23 test cases.examples/chain_analyzer.py— runnable standalone demo.AGENTS.md— repo-map row added.docs/agent-context/architecture.md— module-boundaries table row added;analyzer.pymoves from "Planned" to "delivered."Compatibility rule
Tool A → Tool Bis compatible iff every required field of B'sinput_schemaappears in A'soutput_schemawith an equal type annotation. Optional consumer fields (those with a Pydantic default) are tolerated when missing. Conservative — no coercion, no subtype inference.Invariants
Mirrors the executor's three hard rules — analyzer is invoked offline, but the discipline still applies:
max_depth.Public API
Testing
ruff check chainweaver/ tests/ examples/)ruff format --check chainweaver/ tests/ examples/)python -m mypy chainweaver/ tests/)The performance sanity check in
tests/test_analyzer.py::TestPerformanceruns 50 tools atmax_depth=3→ ~117 k chains in well under the issue's 1-second bar (the test allows up to 5 s for slow CI hosts).Diff stat:
6 files changed, 773 insertions(+), 1 deletion(-)(analyzer module + tests + example + docs).Related Issues
Closes #77. The companion
chainweaver suggestCLI (#155) lands as the next PR in this stack and extendsanalyzer.pywithsuggest_optimizations().Checklist
AGENTS.mdanddocs/agent-context/)ChainAnalyzer+ToolChainexported in__all__; AGENTS.md + architecture.md updated in same PRTradeoffs / risks
typing.List[int]vslist[int]on Python ≥ 3.9) won't compose. Pydantic v2 normalizes these inmodel_fields, so in practice it's rarely an issue — but worth calling out. A future enhancement could computepydantic.TypeAdapterequivalence.doubleproducesvalue;add_tenconsumesvalue— that works. But if a tool producesresult_valueand another consumesvalue, the analyzer won't connect them. The issue body explicitly scopes this to name-equality; semantic similarity (embeddings, aliases) is out of scope.suggest_flows()returnsFlow.version="0.0.0". Auto-generated flows should not be confused with real registered flows, so they ship with a deliberately invalid-looking version that signals "review me before promoting."architecture.mdreservedanalyzer.pyfor Offline computation of valid tool combinations from schemas #77; this PR delivers it and updates the reservation table. The forthcoming Addchainweaver suggest <flow>static optimizer (coordinates with #77) #155 (suggestCLI) coordinates scope by extending the same module.Scope notes
Closes #77 only. The "candidate flow proposal from traces" stretch idea on #12 is intentionally not bundled here —
analyzer.py's public surface stays focused on schema-time analysis. #155 will addsuggest_optimizations(flow, traces=None)as a sibling capability.https://claude.ai/code/session_01QcSJ3NWhe5B4k1EP25Hx3n
Generated by Claude Code