@myagentroam/agent 0.9.158 → 0.9.160
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/agent-core/extensions/agents.d.ts +69 -0
- package/dist/agent-core/extensions/agents.js +160 -0
- package/dist/agent-core/extensions/contracts.d.ts +260 -0
- package/dist/agent-core/extensions/contracts.js +1 -0
- package/dist/agent-core/extensions/data.d.ts +84 -0
- package/dist/agent-core/extensions/data.js +83 -0
- package/dist/agent-core/extensions/environment.d.ts +27 -0
- package/dist/agent-core/extensions/environment.js +52 -0
- package/dist/agent-core/extensions/files.d.ts +64 -0
- package/dist/agent-core/extensions/files.js +26 -0
- package/dist/agent-core/extensions/hooks.d.ts +32 -0
- package/dist/agent-core/extensions/hooks.js +135 -0
- package/dist/agent-core/extensions/manager.d.ts +39 -0
- package/dist/agent-core/extensions/manager.js +458 -0
- package/dist/agent-core/extensions/mcp.d.ts +99 -0
- package/dist/agent-core/extensions/mcp.js +433 -0
- package/dist/agent-core/extensions/model-request.d.ts +60 -0
- package/dist/agent-core/extensions/model-request.js +167 -0
- package/dist/agent-core/extensions/model-stream.d.ts +9 -0
- package/dist/agent-core/extensions/model-stream.js +101 -0
- package/dist/agent-core/extensions/models.d.ts +43 -0
- package/dist/agent-core/extensions/models.js +1 -0
- package/dist/agent-core/extensions/network.d.ts +32 -0
- package/dist/agent-core/extensions/network.js +97 -0
- package/dist/agent-core/extensions/operation.d.ts +29 -0
- package/dist/agent-core/extensions/operation.js +98 -0
- package/dist/agent-core/extensions/processes.d.ts +52 -0
- package/dist/agent-core/extensions/processes.js +283 -0
- package/dist/agent-core/extensions/prompt-composition.d.ts +24 -0
- package/dist/agent-core/extensions/prompt-composition.js +106 -0
- package/dist/agent-core/extensions/prompt-input.d.ts +23 -0
- package/dist/agent-core/extensions/prompt-input.js +46 -0
- package/dist/agent-core/extensions/resources.d.ts +27 -0
- package/dist/agent-core/extensions/resources.js +221 -0
- package/dist/agent-core/extensions/services.d.ts +31 -0
- package/dist/agent-core/extensions/services.js +61 -0
- package/dist/agent-core/extensions/session-input.d.ts +151 -0
- package/dist/agent-core/extensions/session-input.js +351 -0
- package/dist/agent-core/extensions/session-messages.d.ts +41 -0
- package/dist/agent-core/extensions/session-messages.js +76 -0
- package/dist/agent-core/extensions/session.d.ts +68 -0
- package/dist/agent-core/extensions/session.js +593 -0
- package/dist/agent-core/extensions/settings.d.ts +59 -0
- package/dist/agent-core/extensions/settings.js +115 -0
- package/dist/agent-core/extensions/store.d.ts +10 -0
- package/dist/agent-core/extensions/store.js +131 -0
- package/dist/agent-core/extensions/tools.d.ts +61 -0
- package/dist/agent-core/extensions/tools.js +266 -0
- package/dist/agent-core/host/contracts.d.ts +25 -0
- package/dist/agent-core/host/local-agent-host.d.ts +10 -1
- package/dist/agent-core/host/local-agent-host.js +132 -20
- package/dist/agent-core/host/local-file-access.d.ts +30 -0
- package/dist/agent-core/host/local-file-access.js +107 -0
- package/dist/agent-core/host/local-network-access.d.ts +6 -0
- package/dist/agent-core/host/local-network-access.js +97 -0
- package/dist/agent-core/host/local-process-executor.d.ts +5 -1
- package/dist/agent-core/host/local-session-environment.d.ts +18 -0
- package/dist/agent-core/host/local-session-environment.js +102 -0
- package/dist/agent-core/model/anthropic-messages.js +73 -23
- package/dist/agent-core/model/contracts.d.ts +21 -0
- package/dist/agent-core/model/openai-responses.d.ts +3 -1
- package/dist/agent-core/model/openai-responses.js +248 -97
- package/dist/agent-core/model/text-blocks.d.ts +7 -0
- package/dist/agent-core/model/text-blocks.js +40 -0
- package/dist/agent-core/prompts/index.d.ts +6 -2
- package/dist/agent-core/prompts/index.js +38 -24
- package/dist/agent-core/runtime/context/gc-tokens.js +6 -1
- package/dist/agent-core/runtime/context/normalize.js +21 -1
- package/dist/agent-core/runtime/context/projection.js +35 -1
- package/dist/agent-core/runtime/context/request-budget.js +5 -2
- package/dist/agent-core/runtime/context/restore.d.ts +5 -0
- package/dist/agent-core/runtime/context/restore.js +47 -4
- package/dist/agent-core/runtime/context/usage.js +2 -3
- package/dist/agent-core/runtime/contracts.d.ts +2 -0
- package/dist/agent-core/runtime/execution.js +5 -2
- package/dist/agent-core/sdk/agent.js +177 -40
- package/dist/agent-core/sdk/extension-agents.d.ts +9 -0
- package/dist/agent-core/sdk/extension-agents.js +51 -0
- package/dist/agent-core/sdk/extension-models.d.ts +13 -0
- package/dist/agent-core/sdk/extension-models.js +128 -0
- package/dist/agent-core/sdk/extension-session.d.ts +30 -0
- package/dist/agent-core/sdk/extension-session.js +103 -0
- package/dist/agent-core/sdk/extension-tools.d.ts +16 -0
- package/dist/agent-core/sdk/extension-tools.js +126 -0
- package/dist/agent-core/sdk/session.d.ts +26 -2
- package/dist/agent-core/sdk/session.js +1215 -506
- package/dist/agent-core/sdk/types.d.ts +3 -0
- package/dist/agent-core/session/context-gc-checkpoint.js +1 -1
- package/dist/agent-core/session/jsonl-store.d.ts +28 -8
- package/dist/agent-core/session/jsonl-store.js +124 -84
- package/dist/agent-core/session/types.d.ts +4 -1
- package/dist/agent-core/storage/file-lock.d.ts +4 -0
- package/dist/agent-core/storage/file-lock.js +83 -0
- package/dist/agent-core/subagent/contracts.d.ts +11 -1
- package/dist/agent-core/subagent/scheduler.d.ts +8 -0
- package/dist/agent-core/subagent/session-controller.d.ts +22 -1
- package/dist/agent-core/subagent/session-controller.js +355 -98
- package/dist/agent-core/tools/agent/agent-start.d.ts +1 -1
- package/dist/agent-core/tools/code-mode/cells.js +5 -15
- package/dist/agent-core/tools/code-mode/dispatch.d.ts +1 -0
- package/dist/agent-core/tools/code-mode/dispatch.js +13 -1
- package/dist/agent-core/tools/code-mode/index.js +1 -2
- package/dist/agent-core/tools/code-mode/observations.d.ts +5 -0
- package/dist/agent-core/tools/code-mode/observations.js +16 -5
- package/dist/agent-core/tools/code-mode/quickjs-engine.js +10 -5
- package/dist/agent-core/tools/execution.d.ts +11 -2
- package/dist/agent-core/tools/execution.js +58 -21
- package/dist/agent-core/tools/input.d.ts +2 -0
- package/dist/agent-core/tools/input.js +36 -0
- package/dist/agent-core/tools/local/apply-patch.js +21 -17
- package/dist/agent-core/tools/local/exec.d.ts +4 -4
- package/dist/agent-core/tools/local/exec.js +234 -62
- package/dist/agent-core/tools/local/registry.d.ts +6 -0
- package/dist/agent-core/tools/local/registry.js +60 -9
- package/dist/agent-core/tools/local/view-image.js +108 -2
- package/dist/agent-core/tools/mcp/catalog.d.ts +6 -2
- package/dist/agent-core/tools/mcp/catalog.js +4 -4
- package/dist/agent-core/tools/mcp/history.js +2 -2
- package/dist/agent-core/tools/mcp/tool-search.d.ts +3 -1
- package/dist/agent-core/tools/mcp/tool-search.js +2 -2
- package/dist/agent-core/tools/output-projection.d.ts +3 -1
- package/dist/agent-core/tools/output-projection.js +11 -2
- package/dist/agent-core/tools/runtime-context.d.ts +1 -0
- package/dist/agent-core/tools/runtime.d.ts +3 -1
- package/dist/agent-core/tools/runtime.js +22 -7
- package/dist/agent-core/tools/scheduler.d.ts +2 -0
- package/dist/agent-core/tools/scheduler.js +43 -6
- package/dist/index.d.ts +21 -0
- package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +5 -2
- package/package.json +1 -1
|
@@ -10,12 +10,22 @@ import { createSubagentBackend } from './subagent-backend.js';
|
|
|
10
10
|
import { discoveredMcpToolNames, rebindMcpToolSearchOutputs } from '../tools/mcp/history.js';
|
|
11
11
|
import { currentExecutionImages } from '../tools/output-projection.js';
|
|
12
12
|
import { createHash, randomUUID } from 'node:crypto';
|
|
13
|
+
import { ExecutionToolSources } from './extension-tools.js';
|
|
14
|
+
import { ExtensionRequestBridge, ExtensionRequestSnapshots } from '../extensions/model-request.js';
|
|
15
|
+
import { normalizeSessionMessagesInput, sessionMessagesPage } from '../extensions/session-messages.js';
|
|
16
|
+
import { transformCoreModelStream } from '../extensions/model-stream.js';
|
|
17
|
+
import { SessionInputCoordinator, recordSessionInputCommit } from '../extensions/session-input.js';
|
|
18
|
+
import { createExtensionSessionBackend } from './extension-session.js';
|
|
19
|
+
import { invokeCorePromptSubmission } from '../extensions/prompt-input.js';
|
|
20
|
+
import { createExtensionAgentsBackend } from './extension-agents.js';
|
|
21
|
+
import { coreMcpCatalog } from '../extensions/mcp.js';
|
|
13
22
|
import { isDeepStrictEqual } from 'node:util';
|
|
14
23
|
import { MarAgentError, describeMarAgentError } from '../error.js';
|
|
15
24
|
import { usesResponsesConfigurationUpdates } from '../model/configuration.js';
|
|
16
25
|
import { buildEnvironmentContext } from '../prompts/core.js';
|
|
17
26
|
import { executionBudgetEnvironmentEntry } from '../prompts/execution-budget.js';
|
|
18
|
-
import { MAR_AGENT_PROMPT_VERSION,
|
|
27
|
+
import { MAR_AGENT_PROMPT_VERSION, buildSystemPromptSections } from '../prompts/index.js';
|
|
28
|
+
import { renderPromptSections } from '../extensions/prompt-composition.js';
|
|
19
29
|
import { retainedSessionResourcesSnapshot } from '../prompts/resources.js';
|
|
20
30
|
import { childSubagentInstruction } from '../prompts/subagent.js';
|
|
21
31
|
import { AsyncQueue } from '../runtime/async-queue.js';
|
|
@@ -82,6 +92,32 @@ export function createSessionOpener(services) {
|
|
|
82
92
|
delete sessionRuntime.subagentsOpening;
|
|
83
93
|
}
|
|
84
94
|
}
|
|
95
|
+
const buildSessionPromptSections = (availableTools, promptMode, selectedModel, executionSystemInstruction, skillCatalog) => buildSystemPromptSections({
|
|
96
|
+
mode: promptMode,
|
|
97
|
+
platform: description.platform,
|
|
98
|
+
...(description.architecture ? { architecture: description.architecture } : {}),
|
|
99
|
+
...(description.shell ? { shell: description.shell } : {}),
|
|
100
|
+
...(description.guaranteedCommands
|
|
101
|
+
? { guaranteedCommands: description.guaranteedCommands }
|
|
102
|
+
: {}),
|
|
103
|
+
workspace: logicalWorkspace,
|
|
104
|
+
tools: availableTools
|
|
105
|
+
.filter((tool) => !tool.name.startsWith('mcp__'))
|
|
106
|
+
.map((tool) => tool.name),
|
|
107
|
+
directTools: availableTools
|
|
108
|
+
.filter((tool) => !tool.name.startsWith('mcp__') &&
|
|
109
|
+
allowsDirectTool(tool, availableTools.some((candidate) => candidate.name === 'code_exec')))
|
|
110
|
+
.map((tool) => tool.name),
|
|
111
|
+
highDensityCompaction: selectedModel.highDensityCompaction,
|
|
112
|
+
extension: [
|
|
113
|
+
executionSystemInstruction,
|
|
114
|
+
skillCatalog,
|
|
115
|
+
sessionSource.type === 'subagent' ? childSubagentInstruction : undefined
|
|
116
|
+
]
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
.join('\n\n')
|
|
119
|
+
});
|
|
120
|
+
let promptDefaults;
|
|
85
121
|
const sessionAdapter = (modelId, configuredModels) => {
|
|
86
122
|
let selected = sessionRuntime.adapters.get(modelId);
|
|
87
123
|
if (selected === undefined) {
|
|
@@ -99,27 +135,133 @@ export function createSessionOpener(services) {
|
|
|
99
135
|
sessionRuntime.adapters.clear();
|
|
100
136
|
sessionRuntime.adapterGeneration = generation;
|
|
101
137
|
};
|
|
138
|
+
const sessionInputs = () => (sessionRuntime.inputs ??= new SessionInputCoordinator((receipt) => services.extensions.session(sessionId)?.diagnose({
|
|
139
|
+
code: receipt.errorCode ?? 'MAR_AGENT_SESSION_INPUT_FAILED',
|
|
140
|
+
operationId: receipt.operationId,
|
|
141
|
+
sessionId
|
|
142
|
+
})));
|
|
143
|
+
// Only physical record commits and projection replacement enter this lane, never Hooks.
|
|
144
|
+
const withRecordProjection = async (action) => {
|
|
145
|
+
const pending = (sessionRuntime.recordProjection ?? Promise.resolve())
|
|
146
|
+
.catch(() => undefined)
|
|
147
|
+
.then(action);
|
|
148
|
+
sessionRuntime.recordProjection = pending;
|
|
149
|
+
try {
|
|
150
|
+
return await pending;
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
if (sessionRuntime.recordProjection === pending)
|
|
154
|
+
delete sessionRuntime.recordProjection;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const appendExtensionMessage = async (entry, request, call) => {
|
|
158
|
+
call.signal.throwIfAborted();
|
|
159
|
+
const release = await store.acquireSessionWriteLease(sessionId, sessionWriterOwner);
|
|
160
|
+
try {
|
|
161
|
+
return await withRecordProjection(async () => {
|
|
162
|
+
call.signal.throwIfAborted();
|
|
163
|
+
const message = projectAppendedModelMessage(request.input);
|
|
164
|
+
const record = await store.append(sessionId, {
|
|
165
|
+
type: message ? 'model.context' : 'session.notice',
|
|
166
|
+
payload: {
|
|
167
|
+
...(message ?? {
|
|
168
|
+
content: request.input.content,
|
|
169
|
+
textBlocks: request.input.textBlocks
|
|
170
|
+
}),
|
|
171
|
+
source: extensionInputSource(call, request.input.attribution)
|
|
172
|
+
},
|
|
173
|
+
...(call.executionId ? { executionId: call.executionId } : {}),
|
|
174
|
+
...(call.turnId ? { turnId: call.turnId } : {})
|
|
175
|
+
}, { signal: call.signal });
|
|
176
|
+
const result = {
|
|
177
|
+
changed: true,
|
|
178
|
+
modelChanged: !!message,
|
|
179
|
+
recordId: record.recordId,
|
|
180
|
+
...(call.executionId ? { executionId: call.executionId } : {})
|
|
181
|
+
};
|
|
182
|
+
recordSessionInputCommit(entry, result);
|
|
183
|
+
if (message)
|
|
184
|
+
sessionRuntime.appendedMessages?.append(record.recordId, message);
|
|
185
|
+
return result;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
await release();
|
|
190
|
+
}
|
|
191
|
+
};
|
|
102
192
|
const execution = (mode, input, internal = {}) => {
|
|
103
193
|
services.assertCanStart();
|
|
104
194
|
if ([...active.keys()].some((key) => key.startsWith(`${sessionId}:`)))
|
|
105
195
|
throw new MarAgentError('MAR_AGENT_EXECUTION_ACTIVE', 'Session already has an active execution.');
|
|
106
196
|
const executionId = randomUUID(), turnId = internal.turnId ?? randomUUID(), queue = new AsyncQueue(), controller = new AbortController();
|
|
197
|
+
const abortSource = () => controller.abort(internal.signal?.reason);
|
|
198
|
+
internal.signal?.addEventListener('abort', abortSource, { once: true });
|
|
199
|
+
if (internal.signal?.aborted)
|
|
200
|
+
abortSource();
|
|
107
201
|
let executionEnvironment = {
|
|
108
202
|
...currentEnvironment,
|
|
109
203
|
...currentLocalTimeContext()
|
|
110
204
|
};
|
|
111
205
|
const { models: executionModels, defaultModelId: executionDefaultModelId, generation: executionModelGeneration } = services.modelState();
|
|
112
206
|
const executionSystemInstruction = settings.systemInstruction;
|
|
207
|
+
promptDefaults = {
|
|
208
|
+
executionId,
|
|
209
|
+
modelId: input.modelId ?? executionDefaultModelId,
|
|
210
|
+
mode: mode === 'compact' ? 'run' : mode,
|
|
211
|
+
models: executionModels,
|
|
212
|
+
instruction: executionSystemInstruction
|
|
213
|
+
};
|
|
113
214
|
const manualCompactionId = mode === 'compact' ? randomUUID() : undefined;
|
|
114
215
|
active.set(`${sessionId}:${executionId}`, controller);
|
|
115
|
-
const
|
|
216
|
+
const inputs = sessionInputs();
|
|
217
|
+
const acceptParent = (message) => {
|
|
218
|
+
const origin = message.delivery?.origin;
|
|
219
|
+
const signal = AbortSignal.any([
|
|
220
|
+
controller.signal,
|
|
221
|
+
...(message.delivery?.signal === undefined ? [] : [message.delivery.signal])
|
|
222
|
+
]);
|
|
223
|
+
if (signal.aborted) {
|
|
224
|
+
message.delivery?.settled?.('cancelled');
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const accept = (call) => {
|
|
228
|
+
const entry = inputs.accept({ kind: 'submit', input: { text: message.text } }, call, (request, call, leaf) => leaf(request, call), 'accepted', message);
|
|
229
|
+
void entry.terminal.then(() => {
|
|
230
|
+
if (entry.receipt.status === 'cancelled' || entry.receipt.status === 'failed')
|
|
231
|
+
message.delivery?.settled?.(entry.receipt.status);
|
|
232
|
+
});
|
|
233
|
+
};
|
|
234
|
+
if (origin) {
|
|
235
|
+
accept(Object.freeze({
|
|
236
|
+
...origin,
|
|
237
|
+
sessionId,
|
|
238
|
+
sessionEpoch: services.extensions.session(sessionId)?.epoch ?? 0,
|
|
239
|
+
signal,
|
|
240
|
+
executionId,
|
|
241
|
+
turnId
|
|
242
|
+
}));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
services.extensions.operations.enter({
|
|
246
|
+
sessionId,
|
|
247
|
+
sessionEpoch: services.extensions.session(sessionId)?.epoch ?? 0,
|
|
248
|
+
actor: 'sdk',
|
|
249
|
+
entry: 'native-api',
|
|
250
|
+
signal,
|
|
251
|
+
executionId,
|
|
252
|
+
turnId
|
|
253
|
+
}, accept);
|
|
254
|
+
};
|
|
255
|
+
for (const message of internal.initialMailbox ?? [])
|
|
256
|
+
acceptParent(message);
|
|
116
257
|
let acceptsMailbox = sessionSource.type === 'subagent' && mode !== 'compact';
|
|
117
258
|
let sequence = 0;
|
|
118
259
|
let manualCompactionStarted = false;
|
|
119
260
|
let emitTail = Promise.resolve();
|
|
120
261
|
let exhaustedModelAttempt;
|
|
121
262
|
// Serialize durable events before either the local stream or Host observes them.
|
|
122
|
-
const emit = (event) => {
|
|
263
|
+
const emit = (event, assertLive) => {
|
|
264
|
+
assertLive?.();
|
|
123
265
|
const full = {
|
|
124
266
|
...event,
|
|
125
267
|
eventId: randomUUID(),
|
|
@@ -130,7 +272,7 @@ export function createSessionOpener(services) {
|
|
|
130
272
|
turnId
|
|
131
273
|
};
|
|
132
274
|
const operation = emitTail.then(async () => {
|
|
133
|
-
|
|
275
|
+
assertLive?.();
|
|
134
276
|
const persistent = eventForPersistence(full);
|
|
135
277
|
if (persistent !== undefined)
|
|
136
278
|
await store.append(sessionId, {
|
|
@@ -170,7 +312,7 @@ export function createSessionOpener(services) {
|
|
|
170
312
|
emitTail = operation.catch(() => undefined);
|
|
171
313
|
return operation;
|
|
172
314
|
};
|
|
173
|
-
const createCompactionOperation = (compactionId) => new CompactionOperation(
|
|
315
|
+
const createCompactionOperation = (compactionId, signal = controller.signal) => new CompactionOperation(signal, (progress) => {
|
|
174
316
|
const operation = emitTail.then(async () => {
|
|
175
317
|
await store.append(sessionId, {
|
|
176
318
|
type: 'compact.progress',
|
|
@@ -190,13 +332,30 @@ export function createSessionOpener(services) {
|
|
|
190
332
|
(rolloutBudgetOptions ? new RolloutBudget(rolloutBudgetOptions) : undefined);
|
|
191
333
|
const ownsRolloutBudget = rolloutBudget !== undefined && internal.sharedRolloutBudget === undefined;
|
|
192
334
|
let releaseSession;
|
|
335
|
+
let executionToolSources;
|
|
193
336
|
let selectedTurn;
|
|
194
337
|
const contextGc = new ContextGcRuntime();
|
|
195
338
|
let selectedAdapter;
|
|
196
339
|
const executionScopedAdapters = new Set();
|
|
197
340
|
const subagents = sessionSource.type === 'user' ? sessionRuntime.subagents : undefined;
|
|
198
341
|
try {
|
|
342
|
+
controller.signal.throwIfAborted();
|
|
199
343
|
releaseSession = await store.acquireSessionLease(sessionId, sessionWriterOwner);
|
|
344
|
+
if (!inputs.executing)
|
|
345
|
+
await inputs.idle();
|
|
346
|
+
let immediateTarget;
|
|
347
|
+
const pendingAppends = [];
|
|
348
|
+
sessionRuntime.appendedMessages = {
|
|
349
|
+
executionId,
|
|
350
|
+
append(recordId, message) {
|
|
351
|
+
pendingAppends.push({
|
|
352
|
+
recordId,
|
|
353
|
+
message
|
|
354
|
+
});
|
|
355
|
+
if (immediateTarget)
|
|
356
|
+
immediateTarget.push(message);
|
|
357
|
+
}
|
|
358
|
+
};
|
|
200
359
|
await refreshSessionAdapters(executionModelGeneration);
|
|
201
360
|
const sessionState = await store.readExecutionState(sessionId);
|
|
202
361
|
if (!store.hasRetainedSessionLease(sessionId, sessionWriterOwner))
|
|
@@ -231,6 +390,12 @@ export function createSessionOpener(services) {
|
|
|
231
390
|
includeImages: mode !== 'compact'
|
|
232
391
|
});
|
|
233
392
|
const messages = restored.messages;
|
|
393
|
+
const restoredRecordIds = new Set(contextRecords.map((record) => record.recordId));
|
|
394
|
+
for (const pending of pendingAppends)
|
|
395
|
+
if (!restoredRecordIds.has(pending.recordId))
|
|
396
|
+
messages.push(pending.message);
|
|
397
|
+
pendingAppends.length = 0;
|
|
398
|
+
immediateTarget = messages;
|
|
234
399
|
let recordedEnvironment = restored.environmentState;
|
|
235
400
|
let projectedExecutionBudgetStage;
|
|
236
401
|
const appendExecutionBudgetEnvironment = () => {
|
|
@@ -249,28 +414,86 @@ export function createSessionOpener(services) {
|
|
|
249
414
|
const entry = executionBudgetEnvironmentEntry(currentStage === 'normal' ? 'inactive' : currentStage);
|
|
250
415
|
messages.push(environmentContextUpdate(executionEnvironment, executionEnvironment, [entry]));
|
|
251
416
|
};
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
417
|
+
let compactContext;
|
|
418
|
+
const writeInputRecord = async (content, type, metadata, call, committed) => {
|
|
419
|
+
call.signal.throwIfAborted();
|
|
420
|
+
if (content.images?.length && !selectedModel.inputCapabilities.includes('IMAGE'))
|
|
421
|
+
throw new MarAgentError('MAR_AGENT_INPUT_CAPABILITY_UNSUPPORTED', 'Selected model does not support image input.');
|
|
422
|
+
await withRecordProjection(async () => {
|
|
423
|
+
call.signal.throwIfAborted();
|
|
424
|
+
const images = content.images?.length
|
|
425
|
+
? await store.persistInputImages(sessionId, content.images)
|
|
426
|
+
: [];
|
|
427
|
+
const record = await store.append(sessionId, {
|
|
428
|
+
type,
|
|
429
|
+
payload: {
|
|
430
|
+
...metadata,
|
|
431
|
+
prompt: content.text,
|
|
432
|
+
...(content.modelText === undefined ? {} : { modelText: content.modelText }),
|
|
433
|
+
...(content.context === undefined ? {} : { context: content.context }),
|
|
434
|
+
...(content.modelContext === undefined
|
|
435
|
+
? {}
|
|
436
|
+
: { modelContext: content.modelContext }),
|
|
437
|
+
...(images.length ? { images } : {})
|
|
438
|
+
},
|
|
439
|
+
executionId,
|
|
440
|
+
turnId
|
|
441
|
+
}, { signal: call.signal });
|
|
442
|
+
committed(content, record.recordId);
|
|
443
|
+
for (const text of content.modelContext ?? content.context ?? [])
|
|
444
|
+
messages.push({ role: 'user', content: text });
|
|
445
|
+
});
|
|
273
446
|
};
|
|
447
|
+
const appendMailboxMessages = async () => inputs.drain(async (entry, request, call) => {
|
|
448
|
+
call.signal.throwIfAborted();
|
|
449
|
+
if (request.kind === 'compact')
|
|
450
|
+
return { changed: await compactContext(request.input), executionId };
|
|
451
|
+
if (request.kind === 'append') {
|
|
452
|
+
const result = await appendExtensionMessage(entry, request, call);
|
|
453
|
+
return { ...result, executionId };
|
|
454
|
+
}
|
|
455
|
+
const parent = entry.parentMessage;
|
|
456
|
+
let outcome;
|
|
457
|
+
const content = {
|
|
458
|
+
text: request.input.text,
|
|
459
|
+
...(request.input.modelText === undefined
|
|
460
|
+
? {}
|
|
461
|
+
: { modelText: request.input.modelText }),
|
|
462
|
+
...(request.input.context === undefined
|
|
463
|
+
? {}
|
|
464
|
+
: { context: request.input.context }),
|
|
465
|
+
...(request.input.modelContext === undefined
|
|
466
|
+
? {}
|
|
467
|
+
: { modelContext: request.input.modelContext }),
|
|
468
|
+
...(request.input.images === undefined ? {} : { images: request.input.images })
|
|
469
|
+
};
|
|
470
|
+
await writeInputRecord(content, parent && !parent.delivery?.origin ? 'turn.user' : 'extension.input', parent && !parent.delivery?.origin
|
|
471
|
+
? {
|
|
472
|
+
inputSource: 'parent_agent',
|
|
473
|
+
...(parent.delivery ? { messageId: parent.delivery.messageId } : {})
|
|
474
|
+
}
|
|
475
|
+
: {
|
|
476
|
+
source: extensionInputSource(call, request.input.provenance, request.input.modelAttribution),
|
|
477
|
+
...(parent?.delivery ? { messageId: parent.delivery.messageId } : {})
|
|
478
|
+
}, call, (actual, recordId) => {
|
|
479
|
+
outcome = { changed: true, executionId, recordId };
|
|
480
|
+
recordSessionInputCommit(entry, outcome);
|
|
481
|
+
messages.push({
|
|
482
|
+
role: 'user',
|
|
483
|
+
content: actual.modelText ?? actual.text,
|
|
484
|
+
...(actual.images?.length
|
|
485
|
+
? {
|
|
486
|
+
images: actual.images.map(({ mimeType, dataBase64 }) => ({
|
|
487
|
+
mimeType,
|
|
488
|
+
dataBase64
|
|
489
|
+
}))
|
|
490
|
+
}
|
|
491
|
+
: {})
|
|
492
|
+
});
|
|
493
|
+
parent?.delivery?.applied();
|
|
494
|
+
});
|
|
495
|
+
return outcome;
|
|
496
|
+
}, { executionId, turnId, signal: controller.signal });
|
|
274
497
|
const recordEnvironment = async () => {
|
|
275
498
|
const message = environmentContextUpdate(executionEnvironment, recordedEnvironment);
|
|
276
499
|
if (!message)
|
|
@@ -284,44 +507,11 @@ export function createSessionOpener(services) {
|
|
|
284
507
|
messages.push(message);
|
|
285
508
|
recordedEnvironment = executionEnvironment;
|
|
286
509
|
};
|
|
287
|
-
let compactionUserMessages = [
|
|
288
|
-
...restored.userMessages,
|
|
289
|
-
...(mode === 'compact' ? [] : [input.prompt])
|
|
290
|
-
];
|
|
510
|
+
let compactionUserMessages = [...restored.userMessages];
|
|
291
511
|
const hasRestoredUserImages = messages.some((message) => message.role === 'user' && Boolean(message.images?.length));
|
|
292
|
-
|
|
293
|
-
? undefined
|
|
294
|
-
: input.images?.map(({ mimeType, dataBase64 }) => ({
|
|
295
|
-
mimeType,
|
|
296
|
-
dataBase64
|
|
297
|
-
}));
|
|
512
|
+
let modelInputImages;
|
|
298
513
|
const currentExecutionToolImages = [];
|
|
299
514
|
let currentExecutionUserIndex;
|
|
300
|
-
if (mode !== 'compact') {
|
|
301
|
-
await recordEnvironment();
|
|
302
|
-
const inputImageMetadata = input.images?.length
|
|
303
|
-
? await store.persistInputImages(sessionId, input.images)
|
|
304
|
-
: [];
|
|
305
|
-
// A failed sync can still leave a complete record; lease recovery decides image ownership.
|
|
306
|
-
await store.append(sessionId, {
|
|
307
|
-
type: 'turn.user',
|
|
308
|
-
payload: {
|
|
309
|
-
prompt: input.prompt,
|
|
310
|
-
...(internal.delivery ? { messageId: internal.delivery.messageId } : {}),
|
|
311
|
-
...(internal.inputSource === undefined
|
|
312
|
-
? {}
|
|
313
|
-
: { inputSource: internal.inputSource }),
|
|
314
|
-
...(input.clientMessageId ? { clientMessageId: input.clientMessageId } : {}),
|
|
315
|
-
...(inputImageMetadata.length ? { images: inputImageMetadata } : {})
|
|
316
|
-
},
|
|
317
|
-
executionId,
|
|
318
|
-
turnId
|
|
319
|
-
});
|
|
320
|
-
messages.push({ role: 'user', content: input.prompt });
|
|
321
|
-
currentExecutionUserIndex = messages.length - 1;
|
|
322
|
-
internal.delivery?.applied();
|
|
323
|
-
await appendMailboxMessages();
|
|
324
|
-
}
|
|
325
515
|
await emit({ type: 'execution.started', mode });
|
|
326
516
|
if (restored.ignoredImages > 0)
|
|
327
517
|
await store.append(sessionId, {
|
|
@@ -357,25 +547,6 @@ export function createSessionOpener(services) {
|
|
|
357
547
|
? requestReasoningEffort
|
|
358
548
|
: (lastConfigurationEffort(messages, selectedModel.id) ?? requestReasoningEffort)
|
|
359
549
|
: undefined;
|
|
360
|
-
if (mode !== 'compact' &&
|
|
361
|
-
useEffortUpdates &&
|
|
362
|
-
effectiveReasoningEffort !== reasoningEffort) {
|
|
363
|
-
const update = {
|
|
364
|
-
role: 'provider',
|
|
365
|
-
content: '',
|
|
366
|
-
provider: 'OPENAI_RESPONSES',
|
|
367
|
-
providerModelId: selectedModel.id,
|
|
368
|
-
item: { type: 'configuration_update', reasoning: { effort: reasoningEffort } }
|
|
369
|
-
};
|
|
370
|
-
messages.push(update);
|
|
371
|
-
await store.append(sessionId, {
|
|
372
|
-
type: 'model.context',
|
|
373
|
-
payload: update,
|
|
374
|
-
executionId,
|
|
375
|
-
turnId
|
|
376
|
-
});
|
|
377
|
-
effectiveReasoningEffort = reasoningEffort;
|
|
378
|
-
}
|
|
379
550
|
if (mode !== 'compact' && subagents)
|
|
380
551
|
await subagents.beginParentExecution({
|
|
381
552
|
executionId,
|
|
@@ -410,16 +581,13 @@ export function createSessionOpener(services) {
|
|
|
410
581
|
role: turn.role,
|
|
411
582
|
initialMailbox: turn.initialMailbox,
|
|
412
583
|
turnId: turn.turnId,
|
|
584
|
+
...(turn.origin === undefined ? {} : { origin: turn.origin }),
|
|
413
585
|
mcpExecutionScopeId: executionId,
|
|
414
586
|
...(turn.delivery ? { delivery: turn.delivery } : {}),
|
|
415
587
|
...(rolloutBudget === undefined ? {} : { sharedRolloutBudget: rolloutBudget })
|
|
416
588
|
});
|
|
417
589
|
}
|
|
418
590
|
});
|
|
419
|
-
if (mode !== 'compact' &&
|
|
420
|
-
(input.images?.length || hasRestoredUserImages) &&
|
|
421
|
-
!selectedModel.inputCapabilities.includes('IMAGE'))
|
|
422
|
-
throw new MarAgentError('MAR_AGENT_INPUT_CAPABILITY_UNSUPPORTED', 'Selected model does not support image input.');
|
|
423
591
|
const catalogContext = {
|
|
424
592
|
sessionId,
|
|
425
593
|
executionId,
|
|
@@ -470,6 +638,49 @@ export function createSessionOpener(services) {
|
|
|
470
638
|
const combinedTools = [...builtinTools, ...(extensions.tools ?? []), ...mcpTools];
|
|
471
639
|
if (new Set(combinedTools.map((tool) => tool.name)).size !== combinedTools.length)
|
|
472
640
|
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Tool names conflict.');
|
|
641
|
+
const executionSourceNames = new Set(combinedTools.map((tool) => tool.name));
|
|
642
|
+
const supplementalBindings = services.extensions.options
|
|
643
|
+
.baseTools?.(sessionId, { executionId })
|
|
644
|
+
?.filter((binding) => !executionSourceNames.has(binding.definition.name)) ?? [];
|
|
645
|
+
const sources = (executionToolSources = new ExecutionToolSources(executionId, sessionId, combinedTools, builtinTools, mcpCatalog, supplementalBindings));
|
|
646
|
+
const sourceBindings = sources.bindings;
|
|
647
|
+
const coreExtensions = await services.extensions.prepare(sessionId, controller.signal, sourceBindings, sessionSource.type === 'user' &&
|
|
648
|
+
(mode === 'run' || mode === 'plan') &&
|
|
649
|
+
!internal.automaticInput);
|
|
650
|
+
sessionRuntime.toolSources = sources;
|
|
651
|
+
const operation = (run) => services.extensions.operations.run({
|
|
652
|
+
sessionId,
|
|
653
|
+
sessionEpoch: coreExtensions.epoch,
|
|
654
|
+
executionId,
|
|
655
|
+
turnId,
|
|
656
|
+
actor: 'sdk',
|
|
657
|
+
entry: 'native-api',
|
|
658
|
+
signal: controller.signal
|
|
659
|
+
}, run);
|
|
660
|
+
await operation((call) => coreExtensions.ready(call));
|
|
661
|
+
const captureTools = () => operation((call) => {
|
|
662
|
+
return coreExtensions.capture(call, false, sourceBindings.filter((binding) => !supplementalBindings.includes(binding) || binding.available?.(call) !== false));
|
|
663
|
+
});
|
|
664
|
+
const streamModel = (start, signal = controller.signal) => transformCoreModelStream(start, signal, (event, signal) => operation((call) => coreExtensions.modelEvent(event, Object.freeze({ ...call, signal }))), () => coreExtensions.diagnose({
|
|
665
|
+
code: 'MAR_AGENT_MODEL_STREAM_CLEANUP_FAILED',
|
|
666
|
+
sessionId
|
|
667
|
+
}));
|
|
668
|
+
const transformModelRequest = async (candidate, bindings = captureTools(), modelId = selectedModel.id) => {
|
|
669
|
+
let lowered = candidate;
|
|
670
|
+
if (coreExtensions.hooks.hasInterceptors('model.request')) {
|
|
671
|
+
const bridge = new ExtensionRequestBridge(modelId, candidate);
|
|
672
|
+
const request = await operation((call) => coreExtensions.hooks.invoke('model.request', bridge.view, call, async (view) => view));
|
|
673
|
+
lowered = bridge.lower(request);
|
|
674
|
+
}
|
|
675
|
+
for (const definition of lowered.tools) {
|
|
676
|
+
const binding = bindings.get(definition.name);
|
|
677
|
+
const { description: _description, ...contract } = definition;
|
|
678
|
+
const { description: _capturedDescription, ...capturedContract } = binding?.definition ?? {};
|
|
679
|
+
if (!binding || !isDeepStrictEqual(contract, capturedContract))
|
|
680
|
+
throw new MarAgentError('MAR_AGENT_EXTENSION_MODEL_REQUEST_INVALID', 'Request tools do not match captured sources.');
|
|
681
|
+
}
|
|
682
|
+
return lowered;
|
|
683
|
+
};
|
|
473
684
|
const toolEligible = (tool) => {
|
|
474
685
|
toolCallers(tool);
|
|
475
686
|
if (sessionSource.type === 'subagent' && tool.agentScope === 'ROOT_ONLY')
|
|
@@ -486,9 +697,12 @@ export function createSessionOpener(services) {
|
|
|
486
697
|
: tool.name !== 'view_image' ||
|
|
487
698
|
selectedModelForTools.inputCapabilities.includes('IMAGE');
|
|
488
699
|
};
|
|
489
|
-
mcpRegistry.update(mcpCatalog, (tool) => toolEligible(tool.definition));
|
|
700
|
+
const updateMcpRegistry = () => mcpRegistry.update(coreMcpCatalog([...mcpCatalog.servers, ...coreExtensions.mcp.servers()], captureTools()), (tool) => toolEligible(tool.definition), { nativeToolNames: true });
|
|
701
|
+
updateMcpRegistry();
|
|
490
702
|
rebindMcpToolSearchOutputs(messages, mcpRegistry);
|
|
491
|
-
const availableTools =
|
|
703
|
+
const availableTools = [...captureTools().values()]
|
|
704
|
+
.map((binding) => binding.definition)
|
|
705
|
+
.filter(toolEligible);
|
|
492
706
|
const instructionContext = await loadAgentInstructions({
|
|
493
707
|
home: description.homeDirectory,
|
|
494
708
|
workspace: instructionWorkspace,
|
|
@@ -500,14 +714,11 @@ export function createSessionOpener(services) {
|
|
|
500
714
|
});
|
|
501
715
|
const instructionEntries = instructionContext?.entries ?? [];
|
|
502
716
|
const currentInstructionSnapshot = renderAgentInstructions(instructionEntries, false);
|
|
503
|
-
let agentInstructionInsertIndex = mode === 'compact'
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
messages[agentInstructionInsertIndex - 1]?.contextKind === 'environment')
|
|
509
|
-
agentInstructionInsertIndex--;
|
|
510
|
-
const baseTools = () => [...builtinTools, ...(extensions.tools ?? [])].filter((tool) => toolEligible(tool) &&
|
|
717
|
+
let agentInstructionInsertIndex = mode === 'compact' ? contextualInstructionInsertIndex(messages) : messages.length;
|
|
718
|
+
const baseTools = () => [...captureTools().values()]
|
|
719
|
+
.filter((binding) => binding.mcp === undefined)
|
|
720
|
+
.map((binding) => binding.definition)
|
|
721
|
+
.filter((tool) => toolEligible(tool) &&
|
|
511
722
|
(tool.name !== 'skill' || (instructionContext?.skills.size ?? 0) > 0));
|
|
512
723
|
let executionTools = mcpRegistry.project(baseTools());
|
|
513
724
|
const restoreMcpDiscovery = () => {
|
|
@@ -547,30 +758,15 @@ export function createSessionOpener(services) {
|
|
|
547
758
|
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
548
759
|
if (!isDeepStrictEqual(previousContextualWorldState, contextualWorldState))
|
|
549
760
|
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
:
|
|
558
|
-
|
|
559
|
-
tools: availableTools
|
|
560
|
-
.filter((tool) => !tool.name.startsWith('mcp__'))
|
|
561
|
-
.map((tool) => tool.name),
|
|
562
|
-
directTools: availableTools
|
|
563
|
-
.filter((tool) => !tool.name.startsWith('mcp__') &&
|
|
564
|
-
allowsDirectTool(tool, availableTools.some((candidate) => candidate.name === 'code_exec')))
|
|
565
|
-
.map((tool) => tool.name),
|
|
566
|
-
highDensityCompaction: selectedModel.highDensityCompaction,
|
|
567
|
-
extension: [
|
|
568
|
-
executionSystemInstruction,
|
|
569
|
-
instructionContext?.skillCatalog,
|
|
570
|
-
sessionSource.type === 'subagent' ? childSubagentInstruction : undefined
|
|
571
|
-
]
|
|
572
|
-
.filter(Boolean)
|
|
573
|
-
.join('\n\n')
|
|
761
|
+
const buildExecutionPromptSections = (availableTools = executionTools, promptMode = mode) => buildSessionPromptSections(availableTools, promptMode, selectedModel, executionSystemInstruction, instructionContext?.skillCatalog);
|
|
762
|
+
const buildExecutionSystemPrompt = (availableTools = executionTools, promptMode = mode) => renderPromptSections(buildExecutionPromptSections(availableTools, promptMode));
|
|
763
|
+
const promptComposition = (availableTools, promptMode) => ({
|
|
764
|
+
sections: buildExecutionPromptSections(availableTools, promptMode),
|
|
765
|
+
facts: {
|
|
766
|
+
modelId: selectedModel.id,
|
|
767
|
+
mode: promptMode,
|
|
768
|
+
tools: availableTools.map((tool) => tool.name)
|
|
769
|
+
}
|
|
574
770
|
});
|
|
575
771
|
const syncMcpWorldState = async (index) => {
|
|
576
772
|
const snapshot = mcpRegistry.navigation();
|
|
@@ -593,302 +789,487 @@ export function createSessionOpener(services) {
|
|
|
593
789
|
};
|
|
594
790
|
if (mode !== 'compact')
|
|
595
791
|
await syncMcpWorldState(agentInstructionInsertIndex);
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const compactSystemPrompt = initialSystemPrompt;
|
|
602
|
-
const compactHistory = [...messages];
|
|
603
|
-
const projectedHistory = normalizeMessagesForModel(insertContextualWorldState(compactHistory, contextualWorldState.entries), { supportsImages: false });
|
|
604
|
-
const nativeMessages = buildNativeCompactionMessages(projectedHistory, {
|
|
605
|
-
focus: input.prompt,
|
|
606
|
-
highDensityCompaction: selectedModel.highDensityCompaction
|
|
607
|
-
});
|
|
608
|
-
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages('', selectedModel.highDensityCompaction), executionTools);
|
|
609
|
-
const compactInputTokens = selectedModel.contextWindowTokens - compactOverheadTokens;
|
|
610
|
-
if (compactInputTokens <= 0)
|
|
611
|
-
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Compaction prompt exceeds the selected model context window.');
|
|
612
|
-
const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
|
|
613
|
-
focus: input.prompt,
|
|
614
|
-
maxTokens: compactInputTokens
|
|
615
|
-
}), selectedModel.highDensityCompaction);
|
|
616
|
-
const useNative = shouldUseNativeCompaction({
|
|
617
|
-
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeMessages, executionTools),
|
|
618
|
-
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
619
|
-
latestUsage: lastServerUsage,
|
|
620
|
-
historyMessages: compactHistory,
|
|
621
|
-
appendedMessages: nativeMessages.slice(projectedHistory.length)
|
|
622
|
-
});
|
|
623
|
-
messages.splice(0, messages.length, ...(useNative ? nativeMessages : fallbackMessages()));
|
|
624
|
-
if (useNative) {
|
|
625
|
-
let available = true;
|
|
626
|
-
useManualCompactionFallback = () => {
|
|
627
|
-
if (!available)
|
|
628
|
-
return false;
|
|
629
|
-
available = false;
|
|
630
|
-
messages.splice(0, messages.length, ...fallbackMessages());
|
|
631
|
-
return true;
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
await store.append(sessionId, {
|
|
636
|
-
type: 'execution.header',
|
|
637
|
-
payload: {
|
|
638
|
-
promptVersion: MAR_AGENT_PROMPT_VERSION,
|
|
639
|
-
promptHash: createHash('sha256').update(initialSystemPrompt).digest('hex'),
|
|
640
|
-
modelId: selectedModel.id,
|
|
641
|
-
modelName: selectedModel.name,
|
|
642
|
-
reasoningEffort,
|
|
643
|
-
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
644
|
-
mode
|
|
645
|
-
},
|
|
646
|
-
executionId,
|
|
647
|
-
turnId
|
|
792
|
+
const writeCompactionRecord = async (summary, _automatic, signal, write) => withRecordProjection(async () => {
|
|
793
|
+
signal.throwIfAborted();
|
|
794
|
+
const stored = await write(summary, { signal });
|
|
795
|
+
inputs.recordCompactCommit({ changed: true, recordId: stored.recordId, executionId });
|
|
796
|
+
return stored;
|
|
648
797
|
});
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
798
|
+
const performCompact = (input, leaf) => operation((call) => inputs.performCompact(input, call, (commit) => coreExtensions.hooks.invoke('session.compact', input, call, async (input, effective) => {
|
|
799
|
+
effective.signal.throwIfAborted();
|
|
800
|
+
if (input.focus !== undefined && typeof input.focus !== 'string')
|
|
801
|
+
throw new MarAgentError('MAR_AGENT_SESSION_INPUT_INVALID', 'Compaction focus is invalid.');
|
|
802
|
+
const outcome = await leaf(input, effective);
|
|
803
|
+
commit(outcome);
|
|
804
|
+
return outcome;
|
|
805
|
+
})));
|
|
806
|
+
const captureRoundToolScope = () => {
|
|
807
|
+
const roundTools = executionTools;
|
|
808
|
+
const availableBindings = captureTools();
|
|
809
|
+
const roundBindings = new Map(roundTools.map((tool) => [tool.name, availableBindings.get(tool.name)]));
|
|
810
|
+
const defaultComposition = promptComposition(roundTools, mode === 'compact' ? 'run' : mode);
|
|
811
|
+
const defaultSystemPrompt = renderPromptSections(defaultComposition.sections);
|
|
812
|
+
let systemPrompt = defaultSystemPrompt;
|
|
813
|
+
const roundMcpExpectations = new Map(roundTools
|
|
814
|
+
.filter((tool) => roundBindings.get(tool.name)?.mcp !== undefined)
|
|
815
|
+
.map((tool) => [tool.name, mcpRegistry.expectedTool(tool.name)]));
|
|
816
|
+
const parentFrame = subagents === undefined || mode === 'compact'
|
|
817
|
+
? undefined
|
|
818
|
+
: subagents.captureParentFrame(executionId);
|
|
819
|
+
const toolContext = {
|
|
820
|
+
host: host,
|
|
821
|
+
todo,
|
|
822
|
+
...(subagents === undefined || mode === 'compact'
|
|
823
|
+
? {}
|
|
824
|
+
: {
|
|
825
|
+
subagents: coreExtensions.bindAgents(subagents.captureExecution(executionId))
|
|
826
|
+
}),
|
|
827
|
+
mode,
|
|
828
|
+
sessionId,
|
|
829
|
+
executionId,
|
|
830
|
+
modelId: selectedModel.id,
|
|
831
|
+
signal: controller.signal,
|
|
832
|
+
emit,
|
|
833
|
+
skills: instructionContext?.skills ?? new Map(),
|
|
834
|
+
invokeTool: (call, context, caller) => {
|
|
835
|
+
const invoke = () => coreExtensions.withTools(roundBindings, sessionRuntime.scheduleTool, () => services.extensions.operations.enter({
|
|
836
|
+
sessionId,
|
|
837
|
+
sessionEpoch: coreExtensions.epoch,
|
|
838
|
+
executionId,
|
|
839
|
+
turnId,
|
|
840
|
+
actor: caller === 'programmatic' ? 'code-mode' : 'model',
|
|
841
|
+
entry: caller,
|
|
842
|
+
signal: context.signal
|
|
843
|
+
}, (operation) => coreExtensions.invoke(call, operation, roundBindings)));
|
|
844
|
+
return sources.withFrame(context, () => parentFrame === undefined ? invoke() : parentFrame(invoke));
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
const recentImages = () => currentExecutionImages(modelInputImages, currentExecutionToolImages);
|
|
848
|
+
const toolScope = {
|
|
849
|
+
context: toolContext,
|
|
850
|
+
tools: roundTools,
|
|
851
|
+
expectations: roundMcpExpectations,
|
|
852
|
+
extensionToolNames: new Set([...roundBindings.values()]
|
|
853
|
+
.filter((binding) => binding.source.kind === 'host' || binding.source.kind === 'extension')
|
|
854
|
+
.map((binding) => binding.definition.name)),
|
|
855
|
+
schedule: sessionRuntime.scheduleTool,
|
|
856
|
+
assertLive: () => coreExtensions.assertLive(),
|
|
857
|
+
assertExecutionLive: () => sources.assertActive(),
|
|
858
|
+
emit: (event, assertLive) => emit(event, () => {
|
|
859
|
+
coreExtensions.assertLive();
|
|
860
|
+
assertLive?.();
|
|
861
|
+
}),
|
|
862
|
+
searchMcpTools: (arguments_, searchSignal) => mcpRegistry.expose(arguments_, {
|
|
863
|
+
signal: searchSignal,
|
|
864
|
+
base: baseTools(),
|
|
865
|
+
window: selectedModel.contextWindowTokens,
|
|
866
|
+
system: systemPrompt
|
|
867
|
+
}),
|
|
868
|
+
recentImages,
|
|
869
|
+
captureCodeContext: () => ({
|
|
870
|
+
...toolContext,
|
|
871
|
+
recentImages: recentImages()
|
|
872
|
+
}),
|
|
873
|
+
codeModeContext: async (call) => {
|
|
874
|
+
const stateSnapshot = call.name === 'code_exec' ? await store.readCodeModeState(sessionId) : [];
|
|
875
|
+
return {
|
|
876
|
+
retainSession: async () => {
|
|
877
|
+
coreExtensions.assertLive();
|
|
878
|
+
const release = await store.retainSessionLease(sessionId, sessionWriterOwner);
|
|
879
|
+
let unpin;
|
|
880
|
+
try {
|
|
881
|
+
unpin = coreExtensions.pin();
|
|
703
882
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
883
|
+
catch (error) {
|
|
884
|
+
try {
|
|
885
|
+
await release();
|
|
886
|
+
}
|
|
887
|
+
catch {
|
|
888
|
+
coreExtensions.diagnose({
|
|
889
|
+
code: 'MAR_AGENT_EXTENSION_CLEANUP_FAILED',
|
|
890
|
+
sessionId
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
throw error;
|
|
894
|
+
}
|
|
895
|
+
return async () => {
|
|
896
|
+
try {
|
|
897
|
+
await release();
|
|
898
|
+
}
|
|
899
|
+
finally {
|
|
900
|
+
unpin();
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
},
|
|
904
|
+
onSettled: async (result) => {
|
|
905
|
+
await store.append(sessionId, {
|
|
906
|
+
type: 'code.cell.completed',
|
|
907
|
+
payload: { ...result, callId: call.callId },
|
|
908
|
+
executionId,
|
|
909
|
+
turnId
|
|
910
|
+
});
|
|
911
|
+
},
|
|
912
|
+
supportsImages: selectedModel.inputCapabilities.includes('IMAGE'),
|
|
913
|
+
tools: roundTools.filter((tool) => allowsToolCaller(tool, 'programmatic')),
|
|
914
|
+
state: stateSnapshot,
|
|
915
|
+
commitState: (mutations) => store.commitCodeModeState(sessionId, mutations, {
|
|
916
|
+
executionId,
|
|
917
|
+
turnId,
|
|
918
|
+
expectedState: stateSnapshot
|
|
919
|
+
})
|
|
920
|
+
};
|
|
723
921
|
}
|
|
922
|
+
};
|
|
923
|
+
return {
|
|
924
|
+
roundTools,
|
|
925
|
+
roundBindings,
|
|
926
|
+
toolScope,
|
|
927
|
+
async composeSystemPrompt() {
|
|
928
|
+
const composed = await operation((call) => coreExtensions.composeModelSystem(defaultComposition, call));
|
|
929
|
+
systemPrompt = composed.text;
|
|
930
|
+
return composed;
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
};
|
|
934
|
+
sources.bind(captureRoundToolScope().toolScope);
|
|
935
|
+
sessionRuntime.requestMessages = {
|
|
936
|
+
executionId,
|
|
937
|
+
read: () => projectSessionRequestMessages(messages.map((message, index) => index === currentExecutionUserIndex && modelInputImages?.length
|
|
938
|
+
? { ...message, images: modelInputImages }
|
|
939
|
+
: message), mode === 'compact' ? [] : contextualWorldState.entries, mode !== 'compact' && selectedModel.inputCapabilities.includes('IMAGE'), baseTools().some((tool) => tool.name === 'code_exec'))
|
|
940
|
+
};
|
|
941
|
+
if (mode !== 'compact') {
|
|
942
|
+
let entered = false;
|
|
943
|
+
const writeInput = async (content, call) => {
|
|
944
|
+
call.signal.throwIfAborted();
|
|
945
|
+
if ((content.images?.length || hasRestoredUserImages) &&
|
|
946
|
+
!selectedModel.inputCapabilities.includes('IMAGE'))
|
|
947
|
+
throw new MarAgentError('MAR_AGENT_INPUT_CAPABILITY_UNSUPPORTED', 'Selected model does not support image input.');
|
|
948
|
+
if (entered) {
|
|
949
|
+
await sessionRuntime.sessionBackend.enqueue({ kind: 'submit', input: { ...content, delivery: 'idle' } }, call, (request, effective, next) => next(request, effective));
|
|
950
|
+
return {};
|
|
951
|
+
}
|
|
952
|
+
await recordEnvironment();
|
|
953
|
+
call.signal.throwIfAborted();
|
|
954
|
+
await writeInputRecord(content, internal.inputSource === 'extension' ? 'extension.input' : 'turn.user', {
|
|
955
|
+
...(internal.extensionSource ? { source: internal.extensionSource } : {}),
|
|
956
|
+
...(internal.delivery ? { messageId: internal.delivery.messageId } : {}),
|
|
957
|
+
...(internal.inputSource === undefined
|
|
958
|
+
? {}
|
|
959
|
+
: { inputSource: internal.inputSource }),
|
|
960
|
+
...(input.clientMessageId ? { clientMessageId: input.clientMessageId } : {})
|
|
961
|
+
}, call, (actual, recordId) => {
|
|
962
|
+
entered = true;
|
|
963
|
+
compactionUserMessages.push(actual.text);
|
|
964
|
+
modelInputImages = actual.images?.map(({ mimeType, dataBase64 }) => ({
|
|
965
|
+
mimeType,
|
|
966
|
+
dataBase64
|
|
967
|
+
}));
|
|
968
|
+
messages.push({ role: 'user', content: actual.modelText ?? actual.text });
|
|
969
|
+
currentExecutionUserIndex = messages.length - 1;
|
|
970
|
+
internal.inputCommitted?.(recordId);
|
|
971
|
+
internal.delivery?.applied();
|
|
972
|
+
});
|
|
973
|
+
return {};
|
|
974
|
+
};
|
|
975
|
+
const content = {
|
|
976
|
+
text: input.prompt,
|
|
977
|
+
...(internal.modelText === undefined ? {} : { modelText: internal.modelText }),
|
|
978
|
+
...(internal.inputContext === undefined ? {} : { context: internal.inputContext }),
|
|
979
|
+
...(internal.modelContext === undefined
|
|
980
|
+
? {}
|
|
981
|
+
: { modelContext: internal.modelContext }),
|
|
982
|
+
...(input.images === undefined ? {} : { images: input.images })
|
|
983
|
+
};
|
|
984
|
+
await operation((call) => internal.promptAdmitted
|
|
985
|
+
? writeInput(content, call)
|
|
986
|
+
: invokeCorePromptSubmission(coreExtensions.hooks, content, call, writeInput));
|
|
987
|
+
if (!entered) {
|
|
988
|
+
await emit({ type: 'execution.completed' });
|
|
989
|
+
return { executionId, status: 'completed', finalAnswer: '', inputHandled: true };
|
|
724
990
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
991
|
+
}
|
|
992
|
+
if (mode !== 'compact' &&
|
|
993
|
+
useEffortUpdates &&
|
|
994
|
+
effectiveReasoningEffort !== reasoningEffort) {
|
|
995
|
+
const update = {
|
|
996
|
+
role: 'provider',
|
|
997
|
+
content: '',
|
|
998
|
+
provider: 'OPENAI_RESPONSES',
|
|
999
|
+
providerModelId: selectedModel.id,
|
|
1000
|
+
item: { type: 'configuration_update', reasoning: { effort: reasoningEffort } }
|
|
1001
|
+
};
|
|
1002
|
+
messages.push(update);
|
|
1003
|
+
await store.append(sessionId, {
|
|
1004
|
+
type: 'model.context',
|
|
1005
|
+
payload: update,
|
|
740
1006
|
executionId,
|
|
741
1007
|
turnId
|
|
742
1008
|
});
|
|
743
|
-
contextGc.reset();
|
|
744
|
-
messages.splice(0, messages.length, environmentContextUpdate(executionEnvironment), ...compactedHistoryMessages(replacementHistory));
|
|
745
|
-
restoreMcpDiscovery();
|
|
746
|
-
projectedExecutionBudgetStage = undefined;
|
|
747
|
-
recordedEnvironment = executionEnvironment;
|
|
748
|
-
compactionUserMessages = replacementHistory
|
|
749
|
-
.filter((message) => message.kind === 'user_input')
|
|
750
|
-
.map((message) => message.content);
|
|
751
|
-
agentInstructionInsertIndex = Math.max(0, messages.length - 1);
|
|
752
|
-
currentResourceSnapshot = retainedSessionResourcesSnapshot(await loadRetainedSessionResources());
|
|
753
|
-
contextualWorldState = resetContextualWorldState(compactRecord.recordId, agentInstructionInsertIndex, {
|
|
754
|
-
instructionSnapshot: currentInstructionSnapshot,
|
|
755
|
-
instructionContent: renderAgentInstructions(instructionEntries, true),
|
|
756
|
-
resourceSnapshot: currentResourceSnapshot,
|
|
757
|
-
previousMayContainResources: compactSummary.includes('# Retained Session resources')
|
|
758
|
-
});
|
|
759
|
-
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
760
|
-
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
761
|
-
lastServerContextTokens = undefined;
|
|
762
|
-
lastServerUsage = undefined;
|
|
763
|
-
requestReasoningEffort = reasoningEffort;
|
|
764
1009
|
effectiveReasoningEffort = reasoningEffort;
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
const
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
mode,
|
|
780
|
-
sourceType: sessionSource.type,
|
|
781
|
-
signal: controller.signal,
|
|
782
|
-
model: selectedModel,
|
|
783
|
-
messages,
|
|
784
|
-
toolImages: currentExecutionToolImages,
|
|
785
|
-
rolloutBudget,
|
|
786
|
-
publish: emit,
|
|
787
|
-
appendContext: async (message) => {
|
|
788
|
-
await store.append(sessionId, {
|
|
789
|
-
type: 'model.context',
|
|
790
|
-
payload: message,
|
|
791
|
-
executionId,
|
|
792
|
-
turnId
|
|
1010
|
+
}
|
|
1011
|
+
const runPreparedExecution = async (compactFocus = input.prompt, compactSignal = controller.signal) => {
|
|
1012
|
+
const initialSystemPrompt = mode === 'compact'
|
|
1013
|
+
? buildExecutionSystemPrompt(executionTools, 'run')
|
|
1014
|
+
: buildExecutionSystemPrompt();
|
|
1015
|
+
let useManualCompactionFallback;
|
|
1016
|
+
const manualAppendBoundary = pendingAppends.length;
|
|
1017
|
+
if (mode === 'compact') {
|
|
1018
|
+
const compactSystemPrompt = initialSystemPrompt;
|
|
1019
|
+
const compactHistory = [...messages];
|
|
1020
|
+
const projectedHistory = normalizeMessagesForModel(insertContextualWorldState(compactHistory, contextualWorldState.entries), { supportsImages: false });
|
|
1021
|
+
const nativeMessages = buildNativeCompactionMessages(projectedHistory, {
|
|
1022
|
+
focus: compactFocus,
|
|
1023
|
+
highDensityCompaction: selectedModel.highDensityCompaction
|
|
793
1024
|
});
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
1025
|
+
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages('', selectedModel.highDensityCompaction), executionTools);
|
|
1026
|
+
const compactInputTokens = selectedModel.contextWindowTokens - compactOverheadTokens;
|
|
1027
|
+
if (compactInputTokens <= 0)
|
|
1028
|
+
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Compaction prompt exceeds the selected model context window.');
|
|
1029
|
+
const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
|
|
1030
|
+
focus: compactFocus,
|
|
1031
|
+
maxTokens: compactInputTokens
|
|
1032
|
+
}), selectedModel.highDensityCompaction);
|
|
1033
|
+
const useNative = shouldUseNativeCompaction({
|
|
1034
|
+
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeMessages, executionTools),
|
|
1035
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1036
|
+
latestUsage: lastServerUsage,
|
|
1037
|
+
historyMessages: compactHistory,
|
|
1038
|
+
appendedMessages: nativeMessages.slice(projectedHistory.length)
|
|
1039
|
+
});
|
|
1040
|
+
messages.splice(0, messages.length, ...(useNative ? nativeMessages : fallbackMessages()));
|
|
1041
|
+
if (useNative) {
|
|
1042
|
+
let available = true;
|
|
1043
|
+
useManualCompactionFallback = () => {
|
|
1044
|
+
if (!available)
|
|
1045
|
+
return false;
|
|
1046
|
+
available = false;
|
|
1047
|
+
messages.splice(0, messages.length, ...fallbackMessages(), ...pendingAppends.slice(manualAppendBoundary).map((entry) => entry.message));
|
|
1048
|
+
return true;
|
|
1049
|
+
};
|
|
808
1050
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
const directNames = new Set(residentTools.map((tool) => tool.name));
|
|
816
|
-
// Discovery and caller policy are independent: keep nested declarations for active tools.
|
|
817
|
-
return projectCodeModeTools(roundTools, residentTools).filter((tool) => directNames.has(tool.name));
|
|
818
|
-
})();
|
|
819
|
-
const systemPrompt = mode === 'compact'
|
|
820
|
-
? buildExecutionSystemPrompt(roundTools, 'run')
|
|
821
|
-
: buildExecutionSystemPrompt(roundTools);
|
|
822
|
-
const requestContextMessages = pendingOutputContinuation === undefined
|
|
823
|
-
? messages
|
|
824
|
-
: [...messages, pendingOutputContinuation];
|
|
825
|
-
const modelMessages = mode === 'compact'
|
|
826
|
-
? normalizeMessagesForModel(requestContextMessages, { supportsImages: false })
|
|
827
|
-
: normalizeMessagesForModel(insertContextualWorldState(requestContextMessages, contextualWorldState.entries), {
|
|
828
|
-
supportsImages: selectedModel.inputCapabilities.includes('IMAGE')
|
|
829
|
-
});
|
|
830
|
-
const roundMcpExpectations = new Map(roundTools
|
|
831
|
-
.filter((tool) => tool.name.startsWith('mcp__'))
|
|
832
|
-
.map((tool) => [tool.name, mcpRegistry.expectedTool(tool.name)]));
|
|
833
|
-
const toolContext = {
|
|
834
|
-
host: host,
|
|
835
|
-
todo,
|
|
836
|
-
...(subagents === undefined ? {} : { subagents }),
|
|
837
|
-
mode,
|
|
838
|
-
sessionId,
|
|
839
|
-
executionId,
|
|
1051
|
+
}
|
|
1052
|
+
await store.append(sessionId, {
|
|
1053
|
+
type: 'execution.header',
|
|
1054
|
+
payload: {
|
|
1055
|
+
promptVersion: MAR_AGENT_PROMPT_VERSION,
|
|
1056
|
+
promptHash: createHash('sha256').update(initialSystemPrompt).digest('hex'),
|
|
840
1057
|
modelId: selectedModel.id,
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1058
|
+
modelName: selectedModel.name,
|
|
1059
|
+
reasoningEffort,
|
|
1060
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1061
|
+
mode
|
|
1062
|
+
},
|
|
1063
|
+
executionId,
|
|
1064
|
+
turnId
|
|
1065
|
+
});
|
|
1066
|
+
let lastServerContextTokens = lastServerUsage?.contextInputTokens;
|
|
1067
|
+
const compactLeaf = async (input = {}, signal = controller.signal) => {
|
|
1068
|
+
if (messages.length < 2)
|
|
1069
|
+
return false;
|
|
1070
|
+
let compactSummary = '';
|
|
1071
|
+
const current = messages.at(-1);
|
|
1072
|
+
const retainCurrent = current.role === 'user' && current.contextKind !== 'environment';
|
|
1073
|
+
const compactHistory = retainCurrent ? messages.slice(0, -1) : [...messages];
|
|
1074
|
+
const appendBoundary = pendingAppends.length;
|
|
1075
|
+
const compactSystemPrompt = await operation((call) => coreExtensions.compose(promptComposition(executionTools, 'run'), call));
|
|
1076
|
+
const projectedHistory = normalizeMessagesForModel(insertContextualWorldState(compactHistory, contextualWorldState.entries), { supportsImages: false });
|
|
1077
|
+
const nativeCompactMessages = buildNativeCompactionMessages(projectedHistory, {
|
|
1078
|
+
...(input.focus === undefined ? {} : { focus: input.focus }),
|
|
1079
|
+
highDensityCompaction: selectedModel.highDensityCompaction
|
|
1080
|
+
});
|
|
1081
|
+
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages('', selectedModel.highDensityCompaction), executionTools);
|
|
1082
|
+
const compactInputTokens = Math.max(0, selectedModel.contextWindowTokens - compactOverheadTokens);
|
|
1083
|
+
if (compactInputTokens === 0)
|
|
1084
|
+
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Compaction prompt exceeds the selected model context window.');
|
|
1085
|
+
let usingNativeMessages = shouldUseNativeCompaction({
|
|
1086
|
+
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeCompactMessages, executionTools),
|
|
1087
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1088
|
+
latestUsage: lastServerUsage,
|
|
1089
|
+
historyMessages: compactHistory,
|
|
1090
|
+
appendedMessages: nativeCompactMessages.slice(projectedHistory.length)
|
|
1091
|
+
});
|
|
1092
|
+
const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
|
|
1093
|
+
...(input.focus === undefined ? {} : { focus: input.focus }),
|
|
1094
|
+
maxTokens: Math.max(1, compactInputTokens)
|
|
1095
|
+
}), selectedModel.highDensityCompaction);
|
|
1096
|
+
let compactMessages = usingNativeMessages
|
|
1097
|
+
? nativeCompactMessages
|
|
1098
|
+
: fallbackMessages();
|
|
1099
|
+
const compactionId = randomUUID();
|
|
1100
|
+
await emit({ type: 'context.compacting', compactionId });
|
|
1101
|
+
let latestUsage;
|
|
1102
|
+
const compactionRetryState = { attempts: 0 };
|
|
1103
|
+
const compaction = createCompactionOperation(compactionId, signal);
|
|
1104
|
+
try {
|
|
1105
|
+
while (true) {
|
|
1106
|
+
compactSummary = '';
|
|
1107
|
+
latestUsage = undefined;
|
|
1108
|
+
try {
|
|
1109
|
+
const request = await transformModelRequest({
|
|
1110
|
+
retryState: compactionRetryState,
|
|
1111
|
+
system: compactSystemPrompt,
|
|
1112
|
+
messages: compactMessages,
|
|
1113
|
+
tools: executionTools,
|
|
1114
|
+
toolChoice: 'none',
|
|
1115
|
+
promptCacheKey: sessionId,
|
|
1116
|
+
reasoningEffort: requestReasoningEffort ?? reasoningEffort,
|
|
1117
|
+
onAttemptDiagnostic: recordModelAttempt('COMPACTION')
|
|
1118
|
+
});
|
|
1119
|
+
for await (const event of streamModel((signal) => compaction.start({ start: (request) => selected.start(request, signal) }, request), compaction.signal)) {
|
|
1120
|
+
if (event.type === 'text.completed' &&
|
|
1121
|
+
(event.phase ?? 'final_answer') === 'final_answer')
|
|
1122
|
+
compactSummary = event.text.trim();
|
|
1123
|
+
else if (event.type === 'usage') {
|
|
1124
|
+
latestUsage = event.usage;
|
|
1125
|
+
await emit({ type: 'usage.updated', ...publicModelUsage(event.usage) });
|
|
1126
|
+
}
|
|
1127
|
+
else if (event.type === 'client_tool.call')
|
|
1128
|
+
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Compaction returned a tool call while tools were disabled.');
|
|
1129
|
+
}
|
|
1130
|
+
break;
|
|
1131
|
+
}
|
|
1132
|
+
catch (error) {
|
|
1133
|
+
if (await recoverModelStream(error, compactionRetryState, compaction.signal)) {
|
|
1134
|
+
continue;
|
|
1135
|
+
}
|
|
1136
|
+
if (isProviderContextOverflow(error) && usingNativeMessages) {
|
|
1137
|
+
usingNativeMessages = false;
|
|
1138
|
+
compactMessages = fallbackMessages();
|
|
1139
|
+
compactionRetryState.attempts = 0;
|
|
1140
|
+
continue;
|
|
1141
|
+
}
|
|
1142
|
+
if (isProviderContextOverflow(error))
|
|
1143
|
+
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'The compaction request exceeds the model context window.', { cause: error });
|
|
1144
|
+
throw error;
|
|
1145
|
+
}
|
|
886
1146
|
}
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
|
|
1147
|
+
}
|
|
1148
|
+
finally {
|
|
1149
|
+
await compaction.dispose();
|
|
1150
|
+
}
|
|
1151
|
+
if (!compactSummary)
|
|
1152
|
+
throw new MarAgentError('MAR_AGENT_COMPACT_FAILED', 'Automatic compact failed.');
|
|
1153
|
+
rolloutBudget?.recordUsage(latestUsage);
|
|
1154
|
+
let replacementHistory = buildCompactedHistory(compactSummary, retainCurrent ? compactionUserMessages.slice(0, -1) : compactionUserMessages, compactUserTokenLimit, retainCurrent ? current.content : undefined);
|
|
1155
|
+
signal.throwIfAborted();
|
|
1156
|
+
const compactRecord = await writeCompactionRecord(compactSummary, true, signal, async (actual, options) => {
|
|
1157
|
+
compactSummary = actual;
|
|
1158
|
+
replacementHistory = buildCompactedHistory(actual, retainCurrent ? compactionUserMessages.slice(0, -1) : compactionUserMessages, compactUserTokenLimit, retainCurrent ? current.content : undefined);
|
|
1159
|
+
const retainedModelContext = pendingAppends
|
|
1160
|
+
.slice(appendBoundary)
|
|
1161
|
+
.map((entry) => entry.message);
|
|
1162
|
+
const record = await store.compact(sessionId, {
|
|
1163
|
+
summary: compactSummary,
|
|
1164
|
+
replacementHistory,
|
|
1165
|
+
retainedModelContext,
|
|
1166
|
+
automatic: true,
|
|
1167
|
+
environment: executionEnvironment,
|
|
1168
|
+
modelId: selectedModel.id,
|
|
1169
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1170
|
+
...(latestUsage === undefined ? {} : { usage: latestUsage }),
|
|
1171
|
+
executionId,
|
|
1172
|
+
turnId
|
|
1173
|
+
}, options);
|
|
1174
|
+
messages.splice(0, messages.length, environmentContextUpdate(executionEnvironment), ...compactedHistoryMessages(replacementHistory), ...retainedModelContext);
|
|
1175
|
+
pendingAppends.length = 0;
|
|
1176
|
+
return record;
|
|
1177
|
+
});
|
|
1178
|
+
contextGc.reset();
|
|
1179
|
+
restoreMcpDiscovery();
|
|
1180
|
+
projectedExecutionBudgetStage = undefined;
|
|
1181
|
+
recordedEnvironment = executionEnvironment;
|
|
1182
|
+
compactionUserMessages = replacementHistory
|
|
1183
|
+
.filter((message) => message.kind === 'user_input')
|
|
1184
|
+
.map((message) => message.content);
|
|
1185
|
+
agentInstructionInsertIndex = Math.max(0, messages.length - 1);
|
|
1186
|
+
currentResourceSnapshot = retainedSessionResourcesSnapshot(await loadRetainedSessionResources());
|
|
1187
|
+
contextualWorldState = resetContextualWorldState(compactRecord.recordId, agentInstructionInsertIndex, {
|
|
1188
|
+
instructionSnapshot: currentInstructionSnapshot,
|
|
1189
|
+
instructionContent: renderAgentInstructions(instructionEntries, true),
|
|
1190
|
+
resourceSnapshot: currentResourceSnapshot,
|
|
1191
|
+
previousMayContainResources: compactSummary.includes('# Retained Session resources')
|
|
1192
|
+
});
|
|
1193
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
1194
|
+
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
1195
|
+
lastServerContextTokens = undefined;
|
|
1196
|
+
lastServerUsage = undefined;
|
|
1197
|
+
requestReasoningEffort = reasoningEffort;
|
|
1198
|
+
effectiveReasoningEffort = reasoningEffort;
|
|
1199
|
+
await emit({ type: 'context.compacted', compactionId });
|
|
1200
|
+
return true;
|
|
1201
|
+
};
|
|
1202
|
+
compactContext = async (input = {}) => {
|
|
1203
|
+
sources.bind(captureRoundToolScope().toolScope);
|
|
1204
|
+
return (await performCompact(input, async (effective, call) => ({
|
|
1205
|
+
changed: await compactLeaf(effective, call.signal),
|
|
1206
|
+
executionId
|
|
1207
|
+
}))).changed;
|
|
1208
|
+
};
|
|
1209
|
+
const ensureContextBudget = async () => {
|
|
1210
|
+
if (mode === 'compact' || lastServerContextTokens === undefined)
|
|
1211
|
+
return;
|
|
1212
|
+
const hardLimit = selectedModel.contextWindowTokens;
|
|
1213
|
+
const compactLimit = Math.floor((hardLimit * AGENT_EXECUTION_POLICY.automaticCompactionPercent) / 100);
|
|
1214
|
+
if (lastServerContextTokens < compactLimit)
|
|
1215
|
+
return;
|
|
1216
|
+
if (!(await compactContext()))
|
|
1217
|
+
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Provider usage reached the compaction threshold but no history can be compacted.');
|
|
1218
|
+
};
|
|
1219
|
+
executionLoop = new ExecutionLoop({
|
|
1220
|
+
mode,
|
|
1221
|
+
sourceType: sessionSource.type,
|
|
1222
|
+
signal: controller.signal,
|
|
1223
|
+
model: selectedModel,
|
|
1224
|
+
messages,
|
|
1225
|
+
toolImages: currentExecutionToolImages,
|
|
1226
|
+
rolloutBudget,
|
|
1227
|
+
publish: emit,
|
|
1228
|
+
appendContext: (message) => withRecordProjection(async () => {
|
|
1229
|
+
await store.append(sessionId, {
|
|
1230
|
+
type: 'model.context',
|
|
1231
|
+
payload: message,
|
|
1232
|
+
executionId,
|
|
1233
|
+
turnId
|
|
1234
|
+
});
|
|
1235
|
+
}),
|
|
1236
|
+
prepareRound: async (pendingOutputContinuation) => {
|
|
1237
|
+
if (mode !== 'compact')
|
|
1238
|
+
await appendMailboxMessages();
|
|
1239
|
+
appendExecutionBudgetEnvironment();
|
|
1240
|
+
updateMcpRegistry();
|
|
1241
|
+
executionTools = mcpRegistry.project(baseTools());
|
|
1242
|
+
if (mode !== 'compact')
|
|
1243
|
+
await syncMcpWorldState(messages.length);
|
|
1244
|
+
await ensureContextBudget();
|
|
1245
|
+
if (mode !== 'compact')
|
|
1246
|
+
await syncMcpWorldState(messages.length);
|
|
1247
|
+
appendExecutionBudgetEnvironment();
|
|
1248
|
+
if (mode !== 'compact') {
|
|
1249
|
+
executionEnvironment = { ...currentEnvironment, ...currentLocalTimeContext() };
|
|
1250
|
+
await recordEnvironment();
|
|
1251
|
+
}
|
|
1252
|
+
const { roundTools, roundBindings, toolScope, composeSystemPrompt } = captureRoundToolScope();
|
|
1253
|
+
const codeModeEnabled = roundTools.some((tool) => tool.name === 'code_exec');
|
|
1254
|
+
const residentTools = mcpRegistry.projectDirect(baseTools());
|
|
1255
|
+
const requestTools = (() => {
|
|
1256
|
+
if (selectedModel.protocol !== 'OPENAI_RESPONSES')
|
|
1257
|
+
return projectCodeModeTools(roundTools, residentTools);
|
|
1258
|
+
const directNames = new Set(residentTools.map((tool) => tool.name));
|
|
1259
|
+
// Discovery and caller policy are independent: keep nested declarations for active tools.
|
|
1260
|
+
return projectCodeModeTools(roundTools, residentTools).filter((tool) => directNames.has(tool.name));
|
|
1261
|
+
})();
|
|
1262
|
+
const requestContextMessages = pendingOutputContinuation === undefined
|
|
1263
|
+
? messages
|
|
1264
|
+
: [...messages, pendingOutputContinuation];
|
|
1265
|
+
const modelMessages = projectSessionRequestMessages(requestContextMessages, mode === 'compact' ? [] : contextualWorldState.entries, mode !== 'compact' && selectedModel.inputCapabilities.includes('IMAGE'), codeModeEnabled);
|
|
1266
|
+
sources.bind(toolScope);
|
|
1267
|
+
const composedSystem = await composeSystemPrompt();
|
|
1268
|
+
const systemPrompt = composedSystem.text;
|
|
1269
|
+
const candidateRequest = {
|
|
890
1270
|
system: systemPrompt,
|
|
891
|
-
|
|
1271
|
+
...(composedSystem.blocks ? { systemBlocks: composedSystem.blocks } : {}),
|
|
1272
|
+
messages: modelMessages,
|
|
892
1273
|
tools: requestTools,
|
|
893
1274
|
...(mode === 'compact' ? { toolChoice: 'none' } : {}),
|
|
894
1275
|
promptCacheKey: sessionId,
|
|
@@ -896,114 +1277,152 @@ export function createSessionOpener(services) {
|
|
|
896
1277
|
...(requestReasoningEffort === undefined ? {} : { requestReasoningEffort }),
|
|
897
1278
|
...(modelInputImages?.length ? { images: modelInputImages } : {}),
|
|
898
1279
|
onAttemptDiagnostic: recordModelAttempt(mode === 'compact' ? 'COMPACTION' : 'EXECUTION')
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
},
|
|
925
|
-
checkpoint: async (round, latestUsage) => {
|
|
926
|
-
if (mode !== 'compact' &&
|
|
927
|
-
sessionSource.type !== 'subagent' &&
|
|
928
|
-
latestUsage !== undefined) {
|
|
929
|
-
// Only a committed GC checkpoint may replace active context and invalidate continuation.
|
|
930
|
-
const committed = await contextGc.run({
|
|
931
|
-
store,
|
|
932
|
-
sessionId,
|
|
933
|
-
system: round.request.system,
|
|
934
|
-
tools: round.toolScope.tools,
|
|
935
|
-
modelId: selectedModel.id,
|
|
936
|
-
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
937
|
-
usage: latestUsage,
|
|
938
|
-
modelProtocol: selectedModel.protocol,
|
|
939
|
-
responsesConfigurationUpdates: usesResponsesConfigurationUpdates(selectedModel),
|
|
940
|
-
workspace: logicalWorkspace,
|
|
941
|
-
platform: description.platform,
|
|
942
|
-
getActiveProcessIds: async () => {
|
|
943
|
-
const resources = await host
|
|
944
|
-
.listSessionResources?.(sessionId)
|
|
945
|
-
.catch(() => undefined);
|
|
946
|
-
return new Set((resources?.processes ?? [])
|
|
947
|
-
.filter((process) => process.status === 'running')
|
|
948
|
-
.map((process) => process.processId));
|
|
1280
|
+
};
|
|
1281
|
+
return {
|
|
1282
|
+
request: await transformModelRequest(candidateRequest, roundBindings),
|
|
1283
|
+
toolScope
|
|
1284
|
+
};
|
|
1285
|
+
},
|
|
1286
|
+
startModel: async function* (request) {
|
|
1287
|
+
const snapshots = mode === 'compact'
|
|
1288
|
+
? undefined
|
|
1289
|
+
: (sessionRuntime.requestSnapshots ??= new ExtensionRequestSnapshots());
|
|
1290
|
+
const snapshot = snapshots?.record(selectedModel.id, request);
|
|
1291
|
+
if (manualCompactionId !== undefined && !manualCompactionStarted) {
|
|
1292
|
+
manualCompactionStarted = true;
|
|
1293
|
+
manualCompaction = createCompactionOperation(manualCompactionId, compactSignal);
|
|
1294
|
+
await emit({ type: 'context.compacting', compactionId: manualCompactionId });
|
|
1295
|
+
}
|
|
1296
|
+
const compaction = manualCompaction;
|
|
1297
|
+
yield* streamModel(async function* (nativeSignal) {
|
|
1298
|
+
const events = compaction
|
|
1299
|
+
? compaction.start({ start: (value) => selected.start(value, nativeSignal) }, request)
|
|
1300
|
+
: selected.start(request, nativeSignal);
|
|
1301
|
+
for await (const event of events) {
|
|
1302
|
+
if (snapshot && event.type === 'completed' && event.reason !== 'cancelled')
|
|
1303
|
+
snapshots.complete(snapshot);
|
|
1304
|
+
yield event;
|
|
949
1305
|
}
|
|
950
|
-
});
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1306
|
+
}, compaction?.signal ?? controller.signal);
|
|
1307
|
+
},
|
|
1308
|
+
recoverySignal: () => manualCompaction?.signal ?? controller.signal,
|
|
1309
|
+
compactContext,
|
|
1310
|
+
compactionFallback: useManualCompactionFallback,
|
|
1311
|
+
observeContextTokens: (tokens) => {
|
|
1312
|
+
lastServerContextTokens = tokens;
|
|
1313
|
+
},
|
|
1314
|
+
observeUsage: (usage) => {
|
|
1315
|
+
if (usage !== undefined) {
|
|
1316
|
+
lastServerContextTokens = usage.contextInputTokens;
|
|
1317
|
+
lastServerUsage = { ...usage, historyMessages: [...messages] };
|
|
1318
|
+
}
|
|
1319
|
+
},
|
|
1320
|
+
checkpoint: async (round, latestUsage) => {
|
|
1321
|
+
if (mode !== 'compact' &&
|
|
1322
|
+
sessionSource.type !== 'subagent' &&
|
|
1323
|
+
latestUsage !== undefined) {
|
|
1324
|
+
// Only a committed GC checkpoint may replace active context and invalidate continuation.
|
|
1325
|
+
const appendBoundary = pendingAppends.length;
|
|
1326
|
+
const committed = await contextGc.run({
|
|
1327
|
+
store,
|
|
1328
|
+
sessionId,
|
|
1329
|
+
system: round.request.system,
|
|
1330
|
+
tools: round.toolScope.tools,
|
|
1331
|
+
modelId: selectedModel.id,
|
|
1332
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1333
|
+
usage: latestUsage,
|
|
1334
|
+
modelProtocol: selectedModel.protocol,
|
|
1335
|
+
responsesConfigurationUpdates: usesResponsesConfigurationUpdates(selectedModel),
|
|
1336
|
+
workspace: logicalWorkspace,
|
|
1337
|
+
platform: description.platform,
|
|
1338
|
+
getActiveProcessIds: async () => {
|
|
1339
|
+
const resources = await host
|
|
1340
|
+
.listSessionResources?.(sessionId)
|
|
1341
|
+
.catch(() => undefined);
|
|
1342
|
+
return new Set((resources?.processes ?? [])
|
|
1343
|
+
.filter((process) => process.status === 'running')
|
|
1344
|
+
.map((process) => process.processId));
|
|
1345
|
+
}
|
|
974
1346
|
});
|
|
975
|
-
|
|
976
|
-
|
|
1347
|
+
if (committed) {
|
|
1348
|
+
selected.resetContinuation?.();
|
|
1349
|
+
const refreshed = await restoreMessages(store, sessionId, committed.records, {
|
|
1350
|
+
includeImages: true,
|
|
1351
|
+
currentTurnId: turnId,
|
|
1352
|
+
projection: committed.projection
|
|
1353
|
+
});
|
|
1354
|
+
const restoredIds = new Set(committed.records.map((record) => record.recordId));
|
|
1355
|
+
const lateMessages = pendingAppends
|
|
1356
|
+
.slice(appendBoundary)
|
|
1357
|
+
.filter((entry) => !restoredIds.has(entry.recordId))
|
|
1358
|
+
.map((entry) => entry.message);
|
|
1359
|
+
messages.splice(0, messages.length, ...refreshed.messages, ...lateMessages);
|
|
1360
|
+
restoreMcpDiscovery();
|
|
1361
|
+
projectedExecutionBudgetStage = undefined;
|
|
1362
|
+
recordedEnvironment = refreshed.environmentState;
|
|
1363
|
+
compactionUserMessages = [...refreshed.userMessages];
|
|
1364
|
+
agentInstructionInsertIndex =
|
|
1365
|
+
refreshed.currentTurnUserIndex ?? Math.max(0, messages.length - 1);
|
|
1366
|
+
if (agentInstructionInsertIndex &&
|
|
1367
|
+
messages[agentInstructionInsertIndex - 1]?.contextKind === 'environment')
|
|
1368
|
+
agentInstructionInsertIndex--;
|
|
1369
|
+
currentResourceSnapshot = retainedSessionResourcesSnapshot(await loadRetainedSessionResources());
|
|
1370
|
+
contextualWorldState = resetContextualWorldState(latestContextualWorldStateGeneration(committed.records), agentInstructionInsertIndex, {
|
|
1371
|
+
instructionSnapshot: currentInstructionSnapshot,
|
|
1372
|
+
instructionContent: renderAgentInstructions(instructionEntries, committed.records.some((record) => compactSummaryFromCheckpoint(record) !== undefined)),
|
|
1373
|
+
resourceSnapshot: currentResourceSnapshot,
|
|
1374
|
+
previousMayContainResources: compactHistoryMayContainRetainedResources(committed.records)
|
|
1375
|
+
});
|
|
1376
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
1377
|
+
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
},
|
|
1381
|
+
mailbox: {
|
|
1382
|
+
hasPending: () => inputs.hasBoundaryPending && !inputs.executing && mode !== 'compact',
|
|
1383
|
+
append: appendMailboxMessages,
|
|
1384
|
+
close: () => {
|
|
1385
|
+
acceptsMailbox = false;
|
|
977
1386
|
}
|
|
978
1387
|
}
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1388
|
+
});
|
|
1389
|
+
const completed = await executionLoop.run();
|
|
1390
|
+
finalAnswer = completed.finalAnswer;
|
|
1391
|
+
const compactSummary = mode === 'compact' ? finalAnswer.trim() : '';
|
|
1392
|
+
if (manualCompaction) {
|
|
1393
|
+
manualCompaction.signal.throwIfAborted();
|
|
1394
|
+
await manualCompaction.dispose();
|
|
986
1395
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1396
|
+
if (mode === 'compact')
|
|
1397
|
+
await writeCompactionRecord(compactSummary, false, compactSignal, async (actual, options) => {
|
|
1398
|
+
const retainedModelContext = pendingAppends
|
|
1399
|
+
.slice(manualAppendBoundary)
|
|
1400
|
+
.map((entry) => entry.message);
|
|
1401
|
+
const replacementHistory = buildCompactedHistory(actual, compactionUserMessages, compactUserTokenLimit);
|
|
1402
|
+
const record = await store.compact(sessionId, {
|
|
1403
|
+
summary: actual,
|
|
1404
|
+
retainedModelContext,
|
|
1405
|
+
replacementHistory,
|
|
1406
|
+
modelId: selectedModel.id,
|
|
1407
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1408
|
+
...(completed.usage === undefined ? {} : { usage: completed.usage }),
|
|
1409
|
+
executionId,
|
|
1410
|
+
turnId
|
|
1411
|
+
}, options);
|
|
1412
|
+
messages.splice(0, messages.length, ...compactedHistoryMessages(replacementHistory), ...retainedModelContext);
|
|
1413
|
+
pendingAppends.length = 0;
|
|
1414
|
+
return record;
|
|
1415
|
+
});
|
|
1416
|
+
if (mode === 'compact' && manualCompactionId !== undefined)
|
|
1417
|
+
await emit({ type: 'context.compacted', compactionId: manualCompactionId });
|
|
1418
|
+
};
|
|
995
1419
|
if (mode === 'compact')
|
|
996
|
-
await
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
modelId: selectedModel.id,
|
|
1000
|
-
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1001
|
-
...(completed.usage === undefined ? {} : { usage: completed.usage }),
|
|
1002
|
-
executionId,
|
|
1003
|
-
turnId
|
|
1420
|
+
await performCompact({ focus: input.prompt }, async (effective, call) => {
|
|
1421
|
+
await runPreparedExecution(effective.focus ?? DEFAULT_COMPACTION_FOCUS, call.signal);
|
|
1422
|
+
return { changed: true, executionId };
|
|
1004
1423
|
});
|
|
1005
|
-
|
|
1006
|
-
await
|
|
1424
|
+
else
|
|
1425
|
+
await runPreparedExecution();
|
|
1007
1426
|
subagents?.endParentExecution(executionId);
|
|
1008
1427
|
await emit({ type: 'execution.completed' });
|
|
1009
1428
|
return {
|
|
@@ -1036,7 +1455,17 @@ export function createSessionOpener(services) {
|
|
|
1036
1455
|
};
|
|
1037
1456
|
}
|
|
1038
1457
|
finally {
|
|
1458
|
+
if (sessionRuntime.requestMessages?.executionId === executionId)
|
|
1459
|
+
delete sessionRuntime.requestMessages;
|
|
1460
|
+
if (sessionRuntime.appendedMessages?.executionId === executionId)
|
|
1461
|
+
delete sessionRuntime.appendedMessages;
|
|
1462
|
+
if (promptDefaults?.executionId === executionId)
|
|
1463
|
+
promptDefaults = undefined;
|
|
1039
1464
|
acceptsMailbox = false;
|
|
1465
|
+
executionToolSources?.close();
|
|
1466
|
+
if (sessionRuntime.toolSources === executionToolSources)
|
|
1467
|
+
delete sessionRuntime.toolSources;
|
|
1468
|
+
internal.signal?.removeEventListener('abort', abortSource);
|
|
1040
1469
|
if (ownsRolloutBudget)
|
|
1041
1470
|
rolloutBudget.discard();
|
|
1042
1471
|
await manualCompaction?.dispose();
|
|
@@ -1054,12 +1483,19 @@ export function createSessionOpener(services) {
|
|
|
1054
1483
|
subagents?.endParentExecution(executionId);
|
|
1055
1484
|
await releaseSession?.();
|
|
1056
1485
|
active.delete(`${sessionId}:${executionId}`);
|
|
1486
|
+
sessionRuntime.sessionBackend?.kick();
|
|
1057
1487
|
queue.close();
|
|
1058
1488
|
}
|
|
1059
1489
|
})();
|
|
1060
1490
|
const executionKey = `${sessionId}:${executionId}`;
|
|
1061
1491
|
executionResults.set(executionKey, result);
|
|
1062
|
-
void result.then(() =>
|
|
1492
|
+
void result.then((outcome) => {
|
|
1493
|
+
inputs.settleExecution(executionId, outcome.status);
|
|
1494
|
+
executionResults.delete(executionKey);
|
|
1495
|
+
}, () => {
|
|
1496
|
+
inputs.settleExecution(executionId, 'failed');
|
|
1497
|
+
executionResults.delete(executionKey);
|
|
1498
|
+
});
|
|
1063
1499
|
return {
|
|
1064
1500
|
executionId,
|
|
1065
1501
|
turnId,
|
|
@@ -1072,11 +1508,251 @@ export function createSessionOpener(services) {
|
|
|
1072
1508
|
enqueueMessage: (message, delivery) => {
|
|
1073
1509
|
if (!acceptsMailbox || controller.signal.aborted)
|
|
1074
1510
|
return false;
|
|
1075
|
-
|
|
1511
|
+
acceptParent({ text: message, ...(delivery ? { delivery } : {}) });
|
|
1076
1512
|
return true;
|
|
1077
1513
|
}
|
|
1078
1514
|
};
|
|
1079
1515
|
};
|
|
1516
|
+
sessionRuntime.sessionBackend ??= createExtensionSessionBackend({
|
|
1517
|
+
describe: async (call) => {
|
|
1518
|
+
call.signal.throwIfAborted();
|
|
1519
|
+
const current = await store.getSession(sessionId);
|
|
1520
|
+
const records = await store.read(sessionId);
|
|
1521
|
+
call.signal.throwIfAborted();
|
|
1522
|
+
const state = promptDefaults ?? services.modelState();
|
|
1523
|
+
const modelId = promptDefaults?.modelId ?? services.modelState().defaultModelId;
|
|
1524
|
+
const model = state.models.get(modelId);
|
|
1525
|
+
if (!model)
|
|
1526
|
+
throw new MarAgentError('MAR_AGENT_MODEL_DISABLED', 'Selected model is unavailable.');
|
|
1527
|
+
const userTurns = records.filter((record) => {
|
|
1528
|
+
if (record.type !== 'turn.user')
|
|
1529
|
+
return false;
|
|
1530
|
+
const payload = record.payload;
|
|
1531
|
+
return payload.inputSource === undefined;
|
|
1532
|
+
}).length;
|
|
1533
|
+
return {
|
|
1534
|
+
sessionId,
|
|
1535
|
+
...(logicalWorkspace ? { cwd: logicalWorkspace, root: logicalWorkspace } : {}),
|
|
1536
|
+
modelId,
|
|
1537
|
+
modelName: model.name,
|
|
1538
|
+
startedAt: Date.parse(current.createdAt),
|
|
1539
|
+
source: structuredClone(sessionSource),
|
|
1540
|
+
userTurns
|
|
1541
|
+
};
|
|
1542
|
+
},
|
|
1543
|
+
composePrompt: async (facts, call) => {
|
|
1544
|
+
call.signal.throwIfAborted();
|
|
1545
|
+
const defaults = promptDefaults;
|
|
1546
|
+
const state = defaults ?? services.modelState();
|
|
1547
|
+
const modelId = facts.modelId ?? defaults?.modelId ?? services.modelState().defaultModelId;
|
|
1548
|
+
const model = state.models.get(modelId);
|
|
1549
|
+
if (!model)
|
|
1550
|
+
throw new MarAgentError('MAR_AGENT_MODEL_DISABLED', 'Selected model is unavailable.');
|
|
1551
|
+
const mode = facts.mode ?? defaults?.mode ?? 'run';
|
|
1552
|
+
const bindings = services.extensions.session(sessionId)?.capture(call);
|
|
1553
|
+
if (!bindings)
|
|
1554
|
+
throw new MarAgentError('MAR_AGENT_EXTENSION_PROMPT_UNAVAILABLE', 'Session prompt tool sources are unavailable.');
|
|
1555
|
+
const definitions = [...bindings.values()]
|
|
1556
|
+
.filter((binding) => binding.available?.(call) !== false)
|
|
1557
|
+
.map((binding) => binding.definition)
|
|
1558
|
+
.filter((tool) => !(sessionSource.type === 'subagent' &&
|
|
1559
|
+
(tool.agentScope === 'ROOT_ONLY' ||
|
|
1560
|
+
tool.name.startsWith('agent_') ||
|
|
1561
|
+
tool.name === 'question')) &&
|
|
1562
|
+
!(tool.name === 'question' && mode !== 'plan') &&
|
|
1563
|
+
!(tool.name === 'view_image' && !model.inputCapabilities.includes('IMAGE')) &&
|
|
1564
|
+
!(['code_exec', 'code_exec_wait'].includes(tool.name) &&
|
|
1565
|
+
(!model.codeMode || !description.capabilities.includes('code.execute'))));
|
|
1566
|
+
const byName = new Map(definitions.map((tool) => [tool.name, tool]));
|
|
1567
|
+
const tools = facts.tools === undefined
|
|
1568
|
+
? definitions
|
|
1569
|
+
: facts.tools.flatMap((name) => {
|
|
1570
|
+
const tool = byName.get(name);
|
|
1571
|
+
return tool ? [tool] : [];
|
|
1572
|
+
});
|
|
1573
|
+
const executionId = call.executionId ?? defaults?.executionId;
|
|
1574
|
+
if (executionId === undefined && host.listExecutionExtensions && !host.listSessionSkills)
|
|
1575
|
+
throw new MarAgentError('MAR_AGENT_EXTENSION_PROMPT_UNAVAILABLE', 'The Host does not provide an idle Session Skill catalog.');
|
|
1576
|
+
const hostSkills = executionId !== undefined
|
|
1577
|
+
? ((await host.listExecutionExtensions?.({ sessionId, modelId, executionId }))
|
|
1578
|
+
?.skills ?? [])
|
|
1579
|
+
: ((await host.listSessionSkills?.({ sessionId, modelId })) ?? []);
|
|
1580
|
+
call.signal.throwIfAborted();
|
|
1581
|
+
const instructions = await loadAgentInstructions({
|
|
1582
|
+
home: description.homeDirectory,
|
|
1583
|
+
workspace: instructionWorkspace,
|
|
1584
|
+
availableTools: new Set(tools.map((tool) => tool.name)),
|
|
1585
|
+
hostSkills,
|
|
1586
|
+
...(settings.workspaceMapping === undefined
|
|
1587
|
+
? {}
|
|
1588
|
+
: { workspaceDisplayPath: logicalWorkspace })
|
|
1589
|
+
});
|
|
1590
|
+
call.signal.throwIfAborted();
|
|
1591
|
+
return {
|
|
1592
|
+
sections: buildSessionPromptSections(tools, mode, model, defaults?.instruction ?? settings.systemInstruction, instructions?.skillCatalog),
|
|
1593
|
+
facts: { modelId, mode, tools: tools.map((tool) => tool.name) }
|
|
1594
|
+
};
|
|
1595
|
+
},
|
|
1596
|
+
captureRequest: async (call, input) => {
|
|
1597
|
+
call.signal.throwIfAborted();
|
|
1598
|
+
return sessionRuntime.requestSnapshots?.capture(input);
|
|
1599
|
+
},
|
|
1600
|
+
sessionId,
|
|
1601
|
+
coordinator: sessionInputs,
|
|
1602
|
+
activeExecutionId: () => [...active.keys()]
|
|
1603
|
+
.find((key) => key.startsWith(`${sessionId}:`))
|
|
1604
|
+
?.slice(sessionId.length + 1),
|
|
1605
|
+
append: appendExtensionMessage,
|
|
1606
|
+
messages: async (input, call) => {
|
|
1607
|
+
const selection = normalizeSessionMessagesInput(input);
|
|
1608
|
+
call.signal.throwIfAborted();
|
|
1609
|
+
let target = sessionId;
|
|
1610
|
+
let targetModelId;
|
|
1611
|
+
if (selection.agentId !== undefined) {
|
|
1612
|
+
if (!sessionRuntime.agentsBackend)
|
|
1613
|
+
throw new MarAgentError('MAR_AGENT_SESSION_INPUT_UNAVAILABLE', 'Session child message access is unavailable.');
|
|
1614
|
+
const child = await sessionRuntime.agentsBackend.inspect({ agentId: selection.agentId }, call);
|
|
1615
|
+
target = child.agentId;
|
|
1616
|
+
targetModelId = child.modelId;
|
|
1617
|
+
}
|
|
1618
|
+
call.signal.throwIfAborted();
|
|
1619
|
+
const targetRuntime = sessionRuntimes.get(target);
|
|
1620
|
+
if (selection.view === 'request' && targetRuntime?.requestMessages)
|
|
1621
|
+
return sessionMessagesPage(targetRuntime.requestMessages.read(), selection);
|
|
1622
|
+
const modelState = services.modelState();
|
|
1623
|
+
const requestModel = selection.view === 'request'
|
|
1624
|
+
? modelState.models.get(targetModelId ?? modelState.defaultModelId)
|
|
1625
|
+
: undefined;
|
|
1626
|
+
if (selection.view === 'request' && !requestModel)
|
|
1627
|
+
throw new MarAgentError('MAR_AGENT_MODEL_DISABLED', 'Selected model is unavailable.');
|
|
1628
|
+
const includeImages = selection.includeImages &&
|
|
1629
|
+
(requestModel === undefined || requestModel.inputCapabilities.includes('IMAGE'));
|
|
1630
|
+
const state = await store.readExecutionState(target);
|
|
1631
|
+
call.signal.throwIfAborted();
|
|
1632
|
+
const restored = await restoreMessages(store, target, state.contextRecords, {
|
|
1633
|
+
includeImages,
|
|
1634
|
+
strictImages: includeImages
|
|
1635
|
+
});
|
|
1636
|
+
call.signal.throwIfAborted();
|
|
1637
|
+
if (requestModel) {
|
|
1638
|
+
const generation = latestContextualWorldStateGeneration(state.contextRecords);
|
|
1639
|
+
const cachedWorld = targetRuntime?.contextualWorldState;
|
|
1640
|
+
const world = cachedWorld?.generation === generation
|
|
1641
|
+
? cachedWorld
|
|
1642
|
+
: parsePersistedContextualWorldState(await store.readContextualWorldState(target));
|
|
1643
|
+
call.signal.throwIfAborted();
|
|
1644
|
+
return sessionMessagesPage(projectSessionRequestMessages(restored.messages, world?.generation === generation ? (world?.entries ?? []) : [], requestModel.inputCapabilities.includes('IMAGE'), requestModel.codeMode), selection);
|
|
1645
|
+
}
|
|
1646
|
+
return sessionMessagesPage(restored.messages, selection, restored.toolOutcomes);
|
|
1647
|
+
},
|
|
1648
|
+
launch: async (entry, request, call) => {
|
|
1649
|
+
if (sessionSource.type !== 'user')
|
|
1650
|
+
throw new MarAgentError('MAR_AGENT_SESSION_INPUT_UNAVAILABLE', 'Idle subagent input must use its task controller.');
|
|
1651
|
+
let resolveInput;
|
|
1652
|
+
let rejectInput;
|
|
1653
|
+
const inputCommitted = new Promise((resolve, reject) => {
|
|
1654
|
+
resolveInput = resolve;
|
|
1655
|
+
rejectInput = reject;
|
|
1656
|
+
});
|
|
1657
|
+
void inputCommitted.catch(() => undefined);
|
|
1658
|
+
const handle = execution(request.kind === 'compact' ? 'compact' : 'run', {
|
|
1659
|
+
prompt: request.kind === 'compact'
|
|
1660
|
+
? (request.input.focus ?? DEFAULT_COMPACTION_FOCUS)
|
|
1661
|
+
: request.input.text,
|
|
1662
|
+
...(request.kind === 'submit' && request.input.images !== undefined
|
|
1663
|
+
? { images: request.input.images }
|
|
1664
|
+
: {})
|
|
1665
|
+
}, {
|
|
1666
|
+
automaticInput: true,
|
|
1667
|
+
inputCommitted: (recordId) => {
|
|
1668
|
+
const outcome = { changed: true, recordId, executionId: handle.executionId };
|
|
1669
|
+
recordSessionInputCommit(entry, outcome);
|
|
1670
|
+
resolveInput(outcome);
|
|
1671
|
+
},
|
|
1672
|
+
...(request.kind === 'submit' ? { promptAdmitted: true } : {}),
|
|
1673
|
+
...(call.actor === 'sdk' && call.extensionId === undefined
|
|
1674
|
+
? {}
|
|
1675
|
+
: { inputSource: 'extension' }),
|
|
1676
|
+
...(request.kind === 'submit' && request.input.modelText !== undefined
|
|
1677
|
+
? { modelText: request.input.modelText }
|
|
1678
|
+
: {}),
|
|
1679
|
+
...(request.kind === 'submit' && request.input.context !== undefined
|
|
1680
|
+
? { inputContext: request.input.context }
|
|
1681
|
+
: {}),
|
|
1682
|
+
...(request.kind === 'submit' && request.input.modelContext !== undefined
|
|
1683
|
+
? { modelContext: request.input.modelContext }
|
|
1684
|
+
: {}),
|
|
1685
|
+
...(call.actor === 'sdk' && call.extensionId === undefined
|
|
1686
|
+
? {}
|
|
1687
|
+
: {
|
|
1688
|
+
extensionSource: extensionInputSource(call, request.kind === 'submit' ? request.input.provenance : undefined, request.kind === 'submit' ? request.input.modelAttribution : undefined)
|
|
1689
|
+
})
|
|
1690
|
+
});
|
|
1691
|
+
void handle.result().then((result) => {
|
|
1692
|
+
if (request.kind === 'compact')
|
|
1693
|
+
resolveInput({
|
|
1694
|
+
changed: result.status === 'completed',
|
|
1695
|
+
executionId: handle.executionId
|
|
1696
|
+
});
|
|
1697
|
+
else
|
|
1698
|
+
rejectInput(new MarAgentError(result.errorCode ??
|
|
1699
|
+
(result.status === 'cancelled'
|
|
1700
|
+
? 'MAR_AGENT_EXECUTION_CANCELLED'
|
|
1701
|
+
: 'MAR_AGENT_SESSION_INPUT_FAILED'), 'Execution ended before its input record was committed.'));
|
|
1702
|
+
}, rejectInput);
|
|
1703
|
+
return Object.assign(handle, { inputCommitted });
|
|
1704
|
+
},
|
|
1705
|
+
diagnose: (code, operationId) => services.extensions.session(sessionId)?.diagnose({ code, operationId, sessionId })
|
|
1706
|
+
});
|
|
1707
|
+
if (sessionSource.type === 'user')
|
|
1708
|
+
sessionRuntime.agentsBackend ??= createExtensionAgentsBackend({
|
|
1709
|
+
existingController: () => sessionRuntime.subagents,
|
|
1710
|
+
controller: async () => {
|
|
1711
|
+
services.assertCanStart();
|
|
1712
|
+
if (sessionRuntime.subagents === undefined)
|
|
1713
|
+
await openSession(sessionId);
|
|
1714
|
+
if (!sessionRuntime.subagents)
|
|
1715
|
+
throw new MarAgentError('MAR_AGENT_SUBAGENT_FAILED', 'Session task controller is unavailable.');
|
|
1716
|
+
return sessionRuntime.subagents;
|
|
1717
|
+
},
|
|
1718
|
+
parent: (controller, call) => {
|
|
1719
|
+
const current = call.executionId === undefined
|
|
1720
|
+
? undefined
|
|
1721
|
+
: controller.parentExecution(call.executionId);
|
|
1722
|
+
if (call.executionId !== undefined && !current)
|
|
1723
|
+
throw new MarAgentError('MAR_AGENT_SUBAGENT_FAILED', 'Parent Execution source is unavailable.');
|
|
1724
|
+
const state = services.modelState();
|
|
1725
|
+
const selected = state.models.get(state.defaultModelId);
|
|
1726
|
+
return {
|
|
1727
|
+
...(current ?? {
|
|
1728
|
+
modelId: selected.id,
|
|
1729
|
+
reasoningEffort: selected.defaultReasoningEffort,
|
|
1730
|
+
models: state.models,
|
|
1731
|
+
emitTerminal: async () => { },
|
|
1732
|
+
startTurn: async (turn) => {
|
|
1733
|
+
const child = await openSession(turn.sessionId);
|
|
1734
|
+
return child.startSubagentTurn({
|
|
1735
|
+
prompt: turn.prompt,
|
|
1736
|
+
modelId: turn.modelId,
|
|
1737
|
+
reasoningEffort: turn.reasoningEffort,
|
|
1738
|
+
role: turn.role,
|
|
1739
|
+
initialMailbox: turn.initialMailbox,
|
|
1740
|
+
turnId: turn.turnId,
|
|
1741
|
+
...(turn.origin === undefined ? {} : { origin: turn.origin }),
|
|
1742
|
+
...(turn.delivery === undefined ? {} : { delivery: turn.delivery })
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
}),
|
|
1746
|
+
operationId: call.operationId,
|
|
1747
|
+
origin: call,
|
|
1748
|
+
signal: call.signal,
|
|
1749
|
+
...(call.ownerInstanceId === undefined
|
|
1750
|
+
? {}
|
|
1751
|
+
: { ownerInstanceId: call.ownerInstanceId }),
|
|
1752
|
+
...(call.extensionId === undefined ? {} : { extensionId: call.extensionId })
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
});
|
|
1080
1756
|
return {
|
|
1081
1757
|
id: sessionId,
|
|
1082
1758
|
run: (input) => execution('run', input),
|
|
@@ -1092,10 +1768,16 @@ export function createSessionOpener(services) {
|
|
|
1092
1768
|
reasoningEffort: turn.reasoningEffort
|
|
1093
1769
|
}, {
|
|
1094
1770
|
publishHostEvents: false,
|
|
1095
|
-
|
|
1771
|
+
...(turn.origin === undefined ? {} : { signal: turn.origin.signal }),
|
|
1772
|
+
inputSource: turn.origin === undefined ? 'parent_agent' : 'extension',
|
|
1773
|
+
...(turn.origin === undefined
|
|
1774
|
+
? {}
|
|
1775
|
+
: { extensionSource: extensionInputSource(turn.origin) }),
|
|
1096
1776
|
initialMailbox: turn.initialMailbox,
|
|
1097
1777
|
turnId: turn.turnId,
|
|
1098
|
-
|
|
1778
|
+
...(turn.mcpExecutionScopeId === undefined
|
|
1779
|
+
? {}
|
|
1780
|
+
: { mcpExecutionScopeId: turn.mcpExecutionScopeId }),
|
|
1099
1781
|
...(turn.delivery ? { delivery: turn.delivery } : {}),
|
|
1100
1782
|
...(turn.sharedRolloutBudget === undefined
|
|
1101
1783
|
? {}
|
|
@@ -1105,6 +1787,16 @@ export function createSessionOpener(services) {
|
|
|
1105
1787
|
};
|
|
1106
1788
|
return openSession;
|
|
1107
1789
|
}
|
|
1790
|
+
function extensionInputSource(call, provenance, modelAttribution) {
|
|
1791
|
+
return {
|
|
1792
|
+
operationId: call.operationId,
|
|
1793
|
+
actor: call.actor,
|
|
1794
|
+
...(call.extensionId ? { extensionId: call.extensionId } : {}),
|
|
1795
|
+
...(call.ownerInstanceId ? { ownerInstanceId: call.ownerInstanceId } : {}),
|
|
1796
|
+
...(provenance !== undefined ? { provenance } : {}),
|
|
1797
|
+
...(modelAttribution === undefined ? {} : { modelAttribution })
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1108
1800
|
function modelAttemptFailureDiagnostic(diagnostic, summary) {
|
|
1109
1801
|
if (summary === undefined)
|
|
1110
1802
|
return diagnostic;
|
|
@@ -1115,3 +1807,20 @@ function modelAttemptFailureDiagnostic(diagnostic, summary) {
|
|
|
1115
1807
|
message: `${prefix}${[...diagnostic.message].slice(0, availableCharacters).join('')}`
|
|
1116
1808
|
};
|
|
1117
1809
|
}
|
|
1810
|
+
/** Shared, side-effect-free projection for the real request and current Session request view. */
|
|
1811
|
+
function projectSessionRequestMessages(messages, entries, supportsImages, codeMode) {
|
|
1812
|
+
return normalizeMessagesForModel(insertContextualWorldState(messages, entries), {
|
|
1813
|
+
supportsImages
|
|
1814
|
+
}).map((message) => projectCodeModeSearchResult(message, codeMode));
|
|
1815
|
+
}
|
|
1816
|
+
function projectAppendedModelMessage(input) {
|
|
1817
|
+
if (input.visibility === 'transcript')
|
|
1818
|
+
return undefined;
|
|
1819
|
+
return {
|
|
1820
|
+
role: 'user',
|
|
1821
|
+
content: input.content,
|
|
1822
|
+
...(input.textBlocks === undefined
|
|
1823
|
+
? {}
|
|
1824
|
+
: { textBlocks: input.textBlocks.map((block) => ({ text: block.text })) })
|
|
1825
|
+
};
|
|
1826
|
+
}
|