@link-assistant/hive-mind 1.11.3 → 1.11.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/CHANGELOG.md +22 -0
- package/README.md +4 -0
- package/package.json +1 -1
- package/src/agent.lib.mjs +3 -2
- package/src/config.lib.mjs +1 -1
- package/src/model-validation.lib.mjs +9 -7
- package/src/solve.mjs +8 -2
- package/src/solve.results.lib.mjs +8 -4
- package/src/telegram-solve-queue.lib.mjs +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.11.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7d3387c: Fix duplicate Solution Draft Log comments on GitHub PRs
|
|
8
|
+
|
|
9
|
+
When a Claude session ends with uncommitted changes and --attach-logs is enabled, the solution draft log was being uploaded twice - once by verifyResults() during normal completion, and again after temporary watch mode completes. This fix tracks whether logs were already uploaded and skips the duplicate upload.
|
|
10
|
+
|
|
11
|
+
## 1.11.4
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- b8318dd: fix: support opencode/gpt-5-nano and gpt-5-nano for --tool agent (Issue #1185)
|
|
16
|
+
|
|
17
|
+
Fixed AGENT_MODELS mapping to correctly support free OpenCode Zen models:
|
|
18
|
+
- `gpt-5-nano` short alias now correctly maps to `opencode/gpt-5-nano` (previously incorrectly mapped to `openai/gpt-5-nano`)
|
|
19
|
+
- `opencode/gpt-5-nano` full model ID is now recognized as valid
|
|
20
|
+
- Updated `mapModelToId` function in agent.lib.mjs to use correct provider prefix
|
|
21
|
+
- Fixed regex filter in `getAvailableModelNames` to include `gpt-5-nano` in available models display
|
|
22
|
+
- Added comprehensive test suite with 18 tests for agent model validation
|
|
23
|
+
- Added case study documentation with root cause analysis
|
|
24
|
+
|
|
3
25
|
## 1.11.3
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -644,6 +644,10 @@ grep -E '\(cd /tmp/gh-issue-solver-[0-9]+ && claude --resume [0-9a-f-]{36}\)' hi
|
|
|
644
644
|
- `gh auth login` - GitHub CLI authentication
|
|
645
645
|
- `claude-profiles` - Claude authentication profile migration to server
|
|
646
646
|
|
|
647
|
+
**OpenRouter Integration:**
|
|
648
|
+
|
|
649
|
+
Use OpenRouter to access 500+ AI models from 60+ providers with a single API key. See [docs/OPENROUTER.md](./docs/OPENROUTER.md) for setup instructions covering both Claude Code CLI and @link-assistant/agent.
|
|
650
|
+
|
|
647
651
|
**Environment Variables & Advanced Options:**
|
|
648
652
|
|
|
649
653
|
For comprehensive configuration including environment variables, timeouts, retry limits, Telegram bot settings, YouTrack integration, and all CLI options, see [docs/CONFIGURATION.md](./docs/CONFIGURATION.md).
|
package/package.json
CHANGED
package/src/agent.lib.mjs
CHANGED
|
@@ -150,14 +150,15 @@ export const calculateAgentPricing = async (modelId, tokenUsage) => {
|
|
|
150
150
|
};
|
|
151
151
|
|
|
152
152
|
// Model mapping to translate aliases to full model IDs for Agent
|
|
153
|
-
// Agent uses OpenCode's JSON interface and models
|
|
153
|
+
// Agent uses OpenCode Zen's JSON interface and models
|
|
154
|
+
// Issue #1185: Free models use opencode/ prefix (not openai/)
|
|
154
155
|
export const mapModelToId = model => {
|
|
155
156
|
const modelMap = {
|
|
156
157
|
grok: 'opencode/grok-code',
|
|
157
158
|
'grok-code': 'opencode/grok-code',
|
|
158
159
|
'grok-code-fast-1': 'opencode/grok-code',
|
|
159
160
|
'big-pickle': 'opencode/big-pickle',
|
|
160
|
-
'gpt-5-nano': '
|
|
161
|
+
'gpt-5-nano': 'opencode/gpt-5-nano',
|
|
161
162
|
sonnet: 'anthropic/claude-3-5-sonnet',
|
|
162
163
|
haiku: 'anthropic/claude-3-5-haiku',
|
|
163
164
|
opus: 'anthropic/claude-3-opus',
|
package/src/config.lib.mjs
CHANGED
|
@@ -194,7 +194,7 @@ export const cacheTtl = {
|
|
|
194
194
|
api: parseIntWithDefault('HIVE_MIND_API_CACHE_TTL_MS', 3 * 60 * 1000), // 3 minutes
|
|
195
195
|
// Claude Usage API cache TTL - must be at least 20 minutes to avoid rate limiting
|
|
196
196
|
// The API returns null values when called too frequently
|
|
197
|
-
usageApi: parseIntWithDefault('HIVE_MIND_USAGE_API_CACHE_TTL_MS',
|
|
197
|
+
usageApi: parseIntWithDefault('HIVE_MIND_USAGE_API_CACHE_TTL_MS', 10 * 60 * 1000), // 10 minutes
|
|
198
198
|
// System metrics cache TTL (RAM, CPU, disk)
|
|
199
199
|
system: parseIntWithDefault('HIVE_MIND_SYSTEM_CACHE_TTL_MS', 2 * 60 * 1000), // 2 minutes
|
|
200
200
|
};
|
|
@@ -66,21 +66,22 @@ export const CODEX_MODELS = {
|
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
export const AGENT_MODELS = {
|
|
69
|
-
// Free models (via OpenCode)
|
|
69
|
+
// Free models (via OpenCode Zen)
|
|
70
|
+
// Issue #1185: Model IDs must use opencode/ prefix for OpenCode Zen models
|
|
70
71
|
grok: 'opencode/grok-code',
|
|
71
72
|
'grok-code': 'opencode/grok-code',
|
|
72
73
|
'grok-code-fast-1': 'opencode/grok-code',
|
|
73
74
|
'big-pickle': 'opencode/big-pickle',
|
|
74
|
-
'gpt-5-nano': '
|
|
75
|
+
'gpt-5-nano': 'opencode/gpt-5-nano',
|
|
75
76
|
// Premium models (requires OpenCode Zen subscription)
|
|
76
77
|
sonnet: 'anthropic/claude-3-5-sonnet',
|
|
77
78
|
haiku: 'anthropic/claude-3-5-haiku',
|
|
78
79
|
opus: 'anthropic/claude-3-opus',
|
|
79
80
|
'gemini-3-pro': 'google/gemini-3-pro',
|
|
80
|
-
// Full model IDs
|
|
81
|
+
// Full model IDs with provider prefix
|
|
81
82
|
'opencode/grok-code': 'opencode/grok-code',
|
|
82
83
|
'opencode/big-pickle': 'opencode/big-pickle',
|
|
83
|
-
'
|
|
84
|
+
'opencode/gpt-5-nano': 'opencode/gpt-5-nano',
|
|
84
85
|
'anthropic/claude-3-5-sonnet': 'anthropic/claude-3-5-sonnet',
|
|
85
86
|
'anthropic/claude-3-5-haiku': 'anthropic/claude-3-5-haiku',
|
|
86
87
|
'anthropic/claude-3-opus': 'anthropic/claude-3-opus',
|
|
@@ -118,11 +119,12 @@ export const getAvailableModelNames = tool => {
|
|
|
118
119
|
// Keep short aliases only - exclude:
|
|
119
120
|
// - Full model IDs with slashes (e.g., 'openai/gpt-4')
|
|
120
121
|
// - Long claude-prefixed model IDs (e.g., 'claude-sonnet-4-5-20250929')
|
|
121
|
-
// - Full gpt- prefixed IDs
|
|
122
|
-
// But keep
|
|
122
|
+
// - Full gpt- prefixed IDs that are ONLY version numbers (e.g., 'gpt-4', 'gpt-4o', 'gpt-5')
|
|
123
|
+
// But keep descriptive aliases like 'gpt-5-nano', 'gpt-5-codex', 'o3', 'o3-mini', 'gpt5', etc.
|
|
124
|
+
// Issue #1185: Updated regex to not filter out gpt-5-nano (a valid short alias)
|
|
123
125
|
if (key.includes('/')) return false;
|
|
124
126
|
if (key.match(/^claude-.*-\d{8}$/)) return false; // Full claude model IDs with date
|
|
125
|
-
if (key.match(/^gpt-\d
|
|
127
|
+
if (key.match(/^gpt-\d+[a-z]?$/)) return false; // Full gpt-N or gpt-No model IDs only (e.g., gpt-4, gpt-4o, gpt-5)
|
|
126
128
|
return true;
|
|
127
129
|
});
|
|
128
130
|
return [...new Set(aliases)];
|
package/src/solve.mjs
CHANGED
|
@@ -1159,7 +1159,9 @@ try {
|
|
|
1159
1159
|
// Pass shouldRestart to prevent early exit when auto-restart is needed
|
|
1160
1160
|
// Include agent tool pricing data when available (publicPricingEstimate, pricingInfo)
|
|
1161
1161
|
// Issue #1088: Pass errorDuringExecution for "Finished with errors" state
|
|
1162
|
-
|
|
1162
|
+
// Issue #1154: Track if logs were already uploaded to prevent duplicates
|
|
1163
|
+
const verifyResult = await verifyResults(owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart, sessionId, tempDir, anthropicTotalCostUSD, publicPricingEstimate, pricingInfo, errorDuringExecution);
|
|
1164
|
+
const logsAlreadyUploaded = verifyResult?.logUploadSuccess || false;
|
|
1163
1165
|
|
|
1164
1166
|
// Start watch mode if enabled OR if we need to handle uncommitted changes
|
|
1165
1167
|
if (argv.verbose) {
|
|
@@ -1246,7 +1248,8 @@ try {
|
|
|
1246
1248
|
}
|
|
1247
1249
|
|
|
1248
1250
|
// Attach updated logs to PR after auto-restart completes
|
|
1249
|
-
if
|
|
1251
|
+
// Issue #1154: Skip if logs were already uploaded by verifyResults() to prevent duplicates
|
|
1252
|
+
if (shouldAttachLogs && prNumber && !logsAlreadyUploaded) {
|
|
1250
1253
|
await log('📎 Uploading working session logs to Pull Request...');
|
|
1251
1254
|
try {
|
|
1252
1255
|
const logUploadSuccess = await attachLogToGitHub({
|
|
@@ -1273,6 +1276,9 @@ try {
|
|
|
1273
1276
|
} catch (uploadError) {
|
|
1274
1277
|
await log(`⚠️ Error uploading logs: ${uploadError.message}`, { level: 'warning' });
|
|
1275
1278
|
}
|
|
1279
|
+
} else if (logsAlreadyUploaded) {
|
|
1280
|
+
await log('ℹ️ Logs already uploaded by verifyResults, skipping duplicate upload', { verbose: true });
|
|
1281
|
+
logsAttached = true;
|
|
1276
1282
|
}
|
|
1277
1283
|
}
|
|
1278
1284
|
|
|
@@ -564,7 +564,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
|
|
|
564
564
|
if (!argv.watch && !shouldRestart) {
|
|
565
565
|
await safeExit(0, 'Process completed successfully');
|
|
566
566
|
}
|
|
567
|
-
|
|
567
|
+
// Issue #1154: Return logUploadSuccess to prevent duplicate log uploads
|
|
568
|
+
return { logUploadSuccess }; // Return for watch mode or auto-restart
|
|
568
569
|
} else {
|
|
569
570
|
await log(` ℹ️ Found pull request #${pr.number} but it appears to be from a different session`);
|
|
570
571
|
}
|
|
@@ -627,7 +628,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
|
|
|
627
628
|
if (!argv.watch && !shouldRestart) {
|
|
628
629
|
await safeExit(0, 'Process completed successfully');
|
|
629
630
|
}
|
|
630
|
-
|
|
631
|
+
// Issue #1154: Return logUploadSuccess to prevent duplicate log uploads
|
|
632
|
+
return { logUploadSuccess: true }; // Return for watch mode or auto-restart
|
|
631
633
|
} else if (allComments.length > 0) {
|
|
632
634
|
await log(` ℹ️ Issue has ${allComments.length} existing comment(s)`);
|
|
633
635
|
} else {
|
|
@@ -645,7 +647,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
|
|
|
645
647
|
if (!argv.watch) {
|
|
646
648
|
await safeExit(0, 'Process completed successfully');
|
|
647
649
|
}
|
|
648
|
-
|
|
650
|
+
// Issue #1154: Return logUploadSuccess to prevent duplicate log uploads
|
|
651
|
+
return { logUploadSuccess: false }; // Return for watch mode
|
|
649
652
|
} catch (searchError) {
|
|
650
653
|
reportError(searchError, {
|
|
651
654
|
context: 'verify_pr_creation',
|
|
@@ -661,7 +664,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
|
|
|
661
664
|
if (!argv.watch) {
|
|
662
665
|
await safeExit(0, 'Process completed successfully');
|
|
663
666
|
}
|
|
664
|
-
|
|
667
|
+
// Issue #1154: Return logUploadSuccess to prevent duplicate log uploads
|
|
668
|
+
return { logUploadSuccess: false }; // Return for watch mode
|
|
665
669
|
}
|
|
666
670
|
};
|
|
667
671
|
|
|
@@ -41,9 +41,9 @@ export const QUEUE_CONFIG = {
|
|
|
41
41
|
|
|
42
42
|
// API limit thresholds (usage ratios: 0.0 - 1.0)
|
|
43
43
|
// All thresholds use >= comparison (inclusive)
|
|
44
|
-
CLAUDE_5_HOUR_SESSION_THRESHOLD: 0.
|
|
45
|
-
CLAUDE_WEEKLY_THRESHOLD: 0.
|
|
46
|
-
GITHUB_API_THRESHOLD: 0.
|
|
44
|
+
CLAUDE_5_HOUR_SESSION_THRESHOLD: 0.75, // One-at-a-time if 5-hour limit >= 75%
|
|
45
|
+
CLAUDE_WEEKLY_THRESHOLD: 0.97, // One-at-a-time if weekly limit >= 97%
|
|
46
|
+
GITHUB_API_THRESHOLD: 0.75, // Enqueue if GitHub >= 75% with parallel claude
|
|
47
47
|
|
|
48
48
|
// Timing
|
|
49
49
|
// MIN_START_INTERVAL_MS: Time to allow solve command to start actual claude process
|