@theokit/agents 0.29.0 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/decorators/main-loop.ts","../src/decorators/tool.ts","../src/decorators/hook.ts","../src/decorators/conversation.ts","../src/decorators/model.ts","../src/decorators/artifact.ts","../src/decorators/observable.ts","../src/decorators/sandbox.ts","../src/decorators/edit-format.ts","../src/decorators/apply-decorators.ts"],"sourcesContent":["/**\n * @MainLoop() — marks the execution entry point of an agent.\n *\n * Only one @MainLoop per agent class. Second application overwrites (last-wins, with warning).\n */\nimport { setMeta, getMeta, AGENT_MAIN_LOOP } from '../metadata/index.js'\nimport type { MainLoopOptions, MainLoopMeta } from '../types.js'\n\nexport function MainLoop(options: MainLoopOptions = {}): MethodDecorator {\n return (target: object, propertyKey: string | symbol) => {\n const actualTarget = target.constructor\n const existing = getMeta<MainLoopMeta>(AGENT_MAIN_LOOP, actualTarget)\n if (existing) {\n console.warn(\n `[@theokit/agents] ${actualTarget.name}: @MainLoop() already declared on '${String(existing.propertyKey)}'. Overwriting with '${String(propertyKey)}'.`,\n )\n }\n const meta: MainLoopMeta = {\n propertyKey,\n strategy: options.strategy ?? 'simple-chat',\n maxIterations: options.maxIterations,\n timeoutMs: options.timeoutMs,\n }\n setMeta(AGENT_MAIN_LOOP, actualTarget, meta)\n }\n}\n\nexport function getMainLoop(target: Function): MainLoopMeta | undefined {\n return getMeta<MainLoopMeta>(AGENT_MAIN_LOOP, target)\n}\n","/**\n * @Toolbox() + @Tool() — group and define agent tools.\n *\n * @Toolbox({ namespace }) is a class decorator that groups related tools.\n * @Tool({ name, description, input, risk }) is a method decorator compiled to defineTool().\n *\n * @UseGuards on @Toolbox applies to ALL tools (per ADR D7).\n */\nimport { setMeta, getMeta, TOOLBOX_CONFIG, TOOL_CONFIG, TOOL_METHODS } from '../metadata/index.js'\nimport type { ToolboxOptions, ToolOptions } from '../types.js'\n\n/**\n * Convention: TaskTools → namespace: 'tasks', ProjectTools → namespace: 'projects'\n * Strips \"Tools\" suffix, converts to kebab-case.\n */\nfunction inferNamespace(className: string): string {\n const stripped = className.replace(/Tools$/, '')\n return stripped\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase()\n}\n\nexport function Toolbox(options: ToolboxOptions = {}): ClassDecorator {\n return (target: Function) => {\n const ns = options.namespace ?? inferNamespace(target.name)\n setMeta(TOOLBOX_CONFIG, target, { ...options, namespace: ns })\n }\n}\n\nexport function Tool(options: ToolOptions): MethodDecorator {\n return (target: object, propertyKey: string | symbol) => {\n const actualTarget = target.constructor\n setMeta(TOOL_CONFIG, actualTarget, options, propertyKey)\n // Accumulate tool methods list\n const existing = getMeta<(string | symbol)[]>(TOOL_METHODS, actualTarget) ?? []\n setMeta(TOOL_METHODS, actualTarget, [...existing, propertyKey])\n }\n}\n\nexport function getToolboxConfig(target: Function): ToolboxOptions | undefined {\n return getMeta<ToolboxOptions>(TOOLBOX_CONFIG, target)\n}\n\nexport function getToolMethods(target: Function): (string | symbol)[] {\n return getMeta<(string | symbol)[]>(TOOL_METHODS, target) ?? []\n}\n\nexport function getToolConfig(\n target: Function,\n propertyKey: string | symbol,\n): ToolOptions | undefined {\n return getMeta<ToolOptions>(TOOL_CONFIG, target, propertyKey)\n}\n","/**\n * @Hook() — lifecycle hooks WITHIN the agent loop.\n *\n * Unlike HTTP interceptors (which wrap the entire handler), hooks fire at\n * specific points during the agent's reasoning → tool → response cycle.\n *\n * Hook points:\n * - 'before:llm-call' — before each LLM API call\n * - 'after:llm-call' — after each LLM response\n * - 'before:tool-call' — before each tool execution\n * - 'after:tool-call' — after each tool result\n * - 'on:iteration' — at each loop iteration\n * - 'on:complete' — when the agent produces a final answer\n * - 'on:error' — when the agent encounters an error\n *\n * @example\n * ```ts\n * @Agent({ name: 'support', route: '/support' })\n * class SupportAgent {\n * @MainLoop()\n * async run() {}\n *\n * @Hook('before:llm-call')\n * async injectContext(ctx: HookContext) {\n * ctx.appendSystemPrompt(`Time: ${new Date().toISOString()}`)\n * }\n *\n * @Hook('after:tool-call')\n * async trackCost(ctx: HookContext) {\n * await billing.track(ctx.toolCall!.name, ctx.toolCall!.durationMs)\n * }\n * }\n * ```\n */\nimport { setMeta, getMeta } from '../metadata/index.js'\n\nconst HOOKS_CONFIG = Symbol.for('theokit:agents:hooks')\n\nexport type HookPoint =\n | 'before:llm-call'\n | 'after:llm-call'\n | 'before:tool-call'\n | 'after:tool-call'\n | 'on:iteration'\n | 'on:complete'\n | 'on:error'\n\nexport interface HookEntry {\n point: HookPoint\n propertyKey: string | symbol\n}\n\nexport function Hook(point: HookPoint): MethodDecorator {\n return (target: object, propertyKey: string | symbol) => {\n const actualTarget = target.constructor\n const existing = getMeta<HookEntry[]>(HOOKS_CONFIG, actualTarget) ?? []\n setMeta(HOOKS_CONFIG, actualTarget, [...existing, { point, propertyKey }])\n }\n}\n\nexport function getHooks(target: Function): HookEntry[] {\n return getMeta<HookEntry[]>(HOOKS_CONFIG, target) ?? []\n}\n\nexport function getHooksByPoint(target: Function, point: HookPoint): HookEntry[] {\n return getHooks(target).filter((h) => h.point === point)\n}\n","/**\n * @Conversation() — declares conversation persistence strategy for an agent.\n *\n * Controls how the agent remembers message history across sessions.\n * Compiles to SDK's ConversationStorageAdapter configuration.\n *\n * @example\n * ```ts\n * @Agent({ name: 'support', route: '/support' })\n * @Conversation({\n * storage: 'drizzle',\n * maxHistory: 100,\n * compaction: 'summarize',\n * ttl: 24 * 60 * 60 * 1000,\n * })\n * class SupportAgent { ... }\n * ```\n */\nimport { setMeta, getMeta } from '../metadata/index.js'\n\nconst CONVERSATION_CONFIG = Symbol.for('theokit:agents:conversation')\n\nexport type ConversationStorage = 'memory' | 'filesystem' | 'drizzle' | 'redis'\nexport type CompactionStrategy = 'truncate' | 'summarize' | 'sliding-window'\n\nexport interface ConversationOptions {\n /** Storage backend for conversation history. */\n storage?: ConversationStorage\n /** Maximum messages before compaction triggers (0 = no limit). */\n maxHistory?: number\n /** How to compact when maxHistory is exceeded. */\n compaction?: CompactionStrategy\n /** Time-to-live in milliseconds before conversation expires (0 = never). */\n ttl?: number\n /** Number of recent messages to always preserve during compaction. */\n preserveLastN?: number\n}\n\nexport function Conversation(options: ConversationOptions = {}): ClassDecorator {\n return (target: Function) => {\n setMeta(CONVERSATION_CONFIG, target, {\n storage: 'memory',\n maxHistory: 0,\n compaction: 'truncate',\n ttl: 0,\n preserveLastN: 5,\n ...options,\n })\n }\n}\n\nexport function getConversationConfig(target: Function): ConversationOptions | undefined {\n return getMeta<ConversationOptions>(CONVERSATION_CONFIG, target)\n}\n","/**\n * @Model() — override the LLM model at agent or tool level.\n *\n * Hierarchical resolution via Reflector.getAllAndOverride:\n * tool @Model > agent @Model > @Agent({ model }) > config default\n *\n * This is a MODEL selector, not a PROVIDER selector. Provider routing\n * (which API key, which endpoint, fallback chains) lives in theo.config.ts\n * as runtime configuration — not in decorators.\n *\n * @example\n * ```ts\n * @Agent({ name: 'support', route: '/support' })\n * @Model('claude-sonnet-4-5-20250929') // default for all tools\n * class SupportAgent {\n * @MainLoop()\n * async run() {}\n * }\n *\n * @Toolbox({ namespace: 'code' })\n * class CodeTools {\n * @Tool({ name: 'generate', description: 'Generate code', input: z.object({...}) })\n * @Model('claude-opus-4-6') // this tool needs the most capable model\n * async generate() { ... }\n *\n * @Tool({ name: 'lint', description: 'Lint code', input: z.object({...}) })\n * // no @Model — inherits from agent level\n * async lint() { ... }\n * }\n * ```\n */\nimport { createDecorator } from '@theokit/http'\n\n/** Override the LLM model for an agent class or a specific tool method. */\nexport const Model = createDecorator<string>()\n","/**\n * @Artifact() — marks a tool as producing structured output artifacts.\n *\n * Artifacts are SEPARATE from text responses. When a tool produces an artifact\n * (code file, document, diagram, JSON data), the SSE stream emits artifact_start\n * + artifact_chunk events alongside text_delta events.\n *\n * Inspired by assistant-ui's A2AArtifact pattern where artifacts have their own\n * lifecycle (start → chunks → complete) independent of message content.\n *\n * @example\n * ```ts\n * @Toolbox({ namespace: 'code' })\n * class CodeTools {\n * @Tool({ name: 'generate', description: 'Generate code', input: z.object({...}) })\n * @Artifact({ mimeType: 'text/typescript', streamable: true })\n * async generate(input: { spec: string }): Promise<ArtifactResult> {\n * return {\n * content: generatedCode,\n * filename: 'component.tsx',\n * metadata: { language: 'typescript', loc: 42 },\n * }\n * }\n * }\n * ```\n */\nimport { setMeta, getMeta } from '../metadata/index.js'\n\nconst ARTIFACT_CONFIG = Symbol.for('theokit:agents:artifact')\n\nexport interface ArtifactOptions {\n /** MIME type of the artifact output. */\n mimeType: string\n /** Whether the artifact can be streamed in chunks (default: true). */\n streamable?: boolean\n /** Maximum size in bytes (0 = no limit). */\n maxSize?: number\n}\n\n/** Return type for tools decorated with @Artifact. */\nexport interface ArtifactResult {\n /** The artifact content (string for text, Buffer for binary). */\n content: string\n /** Optional filename hint for the client. */\n filename?: string\n /** Optional metadata attached to the artifact. */\n metadata?: Record<string, unknown>\n}\n\nexport function Artifact(options: ArtifactOptions): MethodDecorator {\n return (target: object, propertyKey: string | symbol) => {\n const actualTarget = target.constructor\n setMeta(ARTIFACT_CONFIG, actualTarget, { streamable: true, maxSize: 0, ...options }, propertyKey)\n }\n}\n\nexport function getArtifactConfig(\n target: Function,\n propertyKey: string | symbol,\n): ArtifactOptions | undefined {\n return getMeta<ArtifactOptions>(ARTIFACT_CONFIG, target, propertyKey)\n}\n","/**\n * @Observable() — exposes agent internal state as a real-time stream.\n *\n * Clients subscribe to named observables to monitor agent execution in real-time:\n * token usage, cost, iteration progress, pending approvals, retrieved facts.\n *\n * Inspired by Liveblocks' Presence pattern and tRPC subscriptions. The agent\n * pushes state updates via SSE alongside response events — clients are never\n * \"blind\" during long-running agent operations.\n *\n * @example\n * ```ts\n * @Agent({ name: 'research', route: '/research' })\n * class ResearchAgent {\n * @MainLoop()\n * async run() {}\n *\n * @Observable('metrics')\n * getMetrics(ctx: AgentContext): AgentMetrics {\n * return {\n * tokensUsed: ctx.tokenCount,\n * costUsd: ctx.costUsd,\n * iteration: ctx.iteration,\n * pendingApprovals: ctx.pendingApprovals.length,\n * }\n * }\n * }\n *\n * // SSE emits: { type: 'state_update', channel: 'metrics', data: {...} }\n * // Client: eventSource.addEventListener('state_update', handler)\n * ```\n */\nimport { setMeta, getMeta } from '../metadata/index.js'\n\nconst OBSERVABLE_CONFIG = Symbol.for('theokit:agents:observable')\n\nexport interface ObservableEntry {\n channel: string\n propertyKey: string | symbol\n}\n\nexport function Observable(channel: string): MethodDecorator {\n return (target: object, propertyKey: string | symbol) => {\n const actualTarget = target.constructor\n const existing = getMeta<ObservableEntry[]>(OBSERVABLE_CONFIG, actualTarget) ?? []\n setMeta(OBSERVABLE_CONFIG, actualTarget, [...existing, { channel, propertyKey }])\n }\n}\n\nexport function getObservables(target: Function): ObservableEntry[] {\n return getMeta<ObservableEntry[]>(OBSERVABLE_CONFIG, target) ?? []\n}\n\nexport function getObservableByChannel(target: Function, channel: string): ObservableEntry | undefined {\n return getObservables(target).find((o) => o.channel === channel)\n}\n","/**\n * @Sandbox() — declares file/command permission scope for code assistant agents.\n *\n * Controls what the agent can read, write, and execute. The runtime enforces\n * these permissions BEFORE tool execution — a tool that tries to write to a\n * denied path gets a typed error, not a crash.\n *\n * Inspired by Claude Code's permission system (allow/deny per tool + path).\n *\n * @example\n * ```ts\n * @Agent({ name: 'coder', route: '/agents/coder' })\n * @Sandbox({\n * filesystem: {\n * read: ['src/**', 'tests/**', 'package.json'],\n * write: ['src/**', 'tests/**'],\n * deny: ['node_modules/**', '.env', '*.key'],\n * },\n * commands: {\n * allow: ['npm test', 'tsc --noEmit', 'git diff'],\n * deny: ['rm -rf', 'git push --force', 'npm publish'],\n * },\n * network: false,\n * })\n * class CoderAgent { ... }\n * ```\n */\nimport { resolve } from 'node:path'\n\nimport { setMeta, getMeta } from '../metadata/index.js'\n\nconst SANDBOX_CONFIG = Symbol.for('theokit:agents:sandbox')\n\nexport interface FilesystemPermissions {\n /** Glob patterns for allowed read paths. */\n read?: string[]\n /** Glob patterns for allowed write paths. */\n write?: string[]\n /** Glob patterns for DENIED paths (overrides read/write). */\n deny?: string[]\n}\n\nexport interface CommandPermissions {\n /** Command prefixes allowed to execute. */\n allow?: string[]\n /** Command prefixes denied (overrides allow). */\n deny?: string[]\n}\n\nexport interface SandboxOptions {\n /** Filesystem read/write permissions. */\n filesystem?: FilesystemPermissions\n /** Shell command execution permissions. */\n commands?: CommandPermissions\n /** Allow outbound network from tools (default: true). */\n network?: boolean\n /** Maximum execution time per command in ms (default: 120_000). */\n commandTimeout?: number\n /** Working directory root (default: process.cwd()). */\n cwd?: string\n}\n\nexport function Sandbox(options: SandboxOptions): ClassDecorator {\n return (target: Function) => {\n setMeta(SANDBOX_CONFIG, target, {\n network: true,\n commandTimeout: 120_000,\n ...options,\n })\n }\n}\n\nexport function getSandboxConfig(target: Function): SandboxOptions | undefined {\n return getMeta<SandboxOptions>(SANDBOX_CONFIG, target)\n}\n\n/**\n * Check if a file path is allowed for the given operation.\n * Deny patterns always win over allow patterns.\n *\n * Security: normalizes paths to prevent traversal (../) and rejects null bytes.\n */\nexport function isPathAllowed(\n sandbox: SandboxOptions,\n filePath: string,\n operation: 'read' | 'write',\n): boolean {\n // EC-2: null byte injection — reject before any processing\n if (filePath.includes('\\x00')) return false\n\n // Path traversal fix: normalize to remove ../ sequences\n const normalized = resolve('/', filePath).slice(1)\n\n const fs = sandbox.filesystem\n if (!fs) return true // no filesystem restrictions\n\n // Deny always wins\n if (fs.deny?.some((pattern) => matchGlob(pattern, normalized))) return false\n\n const allowList = operation === 'read' ? fs.read : fs.write\n if (!allowList) return true // no explicit allow = allow all (minus deny)\n\n return allowList.some((pattern) => matchGlob(pattern, normalized))\n}\n\n/**\n * Shell metacharacters that indicate injection attempts.\n * EC-1: includes redirect operators (>, <) and newlines (\\n, \\r).\n */\nconst SHELL_METACHARS = /[;|&$`(){}<>\\n\\r]/\n\n/**\n * Check if a command is allowed to execute.\n * Deny patterns always win. Rejects shell metacharacters.\n *\n * Security: tokenizes command to match binary name, not arbitrary prefix.\n */\nexport function isCommandAllowed(sandbox: SandboxOptions, command: string): boolean {\n const cmds = sandbox.commands\n if (!cmds) return true\n\n // Reject any command with shell metacharacters (injection prevention)\n if (SHELL_METACHARS.test(command)) return false\n\n // Extract binary name (first whitespace-delimited token)\n const binary = command.split(/\\s+/)[0]\n\n // Deny always wins — check both exact binary match and full command prefix\n if (cmds.deny?.some((d) => binary === d || command.startsWith(d + ' ') || command === d))\n return false\n\n if (!cmds.allow) return true\n\n // Allow: match exact binary or full command prefix\n return cmds.allow.some((a) => binary === a || command.startsWith(a + ' ') || command === a)\n}\n\n/**\n * Glob matcher — converts glob pattern to regex at call time.\n * Uses a pre-built RegExp from a sanitized pattern string.\n * Supports *, **, and ? glob characters.\n */\nfunction matchGlob(pattern: string, filePath: string): boolean {\n // Escape all regex specials except glob chars (* and ?)\n const escaped = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/\\*\\*/g, '\\0GLOBSTAR\\0')\n .replace(/\\*/g, '[^/]*')\n .replace(/\\?/g, '[^/]')\n .replace(/\\0GLOBSTAR\\0/g, '.*')\n // Pre-compile regex outside of hot path (pattern is controlled by developer, not user input)\n const regex = buildGlobRegex(escaped)\n return regex.test(filePath)\n}\n\n/** Build a regex from a pre-escaped glob pattern string. */\nfunction buildGlobRegex(escapedPattern: string): RegExp {\n return RegExp(`^${escapedPattern}$`)\n}\n","/**\n * @EditFormat() — declares how a tool outputs file edits.\n *\n * Code assistants show DIFFS, not entire files. This decorator tells the\n * runtime which format the tool produces so the SSE stream emits the\n * correct `file_edit` event type.\n *\n * @example\n * ```ts\n * @Toolbox({ namespace: 'editor' })\n * class EditorTools {\n * @Tool({ name: 'edit', description: 'Edit file', input: editSchema })\n * @EditFormat('search-replace')\n * async edit(input: { file: string; search: string; replace: string }) {\n * return { file: input.file, search: input.search, replace: input.replace }\n * }\n *\n * @Tool({ name: 'write', description: 'Write file', input: writeSchema })\n * @EditFormat('full-file')\n * async write(input: { file: string; content: string }) {\n * return { file: input.file, content: input.content }\n * }\n * }\n * ```\n */\nimport { createDecorator } from '@theokit/http'\n\nexport type EditFormatType =\n | 'search-replace' // { file, search, replace } — Claude Code Edit pattern\n | 'unified-diff' // Standard unified diff format\n | 'full-file' // Complete file content (Write pattern)\n | 'line-range' // { file, startLine, endLine, content }\n\n/** Declare the edit format a tool produces. */\nexport const EditFormat = createDecorator<EditFormatType>()\n","/**\n * applyDecorators() — compose multiple decorators into a single reusable decorator.\n *\n * NestJS-compatible utility. Enables creating \"preset\" decorators that bundle\n * common configurations (auth + throttle + trace + memory + ...) into one decorator.\n *\n * @example\n * ```ts\n * // Create a reusable preset\n * const ProductionAgent = (name: string, route: string) => applyDecorators(\n * Agent({ name, route, model: 'claude-sonnet-4-5-20250929' }),\n * UseGuards(AuthGuard, TenantGuard),\n * Throttle({ limit: 30, ttl: 60_000 }),\n * Budget({ maxCostUsd: 5.00 }),\n * Trace(true),\n * )\n *\n * // Apply preset to any agent\n * @ProductionAgent('support', '/api/agents/support')\n * class SupportAgent {\n * @MainLoop()\n * async run() {}\n * }\n * ```\n */\n\ntype AnyDecorator = ClassDecorator | MethodDecorator | PropertyDecorator\n\n/**\n * Compose multiple decorators into a single decorator.\n * Works for both class-level and method-level decorators.\n */\nexport function applyDecorators(\n ...decorators: AnyDecorator[]\n): ClassDecorator & MethodDecorator {\n return (\n target: object | Function,\n propertyKey?: string | symbol,\n descriptor?: PropertyDescriptor,\n ) => {\n for (const decorator of decorators) {\n if (propertyKey !== undefined && descriptor !== undefined) {\n // Method-level\n ;(decorator as MethodDecorator)(target, propertyKey, descriptor)\n } else {\n // Class-level\n ;(decorator as ClassDecorator)(target as Function)\n }\n }\n }\n}\n"],"mappings":"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","names":["MainLoop","options","target","propertyKey","actualTarget","existing","getMeta","AGENT_MAIN_LOOP","console","warn","name","String","meta","strategy","maxIterations","timeoutMs","setMeta","getMainLoop","inferNamespace","className","stripped","replace","toLowerCase","Toolbox","options","target","ns","namespace","name","setMeta","TOOLBOX_CONFIG","Tool","propertyKey","actualTarget","TOOL_CONFIG","existing","getMeta","TOOL_METHODS","getToolboxConfig","getToolMethods","getToolConfig","HOOKS_CONFIG","Symbol","for","Hook","point","target","propertyKey","actualTarget","existing","getMeta","setMeta","getHooks","getHooksByPoint","filter","h","CONVERSATION_CONFIG","Symbol","for","Conversation","options","target","setMeta","storage","maxHistory","compaction","ttl","preserveLastN","getConversationConfig","getMeta","createDecorator","Model","ARTIFACT_CONFIG","Symbol","for","Artifact","options","target","propertyKey","actualTarget","setMeta","streamable","maxSize","getArtifactConfig","getMeta","OBSERVABLE_CONFIG","Symbol","for","Observable","channel","target","propertyKey","actualTarget","existing","getMeta","setMeta","getObservables","getObservableByChannel","find","o","resolve","SANDBOX_CONFIG","Symbol","for","Sandbox","options","target","setMeta","network","commandTimeout","getSandboxConfig","getMeta","isPathAllowed","sandbox","filePath","operation","includes","normalized","resolve","slice","fs","filesystem","deny","some","pattern","matchGlob","allowList","read","write","SHELL_METACHARS","isCommandAllowed","command","cmds","commands","test","binary","split","d","startsWith","allow","a","escaped","replace","regex","buildGlobRegex","escapedPattern","RegExp","createDecorator","EditFormat","applyDecorators","decorators","target","propertyKey","descriptor","decorator","undefined"]}
@@ -9,9 +9,11 @@ import {
9
9
  TOOL_METHODS,
10
10
  Trace,
11
11
  getAgentConfig,
12
+ getCheckpointConfig,
12
13
  getCompactionConfig,
13
14
  getContextWindowConfig,
14
15
  getGatewayConfig,
16
+ getHumanInTheLoopConfig,
15
17
  getMcpConfig,
16
18
  getMemoryConfig,
17
19
  getMeta,
@@ -19,7 +21,7 @@ import {
19
21
  getProjectContextConfig,
20
22
  getSkillsConfig,
21
23
  getSubAgents
22
- } from "./chunk-GVPUUKKE.js";
24
+ } from "./chunk-FI6ZG2YP.js";
23
25
  import {
24
26
  __name
25
27
  } from "./chunk-7QVYU63E.js";
@@ -117,7 +119,8 @@ var AgentWarningCode = {
117
119
  FILTER_METADATA_ONLY: "THEO_AGENT_FILTER_METADATA_ONLY",
118
120
  BUDGET_TOP_LEVEL_METADATA_ONLY: "THEO_AGENT_BUDGET_TOP_LEVEL_METADATA_ONLY",
119
121
  CONTEXT_STRATEGY_METADATA_ONLY: "THEO_AGENT_CONTEXT_STRATEGY_METADATA_ONLY",
120
- PROJECT_CONTEXT_KNOB_METADATA_ONLY: "THEO_AGENT_PROJECT_CONTEXT_KNOB_METADATA_ONLY"
122
+ PROJECT_CONTEXT_KNOB_METADATA_ONLY: "THEO_AGENT_PROJECT_CONTEXT_KNOB_METADATA_ONLY",
123
+ CHECKPOINT_STORAGE_METADATA_ONLY: "THEO_AGENT_CHECKPOINT_STORAGE_METADATA_ONLY"
121
124
  };
122
125
  var reflectorInstance = new Reflector();
123
126
  function walkToolbox(ToolboxClass) {
@@ -145,7 +148,8 @@ function walkToolbox(ToolboxClass) {
145
148
  capabilities: void 0,
146
149
  budget: void 0,
147
150
  trace: traceVal ?? false,
148
- audit: auditVal ?? false
151
+ audit: auditVal ?? false,
152
+ hitl: getHumanInTheLoopConfig(ToolboxClass, propertyKey)
149
153
  };
150
154
  });
151
155
  return {
@@ -171,6 +175,12 @@ function warnUnmappedDecoratorKnobs(agentName, contextWindow, projectContext) {
171
175
  }
172
176
  }
173
177
  __name(warnUnmappedDecoratorKnobs, "warnUnmappedDecoratorKnobs");
178
+ function warnNonDurableCheckpoint(agentName, checkpoint) {
179
+ if (checkpoint && checkpoint.storage !== "filesystem") {
180
+ console.warn(`[${AgentWarningCode.CHECKPOINT_STORAGE_METADATA_ONLY}] Agent ${agentName}: @Checkpoint({ storage: '${checkpoint.storage ?? "memory"}' }) does NOT resume across requests \u2014 only 'filesystem' selects the SDK's durable conversation store. Use @Checkpoint({ storage: 'filesystem' }) for cross-request resume.`);
181
+ }
182
+ }
183
+ __name(warnNonDurableCheckpoint, "warnNonDurableCheckpoint");
174
184
  var agentWalkCache = /* @__PURE__ */ new WeakMap();
175
185
  function walkAgentMetadata(AgentClass, toolboxClasses = []) {
176
186
  if (toolboxClasses.length === 0) {
@@ -208,6 +218,8 @@ function walkAgentMetadata(AgentClass, toolboxClasses = []) {
208
218
  const projectContext = getProjectContextConfig(AgentClass);
209
219
  warnUnmappedDecoratorKnobs(AgentClass.name, contextWindow, projectContext);
210
220
  const compaction = getCompactionConfig(AgentClass);
221
+ const checkpoint = getCheckpointConfig(AgentClass);
222
+ warnNonDurableCheckpoint(AgentClass.name, checkpoint);
211
223
  const result = {
212
224
  agentConfig,
213
225
  mainLoop,
@@ -223,7 +235,8 @@ function walkAgentMetadata(AgentClass, toolboxClasses = []) {
223
235
  contextWindow,
224
236
  projectContext,
225
237
  mcpServers,
226
- compaction
238
+ compaction,
239
+ checkpoint
227
240
  };
228
241
  if (toolboxClasses.length === 0) {
229
242
  agentWalkCache.set(AgentClass, result);
@@ -258,6 +271,22 @@ function compileSkills(options) {
258
271
  __name(compileSkills, "compileSkills");
259
272
 
260
273
  // src/bridge/agent-compiler.ts
274
+ function toolRuntimeName(namespace, toolName) {
275
+ return namespace ? `${namespace}.${toolName}` : toolName;
276
+ }
277
+ __name(toolRuntimeName, "toolRuntimeName");
278
+ function compileHitlGates(toolboxes) {
279
+ const gates = /* @__PURE__ */ new Map();
280
+ for (const tb of toolboxes) {
281
+ for (const tool of tb.tools) {
282
+ if (tool.hitl) {
283
+ gates.set(toolRuntimeName(tb.namespace, tool.config.name), tool.hitl);
284
+ }
285
+ }
286
+ }
287
+ return gates;
288
+ }
289
+ __name(compileHitlGates, "compileHitlGates");
261
290
  function compileTools(toolboxes, toolboxInstances) {
262
291
  const tools = [];
263
292
  for (const tb of toolboxes) {
@@ -270,7 +299,7 @@ function compileTools(toolboxes, toolboxInstances) {
270
299
  if (typeof handler !== "function") {
271
300
  throw new Error(`[@theokit/agents] Toolbox ${tb.class.name}: '${String(tool.propertyKey)}' is not a function.`);
272
301
  }
273
- const name = tb.namespace ? `${tb.namespace}.${tool.config.name}` : tool.config.name;
302
+ const name = toolRuntimeName(tb.namespace, tool.config.name);
274
303
  tools.push({
275
304
  name,
276
305
  description: tool.config.description,
@@ -298,6 +327,7 @@ __name(compileSubAgents, "compileSubAgents");
298
327
  function compileAgent(walkResult, toolboxInstances = /* @__PURE__ */ new Map()) {
299
328
  const tools = compileTools(walkResult.toolboxes, toolboxInstances);
300
329
  const agents = compileSubAgents(walkResult.subAgentClasses);
330
+ const hitl = compileHitlGates(walkResult.toolboxes);
301
331
  return {
302
332
  model: walkResult.agentConfig.model,
303
333
  reasoningEffort: walkResult.agentConfig.reasoningEffort,
@@ -314,7 +344,9 @@ function compileAgent(walkResult, toolboxInstances = /* @__PURE__ */ new Map())
314
344
  mcpServers: walkResult.mcpServers,
315
345
  maxIterations: walkResult.mainLoop.maxIterations ?? walkResult.agentConfig.maxIterations,
316
346
  timeoutMs: walkResult.mainLoop.timeoutMs ?? walkResult.agentConfig.timeoutMs,
317
- stream: walkResult.agentConfig.stream ?? true
347
+ stream: walkResult.agentConfig.stream ?? true,
348
+ hitl: hitl.size > 0 ? hitl : void 0,
349
+ checkpoint: walkResult.checkpoint
318
350
  };
319
351
  }
320
352
  __name(compileAgent, "compileAgent");
@@ -940,6 +972,25 @@ function buildExtraCreateOptions(overrides, compiled) {
940
972
  return extra;
941
973
  }
942
974
  __name(buildExtraCreateOptions, "buildExtraCreateOptions");
975
+ async function loadSdkRuntime() {
976
+ try {
977
+ const sdk = await import("@theokit/sdk");
978
+ const InMemory = sdk.InMemoryConversationStorage;
979
+ return {
980
+ Agent: sdk.Agent,
981
+ defineTool: sdk.defineTool,
982
+ InMemoryConversationStorage: InMemory,
983
+ FileSystemConversationStorage: "FileSystemConversationStorage" in sdk ? sdk.FileSystemConversationStorage : InMemory
984
+ };
985
+ } catch {
986
+ return null;
987
+ }
988
+ }
989
+ __name(loadSdkRuntime, "loadSdkRuntime");
990
+ function newConversationStorage(compiled, InMemory, FileSystem) {
991
+ return compiled.checkpoint?.storage === "filesystem" ? new FileSystem() : new InMemory();
992
+ }
993
+ __name(newConversationStorage, "newConversationStorage");
943
994
  function createAsyncQueue() {
944
995
  const items = [];
945
996
  let wake = null;
@@ -1069,14 +1120,18 @@ function applyTextTransforms(events, opts) {
1069
1120
  return out;
1070
1121
  }
1071
1122
  __name(applyTextTransforms, "applyTextTransforms");
1123
+ function hasZodInputSchema(schema) {
1124
+ return typeof schema?.parse === "function";
1125
+ }
1126
+ __name(hasZodInputSchema, "hasZodInputSchema");
1072
1127
  function buildSdkTools(compiledTools, defineTool, extraSdkTools = []) {
1073
1128
  return [
1074
- ...compiledTools.map((t) => defineTool({
1129
+ ...compiledTools.map((t) => hasZodInputSchema(t.inputSchema) ? defineTool({
1075
1130
  name: t.name,
1076
1131
  description: t.description,
1077
1132
  inputSchema: t.inputSchema,
1078
1133
  handler: t.handler
1079
- })),
1134
+ }) : t),
1080
1135
  ...extraSdkTools
1081
1136
  ];
1082
1137
  }
@@ -1090,15 +1145,8 @@ function createSdkAgentStream(compiled, compiledTools, apiKey, overrides = {}) {
1090
1145
  async *[Symbol.asyncIterator]() {
1091
1146
  const runId = `run-${Date.now()}`;
1092
1147
  const t0 = Date.now();
1093
- let Agent;
1094
- let defineTool;
1095
- let InMemoryConversationStorage;
1096
- try {
1097
- const sdk = await import("@theokit/sdk");
1098
- Agent = sdk.Agent;
1099
- defineTool = sdk.defineTool;
1100
- InMemoryConversationStorage = sdk.InMemoryConversationStorage;
1101
- } catch {
1148
+ const rt = await loadSdkRuntime();
1149
+ if (!rt) {
1102
1150
  yield {
1103
1151
  type: "error",
1104
1152
  code: "SDK_NOT_INSTALLED",
@@ -1107,6 +1155,7 @@ function createSdkAgentStream(compiled, compiledTools, apiKey, overrides = {}) {
1107
1155
  };
1108
1156
  return;
1109
1157
  }
1158
+ const { Agent, defineTool, InMemoryConversationStorage, FileSystemConversationStorage } = rt;
1110
1159
  const sdkTools = buildSdkTools(compiledTools, defineTool, overrides.sdkTools);
1111
1160
  let agent;
1112
1161
  try {
@@ -1116,7 +1165,7 @@ function createSdkAgentStream(compiled, compiledTools, apiKey, overrides = {}) {
1116
1165
  cwd: overrides.cwd
1117
1166
  };
1118
1167
  const extra = buildExtraCreateOptions(overrides, compiled);
1119
- storage ??= new InMemoryConversationStorage();
1168
+ storage ??= newConversationStorage(compiled, InMemoryConversationStorage, FileSystemConversationStorage);
1120
1169
  if (applied.length > 0) {
1121
1170
  console.debug("[THEO_AGENT_M8_RUNTIME_APPLIED]", {
1122
1171
  skills: applied.includes("skills"),
@@ -1220,6 +1269,36 @@ function* emitToolResult(event, seen) {
1220
1269
  }
1221
1270
  }
1222
1271
  __name(emitToolResult, "emitToolResult");
1272
+ function* emitApprovalRequest(event, seen) {
1273
+ if (!seen.has(event.callId)) {
1274
+ seen.add(event.callId);
1275
+ yield {
1276
+ type: "tool-input-available",
1277
+ toolCallId: event.callId,
1278
+ toolName: event.toolName,
1279
+ input: event.input ?? {},
1280
+ dynamic: true
1281
+ };
1282
+ }
1283
+ yield {
1284
+ type: "tool-approval-request",
1285
+ approvalId: event.callId,
1286
+ toolCallId: event.callId
1287
+ };
1288
+ }
1289
+ __name(emitApprovalRequest, "emitApprovalRequest");
1290
+ function* emitCheckpointSaved(event) {
1291
+ yield {
1292
+ type: "data-checkpoint",
1293
+ data: {
1294
+ checkpointId: event.checkpointId,
1295
+ resumeToken: event.resumeToken,
1296
+ step: event.step
1297
+ },
1298
+ transient: true
1299
+ };
1300
+ }
1301
+ __name(emitCheckpointSaved, "emitCheckpointSaved");
1223
1302
  async function* translateToUIMessageStream(events, opts) {
1224
1303
  yield {
1225
1304
  type: "start"
@@ -1265,9 +1344,15 @@ async function* translateToUIMessageStream(events, opts) {
1265
1344
  } else if (event.type === "tool_call") {
1266
1345
  yield* closeOpenBlock(state, opts.textId);
1267
1346
  yield* emitToolCall(event, seenToolCallIds);
1347
+ } else if (event.type === "approval_required") {
1348
+ yield* closeOpenBlock(state, opts.textId);
1349
+ yield* emitApprovalRequest(event, seenToolCallIds);
1268
1350
  } else if (event.type === "tool_result") {
1269
1351
  yield* closeOpenBlock(state, opts.textId);
1270
1352
  yield* emitToolResult(event, seenToolCallIds);
1353
+ } else if (event.type === "checkpoint_saved") {
1354
+ yield* closeOpenBlock(state, opts.textId);
1355
+ yield* emitCheckpointSaved(event);
1271
1356
  } else if (event.type === "error") {
1272
1357
  yield {
1273
1358
  type: "error",
@@ -1316,6 +1401,35 @@ function compileAgentDefinition(def) {
1316
1401
  }
1317
1402
  __name(compileAgentDefinition, "compileAgentDefinition");
1318
1403
 
1404
+ // src/bridge/hitl-plugin.ts
1405
+ function createHitlPlugin(wiring) {
1406
+ return {
1407
+ name: "theokit-hitl",
1408
+ register(ctx) {
1409
+ ctx.on("pre_tool_call", async (c) => {
1410
+ const opts = wiring.gated.get(c.name);
1411
+ if (!opts) return void 0;
1412
+ const approvalId = crypto.randomUUID();
1413
+ wiring.emit({
1414
+ type: "approval_required",
1415
+ callId: approvalId,
1416
+ toolName: c.name,
1417
+ question: opts.question,
1418
+ input: c.args,
1419
+ callbackUrl: `approve/${approvalId}`,
1420
+ timeoutMs: opts.timeout ?? 3e5
1421
+ });
1422
+ const approved = await wiring.awaitApproval(approvalId, opts);
1423
+ return approved ? void 0 : {
1424
+ block: true,
1425
+ message: `Tool '${c.name}' denied by human approver`
1426
+ };
1427
+ });
1428
+ }
1429
+ };
1430
+ }
1431
+ __name(createHitlPlugin, "createHitlPlugin");
1432
+
1319
1433
  // src/bridge/agent-endpoint.ts
1320
1434
  var AgentDefinitionError = class extends Error {
1321
1435
  static {
@@ -1339,7 +1453,12 @@ function compileAgentModule(mod, source = "agent module") {
1339
1453
  return compileAgentDefinition(def);
1340
1454
  }
1341
1455
  if (typeof def === "function" && getAgentConfig(def) !== void 0) {
1342
- return compileAgent(walkAgentMetadata(def));
1456
+ const walk = walkAgentMetadata(def, getMixins(def));
1457
+ const instances = /* @__PURE__ */ new Map();
1458
+ for (const tb of walk.toolboxes) {
1459
+ instances.set(tb.class, new tb.class());
1460
+ }
1461
+ return compileAgent(walk, instances);
1343
1462
  }
1344
1463
  throw new AgentDefinitionError(source);
1345
1464
  }
@@ -1348,10 +1467,106 @@ async function* asAgentStream(events) {
1348
1467
  for await (const e of events) yield e;
1349
1468
  }
1350
1469
  __name(asAgentStream, "asAgentStream");
1470
+ var EventQueue = class EventQueue2 {
1471
+ static {
1472
+ __name(this, "EventQueue");
1473
+ }
1474
+ #items = [];
1475
+ #resolvers = [];
1476
+ #closed = false;
1477
+ push(item) {
1478
+ if (this.#closed) return;
1479
+ const r = this.#resolvers.shift();
1480
+ if (r) r({
1481
+ value: item,
1482
+ done: false
1483
+ });
1484
+ else this.#items.push(item);
1485
+ }
1486
+ close() {
1487
+ this.#closed = true;
1488
+ for (const r of this.#resolvers.splice(0)) r({
1489
+ value: void 0,
1490
+ done: true
1491
+ });
1492
+ }
1493
+ async *drain() {
1494
+ for (; ; ) {
1495
+ if (this.#items.length > 0) {
1496
+ yield this.#items.shift();
1497
+ continue;
1498
+ }
1499
+ if (this.#closed) return;
1500
+ const next = await new Promise((resolve) => this.#resolvers.push(resolve));
1501
+ if (next.done) return;
1502
+ yield next.value;
1503
+ }
1504
+ }
1505
+ };
1506
+ async function* appendCheckpointSaved(source, sessionId) {
1507
+ let emitted = false;
1508
+ const checkpoint = /* @__PURE__ */ __name(() => ({
1509
+ type: "checkpoint_saved",
1510
+ checkpointId: crypto.randomUUID(),
1511
+ step: 0,
1512
+ resumeToken: sessionId
1513
+ }), "checkpoint");
1514
+ for await (const ev of source) {
1515
+ if (ev.type === "done" && !emitted) {
1516
+ emitted = true;
1517
+ yield checkpoint();
1518
+ }
1519
+ yield ev;
1520
+ }
1521
+ if (!emitted) yield checkpoint();
1522
+ }
1523
+ __name(appendCheckpointSaved, "appendCheckpointSaved");
1351
1524
  function streamAgentUIMessages(compiled, apiKey, input) {
1352
- const events = createSdkAgentStream(compiled, compiled.tools, apiKey)(input.message, input.sessionId);
1353
- return translateToUIMessageStream(asAgentStream(events), {
1354
- textId: crypto.randomUUID()
1525
+ const textId = crypto.randomUUID();
1526
+ const overrides = {};
1527
+ if (input.conversationStorage) overrides.conversationStorage = input.conversationStorage;
1528
+ let source;
1529
+ if (!input.hitl || input.hitl.gated.size === 0) {
1530
+ const events2 = createSdkAgentStream(compiled, compiled.tools, apiKey, overrides)(input.message, input.sessionId);
1531
+ source = asAgentStream(events2);
1532
+ } else {
1533
+ const queue = new EventQueue();
1534
+ input.signal?.addEventListener("abort", () => queue.close(), {
1535
+ once: true
1536
+ });
1537
+ const plugin = createHitlPlugin({
1538
+ gated: input.hitl.gated,
1539
+ emit: /* @__PURE__ */ __name((e) => queue.push(e), "emit"),
1540
+ awaitApproval: input.hitl.awaitApproval
1541
+ });
1542
+ const sdkStream = createSdkAgentStream(compiled, compiled.tools, apiKey, {
1543
+ ...overrides,
1544
+ // The HITL plugin is a structural @theokit/sdk Plugin (createHitlPlugin returns the
1545
+ // { name, register } shape); the RuntimeOverrides.plugins union is widened at the SDK edge.
1546
+ plugins: [
1547
+ plugin
1548
+ ]
1549
+ })(input.message, input.sessionId);
1550
+ void (async () => {
1551
+ try {
1552
+ for await (const e of sdkStream) queue.push(e);
1553
+ } catch (err) {
1554
+ queue.push({
1555
+ type: "error",
1556
+ code: "SDK_STREAM_ERROR",
1557
+ message: err instanceof Error ? err.message : String(err),
1558
+ retryable: false
1559
+ });
1560
+ } finally {
1561
+ queue.close();
1562
+ }
1563
+ })();
1564
+ source = queue.drain();
1565
+ }
1566
+ const durableCheckpoint = compiled.checkpoint?.storage === "filesystem";
1567
+ const events = durableCheckpoint ? appendCheckpointSaved(source, input.sessionId) : source;
1568
+ return translateToUIMessageStream(events, {
1569
+ textId
1355
1570
  });
1356
1571
  }
1357
1572
  __name(streamAgentUIMessages, "streamAgentUIMessages");
@@ -2101,4 +2316,4 @@ export {
2101
2316
  generateAgentManifest,
2102
2317
  agentsPlugin
2103
2318
  };
2104
- //# sourceMappingURL=chunk-4AN6LDJS.js.map
2319
+ //# sourceMappingURL=chunk-XCQNYAVU.js.map