@sanity-labs/nuum 0.5.2 → 0.5.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.
- package/dist/index.js +115 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35674,6 +35674,20 @@ function estimateSummaryTokens(input) {
|
|
|
35674
35674
|
}
|
|
35675
35675
|
// src/agent/loop.ts
|
|
35676
35676
|
var log5 = Log.create({ service: "agent-loop" });
|
|
35677
|
+
var MODEL_MAX_OUTPUT_TOKENS = {
|
|
35678
|
+
"claude-opus-4-6": 128000,
|
|
35679
|
+
"claude-opus-4-6-20250918": 128000,
|
|
35680
|
+
"claude-sonnet-4-5-20250929": 64000,
|
|
35681
|
+
"claude-sonnet-4-5": 64000,
|
|
35682
|
+
"claude-haiku-4-5-20251001": 64000,
|
|
35683
|
+
"claude-haiku-4-5": 64000,
|
|
35684
|
+
"claude-3-5-sonnet-20241022": 8192,
|
|
35685
|
+
"claude-3-5-haiku-20241022": 8192
|
|
35686
|
+
};
|
|
35687
|
+
var DEFAULT_MAX_OUTPUT_TOKENS = 16384;
|
|
35688
|
+
function getMaxOutputTokens(modelId) {
|
|
35689
|
+
return MODEL_MAX_OUTPUT_TOKENS[modelId] ?? DEFAULT_MAX_OUTPUT_TOKENS;
|
|
35690
|
+
}
|
|
35677
35691
|
function addCacheMarkers(messages) {
|
|
35678
35692
|
if (messages.length === 0)
|
|
35679
35693
|
return messages;
|
|
@@ -35702,7 +35716,7 @@ async function runAgentLoop(options) {
|
|
|
35702
35716
|
systemPrompt,
|
|
35703
35717
|
initialMessages,
|
|
35704
35718
|
tools,
|
|
35705
|
-
maxTokens
|
|
35719
|
+
maxTokens: maxTokensOverride,
|
|
35706
35720
|
temperature,
|
|
35707
35721
|
maxTurns,
|
|
35708
35722
|
abortSignal,
|
|
@@ -35713,6 +35727,12 @@ async function runAgentLoop(options) {
|
|
|
35713
35727
|
onBeforeTurn,
|
|
35714
35728
|
onThinking
|
|
35715
35729
|
} = options;
|
|
35730
|
+
const maxTokens = maxTokensOverride ?? getMaxOutputTokens(model.modelId);
|
|
35731
|
+
log5.info("agent loop starting", {
|
|
35732
|
+
model: model.modelId,
|
|
35733
|
+
maxTokens,
|
|
35734
|
+
maxTurns
|
|
35735
|
+
});
|
|
35716
35736
|
if (abortSignal?.aborted) {
|
|
35717
35737
|
throw new AgentLoopCancelledError;
|
|
35718
35738
|
}
|
|
@@ -35768,6 +35788,13 @@ async function runAgentLoop(options) {
|
|
|
35768
35788
|
cacheHitRate: total > 0 ? `${Math.round(cacheRead / total * 100)}%` : "0%"
|
|
35769
35789
|
});
|
|
35770
35790
|
}
|
|
35791
|
+
if (response.finishReason === "length") {
|
|
35792
|
+
log5.warn("output truncated - model hit maxTokens limit", {
|
|
35793
|
+
maxTokens,
|
|
35794
|
+
outputTokens: response.usage.completionTokens,
|
|
35795
|
+
hasToolCalls: (response.toolCalls?.length ?? 0) > 0
|
|
35796
|
+
});
|
|
35797
|
+
}
|
|
35771
35798
|
if (response.text) {
|
|
35772
35799
|
finalText = response.text;
|
|
35773
35800
|
await onText?.(response.text);
|
|
@@ -35812,6 +35839,15 @@ async function runAgentLoop(options) {
|
|
|
35812
35839
|
content: toolResultParts
|
|
35813
35840
|
};
|
|
35814
35841
|
messages.push(toolMsg);
|
|
35842
|
+
if (response.finishReason === "length") {
|
|
35843
|
+
const hadInvalidCalls = toolCallInfos.some((tc) => tc.toolName === "__invalid_tool_call__");
|
|
35844
|
+
if (hadInvalidCalls) {
|
|
35845
|
+
messages.push({
|
|
35846
|
+
role: "user",
|
|
35847
|
+
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 smaller chunks, or use bash with echo/cat to write files incrementally. " + "Do NOT retry the same large tool call \u2014 it will truncate again.]"
|
|
35848
|
+
});
|
|
35849
|
+
}
|
|
35850
|
+
}
|
|
35815
35851
|
if (isDone(toolCallInfos)) {
|
|
35816
35852
|
stopReason = "done";
|
|
35817
35853
|
break;
|
|
@@ -36138,7 +36174,6 @@ async function runCompaction(storage, config) {
|
|
|
36138
36174
|
systemPrompt: ctx.systemPrompt,
|
|
36139
36175
|
initialMessages,
|
|
36140
36176
|
tools,
|
|
36141
|
-
maxTokens: 4096,
|
|
36142
36177
|
temperature: 0,
|
|
36143
36178
|
maxTurns: 5,
|
|
36144
36179
|
isDone: stopOnTool("finish_distillation"),
|
|
@@ -36244,7 +36279,7 @@ async function runSubAgent(storage, config) {
|
|
|
36244
36279
|
extractResult,
|
|
36245
36280
|
tier = "workhorse",
|
|
36246
36281
|
maxTurns = 20,
|
|
36247
|
-
maxTokens
|
|
36282
|
+
maxTokens,
|
|
36248
36283
|
temperature = 0,
|
|
36249
36284
|
onToolResult
|
|
36250
36285
|
} = config;
|
|
@@ -36431,8 +36466,7 @@ async function runReflection(storage, question) {
|
|
|
36431
36466
|
finishToolName: "finish_reflection",
|
|
36432
36467
|
extractResult: getAnswer,
|
|
36433
36468
|
tier: "workhorse",
|
|
36434
|
-
maxTurns: 20
|
|
36435
|
-
maxTokens: 4096
|
|
36469
|
+
maxTurns: 20
|
|
36436
36470
|
});
|
|
36437
36471
|
const answer = result.result ?? "Unable to find relevant information.";
|
|
36438
36472
|
activity.reflection.complete(`${result.turnsUsed} turns, ${answer.length} chars`);
|
|
@@ -36836,7 +36870,6 @@ async function runResearch(storage, topic) {
|
|
|
36836
36870
|
},
|
|
36837
36871
|
tier: "workhorse",
|
|
36838
36872
|
maxTurns: MAX_RESEARCH_TURNS,
|
|
36839
|
-
maxTokens: 8192,
|
|
36840
36873
|
onToolResult: (toolCallId) => {
|
|
36841
36874
|
const toolResult = getLastResult(toolCallId);
|
|
36842
36875
|
if (!toolResult)
|
|
@@ -45086,6 +45119,30 @@ var Mcp;
|
|
|
45086
45119
|
function isHttpConfig(config2) {
|
|
45087
45120
|
return "url" in config2;
|
|
45088
45121
|
}
|
|
45122
|
+
const TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
45123
|
+
function validateToolName(serverName, mcpToolName) {
|
|
45124
|
+
const effectiveName = `${serverName}__${mcpToolName}`;
|
|
45125
|
+
if (TOOL_NAME_PATTERN.test(effectiveName)) {
|
|
45126
|
+
return null;
|
|
45127
|
+
}
|
|
45128
|
+
const invalidChars = effectiveName.split("").filter((c) => !/[a-zA-Z0-9_-]/.test(c));
|
|
45129
|
+
const uniqueInvalid = Array.from(new Set(invalidChars));
|
|
45130
|
+
let message;
|
|
45131
|
+
if (effectiveName.length > 64) {
|
|
45132
|
+
message = `Effective tool name "${effectiveName}" exceeds 64 character limit (${effectiveName.length} chars)`;
|
|
45133
|
+
} else if (effectiveName.length === 0) {
|
|
45134
|
+
message = `Tool name is empty`;
|
|
45135
|
+
} else {
|
|
45136
|
+
message = `Effective tool name "${effectiveName}" contains invalid character(s): ${uniqueInvalid.map((c) => `"${c}"`).join(", ")} (allowed: a-z, A-Z, 0-9, _, -)`;
|
|
45137
|
+
}
|
|
45138
|
+
return {
|
|
45139
|
+
type: "invalid_tool_name",
|
|
45140
|
+
tool: mcpToolName,
|
|
45141
|
+
effectiveName,
|
|
45142
|
+
message
|
|
45143
|
+
};
|
|
45144
|
+
}
|
|
45145
|
+
Mcp.validateToolName = validateToolName;
|
|
45089
45146
|
|
|
45090
45147
|
class Manager {
|
|
45091
45148
|
servers = new Map;
|
|
@@ -45124,6 +45181,8 @@ var Mcp;
|
|
|
45124
45181
|
config: config2,
|
|
45125
45182
|
client: null,
|
|
45126
45183
|
tools: [],
|
|
45184
|
+
allToolCount: 0,
|
|
45185
|
+
issues: [],
|
|
45127
45186
|
status: "disabled"
|
|
45128
45187
|
};
|
|
45129
45188
|
}
|
|
@@ -45141,24 +45200,38 @@ var Mcp;
|
|
|
45141
45200
|
new Promise((_, reject) => setTimeout(() => reject(new Error("Connection timeout")), timeoutMs))
|
|
45142
45201
|
]);
|
|
45143
45202
|
const toolsResult = await client.listTools();
|
|
45144
|
-
const
|
|
45203
|
+
const allTools = toolsResult.tools;
|
|
45204
|
+
const validTools = [];
|
|
45205
|
+
const issues = [];
|
|
45206
|
+
for (const mcpTool of allTools) {
|
|
45207
|
+
const issue2 = validateToolName(name17, mcpTool.name);
|
|
45208
|
+
if (issue2) {
|
|
45209
|
+
issues.push(issue2);
|
|
45210
|
+
console.error(`[mcp:${name17}] Skipping tool "${mcpTool.name}": ${issue2.message}`);
|
|
45211
|
+
} else {
|
|
45212
|
+
validTools.push(mcpTool);
|
|
45213
|
+
}
|
|
45214
|
+
}
|
|
45145
45215
|
let sessionId;
|
|
45146
45216
|
if (transport instanceof StreamableHTTPClientTransport) {
|
|
45147
45217
|
sessionId = transport.sessionId;
|
|
45148
45218
|
if (sessionId) {
|
|
45149
|
-
console.error(`[mcp:${name17}] Connected with session ${sessionId.slice(0, 8)}..., ${
|
|
45219
|
+
console.error(`[mcp:${name17}] Connected with session ${sessionId.slice(0, 8)}..., ${validTools.length}/${allTools.length} tools available`);
|
|
45150
45220
|
} else {
|
|
45151
|
-
console.error(`[mcp:${name17}] Connected (no session), ${
|
|
45221
|
+
console.error(`[mcp:${name17}] Connected (no session), ${validTools.length}/${allTools.length} tools available`);
|
|
45152
45222
|
}
|
|
45153
45223
|
} else {
|
|
45154
|
-
console.error(`[mcp:${name17}] Connected, ${
|
|
45224
|
+
console.error(`[mcp:${name17}] Connected, ${validTools.length}/${allTools.length} tools available`);
|
|
45155
45225
|
}
|
|
45226
|
+
const status = issues.length > 0 ? "degraded" : "connected";
|
|
45156
45227
|
return {
|
|
45157
45228
|
name: name17,
|
|
45158
45229
|
config: config2,
|
|
45159
45230
|
client,
|
|
45160
|
-
tools,
|
|
45161
|
-
|
|
45231
|
+
tools: validTools,
|
|
45232
|
+
allToolCount: allTools.length,
|
|
45233
|
+
issues,
|
|
45234
|
+
status,
|
|
45162
45235
|
sessionId
|
|
45163
45236
|
};
|
|
45164
45237
|
} catch (e) {
|
|
@@ -45169,6 +45242,8 @@ var Mcp;
|
|
|
45169
45242
|
config: config2,
|
|
45170
45243
|
client,
|
|
45171
45244
|
tools: [],
|
|
45245
|
+
allToolCount: 0,
|
|
45246
|
+
issues: [],
|
|
45172
45247
|
status: "failed",
|
|
45173
45248
|
error: error2
|
|
45174
45249
|
};
|
|
@@ -45185,10 +45260,18 @@ var Mcp;
|
|
|
45185
45260
|
this.servers.set(server.name, server);
|
|
45186
45261
|
}
|
|
45187
45262
|
const connected = results.filter((s) => s.status === "connected").length;
|
|
45263
|
+
const degraded = results.filter((s) => s.status === "degraded").length;
|
|
45188
45264
|
const failed = results.filter((s) => s.status === "failed").length;
|
|
45189
45265
|
const disabled = results.filter((s) => s.status === "disabled").length;
|
|
45190
45266
|
if (entries.length > 0) {
|
|
45191
|
-
|
|
45267
|
+
const parts = [`${connected} connected`];
|
|
45268
|
+
if (degraded > 0)
|
|
45269
|
+
parts.push(`${degraded} degraded`);
|
|
45270
|
+
if (failed > 0)
|
|
45271
|
+
parts.push(`${failed} failed`);
|
|
45272
|
+
if (disabled > 0)
|
|
45273
|
+
parts.push(`${disabled} disabled`);
|
|
45274
|
+
console.error(`[mcp] Initialized: ${parts.join(", ")}`);
|
|
45192
45275
|
}
|
|
45193
45276
|
}
|
|
45194
45277
|
async shutdown() {
|
|
@@ -45206,14 +45289,16 @@ var Mcp;
|
|
|
45206
45289
|
return Array.from(this.servers.values()).map((s) => ({
|
|
45207
45290
|
name: s.name,
|
|
45208
45291
|
status: s.status,
|
|
45209
|
-
toolCount: s.
|
|
45292
|
+
toolCount: s.allToolCount,
|
|
45293
|
+
activeToolCount: s.tools.length,
|
|
45294
|
+
issues: s.issues,
|
|
45210
45295
|
error: s.error
|
|
45211
45296
|
}));
|
|
45212
45297
|
}
|
|
45213
45298
|
listTools() {
|
|
45214
45299
|
const tools = [];
|
|
45215
45300
|
for (const [serverName, server] of this.servers) {
|
|
45216
|
-
if (server.status !== "connected")
|
|
45301
|
+
if (server.status !== "connected" && server.status !== "degraded")
|
|
45217
45302
|
continue;
|
|
45218
45303
|
for (const mcpTool of server.tools) {
|
|
45219
45304
|
tools.push(`${serverName}__${mcpTool.name}`);
|
|
@@ -45254,7 +45339,7 @@ var Mcp;
|
|
|
45254
45339
|
getTools() {
|
|
45255
45340
|
const tools = {};
|
|
45256
45341
|
for (const [serverName, server] of this.servers) {
|
|
45257
|
-
if (server.status !== "connected")
|
|
45342
|
+
if (server.status !== "connected" && server.status !== "degraded")
|
|
45258
45343
|
continue;
|
|
45259
45344
|
for (const mcpTool of server.tools) {
|
|
45260
45345
|
const toolName = `${serverName}__${mcpTool.name}`;
|
|
@@ -45319,8 +45404,8 @@ var Mcp;
|
|
|
45319
45404
|
})(Mcp ||= {});
|
|
45320
45405
|
|
|
45321
45406
|
// src/version.ts
|
|
45322
|
-
var VERSION = "0.5.
|
|
45323
|
-
var GIT_HASH = "
|
|
45407
|
+
var VERSION = "0.5.4";
|
|
45408
|
+
var GIT_HASH = "e1f89a6";
|
|
45324
45409
|
var VERSION_STRING = `nuum v${VERSION} (${GIT_HASH})`;
|
|
45325
45410
|
|
|
45326
45411
|
// src/tool/mcp-status.ts
|
|
@@ -45369,14 +45454,23 @@ Use this when:
|
|
|
45369
45454
|
} else {
|
|
45370
45455
|
let connectedCount = 0;
|
|
45371
45456
|
for (const server of mcpStatus) {
|
|
45372
|
-
const statusIcon = server.status === "connected" ? "\u2713" : server.status === "connecting" ? "\u22EF" : "\u2717";
|
|
45457
|
+
const statusIcon = server.status === "connected" ? "\u2713" : server.status === "degraded" ? "\u26A0" : server.status === "connecting" ? "\u22EF" : "\u2717";
|
|
45373
45458
|
output += `**${server.name}** ${statusIcon}
|
|
45374
45459
|
`;
|
|
45375
|
-
if (server.status === "connected") {
|
|
45460
|
+
if (server.status === "connected" || server.status === "degraded") {
|
|
45376
45461
|
connectedCount++;
|
|
45377
45462
|
const serverTools = mcpToolNames.filter((t) => t.startsWith(`${server.name}__`));
|
|
45378
|
-
|
|
45463
|
+
if (server.status === "degraded") {
|
|
45464
|
+
output += `- ${server.activeToolCount}/${server.toolCount} tools active: ${serverTools.map((t) => t.replace(`${server.name}__`, "")).join(", ")}
|
|
45465
|
+
`;
|
|
45466
|
+
for (const issue2 of server.issues) {
|
|
45467
|
+
output += ` - \u26A0 Skipped "${issue2.tool}": ${issue2.message}
|
|
45379
45468
|
`;
|
|
45469
|
+
}
|
|
45470
|
+
} else {
|
|
45471
|
+
output += `- ${server.toolCount} tools: ${serverTools.map((t) => t.replace(`${server.name}__`, "")).join(", ")}
|
|
45472
|
+
`;
|
|
45473
|
+
}
|
|
45380
45474
|
} else if (server.error) {
|
|
45381
45475
|
output += `- Error: ${server.error}
|
|
45382
45476
|
`;
|
|
@@ -46829,7 +46923,6 @@ async function runConsolidation(storage, messages) {
|
|
|
46829
46923
|
},
|
|
46830
46924
|
tier: "workhorse",
|
|
46831
46925
|
maxTurns: MAX_CONSOLIDATION_TURNS,
|
|
46832
|
-
maxTokens: 2048,
|
|
46833
46926
|
onToolResult: (toolCallId) => {
|
|
46834
46927
|
const toolResult = getLastResult(toolCallId);
|
|
46835
46928
|
if (!toolResult)
|
|
@@ -47371,7 +47464,6 @@ async function runAgent(prompt, options) {
|
|
|
47371
47464
|
systemPrompt: ctx.systemPrompt,
|
|
47372
47465
|
initialMessages,
|
|
47373
47466
|
tools,
|
|
47374
|
-
maxTokens: 8192,
|
|
47375
47467
|
maxTurns: MAX_TURNS,
|
|
47376
47468
|
abortSignal,
|
|
47377
47469
|
onText: async (text3) => {
|