graph TD
agents["@funkai/agents"]
models["@funkai/models"]
prompts["@funkai/prompts"]
cli["@funkai/cli"]
ai["ai (Vercel AI SDK)"]
agents --> models
agents --> ai
cli --> prompts
models --> ai
@funkai/agentsdepends on@funkai/models(forProviderRegistrytype) andai(Vercel AI SDK).@funkai/modelsdepends onaifor theLanguageModeltype. Standalone otherwise.@funkai/promptsis fully standalone -- no dependency on other funkai packages.@funkai/clidepends on@funkai/promptsfor prompt generation and linting.
agent() wraps the AI SDK's generateText and streamText with:
- Typed input -- Optional Zod schema + prompt template. When provided,
.generate()accepts typed input and validates it before calling the model. In simple mode, raw strings or message arrays pass through directly. - Tools -- A record of
tool()instances exposed to the model for function calling. - Subagents -- Other agents passed via the
agentsconfig, automatically wrapped as callable tools with abort signal propagation. - Hooks --
onStart,onFinish,onError,onStepFinishfor observability. Per-call overrides merge with base hooks. - Result -- Every method returns
Result<T>. Success fields are flat on the object. Errors carrycode,message, and optionalcause.
The tool loop runs up to maxSteps iterations (default 20), where each iteration may invoke tools or subagents before producing a final response.
flowAgent() provides code-driven orchestration. The handler receives { input, $, log }:
input-- Validated against the input Zod schema.$(StepBuilder) -- Traced operations:$.step(),$.agent(),$.map(),$.each(),$.reduce(),$.while(),$.all(),$.race(). Each call becomes an entry in the execution trace.log-- Scoped logger with contextual bindings.
The handler returns the output value, validated against the optional output Zod schema. Each $ operation is modeled as a synthetic tool call in the message history, making flow agents compatible with the same GenerateResult and StreamResult types as regular agents.
FlowAgent results include additional fields: trace (array of step entries) and duration (wall-clock milliseconds).
Both Agent and FlowAgent satisfy the Runnable interface:
interface Runnable<TInput, TOutput> {
generate(input: TInput, config?): Promise<Result<{ output: TOutput }>>;
stream(input: TInput, config?): Promise<Result<{ output: Promise<TOutput>; fullStream }>>;
fn(): (input: TInput, config?) => Promise<Result<{ output: TOutput }>>;
}This enables nesting: a FlowAgent can call any Agent or FlowAgent via $.agent(). An Agent can delegate to subagents via the agents config. The framework uses a symbol-keyed metadata property (RUNNABLE_META) to extract the name and input schema when wrapping runnables as tools.
Provides three capabilities:
- Model catalog --
model(id)andmodels()for querying model definitions (capabilities, modalities, pricing) sourced from OpenRouter. The catalog is generated at build time viapnpm --filter=@funkai/models generate:models. - Provider registry --
createProviderRegistry()maps provider names to AI SDK provider instances, enabling string-based model resolution (e.g.,'openai/gpt-4.1'). - Cost calculation --
calculateCost()computes dollar costs from token usage and model pricing data.
Build-time prompt templating:
- Prompts are defined as
.promptfiles with YAML frontmatter (metadata, Zod schema reference) and LiquidJS template bodies. createPromptRegistry()loads compiled prompt modules and provides type-safe rendering at runtime.- The
@funkai/clipackage provides commands for creating, generating, and linting prompt files.
Prompts are independent of the agents package -- they can be used standalone or integrated into agent prompt functions.