@agentclientprotocol/codex-acp 1.0.0 → 1.0.1

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 (3) hide show
  1. package/README.md +5 -2
  2. package/dist/index.js +593 -213
  3. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -3343,6 +3343,9 @@ var CLIENT_METHODS = {
3343
3343
  elicitation_create: "elicitation/create",
3344
3344
  elicitation_complete: "elicitation/complete"
3345
3345
  };
3346
+ var PROTOCOL_METHODS = {
3347
+ cancel_request: "$/cancel_request"
3348
+ };
3346
3349
  var PROTOCOL_VERSION = 1;
3347
3350
 
3348
3351
  // node_modules/zod/v4/classic/external.js
@@ -18935,6 +18938,17 @@ var zFileSystemCapabilities = object({
18935
18938
  writeTextFile: boolean2().optional().default(false),
18936
18939
  _meta: record(string2(), unknown()).nullish()
18937
18940
  });
18941
+ var zBooleanConfigOptionCapabilities = object({
18942
+ _meta: record(string2(), unknown()).nullish()
18943
+ });
18944
+ var zSessionConfigOptionsCapabilities = object({
18945
+ boolean: defaultOnError(zBooleanConfigOptionCapabilities.nullish(), () => void 0),
18946
+ _meta: record(string2(), unknown()).nullish()
18947
+ });
18948
+ var zClientSessionCapabilities = object({
18949
+ configOptions: defaultOnError(zSessionConfigOptionsCapabilities.nullish(), () => void 0),
18950
+ _meta: record(string2(), unknown()).nullish()
18951
+ });
18938
18952
  var zPlanCapabilities = object({
18939
18953
  _meta: record(string2(), unknown()).nullish()
18940
18954
  });
@@ -18971,6 +18985,7 @@ var zClientNesCapabilities = object({
18971
18985
  var zClientCapabilities = object({
18972
18986
  fs: zFileSystemCapabilities.optional().default({ readTextFile: false, writeTextFile: false }),
18973
18987
  terminal: boolean2().optional().default(false),
18988
+ session: defaultOnError(zClientSessionCapabilities.nullish(), () => void 0),
18974
18989
  plan: defaultOnError(zPlanCapabilities.nullish(), () => void 0),
18975
18990
  auth: zAuthCapabilities.optional().default({ terminal: false }),
18976
18991
  elicitation: defaultOnError(zElicitationCapabilities.nullish(), () => void 0),
@@ -19515,6 +19530,19 @@ function ndJsonStream(output, input) {
19515
19530
  }
19516
19531
 
19517
19532
  // node_modules/@agentclientprotocol/sdk/dist/jsonrpc.js
19533
+ var CANCEL_REQUEST_METHOD = "$/cancel_request";
19534
+ function isRecord(value) {
19535
+ return typeof value === "object" && value !== null;
19536
+ }
19537
+ function isJsonRpcId(value) {
19538
+ return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
19539
+ }
19540
+ function cancelRequestId(params) {
19541
+ if (!isRecord(params) || !isJsonRpcId(params["requestId"])) {
19542
+ return void 0;
19543
+ }
19544
+ return params["requestId"];
19545
+ }
19518
19546
  var Handled = {
19519
19547
  /**
19520
19548
  * Marks a message as handled.
@@ -19561,13 +19589,40 @@ function errorToResult(error51) {
19561
19589
  return RequestError.internalError({ details }).toResult();
19562
19590
  }
19563
19591
  }
19592
+ function requestCancelledError(reason) {
19593
+ if (reason instanceof RequestError && reason.code === -32800) {
19594
+ return reason;
19595
+ }
19596
+ return RequestError.requestCancelled(reason);
19597
+ }
19598
+ function errorToRequestResult(error51, signal) {
19599
+ const requestCancelled = abortErrorToRequestCancelled(error51, signal);
19600
+ return requestCancelled ? requestCancelled.toResult() : errorToResult(error51);
19601
+ }
19602
+ function abortErrorToRequestCancelled(error51, signal) {
19603
+ if (!signal.aborted || !isAbortError(error51)) {
19604
+ return void 0;
19605
+ }
19606
+ return requestCancelledError(signal.reason);
19607
+ }
19608
+ function isAbortError(error51) {
19609
+ if (typeof error51 !== "object" || error51 === null) {
19610
+ return false;
19611
+ }
19612
+ const maybeAbortError = error51;
19613
+ return maybeAbortError.name === "AbortError" || maybeAbortError.code === "ABORT_ERR";
19614
+ }
19564
19615
  var RequestResponder = class {
19565
19616
  id;
19566
19617
  sendResult;
19618
+ signal;
19619
+ finishRequest;
19567
19620
  didRespond = false;
19568
- constructor(id, sendResult) {
19621
+ constructor(id, sendResult, signal = new AbortController().signal, finishRequest) {
19569
19622
  this.id = id;
19570
19623
  this.sendResult = sendResult;
19624
+ this.signal = signal;
19625
+ this.finishRequest = finishRequest;
19571
19626
  }
19572
19627
  /**
19573
19628
  * Whether this request has already received a response.
@@ -19596,7 +19651,9 @@ var RequestResponder = class {
19596
19651
  return rejectedPromise(new Error("JSON-RPC request already responded"));
19597
19652
  }
19598
19653
  this.didRespond = true;
19599
- return this.sendResult(result);
19654
+ return this.sendResult(result).finally(() => {
19655
+ this.finishRequest?.();
19656
+ });
19600
19657
  }
19601
19658
  };
19602
19659
  var HandlerRegistration = class {
@@ -19636,8 +19693,8 @@ var ConnectionContext = class {
19636
19693
  /**
19637
19694
  * Sends a request over the connection.
19638
19695
  */
19639
- sendRequest(method, params, mapResponse) {
19640
- return this.connection.sendRequest(method, params, mapResponse);
19696
+ sendRequest(method, params, mapResponse, options) {
19697
+ return this.connection.sendRequest(method, params, mapResponse, options);
19641
19698
  }
19642
19699
  /**
19643
19700
  * Sends a notification over the connection.
@@ -19645,6 +19702,12 @@ var ConnectionContext = class {
19645
19702
  sendNotification(method, params) {
19646
19703
  return this.connection.sendNotification(method, params);
19647
19704
  }
19705
+ /**
19706
+ * Sends a protocol-level request cancellation notification.
19707
+ */
19708
+ sendCancelRequest(requestId) {
19709
+ return this.connection.sendCancelRequest(requestId);
19710
+ }
19648
19711
  /**
19649
19712
  * Registers a handler that can be disposed independently.
19650
19713
  */
@@ -19666,6 +19729,7 @@ var ConnectionContext = class {
19666
19729
  };
19667
19730
  var Connection = class {
19668
19731
  pendingResponses = /* @__PURE__ */ new Map();
19732
+ incomingRequests = /* @__PURE__ */ new Map();
19669
19733
  nextRequestId = 0;
19670
19734
  staticHandlers = [];
19671
19735
  dynamicHandlers = /* @__PURE__ */ new Set();
@@ -19763,13 +19827,15 @@ var Connection = class {
19763
19827
  * `mapResponse` can convert the raw result before the returned promise
19764
19828
  * resolves.
19765
19829
  */
19766
- sendRequest(method, params, mapResponse) {
19830
+ sendRequest(method, params, mapResponse, options = {}) {
19767
19831
  if (this.abortController.signal.aborted) {
19768
19832
  return rejectedPromise(this.closedReason());
19769
19833
  }
19770
19834
  const id = this.nextRequestId++;
19835
+ let cancel = () => {
19836
+ };
19771
19837
  const responsePromise = new Promise((resolve, reject) => {
19772
- this.pendingResponses.set(id, {
19838
+ const pendingResponse = {
19773
19839
  resolve: (response) => {
19774
19840
  try {
19775
19841
  const value = mapResponse ? mapResponse(response) : response;
@@ -19779,14 +19845,45 @@ var Connection = class {
19779
19845
  }
19780
19846
  },
19781
19847
  reject
19848
+ };
19849
+ cancel = () => {
19850
+ if (pendingResponse.cancellationSent) {
19851
+ return;
19852
+ }
19853
+ pendingResponse.cancellationSent = true;
19854
+ pendingResponse.cleanup?.();
19855
+ void this.sendCancelRequest(id).catch(() => {
19856
+ });
19857
+ };
19858
+ options.cancellationSignal?.addEventListener("abort", cancel, {
19859
+ once: true
19782
19860
  });
19861
+ pendingResponse.cleanup = () => {
19862
+ options.cancellationSignal?.removeEventListener("abort", cancel);
19863
+ };
19864
+ this.pendingResponses.set(id, pendingResponse);
19783
19865
  });
19784
19866
  responsePromise.catch(() => {
19785
19867
  });
19786
- void this.sendMessage({ jsonrpc: "2.0", id, method, params }).catch(() => {
19868
+ const requestSent = this.sendMessage({
19869
+ jsonrpc: "2.0",
19870
+ id,
19871
+ method,
19872
+ params
19873
+ });
19874
+ void requestSent.catch(() => {
19787
19875
  });
19876
+ if (options.cancellationSignal?.aborted) {
19877
+ cancel();
19878
+ }
19788
19879
  return responsePromise;
19789
19880
  }
19881
+ /**
19882
+ * Sends a protocol-level request cancellation notification.
19883
+ */
19884
+ sendCancelRequest(requestId) {
19885
+ return this.sendNotification(CANCEL_REQUEST_METHOD, { requestId });
19886
+ }
19790
19887
  /**
19791
19888
  * Sends a JSON-RPC notification.
19792
19889
  */
@@ -19804,11 +19901,16 @@ var Connection = class {
19804
19901
  return;
19805
19902
  }
19806
19903
  const closeError = error51 ?? new Error("ACP connection closed");
19904
+ this.abortController.abort(closeError);
19807
19905
  for (const pendingResponse of this.pendingResponses.values()) {
19906
+ pendingResponse.cleanup?.();
19808
19907
  pendingResponse.reject(closeError);
19809
19908
  }
19810
19909
  this.pendingResponses.clear();
19811
- this.abortController.abort(closeError);
19910
+ for (const controller of this.incomingRequests.values()) {
19911
+ controller.abort(closeError);
19912
+ }
19913
+ this.incomingRequests.clear();
19812
19914
  void this.receiveReader?.cancel(closeError).catch(() => {
19813
19915
  });
19814
19916
  }
@@ -19869,6 +19971,9 @@ var Connection = class {
19869
19971
  return;
19870
19972
  }
19871
19973
  if ("method" in message) {
19974
+ if (!("id" in message)) {
19975
+ this.handleProtocolNotification(message);
19976
+ }
19872
19977
  void this.processIncomingMessage(this.toIncomingMessage(message)).catch((error51) => this.close(error51));
19873
19978
  } else if ("id" in message) {
19874
19979
  this.handleResponse(message);
@@ -19909,7 +20014,7 @@ var Connection = class {
19909
20014
  return;
19910
20015
  }
19911
20016
  if (current.kind === "request" && !current.responder.responded) {
19912
- await current.responder.respondWithResult(errorToResult(error51));
20017
+ await current.responder.respondWithResult(errorToRequestResult(error51, current.responder.signal));
19913
20018
  } else {
19914
20019
  const response = errorToResult(error51);
19915
20020
  if ("error" in response) {
@@ -19920,16 +20025,24 @@ var Connection = class {
19920
20025
  }
19921
20026
  toIncomingMessage(message) {
19922
20027
  if ("id" in message) {
20028
+ const abortController = new AbortController();
20029
+ this.incomingRequests.set(message.id, abortController);
20030
+ const finishRequest = () => {
20031
+ if (this.incomingRequests.get(message.id) === abortController) {
20032
+ this.incomingRequests.delete(message.id);
20033
+ }
20034
+ };
19923
20035
  return {
19924
20036
  kind: "request",
19925
20037
  method: message.method,
19926
20038
  params: message.params,
19927
20039
  raw: message,
20040
+ signal: abortController.signal,
19928
20041
  responder: new RequestResponder(message.id, (result) => this.sendMessage({
19929
20042
  jsonrpc: "2.0",
19930
20043
  id: message.id,
19931
20044
  ...result
19932
- }))
20045
+ }), abortController.signal, finishRequest)
19933
20046
  };
19934
20047
  }
19935
20048
  return {
@@ -19942,6 +20055,8 @@ var Connection = class {
19942
20055
  handleResponse(response) {
19943
20056
  const pendingResponse = this.pendingResponses.get(response.id);
19944
20057
  if (pendingResponse) {
20058
+ this.pendingResponses.delete(response.id);
20059
+ pendingResponse.cleanup?.();
19945
20060
  if ("result" in response) {
19946
20061
  pendingResponse.resolve(response.result);
19947
20062
  } else if ("error" in response) {
@@ -19950,11 +20065,24 @@ var Connection = class {
19950
20065
  } else {
19951
20066
  pendingResponse.reject(RequestError.invalidRequest(response));
19952
20067
  }
19953
- this.pendingResponses.delete(response.id);
19954
20068
  } else {
19955
20069
  console.error("Got response to unknown request", response.id);
19956
20070
  }
19957
20071
  }
20072
+ handleProtocolNotification(message) {
20073
+ if (message.method !== CANCEL_REQUEST_METHOD) {
20074
+ return;
20075
+ }
20076
+ const requestId = cancelRequestId(message.params);
20077
+ if (requestId === void 0) {
20078
+ return;
20079
+ }
20080
+ const controller = this.incomingRequests.get(requestId);
20081
+ if (!controller || controller.signal.aborted) {
20082
+ return;
20083
+ }
20084
+ controller.abort(RequestError.requestCancelled({ requestId }));
20085
+ }
19958
20086
  closedReason() {
19959
20087
  return this.abortController.signal.reason ?? new Error("ACP connection closed");
19960
20088
  }
@@ -20095,6 +20223,12 @@ var RequestError = class _RequestError extends Error {
20095
20223
  static internalError(data, additionalMessage) {
20096
20224
  return new _RequestError(-32603, `Internal error${additionalMessage ? `: ${additionalMessage}` : ""}`, data);
20097
20225
  }
20226
+ /**
20227
+ * Execution of the request was aborted.
20228
+ */
20229
+ static requestCancelled(data, additionalMessage) {
20230
+ return new _RequestError(-32800, `Request cancelled${additionalMessage ? `: ${additionalMessage}` : ""}`, data);
20231
+ }
20098
20232
  /**
20099
20233
  * Authentication required.
20100
20234
  */
@@ -20210,6 +20344,9 @@ var methods = {
20210
20344
  create: CLIENT_METHODS.elicitation_create,
20211
20345
  complete: CLIENT_METHODS.elicitation_complete
20212
20346
  }
20347
+ },
20348
+ protocol: {
20349
+ cancelRequest: PROTOCOL_METHODS.cancel_request
20213
20350
  }
20214
20351
  };
20215
20352
  var startActiveSession = /* @__PURE__ */ Symbol("startActiveSession");
@@ -20224,8 +20361,8 @@ var AcpContext = class {
20224
20361
  return this.cx;
20225
20362
  }
20226
20363
  /** @internal */
20227
- sendRequest(method, params, mapResponse) {
20228
- return this.cx.sendRequest(method, params, mapResponse);
20364
+ sendRequest(method, params, mapResponse, options) {
20365
+ return this.cx.sendRequest(method, params, mapResponse, options);
20229
20366
  }
20230
20367
  /** @internal */
20231
20368
  sendNotification(method, params) {
@@ -20244,9 +20381,9 @@ var AgentContext = class _AgentContext extends AcpContext {
20244
20381
  static create(cx) {
20245
20382
  return new _AgentContext(cx);
20246
20383
  }
20247
- request(method, params) {
20384
+ request(method, params, options) {
20248
20385
  const spec = clientRequestSpecsByMethod[method];
20249
- return this.sendRequest(method, params, spec?.mapResponse);
20386
+ return this.sendRequest(method, params, spec?.mapResponse, options);
20250
20387
  }
20251
20388
  notify(method, params) {
20252
20389
  return this.sendNotification(method, params);
@@ -20261,8 +20398,8 @@ var ClientContext = class _ClientContext extends AcpContext {
20261
20398
  return new _ClientContext(cx);
20262
20399
  }
20263
20400
  /** @internal */
20264
- [startActiveSession](params) {
20265
- return this.sendRequest(AGENT_METHODS.session_new, params, (response) => this.attachSession(response));
20401
+ [startActiveSession](params, options) {
20402
+ return this.sendRequest(AGENT_METHODS.session_new, params, (response) => this.attachSession(response), options);
20266
20403
  }
20267
20404
  buildSession(cwdOrRequest) {
20268
20405
  if (typeof cwdOrRequest === "string") {
@@ -20296,9 +20433,9 @@ var ClientContext = class _ClientContext extends AcpContext {
20296
20433
  closeRegistration
20297
20434
  ]);
20298
20435
  }
20299
- request(method, params) {
20436
+ request(method, params, options) {
20300
20437
  const spec = agentRequestSpecsByMethod[method];
20301
- return this.sendRequest(method, params, spec?.mapResponse);
20438
+ return this.sendRequest(method, params, spec?.mapResponse, options);
20302
20439
  }
20303
20440
  notify(method, params) {
20304
20441
  return this.sendNotification(method, params);
@@ -20475,8 +20612,8 @@ var SessionBuilder = class _SessionBuilder {
20475
20612
  * Call `dispose()` on the returned session when you no longer need update
20476
20613
  * routing, or use `withSession(...)` to scope disposal automatically.
20477
20614
  */
20478
- async start() {
20479
- return this.cx[startActiveSession](this.toRequest());
20615
+ async start(options) {
20616
+ return this.cx[startActiveSession](this.toRequest(), options);
20480
20617
  }
20481
20618
  /**
20482
20619
  * Starts the session, runs `op`, and disposes the active-session update
@@ -20538,12 +20675,12 @@ var ActiveSession = class _ActiveSession {
20538
20675
  * `PromptResponse`, and the same completion is also queued as a `stop`
20539
20676
  * message for `nextUpdate()`.
20540
20677
  */
20541
- prompt(prompt) {
20678
+ prompt(prompt, options) {
20542
20679
  this.updates.clearErrors();
20543
20680
  const response = this.cx.request(AGENT_METHODS.session_prompt, {
20544
20681
  sessionId: this.sessionId,
20545
20682
  prompt: this.promptBlocks(prompt)
20546
- });
20683
+ }, options);
20547
20684
  void response.then((value) => {
20548
20685
  this.updates.enqueue({
20549
20686
  kind: "stop",
@@ -20627,12 +20764,12 @@ function notificationSpec(method, params) {
20627
20764
  }
20628
20765
  function registerAppRequest(builder, spec, context, handler) {
20629
20766
  builder.onReceiveRequest(spec.method, (params) => parseParams(spec.params, params), async (params, responder, cx) => {
20630
- const response = await handler(context(params, cx));
20767
+ const response = await handler(context(params, cx, responder.signal));
20631
20768
  await responder.respond(spec.mapResponse ? spec.mapResponse(response) : response);
20632
20769
  });
20633
20770
  }
20634
20771
  function registerAppNotification(builder, spec, context, handler) {
20635
- builder.onReceiveNotification(spec.method, (params) => parseParams(spec.params, params), (params, cx) => handler(context(params, cx)));
20772
+ builder.onReceiveNotification(spec.method, (params) => parseParams(spec.params, params), (params, cx) => handler(context(params, cx, cx.signal)));
20636
20773
  }
20637
20774
  function specsByMethod(specs) {
20638
20775
  const byMethod = {};
@@ -20691,15 +20828,17 @@ var agentRequestSpecsByMethod = specsByMethod(agentRequestSpecs);
20691
20828
  var agentNotificationSpecsByMethod = specsByMethod(agentNotificationSpecs);
20692
20829
  var clientRequestSpecsByMethod = specsByMethod(clientRequestSpecs);
20693
20830
  var clientNotificationSpecsByMethod = specsByMethod(clientNotificationSpecs);
20694
- function agentHandlerContext(params, client) {
20831
+ function agentHandlerContext(params, client, signal) {
20695
20832
  return {
20696
20833
  params,
20834
+ signal,
20697
20835
  client
20698
20836
  };
20699
20837
  }
20700
- function clientHandlerContext(params, agent2) {
20838
+ function clientHandlerContext(params, agent2, signal) {
20701
20839
  return {
20702
20840
  params,
20841
+ signal,
20703
20842
  agent: agent2
20704
20843
  };
20705
20844
  }
@@ -20818,11 +20957,11 @@ var AgentApp = class {
20818
20957
  return this.notification(spec, handlerOrParams);
20819
20958
  }
20820
20959
  request(spec, handler) {
20821
- registerAppRequest(this.builder, spec, (params, cx) => agentHandlerContext(params, AgentContext.create(cx)), handler);
20960
+ registerAppRequest(this.builder, spec, (params, cx, signal) => agentHandlerContext(params, AgentContext.create(cx), signal), handler);
20822
20961
  return this;
20823
20962
  }
20824
20963
  notification(spec, handler) {
20825
- registerAppNotification(this.builder, spec, (params, cx) => agentHandlerContext(params, AgentContext.create(cx)), handler);
20964
+ registerAppNotification(this.builder, spec, (params, cx, signal) => agentHandlerContext(params, AgentContext.create(cx), signal), handler);
20826
20965
  return this;
20827
20966
  }
20828
20967
  connectConnection(target, options = {}) {
@@ -20915,11 +21054,11 @@ var ClientApp = class {
20915
21054
  return this.notification(spec, handlerOrParams);
20916
21055
  }
20917
21056
  request(spec, handler) {
20918
- registerAppRequest(this.builder, spec, (params, cx) => clientHandlerContext(params, ClientContext.create(cx)), handler);
21057
+ registerAppRequest(this.builder, spec, (params, cx, signal) => clientHandlerContext(params, ClientContext.create(cx), signal), handler);
20919
21058
  return this;
20920
21059
  }
20921
21060
  notification(spec, handler) {
20922
- registerAppNotification(this.builder, spec, (params, cx) => clientHandlerContext(params, ClientContext.create(cx)), handler);
21061
+ registerAppNotification(this.builder, spec, (params, cx, signal) => clientHandlerContext(params, ClientContext.create(cx), signal), handler);
20923
21062
  return this;
20924
21063
  }
20925
21064
  connectConnection(target) {
@@ -21844,6 +21983,34 @@ function createWebSearchCompleteUpdate(item) {
21844
21983
  rawInput: item
21845
21984
  };
21846
21985
  }
21986
+ function createCollabAgentToolCallUpdate(item) {
21987
+ return {
21988
+ sessionUpdate: "tool_call",
21989
+ toolCallId: item.id,
21990
+ kind: "other",
21991
+ title: item.tool,
21992
+ status: toAcpStatus(item.status),
21993
+ rawInput: createCollabAgentToolCallRawInput(item)
21994
+ };
21995
+ }
21996
+ function createCollabAgentToolCallCompleteUpdate(item) {
21997
+ return {
21998
+ sessionUpdate: "tool_call_update",
21999
+ toolCallId: item.id,
22000
+ title: item.tool,
22001
+ status: toAcpStatus(item.status),
22002
+ rawInput: createCollabAgentToolCallRawInput(item)
22003
+ };
22004
+ }
22005
+ function createCollabAgentToolCallRawInput(item) {
22006
+ return {
22007
+ prompt: item.prompt,
22008
+ senderThreadId: item.senderThreadId,
22009
+ receiverThreadIds: item.receiverThreadIds,
22010
+ agentsStates: item.agentsStates,
22011
+ status: item.status
22012
+ };
22013
+ }
21847
22014
  function formatWebSearchTitle(item) {
21848
22015
  const action = item.action;
21849
22016
  if (!action) {
@@ -22295,6 +22462,7 @@ var CodexEventHandler = class {
22295
22462
  case "mcpServer/startupStatus/updated":
22296
22463
  case "serverRequest/resolved":
22297
22464
  case "model/verification":
22465
+ case "model/safetyBuffering/updated":
22298
22466
  case "windows/worldWritableWarning":
22299
22467
  case "thread/realtime/started":
22300
22468
  case "thread/realtime/itemAdded":
@@ -22316,6 +22484,7 @@ var CodexEventHandler = class {
22316
22484
  case "remoteControl/status/changed":
22317
22485
  case "app/list/updated":
22318
22486
  case "thread/settings/updated":
22487
+ case "externalAgentConfig/import/progress":
22319
22488
  case "process/outputDelta":
22320
22489
  case "process/exited":
22321
22490
  return null;
@@ -22455,6 +22624,7 @@ ${objective}` : `Goal updated (${status}): ${objective}`;
22455
22624
  this.activeImageGenerationItems.add(event.item.id);
22456
22625
  return createImageGenerationStartUpdate(event.item);
22457
22626
  case "collabAgentToolCall":
22627
+ return createCollabAgentToolCallUpdate(event.item);
22458
22628
  case "subAgentActivity":
22459
22629
  case "sleep":
22460
22630
  case "userMessage":
@@ -22504,12 +22674,13 @@ ${objective}` : `Goal updated (${status}): ${objective}`;
22504
22674
  return this.createCompletedReasoningEvent(event.item);
22505
22675
  case "webSearch":
22506
22676
  return createWebSearchCompleteUpdate(event.item);
22677
+ case "collabAgentToolCall":
22678
+ return createCollabAgentToolCallCompleteUpdate(event.item);
22507
22679
  case "exitedReviewMode":
22508
22680
  return this.createExitedReviewModeEvent(event.item);
22509
22681
  case "contextCompaction":
22510
22682
  return this.createContextCompactedEvent();
22511
22683
  //ignored types
22512
- case "collabAgentToolCall":
22513
22684
  case "subAgentActivity":
22514
22685
  case "sleep":
22515
22686
  case "userMessage":
@@ -22668,8 +22839,12 @@ ${event.stdin}
22668
22839
  }
22669
22840
  async createErrorEvent(params) {
22670
22841
  const error51 = params.error.codexErrorInfo;
22671
- if (error51 == "unauthorized" || error51 == "usageLimitExceeded" || this.getHttpStatusCode(error51) == 401) {
22672
- this.failure = RequestError.authRequired();
22842
+ if (error51 === "usageLimitExceeded") {
22843
+ this.failure = RequestError.internalError(
22844
+ this.createTurnErrorData(params.error)
22845
+ );
22846
+ } else if (this.isAuthenticationRequiredError(error51)) {
22847
+ this.failure = this.sessionState.authConfigured ? RequestError.internalError(this.createTurnErrorData(params.error)) : RequestError.authRequired(this.createTurnErrorData(params.error), params.error.message);
22673
22848
  }
22674
22849
  return {
22675
22850
  sessionUpdate: "agent_message_chunk",
@@ -22681,6 +22856,9 @@ ${event.stdin}
22681
22856
  }
22682
22857
  };
22683
22858
  }
22859
+ isAuthenticationRequiredError(error51) {
22860
+ return error51 === "unauthorized" || this.getHttpStatusCode(error51) === 401;
22861
+ }
22684
22862
  getHttpStatusCode(error51) {
22685
22863
  if (error51 !== null && typeof error51 === "object") {
22686
22864
  if ("httpConnectionFailed" in error51) {
@@ -22695,6 +22873,18 @@ ${event.stdin}
22695
22873
  }
22696
22874
  return null;
22697
22875
  }
22876
+ createTurnErrorData(error51) {
22877
+ const data = {
22878
+ message: error51.additionalDetails ?? error51.message
22879
+ };
22880
+ if (error51.codexErrorInfo !== null) {
22881
+ data.codexErrorInfo = error51.codexErrorInfo;
22882
+ }
22883
+ if (error51.additionalDetails !== null) {
22884
+ data.additionalDetails = error51.additionalDetails;
22885
+ }
22886
+ return data;
22887
+ }
22698
22888
  handleTokenUsageUpdated(params) {
22699
22889
  this.sessionState.lastTokenUsage = toTokenCount(params.tokenUsage.last);
22700
22890
  this.sessionState.totalTokenUsage = toTokenCount(params.tokenUsage.total);
@@ -22774,15 +22964,21 @@ function permissionOption(optionId, name, kind, codexMeta) {
22774
22964
  var CodexApprovalHandler = class {
22775
22965
  connection;
22776
22966
  sessionState;
22777
- constructor(connection, sessionState) {
22967
+ cancellationSignal;
22968
+ constructor(connection, sessionState, cancellationSignal) {
22778
22969
  this.connection = connection;
22779
22970
  this.sessionState = sessionState;
22971
+ this.cancellationSignal = cancellationSignal;
22780
22972
  }
22781
22973
  async handleCommandExecution(params) {
22782
22974
  try {
22783
22975
  const sessionId = this.sessionState.sessionId;
22784
22976
  const acpRequest = this.buildCommandPermissionRequest(sessionId, params);
22785
- const response = await this.connection.request(methods.client.session.requestPermission, acpRequest);
22977
+ const response = await this.connection.request(
22978
+ methods.client.session.requestPermission,
22979
+ acpRequest,
22980
+ this.requestOptions()
22981
+ );
22786
22982
  return this.convertCommandResponse(params, response);
22787
22983
  } catch (error51) {
22788
22984
  logger.error("Error requesting command execution permission", error51);
@@ -22793,7 +22989,11 @@ var CodexApprovalHandler = class {
22793
22989
  try {
22794
22990
  const sessionId = this.sessionState.sessionId;
22795
22991
  const acpRequest = this.buildFileChangePermissionRequest(sessionId, params);
22796
- const response = await this.connection.request(methods.client.session.requestPermission, acpRequest);
22992
+ const response = await this.connection.request(
22993
+ methods.client.session.requestPermission,
22994
+ acpRequest,
22995
+ this.requestOptions()
22996
+ );
22797
22997
  return this.convertFileChangeResponse(params, response);
22798
22998
  } catch (error51) {
22799
22999
  logger.error("Error requesting file change permission", error51);
@@ -22804,13 +23004,20 @@ var CodexApprovalHandler = class {
22804
23004
  try {
22805
23005
  const sessionId = this.sessionState.sessionId;
22806
23006
  const acpRequest = this.buildPermissionsRequest(sessionId, params);
22807
- const response = await this.connection.request(methods.client.session.requestPermission, acpRequest);
23007
+ const response = await this.connection.request(
23008
+ methods.client.session.requestPermission,
23009
+ acpRequest,
23010
+ this.requestOptions()
23011
+ );
22808
23012
  return this.convertPermissionsResponse(params, response);
22809
23013
  } catch (error51) {
22810
23014
  logger.error("Error requesting permissions", error51);
22811
23015
  return this.rejectPermissionsResponse();
22812
23016
  }
22813
23017
  }
23018
+ requestOptions() {
23019
+ return this.cancellationSignal ? { cancellationSignal: this.cancellationSignal } : void 0;
23020
+ }
22814
23021
  buildCommandPermissionRequest(sessionId, params) {
22815
23022
  const options = this.buildCommandOptions(params).map(({ option }) => option);
22816
23023
  return {
@@ -23095,6 +23302,7 @@ function buildToolApprovalOptions(persistOptions) {
23095
23302
  var CodexElicitationHandler = class {
23096
23303
  connection;
23097
23304
  sessionState;
23305
+ cancellationSignal;
23098
23306
  // In Rust, the MCP elicitation handler receives ElicitationRequestEvent directly from the MCP
23099
23307
  // protocol layer, where id is set to "mcp_tool_call_approval_<call_id>" — the call ID is extracted
23100
23308
  // by stripping that prefix.
@@ -23111,9 +23319,10 @@ var CodexElicitationHandler = class {
23111
23319
  // call's elicitation before starting the next, so there is at most one pending approval per
23112
23320
  // (threadId, serverName).
23113
23321
  pendingMcpApprovals = /* @__PURE__ */ new Map();
23114
- constructor(connection, sessionState) {
23322
+ constructor(connection, sessionState, cancellationSignal) {
23115
23323
  this.connection = connection;
23116
23324
  this.sessionState = sessionState;
23325
+ this.cancellationSignal = cancellationSignal;
23117
23326
  }
23118
23327
  handleNotification(notification) {
23119
23328
  switch (notification.method) {
@@ -23133,7 +23342,11 @@ var CodexElicitationHandler = class {
23133
23342
  async handleElicitation(params) {
23134
23343
  try {
23135
23344
  const { request, correlatedCallId } = this.buildPermissionRequest(params);
23136
- const response = await this.connection.request(methods.client.session.requestPermission, request);
23345
+ const response = await this.connection.request(
23346
+ methods.client.session.requestPermission,
23347
+ request,
23348
+ this.requestOptions()
23349
+ );
23137
23350
  if (correlatedCallId !== void 0 && response.outcome.outcome !== "cancelled") {
23138
23351
  const optionId = response.outcome.optionId;
23139
23352
  if (optionId !== McpApprovalOptionId.Decline) {
@@ -23149,6 +23362,9 @@ var CodexElicitationHandler = class {
23149
23362
  return { action: "cancel", content: null, _meta: null };
23150
23363
  }
23151
23364
  }
23365
+ requestOptions() {
23366
+ return this.cancellationSignal ? { cancellationSignal: this.cancellationSignal } : void 0;
23367
+ }
23152
23368
  buildPermissionRequest(params) {
23153
23369
  const sessionId = this.sessionState.sessionId;
23154
23370
  const messageContent = {
@@ -23158,7 +23374,7 @@ var CodexElicitationHandler = class {
23158
23374
  const meta3 = params._meta;
23159
23375
  const isToolApproval = isMcpToolCallApproval(meta3);
23160
23376
  const options = isToolApproval ? buildToolApprovalOptions(parsePersistOptions(meta3)) : ELICITATION_OPTIONS;
23161
- if (params.mode === "form") {
23377
+ if (params.mode === "form" || params.mode === "openai/form") {
23162
23378
  const correlatedCallId = isToolApproval ? this.popPendingApproval(params.threadId, params.serverName) : void 0;
23163
23379
  if (correlatedCallId !== void 0) {
23164
23380
  return {
@@ -23259,6 +23475,8 @@ var CodexElicitationHandler = class {
23259
23475
  };
23260
23476
 
23261
23477
  // src/CodexAuthMethod.ts
23478
+ var CODEX_API_KEY_ENV_VAR = "CODEX_API_KEY";
23479
+ var OPENAI_API_KEY_ENV_VAR = "OPENAI_API_KEY";
23262
23480
  var ApiKeyAuthMethod = {
23263
23481
  id: "api-key",
23264
23482
  name: "API Key",
@@ -23285,8 +23503,11 @@ var GatewayAuthMethod = {
23285
23503
  }
23286
23504
  }
23287
23505
  };
23288
- function getCodexAuthMethods(clientCapabilities) {
23289
- const authMethods = [ApiKeyAuthMethod, ChatGptAuthMethod];
23506
+ function getCodexAuthMethods(clientCapabilities, env = process.env) {
23507
+ const authMethods = [ApiKeyAuthMethod];
23508
+ if (!env["NO_BROWSER"]) {
23509
+ authMethods.push(ChatGptAuthMethod);
23510
+ }
23290
23511
  const supportsGatewayAuth = clientCapabilities?.auth?._meta?.["gateway"] === true;
23291
23512
  if (supportsGatewayAuth) {
23292
23513
  authMethods.push(GatewayAuthMethod);
@@ -24038,7 +24259,7 @@ var package_default = {
24038
24259
  publishConfig: {
24039
24260
  access: "public"
24040
24261
  },
24041
- version: "1.0.0",
24262
+ version: "1.0.1",
24042
24263
  description: "",
24043
24264
  main: "dist/index.js",
24044
24265
  bin: {
@@ -24096,8 +24317,8 @@ var package_default = {
24096
24317
  vitest: "^4.0.10"
24097
24318
  },
24098
24319
  dependencies: {
24099
- "@agentclientprotocol/sdk": "^0.28.1",
24100
- "@openai/codex": "^0.141.0",
24320
+ "@agentclientprotocol/sdk": "^1.0.0",
24321
+ "@openai/codex": "^0.142.2",
24101
24322
  diff: "^8.0.3",
24102
24323
  open: "^11.0.0",
24103
24324
  "vscode-jsonrpc": "^8.2.1",
@@ -24142,17 +24363,15 @@ var CodexAcpClient = class {
24142
24363
  }
24143
24364
  switch (authRequest.methodId) {
24144
24365
  case "api-key": {
24145
- if (!authRequest._meta || !authRequest._meta["api-key"]) throw RequestError.invalidRequest();
24146
- const loginCompletedPromise = this.awaitNextLoginCompleted();
24147
- await this.codexClient.accountLogin({
24148
- type: "apiKey",
24149
- apiKey: authRequest._meta["api-key"].apiKey
24150
- });
24151
- this.gatewayConfig = null;
24152
- const result = await loginCompletedPromise;
24153
- return result.success;
24366
+ const apiKey = authRequest._meta?.["api-key"]?.apiKey ?? this.readApiKeyFromEnv();
24367
+ return await this.authenticateWithApiKey(apiKey);
24154
24368
  }
24155
24369
  case "chat-gpt": {
24370
+ const accountResponse = await this.codexClient.accountRead({ refreshToken: true });
24371
+ if (accountResponse.account?.type === "chatgpt") {
24372
+ this.gatewayConfig = null;
24373
+ return true;
24374
+ }
24156
24375
  const loginCompletedPromise = this.awaitNextLoginCompleted();
24157
24376
  const loginResponse = await this.codexClient.accountLogin({ type: "chatgpt" });
24158
24377
  if (loginResponse.type == "chatgpt") {
@@ -24186,6 +24405,28 @@ var CodexAcpClient = class {
24186
24405
  this.gatewayConfig = null;
24187
24406
  return false;
24188
24407
  }
24408
+ async authenticateWithApiKey(apiKey) {
24409
+ const loginCompletedPromise = this.awaitNextLoginCompleted();
24410
+ await this.codexClient.accountLogin({
24411
+ type: "apiKey",
24412
+ apiKey
24413
+ });
24414
+ this.gatewayConfig = null;
24415
+ const result = await loginCompletedPromise;
24416
+ return result.success;
24417
+ }
24418
+ readApiKeyFromEnv() {
24419
+ for (const envVar of [CODEX_API_KEY_ENV_VAR, OPENAI_API_KEY_ENV_VAR]) {
24420
+ const value = process.env[envVar]?.trim();
24421
+ if (value) {
24422
+ return value;
24423
+ }
24424
+ }
24425
+ throw RequestError.internalError(
24426
+ { envVars: [CODEX_API_KEY_ENV_VAR, OPENAI_API_KEY_ENV_VAR] },
24427
+ `${CODEX_API_KEY_ENV_VAR} or ${OPENAI_API_KEY_ENV_VAR} is not set`
24428
+ );
24429
+ }
24189
24430
  async getAuthenticationStatus() {
24190
24431
  const modelProvider = await this.getCurrentModelProvider();
24191
24432
  if (modelProvider) {
@@ -24208,7 +24449,7 @@ var CodexAcpClient = class {
24208
24449
  case "chatgpt":
24209
24450
  return {
24210
24451
  type: "chat-gpt",
24211
- email: account.email
24452
+ email: account.email ?? ""
24212
24453
  };
24213
24454
  case "amazonBedrock":
24214
24455
  return {
@@ -24223,7 +24464,7 @@ var CodexAcpClient = class {
24223
24464
  return sessionModelProvider;
24224
24465
  }
24225
24466
  const settingsModelProvider = await this.codexClient.configRead({ includeLayers: false });
24226
- return settingsModelProvider.config.model_provider;
24467
+ return settingsModelProvider?.config?.model_provider ?? null;
24227
24468
  }
24228
24469
  async logout() {
24229
24470
  const accountUpdatedPromise = this.awaitNextAccountUpdated();
@@ -24237,6 +24478,9 @@ var CodexAcpClient = class {
24237
24478
  const response = await this.codexClient.accountRead({ refreshToken: false });
24238
24479
  return response.requiresOpenaiAuth && !response.account;
24239
24480
  }
24481
+ hasGatewayAuth() {
24482
+ return this.gatewayConfig !== null;
24483
+ }
24240
24484
  async getAccount() {
24241
24485
  return this.codexClient.accountRead({ refreshToken: false });
24242
24486
  }
@@ -24246,7 +24490,7 @@ var CodexAcpClient = class {
24246
24490
  const response = await this.codexClient.threadResume({
24247
24491
  config: await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []),
24248
24492
  cwd: request.cwd,
24249
- modelProvider: this.getResumeModelProvider(),
24493
+ modelProvider: await this.getResumeModelProvider(),
24250
24494
  threadId: request.sessionId
24251
24495
  });
24252
24496
  onSubscribed?.();
@@ -24256,6 +24500,7 @@ var CodexAcpClient = class {
24256
24500
  sessionId: request.sessionId,
24257
24501
  currentModelId,
24258
24502
  models: codexModels,
24503
+ modelProvider: response.modelProvider,
24259
24504
  currentServiceTier: response.serviceTier ?? null,
24260
24505
  additionalDirectories
24261
24506
  };
@@ -24266,7 +24511,7 @@ var CodexAcpClient = class {
24266
24511
  const response = await this.codexClient.threadResume({
24267
24512
  config: await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []),
24268
24513
  cwd: request.cwd,
24269
- modelProvider: this.getResumeModelProvider(),
24514
+ modelProvider: await this.getResumeModelProvider(),
24270
24515
  threadId: request.sessionId
24271
24516
  });
24272
24517
  onSubscribed?.();
@@ -24280,6 +24525,7 @@ var CodexAcpClient = class {
24280
24525
  sessionId: request.sessionId,
24281
24526
  currentModelId,
24282
24527
  models: codexModels,
24528
+ modelProvider: response.modelProvider,
24283
24529
  currentServiceTier: response.serviceTier ?? null,
24284
24530
  thread: historyResponse.thread,
24285
24531
  additionalDirectories
@@ -24302,6 +24548,7 @@ var CodexAcpClient = class {
24302
24548
  sessionId: response.thread.id,
24303
24549
  currentModelId,
24304
24550
  models: codexModels,
24551
+ modelProvider: response.modelProvider,
24305
24552
  currentServiceTier: response.serviceTier ?? null,
24306
24553
  additionalDirectories
24307
24554
  };
@@ -24372,8 +24619,8 @@ var CodexAcpClient = class {
24372
24619
  getModelProvider() {
24373
24620
  return this.gatewayConfig?.modelProvider ?? this.modelProvider;
24374
24621
  }
24375
- getResumeModelProvider() {
24376
- return this.getModelProvider() ?? "openai";
24622
+ async getResumeModelProvider() {
24623
+ return await this.getCurrentModelProvider() ?? "openai";
24377
24624
  }
24378
24625
  async refreshSkills(cwd, additionalRoots) {
24379
24626
  if (!cwd) {
@@ -24417,11 +24664,18 @@ var CodexAcpClient = class {
24417
24664
  * Falls back to model defaults if parameters are missing or unsupported.
24418
24665
  */
24419
24666
  createModelId(availableModels, modelId, reasoningEffort) {
24420
- const selectedModel = availableModels.find((m) => m.id === modelId) ?? availableModels.find((m) => m.isDefault);
24421
- if (!selectedModel) {
24667
+ const selectedModel = availableModels.find((m) => m.id === modelId);
24668
+ if (selectedModel) {
24669
+ return ModelId.create(selectedModel.id, reasoningEffort ?? selectedModel.defaultReasoningEffort);
24670
+ }
24671
+ if (modelId) {
24672
+ return ModelId.create(modelId, reasoningEffort ?? "medium");
24673
+ }
24674
+ const defaultModel = availableModels.find((m) => m.isDefault);
24675
+ if (!defaultModel) {
24422
24676
  throw new Error(`Model selection failed: No model found for ID "${modelId}" and no default model is defined.`);
24423
24677
  }
24424
- return ModelId.create(selectedModel.id, reasoningEffort ?? selectedModel.defaultReasoningEffort);
24678
+ return ModelId.create(defaultModel.id, reasoningEffort ?? defaultModel.defaultReasoningEffort);
24425
24679
  }
24426
24680
  async subscribeToSessionEvents(sessionId, eventHandler, approvalHandler, elicitationHandler) {
24427
24681
  this.codexClient.onServerNotification(sessionId, (event) => {
@@ -24545,11 +24799,6 @@ var CodexAcpClient = class {
24545
24799
  "vscode",
24546
24800
  "exec",
24547
24801
  "appServer",
24548
- "subAgent",
24549
- "subAgentReview",
24550
- "subAgentCompact",
24551
- "subAgentThreadSpawn",
24552
- "subAgentOther",
24553
24802
  "unknown"
24554
24803
  ];
24555
24804
  const requestedCwd = request.cwd?.trim() ?? null;
@@ -24568,23 +24817,19 @@ var CodexAcpClient = class {
24568
24817
  modelProviders,
24569
24818
  sourceKinds
24570
24819
  });
24571
- if (listResponse.data.length === 0) {
24572
- const diagnostics = await this.runSessionListDiagnostics();
24573
- logger.log("Session list diagnostics", diagnostics);
24574
- }
24575
- let sessions = listResponse.data.map((thread) => ({
24820
+ const mapThreadToSession = (thread) => ({
24576
24821
  sessionId: thread.id,
24577
24822
  cwd: thread.cwd,
24578
24823
  title: (thread.name ?? thread.preview) || null,
24579
24824
  updatedAt: new Date(thread.updatedAt * 1e3).toISOString()
24580
- }));
24825
+ });
24826
+ if (listResponse.data.length === 0) {
24827
+ const diagnostics = await this.runSessionListDiagnostics();
24828
+ logger.log("Session list diagnostics", diagnostics);
24829
+ }
24830
+ let sessions = listResponse.data.map(mapThreadToSession);
24581
24831
  if (requestedCwd) {
24582
- const filtered = listResponse.data.filter(filterByCwd).map((thread) => ({
24583
- sessionId: thread.id,
24584
- cwd: thread.cwd,
24585
- title: (thread.name ?? thread.preview) || null,
24586
- updatedAt: new Date(thread.updatedAt * 1e3).toISOString()
24587
- }));
24832
+ const filtered = listResponse.data.filter(filterByCwd).map(mapThreadToSession);
24588
24833
  if (filtered.length > 0 || path4.isAbsolute(requestedCwd)) {
24589
24834
  sessions = filtered;
24590
24835
  } else {
@@ -24640,7 +24885,7 @@ function buildPromptItems(prompt) {
24640
24885
  case "text":
24641
24886
  return { type: "text", text: block.text, text_elements: [] };
24642
24887
  case "image": {
24643
- const url2 = block.uri ?? `data:${block.mimeType};base64,${block.data}`;
24888
+ const url2 = isSupportedImageUrl(block.uri) ? block.uri : imageDataUrl(block);
24644
24889
  return { type: "image", url: url2 };
24645
24890
  }
24646
24891
  case "resource_link":
@@ -24671,9 +24916,23 @@ ${context}`, text_elements: [] };
24671
24916
  }
24672
24917
  }).filter((block) => block !== null);
24673
24918
  }
24919
+ function imageDataUrl(block) {
24920
+ return `data:${block.mimeType};base64,${block.data}`;
24921
+ }
24674
24922
  function isImageMimeType(mimeType) {
24675
24923
  return mimeType?.startsWith("image/") ?? false;
24676
24924
  }
24925
+ function isSupportedImageUrl(uri) {
24926
+ if (!uri) {
24927
+ return false;
24928
+ }
24929
+ try {
24930
+ const protocol = new URL(uri).protocol;
24931
+ return protocol === "http:" || protocol === "https:" || protocol === "data:";
24932
+ } catch {
24933
+ return false;
24934
+ }
24935
+ }
24677
24936
  function formatUriAsLink(name, uri) {
24678
24937
  if (name && name.length > 0) {
24679
24938
  return `[@${name}](${uri})`;
@@ -24778,6 +25037,18 @@ function findSupportedEffort(options, effort) {
24778
25037
  return options.find((o) => o.reasoningEffort === effort)?.reasoningEffort;
24779
25038
  }
24780
25039
  function createModelConfigOption(availableModels, currentBaseModelId) {
25040
+ const options = availableModels.map((model) => ({
25041
+ value: model.id,
25042
+ name: model.displayName,
25043
+ description: model.description
25044
+ }));
25045
+ if (!availableModels.some((model) => model.id === currentBaseModelId)) {
25046
+ options.unshift({
25047
+ value: currentBaseModelId,
25048
+ name: currentBaseModelId,
25049
+ description: null
25050
+ });
25051
+ }
24781
25052
  return {
24782
25053
  id: MODEL_CONFIG_ID,
24783
25054
  name: "Model",
@@ -24785,11 +25056,7 @@ function createModelConfigOption(availableModels, currentBaseModelId) {
24785
25056
  category: "model",
24786
25057
  type: "select",
24787
25058
  currentValue: currentBaseModelId,
24788
- options: availableModels.map((model) => ({
24789
- value: model.id,
24790
- name: model.displayName,
24791
- description: model.description
24792
- }))
25059
+ options
24793
25060
  };
24794
25061
  }
24795
25062
  function createReasoningEffortConfigOption(supportedReasoningEfforts, currentEffort) {
@@ -24813,10 +25080,13 @@ var CodexCommands = class {
24813
25080
  connection;
24814
25081
  codexAcpClient;
24815
25082
  runWithProcessCheck;
24816
- constructor(connection, codexAcpClient, runWithProcessCheck) {
25083
+ onLogout;
25084
+ constructor(connection, codexAcpClient, runWithProcessCheck, onLogout = () => {
25085
+ }) {
24817
25086
  this.connection = connection;
24818
25087
  this.codexAcpClient = codexAcpClient;
24819
25088
  this.runWithProcessCheck = runWithProcessCheck;
25089
+ this.onLogout = onLogout;
24820
25090
  }
24821
25091
  async publish(sessionId) {
24822
25092
  try {
@@ -24914,7 +25184,7 @@ var CodexCommands = class {
24914
25184
  rest: commandText.slice(name.length).trim()
24915
25185
  };
24916
25186
  }
24917
- async tryHandleCommand(prompt, sessionState) {
25187
+ async tryHandleCommand(prompt, sessionState, options = {}) {
24918
25188
  const command = this.parseCommand(prompt);
24919
25189
  if (command === null) return { handled: false };
24920
25190
  const commandName = command.name;
@@ -24927,7 +25197,7 @@ var CodexCommands = class {
24927
25197
  }
24928
25198
  case "review": {
24929
25199
  const target = this.buildReviewTarget(command.rest);
24930
- const turnCompleted = await this.runReviewCommand(sessionState, target);
25200
+ const turnCompleted = await this.runReviewCommand(sessionState, target, options);
24931
25201
  return { handled: true, turnCompleted };
24932
25202
  }
24933
25203
  case "review-branch": {
@@ -24938,7 +25208,7 @@ var CodexCommands = class {
24938
25208
  const turnCompleted = await this.runReviewCommand(sessionState, {
24939
25209
  type: "baseBranch",
24940
25210
  branch: command.rest
24941
- });
25211
+ }, options);
24942
25212
  return { handled: true, turnCompleted };
24943
25213
  }
24944
25214
  case "review-commit": {
@@ -24950,7 +25220,7 @@ var CodexCommands = class {
24950
25220
  type: "commit",
24951
25221
  sha: command.rest,
24952
25222
  title: null
24953
- });
25223
+ }, options);
24954
25224
  return { handled: true, turnCompleted };
24955
25225
  }
24956
25226
  case "status": {
@@ -24964,6 +25234,7 @@ var CodexCommands = class {
24964
25234
  }
24965
25235
  case "logout": {
24966
25236
  await this.runWithProcessCheck(() => this.codexAcpClient.logout());
25237
+ await this.onLogout();
24967
25238
  const session = new ACPSessionConnection(this.connection, sessionId);
24968
25239
  await session.update({
24969
25240
  sessionUpdate: "agent_message_chunk",
@@ -25008,12 +25279,16 @@ var CodexCommands = class {
25008
25279
  return { handled: true };
25009
25280
  }
25010
25281
  }
25011
- async runReviewCommand(sessionState, target) {
25282
+ async runReviewCommand(sessionState, target, options) {
25012
25283
  return await this.runWithProcessCheck(() => this.codexAcpClient.runReview(
25013
25284
  sessionState.sessionId,
25014
25285
  target,
25015
- (turnId) => {
25016
- sessionState.currentTurnId = turnId;
25286
+ (turnId, threadId) => {
25287
+ if (options.onTurnStarted) {
25288
+ options.onTurnStarted(turnId, threadId);
25289
+ } else {
25290
+ sessionState.currentTurnId = turnId;
25291
+ }
25017
25292
  }
25018
25293
  ));
25019
25294
  }
@@ -25484,15 +25759,16 @@ function createFunctionCallUpdate(item) {
25484
25759
  if (!toolCallId || !name) {
25485
25760
  return null;
25486
25761
  }
25762
+ const isExecCommand = name === "exec_command";
25487
25763
  const args = parseFunctionArguments(item["arguments"]);
25488
- const command = name === "exec_command" ? commandFromFunctionArguments(args) : null;
25489
- const cwd = name === "exec_command" ? cwdFromFunctionArguments(args) : "";
25764
+ const command = isExecCommand ? commandFromFunctionArguments(args) : null;
25765
+ const cwd = isExecCommand ? cwdFromFunctionArguments(args) : "";
25490
25766
  const commandAction = command ? inferCommandAction(command, cwd) : null;
25491
25767
  if (commandAction) {
25492
25768
  return {
25493
25769
  update: createCommandActionEvent(toolCallId, "inProgress", cwd, commandAction),
25494
25770
  usesTerminal: false,
25495
- isExecCommand: true
25771
+ isExecCommand
25496
25772
  };
25497
25773
  }
25498
25774
  const update = {
@@ -25504,12 +25780,12 @@ function createFunctionCallUpdate(item) {
25504
25780
  rawInput: rawInputForFunctionCall(name, args)
25505
25781
  };
25506
25782
  if (!functionCallUsesTerminal(item)) {
25507
- return { update, usesTerminal: false, isExecCommand: false };
25783
+ return { update, usesTerminal: false, isExecCommand };
25508
25784
  }
25509
25785
  return {
25510
25786
  update: withTerminalContent(update, toolCallId, cwd),
25511
25787
  usesTerminal: true,
25512
- isExecCommand: true
25788
+ isExecCommand
25513
25789
  };
25514
25790
  }
25515
25791
  function createFunctionCallOutputUpdate(item, terminalOutputMode, terminalToolCallIds, execToolCallIds) {
@@ -26023,7 +26299,7 @@ function sedFileArguments(args) {
26023
26299
  return files;
26024
26300
  }
26025
26301
  function looksLikeSedRangeScript(arg) {
26026
- return /^(\d+|\$)?(,(\d+|\$))?[pd]$/.test(arg) || /^(\d+|\$)?(,(\d+|\$))?p$/.test(arg);
26302
+ return /^(\d+|\$)?(,(\d+|\$))?[pd]$/.test(arg);
26027
26303
  }
26028
26304
  function headTailFileArguments(args) {
26029
26305
  const files = [];
@@ -26238,7 +26514,8 @@ var CodexAcpServer = class _CodexAcpServer {
26238
26514
  this.availableCommands = new CodexCommands(
26239
26515
  connection,
26240
26516
  codexAcpClient,
26241
- (operation) => this.runWithProcessCheck(operation)
26517
+ (operation) => this.runWithProcessCheck(operation),
26518
+ () => this.refreshSessionsAuthState(null)
26242
26519
  );
26243
26520
  }
26244
26521
  async initialize(_params) {
@@ -26322,6 +26599,7 @@ var CodexAcpServer = class _CodexAcpServer {
26322
26599
  async handleError(e) {
26323
26600
  if (e.message.includes("log out") || e.message.includes("cloud requirements")) {
26324
26601
  await this.runWithProcessCheck(() => this.codexAcpClient.logout());
26602
+ await this.refreshSessionsAuthState(null);
26325
26603
  throw RequestError.internalError(`${e.message}
26326
26604
 
26327
26605
  You have been logged out. Please try again.`);
@@ -26407,9 +26685,10 @@ You have been logged out. Please try again.`);
26407
26685
  sessionMetadata = await this.runWithProcessCheck(() => this.codexAcpClient.newSession(request));
26408
26686
  }
26409
26687
  const { sessionId, currentModelId, models } = sessionMetadata;
26410
- let account;
26688
+ const authProvider = sessionMetadata.modelProvider ?? this.codexAcpClient.getModelProvider();
26689
+ let authState;
26411
26690
  try {
26412
- account = await this.getActiveAccount();
26691
+ authState = await this.getAuthStateForProvider(authProvider);
26413
26692
  } catch (err) {
26414
26693
  if (resumeSubscribed && requestedSessionGeneration !== null) {
26415
26694
  await this.cleanupStaleSessionOpen(sessionId, requestedSessionGeneration);
@@ -26436,7 +26715,9 @@ You have been logged out. Please try again.`);
26436
26715
  totalTokenUsage: null,
26437
26716
  modelContextWindow: null,
26438
26717
  rateLimits: null,
26439
- account,
26718
+ account: authState.account,
26719
+ authConfigured: authState.authConfigured,
26720
+ authProvider,
26440
26721
  cwd: request.cwd,
26441
26722
  additionalDirectories: sessionMetadata.additionalDirectories,
26442
26723
  fastModeEnabled: sessionMetadata.currentServiceTier === "fast",
@@ -26458,12 +26739,33 @@ You have been logged out. Please try again.`);
26458
26739
  const sessionModeState = sessionState.agentMode.toSessionModeState();
26459
26740
  return [sessionId, sessionModelState, sessionModeState];
26460
26741
  }
26461
- async getActiveAccount() {
26462
- if (this.codexAcpClient.getModelProvider()) {
26463
- return null;
26742
+ async getAuthStateForProvider(authProvider) {
26743
+ if (!this.authProviderUsesOpenAiAccount(authProvider)) {
26744
+ return {
26745
+ account: null,
26746
+ authConfigured: true
26747
+ };
26464
26748
  }
26465
26749
  const accountResponse = await this.runWithProcessCheck(() => this.codexAcpClient.getAccount());
26466
- return accountResponse.account;
26750
+ return {
26751
+ account: accountResponse.account,
26752
+ authConfigured: accountResponse.account !== null || !accountResponse.requiresOpenaiAuth
26753
+ };
26754
+ }
26755
+ authProviderUsesOpenAiAccount(authProvider) {
26756
+ return authProvider === null || authProvider === "openai";
26757
+ }
26758
+ authProvidersMatch(a, b) {
26759
+ if (this.authProviderUsesOpenAiAccount(a) && this.authProviderUsesOpenAiAccount(b)) {
26760
+ return true;
26761
+ }
26762
+ return a === b;
26763
+ }
26764
+ getAuthProviderForAuthenticateRequest(request) {
26765
+ if (isCodexAuthRequest(request) && request.methodId === "gateway") {
26766
+ return "custom-gateway";
26767
+ }
26768
+ return null;
26467
26769
  }
26468
26770
  async loadSession(params) {
26469
26771
  logger.log("Loading session...", { sessionId: params.sessionId });
@@ -26592,14 +26894,26 @@ You have been logged out. Please try again.`);
26592
26894
  logger.log("Authenticate request failed");
26593
26895
  throw RequestError.invalidParams();
26594
26896
  }
26897
+ await this.refreshSessionsAuthState(this.getAuthProviderForAuthenticateRequest(_params));
26595
26898
  logger.log("Authenticate request completed");
26596
26899
  return {};
26597
26900
  }
26598
26901
  async logout(_params) {
26599
26902
  logger.log("Logout request received");
26600
26903
  await this.runWithProcessCheck(() => this.codexAcpClient.logout());
26904
+ await this.refreshSessionsAuthState(null);
26601
26905
  logger.log("Logout request completed");
26602
26906
  }
26907
+ async refreshSessionsAuthState(authProvider) {
26908
+ if (this.sessions.size === 0) return;
26909
+ const sessionsToRefresh = [...this.sessions.values()].filter((sessionState) => this.authProvidersMatch(sessionState.authProvider, authProvider));
26910
+ if (sessionsToRefresh.length === 0) return;
26911
+ const authState = await this.getAuthStateForProvider(authProvider);
26912
+ for (const sessionState of sessionsToRefresh) {
26913
+ sessionState.account = authState.account;
26914
+ sessionState.authConfigured = authState.authConfigured;
26915
+ }
26916
+ }
26603
26917
  async setSessionMode(_params) {
26604
26918
  logger.log("Set session mode requested", {
26605
26919
  sessionId: _params.sessionId,
@@ -26657,6 +26971,10 @@ You have been logged out. Please try again.`);
26657
26971
  applyModelChange(sessionState, value) {
26658
26972
  const model = sessionState.availableModels.find((m) => m.id === value);
26659
26973
  if (!model) {
26974
+ const currentModel = ModelId.fromString(sessionState.currentModelId).model;
26975
+ if (value === currentModel) {
26976
+ return;
26977
+ }
26660
26978
  throw RequestError.invalidParams();
26661
26979
  }
26662
26980
  const currentEffort = ModelId.fromString(sessionState.currentModelId).effort;
@@ -26715,12 +27033,17 @@ You have been logged out. Please try again.`);
26715
27033
  }
26716
27034
  createSessionConfigOptions(sessionState) {
26717
27035
  const currentModelId = ModelId.fromString(sessionState.currentModelId);
26718
- return [
27036
+ const configOptions = [
26719
27037
  sessionState.agentMode.toConfigOption(),
26720
- createModelConfigOption(sessionState.availableModels, currentModelId.model),
26721
- createReasoningEffortConfigOption(sessionState.supportedReasoningEfforts, currentModelId.effort),
26722
- createFastModeConfigOption(sessionState.fastModeEnabled)
27038
+ createModelConfigOption(sessionState.availableModels, currentModelId.model)
26723
27039
  ];
27040
+ if (sessionState.supportedReasoningEfforts.length > 0) {
27041
+ configOptions.push(
27042
+ createReasoningEffortConfigOption(sessionState.supportedReasoningEfforts, currentModelId.effort)
27043
+ );
27044
+ }
27045
+ configOptions.push(createFastModeConfigOption(sessionState.fastModeEnabled));
27046
+ return configOptions;
26724
27047
  }
26725
27048
  createSessionConfigOptionsResponse(sessionState) {
26726
27049
  if (!this.isSessionConfigEnabled()) {
@@ -26777,9 +27100,10 @@ You have been logged out. Please try again.`);
26777
27100
  throw err;
26778
27101
  }
26779
27102
  const { sessionId, currentModelId, models, thread } = sessionMetadata;
26780
- let account;
27103
+ const authProvider = sessionMetadata.modelProvider ?? this.codexAcpClient.getModelProvider();
27104
+ let authState;
26781
27105
  try {
26782
- account = await this.getActiveAccount();
27106
+ authState = await this.getAuthStateForProvider(authProvider);
26783
27107
  } catch (err) {
26784
27108
  if (subscribed) {
26785
27109
  await this.cleanupStaleSessionOpen(request.sessionId, requestedSessionGeneration);
@@ -26805,7 +27129,9 @@ You have been logged out. Please try again.`);
26805
27129
  totalTokenUsage: null,
26806
27130
  modelContextWindow: null,
26807
27131
  rateLimits: null,
26808
- account,
27132
+ account: authState.account,
27133
+ authConfigured: authState.authConfigured,
27134
+ authProvider,
26809
27135
  cwd: request.cwd,
26810
27136
  additionalDirectories: sessionMetadata.additionalDirectories,
26811
27137
  fastModeEnabled: sessionMetadata.currentServiceTier === "fast",
@@ -26881,7 +27207,7 @@ You have been logged out. Please try again.`);
26881
27207
  case "dynamicToolCall":
26882
27208
  return [await createDynamicToolCallUpdate(item)];
26883
27209
  case "collabAgentToolCall":
26884
- return [this.createCollabAgentToolCallUpdate(item)];
27210
+ return [createCollabAgentToolCallUpdate(item)];
26885
27211
  case "webSearch":
26886
27212
  return [this.createWebSearchUpdate(item)];
26887
27213
  case "imageView":
@@ -26918,22 +27244,6 @@ You have been logged out. Please try again.`);
26918
27244
  content: { type: "text", text }
26919
27245
  }));
26920
27246
  }
26921
- createCollabAgentToolCallUpdate(item) {
26922
- return {
26923
- sessionUpdate: "tool_call",
26924
- toolCallId: item.id,
26925
- kind: "other",
26926
- title: `collab.${item.tool}`,
26927
- status: this.toAcpToolCallStatus(item.status),
26928
- rawInput: {
26929
- prompt: item.prompt,
26930
- senderThreadId: item.senderThreadId,
26931
- receiverThreadIds: item.receiverThreadIds,
26932
- agentsStates: item.agentsStates,
26933
- status: item.status
26934
- }
26935
- };
26936
- }
26937
27247
  createWebSearchUpdate(item) {
26938
27248
  return {
26939
27249
  sessionUpdate: "tool_call",
@@ -26975,16 +27285,6 @@ ${item.text}`
26975
27285
  }
26976
27286
  };
26977
27287
  }
26978
- toAcpToolCallStatus(status) {
26979
- switch (status) {
26980
- case "inProgress":
26981
- return "in_progress";
26982
- case "completed":
26983
- return "completed";
26984
- case "failed":
26985
- return "failed";
26986
- }
26987
- }
26988
27288
  userInputToContentBlocks(input) {
26989
27289
  switch (input.type) {
26990
27290
  case "text":
@@ -27080,16 +27380,33 @@ ${item.text}`
27080
27380
  const closeSignal = new Promise((resolve) => {
27081
27381
  resolveCloseSignal = resolve;
27082
27382
  });
27383
+ let resolveCancelSignal = () => {
27384
+ };
27385
+ const cancelSignal = new Promise((resolve) => {
27386
+ resolveCancelSignal = resolve;
27387
+ });
27388
+ const abortController = new AbortController();
27083
27389
  let completed = false;
27084
27390
  let closeRequested = false;
27085
27391
  const activePrompt = {
27086
27392
  completion,
27087
27393
  closeSignal,
27394
+ cancelSignal,
27395
+ signal: abortController.signal,
27396
+ currentTurn: null,
27397
+ requestCancel: () => {
27398
+ if (abortController.signal.aborted) {
27399
+ return;
27400
+ }
27401
+ abortController.abort();
27402
+ resolveCancelSignal(null);
27403
+ },
27088
27404
  requestClose: () => {
27089
27405
  if (closeRequested) {
27090
27406
  return;
27091
27407
  }
27092
27408
  closeRequested = true;
27409
+ activePrompt.requestCancel();
27093
27410
  resolveCloseSignal(null);
27094
27411
  },
27095
27412
  complete: () => {
@@ -27106,6 +27423,40 @@ ${item.text}`
27106
27423
  this.activePrompts.set(sessionId, activePrompt);
27107
27424
  return activePrompt;
27108
27425
  }
27426
+ cancelBeforeTurnStarted(activePrompt) {
27427
+ return activePrompt.cancelSignal.then(() => {
27428
+ if (activePrompt.currentTurn === null) {
27429
+ return null;
27430
+ }
27431
+ return new Promise(() => {
27432
+ });
27433
+ });
27434
+ }
27435
+ observePromptRequestCancellation(signal, sessionState, activePrompt) {
27436
+ if (!signal) {
27437
+ return () => {
27438
+ };
27439
+ }
27440
+ const onAbort = () => {
27441
+ if (this.activePrompts.get(sessionState.sessionId) !== activePrompt) {
27442
+ return;
27443
+ }
27444
+ logger.log("Prompt request cancelled", { sessionId: sessionState.sessionId });
27445
+ activePrompt.requestCancel();
27446
+ const turn = activePrompt.currentTurn;
27447
+ if (!turn) {
27448
+ return;
27449
+ }
27450
+ void this.requestTurnInterrupt(turn, "Cancel");
27451
+ };
27452
+ if (signal.aborted) {
27453
+ onAbort();
27454
+ return () => {
27455
+ };
27456
+ }
27457
+ signal.addEventListener("abort", onAbort, { once: true });
27458
+ return () => signal.removeEventListener("abort", onAbort);
27459
+ }
27109
27460
  createPendingTurnStart() {
27110
27461
  let resolve = () => {
27111
27462
  };
@@ -27114,25 +27465,39 @@ ${item.text}`
27114
27465
  });
27115
27466
  return { promise: promise2, resolve };
27116
27467
  }
27117
- interruptLateStartedTurn(sessionId, turnId) {
27468
+ async interruptPromptTurn(turn, requestName) {
27118
27469
  this.codexAcpClient.markTurnStale({
27119
- threadId: sessionId,
27120
- turnId
27470
+ threadId: turn.threadId,
27471
+ turnId: turn.turnId
27121
27472
  });
27122
- void this.runWithProcessCheck(() => this.codexAcpClient.turnInterrupt({
27123
- threadId: sessionId,
27124
- turnId
27125
- })).catch((err) => {
27126
- logger.error(`Close - late turnInterrupt failed`, err);
27127
- }).finally(() => {
27473
+ try {
27474
+ await this.requestTurnInterrupt(turn, requestName);
27475
+ } finally {
27128
27476
  this.codexAcpClient.resolveTurnInterrupted({
27129
- threadId: sessionId,
27130
- turnId
27477
+ threadId: turn.threadId,
27478
+ turnId: turn.turnId
27131
27479
  });
27132
- });
27480
+ }
27481
+ }
27482
+ async requestTurnInterrupt(turn, requestName) {
27483
+ try {
27484
+ await this.runWithProcessCheck(() => this.codexAcpClient.turnInterrupt({
27485
+ threadId: turn.threadId,
27486
+ turnId: turn.turnId
27487
+ }));
27488
+ logger.log(`${requestName} - turnInterrupt succeeded`, {
27489
+ sessionId: turn.threadId,
27490
+ currentTurnId: turn.turnId
27491
+ });
27492
+ } catch (err) {
27493
+ logger.error(`${requestName} - turnInterrupt failed`, err);
27494
+ }
27133
27495
  }
27134
- promptIsClosedOrStale(sessionId, activePrompt) {
27135
- return this.activePrompts.get(sessionId) !== activePrompt || this.sessionIsClosing(sessionId);
27496
+ interruptLateStartedTurn(turn) {
27497
+ void this.interruptPromptTurn(turn, "Close");
27498
+ }
27499
+ promptShouldStop(sessionId, activePrompt) {
27500
+ return activePrompt.signal.aborted || this.activePrompts.get(sessionId) !== activePrompt || this.sessionIsClosing(sessionId);
27136
27501
  }
27137
27502
  async interruptSessionTurn(sessionState, requestName, resolveInterruptedTurn) {
27138
27503
  const turnId = await this.getInterruptibleTurnId(sessionState, requestName);
@@ -27188,7 +27553,7 @@ ${item.text}`
27188
27553
  }
27189
27554
  return turnId;
27190
27555
  }
27191
- async prompt(params) {
27556
+ async prompt(params, signal) {
27192
27557
  logger.log("Prompt received", {
27193
27558
  sessionId: params.sessionId,
27194
27559
  prompt: params.prompt
@@ -27198,10 +27563,11 @@ ${item.text}`
27198
27563
  sessionState.lastTokenUsage = null;
27199
27564
  const activePrompt = this.trackActivePrompt(params.sessionId);
27200
27565
  let pendingTurnStart = null;
27566
+ const disposePromptRequestCancellation = this.observePromptRequestCancellation(signal, sessionState, activePrompt);
27201
27567
  try {
27202
27568
  const eventHandler = new CodexEventHandler(this.connection, sessionState);
27203
- const approvalHandler = new CodexApprovalHandler(this.connection, sessionState);
27204
- const elicitationHandler = new CodexElicitationHandler(this.connection, sessionState);
27569
+ const approvalHandler = new CodexApprovalHandler(this.connection, sessionState, activePrompt.signal);
27570
+ const elicitationHandler = new CodexElicitationHandler(this.connection, sessionState, activePrompt.signal);
27205
27571
  await this.codexAcpClient.subscribeToSessionEvents(
27206
27572
  params.sessionId,
27207
27573
  (event) => {
@@ -27211,28 +27577,39 @@ ${item.text}`
27211
27577
  approvalHandler,
27212
27578
  elicitationHandler
27213
27579
  );
27214
- const commandResult = await this.availableCommands.tryHandleCommand(params.prompt, sessionState);
27580
+ if (activePrompt.signal.aborted) {
27581
+ return this.cancelledPromptResponse(sessionState);
27582
+ }
27583
+ const commandPromise = this.availableCommands.tryHandleCommand(params.prompt, sessionState, {
27584
+ onTurnStarted: (turnId, threadId) => {
27585
+ const turn = { threadId, turnId };
27586
+ activePrompt.currentTurn = turn;
27587
+ if (this.promptShouldStop(params.sessionId, activePrompt)) {
27588
+ this.interruptLateStartedTurn(turn);
27589
+ return;
27590
+ }
27591
+ sessionState.currentTurnId = turnId;
27592
+ }
27593
+ });
27594
+ void commandPromise.catch((err) => {
27595
+ if (this.activePrompts.get(params.sessionId) !== activePrompt) {
27596
+ logger.error(`Command for cancelled prompt ${params.sessionId} failed after prompt returned`, err);
27597
+ }
27598
+ });
27599
+ const commandResult = await Promise.race([
27600
+ commandPromise,
27601
+ activePrompt.closeSignal,
27602
+ this.cancelBeforeTurnStarted(activePrompt)
27603
+ ]);
27604
+ if (commandResult === null) {
27605
+ return this.cancelledPromptResponse(sessionState);
27606
+ }
27215
27607
  if (commandResult.handled) {
27216
27608
  logger.log("Prompt handled by a command");
27217
27609
  await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
27218
27610
  if (commandResult.turnCompleted?.turn.status === "interrupted") {
27219
- if (!this.sessionIsClosing(params.sessionId) && this.sessions.has(params.sessionId)) {
27220
- await this.connection.notify(methods.client.session.update, {
27221
- sessionId: params.sessionId,
27222
- update: {
27223
- sessionUpdate: "agent_message_chunk",
27224
- content: {
27225
- type: "text",
27226
- text: "*Conversation interrupted*"
27227
- }
27228
- }
27229
- });
27230
- }
27231
- return {
27232
- stopReason: "cancelled",
27233
- usage: this.buildPromptUsage(sessionState.lastTokenUsage),
27234
- _meta: this.buildQuotaMeta(sessionState)
27235
- };
27611
+ await this.notifyConversationInterrupted(params.sessionId);
27612
+ return this.cancelledPromptResponse(sessionState);
27236
27613
  }
27237
27614
  const error52 = eventHandler.getFailure();
27238
27615
  if (error52) {
@@ -27245,11 +27622,7 @@ ${item.text}`
27245
27622
  };
27246
27623
  }
27247
27624
  if (this.sessionIsClosing(params.sessionId)) {
27248
- return {
27249
- stopReason: "cancelled",
27250
- usage: this.buildPromptUsage(sessionState.lastTokenUsage),
27251
- _meta: this.buildQuotaMeta(sessionState)
27252
- };
27625
+ return this.cancelledPromptResponse(sessionState);
27253
27626
  }
27254
27627
  const modelId = ModelId.fromString(sessionState.currentModelId);
27255
27628
  const modelLacksReasoning = sessionState.supportedReasoningEfforts.length > 0 && sessionState.supportedReasoningEfforts.every((e) => e.reasoningEffort === "none");
@@ -27280,51 +27653,35 @@ ${item.text}`
27280
27653
  sessionState.cwd,
27281
27654
  sessionState.additionalDirectories,
27282
27655
  (turnId) => {
27283
- if (this.promptIsClosedOrStale(params.sessionId, activePrompt)) {
27284
- this.interruptLateStartedTurn(params.sessionId, turnId);
27656
+ const turn = { threadId: params.sessionId, turnId };
27657
+ activePrompt.currentTurn = turn;
27658
+ if (this.promptShouldStop(params.sessionId, activePrompt)) {
27659
+ this.interruptLateStartedTurn(turn);
27285
27660
  return;
27286
27661
  }
27287
27662
  sessionState.currentTurnId = turnId;
27288
27663
  pendingTurnStart?.resolve(turnId);
27289
27664
  },
27290
- () => this.promptIsClosedOrStale(params.sessionId, activePrompt)
27665
+ () => this.promptShouldStop(params.sessionId, activePrompt)
27291
27666
  )
27292
27667
  );
27293
27668
  void sendPromptPromise.catch((err) => {
27294
27669
  if (this.activePrompts.get(params.sessionId) !== activePrompt) {
27295
- logger.error(`Prompt for closed session ${params.sessionId} failed after close`, err);
27670
+ logger.error(`Prompt for cancelled session ${params.sessionId} failed after prompt returned`, err);
27296
27671
  }
27297
27672
  });
27298
27673
  const turnCompleted = await Promise.race([
27299
27674
  sendPromptPromise,
27300
- activePrompt.closeSignal
27675
+ activePrompt.closeSignal,
27676
+ this.cancelBeforeTurnStarted(activePrompt)
27301
27677
  ]);
27302
27678
  if (turnCompleted === null) {
27303
- return {
27304
- stopReason: "cancelled",
27305
- usage: this.buildPromptUsage(sessionState.lastTokenUsage),
27306
- _meta: this.buildQuotaMeta(sessionState)
27307
- };
27679
+ return this.cancelledPromptResponse(sessionState);
27308
27680
  }
27309
27681
  await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
27310
27682
  if (turnCompleted.turn.status === "interrupted") {
27311
- if (!this.sessionIsClosing(params.sessionId) && this.sessions.has(params.sessionId)) {
27312
- await this.connection.notify(methods.client.session.update, {
27313
- sessionId: params.sessionId,
27314
- update: {
27315
- sessionUpdate: "agent_message_chunk",
27316
- content: {
27317
- type: "text",
27318
- text: "*Conversation interrupted*"
27319
- }
27320
- }
27321
- });
27322
- }
27323
- return {
27324
- stopReason: "cancelled",
27325
- usage: this.buildPromptUsage(sessionState.lastTokenUsage),
27326
- _meta: this.buildQuotaMeta(sessionState)
27327
- };
27683
+ await this.notifyConversationInterrupted(params.sessionId);
27684
+ return this.cancelledPromptResponse(sessionState);
27328
27685
  }
27329
27686
  const error51 = eventHandler.getFailure();
27330
27687
  if (error51) {
@@ -27340,6 +27697,7 @@ ${item.text}`
27340
27697
  throw err;
27341
27698
  } finally {
27342
27699
  logger.log("Prompt completed", { sessionId: params.sessionId });
27700
+ disposePromptRequestCancellation();
27343
27701
  sessionState.currentTurnId = null;
27344
27702
  if (pendingTurnStart !== null && this.pendingTurnStarts.get(params.sessionId) === pendingTurnStart) {
27345
27703
  this.pendingTurnStarts.delete(params.sessionId);
@@ -27348,6 +27706,28 @@ ${item.text}`
27348
27706
  activePrompt.complete();
27349
27707
  }
27350
27708
  }
27709
+ cancelledPromptResponse(sessionState) {
27710
+ return {
27711
+ stopReason: "cancelled",
27712
+ usage: this.buildPromptUsage(sessionState.lastTokenUsage),
27713
+ _meta: this.buildQuotaMeta(sessionState)
27714
+ };
27715
+ }
27716
+ async notifyConversationInterrupted(sessionId) {
27717
+ if (this.sessionIsClosing(sessionId) || !this.sessions.has(sessionId)) {
27718
+ return;
27719
+ }
27720
+ await this.connection.notify(methods.client.session.update, {
27721
+ sessionId,
27722
+ update: {
27723
+ sessionUpdate: "agent_message_chunk",
27724
+ content: {
27725
+ type: "text",
27726
+ text: "*Conversation interrupted*"
27727
+ }
27728
+ }
27729
+ });
27730
+ }
27351
27731
  buildQuotaMeta(sessionState) {
27352
27732
  const lastTokenUsage = sessionState.lastTokenUsage;
27353
27733
  const modelName = sessionState.currentModelId.replace(/\[.*?]$/, "");
@@ -27583,7 +27963,7 @@ var CodexAppServerClient = class {
27583
27963
  });
27584
27964
  try {
27585
27965
  const reviewStarted = await this.reviewStart(params);
27586
- onTurnStarted?.(reviewStarted.turn.id);
27966
+ onTurnStarted?.(reviewStarted.turn.id, reviewStarted.reviewThreadId);
27587
27967
  const earlyCompletion = capturedCompletions.find((event) => event.turn.id === reviewStarted.turn.id);
27588
27968
  releaseCapture();
27589
27969
  if (earlyCompletion) {
@@ -28075,7 +28455,7 @@ function startAcpServer() {
28075
28455
  codexConnection.process.stderr.addListener("data", (data) => {
28076
28456
  stderr = (stderr + data.toString()).slice(-maxStderrTailChars);
28077
28457
  });
28078
- process.stdin.on("close", (chunk) => {
28458
+ process.stdin.on("close", () => {
28079
28459
  codexConnection.process.stdin.end();
28080
28460
  setTimeout(() => {
28081
28461
  if (!codexConnection.process.killed) {
@@ -28105,5 +28485,5 @@ function startAcpServer() {
28105
28485
  codexAcpServer = null;
28106
28486
  }
28107
28487
  });
28108
- }).onRequest(methods.agent.initialize, (ctx) => getAgent().initialize(ctx.params)).onRequest(methods.agent.session.new, (ctx) => getAgent().newSession(ctx.params)).onRequest(methods.agent.session.load, (ctx) => getAgent().loadSession(ctx.params)).onRequest(methods.agent.session.list, (ctx) => getAgent().listSessions(ctx.params)).onRequest(methods.agent.session.delete, (ctx) => getAgent().deleteSession(ctx.params)).onRequest(methods.agent.session.resume, (ctx) => getAgent().resumeSession(ctx.params)).onRequest(methods.agent.session.close, (ctx) => getAgent().closeSession(ctx.params)).onRequest(methods.agent.session.setMode, (ctx) => getAgent().setSessionMode(ctx.params)).onRequest(methods.agent.session.setConfigOption, (ctx) => getAgent().setSessionConfigOption(ctx.params)).onRequest(methods.agent.authenticate, (ctx) => getAgent().authenticate(ctx.params)).onRequest(methods.agent.logout, (ctx) => getAgent().logout(ctx.params)).onRequest(methods.agent.session.prompt, (ctx) => getAgent().prompt(ctx.params)).onNotification(methods.agent.session.cancel, (ctx) => getAgent().cancel(ctx.params)).onRequest("authentication/status", emptyExtensionParamsParser, (ctx) => getAgent().extMethod("authentication/status", ctx.params)).onRequest("authentication/logout", emptyExtensionParamsParser, (ctx) => getAgent().extMethod("authentication/logout", ctx.params)).onRequest(LEGACY_SET_SESSION_MODEL_METHOD, legacySetSessionModelParamsParser, (ctx) => getAgent().extMethod(LEGACY_SET_SESSION_MODEL_METHOD, ctx.params)).connect(acpJsonStream);
28488
+ }).onRequest(methods.agent.initialize, (ctx) => getAgent().initialize(ctx.params)).onRequest(methods.agent.session.new, (ctx) => getAgent().newSession(ctx.params)).onRequest(methods.agent.session.load, (ctx) => getAgent().loadSession(ctx.params)).onRequest(methods.agent.session.list, (ctx) => getAgent().listSessions(ctx.params)).onRequest(methods.agent.session.delete, (ctx) => getAgent().deleteSession(ctx.params)).onRequest(methods.agent.session.resume, (ctx) => getAgent().resumeSession(ctx.params)).onRequest(methods.agent.session.close, (ctx) => getAgent().closeSession(ctx.params)).onRequest(methods.agent.session.setMode, (ctx) => getAgent().setSessionMode(ctx.params)).onRequest(methods.agent.session.setConfigOption, (ctx) => getAgent().setSessionConfigOption(ctx.params)).onRequest(methods.agent.authenticate, (ctx) => getAgent().authenticate(ctx.params)).onRequest(methods.agent.logout, (ctx) => getAgent().logout(ctx.params)).onRequest(methods.agent.session.prompt, (ctx) => getAgent().prompt(ctx.params, ctx.signal)).onNotification(methods.agent.session.cancel, (ctx) => getAgent().cancel(ctx.params)).onRequest("authentication/status", emptyExtensionParamsParser, (ctx) => getAgent().extMethod("authentication/status", ctx.params)).onRequest("authentication/logout", emptyExtensionParamsParser, (ctx) => getAgent().extMethod("authentication/logout", ctx.params)).onRequest(LEGACY_SET_SESSION_MODEL_METHOD, legacySetSessionModelParamsParser, (ctx) => getAgent().extMethod(LEGACY_SET_SESSION_MODEL_METHOD, ctx.params)).connect(acpJsonStream);
28109
28489
  }