@sanity-labs/nuum 0.5.3 → 0.5.5

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 +66 -26
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23485,26 +23485,33 @@ function createLTMStorage(db) {
23485
23485
  }
23486
23486
  return matches.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
23487
23487
  },
23488
- async searchFTS(query, limit = 20) {
23488
+ async searchFTS(query, options = {}) {
23489
+ const { limit = 20, pathPrefix } = options;
23489
23490
  const words = query.split(/\s+/).filter((w) => w.length > 0).map((w) => `"${w.replace(/"/g, '""')}"`).join(" OR ");
23490
23491
  if (!words) {
23491
23492
  return [];
23492
23493
  }
23494
+ const pathFilter = pathPrefix ? `AND e.path LIKE ? || '%'` : "";
23495
+ const params = pathPrefix ? [words, pathPrefix, limit] : [words, limit];
23493
23496
  const results = await db._rawDb.prepare(`
23494
23497
  SELECT
23495
- slug,
23496
- title,
23498
+ fts.slug,
23499
+ fts.title,
23500
+ e.path,
23497
23501
  snippet(ltm_entries_fts, 2, '>>>', '<<<', '...', 32) as snippet,
23498
- rank
23499
- FROM ltm_entries_fts
23502
+ fts.rank
23503
+ FROM ltm_entries_fts fts
23504
+ JOIN ltm_entries e ON e.slug = fts.slug
23500
23505
  WHERE ltm_entries_fts MATCH ?
23501
- AND slug IN (SELECT slug FROM ltm_entries WHERE archived_at IS NULL)
23502
- ORDER BY rank
23506
+ AND e.archived_at IS NULL
23507
+ ${pathFilter}
23508
+ ORDER BY fts.rank
23503
23509
  LIMIT ?
23504
- `).all(words, limit);
23510
+ `).all(...params);
23505
23511
  return results.map((r) => ({
23506
23512
  slug: r.slug,
23507
23513
  title: r.title,
23514
+ path: r.path,
23508
23515
  snippet: r.snippet,
23509
23516
  rank: r.rank
23510
23517
  }));
@@ -35674,6 +35681,20 @@ function estimateSummaryTokens(input) {
35674
35681
  }
35675
35682
  // src/agent/loop.ts
35676
35683
  var log5 = Log.create({ service: "agent-loop" });
35684
+ var MODEL_MAX_OUTPUT_TOKENS = {
35685
+ "claude-opus-4-6": 128000,
35686
+ "claude-opus-4-6-20250918": 128000,
35687
+ "claude-sonnet-4-5-20250929": 64000,
35688
+ "claude-sonnet-4-5": 64000,
35689
+ "claude-haiku-4-5-20251001": 64000,
35690
+ "claude-haiku-4-5": 64000,
35691
+ "claude-3-5-sonnet-20241022": 8192,
35692
+ "claude-3-5-haiku-20241022": 8192
35693
+ };
35694
+ var DEFAULT_MAX_OUTPUT_TOKENS = 16384;
35695
+ function getMaxOutputTokens(modelId) {
35696
+ return MODEL_MAX_OUTPUT_TOKENS[modelId] ?? DEFAULT_MAX_OUTPUT_TOKENS;
35697
+ }
35677
35698
  function addCacheMarkers(messages) {
35678
35699
  if (messages.length === 0)
35679
35700
  return messages;
@@ -35702,7 +35723,7 @@ async function runAgentLoop(options) {
35702
35723
  systemPrompt,
35703
35724
  initialMessages,
35704
35725
  tools,
35705
- maxTokens = 4096,
35726
+ maxTokens: maxTokensOverride,
35706
35727
  temperature,
35707
35728
  maxTurns,
35708
35729
  abortSignal,
@@ -35713,6 +35734,12 @@ async function runAgentLoop(options) {
35713
35734
  onBeforeTurn,
35714
35735
  onThinking
35715
35736
  } = options;
35737
+ const maxTokens = maxTokensOverride ?? getMaxOutputTokens(model.modelId);
35738
+ log5.info("agent loop starting", {
35739
+ model: model.modelId,
35740
+ maxTokens,
35741
+ maxTurns
35742
+ });
35716
35743
  if (abortSignal?.aborted) {
35717
35744
  throw new AgentLoopCancelledError;
35718
35745
  }
@@ -35768,6 +35795,13 @@ async function runAgentLoop(options) {
35768
35795
  cacheHitRate: total > 0 ? `${Math.round(cacheRead / total * 100)}%` : "0%"
35769
35796
  });
35770
35797
  }
35798
+ if (response.finishReason === "length") {
35799
+ log5.warn("output truncated - model hit maxTokens limit", {
35800
+ maxTokens,
35801
+ outputTokens: response.usage.completionTokens,
35802
+ hasToolCalls: (response.toolCalls?.length ?? 0) > 0
35803
+ });
35804
+ }
35771
35805
  if (response.text) {
35772
35806
  finalText = response.text;
35773
35807
  await onText?.(response.text);
@@ -35812,6 +35846,15 @@ async function runAgentLoop(options) {
35812
35846
  content: toolResultParts
35813
35847
  };
35814
35848
  messages.push(toolMsg);
35849
+ if (response.finishReason === "length") {
35850
+ const hadInvalidCalls = toolCallInfos.some((tc) => tc.toolName === "__invalid_tool_call__");
35851
+ if (hadInvalidCalls) {
35852
+ messages.push({
35853
+ role: "user",
35854
+ content: "[SYSTEM: Your previous output was truncated because it exceeded the output token limit. " + "Your tool call was incomplete \u2014 parameters were cut off mid-generation. " + "To fix this: break large content into multiple smaller write calls, or use bash to write incrementally. " + "Do NOT retry the same large tool call \u2014 it will truncate again.]"
35855
+ });
35856
+ }
35857
+ }
35815
35858
  if (isDone(toolCallInfos)) {
35816
35859
  stopReason = "done";
35817
35860
  break;
@@ -36138,7 +36181,6 @@ async function runCompaction(storage, config) {
36138
36181
  systemPrompt: ctx.systemPrompt,
36139
36182
  initialMessages,
36140
36183
  tools,
36141
- maxTokens: 4096,
36142
36184
  temperature: 0,
36143
36185
  maxTurns: 5,
36144
36186
  isDone: stopOnTool("finish_distillation"),
@@ -36244,7 +36286,7 @@ async function runSubAgent(storage, config) {
36244
36286
  extractResult,
36245
36287
  tier = "workhorse",
36246
36288
  maxTurns = 20,
36247
- maxTokens = 4096,
36289
+ maxTokens,
36248
36290
  temperature = 0,
36249
36291
  onToolResult
36250
36292
  } = config;
@@ -36431,8 +36473,7 @@ async function runReflection(storage, question) {
36431
36473
  finishToolName: "finish_reflection",
36432
36474
  extractResult: getAnswer,
36433
36475
  tier: "workhorse",
36434
- maxTurns: 20,
36435
- maxTokens: 4096
36476
+ maxTurns: 20
36436
36477
  });
36437
36478
  const answer = result.result ?? "Unable to find relevant information.";
36438
36479
  activity.reflection.complete(`${result.turnsUsed} turns, ${answer.length} chars`);
@@ -36836,7 +36877,6 @@ async function runResearch(storage, topic) {
36836
36877
  },
36837
36878
  tier: "workhorse",
36838
36879
  maxTurns: MAX_RESEARCH_TURNS,
36839
- maxTokens: 8192,
36840
36880
  onToolResult: (toolCallId) => {
36841
36881
  const toolResult = getLastResult(toolCallId);
36842
36882
  if (!toolResult)
@@ -45371,8 +45411,8 @@ var Mcp;
45371
45411
  })(Mcp ||= {});
45372
45412
 
45373
45413
  // src/version.ts
45374
- var VERSION = "0.5.3";
45375
- var GIT_HASH = "a2a5ddc";
45414
+ var VERSION = "0.5.5";
45415
+ var GIT_HASH = "9c9c471";
45376
45416
  var VERSION_STRING = `nuum v${VERSION} (${GIT_HASH})`;
45377
45417
 
45378
45418
  // src/tool/mcp-status.ts
@@ -45577,24 +45617,26 @@ Returns: [{ slug, title, path, snippet }, ...] ranked by relevance`,
45577
45617
  async execute(args, ctx) {
45578
45618
  const { ltm } = ctx.extra;
45579
45619
  const { query, path: path9, limit } = args;
45580
- const results = await ltm.search(query, path9);
45581
- const limited = results.slice(0, limit ?? 10);
45620
+ const results = await ltm.searchFTS(query, {
45621
+ limit: limit ?? 10,
45622
+ pathPrefix: path9
45623
+ });
45582
45624
  ctx.metadata({
45583
45625
  title: `ltm_search("${query}")`,
45584
45626
  metadata: { operation: "search" }
45585
45627
  });
45586
- if (limited.length === 0) {
45628
+ if (results.length === 0) {
45587
45629
  return {
45588
45630
  title: `ltm_search("${query}")`,
45589
45631
  metadata: { operation: "search" },
45590
45632
  output: `No entries found matching "${query}"`
45591
45633
  };
45592
45634
  }
45593
- const formatted = limited.map((r) => ({
45594
- slug: r.entry.slug,
45595
- title: r.entry.title,
45596
- path: r.entry.path,
45597
- snippet: r.entry.body.slice(0, 150) + (r.entry.body.length > 150 ? "..." : "")
45635
+ const formatted = results.map((r) => ({
45636
+ slug: r.slug,
45637
+ title: r.title,
45638
+ path: r.path,
45639
+ snippet: r.snippet
45598
45640
  }));
45599
45641
  return {
45600
45642
  title: `ltm_search("${query}")`,
@@ -46890,7 +46932,6 @@ async function runConsolidation(storage, messages) {
46890
46932
  },
46891
46933
  tier: "workhorse",
46892
46934
  maxTurns: MAX_CONSOLIDATION_TURNS,
46893
- maxTokens: 2048,
46894
46935
  onToolResult: (toolCallId) => {
46895
46936
  const toolResult = getLastResult(toolCallId);
46896
46937
  if (!toolResult)
@@ -47432,7 +47473,6 @@ async function runAgent(prompt, options) {
47432
47473
  systemPrompt: ctx.systemPrompt,
47433
47474
  initialMessages,
47434
47475
  tools,
47435
- maxTokens: 8192,
47436
47476
  maxTurns: MAX_TURNS,
47437
47477
  abortSignal,
47438
47478
  onText: async (text3) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity-labs/nuum",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "AI coding agent with continuous memory - infinite context across sessions",
5
5
  "type": "module",
6
6
  "bin": {