@loopingai/core 0.5.0 → 0.6.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 (304) hide show
  1. package/README.md +6 -4
  2. package/dist/a2a/agent-stub.d.ts +0 -1
  3. package/dist/a2a/agent-stub.js +0 -1
  4. package/dist/a2a/caller.d.ts +0 -1
  5. package/dist/a2a/caller.js +0 -1
  6. package/dist/a2a/card.d.ts +0 -1
  7. package/dist/a2a/card.js +0 -1
  8. package/dist/a2a/context.d.ts +0 -1
  9. package/dist/a2a/context.js +0 -1
  10. package/dist/a2a/executor.d.ts +0 -1
  11. package/dist/a2a/executor.js +0 -1
  12. package/dist/a2a/index.d.ts +0 -1
  13. package/dist/a2a/index.js +0 -1
  14. package/dist/a2a/notify.d.ts +4 -4
  15. package/dist/a2a/notify.js +4 -4
  16. package/dist/a2a/parts.d.ts +0 -1
  17. package/dist/a2a/parts.js +0 -1
  18. package/dist/a2a/push.d.ts +0 -1
  19. package/dist/a2a/push.js +0 -1
  20. package/dist/a2a/task-store.d.ts +0 -1
  21. package/dist/a2a/task-store.js +0 -1
  22. package/dist/a2a/task.d.ts +0 -1
  23. package/dist/a2a/task.js +0 -1
  24. package/dist/a2a/verify.d.ts +0 -1
  25. package/dist/a2a/verify.js +0 -1
  26. package/dist/agent/anthropic/index.d.ts +15 -0
  27. package/dist/agent/anthropic/index.js +19 -0
  28. package/dist/agent/anthropic/language-model.d.ts +59 -0
  29. package/dist/agent/anthropic/language-model.js +442 -0
  30. package/dist/agent/anthropic/prompt.d.ts +84 -0
  31. package/dist/agent/anthropic/prompt.js +541 -0
  32. package/dist/agent/anthropic/runtime.d.ts +79 -0
  33. package/dist/agent/anthropic/runtime.js +130 -0
  34. package/dist/agent/budget.d.ts +0 -1
  35. package/dist/agent/budget.js +0 -1
  36. package/dist/agent/control.d.ts +0 -1
  37. package/dist/agent/control.js +10 -10
  38. package/dist/agent/errors.d.ts +85 -0
  39. package/dist/agent/errors.js +64 -0
  40. package/dist/agent/final-reply.d.ts +14 -14
  41. package/dist/agent/final-reply.js +28 -12
  42. package/dist/agent/history.d.ts +3 -4
  43. package/dist/agent/history.js +2 -3
  44. package/dist/agent/index.d.ts +4 -3
  45. package/dist/agent/index.js +4 -3
  46. package/dist/agent/inference.d.ts +58 -2
  47. package/dist/agent/inference.js +44 -1
  48. package/dist/agent/model.d.ts +42 -26
  49. package/dist/agent/model.js +1 -49
  50. package/dist/agent/session.d.ts +6 -8
  51. package/dist/agent/session.js +3 -4
  52. package/dist/agent/workers-ai/index.d.ts +23 -0
  53. package/dist/agent/workers-ai/index.js +23 -0
  54. package/dist/agent/workers-ai/runtime.d.ts +42 -0
  55. package/dist/agent/workers-ai/runtime.js +63 -0
  56. package/dist/config.d.ts +49 -16
  57. package/dist/config.js +30 -2
  58. package/dist/contract/index.d.ts +0 -1
  59. package/dist/contract/index.js +0 -1
  60. package/dist/contract/plugin.d.ts +63 -4
  61. package/dist/contract/plugin.js +76 -1
  62. package/dist/contract/recipe.d.ts +16 -18
  63. package/dist/contract/recipe.js +0 -1
  64. package/dist/contract/validation.d.ts +0 -1
  65. package/dist/contract/validation.js +0 -1
  66. package/dist/db/db.d.ts +0 -2
  67. package/dist/db/db.js +0 -1
  68. package/dist/db/index.d.ts +0 -1
  69. package/dist/db/index.js +0 -1
  70. package/dist/db/migrations/index.d.ts +0 -1
  71. package/dist/db/migrations/index.js +8 -2
  72. package/dist/db/models/subtasks.d.ts +24 -26
  73. package/dist/db/models/subtasks.js +33 -77
  74. package/dist/db/models/tasks.d.ts +0 -1
  75. package/dist/db/models/tasks.js +0 -1
  76. package/dist/db/schema.d.ts +2 -22
  77. package/dist/db/schema.js +2 -5
  78. package/dist/env.d.ts +0 -1
  79. package/dist/env.js +0 -1
  80. package/dist/host/agent.d.ts +58 -5
  81. package/dist/host/agent.js +63 -10
  82. package/dist/host/index.d.ts +0 -1
  83. package/dist/host/index.js +0 -1
  84. package/dist/host/plugin-host.d.ts +0 -1
  85. package/dist/host/plugin-host.js +0 -1
  86. package/dist/index.d.ts +2 -3
  87. package/dist/index.js +2 -3
  88. package/dist/platform.d.ts +74 -12
  89. package/dist/platform.js +76 -14
  90. package/dist/round/agent.d.ts +36 -32
  91. package/dist/round/agent.js +61 -90
  92. package/dist/round/index.d.ts +3 -3
  93. package/dist/round/index.js +2 -3
  94. package/dist/round/policy.d.ts +2 -3
  95. package/dist/round/policy.js +0 -1
  96. package/dist/round/subagent.d.ts +19 -2
  97. package/dist/round/subagent.js +22 -6
  98. package/dist/round/turn.d.ts +32 -14
  99. package/dist/round/turn.js +83 -17
  100. package/dist/round/workflow.d.ts +30 -9
  101. package/dist/round/workflow.js +146 -78
  102. package/dist/runtime/index.d.ts +4 -3
  103. package/dist/runtime/index.js +6 -1
  104. package/dist/runtime/tool-families.d.ts +0 -1
  105. package/dist/runtime/tool-families.js +0 -1
  106. package/dist/subagent/fingerprint.d.ts +2 -3
  107. package/dist/subagent/fingerprint.js +8 -18
  108. package/dist/subagent/index.d.ts +6 -5
  109. package/dist/subagent/index.js +8 -7
  110. package/dist/subagent/prompt.d.ts +4 -6
  111. package/dist/subagent/prompt.js +0 -9
  112. package/dist/subagent/run.d.ts +8 -2
  113. package/dist/subagent/run.js +59 -10
  114. package/dist/subagent/workspace.d.ts +0 -1
  115. package/dist/subagent/workspace.js +0 -1
  116. package/dist/subtasks/catalog.d.ts +1 -2
  117. package/dist/subtasks/catalog.js +1 -2
  118. package/dist/subtasks/decomposition.d.ts +16 -21
  119. package/dist/subtasks/decomposition.js +27 -76
  120. package/dist/subtasks/delegate.d.ts +20 -2
  121. package/dist/subtasks/delegate.js +21 -17
  122. package/dist/subtasks/index.d.ts +1 -3
  123. package/dist/subtasks/index.js +1 -3
  124. package/dist/subtasks/subtask-types.d.ts +0 -9
  125. package/dist/subtasks/subtask-types.js +0 -8
  126. package/dist/subtasks/types.d.ts +45 -71
  127. package/dist/subtasks/types.js +0 -1
  128. package/dist/testing/auth.d.ts +0 -1
  129. package/dist/testing/auth.js +0 -1
  130. package/dist/testing/do.d.ts +0 -1
  131. package/dist/testing/do.js +0 -1
  132. package/dist/testing/fake-session.d.ts +0 -1
  133. package/dist/testing/fake-session.js +0 -1
  134. package/dist/testing/fixtures.d.ts +0 -1
  135. package/dist/testing/fixtures.js +0 -1
  136. package/dist/testing/harness.d.ts +0 -1
  137. package/dist/testing/harness.js +0 -1
  138. package/dist/testing/index.d.ts +0 -1
  139. package/dist/testing/index.js +0 -1
  140. package/dist/testing/mock-model.d.ts +35 -1
  141. package/dist/testing/mock-model.js +75 -1
  142. package/dist/testing/node.d.ts +0 -1
  143. package/dist/testing/node.js +0 -1
  144. package/dist/testing/vcr-global-setup.d.ts +1 -4
  145. package/dist/testing/vcr-global-setup.js +1 -4
  146. package/dist/testing/vcr-shared.d.ts +0 -1
  147. package/dist/testing/vcr-shared.js +0 -1
  148. package/dist/testing/vcr-spec.d.ts +0 -1
  149. package/dist/testing/vcr-spec.js +0 -1
  150. package/dist/testing/vcr-store.d.ts +0 -1
  151. package/dist/testing/vcr-store.js +0 -1
  152. package/dist/testing/vcr.d.ts +0 -1
  153. package/dist/testing/vcr.js +0 -1
  154. package/dist/worker/define-agent.d.ts +0 -1
  155. package/dist/worker/define-agent.js +0 -1
  156. package/dist/worker/index.d.ts +5 -13
  157. package/dist/worker/index.js +5 -13
  158. package/package.json +20 -2
  159. package/dist/a2a/agent-stub.d.ts.map +0 -1
  160. package/dist/a2a/agent-stub.js.map +0 -1
  161. package/dist/a2a/caller.d.ts.map +0 -1
  162. package/dist/a2a/caller.js.map +0 -1
  163. package/dist/a2a/card.d.ts.map +0 -1
  164. package/dist/a2a/card.js.map +0 -1
  165. package/dist/a2a/context.d.ts.map +0 -1
  166. package/dist/a2a/context.js.map +0 -1
  167. package/dist/a2a/executor.d.ts.map +0 -1
  168. package/dist/a2a/executor.js.map +0 -1
  169. package/dist/a2a/index.d.ts.map +0 -1
  170. package/dist/a2a/index.js.map +0 -1
  171. package/dist/a2a/notify.d.ts.map +0 -1
  172. package/dist/a2a/notify.js.map +0 -1
  173. package/dist/a2a/parts.d.ts.map +0 -1
  174. package/dist/a2a/parts.js.map +0 -1
  175. package/dist/a2a/push.d.ts.map +0 -1
  176. package/dist/a2a/push.js.map +0 -1
  177. package/dist/a2a/task-store.d.ts.map +0 -1
  178. package/dist/a2a/task-store.js.map +0 -1
  179. package/dist/a2a/task.d.ts.map +0 -1
  180. package/dist/a2a/task.js.map +0 -1
  181. package/dist/a2a/verify.d.ts.map +0 -1
  182. package/dist/a2a/verify.js.map +0 -1
  183. package/dist/agent/budget.d.ts.map +0 -1
  184. package/dist/agent/budget.js.map +0 -1
  185. package/dist/agent/control.d.ts.map +0 -1
  186. package/dist/agent/control.js.map +0 -1
  187. package/dist/agent/final-reply.d.ts.map +0 -1
  188. package/dist/agent/final-reply.js.map +0 -1
  189. package/dist/agent/history.d.ts.map +0 -1
  190. package/dist/agent/history.js.map +0 -1
  191. package/dist/agent/index.d.ts.map +0 -1
  192. package/dist/agent/index.js.map +0 -1
  193. package/dist/agent/inference.d.ts.map +0 -1
  194. package/dist/agent/inference.js.map +0 -1
  195. package/dist/agent/model.d.ts.map +0 -1
  196. package/dist/agent/model.js.map +0 -1
  197. package/dist/agent/session.d.ts.map +0 -1
  198. package/dist/agent/session.js.map +0 -1
  199. package/dist/config.d.ts.map +0 -1
  200. package/dist/config.js.map +0 -1
  201. package/dist/contract/index.d.ts.map +0 -1
  202. package/dist/contract/index.js.map +0 -1
  203. package/dist/contract/plugin.d.ts.map +0 -1
  204. package/dist/contract/plugin.js.map +0 -1
  205. package/dist/contract/recipe.d.ts.map +0 -1
  206. package/dist/contract/recipe.js.map +0 -1
  207. package/dist/contract/validation.d.ts.map +0 -1
  208. package/dist/contract/validation.js.map +0 -1
  209. package/dist/db/db.d.ts.map +0 -1
  210. package/dist/db/db.js.map +0 -1
  211. package/dist/db/index.d.ts.map +0 -1
  212. package/dist/db/index.js.map +0 -1
  213. package/dist/db/migrations/index.d.ts.map +0 -1
  214. package/dist/db/migrations/index.js.map +0 -1
  215. package/dist/db/models/subtasks.d.ts.map +0 -1
  216. package/dist/db/models/subtasks.js.map +0 -1
  217. package/dist/db/models/tasks.d.ts.map +0 -1
  218. package/dist/db/models/tasks.js.map +0 -1
  219. package/dist/db/schema.d.ts.map +0 -1
  220. package/dist/db/schema.js.map +0 -1
  221. package/dist/env.d.ts.map +0 -1
  222. package/dist/env.js.map +0 -1
  223. package/dist/host/agent.d.ts.map +0 -1
  224. package/dist/host/agent.js.map +0 -1
  225. package/dist/host/index.d.ts.map +0 -1
  226. package/dist/host/index.js.map +0 -1
  227. package/dist/host/plugin-host.d.ts.map +0 -1
  228. package/dist/host/plugin-host.js.map +0 -1
  229. package/dist/index.d.ts.map +0 -1
  230. package/dist/index.js.map +0 -1
  231. package/dist/platform.d.ts.map +0 -1
  232. package/dist/platform.js.map +0 -1
  233. package/dist/round/agent.d.ts.map +0 -1
  234. package/dist/round/agent.js.map +0 -1
  235. package/dist/round/index.d.ts.map +0 -1
  236. package/dist/round/index.js.map +0 -1
  237. package/dist/round/policy.d.ts.map +0 -1
  238. package/dist/round/policy.js.map +0 -1
  239. package/dist/round/subagent.d.ts.map +0 -1
  240. package/dist/round/subagent.js.map +0 -1
  241. package/dist/round/turn.d.ts.map +0 -1
  242. package/dist/round/turn.js.map +0 -1
  243. package/dist/round/workflow.d.ts.map +0 -1
  244. package/dist/round/workflow.js.map +0 -1
  245. package/dist/runtime/index.d.ts.map +0 -1
  246. package/dist/runtime/index.js.map +0 -1
  247. package/dist/runtime/tool-families.d.ts.map +0 -1
  248. package/dist/runtime/tool-families.js.map +0 -1
  249. package/dist/subagent/fingerprint.d.ts.map +0 -1
  250. package/dist/subagent/fingerprint.js.map +0 -1
  251. package/dist/subagent/index.d.ts.map +0 -1
  252. package/dist/subagent/index.js.map +0 -1
  253. package/dist/subagent/prompt.d.ts.map +0 -1
  254. package/dist/subagent/prompt.js.map +0 -1
  255. package/dist/subagent/run.d.ts.map +0 -1
  256. package/dist/subagent/run.js.map +0 -1
  257. package/dist/subagent/workspace.d.ts.map +0 -1
  258. package/dist/subagent/workspace.js.map +0 -1
  259. package/dist/subtasks/catalog.d.ts.map +0 -1
  260. package/dist/subtasks/catalog.js.map +0 -1
  261. package/dist/subtasks/decomposition.d.ts.map +0 -1
  262. package/dist/subtasks/decomposition.js.map +0 -1
  263. package/dist/subtasks/delegate.d.ts.map +0 -1
  264. package/dist/subtasks/delegate.js.map +0 -1
  265. package/dist/subtasks/index.d.ts.map +0 -1
  266. package/dist/subtasks/index.js.map +0 -1
  267. package/dist/subtasks/scheduler.d.ts +0 -49
  268. package/dist/subtasks/scheduler.d.ts.map +0 -1
  269. package/dist/subtasks/scheduler.js +0 -48
  270. package/dist/subtasks/scheduler.js.map +0 -1
  271. package/dist/subtasks/subtask-types.d.ts.map +0 -1
  272. package/dist/subtasks/subtask-types.js.map +0 -1
  273. package/dist/subtasks/types.d.ts.map +0 -1
  274. package/dist/subtasks/types.js.map +0 -1
  275. package/dist/testing/auth.d.ts.map +0 -1
  276. package/dist/testing/auth.js.map +0 -1
  277. package/dist/testing/do.d.ts.map +0 -1
  278. package/dist/testing/do.js.map +0 -1
  279. package/dist/testing/fake-session.d.ts.map +0 -1
  280. package/dist/testing/fake-session.js.map +0 -1
  281. package/dist/testing/fixtures.d.ts.map +0 -1
  282. package/dist/testing/fixtures.js.map +0 -1
  283. package/dist/testing/harness.d.ts.map +0 -1
  284. package/dist/testing/harness.js.map +0 -1
  285. package/dist/testing/index.d.ts.map +0 -1
  286. package/dist/testing/index.js.map +0 -1
  287. package/dist/testing/mock-model.d.ts.map +0 -1
  288. package/dist/testing/mock-model.js.map +0 -1
  289. package/dist/testing/node.d.ts.map +0 -1
  290. package/dist/testing/node.js.map +0 -1
  291. package/dist/testing/vcr-global-setup.d.ts.map +0 -1
  292. package/dist/testing/vcr-global-setup.js.map +0 -1
  293. package/dist/testing/vcr-shared.d.ts.map +0 -1
  294. package/dist/testing/vcr-shared.js.map +0 -1
  295. package/dist/testing/vcr-spec.d.ts.map +0 -1
  296. package/dist/testing/vcr-spec.js.map +0 -1
  297. package/dist/testing/vcr-store.d.ts.map +0 -1
  298. package/dist/testing/vcr-store.js.map +0 -1
  299. package/dist/testing/vcr.d.ts.map +0 -1
  300. package/dist/testing/vcr.js.map +0 -1
  301. package/dist/worker/define-agent.d.ts.map +0 -1
  302. package/dist/worker/define-agent.js.map +0 -1
  303. package/dist/worker/index.d.ts.map +0 -1
  304. package/dist/worker/index.js.map +0 -1
@@ -10,8 +10,8 @@ export const FINGERPRINT_VERSION = 1;
10
10
  * Canonical JSON of the fields that define an execution's identity, rebuilt as
11
11
  * literals in fixed key order so `JSON.stringify` is deterministic (object
12
12
  * insertion order). Array order is semantic and preserved: the parent builds
13
- * references and dependency results from ordinal-ordered rows, so a retry of the
14
- * same execution is byte-identical.
13
+ * references from ordinal-ordered rows, so a retry of the same execution is
14
+ * byte-identical.
15
15
  *
16
16
  * **Limits are canonicalized as *declared*, not as merged.** The predecessor
17
17
  * merged them against the house baseline first, on the reasoning that `{}` and
@@ -36,13 +36,12 @@ export function canonicalRequest(request) {
36
36
  recipe: {
37
37
  key: request.recipe.key,
38
38
  version: request.recipe.version,
39
- // No model ids. They used to be hashed because a recipe declared them;
40
- // it no longer can, and their absence here is the same trade this file
41
- // already makes for `limits`: the host's own configuration stays out of
42
- // the fingerprint, so changing it does not invalidate every checkpoint at
43
- // once and restart every in-flight run from turn zero with its budget
44
- // already spent. A run that resumes on a newly configured model resumes
45
- // from conversation state, which is model-independent.
39
+ // No model ids. Their absence is the same trade this file already makes
40
+ // for `limits`: the host's own configuration stays out of the fingerprint,
41
+ // so changing it does not invalidate every checkpoint at once and restart
42
+ // every in-flight run from turn zero with its budget already spent. A run
43
+ // that resumes on a newly configured model resumes from conversation
44
+ // state, which is model-independent.
46
45
  soul: request.recipe.soul,
47
46
  toolFamilies: request.recipe.toolFamilies,
48
47
  enabled: request.recipe.enabled,
@@ -55,14 +54,6 @@ export function canonicalRequest(request) {
55
54
  role: ref.role,
56
55
  text: ref.text
57
56
  })),
58
- dependencyResults: request.dependencyResults.map((dep) => ({
59
- subtaskId: dep.subtaskId,
60
- type: dep.type,
61
- resultParts: dep.resultParts.map((part) => ({
62
- kind: part.kind,
63
- text: part.text
64
- }))
65
- })),
66
57
  // Params ARE identity: the same prompt against a different external resource
67
58
  // is different work, and must not replay a cached result. Key order is fixed
68
59
  // by sorting, so an equivalent params object always canonicalizes identically.
@@ -99,4 +90,3 @@ export async function fingerprintRequest(request) {
99
90
  .map((b) => b.toString(16).padStart(2, "0"))
100
91
  .join("");
101
92
  }
102
- //# sourceMappingURL=fingerprint.js.map
@@ -25,6 +25,8 @@ export interface SubagentRuntime {
25
25
  toolOutputWindow: number;
26
26
  /** `CoreConfig.model.maxOutputTokens`. */
27
27
  maxOutputTokens: number;
28
+ /** `CoreConfig.model.maxRetries`. */
29
+ maxRetries: number;
28
30
  /**
29
31
  * Build the durable file store over this facet's own SQLite.
30
32
  *
@@ -43,14 +45,14 @@ export interface SubagentRuntime {
43
45
  * execution — and a Workflow retry after the parent's cleanup will succeed.
44
46
  */
45
47
  export declare const FINGERPRINT_MISMATCH = "recipe-subagent: request fingerprint mismatch";
46
- /** Deterministic managed-child name for one Subtask execution (shared with C3). */
48
+ /** Deterministic managed-child name for one Subtask execution. */
47
49
  export declare function subagentName(taskId: string, subtaskId: SubtaskId): string;
48
50
  /**
49
51
  * `RecipeSubagent` — the isolated, stateless managed child that executes one
50
52
  * Subtask under a resolved Recipe. Created as an Agents SDK sub-agent (facet)
51
- * beneath the caller's `ReactiveAgent`, so it needs no wrangler Durable Object
52
- * binding and no `new_sqlite_classes` entry; it must only be exported from the
53
- * worker entry (`src/index.ts`) so `ctx.exports` can resolve it by class name.
53
+ * beneath the calling agent, so it needs no wrangler Durable Object binding and
54
+ * no `new_sqlite_classes` entry; it must only be exported from the consuming
55
+ * Worker's entry so `ctx.exports` can resolve it by class name.
54
56
  *
55
57
  * It never constructs a Session, never reads parent history beyond the
56
58
  * references supplied on its request, never reaches durable memory, and never
@@ -144,4 +146,3 @@ export declare abstract class RecipeSubagentBase<TEnv extends Cloudflare.Env = C
144
146
  /** Persist the rolling run state (called after every model turn). */
145
147
  private saveRunState;
146
148
  }
147
- //# sourceMappingURL=index.d.ts.map
@@ -16,7 +16,7 @@ import { runResumableChunk } from "./run.js";
16
16
  * execution — and a Workflow retry after the parent's cleanup will succeed.
17
17
  */
18
18
  export const FINGERPRINT_MISMATCH = "recipe-subagent: request fingerprint mismatch";
19
- /** Deterministic managed-child name for one Subtask execution (shared with C3). */
19
+ /** Deterministic managed-child name for one Subtask execution. */
20
20
  export function subagentName(taskId, subtaskId) {
21
21
  return `subtask:${taskId}:${subtaskId}`;
22
22
  }
@@ -38,9 +38,9 @@ const cachedResultSchema = z.discriminatedUnion("status", [
38
38
  /**
39
39
  * `RecipeSubagent` — the isolated, stateless managed child that executes one
40
40
  * Subtask under a resolved Recipe. Created as an Agents SDK sub-agent (facet)
41
- * beneath the caller's `ReactiveAgent`, so it needs no wrangler Durable Object
42
- * binding and no `new_sqlite_classes` entry; it must only be exported from the
43
- * worker entry (`src/index.ts`) so `ctx.exports` can resolve it by class name.
41
+ * beneath the calling agent, so it needs no wrangler Durable Object binding and
42
+ * no `new_sqlite_classes` entry; it must only be exported from the consuming
43
+ * Worker's entry so `ctx.exports` can resolve it by class name.
44
44
  *
45
45
  * It never constructs a Session, never reads parent history beyond the
46
46
  * references supplied on its request, never reaches durable memory, and never
@@ -158,8 +158,9 @@ export class RecipeSubagentBase extends Agent {
158
158
  });
159
159
  }
160
160
  // Re-check the type's param contract, the same defensive posture as
161
- // `validateRecipe`: a play with no scorecard cannot succeed, and failing
162
- // here costs no model call and gives the parent a real diagnostic.
161
+ // `validateRecipe`: a subtask missing a param its type requires cannot
162
+ // succeed, and failing here costs no model call and gives the parent a real
163
+ // diagnostic.
163
164
  try {
164
165
  rt.types.validateParams(request.type, request.params);
165
166
  }
@@ -213,6 +214,7 @@ export class RecipeSubagentBase extends Agent {
213
214
  toolOutputWindow: rt.toolOutputWindow,
214
215
  reportMetrics: recipe.reportMetrics,
215
216
  maxOutputTokens: rt.maxOutputTokens,
217
+ maxRetries: rt.maxRetries,
216
218
  now: () => Date.now(),
217
219
  progress,
218
220
  checkpoint: (s) => this.saveRunState(fingerprint, s),
@@ -296,4 +298,3 @@ function mismatch(phase) {
296
298
  "different request; the parent must delete a stale child before starting a " +
297
299
  "genuinely new execution");
298
300
  }
299
- //# sourceMappingURL=index.js.map
@@ -2,11 +2,10 @@ import type { RecipeExecutionRequest } from "../subtasks/types.js";
2
2
  import type { ValidatedRecipe } from "../contract/recipe.js";
3
3
  /**
4
4
  * Deterministic rendering of one subagent invocation. Pure — no model, no
5
- * Session, no lookups: everything comes verbatim from the request. The four
5
+ * Session, no lookups: everything comes verbatim from the request. The three
6
6
  * sections stay clearly separated and labeled so tests (and the model) can tell
7
- * them apart: the execution's budget, the main-agent instruction, the verbatim
8
- * conversation reference snapshots, and generated dependency output — which is
9
- * explicitly marked as generated and never presented as conversation evidence.
7
+ * them apart: the execution's budget, the main-agent instruction, and the
8
+ * verbatim conversation reference snapshots.
10
9
  */
11
10
  /**
12
11
  * A request whose Recipe has been through `validateRecipe`, so its limits are
@@ -21,7 +20,7 @@ export type RenderableExecution = RecipeExecutionRequest & {
21
20
  export interface RenderedInvocation {
22
21
  /** The validated Recipe soul, verbatim — the invocation's system prompt. */
23
22
  system: string;
24
- /** The sectioned user message (instruction, references, dependency results). */
23
+ /** The sectioned user message (budget, instruction, references). */
25
24
  prompt: string;
26
25
  }
27
26
  /**
@@ -31,4 +30,3 @@ export interface RenderedInvocation {
31
30
  * content are omitted entirely.
32
31
  */
33
32
  export declare function renderSubagentPrompt(request: RenderableExecution): RenderedInvocation;
34
- //# sourceMappingURL=prompt.d.ts.map
@@ -33,14 +33,5 @@ export function renderSubagentPrompt(request) {
33
33
  sections.push("# Conversation references (verbatim snapshots of the caller's conversation)\n" +
34
34
  refs.join("\n"));
35
35
  }
36
- if (request.dependencyResults.length > 0) {
37
- const deps = request.dependencyResults.map((dep) => {
38
- const text = dep.resultParts.map((part) => part.text).join("\n");
39
- return `[dependency ${dep.subtaskId}] (${dep.type}): ${text}`;
40
- });
41
- sections.push("# Dependency results (generated output from prerequisite subtasks — not conversation evidence)\n" +
42
- deps.join("\n"));
43
- }
44
36
  return { system: request.recipe.soul, prompt: sections.join("\n\n") };
45
37
  }
46
- //# sourceMappingURL=prompt.js.map
@@ -48,7 +48,7 @@ export interface ChunkRunDeps {
48
48
  /**
49
49
  * How many of the most recent assistant turns keep their tool results in full;
50
50
  * older ones are stubbed by {@link elideToolOutputs}. A mechanic of the window
51
- * rather than a property of a domain — see `TOOL_OUTPUT_WINDOW` in `config.ts`.
51
+ * rather than a property of a domain — see `CoreConfig.toolOutputWindow`.
52
52
  */
53
53
  toolOutputWindow: number;
54
54
  reportMetrics: boolean;
@@ -58,6 +58,11 @@ export interface ChunkRunDeps {
58
58
  * hardcoded one.
59
59
  */
60
60
  maxOutputTokens: number;
61
+ /**
62
+ * `CoreConfig.model.maxRetries` — retries on *this* model, honouring the
63
+ * provider's `retry-after`, before the slot hands over to the fallback.
64
+ */
65
+ maxRetries: number;
61
66
  now: () => number;
62
67
  /** Shared sink the tool families push progress events into (fresh per chunk). */
63
68
  progress: ProgressEvent[];
@@ -137,6 +142,8 @@ export interface RecipeRunDeps {
137
142
  toolOutputWindow: number;
138
143
  /** `CoreConfig.model.maxOutputTokens`. */
139
144
  maxOutputTokens: number;
145
+ /** `CoreConfig.model.maxRetries`. */
146
+ maxRetries: number;
140
147
  }
141
148
  /**
142
149
  * Run one recipe execution to a terminal result, driving {@link runResumableChunk}
@@ -148,4 +155,3 @@ export interface RecipeRunDeps {
148
155
  * Throws only on a transient platform fault (as {@link runResumableChunk} does).
149
156
  */
150
157
  export declare function runRecipeExecution(request: RecipeExecutionRequest, deps: RecipeRunDeps): Promise<RecipeExecutionResult>;
151
- //# sourceMappingURL=run.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { generateText, isStepCount } from "ai";
2
2
  import { CHUNK_SOFT_MS } from "../platform.js";
3
3
  import { stepAllowance } from "../agent/budget.js";
4
- import { isTransientAiError } from "../agent/inference.js";
4
+ import { isTransientAiError, nonRecoverableKind } from "../agent/inference.js";
5
5
  import { validateRecipe } from "../contract/validation.js";
6
6
  import { renderSubagentPrompt } from "./prompt.js";
7
7
  /**
@@ -200,6 +200,35 @@ function completed(state, deps, text, modelId) {
200
200
  state
201
201
  };
202
202
  }
203
+ /**
204
+ * Fail a chunk on an error no second attempt can clear.
205
+ *
206
+ * Terminal for this subtask, and deliberately *not* a throw: a throw is retried
207
+ * by the Workflow step, which is exactly the spend this classification exists to
208
+ * avoid. The parent round then hits the same condition on its own inference and
209
+ * fails carrying the kind, which is where an operator-facing message gets
210
+ * attached — a subagent has no channel of its own to say "a human must fix
211
+ * this", only this row's `error` string.
212
+ */
213
+ function nonRecoverableOutcome(state, deps, modelId, kind, diagnostic) {
214
+ console.error("[recipe-runner] non-recoverable model failure", {
215
+ model: modelId,
216
+ kind,
217
+ diagnostic
218
+ });
219
+ return {
220
+ outcome: {
221
+ done: true,
222
+ result: {
223
+ status: "failed",
224
+ error: `${kind}: ${diagnostic}`,
225
+ modelId
226
+ },
227
+ progress: deps.progress
228
+ },
229
+ state
230
+ };
231
+ }
203
232
  /**
204
233
  * Run one durable chunk. Returns a terminal result (natural completion, budget
205
234
  * exhaustion, or exhausted models) or a `done: false` yield with the progress
@@ -263,8 +292,11 @@ export async function runResumableChunk(prev, deps) {
263
292
  // The run-wide deadline. Without it the entry guard would only observe the
264
293
  // deadline at the next chunk boundary, up to `chunkSoftMs` past it.
265
294
  () => deps.now() - state.startedAtMs >= deps.limits.maxWallMs,
266
- // Not a budget: the platform's step timeout, which needs this chunk to
267
- // checkpoint and hand back a fresh step long before ~10 minutes.
295
+ // Not a budget: the configured step timeout, which needs this chunk to
296
+ // checkpoint and hand back a fresh step before it trips. Soft, and only
297
+ // checked here between turns — the turn already in flight when it trips still
298
+ // runs to completion, which is why `STEP_TIMEOUT_MS - CHUNK_SOFT_MS` is sized
299
+ // to cover a whole turn rather than a nominal moment. See `platform.ts`.
268
300
  () => deps.now() - chunkStartMs >= deps.chunkSoftMs,
269
301
  // Not a budget either: publish progress to the user promptly.
270
302
  () => deps.progress.length > 0
@@ -280,8 +312,9 @@ export async function runResumableChunk(prev, deps) {
280
312
  tools: deps.tools,
281
313
  stopWhen: boundaries(),
282
314
  maxOutputTokens: deps.maxOutputTokens,
283
- // Primary fallback recovery is manual; SDK backoff would only add latency.
284
- maxRetries: 0,
315
+ // Not a duplicate of the fallback: the fallback answers "this model
316
+ // cannot do it", and a 429 says "not yet". See `ModelConfig.maxRetries`.
317
+ maxRetries: deps.maxRetries,
285
318
  abortSignal: deps.abortSignal,
286
319
  onStepEnd
287
320
  });
@@ -298,9 +331,9 @@ export async function runResumableChunk(prev, deps) {
298
331
  return { kind: "aborted" };
299
332
  if (result.finishReason === "length") {
300
333
  // Its own warning, not just a diagnostic string: hitting the output ceiling
301
- // is a tuning signal about MAX_OUTPUT_TOKENS, distinct from the model
302
- // producing bad output, and the two are indistinguishable once folded into
303
- // the "recipe exhausted" message.
334
+ // is a tuning signal about `config.model.maxOutputTokens`, distinct from the
335
+ // model producing bad output, and the two are indistinguishable once folded
336
+ // into the "recipe exhausted" message.
304
337
  console.warn("[recipe-runner] model output truncated", {
305
338
  model: modelId,
306
339
  maxOutputTokens: deps.maxOutputTokens
@@ -325,6 +358,14 @@ export async function runResumableChunk(prev, deps) {
325
358
  if (a.kind === "aborted")
326
359
  return yielded();
327
360
  if (a.kind === "failed") {
361
+ // Checked before the fallback, not after: the second slot would present the
362
+ // same rejected credential. Returned rather than thrown — a throw here is
363
+ // retried by the Workflow step, which is the other cost this avoids. The
364
+ // chunk fails, and the parent's next round classifies it properly.
365
+ const blocked = nonRecoverableKind(a.error);
366
+ if (blocked) {
367
+ return nonRecoverableOutcome(state, deps, a.modelId, blocked, a.diagnostic);
368
+ }
328
369
  console.warn("[recipe-runner] primary attempt failed, trying fallback", {
329
370
  model: a.modelId,
330
371
  diagnostic: a.diagnostic
@@ -395,7 +436,9 @@ async function summarizeBudget(state, deps) {
395
436
  messages,
396
437
  stopWhen: isStepCount(1),
397
438
  maxOutputTokens: deps.maxOutputTokens,
398
- maxRetries: 0,
439
+ // Retries on this model, honouring `retry-after`, before the fallback.
440
+ // See `ModelConfig.maxRetries`.
441
+ maxRetries: deps.maxRetries,
399
442
  abortSignal: deps.abortSignal
400
443
  });
401
444
  }
@@ -421,6 +464,12 @@ async function summarizeBudget(state, deps) {
421
464
  if (a.kind === "aborted")
422
465
  return yielded();
423
466
  if (a.kind === "failed") {
467
+ // Same rule as the work loop: no fallback on a credential the API already
468
+ // rejected. A summary is the cheapest call in the run, but it is not free.
469
+ const blocked = nonRecoverableKind(a.error);
470
+ if (blocked) {
471
+ return nonRecoverableOutcome(state, deps, a.modelId, blocked, a.diagnostic);
472
+ }
424
473
  const primaryFailure = a;
425
474
  a = await summarize(deps.models.fallback, deps.models.fallbackId());
426
475
  if (a.kind === "aborted")
@@ -473,6 +522,7 @@ export async function runRecipeExecution(request, deps) {
473
522
  toolOutputWindow: deps.toolOutputWindow,
474
523
  reportMetrics: recipe.reportMetrics,
475
524
  maxOutputTokens: deps.maxOutputTokens,
525
+ maxRetries: deps.maxRetries,
476
526
  now,
477
527
  progress: [],
478
528
  checkpoint: () => { }
@@ -488,4 +538,3 @@ export async function runRecipeExecution(request, deps) {
488
538
  modelId: null
489
539
  };
490
540
  }
491
- //# sourceMappingURL=run.js.map
@@ -83,4 +83,3 @@ export declare class WorkspaceLimitError extends Error {
83
83
  * fill storage.
84
84
  */
85
85
  export declare function makeWorkspaceHandle(ws: WorkspaceBacking): WorkspaceHandle;
86
- //# sourceMappingURL=workspace.d.ts.map
@@ -125,4 +125,3 @@ export function makeWorkspaceHandle(ws) {
125
125
  }
126
126
  };
127
127
  }
128
- //# sourceMappingURL=workspace.js.map
@@ -20,7 +20,7 @@ export interface ReferenceCatalogEntry extends SubtaskReference {
20
20
  * reference.
21
21
  *
22
22
  * This is the single eligibility rule, and it has exactly one caller:
23
- * {@link file://../turn.ts renderTurnMessages} numbers the messages it accepts
23
+ * {@link file://../round/turn.ts renderTurnMessages} numbers the messages it accepts
24
24
  * *and* marks those same messages with their `[ref N]` index, in one pass. One
25
25
  * predicate, one walk — the marked messages and the catalog indices cannot drift.
26
26
  *
@@ -38,4 +38,3 @@ export interface ReferenceCatalogEntry extends SubtaskReference {
38
38
  * flight.
39
39
  */
40
40
  export declare function isCatalogEligible(message: SessionMessage): boolean;
41
- //# sourceMappingURL=catalog.d.ts.map
@@ -10,7 +10,7 @@ import { sessionText } from "../agent/history.js";
10
10
  * reference.
11
11
  *
12
12
  * This is the single eligibility rule, and it has exactly one caller:
13
- * {@link file://../turn.ts renderTurnMessages} numbers the messages it accepts
13
+ * {@link file://../round/turn.ts renderTurnMessages} numbers the messages it accepts
14
14
  * *and* marks those same messages with their `[ref N]` index, in one pass. One
15
15
  * predicate, one walk — the marked messages and the catalog indices cannot drift.
16
16
  *
@@ -34,4 +34,3 @@ export function isCatalogEligible(message) {
34
34
  return false;
35
35
  return sessionText(message).trim().length > 0;
36
36
  }
37
- //# sourceMappingURL=catalog.js.map
@@ -8,16 +8,15 @@ import type { DecompositionProposal, SubtaskDraft } from "./types.js";
8
8
  * reference catalog it was generated against, this either produces the drafts to
9
9
  * persist or throws.
10
10
  *
11
- * Two invariants live here:
11
+ * One invariant lives here: **the model selects references by index only.** It
12
+ * emits catalog indices; this module copies the catalog entry's exact role+text
13
+ * onto the draft. Model output never becomes reference text, so a Subtask cannot
14
+ * carry a rewritten, summarized, or fabricated "quote" of the conversation.
12
15
  *
13
- * - **The model selects references by index only.** It emits catalog indices; this
14
- * module copies the catalog entry's exact role+text onto the draft. Model output
15
- * never becomes reference text, so a Subtask cannot carry a rewritten,
16
- * summarized, or fabricated "quote" of the conversation.
17
- * - **The dependency graph is a validated DAG.** Unknown, duplicate,
18
- * self-referential, and cyclic edges are all rejected here. The data layer's
19
- * `createDecomposition` re-checks the cheap structural rules as a storage guard,
20
- * but full cycle detection is this module's job.
16
+ * A proposal's subtasks are **independent of one another**: they all run at once
17
+ * and none can read another's output, so there is no graph to validate and
18
+ * nothing to order. Sequencing is expressed across rounds instead — the main
19
+ * agent delegates, reads the results, and delegates the next step.
21
20
  *
22
21
  * Invalid output is never repaired: a throw fails the attempt, which falls back to
23
22
  * the other model, and two failed attempts fail the parent Task. Silently
@@ -39,12 +38,11 @@ export declare class DecompositionValidationError extends Error {
39
38
  * constraint reaches the model as part of the tool schema, on every field, with
40
39
  * no per-field `.describe()` needed to restate it.
41
40
  *
42
- * Being shown a rule is not the same as being held to it, and the difference used
43
- * to be a hole. This schema reaches the model through a **control** tool, which has
44
- * no `execute` — so the SDK's input validation never ran on it, and a blank value
45
- * the model was shown the pattern for sailed through anyway. What enforces it is
46
- * {@link file://../control.ts control.ts}, which parses every control call with its
47
- * own schema before the round uses it.
41
+ * Being shown a rule is not the same as being held to it. This schema reaches
42
+ * the model through a **control** tool, which has no `execute`, so the SDK never
43
+ * validates its input what enforces the constraint is
44
+ * {@link file://../agent/control.ts control.ts}, which parses every control call
45
+ * with the tool's own schema before the round uses it.
48
46
  */
49
47
  export declare const nonBlank: (label: string) => z.ZodString;
50
48
  /**
@@ -63,13 +61,11 @@ export declare const nonBlank: (label: string) => z.ZodString;
63
61
  export declare function makeDecompositionProposalSchema(types: SubtaskTypeRegistry, maxSubtasks: number): z.ZodObject<{
64
62
  reply: z.ZodString;
65
63
  subtasks: z.ZodArray<z.ZodObject<{
66
- localKey: z.ZodString;
67
64
  type: z.ZodEnum<{
68
65
  [x: string]: string;
69
66
  }>;
70
67
  prompt: z.ZodString;
71
68
  referenceIndexes: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
72
- dependsOn: z.ZodArray<z.ZodString>;
73
69
  params: z.ZodOptional<z.ZodObject<{
74
70
  [x: string]: z.ZodType<string | undefined, unknown, z.core.$ZodTypeInternals<string | undefined, unknown>>;
75
71
  }, z.core.$strip>>;
@@ -79,12 +75,11 @@ export declare function makeDecompositionProposalSchema(types: SubtaskTypeRegist
79
75
  * Resolve a validated model proposal into the drafts to persist.
80
76
  *
81
77
  * Throws {@link DecompositionValidationError} on any structural problem: blank
82
- * fields, duplicate local keys, unknown/duplicate reference indices, and unknown,
83
- * duplicate, self-referential, or cyclic dependency edges. On success, array order
84
- * is preserved — the data layer derives each Subtask's `ordinal` from it.
78
+ * fields, unknown or duplicate reference indices, and params a type refuses. On
79
+ * success, array order is preserved the data layer derives each Subtask's
80
+ * `ordinal` from it.
85
81
  */
86
82
  export declare function resolveDecomposition(proposal: DecompositionProposal, catalog: ReferenceCatalogEntry[], types: SubtaskTypeRegistry): {
87
83
  reply: string;
88
84
  drafts: SubtaskDraft[];
89
85
  };
90
- //# sourceMappingURL=decomposition.d.ts.map
@@ -6,16 +6,15 @@ import { SubtaskParamsError } from "./subtask-types.js";
6
6
  * reference catalog it was generated against, this either produces the drafts to
7
7
  * persist or throws.
8
8
  *
9
- * Two invariants live here:
9
+ * One invariant lives here: **the model selects references by index only.** It
10
+ * emits catalog indices; this module copies the catalog entry's exact role+text
11
+ * onto the draft. Model output never becomes reference text, so a Subtask cannot
12
+ * carry a rewritten, summarized, or fabricated "quote" of the conversation.
10
13
  *
11
- * - **The model selects references by index only.** It emits catalog indices; this
12
- * module copies the catalog entry's exact role+text onto the draft. Model output
13
- * never becomes reference text, so a Subtask cannot carry a rewritten,
14
- * summarized, or fabricated "quote" of the conversation.
15
- * - **The dependency graph is a validated DAG.** Unknown, duplicate,
16
- * self-referential, and cyclic edges are all rejected here. The data layer's
17
- * `createDecomposition` re-checks the cheap structural rules as a storage guard,
18
- * but full cycle detection is this module's job.
14
+ * A proposal's subtasks are **independent of one another**: they all run at once
15
+ * and none can read another's output, so there is no graph to validate and
16
+ * nothing to order. Sequencing is expressed across rounds instead — the main
17
+ * agent delegates, reads the results, and delegates the next step.
19
18
  *
20
19
  * Invalid output is never repaired: a throw fails the attempt, which falls back to
21
20
  * the other model, and two failed attempts fail the parent Task. Silently
@@ -40,12 +39,11 @@ export class DecompositionValidationError extends Error {
40
39
  * constraint reaches the model as part of the tool schema, on every field, with
41
40
  * no per-field `.describe()` needed to restate it.
42
41
  *
43
- * Being shown a rule is not the same as being held to it, and the difference used
44
- * to be a hole. This schema reaches the model through a **control** tool, which has
45
- * no `execute` — so the SDK's input validation never ran on it, and a blank value
46
- * the model was shown the pattern for sailed through anyway. What enforces it is
47
- * {@link file://../control.ts control.ts}, which parses every control call with its
48
- * own schema before the round uses it.
42
+ * Being shown a rule is not the same as being held to it. This schema reaches
43
+ * the model through a **control** tool, which has no `execute`, so the SDK never
44
+ * validates its input what enforces the constraint is
45
+ * {@link file://../agent/control.ts control.ts}, which parses every control call
46
+ * with the tool's own schema before the round uses it.
49
47
  */
50
48
  export const nonBlank = (label) => z
51
49
  .string()
@@ -53,13 +51,11 @@ export const nonBlank = (label) => z
53
51
  .regex(/\S/, { message: `${label} must not be blank` });
54
52
  function makeSubtaskProposalSchema(types) {
55
53
  return z.object({
56
- localKey: nonBlank("localKey"),
57
54
  // A closed enum, not prose: an invented type is rejected by the tool schema
58
55
  // itself rather than silently resolving to some default recipe.
59
56
  type: z.enum(types.enumKeys()),
60
57
  prompt: nonBlank("prompt"),
61
58
  referenceIndexes: z.array(z.number().int().min(1)).optional(),
62
- dependsOn: z.array(nonBlank("dependsOn entry")),
63
59
  /**
64
60
  * The type's required inputs — ids the model quotes from a tool result.
65
61
  * Every key any type declares is named here, gathered from those types by
@@ -94,45 +90,27 @@ export function makeDecompositionProposalSchema(types, maxSubtasks) {
94
90
  subtasks: z.array(makeSubtaskProposalSchema(types)).min(1).max(maxSubtasks)
95
91
  });
96
92
  }
97
- /**
98
- * Reject an edge set that contains a cycle, by Kahn's algorithm over the
99
- * draft-local keys: repeatedly remove nodes with no unresolved prerequisites; if
100
- * any node survives, it is part of (or downstream of) a cycle.
101
- */
102
- function assertAcyclic(proposal) {
103
- const remaining = new Map(proposal.subtasks.map((s) => [s.localKey, new Set(s.dependsOn)]));
104
- let progressed = true;
105
- while (progressed && remaining.size > 0) {
106
- progressed = false;
107
- for (const [key, deps] of remaining) {
108
- // Ready when every prerequisite has already been removed.
109
- if ([...deps].every((d) => !remaining.has(d))) {
110
- remaining.delete(key);
111
- progressed = true;
112
- }
113
- }
114
- }
115
- if (remaining.size > 0) {
116
- throw new DecompositionValidationError(`dependency cycle among subtasks: ${[...remaining.keys()].join(", ")}`);
117
- }
118
- }
119
93
  /**
120
94
  * Snapshot the selected catalog entries onto a draft: validate every index against
121
95
  * the catalog, reject duplicates, and copy each entry's exact role+text. Indexes
122
96
  * are stored ascending so a Subtask's references read in conversation order
123
97
  * regardless of the order the model listed them.
98
+ *
99
+ * `label` names the offending subtask by its 1-based position in the proposal —
100
+ * the only handle a subtask has, and the one the model can map back to what it
101
+ * just wrote.
124
102
  */
125
- function resolveReferences(localKey, referenceIndexes, catalog) {
103
+ function resolveReferences(label, referenceIndexes, catalog) {
126
104
  if (!referenceIndexes)
127
105
  return [];
128
106
  const seen = new Set();
129
107
  for (const index of referenceIndexes) {
130
108
  if (seen.has(index)) {
131
- throw new DecompositionValidationError(`subtask ${localKey} references index ${index} more than once`);
109
+ throw new DecompositionValidationError(`${label} references index ${index} more than once`);
132
110
  }
133
111
  seen.add(index);
134
112
  if (index > catalog.length) {
135
- throw new DecompositionValidationError(`subtask ${localKey} references unknown catalog index ${index} ` +
113
+ throw new DecompositionValidationError(`${label} references unknown catalog index ${index} ` +
136
114
  `(catalog has ${catalog.length} ${catalog.length === 1 ? "entry" : "entries"})`);
137
115
  }
138
116
  }
@@ -148,37 +126,13 @@ function resolveReferences(localKey, referenceIndexes, catalog) {
148
126
  * Resolve a validated model proposal into the drafts to persist.
149
127
  *
150
128
  * Throws {@link DecompositionValidationError} on any structural problem: blank
151
- * fields, duplicate local keys, unknown/duplicate reference indices, and unknown,
152
- * duplicate, self-referential, or cyclic dependency edges. On success, array order
153
- * is preserved — the data layer derives each Subtask's `ordinal` from it.
129
+ * fields, unknown or duplicate reference indices, and params a type refuses. On
130
+ * success, array order is preserved the data layer derives each Subtask's
131
+ * `ordinal` from it.
154
132
  */
155
133
  export function resolveDecomposition(proposal, catalog, types) {
156
- const keys = new Set();
157
- for (const s of proposal.subtasks) {
158
- if (keys.has(s.localKey)) {
159
- throw new DecompositionValidationError(`duplicate subtask local key: ${s.localKey}`);
160
- }
161
- keys.add(s.localKey);
162
- }
163
- // Every key must be registered before any edge is checked: an edge may point
164
- // forward to a subtask defined later in the array.
165
- for (const s of proposal.subtasks) {
166
- const seen = new Set();
167
- for (const dep of s.dependsOn) {
168
- if (dep === s.localKey) {
169
- throw new DecompositionValidationError(`subtask ${s.localKey} depends on itself`);
170
- }
171
- if (!keys.has(dep)) {
172
- throw new DecompositionValidationError(`subtask ${s.localKey} depends on unknown key: ${dep}`);
173
- }
174
- if (seen.has(dep)) {
175
- throw new DecompositionValidationError(`subtask ${s.localKey} depends on ${dep} more than once`);
176
- }
177
- seen.add(dep);
178
- }
179
- }
180
- assertAcyclic(proposal);
181
- const drafts = proposal.subtasks.map((s) => {
134
+ const drafts = proposal.subtasks.map((s, index) => {
135
+ const label = `subtask ${index + 1}`;
182
136
  const type = s.type.trim();
183
137
  let params;
184
138
  try {
@@ -189,17 +143,14 @@ export function resolveDecomposition(proposal, catalog, types) {
189
143
  catch (err) {
190
144
  if (!(err instanceof SubtaskParamsError))
191
145
  throw err;
192
- throw new DecompositionValidationError(`subtask ${s.localKey}: ${err.message}`);
146
+ throw new DecompositionValidationError(`${label}: ${err.message}`);
193
147
  }
194
148
  return {
195
- localKey: s.localKey,
196
149
  type,
197
150
  prompt: s.prompt.trim(),
198
- references: resolveReferences(s.localKey, s.referenceIndexes, catalog),
199
- dependsOn: [...s.dependsOn],
151
+ references: resolveReferences(label, s.referenceIndexes, catalog),
200
152
  params
201
153
  };
202
154
  });
203
155
  return { reply: proposal.reply.trim(), drafts };
204
156
  }
205
- //# sourceMappingURL=decomposition.js.map