@providerprotocol/agents
@providerprotocol/agents
@providerprotocol/agents
Section titled “@providerprotocol/agents”A powerful, flexible agent framework implementing the Unified Agent Protocol (UAP) 1.0. Built on top of @providerprotocol/ai for seamless multi-provider LLM support.
Features
Section titled “Features”- Functional State Management - Immutable state with explicit data flow
- Execution Strategies - Choose from
loop,react, orplanpatterns - Middleware Pipeline - Composable before/after hooks for logging, guardrails, etc.
- Multi-Provider Support - Works with Anthropic, OpenAI, Google, Ollama, and more
- Streaming - Full streaming support with UAP and UPP events
- Checkpointing - Built-in session persistence and recovery
- Thread Trees - Branching conversation support
- Sub-Agent Tools - Helper utilities for creating tools that spawn sub-agents with event propagation
- Tool Context Injection - Pass execution context (agentId, stateId, toolCallId) to tools
- Tool Ordering - Execute tool calls respecting dependencies and sequential barriers
- Type-Safe - 100% TypeScript with full type inference
Installation
Section titled “Installation”bun install @providerprotocol/agents @providerprotocol/aiQuick Start
Section titled “Quick Start”import { agent, AgentState } from '@providerprotocol/agents';import { anthropic } from '@providerprotocol/ai/anthropic';
// Create an agentconst assistant = agent({ model: anthropic('claude-sonnet-4-20250514'), params: { max_tokens: 4096 }, system: 'You are a helpful assistant.',});
// Single query (stateless)const turn = await assistant.query('What is the capital of France?');console.log(turn.response.text);
// Multi-turn conversation (stateful)let state = AgentState.initial();const r1 = await assistant.ask('My name is Alice.', state);state = r1.state;
const r2 = await assistant.ask('What is my name?', state);console.log(r2.turn.response.text); // "Alice"Adding Tools
Section titled “Adding Tools”import { agent, AgentState } from '@providerprotocol/agents';import { anthropic } from '@providerprotocol/ai/anthropic';
const calculator = { name: 'calculate', description: 'Evaluate a math expression', parameters: { type: 'object' as const, properties: { expression: { type: 'string' as const }, }, required: ['expression'], }, run: async (params: { expression: string }) => { // Use a proper math parser in production return String(eval(params.expression)); },};
const mathBot = agent({ model: anthropic('claude-sonnet-4-20250514'), params: { max_tokens: 1000 }, tools: [calculator],});
const turn = await mathBot.query('What is 42 * 17?');console.log(turn.response.text);console.log(turn.toolExecutions); // Shows calculator was usedExecution Strategies
Section titled “Execution Strategies”Choose how your agent thinks and acts:
Loop (Default)
Section titled “Loop (Default)”Simple tool loop - keeps executing until no more tool calls.
import { loop } from '@providerprotocol/agents/execution';
const myAgent = agent({ model: anthropic('claude-sonnet-4-20250514'), execution: loop({ maxIterations: 10 }),});Reason-Act-Observe pattern with explicit reasoning phase.
import { react } from '@providerprotocol/agents/execution';
const myAgent = agent({ model: anthropic('claude-sonnet-4-20250514'), execution: react({ maxSteps: 20 }),});Generate a structured plan, then execute steps with dependencies.
import { plan } from '@providerprotocol/agents/execution';
const myAgent = agent({ model: anthropic('claude-sonnet-4-20250514'), execution: plan({ maxPlanSteps: 10, allowReplan: true }),});Streaming
Section titled “Streaming”const stream = myAgent.stream('Explain quantum computing', state);
for await (const event of stream) { if (event.source === 'upp' && event.upp?.type === 'text_delta') { process.stdout.write(event.upp.delta.text ?? ''); }}
const { turn, state: newState } = await stream.result;Middleware
Section titled “Middleware”import { logging } from '@providerprotocol/agents/middleware';
const myAgent = agent({ model: anthropic('claude-sonnet-4-20250514'), middleware: [ logging({ level: 'info', includeTiming: true }), ],});Create custom middleware:
import type { Middleware } from '@providerprotocol/agents/middleware';
const rateLimiter: Middleware = { name: 'rate-limiter', async before(context) { await checkRateLimit(context.agent.id); return context; }, async after(context, result) { recordUsage(result.turn.usage); return result; },};Checkpointing
Section titled “Checkpointing”Persist agent sessions for recovery:
import { fileCheckpoints } from '@providerprotocol/agents/checkpoint';
const store = fileCheckpoints({ dir: '.checkpoints' });
const myAgent = agent({ model: anthropic('claude-sonnet-4-20250514'), checkpoints: store, sessionId: 'my-session',});
// Execute - state automatically saved after each stepawait myAgent.generate('Hello', AgentState.initial());
// Later: restore and continueconst saved = await store.load('my-session');if (saved) { const state = AgentState.fromJSON(saved); await myAgent.generate('Continue...', state);}Lifecycle Hooks
Section titled “Lifecycle Hooks”const myAgent = agent({ model: anthropic('claude-sonnet-4-20250514'), strategy: { stopCondition: (state) => state.step > 50, onStepStart: (step, state) => console.log(`Step ${step}`), onAct: (step, toolCalls) => console.log('Tools:', toolCalls), onComplete: (result) => console.log('Done!'), onError: (error, state) => console.error(error), },});Provider Support
Section titled “Provider Support”Works with all providers from @providerprotocol/ai:
import { anthropic } from '@providerprotocol/ai/anthropic';import { openai } from '@providerprotocol/ai/openai';import { google } from '@providerprotocol/ai/google';import { ollama } from '@providerprotocol/ai/ollama';
// Anthropicagent({ model: anthropic('claude-sonnet-4-20250514'), params: { max_tokens: 4096 } });
// OpenAIagent({ model: openai('gpt-4o'), params: { max_output_tokens: 4096 } });
// Googleagent({ model: google('gemini-2.0-flash'), params: { maxOutputTokens: 4096 } });
// Ollama (local)agent({ model: ollama('llama3:8b'), params: { num_predict: 4096 } });Environment Variables
Section titled “Environment Variables”Create a .env file with your API keys:
ANTHROPIC_API_KEY=sk-ant-...OPENAI_API_KEY=sk-...GOOGLE_API_KEY=AI...API Reference
Section titled “API Reference”agent(options)
Section titled “agent(options)”Creates an agent instance.
| Option | Type | Description |
|---|---|---|
model | ModelReference | Required. Model from UPP provider |
params | object | LLM parameters (provider-specific) |
system | string | System prompt |
tools | Tool[] | Available tools |
execution | ExecutionStrategy | Strategy: loop(), react(), plan() |
middleware | Middleware[] | Middleware pipeline |
strategy | AgentStrategy | Lifecycle hooks |
checkpoints | CheckpointStore | Session persistence |
sessionId | string | Session identifier |
Agent Methods
Section titled “Agent Methods”| Method | Returns | Description |
|---|---|---|
generate(input, state) | Promise<GenerateResult> | Execute with state |
stream(input, state) | AgentStreamResult | Stream execution |
ask(input, state) | Promise<GenerateResult> | Multi-turn convenience |
query(input) | Promise<Turn> | Stateless single-turn |
AgentState
Section titled “AgentState”Immutable state with chainable operations:
state.withMessage(msg) // Add messagestate.withMessages(msgs) // Add messagesstate.withContext(msgs) // Replace all messagesstate.withStep(n) // Set step numberstate.withMetadata(k, v) // Add metadatastate.withReasoning(text) // Add reasoning tracestate.withPlan(steps) // Set execution planstate.toJSON() // SerializeAgentState.fromJSON(json) // DeserializeExamples
Section titled “Examples”See the examples/ directory for complete examples:
- coding-agent - A Claude Code-style coding assistant with file operations, bash, search, and sub-agents
Run the coding agent example:
ANTHROPIC_API_KEY=sk-... bun examples/coding-agent/index.ts "List all TypeScript files"Interactive mode:
ANTHROPIC_API_KEY=sk-... bun examples/coding-agent/index.ts -iTUI mode:
ANTHROPIC_API_KEY=sk-... bun examples/coding-agent/index.ts --tuiTesting
Section titled “Testing”bun test # All testsbun test:unit # Unit testsbun test:live # Live API testsbun lint # Lintbun typecheck # Type checkPhilosophy
Section titled “Philosophy”“UAP is a pipe, not a nanny.”
This framework provides orchestration primitives with sensible defaults but no artificial limits. By default:
- Execution continues until naturally complete (no max iterations)
- State is explicit and immutable
- All UPP types flow through without abstraction
- You control safety, budgets, and constraints
Documentation
Section titled “Documentation”- llms.md - Comprehensive API documentation for LLMs and developers
- CLAUDE.md - Project coding guidelines and @providerprotocol/ai usage
License
Section titled “License”MIT
Related
Section titled “Related”- @providerprotocol/ai - Unified Provider Protocol for LLM inference