opencode-acp 1.14.19-pr.313.25 → 1.14.19-pr.314.26

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AA2BjD,QAAA,MAAM,MAAM,EAAE,MAiHK,CAAA;AAEnB,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AA2BjD,QAAA,MAAM,MAAM,EAAE,MAwHK,CAAA;AAEnB,eAAe,MAAM,CAAA"}
package/dist/index.js CHANGED
@@ -2084,18 +2084,6 @@ import { homedir as homedir2 } from "os";
2084
2084
  import { join as join2 } from "path";
2085
2085
 
2086
2086
  // lib/state/utils.ts
2087
- function syncModelIdentity(state, providerID, modelID) {
2088
- if (providerID === void 0 || modelID === void 0) {
2089
- return false;
2090
- }
2091
- if (state.modelProviderID === providerID && state.modelID === modelID) {
2092
- return false;
2093
- }
2094
- state.modelContextLimit = void 0;
2095
- state.modelProviderID = providerID;
2096
- state.modelID = modelID;
2097
- return true;
2098
- }
2099
2087
  var isMessageCompacted = (state, msg) => {
2100
2088
  if (!isMessageWithInfo(msg)) {
2101
2089
  return false;
@@ -2430,9 +2418,7 @@ async function saveSessionState(sessionState, logger, sessionName) {
2430
2418
  nextRef: sessionState.messageIds.nextRef
2431
2419
  },
2432
2420
  lastCompaction: sessionState.lastCompaction,
2433
- modelContextLimit: sessionState.modelContextLimit,
2434
- modelProviderID: sessionState.modelProviderID,
2435
- modelID: sessionState.modelID
2421
+ modelContextLimit: sessionState.modelContextLimit
2436
2422
  };
2437
2423
  await writePersistedSessionState(sessionState.sessionId, state, logger);
2438
2424
  }
@@ -4154,6 +4140,57 @@ var SessionStateRegistry = class {
4154
4140
  startsByCallId: /* @__PURE__ */ new Map(),
4155
4141
  pendingByCallId: /* @__PURE__ */ new Map()
4156
4142
  };
4143
+ // [FIX #312] Catalog of per-model context limits, keyed `${providerID}/${modelID}`.
4144
+ // Within one LLM request the host fires experimental.chat.messages.transform
4145
+ // BEFORE experimental.chat.system.transform (sst/opencode: session/prompt.ts
4146
+ // triggers messages.transform, then llm/request.ts triggers system.transform
4147
+ // during handle.process). state.modelContextLimit is written only by the
4148
+ // system hook, so on the first request after a model switch every percentage
4149
+ // threshold (emergencyThresholdPercent, min/maxContextLimit "%", adaptive
4150
+ // nudge growth, GC tiers) is still computed against the PREVIOUS model's
4151
+ // limit. This catalog lets the messages hook reconcile against the model
4152
+ // named on the request's user message instead of waiting one turn.
4153
+ // Entries are recorded live by the system hook every request and seeded once
4154
+ // at plugin init from the host's /config/providers catalog.
4155
+ modelLimits = /* @__PURE__ */ new Map();
4156
+ recordModelLimit(providerId, modelId, limit) {
4157
+ if (!providerId || !modelId || typeof limit !== "number" || limit <= 0) return;
4158
+ this.modelLimits.set(`${providerId}/${modelId}`, limit);
4159
+ }
4160
+ resolveModelLimit(providerId, modelId) {
4161
+ if (!providerId || !modelId) return void 0;
4162
+ return this.modelLimits.get(`${providerId}/${modelId}`);
4163
+ }
4164
+ /**
4165
+ * Best-effort one-time seed from the host's provider catalog
4166
+ * (`client.config.providers()` → GET /config/providers). Never throws;
4167
+ * returns the number of model-limit entries recorded.
4168
+ */
4169
+ async hydrateModelLimitsFromClient(client) {
4170
+ try {
4171
+ const config = client;
4172
+ const result = await config.config?.providers?.();
4173
+ const payload = result;
4174
+ const providers = payload?.data?.providers;
4175
+ if (!Array.isArray(providers)) return 0;
4176
+ let recorded = 0;
4177
+ for (const provider of providers) {
4178
+ const { id, models } = provider ?? {};
4179
+ if (typeof id !== "string" || !models) continue;
4180
+ for (const [modelId, model] of Object.entries(models)) {
4181
+ const limit = model?.limit;
4182
+ const context = limit?.context;
4183
+ if (typeof context === "number" && context > 0) {
4184
+ this.modelLimits.set(`${id}/${modelId}`, context);
4185
+ recorded++;
4186
+ }
4187
+ }
4188
+ }
4189
+ return recorded;
4190
+ } catch {
4191
+ return 0;
4192
+ }
4193
+ }
4157
4194
  get(sessionId) {
4158
4195
  return this.states.get(sessionId);
4159
4196
  }
@@ -4242,8 +4279,6 @@ function createSessionState() {
4242
4279
  lastCompaction: 0,
4243
4280
  currentTurn: 0,
4244
4281
  modelContextLimit: void 0,
4245
- modelProviderID: void 0,
4246
- modelID: void 0,
4247
4282
  systemPromptTokens: void 0,
4248
4283
  qualityGateRetryPending: false
4249
4284
  };
@@ -4283,8 +4318,6 @@ function resetSessionState(state) {
4283
4318
  state.lastCompaction = 0;
4284
4319
  state.currentTurn = 0;
4285
4320
  state.modelContextLimit = void 0;
4286
- state.modelProviderID = void 0;
4287
- state.modelID = void 0;
4288
4321
  state.systemPromptTokens = void 0;
4289
4322
  state.qualityGateRetryPending = false;
4290
4323
  }
@@ -4360,12 +4393,6 @@ async function ensureSessionInitialized(client, state, sessionId, logger, messag
4360
4393
  if (typeof persisted.modelContextLimit === "number" && persisted.modelContextLimit > 0) {
4361
4394
  state.modelContextLimit = persisted.modelContextLimit;
4362
4395
  }
4363
- if (typeof persisted.modelProviderID === "string") {
4364
- state.modelProviderID = persisted.modelProviderID;
4365
- }
4366
- if (typeof persisted.modelID === "string") {
4367
- state.modelID = persisted.modelID;
4368
- }
4369
4396
  const applied = applyPendingCompressionDurations(state);
4370
4397
  if (applied > 0) {
4371
4398
  await saveSessionState(state, logger);
@@ -8973,7 +9000,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
8973
9000
  import { join as join3 } from "path";
8974
9001
  import { existsSync as existsSync3 } from "fs";
8975
9002
  import { homedir as homedir3 } from "os";
8976
- var LOG_VERSION = true ? "1.14.19-pr.313.25" : "dev";
9003
+ var LOG_VERSION = true ? "1.14.19-pr.314.26" : "dev";
8977
9004
  var Logger = class {
8978
9005
  logDir;
8979
9006
  enabled;
@@ -10540,11 +10567,14 @@ function isInternalAgentRequest(messages) {
10540
10567
  }
10541
10568
  function createSystemPromptHandler(registry4, logger, config, prompts) {
10542
10569
  return async (input, output) => {
10570
+ registry4.recordModelLimit(
10571
+ input.model?.providerID,
10572
+ input.model?.id,
10573
+ input.model?.limit?.context
10574
+ );
10543
10575
  const state = input.sessionID ? registry4.get(input.sessionID) : void 0;
10544
10576
  if (state && input.model?.limit?.context) {
10545
10577
  state.modelContextLimit = input.model.limit.context;
10546
- state.modelProviderID = input.model.providerID;
10547
- state.modelID = input.model.id;
10548
10578
  }
10549
10579
  if (!state || state.isSubAgent && !config.allowSubAgents) {
10550
10580
  return;
@@ -10597,22 +10627,15 @@ function createChatMessageTransformHandler(client, registry4, logger, config, pr
10597
10627
  messages,
10598
10628
  config
10599
10629
  );
10600
- await updatePerTurnState(state, logger, messages);
10601
- const { providerId, modelId } = getModelInfo(messages);
10602
- const prevIdentity = state.modelID;
10603
- const prevModel = prevIdentity ? `${state.modelProviderID}/${prevIdentity}` : void 0;
10604
- if (syncModelIdentity(state, providerId, modelId)) {
10605
- const target = `${providerId}/${modelId}`;
10606
- if (prevIdentity) {
10607
- logger.debug(
10608
- `Model switch detected (${prevModel} \u2192 ${target}); invalidated stale modelContextLimit`
10609
- );
10610
- } else {
10611
- logger.debug(
10612
- `Model identity established (${target}); limit awaits system.transform`
10613
- );
10614
- }
10630
+ const requestModel = lastUserMessage.info.model;
10631
+ const requestModelLimit = registry4.resolveModelLimit(
10632
+ requestModel?.providerID,
10633
+ requestModel?.modelID
10634
+ );
10635
+ if (requestModelLimit !== void 0) {
10636
+ state.modelContextLimit = requestModelLimit;
10615
10637
  }
10638
+ await updatePerTurnState(state, logger, messages);
10616
10639
  }
10617
10640
  syncCompressPermissionState(state, config, hostPermissions, output.messages);
10618
10641
  if (state.isSubAgent && !config.allowSubAgents) {
@@ -10997,6 +11020,8 @@ var server = (async (ctx) => {
10997
11020
  if (isSecureMode()) {
10998
11021
  configureClientAuth(ctx.client);
10999
11022
  }
11023
+ registry4.hydrateModelLimitsFromClient(ctx.client).catch(() => {
11024
+ });
11000
11025
  logger.info("DCP initialized");
11001
11026
  startAutoUpdate(ctx, config.autoUpdate);
11002
11027
  const compressToolContext = {