@link-assistant/hive-mind 2.0.8 → 2.0.9

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 2.0.9
4
+
5
+ ### Patch Changes
6
+
7
+ - c8b241a: Fix Claude public cost estimates for 1-hour prompt-cache writes by pricing `cache_creation.ephemeral_1h_input_tokens` at the documented 2x input rate instead of the 5-minute cache-write rate.
8
+
3
9
  ## 2.0.8
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "2.0.8",
3
+ "version": "2.0.9",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -111,17 +111,27 @@ export const displayModelUsage = async (usage, log) => {
111
111
  await log('');
112
112
  await log(' Cost Calculation (USD):');
113
113
  const breakdown = usage.costBreakdown;
114
- const types = [
115
- { key: 'input', label: 'Input' },
116
- { key: 'cacheWrite', label: 'Cache write' },
117
- { key: 'cacheRead', label: 'Cache read' },
118
- { key: 'output', label: 'Output' },
119
- ];
120
- for (const { key, label } of types) {
121
- if (breakdown[key].tokens > 0) {
122
- await log(` ${label}: ${formatNumber(breakdown[key].tokens)} tokens × $${breakdown[key].costPerMillion}/M = $${new Decimal(breakdown[key].cost).toFixed(6)}`);
114
+ if (breakdown.input.tokens > 0) {
115
+ await log(` Input: ${formatNumber(breakdown.input.tokens)} tokens × $${breakdown.input.costPerMillion}/M = $${new Decimal(breakdown.input.cost).toFixed(6)}`);
116
+ }
117
+ if (breakdown.cacheWrite?.tokens > 0) {
118
+ if (breakdown.cacheWrite.hasExplicitTtlSplit) {
119
+ if (breakdown.cacheWrite5m.tokens > 0) {
120
+ await log(` Cache write (5m): ${formatNumber(breakdown.cacheWrite5m.tokens)} tokens × $${breakdown.cacheWrite5m.costPerMillion}/M = $${new Decimal(breakdown.cacheWrite5m.cost).toFixed(6)}`);
121
+ }
122
+ if (breakdown.cacheWrite1h.tokens > 0) {
123
+ await log(` Cache write (1h): ${formatNumber(breakdown.cacheWrite1h.tokens)} tokens × $${breakdown.cacheWrite1h.costPerMillion}/M = $${new Decimal(breakdown.cacheWrite1h.cost).toFixed(6)}`);
124
+ }
125
+ } else {
126
+ await log(` Cache write: ${formatNumber(breakdown.cacheWrite.tokens)} tokens × $${breakdown.cacheWrite.costPerMillion}/M = $${new Decimal(breakdown.cacheWrite.cost).toFixed(6)}`);
123
127
  }
124
128
  }
129
+ if (breakdown.cacheRead.tokens > 0) {
130
+ await log(` Cache read: ${formatNumber(breakdown.cacheRead.tokens)} tokens × $${breakdown.cacheRead.costPerMillion}/M = $${new Decimal(breakdown.cacheRead.cost).toFixed(6)}`);
131
+ }
132
+ if (breakdown.output.tokens > 0) {
133
+ await log(` Output: ${formatNumber(breakdown.output.tokens)} tokens × $${breakdown.output.costPerMillion}/M = $${new Decimal(breakdown.output.cost).toFixed(6)}`);
134
+ }
125
135
  // Issue #1710: itemise server-tool charges so the residual that puzzled
126
136
  // readers in PR #1707 ($0.04 web_search) is visible in the breakdown.
127
137
  if (breakdown.webSearch && breakdown.webSearch.requests > 0) {
@@ -8,12 +8,22 @@
8
8
  import Decimal from 'decimal.js-light';
9
9
  import { SERVER_TOOL_PRICING_USD } from './anthropic-server-tool-pricing.lib.mjs';
10
10
 
11
+ const getCacheWrite5mPrice = cost => cost.cache_write_5m ?? cost.cache_write ?? 0;
12
+
13
+ const getCacheWrite1hPrice = (cost, cacheWrite5mPrice) => {
14
+ if (cost.cache_write_1h !== undefined && cost.cache_write_1h !== null) return cost.cache_write_1h;
15
+ if (cost.input) return new Decimal(cost.input).mul(2).toNumber();
16
+ if (cacheWrite5mPrice) return new Decimal(cacheWrite5mPrice).mul(1.6).toNumber();
17
+ return 0;
18
+ };
19
+
11
20
  /**
12
21
  * Calculate USD cost for a model's usage with optional detailed breakdown.
13
22
  *
14
23
  * Cost components (Issue #1600 uses Decimal for precision):
15
24
  * - input × cost.input / 1M
16
- * - cacheWrite × cost.cache_write / 1M
25
+ * - cacheWrite5m × cost.cache_write / 1M
26
+ * - cacheWrite1h × (cost.cache_write_1h || cost.input × 2) / 1M
17
27
  * - cacheRead × cost.cache_read / 1M
18
28
  * - output × cost.output / 1M
19
29
  * - webSearch × $0.01 / request (Issue #1710 — see SERVER_TOOL_PRICING_USD)
@@ -32,6 +42,8 @@ export const calculateModelCost = (usage, modelInfo, includeBreakdown = false) =
32
42
  const breakdown = {
33
43
  input: { tokens: 0, costPerMillion: 0, cost: 0 },
34
44
  cacheWrite: { tokens: 0, costPerMillion: 0, cost: 0 },
45
+ cacheWrite5m: { tokens: 0, costPerMillion: 0, cost: 0 },
46
+ cacheWrite1h: { tokens: 0, costPerMillion: 0, cost: 0 },
35
47
  cacheRead: { tokens: 0, costPerMillion: 0, cost: 0 },
36
48
  output: { tokens: 0, costPerMillion: 0, cost: 0 },
37
49
  // Issue #1710: server-side tool usage (web_search) is billed per-request,
@@ -47,11 +59,35 @@ export const calculateModelCost = (usage, modelInfo, includeBreakdown = false) =
47
59
  cost: new Decimal(usage.inputTokens).div(million).mul(new Decimal(cost.input)).toNumber(),
48
60
  };
49
61
  }
50
- if (usage.cacheCreationTokens && cost.cache_write) {
62
+ const explicitCacheWrite5mTokens = usage.cacheCreation5mTokens || 0;
63
+ const explicitCacheWrite1hTokens = usage.cacheCreation1hTokens || 0;
64
+ const explicitCacheWriteTokens = explicitCacheWrite5mTokens + explicitCacheWrite1hTokens;
65
+ const cacheWriteTokens = Math.max(usage.cacheCreationTokens || 0, explicitCacheWriteTokens);
66
+ const hasCacheWriteTtlSplit = explicitCacheWriteTokens > 0;
67
+ const unsplitCacheWriteTokens = hasCacheWriteTtlSplit ? Math.max(0, cacheWriteTokens - explicitCacheWriteTokens) : cacheWriteTokens;
68
+ const cacheWrite5mTokens = hasCacheWriteTtlSplit ? explicitCacheWrite5mTokens + unsplitCacheWriteTokens : cacheWriteTokens;
69
+ const cacheWrite1hTokens = hasCacheWriteTtlSplit ? explicitCacheWrite1hTokens : 0;
70
+ const cacheWrite5mPrice = getCacheWrite5mPrice(cost);
71
+ const cacheWrite1hPrice = getCacheWrite1hPrice(cost, cacheWrite5mPrice);
72
+ if (cacheWriteTokens && (cacheWrite5mPrice || cacheWrite1hPrice)) {
73
+ const cacheWrite5mCost = new Decimal(cacheWrite5mTokens).div(million).mul(new Decimal(cacheWrite5mPrice)).toNumber();
74
+ const cacheWrite1hCost = new Decimal(cacheWrite1hTokens).div(million).mul(new Decimal(cacheWrite1hPrice)).toNumber();
75
+ const cacheWriteCost = new Decimal(cacheWrite5mCost).plus(new Decimal(cacheWrite1hCost)).toNumber();
51
76
  breakdown.cacheWrite = {
52
- tokens: usage.cacheCreationTokens,
53
- costPerMillion: cost.cache_write,
54
- cost: new Decimal(usage.cacheCreationTokens).div(million).mul(new Decimal(cost.cache_write)).toNumber(),
77
+ tokens: cacheWriteTokens,
78
+ costPerMillion: hasCacheWriteTtlSplit ? new Decimal(cacheWriteCost).div(new Decimal(cacheWriteTokens)).mul(million).toNumber() : cacheWrite5mPrice,
79
+ cost: cacheWriteCost,
80
+ hasExplicitTtlSplit: hasCacheWriteTtlSplit,
81
+ };
82
+ breakdown.cacheWrite5m = {
83
+ tokens: cacheWrite5mTokens,
84
+ costPerMillion: cacheWrite5mPrice,
85
+ cost: cacheWrite5mCost,
86
+ };
87
+ breakdown.cacheWrite1h = {
88
+ tokens: cacheWrite1hTokens,
89
+ costPerMillion: cacheWrite1hPrice,
90
+ cost: cacheWrite1hCost,
55
91
  };
56
92
  }
57
93
  if (usage.cacheReadTokens && cost.cache_read) {