@ycodium-ai/agent-codex 0.2.3766 → 0.2.3831

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 +138 -17
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -2351,9 +2351,12 @@ function codexExecLaunchArgs(launchArgs) {
2351
2351
  function codexMcpThreadConfig(servers) {
2352
2352
  return {
2353
2353
  mcp_servers: Object.fromEntries(
2354
- servers.map(({ name, transport }) => [
2354
+ servers.map(({ name, transport, toolTimeoutSeconds }) => [
2355
2355
  name,
2356
- transport.type === "stdio" ? { command: transport.command, args: transport.args ?? [], env: transport.env ?? {} } : { url: transport.url, http_headers: transport.headers ?? {} }
2356
+ {
2357
+ ...transport.type === "stdio" ? { command: transport.command, args: transport.args ?? [], env: transport.env ?? {} } : { url: transport.url, http_headers: transport.headers ?? {} },
2358
+ ...toolTimeoutSeconds === void 0 ? {} : { tool_timeout_sec: toolTimeoutSeconds }
2359
+ }
2357
2360
  ])
2358
2361
  )
2359
2362
  };
@@ -4137,6 +4140,8 @@ function mapNotificationToEvents(input) {
4137
4140
  type: "user-input.requested",
4138
4141
  threadId,
4139
4142
  turnId,
4143
+ // 带上回复条目:宿主据此不再把这条回复和提问卡重复画一遍。
4144
+ itemId,
4140
4145
  requestId: `codex-async:${itemId}`,
4141
4146
  payload: { questions: asyncQuestions, responseMode: "message" },
4142
4147
  method,
@@ -4645,6 +4650,112 @@ function mapServerRequestToEvents(input) {
4645
4650
  ];
4646
4651
  }
4647
4652
 
4653
+ // src/backgroundCommands.ts
4654
+ function commandDescription(item) {
4655
+ const actions = Array.isArray(item["commandActions"]) ? item["commandActions"] : [];
4656
+ const first = isRecord2(actions[0]) ? asString(actions[0]["command"]) : null;
4657
+ return first ?? asString(item["command"]) ?? "";
4658
+ }
4659
+ var CodexBackgroundCommands = class {
4660
+ #commands = /* @__PURE__ */ new Map();
4661
+ #threadId;
4662
+ #providerInstanceId;
4663
+ constructor(threadId, providerInstanceId) {
4664
+ this.#threadId = threadId;
4665
+ this.#providerInstanceId = providerInstanceId;
4666
+ }
4667
+ #completed(taskId, turnId, status, method) {
4668
+ return baseEvent({
4669
+ type: "task.completed",
4670
+ threadId: this.#threadId,
4671
+ turnId,
4672
+ payload: { taskId, status },
4673
+ method,
4674
+ providerInstanceId: this.#providerInstanceId
4675
+ });
4676
+ }
4677
+ #settleTurn(method, params) {
4678
+ const turnId = turnIdOf(params);
4679
+ const events = [];
4680
+ for (const [id, command] of this.#commands) {
4681
+ if (command.background || turnId !== void 0 && command.turnId !== turnId) continue;
4682
+ if (turnCompletedControlFlow(params).state !== "completed") {
4683
+ this.#commands.delete(id);
4684
+ continue;
4685
+ }
4686
+ this.#commands.set(id, { ...command, background: true });
4687
+ events.push(
4688
+ baseEvent({
4689
+ type: "task.started",
4690
+ threadId: this.#threadId,
4691
+ turnId: command.turnId,
4692
+ payload: { taskId: id, taskType: "local_bash", description: command.description },
4693
+ method,
4694
+ providerInstanceId: this.#providerInstanceId
4695
+ })
4696
+ );
4697
+ }
4698
+ return events;
4699
+ }
4700
+ /** 跟着通知走,返回要补发的 task 事件;放在该通知本身的事件之后发。 */
4701
+ observe(method, params) {
4702
+ if (method === "turn/completed") return this.#settleTurn(method, params);
4703
+ if (method === "thread/closed") {
4704
+ const closed = [...this.#commands].filter(([, command2]) => command2.background);
4705
+ this.#commands.clear();
4706
+ return closed.map(([id2, command2]) => this.#completed(id2, command2.turnId, "stopped", method));
4707
+ }
4708
+ if (!isRecord2(params) || !isRecord2(params["item"])) return [];
4709
+ const item = params["item"];
4710
+ const id = item["id"];
4711
+ if (item["type"] !== "commandExecution" || typeof id !== "string") return [];
4712
+ if (method === "item/started") {
4713
+ if (item["source"] === "unifiedExecInteraction") return [];
4714
+ this.#commands.set(id, {
4715
+ turnId: turnIdOf(params),
4716
+ description: commandDescription(item),
4717
+ processId: asString(item["processId"]) ?? void 0,
4718
+ background: false
4719
+ });
4720
+ return [];
4721
+ }
4722
+ if (method !== "item/completed") return [];
4723
+ const command = this.#commands.get(id);
4724
+ this.#commands.delete(id);
4725
+ if (command?.background !== true) return [];
4726
+ const status = itemStatusOf(params);
4727
+ return [
4728
+ this.#completed(
4729
+ id,
4730
+ command.turnId,
4731
+ status === "failed" ? "failed" : status === "declined" ? "stopped" : "completed",
4732
+ method
4733
+ )
4734
+ ];
4735
+ }
4736
+ /** 用户点停止时结束有进程号的后台任务;请求失败的留着,等它自己的 `item/completed`。 */
4737
+ async stop(rpc, nativeThreadId) {
4738
+ const running = [...this.#commands].filter(
4739
+ (entry) => entry[1].background && entry[1].processId !== void 0
4740
+ );
4741
+ const stopped = await Promise.all(
4742
+ running.map(async ([id, command]) => {
4743
+ try {
4744
+ await rpc.request("thread/backgroundTerminals/terminate", {
4745
+ threadId: nativeThreadId,
4746
+ processId: command.processId
4747
+ });
4748
+ } catch {
4749
+ return [];
4750
+ }
4751
+ this.#commands.delete(id);
4752
+ return [this.#completed(id, command.turnId, "stopped")];
4753
+ })
4754
+ );
4755
+ return stopped.flat();
4756
+ }
4757
+ };
4758
+
4648
4759
  // src/openCommands.ts
4649
4760
  import {
4650
4761
  isPosixShellCommandFlag,
@@ -4799,6 +4910,21 @@ function readSubAgentActivity(method, params) {
4799
4910
  agentPath: asString(item["agentPath"]) ?? void 0
4800
4911
  };
4801
4912
  }
4913
+ async function interruptForeignTurns(rpc, turns) {
4914
+ const started = Date.now();
4915
+ await Promise.all(
4916
+ [...turns.entries()].slice(0, 8).map(async ([thread, childTurn]) => {
4917
+ if (Date.now() - started > 1e4) return;
4918
+ try {
4919
+ await Promise.race([
4920
+ rpc.request("turn/interrupt", { threadId: thread, turnId: childTurn }, 0),
4921
+ new Promise((resolve4) => setTimeout(resolve4, 3e3))
4922
+ ]);
4923
+ } catch {
4924
+ }
4925
+ })
4926
+ );
4927
+ }
4802
4928
  var CodexSessionCollab = class {
4803
4929
  runtime;
4804
4930
  constructor(runtime) {
@@ -5294,6 +5420,7 @@ var CodexSessionRuntime = class {
5294
5420
  closeOptions;
5295
5421
  #collab = new CodexSessionCollab(this);
5296
5422
  #requests = new CodexSessionRequests(this);
5423
+ #background;
5297
5424
  /**
5298
5425
  * 对外 requestId 的前缀,每个会话(即每个 app-server 进程)一份。JSON-RPC id 每个进程
5299
5426
  * 都从 0 数起,宿主按 requestId 记「已接受」,不加前缀的话重启后的新请求会撞上旧请求。
@@ -5328,6 +5455,7 @@ var CodexSessionRuntime = class {
5328
5455
  });
5329
5456
  });
5330
5457
  this.emit = (event) => this.#lifecycle.emit(event);
5458
+ this.#background = new CodexBackgroundCommands(input.threadId, host.instanceId);
5331
5459
  this.threadId = input.threadId;
5332
5460
  this.cwd = cwd;
5333
5461
  this.runtimeMode = input.runtimeMode;
@@ -5478,6 +5606,7 @@ var CodexSessionRuntime = class {
5478
5606
  })) {
5479
5607
  this.emit(event);
5480
5608
  }
5609
+ for (const event of this.#background.observe(method, params)) this.emit(event);
5481
5610
  if (method === "turn/started" && this.#lifecycle.acceptsLifecycle) {
5482
5611
  const turnId = turnIdOf(params);
5483
5612
  if (turnId) this.activeTurnId = turnId;
@@ -5673,21 +5802,13 @@ var CodexSessionRuntime = class {
5673
5802
  };
5674
5803
  }
5675
5804
  async interruptTurn(turnId) {
5676
- const childTurns = [...this.liveForeignTurns.entries()];
5677
- const started = Date.now();
5678
- await Promise.all(
5679
- childTurns.slice(0, 8).map(async ([thread, childTurn]) => {
5680
- if (Date.now() - started > 1e4) return;
5681
- try {
5682
- await Promise.race([
5683
- this.rpc.request("turn/interrupt", { threadId: thread, turnId: childTurn }, 0),
5684
- sleep(3e3)
5685
- ]);
5686
- } catch {
5687
- }
5688
- })
5689
- );
5805
+ await interruptForeignTurns(this.rpc, this.liveForeignTurns);
5690
5806
  if (!this.nativeThreadId) return;
5807
+ if (turnId === void 0) {
5808
+ for (const event of await this.#background.stop(this.rpc, this.nativeThreadId)) {
5809
+ this.emit(event);
5810
+ }
5811
+ }
5691
5812
  const target = turnId ?? this.activeTurnId;
5692
5813
  if (target) {
5693
5814
  await this.rpc.request("turn/interrupt", { threadId: this.nativeThreadId, turnId: target }, 0).catch(() => void 0);
@@ -7903,7 +8024,7 @@ var executors = [
7903
8024
  ];
7904
8025
  var index_default = definePlugin({
7905
8026
  id: "agent-codex",
7906
- apiVersion: 56,
8027
+ apiVersion: 60,
7907
8028
  executors,
7908
8029
  activate(ctx) {
7909
8030
  ctx.command({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-codex",
3
- "version": "0.2.3766",
3
+ "version": "0.2.3831",
4
4
  "description": "Codex executor: Codex CLI over the app-server JSON-RPC protocol.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -30,8 +30,8 @@
30
30
  "typescript": "~6.0.3",
31
31
  "vite-plus": "0.2.2",
32
32
  "ycodium-executor-testing": "0.0.0",
33
- "@ycodium-ai/plugin-api": "0.2.3766",
34
- "ycodium-jsonl-stream": "0.0.0"
33
+ "ycodium-jsonl-stream": "0.0.0",
34
+ "@ycodium-ai/plugin-api": "0.2.3831"
35
35
  },
36
36
  "ycodium": {
37
37
  "plugin": "./dist/index.js",