387 lines
7.8 KiB
Markdown
387 lines
7.8 KiB
Markdown
# AgentCore.jl - Learning Guide
|
|
|
|
## How to Use This Documentation
|
|
|
|
### Top-Down Learning Approach
|
|
|
|
This documentation is organized in a **top-down** order, starting from high-level concepts and drilling down into implementation details. Follow this sequence:
|
|
|
|
1. **Architecture Overview** - Understand the big picture
|
|
2. **Agent Component** - Learn about state management and event streaming
|
|
3. **AgentLoop Component** - Understand the core LLM interaction loop
|
|
4. **Types & Messages** - Learn the data structures
|
|
5. **Session Management** - Understand conversation history
|
|
6. **Tools** - Learn about tool execution
|
|
|
|
### Learning Style
|
|
|
|
- **Visual learners**: Study the ASCII diagrams
|
|
- **Hands-on learners**: Code examples provided for each section
|
|
- **Conceptual learners**: Read summaries and overviews first
|
|
|
|
## Quick Start
|
|
|
|
### Minimal Example
|
|
|
|
```julia
|
|
using AgentCore
|
|
|
|
# Create agent
|
|
agent = Agent(Dict(
|
|
:systemPrompt => "You are a helpful assistant.",
|
|
:model => Model(...),
|
|
:tools => [bash_tool],
|
|
))
|
|
|
|
# Run conversation
|
|
prompt(agent, "Hello!")
|
|
|
|
# Wait for completion
|
|
wait_for_idle(agent)
|
|
```
|
|
|
|
### Understanding the Flow
|
|
|
|
```
|
|
User Code
|
|
│
|
|
├─► Create Agent
|
|
│ ├─ Initialize state
|
|
│ ├─ Set up queues
|
|
│ └─ Register hooks
|
|
│
|
|
├─► prompt("Hello")
|
|
│ ├─ Validate input
|
|
│ └─ Start AgentLoop
|
|
│
|
|
├─► AgentLoop (runs in thread)
|
|
│ ├─ Stream LLM response
|
|
│ ├─ Execute tools
|
|
│ └─ Emit events
|
|
│
|
|
└─► Event handlers receive events
|
|
├─ MessageEndEvent
|
|
├─ ToolExecutionEndEvent
|
|
└─ AgentEndEvent
|
|
```
|
|
|
|
## Core Concepts
|
|
|
|
### Agent
|
|
|
|
**What it is**: High-level interface for LLM interactions
|
|
|
|
**What it does**:
|
|
- Manages conversation state
|
|
- Handles event streaming
|
|
- Queues steering/follow-up messages
|
|
- Provides hooks for customization
|
|
|
|
**Key methods**:
|
|
- `prompt()` - Start new conversation
|
|
- `continue!()` - Continue existing conversation
|
|
- `steer()` - Queue message for next turn
|
|
- `followUp()` - Queue message after stop
|
|
- `subscribe()` - Listen to events
|
|
|
|
### AgentLoop
|
|
|
|
**What it is**: Core LLM interaction loop
|
|
|
|
**What it does**:
|
|
- Calls LLM API with streaming
|
|
- Executes tool calls (parallel or sequential)
|
|
- Emits lifecycle events
|
|
- Handles steering/follow-up messages
|
|
|
|
**Key functions**:
|
|
- `agentLoop()` - Start new conversation
|
|
- `agentLoopContinue()` - Continue conversation
|
|
- `runAgentLoop()` - Internal loop execution
|
|
- `streamAssistantResponse()` - LLM API call
|
|
- `executeToolCalls()` - Tool execution
|
|
|
|
### Session
|
|
|
|
**What it is**: Conversation history management
|
|
|
|
**What it does**:
|
|
- Persists messages to storage
|
|
- Supports branching
|
|
- Implements compaction
|
|
- Manages conversation tree
|
|
|
|
**Key methods**:
|
|
- `appendMessage()` - Add message
|
|
- `appendCompaction()` - Compress history
|
|
- `moveTo()` - Navigate branches
|
|
- `buildSessionContext()` - Build context for LLM
|
|
|
|
### Tools
|
|
|
|
**What it is**: Functions agents can call
|
|
|
|
**What they do**:
|
|
- Execute external operations
|
|
- Return results to agent
|
|
- Support streaming updates
|
|
- Implement hooks
|
|
|
|
**Built-in tools**:
|
|
- `bash` - Execute shell commands
|
|
- `read` - Read files
|
|
- `write` - Write files
|
|
- `edit` - Edit files
|
|
|
|
## Event System
|
|
|
|
### Event Types
|
|
|
|
```
|
|
AgentEvent
|
|
├─ AgentStartEvent / AgentEndEvent
|
|
├─ TurnStartEvent / TurnEndEvent
|
|
├─ MessageStartEvent / MessageEndEvent
|
|
├─ MessageUpdateEvent
|
|
├─ ToolExecutionStartEvent / ToolExecutionEndEvent
|
|
└─ ToolExecutionUpdateEvent
|
|
```
|
|
|
|
### Event Flow
|
|
|
|
```
|
|
AgentStartEvent
|
|
│
|
|
├─ TurnStartEvent
|
|
│ ├─ MessageStartEvent (user)
|
|
│ ├─ MessageEndEvent (user)
|
|
│ ├─ MessageStartEvent (assistant)
|
|
│ ├─ MessageUpdateEvent (streaming)
|
|
│ ├─ MessageEndEvent (assistant)
|
|
│ ├─ ToolExecutionStartEvent
|
|
│ ├─ ToolExecutionEndEvent
|
|
│ └─ TurnEndEvent
|
|
│
|
|
└─ AgentEndEvent
|
|
```
|
|
|
|
## Data Flow
|
|
|
|
### Message Transformation
|
|
|
|
```
|
|
AgentMessage[] (internal)
|
|
│
|
|
├─ transform_context() (optional)
|
|
▼
|
|
AgentMessage[] (transformed)
|
|
│
|
|
├─ convert_to_llm()
|
|
▼
|
|
Message[] (LLM API)
|
|
```
|
|
|
|
### Tool Execution Flow
|
|
|
|
```
|
|
ToolCall (in assistant message)
|
|
│
|
|
├─ before_tool_call hook
|
|
├─ prepareToolCall()
|
|
├─ execute()
|
|
├─ after_tool_call hook
|
|
└─ createToolResultMessage()
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Use Hooks for Customization
|
|
|
|
```julia
|
|
# Before tool call
|
|
before_hook = (context, signal) -> begin
|
|
println("Executing: $(context.tool_call.name)")
|
|
return nothing
|
|
end
|
|
|
|
# After tool call
|
|
after_hook = (context, signal) -> begin
|
|
if context.is_error
|
|
println("Tool failed: $(context.tool_call.name)")
|
|
end
|
|
return nothing
|
|
end
|
|
```
|
|
|
|
### 2. Monitor Events
|
|
|
|
```julia
|
|
subscribe(agent) do event, signal
|
|
if event isa MessageEndEvent
|
|
println("Message: $(event.message)")
|
|
elseif event isa ToolExecutionEndEvent
|
|
println("Tool completed: $(event.tool_name)")
|
|
end
|
|
end
|
|
```
|
|
|
|
### 3. Use Steering for Redirection
|
|
|
|
```julia
|
|
# Agent is going wrong direction
|
|
steer(agent, UserMessage("Actually, let's do X instead"))
|
|
```
|
|
|
|
### 4. Use Follow-Up for Continuation
|
|
|
|
```julia
|
|
# Agent thinks it's done, but user wants more
|
|
followUp(agent, UserMessage("Wait, there's one more thing"))
|
|
```
|
|
|
|
## Common Patterns
|
|
|
|
### Pattern 1: Conversation with Memory
|
|
|
|
```julia
|
|
# Use Session to persist conversation
|
|
storage = JsonlSessionStorage(...)
|
|
session = Session(storage)
|
|
|
|
# Add messages to session
|
|
appendMessage(session, user_message)
|
|
appendMessage(session, assistant_message)
|
|
|
|
# Build context from session
|
|
context = buildSessionContext(session)
|
|
```
|
|
|
|
### Pattern 2: Long Conversations
|
|
|
|
```julia
|
|
# Compact periodically to stay within context limits
|
|
if token_count > MAX_TOKENS * 0.8
|
|
compact_id = appendCompaction(
|
|
session,
|
|
summary,
|
|
first_kept_id,
|
|
token_count,
|
|
)
|
|
end
|
|
```
|
|
|
|
### Pattern 3: Branching Conversations
|
|
|
|
```julia
|
|
# User wants to explore alternative
|
|
session.moveTo(branch_point_id)
|
|
|
|
# Create new branch
|
|
appendBranchSummary(session, "Exploring alternative approach")
|
|
appendMessage(session, new_user_message)
|
|
```
|
|
|
|
### Pattern 4: Custom Tools
|
|
|
|
```julia
|
|
# Create custom tool
|
|
custom_tool = AgentTool(
|
|
"custom",
|
|
"custom",
|
|
"Does custom thing",
|
|
...,
|
|
execute_function,
|
|
nothing,
|
|
EXECUTION_PARALLEL,
|
|
)
|
|
|
|
# Add to agent
|
|
agent = Agent(Dict(:tools => [custom_tool]))
|
|
```
|
|
|
|
## Debugging
|
|
|
|
### Check Active Run
|
|
|
|
```julia
|
|
if !isnothing(agent.active_run)
|
|
println("Agent is busy")
|
|
else
|
|
println("Agent is idle")
|
|
end
|
|
```
|
|
|
|
### Clear Queues
|
|
|
|
```julia
|
|
clearAllQueues(agent)
|
|
```
|
|
|
|
### Reset State
|
|
|
|
```julia
|
|
reset!(agent)
|
|
```
|
|
|
|
## Performance Tips
|
|
|
|
1. **Use parallel execution** for independent tools
|
|
2. **Compact periodically** for long conversations
|
|
3. **Use thinking_level wisely** (higher = slower but better)
|
|
4. **Batch tool calls** when possible
|
|
5. **Cache LLM responses** when appropriate
|
|
|
|
## Troubleshooting
|
|
|
|
### Agent stuck in loop
|
|
|
|
```julia
|
|
# Check if agent is still processing
|
|
if hasQueuedMessages(agent)
|
|
# Clear queues
|
|
clearAllQueues(agent)
|
|
end
|
|
```
|
|
|
|
### Too many tokens
|
|
|
|
```julia
|
|
# Compact session
|
|
compact_id = appendCompaction(
|
|
session,
|
|
summary,
|
|
first_kept_id,
|
|
token_count,
|
|
)
|
|
```
|
|
|
|
### Tool execution failed
|
|
|
|
```julia
|
|
# Check tool result
|
|
if result.is_error
|
|
println("Tool failed: $(result.error)")
|
|
end
|
|
```
|
|
|
|
## Next Steps
|
|
|
|
1. Read **Architecture Overview** for deep understanding
|
|
2. Explore **Agent Component** for state management
|
|
3. Study **AgentLoop** for core logic
|
|
4. Learn **Types & Messages** for data structures
|
|
5. Master **Session Management** for persistence
|
|
6. Build **Tools** for custom functionality
|
|
|
|
## Resources
|
|
|
|
- Original TypeScript implementation: `@earendil-works/pi-agent-core`
|
|
- AgentCore.jl source code: `src/`
|
|
- Examples: `examples/`
|
|
|
|
## Community
|
|
|
|
For questions and discussions:
|
|
- GitHub Issues: `/issues`
|
|
- Documentation: `docs/`
|