@olane/o-lane
v0.9.0
Published
oLane path tool to help capture agentic processes
Readme
@olane/o-lane
Agentic process management for Olane OS - transform intents into intelligent, self-organizing workflows
The execution layer that manages AI agent processes through capability-based loops, turning natural language intents into coordinated multi-step actions without explicit orchestration.
Features
- 🔄 Intent-Driven Execution - Transform natural language goals into agent workflows
- 🧠 Capability-Based Loop - Evaluate-plan-execute cycle for emergent behavior
- 📊 Execution Tracking - Complete sequence history with cycle-by-cycle audit trails
- 🌊 Streaming Support - Real-time progress updates to calling agents
- 💾 Persistent State - Content-addressed storage of lane execution history
- 🎯 Pre-built Capabilities - Evaluate and Execute included, with Search, Configure, and Multiple Step planned
Installation
pnpm install @olane/o-laneQuick Start
Creating a Lane-Enabled Tool
import { oLaneTool } from '@olane/o-lane';
import { oAddress } from '@olane/o-core';
class MyAgentTool extends oLaneTool {
constructor() {
super({
address: new oAddress('o://my-agent'),
description: 'My intelligent agent tool'
});
}
// Add custom tool methods
async _tool_analyze(request: oRequest): Promise<any> {
return { analysis: 'Data analyzed successfully' };
}
}
// Start your agent
const agent = new MyAgentTool();
await agent.start();Executing an Intent
// Agent receives an intent and autonomously determines how to execute it
const response = await agent.use(agent.address, {
method: 'intent',
params: {
intent: 'Analyze the sales data and create a summary report',
context: 'Previous conversation context here...',
streamTo: 'o://user/session'
}
});
console.log(response.result.data);
// {
// result: "Analysis complete. Created summary report with key insights...",
// cycles: 5,
// sequence: [
// { type: 'EVALUATE', reasoning: '...' },
// { type: 'EXECUTE', result: '...' },
// { type: 'EVALUATE', result: '...' },
// { type: 'EXECUTE', result: '...' },
// { type: 'STOP', result: '...' }
// ]
// }Response Structure
When calling use() on a lane-enabled tool, responses follow the standard O-Network wrapping structure:
// Response from use() follows this structure:
// {
// jsonrpc: "2.0",
// id: "request-id",
// result: {
// success: boolean, // Whether the operation succeeded
// data: any, // The returned data (on success)
// error?: string // Error details (on failure)
// }
// }
const response = await agent.use(agent.address, {
method: 'intent',
params: { intent: 'Analyze sales data' }
});
// Always check response.result.success before accessing data
if (response.result.success) {
const data = response.result.data;
console.log('Result:', data.result);
console.log('Cycles:', data.cycles);
} else {
console.error('Error:', response.result.error);
}Important: Access data via
response.result.data, notresponse.datadirectly. Theresultobject contains the wrapping fields (success,data,error).
Expected Output
After executing an intent, you'll receive:
- ✅ Final result - The outcome of the intent execution
- ✅ Cycle count - Number of capability cycles executed
- ✅ Execution sequence - Step-by-step breakdown of what the agent did
- ✅ Reasoning traces - Why the agent made each decision
Next Steps
What is o-lane?
The Agent Process Manager
Think of o-lane as the process manager for tool nodes (applications) in Olane OS. It enables your tool nodes to accept natural language intents from AI agents (LLMs) and autonomously resolve them through emergent workflows.
Key Concept:
- AI Agents (Users): GPT-4, Claude, etc. - the intelligent users who send intents
- Tool Nodes (Applications): What you build with o-lane - specialized capabilities that process intents
- o-lane: The runtime that enables tool nodes to execute intent-driven workflows
Key Innovation: Emergent vs Explicit Orchestration
| Traditional Frameworks (LangGraph, etc.) | o-lane | |----------------------------------------|--------| | Pre-define workflow graphs | Agents discover workflows | | Explicit state machines | Emergent behavior patterns | | Manual step orchestration | Capability-based autonomy | | Fixed execution paths | Dynamic path discovery |
How It Works
User Intent → Lane Creation → Capability Loop → Result Storage
↓
[Evaluate → Plan → Execute] × N cycles- User provides natural language intent - "Analyze sales data"
- Lane created - Agentic process begins
- Capability loop - Agent evaluates, plans, executes repeatedly
- Emergent workflow - Agent discovers optimal path through capabilities
- Result stored - Complete execution history saved with content addressing
This is NOT Orchestration
o-lane doesn't tell agents what to do. Instead:
- Agents evaluate their current state and intent
- Agents decide which capability to use next
- Agents learn from execution history
- Workflows emerge from agent intelligence
Core Concepts
Lanes as Agentic Processes
A lane is a self-contained execution context for resolving an intent. Like an OS process, it has:
- Unique ID - Content-addressable identifier (CID)
- Lifecycle states - PENDING → RUNNING → COMPLETED
- Execution history - Complete audit trail of decisions
- Resource isolation - Independent execution context
- Parent-child relationships - Lanes can spawn sub-lanes
Lane Lifecycle
// 1. Lane creation
const lane = await manager.createLane({
intent: new oIntent({ intent: 'Process customer order' }),
currentNode: agentTool,
caller: callerAddress,
context: contextData
});
// 2. Lane execution (automatic lifecycle)
const result = await lane.execute();
// → PREFLIGHT: Preparation and validation
// → RUNNING: Capability loop execution
// → POSTFLIGHT: Cleanup and storage
// → COMPLETED: Final state
// 3. Lane result
console.log(lane.status); // COMPLETED
console.log(lane.sequence); // Full execution historyLane States
| State | Description |
|-------|-------------|
| PENDING | Lane created, awaiting execution |
| PREFLIGHT | Pre-execution validation and setup |
| RUNNING | Active capability loop processing |
| POSTFLIGHT | Storing results and cleanup |
| COMPLETED | Successfully finished |
| FAILED | Encountered unrecoverable error |
| CANCELLED | Manually terminated |
Intents
Intents are natural language expressions of what the agent should accomplish.
import { oIntent } from '@olane/o-lane';
// Simple intent
const intent1 = new oIntent({
intent: 'Find relevant documentation for API authentication'
});
// Complex intent
const intent2 = new oIntent({
intent: 'Analyze Q4 sales trends, identify top performers, and generate executive summary'
});
console.log(intent1.value); // Access the intent stringBest Practice: Keep intents specific and outcome-focused rather than prescriptive:
- ✅ "Create a summary of customer feedback from the last month"
- ❌ "Query the database, filter by date, run sentiment analysis, format results"
Capabilities
Capabilities are atomic execution primitives that agents can use to accomplish tasks. Each capability:
- Performs one specific type of action
- Returns a
oCapabilityResultindicating next capability - Can succeed, fail, or trigger other capabilities
- Is discoverable and composable
import { oCapability, oCapabilityResult, oCapabilityType } from '@olane/o-lane';
// Capabilities are executed in sequence based on agent decisions
class CustomCapability extends oCapability {
get type() {
return oCapabilityType.CUSTOM;
}
async run(): Promise<oCapabilityResult> {
// Your capability logic here
const result = await this.doWork();
return new oCapabilityResult({
type: oCapabilityType.EVALUATE, // Tell agent what to do next
result: result,
config: { intent: this.intent }
});
}
}The Capability Loop
The heart of o-lane's emergent orchestration:
1. EVALUATE → Agent analyzes intent and current state
↓
2. DECIDE → Agent determines next capability to use
↓
3. EXECUTE → Capability performs its action
↓
4. RECORD → Result added to sequence
↓
5. CHECK → Complete? If yes, STOP. If no, return to EVALUATEKey Properties:
- Maximum Cycles: Configurable limit (default: 20) prevents infinite loops
- State Accumulation: Each cycle builds on previous results
- Emergent Patterns: Optimal workflows discovered through execution
- Fault Tolerance: Errors are handled within capability execution
// The loop runs automatically in lane.execute()
async loop(): Promise<oCapabilityResult> {
let iterations = 0;
let currentStep = /* Initial EVALUATE capability */;
while (iterations++ < this.MAX_CYCLES && this.status === RUNNING) {
const result = await this.doCapability(currentStep);
this.addSequence(result); // Track history
if (result.type === oCapabilityType.STOP) {
return result; // Intent resolved
}
currentStep = result; // Continue with next capability
}
}Execution Sequences
Every capability execution is recorded in the lane's sequence, creating a complete audit trail:
// Access execution history
console.log(lane.sequence);
// [
// {
// id: 'cap-1',
// type: 'EVALUATE',
// config: { intent: '...', context: '...' },
// result: { reasoning: 'Need to fetch customer data', next: 'EXECUTE' }
// },
// {
// id: 'cap-2',
// type: 'EXECUTE',
// config: { task: { address: 'o://data', method: 'get_customer' } },
// result: { data: [...], next: 'EVALUATE' }
// },
// // ... more cycles
// ]
// Formatted agent history
console.log(lane.agentHistory);
// [Cycle 1 Begin]
// Cycle Intent: Find customer data
// Cycle Result: { reasoning: "...", result: "..." }
// [Cycle 1 End]
// [Cycle 2 Begin]
// ...Built-in Capabilities
o-lane includes two active capabilities, with three additional ones planned:
Active Capabilities
1. Evaluate (EVALUATE)
Purpose: Analyze the intent and determine the next capability to use.
When Used:
- Start of every lane
- After completing any other capability
- When agent needs to reassess approach
import { oCapabilityEvaluate } from '@olane/o-lane';
// Automatically uses AI to evaluate intent and choose next step
// Returns: { type: 'EXECUTE' | 'STOP', reasoning: '...' }2. Execute (EXECUTE)
Purpose: Execute a specific tool method with parameters determined by the AI agent.
When Used: Agent needs to call a tool (API, database, computation, etc.)
Note:
oCapabilityExecuteis exported directly from@olane/o-laneand can be imported alongside other lane primitives.
import { oCapabilityExecute } from '@olane/o-lane';
// Agent decides to execute a tool call
// Result: { type: 'EXECUTE', config: { task: { address: 'o://tool', payload: {...} } } }
// Capability executes:
const response = await this.node.use(new oAddress('o://analytics'), {
method: 'analyze_sales',
params: { period: 'Q4' }
});Planned Capabilities (not yet active)
3. Search (SEARCH) (planned)
Purpose: Query vector stores, registries, or knowledge bases for information.
When Used: Agent needs to find relevant context, tools, or data
// Searches network for capabilities or information
// Can query vector stores, registries, or other search services4. Configure (CONFIGURE) (planned)
Purpose: Set up tool parameters, establish connections, or prepare environment.
When Used: Before executing complex operations requiring setup
// Configures tools or establishes required state
// Returns configuration result and proceeds to next capability5. Multiple Step (MULTIPLE_STEP) (planned)
Purpose: Coordinate complex multi-step operations.
When Used: Intent requires coordinating several dependent actions
// Manages sequences of related tasks
// Tracks progress across multiple steps
// Handles dependencies between stepsCapability Flow Example
Intent: "Analyze Q4 sales and create report"
↓
Cycle 1: EVALUATE → "Need to fetch sales data"
↓
Cycle 2: EXECUTE → Execute o://analytics/sales/fetch_q4_data
↓
Cycle 3: EVALUATE → "Have data, need to analyze"
↓
Cycle 4: EXECUTE → Execute o://analytics/analyze
↓
Cycle 5: EVALUATE → "Analysis complete, create report"
↓
Cycle 6: EXECUTE → Execute o://reports/create
↓
Cycle 7: EVALUATE → "Report created, done"
↓
Cycle 8: STOP → Return final resultAPI Reference
oLane Class
Core lane execution class that manages the capability loop.
Constructor
new oLane(config: oLaneConfig)Config Properties:
intent: oIntent- The intent to resolve (required)caller: oAddress- Address of the calling agent (required)currentNode: oToolBase- The tool executing the lane (required)promptLoader: PromptLoader- Prompt loader for capability prompts (required)context?: oLaneContext- Historical or domain contextchatHistory?: string- Chat history string for contextstreamTo?: oAddress- Address to stream progress updatescapabilities?: oCapability[]- Custom capability set (overridesenabledCapabilityTypes)enabledCapabilityTypes?: oCapabilityType[]- Filter which capability types to enable fromALL_CAPABILITIESextraInstructions?: string- Additional instructions for the AI agentmaxCycles?: number- Override default max cycles (20)parentLaneId?: string- Parent lane for sub-lanespersistToConfig?: boolean- Persist lane for replay on startupuseStream?: boolean- Enable streaming modeonChunk?: (chunk: any) => void- Callback for streaming chunksrequestId?: string | number- Request ID for request/response correlation
Properties
intent: oIntent- The intent being resolvedsequence: oCapabilityResult[]- Execution historystatus: oLaneStatus- Current lifecycle stateresult: oCapabilityResult- Final execution resultid: string- Unique lane identifier (UUID)cid?: CID- Content identifier for storageagentHistory: string- Formatted execution historyMAX_CYCLES: number- Maximum capability loop iterations (default: 20)onChunk?: (chunk: any) => void- Streaming chunk callback
Methods
async execute(): Promise<oCapabilityResult>
Execute the complete lane lifecycle.
const result = await lane.execute();
// Returns final capability result with outcomeasync loop(): Promise<oCapabilityResult>
Internal capability loop execution (called by execute).
addSequence(result: oCapabilityResult): void
Add a capability result to the execution sequence.
lane.addSequence(new oCapabilityResult({ type: oCapabilityType.EXECUTE, result: data }));async store(): Promise<void>
Store lane execution history to persistent storage.
await lane.store();
// Lane stored at o://lane/<cid>async toCID(): Promise<CID>
Generate content-addressed identifier for this lane.
const cid = await lane.toCID();
console.log(cid.toString()); // "bafyreib..."getExecutionTrace(): string
Get a formatted trace of the lane execution for debugging.
const trace = lane.getExecutionTrace();
console.log(trace);async replay(cid: string): Promise<oCapabilityResult | undefined>
Replay a previously stored lane execution from its CID.
const result = await lane.replay('bafyreib...');cancel(): void
Cancel lane execution.
lane.cancel();
console.log(lane.status); // CANCELLEDoLaneTool Class
Extends oNodeTool with lane execution capabilities via the withLane mixin pattern:
// oLaneTool is defined as:
export class oLaneTool extends withLane(oNodeTool) { }
// The withLane mixin can be applied to any tool base class:
// class MyCustomLaneTool extends withLane(MyBaseClass) { }Built-in Methods
async _tool_handshake(request: oRequest): Promise<oHandshakeResult>
Perform capability negotiation with other agents.
const result = await agent.use(agent.address, {
method: 'handshake',
params: { intent: 'Discover capabilities' }
});
// Returns: { tools: [...], methods: {...} }async _tool_intent(request: oRequest): Promise<any>
Main entry point for intent resolution.
const result = await agent.use(agent.address, {
method: 'intent',
params: {
intent: 'Your natural language goal here',
context: 'Optional conversation history',
streamTo: 'o://optional/stream/address'
}
});async _tool_replay(request: oRequest): Promise<any>
Replay a stored lane execution from its CID.
const result = await agent.use(agent.address, {
method: 'replay',
params: { cid: 'bafyreib...' }
});
// Returns: { result, error, cycles, cid }Customization
Override getPromptLoader() to provide a custom PromptLoader for controlling how prompts are loaded for each capability type.
Usage Example
class CustomAgent extends oLaneTool {
constructor() {
super({
address: new oAddress('o://custom-agent'),
description: 'My specialized agent'
});
}
// Add domain-specific tool methods
async _tool_domain_action(request: oRequest): Promise<any> {
// Your custom logic
return { result: 'done' };
}
}oIntent Class
Wrapper for natural language intents.
import { oIntent } from '@olane/o-lane';
const intent = new oIntent({ intent: 'Process customer order #12345' });
console.log(intent.value); // "Process customer order #12345"oCapability Abstract Class
Base class for creating custom capabilities.
import { oCapability, oCapabilityResult, oCapabilityType } from '@olane/o-lane';
class MyCapability extends oCapability {
// Define capability type
get type(): oCapabilityType {
return oCapabilityType.CUSTOM;
}
static get type() {
return oCapabilityType.CUSTOM;
}
// Implement execution logic
async run(): Promise<oCapabilityResult> {
// Access intent: this.intent
// Access node: this.node
// Access config: this.config
const result = await this.performWork();
return new oCapabilityResult({
type: oCapabilityType.EVALUATE, // Next capability
result: result,
config: { intent: this.intent }
});
}
}oLaneManager Class
Manages lane lifecycle and tracking.
import { oLaneManager } from '@olane/o-lane';
const manager = new oLaneManager();
// Create a new lane
const lane = await manager.createLane({
intent: new oIntent({ intent: 'Your goal' }),
currentNode: agentTool,
caller: callerAddress,
promptLoader: myPromptLoader
});
// Lane is automatically trackedProperties
lanes: oLane[]- All tracked lanesactiveLanes: oLane[]- Currently running lanesstaleLanes: oLane[]- Lanes that are no longer activemaxLanes: number- Maximum concurrent lanes (default: 100)
Methods
async createLane(config: oLaneConfig): Promise<oLane> - Create and track a new lane.
getLane(id: string): oLane | undefined - Retrieve a lane by its ID.
cancelLane(lane: oLane): void - Cancel a running lane.
cleanLanes(): void - Remove completed/stale lanes from tracking.
async teardown(): Promise<void> - Cancel all active lanes and clean up.
oCapabilityResult Class
Result object returned by capabilities.
import { oCapabilityResult, oCapabilityType } from '@olane/o-lane';
const result = new oCapabilityResult({
type: oCapabilityType.EXECUTE,
result: { data: 'success' },
config: { /* next capability config */ },
error: undefined
});Properties:
id: string- Unique result identifiertype: oCapabilityType- Next capability to executeresult?: any- Execution result dataconfig?: oCapabilityConfig- Configuration for next capabilityerror?: string- Error message if failedshouldPersist?: boolean- Whether this result should be persisted to storage
Enums
oLaneStatus
enum oLaneStatus {
PENDING = 'pending',
PREFLIGHT = 'preflight',
RUNNING = 'running',
POSTFLIGHT = 'postflight',
COMPLETED = 'completed',
FAILED = 'failed',
CANCELLED = 'cancelled'
}oCapabilityType
enum oCapabilityType {
TASK = 'task', // Legacy alias - prefer EXECUTE for new code
SEARCH = 'search',
MULTIPLE_STEP = 'multiple_step',
CONFIGURE = 'configure',
EXECUTE = 'execute', // Primary type for executing tool methods
HANDSHAKE = 'handshake',
EVALUATE = 'evaluate',
STOP = 'stop',
UNKNOWN = 'unknown'
}Note on TASK vs EXECUTE:
TASKis a legacy capability type that predatesEXECUTE. For new code, prefer usingoCapabilityType.EXECUTEwhich maps to theoCapabilityExecutecapability class. Both exist in the enum for backward compatibility.
Examples
Basic Intent Resolution
import { oLaneTool, oIntent } from '@olane/o-lane';
import { oAddress } from '@olane/o-core';
// Create agent
const agent = new oLaneTool({
address: new oAddress('o://assistant'),
description: 'General purpose assistant'
});
await agent.start();
// Resolve an intent
const response = await agent.use(agent.address, {
method: 'intent',
params: {
intent: 'Find the latest sales report and summarize key metrics'
}
});
console.log('Result:', response.result.data);
console.log('Cycles used:', response.result.data.cycles);
console.log('Execution path:', response.result.data.sequence.map(s => s.type));
// ['EVALUATE', 'EXECUTE', 'EVALUATE', 'EXECUTE', 'STOP']Custom Capability
import { oCapability, oCapabilityResult, oCapabilityType } from '@olane/o-lane';
// Create domain-specific capability
class EmailCapability extends oCapability {
get type() {
return oCapabilityType.CUSTOM;
}
async run(): Promise<oCapabilityResult> {
this.logger.info('Sending email...');
try {
// Send email using your email service
await this.sendEmail({
to: this.config.recipient,
subject: this.config.subject,
body: this.config.body
});
return new oCapabilityResult({
type: oCapabilityType.EVALUATE, // Back to evaluation
result: 'Email sent successfully',
config: { intent: this.intent }
});
} catch (error) {
return new oCapabilityResult({
type: oCapabilityType.EVALUATE,
error: error.message,
config: { intent: this.intent }
});
}
}
async sendEmail(params: any) {
// Your email sending logic
}
}
// Use custom capability
const lane = await manager.createLane({
intent: new oIntent({ intent: 'Send status update to team' }),
currentNode: agentTool,
caller: callerAddress,
promptLoader: myPromptLoader,
capabilities: [
new oCapabilityEvaluate(),
new oCapabilityExecute(),
new EmailCapability()
]
});
const result = await lane.execute();Streaming Results
// Create streaming endpoint
class StreamReceiver extends oLaneTool {
async _tool_receive_stream(request: oRequest): Promise<any> {
const { data } = request.params;
console.log('Stream update:', data);
// Send to UI, websocket, etc.
return { received: true };
}
}
const receiver = new StreamReceiver({
address: new oAddress('o://stream-receiver')
});
await receiver.start();
// Execute intent with streaming
const response = await agent.use(agent.address, {
method: 'intent',
params: {
intent: 'Process large dataset',
streamTo: 'o://stream-receiver' // Receive real-time updates
}
});
// Receiver gets updates as each capability completes:
// Stream update: { reasoning: "Starting data fetch..." }
// Stream update: { result: "Fetched 1000 records" }
// Stream update: { result: "Processing batch 1/10..." }
// ...Lane with Context
import { oLaneContext } from '@olane/o-lane';
// Create context and add entries
const context = new oLaneContext({});
context.addAll([
'[Previous Conversation]',
'User: What were our sales last quarter?',
'Agent: Q3 sales were $1.2M, up 15% from Q2.',
'User: Now show me Q4 projections.',
'[End Previous Conversation]'
]);
// Or add individual entries
context.add('Additional context here');
const response = await agent.use(agent.address, {
method: 'intent',
params: {
intent: 'Calculate Q4 projections',
context: context.toString()
}
});
// Agent uses context to understand the full conversationMulti-Cycle Execution with Analysis
// Complex intent requiring multiple capabilities
const response = await agent.use(agent.address, {
method: 'intent',
params: {
intent: 'Analyze customer feedback from last month, identify common themes, and create action items'
}
});
// Analyze the execution path
const data = response.result.data;
console.log('Execution Analysis:');
data.sequence.forEach((step, index) => {
console.log(`\nCycle ${index + 1}:`);
console.log(` Type: ${step.type}`);
console.log(` Reasoning: ${step.reasoning}`);
if (step.result) {
console.log(` Result: ${JSON.stringify(step.result).slice(0, 100)}...`);
}
});
// Output might show:
// Cycle 1: EVALUATE - "Need to fetch feedback data"
// Cycle 2: EXECUTE - Fetched 145 feedback items from o://feedback/collector
// Cycle 3: EVALUATE - "Have data, need sentiment analysis"
// Cycle 4: EXECUTE - Analyzed sentiment across feedback
// Cycle 5: EVALUATE - "Need to identify themes"
// Cycle 6: EXECUTE - Extracted 5 common themes
// Cycle 7: EVALUATE - "Ready to create action items"
// Cycle 8: EXECUTE - Generated 8 action items
// Cycle 9: EVALUATE - "All tasks complete"
// Cycle 10: STOP - Completed successfullyAdvanced Usage
Custom Capabilities
Create domain-specific capabilities for specialized workflows:
import { oCapability, oCapabilityResult, oCapabilityType } from '@olane/o-lane';
class DatabaseQueryCapability extends oCapability {
get type() {
return oCapabilityType.CUSTOM;
}
async run(): Promise<oCapabilityResult> {
const { query, params } = this.config;
try {
// Execute database query
const results = await this.executeQuery(query, params);
// Store results in lane storage for later use
await this.node.use(new oAddress('o://lane'), {
method: 'put',
params: {
key: `query-result-${Date.now()}`,
value: JSON.stringify(results)
}
});
return new oCapabilityResult({
type: oCapabilityType.EVALUATE,
result: {
rowCount: results.length,
data: results,
reasoning: `Query returned ${results.length} rows`
}
});
} catch (error) {
return new oCapabilityResult({
type: oCapabilityType.EVALUATE,
error: error.message
});
}
}
async executeQuery(query: string, params: any) {
// Your database logic
}
}When to Create Custom Capabilities:
- Domain-specific operations (database queries, API calls, etc.)
- Complex multi-step processes that should be atomic
- Integration with external systems
- Performance-critical operations requiring optimization
Prompt Loading
Lanes require a PromptLoader to load prompts for each capability type. The PromptLoader abstract class provides a loadPromptForType(type, params?, provider?) method. A PromptLoaderDefault implementation is included for standard use cases.
To customize prompt loading in your oLaneTool, override getPromptLoader():
class MyAgent extends oLaneTool {
getPromptLoader(): PromptLoader {
return new MyCustomPromptLoader();
}
}Lane Context
Provide rich context to help agents make better decisions:
import { oLaneContext } from '@olane/o-lane';
// Conversation context
const conversationContext = new oLaneContext({});
conversationContext.addAll([
'[Chat History]',
'User: Show me last quarter sales',
'Agent: Q3 sales: $1.2M (↑15%)',
'[End History]'
]);
// Domain knowledge context
const domainContext = new oLaneContext({});
domainContext.addAll([
'[Business Rules]',
'- Sales reports require manager approval',
'- Sensitive data must be redacted',
'- All currency in USD',
'[End Rules]'
]);
// Combine contexts
const combinedContext = new oLaneContext({});
combinedContext.addAll([
conversationContext.toString(),
domainContext.toString()
]);
const response = await agent.use(agent.address, {
method: 'intent',
params: {
intent: 'Generate Q4 sales report',
context: combinedContext.toString()
}
});Controlling Max Cycles
Adjust maximum cycles based on task complexity:
// Environment variable (applies to all lanes)
process.env.MAX_CYCLES = '30';
// Per-lane configuration
const lane = await manager.createLane({
intent: new oIntent({ intent: 'Complex multi-step analysis' }),
currentNode: agent,
caller: callerAddress,
maxCycles: 50 // Override default
});
// Quick tasks
const quickLane = await manager.createLane({
intent: new oIntent({ intent: 'Simple lookup' }),
currentNode: agent,
caller: callerAddress,
maxCycles: 5 // Fail fast if not simple
});Guidelines:
- Simple lookups/queries: 5-10 cycles
- Standard tasks: 15-20 cycles (default)
- Complex analysis: 30-50 cycles
- Long-running workflows: 50-100 cycles
Streaming Integration
Implement real-time progress reporting:
class ProgressTracker extends oLaneTool {
private updates: any[] = [];
async _tool_receive_stream(request: oRequest): Promise<any> {
const { data } = request.params;
this.updates.push({
timestamp: Date.now(),
data: data
});
// Send to UI via WebSocket, SSE, etc.
await this.broadcastToUI(data);
return { received: true, totalUpdates: this.updates.length };
}
async broadcastToUI(data: any) {
// Your UI streaming logic (WebSocket, Server-Sent Events, etc.)
this.websocket?.send(JSON.stringify({
type: 'lane_update',
data: data
}));
}
}
// Use with streaming
const tracker = new ProgressTracker({
address: new oAddress('o://progress-tracker')
});
await tracker.start();
// Long-running task with progress updates
const response = await agent.use(agent.address, {
method: 'intent',
params: {
intent: 'Process 10,000 customer records',
streamTo: 'o://progress-tracker'
}
});Lane Storage & Retrieval
Access historical lane executions:
import { oAddress } from '@olane/o-core';
// Execute and store lane
const response = await agent.use(agent.address, {
method: 'intent',
params: { intent: 'Analyze sales data' }
});
// Get the lane's CID from execution
const lane = await manager.createLane({...});
const cid = await lane.toCID();
// Later: retrieve lane history
const storedLane = await agent.use(new oAddress('o://lane'), {
method: 'get',
params: { key: cid.toString() }
});
console.log('Historical execution:', storedLane.result.data);
// {
// config: { intent: '...', caller: '...' },
// sequence: [...],
// result: {...}
// }
// Analyze patterns across multiple lanes
const allLanes = await agent.use(new oAddress('o://lane'), {
method: 'list',
params: { prefix: 'bafy' } // All CIDs
});
// Find common execution patterns
const patterns = analyzeLanePatterns(allLanes);
console.log('Most common capability sequences:', patterns);Testing
Testing Lane Execution
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
import { oLaneTool, oIntent, oLaneManager } from '@olane/o-lane';
import { oAddress } from '@olane/o-core';
describe('Lane Execution', () => {
let agent: oLaneTool;
let manager: oLaneManager;
beforeEach(async () => {
agent = new oLaneTool({
address: new oAddress('o://test-agent'),
description: 'Test agent'
});
await agent.start();
manager = new oLaneManager();
});
afterEach(async () => {
await agent.stop();
});
it('should execute simple intent', async () => {
const lane = await manager.createLane({
intent: new oIntent({ intent: 'Test task' }),
currentNode: agent,
caller: new oAddress('o://tester')
});
const result = await lane.execute();
expect(result).toBeDefined();
expect(lane.status).toBe('completed');
expect(lane.sequence.length).toBeGreaterThan(0);
});
it('should respect max cycles', async () => {
const lane = await manager.createLane({
intent: new oIntent({ intent: 'Complex task' }),
currentNode: agent,
caller: new oAddress('o://tester'),
maxCycles: 3
});
await expect(lane.execute()).rejects.toThrow('reached max iterations');
});
it('should stream updates', async () => {
const updates: any[] = [];
// Mock stream receiver
class MockReceiver extends oLaneTool {
async _tool_receive_stream(request: any) {
updates.push(request.params.data);
return { received: true };
}
}
const receiver = new MockReceiver({
address: new oAddress('o://mock-receiver')
});
await receiver.start();
const lane = await manager.createLane({
intent: new oIntent({ intent: 'Streaming task' }),
currentNode: agent,
caller: new oAddress('o://tester'),
streamTo: new oAddress('o://mock-receiver')
});
await lane.execute();
expect(updates.length).toBeGreaterThan(0);
await receiver.stop();
});
});Mocking Capabilities
import { oCapability, oCapabilityResult, oCapabilityType } from '@olane/o-lane';
// Create mock capability for testing
class MockExecuteCapability extends oCapability {
get type() {
return oCapabilityType.EXECUTE;
}
async run(): Promise<oCapabilityResult> {
// Return predetermined result for testing
return new oCapabilityResult({
type: oCapabilityType.STOP,
result: { mocked: true, data: 'test data' }
});
}
}
// Test with mock capabilities
it('should use mock capabilities', async () => {
const mockCapabilities = [
new oCapabilityEvaluate(),
new MockExecuteCapability()
];
const lane = await manager.createLane({
intent: new oIntent({ intent: 'Test with mocks' }),
currentNode: agent,
caller: new oAddress('o://tester'),
capabilities: mockCapabilities
});
const result = await lane.execute();
expect(result.result.mocked).toBe(true);
});Best Practices
Intent Design
✅ DO:
- Use clear, outcome-focused language
- Specify concrete goals rather than steps
- Provide sufficient context in the intent
- Keep intents scoped to achievable tasks
// Good intents
"Analyze customer satisfaction scores from Q4 and identify improvement areas"
"Find all pending orders and send reminder emails to customers"
"Generate a summary report of this week's support tickets"❌ DON'T:
- Use vague or ambiguous language
- Prescribe specific implementation steps
- Combine unrelated tasks
- Assume agent has unstated context
// Poor intents
"Do some analysis" // Too vague
"Query database, filter results, format as JSON, send to API" // Too prescriptive
"Analyze sales and fix the server bug and update documentation" // Unrelated tasksCapability Design
✅ DO:
- Keep capabilities atomic and focused
- Return clear next-capability signals
- Handle errors gracefully
- Log reasoning and decisions
❌ DON'T:
- Create monolithic capabilities
- Assume state from previous cycles
- Silently fail
- Lose execution context
Context Management
✅ DO:
- Provide relevant conversation history
- Include domain-specific rules and constraints
- Keep context concise but complete
- Update context as conversations evolve
❌ DON'T:
- Dump entire chat history
- Include irrelevant information
- Assume context is remembered between lanes
- Mix different types of context
Cycle Management
✅ DO:
- Set appropriate max cycles for task complexity
- Monitor cycle usage patterns
- Optimize frequently-used capability paths
- Use streaming for long-running tasks
❌ DON'T:
- Use same max cycles for all tasks
- Ignore high cycle counts
- Let lanes run indefinitely
- Block waiting for lane completion
Monitoring & Debugging
✅ DO:
- Store and analyze lane execution histories
- Track capability success/failure rates
- Monitor average cycles per intent type
- Log reasoning at each capability
❌ DON'T:
- Ignore lane storage
- Treat all failures the same
- Skip execution analysis
- Remove debugging information too early
Use Cases
Complex Multi-Step Workflows
// Intent: "Onboard new customer: create account, send welcome email, assign CSM"
// Lane automatically:
// 1. Evaluates steps needed
// 2. Searches for account creation tool
// 3. Creates account
// 4. Searches for email service
// 5. Sends welcome email
// 6. Searches for CSM assignment tool
// 7. Assigns customer success manager
// 8. Returns confirmationLong-Running Agent Tasks
// Intent: "Monitor API health every 5 minutes and alert on failures"
// Lane manages:
// - Periodic execution via scheduling capability
// - State persistence across executions
// - Error detection and alerting
// - Automatic recovery attemptsIntent-Based Automation
// Intent: "When new sales lead arrives, score it and route to appropriate team"
// Lane orchestrates:
// - Lead data extraction
// - Scoring algorithm execution
// - Team assignment logic
// - Notification delivery
// - CRM updatesAgent Coordination Patterns
// Intent: "Coordinate 3 specialist agents to analyze customer data"
// Lane enables:
// - Discovery of specialist agents
// - Parallel task distribution
// - Result aggregation
// - Consensus building
// - Final report generationEmergent Workflow Discovery
// Multiple users with similar intents
// Lane learns optimal paths:
// "Generate sales report" -> most efficient capability sequence emerges
// Future executions follow discovered optimal path
// Workflow improves over time through accumulated learningTroubleshooting
Lane Reaches Max Cycles
Symptom: Lane throws "reached max iterations" error
Causes:
- Intent too complex for cycle limit
- Agent stuck in evaluation loop
- Missing required capabilities
- Poor capability return signals
Solutions:
// 1. Increase max cycles for complex tasks
maxCycles: 50
// 2. Break intent into smaller sub-intents
"Analyze all customer data" → "Analyze customer data for Q4"
// 3. Add missing capabilities
capabilities: [...ALL_CAPABILITIES, new CustomCapability()]
// 4. Review agent history to find loops
console.log(lane.agentHistory);
// Look for repeated capability patternsCapability Not Found Errors
Symptom: "Unknown capability" error during execution
Causes:
- Custom capability not registered
- Agent choosing unavailable capability type
- Capability type mismatch
Solutions:
// 1. Register custom capabilities
const lane = await manager.createLane({
capabilities: [
...ALL_CAPABILITIES,
new MyCustomCapability()
]
});
// 2. Check capability type enum values match
get type() {
return oCapabilityType.CUSTOM; // Must match exactly
}
// 3. Provide all standard capabilities
import { ALL_CAPABILITIES } from '@olane/o-lane';Intent Not Resolving
Symptom: Lane completes but doesn't achieve desired outcome
Causes:
- Intent too vague
- Missing context
- Insufficient capabilities available
- Poor tool descriptions
Solutions:
// 1. Make intent more specific
"Do analysis" → "Calculate average sales per region for Q4 2024"
// 2. Provide context
const ctx = new oLaneContext({});
ctx.addAll(['Available data: sales_q4.csv', 'Required format: JSON with region, avg_sales fields']);
// then pass: context: ctx
// 3. Add specialized capabilities
capabilities: [...ALL_CAPABILITIES, new DataAnalysisCapability()]
// 4. Improve tool descriptions in agent config
description: 'Calculates regional sales averages from CSV data'Storage Failures
Symptom: Lane executes but fails to store results
Causes:
- Storage service unavailable
- Invalid CID generation
- Permission issues
- Storage quota exceeded
Solutions:
// 1. Verify storage service is running
await agent.use(new oAddress('o://lane'), { method: 'ping' });
// 2. Check CID generation
const cid = await lane.toCID();
console.log('CID:', cid.toString());
// 3. Add error handling
try {
await lane.store();
} catch (error) {
console.error('Storage failed:', error);
// Implement fallback storage
}
// 4. Monitor storage usage
const usage = await agent.use(new oAddress('o://lane'), {
method: 'usage'
});Related Packages
- @olane/o-core - Core OS functionality and base classes
- @olane/o-node - Network-connected tools with P2P capabilities
- @olane/o-tool - Tool augmentation system for agent specialization
- @olane/o-leader - Network coordination and agent discovery
- @olane/o-protocol - Protocol definitions and types
- @olane/o-config - Configuration management utilities
Contributing
We welcome contributions! Please see our Contributing Guide for details on our code of conduct and development process.
License
ISC © oLane Inc.
Resources
Part of the Olane OS ecosystem - An agentic operating system for building intelligent, collaborative AI agent networks.
