@nookplot/runtime 0.5.142 → 0.5.144

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 (60) hide show
  1. package/dist/__tests__/bdAgentPack.test.d.ts +2 -0
  2. package/dist/__tests__/bdAgentPack.test.d.ts.map +1 -0
  3. package/dist/__tests__/bdAgentPack.test.js +44 -0
  4. package/dist/__tests__/bdAgentPack.test.js.map +1 -0
  5. package/dist/__tests__/externalMcpTools.test.d.ts +2 -0
  6. package/dist/__tests__/externalMcpTools.test.d.ts.map +1 -0
  7. package/dist/__tests__/externalMcpTools.test.js +94 -0
  8. package/dist/__tests__/externalMcpTools.test.js.map +1 -0
  9. package/dist/__tests__/pack.gating.test.d.ts +2 -0
  10. package/dist/__tests__/pack.gating.test.d.ts.map +1 -0
  11. package/dist/__tests__/pack.gating.test.js +134 -0
  12. package/dist/__tests__/pack.gating.test.js.map +1 -0
  13. package/dist/__tests__/pack.test.d.ts +2 -0
  14. package/dist/__tests__/pack.test.d.ts.map +1 -0
  15. package/dist/__tests__/pack.test.js +299 -0
  16. package/dist/__tests__/pack.test.js.map +1 -0
  17. package/dist/__tests__/packLoader.test.d.ts +2 -0
  18. package/dist/__tests__/packLoader.test.d.ts.map +1 -0
  19. package/dist/__tests__/packLoader.test.js +304 -0
  20. package/dist/__tests__/packLoader.test.js.map +1 -0
  21. package/dist/__tests__/presetLoader.test.d.ts +2 -0
  22. package/dist/__tests__/presetLoader.test.d.ts.map +1 -0
  23. package/dist/__tests__/presetLoader.test.js +766 -0
  24. package/dist/__tests__/presetLoader.test.js.map +1 -0
  25. package/dist/actionCatalog.d.ts.map +1 -1
  26. package/dist/actionCatalog.generated.d.ts +1 -1
  27. package/dist/actionCatalog.generated.d.ts.map +1 -1
  28. package/dist/actionCatalog.generated.js +7 -2
  29. package/dist/actionCatalog.generated.js.map +1 -1
  30. package/dist/actionCatalog.js +4 -12
  31. package/dist/actionCatalog.js.map +1 -1
  32. package/dist/autonomous.d.ts +24 -1
  33. package/dist/autonomous.d.ts.map +1 -1
  34. package/dist/autonomous.js +66 -8
  35. package/dist/autonomous.js.map +1 -1
  36. package/dist/index.d.ts +7 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +6 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/pack.d.ts +181 -0
  41. package/dist/pack.d.ts.map +1 -0
  42. package/dist/pack.js +379 -0
  43. package/dist/pack.js.map +1 -0
  44. package/dist/packLoader.d.ts +109 -0
  45. package/dist/packLoader.d.ts.map +1 -0
  46. package/dist/packLoader.js +236 -0
  47. package/dist/packLoader.js.map +1 -0
  48. package/dist/presetLoader.d.ts +132 -0
  49. package/dist/presetLoader.d.ts.map +1 -0
  50. package/dist/presetLoader.js +740 -0
  51. package/dist/presetLoader.js.map +1 -0
  52. package/dist/signalActionMap.d.ts +17 -1
  53. package/dist/signalActionMap.d.ts.map +1 -1
  54. package/dist/signalActionMap.js +37 -2
  55. package/dist/signalActionMap.js.map +1 -1
  56. package/dist/tools.d.ts +23 -7
  57. package/dist/tools.d.ts.map +1 -1
  58. package/dist/tools.js +20 -6
  59. package/dist/tools.js.map +1 -1
  60. package/package.json +2 -2
@@ -42,7 +42,8 @@
42
42
  import { prepareSignRelay } from "./signing.js";
43
43
  import { runFrontierPass } from "./frontierPass.js";
44
44
  import { wrapUntrusted, sanitizeForPrompt, UNTRUSTED_CONTENT_INSTRUCTION } from "./contentSafety.js";
45
- import { getAvailableActionsFromMap } from "./signalActionMap.js";
45
+ import { getAvailableActionsFromMap, resolveDispatchToolName, CORE_ACTIONS } from "./signalActionMap.js";
46
+ import { resolvePackActions } from "./pack.js";
46
47
  import { getCategoryListing, getToolsInCategory } from "./actionCatalog.js";
47
48
  import { WakeUpStack } from "./wakeUpStack.js";
48
49
  import { hooks as defaultHooks } from "./hooks.js";
@@ -145,8 +146,8 @@ const ON_CHAIN_ACTIONS = new Set([
145
146
  * // → "- reply: Send a text reply in the current context. Params: content (string)\n..."
146
147
  * ```
147
148
  */
148
- export function getAvailableActions(signalType, loadedCategories) {
149
- return getAvailableActionsFromMap(signalType, loadedCategories ?? new Set());
149
+ export function getAvailableActions(signalType, loadedCategories, externalActions, packActions) {
150
+ return getAvailableActionsFromMap(signalType, loadedCategories ?? new Set(), externalActions, packActions);
150
151
  }
151
152
  /**
152
153
  * Maps a `mining_opportunity` signal's optional `track` field to the
@@ -207,6 +208,29 @@ export class AutonomousAgent {
207
208
  this.approvalHandler = options.onApproval;
208
209
  this.cooldownSec = options.responseCooldown ?? 120;
209
210
  this.wakeUpStack = new WakeUpStack(runtime);
211
+ this.packActions = options.pack ? resolvePackActions(options.pack) : null;
212
+ }
213
+ /** External MCP tools (mounted servers) exposed as `mcp__<server>__<tool>` actions. */
214
+ externalMcpActions = [];
215
+ /**
216
+ * Resolved action set of the loaded pack (null = no pack, ungated).
217
+ * Set once at construction from options.pack — packs are immutable per load.
218
+ */
219
+ packActions;
220
+ /**
221
+ * Fetch the agent's mounted external MCP tools and expose them as
222
+ * available actions (ROADMAP_external-mcp-connectors Phase 1). Runs at
223
+ * start(); call again after connectMcpServer to pick up new mounts.
224
+ */
225
+ async refreshExternalMcpActions() {
226
+ const tools = await this.runtime.tools.listMcpTools();
227
+ // The gateway computes the provider-safe wire name at discovery; tools
228
+ // without one (unmappable names) are visible in listMcpTools but can
229
+ // never be dispatched, so they don't surface as actions.
230
+ this.externalMcpActions = tools
231
+ .map((t) => t.wireName)
232
+ .filter((n) => typeof n === "string" && n.startsWith("mcp__"));
233
+ return this.externalMcpActions;
210
234
  }
211
235
  /** Start listening for proactive signals and action requests. */
212
236
  start() {
@@ -243,6 +267,13 @@ export class AutonomousAgent {
243
267
  if (this.verbose) {
244
268
  console.log("[autonomous] AutonomousAgent started — handling signals + actions");
245
269
  }
270
+ // External MCP tools — loaded once at boot so mounted servers' tools
271
+ // surface in getAvailableActions and dispatch as `mcp:<server>:<tool>`.
272
+ this.refreshExternalMcpActions().catch((err) => {
273
+ if (this.verbose) {
274
+ console.error("[autonomous] External MCP tool load failed:", err);
275
+ }
276
+ });
246
277
  }
247
278
  /** Stop the autonomous agent. */
248
279
  stop() {
@@ -1407,7 +1438,11 @@ export class AutonomousAgent {
1407
1438
  console.log("[autonomous] No action parsed from response");
1408
1439
  return;
1409
1440
  }
1410
- const actionType = actionMatch[1].toLowerCase();
1441
+ // Wire names (`mcp__<server>__<tool>`) are case-sensitive registry keys —
1442
+ // lowercasing a mixed-case server/tool segment would dispatch a name that
1443
+ // doesn't exist (and trip pack gating with a misleading refusal).
1444
+ const rawAction = actionMatch[1];
1445
+ const actionType = rawAction.startsWith("mcp__") ? rawAction : rawAction.toLowerCase();
1411
1446
  let payload = {};
1412
1447
  const paramsMatch = text.match(/PARAMS:\s*(\{[\s\S]*\})/i);
1413
1448
  if (paramsMatch) {
@@ -2707,6 +2742,29 @@ export class AutonomousAgent {
2707
2742
  if (this.verbose) {
2708
2743
  console.log(`[autonomous] Action request: ${actionType}${actionId ? ` (${actionId})` : ""}`);
2709
2744
  }
2745
+ // Pack gating (ROADMAP_external-mcp-connectors Phase 3): with a pack
2746
+ // loaded, refuse anything outside CORE ∪ pack ∪ mounted-MCP. Gated
2747
+ // prompts never offer these — this guard catches handler-injected or
2748
+ // hallucinated action types.
2749
+ if (this.packActions) {
2750
+ const allowed = actionType.startsWith("mcp__")
2751
+ ? this.externalMcpActions.includes(actionType)
2752
+ : CORE_ACTIONS.includes(actionType) || this.packActions.includes(actionType);
2753
+ if (!allowed) {
2754
+ if (this.verbose)
2755
+ console.log(`[autonomous] Action denied by pack gating: ${actionType}`);
2756
+ hooks.emitFireAndForget("action_rejected", {
2757
+ actionType, args, reason: "Not allowed by loaded pack", actionId,
2758
+ });
2759
+ if (actionId) {
2760
+ try {
2761
+ await this.runtime.proactive.rejectDelegatedAction(actionId, "Not allowed by loaded pack");
2762
+ }
2763
+ catch { /* best-effort */ }
2764
+ }
2765
+ return;
2766
+ }
2767
+ }
2710
2768
  // Approval gate: on-chain actions require approval when handler is set
2711
2769
  if (this.approvalHandler && ON_CHAIN_ACTIONS.has(actionType)) {
2712
2770
  const approved = await this.approvalHandler(actionType, args);
@@ -2875,7 +2933,7 @@ export class AutonomousAgent {
2875
2933
  // the original `payload` — otherwise input-guardrail mutations
2876
2934
  // (lowercase normalization, content sanitization, etc.) silently get
2877
2935
  // dropped on the way to the gateway.
2878
- const toolName = `nookplot_${actionType}`;
2936
+ const toolName = resolveDispatchToolName(actionType);
2879
2937
  const dispatchPayload = {
2880
2938
  ...args,
2881
2939
  ...(suggestedContent ? { suggestedContent } : {}),
@@ -3444,7 +3502,7 @@ export class AutonomousAgent {
3444
3502
  if (!this.generateResponse)
3445
3503
  return;
3446
3504
  try {
3447
- const actions = getAvailableActionsFromMap("swarm_subtask_available", this.loadedCategories);
3505
+ const actions = getAvailableActionsFromMap("swarm_subtask_available", this.loadedCategories, this.externalMcpActions, this.packActions);
3448
3506
  const prompt = `A swarm "${sanitizeForPrompt(swarmTitle.slice(0, 100))}" has open subtasks matching your skills.\n` +
3449
3507
  `Swarm ID: ${swarmId}\n` +
3450
3508
  `Matching skills: ${skillTags.slice(0, 10).join(", ")}\n\n` +
@@ -3472,7 +3530,7 @@ export class AutonomousAgent {
3472
3530
  if (!this.generateResponse)
3473
3531
  return;
3474
3532
  try {
3475
- const actions = getAvailableActionsFromMap("swarm_result_submitted", this.loadedCategories);
3533
+ const actions = getAvailableActionsFromMap("swarm_result_submitted", this.loadedCategories, this.externalMcpActions, this.packActions);
3476
3534
  const prompt = `A result was submitted for subtask "${sanitizeForPrompt(subtaskTitle.slice(0, 100))}" in your swarm.\n` +
3477
3535
  `Swarm ID: ${swarmId}\n` +
3478
3536
  `Submitted by: ${sanitizeForPrompt((submittedBy).slice(0, 12))}...\n\n` +
@@ -3522,7 +3580,7 @@ export class AutonomousAgent {
3522
3580
  searchResult = await this.parseAndExecuteAction(searchText);
3523
3581
  }
3524
3582
  // Step 2: Based on search results, store an insight
3525
- const actions = getAvailableActionsFromMap("dream_prompt", this.loadedCategories);
3583
+ const actions = getAvailableActionsFromMap("dream_prompt", this.loadedCategories, this.externalMcpActions, this.packActions);
3526
3584
  const searchContext = searchResult
3527
3585
  ? `\nSearch results (summarized): ${JSON.stringify(searchResult).slice(0, 1500)}\n`
3528
3586
  : "\nNo search results found — consider creating foundational knowledge for these domains.\n";