@moxt-ai/mobius 0.0.307 → 0.0.308

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.
Files changed (44) hide show
  1. package/dist/acp/adapter/codex/adapter.d.ts.map +1 -1
  2. package/dist/acp/adapter/codex/adapter.js +66 -9
  3. package/dist/acp/adapter/codex/adapter.js.map +1 -1
  4. package/dist/acp/adapter/codex/tool-event.d.ts +6 -0
  5. package/dist/acp/adapter/codex/tool-event.d.ts.map +1 -0
  6. package/dist/acp/adapter/codex/tool-event.js +66 -0
  7. package/dist/acp/adapter/codex/tool-event.js.map +1 -0
  8. package/dist/acp/adapter/session-events.d.ts +2 -2
  9. package/dist/acp/adapter/session-events.d.ts.map +1 -1
  10. package/dist/acp/adapter/session-events.js +81 -56
  11. package/dist/acp/adapter/session-events.js.map +1 -1
  12. package/dist/acp/content/content-externalizer.d.ts.map +1 -1
  13. package/dist/acp/content/content-externalizer.js +1 -31
  14. package/dist/acp/content/content-externalizer.js.map +1 -1
  15. package/dist/acp/harness/codex/agent.d.ts.map +1 -1
  16. package/dist/acp/harness/codex/agent.js +4 -75
  17. package/dist/acp/harness/codex/agent.js.map +1 -1
  18. package/dist/acp/harness/codex/app-server-protocol.d.ts +9 -0
  19. package/dist/acp/harness/codex/app-server-protocol.d.ts.map +1 -1
  20. package/dist/acp/harness/codex/app-server-protocol.js +1 -0
  21. package/dist/acp/harness/codex/app-server-protocol.js.map +1 -1
  22. package/dist/acp/harness/codex/history.d.ts +5 -0
  23. package/dist/acp/harness/codex/history.d.ts.map +1 -0
  24. package/dist/acp/harness/codex/history.js +116 -0
  25. package/dist/acp/harness/codex/history.js.map +1 -0
  26. package/dist/cli.js +723 -1346
  27. package/dist/cli.js.map +4 -4
  28. package/dist/runtime/command/registry/history.d.ts.map +1 -1
  29. package/dist/runtime/command/registry/history.js +5 -36
  30. package/dist/runtime/command/registry/history.js.map +1 -1
  31. package/dist/runtime.js +662 -1287
  32. package/dist/runtime.js.map +4 -4
  33. package/dist/session/history/session-event-history-projection.d.ts.map +1 -1
  34. package/dist/session/history/session-event-history-projection.js +23 -2
  35. package/dist/session/history/session-event-history-projection.js.map +1 -1
  36. package/package.json +2 -2
  37. package/dist/acp/native-history/codex/codex-history.d.ts +0 -17
  38. package/dist/acp/native-history/codex/codex-history.d.ts.map +0 -1
  39. package/dist/acp/native-history/codex/codex-history.js +0 -661
  40. package/dist/acp/native-history/codex/codex-history.js.map +0 -1
  41. package/dist/acp/native-history/codex/native-history-events.d.ts +0 -8
  42. package/dist/acp/native-history/codex/native-history-events.d.ts.map +0 -1
  43. package/dist/acp/native-history/codex/native-history-events.js +0 -92
  44. package/dist/acp/native-history/codex/native-history-events.js.map +0 -1
@@ -1,661 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { SESSION_HISTORY_CHARACTER_LIMIT, SESSION_HISTORY_MESSAGE_LIMIT } from "@moxt-ai/mobius-sdk/protocol";
3
- import { z } from "zod";
4
- import { executableLaunch, platformSpawnOptions, revalidateExecutable, stopProcessTree, } from "../../../util/process/executable.js";
5
- import { AcpExecutionError } from "../../acp-error.js";
6
- import { nativeSessionIdSchema } from "../../protocol/native-session.js";
7
- import { embedLocalHistoryImages, SESSION_HISTORY_PREVIEW_TURN_LIMIT, } from "./history-images.js";
8
- const responseSchema = z.union([
9
- z.object({
10
- id: z.number(),
11
- error: z.object({ code: z.number(), message: z.string() }),
12
- }),
13
- z.object({ id: z.number(), result: z.unknown() }),
14
- z.object({ method: z.string() }),
15
- ]);
16
- const threadSchema = z.object({
17
- thread: z.object({
18
- id: nativeSessionIdSchema,
19
- cwd: z
20
- .string()
21
- .min(1)
22
- .max(2_048)
23
- .refine((path) => !path.includes("\0")),
24
- }),
25
- });
26
- const turnsSchema = z.object({
27
- data: z
28
- .array(z.object({
29
- id: z.string().min(1),
30
- status: z.enum(["completed", "interrupted", "failed", "inProgress"]),
31
- error: z.unknown().nullish(),
32
- items: z.array(z.unknown()).max(100_000),
33
- }))
34
- .max(SESSION_HISTORY_MESSAGE_LIMIT),
35
- nextCursor: z.string().nullish(),
36
- });
37
- const itemTypeSchema = z.object({ type: z.string().min(1).max(80) });
38
- const userMessageSchema = z.object({
39
- content: z.array(z.unknown()).max(10_000),
40
- type: z.literal("userMessage"),
41
- });
42
- const textSchema = z.object({ text: z.string() });
43
- const imageSchema = z.object({ url: z.string() });
44
- const agentMessageSchema = textSchema.extend({
45
- id: z.string().optional(),
46
- phase: z.string().nullish(),
47
- type: z.literal("agentMessage"),
48
- });
49
- const reasoningSchema = z.object({
50
- id: z.string(),
51
- summary: z.array(z.string()).max(10_000),
52
- content: z.array(z.string()).max(10_000),
53
- type: z.literal("reasoning"),
54
- });
55
- const commandExecutionSchema = z.object({
56
- id: z.string(),
57
- command: z.string(),
58
- cwd: z.string(),
59
- status: z.string(),
60
- commandActions: z.array(z.object({ type: z.string() }).passthrough()).max(100),
61
- aggregatedOutput: z.string().nullish(),
62
- exitCode: z.number().int().nullish(),
63
- type: z.literal("commandExecution"),
64
- });
65
- const fileChangeSchema = z.object({
66
- changes: z.array(z.object({ diff: z.string(), path: z.string() })).max(10_000),
67
- id: z.string(),
68
- status: z.string(),
69
- type: z.literal("fileChange"),
70
- });
71
- const mcpToolCallSchema = z.object({
72
- arguments: z.unknown().optional(),
73
- error: z.unknown().nullish(),
74
- id: z.string(),
75
- result: z.unknown().nullish(),
76
- server: z.string(),
77
- status: z.string(),
78
- tool: z.string(),
79
- type: z.literal("mcpToolCall"),
80
- });
81
- const dynamicToolCallSchema = z.object({
82
- arguments: z.unknown().optional(),
83
- contentItems: z.array(z.unknown()).max(10_000).nullish(),
84
- id: z.string(),
85
- namespace: z.string().nullish(),
86
- status: z.string(),
87
- tool: z.string(),
88
- type: z.literal("dynamicToolCall"),
89
- });
90
- const planSchema = z.object({ id: z.string(), text: z.string(), type: z.literal("plan") });
91
- const historyItemSchema = z.discriminatedUnion("type", [
92
- userMessageSchema,
93
- agentMessageSchema,
94
- reasoningSchema,
95
- commandExecutionSchema,
96
- fileChangeSchema,
97
- mcpToolCallSchema,
98
- dynamicToolCallSchema,
99
- planSchema,
100
- ]);
101
- class CodexHistoryResponseError extends Error {
102
- code;
103
- constructor(response) {
104
- super(response.message);
105
- this.code = response.code;
106
- this.name = "CodexHistoryResponseError";
107
- }
108
- }
109
- function bounded(value, maximum) {
110
- return value.slice(0, maximum);
111
- }
112
- function activity(activityId, activityType, sequence, fields) {
113
- return {
114
- activityId: bounded(activityId, 128) || `history-${sequence.toString()}`,
115
- activityType,
116
- content: [],
117
- input: bounded(fields.input, 100_000),
118
- locations: fields.locations
119
- .filter((location) => location.length > 0)
120
- .map((location) => bounded(location, 2_048))
121
- .slice(0, 100),
122
- name: bounded(fields.name, 128),
123
- output: bounded(fields.output, 100_000),
124
- sequence,
125
- status: bounded(fields.status, 64),
126
- title: bounded(fields.title, 500),
127
- toolKind: bounded(fields.toolKind, 64),
128
- };
129
- }
130
- function errorMessage(value) {
131
- if (typeof value === "string") {
132
- return value;
133
- }
134
- if (typeof value === "object" && value !== null) {
135
- const message = Reflect.get(value, "message");
136
- if (typeof message === "string") {
137
- return message;
138
- }
139
- }
140
- return JSON.stringify(value) ?? "Codex stopped before completing this turn.";
141
- }
142
- function formatted(value) {
143
- if (value === undefined) {
144
- return "";
145
- }
146
- if (typeof value === "string") {
147
- return value;
148
- }
149
- return JSON.stringify(value) ?? "";
150
- }
151
- function toolStatus(status) {
152
- return status === "inProgress" ? "running" : status === "completed" ? "completed" : "failed";
153
- }
154
- function diffContent(path, newText) {
155
- return { newText, path, type: "diff" };
156
- }
157
- function messageSize(message) {
158
- return (message.text.length +
159
- (message.role === "assistant"
160
- ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length
161
- : 0));
162
- }
163
- const SESSION_HISTORY_MESSAGE_CHARACTER_LIMIT = Math.floor(SESSION_HISTORY_CHARACTER_LIMIT / 2);
164
- function fitActivity(activity, maximumCharacters) {
165
- const truncate = (limit) => ({
166
- ...activity,
167
- input: bounded(activity.input, limit),
168
- locations: activity.locations.map((location) => bounded(location, Math.max(1, limit))),
169
- name: bounded(activity.name, limit),
170
- output: bounded(activity.output, limit),
171
- title: bounded(activity.title, limit),
172
- toolKind: bounded(activity.toolKind, limit),
173
- });
174
- let minimum = 1;
175
- let maximum = 100_000;
176
- let fitted = truncate(0);
177
- while (minimum <= maximum) {
178
- const limit = Math.floor((minimum + maximum) / 2);
179
- const candidate = truncate(limit);
180
- if (JSON.stringify(candidate).length <= maximumCharacters) {
181
- fitted = candidate;
182
- minimum = limit + 1;
183
- }
184
- else {
185
- maximum = limit - 1;
186
- }
187
- }
188
- return fitted;
189
- }
190
- function fitActivities(activities, maximumCharacters) {
191
- if (activities.length === 0) {
192
- return activities;
193
- }
194
- const arrayCharacters = 2 + activities.length - 1;
195
- const maximumActivityCharacters = Math.floor(Math.max(0, maximumCharacters - arrayCharacters) / activities.length);
196
- return activities.map((activity) => fitActivity(activity, maximumActivityCharacters));
197
- }
198
- function fitHistoryMessage(message, maximumCharacters = SESSION_HISTORY_MESSAGE_CHARACTER_LIMIT) {
199
- const text = message.text.slice(-maximumCharacters);
200
- if (message.role === "user") {
201
- return {
202
- message: { ...message, text },
203
- truncated: text.length < message.text.length,
204
- };
205
- }
206
- let activities = message.activities;
207
- const content = message.content;
208
- let fitted = { ...message, activities, content, text };
209
- if (messageSize(fitted) > maximumCharacters && activities.length > 0) {
210
- const maximumActivityCharacters = maximumCharacters - text.length - JSON.stringify(content).length;
211
- activities = fitActivities(activities, maximumActivityCharacters);
212
- fitted = { ...fitted, activities };
213
- }
214
- const excess = Math.max(0, messageSize(fitted) - maximumCharacters);
215
- if (excess > 0) {
216
- const maximumTextLength = Math.max(0, fitted.text.length - excess);
217
- fitted = {
218
- ...fitted,
219
- text: maximumTextLength === 0 ? "" : fitted.text.slice(-maximumTextLength),
220
- };
221
- }
222
- return {
223
- message: fitted,
224
- truncated: fitted.text.length < message.text.length ||
225
- JSON.stringify(activities).length < JSON.stringify(message.activities).length,
226
- };
227
- }
228
- function turnOutcome(status) {
229
- switch (status) {
230
- case "completed":
231
- return "succeeded";
232
- case "interrupted":
233
- return "cancelled";
234
- case "failed":
235
- return "failed";
236
- case "inProgress":
237
- return undefined;
238
- default: {
239
- const unhandled = status;
240
- throw new Error(`Unknown Codex turn status: ${String(unhandled)}`);
241
- }
242
- }
243
- }
244
- function decodeHistory(thread, value, options) {
245
- const page = turnsSchema.parse(value);
246
- const nativeTurn = options.nativeTurn?.();
247
- const coveredCommandIds = nativeTurn != null && page.data[0]?.id === nativeTurn.nativeTurnId ? [nativeTurn.commandId] : [];
248
- const messages = [];
249
- let characters = 0;
250
- let truncated = page.nextCursor != null;
251
- for (const turn of page.data.toReversed()) {
252
- const outcome = turnOutcome(turn.status);
253
- const turnMessageCharacterLimit = Math.max(1, Math.floor(SESSION_HISTORY_CHARACTER_LIMIT / Math.max(1, turn.items.length + (turn.error == null ? 0 : 1))));
254
- let sequence = 0;
255
- let assistantMessageIndex = null;
256
- const append = (message) => {
257
- const fitted = fitHistoryMessage(message, turnMessageCharacterLimit);
258
- if (fitted.message.text.length === 0 &&
259
- (fitted.message.images?.length ?? 0) === 0 &&
260
- (fitted.message.role === "user" ||
261
- (fitted.message.activities.length === 0 && fitted.message.content.length === 0))) {
262
- return;
263
- }
264
- truncated ||= fitted.truncated;
265
- messages.push(fitted.message);
266
- if (fitted.message.role === "assistant") {
267
- assistantMessageIndex = messages.length - 1;
268
- }
269
- characters += messageSize(fitted.message);
270
- };
271
- for (const item of turn.items) {
272
- const decoded = historyItemSchema.safeParse(item);
273
- if (!decoded.success) {
274
- continue;
275
- }
276
- const historyItem = decoded.data;
277
- if (historyItem.type === "userMessage") {
278
- const text = historyItem.content
279
- .map((block) => {
280
- const { type } = itemTypeSchema.parse(block);
281
- if (type === "text") {
282
- return textSchema.parse(block).text;
283
- }
284
- if (type === "image") {
285
- return `[@image](${imageSchema.parse(block).url})`;
286
- }
287
- return "[Attachment]";
288
- })
289
- .join("");
290
- append({
291
- role: "user",
292
- text,
293
- });
294
- }
295
- else if (historyItem.type === "agentMessage") {
296
- append({ activities: [], content: [], role: "assistant", text: historyItem.text });
297
- }
298
- else if (historyItem.type === "reasoning") {
299
- const output = (historyItem.content.length > 0 ? historyItem.content : historyItem.summary).join("\n\n");
300
- if (output.length > 0) {
301
- append({
302
- activities: [
303
- activity(historyItem.id, "reasoning", sequence, {
304
- input: "",
305
- locations: [],
306
- name: "",
307
- output,
308
- status: "completed",
309
- title: "Reasoning",
310
- toolKind: "",
311
- }),
312
- ],
313
- content: [],
314
- role: "assistant",
315
- text: "",
316
- });
317
- sequence += 1;
318
- }
319
- }
320
- else if (historyItem.type === "commandExecution") {
321
- const action = historyItem.commandActions[0]?.type ?? "execute";
322
- append({
323
- activities: [
324
- activity(historyItem.id, "tool", sequence, {
325
- input: JSON.stringify({ command: historyItem.command, cwd: historyItem.cwd }),
326
- locations: [historyItem.cwd],
327
- name: "",
328
- output: JSON.stringify({
329
- formatted_output: historyItem.aggregatedOutput ?? "",
330
- ...(historyItem.exitCode == null ? {} : { exit_code: historyItem.exitCode }),
331
- }),
332
- status: toolStatus(historyItem.status),
333
- title: historyItem.command,
334
- toolKind: action,
335
- }),
336
- ],
337
- content: [],
338
- role: "assistant",
339
- text: "",
340
- });
341
- sequence += 1;
342
- }
343
- else if (historyItem.type === "fileChange") {
344
- const paths = historyItem.changes.map((change) => change.path);
345
- const content = historyItem.changes.map((change) => diffContent(change.path, change.diff));
346
- append({
347
- activities: [
348
- activity(historyItem.id, "tool", sequence, {
349
- input: JSON.stringify({ changes: paths }),
350
- locations: paths,
351
- name: "",
352
- output: "",
353
- status: toolStatus(historyItem.status),
354
- title: paths.join(", "),
355
- toolKind: "edit",
356
- }),
357
- ].map((entry) => ({ ...entry, content })),
358
- content: [],
359
- role: "assistant",
360
- text: "",
361
- });
362
- sequence += 1;
363
- }
364
- else if (historyItem.type === "mcpToolCall") {
365
- append({
366
- activities: [
367
- activity(historyItem.id, "tool", sequence, {
368
- input: formatted(historyItem.arguments),
369
- locations: [],
370
- name: historyItem.tool,
371
- output: formatted(historyItem.error ?? historyItem.result),
372
- status: toolStatus(historyItem.status),
373
- title: `${historyItem.server}/${historyItem.tool}`,
374
- toolKind: "other",
375
- }),
376
- ],
377
- content: [],
378
- role: "assistant",
379
- text: "",
380
- });
381
- sequence += 1;
382
- }
383
- else if (historyItem.type === "dynamicToolCall") {
384
- append({
385
- activities: [
386
- activity(historyItem.id, "tool", sequence, {
387
- input: formatted(historyItem.arguments),
388
- locations: [],
389
- name: historyItem.tool,
390
- output: formatted(historyItem.contentItems),
391
- status: toolStatus(historyItem.status),
392
- title: historyItem.namespace == null
393
- ? historyItem.tool
394
- : `${historyItem.namespace}/${historyItem.tool}`,
395
- toolKind: "other",
396
- }),
397
- ],
398
- content: [],
399
- role: "assistant",
400
- text: "",
401
- });
402
- sequence += 1;
403
- }
404
- else if (historyItem.type === "plan") {
405
- append({
406
- activities: [
407
- activity(historyItem.id, "plan", sequence, {
408
- input: "",
409
- locations: [],
410
- name: "",
411
- output: historyItem.text,
412
- status: "completed",
413
- title: "Plan",
414
- toolKind: "",
415
- }),
416
- ],
417
- content: [],
418
- role: "assistant",
419
- text: "",
420
- });
421
- sequence += 1;
422
- }
423
- }
424
- if (turn.error != null) {
425
- append({
426
- activities: [
427
- activity(`agent-error-${sequence.toString()}`, "tool", sequence, {
428
- input: "",
429
- locations: [],
430
- name: "",
431
- output: errorMessage(turn.error),
432
- status: "failed",
433
- title: "Agent error",
434
- toolKind: "other",
435
- }),
436
- ],
437
- content: [],
438
- role: "assistant",
439
- text: "",
440
- });
441
- }
442
- if (assistantMessageIndex !== null) {
443
- const assistant = messages[assistantMessageIndex];
444
- if (assistant?.role === "assistant") {
445
- characters -= messageSize(assistant);
446
- const updated = {
447
- ...assistant,
448
- ...(outcome === undefined ? {} : { outcome }),
449
- };
450
- const fitted = fitHistoryMessage(updated, turnMessageCharacterLimit);
451
- truncated ||= fitted.truncated;
452
- messages[assistantMessageIndex] = fitted.message;
453
- characters += messageSize(fitted.message);
454
- }
455
- }
456
- else if (outcome !== undefined) {
457
- const message = {
458
- activities: [],
459
- content: [],
460
- role: "assistant",
461
- ...(outcome === undefined ? {} : { outcome }),
462
- text: "",
463
- };
464
- const fitted = fitHistoryMessage(message, turnMessageCharacterLimit);
465
- truncated ||= fitted.truncated;
466
- messages.push(fitted.message);
467
- characters += messageSize(fitted.message);
468
- }
469
- while (messages.length > SESSION_HISTORY_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
470
- const removed = messages.shift();
471
- if (removed !== undefined) {
472
- characters -= messageSize(removed);
473
- }
474
- truncated = true;
475
- }
476
- }
477
- return {
478
- nativeSessionId: thread.id,
479
- cwd: thread.cwd,
480
- history: {
481
- status: "available",
482
- messages,
483
- truncated,
484
- coveredCommandIds,
485
- coveredMessageIds: [],
486
- },
487
- };
488
- }
489
- /** Metadata and paginated display history do not acquire the source writer. */
490
- async function readCodexHistoryWithOptions(agent, cwd, nativeSessionId, signal, options) {
491
- signal.throwIfAborted();
492
- nativeSessionIdSchema.parse(nativeSessionId);
493
- if (agent.id !== "codex" || !(await revalidateExecutable(agent.agentIdentity))) {
494
- throw new AcpExecutionError("The local Codex executable changed. Restart Mobius to discover it again.", {}, "agent_executable_changed");
495
- }
496
- signal.throwIfAborted();
497
- const launch = executableLaunch(agent.agentIdentity.realPath, ["app-server"]);
498
- const child = spawn(launch.command, [...launch.arguments], {
499
- cwd,
500
- env: { ...process.env, ...agent.environment },
501
- ...platformSpawnOptions,
502
- shell: false,
503
- stdio: ["pipe", "pipe", "ignore"],
504
- });
505
- const response = Promise.withResolvers();
506
- let state = { kind: "initializing", requestId: 1 };
507
- const seenCursors = new Set();
508
- let pendingBytes = 0;
509
- let pendingFragments = [];
510
- const fail = (cause) => response.reject(cause instanceof AcpExecutionError
511
- ? cause
512
- : new AcpExecutionError("Saved Codex history could not be read.", { cause }, "native_history_unavailable"));
513
- const send = (message) => {
514
- child.stdin.write(`${JSON.stringify(message)}\n`);
515
- };
516
- const onData = (chunk) => {
517
- try {
518
- let cursor = 0;
519
- let newline = chunk.indexOf("\n");
520
- while (newline >= 0) {
521
- const fragment = chunk.slice(cursor, newline);
522
- const lineBytes = pendingBytes + Buffer.byteLength(fragment);
523
- if (lineBytes > 32 * 1_024 * 1_024) {
524
- throw new AcpExecutionError("This saved conversation is too large to preview.", {}, "native_history_too_large");
525
- }
526
- const line = pendingFragments.length === 0 ? fragment : [...pendingFragments, fragment].join("");
527
- pendingBytes = 0;
528
- pendingFragments = [];
529
- cursor = newline + 1;
530
- newline = chunk.indexOf("\n", cursor);
531
- if (line.trim().length === 0) {
532
- continue;
533
- }
534
- const value = JSON.parse(line);
535
- const message = responseSchema.parse(value);
536
- if (!("id" in message)) {
537
- continue;
538
- }
539
- if (message.id !== state.requestId) {
540
- throw new AcpExecutionError("Codex returned an invalid history response.", {}, "invalid_native_session_response");
541
- }
542
- if ("error" in message) {
543
- fail(new AcpExecutionError("Saved Codex history could not be read.", { cause: new CodexHistoryResponseError(message.error) }, "native_history_unavailable"));
544
- return;
545
- }
546
- switch (state.kind) {
547
- case "initializing":
548
- state = { kind: "metadata", requestId: 2 };
549
- send({ method: "initialized", params: {} });
550
- send({
551
- id: state.requestId,
552
- method: "thread/read",
553
- params: { threadId: nativeSessionId, includeTurns: false },
554
- });
555
- break;
556
- case "metadata": {
557
- const { thread } = threadSchema.parse(message.result);
558
- state = { kind: "turns", requestId: 3, thread, pages: [] };
559
- send({
560
- id: state.requestId,
561
- method: "thread/turns/list",
562
- params: {
563
- threadId: nativeSessionId,
564
- limit: SESSION_HISTORY_PREVIEW_TURN_LIMIT,
565
- sortDirection: "desc",
566
- itemsView: "full",
567
- },
568
- });
569
- break;
570
- }
571
- case "turns": {
572
- const page = turnsSchema.parse(message.result);
573
- const pages = [...state.pages, ...page.data];
574
- const maxTurns = SESSION_HISTORY_MESSAGE_LIMIT;
575
- if (page.nextCursor == null || pages.length >= maxTurns) {
576
- response.resolve(decodeHistory(state.thread, {
577
- data: pages.slice(0, maxTurns),
578
- nextCursor: page.nextCursor,
579
- }, options));
580
- return;
581
- }
582
- if (page.data.length === 0 || seenCursors.has(page.nextCursor)) {
583
- throw new AcpExecutionError("Codex repeated a history page cursor.", {}, "invalid_native_session_response");
584
- }
585
- seenCursors.add(page.nextCursor);
586
- state = { kind: "turns", requestId: state.requestId + 1, thread: state.thread, pages };
587
- send({
588
- id: state.requestId,
589
- method: "thread/turns/list",
590
- params: {
591
- threadId: nativeSessionId,
592
- cursor: page.nextCursor,
593
- limit: Math.min(SESSION_HISTORY_PREVIEW_TURN_LIMIT, maxTurns - pages.length),
594
- sortDirection: "desc",
595
- itemsView: "full",
596
- },
597
- });
598
- break;
599
- }
600
- default: {
601
- const unhandled = state;
602
- throw new Error(`Unknown history read state: ${String(unhandled)}`);
603
- }
604
- }
605
- }
606
- const remainder = chunk.slice(cursor);
607
- if (remainder.length > 0) {
608
- pendingBytes += Buffer.byteLength(remainder);
609
- if (pendingBytes > 32 * 1_024 * 1_024) {
610
- throw new AcpExecutionError("This saved conversation is too large to preview.", {}, "native_history_too_large");
611
- }
612
- pendingFragments.push(remainder);
613
- }
614
- }
615
- catch (cause) {
616
- fail(cause);
617
- }
618
- };
619
- const abort = () => response.reject(signal.reason);
620
- const onExit = () => fail(new AcpExecutionError("Codex stopped before its saved history was available.", {}, "native_history_unavailable"));
621
- const timeout = setTimeout(() => fail(new AcpExecutionError("Reading saved Codex history timed out.", {}, "native_history_timeout")), 60_000);
622
- child.stdout.setEncoding("utf8");
623
- child.stdout.on("data", onData);
624
- child.stdin.on("error", fail);
625
- child.on("error", fail);
626
- child.on("exit", onExit);
627
- signal.addEventListener("abort", abort, { once: true });
628
- try {
629
- if (signal.aborted) {
630
- abort();
631
- }
632
- else {
633
- send({
634
- id: 1,
635
- method: "initialize",
636
- params: { clientInfo: { name: "mobius_history", version: "1.0.0" } },
637
- });
638
- }
639
- const snapshot = await response.promise;
640
- return {
641
- ...snapshot,
642
- history: await embedLocalHistoryImages(snapshot.history, signal),
643
- };
644
- }
645
- finally {
646
- clearTimeout(timeout);
647
- signal.removeEventListener("abort", abort);
648
- child.stdout.removeListener("data", onData);
649
- if (child.pid !== undefined) {
650
- await stopProcessTree(child);
651
- }
652
- child.stdin.removeListener("error", fail);
653
- child.removeListener("error", fail);
654
- child.removeListener("exit", onExit);
655
- }
656
- }
657
- /** Reads the complete Codex turn items used to restore non-retained Chats. */
658
- export const readCodexFullHistory = async (agent, cwd, nativeSessionId, signal, nativeTurn) => await readCodexHistoryWithOptions(agent, cwd, nativeSessionId, signal, {
659
- ...(nativeTurn === undefined ? {} : { nativeTurn }),
660
- });
661
- //# sourceMappingURL=codex-history.js.map