@link-assistant/hive-mind 2.7.2 → 2.7.3
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
package/package.json
CHANGED
|
@@ -29,12 +29,11 @@
|
|
|
29
29
|
* shown next to the full-session public estimate covers the same scope. This
|
|
30
30
|
* module is the single source of truth for that running total:
|
|
31
31
|
*
|
|
32
|
-
* - Each `
|
|
33
|
-
* `--previous-anthropic-cost`
|
|
34
|
-
*
|
|
35
|
-
* - Every finished Claude process adds its own
|
|
36
|
-
* `
|
|
37
|
-
* (each iteration is a separate Claude process in the same node process).
|
|
32
|
+
* - Each `executeClaude` call starts a scope. Fresh sessions reset it; true
|
|
33
|
+
* resumes retain it or seed it from `--previous-anthropic-cost` when the
|
|
34
|
+
* resume crosses a process boundary.
|
|
35
|
+
* - Every finished Claude process in that logical session adds its own
|
|
36
|
+
* `total_cost_usd` via `addAnthropicRunCost`.
|
|
38
37
|
* - The display and the cross-process spawn both read the cumulative total,
|
|
39
38
|
* so "Calculated by Anthropic" tracks the full session.
|
|
40
39
|
*
|
|
@@ -43,12 +42,12 @@
|
|
|
43
42
|
* future model. See docs/case-studies/issue-1886/ for the full analysis.
|
|
44
43
|
*/
|
|
45
44
|
|
|
46
|
-
// Module-level singleton: the cumulative Anthropic cost for the
|
|
47
|
-
// session (
|
|
45
|
+
// Module-level singleton: the cumulative Anthropic cost for the active logical
|
|
46
|
+
// session (including anything seeded by a true resume from a prior process).
|
|
48
47
|
let cumulativeAnthropicCostUSD = 0;
|
|
49
|
-
// Seeding must happen exactly once per
|
|
50
|
-
//
|
|
51
|
-
//
|
|
48
|
+
// Seeding must happen exactly once per active scope. Resume retries may call the
|
|
49
|
+
// seed helper repeatedly; re-seeding from the same CLI flag would wipe out the
|
|
50
|
+
// costs already accumulated in this process.
|
|
52
51
|
let seeded = false;
|
|
53
52
|
|
|
54
53
|
/**
|
|
@@ -61,10 +60,34 @@ const toCostAmount = value => {
|
|
|
61
60
|
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
62
61
|
};
|
|
63
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Start accounting for one logical Claude session.
|
|
65
|
+
*
|
|
66
|
+
* A fresh execution owns a new transcript and therefore a new cost scope. A
|
|
67
|
+
* true `--resume` execution continues the active scope (or restores it from
|
|
68
|
+
* `--previous-anthropic-cost` when the resume happens in a child process).
|
|
69
|
+
* Calling this at the public `executeClaude` boundary keeps retries inside one
|
|
70
|
+
* scope while preventing watch-mode and mergeability auto-restarts from
|
|
71
|
+
* inheriting the preceding working session's cost.
|
|
72
|
+
*
|
|
73
|
+
* @param {Object} [options]
|
|
74
|
+
* @param {boolean|string} [options.resume=false] - whether this execution resumes an existing Claude session
|
|
75
|
+
* @param {number|string|null} [options.previousAnthropicCost=0] - cumulative cost restored by a resumed child process
|
|
76
|
+
* @returns {number} the cumulative cost at the start of this execution
|
|
77
|
+
*/
|
|
78
|
+
export const beginAnthropicCostScope = ({ resume = false, previousAnthropicCost = 0 } = {}) => {
|
|
79
|
+
if (!resume) {
|
|
80
|
+
cumulativeAnthropicCostUSD = 0;
|
|
81
|
+
seeded = true;
|
|
82
|
+
return cumulativeAnthropicCostUSD;
|
|
83
|
+
}
|
|
84
|
+
return seedCumulativeAnthropicCost(previousAnthropicCost);
|
|
85
|
+
};
|
|
86
|
+
|
|
64
87
|
/**
|
|
65
88
|
* Seed the accumulator from the carried-forward previous-run cost, exactly once
|
|
66
|
-
* per
|
|
67
|
-
*
|
|
89
|
+
* per active scope. Subsequent calls are no-ops so resume retries do not reset
|
|
90
|
+
* the running total.
|
|
68
91
|
* @param {number|string|null|undefined} previousAnthropicCostUSD
|
|
69
92
|
* @returns {number} the cumulative total after seeding
|
|
70
93
|
*/
|
|
@@ -98,8 +121,8 @@ export const getCumulativeAnthropicCost = () => cumulativeAnthropicCostUSD;
|
|
|
98
121
|
export const hasCumulativeAnthropicCost = () => cumulativeAnthropicCostUSD > 0;
|
|
99
122
|
|
|
100
123
|
/**
|
|
101
|
-
* Reset the accumulator. Intended for tests
|
|
102
|
-
*
|
|
124
|
+
* Reset the accumulator. Intended for tests; production code starts scopes via
|
|
125
|
+
* `beginAnthropicCostScope`.
|
|
103
126
|
*/
|
|
104
127
|
export const resetCumulativeAnthropicCost = () => {
|
|
105
128
|
cumulativeAnthropicCostUSD = 0;
|
package/src/claude.lib.mjs
CHANGED
|
@@ -17,7 +17,7 @@ import { sanitizeObjectStrings } from './unicode-sanitization.lib.mjs';
|
|
|
17
17
|
import Decimal from 'decimal.js-light';
|
|
18
18
|
import { createEmptySubSessionUsage, accumulateModelUsage, mergeResultModelUsage, createSubAgentCallEntry, accumulateSubAgentUsage, getRawRequestInputTokens, displaySessionTokenUsage } from './claude.budget-stats.lib.mjs';
|
|
19
19
|
import { buildClaudeResumeCommand, buildClaudeAutonomousResumeCommand } from './claude.command-builder.lib.mjs';
|
|
20
|
-
import { seedCumulativeAnthropicCost, addAnthropicRunCost } from './anthropic-cost-accumulator.lib.mjs'; //
|
|
20
|
+
import { beginAnthropicCostScope, seedCumulativeAnthropicCost, addAnthropicRunCost } from './anthropic-cost-accumulator.lib.mjs'; // Issues #1886, #2056
|
|
21
21
|
import { buildSolveResumeCommand } from './solve.resume-command.lib.mjs'; // Issue #942
|
|
22
22
|
import { SESSION_FORCE_KILLED_MARKER, postTrackedComment } from './tool-comments.lib.mjs'; // Issue #1625
|
|
23
23
|
import { handleClaudeRuntimeSwitch } from './claude.runtime-switch.lib.mjs'; // see issue #1141
|
|
@@ -236,6 +236,8 @@ export const resolveThinkingSettings = async (argv, log) => {
|
|
|
236
236
|
export const checkPlaywrightMcpAvailability = ensureClaudePlaywrightMcpServer;
|
|
237
237
|
export const executeClaude = async params => {
|
|
238
238
|
const { issueUrl, issueNumber, prNumber, prUrl, branchName, tempDir, workspaceTmpDir, isContinueMode, mergeStateStatus, forkedRepo, feedbackLines, forkActionsUrl, owner, repo, argv, log, setLogFile, getLogFile, formatAligned, getResourceSnapshot, claudePath, $ } = params;
|
|
239
|
+
// Issue #2056: reset fresh sessions while retaining issue #1886's true-resume accumulation.
|
|
240
|
+
beginAnthropicCostScope({ resume: argv.resume, previousAnthropicCost: argv.previousAnthropicCost });
|
|
239
241
|
if (argv.promptSubagentsViaAgentCommander) {
|
|
240
242
|
try {
|
|
241
243
|
await $`which start-agent`;
|
|
@@ -304,11 +306,9 @@ export const executeClaude = async params => {
|
|
|
304
306
|
}
|
|
305
307
|
const escapedPrompt = prompt.replace(/"/g, '\\"').replace(/\$/g, '\\$');
|
|
306
308
|
const escapedSystemPrompt = systemPrompt.replace(/"/g, '\\"').replace(/\$/g, '\\$');
|
|
307
|
-
|
|
308
309
|
// Issue #1877: deploy the experimental HANDOFF.md Agent Skill so Claude loads
|
|
309
310
|
// it natively from .claude/skills/handoff/SKILL.md (no-op unless --use-handoff).
|
|
310
311
|
await deployHandoffSkill({ tempDir, argv, log, $ });
|
|
311
|
-
|
|
312
312
|
return await withAgentsMdAsClaudeMd({ tempDir, branchName, argv, prompt, fs, path, $, log, formatAligned }, () =>
|
|
313
313
|
executeClaudeCommand({
|
|
314
314
|
tempDir,
|
|
@@ -1176,6 +1176,7 @@ export const executeClaudeCommand = async params => {
|
|
|
1176
1176
|
// logs the failure and returns false; we fall through to the normal commandFailed return below
|
|
1177
1177
|
// (the 400 is not a transient pattern, so it is not retried).
|
|
1178
1178
|
if (commandFailed && retryableLastError.requiresFreshSession && (await tryThinkingBlockRecovery({ classified: retryableLastError, source: 'result', sessionId }))) {
|
|
1179
|
+
beginAnthropicCostScope({ resume: argv.resume, previousAnthropicCost: argv.previousAnthropicCost });
|
|
1179
1180
|
return await executeWithRetry();
|
|
1180
1181
|
}
|
|
1181
1182
|
// Issues #1331, #1353, #1472/#1475: Unified transient error retry (exponential backoff, session preservation)
|
|
@@ -1376,6 +1377,7 @@ export const executeClaudeCommand = async params => {
|
|
|
1376
1377
|
// Issue #1834: Corrupted extended-thinking blocks surfaced as a thrown exception. Same recovery
|
|
1377
1378
|
// as the streamed-result path: resume the session first, then fall back to a fresh restart.
|
|
1378
1379
|
if (retryableException.requiresFreshSession && (await tryThinkingBlockRecovery({ classified: retryableException, source: 'exception', sessionId }))) {
|
|
1380
|
+
beginAnthropicCostScope({ resume: argv.resume, previousAnthropicCost: argv.previousAnthropicCost });
|
|
1379
1381
|
retryCount++;
|
|
1380
1382
|
return await executeWithRetry();
|
|
1381
1383
|
}
|
|
@@ -181,7 +181,11 @@ export const autoContinueWhenLimitResets = async (issueUrl, sessionId, argv, sho
|
|
|
181
181
|
// cost folded in at the runClaude return, plus anything carried from prior
|
|
182
182
|
// iterations via --previous-anthropic-cost.
|
|
183
183
|
const carriedAnthropicCost = getCumulativeAnthropicCost();
|
|
184
|
-
|
|
184
|
+
// Issue #2056: only a real resume reads the same transcript and belongs to
|
|
185
|
+
// the same cost scope. A configured auto-restart deliberately starts a
|
|
186
|
+
// fresh Claude session, so carrying the old cost would recreate the exact
|
|
187
|
+
// cross-session overcount reported in the issue.
|
|
188
|
+
if (!isRestart && carriedAnthropicCost > 0) {
|
|
185
189
|
resumeArgs.push('--previous-anthropic-cost', String(carriedAnthropicCost));
|
|
186
190
|
await log(`💰 Carrying forward cumulative Anthropic cost: $${carriedAnthropicCost.toFixed(6)} (issue #1886)`, { verbose: true });
|
|
187
191
|
}
|