@agentclientprotocol/codex-acp 2.5.1-preview.11 → 2.5.1-preview.13

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 +74 -40
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -31968,6 +31968,9 @@ var AIR_CUSTOM_ANSWER_KEY = "customAnswer";
31968
31968
  var LEGACY_AIR_CUSTOM_ANSWER_KEY = "_askUserQuestionCustomAnswer";
31969
31969
  var AIR_EXTENSION_VERSION = 1;
31970
31970
  function withAirMeta(meta3, key, value) {
31971
+ return withAirMetadata(meta3, { [key]: value });
31972
+ }
31973
+ function withAirMetadata(meta3, fields) {
31971
31974
  const root = asRecord(meta3);
31972
31975
  const jetbrains = asRecord(root[JETBRAINS_META_KEY]);
31973
31976
  const air = asRecord(jetbrains[AIR_META_KEY]);
@@ -31978,11 +31981,19 @@ function withAirMeta(meta3, key, value) {
31978
31981
  [AIR_META_KEY]: {
31979
31982
  ...air,
31980
31983
  [AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
31981
- [key]: value
31984
+ ...fields
31982
31985
  }
31983
31986
  }
31984
31987
  };
31985
31988
  }
31989
+ function publishAirSessionMetadata(session, key, value) {
31990
+ if (session.protocolVersion === 2) {
31991
+ return session.patchSessionMetadata((current) => ({
31992
+ [JETBRAINS_META_KEY]: withAirMeta(current, key, value)[JETBRAINS_META_KEY]
31993
+ }));
31994
+ }
31995
+ return session.update({ sessionUpdate: "session_info_update", _meta: withAirMeta(void 0, key, value) });
31996
+ }
31986
31997
  function airOnlyMeta(airClient, key, value) {
31987
31998
  return airClient ? withAirMeta(void 0, key, value) : void 0;
31988
31999
  }
@@ -32238,12 +32249,13 @@ var AcpV2SessionInfo = class {
32238
32249
  await this.publish(copy.update, copy._meta);
32239
32250
  });
32240
32251
  }
32241
- patchMetadata(change) {
32252
+ patchMetadata(change, fields = {}) {
32253
+ const copy = JSON.parse(JSON.stringify(fields));
32242
32254
  return this.enqueue(async () => {
32243
32255
  const current = JSON.parse(JSON.stringify(Object.fromEntries(this.metadata)));
32244
32256
  const patch = change(current);
32245
32257
  if (patch === null) return;
32246
- const update = JSON.parse(JSON.stringify({ sessionUpdate: "session_info_update", _meta: patch }));
32258
+ const update = JSON.parse(JSON.stringify({ ...copy, sessionUpdate: "session_info_update", _meta: patch }));
32247
32259
  this.applyMetadata(update._meta);
32248
32260
  await this.publish(update);
32249
32261
  });
@@ -32921,8 +32933,8 @@ var AcpV2Connection = class {
32921
32933
  snapshotSessionInfo(sessionId, title) {
32922
32934
  return this.sessionInfoFor(sessionId).snapshot(title);
32923
32935
  }
32924
- patchSessionMetadata(sessionId, change) {
32925
- return this.sessionInfoFor(sessionId).patchMetadata(change);
32936
+ patchSessionMetadata(sessionId, change, fields = {}) {
32937
+ return this.sessionInfoFor(sessionId).patchMetadata(change, fields);
32926
32938
  }
32927
32939
  startForegroundItem(sessionId, itemId) {
32928
32940
  return this.foregroundFor(sessionId).startItem(itemId);
@@ -32934,11 +32946,14 @@ var AcpV2Connection = class {
32934
32946
  this.foregroundFor(sessionId, running);
32935
32947
  }
32936
32948
  forgetSession(sessionId) {
32937
- this.foreground.get(sessionId)?.dispose();
32938
- this.foreground.delete(sessionId);
32949
+ this.forgetForegroundState(sessionId);
32939
32950
  this.sessionInfo.get(sessionId)?.dispose();
32940
32951
  this.sessionInfo.delete(sessionId);
32941
32952
  }
32953
+ forgetForegroundState(sessionId) {
32954
+ this.foreground.get(sessionId)?.dispose();
32955
+ this.foreground.delete(sessionId);
32956
+ }
32942
32957
  sessionInfoFor(sessionId, metadata = null) {
32943
32958
  if (this.sessionDelivery && !this.sessionDelivery.canPublishSession(sessionId)) {
32944
32959
  const closed = new AcpV2SessionInfo(async () => {
@@ -33118,8 +33133,8 @@ var ACPSessionConnection = class _ACPSessionConnection {
33118
33133
  return new _ACPSessionConnection(this.connection, sessionId);
33119
33134
  }
33120
33135
  /** Domain writers can rebuild an owned metadata value without changing v2's shallow patch semantics. */
33121
- patchSessionMetadata(change) {
33122
- return this.v2Connection?.patchSessionMetadata(this.sessionId, change) ?? Promise.resolve();
33136
+ patchSessionMetadata(change, fields = {}) {
33137
+ return this.v2Connection?.patchSessionMetadata(this.sessionId, change, fields) ?? Promise.resolve();
33123
33138
  }
33124
33139
  /** Replay shares live report filtering, with v2 entity initialization after conversion. */
33125
33140
  replayUpdate(update, initialized) {
@@ -35303,6 +35318,9 @@ function goalSessionInfoUpdate(goal, airClient) {
35303
35318
  _meta: withAirMeta(void 0, AIR_GOAL_KEY, goal)
35304
35319
  };
35305
35320
  }
35321
+ function publishGoalSessionInfo(session, goal, airClient) {
35322
+ return airClient ? publishAirSessionMetadata(session, AIR_GOAL_KEY, goal) : Promise.resolve();
35323
+ }
35306
35324
 
35307
35325
  // src/tool-calls/ClientCapabilities.ts
35308
35326
  var ClientCapabilities = class _ClientCapabilities {
@@ -37848,7 +37866,7 @@ ${diff}`, "");
37848
37866
  await this.finishCompactionsForNotification(notification);
37849
37867
  if (this.isAuthenticationRequiredError(notification.params.error.codexErrorInfo)) return;
37850
37868
  if (notification.params.willRetry) {
37851
- await this.session.update(this.createSessionFailureUpdate(this.recordRetryWarning(notification.params, false)));
37869
+ await this.publishUpdate(this.createSessionFailureUpdate(this.recordRetryWarning(notification.params, false)));
37852
37870
  return;
37853
37871
  }
37854
37872
  const failure3 = this.recordSessionFailure(
@@ -37859,7 +37877,7 @@ ${diff}`, "");
37859
37877
  void 0,
37860
37878
  false
37861
37879
  );
37862
- await this.session.update(this.createSessionFailureUpdate(failure3));
37880
+ await this.publishUpdate(this.createSessionFailureUpdate(failure3));
37863
37881
  }
37864
37882
  async flushPendingErrors() {
37865
37883
  if (this.sessionState.currentTurnId === null || this.pendingErrors.length === 0) {
@@ -37869,7 +37887,7 @@ ${diff}`, "");
37869
37887
  for (const error62 of errors) {
37870
37888
  const update = await this.createErrorEvent(error62);
37871
37889
  if (update) {
37872
- await this.session.update(update);
37890
+ await this.publishUpdate(update);
37873
37891
  }
37874
37892
  }
37875
37893
  }
@@ -37980,7 +37998,7 @@ ${diff}`, "");
37980
37998
  if (ignoredBySubagents) return;
37981
37999
  if (updateEvent === void 0) updateEvent = await this.createUpdateEvent(notification);
37982
38000
  if (updateEvent) {
37983
- await this.session.update(updateEvent, this.subagents.notificationSessionId(notification));
38001
+ await this.publishUpdate(updateEvent, this.subagents.notificationSessionId(notification));
37984
38002
  }
37985
38003
  }
37986
38004
  async waitForNativeSubagentSession(childThreadId) {
@@ -38259,6 +38277,21 @@ ${params.turnId}`;
38259
38277
  return null;
38260
38278
  }
38261
38279
  }
38280
+ /** These fact builders produce partial owned namespaces, unlike raw metadata patches. */
38281
+ publishUpdate(update, sessionId = this.sessionState.sessionId) {
38282
+ if (this.session.protocolVersion !== 2 || update.sessionUpdate !== "session_info_update" || update._meta == null) {
38283
+ return this.session.update(update, sessionId);
38284
+ }
38285
+ const { _meta, sessionUpdate: _tag, ...fields } = update;
38286
+ return this.session.forSession(sessionId).patchSessionMetadata((current) => {
38287
+ const metadata = { ..._meta };
38288
+ const codex = recordOrNull(_meta["codex"]);
38289
+ if (codex) metadata["codex"] = { ...recordOrNull(current["codex"]), ...codex };
38290
+ const air = recordOrNull(recordOrNull(_meta[JETBRAINS_META_KEY])?.[AIR_META_KEY]);
38291
+ if (air) metadata[JETBRAINS_META_KEY] = withAirMetadata(current, air)[JETBRAINS_META_KEY];
38292
+ return metadata;
38293
+ }, fields);
38294
+ }
38262
38295
  createCodexSessionInfoUpdate(codexMetadata) {
38263
38296
  return {
38264
38297
  sessionUpdate: "session_info_update",
@@ -41223,7 +41256,7 @@ var package_default = {
41223
41256
  publishConfig: {
41224
41257
  access: "public"
41225
41258
  },
41226
- version: "2.5.1-preview.11",
41259
+ version: "2.5.1-preview.13",
41227
41260
  description: "",
41228
41261
  main: "dist/index.js",
41229
41262
  bin: {
@@ -49453,10 +49486,7 @@ var SessionIndexService = class {
49453
49486
  }
49454
49487
  });
49455
49488
  if (archived ? open3 : this.host.session(sessionId) !== void 0) {
49456
- await new ACPSessionConnection(this.host.connection(), sessionId).update({
49457
- sessionUpdate: "session_info_update",
49458
- _meta: withAirMeta(void 0, AIR_ARCHIVED_KEY, archived)
49459
- });
49489
+ await publishAirSessionMetadata(new ACPSessionConnection(this.host.connection(), sessionId), AIR_ARCHIVED_KEY, archived);
49460
49490
  }
49461
49491
  } finally {
49462
49492
  if (archived) this.host.endSessionCloseFence(sessionId);
@@ -50683,7 +50713,7 @@ You have been logged out. Please try again.`);
50683
50713
  endSessionCloseFence(sessionId) {
50684
50714
  const fence = this.closingSessions.get(sessionId);
50685
50715
  if (!fence || --fence.count > 0) return;
50686
- for (const closed of fence.closedSessions) this.clientDelivery.closeSession(closed);
50716
+ for (const closed of fence.closedSessions) this.sealSessionDelivery(closed);
50687
50717
  this.closingSessions.delete(sessionId);
50688
50718
  }
50689
50719
  /** Nested operations such as archive may still owe their final metadata update. */
@@ -50691,9 +50721,13 @@ You have been logged out. Please try again.`);
50691
50721
  const fence = this.closingSessions.get(sessionId);
50692
50722
  for (const closed of [sessionId, ...children]) {
50693
50723
  if (fence) fence.closedSessions.add(closed);
50694
- else this.clientDelivery.closeSession(closed);
50724
+ else this.sealSessionDelivery(closed);
50695
50725
  }
50696
50726
  }
50727
+ sealSessionDelivery(sessionId) {
50728
+ this.clientDelivery.closeSession(sessionId);
50729
+ AcpV2Connection.of(this.connection)?.forgetSession(sessionId);
50730
+ }
50697
50731
  getSessionGeneration(sessionId) {
50698
50732
  return this.sessionGenerations.get(sessionId) ?? 0;
50699
50733
  }
@@ -51420,7 +51454,7 @@ You have been logged out. Please try again.`);
51420
51454
  this.sessions.delete(params.sessionId);
51421
51455
  this.asyncQuestions.get(params.sessionId)?.dispose();
51422
51456
  this.asyncQuestions.delete(params.sessionId);
51423
- AcpV2Connection.of(this.connection)?.forgetSession(params.sessionId);
51457
+ AcpV2Connection.of(this.connection)?.forgetForegroundState(params.sessionId);
51424
51458
  this.mcpSessionStartup.close(params.sessionId);
51425
51459
  this.codexAcpClient.appServerClient.mcpStartup.forgetThread(params.sessionId);
51426
51460
  this.pendingTurnStarts.delete(params.sessionId);
@@ -52493,9 +52527,11 @@ You have been logged out. Please try again.`);
52493
52527
  return;
52494
52528
  }
52495
52529
  sessionState.currentGoal = snapshot;
52496
- const update = goalSessionInfoUpdate(snapshot, sessionState.clientCapabilities.airClient);
52497
- if (update === null) return;
52498
- await new ACPSessionConnection(this.connection, sessionState.sessionId).update(update);
52530
+ await publishGoalSessionInfo(
52531
+ new ACPSessionConnection(this.connection, sessionState.sessionId),
52532
+ snapshot,
52533
+ sessionState.clientCapabilities.airClient
52534
+ );
52499
52535
  }
52500
52536
  /** The models of a root session, for the configuration of its native subagent sessions. */
52501
52537
  subagentModels(sessionState) {
@@ -53004,17 +53040,7 @@ You have been logged out. Please try again.`);
53004
53040
  }
53005
53041
  try {
53006
53042
  const session = new ACPSessionConnection(this.connection, sessionState.sessionId);
53007
- await session.update({
53008
- sessionUpdate: "session_info_update",
53009
- _meta: {
53010
- [JETBRAINS_META_KEY]: {
53011
- [AIR_META_KEY]: {
53012
- [AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
53013
- [AIR_AGENT_FILE_CHANGE_REPORT_KEY]: report
53014
- }
53015
- }
53016
- }
53017
- });
53043
+ await publishAirSessionMetadata(session, AIR_AGENT_FILE_CHANGE_REPORT_KEY, report);
53018
53044
  } catch (error62) {
53019
53045
  logger.error("Failed to publish agent file-change report", error62);
53020
53046
  }
@@ -53347,12 +53373,14 @@ You have been logged out. Please try again.`);
53347
53373
  cancellers.clear();
53348
53374
  }
53349
53375
  async interruptPromptTurn(sessionState, turn, requestName) {
53376
+ const activePrompt = this.activePrompts.get(sessionState.sessionId);
53350
53377
  this.codexAcpClient.markTurnStale({
53351
53378
  threadId: turn.threadId,
53352
53379
  turnId: turn.turnId
53353
53380
  });
53354
53381
  try {
53355
53382
  await this.interruptStandardChildren(sessionState);
53383
+ if (this.activePrompts.get(sessionState.sessionId) !== activePrompt) return;
53356
53384
  await this.requestTurnInterrupt(sessionState, turn.threadId, turn.turnId, requestName);
53357
53385
  } finally {
53358
53386
  this.codexAcpClient.resolveTurnInterrupted({
@@ -53367,13 +53395,17 @@ You have been logged out. Please try again.`);
53367
53395
  * interrupt", and once it registers a later turn under a different id, "expected active turn
53368
53396
  * id <completionTurnId> but found <Y>". Both are retried, with the id recomputed on every
53369
53397
  * attempt so a `turn/started` that arrives between retries is picked up.
53398
+ * Retries belong to that prompt, not to a newer prompt that starts while a reply is pending.
53370
53399
  */
53371
53400
  async requestTurnInterrupt(sessionState, threadId, completionTurnId, requestName) {
53372
53401
  if (this.recovery !== null && !this.turnAppServerIsLive(threadId)) {
53373
53402
  logger.log(`${requestName} - turnInterrupt skipped: the app-server of the turn is gone`, { sessionId: threadId });
53374
53403
  return;
53375
53404
  }
53376
- let turnId = codexRunningTurnId(sessionState, completionTurnId);
53405
+ const activePrompt = this.activePrompts.get(sessionState.sessionId);
53406
+ const ownsRegisteredTurn = activePrompt?.currentTurn?.threadId === threadId && activePrompt.currentTurn.turnId === completionTurnId;
53407
+ const stillOwnsPrompt = () => ownsRegisteredTurn && activePrompt !== void 0 && this.activePrompts.get(sessionState.sessionId) === activePrompt;
53408
+ let turnId = ownsRegisteredTurn ? codexRunningTurnId(sessionState, completionTurnId) : completionTurnId;
53377
53409
  for (let attempt = 0; ; attempt++) {
53378
53410
  try {
53379
53411
  await this.runWithProcessCheck(() => this.codexAcpClient.turnInterrupt({
@@ -53386,15 +53418,15 @@ You have been logged out. Please try again.`);
53386
53418
  });
53387
53419
  return;
53388
53420
  } catch (err) {
53389
- const promptStillActive = this.activePrompts.has(threadId);
53390
53421
  const mismatch = parseExpectedActiveTurnMismatch(err);
53391
53422
  const isMismatch = mismatch !== null && mismatch.expected === sessionState.currentTurnId && mismatch.found !== "";
53392
- const retryable = promptStillActive && (isNoActiveTurnError(err) || isMismatch) && attempt < NO_ACTIVE_TURN_RETRY_DELAYS_MS.length;
53423
+ const retryable = stillOwnsPrompt() && (isNoActiveTurnError(err) || isMismatch) && attempt < NO_ACTIVE_TURN_RETRY_DELAYS_MS.length;
53393
53424
  if (!retryable) {
53394
53425
  logger.error(`${requestName} - turnInterrupt failed`, err);
53395
53426
  return;
53396
53427
  }
53397
53428
  await new Promise((resolve) => setTimeout(resolve, NO_ACTIVE_TURN_RETRY_DELAYS_MS[attempt]));
53429
+ if (!stillOwnsPrompt()) return;
53398
53430
  turnId = sessionState.interruptTurnId ?? (isMismatch ? mismatch.found : completionTurnId);
53399
53431
  logger.log(`${requestName} - turn not interruptible yet, retrying`, {
53400
53432
  sessionId: threadId,
@@ -53416,9 +53448,11 @@ You have been logged out. Please try again.`);
53416
53448
  return activePrompt.signal.aborted || this.activePrompts.get(sessionId) !== activePrompt || this.sessionIsClosing(sessionId);
53417
53449
  }
53418
53450
  async interruptSessionTurn(sessionState, requestName, resolveInterruptedTurn) {
53451
+ const activePrompt = this.activePrompts.get(sessionState.sessionId);
53419
53452
  await this.interruptStandardChildren(sessionState);
53453
+ if (this.activePrompts.get(sessionState.sessionId) !== activePrompt) return;
53420
53454
  const turnId = await this.getInterruptibleTurnId(sessionState, requestName);
53421
- if (!turnId) {
53455
+ if (!turnId || this.activePrompts.get(sessionState.sessionId) !== activePrompt) {
53422
53456
  return;
53423
53457
  }
53424
53458
  logger.log(`${requestName} session requested`, {
@@ -53652,7 +53686,7 @@ You have been logged out. Please try again.`);
53652
53686
  ).finally(() => {
53653
53687
  signal?.removeEventListener("abort", dropPendingRequest);
53654
53688
  reservation.release();
53655
- if (!this.sessions.has(sessionId)) AcpV2Connection.of(this.connection)?.forgetSession(sessionId);
53689
+ if (!this.sessions.has(sessionId)) AcpV2Connection.of(this.connection)?.forgetForegroundState(sessionId);
53656
53690
  });
53657
53691
  });
53658
53692
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "2.5.1-preview.11",
6
+ "version": "2.5.1-preview.13",
7
7
  "description": "",
8
8
  "main": "dist/index.js",
9
9
  "bin": {