@ycodium-ai/agent-codex 0.2.3484 → 0.2.3502
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +184 -188
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -55,7 +55,10 @@ var CODEX_CARD = {
|
|
|
55
55
|
// 出处不是 provider 文档:这是产品此前对所有 provider 统一施加的单图上限(10 MiB),
|
|
56
56
|
// codex 在这个上限下一直把图片以 data URL 内联。没有查到 Codex / OpenAI 对单图的明文
|
|
57
57
|
// 上限,所以不声明尺寸与合计上限;查到后改这里即可,宿主不需要跟着变。
|
|
58
|
-
inlineImages: { maxBytes: 10 * 1024 * 1024 }
|
|
58
|
+
inlineImages: { maxBytes: 10 * 1024 * 1024 },
|
|
59
|
+
// 其它文件夹每轮进 sandboxPolicy.writableRoots(codexTurnSandboxPolicyForNativeMode)。
|
|
60
|
+
// CLI 不读这些文件夹里的 AGENTS.md,说明文件由宿主的开场说明点出。
|
|
61
|
+
acceptsAdditionalDirectories: true
|
|
59
62
|
},
|
|
60
63
|
credentialSources: [],
|
|
61
64
|
diagnostics: [],
|
|
@@ -1682,11 +1685,11 @@ function codexThreadConfigForNativeMode(nativeModeId) {
|
|
|
1682
1685
|
return runtimeModeToThreadConfig("approval-required");
|
|
1683
1686
|
}
|
|
1684
1687
|
}
|
|
1685
|
-
function codexTurnSandboxPolicyForNativeMode(nativeModeId) {
|
|
1688
|
+
function codexTurnSandboxPolicyForNativeMode(nativeModeId, additionalDirectories = []) {
|
|
1686
1689
|
switch (nativeModeId) {
|
|
1687
1690
|
case "workspace-write":
|
|
1688
1691
|
case "auto-review":
|
|
1689
|
-
return runtimeModeToTurnSandboxPolicy("auto-accept-edits");
|
|
1692
|
+
return additionalDirectories.length > 0 ? { type: "workspaceWrite", writableRoots: additionalDirectories } : runtimeModeToTurnSandboxPolicy("auto-accept-edits");
|
|
1690
1693
|
case "full-access":
|
|
1691
1694
|
return runtimeModeToTurnSandboxPolicy("full-access");
|
|
1692
1695
|
default:
|
|
@@ -2452,49 +2455,30 @@ async function spawnCodexAppServer(input) {
|
|
|
2452
2455
|
}
|
|
2453
2456
|
|
|
2454
2457
|
// src/cliVersion.ts
|
|
2458
|
+
import {
|
|
2459
|
+
runProcessOperation,
|
|
2460
|
+
isOperationCleanupError
|
|
2461
|
+
} from "@ycodium-ai/plugin-api/process-operation";
|
|
2455
2462
|
var CODEX_VERSION_TIMEOUT_MS = 15e3;
|
|
2456
2463
|
var VERSION_PATTERN = /(?<![\d.])(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)/;
|
|
2457
|
-
async function collect(stream) {
|
|
2458
|
-
const chunks = [];
|
|
2459
|
-
for await (const chunk of stream) {
|
|
2460
|
-
chunks.push(Buffer.from(chunk));
|
|
2461
|
-
if (Buffer.concat(chunks).length > 64 * 1024) break;
|
|
2462
|
-
}
|
|
2463
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
2464
|
-
}
|
|
2465
2464
|
async function readCodexCliVersion(input) {
|
|
2465
|
+
input.signal?.throwIfAborted();
|
|
2466
2466
|
if (input.recipe.binaryPath.length === 0) return null;
|
|
2467
|
-
let handle;
|
|
2468
2467
|
try {
|
|
2469
|
-
|
|
2468
|
+
const { stdout, stderr, exitCode } = await runProcessOperation(input.host, {
|
|
2470
2469
|
program: input.recipe.binaryPath,
|
|
2471
2470
|
args: ["--version"],
|
|
2472
|
-
owner: { bindingId: input.host.bindingId }
|
|
2471
|
+
owner: { bindingId: input.host.bindingId },
|
|
2472
|
+
signal: input.signal,
|
|
2473
|
+
timeoutMs: CODEX_VERSION_TIMEOUT_MS,
|
|
2474
|
+
maxOutputBytes: 64 * 1024
|
|
2473
2475
|
});
|
|
2474
|
-
} catch {
|
|
2475
|
-
return null;
|
|
2476
|
-
}
|
|
2477
|
-
const collected = Promise.all([collect(handle.stdout), collect(handle.stderr), handle.exited]);
|
|
2478
|
-
let timer;
|
|
2479
|
-
const timeout = new Promise((resolve4) => {
|
|
2480
|
-
timer = setTimeout(() => resolve4("timeout"), CODEX_VERSION_TIMEOUT_MS);
|
|
2481
|
-
timer.unref?.();
|
|
2482
|
-
});
|
|
2483
|
-
try {
|
|
2484
|
-
const settled = await Promise.race([collected, timeout]);
|
|
2485
|
-
if (settled === "timeout") {
|
|
2486
|
-
collected.catch(() => void 0);
|
|
2487
|
-
return null;
|
|
2488
|
-
}
|
|
2489
|
-
const [stdout, stderr, exitCode] = settled;
|
|
2490
2476
|
if (exitCode !== 0) return null;
|
|
2491
|
-
return VERSION_PATTERN.exec(
|
|
2492
|
-
|
|
2493
|
-
|
|
2477
|
+
return VERSION_PATTERN.exec(stdout + "\n" + stderr)?.[1] ?? null;
|
|
2478
|
+
} catch (error) {
|
|
2479
|
+
if (isOperationCleanupError(error)) throw error;
|
|
2480
|
+
input.signal?.throwIfAborted();
|
|
2494
2481
|
return null;
|
|
2495
|
-
} finally {
|
|
2496
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
2497
|
-
await handle.kill("SIGTERM").catch(() => void 0);
|
|
2498
2482
|
}
|
|
2499
2483
|
}
|
|
2500
2484
|
|
|
@@ -2726,6 +2710,88 @@ async function createCodexRpcClient(handle, handlers) {
|
|
|
2726
2710
|
};
|
|
2727
2711
|
}
|
|
2728
2712
|
|
|
2713
|
+
// src/processReuse.ts
|
|
2714
|
+
import * as NodeUtil from "node:util";
|
|
2715
|
+
|
|
2716
|
+
// src/skills.ts
|
|
2717
|
+
var SKILLS_LIST_TIMEOUT_MS = 15e3;
|
|
2718
|
+
function codexProbeSkill(raw, includeRepo = false) {
|
|
2719
|
+
if (!isRecord2(raw)) return null;
|
|
2720
|
+
const name = asString(raw["name"]);
|
|
2721
|
+
const path = asString(raw["path"]);
|
|
2722
|
+
const scope = asString(raw["scope"]);
|
|
2723
|
+
if (!name || !path || scope === "repo" && !includeRepo) return null;
|
|
2724
|
+
const face = isRecord2(raw["interface"]) ? raw["interface"] : void 0;
|
|
2725
|
+
const description = asString(raw["description"]);
|
|
2726
|
+
const displayName = asString(face?.["displayName"]);
|
|
2727
|
+
const shortDescription = asString(face?.["shortDescription"]) || asString(raw["shortDescription"]);
|
|
2728
|
+
return {
|
|
2729
|
+
name,
|
|
2730
|
+
path,
|
|
2731
|
+
enabled: raw["enabled"] !== false,
|
|
2732
|
+
...scope ? { scope } : {},
|
|
2733
|
+
...description ? { description } : {},
|
|
2734
|
+
...displayName ? { displayName } : {},
|
|
2735
|
+
...shortDescription ? { shortDescription } : {}
|
|
2736
|
+
};
|
|
2737
|
+
}
|
|
2738
|
+
async function listCodexWorkspaceSkills(rpc, cwd) {
|
|
2739
|
+
const response = await rpc.request("skills/list", { cwds: [cwd] }, SKILLS_LIST_TIMEOUT_MS);
|
|
2740
|
+
if (!isRecord2(response) || !Array.isArray(response["data"])) {
|
|
2741
|
+
throw new Error("skills/list returned an unexpected shape");
|
|
2742
|
+
}
|
|
2743
|
+
const skills = /* @__PURE__ */ new Map();
|
|
2744
|
+
for (const entry of response["data"]) {
|
|
2745
|
+
if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
|
|
2746
|
+
for (const raw of entry["skills"]) {
|
|
2747
|
+
const skill = codexProbeSkill(raw, true);
|
|
2748
|
+
if (skill !== null) skills.set(skill.path, skill);
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
2752
|
+
}
|
|
2753
|
+
async function listCodexSkills(rpc) {
|
|
2754
|
+
let response;
|
|
2755
|
+
try {
|
|
2756
|
+
response = await rpc.request("skills/list", {}, SKILLS_LIST_TIMEOUT_MS);
|
|
2757
|
+
} catch {
|
|
2758
|
+
return void 0;
|
|
2759
|
+
}
|
|
2760
|
+
if (!isRecord2(response) || !Array.isArray(response["data"])) return void 0;
|
|
2761
|
+
const skills = /* @__PURE__ */ new Map();
|
|
2762
|
+
for (const entry of response["data"]) {
|
|
2763
|
+
if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
|
|
2764
|
+
for (const raw of entry["skills"]) {
|
|
2765
|
+
const skill = codexProbeSkill(raw);
|
|
2766
|
+
if (skill !== null) skills.set(skill.path, skill);
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
2770
|
+
}
|
|
2771
|
+
var codexSessionSkillRoot = (skills) => skills === void 0 || skills.names.length === 0 ? void 0 : skills.skillsDir;
|
|
2772
|
+
async function setCodexSessionSkillRoots(rpc, skills, log, threadId) {
|
|
2773
|
+
const root = codexSessionSkillRoot(skills);
|
|
2774
|
+
if (root === void 0) return;
|
|
2775
|
+
try {
|
|
2776
|
+
await rpc.request("skills/extraRoots/set", { extraRoots: [root] });
|
|
2777
|
+
} catch (error) {
|
|
2778
|
+
log.warn("codex did not take the session skill root; skills stay on the built-in tools", {
|
|
2779
|
+
threadId,
|
|
2780
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2781
|
+
});
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
// src/processReuse.ts
|
|
2786
|
+
var reusesCodexProcess = (running, input, cwd) => {
|
|
2787
|
+
const { runtime, launch } = running;
|
|
2788
|
+
const resume = input.discardResumeCursor === true ? void 0 : parseCodexResumeCursor(input.resumeCursor);
|
|
2789
|
+
return !runtime.closing && runtime.nativeThreadId !== void 0 && resume?.threadId === runtime.nativeThreadId && runtime.cwd === cwd && codexNativeModeFor(runtime.runtimeMode, runtime.nativeModeId) === codexNativeModeFor(input.runtimeMode, input.nativeModeId) && NodeUtil.isDeepStrictEqual(
|
|
2790
|
+
codexMcpThreadConfig(launch.mcpServers ?? []),
|
|
2791
|
+
codexMcpThreadConfig(input.mcpServers ?? [])
|
|
2792
|
+
) && codexSessionSkillRoot(launch.skills) === codexSessionSkillRoot(input.skills);
|
|
2793
|
+
};
|
|
2794
|
+
|
|
2729
2795
|
// src/sessionRuntime.ts
|
|
2730
2796
|
import * as NodeCrypto4 from "node:crypto";
|
|
2731
2797
|
|
|
@@ -5225,6 +5291,8 @@ var CodexSessionRuntime = class {
|
|
|
5225
5291
|
/** 这个会话见过的主额度快照(按字段合并),额度用尽停轮时点名窗口用。 */
|
|
5226
5292
|
rateLimits;
|
|
5227
5293
|
appServerArgs;
|
|
5294
|
+
/** 会话除 cwd 外的文件夹,每轮随 `sandboxPolicy` 发;变了由 `setAdditionalDirectories` 换上,进程不重启。 */
|
|
5295
|
+
#additionalDirectories;
|
|
5228
5296
|
hasConfiguredMcpServer;
|
|
5229
5297
|
host;
|
|
5230
5298
|
attachments;
|
|
@@ -5250,7 +5318,8 @@ var CodexSessionRuntime = class {
|
|
|
5250
5318
|
/** 同上,沙箱策略那一位。 */
|
|
5251
5319
|
#turnSandboxPolicy() {
|
|
5252
5320
|
return codexTurnSandboxPolicyForNativeMode(
|
|
5253
|
-
codexNativeModeFor(this.runtimeMode, this.nativeModeId)
|
|
5321
|
+
codexNativeModeFor(this.runtimeMode, this.nativeModeId),
|
|
5322
|
+
this.#additionalDirectories
|
|
5254
5323
|
);
|
|
5255
5324
|
}
|
|
5256
5325
|
constructor(host, rpc, emit, input, cwd, appServerArgs, grants, declineRelay, attachments, closeOptions = {}) {
|
|
@@ -5272,6 +5341,7 @@ var CodexSessionRuntime = class {
|
|
|
5272
5341
|
this.runtimeMode = input.runtimeMode;
|
|
5273
5342
|
this.nativeModeId = input.nativeModeId;
|
|
5274
5343
|
this.appServerArgs = appServerArgs;
|
|
5344
|
+
this.#additionalDirectories = input.additionalDirectories ?? [];
|
|
5275
5345
|
this.hasConfiguredMcpServer = (input.mcpServers?.length ?? 0) > 0;
|
|
5276
5346
|
this.grants = grants ?? createApprovalGrantStore();
|
|
5277
5347
|
this.declineRelay = declineRelay ?? createDeclineReasonRelay();
|
|
@@ -5295,6 +5365,10 @@ var CodexSessionRuntime = class {
|
|
|
5295
5365
|
this.writeAcks.set(jsonRpcId, { resolve: resolve4 });
|
|
5296
5366
|
});
|
|
5297
5367
|
}
|
|
5368
|
+
/** 下一轮(含插话)起按这份发可写根;正在跑的一轮不变。 */
|
|
5369
|
+
setAdditionalDirectories(directories) {
|
|
5370
|
+
this.#additionalDirectories = directories;
|
|
5371
|
+
}
|
|
5298
5372
|
settleNativeWrite(requestId, status) {
|
|
5299
5373
|
const ack = this.writeAcks.get(requestId);
|
|
5300
5374
|
if (!ack) return;
|
|
@@ -5906,73 +5980,6 @@ async function listCodexModels(rpc) {
|
|
|
5906
5980
|
return models;
|
|
5907
5981
|
}
|
|
5908
5982
|
|
|
5909
|
-
// src/skills.ts
|
|
5910
|
-
var SKILLS_LIST_TIMEOUT_MS = 15e3;
|
|
5911
|
-
function codexProbeSkill(raw, includeRepo = false) {
|
|
5912
|
-
if (!isRecord2(raw)) return null;
|
|
5913
|
-
const name = asString(raw["name"]);
|
|
5914
|
-
const path = asString(raw["path"]);
|
|
5915
|
-
const scope = asString(raw["scope"]);
|
|
5916
|
-
if (!name || !path || scope === "repo" && !includeRepo) return null;
|
|
5917
|
-
const face = isRecord2(raw["interface"]) ? raw["interface"] : void 0;
|
|
5918
|
-
const description = asString(raw["description"]);
|
|
5919
|
-
const displayName = asString(face?.["displayName"]);
|
|
5920
|
-
const shortDescription = asString(face?.["shortDescription"]) || asString(raw["shortDescription"]);
|
|
5921
|
-
return {
|
|
5922
|
-
name,
|
|
5923
|
-
path,
|
|
5924
|
-
enabled: raw["enabled"] !== false,
|
|
5925
|
-
...scope ? { scope } : {},
|
|
5926
|
-
...description ? { description } : {},
|
|
5927
|
-
...displayName ? { displayName } : {},
|
|
5928
|
-
...shortDescription ? { shortDescription } : {}
|
|
5929
|
-
};
|
|
5930
|
-
}
|
|
5931
|
-
async function listCodexWorkspaceSkills(rpc, cwd) {
|
|
5932
|
-
const response = await rpc.request("skills/list", { cwds: [cwd] }, SKILLS_LIST_TIMEOUT_MS);
|
|
5933
|
-
if (!isRecord2(response) || !Array.isArray(response["data"])) {
|
|
5934
|
-
throw new Error("skills/list returned an unexpected shape");
|
|
5935
|
-
}
|
|
5936
|
-
const skills = /* @__PURE__ */ new Map();
|
|
5937
|
-
for (const entry of response["data"]) {
|
|
5938
|
-
if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
|
|
5939
|
-
for (const raw of entry["skills"]) {
|
|
5940
|
-
const skill = codexProbeSkill(raw, true);
|
|
5941
|
-
if (skill !== null) skills.set(skill.path, skill);
|
|
5942
|
-
}
|
|
5943
|
-
}
|
|
5944
|
-
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
5945
|
-
}
|
|
5946
|
-
async function listCodexSkills(rpc) {
|
|
5947
|
-
let response;
|
|
5948
|
-
try {
|
|
5949
|
-
response = await rpc.request("skills/list", {}, SKILLS_LIST_TIMEOUT_MS);
|
|
5950
|
-
} catch {
|
|
5951
|
-
return void 0;
|
|
5952
|
-
}
|
|
5953
|
-
if (!isRecord2(response) || !Array.isArray(response["data"])) return void 0;
|
|
5954
|
-
const skills = /* @__PURE__ */ new Map();
|
|
5955
|
-
for (const entry of response["data"]) {
|
|
5956
|
-
if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
|
|
5957
|
-
for (const raw of entry["skills"]) {
|
|
5958
|
-
const skill = codexProbeSkill(raw);
|
|
5959
|
-
if (skill !== null) skills.set(skill.path, skill);
|
|
5960
|
-
}
|
|
5961
|
-
}
|
|
5962
|
-
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
5963
|
-
}
|
|
5964
|
-
async function setCodexSessionSkillRoots(rpc, skills, log, threadId) {
|
|
5965
|
-
if (skills === void 0 || skills.names.length === 0) return;
|
|
5966
|
-
try {
|
|
5967
|
-
await rpc.request("skills/extraRoots/set", { extraRoots: [skills.skillsDir] });
|
|
5968
|
-
} catch (error) {
|
|
5969
|
-
log.warn("codex did not take the session skill root; skills stay on the built-in tools", {
|
|
5970
|
-
threadId,
|
|
5971
|
-
error: error instanceof Error ? error.message : String(error)
|
|
5972
|
-
});
|
|
5973
|
-
}
|
|
5974
|
-
}
|
|
5975
|
-
|
|
5976
5983
|
// src/workspaceInventory.ts
|
|
5977
5984
|
import * as NodeFS6 from "node:fs";
|
|
5978
5985
|
import * as NodePath8 from "node:path";
|
|
@@ -6366,6 +6373,10 @@ import * as NodePath9 from "node:path";
|
|
|
6366
6373
|
import {
|
|
6367
6374
|
mergeLaunchEnv as mergeLaunchEnv2
|
|
6368
6375
|
} from "@ycodium-ai/plugin-api/executor";
|
|
6376
|
+
import {
|
|
6377
|
+
OperationCleanupError,
|
|
6378
|
+
runProcessOperation as runProcessOperation2
|
|
6379
|
+
} from "@ycodium-ai/plugin-api/process-operation";
|
|
6369
6380
|
var CODEX_TIMEOUT_MS = 18e4;
|
|
6370
6381
|
var EARLIER_CONTENT_TRUNCATION_MARKER = "[Earlier content truncated]\n\n";
|
|
6371
6382
|
function limitSection(value, maxChars) {
|
|
@@ -6518,98 +6529,78 @@ function absoluteImagePaths(attachments) {
|
|
|
6518
6529
|
}
|
|
6519
6530
|
return paths;
|
|
6520
6531
|
}
|
|
6521
|
-
async function collectStream(stream) {
|
|
6522
|
-
const decoder = new TextDecoder();
|
|
6523
|
-
let out = "";
|
|
6524
|
-
for await (const chunk of stream) out += decoder.decode(chunk, { stream: true });
|
|
6525
|
-
return out;
|
|
6526
|
-
}
|
|
6527
6532
|
function createCodexTextGeneration(input) {
|
|
6528
6533
|
const run = async (operation, cwd, prompt, schema, modelSelection, imagePaths, signal) => {
|
|
6529
6534
|
if (input.recipe.binaryPath.length === 0) {
|
|
6530
6535
|
throw new Error("Codex CLI is required but not available on PATH.");
|
|
6531
6536
|
}
|
|
6537
|
+
signal?.throwIfAborted();
|
|
6532
6538
|
const tmp = await NodeFSP5.mkdtemp(NodePath9.join(NodeOS3.tmpdir(), "ycodium-codex-tg-"));
|
|
6533
|
-
|
|
6534
|
-
const outputPath = NodePath9.join(tmp, "output.json");
|
|
6535
|
-
await NodeFSP5.writeFile(schemaPath, JSON.stringify(schema));
|
|
6536
|
-
await NodeFSP5.writeFile(outputPath, "");
|
|
6537
|
-
const reasoningEffort = modelSelectionStringOption(modelSelection, "reasoningEffort") ?? DEFAULT_TEXT_GENERATION_REASONING_EFFORT;
|
|
6538
|
-
const serviceTier = modelSelectionStringOption(modelSelection, "serviceTier");
|
|
6539
|
-
const model = modelIdFromSelection(modelSelection) ?? "gpt-5.6-luna";
|
|
6540
|
-
const env = mergeLaunchEnv2({
|
|
6541
|
-
accountHome: input.layout.effectiveHomePath ? { CODEX_HOME: input.layout.effectiveHomePath } : input.recipe.homePath.trim() ? { CODEX_HOME: expandHomePath(input.recipe.homePath) } : {},
|
|
6542
|
-
instanceTable: input.recipe.environment
|
|
6543
|
-
});
|
|
6544
|
-
const args = [
|
|
6545
|
-
"exec",
|
|
6546
|
-
...codexExecLaunchArgs(input.recipe.launchArgs),
|
|
6547
|
-
"--ephemeral",
|
|
6548
|
-
"--skip-git-repo-check",
|
|
6549
|
-
"-s",
|
|
6550
|
-
"read-only",
|
|
6551
|
-
"--model",
|
|
6552
|
-
model,
|
|
6553
|
-
"--config",
|
|
6554
|
-
`model_reasoning_effort="${reasoningEffort}"`,
|
|
6555
|
-
...serviceTier ? ["--config", `service_tier="${serviceTier}"`] : [],
|
|
6556
|
-
"--output-schema",
|
|
6557
|
-
schemaPath,
|
|
6558
|
-
"--output-last-message",
|
|
6559
|
-
outputPath,
|
|
6560
|
-
...imagePaths.flatMap((imagePath) => ["--image", imagePath]),
|
|
6561
|
-
"-"
|
|
6562
|
-
];
|
|
6563
|
-
const handle = await input.host.process.spawn({
|
|
6564
|
-
program: input.recipe.binaryPath,
|
|
6565
|
-
args,
|
|
6566
|
-
cwd: operation === "summarizeTurn" ? tmp : cwd,
|
|
6567
|
-
env,
|
|
6568
|
-
owner: { bindingId: input.host.bindingId }
|
|
6569
|
-
});
|
|
6570
|
-
const onAbort = () => {
|
|
6571
|
-
void handle.kill("SIGTERM").catch(() => void 0);
|
|
6572
|
-
};
|
|
6573
|
-
signal?.addEventListener("abort", onAbort);
|
|
6574
|
-
let timer;
|
|
6539
|
+
let safeToRemove = true;
|
|
6575
6540
|
try {
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6541
|
+
const schemaPath = NodePath9.join(tmp, "schema.json");
|
|
6542
|
+
const outputPath = NodePath9.join(tmp, "output.json");
|
|
6543
|
+
await NodeFSP5.writeFile(schemaPath, JSON.stringify(schema));
|
|
6544
|
+
await NodeFSP5.writeFile(outputPath, "");
|
|
6545
|
+
const reasoningEffort = modelSelectionStringOption(modelSelection, "reasoningEffort") ?? DEFAULT_TEXT_GENERATION_REASONING_EFFORT;
|
|
6546
|
+
const serviceTier = modelSelectionStringOption(modelSelection, "serviceTier");
|
|
6547
|
+
const model = modelIdFromSelection(modelSelection) ?? "gpt-5.6-luna";
|
|
6548
|
+
const env = mergeLaunchEnv2({
|
|
6549
|
+
accountHome: input.layout.effectiveHomePath ? { CODEX_HOME: input.layout.effectiveHomePath } : input.recipe.homePath.trim() ? { CODEX_HOME: expandHomePath(input.recipe.homePath) } : {},
|
|
6550
|
+
instanceTable: input.recipe.environment
|
|
6551
|
+
});
|
|
6552
|
+
const args = [
|
|
6553
|
+
"exec",
|
|
6554
|
+
...codexExecLaunchArgs(input.recipe.launchArgs),
|
|
6555
|
+
"--ephemeral",
|
|
6556
|
+
"--skip-git-repo-check",
|
|
6557
|
+
"-s",
|
|
6558
|
+
"read-only",
|
|
6559
|
+
"--model",
|
|
6560
|
+
model,
|
|
6561
|
+
"--config",
|
|
6562
|
+
`model_reasoning_effort="${reasoningEffort}"`,
|
|
6563
|
+
...serviceTier ? ["--config", `service_tier="${serviceTier}"`] : [],
|
|
6564
|
+
"--output-schema",
|
|
6565
|
+
schemaPath,
|
|
6566
|
+
"--output-last-message",
|
|
6567
|
+
outputPath,
|
|
6568
|
+
...imagePaths.flatMap((imagePath) => ["--image", imagePath]),
|
|
6569
|
+
"-"
|
|
6570
|
+
];
|
|
6601
6571
|
try {
|
|
6602
|
-
|
|
6572
|
+
const { stdout, stderr, exitCode } = await runProcessOperation2(input.host, {
|
|
6573
|
+
program: input.recipe.binaryPath,
|
|
6574
|
+
args,
|
|
6575
|
+
cwd: operation === "summarizeTurn" ? tmp : cwd,
|
|
6576
|
+
env,
|
|
6577
|
+
owner: { bindingId: input.host.bindingId },
|
|
6578
|
+
signal,
|
|
6579
|
+
timeoutMs: CODEX_TIMEOUT_MS,
|
|
6580
|
+
input: prompt
|
|
6581
|
+
});
|
|
6582
|
+
if (exitCode !== 0) {
|
|
6583
|
+
const detail = stderr.trim() || stdout.trim();
|
|
6584
|
+
throw new Error(
|
|
6585
|
+
detail.length > 0 ? `Codex CLI command failed: ${detail}` : `Codex CLI command failed with code ${String(exitCode)}.`
|
|
6586
|
+
);
|
|
6587
|
+
}
|
|
6588
|
+
const raw = await NodeFSP5.readFile(outputPath, "utf8");
|
|
6589
|
+
let parsed;
|
|
6590
|
+
try {
|
|
6591
|
+
parsed = JSON.parse(raw);
|
|
6592
|
+
} catch (cause) {
|
|
6593
|
+
throw new Error("Codex returned invalid structured output.", { cause });
|
|
6594
|
+
}
|
|
6595
|
+
if (!isRecord2(parsed)) throw new Error("Codex returned invalid structured output.");
|
|
6596
|
+
return parsed;
|
|
6603
6597
|
} catch (cause) {
|
|
6604
|
-
|
|
6598
|
+
if (cause instanceof OperationCleanupError) safeToRemove = false;
|
|
6599
|
+
throw cause;
|
|
6605
6600
|
}
|
|
6606
|
-
if (!isRecord2(parsed)) throw new Error("Codex returned invalid structured output.");
|
|
6607
|
-
return parsed;
|
|
6608
6601
|
} finally {
|
|
6609
|
-
if (
|
|
6610
|
-
|
|
6611
|
-
await NodeFSP5.rm(tmp, { recursive: true, force: true }).catch(() => void 0);
|
|
6612
|
-
void operation;
|
|
6602
|
+
if (safeToRemove)
|
|
6603
|
+
await NodeFSP5.rm(tmp, { recursive: true, force: true }).catch(() => void 0);
|
|
6613
6604
|
}
|
|
6614
6605
|
};
|
|
6615
6606
|
return {
|
|
@@ -7611,7 +7602,7 @@ var createCodexInstance = (config, host, attachments, cache) => {
|
|
|
7611
7602
|
...CODEX_NATIVE_MODE_REPORT
|
|
7612
7603
|
};
|
|
7613
7604
|
},
|
|
7614
|
-
readCliVersion: () => readCodexCliVersion({ recipe, host }),
|
|
7605
|
+
readCliVersion: (signal) => readCodexCliVersion({ recipe, host, ...signal ? { signal } : {} }),
|
|
7615
7606
|
// 有意不处理 input.readOnlyDirectories:codex 的沙箱只限制写入,读不受限,
|
|
7616
7607
|
// 附件目录本来就能读,无需放行。
|
|
7617
7608
|
startSession: async (input, signal) => {
|
|
@@ -7625,6 +7616,11 @@ var createCodexInstance = (config, host, attachments, cache) => {
|
|
|
7625
7616
|
const existing = threads.get(input.threadId);
|
|
7626
7617
|
if (existing !== void 0) {
|
|
7627
7618
|
if (existing.closing) throw new Error(`thread ${input.threadId} is closing`);
|
|
7619
|
+
if (reusesCodexProcess(existing, input, cwd)) {
|
|
7620
|
+
existing.runtime.setAdditionalDirectories(input.additionalDirectories ?? []);
|
|
7621
|
+
host.log.info("session reused", { threadId: input.threadId });
|
|
7622
|
+
return existing.runtime.session;
|
|
7623
|
+
}
|
|
7628
7624
|
await stopBooked(input.threadId, existing);
|
|
7629
7625
|
}
|
|
7630
7626
|
const layout = layoutFor(recipe);
|
|
@@ -7679,7 +7675,7 @@ var createCodexInstance = (config, host, attachments, cache) => {
|
|
|
7679
7675
|
attachments,
|
|
7680
7676
|
{ requestClose: () => stopBooked(input.threadId, booked, "process") }
|
|
7681
7677
|
);
|
|
7682
|
-
booked = { runtime, rpc, handle };
|
|
7678
|
+
booked = { runtime, rpc, handle, launch: input };
|
|
7683
7679
|
threads.set(input.threadId, booked);
|
|
7684
7680
|
try {
|
|
7685
7681
|
await rpc.request("initialize", CODEX_INITIALIZE_PARAMS);
|
|
@@ -7924,7 +7920,7 @@ var executors = [
|
|
|
7924
7920
|
];
|
|
7925
7921
|
var index_default = definePlugin({
|
|
7926
7922
|
id: "agent-codex",
|
|
7927
|
-
apiVersion:
|
|
7923
|
+
apiVersion: 41,
|
|
7928
7924
|
executors,
|
|
7929
7925
|
activate(ctx) {
|
|
7930
7926
|
capturedAttachments = ctx.attachments;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-codex",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3502",
|
|
4
4
|
"description": "Codex executor: Codex CLI over the app-server JSON-RPC protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"tailwindcss": "^4.0.0",
|
|
30
30
|
"typescript": "~6.0.3",
|
|
31
31
|
"vite-plus": "0.2.2",
|
|
32
|
-
"
|
|
32
|
+
"ycodium-jsonl-stream": "0.0.0",
|
|
33
33
|
"ycodium-executor-testing": "0.0.0",
|
|
34
|
-
"ycodium-
|
|
34
|
+
"@ycodium-ai/plugin-api": "0.2.3502"
|
|
35
35
|
},
|
|
36
36
|
"ycodium": {
|
|
37
37
|
"plugin": "./dist/index.js",
|