osborn 0.9.243 → 0.9.245
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-llm.js +55 -8
- package/package.json +1 -1
package/dist/claude-llm.js
CHANGED
|
@@ -1002,17 +1002,64 @@ class MessageChannel {
|
|
|
1002
1002
|
* refuses, caps, or blocks a dispatch — the agent reads it and decides. Returns
|
|
1003
1003
|
* '' on any error so it can never break the turn.
|
|
1004
1004
|
*/
|
|
1005
|
-
|
|
1005
|
+
/**
|
|
1006
|
+
* Instant CPU busy% from /proc/stat (Linux). One aggregate 'cpu' line: idle+iowait
|
|
1007
|
+
* vs total. Two reads a short interval apart give real-time utilization across all
|
|
1008
|
+
* cores — unlike the 1-min loadavg, which lags a fresh burst of heavy commands by
|
|
1009
|
+
* ~30-60s. Returns null off-Linux / on any parse error (caller falls back to loadavg).
|
|
1010
|
+
*/
|
|
1011
|
+
function readProcStatCpu() {
|
|
1012
|
+
try {
|
|
1013
|
+
const line = readFileSync('/proc/stat', 'utf8').split('\n', 1)[0];
|
|
1014
|
+
const n = line.trim().split(/\s+/).slice(1).map(Number); // drop the "cpu" label
|
|
1015
|
+
if (n.length < 5 || n.some(Number.isNaN))
|
|
1016
|
+
return null;
|
|
1017
|
+
const idle = n[3] + (n[4] || 0); // idle + iowait
|
|
1018
|
+
const total = n.reduce((a, b) => a + b, 0);
|
|
1019
|
+
return { idle, total };
|
|
1020
|
+
}
|
|
1021
|
+
catch {
|
|
1022
|
+
return null;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
async function buildMachineNudge() {
|
|
1006
1026
|
try {
|
|
1007
1027
|
const ncpu = Math.max(1, cpus().length);
|
|
1008
|
-
|
|
1028
|
+
// #3: prefer an INSTANT CPU read (proc/stat delta over ~200ms) over the lagging
|
|
1029
|
+
// 1-min loadavg, so a fresh storm of tsc/build/test shows up on THIS turn, not a
|
|
1030
|
+
// minute later. Falls back to loadavg÷cores off-Linux or if the delta is unusable.
|
|
1031
|
+
let cpuPct;
|
|
1032
|
+
const a = readProcStatCpu();
|
|
1033
|
+
if (a) {
|
|
1034
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
1035
|
+
const b = readProcStatCpu();
|
|
1036
|
+
const dTotal = b ? b.total - a.total : 0;
|
|
1037
|
+
cpuPct = b && dTotal > 0
|
|
1038
|
+
? Math.round(((dTotal - (b.idle - a.idle)) / dTotal) * 100)
|
|
1039
|
+
: Math.round((loadavg()[0] / ncpu) * 100);
|
|
1040
|
+
}
|
|
1041
|
+
else {
|
|
1042
|
+
cpuPct = Math.round((loadavg()[0] / ncpu) * 100);
|
|
1043
|
+
}
|
|
1009
1044
|
const memPct = Math.round((1 - freemem() / totalmem()) * 100);
|
|
1010
1045
|
const subagents = statusManager.getActiveDispatchIds().length;
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1046
|
+
// Recommended concurrent heavy sub-agents, adapted to live headroom. A concrete
|
|
1047
|
+
// DEFAULT the agent follows unless a task warrants otherwise — never enforced.
|
|
1048
|
+
const recMax = (cpuPct >= 80 || memPct >= 90) ? Math.max(1, ncpu - 1) // hot: pull back below cores
|
|
1049
|
+
: (cpuPct >= 60) ? ncpu // busy: ~cores
|
|
1050
|
+
: ncpu + 1; // calm: a little headroom
|
|
1051
|
+
const over = subagents > recMax;
|
|
1052
|
+
const warn = over || cpuPct >= 80;
|
|
1053
|
+
// #4: name the actual CPU culprits — the spikes come from heavy COMMANDS sub-agents
|
|
1054
|
+
// run, not their count. One tsc/build/test pegs a core for 30-120s; ten file-reading
|
|
1055
|
+
// agents barely register. Tell the agent WHAT to throttle.
|
|
1056
|
+
const culprits = 'CPU cost is heavy commands (tsc/typecheck, build, test, npm/pnpm install, eslint) — not agent count. Prefer scoped/incremental runs, cache, and never fire several at once.';
|
|
1057
|
+
const head = `[MACHINE${warn ? ' ⚠️' : ''}] CPU ${cpuPct}% · MEM ${memPct}% · sub-agents ${subagents}/${recMax} recommended`;
|
|
1058
|
+
if (over)
|
|
1059
|
+
return `${head} — over the recommended concurrency; wind down to ≤${recMax} (finish or stop in-flight sub-agents) unless a task must continue. ${culprits} (recommendation — the agent decides, not enforced)`;
|
|
1060
|
+
if (cpuPct >= 80)
|
|
1061
|
+
return `${head} — load high; hold new sub-agents beyond ${recMax} unless needed. ${culprits} (recommendation — the agent decides, not enforced)`;
|
|
1062
|
+
return head;
|
|
1016
1063
|
}
|
|
1017
1064
|
catch {
|
|
1018
1065
|
return '';
|
|
@@ -2055,7 +2102,7 @@ class ClaudeLLMStream extends llm.LLMStream {
|
|
|
2055
2102
|
// Lightweight machine-load nudge (main agent only). Cheap synchronous
|
|
2056
2103
|
// snapshot, prepended so it's present even when recall degrades under load.
|
|
2057
2104
|
// Advisory only — never caps/refuses a dispatch.
|
|
2058
|
-
const machineNudge = fromSubagent ? '' : buildMachineNudge();
|
|
2105
|
+
const machineNudge = fromSubagent ? '' : await buildMachineNudge();
|
|
2059
2106
|
const additionalContext = [machineNudge, reminder, recalled].filter(Boolean).join('\n\n');
|
|
2060
2107
|
console.log(`📌 UserPromptSubmit: injected turn-shape reminder (${reminder.length} chars)${recalled ? ` + recall (${recalled.length} chars)` : ''}${machineNudge ? ` + machine(${machineNudge.includes('⚠️') ? 'HOT' : 'ok'})` : ''} for prompt="${promptPreview}..." [tool budget reset to 0/${TOOL_CALL_BUDGET}]`);
|
|
2061
2108
|
return {
|