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