update
This commit is contained in:
+241
-264
@@ -1,270 +1,247 @@
|
|||||||
# Agent Loop Diagram
|
Here's a cleaned-up version with proper alignment:
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ AGENT LOOP │
|
│ AGENT LOOP DIAGRAM │
|
||||||
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ 1. INITIALIZATION │
|
│ 1. INITIALIZATION │
|
||||||
│ ┌──────────────────────┐ │
|
│ │
|
||||||
│ │ Agent.start(prompt) │ │
|
│ Agent.start(prompt) │
|
||||||
│ └──────────┬───────────┘ │
|
│ │ │
|
||||||
│ │ │
|
│ ▼ │
|
||||||
│ ▼ │
|
│ normalizePrompt() ← Convert input (String/Message/Vector) to AgentMessage[] │
|
||||||
│ ┌──────────────────────┐ │
|
│ │ │
|
||||||
│ │ normalizePrompt() │ ← Convert input (String/Message/Vector) to AgentMessage[] │
|
│ ▼ │
|
||||||
│ └──────────┬───────────┘ │
|
│ runPromptMessages() │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ ┌──────────────────────┐ │
|
└─────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
│ │ runPromptMessages() │ │
|
│
|
||||||
│ └──────────┬───────────┘ │
|
▼
|
||||||
│ │ │
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ ▼ │
|
│ 2. AGENT LOOP START (agentLoop/runAgentLoop) │
|
||||||
│ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │
|
│ │
|
||||||
│ │ 2. AGENT LOOP START (agentLoop/runAgentLoop) │ │
|
│ emit(AgentStartEvent) │
|
||||||
│ │ │ │
|
│ emit(TurnStartEvent) │
|
||||||
│ │ emit(AgentStartEvent) │ │
|
│ │
|
||||||
│ │ emit(TurnStartEvent) │ │
|
│ for prompt in prompts: │
|
||||||
│ │ │ │
|
│ emit(MessageStartEvent(prompt)) │
|
||||||
│ │ for prompt in prompts: │ │
|
│ emit(MessageEndEvent(prompt)) │
|
||||||
│ │ emit(MessageStartEvent(prompt)) │ │
|
│ │
|
||||||
│ │ emit(MessageEndEvent(prompt)) │ │
|
│ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │
|
||||||
│ │ │ │
|
│ │ 3. MAIN LOOP (while true) │ │
|
||||||
│ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
|
│ │ │ │
|
||||||
│ │ │ 3. MAIN LOOP (while true) │ │ │
|
│ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
|
||||||
│ │ │ │ │ │
|
│ │ │ 4. PENDING MESSAGE HANDLING │ │ │
|
||||||
│ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ 4. PENDING MESSAGE HANDLING │ │ │ │
|
│ │ │ pending_messages = getSteeringMessages() │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ pending_messages = getSteeringMessages() │ │ │ │
|
│ │ │ while has pending_messages OR has_tool_calls: │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ while has pending_messages OR has_tool_calls: │ │ │ │
|
│ │ │ if pending_messages: │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ for msg in pending_messages: │ │ │
|
||||||
│ │ │ │ if pending_messages: │ │ │ │
|
│ │ │ emit(MessageStartEvent) │ │ │
|
||||||
│ │ │ │ for msg in pending_messages: │ │ │ │
|
│ │ │ emit(MessageEndEvent) │ │ │
|
||||||
│ │ │ │ emit(MessageStartEvent) │ │ │ │
|
│ │ │ push to context.messages │ │ │
|
||||||
│ │ │ │ emit(MessageEndEvent) │ │ │ │
|
│ │ │ pending_messages = [] │ │ │
|
||||||
│ │ │ │ push to context.messages │ │ │ │
|
│ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
|
||||||
│ │ │ │ pending_messages = [] │ │ │ │
|
│ │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
|
||||||
│ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │
|
│ │ │ 5. STREAM ASSISTANT RESPONSE │ │ │
|
||||||
│ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │
|
│ │ │ a) transform_context (if configured) │ │ │
|
||||||
│ │ │ │ 5. STREAM ASSISTANT RESPONSE │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ b) convert_to_llm(messages) │ │ │
|
||||||
│ │ │ │ a) transform_context (if configured) │ │ │ │
|
│ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ │ Converts AgentMessage[] to Message[] │ │ │ │
|
||||||
│ │ │ │ b) convert_to_llm(messages) │ │ │ │
|
│ │ │ │ (filters out compaction/branch summaries, converts bash/custom) │ │ │ │
|
||||||
│ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │
|
│ │ │ └───────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │
|
||||||
│ │ │ │ │ Converts AgentMessage[] to Message[] (filters out compaction/branch summaries, converts bash/custom) │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │
|
│ │ │ c) create Context(system_prompt, llm_messages, tools) │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ c) create Context(system_prompt, llm_messages, tools) │ │ │ │
|
│ │ │ d) stream_function(model, context, config) │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │
|
||||||
│ │ │ │ d) stream_function(model, context, config) │ │ │ │
|
│ │ │ │ LLM Stream Events: │ │ │ │
|
||||||
│ │ │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │
|
│ │ │ │ • start → create partial AssistantMessage │ │ │ │
|
||||||
│ │ │ │ │ LLM Stream Events: │ │ │ │ │
|
│ │ │ │ • text_start/delta/end → update partial message │ │ │ │
|
||||||
│ │ │ │ │ • start → create partial AssistantMessage │ │ │ │ │
|
│ │ │ │ • thinking_start/delta/end → update partial message │ │ │ │
|
||||||
│ │ │ │ │ • text_start/delta/end → update partial message │ │ │ │ │
|
│ │ │ │ • toolcall_start/delta/end → update partial message │ │ │ │
|
||||||
│ │ │ │ │ • thinking_start/delta/end → update partial message │ │ │ │ │
|
│ │ │ │ • done → finalize message │ │ │ │
|
||||||
│ │ │ │ │ • toolcall_start/delta/end → update partial message │ │ │ │ │
|
│ │ │ │ • error → handle error │ │ │ │
|
||||||
│ │ │ │ │ • done → finalize message │ │ │ │ │
|
│ │ │ └───────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │
|
||||||
│ │ │ │ │ • error → handle error │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │
|
│ │ │ e) emit(MessageStartEvent(final_message)) │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ f) emit(MessageEndEvent(final_message)) │ │ │
|
||||||
│ │ │ │ e) emit(MessageStartEvent(final_message)) │ │ │ │
|
│ │ │ g) push to context.messages & new_messages │ │ │
|
||||||
│ │ │ │ f) emit(MessageEndEvent(final_message)) │ │ │ │
|
│ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
|
||||||
│ │ │ │ g) push to context.messages & new_messages │ │ │ │
|
│ │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
|
||||||
│ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │
|
│ │ │ 6. CHECK STOP REASON │ │ │
|
||||||
│ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │
|
│ │ │ if stop_reason in ("error", "aborted"): │ │ │
|
||||||
│ │ │ │ 6. CHECK STOP REASON │ │ │ │
|
│ │ │ emit(TurnEndEvent) │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ emit(AgentEndEvent) ← EXIT LOOP │ │ │
|
||||||
│ │ │ │ if stop_reason in ("error", "aborted"): │ │ │ │
|
│ │ │ return │ │ │
|
||||||
│ │ │ │ emit(TurnEndEvent) │ │ │ │
|
│ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
|
||||||
│ │ │ │ emit(AgentEndEvent) ← EXIT LOOP │ │ │ │
|
│ │ │ │
|
||||||
│ │ │ │ return │ │ │ │
|
│ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ 7. EXTRACT TOOL CALLS │ │ │
|
||||||
│ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ │ │
|
│ │ │ tool_calls = filter(content, isa ToolCall) │ │ │
|
||||||
│ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ 7. EXTRACT TOOL CALLS │ │ │ │
|
│ │ │ if tool_calls: │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ tool_calls = filter(content, isa ToolCall) │ │ │ │
|
│ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ │ 8. EXECUTE TOOL CALLS │ │ │ │
|
||||||
│ │ │ │ if tool_calls: │ │ │ │
|
│ │ │ │ │ │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ │ if config.tool_execution == SEQUENTIAL OR has_sequential_tool: │ │ │ │
|
||||||
│ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │
|
│ │ │ │ executeToolCallsSequential() │ │ │ │
|
||||||
│ │ │ │ │ 8. EXECUTE TOOL CALLS │ │ │ │ │
|
│ │ │ │ else: │ │ │ │
|
||||||
│ │ │ │ │ │ │ │ │ │
|
│ │ │ │ executeToolCallsParallel() │ │ │ │
|
||||||
│ │ │ │ │ if config.tool_execution == SEQUENTIAL │ │ │ │ │
|
│ │ │ │ │ │ │ │
|
||||||
│ │ │ │ │ OR has_sequential_tool: │ │ │ │ │
|
│ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │
|
||||||
│ │ │ │ │ executeToolCallsSequential() │ │ │ │ │
|
│ │ │ │ │ For EACH tool_call: │ │ │ │ │
|
||||||
│ │ │ │ │ else: │ │ │ │ │
|
│ │ │ │ │ │ │ │ │ │
|
||||||
│ │ │ │ │ executeToolCallsParallel() │ │ │ │ │
|
│ │ │ │ │ emit(ToolExecutionStartEvent) │ │ │ │ │
|
||||||
│ │ │ │ │ │ │ │ │ │
|
│ │ │ │ │ │ │ │ │ │
|
||||||
│ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │
|
│ │ │ │ │ prepareToolCall(): │ │ │ │ │
|
||||||
│ │ │ │ │ │ For EACH tool_call: │ │ │ │ │ │
|
│ │ │ │ │ • Find tool by name │ │ │ │ │
|
||||||
│ │ │ │ │ │ │ │ │ │ │ │
|
│ │ │ │ │ • prepare_arguments (if configured) │ │ │ │ │
|
||||||
│ │ │ │ │ │ emit(ToolExecutionStartEvent) │ │ │ │ │ │
|
│ │ │ │ │ • validateToolArguments │ │ │ │ │
|
||||||
│ │ │ │ │ │ │ │ │ │ │ │
|
│ │ │ │ │ • before_tool_call hook (if configured) │ │ │ │ │
|
||||||
│ │ │ │ │ │ prepareToolCall(): │ │ │ │ │ │
|
│ │ │ │ │ └─→ PreparedToolCall("prepared") │ │ │ │ │
|
||||||
│ │ │ │ │ │ • Find tool by name │ │ │ │ │ │
|
│ │ │ │ │ or ImmediateToolCallOutcome("immediate") │ │ │ │ │
|
||||||
│ │ │ │ │ │ • prepare_arguments (if configured) │ │ │ │ │ │
|
│ │ │ │ │ │ │ │ │ │
|
||||||
│ │ │ │ │ │ • validateToolArguments │ │ │ │ │ │
|
│ │ │ │ │ if "immediate": │ │ │ │ │
|
||||||
│ │ │ │ │ │ • before_tool_call hook (if configured) │ │ │ │ │ │
|
│ │ │ │ │ FinalizedToolCallOutcome (synchronous tool) │ │ │ │ │
|
||||||
│ │ │ │ │ │ └─→ PreparedToolCall("prepared") or ImmediateToolCallOutcome("immediate") │ │ │ │ │ │
|
│ │ │ │ │ else: │ │ │ │ │
|
||||||
│ │ │ │ │ │ │ │ │ │ │ │
|
│ │ │ │ │ executePreparedToolCall() → ExecutedToolCallOutcome │ │ │ │ │
|
||||||
│ │ │ │ │ │ if "immediate": │ │ │ │ │ │
|
│ │ │ │ │ finalizeExecutedToolCall() (after_tool_call hook) │ │ │ │ │
|
||||||
│ │ │ │ │ │ FinalizedToolCallOutcome (synchronous tool) │ │ │ │ │ │
|
│ │ │ │ │ └─→ FinalizedToolCallOutcome │ │ │ │ │
|
||||||
│ │ │ │ │ │ else: │ │ │ │ │ │
|
│ │ │ │ │ │ │ │ │ │
|
||||||
│ │ │ │ │ │ executePreparedToolCall() → ExecutedToolCallOutcome │ │ │ │ │ │
|
│ │ │ │ │ emit(ToolExecutionEndEvent) │ │ │ │ │
|
||||||
│ │ │ │ │ │ finalizeExecutedToolCall() (after_tool_call hook) │ │ │ │ │ │
|
│ │ │ │ │ createToolResultMessage() │ │ │ │ │
|
||||||
│ │ │ │ │ │ └─→ FinalizedToolCallOutcome │ │ │ │ │ │
|
│ │ │ │ │ emitToolResultMessage() │ │ │ │ │
|
||||||
│ │ │ │ │ │ │ │ │ │ │ │
|
│ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │
|
||||||
│ │ │ │ │ │ emit(ToolExecutionEndEvent) │ │ │ │ │ │
|
│ │ │ │ │ │ │ │
|
||||||
│ │ │ │ │ │ createToolResultMessage() │ │ │ │ │ │
|
│ │ │ │ Append tool_result_messages to context.messages & new_messages │ │ │ │
|
||||||
│ │ │ │ │ │ emitToolResultMessage() │ │ │ │ │ │
|
│ │ │ └───────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │
|
||||||
│ │ │ │ │ │ │ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │
|
│ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
|
||||||
│ │ │ │ │ │ │ │ │ │
|
│ │ │ │
|
||||||
│ │ │ │ │ Append tool_result_messages to context.messages & new_messages │ │ │ │ │
|
│ │ emit(TurnEndEvent(message, tool_results)) │ │
|
||||||
│ │ │ │ │ │ │ │ │ │
|
│ │ │ │
|
||||||
│ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │
|
│ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ 9. PREPARE NEXT TURN │ │ │
|
||||||
│ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ │ │
|
│ │ │ next_turn_context = PrepareNextTurnContext( │ │ │
|
||||||
│ │ │ emit(TurnEndEvent(message, tool_results)) │ │ │
|
│ │ │ message, tool_results, current_context, new_messages │ │ │
|
||||||
│ │ │ │ │ │
|
│ │ │ ) │ │ │
|
||||||
│ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ 9. PREPARE NEXT TURN │ │ │ │
|
│ │ │ next_turn_snapshot = prepare_next_turn(config, next_turn_context) │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ next_turn_context = PrepareNextTurnContext( │ │ │ │
|
│ │ │ if !isnothing(next_turn_snapshot): │ │ │
|
||||||
│ │ │ │ message, tool_results, current_context, new_messages │ │ │ │
|
│ │ │ update context, model, thinking_level │ │ │
|
||||||
│ │ │ │ ) │ │ │ │
|
│ │ │ │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ if should_stop_after_turn(config, next_turn_context): │ │ │
|
||||||
│ │ │ │ next_turn_snapshot = prepare_next_turn(config, next_turn_context) │ │ │ │
|
│ │ │ emit(AgentEndEvent) ← EXIT LOOP │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ │ return │ │ │
|
||||||
│ │ │ │ if !isnothing(next_turn_snapshot): │ │ │ │
|
│ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
|
||||||
│ │ │ │ update context, model, thinking_level │ │ │ │
|
│ │ │ │
|
||||||
│ │ │ │ │ │ │ │
|
│ │ pending_messages = getSteeringMessages() ← Check for new steering messages │ │
|
||||||
│ │ │ │ if should_stop_after_turn(config, next_turn_context): │ │ │ │
|
│ │ │ │
|
||||||
│ │ │ │ emit(AgentEndEvent) ← EXIT LOOP │ │ │ │
|
│ └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │
|
||||||
│ │ │ │ return │ │ │ │
|
│ │
|
||||||
│ │ │ │ │ │ │ │
|
│ follow_up_messages = getFollowUpMessages() │
|
||||||
│ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │
|
│ │
|
||||||
│ │ │ │ │ │
|
│ if follow_up_messages: │
|
||||||
│ │ │ pending_messages = getSteeringMessages() ← Check for new steering messages │ │ │
|
│ pending_messages = follow_up_messages ← Continue loop to handle follow-ups │
|
||||||
│ │ │ │ │ │
|
│ continue │
|
||||||
│ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
|
│ │
|
||||||
│ │ │ │
|
│ break ← EXIT MAIN LOOP (no more pending messages) │
|
||||||
│ │ follow_up_messages = getFollowUpMessages() │ │
|
│ │
|
||||||
│ │ │ │
|
│ emit(AgentEndEvent(new_messages)) │
|
||||||
│ │ 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 │
|
│ HELPER STRUCTURES │
|
||||||
│ │
|
│ │
|
||||||
│ AgentMessage (union of): │
|
│ AgentMessage (union of): │
|
||||||
│ • UserMessage ("user") │
|
│ • UserMessage ("user") │
|
||||||
│ • AssistantMessage ("assistant") │
|
│ • AssistantMessage ("assistant") │
|
||||||
│ • ToolResultMessage ("toolResult") │
|
│ • ToolResultMessage ("toolResult") │
|
||||||
│ • BranchSummaryMessage ("branchSummary") - converted to UserMessage │
|
│ • BranchSummaryMessage ("branchSummary") - converted to UserMessage │
|
||||||
│ • CompactionSummaryMessage ("compactionSummary") - converted to UserMessage │
|
│ • CompactionSummaryMessage ("compactionSummary") - converted to UserMessage │
|
||||||
│ • BashExecutionMessage ("bash") - converted to UserMessage if not excluded │
|
│ • BashExecutionMessage ("bash") - converted to UserMessage if not excluded │
|
||||||
│ • CustomMessage ("custom") - converted to UserMessage │
|
│ • CustomMessage ("custom") - converted to UserMessage │
|
||||||
│ │
|
│ │
|
||||||
│ Message (LLM interface): │
|
│ Message (LLM interface): │
|
||||||
│ • UserMessage (role: "user") │
|
│ • UserMessage (role: "user") │
|
||||||
│ • AssistantMessage (role: "assistant") │
|
│ • AssistantMessage (role: "assistant") │
|
||||||
│ • ToolResultMessage (role: "toolResult") │
|
│ • ToolResultMessage (role: "toolResult") │
|
||||||
│ │
|
│ │
|
||||||
│ Steering vs Follow-up: │
|
│ Steering vs Follow-up: │
|
||||||
│ • Steering: Injected AFTER current assistant turn finishes (can continue conversation) │
|
│ • Steering: Injected AFTER current assistant turn finishes (can continue conversation) │
|
||||||
│ • Follow-up: Run ONLY after agent would otherwise stop (final messages) │
|
│ • Follow-up: Run ONLY after agent would otherwise stop (final messages) │
|
||||||
│ │
|
│ │
|
||||||
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ DATA FLOW SUMMARY │
|
|
||||||
│ │
|
|
||||||
│ User Input LLM Response │
|
|
||||||
│ │ convert_to_llm() │ │
|
|
||||||
│ ├───────────────────────────────────→ AgentMessage[] ──────────────→ Message[] ──────────→ │ ─────────────────→ AssistantMessage (streamed) │
|
|
||||||
│ │ (filter+convert) │ │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ │ ▼ │ │
|
|
||||||
│ │ Context (system_prompt, │ │
|
|
||||||
│ │ messages, tools) │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ stream_function() ─────────┤ ─────────→ LLM API │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ ▼ │
|
|
||||||
│ │ LLM Stream Events (text_delta, toolcall_delta, ...) │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ ▼ │
|
|
||||||
│ │ AssistantMessage (finalized) │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ ▼ │
|
|
||||||
│ │ check tool_calls? ──────────→ YES ────────────→ execute tools │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ │ NO │ │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ │ │ ▼ ▼
|
|
||||||
│ │ │ emit ToolResultMessage
|
|
||||||
│ │ │ │ │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ │ ▼ ▼
|
|
||||||
│ │ append to context.messages ────────────────────────────────→ ────→ next turn
|
|
||||||
│ │ │
|
|
||||||
│ │ ▼
|
|
||||||
│ │ check pending/follow-up
|
|
||||||
│ │ │
|
|
||||||
│ │ │
|
|
||||||
│ └─────────────────────────────────────────────────────────────────────────────────→ ────────────────────────────────────────────────────────────┘
|
|
||||||
│ (loop back to main loop or end)
|
|
||||||
│
|
|
||||||
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 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) │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Flow Points
|
|
||||||
|
|
||||||
1. **Input Normalization**: User input (String/Message/Vector) → AgentMessage[]
|
|
||||||
2. **LLM Boundary**: AgentMessage[] → Message[] (filtered, converted for LLM)
|
|
||||||
3. **Streaming**: LLM returns event stream → AssistantMessage (built incrementally)
|
|
||||||
4. **Tool Execution**:
|
|
||||||
- Extract ToolCall objects from AssistantMessage.content
|
|
||||||
- Execute in parallel (default) or sequential mode
|
|
||||||
- Emit ToolResultMessage for each
|
|
||||||
5. **Message Queues**:
|
|
||||||
- Steering: Injected between turns (keeps conversation going)
|
|
||||||
- Follow-up: Injected after agent stops (final messages)
|
|
||||||
6. **Context Updates**: All messages appended to context.messages for next iteration
|
|
||||||
7. **Loop Control**: Continue until no pending messages AND agent signals stop
|
|
||||||
|
|
||||||
## Hook Points
|
|
||||||
|
|
||||||
- `transform_context`: Modify messages before LLM call
|
|
||||||
- `convert_to_llm`: Transform AgentMessage[] to Message[]
|
|
||||||
- `before_tool_call`: Block or modify tool execution
|
|
||||||
- `after_tool_call`: Modify tool results
|
|
||||||
- `prepare_next_turn`: Update context/model/thinking level between turns
|
|
||||||
- `should_stop_after_turn`: Signal when agent should terminate
|
|
||||||
|
|||||||
Reference in New Issue
Block a user