@miriad-systems/nuum 0.1.9 → 0.1.10

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 CHANGED
@@ -17400,7 +17400,8 @@ __export(exports_schema, {
17400
17400
  temporalMessages: () => temporalMessages,
17401
17401
  sessionConfig: () => sessionConfig,
17402
17402
  presentState: () => presentState,
17403
- ltmEntries: () => ltmEntries
17403
+ ltmEntries: () => ltmEntries,
17404
+ backgroundReports: () => backgroundReports
17404
17405
  });
17405
17406
 
17406
17407
  // node_modules/drizzle-orm/entity.js
@@ -18694,6 +18695,15 @@ var workers = sqliteTable("workers", {
18694
18695
  completedAt: text("completed_at"),
18695
18696
  error: text("error")
18696
18697
  });
18698
+ var backgroundReports = sqliteTable("background_reports", {
18699
+ id: text("id").primaryKey(),
18700
+ createdAt: text("created_at").notNull(),
18701
+ subsystem: text("subsystem").notNull(),
18702
+ report: text("report").notNull(),
18703
+ surfacedAt: text("surfaced_at")
18704
+ }, (table) => [
18705
+ index("idx_background_reports_unsurfaced").on(table.surfacedAt)
18706
+ ]);
18697
18707
 
18698
18708
  // src/storage/db.ts
18699
18709
  var isBun = typeof globalThis.Bun !== "undefined";
@@ -23457,7 +23467,9 @@ var Identifier;
23457
23467
  task: "tsk",
23458
23468
  entry: "ent",
23459
23469
  worker: "wrk",
23460
- session: "ses"
23470
+ report: "rpt",
23471
+ session: "ses",
23472
+ toolcall: "tcl"
23461
23473
  };
23462
23474
  function schema(prefix) {
23463
23475
  return exports_external.string().startsWith(prefixes[prefix]);
@@ -23561,6 +23573,45 @@ function createSessionStorage(db) {
23561
23573
  };
23562
23574
  }
23563
23575
 
23576
+ // src/storage/background.ts
23577
+ function createBackgroundStorage(db) {
23578
+ return {
23579
+ async fileReport(input) {
23580
+ const id = Identifier.ascending("report");
23581
+ const now = new Date().toISOString();
23582
+ await db.insert(backgroundReports).values({
23583
+ id,
23584
+ createdAt: now,
23585
+ subsystem: input.subsystem,
23586
+ report: JSON.stringify(input.report)
23587
+ });
23588
+ return id;
23589
+ },
23590
+ async getUnsurfaced() {
23591
+ const rows = await db.select().from(backgroundReports).where(isNull(backgroundReports.surfacedAt)).orderBy(backgroundReports.createdAt);
23592
+ return rows.map((row) => ({
23593
+ id: row.id,
23594
+ createdAt: row.createdAt,
23595
+ subsystem: row.subsystem,
23596
+ report: JSON.parse(row.report),
23597
+ surfacedAt: row.surfacedAt
23598
+ }));
23599
+ },
23600
+ async markSurfaced(id) {
23601
+ const now = new Date().toISOString();
23602
+ await db.update(backgroundReports).set({ surfacedAt: now }).where(eq(backgroundReports.id, id));
23603
+ },
23604
+ async markManySurfaced(ids) {
23605
+ if (ids.length === 0)
23606
+ return;
23607
+ const now = new Date().toISOString();
23608
+ for (const id of ids) {
23609
+ await db.update(backgroundReports).set({ surfacedAt: now }).where(eq(backgroundReports.id, id));
23610
+ }
23611
+ }
23612
+ };
23613
+ }
23614
+
23564
23615
  // src/storage/index.ts
23565
23616
  function createStorage(dbPath, options) {
23566
23617
  const { mkdirSync } = __require("fs");
@@ -23579,6 +23630,7 @@ function createStorageFromDb(db) {
23579
23630
  ltm: createLTMStorage(db),
23580
23631
  workers: createWorkerStorage(db),
23581
23632
  session: createSessionStorage(db),
23633
+ background: createBackgroundStorage(db),
23582
23634
  _db: db
23583
23635
  };
23584
23636
  }
@@ -34945,16 +34997,17 @@ function buildCreateDistillationTool(ctx, results) {
34945
34997
  }
34946
34998
  function buildFinishDistillationTool(results) {
34947
34999
  return tool({
34948
- description: "Signal that working memory optimization is complete. Call when you've distilled enough or no more optimization is beneficial.",
35000
+ description: "Signal that working memory optimization is complete. Write a contextual summary for your future self explaining what you compressed and what you retained.",
34949
35001
  parameters: exports_external.object({
34950
- reason: exports_external.string().describe("Brief explanation (e.g., 'reached target', 'recent content needs detail for ongoing work')")
35002
+ summary: exports_external.string().describe("A note to your future self: what did you compress and what key information did you retain? Example: 'Combined the three debugging sessions into one distillation - retained the key insight about the race condition and the fix in src/agent/loop.ts.'")
34951
35003
  }),
34952
- execute: async ({ reason }, { toolCallId }) => {
34953
- log6.info("distillation finished", { reason });
35004
+ execute: async ({ summary }, { toolCallId }) => {
35005
+ log6.info("distillation finished", { summary });
34954
35006
  const result = {
34955
- output: `Distillation complete: ${reason}`,
35007
+ output: `Distillation complete`,
34956
35008
  done: true,
34957
- distillationCreated: false
35009
+ distillationCreated: false,
35010
+ summary
34958
35011
  };
34959
35012
  results.set(toolCallId, result);
34960
35013
  return result.output;
@@ -35044,6 +35097,19 @@ For each distillation, call **create_distillation** with:
35044
35097
 
35045
35098
  Call **finish_distillation** when you've optimized enough or no more distillation is beneficial.
35046
35099
 
35100
+ ### Writing Your Summary
35101
+
35102
+ When you call \`finish_distillation\`, write a brief note to your future self explaining what you compressed and what you retained. This is a dialog between your subconscious (the compactor) and your conscious self (the main agent).
35103
+
35104
+ **Good summaries** explain the WHAT and WHY:
35105
+ - "Combined the three debugging sessions into one distillation - retained the key insight about the race condition and the fix in src/agent/loop.ts."
35106
+ - "Distilled the API refactoring work, keeping all the endpoint paths and the decision to use REST over GraphQL."
35107
+ - "Compressed the deployment troubleshooting - kept the final working config and the gotcha about environment variables."
35108
+
35109
+ **Avoid mechanical summaries**:
35110
+ - \u2717 "Reached target"
35111
+ - \u2717 "Created 3 distillations"
35112
+
35047
35113
  **Remember:** You're optimizing your own working memory. Keep what helps you act with precision.
35048
35114
  `;
35049
35115
  }
@@ -35128,6 +35194,9 @@ async function runCompaction(storage, config) {
35128
35194
  if (toolResult?.distillationCreated) {
35129
35195
  result.distillationsCreated++;
35130
35196
  }
35197
+ if (toolResult?.summary) {
35198
+ result.summary = toolResult.summary;
35199
+ }
35131
35200
  }
35132
35201
  });
35133
35202
  } catch (error) {
@@ -44340,7 +44409,7 @@ var LTMTools = {
44340
44409
  };
44341
44410
  // src/ltm/consolidation.ts
44342
44411
  var log9 = Log.create({ service: "consolidation-agent" });
44343
- var MAX_CONSOLIDATION_TURNS = 10;
44412
+ var MAX_CONSOLIDATION_TURNS = 20;
44344
44413
  var AGENT_TYPE = "ltm-consolidate";
44345
44414
  function isConversationNoteworthy(messages) {
44346
44415
  if (messages.length < 5) {
@@ -44414,7 +44483,13 @@ function buildConsolidationTools(storage) {
44414
44483
  if (entryCreated) {
44415
44484
  activity.ltmCurator.ltmOperation("create", args.slug, args.title);
44416
44485
  }
44417
- const result = { output: toolResult.output, done: false, entryCreated };
44486
+ const result = {
44487
+ output: toolResult.output,
44488
+ done: false,
44489
+ entryCreated,
44490
+ slug: args.slug,
44491
+ title: args.title
44492
+ };
44418
44493
  results.set(toolCallId, result);
44419
44494
  return result.output;
44420
44495
  }
@@ -44428,7 +44503,12 @@ function buildConsolidationTools(storage) {
44428
44503
  if (entryUpdated) {
44429
44504
  activity.ltmCurator.ltmOperation("update", args.slug);
44430
44505
  }
44431
- const result = { output: toolResult.output, done: false, entryUpdated };
44506
+ const result = {
44507
+ output: toolResult.output,
44508
+ done: false,
44509
+ entryUpdated,
44510
+ slug: args.slug
44511
+ };
44432
44512
  results.set(toolCallId, result);
44433
44513
  return result.output;
44434
44514
  }
@@ -44442,7 +44522,12 @@ function buildConsolidationTools(storage) {
44442
44522
  if (entryUpdated) {
44443
44523
  activity.ltmCurator.ltmOperation("update", args.slug, "surgical edit");
44444
44524
  }
44445
- const result = { output: toolResult.output, done: false, entryUpdated };
44525
+ const result = {
44526
+ output: toolResult.output,
44527
+ done: false,
44528
+ entryUpdated,
44529
+ slug: args.slug
44530
+ };
44446
44531
  results.set(toolCallId, result);
44447
44532
  return result.output;
44448
44533
  }
@@ -44456,7 +44541,12 @@ function buildConsolidationTools(storage) {
44456
44541
  if (entryUpdated) {
44457
44542
  activity.ltmCurator.ltmOperation("reparent", args.slug, `\u2192 ${args.newParentSlug ?? "root"}`);
44458
44543
  }
44459
- const result = { output: toolResult.output, done: false, entryUpdated };
44544
+ const result = {
44545
+ output: toolResult.output,
44546
+ done: false,
44547
+ entryUpdated,
44548
+ slug: args.slug
44549
+ };
44460
44550
  results.set(toolCallId, result);
44461
44551
  return result.output;
44462
44552
  }
@@ -44470,7 +44560,12 @@ function buildConsolidationTools(storage) {
44470
44560
  if (entryUpdated) {
44471
44561
  activity.ltmCurator.ltmOperation("rename", args.slug, `\u2192 ${args.newSlug}`);
44472
44562
  }
44473
- const result = { output: toolResult.output, done: false, entryUpdated };
44563
+ const result = {
44564
+ output: toolResult.output,
44565
+ done: false,
44566
+ entryUpdated,
44567
+ slug: args.slug
44568
+ };
44474
44569
  results.set(toolCallId, result);
44475
44570
  return result.output;
44476
44571
  }
@@ -44484,7 +44579,12 @@ function buildConsolidationTools(storage) {
44484
44579
  if (entryArchived) {
44485
44580
  activity.ltmCurator.ltmOperation("archive", args.slug);
44486
44581
  }
44487
- const result = { output: toolResult.output, done: false, entryArchived };
44582
+ const result = {
44583
+ output: toolResult.output,
44584
+ done: false,
44585
+ entryArchived,
44586
+ slug: args.slug
44587
+ };
44488
44588
  results.set(toolCallId, result);
44489
44589
  return result.output;
44490
44590
  }
@@ -44565,9 +44665,9 @@ function buildConsolidationTools(storage) {
44565
44665
  }
44566
44666
  });
44567
44667
  tools.finish_consolidation = tool({
44568
- description: "Call this when you have finished curating the knowledge base. Always call this to complete the task.",
44668
+ description: "Call this when you have finished curating the knowledge base. Write a contextual summary for your future self.",
44569
44669
  parameters: exports_external.object({
44570
- summary: exports_external.string().describe("Brief summary of what you did: entries created/updated, research performed, organization changes, etc.")
44670
+ summary: exports_external.string().describe("A note to your future self: what did you capture and why does it matter? Reference entries with [[slug]] syntax. Example: 'Captured the bloom filter insights in [[bloom-filter-overview]]. Archived X system workarounds since it's decommissioned.'")
44571
44671
  }),
44572
44672
  execute: async ({ summary }, { toolCallId }) => {
44573
44673
  const result = { output: "Curation complete", done: true, summary };
@@ -44742,7 +44842,20 @@ Review these entries periodically. Are they accurate? Complete? Do they reflect
44742
44842
  1. **First**: Capture any insights from the recent conversation (this is the priority)
44743
44843
  2. **Then**: Look at your knowledge base - is it serving you well? Improve it.
44744
44844
  3. **Check**: Are /identity and /behavior current? Update them if you've learned something new.
44745
- 4. **Finally**: Call \`finish_consolidation\` with a summary of what you did
44845
+ 4. **Finally**: Call \`finish_consolidation\` with a contextual summary
44846
+
44847
+ ### Writing Your Summary
44848
+
44849
+ When you call \`finish_consolidation\`, write a brief note to your future self explaining what you captured and why it matters. This is a dialog between your subconscious (the curator) and your conscious self (the main agent).
44850
+
44851
+ **Good summaries** explain the WHAT and WHY:
44852
+ - "Captured the insights on probabilistic filtering in [[bloom-filter-overview]]. Also archived the X system workarounds since it's been decommissioned."
44853
+ - "Updated [[user-preferences]] with the new testing philosophy - run tests before committing. Created [[cast-integration]] to document the engine abstraction pattern."
44854
+ - "Reorganized the codebase knowledge - moved protocol docs under [[miriad-code/protocol]] and cross-linked with [[memory-system]]."
44855
+
44856
+ **Avoid mechanical summaries**:
44857
+ - \u2717 "Created 2 entries, updated 1 entry"
44858
+ - \u2717 "Finished curation"
44746
44859
 
44747
44860
  Be proactive! This is YOUR knowledge base. Make it useful.
44748
44861
  `;
@@ -44755,6 +44868,7 @@ async function runConsolidation(storage, messages) {
44755
44868
  entriesUpdated: 0,
44756
44869
  entriesArchived: 0,
44757
44870
  summary: "",
44871
+ details: [],
44758
44872
  usage: { inputTokens: 0, outputTokens: 0 }
44759
44873
  };
44760
44874
  if (!isConversationNoteworthy(messages)) {
@@ -44792,12 +44906,21 @@ ${reviewTurnContent}` }
44792
44906
  const toolResult = getLastResult(toolCallId);
44793
44907
  if (toolResult?.entryCreated) {
44794
44908
  result.entriesCreated++;
44909
+ if (toolResult.slug) {
44910
+ result.details.push(`Created [[${toolResult.slug}]]${toolResult.title ? ` - ${toolResult.title}` : ""}`);
44911
+ }
44795
44912
  }
44796
44913
  if (toolResult?.entryUpdated) {
44797
44914
  result.entriesUpdated++;
44915
+ if (toolResult.slug) {
44916
+ result.details.push(`Updated [[${toolResult.slug}]]`);
44917
+ }
44798
44918
  }
44799
44919
  if (toolResult?.entryArchived) {
44800
44920
  result.entriesArchived++;
44921
+ if (toolResult.slug) {
44922
+ result.details.push(`Archived [[${toolResult.slug}]]`);
44923
+ }
44801
44924
  }
44802
44925
  if (toolResult?.summary) {
44803
44926
  result.summary = toolResult.summary;
@@ -44874,6 +44997,16 @@ async function runLTMConsolidation(storage) {
44874
44997
  const changes = result.entriesCreated + result.entriesUpdated + result.entriesArchived;
44875
44998
  if (changes > 0) {
44876
44999
  activity.ltmCurator.complete(`${result.entriesCreated} created, ${result.entriesUpdated} updated, ${result.entriesArchived} archived`);
45000
+ await storage.background.fileReport({
45001
+ subsystem: "ltm_curator",
45002
+ report: {
45003
+ entriesCreated: result.entriesCreated,
45004
+ entriesUpdated: result.entriesUpdated,
45005
+ entriesArchived: result.entriesArchived,
45006
+ details: result.details || [],
45007
+ summary: result.summary
45008
+ }
45009
+ });
44877
45010
  } else {
44878
45011
  activity.ltmCurator.complete("No changes needed");
44879
45012
  }
@@ -44899,6 +45032,17 @@ async function runDistillation(storage, threshold, target, force) {
44899
45032
  force
44900
45033
  });
44901
45034
  activity.distillation.tokens(result.tokensBefore, result.tokensAfter, `${result.distillationsCreated} distillations`);
45035
+ if (result.distillationsCreated > 0) {
45036
+ await storage.background.fileReport({
45037
+ subsystem: "distillation",
45038
+ report: {
45039
+ tokensBefore: result.tokensBefore,
45040
+ tokensAfter: result.tokensAfter,
45041
+ distillationsCreated: result.distillationsCreated,
45042
+ summary: result.summary
45043
+ }
45044
+ });
45045
+ }
44902
45046
  return result;
44903
45047
  } catch (error2) {
44904
45048
  activity.distillation.error(error2 instanceof Error ? error2.message : String(error2));
@@ -44908,7 +45052,81 @@ async function runDistillation(storage, threshold, target, force) {
44908
45052
 
44909
45053
  // src/agent/index.ts
44910
45054
  var log10 = Log.create({ service: "agent" });
44911
- var MAX_TURNS = 50;
45055
+ var MAX_TURNS = 200;
45056
+ async function surfaceBackgroundReports(storage) {
45057
+ const reports = await storage.background.getUnsurfaced();
45058
+ if (reports.length === 0)
45059
+ return;
45060
+ log10.info("surfacing background reports", { count: reports.length });
45061
+ for (const report of reports) {
45062
+ const toolCallId = Identifier.ascending("toolcall");
45063
+ await storage.temporal.appendMessage({
45064
+ id: Identifier.ascending("message"),
45065
+ type: "tool_call",
45066
+ content: JSON.stringify({
45067
+ name: "background_activity",
45068
+ args: { subsystem: report.subsystem },
45069
+ toolCallId
45070
+ }),
45071
+ tokenEstimate: 20,
45072
+ createdAt: report.createdAt
45073
+ });
45074
+ const reportContent = formatBackgroundReport(report.subsystem, report.report);
45075
+ await storage.temporal.appendMessage({
45076
+ id: Identifier.ascending("message"),
45077
+ type: "tool_result",
45078
+ content: JSON.stringify({
45079
+ toolCallId,
45080
+ result: reportContent
45081
+ }),
45082
+ tokenEstimate: estimateTokens2(reportContent),
45083
+ createdAt: report.createdAt
45084
+ });
45085
+ await storage.background.markSurfaced(report.id);
45086
+ }
45087
+ }
45088
+ function formatBackgroundReport(subsystem, report) {
45089
+ switch (subsystem) {
45090
+ case "ltm_curator": {
45091
+ const r = report;
45092
+ if (r.summary) {
45093
+ return `[Knowledge Curator] ${r.summary}`;
45094
+ }
45095
+ const lines = ["[Knowledge Curator] I organized my knowledge:"];
45096
+ if (r.entriesCreated)
45097
+ lines.push(`- Created ${r.entriesCreated} new entries`);
45098
+ if (r.entriesUpdated)
45099
+ lines.push(`- Updated ${r.entriesUpdated} existing entries`);
45100
+ if (r.entriesArchived)
45101
+ lines.push(`- Archived ${r.entriesArchived} outdated entries`);
45102
+ if (r.details && r.details.length > 0) {
45103
+ lines.push("");
45104
+ lines.push(...r.details.map((d) => `- ${d}`));
45105
+ }
45106
+ return lines.join(`
45107
+ `);
45108
+ }
45109
+ case "distillation": {
45110
+ const r = report;
45111
+ if (r.summary) {
45112
+ const tokenInfo = r.tokensBefore && r.tokensAfter ? ` (${r.tokensBefore.toLocaleString()} \u2192 ${r.tokensAfter.toLocaleString()} tokens)` : "";
45113
+ return `[Memory Compaction]${tokenInfo} ${r.summary}`;
45114
+ }
45115
+ const lines = ["[Memory Compaction] I compressed my working memory:"];
45116
+ if (r.tokensBefore && r.tokensAfter) {
45117
+ const saved = r.tokensBefore - r.tokensAfter;
45118
+ lines.push(`- Reduced from ${r.tokensBefore.toLocaleString()} to ${r.tokensAfter.toLocaleString()} tokens (saved ${saved.toLocaleString()})`);
45119
+ }
45120
+ if (r.distillationsCreated) {
45121
+ lines.push(`- Created ${r.distillationsCreated} distillation${r.distillationsCreated > 1 ? "s" : ""}`);
45122
+ }
45123
+ return lines.join(`
45124
+ `);
45125
+ }
45126
+ default:
45127
+ return `[${subsystem}] ${JSON.stringify(report, null, 2)}`;
45128
+ }
45129
+ }
44912
45130
  function summarizeToolResult(toolName, result) {
44913
45131
  const lines = result.split(`
44914
45132
  `).length;
@@ -45139,6 +45357,7 @@ async function runAgent(prompt, options) {
45139
45357
  const { storage, onEvent, abortSignal, onBeforeTurn } = options;
45140
45358
  const sessionId = Identifier.ascending("session");
45141
45359
  await initializeMcp();
45360
+ await surfaceBackgroundReports(storage);
45142
45361
  const config2 = Config.get();
45143
45362
  const softLimit = config2.tokenBudgets.compactionThreshold;
45144
45363
  const hardLimit = config2.tokenBudgets.compactionHardLimit;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miriad-systems/nuum",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "AI coding agent with continuous memory - infinite context across sessions",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,15 @@
1
+ -- Background reports table
2
+ -- Allows background workers (LTM curator, distillation, etc.) to file reports
3
+ -- that get surfaced to the main agent at the start of the next turn.
4
+
5
+ CREATE TABLE IF NOT EXISTS background_reports (
6
+ id TEXT PRIMARY KEY,
7
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
8
+ subsystem TEXT NOT NULL, -- e.g., 'ltm_curator', 'distillation'
9
+ report TEXT NOT NULL, -- JSON report content
10
+ surfaced_at TEXT -- NULL until shown to main agent
11
+ );
12
+
13
+ -- Index for efficient lookup of unsurfaced reports
14
+ CREATE INDEX IF NOT EXISTS idx_background_reports_unsurfaced
15
+ ON background_reports(surfaced_at) WHERE surfaced_at IS NULL;