funkai is a composable, functional TypeScript microframework for AI agent orchestration. It is built on the Vercel AI SDK -- not a replacement, but a thin layer that adds typed agents, multi-step workflows, and structured error handling on top of generateText/streamText.
The AI SDK gives you powerful primitives like generateText and streamText. But when you start building real applications, you need more: typed agents with validated I/O, multi-step orchestration with observable traces, consistent error handling that does not rely on try/catch, and a model catalog for cost tracking. funkai adds all of this without introducing classes or hidden state.
funkai provides two agent primitives that share the same Runnable interface:
-
agent()-- A single LLM boundary with a tool loop. WrapsgenerateText/streamTextwith typed input, tools, subagents, hooks, andResult-based error handling. Use this when a single model call (with optional tool iterations) is sufficient. -
flowAgent()-- Multi-step, code-driven orchestration. Your handler function receives{ input, $, log }where$is the StepBuilder providing traced operations like$.step(),$.agent(),$.map(), and$.reduce(). Use this when you need to coordinate multiple agents, run parallel work, or implement custom control flow.
Both return Result<T> from every public method -- a discriminated union you pattern-match on ok instead of catching exceptions.
| Package | Name | Description |
|---|---|---|
@funkai/agents |
Agents | Agent orchestration -- agent(), flowAgent(), tool(), Result utilities |
@funkai/models |
Models | Model catalog, provider registry, and cost calculation |
@funkai/prompts |
Prompts | Build-time prompt templating with LiquidJS and Zod validation |
@funkai/cli |
CLI | Command-line tooling for prompt generation, linting, and setup |
import { agent, flowAgent, tool } from "@funkai/agents";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
// Single LLM boundary
const writer = agent({
name: "writer",
model: openai("gpt-4.1"),
system: "You write concise technical docs.",
});
// Multi-step orchestration
const pipeline = flowAgent(
{
name: "pipeline",
input: z.object({ topics: z.array(z.string()) }),
output: z.object({ docs: z.array(z.string()) }),
},
async ({ input, $ }) => {
const docs = await $.map({
id: "write-docs",
input: input.topics,
execute: async ({ item, $ }) => {
const result = await $.agent({ id: "write", agent: writer, input: item });
if (result.ok) {
return result.output;
}
return "";
},
concurrency: 3,
});
if (docs.ok) {
return { docs: docs.output };
}
return { docs: [] };
},
);
// Both satisfy Runnable -- same .generate(), .stream(), .fn()
const result = await pipeline.generate({ topics: ["TypeScript", "Zod"] });
if (result.ok) {
console.log(result.output);
}- Quick Start -- Install and build your first agent in minutes.
- Agents -- Understand the core
agent()primitive. - Flow Agents -- Multi-step orchestration with
flowAgent().