wheelloop
v0.1.23
Published
Production-ready Node.js framework for building conversational AI agents with tools and MCP integration.
Readme
WheelLoop
Production-ready Node.js framework for building conversational AI agents with tools, middleware, and MCP (Model Context Protocol) integration.
Features
- 🔧 Tool System - Unified registry supporting local tools, HTTP MCP, and stdio MCP providers
- 🔗 Middleware Pipeline - Extensible lifecycle hooks for request/response processing
- 🤖 SubAgent Architecture - Built-in task delegation with specialized agents (research, writing, code review)
- 📡 Event Streaming - Real-time execution feedback with streaming support
- 🛡️ Fine-grained Control - Whitelist filtering for tools and providers
- 🗄️ Filesystem Integration - Read/write file operations via middleware with virtual mode support
Quick Start
Installation
pnpm add wheelloop
# or
npm install wheelloopBasic Usage
import { createWheelAgent, createLocalToolRegistry } from 'wheelloop';
// Create agent with default tools
const toolRegistry = await createLocalToolRegistry();
const agent = createWheelAgent({ toolRegistry });
// Simple chat
const result = await agent.chatStreamWithEvents({
model: 'gpt-4o-mini',
api_key: process.env.OPENAI_API_KEY,
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'Create a todo list for today.' }
]
});
console.log(result.content);With Filesystem Access
import {
createWheelAgent,
createLocalToolRegistry,
createFilesystemMiddleware
} from 'wheelloop';
const toolRegistry = await createLocalToolRegistry();
// Add filesystem capabilities via middleware
const fsMiddleware = createFilesystemMiddleware({
backend: { virtualMode: true }, // Safe virtual filesystem
systemPrompt: 'You can read and modify files to help users.'
});
const agent = createWheelAgent({
toolRegistry,
middlewares: [fsMiddleware]
});
const result = await agent.chatStreamWithEvents({
model: 'gpt-4o-mini',
api_key: process.env.OPENAI_API_KEY,
messages: [
{ role: 'user', content: 'Analyze the package.json file and summarize dependencies.' }
]
});Architecture
Core Flow
flowchart LR
A[User Request] --> B[Middleware Chain]
B --> C{Agent Loop}
C --> D[LLM Call]
D --> E{Tool Call?}
E -->|Yes| F[Execute Tools]
E -->|No| G[Final Response]
F --> C
style B fill:#e1f5ff
style F fill:#ffe1e1
style G fill:#e1ffe1Component Overview
- WheelAgent - Main orchestrator for chat, tools, and events
- ToolRegistry - Manages local tools + MCP providers
- Middleware System - Lifecycle hooks:
beforeAgent→beforeModel→wrapModelCall→afterModel→afterAgent - SubAgent System - Task delegation with depth control and isolated contexts
- Event Handlers - Callbacks for
llm_start,tool_start,agent_end, etc.
Advanced Usage
SubAgent Delegation
Enable task decomposition with specialized agents:
const agent = createWheelAgent({
toolRegistry,
enableSubAgents: true,
maxSubAgentDepth: 3,
subAgentConfigs: [
{
name: 'code-reviewer',
description: 'Reviews code quality and suggests improvements',
systemPrompt: 'You are an expert code reviewer...',
model: 'gpt-4'
}
]
});Built-in SubAgents: research, writing, code-review, general-purpose
Tool Whitelisting
Control which tools are available:
const agent = createWheelAgent({
toolRegistry,
allowedLocalTools: ['search', 'filesystem'],
allowedMcpProviders: ['github'], // HTTP MCP
allowedStdioProviders: ['gitlab'] // Stdio MCP
});Custom Middleware
import type { AgentMiddleware } from 'wheelloop';
const loggingMiddleware: AgentMiddleware = {
beforeModel: async (state, messages, tools, params) => {
console.log(`Calling LLM with ${tools.length} tools`);
return { messages, tools, params };
},
afterModel: async (state, response, params) => {
console.log('LLM response received:', response.content);
return { state, response };
}
};
const agent = createWheelAgent({
toolRegistry,
middlewares: [loggingMiddleware]
});Event Streaming
const result = await agent.chatStreamWithEvents({
model: 'gpt-4o-mini',
api_key: process.env.OPENAI_API_KEY,
messages: [...],
events: {
on_llm_stream: (chunk) => {
process.stdout.write(chunk.content || '');
},
on_tool_start: (tool) => {
console.log(`\n[Tool] ${tool.name}`);
},
on_tool_end: (result) => {
console.log(`[Result] ${result.output}`);
}
}
});Middleware System
Lifecycle Hooks
sequenceDiagram
participant User
participant Middleware
participant LLM
participant Tools
User->>Middleware: Request
Middleware->>Middleware: beforeAgent
Middleware->>Middleware: beforeModel
Middleware->>LLM: wrapModelCall
LLM-->>Middleware: Response
Middleware->>Middleware: afterModel
alt Tool Call Required
Middleware->>Tools: Execute
Tools-->>Middleware: Result
end
Middleware->>Middleware: afterAgent
Middleware-->>User: Final ResponseBuilt-in Middlewares
Filesystem Middleware
import {
createFilesystemMiddleware,
createFilesystemReadOnlyMiddleware
} from 'wheelloop';
// Full access (read + write)
const fsMiddleware = createFilesystemMiddleware({
backend: { virtualMode: true },
systemPrompt: 'You can access and modify files.',
customToolDescriptions: {
ls: 'List directory contents',
read_file: 'Read file contents',
write_file: 'Write to file',
edit_file: 'Edit existing file',
glob: 'Search files by pattern',
grep: 'Search file contents'
}
});
// Read-only access
const readOnlyFs = createFilesystemReadOnlyMiddleware({
backend: { virtualMode: true },
systemPrompt: 'You can read files (read-only access).'
});Other Middlewares
- SummarizationMiddleware - Automatic content summarization
- ContextCompactionMiddleware - Context window management
API Reference
createWheelAgent(options)
interface WheelAgentOptions {
// Tool management
toolRegistry?: ToolRegistry;
// Middleware pipeline
middlewares?: AgentMiddleware[];
// Abort control
abortController?: AbortController;
// SubAgent configuration
enableSubAgents?: boolean;
subAgentConfigs?: SubAgentConfig[];
maxSubAgentDepth?: number; // Default: 3
// Tool filtering
allowedLocalTools?: string[];
allowedMcpProviders?: string[];
allowedStdioProviders?: string[];
}chatStreamWithEvents(params)
interface ChatParams {
// LLM configuration
model: string;
api_key: string;
base_url?: string;
// Messages
messages: Message[];
// Optional parameters
temperature?: number;
max_tokens?: number;
// Event handlers
events?: {
on_llm_start?: (data) => void;
on_llm_stream?: (chunk) => void;
on_llm_end?: (response) => void;
on_tool_start?: (tool) => void;
on_tool_end?: (result) => void;
on_agent_start?: () => void;
on_agent_end?: (result) => void;
};
}Examples
The examples/ directory contains complete working examples:
# Clone and setup
git clone <repo-url>
cd WheelLoop
pnpm install
# Create .env file
cat > .env << EOF
OPENAI_API_KEY=your_key_here
ONE_API_KEY=your_one_api_key
ONE_API_MODEL=deepseek-chat
ONE_API_REMOTE=https://oneapi.example.com
BOCHA_API_KEY=your_bocha_key
SERPER_KEY=your_serper_key
EOF
# Run examples
pnpm tsx examples/test_simple.ts # Basic chat
pnpm tsx examples/test_agent.ts # With tools
pnpm tsx examples/test_middleware.ts # Middleware demo
pnpm tsx examples/test_subagent.ts # SubAgent delegation
pnpm tsx examples/test_stdio_mcp.ts # MCP integrationDevelopment
# Setup
pnpm install
# Development
pnpm dev # Watch mode
pnpm typecheck # Type checking
pnpm build # Build to dist/
# Code Quality
pnpm lint # ESLint
pnpm lint:fix # Auto-fix
pnpm format # Prettier
pnpm format:check # Check formatting
# Testing
pnpm test # Run tests
pnpm test:watch # Watch mode
pnpm test:coverage # Coverage report
pnpm test:ui # UI test runnerUse Cases
- Code Assistants - Build AI coding tools with filesystem access
- Research Agents - Delegate web search and content analysis
- Task Automation - Orchestrate complex workflows with SubAgents
- Document Processing - Read, analyze, and generate documentation
- MCP Integration - Connect to external tools via Model Context Protocol
License
MIT
Documentation: See /CLAUDE.md for architecture details
Issues: GitHub Issues
npm: wheelloop
