lody 0.93.2 → 0.94.0

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.
@@ -21253,6 +21253,57 @@ function toPromptUsage(tokenCount) {
21253
21253
  thoughtTokens: tokenCount.reasoningOutputTokens
21254
21254
  };
21255
21255
  }
21256
+ var CODEX_UNATTRIBUTED_MODEL = "codex:unattributed";
21257
+ var counters = [
21258
+ "inputTokens",
21259
+ "outputTokens",
21260
+ "cacheReadInputTokens",
21261
+ "cacheCreationInputTokens",
21262
+ "reasoningOutputTokens"
21263
+ ];
21264
+ var empty = () => ({
21265
+ inputTokens: 0,
21266
+ outputTokens: 0,
21267
+ cacheReadInputTokens: 0,
21268
+ cacheCreationInputTokens: 0,
21269
+ reasoningOutputTokens: 0
21270
+ });
21271
+ function normalizeCodexUsage(raw) {
21272
+ return {
21273
+ inputTokens: Math.max(0, raw.inputTokens - raw.cachedInputTokens - raw.cacheWriteInputTokens),
21274
+ outputTokens: Math.max(0, raw.outputTokens - raw.reasoningOutputTokens),
21275
+ cacheReadInputTokens: raw.cachedInputTokens,
21276
+ cacheCreationInputTokens: raw.cacheWriteInputTokens,
21277
+ reasoningOutputTokens: raw.reasoningOutputTokens
21278
+ };
21279
+ }
21280
+ var CodexUsageAccounting = class {
21281
+ offset = empty();
21282
+ total = empty();
21283
+ atReset = false;
21284
+ update(sessionId, params) {
21285
+ const { total: raw, modelContextWindow } = params.tokenUsage;
21286
+ const reset = modelContextWindow !== null && modelContextWindow > 0 && raw.totalTokens === modelContextWindow && raw.inputTokens === 0 && raw.outputTokens === 0 && raw.cachedInputTokens === 0 && raw.cacheWriteInputTokens === 0 && raw.reasoningOutputTokens === 0;
21287
+ if (reset && !this.atReset) this.offset = { ...this.total };
21288
+ this.atReset = reset;
21289
+ const normalized = normalizeCodexUsage(raw);
21290
+ const next = empty();
21291
+ const difference = empty();
21292
+ for (const key of counters) {
21293
+ next[key] = Math.max(this.total[key] ?? 0, (this.offset[key] ?? 0) + (normalized[key] ?? 0));
21294
+ difference[key] = (next[key] ?? 0) - (this.total[key] ?? 0);
21295
+ }
21296
+ this.total = next;
21297
+ const usage = { ...next };
21298
+ if (modelContextWindow !== null) usage.contextWindow = modelContextWindow;
21299
+ return {
21300
+ sessionId,
21301
+ usage,
21302
+ modelUsage: { [CODEX_UNATTRIBUTED_MODEL]: { ...next } },
21303
+ delta: { usage: { ...difference }, modelUsage: { [CODEX_UNATTRIBUTED_MODEL]: { ...difference } } }
21304
+ };
21305
+ }
21306
+ };
21256
21307
  function hasOnlyWinLineEndings(string4) {
21257
21308
  return string4.includes("\r\n") && !string4.startsWith("\n") && !string4.match(/[^\r]\n/);
21258
21309
  }
@@ -23749,17 +23800,8 @@ var CodexEventHandler = class _CodexEventHandler {
23749
23800
  await this.connection.notify(extMethod, params);
23750
23801
  }
23751
23802
  createSessionUsageExtNotification(params) {
23752
- const totalUsage = params.tokenUsage.total;
23753
- return {
23754
- sessionId: this.sessionState.sessionId,
23755
- usage: {
23756
- inputTokens: totalUsage.inputTokens,
23757
- outputTokens: totalUsage.outputTokens,
23758
- cacheReadInputTokens: totalUsage.cachedInputTokens,
23759
- reasoningOutputTokens: totalUsage.reasoningOutputTokens,
23760
- ...params.tokenUsage.modelContextWindow === null ? {} : { contextWindow: params.tokenUsage.modelContextWindow }
23761
- }
23762
- };
23803
+ this.sessionState.usageAccounting ??= new CodexUsageAccounting();
23804
+ return this.sessionState.usageAccounting.update(this.sessionState.sessionId, params);
23763
23805
  }
23764
23806
  createSessionRateLimitsExtNotification(rateLimits) {
23765
23807
  return {
@@ -26651,7 +26693,7 @@ var package_default = {
26651
26693
  dependencies: {
26652
26694
  "@agentclientprotocol/sdk": "^1.4.0",
26653
26695
  "@openai/codex": "^0.153.4",
26654
- "acp-extension-core": "0.1.4",
26696
+ "acp-extension-core": "0.1.5",
26655
26697
  diff: "^9.0.0",
26656
26698
  open: "^11.0.1",
26657
26699
  "vscode-jsonrpc": "^9.0.1",
@@ -27710,8 +27752,8 @@ var CodexAcpClient = class {
27710
27752
  delivery: "inline"
27711
27753
  }, onTurnStarted);
27712
27754
  }
27713
- async runCompact(sessionId) {
27714
- await this.codexClient.runCompact({ threadId: sessionId });
27755
+ async runCompact(sessionId, onTurnStarted) {
27756
+ return await this.codexClient.runCompact({ threadId: sessionId }, onTurnStarted);
27715
27757
  }
27716
27758
  async getGoal(sessionId) {
27717
27759
  const response = await this.codexClient.threadGoalGet({ threadId: sessionId });
@@ -28419,7 +28461,7 @@ var CodexAppServerClient = class {
28419
28461
  mcpServerStartupStates = /* @__PURE__ */ new Map();
28420
28462
  mcpServerStartupResolvers = [];
28421
28463
  pendingTurnCompletionResolvers = /* @__PURE__ */ new Map();
28422
- pendingCompactionCompletionResolvers = /* @__PURE__ */ new Map();
28464
+ pendingCompactTurns = /* @__PURE__ */ new Map();
28423
28465
  turnCompletionCaptures = /* @__PURE__ */ new Map();
28424
28466
  turnRoutingCaptures = /* @__PURE__ */ new Map();
28425
28467
  threadStatusCaptures = /* @__PURE__ */ new Map();
@@ -28448,10 +28490,18 @@ var CodexAppServerClient = class {
28448
28490
  this.resolveMcpServerStartupResolvers();
28449
28491
  }
28450
28492
  if (isTurnCompletedNotification(serverNotification)) {
28493
+ const compact = this.pendingCompactTurns.get(serverNotification.params.threadId);
28494
+ if (compact?.turnId === serverNotification.params.turn.id) {
28495
+ compact.resolve(serverNotification.params);
28496
+ }
28451
28497
  this.recordTurnCompleted(serverNotification.params);
28452
28498
  }
28453
- if (isCompactionCompletedNotification(serverNotification)) {
28454
- this.recordCompactionCompleted(serverNotification);
28499
+ if (serverNotification.method === "turn/started") {
28500
+ const compact = this.pendingCompactTurns.get(serverNotification.params.threadId);
28501
+ if (compact && compact.turnId === null) {
28502
+ compact.turnId = serverNotification.params.turn.id;
28503
+ compact.onTurnStarted?.(compact.turnId);
28504
+ }
28455
28505
  }
28456
28506
  if (isThreadStatusChangedNotification(serverNotification)) {
28457
28507
  this.recordThreadStatusChanged(serverNotification.params);
@@ -28753,10 +28803,25 @@ var CodexAppServerClient = class {
28753
28803
  threadStatusChanged: handleThreadStatusChanged
28754
28804
  };
28755
28805
  }
28756
- async runCompact(params) {
28757
- const compactionCompleted = this.awaitCompactionCompleted(params.threadId);
28758
- await this.threadCompactStart(params);
28759
- return await compactionCompleted;
28806
+ async runCompact(params, onTurnStarted) {
28807
+ if (this.turnCompletionTerminalError) throw this.turnCompletionTerminalError;
28808
+ if (this.pendingCompactTurns.has(params.threadId)) {
28809
+ throw new Error("A compaction request already owns this thread");
28810
+ }
28811
+ const completion = new Promise((resolve, reject) => {
28812
+ this.pendingCompactTurns.set(params.threadId, {
28813
+ turnId: null,
28814
+ onTurnStarted,
28815
+ resolve,
28816
+ reject
28817
+ });
28818
+ });
28819
+ try {
28820
+ const [, completed] = await Promise.all([this.threadCompactStart(params), completion]);
28821
+ return completed;
28822
+ } finally {
28823
+ this.pendingCompactTurns.delete(params.threadId);
28824
+ }
28760
28825
  }
28761
28826
  async turnInterrupt(params) {
28762
28827
  return await this.sendRequest({ method: "turn/interrupt", params });
@@ -28901,13 +28966,6 @@ var CodexAppServerClient = class {
28901
28966
  threadResolvers.set(turnId, { resolve, reject });
28902
28967
  });
28903
28968
  }
28904
- async awaitCompactionCompleted(threadId) {
28905
- return await new Promise((resolve) => {
28906
- const resolvers = this.pendingCompactionCompletionResolvers.get(threadId) ?? /* @__PURE__ */ new Set();
28907
- resolvers.add(resolve);
28908
- this.pendingCompactionCompletionResolvers.set(threadId, resolvers);
28909
- });
28910
- }
28911
28969
  resolveTurnInterrupted(threadId, turnId) {
28912
28970
  this.recordTurnCompleted({
28913
28971
  threadId,
@@ -28976,20 +29034,6 @@ var CodexAppServerClient = class {
28976
29034
  capture(event);
28977
29035
  }
28978
29036
  }
28979
- recordCompactionCompleted(event) {
28980
- const threadId = extractThreadId(event);
28981
- if (threadId === null) {
28982
- return;
28983
- }
28984
- const resolvers = this.pendingCompactionCompletionResolvers.get(threadId);
28985
- if (!resolvers) {
28986
- return;
28987
- }
28988
- this.pendingCompactionCompletionResolvers.delete(threadId);
28989
- for (const resolve of resolvers) {
28990
- resolve(event);
28991
- }
28992
- }
28993
29037
  recordThreadStatusChanged(event) {
28994
29038
  const captures = this.threadStatusCaptures.get(event.threadId);
28995
29039
  if (!captures) {
@@ -29074,6 +29118,8 @@ var CodexAppServerClient = class {
29074
29118
  */
29075
29119
  rejectAllPendingTurnCompletions(error48) {
29076
29120
  this.turnCompletionTerminalError ??= error48;
29121
+ for (const compact of this.pendingCompactTurns.values()) compact.reject(error48);
29122
+ this.pendingCompactTurns.clear();
29077
29123
  const threads = [...this.pendingTurnCompletionResolvers.values()];
29078
29124
  this.pendingTurnCompletionResolvers.clear();
29079
29125
  for (const threadResolvers of threads) {
@@ -29234,12 +29280,6 @@ function isThreadGoalUpdatedNotification(notification) {
29234
29280
  function isThreadGoalClearedNotification(notification) {
29235
29281
  return notification.method === "thread/goal/cleared";
29236
29282
  }
29237
- function isCompactionCompletedNotification(notification) {
29238
- if (notification.method === "thread/compacted") {
29239
- return true;
29240
- }
29241
- return notification.method === "item/completed" && notification.params.item.type === "contextCompaction";
29242
- }
29243
29283
  function goalsMatch(left, right) {
29244
29284
  return left.threadId === right.threadId && left.objective === right.objective && left.status === right.status && left.tokenBudget === right.tokenBudget && left.updatedAt === right.updatedAt;
29245
29285
  }
@@ -29504,8 +29544,18 @@ var CodexCommands = class {
29504
29544
  return { handled: options.setConfigOption !== void 0 };
29505
29545
  }
29506
29546
  case "compact": {
29507
- await this.runWithProcessCheck(() => this.codexAcpClient.runCompact(sessionId));
29508
- return { handled: true };
29547
+ options.onTurnStartPending?.();
29548
+ options.onCompactionStarted?.();
29549
+ try {
29550
+ const turnCompleted = await this.runWithProcessCheck(
29551
+ () => this.codexAcpClient.runCompact(sessionId, (turnId) => {
29552
+ options.onTurnStarted?.(turnId, sessionId);
29553
+ })
29554
+ );
29555
+ return { handled: true, turnCompleted };
29556
+ } finally {
29557
+ options.onCompactionFinished?.();
29558
+ }
29509
29559
  }
29510
29560
  case "goal": {
29511
29561
  return await this.runGoalCommand(sessionState, command.rest, options);
@@ -33515,6 +33565,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33515
33565
  signal: abortController.signal,
33516
33566
  currentTurn: null,
33517
33567
  hasCompletedTurn: false,
33568
+ compactionInFlight: false,
33518
33569
  requestCancel: () => {
33519
33570
  if (abortController.signal.aborted) {
33520
33571
  return;
@@ -33567,7 +33618,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33567
33618
  }
33568
33619
  cancelBeforeTurnStarted(activePrompt) {
33569
33620
  return activePrompt.cancelSignal.then(() => {
33570
- if (activePrompt.currentTurn === null) {
33621
+ if (activePrompt.currentTurn === null && !activePrompt.compactionInFlight) {
33571
33622
  return null;
33572
33623
  }
33573
33624
  return new Promise(() => {
@@ -33635,7 +33686,12 @@ Check ${configPath} and project .codex directories, especially their config.toml
33635
33686
  logger.error(`${requestName} - turnInterrupt failed`, err);
33636
33687
  }
33637
33688
  }
33638
- interruptLateStartedTurn(turn) {
33689
+ interruptLateStartedTurn(turn, activePrompt) {
33690
+ if (activePrompt.compactionInFlight) {
33691
+ this.codexAcpClient.markTurnStale(turn);
33692
+ void this.requestTurnInterrupt(turn, "Cancel");
33693
+ return;
33694
+ }
33639
33695
  void this.interruptPromptTurn(turn, "Close");
33640
33696
  }
33641
33697
  promptShouldStop(sessionId, activePrompt) {
@@ -33783,7 +33839,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33783
33839
  const turn = { threadId: params.sessionId, turnId: event.params.turn.id };
33784
33840
  activePrompt.currentTurn = turn;
33785
33841
  if (this.promptShouldStop(params.sessionId, activePrompt)) {
33786
- this.interruptLateStartedTurn(turn);
33842
+ this.interruptLateStartedTurn(turn, activePrompt);
33787
33843
  return;
33788
33844
  }
33789
33845
  recoverableSessionFailure = sessionState.sessionFailure;
@@ -33825,13 +33881,19 @@ Check ${configPath} and project .codex directories, especially their config.toml
33825
33881
  if (threadId === params.sessionId) goalLifecycle.startTurn(turnId);
33826
33882
  activePrompt.currentTurn = turn;
33827
33883
  if (this.promptShouldStop(params.sessionId, activePrompt)) {
33828
- this.interruptLateStartedTurn(turn);
33884
+ this.interruptLateStartedTurn(turn, activePrompt);
33829
33885
  return;
33830
33886
  }
33831
33887
  sessionState.currentTurnId = turnId;
33832
33888
  pendingTurnStart?.resolve(turnId);
33833
33889
  onTurnStarted?.();
33834
33890
  },
33891
+ onCompactionStarted: () => {
33892
+ activePrompt.compactionInFlight = true;
33893
+ },
33894
+ onCompactionFinished: () => {
33895
+ activePrompt.compactionInFlight = false;
33896
+ },
33835
33897
  setConfigOption: async (configId, value) => {
33836
33898
  await this.applySessionConfigOption(sessionState, {
33837
33899
  sessionId: sessionState.sessionId,
@@ -33947,7 +34009,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
33947
34009
  }
33948
34010
  activePrompt.currentTurn = turn;
33949
34011
  if (this.promptShouldStop(params.sessionId, activePrompt)) {
33950
- this.interruptLateStartedTurn(turn);
34012
+ this.interruptLateStartedTurn(turn, activePrompt);
33951
34013
  return;
33952
34014
  }
33953
34015
  sessionState.currentTurnId = turnId;
@@ -34045,7 +34107,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
34045
34107
  if (!goalLifecycle.startSubmittedTurn(turnId)) return;
34046
34108
  activePrompt.currentTurn = turn;
34047
34109
  if (this.promptShouldStop(params.sessionId, activePrompt)) {
34048
- this.interruptLateStartedTurn(turn);
34110
+ this.interruptLateStartedTurn(turn, activePrompt);
34049
34111
  return;
34050
34112
  }
34051
34113
  sessionState.currentTurnId = turnId;
@@ -34287,6 +34349,10 @@ ${stderr}` : "";
34287
34349
  return;
34288
34350
  }
34289
34351
  const activePrompt = this.activePrompts.get(params.sessionId);
34352
+ if (activePrompt?.compactionInFlight) {
34353
+ activePrompt.requestCancel();
34354
+ if (activePrompt.currentTurn === null) return;
34355
+ }
34290
34356
  if (activePrompt?.hasCompletedTurn && activePrompt.currentTurn === null) {
34291
34357
  activePrompt.requestCancel();
34292
34358
  return;