@myagentroam/agent 0.11.12 → 0.11.14

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.
@@ -1,4 +1,4 @@
1
- import { parseModelInputMetadata } from '../../session/store/index.js';
1
+ import { parseModelInputMetadata } from '../../session/store/execution-state.js';
2
2
  import { restoreModelContext } from '../context/projection.js';
3
3
  /** Use a public native identity, never private context text, as the visible boundary. */
4
4
  export function compactSnapshotAnchor(messages, sources) {
@@ -1,5 +1,5 @@
1
1
  import type { ModelMessage } from '../../model/contracts.js';
2
- import { type SessionRecord } from '../../session/store/index.js';
2
+ import type { SessionRecord } from '../../session/store/contracts.js';
3
3
  export declare const SMART_COMPACTION_MARKER = "<mar_runtime>\n <smart_compaction>For this message only, smart_compact may be considered at a clear transition into sustained new work, when the previous phase is largely complete and its details have low continuation value.</smart_compaction>\n</mar_runtime>";
4
4
  export interface SmartCompactionInput {
5
5
  readonly recordId: string;
@@ -1,5 +1,5 @@
1
1
  import { MarAgentError } from '../../error.js';
2
- import { compactSummaryFromCheckpoint } from '../../session/store/index.js';
2
+ import { compactSummaryFromCheckpoint } from '../../session/store/execution-state.js';
3
3
  export const SMART_COMPACTION_MARKER = '<mar_runtime>\n <smart_compaction>For this message only, smart_compact may be considered at a clear transition into sustained new work, when the previous phase is largely complete and its details have low continuation value.</smart_compaction>\n</mar_runtime>';
4
4
  /** A measured watermark, not the stricter native-request budget calibration. */
5
5
  export function latestSmartContextTokens(records, modelId, contextWindowTokens) {
@@ -1,9 +1,9 @@
1
1
  import type { ClientToolDefinition, ModelUsage } from '../../model/contracts.js';
2
2
  import { type ContextGcPlatform } from '../../session/context-gc-checkpoint.js';
3
- import { JsonlSessionStore, type SessionRecord } from '../../session/store/index.js';
3
+ import type { SessionStore, SessionRecord } from '../../session/store/contracts.js';
4
4
  import { type ContextProjection } from './projection.js';
5
5
  export interface ContextGcRuntimeInput {
6
- readonly store: JsonlSessionStore;
6
+ readonly store: SessionStore;
7
7
  readonly sessionId: string;
8
8
  readonly records?: readonly SessionRecord[];
9
9
  readonly system: string;
@@ -1,6 +1,6 @@
1
1
  import { restoreNativeModelContext } from '../../model/native-context.js';
2
2
  import { appliedInputRecord } from '../../session/deferred-input.js';
3
- import { inputMetadataFromRecord } from '../../session/store/index.js';
3
+ import { inputMetadataFromRecord } from '../../session/store/execution-state.js';
4
4
  import { contextGcTargetKey, latestValidContextGcCheckpoint } from '../../session/context-gc-checkpoint.js';
5
5
  import { TOOL_EXECUTION_LIMITS } from '../../tools/execution-limits.js';
6
6
  import { replaceReadContextItems } from '../../tools/local/read-context.js';
@@ -1,8 +1,9 @@
1
+ import type { SessionStore } from '../../session/store/contracts.js';
1
2
  import type { ModelMessage } from '../../model/contracts.js';
2
- import { type CompactUserInput, type JsonlSessionStore } from '../../session/store/index.js';
3
+ import type { CompactUserInput } from '../../session/store/contracts.js';
3
4
  import type { EnvironmentContextState } from './contracts.js';
4
5
  import { type ContextProjection } from './projection.js';
5
- export declare function restoreMessages(store: JsonlSessionStore, sessionId: string, records: readonly import('../../session/store/index.js').SessionRecord[], options: {
6
+ export declare function restoreMessages(store: SessionStore, sessionId: string, records: readonly import('../../session/store/index.js').SessionRecord[], options: {
6
7
  includeImages: boolean;
7
8
  strictImages?: boolean;
8
9
  currentTurnId?: string;
@@ -1,6 +1,6 @@
1
1
  import { MarAgentError } from '../../error.js';
2
2
  import { appliedInputRecord, pendingDeferredInputs } from '../../session/deferred-input.js';
3
- import { compactSummaryFromCheckpoint, replacementHistoryFromCheckpoint, inputMetadataFromRecord } from '../../session/store/index.js';
3
+ import { compactSummaryFromCheckpoint, replacementHistoryFromCheckpoint, inputMetadataFromRecord } from '../../session/store/execution-state.js';
4
4
  import { compactedHistoryMessages, continuationMessage } from '../compaction/history.js';
5
5
  import { restoreCompactTail } from '../compaction/retained-context.js';
6
6
  import { environmentContextUpdate, restoreEnvironmentState } from './environment.js';
@@ -1,6 +1,6 @@
1
1
  import { isDeepStrictEqual } from 'node:util';
2
2
  import { marAgentReasoningEffortSchema } from '../../model/configuration.js';
3
- import { compactSummaryFromCheckpoint } from '../../session/store/index.js';
3
+ import { compactSummaryFromCheckpoint } from '../../session/store/execution-state.js';
4
4
  import { estimatedRequestTokens } from './request-budget.js';
5
5
  export function latestModelUsage(records, selectedModelId) {
6
6
  let usage;
@@ -19,7 +19,7 @@ export declare function insertContextualWorldState(messages: readonly ModelMessa
19
19
  export declare function latestContextualWorldStateGeneration(records: readonly import('../../session/store/index.js').SessionRecord[]): string | undefined;
20
20
  export declare function updatePromptWorldState(state: ContextualWorldState, index: number, parts: readonly ContextualPart[]): ContextualWorldState;
21
21
  export declare function parsePersistedContextualWorldState(payload: unknown): ContextualWorldState | undefined;
22
- export declare function persistContextualWorldState(store: import('../../session/store/index.js').JsonlSessionStore, sessionId: string, state: ContextualWorldState): Promise<void>;
22
+ export declare function persistContextualWorldState(store: import('../../session/store/contracts.js').SessionStore, sessionId: string, state: ContextualWorldState): Promise<void>;
23
23
  export declare function updateContextualWorldState(state: ContextualWorldState, index: number, current: {
24
24
  instructionSnapshot: string | undefined;
25
25
  instructionContent: string | undefined;
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { MarAgentError } from '../../error.js';
3
3
  import { contextualBlock, contextualChanges } from './contextual-blocks.js';
4
- import { compactSummaryFromCheckpoint } from '../../session/store/index.js';
4
+ import { compactSummaryFromCheckpoint } from '../../session/store/execution-state.js';
5
5
  export function insertContextualWorldState(messages, entries) {
6
6
  const result = [...messages];
7
7
  // Entries can be restored before the latest user after Compact. Sort anchors,
@@ -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/index.js';
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
- const store = await JsonlSessionStore.open(description.homeDirectory);
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 reconfiguring = false;
65
+ let reconfiguration;
63
66
  const createAdapter = (modelId, configuredModels = models) => {
64
67
  const configuration = configuredModels.get(modelId);
65
68
  if (!configuration)
@@ -193,17 +196,29 @@ export async function createMarAgentWithAdapter(options) {
193
196
  assertSessionAdmission,
194
197
  assertCanStart: (sessionId) => {
195
198
  assertSessionAdmission(sessionId);
196
- if (reconfiguring)
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) => openSession((await store.createSession(input)).id, input.workspace),
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) => store.list(input),
205
- getSession: (id) => store.getSession(id),
206
- setSessionTitle: (id, title, input) => store.updateTitle(id, title, { ...input, automatic: input?.automatic ?? false }, sessionWriterOwner),
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}:`)))
@@ -243,7 +258,7 @@ export async function createMarAgentWithAdapter(options) {
243
258
  reconfigureModels: async (input) => {
244
259
  if (disposed)
245
260
  throw new MarAgentError('MAR_AGENT_DISPOSED', 'Agent is disposed.');
246
- if (reconfiguring)
261
+ if (reconfiguration)
247
262
  throw new MarAgentError('MAR_AGENT_EXECUTION_ACTIVE', 'Models are already being reconfigured for the next execution.');
248
263
  const next = resolveAgentModels(input.models, input.defaultModelId);
249
264
  const activeSessions = activeSessionIds();
@@ -255,7 +270,10 @@ export async function createMarAgentWithAdapter(options) {
255
270
  for (const adapter of runtime.adapters.values())
256
271
  activeAdapters.add(adapter);
257
272
  const inactiveRuntimes = [...sessionRuntimes].flatMap(([sessionId, runtime]) => activeSessions.has(sessionId) ? [] : [runtime]);
258
- reconfiguring = true;
273
+ const completion = Promise.withResolvers();
274
+ reconfiguration = completion.promise;
275
+ void completion.promise.catch(() => undefined);
276
+ let interruptedByDisposal = false;
259
277
  try {
260
278
  const reconfigurationCommits = new Map();
261
279
  for (const runtime of inactiveRuntimes)
@@ -277,8 +295,10 @@ export async function createMarAgentWithAdapter(options) {
277
295
  runtime.adapters.delete(modelId);
278
296
  }
279
297
  await closeModelAdapters(adapters);
280
- if (disposed)
298
+ if (disposed) {
299
+ interruptedByDisposal = true;
281
300
  throw new MarAgentError('MAR_AGENT_DISPOSED', 'Agent is disposed.');
301
+ }
282
302
  for (const commit of reconfigurationCommits.values())
283
303
  commit();
284
304
  models = next.models;
@@ -296,13 +316,20 @@ export async function createMarAgentWithAdapter(options) {
296
316
  for (const adapter of runtime.adapters.values())
297
317
  addModelCredentialProviders(liveProviders, adapter.configuration);
298
318
  const obsoleteProviders = [...credentialProviders].filter((provider) => !liveProviders.has(provider));
299
- const providerCloseResults = await Promise.allSettled(obsoleteProviders.map((provider) => provider.close()));
319
+ const providerCloseResults = await Promise.allSettled(obsoleteProviders.map(async (provider) => provider.close()));
300
320
  for (const [index, result] of providerCloseResults.entries())
301
321
  if (result.status === 'fulfilled')
302
322
  credentialProviders.delete(obsoleteProviders[index]);
303
323
  }
324
+ catch (error) {
325
+ if (!interruptedByDisposal)
326
+ completion.reject(error);
327
+ throw error;
328
+ }
304
329
  finally {
305
- reconfiguring = false;
330
+ completion.resolve();
331
+ if (reconfiguration === completion.promise)
332
+ reconfiguration = undefined;
306
333
  }
307
334
  },
308
335
  deleteSession: (id) => trackSessionLifecycle(id, 'delete', async () => {
@@ -342,6 +369,7 @@ export async function createMarAgentWithAdapter(options) {
342
369
  const extensionDisposal = extensions.dispose();
343
370
  void extensionDisposal.catch(() => undefined);
344
371
  const runtimes = [...sessionRuntimes.values()];
372
+ const pendingReconfiguration = reconfiguration;
345
373
  disposal = completeAgentCleanup([
346
374
  async () => {
347
375
  const results = await Promise.allSettled([...sessionLifecycles.values()].map(({ pending }) => pending));
@@ -353,10 +381,11 @@ export async function createMarAgentWithAdapter(options) {
353
381
  ...runtimes.map((runtime) => () => runtime.inputs?.retire()),
354
382
  ...runtimes.map((runtime) => () => runtime.subagents?.dispose()),
355
383
  () => Promise.allSettled([...executionResults.values()]),
384
+ () => pendingReconfiguration,
356
385
  () => closeModelAdapters(runtimes.flatMap((runtime) => [...runtime.adapters.values()])),
357
- ...[...credentialProviders].map((provider) => () => provider.close()),
386
+ () => completeAgentCleanup([...credentialProviders].map((provider) => () => provider.close())),
358
387
  () => options.host.dispose(),
359
- () => store.close()
388
+ () => (ownsStore ? store.close() : undefined)
360
389
  ]);
361
390
  return disposal;
362
391
  }
@@ -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: JsonlSessionStore;
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: string) => void;
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/index.js';
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 ?? '';
@@ -297,6 +299,7 @@ export function createSessionOpener(services) {
297
299
  const operation = emitTail.then(async () => {
298
300
  assertLive?.();
299
301
  const persistent = eventForPersistence(full);
302
+ let committedTerminal = false;
300
303
  if (persistent !== undefined && releaseSession !== undefined) {
301
304
  const stored = await store.append(sessionId, {
302
305
  type: full.type,
@@ -307,7 +310,7 @@ export function createSessionOpener(services) {
307
310
  if (full.type === 'execution.completed' ||
308
311
  full.type === 'execution.failed' ||
309
312
  full.type === 'execution.cancelled')
310
- persistedTerminal = true;
313
+ committedTerminal = persistedTerminal = true;
311
314
  if (full.type === 'message.completed') {
312
315
  const message = liveModelMessages.findLast((item) => item.role === 'assistant' && item.content === full.text);
313
316
  if (message)
@@ -316,8 +319,30 @@ export function createSessionOpener(services) {
316
319
  }
317
320
  queue.push(full);
318
321
  compactRequests.publish(full);
319
- if (internal.publishHostEvents !== false)
320
- await host.emit(full);
322
+ if (internal.publishHostEvents !== false) {
323
+ try {
324
+ await host.emit(full);
325
+ }
326
+ catch (error) {
327
+ if (!committedTerminal)
328
+ throw error;
329
+ // Host observation cannot rewrite a terminal already committed to the Store.
330
+ try {
331
+ // Host errors may contain private data; publish only SDK-owned facts.
332
+ process.emitWarning(new MarAgentError('MAR_AGENT_HOST_EVENT_PUBLICATION_FAILED', `Host publication of ${full.type} failed for Execution ${executionId}.`, {
333
+ details: {
334
+ sessionId,
335
+ executionId,
336
+ eventId: full.eventId,
337
+ eventType: full.type
338
+ }
339
+ }));
340
+ }
341
+ catch {
342
+ // A diagnostic sink must not change the committed outcome either.
343
+ }
344
+ }
345
+ }
321
346
  });
322
347
  emitTail = operation.catch(() => undefined);
323
348
  return operation;
@@ -1,3 +1,3 @@
1
- import type { JsonlSessionStore } from '../session/store/index.js';
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: JsonlSessionStore, workspace: string): SubagentSessionControllerBackend;
3
+ export declare function createSubagentBackend(store: SessionStore, workspace: string): SubagentSessionControllerBackend;
@@ -68,10 +68,12 @@ export interface MarAgent {
68
68
  readonly defaultModelId?: string;
69
69
  }): Promise<void>;
70
70
  deleteSession(sessionId: string): Promise<void>;
71
- /** Cancels active executions, then closes SDK-owned providers, the Host and the Session store. */
71
+ /** Joins executions/reconfiguration, closes owned resources, and releases borrowed Store leases. */
72
72
  dispose(): Promise<void>;
73
73
  }
74
74
  export interface CreateMarAgentOptions {
75
+ /** Ready-to-use borrowed Store. The caller closes it after all Agent/Catalog users finish. */
76
+ sessionStore?: import('../session/store/contracts.js').SessionStore;
75
77
  mode: 'normal' | 'node';
76
78
  host: MarAgentHost;
77
79
  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 declare function openMarAgentSessionCatalog(input: {
88
+ export type OpenMarAgentSessionCatalogInput = {
88
89
  homeDirectory: string;
89
- }): Promise<MarAgentSessionCatalog>;
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/index.js';
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 store = await JsonlSessionStore.open(input.homeDirectory);
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) => store.list(options),
10
- firstUserMessagePreview: (sessionId) => store.firstUserMessagePreview(sessionId),
11
- executionConfiguration: (sessionId) => store.executionConfiguration(sessionId),
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) => store.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) => store.rollbackSession(sessionId, options),
108
- clear: (sessionId) => store.clearSession(sessionId),
109
- delete: (sessionId) => store.delete(sessionId),
110
- close: () => store.close()
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) {
@@ -0,0 +1,140 @@
1
+ import type { CoreCheckpoint, CoreJsonValue } from '../../extensions/data.js';
2
+ import type { ModelMessage, ModelUsage } from '../../model/contracts.js';
3
+ import type { EnvironmentContextState } from '../../runtime/context/contracts.js';
4
+ import type { CodeModeStateEntry } from '../../tools/code-mode/state.js';
5
+ import type { AvailableToolResultResource } from '../../tools/result-extensions.js';
6
+ import type { MarAgentSessionPage, MarAgentSessionSummary } from '../catalog.js';
7
+ import type { ContextGcCheckpointDraft } from '../context-gc-checkpoint.js';
8
+ import type { ToolResultResourceInput, ToolResultResourcePage } from '../tool-result-resources.js';
9
+ import type { SessionListInput, SessionSource, SessionTitleUpdateInput } from '../types.js';
10
+ import type { CompactHistoryMessage, RestoredSessionInputImage, SessionExecutionState, SessionInputImage, SessionInputImageData, SessionInputImageMetadata, SessionRecord } from './types.js';
11
+ export type { CompactHistoryMessage, CompactUserInput, RestoredSessionInputImage, SessionExecutionState, SessionInputImage, SessionInputImageData, SessionInputImageMetadata, SessionRecord } from './types.js';
12
+ export type { CodeModeStateEntry } from '../../tools/code-mode/state.js';
13
+ export type { TodoSnapshot, TodoItem } from '../../tools/contracts.js';
14
+ export type { CodeToolCallRecord, CodeObservation } from '../../tools/code-mode/observations.js';
15
+ export type { ModelMessage, ModelUsage, ModelInputMetadata, ModelTextBlock, ModelContextualBlock } from '../../model/contracts.js';
16
+ export type { EnvironmentContextState } from '../../runtime/context/contracts.js';
17
+ export type { ContextGcCheckpointDraft, ContextGcBase, ContextGcPlatform, ContextGcEconomicsPolicy, ContextGcMetrics, ContextGcReplacement, ContextGcTarget, ContextGcReadItemReplacement } from '../context-gc-checkpoint.js';
18
+ export type { ContextGcWebToolName } from '../context-gc-replacements.js';
19
+ export type { ContextGcSubagentToolName } from '../context-gc-subagent.js';
20
+ export type { AvailableToolResultResource } from '../../tools/result-extensions.js';
21
+ /** Logical Session identity, without a physical index or recovery layout. */
22
+ export interface SessionStoreSession {
23
+ id: string;
24
+ title: string;
25
+ workspace: string;
26
+ createdAt: string;
27
+ lastActivityAt: string;
28
+ source?: SessionSource | undefined;
29
+ }
30
+ export interface SessionRecordInput {
31
+ type: string;
32
+ payload: unknown;
33
+ executionId?: string;
34
+ turnId?: string;
35
+ timestamp?: string;
36
+ }
37
+ export interface SessionStoreCompactInput {
38
+ summary: string;
39
+ replacementHistory?: readonly CompactHistoryMessage[];
40
+ retainedModelContext?: readonly ModelMessage[];
41
+ pendingInputs?: readonly SessionRecord[];
42
+ snapshotRecordId?: string;
43
+ snapshotMessageCount?: number;
44
+ environment?: EnvironmentContextState;
45
+ automatic?: boolean;
46
+ modelId?: string;
47
+ contextWindowTokens?: number;
48
+ usage?: ModelUsage;
49
+ executionId?: string;
50
+ turnId?: string;
51
+ }
52
+ /**
53
+ * Session persistence port. Implementations preserve record order, committed-resource
54
+ * visibility and the existing per-Session writer/checkpoint atomic boundaries.
55
+ * Owned handles are closed by their creator; injected instances are borrowed.
56
+ */
57
+ export interface SessionStore {
58
+ createSession(input: {
59
+ title?: string;
60
+ workspace: string;
61
+ source?: SessionSource;
62
+ }): Promise<SessionStoreSession>;
63
+ getSession(sessionId: string): Promise<MarAgentSessionSummary & {
64
+ automaticTitlePending: boolean;
65
+ }>;
66
+ list(input?: SessionListInput): Promise<MarAgentSessionPage>;
67
+ listSubagentChildren(parentSessionId: string): Promise<Array<MarAgentSessionSummary & {
68
+ source: Extract<SessionSource, {
69
+ type: 'subagent';
70
+ }>;
71
+ }>>;
72
+ executionConfiguration(sessionId: string): Promise<{
73
+ readonly modelId: string;
74
+ readonly modelName?: string;
75
+ readonly reasoningEffort?: string;
76
+ } | undefined>;
77
+ firstUserMessagePreview(sessionId: string): Promise<string | undefined>;
78
+ sessionTree(sessionId: string): Promise<readonly string[]>;
79
+ updateTitle(sessionId: string, title: string, input?: SessionTitleUpdateInput, owner?: object): Promise<boolean>;
80
+ append(sessionId: string, input: SessionRecordInput, options?: {
81
+ readonly signal?: AbortSignal;
82
+ }): Promise<SessionRecord>;
83
+ read(sessionId: string): Promise<SessionRecord[]>;
84
+ readPage(sessionId: string, input?: {
85
+ limit?: number;
86
+ beforeSequence?: number;
87
+ }): Promise<{
88
+ records: SessionRecord[];
89
+ previousBeforeSequence?: number;
90
+ }>;
91
+ readExecutionState(sessionId: string): Promise<SessionExecutionState>;
92
+ userTurnCount(sessionId: string): Promise<number>;
93
+ readContextualWorldState(sessionId: string): Promise<unknown | undefined>;
94
+ writeContextualWorldState(sessionId: string, state: unknown): Promise<void>;
95
+ readCodeModeState(sessionId: string): Promise<CodeModeStateEntry[]>;
96
+ commitCodeModeState(sessionId: string, mutations: unknown, input: {
97
+ readonly executionId: string;
98
+ readonly turnId: string;
99
+ readonly expectedState?: readonly CodeModeStateEntry[];
100
+ }): Promise<CodeModeStateEntry[]>;
101
+ readExtensionCheckpoint(sessionId: string, extensionId: string, key: string): Promise<CoreCheckpoint>;
102
+ writeExtensionCheckpoint(sessionId: string, extensionId: string, key: string, value: CoreJsonValue | undefined, expectedRevision: number | undefined, input: {
103
+ owner: object;
104
+ signal: AbortSignal;
105
+ executionId?: string;
106
+ turnId?: string;
107
+ }): Promise<CoreCheckpoint>;
108
+ compact(sessionId: string, input: SessionStoreCompactInput, options?: {
109
+ readonly signal?: AbortSignal;
110
+ }): Promise<SessionRecord>;
111
+ commitContextGc(sessionId: string, draft: ContextGcCheckpointDraft, planningRecords?: readonly SessionRecord[]): Promise<SessionRecord>;
112
+ persistInputImages(sessionId: string, images: readonly SessionInputImage[]): Promise<SessionInputImageMetadata[]>;
113
+ readInputImages(sessionId: string, value: unknown): Promise<RestoredSessionInputImage[]>;
114
+ readInputImage(sessionId: string, input: {
115
+ readonly sequence: number;
116
+ readonly imageIndex: number;
117
+ }): Promise<SessionInputImageData | undefined>;
118
+ writeToolResultResource(sessionId: string, text: string): Promise<AvailableToolResultResource>;
119
+ readToolResultResource(sessionId: string, input: ToolResultResourceInput): Promise<ToolResultResourcePage>;
120
+ /** One main Execution per Session; an owner may reuse its healthy retained writer. */
121
+ acquireSessionLease(sessionId: string, owner?: object): Promise<() => Promise<void>>;
122
+ /** Native writes join the same owner's writer, without admitting another Execution. */
123
+ acquireSessionWriteLease(sessionId: string, owner: object): Promise<() => Promise<void>>;
124
+ /** Retention requires the originating owner to hold an active Execution lease. */
125
+ retainSessionLease(sessionId: string, owner: object): Promise<() => Promise<void>>;
126
+ hasRetainedSessionLease(sessionId: string, owner: object): boolean;
127
+ forkSession(sessionId: string, input: {
128
+ readonly boundaryTurnId: string | null;
129
+ readonly title: string;
130
+ }): Promise<SessionStoreSession>;
131
+ rollbackSession(sessionId: string, input: {
132
+ readonly boundaryTurnId: string | null;
133
+ }): Promise<MarAgentSessionSummary>;
134
+ clearSession(sessionId: string): Promise<MarAgentSessionSummary>;
135
+ delete(sessionId: string): Promise<{
136
+ readonly deleted: boolean;
137
+ }>;
138
+ /** Stop using the handle and release its leases before closing it. Never preempts other owners. */
139
+ close(): Promise<void>;
140
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,20 +1,12 @@
1
+ import type { SessionStore, SessionRecordInput, SessionStoreCompactInput } from './contracts.js';
1
2
  import { type CoreCheckpoint, type CoreJsonValue } from '../../extensions/data.js';
2
- import type { ModelMessage, ModelUsage } from '../../model/contracts.js';
3
- import type { EnvironmentContextState } from '../../runtime/context/contracts.js';
4
3
  import { type CodeModeStateEntry } from '../../tools/code-mode/state.js';
5
4
  import { type ContextGcCheckpointDraft } from '../context-gc-checkpoint.js';
6
5
  import { type ToolResultResourceInput } from '../tool-result-resources.js';
7
6
  import type { SessionListInput, SessionSource, SessionTitleUpdateInput } from '../types.js';
8
- import type { CompactHistoryMessage, RestoredSessionInputImage, SessionExecutionState, SessionInputImage, SessionInputImageData, SessionInputImageMetadata, SessionMeta, SessionRecord } from './types.js';
9
- interface SessionRecordInput {
10
- type: string;
11
- payload: unknown;
12
- executionId?: string;
13
- turnId?: string;
14
- timestamp?: string;
15
- }
7
+ import type { RestoredSessionInputImage, SessionExecutionState, SessionInputImage, SessionInputImageData, SessionInputImageMetadata, SessionMeta, SessionRecord } from './types.js';
16
8
  /** SDK-owned JSONL history with per-HOME in-process sharing and cross-process file locks. */
17
- export declare class JsonlSessionStore {
9
+ export declare class JsonlSessionStore implements SessionStore {
18
10
  #private;
19
11
  private constructor();
20
12
  static open(home: string): Promise<JsonlSessionStore>;
@@ -110,21 +102,7 @@ export declare class JsonlSessionStore {
110
102
  records: SessionRecord[];
111
103
  previousBeforeSequence?: number;
112
104
  }>;
113
- compact(sessionId: string, input: {
114
- summary: string;
115
- replacementHistory?: readonly CompactHistoryMessage[];
116
- retainedModelContext?: readonly ModelMessage[];
117
- pendingInputs?: readonly SessionRecord[];
118
- snapshotRecordId?: string;
119
- snapshotMessageCount?: number;
120
- environment?: EnvironmentContextState;
121
- automatic?: boolean;
122
- modelId?: string;
123
- contextWindowTokens?: number;
124
- usage?: ModelUsage;
125
- executionId?: string;
126
- turnId?: string;
127
- }, options?: {
105
+ compact(sessionId: string, input: SessionStoreCompactInput, options?: {
128
106
  readonly signal?: AbortSignal;
129
107
  }): Promise<SessionRecord>;
130
108
  /** A warm cell retains physical writer ownership between Executions of the same Agent. */
@@ -183,4 +161,3 @@ export declare class JsonlSessionStore {
183
161
  }>;
184
162
  close(): Promise<void>;
185
163
  }
186
- export {};
package/dist/index.d.ts CHANGED
@@ -41,6 +41,8 @@ export type { CoreProcessesApi, CoreProcessesBackend, CoreProcessInput, CoreProc
41
41
  export type { CreateMarAgentOptions, CreateSessionInput, ExecutionHandle, CompactInput, SteerInput, SteerResult, MarAgent, MarAgentSession, SessionTitleUpdateInput } from './agent-core/sdk/types.js';
42
42
  export { openMarAgentSessionCatalog, type MarAgentContextUsage, type MarAgentHistoryEntry, type MarAgentHistoryPage, type MarAgentSessionCatalog, type MarAgentSessionDeleteResult, type MarAgentSessionImage, type MarAgentSessionPage, type MarAgentSessionSummary } from './agent-core/session/catalog.js';
43
43
  export type { SessionListInput, SessionSource } from './agent-core/session/types.js';
44
+ export type { SessionStore, SessionStoreSession, SessionRecordInput, SessionStoreCompactInput, SessionRecord, SessionExecutionState, CompactHistoryMessage, CompactUserInput, SessionInputImage, SessionInputImageMetadata, SessionInputImageData, RestoredSessionInputImage, CodeModeStateEntry, TodoSnapshot, TodoItem, CodeToolCallRecord, CodeObservation, ModelMessage, ModelUsage, ModelInputMetadata, ModelTextBlock, ModelContextualBlock, EnvironmentContextState, ContextGcCheckpointDraft, ContextGcBase, ContextGcPlatform, ContextGcEconomicsPolicy, ContextGcMetrics, ContextGcReplacement, ContextGcTarget, ContextGcReadItemReplacement, ContextGcWebToolName, ContextGcSubagentToolName, AvailableToolResultResource } from './agent-core/session/store/contracts.js';
45
+ export type { OpenMarAgentSessionCatalogInput } from './agent-core/session/catalog.js';
44
46
  export type { ApplyPatchFileResult, ApplyPatchResult, ApplyPatchPartialResult, ClientToolDefinition, MarAgentToolArtifact, MarAgentToolImageArtifact, McpCatalogTool, McpToolCallContext, McpToolCatalog, McpToolCatalogContext, ToolCall, ToolCaller, ToolExecutionContext, ToolExecutionResult } from './agent-core/tools/contracts.js';
45
47
  export { MCP_DEFINITION_LIMITS, assertMcpToolCatalog, assertMcpToolDefinition } from './agent-core/tools/mcp/catalog.js';
46
48
  export type { WorkspacePathMount } from './agent-core/tools/shared/path-resolver.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.11.12",
3
+ "version": "0.11.14",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",