hebbian 0.5.0 → 0.5.1
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/api.d.ts.map +1 -1
- package/dist/bin/hebbian.js +60 -19
- package/dist/bin/hebbian.js.map +1 -1
- package/dist/digest.d.ts.map +1 -1
- package/dist/evolve.d.ts.map +1 -1
- package/dist/grow.d.ts.map +1 -1
- package/dist/index.js +49 -6
- package/dist/index.js.map +1 -1
- package/dist/outcome.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/digest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,YAAY;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAwDD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAYjG;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAsD5G;AA6CD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,mBAAmB,EAAE,
|
|
1
|
+
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,YAAY;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAwDD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAYjG;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAsD5G;AA6CD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,mBAAmB,EAAE,CA8B5E"}
|
package/dist/evolve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evolve.d.ts","sourceRoot":"","sources":["../src/evolve.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"evolve.d.ts","sourceRoot":"","sources":["../src/evolve.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAYrC,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CAChB;AAWD,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAkEzF;AAID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAuBtD;AAeD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAyCjG;AAID,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAyDxF;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CA8BzD;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,KAAK,GAAG,YAAY,EAAE,CAwBtF;AAID,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CA8BjF"}
|
package/dist/grow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grow.d.ts","sourceRoot":"","sources":["../src/grow.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"grow.d.ts","sourceRoot":"","sources":["../src/grow.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,CA2C5E"}
|
package/dist/index.js
CHANGED
|
@@ -400,6 +400,9 @@ function growNeuron(brainRoot, neuronPath) {
|
|
|
400
400
|
const counter = fireNeuron(brainRoot, neuronPath);
|
|
401
401
|
return { action: "fired", path: neuronPath, counter };
|
|
402
402
|
}
|
|
403
|
+
if (neuronPath.includes("..") || neuronPath.startsWith("/")) {
|
|
404
|
+
throw new Error(`Invalid neuron path: "${neuronPath}" (path traversal not allowed)`);
|
|
405
|
+
}
|
|
403
406
|
const parts = neuronPath.split("/");
|
|
404
407
|
const regionName = parts[0];
|
|
405
408
|
if (!REGIONS.includes(regionName)) {
|
|
@@ -1295,10 +1298,20 @@ function json(res, data, status = 200) {
|
|
|
1295
1298
|
function error(res, message, status = 400) {
|
|
1296
1299
|
json(res, { error: message }, status);
|
|
1297
1300
|
}
|
|
1301
|
+
var MAX_BODY_BYTES = 1048576;
|
|
1298
1302
|
async function readBody(req) {
|
|
1299
1303
|
return new Promise((resolve3, reject) => {
|
|
1300
1304
|
const chunks = [];
|
|
1301
|
-
|
|
1305
|
+
let total = 0;
|
|
1306
|
+
req.on("data", (chunk) => {
|
|
1307
|
+
total += chunk.length;
|
|
1308
|
+
if (total > MAX_BODY_BYTES) {
|
|
1309
|
+
reject(new Error("Request body too large"));
|
|
1310
|
+
req.destroy();
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
chunks.push(chunk);
|
|
1314
|
+
});
|
|
1302
1315
|
req.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
|
|
1303
1316
|
req.on("error", reject);
|
|
1304
1317
|
});
|
|
@@ -1795,6 +1808,8 @@ function extractCorrections(messages) {
|
|
|
1795
1808
|
if (text.length < MIN_CORRECTION_LENGTH) continue;
|
|
1796
1809
|
if (/^[\/!]/.test(text.trim())) continue;
|
|
1797
1810
|
if (text.trim().endsWith("?")) continue;
|
|
1811
|
+
if (/^<[a-zA-Z]/.test(text.trim())) continue;
|
|
1812
|
+
if (/^Base directory for this skill:/i.test(text.trim())) continue;
|
|
1798
1813
|
const correction = detectCorrection(text);
|
|
1799
1814
|
if (correction) {
|
|
1800
1815
|
corrections.push(correction);
|
|
@@ -1978,6 +1993,10 @@ function writeAuditLog(brainRoot, sessionId, entries) {
|
|
|
1978
1993
|
writeFileSync11(logPath, lines.join("\n") + (lines.length > 0 ? "\n" : ""), "utf8");
|
|
1979
1994
|
}
|
|
1980
1995
|
|
|
1996
|
+
// src/evolve.ts
|
|
1997
|
+
import { existsSync as existsSync16, readFileSync as readFileSync8, writeFileSync as writeFileSync13 } from "fs";
|
|
1998
|
+
import { join as join17 } from "path";
|
|
1999
|
+
|
|
1981
2000
|
// src/outcome.ts
|
|
1982
2001
|
import { execSync as execSync3 } from "child_process";
|
|
1983
2002
|
import { existsSync as existsSync15, mkdirSync as mkdirSync10, writeFileSync as writeFileSync12, readFileSync as readFileSync7, readdirSync as readdirSync10, rmSync as rmSync2, statSync as statSync4 } from "fs";
|
|
@@ -2154,8 +2173,9 @@ function buildOutcomeSummary(brainRoot) {
|
|
|
2154
2173
|
});
|
|
2155
2174
|
for (const [neuron, s] of sorted) {
|
|
2156
2175
|
const ratio = s.sessions > 0 ? (s.reverts / s.sessions).toFixed(2) : "0.00";
|
|
2157
|
-
const trend = parseFloat(ratio) > 0.5 ? "
|
|
2158
|
-
|
|
2176
|
+
const trend = parseFloat(ratio) > 0.5 ? "act on this" : parseFloat(ratio) > 0.3 ? "watch" : "";
|
|
2177
|
+
const safePath = neuron.replace(/[\n\r#]/g, " ").trim();
|
|
2178
|
+
lines.push(`- ${safePath}: sessions=${s.sessions} reverts=${s.reverts} acceptances=${s.acceptances} contra_ratio=${ratio} ${trend}`);
|
|
2159
2179
|
}
|
|
2160
2180
|
lines.push("");
|
|
2161
2181
|
return lines.join("\n");
|
|
@@ -2204,12 +2224,26 @@ var PROTECTED_REGIONS = ["brainstem", "limbic", "sensors"];
|
|
|
2204
2224
|
var DEFAULT_MODEL = "gemini-2.0-flash-lite";
|
|
2205
2225
|
var API_TIMEOUT = 3e4;
|
|
2206
2226
|
var RETRY_DELAY = 5e3;
|
|
2227
|
+
var EVOLVE_COOLDOWN_FILE = "hippocampus/evolve_last_run";
|
|
2207
2228
|
async function runEvolve(brainRoot, dryRun) {
|
|
2208
2229
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
2209
2230
|
if (!apiKey) {
|
|
2210
2231
|
console.error("\u274C GEMINI_API_KEY not set. Get one at https://aistudio.google.com/apikey");
|
|
2211
2232
|
return { actions: [], executed: 0, skipped: 0, dryRun };
|
|
2212
2233
|
}
|
|
2234
|
+
if (!dryRun && process.env.EVOLVE_NO_COOLDOWN !== "1") {
|
|
2235
|
+
const cooldownMs = (parseInt(process.env.EVOLVE_COOLDOWN_SECONDS ?? "60", 10) || 60) * 1e3;
|
|
2236
|
+
const cooldownPath = join17(brainRoot, EVOLVE_COOLDOWN_FILE);
|
|
2237
|
+
if (existsSync16(cooldownPath)) {
|
|
2238
|
+
const lastRun = parseInt(readFileSync8(cooldownPath, "utf8").trim(), 10);
|
|
2239
|
+
const elapsed = Date.now() - lastRun;
|
|
2240
|
+
if (elapsed < cooldownMs) {
|
|
2241
|
+
const remaining = Math.ceil((cooldownMs - elapsed) / 1e3);
|
|
2242
|
+
console.log(`\u23F3 evolve cooldown: ${remaining}s remaining (use EVOLVE_NO_COOLDOWN=1 to bypass)`);
|
|
2243
|
+
return { actions: [], executed: 0, skipped: 0, dryRun };
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2213
2247
|
const episodes = readEpisodes(brainRoot);
|
|
2214
2248
|
const brain = scanBrain(brainRoot);
|
|
2215
2249
|
const summary = buildBrainSummary(brain);
|
|
@@ -2240,6 +2274,7 @@ async function runEvolve(brainRoot, dryRun) {
|
|
|
2240
2274
|
const executed = executeActions(brainRoot, actions);
|
|
2241
2275
|
logEpisode(brainRoot, "evolve", "", `${executed} action(s) executed, ${skipped} skipped`);
|
|
2242
2276
|
console.log(`\u{1F9E0} evolve: ${executed} action(s) executed, ${skipped} skipped`);
|
|
2277
|
+
writeFileSync13(join17(brainRoot, EVOLVE_COOLDOWN_FILE), String(Date.now()), "utf8");
|
|
2243
2278
|
return { actions, executed, skipped, dryRun: false };
|
|
2244
2279
|
}
|
|
2245
2280
|
function buildBrainSummary(brain) {
|
|
@@ -2262,8 +2297,12 @@ function buildBrainSummary(brain) {
|
|
|
2262
2297
|
}
|
|
2263
2298
|
return lines.join("\n");
|
|
2264
2299
|
}
|
|
2300
|
+
function sanitizeForPrompt(text) {
|
|
2301
|
+
const firstLine = (text.split("\n")[0] ?? "").trim();
|
|
2302
|
+
return firstLine.replace(/^#+\s*/g, "").slice(0, 200);
|
|
2303
|
+
}
|
|
2265
2304
|
function buildPrompt(summary, episodes, outcomeSummary) {
|
|
2266
|
-
const episodeLines = episodes.length > 0 ? episodes.map((e) => `- [${e.ts}] ${e.type}: ${e.path} \u2014 ${e.detail}`).join("\n") : "(no recent episodes)";
|
|
2305
|
+
const episodeLines = episodes.length > 0 ? episodes.map((e) => `- [${e.ts}] ${e.type}: ${e.path} \u2014 ${sanitizeForPrompt(e.detail)}`).join("\n") : "(no recent episodes)";
|
|
2267
2306
|
const outcomeSection = outcomeSummary || "";
|
|
2268
2307
|
return `You are the evolve engine for a hebbian brain \u2014 a filesystem-based memory system for AI agents.
|
|
2269
2308
|
|
|
@@ -2302,7 +2341,7 @@ Respond with a JSON array of actions:
|
|
|
2302
2341
|
}
|
|
2303
2342
|
async function callGemini(prompt, apiKey) {
|
|
2304
2343
|
const model = process.env.EVOLVE_MODEL || DEFAULT_MODEL;
|
|
2305
|
-
const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent
|
|
2344
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent`;
|
|
2306
2345
|
const body = {
|
|
2307
2346
|
contents: [{ parts: [{ text: prompt }] }],
|
|
2308
2347
|
generationConfig: {
|
|
@@ -2318,7 +2357,7 @@ async function callGemini(prompt, apiKey) {
|
|
|
2318
2357
|
try {
|
|
2319
2358
|
const res = await fetch(url, {
|
|
2320
2359
|
method: "POST",
|
|
2321
|
-
headers: { "Content-Type": "application/json" },
|
|
2360
|
+
headers: { "Content-Type": "application/json", "x-goog-api-key": apiKey },
|
|
2322
2361
|
body: JSON.stringify(body),
|
|
2323
2362
|
signal: AbortSignal.timeout(API_TIMEOUT)
|
|
2324
2363
|
});
|
|
@@ -2372,6 +2411,10 @@ function parseActions(text) {
|
|
|
2372
2411
|
}
|
|
2373
2412
|
function validateActions(actions, _brain) {
|
|
2374
2413
|
return actions.filter((action) => {
|
|
2414
|
+
if (action.path.includes("..") || action.path.startsWith("/")) {
|
|
2415
|
+
console.log(` \u26A0\uFE0F blocked: ${action.type} ${action.path} (path traversal)`);
|
|
2416
|
+
return false;
|
|
2417
|
+
}
|
|
2375
2418
|
const region = action.path.split("/")[0];
|
|
2376
2419
|
if (!region || PROTECTED_REGIONS.includes(region)) {
|
|
2377
2420
|
console.log(` \u{1F6E1}\uFE0F blocked: ${action.type} ${action.path} (protected region)`);
|