@getpaseo/server 0.1.75 → 0.1.77

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 (200) hide show
  1. package/dist/server/client/daemon-client.d.ts +14 -2
  2. package/dist/server/client/daemon-client.d.ts.map +1 -1
  3. package/dist/server/client/daemon-client.js +37 -0
  4. package/dist/server/client/daemon-client.js.map +1 -1
  5. package/dist/server/server/agent/agent-manager.d.ts +2 -1
  6. package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
  7. package/dist/server/server/agent/agent-manager.js +21 -10
  8. package/dist/server/server/agent/agent-manager.js.map +1 -1
  9. package/dist/server/server/agent/agent-sdk-types.d.ts +5 -0
  10. package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
  11. package/dist/server/server/agent/agent-sdk-types.js +7 -0
  12. package/dist/server/server/agent/agent-sdk-types.js.map +1 -1
  13. package/dist/server/server/agent/import-sessions.d.ts.map +1 -1
  14. package/dist/server/server/agent/import-sessions.js +6 -2
  15. package/dist/server/server/agent/import-sessions.js.map +1 -1
  16. package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
  17. package/dist/server/server/agent/mcp-server.js +227 -4
  18. package/dist/server/server/agent/mcp-server.js.map +1 -1
  19. package/dist/server/server/agent/provider-history-timestamps.d.ts +2 -0
  20. package/dist/server/server/agent/provider-history-timestamps.d.ts.map +1 -0
  21. package/dist/server/server/agent/provider-history-timestamps.js +16 -0
  22. package/dist/server/server/agent/provider-history-timestamps.js.map +1 -0
  23. package/dist/server/server/agent/provider-manifest.d.ts +1 -1
  24. package/dist/server/server/agent/provider-manifest.d.ts.map +1 -1
  25. package/dist/server/server/agent/provider-manifest.js +14 -0
  26. package/dist/server/server/agent/provider-manifest.js.map +1 -1
  27. package/dist/server/server/agent/provider-registry.d.ts.map +1 -1
  28. package/dist/server/server/agent/provider-registry.js +53 -27
  29. package/dist/server/server/agent/provider-registry.js.map +1 -1
  30. package/dist/server/server/agent/provider-snapshot-manager.d.ts +2 -6
  31. package/dist/server/server/agent/provider-snapshot-manager.d.ts.map +1 -1
  32. package/dist/server/server/agent/provider-snapshot-manager.js +43 -32
  33. package/dist/server/server/agent/provider-snapshot-manager.js.map +1 -1
  34. package/dist/server/server/agent/providers/acp-agent.d.ts +3 -1
  35. package/dist/server/server/agent/providers/acp-agent.d.ts.map +1 -1
  36. package/dist/server/server/agent/providers/acp-agent.js +61 -14
  37. package/dist/server/server/agent/providers/acp-agent.js.map +1 -1
  38. package/dist/server/server/agent/providers/claude/agent.d.ts.map +1 -1
  39. package/dist/server/server/agent/providers/claude/agent.js +111 -38
  40. package/dist/server/server/agent/providers/claude/agent.js.map +1 -1
  41. package/dist/server/server/agent/providers/claude/models.d.ts +2 -0
  42. package/dist/server/server/agent/providers/claude/models.d.ts.map +1 -1
  43. package/dist/server/server/agent/providers/claude/models.js +78 -0
  44. package/dist/server/server/agent/providers/claude/models.js.map +1 -1
  45. package/dist/server/server/agent/providers/codex/app-server-transport.d.ts +1 -0
  46. package/dist/server/server/agent/providers/codex/app-server-transport.d.ts.map +1 -1
  47. package/dist/server/server/agent/providers/codex/app-server-transport.js +14 -10
  48. package/dist/server/server/agent/providers/codex/app-server-transport.js.map +1 -1
  49. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +15 -1
  50. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
  51. package/dist/server/server/agent/providers/codex-app-server-agent.js +372 -69
  52. package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
  53. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +21 -0
  54. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts.map +1 -0
  55. package/dist/server/server/agent/providers/cursor-acp-agent.js +85 -0
  56. package/dist/server/server/agent/providers/cursor-acp-agent.js.map +1 -0
  57. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +13 -0
  58. package/dist/server/server/agent/providers/generic-acp-agent.d.ts.map +1 -1
  59. package/dist/server/server/agent/providers/generic-acp-agent.js +209 -2
  60. package/dist/server/server/agent/providers/generic-acp-agent.js.map +1 -1
  61. package/dist/server/server/agent/providers/opencode/server-manager.d.ts.map +1 -1
  62. package/dist/server/server/agent/providers/opencode/server-manager.js +2 -1
  63. package/dist/server/server/agent/providers/opencode/server-manager.js.map +1 -1
  64. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +7 -0
  65. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts.map +1 -1
  66. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +50 -1
  67. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js.map +1 -1
  68. package/dist/server/server/agent/providers/opencode-agent.d.ts +11 -7
  69. package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
  70. package/dist/server/server/agent/providers/opencode-agent.js +307 -346
  71. package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
  72. package/dist/server/server/agent/providers/pi-direct-agent.d.ts +1 -1
  73. package/dist/server/server/agent/providers/pi-direct-agent.d.ts.map +1 -1
  74. package/dist/server/server/agent/providers/pi-direct-agent.js +14 -0
  75. package/dist/server/server/agent/providers/pi-direct-agent.js.map +1 -1
  76. package/dist/server/server/agent/providers/pi-session-recovery-policy.d.ts +22 -0
  77. package/dist/server/server/agent/providers/pi-session-recovery-policy.d.ts.map +1 -0
  78. package/dist/server/server/agent/providers/pi-session-recovery-policy.js +51 -0
  79. package/dist/server/server/agent/providers/pi-session-recovery-policy.js.map +1 -0
  80. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
  81. package/dist/server/server/agent/timeline-projection.d.ts.map +1 -1
  82. package/dist/server/server/agent/timeline-projection.js +9 -0
  83. package/dist/server/server/agent/timeline-projection.js.map +1 -1
  84. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +40 -0
  85. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts.map +1 -0
  86. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +80 -0
  87. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js.map +1 -0
  88. package/dist/server/server/auto-archive-on-merge/index.d.ts +8 -0
  89. package/dist/server/server/auto-archive-on-merge/index.d.ts.map +1 -0
  90. package/dist/server/server/auto-archive-on-merge/index.js +15 -0
  91. package/dist/server/server/auto-archive-on-merge/index.js.map +1 -0
  92. package/dist/server/server/bootstrap.d.ts +2 -0
  93. package/dist/server/server/bootstrap.d.ts.map +1 -1
  94. package/dist/server/server/bootstrap.js +82 -40
  95. package/dist/server/server/bootstrap.js.map +1 -1
  96. package/dist/server/server/checkout/status-projection.d.ts.map +1 -1
  97. package/dist/server/server/checkout/status-projection.js +5 -1
  98. package/dist/server/server/checkout/status-projection.js.map +1 -1
  99. package/dist/server/server/config.d.ts.map +1 -1
  100. package/dist/server/server/config.js +13 -5
  101. package/dist/server/server/config.js.map +1 -1
  102. package/dist/server/server/daemon-config-store.js +1 -0
  103. package/dist/server/server/daemon-config-store.js.map +1 -1
  104. package/dist/server/server/loop/rpc-schemas.d.ts +96 -96
  105. package/dist/server/server/loop-service.d.ts +18 -18
  106. package/dist/server/server/pairing-offer.d.ts +1 -0
  107. package/dist/server/server/pairing-offer.d.ts.map +1 -1
  108. package/dist/server/server/pairing-offer.js +2 -1
  109. package/dist/server/server/pairing-offer.js.map +1 -1
  110. package/dist/server/server/paseo-worktree-service.d.ts +3 -1
  111. package/dist/server/server/paseo-worktree-service.d.ts.map +1 -1
  112. package/dist/server/server/paseo-worktree-service.js +55 -18
  113. package/dist/server/server/paseo-worktree-service.js.map +1 -1
  114. package/dist/server/server/persisted-config.d.ts +16 -0
  115. package/dist/server/server/persisted-config.d.ts.map +1 -1
  116. package/dist/server/server/persisted-config.js +11 -3
  117. package/dist/server/server/persisted-config.js.map +1 -1
  118. package/dist/server/server/relay-transport.d.ts +2 -1
  119. package/dist/server/server/relay-transport.d.ts.map +1 -1
  120. package/dist/server/server/relay-transport.js +26 -4
  121. package/dist/server/server/relay-transport.js.map +1 -1
  122. package/dist/server/server/session.d.ts +6 -0
  123. package/dist/server/server/session.d.ts.map +1 -1
  124. package/dist/server/server/session.js +195 -34
  125. package/dist/server/server/session.js.map +1 -1
  126. package/dist/server/server/utils/diff-highlighter.d.ts.map +1 -1
  127. package/dist/server/server/utils/diff-highlighter.js +30 -9
  128. package/dist/server/server/utils/diff-highlighter.js.map +1 -1
  129. package/dist/server/server/websocket-server.d.ts.map +1 -1
  130. package/dist/server/server/websocket-server.js +5 -0
  131. package/dist/server/server/websocket-server.js.map +1 -1
  132. package/dist/server/server/workspace-git-service.d.ts +6 -1
  133. package/dist/server/server/workspace-git-service.d.ts.map +1 -1
  134. package/dist/server/server/workspace-git-service.js +27 -4
  135. package/dist/server/server/workspace-git-service.js.map +1 -1
  136. package/dist/server/server/workspace-reconciliation-service.d.ts +4 -2
  137. package/dist/server/server/workspace-reconciliation-service.d.ts.map +1 -1
  138. package/dist/server/server/workspace-reconciliation-service.js +112 -14
  139. package/dist/server/server/workspace-reconciliation-service.js.map +1 -1
  140. package/dist/server/server/workspace-registry.d.ts +6 -1
  141. package/dist/server/server/workspace-registry.d.ts.map +1 -1
  142. package/dist/server/server/workspace-registry.js +11 -0
  143. package/dist/server/server/workspace-registry.js.map +1 -1
  144. package/dist/server/server/worktree-session.d.ts.map +1 -1
  145. package/dist/server/server/worktree-session.js +1 -0
  146. package/dist/server/server/worktree-session.js.map +1 -1
  147. package/dist/server/services/github-service.d.ts +46 -0
  148. package/dist/server/services/github-service.d.ts.map +1 -1
  149. package/dist/server/services/github-service.js +274 -5
  150. package/dist/server/services/github-service.js.map +1 -1
  151. package/dist/server/shared/messages.d.ts +3443 -290
  152. package/dist/server/shared/messages.d.ts.map +1 -1
  153. package/dist/server/shared/messages.js +94 -3
  154. package/dist/server/shared/messages.js.map +1 -1
  155. package/dist/server/shared/terminal-input-mode.d.ts +26 -0
  156. package/dist/server/shared/terminal-input-mode.d.ts.map +1 -0
  157. package/dist/server/shared/terminal-input-mode.js +151 -0
  158. package/dist/server/shared/terminal-input-mode.js.map +1 -0
  159. package/dist/server/terminal/terminal-session-controller.d.ts.map +1 -1
  160. package/dist/server/terminal/terminal-session-controller.js +12 -2
  161. package/dist/server/terminal/terminal-session-controller.js.map +1 -1
  162. package/dist/server/terminal/terminal.d.ts +1 -0
  163. package/dist/server/terminal/terminal.d.ts.map +1 -1
  164. package/dist/server/terminal/terminal.js +16 -3
  165. package/dist/server/terminal/terminal.js.map +1 -1
  166. package/dist/server/terminal/worker-terminal-manager.d.ts.map +1 -1
  167. package/dist/server/terminal/worker-terminal-manager.js +8 -0
  168. package/dist/server/terminal/worker-terminal-manager.js.map +1 -1
  169. package/dist/server/utils/checkout-git.d.ts +4 -1
  170. package/dist/server/utils/checkout-git.d.ts.map +1 -1
  171. package/dist/server/utils/checkout-git.js +85 -29
  172. package/dist/server/utils/checkout-git.js.map +1 -1
  173. package/dist/server/utils/directory-suggestions.d.ts +2 -0
  174. package/dist/server/utils/directory-suggestions.d.ts.map +1 -1
  175. package/dist/server/utils/directory-suggestions.js +87 -14
  176. package/dist/server/utils/directory-suggestions.js.map +1 -1
  177. package/dist/server/utils/executable.d.ts.map +1 -1
  178. package/dist/server/utils/executable.js +6 -3
  179. package/dist/server/utils/executable.js.map +1 -1
  180. package/dist/server/utils/path.d.ts +10 -0
  181. package/dist/server/utils/path.d.ts.map +1 -1
  182. package/dist/server/utils/path.js +65 -1
  183. package/dist/server/utils/path.js.map +1 -1
  184. package/dist/server/utils/run-git-command.d.ts +2 -0
  185. package/dist/server/utils/run-git-command.d.ts.map +1 -1
  186. package/dist/server/utils/run-git-command.js +41 -1
  187. package/dist/server/utils/run-git-command.js.map +1 -1
  188. package/dist/server/utils/worktree.js +1 -1
  189. package/dist/server/utils/worktree.js.map +1 -1
  190. package/dist/src/server/agent/agent-sdk-types.js +7 -0
  191. package/dist/src/server/agent/agent-sdk-types.js.map +1 -1
  192. package/dist/src/server/agent/provider-manifest.js +14 -0
  193. package/dist/src/server/agent/provider-manifest.js.map +1 -1
  194. package/dist/src/server/persisted-config.js +11 -3
  195. package/dist/src/server/persisted-config.js.map +1 -1
  196. package/dist/src/shared/messages.js +94 -3
  197. package/dist/src/shared/messages.js.map +1 -1
  198. package/dist/src/utils/executable.js +6 -3
  199. package/dist/src/utils/executable.js.map +1 -1
  200. package/package.json +3 -3
@@ -11,11 +11,13 @@ import { curateAgentActivity } from "../activity-curator.js";
11
11
  import { mapCodexRolloutToolCall, mapCodexToolCallFromThreadItem, } from "./codex/tool-call-mapper.js";
12
12
  import { createProviderEnv, createProviderEnvSpec, resolveProviderCommandPrefix, } from "../provider-launch-config.js";
13
13
  import { findExecutable, isCommandAvailable } from "../../../utils/executable.js";
14
+ import { createPathEquivalenceMatcher } from "../../../utils/path.js";
14
15
  import { spawnProcess } from "../../../utils/spawn.js";
15
16
  import { extractCodexTerminalSessionId, nonEmptyString } from "./tool-call-mapper-utils.js";
16
17
  import { buildCodexFeatures, codexModelSupportsFastMode } from "./codex-feature-definitions.js";
17
18
  import { CodexAppServerClient, } from "./codex/app-server-transport.js";
18
19
  import { renderProviderImageOutputAsAssistantMarkdown, } from "./provider-image-output.js";
20
+ import { normalizeProviderReplayTimestamp } from "../provider-history-timestamps.js";
19
21
  import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, resolveBinaryVersion, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
20
22
  import { runProviderTurn } from "./provider-runner.js";
21
23
  function assertChildWithPipes(child) {
@@ -38,11 +40,13 @@ const CODEX_TOOL_THREAD_ITEM_TYPES = new Set([
38
40
  "webSearch",
39
41
  "collabAgentToolCall",
40
42
  ]);
43
+ const CODEX_CONTEXT_COMPACTION_TYPE = "contextCompaction";
41
44
  const CODEX_PLAN_IMPLEMENTATION_PROMPT_PREFIX = "The user approved the plan. Implement it now. Do not restate or revise the plan unless blocked.";
42
45
  // Codex's experimental `goals` feature ships in 0.128.0+. Older binaries reject
43
46
  // `--enable goals` at launch, so we gate by version and silently skip the flag
44
47
  // (and the /goal slash command) when the binary is too old.
45
48
  const CODEX_GOALS_MIN_VERSION = [0, 128, 0];
49
+ const CODEX_AUTO_REVIEW_MIN_VERSION = [0, 115, 0];
46
50
  function parseCodexVersion(versionOutput) {
47
51
  const match = versionOutput.match(/(\d+)\.(\d+)\.(\d+)/);
48
52
  if (!match)
@@ -91,6 +95,11 @@ const CODEX_MODES = [
91
95
  label: "Default Permissions",
92
96
  description: "Edit files and run commands with Codex's default approval flow.",
93
97
  },
98
+ {
99
+ id: "auto-review",
100
+ label: "Auto-review",
101
+ description: "Same workspace-write permissions as Default, but eligible `on-request` approvals are routed through the auto-reviewer subagent.",
102
+ },
94
103
  {
95
104
  id: "full-access",
96
105
  label: "Full Access",
@@ -107,12 +116,30 @@ const MODE_PRESETS = {
107
116
  approvalPolicy: "on-request",
108
117
  sandbox: "workspace-write",
109
118
  },
119
+ "auto-review": {
120
+ approvalPolicy: "on-request",
121
+ sandbox: "workspace-write",
122
+ approvalsReviewer: "auto_review",
123
+ },
110
124
  "full-access": {
111
125
  approvalPolicy: "never",
112
126
  sandbox: "danger-full-access",
113
127
  networkAccess: true,
114
128
  },
115
129
  };
130
+ function isAutoReviewReviewer(value) {
131
+ return value === "auto_review" || value === "guardian_subagent";
132
+ }
133
+ function applyApprovalsReviewerParam(params, preset) {
134
+ if (preset.approvalsReviewer) {
135
+ params.approvalsReviewer = preset.approvalsReviewer;
136
+ }
137
+ }
138
+ function shouldPromoteThreadResponseToAutoReview(params) {
139
+ return (isAutoReviewReviewer(params.approvalsReviewer) &&
140
+ params.approvalPolicy === "on-request" &&
141
+ params.sandbox === "workspace-write");
142
+ }
116
143
  function validateCodexMode(modeId) {
117
144
  if (!(modeId in MODE_PRESETS)) {
118
145
  const validModes = Object.keys(MODE_PRESETS).join(", ");
@@ -484,7 +511,8 @@ function filterCodexThreadsByCwd(threads, cwd) {
484
511
  // falls back to process.cwd() if the field is missing, so we only match
485
512
  // here when the row genuinely carries a cwd string — otherwise threads
486
513
  // with no cwd would falsely match the daemon's own cwd.
487
- return threads.filter((thread) => typeof thread.cwd === "string" && thread.cwd === cwd);
514
+ const matchesCwd = createPathEquivalenceMatcher(cwd);
515
+ return threads.filter((thread) => typeof thread.cwd === "string" && matchesCwd(thread.cwd));
488
516
  }
489
517
  function toAgentUsage(tokenUsage) {
490
518
  const usage = toObjectRecord(tokenUsage);
@@ -1070,6 +1098,29 @@ function firstStringField(record, fields) {
1070
1098
  }
1071
1099
  return null;
1072
1100
  }
1101
+ function readCodexHistoryTimestamp(item) {
1102
+ const record = toObjectRecord(item);
1103
+ if (!record) {
1104
+ return null;
1105
+ }
1106
+ return (normalizeProviderReplayTimestamp(record.timestamp) ??
1107
+ normalizeProviderReplayTimestamp(record.createdAt) ??
1108
+ normalizeProviderReplayTimestamp(record.created_at));
1109
+ }
1110
+ function readCodexTurnHistoryTimestamp(turn, timelineItem) {
1111
+ const record = toObjectRecord(turn);
1112
+ if (!record) {
1113
+ return null;
1114
+ }
1115
+ const startedAt = normalizeProviderReplayTimestamp(record.startedAt) ??
1116
+ normalizeProviderReplayTimestamp(record.started_at);
1117
+ const completedAt = normalizeProviderReplayTimestamp(record.completedAt) ??
1118
+ normalizeProviderReplayTimestamp(record.completed_at);
1119
+ if (timelineItem.type === "user_message") {
1120
+ return startedAt ?? completedAt;
1121
+ }
1122
+ return completedAt ?? startedAt;
1123
+ }
1073
1124
  function codexImageOutputFromResult(result) {
1074
1125
  if (typeof result === "string") {
1075
1126
  const trimmed = result.trim();
@@ -1139,15 +1190,23 @@ function threadItemToTimeline(item, options) {
1139
1190
  switch (normalizedType) {
1140
1191
  case "userMessage":
1141
1192
  return mapCodexThreadUserMessageItem(normalizedItem, includeUserMessage);
1142
- case "agentMessage":
1193
+ case "agentMessage": {
1194
+ const messageId = nonEmptyString(normalizedItem.id);
1143
1195
  return {
1144
1196
  type: "assistant_message",
1145
1197
  text: typeof normalizedItem.text === "string" ? normalizedItem.text : "",
1198
+ ...(messageId ? { messageId } : {}),
1146
1199
  };
1200
+ }
1147
1201
  case "plan":
1148
1202
  return mapCodexThreadPlanItem(normalizedItem);
1149
1203
  case "reasoning":
1150
1204
  return mapCodexThreadReasoningItem(normalizedItem);
1205
+ case CODEX_CONTEXT_COMPACTION_TYPE:
1206
+ return {
1207
+ type: "compaction",
1208
+ status: "completed",
1209
+ };
1151
1210
  default:
1152
1211
  return null;
1153
1212
  }
@@ -1179,7 +1238,11 @@ async function loadCodexThreadHistoryTimeline(params) {
1179
1238
  for (const item of turn.items) {
1180
1239
  const timelineItem = threadItemToTimeline(item, { cwd: params.cwd });
1181
1240
  if (timelineItem) {
1182
- timeline.push(timelineItem);
1241
+ const timestamp = readCodexHistoryTimestamp(item) ?? readCodexTurnHistoryTimestamp(turn, timelineItem);
1242
+ timeline.push({
1243
+ item: timelineItem,
1244
+ timestamp: timestamp ?? undefined,
1245
+ });
1183
1246
  }
1184
1247
  }
1185
1248
  }
@@ -1296,6 +1359,12 @@ const ItemLifecycleNotificationSchema = z
1296
1359
  .passthrough(),
1297
1360
  })
1298
1361
  .passthrough();
1362
+ const ContextCompactedNotificationSchema = z
1363
+ .object({
1364
+ threadId: z.string(),
1365
+ turnId: z.string().optional(),
1366
+ })
1367
+ .passthrough();
1299
1368
  const CodexEventTurnAbortedNotificationSchema = z
1300
1369
  .object({
1301
1370
  msg: z
@@ -1511,6 +1580,18 @@ const CodexNotificationSchema = z.union([
1511
1580
  method,
1512
1581
  params,
1513
1582
  })),
1583
+ z
1584
+ .object({ method: z.literal("thread/compacted"), params: ContextCompactedNotificationSchema })
1585
+ .transform(({ params }) => ({
1586
+ kind: "context_compacted",
1587
+ threadId: params.threadId,
1588
+ turnId: params.turnId ?? null,
1589
+ })),
1590
+ z.object({ method: z.literal("thread/compacted"), params: z.unknown() }).transform(({ method, params }) => ({
1591
+ kind: "invalid_payload",
1592
+ method,
1593
+ params,
1594
+ })),
1514
1595
  z
1515
1596
  .object({
1516
1597
  method: z.literal("item/agentMessage/delta"),
@@ -1952,12 +2033,13 @@ function buildCodexCustomProviderConfig(runtimeSettings, customProvider) {
1952
2033
  };
1953
2034
  }
1954
2035
  class CodexAppServerAgentSession {
1955
- constructor(config, resumeHandle, logger, spawnAppServer, deps = {}, ephemeral = false, goalsEnabled = false, agentId) {
2036
+ constructor(config, resumeHandle, logger, spawnAppServer, deps = {}, ephemeral = false, goalsEnabled = false, autoReviewEnabled = false, agentId) {
1956
2037
  this.resumeHandle = resumeHandle;
1957
2038
  this.spawnAppServer = spawnAppServer;
1958
2039
  this.deps = deps;
1959
2040
  this.ephemeral = ephemeral;
1960
2041
  this.goalsEnabled = goalsEnabled;
2042
+ this.autoReviewEnabled = autoReviewEnabled;
1961
2043
  this.agentId = agentId;
1962
2044
  this.provider = CODEX_PROVIDER;
1963
2045
  this.capabilities = CODEX_APP_SERVER_CAPABILITIES;
@@ -1993,6 +2075,12 @@ class CodexAppServerAgentSession {
1993
2075
  this.warnedInvalidNotificationPayloads = new Set();
1994
2076
  this.warnedIncompleteEditToolCallIds = new Set();
1995
2077
  this.latestPlanResult = null;
2078
+ this.pendingManualCompactionStarts = 0;
2079
+ this.compactionTriggerByItemId = new Map();
2080
+ // Codex can report one completed compaction through both channels:
2081
+ // `thread/compacted` and a completed `contextCompaction` item.
2082
+ this.unpairedCompactionNotificationCompletions = 0;
2083
+ this.unpairedCompactionItemCompletions = 0;
1996
2084
  this.connected = false;
1997
2085
  this.collaborationModes = [];
1998
2086
  this.resolvedCollaborationMode = null;
@@ -2009,7 +2097,7 @@ class CodexAppServerAgentSession {
2009
2097
  this.currentMode = config.modeId;
2010
2098
  this.config = config;
2011
2099
  this.config.thinkingOptionId = normalizeCodexThinkingOptionId(this.config.thinkingOptionId);
2012
- if (this.config.featureValues?.fast_mode) {
2100
+ if (this.config.featureValues?.fast_mode && codexModelSupportsFastMode(this.config.model)) {
2013
2101
  this.serviceTier = "fast";
2014
2102
  }
2015
2103
  if (this.config.featureValues?.plan_mode) {
@@ -2094,7 +2182,7 @@ class CodexAppServerAgentSession {
2094
2182
  cwd: [this.config.cwd],
2095
2183
  }));
2096
2184
  const entries = Array.isArray(response?.data) ? response.data : [];
2097
- const skills = [];
2185
+ const skillsByName = new Map();
2098
2186
  for (const entry of entries) {
2099
2187
  const entryRecord = toObjectRecord(entry);
2100
2188
  const list = Array.isArray(entryRecord?.skills) ? entryRecord.skills : [];
@@ -2102,14 +2190,16 @@ class CodexAppServerAgentSession {
2102
2190
  const skillRecord = toObjectRecord(skill);
2103
2191
  if (typeof skillRecord?.name !== "string" || typeof skillRecord?.path !== "string")
2104
2192
  continue;
2105
- skills.push({
2106
- name: skillRecord.name,
2107
- description: resolveSkillDescription(skillRecord),
2108
- path: skillRecord.path,
2109
- });
2193
+ if (!skillsByName.has(skillRecord.name)) {
2194
+ skillsByName.set(skillRecord.name, {
2195
+ name: skillRecord.name,
2196
+ description: resolveSkillDescription(skillRecord),
2197
+ path: skillRecord.path,
2198
+ });
2199
+ }
2110
2200
  }
2111
2201
  }
2112
- this.cachedSkills = skills;
2202
+ this.cachedSkills = Array.from(skillsByName.values());
2113
2203
  }
2114
2204
  catch (error) {
2115
2205
  this.logger.trace({
@@ -2330,56 +2420,18 @@ class CodexAppServerAgentSession {
2330
2420
  }
2331
2421
  const skill = this.cachedSkills.find((entry) => entry.name === commandName);
2332
2422
  if (skill) {
2423
+ const trimmedArgs = args?.trim() ?? "";
2424
+ const text = trimmedArgs ? `$${skill.name} ${trimmedArgs}` : `$${skill.name}`;
2333
2425
  const input = [
2334
2426
  { type: "skill", name: skill.name, path: skill.path },
2427
+ { type: "text", text },
2335
2428
  ];
2336
- if (args && args.trim().length > 0) {
2337
- input.push({ type: "text", text: args.trim() });
2338
- }
2339
- else {
2340
- input.push({ type: "text", text: `$${skill.name}` });
2341
- }
2342
2429
  return input;
2343
2430
  }
2344
2431
  return args ? `$${commandName} ${args}` : `$${commandName}`;
2345
2432
  }
2346
- async run(prompt, options) {
2347
- return runProviderTurn({
2348
- prompt,
2349
- runOptions: options,
2350
- startTurn: (p, o) => this.startTurn(p, o),
2351
- subscribe: (callback) => this.subscribe(callback),
2352
- getSessionId: async () => (await this.getRuntimeInfo()).sessionId ?? "",
2353
- reduceFinalText: ({ current, item }) => {
2354
- if (item.type === "assistant_message") {
2355
- return item.text;
2356
- }
2357
- if (item.type === "tool_call" && item.detail.type === "plan") {
2358
- return item.detail.text;
2359
- }
2360
- return current;
2361
- },
2362
- });
2363
- }
2364
- async startTurn(prompt, options) {
2365
- if (this.activeForegroundTurnId) {
2366
- throw new Error("A foreground turn is already active");
2367
- }
2368
- await this.connect();
2369
- if (!this.client) {
2370
- throw new Error("Codex client not initialized");
2371
- }
2372
- const slashCommand = await this.resolveSlashCommandInvocation(prompt);
2373
- const effectivePrompt = slashCommand
2374
- ? await this.buildCommandPromptInput(slashCommand.commandName, slashCommand.args)
2375
- : prompt;
2376
- if (this.currentThreadId) {
2377
- await this.ensureThreadLoaded();
2378
- }
2379
- else {
2380
- await this.ensureThread();
2381
- }
2382
- const input = await this.buildUserInput(effectivePrompt);
2433
+ async buildTurnStartParams(prompt, options) {
2434
+ const input = await this.buildUserInput(prompt);
2383
2435
  const preset = MODE_PRESETS[this.currentMode] ?? MODE_PRESETS[DEFAULT_CODEX_MODE_ID];
2384
2436
  const approvalPolicy = this.config.approvalPolicy ?? preset.approvalPolicy;
2385
2437
  const sandboxPolicyType = this.config.sandboxMode ?? preset.sandbox;
@@ -2391,6 +2443,7 @@ class CodexAppServerAgentSession {
2391
2443
  ? this.config.networkAccess
2392
2444
  : preset.networkAccess),
2393
2445
  };
2446
+ applyApprovalsReviewerParam(params, preset);
2394
2447
  if (this.config.model) {
2395
2448
  params.model = this.config.model;
2396
2449
  }
@@ -2420,10 +2473,81 @@ class CodexAppServerAgentSession {
2420
2473
  if (codexConfig) {
2421
2474
  params.config = codexConfig;
2422
2475
  }
2476
+ return {
2477
+ params,
2478
+ thinkingOptionId,
2479
+ approvalPolicy,
2480
+ sandboxPolicyType,
2481
+ hasOutputSchema: Boolean(options?.outputSchema),
2482
+ hasCodexConfig: Boolean(codexConfig),
2483
+ };
2484
+ }
2485
+ logTurnStartSummary({ turnId, thinkingOptionId, approvalPolicy, sandboxPolicyType, hasOutputSchema, hasCodexConfig, }) {
2486
+ this.logger.info({
2487
+ turnId,
2488
+ threadId: this.currentThreadId,
2489
+ model: this.config.model ?? null,
2490
+ modeId: this.currentMode ?? null,
2491
+ effort: thinkingOptionId ?? null,
2492
+ serviceTier: this.serviceTier,
2493
+ cwd: this.config.cwd ?? null,
2494
+ approvalPolicy,
2495
+ sandboxPolicyType,
2496
+ hasCollaborationMode: Boolean(this.resolvedCollaborationMode),
2497
+ hasOutputSchema,
2498
+ hasDeveloperInstructions: Boolean(this.config.systemPrompt?.trim()),
2499
+ hasCodexConfig,
2500
+ }, "Starting Codex app-server turn");
2501
+ }
2502
+ async run(prompt, options) {
2503
+ return runProviderTurn({
2504
+ prompt,
2505
+ runOptions: options,
2506
+ startTurn: (p, o) => this.startTurn(p, o),
2507
+ subscribe: (callback) => this.subscribe(callback),
2508
+ getSessionId: async () => (await this.getRuntimeInfo()).sessionId ?? "",
2509
+ reduceFinalText: ({ current, item }) => {
2510
+ if (item.type === "assistant_message") {
2511
+ return item.text;
2512
+ }
2513
+ if (item.type === "tool_call" && item.detail.type === "plan") {
2514
+ return item.detail.text;
2515
+ }
2516
+ return current;
2517
+ },
2518
+ });
2519
+ }
2520
+ async startTurn(prompt, options) {
2521
+ if (this.activeForegroundTurnId) {
2522
+ throw new Error("A foreground turn is already active");
2523
+ }
2524
+ await this.connect();
2525
+ if (!this.client) {
2526
+ throw new Error("Codex client not initialized");
2527
+ }
2528
+ const slashCommand = await this.resolveSlashCommandInvocation(prompt);
2529
+ const effectivePrompt = slashCommand
2530
+ ? await this.buildCommandPromptInput(slashCommand.commandName, slashCommand.args)
2531
+ : prompt;
2532
+ if (this.currentThreadId) {
2533
+ await this.ensureThreadLoaded();
2534
+ }
2535
+ else {
2536
+ await this.ensureThread();
2537
+ }
2538
+ const turnStart = await this.buildTurnStartParams(effectivePrompt, options);
2423
2539
  const turnId = this.createTurnId();
2424
2540
  this.activeForegroundTurnId = turnId;
2425
2541
  try {
2426
- await this.client.request("turn/start", params, TURN_START_TIMEOUT_MS);
2542
+ this.logTurnStartSummary({
2543
+ turnId,
2544
+ thinkingOptionId: turnStart.thinkingOptionId,
2545
+ approvalPolicy: turnStart.approvalPolicy,
2546
+ sandboxPolicyType: turnStart.sandboxPolicyType,
2547
+ hasOutputSchema: turnStart.hasOutputSchema,
2548
+ hasCodexConfig: turnStart.hasCodexConfig,
2549
+ });
2550
+ await this.client.request("turn/start", turnStart.params, TURN_START_TIMEOUT_MS);
2427
2551
  }
2428
2552
  catch (error) {
2429
2553
  this.activeForegroundTurnId = null;
@@ -2444,8 +2568,13 @@ class CodexAppServerAgentSession {
2444
2568
  const history = this.persistedHistory;
2445
2569
  this.persistedHistory = [];
2446
2570
  this.historyPending = false;
2447
- for (const item of history) {
2448
- yield { type: "timeline", provider: CODEX_PROVIDER, item };
2571
+ for (const entry of history) {
2572
+ yield {
2573
+ type: "timeline",
2574
+ provider: CODEX_PROVIDER,
2575
+ item: entry.item,
2576
+ timestamp: entry.timestamp,
2577
+ };
2449
2578
  }
2450
2579
  }
2451
2580
  async getRuntimeInfo() {
@@ -2471,7 +2600,10 @@ class CodexAppServerAgentSession {
2471
2600
  return { ...info };
2472
2601
  }
2473
2602
  async getAvailableModes() {
2474
- return CODEX_MODES;
2603
+ if (this.autoReviewEnabled) {
2604
+ return CODEX_MODES;
2605
+ }
2606
+ return CODEX_MODES.filter((mode) => mode.id !== "auto-review");
2475
2607
  }
2476
2608
  async getCurrentMode() {
2477
2609
  return this.currentMode ?? null;
@@ -2496,6 +2628,9 @@ class CodexAppServerAgentSession {
2496
2628
  }
2497
2629
  async setFeature(featureId, value) {
2498
2630
  if (featureId === "fast_mode") {
2631
+ if (Boolean(value) && !codexModelSupportsFastMode(this.config.model)) {
2632
+ throw new Error(`Codex fast mode is not available for model '${this.config.model ?? "default"}'`);
2633
+ }
2499
2634
  this.applyFeatureValue("fast_mode", Boolean(value));
2500
2635
  return;
2501
2636
  }
@@ -2700,7 +2835,13 @@ class CodexAppServerAgentSession {
2700
2835
  const fallbackSkills = appServerSkills.length === 0
2701
2836
  ? await listCodexSkills(this.config.cwd, this.deps.workspaceGitService)
2702
2837
  : [];
2703
- const builtin = [];
2838
+ const builtin = [
2839
+ {
2840
+ name: "compact",
2841
+ description: "Summarize conversation to prevent hitting the context limit",
2842
+ argumentHint: "",
2843
+ },
2844
+ ];
2704
2845
  if (this.goalsEnabled) {
2705
2846
  builtin.push({
2706
2847
  name: "goal",
@@ -2711,12 +2852,26 @@ class CodexAppServerAgentSession {
2711
2852
  return [...builtin, ...appServerSkills, ...fallbackSkills, ...prompts].sort((a, b) => a.name.localeCompare(b.name));
2712
2853
  }
2713
2854
  tryHandleOutOfBand(prompt) {
2714
- if (!this.goalsEnabled)
2715
- return null;
2716
2855
  if (typeof prompt !== "string")
2717
2856
  return null;
2718
2857
  const parsed = this.parseSlashCommandInput(prompt);
2719
- if (!parsed || parsed.commandName !== "goal")
2858
+ if (!parsed)
2859
+ return null;
2860
+ if (parsed.commandName === "compact") {
2861
+ return {
2862
+ run: async ({ emit }) => {
2863
+ const error = await this.executeCompactCommand();
2864
+ if (error) {
2865
+ emit({
2866
+ type: "timeline",
2867
+ provider: CODEX_PROVIDER,
2868
+ item: { type: "assistant_message", text: formatOutOfBandStatusMessage(error) },
2869
+ });
2870
+ }
2871
+ },
2872
+ };
2873
+ }
2874
+ if (!this.goalsEnabled || parsed.commandName !== "goal")
2720
2875
  return null;
2721
2876
  const subcommand = parseGoalSubcommand(parsed.args);
2722
2877
  return {
@@ -2730,6 +2885,35 @@ class CodexAppServerAgentSession {
2730
2885
  },
2731
2886
  };
2732
2887
  }
2888
+ async executeCompactCommand() {
2889
+ try {
2890
+ await this.connect();
2891
+ if (this.currentThreadId) {
2892
+ await this.ensureThreadLoaded();
2893
+ }
2894
+ else {
2895
+ await this.ensureThread();
2896
+ }
2897
+ if (!this.client || !this.currentThreadId) {
2898
+ throw new Error("Codex thread is not available");
2899
+ }
2900
+ this.pendingManualCompactionStarts += 1;
2901
+ try {
2902
+ await this.client.request("thread/compact/start", {
2903
+ threadId: this.currentThreadId,
2904
+ });
2905
+ }
2906
+ catch (error) {
2907
+ this.pendingManualCompactionStarts = Math.max(0, this.pendingManualCompactionStarts - 1);
2908
+ throw error;
2909
+ }
2910
+ return null;
2911
+ }
2912
+ catch (error) {
2913
+ const message = error instanceof Error ? error.message : "unknown error";
2914
+ return `Failed to compact context: ${message}`;
2915
+ }
2916
+ }
2733
2917
  async executeGoalSubcommand(subcommand) {
2734
2918
  if (subcommand.kind === "usage") {
2735
2919
  return "Usage: /goal <objective>|pause|resume|clear";
@@ -2841,7 +3025,7 @@ class CodexAppServerAgentSession {
2841
3025
  const approvalPolicy = this.config.approvalPolicy ?? preset.approvalPolicy;
2842
3026
  const sandbox = this.config.sandboxMode ?? preset.sandbox;
2843
3027
  const innerConfig = this.buildCodexInnerConfig();
2844
- const rawResponse = await this.client.request("thread/start", {
3028
+ const params = {
2845
3029
  model,
2846
3030
  cwd: this.config.cwd ?? null,
2847
3031
  approvalPolicy,
@@ -2851,13 +3035,24 @@ class CodexAppServerAgentSession {
2851
3035
  : {}),
2852
3036
  ...(innerConfig ? { config: innerConfig } : {}),
2853
3037
  ...(this.ephemeral ? { ephemeral: true } : {}),
2854
- });
3038
+ };
3039
+ applyApprovalsReviewerParam(params, preset);
3040
+ const rawResponse = await this.client.request("thread/start", params);
2855
3041
  const response = toObjectRecord(rawResponse);
2856
3042
  const threadRecord = toObjectRecord(response?.thread);
2857
3043
  const threadId = typeof threadRecord?.id === "string" ? threadRecord.id : undefined;
2858
3044
  if (!threadId) {
2859
3045
  throw new Error("Codex app-server did not return thread id");
2860
3046
  }
3047
+ const responseApprovalsReviewer = typeof response?.approvalsReviewer === "string" ? response.approvalsReviewer : undefined;
3048
+ if (shouldPromoteThreadResponseToAutoReview({
3049
+ approvalsReviewer: responseApprovalsReviewer,
3050
+ approvalPolicy,
3051
+ sandbox,
3052
+ })) {
3053
+ this.currentMode = "auto-review";
3054
+ this.cachedRuntimeInfo = null;
3055
+ }
2861
3056
  this.currentThreadId = threadId;
2862
3057
  }
2863
3058
  buildCodexInnerConfig() {
@@ -2932,6 +3127,9 @@ class CodexAppServerAgentSession {
2932
3127
  case "token_usage_updated":
2933
3128
  this.handleTokenUsageUpdatedNotification(parsed);
2934
3129
  return;
3130
+ case "context_compacted":
3131
+ this.handleContextCompactedNotification(parsed);
3132
+ return;
2935
3133
  case "agent_message_delta":
2936
3134
  case "reasoning_delta":
2937
3135
  case "exec_command_output_delta":
@@ -3085,6 +3283,7 @@ class CodexAppServerAgentSession {
3085
3283
  if (subAgentCallId) {
3086
3284
  this.upsertSubAgentChildItem(subAgentCallId, parsed.itemId, {
3087
3285
  type: "assistant_message",
3286
+ messageId: parsed.itemId,
3088
3287
  text,
3089
3288
  });
3090
3289
  this.emitSubAgentActivityUpdate(subAgentCallId, "running");
@@ -3096,6 +3295,7 @@ class CodexAppServerAgentSession {
3096
3295
  provider: CODEX_PROVIDER,
3097
3296
  item: {
3098
3297
  type: "assistant_message",
3298
+ messageId: parsed.itemId,
3099
3299
  text: isFirstDeltaForItem && this.pendingAssistantMessageBoundary
3100
3300
  ? `${ASSISTANT_MESSAGE_BOUNDARY_MARKDOWN}${parsed.delta}`
3101
3301
  : parsed.delta,
@@ -3200,6 +3400,8 @@ class CodexAppServerAgentSession {
3200
3400
  this.pendingFileChangeOutputDeltas.clear();
3201
3401
  this.pendingAssistantMessageBoundary = false;
3202
3402
  this.warnedIncompleteEditToolCallIds.clear();
3403
+ this.unpairedCompactionNotificationCompletions = 0;
3404
+ this.unpairedCompactionItemCompletions = 0;
3203
3405
  }
3204
3406
  handlePlanUpdatedNotification(parsed) {
3205
3407
  const timelineItem = mapCodexPlanToToolCall({
@@ -3230,6 +3432,55 @@ class CodexAppServerAgentSession {
3230
3432
  });
3231
3433
  }
3232
3434
  }
3435
+ resolveContextCompactionTrigger(itemId) {
3436
+ if (itemId) {
3437
+ const known = this.compactionTriggerByItemId.get(itemId);
3438
+ if (known) {
3439
+ return known;
3440
+ }
3441
+ }
3442
+ if (this.pendingManualCompactionStarts > 0) {
3443
+ this.pendingManualCompactionStarts -= 1;
3444
+ return "manual";
3445
+ }
3446
+ return undefined;
3447
+ }
3448
+ createContextCompactionTimelineItem(status, itemId) {
3449
+ const trigger = this.resolveContextCompactionTrigger(itemId);
3450
+ if (itemId && trigger) {
3451
+ if (status === "loading") {
3452
+ this.compactionTriggerByItemId.set(itemId, trigger);
3453
+ }
3454
+ else {
3455
+ this.compactionTriggerByItemId.delete(itemId);
3456
+ }
3457
+ }
3458
+ return {
3459
+ type: "compaction",
3460
+ status,
3461
+ ...(trigger ? { trigger } : {}),
3462
+ };
3463
+ }
3464
+ isContextCompactionItem(item) {
3465
+ return (normalizeCodexThreadItemType(typeof item.type === "string" ? item.type : undefined) ===
3466
+ CODEX_CONTEXT_COMPACTION_TYPE);
3467
+ }
3468
+ handleContextCompactedNotification(parsed) {
3469
+ if (parsed.threadId !== this.currentThreadId) {
3470
+ return;
3471
+ }
3472
+ if (this.unpairedCompactionItemCompletions > 0) {
3473
+ this.unpairedCompactionItemCompletions -= 1;
3474
+ return;
3475
+ }
3476
+ this.unpairedCompactionNotificationCompletions += 1;
3477
+ this.emitEvent({
3478
+ type: "timeline",
3479
+ provider: CODEX_PROVIDER,
3480
+ item: this.createContextCompactionTimelineItem("completed"),
3481
+ ...(parsed.turnId ? { turnId: parsed.turnId } : {}),
3482
+ });
3483
+ }
3233
3484
  handleExecCommandStartedNotification(parsed) {
3234
3485
  if (parsed.callId) {
3235
3486
  this.emittedExecCommandStartedCallIds.add(parsed.callId);
@@ -3326,6 +3577,19 @@ class CodexAppServerAgentSession {
3326
3577
  if (parsed.source === "codex_event") {
3327
3578
  return;
3328
3579
  }
3580
+ if (this.isContextCompactionItem(parsed.item)) {
3581
+ if (this.unpairedCompactionNotificationCompletions > 0) {
3582
+ this.unpairedCompactionNotificationCompletions -= 1;
3583
+ return;
3584
+ }
3585
+ this.emitEvent({
3586
+ type: "timeline",
3587
+ provider: CODEX_PROVIDER,
3588
+ item: this.createContextCompactionTimelineItem("completed", parsed.item.id),
3589
+ });
3590
+ this.unpairedCompactionItemCompletions += 1;
3591
+ return;
3592
+ }
3329
3593
  const timelineItem = threadItemToTimeline(parsed.item, {
3330
3594
  includeUserMessage: false,
3331
3595
  cwd: this.config.cwd ?? null,
@@ -3407,7 +3671,13 @@ class CodexAppServerAgentSession {
3407
3671
  this.emitEvent({
3408
3672
  type: "timeline",
3409
3673
  provider: CODEX_PROVIDER,
3410
- item: { type: timelineItem.type, text: suffix },
3674
+ item: timelineItem.type === "assistant_message"
3675
+ ? {
3676
+ type: timelineItem.type,
3677
+ text: suffix,
3678
+ ...(timelineItem.messageId ? { messageId: timelineItem.messageId } : {}),
3679
+ }
3680
+ : { type: timelineItem.type, text: suffix },
3411
3681
  });
3412
3682
  }
3413
3683
  applyBufferedDeltaTextToTimelineItem(timelineItem, itemId) {
@@ -3432,6 +3702,14 @@ class CodexAppServerAgentSession {
3432
3702
  if (parsed.source === "codex_event") {
3433
3703
  return;
3434
3704
  }
3705
+ if (this.isContextCompactionItem(parsed.item)) {
3706
+ this.emitEvent({
3707
+ type: "timeline",
3708
+ provider: CODEX_PROVIDER,
3709
+ item: this.createContextCompactionTimelineItem("loading", parsed.item.id),
3710
+ });
3711
+ return;
3712
+ }
3435
3713
  const timelineItem = threadItemToTimeline(parsed.item, {
3436
3714
  includeUserMessage: false,
3437
3715
  cwd: this.config.cwd ?? null,
@@ -3711,6 +3989,7 @@ export class CodexAppServerAgentClient {
3711
3989
  this.provider = CODEX_PROVIDER;
3712
3990
  this.capabilities = CODEX_APP_SERVER_CAPABILITIES;
3713
3991
  this.goalsEnabledPromise = null;
3992
+ this.autoReviewEnabledPromise = null;
3714
3993
  }
3715
3994
  sessionDeps() {
3716
3995
  return {
@@ -3740,6 +4019,28 @@ export class CodexAppServerAgentClient {
3740
4019
  }
3741
4020
  return this.goalsEnabledPromise;
3742
4021
  }
4022
+ resolveAutoReviewEnabled() {
4023
+ if (!this.autoReviewEnabledPromise) {
4024
+ this.autoReviewEnabledPromise = (async () => {
4025
+ try {
4026
+ const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings);
4027
+ const versionOutput = await resolveBinaryVersion(launchPrefix.command);
4028
+ const enabled = codexVersionAtLeast(versionOutput, CODEX_AUTO_REVIEW_MIN_VERSION);
4029
+ this.logger.trace({
4030
+ provider: CODEX_PROVIDER,
4031
+ versionOutput,
4032
+ enabled,
4033
+ }, "provider.codex.config.auto_review_resolved");
4034
+ return enabled;
4035
+ }
4036
+ catch (error) {
4037
+ this.logger.warn({ err: error }, "Failed to probe codex version for auto-review gate");
4038
+ return false;
4039
+ }
4040
+ })();
4041
+ }
4042
+ return this.autoReviewEnabledPromise;
4043
+ }
3743
4044
  async spawnAppServer(launchEnv, options) {
3744
4045
  const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings);
3745
4046
  const args = [...launchPrefix.args, "app-server"];
@@ -3771,7 +4072,8 @@ export class CodexAppServerAgentClient {
3771
4072
  }
3772
4073
  const sessionConfig = { ...config, provider: CODEX_PROVIDER };
3773
4074
  const goalsEnabled = await this.resolveGoalsEnabled();
3774
- const session = new CodexAppServerAgentSession(sessionConfig, null, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled, agentId: launchContext?.agentId }), this.sessionDeps(), options?.persistSession === false, goalsEnabled, launchContext?.agentId);
4075
+ const autoReviewEnabled = await this.resolveAutoReviewEnabled();
4076
+ const session = new CodexAppServerAgentSession(sessionConfig, null, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled, agentId: launchContext?.agentId }), this.sessionDeps(), options?.persistSession === false, goalsEnabled, autoReviewEnabled, launchContext?.agentId);
3775
4077
  await session.connect();
3776
4078
  return session;
3777
4079
  }
@@ -3784,7 +4086,8 @@ export class CodexAppServerAgentClient {
3784
4086
  cwd: overrides?.cwd ?? storedConfig.cwd ?? process.cwd(),
3785
4087
  };
3786
4088
  const goalsEnabled = await this.resolveGoalsEnabled();
3787
- const session = new CodexAppServerAgentSession(merged, handle, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled, agentId: launchContext?.agentId }), this.sessionDeps(), false, goalsEnabled, launchContext?.agentId);
4089
+ const autoReviewEnabled = await this.resolveAutoReviewEnabled();
4090
+ const session = new CodexAppServerAgentSession(merged, handle, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled, agentId: launchContext?.agentId }), this.sessionDeps(), false, goalsEnabled, autoReviewEnabled, launchContext?.agentId);
3788
4091
  await session.connect();
3789
4092
  return session;
3790
4093
  }
@@ -3840,7 +4143,7 @@ export class CodexAppServerAgentClient {
3840
4143
  threadId,
3841
4144
  },
3842
4145
  },
3843
- timeline,
4146
+ timeline: timeline.map((entry) => entry.item),
3844
4147
  };
3845
4148
  }));
3846
4149
  return descriptors;