update
This commit is contained in:
@@ -0,0 +1,403 @@
|
||||
# Quick Start Guide
|
||||
|
||||
## Learning the Pi Agent Architecture
|
||||
|
||||
This guide helps you quickly understand the agent system and prepare for reimplementation in Julia.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Core Concepts (30 minutes)
|
||||
|
||||
### 1. Two-Layer Architecture
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────────┐
|
||||
│ Application Layer │
|
||||
│ ┌──────────────┐ ┌─────────────────┐ ┌───────────────────────┐ │
|
||||
│ │ Agent (Core) │ │ AgentHarness │ │ Your Custom App │ │
|
||||
│ └───────┬──────┘ └────────┬────────┘ └─────────┬────────────┘ │
|
||||
└──────────┼───────────────────┼─────────────────────┼────────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌─────────────────┐ ┌────────────────┐
|
||||
│ agent-loop.ts│ │ agent-harness.ts│ │ Session Repo │
|
||||
│ types.ts │ │ │ │ │
|
||||
└──────────────┘ └─────────────────┘ └────────────────┘
|
||||
```
|
||||
|
||||
**Key Insight**:
|
||||
- **Agent Core** = Low-level async iteration (messages in, messages out)
|
||||
- **AgentHarness** = High-level session management with persistence
|
||||
|
||||
---
|
||||
|
||||
### 2. Core Data Types
|
||||
|
||||
```typescript
|
||||
// Message: Basic unit of conversation
|
||||
interface Message {
|
||||
role: "user" | "assistant" | "toolResult";
|
||||
content: (TextContent | ImageContent)[];
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
// Tool: Function the agent can call
|
||||
interface AgentTool {
|
||||
name: string;
|
||||
label: string;
|
||||
description: string;
|
||||
parameters: Schema;
|
||||
execute(toolCallId, params, signal, onUpdate): Promise<Result>;
|
||||
}
|
||||
|
||||
// Event: Notification of state changes
|
||||
type AgentEvent =
|
||||
| { type: "agent_start" }
|
||||
| { type: "agent_end"; messages: Message[] }
|
||||
| { type: "turn_start" }
|
||||
| { type: "turn_end"; message: Message; toolResults: Message[] }
|
||||
| { type: "message_start"; message: Message }
|
||||
| { type: "message_update"; message: Message }
|
||||
| { type: "message_end"; message: Message }
|
||||
| { type: "tool_execution_start"; ... }
|
||||
| { type: "tool_execution_end"; ... };
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Message Flow (45 minutes)
|
||||
|
||||
### The Agent Loop
|
||||
|
||||
```
|
||||
1. User Input
|
||||
└─► Agent.prompt("Hello")
|
||||
|
||||
2. Agent Start
|
||||
└─► emit: agent_start, turn_start, message_start/end (user)
|
||||
|
||||
3. LLM Streaming
|
||||
└─► streamAssistantResponse()
|
||||
└─► transformContext() → convertToLlm() → streamFn()
|
||||
|
||||
4. Tool Execution
|
||||
└─► executeToolCalls()
|
||||
└─► prepare → execute → finalize (for each tool)
|
||||
|
||||
5. Turn End
|
||||
└─► emit: turn_end
|
||||
└─► Check hooks, drain queues, decide next turn
|
||||
|
||||
6. Repeat or End
|
||||
└─► Loop continues until no more work
|
||||
```
|
||||
|
||||
### Key Insight
|
||||
|
||||
**Everything is a message**: User input, assistant response, tool calls, tool results, steering messages.
|
||||
|
||||
**Everything is an event**: State changes are emitted as events for UI updates.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Hooks System (30 minutes)
|
||||
|
||||
### Hook Categories
|
||||
|
||||
| Category | Purpose | When Called |
|
||||
|----------|---------|-------------|
|
||||
| `convertToLlm` | Filter/transform messages | Before LLM call |
|
||||
| `transformContext` | Manipulate context | Before LLM call |
|
||||
| `beforeToolCall` | Block tool execution | Before tool runs |
|
||||
| `afterToolCall` | Override tool results | After tool runs |
|
||||
| `shouldStopAfterTurn` | Request early stop | After turn ends |
|
||||
| `prepareNextTurn` | Update config | Before next turn |
|
||||
| `getSteeringMessages` | Interrupt agent | After turn ends |
|
||||
| `getFollowUpMessages` | Queue messages | When agent stops |
|
||||
|
||||
### Hook Flow
|
||||
|
||||
```
|
||||
Agent.prompt("Build app")
|
||||
│
|
||||
├─► transformContext() [hook]
|
||||
│
|
||||
├─► convertToLlm() [hook]
|
||||
│
|
||||
├─► LLM call
|
||||
│
|
||||
├─► executeToolCalls()
|
||||
│ ├─► beforeToolCall() [hook]
|
||||
│ ├─► tool.execute()
|
||||
│ └─► afterToolCall() [hook]
|
||||
│
|
||||
└─► turn_end
|
||||
├─► shouldStopAfterTurn() [hook]
|
||||
├─► prepareNextTurn() [hook]
|
||||
├─► getSteeringMessages() [hook]
|
||||
└─► getFollowUpMessages() [hook]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: AgentHarness (45 minutes)
|
||||
|
||||
### High-Level API
|
||||
|
||||
```typescript
|
||||
// Create harness
|
||||
const harness = new AgentHarness({
|
||||
session: session,
|
||||
models: models,
|
||||
tools: [weatherTool, gitTool],
|
||||
activeToolNames: ["weather", "git"],
|
||||
model: gpt4Model,
|
||||
thinkingLevel: "medium"
|
||||
});
|
||||
|
||||
// Main operations
|
||||
await harness.prompt("What's the weather in London?");
|
||||
|
||||
// Queue management
|
||||
await harness.steer("Wait, check this first"); // Interrupt
|
||||
await harness.followUp("Now summarize"); // After agent stops
|
||||
await harness.nextTurn("Also deploy"); // Next turn
|
||||
|
||||
// Session management
|
||||
await harness.compact(); // Compress context
|
||||
await harness.navigateTree(entryId); // Branch conversation
|
||||
```
|
||||
|
||||
### Session Tree
|
||||
|
||||
```
|
||||
Session = Conversation History as a Tree
|
||||
|
||||
root
|
||||
├─ message [user prompt #1]
|
||||
│ └─ message [assistant #1]
|
||||
│ └─ tool_result [result]
|
||||
│ └─ message [user prompt #2]
|
||||
│ └─ compaction [summary]
|
||||
│ ├─ retained: [recent messages]
|
||||
│ └─ message [assistant continues]
|
||||
│ └─ leaf [current head]
|
||||
│
|
||||
└─ branch_summary [point where branch created]
|
||||
└─ message [new branch]
|
||||
└─ leaf [new head]
|
||||
```
|
||||
|
||||
**Key Operations**:
|
||||
- `buildContext()` → Get LLM context from tree
|
||||
- `fork()` → Create branch at point
|
||||
- `compact()` → Summarize history
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Tool Execution (30 minutes)
|
||||
|
||||
### Tool Lifecycle
|
||||
|
||||
```
|
||||
1. LLM sends tool call
|
||||
└─► AssistantMessage with toolCall block
|
||||
|
||||
2. prepareToolCall()
|
||||
├─► Find tool by name
|
||||
├─► Validate arguments
|
||||
└─► beforeToolCall() hook
|
||||
|
||||
3. executePreparedToolCall()
|
||||
└─► tool.execute() with onUpdate callback
|
||||
|
||||
4. finalizeExecutedToolCall()
|
||||
└─► afterToolCall() hook
|
||||
|
||||
5. Emit events
|
||||
├─► tool_execution_start
|
||||
├─► tool_execution_update (streaming)
|
||||
└─► tool_execution_end
|
||||
```
|
||||
|
||||
### Tool Definition
|
||||
|
||||
```typescript
|
||||
const weatherTool: AgentTool = {
|
||||
name: "get_weather",
|
||||
label: "Get Weather",
|
||||
description: "Get current weather for a city",
|
||||
parameters: Type.Object({ city: Type.String() }),
|
||||
execute: async (toolCallId, params, signal, onUpdate) => {
|
||||
// Check for abort
|
||||
if (signal?.aborted) throw new Error("Aborted");
|
||||
|
||||
// Long operation with streaming
|
||||
const result = await fetchWeather(params.city);
|
||||
onUpdate({ content: [{ type: "text", text: "Fetching..." }] });
|
||||
|
||||
return {
|
||||
content: [{ type: "text", text: result }],
|
||||
details: { city: params.city, temp: result.temp },
|
||||
usage: { input: 0, output: 0, ... }
|
||||
};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Session Persistence (30 minutes)
|
||||
|
||||
### 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 point |
|
||||
| `custom` | App data (not visible to model) |
|
||||
| `custom_message` | Custom message |
|
||||
| `label` | User label |
|
||||
| `leaf` | Current head |
|
||||
|
||||
### Context Building
|
||||
|
||||
```typescript
|
||||
// 1. Get path from leaf to root
|
||||
const pathEntries = await session.getBranch();
|
||||
|
||||
// 2. Apply transforms (compaction)
|
||||
const contextEntries = defaultContextEntryTransform(pathEntries);
|
||||
|
||||
// 3. Project entries to messages
|
||||
const messages = contextEntries.flatMap(sessionEntryToContextMessages);
|
||||
|
||||
// 4. Derive state (model, thinking level, active tools)
|
||||
const state = deriveSessionContextState(pathEntries);
|
||||
|
||||
// 5. Return context
|
||||
return { ...state, messages };
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
### What to Remember
|
||||
|
||||
1. **Two layers**: Agent (core) + AgentHarness (high-level)
|
||||
2. **Messages everywhere**: Input, output, tools, events
|
||||
3. **Hooks for customization**: Transform messages, block tools, override results
|
||||
4. **Session = Tree**: Persistent conversation history with branching
|
||||
5. **Events for UI**: All state changes emitted as events
|
||||
6. **Tool lifecycle**: Prepare → Execute → Finalize → Emit
|
||||
|
||||
### Next Steps
|
||||
|
||||
1. **Read the detailed docs**:
|
||||
- `01-ARCHITECTURE-OVERVIEW.md` - Big picture
|
||||
- `02-AGENT-LOOP-DETAILED.md` - Core loop
|
||||
- `03-HOOK-SYSTEM.md` - Hooks reference
|
||||
- `04-SESSION-ARCHITECTURE.md` - Session system
|
||||
- `05-TOOL-EXECUTION.md` - Tool system
|
||||
- `06-AGENTHARNESS-REFERENCE.md` - API reference
|
||||
- `07-DATA-FLOW-STATE.md` - Data flow
|
||||
- `08-LEARNING-PATH.md` - Study guide
|
||||
- `09-DIAGRAMS.md` - Visual diagrams
|
||||
|
||||
2. **Design your Julia implementation**:
|
||||
- Data types
|
||||
- Core agent loop
|
||||
- Hook system
|
||||
- Session persistence
|
||||
- Tool execution
|
||||
|
||||
3. **Start coding**:
|
||||
- Implement basic types
|
||||
- Implement core loop
|
||||
- Add hooks
|
||||
- Add session
|
||||
- Add harness
|
||||
|
||||
### Common Patterns
|
||||
|
||||
**Context window management**:
|
||||
```typescript
|
||||
transformContext: async (messages) => {
|
||||
if (estimateTokens(messages) > MAX_TOKENS) {
|
||||
return pruneOldMessages(messages);
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
```
|
||||
|
||||
**Tool permission checks**:
|
||||
```typescript
|
||||
beforeToolCall: async ({ toolCall }) => {
|
||||
if (toolCall.name === "bash" && !await canExecute()) {
|
||||
return { block: true, reason: "Permission denied" };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
```
|
||||
|
||||
**Streaming updates**:
|
||||
```typescript
|
||||
execute: async (id, params, signal, onUpdate) => {
|
||||
for await (const chunk of process()) {
|
||||
onUpdate({ content: [{ type: "text", text: `Progress: ${chunk}%` }] });
|
||||
}
|
||||
return finalResult;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Agent Core (agent.ts, agent-loop.ts)
|
||||
|
||||
| Function | Purpose |
|
||||
|----------|---------|
|
||||
| `runAgentLoop()` | Start new conversation |
|
||||
| `runAgentLoopContinue()` | Continue existing |
|
||||
| `runLoop()` | Main iteration |
|
||||
| `streamAssistantResponse()` | Stream LLM |
|
||||
| `executeToolCalls()` | Execute tools |
|
||||
|
||||
### AgentHarness API
|
||||
|
||||
| Method | Purpose |
|
||||
|--------|---------|
|
||||
| `prompt()` | Run conversation |
|
||||
| `steer()` | Interrupt agent |
|
||||
| `followUp()` | Queue message |
|
||||
| `compact()` | Compress context |
|
||||
| `navigateTree()` | Branch conversation |
|
||||
|
||||
### Hook Types
|
||||
|
||||
| Hook | Purpose |
|
||||
|------|---------|
|
||||
| `convertToLlm` | Convert messages |
|
||||
| `beforeToolCall` | Block tools |
|
||||
| `afterToolCall` | Override results |
|
||||
| `shouldStopAfterTurn` | Request stop |
|
||||
|
||||
### Entry Types
|
||||
|
||||
| Type | Purpose |
|
||||
|------|---------|
|
||||
| `message` | Conversation messages |
|
||||
| `compaction` | History summary |
|
||||
| `branch_summary` | Branch point |
|
||||
|
||||
---
|
||||
|
||||
**You now have the foundation to reimplement the agent in Julia!**
|
||||
|
||||
Start with data types and the core loop, then add hooks, session, and harness layers incrementally.
|
||||
Reference in New Issue
Block a user