Files
YiemAgent/docs/agent_loop_diagram.md
T
2026-07-28 11:09:22 +07:00

36 KiB

Here's a cleaned-up version with proper alignment:

┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                              AGENT LOOP DIAGRAM                                                 │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 1. INITIALIZATION                                                                                               │
│                                                                                                                 │
│   Agent.start(prompt)                                                                                           │
│         │                                                                                                       │
│         ▼                                                                                                       │
│   normalizePrompt() ← Convert input (String/Message/Vector) to AgentMessage[]                                   │
│         │                                                                                                       │
│         ▼                                                                                                       │
│   runPromptMessages()                                                                                           │
│         │                                                                                                       │
│         ▼                                                                                                       │
└─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┘
          │
          ▼
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 2. AGENT LOOP START (agentLoop/runAgentLoop)                                                                    │
│                                                                                                                 │
│   emit(AgentStartEvent)                                                                                         │
│   emit(TurnStartEvent)                                                                                          │
│                                                                                                                 │
│   for prompt in prompts:                                                                                        │
│     emit(MessageStartEvent(prompt))                                                                             │
│     emit(MessageEndEvent(prompt))                                                                               │
│                                                                                                                 │
│   ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │
│   │ 3. MAIN LOOP (while true)                                                                                 │ │
│   │                                                                                                           │ │
│   │   ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
│   │   │ 4. PENDING MESSAGE HANDLING                                                                         │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   pending_messages = getSteeringMessages()                                                          │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   while has pending_messages OR has_tool_calls:                                                     │ │ │
│   │   │                                                                                                     │ │ │
│   │   │     if pending_messages:                                                                            │ │ │
│   │   │       for msg in pending_messages:                                                                  │ │ │
│   │   │         emit(MessageStartEvent)                                                                     │ │ │
│   │   │         emit(MessageEndEvent)                                                                       │ │ │
│   │   │         push to context.messages                                                                    │ │ │
│   │   │       pending_messages = []                                                                         │ │ │
│   │   └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
│   │                                                                                                           │ │
│   │   ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
│   │   │ 5. STREAM ASSISTANT RESPONSE                                                                        │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   a) transform_context (if configured)                                                              │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   b) convert_to_llm(messages)                                                                       │ │ │
│   │   │      ┌───────────────────────────────────────────────────────────────────────────────────────────┐  │ │ │
│   │   │      │ Converts AgentMessage[] to Message[]                                                      │  │ │ │
│   │   │      │ (filters out compaction/branch summaries, converts bash/custom)                           │  │ │ │
│   │   │      └───────────────────────────────────────────────────────────────────────────────────────────┘  │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   c) create Context(system_prompt, llm_messages, tools)                                             │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   d) stream_function(model, context, config)                                                        │ │ │
│   │   │      ┌───────────────────────────────────────────────────────────────────────────────────────────┐  │ │ │
│   │   │      │ LLM Stream Events:                                                                        │  │ │ │
│   │   │      │   • start → create partial AssistantMessage                                               │  │ │ │
│   │   │      │   • text_start/delta/end → update partial message                                         │  │ │ │
│   │   │      │   • thinking_start/delta/end → update partial message                                     │  │ │ │
│   │   │      │   • toolcall_start/delta/end → update partial message                                     │  │ │ │
│   │   │      │   • done → finalize message                                                               │  │ │ │
│   │   │      │   • error → handle error                                                                  │  │ │ │
│   │   │      └───────────────────────────────────────────────────────────────────────────────────────────┘  │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   e) emit(MessageStartEvent(final_message))                                                         │ │ │
│   │   │   f) emit(MessageEndEvent(final_message))                                                           │ │ │
│   │   │   g) push to context.messages & new_messages                                                        │ │ │
│   │   └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
│   │                                                                                                           │ │
│   │   ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
│   │   │ 6. CHECK STOP REASON                                                                                │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   if stop_reason in ("error", "aborted"):                                                           │ │ │
│   │   │     emit(TurnEndEvent)                                                                              │ │ │
│   │   │     emit(AgentEndEvent) ← EXIT LOOP                                                                 │ │ │
│   │   │     return                                                                                          │ │ │
│   │   └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
│   │                                                                                                           │ │
│   │   ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
│   │   │ 7. EXTRACT TOOL CALLS                                                                               │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   tool_calls = filter(content, isa ToolCall)                                                        │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   if tool_calls:                                                                                    │ │ │
│   │   │                                                                                                     │ │ │
│   │   │     ┌───────────────────────────────────────────────────────────────────────────────────────────┐   │ │ │
│   │   │     │ 8. EXECUTE TOOL CALLS                                                                     │   │ │ │
│   │   │     │                                                                                           │   │ │ │
│   │   │     │   if config.tool_execution == SEQUENTIAL OR has_sequential_tool:                          │   │ │ │
│   │   │     │     executeToolCallsSequential()                                                          │   │ │ │
│   │   │     │   else:                                                                                   │   │ │ │
│   │   │     │     executeToolCallsParallel()                                                            │   │ │ │
│   │   │     │                                                                                           │   │ │ │
│   │   │     │   ┌─────────────────────────────────────────────────────────────────────────────────────┐ │   │ │ │
│   │   │     │   │ For EACH tool_call:                                                                 │ │   │ │ │
│   │   │     │   │                                                                                     │ │   │ │ │
│   │   │     │   │   emit(ToolExecutionStartEvent)                                                     │ │   │ │ │
│   │   │     │   │                                                                                     │ │   │ │ │
│   │   │     │   │   prepareToolCall():                                                                │ │   │ │ │
│   │   │     │   │     • Find tool by name                                                             │ │   │ │ │
│   │   │     │   │     • prepare_arguments (if configured)                                             │ │   │ │ │
│   │   │     │   │     • validateToolArguments                                                         │ │   │ │ │
│   │   │     │   │     • before_tool_call hook (if configured)                                         │ │   │ │ │
│   │   │     │   │     └─→ PreparedToolCall("prepared")                                                │ │   │ │ │
│   │   │     │   │         or ImmediateToolCallOutcome("immediate")                                    │ │   │ │ │
│   │   │     │   │                                                                                     │ │   │ │ │
│   │   │     │   │   if "immediate":                                                                   │ │   │ │ │
│   │   │     │   │     FinalizedToolCallOutcome (synchronous tool)                                     │ │   │ │ │
│   │   │     │   │   else:                                                                             │ │   │ │ │
│   │   │     │   │     executePreparedToolCall() → ExecutedToolCallOutcome                             │ │   │ │ │
│   │   │     │   │     finalizeExecutedToolCall() (after_tool_call hook)                               │ │   │ │ │
│   │   │     │   │     └─→ FinalizedToolCallOutcome                                                    │ │   │ │ │
│   │   │     │   │                                                                                     │ │   │ │ │
│   │   │     │   │   emit(ToolExecutionEndEvent)                                                       │ │   │ │ │
│   │   │     │   │   createToolResultMessage()                                                         │ │   │ │ │
│   │   │     │   │   emitToolResultMessage()                                                           │ │   │ │ │
│   │   │     │   └─────────────────────────────────────────────────────────────────────────────────────┘ │   │ │ │
│   │   │     │                                                                                           │   │ │ │
│   │   │     │   Append tool_result_messages to context.messages & new_messages                          │   │ │ │
│   │   │     └───────────────────────────────────────────────────────────────────────────────────────────┘   │ │ │
│   │   │                                                                                                     │ │ │
│   │   └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
│   │                                                                                                           │ │
│   │   emit(TurnEndEvent(message, tool_results))                                                               │ │
│   │                                                                                                           │ │
│   │   ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
│   │   │ 9. PREPARE NEXT TURN                                                                                │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   next_turn_context = PrepareNextTurnContext(                                                       │ │ │
│   │   │     message, tool_results, current_context, new_messages                                            │ │ │
│   │   │   )                                                                                                 │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   next_turn_snapshot = prepare_next_turn(config, next_turn_context)                                 │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   if !isnothing(next_turn_snapshot):                                                                │ │ │
│   │   │     update context, model, thinking_level                                                           │ │ │
│   │   │                                                                                                     │ │ │
│   │   │   if should_stop_after_turn(config, next_turn_context):                                             │ │ │
│   │   │     emit(AgentEndEvent) ← EXIT LOOP                                                                 │ │ │
│   │   │     return                                                                                          │ │ │
│   │   └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
│   │                                                                                                           │ │
│   │   pending_messages = getSteeringMessages() ← Check for new steering messages                              │ │
│   │                                                                                                           │ │
│   └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                                                 │
│   follow_up_messages = getFollowUpMessages()                                                                    │
│                                                                                                                 │
│   if follow_up_messages:                                                                                        │
│     pending_messages = follow_up_messages  ← Continue loop to handle follow-ups                                 │
│     continue                                                                                                    │
│                                                                                                                 │
│   break  ← EXIT MAIN LOOP (no more pending messages)                                                            │
│                                                                                                                 │
│   emit(AgentEndEvent(new_messages))                                                                             │
│                                                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ HELPER STRUCTURES                                                                                               │
│                                                                                                                 │
│   AgentMessage (union of):                                                                                      │
│     • UserMessage  ("user")                                                                                     │
│     • AssistantMessage  ("assistant")                                                                           │
│     • ToolResultMessage  ("toolResult")                                                                         │
│     • BranchSummaryMessage  ("branchSummary") - converted to UserMessage                                        │
│     • CompactionSummaryMessage  ("compactionSummary") - converted to UserMessage                                │
│     • BashExecutionMessage  ("bash") - converted to UserMessage if not excluded                                 │
│     • CustomMessage  ("custom") - converted to UserMessage                                                      │
│                                                                                                                 │
│   Message (LLM interface):                                                                                      │
│     • UserMessage  (role: "user")                                                                               │
│     • AssistantMessage  (role: "assistant")                                                                     │
│     • ToolResultMessage  (role: "toolResult")                                                                   │
│                                                                                                                 │
│   Steering vs Follow-up:                                                                                        │
│     • Steering: Injected AFTER current assistant turn finishes (can continue conversation)                      │
│     • Follow-up: Run ONLY after agent would otherwise stop (final messages)                                     │
│                                                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ DATA FLOW SUMMARY                                                                                               │
│                                                                                                                 │
│   User Input                              LLM Response                                                          │
│        │                                       │                                                                │
│        │                                       │                                                                │
│        ├──────────► AgentMessage[] ───────────►│                                                                │
│        │            (filter+convert)           │                                                                │
│        │                                       │                                                                │
│        │            convert_to_llm()           │                                                                │
│        ├──────────► Message[] ────────────────►│                                                                │
│        │                                       │                                                                │
│        │            Context                    │                                                                │
│        │            (system_prompt,            │                                                                │
│        │             messages, tools)          │                                                                │
│        ├──────────► stream_function() ────────►│                                                                │
│        │                                       │                                                                │
│        │                                       │                                                                │
│        │            LLM API                    │                                                                │
│        │                                       │                                                                │
│        │                                       ▼                                                                │
│        │            LLM Stream Events                                                                           │
│        │            (text_delta, toolcall_delta, ...)                                                           │
│        │                                       │                                                                │
│        │                                       ▼                                                                │
│        │            AssistantMessage (finalized)                                                                │
│        │                                       │                                                                │
│        │                                       ▼                                                                │
│        │                               check tool_calls?                                                        │
│        │                                 │           │                                                          │
│        │                                 │           │                                                          │
│        │                                YES          NO                                                         │
│        │                                 │           │                                                          │
│        │                                 ▼           │                                                          │
│        │                            execute tools    │                                                          │
│        │                                 │           │                                                          │
│        │                                 ▼           │                                                          │
│        │                       emit ToolResultMessage│                                                          │
│        │                                 │           │                                                          │
│        │                                 └─────┬─────┘                                                          │
│        │                                       │                                                                │
│        │                                       ▼                                                                │
│        │                            append to context.messages                                                  │
│        │                                       │                                                                │
│        │                                       ▼                                                                │
│        │                                 next turn                                                              │
│        │                                       │                                                                │
│        │                                       ▼                                                                │
│        │                            check pending/follow-up                                                     │
│        │                                       │                                                                │
│        │                                       ▼                                                                │
│        └───────────────────────────────────────┴───────────────────────────────────────────────────────────────►│
│                             (loop back to main loop or end)                                                     │
│                                                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘