@link-assistant/hive-mind 1.47.0 → 1.47.1
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/claude.budget-stats.lib.mjs +32 -31
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.47.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3bbd66e: Improve Context and tokens usage output format: move percentage before unit label, parenthesize cached tokens in Total line, use consistent X / Y (Z%) format for output tokens when limit is known, and show sub-sessions under model heading instead of globally
|
|
8
|
+
|
|
3
9
|
## 1.47.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -165,16 +165,15 @@ export const displayBudgetStats = async (usage, tokenUsage, log) => {
|
|
|
165
165
|
const sub = subSessions[i];
|
|
166
166
|
const subPeak = sub.peakContextUsage || 0;
|
|
167
167
|
// Issue #1539: Only use peak per-request context for context window display.
|
|
168
|
-
//
|
|
169
|
-
// impossible percentages (e.g. 250%). When peak is unknown, skip context display.
|
|
168
|
+
// Issue #1547: Percentage before unit label: X / Y (Z%) input tokens
|
|
170
169
|
const parts = [];
|
|
171
170
|
if (contextLimit && subPeak > 0) {
|
|
172
171
|
const pct = ((subPeak / contextLimit) * 100).toFixed(0);
|
|
173
|
-
parts.push(`${formatNumber(subPeak)} / ${formatNumber(contextLimit)}
|
|
172
|
+
parts.push(`${formatNumber(subPeak)} / ${formatNumber(contextLimit)} (${pct}%) input tokens`);
|
|
174
173
|
}
|
|
175
174
|
if (outputLimit) {
|
|
176
175
|
const outPct = ((sub.outputTokens / outputLimit) * 100).toFixed(0);
|
|
177
|
-
parts.push(`${formatNumber(sub.outputTokens)} / ${formatNumber(outputLimit)}
|
|
176
|
+
parts.push(`${formatNumber(sub.outputTokens)} / ${formatNumber(outputLimit)} (${outPct}%) output tokens`);
|
|
178
177
|
}
|
|
179
178
|
if (parts.length > 0) {
|
|
180
179
|
await log(` ${i + 1}. Context window: ${parts.join(', ')}`);
|
|
@@ -182,14 +181,15 @@ export const displayBudgetStats = async (usage, tokenUsage, log) => {
|
|
|
182
181
|
}
|
|
183
182
|
} else if (peakContext > 0) {
|
|
184
183
|
// Single sub-session with known peak: single-line format
|
|
184
|
+
// Issue #1547: Percentage before unit label
|
|
185
185
|
const parts = [];
|
|
186
186
|
if (contextLimit) {
|
|
187
187
|
const pct = ((peakContext / contextLimit) * 100).toFixed(0);
|
|
188
|
-
parts.push(`${formatNumber(peakContext)} / ${formatNumber(contextLimit)}
|
|
188
|
+
parts.push(`${formatNumber(peakContext)} / ${formatNumber(contextLimit)} (${pct}%) input tokens`);
|
|
189
189
|
}
|
|
190
190
|
if (outputLimit) {
|
|
191
191
|
const outPct = ((usage.outputTokens / outputLimit) * 100).toFixed(0);
|
|
192
|
-
parts.push(`${formatNumber(usage.outputTokens)} / ${formatNumber(outputLimit)}
|
|
192
|
+
parts.push(`${formatNumber(usage.outputTokens)} / ${formatNumber(outputLimit)} (${outPct}%) output tokens`);
|
|
193
193
|
}
|
|
194
194
|
if (parts.length > 0) {
|
|
195
195
|
await log(` Context window: ${parts.join(', ')}`);
|
|
@@ -199,15 +199,20 @@ export const displayBudgetStats = async (usage, tokenUsage, log) => {
|
|
|
199
199
|
// Cumulative totals are shown on the Total line below — no duplication needed.
|
|
200
200
|
|
|
201
201
|
// Cumulative totals — single line
|
|
202
|
+
// Issue #1547: Parenthesized cached format and consistent output format
|
|
202
203
|
const totalInputNonCached = usage.inputTokens + usage.cacheCreationTokens;
|
|
203
204
|
const cachedTokens = usage.cacheReadTokens;
|
|
204
|
-
let totalLine
|
|
205
|
-
if (cachedTokens > 0)
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
let totalLine;
|
|
206
|
+
if (cachedTokens > 0) {
|
|
207
|
+
totalLine = `(${formatNumber(totalInputNonCached)} + ${formatNumber(cachedTokens)} cached) input tokens`;
|
|
208
|
+
} else {
|
|
209
|
+
totalLine = `${formatNumber(totalInputNonCached)} input tokens`;
|
|
210
|
+
}
|
|
208
211
|
if (peakContext === 0 && outputLimit) {
|
|
209
212
|
const outPct = ((usage.outputTokens / outputLimit) * 100).toFixed(0);
|
|
210
|
-
totalLine +=
|
|
213
|
+
totalLine += `, ${formatNumber(usage.outputTokens)} / ${formatNumber(outputLimit)} (${outPct}%) output tokens`;
|
|
214
|
+
} else {
|
|
215
|
+
totalLine += `, ${formatNumber(usage.outputTokens)} output tokens`;
|
|
211
216
|
}
|
|
212
217
|
await log(` Total: ${totalLine}`);
|
|
213
218
|
};
|
|
@@ -325,12 +330,12 @@ const formatContextOutputLine = (peakContext, contextLimit, outputTokens, output
|
|
|
325
330
|
// context window metrics and produce impossible percentages (e.g. 250%).
|
|
326
331
|
if (peakContext > 0) {
|
|
327
332
|
const pct = ((peakContext / contextLimit) * 100).toFixed(0);
|
|
328
|
-
parts.push(`${formatTokensCompact(peakContext)} / ${formatTokensCompact(contextLimit)}
|
|
333
|
+
parts.push(`${formatTokensCompact(peakContext)} / ${formatTokensCompact(contextLimit)} (${pct}%) input tokens`);
|
|
329
334
|
}
|
|
330
335
|
}
|
|
331
336
|
if (outputLimit) {
|
|
332
337
|
const outPct = ((outputTokens / outputLimit) * 100).toFixed(0);
|
|
333
|
-
parts.push(`${formatTokensCompact(outputTokens)} / ${formatTokensCompact(outputLimit)}
|
|
338
|
+
parts.push(`${formatTokensCompact(outputTokens)} / ${formatTokensCompact(outputLimit)} (${outPct}%) output tokens`);
|
|
334
339
|
}
|
|
335
340
|
if (parts.length === 0) return '';
|
|
336
341
|
return `\n${prefix}Context window: ${parts.join(', ')}`;
|
|
@@ -364,15 +369,6 @@ export const buildBudgetStatsString = tokenUsage => {
|
|
|
364
369
|
const subSessions = tokenUsage.subSessions || [];
|
|
365
370
|
const hasMultipleSubSessions = subSessions.length > 1;
|
|
366
371
|
|
|
367
|
-
if (isMultiModel && hasMultipleSubSessions) {
|
|
368
|
-
// Issue #1508: For multi-model sessions, show global sub-sessions once (not per-model),
|
|
369
|
-
// since sub-sessions track compactification boundaries which are session-wide.
|
|
370
|
-
// Per-model context/output limits are shown below under each model heading.
|
|
371
|
-
const primaryModelId = modelIds[0];
|
|
372
|
-
const primaryUsage = tokenUsage.modelUsage[primaryModelId];
|
|
373
|
-
stats += formatSubSessionsList(subSessions, primaryUsage.modelInfo?.limit?.context, primaryUsage.modelInfo?.limit?.output);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
372
|
for (const modelId of modelIds) {
|
|
377
373
|
const usage = tokenUsage.modelUsage[modelId];
|
|
378
374
|
const modelName = usage.modelName || modelId;
|
|
@@ -383,8 +379,9 @@ export const buildBudgetStatsString = tokenUsage => {
|
|
|
383
379
|
|
|
384
380
|
const peakContext = usage.peakContextUsage || 0;
|
|
385
381
|
|
|
386
|
-
if (!isMultiModel
|
|
387
|
-
//
|
|
382
|
+
if (hasMultipleSubSessions && (!isMultiModel || modelId === modelIds[0])) {
|
|
383
|
+
// Issue #1547: Show sub-sessions under the primary model heading (not globally).
|
|
384
|
+
// For single-model sessions, show under that model. For multi-model, under the first model.
|
|
388
385
|
stats += formatSubSessionsList(subSessions, contextLimit, outputLimit);
|
|
389
386
|
} else if (peakContext > 0) {
|
|
390
387
|
// Issue #1526: Single line format for context window + output tokens
|
|
@@ -394,18 +391,22 @@ export const buildBudgetStatsString = tokenUsage => {
|
|
|
394
391
|
// Cumulative totals are shown on the Total line below — no duplication needed.
|
|
395
392
|
|
|
396
393
|
// Cumulative totals per model: input tokens + cached shown separately
|
|
397
|
-
// Issue #
|
|
394
|
+
// Issue #1547: Parenthesized cached format: (X + Y cached) input tokens
|
|
398
395
|
const totalInputNonCached = usage.inputTokens + usage.cacheCreationTokens;
|
|
399
396
|
const cachedTokens = usage.cacheReadTokens;
|
|
400
|
-
let totalLine
|
|
401
|
-
if (cachedTokens > 0)
|
|
402
|
-
|
|
397
|
+
let totalLine;
|
|
398
|
+
if (cachedTokens > 0) {
|
|
399
|
+
totalLine = `(${formatTokensCompact(totalInputNonCached)} + ${formatTokensCompact(cachedTokens)} cached) input tokens`;
|
|
400
|
+
} else {
|
|
401
|
+
totalLine = `${formatTokensCompact(totalInputNonCached)} input tokens`;
|
|
402
|
+
}
|
|
403
403
|
|
|
404
|
-
// Issue #
|
|
405
|
-
// output token percentage in the Total line so no data is lost.
|
|
404
|
+
// Issue #1547: Consistent output format — use X / Y (Z%) output tokens when limit known
|
|
406
405
|
if (peakContext === 0 && outputLimit) {
|
|
407
406
|
const outPct = ((usage.outputTokens / outputLimit) * 100).toFixed(0);
|
|
408
|
-
totalLine +=
|
|
407
|
+
totalLine += `, ${formatTokensCompact(usage.outputTokens)} / ${formatTokensCompact(outputLimit)} (${outPct}%) output tokens`;
|
|
408
|
+
} else {
|
|
409
|
+
totalLine += `, ${formatTokensCompact(usage.outputTokens)} output tokens`;
|
|
409
410
|
}
|
|
410
411
|
|
|
411
412
|
// Issue #1508: Show per-model cost when available
|