Agent SDK
kraken-ai is the open-source, fully typed agent framework. Define an agent, give it Zod-typed tools, point it at a model, and run it — with structured output, multi-agent teams, and human-in-the-loop built in.
#Installation
The kraken-ai package is already a dependency of every scaffolded Kraken project — you do not normally install it by hand. To add it to an existing project, install it from npm:
$ pnpm add kraken-ainpm install kraken-ai
The SDK has a single runtime peer dependency, zod (v4+), which you use to type tool parameters and structured output. The Google provider additionally needs @google/genai, declared as an optional peer dependency and loaded lazily only when you use it.
import {
Agent,
tool,
google,
configure,
formatEvent,
} from "kraken-ai";
import { z } from "zod";#Agent
An Agent is constructed from an AgentConfig object. The model is resolved at construction time; tools, teams, and structured output are wired in lazily per run.
const agent = new Agent({
name: "pricing-analyst",
model: "google/gemini-3-flash-preview",
instructions: "You are a pricing analyst. Use tools to look up product data.",
});AgentConfig fields:
namestringRequiredHuman-readable name. Also used as the delegation tool name when this agent is a team member.
modelModel | ModelStringRequiredThe model powering the agent. Either a provider-qualified string such as "google/gemini-3-flash-preview" or a Model instance from a provider factory like google().
instructionsstringRequiredSystem instructions defining the agent's behavior.
descriptionstringOptionalCapabilities description shown to orchestrator agents when this agent is delegated to.
toolsTool[]OptionalTools available to the agent, created with the tool() factory.
temperaturenumberOptionalSampling temperature.
allowTemperatureOverridebooleanOptionalWhen false, a parent agent cannot override this agent's temperature. Defaults to true.
maxOutputTokensnumberOptionalMaximum number of output tokens per model call.
thinkingLevel"low" | "medium" | "high"OptionalDefault reasoning depth for all LLM calls. Providers map this to their native thinking configuration.
teamAgentLike[]OptionalTeam members this agent can delegate to. Each becomes a delegation tool the model can choose to call.
outputSchemaz.ZodTypeOptionalZod schema for structured JSON output. When set, the model is constrained to the schema and the result's output is validated and typed as z.infer<TOutput>.
kernelKernelOptionalCustom kernel for full manual control of the execution loop. See Advanced.
logLevel"silent" | "debug" | "info" | "warn" | "error"OptionalLog verbosity override for this agent.
#agent.run()
agent.run(messages: Message[], options?: RunOptions) executes the agent against a non-empty array of conversation messages and resolves to a RunResult.
A Message has a role of "user" or "assistant" and a string content; assistant turns may also carry toolCalls and toolResults for multi-turn histories.
RunResult is a discriminated union on status. Narrow on status before accessing the other fields — each one exists on only one branch of the union.
| Property | Type | Branch | Description |
|---|---|---|---|
status | "complete" | "interrupted" | Always | The discriminant. "complete" when the agent finished; "interrupted" when a tool requiring approval paused execution. |
output | TOutput | complete | The agent output. unknown by default, or z.infer<TOutput> when outputSchema is configured. |
messages | Message[] | complete | The full conversation history including tool calls and results. |
usage | { inputTokens: number; outputTokens: number } | complete | Aggregated token usage. |
transitions | TransitionRecord[] | complete | The recorded state transitions for the run. |
interrupt | Interrupt | interrupted | The pending tool call awaiting a human decision (toolName, args, toolCallId). |
resume | (decision: HumanDecision) => Promise<RunResult> | interrupted | Resume the run with "approve", "reject", or { feedback: string }. |
RunOptions accepts an onEvent callback for real-time event streaming, an AbortSignal via signal, a middleware chain, an explicit runId, per-run temperature / thinkingLevel / maxOutputTokens overrides, and dryRun (tool calls logged but not executed).
const result = await agent.run([
{ role: "user", content: "What is the price of SKU-4821?" },
]);
if (result.status === "complete") {
console.log(result.output);
} else {
// A tool required approval — decide, then resume.
const next = await result.resume("approve");
}#tool()
tool() creates a Zod-typed tool. The parameters schema is converted to JSON Schema for the model and used at runtime to validate arguments before execute is called. Invalid arguments throw a ToolInputValidationError with the expected schema and per-field errors.
namestringRequiredTool name presented to the model.
descriptionstringRequiredWhat the tool does — the model uses this to decide when to call it.
parametersz.ZodTypeRequiredZod schema for the tool arguments. The execute callback receives z.infer<typeof parameters>.
execute(args) => Promise<TReturn>RequiredThe handler. Receives validated, typed arguments and returns the tool result.
requiresApprovalboolean | ((args) => boolean)OptionalRequire a human decision before execution. A boolean, or a per-invocation predicate over the arguments. When it gates a call, run() returns an interrupted result.
const lookupPrice = tool({
name: "lookup_price",
description: "Look up the current price of a product by SKU",
parameters: z.object({ sku: z.string() }),
execute: async ({ sku }) => {
const price = await db.products.getPrice(sku);
return { sku, price };
},
});#Models & providers
A model is either a provider-qualified string or a Model instance from a provider factory. String format is "provider/model-id" — for example "google/gemini-3.1-pro-preview" or "google/gemini-3-flash-preview". String models are resolved lazily on first use.
google(modelId, config?) returns a Google Gemini model. config accepts an optional apiKey and retry overrides. When no key is passed, the provider reads GEMINI_API_KEY, then GOOGLE_API_KEY, from the environment.
import { google, mock } from "kraken-ai";
const model = google("gemini-3-flash-preview");
// Deterministic model for tests — no network, with call tracking.
const testModel = mock({
response: { text: "ok", usage: { inputTokens: 1, outputTokens: 1 } },
});mock() creates a deterministic model for testing: it records every call and replies from a fixed response or pattern-matched handlers.
Important
openai() is exported and accepts the OpenAI model-id type, but the provider is not yet implemented — calling it throws a ProviderError. Use the Google provider, a mock() model, or a custom Model implementation.
#Events
Pass onEvent in RunOptions to receive a typed AgentEvent for each step of a run. AgentEvent is a discriminated union on type, covering configuration, transcript init, lifecycle transitions, LLM calls, model thoughts, tool calls, delegation, interrupts, kills, errors, notifications, and structured-output completion. Every event carries the agent name, a runId, a timestamp, and a monotonic sequence number.
formatEvent(event) renders any event as a human-readable one-line string, useful for development logging.
import { formatEvent } from "kraken-ai";
await agent.run(messages, {
onEvent: (event) => {
process.stdout.write(formatEvent(event) + "\n");
},
});#Errors
Every SDK error extends KrakenError and carries a stable code string for narrowing.
KrakenErrorcode: "KRAKEN_ERROR"OptionalBase class for all kraken-ai errors.
ValidationErrorcode: "VALIDATION_ERROR"OptionalInvalid configuration or input — for example an unparseable model string or unknown provider.
ProviderErrorcode: "PROVIDER_ERROR"OptionalA failure from an LLM provider (missing API key, rate limit, API error). Also thrown by the not-yet-implemented OpenAI provider.
ToolErrorcode: "TOOL_ERROR"OptionalAn error during tool execution. Carries the toolName.
ToolInputValidationErrorcode: "TOOL_INPUT_VALIDATION_ERROR"OptionalThe model supplied tool arguments that fail the parameter schema. Carries toolName, the expected JSON Schema, and the received arguments.
OutputValidationErrorcode: "OUTPUT_VALIDATION_ERROR"OptionalStructured output failed the agent's outputSchema after retries. Carries the rawOutput and retry context.
#Advanced
defineKernel() defines a custom kernel — an async generator that takes full manual control of the execution loop, yielding signals such as spawn, await, interrupt, and complete. Pass the result as kernel in AgentConfig.
defineSkillTool() and skillDiscoveryMessage() implement the progressive-disclosure skills pattern without framework lock-in:
defineSkillTool({ skillId, load })builds aload_skill_*tool that defers fetching the skill body to a caller-providedloadfunction.skillDiscoveryMessage(entries)builds an<available_skills>catalog string to drop into the system prompt so the model can discover what is loadable.
On the Kraken platform you author skills declaratively instead — see Skills.
Putting it together — an agent with a tool and a Google model:
import { Agent, tool, google } from "kraken-ai";
import { z } from "zod";
const lookupPrice = tool({
name: "lookup_price",
description: "Look up the current price of a product by SKU",
parameters: z.object({ sku: z.string() }),
execute: async ({ sku }) => ({ sku, price: 42.0 }),
});
const agent = new Agent({
name: "pricing-analyst",
model: google("gemini-3-flash-preview"),
instructions: "You are a pricing analyst. Use tools to look up product data.",
tools: [lookupPrice],
});
const result = await agent.run([
{ role: "user", content: "What is the price of SKU-4821?" },
]);
if (result.status === "complete") {
console.log(result.output);
}Note
kraken-ai runs the agent loop in-process. The Kraken platform runs the same agents inside governed, sandboxed runtimes with policy enforcement, audit, and observability — see the Platform SDK.
#Next steps
- Platform SDK — Promote agents to the governed platform: connectors, actions, skills, and the PlatformClient.
- Agents — How agents, runs, teams, and structured output work on the Kraken platform.
- CLI — Scaffold projects, generate types, and manage credentials with the kraken CLI.