@agentconnect.md/codex-acp 1.10.0-agentconnect.1 → 1.11.0-agentconnect.1
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/README.md +11 -0
- package/dist/index.js +233 -108
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ Use [OpenAI Codex](https://github.com/openai/codex) from [Agent Client Protocol]
|
|
|
10
10
|
|
|
11
11
|
- ChatGPT, API key, and client-provided custom gateway authentication.
|
|
12
12
|
- Model, reasoning effort, fast mode, approval, and sandbox mode configuration.
|
|
13
|
+
- Concrete recommended model and reasoning-effort values through the opt-in [AIR recommended config values](docs/recommended-config-values-extension.md) capability.
|
|
13
14
|
- Text prompts, embedded context, images, resource links, and additional workspace directories.
|
|
14
15
|
- Shell command, file change, [permission request](docs/permission-extension.md), MCP tool call, terminal output, reasoning, plan, web search, image generation, image view, token usage, and review events.
|
|
15
16
|
- [Native ACP subagent sessions](docs/subagent-sessions.md) (after capability negotiation) with separate child histories and root-routed permissions; a legacy tool-call fallback otherwise.
|
|
@@ -40,6 +41,16 @@ The npm package includes a compatible `@openai/codex` dependency. Set `CODEX_PAT
|
|
|
40
41
|
CODEX_PATH=/path/to/codex npx -y @agentclientprotocol/codex-acp
|
|
41
42
|
```
|
|
42
43
|
|
|
44
|
+
To try changes that have landed on `main` but are not released yet, install from the
|
|
45
|
+
`preview` channel. Pushes to `main` trigger preview publishing without waiting
|
|
46
|
+
for CI or release-please; release commits are excluded, and newer pushes can
|
|
47
|
+
replace queued previews. See
|
|
48
|
+
[docs/RELEASES.md](docs/RELEASES.md#preview-releases).
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx -y @agentclientprotocol/codex-acp@preview
|
|
52
|
+
```
|
|
53
|
+
|
|
43
54
|
## Authentication
|
|
44
55
|
|
|
45
56
|
The adapter advertises ACP auth methods during initialization. Clients can authenticate with:
|
package/dist/index.js
CHANGED
|
@@ -23670,16 +23670,37 @@ var AIR_SESSION_FAILURE_KEY = "sessionFailure";
|
|
|
23670
23670
|
var AIR_AGENT_FILE_CHANGE_REPORT_KEY = "agentFileChangeReport";
|
|
23671
23671
|
var AIR_NATIVE_SUBAGENT_SESSIONS_KEY = "nativeSubagentSessions";
|
|
23672
23672
|
var AIR_ASYNC_TASKS_KEY = "asyncTasks";
|
|
23673
|
+
var AIR_RECOMMENDED_CONFIG_VALUE_KEY = "recommendedValue";
|
|
23673
23674
|
var AIR_ASYNC_TASKS_BACKGROUNDED_KEY = "backgrounded";
|
|
23674
23675
|
var AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY = "agentFileChangeReportRequest";
|
|
23675
23676
|
var AIR_EXTENSION_VERSION = 1;
|
|
23677
|
+
function withAirMeta(meta3, key, value) {
|
|
23678
|
+
const root = asRecord(meta3);
|
|
23679
|
+
const jetbrains = asRecord(root[JETBRAINS_META_KEY]);
|
|
23680
|
+
const air = asRecord(jetbrains[AIR_META_KEY]);
|
|
23681
|
+
return {
|
|
23682
|
+
...root,
|
|
23683
|
+
[JETBRAINS_META_KEY]: {
|
|
23684
|
+
...jetbrains,
|
|
23685
|
+
[AIR_META_KEY]: {
|
|
23686
|
+
...air,
|
|
23687
|
+
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
23688
|
+
[key]: value
|
|
23689
|
+
}
|
|
23690
|
+
}
|
|
23691
|
+
};
|
|
23692
|
+
}
|
|
23676
23693
|
function clientSupportsAirCapability(capabilities, capability) {
|
|
23677
|
-
const
|
|
23678
|
-
const
|
|
23679
|
-
const
|
|
23680
|
-
const
|
|
23694
|
+
const meta3 = asRecord(capabilities?._meta);
|
|
23695
|
+
const jetbrains = asRecord(meta3[JETBRAINS_META_KEY]);
|
|
23696
|
+
const air = asRecord(jetbrains[AIR_META_KEY]);
|
|
23697
|
+
const version2 = air[AIR_EXTENSION_VERSION_KEY];
|
|
23698
|
+
const supported = air[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
23681
23699
|
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
23682
23700
|
}
|
|
23701
|
+
function asRecord(value) {
|
|
23702
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
23703
|
+
}
|
|
23683
23704
|
|
|
23684
23705
|
// src/subagents/CodexAgentPath.ts
|
|
23685
23706
|
function normalizeAgentPath(path9) {
|
|
@@ -25641,14 +25662,16 @@ function unique(values) {
|
|
|
25641
25662
|
|
|
25642
25663
|
// src/permissions/CodexApprovalHandler.ts
|
|
25643
25664
|
var CodexApprovalHandler = class {
|
|
25644
|
-
constructor(connection, permissionContext, cancellationSignal) {
|
|
25665
|
+
constructor(connection, permissionContext, cancellationSignal, denyRequests) {
|
|
25645
25666
|
this.connection = connection;
|
|
25646
25667
|
this.permissionContext = permissionContext;
|
|
25647
25668
|
this.cancellationSignal = cancellationSignal;
|
|
25669
|
+
this.denyRequests = denyRequests;
|
|
25648
25670
|
}
|
|
25649
25671
|
connection;
|
|
25650
25672
|
permissionContext;
|
|
25651
25673
|
cancellationSignal;
|
|
25674
|
+
denyRequests;
|
|
25652
25675
|
async handleCommandExecution(params) {
|
|
25653
25676
|
const authoritativeParams = params;
|
|
25654
25677
|
const decisions = commandDecisionOptions(authoritativeParams);
|
|
@@ -25707,6 +25730,7 @@ var CodexApprovalHandler = class {
|
|
|
25707
25730
|
}
|
|
25708
25731
|
}
|
|
25709
25732
|
requestPermission(request) {
|
|
25733
|
+
if (this.denyRequests?.()) return Promise.resolve({ outcome: { outcome: "cancelled" } });
|
|
25710
25734
|
return this.connection.request(
|
|
25711
25735
|
methods.client.session.requestPermission,
|
|
25712
25736
|
request,
|
|
@@ -25966,8 +25990,9 @@ function buildMcpPermissionRequest(sessionId, params, context, nextStandaloneToo
|
|
|
25966
25990
|
toolCallId: nextStandaloneToolCallId(),
|
|
25967
25991
|
kind: context.isToolApproval ? "execute" : "other",
|
|
25968
25992
|
status: "pending",
|
|
25993
|
+
title: context.isToolApproval ? "MCP tool call approval" : "Question from MCP server",
|
|
25969
25994
|
content: [messageContent],
|
|
25970
|
-
rawInput: { serverName: params.serverName, schema: params.requestedSchema }
|
|
25995
|
+
rawInput: { serverName: params.serverName, description: params.message, schema: params.requestedSchema }
|
|
25971
25996
|
},
|
|
25972
25997
|
...context.isToolApproval ? { _meta: { is_mcp_tool_approval: true } } : {},
|
|
25973
25998
|
options
|
|
@@ -25985,8 +26010,9 @@ function buildMcpPermissionRequest(sessionId, params, context, nextStandaloneToo
|
|
|
25985
26010
|
toolCallId: `elicitation-${params.elicitationId}`,
|
|
25986
26011
|
kind: "fetch",
|
|
25987
26012
|
status: "pending",
|
|
26013
|
+
title: "MCP server requests to open a URL",
|
|
25988
26014
|
content: [messageContent],
|
|
25989
|
-
rawInput: { serverName: params.serverName, url: params.url }
|
|
26015
|
+
rawInput: { serverName: params.serverName, description: params.message, url: params.url }
|
|
25990
26016
|
},
|
|
25991
26017
|
options
|
|
25992
26018
|
},
|
|
@@ -26099,31 +26125,20 @@ function userInputResponseValue(content, fieldId) {
|
|
|
26099
26125
|
return value;
|
|
26100
26126
|
}
|
|
26101
26127
|
var CodexElicitationHandler = class {
|
|
26102
|
-
connection
|
|
26103
|
-
|
|
26104
|
-
clientCapabilities;
|
|
26105
|
-
cancellationSignal;
|
|
26106
|
-
// In Rust, the MCP elicitation handler receives ElicitationRequestEvent directly from the MCP
|
|
26107
|
-
// protocol layer, where id is set to "mcp_tool_call_approval_<call_id>" — the call ID is extracted
|
|
26108
|
-
// by stripping that prefix.
|
|
26109
|
-
//
|
|
26110
|
-
// In TypeScript, Codex speaks the app-server JSON-RPC protocol (v2), where
|
|
26111
|
-
// McpServerElicitationRequestParams omits elicitationId for form mode, so the MCP-level ID never
|
|
26112
|
-
// reaches the client.
|
|
26113
|
-
//
|
|
26114
|
-
// Workaround: before requesting approval, Codex emits an item/started notification with an
|
|
26115
|
-
// mcpToolCall item carrying the call id and server name. The shared permission lifecycle stores
|
|
26116
|
-
// (threadId, serverName) → callId so this request can correlate to the rendered tool call item.
|
|
26117
|
-
//
|
|
26118
|
-
// The app-server handler exposes URL elicitationId, while serverRequest/resolved only exposes
|
|
26119
|
-
// threadId here, so accepted URL elicitations are completed at thread scope.
|
|
26120
|
-
pendingUrlElicitations = /* @__PURE__ */ new Map();
|
|
26121
|
-
constructor(connection, permissionContext, clientCapabilities = null, cancellationSignal) {
|
|
26128
|
+
constructor(connection, permissionContext, clientCapabilities = null, cancellationSignal, fullAccessHttpServers) {
|
|
26129
|
+
this.fullAccessHttpServers = fullAccessHttpServers;
|
|
26122
26130
|
this.connection = connection;
|
|
26123
26131
|
this.permissionContext = permissionContext;
|
|
26124
26132
|
this.clientCapabilities = clientCapabilities;
|
|
26125
26133
|
this.cancellationSignal = cancellationSignal;
|
|
26126
26134
|
}
|
|
26135
|
+
fullAccessHttpServers;
|
|
26136
|
+
connection;
|
|
26137
|
+
permissionContext;
|
|
26138
|
+
clientCapabilities;
|
|
26139
|
+
cancellationSignal;
|
|
26140
|
+
// App-server omits form elicitation IDs, so item/started correlates MCP approvals to tool calls.
|
|
26141
|
+
pendingUrlElicitations = /* @__PURE__ */ new Map();
|
|
26127
26142
|
async handleNotification(notification) {
|
|
26128
26143
|
switch (notification.method) {
|
|
26129
26144
|
case "serverRequest/resolved":
|
|
@@ -26136,6 +26151,12 @@ var CodexElicitationHandler = class {
|
|
|
26136
26151
|
async handleElicitation(params) {
|
|
26137
26152
|
try {
|
|
26138
26153
|
const context = this.createMcpElicitationContext(params);
|
|
26154
|
+
const httpServers = this.fullAccessHttpServers?.(params);
|
|
26155
|
+
if (httpServers !== void 0) {
|
|
26156
|
+
const accepted = !this.cancellationSignal?.aborted && params.mode === "form" && context.isToolApproval && context.persistOptions.has("session") && httpServers.has(params.serverName);
|
|
26157
|
+
await this.publishAcceptedMcpToolApproval(params.threadId, context, accepted);
|
|
26158
|
+
return { action: accepted ? "accept" : "cancel", content: accepted ? {} : null, _meta: null };
|
|
26159
|
+
}
|
|
26139
26160
|
if (this.shouldUseAcpElicitation(params)) {
|
|
26140
26161
|
const response2 = await this.connection.request(
|
|
26141
26162
|
methods.client.elicitation.create,
|
|
@@ -26168,11 +26189,29 @@ var CodexElicitationHandler = class {
|
|
|
26168
26189
|
context.isToolApproval,
|
|
26169
26190
|
context.persistOptions
|
|
26170
26191
|
);
|
|
26171
|
-
if (correlatedCallId !== void 0
|
|
26172
|
-
|
|
26173
|
-
|
|
26174
|
-
|
|
26175
|
-
|
|
26192
|
+
if (correlatedCallId !== void 0) {
|
|
26193
|
+
if (result.action === "accept") {
|
|
26194
|
+
await this.connection.notify(methods.client.session.update, {
|
|
26195
|
+
sessionId: params.threadId,
|
|
26196
|
+
update: { sessionUpdate: "tool_call_update", toolCallId: correlatedCallId, status: "in_progress" }
|
|
26197
|
+
});
|
|
26198
|
+
}
|
|
26199
|
+
} else {
|
|
26200
|
+
try {
|
|
26201
|
+
await this.connection.notify(methods.client.session.update, {
|
|
26202
|
+
sessionId: params.threadId,
|
|
26203
|
+
update: {
|
|
26204
|
+
sessionUpdate: "tool_call_update",
|
|
26205
|
+
toolCallId: request.toolCall.toolCallId,
|
|
26206
|
+
status: "completed",
|
|
26207
|
+
title: request.toolCall.title,
|
|
26208
|
+
content: request.toolCall.content,
|
|
26209
|
+
rawOutput: { action: result.action }
|
|
26210
|
+
}
|
|
26211
|
+
});
|
|
26212
|
+
} catch (error51) {
|
|
26213
|
+
logger.error("Failed to finalize standalone MCP elicitation tool call", error51);
|
|
26214
|
+
}
|
|
26176
26215
|
}
|
|
26177
26216
|
return result;
|
|
26178
26217
|
} catch (error51) {
|
|
@@ -26181,6 +26220,9 @@ var CodexElicitationHandler = class {
|
|
|
26181
26220
|
}
|
|
26182
26221
|
}
|
|
26183
26222
|
async handleUserInput(params) {
|
|
26223
|
+
if (this.fullAccessHttpServers?.(params) !== void 0 && params.itemId === `mcp-deps-${params.turnId}` && params.questions.some((question) => question.id === "skill_mcp_dependency_install")) {
|
|
26224
|
+
return { answers: {} };
|
|
26225
|
+
}
|
|
26184
26226
|
if (!clientSupportsFormElicitation(this.clientCapabilities)) {
|
|
26185
26227
|
return { answers: {} };
|
|
26186
26228
|
}
|
|
@@ -27329,7 +27371,7 @@ var package_default = {
|
|
|
27329
27371
|
publishConfig: {
|
|
27330
27372
|
access: "public"
|
|
27331
27373
|
},
|
|
27332
|
-
version: "1.
|
|
27374
|
+
version: "1.11.0-agentconnect.1",
|
|
27333
27375
|
description: "",
|
|
27334
27376
|
main: "dist/index.js",
|
|
27335
27377
|
bin: {
|
|
@@ -27391,7 +27433,7 @@ var package_default = {
|
|
|
27391
27433
|
},
|
|
27392
27434
|
dependencies: {
|
|
27393
27435
|
"@agentclientprotocol/sdk": "^1.4.0",
|
|
27394
|
-
"@openai/codex": "^0.153.
|
|
27436
|
+
"@openai/codex": "^0.153.4",
|
|
27395
27437
|
diff: "^9.0.0",
|
|
27396
27438
|
open: "^11.0.1",
|
|
27397
27439
|
"vscode-jsonrpc": "^9.0.1",
|
|
@@ -27524,9 +27566,9 @@ Working directory: ${JSON.stringify(workspace.cwd)}
|
|
|
27524
27566
|
Additional allowed directories: ${JSON.stringify(workspace.additionalDirectories)}`;
|
|
27525
27567
|
}
|
|
27526
27568
|
function parseAgentFileChangeReportRequest(meta3) {
|
|
27527
|
-
const jetbrains =
|
|
27528
|
-
const air =
|
|
27529
|
-
const request =
|
|
27569
|
+
const jetbrains = asRecord2(meta3?.[JETBRAINS_META_KEY]);
|
|
27570
|
+
const air = asRecord2(jetbrains?.[AIR_META_KEY]);
|
|
27571
|
+
const request = asRecord2(air?.[AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY]);
|
|
27530
27572
|
if (request === null || !hasOnlyKeys(request, ["version", "requestId"]) || request["version"] !== AGENT_FILE_CHANGE_REPORT_VERSION) {
|
|
27531
27573
|
return null;
|
|
27532
27574
|
}
|
|
@@ -27593,7 +27635,7 @@ function parseModelFileChangeReport(turn) {
|
|
|
27593
27635
|
} catch {
|
|
27594
27636
|
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned invalid JSON");
|
|
27595
27637
|
}
|
|
27596
|
-
const report =
|
|
27638
|
+
const report = asRecord2(value);
|
|
27597
27639
|
if (report === null || !hasOnlyKeys(report, ["paths", "complete", "uncertainty"])) {
|
|
27598
27640
|
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned an invalid object");
|
|
27599
27641
|
}
|
|
@@ -27770,7 +27812,7 @@ function isWindowsAbsolutePath2(value) {
|
|
|
27770
27812
|
function isValidPathText(value) {
|
|
27771
27813
|
return value.length > 0 && !/[\u0000-\u001F\u007F-\u009F]/.test(value);
|
|
27772
27814
|
}
|
|
27773
|
-
function
|
|
27815
|
+
function asRecord2(value) {
|
|
27774
27816
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
27775
27817
|
}
|
|
27776
27818
|
function hasOnlyKeys(value, allowed) {
|
|
@@ -27897,12 +27939,10 @@ import { createHash } from "node:crypto";
|
|
|
27897
27939
|
async function forkSession(request, additionalDirectories, dependencies) {
|
|
27898
27940
|
await dependencies.refreshSkills(request.cwd, additionalDirectories);
|
|
27899
27941
|
const lastTurnId = await resolveForkTurnId(request, dependencies.codexClient);
|
|
27942
|
+
const prepared = await dependencies.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []);
|
|
27900
27943
|
const response = await dependencies.codexClient.threadFork({
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
additionalDirectories,
|
|
27904
|
-
request.mcpServers ?? []
|
|
27905
|
-
),
|
|
27944
|
+
excludeTurns: true,
|
|
27945
|
+
config: prepared.config,
|
|
27906
27946
|
cwd: request.cwd,
|
|
27907
27947
|
...lastTurnId !== void 0 && { lastTurnId },
|
|
27908
27948
|
modelProvider: await dependencies.getResumeModelProvider(),
|
|
@@ -27917,16 +27957,14 @@ async function forkSession(request, additionalDirectories, dependencies) {
|
|
|
27917
27957
|
collaborationMode: dependencies.getCollaborationMode(response.thread.id),
|
|
27918
27958
|
modelProvider: response.modelProvider,
|
|
27919
27959
|
currentServiceTier: response.serviceTier ?? null,
|
|
27920
|
-
additionalDirectories
|
|
27960
|
+
additionalDirectories,
|
|
27961
|
+
fullAccessHttpMcpServers: prepared.fullAccessHttpMcpServers
|
|
27921
27962
|
};
|
|
27922
27963
|
}
|
|
27923
27964
|
async function resolveForkTurnId(request, codexClient) {
|
|
27924
27965
|
const forkPoint = readAirForkPoint(request._meta);
|
|
27925
27966
|
if (!forkPoint) return void 0;
|
|
27926
|
-
const history = await codexClient.
|
|
27927
|
-
threadId: request.sessionId,
|
|
27928
|
-
includeTurns: true
|
|
27929
|
-
});
|
|
27967
|
+
const history = await codexClient.threadReadWithHistory(request.sessionId);
|
|
27930
27968
|
const candidateIds = airForkMessageIdCandidates(forkPoint.messageId);
|
|
27931
27969
|
const itemTurnId = candidateIds.map((candidateId) => history.thread.turns.find((turn) => turn.items.some((item) => item.id === candidateId))?.id).find((turnId) => turnId !== void 0);
|
|
27932
27970
|
if (itemTurnId) return itemTurnId;
|
|
@@ -28378,8 +28416,11 @@ var CodexAcpClient = class {
|
|
|
28378
28416
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
28379
28417
|
const initialAgentMode = AgentMode.getInitialAgentMode();
|
|
28380
28418
|
await this.refreshSkills(request.cwd, additionalDirectories);
|
|
28419
|
+
const prepared = await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []);
|
|
28420
|
+
await this.restrictResumedHttpMcpServers(request.sessionId, prepared);
|
|
28381
28421
|
const response = await this.codexClient.threadResume({
|
|
28382
|
-
|
|
28422
|
+
excludeTurns: true,
|
|
28423
|
+
config: prepared.config,
|
|
28383
28424
|
cwd: request.cwd,
|
|
28384
28425
|
modelProvider: await this.getResumeModelProvider(),
|
|
28385
28426
|
threadId: request.sessionId,
|
|
@@ -28395,7 +28436,8 @@ var CodexAcpClient = class {
|
|
|
28395
28436
|
collaborationMode: this.getCollaborationMode(response.thread.id),
|
|
28396
28437
|
modelProvider: response.modelProvider,
|
|
28397
28438
|
currentServiceTier: response.serviceTier ?? null,
|
|
28398
|
-
additionalDirectories
|
|
28439
|
+
additionalDirectories,
|
|
28440
|
+
fullAccessHttpMcpServers: prepared.fullAccessHttpMcpServers
|
|
28399
28441
|
};
|
|
28400
28442
|
}
|
|
28401
28443
|
async forkSession(request) {
|
|
@@ -28414,18 +28456,21 @@ var CodexAcpClient = class {
|
|
|
28414
28456
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
28415
28457
|
const initialAgentMode = AgentMode.getInitialAgentMode();
|
|
28416
28458
|
await this.refreshSkills(request.cwd, additionalDirectories);
|
|
28459
|
+
const prepared = await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []);
|
|
28460
|
+
await this.restrictResumedHttpMcpServers(request.sessionId, prepared);
|
|
28417
28461
|
const response = await this.codexClient.threadResume({
|
|
28418
|
-
|
|
28462
|
+
excludeTurns: true,
|
|
28463
|
+
config: prepared.config,
|
|
28419
28464
|
cwd: request.cwd,
|
|
28420
28465
|
modelProvider: await this.getResumeModelProvider(),
|
|
28421
28466
|
threadId: request.sessionId,
|
|
28422
28467
|
...this.permissionProfileSelection(initialAgentMode, request.cwd, additionalDirectories)
|
|
28423
28468
|
});
|
|
28424
28469
|
onSubscribed?.();
|
|
28425
|
-
const
|
|
28426
|
-
|
|
28427
|
-
|
|
28428
|
-
});
|
|
28470
|
+
const thread = response.thread.historyMode === "paginated" ? {
|
|
28471
|
+
...response.thread,
|
|
28472
|
+
turns: response.turnsBackwardsCursor === null ? [] : await this.codexClient.threadReadHistory(response.thread.id, response.turnsBackwardsCursor)
|
|
28473
|
+
} : (await this.codexClient.threadReadWithHistory(response.thread.id)).thread;
|
|
28429
28474
|
const codexModels = await this.fetchAvailableModels();
|
|
28430
28475
|
const currentModelId = this.createModelId(codexModels, response.model, response.reasoningEffort).toString();
|
|
28431
28476
|
return {
|
|
@@ -28435,22 +28480,21 @@ var CodexAcpClient = class {
|
|
|
28435
28480
|
collaborationMode: this.getCollaborationMode(response.thread.id),
|
|
28436
28481
|
modelProvider: response.modelProvider,
|
|
28437
28482
|
currentServiceTier: response.serviceTier ?? null,
|
|
28438
|
-
thread
|
|
28439
|
-
additionalDirectories
|
|
28483
|
+
thread,
|
|
28484
|
+
additionalDirectories,
|
|
28485
|
+
fullAccessHttpMcpServers: prepared.fullAccessHttpMcpServers
|
|
28440
28486
|
};
|
|
28441
28487
|
}
|
|
28442
28488
|
async readSessionThread(sessionId) {
|
|
28443
|
-
return (await this.codexClient.
|
|
28444
|
-
threadId: sessionId,
|
|
28445
|
-
includeTurns: true
|
|
28446
|
-
})).thread;
|
|
28489
|
+
return (await this.codexClient.threadReadWithHistory(sessionId)).thread;
|
|
28447
28490
|
}
|
|
28448
28491
|
async newSession(request) {
|
|
28449
28492
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
28450
28493
|
const initialAgentMode = AgentMode.getInitialAgentMode();
|
|
28451
28494
|
await this.refreshSkills(request.cwd, additionalDirectories);
|
|
28495
|
+
const prepared = await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers);
|
|
28452
28496
|
const response = await this.codexClient.threadStart({
|
|
28453
|
-
config:
|
|
28497
|
+
config: prepared.config,
|
|
28454
28498
|
modelProvider: this.getModelProvider(),
|
|
28455
28499
|
cwd: request.cwd,
|
|
28456
28500
|
...this.permissionProfileSelection(initialAgentMode, request.cwd, additionalDirectories)
|
|
@@ -28467,7 +28511,8 @@ var CodexAcpClient = class {
|
|
|
28467
28511
|
collaborationMode: this.getCollaborationMode(response.thread.id),
|
|
28468
28512
|
modelProvider: response.modelProvider,
|
|
28469
28513
|
currentServiceTier: response.serviceTier ?? null,
|
|
28470
|
-
additionalDirectories
|
|
28514
|
+
additionalDirectories,
|
|
28515
|
+
fullAccessHttpMcpServers: prepared.fullAccessHttpMcpServers
|
|
28471
28516
|
};
|
|
28472
28517
|
}
|
|
28473
28518
|
async closeSession(sessionId) {
|
|
@@ -28482,11 +28527,23 @@ var CodexAcpClient = class {
|
|
|
28482
28527
|
const config2 = this.permissionProfileConfig;
|
|
28483
28528
|
if (!config2) return {};
|
|
28484
28529
|
return {
|
|
28485
|
-
approvalPolicy: agentMode
|
|
28530
|
+
approvalPolicy: this.approvalPolicyForMode(agentMode),
|
|
28486
28531
|
permissions: permissionProfileForMode(config2, agentMode.id),
|
|
28487
28532
|
runtimeWorkspaceRoots: sessionRoots(cwd, additionalDirectories)
|
|
28488
28533
|
};
|
|
28489
28534
|
}
|
|
28535
|
+
isProtectedFullAccess(agentMode) {
|
|
28536
|
+
return this.permissionProfileConfig !== void 0 && agentMode.kind === "full_access";
|
|
28537
|
+
}
|
|
28538
|
+
approvalPolicyForMode(agentMode) {
|
|
28539
|
+
if (!this.isProtectedFullAccess(agentMode)) return agentMode.approvalPolicy;
|
|
28540
|
+
return { granular: { sandbox_approval: false, rules: false, skill_approval: false, request_permissions: false, mcp_elicitations: false } };
|
|
28541
|
+
}
|
|
28542
|
+
async restrictResumedHttpMcpServers(sessionId, prepared) {
|
|
28543
|
+
if (prepared.fullAccessHttpMcpServers.length === 0) return;
|
|
28544
|
+
const loaded = await this.codexClient.threadLoadedList({});
|
|
28545
|
+
if (loaded.data.includes(sessionId) || loaded.nextCursor !== null) prepared.fullAccessHttpMcpServers = [];
|
|
28546
|
+
}
|
|
28490
28547
|
async deleteSession(sessionId) {
|
|
28491
28548
|
await this.codexClient.threadArchive({ threadId: sessionId });
|
|
28492
28549
|
}
|
|
@@ -28571,23 +28628,25 @@ var CodexAcpClient = class {
|
|
|
28571
28628
|
};
|
|
28572
28629
|
const configWithWorkspaceRoots = mergeSandboxWorkspaceWriteRoots(mergedConfig, additionalDirectories);
|
|
28573
28630
|
if (mcpServers.length === 0) {
|
|
28574
|
-
return configWithWorkspaceRoots;
|
|
28631
|
+
return { config: configWithWorkspaceRoots, fullAccessHttpMcpServers: [] };
|
|
28575
28632
|
}
|
|
28576
28633
|
const requestedServers = mcpServers.map((mcp) => ({
|
|
28577
28634
|
name: sanitizeMcpServerName(mcp.name),
|
|
28578
28635
|
server: mcp
|
|
28579
28636
|
}));
|
|
28580
28637
|
let serversToConfigure = requestedServers;
|
|
28638
|
+
const existingNames = shouldDeduplicateMcpConflicts() || this.permissionProfileConfig ? await this.getConfigMcpServerNames(projectPath) : /* @__PURE__ */ new Set();
|
|
28581
28639
|
if (shouldDeduplicateMcpConflicts()) {
|
|
28582
|
-
const existingNames = await this.getConfigMcpServerNames(projectPath);
|
|
28583
28640
|
serversToConfigure = requestedServers.filter((mcp) => !existingNames.has(mcp.name));
|
|
28584
28641
|
}
|
|
28585
28642
|
if (serversToConfigure.length === 0) {
|
|
28586
|
-
return configWithWorkspaceRoots;
|
|
28643
|
+
return { config: configWithWorkspaceRoots, fullAccessHttpMcpServers: [] };
|
|
28587
28644
|
}
|
|
28645
|
+
const configuredServers = Object.fromEntries(serversToConfigure.map((mcp) => [mcp.name, this.createMcpSeverConfig(mcp.server)]));
|
|
28646
|
+
const inheritedServers = isJsonObject(this.config["mcp_servers"]) ? this.config["mcp_servers"] : {};
|
|
28588
28647
|
return {
|
|
28589
|
-
...configWithWorkspaceRoots,
|
|
28590
|
-
|
|
28648
|
+
config: { ...configWithWorkspaceRoots, mcp_servers: configuredServers },
|
|
28649
|
+
fullAccessHttpMcpServers: this.permissionProfileConfig ? Object.entries(configuredServers).filter(([name, server]) => typeof server["url"] === "string" && !existingNames.has(name) && !Object.hasOwn(inheritedServers, name)).map(([name]) => name) : []
|
|
28591
28650
|
};
|
|
28592
28651
|
}
|
|
28593
28652
|
async getConfigMcpServerNames(projectPath) {
|
|
@@ -28720,7 +28779,7 @@ var CodexAcpClient = class {
|
|
|
28720
28779
|
return await this.codexClient.runTurn({
|
|
28721
28780
|
threadId: request.sessionId,
|
|
28722
28781
|
input,
|
|
28723
|
-
approvalPolicy: agentMode
|
|
28782
|
+
approvalPolicy: this.approvalPolicyForMode(agentMode),
|
|
28724
28783
|
approvalsReviewer: agentMode.approvalsReviewer,
|
|
28725
28784
|
...sandboxSelection,
|
|
28726
28785
|
summary: disableSummary ? "none" : "auto",
|
|
@@ -28740,6 +28799,7 @@ var CodexAcpClient = class {
|
|
|
28740
28799
|
let lateStopReason = null;
|
|
28741
28800
|
try {
|
|
28742
28801
|
const forkPromise = this.codexClient.threadFork({
|
|
28802
|
+
excludeTurns: true,
|
|
28743
28803
|
threadId: params.sessionId,
|
|
28744
28804
|
lastTurnId: params.turnId,
|
|
28745
28805
|
cwd: params.workspace.cwd,
|
|
@@ -28828,7 +28888,7 @@ var CodexAcpClient = class {
|
|
|
28828
28888
|
if (!config2) return;
|
|
28829
28889
|
await this.codexClient.threadSettingsUpdate({
|
|
28830
28890
|
threadId: sessionId,
|
|
28831
|
-
approvalPolicy: agentMode
|
|
28891
|
+
approvalPolicy: this.approvalPolicyForMode(agentMode),
|
|
28832
28892
|
permissions: permissionProfileForMode(config2, agentMode.id)
|
|
28833
28893
|
});
|
|
28834
28894
|
}
|
|
@@ -29586,6 +29646,41 @@ var CodexAppServerClient = class {
|
|
|
29586
29646
|
async threadRead(params) {
|
|
29587
29647
|
return await this.sendRequest({ method: "thread/read", params });
|
|
29588
29648
|
}
|
|
29649
|
+
async threadTurnsList(params) {
|
|
29650
|
+
return await this.sendRequest({ method: "thread/turns/list", params });
|
|
29651
|
+
}
|
|
29652
|
+
async threadReadWithHistory(threadId) {
|
|
29653
|
+
const response = await this.threadRead({ threadId });
|
|
29654
|
+
if (response.thread.historyMode === "legacy") {
|
|
29655
|
+
return await this.threadRead({ threadId, includeTurns: true });
|
|
29656
|
+
}
|
|
29657
|
+
const turns = await this.threadReadHistory(threadId);
|
|
29658
|
+
return { ...response, thread: { ...response.thread, turns } };
|
|
29659
|
+
}
|
|
29660
|
+
async threadReadHistory(threadId, initialCursor = null) {
|
|
29661
|
+
const turns = [];
|
|
29662
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
29663
|
+
if (initialCursor !== null) seenCursors.add(initialCursor);
|
|
29664
|
+
let cursor = initialCursor;
|
|
29665
|
+
do {
|
|
29666
|
+
const page = await this.threadTurnsList({
|
|
29667
|
+
threadId,
|
|
29668
|
+
cursor,
|
|
29669
|
+
limit: 50,
|
|
29670
|
+
sortDirection: "desc",
|
|
29671
|
+
itemsView: "full"
|
|
29672
|
+
});
|
|
29673
|
+
turns.push(...page.data);
|
|
29674
|
+
cursor = page.nextCursor;
|
|
29675
|
+
if (cursor !== null) {
|
|
29676
|
+
if (seenCursors.has(cursor)) {
|
|
29677
|
+
throw new Error("Codex returned a repeated thread history cursor");
|
|
29678
|
+
}
|
|
29679
|
+
seenCursors.add(cursor);
|
|
29680
|
+
}
|
|
29681
|
+
} while (cursor !== null);
|
|
29682
|
+
return turns.reverse();
|
|
29683
|
+
}
|
|
29589
29684
|
async threadArchive(params) {
|
|
29590
29685
|
return await this.sendRequest({ method: "thread/archive", params });
|
|
29591
29686
|
}
|
|
@@ -30024,6 +30119,10 @@ function extractTurnRouting(notification) {
|
|
|
30024
30119
|
// src/ModelConfigOption.ts
|
|
30025
30120
|
var MODEL_CONFIG_ID = "model";
|
|
30026
30121
|
var REASONING_EFFORT_CONFIG_ID = "reasoning_effort";
|
|
30122
|
+
function formatModelDisplayName(displayName) {
|
|
30123
|
+
if (!/^gpt-/i.test(displayName)) return displayName;
|
|
30124
|
+
return displayName.replace(/^gpt-/i, "").split(/[-/]+/).filter(Boolean).map(capitalize).join(" ");
|
|
30125
|
+
}
|
|
30027
30126
|
function capitalize(value) {
|
|
30028
30127
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
30029
30128
|
}
|
|
@@ -30031,19 +30130,20 @@ function findSupportedEffort(options, effort) {
|
|
|
30031
30130
|
if (!effort) return void 0;
|
|
30032
30131
|
return options.find((o) => o.reasoningEffort === effort)?.reasoningEffort;
|
|
30033
30132
|
}
|
|
30034
|
-
function createModelConfigOption(availableModels, currentBaseModelId) {
|
|
30133
|
+
function createModelConfigOption(availableModels, currentBaseModelId, recommendedModelId) {
|
|
30035
30134
|
const options = availableModels.map((model) => ({
|
|
30036
30135
|
value: model.id,
|
|
30037
|
-
name: model.displayName,
|
|
30136
|
+
name: formatModelDisplayName(model.displayName),
|
|
30038
30137
|
description: model.description
|
|
30039
30138
|
}));
|
|
30040
30139
|
if (!availableModels.some((model) => model.id === currentBaseModelId)) {
|
|
30041
30140
|
options.unshift({
|
|
30042
30141
|
value: currentBaseModelId,
|
|
30043
|
-
name: currentBaseModelId,
|
|
30142
|
+
name: formatModelDisplayName(currentBaseModelId),
|
|
30044
30143
|
description: null
|
|
30045
30144
|
});
|
|
30046
30145
|
}
|
|
30146
|
+
const recommendation = recommendedModelId && options.some((option) => option.value === recommendedModelId) ? recommendedModelId : void 0;
|
|
30047
30147
|
return {
|
|
30048
30148
|
id: MODEL_CONFIG_ID,
|
|
30049
30149
|
name: "Model",
|
|
@@ -30051,10 +30151,12 @@ function createModelConfigOption(availableModels, currentBaseModelId) {
|
|
|
30051
30151
|
category: "model",
|
|
30052
30152
|
type: "select",
|
|
30053
30153
|
currentValue: currentBaseModelId,
|
|
30054
|
-
options
|
|
30154
|
+
options,
|
|
30155
|
+
...recommendation ? { _meta: withAirMeta(void 0, AIR_RECOMMENDED_CONFIG_VALUE_KEY, recommendation) } : {}
|
|
30055
30156
|
};
|
|
30056
30157
|
}
|
|
30057
|
-
function createReasoningEffortConfigOption(supportedReasoningEfforts, currentEffort) {
|
|
30158
|
+
function createReasoningEffortConfigOption(supportedReasoningEfforts, currentEffort, recommendedEffort) {
|
|
30159
|
+
const recommendation = findSupportedEffort(supportedReasoningEfforts, recommendedEffort);
|
|
30058
30160
|
return {
|
|
30059
30161
|
id: REASONING_EFFORT_CONFIG_ID,
|
|
30060
30162
|
name: "Reasoning effort",
|
|
@@ -30066,7 +30168,8 @@ function createReasoningEffortConfigOption(supportedReasoningEfforts, currentEff
|
|
|
30066
30168
|
value: option.reasoningEffort,
|
|
30067
30169
|
name: capitalize(option.reasoningEffort),
|
|
30068
30170
|
description: option.description
|
|
30069
|
-
}))
|
|
30171
|
+
})),
|
|
30172
|
+
...recommendation ? { _meta: withAirMeta(void 0, AIR_RECOMMENDED_CONFIG_VALUE_KEY, recommendation) } : {}
|
|
30070
30173
|
};
|
|
30071
30174
|
}
|
|
30072
30175
|
|
|
@@ -30766,14 +30869,14 @@ function parseJsonRecord(line) {
|
|
|
30766
30869
|
}
|
|
30767
30870
|
try {
|
|
30768
30871
|
const value = JSON.parse(line);
|
|
30769
|
-
return
|
|
30872
|
+
return asRecord3(value);
|
|
30770
30873
|
} catch {
|
|
30771
30874
|
return null;
|
|
30772
30875
|
}
|
|
30773
30876
|
}
|
|
30774
30877
|
function extractResponseItem(record2) {
|
|
30775
30878
|
if (record2["type"] === "response_item") {
|
|
30776
|
-
return
|
|
30879
|
+
return asRecord3(record2["payload"]);
|
|
30777
30880
|
}
|
|
30778
30881
|
const itemType = record2["type"];
|
|
30779
30882
|
if (typeof itemType === "string" && isLegacyResponseItemType(itemType)) {
|
|
@@ -30807,7 +30910,7 @@ function createEventMsgUpdates(record2) {
|
|
|
30807
30910
|
if (record2["type"] !== "event_msg") {
|
|
30808
30911
|
return null;
|
|
30809
30912
|
}
|
|
30810
|
-
const payload =
|
|
30913
|
+
const payload = asRecord3(record2["payload"]);
|
|
30811
30914
|
if (!payload) {
|
|
30812
30915
|
return [];
|
|
30813
30916
|
}
|
|
@@ -30851,7 +30954,7 @@ function imageBlocks(images) {
|
|
|
30851
30954
|
if (typeof image === "string") {
|
|
30852
30955
|
return [{ type: "text", text: `[@image](${image})` }];
|
|
30853
30956
|
}
|
|
30854
|
-
const record2 =
|
|
30957
|
+
const record2 = asRecord3(image);
|
|
30855
30958
|
const path9 = record2 ? stringValue(record2["path"]) ?? stringValue(record2["url"]) : null;
|
|
30856
30959
|
return path9 ? [{ type: "text", text: `[@image](${path9})` }] : [];
|
|
30857
30960
|
});
|
|
@@ -30861,7 +30964,7 @@ function contentBlocksFromResponseContent(content) {
|
|
|
30861
30964
|
return [];
|
|
30862
30965
|
}
|
|
30863
30966
|
return content.flatMap((entry) => {
|
|
30864
|
-
const record2 =
|
|
30967
|
+
const record2 = asRecord3(entry);
|
|
30865
30968
|
if (!record2) {
|
|
30866
30969
|
return [];
|
|
30867
30970
|
}
|
|
@@ -30894,7 +30997,7 @@ function textParts(value) {
|
|
|
30894
30997
|
if (typeof entry === "string") {
|
|
30895
30998
|
return entry.length > 0 ? [entry] : [];
|
|
30896
30999
|
}
|
|
30897
|
-
const record2 =
|
|
31000
|
+
const record2 = asRecord3(entry);
|
|
30898
31001
|
if (!record2) {
|
|
30899
31002
|
return [];
|
|
30900
31003
|
}
|
|
@@ -30986,7 +31089,7 @@ function parseFunctionArguments(value) {
|
|
|
30986
31089
|
}
|
|
30987
31090
|
function rawInputForFunctionCall(name, args) {
|
|
30988
31091
|
if (name === "exec_command") {
|
|
30989
|
-
const record2 =
|
|
31092
|
+
const record2 = asRecord3(args);
|
|
30990
31093
|
if (record2) {
|
|
30991
31094
|
return {
|
|
30992
31095
|
command: stringValue(record2["cmd"]) ?? stringValue(record2["command"]),
|
|
@@ -31033,14 +31136,14 @@ function functionCallUsesTerminal(item) {
|
|
|
31033
31136
|
return item["name"] === "exec_command";
|
|
31034
31137
|
}
|
|
31035
31138
|
function commandFromFunctionArguments(args) {
|
|
31036
|
-
const record2 =
|
|
31139
|
+
const record2 = asRecord3(args);
|
|
31037
31140
|
if (!record2) {
|
|
31038
31141
|
return null;
|
|
31039
31142
|
}
|
|
31040
31143
|
return stringValue(record2["cmd"]) ?? stringValue(record2["command"]);
|
|
31041
31144
|
}
|
|
31042
31145
|
function cwdFromFunctionArguments(args) {
|
|
31043
|
-
const record2 =
|
|
31146
|
+
const record2 = asRecord3(args);
|
|
31044
31147
|
if (!record2) {
|
|
31045
31148
|
return "";
|
|
31046
31149
|
}
|
|
@@ -31512,7 +31615,7 @@ function outputText(output) {
|
|
|
31512
31615
|
return "";
|
|
31513
31616
|
}
|
|
31514
31617
|
return output.flatMap((entry) => {
|
|
31515
|
-
const record2 =
|
|
31618
|
+
const record2 = asRecord3(entry);
|
|
31516
31619
|
if (!record2) {
|
|
31517
31620
|
return [];
|
|
31518
31621
|
}
|
|
@@ -31528,7 +31631,7 @@ function outputText(output) {
|
|
|
31528
31631
|
}).join("\n");
|
|
31529
31632
|
}
|
|
31530
31633
|
function parseExitCode(rawOutput, output) {
|
|
31531
|
-
const record2 =
|
|
31634
|
+
const record2 = asRecord3(rawOutput);
|
|
31532
31635
|
if (record2) {
|
|
31533
31636
|
const exitCode2 = numberValue(record2["exit_code"]) ?? numberValue(record2["exitCode"]);
|
|
31534
31637
|
if (exitCode2 !== null) {
|
|
@@ -31559,7 +31662,7 @@ function looksLikeCommandFailure(output) {
|
|
|
31559
31662
|
}
|
|
31560
31663
|
return /(^|\n)(Error|Failed|Command failed|Sandbox error|No such file or directory|Permission denied|Operation not permitted|ENOENT|EACCES)(:|\b)/i.test(trimmed);
|
|
31561
31664
|
}
|
|
31562
|
-
function
|
|
31665
|
+
function asRecord3(value) {
|
|
31563
31666
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
31564
31667
|
return null;
|
|
31565
31668
|
}
|
|
@@ -32209,12 +32312,7 @@ function clientSupportsTypedSessionFailures(capabilities) {
|
|
|
32209
32312
|
function clientSupportsAgentFileChangeReports(capabilities) {
|
|
32210
32313
|
return clientSupportsAirCapability(capabilities, AIR_AGENT_FILE_CHANGE_REPORT_KEY);
|
|
32211
32314
|
}
|
|
32212
|
-
var CodexAcpServer = class
|
|
32213
|
-
static MODEL_NAME_TOKEN_OVERRIDES = {
|
|
32214
|
-
gpt: "GPT",
|
|
32215
|
-
mini: "Mini",
|
|
32216
|
-
codex: "Codex"
|
|
32217
|
-
};
|
|
32315
|
+
var CodexAcpServer = class {
|
|
32218
32316
|
codexAcpClient;
|
|
32219
32317
|
connection;
|
|
32220
32318
|
defaultAuthRequest;
|
|
@@ -32341,7 +32439,8 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
32341
32439
|
AIR_SESSION_FAILURE_KEY,
|
|
32342
32440
|
AIR_AGENT_FILE_CHANGE_REPORT_KEY,
|
|
32343
32441
|
AIR_NATIVE_SUBAGENT_SESSIONS_KEY,
|
|
32344
|
-
AIR_ASYNC_TASKS_KEY
|
|
32442
|
+
AIR_ASYNC_TASKS_KEY,
|
|
32443
|
+
AIR_RECOMMENDED_CONFIG_VALUE_KEY
|
|
32345
32444
|
]
|
|
32346
32445
|
}
|
|
32347
32446
|
}
|
|
@@ -32594,6 +32693,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32594
32693
|
supportedReasoningEfforts: currentModel?.supportedReasoningEfforts ?? [],
|
|
32595
32694
|
supportedInputModalities: currentModel?.inputModalities ?? ["text", "image"],
|
|
32596
32695
|
agentMode: AgentMode.getInitialAgentMode(),
|
|
32696
|
+
fullAccessHttpMcpServers: sessionMetadata.fullAccessHttpMcpServers ?? [],
|
|
32597
32697
|
collaborationMode: sessionMetadata.collaborationMode,
|
|
32598
32698
|
currentTurnId: null,
|
|
32599
32699
|
lastTokenUsage: null,
|
|
@@ -32927,12 +33027,13 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
32927
33027
|
for (const session of this.sessions.values()) {
|
|
32928
33028
|
session.asyncTasks.setAppServer(replacement.appServerClient);
|
|
32929
33029
|
try {
|
|
32930
|
-
await replacement.resumeSession({
|
|
33030
|
+
const metadata = await replacement.resumeSession({
|
|
32931
33031
|
sessionId: session.sessionId,
|
|
32932
33032
|
cwd: session.cwd,
|
|
32933
33033
|
additionalDirectories: session.additionalDirectories,
|
|
32934
33034
|
mcpServers: session.mcpServers ?? []
|
|
32935
33035
|
});
|
|
33036
|
+
session.fullAccessHttpMcpServers = metadata.fullAccessHttpMcpServers ?? [];
|
|
32936
33037
|
session.authProvider = replacement.getModelProvider();
|
|
32937
33038
|
session.asyncTasks.refresh();
|
|
32938
33039
|
logger.log("Resumed session after provider restart", { sessionId: session.sessionId });
|
|
@@ -33220,6 +33321,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33220
33321
|
if (!newMode) {
|
|
33221
33322
|
throw RequestError.invalidParams();
|
|
33222
33323
|
}
|
|
33324
|
+
sessionState.permissionModeRevision = (sessionState.permissionModeRevision ?? 0) + 1;
|
|
33223
33325
|
await this.codexAcpClient.setAgentMode(
|
|
33224
33326
|
sessionState.sessionId,
|
|
33225
33327
|
newMode
|
|
@@ -33511,14 +33613,24 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33511
33613
|
}
|
|
33512
33614
|
createSessionConfigOptions(sessionState) {
|
|
33513
33615
|
const currentModelId = ModelId.fromString(sessionState.currentModelId);
|
|
33616
|
+
const useRecommendedValue = clientSupportsAirCapability(
|
|
33617
|
+
this.clientCapabilities,
|
|
33618
|
+
AIR_RECOMMENDED_CONFIG_VALUE_KEY
|
|
33619
|
+
);
|
|
33620
|
+
const currentModel = this.findCurrentModel(sessionState.availableModels, sessionState.currentModelId);
|
|
33621
|
+
const recommendedModelId = useRecommendedValue ? sessionState.availableModels.find((model) => model.isDefault)?.id : void 0;
|
|
33514
33622
|
const configOptions = [
|
|
33515
33623
|
sessionState.agentMode.toConfigOption(),
|
|
33516
33624
|
createCollaborationModeConfigOption(sessionState.collaborationMode),
|
|
33517
|
-
createModelConfigOption(sessionState.availableModels, currentModelId.model)
|
|
33625
|
+
createModelConfigOption(sessionState.availableModels, currentModelId.model, recommendedModelId)
|
|
33518
33626
|
];
|
|
33519
33627
|
if (sessionState.supportedReasoningEfforts.length > 0) {
|
|
33520
33628
|
configOptions.push(
|
|
33521
|
-
createReasoningEffortConfigOption(
|
|
33629
|
+
createReasoningEffortConfigOption(
|
|
33630
|
+
sessionState.supportedReasoningEfforts,
|
|
33631
|
+
currentModelId.effort,
|
|
33632
|
+
useRecommendedValue ? currentModel?.defaultReasoningEffort : void 0
|
|
33633
|
+
)
|
|
33522
33634
|
);
|
|
33523
33635
|
}
|
|
33524
33636
|
if (sessionState.currentModelSupportsFast) {
|
|
@@ -33595,14 +33707,11 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33595
33707
|
const modelId = ModelId.fromString(currentModelId);
|
|
33596
33708
|
return models.find((m) => m.id === modelId.model);
|
|
33597
33709
|
}
|
|
33598
|
-
normalizeModelDisplayName(displayName) {
|
|
33599
|
-
return displayName.split("-").map((token) => _CodexAcpServer.MODEL_NAME_TOKEN_OVERRIDES[token.toLowerCase()] ?? token).join("-");
|
|
33600
|
-
}
|
|
33601
33710
|
createModelState(availableModels, selectedModelId) {
|
|
33602
33711
|
const allowedModels = availableModels.flatMap(
|
|
33603
33712
|
(model) => model.supportedReasoningEfforts.map((effort) => ({
|
|
33604
33713
|
modelId: ModelId.fromComponents(model, effort.reasoningEffort).toString(),
|
|
33605
|
-
name: `${
|
|
33714
|
+
name: `${formatModelDisplayName(model.displayName)} (${effort.reasoningEffort})`,
|
|
33606
33715
|
description: `${model.description} ${effort.description}`
|
|
33607
33716
|
}))
|
|
33608
33717
|
);
|
|
@@ -33656,6 +33765,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33656
33765
|
supportedReasoningEfforts: currentModel?.supportedReasoningEfforts ?? [],
|
|
33657
33766
|
supportedInputModalities: currentModel?.inputModalities ?? ["text", "image"],
|
|
33658
33767
|
agentMode: AgentMode.getInitialAgentMode(),
|
|
33768
|
+
fullAccessHttpMcpServers: sessionMetadata.fullAccessHttpMcpServers ?? [],
|
|
33659
33769
|
collaborationMode: sessionMetadata.collaborationMode,
|
|
33660
33770
|
currentTurnId: null,
|
|
33661
33771
|
lastTokenUsage: null,
|
|
@@ -34400,16 +34510,27 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34400
34510
|
eventHandler = promptEventHandler;
|
|
34401
34511
|
const permissionLifecycle = this.permissionLifecycleContext(sessionState);
|
|
34402
34512
|
const permissionContext = permissionLifecycle.beginPrompt();
|
|
34513
|
+
let promptAgentMode;
|
|
34514
|
+
let permissionModeRevision;
|
|
34515
|
+
const httpServers = new Set(sessionState.fullAccessHttpMcpServers);
|
|
34516
|
+
const noHttpServers = /* @__PURE__ */ new Set();
|
|
34517
|
+
let mcpApprovalTurnId = null;
|
|
34518
|
+
const isProtectedFullAccess = () => this.codexAcpClient.isProtectedFullAccess(promptAgentMode ?? sessionState.agentMode);
|
|
34403
34519
|
const approvalHandler = new CodexApprovalHandler(
|
|
34404
34520
|
this.connection,
|
|
34405
34521
|
permissionContext,
|
|
34406
|
-
activePrompt.signal
|
|
34522
|
+
activePrompt.signal,
|
|
34523
|
+
isProtectedFullAccess
|
|
34407
34524
|
);
|
|
34408
34525
|
const elicitationHandler = new CodexElicitationHandler(
|
|
34409
34526
|
this.connection,
|
|
34410
34527
|
permissionContext,
|
|
34411
34528
|
this.clientCapabilities,
|
|
34412
|
-
activePrompt.signal
|
|
34529
|
+
activePrompt.signal,
|
|
34530
|
+
(request) => {
|
|
34531
|
+
if (!isProtectedFullAccess()) return void 0;
|
|
34532
|
+
return mcpApprovalTurnId !== null && request.turnId === mcpApprovalTurnId && sessionState.agentMode.kind === "full_access" && sessionState.permissionModeRevision === permissionModeRevision ? httpServers : noHttpServers;
|
|
34533
|
+
}
|
|
34413
34534
|
);
|
|
34414
34535
|
const observeInteraction = async (event) => {
|
|
34415
34536
|
permissionContext.handleNotification(event);
|
|
@@ -34534,6 +34655,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34534
34655
|
throw RequestError.invalidRequest("The current model does not support image input");
|
|
34535
34656
|
}
|
|
34536
34657
|
const agentMode = sessionState.agentMode;
|
|
34658
|
+
promptAgentMode = agentMode;
|
|
34659
|
+
permissionModeRevision = sessionState.permissionModeRevision;
|
|
34537
34660
|
const serviceTier = resolveFastServiceTier(
|
|
34538
34661
|
sessionState.fastModeEnabled,
|
|
34539
34662
|
sessionState.currentModelSupportsFast
|
|
@@ -34550,6 +34673,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34550
34673
|
sessionState.cwd,
|
|
34551
34674
|
sessionState.additionalDirectories,
|
|
34552
34675
|
(turnId) => {
|
|
34676
|
+
mcpApprovalTurnId = turnId;
|
|
34553
34677
|
const turn = { threadId: params.sessionId, turnId };
|
|
34554
34678
|
activePrompt.currentTurn = turn;
|
|
34555
34679
|
if (this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
@@ -34560,7 +34684,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34560
34684
|
pendingTurnStart?.resolve(turnId);
|
|
34561
34685
|
onTurnStarted?.();
|
|
34562
34686
|
},
|
|
34563
|
-
() => this.promptShouldStop(params.sessionId, activePrompt)
|
|
34687
|
+
() => this.promptShouldStop(params.sessionId, activePrompt) || sessionState.permissionModeRevision !== permissionModeRevision
|
|
34564
34688
|
)
|
|
34565
34689
|
);
|
|
34566
34690
|
void sendPromptPromise.catch((err) => {
|
|
@@ -34640,6 +34764,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34640
34764
|
sessionState.cwd,
|
|
34641
34765
|
sessionState.additionalDirectories,
|
|
34642
34766
|
(turnId) => {
|
|
34767
|
+
mcpApprovalTurnId = turnId;
|
|
34643
34768
|
const turn = { threadId: params.sessionId, turnId };
|
|
34644
34769
|
activePrompt.currentTurn = turn;
|
|
34645
34770
|
if (this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
@@ -34650,7 +34775,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34650
34775
|
recoverableSessionFailure = sessionState.sessionFailure;
|
|
34651
34776
|
promptNotificationsActive = true;
|
|
34652
34777
|
},
|
|
34653
|
-
() => this.promptShouldStop(params.sessionId, activePrompt)
|
|
34778
|
+
() => this.promptShouldStop(params.sessionId, activePrompt) || sessionState.permissionModeRevision !== permissionModeRevision
|
|
34654
34779
|
)
|
|
34655
34780
|
);
|
|
34656
34781
|
void implementationPromise.catch((err) => {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.11.0-agentconnect.1",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"bin": {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@agentclientprotocol/sdk": "^1.4.0",
|
|
68
|
-
"@openai/codex": "^0.153.
|
|
68
|
+
"@openai/codex": "^0.153.4",
|
|
69
69
|
"diff": "^9.0.0",
|
|
70
70
|
"open": "^11.0.1",
|
|
71
71
|
"vscode-jsonrpc": "^9.0.1",
|