7.8 KiB
7.8 KiB
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:
- Architecture Overview - Understand the big picture
- Agent Component - Learn about state management and event streaming
- AgentLoop Component - Understand the core LLM interaction loop
- Types & Messages - Learn the data structures
- Session Management - Understand conversation history
- 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
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 conversationcontinue!()- Continue existing conversationsteer()- Queue message for next turnfollowUp()- Queue message after stopsubscribe()- 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 conversationagentLoopContinue()- Continue conversationrunAgentLoop()- Internal loop executionstreamAssistantResponse()- LLM API callexecuteToolCalls()- 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 messageappendCompaction()- Compress historymoveTo()- Navigate branchesbuildSessionContext()- 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 commandsread- Read fileswrite- Write filesedit- 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
# 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
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
# Agent is going wrong direction
steer(agent, UserMessage("Actually, let's do X instead"))
4. Use Follow-Up for Continuation
# 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
# 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
# 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
# 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
# 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
if !isnothing(agent.active_run)
println("Agent is busy")
else
println("Agent is idle")
end
Clear Queues
clearAllQueues(agent)
Reset State
reset!(agent)
Performance Tips
- Use parallel execution for independent tools
- Compact periodically for long conversations
- Use thinking_level wisely (higher = slower but better)
- Batch tool calls when possible
- Cache LLM responses when appropriate
Troubleshooting
Agent stuck in loop
# Check if agent is still processing
if hasQueuedMessages(agent)
# Clear queues
clearAllQueues(agent)
end
Too many tokens
# Compact session
compact_id = appendCompaction(
session,
summary,
first_kept_id,
token_count,
)
Tool execution failed
# Check tool result
if result.is_error
println("Tool failed: $(result.error)")
end
Next Steps
- Read Architecture Overview for deep understanding
- Explore Agent Component for state management
- Study AgentLoop for core logic
- Learn Types & Messages for data structures
- Master Session Management for persistence
- 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/