omk-agent-core 0.95.0 → 0.95.2
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/README.md +21 -6
- package/dist/agent-loop.d.ts +43 -0
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +374 -182
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent.d.ts +3 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +8 -0
- package/dist/agent.js.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -4
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAiiBA,uFAAuF;AACvF,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAyB,CAAC;AA0BrE,SAAS,eAAe,CAAC,KAAc,EAAoC;IAC1E,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAAA,CAC5E;AAED,+EAA+E;AAC/E,MAAM,UAAU,oBAAoB,CAAC,KAAc,EAA+B;IACjF,IACC,CAAC,eAAe,CAAC,KAAK,CAAC;QACvB,KAAK,CAAC,MAAM,KAAK,2BAA2B;QAC5C,OAAO,KAAK,CAAC,SAAS,KAAK,SAAS;QACpC,OAAO,KAAK,CAAC,gBAAgB,KAAK,SAAS;QAC3C,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC;QAChE,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS;YAC7B,CAAC,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,EACnG,CAAC;QACF,OAAO,KAAK,CAAC;IACd,CAAC;IAED,QAAQ,KAAK,CAAC,WAAW,EAAE,CAAC;QAC3B,KAAK,WAAW;YACf,OAAO,KAAK,CAAC,SAAS,KAAK,KAAK,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QAC7F,KAAK,QAAQ;YACZ,OAAO,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QACrF,KAAK,SAAS,CAAC;QACf,KAAK,SAAS;YACb,OAAO,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QACpF,KAAK,SAAS;YACb,OAAO,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QACzD,KAAK,SAAS;YACb,OAAO,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QACnF;YACC,OAAO,KAAK,CAAC;IACf,CAAC;AAAA,CACD;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAA8B,EAAsB;IAC5F,MAAM,QAAQ,GAAuB;QACpC,MAAM,EAAE,2BAA2B;QACnC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;QAC/D,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;QACxE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;KACxC,CAAC;IACF,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,SAAS,CAAC,WAAW,2BAA2B,IAAI,KAAK,CAAC,WAAW,WAAW,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAAA,CAC/B","sourcesContent":["import type {\n\tAssistantMessage,\n\tAssistantMessageEvent,\n\tImageContent,\n\tMessage,\n\tModel,\n\tSimpleStreamOptions,\n\tstreamSimple,\n\tTextContent,\n\tTool,\n\tToolResultMessage,\n} from \"omk-ai\";\nimport type { Static, TSchema } from \"typebox\";\n\n/**\n * Stream function used by the agent loop.\n *\n * Contract:\n * - Must not throw or return a rejected promise for request/model/runtime failures.\n * - Must return an AssistantMessageEventStream.\n * - Failures must be encoded in the returned stream via protocol events and a\n * final AssistantMessage with stopReason \"error\" or \"aborted\" and errorMessage.\n */\nexport type StreamFn = (\n\t...args: Parameters<typeof streamSimple>\n) => ReturnType<typeof streamSimple> | Promise<ReturnType<typeof streamSimple>>;\n\n/**\n * Configuration for how tool calls from a single assistant message are executed.\n *\n * - \"sequential\": each tool call is prepared, executed, and finalized before the next one starts.\n * - \"parallel\": tool calls are prepared sequentially, then allowed tools execute concurrently.\n * `tool_execution_end` is emitted in tool completion order after each tool is finalized,\n * while tool-result message artifacts are emitted later in assistant source order.\n */\nexport type ToolExecutionMode = \"sequential\" | \"parallel\";\n\n/**\n * Tool-call scheduler selection for a single assistant turn's tool batch.\n *\n * - `\"waves-v1\"` (default): the original contiguous-wave scheduler\n * (`partitionToolBatchWaves`). Established behavior and the rollback target.\n * - `\"dag-v2\"`: the deterministic resource-claim DAG scheduler\n * (`scheduleDagLevels`). Active only when explicitly selected. It resolves\n * per-call resource claims and groups conflict-free calls into source-index\n * DAG levels so a conflicting call no longer head-of-line-blocks independent\n * later calls (e.g. `write x, write x, write y` schedules as `[[0, 2], [1]]`).\n * Final tool results are buffered globally and emitted in original source\n * order.\n */\nexport type ToolSchedulerKind = \"waves-v1\" | \"dag-v2\";\n\n/**\n * Controls how many queued user messages are injected when the agent loop reaches a queue drain point.\n *\n * - \"all\": drain and inject every queued message at that point.\n * - \"one-at-a-time\": drain and inject only the oldest queued message, leaving the rest queued for later drain points.\n */\nexport type QueueMode = \"all\" | \"one-at-a-time\";\n\n/** A single tool call content block emitted by an assistant message. */\nexport type AgentToolCall = Extract<AssistantMessage[\"content\"][number], { type: \"toolCall\" }>;\n\n/**\n * Result returned from `beforeToolCall`.\n *\n * Returning `{ block: true }` prevents the tool from executing. The loop emits an error tool result instead.\n * `reason` becomes the text shown in that error result. If omitted, a default blocked message is used.\n */\nexport interface BeforeToolCallResult {\n\tblock?: boolean;\n\treason?: string;\n}\n\n/**\n * Partial override returned from `afterToolCall`.\n *\n * Merge semantics are field-by-field:\n * - `content`: if provided, replaces the tool result content array in full\n * - `details`: if provided, replaces the tool result details value in full\n * - `isError`: if provided, replaces the tool result error flag\n * - `terminate`: if provided, replaces the early-termination hint\n *\n * Omitted fields keep the original executed tool result values.\n * There is no deep merge for `content` or `details`.\n */\nexport interface AfterToolCallResult {\n\tcontent?: (TextContent | ImageContent)[];\n\tdetails?: unknown;\n\tisError?: boolean;\n\t/**\n\t * Hint that the agent should stop after the current tool batch.\n\t * Early termination only happens when every finalized tool result in the batch sets this to true.\n\t */\n\tterminate?: boolean;\n}\n\n/** Context passed to `beforeToolCall`. */\nexport interface BeforeToolCallContext {\n\t/** The assistant message that requested the tool call. */\n\tassistantMessage: AssistantMessage;\n\t/** The raw tool call block from `assistantMessage.content`. */\n\ttoolCall: AgentToolCall;\n\t/** Validated tool arguments for the target tool schema. */\n\targs: unknown;\n\t/** Current agent context at the time the tool call is prepared. */\n\tcontext: AgentContext;\n}\n\n/** Context passed to `afterToolCall`. */\nexport interface AfterToolCallContext {\n\t/** The assistant message that requested the tool call. */\n\tassistantMessage: AssistantMessage;\n\t/** The raw tool call block from `assistantMessage.content`. */\n\ttoolCall: AgentToolCall;\n\t/** Validated tool arguments for the target tool schema. */\n\targs: unknown;\n\t/** The executed tool result before any `afterToolCall` overrides are applied. */\n\tresult: AgentToolResult<any>;\n\t/** Whether the executed tool result is currently treated as an error. */\n\tisError: boolean;\n\t/** Current agent context at the time the tool call is finalized. */\n\tcontext: AgentContext;\n}\n\n/** Context passed to `shouldStopAfterTurn`. */\nexport interface ShouldStopAfterTurnContext {\n\t/** The assistant message that completed the turn. */\n\tmessage: AssistantMessage;\n\t/** Tool result messages passed to the preceding `turn_end` event. */\n\ttoolResults: ToolResultMessage[];\n\t/** Current agent context after the turn's assistant message and tool results have been appended. */\n\tcontext: AgentContext;\n\t/** Messages that this loop invocation will return if it exits at this point. Prompt runs include the initial prompt messages; continuation runs do not include pre-existing context messages. */\n\tnewMessages: AgentMessage[];\n}\n\n/** Replacement runtime state used by the agent loop before starting another provider request. */\nexport interface AgentLoopTurnUpdate {\n\t/** Context for the next provider request. */\n\tcontext?: AgentContext;\n\t/** Model for the next provider request. */\n\tmodel?: Model<any>;\n\t/** Thinking level for the next provider request. */\n\tthinkingLevel?: ThinkingLevel;\n}\n\nexport interface PrepareNextTurnContext extends ShouldStopAfterTurnContext {}\n\nexport interface AgentLoopConfig extends SimpleStreamOptions {\n\tmodel: Model<any>;\n\n\t/**\n\t * Converts AgentMessage[] to LLM-compatible Message[] before each LLM call.\n\t *\n\t * Each AgentMessage must be converted to a UserMessage, AssistantMessage, or ToolResultMessage\n\t * that the LLM can understand. AgentMessages that cannot be converted (e.g., UI-only notifications,\n\t * status messages) should be filtered out.\n\t *\n\t * Contract: must not throw or reject. Return a safe fallback value instead.\n\t * Throwing interrupts the low-level agent loop without producing a normal event sequence.\n\t *\n\t * @example\n\t * ```typescript\n\t * convertToLlm: (messages) => messages.flatMap(m => {\n\t * if (m.role === \"custom\") {\n\t * // Convert custom message to user message\n\t * return [{ role: \"user\", content: m.content, timestamp: m.timestamp }];\n\t * }\n\t * if (m.role === \"notification\") {\n\t * // Filter out UI-only messages\n\t * return [];\n\t * }\n\t * // Pass through standard LLM messages\n\t * return [m];\n\t * })\n\t * ```\n\t */\n\tconvertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\n\t/**\n\t * Optional transform applied to the context before `convertToLlm`.\n\t *\n\t * Use this for operations that work at the AgentMessage level:\n\t * - Context window management (pruning old messages)\n\t * - Injecting context from external sources\n\t *\n\t * Contract: must not throw or reject. Return the original messages or another\n\t * safe fallback value instead.\n\t *\n\t * @example\n\t * ```typescript\n\t * transformContext: async (messages) => {\n\t * if (estimateTokens(messages) > MAX_TOKENS) {\n\t * return pruneOldMessages(messages);\n\t * }\n\t * return messages;\n\t * }\n\t * ```\n\t */\n\ttransformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\n\t/**\n\t * Resolves an API key dynamically for each LLM call.\n\t *\n\t * Useful for short-lived OAuth tokens (e.g., GitHub Copilot) that may expire\n\t * during long-running tool execution phases.\n\t *\n\t * Contract: must not throw or reject. Return undefined when no key is available.\n\t */\n\tgetApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\n\t/**\n\t * Called after each turn fully completes and `turn_end` has been emitted.\n\t *\n\t * If it returns true, the loop emits `agent_end` and exits before polling steering or follow-up queues,\n\t * without starting another LLM call. The current assistant response and any tool executions finish normally.\n\t *\n\t * Use this to request a graceful stop after the current turn, e.g. before context gets too full.\n\t *\n\t * Contract: must not throw or reject. Throwing interrupts the low-level agent loop without producing a normal event sequence.\n\t */\n\tshouldStopAfterTurn?: (context: ShouldStopAfterTurnContext) => boolean | Promise<boolean>;\n\n\t/**\n\t * Called after `turn_end` and before the loop decides whether another provider request should start.\n\t * Return replacement context/model/thinking state to affect the next turn in this run.\n\t * Return undefined to keep using the current context/config.\n\t */\n\tprepareNextTurn?: (\n\t\tcontext: PrepareNextTurnContext,\n\t) => AgentLoopTurnUpdate | undefined | Promise<AgentLoopTurnUpdate | undefined>;\n\n\t/**\n\t * Returns steering messages to inject into the conversation mid-run.\n\t *\n\t * Called after the current assistant turn finishes executing its tool calls, unless `shouldStopAfterTurn` exits first.\n\t * If messages are returned, they are added to the context before the next LLM call.\n\t * Tool calls from the current assistant message are not skipped.\n\t *\n\t * Use this for \"steering\" the agent while it's working.\n\t *\n\t * Contract: must not throw or reject. Return [] when no steering messages are available.\n\t */\n\tgetSteeringMessages?: () => Promise<AgentMessage[]>;\n\n\t/**\n\t * Returns follow-up messages to process after the agent would otherwise stop.\n\t *\n\t * Called when the agent has no more tool calls and no steering messages.\n\t * If messages are returned, they're added to the context and the agent\n\t * continues with another turn.\n\t *\n\t * Use this for follow-up messages that should wait until the agent finishes.\n\t *\n\t * Contract: must not throw or reject. Return [] when no follow-up messages are available.\n\t */\n\tgetFollowUpMessages?: () => Promise<AgentMessage[]>;\n\n\t/**\n\t * Tool execution mode.\n\t * - \"sequential\": execute tool calls one by one\n\t * - \"parallel\": preflight tool calls sequentially, then execute allowed tools concurrently;\n\t * emit `tool_execution_end` in tool completion order after each tool is finalized,\n\t * then emit tool-result message artifacts later in assistant source order\n\t *\n\t * Default: \"parallel\"\n\t */\n\ttoolExecution?: ToolExecutionMode;\n\n\t/**\n\t * Default per-tool execution timeout in milliseconds applied to every tool\n\t * call that does not resolve a more specific timeout.\n\t *\n\t * This is deliberately named to avoid colliding with the inherited\n\t * {@link SimpleStreamOptions.timeoutMs} (the provider request timeout).\n\t * Absent, non-finite, or non-positive values disable the tool timeout and\n\t * preserve the current unbounded execution behavior.\n\t */\n\ttoolTimeoutMs?: number;\n\n\t/**\n\t * Per-tool-name execution timeouts in milliseconds. An entry here overrides\n\t * {@link toolTimeoutMs} for that tool name, and is itself overridden by a\n\t * per-tool {@link AgentTool.timeoutMs}. Absent, non-finite, or non-positive\n\t * entries disable the timeout for that name.\n\t */\n\ttoolTimeouts?: Record<string, number>;\n\n\t/**\n\t * Tool-call scheduler. Defaults to `\"waves-v1\"` (the established\n\t * contiguous-wave scheduler). Set to `\"dag-v2\"` to opt into the\n\t * deterministic resource-claim DAG scheduler. The v1 path and its exports\n\t * are unchanged when this is unset or `\"waves-v1\"`.\n\t */\n\ttoolScheduler?: ToolSchedulerKind;\n\n\t/**\n\t * dag-v2 only. Optional positive width cap. When set, each DAG level is\n\t * split into deterministic contiguous chunks of at most this many calls\n\t * (preserving source order) so a wide conflict-free level does not fan out\n\t * unbounded. Absent, non-finite, or non-positive values leave each level\n\t * whole. No effect on the default `\"waves-v1\"` scheduler.\n\t */\n\tmaxToolConcurrency?: number;\n\n\t/**\n\t * dag-v2 only. When `false` (default), an extension/custom tool with\n\t * `executionMode: \"parallel\"` and no resource claims is treated as freely\n\t * parallel (compatibility). When `true`, such tools are treated as\n\t * exclusive (run alone). Unknown tools and bash are always exclusive\n\t * regardless of this flag. No effect on the default `\"waves-v1\"` scheduler.\n\t */\n\tstrictExtensionClaims?: boolean;\n\n\t/** Working directory for path-scoped parallel tool batch checks (read/write/edit). */\n\tcwd?: string;\n\n\t/**\n\t * dag-v2 only. Optional platform identity resolver used to detect\n\t * symlink/hardlink/drive/UNC path aliases when scheduling resource claims.\n\t * Absent, the scheduler uses lexical canonicalization only (browser-safe).\n\t * Resolver failure isolates the call as exclusive (fail closed).\n\t */\n\tresourceKeyResolver?: ResourceKeyResolver;\n\n\t/**\n\t * Execution policy defaults for every tool call in this run. Only\n\t * `lateSettlement` is consumed today; it defaults to `\"audit\"`.\n\t */\n\ttoolExecutionPolicy?: Partial<ToolExecutionPolicy>;\n\n\t/**\n\t * Called before a tool is executed, after arguments have been validated.\n\t *\n\t * Return `{ block: true }` to prevent execution. The loop emits an error tool result instead.\n\t * The runtime bounds the hook by the parent abort signal and ignores a late settlement.\n\t */\n\tbeforeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;\n\n\t/**\n\t * Called after execution but skipped for an immutable committed timeout/abort terminal.\n\t *\n\t * Return an `AfterToolCallResult` to override parts of the executed tool result:\n\t * - `content` replaces the full content array\n\t * - `details` replaces the full details payload\n\t * - `isError` replaces the error flag\n\t * - `terminate` replaces the early-termination hint\n\t *\n\t * Any omitted fields keep their original values. No deep merge is performed.\n\t * The runtime bounds the hook by the parent abort signal and ignores a late settlement.\n\t */\n\tafterToolCall?: (context: AfterToolCallContext, signal?: AbortSignal) => Promise<AfterToolCallResult | undefined>;\n}\n\n/**\n * Thinking/reasoning level for models that support it.\n * Note: \"xhigh\", \"max\", and \"ultra\" are only supported by selected model families. Use model thinking-level\n * metadata from omk-ai to detect support for a concrete model.\n */\nexport type ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" | \"ultra\";\n\n/**\n * Extensible interface for custom app messages.\n * Apps can extend via declaration merging:\n *\n * @example\n * ```typescript\n * declare module \"@mariozechner/agent\" {\n * interface CustomAgentMessages {\n * artifact: ArtifactMessage;\n * notification: NotificationMessage;\n * }\n * }\n * ```\n */\nexport interface CustomAgentMessages {\n\t// Empty by default - apps extend via declaration merging\n}\n\n/**\n * AgentMessage: Union of LLM messages + custom messages.\n * This abstraction allows apps to add custom message types while maintaining\n * type safety and compatibility with the base LLM messages.\n */\nexport type AgentMessage = Message | CustomAgentMessages[keyof CustomAgentMessages];\n\n/**\n * Public agent state.\n *\n * `tools` and `messages` use accessor properties so implementations can copy\n * assigned arrays before storing them.\n */\nexport interface AgentState {\n\t/** System prompt sent with each model request. */\n\tsystemPrompt: string;\n\t/** Active model used for future turns. */\n\tmodel: Model<any>;\n\t/** Requested reasoning level for future turns. */\n\tthinkingLevel: ThinkingLevel;\n\t/** Available tools. Assigning a new array copies the top-level array. */\n\tset tools(tools: AgentTool<any>[]);\n\tget tools(): AgentTool<any>[];\n\t/** Conversation transcript. Assigning a new array copies the top-level array. */\n\tset messages(messages: AgentMessage[]);\n\tget messages(): AgentMessage[];\n\t/**\n\t * True while the agent is processing a prompt or continuation.\n\t *\n\t * This remains true until awaited `agent_end` listeners settle.\n\t */\n\treadonly isStreaming: boolean;\n\t/** Partial assistant message for the current streamed response, if any. */\n\treadonly streamingMessage?: AgentMessage;\n\t/** Tool call ids currently executing. */\n\treadonly pendingToolCalls: ReadonlySet<string>;\n\t/** Error message from the most recent failed or aborted assistant turn, if any. */\n\treadonly errorMessage?: string;\n}\n\n/** Final or partial result produced by a tool. */\nexport interface AgentToolResult<T> {\n\t/** Text or image content returned to the model. */\n\tcontent: (TextContent | ImageContent)[];\n\t/** Arbitrary structured details for logs or UI rendering. */\n\tdetails: T;\n\t/**\n\t * Hint that the agent should stop after the current tool batch.\n\t * Early termination only happens when every finalized tool result in the batch sets this to true.\n\t */\n\tterminate?: boolean;\n}\n\n/** Callback used by tools to stream partial execution updates. */\nexport type AgentToolUpdateCallback<T = any> = (partialResult: AgentToolResult<T>) => void;\n\n/** Access mode used by a tool resource claim. */\nexport type ResourceAccess = \"read\" | \"write\" | \"exclusive\";\n\n/** Access modes valid for path claims and built-in read/write resources. */\nexport type ToolResourceAccess = Extract<ResourceAccess, \"read\" | \"write\">;\n\n/**\n * A resource touched by one tool call.\n *\n * Path claims conflict on lexical parent/child overlap. Other claim kinds\n * conflict when their keys are equal. `exclusive` access conflicts with every\n * call, regardless of resource kind or key.\n */\nexport type ToolResourceClaim =\n\t| {\n\t\t\tkind: \"path\";\n\t\t\tkey: string;\n\t\t\taccess: ToolResourceAccess;\n\t\t\t/** Canonical real-path identity (symlink-resolved), when a resolver is injected. */\n\t\t\trealKey?: string;\n\t\t\t/** `dev:ino` identity for an existing file, when a resolver is injected. */\n\t\t\tinodeKey?: string;\n\t }\n\t| {\n\t\t\tkind: \"session\" | \"terminal\" | \"network\" | \"global\";\n\t\t\tkey: string;\n\t\t\taccess: ResourceAccess;\n\t };\n\n/**\n * Resource contract returned by {@link AgentTool.resourceClaims}.\n *\n * Return `\"exclusive\"` when the call must run alone, or a non-empty claim\n * list. The dag-v2 scheduler fails closed to exclusive when a resolver throws,\n * rejects, or returns an empty or malformed claim list.\n */\nexport type ToolResourceClaims = readonly ToolResourceClaim[] | \"exclusive\";\n\n/** Context passed to {@link AgentTool.resourceClaims}. */\nexport interface ToolResourceClaimsContext {\n\t/** Working directory used by the scheduler for this call batch. */\n\tcwd: string;\n\t/** Provider-supplied id of the tool call being scheduled. */\n\ttoolCallId: string;\n}\n\n/** Tool definition used by the agent runtime. */\nexport interface AgentTool<TParameters extends TSchema = TSchema, TDetails = any> extends Tool<TParameters> {\n\t/** Human-readable label for UI display. */\n\tlabel: string;\n\t/**\n\t * Optional compatibility shim for raw tool-call arguments before schema validation.\n\t * Must return an object that matches `TParameters`.\n\t */\n\tprepareArguments?: (args: unknown) => Static<TParameters>;\n\t/** Execute the tool call. Throw on failure instead of encoding errors in `content`. */\n\texecute: (\n\t\ttoolCallId: string,\n\t\tparams: Static<TParameters>,\n\t\tsignal?: AbortSignal,\n\t\tonUpdate?: AgentToolUpdateCallback<TDetails>,\n\t) => Promise<AgentToolResult<TDetails>>;\n\t/**\n\t * Per-tool execution mode override.\n\t * - \"sequential\": this tool must execute one at a time with other tool calls.\n\t * - \"parallel\": this tool can execute concurrently with other tool calls.\n\t *\n\t * If omitted, the default execution mode applies.\n\t */\n\texecutionMode?: ToolExecutionMode;\n\t/**\n\t * dag-v2 resource contract for this tool call.\n\t *\n\t * The resolver receives the raw call arguments and scheduler context before\n\t * execution starts. It may return synchronously or asynchronously. Throwing,\n\t * rejecting, returning malformed data, or returning no usable claim fails\n\t * closed to exclusive scheduling. This field has no effect on waves-v1.\n\t */\n\tresourceClaims?: (\n\t\targs: unknown,\n\t\tcontext: ToolResourceClaimsContext,\n\t) => ToolResourceClaims | Promise<ToolResourceClaims>;\n\t/**\n\t * Optional per-call execution timeout in milliseconds.\n\t *\n\t * When positive, the tool's `execute` promise is raced against this timeout at\n\t * the shared execution chokepoint. If the timeout elapses first, the loop\n\t * commits an immediate terminal timeout result and aborts the tool's child\n\t * `AbortSignal`, so a tool that ignores the signal cannot stall the run.\n\t *\n\t * Precedence: this value overrides `AgentLoopConfig.toolTimeouts[name]`, which\n\t * overrides `AgentLoopConfig.toolTimeoutMs`. Absent, non-finite, or\n\t * non-positive values disable the timeout and preserve current behavior.\n\t */\n\ttimeoutMs?: number;\n}\n\n/**\n * Terminal disposition of one tool call in a transcript (six-state model).\n *\n * - `completed`: the tool ran and returned a result.\n * - `failed`: the tool ran and threw/rejected, or could not be prepared.\n * - `blocked`: a policy hook prevented execution.\n * - `aborted`: the run's abort terminated the call (started or unstarted).\n * - `timeout`: the per-call timeout terminated the call.\n * - `skipped`: the scheduler closed the call without ever starting it.\n */\nexport type ToolCallDisposition = \"completed\" | \"failed\" | \"blocked\" | \"aborted\" | \"timeout\" | \"skipped\";\n\n/** Schema tag for the {@link ToolResultEnvelope} attached to terminal tool results. */\nexport const TOOL_RESULT_ENVELOPE_SCHEMA = \"tool-result/v2\" as const;\n\n/**\n * Model-invisible disposition envelope stamped at `details.omk` on every\n * terminal tool result. `synthetic` means the result artifact was fabricated\n * by the runtime and does not represent the tool's returned details;\n * `executionStarted` records whether `AgentTool.execute` actually began.\n */\nexport interface ToolResultEnvelope {\n\tschema: typeof TOOL_RESULT_ENVELOPE_SCHEMA;\n\tsynthetic: boolean;\n\tdisposition: ToolCallDisposition;\n\treason?: string;\n\ttimeoutMs?: number;\n\texecutionStarted: boolean;\n}\n\n/** Input accepted by the executor-owned {@link createToolResultEnvelope} boundary. */\nexport type ToolResultEnvelopeInput = Omit<ToolResultEnvelope, \"schema\">;\n\n/** Compatibility wrapper used when original tool details are not a plain object. */\nexport interface WrappedToolResultDetails {\n\treadonly originalDetails: unknown;\n\treadonly omk: ToolResultEnvelope;\n}\n\nfunction isUnknownRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Validate both the v2 shape and disposition-specific executor invariants. */\nexport function isToolResultEnvelope(value: unknown): value is ToolResultEnvelope {\n\tif (\n\t\t!isUnknownRecord(value) ||\n\t\tvalue.schema !== TOOL_RESULT_ENVELOPE_SCHEMA ||\n\t\ttypeof value.synthetic !== \"boolean\" ||\n\t\ttypeof value.executionStarted !== \"boolean\" ||\n\t\t(value.reason !== undefined && typeof value.reason !== \"string\") ||\n\t\t(value.timeoutMs !== undefined &&\n\t\t\t(typeof value.timeoutMs !== \"number\" || !Number.isFinite(value.timeoutMs) || value.timeoutMs <= 0))\n\t) {\n\t\treturn false;\n\t}\n\n\tswitch (value.disposition) {\n\t\tcase \"completed\":\n\t\t\treturn value.synthetic === false && value.executionStarted && value.timeoutMs === undefined;\n\t\tcase \"failed\":\n\t\t\treturn (value.executionStarted || value.synthetic) && value.timeoutMs === undefined;\n\t\tcase \"blocked\":\n\t\tcase \"skipped\":\n\t\t\treturn value.synthetic && !value.executionStarted && value.timeoutMs === undefined;\n\t\tcase \"aborted\":\n\t\t\treturn value.synthetic && value.timeoutMs === undefined;\n\t\tcase \"timeout\":\n\t\t\treturn value.synthetic && value.executionStarted && value.timeoutMs !== undefined;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\n/**\n * Construct and freeze a validated executor envelope. Invalid combinations\n * throw at the executor boundary instead of being persisted into a transcript.\n */\nexport function createToolResultEnvelope(input: ToolResultEnvelopeInput): ToolResultEnvelope {\n\tconst envelope: ToolResultEnvelope = {\n\t\tschema: TOOL_RESULT_ENVELOPE_SCHEMA,\n\t\tsynthetic: input.synthetic,\n\t\tdisposition: input.disposition,\n\t\t...(input.reason === undefined ? {} : { reason: input.reason }),\n\t\t...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),\n\t\texecutionStarted: input.executionStarted,\n\t};\n\tif (!isToolResultEnvelope(envelope)) {\n\t\tthrow new TypeError(`Invalid ${TOOL_RESULT_ENVELOPE_SCHEMA} ${input.disposition} envelope`);\n\t}\n\treturn Object.freeze(envelope);\n}\n\n/**\n * Per-call execution policy (ALG-004 §6.2). `lateSettlement` controls whether\n * a real tool promise settling after its terminal cause is surfaced as an\n * audit-only event (`\"audit\"`, default) or silently dropped (`\"ignore\"`).\n * Terminal results are immutable either way.\n */\nexport interface ToolExecutionPolicy {\n\ttimeoutMs?: number;\n\tcancelSiblingsOnFatal?: boolean;\n\tlateSettlement: \"audit\" | \"ignore\";\n}\n\n/** Committed disposition for a tool call terminated by timeout or parent abort. */\nexport type ToolTimeoutDisposition = \"timeout\" | \"aborted\";\n\n/** Identity keys resolved for one raw path by a {@link ResourceKeyResolver}. */\nexport interface ResolvedResourceKeys {\n\t/** Canonical lexical key (slash-normalized, dot-collapsed, drive/UNC normalized). */\n\tlexicalKey: string;\n\t/** Canonical real path: nearest existing ancestor realpath + non-existing suffix. */\n\trealKey?: string;\n\t/** `dev:ino` identity for an existing file (symlink target/hardlink aware). */\n\tinodeKey?: string;\n}\n\n/**\n * Optional platform identity resolver injected into the dag-v2 scheduler\n * (§5.5 stage 2). The shared agent package stays browser-safe; a Node\n * implementation lives in `omk-agent-core/node`. The raw path reaches the\n * resolver before cwd-relative lexical canonicalization so Node-only tilde and\n * platform aliases remain visible. Returning `null`, throwing, rejecting, or\n * returning malformed keys isolates the call as exclusive.\n */\nexport interface ResourceKeyResolver {\n\tresolvePath(rawPath: string, cwd: string): Promise<ResolvedResourceKeys | null> | ResolvedResourceKeys | null;\n}\n\n/** How a tool's real promise eventually settled after its terminal cause won. */\nexport type ToolLateSettlementOutcome = \"resolved\" | \"rejected\";\n\n/** Context snapshot passed into the low-level agent loop. */\nexport interface AgentContext {\n\t/** System prompt included with the request. */\n\tsystemPrompt: string;\n\t/** Transcript visible to the model. */\n\tmessages: AgentMessage[];\n\t/** Tools available for this run. */\n\ttools?: AgentTool<any>[];\n}\n\n/**\n * Events emitted by the Agent for UI updates.\n *\n * `agent_end` is the last event emitted for a run, and its subscribers remain\n * part of run settlement. `tool_execution_update` delivery is observation-only:\n * subscriber promises are detached and cannot delay timeout/abort terminality.\n */\nexport type AgentEvent =\n\t// Agent lifecycle\n\t| { type: \"agent_start\" }\n\t| { type: \"agent_end\"; messages: AgentMessage[] }\n\t// Turn lifecycle - a turn is one assistant response + any tool calls/results\n\t| { type: \"turn_start\" }\n\t| { type: \"turn_end\"; message: AgentMessage; toolResults: ToolResultMessage[] }\n\t// Message lifecycle - emitted for user, assistant, and toolResult messages\n\t| { type: \"message_start\"; message: AgentMessage }\n\t// Only emitted for assistant messages during streaming\n\t| { type: \"message_update\"; message: AgentMessage; assistantMessageEvent: AssistantMessageEvent }\n\t| { type: \"message_end\"; message: AgentMessage }\n\t// Tool execution lifecycle\n\t| { type: \"tool_execution_start\"; toolCallId: string; toolName: string; args: unknown }\n\t| { type: \"tool_execution_update\"; toolCallId: string; toolName: string; args: unknown; partialResult: unknown }\n\t| { type: \"tool_execution_end\"; toolCallId: string; toolName: string; result: unknown; isError: boolean }\n\t// Audit-only: a tool's real promise settled *after* a timeout/abort terminal\n\t// result was already committed. Carries disposition-safe metadata only (no late\n\t// content/details/error). Never a second tool result or lifecycle end.\n\t| {\n\t\t\ttype: \"tool_execution_late_settlement\";\n\t\t\ttoolCallId: string;\n\t\t\ttoolName: string;\n\t\t\tdisposition: ToolTimeoutDisposition;\n\t\t\toutcome: ToolLateSettlementOutcome;\n\t };\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAgjBA,uFAAuF;AACvF,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAyB,CAAC;AA0BrE,SAAS,eAAe,CAAC,KAAc,EAAoC;IAC1E,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAAA,CAC5E;AAED,+EAA+E;AAC/E,MAAM,UAAU,oBAAoB,CAAC,KAAc,EAA+B;IACjF,IACC,CAAC,eAAe,CAAC,KAAK,CAAC;QACvB,KAAK,CAAC,MAAM,KAAK,2BAA2B;QAC5C,OAAO,KAAK,CAAC,SAAS,KAAK,SAAS;QACpC,OAAO,KAAK,CAAC,gBAAgB,KAAK,SAAS;QAC3C,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC;QAChE,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS;YAC7B,CAAC,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,EACnG,CAAC;QACF,OAAO,KAAK,CAAC;IACd,CAAC;IAED,QAAQ,KAAK,CAAC,WAAW,EAAE,CAAC;QAC3B,KAAK,WAAW;YACf,OAAO,KAAK,CAAC,SAAS,KAAK,KAAK,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QAC7F,KAAK,QAAQ;YACZ,OAAO,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QACrF,KAAK,SAAS,CAAC;QACf,KAAK,SAAS;YACb,OAAO,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QACpF,KAAK,SAAS;YACb,OAAO,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QACzD,KAAK,SAAS;YACb,OAAO,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;QACnF;YACC,OAAO,KAAK,CAAC;IACf,CAAC;AAAA,CACD;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAA8B,EAAsB;IAC5F,MAAM,QAAQ,GAAuB;QACpC,MAAM,EAAE,2BAA2B;QACnC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;QAC/D,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;QACxE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;KACxC,CAAC;IACF,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,SAAS,CAAC,WAAW,2BAA2B,IAAI,KAAK,CAAC,WAAW,WAAW,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAAA,CAC/B","sourcesContent":["import type {\n\tAssistantMessage,\n\tAssistantMessageEvent,\n\tImageContent,\n\tMessage,\n\tModel,\n\tSimpleStreamOptions,\n\tstreamSimple,\n\tTextContent,\n\tTool,\n\tToolResultMessage,\n} from \"omk-ai\";\nimport type { Static, TSchema } from \"typebox\";\n\n/**\n * Stream function used by the agent loop.\n *\n * Contract:\n * - Must not throw or return a rejected promise for request/model/runtime failures.\n * - Must return an AssistantMessageEventStream.\n * - Failures must be encoded in the returned stream via protocol events and a\n * final AssistantMessage with stopReason \"error\" or \"aborted\" and errorMessage.\n */\nexport type StreamFn = (\n\t...args: Parameters<typeof streamSimple>\n) => ReturnType<typeof streamSimple> | Promise<ReturnType<typeof streamSimple>>;\n\n/**\n * Configuration for how tool calls from a single assistant message are executed.\n *\n * - \"sequential\": each tool call is prepared, executed, and finalized before the next one starts.\n * - \"parallel\": tool calls are prepared sequentially, then allowed tools execute concurrently.\n * `tool_execution_end` is emitted in tool completion order after each tool is finalized,\n * while tool-result message artifacts are emitted later in assistant source order.\n */\nexport type ToolExecutionMode = \"sequential\" | \"parallel\";\n\n/**\n * Tool-call scheduler selection for a single assistant turn's tool batch.\n *\n * - `\"waves-v1\"` (default): the original contiguous-wave scheduler\n * (`partitionToolBatchWaves`). Established behavior and the rollback target.\n * - `\"dag-v2\"`: the deterministic resource-claim DAG scheduler\n * (`scheduleDagLevels`). Active only when explicitly selected. It resolves\n * per-call resource claims and groups conflict-free calls into source-index\n * DAG levels so a conflicting call no longer head-of-line-blocks independent\n * later calls (e.g. `write x, write x, write y` schedules as `[[0, 2], [1]]`).\n * Final tool results are buffered globally and emitted in original source\n * order.\n */\nexport type ToolSchedulerKind = \"waves-v1\" | \"dag-v2\";\n\n/**\n * Controls how many queued user messages are injected when the agent loop reaches a queue drain point.\n *\n * - \"all\": drain and inject every queued message at that point.\n * - \"one-at-a-time\": drain and inject only the oldest queued message, leaving the rest queued for later drain points.\n */\nexport type QueueMode = \"all\" | \"one-at-a-time\";\n\n/** A single tool call content block emitted by an assistant message. */\nexport type AgentToolCall = Extract<AssistantMessage[\"content\"][number], { type: \"toolCall\" }>;\n\n/**\n * Result returned from `beforeToolCall`.\n *\n * Returning `{ block: true }` prevents the tool from executing. The loop emits an error tool result instead.\n * `reason` becomes the text shown in that error result. If omitted, a default blocked message is used.\n */\nexport interface BeforeToolCallResult {\n\tblock?: boolean;\n\treason?: string;\n}\n\n/**\n * Partial override returned from `afterToolCall`.\n *\n * Merge semantics are field-by-field:\n * - `content`: if provided, replaces the tool result content array in full\n * - `details`: if provided, replaces the tool result details value in full\n * - `isError`: if provided, replaces the tool result error flag\n * - `terminate`: if provided, replaces the early-termination hint\n *\n * Omitted fields keep the original executed tool result values.\n * There is no deep merge for `content` or `details`.\n */\nexport interface AfterToolCallResult {\n\tcontent?: (TextContent | ImageContent)[];\n\tdetails?: unknown;\n\tisError?: boolean;\n\t/**\n\t * Hint that the agent should stop after the current tool batch.\n\t * Early termination only happens when every finalized tool result in the batch sets this to true.\n\t */\n\tterminate?: boolean;\n}\n\n/** Context passed to `beforeToolCall`. */\nexport interface BeforeToolCallContext {\n\t/** The assistant message that requested the tool call. */\n\tassistantMessage: AssistantMessage;\n\t/** The raw tool call block from `assistantMessage.content`. */\n\ttoolCall: AgentToolCall;\n\t/** Validated tool arguments for the target tool schema. */\n\targs: unknown;\n\t/** Current agent context at the time the tool call is prepared. */\n\tcontext: AgentContext;\n}\n\n/** Context passed to `afterToolCall`. */\nexport interface AfterToolCallContext {\n\t/** The assistant message that requested the tool call. */\n\tassistantMessage: AssistantMessage;\n\t/** The raw tool call block from `assistantMessage.content`. */\n\ttoolCall: AgentToolCall;\n\t/** Validated tool arguments for the target tool schema. */\n\targs: unknown;\n\t/** The executed tool result before any `afterToolCall` overrides are applied. */\n\tresult: AgentToolResult<any>;\n\t/** Whether the executed tool result is currently treated as an error. */\n\tisError: boolean;\n\t/** Current agent context at the time the tool call is finalized. */\n\tcontext: AgentContext;\n}\n\n/** Context passed to `shouldStopAfterTurn`. */\nexport interface ShouldStopAfterTurnContext {\n\t/** The assistant message that completed the turn. */\n\tmessage: AssistantMessage;\n\t/** Tool result messages passed to the preceding `turn_end` event. */\n\ttoolResults: ToolResultMessage[];\n\t/** Current agent context after the turn's assistant message and tool results have been appended. */\n\tcontext: AgentContext;\n\t/** Messages that this loop invocation will return if it exits at this point. Prompt runs include the initial prompt messages; continuation runs do not include pre-existing context messages. */\n\tnewMessages: AgentMessage[];\n}\n\n/** Replacement runtime state used by the agent loop before starting another provider request. */\nexport interface AgentLoopTurnUpdate {\n\t/** Context for the next provider request. */\n\tcontext?: AgentContext;\n\t/** Model for the next provider request. */\n\tmodel?: Model<any>;\n\t/** Thinking level for the next provider request. */\n\tthinkingLevel?: ThinkingLevel;\n}\n\nexport interface PrepareNextTurnContext extends ShouldStopAfterTurnContext {}\n\nexport interface AgentLoopConfig extends SimpleStreamOptions {\n\tmodel: Model<any>;\n\n\t/**\n\t * Maximum provider turns allowed in one loop invocation.\n\t *\n\t * Each assistant response counts as one turn, including responses that call tools.\n\t * When the limit is reached, the current assistant response and tool batch finish normally,\n\t * then the loop emits `agent_end` without preparing another turn or polling message queues.\n\t * Undefined preserves the historical unbounded behavior. Configured values must be positive\n\t * safe integers; invalid values reject the run before any provider request.\n\t */\n\tmaxTurns?: number;\n\n\t/**\n\t * Converts AgentMessage[] to LLM-compatible Message[] before each LLM call.\n\t *\n\t * Each AgentMessage must be converted to a UserMessage, AssistantMessage, or ToolResultMessage\n\t * that the LLM can understand. AgentMessages that cannot be converted (e.g., UI-only notifications,\n\t * status messages) should be filtered out.\n\t *\n\t * Contract: must not throw or reject. Return a safe fallback value instead.\n\t * Throwing interrupts the low-level agent loop without producing a normal event sequence.\n\t *\n\t * @example\n\t * ```typescript\n\t * convertToLlm: (messages) => messages.flatMap(m => {\n\t * if (m.role === \"custom\") {\n\t * // Convert custom message to user message\n\t * return [{ role: \"user\", content: m.content, timestamp: m.timestamp }];\n\t * }\n\t * if (m.role === \"notification\") {\n\t * // Filter out UI-only messages\n\t * return [];\n\t * }\n\t * // Pass through standard LLM messages\n\t * return [m];\n\t * })\n\t * ```\n\t */\n\tconvertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\n\t/**\n\t * Optional transform applied to the context before `convertToLlm`.\n\t *\n\t * Use this for operations that work at the AgentMessage level:\n\t * - Context window management (pruning old messages)\n\t * - Injecting context from external sources\n\t *\n\t * Contract: must not throw or reject. Return the original messages or another\n\t * safe fallback value instead.\n\t *\n\t * @example\n\t * ```typescript\n\t * transformContext: async (messages) => {\n\t * if (estimateTokens(messages) > MAX_TOKENS) {\n\t * return pruneOldMessages(messages);\n\t * }\n\t * return messages;\n\t * }\n\t * ```\n\t */\n\ttransformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\n\t/**\n\t * Resolves an API key dynamically for each LLM call.\n\t *\n\t * Useful for short-lived OAuth tokens (e.g., GitHub Copilot) that may expire\n\t * during long-running tool execution phases.\n\t *\n\t * Contract: must not throw or reject. Return undefined when no key is available.\n\t */\n\tgetApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\n\t/**\n\t * Called after each turn fully completes and `turn_end` has been emitted.\n\t *\n\t * If it returns true, the loop emits `agent_end` and exits before polling steering or follow-up queues,\n\t * without starting another LLM call. The current assistant response and any tool executions finish normally.\n\t *\n\t * Use this to request a graceful stop after the current turn, e.g. before context gets too full.\n\t *\n\t * Contract: must not throw or reject. Throwing interrupts the low-level agent loop without producing a normal event sequence.\n\t */\n\tshouldStopAfterTurn?: (context: ShouldStopAfterTurnContext) => boolean | Promise<boolean>;\n\n\t/**\n\t * Called after `turn_end` and before the loop decides whether another provider request should start.\n\t * Return replacement context/model/thinking state to affect the next turn in this run.\n\t * Return undefined to keep using the current context/config.\n\t */\n\tprepareNextTurn?: (\n\t\tcontext: PrepareNextTurnContext,\n\t) => AgentLoopTurnUpdate | undefined | Promise<AgentLoopTurnUpdate | undefined>;\n\n\t/**\n\t * Returns steering messages to inject into the conversation mid-run.\n\t *\n\t * Called after the current assistant turn finishes executing its tool calls, unless `shouldStopAfterTurn` exits first.\n\t * If messages are returned, they are added to the context before the next LLM call.\n\t * Tool calls from the current assistant message are not skipped.\n\t *\n\t * Use this for \"steering\" the agent while it's working.\n\t *\n\t * Contract: must not throw or reject. Return [] when no steering messages are available.\n\t */\n\tgetSteeringMessages?: () => Promise<AgentMessage[]>;\n\n\t/**\n\t * Returns follow-up messages to process after the agent would otherwise stop.\n\t *\n\t * Called when the agent has no more tool calls and no steering messages.\n\t * If messages are returned, they're added to the context and the agent\n\t * continues with another turn.\n\t *\n\t * Use this for follow-up messages that should wait until the agent finishes.\n\t *\n\t * Contract: must not throw or reject. Return [] when no follow-up messages are available.\n\t */\n\tgetFollowUpMessages?: () => Promise<AgentMessage[]>;\n\n\t/**\n\t * Tool execution mode.\n\t * - \"sequential\": execute tool calls one by one\n\t * - \"parallel\": preflight tool calls sequentially, then execute allowed tools concurrently;\n\t * emit `tool_execution_end` in tool completion order after each tool is finalized,\n\t * then emit tool-result message artifacts later in assistant source order\n\t *\n\t * Default: \"parallel\"\n\t */\n\ttoolExecution?: ToolExecutionMode;\n\n\t/**\n\t * Default per-tool execution timeout in milliseconds applied to every tool\n\t * call that does not resolve a more specific timeout.\n\t *\n\t * This is deliberately named to avoid colliding with the inherited\n\t * {@link SimpleStreamOptions.timeoutMs} (the provider request timeout).\n\t * Absent, non-finite, or non-positive values disable the tool timeout and\n\t * preserve the current unbounded execution behavior.\n\t */\n\ttoolTimeoutMs?: number;\n\n\t/**\n\t * Per-tool-name execution timeouts in milliseconds. An entry here overrides\n\t * {@link toolTimeoutMs} for that tool name, and is itself overridden by a\n\t * per-tool {@link AgentTool.timeoutMs}. Absent, non-finite, or non-positive\n\t * entries disable the timeout for that name.\n\t */\n\ttoolTimeouts?: Record<string, number>;\n\n\t/**\n\t * Tool-call scheduler. Defaults to `\"waves-v1\"` (the established\n\t * contiguous-wave scheduler). Set to `\"dag-v2\"` to opt into the\n\t * deterministic resource-claim DAG scheduler. The v1 path and its exports\n\t * are unchanged when this is unset or `\"waves-v1\"`.\n\t */\n\ttoolScheduler?: ToolSchedulerKind;\n\n\t/**\n\t * dag-v2 only. Optional positive width cap. When set, each DAG level is\n\t * split into deterministic contiguous chunks of at most this many calls\n\t * (preserving source order) so a wide conflict-free level does not fan out\n\t * unbounded. Absent, non-finite, or non-positive values leave each level\n\t * whole. No effect on the default `\"waves-v1\"` scheduler.\n\t */\n\tmaxToolConcurrency?: number;\n\n\t/**\n\t * dag-v2 only. When `false` (default), an extension/custom tool with\n\t * `executionMode: \"parallel\"` and no resource claims is treated as freely\n\t * parallel (compatibility). When `true`, such tools are treated as\n\t * exclusive (run alone). Unknown tools and bash are always exclusive\n\t * regardless of this flag. No effect on the default `\"waves-v1\"` scheduler.\n\t */\n\tstrictExtensionClaims?: boolean;\n\n\t/** Working directory for path-scoped parallel tool batch checks (read/write/edit). */\n\tcwd?: string;\n\n\t/**\n\t * dag-v2 only. Optional platform identity resolver used to detect\n\t * symlink/hardlink/drive/UNC path aliases when scheduling resource claims.\n\t * Absent, the scheduler uses lexical canonicalization only (browser-safe).\n\t * Resolver failure isolates the call as exclusive (fail closed).\n\t */\n\tresourceKeyResolver?: ResourceKeyResolver;\n\n\t/**\n\t * Execution policy defaults for every tool call in this run. Only\n\t * `lateSettlement` is consumed today; it defaults to `\"audit\"`.\n\t */\n\ttoolExecutionPolicy?: Partial<ToolExecutionPolicy>;\n\n\t/**\n\t * Called before a tool is executed, after arguments have been validated.\n\t *\n\t * Return `{ block: true }` to prevent execution. The loop emits an error tool result instead.\n\t * The runtime bounds the hook by the parent abort signal and ignores a late settlement.\n\t */\n\tbeforeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;\n\n\t/**\n\t * Called after execution but skipped for an immutable committed timeout/abort terminal.\n\t *\n\t * Return an `AfterToolCallResult` to override parts of the executed tool result:\n\t * - `content` replaces the full content array\n\t * - `details` replaces the full details payload\n\t * - `isError` replaces the error flag\n\t * - `terminate` replaces the early-termination hint\n\t *\n\t * Any omitted fields keep their original values. No deep merge is performed.\n\t * The runtime bounds the hook by the parent abort signal and ignores a late settlement.\n\t */\n\tafterToolCall?: (context: AfterToolCallContext, signal?: AbortSignal) => Promise<AfterToolCallResult | undefined>;\n}\n\n/**\n * Thinking/reasoning level for models that support it.\n * Note: \"xhigh\", \"max\", and \"ultra\" are only supported by selected model families. Use model thinking-level\n * metadata from omk-ai to detect support for a concrete model.\n */\nexport type ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" | \"ultra\";\n\n/**\n * Extensible interface for custom app messages.\n * Apps can extend via declaration merging:\n *\n * @example\n * ```typescript\n * declare module \"@mariozechner/agent\" {\n * interface CustomAgentMessages {\n * artifact: ArtifactMessage;\n * notification: NotificationMessage;\n * }\n * }\n * ```\n */\nexport interface CustomAgentMessages {\n\t// Empty by default - apps extend via declaration merging\n}\n\n/**\n * AgentMessage: Union of LLM messages + custom messages.\n * This abstraction allows apps to add custom message types while maintaining\n * type safety and compatibility with the base LLM messages.\n */\nexport type AgentMessage = Message | CustomAgentMessages[keyof CustomAgentMessages];\n\n/**\n * Public agent state.\n *\n * `tools` and `messages` use accessor properties so implementations can copy\n * assigned arrays before storing them.\n */\nexport interface AgentState {\n\t/** System prompt sent with each model request. */\n\tsystemPrompt: string;\n\t/** UTF-16 offset ending the stable provider-cacheable system-prompt prefix. */\n\tsystemPromptCacheBoundary?: number;\n\t/** Suppress explicit stable-prefix cache affinity/markers for a dynamic prompt replacement. */\n\tsystemPromptCacheBoundaryBypass?: boolean;\n\t/** Active model used for future turns. */\n\tmodel: Model<any>;\n\t/** Requested reasoning level for future turns. */\n\tthinkingLevel: ThinkingLevel;\n\t/** Available tools. Assigning a new array copies the top-level array. */\n\tset tools(tools: AgentTool<any>[]);\n\tget tools(): AgentTool<any>[];\n\t/** Conversation transcript. Assigning a new array copies the top-level array. */\n\tset messages(messages: AgentMessage[]);\n\tget messages(): AgentMessage[];\n\t/**\n\t * True while the agent is processing a prompt or continuation.\n\t *\n\t * This remains true until awaited `agent_end` listeners settle.\n\t */\n\treadonly isStreaming: boolean;\n\t/** Partial assistant message for the current streamed response, if any. */\n\treadonly streamingMessage?: AgentMessage;\n\t/** Tool call ids currently executing. */\n\treadonly pendingToolCalls: ReadonlySet<string>;\n\t/** Error message from the most recent failed or aborted assistant turn, if any. */\n\treadonly errorMessage?: string;\n}\n\n/** Final or partial result produced by a tool. */\nexport interface AgentToolResult<T> {\n\t/** Text or image content returned to the model. */\n\tcontent: (TextContent | ImageContent)[];\n\t/** Arbitrary structured details for logs or UI rendering. */\n\tdetails: T;\n\t/**\n\t * Hint that the agent should stop after the current tool batch.\n\t * Early termination only happens when every finalized tool result in the batch sets this to true.\n\t */\n\tterminate?: boolean;\n}\n\n/** Callback used by tools to stream partial execution updates. */\nexport type AgentToolUpdateCallback<T = any> = (partialResult: AgentToolResult<T>) => void;\n\n/** Access mode used by a tool resource claim. */\nexport type ResourceAccess = \"read\" | \"write\" | \"exclusive\";\n\n/** Access modes valid for path claims and built-in read/write resources. */\nexport type ToolResourceAccess = Extract<ResourceAccess, \"read\" | \"write\">;\n\n/**\n * A resource touched by one tool call.\n *\n * Path claims conflict on lexical parent/child overlap. Other claim kinds\n * conflict when their keys are equal. `exclusive` access conflicts with every\n * call, regardless of resource kind or key.\n */\nexport type ToolResourceClaim =\n\t| {\n\t\t\tkind: \"path\";\n\t\t\tkey: string;\n\t\t\taccess: ToolResourceAccess;\n\t\t\t/** Canonical real-path identity (symlink-resolved), when a resolver is injected. */\n\t\t\trealKey?: string;\n\t\t\t/** `dev:ino` identity for an existing file, when a resolver is injected. */\n\t\t\tinodeKey?: string;\n\t }\n\t| {\n\t\t\tkind: \"session\" | \"terminal\" | \"network\" | \"global\";\n\t\t\tkey: string;\n\t\t\taccess: ResourceAccess;\n\t };\n\n/**\n * Resource contract returned by {@link AgentTool.resourceClaims}.\n *\n * Return `\"exclusive\"` when the call must run alone, or a non-empty claim\n * list. The dag-v2 scheduler fails closed to exclusive when a resolver throws,\n * rejects, or returns an empty or malformed claim list.\n */\nexport type ToolResourceClaims = readonly ToolResourceClaim[] | \"exclusive\";\n\n/** Context passed to {@link AgentTool.resourceClaims}. */\nexport interface ToolResourceClaimsContext {\n\t/** Working directory used by the scheduler for this call batch. */\n\tcwd: string;\n\t/** Provider-supplied id of the tool call being scheduled. */\n\ttoolCallId: string;\n}\n\n/** Tool definition used by the agent runtime. */\nexport interface AgentTool<TParameters extends TSchema = TSchema, TDetails = any> extends Tool<TParameters> {\n\t/** Human-readable label for UI display. */\n\tlabel: string;\n\t/**\n\t * Optional compatibility shim for raw tool-call arguments before schema validation.\n\t * Must return an object that matches `TParameters`.\n\t */\n\tprepareArguments?: (args: unknown) => Static<TParameters>;\n\t/** Execute the tool call. Throw on failure instead of encoding errors in `content`. */\n\texecute: (\n\t\ttoolCallId: string,\n\t\tparams: Static<TParameters>,\n\t\tsignal?: AbortSignal,\n\t\tonUpdate?: AgentToolUpdateCallback<TDetails>,\n\t) => Promise<AgentToolResult<TDetails>>;\n\t/**\n\t * Per-tool execution mode override.\n\t * - \"sequential\": this tool must execute one at a time with other tool calls.\n\t * - \"parallel\": this tool can execute concurrently with other tool calls.\n\t *\n\t * If omitted, the default execution mode applies.\n\t */\n\texecutionMode?: ToolExecutionMode;\n\t/**\n\t * dag-v2 resource contract for this tool call.\n\t *\n\t * The resolver receives the raw call arguments and scheduler context before\n\t * execution starts. It may return synchronously or asynchronously. Throwing,\n\t * rejecting, returning malformed data, or returning no usable claim fails\n\t * closed to exclusive scheduling. This field has no effect on waves-v1.\n\t */\n\tresourceClaims?: (\n\t\targs: unknown,\n\t\tcontext: ToolResourceClaimsContext,\n\t) => ToolResourceClaims | Promise<ToolResourceClaims>;\n\t/**\n\t * Optional per-call execution timeout in milliseconds.\n\t *\n\t * When positive, the tool's `execute` promise is raced against this timeout at\n\t * the shared execution chokepoint. If the timeout elapses first, the loop\n\t * commits an immediate terminal timeout result and aborts the tool's child\n\t * `AbortSignal`, so a tool that ignores the signal cannot stall the run.\n\t *\n\t * Precedence: this value overrides `AgentLoopConfig.toolTimeouts[name]`, which\n\t * overrides `AgentLoopConfig.toolTimeoutMs`. Absent, non-finite, or\n\t * non-positive values disable the timeout and preserve current behavior.\n\t */\n\ttimeoutMs?: number;\n}\n\n/**\n * Terminal disposition of one tool call in a transcript (six-state model).\n *\n * - `completed`: the tool ran and returned a result.\n * - `failed`: the tool ran and threw/rejected, or could not be prepared.\n * - `blocked`: a policy hook prevented execution.\n * - `aborted`: the run's abort terminated the call (started or unstarted).\n * - `timeout`: the per-call timeout terminated the call.\n * - `skipped`: the scheduler closed the call without ever starting it.\n */\nexport type ToolCallDisposition = \"completed\" | \"failed\" | \"blocked\" | \"aborted\" | \"timeout\" | \"skipped\";\n\n/** Schema tag for the {@link ToolResultEnvelope} attached to terminal tool results. */\nexport const TOOL_RESULT_ENVELOPE_SCHEMA = \"tool-result/v2\" as const;\n\n/**\n * Model-invisible disposition envelope stamped at `details.omk` on every\n * terminal tool result. `synthetic` means the result artifact was fabricated\n * by the runtime and does not represent the tool's returned details;\n * `executionStarted` records whether `AgentTool.execute` actually began.\n */\nexport interface ToolResultEnvelope {\n\tschema: typeof TOOL_RESULT_ENVELOPE_SCHEMA;\n\tsynthetic: boolean;\n\tdisposition: ToolCallDisposition;\n\treason?: string;\n\ttimeoutMs?: number;\n\texecutionStarted: boolean;\n}\n\n/** Input accepted by the executor-owned {@link createToolResultEnvelope} boundary. */\nexport type ToolResultEnvelopeInput = Omit<ToolResultEnvelope, \"schema\">;\n\n/** Compatibility wrapper used when original tool details are not a plain object. */\nexport interface WrappedToolResultDetails {\n\treadonly originalDetails: unknown;\n\treadonly omk: ToolResultEnvelope;\n}\n\nfunction isUnknownRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Validate both the v2 shape and disposition-specific executor invariants. */\nexport function isToolResultEnvelope(value: unknown): value is ToolResultEnvelope {\n\tif (\n\t\t!isUnknownRecord(value) ||\n\t\tvalue.schema !== TOOL_RESULT_ENVELOPE_SCHEMA ||\n\t\ttypeof value.synthetic !== \"boolean\" ||\n\t\ttypeof value.executionStarted !== \"boolean\" ||\n\t\t(value.reason !== undefined && typeof value.reason !== \"string\") ||\n\t\t(value.timeoutMs !== undefined &&\n\t\t\t(typeof value.timeoutMs !== \"number\" || !Number.isFinite(value.timeoutMs) || value.timeoutMs <= 0))\n\t) {\n\t\treturn false;\n\t}\n\n\tswitch (value.disposition) {\n\t\tcase \"completed\":\n\t\t\treturn value.synthetic === false && value.executionStarted && value.timeoutMs === undefined;\n\t\tcase \"failed\":\n\t\t\treturn (value.executionStarted || value.synthetic) && value.timeoutMs === undefined;\n\t\tcase \"blocked\":\n\t\tcase \"skipped\":\n\t\t\treturn value.synthetic && !value.executionStarted && value.timeoutMs === undefined;\n\t\tcase \"aborted\":\n\t\t\treturn value.synthetic && value.timeoutMs === undefined;\n\t\tcase \"timeout\":\n\t\t\treturn value.synthetic && value.executionStarted && value.timeoutMs !== undefined;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\n/**\n * Construct and freeze a validated executor envelope. Invalid combinations\n * throw at the executor boundary instead of being persisted into a transcript.\n */\nexport function createToolResultEnvelope(input: ToolResultEnvelopeInput): ToolResultEnvelope {\n\tconst envelope: ToolResultEnvelope = {\n\t\tschema: TOOL_RESULT_ENVELOPE_SCHEMA,\n\t\tsynthetic: input.synthetic,\n\t\tdisposition: input.disposition,\n\t\t...(input.reason === undefined ? {} : { reason: input.reason }),\n\t\t...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),\n\t\texecutionStarted: input.executionStarted,\n\t};\n\tif (!isToolResultEnvelope(envelope)) {\n\t\tthrow new TypeError(`Invalid ${TOOL_RESULT_ENVELOPE_SCHEMA} ${input.disposition} envelope`);\n\t}\n\treturn Object.freeze(envelope);\n}\n\n/**\n * Per-call execution policy (ALG-004 §6.2). `lateSettlement` controls whether\n * a real tool promise settling after its terminal cause is surfaced as an\n * audit-only event (`\"audit\"`, default) or silently dropped (`\"ignore\"`).\n * Terminal results are immutable either way.\n */\nexport interface ToolExecutionPolicy {\n\ttimeoutMs?: number;\n\tcancelSiblingsOnFatal?: boolean;\n\tlateSettlement: \"audit\" | \"ignore\";\n}\n\n/** Committed disposition for a tool call terminated by timeout or parent abort. */\nexport type ToolTimeoutDisposition = \"timeout\" | \"aborted\";\n\n/** Identity keys resolved for one raw path by a {@link ResourceKeyResolver}. */\nexport interface ResolvedResourceKeys {\n\t/** Canonical lexical key (slash-normalized, dot-collapsed, drive/UNC normalized). */\n\tlexicalKey: string;\n\t/** Canonical real path: nearest existing ancestor realpath + non-existing suffix. */\n\trealKey?: string;\n\t/** `dev:ino` identity for an existing file (symlink target/hardlink aware). */\n\tinodeKey?: string;\n}\n\n/**\n * Optional platform identity resolver injected into the dag-v2 scheduler\n * (§5.5 stage 2). The shared agent package stays browser-safe; a Node\n * implementation lives in `omk-agent-core/node`. The raw path reaches the\n * resolver before cwd-relative lexical canonicalization so Node-only tilde and\n * platform aliases remain visible. Returning `null`, throwing, rejecting, or\n * returning malformed keys isolates the call as exclusive.\n */\nexport interface ResourceKeyResolver {\n\tresolvePath(rawPath: string, cwd: string): Promise<ResolvedResourceKeys | null> | ResolvedResourceKeys | null;\n}\n\n/** How a tool's real promise eventually settled after its terminal cause won. */\nexport type ToolLateSettlementOutcome = \"resolved\" | \"rejected\";\n\n/** Context snapshot passed into the low-level agent loop. */\nexport interface AgentContext {\n\t/** System prompt included with the request. */\n\tsystemPrompt: string;\n\t/** UTF-16 offset ending the stable provider-cacheable system-prompt prefix. */\n\tsystemPromptCacheBoundary?: number;\n\t/** Suppress explicit stable-prefix cache affinity/markers for a dynamic prompt replacement. */\n\tsystemPromptCacheBoundaryBypass?: boolean;\n\t/** Transcript visible to the model. */\n\tmessages: AgentMessage[];\n\t/** Tools available for this run. */\n\ttools?: AgentTool<any>[];\n}\n\n/**\n * Events emitted by the Agent for UI updates.\n *\n * `agent_end` is the last event emitted for a run, and its subscribers remain\n * part of run settlement. `tool_execution_update` delivery is observation-only:\n * subscriber promises are detached and cannot delay timeout/abort terminality.\n */\nexport type AgentEvent =\n\t// Agent lifecycle\n\t| { type: \"agent_start\" }\n\t| { type: \"agent_end\"; messages: AgentMessage[] }\n\t// Turn lifecycle - a turn is one assistant response + any tool calls/results\n\t| { type: \"turn_start\" }\n\t| { type: \"turn_end\"; message: AgentMessage; toolResults: ToolResultMessage[] }\n\t// Message lifecycle - emitted for user, assistant, and toolResult messages\n\t| { type: \"message_start\"; message: AgentMessage }\n\t// Only emitted for assistant messages during streaming\n\t| { type: \"message_update\"; message: AgentMessage; assistantMessageEvent: AssistantMessageEvent }\n\t| { type: \"message_end\"; message: AgentMessage }\n\t// Tool execution lifecycle\n\t| { type: \"tool_execution_start\"; toolCallId: string; toolName: string; args: unknown }\n\t| { type: \"tool_execution_update\"; toolCallId: string; toolName: string; args: unknown; partialResult: unknown }\n\t| { type: \"tool_execution_end\"; toolCallId: string; toolName: string; result: unknown; isError: boolean }\n\t// Audit-only: a tool's real promise settled *after* a timeout/abort terminal\n\t// result was already committed. Carries disposition-safe metadata only (no late\n\t// content/details/error). Never a second tool result or lifecycle end.\n\t| {\n\t\t\ttype: \"tool_execution_late_settlement\";\n\t\t\ttoolCallId: string;\n\t\t\ttoolName: string;\n\t\t\tdisposition: ToolTimeoutDisposition;\n\t\t\toutcome: ToolLateSettlementOutcome;\n\t };\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omk-agent-core",
|
|
3
|
-
"version": "0.95.
|
|
3
|
+
"version": "0.95.2",
|
|
4
4
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"prepublishOnly": "npm run clean && npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"omk-ai": "^0.95.
|
|
33
|
-
"ignore": "7.0.
|
|
34
|
-
"typebox": "1.
|
|
32
|
+
"omk-ai": "^0.95.2",
|
|
33
|
+
"ignore": "7.0.6",
|
|
34
|
+
"typebox": "1.3.11",
|
|
35
35
|
"yaml": "2.9.0"
|
|
36
36
|
},
|
|
37
37
|
"keywords": [
|