@loopingai/core 0.1.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 (238) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +279 -0
  3. package/dist/a2a/agent-stub.d.ts +61 -0
  4. package/dist/a2a/agent-stub.d.ts.map +1 -0
  5. package/dist/a2a/agent-stub.js +2 -0
  6. package/dist/a2a/agent-stub.js.map +1 -0
  7. package/dist/a2a/card.d.ts +119 -0
  8. package/dist/a2a/card.d.ts.map +1 -0
  9. package/dist/a2a/card.js +115 -0
  10. package/dist/a2a/card.js.map +1 -0
  11. package/dist/a2a/context.d.ts +14 -0
  12. package/dist/a2a/context.d.ts.map +1 -0
  13. package/dist/a2a/context.js +55 -0
  14. package/dist/a2a/context.js.map +1 -0
  15. package/dist/a2a/executor.d.ts +85 -0
  16. package/dist/a2a/executor.d.ts.map +1 -0
  17. package/dist/a2a/executor.js +107 -0
  18. package/dist/a2a/executor.js.map +1 -0
  19. package/dist/a2a/index.d.ts +18 -0
  20. package/dist/a2a/index.d.ts.map +1 -0
  21. package/dist/a2a/index.js +17 -0
  22. package/dist/a2a/index.js.map +1 -0
  23. package/dist/a2a/notify.d.ts +75 -0
  24. package/dist/a2a/notify.d.ts.map +1 -0
  25. package/dist/a2a/notify.js +161 -0
  26. package/dist/a2a/notify.js.map +1 -0
  27. package/dist/a2a/parts.d.ts +46 -0
  28. package/dist/a2a/parts.d.ts.map +1 -0
  29. package/dist/a2a/parts.js +95 -0
  30. package/dist/a2a/parts.js.map +1 -0
  31. package/dist/a2a/task-store.d.ts +45 -0
  32. package/dist/a2a/task-store.d.ts.map +1 -0
  33. package/dist/a2a/task-store.js +100 -0
  34. package/dist/a2a/task-store.js.map +1 -0
  35. package/dist/a2a/task.d.ts +86 -0
  36. package/dist/a2a/task.d.ts.map +1 -0
  37. package/dist/a2a/task.js +16 -0
  38. package/dist/a2a/task.js.map +1 -0
  39. package/dist/a2a/verify.d.ts +64 -0
  40. package/dist/a2a/verify.d.ts.map +1 -0
  41. package/dist/a2a/verify.js +122 -0
  42. package/dist/a2a/verify.js.map +1 -0
  43. package/dist/agent/budget.d.ts +47 -0
  44. package/dist/agent/budget.d.ts.map +1 -0
  45. package/dist/agent/budget.js +43 -0
  46. package/dist/agent/budget.js.map +1 -0
  47. package/dist/agent/control.d.ts +110 -0
  48. package/dist/agent/control.d.ts.map +1 -0
  49. package/dist/agent/control.js +115 -0
  50. package/dist/agent/control.js.map +1 -0
  51. package/dist/agent/final-reply.d.ts +49 -0
  52. package/dist/agent/final-reply.d.ts.map +1 -0
  53. package/dist/agent/final-reply.js +52 -0
  54. package/dist/agent/final-reply.js.map +1 -0
  55. package/dist/agent/history.d.ts +83 -0
  56. package/dist/agent/history.d.ts.map +1 -0
  57. package/dist/agent/history.js +117 -0
  58. package/dist/agent/history.js.map +1 -0
  59. package/dist/agent/index.d.ts +17 -0
  60. package/dist/agent/index.d.ts.map +1 -0
  61. package/dist/agent/index.js +17 -0
  62. package/dist/agent/index.js.map +1 -0
  63. package/dist/agent/inference.d.ts +52 -0
  64. package/dist/agent/inference.d.ts.map +1 -0
  65. package/dist/agent/inference.js +79 -0
  66. package/dist/agent/inference.js.map +1 -0
  67. package/dist/agent/model.d.ts +75 -0
  68. package/dist/agent/model.d.ts.map +1 -0
  69. package/dist/agent/model.js +62 -0
  70. package/dist/agent/model.js.map +1 -0
  71. package/dist/agent/session.d.ts +92 -0
  72. package/dist/agent/session.d.ts.map +1 -0
  73. package/dist/agent/session.js +80 -0
  74. package/dist/agent/session.js.map +1 -0
  75. package/dist/config.d.ts +159 -0
  76. package/dist/config.d.ts.map +1 -0
  77. package/dist/config.js +92 -0
  78. package/dist/config.js.map +1 -0
  79. package/dist/contract/index.d.ts +10 -0
  80. package/dist/contract/index.d.ts.map +1 -0
  81. package/dist/contract/index.js +9 -0
  82. package/dist/contract/index.js.map +1 -0
  83. package/dist/contract/plugin.d.ts +163 -0
  84. package/dist/contract/plugin.d.ts.map +1 -0
  85. package/dist/contract/plugin.js +39 -0
  86. package/dist/contract/plugin.js.map +1 -0
  87. package/dist/contract/recipe.d.ts +170 -0
  88. package/dist/contract/recipe.d.ts.map +1 -0
  89. package/dist/contract/recipe.js +2 -0
  90. package/dist/contract/recipe.js.map +1 -0
  91. package/dist/contract/validation.d.ts +86 -0
  92. package/dist/contract/validation.d.ts.map +1 -0
  93. package/dist/contract/validation.js +76 -0
  94. package/dist/contract/validation.js.map +1 -0
  95. package/dist/db/db.d.ts +131 -0
  96. package/dist/db/db.d.ts.map +1 -0
  97. package/dist/db/db.js +91 -0
  98. package/dist/db/db.js.map +1 -0
  99. package/dist/db/index.d.ts +9 -0
  100. package/dist/db/index.d.ts.map +1 -0
  101. package/dist/db/index.js +9 -0
  102. package/dist/db/index.js.map +1 -0
  103. package/dist/db/migrations/index.d.ts +21 -0
  104. package/dist/db/migrations/index.d.ts.map +1 -0
  105. package/dist/db/migrations/index.js +54 -0
  106. package/dist/db/migrations/index.js.map +1 -0
  107. package/dist/db/models/subtasks.d.ts +102 -0
  108. package/dist/db/models/subtasks.d.ts.map +1 -0
  109. package/dist/db/models/subtasks.js +285 -0
  110. package/dist/db/models/subtasks.js.map +1 -0
  111. package/dist/db/models/tasks.d.ts +92 -0
  112. package/dist/db/models/tasks.d.ts.map +1 -0
  113. package/dist/db/models/tasks.js +212 -0
  114. package/dist/db/models/tasks.js.map +1 -0
  115. package/dist/db/schema.d.ts +488 -0
  116. package/dist/db/schema.d.ts.map +1 -0
  117. package/dist/db/schema.js +91 -0
  118. package/dist/db/schema.js.map +1 -0
  119. package/dist/env.d.ts +46 -0
  120. package/dist/env.d.ts.map +1 -0
  121. package/dist/env.js +40 -0
  122. package/dist/env.js.map +1 -0
  123. package/dist/index.d.ts +20 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +18 -0
  126. package/dist/index.js.map +1 -0
  127. package/dist/platform.d.ts +47 -0
  128. package/dist/platform.d.ts.map +1 -0
  129. package/dist/platform.js +47 -0
  130. package/dist/platform.js.map +1 -0
  131. package/dist/runtime/index.d.ts +86 -0
  132. package/dist/runtime/index.d.ts.map +1 -0
  133. package/dist/runtime/index.js +123 -0
  134. package/dist/runtime/index.js.map +1 -0
  135. package/dist/runtime/tool-families.d.ts +33 -0
  136. package/dist/runtime/tool-families.d.ts.map +1 -0
  137. package/dist/runtime/tool-families.js +62 -0
  138. package/dist/runtime/tool-families.js.map +1 -0
  139. package/dist/subagent/fingerprint.d.ts +38 -0
  140. package/dist/subagent/fingerprint.d.ts.map +1 -0
  141. package/dist/subagent/fingerprint.js +97 -0
  142. package/dist/subagent/fingerprint.js.map +1 -0
  143. package/dist/subagent/index.d.ts +147 -0
  144. package/dist/subagent/index.d.ts.map +1 -0
  145. package/dist/subagent/index.js +299 -0
  146. package/dist/subagent/index.js.map +1 -0
  147. package/dist/subagent/prompt.d.ts +34 -0
  148. package/dist/subagent/prompt.d.ts.map +1 -0
  149. package/dist/subagent/prompt.js +46 -0
  150. package/dist/subagent/prompt.js.map +1 -0
  151. package/dist/subagent/run.d.ts +151 -0
  152. package/dist/subagent/run.d.ts.map +1 -0
  153. package/dist/subagent/run.js +491 -0
  154. package/dist/subagent/run.js.map +1 -0
  155. package/dist/subagent/workspace.d.ts +65 -0
  156. package/dist/subagent/workspace.d.ts.map +1 -0
  157. package/dist/subagent/workspace.js +53 -0
  158. package/dist/subagent/workspace.js.map +1 -0
  159. package/dist/subtasks/catalog.d.ts +40 -0
  160. package/dist/subtasks/catalog.d.ts.map +1 -0
  161. package/dist/subtasks/catalog.js +36 -0
  162. package/dist/subtasks/catalog.js.map +1 -0
  163. package/dist/subtasks/decomposition.d.ts +90 -0
  164. package/dist/subtasks/decomposition.d.ts.map +1 -0
  165. package/dist/subtasks/decomposition.js +205 -0
  166. package/dist/subtasks/decomposition.js.map +1 -0
  167. package/dist/subtasks/delegate.d.ts +77 -0
  168. package/dist/subtasks/delegate.d.ts.map +1 -0
  169. package/dist/subtasks/delegate.js +102 -0
  170. package/dist/subtasks/delegate.js.map +1 -0
  171. package/dist/subtasks/index.d.ts +11 -0
  172. package/dist/subtasks/index.d.ts.map +1 -0
  173. package/dist/subtasks/index.js +11 -0
  174. package/dist/subtasks/index.js.map +1 -0
  175. package/dist/subtasks/scheduler.d.ts +49 -0
  176. package/dist/subtasks/scheduler.d.ts.map +1 -0
  177. package/dist/subtasks/scheduler.js +48 -0
  178. package/dist/subtasks/scheduler.js.map +1 -0
  179. package/dist/subtasks/subtask-types.d.ts +100 -0
  180. package/dist/subtasks/subtask-types.d.ts.map +1 -0
  181. package/dist/subtasks/subtask-types.js +111 -0
  182. package/dist/subtasks/subtask-types.js.map +1 -0
  183. package/dist/subtasks/types.d.ts +321 -0
  184. package/dist/subtasks/types.d.ts.map +1 -0
  185. package/dist/subtasks/types.js +16 -0
  186. package/dist/subtasks/types.js.map +1 -0
  187. package/dist/testing/auth.d.ts +12 -0
  188. package/dist/testing/auth.d.ts.map +1 -0
  189. package/dist/testing/auth.js +25 -0
  190. package/dist/testing/auth.js.map +1 -0
  191. package/dist/testing/do.d.ts +30 -0
  192. package/dist/testing/do.d.ts.map +1 -0
  193. package/dist/testing/do.js +26 -0
  194. package/dist/testing/do.js.map +1 -0
  195. package/dist/testing/fake-session.d.ts +27 -0
  196. package/dist/testing/fake-session.d.ts.map +1 -0
  197. package/dist/testing/fake-session.js +38 -0
  198. package/dist/testing/fake-session.js.map +1 -0
  199. package/dist/testing/fixtures.d.ts +27 -0
  200. package/dist/testing/fixtures.d.ts.map +1 -0
  201. package/dist/testing/fixtures.js +67 -0
  202. package/dist/testing/fixtures.js.map +1 -0
  203. package/dist/testing/index.d.ts +31 -0
  204. package/dist/testing/index.d.ts.map +1 -0
  205. package/dist/testing/index.js +31 -0
  206. package/dist/testing/index.js.map +1 -0
  207. package/dist/testing/mock-model.d.ts +43 -0
  208. package/dist/testing/mock-model.d.ts.map +1 -0
  209. package/dist/testing/mock-model.js +62 -0
  210. package/dist/testing/mock-model.js.map +1 -0
  211. package/dist/testing/node.d.ts +24 -0
  212. package/dist/testing/node.d.ts.map +1 -0
  213. package/dist/testing/node.js +24 -0
  214. package/dist/testing/node.js.map +1 -0
  215. package/dist/testing/vcr-global-setup.d.ts +3 -0
  216. package/dist/testing/vcr-global-setup.d.ts.map +1 -0
  217. package/dist/testing/vcr-global-setup.js +9 -0
  218. package/dist/testing/vcr-global-setup.js.map +1 -0
  219. package/dist/testing/vcr-shared.d.ts +21 -0
  220. package/dist/testing/vcr-shared.d.ts.map +1 -0
  221. package/dist/testing/vcr-shared.js +21 -0
  222. package/dist/testing/vcr-shared.js.map +1 -0
  223. package/dist/testing/vcr-spec.d.ts +17 -0
  224. package/dist/testing/vcr-spec.d.ts.map +1 -0
  225. package/dist/testing/vcr-spec.js +72 -0
  226. package/dist/testing/vcr-spec.js.map +1 -0
  227. package/dist/testing/vcr.d.ts +81 -0
  228. package/dist/testing/vcr.d.ts.map +1 -0
  229. package/dist/testing/vcr.js +211 -0
  230. package/dist/testing/vcr.js.map +1 -0
  231. package/dist/worker/index.d.ts +62 -0
  232. package/dist/worker/index.d.ts.map +1 -0
  233. package/dist/worker/index.js +194 -0
  234. package/dist/worker/index.js.map +1 -0
  235. package/eslint-rules/index.js +31 -0
  236. package/eslint-rules/no-deprecated-object-properties.js +81 -0
  237. package/package.json +147 -0
  238. package/scripts/generate-keys.mjs +53 -0
package/dist/config.js ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * The shapes of everything an agent tunes, plus a working set of defaults.
3
+ *
4
+ * In the predecessor repos this file held bare `export const`s that ~12 modules
5
+ * imported directly. That is what this package cannot do: a module-level constant
6
+ * read at import time is not overridable by a consumer, and it freezes the value
7
+ * into the module graph before `env` exists. So core owns the *shapes* and a
8
+ * baseline; a consuming agent passes overrides to {@link resolveConfig} once, at
9
+ * DO start, and the resolved object is threaded through explicitly.
10
+ *
11
+ * The distinction against {@link file://./platform.ts} stays sharp: nothing here
12
+ * is a platform fact, and nothing there is tunable.
13
+ */
14
+ /**
15
+ * A working baseline. Every value is overridable; none is a ceiling. These are
16
+ * the values both predecessor agents converged on in production, so they are a
17
+ * reasonable place to start rather than an opinion about your domain.
18
+ */
19
+ export const DEFAULT_CORE_CONFIG = {
20
+ model: {
21
+ chatModelId: "@cf/zai-org/glm-5.2",
22
+ fallbackChatModelId: "@cf/moonshotai/kimi-k2.7-code",
23
+ aiGatewayId: "default",
24
+ maxOutputTokens: 16_384,
25
+ reasoningEffort: "medium",
26
+ embeddingModelId: "@cf/baai/bge-m3"
27
+ },
28
+ mainAgentLimits: { maxTurns: 20, maxWallMs: 60 * 60_000 },
29
+ subagentLimits: { maxTurns: 20, maxWallMs: 30 * 60_000 },
30
+ toolOutputWindow: 4,
31
+ maxSubtasks: 8,
32
+ session: {
33
+ memoryMaxTokens: 1200,
34
+ compactAfterTokens: 16_000,
35
+ compactTailTokens: 5_000,
36
+ memoryDescription: "Durable facts worth remembering across all of this caller's conversations — " +
37
+ "stable preferences, decisions, people, and context. Keep it concise."
38
+ },
39
+ recall: { topK: 5, metadataTextMax: 2000 }
40
+ };
41
+ export class ConfigError extends Error {
42
+ constructor(message) {
43
+ super(message);
44
+ this.name = "ConfigError";
45
+ }
46
+ }
47
+ /**
48
+ * Merge overrides onto {@link DEFAULT_CORE_CONFIG} and check the invariants that
49
+ * are cheap to get wrong and expensive to notice.
50
+ *
51
+ * Called once, at DO start, and the result threaded explicitly from there. Do
52
+ * not call it per-request: the point of resolving is that every module downstream
53
+ * reads the same object.
54
+ */
55
+ export function resolveConfig(overrides = {}) {
56
+ const config = {
57
+ model: { ...DEFAULT_CORE_CONFIG.model, ...overrides.model },
58
+ mainAgentLimits: {
59
+ ...DEFAULT_CORE_CONFIG.mainAgentLimits,
60
+ ...overrides.mainAgentLimits
61
+ },
62
+ subagentLimits: {
63
+ ...DEFAULT_CORE_CONFIG.subagentLimits,
64
+ ...overrides.subagentLimits
65
+ },
66
+ toolOutputWindow: overrides.toolOutputWindow ?? DEFAULT_CORE_CONFIG.toolOutputWindow,
67
+ maxSubtasks: overrides.maxSubtasks ?? DEFAULT_CORE_CONFIG.maxSubtasks,
68
+ session: { ...DEFAULT_CORE_CONFIG.session, ...overrides.session },
69
+ recall: { ...DEFAULT_CORE_CONFIG.recall, ...overrides.recall }
70
+ };
71
+ const positive = (value, name) => {
72
+ if (!Number.isFinite(value) || value <= 0) {
73
+ throw new ConfigError(`${name} must be a positive number, got ${value}`);
74
+ }
75
+ };
76
+ positive(config.mainAgentLimits.maxTurns, "mainAgentLimits.maxTurns");
77
+ positive(config.mainAgentLimits.maxWallMs, "mainAgentLimits.maxWallMs");
78
+ positive(config.subagentLimits.maxTurns, "subagentLimits.maxTurns");
79
+ positive(config.subagentLimits.maxWallMs, "subagentLimits.maxWallMs");
80
+ positive(config.toolOutputWindow, "toolOutputWindow");
81
+ positive(config.maxSubtasks, "maxSubtasks");
82
+ positive(config.model.maxOutputTokens, "model.maxOutputTokens");
83
+ // See SessionConfig.compactTailTokens — below this gap the fixed floor eats
84
+ // the headroom and compaction fires on nearly every append.
85
+ const headroom = config.session.compactAfterTokens - config.session.compactTailTokens;
86
+ if (headroom < 10_000) {
87
+ throw new ConfigError(`session.compactAfterTokens - session.compactTailTokens must be >= 10000, got ${headroom}. ` +
88
+ "Lower compactTailTokens along with compactAfterTokens.");
89
+ }
90
+ return config;
91
+ }
92
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The plugin contract — the only thing core and a plugin package both name.
3
+ *
4
+ * Re-exported from the package root as well, so a plugin author writes
5
+ * `import { definePlugin } from "@loopingai/core"` and nothing else.
6
+ */
7
+ export { PLUGIN_CONTRACT_VERSION, definePlugin, type AgentPlugin, type EmitProgress, type EnrichResultContext, type PluginRequirements, type RecipeToolSet, type ResolveRuntimeContext, type ToolFamilyBuilder, type ToolFamilyContext } from "./plugin.js";
8
+ export type { DelegationNames, RecipeLimits, ResolvedRecipe, SubtaskParams, SubtaskParamsSchema, SubtaskParamsShape, SubtaskTypeSpec, ValidatedRecipe } from "./recipe.js";
9
+ export { RecipeValidationError, resolveLimits, validateRecipe, type RecipePolicy } from "./validation.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,uBAAuB,EACvB,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,eAAe,EACf,YAAY,EACZ,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The plugin contract — the only thing core and a plugin package both name.
3
+ *
4
+ * Re-exported from the package root as well, so a plugin author writes
5
+ * `import { definePlugin } from "@loopingai/core"` and nothing else.
6
+ */
7
+ export { PLUGIN_CONTRACT_VERSION, definePlugin } from "./plugin.js";
8
+ export { RecipeValidationError, resolveLimits, validateRecipe } from "./validation.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contract/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,uBAAuB,EACvB,YAAY,EASb,MAAM,aAAa,CAAC;AAarB,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,cAAc,EAEf,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,163 @@
1
+ import type { ToolSet } from "ai";
2
+ import type { PluginStore } from "../db/db.js";
3
+ import type { WorkspaceHandle } from "../subagent/workspace.js";
4
+ import type { ProgressEvent, RecipeExecutionRequest, RecipeExecutionResult, SubtaskRuntime } from "../subtasks/types.js";
5
+ import type { SubtaskParams, SubtaskTypeSpec } from "./recipe.js";
6
+ /**
7
+ * The plugin contract — everything an independently-packaged capability may
8
+ * contribute to an agent, and the only thing core knows about one.
9
+ *
10
+ * Nothing in core imports a plugin. A plugin imports core (type-only wherever it
11
+ * can) and is registered by the *host* at DO start. That direction is what makes
12
+ * bundle growth proportional to what an agent actually installs, and it is
13
+ * structural rather than a tree-shaker's opinion.
14
+ */
15
+ /**
16
+ * The contract version a plugin was built against.
17
+ *
18
+ * Three separate repos means a contract change is a three-repo publish train, and
19
+ * the failure mode of a skew is a structural-type mismatch several frames from
20
+ * its cause. `createAgentRuntime` asserts this instead, so a mismatched plugin
21
+ * fails at DO start with a sentence naming the plugin and both versions.
22
+ *
23
+ * The contract is **additive-only** within a major: new capabilities arrive as
24
+ * optional fields on {@link AgentPlugin}. Removing or re-typing an existing field
25
+ * requires a major and a bump here.
26
+ */
27
+ export declare const PLUGIN_CONTRACT_VERSION = 1;
28
+ /**
29
+ * Emit a user-facing progress note from inside a tool (e.g. a level-up in a
30
+ * game, a milestone in a long scrape). The resumable runner collects these and
31
+ * ends the current chunk so the parent can post them promptly. Best-effort — the
32
+ * runner never lets a progress note affect generation.
33
+ */
34
+ export type EmitProgress = (event: ProgressEvent) => void;
35
+ /**
36
+ * Everything a tool family needs to build its tools, closed over so none of it
37
+ * is ever model input.
38
+ *
39
+ * Note what is **not** here: the Worker `env`. The predecessor passed it, which
40
+ * a published package cannot do — `Env` is the ambient interface `wrangler
41
+ * types` generates into a consumer's `worker-configuration.d.ts` and does not
42
+ * exist outside their app. A plugin takes its secrets and bindings as *config at
43
+ * instantiation* instead, which is also the only thing that works on Workers,
44
+ * where `env` does not exist at module scope.
45
+ */
46
+ export interface ToolFamilyContext<TRuntime = SubtaskRuntime> {
47
+ /** The execution's durable file store. */
48
+ workspace: WorkspaceHandle;
49
+ emitProgress: EmitProgress;
50
+ /**
51
+ * The subtask's validated params — the ids its type declared it needs. Chosen
52
+ * by the delegating main agent and checked against its type's contract before
53
+ * this execution began, so a family may read them directly; they are not this
54
+ * model's input.
55
+ */
56
+ params: SubtaskParams;
57
+ /**
58
+ * Session state the parent resolved for this execution — what no model could
59
+ * supply and none should be asked to. Opaque to core; a plugin narrows it to
60
+ * whatever its own {@link AgentPlugin.resolveRuntime} wrote.
61
+ */
62
+ runtime: TRuntime;
63
+ }
64
+ /**
65
+ * A tool family's contribution: its tools, plus an optional `abort` hook the
66
+ * facet runs on cancellation to release external state the family acquired.
67
+ *
68
+ * Anything the hook needs must be reconstructible from the workspace, so it is
69
+ * safe to run on a fresh isolate after eviction.
70
+ */
71
+ export interface RecipeToolSet<TRuntime = SubtaskRuntime> {
72
+ tools: ToolSet;
73
+ abort?: (ctx: ToolFamilyContext<TRuntime>) => Promise<void>;
74
+ }
75
+ /** Builds one tool family's contribution for a single execution. */
76
+ export type ToolFamilyBuilder<TRuntime = SubtaskRuntime> = (ctx: ToolFamilyContext<TRuntime>) => RecipeToolSet<TRuntime>;
77
+ /** What the parent knows when resolving an execution's runtime state. */
78
+ export interface ResolveRuntimeContext {
79
+ taskId: string;
80
+ subtaskId: number;
81
+ type: string;
82
+ params: SubtaskParams;
83
+ toolFamilies: readonly string[];
84
+ }
85
+ /** What the parent knows when a plugin gets to enrich a terminal result. */
86
+ export interface EnrichResultContext<TRuntime = SubtaskRuntime> {
87
+ request: RecipeExecutionRequest;
88
+ runtime: TRuntime;
89
+ }
90
+ /** Bindings and secrets a plugin needs the *host* to provide in `wrangler.jsonc`. */
91
+ export interface PluginRequirements {
92
+ /** Secret names, e.g. `["ARC_API_KEY"]`. */
93
+ secrets?: readonly string[];
94
+ /** Binding names, e.g. `["BROWSER"]`. */
95
+ bindings?: readonly string[];
96
+ }
97
+ export interface AgentPlugin<TRuntime = SubtaskRuntime> {
98
+ /** Stable identifier, unique across installed plugins. */
99
+ key: string;
100
+ /**
101
+ * The {@link PLUGIN_CONTRACT_VERSION} this plugin was built against. Set it
102
+ * from the imported constant, never as a literal — the point is that it moves
103
+ * with the core the plugin compiled against.
104
+ */
105
+ contractVersion: number;
106
+ /**
107
+ * The subtask type this plugin makes delegable, and the recipe it runs under.
108
+ * A plugin that only contributes main-agent tools declares none.
109
+ */
110
+ subtaskType?: SubtaskTypeSpec;
111
+ /**
112
+ * Tool families this plugin registers, keyed by family name. A recipe selects
113
+ * families by name; a name no installed plugin registers is dropped by
114
+ * `validateRecipe`, so the legal set is exactly what is installed.
115
+ */
116
+ toolFamilies?: Record<string, ToolFamilyBuilder<TRuntime>>;
117
+ /** Tools offered to the *main* agent (e.g. a catalogue lookup before delegating). */
118
+ mainAgentTools?: () => ToolSet;
119
+ /**
120
+ * What the main agent is told it can do with this domain, rendered into its
121
+ * soul alongside the other capability blocks.
122
+ */
123
+ capability?: string;
124
+ /**
125
+ * Resolve the session state an execution needs and no model can supply — a
126
+ * leased external resource, a session handle, a cookie jar.
127
+ *
128
+ * Called by the parent before each chunk, and deliberately outside the
129
+ * execution's fingerprint: what it returns can legitimately change between two
130
+ * chunks of one run, and must not make a retry look like different work.
131
+ */
132
+ resolveRuntime?: (ctx: ResolveRuntimeContext) => Promise<TRuntime>;
133
+ /**
134
+ * Amend a terminal result before it is persisted — e.g. append a score the
135
+ * subagent had no way to read. Returning the result unchanged is always valid.
136
+ */
137
+ enrichResult?: (ctx: EnrichResultContext<TRuntime>, result: RecipeExecutionResult) => Promise<RecipeExecutionResult>;
138
+ /** Release anything {@link resolveRuntime} acquired, when an execution is canceled. */
139
+ onAbort?: (ctx: ResolveRuntimeContext) => Promise<void>;
140
+ /** Tables this plugin owns, outside core's migration journal. See {@link PluginStore}. */
141
+ store?: PluginStore;
142
+ /**
143
+ * Bindings and secrets the host must declare in `wrangler.jsonc`. A plugin
144
+ * cannot add its own binding, so declaring them lets startup fail with a
145
+ * readable message instead of at the first tool call, in a request a user is
146
+ * waiting on.
147
+ */
148
+ requires?: PluginRequirements;
149
+ }
150
+ /**
151
+ * Identity helper that pins {@link AgentPlugin.contractVersion} for you and gives
152
+ * a plugin author inference on `TRuntime`.
153
+ *
154
+ * ```ts
155
+ * export function arcAgi(config: { apiKey: string }) {
156
+ * return definePlugin<ArcRuntime>({ key: "arc-agi", … });
157
+ * }
158
+ * ```
159
+ */
160
+ export declare function definePlugin<TRuntime = SubtaskRuntime>(plugin: Omit<AgentPlugin<TRuntime>, "contractVersion"> & {
161
+ contractVersion?: number;
162
+ }): AgentPlugin<TRuntime>;
163
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/contract/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * The plugin contract — everything an independently-packaged capability may
3
+ * contribute to an agent, and the only thing core knows about one.
4
+ *
5
+ * Nothing in core imports a plugin. A plugin imports core (type-only wherever it
6
+ * can) and is registered by the *host* at DO start. That direction is what makes
7
+ * bundle growth proportional to what an agent actually installs, and it is
8
+ * structural rather than a tree-shaker's opinion.
9
+ */
10
+ /**
11
+ * The contract version a plugin was built against.
12
+ *
13
+ * Three separate repos means a contract change is a three-repo publish train, and
14
+ * the failure mode of a skew is a structural-type mismatch several frames from
15
+ * its cause. `createAgentRuntime` asserts this instead, so a mismatched plugin
16
+ * fails at DO start with a sentence naming the plugin and both versions.
17
+ *
18
+ * The contract is **additive-only** within a major: new capabilities arrive as
19
+ * optional fields on {@link AgentPlugin}. Removing or re-typing an existing field
20
+ * requires a major and a bump here.
21
+ */
22
+ export const PLUGIN_CONTRACT_VERSION = 1;
23
+ /**
24
+ * Identity helper that pins {@link AgentPlugin.contractVersion} for you and gives
25
+ * a plugin author inference on `TRuntime`.
26
+ *
27
+ * ```ts
28
+ * export function arcAgi(config: { apiKey: string }) {
29
+ * return definePlugin<ArcRuntime>({ key: "arc-agi", … });
30
+ * }
31
+ * ```
32
+ */
33
+ export function definePlugin(plugin) {
34
+ return {
35
+ ...plugin,
36
+ contractVersion: plugin.contractVersion ?? PLUGIN_CONTRACT_VERSION
37
+ };
38
+ }
39
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/contract/plugin.ts"],"names":[],"mappings":"AAWA;;;;;;;;GAQG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAqJzC;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,MAEC;IAED,OAAO;QACL,GAAG,MAAM;QACT,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,uBAAuB;KACnE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,170 @@
1
+ import type { z } from "zod";
2
+ import type { AgentLimits } from "../config.js";
3
+ /**
4
+ * What a recipe domain declares.
5
+ *
6
+ * These types flow **outward**: the runtime consumes them, and nothing in this
7
+ * file imports from the runtime. That direction is the whole reason a plugin can
8
+ * live in a separate package — a new domain is a new module plus one line in the
9
+ * consuming agent's plugin list, with no edit inside core.
10
+ *
11
+ * Two shapes, and the distinction between them carries real weight:
12
+ *
13
+ * - A **type** ({@link SubtaskTypeSpec}) is the semantic contract of a unit of
14
+ * work: what it means, and what it must be given to be doable at all.
15
+ * - A **Recipe** ({@link ResolvedRecipe}) is the execution *configuration* —
16
+ * models, soul, tool families, budgets. It declares no params, and one Recipe
17
+ * may serve several types.
18
+ */
19
+ /** Params carried by a Subtask: model-chosen, string-valued, shape-checked. */
20
+ export type SubtaskParams = Record<string, string>;
21
+ /**
22
+ * A type's param declaration, as a shape the agent can read back — not an opaque
23
+ * validator. The keys have to be *enumerable* because the delegate tool's schema
24
+ * is built from them: a param the model cannot see declared is a param it will
25
+ * not send. See {@link SubtaskTypeSpec.params}.
26
+ */
27
+ export type SubtaskParamsShape = Record<string, z.ZodType<string>>;
28
+ export type SubtaskParamsSchema = z.ZodObject<SubtaskParamsShape>;
29
+ /**
30
+ * The control-tool names the agent injects when it renders a type's
31
+ * {@link SubtaskTypeSpec.delegationGuidance}.
32
+ *
33
+ * Guidance legitimately names those tools ("ask the user with `final_reply`
34
+ * rather than guessing"), and their names are the agent's to own. Injecting them
35
+ * is what lets a domain write that sentence without importing from the runtime —
36
+ * the direction this module depends on.
37
+ */
38
+ export interface DelegationNames {
39
+ delegateTool: string;
40
+ finalReplyTool: string;
41
+ }
42
+ /**
43
+ * The execution budget for one Recipe, enforced by the resumable runner (not the
44
+ * Workflow). Exactly two fields, because there are exactly two things worth
45
+ * bounding: what an execution **costs** and how long it can **run away for**. The
46
+ * run ends on whichever it reaches first, and either way through the graceful
47
+ * budget summary.
48
+ *
49
+ * Deliberately *not* here: how a run is sliced into durable chunks. That is a
50
+ * Workers step-timeout constraint, it is identical for every Recipe, and it lives
51
+ * in {@link file://../platform.ts}. It used to include a `turnsPerChunk`, on the
52
+ * theory that a turn count could keep a step under the timeout — it cannot,
53
+ * because nothing predicts how long a turn takes, and the resulting arithmetic was
54
+ * wrong by 2-3× in practice.
55
+ */
56
+ /**
57
+ * Structurally identical to {@link AgentLimits} — a budget is a budget at both
58
+ * levels, and keeping one shape means `resolveLimits` merges a recipe's
59
+ * declaration straight over the host's baseline with no translation. Aliased
60
+ * rather than redeclared so the two can never drift apart.
61
+ */
62
+ export type RecipeLimits = AgentLimits;
63
+ /**
64
+ * A Recipe configuration as a domain **declares** it, one per folder in
65
+ * `recipes/<domain>/recipe.ts`; caller-local DB rows mapping into this shape are
66
+ * deferred until a Recipe admin surface exists. Model ids, tool families, and
67
+ * limits are code-validated downstream
68
+ * ({@link file://./validation.ts validateRecipe}), which is also what turns this
69
+ * into a {@link ValidatedRecipe}.
70
+ *
71
+ * One rule governs every field here, and it is worth stating once: **if
72
+ * `config.ts` declares a baseline, a Recipe overrides it; if it does not, the
73
+ * Recipe must supply it.** So `limits` is partial and merges, while `soul` and
74
+ * `historyWindow` are required and a missing one is refused rather than filled in.
75
+ */
76
+ export interface ResolvedRecipe {
77
+ key: string;
78
+ version: number;
79
+ primaryModelId: string;
80
+ fallbackModelId: string;
81
+ /** Required, never defaulted — see `validateRecipe`. */
82
+ soul: string;
83
+ toolFamilies: string[];
84
+ enabled: boolean;
85
+ /**
86
+ * Only the budget fields this Recipe overrides; the rest come from
87
+ * `SUBAGENT_LIMITS`. `{}` means "the baseline", which is what most Recipes want.
88
+ */
89
+ limits: Partial<RecipeLimits>;
90
+ /**
91
+ * Most-recent turns kept verbatim in the rolling model context; older turns are
92
+ * pruned. Required, and required *of the Recipe*: how much context a domain
93
+ * needs is a property of the domain, so there is no house default to fall back
94
+ * to and a missing one is a refused Recipe.
95
+ */
96
+ historyWindow: number;
97
+ /** Append a runtime metrics footer (turns, model calls, wall-clock) to the final result. */
98
+ reportMetrics: boolean;
99
+ }
100
+ /**
101
+ * A Recipe that has been through {@link file://./validation.ts validateRecipe} —
102
+ * limits merged over the baseline, models and tool families checked. The only
103
+ * shape the runner ever consumes: a `Partial<RecipeLimits>` can never reach it.
104
+ */
105
+ export interface ValidatedRecipe extends ResolvedRecipe {
106
+ limits: RecipeLimits;
107
+ }
108
+ /**
109
+ * One entry in the closed set of Subtask types the main agent may delegate,
110
+ * declared by the domain that owns it and collected in
111
+ * {@link file://./index.ts}.
112
+ *
113
+ * Two things follow from the set being closed rather than free prose:
114
+ *
115
+ * - The delegating model picks from an enum, so an invented type is rejected by
116
+ * the tool schema itself instead of silently falling back to a general recipe.
117
+ * - A type can *require params*. `arc-game` cannot be attempted without a
118
+ * scorecard and a game, so a subtask that names neither is refused up front
119
+ * rather than discovering it has nothing to play several turns later.
120
+ *
121
+ * Params are the model's declared inputs — ids it chose, validated for shape and
122
+ * resolved against durable rows at execution start. They are never the place for
123
+ * anything the model cannot know: an API session pinned to one of those ids is
124
+ * resolved by the parent from the id, never carried in the params.
125
+ */
126
+ export interface SubtaskTypeSpec {
127
+ key: string;
128
+ /** One line shown to the delegating model so it picks the right type. */
129
+ description: string;
130
+ /**
131
+ * Required params for this type, or null when it takes none. Kept to flat
132
+ * strings: these are ids the model quotes from a tool result, not structures.
133
+ *
134
+ * A `z.object`, not an opaque `z.ZodType`, and that is load-bearing: the agent
135
+ * reads `.shape` back to build the `params` field of the delegate tool's schema
136
+ * (see `subtaskParamProperties`). Declaring a param the model is never shown is
137
+ * the failure this shape exists to prevent — describe each key with
138
+ * `.describe()`, because that text is what the model reads.
139
+ */
140
+ params: SubtaskParamsSchema | null;
141
+ /** How the model is told to obtain each param, appended to the description. */
142
+ paramsHelp?: string;
143
+ /**
144
+ * What the main agent is told it can *do* with this domain, rendered into its
145
+ * soul alongside the other capability blocks. Omit when the type needs no
146
+ * introduction beyond {@link description}.
147
+ *
148
+ * These two prompt fields exist to hold one rule: **everything the main agent
149
+ * is told about a domain is declared here, never written inside the runtime.**
150
+ * Both of them started as hand-written blocks in `agent/prompt.ts` and
151
+ * `agent/turn.ts`; the main agent read the same advice twice per round from two
152
+ * files that had already drifted into contradicting each other on how many
153
+ * subtasks a multi-game request gets.
154
+ */
155
+ capability?: string;
156
+ /**
157
+ * How to construct a `delegate` payload for this type, rendered into the round
158
+ * contract the main agent reads every round.
159
+ *
160
+ * A function because the text names the control tools, whose names belong to
161
+ * the agent (see {@link DelegationNames}). Three rules, none of them enforced
162
+ * beyond a test: it must open with its own `## ` heading, it must not restate
163
+ * the params schema — the `delegate` tool description already renders that from
164
+ * {@link params} — and it must stay short, because every round pays for it.
165
+ */
166
+ delegationGuidance?: (names: DelegationNames) => string;
167
+ /** The execution configuration this type runs under. */
168
+ recipe: ResolvedRecipe;
169
+ }
170
+ //# sourceMappingURL=recipe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipe.d.ts","sourceRoot":"","sources":["../../src/contract/recipe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AAEH,+EAA+E;AAC/E,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AACnE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;AAElE;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;GAaG;AACH;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC;AAEvC;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9B;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,4FAA4F;IAC5F,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,MAAM,EAAE,YAAY,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;;OASG;IACH,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACnC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,MAAM,CAAC;IACxD,wDAAwD;IACxD,MAAM,EAAE,cAAc,CAAC;CACxB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=recipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipe.js","sourceRoot":"","sources":["../../src/contract/recipe.ts"],"names":[],"mappings":""}
@@ -0,0 +1,86 @@
1
+ import type { AgentLimits } from "../config.js";
2
+ import type { ResolvedRecipe, ValidatedRecipe } from "./recipe.js";
3
+ /**
4
+ * The capability boundary every recipe passes through, whatever declared it.
5
+ *
6
+ * This module imports no domain. It owns only what code must be able to say
7
+ * about *any* recipe: which models and tool families it may select, and how a
8
+ * malformed one is made safe or refused. A domain cannot widen its
9
+ * *capabilities* by declaring them, because the allowlists do not come from the
10
+ * declaration — they come from {@link RecipePolicy}, which the host builds from
11
+ * its resolved config and its installed plugins. Its budget is the deliberate
12
+ * exception; see {@link resolveLimits}.
13
+ *
14
+ * In the predecessor repo the two allowlists were module constants, and one of
15
+ * them hardcoded a domain key (`"arc-game"`) inside otherwise generic code. That
16
+ * is the coupling this indirection removes: the set of legal families is now
17
+ * exactly the set of families the installed plugins registered.
18
+ */
19
+ export interface RecipePolicy {
20
+ /**
21
+ * Model ids a recipe may select — normally the two configured chat models, the
22
+ * only ones proven with this tool-loop pipeline. Extend deliberately, one
23
+ * validated model at a time.
24
+ */
25
+ modelAllowlist: ReadonlySet<string>;
26
+ /** Substituted when a recipe names a primary model outside the allowlist. */
27
+ defaultPrimaryModelId: string;
28
+ /** Substituted when a recipe names a fallback model outside the allowlist. */
29
+ defaultFallbackModelId: string;
30
+ /**
31
+ * Tool-family keys the runtime recognizes — derived from the installed
32
+ * plugins, never hardcoded.
33
+ *
34
+ * `recall` and the Session's `set_context` are never valid families: a
35
+ * subagent has no Session or durable memory to reach, and their absence from
36
+ * any plugin's `toolFamilies` makes them structurally impossible to enable
37
+ * through recipe data.
38
+ */
39
+ knownToolFamilies: ReadonlySet<string>;
40
+ /** The baseline a recipe's declared `limits` merge over. */
41
+ baselineLimits: AgentLimits;
42
+ }
43
+ /**
44
+ * Merge a recipe's declared budget over the baseline, per field. A positive
45
+ * integer wins; anything else — missing, null, zero, fractional — falls back to
46
+ * the baseline rather than reaching the runner.
47
+ *
48
+ * The baseline is a default, not a ceiling: a recipe may declare a budget larger
49
+ * than the baseline and it is honored — sizing its own branch is what declaring
50
+ * `limits` is for, so nothing here clamps. What the merge buys, as
51
+ * defense-in-depth for a recipe that ever comes from data rather than code, is
52
+ * that a corrupt or absent value cannot reach the runner as a zero, fractional,
53
+ * or missing budget.
54
+ *
55
+ * Exported separately from {@link validateRecipe} because it must never throw.
56
+ */
57
+ export declare function resolveLimits(limits: Partial<AgentLimits>, baseline: AgentLimits): AgentLimits;
58
+ /**
59
+ * Thrown by {@link validateRecipe} for a recipe that is unusable as given — it
60
+ * is disabled, carries no soul, or states no history window. All are
61
+ * deterministic caller bugs (the parent must only hand enabled, complete recipes
62
+ * to a subagent), so the child maps this to a terminal failed result rather than
63
+ * retrying.
64
+ */
65
+ export declare class RecipeValidationError extends Error {
66
+ constructor(message: string);
67
+ }
68
+ /**
69
+ * Code-owned defensive validation of an already-resolved recipe. Returns a
70
+ * normalized copy (never mutates the input): a model id outside the policy's
71
+ * allowlist is substituted with the default for its slot — independently per
72
+ * slot — and unknown tool families are dropped (deduped, order-preserving).
73
+ * Applied by the parent when it resolves a recipe and re-applied by the subagent
74
+ * on its inbound request, so recipe data can never select arbitrary models or
75
+ * tools.
76
+ *
77
+ * The split between what is normalized and what is refused follows one rule:
78
+ * **the host declares a baseline ⇒ merge; it does not ⇒ require.** `limits`
79
+ * merge. A soul and a `historyWindow` do not: substituting a generic soul would
80
+ * run the work under an identity nobody declared — the model would answer,
81
+ * plausibly, as something other than what the recipe is for — and how much
82
+ * context a domain needs is likewise a property of the domain, not something a
83
+ * house default can guess. Both fail the recipe outright.
84
+ */
85
+ export declare function validateRecipe(recipe: ResolvedRecipe, policy: RecipePolicy): ValidatedRecipe;
86
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/contract/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,6EAA6E;IAC7E,qBAAqB,EAAE,MAAM,CAAC;IAC9B,8EAA8E;IAC9E,sBAAsB,EAAE,MAAM,CAAC;IAC/B;;;;;;;;OAQG;IACH,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACvC,4DAA4D;IAC5D,cAAc,EAAE,WAAW,CAAC;CAC7B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,EAC5B,QAAQ,EAAE,WAAW,GACpB,WAAW,CAOb;AAED;;;;;;GAMG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,YAAY,GACnB,eAAe,CA+BjB"}