maka-agent 0.2.0-dev.23.20260906 → 0.2.0-dev.24.20260907
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/dist/acp/maka-acp-agent.js +2 -1
- package/dist/acp/session-configuration.js +143 -0
- package/dist/acp/session-registry.js +90 -4
- package/dist/cli-core.js +2 -0
- package/dist/pi-transcript.js +5 -12
- package/dist/pi-tui-runner.js +74 -4
- package/dist/runtime-host-cli-context.js +167 -78
- package/dist/runtime-host-cli-installation.js +8 -2
- package/dist/runtime-host-cli.js +31 -1
- package/dist/runtime-host-handoff-surface.js +81 -0
- package/dist/runtime-host-installed-update-bootstrap.js +13 -0
- package/dist/runtime-host-installed-update-coordinator.js +33 -0
- package/dist/runtime-host-lifecycle-transaction.js +9 -1
- package/dist/runtime-host-local-handoff.js +37 -4
- package/dist/runtime-host-local-managed-activation.js +84 -0
- package/dist/runtime-host-local-source-retirement.js +18 -2
- package/dist/runtime-host-managed-lifecycle-manager.js +1 -0
- package/dist/runtime-host-operator-retirement.js +50 -0
- package/dist/runtime-host-service-manager.js +3 -0
- package/dist/runtime-host-session-driver.js +4 -25
- package/dist/runtime-host-session-update.js +62 -0
- package/dist/runtime-host-tui-command.js +38 -73
- package/dist/runtime-host-tui-context.js +1 -0
- package/dist/runtime-host-tui-owner.js +226 -0
- package/dist/tui-copy-catalog.js +140 -3
- package/dist/tui-host-owner-copy.js +24 -0
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/canonical-runtime-event.js +3 -1
- package/node_modules/@maka/core/dist/model-failure.js +40 -0
- package/node_modules/@maka/core/dist/model-metadata.generated.js +4 -4
- package/node_modules/@maka/core/dist/model-metadata.js +3 -3
- package/node_modules/@maka/core/dist/model-web-search.js +5 -4
- package/node_modules/@maka/core/dist/provider-registry.js +45 -4
- package/node_modules/@maka/core/dist/record-schema.js +9 -2
- package/node_modules/@maka/core/dist/runtime-boundary.js +31 -11
- package/node_modules/@maka/core/dist/runtime-event.js +37 -6
- package/node_modules/@maka/core/dist/runtime-handoff.js +98 -0
- package/node_modules/@maka/core/dist/runtime-invocation.js +1 -1
- package/node_modules/@maka/core/dist/runtime-logical-execution.js +112 -0
- package/node_modules/@maka/core/dist/session.js +54 -52
- package/node_modules/@maka/core/dist/slash-command-catalog.js +2 -0
- package/node_modules/@maka/core/dist/tool-result-archive-evidence.js +20 -0
- package/node_modules/@maka/core/dist/usage-record-schema.js +26 -35
- package/node_modules/@maka/core/package.json +4 -0
- package/node_modules/@maka/mcp/dist/index.js +131 -1
- package/node_modules/@maka/runtime/dist/agent-run.js +272 -105
- package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +13 -5
- package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +109 -34
- package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +127 -133
- package/node_modules/@maka/runtime/dist/context-budget.js +14 -9
- package/node_modules/@maka/runtime/dist/conversation-copy.js +5 -4
- package/node_modules/@maka/runtime/dist/goal-continuation.js +36 -4
- package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +18 -9
- package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +30 -22
- package/node_modules/@maka/runtime/dist/history-compaction.js +29 -4
- package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +106 -0
- package/node_modules/@maka/runtime/dist/message-authority.js +9 -0
- package/node_modules/@maka/runtime/dist/model-adapter.js +19 -98
- package/node_modules/@maka/runtime/dist/model-factory.js +19 -81
- package/node_modules/@maka/runtime/dist/model-fetcher.js +7 -0
- package/node_modules/@maka/runtime/dist/model-runtime.js +85 -111
- package/node_modules/@maka/runtime/dist/native-web-search-tool.js +2 -1
- package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +2 -2
- package/node_modules/@maka/runtime/dist/opencode-session-header.js +4 -2
- package/node_modules/@maka/runtime/dist/provider-error-classification.js +84 -123
- package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +68 -108
- package/node_modules/@maka/runtime/dist/run-handoff-gate.js +97 -0
- package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +82 -54
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +117 -159
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +150 -112
- package/node_modules/@maka/runtime/dist/runtime-ledger-repair.js +160 -79
- package/node_modules/@maka/runtime/dist/runtime-read-model.js +30 -89
- package/node_modules/@maka/runtime/dist/runtime-resume.js +80 -4
- package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +5 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +171 -288
- package/node_modules/@maka/runtime/dist/session-projection-helpers.js +0 -27
- package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +3 -4
- package/node_modules/@maka/runtime/dist/test-connection.js +16 -16
- package/node_modules/@maka/runtime/dist/tool-result-archive-encoding.js +38 -0
- package/node_modules/@maka/runtime/dist/tool-runtime.js +3 -61
- package/node_modules/@maka/runtime/package.json +1 -0
- package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +35 -0
- package/node_modules/@maka/runtime-host/dist/client/connect-or-spawn.js +9 -1
- package/node_modules/@maka/runtime-host/dist/client/connection.js +3 -0
- package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +156 -0
- package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +273 -0
- package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +26 -5
- package/node_modules/@maka/runtime-host/dist/client/index.js +2 -0
- package/node_modules/@maka/runtime-host/dist/client/launcher.js +3 -0
- package/node_modules/@maka/runtime-host/dist/client/remote-compatibility-error.js +2 -0
- package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +27 -5
- package/node_modules/@maka/runtime-host/dist/operator/index.js +2 -1
- package/node_modules/@maka/runtime-host/dist/operator/retirement-cancellation.js +20 -0
- package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +21 -12
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +25 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +40 -20
- package/node_modules/@maka/runtime-host/dist/protocol/session-transcript.js +0 -5
- package/node_modules/@maka/runtime-host/dist/protocol/session-turns.js +29 -58
- package/node_modules/@maka/runtime-host/dist/protocol/turn.js +11 -1
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +1 -0
- package/node_modules/@maka/runtime-host/dist/server/canonical-turn-snapshot.js +19 -4
- package/node_modules/@maka/runtime-host/dist/server/connection-session.js +7 -6
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +100 -24
- package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +5 -5
- package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +3 -2
- package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +40 -1
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +96 -17
- package/node_modules/@maka/runtime-host/dist/server/host-residency-registry.js +13 -7
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-admission-registry.js +3 -1
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +124 -62
- package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +76 -6
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +325 -73
- package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +37 -2
- package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +45 -3
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +50 -7
- package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +87 -25
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +8 -55
- package/node_modules/@maka/runtime-host/dist/server/session-sidecar-purge.js +1 -16
- package/node_modules/@maka/runtime-host/dist/server/session-transcript-pager.js +0 -1
- package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +460 -70
- package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/storage-maintenance.js +109 -0
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +0 -1
- package/node_modules/@maka/storage/dist/artifact-store.js +21 -10
- package/node_modules/@maka/storage/dist/artifact-stores.js +1 -1
- package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +0 -4
- package/node_modules/@maka/storage/dist/codex-session-adapter.js +0 -2
- package/node_modules/@maka/storage/dist/context-offload-snapshot.js +325 -0
- package/node_modules/@maka/storage/dist/execution-stores.js +9 -7
- package/node_modules/@maka/storage/dist/file-session-repository.js +1012 -0
- package/node_modules/@maka/storage/dist/opencode-session-adapter.js +0 -4
- package/node_modules/@maka/storage/dist/operational-state-backup.js +9 -5
- package/node_modules/@maka/storage/dist/runtime-event-persistence.js +1 -0
- package/node_modules/@maka/storage/dist/runtime-transcript-query.js +308 -0
- package/node_modules/@maka/storage/dist/session-bundle-policy.js +24 -4
- package/node_modules/@maka/storage/dist/session-message-projection.js +15 -0
- package/node_modules/@maka/storage/dist/session-repository.js +767 -0
- package/node_modules/@maka/storage/dist/session-store.js +25 -99
- package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +10 -3
- package/node_modules/@maka/storage/dist/sqlite-context-offload-store.js +24 -8
- package/node_modules/@maka/storage/dist/sqlite-core-execution-schema.js +7 -1
- package/node_modules/@maka/storage/dist/sqlite-runtime-schema.js +44 -1
- package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +129 -25
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +109 -892
- package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +111 -0
- package/node_modules/@maka/storage/package.json +2 -0
- package/package.json +1 -1
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
19
|
import { RUN_COMPOSITION_RECORDED_EVENT_TYPE } from '@maka/core/agent-run';
|
|
20
|
+
import { isRuntimeHandoffPause } from '@maka/core/runtime-handoff';
|
|
21
|
+
import { RunHandoffGate } from './run-handoff-gate.js';
|
|
22
|
+
import { preserveHandoffOpening } from './runtime-resume.js';
|
|
20
23
|
import { decodeRunCompositionSnapshot } from '@maka/core/run-composition';
|
|
21
24
|
import { DurableStoreWriteError, RunSealedError } from '@maka/core/runtime-event-store';
|
|
22
25
|
import { buildInvocationOpenedEvent, buildSyntheticTerminalRuntimeEvent, isSessionInlineInvocation, } from '@maka/core/runtime-invocation';
|
|
@@ -26,16 +29,18 @@ import { ToolLedgerCorruptionError, ToolLedgerRejectionError, } from '@maka/core
|
|
|
26
29
|
import { Buffer } from 'node:buffer';
|
|
27
30
|
import { isDeepStrictEqual } from 'node:util';
|
|
28
31
|
import { redactSecrets } from '@maka/core/redaction';
|
|
32
|
+
import { truncateUtf8 } from '@maka/core/diagnostic-log';
|
|
33
|
+
import { MODEL_FAILURE_MESSAGE_MAX_BYTES } from '@maka/core/model-failure';
|
|
29
34
|
import { MODEL_CALL_ATTEMPT_EVENT_TYPE, } from '@maka/core/model-call-attempt';
|
|
30
35
|
import { resolveEffectiveOrchestration, } from '@maka/core/orchestration';
|
|
31
|
-
import { messageContentsEqual } from '@maka/core/events';
|
|
32
36
|
import { buildPriorRuntimeContext as buildPriorRuntimeContextProjection, } from './prior-run-context.js';
|
|
33
37
|
import { buildStatusPatch, normalizeStopSessionSource, statusFromEvent, turnStatusFromEvent, } from './session-projection-helpers.js';
|
|
38
|
+
import { admittedPromptEventId } from './message-authority.js';
|
|
34
39
|
import { commitOrCreateTerminalRunFact } from './terminal-run-commit.js';
|
|
35
40
|
import { createRuntimeContinuationStartAdmissionProof, } from './runtime-continuation-admission.js';
|
|
36
41
|
import { DEFAULT_TOOL_MODE, isToolMode } from '@maka/core/tool-mode';
|
|
37
|
-
import { materializeRuntimeEventTranscriptProjection } from './runtime-ledger-repair.js';
|
|
38
42
|
import { cloneAndFreezeRuntimeSnapshot } from './runtime-snapshot.js';
|
|
43
|
+
import { projectRuntimeEventUserMessage } from './runtime-event-read-model.js';
|
|
39
44
|
export class ContinuationStartCommitError extends Error {
|
|
40
45
|
storeCause;
|
|
41
46
|
name = 'ContinuationStartCommitError';
|
|
@@ -65,6 +70,7 @@ export class AgentRun {
|
|
|
65
70
|
runStoreAvailable = true;
|
|
66
71
|
runtimeEventStoreAvailable = true;
|
|
67
72
|
runtimeEventStoreFailure;
|
|
73
|
+
lastAssistantPreview;
|
|
68
74
|
runtimePartialStreamKey;
|
|
69
75
|
runtimePartialBuffer = [];
|
|
70
76
|
runtimePartialBufferBytes = 0;
|
|
@@ -72,6 +78,7 @@ export class AgentRun {
|
|
|
72
78
|
traceWriteError;
|
|
73
79
|
runComposition;
|
|
74
80
|
runCompositionWrite;
|
|
81
|
+
runCompositionCommitted = false;
|
|
75
82
|
failureClass;
|
|
76
83
|
failureMessage;
|
|
77
84
|
lastTs = 0;
|
|
@@ -79,11 +86,16 @@ export class AgentRun {
|
|
|
79
86
|
finalStatus;
|
|
80
87
|
turnFailed = false;
|
|
81
88
|
finalized = false;
|
|
89
|
+
handoffGate = new RunHandoffGate();
|
|
90
|
+
handoffRequest;
|
|
91
|
+
handoffPaused = false;
|
|
82
92
|
terminalRunFactCommitted = false;
|
|
83
93
|
continuationActive = false;
|
|
84
94
|
providerStateIdentity;
|
|
85
95
|
invocationOpening;
|
|
86
96
|
invocationOpeningCommitted = false;
|
|
97
|
+
/** Set once `begin()` owes this run's prompt, cleared once the ledger has it. */
|
|
98
|
+
initialRuntimeEventPending = false;
|
|
87
99
|
terminalClaim;
|
|
88
100
|
constructor(input) {
|
|
89
101
|
const acceptedInput = {
|
|
@@ -92,6 +104,9 @@ export class AgentRun {
|
|
|
92
104
|
...(input.effectiveOrchestration
|
|
93
105
|
? { effectiveOrchestration: cloneAndFreezeRuntimeSnapshot(input.effectiveOrchestration) }
|
|
94
106
|
: {}),
|
|
107
|
+
...(input.handoffSourceComposition
|
|
108
|
+
? { handoffSourceComposition: decodeRunCompositionSnapshot(input.handoffSourceComposition) }
|
|
109
|
+
: {}),
|
|
95
110
|
};
|
|
96
111
|
this.input = acceptedInput;
|
|
97
112
|
if (acceptedInput.runStore && !acceptedInput.runtimeEventStore) {
|
|
@@ -140,12 +155,121 @@ export class AgentRun {
|
|
|
140
155
|
return false;
|
|
141
156
|
this.terminalClaim = { owner: 'stop' };
|
|
142
157
|
this.stopped = true;
|
|
158
|
+
this.handoffGate.close();
|
|
143
159
|
this.abortSource = abortSource;
|
|
144
160
|
return true;
|
|
145
161
|
}
|
|
146
162
|
isStopped() {
|
|
147
163
|
return this.stopped;
|
|
148
164
|
}
|
|
165
|
+
requestHandoff(pause, signal) {
|
|
166
|
+
if (this.handoffRequest ||
|
|
167
|
+
this.finalized ||
|
|
168
|
+
this.terminalClaim ||
|
|
169
|
+
this.input.runtimeEventStore?.durability !== 'canonical' ||
|
|
170
|
+
!this.toolBoundaryProtocol ||
|
|
171
|
+
Object.hasOwn(pause, 'remainingSteps') ||
|
|
172
|
+
!isRuntimeHandoffPause({ ...pause, remainingSteps: null }) ||
|
|
173
|
+
!this.invocationOpening ||
|
|
174
|
+
pause.rootRunId !==
|
|
175
|
+
(this.invocationOpening.source.kind === 'handoff'
|
|
176
|
+
? this.invocationOpening.source.rootRunId
|
|
177
|
+
: this.runId)) {
|
|
178
|
+
throw new Error('Run cannot reserve a cooperative handoff');
|
|
179
|
+
}
|
|
180
|
+
let settle;
|
|
181
|
+
let fail;
|
|
182
|
+
const sealed = new Promise((resolve, reject) => {
|
|
183
|
+
settle = resolve;
|
|
184
|
+
fail = reject;
|
|
185
|
+
});
|
|
186
|
+
void sealed.catch(() => { });
|
|
187
|
+
const pending = {
|
|
188
|
+
pause: cloneAndFreezeRuntimeSnapshot(pause),
|
|
189
|
+
preview: undefined,
|
|
190
|
+
committed: false,
|
|
191
|
+
settle: (value) => {
|
|
192
|
+
signal.removeEventListener('abort', onAbort);
|
|
193
|
+
settle(value);
|
|
194
|
+
},
|
|
195
|
+
fail: (error) => {
|
|
196
|
+
signal.removeEventListener('abort', onAbort);
|
|
197
|
+
fail(error);
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
this.handoffRequest = pending;
|
|
201
|
+
const gate = this.handoffGate.request(signal);
|
|
202
|
+
const cancel = () => {
|
|
203
|
+
if (pending.committed || this.handoffRequest !== pending)
|
|
204
|
+
return;
|
|
205
|
+
gate.cancel();
|
|
206
|
+
this.handoffRequest = undefined;
|
|
207
|
+
pending.settle(false);
|
|
208
|
+
};
|
|
209
|
+
const onAbort = () => cancel();
|
|
210
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
211
|
+
if (signal.aborted)
|
|
212
|
+
cancel();
|
|
213
|
+
void gate.ready.then((ready) => {
|
|
214
|
+
if (!ready)
|
|
215
|
+
cancel();
|
|
216
|
+
});
|
|
217
|
+
return {
|
|
218
|
+
ready: gate.ready,
|
|
219
|
+
sealed,
|
|
220
|
+
cancel,
|
|
221
|
+
preview: () => {
|
|
222
|
+
if (this.handoffRequest !== pending ||
|
|
223
|
+
this.stopped ||
|
|
224
|
+
pending.committed ||
|
|
225
|
+
!pending.preview) {
|
|
226
|
+
throw new Error('Handoff preview requires the currently held Runtime boundary');
|
|
227
|
+
}
|
|
228
|
+
this.assertRunCompositionCommitted();
|
|
229
|
+
return pending.preview;
|
|
230
|
+
},
|
|
231
|
+
commit: () => {
|
|
232
|
+
this.assertRunCompositionCommitted();
|
|
233
|
+
if (this.handoffRequest !== pending || !gate.commit())
|
|
234
|
+
return false;
|
|
235
|
+
pending.committed = true;
|
|
236
|
+
return true;
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
async reachHandoffBoundary(signal, remainingSteps) {
|
|
241
|
+
if (remainingSteps !== null && (!Number.isSafeInteger(remainingSteps) || remainingSteps <= 0)) {
|
|
242
|
+
throw new Error('Invalid handoff step budget');
|
|
243
|
+
}
|
|
244
|
+
const pending = this.handoffRequest;
|
|
245
|
+
if (pending) {
|
|
246
|
+
pending.preview = cloneAndFreezeRuntimeSnapshot({
|
|
247
|
+
id: this.input.newId(),
|
|
248
|
+
sessionId: this.sessionId,
|
|
249
|
+
runId: this.runId,
|
|
250
|
+
invocationId: this.invocationId,
|
|
251
|
+
turnId: this.turnId,
|
|
252
|
+
ts: this.input.now(),
|
|
253
|
+
partial: false,
|
|
254
|
+
role: 'system',
|
|
255
|
+
author: 'host',
|
|
256
|
+
modelVisibility: 'hidden',
|
|
257
|
+
actions: { endInvocation: true, handoffPause: { ...pending.pause, remainingSteps } },
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
const decision = await this.handoffGate.reachBoundary(signal);
|
|
261
|
+
if (decision === 'pause') {
|
|
262
|
+
this.handoffPaused = true;
|
|
263
|
+
}
|
|
264
|
+
return decision;
|
|
265
|
+
}
|
|
266
|
+
hasCommittedHandoff() {
|
|
267
|
+
return (this.handoffPaused &&
|
|
268
|
+
this.handoffRequest?.committed === true &&
|
|
269
|
+
!this.stopped &&
|
|
270
|
+
!this.failureClass &&
|
|
271
|
+
!this.terminalClaim);
|
|
272
|
+
}
|
|
149
273
|
headerSnapshot() {
|
|
150
274
|
return this.header;
|
|
151
275
|
}
|
|
@@ -251,6 +375,15 @@ export class AgentRun {
|
|
|
251
375
|
return Promise.reject(new Error('AgentRun store is not configured'));
|
|
252
376
|
}
|
|
253
377
|
const normalized = decodeRunCompositionSnapshot(snapshot);
|
|
378
|
+
const expected = this.input.handoffSourceComposition;
|
|
379
|
+
if (expected &&
|
|
380
|
+
(normalized.baseSystemPromptHash !== expected.baseSystemPromptHash ||
|
|
381
|
+
normalized.toolCatalogHash !== expected.toolCatalogHash ||
|
|
382
|
+
normalized.toolAvailabilityHash !== expected.toolAvailabilityHash ||
|
|
383
|
+
normalized.baseProviderOptionsHash !== expected.baseProviderOptionsHash ||
|
|
384
|
+
normalized.contextWindow !== expected.contextWindow)) {
|
|
385
|
+
return Promise.reject(new Error('Handoff Run Composition execution semantics changed'));
|
|
386
|
+
}
|
|
254
387
|
if (this.runComposition && !isDeepStrictEqual(this.runComposition, normalized)) {
|
|
255
388
|
return Promise.reject(new Error('AgentRun Run Composition changed after resolution'));
|
|
256
389
|
}
|
|
@@ -266,7 +399,12 @@ export class AgentRun {
|
|
|
266
399
|
turnId: this.turnId,
|
|
267
400
|
ts: this.input.now(),
|
|
268
401
|
data: { runComposition: normalized },
|
|
269
|
-
}, {
|
|
402
|
+
}, {
|
|
403
|
+
durable: this.requiresDurablePersistence() ||
|
|
404
|
+
this.input.runtimeEventStore?.durability === 'canonical',
|
|
405
|
+
});
|
|
406
|
+
}).then(() => {
|
|
407
|
+
this.runCompositionCommitted = true;
|
|
270
408
|
});
|
|
271
409
|
this.runCompositionWrite = write;
|
|
272
410
|
return write.catch((error) => {
|
|
@@ -275,6 +413,11 @@ export class AgentRun {
|
|
|
275
413
|
throw error;
|
|
276
414
|
});
|
|
277
415
|
}
|
|
416
|
+
assertRunCompositionCommitted() {
|
|
417
|
+
if (!this.runCompositionCommitted) {
|
|
418
|
+
throw new Error('Cooperative handoff requires a durably committed Run Composition');
|
|
419
|
+
}
|
|
420
|
+
}
|
|
278
421
|
/**
|
|
279
422
|
* Canonical accounting record for one physical provider request (#1679).
|
|
280
423
|
*
|
|
@@ -406,8 +549,10 @@ export class AgentRun {
|
|
|
406
549
|
requireTerminalWrite: options.requireTerminalWrite ?? Boolean(this.input.runtimeEventStore),
|
|
407
550
|
});
|
|
408
551
|
await this.recordSessionEvent(sessionEvent, options);
|
|
552
|
+
await this.commitMessageProjection(this.lastAssistantPreview);
|
|
409
553
|
return;
|
|
410
554
|
}
|
|
555
|
+
this.rememberAssistantPreview(runtimeEvent);
|
|
411
556
|
if (this.requiresDurablePersistence() && isInteractionResumeAck(sessionEvent)) {
|
|
412
557
|
// A hosted continuation may resume execution only after its identity-only
|
|
413
558
|
// settlement fact is durable. Session status advances next, and the queue
|
|
@@ -435,48 +580,54 @@ export class AgentRun {
|
|
|
435
580
|
// stays fail-open (a trace gap, not a correctness gap).
|
|
436
581
|
const steering = runtimeEvent.content?.kind === 'text' && runtimeEvent.content.steering === true;
|
|
437
582
|
await this.recordRuntimeEvents([runtimeEvent], steering ? { requireDurableWrite: true } : {});
|
|
438
|
-
|
|
583
|
+
if (steering) {
|
|
584
|
+
await this.commitMessageProjection(projectRuntimeEventUserMessage(runtimeEvent, runtimeEvent.id));
|
|
585
|
+
}
|
|
439
586
|
}
|
|
440
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* A user message is fail-CLOSED: it also takes the Session's connection lock,
|
|
590
|
+
* and no other path re-derives that latch now that the transcript is not a
|
|
591
|
+
* second authority. An assistant preview is fail-open — losing it costs a
|
|
592
|
+
* stale sidebar entry, never the turn.
|
|
593
|
+
*/
|
|
594
|
+
async commitMessageProjection(message) {
|
|
595
|
+
const commit = this.input.hooks.commitMessageProjection;
|
|
596
|
+
if (!commit || !message)
|
|
597
|
+
return;
|
|
598
|
+
const committed = commit.call(this.input.hooks, this.sessionId, message);
|
|
599
|
+
if (message.type === 'user')
|
|
600
|
+
return committed;
|
|
601
|
+
await committed.catch(() => { });
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* The assistant text the Session list shows once the Turn ends.
|
|
605
|
+
*
|
|
606
|
+
* Kept as the run goes so the catalog costs one write per Turn rather than
|
|
607
|
+
* one per streamed step, and read only after the terminal fact is durable —
|
|
608
|
+
* a Turn that never spoke leaves the previous preview standing.
|
|
609
|
+
*/
|
|
610
|
+
rememberAssistantPreview(event) {
|
|
611
|
+
if (event.role !== 'model' || event.content?.kind !== 'text')
|
|
612
|
+
return;
|
|
613
|
+
if (!event.content.text?.trim())
|
|
614
|
+
return;
|
|
615
|
+
this.lastAssistantPreview = {
|
|
616
|
+
type: 'assistant',
|
|
617
|
+
id: event.id,
|
|
618
|
+
turnId: event.turnId,
|
|
619
|
+
ts: event.ts,
|
|
620
|
+
text: event.content.text,
|
|
621
|
+
modelId: this.header.model,
|
|
622
|
+
};
|
|
623
|
+
}
|
|
441
624
|
async begin() {
|
|
625
|
+
// Owed from here, not from after the opening: `openInvocation` can leave the
|
|
626
|
+
// invocation open and still throw, and `finalize` reopens what it can.
|
|
627
|
+
this.initialRuntimeEventPending = true;
|
|
442
628
|
await this.openInvocation();
|
|
443
|
-
|
|
444
|
-
const
|
|
445
|
-
if (this.input.userMessageId === null) {
|
|
446
|
-
initialRuntimeEventId = this.input.newId();
|
|
447
|
-
}
|
|
448
|
-
else {
|
|
449
|
-
const userMessageId = this.input.userMessageId ?? this.input.newId();
|
|
450
|
-
initialRuntimeEventId = userMessageId;
|
|
451
|
-
const userMsg = cloneAndFreezeRuntimeSnapshot({
|
|
452
|
-
type: 'user',
|
|
453
|
-
id: userMessageId,
|
|
454
|
-
turnId: this.turnId,
|
|
455
|
-
ts: userMessageTs,
|
|
456
|
-
text: this.input.userInput.text,
|
|
457
|
-
...(this.input.userInput.displayText !== undefined
|
|
458
|
-
? { displayText: this.input.userInput.displayText }
|
|
459
|
-
: {}),
|
|
460
|
-
...(this.input.userInput.attachments
|
|
461
|
-
? { attachments: this.input.userInput.attachments }
|
|
462
|
-
: {}),
|
|
463
|
-
...(this.input.userInput.directoryReferences
|
|
464
|
-
? { directoryReferences: this.input.userInput.directoryReferences }
|
|
465
|
-
: {}),
|
|
466
|
-
...(this.input.userInput.quotes ? { quotes: this.input.userInput.quotes } : {}),
|
|
467
|
-
...(this.input.userInput.inlineReferences
|
|
468
|
-
? { inlineReferences: this.input.userInput.inlineReferences }
|
|
469
|
-
: {}),
|
|
470
|
-
...(this.input.userInput.origin ? { origin: this.input.userInput.origin } : {}),
|
|
471
|
-
});
|
|
472
|
-
await appendUserMessageOnce(this.input.store, this.sessionId, userMsg);
|
|
473
|
-
}
|
|
474
|
-
await this.input.hooks.appendTurnState(this.sessionId, this.turnId, 'running', this.lineage);
|
|
475
|
-
this.lastTs = userMessageTs;
|
|
476
|
-
const initialRuntimeEvent = cloneAndFreezeRuntimeSnapshot(this.buildInitialRuntimeEvent(initialRuntimeEventId, this.lastTs));
|
|
477
|
-
await this.recordRuntimeEvents([initialRuntimeEvent], {
|
|
478
|
-
requireDurableWrite: this.requiresDurablePersistence(),
|
|
479
|
-
});
|
|
629
|
+
this.lastTs = this.input.now();
|
|
630
|
+
const initialRuntimeEvent = await this.recordInitialRuntimeEvent(this.lastTs);
|
|
480
631
|
this.active = await this.input.hooks.reserveRun(this.sessionId, this.header, this);
|
|
481
632
|
await this.input.hooks.updateStatus(this.sessionId, 'running', undefined, this.lastTs);
|
|
482
633
|
const priorRuntimeContext = await this.buildPriorRuntimeContext();
|
|
@@ -507,13 +658,23 @@ export class AgentRun {
|
|
|
507
658
|
initialRuntimeEvent,
|
|
508
659
|
};
|
|
509
660
|
}
|
|
661
|
+
/** Say what this run was asked to do. */
|
|
662
|
+
async recordInitialRuntimeEvent(ts) {
|
|
663
|
+
const event = cloneAndFreezeRuntimeSnapshot(this.buildInitialRuntimeEvent(admittedPromptEventId(this.runId, this.input.userMessageId), ts));
|
|
664
|
+
await this.recordRuntimeEvents([event], {
|
|
665
|
+
requireDurableWrite: this.requiresDurablePersistence(),
|
|
666
|
+
});
|
|
667
|
+
// Owed until the catalog carries it too, not just until the ledger does:
|
|
668
|
+
// the projection is where the connection lock latches, and re-recording the
|
|
669
|
+
// event is free because its id is derived and the store dedupes it.
|
|
670
|
+
await this.commitMessageProjection(projectRuntimeEventUserMessage(event, event.id));
|
|
671
|
+
this.initialRuntimeEventPending = false;
|
|
672
|
+
return event;
|
|
673
|
+
}
|
|
510
674
|
async beginOperation() {
|
|
511
675
|
await this.openInvocation();
|
|
512
676
|
const startedAt = this.input.now();
|
|
513
677
|
this.lastTs = startedAt;
|
|
514
|
-
await this.input.hooks.appendTurnState(this.sessionId, this.turnId, 'running', this.lineage, {
|
|
515
|
-
ts: startedAt,
|
|
516
|
-
});
|
|
517
678
|
this.active = await this.input.hooks.reserveRun(this.sessionId, this.header, this);
|
|
518
679
|
await this.input.hooks.updateStatus(this.sessionId, 'running', undefined, startedAt);
|
|
519
680
|
const priorRuntimeContext = await this.buildPriorRuntimeContext();
|
|
@@ -545,9 +706,6 @@ export class AgentRun {
|
|
|
545
706
|
throw new ContinuationStartCommitError(error);
|
|
546
707
|
}
|
|
547
708
|
await this.input.continuationFailpoint?.('after_continuation_start_committed');
|
|
548
|
-
await this.input.hooks.appendTurnState(this.sessionId, this.turnId, 'running', this.lineage, {
|
|
549
|
-
ts: startedAt,
|
|
550
|
-
});
|
|
551
709
|
this.active = await this.input.hooks.reserveRun(this.sessionId, this.header, this);
|
|
552
710
|
await this.input.hooks.updateStatus(this.sessionId, 'running', undefined, startedAt);
|
|
553
711
|
return {
|
|
@@ -603,10 +761,29 @@ export class AgentRun {
|
|
|
603
761
|
: {}),
|
|
604
762
|
};
|
|
605
763
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
764
|
+
/**
|
|
765
|
+
* Record something the runtime needs to tell the reader about this turn.
|
|
766
|
+
*
|
|
767
|
+
* It is a fact of the invocation, so it goes where the invocation's facts go.
|
|
768
|
+
* Never model-visible: the note describes what happened to the conversation,
|
|
769
|
+
* it is not part of it.
|
|
770
|
+
*/
|
|
771
|
+
async recordSystemNote(kind, data) {
|
|
772
|
+
await this.recordRuntimeEvents([
|
|
773
|
+
{
|
|
774
|
+
id: this.input.newId(),
|
|
775
|
+
invocationId: this.invocationId,
|
|
776
|
+
runId: this.runId,
|
|
777
|
+
sessionId: this.sessionId,
|
|
778
|
+
turnId: this.turnId,
|
|
779
|
+
ts: this.input.now(),
|
|
780
|
+
partial: false,
|
|
781
|
+
role: 'system',
|
|
782
|
+
author: 'system',
|
|
783
|
+
modelVisibility: 'hidden',
|
|
784
|
+
content: { kind: 'system_note', note: kind, ...(data !== undefined ? { data } : {}) },
|
|
785
|
+
},
|
|
786
|
+
]);
|
|
610
787
|
}
|
|
611
788
|
async recordSessionEvent(ev, options = {}) {
|
|
612
789
|
this.lastTs = ev.ts;
|
|
@@ -631,9 +808,9 @@ export class AgentRun {
|
|
|
631
808
|
this.markRunFailed(turnStatus.errorClass, `turn ended with stopReason=${ev.type === 'complete' ? ev.stopReason : 'unknown'}`);
|
|
632
809
|
}
|
|
633
810
|
}
|
|
634
|
-
if (transition && !this.stopped) {
|
|
811
|
+
if (transition && !this.stopped && ev.type !== 'error') {
|
|
635
812
|
const updateSessionStatus = async () => {
|
|
636
|
-
if (terminalSessionEvent
|
|
813
|
+
if (terminalSessionEvent) {
|
|
637
814
|
await this.input.hooks
|
|
638
815
|
.updateStatus(this.sessionId, transition.status, transition.blockedReason, ev.ts)
|
|
639
816
|
.catch((error) => this.enqueueTraceWriteFailure(error, 'terminal session projection'));
|
|
@@ -643,21 +820,6 @@ export class AgentRun {
|
|
|
643
820
|
};
|
|
644
821
|
await updateSessionStatus();
|
|
645
822
|
}
|
|
646
|
-
if (turnStatus && !this.stopped) {
|
|
647
|
-
const appendTurnState = this.input.hooks.appendTurnState(this.sessionId, this.turnId, turnStatus.status, this.lineage, {
|
|
648
|
-
ts: ev.ts,
|
|
649
|
-
errorClass: turnStatus.errorClass,
|
|
650
|
-
...(turnStatus.status === 'aborted' && this.abortSource
|
|
651
|
-
? { abortSource: this.abortSource }
|
|
652
|
-
: {}),
|
|
653
|
-
});
|
|
654
|
-
if (terminalSessionEvent || ev.type === 'error') {
|
|
655
|
-
await appendTurnState.catch((error) => this.enqueueTraceWriteFailure(error, 'terminal session projection'));
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
await appendTurnState;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
823
|
if (ev.type === 'error') {
|
|
662
824
|
if (this.stopped) {
|
|
663
825
|
this.finalStatus = { status: 'aborted' };
|
|
@@ -665,12 +827,6 @@ export class AgentRun {
|
|
|
665
827
|
else {
|
|
666
828
|
this.turnFailed = true;
|
|
667
829
|
this.finalStatus = transition ?? { status: 'blocked', blockedReason: 'unknown' };
|
|
668
|
-
await this.input.hooks
|
|
669
|
-
.appendTurnState(this.sessionId, this.turnId, 'failed', this.lineage, {
|
|
670
|
-
ts: ev.ts,
|
|
671
|
-
errorClass: ev.reason ?? ev.code ?? 'unknown',
|
|
672
|
-
})
|
|
673
|
-
.catch((error) => this.enqueueTraceWriteFailure(error, 'terminal session projection'));
|
|
674
830
|
this.markRunFailed(ev.reason ?? ev.code ?? 'unknown', ev.message);
|
|
675
831
|
}
|
|
676
832
|
}
|
|
@@ -766,17 +922,40 @@ export class AgentRun {
|
|
|
766
922
|
return;
|
|
767
923
|
}
|
|
768
924
|
this.finalStatus = { status: 'blocked', blockedReason: 'unknown' };
|
|
769
|
-
|
|
770
|
-
.appendTurnState(this.sessionId, this.turnId, 'failed', this.lineage, {
|
|
771
|
-
errorClass: error instanceof Error ? error.name : 'unknown',
|
|
772
|
-
})
|
|
773
|
-
.catch(() => { });
|
|
774
|
-
this.markRunFailed(error instanceof Error ? error.name : 'unknown', errorMessage(error));
|
|
925
|
+
this.markRunFailed(error instanceof Error ? error.name : 'unknown', error instanceof Error ? error.message : String(error));
|
|
775
926
|
}
|
|
776
927
|
async finalize() {
|
|
777
928
|
if (this.finalized)
|
|
778
929
|
return;
|
|
779
930
|
this.finalized = true;
|
|
931
|
+
this.handoffGate.close();
|
|
932
|
+
const handoff = this.handoffRequest;
|
|
933
|
+
if (this.handoffPaused &&
|
|
934
|
+
handoff?.committed &&
|
|
935
|
+
!this.stopped &&
|
|
936
|
+
!this.failureClass &&
|
|
937
|
+
!this.terminalClaim) {
|
|
938
|
+
try {
|
|
939
|
+
await this.flushRuntimePartialBuffer(true);
|
|
940
|
+
// Stop may have claimed the logical outcome during the flush. Reserving
|
|
941
|
+
// the pause below is synchronous up to its first write, so only one wins.
|
|
942
|
+
if (!this.stopped && !this.failureClass && !this.terminalClaim) {
|
|
943
|
+
this.assertRunCompositionCommitted();
|
|
944
|
+
await this.recordRuntimeEvents([handoff.preview], { requireTerminalWrite: true });
|
|
945
|
+
this.terminalRunFactCommitted = true;
|
|
946
|
+
if (this.active)
|
|
947
|
+
await this.input.hooks.unregisterRun(this.active, this);
|
|
948
|
+
await this.traceQueue;
|
|
949
|
+
handoff.settle(true);
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
catch (error) {
|
|
954
|
+
handoff.fail(error);
|
|
955
|
+
throw error;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
handoff?.settle(false);
|
|
780
959
|
// A run cannot end without having begun. Finalizing one that never reached
|
|
781
960
|
// its start would otherwise leave a terminal event on an invocation the
|
|
782
961
|
// inventory cannot see, because nothing opened it. A continuation is the
|
|
@@ -784,6 +963,13 @@ export class AgentRun {
|
|
|
784
963
|
// and a continuation that never committed one has no invocation to end.
|
|
785
964
|
if (!this.input.commitContinuationStart)
|
|
786
965
|
await this.openInvocation().catch(() => { });
|
|
966
|
+
// A run also cannot end without saying what it was asked to do. `begin()`
|
|
967
|
+
// can fail between opening the invocation and recording its prompt, and
|
|
968
|
+
// the terminal event below seals the run against every later append —
|
|
969
|
+
// including the one crash recovery would use to repair the same shape.
|
|
970
|
+
if (this.initialRuntimeEventPending) {
|
|
971
|
+
await this.recordInitialRuntimeEvent(this.lastTs || this.input.now()).catch(() => { });
|
|
972
|
+
}
|
|
787
973
|
await this.flushRuntimePartialBuffer(true);
|
|
788
974
|
const lastTs = this.lastTs || this.input.now();
|
|
789
975
|
if (this.stopped)
|
|
@@ -809,17 +995,6 @@ export class AgentRun {
|
|
|
809
995
|
catch {
|
|
810
996
|
// The user-visible turn already completed; preserve existing behavior.
|
|
811
997
|
}
|
|
812
|
-
if (this.sawCompletion) {
|
|
813
|
-
await this.input.store
|
|
814
|
-
.appendMessage(this.sessionId, {
|
|
815
|
-
type: 'system_note',
|
|
816
|
-
id: this.input.newId(),
|
|
817
|
-
turnId: this.turnId,
|
|
818
|
-
ts: lastTs,
|
|
819
|
-
kind: 'session_resume',
|
|
820
|
-
})
|
|
821
|
-
.catch(() => { });
|
|
822
|
-
}
|
|
823
998
|
await this.finishRun(this.finalStatus, lastTs);
|
|
824
999
|
}
|
|
825
1000
|
async openInvocation(continuation) {
|
|
@@ -864,7 +1039,7 @@ export class AgentRun {
|
|
|
864
1039
|
...(this.input.userInput.agentName ? { agentName: this.input.userInput.agentName } : {}),
|
|
865
1040
|
...(continuation ? { parentRunId: continuation.sourceRunId } : {}),
|
|
866
1041
|
};
|
|
867
|
-
|
|
1042
|
+
const opening = {
|
|
868
1043
|
kind: 'invocation_opened',
|
|
869
1044
|
protocol: 'invocation_opened_v1',
|
|
870
1045
|
route: this.header.llmConnectionId === undefined
|
|
@@ -912,6 +1087,9 @@ export class AgentRun {
|
|
|
912
1087
|
: { kind: 'fresh' },
|
|
913
1088
|
...(Object.keys(lineage).length > 0 ? { lineage } : {}),
|
|
914
1089
|
};
|
|
1090
|
+
return continuation
|
|
1091
|
+
? preserveHandoffOpening(continuation, opening, this.input.handoffSourceOpening)
|
|
1092
|
+
: opening;
|
|
915
1093
|
}
|
|
916
1094
|
invocationRootAuthority() {
|
|
917
1095
|
const origin = this.input.userInput.origin;
|
|
@@ -976,12 +1154,13 @@ export class AgentRun {
|
|
|
976
1154
|
/**
|
|
977
1155
|
* Remember why this run is going to fail.
|
|
978
1156
|
*
|
|
1157
|
+
* Preserve diagnostic text without trace redaction, within the byte budget.
|
|
979
1158
|
* Nothing is written here: the terminal RuntimeEvent carries the failure, and
|
|
980
1159
|
* it is committed once, at the end, by `commitTerminalRun`.
|
|
981
1160
|
*/
|
|
982
1161
|
markRunFailed(failureClass, message) {
|
|
983
1162
|
this.failureClass = failureClass;
|
|
984
|
-
this.failureMessage =
|
|
1163
|
+
this.failureMessage = truncateUtf8(message, MODEL_FAILURE_MESSAGE_MAX_BYTES, '…');
|
|
985
1164
|
}
|
|
986
1165
|
/**
|
|
987
1166
|
* End the run by committing its terminal RuntimeEvent, and nothing else.
|
|
@@ -1394,18 +1573,6 @@ function redactTraceString(value) {
|
|
|
1394
1573
|
function errorMessage(error) {
|
|
1395
1574
|
return redactTraceString(error instanceof Error ? error.message : String(error));
|
|
1396
1575
|
}
|
|
1397
|
-
async function appendUserMessageOnce(store, sessionId, message) {
|
|
1398
|
-
const existing = (await store.readMessages(sessionId)).find((candidate) => candidate.id === message.id);
|
|
1399
|
-
if (!existing) {
|
|
1400
|
-
await store.appendMessage(sessionId, message);
|
|
1401
|
-
return;
|
|
1402
|
-
}
|
|
1403
|
-
if (existing.type !== 'user' ||
|
|
1404
|
-
existing.turnId !== message.turnId ||
|
|
1405
|
-
!messageContentsEqual(existing, message)) {
|
|
1406
|
-
throw new Error(`Durable UserMessage identity ${message.id} has conflicting content`);
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
1576
|
function isInteractionResumeAck(event) {
|
|
1410
1577
|
return (event.type === 'sandbox_boundary_decision_ack' ||
|
|
1411
1578
|
event.type === 'user_question_answer_ack' ||
|
|
@@ -29,7 +29,7 @@ import { AiSdkTurn } from './ai-sdk-turn.js';
|
|
|
29
29
|
import { buildInvalidMakaTool } from './ai-sdk-tool-repair.js';
|
|
30
30
|
import { ToolAvailabilityRuntime } from './tool-availability.js';
|
|
31
31
|
import { MEMORY_EXTRACT_TOOL_NAME, MEMORY_REMEMBER_TOOL_NAME, buildMemoryExtractionTriggerTools, } from './memory-extraction.js';
|
|
32
|
-
import {
|
|
32
|
+
import { resolveModelRuntime } from './model-runtime.js';
|
|
33
33
|
import { routeApplyPatchTools } from './apply-patch-profile.js';
|
|
34
34
|
import { bindToolResultArchiveDecoder } from './tool-result-archive-capability.js';
|
|
35
35
|
import { resolveSelectedModelContextWindow } from './context-budget-policy.js';
|
|
@@ -111,15 +111,17 @@ export class AiSdkBackend {
|
|
|
111
111
|
// One resolved options value for every reader: the main call, the
|
|
112
112
|
// auxiliary memory-extraction call, and the provider request all use the
|
|
113
113
|
// same options value, so they cannot disagree on what was sent.
|
|
114
|
+
const runtime = resolveModelRuntime(input.connection, input.modelId);
|
|
114
115
|
this.resolvedProviderOptions =
|
|
115
116
|
input.providerOptions ??
|
|
116
|
-
buildProviderOptions(input.connection, input.modelId, input.header.thinkingLevel);
|
|
117
|
+
buildProviderOptions(input.connection, input.modelId, input.header.thinkingLevel, runtime);
|
|
117
118
|
this.modelAdapter = new ModelAdapter({
|
|
118
119
|
sessionId: input.sessionId,
|
|
119
120
|
connection: input.connection,
|
|
120
121
|
apiKey: input.apiKey,
|
|
121
122
|
modelId: input.modelId,
|
|
122
123
|
modelFactory: input.modelFactory,
|
|
124
|
+
resolvedRuntime: runtime,
|
|
123
125
|
// `input.providerOptions` is an override escape hatch: when set it owns
|
|
124
126
|
// the whole provider-options namespace (including reasoning effort), and
|
|
125
127
|
// the computed defaults are dropped entirely. Keep providerOptions the
|
|
@@ -144,7 +146,6 @@ export class AiSdkBackend {
|
|
|
144
146
|
assertModelCallAccountingReady: input.assertModelCallAccountingReady,
|
|
145
147
|
beforeRunProviderDispatch: input.beforeRunProviderDispatch,
|
|
146
148
|
});
|
|
147
|
-
const runtime = resolveModelRuntime(input.connection, input.modelId);
|
|
148
149
|
const applyPatchProfile = runtime.applyPatchProfile;
|
|
149
150
|
this.messageProjection = new AiSdkMessageProjection({
|
|
150
151
|
modelAdapter: this.modelAdapter,
|
|
@@ -176,7 +177,7 @@ export class AiSdkBackend {
|
|
|
176
177
|
if (turn)
|
|
177
178
|
turn.memoryExtractRequested = true;
|
|
178
179
|
},
|
|
179
|
-
...(
|
|
180
|
+
...(input.connection.providerType === 'openai' && runtime.wire === 'openai-responses'
|
|
180
181
|
? { unsupportedReason: 'provider_unsupported' }
|
|
181
182
|
: {}),
|
|
182
183
|
})
|
|
@@ -206,11 +207,11 @@ export class AiSdkBackend {
|
|
|
206
207
|
createToolRuntime(identity) {
|
|
207
208
|
const input = this.input;
|
|
208
209
|
return new ToolRuntime({
|
|
210
|
+
inheritedSandboxBoundaryDenied: identity.inheritedSandboxBoundaryDenied,
|
|
209
211
|
sessionId: input.sessionId,
|
|
210
212
|
header: input.header,
|
|
211
213
|
connection: input.connection,
|
|
212
214
|
modelId: input.modelId,
|
|
213
|
-
appendMessage: input.appendMessage,
|
|
214
215
|
readExecutionBoundary: input.readExecutionBoundary,
|
|
215
216
|
createSandboxBoundaryRequest: input.createSandboxBoundaryRequest,
|
|
216
217
|
settleSandboxBoundaryRequest: input.settleSandboxBoundaryRequest,
|
|
@@ -241,6 +242,12 @@ export class AiSdkBackend {
|
|
|
241
242
|
// --------------------------------------------------------------------------
|
|
242
243
|
// send()
|
|
243
244
|
// --------------------------------------------------------------------------
|
|
245
|
+
async prepareRunComposition(input) {
|
|
246
|
+
if (!this.input.beforeRunProviderDispatch) {
|
|
247
|
+
throw new Error('Backend has no durable Run Composition preparation authority');
|
|
248
|
+
}
|
|
249
|
+
await this.input.beforeRunProviderDispatch({ sessionId: this.sessionId, ...input });
|
|
250
|
+
}
|
|
244
251
|
openTurnScope(input) {
|
|
245
252
|
const turn = new AiSdkTurn({
|
|
246
253
|
backend: this.input,
|
|
@@ -257,6 +264,7 @@ export class AiSdkBackend {
|
|
|
257
264
|
maxSteps: this.maxSteps,
|
|
258
265
|
providerRetrySleep: this.providerRetrySleep,
|
|
259
266
|
createToolRuntime: (owner) => this.createToolRuntime({
|
|
267
|
+
inheritedSandboxBoundaryDenied: input.continuation?.sandboxBoundaryDenied === true,
|
|
260
268
|
turnId: owner.turnId,
|
|
261
269
|
runId: owner.runId,
|
|
262
270
|
invocationId: input.invocationId ?? input.runId,
|