@myagentroam/agent 0.11.21 → 0.11.22
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/error.d.ts +1 -1
- package/dist/agent-core/error.js +20 -14
- package/dist/agent-core/extensions/compaction.d.ts +6 -0
- package/dist/agent-core/extensions/compaction.js +16 -2
- package/dist/agent-core/extensions/model-request.d.ts +5 -9
- package/dist/agent-core/extensions/model-request.js +14 -3
- package/dist/agent-core/extensions/prompt-input.js +3 -1
- package/dist/agent-core/host/contracts.d.ts +8 -0
- package/dist/agent-core/host/local-agent-host.d.ts +2 -0
- package/dist/agent-core/host/local-agent-host.js +3 -0
- package/dist/agent-core/model/anthropic-messages.js +15 -26
- package/dist/agent-core/model/catalog-file.d.ts +2 -0
- package/dist/agent-core/model/configuration.d.ts +3 -1
- package/dist/agent-core/model/configuration.js +1 -0
- package/dist/agent-core/model/contracts.d.ts +5 -8
- package/dist/agent-core/model/image.d.ts +17 -0
- package/dist/agent-core/model/image.js +53 -0
- package/dist/agent-core/model/openai-responses.d.ts +7 -2
- package/dist/agent-core/model/openai-responses.js +81 -27
- package/dist/agent-core/runtime/compaction/retained-context.js +2 -9
- package/dist/agent-core/runtime/context/gc-runtime.d.ts +3 -1
- package/dist/agent-core/runtime/context/gc-runtime.js +17 -6
- package/dist/agent-core/runtime/context/gc-tokens.js +13 -0
- package/dist/agent-core/runtime/context/gc.d.ts +2 -1
- package/dist/agent-core/runtime/context/gc.js +75 -12
- package/dist/agent-core/runtime/context/projection.js +4 -0
- package/dist/agent-core/runtime/context/request-budget.d.ts +2 -4
- package/dist/agent-core/runtime/context/restore.d.ts +2 -0
- package/dist/agent-core/runtime/context/restore.js +19 -3
- package/dist/agent-core/runtime/contracts.d.ts +2 -3
- package/dist/agent-core/runtime/execution.d.ts +1 -1
- package/dist/agent-core/runtime/execution.js +10 -4
- package/dist/agent-core/runtime/resource-publication.d.ts +8 -0
- package/dist/agent-core/runtime/resource-publication.js +60 -0
- package/dist/agent-core/sdk/agent.js +16 -0
- package/dist/agent-core/sdk/model-runtime.js +2 -0
- package/dist/agent-core/sdk/resource-input.d.ts +31 -0
- package/dist/agent-core/sdk/resource-input.js +342 -0
- package/dist/agent-core/sdk/session.js +144 -39
- package/dist/agent-core/session/catalog.d.ts +4 -0
- package/dist/agent-core/session/catalog.js +4 -0
- package/dist/agent-core/session/context-gc-checkpoint.d.ts +6 -4
- package/dist/agent-core/session/context-gc-checkpoint.js +41 -16
- package/dist/agent-core/session/inline-media.d.ts +45 -0
- package/dist/agent-core/session/inline-media.js +163 -0
- package/dist/agent-core/session/store/contracts.d.ts +11 -0
- package/dist/agent-core/session/store/history.d.ts +1 -1
- package/dist/agent-core/session/store/history.js +26 -2
- package/dist/agent-core/session/store/images.d.ts +4 -6
- package/dist/agent-core/session/store/images.js +18 -111
- package/dist/agent-core/session/store/jsonl-store.d.ts +9 -0
- package/dist/agent-core/session/store/jsonl-store.js +100 -28
- package/dist/agent-core/session/store/resources.d.ts +26 -0
- package/dist/agent-core/session/store/resources.js +196 -0
- package/dist/agent-core/session/store/types.d.ts +7 -6
- package/dist/agent-core/session/transaction-recovery.js +1 -1
- package/dist/agent-core/tools/code-mode/cells.js +3 -4
- package/dist/agent-core/tools/code-mode/index.js +32 -8
- package/dist/agent-core/tools/code-mode/observations.d.ts +5 -16
- package/dist/agent-core/tools/code-mode/quickjs-engine.js +23 -26
- package/dist/agent-core/tools/contracts.d.ts +15 -5
- package/dist/agent-core/tools/execution-limits.d.ts +3 -1
- package/dist/agent-core/tools/execution-limits.js +3 -1
- package/dist/agent-core/tools/execution.d.ts +2 -1
- package/dist/agent-core/tools/execution.js +31 -4
- package/dist/agent-core/tools/input-diagnostics/source-preview.d.ts +10 -0
- package/dist/agent-core/tools/input-diagnostics/source-preview.js +64 -0
- package/dist/agent-core/tools/local/apply-patch-parser.js +2 -53
- package/dist/agent-core/tools/local/apply-patch.js +1 -1
- package/dist/agent-core/tools/local/image-processing.d.ts +24 -0
- package/dist/agent-core/tools/local/image-processing.js +135 -0
- package/dist/agent-core/tools/local/read.js +1 -1
- package/dist/agent-core/tools/local/view-image.d.ts +4 -0
- package/dist/agent-core/tools/local/view-image.js +154 -25
- package/dist/agent-core/tools/output-projection.d.ts +2 -4
- package/dist/agent-core/tools/output-projection.js +81 -10
- package/dist/agent-core/tools/runtime-context.d.ts +1 -0
- package/dist/agent-core/tools/runtime.js +20 -1
- package/dist/cli/main.js +2 -1
- package/dist/index.d.ts +1 -1
- package/package.json +2 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { restoreMessages } from '../runtime/context/restore.js';
|
|
1
|
+
import { readResourceImages, restoreMessages } from '../runtime/context/restore.js';
|
|
2
2
|
import { createNativeSteer } from './native-steer.js';
|
|
3
3
|
import { latestModelUsage, reasoningEffortBaseline } from '../runtime/context/usage.js';
|
|
4
4
|
import { splitContextualPrompt } from '../runtime/context/contextual-blocks.js';
|
|
5
5
|
import { contextualInstructionInsertIndex, latestContextualWorldStateGeneration, parsePersistedContextualWorldState, persistContextualWorldState, resetContextualWorldState, updateContextualWorldState, updatePromptWorldState } 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
|
+
import { publishModelResources } from '../runtime/resource-publication.js';
|
|
9
|
+
import { ResourceInputProjection } from './resource-input.js';
|
|
8
10
|
import { closeModelAdapters, createExecutionModelResources, createModelTurnSession } from './model-runtime.js';
|
|
9
11
|
import { prepareSessionModelRequest, projectSessionRequestMessages } from './request-preparation.js';
|
|
10
12
|
import { createSubagentBackend } from './subagent-backend.js';
|
|
@@ -543,6 +545,7 @@ export function createSessionOpener(services) {
|
|
|
543
545
|
replaceCompactMessages(replacementHistory, retainedModelContext) {
|
|
544
546
|
messages.splice(0, messages.length, environmentContextUpdate(executionEnvironment), ...compactedHistoryMessages(replacementHistory), ...retainedModelContext);
|
|
545
547
|
pendingAppends.length = 0;
|
|
548
|
+
resourceInput.replace(messages);
|
|
546
549
|
selected.resetContinuation?.();
|
|
547
550
|
},
|
|
548
551
|
// Derived state follows the committed splice, never delays it past the writer window.
|
|
@@ -579,6 +582,8 @@ export function createSessionOpener(services) {
|
|
|
579
582
|
.filter((entry) => !restoredIds.has(entry.recordId))
|
|
580
583
|
.map((entry) => entry.message);
|
|
581
584
|
messages.splice(0, messages.length, ...refreshed.messages, ...lateMessages);
|
|
585
|
+
resourceInput.replace(messages);
|
|
586
|
+
resourceInput.adoptGc(committed.projection.checkpoint?.inlineMedia?.state);
|
|
582
587
|
restoreMcpDiscovery();
|
|
583
588
|
recordedEnvironment = refreshed.environmentState;
|
|
584
589
|
userMessages = [...refreshed.userMessages];
|
|
@@ -620,8 +625,18 @@ export function createSessionOpener(services) {
|
|
|
620
625
|
smartPercent !== undefined &&
|
|
621
626
|
smartPercent >= AGENT_EXECUTION_POLICY.smartCompactionPercent &&
|
|
622
627
|
smartPercent < AGENT_EXECUTION_POLICY.automaticCompactionPercent;
|
|
623
|
-
const
|
|
624
|
-
|
|
628
|
+
const modelImages = await publishModelResources(host, content.images, {
|
|
629
|
+
sessionId,
|
|
630
|
+
executionId
|
|
631
|
+
}, store);
|
|
632
|
+
const actualContent = modelImages === content.images
|
|
633
|
+
? content
|
|
634
|
+
: {
|
|
635
|
+
...content,
|
|
636
|
+
...(modelImages === undefined ? {} : { images: modelImages })
|
|
637
|
+
};
|
|
638
|
+
const images = modelImages?.length
|
|
639
|
+
? await store.persistInputImages(sessionId, modelImages)
|
|
625
640
|
: [];
|
|
626
641
|
const record = await store.append(sessionId, {
|
|
627
642
|
type,
|
|
@@ -649,7 +664,7 @@ export function createSessionOpener(services) {
|
|
|
649
664
|
content: content.modelText ?? content.text,
|
|
650
665
|
metadata: inputMetadata
|
|
651
666
|
});
|
|
652
|
-
committed(
|
|
667
|
+
committed(actualContent, record.recordId, inputMetadata);
|
|
653
668
|
for (const text of content.modelContext ?? content.context ?? [])
|
|
654
669
|
messages.push({ role: 'user', content: text, contextKind: 'contextual' });
|
|
655
670
|
});
|
|
@@ -757,10 +772,7 @@ export function createSessionOpener(services) {
|
|
|
757
772
|
metadata,
|
|
758
773
|
...(actual.images?.length
|
|
759
774
|
? {
|
|
760
|
-
images: actual.images.map((
|
|
761
|
-
mimeType,
|
|
762
|
-
dataBase64
|
|
763
|
-
}))
|
|
775
|
+
images: actual.images.map((image) => ({ ...image }))
|
|
764
776
|
}
|
|
765
777
|
: {})
|
|
766
778
|
});
|
|
@@ -775,6 +787,7 @@ export function createSessionOpener(services) {
|
|
|
775
787
|
}, inputs.boundarySize);
|
|
776
788
|
const hasRestoredUserImages = messages.some((message) => message.role === 'user' && Boolean(message.images?.length));
|
|
777
789
|
let modelInputImages;
|
|
790
|
+
const inputImageBytes = new Map();
|
|
778
791
|
const currentExecutionToolImages = [];
|
|
779
792
|
let currentExecutionUserIndex;
|
|
780
793
|
await emit({ type: 'execution.started', mode, permissionMode: permissionPolicy.mode });
|
|
@@ -791,6 +804,18 @@ export function createSessionOpener(services) {
|
|
|
791
804
|
});
|
|
792
805
|
selectedAdapter = sessionAdapter(input.modelId ?? executionDefaultModelId, executionModels);
|
|
793
806
|
const selectedModel = executionModels.get(input.modelId ?? executionDefaultModelId);
|
|
807
|
+
const restoredMessageCount = messages.length;
|
|
808
|
+
const resourceInput = new ResourceInputProjection(selectedModel.useResourceUrl === true, store, sessionId, messages, {
|
|
809
|
+
records: contextRecords,
|
|
810
|
+
persist: async (state) => {
|
|
811
|
+
await withRecordProjection(() => store.append(sessionId, {
|
|
812
|
+
type: 'resource.window',
|
|
813
|
+
payload: state,
|
|
814
|
+
executionId,
|
|
815
|
+
turnId
|
|
816
|
+
}));
|
|
817
|
+
}
|
|
818
|
+
});
|
|
794
819
|
const selected = modelResources.openTurn(selectedAdapter, services.hasCustomAdapters && selectedAdapter.createTurnSession === undefined);
|
|
795
820
|
let lastServerUsage = latestModelUsage(contextRecords, selectedModel.id);
|
|
796
821
|
let smartContextTokens = latestSmartContextTokens(contextRecords, selectedModel.id, selectedModel.contextWindowTokens);
|
|
@@ -898,9 +923,7 @@ export function createSessionOpener(services) {
|
|
|
898
923
|
?.filter((binding) => !executionSourceNames.has(binding.definition.name)) ?? [];
|
|
899
924
|
const sources = (executionToolSources = new ExecutionToolSources(executionId, sessionId, combinedTools, builtinTools, mcpCatalog, supplementalBindings));
|
|
900
925
|
const sourceBindings = sources.bindings;
|
|
901
|
-
const coreExtensions = await services.extensions.prepare(sessionId, controller.signal, sourceBindings, sessionSource.type === 'user' &&
|
|
902
|
-
(mode === 'run' || mode === 'plan') &&
|
|
903
|
-
!internal.automaticInput);
|
|
926
|
+
const coreExtensions = await services.extensions.prepare(sessionId, controller.signal, sourceBindings, sessionSource.type === 'user' && !internal.automaticInput);
|
|
904
927
|
executionContext.toolSources = sources;
|
|
905
928
|
const operation = (run) => services.extensions.operations.run({
|
|
906
929
|
sessionId,
|
|
@@ -928,9 +951,11 @@ export function createSessionOpener(services) {
|
|
|
928
951
|
const transformModelRequest = async (candidate, bindings = captureTools(), modelId = selectedModel.id, purpose = mode === 'compact' ? 'compact' : 'conversation') => {
|
|
929
952
|
let lowered = candidate;
|
|
930
953
|
if (coreExtensions.hooks.hasInterceptors('model.request')) {
|
|
931
|
-
const bridge = new ExtensionRequestBridge(modelId, candidate);
|
|
954
|
+
const bridge = new ExtensionRequestBridge(modelId, candidate, undefined, selected.continuationInputCount?.() ?? 0);
|
|
932
955
|
const request = await operation((call) => coreExtensions.hooks.invoke('model.request', bridge.view, call, async (view) => view));
|
|
933
956
|
lowered = bridge.lower(request);
|
|
957
|
+
if (bridge.rewroteCommittedInput)
|
|
958
|
+
selected.resetContinuation?.();
|
|
934
959
|
}
|
|
935
960
|
for (const definition of lowered.tools) {
|
|
936
961
|
const binding = bindings.get(definition.name);
|
|
@@ -1068,6 +1093,7 @@ export function createSessionOpener(services) {
|
|
|
1068
1093
|
: subagents.captureParentFrame(executionId);
|
|
1069
1094
|
const roundSmartInput = smartInput;
|
|
1070
1095
|
const toolContext = {
|
|
1096
|
+
imageStore: store,
|
|
1071
1097
|
host: host,
|
|
1072
1098
|
requestSmartCompact: () => {
|
|
1073
1099
|
controller.signal.throwIfAborted();
|
|
@@ -1117,7 +1143,20 @@ export function createSessionOpener(services) {
|
|
|
1117
1143
|
return sources.withFrame(context, () => parentFrame === undefined ? invoke() : parentFrame(invoke));
|
|
1118
1144
|
}
|
|
1119
1145
|
};
|
|
1120
|
-
const recentImages = () =>
|
|
1146
|
+
const recentImages = async () => {
|
|
1147
|
+
const inputImages = await Promise.all((modelInputImages ?? []).map(async (image) => {
|
|
1148
|
+
if (image.dataBase64 !== undefined || image.resourceId === undefined)
|
|
1149
|
+
return image;
|
|
1150
|
+
const cached = inputImageBytes.get(image.resourceId);
|
|
1151
|
+
if (cached !== undefined)
|
|
1152
|
+
return cached;
|
|
1153
|
+
const source = await store.readResource(sessionId, image.resourceId);
|
|
1154
|
+
const restored = { ...image, ...source };
|
|
1155
|
+
inputImageBytes.set(image.resourceId, restored);
|
|
1156
|
+
return restored;
|
|
1157
|
+
}));
|
|
1158
|
+
return currentExecutionImages(inputImages, currentExecutionToolImages);
|
|
1159
|
+
};
|
|
1121
1160
|
const toolScope = {
|
|
1122
1161
|
context: toolContext,
|
|
1123
1162
|
tools: roundTools,
|
|
@@ -1141,8 +1180,7 @@ export function createSessionOpener(services) {
|
|
|
1141
1180
|
recentImages,
|
|
1142
1181
|
captureCodeContext: () => ({
|
|
1143
1182
|
...toolContext,
|
|
1144
|
-
waitInterrupt: undefined
|
|
1145
|
-
recentImages: recentImages()
|
|
1183
|
+
waitInterrupt: undefined
|
|
1146
1184
|
}),
|
|
1147
1185
|
codeModeContext: async (call) => {
|
|
1148
1186
|
const stateSnapshot = call.name === 'code_exec' ? await store.readCodeModeState(sessionId) : [];
|
|
@@ -1214,6 +1252,9 @@ export function createSessionOpener(services) {
|
|
|
1214
1252
|
sources.bind(captureRoundToolScope().toolScope);
|
|
1215
1253
|
let preparingRequestMessages;
|
|
1216
1254
|
let preparingRequestBaseLength = 0;
|
|
1255
|
+
let dispatchedInputCount = 0;
|
|
1256
|
+
const completedMediaRequests = new WeakSet();
|
|
1257
|
+
let dispatchedLocalCount = 0;
|
|
1217
1258
|
executionContext.requestMessages = {
|
|
1218
1259
|
read: () => preparingRequestMessages !== undefined
|
|
1219
1260
|
? normalizeMessagesForModel([...preparingRequestMessages, ...messages.slice(preparingRequestBaseLength)], { supportsImages: selectedModel.inputCapabilities.includes('IMAGE') })
|
|
@@ -1245,14 +1286,12 @@ export function createSessionOpener(services) {
|
|
|
1245
1286
|
...(input.clientMessageId ? { clientMessageId: input.clientMessageId } : {})
|
|
1246
1287
|
}, call, (actual, recordId, metadata) => {
|
|
1247
1288
|
entered = true;
|
|
1248
|
-
modelInputImages = actual.images?.map((
|
|
1249
|
-
mimeType,
|
|
1250
|
-
dataBase64
|
|
1251
|
-
}));
|
|
1289
|
+
modelInputImages = actual.images?.map((image) => ({ ...image }));
|
|
1252
1290
|
messages.push({
|
|
1253
1291
|
role: 'user',
|
|
1254
1292
|
content: actual.modelText ?? actual.text,
|
|
1255
|
-
metadata
|
|
1293
|
+
metadata,
|
|
1294
|
+
...(modelInputImages?.length ? { images: modelInputImages } : {})
|
|
1256
1295
|
});
|
|
1257
1296
|
currentExecutionUserIndex = messages.length - 1;
|
|
1258
1297
|
internal.inputCommitted?.(recordId);
|
|
@@ -1288,8 +1327,12 @@ export function createSessionOpener(services) {
|
|
|
1288
1327
|
call.signal.throwIfAborted();
|
|
1289
1328
|
if (content.images?.length && !selectedModel.inputCapabilities.includes('IMAGE'))
|
|
1290
1329
|
throw new MarAgentError('MAR_AGENT_INPUT_CAPABILITY_UNSUPPORTED', 'Selected model does not support image input.');
|
|
1291
|
-
const
|
|
1292
|
-
|
|
1330
|
+
const modelImages = await publishModelResources(host, content.images, {
|
|
1331
|
+
sessionId,
|
|
1332
|
+
executionId
|
|
1333
|
+
}, store);
|
|
1334
|
+
const images = modelImages?.length
|
|
1335
|
+
? await store.persistInputImages(sessionId, modelImages)
|
|
1293
1336
|
: [];
|
|
1294
1337
|
const record = await store.append(sessionId, {
|
|
1295
1338
|
type: 'turn.user',
|
|
@@ -1401,7 +1444,12 @@ export function createSessionOpener(services) {
|
|
|
1401
1444
|
turnId
|
|
1402
1445
|
});
|
|
1403
1446
|
let lastServerContextTokens = lastServerUsage?.contextInputTokens;
|
|
1404
|
-
let compactBoundary =
|
|
1447
|
+
let compactBoundary = restoredMessageCount;
|
|
1448
|
+
const advanceCompactBoundary = () => {
|
|
1449
|
+
// Keep a new image with its complete tool round until a model accepts it.
|
|
1450
|
+
if (!resourceInput.hasPendingImages(messages.slice(compactBoundary)))
|
|
1451
|
+
compactBoundary = messages.length;
|
|
1452
|
+
};
|
|
1405
1453
|
const invalidateCompactUsage = () => {
|
|
1406
1454
|
lastServerContextTokens = undefined;
|
|
1407
1455
|
lastServerUsage = undefined;
|
|
@@ -1421,7 +1469,7 @@ export function createSessionOpener(services) {
|
|
|
1421
1469
|
message.contextKind === undefined ||
|
|
1422
1470
|
message.contextKind === 'summary'))
|
|
1423
1471
|
return false;
|
|
1424
|
-
const compactHistory = structuredClone(prefix);
|
|
1472
|
+
const compactHistory = structuredClone(prefix).map(({ images: _images, ...message }) => message);
|
|
1425
1473
|
const prefixInputs = modelContext.compactInputs(prefix);
|
|
1426
1474
|
const snapshotTools = structuredClone(projectTools(executionTools));
|
|
1427
1475
|
const generation = modelContext.worldState.generation;
|
|
@@ -1503,6 +1551,7 @@ export function createSessionOpener(services) {
|
|
|
1503
1551
|
const record = await store.compact(sessionId, {
|
|
1504
1552
|
summary: actual,
|
|
1505
1553
|
replacementHistory,
|
|
1554
|
+
inlineMediaState: resourceInput.checkpoint(retainedModelContext),
|
|
1506
1555
|
retainedModelContext: retainedModelContext.map((message) => {
|
|
1507
1556
|
const source = messageSources.get(message);
|
|
1508
1557
|
const saved = source?.type === 'model.context' &&
|
|
@@ -1516,7 +1565,14 @@ export function createSessionOpener(services) {
|
|
|
1516
1565
|
...saved,
|
|
1517
1566
|
...(message.metadata ? { metadata: message.metadata } : {})
|
|
1518
1567
|
}
|
|
1519
|
-
:
|
|
1568
|
+
: {
|
|
1569
|
+
...message,
|
|
1570
|
+
...(message.images?.length
|
|
1571
|
+
? {
|
|
1572
|
+
images: message.images.map(({ dataBase64: _bytes, ...image }) => image)
|
|
1573
|
+
}
|
|
1574
|
+
: {})
|
|
1575
|
+
};
|
|
1520
1576
|
}),
|
|
1521
1577
|
pendingInputs: [...pendingInputs.values()],
|
|
1522
1578
|
snapshotMessageCount: prefix.length,
|
|
@@ -1530,6 +1586,7 @@ export function createSessionOpener(services) {
|
|
|
1530
1586
|
turnId
|
|
1531
1587
|
}, options);
|
|
1532
1588
|
modelContext.replaceCompactMessages(replacementHistory, retainedModelContext);
|
|
1589
|
+
compactBoundary = messages.length - retainedModelContext.length;
|
|
1533
1590
|
return record;
|
|
1534
1591
|
});
|
|
1535
1592
|
await modelContext.adoptCompactCheckpoint(compactRecord.recordId, replacementHistory, retainedModelContext, compactResources);
|
|
@@ -1619,7 +1676,7 @@ export function createSessionOpener(services) {
|
|
|
1619
1676
|
controller.signal.throwIfAborted();
|
|
1620
1677
|
if (!hadPending)
|
|
1621
1678
|
throw error;
|
|
1622
|
-
|
|
1679
|
+
advanceCompactBoundary();
|
|
1623
1680
|
compacted = await compactContext();
|
|
1624
1681
|
}
|
|
1625
1682
|
if (!compacted)
|
|
@@ -1680,7 +1737,7 @@ export function createSessionOpener(services) {
|
|
|
1680
1737
|
updateMcpRegistry();
|
|
1681
1738
|
executionTools = mcpRegistry.project(baseTools());
|
|
1682
1739
|
await modelContext.syncMcpWorldState(messages.length);
|
|
1683
|
-
|
|
1740
|
+
advanceCompactBoundary();
|
|
1684
1741
|
const blocking = compactRequests.drain((input) => startCompact({
|
|
1685
1742
|
...(input.prompt === undefined ? {} : { focus: input.prompt }),
|
|
1686
1743
|
async: input.async === true
|
|
@@ -1737,24 +1794,61 @@ export function createSessionOpener(services) {
|
|
|
1737
1794
|
// Never sample the candidate assembled against the replaced context.
|
|
1738
1795
|
return prepareRound(pendingOutputContinuation, true);
|
|
1739
1796
|
}
|
|
1740
|
-
|
|
1797
|
+
resourceInput.observe(candidateRequest.messages);
|
|
1798
|
+
const media = sessionSource.type === 'subagent'
|
|
1799
|
+
? undefined
|
|
1800
|
+
: await resourceInput.gcCandidate(request, candidateRequest.images);
|
|
1801
|
+
if (media?.reason === 'HARD_LIMIT') {
|
|
1802
|
+
const appendBoundary = pendingAppends.length;
|
|
1803
|
+
const committed = await contextGc.run({
|
|
1804
|
+
inlineMedia: media,
|
|
1805
|
+
mediaView: (messages) => resourceInput.historyView(messages),
|
|
1806
|
+
store,
|
|
1807
|
+
sessionId,
|
|
1808
|
+
system: request.system,
|
|
1809
|
+
tools: toolScope.tools,
|
|
1810
|
+
modelId: selectedModel.id,
|
|
1811
|
+
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1812
|
+
usage: lastServerUsage ?? {},
|
|
1813
|
+
...modelConfiguration.contextProjection,
|
|
1814
|
+
workspace: logicalWorkspace,
|
|
1815
|
+
platform: description.platform
|
|
1816
|
+
});
|
|
1817
|
+
if (committed) {
|
|
1818
|
+
await modelContext.adoptGcCheckpoint(committed, appendBoundary);
|
|
1819
|
+
return prepareRound(pendingOutputContinuation, true);
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
return {
|
|
1823
|
+
request: await resourceInput.prepare(request, candidateRequest.images, candidateRequest.messages),
|
|
1824
|
+
toolScope
|
|
1825
|
+
};
|
|
1741
1826
|
},
|
|
1742
1827
|
startModel: async function* (request) {
|
|
1743
1828
|
const snapshots = (sessionRuntime.requestSnapshots ??=
|
|
1744
1829
|
new ExtensionRequestSnapshots());
|
|
1745
1830
|
const snapshot = snapshots.record(selectedModel.id, request);
|
|
1831
|
+
dispatchedInputCount = request.messages.length;
|
|
1832
|
+
dispatchedLocalCount = messages.length;
|
|
1746
1833
|
yield* streamModel(async function* (nativeSignal) {
|
|
1747
1834
|
for await (const event of selected.start(request, nativeSignal)) {
|
|
1748
|
-
if (
|
|
1749
|
-
|
|
1835
|
+
if (event.type === 'completed' && event.reason !== 'cancelled') {
|
|
1836
|
+
completedMediaRequests.add(request.messages);
|
|
1837
|
+
if (snapshot)
|
|
1838
|
+
snapshots.complete(snapshot);
|
|
1839
|
+
}
|
|
1750
1840
|
yield event;
|
|
1751
1841
|
}
|
|
1752
1842
|
}, controller.signal);
|
|
1753
1843
|
},
|
|
1754
1844
|
recoverySignal: () => controller.signal,
|
|
1755
1845
|
compactContext,
|
|
1756
|
-
afterModel: async (closedPrefixLength) => {
|
|
1757
|
-
|
|
1846
|
+
afterModel: async (closedPrefixLength, acceptedRequest) => {
|
|
1847
|
+
selected.commitContinuationInput?.(dispatchedInputCount + messages.length - dispatchedLocalCount);
|
|
1848
|
+
if (acceptedRequest && completedMediaRequests.has(acceptedRequest.messages)) {
|
|
1849
|
+
await resourceInput.complete(acceptedRequest);
|
|
1850
|
+
compactBoundary = closedPrefixLength;
|
|
1851
|
+
}
|
|
1758
1852
|
if (lastServerContextTokens !== undefined &&
|
|
1759
1853
|
(lastServerContextTokens * 100) / selectedModel.contextWindowTokens >=
|
|
1760
1854
|
AGENT_EXECUTION_POLICY.backgroundCompactionPercent &&
|
|
@@ -1773,7 +1867,7 @@ export function createSessionOpener(services) {
|
|
|
1773
1867
|
}
|
|
1774
1868
|
},
|
|
1775
1869
|
checkpoint: async (round, latestUsage) => {
|
|
1776
|
-
|
|
1870
|
+
advanceCompactBoundary();
|
|
1777
1871
|
const blocking = compactRequests.drain((input) => startCompact({
|
|
1778
1872
|
...(input.prompt === undefined ? {} : { focus: input.prompt }),
|
|
1779
1873
|
async: input.async === true
|
|
@@ -1784,19 +1878,19 @@ export function createSessionOpener(services) {
|
|
|
1784
1878
|
await compactCoordinator.checkpoint(false).catch(() => {
|
|
1785
1879
|
controller.signal.throwIfAborted();
|
|
1786
1880
|
});
|
|
1787
|
-
if (!compactCoordinator.pending &&
|
|
1788
|
-
sessionSource.type !== 'subagent' &&
|
|
1789
|
-
latestUsage !== undefined) {
|
|
1881
|
+
if (!compactCoordinator.pending && sessionSource.type !== 'subagent') {
|
|
1790
1882
|
// Only a committed GC checkpoint may replace active context and invalidate continuation.
|
|
1791
1883
|
const appendBoundary = pendingAppends.length;
|
|
1792
1884
|
const committed = await contextGc.run({
|
|
1885
|
+
inlineMedia: await resourceInput.gcCandidate(),
|
|
1886
|
+
mediaView: (messages) => resourceInput.historyView(messages),
|
|
1793
1887
|
store,
|
|
1794
1888
|
sessionId,
|
|
1795
1889
|
system: round.request.system,
|
|
1796
1890
|
tools: round.toolScope.tools,
|
|
1797
1891
|
modelId: selectedModel.id,
|
|
1798
1892
|
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1799
|
-
usage: latestUsage,
|
|
1893
|
+
usage: latestUsage ?? {},
|
|
1800
1894
|
...modelConfiguration.contextProjection,
|
|
1801
1895
|
workspace: logicalWorkspace,
|
|
1802
1896
|
platform: description.platform,
|
|
@@ -2052,8 +2146,19 @@ export function createSessionOpener(services) {
|
|
|
2052
2146
|
call.signal.throwIfAborted();
|
|
2053
2147
|
const targetRuntime = sessionRuntimes.get(target);
|
|
2054
2148
|
const requestMessages = targetRuntime?.execution?.requestMessages;
|
|
2055
|
-
if (selection.view === 'request' && requestMessages)
|
|
2056
|
-
|
|
2149
|
+
if (selection.view === 'request' && requestMessages) {
|
|
2150
|
+
const messages = requestMessages.read();
|
|
2151
|
+
const restored = selection.includeImages
|
|
2152
|
+
? await Promise.all(messages.map(async (message) => message.images?.length
|
|
2153
|
+
? {
|
|
2154
|
+
...message,
|
|
2155
|
+
images: await readResourceImages(store, target, message.images)
|
|
2156
|
+
}
|
|
2157
|
+
: message))
|
|
2158
|
+
: messages;
|
|
2159
|
+
call.signal.throwIfAborted();
|
|
2160
|
+
return sessionMessagesPage(restored, selection);
|
|
2161
|
+
}
|
|
2057
2162
|
const modelState = services.modelState();
|
|
2058
2163
|
const requestModel = selection.view === 'request'
|
|
2059
2164
|
? modelState.models.get(targetModelId ?? modelState.defaultModelId)
|
|
@@ -72,6 +72,10 @@ export interface MarAgentSessionCatalog {
|
|
|
72
72
|
readonly sequence: number;
|
|
73
73
|
readonly imageIndex: number;
|
|
74
74
|
}): Promise<MarAgentSessionImage | undefined>;
|
|
75
|
+
readResource(sessionId: string, resourceId: string): Promise<{
|
|
76
|
+
mimeType: string;
|
|
77
|
+
dataBase64: string;
|
|
78
|
+
} | undefined>;
|
|
75
79
|
contextUsage(sessionId: string): Promise<MarAgentContextUsage | undefined>;
|
|
76
80
|
readToolResultResource(sessionId: string, input: import('./tool-result-resources.js').ToolResultResourceInput): Promise<import('./tool-result-resources.js').ToolResultResourcePage>;
|
|
77
81
|
fork(sessionId: string, input: {
|
|
@@ -103,6 +103,10 @@ export async function openMarAgentSessionCatalog(input) {
|
|
|
103
103
|
dataBase64: image.dataBase64
|
|
104
104
|
};
|
|
105
105
|
},
|
|
106
|
+
readResource: async (sessionId, resourceId) => {
|
|
107
|
+
assertOpen();
|
|
108
|
+
return store.readResource(sessionId, resourceId);
|
|
109
|
+
},
|
|
106
110
|
readToolResultResource: async (sessionId, input) => {
|
|
107
111
|
assertOpen();
|
|
108
112
|
return store.readToolResultResource(sessionId, input);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type InlineMediaGcCheckpoint } from './inline-media.js';
|
|
1
2
|
import { type ContextGcWebToolName } from './context-gc-replacements.js';
|
|
2
3
|
import { type ContextGcSubagentToolName } from './context-gc-subagent.js';
|
|
3
4
|
import type { SessionRecord } from './store/index.js';
|
|
@@ -93,7 +94,7 @@ export type ContextGcReplacement = {
|
|
|
93
94
|
readonly evidenceSequence: number;
|
|
94
95
|
};
|
|
95
96
|
export interface ContextGcMetrics {
|
|
96
|
-
readonly stage: 'STAGE_A' | 'STAGE_A_AND_EXEC';
|
|
97
|
+
readonly stage: 'STAGE_A' | 'STAGE_A_AND_EXEC' | 'INLINE_MEDIA';
|
|
97
98
|
readonly tokenEstimator?: 'UTF8_BYTES_V1';
|
|
98
99
|
readonly beforeTokens: number;
|
|
99
100
|
readonly afterTokens: number;
|
|
@@ -105,8 +106,8 @@ export interface ContextGcMetrics {
|
|
|
105
106
|
readonly compactDeferralCreditCostUnits: number;
|
|
106
107
|
readonly imminentCompactAvoidanceCreditCostUnits?: number;
|
|
107
108
|
readonly appliedCompactCreditCostUnits?: number;
|
|
108
|
-
readonly requiredPositiveNetRollouts: number;
|
|
109
|
-
readonly requiredTargetRoiRollouts: number;
|
|
109
|
+
readonly requiredPositiveNetRollouts: number | null;
|
|
110
|
+
readonly requiredTargetRoiRollouts: number | null;
|
|
110
111
|
readonly projectedRolloutsUntilCompactAfterGc: number;
|
|
111
112
|
readonly projectedTokensBeforeGc?: number;
|
|
112
113
|
readonly projectedTokensAfterGc?: number;
|
|
@@ -121,12 +122,13 @@ export interface ContextGcMetrics {
|
|
|
121
122
|
readonly cachePenaltyKnown?: boolean;
|
|
122
123
|
}
|
|
123
124
|
export interface ContextGcCheckpointDraft {
|
|
125
|
+
readonly inlineMedia?: InlineMediaGcCheckpoint;
|
|
124
126
|
readonly version: 1;
|
|
125
127
|
readonly base: ContextGcBase;
|
|
126
128
|
readonly boundarySequence: number;
|
|
127
129
|
readonly replacements: readonly ContextGcReplacement[];
|
|
128
130
|
readonly trigger: {
|
|
129
|
-
readonly usageSequence: number;
|
|
131
|
+
readonly usageSequence: number | null;
|
|
130
132
|
readonly contextInputTokens: number;
|
|
131
133
|
readonly contextWindowTokens: number;
|
|
132
134
|
readonly normalRolloutOrdinal: number;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { posix, win32 } from 'node:path';
|
|
2
2
|
import { isDeepStrictEqual } from 'node:util';
|
|
3
|
+
import { inlineMediaGcAnchored, parseInlineMediaGc } from './inline-media.js';
|
|
3
4
|
import { codeCallEvidence, codePartialPatchCallEvidence, callsFromRecord, codeObservationEvidence, observationsFromRecord, retainedCodeInputs } from './context-gc-observations.js';
|
|
4
5
|
import { parseReadContextOutput } from '../tools/local/read-context.js';
|
|
5
6
|
import { codeCellCompletionSequence, contextGcApplyPatchInputReplacement, contextGcCodeModeInputReplacement, contextGcCodeModeOutputReplacement, contextGcExecInputReplacement, contextGcExecOutputReplacement, contextGcPatchResultFromCompletedPayload, contextGcPatchResultFromFailedPayload, contextGcStaleReadReplacement, contextGcWebOutputReplacement, normalizeContextGcCodeModeInput, normalizeContextGcExecResult } from './context-gc-replacements.js';
|
|
@@ -120,10 +121,11 @@ export function parseContextGcCheckpoint(record) {
|
|
|
120
121
|
!isContextGcBase(payload.base) ||
|
|
121
122
|
!isPositiveInteger(payload.boundarySequence) ||
|
|
122
123
|
!Array.isArray(payload.replacements) ||
|
|
123
|
-
payload.replacements.length === 0 ||
|
|
124
|
+
(payload.replacements.length === 0 && payload.inlineMedia === undefined) ||
|
|
124
125
|
!isContextGcTrigger(payload.trigger) ||
|
|
125
126
|
!isContextGcEconomicsPolicy(payload.economics) ||
|
|
126
|
-
!isContextGcMetrics(payload.metrics)
|
|
127
|
+
!isContextGcMetrics(payload.metrics) ||
|
|
128
|
+
(payload.inlineMedia !== undefined && !parseInlineMediaGc(payload.inlineMedia)))
|
|
127
129
|
return undefined;
|
|
128
130
|
const replacements = normalizeContextGcReplacements(payload.replacements);
|
|
129
131
|
if (!replacements || replacements.length !== payload.replacements.length)
|
|
@@ -137,7 +139,10 @@ export function parseContextGcCheckpoint(record) {
|
|
|
137
139
|
replacements,
|
|
138
140
|
trigger: structuredClone(payload.trigger),
|
|
139
141
|
economics: structuredClone(payload.economics),
|
|
140
|
-
metrics: structuredClone(payload.metrics)
|
|
142
|
+
metrics: structuredClone(payload.metrics),
|
|
143
|
+
...(payload.inlineMedia === undefined
|
|
144
|
+
? {}
|
|
145
|
+
: { inlineMedia: parseInlineMediaGc(payload.inlineMedia) })
|
|
141
146
|
};
|
|
142
147
|
}
|
|
143
148
|
export function validateContextGcCheckpoint(records, record, workspace = sessionWorkspace(records), committedReplacements = []) {
|
|
@@ -150,9 +155,14 @@ export function validateContextGcCheckpoint(records, record, workspace = session
|
|
|
150
155
|
const baseSequence = contextGcBaseSequence(payload.base);
|
|
151
156
|
// Later cell completion cannot retroactively authorize an earlier checkpoint.
|
|
152
157
|
records = records.filter((item) => item.sequence <= payload.boundarySequence);
|
|
158
|
+
if (payload.inlineMedia && !inlineMediaGcAnchored(records, payload.inlineMedia))
|
|
159
|
+
return undefined;
|
|
153
160
|
const recordsBySequence = new Map(records.map((item) => [item.sequence, item]));
|
|
154
161
|
if (!triggerMatchesRecords(records, recordsBySequence, payload))
|
|
155
162
|
return undefined;
|
|
163
|
+
if (payload.trigger.usageSequence === null &&
|
|
164
|
+
!isDeepStrictEqual(payload.replacements, committedReplacements))
|
|
165
|
+
return undefined;
|
|
156
166
|
const committed = new Map(committedReplacements.map((replacement) => [contextGcReplacementKey(replacement), replacement]));
|
|
157
167
|
const changed = payload.replacements.flatMap((replacement) => {
|
|
158
168
|
const previous = committed.get(contextGcReplacementKey(replacement));
|
|
@@ -603,14 +613,25 @@ function isSuccessfulExecLifecycleEvidence(replacement, source, records, records
|
|
|
603
613
|
targetResult.sequence <= evidence.result.sequence);
|
|
604
614
|
}
|
|
605
615
|
function triggerMatchesRecords(records, recordsBySequence, payload) {
|
|
606
|
-
if (payload.trigger.usageSequence
|
|
607
|
-
payload.trigger.usageSequence
|
|
616
|
+
if (payload.trigger.usageSequence !== null &&
|
|
617
|
+
(payload.trigger.usageSequence < contextGcBaseSequence(payload.base) ||
|
|
618
|
+
payload.trigger.usageSequence > payload.boundarySequence))
|
|
608
619
|
return false;
|
|
609
|
-
const
|
|
610
|
-
if (
|
|
611
|
-
!
|
|
612
|
-
|
|
613
|
-
|
|
620
|
+
const withoutUsage = payload.trigger.usageSequence === null;
|
|
621
|
+
if (withoutUsage &&
|
|
622
|
+
(!payload.inlineMedia ||
|
|
623
|
+
payload.inlineMedia.reason === 'TEXT_GC' ||
|
|
624
|
+
payload.metrics.stage !== 'INLINE_MEDIA' ||
|
|
625
|
+
payload.trigger.contextInputTokens !== 0))
|
|
626
|
+
return false;
|
|
627
|
+
const usageRecord = withoutUsage
|
|
628
|
+
? undefined
|
|
629
|
+
: recordsBySequence.get(payload.trigger.usageSequence);
|
|
630
|
+
if (!withoutUsage &&
|
|
631
|
+
(!usageRecord ||
|
|
632
|
+
!isRecord(usageRecord.payload) ||
|
|
633
|
+
usageRecord.payload.type !== 'usage.updated' ||
|
|
634
|
+
modelContextUsage(usageRecord.payload) !== payload.trigger.contextInputTokens))
|
|
614
635
|
return false;
|
|
615
636
|
const baseSequence = contextGcBaseSequence(payload.base);
|
|
616
637
|
let modelId;
|
|
@@ -632,7 +653,7 @@ function triggerMatchesRecords(records, recordsBySequence, payload) {
|
|
|
632
653
|
}
|
|
633
654
|
const matchingConfiguration = modelId === payload.trigger.modelId &&
|
|
634
655
|
contextWindowTokens === payload.trigger.contextWindowTokens;
|
|
635
|
-
if (record.sequence === usageRecord
|
|
656
|
+
if (record.sequence === usageRecord?.sequence || withoutUsage)
|
|
636
657
|
triggerConfigurationMatches = matchingConfiguration;
|
|
637
658
|
if (matchingConfiguration &&
|
|
638
659
|
isRecord(record.payload) &&
|
|
@@ -647,7 +668,9 @@ function triggerMatchesRecords(records, recordsBySequence, payload) {
|
|
|
647
668
|
normalRolloutOrdinal++;
|
|
648
669
|
}
|
|
649
670
|
return (triggerConfigurationMatches &&
|
|
650
|
-
|
|
671
|
+
(withoutUsage
|
|
672
|
+
? latestMatchingUsageSequence === undefined
|
|
673
|
+
: latestMatchingUsageSequence === payload.trigger.usageSequence) &&
|
|
651
674
|
normalRolloutOrdinal === payload.trigger.normalRolloutOrdinal);
|
|
652
675
|
}
|
|
653
676
|
function modelContextUsage(value) {
|
|
@@ -822,7 +845,7 @@ function isContextGcBase(value) {
|
|
|
822
845
|
}
|
|
823
846
|
function isContextGcTrigger(value) {
|
|
824
847
|
return (isRecord(value) &&
|
|
825
|
-
isPositiveInteger(value.usageSequence) &&
|
|
848
|
+
(value.usageSequence === null || isPositiveInteger(value.usageSequence)) &&
|
|
826
849
|
isNonnegativeInteger(value.contextInputTokens) &&
|
|
827
850
|
isPositiveInteger(value.contextWindowTokens) &&
|
|
828
851
|
isNonnegativeInteger(value.normalRolloutOrdinal) &&
|
|
@@ -851,7 +874,10 @@ function isContextGcEconomicsPolicy(value) {
|
|
|
851
874
|
].every((key) => isNonnegativeFinite(value[key])));
|
|
852
875
|
}
|
|
853
876
|
function isContextGcMetrics(value) {
|
|
854
|
-
if (!isRecord(value) ||
|
|
877
|
+
if (!isRecord(value) ||
|
|
878
|
+
(value.stage !== 'STAGE_A' &&
|
|
879
|
+
value.stage !== 'STAGE_A_AND_EXEC' &&
|
|
880
|
+
value.stage !== 'INLINE_MEDIA'))
|
|
855
881
|
return false;
|
|
856
882
|
const nonnegative = [
|
|
857
883
|
'beforeTokens',
|
|
@@ -860,8 +886,6 @@ function isContextGcMetrics(value) {
|
|
|
860
886
|
'grossReductionRate',
|
|
861
887
|
'cacheRebuildPenaltyCostUnits',
|
|
862
888
|
'compactDeferralCreditCostUnits',
|
|
863
|
-
'requiredPositiveNetRollouts',
|
|
864
|
-
'requiredTargetRoiRollouts',
|
|
865
889
|
'projectedRolloutsUntilCompactAfterGc',
|
|
866
890
|
'contextGrowthSampleCount',
|
|
867
891
|
'contextGrowthP75Tokens',
|
|
@@ -879,6 +903,7 @@ function isContextGcMetrics(value) {
|
|
|
879
903
|
'projectedTokensAfterGc'
|
|
880
904
|
];
|
|
881
905
|
return (nonnegative.every((key) => isNonnegativeFinite(value[key])) &&
|
|
906
|
+
['requiredPositiveNetRollouts', 'requiredTargetRoiRollouts'].every((key) => isNonnegativeFinite(value[key]) || (value.stage === 'INLINE_MEDIA' && value[key] === null)) &&
|
|
882
907
|
optionalNonnegative.every((key) => value[key] === undefined || isNonnegativeFinite(value[key])) &&
|
|
883
908
|
Number.isFinite(value.expectedNetSavedCostUnits) &&
|
|
884
909
|
Number.isFinite(value.cacheInvestmentRoi) &&
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ModelMessage, ModelRequest } from '../model/contracts.js';
|
|
2
|
+
import type { ModelImage } from '../model/image.js';
|
|
3
|
+
import type { SessionRecord } from './store/types.js';
|
|
4
|
+
export declare const INLINE_MEDIA_POLICY: Readonly<{
|
|
5
|
+
historicalInlineMediaTrigger: number;
|
|
6
|
+
historicalInlineMediaTarget: number;
|
|
7
|
+
requestInlineMediaHardLimit: number;
|
|
8
|
+
}>;
|
|
9
|
+
export interface InlineMediaCursor {
|
|
10
|
+
sourceId: string;
|
|
11
|
+
imageIndex: number;
|
|
12
|
+
}
|
|
13
|
+
/** Processing progress, not evidence that the provider inspected an image. */
|
|
14
|
+
export interface InlineMediaState {
|
|
15
|
+
version: 1;
|
|
16
|
+
consideredThrough?: InlineMediaCursor;
|
|
17
|
+
evictedThrough?: InlineMediaCursor;
|
|
18
|
+
}
|
|
19
|
+
export interface InlineMediaGcCheckpoint {
|
|
20
|
+
readonly reason: 'SOFT_LIMIT' | 'HARD_LIMIT' | 'TEXT_GC';
|
|
21
|
+
readonly state: InlineMediaState;
|
|
22
|
+
readonly beforeBytes: number;
|
|
23
|
+
readonly afterBytes: number;
|
|
24
|
+
}
|
|
25
|
+
export interface InlineMediaGcCandidate extends InlineMediaGcCheckpoint {
|
|
26
|
+
/** Apply the proposed eviction to the current visual-window projection. */
|
|
27
|
+
readonly project: (messages: readonly ModelMessage[]) => ModelMessage[];
|
|
28
|
+
}
|
|
29
|
+
export declare function parseInlineMediaGc(value: unknown): InlineMediaGcCheckpoint | undefined;
|
|
30
|
+
export declare function inlineMediaSource(message: ModelMessage): string | ModelMessage;
|
|
31
|
+
/** GC may advance only a durable, already-considered source prefix. */
|
|
32
|
+
export declare function inlineMediaGcAnchored(records: readonly SessionRecord[], media: InlineMediaGcCheckpoint): boolean;
|
|
33
|
+
export declare function inlineMediaBytes(image: ModelImage): number;
|
|
34
|
+
export declare function inlineMediaLimit(): never;
|
|
35
|
+
/** Final encoding guard; URL-only images do not consume the inline budget. */
|
|
36
|
+
export declare function assertInlineMediaBudget(request: Pick<ModelRequest, 'messages' | 'images'>): void;
|
|
37
|
+
export declare function parseInlineMediaState(value: unknown): InlineMediaState | undefined;
|
|
38
|
+
/** Recover ordering once at the lifecycle boundary, including GC-omitted sources. */
|
|
39
|
+
export declare function inlineMediaHistory(records: readonly SessionRecord[]): {
|
|
40
|
+
cursors: (InlineMediaCursor & {
|
|
41
|
+
rollout: number;
|
|
42
|
+
})[];
|
|
43
|
+
rollouts: number;
|
|
44
|
+
state?: InlineMediaState;
|
|
45
|
+
};
|