hebbian 0.5.3 → 0.6.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/bin/hebbian.js +61 -5
- package/dist/bin/hebbian.js.map +1 -1
- package/dist/digest.d.ts +42 -0
- package/dist/digest.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/hebbian.js
CHANGED
|
@@ -2065,8 +2065,10 @@ var init_hooks = __esm({
|
|
|
2065
2065
|
// src/digest.ts
|
|
2066
2066
|
var digest_exports = {};
|
|
2067
2067
|
__export(digest_exports, {
|
|
2068
|
+
detectToolFailure: () => detectToolFailure,
|
|
2068
2069
|
digestTranscript: () => digestTranscript,
|
|
2069
2070
|
extractCorrections: () => extractCorrections,
|
|
2071
|
+
parseToolResults: () => parseToolResults,
|
|
2070
2072
|
readHookInput: () => readHookInput
|
|
2071
2073
|
});
|
|
2072
2074
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync12, existsSync as existsSync15, mkdirSync as mkdirSync10 } from "fs";
|
|
@@ -2093,14 +2095,25 @@ function digestTranscript(brainRoot, transcriptPath, sessionId) {
|
|
|
2093
2095
|
const logPath = join16(logDir, `${resolvedSessionId}.jsonl`);
|
|
2094
2096
|
if (existsSync15(logPath)) {
|
|
2095
2097
|
console.log(`\u23ED already digested session ${resolvedSessionId}, skip`);
|
|
2096
|
-
return { corrections: 0, skipped: 0, transcriptPath, sessionId: resolvedSessionId };
|
|
2098
|
+
return { corrections: 0, skipped: 0, toolFailures: 0, transcriptPath, sessionId: resolvedSessionId };
|
|
2097
2099
|
}
|
|
2098
2100
|
const messages = parseTranscript(transcriptPath);
|
|
2101
|
+
const toolFailures = parseToolResults(transcriptPath);
|
|
2102
|
+
for (const failure of toolFailures) {
|
|
2103
|
+
logEpisode(brainRoot, "tool-failure", failure.toolName, failure.errorText);
|
|
2104
|
+
}
|
|
2105
|
+
if (toolFailures.length > 0) {
|
|
2106
|
+
console.log(`\u{1F527} digest: ${toolFailures.length} tool failure(s) logged as episodes`);
|
|
2107
|
+
}
|
|
2099
2108
|
const corrections = extractCorrections(messages);
|
|
2100
|
-
if (corrections.length === 0) {
|
|
2109
|
+
if (corrections.length === 0 && toolFailures.length === 0) {
|
|
2101
2110
|
console.log(`\u{1F4DD} digest: no corrections found in session ${resolvedSessionId}`);
|
|
2102
2111
|
writeAuditLog(brainRoot, resolvedSessionId, []);
|
|
2103
|
-
return { corrections: 0, skipped: messages.length, transcriptPath, sessionId: resolvedSessionId };
|
|
2112
|
+
return { corrections: 0, skipped: messages.length, toolFailures: toolFailures.length, transcriptPath, sessionId: resolvedSessionId };
|
|
2113
|
+
}
|
|
2114
|
+
if (corrections.length === 0) {
|
|
2115
|
+
writeAuditLog(brainRoot, resolvedSessionId, []);
|
|
2116
|
+
return { corrections: 0, skipped: messages.length, toolFailures: toolFailures.length, transcriptPath, sessionId: resolvedSessionId };
|
|
2104
2117
|
}
|
|
2105
2118
|
let applied = 0;
|
|
2106
2119
|
const auditEntries = [];
|
|
@@ -2120,6 +2133,7 @@ function digestTranscript(brainRoot, transcriptPath, sessionId) {
|
|
|
2120
2133
|
return {
|
|
2121
2134
|
corrections: applied,
|
|
2122
2135
|
skipped: messages.length - corrections.length,
|
|
2136
|
+
toolFailures: toolFailures.length,
|
|
2123
2137
|
transcriptPath,
|
|
2124
2138
|
sessionId: resolvedSessionId
|
|
2125
2139
|
};
|
|
@@ -2151,6 +2165,47 @@ function extractText(content) {
|
|
|
2151
2165
|
}
|
|
2152
2166
|
return null;
|
|
2153
2167
|
}
|
|
2168
|
+
function parseToolResults(transcriptPath) {
|
|
2169
|
+
const content = readFileSync7(transcriptPath, "utf8");
|
|
2170
|
+
const lines = content.split("\n").filter(Boolean);
|
|
2171
|
+
const failures = [];
|
|
2172
|
+
for (const line of lines) {
|
|
2173
|
+
if (failures.length >= MAX_FAILURES_PER_SESSION) break;
|
|
2174
|
+
let entry;
|
|
2175
|
+
try {
|
|
2176
|
+
entry = JSON.parse(line);
|
|
2177
|
+
} catch {
|
|
2178
|
+
continue;
|
|
2179
|
+
}
|
|
2180
|
+
if (entry.type !== "user") continue;
|
|
2181
|
+
if (!entry.message || !Array.isArray(entry.message.content)) continue;
|
|
2182
|
+
for (const block of entry.message.content) {
|
|
2183
|
+
if (block.type !== "tool_result") continue;
|
|
2184
|
+
if (!block.is_error) continue;
|
|
2185
|
+
const failure = detectToolFailure(block, entry.toolUseResult);
|
|
2186
|
+
if (failure) failures.push(failure);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
return failures;
|
|
2190
|
+
}
|
|
2191
|
+
function detectToolFailure(block, toolUseResult) {
|
|
2192
|
+
if (!block.is_error) return null;
|
|
2193
|
+
let errorText = "";
|
|
2194
|
+
if (typeof block.content === "string") {
|
|
2195
|
+
errorText = block.content;
|
|
2196
|
+
} else if (Array.isArray(block.content)) {
|
|
2197
|
+
errorText = block.content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join("\n");
|
|
2198
|
+
}
|
|
2199
|
+
if (!errorText && typeof toolUseResult === "string") {
|
|
2200
|
+
errorText = toolUseResult;
|
|
2201
|
+
}
|
|
2202
|
+
if (!errorText) return null;
|
|
2203
|
+
const exitMatch = errorText.match(/^Exit code (\d+)/);
|
|
2204
|
+
const exitCode = exitMatch ? parseInt(exitMatch[1], 10) : 1;
|
|
2205
|
+
const firstLine = errorText.split("\n").find((l) => l.trim() && !l.startsWith("Exit code")) || "unknown";
|
|
2206
|
+
const toolName = firstLine.trim().slice(0, 80);
|
|
2207
|
+
return { toolName, exitCode, errorText: errorText.slice(0, 500) };
|
|
2208
|
+
}
|
|
2154
2209
|
function extractCorrections(messages) {
|
|
2155
2210
|
const corrections = [];
|
|
2156
2211
|
for (const text of messages) {
|
|
@@ -2343,7 +2398,7 @@ function writeAuditLog(brainRoot, sessionId, entries) {
|
|
|
2343
2398
|
);
|
|
2344
2399
|
writeFileSync12(logPath, lines.join("\n") + (lines.length > 0 ? "\n" : ""), "utf8");
|
|
2345
2400
|
}
|
|
2346
|
-
var NEGATION_PATTERNS, AFFIRMATION_PATTERNS, MUST_PATTERNS, WARN_PATTERNS;
|
|
2401
|
+
var NEGATION_PATTERNS, AFFIRMATION_PATTERNS, MUST_PATTERNS, WARN_PATTERNS, MAX_FAILURES_PER_SESSION;
|
|
2347
2402
|
var init_digest = __esm({
|
|
2348
2403
|
"src/digest.ts"() {
|
|
2349
2404
|
"use strict";
|
|
@@ -2389,6 +2444,7 @@ var init_digest = __esm({
|
|
|
2389
2444
|
// Korean
|
|
2390
2445
|
/주의/
|
|
2391
2446
|
];
|
|
2447
|
+
MAX_FAILURES_PER_SESSION = 20;
|
|
2392
2448
|
}
|
|
2393
2449
|
});
|
|
2394
2450
|
|
|
@@ -3060,7 +3116,7 @@ var init_doctor = __esm({
|
|
|
3060
3116
|
init_constants();
|
|
3061
3117
|
import { parseArgs } from "util";
|
|
3062
3118
|
import { resolve as resolve3 } from "path";
|
|
3063
|
-
var VERSION = "0.
|
|
3119
|
+
var VERSION = "0.6.0";
|
|
3064
3120
|
var HELP = `
|
|
3065
3121
|
hebbian v${VERSION} \u2014 Folder-as-neuron brain for any AI agent.
|
|
3066
3122
|
|