@link-assistant/hive-mind 1.19.0 → 1.20.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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.20.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 1689caf: Fix agent tool pricing display to show correct provider
8
+ - Add proper model mapping for free models (kimi-k2.5-free, gpt-4o-mini, etc.)
9
+ - Add getProviderName helper function to detect provider from model ID
10
+ - Prioritize provider from model ID over API response to fix issue #1250
11
+ - Display correct provider names: Moonshot AI, OpenAI, Anthropic instead of generic "OpenCode Zen"
12
+
13
+ ## 1.20.0
14
+
15
+ ### Minor Changes
16
+
17
+ - 98a7582: Set kimi-k2.5-free as default model for --tool agent and enhance documentation with free model examples.
18
+
3
19
  ## 1.19.0
4
20
 
5
21
  ### Minor Changes
package/README.md CHANGED
@@ -474,8 +474,17 @@ All commands work in **group chats only** (not in private messages with the bot)
474
474
  Examples:
475
475
  /solve https://github.com/owner/repo/issues/123 --model sonnet
476
476
  /solve https://github.com/owner/repo/issues/123 --model opus --think max
477
+
478
+ Free Models (with --tool agent):
479
+ /solve https://github.com/owner/repo/issues/123 --tool agent --model kimi-k2.5-free
480
+ /solve https://github.com/owner/repo/issues/123 --tool agent --model minimax-m2.1-free
481
+ /solve https://github.com/owner/repo/issues/123 --tool agent --model gpt-5-nano
482
+ /solve https://github.com/owner/repo/issues/123 --tool agent --model glm-4.7-free
483
+ /solve https://github.com/owner/repo/issues/123 --tool agent --model big-pickle
477
484
  ```
478
485
 
486
+ > **šŸ“– Free Models Guide**: See [docs/FREE_MODELS.md](./docs/FREE_MODELS.md) for comprehensive information about all free models.
487
+
479
488
  #### `/hive` - Run Hive Orchestration
480
489
 
481
490
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.19.0",
3
+ "version": "1.20.1",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
package/src/agent.lib.mjs CHANGED
@@ -79,17 +79,51 @@ export const parseAgentTokenUsage = output => {
79
79
  return usage;
80
80
  };
81
81
 
82
+ /**
83
+ * Helper function to get original provider name from provider identifier
84
+ * Used for calculating public pricing estimates based on original provider prices
85
+ * @param {string} providerId - Provider identifier (e.g., 'openai', 'anthropic', 'moonshot')
86
+ * @returns {string} Human-readable provider name for pricing reference
87
+ */
88
+ const getOriginalProviderName = providerId => {
89
+ if (!providerId) return null;
90
+
91
+ const providerMap = {
92
+ openai: 'OpenAI',
93
+ anthropic: 'Anthropic',
94
+ moonshot: 'Moonshot AI',
95
+ google: 'Google',
96
+ opencode: 'OpenCode Zen',
97
+ grok: 'xAI',
98
+ };
99
+
100
+ return providerMap[providerId] || providerId.charAt(0).toUpperCase() + providerId.slice(1);
101
+ };
102
+
82
103
  /**
83
104
  * Calculate pricing for agent tool usage using models.dev API
105
+ * Issue #1250: Shows actual provider (OpenCode Zen) and calculates public pricing estimate
106
+ * based on original provider prices (Moonshot AI, OpenAI, Anthropic, etc.)
107
+ *
84
108
  * @param {string} modelId - The model ID used (e.g., 'opencode/grok-code')
85
109
  * @param {Object} tokenUsage - Token usage data from parseAgentTokenUsage
86
- * @returns {Object} Pricing information
110
+ * @returns {Object} Pricing information with:
111
+ * - provider: Always "OpenCode Zen" (actual provider)
112
+ * - originalProvider: The original model provider for pricing reference
113
+ * - totalCostUSD: Public pricing estimate based on original provider prices
114
+ * - opencodeCost: Actual billed cost from OpenCode Zen (free for most models)
87
115
  */
88
116
  export const calculateAgentPricing = async (modelId, tokenUsage) => {
89
117
  // Extract the model name from provider/model format
90
118
  // e.g., 'opencode/grok-code' -> 'grok-code'
91
119
  const modelName = modelId.includes('/') ? modelId.split('/').pop() : modelId;
92
120
 
121
+ // Extract provider from model ID to determine original provider for pricing
122
+ const providerFromModel = modelId.includes('/') ? modelId.split('/')[0] : null;
123
+
124
+ // Get original provider name for pricing reference
125
+ const originalProvider = getOriginalProviderName(providerFromModel);
126
+
93
127
  try {
94
128
  // Fetch model info from models.dev API
95
129
  const modelInfo = await fetchModelInfo(modelName);
@@ -97,7 +131,7 @@ export const calculateAgentPricing = async (modelId, tokenUsage) => {
97
131
  if (modelInfo && modelInfo.cost) {
98
132
  const cost = modelInfo.cost;
99
133
 
100
- // Calculate cost based on token usage
134
+ // Calculate public pricing estimate based on original provider prices
101
135
  // Prices are per 1M tokens, so divide by 1,000,000
102
136
  const inputCost = (tokenUsage.inputTokens * (cost.input || 0)) / 1_000_000;
103
137
  const outputCost = (tokenUsage.outputTokens * (cost.output || 0)) / 1_000_000;
@@ -106,10 +140,17 @@ export const calculateAgentPricing = async (modelId, tokenUsage) => {
106
140
 
107
141
  const totalCost = inputCost + outputCost + cacheReadCost + cacheWriteCost;
108
142
 
143
+ // Determine if this is a free model from OpenCode Zen
144
+ // Models accessed via OpenCode Zen are free, regardless of original provider pricing
145
+ const isOpencodeFreeModel = providerFromModel === 'opencode' || modelName.toLowerCase().includes('free') || modelName.toLowerCase().includes('grok') || providerFromModel === 'moonshot' || providerFromModel === 'openai' || providerFromModel === 'anthropic';
146
+
109
147
  return {
110
148
  modelId,
111
149
  modelName: modelInfo.name || modelName,
112
- provider: modelInfo.provider || 'OpenCode Zen',
150
+ // Issue #1250: Always show OpenCode Zen as actual provider
151
+ provider: 'OpenCode Zen',
152
+ // Store original provider for reference in pricing display
153
+ originalProvider: originalProvider || modelInfo.provider || null,
113
154
  pricing: {
114
155
  inputPerMillion: cost.input || 0,
115
156
  outputPerMillion: cost.output || 0,
@@ -123,18 +164,26 @@ export const calculateAgentPricing = async (modelId, tokenUsage) => {
123
164
  cacheRead: cacheReadCost,
124
165
  cacheWrite: cacheWriteCost,
125
166
  },
167
+ // Public pricing estimate based on original provider prices
126
168
  totalCostUSD: totalCost,
169
+ // Actual cost from OpenCode Zen (free for supported models)
170
+ opencodeCost: isOpencodeFreeModel ? 0 : totalCost,
171
+ // Keep for backward compatibility - indicates if model has zero pricing
127
172
  isFreeModel: cost.input === 0 && cost.output === 0,
173
+ // New flag to indicate if OpenCode Zen provides this model for free
174
+ isOpencodeFreeModel,
128
175
  };
129
176
  }
130
-
131
177
  // Model not found in API, return what we have
132
178
  return {
133
179
  modelId,
134
180
  modelName,
135
- provider: 'Unknown',
181
+ provider: 'OpenCode Zen',
182
+ originalProvider,
136
183
  tokenUsage,
137
184
  totalCostUSD: null,
185
+ opencodeCost: 0, // OpenCode Zen is free
186
+ isOpencodeFreeModel: true,
138
187
  error: 'Model not found in models.dev API',
139
188
  };
140
189
  } catch (error) {
@@ -142,8 +191,12 @@ export const calculateAgentPricing = async (modelId, tokenUsage) => {
142
191
  return {
143
192
  modelId,
144
193
  modelName,
194
+ provider: 'OpenCode Zen',
195
+ originalProvider,
145
196
  tokenUsage,
146
197
  totalCostUSD: null,
198
+ opencodeCost: 0, // OpenCode Zen is free
199
+ isOpencodeFreeModel: true,
147
200
  error: error.message,
148
201
  };
149
202
  }
@@ -163,6 +216,12 @@ export const mapModelToId = model => {
163
216
  haiku: 'anthropic/claude-3-5-haiku',
164
217
  opus: 'anthropic/claude-3-opus',
165
218
  'gemini-3-pro': 'google/gemini-3-pro',
219
+ // Free models mapping for issue #1250
220
+ 'kimi-k2.5-free': 'moonshot/kimi-k2.5-free',
221
+ 'gpt-4o-mini': 'openai/gpt-4o-mini',
222
+ 'gpt-4o': 'openai/gpt-4o',
223
+ 'claude-3.5-haiku': 'anthropic/claude-3.5-haiku',
224
+ 'claude-3.5-sonnet': 'anthropic/claude-3.5-sonnet',
166
225
  };
167
226
 
168
227
  // Return mapped model ID if it's an alias, otherwise return as-is
@@ -22,25 +22,50 @@ import { uploadLogWithGhUploadLog } from './log-upload.lib.mjs';
22
22
 
23
23
  /**
24
24
  * Build cost estimation string for log comments
25
+ * Issue #1250: Enhanced to show both public pricing estimate and actual provider cost
26
+ *
25
27
  * @param {number|null} totalCostUSD - Public pricing estimate
26
28
  * @param {number|null} anthropicTotalCostUSD - Cost calculated by Anthropic (Claude-specific)
27
29
  * @param {Object|null} pricingInfo - Pricing info from agent tool
30
+ * - opencodeCost: Actual billed cost from OpenCode Zen (for agent tool)
31
+ * - isOpencodeFreeModel: Whether OpenCode Zen provides this model for free
32
+ * - originalProvider: Original provider for pricing reference
28
33
  * @returns {string} Formatted cost info string for markdown (empty if no data available)
29
34
  */
30
35
  const buildCostInfoString = (totalCostUSD, anthropicTotalCostUSD, pricingInfo) => {
31
36
  // Issue #1015: Don't show cost section when all values are unknown (clutters output)
32
37
  const hasPublic = totalCostUSD !== null && totalCostUSD !== undefined;
33
38
  const hasAnthropic = anthropicTotalCostUSD !== null && anthropicTotalCostUSD !== undefined;
34
- const hasPricing = pricingInfo && (pricingInfo.modelName || pricingInfo.tokenUsage || pricingInfo.isFreeModel);
35
- if (!hasPublic && !hasAnthropic && !hasPricing) return '';
39
+ const hasPricing = pricingInfo && (pricingInfo.modelName || pricingInfo.tokenUsage || pricingInfo.isFreeModel || pricingInfo.isOpencodeFreeModel);
40
+ // Issue #1250: Check for OpenCode Zen actual cost
41
+ const hasOpencodeCost = pricingInfo?.opencodeCost !== null && pricingInfo?.opencodeCost !== undefined;
42
+ if (!hasPublic && !hasAnthropic && !hasPricing && !hasOpencodeCost) return '';
36
43
  let costInfo = '\n\nšŸ’° **Cost estimation:**';
37
44
  if (pricingInfo?.modelName) {
38
45
  costInfo += `\n- Model: ${pricingInfo.modelName}`;
39
46
  if (pricingInfo.provider) costInfo += `\n- Provider: ${pricingInfo.provider}`;
40
47
  }
48
+ // Issue #1250: Show public pricing estimate based on original provider prices
41
49
  if (hasPublic) {
42
- costInfo += pricingInfo?.isFreeModel ? '\n- Public pricing estimate: $0.00 (Free model)' : `\n- Public pricing estimate: $${totalCostUSD.toFixed(6)} USD`;
43
- } else if (hasPricing) costInfo += '\n- Public pricing estimate: unknown';
50
+ // For models with zero pricing from original provider, show as free
51
+ if (pricingInfo?.isFreeModel && totalCostUSD === 0) {
52
+ costInfo += '\n- Public pricing estimate: $0.00 (Free model)';
53
+ } else {
54
+ // Show actual public pricing estimate with original provider reference
55
+ const originalProviderRef = pricingInfo?.originalProvider ? ` (based on ${pricingInfo.originalProvider} prices)` : '';
56
+ costInfo += `\n- Public pricing estimate: $${totalCostUSD.toFixed(6)}${originalProviderRef}`;
57
+ }
58
+ } else if (hasPricing) {
59
+ costInfo += '\n- Public pricing estimate: unknown';
60
+ }
61
+ // Issue #1250: Show actual cost from OpenCode Zen for agent tool
62
+ if (hasOpencodeCost) {
63
+ if (pricingInfo.isOpencodeFreeModel) {
64
+ costInfo += '\n- Calculated by OpenCode Zen: $0.00 (Free model)';
65
+ } else {
66
+ costInfo += `\n- Calculated by OpenCode Zen: $${pricingInfo.opencodeCost.toFixed(6)}`;
67
+ }
68
+ }
44
69
  if (pricingInfo?.tokenUsage) {
45
70
  const u = pricingInfo.tokenUsage;
46
71
  let tokenInfo = `\n- Token usage: ${u.inputTokens?.toLocaleString() || 0} input, ${u.outputTokens?.toLocaleString() || 0} output`;
@@ -399,7 +399,7 @@ export const createYargsConfig = yargsInstance => {
399
399
  } else if (currentParsedArgs?.tool === 'codex') {
400
400
  return 'gpt-5';
401
401
  } else if (currentParsedArgs?.tool === 'agent') {
402
- return 'grok-code';
402
+ return 'kimi-k2.5-free';
403
403
  }
404
404
  return 'sonnet';
405
405
  },
@@ -528,7 +528,7 @@ export const parseArguments = async (yargs, hideBin) => {
528
528
  argv.model = 'gpt-5';
529
529
  } else if (argv.tool === 'agent' && !modelExplicitlyProvided) {
530
530
  // User did not explicitly provide --model, so use the correct default for agent
531
- argv.model = 'grok-code';
531
+ argv.model = 'kimi-k2.5-free';
532
532
  }
533
533
 
534
534
  // Tool-specific defaults for --claude-file and --gitkeep-file