523 lines
13 KiB
Markdown
523 lines
13 KiB
Markdown
# Learning Path and Study Guide
|
|
|
|
## Overview
|
|
|
|
This guide helps you learn the Pi Agent architecture **top-down**, starting from high-level concepts to implementation details.
|
|
|
|
---
|
|
|
|
## Phase 1: Big Picture (1-2 hours)
|
|
|
|
### Goal: Understand how components fit together
|
|
|
|
### Resources
|
|
1. **01-ARCHITECTURE-OVERVIEW.md** - Read this first
|
|
2. **Diagrams** - Study the architecture diagrams
|
|
|
|
### Key Questions to Answer
|
|
|
|
✅ What are the two main layers?
|
|
✅ What does each layer do?
|
|
✅ How do messages flow through the system?
|
|
✅ What is the relationship between Agent and AgentHarness?
|
|
✅ What are the main event types?
|
|
✅ How do tools integrate with the agent?
|
|
✅ What is the purpose of hooks?
|
|
|
|
### Exercises
|
|
|
|
1. Draw the architecture diagram from memory
|
|
2. List 3 use cases for each hook type
|
|
3. Trace a message from input to LLM to output
|
|
|
|
---
|
|
|
|
## Phase 2: Core Agent (2-3 hours)
|
|
|
|
### Goal: Understand the low-level agent loop
|
|
|
|
### Resources
|
|
1. **02-AGENT-LOOP-DETAILED.md** - Study the agent loop
|
|
2. Read `src/agent-loop.ts` (skim, focus on comments)
|
|
3. Read `src/types.ts` - Understand AgentEvent, AgentMessage, AgentTool
|
|
|
|
### Key Concepts
|
|
|
|
- **runAgentLoop()** - Starts a new conversation
|
|
- **runAgentLoopContinue()** - Continues existing conversation
|
|
- **runLoop()** - Main iteration (outer and inner loops)
|
|
- **streamAssistantResponse()** - Streams LLM response
|
|
- **executeToolCalls()** - Executes tool calls
|
|
- **prepareToolCall()** - Validates and prepares tools
|
|
- **executePreparedToolCall()** - Executes tool with updates
|
|
- **finalizeExecutedToolCall()** - Finalizes with hooks
|
|
|
|
### Key Questions to Answer
|
|
|
|
✅ What's the difference between outer and inner loop?
|
|
✅ How does streaming work?
|
|
✅ How are tool calls executed (sequential vs parallel)?
|
|
✅ What happens when a tool is blocked?
|
|
✅ How are errors handled?
|
|
✅ What are the four phases of tool execution?
|
|
✅ How does the loop know when to stop?
|
|
|
|
### Exercises
|
|
|
|
1. Trace through a conversation with 1 prompt + 2 tool calls
|
|
2. Draw the outer/inner loop flow
|
|
3. Explain how abort signals propagate
|
|
4. Explain queue draining (steering/follow-up)
|
|
|
|
---
|
|
|
|
## Phase 3: Hooks System (2-3 hours)
|
|
|
|
### Goal: Understand how to customize agent behavior
|
|
|
|
### Resources
|
|
1. **03-HOOK-SYSTEM.md** - Study all hooks
|
|
2. Read `src/types.ts` - Hook types and contexts
|
|
|
|
### Hook Categories
|
|
|
|
**Message Transformation**:
|
|
- `convertToLlm` - Convert messages to LLM format
|
|
- `transformContext` - Manipulate context before LLM
|
|
|
|
**Lifecycle Hooks**:
|
|
- `beforeToolCall` - Block or modify tool execution
|
|
- `afterToolCall` - Override tool results
|
|
- `shouldStopAfterTurn` - Request early termination
|
|
- `prepareNextTurn` - Update context/model/thinking
|
|
|
|
**Queue Draining**:
|
|
- `getSteeringMessages` - Interrupt agent mid-work
|
|
- `getFollowUpMessages` - Queue messages for later
|
|
|
|
### Key Questions to Answer
|
|
|
|
✅ What hooks receive abort signals?
|
|
✅ What hooks can block execution?
|
|
✅ What is the execution order of hooks?
|
|
✅ What's the difference between beforeToolCall and afterToolCall?
|
|
✅ How do you implement context window management?
|
|
✅ How do you implement permission checks?
|
|
✅ What's the difference between steering and follow-up?
|
|
|
|
### Exercises
|
|
|
|
1. Implement a hook that logs all tool calls
|
|
2. Implement a hook that blocks dangerous commands
|
|
3. Implement a hook that summarizes conversation every 5 turns
|
|
4. Implement a hook that switches to high thinking for complex tasks
|
|
|
|
---
|
|
|
|
## Phase 4: AgentHarness (3-4 hours)
|
|
|
|
### Goal: Understand high-level API and session management
|
|
|
|
### Resources
|
|
1. **06-AGENTHARNESS-REFERENCE.md** - Study the harness API
|
|
2. Read `src/harness/agent-harness.ts` (focus on public methods)
|
|
|
|
### Key Concepts
|
|
|
|
- **Session** - Persistent conversation history
|
|
- **SessionTreeEntry** - Individual entries in conversation
|
|
- **Context Building** - Derive LLM context from session
|
|
- **Branching** - Create new conversation paths
|
|
- **Compaction** - Summarize old history
|
|
|
|
### API Methods
|
|
|
|
**Core**:
|
|
- `prompt()` - Run new conversation
|
|
- `skill()` - Execute skill
|
|
- `promptFromTemplate()` - Run template
|
|
|
|
**Queues**:
|
|
- `steer()` - Interrupt agent
|
|
- `followUp()` - Queue message
|
|
- `nextTurn()` - Queue for next turn
|
|
|
|
**Session**:
|
|
- `compact()` - Compress context
|
|
- `navigateTree()` - Branch conversation
|
|
|
|
**State**:
|
|
- `setModel()` - Change model
|
|
- `setThinkingLevel()` - Change reasoning level
|
|
- `setTools()` / `setActiveTools()` - Manage tools
|
|
|
|
### Key Questions to Answer
|
|
|
|
✅ What's the difference between steer() and followUp()?
|
|
✅ How does branching work?
|
|
✅ How does compaction work?
|
|
✅ What's the relationship between Session and SessionStorage?
|
|
✅ What's the difference between MessageEntry and CustomEntry?
|
|
✅ How are pending writes handled during active turns?
|
|
✅ What hooks does AgentHarness provide?
|
|
|
|
### Exercises
|
|
|
|
1. Create a session, add messages, and build context
|
|
2. Implement branching and navigate between branches
|
|
3. Implement compaction and verify it works
|
|
4. Set up hooks for tool call logging
|
|
|
|
---
|
|
|
|
## Phase 5: Session Architecture (2-3 hours)
|
|
|
|
### Goal: Understand persistence and tree structure
|
|
|
|
### Resources
|
|
1. **04-SESSION-ARCHITECTURE.md** - Study session system
|
|
2. Read `src/harness/session/session.ts`
|
|
|
|
### Key Concepts
|
|
|
|
- **SessionTreeEntry** - Tree nodes
|
|
- **Path Tracing** - From leaf to root
|
|
- **Context Building** - Projection to messages
|
|
- **Default Transform** - Compaction logic
|
|
- **Forking** - Create branches
|
|
|
|
### Key Questions to Answer
|
|
|
|
✅ How is conversation history stored?
|
|
✅ What's the difference between ID and parentId?
|
|
✅ How does the session know the current head?
|
|
✅ What entries appear in the LLM context?
|
|
✅ How does compaction work at the session level?
|
|
✅ What's the difference between fork and navigateTree()?
|
|
✅ How are custom entries different from messages?
|
|
|
|
### Exercises
|
|
|
|
1. Create a session and trace its tree
|
|
2. Add custom entries and verify they don't appear in context
|
|
3. Fork a session and compare contexts
|
|
4. Compact a session and verify size reduction
|
|
|
|
---
|
|
|
|
## Phase 6: Tool Execution (2-3 hours)
|
|
|
|
### Goal: Understand how tools work
|
|
|
|
### Resources
|
|
1. **05-TOOL-EXECUTION.md** - Study tool system
|
|
2. Read `src/harness/tools/` - Built-in tools
|
|
|
|
### Key Concepts
|
|
|
|
- **AgentTool** - Tool definition
|
|
- **Tool Execution Flow** - Prepare → Execute → Finalize
|
|
- **Sequential vs Parallel** - Execution modes
|
|
- **Streaming Updates** - Progress updates
|
|
- **Error Handling** - Throw vs return error
|
|
|
|
### Tool Execution Flow
|
|
|
|
```
|
|
prepareToolCall()
|
|
├─ Find tool
|
|
├─ Validate args
|
|
└─ beforeToolCall()
|
|
|
|
executePreparedToolCall()
|
|
└─ tool.execute()
|
|
|
|
finalizeExecutedToolCall()
|
|
└─ afterToolCall()
|
|
|
|
emitToolResult()
|
|
```
|
|
|
|
### Key Questions to Answer
|
|
|
|
✅ What's the difference between prepareArguments and execute?
|
|
✅ How do streaming updates work?
|
|
✅ When do you throw vs return an error?
|
|
✅ How are sequential vs parallel tools different?
|
|
✅ What's in the ToolContext passed to execute()?
|
|
✅ How do you handle long-running operations?
|
|
✅ What's the terminate flag for?
|
|
|
|
### Exercises
|
|
|
|
1. Implement a custom tool (e.g., weather API)
|
|
2. Implement streaming updates for long operation
|
|
3. Implement tool with error handling
|
|
4. Test sequential vs parallel execution
|
|
|
|
---
|
|
|
|
## Phase 7: Data Flow (2-3 hours)
|
|
|
|
### Goal: Understand how data flows through the system
|
|
|
|
### Resources
|
|
1. **07-DATA-FLOW-STATE.md** - Study data flow
|
|
2. Read `src/agent.ts` - State management
|
|
|
|
### Key Concepts
|
|
|
|
- **AgentMessage** - Unified message type
|
|
- **AgentEvent** - Event stream
|
|
- **AgentContext** - Snapshot for LLM
|
|
- **State Mutation** - How state changes on events
|
|
- **Queue Flow** - Steering and follow-up
|
|
|
|
### Key Questions to Answer
|
|
|
|
✅ How do messages flow from input to LLM?
|
|
✅ How is state mutated on events?
|
|
✅ What's the difference between AgentContext and AgentState?
|
|
✅ How do hooks transform data?
|
|
✅ How are abort signals propagated?
|
|
✅ What's the relationship between queue mode and draining?
|
|
✅ How are pending writes handled?
|
|
|
|
### Exercises
|
|
|
|
1. Trace a message through the entire flow
|
|
2. Trace a tool call through all hooks
|
|
3. Trace an abort through the system
|
|
4. Draw the complete data flow diagram
|
|
|
|
---
|
|
|
|
## Phase 8: Implementation (4-6 hours)
|
|
|
|
### Goal: Implement your own version
|
|
|
|
### Steps
|
|
|
|
1. **Design your data structures** (in Julia)
|
|
- AgentMessage equivalent
|
|
- AgentEvent equivalent
|
|
- AgentTool equivalent
|
|
|
|
2. **Implement core agent loop**
|
|
- Message streaming
|
|
- Tool execution
|
|
- Event emission
|
|
|
|
3. **Add hooks system**
|
|
- Hook registration
|
|
- Hook execution
|
|
- Return value handling
|
|
|
|
4. **Implement session persistence**
|
|
- Tree structure
|
|
- Entry types
|
|
- Context building
|
|
|
|
5. **Add harness layer**
|
|
- High-level API
|
|
- Queue management
|
|
- Branching
|
|
|
|
### Recommended Order
|
|
|
|
```
|
|
1. Data Types (2h)
|
|
├─ AgentMessage
|
|
├─ AgentEvent
|
|
└─ AgentTool
|
|
|
|
2. Core Loop (4h)
|
|
├─ streamAssistantResponse
|
|
├─ executeToolCalls
|
|
└─ runLoop
|
|
|
|
3. State Management (2h)
|
|
├─ AgentState
|
|
└─ Event handlers
|
|
|
|
4. Hooks (3h)
|
|
├─ Hook system
|
|
└─ Implement hooks
|
|
|
|
5. Session (4h)
|
|
├─ Tree structure
|
|
├─ Persistence
|
|
└─ Context building
|
|
|
|
6. Harness (4h)
|
|
├─ Public API
|
|
├─ Queue management
|
|
└─ Branching
|
|
```
|
|
|
|
### Tips
|
|
|
|
- Start simple, iterate
|
|
- Test each component
|
|
- Follow TypeScript patterns
|
|
- Use your language's idioms
|
|
|
|
---
|
|
|
|
## Quick Reference
|
|
|
|
### Agent Layer
|
|
|
|
| Function | Purpose |
|
|
|----------|---------|
|
|
| `runAgentLoop()` | Start new conversation |
|
|
| `runAgentLoopContinue()` | Continue existing |
|
|
| `runLoop()` | Main iteration |
|
|
| `streamAssistantResponse()` | Stream LLM |
|
|
| `executeToolCalls()` | Execute tools |
|
|
|
|
### AgentHarness Layer
|
|
|
|
| Method | Purpose |
|
|
|--------|---------|
|
|
| `prompt()` | Run conversation |
|
|
| `steer()` | Interrupt agent |
|
|
| `followUp()` | Queue message |
|
|
| `compact()` | Compress context |
|
|
| `navigateTree()` | Branch conversation |
|
|
|
|
### Hooks
|
|
|
|
| Hook | Purpose |
|
|
|------|---------|
|
|
| `convertToLlm` | Convert messages |
|
|
| `transformContext` | Manipulate context |
|
|
| `beforeToolCall` | Block tools |
|
|
| `afterToolCall` | Override results |
|
|
| `shouldStopAfterTurn` | Request stop |
|
|
| `prepareNextTurn` | Update config |
|
|
| `getSteeringMessages` | Interrupt |
|
|
| `getFollowUpMessages` | Queue for later |
|
|
|
|
### Entry Types
|
|
|
|
| Type | Purpose |
|
|
|------|---------|
|
|
| `message` | User/assistant/toolResult |
|
|
| `model_change` | Model switch |
|
|
| `thinking_level_change` | Reasoning level |
|
|
| `active_tools_change` | Tools change |
|
|
| `compaction` | History summary |
|
|
| `branch_summary` | Branch marker |
|
|
| `custom` | App data |
|
|
| `custom_message` | Custom message |
|
|
| `label` | User label |
|
|
| `leaf` | Current head |
|
|
|
|
---
|
|
|
|
## Common Patterns
|
|
|
|
### 1. Context Window Management
|
|
|
|
```typescript
|
|
transformContext: async (messages, signal) => {
|
|
if (estimateTokens(messages) > MAX_TOKENS) {
|
|
return pruneOldMessages(messages);
|
|
}
|
|
return messages;
|
|
}
|
|
```
|
|
|
|
### 2. Tool Permission Checks
|
|
|
|
```typescript
|
|
beforeToolCall: async ({ toolCall, args }, signal) => {
|
|
if (toolCall.name === "bash" && !await canExecute(args)) {
|
|
return { block: true, reason: "Permission denied" };
|
|
}
|
|
return undefined;
|
|
}
|
|
```
|
|
|
|
### 3. Streaming Updates
|
|
|
|
```typescript
|
|
execute: async (id, params, signal, onUpdate) => {
|
|
for await (const chunk of process()) {
|
|
onUpdate({ content: [{ type: "text", text: `Progress: ${chunk}%` }] });
|
|
}
|
|
return finalResult;
|
|
}
|
|
```
|
|
|
|
### 4. Branching
|
|
|
|
```typescript
|
|
const branchSession = await session.fork(leafId);
|
|
const branchHarness = new AgentHarness({ session: branchSession });
|
|
```
|
|
|
|
---
|
|
|
|
## Study Schedule
|
|
|
|
| Week | Focus | Hours |
|
|
|------|-------|-------|
|
|
| 1 | Phases 1-2 | 6-8 |
|
|
| 2 | Phases 3-4 | 8-10 |
|
|
| 3 | Phases 5-6 | 6-8 |
|
|
| 4 | Phase 7-8 | 8-10 |
|
|
|
|
**Total**: 28-36 hours
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
After understanding the architecture:
|
|
|
|
1. **Implement in Julia**
|
|
- Start with data types
|
|
- Implement core loop
|
|
- Add hooks
|
|
- Implement session
|
|
|
|
2. **Extend Functionality**
|
|
- Add new tool types
|
|
- Implement custom hooks
|
|
- Add new entry types
|
|
|
|
3. **Optimize**
|
|
- Improve token estimation
|
|
- Optimize context pruning
|
|
- Parallelize operations
|
|
|
|
4. **Production**
|
|
- Error handling
|
|
- Logging
|
|
- Monitoring
|
|
|
|
---
|
|
|
|
## Questions to Test Understanding
|
|
|
|
1. How would you implement a tool that requires user approval?
|
|
2. How would you implement conversation summarization every 10 turns?
|
|
3. How would you implement context pruning based on importance?
|
|
4. How would you implement branching with automatic summaries?
|
|
5. How would you implement tool execution rate limiting?
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
**Top-down learning**:
|
|
1. Big picture (layers, components)
|
|
2. Core agent (loop, streaming)
|
|
3. Hooks (customization)
|
|
4. Harness (session, persistence)
|
|
5. Data flow (how everything connects)
|
|
|
|
**Key insight**: The system is built on **messages** and **events** with hooks for customization.
|