/** * Types for @gizmo-ai/server * * SSE event types, server configuration, and API contracts. */ import type { Runtime, Action, Dispatch, RuntimePlugin } from "@gizmo-ai/runtime"; import type { Operation } from "fast-json-patch"; import type { Hono } from "hono"; import type { EventEmitter } from "events"; /** * Context provided to route handlers * * This gives route handlers access to runtime state and dispatch. */ export interface RouteContext { getState: () => S; dispatch: Dispatch; subscribe: (listener: () => void) => () => void; } /** * Route configuration for startServer * * Routes are a server concern - decoupled from RuntimePlugin. * Pass routes to startServer() via the `routes` config option. * * @example * ```typescript * import { startServer } from "@gizmo-ai/server"; * import { createHITLRoutes } from "@gizmo-ai/hitl-plugin"; * import { createBranchingRoutes } from "@gizmo-ai/branching-plugin"; * * startServer(runtime, { * port: 3001, * routes: [ * { path: "/approvals", createHandler: createHITLRoutes }, * { path: "/branching", createHandler: createBranchingRoutes }, * ], * }); * ``` */ export interface ServerRoute { /** Path prefix for mounting (e.g., "/branching") */ path: string; /** Factory function that creates a Hono app */ createHandler: (ctx: RouteContext) => Hono; } /** * Initial state snapshot sent on SSE connection */ export interface InitialStateEvent { type: "state.initial"; slices: Record; timestamp: number; } /** * State slice update event with JSON Patch (RFC 6902) * * Sends either patches (for incremental updates) or value (for full replacement). * Full replacement is used for: * - First update (previousState is undefined) * - Type changes (object → array, primitive → object, etc.) * - When patch computation would be unsafe */ export interface StateUpdateEvent { type: "state.update"; slice: string; /** * JSON Patch operations for incremental updates (RFC 6902). * Omitted when sending full replacement via `value`. */ patches?: Operation[]; /** * Full state value for replacement. * Used instead of patches for type changes or first update. */ value?: unknown; cause?: { type: string; id?: string; payload?: unknown; }; timestamp: number; } /** * Execution lifecycle event */ export interface ExecutionStatusEvent { type: "execution.status"; status: "started" | "completed" | "failed" | "aborted" | "interrupted"; executionId?: string; turnId?: string; error?: string; timestamp: number; } /** * Heartbeat keep-alive event */ export interface HeartbeatEvent { type: "heartbeat"; timestamp: number; } /** * Custom event for coordinator/plugin events */ export interface CustomEvent { type: "custom-event"; data: unknown; timestamp: number; } /** * Union of all SSE event types */ export type SSEEvent = InitialStateEvent | StateUpdateEvent | ExecutionStatusEvent | HeartbeatEvent | CustomEvent; /** * State change event emitted by broadcaster middleware */ export interface StateChangedEvent { slice: string; before: unknown; after: unknown; causingAction: Action; } /** * Execution lifecycle event emitted by broadcaster middleware */ export interface ExecutionLifecycleEvent { status: ExecutionStatusEvent["status"]; executionId?: string; turnId?: string; error?: Error; } /** * Event bus event map */ export interface BusEvents { "state.changed": StateChangedEvent; "execution.lifecycle": ExecutionLifecycleEvent; } /** * Server plugin configuration */ export interface ServerPluginConfig { /** State slices to broadcast (default: all top-level keys) */ slices?: string[]; /** Number of recent runs to store for history (default: 10, 0 = disabled) */ historySize?: number; /** Persistence configuration for JSONL storage */ persistence?: { /** Enable persistence (default: false) */ enabled: boolean; /** Base directory for persistence files (default: .gizmo) */ baseDir?: string; }; } /** * Stored run information for history */ export interface StoredRun { executionId: string; startTime: number; endTime?: number; status: "running" | "completed" | "failed" | "aborted"; actions: Action[]; error?: string; } /** * Server plugin instance with event bus */ export interface ServerPluginInstance = Record, A extends Action = Action> { /** The RuntimePlugin to add to the runtime */ plugin: RuntimePlugin<"__server", object, A, S>; /** Internal event bus for SSE streaming */ bus: EventEmitter; /** Configured slices to track */ slices?: string[]; /** * Get the resolved list of slices being tracked * This accounts for auto-filtering of non-serializable slices * @param state - Current runtime state * @returns Array of slice keys being tracked */ resolvedSlices: (state: S) => string[]; /** Number of recent runs to store in-memory (0 = in-memory disabled) */ historySize: number; /** Get run history map (in-memory) */ getRunHistory: () => Map; /** Record an action/state transition for run history and persistence */ recordAction: (action: A, state: S) => void; /** Persistence store (if enabled) */ persistence: import("./persistence/index.ts").PersistenceStore | null; } /** * Server configuration */ export interface ServerConfig = Record, A extends Action = Action> { /** The Gizmo runtime instance */ runtime: Runtime; /** Server plugin instance from createServerPlugin() */ plugin: ServerPluginInstance; /** Heartbeat interval in ms (default: 30000) */ heartbeatInterval?: number; /** Base path for all routes (default: "") */ basePath?: string; /** Custom serializer for state (default: safe JSON serializer) */ serializer?: (value: unknown) => string; /** * EventEmitter from ag-ui-adapter-plugin (optional) * If provided, enables /events/ag-ui route for AG-UI protocol compatibility * @see @gizmo-ai/ag-ui-adapter-plugin */ agUIAdapterBus?: EventEmitter; /** Optional manifest configuration */ manifest?: ManifestConfig; /** * Action contracts from installed plugins (optional) * If provided, enables /contracts/actions.public.json route */ contracts?: import("@gizmo-ai/runtime").ActionContract[]; } /** * Server instance */ export interface Server { /** Hono app instance for customization */ app: Hono; /** Start the server on a port */ listen: (port: number) => void; /** Stop the server and cleanup */ close: () => void; } /** * POST /invoke request body */ export interface InvokeRequest { input: string; } /** * POST /invoke response */ export interface InvokeResponse { executionId: string; turnId: string; } /** @deprecated Use InvokeRequest instead */ export type ExecuteRequest = InvokeRequest; /** @deprecated Use InvokeResponse instead */ export type ExecuteResponse = InvokeResponse; /** * POST /abort response */ export interface AbortResponse { status: "aborted"; executionId: string; } /** * Run summary for /runs list endpoint */ export interface RunSummary { executionId: string; startTime: number; endTime?: number; status: "running" | "completed" | "failed" | "aborted"; actionCount: number; error?: string; /** SHA-256 digest of run bundle (actions + final state) for tamper evidence */ digest?: string; } /** * Full run details for /runs/:executionId endpoint */ export interface RunDetails extends RunSummary { actions: Action[]; } /** * GET /runs response */ export interface RunsResponse { runs: RunSummary[]; } /** * POST /hydrate request body */ export interface HydrateRequest { /** Source run to hydrate from */ executionId: string; /** Replay only up to this action sequence number */ upToSeq?: number; /** Replay up to end of turn N (turn boundaries defined by RUNTIME_EXECUTION_STARTED actions) */ upToTurn?: number; /** Send a new message after hydration completes */ thenExecute?: string; /** Hydration mode: "full" replays all data, "slim" stubs tool outputs */ hydrateMode?: "full" | "slim"; } /** * POST /hydrate response */ export interface HydrateResponse { status: "hydrated"; /** Number of actions replayed */ actionCount: number; /** Summary of restored state */ state: { conversationLength: number; loopCount: number; }; /** Execution info if thenExecute was provided */ execution?: { executionId: string; turnId: string; }; } /** * Error response */ export interface ErrorResponse { error: string; } /** * Authentication configuration for startServer * * Accepts standard Hono middleware from any auth provider (Clerk, Auth0, etc.) * * @example * ```typescript * import { clerkMiddleware } from "@hono/clerk-auth"; * * startServer(runtime, { * auth: { * middleware: clerkMiddleware(), * publicPaths: ["/health", "/.well-known/*"], * }, * }); * ``` */ export interface AuthConfig { /** * Hono middleware for authentication. * Use middleware from @hono/clerk-auth, @hono/auth-js, or any Hono-compatible auth middleware. */ middleware: import("hono").MiddlewareHandler; /** * Paths that bypass authentication (exact match or prefix with /*). * Default: ["/health", "/.well-known/*", "/contracts/*"] */ publicPaths?: string[]; } /** * Manifest configuration (optional) */ export interface ManifestConfig { identity: { agentId: string; name: string; version?: string; description?: string; documentationUrl?: string; }; auth?: { type?: string; scopes?: string[]; }; } /** * Agent manifest for self-description and capability discovery * Served at /.well-known/manifest.json */ export interface GizmoManifest { /** Schema version for manifest format */ manifestVersion: string; /** Agent identity */ identity: { agentId: string; name: string; version: string; description?: string; documentationUrl?: string; }; /** Authentication requirements (optional) */ auth?: { type?: string; scopes?: string[]; }; /** Available endpoints */ endpoints: { /** Invoke agent with input */ invoke: string; /** Current state snapshot */ state: string; /** Recent run history */ runs: string; /** Stream endpoints for SSE */ streams: { /** State updates only */ state: string; /** Execution lifecycle and action events */ actions: string; /** Combined stream (AG-UI compatible) */ events: string; }; /** Control endpoints for run management */ control?: { /** Cancel a running execution */ cancel: string; /** Continue execution after HITL intervention */ continue: string; }; /** Plugin-provided endpoints (auto-mounted from plugins with routes) */ plugins?: Record; }; /** State structure schema */ state: { slices: string[]; schemaVersion: string; /** Reference to external schema (alternative to inline) */ schemaRef?: string; /** Inline JSON Schema describing the state structure */ schema?: { type: "object"; properties: Record; $defs?: Record; }; }; /** Action contract references */ actions?: { /** Reference to public contracts endpoint */ publicContractsRef: string; }; /** Agent capabilities */ capabilities: { tools?: string[]; skills?: Array<{ name: string; description?: string; source?: string; }>; models?: string[]; features?: string[]; plugins?: string[]; }; } //# sourceMappingURL=types.d.ts.map