update
This commit is contained in:
@@ -0,0 +1,386 @@
|
||||
# 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/`
|
||||
Reference in New Issue
Block a user