@ycodium-ai/agent-codex 0.2.2143 → 0.2.2163
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 +122 -40
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1119,7 +1119,7 @@ var YCODIUM_THREAD_TOOL_INSTRUCTIONS = `
|
|
|
1119
1119
|
|
|
1120
1120
|
The \`ycodium\` MCP server can start child threads on this environment. When \`start_thread\` is listed, use it to hand a self-contained piece of work to another thread \u2014 optionally on a different provider instance or model \u2014 instead of doing everything inline or spawning your own background processes.
|
|
1121
1121
|
|
|
1122
|
-
Call \`list_providers\` and \`list_models\` first when you want a specific provider, model,
|
|
1122
|
+
Call \`list_providers\` and \`list_models\` first when you want a specific provider, model, effort level, or another model option such as a service tier (pass those as \`options\`, with the ids and values \`list_models\` gives); a value a model does not offer is rejected rather than ignored. Pass \`isolate: true\` when the child must not share your working tree.
|
|
1123
1123
|
|
|
1124
1124
|
\`start_thread\` returns as soon as the child is running. You do not need to poll: a message arrives in this thread when the child finishes, fails, stops, or needs an approval, and it names the child thread id. Use \`get_thread_activity\` to read the full transcript behind a truncated summary, \`send_message\` to follow up, \`respond_to_permission\` to answer its approval requests, and \`stop_thread\` to end it. You can only steer child threads you started yourself.
|
|
1125
1125
|
`;
|
|
@@ -1360,6 +1360,20 @@ function toTurnStatus(status) {
|
|
|
1360
1360
|
return "completed";
|
|
1361
1361
|
}
|
|
1362
1362
|
}
|
|
1363
|
+
var COLLAB_CHILD_STATUSES = /* @__PURE__ */ new Set([
|
|
1364
|
+
"running",
|
|
1365
|
+
"idle",
|
|
1366
|
+
"failed",
|
|
1367
|
+
"interrupted",
|
|
1368
|
+
"cancelled"
|
|
1369
|
+
]);
|
|
1370
|
+
function asCollabChildStatus(value) {
|
|
1371
|
+
return typeof value === "string" && COLLAB_CHILD_STATUSES.has(value) ? value : void 0;
|
|
1372
|
+
}
|
|
1373
|
+
function collabTurnEndStatus(turnStatus) {
|
|
1374
|
+
const state = toTurnStatus(turnStatus);
|
|
1375
|
+
return state === "completed" ? "idle" : state;
|
|
1376
|
+
}
|
|
1363
1377
|
function threadStateFromStatus(status) {
|
|
1364
1378
|
const type = isRecord3(status) ? asString(status["type"]) : asString(status);
|
|
1365
1379
|
if (type === "idle") return "idle";
|
|
@@ -1582,11 +1596,12 @@ function mapCollabAgentEvent(input) {
|
|
|
1582
1596
|
];
|
|
1583
1597
|
}
|
|
1584
1598
|
if (method === "collabAgent/completed" || method === "task.completed") {
|
|
1599
|
+
const status = collabTurnEndStatus(asString(input.params["turnStatus"]) ?? void 0);
|
|
1585
1600
|
return [
|
|
1586
1601
|
baseEvent({
|
|
1587
1602
|
type: "task.updated",
|
|
1588
1603
|
threadId,
|
|
1589
|
-
payload: { taskId: agentThreadId, status
|
|
1604
|
+
payload: { taskId: agentThreadId, status, ...linkage },
|
|
1590
1605
|
method,
|
|
1591
1606
|
providerInstanceId: input.providerInstanceId
|
|
1592
1607
|
})
|
|
@@ -1605,6 +1620,19 @@ function mapCollabAgentEvent(input) {
|
|
|
1605
1620
|
})
|
|
1606
1621
|
];
|
|
1607
1622
|
}
|
|
1623
|
+
if (method === "collabAgent/metadata") {
|
|
1624
|
+
const status = asCollabChildStatus(input.params["status"]);
|
|
1625
|
+
if (status === void 0) return [];
|
|
1626
|
+
return [
|
|
1627
|
+
baseEvent({
|
|
1628
|
+
type: "task.updated",
|
|
1629
|
+
threadId,
|
|
1630
|
+
payload: { taskId: agentThreadId, status, ...linkage },
|
|
1631
|
+
method,
|
|
1632
|
+
providerInstanceId: input.providerInstanceId
|
|
1633
|
+
})
|
|
1634
|
+
];
|
|
1635
|
+
}
|
|
1608
1636
|
if (method === "collabAgent/tokenUsage") {
|
|
1609
1637
|
const tokenUsage = isRecord3(input.params["tokenUsage"]) ? input.params["tokenUsage"] : void 0;
|
|
1610
1638
|
const total = tokenUsage && isRecord3(tokenUsage["total"]) ? tokenUsage["total"] : void 0;
|
|
@@ -2357,14 +2385,23 @@ function isRootChild(agentPath, agentThreadId, rootThreadId) {
|
|
|
2357
2385
|
if (agentThreadId === rootThreadId) return true;
|
|
2358
2386
|
return agentPath === "/root" || agentPath === "/";
|
|
2359
2387
|
}
|
|
2388
|
+
function readSubAgentActivity(method, params) {
|
|
2389
|
+
if (method !== "item/started" && method !== "item/completed") return void 0;
|
|
2390
|
+
if (itemTypeOf(params) !== "subAgentActivity") return void 0;
|
|
2391
|
+
const item = isRecord3(params) ? isRecord3(params["item"]) ? params["item"] : params : {};
|
|
2392
|
+
return {
|
|
2393
|
+
agentThreadId: asString(item["agentThreadId"]) ?? void 0,
|
|
2394
|
+
agentPath: asString(item["agentPath"]) ?? void 0
|
|
2395
|
+
};
|
|
2396
|
+
}
|
|
2360
2397
|
function pathLeaf2(value) {
|
|
2361
2398
|
if (!value) return void 0;
|
|
2362
2399
|
const parts = value.split("/").filter((part) => part.length > 0);
|
|
2363
2400
|
return parts.at(-1);
|
|
2364
2401
|
}
|
|
2365
|
-
function
|
|
2402
|
+
function unconfirmedAnswerError(requestId, delivery) {
|
|
2366
2403
|
return new Error(
|
|
2367
|
-
delivery === "closed" ? `
|
|
2404
|
+
delivery === "closed" ? `could not confirm that codex received the answer to request ${requestId}: the session closed before the write was confirmed` : `could not confirm that codex received the answer to request ${requestId}: writing it to the CLI failed`
|
|
2368
2405
|
);
|
|
2369
2406
|
}
|
|
2370
2407
|
var CodexSessionRuntime = class {
|
|
@@ -2405,9 +2442,9 @@ var CodexSessionRuntime = class {
|
|
|
2405
2442
|
codexNativeModeFor(this.runtimeMode, this.nativeModeId)
|
|
2406
2443
|
);
|
|
2407
2444
|
}
|
|
2408
|
-
/** 给 CLI
|
|
2409
|
-
#
|
|
2410
|
-
this.host.log.warn("
|
|
2445
|
+
/** 给 CLI 的应答写入失败:带上线程与方法名记一行 warn。 */
|
|
2446
|
+
#warnAnswerWriteFailed(method, jsonRpcId, error) {
|
|
2447
|
+
this.host.log.warn("writing an answer to codex failed", {
|
|
2411
2448
|
threadId: this.threadId,
|
|
2412
2449
|
method,
|
|
2413
2450
|
jsonRpcId,
|
|
@@ -2508,6 +2545,10 @@ var CodexSessionRuntime = class {
|
|
|
2508
2545
|
return;
|
|
2509
2546
|
}
|
|
2510
2547
|
}
|
|
2548
|
+
const activity = readSubAgentActivity(method, params);
|
|
2549
|
+
if (activity?.agentThreadId !== void 0 && !isRootChild(activity.agentPath, activity.agentThreadId, this.nativeThreadId ?? this.threadId)) {
|
|
2550
|
+
this.upsertCollabChild(activity.agentThreadId, { agentPath: activity.agentPath });
|
|
2551
|
+
}
|
|
2511
2552
|
this.dispatchMapped(method, params);
|
|
2512
2553
|
}
|
|
2513
2554
|
dispatchMapped(method, params) {
|
|
@@ -2548,23 +2589,19 @@ var CodexSessionRuntime = class {
|
|
|
2548
2589
|
}
|
|
2549
2590
|
}
|
|
2550
2591
|
interceptCollab(method, params, conversationId) {
|
|
2551
|
-
const
|
|
2592
|
+
const thread = isRecord3(params) && isRecord3(params["thread"]) ? params["thread"] : void 0;
|
|
2593
|
+
const source = thread === void 0 ? void 0 : thread["source"];
|
|
2552
2594
|
const subAgent = isRecord3(source) ? source["subAgent"] : void 0;
|
|
2553
2595
|
const spawn = isRecord3(subAgent) ? subAgent["thread_spawn"] : void 0;
|
|
2554
|
-
if (method === "thread/started" && isRecord3(spawn)) {
|
|
2596
|
+
if (method === "thread/started" && thread !== void 0 && isRecord3(spawn)) {
|
|
2555
2597
|
const agentPath = asString(spawn["agent_path"]) ?? void 0;
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
...asString(spawn["agent_nickname"]) ? { nickname: asString(spawn["agent_nickname"]) } : {},
|
|
2564
|
-
...spawnTurnId ? { spawnTurnId } : {}
|
|
2565
|
-
};
|
|
2566
|
-
this.collabChildren.set(conversationId, child2);
|
|
2567
|
-
this.emitCollab("collabAgent/started", child2);
|
|
2598
|
+
const knownPath = agentPath ?? this.collabChildren.get(conversationId)?.agentPath;
|
|
2599
|
+
if (isRootChild(knownPath, conversationId, this.nativeThreadId ?? this.threadId)) return;
|
|
2600
|
+
this.upsertCollabChild(conversationId, {
|
|
2601
|
+
agentPath,
|
|
2602
|
+
role: asString(spawn["agent_role"]) ?? asString(thread["agentRole"]) ?? void 0,
|
|
2603
|
+
nickname: asString(spawn["agent_nickname"]) ?? asString(thread["agentNickname"]) ?? void 0
|
|
2604
|
+
});
|
|
2568
2605
|
return;
|
|
2569
2606
|
}
|
|
2570
2607
|
const itemType = itemTypeOf(params);
|
|
@@ -2574,21 +2611,13 @@ var CodexSessionRuntime = class {
|
|
|
2574
2611
|
if (receiver && this.activeTurnId) this.collabReceiverTurns.set(receiver, this.activeTurnId);
|
|
2575
2612
|
return;
|
|
2576
2613
|
}
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
const agentThreadId =
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
if (!this.collabChildren.has(agentThreadId)) {
|
|
2583
|
-
const spawnTurnId = this.activeTurnId;
|
|
2584
|
-
const child2 = {
|
|
2585
|
-
agentThreadId,
|
|
2586
|
-
...agentPath ? { agentPath } : {},
|
|
2587
|
-
...spawnTurnId ? { spawnTurnId } : {}
|
|
2588
|
-
};
|
|
2589
|
-
this.collabChildren.set(agentThreadId, child2);
|
|
2590
|
-
this.emitCollab("collabAgent/started", child2);
|
|
2614
|
+
const activity = readSubAgentActivity(method, params);
|
|
2615
|
+
if (activity !== void 0) {
|
|
2616
|
+
const agentThreadId = activity.agentThreadId ?? conversationId;
|
|
2617
|
+
if (isRootChild(activity.agentPath, agentThreadId, this.nativeThreadId ?? this.threadId)) {
|
|
2618
|
+
return;
|
|
2591
2619
|
}
|
|
2620
|
+
this.upsertCollabChild(agentThreadId, { agentPath: activity.agentPath });
|
|
2592
2621
|
}
|
|
2593
2622
|
const child = this.collabChildren.get(conversationId);
|
|
2594
2623
|
if (method === "turn/started") {
|
|
@@ -2602,13 +2631,26 @@ var CodexSessionRuntime = class {
|
|
|
2602
2631
|
if (CHILD_CHATTER_METHODS.has(method) || !CHILD_AGENT_EVENT_METHODS.has(method)) return;
|
|
2603
2632
|
return;
|
|
2604
2633
|
}
|
|
2634
|
+
if (method === "turn/started") {
|
|
2635
|
+
child.status = "running";
|
|
2636
|
+
this.emitCollab("collabAgent/statusChanged", child, { status: "running" });
|
|
2637
|
+
return;
|
|
2638
|
+
}
|
|
2605
2639
|
if (method === "turn/completed") {
|
|
2606
|
-
|
|
2640
|
+
const turn = isRecord3(params) && isRecord3(params["turn"]) ? params["turn"] : void 0;
|
|
2641
|
+
const turnStatus = turn === void 0 ? void 0 : asString(turn["status"]) ?? void 0;
|
|
2642
|
+
child.status = collabTurnEndStatus(turnStatus);
|
|
2643
|
+
this.emitCollab(
|
|
2644
|
+
"collabAgent/completed",
|
|
2645
|
+
child,
|
|
2646
|
+
turnStatus === void 0 ? {} : { turnStatus }
|
|
2647
|
+
);
|
|
2607
2648
|
return;
|
|
2608
2649
|
}
|
|
2609
2650
|
if (method === "error") {
|
|
2610
2651
|
const willRetry = isRecord3(params) ? params["willRetry"] === true : false;
|
|
2611
2652
|
if (willRetry) return;
|
|
2653
|
+
child.status = "failed";
|
|
2612
2654
|
this.emitCollab("collabAgent/statusChanged", child, { status: "systemError" });
|
|
2613
2655
|
return;
|
|
2614
2656
|
}
|
|
@@ -2621,6 +2663,44 @@ var CodexSessionRuntime = class {
|
|
|
2621
2663
|
this.emitCollab("collabAgent/progress", child, params);
|
|
2622
2664
|
}
|
|
2623
2665
|
}
|
|
2666
|
+
/**
|
|
2667
|
+
* 两条登记路(根线程的 subAgentActivity、子线程的 thread/started)都走这里。
|
|
2668
|
+
* 第一次见到就登记并宣布;已登记的只合并身份:已有的字段保留,缺的补上,补到了就发
|
|
2669
|
+
* 一条带当前状态的元数据更新。不能再宣布一次:一轮结束之后才到的宣布,会让宿主把
|
|
2670
|
+
* idle 当成新一轮开始。
|
|
2671
|
+
*/
|
|
2672
|
+
upsertCollabChild(agentThreadId, identity) {
|
|
2673
|
+
const fill = (known, next) => known ?? (next !== void 0 && next.length > 0 ? next : void 0);
|
|
2674
|
+
const existing = this.collabChildren.get(agentThreadId);
|
|
2675
|
+
const agentPath = fill(existing?.agentPath, identity.agentPath);
|
|
2676
|
+
const role = fill(existing?.role, identity.role);
|
|
2677
|
+
const nickname = fill(existing?.nickname, identity.nickname);
|
|
2678
|
+
if (existing === void 0) {
|
|
2679
|
+
const spawnTurnId = this.activeTurnId;
|
|
2680
|
+
const child = {
|
|
2681
|
+
agentThreadId,
|
|
2682
|
+
...agentPath ? { agentPath } : {},
|
|
2683
|
+
...role ? { role } : {},
|
|
2684
|
+
...nickname ? { nickname } : {},
|
|
2685
|
+
...spawnTurnId ? { spawnTurnId } : {},
|
|
2686
|
+
status: "running"
|
|
2687
|
+
};
|
|
2688
|
+
this.collabChildren.set(agentThreadId, child);
|
|
2689
|
+
this.emitCollab("collabAgent/started", child);
|
|
2690
|
+
return;
|
|
2691
|
+
}
|
|
2692
|
+
if (agentPath === existing.agentPath && role === existing.role && nickname === existing.nickname) {
|
|
2693
|
+
return;
|
|
2694
|
+
}
|
|
2695
|
+
const merged = {
|
|
2696
|
+
...existing,
|
|
2697
|
+
...agentPath ? { agentPath } : {},
|
|
2698
|
+
...role ? { role } : {},
|
|
2699
|
+
...nickname ? { nickname } : {}
|
|
2700
|
+
};
|
|
2701
|
+
this.collabChildren.set(agentThreadId, merged);
|
|
2702
|
+
this.emitCollab("collabAgent/metadata", merged, { status: merged.status });
|
|
2703
|
+
}
|
|
2624
2704
|
emitCollab(method, child, extra) {
|
|
2625
2705
|
const params = {
|
|
2626
2706
|
agentThreadId: child.agentThreadId,
|
|
@@ -2683,7 +2763,7 @@ var CodexSessionRuntime = class {
|
|
|
2683
2763
|
jsonRpcId: id,
|
|
2684
2764
|
settle: (result) => {
|
|
2685
2765
|
this.pendingUserInputs.delete(requestId);
|
|
2686
|
-
void this.rpc.respond(id, result).catch((error) => this.#
|
|
2766
|
+
void this.rpc.respond(id, result).catch((error) => this.#warnAnswerWriteFailed(method, id, error)).finally(resolve2);
|
|
2687
2767
|
}
|
|
2688
2768
|
});
|
|
2689
2769
|
for (const event of events) this.emit(event);
|
|
@@ -2717,7 +2797,7 @@ var CodexSessionRuntime = class {
|
|
|
2717
2797
|
identity,
|
|
2718
2798
|
settle: (decision) => {
|
|
2719
2799
|
this.pendingApprovals.delete(requestId);
|
|
2720
|
-
void this.rpc.respond(id, decision).catch((error) => this.#
|
|
2800
|
+
void this.rpc.respond(id, decision).catch((error) => this.#warnAnswerWriteFailed(method, id, error)).finally(resolve2);
|
|
2721
2801
|
}
|
|
2722
2802
|
});
|
|
2723
2803
|
for (const event of events) this.emit(event);
|
|
@@ -2754,7 +2834,7 @@ var CodexSessionRuntime = class {
|
|
|
2754
2834
|
...reason ? { reason } : {}
|
|
2755
2835
|
}
|
|
2756
2836
|
});
|
|
2757
|
-
if (delivery !== "written") throw
|
|
2837
|
+
if (delivery !== "written") throw unconfirmedAnswerError(requestId, delivery);
|
|
2758
2838
|
}
|
|
2759
2839
|
async respondToUserInput(requestId, answers) {
|
|
2760
2840
|
const pending = this.pendingUserInputs.get(requestId);
|
|
@@ -2776,7 +2856,7 @@ var CodexSessionRuntime = class {
|
|
|
2776
2856
|
// 契约的 answers 是 questionId → 答案 的 record,不是数组。
|
|
2777
2857
|
payload: { answers: toCanonicalUserInputAnswers(mapped) }
|
|
2778
2858
|
});
|
|
2779
|
-
if (delivery !== "written") throw
|
|
2859
|
+
if (delivery !== "written") throw unconfirmedAnswerError(requestId, delivery);
|
|
2780
2860
|
}
|
|
2781
2861
|
async withActiveWriterRecovery(run, allowUnsubscribe) {
|
|
2782
2862
|
let lastError;
|
|
@@ -2896,6 +2976,7 @@ var CodexSessionRuntime = class {
|
|
|
2896
2976
|
const config = this.#threadConfig();
|
|
2897
2977
|
const developerInstructions = this.developerInstructions(input);
|
|
2898
2978
|
const requestedModel = modelIdFromSelection(input.modelSelection) ?? this.model;
|
|
2979
|
+
const serviceTier = modelSelectionStringOption(input.modelSelection, "serviceTier");
|
|
2899
2980
|
const params = {
|
|
2900
2981
|
threadId: this.nativeThreadId,
|
|
2901
2982
|
input: this.turnInput(input),
|
|
@@ -2903,6 +2984,7 @@ var CodexSessionRuntime = class {
|
|
|
2903
2984
|
approvalsReviewer: config.approvalsReviewer,
|
|
2904
2985
|
sandboxPolicy,
|
|
2905
2986
|
...requestedModel ? { model: requestedModel } : {},
|
|
2987
|
+
...serviceTier ? { serviceTier } : {},
|
|
2906
2988
|
...developerInstructions ? { developerInstructions } : {}
|
|
2907
2989
|
};
|
|
2908
2990
|
const interactionMode = typeof input.interactionMode === "string" ? input.interactionMode : void 0;
|
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.2163",
|
|
4
4
|
"description": "Codex executor: Codex CLI over the app-server JSON-RPC protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@types/node": "24.12.4",
|
|
21
21
|
"esbuild": "0.28.1",
|
|
22
22
|
"vite-plus": "0.2.2",
|
|
23
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
23
|
+
"@ycodium-ai/plugin-api": "0.2.0"
|
|
24
24
|
},
|
|
25
25
|
"ycodium": {
|
|
26
26
|
"plugin": "./dist/index.js",
|