@warlock.js/ai 4.15.0 → 4.16.0

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 (89) hide show
  1. package/CHANGELOG.md +182 -163
  2. package/cjs/index.cjs +637 -104
  3. package/cjs/index.cjs.map +1 -1
  4. package/esm/contracts/index.d.mts +2 -2
  5. package/esm/contracts/memory/index.d.mts +1 -1
  6. package/esm/contracts/memory/memory-config.type.d.mts +29 -3
  7. package/esm/contracts/memory/memory-config.type.d.mts.map +1 -1
  8. package/esm/contracts/memory/memory-item.type.d.mts +15 -1
  9. package/esm/contracts/memory/memory-item.type.d.mts.map +1 -1
  10. package/esm/contracts/memory/memory.contract.d.mts +15 -2
  11. package/esm/contracts/memory/memory.contract.d.mts.map +1 -1
  12. package/esm/contracts/memory/recall-options.type.d.mts +12 -0
  13. package/esm/contracts/memory/recall-options.type.d.mts.map +1 -1
  14. package/esm/contracts/orchestrator/index.d.mts +1 -1
  15. package/esm/contracts/orchestrator/orchestrator-config.type.d.mts +38 -1
  16. package/esm/contracts/orchestrator/orchestrator-config.type.d.mts.map +1 -1
  17. package/esm/contracts/orchestrator/orchestrator.contract.d.mts +67 -3
  18. package/esm/contracts/orchestrator/orchestrator.contract.d.mts.map +1 -1
  19. package/esm/contracts/supervisor/supervisor-config.type.d.mts +23 -0
  20. package/esm/contracts/supervisor/supervisor-config.type.d.mts.map +1 -1
  21. package/esm/index.d.mts +6 -5
  22. package/esm/index.mjs +3 -2
  23. package/esm/memory/episodic-memory.mjs +14 -6
  24. package/esm/memory/episodic-memory.mjs.map +1 -1
  25. package/esm/memory/index.d.mts +1 -1
  26. package/esm/memory/memory.d.mts +13 -1
  27. package/esm/memory/memory.d.mts.map +1 -1
  28. package/esm/memory/memory.mjs +41 -7
  29. package/esm/memory/memory.mjs.map +1 -1
  30. package/esm/memory/procedural-memory.mjs +20 -7
  31. package/esm/memory/procedural-memory.mjs.map +1 -1
  32. package/esm/memory/semantic-memory.mjs +27 -10
  33. package/esm/memory/semantic-memory.mjs.map +1 -1
  34. package/esm/memory/working-memory.mjs +70 -13
  35. package/esm/memory/working-memory.mjs.map +1 -1
  36. package/esm/middleware/builtins/semantic-cache.d.mts +46 -1
  37. package/esm/middleware/builtins/semantic-cache.d.mts.map +1 -1
  38. package/esm/middleware/builtins/semantic-cache.mjs +60 -15
  39. package/esm/middleware/builtins/semantic-cache.mjs.map +1 -1
  40. package/esm/middleware/index.d.mts +1 -1
  41. package/esm/orchestrator/as-tool.d.mts +35 -9
  42. package/esm/orchestrator/as-tool.d.mts.map +1 -1
  43. package/esm/orchestrator/as-tool.mjs +67 -19
  44. package/esm/orchestrator/as-tool.mjs.map +1 -1
  45. package/esm/orchestrator/execution.d.mts.map +1 -1
  46. package/esm/orchestrator/execution.mjs +2 -2
  47. package/esm/orchestrator/execution.mjs.map +1 -1
  48. package/esm/orchestrator/index.d.mts +1 -1
  49. package/esm/orchestrator/index.mjs +1 -1
  50. package/esm/orchestrator/memory.d.mts +41 -5
  51. package/esm/orchestrator/memory.d.mts.map +1 -1
  52. package/esm/orchestrator/memory.mjs +53 -5
  53. package/esm/orchestrator/memory.mjs.map +1 -1
  54. package/esm/planner/plan-schema.d.mts +3 -3
  55. package/esm/planner/plan-schema.d.mts.map +1 -1
  56. package/esm/planner/plan-schema.mjs +30 -0
  57. package/esm/planner/plan-schema.mjs.map +1 -1
  58. package/esm/security/index.mjs +1 -0
  59. package/esm/security/outbound-policy.d.mts +9 -0
  60. package/esm/security/outbound-policy.d.mts.map +1 -1
  61. package/esm/security/outbound-policy.mjs +79 -5
  62. package/esm/security/outbound-policy.mjs.map +1 -1
  63. package/esm/security/outbound-policy.type.d.mts +8 -0
  64. package/esm/security/outbound-policy.type.d.mts.map +1 -1
  65. package/esm/security/safe-merge.d.mts +52 -0
  66. package/esm/security/safe-merge.d.mts.map +1 -0
  67. package/esm/security/safe-merge.mjs +68 -0
  68. package/esm/security/safe-merge.mjs.map +1 -0
  69. package/esm/supervisor/decide.mjs +52 -5
  70. package/esm/supervisor/decide.mjs.map +1 -1
  71. package/esm/supervisor/execution.d.mts +22 -0
  72. package/esm/supervisor/execution.d.mts.map +1 -1
  73. package/esm/supervisor/execution.mjs +46 -9
  74. package/esm/supervisor/execution.mjs.map +1 -1
  75. package/esm/supervisor/supervisor.mjs +4 -0
  76. package/esm/supervisor/supervisor.mjs.map +1 -1
  77. package/llms-full.txt +174 -10
  78. package/llms.txt +4 -3
  79. package/package.json +4 -4
  80. package/skills/README.md +5 -1
  81. package/skills/attach-ai-middleware/SKILL.md +17 -1
  82. package/skills/rag-loaders-and-stores/SKILL.md +3 -0
  83. package/skills/run-ai-agent/SKILL.md +3 -0
  84. package/skills/run-orchestrator/SKILL.md +6 -1
  85. package/skills/run-planner/SKILL.md +7 -3
  86. package/skills/run-supervisor/SKILL.md +11 -1
  87. package/skills/secure-outbound-requests/SKILL.md +85 -0
  88. package/skills/use-ai-memory/SKILL.md +36 -3
  89. package/skills/use-runtime-skills/SKILL.md +2 -1
@@ -11,8 +11,9 @@ import "../utils/index.mjs";
11
11
  import { runPipeline } from "../middleware/pipeline.mjs";
12
12
  import { END } from "../contracts/end.type.mjs";
13
13
  import { isAgentResult, isWorkflowResult } from "./entries.mjs";
14
+ import { assignSafeKey, isUnsafeMergeKey, mergeSafely } from "../security/safe-merge.mjs";
14
15
  import { createCancelledError } from "./cancellation.mjs";
15
- import { decide } from "./decide.mjs";
16
+ import { capFanOut, decide, resolveMaxFanOut } from "./decide.mjs";
16
17
  import { persistSupervisorSnapshot } from "./snapshot.mjs";
17
18
  import { log } from "@warlock.js/logger";
18
19
 
@@ -432,9 +433,17 @@ var SupervisorExecution = class {
432
433
  * branch errors don't abort siblings — they're recorded on the
433
434
  * branch snapshot and let evaluate (or default termination logic)
434
435
  * decide the response.
436
+ *
437
+ * `capFanOut` runs here as well as in `decide.ts` — this is the one
438
+ * chokepoint every dispatch source funnels through (router/route
439
+ * decisions, `evaluate.reassignTo`, classifier picks, per-intent
440
+ * `next` unions), so the width bound holds even for the paths that
441
+ * build a `DispatchDecision` without going through `normalize()`.
442
+ * Idempotent for already-normalized decisions.
435
443
  */
436
444
  async dispatchBranches(decision) {
437
- return await Promise.all(decision.intents.map((intent) => this.dispatchOne(intent)));
445
+ const intents = capFanOut(decision.intents, this.entries, resolveMaxFanOut(this.config));
446
+ return await Promise.all(intents.map((intent) => this.dispatchOne(intent)));
438
447
  }
439
448
  /**
440
449
  * Execute a single branch — resolve the input, invoke the
@@ -1120,7 +1129,31 @@ var SupervisorExecution = class {
1120
1129
  if (ackOutcome.error || !ackOutcome.output) return;
1121
1130
  if (typeof ackOutcome.output !== "object" || ackOutcome.output === null) return;
1122
1131
  const slice = ackOutcome.output;
1123
- for (const [key, value] of Object.entries(slice)) this.state[key] = value;
1132
+ this.mergeIntoState(slice, "ack");
1133
+ }
1134
+ /**
1135
+ * Single funnel for "shallow-merge a model-influenced slice into
1136
+ * `this.state`". Wraps the shared {@link mergeSafely} guard so no
1137
+ * merge site can assign `__proto__` / `constructor` / `prototype`
1138
+ * onto the run's state object, and logs when something tried.
1139
+ *
1140
+ * Every slice reaching state is model- or tool-influenced (agent
1141
+ * outputs validated against a DEVELOPER-supplied schema, which may
1142
+ * legitimately be permissive: `z.record()`, `.passthrough()`,
1143
+ * `z.any()`), so the key names are untrusted input even when the
1144
+ * values are shaped.
1145
+ */
1146
+ mergeIntoState(slice, origin) {
1147
+ const skipped = mergeSafely(this.state, slice);
1148
+ this.warnOnUnsafeKeys(skipped, origin);
1149
+ }
1150
+ /** Shared logging for refused prototype-tampering keys. */
1151
+ warnOnUnsafeKeys(skipped, origin) {
1152
+ if (skipped.length === 0) return;
1153
+ this.logger.warn(this.logModule, "state.merge.unsafe-key", `dropped prototype-tampering key(s) from "${origin}" merge: ${skipped.join(", ")}`, {
1154
+ origin,
1155
+ keys: skipped
1156
+ });
1124
1157
  }
1125
1158
  /**
1126
1159
  * Run the iter-0 classifier prelude (Phase 7 / decisions §37).
@@ -1244,9 +1277,9 @@ var SupervisorExecution = class {
1244
1277
  refined = interpretation.refined;
1245
1278
  halted = interpretation.halted;
1246
1279
  final = interpretation.final ?? raw;
1247
- if (interpretation.sliceToMerge) for (const [key, value] of Object.entries(interpretation.sliceToMerge)) this.state[key] = value;
1280
+ if (interpretation.sliceToMerge) this.mergeIntoState(interpretation.sliceToMerge, "classifier.refine");
1248
1281
  }
1249
- for (const [key, value] of Object.entries(final)) this.state[key] = value;
1282
+ this.mergeIntoState(final, "classifier");
1250
1283
  this.classifierSnapshot = {
1251
1284
  intent: halted ? void 0 : final.intent,
1252
1285
  reasoning: final.reasoning,
@@ -1443,7 +1476,7 @@ var SupervisorExecution = class {
1443
1476
  const slice = {};
1444
1477
  for (const [key, value] of Object.entries(record)) {
1445
1478
  if (key === "intent") continue;
1446
- slice[key] = value;
1479
+ assignSafeKey(slice, key, value);
1447
1480
  }
1448
1481
  const final = {
1449
1482
  ...raw,
@@ -1519,6 +1552,10 @@ var SupervisorExecution = class {
1519
1552
  continue;
1520
1553
  }
1521
1554
  for (const [key, value] of Object.entries(slice)) {
1555
+ if (isUnsafeMergeKey(key)) {
1556
+ this.warnOnUnsafeKeys([key], `intent "${intent}"`);
1557
+ continue;
1558
+ }
1522
1559
  const previousOwner = mergedKeys.get(key);
1523
1560
  if (previousOwner !== void 0 && previousOwner !== intent) this.logger.warn(this.logModule, "state.merge.conflict", `state key "${key}" written by both "${previousOwner}" and "${intent}" — last-in-decision-array wins (Q15)`, {
1524
1561
  key,
@@ -1570,9 +1607,9 @@ var SupervisorExecution = class {
1570
1607
  const finalize = this.config.finalizeArtifacts;
1571
1608
  if (finalize) {
1572
1609
  const merged = finalize(this.state, artifacts);
1573
- for (const key of Object.keys(this.state)) if (!(key in merged)) delete this.state[key];
1574
- for (const [key, value] of Object.entries(merged)) this.state[key] = value;
1575
- } else for (const [key, value] of Object.entries(artifacts)) this.state[key] = value;
1610
+ for (const key of Object.keys(this.state)) if (!Object.hasOwn(merged, key)) delete this.state[key];
1611
+ this.mergeIntoState(merged, "finalizeArtifacts");
1612
+ } else this.mergeIntoState(artifacts, "artifacts");
1576
1613
  this.currentArtifacts = {};
1577
1614
  }
1578
1615
  /**