Compare commits

..

2 Commits

Author SHA1 Message Date
ton a0787c2316 update 2026-07-29 13:52:02 +07:00
ton 8fd72f8d37 ีupdate 2026-07-29 13:50:00 +07:00
8 changed files with 288 additions and 288 deletions
+74 -74
View File
@@ -22,9 +22,9 @@
│ 2. AGENT LOOP START (runAgentLoop) │ │ 2. AGENT LOOP START (runAgentLoop) │
│ │ │ │
│ new_messages = copy(prompts) │ │ new_messages = copy(prompts) │
│ current_context.messages = vcat(context.messages, copy(prompts)) │ │ current_context.messages = vcat(context.messages, copy(prompts))
│ │ │ │ │ │
│ └─→ User messages are IMMEDIATELY added to context.messages │ │ └─→ User messages are IMMEDIATELY added to context.messages
│ (They are NOT in the steering queue!) │ │ (They are NOT in the steering queue!) │
│ │ │ │
│ emit(AgentStartEvent) │ │ emit(AgentStartEvent) │
@@ -42,7 +42,7 @@
│ │ │ │
│ pending_messages = get_steering_messages() │ │ pending_messages = get_steering_messages() │
│ │ │ │ │ │
│ └─→ Steering queue: messages from agent.steer() │ │ └─→ Steering queue: messages from agent.steer()
│ These are for CONTINUING conversation (NOT new user prompts) │ │ These are for CONTINUING conversation (NOT new user prompts) │
│ │ │ │
│ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │
@@ -51,17 +51,17 @@
│ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ 4. PENDING MESSAGE HANDLING (steering messages only) │ │ │ │ │ │ 4. PENDING MESSAGE HANDLING (steering messages only) │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ pending_messages = get_steering() │ │ │ │ │ │ pending_messages = get_steering() │ │ │
│ │ │ if !isempty(pending_messages): │ │ │ │ │ │ if !isempty(pending_messages): │ │ │
│ │ │ for msg in pending_messages: │ │ │ │ │ │ for msg in pending_messages: │ │ │
│ │ │ emit(MessageStartEvent(msg)) │ │ │ │ │ │ emit(MessageStartEvent(msg)) │ │ │
│ │ │ emit(MessageEndEvent(msg)) │ │ │ │ │ │ emit(MessageEndEvent(msg)) │ │ │
│ │ │ push to current_context.messages ← Steering messages go HERE │ │ │ │ │ │ push to current_context.messages ← Steering messages go HERE │ │ │
│ │ │ push to new_messages │ │ │ │ │ │ push to new_messages │ │ │
│ │ │ pending_messages = [] │ │ │ │ │ │ pending_messages = [] │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ Note: User messages from Agent.prompt() are ALREADY in context.messages │ │ │ │ │ │ Note: User messages from Agent.prompt() are ALREADY in context.messages │ │ │
│ │ │ (They were added in runAgentLoop via vcat(), not via this queue) │ │ │ │ │ │ (They were added in runAgentLoop via vcat(), not via this queue) │ │ │
│ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │ │ │ │
│ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │
@@ -168,7 +168,7 @@
│ new_messages = [UserMessage("What is Julia?")] │ │ new_messages = [UserMessage("What is Julia?")] │
│ current_context.messages = vcat([...existing...], [UserMessage("What is Julia?")]) │ │ current_context.messages = vcat([...existing...], [UserMessage("What is Julia?")]) │
│ │ │ │ │ │
│ └─→ User message IMMEDIATELY added to context.messages (NOT via steering queue!) │ │ └─→ User message IMMEDIATELY added to context.messages (NOT via steering queue!)
│ emit(AgentStartEvent), emit(TurnStartEvent) │ │ emit(AgentStartEvent), emit(TurnStartEvent) │
│ emit(MessageStart/End) for user message │ │ emit(MessageStart/End) for user message │
│ │ │ │
@@ -207,11 +207,11 @@
│ │ follow_up_queue: [] │ │ │ │ follow_up_queue: [] │ │
│ └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │ │
│ LLM SEES (convert_to_llm() filters): │ LLM SEES (convert_to_llm() filters):
│ ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
│ │ Messages passed to LLM API: │ │ │ │ Messages passed to LLM API: │
│ │ [UserMessage("What is Julia?"), AssistantMessage("Julia is...")] │ │ [UserMessage("What is Julia?"), AssistantMessage("Julia is...")]
│ └─────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────┘
│ │ │ │
│ TURN #2: User asks "How does it work?" │ │ TURN #2: User asks "How does it work?" │
│ ───────────────────────────────────────── │ │ ───────────────────────────────────────── │
@@ -223,7 +223,7 @@
│ new_messages = [UserMessage("How does it work?")] │ │ new_messages = [UserMessage("How does it work?")] │
│ current_context.messages = vcat([...previous..., UserMessage("How does it work?")]) │ │ current_context.messages = vcat([...previous..., UserMessage("How does it work?")]) │
│ │ │ │ │ │
│ └─→ User message added (context preserved from Turn #1) │ │ └─→ User message added (context preserved from Turn #1)
│ emit(AgentStartEvent), emit(TurnStartEvent) │ │ emit(AgentStartEvent), emit(TurnStartEvent) │
│ emit(MessageStart/End) for user message │ │ emit(MessageStart/End) for user message │
│ │ │ │
@@ -245,13 +245,13 @@
│ └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │ │
│ LLM SEES: │ │ LLM SEES: │
│ ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
│ │ Messages passed to LLM API: │ │ │ │ Messages passed to LLM API: │
│ │ [UserMessage("What is Julia?"), │ │ [UserMessage("What is Julia?"),
│ │ AssistantMessage("Julia is..."), │ │ AssistantMessage("Julia is..."),
│ │ UserMessage("How does it work?"), │ │ UserMessage("How does it work?"),
│ │ AssistantMessage("It works by...")] │ │ AssistantMessage("It works by...")]
│ └─────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────┘
│ │ │ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
@@ -261,83 +261,83 @@
│ │ │ │
│ What is a steering message? │ │ What is a steering message? │
│ • A message (any AgentMessage type) injected via: `agent.steer(message)` │ │ • A message (any AgentMessage type) injected via: `agent.steer(message)` │
│ • Goes into the steering queue, not immediately to context.messages │ │ • Goes into the steering queue, not immediately to context.messages
│ │ │ │
│ How is it created? │ │ How is it created? │
│ • User code calls: agent.steer(UserMessage("...")) │ │ • User code calls: agent.steer(UserMessage("..."))
│ • Or: agent.steer(AssistantMessage("...")) │ │ • Or: agent.steer(AssistantMessage("..."))
│ • Or any other AgentMessage subtype │ │ • Or any other AgentMessage subtype
│ │ │ │
│ When is it processed? │ │ When is it processed? │
│ • At the START of the next loop iteration (line 194-202 in agent_loop.jl) │ │ • At the START of the next loop iteration (line 194-202 in agent_loop.jl) │
│ • AFTER the previous assistant turn completes │ │ • AFTER the previous assistant turn completes │
│ • BEFORE the next assistant response is streamed │ │ • BEFORE the next assistant response is streamed
│ │ │ │
│ Why use steering? │ │ Why use steering? │
│ Use case 1: Tool execution result injection │ │ Use case 1: Tool execution result injection
│ - Agent calls a tool (e.g., read_file, bash) │ │ - Agent calls a tool (e.g., read_file, bash)
│ - Tool returns result │ │ - Tool returns result
│ - You want to inject a follow-up question based on the result │ │ - You want to inject a follow-up question based on the result
│ - agent.steer(UserMessage("Based on the file, what should we do next?")) │ │ - agent.steer(UserMessage("Based on the file, what should we do next?"))
│ │ │ │
│ Use case 2: Multi-turn conversation without user input │ │ Use case 2: Multi-turn conversation without user input
│ - Agent responds to user │ │ - Agent responds to user
│ - Before user types again, you want to inject a system message │ │ - Before user types again, you want to inject a system message
│ - agent.steer(BashExecutionMessage(...)) or custom message │ │ - agent.steer(BashExecutionMessage(...)) or custom message
│ - This continues the conversation automatically │ │ - This continues the conversation automatically │
│ │ │ │
│ Use case 3: Branch navigation recovery │ │ Use case 3: Branch navigation recovery
│ - User navigates between conversation branches │ │ - User navigates between conversation branches
│ - After switching branches, you want to inject a context message │ │ - After switching branches, you want to inject a context message
│ - agent.steer(BranchSummaryMessage(...)) │ │ - agent.steer(BranchSummaryMessage(...))
│ - The agent can then continue from the new branch context │ │ - The agent can then continue from the new branch context
│ │ │ │
│ Use case 4: Compaction summary injection │ │ Use case 4: Compaction summary injection
│ - Conversation history is compacted │ │ - Conversation history is compacted
│ - After compaction, inject summary message │ │ - After compaction, inject summary message
│ - agent.steer(CompactionSummaryMessage(...)) │ │ - agent.steer(CompactionSummaryMessage(...))
│ - Agent knows old history was summarized │ │ - Agent knows old history was summarized │
│ │ │ │
│ Example: │ │ Example: │
│ agent.steer(UserMessage("Follow-up question here")) │ │ agent.steer(UserMessage("Follow-up question here"))
│ # This will be processed in the next loop iteration, │ │ # This will be processed in the next loop iteration,
│ # appearing in context.messages before the next LLM call │ │ # appearing in context.messages before the next LLM call
│ │ │ │
│ The LLM sees: │ │ The LLM sees: │
│ ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
│ │ All messages become Message[] via convert_to_llm(): │ │ All messages become Message[] via convert_to_llm():
│ │ [UserMessage(...), AssistantMessage(...), UserMessage(from_steer), ...] │ │ [UserMessage(...), AssistantMessage(...), UserMessage(from_steer), ...]
│ │ │ │ │ │ │
│ │ The LLM cannot tell which came from Agent.prompt() vs agent.steer() │ │ The LLM cannot tell which came from Agent.prompt() vs agent.steer()
│ └─────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────┘
│ │ │ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ LLM PROCESSING: How LLM sees messages │ │ LLM PROCESSING: How LLM sees messages
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ │ │ │
│ The LLM NEVER sees "user message" vs "steering message" - it only sees Message types: │ │ The LLM NEVER sees "user message" vs "steering message" - it only sees Message types:
│ │ │ │
│ ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
│ │ convert_to_llm() transforms ALL AgentMessages to Message[]: │ │ convert_to_llm() transforms ALL AgentMessages to Message[]:
│ │ │ │ │ │ │
│ │ UserMessage("user") → UserMessage (for LLM) │ │ UserMessage("user") → UserMessage (for LLM)
│ │ Steering UserMessage("user") → UserMessage (for LLM) ← Same! │ │ Steering UserMessage("user") → UserMessage (for LLM) ← Same!
│ │ AssistantMessage("assistant") → AssistantMessage (for LLM) │ │ AssistantMessage("assistant") → AssistantMessage (for LLM)
│ │ ToolResultMessage("toolResult") → ToolResultMessage (for LLM) │ │ ToolResultMessage("toolResult") → ToolResultMessage (for LLM)
│ │ │ │ │ │ │
│ │ BranchSummaryMessage → UserMessage (wrapped in summary tags) │ │ BranchSummaryMessage → UserMessage (wrapped in summary tags)
│ │ CompactionSummaryMessage → UserMessage (wrapped in summary tags) │ │ CompactionSummaryMessage → UserMessage (wrapped in summary tags)
│ │ BashExecutionMessage → UserMessage (if not excluded) │ │ BashExecutionMessage → UserMessage (if not excluded)
│ │ CustomMessage → UserMessage │ │ CustomMessage → UserMessage
│ └─────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────┘
│ │ │ │
│ The difference is ONLY in HOW messages enter the system: │ │ The difference is ONLY in HOW messages enter the system:
│ • User messages: Agent.prompt() → vcat() → context.messages (direct) │ │ • User messages: Agent.prompt() → vcat() → context.messages (direct)
│ • Steering: agent.steer() → queue → loop → context.messages (indirect) │ │ • Steering: agent.steer() → queue → loop → context.messages (indirect)
│ │ │ │
│ At LLM level: BOTH become UserMessage in the conversation! │ │ At LLM level: BOTH become UserMessage in the conversation!
│ │ │ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
@@ -347,13 +347,13 @@
│ │ │ │
│ 1. User prompts go DIRECTLY to context.messages via vcat() in runAgentLoop() │ │ 1. User prompts go DIRECTLY to context.messages via vcat() in runAgentLoop() │
│ │ │ │
│ 2. Steering queue is for messages injected via agent.steer() AFTER a turn finishes │ 2. Steering queue is for messages injected via agent.steer() AFTER a turn finishes │
│ This allows continuing conversation without calling Agent.prompt() again │ │ This allows continuing conversation without calling Agent.prompt() again │
│ │ │ │
│ 3. Context is preserved across turns - context.messages grows with each turn │ │ 3. Context is preserved across turns - context.messages grows with each turn │
│ LLM sees the full conversation history │ │ LLM sees the full conversation history │
│ │ │ │
│ 4. At LLM level, ALL messages become Message types (UserMessage/AssistantMessage/ToolResultMessage) │ │ 4. At LLM level, ALL messages become Message types (UserMessage/AssistantMessage/ToolResultMessage)
│ The "steering" vs "user" distinction is just a control mechanism, not a message type │ │ The "steering" vs "user" distinction is just a control mechanism, not a message type │
│ │ │ │
│ 5. New turn is triggered by: │ │ 5. New turn is triggered by: │
+90 -90
View File
@@ -51,7 +51,7 @@
``` ```
┌─────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────┐
│ Agent Lifecycle │ Agent Lifecycle │
└─────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────┘
User Code User Code
@@ -83,20 +83,20 @@
┌──────────────────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────────────────┐
│ AgentLoop (runs in separate thread) │ │ AgentLoop (runs in separate thread) │
│ │
│ ┌────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────┐ │
│ │ 1. Emit AgentStartEvent │ │ │ │ 1. Emit AgentStartEvent │ │
│ │ 2. Emit TurnStartEvent │ │ │ │ 2. Emit TurnStartEvent │ │
│ │ 3. Process prompts (emit MessageStart/End) │ │ │ │ 3. Process prompts (emit MessageStart/End) │ │
│ │ 4. ┌──────────────────────────────────────────────┐ │ │ │ │ 4.┌────────────────────────────────────────────────┐ │ │
│ │ │ while true: │ │ │ │ │ │ while true: │ │ │
│ │ │ │ Process steering/follow-up messages │ │ │ │ │ │ │ Process steering/follow-up messages │ │ │
│ │ │ │ Stream assistant response (LLM call) │ │ │ │ │ │ │ Stream assistant response (LLM call) │ │ │
│ │ │ │ Execute tool calls (parallel/sequential) │ │ │ │ │ │ │ Execute tool calls (parallel/sequential) │ │ │
│ │ │ │ Emit TurnEndEvent │ │ │ │ │ │ │ Emit TurnEndEvent │ │ │
│ │ │ │ Check if should stop │ │ │ │ │ │ │ Check if should stop │ │ │
│ │ │ │ Get next steering messages │ │ │ │ │ │ │ Get next steering messages │ │ │
│ │ └───┴────────────────────────────────────────────┘ │ │ │ │ └───┴────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘ └──────────────────────────────────────────────────────────────┘
@@ -125,18 +125,18 @@
│ ┌────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────┐ │
│ │ agentLoop(prompts, context, config, signal, stream_fn) │ │ │ │ agentLoop(prompts, context, config, signal, stream_fn) │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────┐ │
│ │ runAgentLoop(prompts, context, config, emit, signal) │ │ │ │ runAgentLoop(prompts, context, config, emit, signal) │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────┐ │
│ │ runLoop() - Main Event Loop │ │ │ │ runLoop() - Main Event Loop │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
└──────────────────────────────┼─────────────────────────────────────── └──────────────────────────────┼─────────────────────────────────────┘
│ Loop Iteration │ Loop Iteration
@@ -150,8 +150,8 @@
│ │ │ (after assistant) │ │ (after stop) │ │ │ │ │ │ (after assistant) │ │ (after stop) │ │ │
│ │ └────────────────────┘ └──────────────────────┘ │ │ │ │ └────────────────────┘ └──────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────┐ │
│ │ 2. Stream Assistant Response │ │ │ │ 2. Stream Assistant Response │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │
@@ -161,39 +161,39 @@
│ │ │ - Text deltas │ │ │ │ │ │ - Text deltas │ │ │
│ │ │ - Tool call deltas │ │ │ │ │ │ - Tool call deltas │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────────────────┘ │ │
│ │ │ │ │ │ │ │ │ │
│ │ ▼ │ │ │ │ ▼ │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ Emit: MessageStartEvent, MessageUpdateEvent, │ │ │ │ │ │ Emit: MessageStartEvent, MessageUpdateEvent, │ │ │
│ │ │ MessageEndEvent │ │ │ │ │ │ MessageEndEvent │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────┐ │
│ │ 3. Execute Tool Calls │ │ │ │ 3. Execute Tool Calls │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ extract ToolCall from assistant content │ │ │ │ │ │ extract ToolCall from assistant content │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ if EXECUTION_SEQUENTIAL || has_sequential_tool: │ │ │ │ │ │ if EXECUTION_SEQUENTIAL || has_sequential_tool: │ │ │
│ │ │ executeToolCallsSequential() │ │ │ │ │ │ executeToolCallsSequential() │ │ │
│ │ │ else: │ │ │ │ │ │ else: │ │ │
│ │ │ executeToolCallsParallel() │ │ │ │ │ │ executeToolCallsParallel() │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────────────────┘ │ │
│ │ │ │ │ │ │ │ │ │
│ │ ▼ │ │ │ │ ▼ │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ For each tool call: │ │ │ │ │ │ For each tool call: │ │ │
│ │ │ 1. before_tool_call hook │ │ │ │ │ │ 1. before_tool_call hook │ │ │
│ │ │ 2. prepareToolCall() │ │ │ │ │ │ 2. prepareToolCall() │ │ │
│ │ │ 3. execute() │ │ │ │ │ │ 3. execute() │ │ │
│ │ │ 4. after_tool_call hook │ │ │ │ │ │ 4. after_tool_call hook │ │ │
│ │ │ 5. Emit ToolExecutionStart/Update/EndEvent │ │ │ │ │ │ 5. Emit ToolExecutionStart/Update/EndEvent │ │ │
│ │ │ 6. Emit ToolResultMessage │ │ │ │ │ │ 6. Emit ToolResultMessage │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────┐ │
│ │ 4. Prepare Next Turn │ │ │ │ 4. Prepare Next Turn │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │
@@ -202,29 +202,29 @@
│ │ │ - Optional: Update context │ │ │ │ │ │ - Optional: Update context │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────┐ │
│ │ 5. Check Termination Conditions │ │ │ │ 5. Check Termination Conditions │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ should_stop_after_turn(context) -> bool │ │ │ │ │ │ should_stop_after_turn(context) -> bool │ │ │
│ │ │ - Max turns reached? │ │ │ │ │ │ - Max turns reached? │ │ │
│ │ │ - Tool returned terminate=true? │ │ │ │ │ │ - Tool returned terminate=true? │ │ │
│ │ │ - Steering queue empty and follow-up empty? │ │ │ │ │ │ - Steering queue empty and follow-up empty? │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────┐ │
│ │ 6. Emit TurnEndEvent (message, tool_results) │ │ │ │ 6. Emit TurnEndEvent (message, tool_results) │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────┐ │
│ │ Loop continues until termination condition met │ │ │ │ Loop continues until termination condition met │ │
│ └────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
└──────────────────────────────┼─────────────────────────────────────── └──────────────────────────────┼─────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────────────────┐
@@ -240,34 +240,34 @@
└─────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────┐ ┌───────────────────────────────────────────────────────────────────┐
│ Assistant Message with Tool Calls │ Assistant Message with Tool Calls │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ AssistantMessage: │ │ │ │ AssistantMessage: │ │
│ │ content: [ │ │ │ │ content: [ │ │
│ │ TextContent("I'll help you"), │ │ │ │ TextContent("I'll help you"), │ │
│ │ ToolCall(id="tc1", name="bash", args={...}), │ │ │ │ ToolCall(id="tc1", name="bash", args={...}), │ │
│ │ ToolCall(id="tc2", name="read", args={...}) │ │ │ │ ToolCall(id="tc2", name="read", args={...}) │ │
│ │ ] │ │ │ │ ] │ │
│ └─────────────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ │ ▼ │
└───────────────────────────────────────────────────────────────────┘ └───────────────────────────────────────────────────────────────────┘
│ executeToolCalls() │ executeToolCalls()
┌───────────────────────────────────────────────────────────────────┐ ┌───────────────────────────────────────────────────────────────────┐
│ Determine Execution Mode │ Determine Execution Mode │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ config.tool_execution == EXECUTION_SEQUENTIAL? │ │ │ │ config.tool_execution == EXECUTION_SEQUENTIAL? │ │
│ │ OR any tool has execution_mode == EXECUTION_SEQUENTIAL? │ │ │ │ OR any tool has execution_mode == EXECUTION_SEQUENTIAL? │ │
│ └─────────────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ┌───────────────┴───────────────┐ │ ┌───────────────┴───────────────┐ │
│ ▼ ▼ │ ▼ ▼ │
│ ┌────────────────────────┐ ┌────────────────────────┐ │ │ ┌────────────────────────┐ ┌────────────────────────┐ │
│ │ executeSequential() │ │ executeParallel() │ │ │ │ executeSequential() │ │ executeParallel() │ │
│ └────────────────────────┘ └────────────────────────┘ │ │ └────────────────────────┘ └────────────────────────┘ │
│ │ │ │ │ │ │
└──────────────┼───────────────────────────────┼────────────────────┘ └──────────────┼───────────────────────────────┼────────────────────┘
│ │ │ │
│ │ │ │
@@ -285,7 +285,7 @@
┌───────────────────────────────────────────────────────────────────┐ ┌───────────────────────────────────────────────────────────────────┐
│ For Each Tool Call │ For Each Tool Call │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. before_tool_call hook (optional) │ │ │ │ 1. before_tool_call hook (optional) │ │
│ │ - Can block execution │ │ │ │ - Can block execution │ │
@@ -293,20 +293,20 @@
│ │ - validateToolArguments() │ │ │ │ - validateToolArguments() │ │
│ │ - prepareToolCallArguments() (optional) │ │ │ │ - prepareToolCallArguments() (optional) │ │
│ │ 3. Execute Tool: │ │ │ │ 3. Execute Tool: │ │
│ │ tool.execute(tool_call_id, args, signal, on_update) │ │ │ │ tool.execute(tool_call_id, args, signal, on_update) │ │
│ │ 4. after_tool_call hook (optional) │ │ │ │ 4. after_tool_call hook (optional) │ │
│ │ - Can modify result content │ │ │ │ - Can modify result content │ │
│ │ 5. Emit events: │ │ │ │ 5. Emit events: │ │
│ │ - ToolExecutionStartEvent │ │ │ │ - ToolExecutionStartEvent │ │
│ │ - ToolExecutionUpdateEvent (optional) │ │ │ │ - ToolExecutionUpdateEvent (optional) │ │
│ │ - ToolExecutionEndEvent │ │ │ │ - ToolExecutionEndEvent │ │
│ │ 6. Create ToolResultMessage │ │ │ │ 6. Create ToolResultMessage │ │
│ └─────────────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘ └───────────────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────┐ ┌───────────────────────────────────────────────────────────────────┐
│ Tool Result Messages │ Tool Result Messages │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ToolResultMessage: │ │ │ │ ToolResultMessage: │ │
│ │ role: "toolResult" │ │ │ │ role: "toolResult" │ │
@@ -329,47 +329,47 @@
┌───────────────────────────────────────────────────────────────────┐ ┌───────────────────────────────────────────────────────────────────┐
│ Branch Navigation │ │ Branch Navigation │
│ │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│ │ E1 │────▶│ E2 │────▶│ E3 │────▶│ E4 │────▶│ E5 │ (leaf) │ │ E1 │────▶│ E2 │────▶│ E3 │────▶│ E4 │────▶│ E5 │ (leaf) │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │ │ ▼ ▼ ▼ ▼ ▼ │
│ Message Message Compaction Message BranchSummary │ │ Message Message Compaction Message BranchSummary │
│ │
│ E3 is a Compaction Entry: │ │ E3 is a Compaction Entry: │
│ - Summary of E1, E2 │ │ - Summary of E1, E2 │
│ - first_kept_entry_id: reference to first retained message │ │ - first_kept_entry_id: reference to first retained message │
│ - tokens_before: context size before compaction │ │ - tokens_before: context size before compaction │
│ │
│ E5 is a BranchSummary Entry: │ │ E5 is a BranchSummary Entry: │
│ - Summary of branch from from_id │ │ - Summary of branch from from_id │
│ - Represents a fork point in conversation history │ │ - Represents a fork point in conversation history │
│ │
└───────────────────────────────────────────────────────────────────┘ └───────────────────────────────────────────────────────────────────┘
│ Session.moveTo() │ Session.moveTo()
┌───────────────────────────────────────────────────────────────────┐ ┌───────────────────────────────────────────────────────────────────┐
│ Forking & Branching │ │ Forking & Branching │
│ │
│ Current branch: │ │ Current branch: │
│ ┌─────┐ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ E1 │────▶│ E2 │────▶│ E3 │ │ │ │ E1 │────▶│ E2 │────▶│ E3 │ │
│ └─────┘ └─────┘ └─────┘ │ │ └─────┘ └─────┘ └─────┘ │
│ moveTo(E2) │ │ │ moveTo(E2)
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ E1 │────▶│ E2 │────▶│ E3' │────▶│ E4' │ (new branch) │ │ E1 │────▶│ E2 │────▶│ E3' │────▶│ E4' │ (new branch) │
│ └─────┘ └─────┘ └─────┘ └─────┘ │ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │ │ │ │ │
│ │ create BranchSummary │ │ │ create BranchSummary │
│ ▼ │ │ ▼ │
│ ┌─────┐ ┌─────┐ │
│ │ E5 │ (branch summary) │ E5 │ (branch summary) │
│ └─────┘ └─────┘ │
│ │
└───────────────────────────────────────────────────────────────────┘ └───────────────────────────────────────────────────────────────────┘
``` ```
@@ -377,7 +377,7 @@
``` ```
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ Component Relationships │ Component Relationships │
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
User Code User Code
@@ -409,7 +409,7 @@
``` ```
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ Data Flow Between Layers │ Data Flow Between Layers │
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
User Input (String/Message) User Input (String/Message)
+5 -5
View File
@@ -403,9 +403,9 @@ Scenario: User sends message, agent responds with tool calls
┌────────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────────┐
│ Time 2: User queues steering message │ │ Time 2: User queues steering message │
│ ┌──────────────────┐ │ │ ┌──────────────────┐ │
│ │ steer(msg2) │ ──► steering_queue.push(msg2) │ │ │ steer(msg2) │ ──► steering_queue.push(msg2)
│ └──────────────────┘ │ │ └──────────────────┘ │
│ │
│ (msg2 not processed yet!) │ │ (msg2 not processed yet!) │
└────────────────────────────────────────────────────────────┘ └────────────────────────────────────────────────────────────┘
@@ -413,9 +413,9 @@ Scenario: User sends message, agent responds with tool calls
┌────────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────────┐
│ Time 3: Tool execution │ │ Time 3: Tool execution │
│ ┌──────────────────────────────────────────────────────┐ │ │ ┌──────────────────────────────────────────────────────┐ │
│ │ Execute bash tool... │ │ │ │ Execute bash tool... │ │
│ │ Execute read tool... │ │ │ │ Execute read tool... │ │
│ │ Emit ToolResultMessage[] │ │ │ │ Emit ToolResultMessage[] │ │
│ └──────────────────────────────────────────────────────┘ │ │ └──────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘ └────────────────────────────────────────────────────────────┘
+31 -31
View File
@@ -31,55 +31,55 @@ agentLoopContinue()
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. runAgentLoop() ── Entry point for new conversation │ │ 1. runAgentLoop() ── Entry point for new conversation
│ - Creates copy of prompts │ │ - Creates copy of prompts
│ - Appends prompts to context.messages │ │ - Appends prompts to context.messages
│ - Emits AgentStartEvent │ │ - Emits AgentStartEvent
│ - Emits TurnStartEvent │ │ - Emits TurnStartEvent
│ - Emits MessageStart/End for each prompt │ │ - Emits MessageStart/End for each prompt
│ - Calls runLoop() │ │ - Calls runLoop()
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ 2. runLoop() ── Main event loop │ │ 2. runLoop() ── Main event loop
│ ┌────────────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ while true: │ │ │ │ while true: │ │
│ │ 1. Get steering/follow-up messages (if any) │ │ │ │ 1. Get steering/follow-up messages (if any) │ │
│ │ 2. Emit messages as UserMessage │ │ │ │ 2. Emit messages as UserMessage │ │
│ │ 3. streamAssistantResponse() │ │ │ │ 3. streamAssistantResponse() │ │
│ │ 4. Execute tool calls (sequential or parallel) │ │ │ │ 4. Execute tool calls (sequential or parallel) │ │
│ │ 5. Emit TurnEndEvent │ │ │ │ 5. Emit TurnEndEvent │ │
│ │ 6. prepare_next_turn (optional) │ │ │ │ 6. prepare_next_turn (optional) │ │
│ │ 7. should_stop_after_turn? (check termination) │ │ │ │ 7. should_stop_after_turn? (check termination) │ │
│ │ 8. Loop continues if not terminated │ │ │ │ 8. Loop continues if not terminated │ │
│ └────────────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ 3. streamAssistantResponse() ── LLM interaction │ │ 3. streamAssistantResponse() ── LLM interaction
│ - transform_context (optional) │ │ - transform_context (optional)
│ - convert_to_llm (transform to Message[]) │ │ - convert_to_llm (transform to Message[])
│ - Call stream_fn (LLM API) │ │ - Call stream_fn (LLM API)
│ - Stream response deltas │ │ - Stream response deltas
│ - Emit MessageStart/Update/End events │ │ - Emit MessageStart/Update/End events
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ 4. executeToolCalls() ── Tool execution │ │ 4. executeToolCalls() ── Tool execution
│ ┌────────────────────────────────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ if EXECUTION_SEQUENTIAL || has_sequential_tool: │ │ │ │ if EXECUTION_SEQUENTIAL || has_sequential_tool: │ │
│ │ executeToolCallsSequential() │ │ │ │ executeToolCallsSequential() │ │
│ │ else: │ │ │ │ else: │ │
│ │ executeToolCallsParallel() │ │ │ │ executeToolCallsParallel() │ │
│ └────────────────────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ 5. AgentEndEvent ── Final event with all messages │ │ 5. AgentEndEvent ── Final event with all messages
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
``` ```
@@ -520,13 +520,13 @@ ToolResultMessage(
┌──────┐ ┌──────┐
│ TC1 │ ──► prepareToolCall() ──► create closure ──► ┐ │ TC1 │ ──► prepareToolCall() ──► create closure ──► ┐
└──────┘ └──────┘ │
┌──────┐ ┌──────┐ │
│ TC2 │ ──► prepareToolCall() ──► create closure ──► ├─► All closures queued │ TC2 │ ──► prepareToolCall() ──► create closure ──► ├─► All closures queued
└──────┘ └──────┘ │
┌──────┐ ┌──────┐ │
│ TC3 │ ──► prepareToolCall() ──► create closure ──► ┘ │ TC3 │ ──► prepareToolCall() ──► create closure ──► ┘
└──────┘ └──────┘
+47 -47
View File
@@ -19,80 +19,80 @@
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ ToolExecutionMode (Enum) │ │ ToolExecutionMode (Enum)
│ - EXECUTION_SEQUENTIAL (Tools run one at a time) │ │ - EXECUTION_SEQUENTIAL (Tools run one at a time)
│ - EXECUTION_PARALLEL (Tools run concurrently) │ │ - EXECUTION_PARALLEL (Tools run concurrently)
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ QueueMode (Enum) │ │ QueueMode (Enum)
│ - QUEUE_ALL (Drain all messages at once) │ │ - QUEUE_ALL (Drain all messages at once)
│ - QUEUE_ONE_AT_A_TIME (Process one message at a time) │ │ - QUEUE_ONE_AT_A_TIME (Process one message at a time)
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ MessageContent (Abstract Type) │ │ MessageContent (Abstract Type)
│ ├── TextContent (String) │ │ ├── TextContent (String)
│ └── ImageContent (data::String, mime_type::String) │ │ └── ImageContent (data::String, mime_type::String)
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ Message (Abstract Type) │ │ Message (Abstract Type)
│ ├── UserMessage │ │ ├── UserMessage
│ │ └─ role: "user", content: Message[], timestamp: Int64 │ │ │ └─ role: "user", content: Message[], timestamp: Int64
│ ├── AssistantMessage │ │ ├── AssistantMessage
│ │ └─ role: "assistant", content: Message[], api, provider, model, │ │ │ └─ role: "assistant", content: Message[], api, provider, model,
│ │ usage: Usage, stop_reason, error_message, timestamp │ │ │ usage: Usage, stop_reason, error_message, timestamp
│ └── ToolResultMessage │ │ └── ToolResultMessage
│ └─ role: "toolResult", tool_call_id, tool_name, content, details, │ │ └─ role: "toolResult", tool_call_id, tool_name, content, details,
│ usage, added_tool_names, is_error, timestamp │ │ usage, added_tool_names, is_error, timestamp
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ AgentMessage (Abstract Type) │ │ AgentMessage (Abstract Type)
│ └─ Union of all message types above + custom types │ │ └─ Union of all message types above + custom types
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ AgentTool │ │ AgentTool
│ - name: String │ │ - name: String
│ - label: String │ │ - label: String
│ - description: String │ │ - description: String
│ - parameters: Any │ │ - parameters: Any
│ - execute: Function │ │ - execute: Function
│ - prepare_arguments: Union{Function, Nothing} │ │ - prepare_arguments: Union{Function, Nothing}
│ - execution_mode: Union{ToolExecutionMode, Nothing} │ │ - execution_mode: Union{ToolExecutionMode, Nothing}
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ AgentContext │ │ AgentContext
│ - system_prompt: String │ │ - system_prompt: String
│ - messages: Vector{AgentMessage} │ │ - messages: Vector{AgentMessage}
│ - tools: Union{Vector{AgentTool}, Nothing} │ │ - tools: Union{Vector{AgentTool}, Nothing}
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ AgentEvent (Abstract Type) │ │ AgentEvent (Abstract Type)
│ ├── AgentStartEvent / AgentEndEvent │ │ ├── AgentStartEvent / AgentEndEvent
│ ├── TurnStartEvent / TurnEndEvent │ │ ├── TurnStartEvent / TurnEndEvent
│ ├── MessageStartEvent / MessageEndEvent │ │ ├── MessageStartEvent / MessageEndEvent
│ ├── MessageUpdateEvent │ │ ├── MessageUpdateEvent
│ ├── ToolExecutionStartEvent / ToolExecutionEndEvent │ │ ├── ToolExecutionStartEvent / ToolExecutionEndEvent
│ └── ToolExecutionUpdateEvent │ │ └── ToolExecutionUpdateEvent
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ Usage & ModelCost │ │ Usage & ModelCost
│ Usage: input, output, cache_read, cache_write, total_tokens, cost │ │ Usage: input, output, cache_read, cache_write, total_tokens, cost
│ ModelCost: input, output, cache_read, cache_write (all Float64) │ │ ModelCost: input, output, cache_read, cache_write (all Float64)
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ Model │ │ Model
│ - id, name, api, provider, base_url, reasoning: Bool │ │ - id, name, api, provider, base_url, reasoning: Bool
│ - input: Vector{String} │ │ - input: Vector{String}
│ - cost: ModelCost │ │ - cost: ModelCost
│ - context_window, max_tokens: Int64 │ │ - context_window, max_tokens: Int64
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
``` ```
+13 -13
View File
@@ -9,23 +9,23 @@
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ Session = Tree of Entries │ │ Session = Tree of Entries │
│ │
│ Each entry represents a change in conversation state │ │ Each entry represents a change in conversation state │
│ │
│ Branch Navigation: │ │ Branch Navigation: │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ E1 │────▶│ E2 │────▶│ E3 │────▶│ E4 │────▶│ E5 │ (current leaf) │ │ E1 │────▶│ E2 │────▶│ E3 │────▶│ E4 │────▶│ E5 │ (current leaf) │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │ │ │ │ │ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │ │ ▼ ▼ ▼ ▼ ▼
│ Message Message Compaction Message BranchSummary │ │ Message Message Compaction Message BranchSummary
│ │
│ To navigate to E2 (fork point): │ │ To navigate to E2 (fork point): │
│ Session.moveTo(E2) │ │ Session.moveTo(E2) │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│ │ E1 │────▶│ E2 │────▶│ E3' │────▶│ E4' │────▶│ E5' │ (new branch) │ │ E1 │────▶│ E2 │────▶│ E3' │────▶│ E4' │────▶│ E5' │ (new branch) │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘
│ │ │ │ │ │ │
│ │ ▼ create BranchSummary │ │ │ ▼ create BranchSummary │
│ │ ┌─────┐ │ │ │ ┌─────┐ │
│ └──────│ E6 │ (branch summary) │ │ └──────│ E6 │ (branch summary) │
+12 -12
View File
@@ -8,14 +8,14 @@
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ AgentTool │ │ AgentTool
│ - name: String (identifier) │ │ - name: String (identifier)
│ - label: String (display name) │ │ - label: String (display name)
│ - description: String (what it does) │ │ - description: String (what it does)
│ - parameters: JSON schema │ │ - parameters: JSON schema
│ - execute::Function (main logic) │ │ - execute::Function (main logic)
│ - prepare_arguments::Union{Function, Nothing} │ │ - prepare_arguments::Union{Function, Nothing}
│ - execution_mode::Union{ToolExecutionMode, Nothing} │ │ - execution_mode::Union{ToolExecutionMode, Nothing}
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌───────────────┼───────────────┐ ┌───────────────┼───────────────┐
@@ -47,8 +47,8 @@
┌────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────┐
│ AgentLoop.executeToolCalls() │ │ AgentLoop.executeToolCalls() │
│ - Extract ToolCalls from message content │ │ - Extract ToolCalls from message content
│ - Determine execution mode (sequential/parallel) │ │ - Determine execution mode (sequential/parallel)
└────────────────────────────────────────────────────────┘ └────────────────────────────────────────────────────────┘
├─► executeToolCallsSequential() ├─► executeToolCallsSequential()
@@ -77,7 +77,7 @@
┌────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────┐
│ ToolResultMessage │ │ ToolResultMessage │
│ - tool_call_id: "ref to original ToolCall" │ │ - tool_call_id: "ref to original ToolCall"
│ - tool_name: "bash" │ │ - tool_name: "bash" │
│ - content: [TextContent("file1.md\nfile2.md\n")] │ │ - content: [TextContent("file1.md\nfile2.md\n")] │
│ - is_error: false │ │ - is_error: false │
@@ -85,7 +85,7 @@
┌────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────┐
│ AgentState.messages.append(tool_result) │ │ AgentState.messages.append(tool_result)
│ - Next turn: LLM sees tool results │ │ - Next turn: LLM sees tool results │
└────────────────────────────────────────────────────────┘ └────────────────────────────────────────────────────────┘
``` ```
+16 -16
View File
@@ -9,31 +9,31 @@
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐
│ AgentHarness = Agent + Session + Resources │ │ AgentHarness = Agent + Session + Resources │
│ │
│ ┌───────────────────────────────────────────────────────────────────────┐ │ │ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ AgentHarness │ │ │ │ AgentHarness │ │
│ │ - Manages Agent instances │ │ │ │ - Manages Agent instances │ │
│ │ - Provides Session persistence │ │ │ │ - Provides Session persistence │ │
│ │ - Manages resources (skills, prompt templates) │ │ │ │ - Manages resources (skills, prompt templates) │ │
│ │ - Handles extension hooks │ │ │ │ - Handles extension hooks │ │
│ │ - Coordinates tool execution with context │ │ │ │ - Coordinates tool execution with context │ │
│ └───────────────────────────────────────────────────────────────────────┘ │ │ └───────────────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ┌─────────────────────┼─────────────────────┐ │ │ ┌─────────────────────┼─────────────────────┐ │
│ ▼ ▼ ▼ │ │ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ Agent │ │ SessionRepo │ │ Resources │ │ │ │ Agent │ │ SessionRepo │ │ Resources │
│ │ (state, │ │ (create, │ │ (skills, │ │ │ │ (state, │ │ (create, │ │ (skills, │
│ │ events) │ │ open, │ │ templates) │ │ │ │ events) │ │ open, │ │ templates) │
│ └──────────────┘ │ list) │ └──────────────┘ │ │ └──────────────┘ │ list) │ └──────────────┘
│ └──────────────┘ │ │ └──────────────┘
│ │ │ │ │
│ ▼ │ ▼ │
│ ┌──────────────┐ │ │ ┌──────────────┐
│ │ Session │ │ │ │ Session │
│ │ (history, │ │ │ │ (history, │
│ │ branching) │ │ │ │ branching) │
│ └──────────────┘ │ │ └──────────────┘
└─────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────┐