omk-agent-core 1.2.4 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/agent-loop.d.ts.map +1 -1
  3. package/dist/agent-loop.js +35 -47
  4. package/dist/agent-loop.js.map +1 -1
  5. package/dist/agent.d.ts +6 -1
  6. package/dist/agent.d.ts.map +1 -1
  7. package/dist/agent.js +9 -5
  8. package/dist/agent.js.map +1 -1
  9. package/dist/pending-message-queue.d.ts +1 -0
  10. package/dist/pending-message-queue.d.ts.map +1 -1
  11. package/dist/pending-message-queue.js +16 -5
  12. package/dist/pending-message-queue.js.map +1 -1
  13. package/dist/tool-dag-ecraf.d.ts.map +1 -1
  14. package/dist/tool-dag-ecraf.js +15 -8
  15. package/dist/tool-dag-ecraf.js.map +1 -1
  16. package/dist/tool-dag-index.d.ts +19 -0
  17. package/dist/tool-dag-index.d.ts.map +1 -0
  18. package/dist/tool-dag-index.js +175 -0
  19. package/dist/tool-dag-index.js.map +1 -0
  20. package/dist/tool-dag-memo.d.ts +13 -3
  21. package/dist/tool-dag-memo.d.ts.map +1 -1
  22. package/dist/tool-dag-memo.js +64 -25
  23. package/dist/tool-dag-memo.js.map +1 -1
  24. package/dist/tool-dag-own-number.d.ts +3 -0
  25. package/dist/tool-dag-own-number.d.ts.map +1 -0
  26. package/dist/tool-dag-own-number.js +5 -0
  27. package/dist/tool-dag-own-number.js.map +1 -0
  28. package/dist/tool-dag-owned-task.d.ts +15 -0
  29. package/dist/tool-dag-owned-task.d.ts.map +1 -0
  30. package/dist/tool-dag-owned-task.js +33 -0
  31. package/dist/tool-dag-owned-task.js.map +1 -0
  32. package/dist/tool-dag-plan-copy.d.ts +5 -0
  33. package/dist/tool-dag-plan-copy.d.ts.map +1 -0
  34. package/dist/tool-dag-plan-copy.js +18 -0
  35. package/dist/tool-dag-plan-copy.js.map +1 -0
  36. package/dist/tool-dag-read-aware.d.ts +11 -0
  37. package/dist/tool-dag-read-aware.d.ts.map +1 -0
  38. package/dist/tool-dag-read-aware.js +34 -0
  39. package/dist/tool-dag-read-aware.js.map +1 -0
  40. package/dist/tool-dag-reduce.d.ts +29 -0
  41. package/dist/tool-dag-reduce.d.ts.map +1 -0
  42. package/dist/tool-dag-reduce.js +146 -0
  43. package/dist/tool-dag-reduce.js.map +1 -0
  44. package/dist/tool-dag-scheduler.d.ts.map +1 -1
  45. package/dist/tool-dag-scheduler.js +3 -14
  46. package/dist/tool-dag-scheduler.js.map +1 -1
  47. package/dist/tool-terminal-index.d.ts +4 -0
  48. package/dist/tool-terminal-index.d.ts.map +1 -0
  49. package/dist/tool-terminal-index.js +12 -0
  50. package/dist/tool-terminal-index.js.map +1 -0
  51. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ImageContent,\n\ttype Message,\n\ttype SimpleStreamOptions,\n\tstreamSimple,\n\ttype TextContent,\n\ttype ThinkingBudgets,\n\ttype Transport,\n} from \"omk-ai\";\nimport { planFailureTermination, runAgentLoop, runAgentLoopContinue } from \"./agent-loop.ts\";\nimport { createMutableAgentState, type MutableAgentState } from \"./agent-state.ts\";\nimport { deliverToListeners } from \"./listener-delivery.ts\";\nimport { PendingMessageQueue } from \"./pending-message-queue.ts\";\nimport { type ModelContract, snapshotModelContract } from \"./run-model-contract.ts\";\nimport { createImmutableSnapshot } from \"./tool-execution-boundary.ts\";\nimport type {\n\tAfterToolCallContext,\n\tAfterToolCallResult,\n\tAgentContext,\n\tAgentEvent,\n\tAgentLoopConfig,\n\tAgentLoopTurnUpdate,\n\tAgentMessage,\n\tAgentState,\n\tBeforeToolCallContext,\n\tBeforeToolCallResult,\n\tQueueMode,\n\tStreamFn,\n\tToolExecutionMode,\n} from \"./types.ts\";\n\nexport type { QueueMode } from \"./types.ts\";\n\nfunction defaultConvertToLlm(messages: AgentMessage[]): Message[] {\n\treturn messages.filter(\n\t\t(message) => message.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t);\n}\n\n/** Options for constructing an {@link Agent}. */\nexport interface AgentOptions {\n\tinitialState?: Partial<Omit<AgentState, \"pendingToolCalls\" | \"isStreaming\" | \"streamingMessage\" | \"errorMessage\">>;\n\tconvertToLlm?: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\ttransformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\tstreamFn?: StreamFn;\n\tgetApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\tonPayload?: SimpleStreamOptions[\"onPayload\"];\n\tonResponse?: SimpleStreamOptions[\"onResponse\"];\n\tbeforeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;\n\tafterToolCall?: (context: AfterToolCallContext, signal?: AbortSignal) => Promise<AfterToolCallResult | undefined>;\n\tprepareNextTurn?: (\n\t\tsignal?: AbortSignal,\n\t) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;\n\tsteeringMode?: QueueMode;\n\tfollowUpMode?: QueueMode;\n\tsessionId?: string;\n\tthinkingBudgets?: ThinkingBudgets;\n\ttransport?: Transport;\n\tmaxRetryDelayMs?: number;\n\tmaxTurns?: AgentLoopConfig[\"maxTurns\"];\n\t/** Optional immutable logical request policy for this Agent's runs. */\n\tmodelContract?: ModelContract;\n\tmaxTokens?: SimpleStreamOptions[\"maxTokens\"];\n\ttoolExecution?: ToolExecutionMode;\n\ttoolTimeoutMs?: AgentLoopConfig[\"toolTimeoutMs\"];\n\ttoolTimeouts?: AgentLoopConfig[\"toolTimeouts\"];\n\ttoolScheduler?: AgentLoopConfig[\"toolScheduler\"];\n\tmaxToolConcurrency?: AgentLoopConfig[\"maxToolConcurrency\"];\n\tstrictExtensionClaims?: AgentLoopConfig[\"strictExtensionClaims\"];\n\tcwd?: AgentLoopConfig[\"cwd\"];\n\tresourceKeyResolver?: AgentLoopConfig[\"resourceKeyResolver\"];\n\ttoolExecutionPolicy?: AgentLoopConfig[\"toolExecutionPolicy\"];\n}\n\ntype ActiveRun = {\n\tpromise: Promise<void>;\n\tresolve: () => void;\n\tabortController: AbortController;\n};\n\n/**\n * Stateful wrapper around the low-level agent loop.\n *\n * `Agent` owns the current transcript, emits lifecycle events, executes tools,\n * and exposes queueing APIs for steering and follow-up messages.\n */\nexport class Agent {\n\tprivate _state: MutableAgentState;\n\tprivate readonly listeners = new Set<(event: AgentEvent, signal: AbortSignal) => Promise<void> | void>();\n\tprivate readonly steeringQueue: PendingMessageQueue;\n\tprivate readonly followUpQueue: PendingMessageQueue;\n\n\tpublic convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\tpublic transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\tpublic streamFn: StreamFn;\n\tpublic getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\tpublic onPayload?: SimpleStreamOptions[\"onPayload\"];\n\tpublic onResponse?: SimpleStreamOptions[\"onResponse\"];\n\tpublic beforeToolCall?: (\n\t\tcontext: BeforeToolCallContext,\n\t\tsignal?: AbortSignal,\n\t) => Promise<BeforeToolCallResult | undefined>;\n\tpublic afterToolCall?: (\n\t\tcontext: AfterToolCallContext,\n\t\tsignal?: AbortSignal,\n\t) => Promise<AfterToolCallResult | undefined>;\n\tpublic prepareNextTurn?: (\n\t\tsignal?: AbortSignal,\n\t) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;\n\tprivate activeRun?: ActiveRun;\n\t/** Session identifier forwarded to providers for cache-aware backends. */\n\tpublic sessionId?: string;\n\t/** Optional per-level thinking token budgets forwarded to the stream function. */\n\tpublic thinkingBudgets?: ThinkingBudgets;\n\t/** Preferred transport forwarded to the stream function. */\n\tpublic transport: Transport;\n\t/** Optional cap for provider-requested retry delays. */\n\tpublic maxRetryDelayMs?: number;\n\t/** Optional provider-turn budget for each prompt or continuation run. */\n\tpublic maxTurns?: number;\n\t/** Immutable opt-in policy; it is not a serialized provider request guarantee. */\n\tpublic readonly modelContract?: ModelContract;\n\tpublic maxTokens?: number;\n\t/** Tool execution strategy for assistant messages that contain multiple tool calls. */\n\tpublic toolExecution: ToolExecutionMode;\n\t/** Default execution timeout for tools; provider request timeout remains separate. */\n\tpublic toolTimeoutMs?: number;\n\t/** Per-tool-name execution timeout overrides. */\n\tpublic toolTimeouts?: Record<string, number>;\n\t/** Deterministic tool scheduler selection. */\n\tpublic toolScheduler: NonNullable<AgentLoopConfig[\"toolScheduler\"]>;\n\t/** Optional dag-v2 concurrency cap. */\n\tpublic maxToolConcurrency?: number;\n\t/** Require explicit resource claims for parallel extension tools. */\n\tpublic strictExtensionClaims: boolean;\n\t/** Working directory used to resolve path-scoped resource claims. */\n\tpublic cwd?: string;\n\t/** Optional dag-v2 platform identity resolver for path-claim aliases. */\n\tpublic resourceKeyResolver?: AgentLoopConfig[\"resourceKeyResolver\"];\n\t/** Execution-policy defaults (late-settlement audit policy). */\n\tpublic toolExecutionPolicy?: AgentLoopConfig[\"toolExecutionPolicy\"];\n\n\tconstructor(options: AgentOptions = {}) {\n\t\tthis._state = createMutableAgentState(options.initialState);\n\t\tthis.convertToLlm = options.convertToLlm ?? defaultConvertToLlm;\n\t\tthis.transformContext = options.transformContext;\n\t\tthis.streamFn = options.streamFn ?? streamSimple;\n\t\tthis.getApiKey = options.getApiKey;\n\t\tthis.onPayload = options.onPayload;\n\t\tthis.onResponse = options.onResponse;\n\t\tthis.beforeToolCall = options.beforeToolCall;\n\t\tthis.afterToolCall = options.afterToolCall;\n\t\tthis.prepareNextTurn = options.prepareNextTurn;\n\t\tthis.steeringQueue = new PendingMessageQueue(options.steeringMode ?? \"one-at-a-time\");\n\t\tthis.followUpQueue = new PendingMessageQueue(options.followUpMode ?? \"one-at-a-time\");\n\t\tthis.sessionId = options.sessionId;\n\t\tthis.thinkingBudgets = options.thinkingBudgets;\n\t\tthis.transport = options.transport ?? \"auto\";\n\t\tthis.maxRetryDelayMs = options.maxRetryDelayMs;\n\t\tthis.maxTurns = options.maxTurns;\n\t\tthis.modelContract =\n\t\t\toptions.modelContract === undefined ? undefined : snapshotModelContract(options.modelContract);\n\t\tthis.maxTokens = options.maxTokens;\n\t\tthis.toolExecution = options.toolExecution ?? \"parallel\";\n\t\tthis.toolTimeoutMs = options.toolTimeoutMs;\n\t\tthis.toolTimeouts = options.toolTimeouts;\n\t\tthis.toolScheduler = options.toolScheduler ?? \"dag-v2\";\n\t\tthis.maxToolConcurrency = options.maxToolConcurrency;\n\t\tthis.strictExtensionClaims = options.strictExtensionClaims ?? false;\n\t\tthis.cwd = options.cwd;\n\t\tthis.resourceKeyResolver = options.resourceKeyResolver;\n\t\tthis.toolExecutionPolicy = options.toolExecutionPolicy;\n\t}\n\n\t/**\n\t * Subscribe to agent lifecycle events.\n\t *\n\t * Listener promises are awaited in subscription order except for\n\t * observation-only `tool_execution_update` delivery, which is detached so a\n\t * listener cannot delay timeout/abort closure. Listeners receive the active\n\t * abort signal. `agent_end` remains awaited before the agent becomes idle.\n\t */\n\tsubscribe(listener: (event: AgentEvent, signal: AbortSignal) => Promise<void> | void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\t/**\n\t * Current agent state.\n\t *\n\t * Assigning `state.tools` or `state.messages` copies the provided top-level array.\n\t */\n\tget state(): AgentState {\n\t\treturn this._state;\n\t}\n\n\t/** Controls how queued steering messages are drained. */\n\tset steeringMode(mode: QueueMode) {\n\t\tthis.steeringQueue.mode = mode;\n\t}\n\n\tget steeringMode(): QueueMode {\n\t\treturn this.steeringQueue.mode;\n\t}\n\n\t/** Controls how queued follow-up messages are drained. */\n\tset followUpMode(mode: QueueMode) {\n\t\tthis.followUpQueue.mode = mode;\n\t}\n\n\tget followUpMode(): QueueMode {\n\t\treturn this.followUpQueue.mode;\n\t}\n\n\t/** Queue a message to be injected after the current assistant turn finishes. */\n\tsteer(message: AgentMessage): void {\n\t\tthis.steeringQueue.enqueue(message);\n\t}\n\n\t/** Queue a message to run only after the agent would otherwise stop. */\n\tfollowUp(message: AgentMessage): void {\n\t\tthis.followUpQueue.enqueue(message);\n\t}\n\n\t/** Remove all queued steering messages. */\n\tclearSteeringQueue(): void {\n\t\tthis.steeringQueue.clear();\n\t}\n\n\t/** Remove all queued follow-up messages. */\n\tclearFollowUpQueue(): void {\n\t\tthis.followUpQueue.clear();\n\t}\n\n\t/** Remove all queued steering and follow-up messages. */\n\tclearAllQueues(): void {\n\t\tthis.clearSteeringQueue();\n\t\tthis.clearFollowUpQueue();\n\t}\n\n\t/** Returns true when either queue still contains pending messages. */\n\thasQueuedMessages(): boolean {\n\t\treturn this.steeringQueue.hasItems() || this.followUpQueue.hasItems();\n\t}\n\n\t/** Active abort signal for the current run, if any. */\n\tget signal(): AbortSignal | undefined {\n\t\treturn this.activeRun?.abortController.signal;\n\t}\n\n\t/** Abort the current run, if one is active. */\n\tabort(): void {\n\t\tthis.activeRun?.abortController.abort();\n\t}\n\n\t/**\n\t * Resolve when the current run and all awaited event listeners have finished.\n\t *\n\t * This resolves after `agent_end` listeners settle.\n\t */\n\twaitForIdle(): Promise<void> {\n\t\treturn this.activeRun?.promise ?? Promise.resolve();\n\t}\n\n\t/** Clear transcript state, runtime state, and queued messages. */\n\treset(): void {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before resetting.\");\n\t\t}\n\n\t\tthis._state.messages = [];\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis._state.errorMessage = undefined;\n\t\tthis.clearFollowUpQueue();\n\t\tthis.clearSteeringQueue();\n\t}\n\n\t/** Start a new prompt from text, a single message, or a batch of messages. */\n\tasync prompt(message: AgentMessage | AgentMessage[]): Promise<void>;\n\tasync prompt(input: string, images?: ImageContent[]): Promise<void>;\n\tasync prompt(input: string | AgentMessage | AgentMessage[], images?: ImageContent[]): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.\",\n\t\t\t);\n\t\t}\n\t\tconst messages = this.normalizePromptInput(input, images);\n\t\tawait this.runPromptMessages(messages);\n\t}\n\n\t/** Continue from the current transcript. The last message must be a user or tool-result message. */\n\tasync continue(): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before continuing.\");\n\t\t}\n\n\t\tconst lastMessage = this._state.messages[this._state.messages.length - 1];\n\t\tif (!lastMessage) {\n\t\t\tthrow new Error(\"No messages to continue from\");\n\t\t}\n\n\t\tif (lastMessage.role === \"assistant\") {\n\t\t\tconst queuedSteering = this.steeringQueue.drain();\n\t\t\tif (queuedSteering.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedSteering, { skipInitialSteeringPoll: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst queuedFollowUps = this.followUpQueue.drain();\n\t\t\tif (queuedFollowUps.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedFollowUps);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Last message is a completed assistant turn. Two sub-cases:\n\t\t\t// 1. The assistant message carries pending tool calls without matching\n\t\t\t// tool results -> the provider will reject this, so fail fast with a\n\t\t\t// clear, actionable error.\n\t\t\t// 2. The assistant message is plain text/thinking (no tool calls). This is\n\t\t\t// a finished turn (e.g. after compaction, session resume, or an\n\t\t\t// explicit \"continue\" request). We honour it by injecting an empty\n\t\t\t// user prompt so the model can extend its previous answer rather than\n\t\t\t// throwing the opaque \"Cannot continue from message role: assistant\".\n\t\t\tconst hasPendingToolCalls = lastMessage.content.some((c) => c.type === \"toolCall\");\n\t\t\tif (hasPendingToolCalls) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Cannot continue: the last assistant message has pending tool calls without results. \" +\n\t\t\t\t\t\t\"Provide tool results (or a new user message) before continuing.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait this.runPromptMessages([{ role: \"user\", content: [{ type: \"text\", text: \"\" }], timestamp: Date.now() }]);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.runContinuation();\n\t}\n\n\tprivate normalizePromptInput(\n\t\tinput: string | AgentMessage | AgentMessage[],\n\t\timages?: ImageContent[],\n\t): AgentMessage[] {\n\t\tif (Array.isArray(input)) {\n\t\t\treturn input;\n\t\t}\n\n\t\tif (typeof input !== \"string\") {\n\t\t\treturn [input];\n\t\t}\n\n\t\tconst content: Array<TextContent | ImageContent> = [{ type: \"text\", text: input }];\n\t\tif (images && images.length > 0) {\n\t\t\tcontent.push(...images);\n\t\t}\n\t\treturn [{ role: \"user\", content, timestamp: Date.now() }];\n\t}\n\n\tprivate async runPromptMessages(\n\t\tmessages: AgentMessage[],\n\t\toptions: { skipInitialSteeringPoll?: boolean } = {},\n\t): Promise<void> {\n\t\tawait this.runWithLifecycle(async (signal) => {\n\t\t\tawait runAgentLoop(\n\t\t\t\tmessages,\n\t\t\t\tthis.createContextSnapshot(),\n\t\t\t\tthis.createLoopConfig(options),\n\t\t\t\t(event) => this.processEvents(event),\n\t\t\t\tsignal,\n\t\t\t\tthis.streamFn,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate async runContinuation(): Promise<void> {\n\t\tawait this.runWithLifecycle(async (signal) => {\n\t\t\tawait runAgentLoopContinue(\n\t\t\t\tthis.createContextSnapshot(),\n\t\t\t\tthis.createLoopConfig(),\n\t\t\t\t(event) => this.processEvents(event),\n\t\t\t\tsignal,\n\t\t\t\tthis.streamFn,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate createContextSnapshot(): AgentContext {\n\t\treturn {\n\t\t\tsystemPrompt: this._state.systemPrompt,\n\t\t\tsystemPromptCacheBoundary: this._state.systemPromptCacheBoundary,\n\t\t\tsystemPromptCacheBoundaryBypass: this._state.systemPromptCacheBoundaryBypass,\n\t\t\tmessages: this._state.messages.slice(),\n\t\t\ttools: this._state.tools.slice(),\n\t\t};\n\t}\n\n\tprivate createLoopConfig(options: { skipInitialSteeringPoll?: boolean } = {}): AgentLoopConfig {\n\t\tlet skipInitialSteeringPoll = options.skipInitialSteeringPoll === true;\n\t\treturn {\n\t\t\tmodel: this._state.model,\n\t\t\treasoning: this._state.thinkingLevel === \"off\" ? undefined : this._state.thinkingLevel,\n\t\t\tsessionId: this.sessionId,\n\t\t\tonPayload: this.onPayload,\n\t\t\tonResponse: this.onResponse,\n\t\t\ttransport: this.transport,\n\t\t\tthinkingBudgets: this.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: this.maxRetryDelayMs,\n\t\t\tmaxTurns: this.maxTurns,\n\t\t\tmodelContract: this.modelContract,\n\t\t\tmaxTokens: this.maxTokens,\n\t\t\ttoolExecution: this.toolExecution,\n\t\t\ttoolTimeoutMs: this.toolTimeoutMs,\n\t\t\ttoolTimeouts: this.toolTimeouts,\n\t\t\ttoolScheduler: this.toolScheduler,\n\t\t\tmaxToolConcurrency: this.maxToolConcurrency,\n\t\t\tstrictExtensionClaims: this.strictExtensionClaims,\n\t\t\tcwd: this.cwd,\n\t\t\tresourceKeyResolver: this.resourceKeyResolver,\n\t\t\ttoolExecutionPolicy: this.toolExecutionPolicy,\n\t\t\tbeforeToolCall: this.beforeToolCall,\n\t\t\tafterToolCall: this.afterToolCall,\n\t\t\tprepareNextTurn: this.prepareNextTurn ? async () => await this.prepareNextTurn?.(this.signal) : undefined,\n\t\t\tconvertToLlm: this.convertToLlm,\n\t\t\ttransformContext: this.transformContext,\n\t\t\tgetApiKey: this.getApiKey,\n\t\t\tgetSteeringMessages: async () => {\n\t\t\t\tif (skipInitialSteeringPoll) {\n\t\t\t\t\tskipInitialSteeringPoll = false;\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\treturn this.steeringQueue.drain();\n\t\t\t},\n\t\t\tgetFollowUpMessages: async () => this.followUpQueue.drain(),\n\t\t};\n\t}\n\n\tprivate async runWithLifecycle(executor: (signal: AbortSignal) => Promise<void>): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing.\");\n\t\t}\n\n\t\tconst abortController = new AbortController();\n\t\tlet resolvePromise = () => {};\n\t\tconst promise = new Promise<void>((resolve) => {\n\t\t\tresolvePromise = resolve;\n\t\t});\n\t\tthis.activeRun = { promise, resolve: resolvePromise, abortController };\n\n\t\tthis._state.isStreaming = true;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.errorMessage = undefined;\n\n\t\ttry {\n\t\t\tawait executor(abortController.signal);\n\t\t} catch (error) {\n\t\t\tconst failure = error instanceof Error ? error : new Error(String(error));\n\t\t\tawait this.handleRunFailure(failure, abortController.signal.aborted);\n\t\t} finally {\n\t\t\tthis.finishRun();\n\t\t}\n\t}\n\n\tprivate async handleRunFailure(error: unknown, aborted: boolean): Promise<void> {\n\t\t// Apply the same failure-termination contract as the low-level loop so the\n\t\t// disposition of any unresolved tool calls matches transcript repair:\n\t\t// an unambiguous open turn is closed with exactly one synthetic result per\n\t\t// missing call before a single coherent failure assistant, and an ambiguous\n\t\t// transcript fails closed without fabricating a turn over corruption.\n\t\tconst plan = planFailureTermination(this._state.messages, this._state.model, error, aborted);\n\n\t\tfor (const result of plan.closureResults) {\n\t\t\tawait this.processEvents({ type: \"message_start\", message: result });\n\t\t\tawait this.processEvents({ type: \"message_end\", message: result });\n\t\t}\n\n\t\tif (plan.failureMessage) {\n\t\t\tawait this.processEvents({ type: \"message_start\", message: plan.failureMessage });\n\t\t\tawait this.processEvents({ type: \"message_end\", message: plan.failureMessage });\n\t\t\tawait this.processEvents({ type: \"turn_end\", message: plan.failureMessage, toolResults: [] });\n\t\t}\n\n\t\tawait this.processEvents({ type: \"agent_end\", messages: plan.messages });\n\t}\n\n\tprivate finishRun(): void {\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis.activeRun?.resolve();\n\t\tthis.activeRun = undefined;\n\t}\n\n\t/** Reduce state, detach update observation, and await all terminal listeners. */\n\tprivate async processEvents(sourceEvent: AgentEvent): Promise<void> {\n\t\tconst event = createImmutableSnapshot(sourceEvent);\n\t\tswitch (event.type) {\n\t\t\tcase \"message_start\":\n\t\t\t\tthis._state.streamingMessage = event.message;\n\t\t\t\tbreak;\n\n\t\t\tcase \"message_update\":\n\t\t\t\tthis._state.streamingMessage = event.message;\n\t\t\t\tbreak;\n\n\t\t\tcase \"message_end\":\n\t\t\t\tthis._state.streamingMessage = undefined;\n\t\t\t\tthis._state.messages.push(event.message);\n\t\t\t\tbreak;\n\n\t\t\tcase \"tool_execution_start\":\n\t\t\t\tthis._state.pendingToolCalls = new Set(this._state.pendingToolCalls).add(event.toolCallId);\n\t\t\t\tbreak;\n\n\t\t\tcase \"tool_execution_end\": {\n\t\t\t\tconst pendingToolCalls = new Set(this._state.pendingToolCalls);\n\t\t\t\tpendingToolCalls.delete(event.toolCallId);\n\t\t\t\tthis._state.pendingToolCalls = pendingToolCalls;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"turn_end\":\n\t\t\t\tif (event.message.role === \"assistant\" && event.message.errorMessage) {\n\t\t\t\t\tthis._state.errorMessage = event.message.errorMessage;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"agent_end\":\n\t\t\t\tthis._state.streamingMessage = undefined;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst signal = this.activeRun?.abortController.signal;\n\t\tif (!signal) {\n\t\t\t// A tool's real promise may settle after the run already ended. The\n\t\t\t// late-settlement event is audit-only by contract, so it is still\n\t\t\t// delivered (with an inert signal) instead of being dropped; every\n\t\t\t// other event outside an active run remains a hard invariant break.\n\t\t\tif (event.type === \"tool_execution_late_settlement\") {\n\t\t\t\tawait deliverToListeners(this.listeners, event, new AbortController().signal);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(\"Agent listener invoked outside active run\");\n\t\t}\n\t\tif (event.type === \"tool_execution_update\") {\n\t\t\tfor (const listener of this.listeners) {\n\t\t\t\tconst snapshot = createImmutableSnapshot(event);\n\t\t\t\tvoid Promise.resolve()\n\t\t\t\t\t.then(() => listener(snapshot, signal))\n\t\t\t\t\t.catch(() => undefined);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tawait deliverToListeners(this.listeners, event, signal);\n\t}\n}\n"]}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,KAAK,mBAAmB,EAGxB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,MAAM,QAAQ,CAAC;AAKhB,OAAO,EAAE,KAAK,aAAa,EAAyB,MAAM,yBAAyB,CAAC;AAEpF,OAAO,KAAK,EACX,oBAAoB,EACpB,mBAAmB,EAEnB,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,SAAS,EACT,QAAQ,EACR,iBAAiB,EACjB,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAQ5C,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,kBAAkB,GAAG,aAAa,GAAG,kBAAkB,GAAG,cAAc,CAAC,CAAC,CAAC;IACnH,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5E,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC/F,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;IACnF,SAAS,CAAC,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAC7C,UAAU,CAAC,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,qBAAqB,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAAC;IACrH,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAAC;IAClH,eAAe,CAAC,EAAE,CACjB,MAAM,CAAC,EAAE,WAAW,KAChB,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,GAAG,mBAAmB,GAAG,SAAS,CAAC;IAChF,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IACvC,uEAAuE;IACvE,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,aAAa,CAAC,EAAE,eAAe,CAAC,eAAe,CAAC,CAAC;IACjD,YAAY,CAAC,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE,eAAe,CAAC,eAAe,CAAC,CAAC;IACjD,kBAAkB,CAAC,EAAE,eAAe,CAAC,oBAAoB,CAAC,CAAC;IAC3D,qBAAqB,CAAC,EAAE,eAAe,CAAC,uBAAuB,CAAC,CAAC;IACjE,GAAG,CAAC,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;IAC7B,mBAAmB,CAAC,EAAE,eAAe,CAAC,qBAAqB,CAAC,CAAC;IAC7D,mBAAmB,CAAC,EAAE,eAAe,CAAC,qBAAqB,CAAC,CAAC;CAC7D;AAQD;;;;;GAKG;AACH,qBAAa,KAAK;IACjB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA+E;IACzG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IAE7C,YAAY,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3E,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC/F,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;IACnF,SAAS,CAAC,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAC7C,UAAU,CAAC,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,CACvB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,CAAC,EAAE,WAAW,KAChB,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,CACtB,OAAO,EAAE,oBAAoB,EAC7B,MAAM,CAAC,EAAE,WAAW,KAChB,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAAC;IACvC,eAAe,CAAC,EAAE,CACxB,MAAM,CAAC,EAAE,WAAW,KAChB,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,GAAG,mBAAmB,GAAG,SAAS,CAAC;IAChF;;;OAGG;IACI,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,SAAS,EAAE,CAAC;IAC5F,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,0EAA0E;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IAC1B,kFAAkF;IAC3E,eAAe,CAAC,EAAE,eAAe,CAAC;IACzC,4DAA4D;IACrD,SAAS,EAAE,SAAS,CAAC;IAC5B,wDAAwD;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC;IAChC,yEAAyE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IACzB,kFAAkF;IAClF,SAAgB,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC1B,uFAAuF;IAChF,aAAa,EAAE,iBAAiB,CAAC;IACxC,sFAAsF;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;IAC9B,iDAAiD;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,8CAA8C;IACvC,aAAa,EAAE,WAAW,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC;IACpE,uCAAuC;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACnC,qEAAqE;IAC9D,qBAAqB,EAAE,OAAO,CAAC;IACtC,qEAAqE;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IAClE,mBAAmB,CAAC,EAAE,eAAe,CAAC,qBAAqB,CAAC,CAAC;IACpE,gEAAgE;IACzD,mBAAmB,CAAC,EAAE,eAAe,CAAC,qBAAqB,CAAC,CAAC;IAEpE,YAAY,OAAO,GAAE,YAAiB,EA8BrC;IAED;;;;;;;OAOG;IACH,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,MAAM,IAAI,CAGhG;IAED;;;;OAIG;IACH,IAAI,KAAK,IAAI,UAAU,CAEtB;IAED,yDAAyD;IACzD,IAAI,YAAY,CAAC,IAAI,EAAE,SAAS,EAE/B;IAED,IAAI,YAAY,IAAI,SAAS,CAE5B;IAED,0DAA0D;IAC1D,IAAI,YAAY,CAAC,IAAI,EAAE,SAAS,EAE/B;IAED,IAAI,YAAY,IAAI,SAAS,CAE5B;IAED,gFAAgF;IAChF,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEjC;IAED,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEpC;IAED,2CAA2C;IAC3C,kBAAkB,IAAI,IAAI,CAEzB;IAED,4CAA4C;IAC5C,kBAAkB,IAAI,IAAI,CAEzB;IAED,yDAAyD;IACzD,cAAc,IAAI,IAAI,CAGrB;IAED,sEAAsE;IACtE,iBAAiB,IAAI,OAAO,CAE3B;IAED,uDAAuD;IACvD,IAAI,MAAM,IAAI,WAAW,GAAG,SAAS,CAEpC;IAED,+CAA+C;IAC/C,KAAK,IAAI,IAAI,CAEZ;IAED;;;;OAIG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED,kEAAkE;IAClE,KAAK,IAAI,IAAI,CAYZ;IAED,8EAA8E;IACxE,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAWpE,oGAAoG;IAC9F,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CA6C9B;IAED,OAAO,CAAC,oBAAoB;YAiBd,iBAAiB;YAgBjB,eAAe;IAY7B,OAAO,CAAC,qBAAqB;IAU7B,OAAO,CAAC,gBAAgB;YAwCV,gBAAgB;YA0BhB,gBAAgB;IAsB9B,OAAO,CAAC,SAAS;YASH,aAAa;CA6D3B","sourcesContent":["import {\n\ttype ImageContent,\n\ttype Message,\n\ttype SimpleStreamOptions,\n\tstreamSimple,\n\ttype TextContent,\n\ttype ThinkingBudgets,\n\ttype Transport,\n} from \"omk-ai\";\nimport { planFailureTermination, runAgentLoop, runAgentLoopContinue } from \"./agent-loop.ts\";\nimport { createMutableAgentState, type MutableAgentState } from \"./agent-state.ts\";\nimport { deliverToListeners } from \"./listener-delivery.ts\";\nimport { PendingMessageQueue } from \"./pending-message-queue.ts\";\nimport { type ModelContract, snapshotModelContract } from \"./run-model-contract.ts\";\nimport { createImmutableSnapshot } from \"./tool-execution-boundary.ts\";\nimport type {\n\tAfterToolCallContext,\n\tAfterToolCallResult,\n\tAgentContext,\n\tAgentEvent,\n\tAgentLoopConfig,\n\tAgentLoopTurnUpdate,\n\tAgentMessage,\n\tAgentState,\n\tAgentTool,\n\tBeforeToolCallContext,\n\tBeforeToolCallResult,\n\tQueueMode,\n\tStreamFn,\n\tToolExecutionMode,\n} from \"./types.ts\";\n\nexport type { QueueMode } from \"./types.ts\";\n\nfunction defaultConvertToLlm(messages: AgentMessage[]): Message[] {\n\treturn messages.filter(\n\t\t(message) => message.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t);\n}\n\n/** Options for constructing an {@link Agent}. */\nexport interface AgentOptions {\n\tinitialState?: Partial<Omit<AgentState, \"pendingToolCalls\" | \"isStreaming\" | \"streamingMessage\" | \"errorMessage\">>;\n\tconvertToLlm?: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\ttransformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\tstreamFn?: StreamFn;\n\tgetApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\tonPayload?: SimpleStreamOptions[\"onPayload\"];\n\tonResponse?: SimpleStreamOptions[\"onResponse\"];\n\tbeforeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;\n\tafterToolCall?: (context: AfterToolCallContext, signal?: AbortSignal) => Promise<AfterToolCallResult | undefined>;\n\tprepareNextTurn?: (\n\t\tsignal?: AbortSignal,\n\t) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;\n\tsteeringMode?: QueueMode;\n\tfollowUpMode?: QueueMode;\n\tsessionId?: string;\n\tthinkingBudgets?: ThinkingBudgets;\n\ttransport?: Transport;\n\tmaxRetryDelayMs?: number;\n\tmaxTurns?: AgentLoopConfig[\"maxTurns\"];\n\t/** Optional immutable logical request policy for this Agent's runs. */\n\tmodelContract?: ModelContract;\n\tmaxTokens?: SimpleStreamOptions[\"maxTokens\"];\n\ttoolExecution?: ToolExecutionMode;\n\ttoolTimeoutMs?: AgentLoopConfig[\"toolTimeoutMs\"];\n\ttoolTimeouts?: AgentLoopConfig[\"toolTimeouts\"];\n\ttoolScheduler?: AgentLoopConfig[\"toolScheduler\"];\n\tmaxToolConcurrency?: AgentLoopConfig[\"maxToolConcurrency\"];\n\tstrictExtensionClaims?: AgentLoopConfig[\"strictExtensionClaims\"];\n\tcwd?: AgentLoopConfig[\"cwd\"];\n\tresourceKeyResolver?: AgentLoopConfig[\"resourceKeyResolver\"];\n\ttoolExecutionPolicy?: AgentLoopConfig[\"toolExecutionPolicy\"];\n}\n\ntype ActiveRun = {\n\tpromise: Promise<void>;\n\tresolve: () => void;\n\tabortController: AbortController;\n};\n\n/**\n * Stateful wrapper around the low-level agent loop.\n *\n * `Agent` owns the current transcript, emits lifecycle events, executes tools,\n * and exposes queueing APIs for steering and follow-up messages.\n */\nexport class Agent {\n\tprivate _state: MutableAgentState;\n\tprivate readonly listeners = new Set<(event: AgentEvent, signal: AbortSignal) => Promise<void> | void>();\n\tprivate readonly steeringQueue: PendingMessageQueue;\n\tprivate readonly followUpQueue: PendingMessageQueue;\n\n\tpublic convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\tpublic transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\tpublic streamFn: StreamFn;\n\tpublic getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\tpublic onPayload?: SimpleStreamOptions[\"onPayload\"];\n\tpublic onResponse?: SimpleStreamOptions[\"onResponse\"];\n\tpublic beforeToolCall?: (\n\t\tcontext: BeforeToolCallContext,\n\t\tsignal?: AbortSignal,\n\t) => Promise<BeforeToolCallResult | undefined>;\n\tpublic afterToolCall?: (\n\t\tcontext: AfterToolCallContext,\n\t\tsignal?: AbortSignal,\n\t) => Promise<AfterToolCallResult | undefined>;\n\tpublic prepareNextTurn?: (\n\t\tsignal?: AbortSignal,\n\t) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;\n\t/**\n\t * Selects the tools a run sends to the provider, e.g. to fit the model's input window.\n\t * `pending` holds prompt messages not yet in `state.messages`; active tools are never mutated.\n\t */\n\tpublic prepareTools?: (tools: AgentTool[], pending: readonly AgentMessage[]) => AgentTool[];\n\tprivate activeRun?: ActiveRun;\n\t/** Session identifier forwarded to providers for cache-aware backends. */\n\tpublic sessionId?: string;\n\t/** Optional per-level thinking token budgets forwarded to the stream function. */\n\tpublic thinkingBudgets?: ThinkingBudgets;\n\t/** Preferred transport forwarded to the stream function. */\n\tpublic transport: Transport;\n\t/** Optional cap for provider-requested retry delays. */\n\tpublic maxRetryDelayMs?: number;\n\t/** Optional provider-turn budget for each prompt or continuation run. */\n\tpublic maxTurns?: number;\n\t/** Immutable opt-in policy; it is not a serialized provider request guarantee. */\n\tpublic readonly modelContract?: ModelContract;\n\tpublic maxTokens?: number;\n\t/** Tool execution strategy for assistant messages that contain multiple tool calls. */\n\tpublic toolExecution: ToolExecutionMode;\n\t/** Default execution timeout for tools; provider request timeout remains separate. */\n\tpublic toolTimeoutMs?: number;\n\t/** Per-tool-name execution timeout overrides. */\n\tpublic toolTimeouts?: Record<string, number>;\n\t/** Deterministic tool scheduler selection. */\n\tpublic toolScheduler: NonNullable<AgentLoopConfig[\"toolScheduler\"]>;\n\t/** Optional dag-v2 concurrency cap. */\n\tpublic maxToolConcurrency?: number;\n\t/** Require explicit resource claims for parallel extension tools. */\n\tpublic strictExtensionClaims: boolean;\n\t/** Working directory used to resolve path-scoped resource claims. */\n\tpublic cwd?: string;\n\t/** Optional dag-v2 platform identity resolver for path-claim aliases. */\n\tpublic resourceKeyResolver?: AgentLoopConfig[\"resourceKeyResolver\"];\n\t/** Execution-policy defaults (late-settlement audit policy). */\n\tpublic toolExecutionPolicy?: AgentLoopConfig[\"toolExecutionPolicy\"];\n\n\tconstructor(options: AgentOptions = {}) {\n\t\tthis._state = createMutableAgentState(options.initialState);\n\t\tthis.convertToLlm = options.convertToLlm ?? defaultConvertToLlm;\n\t\tthis.transformContext = options.transformContext;\n\t\tthis.streamFn = options.streamFn ?? streamSimple;\n\t\tthis.getApiKey = options.getApiKey;\n\t\tthis.onPayload = options.onPayload;\n\t\tthis.onResponse = options.onResponse;\n\t\tthis.beforeToolCall = options.beforeToolCall;\n\t\tthis.afterToolCall = options.afterToolCall;\n\t\tthis.prepareNextTurn = options.prepareNextTurn;\n\t\tthis.steeringQueue = new PendingMessageQueue(options.steeringMode ?? \"one-at-a-time\");\n\t\tthis.followUpQueue = new PendingMessageQueue(options.followUpMode ?? \"one-at-a-time\");\n\t\tthis.sessionId = options.sessionId;\n\t\tthis.thinkingBudgets = options.thinkingBudgets;\n\t\tthis.transport = options.transport ?? \"auto\";\n\t\tthis.maxRetryDelayMs = options.maxRetryDelayMs;\n\t\tthis.maxTurns = options.maxTurns;\n\t\tthis.modelContract =\n\t\t\toptions.modelContract === undefined ? undefined : snapshotModelContract(options.modelContract);\n\t\tthis.maxTokens = options.maxTokens;\n\t\tthis.toolExecution = options.toolExecution ?? \"parallel\";\n\t\tthis.toolTimeoutMs = options.toolTimeoutMs;\n\t\tthis.toolTimeouts = options.toolTimeouts;\n\t\tthis.toolScheduler = options.toolScheduler ?? \"dag-v2\";\n\t\tthis.maxToolConcurrency = options.maxToolConcurrency;\n\t\tthis.strictExtensionClaims = options.strictExtensionClaims ?? false;\n\t\tthis.cwd = options.cwd;\n\t\tthis.resourceKeyResolver = options.resourceKeyResolver;\n\t\tthis.toolExecutionPolicy = options.toolExecutionPolicy;\n\t}\n\n\t/**\n\t * Subscribe to agent lifecycle events.\n\t *\n\t * Listener promises are awaited in subscription order except for\n\t * observation-only `tool_execution_update` delivery, which is detached so a\n\t * listener cannot delay timeout/abort closure. Listeners receive the active\n\t * abort signal. `agent_end` remains awaited before the agent becomes idle.\n\t */\n\tsubscribe(listener: (event: AgentEvent, signal: AbortSignal) => Promise<void> | void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\t/**\n\t * Current agent state.\n\t *\n\t * Assigning `state.tools` or `state.messages` copies the provided top-level array.\n\t */\n\tget state(): AgentState {\n\t\treturn this._state;\n\t}\n\n\t/** Controls how queued steering messages are drained. */\n\tset steeringMode(mode: QueueMode) {\n\t\tthis.steeringQueue.mode = mode;\n\t}\n\n\tget steeringMode(): QueueMode {\n\t\treturn this.steeringQueue.mode;\n\t}\n\n\t/** Controls how queued follow-up messages are drained. */\n\tset followUpMode(mode: QueueMode) {\n\t\tthis.followUpQueue.mode = mode;\n\t}\n\n\tget followUpMode(): QueueMode {\n\t\treturn this.followUpQueue.mode;\n\t}\n\n\t/** Queue a message to be injected after the current assistant turn finishes. */\n\tsteer(message: AgentMessage): void {\n\t\tthis.steeringQueue.enqueue(message);\n\t}\n\n\t/** Queue a message to run only after the agent would otherwise stop. */\n\tfollowUp(message: AgentMessage): void {\n\t\tthis.followUpQueue.enqueue(message);\n\t}\n\n\t/** Remove all queued steering messages. */\n\tclearSteeringQueue(): void {\n\t\tthis.steeringQueue.clear();\n\t}\n\n\t/** Remove all queued follow-up messages. */\n\tclearFollowUpQueue(): void {\n\t\tthis.followUpQueue.clear();\n\t}\n\n\t/** Remove all queued steering and follow-up messages. */\n\tclearAllQueues(): void {\n\t\tthis.clearSteeringQueue();\n\t\tthis.clearFollowUpQueue();\n\t}\n\n\t/** Returns true when either queue still contains pending messages. */\n\thasQueuedMessages(): boolean {\n\t\treturn this.steeringQueue.hasItems() || this.followUpQueue.hasItems();\n\t}\n\n\t/** Active abort signal for the current run, if any. */\n\tget signal(): AbortSignal | undefined {\n\t\treturn this.activeRun?.abortController.signal;\n\t}\n\n\t/** Abort the current run, if one is active. */\n\tabort(): void {\n\t\tthis.activeRun?.abortController.abort();\n\t}\n\n\t/**\n\t * Resolve when the current run and all awaited event listeners have finished.\n\t *\n\t * This resolves after `agent_end` listeners settle.\n\t */\n\twaitForIdle(): Promise<void> {\n\t\treturn this.activeRun?.promise ?? Promise.resolve();\n\t}\n\n\t/** Clear transcript state, runtime state, and queued messages. */\n\treset(): void {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before resetting.\");\n\t\t}\n\n\t\tthis._state.messages = [];\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis._state.errorMessage = undefined;\n\t\tthis.clearFollowUpQueue();\n\t\tthis.clearSteeringQueue();\n\t}\n\n\t/** Start a new prompt from text, a single message, or a batch of messages. */\n\tasync prompt(message: AgentMessage | AgentMessage[]): Promise<void>;\n\tasync prompt(input: string, images?: ImageContent[]): Promise<void>;\n\tasync prompt(input: string | AgentMessage | AgentMessage[], images?: ImageContent[]): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.\",\n\t\t\t);\n\t\t}\n\t\tconst messages = this.normalizePromptInput(input, images);\n\t\tawait this.runPromptMessages(messages);\n\t}\n\n\t/** Continue from the current transcript. The last message must be a user or tool-result message. */\n\tasync continue(): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before continuing.\");\n\t\t}\n\n\t\tconst lastMessage = this._state.messages[this._state.messages.length - 1];\n\t\tif (!lastMessage) {\n\t\t\tthrow new Error(\"No messages to continue from\");\n\t\t}\n\n\t\tif (lastMessage.role === \"assistant\") {\n\t\t\tconst queuedSteering = this.steeringQueue.drain();\n\t\t\tif (queuedSteering.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedSteering, { skipInitialSteeringPoll: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst queuedFollowUps = this.followUpQueue.drain();\n\t\t\tif (queuedFollowUps.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedFollowUps);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Last message is a completed assistant turn. Two sub-cases:\n\t\t\t// 1. The assistant message carries pending tool calls without matching\n\t\t\t// tool results -> the provider will reject this, so fail fast with a\n\t\t\t// clear, actionable error.\n\t\t\t// 2. The assistant message is plain text/thinking (no tool calls). This is\n\t\t\t// a finished turn (e.g. after compaction, session resume, or an\n\t\t\t// explicit \"continue\" request). We honour it by injecting an empty\n\t\t\t// user prompt so the model can extend its previous answer rather than\n\t\t\t// throwing the opaque \"Cannot continue from message role: assistant\".\n\t\t\tconst hasPendingToolCalls = lastMessage.content.some((c) => c.type === \"toolCall\");\n\t\t\tif (hasPendingToolCalls) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Cannot continue: the last assistant message has pending tool calls without results. \" +\n\t\t\t\t\t\t\"Provide tool results (or a new user message) before continuing.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait this.runPromptMessages([{ role: \"user\", content: [{ type: \"text\", text: \"\" }], timestamp: Date.now() }]);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.runContinuation();\n\t}\n\n\tprivate normalizePromptInput(\n\t\tinput: string | AgentMessage | AgentMessage[],\n\t\timages?: ImageContent[],\n\t): AgentMessage[] {\n\t\tif (Array.isArray(input)) return input;\n\n\t\tif (typeof input !== \"string\") {\n\t\t\treturn [input];\n\t\t}\n\n\t\tconst content: Array<TextContent | ImageContent> = [{ type: \"text\", text: input }];\n\t\tif (images && images.length > 0) {\n\t\t\tcontent.push(...images);\n\t\t}\n\t\treturn [{ role: \"user\", content, timestamp: Date.now() }];\n\t}\n\n\tprivate async runPromptMessages(\n\t\tmessages: AgentMessage[],\n\t\toptions: { skipInitialSteeringPoll?: boolean } = {},\n\t): Promise<void> {\n\t\tawait this.runWithLifecycle(async (signal) => {\n\t\t\tawait runAgentLoop(\n\t\t\t\tmessages,\n\t\t\t\tthis.createContextSnapshot(messages),\n\t\t\t\tthis.createLoopConfig(options),\n\t\t\t\t(event) => this.processEvents(event),\n\t\t\t\tsignal,\n\t\t\t\tthis.streamFn,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate async runContinuation(): Promise<void> {\n\t\tawait this.runWithLifecycle(async (signal) => {\n\t\t\tawait runAgentLoopContinue(\n\t\t\t\tthis.createContextSnapshot(),\n\t\t\t\tthis.createLoopConfig(),\n\t\t\t\t(event) => this.processEvents(event),\n\t\t\t\tsignal,\n\t\t\t\tthis.streamFn,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate createContextSnapshot(pending: readonly AgentMessage[] = []): AgentContext {\n\t\treturn {\n\t\t\tsystemPrompt: this._state.systemPrompt,\n\t\t\tsystemPromptCacheBoundary: this._state.systemPromptCacheBoundary,\n\t\t\tsystemPromptCacheBoundaryBypass: this._state.systemPromptCacheBoundaryBypass,\n\t\t\tmessages: this._state.messages.slice(),\n\t\t\ttools: (this.prepareTools?.(this._state.tools.slice(), pending) ?? this._state.tools).slice(),\n\t\t};\n\t}\n\n\tprivate createLoopConfig(options: { skipInitialSteeringPoll?: boolean } = {}): AgentLoopConfig {\n\t\tlet skipInitialSteeringPoll = options.skipInitialSteeringPoll === true;\n\t\treturn {\n\t\t\tmodel: this._state.model,\n\t\t\treasoning: this._state.thinkingLevel === \"off\" ? undefined : this._state.thinkingLevel,\n\t\t\tsessionId: this.sessionId,\n\t\t\tonPayload: this.onPayload,\n\t\t\tonResponse: this.onResponse,\n\t\t\ttransport: this.transport,\n\t\t\tthinkingBudgets: this.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: this.maxRetryDelayMs,\n\t\t\tmaxTurns: this.maxTurns,\n\t\t\tmodelContract: this.modelContract,\n\t\t\tmaxTokens: this.maxTokens,\n\t\t\ttoolExecution: this.toolExecution,\n\t\t\ttoolTimeoutMs: this.toolTimeoutMs,\n\t\t\ttoolTimeouts: this.toolTimeouts,\n\t\t\ttoolScheduler: this.toolScheduler,\n\t\t\tmaxToolConcurrency: this.maxToolConcurrency,\n\t\t\tstrictExtensionClaims: this.strictExtensionClaims,\n\t\t\tcwd: this.cwd,\n\t\t\tresourceKeyResolver: this.resourceKeyResolver,\n\t\t\ttoolExecutionPolicy: this.toolExecutionPolicy,\n\t\t\tbeforeToolCall: this.beforeToolCall,\n\t\t\tafterToolCall: this.afterToolCall,\n\t\t\tprepareNextTurn: this.prepareNextTurn ? async () => await this.prepareNextTurn?.(this.signal) : undefined,\n\t\t\tconvertToLlm: this.convertToLlm,\n\t\t\ttransformContext: this.transformContext,\n\t\t\tgetApiKey: this.getApiKey,\n\t\t\tgetSteeringMessages: async () => {\n\t\t\t\tif (skipInitialSteeringPoll) {\n\t\t\t\t\tskipInitialSteeringPoll = false;\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\treturn this.steeringQueue.drain();\n\t\t\t},\n\t\t\tgetFollowUpMessages: async () => this.followUpQueue.drain(),\n\t\t};\n\t}\n\n\tprivate async runWithLifecycle(executor: (signal: AbortSignal) => Promise<void>): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing.\");\n\t\t}\n\n\t\tconst abortController = new AbortController();\n\t\tlet resolvePromise = () => {};\n\t\tconst promise = new Promise<void>((resolve) => {\n\t\t\tresolvePromise = resolve;\n\t\t});\n\t\tthis.activeRun = { promise, resolve: resolvePromise, abortController };\n\n\t\tthis._state.isStreaming = true;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.errorMessage = undefined;\n\n\t\ttry {\n\t\t\tawait executor(abortController.signal);\n\t\t} catch (error) {\n\t\t\tconst failure = error instanceof Error ? error : new Error(String(error));\n\t\t\tawait this.handleRunFailure(failure, abortController.signal.aborted);\n\t\t} finally {\n\t\t\tthis.finishRun();\n\t\t}\n\t}\n\n\tprivate async handleRunFailure(error: unknown, aborted: boolean): Promise<void> {\n\t\t// Apply the same failure-termination contract as the low-level loop so the\n\t\t// disposition of any unresolved tool calls matches transcript repair:\n\t\t// an unambiguous open turn is closed with exactly one synthetic result per\n\t\t// missing call before a single coherent failure assistant, and an ambiguous\n\t\t// transcript fails closed without fabricating a turn over corruption.\n\t\tconst plan = planFailureTermination(this._state.messages, this._state.model, error, aborted);\n\n\t\tfor (const result of plan.closureResults) {\n\t\t\tawait this.processEvents({ type: \"message_start\", message: result });\n\t\t\tawait this.processEvents({ type: \"message_end\", message: result });\n\t\t}\n\n\t\tif (plan.failureMessage) {\n\t\t\tawait this.processEvents({ type: \"message_start\", message: plan.failureMessage });\n\t\t\tawait this.processEvents({ type: \"message_end\", message: plan.failureMessage });\n\t\t\tawait this.processEvents({ type: \"turn_end\", message: plan.failureMessage, toolResults: [] });\n\t\t}\n\n\t\tawait this.processEvents({ type: \"agent_end\", messages: plan.messages });\n\t}\n\n\tprivate finishRun(): void {\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis.activeRun?.resolve();\n\t\tthis.activeRun = undefined;\n\t}\n\n\t/** Reduce state, detach update observation, and await all terminal listeners. */\n\tprivate async processEvents(sourceEvent: AgentEvent): Promise<void> {\n\t\tconst event = createImmutableSnapshot(sourceEvent);\n\t\tswitch (event.type) {\n\t\t\tcase \"message_start\":\n\t\t\t\tthis._state.streamingMessage = event.message;\n\t\t\t\tbreak;\n\n\t\t\tcase \"message_update\":\n\t\t\t\tthis._state.streamingMessage = event.message;\n\t\t\t\tbreak;\n\n\t\t\tcase \"message_end\":\n\t\t\t\tthis._state.streamingMessage = undefined;\n\t\t\t\tthis._state.messages.push(event.message);\n\t\t\t\tbreak;\n\n\t\t\tcase \"tool_execution_start\":\n\t\t\t\tthis._state.pendingToolCalls = new Set(this._state.pendingToolCalls).add(event.toolCallId);\n\t\t\t\tbreak;\n\n\t\t\tcase \"tool_execution_end\": {\n\t\t\t\tconst pendingToolCalls = new Set(this._state.pendingToolCalls);\n\t\t\t\tpendingToolCalls.delete(event.toolCallId);\n\t\t\t\tthis._state.pendingToolCalls = pendingToolCalls;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"turn_end\":\n\t\t\t\tif (event.message.role === \"assistant\" && event.message.errorMessage) {\n\t\t\t\t\tthis._state.errorMessage = event.message.errorMessage;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"agent_end\":\n\t\t\t\tthis._state.streamingMessage = undefined;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst signal = this.activeRun?.abortController.signal;\n\t\tif (!signal) {\n\t\t\t// A tool's real promise may settle after the run already ended. The\n\t\t\t// late-settlement event is audit-only by contract, so it is still\n\t\t\t// delivered (with an inert signal) instead of being dropped; every\n\t\t\t// other event outside an active run remains a hard invariant break.\n\t\t\tif (event.type === \"tool_execution_late_settlement\") {\n\t\t\t\tawait deliverToListeners(this.listeners, event, new AbortController().signal);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(\"Agent listener invoked outside active run\");\n\t\t}\n\t\tif (event.type === \"tool_execution_update\") {\n\t\t\tfor (const listener of this.listeners) {\n\t\t\t\tconst snapshot = createImmutableSnapshot(event);\n\t\t\t\tvoid Promise.resolve()\n\t\t\t\t\t.then(() => listener(snapshot, signal))\n\t\t\t\t\t.catch(() => undefined);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tawait deliverToListeners(this.listeners, event, signal);\n\t}\n}\n"]}
package/dist/agent.js CHANGED
@@ -28,6 +28,11 @@ export class Agent {
28
28
  beforeToolCall;
29
29
  afterToolCall;
30
30
  prepareNextTurn;
31
+ /**
32
+ * Selects the tools a run sends to the provider, e.g. to fit the model's input window.
33
+ * `pending` holds prompt messages not yet in `state.messages`; active tools are never mutated.
34
+ */
35
+ prepareTools;
31
36
  activeRun;
32
37
  /** Session identifier forwarded to providers for cache-aware backends. */
33
38
  sessionId;
@@ -226,9 +231,8 @@ export class Agent {
226
231
  await this.runContinuation();
227
232
  }
228
233
  normalizePromptInput(input, images) {
229
- if (Array.isArray(input)) {
234
+ if (Array.isArray(input))
230
235
  return input;
231
- }
232
236
  if (typeof input !== "string") {
233
237
  return [input];
234
238
  }
@@ -240,7 +244,7 @@ export class Agent {
240
244
  }
241
245
  async runPromptMessages(messages, options = {}) {
242
246
  await this.runWithLifecycle(async (signal) => {
243
- await runAgentLoop(messages, this.createContextSnapshot(), this.createLoopConfig(options), (event) => this.processEvents(event), signal, this.streamFn);
247
+ await runAgentLoop(messages, this.createContextSnapshot(messages), this.createLoopConfig(options), (event) => this.processEvents(event), signal, this.streamFn);
244
248
  });
245
249
  }
246
250
  async runContinuation() {
@@ -248,13 +252,13 @@ export class Agent {
248
252
  await runAgentLoopContinue(this.createContextSnapshot(), this.createLoopConfig(), (event) => this.processEvents(event), signal, this.streamFn);
249
253
  });
250
254
  }
251
- createContextSnapshot() {
255
+ createContextSnapshot(pending = []) {
252
256
  return {
253
257
  systemPrompt: this._state.systemPrompt,
254
258
  systemPromptCacheBoundary: this._state.systemPromptCacheBoundary,
255
259
  systemPromptCacheBoundaryBypass: this._state.systemPromptCacheBoundaryBypass,
256
260
  messages: this._state.messages.slice(),
257
- tools: this._state.tools.slice(),
261
+ tools: (this.prepareTools?.(this._state.tools.slice(), pending) ?? this._state.tools).slice(),
258
262
  };
259
263
  }
260
264
  createLoopConfig(options = {}) {
package/dist/agent.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ImageContent,\n\ttype Message,\n\ttype SimpleStreamOptions,\n\tstreamSimple,\n\ttype TextContent,\n\ttype ThinkingBudgets,\n\ttype Transport,\n} from \"omk-ai\";\nimport { planFailureTermination, runAgentLoop, runAgentLoopContinue } from \"./agent-loop.ts\";\nimport { createMutableAgentState, type MutableAgentState } from \"./agent-state.ts\";\nimport { deliverToListeners } from \"./listener-delivery.ts\";\nimport { PendingMessageQueue } from \"./pending-message-queue.ts\";\nimport { type ModelContract, snapshotModelContract } from \"./run-model-contract.ts\";\nimport { createImmutableSnapshot } from \"./tool-execution-boundary.ts\";\nimport type {\n\tAfterToolCallContext,\n\tAfterToolCallResult,\n\tAgentContext,\n\tAgentEvent,\n\tAgentLoopConfig,\n\tAgentLoopTurnUpdate,\n\tAgentMessage,\n\tAgentState,\n\tBeforeToolCallContext,\n\tBeforeToolCallResult,\n\tQueueMode,\n\tStreamFn,\n\tToolExecutionMode,\n} from \"./types.ts\";\n\nexport type { QueueMode } from \"./types.ts\";\n\nfunction defaultConvertToLlm(messages: AgentMessage[]): Message[] {\n\treturn messages.filter(\n\t\t(message) => message.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t);\n}\n\n/** Options for constructing an {@link Agent}. */\nexport interface AgentOptions {\n\tinitialState?: Partial<Omit<AgentState, \"pendingToolCalls\" | \"isStreaming\" | \"streamingMessage\" | \"errorMessage\">>;\n\tconvertToLlm?: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\ttransformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\tstreamFn?: StreamFn;\n\tgetApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\tonPayload?: SimpleStreamOptions[\"onPayload\"];\n\tonResponse?: SimpleStreamOptions[\"onResponse\"];\n\tbeforeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;\n\tafterToolCall?: (context: AfterToolCallContext, signal?: AbortSignal) => Promise<AfterToolCallResult | undefined>;\n\tprepareNextTurn?: (\n\t\tsignal?: AbortSignal,\n\t) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;\n\tsteeringMode?: QueueMode;\n\tfollowUpMode?: QueueMode;\n\tsessionId?: string;\n\tthinkingBudgets?: ThinkingBudgets;\n\ttransport?: Transport;\n\tmaxRetryDelayMs?: number;\n\tmaxTurns?: AgentLoopConfig[\"maxTurns\"];\n\t/** Optional immutable logical request policy for this Agent's runs. */\n\tmodelContract?: ModelContract;\n\tmaxTokens?: SimpleStreamOptions[\"maxTokens\"];\n\ttoolExecution?: ToolExecutionMode;\n\ttoolTimeoutMs?: AgentLoopConfig[\"toolTimeoutMs\"];\n\ttoolTimeouts?: AgentLoopConfig[\"toolTimeouts\"];\n\ttoolScheduler?: AgentLoopConfig[\"toolScheduler\"];\n\tmaxToolConcurrency?: AgentLoopConfig[\"maxToolConcurrency\"];\n\tstrictExtensionClaims?: AgentLoopConfig[\"strictExtensionClaims\"];\n\tcwd?: AgentLoopConfig[\"cwd\"];\n\tresourceKeyResolver?: AgentLoopConfig[\"resourceKeyResolver\"];\n\ttoolExecutionPolicy?: AgentLoopConfig[\"toolExecutionPolicy\"];\n}\n\ntype ActiveRun = {\n\tpromise: Promise<void>;\n\tresolve: () => void;\n\tabortController: AbortController;\n};\n\n/**\n * Stateful wrapper around the low-level agent loop.\n *\n * `Agent` owns the current transcript, emits lifecycle events, executes tools,\n * and exposes queueing APIs for steering and follow-up messages.\n */\nexport class Agent {\n\tprivate _state: MutableAgentState;\n\tprivate readonly listeners = new Set<(event: AgentEvent, signal: AbortSignal) => Promise<void> | void>();\n\tprivate readonly steeringQueue: PendingMessageQueue;\n\tprivate readonly followUpQueue: PendingMessageQueue;\n\n\tpublic convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\tpublic transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\tpublic streamFn: StreamFn;\n\tpublic getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\tpublic onPayload?: SimpleStreamOptions[\"onPayload\"];\n\tpublic onResponse?: SimpleStreamOptions[\"onResponse\"];\n\tpublic beforeToolCall?: (\n\t\tcontext: BeforeToolCallContext,\n\t\tsignal?: AbortSignal,\n\t) => Promise<BeforeToolCallResult | undefined>;\n\tpublic afterToolCall?: (\n\t\tcontext: AfterToolCallContext,\n\t\tsignal?: AbortSignal,\n\t) => Promise<AfterToolCallResult | undefined>;\n\tpublic prepareNextTurn?: (\n\t\tsignal?: AbortSignal,\n\t) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;\n\tprivate activeRun?: ActiveRun;\n\t/** Session identifier forwarded to providers for cache-aware backends. */\n\tpublic sessionId?: string;\n\t/** Optional per-level thinking token budgets forwarded to the stream function. */\n\tpublic thinkingBudgets?: ThinkingBudgets;\n\t/** Preferred transport forwarded to the stream function. */\n\tpublic transport: Transport;\n\t/** Optional cap for provider-requested retry delays. */\n\tpublic maxRetryDelayMs?: number;\n\t/** Optional provider-turn budget for each prompt or continuation run. */\n\tpublic maxTurns?: number;\n\t/** Immutable opt-in policy; it is not a serialized provider request guarantee. */\n\tpublic readonly modelContract?: ModelContract;\n\tpublic maxTokens?: number;\n\t/** Tool execution strategy for assistant messages that contain multiple tool calls. */\n\tpublic toolExecution: ToolExecutionMode;\n\t/** Default execution timeout for tools; provider request timeout remains separate. */\n\tpublic toolTimeoutMs?: number;\n\t/** Per-tool-name execution timeout overrides. */\n\tpublic toolTimeouts?: Record<string, number>;\n\t/** Deterministic tool scheduler selection. */\n\tpublic toolScheduler: NonNullable<AgentLoopConfig[\"toolScheduler\"]>;\n\t/** Optional dag-v2 concurrency cap. */\n\tpublic maxToolConcurrency?: number;\n\t/** Require explicit resource claims for parallel extension tools. */\n\tpublic strictExtensionClaims: boolean;\n\t/** Working directory used to resolve path-scoped resource claims. */\n\tpublic cwd?: string;\n\t/** Optional dag-v2 platform identity resolver for path-claim aliases. */\n\tpublic resourceKeyResolver?: AgentLoopConfig[\"resourceKeyResolver\"];\n\t/** Execution-policy defaults (late-settlement audit policy). */\n\tpublic toolExecutionPolicy?: AgentLoopConfig[\"toolExecutionPolicy\"];\n\n\tconstructor(options: AgentOptions = {}) {\n\t\tthis._state = createMutableAgentState(options.initialState);\n\t\tthis.convertToLlm = options.convertToLlm ?? defaultConvertToLlm;\n\t\tthis.transformContext = options.transformContext;\n\t\tthis.streamFn = options.streamFn ?? streamSimple;\n\t\tthis.getApiKey = options.getApiKey;\n\t\tthis.onPayload = options.onPayload;\n\t\tthis.onResponse = options.onResponse;\n\t\tthis.beforeToolCall = options.beforeToolCall;\n\t\tthis.afterToolCall = options.afterToolCall;\n\t\tthis.prepareNextTurn = options.prepareNextTurn;\n\t\tthis.steeringQueue = new PendingMessageQueue(options.steeringMode ?? \"one-at-a-time\");\n\t\tthis.followUpQueue = new PendingMessageQueue(options.followUpMode ?? \"one-at-a-time\");\n\t\tthis.sessionId = options.sessionId;\n\t\tthis.thinkingBudgets = options.thinkingBudgets;\n\t\tthis.transport = options.transport ?? \"auto\";\n\t\tthis.maxRetryDelayMs = options.maxRetryDelayMs;\n\t\tthis.maxTurns = options.maxTurns;\n\t\tthis.modelContract =\n\t\t\toptions.modelContract === undefined ? undefined : snapshotModelContract(options.modelContract);\n\t\tthis.maxTokens = options.maxTokens;\n\t\tthis.toolExecution = options.toolExecution ?? \"parallel\";\n\t\tthis.toolTimeoutMs = options.toolTimeoutMs;\n\t\tthis.toolTimeouts = options.toolTimeouts;\n\t\tthis.toolScheduler = options.toolScheduler ?? \"dag-v2\";\n\t\tthis.maxToolConcurrency = options.maxToolConcurrency;\n\t\tthis.strictExtensionClaims = options.strictExtensionClaims ?? false;\n\t\tthis.cwd = options.cwd;\n\t\tthis.resourceKeyResolver = options.resourceKeyResolver;\n\t\tthis.toolExecutionPolicy = options.toolExecutionPolicy;\n\t}\n\n\t/**\n\t * Subscribe to agent lifecycle events.\n\t *\n\t * Listener promises are awaited in subscription order except for\n\t * observation-only `tool_execution_update` delivery, which is detached so a\n\t * listener cannot delay timeout/abort closure. Listeners receive the active\n\t * abort signal. `agent_end` remains awaited before the agent becomes idle.\n\t */\n\tsubscribe(listener: (event: AgentEvent, signal: AbortSignal) => Promise<void> | void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\t/**\n\t * Current agent state.\n\t *\n\t * Assigning `state.tools` or `state.messages` copies the provided top-level array.\n\t */\n\tget state(): AgentState {\n\t\treturn this._state;\n\t}\n\n\t/** Controls how queued steering messages are drained. */\n\tset steeringMode(mode: QueueMode) {\n\t\tthis.steeringQueue.mode = mode;\n\t}\n\n\tget steeringMode(): QueueMode {\n\t\treturn this.steeringQueue.mode;\n\t}\n\n\t/** Controls how queued follow-up messages are drained. */\n\tset followUpMode(mode: QueueMode) {\n\t\tthis.followUpQueue.mode = mode;\n\t}\n\n\tget followUpMode(): QueueMode {\n\t\treturn this.followUpQueue.mode;\n\t}\n\n\t/** Queue a message to be injected after the current assistant turn finishes. */\n\tsteer(message: AgentMessage): void {\n\t\tthis.steeringQueue.enqueue(message);\n\t}\n\n\t/** Queue a message to run only after the agent would otherwise stop. */\n\tfollowUp(message: AgentMessage): void {\n\t\tthis.followUpQueue.enqueue(message);\n\t}\n\n\t/** Remove all queued steering messages. */\n\tclearSteeringQueue(): void {\n\t\tthis.steeringQueue.clear();\n\t}\n\n\t/** Remove all queued follow-up messages. */\n\tclearFollowUpQueue(): void {\n\t\tthis.followUpQueue.clear();\n\t}\n\n\t/** Remove all queued steering and follow-up messages. */\n\tclearAllQueues(): void {\n\t\tthis.clearSteeringQueue();\n\t\tthis.clearFollowUpQueue();\n\t}\n\n\t/** Returns true when either queue still contains pending messages. */\n\thasQueuedMessages(): boolean {\n\t\treturn this.steeringQueue.hasItems() || this.followUpQueue.hasItems();\n\t}\n\n\t/** Active abort signal for the current run, if any. */\n\tget signal(): AbortSignal | undefined {\n\t\treturn this.activeRun?.abortController.signal;\n\t}\n\n\t/** Abort the current run, if one is active. */\n\tabort(): void {\n\t\tthis.activeRun?.abortController.abort();\n\t}\n\n\t/**\n\t * Resolve when the current run and all awaited event listeners have finished.\n\t *\n\t * This resolves after `agent_end` listeners settle.\n\t */\n\twaitForIdle(): Promise<void> {\n\t\treturn this.activeRun?.promise ?? Promise.resolve();\n\t}\n\n\t/** Clear transcript state, runtime state, and queued messages. */\n\treset(): void {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before resetting.\");\n\t\t}\n\n\t\tthis._state.messages = [];\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis._state.errorMessage = undefined;\n\t\tthis.clearFollowUpQueue();\n\t\tthis.clearSteeringQueue();\n\t}\n\n\t/** Start a new prompt from text, a single message, or a batch of messages. */\n\tasync prompt(message: AgentMessage | AgentMessage[]): Promise<void>;\n\tasync prompt(input: string, images?: ImageContent[]): Promise<void>;\n\tasync prompt(input: string | AgentMessage | AgentMessage[], images?: ImageContent[]): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.\",\n\t\t\t);\n\t\t}\n\t\tconst messages = this.normalizePromptInput(input, images);\n\t\tawait this.runPromptMessages(messages);\n\t}\n\n\t/** Continue from the current transcript. The last message must be a user or tool-result message. */\n\tasync continue(): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before continuing.\");\n\t\t}\n\n\t\tconst lastMessage = this._state.messages[this._state.messages.length - 1];\n\t\tif (!lastMessage) {\n\t\t\tthrow new Error(\"No messages to continue from\");\n\t\t}\n\n\t\tif (lastMessage.role === \"assistant\") {\n\t\t\tconst queuedSteering = this.steeringQueue.drain();\n\t\t\tif (queuedSteering.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedSteering, { skipInitialSteeringPoll: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst queuedFollowUps = this.followUpQueue.drain();\n\t\t\tif (queuedFollowUps.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedFollowUps);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Last message is a completed assistant turn. Two sub-cases:\n\t\t\t// 1. The assistant message carries pending tool calls without matching\n\t\t\t// tool results -> the provider will reject this, so fail fast with a\n\t\t\t// clear, actionable error.\n\t\t\t// 2. The assistant message is plain text/thinking (no tool calls). This is\n\t\t\t// a finished turn (e.g. after compaction, session resume, or an\n\t\t\t// explicit \"continue\" request). We honour it by injecting an empty\n\t\t\t// user prompt so the model can extend its previous answer rather than\n\t\t\t// throwing the opaque \"Cannot continue from message role: assistant\".\n\t\t\tconst hasPendingToolCalls = lastMessage.content.some((c) => c.type === \"toolCall\");\n\t\t\tif (hasPendingToolCalls) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Cannot continue: the last assistant message has pending tool calls without results. \" +\n\t\t\t\t\t\t\"Provide tool results (or a new user message) before continuing.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait this.runPromptMessages([{ role: \"user\", content: [{ type: \"text\", text: \"\" }], timestamp: Date.now() }]);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.runContinuation();\n\t}\n\n\tprivate normalizePromptInput(\n\t\tinput: string | AgentMessage | AgentMessage[],\n\t\timages?: ImageContent[],\n\t): AgentMessage[] {\n\t\tif (Array.isArray(input)) {\n\t\t\treturn input;\n\t\t}\n\n\t\tif (typeof input !== \"string\") {\n\t\t\treturn [input];\n\t\t}\n\n\t\tconst content: Array<TextContent | ImageContent> = [{ type: \"text\", text: input }];\n\t\tif (images && images.length > 0) {\n\t\t\tcontent.push(...images);\n\t\t}\n\t\treturn [{ role: \"user\", content, timestamp: Date.now() }];\n\t}\n\n\tprivate async runPromptMessages(\n\t\tmessages: AgentMessage[],\n\t\toptions: { skipInitialSteeringPoll?: boolean } = {},\n\t): Promise<void> {\n\t\tawait this.runWithLifecycle(async (signal) => {\n\t\t\tawait runAgentLoop(\n\t\t\t\tmessages,\n\t\t\t\tthis.createContextSnapshot(),\n\t\t\t\tthis.createLoopConfig(options),\n\t\t\t\t(event) => this.processEvents(event),\n\t\t\t\tsignal,\n\t\t\t\tthis.streamFn,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate async runContinuation(): Promise<void> {\n\t\tawait this.runWithLifecycle(async (signal) => {\n\t\t\tawait runAgentLoopContinue(\n\t\t\t\tthis.createContextSnapshot(),\n\t\t\t\tthis.createLoopConfig(),\n\t\t\t\t(event) => this.processEvents(event),\n\t\t\t\tsignal,\n\t\t\t\tthis.streamFn,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate createContextSnapshot(): AgentContext {\n\t\treturn {\n\t\t\tsystemPrompt: this._state.systemPrompt,\n\t\t\tsystemPromptCacheBoundary: this._state.systemPromptCacheBoundary,\n\t\t\tsystemPromptCacheBoundaryBypass: this._state.systemPromptCacheBoundaryBypass,\n\t\t\tmessages: this._state.messages.slice(),\n\t\t\ttools: this._state.tools.slice(),\n\t\t};\n\t}\n\n\tprivate createLoopConfig(options: { skipInitialSteeringPoll?: boolean } = {}): AgentLoopConfig {\n\t\tlet skipInitialSteeringPoll = options.skipInitialSteeringPoll === true;\n\t\treturn {\n\t\t\tmodel: this._state.model,\n\t\t\treasoning: this._state.thinkingLevel === \"off\" ? undefined : this._state.thinkingLevel,\n\t\t\tsessionId: this.sessionId,\n\t\t\tonPayload: this.onPayload,\n\t\t\tonResponse: this.onResponse,\n\t\t\ttransport: this.transport,\n\t\t\tthinkingBudgets: this.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: this.maxRetryDelayMs,\n\t\t\tmaxTurns: this.maxTurns,\n\t\t\tmodelContract: this.modelContract,\n\t\t\tmaxTokens: this.maxTokens,\n\t\t\ttoolExecution: this.toolExecution,\n\t\t\ttoolTimeoutMs: this.toolTimeoutMs,\n\t\t\ttoolTimeouts: this.toolTimeouts,\n\t\t\ttoolScheduler: this.toolScheduler,\n\t\t\tmaxToolConcurrency: this.maxToolConcurrency,\n\t\t\tstrictExtensionClaims: this.strictExtensionClaims,\n\t\t\tcwd: this.cwd,\n\t\t\tresourceKeyResolver: this.resourceKeyResolver,\n\t\t\ttoolExecutionPolicy: this.toolExecutionPolicy,\n\t\t\tbeforeToolCall: this.beforeToolCall,\n\t\t\tafterToolCall: this.afterToolCall,\n\t\t\tprepareNextTurn: this.prepareNextTurn ? async () => await this.prepareNextTurn?.(this.signal) : undefined,\n\t\t\tconvertToLlm: this.convertToLlm,\n\t\t\ttransformContext: this.transformContext,\n\t\t\tgetApiKey: this.getApiKey,\n\t\t\tgetSteeringMessages: async () => {\n\t\t\t\tif (skipInitialSteeringPoll) {\n\t\t\t\t\tskipInitialSteeringPoll = false;\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\treturn this.steeringQueue.drain();\n\t\t\t},\n\t\t\tgetFollowUpMessages: async () => this.followUpQueue.drain(),\n\t\t};\n\t}\n\n\tprivate async runWithLifecycle(executor: (signal: AbortSignal) => Promise<void>): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing.\");\n\t\t}\n\n\t\tconst abortController = new AbortController();\n\t\tlet resolvePromise = () => {};\n\t\tconst promise = new Promise<void>((resolve) => {\n\t\t\tresolvePromise = resolve;\n\t\t});\n\t\tthis.activeRun = { promise, resolve: resolvePromise, abortController };\n\n\t\tthis._state.isStreaming = true;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.errorMessage = undefined;\n\n\t\ttry {\n\t\t\tawait executor(abortController.signal);\n\t\t} catch (error) {\n\t\t\tconst failure = error instanceof Error ? error : new Error(String(error));\n\t\t\tawait this.handleRunFailure(failure, abortController.signal.aborted);\n\t\t} finally {\n\t\t\tthis.finishRun();\n\t\t}\n\t}\n\n\tprivate async handleRunFailure(error: unknown, aborted: boolean): Promise<void> {\n\t\t// Apply the same failure-termination contract as the low-level loop so the\n\t\t// disposition of any unresolved tool calls matches transcript repair:\n\t\t// an unambiguous open turn is closed with exactly one synthetic result per\n\t\t// missing call before a single coherent failure assistant, and an ambiguous\n\t\t// transcript fails closed without fabricating a turn over corruption.\n\t\tconst plan = planFailureTermination(this._state.messages, this._state.model, error, aborted);\n\n\t\tfor (const result of plan.closureResults) {\n\t\t\tawait this.processEvents({ type: \"message_start\", message: result });\n\t\t\tawait this.processEvents({ type: \"message_end\", message: result });\n\t\t}\n\n\t\tif (plan.failureMessage) {\n\t\t\tawait this.processEvents({ type: \"message_start\", message: plan.failureMessage });\n\t\t\tawait this.processEvents({ type: \"message_end\", message: plan.failureMessage });\n\t\t\tawait this.processEvents({ type: \"turn_end\", message: plan.failureMessage, toolResults: [] });\n\t\t}\n\n\t\tawait this.processEvents({ type: \"agent_end\", messages: plan.messages });\n\t}\n\n\tprivate finishRun(): void {\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis.activeRun?.resolve();\n\t\tthis.activeRun = undefined;\n\t}\n\n\t/** Reduce state, detach update observation, and await all terminal listeners. */\n\tprivate async processEvents(sourceEvent: AgentEvent): Promise<void> {\n\t\tconst event = createImmutableSnapshot(sourceEvent);\n\t\tswitch (event.type) {\n\t\t\tcase \"message_start\":\n\t\t\t\tthis._state.streamingMessage = event.message;\n\t\t\t\tbreak;\n\n\t\t\tcase \"message_update\":\n\t\t\t\tthis._state.streamingMessage = event.message;\n\t\t\t\tbreak;\n\n\t\t\tcase \"message_end\":\n\t\t\t\tthis._state.streamingMessage = undefined;\n\t\t\t\tthis._state.messages.push(event.message);\n\t\t\t\tbreak;\n\n\t\t\tcase \"tool_execution_start\":\n\t\t\t\tthis._state.pendingToolCalls = new Set(this._state.pendingToolCalls).add(event.toolCallId);\n\t\t\t\tbreak;\n\n\t\t\tcase \"tool_execution_end\": {\n\t\t\t\tconst pendingToolCalls = new Set(this._state.pendingToolCalls);\n\t\t\t\tpendingToolCalls.delete(event.toolCallId);\n\t\t\t\tthis._state.pendingToolCalls = pendingToolCalls;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"turn_end\":\n\t\t\t\tif (event.message.role === \"assistant\" && event.message.errorMessage) {\n\t\t\t\t\tthis._state.errorMessage = event.message.errorMessage;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"agent_end\":\n\t\t\t\tthis._state.streamingMessage = undefined;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst signal = this.activeRun?.abortController.signal;\n\t\tif (!signal) {\n\t\t\t// A tool's real promise may settle after the run already ended. The\n\t\t\t// late-settlement event is audit-only by contract, so it is still\n\t\t\t// delivered (with an inert signal) instead of being dropped; every\n\t\t\t// other event outside an active run remains a hard invariant break.\n\t\t\tif (event.type === \"tool_execution_late_settlement\") {\n\t\t\t\tawait deliverToListeners(this.listeners, event, new AbortController().signal);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(\"Agent listener invoked outside active run\");\n\t\t}\n\t\tif (event.type === \"tool_execution_update\") {\n\t\t\tfor (const listener of this.listeners) {\n\t\t\t\tconst snapshot = createImmutableSnapshot(event);\n\t\t\t\tvoid Promise.resolve()\n\t\t\t\t\t.then(() => listener(snapshot, signal))\n\t\t\t\t\t.catch(() => undefined);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tawait deliverToListeners(this.listeners, event, signal);\n\t}\n}\n"]}
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ImageContent,\n\ttype Message,\n\ttype SimpleStreamOptions,\n\tstreamSimple,\n\ttype TextContent,\n\ttype ThinkingBudgets,\n\ttype Transport,\n} from \"omk-ai\";\nimport { planFailureTermination, runAgentLoop, runAgentLoopContinue } from \"./agent-loop.ts\";\nimport { createMutableAgentState, type MutableAgentState } from \"./agent-state.ts\";\nimport { deliverToListeners } from \"./listener-delivery.ts\";\nimport { PendingMessageQueue } from \"./pending-message-queue.ts\";\nimport { type ModelContract, snapshotModelContract } from \"./run-model-contract.ts\";\nimport { createImmutableSnapshot } from \"./tool-execution-boundary.ts\";\nimport type {\n\tAfterToolCallContext,\n\tAfterToolCallResult,\n\tAgentContext,\n\tAgentEvent,\n\tAgentLoopConfig,\n\tAgentLoopTurnUpdate,\n\tAgentMessage,\n\tAgentState,\n\tAgentTool,\n\tBeforeToolCallContext,\n\tBeforeToolCallResult,\n\tQueueMode,\n\tStreamFn,\n\tToolExecutionMode,\n} from \"./types.ts\";\n\nexport type { QueueMode } from \"./types.ts\";\n\nfunction defaultConvertToLlm(messages: AgentMessage[]): Message[] {\n\treturn messages.filter(\n\t\t(message) => message.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t);\n}\n\n/** Options for constructing an {@link Agent}. */\nexport interface AgentOptions {\n\tinitialState?: Partial<Omit<AgentState, \"pendingToolCalls\" | \"isStreaming\" | \"streamingMessage\" | \"errorMessage\">>;\n\tconvertToLlm?: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\ttransformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\tstreamFn?: StreamFn;\n\tgetApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\tonPayload?: SimpleStreamOptions[\"onPayload\"];\n\tonResponse?: SimpleStreamOptions[\"onResponse\"];\n\tbeforeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;\n\tafterToolCall?: (context: AfterToolCallContext, signal?: AbortSignal) => Promise<AfterToolCallResult | undefined>;\n\tprepareNextTurn?: (\n\t\tsignal?: AbortSignal,\n\t) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;\n\tsteeringMode?: QueueMode;\n\tfollowUpMode?: QueueMode;\n\tsessionId?: string;\n\tthinkingBudgets?: ThinkingBudgets;\n\ttransport?: Transport;\n\tmaxRetryDelayMs?: number;\n\tmaxTurns?: AgentLoopConfig[\"maxTurns\"];\n\t/** Optional immutable logical request policy for this Agent's runs. */\n\tmodelContract?: ModelContract;\n\tmaxTokens?: SimpleStreamOptions[\"maxTokens\"];\n\ttoolExecution?: ToolExecutionMode;\n\ttoolTimeoutMs?: AgentLoopConfig[\"toolTimeoutMs\"];\n\ttoolTimeouts?: AgentLoopConfig[\"toolTimeouts\"];\n\ttoolScheduler?: AgentLoopConfig[\"toolScheduler\"];\n\tmaxToolConcurrency?: AgentLoopConfig[\"maxToolConcurrency\"];\n\tstrictExtensionClaims?: AgentLoopConfig[\"strictExtensionClaims\"];\n\tcwd?: AgentLoopConfig[\"cwd\"];\n\tresourceKeyResolver?: AgentLoopConfig[\"resourceKeyResolver\"];\n\ttoolExecutionPolicy?: AgentLoopConfig[\"toolExecutionPolicy\"];\n}\n\ntype ActiveRun = {\n\tpromise: Promise<void>;\n\tresolve: () => void;\n\tabortController: AbortController;\n};\n\n/**\n * Stateful wrapper around the low-level agent loop.\n *\n * `Agent` owns the current transcript, emits lifecycle events, executes tools,\n * and exposes queueing APIs for steering and follow-up messages.\n */\nexport class Agent {\n\tprivate _state: MutableAgentState;\n\tprivate readonly listeners = new Set<(event: AgentEvent, signal: AbortSignal) => Promise<void> | void>();\n\tprivate readonly steeringQueue: PendingMessageQueue;\n\tprivate readonly followUpQueue: PendingMessageQueue;\n\n\tpublic convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\tpublic transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\tpublic streamFn: StreamFn;\n\tpublic getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\tpublic onPayload?: SimpleStreamOptions[\"onPayload\"];\n\tpublic onResponse?: SimpleStreamOptions[\"onResponse\"];\n\tpublic beforeToolCall?: (\n\t\tcontext: BeforeToolCallContext,\n\t\tsignal?: AbortSignal,\n\t) => Promise<BeforeToolCallResult | undefined>;\n\tpublic afterToolCall?: (\n\t\tcontext: AfterToolCallContext,\n\t\tsignal?: AbortSignal,\n\t) => Promise<AfterToolCallResult | undefined>;\n\tpublic prepareNextTurn?: (\n\t\tsignal?: AbortSignal,\n\t) => Promise<AgentLoopTurnUpdate | undefined> | AgentLoopTurnUpdate | undefined;\n\t/**\n\t * Selects the tools a run sends to the provider, e.g. to fit the model's input window.\n\t * `pending` holds prompt messages not yet in `state.messages`; active tools are never mutated.\n\t */\n\tpublic prepareTools?: (tools: AgentTool[], pending: readonly AgentMessage[]) => AgentTool[];\n\tprivate activeRun?: ActiveRun;\n\t/** Session identifier forwarded to providers for cache-aware backends. */\n\tpublic sessionId?: string;\n\t/** Optional per-level thinking token budgets forwarded to the stream function. */\n\tpublic thinkingBudgets?: ThinkingBudgets;\n\t/** Preferred transport forwarded to the stream function. */\n\tpublic transport: Transport;\n\t/** Optional cap for provider-requested retry delays. */\n\tpublic maxRetryDelayMs?: number;\n\t/** Optional provider-turn budget for each prompt or continuation run. */\n\tpublic maxTurns?: number;\n\t/** Immutable opt-in policy; it is not a serialized provider request guarantee. */\n\tpublic readonly modelContract?: ModelContract;\n\tpublic maxTokens?: number;\n\t/** Tool execution strategy for assistant messages that contain multiple tool calls. */\n\tpublic toolExecution: ToolExecutionMode;\n\t/** Default execution timeout for tools; provider request timeout remains separate. */\n\tpublic toolTimeoutMs?: number;\n\t/** Per-tool-name execution timeout overrides. */\n\tpublic toolTimeouts?: Record<string, number>;\n\t/** Deterministic tool scheduler selection. */\n\tpublic toolScheduler: NonNullable<AgentLoopConfig[\"toolScheduler\"]>;\n\t/** Optional dag-v2 concurrency cap. */\n\tpublic maxToolConcurrency?: number;\n\t/** Require explicit resource claims for parallel extension tools. */\n\tpublic strictExtensionClaims: boolean;\n\t/** Working directory used to resolve path-scoped resource claims. */\n\tpublic cwd?: string;\n\t/** Optional dag-v2 platform identity resolver for path-claim aliases. */\n\tpublic resourceKeyResolver?: AgentLoopConfig[\"resourceKeyResolver\"];\n\t/** Execution-policy defaults (late-settlement audit policy). */\n\tpublic toolExecutionPolicy?: AgentLoopConfig[\"toolExecutionPolicy\"];\n\n\tconstructor(options: AgentOptions = {}) {\n\t\tthis._state = createMutableAgentState(options.initialState);\n\t\tthis.convertToLlm = options.convertToLlm ?? defaultConvertToLlm;\n\t\tthis.transformContext = options.transformContext;\n\t\tthis.streamFn = options.streamFn ?? streamSimple;\n\t\tthis.getApiKey = options.getApiKey;\n\t\tthis.onPayload = options.onPayload;\n\t\tthis.onResponse = options.onResponse;\n\t\tthis.beforeToolCall = options.beforeToolCall;\n\t\tthis.afterToolCall = options.afterToolCall;\n\t\tthis.prepareNextTurn = options.prepareNextTurn;\n\t\tthis.steeringQueue = new PendingMessageQueue(options.steeringMode ?? \"one-at-a-time\");\n\t\tthis.followUpQueue = new PendingMessageQueue(options.followUpMode ?? \"one-at-a-time\");\n\t\tthis.sessionId = options.sessionId;\n\t\tthis.thinkingBudgets = options.thinkingBudgets;\n\t\tthis.transport = options.transport ?? \"auto\";\n\t\tthis.maxRetryDelayMs = options.maxRetryDelayMs;\n\t\tthis.maxTurns = options.maxTurns;\n\t\tthis.modelContract =\n\t\t\toptions.modelContract === undefined ? undefined : snapshotModelContract(options.modelContract);\n\t\tthis.maxTokens = options.maxTokens;\n\t\tthis.toolExecution = options.toolExecution ?? \"parallel\";\n\t\tthis.toolTimeoutMs = options.toolTimeoutMs;\n\t\tthis.toolTimeouts = options.toolTimeouts;\n\t\tthis.toolScheduler = options.toolScheduler ?? \"dag-v2\";\n\t\tthis.maxToolConcurrency = options.maxToolConcurrency;\n\t\tthis.strictExtensionClaims = options.strictExtensionClaims ?? false;\n\t\tthis.cwd = options.cwd;\n\t\tthis.resourceKeyResolver = options.resourceKeyResolver;\n\t\tthis.toolExecutionPolicy = options.toolExecutionPolicy;\n\t}\n\n\t/**\n\t * Subscribe to agent lifecycle events.\n\t *\n\t * Listener promises are awaited in subscription order except for\n\t * observation-only `tool_execution_update` delivery, which is detached so a\n\t * listener cannot delay timeout/abort closure. Listeners receive the active\n\t * abort signal. `agent_end` remains awaited before the agent becomes idle.\n\t */\n\tsubscribe(listener: (event: AgentEvent, signal: AbortSignal) => Promise<void> | void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\t/**\n\t * Current agent state.\n\t *\n\t * Assigning `state.tools` or `state.messages` copies the provided top-level array.\n\t */\n\tget state(): AgentState {\n\t\treturn this._state;\n\t}\n\n\t/** Controls how queued steering messages are drained. */\n\tset steeringMode(mode: QueueMode) {\n\t\tthis.steeringQueue.mode = mode;\n\t}\n\n\tget steeringMode(): QueueMode {\n\t\treturn this.steeringQueue.mode;\n\t}\n\n\t/** Controls how queued follow-up messages are drained. */\n\tset followUpMode(mode: QueueMode) {\n\t\tthis.followUpQueue.mode = mode;\n\t}\n\n\tget followUpMode(): QueueMode {\n\t\treturn this.followUpQueue.mode;\n\t}\n\n\t/** Queue a message to be injected after the current assistant turn finishes. */\n\tsteer(message: AgentMessage): void {\n\t\tthis.steeringQueue.enqueue(message);\n\t}\n\n\t/** Queue a message to run only after the agent would otherwise stop. */\n\tfollowUp(message: AgentMessage): void {\n\t\tthis.followUpQueue.enqueue(message);\n\t}\n\n\t/** Remove all queued steering messages. */\n\tclearSteeringQueue(): void {\n\t\tthis.steeringQueue.clear();\n\t}\n\n\t/** Remove all queued follow-up messages. */\n\tclearFollowUpQueue(): void {\n\t\tthis.followUpQueue.clear();\n\t}\n\n\t/** Remove all queued steering and follow-up messages. */\n\tclearAllQueues(): void {\n\t\tthis.clearSteeringQueue();\n\t\tthis.clearFollowUpQueue();\n\t}\n\n\t/** Returns true when either queue still contains pending messages. */\n\thasQueuedMessages(): boolean {\n\t\treturn this.steeringQueue.hasItems() || this.followUpQueue.hasItems();\n\t}\n\n\t/** Active abort signal for the current run, if any. */\n\tget signal(): AbortSignal | undefined {\n\t\treturn this.activeRun?.abortController.signal;\n\t}\n\n\t/** Abort the current run, if one is active. */\n\tabort(): void {\n\t\tthis.activeRun?.abortController.abort();\n\t}\n\n\t/**\n\t * Resolve when the current run and all awaited event listeners have finished.\n\t *\n\t * This resolves after `agent_end` listeners settle.\n\t */\n\twaitForIdle(): Promise<void> {\n\t\treturn this.activeRun?.promise ?? Promise.resolve();\n\t}\n\n\t/** Clear transcript state, runtime state, and queued messages. */\n\treset(): void {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before resetting.\");\n\t\t}\n\n\t\tthis._state.messages = [];\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis._state.errorMessage = undefined;\n\t\tthis.clearFollowUpQueue();\n\t\tthis.clearSteeringQueue();\n\t}\n\n\t/** Start a new prompt from text, a single message, or a batch of messages. */\n\tasync prompt(message: AgentMessage | AgentMessage[]): Promise<void>;\n\tasync prompt(input: string, images?: ImageContent[]): Promise<void>;\n\tasync prompt(input: string | AgentMessage | AgentMessage[], images?: ImageContent[]): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.\",\n\t\t\t);\n\t\t}\n\t\tconst messages = this.normalizePromptInput(input, images);\n\t\tawait this.runPromptMessages(messages);\n\t}\n\n\t/** Continue from the current transcript. The last message must be a user or tool-result message. */\n\tasync continue(): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before continuing.\");\n\t\t}\n\n\t\tconst lastMessage = this._state.messages[this._state.messages.length - 1];\n\t\tif (!lastMessage) {\n\t\t\tthrow new Error(\"No messages to continue from\");\n\t\t}\n\n\t\tif (lastMessage.role === \"assistant\") {\n\t\t\tconst queuedSteering = this.steeringQueue.drain();\n\t\t\tif (queuedSteering.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedSteering, { skipInitialSteeringPoll: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst queuedFollowUps = this.followUpQueue.drain();\n\t\t\tif (queuedFollowUps.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedFollowUps);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Last message is a completed assistant turn. Two sub-cases:\n\t\t\t// 1. The assistant message carries pending tool calls without matching\n\t\t\t// tool results -> the provider will reject this, so fail fast with a\n\t\t\t// clear, actionable error.\n\t\t\t// 2. The assistant message is plain text/thinking (no tool calls). This is\n\t\t\t// a finished turn (e.g. after compaction, session resume, or an\n\t\t\t// explicit \"continue\" request). We honour it by injecting an empty\n\t\t\t// user prompt so the model can extend its previous answer rather than\n\t\t\t// throwing the opaque \"Cannot continue from message role: assistant\".\n\t\t\tconst hasPendingToolCalls = lastMessage.content.some((c) => c.type === \"toolCall\");\n\t\t\tif (hasPendingToolCalls) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Cannot continue: the last assistant message has pending tool calls without results. \" +\n\t\t\t\t\t\t\"Provide tool results (or a new user message) before continuing.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait this.runPromptMessages([{ role: \"user\", content: [{ type: \"text\", text: \"\" }], timestamp: Date.now() }]);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.runContinuation();\n\t}\n\n\tprivate normalizePromptInput(\n\t\tinput: string | AgentMessage | AgentMessage[],\n\t\timages?: ImageContent[],\n\t): AgentMessage[] {\n\t\tif (Array.isArray(input)) return input;\n\n\t\tif (typeof input !== \"string\") {\n\t\t\treturn [input];\n\t\t}\n\n\t\tconst content: Array<TextContent | ImageContent> = [{ type: \"text\", text: input }];\n\t\tif (images && images.length > 0) {\n\t\t\tcontent.push(...images);\n\t\t}\n\t\treturn [{ role: \"user\", content, timestamp: Date.now() }];\n\t}\n\n\tprivate async runPromptMessages(\n\t\tmessages: AgentMessage[],\n\t\toptions: { skipInitialSteeringPoll?: boolean } = {},\n\t): Promise<void> {\n\t\tawait this.runWithLifecycle(async (signal) => {\n\t\t\tawait runAgentLoop(\n\t\t\t\tmessages,\n\t\t\t\tthis.createContextSnapshot(messages),\n\t\t\t\tthis.createLoopConfig(options),\n\t\t\t\t(event) => this.processEvents(event),\n\t\t\t\tsignal,\n\t\t\t\tthis.streamFn,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate async runContinuation(): Promise<void> {\n\t\tawait this.runWithLifecycle(async (signal) => {\n\t\t\tawait runAgentLoopContinue(\n\t\t\t\tthis.createContextSnapshot(),\n\t\t\t\tthis.createLoopConfig(),\n\t\t\t\t(event) => this.processEvents(event),\n\t\t\t\tsignal,\n\t\t\t\tthis.streamFn,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate createContextSnapshot(pending: readonly AgentMessage[] = []): AgentContext {\n\t\treturn {\n\t\t\tsystemPrompt: this._state.systemPrompt,\n\t\t\tsystemPromptCacheBoundary: this._state.systemPromptCacheBoundary,\n\t\t\tsystemPromptCacheBoundaryBypass: this._state.systemPromptCacheBoundaryBypass,\n\t\t\tmessages: this._state.messages.slice(),\n\t\t\ttools: (this.prepareTools?.(this._state.tools.slice(), pending) ?? this._state.tools).slice(),\n\t\t};\n\t}\n\n\tprivate createLoopConfig(options: { skipInitialSteeringPoll?: boolean } = {}): AgentLoopConfig {\n\t\tlet skipInitialSteeringPoll = options.skipInitialSteeringPoll === true;\n\t\treturn {\n\t\t\tmodel: this._state.model,\n\t\t\treasoning: this._state.thinkingLevel === \"off\" ? undefined : this._state.thinkingLevel,\n\t\t\tsessionId: this.sessionId,\n\t\t\tonPayload: this.onPayload,\n\t\t\tonResponse: this.onResponse,\n\t\t\ttransport: this.transport,\n\t\t\tthinkingBudgets: this.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: this.maxRetryDelayMs,\n\t\t\tmaxTurns: this.maxTurns,\n\t\t\tmodelContract: this.modelContract,\n\t\t\tmaxTokens: this.maxTokens,\n\t\t\ttoolExecution: this.toolExecution,\n\t\t\ttoolTimeoutMs: this.toolTimeoutMs,\n\t\t\ttoolTimeouts: this.toolTimeouts,\n\t\t\ttoolScheduler: this.toolScheduler,\n\t\t\tmaxToolConcurrency: this.maxToolConcurrency,\n\t\t\tstrictExtensionClaims: this.strictExtensionClaims,\n\t\t\tcwd: this.cwd,\n\t\t\tresourceKeyResolver: this.resourceKeyResolver,\n\t\t\ttoolExecutionPolicy: this.toolExecutionPolicy,\n\t\t\tbeforeToolCall: this.beforeToolCall,\n\t\t\tafterToolCall: this.afterToolCall,\n\t\t\tprepareNextTurn: this.prepareNextTurn ? async () => await this.prepareNextTurn?.(this.signal) : undefined,\n\t\t\tconvertToLlm: this.convertToLlm,\n\t\t\ttransformContext: this.transformContext,\n\t\t\tgetApiKey: this.getApiKey,\n\t\t\tgetSteeringMessages: async () => {\n\t\t\t\tif (skipInitialSteeringPoll) {\n\t\t\t\t\tskipInitialSteeringPoll = false;\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\treturn this.steeringQueue.drain();\n\t\t\t},\n\t\t\tgetFollowUpMessages: async () => this.followUpQueue.drain(),\n\t\t};\n\t}\n\n\tprivate async runWithLifecycle(executor: (signal: AbortSignal) => Promise<void>): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing.\");\n\t\t}\n\n\t\tconst abortController = new AbortController();\n\t\tlet resolvePromise = () => {};\n\t\tconst promise = new Promise<void>((resolve) => {\n\t\t\tresolvePromise = resolve;\n\t\t});\n\t\tthis.activeRun = { promise, resolve: resolvePromise, abortController };\n\n\t\tthis._state.isStreaming = true;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.errorMessage = undefined;\n\n\t\ttry {\n\t\t\tawait executor(abortController.signal);\n\t\t} catch (error) {\n\t\t\tconst failure = error instanceof Error ? error : new Error(String(error));\n\t\t\tawait this.handleRunFailure(failure, abortController.signal.aborted);\n\t\t} finally {\n\t\t\tthis.finishRun();\n\t\t}\n\t}\n\n\tprivate async handleRunFailure(error: unknown, aborted: boolean): Promise<void> {\n\t\t// Apply the same failure-termination contract as the low-level loop so the\n\t\t// disposition of any unresolved tool calls matches transcript repair:\n\t\t// an unambiguous open turn is closed with exactly one synthetic result per\n\t\t// missing call before a single coherent failure assistant, and an ambiguous\n\t\t// transcript fails closed without fabricating a turn over corruption.\n\t\tconst plan = planFailureTermination(this._state.messages, this._state.model, error, aborted);\n\n\t\tfor (const result of plan.closureResults) {\n\t\t\tawait this.processEvents({ type: \"message_start\", message: result });\n\t\t\tawait this.processEvents({ type: \"message_end\", message: result });\n\t\t}\n\n\t\tif (plan.failureMessage) {\n\t\t\tawait this.processEvents({ type: \"message_start\", message: plan.failureMessage });\n\t\t\tawait this.processEvents({ type: \"message_end\", message: plan.failureMessage });\n\t\t\tawait this.processEvents({ type: \"turn_end\", message: plan.failureMessage, toolResults: [] });\n\t\t}\n\n\t\tawait this.processEvents({ type: \"agent_end\", messages: plan.messages });\n\t}\n\n\tprivate finishRun(): void {\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamingMessage = undefined;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis.activeRun?.resolve();\n\t\tthis.activeRun = undefined;\n\t}\n\n\t/** Reduce state, detach update observation, and await all terminal listeners. */\n\tprivate async processEvents(sourceEvent: AgentEvent): Promise<void> {\n\t\tconst event = createImmutableSnapshot(sourceEvent);\n\t\tswitch (event.type) {\n\t\t\tcase \"message_start\":\n\t\t\t\tthis._state.streamingMessage = event.message;\n\t\t\t\tbreak;\n\n\t\t\tcase \"message_update\":\n\t\t\t\tthis._state.streamingMessage = event.message;\n\t\t\t\tbreak;\n\n\t\t\tcase \"message_end\":\n\t\t\t\tthis._state.streamingMessage = undefined;\n\t\t\t\tthis._state.messages.push(event.message);\n\t\t\t\tbreak;\n\n\t\t\tcase \"tool_execution_start\":\n\t\t\t\tthis._state.pendingToolCalls = new Set(this._state.pendingToolCalls).add(event.toolCallId);\n\t\t\t\tbreak;\n\n\t\t\tcase \"tool_execution_end\": {\n\t\t\t\tconst pendingToolCalls = new Set(this._state.pendingToolCalls);\n\t\t\t\tpendingToolCalls.delete(event.toolCallId);\n\t\t\t\tthis._state.pendingToolCalls = pendingToolCalls;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"turn_end\":\n\t\t\t\tif (event.message.role === \"assistant\" && event.message.errorMessage) {\n\t\t\t\t\tthis._state.errorMessage = event.message.errorMessage;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"agent_end\":\n\t\t\t\tthis._state.streamingMessage = undefined;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst signal = this.activeRun?.abortController.signal;\n\t\tif (!signal) {\n\t\t\t// A tool's real promise may settle after the run already ended. The\n\t\t\t// late-settlement event is audit-only by contract, so it is still\n\t\t\t// delivered (with an inert signal) instead of being dropped; every\n\t\t\t// other event outside an active run remains a hard invariant break.\n\t\t\tif (event.type === \"tool_execution_late_settlement\") {\n\t\t\t\tawait deliverToListeners(this.listeners, event, new AbortController().signal);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(\"Agent listener invoked outside active run\");\n\t\t}\n\t\tif (event.type === \"tool_execution_update\") {\n\t\t\tfor (const listener of this.listeners) {\n\t\t\t\tconst snapshot = createImmutableSnapshot(event);\n\t\t\t\tvoid Promise.resolve()\n\t\t\t\t\t.then(() => listener(snapshot, signal))\n\t\t\t\t\t.catch(() => undefined);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tawait deliverToListeners(this.listeners, event, signal);\n\t}\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import type { AgentMessage, QueueMode } from "./types.ts";
2
2
  export declare class PendingMessageQueue {
3
3
  private messages;
4
+ private head;
4
5
  mode: QueueMode;
5
6
  constructor(mode: QueueMode);
6
7
  enqueue(message: AgentMessage): void;
@@ -1 +1 @@
1
- {"version":3,"file":"pending-message-queue.d.ts","sourceRoot":"","sources":["../src/pending-message-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1D,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,QAAQ,CAAsB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAEvB,YAAY,IAAI,EAAE,SAAS,EAE1B;IAED,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEnC;IAED,QAAQ,IAAI,OAAO,CAElB;IAED,KAAK,IAAI,YAAY,EAAE,CAUtB;IAED,KAAK,IAAI,IAAI,CAEZ;CACD","sourcesContent":["import type { AgentMessage, QueueMode } from \"./types.ts\";\n\nexport class PendingMessageQueue {\n\tprivate messages: AgentMessage[] = [];\n\tpublic mode: QueueMode;\n\n\tconstructor(mode: QueueMode) {\n\t\tthis.mode = mode;\n\t}\n\n\tenqueue(message: AgentMessage): void {\n\t\tthis.messages.push(message);\n\t}\n\n\thasItems(): boolean {\n\t\treturn this.messages.length > 0;\n\t}\n\n\tdrain(): AgentMessage[] {\n\t\tif (this.mode === \"all\") {\n\t\t\tconst drained = this.messages.slice();\n\t\t\tthis.messages = [];\n\t\t\treturn drained;\n\t\t}\n\t\tconst first = this.messages[0];\n\t\tif (!first) return [];\n\t\tthis.messages = this.messages.slice(1);\n\t\treturn [first];\n\t}\n\n\tclear(): void {\n\t\tthis.messages = [];\n\t}\n}\n"]}
1
+ {"version":3,"file":"pending-message-queue.d.ts","sourceRoot":"","sources":["../src/pending-message-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1D,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,IAAI,CAAK;IACV,IAAI,EAAE,SAAS,CAAC;IAEvB,YAAY,IAAI,EAAE,SAAS,EAE1B;IAED,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEnC;IAED,QAAQ,IAAI,OAAO,CAElB;IAED,KAAK,IAAI,YAAY,EAAE,CAkBtB;IAED,KAAK,IAAI,IAAI,CAGZ;CACD","sourcesContent":["import type { AgentMessage, QueueMode } from \"./types.ts\";\n\nexport class PendingMessageQueue {\n\tprivate messages: AgentMessage[] = [];\n\tprivate head = 0;\n\tpublic mode: QueueMode;\n\n\tconstructor(mode: QueueMode) {\n\t\tthis.mode = mode;\n\t}\n\n\tenqueue(message: AgentMessage): void {\n\t\tthis.messages.push(message);\n\t}\n\n\thasItems(): boolean {\n\t\treturn this.head < this.messages.length;\n\t}\n\n\tdrain(): AgentMessage[] {\n\t\tif (this.mode === \"all\") {\n\t\t\tconst drained = this.messages.slice(this.head);\n\t\t\tthis.clear();\n\t\t\treturn drained;\n\t\t}\n\t\tconst first = this.messages[this.head];\n\t\tif (!first) return [];\n\t\t// Release the consumed payload immediately. Compact geometrically so a\n\t\t// continuously replenished queue bounds dead slots without quadratic copies.\n\t\tdelete this.messages[this.head++];\n\t\tif (this.head === this.messages.length) {\n\t\t\tthis.clear();\n\t\t} else if (this.head >= 1024 && this.head * 2 >= this.messages.length) {\n\t\t\tthis.messages = this.messages.slice(this.head);\n\t\t\tthis.head = 0;\n\t\t}\n\t\treturn [first];\n\t}\n\n\tclear(): void {\n\t\tthis.messages = [];\n\t\tthis.head = 0;\n\t}\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  export class PendingMessageQueue {
2
2
  messages = [];
3
+ head = 0;
3
4
  mode;
4
5
  constructor(mode) {
5
6
  this.mode = mode;
@@ -8,22 +9,32 @@ export class PendingMessageQueue {
8
9
  this.messages.push(message);
9
10
  }
10
11
  hasItems() {
11
- return this.messages.length > 0;
12
+ return this.head < this.messages.length;
12
13
  }
13
14
  drain() {
14
15
  if (this.mode === "all") {
15
- const drained = this.messages.slice();
16
- this.messages = [];
16
+ const drained = this.messages.slice(this.head);
17
+ this.clear();
17
18
  return drained;
18
19
  }
19
- const first = this.messages[0];
20
+ const first = this.messages[this.head];
20
21
  if (!first)
21
22
  return [];
22
- this.messages = this.messages.slice(1);
23
+ // Release the consumed payload immediately. Compact geometrically so a
24
+ // continuously replenished queue bounds dead slots without quadratic copies.
25
+ delete this.messages[this.head++];
26
+ if (this.head === this.messages.length) {
27
+ this.clear();
28
+ }
29
+ else if (this.head >= 1024 && this.head * 2 >= this.messages.length) {
30
+ this.messages = this.messages.slice(this.head);
31
+ this.head = 0;
32
+ }
23
33
  return [first];
24
34
  }
25
35
  clear() {
26
36
  this.messages = [];
37
+ this.head = 0;
27
38
  }
28
39
  }
29
40
  //# sourceMappingURL=pending-message-queue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pending-message-queue.js","sourceRoot":"","sources":["../src/pending-message-queue.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,mBAAmB;IACvB,QAAQ,GAAmB,EAAE,CAAC;IAC/B,IAAI,CAAY;IAEvB,YAAY,IAAe,EAAE;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAAA,CACjB;IAED,OAAO,CAAC,OAAqB,EAAQ;QACpC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAAA,CAC5B;IAED,QAAQ,GAAY;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAAA,CAChC;IAED,KAAK,GAAmB;QACvB,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACtC,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;YACnB,OAAO,OAAO,CAAC;QAChB,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,KAAK,CAAC,CAAC;IAAA,CACf;IAED,KAAK,GAAS;QACb,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IAAA,CACnB;CACD","sourcesContent":["import type { AgentMessage, QueueMode } from \"./types.ts\";\n\nexport class PendingMessageQueue {\n\tprivate messages: AgentMessage[] = [];\n\tpublic mode: QueueMode;\n\n\tconstructor(mode: QueueMode) {\n\t\tthis.mode = mode;\n\t}\n\n\tenqueue(message: AgentMessage): void {\n\t\tthis.messages.push(message);\n\t}\n\n\thasItems(): boolean {\n\t\treturn this.messages.length > 0;\n\t}\n\n\tdrain(): AgentMessage[] {\n\t\tif (this.mode === \"all\") {\n\t\t\tconst drained = this.messages.slice();\n\t\t\tthis.messages = [];\n\t\t\treturn drained;\n\t\t}\n\t\tconst first = this.messages[0];\n\t\tif (!first) return [];\n\t\tthis.messages = this.messages.slice(1);\n\t\treturn [first];\n\t}\n\n\tclear(): void {\n\t\tthis.messages = [];\n\t}\n}\n"]}
1
+ {"version":3,"file":"pending-message-queue.js","sourceRoot":"","sources":["../src/pending-message-queue.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,mBAAmB;IACvB,QAAQ,GAAmB,EAAE,CAAC;IAC9B,IAAI,GAAG,CAAC,CAAC;IACV,IAAI,CAAY;IAEvB,YAAY,IAAe,EAAE;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAAA,CACjB;IAED,OAAO,CAAC,OAAqB,EAAQ;QACpC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAAA,CAC5B;IAED,QAAQ,GAAY;QACnB,OAAO,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;IAAA,CACxC;IAED,KAAK,GAAmB;QACvB,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,OAAO,CAAC;QAChB,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QACtB,uEAAuE;QACvE,6EAA6E;QAC7E,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAClC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACxC,IAAI,CAAC,KAAK,EAAE,CAAC;QACd,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACvE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACf,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,CAAC;IAAA,CACf;IAED,KAAK,GAAS;QACb,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;IAAA,CACd;CACD","sourcesContent":["import type { AgentMessage, QueueMode } from \"./types.ts\";\n\nexport class PendingMessageQueue {\n\tprivate messages: AgentMessage[] = [];\n\tprivate head = 0;\n\tpublic mode: QueueMode;\n\n\tconstructor(mode: QueueMode) {\n\t\tthis.mode = mode;\n\t}\n\n\tenqueue(message: AgentMessage): void {\n\t\tthis.messages.push(message);\n\t}\n\n\thasItems(): boolean {\n\t\treturn this.head < this.messages.length;\n\t}\n\n\tdrain(): AgentMessage[] {\n\t\tif (this.mode === \"all\") {\n\t\t\tconst drained = this.messages.slice(this.head);\n\t\t\tthis.clear();\n\t\t\treturn drained;\n\t\t}\n\t\tconst first = this.messages[this.head];\n\t\tif (!first) return [];\n\t\t// Release the consumed payload immediately. Compact geometrically so a\n\t\t// continuously replenished queue bounds dead slots without quadratic copies.\n\t\tdelete this.messages[this.head++];\n\t\tif (this.head === this.messages.length) {\n\t\t\tthis.clear();\n\t\t} else if (this.head >= 1024 && this.head * 2 >= this.messages.length) {\n\t\t\tthis.messages = this.messages.slice(this.head);\n\t\t\tthis.head = 0;\n\t\t}\n\t\treturn [first];\n\t}\n\n\tclear(): void {\n\t\tthis.messages = [];\n\t\tthis.head = 0;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-dag-ecraf.d.ts","sourceRoot":"","sources":["../src/tool-dag-ecraf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,cAAc;IAC9B,yEAAuE;IACvE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,GAAG,eAAe,CAAC;IAC1D,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5D;;;;;;;;;OASG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5D,oFAAmF;IACnF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC;CACrF;AAED,MAAM,WAAW,kBAAkB;IAClC,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AA2JD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,sBAAsB,GAAG,kBAAkB,CAyEvF","sourcesContent":["/**\n * ECRAF — resource-aware ready queue admission planner.\n *\n * Given the current ready frontier, a free-slot count, and multi-dimensional\n * resource capacities, choose which ready nodes to admit next using the\n * deterministic greedy baseline the deep-research report prescribes (PR 8).\n *\n * legacy-v1: D_i = P_i / (epsilon + sum_r weight_r * a_ir)\n * normalized-v2: D_i = P_i / (epsilon + slotCost + sum_r weight_r * a_ir / s_r)\n * Normalization is opt-in, not a live scheduler or a measured improvement.\n *\n * then sorted by density descending, readySeq ascending, sourceIndex ascending.\n * A candidate is admitted only if admitting it does not push cumulative\n * running usage over any capacity and it does not semantically conflict with a\n * node already admitted in this pass. Admission is pure: it computes the plan;\n * the caller launches.\n */\n\nexport interface EcrafCandidate {\n\t/** Source order of the call within the batch — the stable tiebreak. */\n\treadonly sourceIndex: number;\n\t/** Monotonic order in which the node first entered the ready frontier. */\n\treadonly readySeq: number;\n\t/** Resource vector: resource name -> units consumed while running. */\n\treadonly resources: Readonly<Record<string, number>>;\n\t/** Scalar priority P_i already folded (rank, aging, evidence, risk...). */\n\treadonly priority: number;\n}\n\nexport interface EcrafAdmissionsOptions {\n\t/** Omitted: legacy-v1, or normalized-v2 when referenceScales is supplied. */\n\treadonly algorithmVersion?: \"legacy-v1\" | \"normalized-v2\";\n\treadonly candidates: readonly EcrafCandidate[];\n\t/** Resource units already held by running nodes: name -> units. */\n\treadonly runningUsage: Readonly<Record<string, number>>;\n\t/** Hard capacity per resource: name -> max units. Missing = unbounded. */\n\treadonly capacities: Readonly<Record<string, number>>;\n\t/** Free admission slots (concurrency budget). */\n\treadonly slots: number;\n\t/** Density epsilon guarding division-by-zero. Default 1e-6. */\n\treadonly epsilon?: number;\n\t/** Optional weight per resource in the density denominator. Default 1. */\n\treadonly resourceWeights?: Readonly<Record<string, number>>;\n\t/**\n\t * Opt-in dimensionless normalization (audit §13.2): resource name -> positive\n\t * reference scale s_r. When provided, the density denominator uses unitless\n\t * demands a_ir/s_r, making ranking invariant to per-resource unit changes\n\t * (a'_ir = c_r·a_ir with s'_ir = c_r·s_r preserves the mathematical ratio).\n\t * In normalized-v2, omitted entries use positive total capacities, never\n\t * remaining headroom. Positive unbounded demands require explicit scales.\n\t * Zero capacity is a feasibility gate, not a scale. All supplied scales must\n\t * be finite and positive. Supplying this map without a version opts into v2.\n\t */\n\treadonly referenceScales?: Readonly<Record<string, number>>;\n\t/** Finite positive slot term λ_slot in normalized-v2. Default 1; invalid in v1. */\n\treadonly slotCost?: number;\n\t/**\n\t * Semantic-conflict predicate. Return true when the candidate may not run\n\t * concurrently with an already-admitted node. Defaults to no conflicts.\n\t */\n\treadonly conflicts?: (candidate: EcrafCandidate, running: EcrafCandidate) => boolean;\n}\n\nexport interface EcrafAdmissionPlan {\n\t/** Source indices admitted, in the order they should be launched. */\n\treadonly admit: readonly number[];\n\t/** Source indices deferred this pass (capacity or conflict), in source order. */\n\treadonly deferred: readonly number[];\n}\n\n/**\n * Numeric contract for one admission pass (audit §5.3): every resource\n * demand, running usage, and capacity is a finite non-negative number; the\n * slot budget is a non-negative integer; epsilon is finite and positive;\n * ranking weights are finite and non-negative; candidate source indices and\n * ready sequences are unique, finite integers. Violating these invariants\n * silently poisons the plan — NaN makes every capacity check pass, negative\n * demand manufactures capacity, a fractional slot admits ⌈slots⌉ nodes, and\n * duplicate source indices make the admit list ambiguous — so malformed input\n * is rejected up front rather than coerced into \"unbounded\".\n */\nfunction assertFiniteNonNegative(value: number, label: string): void {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tthrow new RangeError(`${label} must be a finite non-negative number, got ${String(value)}`);\n\t}\n}\n\nfunction assertInputContract(options: EcrafAdmissionsOptions): void {\n\tconst {\n\t\tcandidates,\n\t\trunningUsage,\n\t\tcapacities,\n\t\tslots,\n\t\tepsilon = 1e-6,\n\t\tresourceWeights = {},\n\t\treferenceScales,\n\t\tslotCost = 1,\n\t} = options;\n\n\tif (!Number.isInteger(slots) || slots < 0) {\n\t\tthrow new RangeError(`slots must be a non-negative integer, got ${String(slots)}`);\n\t}\n\tif (!Number.isFinite(epsilon) || epsilon <= 0) {\n\t\tthrow new RangeError(`epsilon must be a finite positive number, got ${String(epsilon)}`);\n\t}\n\n\tconst seenSourceIndices = new Set<number>();\n\tconst seenReadySeqs = new Set<number>();\n\tfor (const [position, node] of candidates.entries()) {\n\t\tif (!Number.isInteger(node.sourceIndex) || node.sourceIndex < 0) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`candidates[${position}].sourceIndex must be a non-negative integer, got ${String(node.sourceIndex)}`,\n\t\t\t);\n\t\t}\n\t\tif (seenSourceIndices.has(node.sourceIndex)) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`duplicate candidates[].sourceIndex ${node.sourceIndex} — admit results must be unique per node`,\n\t\t\t);\n\t\t}\n\t\tseenSourceIndices.add(node.sourceIndex);\n\t\tif (!Number.isInteger(node.readySeq) || node.readySeq < 0) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`candidates[${position}].readySeq must be a non-negative integer, got ${String(node.readySeq)}`,\n\t\t\t);\n\t\t}\n\t\tif (seenReadySeqs.has(node.readySeq)) {\n\t\t\tthrow new RangeError(`duplicate candidates[].readySeq ${node.readySeq} — ready ordering must be unambiguous`);\n\t\t}\n\t\tseenReadySeqs.add(node.readySeq);\n\t\tassertFiniteNonNegative(node.priority, `candidates[${position}].priority`);\n\t\tfor (const [name, demand] of Object.entries(node.resources)) {\n\t\t\tassertFiniteNonNegative(demand, `candidates[${position}].resources.${name}`);\n\t\t}\n\t}\n\n\tfor (const [name, value] of Object.entries(runningUsage)) {\n\t\tassertFiniteNonNegative(value, `runningUsage.${name}`);\n\t}\n\tfor (const [name, value] of Object.entries(capacities)) {\n\t\tassertFiniteNonNegative(value, `capacities.${name}`);\n\t}\n\tfor (const [name, value] of Object.entries(resourceWeights)) {\n\t\tassertFiniteNonNegative(value, `resourceWeights.${name}`);\n\t}\n\tif (referenceScales !== undefined) {\n\t\tif (!Number.isFinite(slotCost) || slotCost <= 0) {\n\t\t\tthrow new RangeError(`slotCost must be a finite positive number, got ${String(slotCost)}`);\n\t\t}\n\t\tfor (const [name, scale] of Object.entries(referenceScales)) {\n\t\t\tif (!Number.isFinite(scale) || scale <= 0) {\n\t\t\t\tthrow new RangeError(`referenceScales.${name} must be a finite positive number, got ${String(scale)}`);\n\t\t\t}\n\t\t}\n\t\tfor (const [position, node] of candidates.entries()) {\n\t\t\tfor (const [name, demand] of Object.entries(node.resources)) {\n\t\t\t\tif (demand > 0 && capacities[name] !== 0 && referenceScales[name] === undefined) {\n\t\t\t\t\tthrow new RangeError(\n\t\t\t\t\t\t`referenceScales.${name} is required for a nonzero ${name} demand (candidates[${position}])`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction resourceCost(node: EcrafCandidate, weights: Readonly<Record<string, number>>): number {\n\tlet cost = 0;\n\tfor (const name of Object.keys(node.resources)) {\n\t\tconst weight = weights[name] ?? 1;\n\t\tcost += weight * (node.resources[name] ?? 0);\n\t}\n\treturn cost;\n}\n\nfunction density(\n\tnode: EcrafCandidate,\n\tweights: Readonly<Record<string, number>>,\n\tepsilon: number,\n\treferenceScales?: Readonly<Record<string, number>>,\n\tslotCost = 1,\n): number {\n\t// Normalized mode divides each demand by its reference scale, so per-resource\n\t// unit changes that scale demand and reference together cancel exactly.\n\tconst raw =\n\t\treferenceScales === undefined\n\t\t\t? resourceCost(node, weights)\n\t\t\t: [...Object.entries(node.resources)].reduce(\n\t\t\t\t\t(cost, [name, demand]) =>\n\t\t\t\t\t\tdemand === 0 ? cost : cost + (weights[name] ?? 1) * (demand / referenceScales[name]),\n\t\t\t\t\t0,\n\t\t\t\t);\n\tconst denominator = referenceScales === undefined ? epsilon + raw : epsilon + slotCost + raw;\n\tassertFiniteNonNegative(denominator, `candidate ${node.sourceIndex} density denominator`);\n\tconst score = node.priority / denominator;\n\tassertFiniteNonNegative(score, `candidate ${node.sourceIndex} density`);\n\treturn score;\n}\n\nfunction fits(\n\tnode: EcrafCandidate,\n\tused: Map<string, number>,\n\tcapacities: Readonly<Record<string, number>>,\n\tnormalized: boolean,\n): boolean {\n\tfor (const name of Object.keys(node.resources)) {\n\t\tconst capacity = capacities[name];\n\t\tif (capacity === undefined) continue; // unbounded resource\n\t\tconst needed = node.resources[name] ?? 0;\n\t\tif (normalized && capacity === 0 && needed === 0) continue;\n\t\tconst running = used.get(name) ?? 0;\n\t\tif (running + needed > capacity) return false;\n\t}\n\treturn true;\n}\n\nfunction reserve(node: EcrafCandidate, used: Map<string, number>): void {\n\tfor (const name of Object.keys(node.resources)) {\n\t\tconst total = (used.get(name) ?? 0) + (node.resources[name] ?? 0);\n\t\tassertFiniteNonNegative(total, `candidate ${node.sourceIndex} reserved usage.${name}`);\n\t\tused.set(name, total);\n\t}\n}\n\n/**\n * Greedy admission pass. Deterministic: identical inputs always produce the\n * identical plan. `admit` is ordered by launch preference (density, then\n * readySeq, then sourceIndex); `deferred` preserves source order.\n */\nexport function planEcrafAdmissions(options: EcrafAdmissionsOptions): EcrafAdmissionPlan {\n\tconst version = options.algorithmVersion ?? (options.referenceScales === undefined ? \"legacy-v1\" : \"normalized-v2\");\n\tif (version !== \"legacy-v1\" && version !== \"normalized-v2\") {\n\t\tthrow new RangeError(`Unknown ECRAF algorithmVersion: ${String(version)}`);\n\t}\n\tif (version === \"legacy-v1\" && (options.referenceScales !== undefined || options.slotCost !== undefined)) {\n\t\tthrow new RangeError(\"referenceScales and slotCost require normalized-v2\");\n\t}\n\tif (version === \"normalized-v2\") {\n\t\toptions = {\n\t\t\t...options,\n\t\t\treferenceScales: {\n\t\t\t\t...Object.fromEntries(Object.entries(options.capacities).filter(([, capacity]) => capacity > 0)),\n\t\t\t\t...options.referenceScales,\n\t\t\t},\n\t\t};\n\t}\n\tassertInputContract(options);\n\tconst {\n\t\tcandidates,\n\t\trunningUsage,\n\t\tcapacities,\n\t\tslots,\n\t\tepsilon = 1e-6,\n\t\tresourceWeights = {},\n\t\tconflicts,\n\t\treferenceScales,\n\t\tslotCost = 1,\n\t} = options;\n\n\t// Seed running usage so newly admitted nodes consume from the same budget.\n\tconst used = new Map<string, number>(Object.entries(runningUsage));\n\n\t// Zero-capacity infeasibility precedes scoring in v2. Validate all other\n\t// scores even for singleton and zero-slot batches, before any callbacks.\n\tconst infeasible = new Set(\n\t\tversion === \"normalized-v2\"\n\t\t\t? candidates.filter((node) =>\n\t\t\t\t\tObject.entries(node.resources).some(([name, demand]) => capacities[name] === 0 && demand > 0),\n\t\t\t\t)\n\t\t\t: [],\n\t);\n\tconst sorted = candidates\n\t\t.filter((node) => !infeasible.has(node))\n\t\t.map((node) => ({ node, score: density(node, resourceWeights, epsilon, referenceScales, slotCost) }))\n\t\t.sort(\n\t\t\t(a, b) => b.score - a.score || a.node.readySeq - b.node.readySeq || a.node.sourceIndex - b.node.sourceIndex,\n\t\t);\n\n\tconst admit: number[] = [];\n\tconst deferred: number[] = [...infeasible].map((node) => node.sourceIndex);\n\tconst admittedNodes: EcrafCandidate[] = [];\n\n\tfor (const { node } of sorted) {\n\t\tif (admit.length >= slots) {\n\t\t\tdeferred.push(node.sourceIndex);\n\t\t\tcontinue;\n\t\t}\n\t\tif (conflicts && admittedNodes.some((admitted) => conflicts(node, admitted))) {\n\t\t\tdeferred.push(node.sourceIndex);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!fits(node, used, capacities, version === \"normalized-v2\")) {\n\t\t\tdeferred.push(node.sourceIndex);\n\t\t\tcontinue;\n\t\t}\n\t\treserve(node, used);\n\t\tadmittedNodes.push(node);\n\t\tadmit.push(node.sourceIndex);\n\t}\n\n\tdeferred.sort((a, b) => a - b);\n\treturn { admit, deferred };\n}\n"]}
1
+ {"version":3,"file":"tool-dag-ecraf.d.ts","sourceRoot":"","sources":["../src/tool-dag-ecraf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,WAAW,cAAc;IAC9B,yEAAuE;IACvE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,GAAG,eAAe,CAAC;IAC1D,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5D;;;;;;;;;OASG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5D,oFAAmF;IACnF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC;CACrF;AAED,MAAM,WAAW,kBAAkB;IAClC,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAmKD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,sBAAsB,GAAG,kBAAkB,CA2EvF","sourcesContent":["/**\n * ECRAF — resource-aware ready queue admission planner.\n *\n * Given the current ready frontier, a free-slot count, and multi-dimensional\n * resource capacities, choose which ready nodes to admit next using the\n * deterministic greedy baseline the deep-research report prescribes (PR 8).\n *\n * legacy-v1: D_i = P_i / (epsilon + sum_r weight_r * a_ir)\n * normalized-v2: D_i = P_i / (epsilon + slotCost + sum_r weight_r * a_ir / s_r)\n * Normalization is opt-in, not a live scheduler or a measured improvement.\n *\n * then sorted by density descending, readySeq ascending, sourceIndex ascending.\n * A candidate is admitted only if admitting it does not push cumulative\n * running usage over any capacity and it does not semantically conflict with a\n * node already admitted in this pass. Admission is pure: it computes the plan;\n * the caller launches.\n */\n\nimport { ownResourceNumber } from \"./tool-dag-own-number.ts\";\n\nexport interface EcrafCandidate {\n\t/** Source order of the call within the batch — the stable tiebreak. */\n\treadonly sourceIndex: number;\n\t/** Monotonic order in which the node first entered the ready frontier. */\n\treadonly readySeq: number;\n\t/** Resource vector: resource name -> units consumed while running. */\n\treadonly resources: Readonly<Record<string, number>>;\n\t/** Scalar priority P_i already folded (rank, aging, evidence, risk...). */\n\treadonly priority: number;\n}\n\nexport interface EcrafAdmissionsOptions {\n\t/** Omitted: legacy-v1, or normalized-v2 when referenceScales is supplied. */\n\treadonly algorithmVersion?: \"legacy-v1\" | \"normalized-v2\";\n\treadonly candidates: readonly EcrafCandidate[];\n\t/** Resource units already held by running nodes: name -> units. */\n\treadonly runningUsage: Readonly<Record<string, number>>;\n\t/** Hard capacity per resource: name -> max units. Missing = unbounded. */\n\treadonly capacities: Readonly<Record<string, number>>;\n\t/** Free admission slots (concurrency budget). */\n\treadonly slots: number;\n\t/** Density epsilon guarding division-by-zero. Default 1e-6. */\n\treadonly epsilon?: number;\n\t/** Optional weight per resource in the density denominator. Default 1. */\n\treadonly resourceWeights?: Readonly<Record<string, number>>;\n\t/**\n\t * Opt-in dimensionless normalization (audit §13.2): resource name -> positive\n\t * reference scale s_r. When provided, the density denominator uses unitless\n\t * demands a_ir/s_r, making ranking invariant to per-resource unit changes\n\t * (a'_ir = c_r·a_ir with s'_ir = c_r·s_r preserves the mathematical ratio).\n\t * In normalized-v2, omitted entries use positive total capacities, never\n\t * remaining headroom. Positive unbounded demands require explicit scales.\n\t * Zero capacity is a feasibility gate, not a scale. All supplied scales must\n\t * be finite and positive. Supplying this map without a version opts into v2.\n\t */\n\treadonly referenceScales?: Readonly<Record<string, number>>;\n\t/** Finite positive slot term λ_slot in normalized-v2. Default 1; invalid in v1. */\n\treadonly slotCost?: number;\n\t/**\n\t * Semantic-conflict predicate. Return true when the candidate may not run\n\t * concurrently with an already-admitted node. Defaults to no conflicts.\n\t */\n\treadonly conflicts?: (candidate: EcrafCandidate, running: EcrafCandidate) => boolean;\n}\n\nexport interface EcrafAdmissionPlan {\n\t/** Source indices admitted, in the order they should be launched. */\n\treadonly admit: readonly number[];\n\t/** Source indices deferred this pass (capacity or conflict), in source order. */\n\treadonly deferred: readonly number[];\n}\n\n/**\n * Numeric contract for one admission pass (audit §5.3): every resource\n * demand, running usage, and capacity is a finite non-negative number; the\n * slot budget is a non-negative integer; epsilon is finite and positive;\n * ranking weights are finite and non-negative; candidate source indices and\n * ready sequences are unique, finite integers. Violating these invariants\n * silently poisons the plan — NaN makes every capacity check pass, negative\n * demand manufactures capacity, a fractional slot admits ⌈slots⌉ nodes, and\n * duplicate source indices make the admit list ambiguous — so malformed input\n * is rejected up front rather than coerced into \"unbounded\".\n */\nfunction assertFiniteNonNegative(value: number, label: string): void {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tthrow new RangeError(`${label} must be a finite non-negative number, got ${String(value)}`);\n\t}\n}\n\nfunction assertInputContract(options: EcrafAdmissionsOptions): void {\n\tconst {\n\t\tcandidates,\n\t\trunningUsage,\n\t\tcapacities,\n\t\tslots,\n\t\tepsilon = 1e-6,\n\t\tresourceWeights = {},\n\t\treferenceScales,\n\t\tslotCost = 1,\n\t} = options;\n\n\tif (!Number.isInteger(slots) || slots < 0) {\n\t\tthrow new RangeError(`slots must be a non-negative integer, got ${String(slots)}`);\n\t}\n\tif (!Number.isFinite(epsilon) || epsilon <= 0) {\n\t\tthrow new RangeError(`epsilon must be a finite positive number, got ${String(epsilon)}`);\n\t}\n\n\tconst seenSourceIndices = new Set<number>();\n\tconst seenReadySeqs = new Set<number>();\n\tfor (const [position, node] of candidates.entries()) {\n\t\tif (!Number.isInteger(node.sourceIndex) || node.sourceIndex < 0) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`candidates[${position}].sourceIndex must be a non-negative integer, got ${String(node.sourceIndex)}`,\n\t\t\t);\n\t\t}\n\t\tif (seenSourceIndices.has(node.sourceIndex)) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`duplicate candidates[].sourceIndex ${node.sourceIndex} — admit results must be unique per node`,\n\t\t\t);\n\t\t}\n\t\tseenSourceIndices.add(node.sourceIndex);\n\t\tif (!Number.isInteger(node.readySeq) || node.readySeq < 0) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`candidates[${position}].readySeq must be a non-negative integer, got ${String(node.readySeq)}`,\n\t\t\t);\n\t\t}\n\t\tif (seenReadySeqs.has(node.readySeq)) {\n\t\t\tthrow new RangeError(`duplicate candidates[].readySeq ${node.readySeq} — ready ordering must be unambiguous`);\n\t\t}\n\t\tseenReadySeqs.add(node.readySeq);\n\t\tassertFiniteNonNegative(node.priority, `candidates[${position}].priority`);\n\t\tfor (const [name, demand] of Object.entries(node.resources)) {\n\t\t\tassertFiniteNonNegative(demand, `candidates[${position}].resources.${name}`);\n\t\t}\n\t}\n\n\tfor (const [name, value] of Object.entries(runningUsage)) {\n\t\tassertFiniteNonNegative(value, `runningUsage.${name}`);\n\t}\n\tfor (const [name, value] of Object.entries(capacities)) {\n\t\tassertFiniteNonNegative(value, `capacities.${name}`);\n\t}\n\tfor (const [name, value] of Object.entries(resourceWeights)) {\n\t\tassertFiniteNonNegative(value, `resourceWeights.${name}`);\n\t}\n\tif (referenceScales !== undefined) {\n\t\tif (!Number.isFinite(slotCost) || slotCost <= 0) {\n\t\t\tthrow new RangeError(`slotCost must be a finite positive number, got ${String(slotCost)}`);\n\t\t}\n\t\tfor (const [name, scale] of Object.entries(referenceScales)) {\n\t\t\tif (!Number.isFinite(scale) || scale <= 0) {\n\t\t\t\tthrow new RangeError(`referenceScales.${name} must be a finite positive number, got ${String(scale)}`);\n\t\t\t}\n\t\t}\n\t\tfor (const [position, node] of candidates.entries()) {\n\t\t\tfor (const [name, demand] of Object.entries(node.resources)) {\n\t\t\t\tif (\n\t\t\t\t\tdemand > 0 &&\n\t\t\t\t\townResourceNumber(capacities, name) !== 0 &&\n\t\t\t\t\townResourceNumber(referenceScales, name) === undefined\n\t\t\t\t) {\n\t\t\t\t\tthrow new RangeError(\n\t\t\t\t\t\t`referenceScales.${name} is required for a nonzero ${name} demand (candidates[${position}])`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction resourceCost(node: EcrafCandidate, weights: Readonly<Record<string, number>>): number {\n\tlet cost = 0;\n\tfor (const name of Object.keys(node.resources)) {\n\t\tconst weight = ownResourceNumber(weights, name) ?? 1;\n\t\tcost += weight * (ownResourceNumber(node.resources, name) ?? 0);\n\t}\n\treturn cost;\n}\n\nfunction density(\n\tnode: EcrafCandidate,\n\tweights: Readonly<Record<string, number>>,\n\tepsilon: number,\n\treferenceScales?: Readonly<Record<string, number>>,\n\tslotCost = 1,\n): number {\n\t// Normalized mode divides each demand by its reference scale, so per-resource\n\t// unit changes that scale demand and reference together cancel exactly.\n\tconst raw =\n\t\treferenceScales === undefined\n\t\t\t? resourceCost(node, weights)\n\t\t\t: [...Object.entries(node.resources)].reduce(\n\t\t\t\t\t(cost, [name, demand]) =>\n\t\t\t\t\t\tdemand === 0\n\t\t\t\t\t\t\t? cost\n\t\t\t\t\t\t\t: cost +\n\t\t\t\t\t\t\t\t(ownResourceNumber(weights, name) ?? 1) *\n\t\t\t\t\t\t\t\t\t(demand / (ownResourceNumber(referenceScales, name) ?? Number.NaN)),\n\t\t\t\t\t0,\n\t\t\t\t);\n\tconst denominator = referenceScales === undefined ? epsilon + raw : epsilon + slotCost + raw;\n\tassertFiniteNonNegative(denominator, `candidate ${node.sourceIndex} density denominator`);\n\tconst score = node.priority / denominator;\n\tassertFiniteNonNegative(score, `candidate ${node.sourceIndex} density`);\n\treturn score;\n}\n\nfunction fits(\n\tnode: EcrafCandidate,\n\tused: Map<string, number>,\n\tcapacities: Readonly<Record<string, number>>,\n\tnormalized: boolean,\n): boolean {\n\tfor (const name of Object.keys(node.resources)) {\n\t\tconst capacity = ownResourceNumber(capacities, name);\n\t\tif (capacity === undefined) continue; // unbounded resource\n\t\tconst needed = ownResourceNumber(node.resources, name) ?? 0;\n\t\tif (normalized && capacity === 0 && needed === 0) continue;\n\t\tconst running = used.get(name) ?? 0;\n\t\tif (running + needed > capacity) return false;\n\t}\n\treturn true;\n}\n\nfunction reserve(node: EcrafCandidate, used: Map<string, number>): void {\n\tfor (const name of Object.keys(node.resources)) {\n\t\tconst total = (used.get(name) ?? 0) + (ownResourceNumber(node.resources, name) ?? 0);\n\t\tassertFiniteNonNegative(total, `candidate ${node.sourceIndex} reserved usage.${name}`);\n\t\tused.set(name, total);\n\t}\n}\n\n/**\n * Greedy admission pass. Deterministic: identical inputs always produce the\n * identical plan. `admit` is ordered by launch preference (density, then\n * readySeq, then sourceIndex); `deferred` preserves source order.\n */\nexport function planEcrafAdmissions(options: EcrafAdmissionsOptions): EcrafAdmissionPlan {\n\tconst version = options.algorithmVersion ?? (options.referenceScales === undefined ? \"legacy-v1\" : \"normalized-v2\");\n\tif (version !== \"legacy-v1\" && version !== \"normalized-v2\") {\n\t\tthrow new RangeError(`Unknown ECRAF algorithmVersion: ${String(version)}`);\n\t}\n\tif (version === \"legacy-v1\" && (options.referenceScales !== undefined || options.slotCost !== undefined)) {\n\t\tthrow new RangeError(\"referenceScales and slotCost require normalized-v2\");\n\t}\n\tif (version === \"normalized-v2\") {\n\t\toptions = {\n\t\t\t...options,\n\t\t\treferenceScales: {\n\t\t\t\t...Object.fromEntries(Object.entries(options.capacities).filter(([, capacity]) => capacity > 0)),\n\t\t\t\t...options.referenceScales,\n\t\t\t},\n\t\t};\n\t}\n\tassertInputContract(options);\n\tconst {\n\t\tcandidates,\n\t\trunningUsage,\n\t\tcapacities,\n\t\tslots,\n\t\tepsilon = 1e-6,\n\t\tresourceWeights = {},\n\t\tconflicts,\n\t\treferenceScales,\n\t\tslotCost = 1,\n\t} = options;\n\n\t// Seed running usage so newly admitted nodes consume from the same budget.\n\tconst used = new Map<string, number>(Object.entries(runningUsage));\n\n\t// Zero-capacity infeasibility precedes scoring in v2. Validate all other\n\t// scores even for singleton and zero-slot batches, before any callbacks.\n\tconst infeasible = new Set(\n\t\tversion === \"normalized-v2\"\n\t\t\t? candidates.filter((node) =>\n\t\t\t\t\tObject.entries(node.resources).some(\n\t\t\t\t\t\t([name, demand]) => ownResourceNumber(capacities, name) === 0 && demand > 0,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t: [],\n\t);\n\tconst sorted = candidates\n\t\t.filter((node) => !infeasible.has(node))\n\t\t.map((node) => ({ node, score: density(node, resourceWeights, epsilon, referenceScales, slotCost) }))\n\t\t.sort(\n\t\t\t(a, b) => b.score - a.score || a.node.readySeq - b.node.readySeq || a.node.sourceIndex - b.node.sourceIndex,\n\t\t);\n\n\tconst admit: number[] = [];\n\tconst deferred: number[] = [...infeasible].map((node) => node.sourceIndex);\n\tconst admittedNodes: EcrafCandidate[] = [];\n\n\tfor (const { node } of sorted) {\n\t\tif (admit.length >= slots) {\n\t\t\tdeferred.push(node.sourceIndex);\n\t\t\tcontinue;\n\t\t}\n\t\tif (conflicts && admittedNodes.some((admitted) => conflicts(node, admitted))) {\n\t\t\tdeferred.push(node.sourceIndex);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!fits(node, used, capacities, version === \"normalized-v2\")) {\n\t\t\tdeferred.push(node.sourceIndex);\n\t\t\tcontinue;\n\t\t}\n\t\treserve(node, used);\n\t\tadmittedNodes.push(node);\n\t\tadmit.push(node.sourceIndex);\n\t}\n\n\tdeferred.sort((a, b) => a - b);\n\treturn { admit, deferred };\n}\n"]}
@@ -15,6 +15,7 @@
15
15
  * node already admitted in this pass. Admission is pure: it computes the plan;
16
16
  * the caller launches.
17
17
  */
18
+ import { ownResourceNumber } from "./tool-dag-own-number.js";
18
19
  /**
19
20
  * Numeric contract for one admission pass (audit §5.3): every resource
20
21
  * demand, running usage, and capacity is a finite non-negative number; the
@@ -81,7 +82,9 @@ function assertInputContract(options) {
81
82
  }
82
83
  for (const [position, node] of candidates.entries()) {
83
84
  for (const [name, demand] of Object.entries(node.resources)) {
84
- if (demand > 0 && capacities[name] !== 0 && referenceScales[name] === undefined) {
85
+ if (demand > 0 &&
86
+ ownResourceNumber(capacities, name) !== 0 &&
87
+ ownResourceNumber(referenceScales, name) === undefined) {
85
88
  throw new RangeError(`referenceScales.${name} is required for a nonzero ${name} demand (candidates[${position}])`);
86
89
  }
87
90
  }
@@ -91,8 +94,8 @@ function assertInputContract(options) {
91
94
  function resourceCost(node, weights) {
92
95
  let cost = 0;
93
96
  for (const name of Object.keys(node.resources)) {
94
- const weight = weights[name] ?? 1;
95
- cost += weight * (node.resources[name] ?? 0);
97
+ const weight = ownResourceNumber(weights, name) ?? 1;
98
+ cost += weight * (ownResourceNumber(node.resources, name) ?? 0);
96
99
  }
97
100
  return cost;
98
101
  }
@@ -101,7 +104,11 @@ function density(node, weights, epsilon, referenceScales, slotCost = 1) {
101
104
  // unit changes that scale demand and reference together cancel exactly.
102
105
  const raw = referenceScales === undefined
103
106
  ? resourceCost(node, weights)
104
- : [...Object.entries(node.resources)].reduce((cost, [name, demand]) => demand === 0 ? cost : cost + (weights[name] ?? 1) * (demand / referenceScales[name]), 0);
107
+ : [...Object.entries(node.resources)].reduce((cost, [name, demand]) => demand === 0
108
+ ? cost
109
+ : cost +
110
+ (ownResourceNumber(weights, name) ?? 1) *
111
+ (demand / (ownResourceNumber(referenceScales, name) ?? Number.NaN)), 0);
105
112
  const denominator = referenceScales === undefined ? epsilon + raw : epsilon + slotCost + raw;
106
113
  assertFiniteNonNegative(denominator, `candidate ${node.sourceIndex} density denominator`);
107
114
  const score = node.priority / denominator;
@@ -110,10 +117,10 @@ function density(node, weights, epsilon, referenceScales, slotCost = 1) {
110
117
  }
111
118
  function fits(node, used, capacities, normalized) {
112
119
  for (const name of Object.keys(node.resources)) {
113
- const capacity = capacities[name];
120
+ const capacity = ownResourceNumber(capacities, name);
114
121
  if (capacity === undefined)
115
122
  continue; // unbounded resource
116
- const needed = node.resources[name] ?? 0;
123
+ const needed = ownResourceNumber(node.resources, name) ?? 0;
117
124
  if (normalized && capacity === 0 && needed === 0)
118
125
  continue;
119
126
  const running = used.get(name) ?? 0;
@@ -124,7 +131,7 @@ function fits(node, used, capacities, normalized) {
124
131
  }
125
132
  function reserve(node, used) {
126
133
  for (const name of Object.keys(node.resources)) {
127
- const total = (used.get(name) ?? 0) + (node.resources[name] ?? 0);
134
+ const total = (used.get(name) ?? 0) + (ownResourceNumber(node.resources, name) ?? 0);
128
135
  assertFiniteNonNegative(total, `candidate ${node.sourceIndex} reserved usage.${name}`);
129
136
  used.set(name, total);
130
137
  }
@@ -158,7 +165,7 @@ export function planEcrafAdmissions(options) {
158
165
  // Zero-capacity infeasibility precedes scoring in v2. Validate all other
159
166
  // scores even for singleton and zero-slot batches, before any callbacks.
160
167
  const infeasible = new Set(version === "normalized-v2"
161
- ? candidates.filter((node) => Object.entries(node.resources).some(([name, demand]) => capacities[name] === 0 && demand > 0))
168
+ ? candidates.filter((node) => Object.entries(node.resources).some(([name, demand]) => ownResourceNumber(capacities, name) === 0 && demand > 0))
162
169
  : []);
163
170
  const sorted = candidates
164
171
  .filter((node) => !infeasible.has(node))