@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.
- package/LICENSE +201 -0
- package/dist/{bridge-entry-BlS01zM3.d.ts → bridge-entry-DVhOQc_f.d.ts} +71 -7
- package/dist/bridge.d.ts +2 -2
- package/dist/bridge.js +2 -2
- package/dist/{chunk-GVPUUKKE.js → chunk-FI6ZG2YP.js} +43 -1
- package/dist/chunk-FI6ZG2YP.js.map +1 -0
- package/dist/{chunk-SKTJS4QQ.js → chunk-K4MCMREI.js} +2 -44
- package/dist/chunk-K4MCMREI.js.map +1 -0
- package/dist/{chunk-4AN6LDJS.js → chunk-XCQNYAVU.js} +238 -23
- package/dist/chunk-XCQNYAVU.js.map +1 -0
- package/dist/decorators.d.ts +3 -43
- package/dist/decorators.js +6 -6
- package/dist/index.d.ts +5 -5
- package/dist/index.js +7 -7
- package/dist/{skills-FcUdNDbn.d.ts → skills-Dx_KJ6Eg.d.ts} +41 -1
- package/package.json +9 -9
- package/dist/chunk-4AN6LDJS.js.map +0 -1
- package/dist/chunk-GVPUUKKE.js.map +0 -1
- package/dist/chunk-SKTJS4QQ.js.map +0 -1
|
@@ -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-
|
|
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
|
|
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
|
-
|
|
1094
|
-
|
|
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 ??=
|
|
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
|
-
|
|
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
|
|
1353
|
-
|
|
1354
|
-
|
|
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-
|
|
2319
|
+
//# sourceMappingURL=chunk-XCQNYAVU.js.map
|