Skip to content

TypeScript API Reference

All public APIs are exported from the zupdev package. Types can also be imported from zupdev/types.

import { createAgent, definePlugin, createObserver } from 'zupdev';
import type { AgentContext, Observation } from 'zupdev';

Creates and initializes a Zup agent. Plugins are loaded, capabilities are registered, and the state store is configured.

function createAgent(options?: AgentOptions): Promise<ZupAgent>

Returns a ZupAgent with these methods:

MethodSignatureDescription
runLoop()() => Promise<LoopResult>Execute one OODA loop iteration. Concurrent calls return the same promise.
executeAction(id, params?)(id: string, params?: Record<string, unknown>) => Promise<ActionResult>Execute a registered action directly, bypassing the loop.
start()() => Promise<(() => void) | undefined>Start the agent in its configured mode. Returns a stop function in continuous mode.
startApi(options?)(options?) => ApiServerStart the REST API server.
getContext()() => AgentContextReturn the current agent context.
getCapabilities()() => { observers, orienters, decisionStrategies, actions }List registered capability IDs as string arrays.
getHistory()() => LoopResult[]Return all past loop results from this session.
getState()() => StateStoreReturn the state store for reading/writing.

All fields are optional.

type AgentOptions = {
id?: string; // Default: random UUID
name?: string; // Default: 'Zup'
systemPrompt?: string; // Default: SRE agent prompt
logger?: Logger; // Default: console
llm?: LLMConfig; // LLM provider configuration
mode?: 'manual' | 'continuous' | 'event-driven'; // Default: 'manual'
loopInterval?: number; // Continuous mode interval in ms (default: 60000)
sqlite?: SQLiteConfig; // SQLite database configuration
statePersistence?: {
enabled: boolean;
type: 'memory' | 'file' | 'database';
config?: {
path?: string;
flushIntervalMs?: number;
tableName?: string;
};
};
api?: {
port?: number;
host?: string;
auth?: {
apiKeys?: Array<{ key: string; name: string; permissions?: string[] }>;
allowUnauthenticated?: boolean;
};
};
approvals?: {
autoExpire?: boolean; // Default: true
ttlMs?: number; // Default: 3600000 (1 hour)
};
plugins?: ZupPlugin[];
};

The context object available to all plugins and observers. Passed as ctx throughout the framework.

type AgentContext = {
agent: {
id: string;
name: string;
model: string;
systemPrompt: string;
};
logger: Logger;
llm?: LLMCapability;
sqlite?: SQLiteCapability;
loop: {
iteration: number;
phase: LoopPhase;
startTime: Date;
observations: Observation[];
situation?: Situation;
decision?: Decision;
actionResults: ActionResult[];
};
capabilities: {
observers: Map<string, Observer>;
orienters: Map<string, Orienter>;
decisionStrategies: Map<string, DecisionStrategy>;
actions: Map<string, Action>;
};
state: StateStore;
history: LoopResult[];
options: AgentOptions;
// Plugin-specific data (plugins can add their own keys)
[pluginId: string]: unknown;
};

Identity function that returns the plugin object. Provides type checking and IDE autocomplete.

function definePlugin(plugin: ZupPlugin): ZupPlugin

The full plugin type. All fields except id are optional.

type ZupPlugin = {
id: string;
// Lifecycle
init?: (ctx: AgentContext) => Awaitable<{
context?: Partial<Omit<AgentContext, 'options'>>;
options?: Partial<AgentOptions>;
} | void>;
// OODA components
observers?: Record<string, Observer>;
orienters?: Record<string, Orienter>;
decisionStrategies?: Record<string, DecisionStrategy>;
actions?: Record<string, Action>;
// Phase hooks
onObserve?: (observations: Observation[], ctx: AgentContext) => Awaitable<{
observations?: Observation[];
} | void>;
onOrient?: (situation: Situation, ctx: AgentContext) => Awaitable<{
situation?: Partial<Situation>;
} | void>;
onDecide?: (decision: Decision, ctx: AgentContext) => Awaitable<{
decision?: Partial<Decision>;
veto?: boolean;
} | void>;
// Action hooks
onBeforeAct?: (action: Action, params: Record<string, unknown>, ctx: AgentContext) => Awaitable<void>;
onAfterAct?: (result: ActionResult, ctx: AgentContext) => Awaitable<void>;
// Loop hooks
onLoopStart?: (ctx: AgentContext) => Awaitable<void>;
onLoopComplete?: (loopResult: LoopResult, ctx: AgentContext) => Awaitable<void>;
// API
endpoints?: Record<string, Endpoint>;
middleware?: Middleware[];
// State
schema?: StateSchema;
};

Helper type for plugin factory functions:

type ZupPluginFunction<TOptions = Record<string, unknown>> =
(options?: TOptions) => ZupPlugin;

Runs plugin init hooks sequentially and registers all capabilities. Used internally by createAgent.

function initializePlugins(
ctx: AgentContext,
plugins: ZupPlugin[]
): Promise<{ context: AgentContext; options: AgentOptions }>

executePluginHooks(plugins, hookName, …args)

Section titled “executePluginHooks(plugins, hookName, …args)”

Execute a named hook on all plugins sequentially. Returns the non-undefined results.

function executePluginHooks<T extends keyof ZupPlugin>(
plugins: ZupPlugin[],
hookName: T,
...args: unknown[]
): Promise<unknown[]>

These functions are identity functions that provide type checking. They do not transform the input.

function createObserver(observer: Observer): Observer
type Observer = {
name: string;
description: string;
observe: (ctx: AgentContext) => Promise<Observation[]>;
interval?: number; // For continuous mode (ms)
cost?: number; // API call cost estimate
};
function createOrienter(orienter: Orienter): Orienter
type Orienter = {
name: string;
description: string;
orient: (observations: Observation[], ctx: AgentContext) => Promise<SituationAssessment>;
};
function createDecisionStrategy(strategy: DecisionStrategy): DecisionStrategy
type DecisionStrategy = {
name: string;
description: string;
decide: (situation: Situation, ctx: AgentContext) => Promise<Decision>;
applicableWhen?: (situation: Situation) => boolean;
};
function createAction(action: Action): Action
type Action = {
name: string;
description: string;
execute: (params: Record<string, unknown>, ctx: AgentContext) => Promise<ActionResult>;
risk?: RiskLevel;
schema?: SchemaValidator;
rollback?: (params: Record<string, unknown>, ctx: AgentContext) => Promise<void>;
dryRun?: (params: Record<string, unknown>, ctx: AgentContext) => Promise<string>;
autonomy?: {
mode: 'auto' | 'approval-required' | 'human-only';
minConfidence?: number;
};
};
function createEndpoint(endpoint: Endpoint): Endpoint
type Endpoint = {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
path: string;
description?: string;
handler: (ctx: RequestContext) => Awaitable<Response>;
auth?: boolean; // Default: true
schema?: unknown; // Zod schema for validation
};

Execute a single OODA loop iteration. Used internally by agent.runLoop().

function runOODALoop(ctx: AgentContext, plugins: ZupPlugin[]): Promise<LoopResult>
type LoopResult = {
observations: Observation[];
situation?: Situation;
decision?: Decision;
actionResults: ActionResult[];
duration: number; // Total loop time in ms
success: boolean;
error?: string;
};

type Observation = {
source: string;
timestamp: Date;
type: ObservationType; // 'metric' | 'log' | 'alert' | 'event' | 'state'
severity?: ObservationSeverity; // 'info' | 'warning' | 'error' | 'critical'
data: Record<string, unknown>;
metadata?: Record<string, unknown>;
};
type ObserverRegistration = {
id: string;
observer: Observer;
};
type SituationAssessment = {
source: string;
findings: string[];
contributingFactor?: string;
impactAssessment?: string;
confidence: number; // 0-1
};
type Anomaly = {
type: string;
description: string;
severity: 'low' | 'medium' | 'high' | 'critical';
affectedResources?: string[];
};
type Correlation = {
observations: string[]; // observation source names
description: string;
confidence: number; // 0-1
};
type Situation = {
summary: string;
assessments: SituationAssessment[];
anomalies: Anomaly[];
correlations: Correlation[];
priority: Priority; // 'low' | 'medium' | 'high' | 'critical'
confidence: number; // 0-1
};
type Decision = {
action: string; // Action ID or 'no-op'
params: Record<string, unknown>;
rationale: string;
alternatives?: Decision[];
confidence: number; // 0-1
risk: RiskLevel; // 'low' | 'medium' | 'high' | 'critical'
requiresApproval: boolean;
estimatedImpact?: string;
};
type ActionResult = {
action: string;
success: boolean;
output?: unknown;
error?: string;
duration: number; // ms
sideEffects?: string[];
metrics?: Record<string, number>;
};
type SchemaValidator = {
parse: (data: unknown) => Record<string, unknown>;
};

Create a state store with optional persistence.

function createStateStore(options?: {
persistence?: {
enabled: boolean;
type: 'memory' | 'file' | 'database';
config?: {
path?: string;
flushIntervalMs?: number;
tableName?: string;
};
};
logger?: Logger;
sqlite?: SQLiteCapability;
}): StateStore
type StateStore = {
get(key: string): unknown;
set(key: string, value: unknown): void;
delete(key: string): void;
has(key: string): boolean;
};

Create a SQLite database capability.

function createSQLiteCapability(
config?: SQLiteConfig,
logger?: Logger
): SQLiteCapability
type SQLiteConfig = {
path?: string; // Default: ':memory:'
enableWAL?: boolean; // Default: true
enableVec?: boolean; // Default: true
vecExtensionPath?: string;
};

See SQLite & Embeddings for the full SQLiteCapability method reference.

createEmbeddingCapability(config, logger?)

Section titled “createEmbeddingCapability(config, logger?)”

Create an embedding capability for vector search.

function createEmbeddingCapability(
config: EmbeddingConfig,
logger?: Logger
): EmbeddingCapability
type EmbeddingConfig = {
provider: 'openai';
apiKey: string;
model?: string; // Default: 'text-embedding-3-small'
dimensions?: number; // Default: 1536
};
type EmbeddingCapability = {
embed(text: string): Promise<number[]>;
embedBatch(texts: string[]): Promise<number[][]>;
dimensions: number;
};

Create a raw LLM provider instance.

function createLLMProvider(config: LLMConfig): LLMProvider

Create an LLMCapability object (the same type that appears on ctx.llm).

function createLLMCapability(config: LLMConfig): LLMCapability

Create an LLM provider using the Vercel AI SDK. This is the underlying function used by createLLMProvider — you generally don’t need to call it directly.

function createAISDKProvider(config: LLMConfig): LLMProvider

All 16 provider variants in LLMConfig are supported: anthropic, openai, google, mistral, groq, xai, cohere, perplexity, togetherai, deepinfra, cerebras, openrouter, azure, amazon-bedrock, google-vertex, and openai-compatible.

See LLM Providers for usage patterns and the full type reference.


Create the REST API server. Used internally by agent.startApi().

function createApiServer(ctx: AgentContext, options?: ApiServerOptions): ApiServer
type ApiServerOptions = {
port?: number;
hostname?: string;
basePath?: string;
apiKeys?: string[];
allowUnauthenticated?: boolean;
};
type ApiServer = {
server: ReturnType<typeof Bun.serve>;
route: (method: string, path: string, handler: RouteHandler, auth?: boolean) => void;
stop: () => void;
};

Utility functions for building responses in custom endpoints:

function json(data: unknown, status?: number): Response
function error(message: string, status?: number): Response
function parseBody<T = unknown>(req: Request): Promise<T | null>
const responses: {
ok: <T>(data: T) => Response;
created: <T>(data: T) => Response;
noContent: () => Response;
badRequest: (message: string) => Response;
unauthorized: (message?: string) => Response;
forbidden: (message?: string) => Response;
notFound: (message?: string) => Response;
internalError: (message?: string) => Response;
};

Create a new run in the state store.

function createRun(ctx: AgentContext, input: CreateRunInput): Run
type CreateRunInput = {
title: string;
description: string;
priority?: RunPriority; // Default: 'medium'
context?: Record<string, unknown>;
source?: string; // Default: 'api'
callbackUrl?: string;
};

Retrieve a run by ID. Returns undefined if not found.

function getRun(ctx: AgentContext, runId: string): Run | undefined

List runs, optionally filtered by status and limited in count.

function listRuns(
ctx: AgentContext,
opts?: { status?: RunStatus; limit?: number }
): Run[]

updateRunStatus(ctx, runId, status, result?)

Section titled “updateRunStatus(ctx, runId, status, result?)”

Update a run’s status and optionally attach a result.

function updateRunStatus(
ctx: AgentContext,
runId: string,
status: RunStatus,
result?: RunResult
): Run | undefined

Convert a run into an Observation for injection into the observe phase.

function runToObservation(run: Run): Observation

Build a RunResult from a completed loop iteration.

function buildRunResult(loopResult: LoopResult, run: Run): RunResult

POST the run’s result to its callbackUrl, if one is set.

function sendCallback(run: Run): Promise<void>
type RunStatus = 'pending' | 'investigating' | 'completed' | 'failed' | 'cancelled';
type RunPriority = 'low' | 'medium' | 'high' | 'critical';
type Run = {
id: string;
title: string;
description: string;
priority: RunPriority;
status: RunStatus;
context: Record<string, unknown>;
source: string;
callbackUrl?: string;
createdAt: string;
updatedAt: string;
completedAt?: string;
result?: RunResult;
};
type RunResult = {
summary: string;
findings: string[];
actionsPerformed: Array<{
action: string;
success: boolean;
description: string;
}>;
loopIterations: number;
duration: number;
situationAssessment?: string;
recommendations?: string[];
};

type Awaitable<T> = T | Promise<T>;
type RiskLevel = 'low' | 'medium' | 'high' | 'critical';
type LoopPhase = 'observe' | 'orient' | 'decide' | 'act' | 'idle';
type ObservationType = 'metric' | 'log' | 'alert' | 'event' | 'state';
type ObservationSeverity = 'info' | 'warning' | 'error' | 'critical';
type Priority = 'low' | 'medium' | 'high' | 'critical';
interface Logger {
debug(message: string, ...args: unknown[]): void;
info(message: string, ...args: unknown[]): void;
warn(message: string, ...args: unknown[]): void;
error(message: string, ...args: unknown[]): void;
}

The Logger interface is compatible with console, Winston, Pino, and most logging libraries.


type Endpoint = {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
path: string;
description?: string;
handler: (ctx: RequestContext) => Awaitable<Response>;
auth?: boolean;
schema?: unknown;
};
type Middleware = (
req: Request,
ctx: AgentContext,
next: () => Promise<unknown>
) => Promise<unknown>;
type StateSchema = {
[key: string]: {
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
description?: string;
default?: unknown;
};
};
type RequestContext = {
request: Request;
params: Record<string, string>;
context: AgentContext;
};
type RouteHandler = (ctx: RequestContext) => Promise<Response> | Response;
type Route = {
method: string;
path: string;
handler: RouteHandler;
auth?: boolean;
};

All factory functions work independently of the agent. You can use them in scripts, tests, or external tools:

import {
createStateStore,
createSQLiteCapability,
createEmbeddingCapability,
createLLMCapability,
} from 'zupdev';
// Standalone state store with file persistence
const state = createStateStore({
persistence: { enabled: true, type: 'file', config: { path: './state.json' } },
});
state.set('counter', 42);
console.log(state.get('counter')); // 42
// Standalone SQLite
const sqlite = createSQLiteCapability({ path: './data.db' });
sqlite.createTable('app', 'logs', 'id INTEGER PRIMARY KEY, message TEXT');
sqlite.run('INSERT INTO app_logs (message) VALUES ($msg)', { msg: 'hello' });
sqlite.close();
// Standalone LLM
const llm = createLLMCapability({
provider: 'anthropic',
apiKey: process.env.ANTHROPIC_API_KEY!,
model: 'claude-sonnet-4-6',
});
const result = await llm.generateText('What is 2 + 2?');
console.log(result.text);