update
This commit is contained in:
+116
-207
@@ -1,221 +1,130 @@
|
|||||||
# Agent Loop Sequence Diagram (ASCII)
|
# Agent Loop Sequence Diagram
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ ┌───────────┐
|
+---------+ +---------+ +------------+ +-------+ +-------+
|
||||||
│ User │─────>│ Agent │─────>│ AgentLoop │─────>│ LLM │
|
| User | | Agent | | AgentLoop | | LLM | | Tool |
|
||||||
└─────────────┘ └─────────────┘ └─────────────────┘ └───────────┘
|
+---------+ +---------+ +------------+ +-------+ +-------+
|
||||||
│
|
| | | | |
|
||||||
▼
|
| prompt(messages)| | | |
|
||||||
┌─────────────┐ ┌─────────────────┐ ┌───────────┐ ┌─────────────┐
|
|---------------->--> | | |
|
||||||
│ User │<─────│ AgentLoop │─────>│ Agent │─────>│ Session │
|
| | normalizePrompt()| | |
|
||||||
└─────────────┘ └─────────────────┘ └───────────┘ └─────────────┘
|
| |----------------->>| | |
|
||||||
│
|
| | runPromptMessages| | |
|
||||||
▼
|
| |----------------->>| | |
|
||||||
┌─────────────┐
|
| | | | |
|
||||||
│ Session │
|
| | createLoopConfig | | |
|
||||||
└─────────────┘
|
| |----------------->>| | |
|
||||||
|
| | | | |
|
||||||
┌─────────────────────────────────────────────────────────────────────────────────────────┐
|
| | agentLoop() | | |
|
||||||
│ AGENT LOOP MAIN FLOW │
|
| |----------------->>| | |
|
||||||
└─────────────────────────────────────────────────────────────────────────────────────────┘
|
| | | emit(AgentStart) | |
|
||||||
|
| | |------------------> | |
|
||||||
User
|
| | | | |
|
||||||
│
|
| | | transform_context() | |
|
||||||
│ prompt(messages)
|
| | |------------------> | |
|
||||||
▼
|
| | | convert_to_llm() | |
|
||||||
Agent
|
| | |------------------> | |
|
||||||
│
|
| | | stream_function() | |
|
||||||
│ normalizePromptInput()
|
| | |-------------------------> |
|
||||||
│ runPromptMessages()
|
| | | | response |
|
||||||
│
|
| | |<------------------------- |
|
||||||
├─ alt steering_queue has messages
|
| | | emit(MessageStart)| |
|
||||||
│ │ drain(steering_queue)
|
| | |------------------> | |
|
||||||
│ │ runPromptMessages()
|
| | | emit(MessageEnd) | |
|
||||||
│
|
| | |------------------> | |
|
||||||
├─ alt follow_up_queue has messages
|
| | | | |
|
||||||
│ │ drain(follow_up_queue)
|
| | | extract_tool_calls()| |
|
||||||
│ │ runPromptMessages()
|
| | |------------------> | |
|
||||||
│
|
| | | | |
|
||||||
└─ else (normal prompt)
|
| | | executeToolCalls() | |
|
||||||
│ createLoopConfig()
|
| | |-------------------------> |
|
||||||
│ createActiveRun()
|
| | | | execute() |
|
||||||
│
|
| | |-------------------------> |
|
||||||
▼
|
| | | | result |
|
||||||
AgentLoop
|
| | |<------------------------- |
|
||||||
│
|
| | | emit(ToolExecutionEnd)| |
|
||||||
│ agentLoop(messages, context, config)
|
| | |------------------> | |
|
||||||
│
|
| | | createToolResult() | |
|
||||||
▼
|
| | |------------------> | |
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
| | | emit(MessageEnd) | |
|
||||||
│ MAIN LOOP │
|
| | |------------------> | |
|
||||||
├─────────────────────────────────────────────────────────────┤
|
| | | | |
|
||||||
│ │
|
| | | emit(TurnEnd) | |
|
||||||
│ 1. Handle queued messages │
|
| | |------------------> | |
|
||||||
│ ├─ drain(steering_queue) │
|
| | | | |
|
||||||
│ ├─ emit(MessageStartEvent) │
|
| | | prepare_next_turn() | |
|
||||||
│ ├─ push to context.messages │
|
| | |------------------> | |
|
||||||
│ └─ emit(MessageEndEvent) │
|
| | | | |
|
||||||
│ │
|
| | | should_stop_check() | |
|
||||||
│ 2. Get LLM Response │
|
| | |------------------> | |
|
||||||
│ ├─ transform_context?(messages) │
|
| | | | |
|
||||||
│ ├─ convert_to_llm(messages) │
|
| | | drain(steering_queue)| |
|
||||||
│ └─ stream_function(model, context, config) │
|
| | |------------------> | |
|
||||||
│ │
|
| | | | |
|
||||||
│ LLM │
|
| | | drain(follow_up_queue)| |
|
||||||
│ │ response stream │
|
| | |------------------> | |
|
||||||
│ └─ emit(MessageStartEvent) │
|
| | | | |
|
||||||
│ └─ emit(MessageUpdateEvent) (streaming) │
|
| | emit(AgentEnd) | | |
|
||||||
│ └─ emit(MessageEndEvent(final_message)) │
|
| |------------------>| | |
|
||||||
│ │
|
| | | | |
|
||||||
│ 3. Check for Tool Calls │
|
| | appendMessage() | | |
|
||||||
│ └─ extract_tool_calls(message.content) │
|
| |------------------> Session | |
|
||||||
│ │
|
|<----------------| | | |
|
||||||
│ 4. Execute Tools (if any) │
|
| messages | | | |
|
||||||
│ ├─ emit(ToolExecutionStartEvent) │
|
| | | | |
|
||||||
│ ├─ prepareToolCall() │
|
|
||||||
│ │ ├─ before_tool_call? (block if needed) │
|
|
||||||
│ │ └─ validateToolArguments() │
|
|
||||||
│ ├─ execute(tool_call_id, args) │
|
|
||||||
│ │ Tool │
|
|
||||||
│ │ │ execute() │
|
|
||||||
│ │ └─ on_update(partial_result) │
|
|
||||||
│ ├─ emit(ToolExecutionEndEvent) │
|
|
||||||
│ └─ createToolResultMessage() │
|
|
||||||
│ │
|
|
||||||
│ 5. Emit Turn End Event │
|
|
||||||
│ └─ emit(TurnEndEvent(message, tool_results)) │
|
|
||||||
│ │
|
|
||||||
│ 6. Prepare Next Turn │
|
|
||||||
│ └─ prepare_next_turn(context) │
|
|
||||||
│ └─ AgentLoopTurnUpdate │
|
|
||||||
│ │
|
|
||||||
│ 7. Check Stop Condition │
|
|
||||||
│ └─ should_stop_after_turn? (break if true) │
|
|
||||||
│ │
|
|
||||||
│ 8. Get Steering/Follow-up Messages │
|
|
||||||
│ ├─ drain(steering_queue) │
|
|
||||||
│ └─ drain(follow_up_queue) │
|
|
||||||
│ │
|
|
||||||
│ 9. Continue or Break │
|
|
||||||
│ ├─ alt pending messages exist → continue loop │
|
|
||||||
│ └─ else → break │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────────┘
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
AgentLoop
|
|
||||||
│
|
|
||||||
│ emit(AgentEndEvent(messages))
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
Agent
|
|
||||||
│
|
|
||||||
│ appendMessage() → Session
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
User (via promise)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## KEY COMPONENTS
|
## Key Participants
|
||||||
|
|
||||||
### Agent Layer
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────────────────┐
|
|
||||||
│ Agent │
|
|
||||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ state: AgentState │ │
|
|
||||||
│ │ - system_prompt │ │
|
|
||||||
│ │ - model │ │
|
|
||||||
│ │ - messages[] │ │
|
|
||||||
│ │ - tools[] │ │
|
|
||||||
│ └──────────────────────────────────────────────────────────┘ │
|
|
||||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ Queues: │ │
|
|
||||||
│ │ - steering_queue: inject after assistant turn │ │
|
|
||||||
│ │ - follow_up_queue: run when agent stops │ │
|
|
||||||
│ └──────────────────────────────────────────────────────────┘ │
|
|
||||||
└──────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### AgentLoop Layer
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────────────────┐
|
|
||||||
│ AgentLoop │
|
|
||||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ agentLoop() │ │
|
|
||||||
│ │ - Main loop execution │ │
|
|
||||||
│ │ - Tool orchestration │ │
|
|
||||||
│ │ - Event emission │ │
|
|
||||||
│ └──────────────────────────────────────────────────────────┘ │
|
|
||||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ executeToolCallsSequential() │ │
|
|
||||||
│ │ executeToolCallsParallel() │ │
|
|
||||||
│ │ - Tool execution coordination │ │
|
|
||||||
│ │ - Hook invocation │ │
|
|
||||||
│ │ - Result collection │ │
|
|
||||||
│ └──────────────────────────────────────────────────────────┘ │
|
|
||||||
└──────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lifecycle Events Flow
|
|
||||||
```
|
|
||||||
AgentStartEvent
|
|
||||||
│
|
|
||||||
├─ TurnStartEvent
|
|
||||||
│ ├─ MessageStartEvent (user/assistant)
|
|
||||||
│ ├─ MessageEndEvent
|
|
||||||
│ ├─ ToolExecutionStartEvent
|
|
||||||
│ │ ├─ ToolExecutionUpdateEvent (streaming)
|
|
||||||
│ │ └─ ToolExecutionEndEvent
|
|
||||||
│ └─ TurnEndEvent
|
|
||||||
│
|
|
||||||
└─ AgentEndEvent (with final messages)
|
|
||||||
```
|
|
||||||
|
|
||||||
## QUEUE PROCESSING ORDER
|
|
||||||
|
|
||||||
1. **Initial steering messages** (if any)
|
|
||||||
2. **Main loop**:
|
|
||||||
- Steering/follow-up messages (if any)
|
|
||||||
- LLM call
|
|
||||||
- Tool execution (if any)
|
|
||||||
- Turn end event
|
|
||||||
- Next turn preparation
|
|
||||||
- Check stop condition
|
|
||||||
3. **Follow-up messages** (after loop exits, only if no steering)
|
|
||||||
|
|
||||||
## DATA FLOW
|
|
||||||
|
|
||||||
```
|
```
|
||||||
Input:
|
User - Initiates conversation by calling prompt()
|
||||||
User messages → Agent.normalizePromptInput() → AgentLoop
|
Agent - High-level wrapper managing state, queues, and events
|
||||||
|
AgentLoop - Low-level execution engine (agentLoop, runLoop)
|
||||||
LLM Call:
|
LLM - Language model API (via stream_function)
|
||||||
AgentMessage[] → transform_context() → convert_to_llm() →
|
Tool - Tool execution (bash, read, write, edit)
|
||||||
LLM.stream() → AssistantMessage
|
Session - Conversation history persistence
|
||||||
|
|
||||||
Tool Execution:
|
|
||||||
ToolCall[] → prepareToolCall() →
|
|
||||||
before_tool_call? → execute() → after_tool_call? →
|
|
||||||
ToolResultMessage[]
|
|
||||||
|
|
||||||
Output:
|
|
||||||
AgentEndEvent(messages) → Session.appendMessage() → User promise
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## EXECUTION MODES
|
## Main Loop Flow
|
||||||
|
|
||||||
### Sequential (EXECUTION_SEQUENTIAL)
|
|
||||||
```
|
```
|
||||||
ToolCall1 → ToolCall2 → ToolCall3
|
1. [Agent] normalizePromptInput() - Convert input to messages
|
||||||
│ │ │
|
2. [Agent] runPromptMessages() - Start processing
|
||||||
▼ ▼ ▼
|
3. [Agent] createLoopConfig() - Build loop configuration
|
||||||
Result1 Result2 Result3
|
4. [Agent] agentLoop() - Start low-level loop
|
||||||
|
5. [AgentLoop] emit(AgentStart) - Signal start
|
||||||
|
6. [AgentLoop] transform_context() - Optional context transform
|
||||||
|
7. [AgentLoop] convert_to_llm() - Convert to LLM messages
|
||||||
|
8. [AgentLoop] stream_function() - Call LLM
|
||||||
|
9. [AgentLoop] emit(MessageStart/End) - Stream response
|
||||||
|
10. [AgentLoop] extract_tool_calls() - Check for tool calls
|
||||||
|
11. [AgentLoop] executeToolCalls() - Execute tools (seq/parallel)
|
||||||
|
12. [AgentLoop] emit(TurnEnd) - Signal turn complete
|
||||||
|
13. [AgentLoop] prepare_next_turn() - Optional next turn setup
|
||||||
|
14. [AgentLoop] should_stop_check() - Check termination
|
||||||
|
15. [AgentLoop] drain queues() - Check steering/follow-up
|
||||||
|
16. [AgentLoop] emit(AgentEnd) - Signal completion
|
||||||
|
17. [Agent] appendMessage() - Persist to session
|
||||||
```
|
```
|
||||||
|
|
||||||
### Parallel (EXECUTION_PARALLEL)
|
## Queue Processing
|
||||||
|
|
||||||
```
|
```
|
||||||
ToolCall1 ─┐
|
steering_queue: Injected after assistant turn, before next LLM call
|
||||||
ToolCall2──┼→ Execute all → Wait for all → Results
|
follow_up_queue: Run only when agent would otherwise stop (after loop exit)
|
||||||
ToolCall3 ─┘
|
```
|
||||||
|
|
||||||
|
## Event Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
AgentStart → [TurnStart → MessageStart → MessageEnd → ...] → TurnEnd → ...
|
||||||
|
↓
|
||||||
|
AgentEnd
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tool Execution Options
|
||||||
|
|
||||||
|
```
|
||||||
|
Sequential: One tool at a time, in order
|
||||||
|
Parallel: All tools spawned concurrently, results collected
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user