@myagentroam/agent 0.10.60 → 0.10.61

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.
@@ -100,7 +100,7 @@ export async function createMarAgentWithAdapter(options) {
100
100
  return schedule(definition, run);
101
101
  },
102
102
  baseTools: (id, context) => {
103
- const execution = sessionRuntimes.get(id)?.toolSources;
103
+ const execution = sessionRuntimes.get(id)?.execution?.toolSources;
104
104
  if (context?.executionId && execution?.executionId === context.executionId)
105
105
  return execution.bindings;
106
106
  return (options.host.extensionPorts?.tools?.catalog(id, context?.executionId) ?? []).map((source) => ({
@@ -28,7 +28,11 @@ export function createExtensionAgentsBackend(input) {
28
28
  throw new MarAgentError(created.errorCode ?? 'MAR_AGENT_SUBAGENT_FAILED', created.errorMessage ?? 'Agent could not start.');
29
29
  }
30
30
  })),
31
- list: (call) => withController(call, async (controller) => controller.inspectAll()),
31
+ list: (call) => withController(call, async (controller) => {
32
+ await controller.prepareAll(call.signal);
33
+ call.signal.throwIfAborted();
34
+ return controller.inspectAll();
35
+ }),
32
36
  inspect: (target, call) => withController(call, (controller) => controller.inspect(target.agentId)),
33
37
  wait: (target, call) => withController(call, (controller) => {
34
38
  const selection = parseAgentWaitTargets(target);
@@ -14,9 +14,25 @@ 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';
17
- import type { CreateMarAgentOptions, ExecutionResult, MarAgentSession } from './types.js';
18
- export interface SessionRuntime {
17
+ import type { CreateMarAgentOptions, ExecutionMode, ExecutionResult, MarAgentSession } from './types.js';
18
+ interface SessionExecutionContext {
19
+ readonly executionId: string;
20
+ readonly modelId: string;
21
+ readonly mode: ExecutionMode;
22
+ readonly models: ReadonlyMap<string, ResolvedModelConfiguration>;
23
+ readonly instruction: string | undefined;
19
24
  steer?: (input: import('./types.js').SteerInput) => Promise<import('./types.js').SteerResult>;
25
+ compactRequests?: CompactRequests;
26
+ requestMessages?: {
27
+ read(): readonly ModelMessage[];
28
+ };
29
+ appendedMessages?: {
30
+ append(recordId: string, message: ModelMessage): void;
31
+ };
32
+ toolSources?: ExecutionToolSources;
33
+ }
34
+ export interface SessionRuntime {
35
+ execution?: SessionExecutionContext;
20
36
  todo?: TodoStore;
21
37
  readonly scheduleTool: ReturnType<typeof createSessionToolScheduler>;
22
38
  readonly sourceType: 'user' | 'subagent';
@@ -26,22 +42,12 @@ export interface SessionRuntime {
26
42
  subagents?: SubagentSessionController;
27
43
  subagentsOpening?: Promise<SubagentSessionController>;
28
44
  inputs?: SessionInputCoordinator;
29
- compactRequests?: CompactRequests;
30
45
  requestSnapshots?: ExtensionRequestSnapshots;
31
- requestMessages?: {
32
- readonly executionId: string;
33
- read(): readonly ModelMessage[];
34
- };
35
46
  recordProjection?: Promise<unknown>;
36
- appendedMessages?: {
37
- readonly executionId: string;
38
- append(recordId: string, message: ModelMessage): void;
39
- };
40
47
  sessionBackend?: CoreSessionBackend & {
41
48
  kick(): void;
42
49
  };
43
50
  agentsBackend?: CoreAgentsBackend;
44
- toolSources?: ExecutionToolSources;
45
51
  }
46
52
  interface InternalMarAgentSession extends MarAgentSession {
47
53
  startSubagentTurn(input: {
@@ -123,7 +123,6 @@ export function createSessionOpener(services) {
123
123
  text: sessionSource.type === 'subagent' ? childSubagentInstruction || null : null
124
124
  }
125
125
  ]);
126
- let promptDefaults;
127
126
  const sessionAdapter = (modelId, configuredModels) => {
128
127
  let selected = sessionRuntime.adapters.get(modelId);
129
128
  if (selected === undefined) {
@@ -187,7 +186,7 @@ export function createSessionOpener(services) {
187
186
  };
188
187
  recordSessionInputCommit(entry, result);
189
188
  if (message)
190
- sessionRuntime.appendedMessages?.append(record.recordId, message);
189
+ sessionRuntime.execution?.appendedMessages?.append(record.recordId, message);
191
190
  return result;
192
191
  });
193
192
  }
@@ -208,7 +207,6 @@ export function createSessionOpener(services) {
208
207
  const messageSources = new WeakMap();
209
208
  let liveModelMessages = [];
210
209
  const compactRequests = new CompactRequests(executionId, () => compactCoordinator.assertNotReentrant());
211
- sessionRuntime.compactRequests = compactRequests;
212
210
  const permissionPolicy = new ExecutionToolPermissions(mode === 'compact' ? 'full-access' : resolvePermissionMode(input.permissionMode), { sessionId, executionId }, host.requestToolApproval
213
211
  ? {
214
212
  request: (request, signal) => host.requestToolApproval(request, signal),
@@ -225,13 +223,15 @@ export function createSessionOpener(services) {
225
223
  ...currentLocalTimeContext()
226
224
  };
227
225
  const executionSystemInstruction = settings.systemInstruction;
228
- promptDefaults = {
226
+ const executionContext = {
229
227
  executionId,
230
228
  modelId: input.modelId ?? executionDefaultModelId,
231
229
  mode: mode === 'compact' ? 'run' : mode,
232
230
  models: executionModels,
233
- instruction: executionSystemInstruction
231
+ instruction: executionSystemInstruction,
232
+ compactRequests
234
233
  };
234
+ sessionRuntime.execution = executionContext;
235
235
  const manualCompactionId = mode === 'compact' ? randomUUID() : undefined;
236
236
  active.set(`${sessionId}:${executionId}`, controller);
237
237
  const inputs = sessionInputs();
@@ -369,8 +369,7 @@ export function createSessionOpener(services) {
369
369
  await inputs.idle();
370
370
  let immediateTarget;
371
371
  const pendingAppends = [];
372
- sessionRuntime.appendedMessages = {
373
- executionId,
372
+ executionContext.appendedMessages = {
374
373
  append(recordId, message) {
375
374
  pendingAppends.push({
376
375
  recordId,
@@ -755,7 +754,7 @@ export function createSessionOpener(services) {
755
754
  const coreExtensions = await services.extensions.prepare(sessionId, controller.signal, sourceBindings, sessionSource.type === 'user' &&
756
755
  (mode === 'run' || mode === 'plan') &&
757
756
  !internal.automaticInput);
758
- sessionRuntime.toolSources = sources;
757
+ executionContext.toolSources = sources;
759
758
  const operation = (run) => services.extensions.operations.run({
760
759
  sessionId,
761
760
  sessionEpoch: coreExtensions.epoch,
@@ -863,6 +862,7 @@ export function createSessionOpener(services) {
863
862
  executionTools = mcpRegistry.project(baseTools());
864
863
  };
865
864
  const loadRetainedSessionResources = async () => {
865
+ await subagents?.prepareSessionResources(controller.signal);
866
866
  const hostResources = (await host.listSessionResources?.(sessionId)) ?? {
867
867
  processes: []
868
868
  };
@@ -1128,8 +1128,7 @@ export function createSessionOpener(services) {
1128
1128
  sources.bind(captureRoundToolScope().toolScope);
1129
1129
  let preparingRequestMessages;
1130
1130
  let preparingRequestBaseLength = 0;
1131
- sessionRuntime.requestMessages = {
1132
- executionId,
1131
+ executionContext.requestMessages = {
1133
1132
  read: () => preparingRequestMessages !== undefined
1134
1133
  ? normalizeMessagesForModel([...preparingRequestMessages, ...messages.slice(preparingRequestBaseLength)], { supportsImages: selectedModel.inputCapabilities.includes('IMAGE') })
1135
1134
  : projectSessionRequestMessages(messages.map((message, index) => index === currentExecutionUserIndex && modelInputImages?.length
@@ -1192,7 +1191,7 @@ export function createSessionOpener(services) {
1192
1191
  return { executionId, status: 'completed', finalAnswer: '', inputHandled: true };
1193
1192
  }
1194
1193
  acceptsSteer = true;
1195
- sessionRuntime.steer = createNativeSteer({
1194
+ executionContext.steer = createNativeSteer({
1196
1195
  executionId,
1197
1196
  inputs,
1198
1197
  signal: controller.signal,
@@ -1885,12 +1884,12 @@ export function createSessionOpener(services) {
1885
1884
  finalAnswer = executionLoop?.finalAnswer ?? finalAnswer;
1886
1885
  acceptsMailbox = false;
1887
1886
  acceptsSteer = false;
1888
- delete sessionRuntime.steer;
1887
+ delete executionContext.steer;
1889
1888
  await sessionRuntime.recordProjection?.catch(() => undefined);
1890
1889
  await compactCoordinator.close(error);
1891
1890
  compactRequests.close(new MarAgentError('MAR_AGENT_CANCELLED', 'Execution ended.'));
1892
- if (sessionRuntime.compactRequests === compactRequests)
1893
- delete sessionRuntime.compactRequests;
1891
+ if (executionContext.compactRequests === compactRequests)
1892
+ delete executionContext.compactRequests;
1894
1893
  if (controller.signal.aborted) {
1895
1894
  subagents?.endParentExecution(executionId);
1896
1895
  await emit({ type: 'execution.cancelled' });
@@ -1912,19 +1911,16 @@ export function createSessionOpener(services) {
1912
1911
  };
1913
1912
  }
1914
1913
  finally {
1915
- if (sessionRuntime.requestMessages?.executionId === executionId)
1916
- delete sessionRuntime.requestMessages;
1914
+ delete executionContext.requestMessages;
1917
1915
  compactRequests.close(new MarAgentError('MAR_AGENT_CANCELLED', 'Execution ended.'));
1918
- if (sessionRuntime.compactRequests === compactRequests)
1919
- delete sessionRuntime.compactRequests;
1920
- if (sessionRuntime.appendedMessages?.executionId === executionId)
1921
- delete sessionRuntime.appendedMessages;
1922
- if (promptDefaults?.executionId === executionId)
1923
- promptDefaults = undefined;
1916
+ if (executionContext.compactRequests === compactRequests)
1917
+ delete executionContext.compactRequests;
1918
+ delete executionContext.appendedMessages;
1919
+ delete executionContext.steer;
1924
1920
  acceptsMailbox = false;
1925
1921
  executionToolSources?.close();
1926
- if (sessionRuntime.toolSources === executionToolSources)
1927
- delete sessionRuntime.toolSources;
1922
+ if (executionContext.toolSources === executionToolSources)
1923
+ delete executionContext.toolSources;
1928
1924
  internal.signal?.removeEventListener('abort', abortSource);
1929
1925
  await compactCoordinator.close(controller.signal.reason ?? new MarAgentError('MAR_AGENT_CANCELLED', 'Execution ended.'));
1930
1926
  await selectedTurn?.close().catch(() => undefined);
@@ -1940,6 +1936,8 @@ export function createSessionOpener(services) {
1940
1936
  }
1941
1937
  subagents?.endParentExecution(executionId);
1942
1938
  await releaseSession?.();
1939
+ if (sessionRuntime.execution === executionContext)
1940
+ delete sessionRuntime.execution;
1943
1941
  active.delete(`${sessionId}:${executionId}`);
1944
1942
  sessionRuntime.sessionBackend?.kick();
1945
1943
  queue.close();
@@ -1974,20 +1972,15 @@ export function createSessionOpener(services) {
1974
1972
  sessionRuntime.sessionBackend ??= createExtensionSessionBackend({
1975
1973
  describe: async (call) => {
1976
1974
  call.signal.throwIfAborted();
1975
+ const defaults = sessionRuntime.execution;
1976
+ const state = defaults ?? services.modelState();
1977
+ const modelId = defaults?.modelId ?? services.modelState().defaultModelId;
1977
1978
  const current = await store.getSession(sessionId);
1978
- const records = await store.read(sessionId);
1979
+ const userTurns = await store.userTurnCount(sessionId);
1979
1980
  call.signal.throwIfAborted();
1980
- const state = promptDefaults ?? services.modelState();
1981
- const modelId = promptDefaults?.modelId ?? services.modelState().defaultModelId;
1982
1981
  const model = state.models.get(modelId);
1983
1982
  if (!model)
1984
1983
  throw new MarAgentError('MAR_AGENT_MODEL_DISABLED', 'Selected model is unavailable.');
1985
- const userTurns = records.filter((record) => {
1986
- if (record.type !== 'turn.user')
1987
- return false;
1988
- const payload = record.payload;
1989
- return payload.inputSource === undefined;
1990
- }).length;
1991
1984
  return {
1992
1985
  sessionId,
1993
1986
  ...(logicalWorkspace ? { cwd: logicalWorkspace, root: logicalWorkspace } : {}),
@@ -2000,9 +1993,10 @@ export function createSessionOpener(services) {
2000
1993
  },
2001
1994
  composePrompt: async (facts, call) => {
2002
1995
  call.signal.throwIfAborted();
2003
- const defaults = promptDefaults;
1996
+ const defaults = sessionRuntime.execution;
2004
1997
  const state = defaults ?? services.modelState();
2005
1998
  const modelId = facts.modelId ?? defaults?.modelId ?? services.modelState().defaultModelId;
1999
+ const instruction = defaults ? defaults.instruction : settings.systemInstruction;
2006
2000
  const model = state.models.get(modelId);
2007
2001
  if (!model)
2008
2002
  throw new MarAgentError('MAR_AGENT_MODEL_DISABLED', 'Selected model is unavailable.');
@@ -2047,7 +2041,7 @@ export function createSessionOpener(services) {
2047
2041
  });
2048
2042
  call.signal.throwIfAborted();
2049
2043
  return {
2050
- sections: buildSessionPromptSections(tools, mode, model, defaults?.instruction ?? settings.systemInstruction, instructions?.skillCatalog),
2044
+ sections: buildSessionPromptSections(tools, mode, model, instruction, instructions?.skillCatalog),
2051
2045
  facts: { modelId, mode, tools: tools.map((tool) => tool.name) }
2052
2046
  };
2053
2047
  },
@@ -2075,8 +2069,9 @@ export function createSessionOpener(services) {
2075
2069
  }
2076
2070
  call.signal.throwIfAborted();
2077
2071
  const targetRuntime = sessionRuntimes.get(target);
2078
- if (selection.view === 'request' && targetRuntime?.requestMessages)
2079
- return sessionMessagesPage(targetRuntime.requestMessages.read(), selection);
2072
+ const requestMessages = targetRuntime?.execution?.requestMessages;
2073
+ if (selection.view === 'request' && requestMessages)
2074
+ return sessionMessagesPage(requestMessages.read(), selection);
2080
2075
  const modelState = services.modelState();
2081
2076
  const requestModel = selection.view === 'request'
2082
2077
  ? modelState.models.get(targetModelId ?? modelState.defaultModelId)
@@ -2215,8 +2210,8 @@ export function createSessionOpener(services) {
2215
2210
  id: sessionId,
2216
2211
  run: (input) => execution('run', input),
2217
2212
  plan: (input) => execution('plan', input),
2218
- steer: (input) => sessionRuntime.steer?.(input) ?? Promise.resolve({ status: 'notAccepted' }),
2219
- compact: (input = {}) => sessionRuntime.compactRequests?.request(input) ??
2213
+ steer: (input) => sessionRuntime.execution?.steer?.(input) ?? Promise.resolve({ status: 'notAccepted' }),
2214
+ compact: (input = {}) => sessionRuntime.execution?.compactRequests?.request(input) ??
2220
2215
  execution('compact', {
2221
2216
  prompt: input.prompt ?? DEFAULT_COMPACTION_FOCUS,
2222
2217
  ...input
@@ -14,33 +14,36 @@ export function createSubagentBackend(store, workspace) {
14
14
  },
15
15
  listChildren: async (parentSessionId) => {
16
16
  const sessions = await store.listSubagentChildren(parentSessionId);
17
- return Promise.all(sessions.map(async (session) => ({
17
+ return sessions.map((session) => ({
18
18
  id: session.id,
19
19
  createdAt: session.createdAt,
20
20
  lastActivityAt: session.lastActivityAt,
21
- source: session.source,
22
- records: await store.read(session.id)
23
- })));
21
+ source: session.source
22
+ }));
24
23
  },
25
24
  loadChild: async (parentSessionId, childSessionId) => {
26
- let session;
27
25
  try {
28
- session = await store.getSession(childSessionId);
26
+ const session = await store.getSession(childSessionId);
27
+ if (session.source.type !== 'subagent' ||
28
+ session.source.parentSessionId !== parentSessionId)
29
+ return undefined;
30
+ return {
31
+ id: session.id,
32
+ createdAt: session.createdAt,
33
+ lastActivityAt: session.lastActivityAt,
34
+ source: session.source,
35
+ records: await store.read(session.id)
36
+ };
29
37
  }
30
38
  catch (error) {
31
- if (error instanceof MarAgentError && error.code === 'MAR_AGENT_SESSION_NOT_FOUND')
32
- return undefined;
39
+ if (error instanceof MarAgentError && error.code === 'MAR_AGENT_SESSION_NOT_FOUND') {
40
+ // A history read failure is not proof that the child was deleted.
41
+ const children = await store.listSubagentChildren(parentSessionId);
42
+ if (!children.some((child) => child.id === childSessionId))
43
+ return undefined;
44
+ }
33
45
  throw error;
34
46
  }
35
- if (session.source.type !== 'subagent' || session.source.parentSessionId !== parentSessionId)
36
- return undefined;
37
- return {
38
- id: session.id,
39
- createdAt: session.createdAt,
40
- lastActivityAt: session.lastActivityAt,
41
- source: session.source,
42
- records: await store.read(session.id)
43
- };
44
47
  }
45
48
  };
46
49
  }
@@ -1,7 +1,7 @@
1
1
  import type { SessionListInput, SessionSource } from '../types.js';
2
2
  import type { SessionIndex, SessionMeta } from './types.js';
3
- /** Merge a derived cache only onto the unchanged history it was computed from. */
4
- export declare function mergeFirstUserMessagePreviewCache(current: SessionMeta, cached: SessionMeta): SessionMeta;
3
+ /** Merge only derived fields, and only onto the history they were computed from. */
4
+ export declare function mergeSessionDerivedCache(current: SessionMeta, cached: SessionMeta): SessionMeta;
5
5
  export declare function readSessionIndex(path: string): Promise<SessionIndex | undefined>;
6
6
  export declare function persistSessionIndex(path: string, index: SessionIndex): Promise<void>;
7
7
  export declare function normalizeSessionSource(value: SessionSource | undefined): SessionSource;
@@ -2,21 +2,25 @@ import { randomUUID } from 'node:crypto';
2
2
  import { readFile, rename, rm, writeFile } from 'node:fs/promises';
3
3
  import { isDeepStrictEqual } from 'node:util';
4
4
  import { MarAgentError } from '../../error.js';
5
- /** Merge a derived cache only onto the unchanged history it was computed from. */
6
- export function mergeFirstUserMessagePreviewCache(current, cached) {
7
- if (cached.resume?.firstUserMessageIndexed !== true ||
8
- current.nextSequence !== cached.nextSequence ||
9
- current.storageTransactionId !== cached.storageTransactionId ||
10
- current.resume?.firstUserMessagePreview !== undefined ||
11
- (current.resume?.firstUserMessageIndexed === true &&
12
- cached.resume.firstUserMessagePreview === undefined))
5
+ /** Merge only derived fields, and only onto the history they were computed from. */
6
+ export function mergeSessionDerivedCache(current, cached) {
7
+ if (current.nextSequence !== cached.nextSequence ||
8
+ current.storageTransactionId !== cached.storageTransactionId)
9
+ return current;
10
+ const preview = cached.resume?.firstUserMessageIndexed === true &&
11
+ current.resume?.firstUserMessagePreview === undefined &&
12
+ !(current.resume?.firstUserMessageIndexed === true &&
13
+ cached.resume.firstUserMessagePreview === undefined);
14
+ const count = current.resume?.userTurns === undefined && cached.resume?.userTurns !== undefined;
15
+ if (!preview && !count)
13
16
  return current;
14
17
  return {
15
18
  ...current,
16
19
  resume: {
17
20
  ...(current.resume ?? { version: 1, todoRevision: 0 }),
18
- firstUserMessageIndexed: true,
19
- ...(cached.resume?.firstUserMessagePreview === undefined
21
+ ...(count ? { userTurns: cached.resume.userTurns } : {}),
22
+ ...(preview ? { firstUserMessageIndexed: true } : {}),
23
+ ...(!preview || cached.resume?.firstUserMessagePreview === undefined
20
24
  ? {}
21
25
  : { firstUserMessagePreview: cached.resume.firstUserMessagePreview })
22
26
  }
@@ -45,7 +49,9 @@ export async function readSessionIndex(path) {
45
49
  typeof session.createdAt !== 'string' ||
46
50
  typeof session.lastActivityAt !== 'string' ||
47
51
  !Number.isSafeInteger(session.nextSequence) ||
48
- session.nextSequence < 1))
52
+ session.nextSequence < 1 ||
53
+ (session.resume?.userTurns !== undefined &&
54
+ (!Number.isSafeInteger(session.resume.userTurns) || session.resume.userTurns < 0))))
49
55
  throw new Error('invalid index shape');
50
56
  return value;
51
57
  }
@@ -3,6 +3,7 @@ import type { CompactHistoryMessage, SessionExecutionState, SessionMeta, Session
3
3
  export declare function deriveExecutionState(records: readonly SessionRecord[]): SessionExecutionState & {
4
4
  resume: NonNullable<SessionMeta['resume']>;
5
5
  };
6
+ export declare function isNativeUserTurn(record: SessionRecord): boolean;
6
7
  export declare function userMessagePreviewFromRecord(record: SessionRecord): string | undefined;
7
8
  export declare function executionModelFromRecord(record: SessionRecord): {
8
9
  modelId: string;
@@ -9,7 +9,10 @@ export function deriveExecutionState(records) {
9
9
  let todoItems = [];
10
10
  let executionModel;
11
11
  let firstUserMessagePreview;
12
+ let userTurns = 0;
12
13
  for (const record of records) {
14
+ if (isNativeUserTurn(record))
15
+ userTurns++;
13
16
  firstUserMessagePreview ??= userMessagePreviewFromRecord(record);
14
17
  if (record.type === 'session.created')
15
18
  automaticTitle =
@@ -40,6 +43,7 @@ export function deriveExecutionState(records) {
40
43
  contextRecords: boundary < 0 ? [...records] : records.slice(boundary),
41
44
  resume: {
42
45
  version: 1,
46
+ userTurns,
43
47
  ...(compactSequence === undefined ? {} : { compactSequence }),
44
48
  ...(checkpoint === undefined
45
49
  ? {}
@@ -57,6 +61,10 @@ export function deriveExecutionState(records) {
57
61
  }
58
62
  };
59
63
  }
64
+ export function isNativeUserTurn(record) {
65
+ return (record.type === 'turn.user' &&
66
+ record.payload.inputSource === undefined);
67
+ }
60
68
  export function userMessagePreviewFromRecord(record) {
61
69
  if (record.type !== 'turn.user' ||
62
70
  !isObject(record.payload) ||
@@ -160,6 +168,7 @@ export function isCompactCheckpoint(record) {
160
168
  }
161
169
  export function sameResumeIndex(left, right) {
162
170
  return (left?.version === right.version &&
171
+ left.userTurns === right.userTurns &&
163
172
  left.compactSequence === right.compactSequence &&
164
173
  left.gcSequence === right.gcSequence &&
165
174
  left.gcGeneration === right.gcGeneration &&
@@ -24,7 +24,6 @@ export declare class JsonlSessionStore {
24
24
  workspace: string;
25
25
  source?: SessionSource;
26
26
  }): Promise<SessionMeta>;
27
- sessionDirectory(sessionId: string): string;
28
27
  readContextualWorldState(sessionId: string): Promise<unknown | undefined>;
29
28
  writeContextualWorldState(sessionId: string, state: unknown): Promise<void>;
30
29
  /** Mark each image pending before publication; turn.user or lease recovery resolves ownership. */
@@ -102,7 +101,6 @@ export declare class JsonlSessionStore {
102
101
  readonly expectedState?: readonly CodeModeStateEntry[];
103
102
  }): Promise<CodeModeStateEntry[]>;
104
103
  readExecutionState(sessionId: string): Promise<SessionExecutionState>;
105
- readContext(sessionId: string): Promise<SessionRecord[]>;
106
104
  /** Compare the planned sequence inside the existing record writer queue. */
107
105
  commitContextGc(sessionId: string, draft: ContextGcCheckpointDraft, planningRecords?: readonly SessionRecord[]): Promise<SessionRecord>;
108
106
  readPage(sessionId: string, input?: {
@@ -177,6 +175,8 @@ export declare class JsonlSessionStore {
177
175
  readonly reasoningEffort?: string;
178
176
  } | undefined>;
179
177
  sessionTree(sessionId: string): Promise<readonly string[]>;
178
+ /** Counts native input records, not the post-Compact model context. */
179
+ userTurnCount(sessionId: string): Promise<number>;
180
180
  firstUserMessagePreview(sessionId: string): Promise<string | undefined>;
181
181
  delete(sessionId: string): Promise<{
182
182
  readonly deleted: boolean;