@bman654/clodex 2.1.6 → 2.1.8

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.
package/dist/cli.js CHANGED
@@ -217,7 +217,7 @@ import { join } from "path";
217
217
  // package.json
218
218
  var package_default = {
219
219
  name: "@bman654/clodex",
220
- version: "2.1.6",
220
+ version: "2.1.8",
221
221
  publishConfig: {
222
222
  access: "public"
223
223
  },
@@ -4406,6 +4406,10 @@ function normalizeToolCallJson(value) {
4406
4406
  } catch {
4407
4407
  }
4408
4408
  }
4409
+ if (record.type === "reasoning") {
4410
+ if (Array.isArray(record.content) && record.content.length === 0) delete out.content;
4411
+ if (typeof record.encrypted_content === "string" && record.encrypted_content) delete out.summary;
4412
+ }
4409
4413
  return out;
4410
4414
  }
4411
4415
  function arraysEqual(left, right) {
@@ -4421,7 +4425,66 @@ function conversationItemKind(value) {
4421
4425
  function conversationItemHash(value) {
4422
4426
  return createHash3("sha256").update(canonicalJson(normalizeToolCallJson(value))).digest("hex").slice(0, 16);
4423
4427
  }
4424
- function continuationMismatchDetails(entry, payload) {
4428
+ function reasoningNormalizationGap(expected, actual) {
4429
+ if (conversationItemKind(expected) !== "reasoning" || conversationItemKind(actual) !== "reasoning") return void 0;
4430
+ const left = expected;
4431
+ const right = actual;
4432
+ const blob = left.encrypted_content;
4433
+ if (typeof blob !== "string" || !blob || blob !== right.encrypted_content) return void 0;
4434
+ const normalizedLeft = normalizeToolCallJson(left);
4435
+ const normalizedRight = normalizeToolCallJson(right);
4436
+ const fields = [.../* @__PURE__ */ new Set([...Object.keys(normalizedLeft), ...Object.keys(normalizedRight)])].sort().filter((key) => canonicalJson(normalizedLeft[key]) !== canonicalJson(normalizedRight[key]));
4437
+ return fields.length ? fields : void 0;
4438
+ }
4439
+ function reasoningGapShape(expected, actual, full, storedTail, index) {
4440
+ const describe = (value) => {
4441
+ const record = value ?? {};
4442
+ return {
4443
+ keys: Object.keys(record).sort(),
4444
+ summaryParts: Array.isArray(record.summary) ? record.summary.length : 0,
4445
+ contentItems: Array.isArray(record.content) ? record.content.length : 0
4446
+ };
4447
+ };
4448
+ const blob = expected.encrypted_content;
4449
+ const runFrom = (items, start) => {
4450
+ let count = 0;
4451
+ for (let at = start; at < items.length; at += 1) {
4452
+ const item = items[at];
4453
+ if (conversationItemKind(item) !== "reasoning" || item?.encrypted_content !== blob) break;
4454
+ count += 1;
4455
+ }
4456
+ return count;
4457
+ };
4458
+ const storedStart = storedTail.findIndex((item) => item?.encrypted_content === blob);
4459
+ return {
4460
+ expected: describe(expected),
4461
+ actual: describe(actual),
4462
+ clientReasoningRun: runFrom(full, index),
4463
+ storedReasoningRun: storedStart < 0 ? 0 : runFrom(storedTail, storedStart)
4464
+ };
4465
+ }
4466
+ var warnedReasoningGaps = /* @__PURE__ */ new Set();
4467
+ var MAX_REASONING_GAP_WARNINGS = 3;
4468
+ function warnReasoningNormalizationGap(fields, log12) {
4469
+ const signature = fields.join(",");
4470
+ const message = `clodex: warning: a reasoning item with identical encrypted_content failed the continuation match on field(s): ${signature}. Prompt caching is degraded for this turn \u2014 this is a clodex normalization gap, please report it at https://github.com/bman654/clodex/issues`;
4471
+ try {
4472
+ log12?.(`reasoning normalization gap: ${signature}`);
4473
+ } catch {
4474
+ }
4475
+ if (warnedReasoningGaps.has(signature)) return;
4476
+ if (warnedReasoningGaps.size >= MAX_REASONING_GAP_WARNINGS) return;
4477
+ warnedReasoningGaps.add(signature);
4478
+ try {
4479
+ process.stderr.write(`${message}
4480
+ `);
4481
+ if (warnedReasoningGaps.size === MAX_REASONING_GAP_WARNINGS) {
4482
+ process.stderr.write("clodex: warning: further reasoning-normalization warnings suppressed.\n");
4483
+ }
4484
+ } catch {
4485
+ }
4486
+ }
4487
+ function continuationMismatchDetails(entry, payload, log12, warnOnGap = false) {
4425
4488
  const full = inputArray(payload);
4426
4489
  const prefix = [...entry.requestInput ?? [], ...entry.expectedAssistant ?? []];
4427
4490
  const comparable = Math.min(full.length, prefix.length);
@@ -4434,6 +4497,8 @@ function continuationMismatchDetails(entry, payload) {
4434
4497
  }
4435
4498
  const expected = mismatch < prefix.length ? prefix[mismatch] : void 0;
4436
4499
  const actual = mismatch < full.length ? full[mismatch] : void 0;
4500
+ const reasoningGap = reasoningNormalizationGap(expected, actual);
4501
+ if (reasoningGap && warnOnGap) warnReasoningNormalizationGap(reasoningGap, log12);
4437
4502
  return {
4438
4503
  fullItems: full.length,
4439
4504
  expectedPrefixItems: prefix.length,
@@ -4441,11 +4506,21 @@ function continuationMismatchDetails(entry, payload) {
4441
4506
  expectedKind: expected === void 0 ? "none" : conversationItemKind(expected),
4442
4507
  actualKind: actual === void 0 ? "none" : conversationItemKind(actual),
4443
4508
  ...expected !== void 0 ? { expectedHash: conversationItemHash(expected) } : {},
4444
- ...actual !== void 0 ? { actualHash: conversationItemHash(actual) } : {}
4509
+ ...actual !== void 0 ? { actualHash: conversationItemHash(actual) } : {},
4510
+ ...reasoningGap ? {
4511
+ reasoningNormalizationGap: reasoningGap,
4512
+ reasoningGapShape: reasoningGapShape(
4513
+ expected,
4514
+ actual,
4515
+ full,
4516
+ entry.expectedAssistant ?? [],
4517
+ mismatch
4518
+ )
4519
+ } : {}
4445
4520
  };
4446
4521
  }
4447
- function continuationMismatchSummary(entry, payload) {
4448
- const details = continuationMismatchDetails(entry, payload);
4522
+ function continuationMismatchSummary(entry, payload, log12) {
4523
+ const details = continuationMismatchDetails(entry, payload, log12, true);
4449
4524
  return `full_items=${details.fullItems} expected_prefix_items=${details.expectedPrefixItems} first_mismatch=${details.firstMismatch} expected=${details.expectedKind} actual=${details.actualKind}`;
4450
4525
  }
4451
4526
  function continuationMatch(entry, payload) {
@@ -5188,6 +5263,19 @@ function createConnection(WebSocket, wsUrl, headers, persistent, key, options, d
5188
5263
  });
5189
5264
  return entry;
5190
5265
  }
5266
+ function envConnectionCap(name, log12) {
5267
+ const raw = process.env[name];
5268
+ if (raw === void 0 || raw.trim() === "") return void 0;
5269
+ const value = Number(raw.trim());
5270
+ if (!Number.isInteger(value) || value < 1 || value > 1024) {
5271
+ try {
5272
+ log12?.(`ws: ignoring ${name}=${raw} (expected an integer between 1 and 1024)`);
5273
+ } catch {
5274
+ }
5275
+ return void 0;
5276
+ }
5277
+ return value;
5278
+ }
5191
5279
  function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
5192
5280
  const debug = (message) => {
5193
5281
  try {
@@ -5199,8 +5287,8 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
5199
5287
  hardTtlMs: options.hardTtlMs ?? RESPONSES_WS_HARD_TTL_MS,
5200
5288
  idleTtlMs: options.idleTtlMs ?? RESPONSES_WS_IDLE_TTL_MS,
5201
5289
  nurseryIdleTtlMs: options.nurseryIdleTtlMs ?? Math.min(RESPONSES_WS_NURSERY_IDLE_TTL_MS, options.idleTtlMs ?? RESPONSES_WS_IDLE_TTL_MS),
5202
- maxConnections: options.maxConnections ?? RESPONSES_WS_MAX_CONNECTIONS,
5203
- maxNurseryConnections: options.maxNurseryConnections ?? RESPONSES_WS_MAX_NURSERY_CONNECTIONS,
5290
+ maxConnections: options.maxConnections ?? envConnectionCap("CLODEX_WS_MAX_CONNECTIONS", log12) ?? RESPONSES_WS_MAX_CONNECTIONS,
5291
+ maxNurseryConnections: options.maxNurseryConnections ?? envConnectionCap("CLODEX_WS_MAX_NURSERY_CONNECTIONS", log12) ?? RESPONSES_WS_MAX_NURSERY_CONNECTIONS,
5204
5292
  now: options.now ?? Date.now
5205
5293
  };
5206
5294
  return async (_input, init) => {
@@ -5272,7 +5360,7 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
5272
5360
  debug("parallel request using an isolated socket");
5273
5361
  } else if (diagnosticEntry) {
5274
5362
  debug(
5275
- `history mismatch starting an additional chain; retained ${candidates.length} existing head(s) (${continuationMismatchSummary(diagnosticEntry, payload)})`
5363
+ `history mismatch starting an additional chain; retained ${candidates.length} existing head(s) (${continuationMismatchSummary(diagnosticEntry, payload, debug)})`
5276
5364
  );
5277
5365
  decision = "history_mismatch_new_head";
5278
5366
  } else if (partitionKey) {
@@ -5332,7 +5420,7 @@ function createResponsesWebSocketFetch(wsUrl, log12, options = {}) {
5332
5420
  ttlPausedMs: entry.ttlPausedMs,
5333
5421
  idleMs: Math.max(0, now - entry.lastUsedAt),
5334
5422
  promptChanges: changedPromptFields(entry.promptFieldHashes, promptFieldHashes),
5335
- mismatch: continuationMismatchDetails(entry, payload)
5423
+ mismatch: continuationMismatchDetails(entry, payload, debug)
5336
5424
  })),
5337
5425
  evictions
5338
5426
  }, diagnosticCorrelation);