@nyssance/codex-acp-v2 0.7.1 → 0.7.3
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/CHANGELOG.md +17 -0
- package/dist/index.js +2234 -2207
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21844,7 +21844,7 @@ var package_default = {
|
|
|
21844
21844
|
publishConfig: {
|
|
21845
21845
|
access: "public"
|
|
21846
21846
|
},
|
|
21847
|
-
version: "0.7.
|
|
21847
|
+
version: "0.7.3",
|
|
21848
21848
|
description: "Native ACP v2 agent for the OpenAI Codex app-server",
|
|
21849
21849
|
packageManager: "bun@1.4.0",
|
|
21850
21850
|
engines: {
|
|
@@ -24204,138 +24204,10 @@ function withWritableRoots(policy, roots) {
|
|
|
24204
24204
|
return { ...policy, writableRoots: [...new Set([...policy.writableRoots, ...roots])] };
|
|
24205
24205
|
}
|
|
24206
24206
|
|
|
24207
|
-
// src/
|
|
24208
|
-
|
|
24209
|
-
|
|
24210
|
-
|
|
24211
|
-
var COLLABORATION_MODE_CONFIG_ID = "collaboration_mode";
|
|
24212
|
-
var DEFAULT_EFFORT = "medium";
|
|
24213
|
-
var FAST_SERVICE_TIER = "fast";
|
|
24214
|
-
function resolveModelSelection(catalog, modelId, effort) {
|
|
24215
|
-
const listed = modelId === null ? undefined : catalog.find((model) => model.id === modelId);
|
|
24216
|
-
if (listed)
|
|
24217
|
-
return { model: listed.id, effort: effort ?? listed.defaultReasoningEffort };
|
|
24218
|
-
if (modelId)
|
|
24219
|
-
return { model: modelId, effort: effort ?? DEFAULT_EFFORT };
|
|
24220
|
-
const fallback = catalog.find((model) => model.isDefault) ?? catalog[0];
|
|
24221
|
-
if (!fallback)
|
|
24222
|
-
throw new Error("Codex did not return any models");
|
|
24223
|
-
return { model: fallback.id, effort: effort ?? fallback.defaultReasoningEffort };
|
|
24224
|
-
}
|
|
24225
|
-
function findModel(catalog, modelId) {
|
|
24226
|
-
return catalog.find((model) => model.id === modelId);
|
|
24227
|
-
}
|
|
24228
|
-
function supportedEfforts(model) {
|
|
24229
|
-
return model?.supportedReasoningEfforts ?? [];
|
|
24230
|
-
}
|
|
24231
|
-
function coerceEffort(model, effort) {
|
|
24232
|
-
const options = supportedEfforts(model);
|
|
24233
|
-
if (options.length === 0)
|
|
24234
|
-
return effort;
|
|
24235
|
-
if (options.some((option) => option.reasoningEffort === effort))
|
|
24236
|
-
return effort;
|
|
24237
|
-
return model?.defaultReasoningEffort ?? options[0].reasoningEffort;
|
|
24238
|
-
}
|
|
24239
|
-
function modelSupportsFast(model) {
|
|
24240
|
-
if (!model)
|
|
24241
|
-
return false;
|
|
24242
|
-
return model.serviceTiers.some((tier) => tier.id === FAST_SERVICE_TIER) || model.additionalSpeedTiers.includes(FAST_SERVICE_TIER);
|
|
24243
|
-
}
|
|
24244
|
-
function modelSupportsImages(model) {
|
|
24245
|
-
return model?.inputModalities.includes("image") ?? true;
|
|
24246
|
-
}
|
|
24247
|
-
function modelLacksReasoning(model) {
|
|
24248
|
-
const options = supportedEfforts(model);
|
|
24249
|
-
return options.length > 0 && options.every((option) => option.reasoningEffort === "none");
|
|
24250
|
-
}
|
|
24251
|
-
function modelConfigOption(catalog, current, gatewayGroups = []) {
|
|
24252
|
-
const visible = catalog.filter((model) => !model.hidden || model.id === current);
|
|
24253
|
-
const options = visible.map((model) => ({
|
|
24254
|
-
value: model.id,
|
|
24255
|
-
name: model.displayName,
|
|
24256
|
-
description: model.description || null
|
|
24257
|
-
}));
|
|
24258
|
-
if (!options.some((option) => option.value === current)) {
|
|
24259
|
-
options.unshift({ value: current, name: current, description: null });
|
|
24260
|
-
}
|
|
24261
|
-
const base = {
|
|
24262
|
-
configId: MODEL_CONFIG_ID,
|
|
24263
|
-
name: "Model",
|
|
24264
|
-
description: "Model Codex uses for this session",
|
|
24265
|
-
category: "model",
|
|
24266
|
-
type: "select",
|
|
24267
|
-
currentValue: current
|
|
24268
|
-
};
|
|
24269
|
-
if (gatewayGroups.length === 0)
|
|
24270
|
-
return { ...base, options };
|
|
24271
|
-
const owner = new Map;
|
|
24272
|
-
for (const group of gatewayGroups)
|
|
24273
|
-
for (const id of group.modelIds)
|
|
24274
|
-
owner.set(id, group.id);
|
|
24275
|
-
const native = options.filter((option) => !owner.has(option.value));
|
|
24276
|
-
return {
|
|
24277
|
-
...base,
|
|
24278
|
-
options: [
|
|
24279
|
-
{ groupId: "codex", name: "Codex", options: native },
|
|
24280
|
-
...gatewayGroups.map((group) => ({ groupId: group.id, name: group.name, options: options.filter((option) => owner.get(option.value) === group.id) }))
|
|
24281
|
-
]
|
|
24282
|
-
};
|
|
24283
|
-
}
|
|
24284
|
-
function effortConfigOption(efforts, current) {
|
|
24285
|
-
const options = efforts.map((option) => ({
|
|
24286
|
-
value: option.reasoningEffort,
|
|
24287
|
-
name: capitalize(option.reasoningEffort),
|
|
24288
|
-
description: option.description || null
|
|
24289
|
-
}));
|
|
24290
|
-
if (!options.some((option) => option.value === current)) {
|
|
24291
|
-
options.unshift({ value: current, name: capitalize(current), description: null });
|
|
24292
|
-
}
|
|
24293
|
-
return {
|
|
24294
|
-
configId: EFFORT_CONFIG_ID,
|
|
24295
|
-
name: "Reasoning effort",
|
|
24296
|
-
description: "How much reasoning effort the model should use",
|
|
24297
|
-
category: "thought_level",
|
|
24298
|
-
type: "select",
|
|
24299
|
-
currentValue: current,
|
|
24300
|
-
options
|
|
24301
|
-
};
|
|
24302
|
-
}
|
|
24303
|
-
function fastModeConfigOption(enabled) {
|
|
24304
|
-
return {
|
|
24305
|
-
configId: FAST_MODE_CONFIG_ID,
|
|
24306
|
-
name: "Fast mode",
|
|
24307
|
-
description: "1.5x speed, increased usage",
|
|
24308
|
-
category: "model_config",
|
|
24309
|
-
type: "boolean",
|
|
24310
|
-
currentValue: enabled
|
|
24311
|
-
};
|
|
24312
|
-
}
|
|
24313
|
-
var DEFAULT_COLLABORATION_MODE = "default";
|
|
24314
|
-
var PLAN_COLLABORATION_MODE = "plan";
|
|
24315
|
-
function collaborationModeConfigOption(current) {
|
|
24316
|
-
return {
|
|
24317
|
-
configId: COLLABORATION_MODE_CONFIG_ID,
|
|
24318
|
-
name: "Collaboration mode",
|
|
24319
|
-
description: "How Codex collaborates on subsequent turns",
|
|
24320
|
-
category: "model_config",
|
|
24321
|
-
type: "select",
|
|
24322
|
-
currentValue: current,
|
|
24323
|
-
options: [
|
|
24324
|
-
{ value: DEFAULT_COLLABORATION_MODE, name: "Default", description: "Make changes directly" },
|
|
24325
|
-
{ value: PLAN_COLLABORATION_MODE, name: "Plan", description: "Plan before making changes" }
|
|
24326
|
-
]
|
|
24327
|
-
};
|
|
24328
|
-
}
|
|
24329
|
-
function parseCollaborationMode(value) {
|
|
24330
|
-
if (value === DEFAULT_COLLABORATION_MODE)
|
|
24331
|
-
return DEFAULT_COLLABORATION_MODE;
|
|
24332
|
-
if (value === PLAN_COLLABORATION_MODE)
|
|
24333
|
-
return PLAN_COLLABORATION_MODE;
|
|
24334
|
-
return;
|
|
24335
|
-
}
|
|
24336
|
-
function capitalize(value) {
|
|
24337
|
-
return value.length === 0 ? value : value[0].toUpperCase() + value.slice(1);
|
|
24338
|
-
}
|
|
24207
|
+
// src/agent/providers.ts
|
|
24208
|
+
import { readFileSync } from "fs";
|
|
24209
|
+
import os from "os";
|
|
24210
|
+
import path4 from "path";
|
|
24339
24211
|
|
|
24340
24212
|
// src/permissions/json.ts
|
|
24341
24213
|
function isRecord2(value) {
|
|
@@ -24362,2278 +24234,2424 @@ function normalizeJsonObject(value) {
|
|
|
24362
24234
|
return Object.fromEntries(Object.entries(value).filter(([, nested]) => nested !== undefined).map(([key, nested]) => [key, normalizeJsonValue(nested)]));
|
|
24363
24235
|
}
|
|
24364
24236
|
|
|
24365
|
-
// src/
|
|
24366
|
-
|
|
24367
|
-
|
|
24368
|
-
|
|
24369
|
-
|
|
24370
|
-
|
|
24371
|
-
|
|
24372
|
-
|
|
24373
|
-
|
|
24374
|
-
const decision = parseDecision(candidate, params);
|
|
24375
|
-
if (!decision)
|
|
24376
|
-
return;
|
|
24377
|
-
decisions.push(decision);
|
|
24378
|
-
}
|
|
24379
|
-
return decisions;
|
|
24237
|
+
// src/agent/providers.ts
|
|
24238
|
+
var OPENAI_PROVIDER_ID = "openai";
|
|
24239
|
+
var GATEWAY_MODEL_PROVIDER = "custom-gateway";
|
|
24240
|
+
var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
24241
|
+
var NATIVE_GROUP_ID = "chatgpt";
|
|
24242
|
+
var NATIVE_GROUP_NAME = "ChatGPT";
|
|
24243
|
+
var GATEWAY_ID_PATTERN = /^[a-z0-9-]+$/;
|
|
24244
|
+
function gatewayModelId(connectionId, modelId) {
|
|
24245
|
+
return `gateway:${encodeURIComponent(connectionId)}:${encodeURIComponent(modelId)}`;
|
|
24380
24246
|
}
|
|
24381
|
-
|
|
24382
|
-
|
|
24383
|
-
|
|
24384
|
-
|
|
24385
|
-
|
|
24386
|
-
|
|
24387
|
-
|
|
24388
|
-
|
|
24389
|
-
}
|
|
24390
|
-
if (params.additionalPermissions)
|
|
24391
|
-
return ["accept", "cancel"];
|
|
24392
|
-
const decisions = ["accept", "acceptForSession"];
|
|
24393
|
-
if (params.proposedExecpolicyAmendment && params.proposedExecpolicyAmendment.length > 0) {
|
|
24394
|
-
decisions.push({ acceptWithExecpolicyAmendment: { execpolicy_amendment: params.proposedExecpolicyAmendment } });
|
|
24247
|
+
|
|
24248
|
+
class ProviderRouting {
|
|
24249
|
+
baseConfig;
|
|
24250
|
+
configuredProvider;
|
|
24251
|
+
gateways = new Map;
|
|
24252
|
+
constructor(baseConfig, configuredProvider) {
|
|
24253
|
+
this.baseConfig = baseConfig;
|
|
24254
|
+
this.configuredProvider = configuredProvider;
|
|
24395
24255
|
}
|
|
24396
|
-
|
|
24397
|
-
|
|
24398
|
-
|
|
24399
|
-
|
|
24400
|
-
if (candidate === "accept" || candidate === "acceptForSession" || candidate === "decline" || candidate === "cancel") {
|
|
24401
|
-
return candidate;
|
|
24256
|
+
copy() {
|
|
24257
|
+
const copy = new ProviderRouting(this.baseConfig, this.configuredProvider);
|
|
24258
|
+
copy.gateways = new Map(this.gateways);
|
|
24259
|
+
return copy;
|
|
24402
24260
|
}
|
|
24403
|
-
|
|
24404
|
-
return;
|
|
24405
|
-
if ("acceptWithExecpolicyAmendment" in candidate) {
|
|
24406
|
-
const value = candidate["acceptWithExecpolicyAmendment"];
|
|
24407
|
-
if (!isRecord2(value))
|
|
24408
|
-
return;
|
|
24409
|
-
const amendment = value["execpolicy_amendment"];
|
|
24410
|
-
if (!isStringArray(amendment) || amendment.length === 0)
|
|
24411
|
-
return;
|
|
24412
|
-
if (!sameStrings(amendment, params.proposedExecpolicyAmendment))
|
|
24413
|
-
return;
|
|
24414
|
-
return { acceptWithExecpolicyAmendment: { execpolicy_amendment: [...amendment] } };
|
|
24261
|
+
get active() {
|
|
24262
|
+
return this.gateways.values().next().value ?? null;
|
|
24415
24263
|
}
|
|
24416
|
-
|
|
24417
|
-
|
|
24418
|
-
if (!isRecord2(value))
|
|
24419
|
-
return;
|
|
24420
|
-
const amendment = parseNetworkAmendment(value["network_policy_amendment"]);
|
|
24421
|
-
if (!amendment || !params.networkApprovalContext)
|
|
24422
|
-
return;
|
|
24423
|
-
if (amendment.host !== params.networkApprovalContext.host)
|
|
24424
|
-
return;
|
|
24425
|
-
const proposed = params.proposedNetworkPolicyAmendments ?? [];
|
|
24426
|
-
if (!proposed.some((entry) => entry.host === amendment.host && entry.action === amendment.action))
|
|
24427
|
-
return;
|
|
24428
|
-
return { applyNetworkPolicyAmendment: { network_policy_amendment: amendment } };
|
|
24264
|
+
gateway(id) {
|
|
24265
|
+
return id === null ? null : this.gateways.get(id) ?? null;
|
|
24429
24266
|
}
|
|
24430
|
-
|
|
24431
|
-
|
|
24432
|
-
function parseNetworkAmendment(value) {
|
|
24433
|
-
if (!isRecord2(value) || typeof value["host"] !== "string")
|
|
24434
|
-
return;
|
|
24435
|
-
const action = value["action"];
|
|
24436
|
-
if (action !== "allow" && action !== "deny")
|
|
24437
|
-
return;
|
|
24438
|
-
return { host: value["host"], action };
|
|
24439
|
-
}
|
|
24440
|
-
function isStringArray(value) {
|
|
24441
|
-
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
24442
|
-
}
|
|
24443
|
-
function sameStrings(left, right) {
|
|
24444
|
-
return !!right && left.length === right.length && left.every((value, index) => value === right[index]);
|
|
24445
|
-
}
|
|
24446
|
-
function renderExecPolicyPrefix(command) {
|
|
24447
|
-
const script = extractWrappedScript(command);
|
|
24448
|
-
if (script !== undefined)
|
|
24449
|
-
return script;
|
|
24450
|
-
if (command.some((value) => value.includes("\x00")))
|
|
24451
|
-
return command.join(" ");
|
|
24452
|
-
return command.map(shlexQuote).join(" ");
|
|
24453
|
-
}
|
|
24454
|
-
function extractWrappedScript(command) {
|
|
24455
|
-
const executable = executableName(command[0]);
|
|
24456
|
-
if ((executable === "bash" || executable === "zsh" || executable === "sh") && command.length === 3 && (command[1] === "-lc" || command[1] === "-c")) {
|
|
24457
|
-
return command[2];
|
|
24267
|
+
hasGateway(id) {
|
|
24268
|
+
return id !== null && this.gateways.has(id);
|
|
24458
24269
|
}
|
|
24459
|
-
|
|
24460
|
-
|
|
24461
|
-
|
|
24462
|
-
|
|
24463
|
-
|
|
24464
|
-
|
|
24465
|
-
|
|
24466
|
-
|
|
24467
|
-
|
|
24270
|
+
list() {
|
|
24271
|
+
const first = this.active;
|
|
24272
|
+
const routed = first !== null && first.mode === "route";
|
|
24273
|
+
const summary = (gateway) => ({ id: gateway.id, name: gateway.name, baseUrl: gateway.baseUrl, models: gateway.models.map((model) => model.id) });
|
|
24274
|
+
return {
|
|
24275
|
+
providers: [{
|
|
24276
|
+
providerId: OPENAI_PROVIDER_ID,
|
|
24277
|
+
supported: ["openai"],
|
|
24278
|
+
required: false,
|
|
24279
|
+
current: routed && first ? { apiType: "openai", baseUrl: first.baseUrl } : { apiType: "openai", baseUrl: this.nativeBaseUrl() },
|
|
24280
|
+
...first && !routed ? { _meta: { codex: { mode: "catalog", gateway: summary(first), gateways: [...this.gateways.values()].map(summary) } } } : {}
|
|
24281
|
+
}]
|
|
24282
|
+
};
|
|
24468
24283
|
}
|
|
24469
|
-
|
|
24470
|
-
|
|
24471
|
-
|
|
24472
|
-
|
|
24473
|
-
|
|
24474
|
-
|
|
24475
|
-
|
|
24476
|
-
const
|
|
24477
|
-
if (
|
|
24478
|
-
|
|
24479
|
-
|
|
24284
|
+
set(request) {
|
|
24285
|
+
if (request.providerId !== OPENAI_PROVIDER_ID) {
|
|
24286
|
+
throw RequestError.invalidParams({ providerId: request.providerId }, `Unknown providerId "${request.providerId}"; only "${OPENAI_PROVIDER_ID}" is configurable`);
|
|
24287
|
+
}
|
|
24288
|
+
if (request.apiType !== "openai") {
|
|
24289
|
+
throw RequestError.invalidParams({ apiType: request.apiType }, `Codex only speaks the OpenAI protocol; got apiType "${request.apiType}"`);
|
|
24290
|
+
}
|
|
24291
|
+
const baseUrl = typeof request.baseUrl === "string" ? request.baseUrl.trim() : "";
|
|
24292
|
+
if (!/^https?:\/\//.test(baseUrl)) {
|
|
24293
|
+
throw RequestError.invalidParams({ baseUrl: request.baseUrl }, "baseUrl must be an http(s) URL");
|
|
24294
|
+
}
|
|
24295
|
+
const hints = readHints(request._meta);
|
|
24296
|
+
if (hints.id === OPENAI_PROVIDER_ID || hints.id === this.configuredProvider) {
|
|
24297
|
+
throw RequestError.invalidParams({ id: hints.id }, `_meta.codex.id "${hints.id}" is Codex's own provider; pick another gateway id`);
|
|
24298
|
+
}
|
|
24299
|
+
if (hints.mode === "route" || this.mode !== hints.mode)
|
|
24300
|
+
this.gateways.clear();
|
|
24301
|
+
this.gateways.set(hints.id, {
|
|
24302
|
+
id: hints.id,
|
|
24303
|
+
baseUrl,
|
|
24304
|
+
headers: { ...request.headers ?? {} },
|
|
24305
|
+
name: hints.name ?? "Client-configured gateway",
|
|
24306
|
+
models: hints.models,
|
|
24307
|
+
model: hints.model,
|
|
24308
|
+
bearerToken: hints.bearerToken,
|
|
24309
|
+
config: hints.config,
|
|
24310
|
+
mode: hints.mode,
|
|
24311
|
+
catalogEntries: hints.catalogEntries
|
|
24312
|
+
});
|
|
24480
24313
|
}
|
|
24481
|
-
|
|
24482
|
-
|
|
24483
|
-
|
|
24484
|
-
|
|
24485
|
-
|
|
24486
|
-
|
|
24487
|
-
|
|
24488
|
-
if (!value.includes("'"))
|
|
24489
|
-
return `'${value}'`;
|
|
24490
|
-
return `"${value.replace(/["\\$`!]/g, "\\$&")}"`;
|
|
24491
|
-
}
|
|
24492
|
-
|
|
24493
|
-
// src/permissions/options.ts
|
|
24494
|
-
var OptionId = {
|
|
24495
|
-
AllowOnce: "allow_once",
|
|
24496
|
-
AllowForSession: "allow_for_session",
|
|
24497
|
-
Decline: "decline",
|
|
24498
|
-
Cancel: "cancel",
|
|
24499
|
-
AcceptWithExecpolicyAmendment: "accept_execpolicy_amendment",
|
|
24500
|
-
ApplyNetworkPolicyAmendment: "apply_network_policy_amendment",
|
|
24501
|
-
AllowPermissionsForTurn: "allow_permissions_turn",
|
|
24502
|
-
AllowPermissionsForTurnStrict: "allow_permissions_turn_strict_auto_review",
|
|
24503
|
-
AllowPermissionsForSession: "allow_permissions_session",
|
|
24504
|
-
RejectPermissions: "reject_permissions"
|
|
24505
|
-
};
|
|
24506
|
-
function commandDecisionOptions(params) {
|
|
24507
|
-
const decisions = availableCommandDecisions(params);
|
|
24508
|
-
if (!decisions)
|
|
24509
|
-
return;
|
|
24510
|
-
const options = [];
|
|
24511
|
-
let networkIndex = 0;
|
|
24512
|
-
for (const decision of decisions) {
|
|
24513
|
-
if (decision === "accept") {
|
|
24514
|
-
options.push(decisionOption(OptionId.AllowOnce, params.networkApprovalContext ? "Yes, just this once" : "Yes, proceed", "allow_once", decision));
|
|
24515
|
-
} else if (decision === "acceptForSession") {
|
|
24516
|
-
const name = params.networkApprovalContext ? "Yes, and allow this host for this conversation" : params.additionalPermissions ? "Yes, and allow these permissions for this session" : "Yes, and don't ask again for this command in this session";
|
|
24517
|
-
options.push(decisionOption(OptionId.AllowForSession, name, "allow_always", decision));
|
|
24518
|
-
} else if (decision === "decline") {
|
|
24519
|
-
options.push(decisionOption(OptionId.Decline, "No, continue without running it", "reject_once", decision));
|
|
24520
|
-
} else if (decision === "cancel") {
|
|
24521
|
-
options.push(decisionOption(OptionId.Cancel, "No, and tell Codex what to do differently", "reject_once", decision));
|
|
24522
|
-
} else if ("acceptWithExecpolicyAmendment" in decision) {
|
|
24523
|
-
const prefix = renderExecPolicyPrefix(decision.acceptWithExecpolicyAmendment.execpolicy_amendment);
|
|
24524
|
-
if (prefix.includes(`
|
|
24525
|
-
`) || prefix.includes("\r"))
|
|
24526
|
-
continue;
|
|
24527
|
-
options.push(decisionOption(OptionId.AcceptWithExecpolicyAmendment, `Yes, and don't ask again for commands that start with \`${prefix}\``, "allow_always", decision));
|
|
24528
|
-
} else {
|
|
24529
|
-
const amendment = decision.applyNetworkPolicyAmendment.network_policy_amendment;
|
|
24530
|
-
options.push(decisionOption(`${OptionId.ApplyNetworkPolicyAmendment}:${networkIndex++}`, amendment.action === "allow" ? "Yes, and allow this host in the future" : "No, and block this host in the future", amendment.action === "allow" ? "allow_always" : "reject_always", decision));
|
|
24314
|
+
get mode() {
|
|
24315
|
+
return this.active?.mode ?? "route";
|
|
24316
|
+
}
|
|
24317
|
+
gatewayFor(modelId) {
|
|
24318
|
+
for (const gateway of this.gateways.values()) {
|
|
24319
|
+
if (gateway.models.some((model) => (this.mode === "catalog" ? gatewayModelId(gateway.id, model.id) : model.id) === modelId))
|
|
24320
|
+
return gateway;
|
|
24531
24321
|
}
|
|
24322
|
+
return null;
|
|
24532
24323
|
}
|
|
24533
|
-
|
|
24534
|
-
|
|
24535
|
-
|
|
24536
|
-
|
|
24537
|
-
|
|
24538
|
-
}
|
|
24539
|
-
|
|
24540
|
-
|
|
24541
|
-
|
|
24542
|
-
|
|
24543
|
-
|
|
24544
|
-
|
|
24545
|
-
|
|
24546
|
-
|
|
24547
|
-
|
|
24548
|
-
|
|
24549
|
-
|
|
24550
|
-
|
|
24551
|
-
|
|
24552
|
-
|
|
24553
|
-
|
|
24554
|
-
|
|
24555
|
-
|
|
24556
|
-
|
|
24557
|
-
|
|
24558
|
-
|
|
24559
|
-
|
|
24560
|
-
|
|
24561
|
-
|
|
24562
|
-
|
|
24563
|
-
|
|
24564
|
-
|
|
24565
|
-
|
|
24566
|
-
|
|
24567
|
-
|
|
24568
|
-
|
|
24569
|
-
return;
|
|
24570
|
-
|
|
24571
|
-
|
|
24572
|
-
|
|
24573
|
-
|
|
24574
|
-
|
|
24575
|
-
|
|
24576
|
-
|
|
24577
|
-
|
|
24578
|
-
|
|
24579
|
-
|
|
24580
|
-
|
|
24581
|
-
|
|
24582
|
-
|
|
24583
|
-
|
|
24584
|
-
|
|
24585
|
-
|
|
24586
|
-
|
|
24587
|
-
|
|
24588
|
-
|
|
24589
|
-
|
|
24590
|
-
if (params.additionalPermissions)
|
|
24591
|
-
content.push(...profileContent(params.additionalPermissions));
|
|
24592
|
-
const locations = unique([...commandActionPaths(params.commandActions), ...profilePaths(params.additionalPermissions)]);
|
|
24593
|
-
return {
|
|
24594
|
-
toolCallId: params.itemId,
|
|
24595
|
-
name: ToolName.Shell,
|
|
24596
|
-
kind: "execute",
|
|
24597
|
-
status: "pending",
|
|
24598
|
-
title: network ? `${network.protocol} network access to ${network.host}` : commandTitle(params.command, params.commandActions),
|
|
24599
|
-
...Object.keys(rawInput).length > 0 ? { rawInput } : {},
|
|
24600
|
-
...locations.length > 0 ? { locations: locations.map((path4) => ({ path: path4 })) } : {},
|
|
24601
|
-
...content.length > 0 ? { content } : {}
|
|
24602
|
-
};
|
|
24603
|
-
}
|
|
24604
|
-
function fileChangeSubject(params, item) {
|
|
24605
|
-
const paths = item ? changePaths(item.changes) : [];
|
|
24606
|
-
return {
|
|
24607
|
-
toolCallId: params.itemId,
|
|
24608
|
-
name: ToolName.ApplyPatch,
|
|
24609
|
-
kind: "edit",
|
|
24610
|
-
status: "pending",
|
|
24611
|
-
title: paths.length === 1 ? `Edit ${paths[0]}` : paths.length > 1 ? `Edit ${paths.length} files` : "Edit files",
|
|
24612
|
-
...paths.length > 0 ? { locations: paths.map((path4) => ({ path: path4 })) } : {},
|
|
24613
|
-
...item ? { content: item.changes.map(diffContent) } : {},
|
|
24614
|
-
...params.grantRoot ? { rawInput: { grantRoot: params.grantRoot } } : {}
|
|
24615
|
-
};
|
|
24616
|
-
}
|
|
24617
|
-
function permissionsSubject(itemId, cwd, environmentId, permissions) {
|
|
24618
|
-
const content = profileContent(permissions);
|
|
24619
|
-
const paths = profilePaths(permissions);
|
|
24620
|
-
return {
|
|
24621
|
-
toolCallId: itemId,
|
|
24622
|
-
name: ToolName.Shell,
|
|
24623
|
-
kind: "other",
|
|
24624
|
-
status: "pending",
|
|
24625
|
-
title: "Additional sandbox permissions",
|
|
24626
|
-
rawInput: { permissions, cwd, environmentId },
|
|
24627
|
-
...paths.length > 0 ? { locations: paths.map((path4) => ({ path: path4 })) } : {},
|
|
24628
|
-
...content.length > 0 ? { content } : {}
|
|
24629
|
-
};
|
|
24630
|
-
}
|
|
24631
|
-
function commandTitle(command, actions) {
|
|
24632
|
-
const first = actions?.[0];
|
|
24633
|
-
if (first?.type === "read")
|
|
24634
|
-
return actions?.length === 1 ? `Read ${first.path}` : "Run command with file reads";
|
|
24635
|
-
if (first?.type === "listFiles")
|
|
24636
|
-
return "List files";
|
|
24637
|
-
if (first?.type === "search")
|
|
24638
|
-
return "Search files";
|
|
24639
|
-
return command ? stripShellPrefix(command) : "Run command";
|
|
24640
|
-
}
|
|
24641
|
-
function profilePaths(permissions) {
|
|
24642
|
-
const fileSystem = permissions?.fileSystem;
|
|
24643
|
-
return unique([
|
|
24644
|
-
...fileSystem?.read ?? [],
|
|
24645
|
-
...fileSystem?.write ?? [],
|
|
24646
|
-
...(fileSystem?.entries ?? []).flatMap((entry) => entry.path.type === "path" ? [entry.path.path] : [])
|
|
24647
|
-
]);
|
|
24648
|
-
}
|
|
24649
|
-
function profileContent(permissions) {
|
|
24650
|
-
const lines = [];
|
|
24651
|
-
const networkEnabled = permissions.network?.enabled;
|
|
24652
|
-
if (networkEnabled !== null && networkEnabled !== undefined) {
|
|
24653
|
-
lines.push(networkEnabled ? "Enable network access" : "Disable network access");
|
|
24324
|
+
gatewayIdFor(modelId) {
|
|
24325
|
+
return this.gatewayFor(modelId)?.id ?? null;
|
|
24326
|
+
}
|
|
24327
|
+
isGatewayModel(modelId) {
|
|
24328
|
+
return this.gatewayFor(modelId) !== null;
|
|
24329
|
+
}
|
|
24330
|
+
gatewayGroups() {
|
|
24331
|
+
if (this.mode !== "catalog")
|
|
24332
|
+
return [];
|
|
24333
|
+
return [...this.gateways.values()].filter((gateway) => gateway.models.length > 0).map((gateway) => ({ id: gateway.id, name: gateway.name, modelIds: gateway.models.map((model) => gatewayModelId(gateway.id, model.id)) }));
|
|
24334
|
+
}
|
|
24335
|
+
selectionId(modelId, provider) {
|
|
24336
|
+
return modelId !== null && this.mode === "catalog" && this.hasGateway(provider) ? gatewayModelId(provider, modelId) : modelId;
|
|
24337
|
+
}
|
|
24338
|
+
upstreamModel(selectionId) {
|
|
24339
|
+
if (selectionId === null || !selectionId.startsWith("gateway:"))
|
|
24340
|
+
return selectionId;
|
|
24341
|
+
const gateway = this.gatewayFor(selectionId);
|
|
24342
|
+
const model = gateway?.models.find((model2) => gatewayModelId(gateway.id, model2.id) === selectionId);
|
|
24343
|
+
if (!model)
|
|
24344
|
+
throw RequestError.invalidParams({ model: selectionId }, "The selected provider connection or model is unavailable");
|
|
24345
|
+
return model.id;
|
|
24346
|
+
}
|
|
24347
|
+
disable(request) {
|
|
24348
|
+
if (request.providerId !== OPENAI_PROVIDER_ID)
|
|
24349
|
+
return;
|
|
24350
|
+
const id = readGatewayId(request._meta);
|
|
24351
|
+
if (id === null)
|
|
24352
|
+
this.gateways.clear();
|
|
24353
|
+
else
|
|
24354
|
+
this.gateways.delete(id);
|
|
24355
|
+
}
|
|
24356
|
+
modelProvider() {
|
|
24357
|
+
return this.defaultGatewayId() ?? this.configuredProvider;
|
|
24358
|
+
}
|
|
24359
|
+
routesByDefault() {
|
|
24360
|
+
return this.defaultGatewayId() !== null;
|
|
24361
|
+
}
|
|
24362
|
+
defaultGatewayId() {
|
|
24363
|
+
const first = this.active;
|
|
24364
|
+
return first !== null && first.mode === "route" ? first.id : null;
|
|
24365
|
+
}
|
|
24366
|
+
threadConfig(gatewayId = this.defaultGatewayId()) {
|
|
24367
|
+
const gateway = this.gateway(gatewayId);
|
|
24368
|
+
if (!gateway)
|
|
24369
|
+
return this.baseConfig;
|
|
24370
|
+
return this.applyGateway(this.baseConfig, gateway);
|
|
24371
|
+
}
|
|
24372
|
+
routeConfig(config2, gatewayId) {
|
|
24373
|
+
return this.rebind(config2, this, gatewayId);
|
|
24374
|
+
}
|
|
24375
|
+
overrideKeys() {
|
|
24376
|
+
const keys = new Set;
|
|
24377
|
+
for (const gateway of this.gateways.values())
|
|
24378
|
+
for (const key of Object.keys(gateway.config))
|
|
24379
|
+
keys.add(key);
|
|
24380
|
+
return [...keys];
|
|
24654
24381
|
}
|
|
24655
|
-
|
|
24656
|
-
|
|
24657
|
-
|
|
24658
|
-
|
|
24659
|
-
|
|
24382
|
+
rebind(config2, previous, gatewayId = this.defaultGatewayId()) {
|
|
24383
|
+
const next = { ...config2 };
|
|
24384
|
+
for (const key of previous.overrideKeys()) {
|
|
24385
|
+
if (key in this.baseConfig)
|
|
24386
|
+
next[key] = this.baseConfig[key];
|
|
24387
|
+
else
|
|
24388
|
+
delete next[key];
|
|
24389
|
+
}
|
|
24390
|
+
delete next["model_providers"];
|
|
24391
|
+
if (isRecord2(this.baseConfig["model_providers"]))
|
|
24392
|
+
next["model_providers"] = this.baseConfig["model_providers"];
|
|
24393
|
+
const gateway = this.gateway(gatewayId);
|
|
24394
|
+
return gateway ? this.applyGateway(next, gateway) : next;
|
|
24660
24395
|
}
|
|
24661
|
-
|
|
24662
|
-
|
|
24663
|
-
|
|
24664
|
-
|
|
24665
|
-
|
|
24666
|
-
|
|
24667
|
-
|
|
24668
|
-
|
|
24669
|
-
|
|
24670
|
-
|
|
24671
|
-
|
|
24672
|
-
|
|
24673
|
-
|
|
24674
|
-
|
|
24675
|
-
|
|
24676
|
-
constructor(client, turn, signal = () => {
|
|
24677
|
-
return;
|
|
24678
|
-
}) {
|
|
24679
|
-
this.client = client;
|
|
24680
|
-
this.turn = turn;
|
|
24681
|
-
this.signal = signal;
|
|
24396
|
+
applyGateway(config2, gateway) {
|
|
24397
|
+
const existing = isRecord2(config2["model_providers"]) ? config2["model_providers"] : {};
|
|
24398
|
+
const entry = {
|
|
24399
|
+
name: gateway.name,
|
|
24400
|
+
base_url: gateway.baseUrl,
|
|
24401
|
+
wire_api: "responses",
|
|
24402
|
+
http_headers: { "X-Client-Feature-ID": "codex", ...gateway.headers }
|
|
24403
|
+
};
|
|
24404
|
+
if (gateway.bearerToken !== null)
|
|
24405
|
+
entry["experimental_bearer_token"] = gateway.bearerToken;
|
|
24406
|
+
return {
|
|
24407
|
+
...config2,
|
|
24408
|
+
...gateway.config,
|
|
24409
|
+
model_providers: { ...existing, [gateway.id]: entry }
|
|
24410
|
+
};
|
|
24682
24411
|
}
|
|
24683
|
-
|
|
24684
|
-
const
|
|
24685
|
-
|
|
24686
|
-
|
|
24687
|
-
|
|
24688
|
-
|
|
24412
|
+
catalog(codexCatalog) {
|
|
24413
|
+
const first = this.active;
|
|
24414
|
+
if (first === null)
|
|
24415
|
+
return codexCatalog;
|
|
24416
|
+
if (first.mode === "route") {
|
|
24417
|
+
if (first.models.length === 0)
|
|
24418
|
+
return codexCatalog;
|
|
24419
|
+
return first.models.map((model, index) => gatewayModel(model, index === 0, codexCatalog[0], first.catalogEntries.get(model.id)));
|
|
24689
24420
|
}
|
|
24690
|
-
|
|
24691
|
-
|
|
24692
|
-
|
|
24693
|
-
|
|
24694
|
-
subject: { type: "tool_call", toolCall: commandSubject(approvalParams) },
|
|
24695
|
-
options: decisions.map(({ option }) => option)
|
|
24696
|
-
}, this.signal());
|
|
24697
|
-
return { decision: selectedDecision(response, decisions) ?? "cancel" };
|
|
24698
|
-
} catch (error40) {
|
|
24699
|
-
logger.error("command approval failed", error40, { itemId: params.itemId });
|
|
24700
|
-
return { decision: "cancel" };
|
|
24421
|
+
const own = [];
|
|
24422
|
+
for (const gateway of this.gateways.values()) {
|
|
24423
|
+
for (const model of gateway.models)
|
|
24424
|
+
own.push({ ...gatewayModel(model, false, codexCatalog[0], gateway.catalogEntries.get(model.id)), id: gatewayModelId(gateway.id, model.id) });
|
|
24701
24425
|
}
|
|
24426
|
+
return [...codexCatalog, ...own];
|
|
24702
24427
|
}
|
|
24703
|
-
|
|
24704
|
-
const
|
|
24705
|
-
|
|
24706
|
-
const
|
|
24707
|
-
|
|
24708
|
-
|
|
24709
|
-
|
|
24710
|
-
options: decisions.map(({ option }) => option)
|
|
24711
|
-
}, this.signal());
|
|
24712
|
-
return { decision: selectedDecision(response, decisions) ?? "cancel" };
|
|
24713
|
-
} catch (error40) {
|
|
24714
|
-
logger.error("file change approval failed", error40, { itemId: params.itemId });
|
|
24715
|
-
return { decision: "cancel" };
|
|
24428
|
+
nativeBaseUrl() {
|
|
24429
|
+
const providers = this.baseConfig["model_providers"];
|
|
24430
|
+
if (this.configuredProvider && isRecord2(providers)) {
|
|
24431
|
+
const entry = providers[this.configuredProvider];
|
|
24432
|
+
const baseUrl = isRecord2(entry) ? entry["base_url"] : undefined;
|
|
24433
|
+
if (typeof baseUrl === "string" && baseUrl.length > 0)
|
|
24434
|
+
return baseUrl;
|
|
24716
24435
|
}
|
|
24436
|
+
return DEFAULT_OPENAI_BASE_URL;
|
|
24717
24437
|
}
|
|
24718
|
-
|
|
24719
|
-
|
|
24720
|
-
|
|
24721
|
-
|
|
24722
|
-
|
|
24723
|
-
|
|
24724
|
-
|
|
24725
|
-
|
|
24726
|
-
|
|
24727
|
-
|
|
24728
|
-
|
|
24729
|
-
|
|
24438
|
+
}
|
|
24439
|
+
function readHints(meta) {
|
|
24440
|
+
const root = isRecord2(meta) ? meta : {};
|
|
24441
|
+
const alwith = isRecord2(root["alwith"]) ? root["alwith"] : {};
|
|
24442
|
+
const codex = isRecord2(root["codex"]) ? root["codex"] : {};
|
|
24443
|
+
const id = readGatewayId(meta) ?? GATEWAY_MODEL_PROVIDER;
|
|
24444
|
+
const models = [];
|
|
24445
|
+
if (Array.isArray(alwith["models"])) {
|
|
24446
|
+
for (const entry of alwith["models"]) {
|
|
24447
|
+
if (!isRecord2(entry) || typeof entry["id"] !== "string" || entry["id"].length === 0)
|
|
24448
|
+
continue;
|
|
24449
|
+
models.push({
|
|
24450
|
+
id: entry["id"],
|
|
24451
|
+
name: typeof entry["label"] === "string" && entry["label"].length > 0 ? entry["label"] : entry["id"],
|
|
24452
|
+
description: typeof entry["description"] === "string" ? entry["description"] : null
|
|
24453
|
+
});
|
|
24454
|
+
}
|
|
24455
|
+
}
|
|
24456
|
+
const model = typeof alwith["model"] === "string" && alwith["model"].length > 0 ? alwith["model"] : null;
|
|
24457
|
+
const name = typeof codex["name"] === "string" && codex["name"].length > 0 ? codex["name"] : null;
|
|
24458
|
+
const bearerToken = typeof codex["bearerToken"] === "string" && codex["bearerToken"].length > 0 ? codex["bearerToken"] : null;
|
|
24459
|
+
const rawConfig = codex["config"];
|
|
24460
|
+
if (rawConfig !== undefined && !isRecord2(rawConfig)) {
|
|
24461
|
+
throw RequestError.invalidParams({ config: rawConfig }, "_meta.codex.config must be an object of top-level Codex config keys");
|
|
24462
|
+
}
|
|
24463
|
+
const config2 = {};
|
|
24464
|
+
if (isRecord2(rawConfig)) {
|
|
24465
|
+
for (const [key, value] of Object.entries(rawConfig)) {
|
|
24466
|
+
if (key === "model_providers")
|
|
24467
|
+
throw RequestError.invalidParams({ config: rawConfig }, "_meta.codex.config cannot set model_providers; that entry is derived from baseUrl and headers");
|
|
24468
|
+
config2[key] = value;
|
|
24730
24469
|
}
|
|
24731
24470
|
}
|
|
24471
|
+
const rawMode = codex["mode"];
|
|
24472
|
+
if (rawMode !== undefined && rawMode !== "route" && rawMode !== "catalog") {
|
|
24473
|
+
throw RequestError.invalidParams({ mode: rawMode }, '_meta.codex.mode must be "route" or "catalog"');
|
|
24474
|
+
}
|
|
24475
|
+
const mode = rawMode === "catalog" ? "catalog" : "route";
|
|
24476
|
+
if (mode === "catalog" && models.length === 0) {
|
|
24477
|
+
throw RequestError.invalidParams(undefined, `_meta.codex.mode "catalog" needs _meta.alwith.models: the models offered next to Codex's`);
|
|
24478
|
+
}
|
|
24479
|
+
const catalogPath = config2["model_catalog_json"];
|
|
24480
|
+
const catalogEntries = typeof catalogPath === "string" ? readCatalogFile(catalogPath) : new Map;
|
|
24481
|
+
return { id, models, model, name, bearerToken, config: config2, mode, catalogEntries };
|
|
24732
24482
|
}
|
|
24733
|
-
function
|
|
24734
|
-
|
|
24735
|
-
|
|
24736
|
-
|
|
24737
|
-
|
|
24738
|
-
|
|
24739
|
-
|
|
24740
|
-
|
|
24741
|
-
|
|
24742
|
-
|
|
24743
|
-
|
|
24744
|
-
|
|
24483
|
+
function readGatewayId(meta) {
|
|
24484
|
+
const root = isRecord2(meta) ? meta : {};
|
|
24485
|
+
const codex = isRecord2(root["codex"]) ? root["codex"] : {};
|
|
24486
|
+
const raw = codex["id"];
|
|
24487
|
+
if (raw === undefined)
|
|
24488
|
+
return null;
|
|
24489
|
+
if (typeof raw !== "string" || !GATEWAY_ID_PATTERN.test(raw)) {
|
|
24490
|
+
throw RequestError.invalidParams({ id: raw }, "_meta.codex.id must match [a-z0-9-]+");
|
|
24491
|
+
}
|
|
24492
|
+
if (raw === NATIVE_GROUP_ID) {
|
|
24493
|
+
throw RequestError.invalidParams({ id: raw }, `_meta.codex.id "${NATIVE_GROUP_ID}" is the native model group`);
|
|
24494
|
+
}
|
|
24495
|
+
return raw;
|
|
24496
|
+
}
|
|
24497
|
+
function readCatalogFile(catalogPath) {
|
|
24498
|
+
const resolved = catalogPath.startsWith("~/") ? path4.join(os.homedir(), catalogPath.slice(2)) : catalogPath;
|
|
24499
|
+
let parsed;
|
|
24500
|
+
try {
|
|
24501
|
+
parsed = JSON.parse(readFileSync(resolved, "utf8"));
|
|
24502
|
+
} catch (error40) {
|
|
24503
|
+
throw RequestError.invalidParams({ model_catalog_json: catalogPath }, `model_catalog_json could not be read as JSON: ${error40 instanceof Error ? error40.message : String(error40)}`);
|
|
24504
|
+
}
|
|
24505
|
+
const models = isRecord2(parsed) && Array.isArray(parsed["models"]) ? parsed["models"] : null;
|
|
24506
|
+
if (models === null)
|
|
24507
|
+
throw RequestError.invalidParams({ model_catalog_json: catalogPath }, "model_catalog_json must be {models: [...]} as Codex expects");
|
|
24508
|
+
const entries = new Map;
|
|
24509
|
+
for (const entry of models) {
|
|
24510
|
+
if (!isRecord2(entry) || typeof entry["slug"] !== "string")
|
|
24511
|
+
continue;
|
|
24512
|
+
const levels = Array.isArray(entry["supported_reasoning_levels"]) ? entry["supported_reasoning_levels"] : [];
|
|
24513
|
+
const efforts = [];
|
|
24514
|
+
for (const level of levels) {
|
|
24515
|
+
if (!isRecord2(level) || typeof level["effort"] !== "string")
|
|
24516
|
+
continue;
|
|
24517
|
+
efforts.push({ reasoningEffort: level["effort"], description: typeof level["description"] === "string" ? level["description"] : "" });
|
|
24518
|
+
}
|
|
24519
|
+
const modalities = Array.isArray(entry["input_modalities"]) ? entry["input_modalities"].filter((value) => value === "text" || value === "image") : null;
|
|
24520
|
+
entries.set(entry["slug"], {
|
|
24521
|
+
displayName: typeof entry["display_name"] === "string" ? entry["display_name"] : null,
|
|
24522
|
+
description: typeof entry["description"] === "string" ? entry["description"] : null,
|
|
24523
|
+
efforts,
|
|
24524
|
+
defaultEffort: typeof entry["default_reasoning_level"] === "string" ? entry["default_reasoning_level"] : null,
|
|
24525
|
+
inputModalities: modalities
|
|
24526
|
+
});
|
|
24745
24527
|
}
|
|
24528
|
+
return entries;
|
|
24529
|
+
}
|
|
24530
|
+
function gatewayModel(model, isDefault, template, entry) {
|
|
24531
|
+
const efforts = entry && entry.efforts.length > 0 ? entry.efforts : template?.supportedReasoningEfforts ?? [];
|
|
24532
|
+
const defaultEffort = entry?.defaultEffort ?? template?.defaultReasoningEffort ?? "medium";
|
|
24533
|
+
return {
|
|
24534
|
+
id: model.id,
|
|
24535
|
+
model: model.id,
|
|
24536
|
+
upgrade: null,
|
|
24537
|
+
upgradeInfo: null,
|
|
24538
|
+
availabilityNux: null,
|
|
24539
|
+
displayName: model.name !== model.id ? model.name : entry?.displayName ?? model.name,
|
|
24540
|
+
description: model.description ?? entry?.description ?? "",
|
|
24541
|
+
modelSpecialty: null,
|
|
24542
|
+
hidden: false,
|
|
24543
|
+
supportedReasoningEfforts: efforts,
|
|
24544
|
+
defaultReasoningEffort: defaultEffort,
|
|
24545
|
+
inputModalities: entry?.inputModalities ?? ["text", "image"],
|
|
24546
|
+
supportsPersonality: false,
|
|
24547
|
+
multiAgentVersion: null,
|
|
24548
|
+
additionalSpeedTiers: [],
|
|
24549
|
+
serviceTiers: [],
|
|
24550
|
+
defaultServiceTier: null,
|
|
24551
|
+
availableAccessPrograms: null,
|
|
24552
|
+
isDefault
|
|
24553
|
+
};
|
|
24554
|
+
}
|
|
24555
|
+
|
|
24556
|
+
// src/codex/models.ts
|
|
24557
|
+
var MODEL_CONFIG_ID = "model";
|
|
24558
|
+
var EFFORT_CONFIG_ID = "effort";
|
|
24559
|
+
var FAST_MODE_CONFIG_ID = "fast_mode";
|
|
24560
|
+
var COLLABORATION_MODE_CONFIG_ID = "collaboration_mode";
|
|
24561
|
+
var DEFAULT_EFFORT = "medium";
|
|
24562
|
+
var FAST_SERVICE_TIER = "fast";
|
|
24563
|
+
function resolveModelSelection(catalog, modelId, effort) {
|
|
24564
|
+
const listed = modelId === null ? undefined : catalog.find((model) => model.id === modelId);
|
|
24565
|
+
if (listed)
|
|
24566
|
+
return { model: listed.id, effort: effort ?? listed.defaultReasoningEffort };
|
|
24567
|
+
if (modelId)
|
|
24568
|
+
return { model: modelId, effort: effort ?? DEFAULT_EFFORT };
|
|
24569
|
+
const fallback = catalog.find((model) => model.isDefault) ?? catalog[0];
|
|
24570
|
+
if (!fallback)
|
|
24571
|
+
throw new Error("Codex did not return any models");
|
|
24572
|
+
return { model: fallback.id, effort: effort ?? fallback.defaultReasoningEffort };
|
|
24746
24573
|
}
|
|
24747
|
-
function
|
|
24748
|
-
return
|
|
24749
|
-
...permissions.network ? { network: permissions.network } : {},
|
|
24750
|
-
...permissions.fileSystem ? { fileSystem: permissions.fileSystem } : {}
|
|
24751
|
-
};
|
|
24574
|
+
function findModel(catalog, modelId) {
|
|
24575
|
+
return catalog.find((model) => model.id === modelId);
|
|
24752
24576
|
}
|
|
24753
|
-
function
|
|
24754
|
-
return
|
|
24577
|
+
function supportedEfforts(model) {
|
|
24578
|
+
return model?.supportedReasoningEfforts ?? [];
|
|
24755
24579
|
}
|
|
24756
|
-
function
|
|
24757
|
-
const
|
|
24758
|
-
|
|
24580
|
+
function coerceEffort(model, effort) {
|
|
24581
|
+
const options = supportedEfforts(model);
|
|
24582
|
+
if (options.length === 0)
|
|
24583
|
+
return effort;
|
|
24584
|
+
if (options.some((option) => option.reasoningEffort === effort))
|
|
24585
|
+
return effort;
|
|
24586
|
+
return model?.defaultReasoningEffort ?? options[0].reasoningEffort;
|
|
24759
24587
|
}
|
|
24760
|
-
|
|
24761
|
-
|
|
24762
|
-
|
|
24763
|
-
|
|
24764
|
-
Accept: "accept",
|
|
24765
|
-
AllowSession: "allow_session",
|
|
24766
|
-
AllowAlways: "allow_always",
|
|
24767
|
-
Decline: "decline",
|
|
24768
|
-
Cancel: "cancel"
|
|
24769
|
-
};
|
|
24770
|
-
function parsePersistOptions(meta) {
|
|
24771
|
-
const result = new Set;
|
|
24772
|
-
if (!isRecord2(meta))
|
|
24773
|
-
return result;
|
|
24774
|
-
const persist = meta["persist"];
|
|
24775
|
-
const values = Array.isArray(persist) ? persist : [persist];
|
|
24776
|
-
if (values.includes("session"))
|
|
24777
|
-
result.add("session");
|
|
24778
|
-
if (values.includes("always"))
|
|
24779
|
-
result.add("always");
|
|
24780
|
-
return result;
|
|
24588
|
+
function modelSupportsFast(model) {
|
|
24589
|
+
if (!model)
|
|
24590
|
+
return false;
|
|
24591
|
+
return model.serviceTiers.some((tier) => tier.id === FAST_SERVICE_TIER) || model.additionalSpeedTiers.includes(FAST_SERVICE_TIER);
|
|
24781
24592
|
}
|
|
24782
|
-
function
|
|
24783
|
-
return
|
|
24593
|
+
function modelSupportsImages(model) {
|
|
24594
|
+
return model?.inputModalities.includes("image") ?? true;
|
|
24784
24595
|
}
|
|
24785
|
-
function
|
|
24786
|
-
const options =
|
|
24787
|
-
|
|
24788
|
-
options.push(permissionOption(McpOptionId.AllowSession, "Allow for this session", "allow_always", isToolApproval ? "Run the tool and remember this choice for this session." : "Allow this request and remember this choice for this session."));
|
|
24789
|
-
}
|
|
24790
|
-
if (persist.has("always")) {
|
|
24791
|
-
options.push(permissionOption(McpOptionId.AllowAlways, "Always allow", "allow_always", isToolApproval ? "Run the tool and remember this choice for future tool calls." : "Allow this request and remember this choice for future requests."));
|
|
24792
|
-
}
|
|
24793
|
-
if (!isToolApproval) {
|
|
24794
|
-
options.push(permissionOption(McpOptionId.Decline, "Deny", "reject_once", "Decline this request and continue."));
|
|
24795
|
-
}
|
|
24796
|
-
options.push(permissionOption(McpOptionId.Cancel, "Cancel", "reject_once", isToolApproval ? "Cancel this tool call." : "Cancel this request."));
|
|
24797
|
-
return options;
|
|
24596
|
+
function modelLacksReasoning(model) {
|
|
24597
|
+
const options = supportedEfforts(model);
|
|
24598
|
+
return options.length > 0 && options.every((option) => option.reasoningEffort === "none");
|
|
24798
24599
|
}
|
|
24799
|
-
function
|
|
24800
|
-
const
|
|
24801
|
-
const options =
|
|
24802
|
-
|
|
24803
|
-
|
|
24804
|
-
|
|
24805
|
-
|
|
24806
|
-
|
|
24807
|
-
|
|
24808
|
-
type: "tool_call",
|
|
24809
|
-
toolCall: {
|
|
24810
|
-
toolCallId: `elicitation:${params.elicitationId}`,
|
|
24811
|
-
name: ToolName.Mcp,
|
|
24812
|
-
kind: "fetch",
|
|
24813
|
-
status: "pending",
|
|
24814
|
-
title: `Open ${params.url}`,
|
|
24815
|
-
content: [message],
|
|
24816
|
-
rawInput: { serverName: params.serverName, url: params.url }
|
|
24817
|
-
}
|
|
24818
|
-
},
|
|
24819
|
-
options
|
|
24820
|
-
};
|
|
24821
|
-
}
|
|
24822
|
-
if (context.correlatedCallId !== undefined) {
|
|
24823
|
-
return {
|
|
24824
|
-
title,
|
|
24825
|
-
description: params.message,
|
|
24826
|
-
subject: { type: "tool_call", toolCall: { toolCallId: context.correlatedCallId, status: "pending" } },
|
|
24827
|
-
options
|
|
24828
|
-
};
|
|
24600
|
+
function modelConfigOption(catalog, current, gatewayGroups = []) {
|
|
24601
|
+
const visible = catalog.filter((model) => !model.hidden || model.id === current);
|
|
24602
|
+
const options = visible.map((model) => ({
|
|
24603
|
+
value: model.id,
|
|
24604
|
+
name: model.displayName,
|
|
24605
|
+
description: model.description || null
|
|
24606
|
+
}));
|
|
24607
|
+
if (!options.some((option) => option.value === current)) {
|
|
24608
|
+
options.unshift({ value: current, name: current, description: null });
|
|
24829
24609
|
}
|
|
24610
|
+
const base = {
|
|
24611
|
+
configId: MODEL_CONFIG_ID,
|
|
24612
|
+
name: "Model",
|
|
24613
|
+
description: "Model Codex uses for this session",
|
|
24614
|
+
category: "model",
|
|
24615
|
+
type: "select",
|
|
24616
|
+
currentValue: current
|
|
24617
|
+
};
|
|
24618
|
+
if (gatewayGroups.length === 0)
|
|
24619
|
+
return { ...base, options };
|
|
24620
|
+
const owner = new Map;
|
|
24621
|
+
for (const group of gatewayGroups)
|
|
24622
|
+
for (const id of group.modelIds)
|
|
24623
|
+
owner.set(id, group.id);
|
|
24624
|
+
const native = options.filter((option) => !owner.has(option.value));
|
|
24830
24625
|
return {
|
|
24831
|
-
|
|
24832
|
-
|
|
24833
|
-
|
|
24834
|
-
|
|
24835
|
-
|
|
24836
|
-
toolCallId: nextStandaloneToolCallId(),
|
|
24837
|
-
name: ToolName.Mcp,
|
|
24838
|
-
kind: context.isToolApproval ? "execute" : "other",
|
|
24839
|
-
status: "pending",
|
|
24840
|
-
title,
|
|
24841
|
-
content: [message],
|
|
24842
|
-
rawInput: { serverName: params.serverName, schema: params.requestedSchema }
|
|
24843
|
-
}
|
|
24844
|
-
},
|
|
24845
|
-
options
|
|
24626
|
+
...base,
|
|
24627
|
+
options: [
|
|
24628
|
+
{ groupId: NATIVE_GROUP_ID, name: NATIVE_GROUP_NAME, options: native },
|
|
24629
|
+
...gatewayGroups.map((group) => ({ groupId: group.id, name: group.name, options: options.filter((option) => owner.get(option.value) === group.id) }))
|
|
24630
|
+
]
|
|
24846
24631
|
};
|
|
24847
24632
|
}
|
|
24848
|
-
function
|
|
24849
|
-
|
|
24850
|
-
|
|
24851
|
-
|
|
24852
|
-
|
|
24853
|
-
|
|
24854
|
-
|
|
24855
|
-
|
|
24856
|
-
case McpOptionId.AllowOnce:
|
|
24857
|
-
return isToolApproval ? accepted(null) : cancelled();
|
|
24858
|
-
case McpOptionId.Accept:
|
|
24859
|
-
return isToolApproval ? cancelled() : accepted(null);
|
|
24860
|
-
case McpOptionId.Decline:
|
|
24861
|
-
return isToolApproval ? cancelled() : { action: "decline", content: null, _meta: null };
|
|
24862
|
-
default:
|
|
24863
|
-
return cancelled();
|
|
24633
|
+
function effortConfigOption(efforts, current) {
|
|
24634
|
+
const options = efforts.map((option) => ({
|
|
24635
|
+
value: option.reasoningEffort,
|
|
24636
|
+
name: capitalize(option.reasoningEffort),
|
|
24637
|
+
description: option.description || null
|
|
24638
|
+
}));
|
|
24639
|
+
if (!options.some((option) => option.value === current)) {
|
|
24640
|
+
options.unshift({ value: current, name: capitalize(current), description: null });
|
|
24864
24641
|
}
|
|
24642
|
+
return {
|
|
24643
|
+
configId: EFFORT_CONFIG_ID,
|
|
24644
|
+
name: "Reasoning effort",
|
|
24645
|
+
description: "How much reasoning effort the model should use",
|
|
24646
|
+
category: "thought_level",
|
|
24647
|
+
type: "select",
|
|
24648
|
+
currentValue: current,
|
|
24649
|
+
options
|
|
24650
|
+
};
|
|
24865
24651
|
}
|
|
24866
|
-
function
|
|
24867
|
-
return {
|
|
24868
|
-
|
|
24869
|
-
|
|
24870
|
-
|
|
24652
|
+
function fastModeConfigOption(enabled) {
|
|
24653
|
+
return {
|
|
24654
|
+
configId: FAST_MODE_CONFIG_ID,
|
|
24655
|
+
name: "Fast mode",
|
|
24656
|
+
description: "1.5x speed, increased usage",
|
|
24657
|
+
category: "model_config",
|
|
24658
|
+
type: "boolean",
|
|
24659
|
+
currentValue: enabled
|
|
24660
|
+
};
|
|
24871
24661
|
}
|
|
24872
|
-
|
|
24873
|
-
|
|
24874
|
-
|
|
24875
|
-
|
|
24876
|
-
|
|
24877
|
-
|
|
24878
|
-
|
|
24879
|
-
|
|
24880
|
-
|
|
24881
|
-
|
|
24882
|
-
|
|
24883
|
-
|
|
24884
|
-
|
|
24885
|
-
|
|
24886
|
-
|
|
24887
|
-
|
|
24888
|
-
|
|
24889
|
-
|
|
24890
|
-
|
|
24891
|
-
|
|
24892
|
-
|
|
24893
|
-
|
|
24894
|
-
|
|
24895
|
-
|
|
24896
|
-
|
|
24897
|
-
|
|
24898
|
-
|
|
24899
|
-
|
|
24900
|
-
|
|
24901
|
-
|
|
24902
|
-
|
|
24903
|
-
const context = this.mcpContext(params);
|
|
24904
|
-
const messageOnly = isMessageOnlyForm(params);
|
|
24905
|
-
if (!messageOnly && this.useAcpElicitation(params)) {
|
|
24906
|
-
const response2 = await this.client.createElicitation(this.elicitationRequest(params, context), this.signal());
|
|
24907
|
-
const result2 = convertMcpElicitationResponse(response2, context);
|
|
24908
|
-
if (params.mode === "url" && result2.action === "accept")
|
|
24909
|
-
this.pendingUrlElicitations.add(params.elicitationId);
|
|
24910
|
-
if (result2.action === "accept")
|
|
24911
|
-
await this.markCorrelatedCallRunning(context);
|
|
24912
|
-
return result2;
|
|
24913
|
-
}
|
|
24914
|
-
if (params.mode !== "url" && !messageOnly) {
|
|
24915
|
-
return cancelled();
|
|
24916
|
-
}
|
|
24917
|
-
const request = mcpPermissionRequest(params, context, () => this.turn.nextStandaloneToolCallId(params.serverName));
|
|
24918
|
-
const response = await this.client.requestPermission(request, this.signal());
|
|
24919
|
-
const result = mcpPermissionResponse(response, context.isToolApproval, context.persistOptions);
|
|
24920
|
-
if (result.action === "accept")
|
|
24921
|
-
await this.markCorrelatedCallRunning(context);
|
|
24922
|
-
return result;
|
|
24923
|
-
} catch (error40) {
|
|
24924
|
-
logger.error("MCP elicitation failed", error40, { server: params.serverName });
|
|
24925
|
-
return cancelled();
|
|
24926
|
-
}
|
|
24662
|
+
var DEFAULT_COLLABORATION_MODE = "default";
|
|
24663
|
+
var PLAN_COLLABORATION_MODE = "plan";
|
|
24664
|
+
function collaborationModeConfigOption(current) {
|
|
24665
|
+
return {
|
|
24666
|
+
configId: COLLABORATION_MODE_CONFIG_ID,
|
|
24667
|
+
name: "Collaboration mode",
|
|
24668
|
+
description: "How Codex collaborates on subsequent turns",
|
|
24669
|
+
category: "model_config",
|
|
24670
|
+
type: "select",
|
|
24671
|
+
currentValue: current,
|
|
24672
|
+
options: [
|
|
24673
|
+
{ value: DEFAULT_COLLABORATION_MODE, name: "Default", description: "Make changes directly" },
|
|
24674
|
+
{ value: PLAN_COLLABORATION_MODE, name: "Plan", description: "Plan before making changes" }
|
|
24675
|
+
]
|
|
24676
|
+
};
|
|
24677
|
+
}
|
|
24678
|
+
function parseCollaborationMode(value) {
|
|
24679
|
+
if (value === DEFAULT_COLLABORATION_MODE)
|
|
24680
|
+
return DEFAULT_COLLABORATION_MODE;
|
|
24681
|
+
if (value === PLAN_COLLABORATION_MODE)
|
|
24682
|
+
return PLAN_COLLABORATION_MODE;
|
|
24683
|
+
return;
|
|
24684
|
+
}
|
|
24685
|
+
function capitalize(value) {
|
|
24686
|
+
return value.length === 0 ? value : value[0].toUpperCase() + value.slice(1);
|
|
24687
|
+
}
|
|
24688
|
+
|
|
24689
|
+
// src/permissions/commandDecisions.ts
|
|
24690
|
+
function availableCommandDecisions(params) {
|
|
24691
|
+
if (params.availableDecisions === undefined || params.availableDecisions === null) {
|
|
24692
|
+
return defaultDecisions(params);
|
|
24927
24693
|
}
|
|
24928
|
-
|
|
24929
|
-
|
|
24930
|
-
|
|
24931
|
-
|
|
24932
|
-
|
|
24933
|
-
|
|
24934
|
-
|
|
24935
|
-
|
|
24936
|
-
|
|
24694
|
+
if (!Array.isArray(params.availableDecisions) || params.availableDecisions.length === 0)
|
|
24695
|
+
return;
|
|
24696
|
+
const decisions = [];
|
|
24697
|
+
for (const candidate of params.availableDecisions) {
|
|
24698
|
+
const decision = parseDecision(candidate, params);
|
|
24699
|
+
if (!decision)
|
|
24700
|
+
return;
|
|
24701
|
+
decisions.push(decision);
|
|
24702
|
+
}
|
|
24703
|
+
return decisions;
|
|
24704
|
+
}
|
|
24705
|
+
function defaultDecisions(params) {
|
|
24706
|
+
if (params.networkApprovalContext) {
|
|
24707
|
+
const decisions2 = ["accept", "acceptForSession"];
|
|
24708
|
+
for (const amendment of params.proposedNetworkPolicyAmendments ?? []) {
|
|
24709
|
+
decisions2.push({ applyNetworkPolicyAmendment: { network_policy_amendment: amendment } });
|
|
24937
24710
|
}
|
|
24711
|
+
decisions2.push("decline", "cancel");
|
|
24712
|
+
return decisions2;
|
|
24938
24713
|
}
|
|
24939
|
-
|
|
24940
|
-
|
|
24941
|
-
|
|
24942
|
-
|
|
24943
|
-
|
|
24944
|
-
correlatedCallId: isToolApproval ? this.turn.popPendingMcpCall(params.serverName) : undefined
|
|
24945
|
-
};
|
|
24714
|
+
if (params.additionalPermissions)
|
|
24715
|
+
return ["accept", "cancel"];
|
|
24716
|
+
const decisions = ["accept", "acceptForSession"];
|
|
24717
|
+
if (params.proposedExecpolicyAmendment && params.proposedExecpolicyAmendment.length > 0) {
|
|
24718
|
+
decisions.push({ acceptWithExecpolicyAmendment: { execpolicy_amendment: params.proposedExecpolicyAmendment } });
|
|
24946
24719
|
}
|
|
24947
|
-
|
|
24948
|
-
|
|
24949
|
-
|
|
24950
|
-
|
|
24951
|
-
|
|
24952
|
-
return
|
|
24720
|
+
decisions.push("decline", "cancel");
|
|
24721
|
+
return decisions;
|
|
24722
|
+
}
|
|
24723
|
+
function parseDecision(candidate, params) {
|
|
24724
|
+
if (candidate === "accept" || candidate === "acceptForSession" || candidate === "decline" || candidate === "cancel") {
|
|
24725
|
+
return candidate;
|
|
24953
24726
|
}
|
|
24954
|
-
|
|
24955
|
-
|
|
24956
|
-
|
|
24957
|
-
|
|
24958
|
-
|
|
24959
|
-
|
|
24960
|
-
|
|
24961
|
-
if (
|
|
24962
|
-
return
|
|
24963
|
-
|
|
24964
|
-
|
|
24727
|
+
if (!isRecord2(candidate))
|
|
24728
|
+
return;
|
|
24729
|
+
if ("acceptWithExecpolicyAmendment" in candidate) {
|
|
24730
|
+
const value = candidate["acceptWithExecpolicyAmendment"];
|
|
24731
|
+
if (!isRecord2(value))
|
|
24732
|
+
return;
|
|
24733
|
+
const amendment = value["execpolicy_amendment"];
|
|
24734
|
+
if (!isStringArray(amendment) || amendment.length === 0)
|
|
24735
|
+
return;
|
|
24736
|
+
if (!sameStrings(amendment, params.proposedExecpolicyAmendment))
|
|
24737
|
+
return;
|
|
24738
|
+
return { acceptWithExecpolicyAmendment: { execpolicy_amendment: [...amendment] } };
|
|
24965
24739
|
}
|
|
24966
|
-
|
|
24967
|
-
|
|
24740
|
+
if ("applyNetworkPolicyAmendment" in candidate) {
|
|
24741
|
+
const value = candidate["applyNetworkPolicyAmendment"];
|
|
24742
|
+
if (!isRecord2(value))
|
|
24968
24743
|
return;
|
|
24969
|
-
|
|
24744
|
+
const amendment = parseNetworkAmendment(value["network_policy_amendment"]);
|
|
24745
|
+
if (!amendment || !params.networkApprovalContext)
|
|
24746
|
+
return;
|
|
24747
|
+
if (amendment.host !== params.networkApprovalContext.host)
|
|
24748
|
+
return;
|
|
24749
|
+
const proposed = params.proposedNetworkPolicyAmendments ?? [];
|
|
24750
|
+
if (!proposed.some((entry) => entry.host === amendment.host && entry.action === amendment.action))
|
|
24751
|
+
return;
|
|
24752
|
+
return { applyNetworkPolicyAmendment: { network_policy_amendment: amendment } };
|
|
24970
24753
|
}
|
|
24754
|
+
return;
|
|
24971
24755
|
}
|
|
24972
|
-
function
|
|
24973
|
-
if (
|
|
24974
|
-
return
|
|
24975
|
-
const
|
|
24976
|
-
if (
|
|
24977
|
-
return
|
|
24978
|
-
|
|
24979
|
-
return false;
|
|
24980
|
-
return schema["type"] === "object" && isRecord2(schema["properties"]) && Object.keys(schema["properties"]).length === 0;
|
|
24756
|
+
function parseNetworkAmendment(value) {
|
|
24757
|
+
if (!isRecord2(value) || typeof value["host"] !== "string")
|
|
24758
|
+
return;
|
|
24759
|
+
const action = value["action"];
|
|
24760
|
+
if (action !== "allow" && action !== "deny")
|
|
24761
|
+
return;
|
|
24762
|
+
return { host: value["host"], action };
|
|
24981
24763
|
}
|
|
24982
|
-
function
|
|
24983
|
-
|
|
24984
|
-
if (!isRecord2(normalized))
|
|
24985
|
-
return { type: "object", properties: {} };
|
|
24986
|
-
return { ...normalized, type: "object" };
|
|
24764
|
+
function isStringArray(value) {
|
|
24765
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
24987
24766
|
}
|
|
24988
|
-
function
|
|
24989
|
-
|
|
24990
|
-
|
|
24991
|
-
|
|
24992
|
-
|
|
24993
|
-
if (
|
|
24767
|
+
function sameStrings(left, right) {
|
|
24768
|
+
return !!right && left.length === right.length && left.every((value, index) => value === right[index]);
|
|
24769
|
+
}
|
|
24770
|
+
function renderExecPolicyPrefix(command) {
|
|
24771
|
+
const script = extractWrappedScript(command);
|
|
24772
|
+
if (script !== undefined)
|
|
24773
|
+
return script;
|
|
24774
|
+
if (command.some((value) => value.includes("\x00")))
|
|
24775
|
+
return command.join(" ");
|
|
24776
|
+
return command.map(shlexQuote).join(" ");
|
|
24777
|
+
}
|
|
24778
|
+
function extractWrappedScript(command) {
|
|
24779
|
+
const executable = executableName(command[0]);
|
|
24780
|
+
if ((executable === "bash" || executable === "zsh" || executable === "sh") && command.length === 3 && (command[1] === "-lc" || command[1] === "-c")) {
|
|
24781
|
+
return command[2];
|
|
24782
|
+
}
|
|
24783
|
+
if (executable !== "pwsh" && executable !== "powershell")
|
|
24784
|
+
return;
|
|
24785
|
+
const allowedFlags = new Set(["-nologo", "-noprofile", "-command", "-c"]);
|
|
24786
|
+
for (let index = 1;index + 1 < command.length; index++) {
|
|
24787
|
+
const flag = command[index]?.toLowerCase();
|
|
24788
|
+
if (flag === undefined || !allowedFlags.has(flag))
|
|
24789
|
+
return;
|
|
24790
|
+
if (flag === "-command" || flag === "-c")
|
|
24791
|
+
return command[index + 1];
|
|
24792
|
+
}
|
|
24793
|
+
return;
|
|
24794
|
+
}
|
|
24795
|
+
function executableName(command) {
|
|
24796
|
+
let filename = command?.replaceAll("\\", "/").split("/").at(-1);
|
|
24797
|
+
while (filename !== undefined) {
|
|
24798
|
+
if (["bash", "zsh", "sh", "pwsh", "powershell"].includes(filename))
|
|
24799
|
+
return filename;
|
|
24800
|
+
const dot = filename.lastIndexOf(".");
|
|
24801
|
+
if (dot <= 0)
|
|
24802
|
+
return;
|
|
24803
|
+
filename = filename.slice(0, dot);
|
|
24804
|
+
}
|
|
24805
|
+
return;
|
|
24806
|
+
}
|
|
24807
|
+
function shlexQuote(value) {
|
|
24808
|
+
if (value.length === 0)
|
|
24809
|
+
return "''";
|
|
24810
|
+
if (/^[0-9A-Za-z+\-./:@_]+$/.test(value))
|
|
24994
24811
|
return value;
|
|
24995
|
-
|
|
24996
|
-
|
|
24997
|
-
|
|
24998
|
-
|
|
24999
|
-
|
|
25000
|
-
|
|
25001
|
-
|
|
24812
|
+
if (!value.includes("'"))
|
|
24813
|
+
return `'${value}'`;
|
|
24814
|
+
return `"${value.replace(/["\\$`!]/g, "\\$&")}"`;
|
|
24815
|
+
}
|
|
24816
|
+
|
|
24817
|
+
// src/permissions/options.ts
|
|
24818
|
+
var OptionId = {
|
|
24819
|
+
AllowOnce: "allow_once",
|
|
24820
|
+
AllowForSession: "allow_for_session",
|
|
24821
|
+
Decline: "decline",
|
|
24822
|
+
Cancel: "cancel",
|
|
24823
|
+
AcceptWithExecpolicyAmendment: "accept_execpolicy_amendment",
|
|
24824
|
+
ApplyNetworkPolicyAmendment: "apply_network_policy_amendment",
|
|
24825
|
+
AllowPermissionsForTurn: "allow_permissions_turn",
|
|
24826
|
+
AllowPermissionsForTurnStrict: "allow_permissions_turn_strict_auto_review",
|
|
24827
|
+
AllowPermissionsForSession: "allow_permissions_session",
|
|
24828
|
+
RejectPermissions: "reject_permissions"
|
|
24829
|
+
};
|
|
24830
|
+
function commandDecisionOptions(params) {
|
|
24831
|
+
const decisions = availableCommandDecisions(params);
|
|
24832
|
+
if (!decisions)
|
|
24833
|
+
return;
|
|
24834
|
+
const options = [];
|
|
24835
|
+
let networkIndex = 0;
|
|
24836
|
+
for (const decision of decisions) {
|
|
24837
|
+
if (decision === "accept") {
|
|
24838
|
+
options.push(decisionOption(OptionId.AllowOnce, params.networkApprovalContext ? "Yes, just this once" : "Yes, proceed", "allow_once", decision));
|
|
24839
|
+
} else if (decision === "acceptForSession") {
|
|
24840
|
+
const name = params.networkApprovalContext ? "Yes, and allow this host for this conversation" : params.additionalPermissions ? "Yes, and allow these permissions for this session" : "Yes, and don't ask again for this command in this session";
|
|
24841
|
+
options.push(decisionOption(OptionId.AllowForSession, name, "allow_always", decision));
|
|
24842
|
+
} else if (decision === "decline") {
|
|
24843
|
+
options.push(decisionOption(OptionId.Decline, "No, continue without running it", "reject_once", decision));
|
|
24844
|
+
} else if (decision === "cancel") {
|
|
24845
|
+
options.push(decisionOption(OptionId.Cancel, "No, and tell Codex what to do differently", "reject_once", decision));
|
|
24846
|
+
} else if ("acceptWithExecpolicyAmendment" in decision) {
|
|
24847
|
+
const prefix = renderExecPolicyPrefix(decision.acceptWithExecpolicyAmendment.execpolicy_amendment);
|
|
24848
|
+
if (prefix.includes(`
|
|
24849
|
+
`) || prefix.includes("\r"))
|
|
24850
|
+
continue;
|
|
24851
|
+
options.push(decisionOption(OptionId.AcceptWithExecpolicyAmendment, `Yes, and don't ask again for commands that start with \`${prefix}\``, "allow_always", decision));
|
|
24852
|
+
} else {
|
|
24853
|
+
const amendment = decision.applyNetworkPolicyAmendment.network_policy_amendment;
|
|
24854
|
+
options.push(decisionOption(`${OptionId.ApplyNetworkPolicyAmendment}:${networkIndex++}`, amendment.action === "allow" ? "Yes, and allow this host in the future" : "No, and block this host in the future", amendment.action === "allow" ? "allow_always" : "reject_always", decision));
|
|
24855
|
+
}
|
|
25002
24856
|
}
|
|
25003
|
-
|
|
24857
|
+
const ordered = [...options].sort((left, right) => order(left.option) - order(right.option));
|
|
24858
|
+
const hasAllow = ordered.some(({ option }) => option.kind === "allow_once" || option.kind === "allow_always");
|
|
24859
|
+
const hasReject = ordered.some(({ option }) => option.kind === "reject_once" || option.kind === "reject_always");
|
|
24860
|
+
const ids = ordered.map(({ option }) => option.optionId);
|
|
24861
|
+
return hasAllow && hasReject && new Set(ids).size === ids.length ? ordered : undefined;
|
|
24862
|
+
}
|
|
24863
|
+
function order(option) {
|
|
24864
|
+
if (option.kind === "allow_once")
|
|
24865
|
+
return 0;
|
|
24866
|
+
if (option.kind === "allow_always")
|
|
24867
|
+
return 1;
|
|
24868
|
+
return 2;
|
|
24869
|
+
}
|
|
24870
|
+
function fileChangeDecisionOptions() {
|
|
24871
|
+
return [
|
|
24872
|
+
decisionOption(OptionId.AllowOnce, "Yes, proceed", "allow_once", "accept"),
|
|
24873
|
+
decisionOption(OptionId.AllowForSession, "Yes, and don't ask again for these files", "allow_always", "acceptForSession"),
|
|
24874
|
+
decisionOption(OptionId.Cancel, "No, and tell Codex what to do differently", "reject_once", "cancel")
|
|
24875
|
+
];
|
|
25004
24876
|
}
|
|
25005
|
-
function
|
|
25006
|
-
|
|
25007
|
-
|
|
25008
|
-
|
|
25009
|
-
|
|
25010
|
-
|
|
25011
|
-
|
|
25012
|
-
delete content["persist"];
|
|
25013
|
-
return { action: "accept", content: contentOrNull(content), _meta: responseMeta(response, context, persist) };
|
|
25014
|
-
}
|
|
25015
|
-
if (CreateElicitationResponse.isDecline(response)) {
|
|
25016
|
-
return context.isToolApproval ? { action: "cancel", content: null, _meta: responseMeta(response, context) } : { action: "decline", content: null, _meta: responseMeta(response, context) };
|
|
25017
|
-
}
|
|
25018
|
-
if (CreateElicitationResponse.isCancel(response)) {
|
|
25019
|
-
return { action: "cancel", content: null, _meta: responseMeta(response, context) };
|
|
25020
|
-
}
|
|
25021
|
-
return cancelled();
|
|
24877
|
+
function permissionProfileOptions() {
|
|
24878
|
+
return [
|
|
24879
|
+
permissionOption(OptionId.AllowPermissionsForTurn, "Yes, grant these permissions for this turn", "allow_once"),
|
|
24880
|
+
permissionOption(OptionId.AllowPermissionsForTurnStrict, "Yes, grant for this turn with strict auto review", "allow_once"),
|
|
24881
|
+
permissionOption(OptionId.AllowPermissionsForSession, "Yes, grant these permissions for this session", "allow_always"),
|
|
24882
|
+
permissionOption(OptionId.RejectPermissions, "No, continue without permissions", "reject_once")
|
|
24883
|
+
];
|
|
25022
24884
|
}
|
|
25023
|
-
function
|
|
25024
|
-
return
|
|
24885
|
+
function decisionOption(optionId, name, kind, decision) {
|
|
24886
|
+
return { option: permissionOption(optionId, name, kind), decision };
|
|
25025
24887
|
}
|
|
25026
|
-
function
|
|
25027
|
-
|
|
25028
|
-
if (entries.length === 0)
|
|
25029
|
-
return null;
|
|
25030
|
-
return Object.fromEntries(entries.map(([key, value]) => [key, normalizeJsonValue(value)]));
|
|
24888
|
+
function permissionOption(optionId, name, kind, description) {
|
|
24889
|
+
return { optionId, name, kind, ...description ? { _meta: { codex: { description } } } : {} };
|
|
25031
24890
|
}
|
|
25032
|
-
function
|
|
25033
|
-
|
|
25034
|
-
|
|
25035
|
-
|
|
25036
|
-
|
|
25037
|
-
if (persist === "session" || persist === "always")
|
|
25038
|
-
meta["persist"] = persist;
|
|
25039
|
-
return Object.keys(meta).length === 0 ? null : meta;
|
|
24891
|
+
function selectedDecision(response, decisions) {
|
|
24892
|
+
if (response.outcome.outcome !== "selected")
|
|
24893
|
+
return;
|
|
24894
|
+
const optionId = response.outcome.optionId;
|
|
24895
|
+
return decisions.find(({ option }) => option.optionId === optionId)?.decision;
|
|
25040
24896
|
}
|
|
25041
|
-
|
|
25042
|
-
|
|
25043
|
-
|
|
25044
|
-
|
|
25045
|
-
|
|
25046
|
-
|
|
25047
|
-
|
|
25048
|
-
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
}
|
|
25053
|
-
|
|
25054
|
-
|
|
25055
|
-
|
|
25056
|
-
|
|
25057
|
-
|
|
25058
|
-
|
|
25059
|
-
|
|
25060
|
-
|
|
25061
|
-
_meta: { codex: { questionId: question.id, isOtherAnswer: true, isSecret: question.isSecret } }
|
|
25062
|
-
};
|
|
25063
|
-
}
|
|
25064
|
-
}
|
|
25065
|
-
const first = params.questions[0];
|
|
24897
|
+
|
|
24898
|
+
// src/permissions/presentation.ts
|
|
24899
|
+
var COMMAND_TITLE = "Run command?";
|
|
24900
|
+
var NETWORK_TITLE = "Allow network access?";
|
|
24901
|
+
var FILE_CHANGE_TITLE = "Make edits?";
|
|
24902
|
+
var PERMISSIONS_TITLE = "Grant permissions?";
|
|
24903
|
+
function commandSubject(params) {
|
|
24904
|
+
const network = params.networkApprovalContext;
|
|
24905
|
+
const rawInput = {
|
|
24906
|
+
...params.command ? { command: stripShellPrefix(params.command) } : {},
|
|
24907
|
+
...params.cwd ? { cwd: params.cwd } : {},
|
|
24908
|
+
...network?.protocol === "http" || network?.protocol === "https" ? { url: `${network.protocol}://${network.host}` } : {},
|
|
24909
|
+
...params.additionalPermissions ? { additionalPermissions: params.additionalPermissions } : {}
|
|
24910
|
+
};
|
|
24911
|
+
const content = [];
|
|
24912
|
+
if (network)
|
|
24913
|
+
content.push(text(`${network.protocol} access to ${network.host}`));
|
|
24914
|
+
if (params.additionalPermissions)
|
|
24915
|
+
content.push(...profileContent(params.additionalPermissions));
|
|
24916
|
+
const locations = unique([...commandActionPaths(params.commandActions), ...profilePaths(params.additionalPermissions)]);
|
|
25066
24917
|
return {
|
|
25067
|
-
sessionId,
|
|
25068
24918
|
toolCallId: params.itemId,
|
|
25069
|
-
|
|
25070
|
-
|
|
25071
|
-
|
|
25072
|
-
|
|
24919
|
+
name: ToolName.Shell,
|
|
24920
|
+
kind: "execute",
|
|
24921
|
+
status: "pending",
|
|
24922
|
+
title: network ? `${network.protocol} network access to ${network.host}` : commandTitle(params.command, params.commandActions),
|
|
24923
|
+
...Object.keys(rawInput).length > 0 ? { rawInput } : {},
|
|
24924
|
+
...locations.length > 0 ? { locations: locations.map((path5) => ({ path: path5 })) } : {},
|
|
24925
|
+
...content.length > 0 ? { content } : {}
|
|
25073
24926
|
};
|
|
25074
24927
|
}
|
|
25075
|
-
function
|
|
25076
|
-
|
|
25077
|
-
|
|
25078
|
-
|
|
25079
|
-
|
|
25080
|
-
|
|
25081
|
-
|
|
25082
|
-
|
|
25083
|
-
|
|
25084
|
-
|
|
25085
|
-
|
|
25086
|
-
|
|
24928
|
+
function fileChangeSubject(params, item) {
|
|
24929
|
+
const paths = item ? changePaths(item.changes) : [];
|
|
24930
|
+
return {
|
|
24931
|
+
toolCallId: params.itemId,
|
|
24932
|
+
name: ToolName.ApplyPatch,
|
|
24933
|
+
kind: "edit",
|
|
24934
|
+
status: "pending",
|
|
24935
|
+
title: paths.length === 1 ? `Edit ${paths[0]}` : paths.length > 1 ? `Edit ${paths.length} files` : "Edit files",
|
|
24936
|
+
...paths.length > 0 ? { locations: paths.map((path5) => ({ path: path5 })) } : {},
|
|
24937
|
+
...item ? { content: item.changes.map(diffContent) } : {},
|
|
24938
|
+
...params.grantRoot ? { rawInput: { grantRoot: params.grantRoot } } : {}
|
|
24939
|
+
};
|
|
24940
|
+
}
|
|
24941
|
+
function permissionsSubject(itemId, cwd, environmentId, permissions) {
|
|
24942
|
+
const content = profileContent(permissions);
|
|
24943
|
+
const paths = profilePaths(permissions);
|
|
24944
|
+
return {
|
|
24945
|
+
toolCallId: itemId,
|
|
24946
|
+
name: ToolName.Shell,
|
|
24947
|
+
kind: "other",
|
|
24948
|
+
status: "pending",
|
|
24949
|
+
title: "Additional sandbox permissions",
|
|
24950
|
+
rawInput: { permissions, cwd, environmentId },
|
|
24951
|
+
...paths.length > 0 ? { locations: paths.map((path5) => ({ path: path5 })) } : {},
|
|
24952
|
+
...content.length > 0 ? { content } : {}
|
|
24953
|
+
};
|
|
24954
|
+
}
|
|
24955
|
+
function commandTitle(command, actions) {
|
|
24956
|
+
const first = actions?.[0];
|
|
24957
|
+
if (first?.type === "read")
|
|
24958
|
+
return actions?.length === 1 ? `Read ${first.path}` : "Run command with file reads";
|
|
24959
|
+
if (first?.type === "listFiles")
|
|
24960
|
+
return "List files";
|
|
24961
|
+
if (first?.type === "search")
|
|
24962
|
+
return "Search files";
|
|
24963
|
+
return command ? stripShellPrefix(command) : "Run command";
|
|
24964
|
+
}
|
|
24965
|
+
function profilePaths(permissions) {
|
|
24966
|
+
const fileSystem = permissions?.fileSystem;
|
|
24967
|
+
return unique([
|
|
24968
|
+
...fileSystem?.read ?? [],
|
|
24969
|
+
...fileSystem?.write ?? [],
|
|
24970
|
+
...(fileSystem?.entries ?? []).flatMap((entry) => entry.path.type === "path" ? [entry.path.path] : [])
|
|
24971
|
+
]);
|
|
24972
|
+
}
|
|
24973
|
+
function profileContent(permissions) {
|
|
24974
|
+
const lines = [];
|
|
24975
|
+
const networkEnabled = permissions.network?.enabled;
|
|
24976
|
+
if (networkEnabled !== null && networkEnabled !== undefined) {
|
|
24977
|
+
lines.push(networkEnabled ? "Enable network access" : "Disable network access");
|
|
25087
24978
|
}
|
|
25088
|
-
|
|
24979
|
+
for (const entry of permissions.fileSystem?.entries ?? []) {
|
|
24980
|
+
if (entry.path.type === "glob_pattern")
|
|
24981
|
+
lines.push(`${entry.access} filesystem pattern ${entry.path.pattern}`);
|
|
24982
|
+
else if (entry.path.type === "special")
|
|
24983
|
+
lines.push(`${entry.access} Codex filesystem scope ${JSON.stringify(entry.path.value)}`);
|
|
24984
|
+
}
|
|
24985
|
+
return lines.length > 0 ? [text(lines.join(`
|
|
24986
|
+
`))] : [];
|
|
25089
24987
|
}
|
|
25090
|
-
function
|
|
25091
|
-
|
|
25092
|
-
if (typeof value === "string" && value.trim() === "")
|
|
25093
|
-
return;
|
|
25094
|
-
if (Array.isArray(value) && value.length === 0)
|
|
25095
|
-
return;
|
|
25096
|
-
return value;
|
|
24988
|
+
function text(value) {
|
|
24989
|
+
return { type: "content", content: { type: "text", text: value } };
|
|
25097
24990
|
}
|
|
25098
|
-
function
|
|
25099
|
-
|
|
25100
|
-
if (!ids.has(base))
|
|
25101
|
-
return base;
|
|
25102
|
-
let index = 1;
|
|
25103
|
-
while (ids.has(`${base}${index}`))
|
|
25104
|
-
index += 1;
|
|
25105
|
-
return `${base}${index}`;
|
|
24991
|
+
function unique(values) {
|
|
24992
|
+
return [...new Set(values)];
|
|
25106
24993
|
}
|
|
25107
24994
|
|
|
25108
|
-
// src/permissions/
|
|
25109
|
-
class
|
|
25110
|
-
|
|
25111
|
-
|
|
25112
|
-
|
|
25113
|
-
|
|
25114
|
-
|
|
25115
|
-
|
|
24995
|
+
// src/permissions/ApprovalHandler.ts
|
|
24996
|
+
class CodexApprovalHandler {
|
|
24997
|
+
client;
|
|
24998
|
+
turn;
|
|
24999
|
+
signal;
|
|
25000
|
+
constructor(client, turn, signal = () => {
|
|
25001
|
+
return;
|
|
25002
|
+
}) {
|
|
25003
|
+
this.client = client;
|
|
25004
|
+
this.turn = turn;
|
|
25005
|
+
this.signal = signal;
|
|
25116
25006
|
}
|
|
25117
|
-
|
|
25118
|
-
|
|
25119
|
-
|
|
25120
|
-
|
|
25121
|
-
|
|
25122
|
-
|
|
25123
|
-
|
|
25124
|
-
|
|
25125
|
-
|
|
25126
|
-
|
|
25127
|
-
|
|
25128
|
-
|
|
25129
|
-
|
|
25130
|
-
|
|
25131
|
-
|
|
25132
|
-
|
|
25133
|
-
|
|
25007
|
+
async handleCommandExecution(params) {
|
|
25008
|
+
const approvalParams = params;
|
|
25009
|
+
const decisions = commandDecisionOptions(approvalParams);
|
|
25010
|
+
if (!decisions) {
|
|
25011
|
+
logger.log("cancelling command approval: no complete decision set", { itemId: params.itemId });
|
|
25012
|
+
return { decision: "cancel" };
|
|
25013
|
+
}
|
|
25014
|
+
try {
|
|
25015
|
+
const response = await this.client.requestPermission({
|
|
25016
|
+
title: params.networkApprovalContext ? NETWORK_TITLE : COMMAND_TITLE,
|
|
25017
|
+
description: nonBlank(params.reason),
|
|
25018
|
+
subject: { type: "tool_call", toolCall: commandSubject(approvalParams) },
|
|
25019
|
+
options: decisions.map(({ option }) => option)
|
|
25020
|
+
}, this.signal());
|
|
25021
|
+
return { decision: selectedDecision(response, decisions) ?? "cancel" };
|
|
25022
|
+
} catch (error40) {
|
|
25023
|
+
logger.error("command approval failed", error40, { itemId: params.itemId });
|
|
25024
|
+
return { decision: "cancel" };
|
|
25134
25025
|
}
|
|
25135
25026
|
}
|
|
25136
|
-
|
|
25137
|
-
|
|
25138
|
-
|
|
25139
|
-
|
|
25140
|
-
|
|
25141
|
-
|
|
25142
|
-
|
|
25143
|
-
|
|
25144
|
-
|
|
25145
|
-
|
|
25146
|
-
|
|
25147
|
-
|
|
25148
|
-
|
|
25149
|
-
}
|
|
25150
|
-
itemStarted(item) {
|
|
25151
|
-
if (item.type === "fileChange") {
|
|
25152
|
-
this.fileChanges.set(item.id, item);
|
|
25153
|
-
} else if (item.type === "mcpToolCall") {
|
|
25154
|
-
const pending = this.pendingMcpCalls.get(item.server) ?? [];
|
|
25155
|
-
pending.push(item.id);
|
|
25156
|
-
this.pendingMcpCalls.set(item.server, pending);
|
|
25027
|
+
async handleFileChange(params) {
|
|
25028
|
+
const decisions = fileChangeDecisionOptions();
|
|
25029
|
+
try {
|
|
25030
|
+
const response = await this.client.requestPermission({
|
|
25031
|
+
title: FILE_CHANGE_TITLE,
|
|
25032
|
+
description: nonBlank(params.reason),
|
|
25033
|
+
subject: { type: "tool_call", toolCall: fileChangeSubject(params, this.turn.fileChange(params.itemId)) },
|
|
25034
|
+
options: decisions.map(({ option }) => option)
|
|
25035
|
+
}, this.signal());
|
|
25036
|
+
return { decision: selectedDecision(response, decisions) ?? "cancel" };
|
|
25037
|
+
} catch (error40) {
|
|
25038
|
+
logger.error("file change approval failed", error40, { itemId: params.itemId });
|
|
25039
|
+
return { decision: "cancel" };
|
|
25157
25040
|
}
|
|
25158
25041
|
}
|
|
25159
|
-
|
|
25160
|
-
|
|
25161
|
-
this.
|
|
25162
|
-
|
|
25163
|
-
|
|
25164
|
-
|
|
25165
|
-
|
|
25166
|
-
|
|
25167
|
-
|
|
25168
|
-
|
|
25169
|
-
|
|
25170
|
-
|
|
25042
|
+
async handlePermissionsRequest(params) {
|
|
25043
|
+
try {
|
|
25044
|
+
const response = await this.client.requestPermission({
|
|
25045
|
+
title: PERMISSIONS_TITLE,
|
|
25046
|
+
description: nonBlank(params.reason),
|
|
25047
|
+
subject: { type: "tool_call", toolCall: permissionsSubject(params.itemId, params.cwd, params.environmentId, params.permissions) },
|
|
25048
|
+
options: permissionProfileOptions()
|
|
25049
|
+
}, this.signal());
|
|
25050
|
+
return permissionsResponse(params.permissions, response);
|
|
25051
|
+
} catch (error40) {
|
|
25052
|
+
logger.error("permissions approval failed", error40, { itemId: params.itemId });
|
|
25053
|
+
return rejected();
|
|
25171
25054
|
}
|
|
25172
25055
|
}
|
|
25173
25056
|
}
|
|
25174
|
-
|
|
25175
|
-
|
|
25176
|
-
|
|
25177
|
-
|
|
25178
|
-
|
|
25179
|
-
|
|
25180
|
-
|
|
25181
|
-
|
|
25182
|
-
|
|
25183
|
-
|
|
25184
|
-
|
|
25185
|
-
|
|
25186
|
-
import fs5, { constants as fsConstants } from "fs/promises";
|
|
25187
|
-
|
|
25188
|
-
// node_modules/is-wsl/index.js
|
|
25189
|
-
import process2 from "process";
|
|
25190
|
-
import os from "os";
|
|
25191
|
-
import fs4 from "fs";
|
|
25192
|
-
|
|
25193
|
-
// node_modules/is-inside-container/index.js
|
|
25194
|
-
import fs3 from "fs";
|
|
25195
|
-
|
|
25196
|
-
// node_modules/is-docker/index.js
|
|
25197
|
-
import fs2 from "fs";
|
|
25198
|
-
var isDockerCached;
|
|
25199
|
-
function hasDockerEnv() {
|
|
25200
|
-
try {
|
|
25201
|
-
fs2.statSync("/.dockerenv");
|
|
25202
|
-
return true;
|
|
25203
|
-
} catch {
|
|
25204
|
-
return false;
|
|
25057
|
+
function permissionsResponse(permissions, response) {
|
|
25058
|
+
if (response.outcome.outcome !== "selected")
|
|
25059
|
+
return rejected();
|
|
25060
|
+
switch (response.outcome.optionId) {
|
|
25061
|
+
case OptionId.AllowPermissionsForTurn:
|
|
25062
|
+
return { permissions: granted(permissions), scope: "turn", strictAutoReview: false };
|
|
25063
|
+
case OptionId.AllowPermissionsForTurnStrict:
|
|
25064
|
+
return { permissions: granted(permissions), scope: "turn", strictAutoReview: true };
|
|
25065
|
+
case OptionId.AllowPermissionsForSession:
|
|
25066
|
+
return { permissions: granted(permissions), scope: "session", strictAutoReview: false };
|
|
25067
|
+
default:
|
|
25068
|
+
return rejected();
|
|
25205
25069
|
}
|
|
25206
25070
|
}
|
|
25207
|
-
function
|
|
25208
|
-
|
|
25209
|
-
|
|
25210
|
-
|
|
25211
|
-
|
|
25212
|
-
}
|
|
25071
|
+
function granted(permissions) {
|
|
25072
|
+
return {
|
|
25073
|
+
...permissions.network ? { network: permissions.network } : {},
|
|
25074
|
+
...permissions.fileSystem ? { fileSystem: permissions.fileSystem } : {}
|
|
25075
|
+
};
|
|
25213
25076
|
}
|
|
25214
|
-
function
|
|
25215
|
-
|
|
25216
|
-
|
|
25217
|
-
|
|
25218
|
-
|
|
25077
|
+
function rejected() {
|
|
25078
|
+
return { permissions: {}, scope: "turn", strictAutoReview: false };
|
|
25079
|
+
}
|
|
25080
|
+
function nonBlank(value) {
|
|
25081
|
+
const trimmed = value?.trim();
|
|
25082
|
+
return trimmed ? trimmed : null;
|
|
25219
25083
|
}
|
|
25220
25084
|
|
|
25221
|
-
//
|
|
25222
|
-
var
|
|
25223
|
-
|
|
25224
|
-
|
|
25225
|
-
|
|
25226
|
-
|
|
25227
|
-
|
|
25228
|
-
|
|
25229
|
-
}
|
|
25085
|
+
// src/permissions/mcp.ts
|
|
25086
|
+
var McpOptionId = {
|
|
25087
|
+
AllowOnce: "allow_once",
|
|
25088
|
+
Accept: "accept",
|
|
25089
|
+
AllowSession: "allow_session",
|
|
25090
|
+
AllowAlways: "allow_always",
|
|
25091
|
+
Decline: "decline",
|
|
25092
|
+
Cancel: "cancel"
|
|
25230
25093
|
};
|
|
25231
|
-
function
|
|
25232
|
-
|
|
25233
|
-
|
|
25234
|
-
|
|
25235
|
-
|
|
25094
|
+
function parsePersistOptions(meta) {
|
|
25095
|
+
const result = new Set;
|
|
25096
|
+
if (!isRecord2(meta))
|
|
25097
|
+
return result;
|
|
25098
|
+
const persist = meta["persist"];
|
|
25099
|
+
const values = Array.isArray(persist) ? persist : [persist];
|
|
25100
|
+
if (values.includes("session"))
|
|
25101
|
+
result.add("session");
|
|
25102
|
+
if (values.includes("always"))
|
|
25103
|
+
result.add("always");
|
|
25104
|
+
return result;
|
|
25236
25105
|
}
|
|
25237
|
-
|
|
25238
|
-
|
|
25239
|
-
|
|
25240
|
-
|
|
25241
|
-
|
|
25106
|
+
function isMcpToolCallApproval(meta) {
|
|
25107
|
+
return isRecord2(meta) && meta["codex_approval_kind"] === "mcp_tool_call";
|
|
25108
|
+
}
|
|
25109
|
+
function mcpPermissionOptions(isToolApproval, persist) {
|
|
25110
|
+
const options = [permissionOption(isToolApproval ? McpOptionId.AllowOnce : McpOptionId.Accept, "Allow", "allow_once", isToolApproval ? "Run the tool and continue." : "Allow this request and continue.")];
|
|
25111
|
+
if (persist.has("session")) {
|
|
25112
|
+
options.push(permissionOption(McpOptionId.AllowSession, "Allow for this session", "allow_always", isToolApproval ? "Run the tool and remember this choice for this session." : "Allow this request and remember this choice for this session."));
|
|
25242
25113
|
}
|
|
25243
|
-
if (
|
|
25244
|
-
|
|
25245
|
-
return false;
|
|
25246
|
-
}
|
|
25247
|
-
return true;
|
|
25114
|
+
if (persist.has("always")) {
|
|
25115
|
+
options.push(permissionOption(McpOptionId.AllowAlways, "Always allow", "allow_always", isToolApproval ? "Run the tool and remember this choice for future tool calls." : "Allow this request and remember this choice for future requests."));
|
|
25248
25116
|
}
|
|
25249
|
-
|
|
25250
|
-
|
|
25251
|
-
return !isInsideContainer();
|
|
25252
|
-
}
|
|
25253
|
-
} catch {}
|
|
25254
|
-
if (fs4.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs4.existsSync("/run/WSL")) {
|
|
25255
|
-
return !isInsideContainer();
|
|
25117
|
+
if (!isToolApproval) {
|
|
25118
|
+
options.push(permissionOption(McpOptionId.Decline, "Deny", "reject_once", "Decline this request and continue."));
|
|
25256
25119
|
}
|
|
25257
|
-
|
|
25258
|
-
|
|
25259
|
-
|
|
25260
|
-
|
|
25261
|
-
|
|
25262
|
-
|
|
25263
|
-
|
|
25264
|
-
|
|
25265
|
-
|
|
25266
|
-
|
|
25267
|
-
|
|
25268
|
-
|
|
25269
|
-
|
|
25270
|
-
|
|
25271
|
-
|
|
25272
|
-
|
|
25273
|
-
|
|
25274
|
-
|
|
25275
|
-
|
|
25276
|
-
|
|
25277
|
-
|
|
25278
|
-
|
|
25279
|
-
|
|
25280
|
-
|
|
25281
|
-
};
|
|
25282
|
-
|
|
25283
|
-
|
|
25284
|
-
|
|
25285
|
-
|
|
25286
|
-
|
|
25287
|
-
|
|
25288
|
-
|
|
25289
|
-
|
|
25290
|
-
|
|
25291
|
-
|
|
25292
|
-
|
|
25293
|
-
|
|
25294
|
-
|
|
25295
|
-
|
|
25296
|
-
|
|
25297
|
-
|
|
25298
|
-
|
|
25299
|
-
|
|
25300
|
-
|
|
25301
|
-
|
|
25302
|
-
|
|
25303
|
-
|
|
25120
|
+
options.push(permissionOption(McpOptionId.Cancel, "Cancel", "reject_once", isToolApproval ? "Cancel this tool call." : "Cancel this request."));
|
|
25121
|
+
return options;
|
|
25122
|
+
}
|
|
25123
|
+
function mcpPermissionRequest(params, context, nextStandaloneToolCallId) {
|
|
25124
|
+
const message = { type: "content", content: { type: "text", text: params.message } };
|
|
25125
|
+
const options = mcpPermissionOptions(context.isToolApproval, context.persistOptions);
|
|
25126
|
+
const title = context.isToolApproval ? `Allow MCP tool call on ${params.serverName}?` : `${params.serverName} requests approval`;
|
|
25127
|
+
if (params.mode === "url") {
|
|
25128
|
+
return {
|
|
25129
|
+
title,
|
|
25130
|
+
description: params.message,
|
|
25131
|
+
subject: {
|
|
25132
|
+
type: "tool_call",
|
|
25133
|
+
toolCall: {
|
|
25134
|
+
toolCallId: `elicitation:${params.elicitationId}`,
|
|
25135
|
+
name: ToolName.Mcp,
|
|
25136
|
+
kind: "fetch",
|
|
25137
|
+
status: "pending",
|
|
25138
|
+
title: `Open ${params.url}`,
|
|
25139
|
+
content: [message],
|
|
25140
|
+
rawInput: { serverName: params.serverName, url: params.url }
|
|
25141
|
+
}
|
|
25142
|
+
},
|
|
25143
|
+
options
|
|
25144
|
+
};
|
|
25145
|
+
}
|
|
25146
|
+
if (context.correlatedCallId !== undefined) {
|
|
25147
|
+
return {
|
|
25148
|
+
title,
|
|
25149
|
+
description: params.message,
|
|
25150
|
+
subject: { type: "tool_call", toolCall: { toolCallId: context.correlatedCallId, status: "pending" } },
|
|
25151
|
+
options
|
|
25152
|
+
};
|
|
25153
|
+
}
|
|
25154
|
+
return {
|
|
25155
|
+
title,
|
|
25156
|
+
description: params.message,
|
|
25157
|
+
subject: {
|
|
25158
|
+
type: "tool_call",
|
|
25159
|
+
toolCall: {
|
|
25160
|
+
toolCallId: nextStandaloneToolCallId(),
|
|
25161
|
+
name: ToolName.Mcp,
|
|
25162
|
+
kind: context.isToolApproval ? "execute" : "other",
|
|
25163
|
+
status: "pending",
|
|
25164
|
+
title,
|
|
25165
|
+
content: [message],
|
|
25166
|
+
rawInput: { serverName: params.serverName, schema: params.requestedSchema }
|
|
25167
|
+
}
|
|
25168
|
+
},
|
|
25169
|
+
options
|
|
25170
|
+
};
|
|
25171
|
+
}
|
|
25172
|
+
function mcpPermissionResponse(response, isToolApproval, persist) {
|
|
25173
|
+
if (response.outcome.outcome !== "selected")
|
|
25174
|
+
return cancelled();
|
|
25175
|
+
switch (response.outcome.optionId) {
|
|
25176
|
+
case McpOptionId.AllowSession:
|
|
25177
|
+
return persist.has("session") ? accepted({ persist: "session" }) : cancelled();
|
|
25178
|
+
case McpOptionId.AllowAlways:
|
|
25179
|
+
return persist.has("always") ? accepted({ persist: "always" }) : cancelled();
|
|
25180
|
+
case McpOptionId.AllowOnce:
|
|
25181
|
+
return isToolApproval ? accepted(null) : cancelled();
|
|
25182
|
+
case McpOptionId.Accept:
|
|
25183
|
+
return isToolApproval ? cancelled() : accepted(null);
|
|
25184
|
+
case McpOptionId.Decline:
|
|
25185
|
+
return isToolApproval ? cancelled() : { action: "decline", content: null, _meta: null };
|
|
25186
|
+
default:
|
|
25187
|
+
return cancelled();
|
|
25304
25188
|
}
|
|
25305
25189
|
}
|
|
25190
|
+
function accepted(meta) {
|
|
25191
|
+
return { action: "accept", content: null, _meta: meta };
|
|
25192
|
+
}
|
|
25193
|
+
function cancelled() {
|
|
25194
|
+
return { action: "cancel", content: null, _meta: null };
|
|
25195
|
+
}
|
|
25306
25196
|
|
|
25307
|
-
//
|
|
25308
|
-
var
|
|
25309
|
-
|
|
25310
|
-
|
|
25311
|
-
|
|
25312
|
-
|
|
25313
|
-
|
|
25314
|
-
|
|
25197
|
+
// src/permissions/ElicitationHandler.ts
|
|
25198
|
+
var OTHER_SUFFIX = "__other";
|
|
25199
|
+
|
|
25200
|
+
class CodexElicitationHandler {
|
|
25201
|
+
client;
|
|
25202
|
+
turn;
|
|
25203
|
+
signal;
|
|
25204
|
+
pendingUrlElicitations = new Set;
|
|
25205
|
+
constructor(client, turn, signal = () => {
|
|
25206
|
+
return;
|
|
25207
|
+
}) {
|
|
25208
|
+
this.client = client;
|
|
25209
|
+
this.turn = turn;
|
|
25210
|
+
this.signal = signal;
|
|
25211
|
+
}
|
|
25212
|
+
async observe(notification) {
|
|
25213
|
+
if (notification.method !== "serverRequest/resolved")
|
|
25214
|
+
return;
|
|
25215
|
+
const ids = [...this.pendingUrlElicitations];
|
|
25216
|
+
this.pendingUrlElicitations.clear();
|
|
25217
|
+
for (const elicitationId of ids) {
|
|
25218
|
+
await this.client.completeElicitation(elicitationId);
|
|
25315
25219
|
}
|
|
25316
|
-
|
|
25317
|
-
|
|
25220
|
+
}
|
|
25221
|
+
async handleElicitation(params) {
|
|
25318
25222
|
try {
|
|
25319
|
-
|
|
25320
|
-
|
|
25321
|
-
|
|
25322
|
-
|
|
25323
|
-
|
|
25324
|
-
|
|
25325
|
-
|
|
25326
|
-
|
|
25327
|
-
|
|
25328
|
-
|
|
25223
|
+
if (params.mode === "openai/userVerification") {
|
|
25224
|
+
logger.log("MCP user verification is not supported over ACP", { server: params.serverName });
|
|
25225
|
+
return cancelled();
|
|
25226
|
+
}
|
|
25227
|
+
const context = this.mcpContext(params);
|
|
25228
|
+
const messageOnly = isMessageOnlyForm(params);
|
|
25229
|
+
if (!messageOnly && this.useAcpElicitation(params)) {
|
|
25230
|
+
const response2 = await this.client.createElicitation(this.elicitationRequest(params, context), this.signal());
|
|
25231
|
+
const result2 = convertMcpElicitationResponse(response2, context);
|
|
25232
|
+
if (params.mode === "url" && result2.action === "accept")
|
|
25233
|
+
this.pendingUrlElicitations.add(params.elicitationId);
|
|
25234
|
+
if (result2.action === "accept")
|
|
25235
|
+
await this.markCorrelatedCallRunning(context);
|
|
25236
|
+
return result2;
|
|
25237
|
+
}
|
|
25238
|
+
if (params.mode !== "url" && !messageOnly) {
|
|
25239
|
+
return cancelled();
|
|
25240
|
+
}
|
|
25241
|
+
const request = mcpPermissionRequest(params, context, () => this.turn.nextStandaloneToolCallId(params.serverName));
|
|
25242
|
+
const response = await this.client.requestPermission(request, this.signal());
|
|
25243
|
+
const result = mcpPermissionResponse(response, context.isToolApproval, context.persistOptions);
|
|
25244
|
+
if (result.action === "accept")
|
|
25245
|
+
await this.markCorrelatedCallRunning(context);
|
|
25246
|
+
return result;
|
|
25247
|
+
} catch (error40) {
|
|
25248
|
+
logger.error("MCP elicitation failed", error40, { server: params.serverName });
|
|
25249
|
+
return cancelled();
|
|
25329
25250
|
}
|
|
25330
|
-
|
|
25331
|
-
|
|
25332
|
-
|
|
25333
|
-
|
|
25334
|
-
})();
|
|
25335
|
-
var powerShellPathFromWsl = async () => {
|
|
25336
|
-
const mountPoint = await wslDrivesMountPoint();
|
|
25337
|
-
return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
|
|
25338
|
-
};
|
|
25339
|
-
var powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
|
|
25340
|
-
var canAccessPowerShellPromise;
|
|
25341
|
-
var canAccessPowerShell = async () => {
|
|
25342
|
-
canAccessPowerShellPromise ??= (async () => {
|
|
25251
|
+
}
|
|
25252
|
+
async handleUserInput(params) {
|
|
25253
|
+
if (!this.client.capabilities.formElicitation)
|
|
25254
|
+
return { answers: {} };
|
|
25343
25255
|
try {
|
|
25344
|
-
const
|
|
25345
|
-
|
|
25346
|
-
|
|
25347
|
-
|
|
25348
|
-
return
|
|
25349
|
-
}
|
|
25350
|
-
})();
|
|
25351
|
-
return canAccessPowerShellPromise;
|
|
25352
|
-
};
|
|
25353
|
-
var wslDefaultBrowser = async () => {
|
|
25354
|
-
const psPath = await powerShellPath2();
|
|
25355
|
-
const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
|
|
25356
|
-
const { stdout } = await executePowerShell(command, {
|
|
25357
|
-
powerShellPath: psPath,
|
|
25358
|
-
cwd: path4.dirname(psPath)
|
|
25359
|
-
});
|
|
25360
|
-
return stdout.trim();
|
|
25361
|
-
};
|
|
25362
|
-
var isUrl = (path5) => /^[a-z]+:\/\//i.test(path5);
|
|
25363
|
-
var convertWslPathToWindows = async (paths) => {
|
|
25364
|
-
const isBatch = Array.isArray(paths);
|
|
25365
|
-
const pathArray = isBatch ? paths : [paths];
|
|
25366
|
-
const indicesToConvert = [];
|
|
25367
|
-
const pathsToConvert = [];
|
|
25368
|
-
for (const [index, path5] of pathArray.entries()) {
|
|
25369
|
-
if (!isUrl(path5)) {
|
|
25370
|
-
indicesToConvert.push(index);
|
|
25371
|
-
pathsToConvert.push(path5);
|
|
25256
|
+
const response = await this.client.createElicitation(userInputRequest(this.client.sessionId, params), this.signal());
|
|
25257
|
+
return convertUserInputResponse(response, params);
|
|
25258
|
+
} catch (error40) {
|
|
25259
|
+
logger.error("user input request failed", error40, { itemId: params.itemId });
|
|
25260
|
+
return { answers: {} };
|
|
25372
25261
|
}
|
|
25373
25262
|
}
|
|
25374
|
-
|
|
25375
|
-
|
|
25376
|
-
|
|
25377
|
-
|
|
25378
|
-
|
|
25379
|
-
|
|
25380
|
-
|
|
25381
|
-
}
|
|
25382
|
-
} catch {}
|
|
25263
|
+
mcpContext(params) {
|
|
25264
|
+
const isToolApproval = isMcpToolCallApproval(params._meta) && isMessageOnlyForm(params);
|
|
25265
|
+
return {
|
|
25266
|
+
isToolApproval,
|
|
25267
|
+
persistOptions: parsePersistOptions(params._meta),
|
|
25268
|
+
correlatedCallId: isToolApproval ? this.turn.popPendingMcpCall(params.serverName) : undefined
|
|
25269
|
+
};
|
|
25383
25270
|
}
|
|
25384
|
-
|
|
25385
|
-
|
|
25386
|
-
|
|
25387
|
-
|
|
25388
|
-
|
|
25389
|
-
|
|
25390
|
-
|
|
25391
|
-
|
|
25392
|
-
|
|
25393
|
-
|
|
25394
|
-
|
|
25395
|
-
|
|
25396
|
-
|
|
25397
|
-
|
|
25398
|
-
|
|
25399
|
-
|
|
25400
|
-
];
|
|
25401
|
-
var encodeCommand = (command) => Buffer3.from(command, "utf16le").toString("base64");
|
|
25402
|
-
var escapeArgument = (value) => `'${String(value).replaceAll(/['\u2018\u2019\u201A\u201B]/g, (match) => match + match)}'`;
|
|
25403
|
-
var createArguments = (command) => [...argumentsPrefix, encodeCommand(command)];
|
|
25404
|
-
var createExecFileOptions = (options) => ({
|
|
25405
|
-
encoding: "utf8",
|
|
25406
|
-
...options,
|
|
25407
|
-
shell: false
|
|
25408
|
-
});
|
|
25409
|
-
var executePowerShell2 = async (command, options = {}) => {
|
|
25410
|
-
const {
|
|
25411
|
-
powerShellPath: psPath,
|
|
25412
|
-
...execFileOptions
|
|
25413
|
-
} = options;
|
|
25414
|
-
return execFile3(psPath ?? powerShellPath3(), createArguments(command), createExecFileOptions(execFileOptions));
|
|
25415
|
-
};
|
|
25416
|
-
executePowerShell2.argumentsPrefix = argumentsPrefix;
|
|
25417
|
-
executePowerShell2.encodeCommand = encodeCommand;
|
|
25418
|
-
executePowerShell2.escapeArgument = escapeArgument;
|
|
25419
|
-
executePowerShell2.createArguments = createArguments;
|
|
25420
|
-
|
|
25421
|
-
// node_modules/define-lazy-prop/index.js
|
|
25422
|
-
function defineLazyProperty(object2, propertyName, valueGetter) {
|
|
25423
|
-
const define = (value) => Object.defineProperty(object2, propertyName, { value, enumerable: true, writable: true });
|
|
25424
|
-
Object.defineProperty(object2, propertyName, {
|
|
25425
|
-
configurable: true,
|
|
25426
|
-
enumerable: true,
|
|
25427
|
-
get() {
|
|
25428
|
-
const result = valueGetter();
|
|
25429
|
-
define(result);
|
|
25430
|
-
return result;
|
|
25431
|
-
},
|
|
25432
|
-
set(value) {
|
|
25433
|
-
define(value);
|
|
25271
|
+
useAcpElicitation(params) {
|
|
25272
|
+
if (params.mode === "form")
|
|
25273
|
+
return this.client.capabilities.formElicitation;
|
|
25274
|
+
if (params.mode === "url")
|
|
25275
|
+
return this.client.capabilities.urlElicitation;
|
|
25276
|
+
return false;
|
|
25277
|
+
}
|
|
25278
|
+
elicitationRequest(params, context) {
|
|
25279
|
+
const base = {
|
|
25280
|
+
sessionId: this.client.sessionId,
|
|
25281
|
+
...context.correlatedCallId ? { toolCallId: context.correlatedCallId } : {},
|
|
25282
|
+
message: params.message,
|
|
25283
|
+
_meta: recordOrNull(params._meta)
|
|
25284
|
+
};
|
|
25285
|
+
if (params.mode === "form") {
|
|
25286
|
+
return { ...base, mode: "form", requestedSchema: normalizeSchema(params.requestedSchema) };
|
|
25434
25287
|
}
|
|
25435
|
-
|
|
25436
|
-
|
|
25288
|
+
return { ...base, mode: "url", url: params.url, elicitationId: params.elicitationId };
|
|
25289
|
+
}
|
|
25290
|
+
async markCorrelatedCallRunning(context) {
|
|
25291
|
+
if (context.correlatedCallId === undefined)
|
|
25292
|
+
return;
|
|
25293
|
+
await this.client.update({ sessionUpdate: "tool_call_update", toolCallId: context.correlatedCallId, status: "in_progress" });
|
|
25294
|
+
}
|
|
25295
|
+
}
|
|
25296
|
+
function isMessageOnlyForm(params) {
|
|
25297
|
+
if (params.mode !== "form" && params.mode !== "openai/form" && params.mode !== "openaiForm")
|
|
25298
|
+
return false;
|
|
25299
|
+
const schema = params.requestedSchema;
|
|
25300
|
+
if (schema === null)
|
|
25301
|
+
return true;
|
|
25302
|
+
if (!isRecord2(schema))
|
|
25303
|
+
return false;
|
|
25304
|
+
return schema["type"] === "object" && isRecord2(schema["properties"]) && Object.keys(schema["properties"]).length === 0;
|
|
25305
|
+
}
|
|
25306
|
+
function normalizeSchema(value) {
|
|
25307
|
+
const normalized = normalizeSchemaValue(value);
|
|
25308
|
+
if (!isRecord2(normalized))
|
|
25309
|
+
return { type: "object", properties: {} };
|
|
25310
|
+
return { ...normalized, type: "object" };
|
|
25437
25311
|
}
|
|
25438
|
-
|
|
25439
|
-
|
|
25440
|
-
|
|
25441
|
-
|
|
25442
|
-
|
|
25443
|
-
|
|
25444
|
-
|
|
25445
|
-
|
|
25446
|
-
|
|
25447
|
-
|
|
25448
|
-
|
|
25449
|
-
|
|
25450
|
-
|
|
25451
|
-
|
|
25312
|
+
function normalizeSchemaValue(value) {
|
|
25313
|
+
if (typeof value === "bigint")
|
|
25314
|
+
return Number(value);
|
|
25315
|
+
if (Array.isArray(value))
|
|
25316
|
+
return value.map(normalizeSchemaValue);
|
|
25317
|
+
if (!isRecord2(value))
|
|
25318
|
+
return value;
|
|
25319
|
+
const result = Object.fromEntries(Object.entries(value).filter(([, nested]) => nested !== undefined).map(([key, nested]) => [key, normalizeSchemaValue(nested)]));
|
|
25320
|
+
if (result["type"] === "string" && Array.isArray(result["enum"]) && Array.isArray(result["enumNames"]) && !Array.isArray(result["oneOf"])) {
|
|
25321
|
+
const values = result["enum"];
|
|
25322
|
+
const names = result["enumNames"];
|
|
25323
|
+
result["oneOf"] = values.map((entry, index) => ({ const: String(entry), title: String(names[index] ?? entry) }));
|
|
25324
|
+
delete result["enum"];
|
|
25325
|
+
delete result["enumNames"];
|
|
25452
25326
|
}
|
|
25453
|
-
|
|
25454
|
-
|
|
25455
|
-
|
|
25456
|
-
if (
|
|
25457
|
-
|
|
25327
|
+
return result;
|
|
25328
|
+
}
|
|
25329
|
+
function convertMcpElicitationResponse(response, context) {
|
|
25330
|
+
if (CreateElicitationResponse.isAccept(response)) {
|
|
25331
|
+
const content = isRecord2(response.content) ? { ...response.content } : {};
|
|
25332
|
+
const persist = context.isToolApproval ? content["persist"] : undefined;
|
|
25333
|
+
if (context.isToolApproval && !persistAllowed(persist, context.persistOptions))
|
|
25334
|
+
return cancelled();
|
|
25335
|
+
if (persist === "session" || persist === "always" || persist === "once")
|
|
25336
|
+
delete content["persist"];
|
|
25337
|
+
return { action: "accept", content: contentOrNull(content), _meta: responseMeta(response, context, persist) };
|
|
25458
25338
|
}
|
|
25459
|
-
|
|
25339
|
+
if (CreateElicitationResponse.isDecline(response)) {
|
|
25340
|
+
return context.isToolApproval ? { action: "cancel", content: null, _meta: responseMeta(response, context) } : { action: "decline", content: null, _meta: responseMeta(response, context) };
|
|
25341
|
+
}
|
|
25342
|
+
if (CreateElicitationResponse.isCancel(response)) {
|
|
25343
|
+
return { action: "cancel", content: null, _meta: responseMeta(response, context) };
|
|
25344
|
+
}
|
|
25345
|
+
return cancelled();
|
|
25460
25346
|
}
|
|
25461
|
-
|
|
25462
|
-
|
|
25463
|
-
|
|
25464
|
-
|
|
25465
|
-
|
|
25466
|
-
|
|
25467
|
-
|
|
25468
|
-
|
|
25469
|
-
|
|
25347
|
+
function persistAllowed(persist, options) {
|
|
25348
|
+
return persist === undefined || persist === "once" || persist === "session" && options.has("session") || persist === "always" && options.has("always");
|
|
25349
|
+
}
|
|
25350
|
+
function contentOrNull(content) {
|
|
25351
|
+
const entries = Object.entries(content);
|
|
25352
|
+
if (entries.length === 0)
|
|
25353
|
+
return null;
|
|
25354
|
+
return Object.fromEntries(entries.map(([key, value]) => [key, normalizeJsonValue(value)]));
|
|
25355
|
+
}
|
|
25356
|
+
function responseMeta(response, context, persist) {
|
|
25357
|
+
const source = recordOrNull(response._meta);
|
|
25358
|
+
const meta = source ? normalizeJsonObject(source) : {};
|
|
25359
|
+
if (context.isToolApproval)
|
|
25360
|
+
delete meta["persist"];
|
|
25361
|
+
if (persist === "session" || persist === "always")
|
|
25362
|
+
meta["persist"] = persist;
|
|
25363
|
+
return Object.keys(meta).length === 0 ? null : meta;
|
|
25364
|
+
}
|
|
25365
|
+
function userInputRequest(sessionId, params) {
|
|
25366
|
+
const properties = {};
|
|
25367
|
+
const required2 = [];
|
|
25368
|
+
const ids = new Set(params.questions.map((question) => question.id));
|
|
25369
|
+
for (const question of params.questions) {
|
|
25370
|
+
const options = question.options ?? [];
|
|
25371
|
+
const hasOther = question.isOther && options.length > 0;
|
|
25372
|
+
const base = {
|
|
25373
|
+
title: question.header || question.id,
|
|
25374
|
+
description: question.question,
|
|
25375
|
+
_meta: { codex: { isOther: question.isOther, isSecret: question.isSecret } }
|
|
25376
|
+
};
|
|
25377
|
+
if (!hasOther)
|
|
25378
|
+
required2.push(question.id);
|
|
25379
|
+
properties[question.id] = options.length > 0 ? { ...base, type: "string", oneOf: options.map((option) => ({ const: option.label, title: option.label, description: option.description })) } : { ...base, type: "string" };
|
|
25380
|
+
if (hasOther) {
|
|
25381
|
+
properties[otherFieldId(question.id, ids)] = {
|
|
25382
|
+
type: "string",
|
|
25383
|
+
title: "Other",
|
|
25384
|
+
description: "Type your own answer instead of choosing an option above.",
|
|
25385
|
+
_meta: { codex: { questionId: question.id, isOtherAnswer: true, isSecret: question.isSecret } }
|
|
25386
|
+
};
|
|
25387
|
+
}
|
|
25470
25388
|
}
|
|
25471
|
-
const
|
|
25472
|
-
|
|
25473
|
-
|
|
25474
|
-
|
|
25389
|
+
const first = params.questions[0];
|
|
25390
|
+
return {
|
|
25391
|
+
sessionId,
|
|
25392
|
+
toolCallId: params.itemId,
|
|
25393
|
+
mode: "form",
|
|
25394
|
+
message: params.questions.length === 1 && first ? first.question : "Input requested",
|
|
25395
|
+
requestedSchema: { type: "object", properties, required: required2 },
|
|
25396
|
+
_meta: { codex: { isBlocking: params.isBlocking } }
|
|
25397
|
+
};
|
|
25398
|
+
}
|
|
25399
|
+
function convertUserInputResponse(response, params) {
|
|
25400
|
+
if (!CreateElicitationResponse.isAccept(response))
|
|
25401
|
+
return { answers: {} };
|
|
25402
|
+
const content = isRecord2(response.content) ? response.content : {};
|
|
25403
|
+
const ids = new Set(params.questions.map((question) => question.id));
|
|
25404
|
+
const answers = {};
|
|
25405
|
+
for (const question of params.questions) {
|
|
25406
|
+
const hasOther = question.isOther && (question.options?.length ?? 0) > 0;
|
|
25407
|
+
const value = (hasOther ? answerValue(content, otherFieldId(question.id, ids)) : undefined) ?? answerValue(content, question.id);
|
|
25408
|
+
if (value === undefined)
|
|
25409
|
+
continue;
|
|
25410
|
+
answers[question.id] = { answers: Array.isArray(value) ? value.map(String) : [String(value)] };
|
|
25475
25411
|
}
|
|
25476
|
-
|
|
25477
|
-
return stdout.trim();
|
|
25412
|
+
return { answers };
|
|
25478
25413
|
}
|
|
25479
|
-
|
|
25480
|
-
|
|
25481
|
-
|
|
25482
|
-
|
|
25483
|
-
|
|
25414
|
+
function answerValue(content, fieldId) {
|
|
25415
|
+
const value = content[fieldId];
|
|
25416
|
+
if (typeof value === "string" && value.trim() === "")
|
|
25417
|
+
return;
|
|
25418
|
+
if (Array.isArray(value) && value.length === 0)
|
|
25419
|
+
return;
|
|
25420
|
+
return value;
|
|
25484
25421
|
}
|
|
25485
|
-
|
|
25486
|
-
|
|
25487
|
-
|
|
25488
|
-
|
|
25489
|
-
|
|
25490
|
-
|
|
25491
|
-
|
|
25492
|
-
|
|
25493
|
-
MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
|
|
25494
|
-
MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
|
|
25495
|
-
AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
|
|
25496
|
-
ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
|
|
25497
|
-
ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
|
|
25498
|
-
ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
|
|
25499
|
-
ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
|
|
25500
|
-
BraveHTML: { name: "Brave", id: "com.brave.Browser" },
|
|
25501
|
-
BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
|
|
25502
|
-
BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
|
|
25503
|
-
BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
|
|
25504
|
-
FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
|
|
25505
|
-
OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
|
|
25506
|
-
VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
|
|
25507
|
-
"IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
|
|
25508
|
-
};
|
|
25509
|
-
var _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
|
|
25510
|
-
|
|
25511
|
-
class UnknownBrowserError extends Error {
|
|
25422
|
+
function otherFieldId(questionId, ids) {
|
|
25423
|
+
const base = `${questionId}${OTHER_SUFFIX}`;
|
|
25424
|
+
if (!ids.has(base))
|
|
25425
|
+
return base;
|
|
25426
|
+
let index = 1;
|
|
25427
|
+
while (ids.has(`${base}${index}`))
|
|
25428
|
+
index += 1;
|
|
25429
|
+
return `${base}${index}`;
|
|
25512
25430
|
}
|
|
25513
|
-
|
|
25514
|
-
|
|
25515
|
-
|
|
25516
|
-
|
|
25517
|
-
|
|
25518
|
-
|
|
25519
|
-
|
|
25520
|
-
|
|
25521
|
-
|
|
25522
|
-
|
|
25523
|
-
|
|
25431
|
+
|
|
25432
|
+
// src/permissions/turnContext.ts
|
|
25433
|
+
class TurnContext {
|
|
25434
|
+
sessionId;
|
|
25435
|
+
fileChanges = new Map;
|
|
25436
|
+
pendingMcpCalls = new Map;
|
|
25437
|
+
sequence = 0;
|
|
25438
|
+
constructor(sessionId) {
|
|
25439
|
+
this.sessionId = sessionId;
|
|
25440
|
+
}
|
|
25441
|
+
observe(notification) {
|
|
25442
|
+
switch (notification.method) {
|
|
25443
|
+
case "item/started":
|
|
25444
|
+
this.itemStarted(notification.params.item);
|
|
25445
|
+
return;
|
|
25446
|
+
case "item/completed":
|
|
25447
|
+
this.itemCompleted(notification.params.item);
|
|
25448
|
+
return;
|
|
25449
|
+
case "turn/completed":
|
|
25450
|
+
this.fileChanges.clear();
|
|
25451
|
+
this.pendingMcpCalls.clear();
|
|
25452
|
+
return;
|
|
25453
|
+
case "serverRequest/resolved":
|
|
25454
|
+
this.pendingMcpCalls.clear();
|
|
25455
|
+
return;
|
|
25456
|
+
default:
|
|
25457
|
+
return;
|
|
25458
|
+
}
|
|
25459
|
+
}
|
|
25460
|
+
fileChange(itemId) {
|
|
25461
|
+
return this.fileChanges.get(itemId);
|
|
25462
|
+
}
|
|
25463
|
+
popPendingMcpCall(serverName) {
|
|
25464
|
+
const pending = this.pendingMcpCalls.get(serverName);
|
|
25465
|
+
if (pending?.length !== 1)
|
|
25466
|
+
return;
|
|
25467
|
+
this.pendingMcpCalls.delete(serverName);
|
|
25468
|
+
return pending[0];
|
|
25469
|
+
}
|
|
25470
|
+
nextStandaloneToolCallId(serverName) {
|
|
25471
|
+
this.sequence += 1;
|
|
25472
|
+
return `elicitation:${this.sessionId}:${serverName}:${this.sequence}`;
|
|
25473
|
+
}
|
|
25474
|
+
itemStarted(item) {
|
|
25475
|
+
if (item.type === "fileChange") {
|
|
25476
|
+
this.fileChanges.set(item.id, item);
|
|
25477
|
+
} else if (item.type === "mcpToolCall") {
|
|
25478
|
+
const pending = this.pendingMcpCalls.get(item.server) ?? [];
|
|
25479
|
+
pending.push(item.id);
|
|
25480
|
+
this.pendingMcpCalls.set(item.server, pending);
|
|
25481
|
+
}
|
|
25482
|
+
}
|
|
25483
|
+
itemCompleted(item) {
|
|
25484
|
+
if (item.type === "fileChange") {
|
|
25485
|
+
this.fileChanges.delete(item.id);
|
|
25486
|
+
} else if (item.type === "mcpToolCall") {
|
|
25487
|
+
const pending = this.pendingMcpCalls.get(item.server);
|
|
25488
|
+
if (!pending)
|
|
25489
|
+
return;
|
|
25490
|
+
const index = pending.indexOf(item.id);
|
|
25491
|
+
if (index >= 0)
|
|
25492
|
+
pending.splice(index, 1);
|
|
25493
|
+
if (pending.length === 0)
|
|
25494
|
+
this.pendingMcpCalls.delete(item.server);
|
|
25495
|
+
}
|
|
25524
25496
|
}
|
|
25525
|
-
const { id } = match.groups;
|
|
25526
|
-
const dotIndex = id.lastIndexOf(".");
|
|
25527
|
-
const hyphenIndex = id.lastIndexOf("-");
|
|
25528
|
-
const baseIdByDot = dotIndex === -1 ? undefined : id.slice(0, dotIndex);
|
|
25529
|
-
const baseIdByHyphen = hyphenIndex === -1 ? undefined : id.slice(0, hyphenIndex);
|
|
25530
|
-
return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
|
|
25531
25497
|
}
|
|
25532
25498
|
|
|
25533
|
-
// node_modules/
|
|
25534
|
-
|
|
25535
|
-
|
|
25536
|
-
|
|
25537
|
-
|
|
25538
|
-
|
|
25539
|
-
|
|
25540
|
-
|
|
25499
|
+
// node_modules/open/index.js
|
|
25500
|
+
import process10 from "process";
|
|
25501
|
+
import path6 from "path";
|
|
25502
|
+
import { fileURLToPath } from "url";
|
|
25503
|
+
import childProcess4 from "child_process";
|
|
25504
|
+
import fs6, { constants as fsConstants2 } from "fs/promises";
|
|
25505
|
+
|
|
25506
|
+
// node_modules/wsl-utils/index.js
|
|
25507
|
+
import path5 from "path";
|
|
25508
|
+
import { promisify as promisify2 } from "util";
|
|
25509
|
+
import childProcess2 from "child_process";
|
|
25510
|
+
import fs5, { constants as fsConstants } from "fs/promises";
|
|
25511
|
+
|
|
25512
|
+
// node_modules/is-wsl/index.js
|
|
25513
|
+
import process2 from "process";
|
|
25514
|
+
import os2 from "os";
|
|
25515
|
+
import fs4 from "fs";
|
|
25516
|
+
|
|
25517
|
+
// node_modules/is-inside-container/index.js
|
|
25518
|
+
import fs3 from "fs";
|
|
25519
|
+
|
|
25520
|
+
// node_modules/is-docker/index.js
|
|
25521
|
+
import fs2 from "fs";
|
|
25522
|
+
var isDockerCached;
|
|
25523
|
+
function hasDockerEnv() {
|
|
25524
|
+
try {
|
|
25525
|
+
fs2.statSync("/.dockerenv");
|
|
25526
|
+
return true;
|
|
25527
|
+
} catch {
|
|
25528
|
+
return false;
|
|
25541
25529
|
}
|
|
25542
|
-
|
|
25543
|
-
|
|
25544
|
-
|
|
25545
|
-
|
|
25546
|
-
|
|
25530
|
+
}
|
|
25531
|
+
function hasDockerCGroup() {
|
|
25532
|
+
try {
|
|
25533
|
+
return fs2.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
25534
|
+
} catch {
|
|
25535
|
+
return false;
|
|
25547
25536
|
}
|
|
25548
|
-
|
|
25549
|
-
|
|
25537
|
+
}
|
|
25538
|
+
function isDocker() {
|
|
25539
|
+
if (isDockerCached === undefined) {
|
|
25540
|
+
isDockerCached = hasDockerEnv() || hasDockerCGroup();
|
|
25550
25541
|
}
|
|
25551
|
-
|
|
25542
|
+
return isDockerCached;
|
|
25552
25543
|
}
|
|
25553
25544
|
|
|
25554
|
-
// node_modules/is-
|
|
25555
|
-
|
|
25556
|
-
var
|
|
25557
|
-
|
|
25558
|
-
|
|
25559
|
-
|
|
25560
|
-
|
|
25561
|
-
|
|
25562
|
-
var localXdgOpenPath = path5.join(__dirname2, "xdg-open");
|
|
25563
|
-
var { platform, arch } = process10;
|
|
25564
|
-
var tryEachApp = async (apps, opener) => {
|
|
25565
|
-
if (apps.length === 0) {
|
|
25566
|
-
return;
|
|
25567
|
-
}
|
|
25568
|
-
const errors3 = [];
|
|
25569
|
-
for (const app of apps) {
|
|
25570
|
-
try {
|
|
25571
|
-
return await opener(app);
|
|
25572
|
-
} catch (error40) {
|
|
25573
|
-
errors3.push(error40);
|
|
25574
|
-
}
|
|
25545
|
+
// node_modules/is-inside-container/index.js
|
|
25546
|
+
var cachedResult;
|
|
25547
|
+
var hasContainerEnv = () => {
|
|
25548
|
+
try {
|
|
25549
|
+
fs3.statSync("/run/.containerenv");
|
|
25550
|
+
return true;
|
|
25551
|
+
} catch {
|
|
25552
|
+
return false;
|
|
25575
25553
|
}
|
|
25576
|
-
throw new AggregateError(errors3, "Failed to open in all supported apps");
|
|
25577
25554
|
};
|
|
25578
|
-
|
|
25579
|
-
|
|
25580
|
-
|
|
25581
|
-
background: false,
|
|
25582
|
-
newInstance: false,
|
|
25583
|
-
allowNonzeroExitCode: false,
|
|
25584
|
-
...options
|
|
25585
|
-
};
|
|
25586
|
-
const isFallbackAttempt = options[fallbackAttemptSymbol] === true;
|
|
25587
|
-
delete options[fallbackAttemptSymbol];
|
|
25588
|
-
if (Array.isArray(options.app)) {
|
|
25589
|
-
return tryEachApp(options.app, (singleApp) => baseOpen({
|
|
25590
|
-
...options,
|
|
25591
|
-
app: singleApp,
|
|
25592
|
-
[fallbackAttemptSymbol]: true
|
|
25593
|
-
}));
|
|
25555
|
+
function isInsideContainer() {
|
|
25556
|
+
if (cachedResult === undefined) {
|
|
25557
|
+
cachedResult = hasContainerEnv() || isDocker();
|
|
25594
25558
|
}
|
|
25595
|
-
|
|
25596
|
-
|
|
25597
|
-
|
|
25598
|
-
|
|
25599
|
-
|
|
25600
|
-
|
|
25601
|
-
|
|
25602
|
-
arguments: appArguments
|
|
25603
|
-
},
|
|
25604
|
-
[fallbackAttemptSymbol]: true
|
|
25605
|
-
}));
|
|
25559
|
+
return cachedResult;
|
|
25560
|
+
}
|
|
25561
|
+
|
|
25562
|
+
// node_modules/is-wsl/index.js
|
|
25563
|
+
var isWsl = () => {
|
|
25564
|
+
if (process2.platform !== "linux") {
|
|
25565
|
+
return false;
|
|
25606
25566
|
}
|
|
25607
|
-
if (
|
|
25608
|
-
|
|
25609
|
-
|
|
25610
|
-
"google-chrome.desktop": "chrome",
|
|
25611
|
-
"com.brave.browser": "brave",
|
|
25612
|
-
"org.mozilla.firefox": "firefox",
|
|
25613
|
-
"firefox.desktop": "firefox",
|
|
25614
|
-
"com.microsoft.msedge": "edge",
|
|
25615
|
-
"com.microsoft.edge": "edge",
|
|
25616
|
-
"com.microsoft.edgemac": "edge",
|
|
25617
|
-
"microsoft-edge.desktop": "edge",
|
|
25618
|
-
"com.apple.safari": "safari"
|
|
25619
|
-
};
|
|
25620
|
-
const flags = {
|
|
25621
|
-
chrome: "--incognito",
|
|
25622
|
-
brave: "--incognito",
|
|
25623
|
-
firefox: "--private-window",
|
|
25624
|
-
edge: "--inPrivate"
|
|
25625
|
-
};
|
|
25626
|
-
let browser;
|
|
25627
|
-
if (is_wsl_default) {
|
|
25628
|
-
const progId = await wslDefaultBrowser();
|
|
25629
|
-
const browserInfo = _windowsBrowserProgIdMap.get(progId);
|
|
25630
|
-
browser = browserInfo ?? {};
|
|
25631
|
-
} else {
|
|
25632
|
-
browser = await defaultBrowser2();
|
|
25633
|
-
}
|
|
25634
|
-
if (Object.hasOwn(ids, browser.id)) {
|
|
25635
|
-
const browserName = ids[browser.id.toLowerCase()];
|
|
25636
|
-
if (browserName === undefined) {
|
|
25637
|
-
throw new Error(`${browser.name} is not supported as a default browser`);
|
|
25638
|
-
}
|
|
25639
|
-
if (app === "browserPrivate") {
|
|
25640
|
-
if (browserName === "safari") {
|
|
25641
|
-
throw new Error("Safari doesn't support opening in private mode via command line");
|
|
25642
|
-
}
|
|
25643
|
-
appArguments.push(flags[browserName]);
|
|
25644
|
-
}
|
|
25645
|
-
return baseOpen({
|
|
25646
|
-
...options,
|
|
25647
|
-
app: {
|
|
25648
|
-
name: apps[browserName],
|
|
25649
|
-
arguments: appArguments
|
|
25650
|
-
}
|
|
25651
|
-
});
|
|
25567
|
+
if (os2.release().toLowerCase().includes("microsoft")) {
|
|
25568
|
+
if (isInsideContainer()) {
|
|
25569
|
+
return false;
|
|
25652
25570
|
}
|
|
25653
|
-
|
|
25654
|
-
}
|
|
25655
|
-
let command;
|
|
25656
|
-
const cliArguments = [];
|
|
25657
|
-
const childProcessOptions = {};
|
|
25658
|
-
let shouldUseWindowsInWsl = false;
|
|
25659
|
-
if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
|
|
25660
|
-
shouldUseWindowsInWsl = await canAccessPowerShell();
|
|
25571
|
+
return true;
|
|
25661
25572
|
}
|
|
25662
|
-
|
|
25663
|
-
|
|
25664
|
-
|
|
25665
|
-
cliArguments.push("--wait-apps");
|
|
25666
|
-
}
|
|
25667
|
-
if (options.background) {
|
|
25668
|
-
cliArguments.push("--background");
|
|
25669
|
-
}
|
|
25670
|
-
if (options.newInstance) {
|
|
25671
|
-
cliArguments.push("--new");
|
|
25672
|
-
}
|
|
25673
|
-
if (app) {
|
|
25674
|
-
cliArguments.push("-a", app);
|
|
25675
|
-
}
|
|
25676
|
-
} else if (platform === "win32" || shouldUseWindowsInWsl) {
|
|
25677
|
-
command = await powerShellPath2();
|
|
25678
|
-
cliArguments.push(...executePowerShell2.argumentsPrefix);
|
|
25679
|
-
if (!is_wsl_default) {
|
|
25680
|
-
childProcessOptions.windowsVerbatimArguments = true;
|
|
25681
|
-
}
|
|
25682
|
-
if (is_wsl_default && options.target) {
|
|
25683
|
-
options.target = await convertWslPathToWindows(options.target);
|
|
25684
|
-
}
|
|
25685
|
-
const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
|
|
25686
|
-
if (options.wait) {
|
|
25687
|
-
encodedArguments.push("-Wait");
|
|
25688
|
-
}
|
|
25689
|
-
if (app) {
|
|
25690
|
-
encodedArguments.push(executePowerShell2.escapeArgument(app));
|
|
25691
|
-
if (options.target) {
|
|
25692
|
-
appArguments.push(options.target);
|
|
25693
|
-
}
|
|
25694
|
-
} else if (options.target) {
|
|
25695
|
-
encodedArguments.push(executePowerShell2.escapeArgument(options.target));
|
|
25573
|
+
try {
|
|
25574
|
+
if (fs4.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
|
|
25575
|
+
return !isInsideContainer();
|
|
25696
25576
|
}
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
25577
|
+
} catch {}
|
|
25578
|
+
if (fs4.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs4.existsSync("/run/WSL")) {
|
|
25579
|
+
return !isInsideContainer();
|
|
25580
|
+
}
|
|
25581
|
+
return false;
|
|
25582
|
+
};
|
|
25583
|
+
var is_wsl_default = process2.env.__IS_WSL_TEST__ ? isWsl : isWsl();
|
|
25584
|
+
|
|
25585
|
+
// node_modules/wsl-utils/node_modules/powershell-utils/index.js
|
|
25586
|
+
import process3 from "process";
|
|
25587
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
25588
|
+
import { promisify } from "util";
|
|
25589
|
+
import childProcess from "child_process";
|
|
25590
|
+
var execFile = promisify(childProcess.execFile);
|
|
25591
|
+
var powerShellPath = () => `${process3.env.SYSTEMROOT || process3.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
|
25592
|
+
var executePowerShell = async (command, options = {}) => {
|
|
25593
|
+
const {
|
|
25594
|
+
powerShellPath: psPath,
|
|
25595
|
+
...execFileOptions
|
|
25596
|
+
} = options;
|
|
25597
|
+
const encodedCommand = executePowerShell.encodeCommand(command);
|
|
25598
|
+
return execFile(psPath ?? powerShellPath(), [
|
|
25599
|
+
...executePowerShell.argumentsPrefix,
|
|
25600
|
+
encodedCommand
|
|
25601
|
+
], {
|
|
25602
|
+
encoding: "utf8",
|
|
25603
|
+
...execFileOptions
|
|
25604
|
+
});
|
|
25605
|
+
};
|
|
25606
|
+
executePowerShell.argumentsPrefix = [
|
|
25607
|
+
"-NoProfile",
|
|
25608
|
+
"-NonInteractive",
|
|
25609
|
+
"-ExecutionPolicy",
|
|
25610
|
+
"Bypass",
|
|
25611
|
+
"-EncodedCommand"
|
|
25612
|
+
];
|
|
25613
|
+
executePowerShell.encodeCommand = (command) => Buffer2.from(command, "utf16le").toString("base64");
|
|
25614
|
+
executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
|
|
25615
|
+
|
|
25616
|
+
// node_modules/wsl-utils/utilities.js
|
|
25617
|
+
function parseMountPointFromConfig(content) {
|
|
25618
|
+
for (const line of content.split(`
|
|
25619
|
+
`)) {
|
|
25620
|
+
if (/^\s*#/.test(line)) {
|
|
25621
|
+
continue;
|
|
25700
25622
|
}
|
|
25701
|
-
|
|
25702
|
-
if (!
|
|
25703
|
-
|
|
25623
|
+
const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
|
|
25624
|
+
if (!match) {
|
|
25625
|
+
continue;
|
|
25704
25626
|
}
|
|
25705
|
-
|
|
25706
|
-
|
|
25627
|
+
return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
|
|
25628
|
+
}
|
|
25629
|
+
}
|
|
25630
|
+
|
|
25631
|
+
// node_modules/wsl-utils/index.js
|
|
25632
|
+
var execFile2 = promisify2(childProcess2.execFile);
|
|
25633
|
+
var wslDrivesMountPoint = (() => {
|
|
25634
|
+
const defaultMountPoint = "/mnt/";
|
|
25635
|
+
let mountPoint;
|
|
25636
|
+
return async function() {
|
|
25637
|
+
if (mountPoint) {
|
|
25638
|
+
return mountPoint;
|
|
25707
25639
|
}
|
|
25708
|
-
|
|
25709
|
-
|
|
25710
|
-
|
|
25711
|
-
|
|
25712
|
-
|
|
25713
|
-
|
|
25714
|
-
|
|
25715
|
-
|
|
25716
|
-
exeLocalXdgOpen = true;
|
|
25717
|
-
} catch {}
|
|
25718
|
-
const useSystemXdgOpen = process10.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
|
|
25719
|
-
command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
|
|
25640
|
+
const configFilePath = "/etc/wsl.conf";
|
|
25641
|
+
let isConfigFileExists = false;
|
|
25642
|
+
try {
|
|
25643
|
+
await fs5.access(configFilePath, fsConstants.F_OK);
|
|
25644
|
+
isConfigFileExists = true;
|
|
25645
|
+
} catch {}
|
|
25646
|
+
if (!isConfigFileExists) {
|
|
25647
|
+
return defaultMountPoint;
|
|
25720
25648
|
}
|
|
25721
|
-
|
|
25722
|
-
|
|
25649
|
+
const configContent = await fs5.readFile(configFilePath, { encoding: "utf8" });
|
|
25650
|
+
const parsedMountPoint = parseMountPointFromConfig(configContent);
|
|
25651
|
+
if (parsedMountPoint === undefined) {
|
|
25652
|
+
return defaultMountPoint;
|
|
25723
25653
|
}
|
|
25724
|
-
|
|
25725
|
-
|
|
25726
|
-
|
|
25654
|
+
mountPoint = parsedMountPoint;
|
|
25655
|
+
mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
|
|
25656
|
+
return mountPoint;
|
|
25657
|
+
};
|
|
25658
|
+
})();
|
|
25659
|
+
var powerShellPathFromWsl = async () => {
|
|
25660
|
+
const mountPoint = await wslDrivesMountPoint();
|
|
25661
|
+
return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
|
|
25662
|
+
};
|
|
25663
|
+
var powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
|
|
25664
|
+
var canAccessPowerShellPromise;
|
|
25665
|
+
var canAccessPowerShell = async () => {
|
|
25666
|
+
canAccessPowerShellPromise ??= (async () => {
|
|
25667
|
+
try {
|
|
25668
|
+
const psPath = await powerShellPath2();
|
|
25669
|
+
await fs5.access(psPath, fsConstants.X_OK);
|
|
25670
|
+
return true;
|
|
25671
|
+
} catch {
|
|
25672
|
+
return false;
|
|
25727
25673
|
}
|
|
25728
|
-
}
|
|
25729
|
-
|
|
25730
|
-
cliArguments.push("--args", ...appArguments);
|
|
25731
|
-
}
|
|
25732
|
-
if (options.target) {
|
|
25733
|
-
cliArguments.push(options.target);
|
|
25734
|
-
}
|
|
25735
|
-
const subprocess = childProcess4.spawn(command, cliArguments, childProcessOptions);
|
|
25736
|
-
if (options.wait) {
|
|
25737
|
-
return new Promise((resolve, reject) => {
|
|
25738
|
-
subprocess.once("error", reject);
|
|
25739
|
-
subprocess.once("close", (exitCode) => {
|
|
25740
|
-
if (!options.allowNonzeroExitCode && exitCode !== 0) {
|
|
25741
|
-
reject(new Error(`Exited with code ${exitCode}`));
|
|
25742
|
-
return;
|
|
25743
|
-
}
|
|
25744
|
-
resolve(subprocess);
|
|
25745
|
-
});
|
|
25746
|
-
});
|
|
25747
|
-
}
|
|
25748
|
-
if (isFallbackAttempt) {
|
|
25749
|
-
return new Promise((resolve, reject) => {
|
|
25750
|
-
subprocess.once("error", reject);
|
|
25751
|
-
subprocess.once("spawn", () => {
|
|
25752
|
-
subprocess.once("close", (exitCode) => {
|
|
25753
|
-
subprocess.off("error", reject);
|
|
25754
|
-
if (exitCode !== 0) {
|
|
25755
|
-
reject(new Error(`Exited with code ${exitCode}`));
|
|
25756
|
-
return;
|
|
25757
|
-
}
|
|
25758
|
-
subprocess.unref();
|
|
25759
|
-
resolve(subprocess);
|
|
25760
|
-
});
|
|
25761
|
-
});
|
|
25762
|
-
});
|
|
25763
|
-
}
|
|
25764
|
-
subprocess.unref();
|
|
25765
|
-
return new Promise((resolve, reject) => {
|
|
25766
|
-
subprocess.once("error", reject);
|
|
25767
|
-
subprocess.once("spawn", () => {
|
|
25768
|
-
subprocess.off("error", reject);
|
|
25769
|
-
resolve(subprocess);
|
|
25770
|
-
});
|
|
25771
|
-
});
|
|
25674
|
+
})();
|
|
25675
|
+
return canAccessPowerShellPromise;
|
|
25772
25676
|
};
|
|
25773
|
-
var
|
|
25774
|
-
|
|
25775
|
-
|
|
25776
|
-
}
|
|
25777
|
-
|
|
25778
|
-
|
|
25779
|
-
target
|
|
25677
|
+
var wslDefaultBrowser = async () => {
|
|
25678
|
+
const psPath = await powerShellPath2();
|
|
25679
|
+
const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
|
|
25680
|
+
const { stdout } = await executePowerShell(command, {
|
|
25681
|
+
powerShellPath: psPath,
|
|
25682
|
+
cwd: path5.dirname(psPath)
|
|
25780
25683
|
});
|
|
25684
|
+
return stdout.trim();
|
|
25781
25685
|
};
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25785
|
-
|
|
25786
|
-
const
|
|
25787
|
-
|
|
25788
|
-
|
|
25789
|
-
|
|
25790
|
-
|
|
25791
|
-
|
|
25792
|
-
|
|
25793
|
-
if (wsl && is_wsl_default) {
|
|
25794
|
-
return detectArchBinary(wsl);
|
|
25686
|
+
var isUrl = (path6) => /^[a-z]+:\/\//i.test(path6);
|
|
25687
|
+
var convertWslPathToWindows = async (paths) => {
|
|
25688
|
+
const isBatch = Array.isArray(paths);
|
|
25689
|
+
const pathArray = isBatch ? paths : [paths];
|
|
25690
|
+
const indicesToConvert = [];
|
|
25691
|
+
const pathsToConvert = [];
|
|
25692
|
+
for (const [index, path6] of pathArray.entries()) {
|
|
25693
|
+
if (!isUrl(path6)) {
|
|
25694
|
+
indicesToConvert.push(index);
|
|
25695
|
+
pathsToConvert.push(path6);
|
|
25696
|
+
}
|
|
25795
25697
|
}
|
|
25796
|
-
|
|
25797
|
-
|
|
25698
|
+
const results = [...pathArray];
|
|
25699
|
+
if (pathsToConvert.length > 0) {
|
|
25700
|
+
try {
|
|
25701
|
+
const { stdout } = await execFile2("wslpath", ["-aw", ...pathsToConvert], { encoding: "utf8" });
|
|
25702
|
+
const convertedPaths = stdout.split(/\r?\n/).filter(Boolean);
|
|
25703
|
+
for (const [index, originalIndex] of indicesToConvert.entries()) {
|
|
25704
|
+
results[originalIndex] = convertedPaths[index] ?? pathArray[originalIndex];
|
|
25705
|
+
}
|
|
25706
|
+
} catch {}
|
|
25798
25707
|
}
|
|
25799
|
-
return
|
|
25800
|
-
}
|
|
25801
|
-
var apps = {
|
|
25802
|
-
browser: "browser",
|
|
25803
|
-
browserPrivate: "browserPrivate"
|
|
25708
|
+
return isBatch ? results : results[0];
|
|
25804
25709
|
};
|
|
25805
|
-
defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
|
|
25806
|
-
darwin: "google chrome",
|
|
25807
|
-
win32: "chrome",
|
|
25808
|
-
linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
|
|
25809
|
-
}, {
|
|
25810
|
-
wsl: {
|
|
25811
|
-
ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
|
25812
|
-
x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
|
|
25813
|
-
}
|
|
25814
|
-
}));
|
|
25815
|
-
defineLazyProperty(apps, "brave", () => detectPlatformBinary({
|
|
25816
|
-
darwin: "brave browser",
|
|
25817
|
-
win32: "brave",
|
|
25818
|
-
linux: ["brave-browser", "brave"]
|
|
25819
|
-
}, {
|
|
25820
|
-
wsl: {
|
|
25821
|
-
ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
|
|
25822
|
-
x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
|
|
25823
|
-
}
|
|
25824
|
-
}));
|
|
25825
|
-
defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
|
|
25826
|
-
darwin: "firefox",
|
|
25827
|
-
win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
|
|
25828
|
-
linux: "firefox"
|
|
25829
|
-
}, {
|
|
25830
|
-
wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
|
|
25831
|
-
}));
|
|
25832
|
-
defineLazyProperty(apps, "edge", () => detectPlatformBinary({
|
|
25833
|
-
darwin: "microsoft edge",
|
|
25834
|
-
win32: "msedge",
|
|
25835
|
-
linux: ["microsoft-edge", "microsoft-edge-dev"]
|
|
25836
|
-
}, {
|
|
25837
|
-
wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
|
|
25838
|
-
}));
|
|
25839
|
-
defineLazyProperty(apps, "safari", () => detectPlatformBinary({
|
|
25840
|
-
darwin: "Safari"
|
|
25841
|
-
}));
|
|
25842
|
-
var open_default = open;
|
|
25843
25710
|
|
|
25844
|
-
//
|
|
25845
|
-
|
|
25846
|
-
|
|
25847
|
-
|
|
25848
|
-
|
|
25849
|
-
|
|
25850
|
-
var
|
|
25851
|
-
var
|
|
25852
|
-
|
|
25853
|
-
|
|
25854
|
-
|
|
25855
|
-
|
|
25856
|
-
|
|
25857
|
-
|
|
25858
|
-
|
|
25859
|
-
|
|
25860
|
-
|
|
25861
|
-
|
|
25862
|
-
|
|
25863
|
-
|
|
25864
|
-
|
|
25865
|
-
|
|
25711
|
+
// node_modules/powershell-utils/index.js
|
|
25712
|
+
import process4 from "process";
|
|
25713
|
+
import { Buffer as Buffer3 } from "buffer";
|
|
25714
|
+
import { promisify as promisify3 } from "util";
|
|
25715
|
+
import childProcess3 from "child_process";
|
|
25716
|
+
var execFile3 = promisify3(childProcess3.execFile);
|
|
25717
|
+
var powerShellPath3 = () => `${process4.env.SYSTEMROOT || process4.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
|
25718
|
+
var argumentsPrefix = [
|
|
25719
|
+
"-NoProfile",
|
|
25720
|
+
"-NonInteractive",
|
|
25721
|
+
"-ExecutionPolicy",
|
|
25722
|
+
"Bypass",
|
|
25723
|
+
"-EncodedCommand"
|
|
25724
|
+
];
|
|
25725
|
+
var encodeCommand = (command) => Buffer3.from(command, "utf16le").toString("base64");
|
|
25726
|
+
var escapeArgument = (value) => `'${String(value).replaceAll(/['\u2018\u2019\u201A\u201B]/g, (match) => match + match)}'`;
|
|
25727
|
+
var createArguments = (command) => [...argumentsPrefix, encodeCommand(command)];
|
|
25728
|
+
var createExecFileOptions = (options) => ({
|
|
25729
|
+
encoding: "utf8",
|
|
25730
|
+
...options,
|
|
25731
|
+
shell: false
|
|
25732
|
+
});
|
|
25733
|
+
var executePowerShell2 = async (command, options = {}) => {
|
|
25734
|
+
const {
|
|
25735
|
+
powerShellPath: psPath,
|
|
25736
|
+
...execFileOptions
|
|
25737
|
+
} = options;
|
|
25738
|
+
return execFile3(psPath ?? powerShellPath3(), createArguments(command), createExecFileOptions(execFileOptions));
|
|
25739
|
+
};
|
|
25740
|
+
executePowerShell2.argumentsPrefix = argumentsPrefix;
|
|
25741
|
+
executePowerShell2.encodeCommand = encodeCommand;
|
|
25742
|
+
executePowerShell2.escapeArgument = escapeArgument;
|
|
25743
|
+
executePowerShell2.createArguments = createArguments;
|
|
25744
|
+
|
|
25745
|
+
// node_modules/define-lazy-prop/index.js
|
|
25746
|
+
function defineLazyProperty(object2, propertyName, valueGetter) {
|
|
25747
|
+
const define = (value) => Object.defineProperty(object2, propertyName, { value, enumerable: true, writable: true });
|
|
25748
|
+
Object.defineProperty(object2, propertyName, {
|
|
25749
|
+
configurable: true,
|
|
25750
|
+
enumerable: true,
|
|
25751
|
+
get() {
|
|
25752
|
+
const result = valueGetter();
|
|
25753
|
+
define(result);
|
|
25754
|
+
return result;
|
|
25755
|
+
},
|
|
25756
|
+
set(value) {
|
|
25757
|
+
define(value);
|
|
25758
|
+
}
|
|
25759
|
+
});
|
|
25760
|
+
return object2;
|
|
25761
|
+
}
|
|
25762
|
+
|
|
25763
|
+
// node_modules/default-browser/index.js
|
|
25764
|
+
import { promisify as promisify7 } from "util";
|
|
25765
|
+
import process8 from "process";
|
|
25766
|
+
import { execFile as execFile7 } from "child_process";
|
|
25767
|
+
|
|
25768
|
+
// node_modules/default-browser-id/index.js
|
|
25769
|
+
import { promisify as promisify4 } from "util";
|
|
25770
|
+
import process5 from "process";
|
|
25771
|
+
import { execFile as execFile4 } from "child_process";
|
|
25772
|
+
var execFileAsync = promisify4(execFile4);
|
|
25773
|
+
async function defaultBrowserId() {
|
|
25774
|
+
if (process5.platform !== "darwin") {
|
|
25775
|
+
throw new Error("macOS only");
|
|
25866
25776
|
}
|
|
25867
|
-
|
|
25868
|
-
|
|
25869
|
-
|
|
25870
|
-
|
|
25871
|
-
|
|
25872
|
-
description: "Sign in to ChatGPT by opening a verification page and entering a one-time code"
|
|
25873
|
-
});
|
|
25777
|
+
const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
|
|
25778
|
+
const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
|
|
25779
|
+
const browserId = match?.groups.id ?? "com.apple.Safari";
|
|
25780
|
+
if (browserId === "com.apple.safari") {
|
|
25781
|
+
return "com.apple.Safari";
|
|
25874
25782
|
}
|
|
25875
|
-
return
|
|
25783
|
+
return browserId;
|
|
25876
25784
|
}
|
|
25877
|
-
|
|
25878
|
-
|
|
25879
|
-
|
|
25880
|
-
|
|
25881
|
-
|
|
25882
|
-
|
|
25883
|
-
|
|
25884
|
-
|
|
25885
|
-
|
|
25886
|
-
throw RequestError.invalidParams({ methodId: request.methodId }, `Unknown auth method "${request.methodId}"; expected one of ${Object.values(AuthMethodId).join(", ")}`);
|
|
25785
|
+
|
|
25786
|
+
// node_modules/run-applescript/index.js
|
|
25787
|
+
import process6 from "process";
|
|
25788
|
+
import { promisify as promisify5 } from "util";
|
|
25789
|
+
import { execFile as execFile5, execFileSync } from "child_process";
|
|
25790
|
+
var execFileAsync2 = promisify5(execFile5);
|
|
25791
|
+
async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
|
|
25792
|
+
if (process6.platform !== "darwin") {
|
|
25793
|
+
throw new Error("macOS only");
|
|
25887
25794
|
}
|
|
25888
|
-
|
|
25889
|
-
|
|
25890
|
-
|
|
25891
|
-
|
|
25892
|
-
const apiKey = typeof fromMeta === "string" && fromMeta.trim().length > 0 ? fromMeta.trim() : env[CODEX_API_KEY_ENV]?.trim() || env[OPENAI_API_KEY_ENV]?.trim();
|
|
25893
|
-
if (!apiKey) {
|
|
25894
|
-
throw RequestError.invalidParams({ envVars: [CODEX_API_KEY_ENV, OPENAI_API_KEY_ENV] }, `No API key: set ${CODEX_API_KEY_ENV} or ${OPENAI_API_KEY_ENV}, or pass _meta["api-key"].apiKey`);
|
|
25795
|
+
const outputArguments = humanReadableOutput ? [] : ["-ss"];
|
|
25796
|
+
const execOptions = {};
|
|
25797
|
+
if (signal) {
|
|
25798
|
+
execOptions.signal = signal;
|
|
25895
25799
|
}
|
|
25896
|
-
await
|
|
25897
|
-
|
|
25898
|
-
const result = await completed;
|
|
25899
|
-
if (!result.success)
|
|
25900
|
-
throw RequestError.authRequired({ error: result.error }, result.error ?? "API key login failed");
|
|
25901
|
-
});
|
|
25800
|
+
const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments], execOptions);
|
|
25801
|
+
return stdout.trim();
|
|
25902
25802
|
}
|
|
25903
|
-
|
|
25904
|
-
|
|
25905
|
-
|
|
25906
|
-
|
|
25907
|
-
|
|
25908
|
-
const started = await codex.accountLogin({ type: "chatgpt" });
|
|
25909
|
-
if (started.type !== "chatgpt")
|
|
25910
|
-
throw RequestError.internalError({ type: started.type }, "Unexpected login response");
|
|
25911
|
-
logger.log("opening browser for ChatGPT login", { loginId: started.loginId });
|
|
25912
|
-
await open_default(started.authUrl);
|
|
25913
|
-
const result = await completed;
|
|
25914
|
-
if (!result.success)
|
|
25915
|
-
throw RequestError.authRequired({ error: result.error }, result.error ?? "ChatGPT login failed");
|
|
25916
|
-
});
|
|
25803
|
+
|
|
25804
|
+
// node_modules/bundle-name/index.js
|
|
25805
|
+
async function bundleName(bundleId) {
|
|
25806
|
+
return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
|
|
25807
|
+
tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
|
|
25917
25808
|
}
|
|
25918
|
-
|
|
25919
|
-
|
|
25920
|
-
|
|
25921
|
-
|
|
25922
|
-
|
|
25923
|
-
|
|
25924
|
-
|
|
25925
|
-
|
|
25926
|
-
|
|
25927
|
-
|
|
25928
|
-
|
|
25929
|
-
|
|
25930
|
-
|
|
25931
|
-
|
|
25932
|
-
|
|
25933
|
-
|
|
25934
|
-
|
|
25935
|
-
|
|
25936
|
-
|
|
25937
|
-
|
|
25938
|
-
|
|
25939
|
-
|
|
25940
|
-
|
|
25941
|
-
|
|
25942
|
-
|
|
25943
|
-
|
|
25944
|
-
|
|
25945
|
-
throw RequestError.authRequired({ error: result.error }, result.error ?? "ChatGPT login failed");
|
|
25946
|
-
});
|
|
25809
|
+
|
|
25810
|
+
// node_modules/default-browser/windows.js
|
|
25811
|
+
import process7 from "process";
|
|
25812
|
+
import { promisify as promisify6 } from "util";
|
|
25813
|
+
import { execFile as execFile6 } from "child_process";
|
|
25814
|
+
var execFileAsync3 = promisify6(execFile6);
|
|
25815
|
+
var windowsBrowserProgIds = {
|
|
25816
|
+
MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
|
|
25817
|
+
MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
|
|
25818
|
+
MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
|
|
25819
|
+
AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
|
|
25820
|
+
ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
|
|
25821
|
+
ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
|
|
25822
|
+
ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
|
|
25823
|
+
ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
|
|
25824
|
+
BraveHTML: { name: "Brave", id: "com.brave.Browser" },
|
|
25825
|
+
BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
|
|
25826
|
+
BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
|
|
25827
|
+
BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
|
|
25828
|
+
FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
|
|
25829
|
+
OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
|
|
25830
|
+
VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
|
|
25831
|
+
"IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
|
|
25832
|
+
};
|
|
25833
|
+
var _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
|
|
25834
|
+
|
|
25835
|
+
class UnknownBrowserError extends Error {
|
|
25947
25836
|
}
|
|
25948
|
-
async function
|
|
25949
|
-
|
|
25950
|
-
|
|
25951
|
-
|
|
25952
|
-
|
|
25837
|
+
async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
25838
|
+
const regPath = `${process7.env.SYSTEMROOT ?? process7.env.windir ?? "C:\\Windows"}\\System32\\reg.exe`;
|
|
25839
|
+
const { stdout } = await _execFileAsync(regPath, [
|
|
25840
|
+
"QUERY",
|
|
25841
|
+
" HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
|
|
25842
|
+
"/v",
|
|
25843
|
+
"ProgId"
|
|
25844
|
+
]);
|
|
25845
|
+
const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
|
|
25846
|
+
if (!match) {
|
|
25847
|
+
throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
|
|
25848
|
+
}
|
|
25849
|
+
const { id } = match.groups;
|
|
25850
|
+
const dotIndex = id.lastIndexOf(".");
|
|
25851
|
+
const hyphenIndex = id.lastIndexOf("-");
|
|
25852
|
+
const baseIdByDot = dotIndex === -1 ? undefined : id.slice(0, dotIndex);
|
|
25853
|
+
const baseIdByHyphen = hyphenIndex === -1 ? undefined : id.slice(0, hyphenIndex);
|
|
25854
|
+
return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
|
|
25953
25855
|
}
|
|
25954
25856
|
|
|
25955
|
-
//
|
|
25956
|
-
|
|
25957
|
-
|
|
25958
|
-
|
|
25959
|
-
|
|
25960
|
-
|
|
25961
|
-
|
|
25962
|
-
|
|
25963
|
-
disposed = false;
|
|
25964
|
-
output = new AbortController;
|
|
25965
|
-
terminalAttempted = false;
|
|
25966
|
-
get signal() {
|
|
25967
|
-
return this.output.signal;
|
|
25968
|
-
}
|
|
25969
|
-
constructor(sessionId, link, capabilities) {
|
|
25970
|
-
this.sessionId = sessionId;
|
|
25971
|
-
this.link = link;
|
|
25972
|
-
this.capabilities = capabilities;
|
|
25973
|
-
}
|
|
25974
|
-
async update(update) {
|
|
25975
|
-
if (this.disposed)
|
|
25976
|
-
return;
|
|
25977
|
-
await abortable(this.link.notify(methods.client.session.update, { sessionId: this.sessionId, update }), this.output.signal);
|
|
25978
|
-
}
|
|
25979
|
-
async updateAll(updates) {
|
|
25980
|
-
for (const update of updates)
|
|
25981
|
-
await this.update(update);
|
|
25982
|
-
}
|
|
25983
|
-
async requestPermission(request, signal) {
|
|
25984
|
-
signal = signal ? AbortSignal.any([signal, this.output.signal]) : this.output.signal;
|
|
25985
|
-
signal.throwIfAborted();
|
|
25986
|
-
return await this.waitingOnClient(() => {
|
|
25987
|
-
signal?.throwIfAborted();
|
|
25988
|
-
const pending = this.link.request(methods.client.session.requestPermission, { sessionId: this.sessionId, ...request }, signal ? { cancellationSignal: signal } : undefined);
|
|
25989
|
-
return signal ? abortable(pending, signal) : pending;
|
|
25990
|
-
}, signal);
|
|
25991
|
-
}
|
|
25992
|
-
async requestTool(params, signal) {
|
|
25993
|
-
return await this.link.request("_alwith/tool/call", params, { cancellationSignal: signal });
|
|
25994
|
-
}
|
|
25995
|
-
async createElicitation(request, signal) {
|
|
25996
|
-
signal = signal ? AbortSignal.any([signal, this.output.signal]) : this.output.signal;
|
|
25997
|
-
signal.throwIfAborted();
|
|
25998
|
-
return await this.waitingOnClient(() => {
|
|
25999
|
-
signal?.throwIfAborted();
|
|
26000
|
-
const pending = this.link.request(methods.client.elicitation.create, request, signal ? { cancellationSignal: signal } : undefined);
|
|
26001
|
-
return signal ? abortable(pending, signal) : pending;
|
|
26002
|
-
}, signal);
|
|
26003
|
-
}
|
|
26004
|
-
async completeElicitation(elicitationId) {
|
|
26005
|
-
if (this.disposed)
|
|
26006
|
-
return;
|
|
26007
|
-
await abortable(this.link.notify(methods.client.elicitation.complete, { elicitationId }), this.output.signal);
|
|
25857
|
+
// node_modules/default-browser/index.js
|
|
25858
|
+
var execFileAsync4 = promisify7(execFile7);
|
|
25859
|
+
var titleize = (string4) => string4.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
|
|
25860
|
+
async function defaultBrowser2() {
|
|
25861
|
+
if (process8.platform === "darwin") {
|
|
25862
|
+
const id = await defaultBrowserId();
|
|
25863
|
+
const name = await bundleName(id);
|
|
25864
|
+
return { name, id };
|
|
26008
25865
|
}
|
|
26009
|
-
|
|
26010
|
-
|
|
26011
|
-
|
|
26012
|
-
|
|
26013
|
-
|
|
26014
|
-
this.state({ sessionUpdate: "state_update", state: "running" });
|
|
25866
|
+
if (process8.platform === "linux") {
|
|
25867
|
+
const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
|
|
25868
|
+
const id = stdout.trim();
|
|
25869
|
+
const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
|
|
25870
|
+
return { name, id };
|
|
26015
25871
|
}
|
|
26016
|
-
|
|
26017
|
-
|
|
26018
|
-
return;
|
|
26019
|
-
this.terminalAttempted = true;
|
|
26020
|
-
this.turnActive = false;
|
|
26021
|
-
this.waiting = 0;
|
|
26022
|
-
await this.update({
|
|
26023
|
-
sessionUpdate: "state_update",
|
|
26024
|
-
state: "idle",
|
|
26025
|
-
stopReason,
|
|
26026
|
-
...extra?.usage === undefined ? {} : { usage: extra.usage },
|
|
26027
|
-
...extra?._meta === undefined ? {} : { _meta: extra._meta }
|
|
26028
|
-
});
|
|
25872
|
+
if (process8.platform === "win32") {
|
|
25873
|
+
return defaultBrowser();
|
|
26029
25874
|
}
|
|
26030
|
-
|
|
26031
|
-
|
|
26032
|
-
|
|
26033
|
-
|
|
26034
|
-
|
|
26035
|
-
|
|
26036
|
-
|
|
26037
|
-
|
|
26038
|
-
|
|
26039
|
-
|
|
26040
|
-
|
|
26041
|
-
|
|
26042
|
-
|
|
26043
|
-
|
|
26044
|
-
|
|
26045
|
-
|
|
25875
|
+
throw new Error("Only macOS, Linux, and Windows are supported");
|
|
25876
|
+
}
|
|
25877
|
+
|
|
25878
|
+
// node_modules/is-in-ssh/index.js
|
|
25879
|
+
import process9 from "process";
|
|
25880
|
+
var isInSsh = Boolean(process9.env.SSH_CONNECTION || process9.env.SSH_CLIENT || process9.env.SSH_TTY);
|
|
25881
|
+
var is_in_ssh_default = isInSsh;
|
|
25882
|
+
|
|
25883
|
+
// node_modules/open/index.js
|
|
25884
|
+
var fallbackAttemptSymbol = Symbol("fallbackAttempt");
|
|
25885
|
+
var __dirname2 = import.meta.url ? path6.dirname(fileURLToPath(import.meta.url)) : "";
|
|
25886
|
+
var localXdgOpenPath = path6.join(__dirname2, "xdg-open");
|
|
25887
|
+
var { platform, arch } = process10;
|
|
25888
|
+
var tryEachApp = async (apps, opener) => {
|
|
25889
|
+
if (apps.length === 0) {
|
|
25890
|
+
return;
|
|
26046
25891
|
}
|
|
26047
|
-
|
|
25892
|
+
const errors3 = [];
|
|
25893
|
+
for (const app of apps) {
|
|
26048
25894
|
try {
|
|
26049
|
-
await
|
|
25895
|
+
return await opener(app);
|
|
26050
25896
|
} catch (error40) {
|
|
26051
|
-
|
|
25897
|
+
errors3.push(error40);
|
|
26052
25898
|
}
|
|
26053
25899
|
}
|
|
26054
|
-
|
|
26055
|
-
|
|
26056
|
-
|
|
26057
|
-
|
|
26058
|
-
|
|
25900
|
+
throw new AggregateError(errors3, "Failed to open in all supported apps");
|
|
25901
|
+
};
|
|
25902
|
+
var baseOpen = async (options) => {
|
|
25903
|
+
options = {
|
|
25904
|
+
wait: false,
|
|
25905
|
+
background: false,
|
|
25906
|
+
newInstance: false,
|
|
25907
|
+
allowNonzeroExitCode: false,
|
|
25908
|
+
...options
|
|
25909
|
+
};
|
|
25910
|
+
const isFallbackAttempt = options[fallbackAttemptSymbol] === true;
|
|
25911
|
+
delete options[fallbackAttemptSymbol];
|
|
25912
|
+
if (Array.isArray(options.app)) {
|
|
25913
|
+
return tryEachApp(options.app, (singleApp) => baseOpen({
|
|
25914
|
+
...options,
|
|
25915
|
+
app: singleApp,
|
|
25916
|
+
[fallbackAttemptSymbol]: true
|
|
25917
|
+
}));
|
|
26059
25918
|
}
|
|
26060
|
-
}
|
|
26061
|
-
|
|
26062
|
-
|
|
26063
|
-
|
|
26064
|
-
|
|
26065
|
-
|
|
26066
|
-
|
|
26067
|
-
|
|
26068
|
-
|
|
26069
|
-
|
|
26070
|
-
|
|
26071
|
-
{ name: "skills", description: "List available skills" },
|
|
26072
|
-
{ name: "logout", description: "Sign out of the Codex account" }
|
|
26073
|
-
];
|
|
26074
|
-
function parseCommand(prompt) {
|
|
26075
|
-
const first = prompt[0];
|
|
26076
|
-
if (!first || first.type !== "text")
|
|
26077
|
-
return null;
|
|
26078
|
-
const text2 = first.text.trim();
|
|
26079
|
-
if (!text2.startsWith("/"))
|
|
26080
|
-
return null;
|
|
26081
|
-
const body = text2.slice(1).trim();
|
|
26082
|
-
const [name] = body.split(/\s+/);
|
|
26083
|
-
if (!name || name.startsWith("$"))
|
|
26084
|
-
return null;
|
|
26085
|
-
return { name: name.toLowerCase(), rest: body.slice(name.length).trim() };
|
|
26086
|
-
}
|
|
26087
|
-
function resolveCommand(command, session) {
|
|
26088
|
-
switch (command.name) {
|
|
26089
|
-
case "plan":
|
|
26090
|
-
return {
|
|
26091
|
-
kind: "config",
|
|
26092
|
-
configId: COLLABORATION_MODE_CONFIG_ID,
|
|
26093
|
-
value: session.collaborationMode === PLAN_COLLABORATION_MODE ? DEFAULT_COLLABORATION_MODE : PLAN_COLLABORATION_MODE
|
|
26094
|
-
};
|
|
26095
|
-
case "compact":
|
|
26096
|
-
return { kind: "compact" };
|
|
26097
|
-
case "review":
|
|
26098
|
-
return { kind: "review", target: command.rest.length > 0 ? { type: "custom", instructions: command.rest } : { type: "uncommittedChanges" } };
|
|
26099
|
-
case "review-branch":
|
|
26100
|
-
return command.rest.length > 0 ? { kind: "review", target: { type: "baseBranch", branch: command.rest } } : { kind: "message", text: usage("review-branch", "<branch name>") };
|
|
26101
|
-
case "review-commit":
|
|
26102
|
-
return command.rest.length > 0 ? { kind: "review", target: { type: "commit", sha: command.rest, title: null } } : { kind: "message", text: usage("review-commit", "<commit sha>") };
|
|
26103
|
-
case "logout":
|
|
26104
|
-
return { kind: "logout" };
|
|
26105
|
-
case "status":
|
|
26106
|
-
case "mcp":
|
|
26107
|
-
case "skills":
|
|
26108
|
-
return { kind: "message", text: "" };
|
|
26109
|
-
default:
|
|
26110
|
-
return { kind: "prompt" };
|
|
25919
|
+
let { name: app, arguments: appArguments = [] } = options.app ?? {};
|
|
25920
|
+
appArguments = [...appArguments];
|
|
25921
|
+
if (Array.isArray(app)) {
|
|
25922
|
+
return tryEachApp(app, (appName) => baseOpen({
|
|
25923
|
+
...options,
|
|
25924
|
+
app: {
|
|
25925
|
+
name: appName,
|
|
25926
|
+
arguments: appArguments
|
|
25927
|
+
},
|
|
25928
|
+
[fallbackAttemptSymbol]: true
|
|
25929
|
+
}));
|
|
26111
25930
|
}
|
|
26112
|
-
|
|
26113
|
-
|
|
26114
|
-
|
|
26115
|
-
|
|
26116
|
-
|
|
26117
|
-
|
|
26118
|
-
|
|
26119
|
-
|
|
26120
|
-
|
|
26121
|
-
|
|
26122
|
-
|
|
26123
|
-
|
|
26124
|
-
|
|
26125
|
-
|
|
25931
|
+
if (app === "browser" || app === "browserPrivate") {
|
|
25932
|
+
const ids = {
|
|
25933
|
+
"com.google.chrome": "chrome",
|
|
25934
|
+
"google-chrome.desktop": "chrome",
|
|
25935
|
+
"com.brave.browser": "brave",
|
|
25936
|
+
"org.mozilla.firefox": "firefox",
|
|
25937
|
+
"firefox.desktop": "firefox",
|
|
25938
|
+
"com.microsoft.msedge": "edge",
|
|
25939
|
+
"com.microsoft.edge": "edge",
|
|
25940
|
+
"com.microsoft.edgemac": "edge",
|
|
25941
|
+
"microsoft-edge.desktop": "edge",
|
|
25942
|
+
"com.apple.safari": "safari"
|
|
25943
|
+
};
|
|
25944
|
+
const flags = {
|
|
25945
|
+
chrome: "--incognito",
|
|
25946
|
+
brave: "--incognito",
|
|
25947
|
+
firefox: "--private-window",
|
|
25948
|
+
edge: "--inPrivate"
|
|
25949
|
+
};
|
|
25950
|
+
let browser;
|
|
25951
|
+
if (is_wsl_default) {
|
|
25952
|
+
const progId = await wslDefaultBrowser();
|
|
25953
|
+
const browserInfo = _windowsBrowserProgIdMap.get(progId);
|
|
25954
|
+
browser = browserInfo ?? {};
|
|
25955
|
+
} else {
|
|
25956
|
+
browser = await defaultBrowser2();
|
|
25957
|
+
}
|
|
25958
|
+
if (Object.hasOwn(ids, browser.id)) {
|
|
25959
|
+
const browserName = ids[browser.id.toLowerCase()];
|
|
25960
|
+
if (browserName === undefined) {
|
|
25961
|
+
throw new Error(`${browser.name} is not supported as a default browser`);
|
|
25962
|
+
}
|
|
25963
|
+
if (app === "browserPrivate") {
|
|
25964
|
+
if (browserName === "safari") {
|
|
25965
|
+
throw new Error("Safari doesn't support opening in private mode via command line");
|
|
25966
|
+
}
|
|
25967
|
+
appArguments.push(flags[browserName]);
|
|
25968
|
+
}
|
|
25969
|
+
return baseOpen({
|
|
25970
|
+
...options,
|
|
25971
|
+
app: {
|
|
25972
|
+
name: apps[browserName],
|
|
25973
|
+
arguments: appArguments
|
|
25974
|
+
}
|
|
25975
|
+
});
|
|
25976
|
+
}
|
|
25977
|
+
throw new Error(`${browser.name} is not supported as a default browser`);
|
|
25978
|
+
}
|
|
25979
|
+
let command;
|
|
25980
|
+
const cliArguments = [];
|
|
25981
|
+
const childProcessOptions = {};
|
|
25982
|
+
let shouldUseWindowsInWsl = false;
|
|
25983
|
+
if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
|
|
25984
|
+
shouldUseWindowsInWsl = await canAccessPowerShell();
|
|
25985
|
+
}
|
|
25986
|
+
if (platform === "darwin") {
|
|
25987
|
+
command = "open";
|
|
25988
|
+
if (options.wait) {
|
|
25989
|
+
cliArguments.push("--wait-apps");
|
|
25990
|
+
}
|
|
25991
|
+
if (options.background) {
|
|
25992
|
+
cliArguments.push("--background");
|
|
25993
|
+
}
|
|
25994
|
+
if (options.newInstance) {
|
|
25995
|
+
cliArguments.push("--new");
|
|
25996
|
+
}
|
|
25997
|
+
if (app) {
|
|
25998
|
+
cliArguments.push("-a", app);
|
|
25999
|
+
}
|
|
26000
|
+
} else if (platform === "win32" || shouldUseWindowsInWsl) {
|
|
26001
|
+
command = await powerShellPath2();
|
|
26002
|
+
cliArguments.push(...executePowerShell2.argumentsPrefix);
|
|
26003
|
+
if (!is_wsl_default) {
|
|
26004
|
+
childProcessOptions.windowsVerbatimArguments = true;
|
|
26005
|
+
}
|
|
26006
|
+
if (is_wsl_default && options.target) {
|
|
26007
|
+
options.target = await convertWslPathToWindows(options.target);
|
|
26008
|
+
}
|
|
26009
|
+
const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
|
|
26010
|
+
if (options.wait) {
|
|
26011
|
+
encodedArguments.push("-Wait");
|
|
26012
|
+
}
|
|
26013
|
+
if (app) {
|
|
26014
|
+
encodedArguments.push(executePowerShell2.escapeArgument(app));
|
|
26015
|
+
if (options.target) {
|
|
26016
|
+
appArguments.push(options.target);
|
|
26017
|
+
}
|
|
26018
|
+
} else if (options.target) {
|
|
26019
|
+
encodedArguments.push(executePowerShell2.escapeArgument(options.target));
|
|
26020
|
+
}
|
|
26021
|
+
if (appArguments.length > 0) {
|
|
26022
|
+
appArguments = appArguments.map((argument) => executePowerShell2.escapeArgument(argument));
|
|
26023
|
+
encodedArguments.push("-ArgumentList", appArguments.join(","));
|
|
26024
|
+
}
|
|
26025
|
+
options.target = executePowerShell2.encodeCommand(encodedArguments.join(" "));
|
|
26026
|
+
if (!options.wait) {
|
|
26027
|
+
childProcessOptions.stdio = "ignore";
|
|
26028
|
+
}
|
|
26029
|
+
if (is_wsl_default) {
|
|
26030
|
+
childProcessOptions.cwd = path6.dirname(command);
|
|
26031
|
+
}
|
|
26032
|
+
} else {
|
|
26033
|
+
if (app) {
|
|
26034
|
+
command = app;
|
|
26035
|
+
} else {
|
|
26036
|
+
const isBundled = !__dirname2 || __dirname2 === "/";
|
|
26037
|
+
let exeLocalXdgOpen = false;
|
|
26038
|
+
try {
|
|
26039
|
+
await fs6.access(localXdgOpenPath, fsConstants2.X_OK);
|
|
26040
|
+
exeLocalXdgOpen = true;
|
|
26041
|
+
} catch {}
|
|
26042
|
+
const useSystemXdgOpen = process10.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
|
|
26043
|
+
command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
|
|
26044
|
+
}
|
|
26045
|
+
if (appArguments.length > 0) {
|
|
26046
|
+
cliArguments.push(...appArguments);
|
|
26047
|
+
}
|
|
26048
|
+
if (!options.wait) {
|
|
26049
|
+
childProcessOptions.stdio = "ignore";
|
|
26050
|
+
childProcessOptions.detached = true;
|
|
26126
26051
|
}
|
|
26127
26052
|
}
|
|
26128
|
-
|
|
26129
|
-
|
|
26130
|
-
|
|
26131
|
-
|
|
26132
|
-
|
|
26133
|
-
|
|
26053
|
+
if (platform === "darwin" && appArguments.length > 0) {
|
|
26054
|
+
cliArguments.push("--args", ...appArguments);
|
|
26055
|
+
}
|
|
26056
|
+
if (options.target) {
|
|
26057
|
+
cliArguments.push(options.target);
|
|
26058
|
+
}
|
|
26059
|
+
const subprocess = childProcess4.spawn(command, cliArguments, childProcessOptions);
|
|
26060
|
+
if (options.wait) {
|
|
26061
|
+
return new Promise((resolve, reject) => {
|
|
26062
|
+
subprocess.once("error", reject);
|
|
26063
|
+
subprocess.once("close", (exitCode) => {
|
|
26064
|
+
if (!options.allowNonzeroExitCode && exitCode !== 0) {
|
|
26065
|
+
reject(new Error(`Exited with code ${exitCode}`));
|
|
26066
|
+
return;
|
|
26067
|
+
}
|
|
26068
|
+
resolve(subprocess);
|
|
26069
|
+
});
|
|
26070
|
+
});
|
|
26071
|
+
}
|
|
26072
|
+
if (isFallbackAttempt) {
|
|
26073
|
+
return new Promise((resolve, reject) => {
|
|
26074
|
+
subprocess.once("error", reject);
|
|
26075
|
+
subprocess.once("spawn", () => {
|
|
26076
|
+
subprocess.once("close", (exitCode) => {
|
|
26077
|
+
subprocess.off("error", reject);
|
|
26078
|
+
if (exitCode !== 0) {
|
|
26079
|
+
reject(new Error(`Exited with code ${exitCode}`));
|
|
26080
|
+
return;
|
|
26081
|
+
}
|
|
26082
|
+
subprocess.unref();
|
|
26083
|
+
resolve(subprocess);
|
|
26084
|
+
});
|
|
26085
|
+
});
|
|
26086
|
+
});
|
|
26087
|
+
}
|
|
26088
|
+
subprocess.unref();
|
|
26089
|
+
return new Promise((resolve, reject) => {
|
|
26090
|
+
subprocess.once("error", reject);
|
|
26091
|
+
subprocess.once("spawn", () => {
|
|
26092
|
+
subprocess.off("error", reject);
|
|
26093
|
+
resolve(subprocess);
|
|
26094
|
+
});
|
|
26134
26095
|
});
|
|
26135
|
-
|
|
26136
|
-
|
|
26137
|
-
|
|
26138
|
-
|
|
26139
|
-
|
|
26140
|
-
|
|
26141
|
-
|
|
26142
|
-
|
|
26143
|
-
return `- ${server.name}: ${tools} tools, ${resources} resources, auth=${server.authStatus}`;
|
|
26096
|
+
};
|
|
26097
|
+
var open = (target, options) => {
|
|
26098
|
+
if (typeof target !== "string") {
|
|
26099
|
+
throw new TypeError("Expected a `target`");
|
|
26100
|
+
}
|
|
26101
|
+
return baseOpen({
|
|
26102
|
+
...options,
|
|
26103
|
+
target
|
|
26144
26104
|
});
|
|
26145
|
-
|
|
26146
|
-
|
|
26147
|
-
|
|
26148
|
-
|
|
26149
|
-
...sessionLines.length > 0 ? ["", "Session MCP servers:", ...sessionLines] : []
|
|
26150
|
-
].join(`
|
|
26151
|
-
`);
|
|
26152
|
-
}
|
|
26153
|
-
function statusMessage(session, rateLimits) {
|
|
26154
|
-
const usage2 = session.lastUsage;
|
|
26155
|
-
const lines = [
|
|
26156
|
-
"**Session**",
|
|
26157
|
-
`**Session ID:** ${session.id}`,
|
|
26158
|
-
`**Working directory:** ${session.cwd}`,
|
|
26159
|
-
`**Model:** ${session.model.model} (${session.model.effort})`,
|
|
26160
|
-
`**Mode:** ${session.mode.name}`,
|
|
26161
|
-
`**Collaboration:** ${session.collaborationMode}`,
|
|
26162
|
-
`**Fast mode:** ${session.fastMode ? "on" : "off"}`,
|
|
26163
|
-
`**Account:** ${accountInfo(session)}`,
|
|
26164
|
-
"",
|
|
26165
|
-
"**Usage**",
|
|
26166
|
-
`**Last turn:** ${usage2 ? `${formatTokenCount(usage2.totalTokens)} total (${formatTokenCount(usage2.inputTokens)} input + ${formatTokenCount(usage2.cachedInputTokens)} cached, ${formatTokenCount(usage2.outputTokens)} output)` : "not available yet"}`,
|
|
26167
|
-
`**Context window:** ${usage2 && session.contextWindow ? `${Math.round((session.contextWindow - usage2.totalTokens) / session.contextWindow * 100)}% left (${formatTokenCount(usage2.totalTokens)} / ${formatTokenCount(session.contextWindow)})` : "not available yet"}`,
|
|
26168
|
-
...rateLimitLines(rateLimits)
|
|
26169
|
-
];
|
|
26170
|
-
return lines.join(`
|
|
26171
|
-
`);
|
|
26172
|
-
}
|
|
26173
|
-
function accountInfo(session) {
|
|
26174
|
-
const account = session.account;
|
|
26175
|
-
if (!account)
|
|
26176
|
-
return "not logged in";
|
|
26177
|
-
switch (account.type) {
|
|
26178
|
-
case "apiKey":
|
|
26179
|
-
return "API key";
|
|
26180
|
-
case "chatgpt":
|
|
26181
|
-
return `ChatGPT ${account.planType}${account.email ? ` (${account.email})` : ""}`;
|
|
26182
|
-
case "amazonBedrock":
|
|
26183
|
-
return "Amazon Bedrock";
|
|
26105
|
+
};
|
|
26106
|
+
function detectArchBinary(binary) {
|
|
26107
|
+
if (typeof binary === "string" || Array.isArray(binary)) {
|
|
26108
|
+
return binary;
|
|
26184
26109
|
}
|
|
26185
|
-
}
|
|
26186
|
-
|
|
26187
|
-
|
|
26188
|
-
for (const snapshot of rateLimits.values()) {
|
|
26189
|
-
const prefix = snapshot.limitName ? `${snapshot.limitName} ` : "";
|
|
26190
|
-
for (const window of [snapshot.primary, snapshot.secondary]) {
|
|
26191
|
-
if (!window)
|
|
26192
|
-
continue;
|
|
26193
|
-
const label = windowLabel(window.windowDurationMins);
|
|
26194
|
-
const reset = window.resetsAt === null ? "" : ` (resets ${new Date(window.resetsAt * 1000).toLocaleString()})`;
|
|
26195
|
-
lines.push(`**${prefix}${label}:** ${Math.round(100 - window.usedPercent)}% left${reset}`);
|
|
26196
|
-
}
|
|
26197
|
-
if (snapshot.credits?.unlimited)
|
|
26198
|
-
lines.push(`**${prefix}Credits:** unlimited`);
|
|
26199
|
-
else if (snapshot.credits?.balance)
|
|
26200
|
-
lines.push(`**${prefix}Credits:** ${snapshot.credits.balance}`);
|
|
26110
|
+
const { [arch]: archBinary } = binary;
|
|
26111
|
+
if (!archBinary) {
|
|
26112
|
+
throw new Error(`${arch} is not supported`);
|
|
26201
26113
|
}
|
|
26202
|
-
return
|
|
26114
|
+
return archBinary;
|
|
26203
26115
|
}
|
|
26204
|
-
function
|
|
26205
|
-
if (
|
|
26206
|
-
return
|
|
26207
|
-
|
|
26208
|
-
|
|
26209
|
-
|
|
26210
|
-
|
|
26211
|
-
|
|
26212
|
-
return `${Math.round(minutes / 1440)}d limit`;
|
|
26213
|
-
return "Weekly limit";
|
|
26116
|
+
function detectPlatformBinary({ [platform]: platformBinary }, { wsl } = {}) {
|
|
26117
|
+
if (wsl && is_wsl_default) {
|
|
26118
|
+
return detectArchBinary(wsl);
|
|
26119
|
+
}
|
|
26120
|
+
if (!platformBinary) {
|
|
26121
|
+
throw new Error(`${platform} is not supported`);
|
|
26122
|
+
}
|
|
26123
|
+
return detectArchBinary(platformBinary);
|
|
26214
26124
|
}
|
|
26125
|
+
var apps = {
|
|
26126
|
+
browser: "browser",
|
|
26127
|
+
browserPrivate: "browserPrivate"
|
|
26128
|
+
};
|
|
26129
|
+
defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
|
|
26130
|
+
darwin: "google chrome",
|
|
26131
|
+
win32: "chrome",
|
|
26132
|
+
linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
|
|
26133
|
+
}, {
|
|
26134
|
+
wsl: {
|
|
26135
|
+
ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
|
26136
|
+
x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
|
|
26137
|
+
}
|
|
26138
|
+
}));
|
|
26139
|
+
defineLazyProperty(apps, "brave", () => detectPlatformBinary({
|
|
26140
|
+
darwin: "brave browser",
|
|
26141
|
+
win32: "brave",
|
|
26142
|
+
linux: ["brave-browser", "brave"]
|
|
26143
|
+
}, {
|
|
26144
|
+
wsl: {
|
|
26145
|
+
ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
|
|
26146
|
+
x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
|
|
26147
|
+
}
|
|
26148
|
+
}));
|
|
26149
|
+
defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
|
|
26150
|
+
darwin: "firefox",
|
|
26151
|
+
win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
|
|
26152
|
+
linux: "firefox"
|
|
26153
|
+
}, {
|
|
26154
|
+
wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
|
|
26155
|
+
}));
|
|
26156
|
+
defineLazyProperty(apps, "edge", () => detectPlatformBinary({
|
|
26157
|
+
darwin: "microsoft edge",
|
|
26158
|
+
win32: "msedge",
|
|
26159
|
+
linux: ["microsoft-edge", "microsoft-edge-dev"]
|
|
26160
|
+
}, {
|
|
26161
|
+
wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
|
|
26162
|
+
}));
|
|
26163
|
+
defineLazyProperty(apps, "safari", () => detectPlatformBinary({
|
|
26164
|
+
darwin: "Safari"
|
|
26165
|
+
}));
|
|
26166
|
+
var open_default = open;
|
|
26215
26167
|
|
|
26216
|
-
// src/agent/
|
|
26217
|
-
|
|
26218
|
-
|
|
26219
|
-
|
|
26220
|
-
|
|
26221
|
-
|
|
26222
|
-
|
|
26223
|
-
|
|
26224
|
-
|
|
26225
|
-
|
|
26226
|
-
|
|
26227
|
-
|
|
26168
|
+
// src/agent/auth.ts
|
|
26169
|
+
var AuthMethodId = {
|
|
26170
|
+
ApiKey: "api-key",
|
|
26171
|
+
ChatGpt: "chat-gpt",
|
|
26172
|
+
ChatGptDeviceCode: "chat-gpt-device-code"
|
|
26173
|
+
};
|
|
26174
|
+
var CODEX_API_KEY_ENV = "CODEX_API_KEY";
|
|
26175
|
+
var OPENAI_API_KEY_ENV = "OPENAI_API_KEY";
|
|
26176
|
+
function authMethods(capabilities, env = process.env) {
|
|
26177
|
+
const methods2 = [{
|
|
26178
|
+
type: "agent",
|
|
26179
|
+
methodId: AuthMethodId.ApiKey,
|
|
26180
|
+
name: "API key",
|
|
26181
|
+
description: `Use the API key from ${CODEX_API_KEY_ENV} or ${OPENAI_API_KEY_ENV}, or pass it in _meta["api-key"].apiKey`
|
|
26182
|
+
}];
|
|
26183
|
+
if (!env["NO_BROWSER"]) {
|
|
26184
|
+
methods2.push({
|
|
26185
|
+
type: "agent",
|
|
26186
|
+
methodId: AuthMethodId.ChatGpt,
|
|
26187
|
+
name: "ChatGPT",
|
|
26188
|
+
description: "Sign in to ChatGPT in your browser"
|
|
26189
|
+
});
|
|
26190
|
+
}
|
|
26191
|
+
if (capabilities.urlElicitation) {
|
|
26192
|
+
methods2.push({
|
|
26193
|
+
type: "agent",
|
|
26194
|
+
methodId: AuthMethodId.ChatGptDeviceCode,
|
|
26195
|
+
name: "ChatGPT (device code)",
|
|
26196
|
+
description: "Sign in to ChatGPT by opening a verification page and entering a one-time code"
|
|
26197
|
+
});
|
|
26198
|
+
}
|
|
26199
|
+
return methods2;
|
|
26228
26200
|
}
|
|
26229
|
-
async function
|
|
26230
|
-
switch (request.
|
|
26231
|
-
case
|
|
26232
|
-
|
|
26233
|
-
|
|
26234
|
-
|
|
26235
|
-
|
|
26236
|
-
return;
|
|
26237
|
-
}
|
|
26238
|
-
case MODEL_CONFIG_ID: {
|
|
26239
|
-
const modelId = stringValue(request);
|
|
26240
|
-
const model = findModel(session.catalog, modelId);
|
|
26241
|
-
session.model = { model: modelId, effort: coerceEffort(model, session.model.effort) };
|
|
26242
|
-
if (!modelSupportsFast(model))
|
|
26243
|
-
session.fastMode = false;
|
|
26244
|
-
return;
|
|
26245
|
-
}
|
|
26246
|
-
case EFFORT_CONFIG_ID: {
|
|
26247
|
-
const effort = stringValue(request);
|
|
26248
|
-
const model = findModel(session.catalog, session.model.model);
|
|
26249
|
-
const efforts = supportedEfforts(model);
|
|
26250
|
-
if (efforts.length > 0 && !efforts.some((option) => option.reasoningEffort === effort)) {
|
|
26251
|
-
throw RequestError.invalidParams({ configId: request.configId }, `Model ${session.model.model} does not support effort "${effort}"`);
|
|
26252
|
-
}
|
|
26253
|
-
session.model = { ...session.model, effort };
|
|
26254
|
-
return;
|
|
26255
|
-
}
|
|
26256
|
-
case FAST_MODE_CONFIG_ID: {
|
|
26257
|
-
if (request.type !== "boolean" || typeof request.value !== "boolean") {
|
|
26258
|
-
throw RequestError.invalidParams({ configId: request.configId }, "fast_mode expects a boolean value");
|
|
26259
|
-
}
|
|
26260
|
-
if (request.value && !modelSupportsFast(findModel(session.catalog, session.model.model))) {
|
|
26261
|
-
throw RequestError.invalidParams({ configId: request.configId }, `Model ${session.model.model} does not support fast mode`);
|
|
26262
|
-
}
|
|
26263
|
-
session.fastMode = request.value;
|
|
26264
|
-
return;
|
|
26265
|
-
}
|
|
26266
|
-
case COLLABORATION_MODE_CONFIG_ID: {
|
|
26267
|
-
const mode = parseCollaborationMode(stringValue(request));
|
|
26268
|
-
if (!mode)
|
|
26269
|
-
throw RequestError.invalidParams({ configId: request.configId }, `Unknown collaboration mode "${String(request.value)}"`);
|
|
26270
|
-
await codex.threadSettingsUpdate({
|
|
26271
|
-
threadId: session.id,
|
|
26272
|
-
collaborationMode: {
|
|
26273
|
-
mode,
|
|
26274
|
-
settings: { model: findModel(session.catalog, session.model.model)?.model ?? session.model.model, reasoning_effort: session.model.effort, developer_instructions: null }
|
|
26275
|
-
}
|
|
26276
|
-
});
|
|
26277
|
-
session.collaborationMode = mode;
|
|
26278
|
-
return;
|
|
26279
|
-
}
|
|
26201
|
+
async function login(codex, link, request, requestId, env = process.env) {
|
|
26202
|
+
switch (request.methodId) {
|
|
26203
|
+
case AuthMethodId.ApiKey:
|
|
26204
|
+
return await loginWithApiKey(codex, request, env);
|
|
26205
|
+
case AuthMethodId.ChatGpt:
|
|
26206
|
+
return await loginWithChatGpt(codex);
|
|
26207
|
+
case AuthMethodId.ChatGptDeviceCode:
|
|
26208
|
+
return await loginWithDeviceCode(codex, link, requestId);
|
|
26280
26209
|
default:
|
|
26281
|
-
throw RequestError.invalidParams({
|
|
26210
|
+
throw RequestError.invalidParams({ methodId: request.methodId }, `Unknown auth method "${request.methodId}"; expected one of ${Object.values(AuthMethodId).join(", ")}`);
|
|
26282
26211
|
}
|
|
26283
26212
|
}
|
|
26284
|
-
function
|
|
26285
|
-
|
|
26286
|
-
|
|
26213
|
+
async function loginWithApiKey(codex, request, env) {
|
|
26214
|
+
const meta = request._meta?.["api-key"];
|
|
26215
|
+
const fromMeta = typeof meta === "object" && meta !== null ? meta.apiKey : undefined;
|
|
26216
|
+
const apiKey = typeof fromMeta === "string" && fromMeta.trim().length > 0 ? fromMeta.trim() : env[CODEX_API_KEY_ENV]?.trim() || env[OPENAI_API_KEY_ENV]?.trim();
|
|
26217
|
+
if (!apiKey) {
|
|
26218
|
+
throw RequestError.invalidParams({ envVars: [CODEX_API_KEY_ENV, OPENAI_API_KEY_ENV] }, `No API key: set ${CODEX_API_KEY_ENV} or ${OPENAI_API_KEY_ENV}, or pass _meta["api-key"].apiKey`);
|
|
26287
26219
|
}
|
|
26288
|
-
|
|
26220
|
+
await codex.withNotification("account/login/completed", async (completed) => {
|
|
26221
|
+
await codex.accountLogin({ type: "apiKey", apiKey });
|
|
26222
|
+
const result = await completed;
|
|
26223
|
+
if (!result.success)
|
|
26224
|
+
throw RequestError.authRequired({ error: result.error }, result.error ?? "API key login failed");
|
|
26225
|
+
});
|
|
26289
26226
|
}
|
|
26290
|
-
|
|
26291
|
-
|
|
26292
|
-
|
|
26293
|
-
|
|
26294
|
-
|
|
26295
|
-
|
|
26296
|
-
|
|
26297
|
-
|
|
26298
|
-
|
|
26299
|
-
|
|
26227
|
+
async function loginWithChatGpt(codex) {
|
|
26228
|
+
const account = await codex.accountRead({ refreshToken: true });
|
|
26229
|
+
if (account.account?.type === "chatgpt")
|
|
26230
|
+
return;
|
|
26231
|
+
await codex.withNotification("account/login/completed", async (completed) => {
|
|
26232
|
+
const started = await codex.accountLogin({ type: "chatgpt" });
|
|
26233
|
+
if (started.type !== "chatgpt")
|
|
26234
|
+
throw RequestError.internalError({ type: started.type }, "Unexpected login response");
|
|
26235
|
+
logger.log("opening browser for ChatGPT login", { loginId: started.loginId });
|
|
26236
|
+
await open_default(started.authUrl);
|
|
26237
|
+
const result = await completed;
|
|
26238
|
+
if (!result.success)
|
|
26239
|
+
throw RequestError.authRequired({ error: result.error }, result.error ?? "ChatGPT login failed");
|
|
26240
|
+
});
|
|
26300
26241
|
}
|
|
26301
|
-
function
|
|
26302
|
-
const
|
|
26303
|
-
if (
|
|
26304
|
-
return
|
|
26305
|
-
|
|
26306
|
-
|
|
26307
|
-
|
|
26308
|
-
|
|
26309
|
-
|
|
26310
|
-
|
|
26311
|
-
|
|
26242
|
+
async function loginWithDeviceCode(codex, link, requestId) {
|
|
26243
|
+
const account = await codex.accountRead({ refreshToken: true });
|
|
26244
|
+
if (account.account?.type === "chatgpt")
|
|
26245
|
+
return;
|
|
26246
|
+
await codex.withNotification("account/login/completed", async (completed) => {
|
|
26247
|
+
const started = await codex.accountLogin({ type: "chatgptDeviceCode" });
|
|
26248
|
+
if (started.type !== "chatgptDeviceCode")
|
|
26249
|
+
throw RequestError.internalError({ type: started.type }, "Unexpected login response");
|
|
26250
|
+
const elicitation = link.request(methods.client.elicitation.create, {
|
|
26251
|
+
mode: "url",
|
|
26252
|
+
requestId,
|
|
26253
|
+
elicitationId: started.loginId,
|
|
26254
|
+
url: started.verificationUrl,
|
|
26255
|
+
message: `Sign in to ChatGPT and enter this code: ${started.userCode}`
|
|
26256
|
+
});
|
|
26257
|
+
elicitation.catch(() => {});
|
|
26258
|
+
const first = await Promise.race([
|
|
26259
|
+
completed.then((result2) => ({ kind: "completed", result: result2 })),
|
|
26260
|
+
elicitation.then((response) => ({ kind: "elicitation", response }))
|
|
26261
|
+
]);
|
|
26262
|
+
if (first.kind === "elicitation" && !CreateElicitationResponse.isAccept(first.response)) {
|
|
26263
|
+
await codex.accountLoginCancel({ loginId: started.loginId });
|
|
26264
|
+
throw RequestError.authRequired(undefined, "ChatGPT device code login was cancelled");
|
|
26312
26265
|
}
|
|
26313
|
-
|
|
26314
|
-
|
|
26315
|
-
|
|
26316
|
-
}
|
|
26317
|
-
|
|
26318
|
-
const line = text2.split(/\r?\n/).map((part) => part.trim()).find((part) => part.length > 0) ?? text2;
|
|
26319
|
-
return line.length > 120 ? `${line.slice(0, 117)}...` : line;
|
|
26266
|
+
const result = first.kind === "completed" ? first.result : await completed;
|
|
26267
|
+
await link.notify(methods.client.elicitation.complete, { elicitationId: started.loginId });
|
|
26268
|
+
if (!result.success)
|
|
26269
|
+
throw RequestError.authRequired({ error: result.error }, result.error ?? "ChatGPT login failed");
|
|
26270
|
+
});
|
|
26320
26271
|
}
|
|
26321
|
-
|
|
26322
|
-
|
|
26323
|
-
|
|
26324
|
-
|
|
26325
|
-
|
|
26326
|
-
var OPENAI_PROVIDER_ID = "openai";
|
|
26327
|
-
var GATEWAY_MODEL_PROVIDER = "custom-gateway";
|
|
26328
|
-
var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
26329
|
-
var GATEWAY_ID_PATTERN = /^[a-z0-9-]+$/;
|
|
26330
|
-
function gatewayModelId(connectionId, modelId) {
|
|
26331
|
-
return `gateway:${encodeURIComponent(connectionId)}:${encodeURIComponent(modelId)}`;
|
|
26272
|
+
async function logout(codex) {
|
|
26273
|
+
await codex.withNotification("account/updated", async (updated) => {
|
|
26274
|
+
await codex.accountLogout();
|
|
26275
|
+
await updated;
|
|
26276
|
+
});
|
|
26332
26277
|
}
|
|
26333
26278
|
|
|
26334
|
-
|
|
26335
|
-
|
|
26336
|
-
|
|
26337
|
-
|
|
26338
|
-
|
|
26339
|
-
|
|
26340
|
-
|
|
26341
|
-
|
|
26342
|
-
|
|
26343
|
-
|
|
26344
|
-
|
|
26345
|
-
|
|
26346
|
-
|
|
26347
|
-
|
|
26348
|
-
return this.gateways.values().next().value ?? null;
|
|
26349
|
-
}
|
|
26350
|
-
gateway(id) {
|
|
26351
|
-
return id === null ? null : this.gateways.get(id) ?? null;
|
|
26352
|
-
}
|
|
26353
|
-
hasGateway(id) {
|
|
26354
|
-
return id !== null && this.gateways.has(id);
|
|
26355
|
-
}
|
|
26356
|
-
list() {
|
|
26357
|
-
const first = this.active;
|
|
26358
|
-
const routed = first !== null && first.mode === "route";
|
|
26359
|
-
const summary = (gateway) => ({ id: gateway.id, name: gateway.name, baseUrl: gateway.baseUrl, models: gateway.models.map((model) => model.id) });
|
|
26360
|
-
return {
|
|
26361
|
-
providers: [{
|
|
26362
|
-
providerId: OPENAI_PROVIDER_ID,
|
|
26363
|
-
supported: ["openai"],
|
|
26364
|
-
required: false,
|
|
26365
|
-
current: routed && first ? { apiType: "openai", baseUrl: first.baseUrl } : { apiType: "openai", baseUrl: this.nativeBaseUrl() },
|
|
26366
|
-
...first && !routed ? { _meta: { codex: { mode: "catalog", gateway: summary(first), gateways: [...this.gateways.values()].map(summary) } } } : {}
|
|
26367
|
-
}]
|
|
26368
|
-
};
|
|
26369
|
-
}
|
|
26370
|
-
set(request) {
|
|
26371
|
-
if (request.providerId !== OPENAI_PROVIDER_ID) {
|
|
26372
|
-
throw RequestError.invalidParams({ providerId: request.providerId }, `Unknown providerId "${request.providerId}"; only "${OPENAI_PROVIDER_ID}" is configurable`);
|
|
26373
|
-
}
|
|
26374
|
-
if (request.apiType !== "openai") {
|
|
26375
|
-
throw RequestError.invalidParams({ apiType: request.apiType }, `Codex only speaks the OpenAI protocol; got apiType "${request.apiType}"`);
|
|
26376
|
-
}
|
|
26377
|
-
const baseUrl = typeof request.baseUrl === "string" ? request.baseUrl.trim() : "";
|
|
26378
|
-
if (!/^https?:\/\//.test(baseUrl)) {
|
|
26379
|
-
throw RequestError.invalidParams({ baseUrl: request.baseUrl }, "baseUrl must be an http(s) URL");
|
|
26380
|
-
}
|
|
26381
|
-
const hints = readHints(request._meta);
|
|
26382
|
-
if (hints.id === OPENAI_PROVIDER_ID || hints.id === this.configuredProvider) {
|
|
26383
|
-
throw RequestError.invalidParams({ id: hints.id }, `_meta.codex.id "${hints.id}" is Codex's own provider; pick another gateway id`);
|
|
26384
|
-
}
|
|
26385
|
-
if (hints.mode === "route" || this.mode !== hints.mode)
|
|
26386
|
-
this.gateways.clear();
|
|
26387
|
-
this.gateways.set(hints.id, {
|
|
26388
|
-
id: hints.id,
|
|
26389
|
-
baseUrl,
|
|
26390
|
-
headers: { ...request.headers ?? {} },
|
|
26391
|
-
name: hints.name ?? "Client-configured gateway",
|
|
26392
|
-
models: hints.models,
|
|
26393
|
-
model: hints.model,
|
|
26394
|
-
bearerToken: hints.bearerToken,
|
|
26395
|
-
config: hints.config,
|
|
26396
|
-
mode: hints.mode,
|
|
26397
|
-
catalogEntries: hints.catalogEntries
|
|
26398
|
-
});
|
|
26399
|
-
}
|
|
26400
|
-
get mode() {
|
|
26401
|
-
return this.active?.mode ?? "route";
|
|
26279
|
+
// src/agent/clientSession.ts
|
|
26280
|
+
class ClientSession {
|
|
26281
|
+
sessionId;
|
|
26282
|
+
link;
|
|
26283
|
+
capabilities;
|
|
26284
|
+
waiting = 0;
|
|
26285
|
+
turnActive = false;
|
|
26286
|
+
turnGeneration = 0;
|
|
26287
|
+
disposed = false;
|
|
26288
|
+
output = new AbortController;
|
|
26289
|
+
terminalAttempted = false;
|
|
26290
|
+
messageId;
|
|
26291
|
+
get signal() {
|
|
26292
|
+
return this.output.signal;
|
|
26402
26293
|
}
|
|
26403
|
-
|
|
26404
|
-
|
|
26405
|
-
|
|
26406
|
-
|
|
26407
|
-
}
|
|
26408
|
-
return null;
|
|
26294
|
+
constructor(sessionId, link, capabilities) {
|
|
26295
|
+
this.sessionId = sessionId;
|
|
26296
|
+
this.link = link;
|
|
26297
|
+
this.capabilities = capabilities;
|
|
26409
26298
|
}
|
|
26410
|
-
|
|
26411
|
-
|
|
26299
|
+
async update(update) {
|
|
26300
|
+
if (this.disposed)
|
|
26301
|
+
return;
|
|
26302
|
+
await abortable(this.link.notify(methods.client.session.update, { sessionId: this.sessionId, update }), this.output.signal);
|
|
26412
26303
|
}
|
|
26413
|
-
|
|
26414
|
-
|
|
26304
|
+
async updateAll(updates) {
|
|
26305
|
+
for (const update of updates)
|
|
26306
|
+
await this.update(update);
|
|
26415
26307
|
}
|
|
26416
|
-
|
|
26417
|
-
|
|
26418
|
-
|
|
26419
|
-
return
|
|
26308
|
+
async requestPermission(request, signal) {
|
|
26309
|
+
signal = signal ? AbortSignal.any([signal, this.output.signal]) : this.output.signal;
|
|
26310
|
+
signal.throwIfAborted();
|
|
26311
|
+
return await this.waitingOnClient(() => {
|
|
26312
|
+
signal?.throwIfAborted();
|
|
26313
|
+
const pending = this.link.request(methods.client.session.requestPermission, { sessionId: this.sessionId, ...request }, signal ? { cancellationSignal: signal } : undefined);
|
|
26314
|
+
return signal ? abortable(pending, signal) : pending;
|
|
26315
|
+
}, signal);
|
|
26420
26316
|
}
|
|
26421
|
-
|
|
26422
|
-
return
|
|
26317
|
+
async requestTool(params, signal) {
|
|
26318
|
+
return await this.link.request("_alwith/tool/call", params, { cancellationSignal: signal });
|
|
26423
26319
|
}
|
|
26424
|
-
|
|
26425
|
-
|
|
26426
|
-
|
|
26427
|
-
|
|
26428
|
-
|
|
26429
|
-
|
|
26430
|
-
|
|
26431
|
-
|
|
26320
|
+
async createElicitation(request, signal) {
|
|
26321
|
+
signal = signal ? AbortSignal.any([signal, this.output.signal]) : this.output.signal;
|
|
26322
|
+
signal.throwIfAborted();
|
|
26323
|
+
return await this.waitingOnClient(() => {
|
|
26324
|
+
signal?.throwIfAborted();
|
|
26325
|
+
const pending = this.link.request(methods.client.elicitation.create, request, signal ? { cancellationSignal: signal } : undefined);
|
|
26326
|
+
return signal ? abortable(pending, signal) : pending;
|
|
26327
|
+
}, signal);
|
|
26432
26328
|
}
|
|
26433
|
-
|
|
26434
|
-
if (
|
|
26329
|
+
async completeElicitation(elicitationId) {
|
|
26330
|
+
if (this.disposed)
|
|
26435
26331
|
return;
|
|
26436
|
-
|
|
26437
|
-
if (id === null)
|
|
26438
|
-
this.gateways.clear();
|
|
26439
|
-
else
|
|
26440
|
-
this.gateways.delete(id);
|
|
26441
|
-
}
|
|
26442
|
-
modelProvider() {
|
|
26443
|
-
return this.defaultGatewayId() ?? this.configuredProvider;
|
|
26444
|
-
}
|
|
26445
|
-
routesByDefault() {
|
|
26446
|
-
return this.defaultGatewayId() !== null;
|
|
26332
|
+
await abortable(this.link.notify(methods.client.elicitation.complete, { elicitationId }), this.output.signal);
|
|
26447
26333
|
}
|
|
26448
|
-
|
|
26449
|
-
|
|
26450
|
-
|
|
26334
|
+
reportRunning(messageId) {
|
|
26335
|
+
this.messageId = messageId;
|
|
26336
|
+
this.terminalAttempted = false;
|
|
26337
|
+
this.turnGeneration += 1;
|
|
26338
|
+
this.turnActive = true;
|
|
26339
|
+
this.waiting = 0;
|
|
26340
|
+
this.state({ sessionUpdate: "state_update", state: "running" });
|
|
26451
26341
|
}
|
|
26452
|
-
|
|
26453
|
-
|
|
26454
|
-
|
|
26455
|
-
|
|
26456
|
-
|
|
26342
|
+
async reportIdle(stopReason, extra, messageId = this.messageId) {
|
|
26343
|
+
if (messageId !== this.messageId)
|
|
26344
|
+
return;
|
|
26345
|
+
if (this.terminalAttempted)
|
|
26346
|
+
return;
|
|
26347
|
+
this.terminalAttempted = true;
|
|
26348
|
+
this.turnActive = false;
|
|
26349
|
+
this.waiting = 0;
|
|
26350
|
+
await this.update(this.correlated({
|
|
26351
|
+
sessionUpdate: "state_update",
|
|
26352
|
+
state: "idle",
|
|
26353
|
+
stopReason,
|
|
26354
|
+
...extra?.usage === undefined ? {} : { usage: extra.usage },
|
|
26355
|
+
...extra?._meta === undefined ? {} : { _meta: extra._meta }
|
|
26356
|
+
}));
|
|
26457
26357
|
}
|
|
26458
|
-
|
|
26459
|
-
|
|
26358
|
+
correlated(update) {
|
|
26359
|
+
if (this.messageId === undefined)
|
|
26360
|
+
return update;
|
|
26361
|
+
const meta = update._meta;
|
|
26362
|
+
const alwith = meta?.["alwith"];
|
|
26363
|
+
return { ...update, _meta: { ...meta, alwith: { ...alwith, messageId: this.messageId } } };
|
|
26460
26364
|
}
|
|
26461
|
-
|
|
26462
|
-
|
|
26463
|
-
|
|
26464
|
-
|
|
26465
|
-
|
|
26466
|
-
|
|
26365
|
+
async waitingOnClient(operation, signal) {
|
|
26366
|
+
if (this.disposed)
|
|
26367
|
+
throw new Error("Session is closed");
|
|
26368
|
+
const generation = this.turnActive ? this.turnGeneration : null;
|
|
26369
|
+
try {
|
|
26370
|
+
if (generation !== null && this.waiting++ === 0) {
|
|
26371
|
+
const pending = this.state({ sessionUpdate: "state_update", state: "requires_action" });
|
|
26372
|
+
await (signal ? abortable(pending, signal) : pending);
|
|
26373
|
+
}
|
|
26374
|
+
return await operation();
|
|
26375
|
+
} finally {
|
|
26376
|
+
if (this.turnActive && generation === this.turnGeneration && --this.waiting === 0) {
|
|
26377
|
+
const pending = this.state({ sessionUpdate: "state_update", state: "running" });
|
|
26378
|
+
await (signal ? abortable(pending, signal).catch(() => {}) : pending);
|
|
26379
|
+
}
|
|
26380
|
+
}
|
|
26467
26381
|
}
|
|
26468
|
-
|
|
26469
|
-
|
|
26470
|
-
|
|
26471
|
-
|
|
26472
|
-
|
|
26473
|
-
else
|
|
26474
|
-
delete next[key];
|
|
26382
|
+
async state(update) {
|
|
26383
|
+
try {
|
|
26384
|
+
await this.update(this.correlated(update));
|
|
26385
|
+
} catch (error40) {
|
|
26386
|
+
logger.error("Failed to publish session state", error40, { sessionId: this.sessionId });
|
|
26475
26387
|
}
|
|
26476
|
-
delete next["model_providers"];
|
|
26477
|
-
if (isRecord2(this.baseConfig["model_providers"]))
|
|
26478
|
-
next["model_providers"] = this.baseConfig["model_providers"];
|
|
26479
|
-
const gateway = this.gateway(gatewayId);
|
|
26480
|
-
return gateway ? this.applyGateway(next, gateway) : next;
|
|
26481
26388
|
}
|
|
26482
|
-
|
|
26483
|
-
|
|
26484
|
-
|
|
26485
|
-
|
|
26486
|
-
|
|
26487
|
-
wire_api: "responses",
|
|
26488
|
-
http_headers: { "X-Client-Feature-ID": "codex", ...gateway.headers }
|
|
26489
|
-
};
|
|
26490
|
-
if (gateway.bearerToken !== null)
|
|
26491
|
-
entry["experimental_bearer_token"] = gateway.bearerToken;
|
|
26492
|
-
return {
|
|
26493
|
-
...config2,
|
|
26494
|
-
...gateway.config,
|
|
26495
|
-
model_providers: { ...existing, [gateway.id]: entry }
|
|
26496
|
-
};
|
|
26389
|
+
dispose() {
|
|
26390
|
+
this.disposed = true;
|
|
26391
|
+
this.output.abort();
|
|
26392
|
+
this.turnActive = false;
|
|
26393
|
+
this.waiting = 0;
|
|
26497
26394
|
}
|
|
26498
|
-
|
|
26499
|
-
|
|
26500
|
-
|
|
26501
|
-
|
|
26502
|
-
|
|
26503
|
-
|
|
26504
|
-
|
|
26505
|
-
|
|
26506
|
-
|
|
26507
|
-
|
|
26508
|
-
|
|
26509
|
-
|
|
26510
|
-
|
|
26511
|
-
|
|
26512
|
-
|
|
26395
|
+
}
|
|
26396
|
+
|
|
26397
|
+
// src/agent/commands.ts
|
|
26398
|
+
var BUILTIN_COMMANDS = [
|
|
26399
|
+
{ name: "plan", description: "Toggle plan mode: Codex proposes a plan before making changes" },
|
|
26400
|
+
{ name: "review", description: "Review uncommitted changes, or review with custom instructions", input: { type: "text", hint: "optional review instructions" } },
|
|
26401
|
+
{ name: "review-branch", description: "Review changes relative to a base branch", input: { type: "text", hint: "branch name" } },
|
|
26402
|
+
{ name: "review-commit", description: "Review a specific commit", input: { type: "text", hint: "commit sha" } },
|
|
26403
|
+
{ name: "compact", description: "Summarize the conversation to free up context" },
|
|
26404
|
+
{ name: "status", description: "Show session configuration, token usage, and rate limits" },
|
|
26405
|
+
{ name: "mcp", description: "List configured Model Context Protocol (MCP) servers" },
|
|
26406
|
+
{ name: "skills", description: "List available skills" },
|
|
26407
|
+
{ name: "logout", description: "Sign out of the Codex account" }
|
|
26408
|
+
];
|
|
26409
|
+
function parseCommand(prompt) {
|
|
26410
|
+
const first = prompt[0];
|
|
26411
|
+
if (!first || first.type !== "text")
|
|
26412
|
+
return null;
|
|
26413
|
+
const text2 = first.text.trim();
|
|
26414
|
+
if (!text2.startsWith("/"))
|
|
26415
|
+
return null;
|
|
26416
|
+
const body = text2.slice(1).trim();
|
|
26417
|
+
const [name] = body.split(/\s+/);
|
|
26418
|
+
if (!name || name.startsWith("$"))
|
|
26419
|
+
return null;
|
|
26420
|
+
return { name: name.toLowerCase(), rest: body.slice(name.length).trim() };
|
|
26421
|
+
}
|
|
26422
|
+
function resolveCommand(command, session) {
|
|
26423
|
+
switch (command.name) {
|
|
26424
|
+
case "plan":
|
|
26425
|
+
return {
|
|
26426
|
+
kind: "config",
|
|
26427
|
+
configId: COLLABORATION_MODE_CONFIG_ID,
|
|
26428
|
+
value: session.collaborationMode === PLAN_COLLABORATION_MODE ? DEFAULT_COLLABORATION_MODE : PLAN_COLLABORATION_MODE
|
|
26429
|
+
};
|
|
26430
|
+
case "compact":
|
|
26431
|
+
return { kind: "compact" };
|
|
26432
|
+
case "review":
|
|
26433
|
+
return { kind: "review", target: command.rest.length > 0 ? { type: "custom", instructions: command.rest } : { type: "uncommittedChanges" } };
|
|
26434
|
+
case "review-branch":
|
|
26435
|
+
return command.rest.length > 0 ? { kind: "review", target: { type: "baseBranch", branch: command.rest } } : { kind: "message", text: usage("review-branch", "<branch name>") };
|
|
26436
|
+
case "review-commit":
|
|
26437
|
+
return command.rest.length > 0 ? { kind: "review", target: { type: "commit", sha: command.rest, title: null } } : { kind: "message", text: usage("review-commit", "<commit sha>") };
|
|
26438
|
+
case "logout":
|
|
26439
|
+
return { kind: "logout" };
|
|
26440
|
+
case "status":
|
|
26441
|
+
case "mcp":
|
|
26442
|
+
case "skills":
|
|
26443
|
+
return { kind: "message", text: "" };
|
|
26444
|
+
default:
|
|
26445
|
+
return { kind: "prompt" };
|
|
26513
26446
|
}
|
|
26514
|
-
|
|
26515
|
-
|
|
26516
|
-
|
|
26517
|
-
|
|
26518
|
-
|
|
26519
|
-
|
|
26520
|
-
|
|
26447
|
+
}
|
|
26448
|
+
function usage(name, hint) {
|
|
26449
|
+
return `Usage: /${name} ${hint}`;
|
|
26450
|
+
}
|
|
26451
|
+
function availableCommands(skills) {
|
|
26452
|
+
const commands = new Map;
|
|
26453
|
+
for (const builtin of BUILTIN_COMMANDS)
|
|
26454
|
+
commands.set(builtin.name, builtin);
|
|
26455
|
+
for (const entry of skills) {
|
|
26456
|
+
for (const skill of entry.skills) {
|
|
26457
|
+
const name = `$${skill.name}`;
|
|
26458
|
+
if (commands.has(name))
|
|
26459
|
+
continue;
|
|
26460
|
+
commands.set(name, { name, description: skill.shortDescription || skill.description || skill.name });
|
|
26521
26461
|
}
|
|
26522
|
-
|
|
26462
|
+
}
|
|
26463
|
+
return [...commands.values()];
|
|
26464
|
+
}
|
|
26465
|
+
function skillsMessage(skills) {
|
|
26466
|
+
const lines = skills.flatMap((entry) => entry.skills).map((skill) => {
|
|
26467
|
+
const description = skill.shortDescription || skill.description;
|
|
26468
|
+
return description ? `- ${skill.name}: ${description}` : `- ${skill.name}`;
|
|
26469
|
+
});
|
|
26470
|
+
return lines.length > 0 ? ["Available skills:", ...lines].join(`
|
|
26471
|
+
`) : "No skills configured.";
|
|
26472
|
+
}
|
|
26473
|
+
async function mcpMessage(codex, session) {
|
|
26474
|
+
const servers = await codex.mcpServerStatusList({});
|
|
26475
|
+
const lines = servers.data.map((server) => {
|
|
26476
|
+
const tools = Object.keys(server.tools ?? {}).length;
|
|
26477
|
+
const resources = (server.resources ?? []).length;
|
|
26478
|
+
return `- ${server.name}: ${tools} tools, ${resources} resources, auth=${server.authStatus}`;
|
|
26479
|
+
});
|
|
26480
|
+
const sessionLines = session.mcpServerNames.map((name) => `- ${name}`);
|
|
26481
|
+
return [
|
|
26482
|
+
lines.length > 0 ? "Configured MCP servers:" : "No MCP servers configured.",
|
|
26483
|
+
...lines,
|
|
26484
|
+
...sessionLines.length > 0 ? ["", "Session MCP servers:", ...sessionLines] : []
|
|
26485
|
+
].join(`
|
|
26486
|
+
`);
|
|
26487
|
+
}
|
|
26488
|
+
function statusMessage(session, rateLimits) {
|
|
26489
|
+
const usage2 = session.lastUsage;
|
|
26490
|
+
const lines = [
|
|
26491
|
+
"**Session**",
|
|
26492
|
+
`**Session ID:** ${session.id}`,
|
|
26493
|
+
`**Working directory:** ${session.cwd}`,
|
|
26494
|
+
`**Model:** ${session.model.model} (${session.model.effort})`,
|
|
26495
|
+
`**Mode:** ${session.mode.name}`,
|
|
26496
|
+
`**Collaboration:** ${session.collaborationMode}`,
|
|
26497
|
+
`**Fast mode:** ${session.fastMode ? "on" : "off"}`,
|
|
26498
|
+
`**Account:** ${accountInfo(session)}`,
|
|
26499
|
+
"",
|
|
26500
|
+
"**Usage**",
|
|
26501
|
+
`**Last turn:** ${usage2 ? `${formatTokenCount(usage2.totalTokens)} total (${formatTokenCount(usage2.inputTokens)} input + ${formatTokenCount(usage2.cachedInputTokens)} cached, ${formatTokenCount(usage2.outputTokens)} output)` : "not available yet"}`,
|
|
26502
|
+
`**Context window:** ${usage2 && session.contextWindow ? `${Math.round((session.contextWindow - usage2.totalTokens) / session.contextWindow * 100)}% left (${formatTokenCount(usage2.totalTokens)} / ${formatTokenCount(session.contextWindow)})` : "not available yet"}`,
|
|
26503
|
+
...rateLimitLines(rateLimits)
|
|
26504
|
+
];
|
|
26505
|
+
return lines.join(`
|
|
26506
|
+
`);
|
|
26507
|
+
}
|
|
26508
|
+
function accountInfo(session) {
|
|
26509
|
+
const account = session.account;
|
|
26510
|
+
if (!account)
|
|
26511
|
+
return "not logged in";
|
|
26512
|
+
switch (account.type) {
|
|
26513
|
+
case "apiKey":
|
|
26514
|
+
return "API key";
|
|
26515
|
+
case "chatgpt":
|
|
26516
|
+
return `ChatGPT ${account.planType}${account.email ? ` (${account.email})` : ""}`;
|
|
26517
|
+
case "amazonBedrock":
|
|
26518
|
+
return "Amazon Bedrock";
|
|
26523
26519
|
}
|
|
26524
26520
|
}
|
|
26525
|
-
function
|
|
26526
|
-
const
|
|
26527
|
-
const
|
|
26528
|
-
|
|
26529
|
-
|
|
26530
|
-
|
|
26531
|
-
if (Array.isArray(alwith["models"])) {
|
|
26532
|
-
for (const entry of alwith["models"]) {
|
|
26533
|
-
if (!isRecord2(entry) || typeof entry["id"] !== "string" || entry["id"].length === 0)
|
|
26521
|
+
function rateLimitLines(rateLimits) {
|
|
26522
|
+
const lines = [];
|
|
26523
|
+
for (const snapshot of rateLimits.values()) {
|
|
26524
|
+
const prefix = snapshot.limitName ? `${snapshot.limitName} ` : "";
|
|
26525
|
+
for (const window of [snapshot.primary, snapshot.secondary]) {
|
|
26526
|
+
if (!window)
|
|
26534
26527
|
continue;
|
|
26535
|
-
|
|
26536
|
-
|
|
26537
|
-
|
|
26538
|
-
description: typeof entry["description"] === "string" ? entry["description"] : null
|
|
26539
|
-
});
|
|
26528
|
+
const label = windowLabel(window.windowDurationMins);
|
|
26529
|
+
const reset = window.resetsAt === null ? "" : ` (resets ${new Date(window.resetsAt * 1000).toLocaleString()})`;
|
|
26530
|
+
lines.push(`**${prefix}${label}:** ${Math.round(100 - window.usedPercent)}% left${reset}`);
|
|
26540
26531
|
}
|
|
26532
|
+
if (snapshot.credits?.unlimited)
|
|
26533
|
+
lines.push(`**${prefix}Credits:** unlimited`);
|
|
26534
|
+
else if (snapshot.credits?.balance)
|
|
26535
|
+
lines.push(`**${prefix}Credits:** ${snapshot.credits.balance}`);
|
|
26541
26536
|
}
|
|
26542
|
-
|
|
26543
|
-
|
|
26544
|
-
|
|
26545
|
-
|
|
26546
|
-
|
|
26547
|
-
|
|
26548
|
-
|
|
26549
|
-
|
|
26550
|
-
|
|
26551
|
-
|
|
26552
|
-
|
|
26553
|
-
|
|
26554
|
-
|
|
26537
|
+
return lines.length > 0 ? lines : ["**Limits:** not available yet"];
|
|
26538
|
+
}
|
|
26539
|
+
function windowLabel(minutes) {
|
|
26540
|
+
if (minutes === null)
|
|
26541
|
+
return "Limit";
|
|
26542
|
+
if (minutes < 60)
|
|
26543
|
+
return `${minutes}m limit`;
|
|
26544
|
+
if (minutes < 1440)
|
|
26545
|
+
return `${Math.round(minutes / 60)}h limit`;
|
|
26546
|
+
if (minutes < 10080)
|
|
26547
|
+
return `${Math.round(minutes / 1440)}d limit`;
|
|
26548
|
+
return "Weekly limit";
|
|
26549
|
+
}
|
|
26550
|
+
|
|
26551
|
+
// src/agent/configOptions.ts
|
|
26552
|
+
function sessionConfigOptions(session) {
|
|
26553
|
+
const model = findModel(session.catalog, session.model.model);
|
|
26554
|
+
const options = [
|
|
26555
|
+
modeConfigOption(session.mode),
|
|
26556
|
+
modelConfigOption(session.catalog, session.model.model, session.gatewayGroups),
|
|
26557
|
+
effortConfigOption(supportedEfforts(model), session.model.effort),
|
|
26558
|
+
collaborationModeConfigOption(session.collaborationMode)
|
|
26559
|
+
];
|
|
26560
|
+
if (modelSupportsFast(model))
|
|
26561
|
+
options.push(fastModeConfigOption(session.fastMode));
|
|
26562
|
+
return options;
|
|
26563
|
+
}
|
|
26564
|
+
async function applyConfigOption(session, codex, request) {
|
|
26565
|
+
switch (request.configId) {
|
|
26566
|
+
case MODE_CONFIG_ID: {
|
|
26567
|
+
const mode = findAgentMode(stringValue(request));
|
|
26568
|
+
if (!mode)
|
|
26569
|
+
throw RequestError.invalidParams({ configId: request.configId }, `Unknown mode "${String(request.value)}"`);
|
|
26570
|
+
session.mode = mode;
|
|
26571
|
+
return;
|
|
26555
26572
|
}
|
|
26573
|
+
case MODEL_CONFIG_ID: {
|
|
26574
|
+
const modelId = stringValue(request);
|
|
26575
|
+
const model = findModel(session.catalog, modelId);
|
|
26576
|
+
session.model = { model: modelId, effort: coerceEffort(model, session.model.effort) };
|
|
26577
|
+
if (!modelSupportsFast(model))
|
|
26578
|
+
session.fastMode = false;
|
|
26579
|
+
return;
|
|
26580
|
+
}
|
|
26581
|
+
case EFFORT_CONFIG_ID: {
|
|
26582
|
+
const effort = stringValue(request);
|
|
26583
|
+
const model = findModel(session.catalog, session.model.model);
|
|
26584
|
+
const efforts = supportedEfforts(model);
|
|
26585
|
+
if (efforts.length > 0 && !efforts.some((option) => option.reasoningEffort === effort)) {
|
|
26586
|
+
throw RequestError.invalidParams({ configId: request.configId }, `Model ${session.model.model} does not support effort "${effort}"`);
|
|
26587
|
+
}
|
|
26588
|
+
session.model = { ...session.model, effort };
|
|
26589
|
+
return;
|
|
26590
|
+
}
|
|
26591
|
+
case FAST_MODE_CONFIG_ID: {
|
|
26592
|
+
if (request.type !== "boolean" || typeof request.value !== "boolean") {
|
|
26593
|
+
throw RequestError.invalidParams({ configId: request.configId }, "fast_mode expects a boolean value");
|
|
26594
|
+
}
|
|
26595
|
+
if (request.value && !modelSupportsFast(findModel(session.catalog, session.model.model))) {
|
|
26596
|
+
throw RequestError.invalidParams({ configId: request.configId }, `Model ${session.model.model} does not support fast mode`);
|
|
26597
|
+
}
|
|
26598
|
+
session.fastMode = request.value;
|
|
26599
|
+
return;
|
|
26600
|
+
}
|
|
26601
|
+
case COLLABORATION_MODE_CONFIG_ID: {
|
|
26602
|
+
const mode = parseCollaborationMode(stringValue(request));
|
|
26603
|
+
if (!mode)
|
|
26604
|
+
throw RequestError.invalidParams({ configId: request.configId }, `Unknown collaboration mode "${String(request.value)}"`);
|
|
26605
|
+
await codex.threadSettingsUpdate({
|
|
26606
|
+
threadId: session.id,
|
|
26607
|
+
collaborationMode: {
|
|
26608
|
+
mode,
|
|
26609
|
+
settings: { model: findModel(session.catalog, session.model.model)?.model ?? session.model.model, reasoning_effort: session.model.effort, developer_instructions: null }
|
|
26610
|
+
}
|
|
26611
|
+
});
|
|
26612
|
+
session.collaborationMode = mode;
|
|
26613
|
+
return;
|
|
26614
|
+
}
|
|
26615
|
+
default:
|
|
26616
|
+
throw RequestError.invalidParams({ configId: request.configId }, `Unknown config option "${request.configId}"`);
|
|
26556
26617
|
}
|
|
26557
|
-
const rawMode = codex["mode"];
|
|
26558
|
-
if (rawMode !== undefined && rawMode !== "route" && rawMode !== "catalog") {
|
|
26559
|
-
throw RequestError.invalidParams({ mode: rawMode }, '_meta.codex.mode must be "route" or "catalog"');
|
|
26560
|
-
}
|
|
26561
|
-
const mode = rawMode === "catalog" ? "catalog" : "route";
|
|
26562
|
-
if (mode === "catalog" && models.length === 0) {
|
|
26563
|
-
throw RequestError.invalidParams(undefined, `_meta.codex.mode "catalog" needs _meta.alwith.models: the models offered next to Codex's`);
|
|
26564
|
-
}
|
|
26565
|
-
const catalogPath = config2["model_catalog_json"];
|
|
26566
|
-
const catalogEntries = typeof catalogPath === "string" ? readCatalogFile(catalogPath) : new Map;
|
|
26567
|
-
return { id, models, model, name, bearerToken, config: config2, mode, catalogEntries };
|
|
26568
26618
|
}
|
|
26569
|
-
function
|
|
26570
|
-
|
|
26571
|
-
|
|
26572
|
-
const raw = codex["id"];
|
|
26573
|
-
if (raw === undefined)
|
|
26574
|
-
return null;
|
|
26575
|
-
if (typeof raw !== "string" || !GATEWAY_ID_PATTERN.test(raw)) {
|
|
26576
|
-
throw RequestError.invalidParams({ id: raw }, "_meta.codex.id must match [a-z0-9-]+");
|
|
26619
|
+
function stringValue(request) {
|
|
26620
|
+
if (typeof request.value !== "string" || request.value.length === 0) {
|
|
26621
|
+
throw RequestError.invalidParams({ configId: request.configId }, `Config option "${request.configId}" expects a string value`);
|
|
26577
26622
|
}
|
|
26578
|
-
return
|
|
26623
|
+
return request.value;
|
|
26579
26624
|
}
|
|
26580
|
-
|
|
26581
|
-
|
|
26582
|
-
|
|
26583
|
-
|
|
26584
|
-
|
|
26585
|
-
|
|
26586
|
-
|
|
26625
|
+
|
|
26626
|
+
// src/agent/history.ts
|
|
26627
|
+
function historyUpdates(turns) {
|
|
26628
|
+
const updates = [];
|
|
26629
|
+
for (const turn of turns) {
|
|
26630
|
+
for (const item of turn.items) {
|
|
26631
|
+
updates.push(...itemSnapshot(item));
|
|
26632
|
+
}
|
|
26587
26633
|
}
|
|
26588
|
-
|
|
26589
|
-
|
|
26590
|
-
|
|
26591
|
-
const
|
|
26592
|
-
|
|
26593
|
-
|
|
26594
|
-
|
|
26595
|
-
const
|
|
26596
|
-
|
|
26597
|
-
for (const level of levels) {
|
|
26598
|
-
if (!isRecord2(level) || typeof level["effort"] !== "string")
|
|
26634
|
+
return updates;
|
|
26635
|
+
}
|
|
26636
|
+
function historyTitle(thread, turns) {
|
|
26637
|
+
const explicit = thread.name?.trim();
|
|
26638
|
+
if (explicit)
|
|
26639
|
+
return explicit;
|
|
26640
|
+
for (const turn of turns) {
|
|
26641
|
+
for (const item of turn.items) {
|
|
26642
|
+
if (item.type !== "userMessage")
|
|
26599
26643
|
continue;
|
|
26600
|
-
|
|
26644
|
+
const text2 = item.content.filter((input) => input.type === "text").map((input) => input.text.trim()).find((part) => part.length > 0);
|
|
26645
|
+
if (text2)
|
|
26646
|
+
return firstLine(text2);
|
|
26601
26647
|
}
|
|
26602
|
-
const modalities = Array.isArray(entry["input_modalities"]) ? entry["input_modalities"].filter((value) => value === "text" || value === "image") : null;
|
|
26603
|
-
entries.set(entry["slug"], {
|
|
26604
|
-
displayName: typeof entry["display_name"] === "string" ? entry["display_name"] : null,
|
|
26605
|
-
description: typeof entry["description"] === "string" ? entry["description"] : null,
|
|
26606
|
-
efforts,
|
|
26607
|
-
defaultEffort: typeof entry["default_reasoning_level"] === "string" ? entry["default_reasoning_level"] : null,
|
|
26608
|
-
inputModalities: modalities
|
|
26609
|
-
});
|
|
26610
26648
|
}
|
|
26611
|
-
|
|
26649
|
+
const preview = thread.preview.trim();
|
|
26650
|
+
return preview.length > 0 ? firstLine(preview) : null;
|
|
26612
26651
|
}
|
|
26613
|
-
function
|
|
26614
|
-
const
|
|
26615
|
-
|
|
26616
|
-
return {
|
|
26617
|
-
id: model.id,
|
|
26618
|
-
model: model.id,
|
|
26619
|
-
upgrade: null,
|
|
26620
|
-
upgradeInfo: null,
|
|
26621
|
-
availabilityNux: null,
|
|
26622
|
-
displayName: model.name !== model.id ? model.name : entry?.displayName ?? model.name,
|
|
26623
|
-
description: model.description ?? entry?.description ?? "",
|
|
26624
|
-
modelSpecialty: null,
|
|
26625
|
-
hidden: false,
|
|
26626
|
-
supportedReasoningEfforts: efforts,
|
|
26627
|
-
defaultReasoningEffort: defaultEffort,
|
|
26628
|
-
inputModalities: entry?.inputModalities ?? ["text", "image"],
|
|
26629
|
-
supportsPersonality: false,
|
|
26630
|
-
multiAgentVersion: null,
|
|
26631
|
-
additionalSpeedTiers: [],
|
|
26632
|
-
serviceTiers: [],
|
|
26633
|
-
defaultServiceTier: null,
|
|
26634
|
-
availableAccessPrograms: null,
|
|
26635
|
-
isDefault
|
|
26636
|
-
};
|
|
26652
|
+
function firstLine(text2) {
|
|
26653
|
+
const line = text2.split(/\r?\n/).map((part) => part.trim()).find((part) => part.length > 0) ?? text2;
|
|
26654
|
+
return line.length > 120 ? `${line.slice(0, 117)}...` : line;
|
|
26637
26655
|
}
|
|
26638
26656
|
|
|
26639
26657
|
// src/agent/session.ts
|
|
@@ -26776,7 +26794,7 @@ class CodexAgent {
|
|
|
26776
26794
|
additionalDirectories: {}
|
|
26777
26795
|
},
|
|
26778
26796
|
providers: {},
|
|
26779
|
-
_meta: { alwith: { tools: { version: 1 } }, codex: { archive: true, seedHistory: true, skills: true, plugins: true, providerCatalog: true, rename: true, account: true, fuzzyFileSearch: true } }
|
|
26797
|
+
_meta: { alwith: { tools: { version: 1 }, turns: { version: 2 } }, codex: { archive: true, seedHistory: true, skills: true, plugins: true, providerCatalog: true, rename: true, account: true, fuzzyFileSearch: true } }
|
|
26780
26798
|
},
|
|
26781
26799
|
authMethods: authMethods(this.capabilities, this.env)
|
|
26782
26800
|
};
|
|
@@ -27533,7 +27551,7 @@ class CodexAgent {
|
|
|
27533
27551
|
return runtime;
|
|
27534
27552
|
}
|
|
27535
27553
|
async prompt(params) {
|
|
27536
|
-
return await this.promptInternal(params, false, crypto.randomUUID());
|
|
27554
|
+
return await this.promptInternal(params, false, requestedMessageId(params) ?? crypto.randomUUID());
|
|
27537
27555
|
}
|
|
27538
27556
|
async promptInternal(params, allowReentry, messageId) {
|
|
27539
27557
|
this.assertRoutingAvailable();
|
|
@@ -27557,7 +27575,7 @@ class CodexAgent {
|
|
|
27557
27575
|
}
|
|
27558
27576
|
const turn = createActiveTurn(session.id, messageId);
|
|
27559
27577
|
session.activeTurn = turn;
|
|
27560
|
-
runtime.client.reportRunning();
|
|
27578
|
+
runtime.client.reportRunning(messageId);
|
|
27561
27579
|
this.runPrompt(runtime, turn, params);
|
|
27562
27580
|
return { messageId };
|
|
27563
27581
|
}
|
|
@@ -27781,7 +27799,7 @@ class CodexAgent {
|
|
|
27781
27799
|
await runtime.bridge.finishOpenToolCalls(reason === "cancelled" ? "cancelled" : reason === "end_turn" ? "completed" : "failed");
|
|
27782
27800
|
if (runtime.session.activeTurn === turn)
|
|
27783
27801
|
runtime.session.activeTurn = null;
|
|
27784
|
-
await runtime.client.reportIdle(reason, extra);
|
|
27802
|
+
await runtime.client.reportIdle(reason, extra, turn.clientUserMessageId ?? undefined);
|
|
27785
27803
|
}
|
|
27786
27804
|
async reportTurnFailure(runtime, turn, error40) {
|
|
27787
27805
|
const { stopReason, ...classification } = classifyTurnError(error40.codexErrorInfo);
|
|
@@ -27966,6 +27984,15 @@ ${stderr}` : ""}`);
|
|
|
27966
27984
|
function mcpServerNames(servers) {
|
|
27967
27985
|
return servers.flatMap((server) => typeof server.name === "string" ? [sanitizeMcpServerName(server.name)] : []);
|
|
27968
27986
|
}
|
|
27987
|
+
function requestedMessageId(params) {
|
|
27988
|
+
const alwith = params._meta?.["alwith"];
|
|
27989
|
+
if (alwith?.messageId === undefined)
|
|
27990
|
+
return;
|
|
27991
|
+
if (typeof alwith.messageId !== "string" || alwith.messageId.length === 0) {
|
|
27992
|
+
throw RequestError.invalidParams(undefined, "_meta.alwith.messageId must be a non-empty string");
|
|
27993
|
+
}
|
|
27994
|
+
return alwith.messageId;
|
|
27995
|
+
}
|
|
27969
27996
|
function agentMessage(messageId, text2) {
|
|
27970
27997
|
return { sessionUpdate: "agent_message_chunk", messageId, content: { type: "text", text: text2 } };
|
|
27971
27998
|
}
|