English | 简体ä¸ć–‡
A lightweight chain-based API for generating AG-UI protocol events with automatic state management and event subscription. Fully compliant with the AG-UI Protocol specification.
- 🚀 Simple API: Easy-to-use chain-based interface
- 🔄 Automatic State Management: Automatically handles event start/end states
- 📡 Event Subscription: Subscribe to events for real-time processing
- 🛠️ Tool Call Support: Full support for tool call workflows
- 🎯 TypeScript Support: Full TypeScript support with type safety
- 📦 Lightweight: Minimal dependencies and bundle size
- âś… AG-UI Compliant: Complete implementation of the AG-UI Protocol specification
- ⏰ Timestamp Support: Automatic timestamp generation for all events
- đź”— Raw Event Support: Integration with external systems via raw events
This library implements the complete AG-UI Protocol specification, including:
| Category | Events | Status |
|---|---|---|
| Lifecycle Events | RUN_STARTED, RUN_FINISHED, RUN_ERROR, STEP_STARTED, STEP_FINISHED |
âś… Complete |
| Text Message Events | TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END |
âś… Complete |
| Tool Call Events | TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, TOOL_CALL_RESULT |
âś… Complete |
| State Management Events | STATE_SNAPSHOT, STATE_DELTA, MESSAGES_SNAPSHOT |
âś… Complete |
| Special Events | RAW, CUSTOM |
âś… Complete |
All events automatically include:
type: Event type identifiertimestamp: Automatic timestamp generationrawEvent: Support for preserving original event data
Supports all AG-UI event flow patterns:
- Start-Content-End Pattern: For streaming content (text messages, tool calls)
- Snapshot-Delta Pattern: For state synchronization
- Lifecycle Pattern: For monitoring agent runs
npm install agui-chainimport { AguiChain } from 'agui-chain';
const chain = new AguiChain({ threadId: 'thread_123', runId: 'run_456' })
.subscribe(event => {
console.log('Event:', event.type, event);
});
chain
.text('Hello, World!')
.think('Processing...')
.text('Operation completed!')
.end();const chain = new AguiChain()
.subscribe(event => {
// Send event via SSE
sseClient.send(event);
});
// Handle external stream data
res.on('data', data => {
if (data.type === 'text') {
chain.text(data.content);
} else if (data.type === 'thinking') {
chain.think(data.content);
}
});
res.on('end', () => {
chain.end();
});new AguiChain(options?: RunOptions)Options:
threadId?: string- Thread identifierrunId?: string- Run identifier
// Subscribe to events
chain.subscribe(callback: (event: AguiEvent) => void)
// Unsubscribe from events
chain.unsubscribe(callback: (event: AguiEvent) => void)// Add text content with default role (assistant)
chain.text(content: string)
// Add text content with custom role
chain.text(content: string, role: string)Parameters:
content: string- The text content to addrole?: string- The role of the message (optional, defaults to 'assistant')
Supported Roles:
'assistant'- Assistant role (default)'user'- User role'system'- System role'tool'- Tool role- Any custom role string
Example:
chain
.text('User input message', 'user')
.text('System processing...', 'system')
.text('Assistant response', 'assistant')
.text('Tool execution result', 'tool');// Add thinking content (automatically handles start/content/end)
chain.think(content: string)// Start tool call
chain.tool_call_start(data: ToolCallData)
// Add tool call arguments
chain.tool_call_args(args: string)
// End tool call
chain.tool_call_end()
// Add tool call result
chain.tool_call_result(data: ToolCallResultData)// Add custom event
chain.custom(name: string, value: any, payload?: Record<string, unknown>)
// Add raw event object
chain.event(event: AguiEvent)// Add error event
chain.error(message: string, code?: number)// Start step
chain.stepStarted(stepName: string)
// Finish step
chain.stepFinished(stepName: string)// Add state snapshot
chain.stateSnapshot(snapshot: object)
// Add state delta
chain.stateDelta(delta: object[])
// Add messages snapshot
chain.messagesSnapshot(messages: object[])// Add raw event
chain.raw(event: object, source?: string)// End all current modes and finish chain
chain.end()
// Manually send RUN_STARTED event
chain.runStarted()
// Manually send RUN_FINISHED event
chain.runFinished()
// Set or update run options
chain.setRunOptions(options: RunOptions)const chain = new AguiChain()
.subscribe(event => console.log(event));
chain
.text('Hello')
.text(' ')
.text('World')
.think('Processing...')
.text('Done!')
.end();const chain = new AguiChain()
.subscribe(event => console.log(event));
chain
.text('User question: How do I implement authentication?', 'user')
.text('System: Processing authentication request...', 'system')
.think('Analyzing authentication requirements...')
.text('Here are the steps to implement authentication:', 'assistant')
.text('1. Set up JWT tokens', 'assistant')
.text('2. Implement middleware', 'assistant')
.text('3. Add route protection', 'assistant')
.end();const chain = new AguiChain()
.subscribe(event => console.log(event));
chain
.text('I need to fetch data')
.tool_call_start({
toolCallId: 'tool_1',
toolCallName: 'fetch_data'
})
.tool_call_args('{"url": "https://api.example.com"}')
.tool_call_end()
.tool_call_result({
messageId: 'msg_1',
toolCallId: 'tool_1',
content: 'Data fetched successfully'
})
.text('Data retrieved')
.end();const chain = new AguiChain({ threadId: 'thread_123', runId: 'run_456' })
.subscribe(event => {
console.log('Protocol Event:', {
type: event.type,
timestamp: event.timestamp,
...event
});
});
// Complete AG-UI protocol flow
chain
.runStarted()
.stepStarted('initialization')
.stateSnapshot({ user: { id: 'user_123' } })
.stepFinished('initialization')
.text('Hello, I am an AG-UI compliant agent')
.tool_call_start({
toolCallId: 'tool_1',
toolCallName: 'fetch_data'
})
.tool_call_args('{"param": "value"}')
.tool_call_end()
.tool_call_result({
messageId: 'msg_1',
toolCallId: 'tool_1',
content: 'Data retrieved'
})
.runFinished();const chain = new AguiChain()
.subscribe(event => console.log('Flow Pattern:', event.type));
// 1. Start-Content-End Pattern (Text Messages)
chain.text('Streaming text content');
// 2. Start-Content-End Pattern (Tool Calls)
chain.tool_call_start({ toolCallId: 'tool_1', toolCallName: 'example' });
chain.tool_call_args('{"param": "value"}');
chain.tool_call_end();
// 3. Snapshot-Delta Pattern (State Management)
chain.stateSnapshot({ counter: 0 });
chain.stateDelta([{ op: 'replace', path: '/counter', value: 1 }]);
// 4. Lifecycle Pattern
chain.stepStarted('processing');
chain.stepFinished('processing');const chain = new AguiChain()
.subscribe(event => {
if (event.type === 'RAW') {
console.log('External Event:', event.source, event.event);
}
});
// Integrate with external systems
chain.raw({ type: 'EXTERNAL_LOG', level: 'info' }, 'monitoring_system');
chain.raw({ type: 'EXTERNAL_METRIC', value: 75.5 }, 'metrics_system');const chain = new AguiChain();
// SSE subscriber
chain.subscribe(event => sseClient.send(event));
// Logger subscriber
chain.subscribe(event => console.log(JSON.stringify(event, null, 2)));
// UI updater subscriber
chain.subscribe(event => updateUI(event));
chain
.text('Hello from multiple subscribers')
.end();const chain = new AguiChain()
.subscribe(event => sseClient.send(event));
// Process external stream data
const processStreamData = (data: any) => {
switch (data.type) {
case 'text':
chain.text(data.content);
break;
case 'thinking':
chain.think(data.content);
break;
case 'tool_call_start':
chain.tool_call_start(data);
break;
case 'tool_call_args':
chain.tool_call_args(data.args);
break;
case 'tool_call_end':
chain.tool_call_end();
break;
case 'tool_call_result':
chain.tool_call_result(data);
break;
case 'error':
chain.error(data.message, data.code);
break;
default:
chain.custom(data.type, data.value, data.payload);
}
};
// Handle stream data
res.on('data', processStreamData);
res.on('end', () => chain.end());interface AguiEvent {
type: string;
timestamp?: number;
rawEvent?: any;
[key: string]: any;
}
interface RunOptions {
threadId?: string;
runId?: string;
}
interface EventCallback {
(event: AguiEvent): void;
}
interface ToolCallData {
toolCallId: string;
toolCallName: string;
parentMessageId?: string;
args?: string;
}
interface ToolCallResultData {
messageId: string;
toolCallId: string;
content: string;
role?: string;
}The library generates events according to the AG-UI Protocol specification:
RUN_STARTED- Run started eventRUN_FINISHED- Run finished eventRUN_ERROR- Run error eventSTEP_STARTED- Step startedSTEP_FINISHED- Step finished
TEXT_MESSAGE_START- Text message startedTEXT_MESSAGE_CONTENT- Text message contentTEXT_MESSAGE_END- Text message ended
TOOL_CALL_START- Tool call startedTOOL_CALL_ARGS- Tool call argumentsTOOL_CALL_END- Tool call endedTOOL_CALL_RESULT- Tool call result
STATE_SNAPSHOT- State snapshotSTATE_DELTA- State deltaMESSAGES_SNAPSHOT- Messages snapshot
RAW- Raw eventCUSTOM- Custom event
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.