@agentclientprotocol/codex-acp 1.1.8 → 1.1.9

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 +90 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23582,8 +23582,8 @@ function sameThreadGoalSnapshot(left, right) {
23582
23582
  }
23583
23583
 
23584
23584
  // src/CodexEventHandler.ts
23585
- var CodexEventHandler = class {
23586
- connection;
23585
+ var CodexEventHandler = class _CodexEventHandler {
23586
+ static PLAN_UPDATE_INTERVAL_MS = 150;
23587
23587
  sessionState;
23588
23588
  supportsPlanUpdates;
23589
23589
  failure = null;
@@ -23593,15 +23593,21 @@ var CodexEventHandler = class {
23593
23593
  activeImageGenerationItems = /* @__PURE__ */ new Set();
23594
23594
  emittedImageViewItems = /* @__PURE__ */ new Set();
23595
23595
  planDeltaTextByItemId = /* @__PURE__ */ new Map();
23596
+ pendingPlanItemIds = /* @__PURE__ */ new Set();
23597
+ lastEmittedPlanTextByItemId = /* @__PURE__ */ new Map();
23598
+ session;
23599
+ planUpdateTimer = null;
23600
+ planUpdateChain = Promise.resolve();
23601
+ disposed = false;
23596
23602
  seenReasoningDeltaItemIds = /* @__PURE__ */ new Set();
23597
23603
  terminalCommandIds = /* @__PURE__ */ new Set();
23598
23604
  terminalCommandOutputIds = /* @__PURE__ */ new Set();
23599
23605
  agentMessagePhases = /* @__PURE__ */ new Map();
23600
23606
  activeSubAgentActivities = /* @__PURE__ */ new Set();
23601
23607
  constructor(connection, sessionState, supportsPlanUpdates = false) {
23602
- this.connection = connection;
23603
23608
  this.sessionState = sessionState;
23604
23609
  this.supportsPlanUpdates = supportsPlanUpdates;
23610
+ this.session = new ACPSessionConnection(connection, sessionState.sessionId);
23605
23611
  }
23606
23612
  getFailure() {
23607
23613
  return this.failure;
@@ -23612,12 +23618,32 @@ var CodexEventHandler = class {
23612
23618
  return plan;
23613
23619
  }
23614
23620
  async handleNotification(notification) {
23615
- const session = new ACPSessionConnection(this.connection, this.sessionState.sessionId);
23616
23621
  const updateEvent = await this.createUpdateEvent(notification);
23617
23622
  if (updateEvent) {
23618
- await session.update(updateEvent);
23623
+ await this.session.update(updateEvent);
23619
23624
  }
23620
23625
  }
23626
+ async flushPendingPlanUpdates() {
23627
+ this.cancelPlanUpdateTimer();
23628
+ do {
23629
+ const itemIds = [...this.pendingPlanItemIds];
23630
+ this.pendingPlanItemIds.clear();
23631
+ await Promise.all(itemIds.map((itemId) => {
23632
+ const text = this.planDeltaTextByItemId.get(itemId) ?? "";
23633
+ return text.length > 0 ? this.enqueuePlanSnapshot(itemId, text) : Promise.resolve();
23634
+ }));
23635
+ await this.planUpdateChain;
23636
+ } while (this.pendingPlanItemIds.size > 0);
23637
+ }
23638
+ async dispose() {
23639
+ if (this.disposed) return;
23640
+ await this.flushPendingPlanUpdates();
23641
+ this.disposed = true;
23642
+ this.cancelPlanUpdateTimer();
23643
+ this.pendingPlanItemIds.clear();
23644
+ this.planDeltaTextByItemId.clear();
23645
+ this.lastEmittedPlanTextByItemId.clear();
23646
+ }
23621
23647
  async createUpdateEvent(notification) {
23622
23648
  switch (notification.method) {
23623
23649
  case "item/agentMessage/delta":
@@ -23636,6 +23662,8 @@ var CodexEventHandler = class {
23636
23662
  this.sessionState.currentTurnId = notification.params.turn.id;
23637
23663
  return null;
23638
23664
  case "turn/completed":
23665
+ await this.flushPendingPlanUpdates();
23666
+ this.clearPlanTurnState();
23639
23667
  this.sessionState.currentTurnId = null;
23640
23668
  return null;
23641
23669
  case "thread/tokenUsage/updated":
@@ -23806,7 +23834,11 @@ ${event.details}` : "";
23806
23834
  const text = this.planDeltaTextByItemId.get(event.itemId) ?? "";
23807
23835
  const updatedText = text + event.delta;
23808
23836
  this.planDeltaTextByItemId.set(event.itemId, updatedText);
23809
- return this.supportsPlanUpdates ? this.createPlanUpdateEvent(updatedText, event.itemId) : null;
23837
+ if (this.supportsPlanUpdates) {
23838
+ this.pendingPlanItemIds.add(event.itemId);
23839
+ this.schedulePlanUpdate();
23840
+ }
23841
+ return null;
23810
23842
  }
23811
23843
  createReasoningSectionBreakEvent(event) {
23812
23844
  this.seenReasoningDeltaItemIds.add(event.itemId);
@@ -23903,8 +23935,7 @@ ${event.details}` : "";
23903
23935
  return null;
23904
23936
  case "plan": {
23905
23937
  const deltaText = this.planDeltaTextByItemId.get(event.item.id) ?? "";
23906
- this.planDeltaTextByItemId.delete(event.item.id);
23907
- return this.createCompletedPlanEvent(event.item, deltaText);
23938
+ return await this.createCompletedPlanEvent(event.item, deltaText);
23908
23939
  }
23909
23940
  case "exitedReviewMode":
23910
23941
  return this.createExitedReviewModeEvent(event.item);
@@ -23933,13 +23964,53 @@ ${event.details}` : "";
23933
23964
  }
23934
23965
  return this.createAgentThoughtEvent(text, item.id);
23935
23966
  }
23936
- createCompletedPlanEvent(item, deltaText) {
23967
+ async createCompletedPlanEvent(item, deltaText) {
23937
23968
  const text = item.text.length > 0 ? item.text : deltaText;
23969
+ this.pendingPlanItemIds.delete(item.id);
23970
+ if (this.pendingPlanItemIds.size === 0) {
23971
+ this.cancelPlanUpdateTimer();
23972
+ }
23973
+ this.planDeltaTextByItemId.delete(item.id);
23938
23974
  if (text.length === 0) {
23939
23975
  return null;
23940
23976
  }
23941
23977
  this.completedPlan = { itemId: item.id, text };
23942
- return this.supportsPlanUpdates ? this.createPlanUpdateEvent(text, item.id) : this.createPlanTextEvent(text, item.id);
23978
+ if (this.supportsPlanUpdates) {
23979
+ await this.enqueuePlanSnapshot(item.id, text);
23980
+ return null;
23981
+ }
23982
+ return this.createPlanTextEvent(text, item.id);
23983
+ }
23984
+ schedulePlanUpdate() {
23985
+ if (this.disposed || this.planUpdateTimer !== null) return;
23986
+ this.planUpdateTimer = setTimeout(() => {
23987
+ this.planUpdateTimer = null;
23988
+ void this.flushPendingPlanUpdates().catch((error51) => {
23989
+ logger.error("Failed to flush throttled plan updates", error51);
23990
+ });
23991
+ }, _CodexEventHandler.PLAN_UPDATE_INTERVAL_MS);
23992
+ }
23993
+ cancelPlanUpdateTimer() {
23994
+ if (this.planUpdateTimer === null) return;
23995
+ clearTimeout(this.planUpdateTimer);
23996
+ this.planUpdateTimer = null;
23997
+ }
23998
+ enqueuePlanSnapshot(itemId, text) {
23999
+ const send = async () => {
24000
+ if (this.lastEmittedPlanTextByItemId.get(itemId) === text) return;
24001
+ await this.session.update(this.createPlanUpdateEvent(text, itemId));
24002
+ this.lastEmittedPlanTextByItemId.set(itemId, text);
24003
+ };
24004
+ const result = this.planUpdateChain.then(send);
24005
+ this.planUpdateChain = result.catch(() => {
24006
+ });
24007
+ return result;
24008
+ }
24009
+ clearPlanTurnState() {
24010
+ this.cancelPlanUpdateTimer();
24011
+ this.pendingPlanItemIds.clear();
24012
+ this.planDeltaTextByItemId.clear();
24013
+ this.lastEmittedPlanTextByItemId.clear();
23943
24014
  }
23944
24015
  createPlanUpdateEvent(text, planId) {
23945
24016
  return {
@@ -26065,7 +26136,7 @@ var package_default = {
26065
26136
  publishConfig: {
26066
26137
  access: "public"
26067
26138
  },
26068
- version: "1.1.8",
26139
+ version: "1.1.9",
26069
26140
  description: "",
26070
26141
  main: "dist/index.js",
26071
26142
  bin: {
@@ -30035,12 +30106,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
30035
30106
  return pendingTurnStart;
30036
30107
  };
30037
30108
  const disposePromptRequestCancellation = this.observePromptRequestCancellation(signal, sessionState, activePrompt);
30109
+ let eventHandler = null;
30038
30110
  try {
30039
- const eventHandler = new CodexEventHandler(
30111
+ const promptEventHandler = new CodexEventHandler(
30040
30112
  this.connection,
30041
30113
  sessionState,
30042
30114
  clientSupportsPlanUpdates(this.clientCapabilities)
30043
30115
  );
30116
+ eventHandler = promptEventHandler;
30044
30117
  const approvalHandler = new CodexApprovalHandler(this.connection, sessionState, activePrompt.signal);
30045
30118
  const elicitationHandler = new CodexElicitationHandler(
30046
30119
  this.connection,
@@ -30052,7 +30125,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
30052
30125
  params.sessionId,
30053
30126
  async (event) => {
30054
30127
  await elicitationHandler.handleNotification(event);
30055
- return eventHandler.handleNotification(event);
30128
+ return promptEventHandler.handleNotification(event);
30056
30129
  },
30057
30130
  approvalHandler,
30058
30131
  elicitationHandler
@@ -30177,6 +30250,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
30177
30250
  }
30178
30251
  await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
30179
30252
  if (turnCompleted.turn.status === "interrupted") {
30253
+ await eventHandler.flushPendingPlanUpdates();
30180
30254
  await this.notifyConversationInterrupted(params.sessionId);
30181
30255
  return this.cancelledPromptResponse(sessionState);
30182
30256
  }
@@ -30184,6 +30258,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
30184
30258
  if (error51) {
30185
30259
  throw error51;
30186
30260
  }
30261
+ await eventHandler.flushPendingPlanUpdates();
30187
30262
  const completedPlan = eventHandler.takeCompletedPlan();
30188
30263
  if (completedPlan !== null && sessionState.collaborationMode === PLAN_COLLABORATION_MODE && !this.promptShouldStop(params.sessionId, activePrompt)) {
30189
30264
  const approved = await this.requestPlanImplementationPermission(
@@ -30242,6 +30317,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
30242
30317
  }
30243
30318
  await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
30244
30319
  if (turnCompleted.turn.status === "interrupted") {
30320
+ await eventHandler.flushPendingPlanUpdates();
30245
30321
  await this.notifyConversationInterrupted(params.sessionId);
30246
30322
  return this.cancelledPromptResponse(sessionState);
30247
30323
  }
@@ -30265,6 +30341,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
30265
30341
  throw err;
30266
30342
  } finally {
30267
30343
  logger.log("Prompt completed", { sessionId: params.sessionId });
30344
+ await eventHandler?.dispose();
30268
30345
  disposePromptRequestCancellation();
30269
30346
  sessionState.currentTurnId = null;
30270
30347
  const registeredPendingTurnStart = this.pendingTurnStarts.get(params.sessionId);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.1.8",
6
+ "version": "1.1.9",
7
7
  "description": "",
8
8
  "main": "dist/index.js",
9
9
  "bin": {