ZaFlow solves the complexity of building AI agent systems by providing a high-level, opinionated API. It is built for developers who need to create chatbots, autonomous agents, or AI-powered workflows without getting bogged down in protocol details.
Targeting Node.js and TypeScript developers, ZaFlow integrates essential features like multi-provider support, tool calling, agent delegation, and flow control out of the box.
- ✅ Lightweight - Minimal dependencies, fast startup, no bloat
- ✅ Multi-Provider - OpenAI, Groq, Ollama, or custom provider
- ✅ 3 Execution Modes - Single, Agentic, Autonomous
- ✅ Tools & Agents - Define tools with Zod schema validation
- ✅ Flow Control - Steps, conditions, loops, parallel execution
- ✅ Multimodal - Image, audio, file support with smart media reference system
- ✅ Output Format - Auto, JSON, WhatsApp formatting
- ✅ Agent Delegation - Autonomous agent-to-agent communication
- ✅ Structured Output - Type-safe responses with Zod schema validation
ZaFlow - Your orchestrator. Manages providers, tools, agents, and execution flows.
Provider - AI model connection (OpenAI, Groq, Ollama, or custom).
Tool - Functions that AI can call with validated parameters via Zod schemas.
Agent - Specialized AI with its own provider, prompt, and tools.
ExecutionContext - Rich context object with state, messages, and helpers.
Install zaflow using your preferred package manager:
npm install zaflow
# or
pnpm add zaflow
# or
bun add zaflowNote: Requires Node.js v20+ and TypeScript for best experience.
# For OpenAI provider
npm install openai
# For Groq provider
npm install groq-sdk
# For Ollama provider
npm install ollamaHere is a minimal example to get your AI agent running:
import { ZaFlow, defineProvider } from 'zaflow';
const GroqProvider = defineProvider({
type: 'groq',
apiKey: 'your-api-key',
defaultModel: 'moonshotai/kimi-k2-instruct',
});
const zaflow = new ZaFlow({
mode: 'single',
provider: GroqProvider,
});
const result = await zaflow.run('Explain quantum computing in one sentence');
console.log(result.content);The ZaFlow constructor accepts a configuration object:
| Option | Type | Required | Description |
|---|---|---|---|
mode |
ExecutionMode |
✅ | Execution mode: single, agentic, autonomous |
provider |
Provider |
✅ | AI provider instance |
agents |
Agent[] |
❌ | Sub-agents (for autonomous mode) |
tools |
Tool[] |
❌ | Tools (for agentic/autonomous mode) |
config |
ModelConfig |
❌ | Model configuration |
historyConfig |
HistoryConfig |
❌ | History management |
storage |
StoragePlugin |
❌ | Storage plugin |
hooks |
Hooks |
❌ | Event hooks |
systemPrompt |
string |
❌ | Custom system prompt |
You can define tools with Zod schema validation for type-safe AI function calling.
import { ZaFlow, defineProvider, defineTool } from 'zaflow';
import { z } from 'zod';
const calculator = defineTool({
name: 'calculator',
description: 'Perform mathematical calculations',
schema: z.object({
expression: z.string().describe('Math expression like "2 + 2"'),
}),
execute: ({ expression }) => eval(expression),
});
const zaflow = new ZaFlow({
mode: 'agentic',
// if you want to use other provider
// provider: GroqProvider,
tools: [calculator],
});
const result = await zaflow.run('What is 15 * 7 + 23?');import { defineProvider } from 'zaflow';
const provider = defineProvider({
type: 'openai',
apiKey: 'sk-xxx',
defaultModel: 'gpt-4o-mini',
});import { defineProvider } from 'zaflow';
const provider = defineProvider({
type: 'groq',
apiKey: 'gsk_xxx',
defaultModel: 'llama-3.3-70b-versatile',
});import { defineProvider } from 'zaflow';
const provider = defineProvider({
type: 'ollama',
baseURL: 'http://localhost:11434',
defaultModel: 'llama3.2',
});import { defineProvider } from 'zaflow';
// with your external AI API
const customAI = defineProvider({
type: 'custom',
name: 'my-ai',
adapter: async (messages, config) => {
const res = await fetch('https://my-api.com/chat', {
method: 'POST',
body: JSON.stringify({ messages }),
});
const json = await res.json();
return {
content: json.response,
usage: {
promptTokens: 0,
completionTokens: 0,
totalTokens: 0,
},
};
},
});
const zaflow = new ZaFlow({ mode: 'single', provider: customAI });
⚠️ AI Model Quality Affects Tool Calling & Agent DelegationThe quality of your AI model significantly impacts whether tool calls and agent delegations work correctly. When using Custom Provider with external APIs:
- Low-quality models may ignore tool instructions and respond directly instead of returning the required JSON format
{"tool": "...", "params": {...}}- Inconsistent behavior - The same prompt may sometimes trigger tools and sometimes not
- Empty responses - Some APIs may return empty responses causing execution errors
Recommendations:
Use Case Recommended Models Tool Calling GPT-4, GPT-4o, Claude 3, Llama 3.1 70B+, Qwen 2.5 72B+ Agent Delegation GPT-4o, Claude 3 Opus, Llama 3.3 70B Simple Chat Any model works fine For best results with tool calling and agent features, use built-in providers (
openai,groq,ollama) with high-quality models that have native function calling support.
Quick Jump: Single · Agentic · Autonomous
One chat call without tools. Fastest and most token-efficient.
const zaflow = new ZaFlow({
mode: 'single',
provider: GroqProvider,
});
const result = await zaflow.run('Hello!');AI can automatically call tools when needed.
const zaflow = new ZaFlow({
mode: 'agentic',
provider: GroqProvider,
tools: [weatherTool],
});
const result = await zaflow.run('Search weather in Jakarta');AI can call tools AND delegate to other agents.
const zaflow = new ZaFlow({
mode: 'autonomous',
provider: GroqProvider,
agents: [visionAgent, poetAgent],
tools: [analysisTool],
});
const result = await zaflow.run('Analyze this image and generate a poem');Quick Jump: Define Tool · Tool Config · Media Handling
import { defineTool } from 'zaflow';
import { z } from 'zod';
const weatherTool = defineTool({
name: 'get_weather',
description: 'Get current weather for a city',
schema: z.object({
city: z.string().describe('City name'),
unit: z.enum(['celsius', 'fahrenheit']).optional(),
}),
execute: async ({ city, unit = 'celsius' }) => {
// const data = await fetchWeatherAPI...
return `Currently in ${city} is 20°`;
},
});const tool = defineTool({
name: 'my_tool',
description: 'My tool description',
schema: z.object({ input: z.string() }),
execute: async ({ input }) => input,
cache: 300000, // TTL in ms, or true for default
retry: {
maxAttempts: 3,
delayMs: 1000,
backoff: 'exponential',
},
});const imageAnalyzer = defineTool({
name: 'analyze_image',
description: 'Analyze image content',
schema: z.object({ imageUrl: z.string() }),
handles: ['image'],
execute: async ({ imageUrl }) => {
// const data = await fetchAIImageAnalyzer...
return 'The picture shows the sun rising!';
},
});Quick Jump: Define Agent · Media Support · Register
import { defineAgent, defineProvider } from 'zaflow';
const codeReviewer = defineAgent({
name: 'Code Reviewer',
role: 'Expert code reviewer',
systemPrompt: `You are an expert code reviewer. Review code for bugs, security issues, and best practices.`,
provider: GroqProvider,
model: 'llama-3.3-70b-versatile',
config: { temperature: 0.3 },
tools: [lintTool, securityScanTool],
});
const contentWriter = defineAgent({
name: 'Content Writer',
role: 'Creative content writer',
systemPrompt: 'You are a creative content writer.',
provider: GroqProvider,
config: { temperature: 0.8 },
});const visionAgent = defineAgent({
name: 'Vision Analyzer',
role: 'Image analysis expert',
systemPrompt: 'You analyze images and describe their content.',
provider: GroqProvider,
// Tools that handle media will automatically be available
});const zaflow = new ZaFlow({
mode: 'autonomous',
provider: GroqProvider,
agents: [codeReviewer, contentWriter, visionAgent],
});Quick Jump: Image URL · Image Base64 · Media Reference
import { msg, text, image } from 'zaflow';
const messages = [
...,
msg.user([
text('What is in this image?'),
image('https://example.com/photo.jpg')
])
];
const result = await zaflow.run(messages);import { msg, text, imageBase64 } from 'zaflow';
const messages = [
...,
msg.user([
text('Describe this:'),
imageBase64(base64Data, 'image/png')
])
];
const result = await zaflow.run(messages, { mode: 'autonomous' });ZaFlow automatically uses a reference system for large media files (token efficient!):
// 20MB image is NOT copied to every agent
// Only reference ID is passed around
image(massive20MBBase64);
// Agents that need the image: needsMedia: ['image']
// → Receives full resolved data
// Agents that don't need the image
// → Media is stripped, saving tokens!Force AI to respond in a specific JSON structure with Zod schema validation:
import { ZaFlow, defineProvider } from 'zaflow';
import { z } from 'zod';
const zaflow = new ZaFlow({
mode: 'single',
provider: GroqProvider,
});
// Define your expected response schema
const personSchema = z.object({
name: z.string(),
age: z.number(),
occupation: z.string(),
skills: z.array(z.string()),
});
const result = await zaflow.run('Extract info: John Doe is a 28 year old software engineer skilled in TypeScript and React', {
schema: personSchema,
});
// result.content → response string (may contain JSON)
// To get validated data, you need to parse result.content based on schema
console.log(result.content); // Raw responseconst articleSchema = z.object({
title: z.string(),
summary: z.string().max(200),
tags: z.array(z.string()).min(1).max(5),
sentiment: z.enum(['positive', 'negative', 'neutral']),
metadata: z.object({
wordCount: z.number(),
readingTime: z.string(),
}),
});
const result = await zaflow.run('Analyze this article: ...', {
schema: articleSchema,
});Note: The
schemaoption guides the AI to output in the specified structure, but you'll need to parseresult.contentto get typed data.
const result = await zaflow.run(input, {
config: {
maxTokens: 4096,
temperature: 0.7,
topP: 0.9,
},
schema: responseSchema,
detailed: true,
persistContext: false,
systemPrompt: 'You are a helpful assistant.',
});Customize AI behavior without affecting library's internal prompts:
const result = await zaflow.run('Halo!', {
systemPrompt: `Kamu adalah JawiBot, asisten AI berbahasa Jawa.
Jawab semua pertanyaan dalam bahasa Jawa yang sopan.
Gunakan emoji sesekali untuk membuat percakapan lebih hidup.`,
});
// Output: "Sugeng enjing! Aku JawiBot, asisten AI sing siap mbantu sampeyan! 😊"Note:
systemPromptis injected before library's internal prompts (tools, agents), ensuring your personalization takes priority.
const result = await zaflow.run(input);
result.content; // Response content (string)
result.metadata; // Execution metadata (if detailed: true)
result.metadata?.tokensUsed; // Token usage { prompt, completion, total }
result.metadata?.toolsCalled; // Array of tool names called
result.metadata?.agentsCalled; // Array of agent names called
result.metadata?.executionTime; // Execution time in milliseconds
result.metadata?.model; // Model name used
result.error; // Error object (if any)import type {
ZaFlowOptions,
ZaFlowResponse,
RunOptions,
StreamOptions,
ModelConfig,
HistoryConfig,
Message,
QuotedMessage,
ExecutionMode,
TokenUsage,
ExecutionMetadata,
ErrorResponse,
Provider,
ProviderDefinition,
ProviderAdapter,
ProviderResponse,
ProviderMessage,
ToolCall,
RateLimit,
Tool,
ToolDefinition,
ToolContext,
SharedMemory,
StorageInterface,
Agent,
AgentDefinition,
AgentCapability,
AgentConstraints,
Hooks,
ErrorContext,
StoragePlugin,
StorageAdapter,
StorageDefinition,
OptimizationConfig,
RetryConfig,
CacheConfig,
TokenBudget,
ContentPart,
TextPart,
ImagePart,
AudioPart,
FilePart,
MediaType,
QuoteConfig,
} from 'zaflow';Contributions are welcome! Please follow these steps:
- Fork the repository.
- Create new branch:
git checkout -b feature/my-feature. - Commit your changes:
git commit -m 'Add some feature'. - Push to the branch:
git push origin feature/my-feature. - Open Pull Request.
If you encounter any problems or have feature requests, please open an issue
- Buy me coffee ☕
- Ko-Fi
- Trakteer
- ⭐ Star the repo on GitHub
Distributed under the MIT License. See LICENSE for details.
