@nyssance/codex-acp-v2 0.7.0 → 0.7.2

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 CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.2 — 2026-09-29
4
+
5
+ ### Added
6
+
7
+ - Turn correlation v2 (`capabilities._meta.alwith.turns = {version: 2}`): `session/prompt`
8
+ accepts a host-named receipt in `_meta.alwith.messageId`, and every `state_update` of a
9
+ prompted turn carries `_meta.alwith.messageId`. A stale `idle` of an older turn is dropped
10
+ once a newer prompt owns the session.
11
+
12
+ ## 0.7.1 — 2026-09-29
13
+
14
+ ### Changed
15
+
16
+ - Generated against Codex 0.158.0 (`@openai/codex` `^0.158.0`); the version floor follows.
17
+ - MCP `openai/userVerification` elicitations (signed device challenges) are declined with
18
+ `cancelled`: ACP has no surface for them and enrollment stays inside Codex.
19
+ - `codexErrorInfo` `flexUnavailable` classifies as `flex_unavailable`, retryable.
20
+ - Replayed `image` user input renders `image:<fileId>` when Codex stored an uploaded file
21
+ instead of a URL.
22
+
23
+ ## 0.7.0 — 2026-09-29
24
+
25
+ ### Changed
26
+
27
+ - `session/prompt` returns `{messageId}` (ACP v2, sdk 1.5.1). The id is passed to Codex as
28
+ `clientUserMessageId`; `user_message` echoes and replays report it as `messageId`
29
+ (`userMessage.clientId ?? id`). Steering returns `{messageId, _meta.codex.steered}`.
30
+
3
31
  ## 0.6.0 — 2026-09-11
4
32
 
5
33
  ### Added
package/README.md CHANGED
@@ -59,7 +59,7 @@ See [`docs/protocol.md`](docs/protocol.md) for the exact wire contract.
59
59
 
60
60
  ## Requirements
61
61
 
62
- - Codex CLI **0.153.0 or newer** — the app-server types under `src/app-server` are generated
62
+ - Codex CLI **0.158.0 or newer** — the app-server types under `src/app-server` are generated
63
63
  from the `@openai/codex` release named in `optionalDependencies`, and the agent checks
64
64
  `codex --version` before starting the server; an older Codex fails at startup with an
65
65
  upgrade hint.
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.0",
21847
+ version: "0.7.2",
21848
21848
  description: "Native ACP v2 agent for the OpenAI Codex app-server",
21849
21849
  packageManager: "bun@1.4.0",
21850
21850
  engines: {
@@ -21916,7 +21916,7 @@ var package_default = {
21916
21916
  "vscode-jsonrpc": "^9.0.2"
21917
21917
  },
21918
21918
  optionalDependencies: {
21919
- "@openai/codex": "^0.153.0"
21919
+ "@openai/codex": "^0.158.0"
21920
21920
  }
21921
21921
  };
21922
21922
 
@@ -22084,6 +22084,8 @@ function classifyTurnError(info) {
22084
22084
  return failure2("rate_limit", true);
22085
22085
  case "serverOverloaded":
22086
22086
  return failure2("overloaded", true);
22087
+ case "flexUnavailable":
22088
+ return failure2("flex_unavailable", true);
22087
22089
  case "internalServerError":
22088
22090
  return failure2("internal", true);
22089
22091
  case "unauthorized":
@@ -23556,7 +23558,7 @@ function fromUserInput(input) {
23556
23558
  case "text":
23557
23559
  return input.text.length > 0 ? [{ type: "text", text: input.text }] : [];
23558
23560
  case "image":
23559
- return [{ type: "text", text: formatUriAsLink("image", input.url) }];
23561
+ return [{ type: "text", text: "url" in input ? formatUriAsLink("image", input.url) : `image:${input.fileId}` }];
23560
23562
  case "localImage":
23561
23563
  return [{ type: "text", text: formatUriAsLink(null, toFileUri(input.path)) }];
23562
23564
  case "skill":
@@ -23904,6 +23906,8 @@ ${details}` : summary)];
23904
23906
  case "mcpServer/event/stream/notification":
23905
23907
  case "account/updated":
23906
23908
  case "account/login/completed":
23909
+ case "account/gatewayOAuth/changed":
23910
+ case "thread/attachment/updated":
23907
23911
  case "app/list/updated":
23908
23912
  case "remoteControl/status/changed":
23909
23913
  case "externalAgentConfig/import/progress":
@@ -24892,6 +24896,10 @@ class CodexElicitationHandler {
24892
24896
  }
24893
24897
  async handleElicitation(params) {
24894
24898
  try {
24899
+ if (params.mode === "openai/userVerification") {
24900
+ logger.log("MCP user verification is not supported over ACP", { server: params.serverName });
24901
+ return cancelled();
24902
+ }
24895
24903
  const context = this.mcpContext(params);
24896
24904
  const messageOnly = isMessageOnlyForm(params);
24897
24905
  if (!messageOnly && this.useAcpElicitation(params)) {
@@ -25955,6 +25963,7 @@ class ClientSession {
25955
25963
  disposed = false;
25956
25964
  output = new AbortController;
25957
25965
  terminalAttempted = false;
25966
+ messageId;
25958
25967
  get signal() {
25959
25968
  return this.output.signal;
25960
25969
  }
@@ -25998,26 +26007,36 @@ class ClientSession {
25998
26007
  return;
25999
26008
  await abortable(this.link.notify(methods.client.elicitation.complete, { elicitationId }), this.output.signal);
26000
26009
  }
26001
- reportRunning() {
26010
+ reportRunning(messageId) {
26011
+ this.messageId = messageId;
26002
26012
  this.terminalAttempted = false;
26003
26013
  this.turnGeneration += 1;
26004
26014
  this.turnActive = true;
26005
26015
  this.waiting = 0;
26006
26016
  this.state({ sessionUpdate: "state_update", state: "running" });
26007
26017
  }
26008
- async reportIdle(stopReason, extra) {
26018
+ async reportIdle(stopReason, extra, messageId = this.messageId) {
26019
+ if (messageId !== this.messageId)
26020
+ return;
26009
26021
  if (this.terminalAttempted)
26010
26022
  return;
26011
26023
  this.terminalAttempted = true;
26012
26024
  this.turnActive = false;
26013
26025
  this.waiting = 0;
26014
- await this.update({
26026
+ await this.update(this.correlated({
26015
26027
  sessionUpdate: "state_update",
26016
26028
  state: "idle",
26017
26029
  stopReason,
26018
26030
  ...extra?.usage === undefined ? {} : { usage: extra.usage },
26019
26031
  ...extra?._meta === undefined ? {} : { _meta: extra._meta }
26020
- });
26032
+ }));
26033
+ }
26034
+ correlated(update) {
26035
+ if (this.messageId === undefined)
26036
+ return update;
26037
+ const meta = update._meta;
26038
+ const alwith = meta?.["alwith"];
26039
+ return { ...update, _meta: { ...meta, alwith: { ...alwith, messageId: this.messageId } } };
26021
26040
  }
26022
26041
  async waitingOnClient(operation, signal) {
26023
26042
  if (this.disposed)
@@ -26038,7 +26057,7 @@ class ClientSession {
26038
26057
  }
26039
26058
  async state(update) {
26040
26059
  try {
26041
- await this.update(update);
26060
+ await this.update(this.correlated(update));
26042
26061
  } catch (error40) {
26043
26062
  logger.error("Failed to publish session state", error40, { sessionId: this.sessionId });
26044
26063
  }
@@ -26623,6 +26642,7 @@ function gatewayModel(model, isDefault, template, entry) {
26623
26642
  additionalSpeedTiers: [],
26624
26643
  serviceTiers: [],
26625
26644
  defaultServiceTier: null,
26645
+ availableAccessPrograms: null,
26626
26646
  isDefault
26627
26647
  };
26628
26648
  }
@@ -26767,7 +26787,7 @@ class CodexAgent {
26767
26787
  additionalDirectories: {}
26768
26788
  },
26769
26789
  providers: {},
26770
- _meta: { alwith: { tools: { version: 1 } }, codex: { archive: true, seedHistory: true, skills: true, plugins: true, providerCatalog: true, rename: true, account: true, fuzzyFileSearch: true } }
26790
+ _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 } }
26771
26791
  },
26772
26792
  authMethods: authMethods(this.capabilities, this.env)
26773
26793
  };
@@ -27524,7 +27544,7 @@ class CodexAgent {
27524
27544
  return runtime;
27525
27545
  }
27526
27546
  async prompt(params) {
27527
- return await this.promptInternal(params, false, crypto.randomUUID());
27547
+ return await this.promptInternal(params, false, requestedMessageId(params) ?? crypto.randomUUID());
27528
27548
  }
27529
27549
  async promptInternal(params, allowReentry, messageId) {
27530
27550
  this.assertRoutingAvailable();
@@ -27548,7 +27568,7 @@ class CodexAgent {
27548
27568
  }
27549
27569
  const turn = createActiveTurn(session.id, messageId);
27550
27570
  session.activeTurn = turn;
27551
- runtime.client.reportRunning();
27571
+ runtime.client.reportRunning(messageId);
27552
27572
  this.runPrompt(runtime, turn, params);
27553
27573
  return { messageId };
27554
27574
  }
@@ -27772,7 +27792,7 @@ class CodexAgent {
27772
27792
  await runtime.bridge.finishOpenToolCalls(reason === "cancelled" ? "cancelled" : reason === "end_turn" ? "completed" : "failed");
27773
27793
  if (runtime.session.activeTurn === turn)
27774
27794
  runtime.session.activeTurn = null;
27775
- await runtime.client.reportIdle(reason, extra);
27795
+ await runtime.client.reportIdle(reason, extra, turn.clientUserMessageId ?? undefined);
27776
27796
  }
27777
27797
  async reportTurnFailure(runtime, turn, error40) {
27778
27798
  const { stopReason, ...classification } = classifyTurnError(error40.codexErrorInfo);
@@ -27957,6 +27977,15 @@ ${stderr}` : ""}`);
27957
27977
  function mcpServerNames(servers) {
27958
27978
  return servers.flatMap((server) => typeof server.name === "string" ? [sanitizeMcpServerName(server.name)] : []);
27959
27979
  }
27980
+ function requestedMessageId(params) {
27981
+ const alwith = params._meta?.["alwith"];
27982
+ if (alwith?.messageId === undefined)
27983
+ return;
27984
+ if (typeof alwith.messageId !== "string" || alwith.messageId.length === 0) {
27985
+ throw RequestError.invalidParams(undefined, "_meta.alwith.messageId must be a non-empty string");
27986
+ }
27987
+ return alwith.messageId;
27988
+ }
27960
27989
  function agentMessage(messageId, text2) {
27961
27990
  return { sessionUpdate: "agent_message_chunk", messageId, content: { type: "text", text: text2 } };
27962
27991
  }
@@ -28026,12 +28055,18 @@ function readOnlyThread(thread, cwd) {
28026
28055
  model: thread.model ?? "",
28027
28056
  modelProvider: thread.modelProvider,
28028
28057
  serviceTier: null,
28058
+ disabledPluginIds: [],
28029
28059
  cwd,
28060
+ runtimeWorkspaceRoots: [],
28030
28061
  instructionSources: [],
28031
28062
  approvalPolicy: "on-request",
28032
28063
  approvalsReviewer: "user",
28033
28064
  sandbox: { type: "readOnly", networkAccess: false },
28065
+ activePermissionProfile: null,
28034
28066
  reasoningEffort: thread.reasoningEffort,
28067
+ collaborationMode: null,
28068
+ multiAgentMode: "explicitRequestOnly",
28069
+ initialTurnsPage: null,
28035
28070
  turnsBackwardsCursor: null,
28036
28071
  itemsBackwardsCursor: null
28037
28072
  };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.7.0",
6
+ "version": "0.7.2",
7
7
  "description": "Native ACP v2 agent for the OpenAI Codex app-server",
8
8
  "packageManager": "bun@1.4.0",
9
9
  "engines": {
@@ -75,6 +75,6 @@
75
75
  "vscode-jsonrpc": "^9.0.2"
76
76
  },
77
77
  "optionalDependencies": {
78
- "@openai/codex": "^0.153.0"
78
+ "@openai/codex": "^0.158.0"
79
79
  }
80
80
  }