Graph 10. Complete Reference — Fields, Error Codes, Safe Design Checklist
This document is the complete reference for the euleragent graph module. Use it as a
quick-reference guide for all concepts covered in the tutorials.
1. Graph YAML Complete Field Table
1.1 Top-Level Fields
| Field |
Type |
Required |
Description |
id |
string |
Y |
Graph identifier. Convention: graph.{name} |
version |
integer |
Y |
Graph version number (starting from 1) |
category |
string |
Y |
Category (research, engineering, marketing, etc.) |
description |
string |
Y |
Graph description |
checkpointer |
boolean/string |
Conditional |
Required when using interrupt_before/interrupt_after. One of true, "memory", "sqlite" |
state_schema |
dict |
Conditional |
Required when using parallel_groups |
parallel_groups |
list |
N |
List of parallel Fan-out/Fan-in groups |
defaults |
dict |
Y |
Execution constraints (includes max_iterations) |
nodes |
list |
Y |
List of nodes |
edges |
list |
Y |
List of edges |
finalize |
dict |
Y |
Final node configuration |
1.2 state_schema Fields
state_schema:
<key_name>:
type: string | integer | float | list | dict
merge: append_list | sum_int | concat_str | last_write | first_write
| Field |
Type |
Required |
Description |
type |
enum |
Y |
Data type of the state value |
merge |
enum |
Y |
Conflict resolution strategy (Reducer) for parallel writes |
1.3 parallel_groups Fields
parallel_groups:
- id: <group_id>
branches: [<node_id>, ...]
join: <join_node_id>
| Field |
Type |
Required |
Description |
id |
string |
Y |
Group identifier |
branches |
list[string] |
Y |
List of node IDs to execute in parallel (2 to 8) |
join |
string |
Y |
Fan-in join node ID |
1.4 defaults Fields
| Field |
Type |
Required |
Description |
max_iterations |
integer |
Required for loops |
Maximum execution count for the loop reference node |
max_total_tool_calls |
integer |
N |
Total tool call budget |
max_web_search_calls |
integer |
N |
Web search call budget |
1.5 nodes Fields (Graph-Specific Additional Fields)
Graph-specific fields added on top of all Pattern node fields:
| Field |
Type |
Required |
Description |
id |
string |
Y |
Node identifier (unique within the graph) |
kind |
enum |
Y |
llm, judge, finalize |
runner |
dict |
When kind=llm |
Execution mode configuration |
runner.mode |
enum |
Y |
plan, execute |
runner.force_tool |
string |
N |
Forced tool (web.search, file.write, shell.exec) |
runner.exclude_tools |
list |
N |
List of tools to exclude |
runner.min_proposals |
integer |
N |
Minimum number of proposals in plan mode |
runner.max_loops |
integer |
N |
Maximum internal retry count within a node |
judge |
dict |
When kind=judge |
Judge configuration |
judge.schema |
string |
Y |
Evaluation schema ID |
judge.route_values |
list |
Y |
List of possible routing values |
artifacts |
dict |
N |
Artifact configuration |
artifacts.primary |
string |
N |
Primary artifact filename |
guardrails |
dict |
N |
Tool usage constraints |
guardrails.tool_call_budget |
dict |
N |
Per-tool call count limits |
writes_state |
list |
Required for branches |
List of state_schema keys this node writes to. All keys must be declared in state_schema (raises STATE_UPDATE_OUTSIDE_DECLARED_WRITES if undeclared) |
reads_state |
list |
N |
List of state_schema keys this node reads. Undeclared keys produce a READS_STATE_UNKNOWN_KEY warning |
interrupt_before |
boolean |
N |
LangGraph Checkpoint pause before execution. Top-level checkpointer: required |
interrupt_after |
boolean |
N |
LangGraph Checkpoint pause after execution. Top-level checkpointer: required |
1.6 edges Fields
| Field |
Type |
Required |
Description |
from |
string |
Y |
Source node ID |
to |
string |
Y |
Target node ID (including finalize) |
when |
string |
Y |
Condition expression |
when condition expressions:
- "true" -- always proceed
- "approvals_resolved" -- after the HITL approval queue is cleared
- "judge.route == <value>" -- when the judge returns a specific value
1.7 finalize Fields
| Field |
Type |
Required |
Description |
artifact |
string |
Y |
Final artifact filename |
2. Pattern vs Graph Comparison Table
| Aspect |
Pattern |
Graph |
| YAML structure |
Identical |
Superset of Pattern |
| Execution engine |
euleragent sequential executor |
LangGraph StateGraph |
| state_schema |
None |
Added (required for parallel) |
| parallel_groups |
None |
Added (Fan-out/Fan-in) |
| interrupt_before/after |
None |
Added (Checkpoint-based) |
| Judge routing |
Runtime condition evaluation |
add_conditional_edges compilation |
| writes_state / reads_state |
None |
Added (parallel branch documentation) |
| graph_type (IR) |
"pattern" |
"graph" |
| CLI commands |
pattern validate/show |
graph validate/show/compile |
| Stability |
Stable |
Experimental |
| Parallel execution |
Not available |
Available |
| Intermediate state persistence |
Not available |
LangGraph Checkpointer |
3. Complete Error/Warning Code Table
3.1 Semantic Error Codes (New)
| # |
Error Code |
Trigger Condition |
Resolution |
| L |
INTERRUPT_REQUIRES_CHECKPOINTER |
Using interrupt_before/after without top-level checkpointer: |
Add checkpointer: memory |
| M |
STATE_UPDATE_OUTSIDE_DECLARED_WRITES |
Node's writes_state key is not in state_schema |
Add the key to state_schema or remove from writes_state |
| P3b |
PARALLEL_JOIN_IN_BRANCHES |
join node is included in its own branches list |
Remove the join node from branches |
3.2 Warning Codes (ok=True, Non-Blocking)
| # |
Warning Code |
Trigger Condition |
Recommended Action |
| N |
READS_STATE_UNKNOWN_KEY |
reads_state key is not in state_schema |
Check for typos or add to state_schema |
| P14 |
PARALLEL_ORDER_DEPENDENT_MERGE |
Using append_list in a parallel group |
Add source/rank fields to items and sort in the join |
3.3 Parallel Error Codes (14 Total)
| # |
Error Code |
Trigger Condition |
Resolution |
| 1 |
PARALLEL_JOIN_MISSING |
parallel_groups has no join |
Add join: <node_id> |
| 2 |
PARALLEL_JOIN_MULTIPLE |
A single group has 2 join entries |
Reduce to a single join |
| 3 |
PARALLEL_FANOUT_MISSING |
No Fan-out edge leading to a branch |
Add source -> branch edge |
| 4 |
PARALLEL_JOIN_EDGE_MISSING |
No branch -> join edge |
Add branch -> join edge |
| 5 |
PARALLEL_BRANCH_NOT_CONVERGING |
Branch does not converge to the join node |
Fix the Fan-in edges |
| 6 |
PARALLEL_STATE_SCHEMA_MISSING |
parallel_groups exists but state_schema is missing |
Add state_schema at the top level |
| 7 |
PARALLEL_STATE_KEY_MERGE_MISSING |
State key written by a branch has no merge strategy |
Add merge for the key in state_schema |
| 8 |
PARALLEL_NONDETERMINISTIC_MERGE |
Multiple branches share a last_write or first_write key |
Change to append_list, sum_int, or concat_str |
| 9 |
STATE_SCHEMA_MERGE_TYPE_MISMATCH |
Forbidden type+merge combination used |
Refer to the compatibility table and fix |
| 10 |
PARALLEL_SIDE_EFFECT_FORBIDDEN |
shell.exec/file.write as force_tool in a branch |
Perform in a node after the join |
| 11 |
PARALLEL_BRANCH_LIMIT_EXCEEDED |
9 or more branches |
Reduce to 8 or fewer |
| 12 |
PARALLEL_METADATA_DROPPED |
Branch node has no writes_state |
Explicitly add writes_state: [] |
| 13 |
PARALLEL_FINALIZE_BEFORE_JOIN |
Branch routes directly to finalize |
Change to route through join node -> finalize |
| 14 |
LANGGRAPH_COMPILE_FAILED |
LangGraph version mismatch or IR error |
Install LangGraph 1.0.9+, run euleragent doctor |
4. Type+Merge Compatibility Matrix
Cell symbols: O = Allowed, X = Forbidden (STATE_SCHEMA_MERGE_TYPE_MISMATCH), O = Recommended
| Type \ Merge |
append_list |
sum_int |
concat_str |
last_write |
first_write |
list |
O |
X |
X |
O |
O |
string |
X |
X |
O |
O |
O |
integer |
X |
O |
X |
O |
O |
float |
X |
X |
X |
O |
O |
dict |
X |
X |
X |
O |
O |
Bold: Recommended merge strategy for the given type
4.1 Recommended Combination Summary
# 병렬 결과 수집 (리스트) → append_list
findings:
type: list
merge: append_list
# 숫자 합산 → sum_int
count:
type: integer
merge: sum_int
# 텍스트 연결 (병렬) → concat_str
notes:
type: string
merge: concat_str
# 단일 노드 쓰기 → last_write
summary:
type: string # 또는 float, dict
merge: last_write
# 최초 쓰기 우선 → first_write
initial_value:
type: string # 또는 다른 타입
merge: first_write
5. Safe Parallel Design Checklist (16 Items)
Design Phase
□ 1. 진정한 병렬 실행이 필요한지 확인
순차로 충분하면 Pattern 사용 (더 단순하고 안정적)
□ 2. 브랜치 수 결정 (2~8개)
처음에는 2~3개로 시작하고 필요 시 확장
□ 3. state_schema 설계 완료
모든 브랜치의 writes_state 키 목록화
각 키의 type과 merge 전략 결정
□ 4. 공유 키(여러 브랜치가 씀) 식별
공유 list 키 → append_list
공유 integer 키 → sum_int
공유 string 키 → concat_str 또는 last_write(비결정론적 허용 시)
□ 5. 단일 브랜치 키 식별
단일 브랜치 키 → last_write (안전)
Declaration Phase
□ 6. state_schema 최상위에 선언
□ 7. parallel_groups 선언 (id, branches, join)
□ 8. 모든 브랜치 노드에 writes_state 선언
상태를 쓰지 않아도 writes_state: [] 명시
□ 9. 조인 노드에 reads_state 선언 (문서화)
□ 10. 팬아웃 엣지 선언 (소스 → 모든 브랜치)
□ 11. 팬인 엣지 선언 (모든 브랜치 → 조인 노드)
HITL 브랜치는 when: "approvals_resolved"
자율 브랜치는 when: "true"
□ 12. interrupt_before/after 사용 시 최상위 checkpointer: 선언
미선언 시 INTERRUPT_REQUIRES_CHECKPOINTER 에러 (정적 검증 실패)
최소: checkpointer: memory
Validation Phase
□ 13. euleragent graph validate 실행 및 통과 확인
□ 14. PARALLEL_NONDETERMINISTIC_MERGE / PARALLEL_ORDER_DEPENDENT_MERGE 경고 검토
비결정론적 결과 허용 여부 확인; append_list 시 source/rank 필드 고려
□ 15. euleragent graph compile로 IR 생성 및 검토
langgraph_builder 섹션에서 add_edges 확인
□ 16. 실험적 기능 사용 주의사항 재확인
00_disclaimer.md 참조
6. LangGraph StateGraph Compilation Details
This shows how each element of the Graph YAML maps to LangGraph methods.
6.1 Mapping Table
| Graph YAML Element |
LangGraph API |
state_schema (entire) |
StateGraph(TypedDict) type definition |
state_schema.*.merge: append_list |
Annotated[list, operator.add] |
state_schema.*.merge: sum_int |
Annotated[int, operator.add] |
state_schema.*.merge: concat_str |
Annotated[str, operator.add] |
state_schema.*.merge: last_write |
Default type (no annotation) |
state_schema.*.merge: first_write |
Custom first_write Reducer |
nodes[*] |
graph.add_node(id, fn) |
| First node |
graph.set_entry_point(id) |
finalize node |
graph.set_finish_point(id) |
edges[*] (when="true") |
graph.add_edge(from, to) |
edges[*] (when="judge.route==X") |
graph.add_conditional_edges(...) |
parallel_groups[*] |
Fan-out/Fan-in edges (multiple add_edge) |
interrupt_before: [...] |
graph.compile(interrupt_before=[...]) |
interrupt_after: [...] |
graph.compile(interrupt_after=[...]) |
defaults.max_iterations |
Runtime guard (outside LangGraph) |
6.2 Full Compilation Example (Conceptual Python Code)
The following shows how parallel_research_with_quality.yaml is transformed into LangGraph code.
from langgraph.graph import StateGraph, END
from typing import Annotated, TypedDict
import operator
# state_schema → TypedDict
class GraphState(TypedDict):
findings: Annotated[list, operator.add] # append_list
source_count: Annotated[int, operator.add] # sum_int
final_summary: str # last_write (기본)
route: str # judge 라우팅용 내부 키
# StateGraph 초기화
graph = StateGraph(GraphState)
# 노드 추가
graph.add_node("plan", plan_fn)
graph.add_node("web_search", web_search_fn)
graph.add_node("local_search", local_search_fn)
graph.add_node("doc_search", doc_search_fn)
graph.add_node("merge_findings", merge_findings_fn)
graph.add_node("evaluate", evaluate_fn)
graph.add_node("revise", revise_fn)
# 진입점
graph.set_entry_point("plan")
# 팬아웃 엣지 (plan → 브랜치들)
graph.add_edge("plan", "web_search")
graph.add_edge("plan", "local_search")
graph.add_edge("plan", "doc_search")
# 팬인 엣지 (브랜치들 → 조인)
graph.add_edge("web_search", "merge_findings")
graph.add_edge("local_search", "merge_findings")
graph.add_edge("doc_search", "merge_findings")
# 하류 엣지
graph.add_edge("merge_findings", "evaluate")
graph.add_edge("revise", "evaluate")
# Judge 조건부 엣지
def route_evaluate(state: GraphState) -> str:
return state.get("route", "finalize")
graph.add_conditional_edges(
"evaluate",
route_evaluate,
{"finalize": END, "revise": "revise"}
)
# 컴파일 (interrupt 없는 경우)
compiled = graph.compile()
# 또는 interrupt 있는 경우
compiled = graph.compile(
checkpointer=checkpointer,
interrupt_before=["publish"], # interrupt_before 노드 목록
interrupt_after=["draft"] # interrupt_after 노드 목록
)
6.3 first_write Reducer Implementation (Conceptual)
first_write is not a built-in LangGraph annotation, so it is implemented as a custom Reducer.
def first_write_reducer(old_value, new_value):
"""첫 번째 쓰기 값을 유지. None이면 new_value 사용."""
if old_value is None:
return new_value
return old_value # 이미 값이 있으면 새 값 무시
# TypedDict에서의 선언
class GraphState(TypedDict):
primary_result: Annotated[str, first_write_reducer]
7. Experimental Feature Usage Precautions Summary
Refer to 00_disclaimer.md for the full disclaimer.
7.1 Safety Level Classification
| Feature |
Safety Level |
Description |
| Linear Graph (no parallel) |
Stable |
Equivalent to Pattern |
| Judge routing |
Stable |
Equivalent behavior to Pattern |
| interrupt_before/after |
Experimental |
Depends on LangGraph version |
| 2-branch parallel_groups |
Experimental |
Basic validation complete |
| 3-8 branch parallel_groups |
Experimental |
Thorough testing required |
graph run command |
Experimental |
Some scenarios unverified |
7.2 Required Steps After Version Upgrades
# euleragent 또는 langgraph 업그레이드 후
pip install --upgrade euleragent langgraph
# 모든 Graph YAML 재검증
for yaml_file in examples/graphs/**/*.yaml; do
echo "검증: $yaml_file"
euleragent graph validate "$yaml_file"
done
# 컴파일된 IR 재생성
euleragent graph compile my_graph.yaml --out my_graph_compiled.json
7.3 Pre-Production Deployment Checklist
□ euleragent doctor 실행 → 모든 항목 통과 확인
□ graph validate 통과 (오류 0개)
□ graph validate --format json 출력에서 경고 검토
□ graph compile 성공
□ 스테이징 환경에서 10회 이상 반복 실행 테스트
□ 병렬 결과의 비결정론적 변동 허용 범위 확인
□ HITL 승인 워크플로우 테스트
□ interrupt hooks 재개 시나리오 테스트
□ 감사 로그 (approvals.jsonl, tool_calls.jsonl) 검토
□ 최대 비용 시나리오 계산 (max_iterations × max_total_tool_calls)
Quick Reference Card
CLI Commands
euleragent graph list # 그래프 목록
euleragent graph show <path> # 구조 보기
euleragent graph validate <path> # 검증
euleragent graph validate <path> --format json # JSON 형식 검증
euleragent graph compile <path> # IR 컴파일
euleragent graph compile <path> --out file.json # IR 파일로 저장
Minimal Parallel Graph Template
id: graph.template
version: 1
category: demo
description: 최소 병렬 그래프 템플릿
state_schema:
results:
type: list
merge: append_list
defaults:
max_iterations: 2
max_total_tool_calls: 30
parallel_groups:
- id: my_group
branches: [branch_a, branch_b]
join: join_node
nodes:
- id: source
kind: llm
runner: {mode: execute}
- id: branch_a
kind: llm
runner: {mode: execute}
writes_state: [results]
- id: branch_b
kind: llm
runner: {mode: execute}
writes_state: [results]
- id: join_node
kind: llm
runner: {mode: execute}
reads_state: [results]
artifacts:
primary: output.md
edges:
- {from: source, to: branch_a, when: "true"}
- {from: source, to: branch_b, when: "true"}
- {from: branch_a, to: join_node, when: "true"}
- {from: branch_b, to: join_node, when: "true"}
- {from: join_node, to: finalize, when: "true"}
finalize:
artifact: output.md
Previous: 09_parallel_with_quality.md | Table of Contents: README.md