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