open-think 0.2.3 → 0.2.4

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.
Files changed (2) hide show
  1. package/dist/index.js +61 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -276,6 +276,13 @@ var migrations = [
276
276
  db2.exec("ALTER TABLE memories ADD COLUMN episode_key TEXT;");
277
277
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memories_episode_key ON memories(episode_key);");
278
278
  }
279
+ },
280
+ {
281
+ version: 4,
282
+ up: (db2) => {
283
+ db2.exec("ALTER TABLE engrams ADD COLUMN context TEXT;");
284
+ db2.exec("ALTER TABLE engrams ADD COLUMN decisions TEXT;");
285
+ }
279
286
  }
280
287
  ];
281
288
  function getCortexDb(cortexName) {
@@ -307,10 +314,12 @@ function insertEngram(cortexName, params) {
307
314
  const expiresInDays = params.expiresInDays ?? 60;
308
315
  const expires_at = new Date(now.getTime() + expiresInDays * 864e5).toISOString();
309
316
  const episodeKey = params.episodeKey ?? null;
317
+ const context = params.context ?? null;
318
+ const decisions = params.decisions?.length ? JSON.stringify(params.decisions) : null;
310
319
  db2.prepare(
311
- `INSERT INTO engrams (id, content, created_at, expires_at, episode_key) VALUES (?, ?, ?, ?, ?)`
312
- ).run(id, params.content, created_at, expires_at, episodeKey);
313
- return { id, content: params.content, created_at, expires_at, evaluated_at: null, promoted: null, deleted_at: null, episode_key: episodeKey };
320
+ `INSERT INTO engrams (id, content, created_at, expires_at, episode_key, context, decisions) VALUES (?, ?, ?, ?, ?, ?, ?)`
321
+ ).run(id, params.content, created_at, expires_at, episodeKey, context, decisions);
322
+ return { id, content: params.content, created_at, expires_at, evaluated_at: null, promoted: null, deleted_at: null, episode_key: episodeKey, context, decisions };
314
323
  }
315
324
  function getPendingEngrams(cortexName) {
316
325
  const db2 = getCortexDb(cortexName);
@@ -501,7 +510,7 @@ var logCommand = new Command("log").description("Log a note or entry").argument(
501
510
  }
502
511
  closeDb();
503
512
  });
504
- var syncCommand = new Command("sync").description("Log a sync/work-log entry (shorthand for log --category sync)").argument("<message>", "The message to log").option("-s, --source <source>", "Source of the entry", "manual").option("-t, --tags <tags>", "Comma-separated tags").option("-e, --episode <key>", "Tag this engram with an episode identifier").option("--silent", "Suppress output").action(function(message, opts) {
513
+ var syncCommand = new Command("sync").description("Log a sync/work-log entry (shorthand for log --category sync)").argument("<message>", "The message to log").option("-s, --source <source>", "Source of the entry", "manual").option("-t, --tags <tags>", "Comma-separated tags").option("-e, --episode <key>", "Tag this engram with an episode identifier").option("--context <json>", "Attach structured JSON metadata to this engram").option("-d, --decision <text>", "Record a decision (repeatable)", (val, prev) => [...prev, val], []).option("--silent", "Suppress output").action(function(message, opts) {
505
514
  const globalOpts = this.optsWithGlobals();
506
515
  const config = getConfig();
507
516
  if (config.paused) {
@@ -516,7 +525,17 @@ var syncCommand = new Command("sync").description("Log a sync/work-log entry (sh
516
525
  console.log(chalk.yellow(` \u26A0 ${w}`));
517
526
  }
518
527
  }
519
- const engram = insertEngram(cortex, { content: message, episodeKey: opts.episode });
528
+ if (opts.context) {
529
+ try {
530
+ JSON.parse(opts.context);
531
+ } catch {
532
+ console.error(chalk.red("Error: --context must be valid JSON"));
533
+ process.exitCode = 1;
534
+ return;
535
+ }
536
+ }
537
+ const decisions = opts.decision?.length ? opts.decision : void 0;
538
+ const engram = insertEngram(cortex, { content: message, episodeKey: opts.episode, context: opts.context, decisions });
520
539
  if (!opts.silent) {
521
540
  const badge = chalk.cyan(`[${cortex}]`);
522
541
  const ts = chalk.gray(engram.created_at.slice(0, 16).replace("T", " "));
@@ -1214,6 +1233,7 @@ Your task:
1214
1233
  - Blockers encountered or resolved
1215
1234
  - Clusters \u2014 multiple events around the same topic signal importance
1216
1235
  - Weight \u2014 urgency, frustration, or surprise in the language suggests significance
1236
+ - Decisions \u2014 events with explicit decisions attached are high-signal and should almost always be promoted. Preserve the decision rationale in the memory.
1217
1237
  4. Routine, administrative, or low-signal events should be dropped.
1218
1238
  Dropping is correct, not a failure.
1219
1239
 
@@ -1279,7 +1299,24 @@ function assembleCurationPrompt(params) {
1279
1299
  const longtermText = params.longtermSummary ?? "(no long-term context yet)";
1280
1300
  const recentText = params.recentMemories.length > 0 ? params.recentMemories.map((m) => `- [${m.ts}] ${m.author}: ${m.content}`).join("\n") : "(no recent memories)";
1281
1301
  const curatorMdText = params.curatorMd ?? "(none provided)";
1282
- const engramsText = params.pendingEngrams.map((e) => `- [${e.created_at}] (id: ${e.id}) ${e.content}`).join("\n");
1302
+ const engramsText = params.pendingEngrams.map((e) => {
1303
+ let line = `- [${e.created_at}] (id: ${e.id}) ${e.content}`;
1304
+ if (e.decisions) {
1305
+ try {
1306
+ const decisions = JSON.parse(e.decisions);
1307
+ if (decisions.length > 0) {
1308
+ line += `
1309
+ Decisions: ${decisions.map((d) => `"${d}"`).join("; ")}`;
1310
+ }
1311
+ } catch {
1312
+ }
1313
+ }
1314
+ if (e.context) {
1315
+ line += `
1316
+ Context: ${e.context}`;
1317
+ }
1318
+ return line;
1319
+ }).join("\n");
1283
1320
  const userMessage = [
1284
1321
  "## Long-term context (compressed history)",
1285
1322
  wrapData("longterm-summary", longtermText),
@@ -1431,7 +1468,24 @@ Output: Return a JSON object with a single "content" field containing your narra
1431
1468
 
1432
1469
  Do not include markdown, code fences, or explanation outside the JSON.`;
1433
1470
  function assembleEpisodeCurationPrompt(params) {
1434
- const engramsText = params.pendingEngrams.map((e) => `- [${e.created_at}] ${e.content}`).join("\n");
1471
+ const engramsText = params.pendingEngrams.map((e) => {
1472
+ let line = `- [${e.created_at}] ${e.content}`;
1473
+ if (e.decisions) {
1474
+ try {
1475
+ const decisions = JSON.parse(e.decisions);
1476
+ if (decisions.length > 0) {
1477
+ line += `
1478
+ Decisions: ${decisions.map((d) => `"${d}"`).join("; ")}`;
1479
+ }
1480
+ } catch {
1481
+ }
1482
+ }
1483
+ if (e.context) {
1484
+ line += `
1485
+ Context: ${e.context}`;
1486
+ }
1487
+ return line;
1488
+ }).join("\n");
1435
1489
  const sections = [
1436
1490
  "## Episode",
1437
1491
  wrapData("episode-key", params.episodeKey),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-think",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "Local-first CLI that gives AI agents persistent, curated memory",
6
6
  "bin": {