Files
YiemAgent/learning/01-ARCHITECTURE_OVERVIEW.md
T
2026-07-29 13:50:00 +07:00

42 KiB

AgentCore.jl - Architecture Overview

Top-Down Architecture

┌─────────────────────────────────────────────────────────────────────────┐
│                        AgentCore.jl Layers                              │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│  Level 1: AgentHarness (Session Management & Persistence)               │
│  - Session persistence with JSONL storage                               │
│  - Resource management (skills, prompt templates)                       │
│  - Extension hooks system                                               │
│  - Branch navigation and compaction                                     │
└─────────────────────────────────────────────────────────────────────────┘
                              │
                              │ orchestrates
                              ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  Level 2: Agent (State Management & Event Streaming)                    │
│  - Conversation state (messages, tools, system prompt)                  │
│  - Event streaming and lifecycle management                             │
│  - Steering and follow-up message queues                                │
│  - Abort handling                                                       │
└─────────────────────────────────────────────────────────────────────────┘
                              │
                              │ delegates to
                              ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  Level 3: AgentLoop (Core LLM Interaction Loop)                         │
│  - Stateful LLM interactions                                            │
│  - Tool execution (parallel or sequential)                              │
│  - Event emission lifecycle                                             │
│  - Steering/follow-up message handling                                  │
└─────────────────────────────────────────────────────────────────────────┘
                              │
                              │ transforms to
                              ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  Level 4: Session (Conversation History Management)                     │
│  - Tree-based conversation history                                      │
│  - Branch support with compaction                                       │
│  - Message and metadata persistence                                     │
└─────────────────────────────────────────────────────────────────────────┘

Process Flow

1. Agent Lifecycle

┌─────────────────────────────────────────────────────────────────────────┐
│                         Agent Lifecycle                                 │
└─────────────────────────────────────────────────────────────────────────┘

    User Code
         │
         │ 1. Create Agent
         ▼
    ┌──────────────┐
    │   Agent()    │  ──► Initialize state, queues, listeners
    └──────────────┘
         │
         │ 2. Subscribe to events
         ▼
    ┌──────────────────┐
    │ subscribe()      │  ──► Register event handlers
    └──────────────────┘
         │
         │ 3. Run prompt
         ▼
    ┌──────────────────┐
    │ prompt()         │  ──► Validate input, normalize messages
    └──────────────────┘
         │
         │ 4. Start AgentLoop
         ▼
    ┌──────────────────┐
    │ runPromptMessages│  ──► Create ActiveRun, spawn loop
    └──────────────────┘
         │
         ▼
    ┌──────────────────────────────────────────────────────────────┐
    │  AgentLoop (runs in separate thread)                         │
    │                                                              │
    │  ┌────────────────────────────────────────────────────────┐  │
    │  │ 1. Emit AgentStartEvent                                │  │
    │  │ 2. Emit TurnStartEvent                                 │  │
    │  │ 3. Process prompts (emit MessageStart/End)             │  │
    │  │ 4.┌────────────────────────────────────────────────┐   │ │
    │  │   │ while true:                                    │   │ │
    │  │   │   │ Process steering/follow-up messages        │   │ │
    │  │   │   │ Stream assistant response (LLM call)       │   │ │
    │  │   │   │ Execute tool calls (parallel/sequential)   │   │ │
    │  │   │   │ Emit TurnEndEvent                          │   │ │
    │  │   │   │ Check if should stop                       │   │ │
    │  │   │   │ Get next steering messages                 │   │ │
    │  │   └───┴────────────────────────────────────────────┘   │ │
    │  └────────────────────────────────────────────────────────┘  │
    └──────────────────────────────────────────────────────────────┘
         │
         │ 5. Event streaming
         ▼
    ┌──────────────────┐
    │ Event Handlers   │  ──► User-defined listeners receive events
    └──────────────────┘
         │
         │ 6. Wait for completion
         ▼
    ┌──────────────────┐
    │ waitForIdle()    │  ──► Resolve when all events processed
    └──────────────────┘

2. AgentLoop Flow Diagram

┌─────────────────────────────────────────────────────────────────────────┐
│                    AgentLoop Process Flow                               │
└─────────────────────────────────────────────────────────────────────────┘

    ┌────────────────────────────────────────────────────────────────────┐
    │  AgentLoop Entrypoint                                              │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ agentLoop(prompts, context, config, signal, stream_fn)     │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    │                              ▼                                     │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ runAgentLoop(prompts, context, config, emit, signal)       │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    │                              ▼                                     │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ runLoop() - Main Event Loop                                │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    └──────────────────────────────┼─────────────────────────────────────┘
                                   │
                                   │ Loop Iteration
                                   ▼
    ┌────────────────────────────────────────────────────────────────────┐
    │  Main Processing Loop                                              │
    │                                                                    │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ 1. Get Steering/Follow-up Messages                         │    │
    │  │    ┌────────────────────┐      ┌──────────────────────┐    │    │
    │  │    │ steering_queue     │      │ follow_up_queue      │    │    │
    │  │    │ (after assistant)  │      │ (after stop)         │    │    │
    │  │    └────────────────────┘      └──────────────────────┘    │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    │                              ▼                                     │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ 2. Stream Assistant Response                               │    │
    │  │    ┌────────────────────────────────────────────────────┐  │    │
    │  │    │ transform_context()                                │  │    │
    │  │    │ convert_to_llm(messages) -> Message[]              │  │    │
    │  │    │ stream_fn(model, context, config) -> Response      │  │    │
    │  │    │  - Text deltas                                     │  │    │
    │  │    │  - Tool call deltas                                │  │    │
    │  │    └────────────────────────────────────────────────────┘  │    │
    │  │                              │                             │    │
    │  │                              ▼                             │    │
    │  │  ┌────────────────────────────────────────────────────┐    │    │
    │  │  │ Emit: MessageStartEvent, MessageUpdateEvent,       │    │    │
    │  │  │       MessageEndEvent                              │    │    │
    │  │  └────────────────────────────────────────────────────┘    │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    │                              ▼                                     │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ 3. Execute Tool Calls                                      │    │
    │  │    ┌────────────────────────────────────────────────────┐  │    │
    │  │    │ extract ToolCall from assistant content            │  │    │
    │  │    │                                                    │  │    │
    │  │    │ if EXECUTION_SEQUENTIAL || has_sequential_tool:    │  │    │
    │  │    │   executeToolCallsSequential()                     │  │    │
    │  │    │ else:                                              │  │    │
    │  │    │   executeToolCallsParallel()                       │  │    │
    │  │    └────────────────────────────────────────────────────┘  │    │
    │  │                              │                             │    │
    │  │                              ▼                             │    │
    │  │  ┌────────────────────────────────────────────────────┐    │    │
    │  │  │ For each tool call:                                │    │    │
    │  │  │  1. before_tool_call hook                          │    │    │
    │  │  │  2. prepareToolCall()                              │    │    │
    │  │  │  3. execute()                                      │    │    │
    │  │  │  4. after_tool_call hook                           │    │    │
    │  │  │  5. Emit ToolExecutionStart/Update/EndEvent        │    │    │
    │  │  │  6. Emit ToolResultMessage                         │    │    │
    │  │  └────────────────────────────────────────────────────┘    │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    │                              ▼                                     │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ 4. Prepare Next Turn                                       │    │
    │  │    ┌────────────────────────────────────────────────────┐  │    │
    │  │    │ prepare_next_turn(context) -> next_turn_snapshot   │  │    │
    │  │    │ - Optional: Update model/thinking_level            │  │    │
    │  │    │ - Optional: Update context                         │  │    │
    │  │    └────────────────────────────────────────────────────┘  │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    │                              ▼                                     │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ 5. Check Termination Conditions                            │    │
    │  │    ┌────────────────────────────────────────────────────┐  │    │
    │  │    │ should_stop_after_turn(context) -> bool            │  │    │
    │  │    │ - Max turns reached?                               │  │    │
    │  │    │ - Tool returned terminate=true?                    │  │    │
    │  │    │ - Steering queue empty and follow-up empty?        │  │    │
    │  │    └────────────────────────────────────────────────────┘  │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    │                              ▼                                     │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ 6. Emit TurnEndEvent (message, tool_results)               │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    │                              ▼                                     │
    │  ┌────────────────────────────────────────────────────────────┐    │
    │  │ Loop continues until termination condition met             │    │
    │  └────────────────────────────────────────────────────────────┘    │
    │                              │                                     │
    └──────────────────────────────┼─────────────────────────────────────┘
                                   │
                                   ▼
    ┌────────────────────────────────────────────────────────────────────┐
    │  AgentEndEvent with final messages                                 │
    └────────────────────────────────────────────────────────────────────┘

3. Tool Execution Flow

┌─────────────────────────────────────────────────────────────────────────┐
│                        Tool Execution Flow                              │
└─────────────────────────────────────────────────────────────────────────┘

    ┌───────────────────────────────────────────────────────────────────┐
    │  Assistant Message with Tool Calls                                │
    │  ┌─────────────────────────────────────────────────────────────┐  │
    │  │ AssistantMessage:                                           │  │
    │  │   content: [                                                │  │
    │  │     TextContent("I'll help you"),                           │  │
    │  │     ToolCall(id="tc1", name="bash", args={...}),            │  │
    │  │     ToolCall(id="tc2", name="read", args={...})             │  │
    │  │   ]                                                         │  │
    │  └─────────────────────────────────────────────────────────────┘  │
    │                              │                                    │
    │                              ▼                                    │
    └───────────────────────────────────────────────────────────────────┘
                                   │
                                   │ executeToolCalls()
                                   ▼
    ┌───────────────────────────────────────────────────────────────────┐
    │  Determine Execution Mode                                         │
    │  ┌─────────────────────────────────────────────────────────────┐  │
    │  │ config.tool_execution == EXECUTION_SEQUENTIAL?              │  │
    │  │ OR any tool has execution_mode == EXECUTION_SEQUENTIAL?     │  │
    │  └─────────────────────────────────────────────────────────────┘  │
    │                              │                                    │
    │              ┌───────────────┴───────────────┐                    │
    │              ▼                               ▼                    │
    │  ┌────────────────────────┐      ┌────────────────────────┐       │
    │  │ executeSequential()    │      │ executeParallel()      │       │
    │  └────────────────────────┘      └────────────────────────┘       │
    │              │                               │                    │
    └──────────────┼───────────────────────────────┼────────────────────┘
                   │                               │
                   │                               │
                   ▼                               ▼
    ┌──────────────────────┐              ┌──────────────────────┐
    │ Sequential Execution │              │ Parallel Execution   │
    │                      │              │                      │
    │  for tool_call in:   │              │  for tool_call in:   │
    │    prepareToolCall() │              │    prepareToolCall() │
    │    execute()         │              │    execute() (async) │
    │    finalize()        │              │                      │
    │                      │              │  wait all results    │
    │                      │              └──────────────────────┘
    └──────────────────────┘
                   │
                   ▼
    ┌───────────────────────────────────────────────────────────────────┐
    │  For Each Tool Call                                               │
    │  ┌─────────────────────────────────────────────────────────────┐  │
    │  │ 1. before_tool_call hook (optional)                         │  │
    │  │    - Can block execution                                    │  │
    │  │ 2. prepareToolCall()                                        │  │
    │  │    - validateToolArguments()                                │  │
    │  │    - prepareToolCallArguments() (optional)                  │  │
    │  │ 3. Execute Tool:                                            │  │
    │  │    tool.execute(tool_call_id, args, signal, on_update)      │  │
    │  │ 4. after_tool_call hook (optional)                          │  │
    │  │    - Can modify result content                              │  │
    │  │ 5. Emit events:                                             │  │
    │  │    - ToolExecutionStartEvent                                │  │
    │  │    - ToolExecutionUpdateEvent (optional)                    │  │
    │  │    - ToolExecutionEndEvent                                  │  │
    │  │ 6. Create ToolResultMessage                                 │  │
    │  └─────────────────────────────────────────────────────────────┘  │
    └───────────────────────────────────────────────────────────────────┘
                   │
                   ▼
    ┌───────────────────────────────────────────────────────────────────┐
    │  Tool Result Messages                                             │
    │  ┌─────────────────────────────────────────────────────────────┐  │
    │  │ ToolResultMessage:                                          │  │
    │  │   role: "toolResult"                                        │  │
    │  │   tool_call_id: "tc1"                                       │  │
    │  │   tool_name: "bash"                                         │  │
    │  │   content: [TextContent("command output")]                  │  │
    │  │   is_error: false                                           │  │
    │  └─────────────────────────────────────────────────────────────┘  │
    └───────────────────────────────────────────────────────────────────┘

4. Session & Tree Structure

┌─────────────────────────────────────────────────────────────────────────┐
│                        Session Tree Structure                           │
└─────────────────────────────────────────────────────────────────────────┘

    Session = Linked List of Entries (tree structure)

    ┌───────────────────────────────────────────────────────────────────┐
    │  Branch Navigation                                                │
    │                                                                   │
    │  ┌─────┐      ┌─────┐     ┌─────┐      ┌─────┐     ┌─────┐        │
    │  │ E1  │────▶│ E2  │────▶│ E3  │────▶│ E4  │────▶│ E5  │ (leaf) │
    │  └─────┘      └─────┘     └─────┘      └─────┘     └─────┘        │
    │      │           │           │           │           │            │
    │      ▼           ▼           ▼           ▼           ▼            │
    │   Message    Message    Compaction   Message    BranchSummary     │
    │                                                                   │
    │  E3 is a Compaction Entry:                                        │
    │  - Summary of E1, E2                                              │
    │  - first_kept_entry_id: reference to first retained message       │
    │  - tokens_before: context size before compaction                  │
    │                                                                   │
    │  E5 is a BranchSummary Entry:                                     │
    │  - Summary of branch from from_id                                 │
    │  - Represents a fork point in conversation history                │
    │                                                                   │
    └───────────────────────────────────────────────────────────────────┘
                   │
                   │ Session.moveTo()
                   ▼
    ┌───────────────────────────────────────────────────────────────────┐
    │  Forking & Branching                                              │
    │                                                                   │
    │  Current branch:                                                  │
    │  ┌─────┐      ┌─────┐     ┌─────┐                                 │
    │  │ E1  │────▶│ E2  │────▶│ E3  │                                 │
    │  └─────┘      └─────┘     └─────┘                                 │
    │                              │                                    │
    │                              │ moveTo(E2)                         │
    │                              ▼                                    │
    │  ┌─────┐      ┌─────┐     ┌─────┐      ┌─────┐                    │
    │  │ E1  │────▶│ E2  │────▶│ E3' │────▶│ E4' │ (new branch)       │
    │  └─────┘      └─────┘     └─────┘      └─────┘                    │
    │                                    │                              │
    │                                    │ create BranchSummary         │
    │                                    ▼                              │
    │                                  ┌─────┐                          │
    │                                  │ E5  │ (branch summary)         │
    │                                  └─────┘                          │
    │                                                                   │
    └───────────────────────────────────────────────────────────────────┘

Component Relationships

┌─────────────────────────────────────────────────────────────────────────────┐
│                          Component Relationships                            │
└─────────────────────────────────────────────────────────────────────────────┘

    User Code
        │
        ├── Creates ──► Agent
        │                  │
        │                  ├── Uses ──► AgentLoop
        │                  │                 │
        │                  │                 ├── Uses ──► StreamFn (LLM API)
        │                  │                 │
        │                  │                 └── Uses ──► Session
        │                  │
        │                  ├── Manages ──► AgentState
        │                  │
        │                  ├── Queues ──► SteeringQueue
        │                  │
        │                  └── Queues ──► FollowUpQueue
        │
        └── Interacts With ──► AgentHarness (optional, higher level)
                              │
                              ├── Manages ──► SessionRepo
                              │
                              ├── Manages ──► Skills
                              │
                              └── Manages ──► PromptTemplates

Data Flow

┌─────────────────────────────────────────────────────────────────────────────┐
│                            Data Flow Between Layers                         │
└─────────────────────────────────────────────────────────────────────────────┘

    User Input (String/Message)
              │
              ▼
    ┌──────────────────────┐
    │ Agent.prompt()       │
    │ - normalizeInput()   │
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ AgentState.messages  │  ──► AgentMessage[]
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ AgentLoop            │
    │ - transform_context  │
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ convertToLlm()       │  ──► Transforms AgentMessage[] to Message[]
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ LLM API (StreamFn)   │
    │ - Context: Message[] │
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ Response (Streaming) │
    │ - Text deltas        │
    │ - Tool call deltas   │
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ AssistantMessage     │
    │ - content: Message[] │
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ AgentState.messages  │  ──► Appended to conversation
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ Tool Execution       │
    │ - Extract ToolCalls  │
    │ - Execute tools      │
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ ToolResultMessage[]  │
    └──────────────────────┘
              │
              ▼
    ┌──────────────────────┐
    │ AgentState.messages  │  ──► Tool results appended
    └──────────────────────┘
              │
              │ (Loop back to LLM or end)
              ▼
    ┌──────────────────────┐
    │ Session Storage      │
    │ - JSONL format       │
    │ - Tree entries       │
    └──────────────────────┘

Summary

The AgentCore.jl architecture follows a clean separation of concerns:

  1. AgentHarness - Highest level, handles persistence and resources
  2. Agent - State management and event streaming
  3. AgentLoop - Core LLM interaction loop
  4. Session - Conversation history management

Each layer transforms data and passes it to the next layer, with clear interfaces and event hooks for customization.