@myagentroam/agent 0.9.171 → 0.9.172
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/compaction.d.ts +16 -0
- package/dist/agent-core/extensions/compaction.js +42 -1
- package/dist/agent-core/model/anthropic-messages.js +40 -6
- package/dist/agent-core/model/attempt-diagnostics.d.ts +3 -0
- package/dist/agent-core/model/attempt-diagnostics.js +9 -0
- package/dist/agent-core/model/contracts.d.ts +9 -1
- package/dist/agent-core/model/openai-responses.js +4 -11
- package/dist/agent-core/prompts/resources.d.ts +0 -1
- package/dist/agent-core/prompts/resources.js +4 -14
- package/dist/agent-core/runtime/compaction/history.d.ts +3 -2
- package/dist/agent-core/runtime/compaction/history.js +42 -12
- package/dist/agent-core/runtime/compaction/operation.d.ts +5 -0
- package/dist/agent-core/runtime/compaction/operation.js +22 -2
- package/dist/agent-core/runtime/context/projection.js +1 -0
- package/dist/agent-core/runtime/context/request-budget.js +1 -1
- package/dist/agent-core/runtime/context/restore.d.ts +2 -2
- package/dist/agent-core/runtime/context/restore.js +24 -8
- package/dist/agent-core/runtime/context/world-state.d.ts +2 -5
- package/dist/agent-core/runtime/context/world-state.js +14 -14
- package/dist/agent-core/sdk/session.js +82 -49
- package/dist/agent-core/session/context-gc-replacements.js +14 -3
- package/dist/agent-core/session/jsonl-store.d.ts +9 -4
- package/dist/agent-core/session/jsonl-store.js +48 -1
- package/dist/agent-core/tools/code-mode/observations.js +19 -1
- package/dist/agent-core/tools/local/exec.d.ts +3 -1
- package/dist/agent-core/tools/local/exec.js +21 -0
- package/dist/agent-core/tools/local/registry.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/shared/model-text.d.ts +2 -1
- package/dist/shared/model-text.js +1 -0
- package/package.json +1 -1
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { retainedSessionResourcesUpdate } from '../../prompts/resources.js';
|
|
2
1
|
import { compactSummaryFromCheckpoint } from '../../session/jsonl-store.js';
|
|
3
2
|
export function insertContextualWorldState(messages, entries) {
|
|
4
3
|
const result = [...messages];
|
|
5
4
|
let offset = 0;
|
|
6
5
|
for (const entry of entries) {
|
|
7
6
|
const insertionIndex = Math.max(0, Math.min(entry.index + offset, result.length));
|
|
8
|
-
result.splice(insertionIndex, 0, {
|
|
7
|
+
result.splice(insertionIndex, 0, {
|
|
8
|
+
role: 'user',
|
|
9
|
+
content: entry.content,
|
|
10
|
+
contextKind: 'contextual'
|
|
11
|
+
});
|
|
9
12
|
offset++;
|
|
10
13
|
}
|
|
11
14
|
return result;
|
|
@@ -87,24 +90,18 @@ export async function persistContextualWorldState(store, sessionId, state) {
|
|
|
87
90
|
entries: state.entries
|
|
88
91
|
});
|
|
89
92
|
}
|
|
90
|
-
export function compactHistoryMayContainRetainedResources(records) {
|
|
91
|
-
return records.some((record) => compactSummaryFromCheckpoint(record)?.includes('# Retained Session resources'));
|
|
92
|
-
}
|
|
93
93
|
export function updateContextualWorldState(state, index, current) {
|
|
94
94
|
const entries = [...state.entries];
|
|
95
95
|
if (!state.initialized || state.instructionSnapshot !== current.instructionSnapshot) {
|
|
96
96
|
if (current.instructionContent !== undefined)
|
|
97
97
|
entries.push({ index, kind: 'instructions', content: current.instructionContent });
|
|
98
98
|
}
|
|
99
|
-
const resourceContent = retainedSessionResourcesUpdate(current.resourceSnapshot, state.initialized ? state.resourceSnapshot : undefined, current.previousMayContainResources);
|
|
100
|
-
if (resourceContent !== undefined)
|
|
101
|
-
entries.push({ index, kind: 'resources', content: resourceContent });
|
|
102
99
|
return {
|
|
103
100
|
generation: state.generation,
|
|
104
101
|
mcpSnapshot: state.mcpSnapshot,
|
|
105
102
|
initialized: true,
|
|
106
103
|
instructionSnapshot: current.instructionSnapshot,
|
|
107
|
-
resourceSnapshot:
|
|
104
|
+
resourceSnapshot: state.resourceSnapshot,
|
|
108
105
|
entries
|
|
109
106
|
};
|
|
110
107
|
}
|
|
@@ -112,9 +109,8 @@ export function resetContextualWorldState(generation, index, current) {
|
|
|
112
109
|
const entries = [];
|
|
113
110
|
if (current.instructionContent !== undefined)
|
|
114
111
|
entries.push({ index, kind: 'instructions', content: current.instructionContent });
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
entries.push({ index, kind: 'resources', content: resourceContent });
|
|
112
|
+
if (current.resourceSnapshot !== undefined)
|
|
113
|
+
entries.push({ index, kind: 'resources', content: current.resourceSnapshot });
|
|
118
114
|
return {
|
|
119
115
|
generation,
|
|
120
116
|
initialized: true,
|
|
@@ -124,9 +120,13 @@ export function resetContextualWorldState(generation, index, current) {
|
|
|
124
120
|
};
|
|
125
121
|
}
|
|
126
122
|
export function contextualInstructionInsertIndex(messages) {
|
|
127
|
-
let index = messages.findLastIndex((message) => message.role === 'user' &&
|
|
123
|
+
let index = messages.findLastIndex((message) => message.role === 'user' &&
|
|
124
|
+
message.contextKind === undefined &&
|
|
125
|
+
message.metadata?.source !== 'extension');
|
|
126
|
+
if (index < 0)
|
|
127
|
+
index = messages.findLastIndex((message) => message.contextKind === 'summary');
|
|
128
128
|
if (index < 0)
|
|
129
|
-
return
|
|
129
|
+
return messages.length;
|
|
130
130
|
if (index > 0 && messages[index - 1]?.contextKind === 'environment')
|
|
131
131
|
index--;
|
|
132
132
|
return index;
|
|
@@ -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 {
|
|
5
|
+
import { contextualInstructionInsertIndex, insertContextualWorldState, latestContextualWorldStateGeneration, parsePersistedContextualWorldState, persistContextualWorldState, resetContextualWorldState, updateContextualWorldState } from '../runtime/context/world-state.js';
|
|
6
6
|
import { eventForPersistence, publicModelUsage } from '../runtime/event-projection.js';
|
|
7
7
|
import { ExecutionLoop } from '../runtime/execution.js';
|
|
8
8
|
import { closeModelAdapters, createModelTurnSession } from './model-runtime.js';
|
|
@@ -11,7 +11,7 @@ import { discoveredMcpToolNames, rebindMcpToolSearchOutputs } from '../tools/mcp
|
|
|
11
11
|
import { currentExecutionImages } from '../tools/output-projection.js';
|
|
12
12
|
import { createHash, randomUUID } from 'node:crypto';
|
|
13
13
|
import { ExecutionToolSources } from './extension-tools.js';
|
|
14
|
-
import { compactExtensionMessages, compactExtensionResult } from '../extensions/compaction.js';
|
|
14
|
+
import { compactExtensionMessages, compactExtensionResult, compactExtensionDiagnostic } from '../extensions/compaction.js';
|
|
15
15
|
import { ExtensionRequestBridge, ExtensionRequestSnapshots } from '../extensions/model-request.js';
|
|
16
16
|
import { normalizeSessionMessagesInput, sessionMessagesPage } from '../extensions/session-messages.js';
|
|
17
17
|
import { transformCoreModelStream } from '../extensions/model-stream.js';
|
|
@@ -38,7 +38,7 @@ import { AGENT_EXECUTION_POLICY } from '../runtime/execution-policy.js';
|
|
|
38
38
|
import { loadAgentInstructions, renderAgentInstructions } from '../runtime/context/instructions.js';
|
|
39
39
|
import { normalizeMessagesForModel } from '../runtime/context/normalize.js';
|
|
40
40
|
import { RolloutBudget } from '../runtime/rollout-budget.js';
|
|
41
|
-
import { compactSummaryFromCheckpoint } from '../session/jsonl-store.js';
|
|
41
|
+
import { compactSummaryFromCheckpoint, inputMetadataFromRecord } from '../session/jsonl-store.js';
|
|
42
42
|
import { SubagentSessionController } from '../subagent/session-controller.js';
|
|
43
43
|
import { agentStartToolDefinitionWithModels } from '../tools/agent/agent-start.js';
|
|
44
44
|
import { allowsDirectTool, allowsToolCaller, toolCallers } from '../tools/callers.js';
|
|
@@ -386,7 +386,6 @@ export function createSessionOpener(services) {
|
|
|
386
386
|
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
387
387
|
}
|
|
388
388
|
const compactMayContainAgentInstructions = contextRecords.some((record) => compactSummaryFromCheckpoint(record) !== undefined);
|
|
389
|
-
const compactMayContainRetainedResources = compactHistoryMayContainRetainedResources(contextRecords);
|
|
390
389
|
const restored = await restoreMessages(store, sessionId, contextRecords, {
|
|
391
390
|
includeImages: mode !== 'compact'
|
|
392
391
|
});
|
|
@@ -440,9 +439,14 @@ export function createSessionOpener(services) {
|
|
|
440
439
|
executionId,
|
|
441
440
|
turnId
|
|
442
441
|
}, { signal: call.signal });
|
|
443
|
-
|
|
442
|
+
const inputMetadata = inputMetadataFromRecord(record);
|
|
443
|
+
compactionUserMessages.push({
|
|
444
|
+
content: content.modelText ?? content.text,
|
|
445
|
+
metadata: inputMetadata
|
|
446
|
+
});
|
|
447
|
+
committed(content, record.recordId, inputMetadata);
|
|
444
448
|
for (const text of content.modelContext ?? content.context ?? [])
|
|
445
|
-
messages.push({ role: 'user', content: text });
|
|
449
|
+
messages.push({ role: 'user', content: text, contextKind: 'contextual' });
|
|
446
450
|
});
|
|
447
451
|
};
|
|
448
452
|
const appendMailboxMessages = async () => inputs.drain(async (entry, request, call) => {
|
|
@@ -476,12 +480,13 @@ export function createSessionOpener(services) {
|
|
|
476
480
|
: {
|
|
477
481
|
source: extensionInputSource(call, request.input.provenance, request.input.modelAttribution),
|
|
478
482
|
...(parent?.delivery ? { messageId: parent.delivery.messageId } : {})
|
|
479
|
-
}, call, (actual, recordId) => {
|
|
483
|
+
}, call, (actual, recordId, metadata) => {
|
|
480
484
|
outcome = { changed: true, executionId, recordId };
|
|
481
485
|
recordSessionInputCommit(entry, outcome);
|
|
482
486
|
messages.push({
|
|
483
487
|
role: 'user',
|
|
484
488
|
content: actual.modelText ?? actual.text,
|
|
489
|
+
metadata,
|
|
485
490
|
...(actual.images?.length
|
|
486
491
|
? {
|
|
487
492
|
images: actual.images.map(({ mimeType, dataBase64 }) => ({
|
|
@@ -739,21 +744,26 @@ export function createSessionOpener(services) {
|
|
|
739
744
|
subagents: subagents?.listSessionResources() ?? []
|
|
740
745
|
};
|
|
741
746
|
};
|
|
742
|
-
|
|
747
|
+
const resetCompactWorldState = async (generation) => {
|
|
748
|
+
agentInstructionInsertIndex = contextualInstructionInsertIndex(messages);
|
|
749
|
+
contextualWorldState = resetContextualWorldState(generation, agentInstructionInsertIndex, {
|
|
750
|
+
instructionSnapshot: currentInstructionSnapshot,
|
|
751
|
+
instructionContent: renderAgentInstructions(instructionEntries, true),
|
|
752
|
+
resourceSnapshot: retainedSessionResourcesSnapshot(await loadRetainedSessionResources())
|
|
753
|
+
});
|
|
754
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
755
|
+
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
756
|
+
};
|
|
757
|
+
// A missing sidecar is rebuilt only for the latest Compact, never for a GC boundary.
|
|
758
|
+
if (!contextualWorldState.initialized &&
|
|
759
|
+
contextRecords.some((record) => record.recordId === contextualWorldStateGeneration &&
|
|
760
|
+
compactSummaryFromCheckpoint(record) !== undefined))
|
|
761
|
+
await resetCompactWorldState(contextualWorldStateGeneration);
|
|
743
762
|
const previousContextualWorldState = contextualWorldState;
|
|
744
763
|
contextualWorldState = updateContextualWorldState(contextualWorldState, agentInstructionInsertIndex, {
|
|
745
764
|
instructionSnapshot: currentInstructionSnapshot,
|
|
746
765
|
instructionContent: renderAgentInstructions(instructionEntries, compactMayContainAgentInstructions ||
|
|
747
|
-
contextualWorldState.instructionSnapshot !== undefined)
|
|
748
|
-
resourceSnapshot: currentResourceSnapshot,
|
|
749
|
-
previousMayContainResources: (!contextualWorldState.initialized && compactMayContainRetainedResources) ||
|
|
750
|
-
(host.listSessionResources !== undefined &&
|
|
751
|
-
currentResourceSnapshot === undefined &&
|
|
752
|
-
messages
|
|
753
|
-
.slice(contextualWorldState.entries.findLast((entry) => entry.kind === 'resources')
|
|
754
|
-
?.index ?? 0)
|
|
755
|
-
.some((message) => message.role === 'tool_call' &&
|
|
756
|
-
['exec', 'code_exec', 'agent_start'].includes(message.name ?? '')))
|
|
766
|
+
contextualWorldState.instructionSnapshot !== undefined)
|
|
757
767
|
});
|
|
758
768
|
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
759
769
|
if (!isDeepStrictEqual(previousContextualWorldState, contextualWorldState))
|
|
@@ -958,14 +968,17 @@ export function createSessionOpener(services) {
|
|
|
958
968
|
? {}
|
|
959
969
|
: { inputSource: internal.inputSource }),
|
|
960
970
|
...(input.clientMessageId ? { clientMessageId: input.clientMessageId } : {})
|
|
961
|
-
}, call, (actual, recordId) => {
|
|
971
|
+
}, call, (actual, recordId, metadata) => {
|
|
962
972
|
entered = true;
|
|
963
|
-
compactionUserMessages.push(actual.text);
|
|
964
973
|
modelInputImages = actual.images?.map(({ mimeType, dataBase64 }) => ({
|
|
965
974
|
mimeType,
|
|
966
975
|
dataBase64
|
|
967
976
|
}));
|
|
968
|
-
messages.push({
|
|
977
|
+
messages.push({
|
|
978
|
+
role: 'user',
|
|
979
|
+
content: actual.modelText ?? actual.text,
|
|
980
|
+
metadata
|
|
981
|
+
});
|
|
969
982
|
currentExecutionUserIndex = messages.length - 1;
|
|
970
983
|
internal.inputCommitted?.(recordId);
|
|
971
984
|
internal.delivery?.applied();
|
|
@@ -1019,6 +1032,8 @@ export function createSessionOpener(services) {
|
|
|
1019
1032
|
return undefined;
|
|
1020
1033
|
const summaryTokenBudget = Math.min(10_000, selectedModel.maxOutputTokens, Math.max(1, Math.floor(selectedModel.contextWindowTokens / 4)));
|
|
1021
1034
|
const highDensityCompaction = selectedModel.highDensityCompaction;
|
|
1035
|
+
let diagnosticReports = 0;
|
|
1036
|
+
let acceptsDiagnostics = true;
|
|
1022
1037
|
try {
|
|
1023
1038
|
const result = await compaction.generate((signal) => operation((call) => coreExtensions.hooks.invoke('compact.generate', Object.freeze({
|
|
1024
1039
|
operationId: call.operationId,
|
|
@@ -1026,15 +1041,33 @@ export function createSessionOpener(services) {
|
|
|
1026
1041
|
messages: compactExtensionMessages(history),
|
|
1027
1042
|
...(focus === undefined ? {} : { focus }),
|
|
1028
1043
|
summaryTokenBudget,
|
|
1029
|
-
getPrompt: () => buildCompactionMessages('', highDensityCompaction)[1].content
|
|
1044
|
+
getPrompt: () => buildCompactionMessages('', highDensityCompaction)[1].content,
|
|
1045
|
+
reportDiagnostic: async (value) => {
|
|
1046
|
+
if (!acceptsDiagnostics || ++diagnosticReports > 8)
|
|
1047
|
+
return;
|
|
1048
|
+
try {
|
|
1049
|
+
const diagnostic = compactExtensionDiagnostic(value);
|
|
1050
|
+
if (diagnostic)
|
|
1051
|
+
await compaction.observeExtension(diagnostic);
|
|
1052
|
+
}
|
|
1053
|
+
catch {
|
|
1054
|
+
// Diagnostic failures must not change compaction or fallback.
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1030
1057
|
}), Object.freeze({ ...call, signal }), async () => undefined)));
|
|
1031
1058
|
compaction.signal.throwIfAborted();
|
|
1032
|
-
|
|
1059
|
+
const handled = compactExtensionResult(result, summaryTokenBudget);
|
|
1060
|
+
await compaction.finishExtension(handled ? 'HANDLED' : result === undefined ? 'DECLINED' : 'INVALID_RESULT');
|
|
1061
|
+
return handled;
|
|
1033
1062
|
}
|
|
1034
1063
|
catch {
|
|
1064
|
+
await compaction.finishExtension('FAILED');
|
|
1035
1065
|
compaction.signal.throwIfAborted();
|
|
1036
1066
|
return undefined;
|
|
1037
1067
|
}
|
|
1068
|
+
finally {
|
|
1069
|
+
acceptsDiagnostics = false;
|
|
1070
|
+
}
|
|
1038
1071
|
};
|
|
1039
1072
|
let manualExtension;
|
|
1040
1073
|
if (mode === 'compact' && coreExtensions.hooks.hasInterceptors('compact.generate')) {
|
|
@@ -1099,7 +1132,7 @@ export function createSessionOpener(services) {
|
|
|
1099
1132
|
return false;
|
|
1100
1133
|
let compactSummary = '';
|
|
1101
1134
|
const current = messages.at(-1);
|
|
1102
|
-
const retainCurrent = current.role === 'user' && current.contextKind
|
|
1135
|
+
const retainCurrent = current.role === 'user' && current.contextKind === undefined;
|
|
1103
1136
|
const compactHistory = retainCurrent ? messages.slice(0, -1) : [...messages];
|
|
1104
1137
|
const appendBoundary = pendingAppends.length;
|
|
1105
1138
|
const compactSystemPrompt = await operation((call) => coreExtensions.compose(promptComposition(executionTools, 'run'), call));
|
|
@@ -1188,11 +1221,21 @@ export function createSessionOpener(services) {
|
|
|
1188
1221
|
if (!compactSummary)
|
|
1189
1222
|
throw new MarAgentError('MAR_AGENT_COMPACT_FAILED', 'Automatic compact failed.');
|
|
1190
1223
|
rolloutBudget?.recordUsage(latestUsage);
|
|
1191
|
-
let replacementHistory = buildCompactedHistory(compactSummary, retainCurrent ? compactionUserMessages.slice(0, -1) : compactionUserMessages, compactUserTokenLimit, retainCurrent
|
|
1224
|
+
let replacementHistory = buildCompactedHistory(compactSummary, retainCurrent ? compactionUserMessages.slice(0, -1) : compactionUserMessages, compactUserTokenLimit, retainCurrent
|
|
1225
|
+
? {
|
|
1226
|
+
content: current.content,
|
|
1227
|
+
...(current.metadata ? { metadata: current.metadata } : {})
|
|
1228
|
+
}
|
|
1229
|
+
: undefined);
|
|
1192
1230
|
signal.throwIfAborted();
|
|
1193
1231
|
const compactRecord = await writeCompactionRecord(compactSummary, true, signal, async (actual, options) => {
|
|
1194
1232
|
compactSummary = actual;
|
|
1195
|
-
replacementHistory = buildCompactedHistory(actual, retainCurrent ? compactionUserMessages.slice(0, -1) : compactionUserMessages, compactUserTokenLimit, retainCurrent
|
|
1233
|
+
replacementHistory = buildCompactedHistory(actual, retainCurrent ? compactionUserMessages.slice(0, -1) : compactionUserMessages, compactUserTokenLimit, retainCurrent
|
|
1234
|
+
? {
|
|
1235
|
+
content: current.content,
|
|
1236
|
+
...(current.metadata ? { metadata: current.metadata } : {})
|
|
1237
|
+
}
|
|
1238
|
+
: undefined);
|
|
1196
1239
|
const retainedModelContext = pendingAppends
|
|
1197
1240
|
.slice(appendBoundary)
|
|
1198
1241
|
.map((entry) => entry.message);
|
|
@@ -1218,18 +1261,12 @@ export function createSessionOpener(services) {
|
|
|
1218
1261
|
projectedExecutionBudgetStage = undefined;
|
|
1219
1262
|
recordedEnvironment = executionEnvironment;
|
|
1220
1263
|
compactionUserMessages = replacementHistory
|
|
1221
|
-
.filter((message) => message.kind
|
|
1222
|
-
.map((message) =>
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
instructionContent: renderAgentInstructions(instructionEntries, true),
|
|
1228
|
-
resourceSnapshot: currentResourceSnapshot,
|
|
1229
|
-
previousMayContainResources: compactSummary.includes('# Retained Session resources')
|
|
1230
|
-
});
|
|
1231
|
-
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
1232
|
-
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
1264
|
+
.filter((message) => message.kind !== 'summary')
|
|
1265
|
+
.map((message) => ({
|
|
1266
|
+
content: message.content,
|
|
1267
|
+
...(message.metadata ? { metadata: { ...message.metadata } } : {})
|
|
1268
|
+
}));
|
|
1269
|
+
await resetCompactWorldState(compactRecord.recordId);
|
|
1233
1270
|
lastServerContextTokens = undefined;
|
|
1234
1271
|
lastServerUsage = undefined;
|
|
1235
1272
|
requestReasoningEffort = reasoningEffort;
|
|
@@ -1399,17 +1436,10 @@ export function createSessionOpener(services) {
|
|
|
1399
1436
|
projectedExecutionBudgetStage = undefined;
|
|
1400
1437
|
recordedEnvironment = refreshed.environmentState;
|
|
1401
1438
|
compactionUserMessages = [...refreshed.userMessages];
|
|
1402
|
-
agentInstructionInsertIndex =
|
|
1403
|
-
refreshed.currentTurnUserIndex ?? Math.max(0, messages.length - 1);
|
|
1404
|
-
if (agentInstructionInsertIndex &&
|
|
1405
|
-
messages[agentInstructionInsertIndex - 1]?.contextKind === 'environment')
|
|
1406
|
-
agentInstructionInsertIndex--;
|
|
1407
|
-
currentResourceSnapshot = retainedSessionResourcesSnapshot(await loadRetainedSessionResources());
|
|
1439
|
+
agentInstructionInsertIndex = contextualInstructionInsertIndex(messages);
|
|
1408
1440
|
contextualWorldState = resetContextualWorldState(latestContextualWorldStateGeneration(committed.records), agentInstructionInsertIndex, {
|
|
1409
1441
|
instructionSnapshot: currentInstructionSnapshot,
|
|
1410
|
-
instructionContent: renderAgentInstructions(instructionEntries, committed.records.some((record) => compactSummaryFromCheckpoint(record) !== undefined))
|
|
1411
|
-
resourceSnapshot: currentResourceSnapshot,
|
|
1412
|
-
previousMayContainResources: compactHistoryMayContainRetainedResources(committed.records)
|
|
1442
|
+
instructionContent: renderAgentInstructions(instructionEntries, committed.records.some((record) => compactSummaryFromCheckpoint(record) !== undefined))
|
|
1413
1443
|
});
|
|
1414
1444
|
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
1415
1445
|
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
@@ -1439,8 +1469,8 @@ export function createSessionOpener(services) {
|
|
|
1439
1469
|
manualCompaction.signal.throwIfAborted();
|
|
1440
1470
|
await manualCompaction.dispose();
|
|
1441
1471
|
}
|
|
1442
|
-
if (mode === 'compact')
|
|
1443
|
-
await writeCompactionRecord(compactSummary, false, compactSignal, async (actual, options) => {
|
|
1472
|
+
if (mode === 'compact') {
|
|
1473
|
+
const compactRecord = await writeCompactionRecord(compactSummary, false, compactSignal, async (actual, options) => {
|
|
1444
1474
|
const retainedModelContext = pendingAppends
|
|
1445
1475
|
.slice(manualAppendBoundary)
|
|
1446
1476
|
.map((entry) => entry.message);
|
|
@@ -1460,6 +1490,8 @@ export function createSessionOpener(services) {
|
|
|
1460
1490
|
selected.resetContinuation?.();
|
|
1461
1491
|
return record;
|
|
1462
1492
|
});
|
|
1493
|
+
await resetCompactWorldState(compactRecord.recordId);
|
|
1494
|
+
}
|
|
1463
1495
|
if (mode === 'compact' && manualCompactionId !== undefined)
|
|
1464
1496
|
await emit({ type: 'context.compacted', compactionId: manualCompactionId });
|
|
1465
1497
|
};
|
|
@@ -1861,6 +1893,7 @@ function projectAppendedModelMessage(input) {
|
|
|
1861
1893
|
return undefined;
|
|
1862
1894
|
return {
|
|
1863
1895
|
role: 'user',
|
|
1896
|
+
contextKind: 'contextual',
|
|
1864
1897
|
content: input.content,
|
|
1865
1898
|
...(input.textBlocks === undefined
|
|
1866
1899
|
? {}
|
|
@@ -222,16 +222,27 @@ export function parseContextGcExecResult(value) {
|
|
|
222
222
|
parsed.status !== 'completed' &&
|
|
223
223
|
parsed.status !== 'cancelled') ||
|
|
224
224
|
typeof parsed.stdout !== 'string' ||
|
|
225
|
-
typeof parsed.stderr !== 'string')
|
|
225
|
+
(parsed.stderr !== undefined && typeof parsed.stderr !== 'string') ||
|
|
226
|
+
(parsed.truncated === true &&
|
|
227
|
+
(parsed.stdoutBytes === undefined || parsed.stderrBytes === undefined)))
|
|
226
228
|
return undefined;
|
|
227
|
-
const
|
|
229
|
+
const stderr = parsed.stderr === undefined ? '' : parsed.stderr;
|
|
230
|
+
// Native exec bodies omit only empty/default fields and exactly derivable byte counts.
|
|
231
|
+
const defaults = {
|
|
232
|
+
truncated: false,
|
|
233
|
+
stdoutBytes: Buffer.byteLength(parsed.stdout),
|
|
234
|
+
stderrBytes: Buffer.byteLength(stderr),
|
|
235
|
+
stdoutDroppedBytes: 0,
|
|
236
|
+
stderrDroppedBytes: 0
|
|
237
|
+
};
|
|
238
|
+
const metadata = parseContextGcExecMetadata({ ...defaults, ...parsed });
|
|
228
239
|
return metadata
|
|
229
240
|
? {
|
|
230
241
|
source: 'STRUCTURED',
|
|
231
242
|
...metadata,
|
|
232
243
|
status: parsed.status,
|
|
233
244
|
stdout: parsed.stdout,
|
|
234
|
-
stderr
|
|
245
|
+
stderr
|
|
235
246
|
}
|
|
236
247
|
: undefined;
|
|
237
248
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CoreCheckpoint, type CoreJsonValue } from '../extensions/data.js';
|
|
2
|
-
import type { ModelMessage, ModelUsage } from '../model/contracts.js';
|
|
2
|
+
import type { ModelInputMetadata, ModelMessage, ModelUsage } from '../model/contracts.js';
|
|
3
3
|
import type { EnvironmentContextState } from '../runtime/context/contracts.js';
|
|
4
4
|
import { type CodeModeStateEntry } from '../tools/code-mode/state.js';
|
|
5
5
|
import { type TodoSnapshot } from '../tools/agent/todo.js';
|
|
@@ -29,10 +29,13 @@ export interface SessionExecutionState {
|
|
|
29
29
|
todo: TodoSnapshot;
|
|
30
30
|
contextRecords: SessionRecord[];
|
|
31
31
|
}
|
|
32
|
-
export interface
|
|
33
|
-
role: 'user';
|
|
32
|
+
export interface CompactUserInput {
|
|
34
33
|
content: string;
|
|
35
|
-
|
|
34
|
+
metadata?: ModelInputMetadata;
|
|
35
|
+
}
|
|
36
|
+
export interface CompactHistoryMessage extends CompactUserInput {
|
|
37
|
+
role: 'user';
|
|
38
|
+
kind: 'user_input' | 'extension_input' | 'summary';
|
|
36
39
|
}
|
|
37
40
|
export interface SessionInputImage {
|
|
38
41
|
readonly name: string;
|
|
@@ -247,3 +250,5 @@ export declare class JsonlSessionStore {
|
|
|
247
250
|
}
|
|
248
251
|
export declare function compactSummaryFromCheckpoint(record: SessionRecord | undefined): string | undefined;
|
|
249
252
|
export declare function replacementHistoryFromCheckpoint(record: SessionRecord): CompactHistoryMessage[] | undefined;
|
|
253
|
+
export declare function parseModelInputMetadata(value: unknown): ModelInputMetadata | undefined;
|
|
254
|
+
export declare function inputMetadataFromRecord(record: SessionRecord): ModelInputMetadata;
|
|
@@ -2455,11 +2455,58 @@ export function replacementHistoryFromCheckpoint(record) {
|
|
|
2455
2455
|
typeof message === 'object' &&
|
|
2456
2456
|
message.role === 'user' &&
|
|
2457
2457
|
typeof message.content === 'string' &&
|
|
2458
|
+
(message.metadata === undefined ||
|
|
2459
|
+
(parseModelInputMetadata(message.metadata) !== undefined &&
|
|
2460
|
+
(message.kind === 'extension_input'
|
|
2461
|
+
? message.metadata.source === 'extension'
|
|
2462
|
+
: message.kind === 'user_input' && message.metadata.source !== 'extension'))) &&
|
|
2458
2463
|
(message.kind === 'user_input' ||
|
|
2464
|
+
message.kind === 'extension_input' ||
|
|
2459
2465
|
(message.kind === 'summary' && message.content.trim().length > 0))) ||
|
|
2460
2466
|
history.filter((message) => message.kind === 'summary').length !== 1)
|
|
2461
2467
|
return undefined;
|
|
2462
|
-
return history.map(({ role, content, kind }) => ({
|
|
2468
|
+
return history.map(({ role, content, kind, metadata }) => ({
|
|
2469
|
+
role,
|
|
2470
|
+
content,
|
|
2471
|
+
kind,
|
|
2472
|
+
...(parseModelInputMetadata(metadata) === undefined
|
|
2473
|
+
? {}
|
|
2474
|
+
: { metadata: parseModelInputMetadata(metadata) })
|
|
2475
|
+
}));
|
|
2476
|
+
}
|
|
2477
|
+
export function parseModelInputMetadata(value) {
|
|
2478
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
2479
|
+
return undefined;
|
|
2480
|
+
const metadata = value;
|
|
2481
|
+
if (metadata.source !== 'user' &&
|
|
2482
|
+
metadata.source !== 'parent_agent' &&
|
|
2483
|
+
metadata.source !== 'extension')
|
|
2484
|
+
return undefined;
|
|
2485
|
+
return {
|
|
2486
|
+
source: metadata.source,
|
|
2487
|
+
...(typeof metadata.recordId === 'string' && metadata.recordId.length <= 128
|
|
2488
|
+
? { recordId: metadata.recordId }
|
|
2489
|
+
: {}),
|
|
2490
|
+
...(typeof metadata.extensionId === 'string' && metadata.extensionId.length <= 128
|
|
2491
|
+
? { extensionId: metadata.extensionId }
|
|
2492
|
+
: {}),
|
|
2493
|
+
...(metadata.truncated === true ? { truncated: true } : {})
|
|
2494
|
+
};
|
|
2495
|
+
}
|
|
2496
|
+
export function inputMetadataFromRecord(record) {
|
|
2497
|
+
const payload = record.payload;
|
|
2498
|
+
const source = payload.source;
|
|
2499
|
+
return {
|
|
2500
|
+
source: record.type === 'extension.input' || payload.inputSource === 'extension'
|
|
2501
|
+
? 'extension'
|
|
2502
|
+
: payload.inputSource === 'parent_agent'
|
|
2503
|
+
? 'parent_agent'
|
|
2504
|
+
: 'user',
|
|
2505
|
+
recordId: record.recordId,
|
|
2506
|
+
...(typeof source?.extensionId === 'string' && source.extensionId.length <= 128
|
|
2507
|
+
? { extensionId: source.extensionId }
|
|
2508
|
+
: {})
|
|
2509
|
+
};
|
|
2463
2510
|
}
|
|
2464
2511
|
function isCompactCheckpoint(record) {
|
|
2465
2512
|
return compactSummaryFromCheckpoint(record) !== undefined;
|
|
@@ -145,17 +145,35 @@ export function newObservationId() {
|
|
|
145
145
|
return randomUUID();
|
|
146
146
|
}
|
|
147
147
|
export function observationModelParts(message) {
|
|
148
|
-
if (message.textBlocks !== undefined ||
|
|
148
|
+
if (message.textBlocks !== undefined || message.observations === undefined)
|
|
149
149
|
return undefined;
|
|
150
150
|
const prefix = [];
|
|
151
151
|
try {
|
|
152
152
|
const parsed = JSON.parse(message.content ?? '');
|
|
153
153
|
if (parsed && !Array.isArray(parsed) && typeof parsed === 'object') {
|
|
154
154
|
const { observations: _observations, ...metadata } = parsed;
|
|
155
|
+
const cellEnvelope = typeof metadata.cellId === 'string' &&
|
|
156
|
+
typeof metadata.status === 'string' &&
|
|
157
|
+
Array.isArray(_observations);
|
|
158
|
+
if (!message.observations.length && !cellEnvelope)
|
|
159
|
+
return undefined;
|
|
160
|
+
if (cellEnvelope) {
|
|
161
|
+
// Keep execution facts in storage; project only actionable lifecycle metadata.
|
|
162
|
+
delete metadata.toolCalls;
|
|
163
|
+
delete metadata.outputBytes;
|
|
164
|
+
if (metadata.outputDroppedBytes === 0)
|
|
165
|
+
delete metadata.outputDroppedBytes;
|
|
166
|
+
if (metadata.truncated === false)
|
|
167
|
+
delete metadata.truncated;
|
|
168
|
+
if (metadata.cached === false)
|
|
169
|
+
delete metadata.cached;
|
|
170
|
+
}
|
|
155
171
|
prefix.push({ type: 'text', text: JSON.stringify(metadata) });
|
|
156
172
|
}
|
|
157
173
|
}
|
|
158
174
|
catch { }
|
|
175
|
+
if (!message.observations.length && !prefix.length)
|
|
176
|
+
return undefined;
|
|
159
177
|
return [
|
|
160
178
|
...prefix,
|
|
161
179
|
...message.observations.flatMap((value) => {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { type LocalProcessExecutor } from '../../host/local-process-executor.js';
|
|
2
2
|
import type { ClientToolDefinition } from '../../model/contracts.js';
|
|
3
|
-
import type { ExecResult } from '../contracts.js';
|
|
3
|
+
import type { ExecResult, ToolExecutionResult } from '../contracts.js';
|
|
4
4
|
import { WorkspacePathResolver } from '../shared/path-resolver.js';
|
|
5
5
|
import { type CoreProcessInput, type CoreProcessHandle } from '../../extensions/processes.js';
|
|
6
6
|
import type { CoreOperationContext } from '../../extensions/operation.js';
|
|
7
7
|
export type { ExecResult } from '../contracts.js';
|
|
8
|
+
/** Share the model-facing body across direct calls and original Code Mode observations. */
|
|
9
|
+
export declare function formatExecResult(result: ExecResult): ToolExecutionResult;
|
|
8
10
|
export type ExecInput = {
|
|
9
11
|
action?: 'start';
|
|
10
12
|
command: string;
|
|
@@ -4,6 +4,27 @@ import { MarAgentError } from '../../error.js';
|
|
|
4
4
|
import { directLocalProcessExecutor, signalProcessTree } from '../../host/local-process-executor.js';
|
|
5
5
|
import { TOOL_EXECUTION_LIMITS } from '../execution-limits.js';
|
|
6
6
|
import { validateCoreProcessInput } from '../../extensions/processes.js';
|
|
7
|
+
/** Share the model-facing body across direct calls and original Code Mode observations. */
|
|
8
|
+
export function formatExecResult(result) {
|
|
9
|
+
const visible = { ...result };
|
|
10
|
+
if (result.stderr === '')
|
|
11
|
+
delete visible.stderr;
|
|
12
|
+
if (!result.truncated) {
|
|
13
|
+
delete visible.truncated;
|
|
14
|
+
// Incremental output may be smaller than the cumulative stream counts.
|
|
15
|
+
if (result.stdoutBytes === Buffer.byteLength(result.stdout))
|
|
16
|
+
delete visible.stdoutBytes;
|
|
17
|
+
if (result.stderrBytes === Buffer.byteLength(result.stderr))
|
|
18
|
+
delete visible.stderrBytes;
|
|
19
|
+
}
|
|
20
|
+
if (result.stdoutDroppedBytes === 0)
|
|
21
|
+
delete visible.stdoutDroppedBytes;
|
|
22
|
+
if (result.stderrDroppedBytes === 0)
|
|
23
|
+
delete visible.stderrDroppedBytes;
|
|
24
|
+
if (result.cached === false)
|
|
25
|
+
delete visible.cached;
|
|
26
|
+
return { content: JSON.stringify(visible), data: result, truncated: result.truncated };
|
|
27
|
+
}
|
|
7
28
|
export const execToolDefinition = {
|
|
8
29
|
name: 'exec',
|
|
9
30
|
allowedCallers: ['direct', 'programmatic'],
|
|
@@ -3,7 +3,7 @@ import { LocalFileAccess } from '../../host/local-file-access.js';
|
|
|
3
3
|
import { ApplyPatchTool, applyPatchToolInput, applyPatchToolDefinition } from './apply-patch.js';
|
|
4
4
|
import { CodeModeTool, codeModeToolDefinition, codeExecWaitToolDefinition } from '../code-mode/index.js';
|
|
5
5
|
import { normalizeToolInput } from '../input.js';
|
|
6
|
-
import { ExecTool, execToolInput, execToolDefinition, execWaitToolDefinition } from './exec.js';
|
|
6
|
+
import { ExecTool, execToolInput, execToolDefinition, execWaitToolDefinition, formatExecResult } from './exec.js';
|
|
7
7
|
import { ReadTool, formatBatchReadOutput, readToolDefinition } from './read.js';
|
|
8
8
|
import { WorkspacePathResolver } from '../shared/path-resolver.js';
|
|
9
9
|
import { ViewImageTool, viewImageToolDefinition } from './view-image.js';
|
|
@@ -91,7 +91,7 @@ export class LocalToolRegistry {
|
|
|
91
91
|
: { ownerInstanceId: context.operation.ownerInstanceId })
|
|
92
92
|
})
|
|
93
93
|
});
|
|
94
|
-
return
|
|
94
|
+
return formatExecResult(result);
|
|
95
95
|
}
|
|
96
96
|
])
|
|
97
97
|
]);
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type { CoreAgentExtensionContext, CoreSessionExtensionContext, CoreRuntim
|
|
|
13
13
|
export type { CoreDisposer, CoreResourceRegistration, CoreResourceScope } from './agent-core/extensions/resources.js';
|
|
14
14
|
export type { CoreHookOptions, CoreInterceptor } from './agent-core/extensions/hooks.js';
|
|
15
15
|
export type { CoreOperationContext } from './agent-core/extensions/operation.js';
|
|
16
|
-
export type { CoreCompactContext, CoreCompactMessage, CoreCompactResult } from './agent-core/extensions/compaction.js';
|
|
16
|
+
export type { CoreCompactContext, CoreCompactDiagnostic, CoreCompactMessage, CoreCompactResult } from './agent-core/extensions/compaction.js';
|
|
17
17
|
export { buildCompactionInput as buildCompactEvidence } from './agent-core/runtime/compaction/history.js';
|
|
18
18
|
export { countModelTokens } from './agent-core/runtime/token-budget.js';
|
|
19
19
|
export type { CoreServiceKey, CoreServiceRegistry } from './agent-core/extensions/services.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type MarAgentModelConfiguration, type MarAgentReasoningEffort } from '../agent-core/model/configuration.js';
|
|
2
|
-
import type { ModelUsage } from '../agent-core/model/contracts.js';
|
|
2
|
+
import type { ModelAttemptDiagnostic, ModelUsage } from '../agent-core/model/contracts.js';
|
|
3
3
|
import type { CoreCompactMessage } from '../agent-core/extensions/compaction.js';
|
|
4
4
|
export interface GenerateModelTextInput {
|
|
5
5
|
readonly model: MarAgentModelConfiguration;
|
|
@@ -8,6 +8,7 @@ export interface GenerateModelTextInput {
|
|
|
8
8
|
readonly reasoningEffort?: MarAgentReasoningEffort;
|
|
9
9
|
readonly outputLimit?: number;
|
|
10
10
|
readonly signal: AbortSignal;
|
|
11
|
+
readonly onAttemptDiagnostic?: (diagnostic: ModelAttemptDiagnostic) => Promise<void> | void;
|
|
11
12
|
}
|
|
12
13
|
/** One tool-free request using the SDK transports. Credential providers remain caller-owned. */
|
|
13
14
|
export declare function generateModelText(input: GenerateModelTextInput): Promise<{
|
|
@@ -22,6 +22,7 @@ export async function generateModelText(input) {
|
|
|
22
22
|
allowTools: false,
|
|
23
23
|
toolChoice: 'none',
|
|
24
24
|
reasoningEffort: input.reasoningEffort ?? resolveModelDefaultReasoningEffort(input.model),
|
|
25
|
+
...(input.onAttemptDiagnostic ? { onAttemptDiagnostic: input.onAttemptDiagnostic } : {}),
|
|
25
26
|
...(input.outputLimit === undefined ? {} : { outputLimit: input.outputLimit })
|
|
26
27
|
}, input.signal)) {
|
|
27
28
|
input.signal.throwIfAborted();
|