3.6 KiB
3.6 KiB
Story 4.1: Dynamischer Graph-Builder aus Blueprint-JSON
Status: done
Story
Als Backend-Entwickler,
möchte ich dynamic_graph_builder.py,
so dass er aus einem Blueprint-JSON zur Laufzeit einen kompilierten LangGraph-Graphen baut, der Zyklen korrekt erhält.
Acceptance Criteria
- Valides Blueprint-JSON mit N Nodes → kompilierter
StateGraph - Blueprint mit Zyklus (A→B→A, bedingt) → Graph kompiliert, Zyklus erhalten
- Blueprint mit nicht-existenter Node-ID in Edge →
ValueErrormit sprechender Fehlermeldung - Blueprint mit 0 Nodes →
ValueError - Blueprint mit 2 Nodes, 0 Edges →
ValueError - Bedingte Edge mit
condition-Label wird korrekt als conditional edge verdrahtet - Nodes mit
tools.web_search = truebekommen Tavily-Tool gebunden - Nodes mit
tools.pdf_reader = truebekommen PDF-Search-Tool gebunden
Tasks / Subtasks
- Task 1: Blueprint-JSON-Schema validieren (AC: 3, 4, 5)
- Subtask 1.1: Prüfen ob
nodesnicht leer - Subtask 1.2: Alle Edge
source/targetIDs auf Existenz innodesprüfen - Subtask 1.3: Sicherstellen ≥1 Edge vorhanden
- Subtask 1.1: Prüfen ob
- Task 2: Node-Funktionen dynamisch erzeugen (AC: 1, 7, 8)
- Subtask 2.1: Agent-Node-Fabrik mit konfigurierbarem System-Prompt und Modell
- Subtask 2.2: Tool-Binding für web_search/pdf_reader
- Task 3: Graph-Topologie aufbauen (AC: 1, 2, 6)
- Subtask 3.1: Entry-Point = erster Node ohne eingehende Edges
- Subtask 3.2: Lineare Edges als
add_edge - Subtask 3.3: Bedingte Edges als
add_conditional_edgesmit Routing-Funktion
- Task 4: God-Mode-Unterstützung via
interrupt_before(AC für Story 5.3)- Subtask 4.1:
interrupt_before=node_idsbeim Kompilieren setzen
- Subtask 4.1:
- Task 5: Unit-Tests (AC: 1–6)
- Subtask 5.1: Test valides Blueprint
- Subtask 5.2: Test Blueprint mit Zyklus
- Subtask 5.3: Test Blueprint mit ungültiger Edge (ValueError)
- Subtask 5.4: Test Blueprint mit 0 Nodes (ValueError)
Dev Notes
- Zyklen sind First-Class: Niemals den Graphen zu einem DAG vereinfachen.
- Entry-Point-Erkennung: Node ohne eingehende Edges = Startpunkt. Bei Zyklen: erster Node in
nodes-Array. - Routing-Funktion: Dynamisch erzeugte Closure über
route_decision-State-Feld. - Bezug:
backend/state.py,backend/services/graph_builder.py(Phase-1-Referenz)
Project Structure Notes
- Implementiert in:
backend/services/dynamic_graph_builder.py - Tests in:
backend/tests/test_dynamic_graph_builder.py - Nutzt:
backend/tools/web_search.py,backend/tools/pdf_reader.py
References
- [Source: _bmad-output/planning-artifacts/architecture.md#ADR-004] — Dynamischer Graph-Builder
- [Source: _bmad-output/planning-artifacts/architecture.md#Blueprint-JSON-Schema] — Datenformat
- [Source: _bmad-output/planning-artifacts/epics.md#Story-4.1] — ACs
- [Source: CLAUDE.md#Key Design Constraints] — Zyklen sind First-Class
Dev Agent Record
Agent Model Used
Amelia (💻 BMAD Dev Agent) — dev-story workflow
Completion Notes List
- Entry-Point-Erkennung via Set-Differenz:
{alle Node-IDs} - {IDs die als Edge-Target vorkommen} - Routing-Closure für bedingte Edges:
lambda state: state.get("route_decision", "rework") interrupt_beforewird als Liste aller Node-IDs gesetzt wenngod_mode=True
File List
backend/services/dynamic_graph_builder.pybackend/tests/test_dynamic_graph_builder.py