Closes the subgraph class derivation test gap by adding a parse() pipeline
test that verifies DOT subgraph labels produce correct CSS-like classes on
contained nodes. Updates gap analysis to remove resolved items, add spec
contradictions section, and narrow remaining gaps to SVG rendering and
retry predicate customization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Gap 1: Real preamble synthesis per fidelity mode (truncate, compact,
summary:low/medium/high) in new preamble.rs module, replacing placeholder
- Gap 2: Pass thread_id to CodergenBackend.run() so backends can reuse
LLM sessions across nodes sharing the same thread
- Gap 7: Engine cancellation via AtomicBool token checked between nodes,
wired to server cancel endpoint, new Cancelled error variant
- Gap 8: RecordingInterviewer serialization (to_json/from_json, file I/O)
and new ReplayInterviewer for replaying recorded Q&A sessions
- Gap 12: Preset retry policies selectable from DOT via retry_policy attr
(none, standard, aggressive, linear, patient)
- Gap 15: Engine calls Interviewer.inform() at pipeline start, stage
start, and stage complete lifecycle points
37 new tests (450 unit + 49 integration, all passing).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds the attractor crate implementing all 11 sections of the attractor spec:
- DOT parser (lexer, grammar, semantic analysis) for strict DOT subset
- Pipeline execution engine with edge selection, goal gates, retry logic,
failure routing, checkpoint save/resume, and loop_restart
- 9 node handlers: start, exit, codergen, wait_human, conditional, parallel
(concurrent with join/error policies), fan_in (with LLM eval), tool, manager_loop
- State management: PipelineContext, Outcome, Artifact store, fidelity resolution
- Human-in-the-loop: Interviewer trait with auto_approve, callback, queue,
recording, and console implementations, plus timeout enforcement
- Validation: 14 built-in lint rules with custom rule registration API
- Model stylesheet with universal/shape/class/ID selectors and specificity
- Transforms: variable expansion, stylesheet application, preamble; plus
PipelineBuilder with register_transform and prepare_pipeline
- Condition expression language with =, !=, bare-key truthiness, && combinator
- Event system with all 16 event types emitted by engine and handlers
- Tool call hooks (pre/post) for CodergenHandler
- Run directory with manifest.json and per-node status.json
370 tests (354 unit + 16 integration) covering all spec sections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract shared test infrastructure (MockExecutionEnvironment, TestProfile,
MockLlmProvider) replacing 11 duplicate mock implementations across tests
- Deduplicate tool execution logic between sequential and parallel paths
- Narrow ProviderProfile trait from 14 to 7 required methods via
ProfileCapabilities struct and default implementations
- Replace stringly-typed HashMap event data with typed EventData enum
- Extract shared assemble_system_prompt helper and register_subagent_tools
default method, eliminating copy-paste across all 3 profiles
- Replace fragile shell-based glob with glob crate, fix rg detection
- Add delete_file to ExecutionEnvironment, wire git context into env block
- Remove dead code (AgentError::Io, count_turns, trivial derived-trait tests)
- Use match-based lookups in truncation instead of per-call HashMap allocation
Net reduction: -1,401 lines across 20 files. All 180 tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add knowledge_cutoff() method to ProviderProfile trait so session can
populate EnvContext from the profile instead of leaving it empty
- Set subagent default max_turns to 50 per spec (was using session
factory default which could be 0/unlimited)
- Add corrected spec compliance review after manual verification found
the initial 5-agent review was largely false positives
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
resolve_model() was passing raw alias strings (e.g. "gpt5") directly to
APIs instead of resolving them to actual model IDs (e.g. "gpt-5.2").
Also rename gpt-5.2-mini to gpt-5-mini, which is the correct OpenAI
model ID.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Enforce stream_read timeout (30s default) in all 4 providers' streaming code
- Add with_timeout() builder method to all adapter constructors
- Fix ResponseFormatType::JsonObject to serialize as "json" per spec
- Add STEP_FINISH to StreamEventType enum in spec doc
- Add UnsupportedToolChoice error and enforce in all adapters via validate_tool_choice()
- Fix error classification to check status code before message content
- Add stop_sequences support to OpenAI Responses API adapter
- Handle Gemini thought parts (thought: true) in both complete and streaming paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parse x-ratelimit-* headers into RateLimitInfo for Anthropic, OpenAI, and
OpenAI-compatible providers (previously hardcoded to None)
- Add "not found"/"does not exist" and "unauthorized"/"invalid key" error
message classification patterns for ambiguous HTTP status codes
- Apply TimeoutConfig.total to wrap the entire multi-step generate() loop
(previously only per_step was used)
- Add metadata field to GenerateParams with builder method, pass through to
Request instead of hardcoding None
- Implement stream_object() for streaming structured output with incremental
JSON parsing via new ObjectStreamEvent type (Partial/Delta/Complete variants)
- Add OpenAI-compatible Chat Completions adapter for third-party endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>