@mclawnet/claude-adapter 0.1.14 → 0.1.16
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/dist/claude-code-adapter.d.ts +7 -0
- package/dist/claude-code-adapter.d.ts.map +1 -1
- package/dist/claude-code-adapter.js +46 -10
- package/dist/claude-code-adapter.js.map +1 -1
- package/dist/claude-process.d.ts +56 -1
- package/dist/claude-process.d.ts.map +1 -1
- package/dist/claude-process.js +150 -4
- package/dist/claude-process.js.map +1 -1
- package/dist/token-budget.d.ts +105 -0
- package/dist/token-budget.d.ts.map +1 -0
- package/dist/token-budget.js +225 -0
- package/dist/token-budget.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -32,5 +32,12 @@ export declare class ClaudeCodeAdapter implements BackendAdapter {
|
|
|
32
32
|
claudeSessionId: string;
|
|
33
33
|
}) => void): void;
|
|
34
34
|
onExit(process: BackendProcess, handler: (code: number | null) => void): void;
|
|
35
|
+
onTokenBudgetWarning(process: BackendProcess, handler: (info: {
|
|
36
|
+
used: number;
|
|
37
|
+
hardLimit: number;
|
|
38
|
+
threshold: number;
|
|
39
|
+
distanceToHard: number;
|
|
40
|
+
maxOutputTokens: number;
|
|
41
|
+
}) => void): void;
|
|
35
42
|
}
|
|
36
43
|
//# sourceMappingURL=claude-code-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code-adapter.d.ts","sourceRoot":"","sources":["../src/claude-code-adapter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-code-adapter.d.ts","sourceRoot":"","sources":["../src/claude-code-adapter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA4CpD;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,cAAc;IACtD,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAS;gBAEnB,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE;IAK/D,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAmHpD,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAMlD,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAMxE,cAAc,CACZ,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KAChD,KAAK,IAAI,GACT,IAAI;IAMP,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAMvE,gBAAgB,CACd,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACnD,IAAI;IAMP,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI;IAM7E,oBAAoB,CAClB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;KACzB,KAAK,IAAI,GACT,IAAI;CAKR"}
|
|
@@ -3,6 +3,7 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { homedir, platform } from "node:os";
|
|
4
4
|
import { join, delimiter, dirname } from "node:path";
|
|
5
5
|
import { ClaudeProcess } from "./claude-process.js";
|
|
6
|
+
import { estimateStaticPrepend } from "./token-budget.js";
|
|
6
7
|
const isWin = platform() === "win32";
|
|
7
8
|
/** Resolve claude CLI binary using system lookup (where/which), then known paths as fallback. */
|
|
8
9
|
function resolveClaudeBin(explicit) {
|
|
@@ -70,15 +71,29 @@ export class ClaudeCodeAdapter {
|
|
|
70
71
|
if (options.systemPrompt) {
|
|
71
72
|
args.push("--append-system-prompt", options.systemPrompt);
|
|
72
73
|
}
|
|
74
|
+
// Collect every directory we'll mount via --add-dir so the budget
|
|
75
|
+
// estimator (estimateStaticPrepend) can walk them once. The CLI's own
|
|
76
|
+
// usage.input_tokens does NOT see these directories' .md content until
|
|
77
|
+
// the first turn lands — pre-counting closes that blind spot.
|
|
78
|
+
const addedDirs = [];
|
|
73
79
|
if (options.useBrainCore) {
|
|
74
80
|
const brainDir = join(homedir(), ".brain");
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
addedDirs.push(join(brainDir, "BrainCore"));
|
|
82
|
+
addedDirs.push(join(brainDir, "CoreSkill"));
|
|
77
83
|
}
|
|
78
84
|
// Skill system: mount clawnet home for skill discovery
|
|
79
85
|
// Skills are at ~/.clawnet/.claude/skills/{name}/SKILL.md
|
|
80
86
|
const clawnetDir = join(homedir(), ".clawnet");
|
|
81
|
-
|
|
87
|
+
addedDirs.push(clawnetDir);
|
|
88
|
+
// Extra directories (e.g., project-specific skill dirs)
|
|
89
|
+
if (options.additionalDirs) {
|
|
90
|
+
for (const dir of options.additionalDirs) {
|
|
91
|
+
addedDirs.push(dir);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const dir of addedDirs) {
|
|
95
|
+
args.push("--add-dir", dir);
|
|
96
|
+
}
|
|
82
97
|
// ClawNet MCP config (memory MCP + custom MCPs)
|
|
83
98
|
const clawnetMcpConfig = join(clawnetDir, "mcp.json");
|
|
84
99
|
if (existsSync(clawnetMcpConfig)) {
|
|
@@ -87,11 +102,11 @@ export class ClaudeCodeAdapter {
|
|
|
87
102
|
if (options.mcpConfigPath) {
|
|
88
103
|
args.push("--mcp-config", options.mcpConfigPath);
|
|
89
104
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
if (options.allowedTools && options.allowedTools.length > 0) {
|
|
106
|
+
args.push("--allowedTools", options.allowedTools.join(","));
|
|
107
|
+
}
|
|
108
|
+
if (options.disallowedTools && options.disallowedTools.length > 0) {
|
|
109
|
+
args.push("--disallowedTools", options.disallowedTools.join(","));
|
|
95
110
|
}
|
|
96
111
|
// Validate cwd exists — invalid cwd causes ENOENT even if the binary is fine
|
|
97
112
|
let cwd = options.workDir || process.cwd();
|
|
@@ -102,10 +117,17 @@ export class ClaudeCodeAdapter {
|
|
|
102
117
|
const currentPath = process.env.PATH || "";
|
|
103
118
|
const binDir = dirname(this.claudeBin);
|
|
104
119
|
const augmentedPath = currentPath.includes(binDir) ? currentPath : [binDir, currentPath].join(delimiter);
|
|
120
|
+
// Inject CLAUDE_CODE_MAX_OUTPUT_TOKENS only when SessionManager actively
|
|
121
|
+
// chose a non-default ladder step. Setting it unconditionally would shadow
|
|
122
|
+
// user-provided env in shells that already export the var.
|
|
123
|
+
const envOverrides = {};
|
|
124
|
+
if (typeof options.maxOutputTokens === "number" && options.maxOutputTokens > 0) {
|
|
125
|
+
envOverrides.CLAUDE_CODE_MAX_OUTPUT_TOKENS = String(options.maxOutputTokens);
|
|
126
|
+
}
|
|
105
127
|
const proc = spawn(this.claudeBin, args, {
|
|
106
128
|
cwd,
|
|
107
129
|
stdio: ["pipe", "pipe", "pipe"],
|
|
108
|
-
env: { ...process.env, PATH: augmentedPath },
|
|
130
|
+
env: { ...process.env, PATH: augmentedPath, ...envOverrides },
|
|
109
131
|
shell: isWin,
|
|
110
132
|
});
|
|
111
133
|
// Wait for process to be ready (or fail to start)
|
|
@@ -120,7 +142,16 @@ export class ClaudeCodeAdapter {
|
|
|
120
142
|
resolve();
|
|
121
143
|
});
|
|
122
144
|
});
|
|
123
|
-
|
|
145
|
+
// Pre-compute the static prepend budget. Pure read — never throws (the
|
|
146
|
+
// estimator silently skips missing dirs / unreadable files).
|
|
147
|
+
const staticPrependTokens = estimateStaticPrepend({
|
|
148
|
+
systemPromptAppend: options.systemPrompt,
|
|
149
|
+
addedDirs,
|
|
150
|
+
});
|
|
151
|
+
return new ClaudeProcess(options.sessionId, proc, {
|
|
152
|
+
staticPrependTokens,
|
|
153
|
+
maxOutputTokens: options.maxOutputTokens,
|
|
154
|
+
});
|
|
124
155
|
}
|
|
125
156
|
async stop(process) {
|
|
126
157
|
await process.kill();
|
|
@@ -155,5 +186,10 @@ export class ClaudeCodeAdapter {
|
|
|
155
186
|
process.on("exit", handler);
|
|
156
187
|
}
|
|
157
188
|
}
|
|
189
|
+
onTokenBudgetWarning(process, handler) {
|
|
190
|
+
if (process instanceof ClaudeProcess) {
|
|
191
|
+
process.on("token_budget_warning", handler);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
158
194
|
}
|
|
159
195
|
//# sourceMappingURL=claude-code-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code-adapter.js","sourceRoot":"","sources":["../src/claude-code-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-code-adapter.js","sourceRoot":"","sources":["../src/claude-code-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/claude-process.d.ts
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { type ChildProcess } from "node:child_process";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
import type { BackendProcess } from "@mclawnet/agent";
|
|
4
|
+
import { type TokenBudget } from "./token-budget.js";
|
|
5
|
+
/**
|
|
6
|
+
* Optional construction-time hints that let the adapter own the math without
|
|
7
|
+
* forcing every caller to thread them through:
|
|
8
|
+
* - staticPrependTokens: bytes-rounded estimate of the ClawNet-injected
|
|
9
|
+
* prepend (memory section + roleId hint + --add-dir .md walks). Counted
|
|
10
|
+
* into `used` because the CLI's own usage.input_tokens does NOT see it.
|
|
11
|
+
* - maxOutputTokens: the value of CLAUDE_CODE_MAX_OUTPUT_TOKENS this
|
|
12
|
+
* spawn was launched with. Drives `calcBudget()` so warning thresholds
|
|
13
|
+
* match the actual server-side hardLimit.
|
|
14
|
+
*/
|
|
15
|
+
export interface ClaudeProcessOptions {
|
|
16
|
+
staticPrependTokens?: number;
|
|
17
|
+
maxOutputTokens?: number;
|
|
18
|
+
}
|
|
19
|
+
/** Snapshot of token-budget state — surfaced via event payload + getter. */
|
|
20
|
+
export interface TokenBudgetStatus {
|
|
21
|
+
used: number;
|
|
22
|
+
budget: TokenBudget;
|
|
23
|
+
distanceToWarn: number;
|
|
24
|
+
distanceToHard: number;
|
|
25
|
+
}
|
|
4
26
|
/**
|
|
5
27
|
* Wraps a single Claude CLI process with stdin/stdout NDJSON communication.
|
|
6
28
|
*
|
|
@@ -14,7 +36,31 @@ export declare class ClaudeProcess extends EventEmitter implements BackendProces
|
|
|
14
36
|
private parser;
|
|
15
37
|
private killed;
|
|
16
38
|
private log;
|
|
17
|
-
|
|
39
|
+
/** Sum of `usage` totals seen on the most recent assistant frame.
|
|
40
|
+
* Reset only when the CLI itself reports a new `usage` (replacement, not
|
|
41
|
+
* delta — Anthropic's usage is cumulative-per-turn) so we don't double-count. */
|
|
42
|
+
private lastUsageTotal;
|
|
43
|
+
/** Locally-estimated tokens for stdin sent since the last `result` frame.
|
|
44
|
+
* Acts as a forward bound: between turns the CLI hasn't echoed back a
|
|
45
|
+
* fresh `usage`, so we approximate from what we wrote. Cleared on result. */
|
|
46
|
+
private pendingDelta;
|
|
47
|
+
/** Bytes-rounded prepend size known at spawn time — invariant across turns. */
|
|
48
|
+
private readonly staticPrependTokens;
|
|
49
|
+
/** Pre-computed thresholds for the spawn's max_output_tokens setting. */
|
|
50
|
+
private readonly budget;
|
|
51
|
+
/** Latches once we emit `token_budget_warning` to avoid spamming hub once
|
|
52
|
+
* per turn after we've already nudged the upper layer. Resets on every
|
|
53
|
+
* fresh assistant frame because that means the model is making progress. */
|
|
54
|
+
private warningEmittedThisStretch;
|
|
55
|
+
constructor(sessionId: string, proc: ChildProcess, opts?: ClaudeProcessOptions);
|
|
56
|
+
/**
|
|
57
|
+
* OS pid of the spawned `claude` CLI process. `undefined` between spawn
|
|
58
|
+
* call and the kernel actually allocating it (vanishingly rare in practice
|
|
59
|
+
* but Node.js types reflect it). Used by SessionManager.flushCheckpoint
|
|
60
|
+
* (PR-C) — checkpointing a session whose pid is briefly missing simply
|
|
61
|
+
* skips this entry until the next debounce tick picks it up.
|
|
62
|
+
*/
|
|
63
|
+
get pid(): number | undefined;
|
|
18
64
|
/** Send user input to Claude CLI stdin as NDJSON */
|
|
19
65
|
sendInput(content: string): void;
|
|
20
66
|
/**
|
|
@@ -27,6 +73,15 @@ export declare class ClaudeProcess extends EventEmitter implements BackendProces
|
|
|
27
73
|
isAlive(): boolean;
|
|
28
74
|
kill(): Promise<void>;
|
|
29
75
|
private handleEvent;
|
|
76
|
+
/**
|
|
77
|
+
* Snapshot the current token-budget situation. `used` includes:
|
|
78
|
+
* - lastUsageTotal — replaces with the most recent assistant `usage`
|
|
79
|
+
* - pendingDelta — locally-estimated stdin not yet echoed back
|
|
80
|
+
* - staticPrependTokens — invariant prepend the CLI cannot see
|
|
81
|
+
* Public so SessionManager can read it on demand (e.g. when deciding the
|
|
82
|
+
* next spawn's max_output_tokens without waiting for an explicit warning).
|
|
83
|
+
*/
|
|
84
|
+
getTokenBudgetStatus(): TokenBudgetStatus;
|
|
30
85
|
/** Single chokepoint for stdout-side logging — every parsed event passes through here. */
|
|
31
86
|
private logEvent;
|
|
32
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-process.d.ts","sourceRoot":"","sources":["../src/claude-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-process.d.ts","sourceRoot":"","sources":["../src/claude-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EAA4B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG/E;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,YAAa,YAAW,cAAc;IACvE,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,GAAG,CAAC;IAEZ;;sFAEkF;IAClF,OAAO,CAAC,cAAc,CAAK;IAC3B;;kFAE8E;IAC9E,OAAO,CAAC,YAAY,CAAK;IACzB,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC;;iFAE6E;IAC7E,OAAO,CAAC,yBAAyB,CAAS;gBAE9B,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,GAAE,oBAAyB;IAyClF;;;;;;OAMG;IACH,IAAI,GAAG,IAAI,MAAM,GAAG,SAAS,CAE5B;IAED,oDAAoD;IACpD,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAsBhC;;;;;;OAMG;IACH,OAAO,IAAI,OAAO;IASZ,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB3B,OAAO,CAAC,WAAW;IAoEnB;;;;;;;OAOG;IACH,oBAAoB,IAAI,iBAAiB;IAUzC,0FAA0F;IAC1F,OAAO,CAAC,QAAQ;CAqGjB"}
|
package/dist/claude-process.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import { StreamParser } from "./stream-parser.js";
|
|
3
|
+
import { calcBudget, estimateText } from "./token-budget.js";
|
|
3
4
|
import { createLogger, previewFields } from "@mclawnet/logger";
|
|
4
5
|
/**
|
|
5
6
|
* Wraps a single Claude CLI process with stdin/stdout NDJSON communication.
|
|
@@ -14,7 +15,23 @@ export class ClaudeProcess extends EventEmitter {
|
|
|
14
15
|
parser;
|
|
15
16
|
killed = false;
|
|
16
17
|
log;
|
|
17
|
-
|
|
18
|
+
/** Sum of `usage` totals seen on the most recent assistant frame.
|
|
19
|
+
* Reset only when the CLI itself reports a new `usage` (replacement, not
|
|
20
|
+
* delta — Anthropic's usage is cumulative-per-turn) so we don't double-count. */
|
|
21
|
+
lastUsageTotal = 0;
|
|
22
|
+
/** Locally-estimated tokens for stdin sent since the last `result` frame.
|
|
23
|
+
* Acts as a forward bound: between turns the CLI hasn't echoed back a
|
|
24
|
+
* fresh `usage`, so we approximate from what we wrote. Cleared on result. */
|
|
25
|
+
pendingDelta = 0;
|
|
26
|
+
/** Bytes-rounded prepend size known at spawn time — invariant across turns. */
|
|
27
|
+
staticPrependTokens;
|
|
28
|
+
/** Pre-computed thresholds for the spawn's max_output_tokens setting. */
|
|
29
|
+
budget;
|
|
30
|
+
/** Latches once we emit `token_budget_warning` to avoid spamming hub once
|
|
31
|
+
* per turn after we've already nudged the upper layer. Resets on every
|
|
32
|
+
* fresh assistant frame because that means the model is making progress. */
|
|
33
|
+
warningEmittedThisStretch = false;
|
|
34
|
+
constructor(sessionId, proc, opts = {}) {
|
|
18
35
|
super();
|
|
19
36
|
this.id = sessionId;
|
|
20
37
|
this.log = createLogger({ module: "claude", sessionId });
|
|
@@ -22,6 +39,8 @@ export class ClaudeProcess extends EventEmitter {
|
|
|
22
39
|
? proc.spawnargs[proc.spawnargs.indexOf("--cwd") + 1]
|
|
23
40
|
: process.cwd();
|
|
24
41
|
this.proc = proc;
|
|
42
|
+
this.staticPrependTokens = Math.max(0, opts.staticPrependTokens ?? 0);
|
|
43
|
+
this.budget = calcBudget({ maxOutputTokens: opts.maxOutputTokens });
|
|
25
44
|
this.parser = new StreamParser((event) => this.handleEvent(event), (error) => this.emit("error", error));
|
|
26
45
|
// Wire stdout
|
|
27
46
|
proc.stdout?.on("data", (chunk) => {
|
|
@@ -44,6 +63,16 @@ export class ClaudeProcess extends EventEmitter {
|
|
|
44
63
|
this.emit("error", err);
|
|
45
64
|
});
|
|
46
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* OS pid of the spawned `claude` CLI process. `undefined` between spawn
|
|
68
|
+
* call and the kernel actually allocating it (vanishingly rare in practice
|
|
69
|
+
* but Node.js types reflect it). Used by SessionManager.flushCheckpoint
|
|
70
|
+
* (PR-C) — checkpointing a session whose pid is briefly missing simply
|
|
71
|
+
* skips this entry until the next debounce tick picks it up.
|
|
72
|
+
*/
|
|
73
|
+
get pid() {
|
|
74
|
+
return this.proc.pid;
|
|
75
|
+
}
|
|
47
76
|
/** Send user input to Claude CLI stdin as NDJSON */
|
|
48
77
|
sendInput(content) {
|
|
49
78
|
if (!this.proc.stdin?.writable) {
|
|
@@ -55,6 +84,11 @@ export class ClaudeProcess extends EventEmitter {
|
|
|
55
84
|
type: "user",
|
|
56
85
|
message: { role: "user", content },
|
|
57
86
|
}) + "\n";
|
|
87
|
+
// Locally estimate the user's contribution so the warning can fire even
|
|
88
|
+
// before the next assistant frame ships an updated `usage`. Cleared on
|
|
89
|
+
// the next `result` event since at that point lastUsageTotal already
|
|
90
|
+
// reflects the new turn.
|
|
91
|
+
this.pendingDelta += estimateText(content);
|
|
58
92
|
this.log.debug(previewFields(content), "stdin.write user input");
|
|
59
93
|
this.proc.stdin.write(message);
|
|
60
94
|
}
|
|
@@ -90,16 +124,50 @@ export class ClaudeProcess extends EventEmitter {
|
|
|
90
124
|
handleEvent(event) {
|
|
91
125
|
this.logEvent(event);
|
|
92
126
|
this.emit("output", event);
|
|
127
|
+
if (event.type === "assistant") {
|
|
128
|
+
// Anthropic's `usage` is cumulative within a single message — replace,
|
|
129
|
+
// don't add. Sum mirrors getTokenCountFromUsage() in claude-code.
|
|
130
|
+
const usage = event.message?.usage;
|
|
131
|
+
if (usage) {
|
|
132
|
+
this.lastUsageTotal =
|
|
133
|
+
(usage.input_tokens ?? 0) +
|
|
134
|
+
(usage.output_tokens ?? 0) +
|
|
135
|
+
(usage.cache_creation_input_tokens ?? 0) +
|
|
136
|
+
(usage.cache_read_input_tokens ?? 0);
|
|
137
|
+
// Fresh model output ≈ progress; allow a future warning if usage rises again.
|
|
138
|
+
this.warningEmittedThisStretch = false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
93
141
|
if (event.type === "result") {
|
|
94
142
|
const resultEvent = event;
|
|
95
143
|
// Update session ID from Claude's response
|
|
96
144
|
if (resultEvent.session_id) {
|
|
97
145
|
this.id = resultEvent.session_id;
|
|
98
146
|
}
|
|
147
|
+
// Run budget check at end-of-turn — by now lastUsageTotal reflects the
|
|
148
|
+
// server's authoritative count for the just-finished turn, plus our
|
|
149
|
+
// optimistic pendingDelta and the invisible static prepend.
|
|
150
|
+
const status = this.getTokenBudgetStatus();
|
|
151
|
+
if (!this.warningEmittedThisStretch &&
|
|
152
|
+
status.used >= status.budget.clawnetWarnThreshold) {
|
|
153
|
+
this.warningEmittedThisStretch = true;
|
|
154
|
+
this.emit("token_budget_warning", {
|
|
155
|
+
used: status.used,
|
|
156
|
+
hardLimit: status.budget.hardLimit,
|
|
157
|
+
threshold: status.budget.clawnetWarnThreshold,
|
|
158
|
+
distanceToHard: status.distanceToHard,
|
|
159
|
+
// Caller (SessionManager) owns the ladder index — we just signal.
|
|
160
|
+
maxOutputTokens: status.budget.maxOutputTokens,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
// Locally-estimated stdin contribution is now folded into the CLI's
|
|
164
|
+
// own usage, so wipe to avoid double-counting on the next turn.
|
|
165
|
+
this.pendingDelta = 0;
|
|
99
166
|
this.emit("turn_complete", {
|
|
100
167
|
claudeSessionId: resultEvent.session_id,
|
|
101
168
|
cost: resultEvent.cost_usd,
|
|
102
169
|
duration: resultEvent.duration_ms,
|
|
170
|
+
contextUsage: { used: status.used, total: status.budget.hardLimit },
|
|
103
171
|
});
|
|
104
172
|
}
|
|
105
173
|
// System frames come in several subtypes:
|
|
@@ -115,16 +183,48 @@ export class ClaudeProcess extends EventEmitter {
|
|
|
115
183
|
this.emit("session_started", { claudeSessionId: event.session_id });
|
|
116
184
|
}
|
|
117
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Snapshot the current token-budget situation. `used` includes:
|
|
188
|
+
* - lastUsageTotal — replaces with the most recent assistant `usage`
|
|
189
|
+
* - pendingDelta — locally-estimated stdin not yet echoed back
|
|
190
|
+
* - staticPrependTokens — invariant prepend the CLI cannot see
|
|
191
|
+
* Public so SessionManager can read it on demand (e.g. when deciding the
|
|
192
|
+
* next spawn's max_output_tokens without waiting for an explicit warning).
|
|
193
|
+
*/
|
|
194
|
+
getTokenBudgetStatus() {
|
|
195
|
+
const used = this.lastUsageTotal + this.pendingDelta + this.staticPrependTokens;
|
|
196
|
+
return {
|
|
197
|
+
used,
|
|
198
|
+
budget: this.budget,
|
|
199
|
+
distanceToWarn: this.budget.clawnetWarnThreshold - used,
|
|
200
|
+
distanceToHard: this.budget.hardLimit - used,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
118
203
|
/** Single chokepoint for stdout-side logging — every parsed event passes through here. */
|
|
119
204
|
logEvent(event) {
|
|
120
205
|
if (event.type === "assistant") {
|
|
121
206
|
const blocks = event.message?.content ?? [];
|
|
207
|
+
// Forensic guard: an assistant frame with empty content (or only blocks
|
|
208
|
+
// of types we don't recognise — e.g. `image`) is the smoking gun for
|
|
209
|
+
// "Claude returned but the bubble is empty". Dump the raw event at INFO
|
|
210
|
+
// so it survives the default DEBUG-suppressed log level. See the
|
|
211
|
+
// /compact + empty-reply diagnosis on PR #109.
|
|
212
|
+
let logged = 0;
|
|
122
213
|
for (const block of blocks) {
|
|
123
214
|
if (block.type === "text" && block.text) {
|
|
124
215
|
this.log.debug({ eventType: "assistant.text", ...previewFields(block.text) }, "stdout.event");
|
|
216
|
+
logged++;
|
|
125
217
|
}
|
|
126
|
-
else if (block.type === "thinking"
|
|
127
|
-
|
|
218
|
+
else if (block.type === "thinking") {
|
|
219
|
+
// Anthropic schema puts thinking in `block.thinking`, not `block.text`.
|
|
220
|
+
// Old code checked block.text and silently skipped every thinking
|
|
221
|
+
// block — masked the symptom that thinking-only turns produce no
|
|
222
|
+
// visible reply.
|
|
223
|
+
const thinkingText = block.thinking ?? block.text;
|
|
224
|
+
if (thinkingText) {
|
|
225
|
+
this.log.debug({ eventType: "assistant.thinking", ...previewFields(thinkingText) }, "stdout.event");
|
|
226
|
+
logged++;
|
|
227
|
+
}
|
|
128
228
|
}
|
|
129
229
|
else if (block.type === "tool_use") {
|
|
130
230
|
this.log.debug({
|
|
@@ -133,16 +233,31 @@ export class ClaudeProcess extends EventEmitter {
|
|
|
133
233
|
toolUseId: block.id,
|
|
134
234
|
...previewFields(JSON.stringify(block.input ?? {})),
|
|
135
235
|
}, "stdout.event");
|
|
236
|
+
logged++;
|
|
136
237
|
}
|
|
137
238
|
else if (block.type === "tool_result") {
|
|
138
239
|
this.log.debug({
|
|
139
240
|
eventType: "assistant.tool_result",
|
|
140
241
|
...previewFields(block.content ?? ""),
|
|
141
242
|
}, "stdout.event");
|
|
243
|
+
logged++;
|
|
142
244
|
}
|
|
143
245
|
}
|
|
246
|
+
if (logged === 0) {
|
|
247
|
+
// Forensic dump: blocks=[], or only unknown block types
|
|
248
|
+
// (image / unknown). INFO level so it shows up without --debug.
|
|
249
|
+
this.log.info({
|
|
250
|
+
eventType: "assistant.empty_or_unknown",
|
|
251
|
+
blockCount: blocks.length,
|
|
252
|
+
blockTypes: blocks.map((b) => b.type ?? "?"),
|
|
253
|
+
stopReason: event.message?.stop_reason ?? null,
|
|
254
|
+
usage: event.message?.usage ?? null,
|
|
255
|
+
rawEvent: safeStringify(event),
|
|
256
|
+
}, "stdout.event: assistant frame produced no loggable content (model returned empty / non-text blocks)");
|
|
257
|
+
}
|
|
144
258
|
}
|
|
145
259
|
else if (event.type === "result") {
|
|
260
|
+
const status = this.getTokenBudgetStatus();
|
|
146
261
|
this.log.info({
|
|
147
262
|
eventType: "result",
|
|
148
263
|
subtype: event.subtype,
|
|
@@ -150,14 +265,45 @@ export class ClaudeProcess extends EventEmitter {
|
|
|
150
265
|
costUsd: event.cost_usd,
|
|
151
266
|
durationMs: event.duration_ms,
|
|
152
267
|
numTurns: event.num_turns,
|
|
268
|
+
tokenBudget: {
|
|
269
|
+
used: status.used,
|
|
270
|
+
hardLimit: status.budget.hardLimit,
|
|
271
|
+
threshold: status.budget.clawnetWarnThreshold,
|
|
272
|
+
maxOutputTokens: status.budget.maxOutputTokens,
|
|
273
|
+
},
|
|
153
274
|
}, "stdout.event");
|
|
154
275
|
}
|
|
155
276
|
else if (event.type === "system") {
|
|
156
277
|
this.log.debug({ eventType: `system.${event.subtype}`, sid: event.session_id }, "stdout.event");
|
|
157
278
|
}
|
|
158
279
|
else {
|
|
159
|
-
|
|
280
|
+
// Unknown event type (not assistant/result/system). INFO level + full
|
|
281
|
+
// payload so we can spot new Claude CLI frame types instead of silently
|
|
282
|
+
// dropping them at DEBUG.
|
|
283
|
+
const eventType = event.type;
|
|
284
|
+
this.log.info({ eventType: eventType ?? "<missing>", rawEvent: safeStringify(event) }, "stdout.event: unknown frame type");
|
|
160
285
|
}
|
|
161
286
|
}
|
|
162
287
|
}
|
|
288
|
+
/** Best-effort JSON.stringify with circular-safety + 4KB cap so a runaway
|
|
289
|
+
* event payload doesn't blow up logger ring buffers. */
|
|
290
|
+
function safeStringify(value) {
|
|
291
|
+
try {
|
|
292
|
+
const seen = new WeakSet();
|
|
293
|
+
const json = JSON.stringify(value, (_key, v) => {
|
|
294
|
+
if (typeof v === "object" && v !== null) {
|
|
295
|
+
if (seen.has(v))
|
|
296
|
+
return "[Circular]";
|
|
297
|
+
seen.add(v);
|
|
298
|
+
}
|
|
299
|
+
return v;
|
|
300
|
+
});
|
|
301
|
+
if (!json)
|
|
302
|
+
return "<unserialisable>";
|
|
303
|
+
return json.length > 4096 ? `${json.slice(0, 4096)}…(truncated, total=${json.length})` : json;
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
return `<stringify failed: ${err.message}>`;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
163
309
|
//# sourceMappingURL=claude-process.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-process.js","sourceRoot":"","sources":["../src/claude-process.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-process.js","sourceRoot":"","sources":["../src/claude-process.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export { MAX_TOKENS_LADDER, clampLadderIndex } from "@mclawnet/shared";
|
|
2
|
+
/** Total context window in tokens. Same default as claude-code. */
|
|
3
|
+
export declare const MODEL_CONTEXT_WINDOW_DEFAULT = 200000;
|
|
4
|
+
/**
|
|
5
|
+
* Cap used when claude-code computes its "effective window" — output tokens
|
|
6
|
+
* above this don't shrink the input budget further (because the CLI assumes
|
|
7
|
+
* 20k is plenty for the summary turn). Mirrors claude-code's
|
|
8
|
+
* `MAX_OUTPUT_TOKENS_FOR_SUMMARY`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20000;
|
|
11
|
+
/** Buffer claude-code keeps before triggering its own auto-compact. */
|
|
12
|
+
export declare const AUTOCOMPACT_BUFFER_TOKENS = 13000;
|
|
13
|
+
/**
|
|
14
|
+
* Extra ClawNet-specific safety pad. Covers two unknowns:
|
|
15
|
+
* - the CLI doesn't see ClawNet's prepend, so its `usage.input_tokens`
|
|
16
|
+
* under-counts by the prepend size,
|
|
17
|
+
* - chars/4 estimation has ±20% noise depending on the language mix.
|
|
18
|
+
* 12k is a deliberate over-provision so the warning fires early enough that
|
|
19
|
+
* ladder escalation can land before the hard wall.
|
|
20
|
+
*/
|
|
21
|
+
export declare const CLAWNET_EXTRA_BUFFER_TOKENS = 12000;
|
|
22
|
+
/**
|
|
23
|
+
* Escalate to the next ladder step when `used` is within this many tokens of
|
|
24
|
+
* the hard limit. 8k is one short turn's worth of new input — gives just
|
|
25
|
+
* enough lookahead to swap env vars before the next turn writes prompt-too-large.
|
|
26
|
+
*/
|
|
27
|
+
export declare const ESCALATE_BUFFER_TOKENS = 8000;
|
|
28
|
+
/** Default chars-per-token ratio for plain text (claude-code uses 4). */
|
|
29
|
+
export declare const TOKEN_RATIO_TEXT = 4;
|
|
30
|
+
/** chars-per-token ratio for JSON-shaped content (claude-code uses 2). */
|
|
31
|
+
export declare const TOKEN_RATIO_JSON = 2;
|
|
32
|
+
export interface TokenBudget {
|
|
33
|
+
/** Total context window (200k for current models). */
|
|
34
|
+
contextWindow: number;
|
|
35
|
+
/** max_output_tokens currently in effect for spawned CLI. */
|
|
36
|
+
maxOutputTokens: number;
|
|
37
|
+
/** Server-side prompt cap = contextWindow − maxOutputTokens. Hitting this is the 400 error. */
|
|
38
|
+
hardLimit: number;
|
|
39
|
+
/** What claude-code calls "effective context window" — its compaction math denominator. */
|
|
40
|
+
effectiveWindow: number;
|
|
41
|
+
/** Threshold at which the CLI's own auto-compact would fire. */
|
|
42
|
+
cliAutoCompactThreshold: number;
|
|
43
|
+
/** ClawNet's earlier warning threshold — buys time before CLI/server limits. */
|
|
44
|
+
clawnetWarnThreshold: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Compute the budget for a given (contextWindow, maxOutputTokens) combination.
|
|
48
|
+
* Pure function; no I/O. Defaults align with `claude-opus-4.7-xhigh`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function calcBudget(opts?: {
|
|
51
|
+
contextWindow?: number;
|
|
52
|
+
maxOutputTokens?: number;
|
|
53
|
+
}): TokenBudget;
|
|
54
|
+
/**
|
|
55
|
+
* Rough token count for a string. Mirrors
|
|
56
|
+
* `claude-code/services/tokenEstimation.ts:roughTokenCountEstimation`.
|
|
57
|
+
*
|
|
58
|
+
* For non-string inputs returns 0 — keeps callers from having to null-check
|
|
59
|
+
* every prepend slot they haven't populated.
|
|
60
|
+
*/
|
|
61
|
+
export declare function estimateText(s: string | undefined | null, ratio?: number): number;
|
|
62
|
+
/**
|
|
63
|
+
* Estimate the static prepend that ClawNet injects on every spawn but the
|
|
64
|
+
* underlying CLI cannot see. Two sources contribute:
|
|
65
|
+
*
|
|
66
|
+
* 1. `systemPromptAppend` — the final string that ClawNet hands to
|
|
67
|
+
* `--append-system-prompt`. This already includes memory section +
|
|
68
|
+
* roleId hint + pending notice (assembled in
|
|
69
|
+
* session-manager.ts:189-219), so we just measure the resulting blob.
|
|
70
|
+
*
|
|
71
|
+
* 2. `addedDirs` — every path passed to `--add-dir`. We walk one level
|
|
72
|
+
* deep looking for `.md` files (the only file type the CLI loads
|
|
73
|
+
* eagerly) and sum their sizes / 4. Recursing further gives diminishing
|
|
74
|
+
* returns — most prompt-heavy assets live in the top-level Skill / Brain
|
|
75
|
+
* directories and the CLI lazy-loads anything deeper.
|
|
76
|
+
*
|
|
77
|
+
* I/O here is sync because spawn() itself is sync-ish (waits for `proc.spawn`
|
|
78
|
+
* event) and the read fan-out is small (≤ 4 dirs × small handful of files).
|
|
79
|
+
* If a path is missing or unreadable it's silently skipped — we never want
|
|
80
|
+
* the budget estimator to break a working spawn.
|
|
81
|
+
*/
|
|
82
|
+
export declare function estimateStaticPrepend(parts: {
|
|
83
|
+
systemPromptAppend?: string;
|
|
84
|
+
addedDirs?: string[];
|
|
85
|
+
}): number;
|
|
86
|
+
/**
|
|
87
|
+
* Decide whether to escalate the max_output_tokens ladder. Pure function so
|
|
88
|
+
* SessionManager can drive it deterministically from tests.
|
|
89
|
+
*
|
|
90
|
+
* Escalation rule: `used >= hardLimit − ESCALATE_BUFFER_TOKENS` *and* there
|
|
91
|
+
* is a lower step still available. Once the lowest step is reached we stop
|
|
92
|
+
* escalating — reporting "already at floor" is the caller's job.
|
|
93
|
+
*/
|
|
94
|
+
export declare function chooseMaxOutputTokens(input: {
|
|
95
|
+
currentLadderIndex: number;
|
|
96
|
+
used: number;
|
|
97
|
+
hardLimit: number;
|
|
98
|
+
/** Override threshold for tests; defaults to ESCALATE_BUFFER_TOKENS. */
|
|
99
|
+
escalateBufferTokens?: number;
|
|
100
|
+
}): {
|
|
101
|
+
ladderIndex: number;
|
|
102
|
+
maxOutputTokens: number;
|
|
103
|
+
escalated: boolean;
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=token-budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-budget.d.ts","sourceRoot":"","sources":["../src/token-budget.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEvE,mEAAmE;AACnE,eAAO,MAAM,4BAA4B,SAAU,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAEpD,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,OAAQ,CAAC;AA0B5C,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,eAAe,EAAE,MAAM,CAAC;IACxB,+FAA+F;IAC/F,SAAS,EAAE,MAAM,CAAC;IAClB,2FAA2F;IAC3F,eAAe,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,uBAAuB,EAAE,MAAM,CAAC;IAChC,gFAAgF;IAChF,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,CAAC,EAAE;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,WAAW,CAoBd;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,KAAK,GAAE,MAAyB,GAAG,MAAM,CAInG;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB,GAAG,MAAM,CAUT;AAwDD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAYvE"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-budget primitives for ClawNet's claude-adapter.
|
|
3
|
+
*
|
|
4
|
+
* Why this exists: claude-code CLI auto-compacts based on its own internal
|
|
5
|
+
* token estimate, but ClawNet injects a sizeable prepend (memory section,
|
|
6
|
+
* roleId hint, skill notice, --add-dir directories) that the CLI cannot see.
|
|
7
|
+
* The result: by the time the CLI thinks "still 5k headroom", the server
|
|
8
|
+
* has already received >168k tokens and replies with HTTP 400.
|
|
9
|
+
*
|
|
10
|
+
* This module is the math layer for two countermeasures:
|
|
11
|
+
* 1. (B+C) Estimate "real" token usage = backend usage + ClawNet prepend
|
|
12
|
+
* so we can warn the upper layers (hub/UI) before the wall.
|
|
13
|
+
* 2. (D-lite) Decide the next CLAUDE_CODE_MAX_OUTPUT_TOKENS ladder step;
|
|
14
|
+
* lowering max_output_tokens raises the server-side prompt limit
|
|
15
|
+
* (200k − max_tokens) and gives auto-compact more breathing room.
|
|
16
|
+
*
|
|
17
|
+
* Constants below mirror claude-code 2.1.88 source for compatibility:
|
|
18
|
+
* - source/src/utils/context.ts:9 (MODEL_CONTEXT_WINDOW_DEFAULT)
|
|
19
|
+
* - source/src/services/compact/autoCompact.ts:30-65 (effective window + threshold)
|
|
20
|
+
* - source/src/services/tokenEstimation.ts:203-242 (chars/4 estimation)
|
|
21
|
+
*
|
|
22
|
+
* `MAX_TOKENS_LADDER` and `clampLadderIndex` live in `@mclawnet/shared` so
|
|
23
|
+
* SessionManager (in @mclawnet/agent) and this module agree on the same
|
|
24
|
+
* ladder without one taking a runtime dependency on the other. They are
|
|
25
|
+
* re-exported here for back-compat with consumers that already import
|
|
26
|
+
* from claude-adapter.
|
|
27
|
+
*/
|
|
28
|
+
import { MAX_TOKENS_LADDER, clampLadderIndex } from "@mclawnet/shared";
|
|
29
|
+
export { MAX_TOKENS_LADDER, clampLadderIndex } from "@mclawnet/shared";
|
|
30
|
+
/** Total context window in tokens. Same default as claude-code. */
|
|
31
|
+
export const MODEL_CONTEXT_WINDOW_DEFAULT = 200_000;
|
|
32
|
+
/**
|
|
33
|
+
* Cap used when claude-code computes its "effective window" — output tokens
|
|
34
|
+
* above this don't shrink the input budget further (because the CLI assumes
|
|
35
|
+
* 20k is plenty for the summary turn). Mirrors claude-code's
|
|
36
|
+
* `MAX_OUTPUT_TOKENS_FOR_SUMMARY`.
|
|
37
|
+
*/
|
|
38
|
+
export const MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20_000;
|
|
39
|
+
/** Buffer claude-code keeps before triggering its own auto-compact. */
|
|
40
|
+
export const AUTOCOMPACT_BUFFER_TOKENS = 13_000;
|
|
41
|
+
/**
|
|
42
|
+
* Extra ClawNet-specific safety pad. Covers two unknowns:
|
|
43
|
+
* - the CLI doesn't see ClawNet's prepend, so its `usage.input_tokens`
|
|
44
|
+
* under-counts by the prepend size,
|
|
45
|
+
* - chars/4 estimation has ±20% noise depending on the language mix.
|
|
46
|
+
* 12k is a deliberate over-provision so the warning fires early enough that
|
|
47
|
+
* ladder escalation can land before the hard wall.
|
|
48
|
+
*/
|
|
49
|
+
export const CLAWNET_EXTRA_BUFFER_TOKENS = 12_000;
|
|
50
|
+
/**
|
|
51
|
+
* Escalate to the next ladder step when `used` is within this many tokens of
|
|
52
|
+
* the hard limit. 8k is one short turn's worth of new input — gives just
|
|
53
|
+
* enough lookahead to swap env vars before the next turn writes prompt-too-large.
|
|
54
|
+
*/
|
|
55
|
+
export const ESCALATE_BUFFER_TOKENS = 8_000;
|
|
56
|
+
/**
|
|
57
|
+
* Invariant: the ClawNet warning threshold must fire *before* the ladder's
|
|
58
|
+
* escalation window opens, otherwise we'd warn and escalate on the same turn
|
|
59
|
+
* (or worse, escalate without ever warning) — defeating the purpose of giving
|
|
60
|
+
* upper layers a heads-up. Concretely:
|
|
61
|
+
*
|
|
62
|
+
* clawnetWarnThreshold = cliAutoCompactThreshold − CLAWNET_EXTRA_BUFFER_TOKENS
|
|
63
|
+
* escalationFires when: used >= hardLimit − ESCALATE_BUFFER_TOKENS
|
|
64
|
+
*
|
|
65
|
+
* For the warn → escalate sequencing to hold across estimation noise we need
|
|
66
|
+
* `CLAWNET_EXTRA_BUFFER_TOKENS` to exceed `ESCALATE_BUFFER_TOKENS` by a
|
|
67
|
+
* comfortable margin (4k absorbs chars/4 jitter on a typical 32k context
|
|
68
|
+
* window). Module-load assertion below catches any future tweak that breaks
|
|
69
|
+
* this — better to fail fast at import time than to ship a silently wrong
|
|
70
|
+
* threshold ordering.
|
|
71
|
+
*/
|
|
72
|
+
if (CLAWNET_EXTRA_BUFFER_TOKENS < ESCALATE_BUFFER_TOKENS + 4_000) {
|
|
73
|
+
throw new Error(`token-budget invariant violated: CLAWNET_EXTRA_BUFFER_TOKENS (${CLAWNET_EXTRA_BUFFER_TOKENS}) ` +
|
|
74
|
+
`must be >= ESCALATE_BUFFER_TOKENS (${ESCALATE_BUFFER_TOKENS}) + 4000 ` +
|
|
75
|
+
`so the warning threshold lands before the escalation window opens.`);
|
|
76
|
+
}
|
|
77
|
+
/** Default chars-per-token ratio for plain text (claude-code uses 4). */
|
|
78
|
+
export const TOKEN_RATIO_TEXT = 4;
|
|
79
|
+
/** chars-per-token ratio for JSON-shaped content (claude-code uses 2). */
|
|
80
|
+
export const TOKEN_RATIO_JSON = 2;
|
|
81
|
+
/**
|
|
82
|
+
* Compute the budget for a given (contextWindow, maxOutputTokens) combination.
|
|
83
|
+
* Pure function; no I/O. Defaults align with `claude-opus-4.7-xhigh`.
|
|
84
|
+
*/
|
|
85
|
+
export function calcBudget(opts) {
|
|
86
|
+
const contextWindow = opts?.contextWindow ?? MODEL_CONTEXT_WINDOW_DEFAULT;
|
|
87
|
+
const maxOutputTokens = opts?.maxOutputTokens ?? MAX_TOKENS_LADDER[0];
|
|
88
|
+
const hardLimit = Math.max(0, contextWindow - maxOutputTokens);
|
|
89
|
+
// claude-code: effectiveWindow = contextWindow - min(maxOutputTokens, MAX_OUTPUT_TOKENS_FOR_SUMMARY).
|
|
90
|
+
// The min() means going below 20k max_output stops shrinking the cap (because
|
|
91
|
+
// even the summarisation pass needs ~20k headroom).
|
|
92
|
+
const effectiveWindow = contextWindow - Math.min(maxOutputTokens, MAX_OUTPUT_TOKENS_FOR_SUMMARY);
|
|
93
|
+
const cliAutoCompactThreshold = Math.max(0, effectiveWindow - AUTOCOMPACT_BUFFER_TOKENS);
|
|
94
|
+
const clawnetWarnThreshold = Math.max(0, cliAutoCompactThreshold - CLAWNET_EXTRA_BUFFER_TOKENS);
|
|
95
|
+
return {
|
|
96
|
+
contextWindow,
|
|
97
|
+
maxOutputTokens,
|
|
98
|
+
hardLimit,
|
|
99
|
+
effectiveWindow,
|
|
100
|
+
cliAutoCompactThreshold,
|
|
101
|
+
clawnetWarnThreshold,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Rough token count for a string. Mirrors
|
|
106
|
+
* `claude-code/services/tokenEstimation.ts:roughTokenCountEstimation`.
|
|
107
|
+
*
|
|
108
|
+
* For non-string inputs returns 0 — keeps callers from having to null-check
|
|
109
|
+
* every prepend slot they haven't populated.
|
|
110
|
+
*/
|
|
111
|
+
export function estimateText(s, ratio = TOKEN_RATIO_TEXT) {
|
|
112
|
+
if (!s)
|
|
113
|
+
return 0;
|
|
114
|
+
if (ratio <= 0)
|
|
115
|
+
return 0;
|
|
116
|
+
return Math.ceil(s.length / ratio);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Estimate the static prepend that ClawNet injects on every spawn but the
|
|
120
|
+
* underlying CLI cannot see. Two sources contribute:
|
|
121
|
+
*
|
|
122
|
+
* 1. `systemPromptAppend` — the final string that ClawNet hands to
|
|
123
|
+
* `--append-system-prompt`. This already includes memory section +
|
|
124
|
+
* roleId hint + pending notice (assembled in
|
|
125
|
+
* session-manager.ts:189-219), so we just measure the resulting blob.
|
|
126
|
+
*
|
|
127
|
+
* 2. `addedDirs` — every path passed to `--add-dir`. We walk one level
|
|
128
|
+
* deep looking for `.md` files (the only file type the CLI loads
|
|
129
|
+
* eagerly) and sum their sizes / 4. Recursing further gives diminishing
|
|
130
|
+
* returns — most prompt-heavy assets live in the top-level Skill / Brain
|
|
131
|
+
* directories and the CLI lazy-loads anything deeper.
|
|
132
|
+
*
|
|
133
|
+
* I/O here is sync because spawn() itself is sync-ish (waits for `proc.spawn`
|
|
134
|
+
* event) and the read fan-out is small (≤ 4 dirs × small handful of files).
|
|
135
|
+
* If a path is missing or unreadable it's silently skipped — we never want
|
|
136
|
+
* the budget estimator to break a working spawn.
|
|
137
|
+
*/
|
|
138
|
+
export function estimateStaticPrepend(parts) {
|
|
139
|
+
let total = estimateText(parts.systemPromptAppend);
|
|
140
|
+
if (Array.isArray(parts.addedDirs)) {
|
|
141
|
+
for (const dir of parts.addedDirs) {
|
|
142
|
+
total += estimateDirMdSize(dir);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return total;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Walk one level deep, sum size of `.md` files, return token estimate.
|
|
149
|
+
* Lazy import of `node:fs` keeps this module tree-shake-friendly when called
|
|
150
|
+
* from environments that stub the filesystem.
|
|
151
|
+
*/
|
|
152
|
+
function estimateDirMdSize(dir) {
|
|
153
|
+
if (!dir)
|
|
154
|
+
return 0;
|
|
155
|
+
let totalChars = 0;
|
|
156
|
+
try {
|
|
157
|
+
// Deferred require so vitest/jsdom users without `node:fs` polyfills can
|
|
158
|
+
// still import token-budget for the pure functions above.
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
160
|
+
const fs = require("node:fs");
|
|
161
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
162
|
+
const path = require("node:path");
|
|
163
|
+
if (!fs.existsSync(dir))
|
|
164
|
+
return 0;
|
|
165
|
+
const stat = fs.statSync(dir);
|
|
166
|
+
if (!stat.isDirectory())
|
|
167
|
+
return 0;
|
|
168
|
+
const stack = [dir];
|
|
169
|
+
let depthBudget = 2; // dir itself + one nested level
|
|
170
|
+
while (stack.length > 0 && depthBudget > 0) {
|
|
171
|
+
const next = [];
|
|
172
|
+
for (const current of stack) {
|
|
173
|
+
let entries;
|
|
174
|
+
try {
|
|
175
|
+
entries = fs.readdirSync(current, { withFileTypes: true });
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
for (const entry of entries) {
|
|
181
|
+
const full = path.join(current, entry.name);
|
|
182
|
+
if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
|
|
183
|
+
try {
|
|
184
|
+
totalChars += fs.statSync(full).size;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
/* skip unreadable file */
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else if (entry.isDirectory()) {
|
|
191
|
+
next.push(full);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
stack.length = 0;
|
|
196
|
+
stack.push(...next);
|
|
197
|
+
depthBudget -= 1;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
return Math.ceil(totalChars / TOKEN_RATIO_TEXT);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Decide whether to escalate the max_output_tokens ladder. Pure function so
|
|
207
|
+
* SessionManager can drive it deterministically from tests.
|
|
208
|
+
*
|
|
209
|
+
* Escalation rule: `used >= hardLimit − ESCALATE_BUFFER_TOKENS` *and* there
|
|
210
|
+
* is a lower step still available. Once the lowest step is reached we stop
|
|
211
|
+
* escalating — reporting "already at floor" is the caller's job.
|
|
212
|
+
*/
|
|
213
|
+
export function chooseMaxOutputTokens(input) {
|
|
214
|
+
const buffer = input.escalateBufferTokens ?? ESCALATE_BUFFER_TOKENS;
|
|
215
|
+
const currentIndex = clampLadderIndex(input.currentLadderIndex);
|
|
216
|
+
const atFloor = currentIndex >= MAX_TOKENS_LADDER.length - 1;
|
|
217
|
+
const shouldEscalate = !atFloor && input.used >= input.hardLimit - buffer;
|
|
218
|
+
const nextIndex = shouldEscalate ? currentIndex + 1 : currentIndex;
|
|
219
|
+
return {
|
|
220
|
+
ladderIndex: nextIndex,
|
|
221
|
+
maxOutputTokens: MAX_TOKENS_LADDER[nextIndex],
|
|
222
|
+
escalated: shouldEscalate,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=token-budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-budget.js","sourceRoot":"","sources":["../src/token-budget.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,kBAAkB,EAAE,CAAC;QAC9B,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,KAAK,CAAC,EAAE;YACN,YAAY,EAAE,MAAM,CAAC;YACrB,aAAa,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,kBAAkB,EAAE,CAAC;QAC9B,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,KAAK,CAAC,EAAE;YACN,YAAY,EAAE,MAAM,CAAC;YACrB,aAAa,EAAE,MAAM,CAAC;YAKtB,2BAA2B,CAAC,EAAE,MAAM,CAAC;YACrC,uBAAuB,CAAC,EAAE,MAAM,CAAC;SAClC,CAAC;KACH,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,iBAAiB,GACzB,oBAAoB,GACpB,iBAAiB,GACjB,iBAAiB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mclawnet/claude-adapter",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"access": "public"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@mclawnet/shared": "0.1.
|
|
19
|
-
"@mclawnet/logger": "0.1.
|
|
18
|
+
"@mclawnet/shared": "0.1.3",
|
|
19
|
+
"@mclawnet/logger": "0.1.6"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"@mclawnet/agent": "0.6.
|
|
22
|
+
"@mclawnet/agent": "0.6.24"
|
|
23
23
|
},
|
|
24
24
|
"peerDependenciesMeta": {
|
|
25
25
|
"@mclawnet/agent": {
|