@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.
Files changed (2) hide show
  1. package/dist/index.js +122 -40
  2. 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, or effort level; passing an effort a model does not offer is rejected rather than ignored. Pass \`isolate: true\` when the child must not share your working tree.
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: "idle", ...linkage },
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 undeliveredAnswerError(requestId, delivery) {
2402
+ function unconfirmedAnswerError(requestId, delivery) {
2366
2403
  return new Error(
2367
- delivery === "closed" ? `codex did not receive the answer to request ${requestId}: the session closed before the answer was written` : `codex did not receive the answer to request ${requestId}: writing it to the CLI failed`
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 的应答没写进去:带上线程与方法名记一行 warn。 */
2409
- #warnAnswerUndelivered(method, jsonRpcId, error) {
2410
- this.host.log.warn("codex did not receive an answer", {
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 source = isRecord3(params) ? params["source"] : void 0;
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
- if (isRootChild(agentPath, conversationId, this.nativeThreadId ?? this.threadId)) return;
2557
- const existing = this.collabChildren.get(conversationId);
2558
- const spawnTurnId = existing?.spawnTurnId ?? this.activeTurnId;
2559
- const child2 = {
2560
- agentThreadId: conversationId,
2561
- ...agentPath ? { agentPath } : {},
2562
- ...asString(spawn["agent_role"]) ? { role: asString(spawn["agent_role"]) } : {},
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
- if ((method === "item/started" || method === "item/completed") && itemType === "subAgentActivity") {
2578
- const item = isRecord3(params) ? isRecord3(params["item"]) ? params["item"] : params : {};
2579
- const agentThreadId = asString(item["agentThreadId"]) ?? conversationId;
2580
- const agentPath = asString(item["agentPath"]) ?? void 0;
2581
- if (isRootChild(agentPath, agentThreadId, this.nativeThreadId ?? this.threadId)) return;
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
- this.emitCollab("collabAgent/completed", child);
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.#warnAnswerUndelivered(method, id, error)).finally(resolve2);
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.#warnAnswerUndelivered(method, id, error)).finally(resolve2);
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 undeliveredAnswerError(requestId, delivery);
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 undeliveredAnswerError(requestId, delivery);
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.2143",
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.2143"
23
+ "@ycodium-ai/plugin-api": "0.2.0"
24
24
  },
25
25
  "ycodium": {
26
26
  "plugin": "./dist/index.js",