@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.
- package/LICENSE +674 -0
- package/README.md +279 -0
- package/dist/a2a/agent-stub.d.ts +61 -0
- package/dist/a2a/agent-stub.d.ts.map +1 -0
- package/dist/a2a/agent-stub.js +2 -0
- package/dist/a2a/agent-stub.js.map +1 -0
- package/dist/a2a/card.d.ts +119 -0
- package/dist/a2a/card.d.ts.map +1 -0
- package/dist/a2a/card.js +115 -0
- package/dist/a2a/card.js.map +1 -0
- package/dist/a2a/context.d.ts +14 -0
- package/dist/a2a/context.d.ts.map +1 -0
- package/dist/a2a/context.js +55 -0
- package/dist/a2a/context.js.map +1 -0
- package/dist/a2a/executor.d.ts +85 -0
- package/dist/a2a/executor.d.ts.map +1 -0
- package/dist/a2a/executor.js +107 -0
- package/dist/a2a/executor.js.map +1 -0
- package/dist/a2a/index.d.ts +18 -0
- package/dist/a2a/index.d.ts.map +1 -0
- package/dist/a2a/index.js +17 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/a2a/notify.d.ts +75 -0
- package/dist/a2a/notify.d.ts.map +1 -0
- package/dist/a2a/notify.js +161 -0
- package/dist/a2a/notify.js.map +1 -0
- package/dist/a2a/parts.d.ts +46 -0
- package/dist/a2a/parts.d.ts.map +1 -0
- package/dist/a2a/parts.js +95 -0
- package/dist/a2a/parts.js.map +1 -0
- package/dist/a2a/task-store.d.ts +45 -0
- package/dist/a2a/task-store.d.ts.map +1 -0
- package/dist/a2a/task-store.js +100 -0
- package/dist/a2a/task-store.js.map +1 -0
- package/dist/a2a/task.d.ts +86 -0
- package/dist/a2a/task.d.ts.map +1 -0
- package/dist/a2a/task.js +16 -0
- package/dist/a2a/task.js.map +1 -0
- package/dist/a2a/verify.d.ts +64 -0
- package/dist/a2a/verify.d.ts.map +1 -0
- package/dist/a2a/verify.js +122 -0
- package/dist/a2a/verify.js.map +1 -0
- package/dist/agent/budget.d.ts +47 -0
- package/dist/agent/budget.d.ts.map +1 -0
- package/dist/agent/budget.js +43 -0
- package/dist/agent/budget.js.map +1 -0
- package/dist/agent/control.d.ts +110 -0
- package/dist/agent/control.d.ts.map +1 -0
- package/dist/agent/control.js +115 -0
- package/dist/agent/control.js.map +1 -0
- package/dist/agent/final-reply.d.ts +49 -0
- package/dist/agent/final-reply.d.ts.map +1 -0
- package/dist/agent/final-reply.js +52 -0
- package/dist/agent/final-reply.js.map +1 -0
- package/dist/agent/history.d.ts +83 -0
- package/dist/agent/history.d.ts.map +1 -0
- package/dist/agent/history.js +117 -0
- package/dist/agent/history.js.map +1 -0
- package/dist/agent/index.d.ts +17 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +17 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/inference.d.ts +52 -0
- package/dist/agent/inference.d.ts.map +1 -0
- package/dist/agent/inference.js +79 -0
- package/dist/agent/inference.js.map +1 -0
- package/dist/agent/model.d.ts +75 -0
- package/dist/agent/model.d.ts.map +1 -0
- package/dist/agent/model.js +62 -0
- package/dist/agent/model.js.map +1 -0
- package/dist/agent/session.d.ts +92 -0
- package/dist/agent/session.d.ts.map +1 -0
- package/dist/agent/session.js +80 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/config.d.ts +159 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +92 -0
- package/dist/config.js.map +1 -0
- package/dist/contract/index.d.ts +10 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +9 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/contract/plugin.d.ts +163 -0
- package/dist/contract/plugin.d.ts.map +1 -0
- package/dist/contract/plugin.js +39 -0
- package/dist/contract/plugin.js.map +1 -0
- package/dist/contract/recipe.d.ts +170 -0
- package/dist/contract/recipe.d.ts.map +1 -0
- package/dist/contract/recipe.js +2 -0
- package/dist/contract/recipe.js.map +1 -0
- package/dist/contract/validation.d.ts +86 -0
- package/dist/contract/validation.d.ts.map +1 -0
- package/dist/contract/validation.js +76 -0
- package/dist/contract/validation.js.map +1 -0
- package/dist/db/db.d.ts +131 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +91 -0
- package/dist/db/db.js.map +1 -0
- package/dist/db/index.d.ts +9 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +9 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrations/index.d.ts +21 -0
- package/dist/db/migrations/index.d.ts.map +1 -0
- package/dist/db/migrations/index.js +54 -0
- package/dist/db/migrations/index.js.map +1 -0
- package/dist/db/models/subtasks.d.ts +102 -0
- package/dist/db/models/subtasks.d.ts.map +1 -0
- package/dist/db/models/subtasks.js +285 -0
- package/dist/db/models/subtasks.js.map +1 -0
- package/dist/db/models/tasks.d.ts +92 -0
- package/dist/db/models/tasks.d.ts.map +1 -0
- package/dist/db/models/tasks.js +212 -0
- package/dist/db/models/tasks.js.map +1 -0
- package/dist/db/schema.d.ts +488 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +91 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/env.d.ts +46 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +40 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +47 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +47 -0
- package/dist/platform.js.map +1 -0
- package/dist/runtime/index.d.ts +86 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +123 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/tool-families.d.ts +33 -0
- package/dist/runtime/tool-families.d.ts.map +1 -0
- package/dist/runtime/tool-families.js +62 -0
- package/dist/runtime/tool-families.js.map +1 -0
- package/dist/subagent/fingerprint.d.ts +38 -0
- package/dist/subagent/fingerprint.d.ts.map +1 -0
- package/dist/subagent/fingerprint.js +97 -0
- package/dist/subagent/fingerprint.js.map +1 -0
- package/dist/subagent/index.d.ts +147 -0
- package/dist/subagent/index.d.ts.map +1 -0
- package/dist/subagent/index.js +299 -0
- package/dist/subagent/index.js.map +1 -0
- package/dist/subagent/prompt.d.ts +34 -0
- package/dist/subagent/prompt.d.ts.map +1 -0
- package/dist/subagent/prompt.js +46 -0
- package/dist/subagent/prompt.js.map +1 -0
- package/dist/subagent/run.d.ts +151 -0
- package/dist/subagent/run.d.ts.map +1 -0
- package/dist/subagent/run.js +491 -0
- package/dist/subagent/run.js.map +1 -0
- package/dist/subagent/workspace.d.ts +65 -0
- package/dist/subagent/workspace.d.ts.map +1 -0
- package/dist/subagent/workspace.js +53 -0
- package/dist/subagent/workspace.js.map +1 -0
- package/dist/subtasks/catalog.d.ts +40 -0
- package/dist/subtasks/catalog.d.ts.map +1 -0
- package/dist/subtasks/catalog.js +36 -0
- package/dist/subtasks/catalog.js.map +1 -0
- package/dist/subtasks/decomposition.d.ts +90 -0
- package/dist/subtasks/decomposition.d.ts.map +1 -0
- package/dist/subtasks/decomposition.js +205 -0
- package/dist/subtasks/decomposition.js.map +1 -0
- package/dist/subtasks/delegate.d.ts +77 -0
- package/dist/subtasks/delegate.d.ts.map +1 -0
- package/dist/subtasks/delegate.js +102 -0
- package/dist/subtasks/delegate.js.map +1 -0
- package/dist/subtasks/index.d.ts +11 -0
- package/dist/subtasks/index.d.ts.map +1 -0
- package/dist/subtasks/index.js +11 -0
- package/dist/subtasks/index.js.map +1 -0
- package/dist/subtasks/scheduler.d.ts +49 -0
- package/dist/subtasks/scheduler.d.ts.map +1 -0
- package/dist/subtasks/scheduler.js +48 -0
- package/dist/subtasks/scheduler.js.map +1 -0
- package/dist/subtasks/subtask-types.d.ts +100 -0
- package/dist/subtasks/subtask-types.d.ts.map +1 -0
- package/dist/subtasks/subtask-types.js +111 -0
- package/dist/subtasks/subtask-types.js.map +1 -0
- package/dist/subtasks/types.d.ts +321 -0
- package/dist/subtasks/types.d.ts.map +1 -0
- package/dist/subtasks/types.js +16 -0
- package/dist/subtasks/types.js.map +1 -0
- package/dist/testing/auth.d.ts +12 -0
- package/dist/testing/auth.d.ts.map +1 -0
- package/dist/testing/auth.js +25 -0
- package/dist/testing/auth.js.map +1 -0
- package/dist/testing/do.d.ts +30 -0
- package/dist/testing/do.d.ts.map +1 -0
- package/dist/testing/do.js +26 -0
- package/dist/testing/do.js.map +1 -0
- package/dist/testing/fake-session.d.ts +27 -0
- package/dist/testing/fake-session.d.ts.map +1 -0
- package/dist/testing/fake-session.js +38 -0
- package/dist/testing/fake-session.js.map +1 -0
- package/dist/testing/fixtures.d.ts +27 -0
- package/dist/testing/fixtures.d.ts.map +1 -0
- package/dist/testing/fixtures.js +67 -0
- package/dist/testing/fixtures.js.map +1 -0
- package/dist/testing/index.d.ts +31 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +31 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-model.d.ts +43 -0
- package/dist/testing/mock-model.d.ts.map +1 -0
- package/dist/testing/mock-model.js +62 -0
- package/dist/testing/mock-model.js.map +1 -0
- package/dist/testing/node.d.ts +24 -0
- package/dist/testing/node.d.ts.map +1 -0
- package/dist/testing/node.js +24 -0
- package/dist/testing/node.js.map +1 -0
- package/dist/testing/vcr-global-setup.d.ts +3 -0
- package/dist/testing/vcr-global-setup.d.ts.map +1 -0
- package/dist/testing/vcr-global-setup.js +9 -0
- package/dist/testing/vcr-global-setup.js.map +1 -0
- package/dist/testing/vcr-shared.d.ts +21 -0
- package/dist/testing/vcr-shared.d.ts.map +1 -0
- package/dist/testing/vcr-shared.js +21 -0
- package/dist/testing/vcr-shared.js.map +1 -0
- package/dist/testing/vcr-spec.d.ts +17 -0
- package/dist/testing/vcr-spec.d.ts.map +1 -0
- package/dist/testing/vcr-spec.js +72 -0
- package/dist/testing/vcr-spec.js.map +1 -0
- package/dist/testing/vcr.d.ts +81 -0
- package/dist/testing/vcr.d.ts.map +1 -0
- package/dist/testing/vcr.js +211 -0
- package/dist/testing/vcr.js.map +1 -0
- package/dist/worker/index.d.ts +62 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +194 -0
- package/dist/worker/index.js.map +1 -0
- package/eslint-rules/index.js +31 -0
- package/eslint-rules/no-deprecated-object-properties.js +81 -0
- package/package.json +147 -0
- package/scripts/generate-keys.mjs +53 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge a recipe's declared budget over the baseline, per field. A positive
|
|
3
|
+
* integer wins; anything else — missing, null, zero, fractional — falls back to
|
|
4
|
+
* the baseline rather than reaching the runner.
|
|
5
|
+
*
|
|
6
|
+
* The baseline is a default, not a ceiling: a recipe may declare a budget larger
|
|
7
|
+
* than the baseline and it is honored — sizing its own branch is what declaring
|
|
8
|
+
* `limits` is for, so nothing here clamps. What the merge buys, as
|
|
9
|
+
* defense-in-depth for a recipe that ever comes from data rather than code, is
|
|
10
|
+
* that a corrupt or absent value cannot reach the runner as a zero, fractional,
|
|
11
|
+
* or missing budget.
|
|
12
|
+
*
|
|
13
|
+
* Exported separately from {@link validateRecipe} because it must never throw.
|
|
14
|
+
*/
|
|
15
|
+
export function resolveLimits(limits, baseline) {
|
|
16
|
+
const positiveInt = (n, fallback) => typeof n === "number" && Number.isInteger(n) && n > 0 ? n : fallback;
|
|
17
|
+
return {
|
|
18
|
+
maxTurns: positiveInt(limits?.maxTurns, baseline.maxTurns),
|
|
19
|
+
maxWallMs: positiveInt(limits?.maxWallMs, baseline.maxWallMs)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Thrown by {@link validateRecipe} for a recipe that is unusable as given — it
|
|
24
|
+
* is disabled, carries no soul, or states no history window. All are
|
|
25
|
+
* deterministic caller bugs (the parent must only hand enabled, complete recipes
|
|
26
|
+
* to a subagent), so the child maps this to a terminal failed result rather than
|
|
27
|
+
* retrying.
|
|
28
|
+
*/
|
|
29
|
+
export class RecipeValidationError extends Error {
|
|
30
|
+
constructor(message) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.name = "RecipeValidationError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Code-owned defensive validation of an already-resolved recipe. Returns a
|
|
37
|
+
* normalized copy (never mutates the input): a model id outside the policy's
|
|
38
|
+
* allowlist is substituted with the default for its slot — independently per
|
|
39
|
+
* slot — and unknown tool families are dropped (deduped, order-preserving).
|
|
40
|
+
* Applied by the parent when it resolves a recipe and re-applied by the subagent
|
|
41
|
+
* on its inbound request, so recipe data can never select arbitrary models or
|
|
42
|
+
* tools.
|
|
43
|
+
*
|
|
44
|
+
* The split between what is normalized and what is refused follows one rule:
|
|
45
|
+
* **the host declares a baseline ⇒ merge; it does not ⇒ require.** `limits`
|
|
46
|
+
* merge. A soul and a `historyWindow` do not: substituting a generic soul would
|
|
47
|
+
* run the work under an identity nobody declared — the model would answer,
|
|
48
|
+
* plausibly, as something other than what the recipe is for — and how much
|
|
49
|
+
* context a domain needs is likewise a property of the domain, not something a
|
|
50
|
+
* house default can guess. Both fail the recipe outright.
|
|
51
|
+
*/
|
|
52
|
+
export function validateRecipe(recipe, policy) {
|
|
53
|
+
if (!recipe.enabled) {
|
|
54
|
+
throw new RecipeValidationError(`recipe "${recipe.key}" (v${recipe.version}) is disabled`);
|
|
55
|
+
}
|
|
56
|
+
if (recipe.soul.trim() === "") {
|
|
57
|
+
throw new RecipeValidationError(`recipe "${recipe.key}" (v${recipe.version}) has no soul`);
|
|
58
|
+
}
|
|
59
|
+
if (!Number.isInteger(recipe.historyWindow) || recipe.historyWindow <= 0) {
|
|
60
|
+
throw new RecipeValidationError(`recipe "${recipe.key}" (v${recipe.version}) has no usable historyWindow ` +
|
|
61
|
+
`(got ${recipe.historyWindow}); every recipe states its own`);
|
|
62
|
+
}
|
|
63
|
+
const toolFamilies = [...new Set(recipe.toolFamilies)].filter((family) => policy.knownToolFamilies.has(family));
|
|
64
|
+
return {
|
|
65
|
+
...recipe,
|
|
66
|
+
primaryModelId: policy.modelAllowlist.has(recipe.primaryModelId)
|
|
67
|
+
? recipe.primaryModelId
|
|
68
|
+
: policy.defaultPrimaryModelId,
|
|
69
|
+
fallbackModelId: policy.modelAllowlist.has(recipe.fallbackModelId)
|
|
70
|
+
? recipe.fallbackModelId
|
|
71
|
+
: policy.defaultFallbackModelId,
|
|
72
|
+
toolFamilies,
|
|
73
|
+
limits: resolveLimits(recipe.limits, policy.baselineLimits)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/contract/validation.ts"],"names":[],"mappings":"AA4CA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAC3B,MAA4B,EAC5B,QAAqB;IAErB,MAAM,WAAW,GAAG,CAAC,CAAqB,EAAE,QAAgB,EAAU,EAAE,CACtE,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACvE,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC;QAC1D,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC;KAC9D,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAsB,EACtB,MAAoB;IAEpB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,qBAAqB,CAC7B,WAAW,MAAM,CAAC,GAAG,OAAO,MAAM,CAAC,OAAO,eAAe,CAC1D,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9B,MAAM,IAAI,qBAAqB,CAC7B,WAAW,MAAM,CAAC,GAAG,OAAO,MAAM,CAAC,OAAO,eAAe,CAC1D,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,aAAa,IAAI,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,qBAAqB,CAC7B,WAAW,MAAM,CAAC,GAAG,OAAO,MAAM,CAAC,OAAO,gCAAgC;YACxE,QAAQ,MAAM,CAAC,aAAa,gCAAgC,CAC/D,CAAC;IACJ,CAAC;IACD,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CACvE,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CACrC,CAAC;IACF,OAAO;QACL,GAAG,MAAM;QACT,cAAc,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC;YAC9D,CAAC,CAAC,MAAM,CAAC,cAAc;YACvB,CAAC,CAAC,MAAM,CAAC,qBAAqB;QAChC,eAAe,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC;YAChE,CAAC,CAAC,MAAM,CAAC,eAAe;YACxB,CAAC,CAAC,MAAM,CAAC,sBAAsB;QACjC,YAAY;QACZ,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;KAC5D,CAAC;AACJ,CAAC"}
|
package/dist/db/db.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { type DrizzleSqliteDODatabase } from "drizzle-orm/durable-sqlite";
|
|
2
|
+
import * as schema from "./schema.js";
|
|
3
|
+
export type DB = DrizzleSqliteDODatabase<typeof schema>;
|
|
4
|
+
/**
|
|
5
|
+
* A table owner outside core's migration journal.
|
|
6
|
+
*
|
|
7
|
+
* Drizzle's durable-sqlite migrator keeps **one flat integer journal** and one
|
|
8
|
+
* global `__drizzle_migrations` table. Two independently-versioned npm packages
|
|
9
|
+
* cannot share that index space — and this is not hypothetical: the two
|
|
10
|
+
* predecessor agents, both consuming the same `notify_tasks` module, had already
|
|
11
|
+
* forked the journal at index 1 (`0001_unusual_nova` vs `0001_great_goliath`).
|
|
12
|
+
* Worse, `drizzle-kit generate` diffs against a snapshot in one output
|
|
13
|
+
* directory, so a plugin shipping from its own repo cannot produce a correct
|
|
14
|
+
* diff at all.
|
|
15
|
+
*
|
|
16
|
+
* So a plugin never touches core's journal. It implements this instead:
|
|
17
|
+
* idempotent `CREATE TABLE IF NOT EXISTS` DDL, plus its own version bookkeeping
|
|
18
|
+
* in the {@link PLUGIN_MIGRATIONS_TABLE} row this class manages for it. That
|
|
19
|
+
* pattern is not novel here — it is what the subagent facet already does for its
|
|
20
|
+
* own two tables.
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* const scorecardStore: PluginStore = {
|
|
24
|
+
* plugin: "arc-agi",
|
|
25
|
+
* version: 2,
|
|
26
|
+
* ensureTables(sql, from) {
|
|
27
|
+
* sql.exec(`CREATE TABLE IF NOT EXISTS arc_scorecards (…)`);
|
|
28
|
+
* if (from < 2) sql.exec(`ALTER TABLE arc_scorecards ADD COLUMN …`);
|
|
29
|
+
* }
|
|
30
|
+
* };
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export interface PluginStore {
|
|
34
|
+
/** Stable identifier. Also the bookkeeping row's key — never rename it. */
|
|
35
|
+
plugin: string;
|
|
36
|
+
/**
|
|
37
|
+
* Monotonically increasing schema version, starting at 1. Bump it whenever
|
|
38
|
+
* {@link ensureTables} needs to do something it did not do before.
|
|
39
|
+
*/
|
|
40
|
+
version: number;
|
|
41
|
+
/**
|
|
42
|
+
* Bring this plugin's tables up to {@link version}.
|
|
43
|
+
*
|
|
44
|
+
* Called once per DO instance, and re-called on every hibernation wake-up, so
|
|
45
|
+
* it **must be idempotent**. `from` is the version last recorded for this
|
|
46
|
+
* plugin (0 on first ever run), which is what lets an upgrade path branch
|
|
47
|
+
* without re-running earlier DDL.
|
|
48
|
+
*/
|
|
49
|
+
ensureTables(sql: SqlStorage, from: number): void;
|
|
50
|
+
}
|
|
51
|
+
/** Bookkeeping for {@link PluginStore} versions. Core owns the table; plugins own their rows. */
|
|
52
|
+
export declare const PLUGIN_MIGRATIONS_TABLE = "plugin_migrations";
|
|
53
|
+
export interface AgentDBOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Plugin-owned stores to bring up alongside core's own tables. Order is
|
|
56
|
+
* preserved but must not matter: a plugin that depends on another plugin's
|
|
57
|
+
* table is a plugin that should have been one plugin.
|
|
58
|
+
*/
|
|
59
|
+
stores?: readonly PluginStore[];
|
|
60
|
+
/**
|
|
61
|
+
* `CoreConfig.maxSubtasks` — the durable guard `createDecomposition` enforces.
|
|
62
|
+
* Passed rather than imported so one resolved config governs both the schema
|
|
63
|
+
* offered to the model and the write that has to hold.
|
|
64
|
+
*/
|
|
65
|
+
maxSubtasks: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The agent's database: one drizzle handle over the DO's SQLite, with a memoized
|
|
69
|
+
* namespace per table domain (`db.tasks`, `db.subtasks`).
|
|
70
|
+
*
|
|
71
|
+
* Constructed once per DO instance. Core's migrations run in the constructor —
|
|
72
|
+
* the durable-sqlite migrator is idempotent, so a fresh `AgentDB` on every
|
|
73
|
+
* hibernation wake-up re-validates the schema safely. Call `ensureReady()` (and
|
|
74
|
+
* await it) before issuing any queries.
|
|
75
|
+
*
|
|
76
|
+
* Plugin stores are brought up in the same place but through a different
|
|
77
|
+
* mechanism, deliberately — see {@link PluginStore}.
|
|
78
|
+
*/
|
|
79
|
+
export declare class AgentDB {
|
|
80
|
+
private readonly storage;
|
|
81
|
+
private readonly options;
|
|
82
|
+
private readonly db;
|
|
83
|
+
private readonly _ready;
|
|
84
|
+
private _tasks?;
|
|
85
|
+
private _subtasks?;
|
|
86
|
+
constructor(storage: DurableObjectStorage, options: AgentDBOptions);
|
|
87
|
+
ensureReady(): Promise<void>;
|
|
88
|
+
get tasks(): {
|
|
89
|
+
begin(input: {
|
|
90
|
+
messageId: string;
|
|
91
|
+
taskId: string;
|
|
92
|
+
contextId: string;
|
|
93
|
+
}): import("../a2a/task.js").PlainTask;
|
|
94
|
+
get(taskId: string): import("../a2a/task.js").PlainTask | null;
|
|
95
|
+
list(query: import("./index.js").TaskListQuery): {
|
|
96
|
+
tasks: import("../a2a/task.js").PlainTask[];
|
|
97
|
+
totalSize: number;
|
|
98
|
+
};
|
|
99
|
+
save(task: import("@a2a-js/sdk").Task): boolean;
|
|
100
|
+
markWorking(taskId: string): "ok" | "canceled";
|
|
101
|
+
cancel(taskId: string): import("../a2a/task.js").PlainTask | null;
|
|
102
|
+
cleanup(): void;
|
|
103
|
+
};
|
|
104
|
+
get subtasks(): {
|
|
105
|
+
createDecomposition(taskId: string, round: number, drafts: import("../subtasks/types.js").SubtaskDraft[]): import("../subtasks/types.js").Subtask[];
|
|
106
|
+
get(id: import("../subtasks/types.js").SubtaskId): import("../subtasks/types.js").Subtask | null;
|
|
107
|
+
list(taskId: string): import("../subtasks/types.js").Subtask[];
|
|
108
|
+
listRound(taskId: string, round: number): import("../subtasks/types.js").Subtask[];
|
|
109
|
+
start(id: import("../subtasks/types.js").SubtaskId, recipe: {
|
|
110
|
+
recipeId: string;
|
|
111
|
+
recipeVersion: number;
|
|
112
|
+
}): boolean;
|
|
113
|
+
complete(id: import("../subtasks/types.js").SubtaskId, resultParts: import("../subtasks/types.js").SubtaskResultPart[]): boolean;
|
|
114
|
+
fail(id: import("../subtasks/types.js").SubtaskId, error: string): boolean;
|
|
115
|
+
skip(id: import("../subtasks/types.js").SubtaskId): boolean;
|
|
116
|
+
cancelRunning(id: import("../subtasks/types.js").SubtaskId): boolean;
|
|
117
|
+
cancelPending(taskId: string): number;
|
|
118
|
+
cleanup(): void;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Run each plugin store's DDL and record its version, after core's own
|
|
122
|
+
* migrations so a plugin may safely reference core tables (nothing should, but
|
|
123
|
+
* the ordering is free and the alternative is a surprising failure).
|
|
124
|
+
*
|
|
125
|
+
* A store that throws fails DO start rather than being skipped: a plugin whose
|
|
126
|
+
* tables are missing would otherwise fail later, at its first tool call, in a
|
|
127
|
+
* request the user is waiting on.
|
|
128
|
+
*/
|
|
129
|
+
private applyStores;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAKtC,MAAM,MAAM,EAAE,GAAG,uBAAuB,CAAC,OAAO,MAAM,CAAC,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACnD;AAED,iGAAiG;AACjG,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IAChC;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,OAAO;IAOhB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,MAAM,CAAC,CAA+B;IAC9C,OAAO,CAAC,SAAS,CAAC,CAAkC;gBAGjC,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,cAAc;IAQ1C,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,IAAI,KAAK;;;;;;;;;;;;;;;MAER;IAED,IAAI,QAAQ;;;;;;;;;;;;;;;MAIX;IAED;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;CAsDpB"}
|
package/dist/db/db.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { drizzle } from "drizzle-orm/durable-sqlite";
|
|
2
|
+
import { migrate } from "drizzle-orm/durable-sqlite/migrator";
|
|
3
|
+
import * as schema from "./schema.js";
|
|
4
|
+
import dbMigrations from "./migrations/index.js";
|
|
5
|
+
import { makeTasks } from "./models/tasks.js";
|
|
6
|
+
import { makeSubtasks } from "./models/subtasks.js";
|
|
7
|
+
/** Bookkeeping for {@link PluginStore} versions. Core owns the table; plugins own their rows. */
|
|
8
|
+
export const PLUGIN_MIGRATIONS_TABLE = "plugin_migrations";
|
|
9
|
+
/**
|
|
10
|
+
* The agent's database: one drizzle handle over the DO's SQLite, with a memoized
|
|
11
|
+
* namespace per table domain (`db.tasks`, `db.subtasks`).
|
|
12
|
+
*
|
|
13
|
+
* Constructed once per DO instance. Core's migrations run in the constructor —
|
|
14
|
+
* the durable-sqlite migrator is idempotent, so a fresh `AgentDB` on every
|
|
15
|
+
* hibernation wake-up re-validates the schema safely. Call `ensureReady()` (and
|
|
16
|
+
* await it) before issuing any queries.
|
|
17
|
+
*
|
|
18
|
+
* Plugin stores are brought up in the same place but through a different
|
|
19
|
+
* mechanism, deliberately — see {@link PluginStore}.
|
|
20
|
+
*/
|
|
21
|
+
export class AgentDB {
|
|
22
|
+
storage;
|
|
23
|
+
options;
|
|
24
|
+
db;
|
|
25
|
+
_ready;
|
|
26
|
+
_tasks;
|
|
27
|
+
_subtasks;
|
|
28
|
+
constructor(storage, options) {
|
|
29
|
+
this.storage = storage;
|
|
30
|
+
this.options = options;
|
|
31
|
+
this.db = drizzle(storage, { schema });
|
|
32
|
+
this._ready = migrate(this.db, dbMigrations).then(() => {
|
|
33
|
+
this.applyStores(options.stores ?? []);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
ensureReady() {
|
|
37
|
+
return this._ready;
|
|
38
|
+
}
|
|
39
|
+
get tasks() {
|
|
40
|
+
return (this._tasks ??= makeTasks(this.db));
|
|
41
|
+
}
|
|
42
|
+
get subtasks() {
|
|
43
|
+
return (this._subtasks ??= makeSubtasks(this.db, {
|
|
44
|
+
maxSubtasks: this.options.maxSubtasks
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Run each plugin store's DDL and record its version, after core's own
|
|
49
|
+
* migrations so a plugin may safely reference core tables (nothing should, but
|
|
50
|
+
* the ordering is free and the alternative is a surprising failure).
|
|
51
|
+
*
|
|
52
|
+
* A store that throws fails DO start rather than being skipped: a plugin whose
|
|
53
|
+
* tables are missing would otherwise fail later, at its first tool call, in a
|
|
54
|
+
* request the user is waiting on.
|
|
55
|
+
*/
|
|
56
|
+
applyStores(stores) {
|
|
57
|
+
if (stores.length === 0)
|
|
58
|
+
return;
|
|
59
|
+
const sql = this.storage.sql;
|
|
60
|
+
sql.exec(`CREATE TABLE IF NOT EXISTS ${PLUGIN_MIGRATIONS_TABLE} (
|
|
61
|
+
plugin TEXT PRIMARY KEY,
|
|
62
|
+
version INTEGER NOT NULL,
|
|
63
|
+
updated_at INTEGER NOT NULL
|
|
64
|
+
)`);
|
|
65
|
+
const seen = new Set();
|
|
66
|
+
for (const store of stores) {
|
|
67
|
+
if (seen.has(store.plugin)) {
|
|
68
|
+
throw new Error(`duplicate PluginStore '${store.plugin}' — two plugins claim the same storage namespace`);
|
|
69
|
+
}
|
|
70
|
+
seen.add(store.plugin);
|
|
71
|
+
if (!Number.isInteger(store.version) || store.version < 1) {
|
|
72
|
+
throw new Error(`PluginStore '${store.plugin}' version must be an integer >= 1, got ${store.version}`);
|
|
73
|
+
}
|
|
74
|
+
const row = sql
|
|
75
|
+
.exec(`SELECT version FROM ${PLUGIN_MIGRATIONS_TABLE} WHERE plugin = ?`, store.plugin)
|
|
76
|
+
.toArray()[0];
|
|
77
|
+
const from = row?.version ?? 0;
|
|
78
|
+
if (from > store.version) {
|
|
79
|
+
throw new Error(`PluginStore '${store.plugin}' is at version ${from} on disk but the ` +
|
|
80
|
+
`installed plugin declares ${store.version} — downgrade is not supported`);
|
|
81
|
+
}
|
|
82
|
+
store.ensureTables(sql, from);
|
|
83
|
+
if (from !== store.version) {
|
|
84
|
+
sql.exec(`INSERT INTO ${PLUGIN_MIGRATIONS_TABLE} (plugin, version, updated_at)
|
|
85
|
+
VALUES (?, ?, ?)
|
|
86
|
+
ON CONFLICT(plugin) DO UPDATE SET version = excluded.version, updated_at = excluded.updated_at`, store.plugin, store.version, Date.now());
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@loopingai/core/db` — the two tables core owns, and the seam a plugin uses to
|
|
3
|
+
* own its own without touching core's migration journal.
|
|
4
|
+
*/
|
|
5
|
+
export { AgentDB, PLUGIN_MIGRATIONS_TABLE, type AgentDBOptions, type DB, type PluginStore } from "./db.js";
|
|
6
|
+
export { notifyTasks, subtasks } from "./schema.js";
|
|
7
|
+
export { makeTasks, stateOf, type TaskListQuery } from "./models/tasks.js";
|
|
8
|
+
export { makeSubtasks, type SubtaskModelOptions } from "./models/subtasks.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,OAAO,EACP,uBAAuB,EACvB,KAAK,cAAc,EACnB,KAAK,EAAE,EACP,KAAK,WAAW,EACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE3E,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/db/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@loopingai/core/db` — the two tables core owns, and the seam a plugin uses to
|
|
3
|
+
* own its own without touching core's migration journal.
|
|
4
|
+
*/
|
|
5
|
+
export { AgentDB, PLUGIN_MIGRATIONS_TABLE } from "./db.js";
|
|
6
|
+
export { notifyTasks, subtasks } from "./schema.js";
|
|
7
|
+
export { makeTasks, stateOf } from "./models/tasks.js";
|
|
8
|
+
export { makeSubtasks } from "./models/subtasks.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,OAAO,EACP,uBAAuB,EAIxB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAsB,MAAM,mBAAmB,CAAC;AAE3E,OAAO,EAAE,YAAY,EAA4B,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drizzle migrations, inlined for Cloudflare Workers.
|
|
3
|
+
*
|
|
4
|
+
* GENERATED FILE — do not edit. Run `npm run db:generate` after changing
|
|
5
|
+
* `src/db/schema.ts`; that runs `drizzle-kit generate` and then
|
|
6
|
+
* `scripts/build-migrations.mjs`, which rebuilds this from
|
|
7
|
+
* `meta/_journal.json` and the `.sql` files beside it.
|
|
8
|
+
*
|
|
9
|
+
* Key format: "m{zero-padded idx}" — what drizzle's durable-sqlite migrator
|
|
10
|
+
* reads from `config.migrations[key]`.
|
|
11
|
+
*
|
|
12
|
+
* This journal is CORE's alone. A plugin must never add an entry: the journal is
|
|
13
|
+
* a flat integer sequence over one shared `__drizzle_migrations` table, and two
|
|
14
|
+
* independently-versioned packages writing to it will collide. Plugins own their
|
|
15
|
+
* tables through `PluginStore` instead — see `src/db/db.ts`.
|
|
16
|
+
*/
|
|
17
|
+
import type { migrate } from "drizzle-orm/durable-sqlite/migrator";
|
|
18
|
+
type MigrationConfig = Parameters<typeof migrate>[1];
|
|
19
|
+
declare const dbMigrations: MigrationConfig;
|
|
20
|
+
export default dbMigrations;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/db/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAC;AAEnE,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAErD,QAAA,MAAM,YAAY,EAAE,eAmDnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const dbMigrations = {
|
|
2
|
+
journal: {
|
|
3
|
+
entries: [
|
|
4
|
+
{
|
|
5
|
+
idx: 0,
|
|
6
|
+
when: 1785537420937,
|
|
7
|
+
tag: "0000_init",
|
|
8
|
+
breakpoints: true
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
migrations: {
|
|
13
|
+
m0000: `CREATE TABLE \`notify_tasks\` (
|
|
14
|
+
\`task_id\` text PRIMARY KEY NOT NULL,
|
|
15
|
+
\`message_id\` text,
|
|
16
|
+
\`context_id\` text DEFAULT '' NOT NULL,
|
|
17
|
+
\`state\` text NOT NULL,
|
|
18
|
+
\`task_json\` text NOT NULL,
|
|
19
|
+
\`created_at\` integer NOT NULL,
|
|
20
|
+
\`updated_at\` integer NOT NULL
|
|
21
|
+
);
|
|
22
|
+
--> statement-breakpoint
|
|
23
|
+
CREATE UNIQUE INDEX \`notify_tasks_message_id_unique\` ON \`notify_tasks\` (\`message_id\`);--> statement-breakpoint
|
|
24
|
+
CREATE INDEX \`idx_notify_tasks_created_at\` ON \`notify_tasks\` (\`created_at\`);--> statement-breakpoint
|
|
25
|
+
CREATE INDEX \`idx_notify_tasks_context\` ON \`notify_tasks\` (\`context_id\`);--> statement-breakpoint
|
|
26
|
+
CREATE INDEX \`idx_notify_tasks_state\` ON \`notify_tasks\` (\`state\`);--> statement-breakpoint
|
|
27
|
+
CREATE TABLE \`subtasks\` (
|
|
28
|
+
\`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
29
|
+
\`task_id\` text NOT NULL,
|
|
30
|
+
\`round\` integer NOT NULL,
|
|
31
|
+
\`ordinal\` integer NOT NULL,
|
|
32
|
+
\`type\` text NOT NULL,
|
|
33
|
+
\`recipe_id\` text,
|
|
34
|
+
\`recipe_version\` integer,
|
|
35
|
+
\`prompt\` text NOT NULL,
|
|
36
|
+
\`references_json\` text NOT NULL,
|
|
37
|
+
\`depends_on_json\` text NOT NULL,
|
|
38
|
+
\`params_json\` text DEFAULT '{}' NOT NULL,
|
|
39
|
+
\`status\` text NOT NULL,
|
|
40
|
+
\`result_parts_json\` text,
|
|
41
|
+
\`error\` text,
|
|
42
|
+
\`created_at\` integer NOT NULL,
|
|
43
|
+
\`updated_at\` integer NOT NULL,
|
|
44
|
+
\`completed_at\` integer
|
|
45
|
+
);
|
|
46
|
+
--> statement-breakpoint
|
|
47
|
+
CREATE UNIQUE INDEX \`idx_subtasks_task_ordinal\` ON \`subtasks\` (\`task_id\`,\`ordinal\`);--> statement-breakpoint
|
|
48
|
+
CREATE INDEX \`idx_subtasks_task_round\` ON \`subtasks\` (\`task_id\`,\`round\`);--> statement-breakpoint
|
|
49
|
+
CREATE INDEX \`idx_subtasks_status\` ON \`subtasks\` (\`status\`);--> statement-breakpoint
|
|
50
|
+
CREATE INDEX \`idx_subtasks_created_at\` ON \`subtasks\` (\`created_at\`);`
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
export default dbMigrations;
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/db/migrations/index.ts"],"names":[],"mappings":"AAoBA,MAAM,YAAY,GAAoB;IACpC,OAAO,EAAE;QACP,OAAO,EAAE;YACP;gBACE,GAAG,EAAE,CAAC;gBACN,IAAI,EAAE,aAAa;gBACnB,GAAG,EAAE,WAAW;gBAChB,WAAW,EAAE,IAAI;aAClB;SACF;KACF;IACD,UAAU,EAAE;QACV,KAAK,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2EAqCgE;KACxE;CACF,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { DB } from "../db.js";
|
|
2
|
+
import type { Subtask, SubtaskDraft, SubtaskId, SubtaskResultPart } from "../../subtasks/types.js";
|
|
3
|
+
export interface SubtaskModelOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Upper bound on subtasks per round, re-checked here as the **durable** guard.
|
|
6
|
+
* The delegation schema offers the model the same bound, but a schema is a
|
|
7
|
+
* suggestion to a model and this is the write that has to hold.
|
|
8
|
+
*/
|
|
9
|
+
maxSubtasks: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Query methods for the `subtasks` table (durable decomposed units of work).
|
|
13
|
+
*
|
|
14
|
+
* Bound to a drizzle handle by {@link AgentDB} and reached as `db.subtasks.*`.
|
|
15
|
+
* durable-sqlite is synchronous; the multi-statement `createDecomposition` runs
|
|
16
|
+
* inside an explicit `db.transaction` (drizzle maps it to
|
|
17
|
+
* `storage.transactionSync`), so a mid-create failure rolls back every statement
|
|
18
|
+
* instead of leaving a partial DAG. Guarded transitions filter on the expected
|
|
19
|
+
* current `status`, so a disallowed transition matches no row and is a no-op.
|
|
20
|
+
*/
|
|
21
|
+
export declare function makeSubtasks(db: DB, opts: SubtaskModelOptions): {
|
|
22
|
+
/**
|
|
23
|
+
* Create one **round's** decomposition atomically: the entire
|
|
24
|
+
* check-validate-insert sequence runs in one synchronous `db.transaction`, so
|
|
25
|
+
* a failure anywhere rolls back every statement — no truncated subtask set, no
|
|
26
|
+
* nodes left with unwritten dependency edges. Idempotent on
|
|
27
|
+
* `(taskId, round)`: if this round already has Subtasks, returns them
|
|
28
|
+
* unchanged (a Workflow-step retry must not duplicate work); the unique
|
|
29
|
+
* `(task_id, ordinal)` index is the schema-level backstop. Enforces the 1..8
|
|
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.
|
|
34
|
+
*
|
|
35
|
+
* `ordinal` continues across rounds (it is the Task-wide position, and what
|
|
36
|
+
* the unique index is built on), so a later round's rows sort after the
|
|
37
|
+
* earlier ones in {@link list}. Dependency edges never cross a round: each
|
|
38
|
+
* round's DAG is self-contained, and the drafts handed here only carry keys
|
|
39
|
+
* from their own round.
|
|
40
|
+
*/
|
|
41
|
+
createDecomposition(taskId: string, round: number, drafts: SubtaskDraft[]): Subtask[];
|
|
42
|
+
/** Load one Subtask by id. */
|
|
43
|
+
get(id: SubtaskId): Subtask | null;
|
|
44
|
+
/** List every round's Subtasks for a Task, in ordinal order. */
|
|
45
|
+
list(taskId: string): Subtask[];
|
|
46
|
+
/**
|
|
47
|
+
* List one round's Subtasks, in ordinal order — the scheduler's view. Phase 2
|
|
48
|
+
* drives a single round's DAG at a time, so it must not see a sibling round's
|
|
49
|
+
* rows; composition, by contrast, reads {@link list} across all rounds.
|
|
50
|
+
*/
|
|
51
|
+
listRound(taskId: string, round: number): Subtask[];
|
|
52
|
+
/**
|
|
53
|
+
* Begin execution: guarded `pending -> running`, recording the resolved
|
|
54
|
+
* Recipe id/version after-the-fact. Returns false if the Subtask was not
|
|
55
|
+
* pending (already started, terminal, or unknown).
|
|
56
|
+
*/
|
|
57
|
+
start(id: SubtaskId, recipe: {
|
|
58
|
+
recipeId: string;
|
|
59
|
+
recipeVersion: number;
|
|
60
|
+
}): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Persist a successful terminal result: guarded `running -> completed`.
|
|
63
|
+
* Requires at least one non-empty text result part (a successful Recipe
|
|
64
|
+
* output invariant).
|
|
65
|
+
*/
|
|
66
|
+
complete(id: SubtaskId, resultParts: SubtaskResultPart[]): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Persist a failure from either non-terminal status, with a diagnostic message.
|
|
69
|
+
*
|
|
70
|
+
* Both sides are reachable and both must land. A child's failed result arrives
|
|
71
|
+
* on a `running` row. The Workflow's last resort — `failSubtask`, once
|
|
72
|
+
* `execute:<id>` has exhausted every retry — can arrive on either:
|
|
73
|
+
* `executeSubtask` may throw before its `pending -> running` claim (a
|
|
74
|
+
* dependency-invariant fault) or after it (a transient child fault). Leaving
|
|
75
|
+
* either behind strands the row: a `pending` node re-enters the next wave
|
|
76
|
+
* forever, and a `running` node blocks its dependents, which {@link skip} only
|
|
77
|
+
* propagates past *failed* prerequisites.
|
|
78
|
+
*
|
|
79
|
+
* Returns false once the row is terminal — a late loser to the real result.
|
|
80
|
+
*/
|
|
81
|
+
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
|
+
/**
|
|
85
|
+
* Discard a late result after parent cancellation: guarded
|
|
86
|
+
* `running -> canceled`. The parent calls this when a child returned a
|
|
87
|
+
* terminal result but the Task was canceled while it ran — the result is
|
|
88
|
+
* dropped, and this leaves the row in a truthful terminal state instead of a
|
|
89
|
+
* `running` that never resolves. Returns false if the Subtask was not running.
|
|
90
|
+
*/
|
|
91
|
+
cancelRunning(id: SubtaskId): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Cancel every still-pending Subtask of a Task (parent cancellation).
|
|
94
|
+
* Running Subtasks are left alone here — the parent transitions those with
|
|
95
|
+
* {@link cancelRunning} once their in-flight result comes back and is
|
|
96
|
+
* discarded. Returns the number canceled.
|
|
97
|
+
*/
|
|
98
|
+
cancelPending(taskId: string): number;
|
|
99
|
+
/** Delete Subtasks older than 30 days (called by the weekly maintenance cron). */
|
|
100
|
+
cleanup(): void;
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=subtasks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subtasks.d.ts","sourceRoot":"","sources":["../../../src/db/models/subtasks.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,EACV,OAAO,EACP,YAAY,EACZ,SAAS,EAET,iBAAiB,EAElB,MAAM,yBAAyB,CAAC;AAmBjC,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB;IAiE1D;;;;;;;;;;;;;;;;;;OAkBG;gCAEO,MAAM,SACP,MAAM,UACL,YAAY,EAAE,GACrB,OAAO,EAAE;IA+FZ,8BAA8B;YACtB,SAAS,GAAG,OAAO,GAAG,IAAI;IAKlC,gEAAgE;iBACnD,MAAM,GAAG,OAAO,EAAE;IAI/B;;;;OAIG;sBACe,MAAM,SAAS,MAAM,GAAG,OAAO,EAAE;IAInD;;;;OAIG;cAEG,SAAS,UACL;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,GAClD,OAAO;IAQV;;;;OAIG;iBACU,SAAS,eAAe,iBAAiB,EAAE,GAAG,OAAO;IAYlE;;;;;;;;;;;;;OAaG;aACM,SAAS,SAAS,MAAM,GAAG,OAAO;IAQ3C,2FAA2F;aAClF,SAAS,GAAG,OAAO;IAI5B;;;;;;OAMG;sBACe,SAAS,GAAG,OAAO;IAOrC;;;;;OAKG;0BACmB,MAAM,GAAG,MAAM;IAWrC,kFAAkF;eACvE,IAAI;EAKlB"}
|