@10xscale/agentflow-client
v0.4.0
Published
TypeScript client library for AgentFlow API - build intelligent agents with thread management, streaming, memory, and tool execution
Maintainers
Readme
AgentFlow Client
A TypeScript client library for the AgentFlow multi-agent system API. Build conversational AI applications with streaming responses, realtime audio, tool execution, and dynamic state management.
✨ Features
- 🚀 Simple API - Clean, intuitive client for AgentFlow
- 💬 Streaming Support - Real-time streaming responses for chat UIs
- 🔧 Tool Execution - Automatic local tool execution with recursion handling
- 📊 State Management - Dynamic state schema with validation
- 🎙️ Realtime Audio - WebSocket audio-to-audio via
/v1/graph/live - 📘 TypeScript First - Full TypeScript support with comprehensive types
- 🎯 Zero Config - Works out of the box with sensible defaults
📦 Installation
npm install @10xscale/agentflow-client
# or
yarn add @10xscale/agentflow-client
# or
pnpm add @10xscale/agentflow-clientVersion compatibility
This package versions independently of the Python packages, so the numbers do not line up. Pick versions by the table below rather than by matching version numbers:
| @10xscale/agentflow-client (npm) | 10xscale-agentflow-cli (API server) | 10xscale-agentflow (core) |
| ---------------------------------- | ------------------------------------- | --------------------------- |
| 0.4.x | >= 0.5.0 | >= 0.9.0 |
| 0.3.x | >= 0.5.0 | >= 0.9.0 |
The client version tracks the API server (10xscale-agentflow-cli), which is what it talks to;
the core version follows from whatever the server requires (the CLI pins
10xscale-agentflow>=0.9.0). Client 0.3.x and later need server >= 0.5.0 specifically for
graphTools() and observability(); the invoke, stream, thread, memory, and file endpoints work
against older servers too. Client releases before 0.3.0 are not supported - upgrade rather than
pinning them.
🚀 Quick Start
Basic Usage
import { AgentFlowClient, Message } from '@10xscale/agentflow-client';
// Initialize client
const client = new AgentFlowClient({
baseUrl: 'http://localhost:8000',
authToken: 'your-token', // optional legacy Bearer auth
debug: true, // optional
});
// Send a message and get response
const result = await client.invoke([Message.text_message('Hello, how can you help me?', 'user')]);
console.log(result.messages); // Array of response messagesAuthentication Options
import { AgentFlowClient, basicAuth, headerAuth } from '@10xscale/agentflow-client';
const bearerClient = new AgentFlowClient({
baseUrl: 'https://api.example.com',
authToken: process.env.AGENTFLOW_TOKEN,
});
const basicClient = new AgentFlowClient({
baseUrl: 'https://api.example.com',
auth: basicAuth('service-user', 'service-password'),
});
const apiKeyClient = new AgentFlowClient({
baseUrl: 'https://api.example.com',
auth: headerAuth('X-API-Key', process.env.AGENTFLOW_API_KEY!),
});
const sessionClient = new AgentFlowClient({
baseUrl: 'https://api.example.com',
credentials: 'include',
});Streaming Chat
// Stream responses in real-time
const stream = client.stream([Message.text_message('Tell me a story', 'user')]);
for await (const chunk of stream) {
if (chunk.event === 'message') {
console.log(chunk.message?.content);
}
}Realtime audio (/v1/graph/live)
Transport-only: you stream PCM16 in and get PCM16 out. Mic capture and playback are yours to wire.
import { AgentFlowClient } from '@10xscale/agentflow-client';
const client = new AgentFlowClient({ baseUrl: 'http://localhost:8000', authToken });
const session = client.realtime(
{ model: 'gemini-2.5-flash-live', modalities: 'AUDIO' },
{ reconnect: { maxAttempts: 5 } }
);
session.on('audio', (pcm16, sampleRate) => playback(pcm16, sampleRate)); // PCM16 @ 24 kHz
session.on('output_transcript', (e) => console.log(e.text));
session.on('tool_call', (e) => console.log('tool', e.name, e.args));
session.on('error', (e) => console.error(e.message));
await session.ready; // socket open + init sent
session.sendAudio(micChunk); // PCM16 @ 16 kHz (Uint8Array | ArrayBuffer)
// push-to-talk: session.activityStart() / session.activityEnd()
session.close(); // graceful end; disables reconnectAuth uses the browser-safe agentflow-bearer subprotocol automatically. In Node < 21 (no global
WebSocket), pass an implementation:
import WebSocket from 'ws';
const client = new AgentFlowClient({ baseUrl, authToken, webSocketImpl: WebSocket });File Uploads And Access URLs
const upload = await client.uploadFile(file);
// Best URL for rendering/downloading in the UI.
// Cloud-backed deployments typically return a signed URL here.
const accessUrl = upload.data.direct_url ?? upload.data.url;
const fileInfo = await client.getFileInfo(upload.data.file_id);
const fileUrl = await client.getFileAccessUrl(upload.data.file_id);
const msg = Message.withFile('Summarize this document', upload.data.file_id, upload.data.mime_type);Tool Registration
⚠️ Important: Remote tools (registered client-side) should only be used for browser-level APIs like localStorage, navigator.geolocation, etc. For most operations (database queries, external API calls, calculations), define your tools in the Python backend instead. See How to register remote tools for details.
// Register custom tools for agent execution (ONLY for browser APIs)
client.registerTool({
node: 'assistant',
name: 'get_weather',
description: 'Get current weather for a location',
parameters: {
type: 'object',
properties: {
location: { type: 'string' },
},
required: ['location'],
},
handler: async ({ location }) => {
// Your tool logic here
return { temperature: 72, conditions: 'sunny' };
},
});
// Tools execute automatically during invoke
const result = await client.invoke([Message.text_message('What is the weather in NYC?', 'user')]);parameters is a plain JSON Schema, and properties / required are both optional. A tool whose
arguments are all optional needs no required, and a tool that takes no arguments needs neither:
client.registerTool({
node: 'assistant',
name: 'read_terminal',
description: 'Read recent terminal output',
parameters: {
type: 'object',
properties: {
last_chars: { type: 'integer', description: 'Defaults to 2000' },
},
},
handler: async ({ last_chars = 2000 }) => readTerminal(last_chars),
});
client.registerTool({
node: 'assistant',
name: 'read_diff',
description: 'Read the current diff',
parameters: { type: 'object' }, // or omit `parameters` entirely
handler: async () => getDiff(),
});The missing keywords are filled in (properties: {}, required: []) when the tool definition is
sent to the server, so the schema the model sees is always complete.
📚 Documentation
Full documentation lives at agentflow.10xscale.ai.
Getting Started
- Connect a client - Setup and first request
AgentFlowClientreference - Constructor config and every methodMessageand content blocks - The message and content-block types
Core Concepts
- Invoke API - Request/response pattern with tool execution
- Stream API - Real-time streaming responses
- Graph and state schema -
graphStateSchema()and graph lifecycle - Tools reference - Tool registration and execution ⚠️ Important: Remote vs Backend tools
Reference
- Reference overview - Python library, REST/WebSocket API, CLI, and TypeScript client
- Troubleshooting - Common issues and solutions
🎯 Key APIs
invoke() - Batch Processing
Execute agent with automatic tool execution loop:
const result = await client.invoke(messages, {
recursion_limit: 25,
response_granularity: 'full',
});stream() - Real-time Streaming
Stream responses as they're generated:
const stream = client.stream(messages);
for await (const chunk of stream) {
// Process chunks in real-time
}graphStateSchema() - Dynamic Schema
Get agent state schema for form generation and validation:
const schema = await client.graphStateSchema();
// Build forms, validate data, generate typesgraphTools() - Tool Inventory
List the tools the graph's tool nodes expose, grouped by node. Each tool is tagged with its
source (local, mcp, or remote):
const { data } = await client.graphTools();
// data.nodes[].tools[] -> { name, description, source, parameters }observability(threadId, runId?) - Run Traces
Fetch the reconstructed trace for a run - spans, events, and cost. Defaults to the thread's latest run:
const trace = await client.observability(threadId);
const specific = await client.observability(threadId, runId);Tool Registration
Register local tools that agents can execute:
client.registerTool({
node: 'node_name',
name: 'tool_name',
handler: async (args) => {
/* ... */
},
});💡 Examples
Check out the examples/ directory for complete working examples:
- invoke-example.ts - Basic invoke with tool execution
- stream-example.ts - Streaming responses
- state-schema-examples.ts - Form generation and validation
🏗️ Architecture
┌─────────────────────┐
│ Your Application │
└──────────┬──────────┘
│
│ AgentFlowClient
▼
┌─────────────────────┐
│ @10xscale/agentflow-client │ ← This library
│ - Client │
│ - Tools │
│ - Messages │
└──────────┬──────────┘
│
│ HTTP/HTTPS + WebSocket
▼
┌─────────────────────┐
│ AgentFlow Server │ ← Your backend
│ (Multi-agent API) │
└─────────────────────┘🔧 Configuration
const client = new AgentFlowClient({
baseUrl: string, // Required: API base URL
authToken?: string, // Optional: legacy Bearer token
auth?: AgentFlowAuth, // Optional: basic/custom header auth
headers?: HeadersInit, // Optional: extra headers for every request
credentials?: RequestCredentials, // Optional: cookie/session auth
timeout?: number, // Optional: Request timeout (default: 5min)
debug?: boolean, // Optional: Enable debug logging
webSocketImpl?: typeof WebSocket // Node < 21 (pass the 'ws' package)
});Module formats
Ships dual ESM + CJS with types. import resolves dist/index.js (ESM); require resolves
dist/index.cjs. Tree-shakeable ("sideEffects": false).
🧪 Testing
# Run all tests
npm test
# Run tests once
npm run test:run
# Build the library
npm run build📝 TypeScript Support
Full TypeScript support with comprehensive type definitions:
import type {
AgentFlowClient,
Message,
ToolRegistration,
InvokeResult,
StreamChunk,
AgentState,
AgentStateSchema,
} from '@10xscale/agentflow-client';🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🆘 Support
🙏 Acknowledgments
Built for the AgentFlow multi-agent system framework.
Made with ❤️ for the AgentFlow community
