@alvin0/ai-agent-sdk-core 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/agent/define/session.d.ts +5 -2
- package/dist/agent/define/session.d.ts.map +1 -1
- package/dist/agent/define/session.js +1 -1
- package/dist/agent/define/session.js.map +1 -1
- package/dist/agent/history/input-work.js +2 -0
- package/dist/agent/history/input-work.js.map +1 -0
- package/dist/agent/loop/control-text.d.ts +6 -0
- package/dist/agent/loop/control-text.d.ts.map +1 -0
- package/dist/agent/loop/control-text.js +2 -0
- package/dist/agent/loop/control-text.js.map +1 -0
- package/dist/agent/loop/run-turn.js +1 -1
- package/dist/agent/loop/run-turn.js.map +1 -1
- package/dist/agent/loop/turn/model-round.js +1 -1
- package/dist/agent/loop/turn/model-round.js.map +1 -1
- package/dist/agent/mode/run-agent.d.ts +8 -15
- package/dist/agent/mode/run-agent.d.ts.map +1 -1
- package/dist/agent/mode/run-agent.js +2 -2
- package/dist/agent/mode/run-agent.js.map +1 -1
- package/dist/agent/team/contracts.d.ts +3 -1
- package/dist/agent/team/contracts.d.ts.map +1 -1
- package/dist/agent/team/managed.d.ts.map +1 -1
- package/dist/agent/team/managed.js +5 -5
- package/dist/agent/team/managed.js.map +1 -1
- package/dist/agent/team/team.d.ts.map +1 -1
- package/dist/agent/team/team.js +1 -1
- package/dist/agent/team/team.js.map +1 -1
- package/dist/agent/tool/pipeline.js +1 -1
- package/dist/agent/tool/pipeline.js.map +1 -1
- package/dist/agent.d.ts +2 -1
- package/dist/agent.js +1 -1
- package/dist/composition/agent/session.js +1 -1
- package/dist/composition/agent/session.js.map +1 -1
- package/dist/composition/agent/types.d.ts +3 -1
- package/dist/composition/agent/types.d.ts.map +1 -1
- package/dist/observability/bus.js +1 -1
- package/dist/primitives/version.d.ts +1 -1
- package/dist/primitives/version.js +1 -1
- package/dist/primitives/version.js.map +1 -1
- package/dist/runtime/registry.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-turn.js","names":[],"sources":["../../../src/agent/loop/run-turn.ts"],"sourcesContent":["import { createUserMessage } from '../../message/index.ts'\nimport { detachedFrozen } from '../../primitives/index.ts'\nimport type { ModelCallReport } from '../../observation/index.ts'\nimport { waitForSettlement } from '../../async/index.ts'\nimport { authoritativeTokenUsage, budgetTokenTotal, summarizeModelCallUsage } from '../accounting/ledger.ts'\nimport { createSpanId, createTraceId, type TraceRef } from '../trace/trace.ts'\nimport type { AgentEvent, ExhaustedBudget, ToolDeclineReason, TurnHooks, TurnOutcome } from './types.ts'\nimport { AwaitedEventQueue } from './queue.ts'\nimport { scheduleToolCalls } from './schedule.ts'\nimport { captureProgramGrants } from '../tool/nested.ts'\nimport { ProgramResultStore } from '../tool/program-results.ts'\nimport { type RunTurnOptions } from './turn/types.ts'\nimport { resolveBounds, positiveFinite, snapshotRunTurnOptions } from './turn/config.ts'\nimport { codedRuntimeError, messageOf, errorCodeOf, now } from './turn/common.ts'\nimport { deliverQueuedInput } from './turn/model-request-boundary.ts'\nimport { runOptionalHook, runHook } from './turn/hooks.ts'\nimport { maintenanceEmitter, emitAssistantContent, textOf } from './turn/content.ts'\nimport { repeatKey, toolActionPattern, repeatedSuffixCycle } from './turn/repetition.ts'\nimport { modelRound } from './turn/model-round.ts'\nimport { accountingUsageStop } from './turn/usage-stop.ts'\nimport { ContextSectionRuntime } from '../context/section.ts'\nimport type { ContextToolTouch } from '../context/types.ts'\n\nfunction hasCallableTools(options: RunTurnOptions): boolean {\n if (options.toolChoice === 'none') return false\n return (options.tools?.names().length ?? 0) > 0 || (options.nativeTools?.length ?? 0) > 0\n}\n\n/** Run one bounded turn as a backpressured event stream. */\nexport function runTurn(options: RunTurnOptions): AsyncIterable<AgentEvent> {\n return {\n async * [Symbol.asyncIterator]() {\n const invocation = snapshotRunTurnOptions(options)\n const queue = new AwaitedEventQueue<AgentEvent>()\n const consumer = new AbortController()\n const teardownTimeoutMs = positiveFinite(invocation.teardownTimeoutMs ?? 30_000, 'teardownTimeoutMs')\n const signal = invocation.signal === undefined\n ? consumer.signal\n : AbortSignal.any([invocation.signal, consumer.signal])\n const task = driveTurn(invocation, signal, event => queue.push(detachedFrozen(event)))\n .then(() => queue.close(), error => queue.fail(error))\n try {\n while (true) {\n const item = await queue.take()\n if (item.done) break\n yield item.value\n }\n await task\n } finally {\n consumer.abort(new Error('turn event consumer stopped'))\n queue.close()\n if (!await waitForSettlement(task, teardownTimeoutMs)) {\n throw codedRuntimeError(\n `turn producer ignored cancellation for more than ${teardownTimeoutMs}ms`,\n 'TURN_TEARDOWN_TIMEOUT',\n consumer.signal.reason,\n )\n }\n }\n },\n }\n}\n\nasync function driveTurn(\n options: RunTurnOptions,\n signal: AbortSignal,\n emit: (event: AgentEvent) => Promise<void>,\n): Promise<void> {\n const bounds = resolveBounds(options.bounds)\n const maxTotalTokens = bounds.maxTotalTokens === 'auto' ? Infinity : bounds.maxTotalTokens\n // Infinity is local control flow only. Public configuration/events retain\n // the serializable 'auto' value, and all other admission guards still apply.\n const maxSteps = bounds.maxSteps === 'auto' ? Infinity : bounds.maxSteps\n const traceId = options.trace?.traceId ?? createTraceId()\n const root: TraceRef = { traceId, spanId: createSpanId(), parentSpanId: options.trace?.parentSpanId ?? null }\n const turn = Math.max(1, options.history.entries().filter(entry =>\n entry.event.kind === 'user' && entry.event.message.source.kind === 'user').length)\n const startedAt = now()\n let steps = 0\n let toolCalls = 0\n // Descending, so \"how many are below the remainder\" counts the crossings.\n const budgetReminders = [...bounds.toolBudgetRemindAt]\n .filter(threshold => threshold > 0 && threshold < bounds.maxToolCalls)\n .sort((left, right) => right - left)\n let budgetRemindersSent = 0\n /** How many full budgets an unwalled turn has spent and been told about. */\n let overBudgetNoticesSent = 0\n /** Sequence of the budget notice currently on the surface, if any. */\n let budgetNoticeSeq: number | undefined\n let stepReminderSent = false\n let tokenRemindersSent = 0\n let consecutiveErrors = 0\n let text = ''\n const modelCallReports: ModelCallReport[] = []\n let reason: TurnOutcome['reason'] | undefined\n let outcome: TurnOutcome\n let lastRepeat: { key: string; count: number } | undefined\n const actionSteps: string[] = []\n const emitMaintenance = maintenanceEmitter(emit, root)\n /**\n * Put the current budget notice on the surface, replacing the previous one.\n *\n * One live notice, never a pile of them. Appending each new remainder leaves\n * \"16 calls remain\" and \"6 calls remain\" both readable, and a model that\n * plans against the older number plans against a budget it no longer has.\n * Codex keeps exactly one `<rollout_budget>` fragment for the same reason\n * (`context/rollout_budget.rs`), replacing it as the number moves.\n * @param text - What the model should read now.\n */\n const appendBudgetNotice = (text: string): void => {\n const message = createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-budget-guard' },\n content: [{ type: 'text', text }],\n })\n const previous = budgetNoticeSeq\n // Replacing is best-effort. Compaction can shadow the earlier notice\n // between steps, and a replace whose target is no longer on the surface is\n // rejected — which must cost the model a reminder, never the turn.\n if (previous !== undefined) {\n try {\n budgetNoticeSeq = options.history.append(\n { kind: 'user', message },\n { op: 'replace', from: previous, to: previous, targets: [previous] },\n ).seq\n return\n } catch {\n budgetNoticeSeq = undefined\n }\n }\n budgetNoticeSeq = options.history.append({ kind: 'user', message }).seq\n }\n const contextSections = options.contextSections === undefined || options.contextSections.length === 0\n ? undefined\n : new ContextSectionRuntime({\n sections: options.contextSections,\n history: options.history,\n ...options.logger === undefined ? {} : { logger: options.logger },\n guard: (pending, name) => runHook(pending, options, signal, name),\n scope: { agentId: options.trace?.agentId, conversationId: options.trace?.conversationId },\n })\n /** Tool calls committed since the last section reconcile. */\n let contextTouches: ContextToolTouch[] = []\n let rootStarted = false\n let rootEnded = false\n const callableTools = hasCallableTools(options)\n const programs = options.experimentalPrograms === undefined ? undefined : captureProgramGrants(options.experimentalPrograms)\n // Handles programs retain live for this turn only.\n const programResults = programs === undefined ? undefined : new ProgramResultStore()\n const dedicatedFinalOutput = options.outputFormat?.type === 'json_schema' && callableTools\n const turnOperationId = options.accounting?.startOperation('turn', {\n data: { turn, model: options.config.model },\n })\n let turnOperationEnded = false\n let usageStop: TurnOutcome['reason'] | undefined\n // Shared by retries, hook continuations, and both finalizer paths. Finalizers\n // may have a separate step allowance, never a separate token allowance.\n const admissionStop = (): TurnOutcome['reason'] | undefined => {\n if (signal.aborted) return { kind: 'aborted' }\n const mandatoryStop = accountingUsageStop(options.accounting)\n if (mandatoryStop !== undefined) return mandatoryStop\n if (usageStop !== undefined) return usageStop\n const tokens = budgetTokenTotal(summarizeModelCallUsage(modelCallReports))\n return tokens !== undefined && tokens >= maxTotalTokens\n ? { kind: 'budget-exhausted', budget: 'tokens', forcedFinalAnswer: false }\n : undefined\n }\n\n try {\n await emit({\n type: 'span-start', trace: root, at: startedAt,\n name: `invoke_agent ${options.trace?.agentId ?? 'agent'}`, kind: 'invoke_agent',\n attributes: {\n 'gen_ai.operation.name': 'invoke_agent',\n 'gen_ai.agent.id': options.trace?.agentId ?? 'agent',\n 'gen_ai.agent.name': options.trace?.agentName ?? options.trace?.agentId ?? 'agent',\n 'gen_ai.request.model': options.config.model,\n ...options.trace?.conversationId === undefined\n ? {}\n : { 'gen_ai.conversation.id': options.trace.conversationId },\n },\n })\n rootStarted = true\n await emit({ type: 'turn-start', turn, trace: root })\n\n turnLifecycle: while (true) {\n while (reason === undefined && steps < maxSteps && !signal.aborted) {\n reason = admissionStop()\n if (reason !== undefined) break\n // Auto has no step countdown. Warn from the same usage total as admission,\n // before a hard token stop can leave the agent without a reporting call.\n const usedTokens = budgetTokenTotal(summarizeModelCallUsage(modelCallReports))\n if (bounds.maxTotalTokens !== 'auto' && usedTokens !== undefined) {\n const crossed = [0.5, 0.75, 0.9].filter(ratio => usedTokens >= maxTotalTokens * ratio).length\n if (crossed > tokenRemindersSent) {\n tokenRemindersSent = crossed\n const remaining = Math.max(0, maxTotalTokens - usedTokens)\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-token-guard' },\n content: [{ type: 'text', text: `Token budget: ${remaining} of ${bounds.maxTotalTokens} aggregate tokens remain. Each request also spends input tokens on the accumulated context. `\n + (crossed >= 2 ? 'Stop broad exploration. ' : 'Prioritize outstanding verification and reporting. ')\n + 'Reserve capacity for the required self-check, honest todo reconciliation and substantive final report. State unavailable evidence and unfinished work; do not claim it is verified. No extra model call is allowed after the hard token limit.',\n }],\n }) })\n }\n }\n // Leave time to reconcile a plan and submit a result before the final\n // tools-disabled summary. Tool-call reminders do not cover step limits.\n if (!stepReminderSent && steps > 0 && maxSteps - steps <= 2) {\n stepReminderSent = true\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-step-guard' },\n content: [{ type: 'text', text:\n `${maxSteps - steps} work steps remain. Finish essential verification, update any task list honestly, and submit the result if required. Summarize findings, evidence, and unfinished work; do not start new exploration.`,\n }],\n }) })\n }\n // Recomputed before the request that will read it, so a section reacting to\n // the previous step's tool calls is already on the surface.\n if (contextSections !== undefined) {\n await contextSections.reconcile(steps, contextTouches, signal)\n contextTouches = []\n }\n const step = steps + 1\n const round = await modelRound(\n options, signal, emit, emitMaintenance, root, turn, step,\n dedicatedFinalOutput\n ? 'process'\n : options.outputFormat?.type === 'json_schema' ? 'final' : 'standard',\n )\n steps++\n if (round.report !== undefined) modelCallReports.push(round.report)\n if (round.message !== undefined) {\n options.history.append({\n kind: 'assistant', message: round.message,\n ...round.finish.kind === 'aborted' ? { interrupted: true as const } : {},\n ...round.usage === undefined ? {} : { usage: round.usage },\n })\n await emit({ type: 'assistant-message', message: round.message, trace: round.trace })\n await emitAssistantContent(round, emit)\n text = textOf(round.message.content)\n }\n usageStop = accountingUsageStop(options.accounting) ?? (round.usageRequired\n ? { kind: 'error', failure: { message: 'provider usage is required by the configured run policy', code: 'USAGE_REQUIRED' } }\n : round.usageUnavailable\n ? { kind: 'usage-unavailable', modelCallId: round.report?.modelCallId ?? 'unknown' }\n : undefined)\n if (signal.aborted || round.finish.kind === 'aborted') { reason = { kind: 'aborted' }; break }\n // Pair emitted tool calls with declined results even when policy stops the\n // run; never execute those calls or allow a retry hook to override policy.\n if (round.finish.kind === 'error' && usageStop !== undefined) {\n reason = { kind: 'error', failure: round.finish.failure }\n break\n }\n if (round.usageRequired && (round.calls.length === 0 || options.tools === undefined)) { reason = usageStop; break }\n if (round.finish.kind === 'error' && !round.usageRequired) {\n reason = admissionStop()\n if (reason !== undefined) break\n const decision = await runOptionalHook(options.hooks?.onRequestError, [{\n turn, step, failure: round.finish.failure, snapshot: options.history.snapshot(), signal,\n ...(options.logger === undefined ? {} : { logger: options.logger }),\n emit: emitMaintenance,\n }], options, signal, 'onRequestError')\n const maintenanceStop = accountingUsageStop(options.accounting)\n if (maintenanceStop !== undefined) { reason = signal.aborted ? { kind: 'aborted' } : maintenanceStop; break }\n if (decision === 'retry' && steps < maxSteps) continue\n reason = { kind: 'error', failure: round.finish.failure }\n break\n }\n if (round.finish.kind === 'max-tokens' && !round.usageRequired) { reason = { kind: 'max-tokens' }; break }\n if (round.calls.length === 0 && round.usageUnavailable) {\n reason = accountingUsageStop(options.accounting) ?? { kind: 'usage-unavailable', modelCallId: round.report?.modelCallId ?? 'unknown' }\n break\n }\n if (round.calls.length === 0 && dedicatedFinalOutput) {\n reason = admissionStop()\n if (reason !== undefined) break\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'structured-output-finalizer' },\n content: [{\n type: 'text',\n text: 'The process phase is complete. Return the final answer now in the requested output format. Do not call tools.',\n }],\n }) })\n const final = await modelRound(\n options, signal, emit, emitMaintenance, root, turn, steps + 1, 'final',\n )\n steps++\n if (final.report !== undefined) modelCallReports.push(final.report)\n if (final.message !== undefined) {\n options.history.append({\n kind: 'assistant', message: final.message,\n ...final.usage === undefined ? {} : { usage: final.usage },\n })\n await emit({ type: 'assistant-message', message: final.message, trace: final.trace })\n await emitAssistantContent(final, emit)\n text = textOf(final.message.content)\n }\n if (final.finish.kind === 'aborted') reason = { kind: 'aborted' }\n else if (final.finish.kind === 'error') reason = { kind: 'error', failure: final.finish.failure }\n else if (final.finish.kind === 'max-tokens') reason = { kind: 'max-tokens' }\n else if (final.usageRequired) reason = { kind: 'error', failure: {\n message: 'provider usage is required by the configured run policy',\n code: 'USAGE_REQUIRED',\n } }\n else if (final.usageUnavailable) {\n reason = accountingUsageStop(options.accounting) ?? { kind: 'usage-unavailable', modelCallId: final.report?.modelCallId ?? 'unknown' }\n } else reason = { kind: 'completed' }\n break\n }\n // A provider that repeated an id had the repeat dropped. Saying so is what\n // keeps the model from reading one result for two calls as a tool that\n // silently ignored it.\n if (round.droppedDuplicateCalls !== undefined) {\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-duplicate-guard' },\n content: [{\n type: 'text',\n text: `You reused the tool-call id ${round.droppedDuplicateCalls.map(id => `'${id}'`).join(', ')}.`\n + ' A result pairs to exactly one call, so the repeat was not run and only the first'\n + ' call of that id has a result. Give every call its own id, and call again if you'\n + ' still need what the dropped one would have done.',\n }],\n }) })\n }\n if (round.calls.length === 0 || options.tools === undefined) { reason = { kind: 'completed' }; break }\n\n // Calls the budget does not govern: submitting, asking, delegating. They\n // are dispatched even when the budget is spent, so the model always has a\n // legal way to finish. See `ToolDefinition.budgetExempt`.\n const budgetedCalls = round.calls\n .filter(call => options.tools?.get(call.toolName)?.budgetExempt !== true).length\n const remaining = Math.max(0, bounds.maxToolCalls - toolCalls)\n let repeatProjection = lastRepeat\n const projectedRepeats = round.calls.map(call => {\n const key = repeatKey(call)\n // Count consecutive calls, not lifetime visits to a source or test command.\n // Distinct intervening work may change its result. Alternating loops are\n // handled separately by the step-cycle guard below.\n const count = repeatProjection?.key === key ? repeatProjection.count + 1 : 1\n repeatProjection = { key, count }\n return count\n })\n const repeatedLimitBeforeDispatch = projectedRepeats.some(count => count >= bounds.repeatToolLimit)\n const actionPattern = toolActionPattern(round.calls)\n const projectedCycle = repeatedSuffixCycle(\n [...actionSteps, actionPattern],\n bounds.maxToolCycleLength,\n )\n const cycleLimitBeforeDispatch = projectedCycle !== undefined\n && projectedCycle.repetitions >= bounds.toolCycleLimit\n const currentUsage = summarizeModelCallUsage(modelCallReports)\n const budgetTokens = budgetTokenTotal(currentUsage)\n const tokenLimitBeforeDispatch = budgetTokens !== undefined\n && budgetTokens >= maxTotalTokens\n const guardDeclined = repeatedLimitBeforeDispatch || cycleLimitBeforeDispatch || tokenLimitBeforeDispatch || round.usageRequired\n // Name the limit that actually declined the call. Reporting a repeat guard\n // as an empty budget teaches the model the wrong lesson, and it repeats the\n // call on the next turn with the budget it was told it lacked.\n const declineReason: ToolDeclineReason = tokenLimitBeforeDispatch\n ? 'tokens'\n : cycleLimitBeforeDispatch\n ? 'tool-call-cycle'\n : repeatedLimitBeforeDispatch\n ? 'repeated-tool-call'\n : round.usageRequired\n ? 'usage-required'\n : 'tool-calls'\n // `continue` takes the wall down: the budget becomes a notice and the turn\n // is bounded by steps, tokens, and the run-level ledger instead. Guards\n // that mean \"this is not working\" still decline, whatever the setting.\n const budgetIsAWall = bounds.onExhausted !== 'continue'\n const scheduled = await scheduleToolCalls({\n calls: round.calls, catalog: options.tools, history: options.history,\n position: { turn, step,\n ...(options.accounting === undefined ? {} : { runId: options.accounting.runId }),\n ...(options.trace?.conversationId === undefined ? {} : { conversationId: options.trace.conversationId }),\n }, signal, parentTrace: root,\n maxParallel: bounds.maxParallel,\n dispatchLimit: guardDeclined ? 0 : budgetIsAWall ? remaining : round.calls.length,\n declineReason,\n maxResultBytes: bounds.maxToolResultBytes,\n maxResultTokens: bounds.maxToolResultTokens,\n resultOverflow: bounds.toolResultOverflow,\n ...options.spillStore === undefined ? {} : { spillStore: options.spillStore },\n maxDurationMs: bounds.maxToolDurationMs,\n teardownTimeoutMs: bounds.toolTeardownTimeoutMs,\n ...(options.logger === undefined ? {} : { logger: options.logger }),\n ...options.interceptors === undefined ? {} : { interceptors: options.interceptors },\n ...options.approvals === undefined ? {} : { approvals: options.approvals },\n ...options.accounting === undefined ? {} : { accounting: options.accounting },\n emit,\n ...options.hooks?.checkpoint === undefined ? {} : {\n checkpoint: (context: Parameters<NonNullable<TurnHooks['checkpoint']>>[0]) => runHook(\n Promise.resolve(options.hooks?.checkpoint?.(context)), options, signal, 'checkpoint',\n ),\n },\n }, {\n admissionLimit: guardDeclined ? 0 : budgetIsAWall ? remaining : 'unbounded',\n ...programs === undefined ? {} : { programs },\n ...programResults === undefined ? {} : { programResults },\n })\n // Results commit in model order, one per requested call, so the pairing\n // holds for declined calls too. A short result list means a sibling failed\n // its contract and the turn is already unwinding; reporting a guessed\n // outcome would be worse than reporting nothing.\n if (contextSections !== undefined && scheduled.results.length === round.calls.length) {\n contextTouches.push(...round.calls.map((call, index) => ({\n toolName: call.toolName,\n rawArguments: call.rawArguments,\n failed: scheduled.results[index]?.isError ?? true,\n })))\n }\n toolCalls += scheduled.budgeted\n const remainingAfterDispatch = Math.max(0, bounds.maxToolCalls - toolCalls)\n // One reminder per threshold crossed, not one per turn.\n //\n // This was a single boolean: the model was told once, at 25% remaining,\n // and then never again however close it came to the end. A model warned at\n // sixteen calls left and still exploring at four has been told nothing\n // since, and runs into the wall with no notice — which is what produces a\n // red \"no remaining tool-call budget\" where an answer should have been.\n //\n // Codex counts thresholds rather than remembering a flag\n // (`rollout_budget.rs`, `reminder_index`): every threshold now below the\n // remaining budget that has not been reported yet gets reported. Crossing\n // several at once collapses into the one that matters, the lowest.\n const crossed = budgetReminders.filter(threshold => remainingAfterDispatch <= threshold).length\n if (crossed > budgetRemindersSent && remainingAfterDispatch > 0) {\n budgetRemindersSent = crossed\n appendBudgetNotice(\n `Tool budget: ${remainingAfterDispatch} of ${bounds.maxToolCalls} calls remain in this turn.`\n + ' Stop broad exploration, make the necessary edits, and reserve calls for'\n + (budgetIsAWall\n ? ' verification. When the budget runs out no further work call will run, so'\n + ' finish with what you can still verify.'\n : ' verification. Past the budget you are expected to be wrapping up, not'\n + ' opening new lines of work.'),\n )\n }\n // Past the budget with the wall down. The turn is not stopped — the model\n // keeps its tools — but it is told, once per further budget spent, that it\n // is now expected to be finishing. This is the shape of Codex's\n // `budget_limit` goal prompt: no new substantive work, wrap up, name what\n // is left.\n if (!budgetIsAWall && remainingAfterDispatch === 0) {\n const windows = Math.floor(toolCalls / bounds.maxToolCalls)\n if (windows > overBudgetNoticesSent) {\n overBudgetNoticesSent = windows\n appendBudgetNotice(\n `Tool budget spent: ${toolCalls} calls made against a budget of ${bounds.maxToolCalls}.`\n + ' Do not start new substantive work. Finish what is in flight, verify what you'\n + ' can, and answer — stating plainly what is unverified or unfinished.',\n )\n }\n }\n await emit({ type: 'step-end', turn, step, trace: round.trace })\n\n actionSteps.push(actionPattern)\n let repeatedLimit = repeatedLimitBeforeDispatch\n for (let index = 0; index < round.calls.length; index++) {\n const call = round.calls[index]\n const result = scheduled.results[index]\n if (call === undefined || result === undefined) continue\n consecutiveErrors = result.isError ? consecutiveErrors + 1 : 0\n const key = repeatKey(call)\n const count = lastRepeat?.key === key ? lastRepeat.count + 1 : 1\n lastRepeat = { key, count }\n if (count === bounds.repeatToolWarningAt) {\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-repeat-guard' },\n content: [{ type: 'text', text: `You have called ${call.toolName} with the same arguments ${count} consecutive times. Reassess before repeating it.` }],\n }) })\n }\n if (count >= bounds.repeatToolLimit) repeatedLimit = true\n }\n if (projectedCycle?.repetitions === bounds.toolCycleWarningAt) {\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-cycle-guard' },\n content: [{\n type: 'text',\n text: `Tool-use pattern repeated ${projectedCycle.repetitions} times across ${projectedCycle.period} step(s). Reassess the approach and identify concrete new evidence before continuing.`,\n }],\n }) })\n }\n if (scheduled.concluded) { reason = { kind: 'concluded-by-tool', toolName: scheduled.concludedBy ?? 'unknown' }; break }\n if (signal.aborted) { reason = { kind: 'aborted' }; break }\n if (round.usageRequired) { reason = usageStop; break }\n if (round.usageUnavailable) {\n reason = accountingUsageStop(options.accounting) ?? { kind: 'usage-unavailable', modelCallId: round.report?.modelCallId ?? 'unknown' }\n break\n }\n let exhausted: ExhaustedBudget | undefined\n const reportReserveReached = bounds.maxTotalTokens !== 'auto'\n && bounds.finalReportReserveTokens > 0 && budgetTokens !== undefined\n && budgetTokens >= maxTotalTokens - bounds.finalReportReserveTokens\n if (tokenLimitBeforeDispatch) exhausted = 'tokens'\n else if (reportReserveReached) exhausted = 'tokens'\n else if (cycleLimitBeforeDispatch) exhausted = 'tool-call-cycle'\n else if (budgetIsAWall && budgetedCalls > remaining) exhausted = 'tool-calls'\n else if (consecutiveErrors >= bounds.maxConsecutiveToolErrors) exhausted = 'consecutive-tool-errors'\n else if (repeatedLimit) exhausted = 'repeated-tool-call'\n else if (steps >= maxSteps) exhausted = 'steps'\n if (exhausted !== undefined) {\n const forced = (exhausted !== 'tokens' || (reportReserveReached && !tokenLimitBeforeDispatch))\n && bounds.onExhausted !== 'stop'\n && admissionStop() === undefined\n if (forced) {\n const final = await modelRound(\n options, signal, emit, emitMaintenance, root, turn, steps + 1, 'forced-final',\n )\n steps++\n if (final.report !== undefined) modelCallReports.push(final.report)\n if (final.message !== undefined) {\n options.history.append({ kind: 'assistant', message: final.message, ...final.usage === undefined ? {} : { usage: final.usage } })\n await emit({ type: 'assistant-message', message: final.message, trace: final.trace })\n await emitAssistantContent(final, emit)\n text = textOf(final.message.content)\n }\n if (final.finish.kind === 'aborted') {\n reason = { kind: 'aborted' }\n break\n }\n if (final.finish.kind === 'error') {\n reason = { kind: 'error', failure: final.finish.failure }\n break\n }\n if (final.finish.kind === 'max-tokens') {\n reason = { kind: 'max-tokens' }\n break\n }\n if (final.usageRequired) {\n reason = { kind: 'error', failure: {\n message: 'provider usage is required by the configured run policy',\n code: 'USAGE_REQUIRED',\n } }\n break\n }\n if (final.usageUnavailable) {\n reason = accountingUsageStop(options.accounting) ?? { kind: 'usage-unavailable', modelCallId: final.report?.modelCallId ?? 'unknown' }\n break\n }\n }\n reason = { kind: 'budget-exhausted', budget: exhausted, forcedFinalAnswer: forced,\n ...(exhausted === 'tokens' && reportReserveReached && !tokenLimitBeforeDispatch\n ? { trigger: 'report-reserve' as const } : {}),\n }\n }\n }\n\n if (reason === undefined) {\n reason = signal.aborted\n ? { kind: 'aborted' }\n : { kind: 'budget-exhausted', budget: 'steps', forcedFinalAnswer: false }\n }\n const usageReport = summarizeModelCallUsage(modelCallReports)\n const usage = authoritativeTokenUsage(usageReport)\n const candidate: TurnOutcome = {\n reason, text, steps, usageReport, toolCalls, traceId,\n ...usage === undefined ? {} : { usage },\n }\n const entriesBeforeHook = options.history.entries().length\n const canContinue = reason.kind === 'completed'\n && steps < maxSteps\n && admissionStop() === undefined\n await runOptionalHook(options.hooks?.onTurnEnd, [{\n outcome: candidate,\n snapshot: options.history.snapshot(),\n canContinue,\n }], options, signal, 'onTurnEnd')\n // Hooks object by appending context rather than by returning a veto. Re-run only\n // a normally completed turn; abort/error/budget outcomes remain terminal.\n // Input the person sent while the final answer was being written is owed an\n // answer too: when nothing else continues the turn, take it and continue.\n if (canContinue\n && !signal.aborted\n && (options.history.entries().length > entriesBeforeHook || deliverQueuedInput(options.history))) {\n reason = undefined\n continue turnLifecycle\n }\n outcome = candidate\n break\n }\n if (outcome.reason.kind === 'aborted') {\n // Without this, the next turn sees an unfinished request and a cancelled\n // tool call, and a model resumes the abandoned work instead of answering\n // the new message (observed live). Codex and Claude Code record the same\n // interruption marker.\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'turn-interrupted' },\n content: [{ type: 'text', text: 'The previous request was interrupted before it finished. Use the next message to determine what to do next.' }],\n }) })\n }\n await emit({\n type: 'span-end', trace: root, at: now(),\n status: outcome.reason.kind === 'error' ? 'error' : outcome.reason.kind === 'aborted' ? 'aborted' : 'success',\n output: { reason: outcome.reason, text },\n ...outcome.usage === undefined ? {} : { usage: outcome.usage },\n ...outcome.reason.kind === 'error' ? { error: { type: 'ModelError', message: outcome.reason.failure.message, code: outcome.reason.failure.code } } : {},\n })\n rootEnded = true\n if (turnOperationId !== undefined) {\n options.accounting?.endOperation(\n turnOperationId,\n outcome.reason.kind === 'error' ? 'error' : outcome.reason.kind === 'aborted' ? 'aborted' : 'success',\n { data: { reason: outcome.reason.kind, steps, toolCalls } },\n )\n turnOperationEnded = true\n }\n await emit({ type: 'turn-end', outcome, trace: root })\n } catch (error: unknown) {\n const code = errorCodeOf(error)\n if (rootStarted && !rootEnded) {\n await emit({\n type: 'span-end', trace: root, at: now(), status: signal.aborted ? 'aborted' : 'error',\n error: {\n type: error instanceof Error ? error.name : 'RuntimeError',\n message: messageOf(error),\n ...code === undefined ? {} : { code },\n },\n }).catch(() => undefined)\n }\n if (turnOperationId !== undefined && !turnOperationEnded) {\n options.accounting?.endOperation(\n turnOperationId,\n signal.aborted ? 'aborted' : 'error',\n { error },\n )\n turnOperationEnded = true\n }\n throw error\n } finally {\n programResults?.close()\n }\n}\n\n\nexport type { RunTurnOptions } from './turn/types.ts'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-turn.js","names":[],"sources":["../../../src/agent/loop/run-turn.ts"],"sourcesContent":["import { createUserMessage } from '../../message/index.ts'\nimport { detachedFrozen } from '../../primitives/index.ts'\nimport type { ModelCallReport } from '../../observation/index.ts'\nimport { waitForSettlement } from '../../async/index.ts'\nimport { authoritativeTokenUsage, budgetTokenTotal, summarizeModelCallUsage } from '../accounting/ledger.ts'\nimport { createSpanId, createTraceId, type TraceRef } from '../trace/trace.ts'\nimport type { AgentEvent, ExhaustedBudget, ToolDeclineReason, TurnHooks, TurnOutcome } from './types.ts'\nimport { AwaitedEventQueue } from './queue.ts'\nimport { scheduleToolCalls } from './schedule.ts'\nimport { captureProgramGrants } from '../tool/nested.ts'\nimport { ProgramResultStore } from '../tool/program-results.ts'\nimport { type RunTurnOptions } from './turn/types.ts'\nimport { resolveBounds, positiveFinite, snapshotRunTurnOptions } from './turn/config.ts'\nimport { codedRuntimeError, messageOf, errorCodeOf, now } from './turn/common.ts'\nimport { deliverQueuedInput } from './turn/model-request-boundary.ts'\nimport { runOptionalHook, runHook } from './turn/hooks.ts'\nimport { maintenanceEmitter, emitAssistantContent, textOf } from './turn/content.ts'\nimport { repeatKey, toolActionPattern, repeatedSuffixCycle } from './turn/repetition.ts'\nimport { modelRound } from './turn/model-round.ts'\nimport { accountingUsageStop } from './turn/usage-stop.ts'\nimport { ContextSectionRuntime } from '../context/section.ts'\nimport type { ContextToolTouch } from '../context/types.ts'\n\nfunction hasCallableTools(options: RunTurnOptions): boolean {\n if (options.toolChoice === 'none') return false\n return (options.tools?.names().length ?? 0) > 0 || (options.nativeTools?.length ?? 0) > 0\n}\n\n/** Run one bounded turn as a backpressured event stream. */\nexport function runTurn(options: RunTurnOptions): AsyncIterable<AgentEvent> {\n return {\n async * [Symbol.asyncIterator]() {\n const invocation = snapshotRunTurnOptions(options)\n const queue = new AwaitedEventQueue<AgentEvent>()\n const consumer = new AbortController()\n const teardownTimeoutMs = positiveFinite(invocation.teardownTimeoutMs ?? 30_000, 'teardownTimeoutMs')\n const signal = invocation.signal === undefined\n ? consumer.signal\n : AbortSignal.any([invocation.signal, consumer.signal])\n const task = driveTurn(invocation, signal, event => queue.push(detachedFrozen(event)))\n .then(() => queue.close(), error => queue.fail(error))\n try {\n while (true) {\n const item = await queue.take()\n if (item.done) break\n yield item.value\n }\n await task\n } finally {\n consumer.abort(new Error('turn event consumer stopped'))\n queue.close()\n if (!await waitForSettlement(task, teardownTimeoutMs)) {\n throw codedRuntimeError(\n `turn producer ignored cancellation for more than ${teardownTimeoutMs}ms`,\n 'TURN_TEARDOWN_TIMEOUT',\n consumer.signal.reason,\n )\n }\n }\n },\n }\n}\n\nasync function driveTurn(\n options: RunTurnOptions,\n signal: AbortSignal,\n emit: (event: AgentEvent) => Promise<void>,\n): Promise<void> {\n const bounds = resolveBounds(options.bounds)\n const maxTotalTokens = bounds.maxTotalTokens === 'auto' ? Infinity : bounds.maxTotalTokens\n // Infinity is local control flow only. Public configuration/events retain\n // the serializable 'auto' value, and all other admission guards still apply.\n const maxSteps = bounds.maxSteps === 'auto' ? Infinity : bounds.maxSteps\n const traceId = options.trace?.traceId ?? createTraceId()\n const root: TraceRef = { traceId, spanId: createSpanId(), parentSpanId: options.trace?.parentSpanId ?? null }\n const turn = Math.max(1, options.history.entries().filter(entry =>\n entry.event.kind === 'user' && entry.event.message.source.kind === 'user').length)\n const startedAt = now()\n let steps = 0\n let toolCalls = 0\n // Descending, so \"how many are below the remainder\" counts the crossings.\n const budgetReminders = [...bounds.toolBudgetRemindAt]\n .filter(threshold => threshold > 0 && threshold < bounds.maxToolCalls)\n .sort((left, right) => right - left)\n let budgetRemindersSent = 0\n /** How many full budgets an unwalled turn has spent and been told about. */\n let overBudgetNoticesSent = 0\n /** Sequence of the budget notice currently on the surface, if any. */\n let budgetNoticeSeq: number | undefined\n let stepReminderSent = false\n let tokenRemindersSent = 0\n let consecutiveErrors = 0\n let text = ''\n const modelCallReports: ModelCallReport[] = []\n let reason: TurnOutcome['reason'] | undefined\n let outcome: TurnOutcome\n let lastRepeat: { key: string; count: number } | undefined\n const actionSteps: string[] = []\n const emitMaintenance = maintenanceEmitter(emit, root)\n /**\n * Put the current budget notice on the surface, replacing the previous one.\n *\n * One live notice, never a pile of them. Appending each new remainder leaves\n * \"16 calls remain\" and \"6 calls remain\" both readable, and a model that\n * plans against the older number plans against a budget it no longer has.\n * Codex keeps exactly one `<rollout_budget>` fragment for the same reason\n * (`context/rollout_budget.rs`), replacing it as the number moves.\n * @param text - What the model should read now.\n */\n const appendBudgetNotice = (text: string): void => {\n const message = createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-budget-guard' },\n content: [{ type: 'text', text }],\n })\n const previous = budgetNoticeSeq\n // Replacing is best-effort. Compaction can shadow the earlier notice\n // between steps, and a replace whose target is no longer on the surface is\n // rejected — which must cost the model a reminder, never the turn.\n if (previous !== undefined) {\n try {\n budgetNoticeSeq = options.history.append(\n { kind: 'user', message },\n { op: 'replace', from: previous, to: previous, targets: [previous] },\n ).seq\n return\n } catch {\n budgetNoticeSeq = undefined\n }\n }\n budgetNoticeSeq = options.history.append({ kind: 'user', message }).seq\n }\n const contextSections = options.contextSections === undefined || options.contextSections.length === 0\n ? undefined\n : new ContextSectionRuntime({\n sections: options.contextSections,\n history: options.history,\n ...options.logger === undefined ? {} : { logger: options.logger },\n guard: (pending, name) => runHook(pending, options, signal, name),\n scope: { agentId: options.trace?.agentId, conversationId: options.trace?.conversationId },\n })\n /** Tool calls committed since the last section reconcile. */\n let contextTouches: ContextToolTouch[] = []\n let rootStarted = false\n let rootEnded = false\n const callableTools = hasCallableTools(options)\n const programs = options.experimentalPrograms === undefined ? undefined : captureProgramGrants(options.experimentalPrograms)\n // Handles programs retain live for this turn only.\n const programResults = programs === undefined ? undefined : new ProgramResultStore()\n const dedicatedFinalOutput = options.outputFormat?.type === 'json_schema' && callableTools\n const turnOperationId = options.accounting?.startOperation('turn', {\n data: { turn, model: options.config.model },\n })\n let turnOperationEnded = false\n let usageStop: TurnOutcome['reason'] | undefined\n // Shared by retries, hook continuations, and both finalizer paths. Finalizers\n // may have a separate step allowance, never a separate token allowance.\n const admissionStop = (): TurnOutcome['reason'] | undefined => {\n if (signal.aborted) return { kind: 'aborted' }\n const mandatoryStop = accountingUsageStop(options.accounting)\n if (mandatoryStop !== undefined) return mandatoryStop\n if (usageStop !== undefined) return usageStop\n const tokens = budgetTokenTotal(summarizeModelCallUsage(modelCallReports))\n return tokens !== undefined && tokens >= maxTotalTokens\n ? { kind: 'budget-exhausted', budget: 'tokens', forcedFinalAnswer: false }\n : undefined\n }\n\n try {\n await emit({\n type: 'span-start', trace: root, at: startedAt,\n name: `invoke_agent ${options.trace?.agentId ?? 'agent'}`, kind: 'invoke_agent',\n attributes: {\n 'gen_ai.operation.name': 'invoke_agent',\n 'gen_ai.agent.id': options.trace?.agentId ?? 'agent',\n 'gen_ai.agent.name': options.trace?.agentName ?? options.trace?.agentId ?? 'agent',\n 'gen_ai.request.model': options.config.model,\n ...options.trace?.conversationId === undefined\n ? {}\n : { 'gen_ai.conversation.id': options.trace.conversationId },\n },\n })\n rootStarted = true\n await emit({ type: 'turn-start', turn, trace: root })\n\n turnLifecycle: while (true) {\n while (reason === undefined && steps < maxSteps && !signal.aborted) {\n reason = admissionStop()\n if (reason !== undefined) break\n // Auto has no step countdown. Warn from the same usage total as admission,\n // before a hard token stop can leave the agent without a reporting call.\n const usedTokens = budgetTokenTotal(summarizeModelCallUsage(modelCallReports))\n if (bounds.maxTotalTokens !== 'auto' && usedTokens !== undefined) {\n const crossed = [0.5, 0.75, 0.9].filter(ratio => usedTokens >= maxTotalTokens * ratio).length\n if (crossed > tokenRemindersSent) {\n tokenRemindersSent = crossed\n const remaining = Math.max(0, maxTotalTokens - usedTokens)\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-token-guard' },\n content: [{ type: 'text', text: `Token budget: ${remaining} of ${bounds.maxTotalTokens} aggregate tokens remain. Each request also spends input tokens on the accumulated context. `\n + (crossed >= 2 ? 'Stop broad exploration. ' : 'Prioritize outstanding verification and reporting. ')\n + 'Reserve capacity for the required self-check, honest todo reconciliation and substantive final report. State unavailable evidence and unfinished work; do not claim it is verified. No extra model call is allowed after the hard token limit.',\n }],\n }) })\n }\n }\n // Leave time to reconcile a plan and submit a result before the final\n // tools-disabled summary. Tool-call reminders do not cover step limits.\n if (!stepReminderSent && steps > 0 && maxSteps - steps <= 2) {\n stepReminderSent = true\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-step-guard' },\n content: [{ type: 'text', text:\n `${maxSteps - steps} work steps remain. Finish essential verification, update any task list honestly, and submit the result if required. Summarize findings, evidence, and unfinished work; do not start new exploration.`,\n }],\n }) })\n }\n // Recomputed before the request that will read it, so a section reacting to\n // the previous step's tool calls is already on the surface.\n if (contextSections !== undefined) {\n await contextSections.reconcile(steps, contextTouches, signal)\n contextTouches = []\n }\n const step = steps + 1\n const round = await modelRound(\n options, signal, emit, emitMaintenance, root, turn, step,\n dedicatedFinalOutput\n ? 'process'\n : options.outputFormat?.type === 'json_schema' ? 'final' : 'standard',\n )\n steps++\n if (round.report !== undefined) modelCallReports.push(round.report)\n if (round.message !== undefined) {\n options.history.append({\n kind: 'assistant', message: round.message,\n ...round.finish.kind === 'aborted' ? { interrupted: true as const } : {},\n ...round.usage === undefined ? {} : { usage: round.usage },\n })\n await emit({ type: 'assistant-message', message: round.message, trace: round.trace })\n await emitAssistantContent(round, emit)\n text = textOf(round.message.content)\n } else if (round.finish.kind === 'stop') {\n // A successful empty round cannot answer new input with earlier text.\n // Keep earlier text only when a later request fails or is interrupted.\n text = ''\n }\n usageStop = accountingUsageStop(options.accounting) ?? (round.usageRequired\n ? { kind: 'error', failure: { message: 'provider usage is required by the configured run policy', code: 'USAGE_REQUIRED' } }\n : round.usageUnavailable\n ? { kind: 'usage-unavailable', modelCallId: round.report?.modelCallId ?? 'unknown' }\n : undefined)\n if (signal.aborted || round.finish.kind === 'aborted') { reason = { kind: 'aborted' }; break }\n // Pair emitted tool calls with declined results even when policy stops the\n // run; never execute those calls or allow a retry hook to override policy.\n if (round.finish.kind === 'error' && usageStop !== undefined) {\n reason = { kind: 'error', failure: round.finish.failure }\n break\n }\n if (round.usageRequired && (round.calls.length === 0 || options.tools === undefined)) { reason = usageStop; break }\n if (round.finish.kind === 'error' && !round.usageRequired) {\n reason = admissionStop()\n if (reason !== undefined) break\n const decision = await runOptionalHook(options.hooks?.onRequestError, [{\n turn, step, failure: round.finish.failure, snapshot: options.history.snapshot(), signal,\n ...(options.logger === undefined ? {} : { logger: options.logger }),\n emit: emitMaintenance,\n }], options, signal, 'onRequestError')\n const maintenanceStop = accountingUsageStop(options.accounting)\n if (maintenanceStop !== undefined) { reason = signal.aborted ? { kind: 'aborted' } : maintenanceStop; break }\n if (decision === 'retry' && steps < maxSteps) continue\n reason = { kind: 'error', failure: round.finish.failure }\n break\n }\n if (round.finish.kind === 'max-tokens' && !round.usageRequired) { reason = { kind: 'max-tokens' }; break }\n if (round.calls.length === 0 && round.usageUnavailable) {\n reason = accountingUsageStop(options.accounting) ?? { kind: 'usage-unavailable', modelCallId: round.report?.modelCallId ?? 'unknown' }\n break\n }\n if (round.calls.length === 0 && dedicatedFinalOutput) {\n reason = admissionStop()\n if (reason !== undefined) break\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'structured-output-finalizer' },\n content: [{\n type: 'text',\n text: 'The process phase is complete. Return the final answer now in the requested output format. Do not call tools.',\n }],\n }) })\n const final = await modelRound(\n options, signal, emit, emitMaintenance, root, turn, steps + 1, 'final',\n )\n steps++\n if (final.report !== undefined) modelCallReports.push(final.report)\n if (final.message !== undefined) {\n options.history.append({\n kind: 'assistant', message: final.message,\n ...final.usage === undefined ? {} : { usage: final.usage },\n })\n await emit({ type: 'assistant-message', message: final.message, trace: final.trace })\n await emitAssistantContent(final, emit)\n text = textOf(final.message.content)\n }\n if (final.finish.kind === 'aborted') reason = { kind: 'aborted' }\n else if (final.finish.kind === 'error') reason = { kind: 'error', failure: final.finish.failure }\n else if (final.finish.kind === 'max-tokens') reason = { kind: 'max-tokens' }\n else if (final.usageRequired) reason = { kind: 'error', failure: {\n message: 'provider usage is required by the configured run policy',\n code: 'USAGE_REQUIRED',\n } }\n else if (final.usageUnavailable) {\n reason = accountingUsageStop(options.accounting) ?? { kind: 'usage-unavailable', modelCallId: final.report?.modelCallId ?? 'unknown' }\n } else reason = { kind: 'completed' }\n break\n }\n // A provider that repeated an id had the repeat dropped. Saying so is what\n // keeps the model from reading one result for two calls as a tool that\n // silently ignored it.\n if (round.droppedDuplicateCalls !== undefined) {\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-duplicate-guard' },\n content: [{\n type: 'text',\n text: `You reused the tool-call id ${round.droppedDuplicateCalls.map(id => `'${id}'`).join(', ')}.`\n + ' A result pairs to exactly one call, so the repeat was not run and only the first'\n + ' call of that id has a result. Give every call its own id, and call again if you'\n + ' still need what the dropped one would have done.',\n }],\n }) })\n }\n if (round.calls.length === 0 || options.tools === undefined) { reason = { kind: 'completed' }; break }\n\n // Calls the budget does not govern: submitting, asking, delegating. They\n // are dispatched even when the budget is spent, so the model always has a\n // legal way to finish. See `ToolDefinition.budgetExempt`.\n const budgetedCalls = round.calls\n .filter(call => options.tools?.get(call.toolName)?.budgetExempt !== true).length\n const remaining = Math.max(0, bounds.maxToolCalls - toolCalls)\n let repeatProjection = lastRepeat\n const projectedRepeats = round.calls.map(call => {\n const key = repeatKey(call)\n // Count consecutive calls, not lifetime visits to a source or test command.\n // Distinct intervening work may change its result. Alternating loops are\n // handled separately by the step-cycle guard below.\n const count = repeatProjection?.key === key ? repeatProjection.count + 1 : 1\n repeatProjection = { key, count }\n return count\n })\n const repeatedLimitBeforeDispatch = projectedRepeats.some(count => count >= bounds.repeatToolLimit)\n const actionPattern = toolActionPattern(round.calls)\n const projectedCycle = repeatedSuffixCycle(\n [...actionSteps, actionPattern],\n bounds.maxToolCycleLength,\n )\n const cycleLimitBeforeDispatch = projectedCycle !== undefined\n && projectedCycle.repetitions >= bounds.toolCycleLimit\n const currentUsage = summarizeModelCallUsage(modelCallReports)\n const budgetTokens = budgetTokenTotal(currentUsage)\n const tokenLimitBeforeDispatch = budgetTokens !== undefined\n && budgetTokens >= maxTotalTokens\n const guardDeclined = repeatedLimitBeforeDispatch || cycleLimitBeforeDispatch || tokenLimitBeforeDispatch || round.usageRequired\n // Name the limit that actually declined the call. Reporting a repeat guard\n // as an empty budget teaches the model the wrong lesson, and it repeats the\n // call on the next turn with the budget it was told it lacked.\n const declineReason: ToolDeclineReason = tokenLimitBeforeDispatch\n ? 'tokens'\n : cycleLimitBeforeDispatch\n ? 'tool-call-cycle'\n : repeatedLimitBeforeDispatch\n ? 'repeated-tool-call'\n : round.usageRequired\n ? 'usage-required'\n : 'tool-calls'\n // `continue` takes the wall down: the budget becomes a notice and the turn\n // is bounded by steps, tokens, and the run-level ledger instead. Guards\n // that mean \"this is not working\" still decline, whatever the setting.\n const budgetIsAWall = bounds.onExhausted !== 'continue'\n const scheduled = await scheduleToolCalls({\n calls: round.calls, catalog: options.tools, history: options.history,\n position: { turn, step,\n ...(options.accounting === undefined ? {} : { runId: options.accounting.runId }),\n ...(options.trace?.conversationId === undefined ? {} : { conversationId: options.trace.conversationId }),\n }, signal, parentTrace: root,\n maxParallel: bounds.maxParallel,\n dispatchLimit: guardDeclined ? 0 : budgetIsAWall ? remaining : round.calls.length,\n declineReason,\n maxResultBytes: bounds.maxToolResultBytes,\n maxResultTokens: bounds.maxToolResultTokens,\n resultOverflow: bounds.toolResultOverflow,\n ...options.spillStore === undefined ? {} : { spillStore: options.spillStore },\n maxDurationMs: bounds.maxToolDurationMs,\n teardownTimeoutMs: bounds.toolTeardownTimeoutMs,\n ...(options.logger === undefined ? {} : { logger: options.logger }),\n ...options.interceptors === undefined ? {} : { interceptors: options.interceptors },\n ...options.approvals === undefined ? {} : { approvals: options.approvals },\n ...options.accounting === undefined ? {} : { accounting: options.accounting },\n emit,\n ...options.hooks?.checkpoint === undefined ? {} : {\n checkpoint: (context: Parameters<NonNullable<TurnHooks['checkpoint']>>[0]) => runHook(\n Promise.resolve(options.hooks?.checkpoint?.(context)), options, signal, 'checkpoint',\n ),\n },\n }, {\n admissionLimit: guardDeclined ? 0 : budgetIsAWall ? remaining : 'unbounded',\n ...programs === undefined ? {} : { programs },\n ...programResults === undefined ? {} : { programResults },\n })\n // Results commit in model order, one per requested call, so the pairing\n // holds for declined calls too. A short result list means a sibling failed\n // its contract and the turn is already unwinding; reporting a guessed\n // outcome would be worse than reporting nothing.\n if (contextSections !== undefined && scheduled.results.length === round.calls.length) {\n contextTouches.push(...round.calls.map((call, index) => ({\n toolName: call.toolName,\n rawArguments: call.rawArguments,\n failed: scheduled.results[index]?.isError ?? true,\n })))\n }\n toolCalls += scheduled.budgeted\n const remainingAfterDispatch = Math.max(0, bounds.maxToolCalls - toolCalls)\n // One reminder per threshold crossed, not one per turn.\n //\n // This was a single boolean: the model was told once, at 25% remaining,\n // and then never again however close it came to the end. A model warned at\n // sixteen calls left and still exploring at four has been told nothing\n // since, and runs into the wall with no notice — which is what produces a\n // red \"no remaining tool-call budget\" where an answer should have been.\n //\n // Codex counts thresholds rather than remembering a flag\n // (`rollout_budget.rs`, `reminder_index`): every threshold now below the\n // remaining budget that has not been reported yet gets reported. Crossing\n // several at once collapses into the one that matters, the lowest.\n const crossed = budgetReminders.filter(threshold => remainingAfterDispatch <= threshold).length\n if (crossed > budgetRemindersSent && remainingAfterDispatch > 0) {\n budgetRemindersSent = crossed\n appendBudgetNotice(\n `Tool budget: ${remainingAfterDispatch} of ${bounds.maxToolCalls} calls remain in this turn.`\n + ' Stop broad exploration, make the necessary edits, and reserve calls for'\n + (budgetIsAWall\n ? ' verification. When the budget runs out no further work call will run, so'\n + ' finish with what you can still verify.'\n : ' verification. Past the budget you are expected to be wrapping up, not'\n + ' opening new lines of work.'),\n )\n }\n // Past the budget with the wall down. The turn is not stopped — the model\n // keeps its tools — but it is told, once per further budget spent, that it\n // is now expected to be finishing. This is the shape of Codex's\n // `budget_limit` goal prompt: no new substantive work, wrap up, name what\n // is left.\n if (!budgetIsAWall && remainingAfterDispatch === 0) {\n const windows = Math.floor(toolCalls / bounds.maxToolCalls)\n if (windows > overBudgetNoticesSent) {\n overBudgetNoticesSent = windows\n appendBudgetNotice(\n `Tool budget spent: ${toolCalls} calls made against a budget of ${bounds.maxToolCalls}.`\n + ' Do not start new substantive work. Finish what is in flight, verify what you'\n + ' can, and answer — stating plainly what is unverified or unfinished.',\n )\n }\n }\n await emit({ type: 'step-end', turn, step, trace: round.trace })\n\n actionSteps.push(actionPattern)\n let repeatedLimit = repeatedLimitBeforeDispatch\n for (let index = 0; index < round.calls.length; index++) {\n const call = round.calls[index]\n const result = scheduled.results[index]\n if (call === undefined || result === undefined) continue\n consecutiveErrors = result.isError ? consecutiveErrors + 1 : 0\n const key = repeatKey(call)\n const count = lastRepeat?.key === key ? lastRepeat.count + 1 : 1\n lastRepeat = { key, count }\n if (count === bounds.repeatToolWarningAt) {\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-repeat-guard' },\n content: [{ type: 'text', text: `You have called ${call.toolName} with the same arguments ${count} consecutive times. Reassess before repeating it.` }],\n }) })\n }\n if (count >= bounds.repeatToolLimit) repeatedLimit = true\n }\n if (projectedCycle?.repetitions === bounds.toolCycleWarningAt) {\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'tool-loop-cycle-guard' },\n content: [{\n type: 'text',\n text: `Tool-use pattern repeated ${projectedCycle.repetitions} times across ${projectedCycle.period} step(s). Reassess the approach and identify concrete new evidence before continuing.`,\n }],\n }) })\n }\n if (scheduled.concluded) { reason = { kind: 'concluded-by-tool', toolName: scheduled.concludedBy ?? 'unknown' }; break }\n if (signal.aborted) { reason = { kind: 'aborted' }; break }\n if (round.usageRequired) { reason = usageStop; break }\n if (round.usageUnavailable) {\n reason = accountingUsageStop(options.accounting) ?? { kind: 'usage-unavailable', modelCallId: round.report?.modelCallId ?? 'unknown' }\n break\n }\n let exhausted: ExhaustedBudget | undefined\n const reportReserveReached = bounds.maxTotalTokens !== 'auto'\n && bounds.finalReportReserveTokens > 0 && budgetTokens !== undefined\n && budgetTokens >= maxTotalTokens - bounds.finalReportReserveTokens\n if (tokenLimitBeforeDispatch) exhausted = 'tokens'\n else if (reportReserveReached) exhausted = 'tokens'\n else if (cycleLimitBeforeDispatch) exhausted = 'tool-call-cycle'\n else if (budgetIsAWall && budgetedCalls > remaining) exhausted = 'tool-calls'\n else if (consecutiveErrors >= bounds.maxConsecutiveToolErrors) exhausted = 'consecutive-tool-errors'\n else if (repeatedLimit) exhausted = 'repeated-tool-call'\n else if (steps >= maxSteps) exhausted = 'steps'\n if (exhausted !== undefined) {\n const forced = (exhausted !== 'tokens' || (reportReserveReached && !tokenLimitBeforeDispatch))\n && bounds.onExhausted !== 'stop'\n && admissionStop() === undefined\n if (forced) {\n const final = await modelRound(\n options, signal, emit, emitMaintenance, root, turn, steps + 1, 'forced-final',\n )\n steps++\n if (final.report !== undefined) modelCallReports.push(final.report)\n if (final.message !== undefined) {\n options.history.append({ kind: 'assistant', message: final.message, ...final.usage === undefined ? {} : { usage: final.usage } })\n await emit({ type: 'assistant-message', message: final.message, trace: final.trace })\n await emitAssistantContent(final, emit)\n text = textOf(final.message.content)\n }\n if (final.finish.kind === 'aborted') {\n reason = { kind: 'aborted' }\n break\n }\n if (final.finish.kind === 'error') {\n reason = { kind: 'error', failure: final.finish.failure }\n break\n }\n if (final.finish.kind === 'max-tokens') {\n reason = { kind: 'max-tokens' }\n break\n }\n if (final.usageRequired) {\n reason = { kind: 'error', failure: {\n message: 'provider usage is required by the configured run policy',\n code: 'USAGE_REQUIRED',\n } }\n break\n }\n if (final.usageUnavailable) {\n reason = accountingUsageStop(options.accounting) ?? { kind: 'usage-unavailable', modelCallId: final.report?.modelCallId ?? 'unknown' }\n break\n }\n }\n reason = { kind: 'budget-exhausted', budget: exhausted, forcedFinalAnswer: forced,\n ...(exhausted === 'tokens' && reportReserveReached && !tokenLimitBeforeDispatch\n ? { trigger: 'report-reserve' as const } : {}),\n }\n }\n }\n\n if (reason === undefined) {\n reason = signal.aborted\n ? { kind: 'aborted' }\n : { kind: 'budget-exhausted', budget: 'steps', forcedFinalAnswer: false }\n }\n const usageReport = summarizeModelCallUsage(modelCallReports)\n const usage = authoritativeTokenUsage(usageReport)\n const candidate: TurnOutcome = {\n reason, text, steps, usageReport, toolCalls, traceId,\n ...usage === undefined ? {} : { usage },\n }\n const entriesBeforeHook = options.history.entries().length\n const canContinue = reason.kind === 'completed'\n && steps < maxSteps\n && admissionStop() === undefined\n await runOptionalHook(options.hooks?.onTurnEnd, [{\n outcome: candidate,\n snapshot: options.history.snapshot(),\n canContinue,\n }], options, signal.aborted ? new AbortController().signal : signal, 'onTurnEnd')\n // Hooks object by appending context rather than by returning a veto. Re-run only\n // a normally completed turn; abort/error/budget outcomes remain terminal.\n // Input the person sent while the final answer was being written is owed an\n // answer too: when nothing else continues the turn, take it and continue.\n if (canContinue\n && !signal.aborted\n && (options.history.entries().length > entriesBeforeHook || deliverQueuedInput(options.history))) {\n reason = undefined\n continue turnLifecycle\n }\n outcome = candidate\n break\n }\n if (outcome.reason.kind === 'aborted') {\n // Without this, the next turn sees an unfinished request and a cancelled\n // tool call, and a model resumes the abandoned work instead of answering\n // the new message (observed live). Codex and Claude Code record the same\n // interruption marker.\n options.history.append({ kind: 'user', message: createUserMessage({\n source: { kind: 'app', producer: 'turn-interrupted' },\n content: [{ type: 'text', text: 'The previous request was interrupted before it finished. Use the next message to determine what to do next.' }],\n }) })\n }\n await emit({\n type: 'span-end', trace: root, at: now(),\n status: outcome.reason.kind === 'error' ? 'error' : outcome.reason.kind === 'aborted' ? 'aborted' : 'success',\n output: { reason: outcome.reason, text },\n ...outcome.usage === undefined ? {} : { usage: outcome.usage },\n ...outcome.reason.kind === 'error' ? { error: { type: 'ModelError', message: outcome.reason.failure.message, code: outcome.reason.failure.code } } : {},\n })\n rootEnded = true\n if (turnOperationId !== undefined) {\n options.accounting?.endOperation(\n turnOperationId,\n outcome.reason.kind === 'error' ? 'error' : outcome.reason.kind === 'aborted' ? 'aborted' : 'success',\n { data: { reason: outcome.reason.kind, steps, toolCalls } },\n )\n turnOperationEnded = true\n }\n await emit({ type: 'turn-end', outcome, trace: root })\n } catch (error: unknown) {\n const code = errorCodeOf(error)\n if (rootStarted && !rootEnded) {\n await emit({\n type: 'span-end', trace: root, at: now(), status: signal.aborted ? 'aborted' : 'error',\n error: {\n type: error instanceof Error ? error.name : 'RuntimeError',\n message: messageOf(error),\n ...code === undefined ? {} : { code },\n },\n }).catch(() => undefined)\n }\n if (turnOperationId !== undefined && !turnOperationEnded) {\n options.accounting?.endOperation(\n turnOperationId,\n signal.aborted ? 'aborted' : 'error',\n { error },\n )\n turnOperationEnded = true\n }\n throw error\n } finally {\n programResults?.close()\n }\n}\n\n\nexport type { RunTurnOptions } from './turn/types.ts'\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createSpanId as e}from"../../../observation/context.js";import{MODEL_ERROR_CODES as t}from"../../../errors/model-error.js";import{BlockAssembler as n}from"../../../stream/assembler.js";import{normalizeToolPairing as r}from"../../history/normalize.js";import{observeModelRequestBoundary as i}from"./model-request-boundary.js";import{stepProjectionSources as a}from"./step-projection.js";import{positiveFinite as o,positiveSafeInteger as s}from"./config.js";import{messageOf as c,modelAbortedFinish as ee,modelFailureFinish as l,now as u,serializedBytes as d}from"./common.js";import{StreamAbortError as te,closeIterator as ne,nextWithAbort as re}from"./cancellation.js";import{runOptionalHook as f}from"./hooks.js";import{classifyTextPhases as p,contentTiming as m,createAssistant as ie,dropDuplicateToolCalls as ae,invalidHostToolCall as oe,recentToolResultIds as se,systemText as ce,textOf as h}from"./content.js";import{validateStreamChunk as le}from"./validation.js";import{accountingUsageStop as ue}from"./usage-stop.js";function g(e){let t=e.replace(/\s+/gu,` `).trim();return t.length>600?`${t.slice(0,600)}…`:t}function _(e){let t=[],n=[];for(let r of e.content)r.type===`text`||r.type===`reasoning`?t.push(r.text):r.type===`tool-call`?n.push(`${r.name}(${g(r.arguments)})`):r.type===`tool-result`?t.push(h(r.content)):t.push(`[${r.type}]`);return{role:e.role,producer:e.source.kind,...t.length===0?{}:{text:g(t.join(` `))},...n.length===0?{}:{toolCalls:n}}}function de(e){let t=e.messages??[],n=Math.max(0,t.length-8);return{messageCount:t.length,...t.at(-1)===void 0?{}:{lastMessageId:t.at(-1)?.id},...e.system===void 0?{}:{system:g(e.system)},...e.tools===void 0||e.tools.length===0?{}:{tools:e.tools.map(e=>e.name)},...e.toolChoice===void 0?{}:{toolChoice:e.toolChoice},...n===0?{}:{earlierMessagesOmitted:n},messages:t.slice(-8).map(_)}}async function v(g,_,v,pe,me,y,b,x){let S=x===`forced-final`,C=x===`final`||S,w={traceId:me.traceId,spanId:e(),parentSpanId:me.spanId},T=r(g.history.messages()),he=T,E=se(g.history),ge=g.history.generation(),_e=g.history.entries().length,D=()=>{let e=ue(g.accounting);if(!(e===void 0&&!_.aborted))return{trace:w,finish:_.aborted?{kind:`aborted`,failure:{code:`ABORTED`,message:c(_.reason)}}:{kind:`stop`},calls:[],afterToolCallIds:E,timing:m(!1,E.length>0),...e?.kind===`error`?{usageRequired:!0}:{},...e?.kind===`usage-unavailable`?{usageUnavailable:!0}:{}}},O=D();if(O!==void 0)return O;let k=await f(g.hooks?.beforeStep,[{turn:y,step:b,messages:T,snapshot:g.history.snapshot(),signal:_,...g.logger===void 0?{}:{logger:g.logger},emit:pe}],g,_,`beforeStep`),A=D();if(A!==void 0)return A;if(k?.kind===`reject`)return{trace:w,finish:{kind:`error`,failure:{message:k.reason,code:`STEP_REJECTED`}},calls:[],afterToolCallIds:E,timing:m(!1,E.length>0)};if((g.history.generation()!==ge||g.history.entries().length!==_e)&&(T=r(g.history.messages())),k?.messages!==void 0){let e=a(k)??new Set(he.map(e=>e.id)),t=new Set(k.messages.map(e=>e.id)),n=T.filter(n=>!e.has(n.id)&&!t.has(n.id)),i=new Set(T.map(e=>e.id)),o=[...e].some(e=>!i.has(e)),s=new Map(k.messages.map(e=>[e.id,e]));T=r(o?[...k.messages.filter(t=>!e.has(t.id)&&!i.has(t.id)&&t.source.kind===`app`),...T.flatMap(t=>{let n=s.get(t.id);return n===void 0?e.has(t.id)?[]:[t]:[n]})]:[...k.messages,...n])}k?.prepend!==void 0&&(T=Object.freeze([...k.prepend,...T]));let j=ce(g,S),M=[...g.tools?.schemas()??[],...g.nativeTools??[]],N=!C&&g.outputFormat?.type===`json_schema`?{type:`text`}:g.outputFormat,P={...g.config,messages:T,...j.length===0?{}:{system:j},...M.length===0?{}:{tools:M},...C&&M.length>0?{toolChoice:`none`}:g.toolChoice===void 0?{}:{toolChoice:g.toolChoice},...g.imagePolicy===void 0?{}:{imagePolicy:g.imagePolicy},...g.documentPolicy===void 0?{}:{documentPolicy:g.documentPolicy},...N===void 0?{}:{outputFormat:N}},ve={...P,signal:_};i(g.history,!0);try{await f(g.hooks?.checkpoint,[{kind:`before-model-request`,request:ve,snapshot:g.history.snapshot(),signal:_,...g.logger===void 0?{}:{logger:g.logger}}],g,_,`checkpoint`)}catch(e){return i(g.history,!1),{trace:w,finish:{kind:`error`,failure:{message:`history checkpoint failed: ${c(e)}`,code:`CHECKPOINT_FAILED`}},calls:[],afterToolCallIds:E,timing:m(!1,E.length>0)}}let F=D();if(F!==void 0)return i(g.history,!1),F;await v({type:`span-start`,trace:w,at:u(),name:`chat ${g.config.model}`,kind:`chat`,attributes:{"gen_ai.operation.name":`chat`,"gen_ai.request.model":g.config.model,...g.config.reasoningEffort===void 0?{}:{"gen_ai.request.reasoning_effort":g.config.reasoningEffort},turn:y,step:b,forcedFinal:S,phase:x},input:de(P)}),await v({type:`step-start`,turn:y,step:b,trace:w,...S?{forcedFinal:!0}:{}});let I=new n,L=new Set,R=o(g.modelTimeoutMs??6e5,`modelTimeoutMs`),z=s(g.maxModelRequestBytes??33554432,`maxModelRequestBytes`),B=s(g.maxModelResponseBytes??33554432,`maxModelResponseBytes`),V=s(g.maxModelStreamEvents??1e5,`maxModelStreamEvents`),ye=o(g.teardownTimeoutMs??3e4,`teardownTimeoutMs`),H,be=!1,xe=!1,U;try{U=d(P)}catch(e){U=-1,I.push(l(`model request is not serializable: ${c(e)}`,`INVALID_MODEL_REQUEST`))}if(U>z)I.push(l(`model request exceeds the ${z}-byte limit`,`MODEL_REQUEST_TOO_LARGE`));else if(U>=0){let e=new AbortController,t=AbortSignal.any([_,e.signal]),n=!1,r=setTimeout(()=>{n=!0,e.abort(Error(`model stream exceeded ${R}ms`))},R),i=g.registry.stream({...P,signal:t},g.accounting?.modelInvocation),a=i[Symbol.asyncIterator](),o=!1,s=0,u=0,f=!1;try{for(;;){let n=await re(a.next(),t);if(n.done===!0){o=!0;break}let r=n.value;try{le(r,V)}catch(t){I.push(l(`model adapter emitted an invalid stream chunk: ${c(t)}`,`INVALID_MODEL_STREAM`)),e.abort(Error(`invalid model stream chunk`));break}s++;try{u+=d(r)}catch(t){I.push(l(`model adapter emitted a non-serializable stream chunk: ${c(t)}`,`INVALID_MODEL_STREAM`)),e.abort(Error(`non-serializable model stream chunk`));break}if(s>V||u>B){let t=s>V?`${V}-event`:`${B}-byte`;I.push(l(`model response exceeds the ${t} limit`,`MODEL_RESPONSE_TOO_LARGE`)),e.abort(Error(`model response resource limit exceeded`));break}if(f){I.push(l(`model adapter emitted data after its terminal finish chunk`,`INVALID_MODEL_STREAM`)),e.abort(Error(`invalid model stream`));break}I.push(r),!((r.type===`text-delta`||r.type===`reasoning-delta`||r.type===`tool-call-delta`)&&L.has(r.index))&&(r.type===`block-end`&&L.add(r.index),r.type===`finish`&&(f=!0),r.type===`text-delta`?await v({type:`text-delta`,index:r.index,text:r.text,phase:x===`process`?`commentary`:r.phase??`unknown`,trace:w}):r.type===`reasoning-delta`?await v({type:`reasoning-delta`,index:r.index,text:r.text,trace:w}):r.type===`image-delta`?await v({type:`image-delta`,itemId:r.itemId,data:r.data,mediaType:r.mediaType,...r.partialIndex===void 0?{}:{partialIndex:r.partialIndex},trace:w}):r.type===`usage`?await v({type:`usage`,usage:r.usage,trace:w}):r.type===`usage-progress`&&await v({...r,trace:w}))}}catch(e){if(!(e instanceof te))throw e;I.push(_.aborted?ee(c(_.reason??e)):n?l(`model stream exceeded ${R}ms`,`MODEL_TIMEOUT`):l(c(e.cause??e),`MODEL_STREAM_ABORTED`))}finally{clearTimeout(r),o||(e.abort(Error(`model stream closed before exhaustion`)),await ne(a,ye)||I.push(l(`model stream ignored cancellation for more than ${ye}ms; the adapter operation may still be running`,`MODEL_TEARDOWN_TIMEOUT`)))}let p=await i.report,m=g.accounting===void 0?void 0:await g.accounting.recordModelCall(p,{...P,signal:_});H=m?.report??p,be=m?.usageRequired??!1,xe=m?.usageUnavailable??!1}let W=I.finish,G=W.kind===`aborted`,K;try{K=W.kind===`aborted`?I.interruptedBlocks():I.blocks()}catch(e){W={kind:`error`,failure:{message:`model adapter emitted an invalid block sequence: ${c(e)}`,code:`INVALID_MODEL_STREAM`}},G=!0,K=I.interruptedBlocks()}let Se=I.textBlocks().filter(({block:e})=>!G||e.text.trim()!==``),Ce=0,we=p(K.map(e=>{if(e.type!==`text`)return e;let t=Se[Ce++];return e.phase===void 0&&t?.beforeNativeCall?{...e,phase:`commentary`}:e}),x===`process`,I.hasToolCalls),q=ae(we,g.history),J=q.blocks,Te=C&&g.outputFormat?.type===`json_schema`&&W.kind===`stop`&&!fe(h(J),g.validateOutput)?{message:`model returned invalid JSON or failed the structured output validator`,code:t.MALFORMED_RESPONSE}:void 0,Y=(C&&J.some(e=>e.type===`tool-call`)?{message:`model emitted a host tool call during the final output phase`,code:`INVALID_TOOL_CALL`}:void 0)??Te??oe(J,g.history),X=Y===void 0?J:J.filter(e=>e.type!==`tool-call`),Z=Y===void 0?W:{kind:`error`,failure:Y},Q=X.length===0&&(Z.kind===`error`||Z.kind===`aborted`)?void 0:ie(g,X,G?void 0:I.replayState),$=Q?.content.filter(e=>e.type===`tool-call`).map(e=>({callId:e.id,toolName:e.name,rawArguments:e.arguments}))??[],Ee=m($.length>0,E.length>0);if(X.some(e=>e.type===`text`)){let e=Se.map(({index:e})=>e),t=Z.kind===`error`||Z.kind===`aborted`||Z.kind===`max-tokens`,n=0;for(let r of X){if(r.type!==`text`)continue;let i=e[n++];i!==void 0&&await v({type:`text-end`,index:i,text:r.text,phase:r.phase??`final-answer`,trace:w,...t?{incomplete:!0}:{}})}}return await v({type:`span-end`,trace:w,at:u(),status:Z.kind===`error`?`error`:Z.kind===`aborted`?`aborted`:`success`,output:Q===void 0?void 0:{text:h(Q.content),commentary:Q.content.flatMap(e=>e.type===`text`&&e.phase===`commentary`?[e.text]:[]),reasoning:Q.content.flatMap(e=>e.type===`reasoning`?[e.text]:[]),toolCalls:$.length},...I.usage===void 0?{}:{usage:I.usage},...Z.kind===`error`||Z.kind===`aborted`?{error:{type:`ModelError`,message:Z.failure.message,code:Z.failure.code}}:{}}),($.length===0||C)&&await v({type:`step-end`,turn:y,step:b,trace:w}),{trace:w,...Q===void 0?{}:{message:Q},finish:Z,...I.usage===void 0?{}:{usage:I.usage},...H===void 0?{}:{report:H},...be?{usageRequired:!0}:{},...xe?{usageUnavailable:!0}:{},calls:$,afterToolCallIds:E,timing:Ee,...q.dropped.length===0?{}:{droppedDuplicateCalls:q.dropped}}}function fe(e,t){try{let n=JSON.parse(e);return t?.(n),!0}catch{return!1}}export{v as modelRound};
|
|
1
|
+
import{createSpanId as e}from"../../../observation/context.js";import{MODEL_ERROR_CODES as t}from"../../../errors/model-error.js";import{BlockAssembler as n}from"../../../stream/assembler.js";import{normalizeToolPairing as r}from"../../history/normalize.js";import{observeModelRequestBoundary as i}from"./model-request-boundary.js";import{stepProjectionSources as a}from"./step-projection.js";import{positiveFinite as o,positiveSafeInteger as s}from"./config.js";import{messageOf as c,modelAbortedFinish as ee,modelFailureFinish as l,now as u,serializedBytes as te}from"./common.js";import{StreamAbortError as ne,closeIterator as re,nextWithAbort as ie}from"./cancellation.js";import{runOptionalHook as d}from"./hooks.js";import{classifyTextPhases as f,contentTiming as p,createAssistant as ae,dropDuplicateToolCalls as oe,invalidHostToolCall as se,recentToolResultIds as ce,systemText as le,textOf as m}from"./content.js";import{UNCHANGED_ANSWER_MARKER as ue}from"../control-text.js";import{validateStreamChunk as de}from"./validation.js";import{accountingUsageStop as fe}from"./usage-stop.js";function h(e){let t=e.replace(/\s+/gu,` `).trim();return t.length>600?`${t.slice(0,600)}…`:t}function g(e){let t=[],n=[];for(let r of e.content)r.type===`text`||r.type===`reasoning`?t.push(r.text):r.type===`tool-call`?n.push(`${r.name}(${h(r.arguments)})`):r.type===`tool-result`?t.push(m(r.content)):t.push(`[${r.type}]`);return{role:e.role,producer:e.source.kind,...t.length===0?{}:{text:h(t.join(` `))},...n.length===0?{}:{toolCalls:n}}}function pe(e){let t=e.messages??[],n=Math.max(0,t.length-8);return{messageCount:t.length,...t.at(-1)===void 0?{}:{lastMessageId:t.at(-1)?.id},...e.system===void 0?{}:{system:h(e.system)},...e.tools===void 0||e.tools.length===0?{}:{tools:e.tools.map(e=>e.name)},...e.toolChoice===void 0?{}:{toolChoice:e.toolChoice},...n===0?{}:{earlierMessagesOmitted:n},messages:t.slice(-8).map(g)}}async function _(h,g,_,he,ge,v,y,b){let x=b===`forced-final`,S=b===`final`||x,C={traceId:ge.traceId,spanId:e(),parentSpanId:ge.spanId},w=r(h.history.messages()),_e=w,T=ce(h.history),ve=h.history.generation(),ye=h.history.entries().length,E=()=>{let e=fe(h.accounting);if(!(e===void 0&&!g.aborted))return{trace:C,finish:g.aborted?{kind:`aborted`,failure:{code:`ABORTED`,message:c(g.reason)}}:{kind:`stop`},calls:[],afterToolCallIds:T,timing:p(!1,T.length>0),...e?.kind===`error`?{usageRequired:!0}:{},...e?.kind===`usage-unavailable`?{usageUnavailable:!0}:{}}},D=E();if(D!==void 0)return D;let O=await d(h.hooks?.beforeStep,[{turn:v,step:y,messages:w,snapshot:h.history.snapshot(),signal:g,...h.logger===void 0?{}:{logger:h.logger},emit:he}],h,g,`beforeStep`),k=E();if(k!==void 0)return k;if(O?.kind===`reject`)return{trace:C,finish:{kind:`error`,failure:{message:O.reason,code:`STEP_REJECTED`}},calls:[],afterToolCallIds:T,timing:p(!1,T.length>0)};if((h.history.generation()!==ve||h.history.entries().length!==ye)&&(w=r(h.history.messages())),O?.messages!==void 0){let e=a(O)??new Set(_e.map(e=>e.id)),t=new Set(O.messages.map(e=>e.id)),n=w.filter(n=>!e.has(n.id)&&!t.has(n.id)),i=new Set(w.map(e=>e.id)),o=[...e].some(e=>!i.has(e)),s=new Map(O.messages.map(e=>[e.id,e]));w=r(o?[...O.messages.filter(t=>!e.has(t.id)&&!i.has(t.id)&&t.source.kind===`app`),...w.flatMap(t=>{let n=s.get(t.id);return n===void 0?e.has(t.id)?[]:[t]:[n]})]:[...O.messages,...n])}O?.prepend!==void 0&&(w=Object.freeze([...O.prepend,...w]));let A=le(h,x),j=[...h.tools?.schemas()??[],...h.nativeTools??[]],M=!S&&h.outputFormat?.type===`json_schema`?{type:`text`}:h.outputFormat,N={...h.config,messages:w,...A.length===0?{}:{system:A},...j.length===0?{}:{tools:j},...S&&j.length>0?{toolChoice:`none`}:h.toolChoice===void 0?{}:{toolChoice:h.toolChoice},...h.imagePolicy===void 0?{}:{imagePolicy:h.imagePolicy},...h.documentPolicy===void 0?{}:{documentPolicy:h.documentPolicy},...M===void 0?{}:{outputFormat:M}},be={...N,signal:g};i(h.history,!0);try{await d(h.hooks?.checkpoint,[{kind:`before-model-request`,request:be,snapshot:h.history.snapshot(),signal:g,...h.logger===void 0?{}:{logger:h.logger}}],h,g,`checkpoint`)}catch(e){return i(h.history,!1),{trace:C,finish:{kind:`error`,failure:{message:`history checkpoint failed: ${c(e)}`,code:`CHECKPOINT_FAILED`}},calls:[],afterToolCallIds:T,timing:p(!1,T.length>0)}}let P=E();if(P!==void 0)return i(h.history,!1),P;await _({type:`span-start`,trace:C,at:u(),name:`chat ${h.config.model}`,kind:`chat`,attributes:{"gen_ai.operation.name":`chat`,"gen_ai.request.model":h.config.model,...h.config.reasoningEffort===void 0?{}:{"gen_ai.request.reasoning_effort":h.config.reasoningEffort},turn:v,step:y,forcedFinal:x,phase:b},input:pe(N)}),await _({type:`step-start`,turn:v,step:y,trace:C,...x?{forcedFinal:!0}:{}});let F=new n,I=new Set,L=o(h.modelTimeoutMs??6e5,`modelTimeoutMs`),R=s(h.maxModelRequestBytes??33554432,`maxModelRequestBytes`),z=s(h.maxModelResponseBytes??33554432,`maxModelResponseBytes`),B=s(h.maxModelStreamEvents??1e5,`maxModelStreamEvents`),xe=o(h.teardownTimeoutMs??3e4,`teardownTimeoutMs`),V,Se=!1,Ce=!1,H;try{H=te(N)}catch(e){H=-1,F.push(l(`model request is not serializable: ${c(e)}`,`INVALID_MODEL_REQUEST`))}if(H>R)F.push(l(`model request exceeds the ${R}-byte limit`,`MODEL_REQUEST_TOO_LARGE`));else if(H>=0){let e=new AbortController,t=AbortSignal.any([g,e.signal]),n=!1,r=setTimeout(()=>{n=!0,e.abort(Error(`model stream exceeded ${L}ms`))},L),i=h.registry.stream({...N,signal:t},h.accounting?.modelInvocation),a=i[Symbol.asyncIterator](),o=!1,s=0,u=0,d=!1;try{for(;;){let n=await ie(a.next(),t);if(n.done===!0){o=!0;break}let r=n.value;try{de(r,B)}catch(t){F.push(l(`model adapter emitted an invalid stream chunk: ${c(t)}`,`INVALID_MODEL_STREAM`)),e.abort(Error(`invalid model stream chunk`));break}s++;try{u+=te(r)}catch(t){F.push(l(`model adapter emitted a non-serializable stream chunk: ${c(t)}`,`INVALID_MODEL_STREAM`)),e.abort(Error(`non-serializable model stream chunk`));break}if(s>B||u>z){let t=s>B?`${B}-event`:`${z}-byte`;F.push(l(`model response exceeds the ${t} limit`,`MODEL_RESPONSE_TOO_LARGE`)),e.abort(Error(`model response resource limit exceeded`));break}if(d){F.push(l(`model adapter emitted data after its terminal finish chunk`,`INVALID_MODEL_STREAM`)),e.abort(Error(`invalid model stream`));break}F.push(r),!((r.type===`text-delta`||r.type===`reasoning-delta`||r.type===`tool-call-delta`)&&I.has(r.index))&&(r.type===`block-end`&&I.add(r.index),r.type===`finish`&&(d=!0),r.type===`text-delta`?await _({type:`text-delta`,index:r.index,text:r.text,phase:b===`process`?`commentary`:r.phase??`unknown`,trace:C}):r.type===`reasoning-delta`?await _({type:`reasoning-delta`,index:r.index,text:r.text,trace:C}):r.type===`image-delta`?await _({type:`image-delta`,itemId:r.itemId,data:r.data,mediaType:r.mediaType,...r.partialIndex===void 0?{}:{partialIndex:r.partialIndex},trace:C}):r.type===`usage`?await _({type:`usage`,usage:r.usage,trace:C}):r.type===`usage-progress`&&await _({...r,trace:C}))}}catch(e){if(!(e instanceof ne))throw e;F.push(g.aborted?ee(c(g.reason??e)):n?l(`model stream exceeded ${L}ms`,`MODEL_TIMEOUT`):l(c(e.cause??e),`MODEL_STREAM_ABORTED`))}finally{clearTimeout(r),o||(e.abort(Error(`model stream closed before exhaustion`)),await re(a,xe)||F.push(l(`model stream ignored cancellation for more than ${xe}ms; the adapter operation may still be running`,`MODEL_TEARDOWN_TIMEOUT`)))}let f=await i.report,p=h.accounting===void 0?void 0:await h.accounting.recordModelCall(f,{...N,signal:g});V=p?.report??f,Se=p?.usageRequired??!1,Ce=p?.usageUnavailable??!1}let U=F.finish,W=U.kind===`aborted`,G;try{G=U.kind===`aborted`?F.interruptedBlocks():F.blocks()}catch(e){U={kind:`error`,failure:{message:`model adapter emitted an invalid block sequence: ${c(e)}`,code:`INVALID_MODEL_STREAM`}},W=!0,G=F.interruptedBlocks()}let we=F.textBlocks().filter(({block:e})=>!W||e.text.trim()!==``),Te=0,Ee=f(G.map(e=>{if(e.type!==`text`)return e;let t=we[Te++];return e.phase===void 0&&t?.beforeNativeCall?{...e,phase:`commentary`}:e}),b===`process`,F.hasToolCalls),K=oe(Ee,h.history),q=K.blocks,De=S&&h.outputFormat?.type===`json_schema`&&U.kind===`stop`&&!me(m(q),h.validateOutput)?{message:`model returned invalid JSON or failed the structured output validator`,code:t.MALFORMED_RESPONSE}:void 0,J=(S&&q.some(e=>e.type===`tool-call`)?{message:`model emitted a host tool call during the final output phase`,code:`INVALID_TOOL_CALL`}:void 0)??De??se(q,h.history),Y=J===void 0?q:q.filter(e=>e.type!==`tool-call`),X=Y.some(e=>e.type===`tool-call`)?Y.map(e=>e.type===`text`?{...e,text:e.text.replaceAll(ue,``)}:e):Y,Z=J===void 0?U:{kind:`error`,failure:J},Q=X.length===0?void 0:ae(h,X,W?void 0:F.replayState),$=Q?.content.filter(e=>e.type===`tool-call`).map(e=>({callId:e.id,toolName:e.name,rawArguments:e.arguments}))??[],Oe=p($.length>0,T.length>0);if(X.some(e=>e.type===`text`)){let e=we.map(({index:e})=>e),t=Z.kind===`error`||Z.kind===`aborted`||Z.kind===`max-tokens`,n=0;for(let r of X){if(r.type!==`text`)continue;let i=e[n++];i!==void 0&&await _({type:`text-end`,index:i,text:r.text,phase:r.phase??`final-answer`,trace:C,...t?{incomplete:!0}:{}})}}return await _({type:`span-end`,trace:C,at:u(),status:Z.kind===`error`?`error`:Z.kind===`aborted`?`aborted`:`success`,output:Q===void 0?void 0:{text:m(Q.content),commentary:Q.content.flatMap(e=>e.type===`text`&&e.phase===`commentary`?[e.text]:[]),reasoning:Q.content.flatMap(e=>e.type===`reasoning`?[e.text]:[]),toolCalls:$.length},...F.usage===void 0?{}:{usage:F.usage},...Z.kind===`error`||Z.kind===`aborted`?{error:{type:`ModelError`,message:Z.failure.message,code:Z.failure.code}}:{}}),($.length===0||S)&&await _({type:`step-end`,turn:v,step:y,trace:C}),{trace:C,...Q===void 0?{}:{message:Q},finish:Z,...F.usage===void 0?{}:{usage:F.usage},...V===void 0?{}:{report:V},...Se?{usageRequired:!0}:{},...Ce?{usageUnavailable:!0}:{},calls:$,afterToolCallIds:T,timing:Oe,...K.dropped.length===0?{}:{droppedDuplicateCalls:K.dropped}}}function me(e,t){try{let n=JSON.parse(e);return t?.(n),!0}catch{return!1}}export{_ as modelRound};
|
|
2
2
|
//# sourceMappingURL=model-round.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-round.js","names":[],"sources":["../../../../src/agent/loop/turn/model-round.ts"],"sourcesContent":["import type { GenerateOptions } from '../../../contract/index.ts'\nimport { MODEL_ERROR_CODES, type ModelFailure } from '../../../errors/index.ts'\nimport type { ContentBlock, Message, ToolCallBlock } from '../../../message/index.ts'\nimport { BlockAssembler } from '../../../stream/index.ts'\nimport type { FinishReason } from '../../../stream/index.ts'\nimport type { ModelCallReport } from '../../../observation/index.ts'\nimport { normalizeToolPairing } from '../../history/normalize.ts'\nimport { createSpanId, type TraceRef } from '../../trace/trace.ts'\nimport type { AgentEvent, AgentMaintenanceEvent } from '../types.ts'\nimport { type ModelRoundPhase, type RunTurnOptions, type RoundResult } from './types.ts'\nimport { positiveFinite, positiveSafeInteger } from './config.ts'\nimport { serializedBytes, modelFailureFinish, modelAbortedFinish, messageOf, now } from './common.ts'\nimport { validateStreamChunk } from './validation.ts'\nimport { StreamAbortError, nextWithAbort, closeIterator } from './cancellation.ts'\nimport { runOptionalHook } from './hooks.ts'\nimport { stepProjectionSources } from './step-projection.ts'\nimport { observeModelRequestBoundary } from './model-request-boundary.ts'\nimport { accountingUsageStop } from './usage-stop.ts'\nimport {\n classifyTextPhases, dropDuplicateToolCalls, invalidHostToolCall, contentTiming,\n recentToolResultIds, systemText,\n createAssistant, textOf,\n} from './content.ts'\n\n/** How much of one message the trace keeps. */\nconst PREVIEW_CHARS = 600\n\n/** How many trailing messages the trace keeps. */\nconst PREVIEW_MESSAGES = 8\n\nfunction clip(text: string): string {\n const flattened = text.replace(/\\s+/gu, ' ').trim()\n return flattened.length > PREVIEW_CHARS ? `${flattened.slice(0, PREVIEW_CHARS)}…` : flattened\n}\n\n/** One message as a line: who spoke, and what the model could read of it. */\nfunction previewMessage(message: Message): Record<string, unknown> {\n const parts: string[] = []\n const calls: string[] = []\n for (const block of message.content) {\n if (block.type === 'text' || block.type === 'reasoning') parts.push(block.text)\n else if (block.type === 'tool-call') calls.push(`${block.name}(${clip(block.arguments)})`)\n else if (block.type === 'tool-result') parts.push(textOf(block.content))\n else parts.push(`[${block.type}]`)\n }\n return {\n role: message.role,\n producer: message.source.kind,\n ...parts.length === 0 ? {} : { text: clip(parts.join(' ')) },\n ...calls.length === 0 ? {} : { toolCalls: calls },\n }\n}\n\n/**\n * What this round sent the model, in a form a person can read.\n *\n * A summary, not a copy: the request can be the whole conversation plus every\n * tool schema, and a trace that stored it verbatim would be larger than the\n * work it describes. What survives is the part that explains the round — which\n * tools were on offer, how long the context was, and the tail of the\n * conversation the model was actually answering, each message clipped.\n * @param request - The request about to be dispatched.\n * @returns The summary for the span.\n */\nfunction requestSummary(request: GenerateOptions): Record<string, unknown> {\n const messages = request.messages ?? []\n const dropped = Math.max(0, messages.length - PREVIEW_MESSAGES)\n return {\n messageCount: messages.length,\n // The identity of the request, for a host that records the provider call\n // separately and has to say WHICH round each recording belongs to. Message\n // ids are stable across every representation boundary, so the last one plus\n // the count names one round of one agent without ambiguity.\n ...messages.at(-1) === undefined ? {} : { lastMessageId: messages.at(-1)?.id },\n ...request.system === undefined ? {} : { system: clip(request.system) },\n ...request.tools === undefined || request.tools.length === 0\n ? {}\n : { tools: request.tools.map(tool => tool.name) },\n ...request.toolChoice === undefined ? {} : { toolChoice: request.toolChoice },\n ...dropped === 0 ? {} : { earlierMessagesOmitted: dropped },\n messages: messages.slice(-PREVIEW_MESSAGES).map(previewMessage),\n }\n}\n\nexport async function modelRound(\n options: RunTurnOptions,\n signal: AbortSignal,\n emit: (event: AgentEvent) => Promise<void>,\n emitMaintenance: (event: AgentMaintenanceEvent) => Promise<void>,\n root: TraceRef,\n turn: number,\n step: number,\n phase: ModelRoundPhase,\n): Promise<RoundResult> {\n const forcedFinal = phase === 'forced-final'\n const finalOutput = phase === 'final' || forcedFinal\n const trace: TraceRef = { traceId: root.traceId, spanId: createSpanId(), parentSpanId: root.spanId }\n let messages = normalizeToolPairing(options.history.messages())\n const initialMessages = messages\n const afterToolCallIds = recentToolResultIds(options.history)\n const generation = options.history.generation()\n const entries = options.history.entries().length\n const stopped = (): RoundResult | undefined => {\n const stop = accountingUsageStop(options.accounting)\n if (stop === undefined && !signal.aborted) return undefined\n return {\n trace, finish: signal.aborted\n ? { kind: 'aborted', failure: { code: 'ABORTED', message: messageOf(signal.reason) } }\n : { kind: 'stop' },\n calls: [], afterToolCallIds, timing: contentTiming(false, afterToolCallIds.length > 0),\n ...(stop?.kind === 'error' ? { usageRequired: true } : {}),\n ...(stop?.kind === 'usage-unavailable' ? { usageUnavailable: true } : {}),\n }\n }\n const beforeMaintenance = stopped()\n if (beforeMaintenance !== undefined) return beforeMaintenance\n const decision = await runOptionalHook(options.hooks?.beforeStep, [{\n turn, step, messages, snapshot: options.history.snapshot(), signal,\n ...(options.logger === undefined ? {} : { logger: options.logger }),\n emit: emitMaintenance,\n }], options, signal, 'beforeStep')\n const afterMaintenance = stopped()\n if (afterMaintenance !== undefined) return afterMaintenance\n if (decision?.kind === 'reject') {\n const failure: ModelFailure = { message: decision.reason, code: 'STEP_REJECTED' }\n return {\n trace, finish: { kind: 'error', failure }, calls: [], afterToolCallIds,\n timing: contentTiming(false, afterToolCallIds.length > 0),\n }\n }\n // Hooks may append live steering as well as replacing compacted history.\n // Refresh for either mutation so new user input stays at the chronological\n // tail instead of needing to be prepended ahead of older history.\n if (options.history.generation() !== generation\n || options.history.entries().length !== entries) {\n messages = normalizeToolPairing(options.history.messages())\n }\n if (decision?.messages !== undefined) {\n const originalIds = stepProjectionSources(decision) ?? new Set(initialMessages.map(message => message.id))\n const projectedIds = new Set(decision.messages.map(message => message.id))\n const introduced = messages.filter(message => !originalIds.has(message.id) && !projectedIds.has(message.id))\n const currentIds = new Set(messages.map(message => message.id))\n const replaced = [...originalIds].some(id => !currentIds.has(id))\n // A hook can await external I/O while live steering or replacement arrives.\n // Replacements invalidate a stale projection; append-only steering stays at the tail.\n const projectedById = new Map(decision.messages.map(message => [message.id, message]))\n messages = normalizeToolPairing(replaced\n ? [...decision.messages.filter(message => !originalIds.has(message.id) && !currentIds.has(message.id) && message.source.kind === 'app'),\n ...messages.flatMap(message => {\n const projected = projectedById.get(message.id)\n return projected === undefined ? originalIds.has(message.id) ? [] : [message] : [projected]\n })]\n : [...decision.messages, ...introduced])\n }\n if (decision?.prepend !== undefined) messages = Object.freeze([...decision.prepend, ...messages])\n const system = systemText(options, forcedFinal)\n const availableTools = [\n ...options.tools?.schemas() ?? [],\n ...options.nativeTools ?? [],\n ]\n const tools = availableTools\n const outputFormat = !finalOutput && options.outputFormat?.type === 'json_schema'\n ? { type: 'text' as const }\n : options.outputFormat\n const requestBase: GenerateOptions = {\n ...options.config,\n messages,\n ...system.length === 0 ? {} : { system },\n ...tools.length === 0 ? {} : { tools },\n ...finalOutput && tools.length > 0\n ? { toolChoice: 'none' as const }\n : options.toolChoice === undefined ? {} : { toolChoice: options.toolChoice },\n ...options.imagePolicy === undefined ? {} : { imagePolicy: options.imagePolicy },\n ...options.documentPolicy === undefined ? {} : { documentPolicy: options.documentPolicy },\n ...outputFormat === undefined ? {} : { outputFormat },\n }\n const checkpointRequest: GenerateOptions = { ...requestBase, signal }\n observeModelRequestBoundary(options.history, true)\n try {\n await runOptionalHook(options.hooks?.checkpoint, [{\n kind: 'before-model-request', request: checkpointRequest,\n snapshot: options.history.snapshot(), signal,\n ...(options.logger === undefined ? {} : { logger: options.logger }),\n }], options, signal, 'checkpoint')\n } catch (error: unknown) {\n // No output will be recorded for this request. Release queued input before\n // recovery hooks or the retry's beforeStep can read or inject into history.\n observeModelRequestBoundary(options.history, false)\n const failure: ModelFailure = { message: `history checkpoint failed: ${messageOf(error)}`, code: 'CHECKPOINT_FAILED' }\n return {\n trace, finish: { kind: 'error', failure }, calls: [], afterToolCallIds,\n timing: contentTiming(false, afterToolCallIds.length > 0),\n }\n }\n const beforeDispatch = stopped()\n if (beforeDispatch !== undefined) {\n observeModelRequestBoundary(options.history, false)\n return beforeDispatch\n }\n await emit({ type: 'span-start', trace, at: now(), name: `chat ${options.config.model}`, kind: 'chat', attributes: {\n 'gen_ai.operation.name': 'chat', 'gen_ai.request.model': options.config.model,\n // The effort is part of WHICH call this was: the same model at minimal and\n // at high is two different requests, priced and paced differently, and a\n // trace that omits it cannot explain either. Absent when the route has no\n // effort ladder, rather than reported as a default nobody chose.\n ...options.config.reasoningEffort === undefined\n ? {}\n : { 'gen_ai.request.reasoning_effort': options.config.reasoningEffort },\n turn, step, forcedFinal, phase,\n }, input: requestSummary(requestBase) })\n await emit({ type: 'step-start', turn, step, trace, ...forcedFinal ? { forcedFinal: true as const } : {} })\n const assembler = new BlockAssembler()\n const closedBlockIndexes = new Set<number>()\n const modelTimeoutMs = positiveFinite(options.modelTimeoutMs ?? 10 * 60_000, 'modelTimeoutMs')\n const maxRequestBytes = positiveSafeInteger(options.maxModelRequestBytes ?? 32 * 1024 * 1024, 'maxModelRequestBytes')\n const maxResponseBytes = positiveSafeInteger(options.maxModelResponseBytes ?? 32 * 1024 * 1024, 'maxModelResponseBytes')\n const maxStreamEvents = positiveSafeInteger(options.maxModelStreamEvents ?? 100_000, 'maxModelStreamEvents')\n const teardownTimeoutMs = positiveFinite(options.teardownTimeoutMs ?? 30_000, 'teardownTimeoutMs')\n let modelCallReport: ModelCallReport | undefined\n let usageRequired = false\n let usageUnavailable = false\n let requestBytes: number\n try {\n requestBytes = serializedBytes(requestBase)\n } catch (error: unknown) {\n requestBytes = -1\n assembler.push(modelFailureFinish(`model request is not serializable: ${messageOf(error)}`, 'INVALID_MODEL_REQUEST'))\n }\n if (requestBytes > maxRequestBytes) {\n assembler.push(modelFailureFinish(\n `model request exceeds the ${maxRequestBytes}-byte limit`,\n 'MODEL_REQUEST_TOO_LARGE',\n ))\n } else if (requestBytes >= 0) {\n const owned = new AbortController()\n const roundSignal = AbortSignal.any([signal, owned.signal])\n let timedOut = false\n const timeout = setTimeout(() => {\n timedOut = true\n owned.abort(new Error(`model stream exceeded ${modelTimeoutMs}ms`))\n }, modelTimeoutMs)\n const handle = options.registry.stream(\n { ...requestBase, signal: roundSignal },\n options.accounting?.modelInvocation,\n )\n const iterator = handle[Symbol.asyncIterator]()\n let exhausted = false\n let events = 0\n let responseBytes = 0\n let sawFinish = false\n try {\n while (true) {\n const next = await nextWithAbort(iterator.next(), roundSignal)\n if (next.done === true) {\n exhausted = true\n break\n }\n const chunk = next.value\n try {\n validateStreamChunk(chunk, maxStreamEvents)\n } catch (error: unknown) {\n assembler.push(modelFailureFinish(\n `model adapter emitted an invalid stream chunk: ${messageOf(error)}`,\n 'INVALID_MODEL_STREAM',\n ))\n owned.abort(new Error('invalid model stream chunk'))\n break\n }\n events++\n try {\n responseBytes += serializedBytes(chunk)\n } catch (error: unknown) {\n assembler.push(modelFailureFinish(\n `model adapter emitted a non-serializable stream chunk: ${messageOf(error)}`,\n 'INVALID_MODEL_STREAM',\n ))\n owned.abort(new Error('non-serializable model stream chunk'))\n break\n }\n if (events > maxStreamEvents || responseBytes > maxResponseBytes) {\n const dimension = events > maxStreamEvents\n ? `${maxStreamEvents}-event`\n : `${maxResponseBytes}-byte`\n assembler.push(modelFailureFinish(\n `model response exceeds the ${dimension} limit`,\n 'MODEL_RESPONSE_TOO_LARGE',\n ))\n owned.abort(new Error('model response resource limit exceeded'))\n break\n }\n if (sawFinish) {\n assembler.push(modelFailureFinish(\n 'model adapter emitted data after its terminal finish chunk',\n 'INVALID_MODEL_STREAM',\n ))\n owned.abort(new Error('invalid model stream'))\n break\n }\n assembler.push(chunk)\n // The assembler ignores deltas after the first close. The visible\n // stream must do the same or UI text can disagree with stored history.\n if ((chunk.type === 'text-delta' || chunk.type === 'reasoning-delta' || chunk.type === 'tool-call-delta')\n && closedBlockIndexes.has(chunk.index)) continue\n if (chunk.type === 'block-end') closedBlockIndexes.add(chunk.index)\n if (chunk.type === 'finish') sawFinish = true\n if (chunk.type === 'text-delta') await emit({\n type: 'text-delta', index: chunk.index, text: chunk.text,\n phase: phase === 'process' ? 'commentary' : chunk.phase ?? 'unknown', trace,\n })\n else if (chunk.type === 'reasoning-delta') await emit({\n type: 'reasoning-delta', index: chunk.index, text: chunk.text, trace,\n })\n else if (chunk.type === 'image-delta') await emit({\n type: 'image-delta', itemId: chunk.itemId, data: chunk.data,\n mediaType: chunk.mediaType, ...chunk.partialIndex === undefined ? {} : { partialIndex: chunk.partialIndex }, trace,\n })\n else if (chunk.type === 'usage') await emit({ type: 'usage', usage: chunk.usage, trace })\n else if (chunk.type === 'usage-progress') await emit({ ...chunk, trace })\n }\n } catch (error: unknown) {\n if (!(error instanceof StreamAbortError)) throw error\n assembler.push(signal.aborted\n ? modelAbortedFinish(messageOf(signal.reason ?? error))\n : timedOut\n ? modelFailureFinish(`model stream exceeded ${modelTimeoutMs}ms`, 'MODEL_TIMEOUT')\n : modelFailureFinish(messageOf(error.cause ?? error), 'MODEL_STREAM_ABORTED'))\n } finally {\n clearTimeout(timeout)\n if (!exhausted) {\n owned.abort(new Error('model stream closed before exhaustion'))\n const settled = await closeIterator(iterator, teardownTimeoutMs)\n if (!settled) {\n assembler.push(modelFailureFinish(\n `model stream ignored cancellation for more than ${teardownTimeoutMs}ms; the adapter operation may still be running`,\n 'MODEL_TEARDOWN_TIMEOUT',\n ))\n }\n }\n }\n const report = await handle.report\n const decision = options.accounting === undefined\n ? undefined\n : await options.accounting.recordModelCall(report, { ...requestBase, signal })\n modelCallReport = decision?.report ?? report\n usageRequired = decision?.usageRequired ?? false\n usageUnavailable = decision?.usageUnavailable ?? false\n }\n let providerFinish = assembler.finish\n let retainedPrefix = providerFinish.kind === 'aborted'\n let rawBlocks: ContentBlock[]\n try {\n rawBlocks = providerFinish.kind === 'aborted' ? assembler.interruptedBlocks() : assembler.blocks()\n } catch (error: unknown) {\n providerFinish = {\n kind: 'error',\n failure: {\n message: `model adapter emitted an invalid block sequence: ${messageOf(error)}`,\n code: 'INVALID_MODEL_STREAM',\n },\n }\n // A broken extension must not discard text already delivered to the user.\n // This prefix deliberately excludes tools and unassembled extension data.\n retainedPrefix = true\n rawBlocks = assembler.interruptedBlocks()\n }\n // Interrupted/truncated assembly drops unfinished calls, but the text that\n // introduced those calls is still process narration, not a final answer.\n const canonicalTexts = assembler.textBlocks()\n .filter(({ block }) => !retainedPrefix || block.text.trim() !== '')\n let textPosition = 0\n const classifiedRaw = classifyTextPhases(rawBlocks.map(block => {\n if (block.type !== 'text') return block\n const canonical = canonicalTexts[textPosition++]\n // Safe-prefix recovery removes native calls too. Retain their position so\n // search narration cannot become an answer merely because a call was removed.\n return block.phase === undefined && canonical?.beforeNativeCall\n ? { ...block, phase: 'commentary' as const } : block\n }), phase === 'process', assembler.hasToolCalls)\n // A repeated id costs the model that one call, not its whole turn.\n const deduped = dropDuplicateToolCalls(classifiedRaw, options.history)\n const classified = deduped.blocks\n const structuredOutputFailure = finalOutput\n && options.outputFormat?.type === 'json_schema'\n && providerFinish.kind === 'stop'\n && !isJsonText(textOf(classified), options.validateOutput)\n ? {\n message: 'model returned invalid JSON or failed the structured output validator',\n code: MODEL_ERROR_CODES.MALFORMED_RESPONSE,\n }\n : undefined\n const disabledCall = finalOutput && classified.some(block => block.type === 'tool-call')\n ? { message: 'model emitted a host tool call during the final output phase', code: 'INVALID_TOOL_CALL' }\n : undefined\n const invalidCall = disabledCall\n ?? structuredOutputFailure\n ?? invalidHostToolCall(classified, options.history)\n const blocks = invalidCall === undefined\n ? classified\n : classified.filter(block => block.type !== 'tool-call')\n const finish: FinishReason = invalidCall === undefined\n ? providerFinish\n : { kind: 'error', failure: invalidCall }\n const message = blocks.length === 0 && (finish.kind === 'error' || finish.kind === 'aborted')\n ? undefined\n : createAssistant(options, blocks, retainedPrefix ? undefined : assembler.replayState)\n const calls = message?.content\n .filter((block): block is ToolCallBlock => block.type === 'tool-call')\n .map(block => ({ callId: block.id, toolName: block.name, rawArguments: block.arguments })) ?? []\n const timing = contentTiming(calls.length > 0, afterToolCallIds.length > 0)\n // Deltas may have no phase, or block-end may correct it. Publish the\n // canonical snapshot before consumers close this step, including providers\n // that only emit block-end. Keep provider indexes (which may be sparse).\n if (blocks.some(block => block.type === 'text')) {\n const indexes = canonicalTexts.map(({ index }) => index)\n const incomplete = finish.kind === 'error' || finish.kind === 'aborted' || finish.kind === 'max-tokens'\n let position = 0\n for (const block of blocks) {\n if (block.type !== 'text') continue\n const index = indexes[position++]\n if (index !== undefined) await emit({\n type: 'text-end', index, text: block.text,\n phase: block.phase ?? 'final-answer', trace,\n ...incomplete ? { incomplete: true as const } : {},\n })\n }\n }\n await emit({\n type: 'span-end', trace, at: now(),\n status: finish.kind === 'error' ? 'error' : finish.kind === 'aborted' ? 'aborted' : 'success',\n output: message === undefined ? undefined : {\n text: textOf(message.content),\n commentary: message.content.flatMap(block => block.type === 'text' && block.phase === 'commentary' ? [block.text] : []),\n reasoning: message.content.flatMap(block => block.type === 'reasoning' ? [block.text] : []),\n toolCalls: calls.length,\n },\n ...assembler.usage === undefined ? {} : { usage: assembler.usage },\n ...finish.kind === 'error' || finish.kind === 'aborted'\n ? { error: { type: 'ModelError', message: finish.failure.message, code: finish.failure.code } }\n : {},\n })\n if (calls.length === 0 || finalOutput) await emit({ type: 'step-end', turn, step, trace })\n return {\n trace, ...message === undefined ? {} : { message }, finish,\n ...assembler.usage === undefined ? {} : { usage: assembler.usage },\n ...modelCallReport === undefined ? {} : { report: modelCallReport },\n ...usageRequired ? { usageRequired: true as const } : {},\n ...usageUnavailable ? { usageUnavailable: true as const } : {},\n calls, afterToolCallIds, timing,\n ...deduped.dropped.length === 0 ? {} : { droppedDuplicateCalls: deduped.dropped },\n }\n}\n\nfunction isJsonText(value: string, validate?: (value: unknown) => void): boolean {\n try {\n const parsed: unknown = JSON.parse(value)\n validate?.(parsed)\n return true\n } catch {\n return false\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"model-round.js","names":[],"sources":["../../../../src/agent/loop/turn/model-round.ts"],"sourcesContent":["import type { GenerateOptions } from '../../../contract/index.ts'\nimport { UNCHANGED_ANSWER_MARKER } from '../control-text.ts'\nimport { MODEL_ERROR_CODES, type ModelFailure } from '../../../errors/index.ts'\nimport type { ContentBlock, Message, ToolCallBlock } from '../../../message/index.ts'\nimport { BlockAssembler } from '../../../stream/index.ts'\nimport type { FinishReason } from '../../../stream/index.ts'\nimport type { ModelCallReport } from '../../../observation/index.ts'\nimport { normalizeToolPairing } from '../../history/normalize.ts'\nimport { createSpanId, type TraceRef } from '../../trace/trace.ts'\nimport type { AgentEvent, AgentMaintenanceEvent } from '../types.ts'\nimport { type ModelRoundPhase, type RunTurnOptions, type RoundResult } from './types.ts'\nimport { positiveFinite, positiveSafeInteger } from './config.ts'\nimport { serializedBytes, modelFailureFinish, modelAbortedFinish, messageOf, now } from './common.ts'\nimport { validateStreamChunk } from './validation.ts'\nimport { StreamAbortError, nextWithAbort, closeIterator } from './cancellation.ts'\nimport { runOptionalHook } from './hooks.ts'\nimport { stepProjectionSources } from './step-projection.ts'\nimport { observeModelRequestBoundary } from './model-request-boundary.ts'\nimport { accountingUsageStop } from './usage-stop.ts'\nimport {\n classifyTextPhases, dropDuplicateToolCalls, invalidHostToolCall, contentTiming,\n recentToolResultIds, systemText,\n createAssistant, textOf,\n} from './content.ts'\n\n/** How much of one message the trace keeps. */\nconst PREVIEW_CHARS = 600\n\n/** How many trailing messages the trace keeps. */\nconst PREVIEW_MESSAGES = 8\n\nfunction clip(text: string): string {\n const flattened = text.replace(/\\s+/gu, ' ').trim()\n return flattened.length > PREVIEW_CHARS ? `${flattened.slice(0, PREVIEW_CHARS)}…` : flattened\n}\n\n/** One message as a line: who spoke, and what the model could read of it. */\nfunction previewMessage(message: Message): Record<string, unknown> {\n const parts: string[] = []\n const calls: string[] = []\n for (const block of message.content) {\n if (block.type === 'text' || block.type === 'reasoning') parts.push(block.text)\n else if (block.type === 'tool-call') calls.push(`${block.name}(${clip(block.arguments)})`)\n else if (block.type === 'tool-result') parts.push(textOf(block.content))\n else parts.push(`[${block.type}]`)\n }\n return {\n role: message.role,\n producer: message.source.kind,\n ...parts.length === 0 ? {} : { text: clip(parts.join(' ')) },\n ...calls.length === 0 ? {} : { toolCalls: calls },\n }\n}\n\n/**\n * What this round sent the model, in a form a person can read.\n *\n * A summary, not a copy: the request can be the whole conversation plus every\n * tool schema, and a trace that stored it verbatim would be larger than the\n * work it describes. What survives is the part that explains the round — which\n * tools were on offer, how long the context was, and the tail of the\n * conversation the model was actually answering, each message clipped.\n * @param request - The request about to be dispatched.\n * @returns The summary for the span.\n */\nfunction requestSummary(request: GenerateOptions): Record<string, unknown> {\n const messages = request.messages ?? []\n const dropped = Math.max(0, messages.length - PREVIEW_MESSAGES)\n return {\n messageCount: messages.length,\n // The identity of the request, for a host that records the provider call\n // separately and has to say WHICH round each recording belongs to. Message\n // ids are stable across every representation boundary, so the last one plus\n // the count names one round of one agent without ambiguity.\n ...messages.at(-1) === undefined ? {} : { lastMessageId: messages.at(-1)?.id },\n ...request.system === undefined ? {} : { system: clip(request.system) },\n ...request.tools === undefined || request.tools.length === 0\n ? {}\n : { tools: request.tools.map(tool => tool.name) },\n ...request.toolChoice === undefined ? {} : { toolChoice: request.toolChoice },\n ...dropped === 0 ? {} : { earlierMessagesOmitted: dropped },\n messages: messages.slice(-PREVIEW_MESSAGES).map(previewMessage),\n }\n}\n\nexport async function modelRound(\n options: RunTurnOptions,\n signal: AbortSignal,\n emit: (event: AgentEvent) => Promise<void>,\n emitMaintenance: (event: AgentMaintenanceEvent) => Promise<void>,\n root: TraceRef,\n turn: number,\n step: number,\n phase: ModelRoundPhase,\n): Promise<RoundResult> {\n const forcedFinal = phase === 'forced-final'\n const finalOutput = phase === 'final' || forcedFinal\n const trace: TraceRef = { traceId: root.traceId, spanId: createSpanId(), parentSpanId: root.spanId }\n let messages = normalizeToolPairing(options.history.messages())\n const initialMessages = messages\n const afterToolCallIds = recentToolResultIds(options.history)\n const generation = options.history.generation()\n const entries = options.history.entries().length\n const stopped = (): RoundResult | undefined => {\n const stop = accountingUsageStop(options.accounting)\n if (stop === undefined && !signal.aborted) return undefined\n return {\n trace, finish: signal.aborted\n ? { kind: 'aborted', failure: { code: 'ABORTED', message: messageOf(signal.reason) } }\n : { kind: 'stop' },\n calls: [], afterToolCallIds, timing: contentTiming(false, afterToolCallIds.length > 0),\n ...(stop?.kind === 'error' ? { usageRequired: true } : {}),\n ...(stop?.kind === 'usage-unavailable' ? { usageUnavailable: true } : {}),\n }\n }\n const beforeMaintenance = stopped()\n if (beforeMaintenance !== undefined) return beforeMaintenance\n const decision = await runOptionalHook(options.hooks?.beforeStep, [{\n turn, step, messages, snapshot: options.history.snapshot(), signal,\n ...(options.logger === undefined ? {} : { logger: options.logger }),\n emit: emitMaintenance,\n }], options, signal, 'beforeStep')\n const afterMaintenance = stopped()\n if (afterMaintenance !== undefined) return afterMaintenance\n if (decision?.kind === 'reject') {\n const failure: ModelFailure = { message: decision.reason, code: 'STEP_REJECTED' }\n return {\n trace, finish: { kind: 'error', failure }, calls: [], afterToolCallIds,\n timing: contentTiming(false, afterToolCallIds.length > 0),\n }\n }\n // Hooks may append live steering as well as replacing compacted history.\n // Refresh for either mutation so new user input stays at the chronological\n // tail instead of needing to be prepended ahead of older history.\n if (options.history.generation() !== generation\n || options.history.entries().length !== entries) {\n messages = normalizeToolPairing(options.history.messages())\n }\n if (decision?.messages !== undefined) {\n const originalIds = stepProjectionSources(decision) ?? new Set(initialMessages.map(message => message.id))\n const projectedIds = new Set(decision.messages.map(message => message.id))\n const introduced = messages.filter(message => !originalIds.has(message.id) && !projectedIds.has(message.id))\n const currentIds = new Set(messages.map(message => message.id))\n const replaced = [...originalIds].some(id => !currentIds.has(id))\n // A hook can await external I/O while live steering or replacement arrives.\n // Replacements invalidate a stale projection; append-only steering stays at the tail.\n const projectedById = new Map(decision.messages.map(message => [message.id, message]))\n messages = normalizeToolPairing(replaced\n ? [...decision.messages.filter(message => !originalIds.has(message.id) && !currentIds.has(message.id) && message.source.kind === 'app'),\n ...messages.flatMap(message => {\n const projected = projectedById.get(message.id)\n return projected === undefined ? originalIds.has(message.id) ? [] : [message] : [projected]\n })]\n : [...decision.messages, ...introduced])\n }\n if (decision?.prepend !== undefined) messages = Object.freeze([...decision.prepend, ...messages])\n const system = systemText(options, forcedFinal)\n const availableTools = [\n ...options.tools?.schemas() ?? [],\n ...options.nativeTools ?? [],\n ]\n const tools = availableTools\n const outputFormat = !finalOutput && options.outputFormat?.type === 'json_schema'\n ? { type: 'text' as const }\n : options.outputFormat\n const requestBase: GenerateOptions = {\n ...options.config,\n messages,\n ...system.length === 0 ? {} : { system },\n ...tools.length === 0 ? {} : { tools },\n ...finalOutput && tools.length > 0\n ? { toolChoice: 'none' as const }\n : options.toolChoice === undefined ? {} : { toolChoice: options.toolChoice },\n ...options.imagePolicy === undefined ? {} : { imagePolicy: options.imagePolicy },\n ...options.documentPolicy === undefined ? {} : { documentPolicy: options.documentPolicy },\n ...outputFormat === undefined ? {} : { outputFormat },\n }\n const checkpointRequest: GenerateOptions = { ...requestBase, signal }\n observeModelRequestBoundary(options.history, true)\n try {\n await runOptionalHook(options.hooks?.checkpoint, [{\n kind: 'before-model-request', request: checkpointRequest,\n snapshot: options.history.snapshot(), signal,\n ...(options.logger === undefined ? {} : { logger: options.logger }),\n }], options, signal, 'checkpoint')\n } catch (error: unknown) {\n // No output will be recorded for this request. Release queued input before\n // recovery hooks or the retry's beforeStep can read or inject into history.\n observeModelRequestBoundary(options.history, false)\n const failure: ModelFailure = { message: `history checkpoint failed: ${messageOf(error)}`, code: 'CHECKPOINT_FAILED' }\n return {\n trace, finish: { kind: 'error', failure }, calls: [], afterToolCallIds,\n timing: contentTiming(false, afterToolCallIds.length > 0),\n }\n }\n const beforeDispatch = stopped()\n if (beforeDispatch !== undefined) {\n observeModelRequestBoundary(options.history, false)\n return beforeDispatch\n }\n await emit({ type: 'span-start', trace, at: now(), name: `chat ${options.config.model}`, kind: 'chat', attributes: {\n 'gen_ai.operation.name': 'chat', 'gen_ai.request.model': options.config.model,\n // The effort is part of WHICH call this was: the same model at minimal and\n // at high is two different requests, priced and paced differently, and a\n // trace that omits it cannot explain either. Absent when the route has no\n // effort ladder, rather than reported as a default nobody chose.\n ...options.config.reasoningEffort === undefined\n ? {}\n : { 'gen_ai.request.reasoning_effort': options.config.reasoningEffort },\n turn, step, forcedFinal, phase,\n }, input: requestSummary(requestBase) })\n await emit({ type: 'step-start', turn, step, trace, ...forcedFinal ? { forcedFinal: true as const } : {} })\n const assembler = new BlockAssembler()\n const closedBlockIndexes = new Set<number>()\n const modelTimeoutMs = positiveFinite(options.modelTimeoutMs ?? 10 * 60_000, 'modelTimeoutMs')\n const maxRequestBytes = positiveSafeInteger(options.maxModelRequestBytes ?? 32 * 1024 * 1024, 'maxModelRequestBytes')\n const maxResponseBytes = positiveSafeInteger(options.maxModelResponseBytes ?? 32 * 1024 * 1024, 'maxModelResponseBytes')\n const maxStreamEvents = positiveSafeInteger(options.maxModelStreamEvents ?? 100_000, 'maxModelStreamEvents')\n const teardownTimeoutMs = positiveFinite(options.teardownTimeoutMs ?? 30_000, 'teardownTimeoutMs')\n let modelCallReport: ModelCallReport | undefined\n let usageRequired = false\n let usageUnavailable = false\n let requestBytes: number\n try {\n requestBytes = serializedBytes(requestBase)\n } catch (error: unknown) {\n requestBytes = -1\n assembler.push(modelFailureFinish(`model request is not serializable: ${messageOf(error)}`, 'INVALID_MODEL_REQUEST'))\n }\n if (requestBytes > maxRequestBytes) {\n assembler.push(modelFailureFinish(\n `model request exceeds the ${maxRequestBytes}-byte limit`,\n 'MODEL_REQUEST_TOO_LARGE',\n ))\n } else if (requestBytes >= 0) {\n const owned = new AbortController()\n const roundSignal = AbortSignal.any([signal, owned.signal])\n let timedOut = false\n const timeout = setTimeout(() => {\n timedOut = true\n owned.abort(new Error(`model stream exceeded ${modelTimeoutMs}ms`))\n }, modelTimeoutMs)\n const handle = options.registry.stream(\n { ...requestBase, signal: roundSignal },\n options.accounting?.modelInvocation,\n )\n const iterator = handle[Symbol.asyncIterator]()\n let exhausted = false\n let events = 0\n let responseBytes = 0\n let sawFinish = false\n try {\n while (true) {\n const next = await nextWithAbort(iterator.next(), roundSignal)\n if (next.done === true) {\n exhausted = true\n break\n }\n const chunk = next.value\n try {\n validateStreamChunk(chunk, maxStreamEvents)\n } catch (error: unknown) {\n assembler.push(modelFailureFinish(\n `model adapter emitted an invalid stream chunk: ${messageOf(error)}`,\n 'INVALID_MODEL_STREAM',\n ))\n owned.abort(new Error('invalid model stream chunk'))\n break\n }\n events++\n try {\n responseBytes += serializedBytes(chunk)\n } catch (error: unknown) {\n assembler.push(modelFailureFinish(\n `model adapter emitted a non-serializable stream chunk: ${messageOf(error)}`,\n 'INVALID_MODEL_STREAM',\n ))\n owned.abort(new Error('non-serializable model stream chunk'))\n break\n }\n if (events > maxStreamEvents || responseBytes > maxResponseBytes) {\n const dimension = events > maxStreamEvents\n ? `${maxStreamEvents}-event`\n : `${maxResponseBytes}-byte`\n assembler.push(modelFailureFinish(\n `model response exceeds the ${dimension} limit`,\n 'MODEL_RESPONSE_TOO_LARGE',\n ))\n owned.abort(new Error('model response resource limit exceeded'))\n break\n }\n if (sawFinish) {\n assembler.push(modelFailureFinish(\n 'model adapter emitted data after its terminal finish chunk',\n 'INVALID_MODEL_STREAM',\n ))\n owned.abort(new Error('invalid model stream'))\n break\n }\n assembler.push(chunk)\n // The assembler ignores deltas after the first close. The visible\n // stream must do the same or UI text can disagree with stored history.\n if ((chunk.type === 'text-delta' || chunk.type === 'reasoning-delta' || chunk.type === 'tool-call-delta')\n && closedBlockIndexes.has(chunk.index)) continue\n if (chunk.type === 'block-end') closedBlockIndexes.add(chunk.index)\n if (chunk.type === 'finish') sawFinish = true\n if (chunk.type === 'text-delta') await emit({\n type: 'text-delta', index: chunk.index, text: chunk.text,\n phase: phase === 'process' ? 'commentary' : chunk.phase ?? 'unknown', trace,\n })\n else if (chunk.type === 'reasoning-delta') await emit({\n type: 'reasoning-delta', index: chunk.index, text: chunk.text, trace,\n })\n else if (chunk.type === 'image-delta') await emit({\n type: 'image-delta', itemId: chunk.itemId, data: chunk.data,\n mediaType: chunk.mediaType, ...chunk.partialIndex === undefined ? {} : { partialIndex: chunk.partialIndex }, trace,\n })\n else if (chunk.type === 'usage') await emit({ type: 'usage', usage: chunk.usage, trace })\n else if (chunk.type === 'usage-progress') await emit({ ...chunk, trace })\n }\n } catch (error: unknown) {\n if (!(error instanceof StreamAbortError)) throw error\n assembler.push(signal.aborted\n ? modelAbortedFinish(messageOf(signal.reason ?? error))\n : timedOut\n ? modelFailureFinish(`model stream exceeded ${modelTimeoutMs}ms`, 'MODEL_TIMEOUT')\n : modelFailureFinish(messageOf(error.cause ?? error), 'MODEL_STREAM_ABORTED'))\n } finally {\n clearTimeout(timeout)\n if (!exhausted) {\n owned.abort(new Error('model stream closed before exhaustion'))\n const settled = await closeIterator(iterator, teardownTimeoutMs)\n if (!settled) {\n assembler.push(modelFailureFinish(\n `model stream ignored cancellation for more than ${teardownTimeoutMs}ms; the adapter operation may still be running`,\n 'MODEL_TEARDOWN_TIMEOUT',\n ))\n }\n }\n }\n const report = await handle.report\n const decision = options.accounting === undefined\n ? undefined\n : await options.accounting.recordModelCall(report, { ...requestBase, signal })\n modelCallReport = decision?.report ?? report\n usageRequired = decision?.usageRequired ?? false\n usageUnavailable = decision?.usageUnavailable ?? false\n }\n let providerFinish = assembler.finish\n let retainedPrefix = providerFinish.kind === 'aborted'\n let rawBlocks: ContentBlock[]\n try {\n rawBlocks = providerFinish.kind === 'aborted' ? assembler.interruptedBlocks() : assembler.blocks()\n } catch (error: unknown) {\n providerFinish = {\n kind: 'error',\n failure: {\n message: `model adapter emitted an invalid block sequence: ${messageOf(error)}`,\n code: 'INVALID_MODEL_STREAM',\n },\n }\n // A broken extension must not discard text already delivered to the user.\n // This prefix deliberately excludes tools and unassembled extension data.\n retainedPrefix = true\n rawBlocks = assembler.interruptedBlocks()\n }\n // Interrupted/truncated assembly drops unfinished calls, but the text that\n // introduced those calls is still process narration, not a final answer.\n const canonicalTexts = assembler.textBlocks()\n .filter(({ block }) => !retainedPrefix || block.text.trim() !== '')\n let textPosition = 0\n const classifiedRaw = classifyTextPhases(rawBlocks.map(block => {\n if (block.type !== 'text') return block\n const canonical = canonicalTexts[textPosition++]\n // Safe-prefix recovery removes native calls too. Retain their position so\n // search narration cannot become an answer merely because a call was removed.\n return block.phase === undefined && canonical?.beforeNativeCall\n ? { ...block, phase: 'commentary' as const } : block\n }), phase === 'process', assembler.hasToolCalls)\n // A repeated id costs the model that one call, not its whole turn.\n const deduped = dropDuplicateToolCalls(classifiedRaw, options.history)\n const classified = deduped.blocks\n const structuredOutputFailure = finalOutput\n && options.outputFormat?.type === 'json_schema'\n && providerFinish.kind === 'stop'\n && !isJsonText(textOf(classified), options.validateOutput)\n ? {\n message: 'model returned invalid JSON or failed the structured output validator',\n code: MODEL_ERROR_CODES.MALFORMED_RESPONSE,\n }\n : undefined\n const disabledCall = finalOutput && classified.some(block => block.type === 'tool-call')\n ? { message: 'model emitted a host tool call during the final output phase', code: 'INVALID_TOOL_CALL' }\n : undefined\n const invalidCall = disabledCall\n ?? structuredOutputFailure\n ?? invalidHostToolCall(classified, options.history)\n const rawContent = invalidCall === undefined\n ? classified\n : classified.filter(block => block.type !== 'tool-call')\n // A control reply cannot confirm an answer while dispatching more work.\n // Strip it before persistence so tool-call identities are recorded only once.\n const blocks = rawContent.some(block => block.type === 'tool-call')\n ? rawContent.map(block => block.type === 'text'\n ? { ...block, text: block.text.replaceAll(UNCHANGED_ANSWER_MARKER, '') } : block)\n : rawContent\n const finish: FinishReason = invalidCall === undefined\n ? providerFinish\n : { kind: 'error', failure: invalidCall }\n const message = blocks.length === 0\n ? undefined\n : createAssistant(options, blocks, retainedPrefix ? undefined : assembler.replayState)\n const calls = message?.content\n .filter((block): block is ToolCallBlock => block.type === 'tool-call')\n .map(block => ({ callId: block.id, toolName: block.name, rawArguments: block.arguments })) ?? []\n const timing = contentTiming(calls.length > 0, afterToolCallIds.length > 0)\n // Deltas may have no phase, or block-end may correct it. Publish the\n // canonical snapshot before consumers close this step, including providers\n // that only emit block-end. Keep provider indexes (which may be sparse).\n if (blocks.some(block => block.type === 'text')) {\n const indexes = canonicalTexts.map(({ index }) => index)\n const incomplete = finish.kind === 'error' || finish.kind === 'aborted' || finish.kind === 'max-tokens'\n let position = 0\n for (const block of blocks) {\n if (block.type !== 'text') continue\n const index = indexes[position++]\n if (index !== undefined) await emit({\n type: 'text-end', index, text: block.text,\n phase: block.phase ?? 'final-answer', trace,\n ...incomplete ? { incomplete: true as const } : {},\n })\n }\n }\n await emit({\n type: 'span-end', trace, at: now(),\n status: finish.kind === 'error' ? 'error' : finish.kind === 'aborted' ? 'aborted' : 'success',\n output: message === undefined ? undefined : {\n text: textOf(message.content),\n commentary: message.content.flatMap(block => block.type === 'text' && block.phase === 'commentary' ? [block.text] : []),\n reasoning: message.content.flatMap(block => block.type === 'reasoning' ? [block.text] : []),\n toolCalls: calls.length,\n },\n ...assembler.usage === undefined ? {} : { usage: assembler.usage },\n ...finish.kind === 'error' || finish.kind === 'aborted'\n ? { error: { type: 'ModelError', message: finish.failure.message, code: finish.failure.code } }\n : {},\n })\n if (calls.length === 0 || finalOutput) await emit({ type: 'step-end', turn, step, trace })\n return {\n trace, ...message === undefined ? {} : { message }, finish,\n ...assembler.usage === undefined ? {} : { usage: assembler.usage },\n ...modelCallReport === undefined ? {} : { report: modelCallReport },\n ...usageRequired ? { usageRequired: true as const } : {},\n ...usageUnavailable ? { usageUnavailable: true as const } : {},\n calls, afterToolCallIds, timing,\n ...deduped.dropped.length === 0 ? {} : { droppedDuplicateCalls: deduped.dropped },\n }\n}\n\nfunction isJsonText(value: string, validate?: (value: unknown) => void): boolean {\n try {\n const parsed: unknown = JSON.parse(value)\n validate?.(parsed)\n return true\n } catch {\n return false\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,28 +1,16 @@
|
|
|
1
|
+
import { Message } from "../../message/message.js";
|
|
1
2
|
import { CallConfig } from "../../contract/call-config.js";
|
|
2
3
|
import { ToolCatalog } from "../tool/registry.js";
|
|
3
4
|
import { AgentEvent, TurnHooks, TurnOutcome } from "../loop/events.js";
|
|
4
5
|
import { TurnBounds } from "../loop/types.js";
|
|
5
6
|
import { RunTurnOptions } from "../loop/turn/types.js";
|
|
7
|
+
import { UNCHANGED_ANSWER_MARKER } from "../loop/control-text.js";
|
|
6
8
|
import { UserInputBroker, UserInputRequest, UserInputResponse } from "./user-input.js";
|
|
7
9
|
//#region src/agent/mode/run-agent.d.ts
|
|
8
10
|
declare const AGENT_CONTROL_TOOLS: Readonly<{
|
|
9
11
|
readonly complete: 'submit_result';
|
|
10
12
|
readonly requestUserInput: 'request_user_input';
|
|
11
13
|
}>;
|
|
12
|
-
/**
|
|
13
|
-
* What the model replies with, after an accepted self-check, when the answer
|
|
14
|
-
* it already gave the user earlier in the run still stands.
|
|
15
|
-
*
|
|
16
|
-
* Deep modes gate on an accepted `submit_result`, so a model that answered
|
|
17
|
-
* before checking is asked to check, then told to "deliver the answer"
|
|
18
|
-
* again — even when the check found nothing to add. Without this marker that
|
|
19
|
-
* second pass either pads an already-adequate answer or, worse, quietly
|
|
20
|
-
* changes it while claiming to only be confirming it. `driveAgent` treats a
|
|
21
|
-
* reply that is exactly this marker as "no change": the run's `text` (and,
|
|
22
|
-
* where the earlier answer is still the history's current surface, the
|
|
23
|
-
* transcript) keep the answer already given instead of this marker.
|
|
24
|
-
*/
|
|
25
|
-
declare const UNCHANGED_ANSWER_MARKER = "<<deep-mode:answer-unchanged>>";
|
|
26
14
|
/** Default high-level runtime requested by this SDK; `runTurn` remains provider-neutral. */
|
|
27
15
|
type AgentMode = 'basic' | 'deep' | 'deep-human-in-loop';
|
|
28
16
|
interface AgentRunCommon extends Omit<RunTurnOptions, 'bounds' | 'commentary' | 'config' | 'hooks' | 'system' | 'tools'> {
|
|
@@ -79,7 +67,12 @@ interface AgentModeEndEvent {
|
|
|
79
67
|
readonly type: 'agent-end';
|
|
80
68
|
readonly outcome: AgentRunOutcome;
|
|
81
69
|
}
|
|
82
|
-
|
|
70
|
+
interface AssistantReplacementEvent {
|
|
71
|
+
readonly type: 'assistant-replacement';
|
|
72
|
+
readonly fromMessageId: Message['id'];
|
|
73
|
+
readonly message: Message;
|
|
74
|
+
}
|
|
75
|
+
type AgentRunEvent = AgentEvent | AssistantReplacementEvent | AgentModeStartEvent | UserInputRequestEvent | UserInputResponseEvent | AgentModeEndEvent;
|
|
83
76
|
/**
|
|
84
77
|
* Run an agent in basic, self-checking deep, or deep human-in-loop mode.
|
|
85
78
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-agent.d.ts","names":[],"sources":["../../../src/agent/mode/run-agent.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-agent.d.ts","names":[],"sources":["../../../src/agent/mode/run-agent.ts"],"mappings":";;;;;;;;;cAmBa,qBAAmB;WACpB;WACQ;;;KAmBR;UAEF,uBAAuB,KAAK;;WAE3B,QAAQ;WACR,QAAQ;WACR;;;WAGA;WACA,SAAS,KAAK,QAAQ;WACtB,aAAa;WACb,QAAQ;;UAGF,0BAA0B;WAChC;;UAGM,yBAAyB;WAC/B;;WAEA,YAAY;;UAGN,gCAAgC;WACtC;;WAEA,WAAW;;KAGV,kBAAkB,oBAAoB,mBAAmB;UAEpD;WACN;WACA;;UAGM,wBAAwB;WAC9B,MAAM;;WAEN;WACA,aAAa;;UAGd;WACC;WACA,MAAM;WACN;;UAED;WACC;WACA,SAAS;;UAEV;WACC;WACA,SAAS;WACT,UAAU;;UAEX;WACC;WACA,SAAS;;UAGV;WACC;WACA,eAAe;WACf,SAAS;;KAGR,gBAAgB,aAAa,4BACrC,sBACA,wBACA,yBACA;;;;;;;;iBAqDY,SAAS,SAAS,kBAAkB,cAAc"}
|