@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.
- package/README.md +6 -4
- package/dist/a2a/agent-stub.d.ts +0 -1
- package/dist/a2a/agent-stub.js +0 -1
- package/dist/a2a/caller.d.ts +0 -1
- package/dist/a2a/caller.js +0 -1
- package/dist/a2a/card.d.ts +0 -1
- package/dist/a2a/card.js +0 -1
- package/dist/a2a/context.d.ts +0 -1
- package/dist/a2a/context.js +0 -1
- package/dist/a2a/executor.d.ts +0 -1
- package/dist/a2a/executor.js +0 -1
- package/dist/a2a/index.d.ts +0 -1
- package/dist/a2a/index.js +0 -1
- package/dist/a2a/notify.d.ts +4 -4
- package/dist/a2a/notify.js +4 -4
- package/dist/a2a/parts.d.ts +0 -1
- package/dist/a2a/parts.js +0 -1
- package/dist/a2a/push.d.ts +0 -1
- package/dist/a2a/push.js +0 -1
- package/dist/a2a/task-store.d.ts +0 -1
- package/dist/a2a/task-store.js +0 -1
- package/dist/a2a/task.d.ts +0 -1
- package/dist/a2a/task.js +0 -1
- package/dist/a2a/verify.d.ts +0 -1
- package/dist/a2a/verify.js +0 -1
- package/dist/agent/anthropic/index.d.ts +15 -0
- package/dist/agent/anthropic/index.js +19 -0
- package/dist/agent/anthropic/language-model.d.ts +59 -0
- package/dist/agent/anthropic/language-model.js +442 -0
- package/dist/agent/anthropic/prompt.d.ts +84 -0
- package/dist/agent/anthropic/prompt.js +541 -0
- package/dist/agent/anthropic/runtime.d.ts +79 -0
- package/dist/agent/anthropic/runtime.js +130 -0
- package/dist/agent/budget.d.ts +0 -1
- package/dist/agent/budget.js +0 -1
- package/dist/agent/control.d.ts +0 -1
- package/dist/agent/control.js +10 -10
- package/dist/agent/errors.d.ts +85 -0
- package/dist/agent/errors.js +64 -0
- package/dist/agent/final-reply.d.ts +14 -14
- package/dist/agent/final-reply.js +28 -12
- package/dist/agent/history.d.ts +3 -4
- package/dist/agent/history.js +2 -3
- package/dist/agent/index.d.ts +4 -3
- package/dist/agent/index.js +4 -3
- package/dist/agent/inference.d.ts +58 -2
- package/dist/agent/inference.js +44 -1
- package/dist/agent/model.d.ts +42 -26
- package/dist/agent/model.js +1 -49
- package/dist/agent/session.d.ts +6 -8
- package/dist/agent/session.js +3 -4
- package/dist/agent/workers-ai/index.d.ts +23 -0
- package/dist/agent/workers-ai/index.js +23 -0
- package/dist/agent/workers-ai/runtime.d.ts +42 -0
- package/dist/agent/workers-ai/runtime.js +63 -0
- package/dist/config.d.ts +49 -16
- package/dist/config.js +30 -2
- package/dist/contract/index.d.ts +0 -1
- package/dist/contract/index.js +0 -1
- package/dist/contract/plugin.d.ts +63 -4
- package/dist/contract/plugin.js +76 -1
- package/dist/contract/recipe.d.ts +16 -18
- package/dist/contract/recipe.js +0 -1
- package/dist/contract/validation.d.ts +0 -1
- package/dist/contract/validation.js +0 -1
- package/dist/db/db.d.ts +0 -2
- package/dist/db/db.js +0 -1
- package/dist/db/index.d.ts +0 -1
- package/dist/db/index.js +0 -1
- package/dist/db/migrations/index.d.ts +0 -1
- package/dist/db/migrations/index.js +8 -2
- package/dist/db/models/subtasks.d.ts +24 -26
- package/dist/db/models/subtasks.js +33 -77
- package/dist/db/models/tasks.d.ts +0 -1
- package/dist/db/models/tasks.js +0 -1
- package/dist/db/schema.d.ts +2 -22
- package/dist/db/schema.js +2 -5
- package/dist/env.d.ts +0 -1
- package/dist/env.js +0 -1
- package/dist/host/agent.d.ts +58 -5
- package/dist/host/agent.js +63 -10
- package/dist/host/index.d.ts +0 -1
- package/dist/host/index.js +0 -1
- package/dist/host/plugin-host.d.ts +0 -1
- package/dist/host/plugin-host.js +0 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -3
- package/dist/platform.d.ts +74 -12
- package/dist/platform.js +76 -14
- package/dist/round/agent.d.ts +36 -32
- package/dist/round/agent.js +61 -90
- package/dist/round/index.d.ts +3 -3
- package/dist/round/index.js +2 -3
- package/dist/round/policy.d.ts +2 -3
- package/dist/round/policy.js +0 -1
- package/dist/round/subagent.d.ts +19 -2
- package/dist/round/subagent.js +22 -6
- package/dist/round/turn.d.ts +32 -14
- package/dist/round/turn.js +83 -17
- package/dist/round/workflow.d.ts +30 -9
- package/dist/round/workflow.js +146 -78
- package/dist/runtime/index.d.ts +4 -3
- package/dist/runtime/index.js +6 -1
- package/dist/runtime/tool-families.d.ts +0 -1
- package/dist/runtime/tool-families.js +0 -1
- package/dist/subagent/fingerprint.d.ts +2 -3
- package/dist/subagent/fingerprint.js +8 -18
- package/dist/subagent/index.d.ts +6 -5
- package/dist/subagent/index.js +8 -7
- package/dist/subagent/prompt.d.ts +4 -6
- package/dist/subagent/prompt.js +0 -9
- package/dist/subagent/run.d.ts +8 -2
- package/dist/subagent/run.js +59 -10
- package/dist/subagent/workspace.d.ts +0 -1
- package/dist/subagent/workspace.js +0 -1
- package/dist/subtasks/catalog.d.ts +1 -2
- package/dist/subtasks/catalog.js +1 -2
- package/dist/subtasks/decomposition.d.ts +16 -21
- package/dist/subtasks/decomposition.js +27 -76
- package/dist/subtasks/delegate.d.ts +20 -2
- package/dist/subtasks/delegate.js +21 -17
- package/dist/subtasks/index.d.ts +1 -3
- package/dist/subtasks/index.js +1 -3
- package/dist/subtasks/subtask-types.d.ts +0 -9
- package/dist/subtasks/subtask-types.js +0 -8
- package/dist/subtasks/types.d.ts +45 -71
- package/dist/subtasks/types.js +0 -1
- package/dist/testing/auth.d.ts +0 -1
- package/dist/testing/auth.js +0 -1
- package/dist/testing/do.d.ts +0 -1
- package/dist/testing/do.js +0 -1
- package/dist/testing/fake-session.d.ts +0 -1
- package/dist/testing/fake-session.js +0 -1
- package/dist/testing/fixtures.d.ts +0 -1
- package/dist/testing/fixtures.js +0 -1
- package/dist/testing/harness.d.ts +0 -1
- package/dist/testing/harness.js +0 -1
- package/dist/testing/index.d.ts +0 -1
- package/dist/testing/index.js +0 -1
- package/dist/testing/mock-model.d.ts +35 -1
- package/dist/testing/mock-model.js +75 -1
- package/dist/testing/node.d.ts +0 -1
- package/dist/testing/node.js +0 -1
- package/dist/testing/vcr-global-setup.d.ts +1 -4
- package/dist/testing/vcr-global-setup.js +1 -4
- package/dist/testing/vcr-shared.d.ts +0 -1
- package/dist/testing/vcr-shared.js +0 -1
- package/dist/testing/vcr-spec.d.ts +0 -1
- package/dist/testing/vcr-spec.js +0 -1
- package/dist/testing/vcr-store.d.ts +0 -1
- package/dist/testing/vcr-store.js +0 -1
- package/dist/testing/vcr.d.ts +0 -1
- package/dist/testing/vcr.js +0 -1
- package/dist/worker/define-agent.d.ts +0 -1
- package/dist/worker/define-agent.js +0 -1
- package/dist/worker/index.d.ts +5 -13
- package/dist/worker/index.js +5 -13
- package/package.json +20 -2
- package/dist/a2a/agent-stub.d.ts.map +0 -1
- package/dist/a2a/agent-stub.js.map +0 -1
- package/dist/a2a/caller.d.ts.map +0 -1
- package/dist/a2a/caller.js.map +0 -1
- package/dist/a2a/card.d.ts.map +0 -1
- package/dist/a2a/card.js.map +0 -1
- package/dist/a2a/context.d.ts.map +0 -1
- package/dist/a2a/context.js.map +0 -1
- package/dist/a2a/executor.d.ts.map +0 -1
- package/dist/a2a/executor.js.map +0 -1
- package/dist/a2a/index.d.ts.map +0 -1
- package/dist/a2a/index.js.map +0 -1
- package/dist/a2a/notify.d.ts.map +0 -1
- package/dist/a2a/notify.js.map +0 -1
- package/dist/a2a/parts.d.ts.map +0 -1
- package/dist/a2a/parts.js.map +0 -1
- package/dist/a2a/push.d.ts.map +0 -1
- package/dist/a2a/push.js.map +0 -1
- package/dist/a2a/task-store.d.ts.map +0 -1
- package/dist/a2a/task-store.js.map +0 -1
- package/dist/a2a/task.d.ts.map +0 -1
- package/dist/a2a/task.js.map +0 -1
- package/dist/a2a/verify.d.ts.map +0 -1
- package/dist/a2a/verify.js.map +0 -1
- package/dist/agent/budget.d.ts.map +0 -1
- package/dist/agent/budget.js.map +0 -1
- package/dist/agent/control.d.ts.map +0 -1
- package/dist/agent/control.js.map +0 -1
- package/dist/agent/final-reply.d.ts.map +0 -1
- package/dist/agent/final-reply.js.map +0 -1
- package/dist/agent/history.d.ts.map +0 -1
- package/dist/agent/history.js.map +0 -1
- package/dist/agent/index.d.ts.map +0 -1
- package/dist/agent/index.js.map +0 -1
- package/dist/agent/inference.d.ts.map +0 -1
- package/dist/agent/inference.js.map +0 -1
- package/dist/agent/model.d.ts.map +0 -1
- package/dist/agent/model.js.map +0 -1
- package/dist/agent/session.d.ts.map +0 -1
- package/dist/agent/session.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/contract/index.d.ts.map +0 -1
- package/dist/contract/index.js.map +0 -1
- package/dist/contract/plugin.d.ts.map +0 -1
- package/dist/contract/plugin.js.map +0 -1
- package/dist/contract/recipe.d.ts.map +0 -1
- package/dist/contract/recipe.js.map +0 -1
- package/dist/contract/validation.d.ts.map +0 -1
- package/dist/contract/validation.js.map +0 -1
- package/dist/db/db.d.ts.map +0 -1
- package/dist/db/db.js.map +0 -1
- package/dist/db/index.d.ts.map +0 -1
- package/dist/db/index.js.map +0 -1
- package/dist/db/migrations/index.d.ts.map +0 -1
- package/dist/db/migrations/index.js.map +0 -1
- package/dist/db/models/subtasks.d.ts.map +0 -1
- package/dist/db/models/subtasks.js.map +0 -1
- package/dist/db/models/tasks.d.ts.map +0 -1
- package/dist/db/models/tasks.js.map +0 -1
- package/dist/db/schema.d.ts.map +0 -1
- package/dist/db/schema.js.map +0 -1
- package/dist/env.d.ts.map +0 -1
- package/dist/env.js.map +0 -1
- package/dist/host/agent.d.ts.map +0 -1
- package/dist/host/agent.js.map +0 -1
- package/dist/host/index.d.ts.map +0 -1
- package/dist/host/index.js.map +0 -1
- package/dist/host/plugin-host.d.ts.map +0 -1
- package/dist/host/plugin-host.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/platform.d.ts.map +0 -1
- package/dist/platform.js.map +0 -1
- package/dist/round/agent.d.ts.map +0 -1
- package/dist/round/agent.js.map +0 -1
- package/dist/round/index.d.ts.map +0 -1
- package/dist/round/index.js.map +0 -1
- package/dist/round/policy.d.ts.map +0 -1
- package/dist/round/policy.js.map +0 -1
- package/dist/round/subagent.d.ts.map +0 -1
- package/dist/round/subagent.js.map +0 -1
- package/dist/round/turn.d.ts.map +0 -1
- package/dist/round/turn.js.map +0 -1
- package/dist/round/workflow.d.ts.map +0 -1
- package/dist/round/workflow.js.map +0 -1
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/tool-families.d.ts.map +0 -1
- package/dist/runtime/tool-families.js.map +0 -1
- package/dist/subagent/fingerprint.d.ts.map +0 -1
- package/dist/subagent/fingerprint.js.map +0 -1
- package/dist/subagent/index.d.ts.map +0 -1
- package/dist/subagent/index.js.map +0 -1
- package/dist/subagent/prompt.d.ts.map +0 -1
- package/dist/subagent/prompt.js.map +0 -1
- package/dist/subagent/run.d.ts.map +0 -1
- package/dist/subagent/run.js.map +0 -1
- package/dist/subagent/workspace.d.ts.map +0 -1
- package/dist/subagent/workspace.js.map +0 -1
- package/dist/subtasks/catalog.d.ts.map +0 -1
- package/dist/subtasks/catalog.js.map +0 -1
- package/dist/subtasks/decomposition.d.ts.map +0 -1
- package/dist/subtasks/decomposition.js.map +0 -1
- package/dist/subtasks/delegate.d.ts.map +0 -1
- package/dist/subtasks/delegate.js.map +0 -1
- package/dist/subtasks/index.d.ts.map +0 -1
- package/dist/subtasks/index.js.map +0 -1
- package/dist/subtasks/scheduler.d.ts +0 -49
- package/dist/subtasks/scheduler.d.ts.map +0 -1
- package/dist/subtasks/scheduler.js +0 -48
- package/dist/subtasks/scheduler.js.map +0 -1
- package/dist/subtasks/subtask-types.d.ts.map +0 -1
- package/dist/subtasks/subtask-types.js.map +0 -1
- package/dist/subtasks/types.d.ts.map +0 -1
- package/dist/subtasks/types.js.map +0 -1
- package/dist/testing/auth.d.ts.map +0 -1
- package/dist/testing/auth.js.map +0 -1
- package/dist/testing/do.d.ts.map +0 -1
- package/dist/testing/do.js.map +0 -1
- package/dist/testing/fake-session.d.ts.map +0 -1
- package/dist/testing/fake-session.js.map +0 -1
- package/dist/testing/fixtures.d.ts.map +0 -1
- package/dist/testing/fixtures.js.map +0 -1
- package/dist/testing/harness.d.ts.map +0 -1
- package/dist/testing/harness.js.map +0 -1
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/index.js.map +0 -1
- package/dist/testing/mock-model.d.ts.map +0 -1
- package/dist/testing/mock-model.js.map +0 -1
- package/dist/testing/node.d.ts.map +0 -1
- package/dist/testing/node.js.map +0 -1
- package/dist/testing/vcr-global-setup.d.ts.map +0 -1
- package/dist/testing/vcr-global-setup.js.map +0 -1
- package/dist/testing/vcr-shared.d.ts.map +0 -1
- package/dist/testing/vcr-shared.js.map +0 -1
- package/dist/testing/vcr-spec.d.ts.map +0 -1
- package/dist/testing/vcr-spec.js.map +0 -1
- package/dist/testing/vcr-store.d.ts.map +0 -1
- package/dist/testing/vcr-store.js.map +0 -1
- package/dist/testing/vcr.d.ts.map +0 -1
- package/dist/testing/vcr.js.map +0 -1
- package/dist/worker/define-agent.d.ts.map +0 -1
- package/dist/worker/define-agent.js.map +0 -1
- package/dist/worker/index.d.ts.map +0 -1
- package/dist/worker/index.js.map +0 -1
|
@@ -160,9 +160,9 @@ export interface AgentPlugin<TRuntime = SubtaskRuntime> {
|
|
|
160
160
|
*
|
|
161
161
|
* A plugin that declares a {@link subtaskType} should put its capability block
|
|
162
162
|
* on the *type* instead ({@link SubtaskTypeSpec.capability}) and leave this
|
|
163
|
-
* unset
|
|
164
|
-
*
|
|
165
|
-
*
|
|
163
|
+
* unset. Both are rendered, so declaring both makes the main agent read the
|
|
164
|
+
* same advice twice per round — the exact failure the type's own prompt
|
|
165
|
+
* fields were introduced to end.
|
|
166
166
|
*/
|
|
167
167
|
capability?: string;
|
|
168
168
|
/**
|
|
@@ -262,4 +262,63 @@ export interface AgentPlugin<TRuntime = SubtaskRuntime> {
|
|
|
262
262
|
export declare function definePlugin<TRuntime = SubtaskRuntime>(plugin: Omit<AgentPlugin<TRuntime>, "contractVersion"> & {
|
|
263
263
|
contractVersion?: number;
|
|
264
264
|
}): AgentPlugin<TRuntime>;
|
|
265
|
-
|
|
265
|
+
/** See {@link restrictMainAgentTools}. */
|
|
266
|
+
export interface RestrictMainAgentToolsOptions {
|
|
267
|
+
/**
|
|
268
|
+
* The tool names the main agent keeps. `[]` removes the hook entirely, which
|
|
269
|
+
* is the "orchestrator with no hands" case.
|
|
270
|
+
*
|
|
271
|
+
* Names rather than a predicate, because the point is to state the surface
|
|
272
|
+
* explicitly at the install site: a reader of `plugins.ts` should be able to
|
|
273
|
+
* see what the main agent can do without opening the plugin.
|
|
274
|
+
*/
|
|
275
|
+
allow: readonly string[];
|
|
276
|
+
/**
|
|
277
|
+
* What the main agent is told instead of the plugin's own
|
|
278
|
+
* {@link AgentPlugin.capability}.
|
|
279
|
+
*
|
|
280
|
+
* Required in spirit whenever `allow` is non-empty: the plugin's block
|
|
281
|
+
* describes its *whole* surface, so leaving it in place tells the model about
|
|
282
|
+
* tools it no longer has — which it then tries to call. Omit it to say
|
|
283
|
+
* nothing, which is right for `allow: []`.
|
|
284
|
+
*/
|
|
285
|
+
capability?: string;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* A plugin whose tool families stay registered but whose main-agent surface is
|
|
289
|
+
* narrowed, or removed.
|
|
290
|
+
*
|
|
291
|
+
* ## Why this has to exist
|
|
292
|
+
*
|
|
293
|
+
* `validateRecipe` runs on the **parent** and drops any tool family no installed
|
|
294
|
+
* plugin registered. So an agent that wants "my subagents can run a shell, I
|
|
295
|
+
* cannot" has a problem: uninstalling the sandbox plugin from the parent also
|
|
296
|
+
* deletes `sandbox` from every recipe the parent validates, and the subagents
|
|
297
|
+
* silently lose it. The parent has to install the plugin and decline its tools,
|
|
298
|
+
* which is exactly what this expresses.
|
|
299
|
+
*
|
|
300
|
+
* ```ts
|
|
301
|
+
* // The parent registers the family, and gets three read-only tools from it.
|
|
302
|
+
* restrictMainAgentTools(sandbox(cfg), {
|
|
303
|
+
* allow: ["sb_read", "sb_ls", "sb_exists"],
|
|
304
|
+
* capability: "You can read the checkout, not change it."
|
|
305
|
+
* })
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* ## What passes through untouched
|
|
309
|
+
*
|
|
310
|
+
* Everything else: `toolFamilies`, `subtaskType`, `resolveRuntime`, `store`,
|
|
311
|
+
* `requires`, and the lifecycle hooks. In particular `requires` must survive, or
|
|
312
|
+
* a parent that stops offering `sb_exec` also stops asserting that the `Sandbox`
|
|
313
|
+
* binding exists — and the failure moves from DO start to a subagent's first
|
|
314
|
+
* tool call.
|
|
315
|
+
*
|
|
316
|
+
* ## Why a missing name logs instead of throwing
|
|
317
|
+
*
|
|
318
|
+
* `mainAgentTools` is async and called per turn, so a throw here lands inside a
|
|
319
|
+
* request someone is waiting on — a bad trade for what is always a typo. The
|
|
320
|
+
* error names the plugin and the tool so it is greppable, and the honest place
|
|
321
|
+
* to catch it is a test over the assembled surface, which is cheap to write and
|
|
322
|
+
* fails the build instead.
|
|
323
|
+
*/
|
|
324
|
+
export declare function restrictMainAgentTools<TRuntime = SubtaskRuntime>(plugin: AgentPlugin<TRuntime>, options: RestrictMainAgentToolsOptions): AgentPlugin<TRuntime>;
|
package/dist/contract/plugin.js
CHANGED
|
@@ -36,4 +36,79 @@ export function definePlugin(plugin) {
|
|
|
36
36
|
contractVersion: plugin.contractVersion ?? PLUGIN_CONTRACT_VERSION
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
/**
|
|
40
|
+
* A plugin whose tool families stay registered but whose main-agent surface is
|
|
41
|
+
* narrowed, or removed.
|
|
42
|
+
*
|
|
43
|
+
* ## Why this has to exist
|
|
44
|
+
*
|
|
45
|
+
* `validateRecipe` runs on the **parent** and drops any tool family no installed
|
|
46
|
+
* plugin registered. So an agent that wants "my subagents can run a shell, I
|
|
47
|
+
* cannot" has a problem: uninstalling the sandbox plugin from the parent also
|
|
48
|
+
* deletes `sandbox` from every recipe the parent validates, and the subagents
|
|
49
|
+
* silently lose it. The parent has to install the plugin and decline its tools,
|
|
50
|
+
* which is exactly what this expresses.
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* // The parent registers the family, and gets three read-only tools from it.
|
|
54
|
+
* restrictMainAgentTools(sandbox(cfg), {
|
|
55
|
+
* allow: ["sb_read", "sb_ls", "sb_exists"],
|
|
56
|
+
* capability: "You can read the checkout, not change it."
|
|
57
|
+
* })
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* ## What passes through untouched
|
|
61
|
+
*
|
|
62
|
+
* Everything else: `toolFamilies`, `subtaskType`, `resolveRuntime`, `store`,
|
|
63
|
+
* `requires`, and the lifecycle hooks. In particular `requires` must survive, or
|
|
64
|
+
* a parent that stops offering `sb_exec` also stops asserting that the `Sandbox`
|
|
65
|
+
* binding exists — and the failure moves from DO start to a subagent's first
|
|
66
|
+
* tool call.
|
|
67
|
+
*
|
|
68
|
+
* ## Why a missing name logs instead of throwing
|
|
69
|
+
*
|
|
70
|
+
* `mainAgentTools` is async and called per turn, so a throw here lands inside a
|
|
71
|
+
* request someone is waiting on — a bad trade for what is always a typo. The
|
|
72
|
+
* error names the plugin and the tool so it is greppable, and the honest place
|
|
73
|
+
* to catch it is a test over the assembled surface, which is cheap to write and
|
|
74
|
+
* fails the build instead.
|
|
75
|
+
*/
|
|
76
|
+
export function restrictMainAgentTools(plugin, options) {
|
|
77
|
+
const allow = new Set(options.allow);
|
|
78
|
+
// Spread first so anything added to `AgentPlugin` later keeps flowing through
|
|
79
|
+
// without an edit here — the failure mode of an explicit field list is a
|
|
80
|
+
// capability that silently stops reaching the parent.
|
|
81
|
+
const restricted = { ...plugin };
|
|
82
|
+
if (allow.size === 0) {
|
|
83
|
+
delete restricted.mainAgentTools;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Installed even when the plugin offers no `mainAgentTools` at all, rather
|
|
87
|
+
// than left `undefined`. A plugin with no main-agent surface is not the
|
|
88
|
+
// "nothing to narrow" case it looks like — it is an allowlist naming tools
|
|
89
|
+
// that do not exist, which is precisely the typo this helper promises to
|
|
90
|
+
// report, and the one shape of it that is hardest to spot: a whole surface
|
|
91
|
+
// removed or renamed disappears without a word. The assembled tool set is
|
|
92
|
+
// identical either way, because `runtime.mainAgentTools` merges each
|
|
93
|
+
// plugin's result and an empty one contributes nothing.
|
|
94
|
+
const inner = plugin.mainAgentTools;
|
|
95
|
+
restricted.mainAgentTools = async (ctx) => {
|
|
96
|
+
const all = inner ? await inner(ctx) : {};
|
|
97
|
+
const kept = {};
|
|
98
|
+
for (const name of allow) {
|
|
99
|
+
if (name in all)
|
|
100
|
+
kept[name] = all[name];
|
|
101
|
+
else
|
|
102
|
+
console.error(`[plugin] "${plugin.key}" offers no main-agent tool "${name}" — ` +
|
|
103
|
+
"the allowlist names a tool that does not exist, so the main " +
|
|
104
|
+
"agent is quietly missing it. Check for a rename.");
|
|
105
|
+
}
|
|
106
|
+
return kept;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (options.capability === undefined)
|
|
110
|
+
delete restricted.capability;
|
|
111
|
+
else
|
|
112
|
+
restricted.capability = options.capability;
|
|
113
|
+
return restricted;
|
|
114
|
+
}
|
|
@@ -48,12 +48,10 @@ export interface DelegationNames {
|
|
|
48
48
|
*
|
|
49
49
|
* Deliberately *not* here: how a run is sliced into durable chunks. That is a
|
|
50
50
|
* Workers step-timeout constraint, it is identical for every Recipe, and it lives
|
|
51
|
-
* in {@link file://../platform.ts}.
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*/
|
|
56
|
-
/**
|
|
51
|
+
* in {@link file://../platform.ts}. A turn count cannot do that job — nothing
|
|
52
|
+
* predicts how long a turn takes — so no per-chunk turn budget belongs on a
|
|
53
|
+
* Recipe.
|
|
54
|
+
*
|
|
57
55
|
* Structurally identical to {@link AgentLimits} — a budget is a budget at both
|
|
58
56
|
* levels, and keeping one shape means `resolveLimits` merges a recipe's
|
|
59
57
|
* declaration straight over the host's baseline with no translation. Aliased
|
|
@@ -81,8 +79,10 @@ export interface ResolvedRecipe {
|
|
|
81
79
|
toolFamilies: string[];
|
|
82
80
|
enabled: boolean;
|
|
83
81
|
/**
|
|
84
|
-
* Only the budget fields this Recipe overrides; the rest come from
|
|
85
|
-
* `
|
|
82
|
+
* Only the budget fields this Recipe overrides; the rest come from the host's
|
|
83
|
+
* `CoreConfig.subagentLimits`, which reaches validation as
|
|
84
|
+
* `RecipePolicy.baselineLimits`. `{}` means "the baseline", which is what most
|
|
85
|
+
* Recipes want.
|
|
86
86
|
*/
|
|
87
87
|
limits: Partial<RecipeLimits>;
|
|
88
88
|
/**
|
|
@@ -107,8 +107,8 @@ export interface ValidatedRecipe extends ResolvedRecipe {
|
|
|
107
107
|
*
|
|
108
108
|
* These exist only here, never on {@link ResolvedRecipe}, and that asymmetry
|
|
109
109
|
* is the design: a recipe cannot state a model, so the only way to hold one is
|
|
110
|
-
* to have been through
|
|
111
|
-
*
|
|
110
|
+
* to have been through `validateRecipe`, which copies the host's. Recipe data
|
|
111
|
+
* has no path to influence them.
|
|
112
112
|
*
|
|
113
113
|
* Guaranteed non-empty and guaranteed distinct, because `resolveConfig`
|
|
114
114
|
* refuses a config that is either — so the fallback is always a genuinely
|
|
@@ -145,9 +145,9 @@ export interface SubtaskTypeSpec {
|
|
|
145
145
|
*
|
|
146
146
|
* A `z.object`, not an opaque `z.ZodType`, and that is load-bearing: the agent
|
|
147
147
|
* reads `.shape` back to build the `params` field of the delegate tool's schema
|
|
148
|
-
* (see `
|
|
149
|
-
* the failure this shape exists to prevent — describe each key
|
|
150
|
-
* `.describe()`, because that text is what the model reads.
|
|
148
|
+
* (see `SubtaskTypeRegistry.paramProperties`). Declaring a param the model is
|
|
149
|
+
* never shown is the failure this shape exists to prevent — describe each key
|
|
150
|
+
* with `.describe()`, because that text is what the model reads.
|
|
151
151
|
*/
|
|
152
152
|
params: SubtaskParamsSchema | null;
|
|
153
153
|
/** How the model is told to obtain each param, appended to the description. */
|
|
@@ -159,10 +159,9 @@ export interface SubtaskTypeSpec {
|
|
|
159
159
|
*
|
|
160
160
|
* These two prompt fields exist to hold one rule: **everything the main agent
|
|
161
161
|
* is told about a domain is declared here, never written inside the runtime.**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* subtasks a multi-game request gets.
|
|
162
|
+
* Advice written in the runtime instead has to be repeated per call site, and
|
|
163
|
+
* the copies drift — into telling the main agent two contradictory things
|
|
164
|
+
* about the same domain, twice per round.
|
|
166
165
|
*/
|
|
167
166
|
capability?: string;
|
|
168
167
|
/**
|
|
@@ -179,4 +178,3 @@ export interface SubtaskTypeSpec {
|
|
|
179
178
|
/** The execution configuration this type runs under. */
|
|
180
179
|
recipe: ResolvedRecipe;
|
|
181
180
|
}
|
|
182
|
-
//# sourceMappingURL=recipe.d.ts.map
|
package/dist/contract/recipe.js
CHANGED
|
@@ -89,4 +89,3 @@ export declare class RecipeValidationError extends Error {
|
|
|
89
89
|
* house default can guess. Both fail the recipe outright.
|
|
90
90
|
*/
|
|
91
91
|
export declare function validateRecipe(recipe: ResolvedRecipe, policy: RecipePolicy): ValidatedRecipe;
|
|
92
|
-
//# sourceMappingURL=validation.d.ts.map
|
package/dist/db/db.d.ts
CHANGED
|
@@ -130,7 +130,6 @@ export declare class AgentDB {
|
|
|
130
130
|
}): boolean;
|
|
131
131
|
complete(id: import("../subtasks/types.js").SubtaskId, resultParts: import("../subtasks/types.js").SubtaskResultPart[]): boolean;
|
|
132
132
|
fail(id: import("../subtasks/types.js").SubtaskId, error: string): boolean;
|
|
133
|
-
skip(id: import("../subtasks/types.js").SubtaskId): boolean;
|
|
134
133
|
cancelRunning(id: import("../subtasks/types.js").SubtaskId): boolean;
|
|
135
134
|
cancelPending(taskId: string): number;
|
|
136
135
|
cleanup(): void;
|
|
@@ -146,4 +145,3 @@ export declare class AgentDB {
|
|
|
146
145
|
*/
|
|
147
146
|
private applyStores;
|
|
148
147
|
}
|
|
149
|
-
//# sourceMappingURL=db.d.ts.map
|
package/dist/db/db.js
CHANGED
package/dist/db/index.d.ts
CHANGED
|
@@ -6,4 +6,3 @@ export { AgentDB, PLUGIN_MIGRATIONS_TABLE, type AgentDBOptions, type DB, type Pl
|
|
|
6
6
|
export { notifyTasks, subtasks } from "./schema.js";
|
|
7
7
|
export { makeTasks, stateOf, type TaskListQuery } from "./models/tasks.js";
|
|
8
8
|
export { makeSubtasks, type SubtaskModelOptions } from "./models/subtasks.js";
|
|
9
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/db/index.js
CHANGED
|
@@ -6,6 +6,12 @@ const dbMigrations = {
|
|
|
6
6
|
when: 1785537420937,
|
|
7
7
|
tag: "0000_init",
|
|
8
8
|
breakpoints: true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
idx: 1,
|
|
12
|
+
when: 1786871925215,
|
|
13
|
+
tag: "0001_drop_depends_on",
|
|
14
|
+
breakpoints: true
|
|
9
15
|
}
|
|
10
16
|
]
|
|
11
17
|
},
|
|
@@ -47,8 +53,8 @@ CREATE TABLE \`subtasks\` (
|
|
|
47
53
|
CREATE UNIQUE INDEX \`idx_subtasks_task_ordinal\` ON \`subtasks\` (\`task_id\`,\`ordinal\`);--> statement-breakpoint
|
|
48
54
|
CREATE INDEX \`idx_subtasks_task_round\` ON \`subtasks\` (\`task_id\`,\`round\`);--> statement-breakpoint
|
|
49
55
|
CREATE INDEX \`idx_subtasks_status\` ON \`subtasks\` (\`status\`);--> statement-breakpoint
|
|
50
|
-
CREATE INDEX \`idx_subtasks_created_at\` ON \`subtasks\` (\`created_at\`)
|
|
56
|
+
CREATE INDEX \`idx_subtasks_created_at\` ON \`subtasks\` (\`created_at\`);`,
|
|
57
|
+
m0001: `ALTER TABLE \`subtasks\` DROP COLUMN \`depends_on_json\`;`
|
|
51
58
|
}
|
|
52
59
|
};
|
|
53
60
|
export default dbMigrations;
|
|
54
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -15,28 +15,22 @@ export interface SubtaskModelOptions {
|
|
|
15
15
|
* durable-sqlite is synchronous; the multi-statement `createDecomposition` runs
|
|
16
16
|
* inside an explicit `db.transaction` (drizzle maps it to
|
|
17
17
|
* `storage.transactionSync`), so a mid-create failure rolls back every statement
|
|
18
|
-
* instead of leaving a partial
|
|
18
|
+
* instead of leaving a partial decomposition. Guarded transitions filter on the expected
|
|
19
19
|
* current `status`, so a disallowed transition matches no row and is a no-op.
|
|
20
20
|
*/
|
|
21
21
|
export declare function makeSubtasks(db: DB, opts: SubtaskModelOptions): {
|
|
22
22
|
/**
|
|
23
|
-
* Create one **round's** decomposition atomically: the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* per-round bound, unique local keys, and resolvable non-self dependency
|
|
31
|
-
* edges, then resolves draft-local dependency keys to the SQLite-assigned
|
|
32
|
-
* {@link SubtaskId}s. Full cycle/edge DAG validation lives in the turn
|
|
33
|
-
* operation; this is the storage guard.
|
|
23
|
+
* Create one **round's** decomposition atomically: the whole check-and-insert
|
|
24
|
+
* sequence runs in one synchronous `db.transaction`, so a failure anywhere
|
|
25
|
+
* rolls back every statement rather than leaving a truncated subtask set.
|
|
26
|
+
* Idempotent on `(taskId, round)`: if this round already has Subtasks,
|
|
27
|
+
* returns them unchanged (a Workflow-step retry must not duplicate work); the
|
|
28
|
+
* unique `(task_id, ordinal)` index is the schema-level backstop. Enforces the
|
|
29
|
+
* 1..8 per-round bound as the durable guard.
|
|
34
30
|
*
|
|
35
31
|
* `ordinal` continues across rounds (it is the Task-wide position, and what
|
|
36
32
|
* the unique index is built on), so a later round's rows sort after the
|
|
37
|
-
* earlier ones in {@link list}.
|
|
38
|
-
* round's DAG is self-contained, and the drafts handed here only carry keys
|
|
39
|
-
* from their own round.
|
|
33
|
+
* earlier ones in {@link list}.
|
|
40
34
|
*/
|
|
41
35
|
createDecomposition(taskId: string, round: number, drafts: SubtaskDraft[]): Subtask[];
|
|
42
36
|
/** Load one Subtask by id. */
|
|
@@ -44,9 +38,10 @@ export declare function makeSubtasks(db: DB, opts: SubtaskModelOptions): {
|
|
|
44
38
|
/** List every round's Subtasks for a Task, in ordinal order. */
|
|
45
39
|
list(taskId: string): Subtask[];
|
|
46
40
|
/**
|
|
47
|
-
* List one round's Subtasks, in ordinal order — the
|
|
48
|
-
*
|
|
49
|
-
* rows;
|
|
41
|
+
* List one round's Subtasks, in ordinal order — what the Workflow's `scan`
|
|
42
|
+
* projects. It executes a single round at a time, so it must not see a
|
|
43
|
+
* sibling round's rows; a later round, by contrast, reads {@link list}
|
|
44
|
+
* across all rounds to reunite each `delegate` call with its results.
|
|
50
45
|
*/
|
|
51
46
|
listRound(taskId: string, round: number): Subtask[];
|
|
52
47
|
/**
|
|
@@ -70,17 +65,14 @@ export declare function makeSubtasks(db: DB, opts: SubtaskModelOptions): {
|
|
|
70
65
|
* Both sides are reachable and both must land. A child's failed result arrives
|
|
71
66
|
* on a `running` row. The Workflow's last resort — `failSubtask`, once
|
|
72
67
|
* `execute:<id>` has exhausted every retry — can arrive on either:
|
|
73
|
-
* `executeSubtask` may throw before its `pending -> running` claim (
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* propagates past *failed* prerequisites.
|
|
68
|
+
* `executeSubtask` may throw before its `pending -> running` claim (an
|
|
69
|
+
* unresolvable recipe) or after it (a transient child fault). Leaving either
|
|
70
|
+
* behind strands the row in a non-terminal state that nobody is coming back
|
|
71
|
+
* to resolve.
|
|
78
72
|
*
|
|
79
73
|
* Returns false once the row is terminal — a late loser to the real result.
|
|
80
74
|
*/
|
|
81
75
|
fail(id: SubtaskId, error: string): boolean;
|
|
82
|
-
/** Skip a Subtask blocked by a failed/skipped dependency: guarded `pending -> skipped`. */
|
|
83
|
-
skip(id: SubtaskId): boolean;
|
|
84
76
|
/**
|
|
85
77
|
* Discard a late result after parent cancellation: guarded
|
|
86
78
|
* `running -> canceled`. The parent calls this when a child returned a
|
|
@@ -94,9 +86,15 @@ export declare function makeSubtasks(db: DB, opts: SubtaskModelOptions): {
|
|
|
94
86
|
* Running Subtasks are left alone here — the parent transitions those with
|
|
95
87
|
* {@link cancelRunning} once their in-flight result comes back and is
|
|
96
88
|
* discarded. Returns the number canceled.
|
|
89
|
+
*
|
|
90
|
+
* Keyed on the Task rather than one id, so this is the one guarded
|
|
91
|
+
* transition that cannot go through {@link transition} and sets its own
|
|
92
|
+
* timestamps. `completedAt` is part of that and not optional: every other
|
|
93
|
+
* terminal write records it, and a terminal row without one reads as still
|
|
94
|
+
* in flight to anything measuring how long a Subtask took or when a Task
|
|
95
|
+
* actually stopped.
|
|
97
96
|
*/
|
|
98
97
|
cancelPending(taskId: string): number;
|
|
99
98
|
/** Delete Subtasks older than 30 days (called by the weekly maintenance cron). */
|
|
100
99
|
cleanup(): void;
|
|
101
100
|
};
|
|
102
|
-
//# sourceMappingURL=subtasks.d.ts.map
|
|
@@ -11,7 +11,6 @@ const resultPartSchema = z.object({
|
|
|
11
11
|
});
|
|
12
12
|
const referencesSchema = z.array(referenceSchema);
|
|
13
13
|
const resultPartsSchema = z.array(resultPartSchema);
|
|
14
|
-
const dependsOnSchema = z.array(z.number().int());
|
|
15
14
|
const paramsSchema = z.record(z.string(), z.string());
|
|
16
15
|
/**
|
|
17
16
|
* Query methods for the `subtasks` table (durable decomposed units of work).
|
|
@@ -20,7 +19,7 @@ const paramsSchema = z.record(z.string(), z.string());
|
|
|
20
19
|
* durable-sqlite is synchronous; the multi-statement `createDecomposition` runs
|
|
21
20
|
* inside an explicit `db.transaction` (drizzle maps it to
|
|
22
21
|
* `storage.transactionSync`), so a mid-create failure rolls back every statement
|
|
23
|
-
* instead of leaving a partial
|
|
22
|
+
* instead of leaving a partial decomposition. Guarded transitions filter on the expected
|
|
24
23
|
* current `status`, so a disallowed transition matches no row and is a no-op.
|
|
25
24
|
*/
|
|
26
25
|
export function makeSubtasks(db, opts) {
|
|
@@ -34,7 +33,6 @@ export function makeSubtasks(db, opts) {
|
|
|
34
33
|
recipeVersion: row.recipeVersion,
|
|
35
34
|
prompt: row.prompt,
|
|
36
35
|
references: referencesSchema.parse(JSON.parse(row.referencesJson)),
|
|
37
|
-
dependsOn: dependsOnSchema.parse(JSON.parse(row.dependsOnJson)),
|
|
38
36
|
params: paramsSchema.parse(JSON.parse(row.paramsJson)),
|
|
39
37
|
status: row.status,
|
|
40
38
|
resultParts: row.resultPartsJson === null
|
|
@@ -74,23 +72,17 @@ export function makeSubtasks(db, opts) {
|
|
|
74
72
|
};
|
|
75
73
|
return {
|
|
76
74
|
/**
|
|
77
|
-
* Create one **round's** decomposition atomically: the
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* per-round bound, unique local keys, and resolvable non-self dependency
|
|
85
|
-
* edges, then resolves draft-local dependency keys to the SQLite-assigned
|
|
86
|
-
* {@link SubtaskId}s. Full cycle/edge DAG validation lives in the turn
|
|
87
|
-
* operation; this is the storage guard.
|
|
75
|
+
* Create one **round's** decomposition atomically: the whole check-and-insert
|
|
76
|
+
* sequence runs in one synchronous `db.transaction`, so a failure anywhere
|
|
77
|
+
* rolls back every statement rather than leaving a truncated subtask set.
|
|
78
|
+
* Idempotent on `(taskId, round)`: if this round already has Subtasks,
|
|
79
|
+
* returns them unchanged (a Workflow-step retry must not duplicate work); the
|
|
80
|
+
* unique `(task_id, ordinal)` index is the schema-level backstop. Enforces the
|
|
81
|
+
* 1..8 per-round bound as the durable guard.
|
|
88
82
|
*
|
|
89
83
|
* `ordinal` continues across rounds (it is the Task-wide position, and what
|
|
90
84
|
* the unique index is built on), so a later round's rows sort after the
|
|
91
|
-
* earlier ones in {@link list}.
|
|
92
|
-
* round's DAG is self-contained, and the drafts handed here only carry keys
|
|
93
|
-
* from their own round.
|
|
85
|
+
* earlier ones in {@link list}.
|
|
94
86
|
*/
|
|
95
87
|
createDecomposition(taskId, round, drafts) {
|
|
96
88
|
return db.transaction(() => {
|
|
@@ -100,38 +92,14 @@ export function makeSubtasks(db, opts) {
|
|
|
100
92
|
if (drafts.length < 1 || drafts.length > opts.maxSubtasks) {
|
|
101
93
|
throw new Error(`decomposition must have 1..${opts.maxSubtasks} subtasks, got ${drafts.length}`);
|
|
102
94
|
}
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
// edge may point forward to a draft defined later, so every key must be
|
|
106
|
-
// known before any edge is validated.
|
|
107
|
-
const keys = new Set();
|
|
108
|
-
for (const d of drafts) {
|
|
109
|
-
if (keys.has(d.localKey)) {
|
|
110
|
-
throw new Error(`duplicate draft local key: ${d.localKey}`);
|
|
111
|
-
}
|
|
112
|
-
keys.add(d.localKey);
|
|
113
|
-
}
|
|
114
|
-
for (const d of drafts) {
|
|
115
|
-
for (const dep of d.dependsOn) {
|
|
116
|
-
// A subtask cannot depend on itself.
|
|
117
|
-
if (dep === d.localKey) {
|
|
118
|
-
throw new Error(`subtask ${d.localKey} depends on itself`);
|
|
119
|
-
}
|
|
120
|
-
// Every edge must resolve to a key in this decomposition.
|
|
121
|
-
if (!keys.has(dep)) {
|
|
122
|
-
throw new Error(`subtask ${d.localKey} depends on unknown key: ${dep}`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
// References must match the persisted shape before we serialize them.
|
|
95
|
+
// References must match the persisted shape before we serialize them.
|
|
96
|
+
for (const d of drafts)
|
|
126
97
|
referencesSchema.parse(d.references);
|
|
127
|
-
}
|
|
128
98
|
const now = Date.now();
|
|
129
|
-
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
// Task cannot hand a later round an ordinal that is already taken. Both
|
|
134
|
-
// read the `(task_id, ordinal)` index; only this one stays monotonic.
|
|
99
|
+
// Ordinals continue above every earlier round's rows — from the current
|
|
100
|
+
// maximum, not a row count, so a gap left by {@link cleanup} deleting part
|
|
101
|
+
// of a Task cannot hand a later round an ordinal that is already taken.
|
|
102
|
+
// Both read the `(task_id, ordinal)` index; only this one stays monotonic.
|
|
135
103
|
const highest = db
|
|
136
104
|
.select({ max: max(subtasks.ordinal) })
|
|
137
105
|
.from(subtasks)
|
|
@@ -139,8 +107,7 @@ export function makeSubtasks(db, opts) {
|
|
|
139
107
|
.get()?.max ?? null;
|
|
140
108
|
const firstOrdinal = highest === null ? 0 : highest + 1;
|
|
141
109
|
drafts.forEach((d, offset) => {
|
|
142
|
-
|
|
143
|
-
.insert(subtasks)
|
|
110
|
+
db.insert(subtasks)
|
|
144
111
|
.values({
|
|
145
112
|
taskId,
|
|
146
113
|
round,
|
|
@@ -150,7 +117,6 @@ export function makeSubtasks(db, opts) {
|
|
|
150
117
|
recipeVersion: null,
|
|
151
118
|
prompt: d.prompt,
|
|
152
119
|
referencesJson: JSON.stringify(d.references),
|
|
153
|
-
dependsOnJson: "[]",
|
|
154
120
|
paramsJson: JSON.stringify(d.params ?? {}),
|
|
155
121
|
status: "pending",
|
|
156
122
|
resultPartsJson: null,
|
|
@@ -159,20 +125,8 @@ export function makeSubtasks(db, opts) {
|
|
|
159
125
|
updatedAt: now,
|
|
160
126
|
completedAt: null
|
|
161
127
|
})
|
|
162
|
-
.returning({ id: subtasks.id })
|
|
163
|
-
.get();
|
|
164
|
-
keyToId.set(d.localKey, id);
|
|
165
|
-
});
|
|
166
|
-
// Pass 2: rewrite dependency edges to real ids.
|
|
167
|
-
for (const d of drafts) {
|
|
168
|
-
if (d.dependsOn.length === 0)
|
|
169
|
-
continue;
|
|
170
|
-
const ids = d.dependsOn.map((k) => keyToId.get(k));
|
|
171
|
-
db.update(subtasks)
|
|
172
|
-
.set({ dependsOnJson: JSON.stringify(ids) })
|
|
173
|
-
.where(eq(subtasks.id, keyToId.get(d.localKey)))
|
|
174
128
|
.run();
|
|
175
|
-
}
|
|
129
|
+
});
|
|
176
130
|
return listRound(taskId, round);
|
|
177
131
|
});
|
|
178
132
|
},
|
|
@@ -186,9 +140,10 @@ export function makeSubtasks(db, opts) {
|
|
|
186
140
|
return list(taskId);
|
|
187
141
|
},
|
|
188
142
|
/**
|
|
189
|
-
* List one round's Subtasks, in ordinal order — the
|
|
190
|
-
*
|
|
191
|
-
* rows;
|
|
143
|
+
* List one round's Subtasks, in ordinal order — what the Workflow's `scan`
|
|
144
|
+
* projects. It executes a single round at a time, so it must not see a
|
|
145
|
+
* sibling round's rows; a later round, by contrast, reads {@link list}
|
|
146
|
+
* across all rounds to reunite each `delegate` call with its results.
|
|
192
147
|
*/
|
|
193
148
|
listRound(taskId, round) {
|
|
194
149
|
return listRound(taskId, round);
|
|
@@ -227,11 +182,10 @@ export function makeSubtasks(db, opts) {
|
|
|
227
182
|
* Both sides are reachable and both must land. A child's failed result arrives
|
|
228
183
|
* on a `running` row. The Workflow's last resort — `failSubtask`, once
|
|
229
184
|
* `execute:<id>` has exhausted every retry — can arrive on either:
|
|
230
|
-
* `executeSubtask` may throw before its `pending -> running` claim (
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
* propagates past *failed* prerequisites.
|
|
185
|
+
* `executeSubtask` may throw before its `pending -> running` claim (an
|
|
186
|
+
* unresolvable recipe) or after it (a transient child fault). Leaving either
|
|
187
|
+
* behind strands the row in a non-terminal state that nobody is coming back
|
|
188
|
+
* to resolve.
|
|
235
189
|
*
|
|
236
190
|
* Returns false once the row is terminal — a late loser to the real result.
|
|
237
191
|
*/
|
|
@@ -242,10 +196,6 @@ export function makeSubtasks(db, opts) {
|
|
|
242
196
|
completedAt: Date.now()
|
|
243
197
|
});
|
|
244
198
|
},
|
|
245
|
-
/** Skip a Subtask blocked by a failed/skipped dependency: guarded `pending -> skipped`. */
|
|
246
|
-
skip(id) {
|
|
247
|
-
return transition(id, "pending", { status: "skipped" });
|
|
248
|
-
},
|
|
249
199
|
/**
|
|
250
200
|
* Discard a late result after parent cancellation: guarded
|
|
251
201
|
* `running -> canceled`. The parent calls this when a child returned a
|
|
@@ -264,12 +214,19 @@ export function makeSubtasks(db, opts) {
|
|
|
264
214
|
* Running Subtasks are left alone here — the parent transitions those with
|
|
265
215
|
* {@link cancelRunning} once their in-flight result comes back and is
|
|
266
216
|
* discarded. Returns the number canceled.
|
|
217
|
+
*
|
|
218
|
+
* Keyed on the Task rather than one id, so this is the one guarded
|
|
219
|
+
* transition that cannot go through {@link transition} and sets its own
|
|
220
|
+
* timestamps. `completedAt` is part of that and not optional: every other
|
|
221
|
+
* terminal write records it, and a terminal row without one reads as still
|
|
222
|
+
* in flight to anything measuring how long a Subtask took or when a Task
|
|
223
|
+
* actually stopped.
|
|
267
224
|
*/
|
|
268
225
|
cancelPending(taskId) {
|
|
269
226
|
const now = Date.now();
|
|
270
227
|
const canceled = db
|
|
271
228
|
.update(subtasks)
|
|
272
|
-
.set({ status: "canceled", updatedAt: now })
|
|
229
|
+
.set({ status: "canceled", updatedAt: now, completedAt: now })
|
|
273
230
|
.where(and(eq(subtasks.taskId, taskId), eq(subtasks.status, "pending")))
|
|
274
231
|
.returning({ id: subtasks.id })
|
|
275
232
|
.all();
|
|
@@ -282,4 +239,3 @@ export function makeSubtasks(db, opts) {
|
|
|
282
239
|
}
|
|
283
240
|
};
|
|
284
241
|
}
|
|
285
|
-
//# sourceMappingURL=subtasks.js.map
|
package/dist/db/models/tasks.js
CHANGED