codex-copilot-dx 0.9.4 → 0.9.5

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/README.md CHANGED
@@ -107,7 +107,7 @@ This performs a fresh, read-only GitHub Copilot model-directory lookup without s
107
107
 
108
108
  Interactive terminals use aligned tables for `models`, `auth status`, and `usage`. Redirected or piped output retains the plain-text layout for scripts; use `--format table` or `--format plain` when a command offers an explicit format override.
109
109
 
110
- `ccdx usage` and the dashboard Usage table show token cache hit rate for each model and the aggregate: cached input tokens divided by input tokens, weighted by token count rather than averaging request percentages. This describes the upstream prompt cache; the local history and image-transform caches are separate. A rate is `—` when input tokens are zero or any included record lacks valid paired input/cache counts. Older logs may omit explicit zero cache counts; new Responses usage records retain reported zeros. CLI tables keep existing token columns on narrow terminals and show rates below the table when the extra column does not fit.
110
+ `ccdx usage` and the dashboard Usage table show token cache hit rate for each model and the aggregate: recorded cached input tokens divided by recorded input tokens, weighted by token count rather than averaging request percentages. This describes the upstream prompt cache; the local history and image-transform caches are separate. Incomplete historical records do not hide a computable ratio: `~` marks a rate derived from incomplete counts. A rate is `—` when input tokens are zero, usable totals are missing, or token counts are invalid. Older logs may omit explicit zero cache counts; new Responses usage records retain reported zeros. CLI tables keep existing token columns on narrow terminals and show rates below the table when the extra column does not fit.
111
111
 
112
112
  ### Auto-review model
113
113
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-copilot-dx",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "description": "Use Codex App with GitHub Copilot",
5
5
  "author": "Dale Xiao",
6
6
  "type": "module",
@@ -64,7 +64,7 @@
64
64
  <div class="panel-heading"><h2>USAGE</h2><div class="heading-actions"><span id="usage-state">READING LOG</span><button id="refresh-usage" type="button">Refresh</button></div></div>
65
65
  <p id="usage-note" class="table-note">Aggregating local usage metadata…</p>
66
66
  <div class="table-wrap"><table class="usage-table"><thead><tr><th scope="col">MODEL</th><th scope="col">CALLS</th><th scope="col">INPUT</th><th scope="col">CACHE READ</th><th scope="col">OUTPUT</th><th scope="col">TOTAL</th><th scope="col">CACHE HIT</th></tr></thead><tbody id="usage-body"><tr><td colspan="7">Loading…</td></tr></tbody></table></div>
67
- <p class="hint">Cache hit = cached / input tokens. — = incomplete usage data or no input tokens.</p>
67
+ <p class="hint">Cache hit = recorded cached / input tokens. ~ = incomplete history. — = unavailable or invalid counts.</p>
68
68
  </section>
69
69
 
70
70
  <section class="lower" aria-label="Recent failures">
@@ -309,7 +309,7 @@ async function loadModels() {
309
309
 
310
310
  function usageValues(row) {
311
311
  const rate = Number.isFinite(row.cache_hit_rate) && row.cache_hit_rate >= 0 && row.cache_hit_rate <= 1
312
- ? `${(row.cache_hit_rate * 100).toFixed(1)}%` : "—";
312
+ ? `${row.cache_hit_rate_partial ? "~" : ""}${(row.cache_hit_rate * 100).toFixed(1)}%` : "—";
313
313
  return [row.model, number(row.requests), number(row.input_tokens), number(row.cache_read_tokens), number(row.output_tokens), number(row.total_tokens), rate];
314
314
  }
315
315
 
@@ -86,6 +86,7 @@ function usageRow(model, values) {
86
86
  input_tokens: finite(values.input_tokens),
87
87
  cache_read_tokens: cacheReadTokens(values) ?? null,
88
88
  cache_hit_rate: usageCacheHitRate(values),
89
+ cache_hit_rate_partial: values.cache_hit_unknown_requests > 0,
89
90
  output_tokens: finite(values.output_tokens),
90
91
  total_tokens: finite(values.total_tokens),
91
92
  };
package/src/usage.mjs CHANGED
@@ -277,6 +277,13 @@ export function summarizeUsage(records) {
277
277
  summary.totals.cache_hit_unknown_requests = (summary.totals.cache_hit_unknown_requests || 0) + 1;
278
278
  modelTotals.cache_hit_unknown_requests = (modelTotals.cache_hit_unknown_requests || 0) + 1;
279
279
  }
280
+ const cacheCounts = [record.usage?.cached_input_tokens, record.usage?.cache_read_input_tokens];
281
+ if ((input != null && (!Number.isFinite(input) || input < 0))
282
+ || cacheCounts.some((value) => value != null && (!Number.isFinite(value) || value < 0))
283
+ || (Number.isFinite(input) && Number.isFinite(cached) && cached > input)) {
284
+ summary.totals.cache_hit_invalid_requests = (summary.totals.cache_hit_invalid_requests || 0) + 1;
285
+ modelTotals.cache_hit_invalid_requests = (modelTotals.cache_hit_invalid_requests || 0) + 1;
286
+ }
280
287
  }
281
288
  return summary;
282
289
  }
@@ -315,14 +322,14 @@ export function cacheReadTokens(usage = {}) {
315
322
  export function usageCacheHitRate(usage = {}) {
316
323
  const input = usage.input_tokens;
317
324
  const cached = cacheReadTokens(usage);
318
- if (usage.cache_hit_unknown_requests > 0 || !Number.isFinite(input) || input <= 0
325
+ if (usage.cache_hit_invalid_requests > 0 || !Number.isFinite(input) || input <= 0
319
326
  || !Number.isFinite(cached) || cached < 0 || cached > input) return null;
320
327
  return cached / input;
321
328
  }
322
329
 
323
330
  function cacheHitPercent(usage) {
324
331
  const rate = usageCacheHitRate(usage);
325
- return rate === null ? "—" : `${(rate * 100).toFixed(1)}%`;
332
+ return rate === null ? "—" : `${usage.cache_hit_unknown_requests > 0 ? "~" : ""}${(rate * 100).toFixed(1)}%`;
326
333
  }
327
334
 
328
335
  function formatPlainUsageSummary(summary, filePath, { sanitize = false } = {}) {