@myagentroam/node 0.9.3 → 0.9.4

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.
@@ -51,6 +51,18 @@ export interface CodexRunConfiguration {
51
51
  readonly collaborationMode?: 'default' | 'plan';
52
52
  readonly mcpServers?: unknown;
53
53
  }
54
+ interface CodexRpcErrorPayload {
55
+ readonly code?: unknown;
56
+ readonly message?: unknown;
57
+ readonly data?: unknown;
58
+ }
59
+ export declare class CodexAppServerRpcError extends Error {
60
+ readonly code: unknown;
61
+ readonly rpcMessage: string;
62
+ readonly data: unknown;
63
+ constructor(payload: CodexRpcErrorPayload);
64
+ }
65
+ export declare function isCodexRolloutMissingError(error: unknown): boolean;
54
66
  /** Public App Server turn inputs supported by the Workbench Composer. */
55
67
  export type CodexComposerInput = {
56
68
  readonly type: 'text';
@@ -71,15 +83,26 @@ export declare class CodexAppServerClient {
71
83
  private socketPath;
72
84
  private nextId;
73
85
  private readonly pending;
86
+ private readonly pendingDrainWaiters;
74
87
  private readonly notifications;
75
88
  private environment;
89
+ private starting;
90
+ private restarting;
91
+ private lifecycleRevision;
76
92
  constructor(options?: CodexAppServerOptions);
77
93
  configureEnvironment(environment: Readonly<Record<string, string>>): void;
78
94
  clearEnvironment(): void;
79
95
  start(): Promise<void>;
96
+ restart(): Promise<void>;
97
+ private startManaged;
98
+ private restartManaged;
80
99
  stop(): void;
100
+ private stopManaged;
81
101
  onNotification(listener: (notification: JsonRpcNotification) => void): () => void;
82
102
  request(method: string, params: unknown): Promise<unknown>;
103
+ private requestDirect;
104
+ private waitForPendingRequests;
105
+ private resolvePendingDrain;
83
106
  notify(method: string, params: unknown): void;
84
107
  respond(requestId: string | number, result: unknown): void;
85
108
  startThread(cwd: string, configuration?: CodexRunConfiguration): Promise<unknown>;
@@ -106,3 +129,4 @@ export declare class CodexAppServerClient {
106
129
  export declare function probeCodex(command?: string): CodexProbe;
107
130
  export declare function probeCodexAsync(command?: string): Promise<CodexProbe>;
108
131
  export declare function isSupportedCodexVersion(version: string): boolean;
132
+ export {};
@@ -36,6 +36,25 @@ export function codexSessionControl(input) {
36
36
  capabilities: ['history.read', 'turn.start']
37
37
  };
38
38
  }
39
+ export class CodexAppServerRpcError extends Error {
40
+ code;
41
+ rpcMessage;
42
+ data;
43
+ constructor(payload) {
44
+ const rpcMessage = typeof payload.message === 'string' ? payload.message : 'Codex App Server request failed';
45
+ super(`CODEX_APP_SERVER_RPC_ERROR:${JSON.stringify(payload)}`);
46
+ this.name = 'CodexAppServerRpcError';
47
+ this.code = payload.code;
48
+ this.rpcMessage = rpcMessage;
49
+ this.data = payload.data;
50
+ }
51
+ }
52
+ export function isCodexRolloutMissingError(error) {
53
+ return (error instanceof CodexAppServerRpcError &&
54
+ error.code === -32600 &&
55
+ (/^no rollout found for thread id\b/i.test(error.rpcMessage) ||
56
+ /^thread not loaded:\s*/i.test(error.rpcMessage)));
57
+ }
39
58
  /**
40
59
  * Local JSON-RPC client for a Node-supervised Codex App Server. Linux uses a
41
60
  * private Unix socket by default; Windows uses stdio. Neither is exposed to
@@ -48,8 +67,12 @@ export class CodexAppServerClient {
48
67
  socketPath;
49
68
  nextId = 1;
50
69
  pending = new Map();
70
+ pendingDrainWaiters = new Set();
51
71
  notifications = new Set();
52
72
  environment = {};
73
+ starting;
74
+ restarting;
75
+ lifecycleRevision = 0;
53
76
  constructor(options = {}) {
54
77
  this.options = options;
55
78
  }
@@ -63,9 +86,35 @@ export class CodexAppServerClient {
63
86
  throw new Error('CODEX_APP_SERVER_ALREADY_STARTED');
64
87
  this.environment = {};
65
88
  }
66
- async start() {
89
+ start() {
90
+ if (this.restarting !== undefined)
91
+ return this.restarting;
92
+ if (this.starting !== undefined)
93
+ return this.starting;
67
94
  if (this.child !== undefined)
68
- return;
95
+ return Promise.resolve();
96
+ const starting = this.startManaged();
97
+ this.starting = starting;
98
+ const clearStarting = () => {
99
+ if (this.starting === starting)
100
+ this.starting = undefined;
101
+ };
102
+ void starting.then(clearStarting, clearStarting);
103
+ return starting;
104
+ }
105
+ restart() {
106
+ if (this.restarting !== undefined)
107
+ return this.restarting;
108
+ const restarting = this.restartManaged(this.lifecycleRevision);
109
+ this.restarting = restarting;
110
+ const clearRestarting = () => {
111
+ if (this.restarting === restarting)
112
+ this.restarting = undefined;
113
+ };
114
+ void restarting.then(clearRestarting, clearRestarting);
115
+ return restarting;
116
+ }
117
+ async startManaged() {
69
118
  const command = this.options.command ?? 'codex';
70
119
  const mode = this.transportMode();
71
120
  this.socketPath =
@@ -105,18 +154,39 @@ export class CodexAppServerClient {
105
154
  this.transport = socket ?? stdioTransport(child);
106
155
  const lines = createInterface({ input: socket ?? child.stdout });
107
156
  lines.on('line', (line) => this.handleLine(line));
108
- child.once('error', (error) => this.failAll(new Error(`CODEX_APP_SERVER_START_FAILED:${error.message}`)));
157
+ const managedChild = child;
158
+ child.once('error', (error) => {
159
+ if (this.child !== managedChild)
160
+ return;
161
+ this.failAll(new Error(`CODEX_APP_SERVER_START_FAILED:${error.message}`));
162
+ });
109
163
  child.once('exit', () => {
164
+ if (this.child !== managedChild)
165
+ return;
110
166
  this.child = undefined;
111
167
  this.failAll(new Error('CODEX_APP_SERVER_EXITED'));
112
168
  });
113
- await this.request('initialize', {
169
+ await this.requestDirect('initialize', {
114
170
  clientInfo: { name: 'codex_vscode', title: 'MyAgentRoam', version: '0.1.4' },
115
171
  capabilities: { experimentalApi: true }
116
172
  });
117
173
  this.notify('initialized', {});
118
174
  }
175
+ async restartManaged(lifecycleRevision) {
176
+ await Promise.resolve();
177
+ if (this.starting !== undefined)
178
+ await this.starting;
179
+ await this.waitForPendingRequests();
180
+ if (this.lifecycleRevision !== lifecycleRevision)
181
+ throw new Error('CODEX_APP_SERVER_STOPPED');
182
+ this.stopManaged();
183
+ await this.startManaged();
184
+ }
119
185
  stop() {
186
+ this.lifecycleRevision += 1;
187
+ this.stopManaged();
188
+ }
189
+ stopManaged() {
120
190
  this.transport?.destroy();
121
191
  this.transport = undefined;
122
192
  this.child?.kill();
@@ -131,6 +201,13 @@ export class CodexAppServerClient {
131
201
  return () => this.notifications.delete(listener);
132
202
  }
133
203
  async request(method, params) {
204
+ if (this.restarting !== undefined)
205
+ await this.restarting;
206
+ else if (this.starting !== undefined)
207
+ await this.starting;
208
+ return this.requestDirect(method, params);
209
+ }
210
+ requestDirect(method, params) {
134
211
  const transport = this.transport;
135
212
  if (transport === undefined || !transport.writable)
136
213
  throw new Error('CODEX_APP_SERVER_UNAVAILABLE');
@@ -139,6 +216,7 @@ export class CodexAppServerClient {
139
216
  const result = new Promise((resolve, reject) => {
140
217
  const timer = setTimeout(() => {
141
218
  this.pending.delete(id);
219
+ this.resolvePendingDrain();
142
220
  reject(new Error('CODEX_APP_SERVER_TIMEOUT'));
143
221
  }, timeoutMs);
144
222
  this.pending.set(id, { resolve, reject, timer });
@@ -146,6 +224,18 @@ export class CodexAppServerClient {
146
224
  transport.write(`${JSON.stringify({ method, id, params })}\n`);
147
225
  return result;
148
226
  }
227
+ waitForPendingRequests() {
228
+ if (this.pending.size === 0)
229
+ return Promise.resolve();
230
+ return new Promise((resolve) => this.pendingDrainWaiters.add(resolve));
231
+ }
232
+ resolvePendingDrain() {
233
+ if (this.pending.size !== 0)
234
+ return;
235
+ for (const resolve of this.pendingDrainWaiters)
236
+ resolve();
237
+ this.pendingDrainWaiters.clear();
238
+ }
149
239
  notify(method, params) {
150
240
  const transport = this.transport;
151
241
  if (transport === undefined || !transport.writable)
@@ -233,8 +323,9 @@ export class CodexAppServerClient {
233
323
  return;
234
324
  clearTimeout(pending.timer);
235
325
  this.pending.delete(message.id);
326
+ this.resolvePendingDrain();
236
327
  if (message.error !== undefined) {
237
- pending.reject(new Error(`CODEX_APP_SERVER_RPC_ERROR:${JSON.stringify(message.error)}`));
328
+ pending.reject(new CodexAppServerRpcError(isRecord(message.error) ? message.error : { message: String(message.error) }));
238
329
  }
239
330
  else {
240
331
  pending.resolve(message.result);
@@ -252,6 +343,7 @@ export class CodexAppServerClient {
252
343
  pending.reject(error);
253
344
  this.pending.delete(id);
254
345
  }
346
+ this.resolvePendingDrain();
255
347
  }
256
348
  transportMode() {
257
349
  const requested = this.options.transport ?? 'auto';
@@ -371,6 +463,9 @@ function defaultSpawn(command, args, options) {
371
463
  ...(options.env === undefined ? {} : { env: options.env })
372
464
  });
373
465
  }
466
+ function isRecord(value) {
467
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
468
+ }
374
469
  function stdioTransport(child) {
375
470
  return {
376
471
  get writable() {
package/dist/connector.js CHANGED
@@ -43,7 +43,7 @@ import { SessionQueryService } from './service/session-query-service.js';
43
43
  import { WorkspaceQueueWorkbenchService } from './service/workspace-queue-workbench-service.js';
44
44
  import { SessionIdentityService } from './service/session-identity-service.js';
45
45
  import { NativeSessionProjectionService } from './service/native-session-projection-service.js';
46
- import { ConversationHistoryService, hasManagedActiveRun } from './service/conversation-history-service.js';
46
+ import { ConversationHistoryService, convergeConversationWatchPage, hasManagedActiveRun } from './service/conversation-history-service.js';
47
47
  import { ConversationSegmentService, conversationSegmentIdentityForItem, conversationSegments } from './service/conversation-segment-service.js';
48
48
  import { RunnerInteractionService } from './service/runner-interaction-service.js';
49
49
  import { SessionLifecycleService } from './service/session-lifecycle-service.js';
@@ -197,9 +197,13 @@ export class NodeConnector {
197
197
  refreshActivity: (session) => this.conversationHistoryService.refreshExternalActivity(session),
198
198
  present: (session) => this.sessionPresentationService.present(session),
199
199
  readPage: (session, limit) => this.conversationHistoryService.read(session, { limit }),
200
+ convergePage: convergeConversationWatchPage,
200
201
  projectInitialPage: (session, page, _unit, limit) => this.conversationSegmentService.projectInitial(session, page, limit),
201
202
  emitSession: (session) => this.emitWorkbenchEvent('session', { session }),
202
- emitTurn: (turn) => this.emitConversationTurn(turn)
203
+ emitPage: (session, page) => this.emitWorkbenchEvent('conversation', {
204
+ sessionId: session.id,
205
+ snapshot: this.conversationSegmentService.projectInitial(session, page, 10)
206
+ })
203
207
  });
204
208
  constructor(options = {}) {
205
209
  this.config = options.config;
@@ -67,6 +67,8 @@ export interface NodeAgentRun {
67
67
  readonly recoveryState: RunRecoveryState;
68
68
  readonly version: number;
69
69
  readonly clientMessageId: string;
70
+ /** Server-authenticated user that submitted this Run. Internal lifecycle metadata only. */
71
+ readonly initiatedByUserId?: number;
70
72
  readonly createdAt: number;
71
73
  readonly updatedAt: number;
72
74
  }
@@ -6,6 +6,15 @@ import { CodexRunner } from '../codex-runner.js';
6
6
  type CodexImageInput = Extract<CodexComposerInput, {
7
7
  readonly type: 'localImage';
8
8
  }>;
9
+ interface CodexNotificationRun {
10
+ readonly threadId: string;
11
+ readonly turnId?: string;
12
+ }
13
+ export declare function resolveCodexNotificationRun<T extends CodexNotificationRun>(runs: ReadonlyMap<string, T>, input: {
14
+ readonly threadId?: string;
15
+ readonly turnId?: string;
16
+ readonly allowUnboundFallback?: boolean;
17
+ }): readonly [string, T] | undefined;
9
18
  export interface CodexManagedRunHost<TAttachment> {
10
19
  readonly available: () => boolean;
11
20
  readonly intercepted: () => boolean;
@@ -3,6 +3,25 @@ import { parseSecretEnvironment } from '../../util/secret-environment.js';
3
3
  import { safeErrorCode } from '../../util/safe-error.js';
4
4
  import { runnerErrorProjection } from '../../util/runner-error.js';
5
5
  import { boundedConversationItemId, codexImageAttachments, codexLiveConversationItem, codexUserInputQuestions, compactRunnerText, isPlainRecord } from './conversation-parser.js';
6
+ export function resolveCodexNotificationRun(runs, input) {
7
+ const entries = [...runs.entries()];
8
+ if (input.turnId !== undefined) {
9
+ const exact = entries.find(([, value]) => value.turnId === input.turnId &&
10
+ (input.threadId === undefined || value.threadId === input.threadId));
11
+ if (exact !== undefined)
12
+ return exact;
13
+ if (input.allowUnboundFallback !== true)
14
+ return undefined;
15
+ // `turn/started` can arrive before the `turn/start` response binds its native Turn ID. Only
16
+ // an unbound Run on the same thread is a valid fallback; an older bound Run is never valid.
17
+ return entries
18
+ .reverse()
19
+ .find(([, value]) => value.threadId === input.threadId && value.turnId === undefined);
20
+ }
21
+ if (input.threadId === undefined)
22
+ return undefined;
23
+ return entries.reverse().find(([, value]) => value.threadId === input.threadId);
24
+ }
6
25
  export class CodexManagedRunController {
7
26
  runner;
8
27
  host;
@@ -104,8 +123,11 @@ export class CodexManagedRunController {
104
123
  const threadId = typeof params.threadId === 'string' ? params.threadId : undefined;
105
124
  if (turnId === undefined && threadId === undefined)
106
125
  return;
107
- const run = [...this.runner.execution.runs.entries()].find(([, value]) => (turnId !== undefined && value.turnId === turnId) ||
108
- (threadId !== undefined && value.threadId === threadId));
126
+ const run = resolveCodexNotificationRun(this.runner.execution.runs, {
127
+ ...(turnId === undefined ? {} : { turnId }),
128
+ ...(threadId === undefined ? {} : { threadId }),
129
+ ...(notification.method === 'turn/started' ? { allowUnboundFallback: true } : {})
130
+ });
109
131
  if (run === undefined)
110
132
  return;
111
133
  const [runId] = run;
@@ -350,28 +372,46 @@ export class CodexManagedRunController {
350
372
  ...(typeof payload.access === 'string' ? { access: payload.access } : {}),
351
373
  ...(payload.mcpServers === undefined ? {} : { mcpServers: payload.mcpServers })
352
374
  };
353
- const threadResult = typeof payload.externalSessionId === 'string'
354
- ? await this.runner.resumeThread(payload.externalSessionId, cwd, configuration)
355
- : await this.runner.startThread(cwd, configuration);
356
- if (this.host.completeCancelled(runId, cwd)) {
357
- this.runner.releaseEnvironment(runId);
358
- return;
375
+ const collaborationMode = payload.collaborationMode === 'plan' || payload.collaborationMode === 'default'
376
+ ? payload.collaborationMode
377
+ : undefined;
378
+ const turnConfiguration = {
379
+ ...configuration,
380
+ ...(collaborationMode === undefined ? {} : { collaborationMode }),
381
+ ...(payload.serviceTier === 'fast' ? { serviceTier: 'fast' } : {})
382
+ };
383
+ const materializedAttachments = await this.host.materialize(runId, attachments);
384
+ let threadId;
385
+ let turnResult;
386
+ for (let attempt = 0; attempt < 2; attempt += 1) {
387
+ try {
388
+ const threadResult = typeof payload.externalSessionId === 'string'
389
+ ? await this.runner.resumeThread(payload.externalSessionId, cwd, configuration)
390
+ : await this.runner.startThread(cwd, configuration);
391
+ if (this.host.completeCancelled(runId, cwd)) {
392
+ this.runner.releaseEnvironment(runId);
393
+ return;
394
+ }
395
+ threadId = extractId(threadResult, 'thread');
396
+ this.runner.execution.runs.set(runId, { sessionId, threadId, cwd });
397
+ turnResult = await this.runner.startTurn(threadId, input, cwd, turnConfiguration, materializedAttachments);
398
+ break;
399
+ }
400
+ catch (error) {
401
+ this.runner.execution.runs.delete(runId);
402
+ if (attempt === 0 && (await this.runner.recoverMissingRollout(runId, error)))
403
+ continue;
404
+ throw error;
405
+ }
359
406
  }
360
- const threadId = extractId(threadResult, 'thread');
407
+ if (threadId === undefined || turnResult === undefined)
408
+ throw new Error('CODEX_RUN_FAILED');
361
409
  let publicSessionId = sessionId;
362
410
  if (typeof payload.externalSessionId !== 'string') {
363
411
  this.host.promoteSession(sessionId, threadId);
364
412
  publicSessionId = threadId;
365
413
  this.host.send('session.external-id', { sessionId, externalSessionId: threadId });
366
414
  }
367
- this.runner.execution.runs.set(runId, { sessionId: publicSessionId, threadId, cwd });
368
- const turnResult = await this.runner.startTurn(threadId, input, cwd, {
369
- ...configuration,
370
- ...(payload.collaborationMode === 'plan' || payload.collaborationMode === 'default'
371
- ? { collaborationMode: payload.collaborationMode }
372
- : {}),
373
- ...(payload.serviceTier === 'fast' ? { serviceTier: 'fast' } : {})
374
- }, await this.host.materialize(runId, attachments));
375
415
  const turnId = extractId(turnResult, 'turn');
376
416
  this.runner.execution.runs.set(runId, { sessionId: publicSessionId, threadId, turnId, cwd });
377
417
  this.runner.execution.managedTurns.set(turnId, { sessionId: publicSessionId, runId });
@@ -58,6 +58,7 @@ export declare class CodexRunner extends AbstractRunner<'codex'> {
58
58
  presentSession(session: NodeAgentSession, capabilities: NodeCapabilities, context: RunnerSessionPresentationContext): RunnerSessionPresentation;
59
59
  onNotification(listener: (notification: JsonRpcNotification) => void): () => void;
60
60
  start(): Promise<void>;
61
+ recoverMissingRollout(runId: string, error: unknown): Promise<boolean>;
61
62
  prepareEnvironment(environment: Readonly<Record<string, string>>, runId: string): void;
62
63
  releaseEnvironment(runId: string): void;
63
64
  stop(): void;
@@ -1,4 +1,4 @@
1
- import { CodexAppServerClient } from '../codex-app-server.js';
1
+ import { CodexAppServerClient, isCodexRolloutMissingError } from '../codex-app-server.js';
2
2
  import { AbstractRunner } from './abstract-runner.js';
3
3
  import { declaredRunnerProfiles } from '../runner-profiles.js';
4
4
  import { homedir } from 'node:os';
@@ -451,6 +451,17 @@ export class CodexRunner extends AbstractRunner {
451
451
  start() {
452
452
  return this.client.start();
453
453
  }
454
+ async recoverMissingRollout(runId, error) {
455
+ if (!isCodexRolloutMissingError(error))
456
+ return false;
457
+ if ([...this.environmentRuns].some((activeRunId) => activeRunId !== runId))
458
+ return false;
459
+ if ([...this.execution.runs.keys()].some((activeRunId) => activeRunId !== runId))
460
+ return false;
461
+ nodeLog('runner.codex.rollout.recovering', { runId });
462
+ await this.client.restart();
463
+ return true;
464
+ }
454
465
  prepareEnvironment(environment, runId) {
455
466
  if (Object.keys(environment).length === 0 && this.environmentFingerprint === undefined) {
456
467
  this.environmentRuns.add(runId);
@@ -86,9 +86,11 @@ export declare class NodeRuntimeState {
86
86
  */
87
87
  setRunnerTitleFromNative(id: string, title: string): NodeAgentSession;
88
88
  createMessageRun(input: {
89
+ readonly runId?: string;
89
90
  readonly sessionId: string;
90
91
  readonly clientMessageId: string;
91
92
  readonly content: string;
93
+ readonly initiatedByUserId?: number;
92
94
  readonly attachments?: readonly NodeMessageAttachmentInput[];
93
95
  }): {
94
96
  readonly run: NodeAgentRun;
@@ -255,7 +255,7 @@ export class NodeRuntimeState {
255
255
  const session = this.requireSession(input.sessionId);
256
256
  const now = this.now();
257
257
  const run = {
258
- id: randomUUID(),
258
+ id: input.runId ?? randomUUID(),
259
259
  sessionId: session.id,
260
260
  nodeId: this.nodeId(),
261
261
  workspaceId: session.workspaceId,
@@ -264,6 +264,9 @@ export class NodeRuntimeState {
264
264
  recoveryState: 'ACTIVE',
265
265
  version: 0,
266
266
  clientMessageId: input.clientMessageId,
267
+ ...(input.initiatedByUserId === undefined
268
+ ? {}
269
+ : { initiatedByUserId: input.initiatedByUserId }),
267
270
  createdAt: now,
268
271
  updatedAt: now
269
272
  };
@@ -471,15 +474,16 @@ export class NodeRuntimeState {
471
474
  }
472
475
  listConversationTurns(input) {
473
476
  this.requireSession(input.sessionId);
474
- // Queued turns have not received `run.started` yet. Their user item still
475
- // has the acceptance timestamp, so use it rather than sorting every
476
- // queued turn as time zero. The insertion index makes same-millisecond
477
- // sends deterministic; callers receive every page from oldest to newest.
477
+ // A managed Turn keeps the user's acceptance time as its stable timeline
478
+ // position. Runner start/completion timestamps must not move it behind a
479
+ // message that was accepted later. Native Turns without a user timestamp
480
+ // fall back to their own lifecycle time.
478
481
  const all = [...(this.turns.get(input.sessionId) ?? [])]
479
482
  .map((turn, index) => ({ turn, index }))
480
483
  .sort((a, b) => {
481
- const timestamp = (value) => value.startedAt ??
482
- value.items.find((item) => item.id === value.userItemId)?.startedAt ??
484
+ const timestamp = (value) => value.items.find((item) => item.id === value.userItemId)?.startedAt ??
485
+ value.startedAt ??
486
+ value.completedAt ??
483
487
  0;
484
488
  return timestamp(a.turn) - timestamp(b.turn) || a.index - b.index;
485
489
  })
@@ -5,6 +5,10 @@ import type { RunnerRegistry } from '../runner/runner-registry.js';
5
5
  import { type ConversationHistoryPage } from '../util/runner-native-session-parsers.js';
6
6
  import type { RunAttachmentService } from './run-attachment-service.js';
7
7
  export declare function hasManagedActiveRun(runtime: NodeRuntimeState, session: NodeAgentSession): boolean;
8
+ export declare function convergeConversationWatchPage(previous: ConversationHistoryPage | undefined, previousObserved: ConversationHistoryPage | undefined, next: ConversationHistoryPage, previousAuthority: unknown): {
9
+ readonly page: ConversationHistoryPage;
10
+ readonly authority: ConversationHistoryPage['source'];
11
+ };
8
12
  interface ConversationHistoryServiceOptions {
9
13
  readonly runtime: NodeRuntimeState;
10
14
  readonly runners: RunnerRegistry;
@@ -16,11 +20,15 @@ interface ConversationHistoryServiceOptions {
16
20
  }
17
21
  export declare class ConversationHistoryService {
18
22
  private readonly options;
23
+ private readonly activeOfficialReads;
19
24
  constructor(options: ConversationHistoryServiceOptions);
20
25
  read(session: NodeAgentSession, input: {
21
26
  readonly cursor?: string;
22
27
  readonly limit?: number;
23
28
  }): Promise<ConversationHistoryPage>;
29
+ private readManagedActive;
30
+ private prefetchActiveOfficial;
31
+ private takeActiveOfficialRead;
24
32
  refreshExternalActivity(session: NodeAgentSession): Promise<void>;
25
33
  readNative(session: NodeAgentSession): Promise<import("../native-session-history.js").NativeSessionHistory | undefined>;
26
34
  private attachNativeImages;