omk-agent-core 0.98.4 → 0.99.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.99.0] - 2026-09-13
6
+
7
+ ## [0.98.5] - 2026-09-12
8
+
9
+ ### Fixed
10
+
11
+ - Tool timeout text distinguishes cancellation requested from termination observed. The teardown grace period uses a monotonic clock rather than wall-clock time.
12
+
5
13
  ## [0.98.4] - 2026-09-10
6
14
 
7
15
  ### Added
@@ -1 +1 @@
1
- {"version":3,"file":"tool-execution-boundary.d.ts","sourceRoot":"","sources":["../src/tool-execution-boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,KAAK,EACX,YAAY,EACZ,eAAe,EACf,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEvG,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAExF,+EAA+E;AAC/E,wBAAsB,cAAc,CAAC,CAAC,EACrC,KAAK,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAC3B,MAAM,EAAE,WAAW,GAAG,SAAS,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAiB9B;AAED,MAAM,WAAW,uBAAuB;IACvC,GAAG,EAAE,kBAAkB,CAAC;CACxB;AAwBD,uEAAuE;AACvE,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC,uBAAuB,CAAC,CAarH;AAED,qEAAqE;AACrE,wBAAgB,uBAAuB,CAAC,gBAAgB,EAAE,OAAO,GAAG,eAAe,CAAC,uBAAuB,CAAC,CAY3G;AAED,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,sBAAsB,CAAC;IAC7C,oBAAoB,EAAE,MAAM,OAAO,CAAC;IACpC,cAAc,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACxC,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,UAAU,uBAAuB;IAChC,cAAc,EAAE,YAAY,CAAC;IAC7B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,QAAQ,EAAE;QAAE,QAAQ,EAAE,aAAa,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,QAAQ,EAAE,uBAAuB,CAAC;IAClC,aAAa,EAAE,eAAe,CAAC,eAAe,CAAC,CAAC;IAChD,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;CAChC;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAE/E;AAED,6FAA6F;AAC7F,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CA8FlH;AAQD,gFAAgF;AAChF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAO/F","sourcesContent":["import type { AssistantMessage } from \"omk-ai\";\nimport { createImmutableSnapshot } from \"./plain-data.ts\";\nimport type {\n\tAgentContext,\n\tAgentLoopConfig,\n\tAgentToolCall,\n\tAgentToolResult,\n\tToolResultEnvelope,\n\tToolTimeoutDisposition,\n} from \"./types.ts\";\nimport { createToolResultEnvelope, isToolResultEnvelope } from \"./types.ts\";\n\nexport { createImmutableJsonSnapshot, createImmutableSnapshot, parseJsonValue } from \"./plain-data.ts\";\n\nexport type AbortBoundResult<T> = { kind: \"completed\"; value: T } | { kind: \"aborted\" };\n\n/** Race one async extension boundary against the parent run's abort signal. */\nexport async function awaitWithAbort<T>(\n\tstart: () => Promise<T> | T,\n\tsignal: AbortSignal | undefined,\n): Promise<AbortBoundResult<T>> {\n\tif (signal?.aborted) return { kind: \"aborted\" };\n\tif (signal === undefined) return { kind: \"completed\", value: await start() };\n\n\tlet notifyAbort: (() => void) | undefined;\n\tconst aborted = new Promise<AbortBoundResult<T>>((resolve) => {\n\t\tnotifyAbort = () => resolve({ kind: \"aborted\" });\n\t\tsignal.addEventListener(\"abort\", notifyAbort, { once: true });\n\t});\n\tif (signal.aborted) notifyAbort?.();\n\n\ttry {\n\t\tconst operation = Promise.resolve(start()).then((value): AbortBoundResult<T> => ({ kind: \"completed\", value }));\n\t\treturn await Promise.race([operation, aborted]);\n\t} finally {\n\t\tif (notifyAbort !== undefined) signal.removeEventListener(\"abort\", notifyAbort);\n\t}\n}\n\nexport interface ToolDispositionEnvelope {\n\tomk: ToolResultEnvelope;\n}\n\nfunction createValidatedToolResultSnapshot(result: AgentToolResult<unknown>): AgentToolResult<unknown> {\n\tconst snapshot = createImmutableSnapshot(result);\n\tif (!Array.isArray(snapshot.content)) throw new TypeError(\"Tool result content must be an array\");\n\tfor (const block of snapshot.content) {\n\t\tif (typeof block !== \"object\" || block === null) throw new TypeError(\"Invalid tool result content block\");\n\t\tconst type = Reflect.get(block, \"type\");\n\t\tif (type === \"text\" && typeof Reflect.get(block, \"text\") === \"string\") continue;\n\t\tif (\n\t\t\ttype === \"image\" &&\n\t\t\ttypeof Reflect.get(block, \"data\") === \"string\" &&\n\t\t\ttypeof Reflect.get(block, \"mimeType\") === \"string\"\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tthrow new TypeError(\"Invalid tool result content block\");\n\t}\n\tif (snapshot.terminate !== undefined && typeof snapshot.terminate !== \"boolean\") {\n\t\tthrow new TypeError(\"Tool result terminate must be a boolean\");\n\t}\n\treturn snapshot;\n}\n\n/** Build the immutable terminal committed when a tool timeout wins. */\nexport function createTimeoutToolResult(toolName: string, timeoutMs: number): AgentToolResult<ToolDispositionEnvelope> {\n\treturn createImmutableSnapshot({\n\t\tcontent: [{ type: \"text\", text: `Tool \"${toolName}\" timed out after ${timeoutMs}ms and was terminated.` }],\n\t\tdetails: {\n\t\t\tomk: createToolResultEnvelope({\n\t\t\t\tsynthetic: true,\n\t\t\t\tdisposition: \"timeout\",\n\t\t\t\treason: `Tool \"${toolName}\" timed out after ${timeoutMs}ms`,\n\t\t\t\ttimeoutMs,\n\t\t\t\texecutionStarted: true,\n\t\t\t}),\n\t\t},\n\t});\n}\n\n/** Build the immutable terminal committed when parent abort wins. */\nexport function createAbortedToolResult(executionStarted: boolean): AgentToolResult<ToolDispositionEnvelope> {\n\treturn createImmutableSnapshot({\n\t\tcontent: [{ type: \"text\", text: \"Operation aborted\" }],\n\t\tdetails: {\n\t\t\tomk: createToolResultEnvelope({\n\t\t\t\tsynthetic: true,\n\t\t\t\tdisposition: \"aborted\",\n\t\t\t\treason: \"Operation aborted\",\n\t\t\t\texecutionStarted,\n\t\t\t}),\n\t\t},\n\t});\n}\n\nexport interface ExecutedToolCallOutcome {\n\tresult: AgentToolResult<unknown>;\n\tisError: boolean;\n\texecutionStarted: boolean;\n\tterminalDisposition?: ToolTimeoutDisposition;\n\tisRealPromiseSettled: () => boolean;\n\tcommitTerminal: () => void;\n}\n\nexport interface FinalizedToolCallOutcome {\n\ttoolCall: AgentToolCall;\n\tresult: AgentToolResult<unknown>;\n\tisError: boolean;\n\tenvelope: ToolResultEnvelope;\n\tisRealPromiseSettled?: () => boolean;\n\tcommitTerminal?: () => void;\n}\n\ninterface FinalizeToolCallOptions {\n\tcurrentContext: AgentContext;\n\tassistantMessage: AssistantMessage;\n\tprepared: { toolCall: AgentToolCall; args: unknown; timeoutMs: number };\n\texecuted: ExecutedToolCallOutcome;\n\tafterToolCall: AgentLoopConfig[\"afterToolCall\"];\n\tsignal: AbortSignal | undefined;\n}\n\nexport function createErrorToolResult(message: string): AgentToolResult<unknown> {\n\treturn createImmutableSnapshot({ content: [{ type: \"text\", text: message }], details: {} });\n}\n\n/** Commit a real result or immutable timeout/abort result across the after hook boundary. */\nexport async function finalizeExecutedToolCall(options: FinalizeToolCallOptions): Promise<FinalizedToolCallOutcome> {\n\tconst { currentContext, assistantMessage, prepared, executed, afterToolCall, signal } = options;\n\tlet result = executed.result;\n\tlet isError = executed.isError;\n\tlet syntheticFailure = false;\n\tlet terminalDisposition = executed.terminalDisposition;\n\n\ttry {\n\t\tresult = createValidatedToolResultSnapshot(result);\n\t} catch (error) {\n\t\tresult = createErrorToolResult(`Invalid tool result: ${error instanceof Error ? error.message : String(error)}`);\n\t\tisError = true;\n\t\tsyntheticFailure = true;\n\t}\n\n\tif (terminalDisposition === undefined && signal?.aborted) {\n\t\tterminalDisposition = \"aborted\";\n\t\tresult = createAbortedToolResult(executed.executionStarted);\n\t\tisError = true;\n\t}\n\tif (terminalDisposition === undefined && afterToolCall && !syntheticFailure) {\n\t\ttry {\n\t\t\tconst bounded = await awaitWithAbort(\n\t\t\t\t() =>\n\t\t\t\t\tafterToolCall(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tassistantMessage,\n\t\t\t\t\t\t\ttoolCall: prepared.toolCall,\n\t\t\t\t\t\t\targs: prepared.args,\n\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\tisError,\n\t\t\t\t\t\t\tcontext: currentContext,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tif (bounded.kind === \"aborted\" || signal?.aborted) {\n\t\t\t\tterminalDisposition = \"aborted\";\n\t\t\t\tresult = createAbortedToolResult(executed.executionStarted);\n\t\t\t\tisError = true;\n\t\t\t} else if (bounded.value) {\n\t\t\t\tresult = {\n\t\t\t\t\tcontent: bounded.value.content ?? result.content,\n\t\t\t\t\tdetails: Object.hasOwn(bounded.value, \"details\") ? bounded.value.details : result.details,\n\t\t\t\t\tterminate: bounded.value.terminate ?? result.terminate,\n\t\t\t\t};\n\t\t\t\tisError = bounded.value.isError ?? isError;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tresult = createErrorToolResult(error instanceof Error ? error.message : String(error));\n\t\t\tisError = true;\n\t\t\tsyntheticFailure = true;\n\t\t}\n\t}\n\n\tif (terminalDisposition === undefined) {\n\t\ttry {\n\t\t\tresult = createValidatedToolResultSnapshot(result);\n\t\t} catch (error) {\n\t\t\tresult = createErrorToolResult(\n\t\t\t\t`Invalid tool result: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\tisError = true;\n\t\t\tsyntheticFailure = true;\n\t\t}\n\t} else {\n\t\tisError = true;\n\t}\n\tconst envelope =\n\t\tterminalDisposition !== undefined\n\t\t\t? createToolResultEnvelope({\n\t\t\t\t\tdisposition: terminalDisposition,\n\t\t\t\t\tsynthetic: true,\n\t\t\t\t\texecutionStarted: executed.executionStarted,\n\t\t\t\t\treason:\n\t\t\t\t\t\tterminalDisposition === \"timeout\"\n\t\t\t\t\t\t\t? `Tool \"${prepared.toolCall.name}\" timed out after ${prepared.timeoutMs}ms`\n\t\t\t\t\t\t\t: \"Operation aborted\",\n\t\t\t\t\t...(terminalDisposition === \"timeout\" ? { timeoutMs: prepared.timeoutMs } : {}),\n\t\t\t\t})\n\t\t\t: createToolResultEnvelope({\n\t\t\t\t\tdisposition: isError ? \"failed\" : \"completed\",\n\t\t\t\t\tsynthetic: syntheticFailure,\n\t\t\t\t\texecutionStarted: executed.executionStarted,\n\t\t\t\t});\n\treturn {\n\t\ttoolCall: prepared.toolCall,\n\t\tresult,\n\t\tisError,\n\t\tenvelope,\n\t\tisRealPromiseSettled: executed.isRealPromiseSettled,\n\t\tcommitTerminal: executed.commitTerminal,\n\t};\n}\n\nfunction isPlainDetails(details: unknown): details is Record<string, unknown> {\n\tif (typeof details !== \"object\" || details === null || Array.isArray(details)) return false;\n\tconst prototype = Object.getPrototypeOf(details);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\n/** Preserve compatibility details while replacing any untrusted `omk` field. */\nexport function stampToolResultEnvelope(details: unknown, envelope: ToolResultEnvelope): unknown {\n\tif (!isToolResultEnvelope(envelope)) throw new TypeError(\"Refusing to persist an invalid tool-result/v2 envelope\");\n\tif (details === undefined) return { omk: envelope };\n\tif (!isPlainDetails(details)) return { originalDetails: details, omk: envelope };\n\tconst preserved = { ...details };\n\tdelete preserved.omk;\n\treturn { ...preserved, omk: envelope };\n}\n"]}
1
+ {"version":3,"file":"tool-execution-boundary.d.ts","sourceRoot":"","sources":["../src/tool-execution-boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,KAAK,EACX,YAAY,EACZ,eAAe,EACf,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEvG,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAExF,+EAA+E;AAC/E,wBAAsB,cAAc,CAAC,CAAC,EACrC,KAAK,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAC3B,MAAM,EAAE,WAAW,GAAG,SAAS,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAiB9B;AAED,MAAM,WAAW,uBAAuB;IACvC,GAAG,EAAE,kBAAkB,CAAC;CACxB;AAwBD,uEAAuE;AACvE,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC,uBAAuB,CAAC,CAkBrH;AAED,qEAAqE;AACrE,wBAAgB,uBAAuB,CAAC,gBAAgB,EAAE,OAAO,GAAG,eAAe,CAAC,uBAAuB,CAAC,CAY3G;AAED,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,sBAAsB,CAAC;IAC7C,oBAAoB,EAAE,MAAM,OAAO,CAAC;IACpC,cAAc,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACxC,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,UAAU,uBAAuB;IAChC,cAAc,EAAE,YAAY,CAAC;IAC7B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,QAAQ,EAAE;QAAE,QAAQ,EAAE,aAAa,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,QAAQ,EAAE,uBAAuB,CAAC;IAClC,aAAa,EAAE,eAAe,CAAC,eAAe,CAAC,CAAC;IAChD,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;CAChC;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAE/E;AAED,6FAA6F;AAC7F,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CA8FlH;AAQD,gFAAgF;AAChF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAO/F","sourcesContent":["import type { AssistantMessage } from \"omk-ai\";\nimport { createImmutableSnapshot } from \"./plain-data.ts\";\nimport type {\n\tAgentContext,\n\tAgentLoopConfig,\n\tAgentToolCall,\n\tAgentToolResult,\n\tToolResultEnvelope,\n\tToolTimeoutDisposition,\n} from \"./types.ts\";\nimport { createToolResultEnvelope, isToolResultEnvelope } from \"./types.ts\";\n\nexport { createImmutableJsonSnapshot, createImmutableSnapshot, parseJsonValue } from \"./plain-data.ts\";\n\nexport type AbortBoundResult<T> = { kind: \"completed\"; value: T } | { kind: \"aborted\" };\n\n/** Race one async extension boundary against the parent run's abort signal. */\nexport async function awaitWithAbort<T>(\n\tstart: () => Promise<T> | T,\n\tsignal: AbortSignal | undefined,\n): Promise<AbortBoundResult<T>> {\n\tif (signal?.aborted) return { kind: \"aborted\" };\n\tif (signal === undefined) return { kind: \"completed\", value: await start() };\n\n\tlet notifyAbort: (() => void) | undefined;\n\tconst aborted = new Promise<AbortBoundResult<T>>((resolve) => {\n\t\tnotifyAbort = () => resolve({ kind: \"aborted\" });\n\t\tsignal.addEventListener(\"abort\", notifyAbort, { once: true });\n\t});\n\tif (signal.aborted) notifyAbort?.();\n\n\ttry {\n\t\tconst operation = Promise.resolve(start()).then((value): AbortBoundResult<T> => ({ kind: \"completed\", value }));\n\t\treturn await Promise.race([operation, aborted]);\n\t} finally {\n\t\tif (notifyAbort !== undefined) signal.removeEventListener(\"abort\", notifyAbort);\n\t}\n}\n\nexport interface ToolDispositionEnvelope {\n\tomk: ToolResultEnvelope;\n}\n\nfunction createValidatedToolResultSnapshot(result: AgentToolResult<unknown>): AgentToolResult<unknown> {\n\tconst snapshot = createImmutableSnapshot(result);\n\tif (!Array.isArray(snapshot.content)) throw new TypeError(\"Tool result content must be an array\");\n\tfor (const block of snapshot.content) {\n\t\tif (typeof block !== \"object\" || block === null) throw new TypeError(\"Invalid tool result content block\");\n\t\tconst type = Reflect.get(block, \"type\");\n\t\tif (type === \"text\" && typeof Reflect.get(block, \"text\") === \"string\") continue;\n\t\tif (\n\t\t\ttype === \"image\" &&\n\t\t\ttypeof Reflect.get(block, \"data\") === \"string\" &&\n\t\t\ttypeof Reflect.get(block, \"mimeType\") === \"string\"\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tthrow new TypeError(\"Invalid tool result content block\");\n\t}\n\tif (snapshot.terminate !== undefined && typeof snapshot.terminate !== \"boolean\") {\n\t\tthrow new TypeError(\"Tool result terminate must be a boolean\");\n\t}\n\treturn snapshot;\n}\n\n/** Build the immutable terminal committed when a tool timeout wins. */\nexport function createTimeoutToolResult(toolName: string, timeoutMs: number): AgentToolResult<ToolDispositionEnvelope> {\n\treturn createImmutableSnapshot({\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `Tool \"${toolName}\" timed out after ${timeoutMs}ms. Cancellation was requested; execution may still be running.`,\n\t\t\t},\n\t\t],\n\t\tdetails: {\n\t\t\tomk: createToolResultEnvelope({\n\t\t\t\tsynthetic: true,\n\t\t\t\tdisposition: \"timeout\",\n\t\t\t\treason: `Tool \"${toolName}\" timed out after ${timeoutMs}ms`,\n\t\t\t\ttimeoutMs,\n\t\t\t\texecutionStarted: true,\n\t\t\t}),\n\t\t},\n\t});\n}\n\n/** Build the immutable terminal committed when parent abort wins. */\nexport function createAbortedToolResult(executionStarted: boolean): AgentToolResult<ToolDispositionEnvelope> {\n\treturn createImmutableSnapshot({\n\t\tcontent: [{ type: \"text\", text: \"Operation aborted\" }],\n\t\tdetails: {\n\t\t\tomk: createToolResultEnvelope({\n\t\t\t\tsynthetic: true,\n\t\t\t\tdisposition: \"aborted\",\n\t\t\t\treason: \"Operation aborted\",\n\t\t\t\texecutionStarted,\n\t\t\t}),\n\t\t},\n\t});\n}\n\nexport interface ExecutedToolCallOutcome {\n\tresult: AgentToolResult<unknown>;\n\tisError: boolean;\n\texecutionStarted: boolean;\n\tterminalDisposition?: ToolTimeoutDisposition;\n\tisRealPromiseSettled: () => boolean;\n\tcommitTerminal: () => void;\n}\n\nexport interface FinalizedToolCallOutcome {\n\ttoolCall: AgentToolCall;\n\tresult: AgentToolResult<unknown>;\n\tisError: boolean;\n\tenvelope: ToolResultEnvelope;\n\tisRealPromiseSettled?: () => boolean;\n\tcommitTerminal?: () => void;\n}\n\ninterface FinalizeToolCallOptions {\n\tcurrentContext: AgentContext;\n\tassistantMessage: AssistantMessage;\n\tprepared: { toolCall: AgentToolCall; args: unknown; timeoutMs: number };\n\texecuted: ExecutedToolCallOutcome;\n\tafterToolCall: AgentLoopConfig[\"afterToolCall\"];\n\tsignal: AbortSignal | undefined;\n}\n\nexport function createErrorToolResult(message: string): AgentToolResult<unknown> {\n\treturn createImmutableSnapshot({ content: [{ type: \"text\", text: message }], details: {} });\n}\n\n/** Commit a real result or immutable timeout/abort result across the after hook boundary. */\nexport async function finalizeExecutedToolCall(options: FinalizeToolCallOptions): Promise<FinalizedToolCallOutcome> {\n\tconst { currentContext, assistantMessage, prepared, executed, afterToolCall, signal } = options;\n\tlet result = executed.result;\n\tlet isError = executed.isError;\n\tlet syntheticFailure = false;\n\tlet terminalDisposition = executed.terminalDisposition;\n\n\ttry {\n\t\tresult = createValidatedToolResultSnapshot(result);\n\t} catch (error) {\n\t\tresult = createErrorToolResult(`Invalid tool result: ${error instanceof Error ? error.message : String(error)}`);\n\t\tisError = true;\n\t\tsyntheticFailure = true;\n\t}\n\n\tif (terminalDisposition === undefined && signal?.aborted) {\n\t\tterminalDisposition = \"aborted\";\n\t\tresult = createAbortedToolResult(executed.executionStarted);\n\t\tisError = true;\n\t}\n\tif (terminalDisposition === undefined && afterToolCall && !syntheticFailure) {\n\t\ttry {\n\t\t\tconst bounded = await awaitWithAbort(\n\t\t\t\t() =>\n\t\t\t\t\tafterToolCall(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tassistantMessage,\n\t\t\t\t\t\t\ttoolCall: prepared.toolCall,\n\t\t\t\t\t\t\targs: prepared.args,\n\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\tisError,\n\t\t\t\t\t\t\tcontext: currentContext,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tif (bounded.kind === \"aborted\" || signal?.aborted) {\n\t\t\t\tterminalDisposition = \"aborted\";\n\t\t\t\tresult = createAbortedToolResult(executed.executionStarted);\n\t\t\t\tisError = true;\n\t\t\t} else if (bounded.value) {\n\t\t\t\tresult = {\n\t\t\t\t\tcontent: bounded.value.content ?? result.content,\n\t\t\t\t\tdetails: Object.hasOwn(bounded.value, \"details\") ? bounded.value.details : result.details,\n\t\t\t\t\tterminate: bounded.value.terminate ?? result.terminate,\n\t\t\t\t};\n\t\t\t\tisError = bounded.value.isError ?? isError;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tresult = createErrorToolResult(error instanceof Error ? error.message : String(error));\n\t\t\tisError = true;\n\t\t\tsyntheticFailure = true;\n\t\t}\n\t}\n\n\tif (terminalDisposition === undefined) {\n\t\ttry {\n\t\t\tresult = createValidatedToolResultSnapshot(result);\n\t\t} catch (error) {\n\t\t\tresult = createErrorToolResult(\n\t\t\t\t`Invalid tool result: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\tisError = true;\n\t\t\tsyntheticFailure = true;\n\t\t}\n\t} else {\n\t\tisError = true;\n\t}\n\tconst envelope =\n\t\tterminalDisposition !== undefined\n\t\t\t? createToolResultEnvelope({\n\t\t\t\t\tdisposition: terminalDisposition,\n\t\t\t\t\tsynthetic: true,\n\t\t\t\t\texecutionStarted: executed.executionStarted,\n\t\t\t\t\treason:\n\t\t\t\t\t\tterminalDisposition === \"timeout\"\n\t\t\t\t\t\t\t? `Tool \"${prepared.toolCall.name}\" timed out after ${prepared.timeoutMs}ms`\n\t\t\t\t\t\t\t: \"Operation aborted\",\n\t\t\t\t\t...(terminalDisposition === \"timeout\" ? { timeoutMs: prepared.timeoutMs } : {}),\n\t\t\t\t})\n\t\t\t: createToolResultEnvelope({\n\t\t\t\t\tdisposition: isError ? \"failed\" : \"completed\",\n\t\t\t\t\tsynthetic: syntheticFailure,\n\t\t\t\t\texecutionStarted: executed.executionStarted,\n\t\t\t\t});\n\treturn {\n\t\ttoolCall: prepared.toolCall,\n\t\tresult,\n\t\tisError,\n\t\tenvelope,\n\t\tisRealPromiseSettled: executed.isRealPromiseSettled,\n\t\tcommitTerminal: executed.commitTerminal,\n\t};\n}\n\nfunction isPlainDetails(details: unknown): details is Record<string, unknown> {\n\tif (typeof details !== \"object\" || details === null || Array.isArray(details)) return false;\n\tconst prototype = Object.getPrototypeOf(details);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\n/** Preserve compatibility details while replacing any untrusted `omk` field. */\nexport function stampToolResultEnvelope(details: unknown, envelope: ToolResultEnvelope): unknown {\n\tif (!isToolResultEnvelope(envelope)) throw new TypeError(\"Refusing to persist an invalid tool-result/v2 envelope\");\n\tif (details === undefined) return { omk: envelope };\n\tif (!isPlainDetails(details)) return { originalDetails: details, omk: envelope };\n\tconst preserved = { ...details };\n\tdelete preserved.omk;\n\treturn { ...preserved, omk: envelope };\n}\n"]}
@@ -48,7 +48,12 @@ function createValidatedToolResultSnapshot(result) {
48
48
  /** Build the immutable terminal committed when a tool timeout wins. */
49
49
  export function createTimeoutToolResult(toolName, timeoutMs) {
50
50
  return createImmutableSnapshot({
51
- content: [{ type: "text", text: `Tool "${toolName}" timed out after ${timeoutMs}ms and was terminated.` }],
51
+ content: [
52
+ {
53
+ type: "text",
54
+ text: `Tool "${toolName}" timed out after ${timeoutMs}ms. Cancellation was requested; execution may still be running.`,
55
+ },
56
+ ],
52
57
  details: {
53
58
  omk: createToolResultEnvelope({
54
59
  synthetic: true,
@@ -1 +1 @@
1
- {"version":3,"file":"tool-execution-boundary.js","sourceRoot":"","sources":["../src/tool-execution-boundary.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAS1D,OAAO,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIvG,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,cAAc,CACnC,KAA2B,EAC3B,MAA+B,EACA;IAC/B,IAAI,MAAM,EAAE,OAAO;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAChD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,KAAK,EAAE,EAAE,CAAC;IAE7E,IAAI,WAAqC,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAsB,CAAC,OAAO,EAAE,EAAE,CAAC;QAC7D,WAAW,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAAA,CAC9D,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,OAAO;QAAE,WAAW,EAAE,EAAE,CAAC;IAEpC,IAAI,CAAC;QACJ,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAuB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAChH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;YAAS,CAAC;QACV,IAAI,WAAW,KAAK,SAAS;YAAE,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACjF,CAAC;AAAA,CACD;AAMD,SAAS,iCAAiC,CAAC,MAAgC,EAA4B;IACtG,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAC;IAClG,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,MAAM,IAAI,SAAS,CAAC,mCAAmC,CAAC,CAAC;QAC1G,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACxC,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,QAAQ;YAAE,SAAS;QAChF,IACC,IAAI,KAAK,OAAO;YAChB,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,QAAQ;YAC9C,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,QAAQ,EACjD,CAAC;YACF,SAAS;QACV,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,mCAAmC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjF,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB;AAED,uEAAuE;AACvE,MAAM,UAAU,uBAAuB,CAAC,QAAgB,EAAE,SAAiB,EAA4C;IACtH,OAAO,uBAAuB,CAAC;QAC9B,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,QAAQ,qBAAqB,SAAS,wBAAwB,EAAE,CAAC;QAC1G,OAAO,EAAE;YACR,GAAG,EAAE,wBAAwB,CAAC;gBAC7B,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,SAAS;gBACtB,MAAM,EAAE,SAAS,QAAQ,qBAAqB,SAAS,IAAI;gBAC3D,SAAS;gBACT,gBAAgB,EAAE,IAAI;aACtB,CAAC;SACF;KACD,CAAC,CAAC;AAAA,CACH;AAED,qEAAqE;AACrE,MAAM,UAAU,uBAAuB,CAAC,gBAAyB,EAA4C;IAC5G,OAAO,uBAAuB,CAAC;QAC9B,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;QACtD,OAAO,EAAE;YACR,GAAG,EAAE,wBAAwB,CAAC;gBAC7B,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,SAAS;gBACtB,MAAM,EAAE,mBAAmB;gBAC3B,gBAAgB;aAChB,CAAC;SACF;KACD,CAAC,CAAC;AAAA,CACH;AA6BD,MAAM,UAAU,qBAAqB,CAAC,OAAe,EAA4B;IAChF,OAAO,uBAAuB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;AAAA,CAC5F;AAED,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAgC,EAAqC;IACnH,MAAM,EAAE,cAAc,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAChG,IAAI,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC7B,IAAI,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;IAC/B,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,IAAI,mBAAmB,GAAG,QAAQ,CAAC,mBAAmB,CAAC;IAEvD,IAAI,CAAC;QACJ,MAAM,GAAG,iCAAiC,CAAC,MAAM,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,GAAG,qBAAqB,CAAC,wBAAwB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjH,OAAO,GAAG,IAAI,CAAC;QACf,gBAAgB,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,IAAI,mBAAmB,KAAK,SAAS,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QAC1D,mBAAmB,GAAG,SAAS,CAAC;QAChC,MAAM,GAAG,uBAAuB,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QAC5D,OAAO,GAAG,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,mBAAmB,KAAK,SAAS,IAAI,aAAa,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC7E,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,MAAM,cAAc,CACnC,GAAG,EAAE,CACJ,aAAa,CACZ;gBACC,gBAAgB;gBAChB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,MAAM;gBACN,OAAO;gBACP,OAAO,EAAE,cAAc;aACvB,EACD,MAAM,CACN,EACF,MAAM,CACN,CAAC;YACF,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;gBACnD,mBAAmB,GAAG,SAAS,CAAC;gBAChC,MAAM,GAAG,uBAAuB,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;gBAC5D,OAAO,GAAG,IAAI,CAAC;YAChB,CAAC;iBAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC1B,MAAM,GAAG;oBACR,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO;oBAChD,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO;oBACzF,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS;iBACtD,CAAC;gBACF,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,IAAI,OAAO,CAAC;YAC5C,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,GAAG,qBAAqB,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACvF,OAAO,GAAG,IAAI,CAAC;YACf,gBAAgB,GAAG,IAAI,CAAC;QACzB,CAAC;IACF,CAAC;IAED,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;QACvC,IAAI,CAAC;YACJ,MAAM,GAAG,iCAAiC,CAAC,MAAM,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,GAAG,qBAAqB,CAC7B,wBAAwB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAChF,CAAC;YACF,OAAO,GAAG,IAAI,CAAC;YACf,gBAAgB,GAAG,IAAI,CAAC;QACzB,CAAC;IACF,CAAC;SAAM,CAAC;QACP,OAAO,GAAG,IAAI,CAAC;IAChB,CAAC;IACD,MAAM,QAAQ,GACb,mBAAmB,KAAK,SAAS;QAChC,CAAC,CAAC,wBAAwB,CAAC;YACzB,WAAW,EAAE,mBAAmB;YAChC,SAAS,EAAE,IAAI;YACf,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;YAC3C,MAAM,EACL,mBAAmB,KAAK,SAAS;gBAChC,CAAC,CAAC,SAAS,QAAQ,CAAC,QAAQ,CAAC,IAAI,qBAAqB,QAAQ,CAAC,SAAS,IAAI;gBAC5E,CAAC,CAAC,mBAAmB;YACvB,GAAG,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/E,CAAC;QACH,CAAC,CAAC,wBAAwB,CAAC;YACzB,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW;YAC7C,SAAS,EAAE,gBAAgB;YAC3B,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;SAC3C,CAAC,CAAC;IACN,OAAO;QACN,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,MAAM;QACN,OAAO;QACP,QAAQ;QACR,oBAAoB,EAAE,QAAQ,CAAC,oBAAoB;QACnD,cAAc,EAAE,QAAQ,CAAC,cAAc;KACvC,CAAC;AAAA,CACF;AAED,SAAS,cAAc,CAAC,OAAgB,EAAsC;IAC7E,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5F,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO,SAAS,KAAK,MAAM,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI,CAAC;AAAA,CAC5D;AAED,gFAAgF;AAChF,MAAM,UAAU,uBAAuB,CAAC,OAAgB,EAAE,QAA4B,EAAW;IAChG,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,wDAAwD,CAAC,CAAC;IACnH,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;IACpD,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;IACjF,MAAM,SAAS,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IACjC,OAAO,SAAS,CAAC,GAAG,CAAC;IACrB,OAAO,EAAE,GAAG,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;AAAA,CACvC","sourcesContent":["import type { AssistantMessage } from \"omk-ai\";\nimport { createImmutableSnapshot } from \"./plain-data.ts\";\nimport type {\n\tAgentContext,\n\tAgentLoopConfig,\n\tAgentToolCall,\n\tAgentToolResult,\n\tToolResultEnvelope,\n\tToolTimeoutDisposition,\n} from \"./types.ts\";\nimport { createToolResultEnvelope, isToolResultEnvelope } from \"./types.ts\";\n\nexport { createImmutableJsonSnapshot, createImmutableSnapshot, parseJsonValue } from \"./plain-data.ts\";\n\nexport type AbortBoundResult<T> = { kind: \"completed\"; value: T } | { kind: \"aborted\" };\n\n/** Race one async extension boundary against the parent run's abort signal. */\nexport async function awaitWithAbort<T>(\n\tstart: () => Promise<T> | T,\n\tsignal: AbortSignal | undefined,\n): Promise<AbortBoundResult<T>> {\n\tif (signal?.aborted) return { kind: \"aborted\" };\n\tif (signal === undefined) return { kind: \"completed\", value: await start() };\n\n\tlet notifyAbort: (() => void) | undefined;\n\tconst aborted = new Promise<AbortBoundResult<T>>((resolve) => {\n\t\tnotifyAbort = () => resolve({ kind: \"aborted\" });\n\t\tsignal.addEventListener(\"abort\", notifyAbort, { once: true });\n\t});\n\tif (signal.aborted) notifyAbort?.();\n\n\ttry {\n\t\tconst operation = Promise.resolve(start()).then((value): AbortBoundResult<T> => ({ kind: \"completed\", value }));\n\t\treturn await Promise.race([operation, aborted]);\n\t} finally {\n\t\tif (notifyAbort !== undefined) signal.removeEventListener(\"abort\", notifyAbort);\n\t}\n}\n\nexport interface ToolDispositionEnvelope {\n\tomk: ToolResultEnvelope;\n}\n\nfunction createValidatedToolResultSnapshot(result: AgentToolResult<unknown>): AgentToolResult<unknown> {\n\tconst snapshot = createImmutableSnapshot(result);\n\tif (!Array.isArray(snapshot.content)) throw new TypeError(\"Tool result content must be an array\");\n\tfor (const block of snapshot.content) {\n\t\tif (typeof block !== \"object\" || block === null) throw new TypeError(\"Invalid tool result content block\");\n\t\tconst type = Reflect.get(block, \"type\");\n\t\tif (type === \"text\" && typeof Reflect.get(block, \"text\") === \"string\") continue;\n\t\tif (\n\t\t\ttype === \"image\" &&\n\t\t\ttypeof Reflect.get(block, \"data\") === \"string\" &&\n\t\t\ttypeof Reflect.get(block, \"mimeType\") === \"string\"\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tthrow new TypeError(\"Invalid tool result content block\");\n\t}\n\tif (snapshot.terminate !== undefined && typeof snapshot.terminate !== \"boolean\") {\n\t\tthrow new TypeError(\"Tool result terminate must be a boolean\");\n\t}\n\treturn snapshot;\n}\n\n/** Build the immutable terminal committed when a tool timeout wins. */\nexport function createTimeoutToolResult(toolName: string, timeoutMs: number): AgentToolResult<ToolDispositionEnvelope> {\n\treturn createImmutableSnapshot({\n\t\tcontent: [{ type: \"text\", text: `Tool \"${toolName}\" timed out after ${timeoutMs}ms and was terminated.` }],\n\t\tdetails: {\n\t\t\tomk: createToolResultEnvelope({\n\t\t\t\tsynthetic: true,\n\t\t\t\tdisposition: \"timeout\",\n\t\t\t\treason: `Tool \"${toolName}\" timed out after ${timeoutMs}ms`,\n\t\t\t\ttimeoutMs,\n\t\t\t\texecutionStarted: true,\n\t\t\t}),\n\t\t},\n\t});\n}\n\n/** Build the immutable terminal committed when parent abort wins. */\nexport function createAbortedToolResult(executionStarted: boolean): AgentToolResult<ToolDispositionEnvelope> {\n\treturn createImmutableSnapshot({\n\t\tcontent: [{ type: \"text\", text: \"Operation aborted\" }],\n\t\tdetails: {\n\t\t\tomk: createToolResultEnvelope({\n\t\t\t\tsynthetic: true,\n\t\t\t\tdisposition: \"aborted\",\n\t\t\t\treason: \"Operation aborted\",\n\t\t\t\texecutionStarted,\n\t\t\t}),\n\t\t},\n\t});\n}\n\nexport interface ExecutedToolCallOutcome {\n\tresult: AgentToolResult<unknown>;\n\tisError: boolean;\n\texecutionStarted: boolean;\n\tterminalDisposition?: ToolTimeoutDisposition;\n\tisRealPromiseSettled: () => boolean;\n\tcommitTerminal: () => void;\n}\n\nexport interface FinalizedToolCallOutcome {\n\ttoolCall: AgentToolCall;\n\tresult: AgentToolResult<unknown>;\n\tisError: boolean;\n\tenvelope: ToolResultEnvelope;\n\tisRealPromiseSettled?: () => boolean;\n\tcommitTerminal?: () => void;\n}\n\ninterface FinalizeToolCallOptions {\n\tcurrentContext: AgentContext;\n\tassistantMessage: AssistantMessage;\n\tprepared: { toolCall: AgentToolCall; args: unknown; timeoutMs: number };\n\texecuted: ExecutedToolCallOutcome;\n\tafterToolCall: AgentLoopConfig[\"afterToolCall\"];\n\tsignal: AbortSignal | undefined;\n}\n\nexport function createErrorToolResult(message: string): AgentToolResult<unknown> {\n\treturn createImmutableSnapshot({ content: [{ type: \"text\", text: message }], details: {} });\n}\n\n/** Commit a real result or immutable timeout/abort result across the after hook boundary. */\nexport async function finalizeExecutedToolCall(options: FinalizeToolCallOptions): Promise<FinalizedToolCallOutcome> {\n\tconst { currentContext, assistantMessage, prepared, executed, afterToolCall, signal } = options;\n\tlet result = executed.result;\n\tlet isError = executed.isError;\n\tlet syntheticFailure = false;\n\tlet terminalDisposition = executed.terminalDisposition;\n\n\ttry {\n\t\tresult = createValidatedToolResultSnapshot(result);\n\t} catch (error) {\n\t\tresult = createErrorToolResult(`Invalid tool result: ${error instanceof Error ? error.message : String(error)}`);\n\t\tisError = true;\n\t\tsyntheticFailure = true;\n\t}\n\n\tif (terminalDisposition === undefined && signal?.aborted) {\n\t\tterminalDisposition = \"aborted\";\n\t\tresult = createAbortedToolResult(executed.executionStarted);\n\t\tisError = true;\n\t}\n\tif (terminalDisposition === undefined && afterToolCall && !syntheticFailure) {\n\t\ttry {\n\t\t\tconst bounded = await awaitWithAbort(\n\t\t\t\t() =>\n\t\t\t\t\tafterToolCall(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tassistantMessage,\n\t\t\t\t\t\t\ttoolCall: prepared.toolCall,\n\t\t\t\t\t\t\targs: prepared.args,\n\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\tisError,\n\t\t\t\t\t\t\tcontext: currentContext,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tif (bounded.kind === \"aborted\" || signal?.aborted) {\n\t\t\t\tterminalDisposition = \"aborted\";\n\t\t\t\tresult = createAbortedToolResult(executed.executionStarted);\n\t\t\t\tisError = true;\n\t\t\t} else if (bounded.value) {\n\t\t\t\tresult = {\n\t\t\t\t\tcontent: bounded.value.content ?? result.content,\n\t\t\t\t\tdetails: Object.hasOwn(bounded.value, \"details\") ? bounded.value.details : result.details,\n\t\t\t\t\tterminate: bounded.value.terminate ?? result.terminate,\n\t\t\t\t};\n\t\t\t\tisError = bounded.value.isError ?? isError;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tresult = createErrorToolResult(error instanceof Error ? error.message : String(error));\n\t\t\tisError = true;\n\t\t\tsyntheticFailure = true;\n\t\t}\n\t}\n\n\tif (terminalDisposition === undefined) {\n\t\ttry {\n\t\t\tresult = createValidatedToolResultSnapshot(result);\n\t\t} catch (error) {\n\t\t\tresult = createErrorToolResult(\n\t\t\t\t`Invalid tool result: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\tisError = true;\n\t\t\tsyntheticFailure = true;\n\t\t}\n\t} else {\n\t\tisError = true;\n\t}\n\tconst envelope =\n\t\tterminalDisposition !== undefined\n\t\t\t? createToolResultEnvelope({\n\t\t\t\t\tdisposition: terminalDisposition,\n\t\t\t\t\tsynthetic: true,\n\t\t\t\t\texecutionStarted: executed.executionStarted,\n\t\t\t\t\treason:\n\t\t\t\t\t\tterminalDisposition === \"timeout\"\n\t\t\t\t\t\t\t? `Tool \"${prepared.toolCall.name}\" timed out after ${prepared.timeoutMs}ms`\n\t\t\t\t\t\t\t: \"Operation aborted\",\n\t\t\t\t\t...(terminalDisposition === \"timeout\" ? { timeoutMs: prepared.timeoutMs } : {}),\n\t\t\t\t})\n\t\t\t: createToolResultEnvelope({\n\t\t\t\t\tdisposition: isError ? \"failed\" : \"completed\",\n\t\t\t\t\tsynthetic: syntheticFailure,\n\t\t\t\t\texecutionStarted: executed.executionStarted,\n\t\t\t\t});\n\treturn {\n\t\ttoolCall: prepared.toolCall,\n\t\tresult,\n\t\tisError,\n\t\tenvelope,\n\t\tisRealPromiseSettled: executed.isRealPromiseSettled,\n\t\tcommitTerminal: executed.commitTerminal,\n\t};\n}\n\nfunction isPlainDetails(details: unknown): details is Record<string, unknown> {\n\tif (typeof details !== \"object\" || details === null || Array.isArray(details)) return false;\n\tconst prototype = Object.getPrototypeOf(details);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\n/** Preserve compatibility details while replacing any untrusted `omk` field. */\nexport function stampToolResultEnvelope(details: unknown, envelope: ToolResultEnvelope): unknown {\n\tif (!isToolResultEnvelope(envelope)) throw new TypeError(\"Refusing to persist an invalid tool-result/v2 envelope\");\n\tif (details === undefined) return { omk: envelope };\n\tif (!isPlainDetails(details)) return { originalDetails: details, omk: envelope };\n\tconst preserved = { ...details };\n\tdelete preserved.omk;\n\treturn { ...preserved, omk: envelope };\n}\n"]}
1
+ {"version":3,"file":"tool-execution-boundary.js","sourceRoot":"","sources":["../src/tool-execution-boundary.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"omk-ai\";\nimport { createImmutableSnapshot } from \"./plain-data.ts\";\nimport type {\n\tAgentContext,\n\tAgentLoopConfig,\n\tAgentToolCall,\n\tAgentToolResult,\n\tToolResultEnvelope,\n\tToolTimeoutDisposition,\n} from \"./types.ts\";\nimport { createToolResultEnvelope, isToolResultEnvelope } from \"./types.ts\";\n\nexport { createImmutableJsonSnapshot, createImmutableSnapshot, parseJsonValue } from \"./plain-data.ts\";\n\nexport type AbortBoundResult<T> = { kind: \"completed\"; value: T } | { kind: \"aborted\" };\n\n/** Race one async extension boundary against the parent run's abort signal. */\nexport async function awaitWithAbort<T>(\n\tstart: () => Promise<T> | T,\n\tsignal: AbortSignal | undefined,\n): Promise<AbortBoundResult<T>> {\n\tif (signal?.aborted) return { kind: \"aborted\" };\n\tif (signal === undefined) return { kind: \"completed\", value: await start() };\n\n\tlet notifyAbort: (() => void) | undefined;\n\tconst aborted = new Promise<AbortBoundResult<T>>((resolve) => {\n\t\tnotifyAbort = () => resolve({ kind: \"aborted\" });\n\t\tsignal.addEventListener(\"abort\", notifyAbort, { once: true });\n\t});\n\tif (signal.aborted) notifyAbort?.();\n\n\ttry {\n\t\tconst operation = Promise.resolve(start()).then((value): AbortBoundResult<T> => ({ kind: \"completed\", value }));\n\t\treturn await Promise.race([operation, aborted]);\n\t} finally {\n\t\tif (notifyAbort !== undefined) signal.removeEventListener(\"abort\", notifyAbort);\n\t}\n}\n\nexport interface ToolDispositionEnvelope {\n\tomk: ToolResultEnvelope;\n}\n\nfunction createValidatedToolResultSnapshot(result: AgentToolResult<unknown>): AgentToolResult<unknown> {\n\tconst snapshot = createImmutableSnapshot(result);\n\tif (!Array.isArray(snapshot.content)) throw new TypeError(\"Tool result content must be an array\");\n\tfor (const block of snapshot.content) {\n\t\tif (typeof block !== \"object\" || block === null) throw new TypeError(\"Invalid tool result content block\");\n\t\tconst type = Reflect.get(block, \"type\");\n\t\tif (type === \"text\" && typeof Reflect.get(block, \"text\") === \"string\") continue;\n\t\tif (\n\t\t\ttype === \"image\" &&\n\t\t\ttypeof Reflect.get(block, \"data\") === \"string\" &&\n\t\t\ttypeof Reflect.get(block, \"mimeType\") === \"string\"\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tthrow new TypeError(\"Invalid tool result content block\");\n\t}\n\tif (snapshot.terminate !== undefined && typeof snapshot.terminate !== \"boolean\") {\n\t\tthrow new TypeError(\"Tool result terminate must be a boolean\");\n\t}\n\treturn snapshot;\n}\n\n/** Build the immutable terminal committed when a tool timeout wins. */\nexport function createTimeoutToolResult(toolName: string, timeoutMs: number): AgentToolResult<ToolDispositionEnvelope> {\n\treturn createImmutableSnapshot({\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `Tool \"${toolName}\" timed out after ${timeoutMs}ms. Cancellation was requested; execution may still be running.`,\n\t\t\t},\n\t\t],\n\t\tdetails: {\n\t\t\tomk: createToolResultEnvelope({\n\t\t\t\tsynthetic: true,\n\t\t\t\tdisposition: \"timeout\",\n\t\t\t\treason: `Tool \"${toolName}\" timed out after ${timeoutMs}ms`,\n\t\t\t\ttimeoutMs,\n\t\t\t\texecutionStarted: true,\n\t\t\t}),\n\t\t},\n\t});\n}\n\n/** Build the immutable terminal committed when parent abort wins. */\nexport function createAbortedToolResult(executionStarted: boolean): AgentToolResult<ToolDispositionEnvelope> {\n\treturn createImmutableSnapshot({\n\t\tcontent: [{ type: \"text\", text: \"Operation aborted\" }],\n\t\tdetails: {\n\t\t\tomk: createToolResultEnvelope({\n\t\t\t\tsynthetic: true,\n\t\t\t\tdisposition: \"aborted\",\n\t\t\t\treason: \"Operation aborted\",\n\t\t\t\texecutionStarted,\n\t\t\t}),\n\t\t},\n\t});\n}\n\nexport interface ExecutedToolCallOutcome {\n\tresult: AgentToolResult<unknown>;\n\tisError: boolean;\n\texecutionStarted: boolean;\n\tterminalDisposition?: ToolTimeoutDisposition;\n\tisRealPromiseSettled: () => boolean;\n\tcommitTerminal: () => void;\n}\n\nexport interface FinalizedToolCallOutcome {\n\ttoolCall: AgentToolCall;\n\tresult: AgentToolResult<unknown>;\n\tisError: boolean;\n\tenvelope: ToolResultEnvelope;\n\tisRealPromiseSettled?: () => boolean;\n\tcommitTerminal?: () => void;\n}\n\ninterface FinalizeToolCallOptions {\n\tcurrentContext: AgentContext;\n\tassistantMessage: AssistantMessage;\n\tprepared: { toolCall: AgentToolCall; args: unknown; timeoutMs: number };\n\texecuted: ExecutedToolCallOutcome;\n\tafterToolCall: AgentLoopConfig[\"afterToolCall\"];\n\tsignal: AbortSignal | undefined;\n}\n\nexport function createErrorToolResult(message: string): AgentToolResult<unknown> {\n\treturn createImmutableSnapshot({ content: [{ type: \"text\", text: message }], details: {} });\n}\n\n/** Commit a real result or immutable timeout/abort result across the after hook boundary. */\nexport async function finalizeExecutedToolCall(options: FinalizeToolCallOptions): Promise<FinalizedToolCallOutcome> {\n\tconst { currentContext, assistantMessage, prepared, executed, afterToolCall, signal } = options;\n\tlet result = executed.result;\n\tlet isError = executed.isError;\n\tlet syntheticFailure = false;\n\tlet terminalDisposition = executed.terminalDisposition;\n\n\ttry {\n\t\tresult = createValidatedToolResultSnapshot(result);\n\t} catch (error) {\n\t\tresult = createErrorToolResult(`Invalid tool result: ${error instanceof Error ? error.message : String(error)}`);\n\t\tisError = true;\n\t\tsyntheticFailure = true;\n\t}\n\n\tif (terminalDisposition === undefined && signal?.aborted) {\n\t\tterminalDisposition = \"aborted\";\n\t\tresult = createAbortedToolResult(executed.executionStarted);\n\t\tisError = true;\n\t}\n\tif (terminalDisposition === undefined && afterToolCall && !syntheticFailure) {\n\t\ttry {\n\t\t\tconst bounded = await awaitWithAbort(\n\t\t\t\t() =>\n\t\t\t\t\tafterToolCall(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tassistantMessage,\n\t\t\t\t\t\t\ttoolCall: prepared.toolCall,\n\t\t\t\t\t\t\targs: prepared.args,\n\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\tisError,\n\t\t\t\t\t\t\tcontext: currentContext,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tif (bounded.kind === \"aborted\" || signal?.aborted) {\n\t\t\t\tterminalDisposition = \"aborted\";\n\t\t\t\tresult = createAbortedToolResult(executed.executionStarted);\n\t\t\t\tisError = true;\n\t\t\t} else if (bounded.value) {\n\t\t\t\tresult = {\n\t\t\t\t\tcontent: bounded.value.content ?? result.content,\n\t\t\t\t\tdetails: Object.hasOwn(bounded.value, \"details\") ? bounded.value.details : result.details,\n\t\t\t\t\tterminate: bounded.value.terminate ?? result.terminate,\n\t\t\t\t};\n\t\t\t\tisError = bounded.value.isError ?? isError;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tresult = createErrorToolResult(error instanceof Error ? error.message : String(error));\n\t\t\tisError = true;\n\t\t\tsyntheticFailure = true;\n\t\t}\n\t}\n\n\tif (terminalDisposition === undefined) {\n\t\ttry {\n\t\t\tresult = createValidatedToolResultSnapshot(result);\n\t\t} catch (error) {\n\t\t\tresult = createErrorToolResult(\n\t\t\t\t`Invalid tool result: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\tisError = true;\n\t\t\tsyntheticFailure = true;\n\t\t}\n\t} else {\n\t\tisError = true;\n\t}\n\tconst envelope =\n\t\tterminalDisposition !== undefined\n\t\t\t? createToolResultEnvelope({\n\t\t\t\t\tdisposition: terminalDisposition,\n\t\t\t\t\tsynthetic: true,\n\t\t\t\t\texecutionStarted: executed.executionStarted,\n\t\t\t\t\treason:\n\t\t\t\t\t\tterminalDisposition === \"timeout\"\n\t\t\t\t\t\t\t? `Tool \"${prepared.toolCall.name}\" timed out after ${prepared.timeoutMs}ms`\n\t\t\t\t\t\t\t: \"Operation aborted\",\n\t\t\t\t\t...(terminalDisposition === \"timeout\" ? { timeoutMs: prepared.timeoutMs } : {}),\n\t\t\t\t})\n\t\t\t: createToolResultEnvelope({\n\t\t\t\t\tdisposition: isError ? \"failed\" : \"completed\",\n\t\t\t\t\tsynthetic: syntheticFailure,\n\t\t\t\t\texecutionStarted: executed.executionStarted,\n\t\t\t\t});\n\treturn {\n\t\ttoolCall: prepared.toolCall,\n\t\tresult,\n\t\tisError,\n\t\tenvelope,\n\t\tisRealPromiseSettled: executed.isRealPromiseSettled,\n\t\tcommitTerminal: executed.commitTerminal,\n\t};\n}\n\nfunction isPlainDetails(details: unknown): details is Record<string, unknown> {\n\tif (typeof details !== \"object\" || details === null || Array.isArray(details)) return false;\n\tconst prototype = Object.getPrototypeOf(details);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\n/** Preserve compatibility details while replacing any untrusted `omk` field. */\nexport function stampToolResultEnvelope(details: unknown, envelope: ToolResultEnvelope): unknown {\n\tif (!isToolResultEnvelope(envelope)) throw new TypeError(\"Refusing to persist an invalid tool-result/v2 envelope\");\n\tif (details === undefined) return { omk: envelope };\n\tif (!isPlainDetails(details)) return { originalDetails: details, omk: envelope };\n\tconst preserved = { ...details };\n\tdelete preserved.omk;\n\treturn { ...preserved, omk: envelope };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-timeout-settlement.d.ts","sourceRoot":"","sources":["../src/tool-timeout-settlement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAE7E,4EAA4E;AAC5E,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,mFAAmF;AACnF,wBAAsB,mBAAmB,CAAC,cAAc,EAAE,SAAS,wBAAwB,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ/G","sourcesContent":["import type { FinalizedToolCallOutcome } from \"./tool-execution-boundary.ts\";\n\n/** Bounded OS/event-loop teardown window paid only after a tool timeout. */\nexport const DEFAULT_TOOL_TEARDOWN_GRACE_MS = 250;\n\n/** Return true when a timed-out tool is still active after the teardown window. */\nexport async function hasUnsettledTimeout(finalizedCalls: readonly FinalizedToolCallOutcome[]): Promise<boolean> {\n\tconst stillRunning = () =>\n\t\tfinalizedCalls.some(\n\t\t\t(finalized) => finalized.envelope.disposition === \"timeout\" && finalized.isRealPromiseSettled?.() === false,\n\t\t);\n\tconst deadline = Date.now() + DEFAULT_TOOL_TEARDOWN_GRACE_MS;\n\twhile (Date.now() < deadline && stillRunning()) await new Promise((resolve) => setTimeout(resolve, 5));\n\treturn stillRunning();\n}\n"]}
1
+ {"version":3,"file":"tool-timeout-settlement.d.ts","sourceRoot":"","sources":["../src/tool-timeout-settlement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAE7E,4EAA4E;AAC5E,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,mFAAmF;AACnF,wBAAsB,mBAAmB,CAAC,cAAc,EAAE,SAAS,wBAAwB,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ/G","sourcesContent":["import type { FinalizedToolCallOutcome } from \"./tool-execution-boundary.ts\";\n\n/** Bounded OS/event-loop teardown window paid only after a tool timeout. */\nexport const DEFAULT_TOOL_TEARDOWN_GRACE_MS = 250;\n\n/** Return true when a timed-out tool is still active after the teardown window. */\nexport async function hasUnsettledTimeout(finalizedCalls: readonly FinalizedToolCallOutcome[]): Promise<boolean> {\n\tconst stillRunning = () =>\n\t\tfinalizedCalls.some(\n\t\t\t(finalized) => finalized.envelope.disposition === \"timeout\" && finalized.isRealPromiseSettled?.() === false,\n\t\t);\n\tconst deadline = performance.now() + DEFAULT_TOOL_TEARDOWN_GRACE_MS;\n\twhile (performance.now() < deadline && stillRunning()) await new Promise((resolve) => setTimeout(resolve, 5));\n\treturn stillRunning();\n}\n"]}
@@ -3,8 +3,8 @@ export const DEFAULT_TOOL_TEARDOWN_GRACE_MS = 250;
3
3
  /** Return true when a timed-out tool is still active after the teardown window. */
4
4
  export async function hasUnsettledTimeout(finalizedCalls) {
5
5
  const stillRunning = () => finalizedCalls.some((finalized) => finalized.envelope.disposition === "timeout" && finalized.isRealPromiseSettled?.() === false);
6
- const deadline = Date.now() + DEFAULT_TOOL_TEARDOWN_GRACE_MS;
7
- while (Date.now() < deadline && stillRunning())
6
+ const deadline = performance.now() + DEFAULT_TOOL_TEARDOWN_GRACE_MS;
7
+ while (performance.now() < deadline && stillRunning())
8
8
  await new Promise((resolve) => setTimeout(resolve, 5));
9
9
  return stillRunning();
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tool-timeout-settlement.js","sourceRoot":"","sources":["../src/tool-timeout-settlement.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAElD,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,cAAmD,EAAoB;IAChH,MAAM,YAAY,GAAG,GAAG,EAAE,CACzB,cAAc,CAAC,IAAI,CAClB,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,KAAK,SAAS,IAAI,SAAS,CAAC,oBAAoB,EAAE,EAAE,KAAK,KAAK,CAC3G,CAAC;IACH,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,8BAA8B,CAAC;IAC7D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,IAAI,YAAY,EAAE;QAAE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IACvG,OAAO,YAAY,EAAE,CAAC;AAAA,CACtB","sourcesContent":["import type { FinalizedToolCallOutcome } from \"./tool-execution-boundary.ts\";\n\n/** Bounded OS/event-loop teardown window paid only after a tool timeout. */\nexport const DEFAULT_TOOL_TEARDOWN_GRACE_MS = 250;\n\n/** Return true when a timed-out tool is still active after the teardown window. */\nexport async function hasUnsettledTimeout(finalizedCalls: readonly FinalizedToolCallOutcome[]): Promise<boolean> {\n\tconst stillRunning = () =>\n\t\tfinalizedCalls.some(\n\t\t\t(finalized) => finalized.envelope.disposition === \"timeout\" && finalized.isRealPromiseSettled?.() === false,\n\t\t);\n\tconst deadline = Date.now() + DEFAULT_TOOL_TEARDOWN_GRACE_MS;\n\twhile (Date.now() < deadline && stillRunning()) await new Promise((resolve) => setTimeout(resolve, 5));\n\treturn stillRunning();\n}\n"]}
1
+ {"version":3,"file":"tool-timeout-settlement.js","sourceRoot":"","sources":["../src/tool-timeout-settlement.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAElD,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,cAAmD,EAAoB;IAChH,MAAM,YAAY,GAAG,GAAG,EAAE,CACzB,cAAc,CAAC,IAAI,CAClB,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,KAAK,SAAS,IAAI,SAAS,CAAC,oBAAoB,EAAE,EAAE,KAAK,KAAK,CAC3G,CAAC;IACH,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,8BAA8B,CAAC;IACpE,OAAO,WAAW,CAAC,GAAG,EAAE,GAAG,QAAQ,IAAI,YAAY,EAAE;QAAE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9G,OAAO,YAAY,EAAE,CAAC;AAAA,CACtB","sourcesContent":["import type { FinalizedToolCallOutcome } from \"./tool-execution-boundary.ts\";\n\n/** Bounded OS/event-loop teardown window paid only after a tool timeout. */\nexport const DEFAULT_TOOL_TEARDOWN_GRACE_MS = 250;\n\n/** Return true when a timed-out tool is still active after the teardown window. */\nexport async function hasUnsettledTimeout(finalizedCalls: readonly FinalizedToolCallOutcome[]): Promise<boolean> {\n\tconst stillRunning = () =>\n\t\tfinalizedCalls.some(\n\t\t\t(finalized) => finalized.envelope.disposition === \"timeout\" && finalized.isRealPromiseSettled?.() === false,\n\t\t);\n\tconst deadline = performance.now() + DEFAULT_TOOL_TEARDOWN_GRACE_MS;\n\twhile (performance.now() < deadline && stillRunning()) await new Promise((resolve) => setTimeout(resolve, 5));\n\treturn stillRunning();\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omk-agent-core",
3
- "version": "0.98.4",
3
+ "version": "0.99.0",
4
4
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,7 +30,7 @@
30
30
  "prepublishOnly": "npm run clean && npm run build"
31
31
  },
32
32
  "dependencies": {
33
- "omk-ai": "^0.98.4",
33
+ "omk-ai": "^0.99.0",
34
34
  "ignore": "7.0.6",
35
35
  "typebox": "1.3.11",
36
36
  "yaml": "2.9.0"