@myagentroam/agent 0.11.13 → 0.11.15
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/host/contracts.d.ts +2 -2
- package/dist/agent-core/host/contracts.js +1 -2
- package/dist/agent-core/host/local-agent-host.js +1 -2
- package/dist/agent-core/runtime/compaction/requests.d.ts +1 -1
- package/dist/agent-core/runtime/compaction/retained-context.js +1 -1
- package/dist/agent-core/runtime/compaction/smart.d.ts +1 -1
- package/dist/agent-core/runtime/compaction/smart.js +1 -1
- package/dist/agent-core/runtime/context/gc-runtime.d.ts +2 -2
- package/dist/agent-core/runtime/context/gc-runtime.js +9 -6
- package/dist/agent-core/runtime/context/gc.js +43 -29
- package/dist/agent-core/runtime/context/projection.d.ts +1 -1
- package/dist/agent-core/runtime/context/projection.js +4 -4
- package/dist/agent-core/runtime/context/restore.d.ts +3 -2
- package/dist/agent-core/runtime/context/restore.js +2 -3
- package/dist/agent-core/runtime/context/usage.js +1 -1
- package/dist/agent-core/runtime/context/world-state.d.ts +1 -1
- package/dist/agent-core/runtime/context/world-state.js +1 -1
- package/dist/agent-core/runtime/execution-handle.d.ts +12 -0
- package/dist/agent-core/runtime/execution-handle.js +1 -0
- package/dist/agent-core/sdk/agent.js +140 -63
- package/dist/agent-core/sdk/session.d.ts +3 -3
- package/dist/agent-core/sdk/session.js +3 -1
- package/dist/agent-core/sdk/subagent-backend.d.ts +2 -2
- package/dist/agent-core/sdk/types.d.ts +6 -13
- package/dist/agent-core/session/catalog.d.ts +8 -2
- package/dist/agent-core/session/catalog.js +48 -10
- package/dist/agent-core/session/context-gc-checkpoint.d.ts +4 -2
- package/dist/agent-core/session/context-gc-checkpoint.js +15 -7
- package/dist/agent-core/session/store/contracts.d.ts +148 -0
- package/dist/agent-core/session/store/contracts.js +1 -0
- package/dist/agent-core/session/store/execution-state.js +0 -12
- package/dist/agent-core/session/store/jsonl-store.d.ts +7 -30
- package/dist/agent-core/session/store/jsonl-store.js +133 -47
- package/dist/agent-core/session/store/types.d.ts +0 -3
- package/dist/index.d.ts +2 -0
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ import { negotiateHost } from '../host/contracts.js';
|
|
|
7
7
|
import { toolCallers } from '../tools/callers.js';
|
|
8
8
|
import { AnthropicMessagesAdapter } from '../model/anthropic-messages.js';
|
|
9
9
|
import { OpenAiResponsesAdapter } from '../model/openai-responses.js';
|
|
10
|
-
import { JsonlSessionStore } from '../session/store/
|
|
10
|
+
import { JsonlSessionStore } from '../session/store/jsonl-store.js';
|
|
11
11
|
/** Validate models before Host negotiation and expose only built-in protocol adapters. */
|
|
12
12
|
export async function createMarAgent(options) {
|
|
13
13
|
if (Object.hasOwn(options, 'adapterFactory'))
|
|
@@ -23,7 +23,10 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
23
23
|
const description = negotiateHost(await options.host.describe());
|
|
24
24
|
if (description.mode !== options.mode)
|
|
25
25
|
throw new MarAgentError('MAR_AGENT_HOST_INCOMPATIBLE', 'Host mode does not match Agent mode.');
|
|
26
|
-
|
|
26
|
+
if (options.sessionStore === null)
|
|
27
|
+
throw new MarAgentError('MAR_AGENT_SESSION_STORE_INVALID', 'Session store must not be null.');
|
|
28
|
+
const ownsStore = options.sessionStore === undefined;
|
|
29
|
+
const store = options.sessionStore ?? (await JsonlSessionStore.open(description.homeDirectory));
|
|
27
30
|
const active = new Map();
|
|
28
31
|
const activeExecutionAdapters = new Set();
|
|
29
32
|
const executionResults = new Map();
|
|
@@ -59,7 +62,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
59
62
|
}
|
|
60
63
|
return pending;
|
|
61
64
|
};
|
|
62
|
-
let
|
|
65
|
+
let reconfiguration;
|
|
63
66
|
const createAdapter = (modelId, configuredModels = models) => {
|
|
64
67
|
const configuration = configuredModels.get(modelId);
|
|
65
68
|
if (!configuration)
|
|
@@ -193,44 +196,73 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
193
196
|
assertSessionAdmission,
|
|
194
197
|
assertCanStart: (sessionId) => {
|
|
195
198
|
assertSessionAdmission(sessionId);
|
|
196
|
-
if (
|
|
199
|
+
if (reconfiguration)
|
|
197
200
|
throw new MarAgentError('MAR_AGENT_EXECUTION_ACTIVE', 'Models are being reconfigured for the next execution.');
|
|
198
201
|
}
|
|
199
202
|
});
|
|
200
203
|
return {
|
|
201
204
|
extensionDiagnostics: () => extensions.diagnostics(),
|
|
202
|
-
createSession: async (input) =>
|
|
205
|
+
createSession: async (input) => {
|
|
206
|
+
assertSessionAdmission();
|
|
207
|
+
return openSession((await store.createSession(input)).id, input.workspace);
|
|
208
|
+
},
|
|
203
209
|
openSession: (id) => openSession(id),
|
|
204
|
-
listSessions: (input) =>
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
listSessions: async (input) => {
|
|
211
|
+
assertSessionAdmission();
|
|
212
|
+
return store.list(input);
|
|
213
|
+
},
|
|
214
|
+
getSession: async (id) => {
|
|
215
|
+
assertSessionAdmission();
|
|
216
|
+
return store.getSession(id);
|
|
217
|
+
},
|
|
218
|
+
setSessionTitle: async (id, title, input) => {
|
|
219
|
+
assertSessionAdmission();
|
|
220
|
+
return store.updateTitle(id, title, { ...input, automatic: input?.automatic ?? false }, sessionWriterOwner);
|
|
221
|
+
},
|
|
207
222
|
clearSession: (id) => trackSessionLifecycle(id, 'clear', async () => {
|
|
208
223
|
const runtime = sessionRuntimes.get(id);
|
|
209
224
|
if ([...active.keys()].some((key) => key.startsWith(`${id}:`)))
|
|
210
225
|
throw new MarAgentError('MAR_AGENT_EXECUTION_ACTIVE', 'A session cannot be cleared while an execution is active.');
|
|
211
|
-
await
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
runtime
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
226
|
+
const maintenance = await store.acquireSessionMaintenance(id, 'clear', sessionWriterOwner);
|
|
227
|
+
let failed = false;
|
|
228
|
+
try {
|
|
229
|
+
await completeAgentCleanup([
|
|
230
|
+
() => extensions.endSession(id, 'clear'),
|
|
231
|
+
() => extensions.retireSession(id),
|
|
232
|
+
() => extensions.clearSession(id),
|
|
233
|
+
() => runtime?.inputs?.retire(),
|
|
234
|
+
() => runtime?.subagents?.dispose(),
|
|
235
|
+
() => closeModelAdapters(runtime === undefined ? [] : [...runtime.adapters.values()]),
|
|
236
|
+
() => {
|
|
237
|
+
// Existing SDK Session handles share this runtime and remain usable after clear.
|
|
238
|
+
if (runtime) {
|
|
239
|
+
runtime.adapters.clear();
|
|
240
|
+
runtime.adapterGeneration = modelGeneration;
|
|
241
|
+
delete runtime.todo;
|
|
242
|
+
delete runtime.subagents;
|
|
243
|
+
delete runtime.subagentsOpening;
|
|
244
|
+
delete runtime.contextualWorldState;
|
|
245
|
+
delete runtime.inputs;
|
|
246
|
+
delete runtime.requestSnapshots;
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
() => options.host.disposeSessionResources?.(id),
|
|
250
|
+
() => store.clearSession(id, maintenance)
|
|
251
|
+
]);
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
failed = true;
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
try {
|
|
259
|
+
await maintenance.release();
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
if (!failed)
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
234
266
|
}),
|
|
235
267
|
setSystemInstruction: (systemInstruction) => {
|
|
236
268
|
if (disposed)
|
|
@@ -243,7 +275,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
243
275
|
reconfigureModels: async (input) => {
|
|
244
276
|
if (disposed)
|
|
245
277
|
throw new MarAgentError('MAR_AGENT_DISPOSED', 'Agent is disposed.');
|
|
246
|
-
if (
|
|
278
|
+
if (reconfiguration)
|
|
247
279
|
throw new MarAgentError('MAR_AGENT_EXECUTION_ACTIVE', 'Models are already being reconfigured for the next execution.');
|
|
248
280
|
const next = resolveAgentModels(input.models, input.defaultModelId);
|
|
249
281
|
const activeSessions = activeSessionIds();
|
|
@@ -255,7 +287,10 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
255
287
|
for (const adapter of runtime.adapters.values())
|
|
256
288
|
activeAdapters.add(adapter);
|
|
257
289
|
const inactiveRuntimes = [...sessionRuntimes].flatMap(([sessionId, runtime]) => activeSessions.has(sessionId) ? [] : [runtime]);
|
|
258
|
-
|
|
290
|
+
const completion = Promise.withResolvers();
|
|
291
|
+
reconfiguration = completion.promise;
|
|
292
|
+
void completion.promise.catch(() => undefined);
|
|
293
|
+
let interruptedByDisposal = false;
|
|
259
294
|
try {
|
|
260
295
|
const reconfigurationCommits = new Map();
|
|
261
296
|
for (const runtime of inactiveRuntimes)
|
|
@@ -277,8 +312,10 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
277
312
|
runtime.adapters.delete(modelId);
|
|
278
313
|
}
|
|
279
314
|
await closeModelAdapters(adapters);
|
|
280
|
-
if (disposed)
|
|
315
|
+
if (disposed) {
|
|
316
|
+
interruptedByDisposal = true;
|
|
281
317
|
throw new MarAgentError('MAR_AGENT_DISPOSED', 'Agent is disposed.');
|
|
318
|
+
}
|
|
282
319
|
for (const commit of reconfigurationCommits.values())
|
|
283
320
|
commit();
|
|
284
321
|
models = next.models;
|
|
@@ -296,41 +333,79 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
296
333
|
for (const adapter of runtime.adapters.values())
|
|
297
334
|
addModelCredentialProviders(liveProviders, adapter.configuration);
|
|
298
335
|
const obsoleteProviders = [...credentialProviders].filter((provider) => !liveProviders.has(provider));
|
|
299
|
-
const providerCloseResults = await Promise.allSettled(obsoleteProviders.map((provider) => provider.close()));
|
|
336
|
+
const providerCloseResults = await Promise.allSettled(obsoleteProviders.map(async (provider) => provider.close()));
|
|
300
337
|
for (const [index, result] of providerCloseResults.entries())
|
|
301
338
|
if (result.status === 'fulfilled')
|
|
302
339
|
credentialProviders.delete(obsoleteProviders[index]);
|
|
303
340
|
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
if (!interruptedByDisposal)
|
|
343
|
+
completion.reject(error);
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
304
346
|
finally {
|
|
305
|
-
|
|
347
|
+
completion.resolve();
|
|
348
|
+
if (reconfiguration === completion.promise)
|
|
349
|
+
reconfiguration = undefined;
|
|
306
350
|
}
|
|
307
351
|
},
|
|
308
352
|
deleteSession: (id) => trackSessionLifecycle(id, 'delete', async () => {
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
353
|
+
const maintenance = await store.acquireSessionMaintenance(id, 'delete', sessionWriterOwner);
|
|
354
|
+
let failed = false;
|
|
355
|
+
try {
|
|
356
|
+
const sessionIds = maintenance.sessionIds;
|
|
357
|
+
const sessionIdSet = new Set(sessionIds);
|
|
358
|
+
const executionKeys = [...active.keys()].filter((key) => sessionIdSet.has(key.slice(0, key.indexOf(':'))));
|
|
359
|
+
for (const key of executionKeys)
|
|
360
|
+
active.get(key)?.abort();
|
|
361
|
+
const runtimes = sessionIds.flatMap((sessionId) => {
|
|
362
|
+
const runtime = sessionRuntimes.get(sessionId);
|
|
363
|
+
return runtime === undefined ? [] : [runtime];
|
|
364
|
+
});
|
|
365
|
+
await completeAgentCleanup([
|
|
366
|
+
async () => {
|
|
367
|
+
let failure;
|
|
368
|
+
await Promise.all(sessionIds.map(async (sessionId) => {
|
|
369
|
+
try {
|
|
370
|
+
await extensions.endSession(sessionId, 'other', false);
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
failure ??= { error };
|
|
374
|
+
}
|
|
375
|
+
}));
|
|
376
|
+
if (failure)
|
|
377
|
+
throw failure.error;
|
|
378
|
+
},
|
|
379
|
+
...sessionIds.map((sessionId) => () => extensions.retireSession(sessionId)),
|
|
380
|
+
() => {
|
|
381
|
+
for (const sessionId of sessionIds)
|
|
382
|
+
sessionRuntimes.delete(sessionId);
|
|
383
|
+
},
|
|
384
|
+
...sessionIds.map((sessionId) => () => extensions.clearSession(sessionId)),
|
|
385
|
+
...runtimes.map((runtime) => () => runtime.inputs?.retire()),
|
|
386
|
+
...runtimes.map((runtime) => () => runtime.subagents?.dispose()),
|
|
387
|
+
() => Promise.allSettled(executionKeys.flatMap((key) => {
|
|
388
|
+
const result = executionResults.get(key);
|
|
389
|
+
return result === undefined ? [] : [result];
|
|
390
|
+
})),
|
|
391
|
+
() => closeModelAdapters(runtimes.flatMap((runtime) => [...runtime.adapters.values()])),
|
|
392
|
+
...sessionIds.map((sessionId) => () => options.host.disposeSessionResources?.(sessionId)),
|
|
393
|
+
() => store.delete(id, maintenance)
|
|
394
|
+
]);
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
failed = true;
|
|
398
|
+
throw error;
|
|
399
|
+
}
|
|
400
|
+
finally {
|
|
401
|
+
try {
|
|
402
|
+
await maintenance.release();
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
if (!failed)
|
|
406
|
+
throw error;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
334
409
|
}),
|
|
335
410
|
dispose: () => {
|
|
336
411
|
if (disposal)
|
|
@@ -342,6 +417,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
342
417
|
const extensionDisposal = extensions.dispose();
|
|
343
418
|
void extensionDisposal.catch(() => undefined);
|
|
344
419
|
const runtimes = [...sessionRuntimes.values()];
|
|
420
|
+
const pendingReconfiguration = reconfiguration;
|
|
345
421
|
disposal = completeAgentCleanup([
|
|
346
422
|
async () => {
|
|
347
423
|
const results = await Promise.allSettled([...sessionLifecycles.values()].map(({ pending }) => pending));
|
|
@@ -353,10 +429,11 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
353
429
|
...runtimes.map((runtime) => () => runtime.inputs?.retire()),
|
|
354
430
|
...runtimes.map((runtime) => () => runtime.subagents?.dispose()),
|
|
355
431
|
() => Promise.allSettled([...executionResults.values()]),
|
|
432
|
+
() => pendingReconfiguration,
|
|
356
433
|
() => closeModelAdapters(runtimes.flatMap((runtime) => [...runtime.adapters.values()])),
|
|
357
|
-
|
|
434
|
+
() => completeAgentCleanup([...credentialProviders].map((provider) => () => provider.close())),
|
|
358
435
|
() => options.host.dispose(),
|
|
359
|
-
() => store.close()
|
|
436
|
+
() => (ownsStore ? store.close() : undefined)
|
|
360
437
|
]);
|
|
361
438
|
return disposal;
|
|
362
439
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SessionStore } from '../session/store/contracts.js';
|
|
1
2
|
import type { ContextualWorldState } from '../runtime/context/world-state.js';
|
|
2
3
|
import type { ResolvedModelConfiguration } from './model-runtime.js';
|
|
3
4
|
import { ExecutionToolSources } from './extension-tools.js';
|
|
@@ -10,7 +11,6 @@ import type { HostDescription, MarAgentHost } from '../host/contracts.js';
|
|
|
10
11
|
import type { MarAgentReasoningEffort } from '../model/configuration.js';
|
|
11
12
|
import type { ModelAdapter, ModelMessage } from '../model/contracts.js';
|
|
12
13
|
import { CompactRequests } from '../runtime/compaction/requests.js';
|
|
13
|
-
import { JsonlSessionStore } from '../session/store/index.js';
|
|
14
14
|
import { SubagentSessionController, type SubagentMailboxMessage, type SubagentMessageDelivery, type SubagentTurnHandle } from '../subagent/session-controller.js';
|
|
15
15
|
import { createSessionToolScheduler } from '../tools/scheduler.js';
|
|
16
16
|
import { TodoStore } from '../tools/agent/todo.js';
|
|
@@ -75,7 +75,7 @@ interface SessionServices {
|
|
|
75
75
|
readonly host: MarAgentHost;
|
|
76
76
|
readonly description: HostDescription;
|
|
77
77
|
readonly settings: Pick<CreateMarAgentOptions, 'workspaceMapping' | 'systemInstruction'>;
|
|
78
|
-
readonly store:
|
|
78
|
+
readonly store: SessionStore;
|
|
79
79
|
readonly extensions: ExtensionManager;
|
|
80
80
|
readonly registry: AgentSessionRegistry;
|
|
81
81
|
readonly hasCustomAdapters: boolean;
|
|
@@ -87,7 +87,7 @@ interface SessionServices {
|
|
|
87
87
|
readonly createAdapter: (modelId: string, models: ReadonlyMap<string, ResolvedModelConfiguration>) => ModelAdapter;
|
|
88
88
|
readonly activeAdaptersExcept: (sessionId: string) => ReadonlySet<ModelAdapter>;
|
|
89
89
|
readonly assertCanStart: (sessionId?: string) => void;
|
|
90
|
-
readonly assertSessionAdmission: (sessionId
|
|
90
|
+
readonly assertSessionAdmission: (sessionId?: string) => void;
|
|
91
91
|
}
|
|
92
92
|
/** SDK Session orchestration owns warm resources; Runtime owns only the model/tool loop. */
|
|
93
93
|
export declare function createSessionOpener(services: SessionServices): (sessionId: string, workspace?: string) => Promise<InternalMarAgentSession>;
|
|
@@ -45,7 +45,7 @@ import { AGENT_EXECUTION_POLICY } from '../runtime/execution-policy.js';
|
|
|
45
45
|
import { loadAgentInstructions, renderAgentInstructions } from '../runtime/context/instructions.js';
|
|
46
46
|
import { normalizeMessagesForModel } from '../runtime/context/normalize.js';
|
|
47
47
|
import { latestSmartContextTokens, requestSmartCompaction } from '../runtime/compaction/smart.js';
|
|
48
|
-
import { compactSummaryFromCheckpoint, inputMetadataFromRecord } from '../session/store/
|
|
48
|
+
import { compactSummaryFromCheckpoint, inputMetadataFromRecord } from '../session/store/execution-state.js';
|
|
49
49
|
import { SubagentSessionController } from '../subagent/session-controller.js';
|
|
50
50
|
import { agentStartToolDefinitionWithModels } from '../tools/agent/agent-start.js';
|
|
51
51
|
import { allowsDirectTool, allowsToolCaller, toolCallers } from '../tools/callers.js';
|
|
@@ -59,7 +59,9 @@ export function createSessionOpener(services) {
|
|
|
59
59
|
const { host, description, settings, store, createAdapter, activeAdaptersExcept } = services;
|
|
60
60
|
const { active, activeExecutionAdapters, executionResults, sessionRuntimes, sessionWriterOwner } = services.registry;
|
|
61
61
|
const openSession = async (sessionId, workspace) => {
|
|
62
|
+
services.assertSessionAdmission();
|
|
62
63
|
const storedSession = await store.getSession(sessionId);
|
|
64
|
+
services.assertSessionAdmission();
|
|
63
65
|
const storedWorkspace = storedSession.workspace;
|
|
64
66
|
const sessionSource = storedSession.source;
|
|
65
67
|
const logicalWorkspace = settings.workspaceMapping?.logicalPath ?? workspace ?? storedWorkspace ?? '';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SessionStore } from '../session/store/contracts.js';
|
|
2
2
|
import type { SubagentSessionControllerBackend } from '../subagent/session-controller.js';
|
|
3
|
-
export declare function createSubagentBackend(store:
|
|
3
|
+
export declare function createSubagentBackend(store: SessionStore, workspace: string): SubagentSessionControllerBackend;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { MarAgentHost } from '../host/contracts.js';
|
|
2
2
|
import type { CoreExtensionSource, CoreRuntimeExtension } from '../extensions/contracts.js';
|
|
3
3
|
import type { MarAgentModelConfiguration } from '../model/configuration.js';
|
|
4
|
-
import type {
|
|
5
|
-
import type {
|
|
4
|
+
import type { RolloutBudgetOptions, RunInput } from '../runtime/contracts.js';
|
|
5
|
+
import type { CompactInput, ExecutionHandle } from '../runtime/execution-handle.js';
|
|
6
6
|
import type { MarAgentSessionPage, MarAgentSessionSummary } from '../session/catalog.js';
|
|
7
7
|
import type { SessionListInput, SessionSource, SessionTitleUpdateInput } from '../session/types.js';
|
|
8
8
|
export interface CreateSessionInput {
|
|
@@ -13,17 +13,8 @@ export type { SessionTitleUpdateInput } from '../session/types.js';
|
|
|
13
13
|
export type { HostExecutionExtensions, HostSessionResourceSnapshot, HostSkill, MarAgentHost } from '../host/contracts.js';
|
|
14
14
|
export type { AccessMode, ExecutionMode, ExecutionResult, MarAgentImageMetadata, RolloutBudgetOptions, RunInput, RunInputImage } from '../runtime/contracts.js';
|
|
15
15
|
export type { MarAgentEvent, MarAgentEventBase } from '../runtime/events.js';
|
|
16
|
+
export type { CompactInput, ExecutionHandle } from '../runtime/execution-handle.js';
|
|
16
17
|
export type { CodeCellEventData, MarAgentToolArtifact, MarAgentToolImageArtifact, McpCatalogTool, McpToolCallContext, McpToolCatalog, McpToolCatalogContext, ToolCall, ToolExecutionContext, ToolExecutionResult } from '../tools/contracts.js';
|
|
17
|
-
/** A live execution exposes streamed events separately from its terminal result. */
|
|
18
|
-
export interface ExecutionHandle extends AsyncIterable<MarAgentEvent> {
|
|
19
|
-
readonly executionId: string;
|
|
20
|
-
result(): Promise<ExecutionResult>;
|
|
21
|
-
/** Signals abort; await result() to observe the terminal status and cleanup. */
|
|
22
|
-
cancel(): void;
|
|
23
|
-
}
|
|
24
|
-
export type CompactInput = Partial<RunInput> & {
|
|
25
|
-
readonly async?: boolean;
|
|
26
|
-
};
|
|
27
18
|
export interface SteerInput {
|
|
28
19
|
readonly expectedExecutionId: string;
|
|
29
20
|
readonly prompt: string;
|
|
@@ -68,10 +59,12 @@ export interface MarAgent {
|
|
|
68
59
|
readonly defaultModelId?: string;
|
|
69
60
|
}): Promise<void>;
|
|
70
61
|
deleteSession(sessionId: string): Promise<void>;
|
|
71
|
-
/**
|
|
62
|
+
/** Joins executions/reconfiguration, closes owned resources, and releases borrowed Store leases. */
|
|
72
63
|
dispose(): Promise<void>;
|
|
73
64
|
}
|
|
74
65
|
export interface CreateMarAgentOptions {
|
|
66
|
+
/** Ready-to-use borrowed Store. The caller closes it after all Agent/Catalog users finish. */
|
|
67
|
+
sessionStore?: import('../session/store/contracts.js').SessionStore;
|
|
75
68
|
mode: 'normal' | 'node';
|
|
76
69
|
host: MarAgentHost;
|
|
77
70
|
models: readonly MarAgentModelConfiguration[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MarAgentImageMetadata } from '../runtime/contracts.js';
|
|
2
2
|
import type { MarAgentEvent } from '../runtime/events.js';
|
|
3
|
+
import type { SessionStore } from './store/contracts.js';
|
|
3
4
|
import type { SessionListInput, SessionSource } from './types.js';
|
|
4
5
|
export interface MarAgentSessionSummary {
|
|
5
6
|
id: string;
|
|
@@ -84,7 +85,12 @@ export interface MarAgentSessionCatalog {
|
|
|
84
85
|
delete(sessionId: string): Promise<MarAgentSessionDeleteResult>;
|
|
85
86
|
close(): Promise<void>;
|
|
86
87
|
}
|
|
87
|
-
export
|
|
88
|
+
export type OpenMarAgentSessionCatalogInput = {
|
|
88
89
|
homeDirectory: string;
|
|
89
|
-
|
|
90
|
+
sessionStore?: never;
|
|
91
|
+
} | {
|
|
92
|
+
sessionStore: SessionStore;
|
|
93
|
+
homeDirectory?: never;
|
|
94
|
+
};
|
|
95
|
+
export declare function openMarAgentSessionCatalog(input: OpenMarAgentSessionCatalogInput): Promise<MarAgentSessionCatalog>;
|
|
90
96
|
export declare function imageMetadata(value: unknown): MarAgentHistoryImageMetadata[];
|
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
import { MarAgentError } from '../error.js';
|
|
2
2
|
import { publicHostedToolEvents } from '../runtime/event-projection.js';
|
|
3
|
-
import { JsonlSessionStore } from './store/
|
|
3
|
+
import { JsonlSessionStore } from './store/jsonl-store.js';
|
|
4
4
|
const MAX_INPUT_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
5
5
|
const INPUT_IMAGE_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);
|
|
6
6
|
export async function openMarAgentSessionCatalog(input) {
|
|
7
|
-
const
|
|
7
|
+
const borrowed = input.sessionStore !== undefined;
|
|
8
|
+
if (input.sessionStore === null ||
|
|
9
|
+
borrowed === (input.homeDirectory !== undefined) ||
|
|
10
|
+
(!borrowed && (typeof input.homeDirectory !== 'string' || !input.homeDirectory)))
|
|
11
|
+
throw new MarAgentError('MAR_AGENT_SESSION_STORE_INVALID', 'Specify exactly one Session store or home directory.');
|
|
12
|
+
const store = input.sessionStore ?? (await JsonlSessionStore.open(input.homeDirectory));
|
|
13
|
+
let closure;
|
|
14
|
+
const assertOpen = () => {
|
|
15
|
+
if (closure)
|
|
16
|
+
throw new MarAgentError('MAR_AGENT_DISPOSED', 'Session catalog is closed.');
|
|
17
|
+
};
|
|
8
18
|
return {
|
|
9
|
-
list: (options) =>
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
list: async (options) => {
|
|
20
|
+
assertOpen();
|
|
21
|
+
return store.list(options);
|
|
22
|
+
},
|
|
23
|
+
firstUserMessagePreview: async (sessionId) => {
|
|
24
|
+
assertOpen();
|
|
25
|
+
return store.firstUserMessagePreview(sessionId);
|
|
26
|
+
},
|
|
27
|
+
executionConfiguration: async (sessionId) => {
|
|
28
|
+
assertOpen();
|
|
29
|
+
return store.executionConfiguration(sessionId);
|
|
30
|
+
},
|
|
12
31
|
history: async (sessionId, options = {}) => {
|
|
32
|
+
assertOpen();
|
|
13
33
|
const beforeSequence = parseCursor(options.cursor);
|
|
14
34
|
const page = await store.readPage(sessionId, {
|
|
15
35
|
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
@@ -72,6 +92,7 @@ export async function openMarAgentSessionCatalog(input) {
|
|
|
72
92
|
};
|
|
73
93
|
},
|
|
74
94
|
readImage: async (sessionId, input) => {
|
|
95
|
+
assertOpen();
|
|
75
96
|
const image = await store.readInputImage(sessionId, input);
|
|
76
97
|
return image === undefined
|
|
77
98
|
? undefined
|
|
@@ -82,8 +103,12 @@ export async function openMarAgentSessionCatalog(input) {
|
|
|
82
103
|
dataBase64: image.dataBase64
|
|
83
104
|
};
|
|
84
105
|
},
|
|
85
|
-
readToolResultResource: (sessionId, input) =>
|
|
106
|
+
readToolResultResource: async (sessionId, input) => {
|
|
107
|
+
assertOpen();
|
|
108
|
+
return store.readToolResultResource(sessionId, input);
|
|
109
|
+
},
|
|
86
110
|
contextUsage: async (sessionId) => {
|
|
111
|
+
assertOpen();
|
|
87
112
|
const page = await store.readPage(sessionId, { limit: 1000 });
|
|
88
113
|
for (const record of page.records.toReversed()) {
|
|
89
114
|
if (!isMarAgentEvent(record.payload))
|
|
@@ -101,13 +126,26 @@ export async function openMarAgentSessionCatalog(input) {
|
|
|
101
126
|
return undefined;
|
|
102
127
|
},
|
|
103
128
|
fork: async (sessionId, options) => {
|
|
129
|
+
assertOpen();
|
|
104
130
|
const session = await store.forkSession(sessionId, options);
|
|
105
131
|
return { ...session, source: session.source ?? { type: 'user' } };
|
|
106
132
|
},
|
|
107
|
-
rollback: (sessionId, options) =>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
133
|
+
rollback: async (sessionId, options) => {
|
|
134
|
+
assertOpen();
|
|
135
|
+
return store.rollbackSession(sessionId, options);
|
|
136
|
+
},
|
|
137
|
+
clear: async (sessionId) => {
|
|
138
|
+
assertOpen();
|
|
139
|
+
return store.clearSession(sessionId);
|
|
140
|
+
},
|
|
141
|
+
delete: async (sessionId) => {
|
|
142
|
+
assertOpen();
|
|
143
|
+
return store.delete(sessionId);
|
|
144
|
+
},
|
|
145
|
+
close: () => {
|
|
146
|
+
closure ??= Promise.resolve().then(() => (borrowed ? undefined : store.close()));
|
|
147
|
+
return closure;
|
|
148
|
+
}
|
|
111
149
|
};
|
|
112
150
|
}
|
|
113
151
|
function parseCursor(cursor) {
|
|
@@ -143,9 +143,11 @@ export interface ContextGcCheckpointPayload extends ContextGcCheckpointDraft {
|
|
|
143
143
|
/** Disposable memoization for one evaluation's immutable record snapshot. */
|
|
144
144
|
export declare class ContextGcCheckpointCache {
|
|
145
145
|
#private;
|
|
146
|
-
read(records: readonly SessionRecord[], boundarySequence?: number
|
|
146
|
+
read(records: readonly SessionRecord[], boundarySequence?: number): ReturnType<typeof latestValidContextGcCheckpoint>;
|
|
147
147
|
}
|
|
148
148
|
export declare function contextGcMinimumUsageGrowth(contextWindowTokens: number): number;
|
|
149
|
+
/** Compare adjacent checkpoint triggers only within the same model/window scope. */
|
|
150
|
+
export declare function contextGcCheckpointIntervalEligible(trigger: ContextGcCheckpointDraft['trigger'], previous?: ContextGcCheckpointDraft['trigger']): boolean;
|
|
149
151
|
export declare function contextGcLogicalPathKey(path: string, workspace: string, platform?: ContextGcPlatform): string | undefined;
|
|
150
152
|
export declare function contextGcTargetKey(target: ContextGcTarget): string;
|
|
151
153
|
export declare function contextGcReplacementKey(replacement: ContextGcReplacement): string;
|
|
@@ -154,7 +156,7 @@ export declare function contextGcBaseSequence(base: ContextGcBase): number;
|
|
|
154
156
|
export declare function normalizeContextGcReplacements(replacements: readonly ContextGcReplacement[]): ContextGcReplacement[] | undefined;
|
|
155
157
|
export declare function parseContextGcCheckpoint(record: SessionRecord | undefined): ContextGcCheckpointPayload | undefined;
|
|
156
158
|
export declare function validateContextGcCheckpoint(records: readonly SessionRecord[], record: SessionRecord, workspace?: string | undefined, committedReplacements?: readonly ContextGcReplacement[]): ContextGcCheckpointPayload | undefined;
|
|
157
|
-
export declare function latestValidContextGcCheckpoint(records: readonly SessionRecord[], boundarySequence?: number
|
|
159
|
+
export declare function latestValidContextGcCheckpoint(records: readonly SessionRecord[], boundarySequence?: number): {
|
|
158
160
|
readonly record: SessionRecord;
|
|
159
161
|
readonly payload: ContextGcCheckpointPayload;
|
|
160
162
|
} | undefined;
|
|
@@ -9,20 +9,28 @@ export const CONTEXT_GC_MAX_TARGETS = 4_096;
|
|
|
9
9
|
/** Disposable memoization for one evaluation's immutable record snapshot. */
|
|
10
10
|
export class ContextGcCheckpointCache {
|
|
11
11
|
#snapshot;
|
|
12
|
-
read(records, boundarySequence = records.at(-1)?.sequence ?? 0
|
|
12
|
+
read(records, boundarySequence = records.at(-1)?.sequence ?? 0) {
|
|
13
13
|
const cached = this.#snapshot;
|
|
14
|
-
if (cached?.records === records &&
|
|
15
|
-
cached.boundarySequence === boundarySequence &&
|
|
16
|
-
cached.workspace === workspace)
|
|
14
|
+
if (cached?.records === records && cached.boundarySequence === boundarySequence)
|
|
17
15
|
return cached.value;
|
|
18
|
-
const value = latestValidContextGcCheckpoint(records, boundarySequence
|
|
19
|
-
this.#snapshot = { records, boundarySequence,
|
|
16
|
+
const value = latestValidContextGcCheckpoint(records, boundarySequence);
|
|
17
|
+
this.#snapshot = { records, boundarySequence, value };
|
|
20
18
|
return value;
|
|
21
19
|
}
|
|
22
20
|
}
|
|
23
21
|
export function contextGcMinimumUsageGrowth(contextWindowTokens) {
|
|
24
22
|
return Math.max(2_000, Math.floor(contextWindowTokens * 0.05));
|
|
25
23
|
}
|
|
24
|
+
/** Compare adjacent checkpoint triggers only within the same model/window scope. */
|
|
25
|
+
export function contextGcCheckpointIntervalEligible(trigger, previous) {
|
|
26
|
+
if (!previous ||
|
|
27
|
+
trigger.modelId !== previous.modelId ||
|
|
28
|
+
trigger.contextWindowTokens !== previous.contextWindowTokens)
|
|
29
|
+
return true;
|
|
30
|
+
return (trigger.normalRolloutOrdinal - previous.normalRolloutOrdinal >= 2 &&
|
|
31
|
+
trigger.contextInputTokens - previous.contextInputTokens >=
|
|
32
|
+
contextGcMinimumUsageGrowth(trigger.contextWindowTokens));
|
|
33
|
+
}
|
|
26
34
|
export function contextGcLogicalPathKey(path, workspace, platform) {
|
|
27
35
|
if (!path || !workspace || path.includes('\0') || workspace.includes('\0'))
|
|
28
36
|
return undefined;
|
|
@@ -198,7 +206,7 @@ export function validateContextGcCheckpoint(records, record, workspace = session
|
|
|
198
206
|
}
|
|
199
207
|
return payload;
|
|
200
208
|
}
|
|
201
|
-
export function latestValidContextGcCheckpoint(records, boundarySequence = records.at(-1)?.sequence ?? 0
|
|
209
|
+
export function latestValidContextGcCheckpoint(records, boundarySequence = records.at(-1)?.sequence ?? 0) {
|
|
202
210
|
const base = contextGcBaseFromRecords(records, boundarySequence);
|
|
203
211
|
if (!base)
|
|
204
212
|
return undefined;
|