@loopingai/core 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +83 -28
  2. package/dist/a2a/caller.d.ts +24 -0
  3. package/dist/a2a/caller.d.ts.map +1 -0
  4. package/dist/a2a/caller.js +34 -0
  5. package/dist/a2a/caller.js.map +1 -0
  6. package/dist/a2a/card.d.ts +7 -2
  7. package/dist/a2a/card.d.ts.map +1 -1
  8. package/dist/a2a/card.js +16 -7
  9. package/dist/a2a/card.js.map +1 -1
  10. package/dist/a2a/index.d.ts +15 -0
  11. package/dist/a2a/index.d.ts.map +1 -1
  12. package/dist/a2a/index.js +15 -0
  13. package/dist/a2a/index.js.map +1 -1
  14. package/dist/a2a/notify.d.ts +27 -5
  15. package/dist/a2a/notify.d.ts.map +1 -1
  16. package/dist/a2a/notify.js +18 -8
  17. package/dist/a2a/notify.js.map +1 -1
  18. package/dist/a2a/push.d.ts +71 -0
  19. package/dist/a2a/push.d.ts.map +1 -0
  20. package/dist/a2a/push.js +54 -0
  21. package/dist/a2a/push.js.map +1 -0
  22. package/dist/a2a/verify.d.ts +28 -36
  23. package/dist/a2a/verify.d.ts.map +1 -1
  24. package/dist/a2a/verify.js +20 -25
  25. package/dist/a2a/verify.js.map +1 -1
  26. package/dist/agent/index.d.ts +16 -5
  27. package/dist/agent/index.d.ts.map +1 -1
  28. package/dist/agent/index.js +16 -5
  29. package/dist/agent/index.js.map +1 -1
  30. package/dist/config.d.ts +49 -7
  31. package/dist/config.d.ts.map +1 -1
  32. package/dist/config.js +25 -3
  33. package/dist/config.js.map +1 -1
  34. package/dist/contract/recipe.d.ts +14 -2
  35. package/dist/contract/recipe.d.ts.map +1 -1
  36. package/dist/contract/validation.d.ts +22 -18
  37. package/dist/contract/validation.d.ts.map +1 -1
  38. package/dist/contract/validation.js +19 -10
  39. package/dist/contract/validation.js.map +1 -1
  40. package/dist/db/models/tasks.d.ts +19 -5
  41. package/dist/db/models/tasks.d.ts.map +1 -1
  42. package/dist/db/models/tasks.js +38 -8
  43. package/dist/db/models/tasks.js.map +1 -1
  44. package/dist/host/agent.d.ts +217 -0
  45. package/dist/host/agent.d.ts.map +1 -0
  46. package/dist/host/agent.js +304 -0
  47. package/dist/host/agent.js.map +1 -0
  48. package/dist/host/index.d.ts +21 -0
  49. package/dist/host/index.d.ts.map +1 -0
  50. package/dist/host/index.js +20 -0
  51. package/dist/host/index.js.map +1 -0
  52. package/dist/host/plugin-host.d.ts +43 -0
  53. package/dist/host/plugin-host.d.ts.map +1 -0
  54. package/dist/host/plugin-host.js +2 -0
  55. package/dist/host/plugin-host.js.map +1 -0
  56. package/dist/round/agent.d.ts +267 -0
  57. package/dist/round/agent.d.ts.map +1 -0
  58. package/dist/round/agent.js +691 -0
  59. package/dist/round/agent.js.map +1 -0
  60. package/dist/round/index.d.ts +25 -0
  61. package/dist/round/index.d.ts.map +1 -0
  62. package/dist/round/index.js +24 -0
  63. package/dist/round/index.js.map +1 -0
  64. package/dist/round/policy.d.ts +99 -0
  65. package/dist/round/policy.d.ts.map +1 -0
  66. package/dist/round/policy.js +2 -0
  67. package/dist/round/policy.js.map +1 -0
  68. package/dist/round/subagent.d.ts +67 -0
  69. package/dist/round/subagent.d.ts.map +1 -0
  70. package/dist/round/subagent.js +89 -0
  71. package/dist/round/subagent.js.map +1 -0
  72. package/dist/round/turn.d.ts +231 -0
  73. package/dist/round/turn.d.ts.map +1 -0
  74. package/dist/round/turn.js +497 -0
  75. package/dist/round/turn.js.map +1 -0
  76. package/dist/round/workflow.d.ts +109 -0
  77. package/dist/round/workflow.d.ts.map +1 -0
  78. package/dist/round/workflow.js +316 -0
  79. package/dist/round/workflow.js.map +1 -0
  80. package/dist/runtime/index.d.ts +5 -1
  81. package/dist/runtime/index.d.ts.map +1 -1
  82. package/dist/runtime/index.js +2 -6
  83. package/dist/runtime/index.js.map +1 -1
  84. package/dist/subagent/fingerprint.d.ts.map +1 -1
  85. package/dist/subagent/fingerprint.js +7 -2
  86. package/dist/subagent/fingerprint.js.map +1 -1
  87. package/dist/testing/auth.d.ts.map +1 -1
  88. package/dist/testing/auth.js +10 -7
  89. package/dist/testing/auth.js.map +1 -1
  90. package/dist/testing/fixtures.d.ts +17 -0
  91. package/dist/testing/fixtures.d.ts.map +1 -1
  92. package/dist/testing/fixtures.js +17 -0
  93. package/dist/testing/fixtures.js.map +1 -1
  94. package/dist/testing/harness.d.ts +98 -0
  95. package/dist/testing/harness.d.ts.map +1 -0
  96. package/dist/testing/harness.js +139 -0
  97. package/dist/testing/harness.js.map +1 -0
  98. package/dist/testing/index.d.ts +2 -1
  99. package/dist/testing/index.d.ts.map +1 -1
  100. package/dist/testing/index.js +2 -1
  101. package/dist/testing/index.js.map +1 -1
  102. package/dist/worker/define-agent.d.ts +124 -0
  103. package/dist/worker/define-agent.d.ts.map +1 -0
  104. package/dist/worker/define-agent.js +21 -0
  105. package/dist/worker/define-agent.js.map +1 -0
  106. package/dist/worker/index.d.ts +29 -4
  107. package/dist/worker/index.d.ts.map +1 -1
  108. package/dist/worker/index.js +70 -12
  109. package/dist/worker/index.js.map +1 -1
  110. package/package.json +12 -3
@@ -1,47 +1,39 @@
1
1
  import { type JWTPayload } from "jose";
2
+ import { type GatewayIdentity } from "@loopingai/a2a-protocol";
2
3
  /**
3
- * Default namespaced claim carrying the minimal caller identity.
4
+ * Verify the gateway identity JWT (the "B authenticates A" half of zero-trust).
4
5
  *
5
- * Overridable via {@link VerifyOptions.identityClaim} for a deployment that
6
- * isn't behind looping-gateway; the default is the Looping namespace so an
7
- * agent built on this package needs no configuration to interoperate.
8
- */
9
- export declare const IDENTITY_CLAIM = "https://loopingai.org/identity";
10
- /**
11
- * Default namespaced claim naming the **tenant** the gateway minted this token
12
- * for which of the agents on this origin it authorizes the call to reach.
6
+ * The gateway signs a short-lived EdDSA JWT and sends it as a Bearer token on
7
+ * every A2A call. Per RFC 7515 §4.1.2 it embeds a `jku` header pointing at its
8
+ * public JWKS, so remote agents don't need a separately configured JWKS URL —
9
+ * they read `jku` straight from the token and verify the key from there.
10
+ *
11
+ * Security: the `jku` origin is validated against the allowed origins before
12
+ * fetching, preventing key-injection attacks (an attacker cannot point `jku` at
13
+ * their own JWKS and have it accepted).
13
14
  *
14
- * Several agents share one endpoint, so they also share an `aud`: the audience
15
- * proves the token was minted for *this deployment*, and can say nothing about
16
- * which agent on it. This claim is the only thing that can, which is why the
17
- * Worker refuses a token that omits it rather than falling back to a default.
18
- * Without it `tenant` would be an unauthenticated field in the request body,
19
- * and a token legitimately issued for one agent could be replayed against any
20
- * of its siblings.
15
+ * **This file is a guardian.** The four checks below `jku` present → origin
16
+ * allowlist `iss` origin equals `jku` origin `jwtVerify` pinned to EdDSA
17
+ * are the whole zero-trust contract, and they arrived here byte-identical from
18
+ * two independently-evolved agents. Do not weaken any of them, do not make any
19
+ * of them optional, and do not add a bypass for local development: run a local
20
+ * gateway instead.
21
21
  */
22
- export declare const TENANT_CLAIM = "https://loopingai.org/tenant";
23
22
  /**
24
- * The gateway-agent instance identity forwarded by the gatewayi.e. which
25
- * registered agent instance dispatched this call, not the human end user.
26
- * Mirrors `RemoteIdentity` in looping-gateway's `src/auth/agent-jwt.ts`.
23
+ * The wire contract claim names, algorithm, identity shape comes from
24
+ * `@loopingai/a2a-protocol`, which the gateway also depends on directly.
27
25
  *
28
- * Any end user travels unverified, inline in the message text; the gateway
29
- * deliberately excludes it from this signed claim so a remote agent cannot read
30
- * the full caller auth context. Every field is optional because the claim is
31
- * whatever the issuer put there {@link GatewayIdentity.key} is the only one
32
- * anything downstream depends on, and a caller without it is rejected before a
33
- * DO is ever addressed.
26
+ * It used to be declared here and again in the gateway, each with a comment
27
+ * saying it must match the other, because the gateway is not an agent and must
28
+ * not import this package. That failed exactly as it always does: one side
29
+ * moved to the `loopingai.org` namespace while the other still minted
30
+ * `https://looping.ai/tenant`, verification read an empty tenant, and every
31
+ * request 401'd with both builds green.
32
+ *
33
+ * Re-exported below so nothing downstream of `@loopingai/core/a2a` has to know
34
+ * the split happened — an agent still imports these from here.
34
35
  */
35
- export interface GatewayIdentity {
36
- /** Canonical instance key, e.g. `custom:7:analytics`. */
37
- key?: string;
38
- /** Registry name of the logical agent instance. */
39
- name?: string;
40
- /** Dispatch kind of the caller (`"custom"` for remote agents). */
41
- kind?: string;
42
- /** Workspace the calling agent instance belongs to. */
43
- workspaceId?: number | null;
44
- }
36
+ export { IDENTITY_CLAIM, TENANT_CLAIM, type GatewayIdentity } from "@loopingai/a2a-protocol";
45
37
  /** Thrown when a gateway token is missing or fails verification. */
46
38
  export declare class GatewayAuthError extends Error {
47
39
  constructor(message: string);
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/a2a/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,MAAM,CAAC;AAyBd;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,mCAAmC,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,iCAAiC,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,oEAAoE;AACpE,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAcD,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI3D;AAED,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAenE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC;IACT,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CA8CD"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/a2a/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,MAAM,CAAC;AACd,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,cAAc,EACd,YAAY,EACZ,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAEjC,oEAAoE;AACpE,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAcD,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI3D;AAED,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAenE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC;IACT,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAgDD"}
@@ -1,4 +1,5 @@
1
1
  import { createRemoteJWKSet, decodeJwt, decodeProtectedHeader, jwtVerify } from "jose";
2
+ import { A2A_JWS_ALG, readIdentityClaim, readTenantClaim } from "@loopingai/a2a-protocol";
2
3
  /**
3
4
  * Verify the gateway identity JWT (the "B authenticates A" half of zero-trust).
4
5
  *
@@ -18,29 +19,21 @@ import { createRemoteJWKSet, decodeJwt, decodeProtectedHeader, jwtVerify } from
18
19
  * of them optional, and do not add a bypass for local development: run a local
19
20
  * gateway instead.
20
21
  */
21
- /** Algorithm the gateway signs with — reject anything else. */
22
- const ALG = "EdDSA";
23
22
  /**
24
- * Default namespaced claim carrying the minimal caller identity.
23
+ * The wire contract — claim names, algorithm, identity shape — comes from
24
+ * `@loopingai/a2a-protocol`, which the gateway also depends on directly.
25
25
  *
26
- * Overridable via {@link VerifyOptions.identityClaim} for a deployment that
27
- * isn't behind looping-gateway; the default is the Looping namespace so an
28
- * agent built on this package needs no configuration to interoperate.
29
- */
30
- export const IDENTITY_CLAIM = "https://loopingai.org/identity";
31
- /**
32
- * Default namespaced claim naming the **tenant** the gateway minted this token
33
- * for — which of the agents on this origin it authorizes the call to reach.
26
+ * It used to be declared here and again in the gateway, each with a comment
27
+ * saying it must match the other, because the gateway is not an agent and must
28
+ * not import this package. That failed exactly as it always does: one side
29
+ * moved to the `loopingai.org` namespace while the other still minted
30
+ * `https://looping.ai/tenant`, verification read an empty tenant, and every
31
+ * request 401'd with both builds green.
34
32
  *
35
- * Several agents share one endpoint, so they also share an `aud`: the audience
36
- * proves the token was minted for *this deployment*, and can say nothing about
37
- * which agent on it. This claim is the only thing that can, which is why the
38
- * Worker refuses a token that omits it rather than falling back to a default.
39
- * Without it `tenant` would be an unauthenticated field in the request body,
40
- * and a token legitimately issued for one agent could be replayed against any
41
- * of its siblings.
33
+ * Re-exported below so nothing downstream of `@loopingai/core/a2a` has to know
34
+ * the split happened an agent still imports these from here.
42
35
  */
43
- export const TENANT_CLAIM = "https://loopingai.org/tenant";
36
+ export { IDENTITY_CLAIM, TENANT_CLAIM } from "@loopingai/a2a-protocol";
44
37
  /** Thrown when a gateway token is missing or fails verification. */
45
38
  export class GatewayAuthError extends Error {
46
39
  constructor(message) {
@@ -125,15 +118,17 @@ export async function verifyGatewayToken(token, opts) {
125
118
  const { payload } = await jwtVerify(token, jwksFor(jku), {
126
119
  issuer: allowedOrigins,
127
120
  audience: opts.audience,
128
- algorithms: [ALG]
121
+ algorithms: [A2A_JWS_ALG]
129
122
  });
130
- const claim = opts.identityClaim ?? IDENTITY_CLAIM;
131
- const identity = payload[claim] ?? {};
132
- const tenant = payload[opts.tenantClaim ?? TENANT_CLAIM];
123
+ // Read through the protocol package's readers rather than indexing the
124
+ // payload here: they are where "an absent or malformed claim yields an
125
+ // empty value, never a default" has its single implementation, and the
126
+ // emptiness is load-bearing — `createA2AWorker` compares the tenant against
127
+ // the one the request body addressed, and `""` matches none of them.
133
128
  return {
134
129
  payload,
135
- identity,
136
- tenant: typeof tenant === "string" ? tenant : ""
130
+ identity: readIdentityClaim(payload, opts.identityClaim),
131
+ tenant: readTenantClaim(payload, opts.tenantClaim)
137
132
  };
138
133
  }
139
134
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/a2a/verify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/a2a/verify.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,22 @@
1
1
  /**
2
2
  * `@loopingai/core/agent` — the primitives a loop is built from.
3
3
  *
4
- * Core ships no loop. `turn.ts` / `loop.ts` are the agent's, because how a round
5
- * ends is the one thing every agent genuinely differs on. What core owns is
6
- * everything both predecessor loops needed identically: the session, the model
7
- * pair with its fallback, the budget, and the control-tool abstraction that
8
- * turns "the model called something that ends the round" into a checked value.
4
+ * The session, the model pair with its fallback, the budget, and the
5
+ * control-tool abstraction that turns "the model called something that ends the
6
+ * round" into a checked value. Everything both predecessor loops needed
7
+ * identically, and nothing about how a round is shaped.
8
+ *
9
+ * This subpath ships **no loop** — that is what makes it importable by one. A
10
+ * loop module needs these primitives without also pulling in a Durable Object
11
+ * base class and drizzle, which is why `LoopingAgent` lives in
12
+ * `@loopingai/core/host` and the delegating round loop in
13
+ * `@loopingai/core/round`.
14
+ *
15
+ * Core as a whole *does* now ship a loop, opt-in, in `/round`. The rule it
16
+ * still keeps is narrower and better: **core ships no prompt copy and no
17
+ * policy** — see `AGENTS.md`, "The line core does not cross". An agent that
18
+ * wants a different round shape imports none of `/round` and builds it from
19
+ * exactly what is here.
9
20
  */
10
21
  export { newTurnBudget, stepAllowance, type TurnBudget } from "./budget.js";
11
22
  export { createModelRuntime, type GatewayMetadata, type ModelOverrides, type ModelPair, type ModelRuntime, type ModelRuntimeDeps } from "./model.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EACL,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,sBAAsB,EACtB,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,+BAA+B,EAC/B,kBAAkB,EAClB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACf,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EACL,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,sBAAsB,EACtB,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,+BAA+B,EAC/B,kBAAkB,EAClB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACf,MAAM,kBAAkB,CAAC"}
@@ -1,11 +1,22 @@
1
1
  /**
2
2
  * `@loopingai/core/agent` — the primitives a loop is built from.
3
3
  *
4
- * Core ships no loop. `turn.ts` / `loop.ts` are the agent's, because how a round
5
- * ends is the one thing every agent genuinely differs on. What core owns is
6
- * everything both predecessor loops needed identically: the session, the model
7
- * pair with its fallback, the budget, and the control-tool abstraction that
8
- * turns "the model called something that ends the round" into a checked value.
4
+ * The session, the model pair with its fallback, the budget, and the
5
+ * control-tool abstraction that turns "the model called something that ends the
6
+ * round" into a checked value. Everything both predecessor loops needed
7
+ * identically, and nothing about how a round is shaped.
8
+ *
9
+ * This subpath ships **no loop** — that is what makes it importable by one. A
10
+ * loop module needs these primitives without also pulling in a Durable Object
11
+ * base class and drizzle, which is why `LoopingAgent` lives in
12
+ * `@loopingai/core/host` and the delegating round loop in
13
+ * `@loopingai/core/round`.
14
+ *
15
+ * Core as a whole *does* now ship a loop, opt-in, in `/round`. The rule it
16
+ * still keeps is narrower and better: **core ships no prompt copy and no
17
+ * policy** — see `AGENTS.md`, "The line core does not cross". An agent that
18
+ * wants a different round shape imports none of `/round` and builds it from
19
+ * exactly what is here.
9
20
  */
10
21
  export { newTurnBudget, stepAllowance } from "./budget.js";
11
22
  export { createModelRuntime } from "./model.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAmB,MAAM,aAAa,CAAC;AAE5E,OAAO,EACL,kBAAkB,EAMnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EAIpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,sBAAsB,EACtB,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,eAAe,EAEhB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,+BAA+B,EAC/B,kBAAkB,EAEnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EAGf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACf,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAmB,MAAM,aAAa,CAAC;AAE5E,OAAO,EACL,kBAAkB,EAMnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EAIpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,sBAAsB,EACtB,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,eAAe,EAEhB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,+BAA+B,EAC/B,kBAAkB,EAEnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,EAGf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACf,MAAM,kBAAkB,CAAC"}
package/dist/config.d.ts CHANGED
@@ -13,11 +13,29 @@
13
13
  */
14
14
  /** Model ids and per-call generation settings. */
15
15
  export interface ModelConfig {
16
- /** Workers AI model for the tool loop. Must support function calling. */
16
+ /**
17
+ * Workers AI model for the tool loop. Must support function calling.
18
+ *
19
+ * **Required — core ships no default.** Which model an agent runs on is the
20
+ * single most consequential thing about it: it sets the cost of every turn,
21
+ * the tool-calling reliability the whole control-tool design rests on, and the
22
+ * failure modes the fallback exists to escape. A default here would be core
23
+ * making that choice on a consumer's behalf, silently, and being wrong for
24
+ * most of them — the same reason core ships no prompt copy.
25
+ *
26
+ * It is also the value most likely to age badly. A model id baked into a
27
+ * published package survives every deprecation until someone bumps the
28
+ * package; one written in the agent that uses it is read by whoever owns the
29
+ * bill.
30
+ */
17
31
  chatModelId: string;
18
32
  /**
19
- * Tried when the primary throws. Should be a *different vendor and family* —
20
- * a same-family fallback shares the failure mode you are falling back from.
33
+ * Tried when the primary throws. **Required core ships no default.**
34
+ *
35
+ * Should be a *different vendor and family* — a same-family fallback shares
36
+ * the failure mode you are falling back from, which makes it a retry wearing
37
+ * a costume. Core cannot pick this for you precisely because it depends on
38
+ * what you chose as primary.
21
39
  */
22
40
  fallbackChatModelId: string;
23
41
  /** AI Gateway slug; `"default"` auto-provisions on first request. */
@@ -117,15 +135,39 @@ export interface CoreConfig {
117
135
  maxSubtasks: number;
118
136
  session: SessionConfig;
119
137
  }
138
+ /** The two ids an agent must choose for itself. Core has no opinion. */
139
+ export type RequiredModelIds = Pick<ModelConfig, "chatModelId" | "fallbackChatModelId">;
140
+ /**
141
+ * The baseline, which is everything core *does* still have an opinion about.
142
+ *
143
+ * Note what is missing: the model pair. This type is `CoreConfig` minus those
144
+ * two ids precisely so that no value of it can supply them — a default nobody
145
+ * declared is how an agent ends up billing a model its author never chose.
146
+ */
147
+ export type CoreConfigBaseline = Omit<CoreConfig, "model"> & {
148
+ model: Omit<ModelConfig, keyof RequiredModelIds>;
149
+ };
120
150
  /**
121
151
  * A working baseline. Every value is overridable; none is a ceiling. These are
122
152
  * the values both predecessor agents converged on in production, so they are a
123
153
  * reasonable place to start rather than an opinion about your domain.
154
+ *
155
+ * **It carries no model ids.** See {@link ModelConfig.chatModelId}.
156
+ */
157
+ export declare const DEFAULT_CORE_CONFIG: CoreConfigBaseline;
158
+ /**
159
+ * One level of optionality per nested group — enough for a config this shallow.
160
+ *
161
+ * `model` is the exception, and deliberately not optional: an agent must name
162
+ * its own primary and fallback. That is a compile error rather than a runtime
163
+ * one, so the omission is found while writing the agent rather than on the first
164
+ * request it serves.
124
165
  */
125
- export declare const DEFAULT_CORE_CONFIG: CoreConfig;
126
- /** One level of optionality per nested group — enough for a config this shallow. */
127
166
  export type CoreConfigOverrides = {
128
- [K in keyof CoreConfig]?: CoreConfig[K] extends object ? Partial<CoreConfig[K]> : CoreConfig[K];
167
+ [K in Exclude<keyof CoreConfig, "model">]?: CoreConfig[K] extends object ? Partial<CoreConfig[K]> : CoreConfig[K];
168
+ } & {
169
+ /** Required: the two model ids, plus any generation setting you want changed. */
170
+ model: RequiredModelIds & Partial<Omit<ModelConfig, keyof RequiredModelIds>>;
129
171
  };
130
172
  export declare class ConfigError extends Error {
131
173
  constructor(message: string);
@@ -138,5 +180,5 @@ export declare class ConfigError extends Error {
138
180
  * not call it per-request: the point of resolving is that every module downstream
139
181
  * reads the same object.
140
182
  */
141
- export declare function resolveConfig(overrides?: CoreConfigOverrides): CoreConfig;
183
+ export declare function resolveConfig(overrides: CoreConfigOverrides): CoreConfig;
142
184
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,mFAAmF;IACnF,eAAe,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC5C;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0CAA0C;AAC1C,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,eAAe,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;;;OAaG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,iEAAiE;IACjE,eAAe,EAAE,WAAW,CAAC;IAC7B;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAoBjC,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,mBAAmB,GAAG;KAC/B,CAAC,IAAI,MAAM,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,MAAM,GAClD,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GACtB,UAAU,CAAC,CAAC,CAAC;CAClB,CAAC;AAEF,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,SAAS,GAAE,mBAAwB,GAAG,UAAU,CA2C7E"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;;;;;;OAcG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,mFAAmF;IACnF,eAAe,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC5C;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0CAA0C;AAC1C,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,eAAe,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;;;OAaG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,iEAAiE;IACjE,eAAe,EAAE,WAAW,CAAC;IAC7B;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,wEAAwE;AACxE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,WAAW,EACX,aAAa,GAAG,qBAAqB,CACtC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG;IAC3D,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,gBAAgB,CAAC,CAAC;CAClD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,kBAoBjC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG;KAC/B,CAAC,IAAI,OAAO,CAAC,MAAM,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,MAAM,GACpE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GACtB,UAAU,CAAC,CAAC,CAAC;CAClB,GAAG;IACF,iFAAiF;IACjF,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,gBAAgB,CAAC,CAAC,CAAC;CAC9E,CAAC;AAEF,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,mBAAmB,GAAG,UAAU,CAsExE"}
package/dist/config.js CHANGED
@@ -15,11 +15,13 @@
15
15
  * A working baseline. Every value is overridable; none is a ceiling. These are
16
16
  * the values both predecessor agents converged on in production, so they are a
17
17
  * reasonable place to start rather than an opinion about your domain.
18
+ *
19
+ * **It carries no model ids.** See {@link ModelConfig.chatModelId}.
18
20
  */
19
21
  export const DEFAULT_CORE_CONFIG = {
20
22
  model: {
21
- chatModelId: "@cf/zai-org/glm-5.2",
22
- fallbackChatModelId: "@cf/moonshotai/kimi-k2.7-code",
23
+ // Not a model: an AI Gateway slug, and `"default"` is Cloudflare's own
24
+ // auto-provision behaviour rather than a choice core is making for anyone.
23
25
  aiGatewayId: "default",
24
26
  maxOutputTokens: 16_384,
25
27
  reasoningEffort: "medium"
@@ -50,7 +52,7 @@ export class ConfigError extends Error {
50
52
  * not call it per-request: the point of resolving is that every module downstream
51
53
  * reads the same object.
52
54
  */
53
- export function resolveConfig(overrides = {}) {
55
+ export function resolveConfig(overrides) {
54
56
  const config = {
55
57
  model: { ...DEFAULT_CORE_CONFIG.model, ...overrides.model },
56
58
  mainAgentLimits: {
@@ -70,6 +72,26 @@ export function resolveConfig(overrides = {}) {
70
72
  throw new ConfigError(`${name} must be a positive number, got ${value}`);
71
73
  }
72
74
  };
75
+ // The type already requires both ids; this catches the JavaScript consumer,
76
+ // the `as CoreConfigOverrides` cast, and the empty string — which typechecks
77
+ // and then reaches Workers AI as a model that does not exist, failing on the
78
+ // first generation with a binding error that names nothing useful.
79
+ const modelId = (value, name) => {
80
+ if (typeof value !== "string" || value.trim() === "") {
81
+ throw new ConfigError(`model.${name} is required and must be a non-empty model id — core ` +
82
+ `ships no default, because which model an agent runs on is the agent's ` +
83
+ `most consequential choice and cannot be made on its behalf`);
84
+ }
85
+ };
86
+ modelId(config.model.chatModelId, "chatModelId");
87
+ modelId(config.model.fallbackChatModelId, "fallbackChatModelId");
88
+ // A fallback identical to the primary is a retry wearing a costume: it shares
89
+ // the outage, the rate limit and the deprecation you are falling back from.
90
+ if (config.model.chatModelId === config.model.fallbackChatModelId) {
91
+ throw new ConfigError(`model.fallbackChatModelId must differ from model.chatModelId (both are ` +
92
+ `'${config.model.chatModelId}') — a same-model fallback shares every ` +
93
+ `failure mode you are falling back from`);
94
+ }
73
95
  positive(config.mainAgentLimits.maxTurns, "mainAgentLimits.maxTurns");
74
96
  positive(config.mainAgentLimits.maxWallMs, "mainAgentLimits.maxWallMs");
75
97
  positive(config.subagentLimits.maxTurns, "subagentLimits.maxTurns");
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -76,8 +76,6 @@ export type RecipeLimits = AgentLimits;
76
76
  export interface ResolvedRecipe {
77
77
  key: string;
78
78
  version: number;
79
- primaryModelId: string;
80
- fallbackModelId: string;
81
79
  /** Required, never defaulted — see `validateRecipe`. */
82
80
  soul: string;
83
81
  toolFamilies: string[];
@@ -104,6 +102,20 @@ export interface ResolvedRecipe {
104
102
  */
105
103
  export interface ValidatedRecipe extends ResolvedRecipe {
106
104
  limits: RecipeLimits;
105
+ /**
106
+ * The pair this recipe will actually run on — **the host's, always**.
107
+ *
108
+ * These exist only here, never on {@link ResolvedRecipe}, and that asymmetry
109
+ * is the design: a recipe cannot state a model, so the only way to hold one is
110
+ * to have been through {@link validateRecipe}, which copies the host's. Recipe
111
+ * data has no path to influence them.
112
+ *
113
+ * Guaranteed non-empty and guaranteed distinct, because `resolveConfig`
114
+ * refuses a config that is either — so the fallback is always a genuinely
115
+ * different model from the primary, which is the entire point of having one.
116
+ */
117
+ primaryModelId: string;
118
+ fallbackModelId: string;
107
119
  }
108
120
  /**
109
121
  * One entry in the closed set of Subtask types the main agent may delegate,
@@ -1 +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"}
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;IAyBhB,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;IACrB;;;;;;;;;;;OAWG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;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"}
@@ -4,12 +4,12 @@ import type { ResolvedRecipe, ValidatedRecipe } from "./recipe.js";
4
4
  * The capability boundary every recipe passes through, whatever declared it.
5
5
  *
6
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}.
7
+ * about *any* recipe: which tool families it may select, which models it runs
8
+ * on, and how a malformed one is made safe or refused. A domain cannot widen
9
+ * its *capabilities* by declaring them the legal tool families come from
10
+ * {@link RecipePolicy}, which the host builds from its installed plugins, and
11
+ * the model pair comes from the host's config with no declaration involved at
12
+ * all. Its budget is the deliberate exception; see {@link resolveLimits}.
13
13
  *
14
14
  * In the predecessor repo the two allowlists were module constants, and one of
15
15
  * them hardcoded a domain key (`"arc-game"`) inside otherwise generic code. That
@@ -18,15 +18,19 @@ import type { ResolvedRecipe, ValidatedRecipe } from "./recipe.js";
18
18
  */
19
19
  export interface RecipePolicy {
20
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.
21
+ * The pair every recipe runs on: the host agent's own, copied verbatim onto
22
+ * each {@link ValidatedRecipe}.
23
+ *
24
+ * There is no allowlist any more, because there is nothing to check against
25
+ * it — a recipe cannot state a model. `modelAllowlist` existed to police
26
+ * recipe-stated preferences, and it could only ever contain these same two
27
+ * ids, so the "preference" it policed could never reach a third model. It
28
+ * could only swap the primary for the fallback, which is not a capability
29
+ * anyone wants and which broke the pair's distinctness.
24
30
  */
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;
31
+ primaryModelId: string;
32
+ /** See {@link primaryModelId}. Guaranteed distinct from it by `resolveConfig`. */
33
+ fallbackModelId: string;
30
34
  /**
31
35
  * Tool-family keys the runtime recognizes — derived from the installed
32
36
  * plugins, never hardcoded.
@@ -69,12 +73,12 @@ export declare class RecipeValidationError extends Error {
69
73
  }
70
74
  /**
71
75
  * Code-owned defensive validation of an already-resolved recipe. Returns a
72
- * normalized copy (never mutates the input): a model id outside the policy's
73
- * allowlist is substituted with the default for its slot — independently per
74
- * slot — and unknown tool families are dropped (deduped, order-preserving).
76
+ * normalized copy (never mutates the input): the host's model pair is stamped
77
+ * on, and unknown tool families are dropped (deduped, order-preserving).
75
78
  * Applied by the parent when it resolves a recipe and re-applied by the subagent
76
79
  * on its inbound request, so recipe data can never select arbitrary models or
77
- * tools.
80
+ * tools — models because there is no field to select one with, tools because
81
+ * the legal set comes from the installed plugins rather than the declaration.
78
82
  *
79
83
  * The split between what is normalized and what is refused follows one rule:
80
84
  * **the host declares a baseline ⇒ merge; it does not ⇒ require.** `limits`
@@ -1 +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;;;;;;;;;;OAUG;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"}
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;;;;;;;;;;OAUG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,kFAAkF;IAClF,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;OAUG;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,CAwCjB"}
@@ -34,12 +34,12 @@ export class RecipeValidationError extends Error {
34
34
  }
35
35
  /**
36
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).
37
+ * normalized copy (never mutates the input): the host's model pair is stamped
38
+ * on, and unknown tool families are dropped (deduped, order-preserving).
40
39
  * Applied by the parent when it resolves a recipe and re-applied by the subagent
41
40
  * on its inbound request, so recipe data can never select arbitrary models or
42
- * tools.
41
+ * tools — models because there is no field to select one with, tools because
42
+ * the legal set comes from the installed plugins rather than the declaration.
43
43
  *
44
44
  * The split between what is normalized and what is refused follows one rule:
45
45
  * **the host declares a baseline ⇒ merge; it does not ⇒ require.** `limits`
@@ -63,12 +63,21 @@ export function validateRecipe(recipe, policy) {
63
63
  const toolFamilies = [...new Set(recipe.toolFamilies)].filter((family) => policy.knownToolFamilies.has(family));
64
64
  return {
65
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,
66
+ // The host's pair, copied. Not selected, not substituted, not merged —
67
+ // there is nothing on a `ResolvedRecipe` to select *from*.
68
+ //
69
+ // This used to substitute a recipe's stated preference against
70
+ // an allowlist, per slot and independently. That produced a real defect:
71
+ // a recipe preferring the host's *fallback* as its primary, and stating no
72
+ // fallback of its own, resolved to the same id in both slots — so the
73
+ // fallback retried the model that had just failed, defeating the distinct-
74
+ // pair invariant `resolveConfig` enforces one layer up.
75
+ //
76
+ // Copying wholesale makes that unrepresentable: the pair here is exactly the
77
+ // pair the agent configured, which `resolveConfig` has already guaranteed is
78
+ // non-empty and distinct.
79
+ primaryModelId: policy.primaryModelId,
80
+ fallbackModelId: policy.fallbackModelId,
72
81
  toolFamilies,
73
82
  limits: resolveLimits(recipe.limits, policy.baselineLimits)
74
83
  };
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/contract/validation.ts"],"names":[],"mappings":"AA8CA;;;;;;;;;;;;;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"}
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/contract/validation.ts"],"names":[],"mappings":"AAkDA;;;;;;;;;;;;;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,uEAAuE;QACvE,2DAA2D;QAC3D,EAAE;QACF,+DAA+D;QAC/D,yEAAyE;QACzE,2EAA2E;QAC3E,sEAAsE;QACtE,2EAA2E;QAC3E,wDAAwD;QACxD,EAAE;QACF,6EAA6E;QAC7E,6EAA6E;QAC7E,0BAA0B;QAC1B,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,YAAY;QACZ,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;KAC5D,CAAC;AACJ,CAAC"}