@myagentroam/agent 0.10.28 → 0.10.30
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/session-input.d.ts +2 -0
- package/dist/agent-core/extensions/session-input.js +21 -3
- package/dist/agent-core/model/openai-responses.js +1 -1
- package/dist/agent-core/runtime/compaction/coordinator.d.ts +15 -0
- package/dist/agent-core/runtime/compaction/coordinator.js +88 -0
- package/dist/agent-core/runtime/compaction/requests.d.ts +16 -0
- package/dist/agent-core/runtime/compaction/requests.js +114 -0
- package/dist/agent-core/runtime/compaction/retained-context.d.ts +6 -0
- package/dist/agent-core/runtime/compaction/retained-context.js +52 -0
- package/dist/agent-core/runtime/context/restore.d.ts +1 -0
- package/dist/agent-core/runtime/context/restore.js +14 -4
- package/dist/agent-core/runtime/context/usage.js +3 -1
- package/dist/agent-core/runtime/event-projection.js +1 -1
- package/dist/agent-core/runtime/events.d.ts +21 -0
- package/dist/agent-core/runtime/execution-policy.d.ts +1 -0
- package/dist/agent-core/runtime/execution-policy.js +1 -0
- package/dist/agent-core/runtime/execution.d.ts +1 -0
- package/dist/agent-core/runtime/execution.js +1 -0
- package/dist/agent-core/sdk/extension-session.js +4 -2
- package/dist/agent-core/sdk/session.d.ts +2 -0
- package/dist/agent-core/sdk/session.js +307 -191
- package/dist/agent-core/sdk/types.d.ts +4 -1
- package/dist/agent-core/session/catalog.js +2 -2
- package/dist/agent-core/session/jsonl-store.d.ts +2 -0
- package/dist/agent-core/session/jsonl-store.js +6 -0
- package/dist/agent-core/tools/local/exec.js +9 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { isProviderContextOverflow, recoverModelStream } from '../model/recovery
|
|
|
2
2
|
import { estimatedRequestTokens } from '../runtime/context/request-budget.js';
|
|
3
3
|
import { restoreMessages } from '../runtime/context/restore.js';
|
|
4
4
|
import { lastConfigurationEffort, latestModelUsage, reasoningEffortBaseline, shouldUseNativeCompaction } from '../runtime/context/usage.js';
|
|
5
|
-
import { splitContextualPrompt
|
|
5
|
+
import { splitContextualPrompt } from '../runtime/context/contextual-blocks.js';
|
|
6
6
|
import { contextualInstructionInsertIndex, insertContextualWorldState, latestContextualWorldStateGeneration, parsePersistedContextualWorldState, persistContextualWorldState, resetContextualWorldState, updateContextualWorldState, updatePromptWorldState } from '../runtime/context/world-state.js';
|
|
7
7
|
import { eventForPersistence, publicModelUsage } from '../runtime/event-projection.js';
|
|
8
8
|
import { ExecutionLoop } from '../runtime/execution.js';
|
|
@@ -32,6 +32,9 @@ import { retainedSessionResourcesSnapshot } from '../prompts/resources.js';
|
|
|
32
32
|
import { childSubagentInstruction } from '../prompts/subagent.js';
|
|
33
33
|
import { AsyncQueue } from '../runtime/async-queue.js';
|
|
34
34
|
import { CompactionOperation } from '../runtime/compaction/operation.js';
|
|
35
|
+
import { CompactCoordinator } from '../runtime/compaction/coordinator.js';
|
|
36
|
+
import { CompactRequests } from '../runtime/compaction/requests.js';
|
|
37
|
+
import { compactSnapshotAnchor } from '../runtime/compaction/retained-context.js';
|
|
35
38
|
import { DEFAULT_COMPACTION_FOCUS, buildCompactedHistory, buildCompactionInput, buildCompactionMessages, buildNativeCompactionMessages, compactedHistoryMessages } from '../runtime/compaction/history.js';
|
|
36
39
|
import { currentLocalTimeContext, environmentContextUpdate, restoreEnvironmentState } from '../runtime/context/environment.js';
|
|
37
40
|
import { ContextGcRuntime } from '../runtime/context/gc-runtime.js';
|
|
@@ -197,6 +200,11 @@ export function createSessionOpener(services) {
|
|
|
197
200
|
executionModels.get(input.modelId ?? executionDefaultModelId)?.conversationModel === false)
|
|
198
201
|
throw new MarAgentError('MAR_AGENT_MODEL_DISABLED', 'The selected model is not a conversation model.');
|
|
199
202
|
const executionId = randomUUID(), turnId = internal.turnId ?? randomUUID(), queue = new AsyncQueue(), controller = new AbortController();
|
|
203
|
+
const compactCoordinator = new CompactCoordinator();
|
|
204
|
+
const messageSources = new WeakMap();
|
|
205
|
+
let liveModelMessages = [];
|
|
206
|
+
const compactRequests = new CompactRequests(executionId, () => compactCoordinator.assertNotReentrant());
|
|
207
|
+
sessionRuntime.compactRequests = compactRequests;
|
|
200
208
|
const permissionPolicy = new ExecutionToolPermissions(mode === 'compact' ? 'full-access' : resolvePermissionMode(input.permissionMode), { sessionId, executionId }, host.requestToolApproval
|
|
201
209
|
? {
|
|
202
210
|
request: (request, signal) => host.requestToolApproval(request, signal),
|
|
@@ -265,7 +273,6 @@ export function createSessionOpener(services) {
|
|
|
265
273
|
acceptParent(message);
|
|
266
274
|
let acceptsMailbox = sessionSource.type === 'subagent' && mode !== 'compact';
|
|
267
275
|
let sequence = 0;
|
|
268
|
-
let manualCompactionStarted = false;
|
|
269
276
|
let emitTail = Promise.resolve();
|
|
270
277
|
let releaseSession;
|
|
271
278
|
let exhaustedModelAttempt;
|
|
@@ -284,14 +291,21 @@ export function createSessionOpener(services) {
|
|
|
284
291
|
const operation = emitTail.then(async () => {
|
|
285
292
|
assertLive?.();
|
|
286
293
|
const persistent = eventForPersistence(full);
|
|
287
|
-
if (persistent !== undefined && releaseSession !== undefined)
|
|
288
|
-
await store.append(sessionId, {
|
|
294
|
+
if (persistent !== undefined && releaseSession !== undefined) {
|
|
295
|
+
const stored = await store.append(sessionId, {
|
|
289
296
|
type: full.type,
|
|
290
297
|
payload: persistent,
|
|
291
298
|
executionId,
|
|
292
299
|
turnId
|
|
293
300
|
});
|
|
301
|
+
if (full.type === 'message.completed') {
|
|
302
|
+
const message = liveModelMessages.findLast((item) => item.role === 'assistant' && item.content === full.text);
|
|
303
|
+
if (message)
|
|
304
|
+
messageSources.set(message, stored);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
294
307
|
queue.push(full);
|
|
308
|
+
compactRequests.publish(full);
|
|
295
309
|
if (internal.publishHostEvents !== false)
|
|
296
310
|
await host.emit(full);
|
|
297
311
|
});
|
|
@@ -337,7 +351,6 @@ export function createSessionOpener(services) {
|
|
|
337
351
|
const result = withToolPermissions(permissionPolicy, async () => {
|
|
338
352
|
let finalAnswer = '';
|
|
339
353
|
let executionLoop;
|
|
340
|
-
let manualCompaction;
|
|
341
354
|
let executionToolSources;
|
|
342
355
|
let selectedTurn;
|
|
343
356
|
const contextGc = new ContextGcRuntime();
|
|
@@ -392,9 +405,11 @@ export function createSessionOpener(services) {
|
|
|
392
405
|
}
|
|
393
406
|
const compactMayContainAgentInstructions = contextRecords.some((record) => compactSummaryFromCheckpoint(record) !== undefined);
|
|
394
407
|
const restored = await restoreMessages(store, sessionId, contextRecords, {
|
|
408
|
+
messageSources,
|
|
395
409
|
includeImages: mode !== 'compact'
|
|
396
410
|
});
|
|
397
411
|
const messages = restored.messages;
|
|
412
|
+
liveModelMessages = messages;
|
|
398
413
|
const restoredRecordIds = new Set(contextRecords.map((record) => record.recordId));
|
|
399
414
|
for (const pending of pendingAppends)
|
|
400
415
|
if (!restoredRecordIds.has(pending.recordId))
|
|
@@ -403,6 +418,7 @@ export function createSessionOpener(services) {
|
|
|
403
418
|
immediateTarget = messages;
|
|
404
419
|
let recordedEnvironment = restored.environmentState;
|
|
405
420
|
let compactContext;
|
|
421
|
+
let startCompact;
|
|
406
422
|
const writeInputRecord = async (content, type, metadata, call, committed) => {
|
|
407
423
|
call.signal.throwIfAborted();
|
|
408
424
|
if (content.images?.length && !selectedModel.inputCapabilities.includes('IMAGE'))
|
|
@@ -439,8 +455,14 @@ export function createSessionOpener(services) {
|
|
|
439
455
|
};
|
|
440
456
|
const appendMailboxMessages = async () => inputs.drain(async (entry, request, call) => {
|
|
441
457
|
call.signal.throwIfAborted();
|
|
442
|
-
if (request.kind === 'compact')
|
|
458
|
+
if (request.kind === 'compact') {
|
|
459
|
+
if (request.input.async) {
|
|
460
|
+
const flight = startCompact(request.input);
|
|
461
|
+
entry.start();
|
|
462
|
+
return { changed: await flight.result, executionId };
|
|
463
|
+
}
|
|
443
464
|
return { changed: await compactContext(request.input), executionId };
|
|
465
|
+
}
|
|
444
466
|
if (request.kind === 'append') {
|
|
445
467
|
const result = await appendExtensionMessage(entry, request, call);
|
|
446
468
|
return { ...result, executionId };
|
|
@@ -765,14 +787,31 @@ export function createSessionOpener(services) {
|
|
|
765
787
|
contextualWorldState = next;
|
|
766
788
|
sessionRuntime.contextualWorldState = next;
|
|
767
789
|
};
|
|
768
|
-
const resetCompactWorldState = async (generation) => {
|
|
790
|
+
const resetCompactWorldState = async (generation, committed) => {
|
|
769
791
|
agentInstructionInsertIndex = contextualInstructionInsertIndex(messages);
|
|
770
792
|
const next = resetContextualWorldState(generation, agentInstructionInsertIndex, {
|
|
771
793
|
instructionSnapshot: currentInstructionSnapshot,
|
|
772
794
|
instructionContent: renderAgentInstructions(instructionEntries, true),
|
|
773
|
-
resourceSnapshot:
|
|
795
|
+
resourceSnapshot: committed
|
|
796
|
+
? committed.resources
|
|
797
|
+
: retainedSessionResourcesSnapshot(await loadRetainedSessionResources())
|
|
774
798
|
});
|
|
775
|
-
|
|
799
|
+
if (!committed)
|
|
800
|
+
await commitWorldState(next);
|
|
801
|
+
else {
|
|
802
|
+
// The checkpoint is authoritative; its sidecar is recoverable on restart.
|
|
803
|
+
contextualWorldState = next;
|
|
804
|
+
sessionRuntime.contextualWorldState = next;
|
|
805
|
+
try {
|
|
806
|
+
await persistContextualWorldState(store, sessionId, next);
|
|
807
|
+
}
|
|
808
|
+
catch {
|
|
809
|
+
coreExtensions.diagnose({
|
|
810
|
+
code: 'MAR_AGENT_COMPACT_SIDECAR_PERSIST_FAILED',
|
|
811
|
+
sessionId
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
}
|
|
776
815
|
};
|
|
777
816
|
// A missing sidecar is rebuilt only for the latest Compact, never for a GC boundary.
|
|
778
817
|
if (!contextualWorldState.initialized &&
|
|
@@ -1062,8 +1101,6 @@ export function createSessionOpener(services) {
|
|
|
1062
1101
|
const initialSystemPrompt = mode === 'compact'
|
|
1063
1102
|
? buildExecutionSystemPrompt(executionTools, 'run')
|
|
1064
1103
|
: buildExecutionSystemPrompt();
|
|
1065
|
-
let useManualCompactionFallback;
|
|
1066
|
-
const manualAppendBoundary = pendingAppends.length;
|
|
1067
1104
|
const generateCompactExtension = async (history, reason, focus, compaction) => {
|
|
1068
1105
|
if (!coreExtensions.hooks.hasInterceptors('compact.generate'))
|
|
1069
1106
|
return undefined;
|
|
@@ -1114,50 +1151,6 @@ export function createSessionOpener(services) {
|
|
|
1114
1151
|
acceptsDiagnostics = false;
|
|
1115
1152
|
}
|
|
1116
1153
|
};
|
|
1117
|
-
let manualExtension;
|
|
1118
|
-
if (mode === 'compact' && coreExtensions.hooks.hasInterceptors('compact.generate')) {
|
|
1119
|
-
manualCompactionStarted = true;
|
|
1120
|
-
manualCompaction = createCompactionOperation(manualCompactionId, compactSignal);
|
|
1121
|
-
await emit({ type: 'context.compacting', compactionId: manualCompactionId });
|
|
1122
|
-
manualExtension = await generateCompactExtension(messages, 'manual', compactFocus, manualCompaction);
|
|
1123
|
-
}
|
|
1124
|
-
if (mode === 'compact' && manualExtension === undefined) {
|
|
1125
|
-
preparedCompactPrompt = await operation((call) => coreExtensions.composeModelSystem(promptComposition(executionTools, 'run'), call));
|
|
1126
|
-
const compactComposition = splitContextualPrompt(preparedCompactPrompt);
|
|
1127
|
-
const compactSystemPrompt = compactComposition.system;
|
|
1128
|
-
const projectCompact = (input) => projectCompactPromptMessages(input, compactComposition.parts, contextualWorldState.promptSnapshot ?? []);
|
|
1129
|
-
const compactHistory = [...messages];
|
|
1130
|
-
const projectedHistory = normalizeMessagesForModel(insertContextualWorldState(compactHistory, contextualWorldState.entries), { supportsImages: false });
|
|
1131
|
-
const nativeMessages = buildNativeCompactionMessages(projectedHistory, {
|
|
1132
|
-
focus: compactFocus
|
|
1133
|
-
});
|
|
1134
|
-
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, projectCompact(buildCompactionMessages('')), executionTools);
|
|
1135
|
-
const compactInputTokens = selectedModel.contextWindowTokens - compactOverheadTokens;
|
|
1136
|
-
if (compactInputTokens <= 0)
|
|
1137
|
-
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Compaction prompt exceeds the selected model context window.');
|
|
1138
|
-
const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
|
|
1139
|
-
focus: compactFocus,
|
|
1140
|
-
maxTokens: compactInputTokens
|
|
1141
|
-
}));
|
|
1142
|
-
const useNative = shouldUseNativeCompaction({
|
|
1143
|
-
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, projectCompact(nativeMessages), executionTools),
|
|
1144
|
-
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1145
|
-
latestUsage: lastServerUsage,
|
|
1146
|
-
historyMessages: compactHistory,
|
|
1147
|
-
appendedMessages: projectCompact(nativeMessages).slice(projectedHistory.length)
|
|
1148
|
-
});
|
|
1149
|
-
messages.splice(0, messages.length, ...(useNative ? nativeMessages : fallbackMessages()));
|
|
1150
|
-
if (useNative) {
|
|
1151
|
-
let available = true;
|
|
1152
|
-
useManualCompactionFallback = () => {
|
|
1153
|
-
if (!available)
|
|
1154
|
-
return false;
|
|
1155
|
-
available = false;
|
|
1156
|
-
messages.splice(0, messages.length, ...fallbackMessages(), ...pendingAppends.slice(manualAppendBoundary).map((entry) => entry.message));
|
|
1157
|
-
return true;
|
|
1158
|
-
};
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
1154
|
await store.append(sessionId, {
|
|
1162
1155
|
type: 'execution.header',
|
|
1163
1156
|
payload: {
|
|
@@ -1173,29 +1166,53 @@ export function createSessionOpener(services) {
|
|
|
1173
1166
|
turnId
|
|
1174
1167
|
});
|
|
1175
1168
|
let lastServerContextTokens = lastServerUsage?.contextInputTokens;
|
|
1176
|
-
|
|
1169
|
+
let compactBoundary = messages.length;
|
|
1170
|
+
const compactLeaf = async (input, signal, prepare, compactionId) => {
|
|
1177
1171
|
if (messages.length < 2)
|
|
1178
1172
|
return false;
|
|
1179
1173
|
let compactSummary = '';
|
|
1180
|
-
const
|
|
1181
|
-
const
|
|
1182
|
-
const
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1174
|
+
const cutoff = Math.min(compactBoundary, messages.length);
|
|
1175
|
+
const current = messages[cutoff - 1];
|
|
1176
|
+
const retainCurrent = mode !== 'compact' && current.role === 'user' && current.contextKind === undefined;
|
|
1177
|
+
const prefix = messages.slice(0, cutoff - (retainCurrent ? 1 : 0));
|
|
1178
|
+
if (!prefix.some((message) => message.role !== 'user' ||
|
|
1179
|
+
message.contextKind === undefined ||
|
|
1180
|
+
message.contextKind === 'summary'))
|
|
1181
|
+
return false;
|
|
1182
|
+
const compactHistory = structuredClone(prefix);
|
|
1183
|
+
const prefixInputs = compactionUserMessages.filter((entry) => prefix.some((message) => message.role === 'user' &&
|
|
1184
|
+
message.contextKind === undefined &&
|
|
1185
|
+
(entry.metadata?.recordId
|
|
1186
|
+
? message.metadata?.recordId === entry.metadata.recordId
|
|
1187
|
+
: message.content === entry.content)));
|
|
1188
|
+
const snapshotTools = structuredClone(executionTools);
|
|
1189
|
+
const generation = contextualWorldState.generation;
|
|
1190
|
+
const snapshotUsage = lastServerUsage;
|
|
1191
|
+
const snapshotEffort = requestReasoningEffort ?? reasoningEffort;
|
|
1192
|
+
const anchorRecordId = prefix
|
|
1193
|
+
.map((message) => messageSources.get(message)?.recordId ?? message.metadata?.recordId)
|
|
1194
|
+
.findLast((id) => id !== undefined);
|
|
1195
|
+
const visibleAnchor = compactSnapshotAnchor(prefix, messageSources);
|
|
1196
|
+
const anchor = {
|
|
1197
|
+
...(anchorRecordId ? { anchorRecordId } : {}),
|
|
1198
|
+
...(visibleAnchor ? { anchor: visibleAnchor } : {})
|
|
1199
|
+
};
|
|
1200
|
+
const compactComposition = splitContextualPrompt(await operation((call) => coreExtensions.composeModelSystem(promptComposition(snapshotTools, 'run'), call)));
|
|
1185
1201
|
const compactSystemPrompt = compactComposition.system;
|
|
1186
|
-
const
|
|
1187
|
-
|
|
1202
|
+
const projectedHistory = normalizeMessagesForModel(compactHistory, {
|
|
1203
|
+
supportsImages: false
|
|
1204
|
+
});
|
|
1188
1205
|
const nativeCompactMessages = buildNativeCompactionMessages(projectedHistory, {
|
|
1189
1206
|
...(input.focus === undefined ? {} : { focus: input.focus })
|
|
1190
1207
|
});
|
|
1191
|
-
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt,
|
|
1208
|
+
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages(''), snapshotTools);
|
|
1192
1209
|
const compactInputTokens = Math.max(0, selectedModel.contextWindowTokens - compactOverheadTokens);
|
|
1193
1210
|
let usingNativeMessages = shouldUseNativeCompaction({
|
|
1194
|
-
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt,
|
|
1211
|
+
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeCompactMessages, snapshotTools),
|
|
1195
1212
|
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1196
|
-
latestUsage:
|
|
1213
|
+
latestUsage: snapshotUsage,
|
|
1197
1214
|
historyMessages: compactHistory,
|
|
1198
|
-
appendedMessages:
|
|
1215
|
+
appendedMessages: nativeCompactMessages.slice(projectedHistory.length)
|
|
1199
1216
|
});
|
|
1200
1217
|
const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
|
|
1201
1218
|
...(input.focus === undefined ? {} : { focus: input.focus }),
|
|
@@ -1204,18 +1221,28 @@ export function createSessionOpener(services) {
|
|
|
1204
1221
|
let compactMessages = usingNativeMessages
|
|
1205
1222
|
? nativeCompactMessages
|
|
1206
1223
|
: fallbackMessages();
|
|
1207
|
-
|
|
1208
|
-
|
|
1224
|
+
await emit({
|
|
1225
|
+
type: 'context.compacting',
|
|
1226
|
+
compactionId,
|
|
1227
|
+
async: input.async === true,
|
|
1228
|
+
stage: 'GENERATING',
|
|
1229
|
+
...anchor
|
|
1230
|
+
});
|
|
1209
1231
|
let latestUsage;
|
|
1210
1232
|
const compactionRetryState = { attempts: 0 };
|
|
1211
1233
|
const compaction = createCompactionOperation(compactionId, signal);
|
|
1234
|
+
const compactTurn = createModelTurnSession(selectedAdapter);
|
|
1212
1235
|
try {
|
|
1213
|
-
const extensionResult = await generateCompactExtension(compactHistory, 'automatic', input.focus, compaction);
|
|
1236
|
+
const extensionResult = await generateCompactExtension(compactHistory, mode === 'compact' ? 'manual' : 'automatic', input.focus, compaction);
|
|
1214
1237
|
if (extensionResult) {
|
|
1215
1238
|
compactSummary = extensionResult.summary;
|
|
1216
1239
|
latestUsage = extensionResult.usage;
|
|
1217
1240
|
if (latestUsage)
|
|
1218
|
-
await emit({
|
|
1241
|
+
await emit({
|
|
1242
|
+
type: 'usage.updated',
|
|
1243
|
+
purpose: 'compact',
|
|
1244
|
+
...publicModelUsage(latestUsage)
|
|
1245
|
+
});
|
|
1219
1246
|
}
|
|
1220
1247
|
while (extensionResult === undefined) {
|
|
1221
1248
|
if (compactInputTokens === 0)
|
|
@@ -1229,20 +1256,24 @@ export function createSessionOpener(services) {
|
|
|
1229
1256
|
...(compactComposition.systemBlocks === undefined
|
|
1230
1257
|
? {}
|
|
1231
1258
|
: { systemBlocks: compactComposition.systemBlocks }),
|
|
1232
|
-
messages:
|
|
1233
|
-
tools:
|
|
1259
|
+
messages: compactMessages,
|
|
1260
|
+
tools: snapshotTools,
|
|
1234
1261
|
toolChoice: 'none',
|
|
1235
1262
|
promptCacheKey: sessionId,
|
|
1236
|
-
reasoningEffort:
|
|
1263
|
+
reasoningEffort: snapshotEffort,
|
|
1237
1264
|
onAttemptDiagnostic: recordModelAttempt('COMPACTION')
|
|
1238
1265
|
}, undefined, selectedModel.id, 'compact');
|
|
1239
|
-
for await (const event of streamModel((signal) => compaction.start({ start: (request) =>
|
|
1266
|
+
for await (const event of streamModel((signal) => compaction.start({ start: (request) => compactTurn.start(request, signal) }, request), compaction.signal)) {
|
|
1240
1267
|
if (event.type === 'text.completed' &&
|
|
1241
1268
|
(event.phase ?? 'final_answer') === 'final_answer')
|
|
1242
1269
|
compactSummary = event.text.trim();
|
|
1243
1270
|
else if (event.type === 'usage') {
|
|
1244
1271
|
latestUsage = event.usage;
|
|
1245
|
-
await emit({
|
|
1272
|
+
await emit({
|
|
1273
|
+
type: 'usage.updated',
|
|
1274
|
+
purpose: 'compact',
|
|
1275
|
+
...publicModelUsage(event.usage)
|
|
1276
|
+
});
|
|
1246
1277
|
}
|
|
1247
1278
|
else if (event.type === 'client_tool.call')
|
|
1248
1279
|
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Compaction returned a tool call while tools were disabled.');
|
|
@@ -1267,32 +1298,36 @@ export function createSessionOpener(services) {
|
|
|
1267
1298
|
}
|
|
1268
1299
|
finally {
|
|
1269
1300
|
await compaction.dispose();
|
|
1301
|
+
await compactTurn.close();
|
|
1270
1302
|
}
|
|
1271
1303
|
if (!compactSummary)
|
|
1272
1304
|
throw new MarAgentError('MAR_AGENT_COMPACT_FAILED', 'Automatic compact failed.');
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1305
|
+
await emit({
|
|
1306
|
+
type: 'context.compacting',
|
|
1307
|
+
compactionId,
|
|
1308
|
+
async: !compactCoordinator.waiting && input.async === true,
|
|
1309
|
+
stage: compactCoordinator.waiting ? 'WAITING' : 'READY',
|
|
1310
|
+
...anchor
|
|
1311
|
+
});
|
|
1312
|
+
await prepare();
|
|
1279
1313
|
signal.throwIfAborted();
|
|
1314
|
+
const compactResources = retainedSessionResourcesSnapshot(await loadRetainedSessionResources());
|
|
1315
|
+
const replacementHistory = buildCompactedHistory(compactSummary, prefixInputs, compactUserTokenLimit);
|
|
1316
|
+
let retainedModelContext = [];
|
|
1280
1317
|
const compactRecord = await writeCompactionRecord(compactSummary, true, signal, async (actual, options) => {
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
: undefined);
|
|
1288
|
-
const retainedModelContext = pendingAppends
|
|
1289
|
-
.slice(appendBoundary)
|
|
1290
|
-
.map((entry) => entry.message);
|
|
1318
|
+
if (contextualWorldState.generation !== generation ||
|
|
1319
|
+
prefix.some((message, index) => messages[index] !== message))
|
|
1320
|
+
throw new MarAgentError('MAR_AGENT_COMPACT_STALE', 'The compaction prefix has changed.');
|
|
1321
|
+
retainedModelContext = messages
|
|
1322
|
+
.slice(prefix.length)
|
|
1323
|
+
.filter((message) => message.contextKind !== 'private' || message.role === 'provider');
|
|
1291
1324
|
const record = await store.compact(sessionId, {
|
|
1292
|
-
summary:
|
|
1325
|
+
summary: actual,
|
|
1293
1326
|
replacementHistory,
|
|
1294
1327
|
retainedModelContext,
|
|
1295
|
-
|
|
1328
|
+
snapshotMessageCount: prefix.length,
|
|
1329
|
+
...(anchorRecordId ? { snapshotRecordId: anchorRecordId } : {}),
|
|
1330
|
+
automatic: mode !== 'compact',
|
|
1296
1331
|
environment: executionEnvironment,
|
|
1297
1332
|
modelId: selectedModel.id,
|
|
1298
1333
|
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
@@ -1314,30 +1349,115 @@ export function createSessionOpener(services) {
|
|
|
1314
1349
|
content: message.content,
|
|
1315
1350
|
...(message.metadata ? { metadata: { ...message.metadata } } : {})
|
|
1316
1351
|
}));
|
|
1317
|
-
|
|
1352
|
+
compactionUserMessages.push(...retainedModelContext
|
|
1353
|
+
.filter((message) => message.role === 'user' && message.contextKind === undefined)
|
|
1354
|
+
.map((message) => ({
|
|
1355
|
+
content: message.content,
|
|
1356
|
+
...(message.metadata ? { metadata: message.metadata } : {})
|
|
1357
|
+
})));
|
|
1358
|
+
await resetCompactWorldState(compactRecord.recordId, { resources: compactResources });
|
|
1318
1359
|
lastServerContextTokens = undefined;
|
|
1319
1360
|
lastServerUsage = undefined;
|
|
1320
1361
|
requestReasoningEffort = reasoningEffort;
|
|
1321
1362
|
effectiveReasoningEffort = reasoningEffort;
|
|
1322
|
-
await emit({
|
|
1363
|
+
await emit({
|
|
1364
|
+
type: 'context.compacted',
|
|
1365
|
+
compactionId,
|
|
1366
|
+
async: input.async === true,
|
|
1367
|
+
retainedContext: retainedModelContext.length > 0,
|
|
1368
|
+
...anchor
|
|
1369
|
+
});
|
|
1323
1370
|
return true;
|
|
1324
1371
|
};
|
|
1372
|
+
startCompact = (input = {}) => {
|
|
1373
|
+
const id = manualCompactionId ?? randomUUID();
|
|
1374
|
+
return compactCoordinator.start(id, input.focus, async (prepare, signal) => {
|
|
1375
|
+
const linked = AbortSignal.any([signal, controller.signal, compactSignal]);
|
|
1376
|
+
try {
|
|
1377
|
+
if (mode === 'compact' && inputs.currentCompact())
|
|
1378
|
+
return await compactLeaf(input, linked, prepare, id);
|
|
1379
|
+
return (await performCompact(input, async (effective, call) => ({
|
|
1380
|
+
changed: await compactLeaf({ ...effective, async: input.async === true }, AbortSignal.any([linked, call.signal]), prepare, id),
|
|
1381
|
+
executionId
|
|
1382
|
+
}))).changed;
|
|
1383
|
+
}
|
|
1384
|
+
catch (error) {
|
|
1385
|
+
const diagnostic = describeMarAgentError(error, 'MAR_AGENT_COMPACT_FAILED');
|
|
1386
|
+
await emit({
|
|
1387
|
+
type: 'context.compact_failed',
|
|
1388
|
+
compactionId: id,
|
|
1389
|
+
code: diagnostic.code,
|
|
1390
|
+
async: input.async === true,
|
|
1391
|
+
cancelled: linked.aborted
|
|
1392
|
+
});
|
|
1393
|
+
throw error;
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
};
|
|
1325
1397
|
compactContext = async (input = {}) => {
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1398
|
+
const flight = startCompact(input);
|
|
1399
|
+
if (input.async)
|
|
1400
|
+
return false;
|
|
1401
|
+
await emit({
|
|
1402
|
+
type: 'context.compacting',
|
|
1403
|
+
compactionId: flight.id,
|
|
1404
|
+
stage: 'WAITING',
|
|
1405
|
+
async: false
|
|
1406
|
+
});
|
|
1407
|
+
return (await compactCoordinator.checkpoint(true)) ?? false;
|
|
1331
1408
|
};
|
|
1409
|
+
compactRequests.bind((input) => compactCoordinator.pending
|
|
1410
|
+
? startCompact({
|
|
1411
|
+
...(input.prompt === undefined ? {} : { focus: input.prompt }),
|
|
1412
|
+
async: input.async === true
|
|
1413
|
+
})
|
|
1414
|
+
: undefined);
|
|
1415
|
+
if (mode === 'compact') {
|
|
1416
|
+
startCompact({ focus: compactFocus });
|
|
1417
|
+
compactRequests.drain((input) => startCompact({
|
|
1418
|
+
...(input.prompt === undefined ? {} : { focus: input.prompt }),
|
|
1419
|
+
async: input.async === true
|
|
1420
|
+
}));
|
|
1421
|
+
await compactCoordinator.checkpoint(true);
|
|
1422
|
+
compactRequests.seal();
|
|
1423
|
+
compactRequests.drain((input) => startCompact({
|
|
1424
|
+
...(input.prompt === undefined ? {} : { focus: input.prompt }),
|
|
1425
|
+
async: input.async === true
|
|
1426
|
+
}));
|
|
1427
|
+
await compactCoordinator.checkpoint(true);
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1332
1430
|
const ensureContextBudget = async () => {
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1431
|
+
const percent = lastServerContextTokens === undefined
|
|
1432
|
+
? undefined
|
|
1433
|
+
: (lastServerContextTokens * 100) / selectedModel.contextWindowTokens;
|
|
1434
|
+
if (percent !== undefined &&
|
|
1435
|
+
percent >= AGENT_EXECUTION_POLICY.automaticCompactionPercent) {
|
|
1436
|
+
const hadPending = compactCoordinator.pending;
|
|
1437
|
+
let compacted;
|
|
1438
|
+
try {
|
|
1439
|
+
compacted = await compactContext();
|
|
1440
|
+
}
|
|
1441
|
+
catch (error) {
|
|
1442
|
+
controller.signal.throwIfAborted();
|
|
1443
|
+
if (!hadPending)
|
|
1444
|
+
throw error;
|
|
1445
|
+
compactBoundary = messages.length;
|
|
1446
|
+
compacted = await compactContext();
|
|
1447
|
+
}
|
|
1448
|
+
if (!compacted)
|
|
1449
|
+
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Provider usage reached the compaction threshold but no history can be compacted.');
|
|
1450
|
+
}
|
|
1451
|
+
else {
|
|
1452
|
+
const adopted = await compactCoordinator.checkpoint(false).catch(() => {
|
|
1453
|
+
controller.signal.throwIfAborted();
|
|
1454
|
+
});
|
|
1455
|
+
if (!adopted &&
|
|
1456
|
+
percent !== undefined &&
|
|
1457
|
+
percent >= AGENT_EXECUTION_POLICY.backgroundCompactionPercent &&
|
|
1458
|
+
!compactCoordinator.pending)
|
|
1459
|
+
startCompact({ async: true });
|
|
1460
|
+
}
|
|
1341
1461
|
};
|
|
1342
1462
|
executionLoop = new ExecutionLoop({
|
|
1343
1463
|
mode,
|
|
@@ -1349,27 +1469,30 @@ export function createSessionOpener(services) {
|
|
|
1349
1469
|
toolImages: currentExecutionToolImages,
|
|
1350
1470
|
publish: emit,
|
|
1351
1471
|
appendContext: (message) => withRecordProjection(async () => {
|
|
1352
|
-
await store.append(sessionId, {
|
|
1472
|
+
const stored = await store.append(sessionId, {
|
|
1353
1473
|
type: 'model.context',
|
|
1354
1474
|
payload: message,
|
|
1355
1475
|
executionId,
|
|
1356
1476
|
turnId
|
|
1357
1477
|
});
|
|
1478
|
+
messageSources.set(message, stored);
|
|
1358
1479
|
}),
|
|
1359
|
-
prepareRound: async (pendingOutputContinuation)
|
|
1360
|
-
|
|
1361
|
-
await appendMailboxMessages();
|
|
1480
|
+
prepareRound: async function prepareRound(pendingOutputContinuation) {
|
|
1481
|
+
await appendMailboxMessages();
|
|
1362
1482
|
updateMcpRegistry();
|
|
1363
1483
|
executionTools = mcpRegistry.project(baseTools());
|
|
1364
|
-
|
|
1365
|
-
|
|
1484
|
+
await syncMcpWorldState(messages.length);
|
|
1485
|
+
compactBoundary = messages.length;
|
|
1486
|
+
const blocking = compactRequests.drain((input) => startCompact({
|
|
1487
|
+
...(input.prompt === undefined ? {} : { focus: input.prompt }),
|
|
1488
|
+
async: input.async === true
|
|
1489
|
+
}));
|
|
1490
|
+
if (blocking)
|
|
1491
|
+
await compactCoordinator.checkpoint(true);
|
|
1366
1492
|
await ensureContextBudget();
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
executionEnvironment = { ...currentEnvironment, ...currentLocalTimeContext() };
|
|
1371
|
-
await recordEnvironment();
|
|
1372
|
-
}
|
|
1493
|
+
await syncMcpWorldState(messages.length);
|
|
1494
|
+
executionEnvironment = { ...currentEnvironment, ...currentLocalTimeContext() };
|
|
1495
|
+
await recordEnvironment();
|
|
1373
1496
|
const { roundTools, roundBindings, toolScope, composeSystemPrompt } = captureRoundToolScope();
|
|
1374
1497
|
const codeModeEnabled = roundTools.some((tool) => tool.name === 'code_exec');
|
|
1375
1498
|
const residentTools = projectTools(mcpRegistry.projectDirect(baseTools()));
|
|
@@ -1385,13 +1508,8 @@ export function createSessionOpener(services) {
|
|
|
1385
1508
|
: [...messages, pendingOutputContinuation];
|
|
1386
1509
|
sources.bind(toolScope);
|
|
1387
1510
|
const composedSystem = splitContextualPrompt(await composeSystemPrompt());
|
|
1388
|
-
const candidateWorld =
|
|
1389
|
-
|
|
1390
|
-
: updatePromptWorldState(contextualWorldState, messages.length, composedSystem.parts);
|
|
1391
|
-
const projectedMessages = projectSessionRequestMessages(requestContextMessages, mode === 'compact' ? [] : candidateWorld.entries, mode !== 'compact' && selectedModel.inputCapabilities.includes('IMAGE'), codeModeEnabled, permissionPolicy.mode === 'auto');
|
|
1392
|
-
const modelMessages = mode === 'compact'
|
|
1393
|
-
? projectCompactPromptMessages(projectedMessages, composedSystem.parts, contextualWorldState.promptSnapshot ?? [])
|
|
1394
|
-
: projectedMessages;
|
|
1511
|
+
const candidateWorld = updatePromptWorldState(contextualWorldState, messages.length, composedSystem.parts);
|
|
1512
|
+
const modelMessages = projectSessionRequestMessages(requestContextMessages, candidateWorld.entries, selectedModel.inputCapabilities.includes('IMAGE'), codeModeEnabled, permissionPolicy.mode === 'auto');
|
|
1395
1513
|
const systemPrompt = composedSystem.system;
|
|
1396
1514
|
const candidateRequest = {
|
|
1397
1515
|
system: systemPrompt,
|
|
@@ -1401,12 +1519,11 @@ export function createSessionOpener(services) {
|
|
|
1401
1519
|
messages: modelMessages,
|
|
1402
1520
|
tools: requestTools,
|
|
1403
1521
|
...(permissionPolicy.mode === 'auto' ? { allowHostedTools: false } : {}),
|
|
1404
|
-
...(mode === 'compact' ? { toolChoice: 'none' } : {}),
|
|
1405
1522
|
promptCacheKey: sessionId,
|
|
1406
1523
|
reasoningEffort,
|
|
1407
1524
|
...(requestReasoningEffort === undefined ? {} : { requestReasoningEffort }),
|
|
1408
1525
|
...(modelInputImages?.length ? { images: modelInputImages } : {}),
|
|
1409
|
-
onAttemptDiagnostic: recordModelAttempt(
|
|
1526
|
+
onAttemptDiagnostic: recordModelAttempt('EXECUTION')
|
|
1410
1527
|
};
|
|
1411
1528
|
preparingRequestMessages = modelMessages;
|
|
1412
1529
|
preparingRequestBaseLength = messages.length;
|
|
@@ -1422,33 +1539,41 @@ export function createSessionOpener(services) {
|
|
|
1422
1539
|
// Commit only after request middleware accepts the entire candidate.
|
|
1423
1540
|
await commitWorldState(candidateWorld);
|
|
1424
1541
|
}
|
|
1542
|
+
const lateCoreChange = inputs.hasBoundaryCompactPending && (await appendMailboxMessages());
|
|
1543
|
+
const lateBlocking = compactRequests.drain((input) => startCompact({
|
|
1544
|
+
...(input.prompt === undefined ? {} : { focus: input.prompt }),
|
|
1545
|
+
async: input.async === true
|
|
1546
|
+
}));
|
|
1547
|
+
const lateAdopted = lateBlocking && (await compactCoordinator.checkpoint(true));
|
|
1548
|
+
if (lateCoreChange || lateAdopted) {
|
|
1549
|
+
// Middleware may admit a blocking join after the initial checkpoint.
|
|
1550
|
+
// Never sample the candidate assembled against the replaced context.
|
|
1551
|
+
return prepareRound(pendingOutputContinuation);
|
|
1552
|
+
}
|
|
1425
1553
|
return { request, toolScope };
|
|
1426
1554
|
},
|
|
1427
1555
|
startModel: async function* (request) {
|
|
1428
|
-
const snapshots =
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
const snapshot = snapshots?.record(selectedModel.id, request);
|
|
1432
|
-
if (manualCompactionId !== undefined && !manualCompactionStarted) {
|
|
1433
|
-
manualCompactionStarted = true;
|
|
1434
|
-
manualCompaction = createCompactionOperation(manualCompactionId, compactSignal);
|
|
1435
|
-
await emit({ type: 'context.compacting', compactionId: manualCompactionId });
|
|
1436
|
-
}
|
|
1437
|
-
const compaction = manualCompaction;
|
|
1556
|
+
const snapshots = (sessionRuntime.requestSnapshots ??=
|
|
1557
|
+
new ExtensionRequestSnapshots());
|
|
1558
|
+
const snapshot = snapshots.record(selectedModel.id, request);
|
|
1438
1559
|
yield* streamModel(async function* (nativeSignal) {
|
|
1439
|
-
const
|
|
1440
|
-
? compaction.start({ start: (value) => selected.start(value, nativeSignal) }, request)
|
|
1441
|
-
: selected.start(request, nativeSignal);
|
|
1442
|
-
for await (const event of events) {
|
|
1560
|
+
for await (const event of selected.start(request, nativeSignal)) {
|
|
1443
1561
|
if (snapshot && event.type === 'completed' && event.reason !== 'cancelled')
|
|
1444
1562
|
snapshots.complete(snapshot);
|
|
1445
1563
|
yield event;
|
|
1446
1564
|
}
|
|
1447
|
-
},
|
|
1565
|
+
}, controller.signal);
|
|
1448
1566
|
},
|
|
1449
|
-
recoverySignal: () =>
|
|
1567
|
+
recoverySignal: () => controller.signal,
|
|
1450
1568
|
compactContext,
|
|
1451
|
-
|
|
1569
|
+
afterModel: async (closedPrefixLength) => {
|
|
1570
|
+
compactBoundary = closedPrefixLength;
|
|
1571
|
+
if (lastServerContextTokens !== undefined &&
|
|
1572
|
+
(lastServerContextTokens * 100) / selectedModel.contextWindowTokens >=
|
|
1573
|
+
AGENT_EXECUTION_POLICY.backgroundCompactionPercent &&
|
|
1574
|
+
!compactCoordinator.pending)
|
|
1575
|
+
startCompact({ async: true });
|
|
1576
|
+
},
|
|
1452
1577
|
observeContextTokens: (tokens) => {
|
|
1453
1578
|
lastServerContextTokens = tokens;
|
|
1454
1579
|
},
|
|
@@ -1459,7 +1584,18 @@ export function createSessionOpener(services) {
|
|
|
1459
1584
|
}
|
|
1460
1585
|
},
|
|
1461
1586
|
checkpoint: async (round, latestUsage) => {
|
|
1462
|
-
|
|
1587
|
+
compactBoundary = messages.length;
|
|
1588
|
+
const blocking = compactRequests.drain((input) => startCompact({
|
|
1589
|
+
...(input.prompt === undefined ? {} : { focus: input.prompt }),
|
|
1590
|
+
async: input.async === true
|
|
1591
|
+
}));
|
|
1592
|
+
if (blocking)
|
|
1593
|
+
await compactCoordinator.checkpoint(true);
|
|
1594
|
+
else
|
|
1595
|
+
await compactCoordinator.checkpoint(false).catch(() => {
|
|
1596
|
+
controller.signal.throwIfAborted();
|
|
1597
|
+
});
|
|
1598
|
+
if (!compactCoordinator.pending &&
|
|
1463
1599
|
sessionSource.type !== 'subagent' &&
|
|
1464
1600
|
latestUsage !== undefined) {
|
|
1465
1601
|
// Only a committed GC checkpoint may replace active context and invalidate continuation.
|
|
@@ -1511,51 +1647,23 @@ export function createSessionOpener(services) {
|
|
|
1511
1647
|
}
|
|
1512
1648
|
},
|
|
1513
1649
|
mailbox: {
|
|
1514
|
-
hasPending: () => inputs.hasBoundaryPending && !inputs.executing
|
|
1650
|
+
hasPending: () => inputs.hasBoundaryPending && !inputs.executing,
|
|
1515
1651
|
append: appendMailboxMessages,
|
|
1516
1652
|
close: () => {
|
|
1517
1653
|
acceptsMailbox = false;
|
|
1518
1654
|
}
|
|
1519
1655
|
}
|
|
1520
1656
|
});
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1657
|
+
const completed = await executionLoop.run();
|
|
1658
|
+
compactRequests.seal();
|
|
1659
|
+
compactRequests.drain((input) => startCompact({
|
|
1660
|
+
...(input.prompt === undefined ? {} : { focus: input.prompt }),
|
|
1661
|
+
async: input.async === true
|
|
1662
|
+
}));
|
|
1663
|
+
await compactCoordinator.checkpoint(true).catch(() => {
|
|
1664
|
+
controller.signal.throwIfAborted();
|
|
1665
|
+
});
|
|
1528
1666
|
finalAnswer = completed.finalAnswer;
|
|
1529
|
-
const compactSummary = mode === 'compact' ? finalAnswer.trim() : '';
|
|
1530
|
-
if (manualCompaction) {
|
|
1531
|
-
manualCompaction.signal.throwIfAborted();
|
|
1532
|
-
await manualCompaction.dispose();
|
|
1533
|
-
}
|
|
1534
|
-
if (mode === 'compact') {
|
|
1535
|
-
const compactRecord = await writeCompactionRecord(compactSummary, false, compactSignal, async (actual, options) => {
|
|
1536
|
-
const retainedModelContext = pendingAppends
|
|
1537
|
-
.slice(manualAppendBoundary)
|
|
1538
|
-
.map((entry) => entry.message);
|
|
1539
|
-
const replacementHistory = buildCompactedHistory(actual, compactionUserMessages, compactUserTokenLimit);
|
|
1540
|
-
const record = await store.compact(sessionId, {
|
|
1541
|
-
summary: actual,
|
|
1542
|
-
retainedModelContext,
|
|
1543
|
-
replacementHistory,
|
|
1544
|
-
modelId: selectedModel.id,
|
|
1545
|
-
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1546
|
-
...(completed.usage === undefined ? {} : { usage: completed.usage }),
|
|
1547
|
-
executionId,
|
|
1548
|
-
turnId
|
|
1549
|
-
}, options);
|
|
1550
|
-
messages.splice(0, messages.length, ...compactedHistoryMessages(replacementHistory), ...retainedModelContext);
|
|
1551
|
-
pendingAppends.length = 0;
|
|
1552
|
-
selected.resetContinuation?.();
|
|
1553
|
-
return record;
|
|
1554
|
-
});
|
|
1555
|
-
await resetCompactWorldState(compactRecord.recordId);
|
|
1556
|
-
}
|
|
1557
|
-
if (mode === 'compact' && manualCompactionId !== undefined)
|
|
1558
|
-
await emit({ type: 'context.compacted', compactionId: manualCompactionId });
|
|
1559
1667
|
};
|
|
1560
1668
|
if (mode === 'compact')
|
|
1561
1669
|
await performCompact({ focus: input.prompt }, async (effective, call) => {
|
|
@@ -1579,6 +1687,10 @@ export function createSessionOpener(services) {
|
|
|
1579
1687
|
catch (error) {
|
|
1580
1688
|
finalAnswer = executionLoop?.finalAnswer ?? finalAnswer;
|
|
1581
1689
|
acceptsMailbox = false;
|
|
1690
|
+
await compactCoordinator.close(error);
|
|
1691
|
+
compactRequests.close(new MarAgentError('MAR_AGENT_CANCELLED', 'Execution ended.'));
|
|
1692
|
+
if (sessionRuntime.compactRequests === compactRequests)
|
|
1693
|
+
delete sessionRuntime.compactRequests;
|
|
1582
1694
|
if (controller.signal.aborted) {
|
|
1583
1695
|
subagents?.endParentExecution(executionId);
|
|
1584
1696
|
await emit({ type: 'execution.cancelled' });
|
|
@@ -1602,6 +1714,9 @@ export function createSessionOpener(services) {
|
|
|
1602
1714
|
finally {
|
|
1603
1715
|
if (sessionRuntime.requestMessages?.executionId === executionId)
|
|
1604
1716
|
delete sessionRuntime.requestMessages;
|
|
1717
|
+
compactRequests.close(new MarAgentError('MAR_AGENT_CANCELLED', 'Execution ended.'));
|
|
1718
|
+
if (sessionRuntime.compactRequests === compactRequests)
|
|
1719
|
+
delete sessionRuntime.compactRequests;
|
|
1605
1720
|
if (sessionRuntime.appendedMessages?.executionId === executionId)
|
|
1606
1721
|
delete sessionRuntime.appendedMessages;
|
|
1607
1722
|
if (promptDefaults?.executionId === executionId)
|
|
@@ -1611,7 +1726,7 @@ export function createSessionOpener(services) {
|
|
|
1611
1726
|
if (sessionRuntime.toolSources === executionToolSources)
|
|
1612
1727
|
delete sessionRuntime.toolSources;
|
|
1613
1728
|
internal.signal?.removeEventListener('abort', abortSource);
|
|
1614
|
-
await
|
|
1729
|
+
await compactCoordinator.close(controller.signal.reason ?? new MarAgentError('MAR_AGENT_CANCELLED', 'Execution ended.'));
|
|
1615
1730
|
await selectedTurn?.close().catch(() => undefined);
|
|
1616
1731
|
try {
|
|
1617
1732
|
await closeModelAdapters(executionScopedAdapters);
|
|
@@ -1900,10 +2015,11 @@ export function createSessionOpener(services) {
|
|
|
1900
2015
|
id: sessionId,
|
|
1901
2016
|
run: (input) => execution('run', input),
|
|
1902
2017
|
plan: (input) => execution('plan', input),
|
|
1903
|
-
compact: (input = {}) =>
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
2018
|
+
compact: (input = {}) => sessionRuntime.compactRequests?.request(input) ??
|
|
2019
|
+
execution('compact', {
|
|
2020
|
+
prompt: input.prompt ?? DEFAULT_COMPACTION_FOCUS,
|
|
2021
|
+
...input
|
|
2022
|
+
}),
|
|
1907
2023
|
cancel: async (executionId) => active.get(`${sessionId}:${executionId}`)?.abort(),
|
|
1908
2024
|
startSubagentTurn: (turn) => execution(turn.role === 'explore' ? 'plan' : 'run', {
|
|
1909
2025
|
prompt: turn.prompt,
|