claudish 7.31.0 → 7.32.0
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/index.js +267 -52
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -651,7 +651,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
651
651
|
});
|
|
652
652
|
|
|
653
653
|
// src/version.ts
|
|
654
|
-
var VERSION = "7.
|
|
654
|
+
var VERSION = "7.32.0";
|
|
655
655
|
|
|
656
656
|
// src/logger.ts
|
|
657
657
|
var exports_logger = {};
|
|
@@ -36651,6 +36651,7 @@ data: ${JSON.stringify(d)}
|
|
|
36651
36651
|
output_tokens: state.usage?.completion_tokens || 0
|
|
36652
36652
|
}
|
|
36653
36653
|
});
|
|
36654
|
+
behavior?.onTurnEnd?.();
|
|
36654
36655
|
send("message_stop", { type: "message_stop" });
|
|
36655
36656
|
}
|
|
36656
36657
|
if (onTokenUpdate) {
|
|
@@ -36717,6 +36718,7 @@ data: ${JSON.stringify(d)}
|
|
|
36717
36718
|
});
|
|
36718
36719
|
}
|
|
36719
36720
|
if (delta.reasoning_content) {
|
|
36721
|
+
behavior?.onAssistantText?.(delta.reasoning_content, "reasoning");
|
|
36720
36722
|
state.lastActivity = Date.now();
|
|
36721
36723
|
if (!state.reasoningStarted) {
|
|
36722
36724
|
state.reasoningIdx = state.curIdx++;
|
|
@@ -36734,6 +36736,8 @@ data: ${JSON.stringify(d)}
|
|
|
36734
36736
|
});
|
|
36735
36737
|
}
|
|
36736
36738
|
const txt = delta.content || "";
|
|
36739
|
+
if (txt)
|
|
36740
|
+
behavior?.onAssistantText?.(txt, "text");
|
|
36737
36741
|
log(`[Streaming] Text chunk: "${txt.substring(0, 30).replace(/\n/g, "\\n")}" (${txt.length} chars)`);
|
|
36738
36742
|
if (txt) {
|
|
36739
36743
|
state.lastActivity = Date.now();
|
|
@@ -38191,24 +38195,44 @@ function parseBehaviorConfig(raw2) {
|
|
|
38191
38195
|
}
|
|
38192
38196
|
return result.data;
|
|
38193
38197
|
}
|
|
38194
|
-
function resolveSeverity(ruleId, defaultSeverity, config2) {
|
|
38198
|
+
function resolveSeverity(ruleId, defaultSeverity, config2, modelId) {
|
|
38195
38199
|
const rules = config2.rules;
|
|
38196
38200
|
if (!rules)
|
|
38197
38201
|
return defaultSeverity;
|
|
38198
|
-
|
|
38199
|
-
|
|
38200
|
-
|
|
38202
|
+
if (modelId) {
|
|
38203
|
+
const scoped = bestMatch(rules, ruleId, modelId);
|
|
38204
|
+
if (scoped)
|
|
38205
|
+
return scoped;
|
|
38206
|
+
}
|
|
38207
|
+
return bestMatch(rules, ruleId, undefined) ?? defaultSeverity;
|
|
38208
|
+
}
|
|
38209
|
+
function bestMatch(rules, ruleId, modelId) {
|
|
38201
38210
|
let best = null;
|
|
38202
|
-
for (const [
|
|
38203
|
-
|
|
38211
|
+
for (const [key, severity] of Object.entries(rules)) {
|
|
38212
|
+
const { model: keyModel, rule: keyRule } = parseRuleKey(key);
|
|
38213
|
+
if (!scopeMatches(keyModel, modelId))
|
|
38204
38214
|
continue;
|
|
38205
|
-
if (!globMatches(
|
|
38215
|
+
if (!globMatches(keyRule, ruleId))
|
|
38206
38216
|
continue;
|
|
38207
|
-
const
|
|
38208
|
-
if (!best ||
|
|
38209
|
-
best = {
|
|
38217
|
+
const score = specificity(keyRule);
|
|
38218
|
+
if (!best || score > best.score)
|
|
38219
|
+
best = { score, severity };
|
|
38210
38220
|
}
|
|
38211
|
-
return best ? best.severity :
|
|
38221
|
+
return best ? best.severity : null;
|
|
38222
|
+
}
|
|
38223
|
+
function parseRuleKey(key) {
|
|
38224
|
+
const sep = key.indexOf(":");
|
|
38225
|
+
if (sep <= 0 || key.startsWith("hook:"))
|
|
38226
|
+
return { rule: key };
|
|
38227
|
+
return { model: key.slice(0, sep), rule: key.slice(sep + 1) };
|
|
38228
|
+
}
|
|
38229
|
+
function scopeMatches(keyModel, modelId) {
|
|
38230
|
+
if (modelId === undefined)
|
|
38231
|
+
return keyModel === undefined;
|
|
38232
|
+
return keyModel !== undefined && globMatches(keyModel, modelId);
|
|
38233
|
+
}
|
|
38234
|
+
function specificity(pattern) {
|
|
38235
|
+
return pattern.includes("*") ? pattern.replace(/\*/g, "").length : Number.MAX_SAFE_INTEGER;
|
|
38212
38236
|
}
|
|
38213
38237
|
function globMatches(pattern, value) {
|
|
38214
38238
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
@@ -38235,6 +38259,41 @@ var init_config = __esm(() => {
|
|
|
38235
38259
|
});
|
|
38236
38260
|
|
|
38237
38261
|
// src/behavior/harness.ts
|
|
38262
|
+
function extractAvailableSkills(systemText) {
|
|
38263
|
+
if (!systemText)
|
|
38264
|
+
return [];
|
|
38265
|
+
const start = SKILL_SECTION.exec(systemText);
|
|
38266
|
+
if (!start)
|
|
38267
|
+
return [];
|
|
38268
|
+
const out = [];
|
|
38269
|
+
const body = systemText.slice(start.index + start[0].length);
|
|
38270
|
+
for (const line of body.split(`
|
|
38271
|
+
`)) {
|
|
38272
|
+
const trimmed = line.trim();
|
|
38273
|
+
if (!trimmed)
|
|
38274
|
+
continue;
|
|
38275
|
+
const m = SKILL_LINE.exec(trimmed);
|
|
38276
|
+
if (!m) {
|
|
38277
|
+
if (out.length > 0)
|
|
38278
|
+
break;
|
|
38279
|
+
continue;
|
|
38280
|
+
}
|
|
38281
|
+
out.push({ name: m[1], description: m[2].trim() });
|
|
38282
|
+
}
|
|
38283
|
+
return out;
|
|
38284
|
+
}
|
|
38285
|
+
function extractSessionId(claudeRequest) {
|
|
38286
|
+
const raw2 = claudeRequest?.metadata?.user_id;
|
|
38287
|
+
if (typeof raw2 !== "string")
|
|
38288
|
+
return;
|
|
38289
|
+
try {
|
|
38290
|
+
const parsed = JSON.parse(raw2);
|
|
38291
|
+
const id = parsed?.session_id;
|
|
38292
|
+
return typeof id === "string" && id.length > 0 ? id : undefined;
|
|
38293
|
+
} catch {
|
|
38294
|
+
return;
|
|
38295
|
+
}
|
|
38296
|
+
}
|
|
38238
38297
|
function textOf(value) {
|
|
38239
38298
|
if (!value)
|
|
38240
38299
|
return "";
|
|
@@ -38286,7 +38345,7 @@ function detectHarnessFacts(claudeRequest) {
|
|
|
38286
38345
|
}
|
|
38287
38346
|
return facts;
|
|
38288
38347
|
}
|
|
38289
|
-
var PLAN_PATH_PATTERNS, PLAN_MODE_HINT;
|
|
38348
|
+
var PLAN_PATH_PATTERNS, PLAN_MODE_HINT, SKILL_SECTION, SKILL_LINE;
|
|
38290
38349
|
var init_harness = __esm(() => {
|
|
38291
38350
|
PLAN_PATH_PATTERNS = [
|
|
38292
38351
|
/You should create your plan at\s+(\S+?\.md)/,
|
|
@@ -38294,10 +38353,12 @@ var init_harness = __esm(() => {
|
|
|
38294
38353
|
/Read-only except plan file\s*\(([^)]+\.md)\)/
|
|
38295
38354
|
];
|
|
38296
38355
|
PLAN_MODE_HINT = /plan file|create your plan at|Plan mode is active|Plan mode still active/i;
|
|
38356
|
+
SKILL_SECTION = /The following skills are available[^\n]*\n/;
|
|
38357
|
+
SKILL_LINE = /^-\s+([a-z0-9][a-z0-9:_-]*):\s*(.+)$/i;
|
|
38297
38358
|
});
|
|
38298
38359
|
|
|
38299
38360
|
// src/behavior/journal.ts
|
|
38300
|
-
import { appendFile as appendFile2, mkdir, stat } from "fs/promises";
|
|
38361
|
+
import { appendFile as appendFile2, mkdir, readFile, rename, stat, writeFile } from "fs/promises";
|
|
38301
38362
|
import { homedir as homedir18 } from "os";
|
|
38302
38363
|
import { dirname as dirname6, join as join18 } from "path";
|
|
38303
38364
|
function classifyPath(observed, expected) {
|
|
@@ -38313,28 +38374,46 @@ function classifyPath(observed, expected) {
|
|
|
38313
38374
|
function journalPath() {
|
|
38314
38375
|
return join18(homedir18(), ".claudish", "behavior-journal.jsonl");
|
|
38315
38376
|
}
|
|
38377
|
+
async function prune(path) {
|
|
38378
|
+
const content = await readFile(path, "utf8");
|
|
38379
|
+
const lines = content.split(`
|
|
38380
|
+
`).filter(Boolean);
|
|
38381
|
+
let kept = 0;
|
|
38382
|
+
let firstKept = lines.length;
|
|
38383
|
+
for (let i = lines.length - 1;i >= 0; i--) {
|
|
38384
|
+
const cost = Buffer.byteLength(lines[i]) + 1;
|
|
38385
|
+
if (kept + cost > PRUNE_TO_BYTES)
|
|
38386
|
+
break;
|
|
38387
|
+
kept += cost;
|
|
38388
|
+
firstKept = i;
|
|
38389
|
+
}
|
|
38390
|
+
const survivors = lines.slice(firstKept);
|
|
38391
|
+
const tmp = `${path}.pruning`;
|
|
38392
|
+
await writeFile(tmp, survivors.length ? `${survivors.join(`
|
|
38393
|
+
`)}
|
|
38394
|
+
` : "");
|
|
38395
|
+
await rename(tmp, path);
|
|
38396
|
+
log(`[behavior:journal] pruned ${lines.length - survivors.length} of ${lines.length} entries ` + `to stay under ${Math.round(MAX_JOURNAL_BYTES / 1e6)}MB`);
|
|
38397
|
+
}
|
|
38316
38398
|
async function recordDecision(entry, path = journalPath()) {
|
|
38317
38399
|
try {
|
|
38318
38400
|
const size = await stat(path).then((s) => s.size, () => 0);
|
|
38319
|
-
if (size > MAX_JOURNAL_BYTES) {
|
|
38320
|
-
if (!capWarned) {
|
|
38321
|
-
capWarned = true;
|
|
38322
|
-
log(`[behavior:journal] ${path} exceeded ${Math.round(MAX_JOURNAL_BYTES / 1e6)}MB \u2014 ` + "no longer recording. Archive or delete it to resume.");
|
|
38323
|
-
}
|
|
38324
|
-
return;
|
|
38325
|
-
}
|
|
38326
38401
|
if (size === 0)
|
|
38327
38402
|
await mkdir(dirname6(path), { recursive: true }).catch(() => {});
|
|
38403
|
+
if (size > MAX_JOURNAL_BYTES) {
|
|
38404
|
+
await prune(path).catch((err) => log(`[behavior:journal] prune failed: ${err}`));
|
|
38405
|
+
}
|
|
38328
38406
|
await appendFile2(path, `${JSON.stringify(entry)}
|
|
38329
38407
|
`);
|
|
38330
38408
|
} catch (err) {
|
|
38331
38409
|
log(`[behavior:journal] could not record: ${err}`);
|
|
38332
38410
|
}
|
|
38333
38411
|
}
|
|
38334
|
-
var MAX_JOURNAL_BYTES,
|
|
38412
|
+
var MAX_JOURNAL_BYTES, PRUNE_TO_BYTES;
|
|
38335
38413
|
var init_journal = __esm(() => {
|
|
38336
38414
|
init_logger();
|
|
38337
38415
|
MAX_JOURNAL_BYTES = 32 * 1024 * 1024;
|
|
38416
|
+
PRUNE_TO_BYTES = Math.floor(MAX_JOURNAL_BYTES * 0.6);
|
|
38338
38417
|
});
|
|
38339
38418
|
|
|
38340
38419
|
// src/behavior/observer/digest.ts
|
|
@@ -38551,13 +38630,23 @@ class BehaviorSession {
|
|
|
38551
38630
|
modelId;
|
|
38552
38631
|
providerName;
|
|
38553
38632
|
config;
|
|
38633
|
+
engine;
|
|
38554
38634
|
facts = { planModeActive: false };
|
|
38555
38635
|
bufferedTools = new Set;
|
|
38556
|
-
|
|
38636
|
+
textBuf = "";
|
|
38637
|
+
reasoningBuf = "";
|
|
38638
|
+
toolsCalled = [];
|
|
38639
|
+
sessionId;
|
|
38640
|
+
systemText = "";
|
|
38641
|
+
get watchesOutput() {
|
|
38642
|
+
return this.active.some((a) => typeof a.rule.onModelOutput === "function");
|
|
38643
|
+
}
|
|
38644
|
+
constructor(active, modelId, providerName, config2 = {}, engine = { queueCorrection() {}, drainCorrections: () => [] }) {
|
|
38557
38645
|
this.active = active;
|
|
38558
38646
|
this.modelId = modelId;
|
|
38559
38647
|
this.providerName = providerName;
|
|
38560
38648
|
this.config = config2;
|
|
38649
|
+
this.engine = engine;
|
|
38561
38650
|
}
|
|
38562
38651
|
get observerOn() {
|
|
38563
38652
|
return this.config.observer?.enabled === true && (this.config.observer.mode ?? "suggest") !== "off";
|
|
@@ -38591,7 +38680,26 @@ class BehaviorSession {
|
|
|
38591
38680
|
if (this.active.length === 0)
|
|
38592
38681
|
return;
|
|
38593
38682
|
this.facts = detectHarnessFacts(claudeRequest);
|
|
38683
|
+
this.sessionId = extractSessionId(claudeRequest);
|
|
38684
|
+
this.systemText = typeof claudeRequest?.system === "string" ? claudeRequest.system : String(claudeRequest?.system ?? "");
|
|
38685
|
+
this.facts.sessionId = this.sessionId;
|
|
38686
|
+
this.facts.skills = extractAvailableSkills(this.systemText);
|
|
38594
38687
|
this.armBuffering();
|
|
38688
|
+
if (this.sessionId) {
|
|
38689
|
+
for (const text of this.engine.drainCorrections(this.sessionId)) {
|
|
38690
|
+
this.applyAction("behavior/pending-correction", "fix", { type: "injectSystemNote", text }, {
|
|
38691
|
+
modelId: this.modelId,
|
|
38692
|
+
providerName: this.providerName,
|
|
38693
|
+
isNativeAnthropic: false,
|
|
38694
|
+
claudeRequest,
|
|
38695
|
+
claudeTools,
|
|
38696
|
+
tools,
|
|
38697
|
+
messages,
|
|
38698
|
+
systemText: this.systemText,
|
|
38699
|
+
harness: this.facts
|
|
38700
|
+
});
|
|
38701
|
+
}
|
|
38702
|
+
}
|
|
38595
38703
|
const ctx = {
|
|
38596
38704
|
modelId: this.modelId,
|
|
38597
38705
|
providerName: this.providerName,
|
|
@@ -38600,6 +38708,7 @@ class BehaviorSession {
|
|
|
38600
38708
|
claudeTools,
|
|
38601
38709
|
tools,
|
|
38602
38710
|
messages,
|
|
38711
|
+
systemText: this.systemText,
|
|
38603
38712
|
harness: this.facts
|
|
38604
38713
|
};
|
|
38605
38714
|
for (const { rule, severity } of this.active) {
|
|
@@ -38619,6 +38728,66 @@ class BehaviorSession {
|
|
|
38619
38728
|
interceptsTool(toolName) {
|
|
38620
38729
|
return this.bufferedTools.has(toolName);
|
|
38621
38730
|
}
|
|
38731
|
+
observeText(text, kind = "text") {
|
|
38732
|
+
if (!this.watchesOutput || !text)
|
|
38733
|
+
return;
|
|
38734
|
+
const buf = kind === "reasoning" ? this.reasoningBuf : this.textBuf;
|
|
38735
|
+
if (buf.length >= MAX_OBSERVED_CHARS)
|
|
38736
|
+
return;
|
|
38737
|
+
if (kind === "reasoning")
|
|
38738
|
+
this.reasoningBuf += text;
|
|
38739
|
+
else
|
|
38740
|
+
this.textBuf += text;
|
|
38741
|
+
}
|
|
38742
|
+
observeToolCall(toolName) {
|
|
38743
|
+
if (!this.watchesOutput)
|
|
38744
|
+
return;
|
|
38745
|
+
if (this.toolsCalled.length < MAX_OBSERVED_TOOLS)
|
|
38746
|
+
this.toolsCalled.push(toolName);
|
|
38747
|
+
}
|
|
38748
|
+
finishTurn() {
|
|
38749
|
+
if (!this.watchesOutput)
|
|
38750
|
+
return;
|
|
38751
|
+
const ctx = {
|
|
38752
|
+
modelId: this.modelId,
|
|
38753
|
+
providerName: this.providerName,
|
|
38754
|
+
text: this.textBuf,
|
|
38755
|
+
reasoning: this.reasoningBuf,
|
|
38756
|
+
toolsCalled: this.toolsCalled,
|
|
38757
|
+
harness: this.facts
|
|
38758
|
+
};
|
|
38759
|
+
for (const { rule, severity } of this.active) {
|
|
38760
|
+
if (!rule.onModelOutput)
|
|
38761
|
+
continue;
|
|
38762
|
+
let actions = [];
|
|
38763
|
+
try {
|
|
38764
|
+
actions = rule.onModelOutput(ctx) ?? [];
|
|
38765
|
+
} catch (err) {
|
|
38766
|
+
log(`[behavior] rule ${rule.id} onModelOutput threw: ${err}`);
|
|
38767
|
+
continue;
|
|
38768
|
+
}
|
|
38769
|
+
for (const action of actions) {
|
|
38770
|
+
if (action.type === "warn") {
|
|
38771
|
+
log(`[behavior] ${rule.id} (output): ${action.message}`);
|
|
38772
|
+
this.journal("model_output", "warned", { ruleId: rule.id, note: action.message });
|
|
38773
|
+
continue;
|
|
38774
|
+
}
|
|
38775
|
+
if (action.type !== "injectSystemNote")
|
|
38776
|
+
continue;
|
|
38777
|
+
if (severity !== "fix") {
|
|
38778
|
+
this.journal("model_output", "warned", { ruleId: rule.id, note: "correction withheld" });
|
|
38779
|
+
continue;
|
|
38780
|
+
}
|
|
38781
|
+
if (this.sessionId)
|
|
38782
|
+
this.engine.queueCorrection(this.sessionId, action.text);
|
|
38783
|
+
this.journal("model_output", "matched", { ruleId: rule.id, note: "correction queued" });
|
|
38784
|
+
log(`[behavior] ${rule.id} queued a correction for the next request`);
|
|
38785
|
+
}
|
|
38786
|
+
}
|
|
38787
|
+
this.textBuf = "";
|
|
38788
|
+
this.reasoningBuf = "";
|
|
38789
|
+
this.toolsCalled = [];
|
|
38790
|
+
}
|
|
38622
38791
|
repairToolCall(toolName, rawArgs) {
|
|
38623
38792
|
if (!this.bufferedTools.has(toolName))
|
|
38624
38793
|
return null;
|
|
@@ -38786,15 +38955,32 @@ ${action.text}`;
|
|
|
38786
38955
|
class BehaviorEngine {
|
|
38787
38956
|
config;
|
|
38788
38957
|
rules;
|
|
38958
|
+
corrections = new Map;
|
|
38789
38959
|
constructor(config2, rules) {
|
|
38790
38960
|
this.config = config2;
|
|
38791
38961
|
this.rules = rules;
|
|
38792
38962
|
}
|
|
38963
|
+
queueCorrection(key, text) {
|
|
38964
|
+
const list = this.corrections.get(key) ?? [];
|
|
38965
|
+
list.push(text);
|
|
38966
|
+
this.corrections.set(key, list);
|
|
38967
|
+
while (this.corrections.size > MAX_TRACKED_CONVERSATIONS) {
|
|
38968
|
+
const oldest = this.corrections.keys().next().value;
|
|
38969
|
+
if (oldest === undefined)
|
|
38970
|
+
break;
|
|
38971
|
+
this.corrections.delete(oldest);
|
|
38972
|
+
}
|
|
38973
|
+
}
|
|
38974
|
+
drainCorrections(key) {
|
|
38975
|
+
const list = this.corrections.get(key) ?? [];
|
|
38976
|
+
this.corrections.delete(key);
|
|
38977
|
+
return list;
|
|
38978
|
+
}
|
|
38793
38979
|
startSession(params) {
|
|
38794
38980
|
const active = [];
|
|
38795
38981
|
if (!params.isNativeAnthropic) {
|
|
38796
38982
|
for (const rule of this.rules) {
|
|
38797
|
-
const severity = resolveSeverity(rule.id, rule.defaultSeverity, this.config);
|
|
38983
|
+
const severity = resolveSeverity(rule.id, rule.defaultSeverity, this.config, params.modelId);
|
|
38798
38984
|
if (severity === "off")
|
|
38799
38985
|
continue;
|
|
38800
38986
|
let applies = false;
|
|
@@ -38811,14 +38997,16 @@ class BehaviorEngine {
|
|
|
38811
38997
|
if (active.length > 0) {
|
|
38812
38998
|
log(`[behavior] ${active.length} rule(s) active for ${params.modelId}: ` + active.map((a) => `${a.rule.id}=${a.severity}`).join(", "));
|
|
38813
38999
|
}
|
|
38814
|
-
return new BehaviorSession(active, params.modelId, params.providerName, this.config);
|
|
39000
|
+
return new BehaviorSession(active, params.modelId, params.providerName, this.config, this);
|
|
38815
39001
|
}
|
|
38816
39002
|
}
|
|
39003
|
+
var MAX_OBSERVED_CHARS, MAX_OBSERVED_TOOLS = 200, MAX_TRACKED_CONVERSATIONS = 64;
|
|
38817
39004
|
var init_engine = __esm(() => {
|
|
38818
39005
|
init_logger();
|
|
38819
39006
|
init_config();
|
|
38820
39007
|
init_harness();
|
|
38821
39008
|
init_journal();
|
|
39009
|
+
MAX_OBSERVED_CHARS = 64 * 1024;
|
|
38822
39010
|
});
|
|
38823
39011
|
|
|
38824
39012
|
// src/behavior/rules/plan-mode.ts
|
|
@@ -41248,11 +41436,13 @@ data: ${JSON.stringify({
|
|
|
41248
41436
|
}
|
|
41249
41437
|
if (data.type === "content_block_delta" && data.delta?.type === "text_delta") {
|
|
41250
41438
|
const txt = data.delta.text || "";
|
|
41439
|
+
opts.onAssistantText?.(txt, "text");
|
|
41251
41440
|
textChunks++;
|
|
41252
41441
|
log(`[AnthropicSSE] Text chunk: "${txt.substring(0, 30).replace(/\n/g, "\\n")}" (${txt.length} chars)`);
|
|
41253
41442
|
}
|
|
41254
41443
|
if (data.type === "content_block_start" && data.content_block?.type === "tool_use") {
|
|
41255
41444
|
toolUseBlocks++;
|
|
41445
|
+
opts.onToolCallObserved?.(data.content_block.name);
|
|
41256
41446
|
log(`[AnthropicSSE] Tool use: ${data.content_block.name}`);
|
|
41257
41447
|
}
|
|
41258
41448
|
if (data.type === "message_delta" && data.delta?.stop_reason) {
|
|
@@ -41292,10 +41482,12 @@ data: ${JSON.stringify({
|
|
|
41292
41482
|
outputTokens = data.usage.output_tokens || outputTokens;
|
|
41293
41483
|
}
|
|
41294
41484
|
if (data.type === "content_block_delta" && data.delta?.type === "text_delta") {
|
|
41485
|
+
opts.onAssistantText?.(data.delta.text || "", "text");
|
|
41295
41486
|
textChunks++;
|
|
41296
41487
|
}
|
|
41297
41488
|
if (data.type === "content_block_start" && data.content_block?.type === "tool_use") {
|
|
41298
41489
|
toolUseBlocks++;
|
|
41490
|
+
opts.onToolCallObserved?.(data.content_block.name);
|
|
41299
41491
|
log(`[AnthropicSSE] Tool use: ${data.content_block.name}`);
|
|
41300
41492
|
}
|
|
41301
41493
|
if (data.type === "message_delta" && data.delta?.stop_reason) {
|
|
@@ -41306,6 +41498,7 @@ data: ${JSON.stringify({
|
|
|
41306
41498
|
}
|
|
41307
41499
|
}
|
|
41308
41500
|
log(`[AnthropicSSE] Stream complete for ${opts.modelName}: ${totalLines} lines, ${textChunks} text chunks, ${toolUseBlocks} tool_use blocks, stop_reason=${stopReason}${filterThinking ? `, filtered ${thinkingBlocksSuppressed} thinking blocks` : ""}`);
|
|
41501
|
+
opts.onTurnEnd?.();
|
|
41309
41502
|
if (opts.onTokenUpdate) {
|
|
41310
41503
|
opts.onTokenUpdate(inputTokens, outputTokens);
|
|
41311
41504
|
}
|
|
@@ -41434,6 +41627,7 @@ data: ${JSON.stringify(data)}
|
|
|
41434
41627
|
output_tokens: outputTokens
|
|
41435
41628
|
}
|
|
41436
41629
|
});
|
|
41630
|
+
opts.onTurnEnd?.();
|
|
41437
41631
|
send("message_stop", { type: "message_stop" });
|
|
41438
41632
|
}
|
|
41439
41633
|
if (!isClosed) {
|
|
@@ -41541,6 +41735,7 @@ data: ${JSON.stringify(data)}
|
|
|
41541
41735
|
const toolIdx = toolCalls.size;
|
|
41542
41736
|
const toolId = `toolu_${Date.now()}_${toolIdx}`;
|
|
41543
41737
|
const blockIndex = curIdx++;
|
|
41738
|
+
opts.onToolCallObserved?.(part.functionCall.name);
|
|
41544
41739
|
let args = JSON.stringify(part.functionCall.args || {});
|
|
41545
41740
|
if (opts.repairToolArgs) {
|
|
41546
41741
|
try {
|
|
@@ -41879,6 +42074,7 @@ data: ${JSON.stringify(data)}
|
|
|
41879
42074
|
log(`[ResponsesSSE] Event: ${event.type}`);
|
|
41880
42075
|
}
|
|
41881
42076
|
if (event.type === "response.output_text.delta") {
|
|
42077
|
+
opts.onAssistantText?.(event.delta ?? "", "text");
|
|
41882
42078
|
closeReasoning();
|
|
41883
42079
|
if (textIdx < 0) {
|
|
41884
42080
|
textIdx = curIdx++;
|
|
@@ -41914,6 +42110,7 @@ data: ${JSON.stringify(data)}
|
|
|
41914
42110
|
functionCalls.set(itemId, fnCallData);
|
|
41915
42111
|
}
|
|
41916
42112
|
openToolBlocks.add(fnCallData);
|
|
42113
|
+
opts.onToolCallObserved?.(fnName);
|
|
41917
42114
|
if (pendingReasoning.length > 0) {
|
|
41918
42115
|
rememberReasoningForCall(callId, pendingReasoning);
|
|
41919
42116
|
pendingReasoning = [];
|
|
@@ -41926,6 +42123,7 @@ data: ${JSON.stringify(data)}
|
|
|
41926
42123
|
hasToolUse = true;
|
|
41927
42124
|
}
|
|
41928
42125
|
} else if (event.type === "response.reasoning_summary_text.delta") {
|
|
42126
|
+
opts.onAssistantText?.(event.delta ?? "", "reasoning");
|
|
41929
42127
|
const summaryIndex = typeof event.summary_index === "number" ? event.summary_index : 0;
|
|
41930
42128
|
if (reasoningIdx < 0) {
|
|
41931
42129
|
closeText();
|
|
@@ -42088,6 +42286,7 @@ data: ${JSON.stringify(data)}
|
|
|
42088
42286
|
if (opts.middlewareManager) {
|
|
42089
42287
|
await opts.middlewareManager.afterStreamComplete(opts.modelName, streamMetadata);
|
|
42090
42288
|
}
|
|
42289
|
+
opts.onTurnEnd?.();
|
|
42091
42290
|
safeClose();
|
|
42092
42291
|
} catch (error46) {
|
|
42093
42292
|
if (pingInterval) {
|
|
@@ -42904,7 +43103,10 @@ class ComposedHandler {
|
|
|
42904
43103
|
case "openai-sse":
|
|
42905
43104
|
return createStreamingResponseHandler(c, response, adapter, this.bareModelName, this.middlewareManager, onTokenUpdate, claudeRequest.tools, toolNameMap, priorInputTokens, behaviorSession && {
|
|
42906
43105
|
shouldBufferTool: (name) => behaviorSession.interceptsTool(name),
|
|
42907
|
-
onToolCall: (name, argsJson) => behaviorSession.repairToolCall(name, argsJson)
|
|
43106
|
+
onToolCall: (name, argsJson) => behaviorSession.repairToolCall(name, argsJson),
|
|
43107
|
+
onAssistantText: (text, kind) => behaviorSession.observeText(text, kind),
|
|
43108
|
+
onToolCallObserved: (name) => behaviorSession.observeToolCall(name),
|
|
43109
|
+
onTurnEnd: () => behaviorSession.finishTurn()
|
|
42908
43110
|
});
|
|
42909
43111
|
case "openai-responses-sse":
|
|
42910
43112
|
return createResponsesStreamHandler(c, response, {
|
|
@@ -42916,7 +43118,10 @@ class ComposedHandler {
|
|
|
42916
43118
|
priorInputTokens,
|
|
42917
43119
|
middlewareManager: this.middlewareManager,
|
|
42918
43120
|
shouldBufferTool: (name) => behaviorSession?.interceptsTool(name) ?? false,
|
|
42919
|
-
onToolCall: (name, argsJson) => behaviorSession?.repairToolCall(name, argsJson) ?? null
|
|
43121
|
+
onToolCall: (name, argsJson) => behaviorSession?.repairToolCall(name, argsJson) ?? null,
|
|
43122
|
+
onAssistantText: (text, kind) => behaviorSession?.observeText(text, kind),
|
|
43123
|
+
onToolCallObserved: (name) => behaviorSession?.observeToolCall(name),
|
|
43124
|
+
onTurnEnd: () => behaviorSession?.finishTurn()
|
|
42920
43125
|
});
|
|
42921
43126
|
case "anthropic-sse":
|
|
42922
43127
|
return createAnthropicPassthroughStream(c, response, {
|
|
@@ -42924,7 +43129,10 @@ class ComposedHandler {
|
|
|
42924
43129
|
onTokenUpdate,
|
|
42925
43130
|
adapter: this.modelAdapter ?? adapter,
|
|
42926
43131
|
shouldBufferTool: (name) => behaviorSession?.interceptsTool(name) ?? false,
|
|
42927
|
-
repairToolArgs: (name, argsJson) => behaviorSession?.repairToolCall(name, argsJson) ?? null
|
|
43132
|
+
repairToolArgs: (name, argsJson) => behaviorSession?.repairToolCall(name, argsJson) ?? null,
|
|
43133
|
+
onAssistantText: (text, kind) => behaviorSession?.observeText(text, kind),
|
|
43134
|
+
onToolCallObserved: (name) => behaviorSession?.observeToolCall(name),
|
|
43135
|
+
onTurnEnd: () => behaviorSession?.finishTurn()
|
|
42928
43136
|
});
|
|
42929
43137
|
case "gemini-sse": {
|
|
42930
43138
|
const onToolCall = (toolId, name, thoughtSignature) => {
|
|
@@ -42939,6 +43147,9 @@ class ComposedHandler {
|
|
|
42939
43147
|
onTokenUpdate,
|
|
42940
43148
|
onToolCall,
|
|
42941
43149
|
repairToolArgs: (name, argsJson) => behaviorSession?.repairToolCall(name, argsJson) ?? null,
|
|
43150
|
+
onAssistantText: (text, kind) => behaviorSession?.observeText(text, kind),
|
|
43151
|
+
onToolCallObserved: (name) => behaviorSession?.observeToolCall(name),
|
|
43152
|
+
onTurnEnd: () => behaviorSession?.finishTurn(),
|
|
42942
43153
|
unwrapResponse: this.options.unwrapGeminiResponse,
|
|
42943
43154
|
priorInputTokens
|
|
42944
43155
|
});
|
|
@@ -48981,6 +49192,28 @@ Behavior rules
|
|
|
48981
49192
|
console.log(` ${dim2(`observer model: ${obs.model}`)}`);
|
|
48982
49193
|
console.log();
|
|
48983
49194
|
}
|
|
49195
|
+
function printByModel(records) {
|
|
49196
|
+
const byModel = new Map;
|
|
49197
|
+
for (const r of records) {
|
|
49198
|
+
const m = r.model ?? "unknown";
|
|
49199
|
+
const e = byModel.get(m) ?? { ok: 0, degraded: 0 };
|
|
49200
|
+
if (r.outcome === "degraded")
|
|
49201
|
+
e.degraded++;
|
|
49202
|
+
else
|
|
49203
|
+
e.ok++;
|
|
49204
|
+
byModel.set(m, e);
|
|
49205
|
+
}
|
|
49206
|
+
if (byModel.size === 0)
|
|
49207
|
+
return;
|
|
49208
|
+
console.log(bold2(` by model (degraded / ok)
|
|
49209
|
+
`));
|
|
49210
|
+
const ranked = [...byModel.entries()].sort((a, b) => b[1].degraded - a[1].degraded || b[1].ok - a[1].ok);
|
|
49211
|
+
for (const [model, v] of ranked) {
|
|
49212
|
+
const flag = v.degraded > 0 ? yellow(String(v.degraded)) : dim2(String(v.degraded));
|
|
49213
|
+
console.log(` ${model.padEnd(26)} ${flag} / ${v.ok}`);
|
|
49214
|
+
}
|
|
49215
|
+
console.log();
|
|
49216
|
+
}
|
|
48984
49217
|
function showCorpus(write, json2) {
|
|
48985
49218
|
const result = buildCorpus({ write });
|
|
48986
49219
|
if (json2) {
|
|
@@ -48999,25 +49232,7 @@ Behavior divergence corpus
|
|
|
48999
49232
|
console.log(` ${yellow("degraded (no plan)")} : ${degraded.length}`);
|
|
49000
49233
|
console.log(` of those, a rule would have fired on ${catchable.length}
|
|
49001
49234
|
`);
|
|
49002
|
-
|
|
49003
|
-
for (const r of result.records) {
|
|
49004
|
-
const m = r.model ?? "unknown";
|
|
49005
|
-
const e = byModel.get(m) ?? { ok: 0, degraded: 0 };
|
|
49006
|
-
if (r.outcome === "degraded")
|
|
49007
|
-
e.degraded++;
|
|
49008
|
-
else
|
|
49009
|
-
e.ok++;
|
|
49010
|
-
byModel.set(m, e);
|
|
49011
|
-
}
|
|
49012
|
-
if (byModel.size > 0) {
|
|
49013
|
-
console.log(bold2(` by model (degraded / ok)
|
|
49014
|
-
`));
|
|
49015
|
-
for (const [model, v] of [...byModel.entries()].sort((a, b) => b[1].degraded - a[1].degraded || b[1].ok - a[1].ok)) {
|
|
49016
|
-
const flag = v.degraded > 0 ? yellow(String(v.degraded)) : dim2("0");
|
|
49017
|
-
console.log(` ${model.padEnd(26)} ${flag} / ${v.ok}`);
|
|
49018
|
-
}
|
|
49019
|
-
console.log();
|
|
49020
|
-
}
|
|
49235
|
+
printByModel(result.records);
|
|
49021
49236
|
if (result.outputPath) {
|
|
49022
49237
|
console.log(dim2(` appended to ${result.outputPath}
|
|
49023
49238
|
`));
|
|
@@ -49043,9 +49258,9 @@ async function behaviorCommand(argv) {
|
|
|
49043
49258
|
default:
|
|
49044
49259
|
console.error(`Unknown action "${action}".
|
|
49045
49260
|
|
|
49046
|
-
|
|
49047
|
-
|
|
49048
|
-
|
|
49261
|
+
Usage:
|
|
49262
|
+
claudish behavior rules [--json]
|
|
49263
|
+
claudish behavior corpus [--write] [--json]
|
|
49049
49264
|
`);
|
|
49050
49265
|
process.exit(1);
|
|
49051
49266
|
}
|
|
@@ -74829,9 +75044,9 @@ function managedSettingsPath() {
|
|
|
74829
75044
|
}
|
|
74830
75045
|
return "/etc/claude-code/managed-settings.json";
|
|
74831
75046
|
}
|
|
74832
|
-
function managedSettingsForcesClaudeAi(
|
|
75047
|
+
function managedSettingsForcesClaudeAi(readFile2 = readFileSync24) {
|
|
74833
75048
|
try {
|
|
74834
|
-
const raw2 =
|
|
75049
|
+
const raw2 = readFile2(managedSettingsPath(), "utf-8");
|
|
74835
75050
|
const parsed = JSON.parse(raw2);
|
|
74836
75051
|
return parsed.forceLoginMethod === "claudeai";
|
|
74837
75052
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudish",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.32.0",
|
|
4
4
|
"description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"ai"
|
|
61
61
|
],
|
|
62
62
|
"optionalDependencies": {
|
|
63
|
-
"@claudish/magmux-darwin-arm64": "7.
|
|
64
|
-
"@claudish/magmux-darwin-x64": "7.
|
|
65
|
-
"@claudish/magmux-linux-arm64": "7.
|
|
66
|
-
"@claudish/magmux-linux-x64": "7.
|
|
63
|
+
"@claudish/magmux-darwin-arm64": "7.32.0",
|
|
64
|
+
"@claudish/magmux-darwin-x64": "7.32.0",
|
|
65
|
+
"@claudish/magmux-linux-arm64": "7.32.0",
|
|
66
|
+
"@claudish/magmux-linux-x64": "7.32.0"
|
|
67
67
|
},
|
|
68
68
|
"author": "Jack Rudenko <i@madappgang.com>",
|
|
69
69
|
"license": "MIT",
|