@link-assistant/hive-mind 2.0.0 → 2.0.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 +49 -0
- package/package.json +1 -1
- package/src/claude.lib.mjs +7 -6
- package/src/usage-limit.lib.mjs +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 2.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 70e1542: fix(retry): treat 5-hour "session limit" and "weekly limit" 429s as account usage limits, not transient throttles (#1935)
|
|
8
|
+
|
|
9
|
+
A long-running solve session (588 turns, ~$70.62) hit Claude's **5-hour session
|
|
10
|
+
limit**. The Claude CLI surfaced it as a `result` event with `is_error: true`,
|
|
11
|
+
`api_error_status: 429`, and:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
You've hit your session limit · resets 4pm (UTC)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Instead of being treated as an **account usage limit** (post a comment with the
|
|
18
|
+
reset time + wait until the exact reset moment), it was put through the transient
|
|
19
|
+
exponential-backoff retry loop:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
⚠️ Server rate limited (429) detected. Retry 1/10 in 2 min (session preserved)...
|
|
23
|
+
Error: You've hit your session limit · resets 4pm (UTC)
|
|
24
|
+
⚠️ Server rate limited (429) detected. Retry 2/10 in 4 min (session preserved)...
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Each retry re-hit the same limit because the quota only frees at the reset time —
|
|
28
|
+
so the harness burned ~10 futile retries and never told the user when the limit
|
|
29
|
+
resets.
|
|
30
|
+
|
|
31
|
+
Root cause (regression from #1924): `src/claude.lib.mjs` set
|
|
32
|
+
`isRateLimitError = true` for **every** structured `api_error_status === 429`,
|
|
33
|
+
without checking whether the message was an account usage limit. Claude reports
|
|
34
|
+
**both** a transient throttle ("...not your usage limit...") and account
|
|
35
|
+
session/weekly limits with `api_error_status: 429`, so the unconditional check
|
|
36
|
+
swept genuine usage limits into the transient-retry path — ahead of the
|
|
37
|
+
`detectUsageLimit()` reset-time wait, which was therefore never reached.
|
|
38
|
+
|
|
39
|
+
Fix: `src/claude.lib.mjs` now only flags a structured 429 as a transient rate
|
|
40
|
+
limit when the message is **not** a usage limit
|
|
41
|
+
(`api_error_status === 429 && !isUsageLimitError(lastMessage)`), so session/weekly
|
|
42
|
+
limits fall through to the usage-limit handler that immediately posts a comment
|
|
43
|
+
and waits until the exact reset time (auto-resuming there with
|
|
44
|
+
`--auto-continue-limit`). `src/usage-limit.lib.mjs` additionally recognises the
|
|
45
|
+
"hit your session limit" / "hit your weekly limit" phrasing as a backstop (the
|
|
46
|
+
reset-time regex already matched "resets 4pm").
|
|
47
|
+
|
|
48
|
+
Added `tests/test-issue-1935-session-limit-429.mjs` (15 assertions) and a full
|
|
49
|
+
case study with timeline, blame history (PR #1924), root-cause analysis, and the
|
|
50
|
+
captured logs under `docs/case-studies/issue-1935`.
|
|
51
|
+
|
|
3
52
|
## 2.0.0
|
|
4
53
|
|
|
5
54
|
### Major Changes
|
package/package.json
CHANGED
package/src/claude.lib.mjs
CHANGED
|
@@ -9,7 +9,7 @@ const path = (await use('path')).default;
|
|
|
9
9
|
import { log, isENOSPC } from './lib.mjs';
|
|
10
10
|
import { reportError } from './sentry.lib.mjs';
|
|
11
11
|
import { timeouts, retryLimits, claudeCode, getClaudeEnv, getThinkingLevelToTokens, getTokensToThinkingLevel, supportsThinkingBudget, DEFAULT_MAX_THINKING_BUDGET, getMaxOutputTokensForModel } from './config.lib.mjs';
|
|
12
|
-
import { detectUsageLimit, formatUsageLimitMessage } from './usage-limit.lib.mjs';
|
|
12
|
+
import { detectUsageLimit, formatUsageLimitMessage, isUsageLimitError } from './usage-limit.lib.mjs';
|
|
13
13
|
import { createInteractiveHandler } from './interactive-mode.lib.mjs';
|
|
14
14
|
import { setupBidirectionalHandler, finalizeBidirectionalHandler, validateBidirectionalModeConfig, attachStreamingInput } from './bidirectional-interactive.lib.mjs';
|
|
15
15
|
import { initProgressMonitoring } from './solve.progress-monitoring.lib.mjs';
|
|
@@ -978,11 +978,12 @@ export const executeClaudeCommand = async params => {
|
|
|
978
978
|
isRequestTimeout = true;
|
|
979
979
|
await log('⏱️ Detected request timeout from Claude CLI (will retry with --resume)', { verbose: true });
|
|
980
980
|
}
|
|
981
|
-
// Issue #1924:
|
|
982
|
-
// throttle
|
|
983
|
-
//
|
|
984
|
-
//
|
|
985
|
-
|
|
981
|
+
// Issue #1924: server-side temporary rate limiting (HTTP 429) is a transient
|
|
982
|
+
// throttle ("...not your usage limit..."), so retry with --resume. Issue #1935
|
|
983
|
+
// (regression from #1924): account usage limits ("session limit" / "weekly limit")
|
|
984
|
+
// ALSO arrive with api_error_status === 429 plus an explicit reset time, so the
|
|
985
|
+
// isUsageLimitError() guard routes those to the usage-limit handler below instead.
|
|
986
|
+
if (data.api_error_status === 429 && !isUsageLimitError(lastMessage)) {
|
|
986
987
|
isRateLimitError = true;
|
|
987
988
|
await log(`⚠️ Detected server-side rate limiting (429) from Claude CLI (will retry with --resume). request_id=${data.request_id || 'unknown'}`, { verbose: true });
|
|
988
989
|
}
|
package/src/usage-limit.lib.mjs
CHANGED
|
@@ -48,6 +48,14 @@ export function isUsageLimitError(message) {
|
|
|
48
48
|
// Provider-specific phrasings we've seen in the wild
|
|
49
49
|
'session limit reached', // Claude
|
|
50
50
|
'weekly limit reached', // Claude
|
|
51
|
+
// Issue #1935: Claude surfaces 5-hour / weekly account limits as
|
|
52
|
+
// "You've hit your session limit · resets 4pm (UTC)"
|
|
53
|
+
// "You've hit your weekly limit · resets Jan 15, 8am (UTC)"
|
|
54
|
+
// These arrive with api_error_status === 429 but are real usage limits with an
|
|
55
|
+
// explicit reset time, so detect the "hit your <window> limit" phrasing directly
|
|
56
|
+
// (independent of whether a parseable reset time is present in the message).
|
|
57
|
+
'hit your session limit', // Claude 5-hour limit
|
|
58
|
+
'hit your weekly limit', // Claude weekly limit
|
|
51
59
|
'daily limit reached',
|
|
52
60
|
'monthly limit reached',
|
|
53
61
|
'billing hard limit',
|