@demlik/tea 0.14.0 → 0.16.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 (116) hide show
  1. package/README.md +30 -7
  2. package/dist/agent/index.d.ts +49 -36
  3. package/dist/agent/index.js +12 -8
  4. package/dist/chunk-4LPY67E4.js +18 -0
  5. package/dist/chunk-4LPY67E4.js.map +1 -0
  6. package/dist/chunk-5XU6ZJO2.js +533 -0
  7. package/dist/chunk-5XU6ZJO2.js.map +1 -0
  8. package/dist/{chunk-AQ6ZIMEA.js → chunk-6NG4V5SB.js} +89 -115
  9. package/dist/chunk-6NG4V5SB.js.map +1 -0
  10. package/dist/{chunk-HYDWG35Q.js → chunk-7MGXQZPW.js} +11 -9
  11. package/dist/chunk-7MGXQZPW.js.map +1 -0
  12. package/dist/{chunk-BLJ2JQSH.js → chunk-BCTEOVOU.js} +3 -3
  13. package/dist/{chunk-BLJ2JQSH.js.map → chunk-BCTEOVOU.js.map} +1 -1
  14. package/dist/chunk-CH5KTOEZ.js +710 -0
  15. package/dist/chunk-CH5KTOEZ.js.map +1 -0
  16. package/dist/chunk-CIHSHLQX.js +64 -0
  17. package/dist/chunk-CIHSHLQX.js.map +1 -0
  18. package/dist/{chunk-Z2L3LSNV.js → chunk-EHUDXAKC.js} +246 -210
  19. package/dist/chunk-EHUDXAKC.js.map +1 -0
  20. package/dist/chunk-GOX2CYIM.js +380 -0
  21. package/dist/chunk-GOX2CYIM.js.map +1 -0
  22. package/dist/chunk-IVJP3GKJ.js +104 -0
  23. package/dist/chunk-IVJP3GKJ.js.map +1 -0
  24. package/dist/{chunk-F7FMAWLA.js → chunk-MVZS5FDM.js} +13 -6
  25. package/dist/chunk-MVZS5FDM.js.map +1 -0
  26. package/dist/{chunk-LYLTKJWM.js → chunk-MYNLY3HP.js} +9 -8
  27. package/dist/chunk-MYNLY3HP.js.map +1 -0
  28. package/dist/{chunk-I5MQMJDW.js → chunk-NSIAORRY.js} +20 -30
  29. package/dist/chunk-NSIAORRY.js.map +1 -0
  30. package/dist/{chunk-MYXFNWAJ.js → chunk-QNGYQMZB.js} +4 -4
  31. package/dist/chunk-QNGYQMZB.js.map +1 -0
  32. package/dist/chunk-WT5PBPLB.js +98 -0
  33. package/dist/chunk-WT5PBPLB.js.map +1 -0
  34. package/dist/{core-CTzMJ82M.d.ts → core-BbgtiXdg.d.ts} +231 -139
  35. package/dist/do/index.d.ts +37 -32
  36. package/dist/do/index.js +21 -14
  37. package/dist/do/index.js.map +1 -1
  38. package/dist/{durable-effects-B0-qGQDy.d.ts → durable-effects-7MTK_jnj.d.ts} +1 -1
  39. package/dist/effect/index.d.ts +151 -0
  40. package/dist/effect/index.js +98 -0
  41. package/dist/effect/index.js.map +1 -0
  42. package/dist/extension/index.d.ts +6 -7
  43. package/dist/extension/index.js +3 -2
  44. package/dist/extension/index.js.map +1 -1
  45. package/dist/flow/index.d.ts +68 -70
  46. package/dist/flow/index.js +32 -27
  47. package/dist/flow/index.js.map +1 -1
  48. package/dist/idempotency/index.d.ts +6 -7
  49. package/dist/idempotency/index.js +4 -2
  50. package/dist/{index-DJWIER_3.d.ts → index-7vV8xmsD.d.ts} +1 -1
  51. package/dist/{index-NjrT3fL2.d.ts → index-Bz5Rh9Ga.d.ts} +19 -96
  52. package/dist/index-CjFDUBeq.d.ts +207 -0
  53. package/dist/{index-6A7dB8f6.d.ts → index-CkFYA9Y6.d.ts} +14 -16
  54. package/dist/{index-B5BZ-_cT.d.ts → index-Cou86-GX.d.ts} +189 -108
  55. package/dist/{index-TvRb1KVf.d.ts → index-DU6JpQ8G.d.ts} +1 -1
  56. package/dist/{index-q0hXFeZ0.d.ts → index-Xufl55W8.d.ts} +286 -215
  57. package/dist/{index-4vZzljCD.d.ts → index-_dOR3xqA.d.ts} +57 -45
  58. package/dist/index.d.ts +181 -385
  59. package/dist/index.js +2 -1
  60. package/dist/jev/index.d.ts +147 -99
  61. package/dist/jev/index.js +329 -233
  62. package/dist/jev/index.js.map +1 -1
  63. package/dist/{machine-CdIcN2Xm.d.ts → machine-BQzTV8On.d.ts} +171 -280
  64. package/dist/machine-viz/index.d.ts +5 -5
  65. package/dist/machine-viz/index.js +8 -4
  66. package/dist/machine-viz/index.js.map +1 -1
  67. package/dist/mem/index.d.ts +3 -4
  68. package/dist/mem/index.js +2 -1
  69. package/dist/mem/index.js.map +1 -1
  70. package/dist/node/index.d.ts +119 -78
  71. package/dist/node/index.js +52 -38
  72. package/dist/node/index.js.map +1 -1
  73. package/dist/paginate/index.d.ts +27 -33
  74. package/dist/paginate/index.js +6 -4
  75. package/dist/parity/index.d.ts +4 -5
  76. package/dist/parity/index.js +3 -2
  77. package/dist/parity/index.js.map +1 -1
  78. package/dist/pbt/index.d.ts +2 -2
  79. package/dist/pbt/index.js +2 -1
  80. package/dist/pbt/index.js.map +1 -1
  81. package/dist/persistence/index.d.ts +6 -7
  82. package/dist/persistence/index.js +5 -3
  83. package/dist/promise/index.d.ts +186 -0
  84. package/dist/promise/index.js +5 -0
  85. package/dist/promise/index.js.map +1 -0
  86. package/dist/protocol-ClRZBhHQ.d.ts +53 -0
  87. package/dist/react/index.d.ts +36 -17
  88. package/dist/react/index.js +27 -4
  89. package/dist/react/index.js.map +1 -1
  90. package/dist/resilience/index.d.ts +63 -455
  91. package/dist/resilience/index.js +37 -483
  92. package/dist/resilience/index.js.map +1 -1
  93. package/dist/{runtime-types-LWDoi943.d.ts → runtime-types-CiVpC0HN.d.ts} +131 -388
  94. package/dist/testing/index.d.ts +165 -15
  95. package/dist/testing/index.js +104 -3
  96. package/dist/testing/index.js.map +1 -1
  97. package/dist/timing/index.d.ts +25 -22
  98. package/dist/timing/index.js +4 -3
  99. package/dist/timing/index.js.map +1 -1
  100. package/dist/{types-DP3f5NIl.d.ts → types-LxZxGYda.d.ts} +2 -2
  101. package/dist/work-queue/index.d.ts +5 -6
  102. package/package.json +18 -5
  103. package/dist/chunk-AQ6ZIMEA.js.map +0 -1
  104. package/dist/chunk-F2US5BW6.js +0 -72
  105. package/dist/chunk-F2US5BW6.js.map +0 -1
  106. package/dist/chunk-F7FMAWLA.js.map +0 -1
  107. package/dist/chunk-HUKZQX6U.js +0 -97
  108. package/dist/chunk-HUKZQX6U.js.map +0 -1
  109. package/dist/chunk-HYDWG35Q.js.map +0 -1
  110. package/dist/chunk-I5MQMJDW.js.map +0 -1
  111. package/dist/chunk-LYLTKJWM.js.map +0 -1
  112. package/dist/chunk-MYXFNWAJ.js.map +0 -1
  113. package/dist/chunk-RQULHGYH.js +0 -1804
  114. package/dist/chunk-RQULHGYH.js.map +0 -1
  115. package/dist/chunk-Z2L3LSNV.js.map +0 -1
  116. package/dist/index-DMCeMPMJ.d.ts +0 -272
@@ -1,133 +1,101 @@
1
- import { C as Cmd, j as Tagged, I as Interpret, A as AnyCmdDef, a as CmdOf, b as CmdDef, e as Settled, k as NoCtx, O as OkOf, E as ErrOf, l as MalformedResult, i as CmdValue, g as PortEmitter, m as Requirements, n as TaggedError, M as Machine } from './core-CTzMJ82M.js';
2
- import { a as MonitoredRunState, R as RunFailure, M as MonitoredRunCmd } from './index-NjrT3fL2.js';
3
- import { R as RunCmd, S as SucceedMsg, F as FailMsg, a as ResilientState, M as MsgType, b as MsgTypeValue } from './index-B5BZ-_cT.js';
4
- import { D as DeadlineExceeded, a as DeadlineSub } from './index-q0hXFeZ0.js';
5
- import { F as FanOutState } from './index-6A7dB8f6.js';
1
+ import { C as Cmd, s as Tagged, p as Interpret, A as AnyCmdDef, c as CmdOf, b as CmdDef, j as Settled, t as OkOf, u as ErrOf, r as MalformedResult, l as Outcome, v as CmdValue, m as PortEmitter, g as TaggedError, M as Machine, d as Subscribe } from './core-BbgtiXdg.js';
2
+ import { a as MonitoredRunState, R as RunFailure, M as MonitoredRunCmd } from './index-Bz5Rh9Ga.js';
3
+ import { R as RunCmd, S as SucceedMsg, F as FailMsg, a as ResilientState, r as RunCmdDef } from './index-Cou86-GX.js';
4
+ import { D as DeadlineExceeded, a as DeadlineSub, b as DeadlinesSub } from './index-Xufl55W8.js';
5
+ import { M as MsgType, a as MsgTypeValue } from './protocol-ClRZBhHQ.js';
6
+ import { F as FanOutState } from './index-CkFYA9Y6.js';
6
7
  import { RetryPolicy, AnyRetryPolicy } from './retry-backoff/index.js';
7
- import { Result } from 'better-result';
8
- import { z } from 'zod';
9
-
10
- /**
11
- * @packageDocumentation
12
- * internal/llm-call — `resilient-call` + structured-output parse + a typed
13
- * failure variant, around a purpose-discriminated LLM invocation. Internal
14
- * since #49 — not published on any subpath; `@demlik/tea/agent` re-exports
15
- * the types a consumer meets.
16
- *
17
- * This is the ~60-line `call_llm` handler from the audit-agent seed
18
- * (`interpret.ts` / `effects.ts`) collapsed into the uniform L2 knob: a config
19
- * object, the resilient-call slice it inherits, and one interpret handler that
20
- * assembles messages, binds the structured-output schema for the call's
21
- * `purpose`, invokes the model (retry composed from `../resilient-call`, NOT
22
- * reinvented), parses the output, and RETURNS the enriched resilient settle Msg
23
- * (`resilient_ok` / `resilient_err`) so it re-enters the host reducer and drives
24
- * the inherited succeed/fail → backoff → onTimer loop.
25
- *
26
- * ## What it adds over `../resilient-call`
27
- *
28
- * - **Two DI ports** (the seed's two seams):
29
- * 1. `model` — either `async (messages) => answer`, the plain-function
30
- * port (#58), or `(modelId) => LLM`, the model factory that binds the
31
- * structured-output schema itself. Tests pass a fake so the handler
32
- * runs end-to-end without touching a real provider; the production
33
- * worker wires `createChatModel(env, …)`.
34
- * 2. `loadMessages: Loader` — the SDK / message loader. The seed lazy-
35
- * imports `@langchain/core/messages` (a top-level `import type` blows
36
- * up the workers test runner); the loader keeps that import lazy and
37
- * stubbable. It produces the `BaseMessage[]` for a given call.
38
- * - **Structured-output parse** — each `purpose` maps to a `Schema` in
39
- * `config.schemas`. The handler binds `model.withStructuredOutput(schema)`
40
- * so the invoke resolves to a typed object; a `Schema.parse` that throws
41
- * becomes a `resilient_err` carrying an `LlmErr` (a parse failure is a
42
- * failure, not a stall — "errors are data"). `withStructuredOutput` is the
43
- * seed's brain-only path; the fake model in tests returns the typed object
44
- * directly.
45
- * - **A typed failure variant** — every failure (model throw, timeout-via-
46
- * retry-exhaustion, schema parse) is surfaced as the `LlmErr` carried on the
47
- * enriched `resilient_err` settle Msg, tagged with the `purpose` so the
48
- * consumer's reducer routes per-stage. The seed dispatched
49
- * `llm_failed{purpose}`; the consumer rebuilds that shape in its reducer arm
50
- * from `m.error: LlmErr`.
51
- *
52
- * ## Inheriting resilient-call by composition (not reinvention)
53
- *
54
- * The retry / backoff lives in `../resilient-call`: `createLlmCall` builds a
55
- * `createResilientCall` knob over the model-invoke port and DELEGATES `init`,
56
- * `attempt`, `succeed`, `fail`, `onTimer`, `subs` to it verbatim — the slice is
57
- * literally resilient-call's slice (the spec's "retry lives here"). There is no
58
- * second backoff implementation here. The handler runs the invoke through the
59
- * resilient-call handler so a transient model failure backs off exactly as a
60
- * resilient HTTP call would; the `purpose`-branch + structured parse wrap the
61
- * port the resilient handler drives.
62
- *
63
- * ## The two non-negotiables (canon, inherited)
64
- *
65
- * - **Durable** — the slice is resilient-call's plain-data slice (a Model
66
- * field). Input carried on the `resilient_run` Cmd is the plain
67
- * `LlmCall` request (purpose + modelId + payload) — no closures.
68
- * - **Replayable** — every transition is a resilient-call verb; the handler
69
- * is the only impurity, and the one clock read is `Date.now()` at the
70
- * effect boundary (inside the handler), exactly as the seed stamped its
71
- * `llm_responded` / `llm_failed` Msgs.
72
- *
73
- * ## Typical wiring
74
- *
75
- * const llm = createLlmCall<MyPurpose, MyOutputs>({
76
- * model: (id) => createChatModel(env, id),
77
- * schemas: { plan: planSchema, report: reportSchema },
78
- * retry: defaultRetryPolicy,
79
- * loadMessages: defaultMessagesLoader,
80
- * });
81
- *
82
- * // in the machine:
83
- * init: () => [{ resilience: llm.init() }, []],
84
- * update: {
85
- * call_llm: (s, m) => lift(s, llm.attempt(s.resilience, m.input, m.at)),
86
- * // `resilient_ok` / `resilient_err` RE-ENTER from `handlers` (the settle
87
- * // Msg the interpret handler returns). Run the inherited verb FIRST so the
88
- * // succeed/fail → backoff → onTimer loop advances, THEN fold the enriched
89
- * // payload (`m.result: LlmOk` / `m.error: LlmErr`) into the host's own
90
- * // state — the enrichment lives in the reducer arm, not the handler.
91
- * resilient_ok: (s, m) => {
92
- * const [slice, cmds] = llm.succeed(s.resilience, m.key, m);
93
- * return [{ ...s, resilience: slice, output: m.result.output }, cmds];
94
- * },
95
- * resilient_err: (s, m) => {
96
- * const [slice, cmds] = llm.fail(s.resilience, m.key, m);
97
- * return [{ ...s, resilience: slice, failure: m.error }, cmds];
98
- * },
99
- * deadline_exceeded: (s, m) => lift(s, llm.onTimer(s.resilience, m)),
100
- * },
101
- * subscriptions: (s) => llm.subs(s.resilience),
102
- * subscribe: { deadline: subscribeDeadline },
103
- * interpret: llm.handlers(),
104
- */
8
+ import { StandardSchemaV1 } from '@standard-schema/spec';
105
9
 
106
10
  /**
107
11
  * The minimal structured-output schema contract: `parse(unknown) => T`, the
108
- * zod-style call the handler uses to validate the model's output before it
109
- * settles `resilient_ok`. A throwing `parse` (the zod contract on invalid
110
- * input) propagates out of `invokeOne` and is caught by the resilient handler,
111
- * which settles `resilient_err` (enriched to `LlmErr`) — a parse failure is a
112
- * failure, never a silent pass. Structural so a real `z.ZodType<T>` satisfies
113
- * it without an import.
12
+ * zod-style call `decode` uses to validate the model's output before it
13
+ * settles `resilient_run_ok`. A throwing `parse` (the zod contract on invalid
14
+ * input) becomes a `port_rejected` outcome — a parse failure is a failure,
15
+ * never a silent pass. Structural so a real `z.ZodType<T>` satisfies it
16
+ * without an import.
114
17
  */
115
18
  interface Schema<T> {
116
19
  /** Validate + narrow `value` to `T`, or throw on mismatch (the zod contract). */
117
20
  parse(value: unknown): T;
118
21
  }
22
+ /**
23
+ * One LLM call request — the resilient-call `input` for this module, carried on
24
+ * the `resilient_run` Cmd as plain data — no closures, so it survives
25
+ * persistence and replay. Purpose-discriminated: a `purpose` selecting the
26
+ * schema + prompt assembly, the `model` id, and the opaque per-purpose
27
+ * `payload` the handler's message loader consumes.
28
+ *
29
+ * `key` defaults to `purpose` when the consumer calls `attempt(s, input, at)`,
30
+ * so one in-flight call per purpose is tracked under the resilient-call slice —
31
+ * the common single-call-per-stage shape. A consumer that fans out many calls
32
+ * of one purpose passes a distinct `key`.
33
+ */
34
+ interface LlmCall<P extends string> {
35
+ /** The stage / schema selector — drives both `schemas[purpose]` and message assembly. */
36
+ readonly purpose: P;
37
+ /** The model id to invoke; `null` = the host's default model. */
38
+ readonly model: string | null;
39
+ /** The per-purpose prompt payload the message loader consumes. Opaque to the knob. */
40
+ readonly payload: unknown;
41
+ }
42
+ /** The parsed, typed success carried on `resilient_run_ok`, tagged with its purpose. */
43
+ interface LlmOk<P extends string, O extends Record<P, unknown>> {
44
+ readonly key: string;
45
+ readonly purpose: P;
46
+ readonly output: O[P];
47
+ }
48
+ /** The typed failure variant — every failure path surfaces this, tagged by purpose. */
49
+ interface LlmErr<P extends string> {
50
+ readonly key: string;
51
+ readonly purpose: P;
52
+ /** A human-readable cause (model throw, retry-exhaustion, or schema parse). */
53
+ readonly reason: string;
54
+ /** The original error, carried untouched for the consumer to inspect. */
55
+ readonly error: unknown;
56
+ }
57
+ /**
58
+ * The effect Cmd this module emits: run the LLM call for `key` with `input`. It
59
+ * is `../resilient-call`'s `Cmd.define`d `RunCmd` specialized to the `LlmCall`
60
+ * input — NOT a re-declared shape — so the resilient verbs' return tuples
61
+ * thread through `attempt` / `succeed` / `fail` / `onTimer` with no cast.
62
+ */
63
+ type LlmRunCmd<P extends string> = RunCmd<LlmCall<P>>;
64
+ /** The success Msg the engine mints — resilient-call's, with the parsed `LlmOk`. */
65
+ type LlmSucceedMsg<P extends string, O extends Record<P, unknown>> = SucceedMsg<LlmOk<P, O>, "resilient", LlmCall<P>>;
66
+ /**
67
+ * The failure Msg the engine mints — resilient-call's. Its `error` is the
68
+ * handler's `port_rejected` (an {@link LlmRejected} when the handler used
69
+ * `decode` / `rejected`); read it as the typed {@link LlmErr} with `errOf`.
70
+ */
71
+ type LlmFailMsg<P extends string> = FailMsg<"resilient", LlmCall<P>>;
72
+ /** The retry / deadline timer Msg — `DeadlineExceeded`, inherited from resilient-call. */
73
+ type LlmTimerMsg = DeadlineExceeded;
74
+
75
+ /**
76
+ * @demlik/tea/agent — the model ports and the brain call's Promise handler.
77
+ *
78
+ * `../internal/llm-call` is pure: it owns the brain call's slice, its
79
+ * `Cmd.define`d run Cmd and the parse that turns a model's answer into that
80
+ * Cmd's outcome, and it ships no engine code (ADR 0021). The agent is a Promise
81
+ * host — `toMachine` hands its caller an `interpret` table and `defineAgent`
82
+ * runs itself — so the one handler that actually invokes the model lives here:
83
+ * the two DI ports (`model`, `loadMessages`) and {@link brainHandler}, which
84
+ * calls them and returns the outcome `llm.decode` builds.
85
+ */
86
+
119
87
  /**
120
88
  * The minimal chat-model contract every model the handler talks to must
121
89
  * satisfy — the seed's `InjectableChatModel`, trimmed to the one operation
122
- * llm-call drives for brain-only stages:
90
+ * the brain call drives for brain-only stages:
123
91
  *
124
92
  * `withStructuredOutput(schema)` → a runnable whose `invoke(messages)`
125
93
  * resolves to a typed object matching `schema`.
126
94
  *
127
95
  * `BaseChatModel` from `@langchain/core` is the runtime type; this surface
128
- * names only what llm-call calls so a test fake can ignore the rest. Generic
96
+ * names only what the handler calls so a test fake can ignore the rest. Generic
129
97
  * over the message shape `Msg` so a consumer's loader and model agree on it
130
- * without llm-call inspecting messages.
98
+ * without the agent inspecting messages.
131
99
  */
132
100
  interface Llm<Msg> {
133
101
  withStructuredOutput<T>(schema: Schema<T>): {
@@ -153,8 +121,8 @@ type ModelFactory<Msg> = (modelId: string | null) => Llm<Msg>;
153
121
  * The plain-function model port — the common path. One async function
154
122
  * from the assembled messages to the model's answer; the handler validates the
155
123
  * answer through the purpose's `Schema` exactly as it re-validates the
156
- * structured-output path, so a malformed answer is a `resilient_err`, never a
157
- * corrupt success. `ModelFactory` → `withStructuredOutput(schema).invoke(...)`
124
+ * structured-output path, so a malformed answer is a `resilient_run_err`, never
125
+ * a corrupt success. `ModelFactory` → `withStructuredOutput(schema).invoke(...)`
158
126
  * stays the advanced form for a model that binds the schema itself.
159
127
  *
160
128
  * `T` is the answer type the schema narrows to — for the agent, an `AgentTurn`.
@@ -182,96 +150,6 @@ declare function plainModel<Msg, T>(fn: PlainModel<Msg, T>): ModelFactory<Msg>;
182
150
  * passed as `model` bare — the one runtime shape neither port can own.
183
151
  */
184
152
  declare const PLAIN_MODEL_MISROUTE_REASON: string;
185
- /**
186
- * One LLM call request — the resilient-call `input` for this module, carried on
187
- * the `resilient_run` Cmd as plain data — no closures, so it survives
188
- * persistence and replay. Purpose-discriminated: a `purpose` selecting the
189
- * schema + prompt assembly, the `model` id, and the opaque per-purpose
190
- * `payload` the loader consumes.
191
- *
192
- * `key` defaults to `purpose` when the consumer calls `attempt(s, purpose, …)`,
193
- * so one in-flight call per purpose is tracked under the resilient-call slice —
194
- * the common single-call-per-stage shape. A consumer that fans out many calls
195
- * of one purpose passes a distinct `key`.
196
- */
197
- interface LlmCall<P extends string> {
198
- /** The stage / schema selector — drives both `schemas[purpose]` and message assembly. */
199
- readonly purpose: P;
200
- /** The model id to invoke; `null` = the host's default model. */
201
- readonly model: string | null;
202
- /** The per-purpose prompt payload the `MessageLoader` consumes. Opaque to the knob. */
203
- readonly payload: unknown;
204
- }
205
- /** The parsed, typed success carried on the `resilient_ok` settle Msg, tagged with its purpose. */
206
- interface LlmOk<P extends string, O extends Record<P, unknown>> {
207
- readonly key: string;
208
- readonly purpose: P;
209
- readonly output: O[P];
210
- }
211
- /** The typed failure variant — every failure path surfaces this, tagged by purpose. */
212
- interface LlmErr<P extends string> {
213
- readonly key: string;
214
- readonly purpose: P;
215
- /** A human-readable cause (model throw, retry-exhaustion, or schema parse). */
216
- readonly reason: string;
217
- /** The original error, carried untouched for the consumer to inspect. */
218
- readonly error: unknown;
219
- }
220
- /**
221
- * The settle Msgs llm-call's handler RETURNS from `interpret` so the substrate
222
- * enqueues them as follow-up Msgs (re-entry) into the host reducer — exactly as
223
- * `../resilient-call` does. They are the resilient-call settle Msgs with the
224
- * payloads ENRICHED to llm-call's typed variants: `result` is the parsed,
225
- * purpose-tagged `LlmOk`; `error` is the typed `LlmErr` (purpose + reason +
226
- * raw). The host wires `resilient_ok` → `succeed` and `resilient_err` → `fail`
227
- * reducer arms (the doc-comment wiring), and folds the enriched payload into its
228
- * own state there — llm-call never forces a Msg vocabulary on the host, and the
229
- * settle Msg drives the inherited succeed/fail → backoff → onTimer loop instead
230
- * of bypassing it.
231
- */
232
- type LlmSucceedMsg<P extends string, O extends Record<P, unknown>> = SucceedMsg<LlmOk<P, O>>;
233
- /**
234
- * The FAILURE settle Msg (`resilient_err`) — resilient-call's `FailMsg` with its
235
- * `error: unknown` narrowed to the typed `LlmErr`, so the host reducer reads the
236
- * purpose, the reason and the raw payload without a cast.
237
- */
238
- type LlmFailMsg<P extends string> = Omit<FailMsg, "error"> & {
239
- readonly error: LlmErr<P>;
240
- };
241
- /** The retry / deadline timer Msg — `DeadlineExceeded`, inherited from resilient-call. */
242
- type LlmTimerMsg = DeadlineExceeded;
243
- /**
244
- * The ports the LEGACY detached `handlers(ports)` form takes. Two outbound Msg
245
- * builders the handler hands the typed Ok / Err; the consumer returns its own
246
- * Msg (or `undefined`). KEPT only for `../agent`, which still inherits the
247
- * detached shape; that path does NOT drive the retry loop (it dispatches the
248
- * consumer's Msg directly and never re-enters the resilient settle Msg). New
249
- * consumers use the no-arg `handlers()` form, which RETURNS the settle Msg for
250
- * re-entry and drives the inherited succeed/fail → backoff → onTimer loop.
251
- * `../agent` carries the same retry-loop gap and is fixed separately.
252
- *
253
- * The builders return `M | undefined` — `undefined` is the "dispatch nothing"
254
- * sentinel the detached form checks (`!== undefined`), spelled as `undefined`
255
- * rather than `void` so the union is unambiguous (a `void` member of a union is
256
- * confusing and reads as "may return anything").
257
- */
258
- interface LlmCallPorts<P extends string, O extends Record<P, unknown>, M> {
259
- /** Build the Msg dispatched on a parsed success. Return `undefined` to dispatch nothing. */
260
- readonly onOk: (ok: LlmOk<P, O>) => M | undefined;
261
- /** Build the Msg dispatched on any failure (throw / retry-exhausted / parse). */
262
- readonly onErr: (err: LlmErr<P>) => M | undefined;
263
- }
264
- /**
265
- * The effect Cmd this module emits: run the LLM call for `key` with `input`. The
266
- * `input` is the plain `LlmCall` request — the handler reads `purpose` /
267
- * `model` / `payload` off it (invariant 3: Cmds are data).
268
- *
269
- * It is `../resilient-call`'s `RunCmd` specialized to the `LlmCall` input — NOT a
270
- * re-declared shape — so the resilient verbs' return tuples (`[State, RunCmd[]]`)
271
- * are this exact type and thread through `attempt` / `succeed` / `fail` /
272
- * `onTimer` with no cast.
273
- */
274
- type LlmRunCmd<P extends string> = RunCmd<LlmCall<P>>;
275
153
 
276
154
  /**
277
155
  * @demlik/tea/agent — the domain data model: the tool + turn shapes the consumer
@@ -1121,8 +999,8 @@ type CompactInterpret<M extends {
1121
999
  */
1122
1000
 
1123
1001
  /**
1124
- * The prefix a protocol discriminant was minted from: `resilient_ok` →
1125
- * `resilient`, `compact_run` → `compact`. A tool named by that prefix would
1002
+ * The prefix a protocol discriminant was minted from: `resilient_run_ok` →
1003
+ * `resilient_run`, `compact_run` → `compact`. A tool named by that prefix would
1126
1004
  * mint the same `<name>_ok` / `<name>_err` the agent's reducer already owns.
1127
1005
  */
1128
1006
  type SettlePrefixOf<T extends string> = T extends `${infer P}_ok` | `${infer P}_err` | `${infer P}_run` ? P : never;
@@ -1132,10 +1010,13 @@ declare const SNAPSHOT_WRITE_TYPE = "snapshot_write";
1132
1010
  * A tool name `tool()` refuses. A tool's name is its Cmd `type` — so
1133
1011
  * its interpret key — and the prefix of its settle Msgs, so every string
1134
1012
  * already spoken by the protocol is taken twice over: the settle prefixes
1135
- * (`resilient`, `agent_tool`, `compact`) would overwrite the agent's own
1013
+ * (`resilient_run`, `agent_tool`, `compact`) would overwrite the agent's own
1136
1014
  * reducer handlers through `toMachine`'s last-wins spread, and the discriminants
1137
1015
  * themselves (`compact_run`, `resilient_run`, …) would shadow the interpret
1138
- * handler of that name. Both halves derive from `MsgType`: a new entry there
1016
+ * handler of that name. `resilient` is reserved as a Cmd prefix — the part
1017
+ * before `_run` in the brain Cmd `resilient_run` — not as a settle prefix: its
1018
+ * `resilient_ok` / `resilient_err` name nothing the agent settles. Both halves
1019
+ * derive from `MsgType`: a new entry there
1139
1020
  * reserves its name and its prefix with no second edit. The two names outside
1140
1021
  * the protocol are the router's own `tool_rejected` and the checkpoint handler
1141
1022
  * `snapshot_write`, which `toMachine` merges under the consumer's key.
@@ -1173,60 +1054,67 @@ type ToolThrown = {
1173
1054
  * fixed to what the `ok` schema parses, so a value of the wrong shape is
1174
1055
  * refused where it is written.
1175
1056
  */
1176
- type ToolOk<Ok, E extends Tagged> = (value: Ok) => Result<Ok, E>;
1057
+ type ToolOk<Ok, E extends Tagged> = (value: Ok) => Outcome<Ok, E>;
1177
1058
  /**
1178
1059
  * The typed failure constructor a handler receives: `fail({ _tag })` with `E`
1179
1060
  * fixed to the declared tags, so the literal is checked against them where it
1180
1061
  * is written. (A bare `{ _tag: "x" }` built elsewhere infers `_tag: string`
1181
1062
  * and cannot be — the parameter type is what keeps it literal.)
1182
1063
  */
1183
- type ToolFail<Ok, E extends Tagged> = (error: E) => Result<Ok, E>;
1064
+ type ToolFail<Ok, E extends Tagged> = (error: E) => Outcome<Ok, E>;
1184
1065
  /**
1185
1066
  * The two constructors a handler is handed, one per channel — `ok` for the
1186
- * value the `ok` schema parses, `fail` for a declared `{ _tag }`. Both are
1187
- * tea's, so a handler settles either arm without naming the result library
1188
- * underneath.
1067
+ * value the `ok` schema parses, `fail` for a declared `{ _tag }`. Both build
1068
+ * the core's `Outcome` record (ADR 0021).
1189
1069
  */
1190
1070
  type ToolConstructors<Ok, E extends Tagged> = {
1191
1071
  readonly ok: ToolOk<Ok, E>;
1192
1072
  readonly fail: ToolFail<Ok, E>;
1193
1073
  };
1194
1074
  /**
1195
- * A tool's handler: the parsed `args`, the ctx slice `requirements` named, and the
1196
- * typed `{ ok, fail }`, to a result over the declared channels — `Ok` is what
1197
- * the `ok` schema parses, `E` the declared `_tag` union. An undeclared tag
1198
- * does not compile.
1075
+ * A tool's handler: the parsed `args`, the plain `ctx` the host handed `run`,
1076
+ * and the typed `{ ok, fail }`, to an outcome over the declared channels — `Ok`
1077
+ * is what the `ok` schema parses, `E` the declared `_tag` union. An undeclared
1078
+ * tag does not compile. `Ctx` is whatever the handler annotates its `ctx`
1079
+ * parameter with; tea does no dependency injection (ADR 0020).
1199
1080
  */
1200
- type ToolHandler<Args, Ok, E extends Tagged, R> = (args: Args, ctx: R & PortEmitter, settle: ToolConstructors<Ok, E>) => Promise<Result<Ok, E>>;
1081
+ type ToolHandler<Args, Ok, E extends Tagged, Ctx> = (args: Args, ctx: Ctx & PortEmitter, settle: ToolConstructors<Ok, E>) => Promise<Outcome<Ok, E>>;
1201
1082
  /**
1202
1083
  * What `tool()` returns: the `Cmd.define`d constructor (so `Settled<typeof t>`
1203
1084
  * / `CmdOf<typeof t>` read it like any def) plus the colocated `interpret` handler,
1204
1085
  * the bare `args` schema the router parses a call against, and the
1205
1086
  * `description` a provider adapter declares to the model beside that schema.
1206
1087
  * `E` is the full failure union the Cmd settles with — the declared tags plus
1207
- * `thrown`.
1088
+ * `thrown`. `Ctx` is the ctx the colocated handler reads — a fact about the
1089
+ * handler, never about the Cmd it builds (ADR 0020).
1208
1090
  */
1209
- type ToolDef<Name extends string, Args, Ok, E extends Tagged, R> = CmdDef<Name, ToolInput<Args>, Ok, E, R> & {
1091
+ type ToolDef<Name extends string, Args, Ok, E extends Tagged, Ctx> = CmdDef<Name, ToolInput<Args>, Ok, E> & {
1210
1092
  readonly description: string;
1211
- readonly args: z.ZodType<Args>;
1093
+ readonly args: StandardSchemaV1<unknown, Args>;
1212
1094
  /**
1213
1095
  * The timeout / retry knob this tool declared, or `null` when it declared
1214
1096
  * neither. `toolRouter` serves it to the agent as `resilienceOf`.
1215
1097
  */
1216
1098
  readonly resilience: ToolResilience | null;
1217
- readonly interpret: (cmd: CmdValue<Name, ToolInput<Args>, E, R>, ctx: R & PortEmitter) => Promise<Settled<CmdDef<Name, ToolInput<Args>, Ok, E, R>>>;
1099
+ /**
1100
+ * The colocated handler, as an interpret cell: it returns the tool's
1101
+ * outcome, and the engine mints `<name>_ok` / `<name>_err` from it.
1102
+ */
1103
+ readonly interpret: (cmd: CmdValue<Name, ToolInput<Args>, Ok, E>, ctx: Ctx & PortEmitter) => Promise<Outcome<Ok, E>>;
1104
+ /** Phantom — the ctx the handler reads. Never assigned. */
1105
+ readonly __ctx?: Ctx;
1218
1106
  };
1219
1107
  /** The declaration-erased view the router reads. */
1220
1108
  type AnyToolDef = AnyCmdDef & {
1221
1109
  readonly description: string;
1222
- readonly args: z.ZodType;
1110
+ readonly args: StandardSchemaV1;
1223
1111
  readonly resilience: ToolResilience | null;
1224
1112
  readonly interpret: (cmd: never, ctx: never) => Promise<unknown>;
1225
1113
  };
1226
1114
  /**
1227
1115
  * Declare one tool the model may call — its name, the schemas for its arguments
1228
1116
  * and result, the failures it may return and the handler that runs it — and get
1229
- * back a `Cmd<T, E, R>` definition, whose `T` is what `ok` parses and whose `E`
1117
+ * back a `Cmd<T, Ok, E>` definition, whose `Ok` is what `ok` parses and whose `E`
1230
1118
  * is the `err` tag union, that you pass to `toolRouter` or `defineAgent`.
1231
1119
  *
1232
1120
  * So a tool's two declared channels ARE the kernel's two typed effect channels
@@ -1240,9 +1128,10 @@ type AnyToolDef = AnyCmdDef & {
1240
1128
  * `description`, OpenAI `function.description`) so the model can tell when to
1241
1129
  * call the tool, read off `def.description`, never off the `input` schema;
1242
1130
  * `input` parses the model's `args`; `ok` parses the handler's value at the
1243
- * edge; `err` is the `_tag` list the handler may fail with; `requirements` is the ctx
1244
- * slice it reads, demanded at `run`. The handler returns one of the two
1245
- * constructors it is handed — `ok(value)` or the typed `fail({ _tag })`; a
1131
+ * edge; `err` is the `_tag` list the handler may fail with. The handler reads
1132
+ * its services off the plain `ctx` `run` was handed — annotate its `ctx`
1133
+ * parameter and `defineAgent` asks for that ctx at `run`. The handler returns
1134
+ * one of the two constructors it is handed — `ok(value)` or the typed `fail({ _tag })`; a
1246
1135
  * throw settles `<name>_err` — with the thrown `_tag` when it is a declared
1247
1136
  * one, else as `{ _tag: "thrown", message }`.
1248
1137
  *
@@ -1250,12 +1139,11 @@ type AnyToolDef = AnyCmdDef & {
1250
1139
  * as a widened `string` throws — the same declaration-bug refusal
1251
1140
  * `toolRouter` gives a name declared twice.
1252
1141
  */
1253
- declare function tool<const Name extends string, Args, Ok, const Tags extends readonly string[], R = unknown>(name: Name & NotReserved<Name>, spec: {
1142
+ declare function tool<const Name extends string, Args, Ok, const Tags extends readonly string[], Ctx = unknown>(name: Name & NotReserved<Name>, spec: {
1254
1143
  readonly description: string;
1255
- readonly input: z.ZodType<Args>;
1256
- readonly ok: z.ZodType<Ok>;
1144
+ readonly input: StandardSchemaV1<unknown, Args>;
1145
+ readonly ok: StandardSchemaV1<unknown, Ok>;
1257
1146
  readonly err: Tags;
1258
- readonly requirements?: Requirements<R>;
1259
1147
  /**
1260
1148
  * The budget one call of this tool gets, in ms — the overall cap, measured
1261
1149
  * from the first attempt and not restarted by a retry. When it elapses the
@@ -1275,7 +1163,7 @@ declare function tool<const Name extends string, Args, Ok, const Tags extends re
1275
1163
  * Omit → the first failure is the outcome.
1276
1164
  */
1277
1165
  readonly retry?: ToolResilience["retry"];
1278
- }, handler: ToolHandler<Args, Ok, TaggedError<Tags[number]>, R>): ToolDef<Name, Args, Ok, TaggedError<Tags[number] | "thrown">, R>;
1166
+ }, handler: ToolHandler<Args, Ok, TaggedError<Tags[number]>, Ctx>): ToolDef<Name, Args, Ok, TaggedError<Tags[number] | "thrown">, Ctx>;
1279
1167
  /**
1280
1168
  * A call the router could not hand to a tool: the model named a tool nobody
1281
1169
  * declared, or its `args` failed the tool's `input` schema. `toolOf` is total —
@@ -1302,11 +1190,24 @@ declare const rejected: CmdDef<"tool_rejected", {
1302
1190
  } | {
1303
1191
  readonly [detail: string]: unknown;
1304
1192
  readonly _tag: "malformed_args";
1305
- }, unknown>;
1193
+ }>;
1306
1194
  /** The Cmd `tool_rejected` builds — the router-owned variant of `ToolCmd`. */
1307
1195
  type ToolRejectedCmd = CmdOf<typeof rejected>;
1308
1196
  /** The Cmd union a router's `toolOf` produces — `TC` for `createAgent`. */
1309
1197
  type ToolCmd<T extends AnyToolDef> = CmdOf<T> | ToolRejectedCmd;
1198
+ /** The ctx one tool's handler reads; `unknown` for a handler that reads none. */
1199
+ type ToolCtxOf<T> = T extends {
1200
+ readonly __ctx?: infer Ctx;
1201
+ } ? Ctx : unknown;
1202
+ type UnionToIntersection<U> = (U extends unknown ? (u: U) => void : never) extends (u: infer I) => void ? I : never;
1203
+ type ToolCtxBoxed<T> = T extends unknown ? [ToolCtxOf<T>] : never;
1204
+ type KnownToolCtx<B> = B extends [infer Ctx] ? unknown extends Ctx ? never : Ctx : never;
1205
+ /**
1206
+ * The ctx a tool set's handlers read, intersected — what `run` asks the host
1207
+ * for once the tools are wired into a machine. A tool whose handler reads
1208
+ * nothing leaves its siblings' demand intact.
1209
+ */
1210
+ type ToolsCtx<T extends AnyToolDef> = UnionToIntersection<KnownToolCtx<ToolCtxBoxed<T>>>;
1310
1211
  /** The settled Msg union a router's handlers return — folded by `toMachine`. */
1311
1212
  type ToolMsg<T extends AnyToolDef> = Settled<T> | Settled<typeof rejected>;
1312
1213
  /**
@@ -1355,7 +1256,7 @@ interface ToolRouter<T extends AnyToolDef> {
1355
1256
  /** The `toolOf` for `createAgent`: total, pure, parses `args` at the edge. */
1356
1257
  readonly toolOf: (call: ToolCall) => ToolCmd<T>;
1357
1258
  /** One interpret handler per tool plus the `tool_rejected` handler. */
1358
- readonly interpret: Interpret<ToolMsg<T>, ToolCmd<T>, NoCtx>;
1259
+ readonly interpret: Interpret<ToolMsg<T>, ToolCmd<T>, ToolsCtx<T>>;
1359
1260
  /**
1360
1261
  * The timeout / retry knob the called tool declared — `AgentConfigCore`'s
1361
1262
  * `toolResilienceOf` seam, filled from the `tool()` specs. `null` for a tool
@@ -1419,7 +1320,7 @@ declare function toolRouter<T extends AnyToolDef>(tools: readonly T[]): ToolRout
1419
1320
  * the bare cells at the serial default, and a tool that never overlaps is the
1420
1321
  * exact function `toolRouter` built.
1421
1322
  */
1422
- declare function fanOutInterpret<T extends AnyToolDef>(interpret: Interpret<ToolMsg<T>, ToolCmd<T>, NoCtx>): Interpret<ToolMsg<T>, ToolCmd<T>, NoCtx>;
1323
+ declare function fanOutInterpret<T extends AnyToolDef>(interpret: Interpret<ToolMsg<T>, ToolCmd<T>, ToolsCtx<T>>): Interpret<ToolMsg<T>, ToolCmd<T>, ToolsCtx<T>>;
1423
1324
  /**
1424
1325
  * Turn a tool failure into the human-readable reason string the conversation
1425
1326
  * carries — pass the `{ _tag, ...detail }` a tool failed with, get the tag
@@ -1487,7 +1388,10 @@ type SnapshotInterpret<M extends {
1487
1388
  readonly snapshot_write?: never;
1488
1389
  };
1489
1390
  /**
1490
- * The `toMachine` signature, parametrized on the `Snap` + `Compact` discriminants
1391
+ * The `toMachine` signature. It returns a `Wired`: the machine and, beside it,
1392
+ * the merged `interpret` table and the `deadline` runner its one Sub needs — a
1393
+ * machine carries no handlers (#278, #279), so it is run as
1394
+ * `run(wired.machine, { ...wired, ctx })`. Parametrized on the `Snap` + `Compact` discriminants
1491
1395
  * so the snapshotting / compaction overloads of `createAgent` hand back the right
1492
1396
  * obligations. The `toolInterpret` requires (ON) or forbids (OFF) the
1493
1397
  * `snapshot_write` handler via {@link SnapshotInterpret} and the `compact_run` handler
@@ -1503,11 +1407,16 @@ type SnapshotInterpret<M extends {
1503
1407
  type AgentToMachine<Stage, P extends string, O extends Record<P, AgentTurn>, R, TC extends Cmd, Snap extends boolean, Compact extends boolean> = <Ctx = object, T extends AnyToolDef = never>(opts?: {
1504
1408
  readonly tools?: ToolRouter<T>;
1505
1409
  readonly toolInterpret?: Interpret<AgentMachineMsg<P, O, R> | WiredToolMsg<T>, Exclude<TC, WiredToolCmd<T>>, Ctx> & SnapshotInterpret<AgentMachineMsg<P, O, R> | WiredToolMsg<T>, Snap, Ctx> & CompactInterpret<AgentMachineMsg<P, O, R> | WiredToolMsg<T>, Compact, Ctx>;
1506
- }) => Machine<AgentState<Stage, P, O, R>, AgentMachineMsg<P, O, R> | WiredToolMsg<T>, AgentCmd<P, TC, Snap, Compact>, DeadlineSub, Ctx>;
1410
+ }) => {
1411
+ readonly machine: Machine<AgentState<Stage, P, O, R>, AgentMachineMsg<P, O, R> | WiredToolMsg<T>, AgentCmd<P, TC, Snap, Compact>, DeadlinesSub, Ctx & ToolsCtx<T>>;
1412
+ readonly interpret: Interpret<AgentMachineMsg<P, O, R> | WiredToolMsg<T>, AgentCmd<P, TC, Snap, Compact>, Ctx & ToolsCtx<T>>;
1413
+ readonly subscribe: Subscribe<AgentMachineMsg<P, O, R> | WiredToolMsg<T>, DeadlinesSub, Ctx & ToolsCtx<T>>;
1414
+ };
1507
1415
  /**
1508
1416
  * The agent handle `createAgent` returns — the uniform verb contract every tea
1509
- * composition exposes, plus the wired `toMachine` and the `unsafeDetachedHandlers`
1510
- * escape hatch. `Snap` flows ONLY into `toMachine`'s `toolInterpret` obligation
1417
+ * composition exposes, plus the wired `toMachine` and `brainInterpret`, the
1418
+ * brain call's handler for a consumer wiring the verbs by hand. `Snap` flows
1419
+ * ONLY into `toMachine`'s `toolInterpret` obligation
1511
1420
  * (the snapshot derivation); every verb is snapshot-agnostic. The model
1512
1421
  * message shape `Msg` does not appear on the handle's surface (it is internal to the
1513
1422
  * brain call's loader), so it is not a type parameter here — only `createAgent`
@@ -1537,12 +1446,10 @@ interface AgentKnob<Stage, P extends string, O extends Record<P, AgentTurn>, R,
1537
1446
  at: number
1538
1447
  ]>;
1539
1448
  readonly succeed: AgentVerb1<Stage, P, O, R, TC, [
1540
- key: string,
1541
1449
  msg: AgentLlmOkMsg<P, O>,
1542
1450
  at: number
1543
1451
  ]>;
1544
1452
  readonly fail: AgentVerb1<Stage, P, O, R, TC, [
1545
- key: string,
1546
1453
  msg: AgentLlmErrMsg<P>,
1547
1454
  at: number
1548
1455
  ]>;
@@ -1563,15 +1470,23 @@ interface AgentKnob<Stage, P extends string, O extends Record<P, AgentTurn>, R,
1563
1470
  readonly brainCall: (s: AgentState<Stage, P, O, R>) => LlmCall<P>;
1564
1471
  readonly subs: (s: AgentState<Stage, P, O, R>) => readonly DeadlineSub[];
1565
1472
  readonly toMachine: AgentToMachine<Stage, P, O, R, TC, Snap, Compact>;
1566
- readonly unsafeDetachedHandlers: <M>(ports: AgentPorts<P, O, M>) => AgentDetachedHandlers<P, M>;
1473
+ /**
1474
+ * The brain call's `resilient_run` handler — the one `toMachine` wires. Its
1475
+ * Cmd is `Cmd.define`d, so it returns an outcome and the engine mints the
1476
+ * `resilient_run_ok` / `resilient_run_err` Msg that `succeed` / `fail` fold
1477
+ * (ADR 0021). List `AgentKnob`'s brain Cmd def in `cmds` when you hand-wire.
1478
+ */
1479
+ readonly brainInterpret: () => Interpret<AgentLlmOkMsg<P, O> | AgentLlmErrMsg<P>, AgentLlmRunCmd<P>, unknown>;
1480
+ /** The brain call's `Cmd.define`d run Cmd def — list it in `cmds` when you hand-wire. */
1481
+ readonly brain: RunCmdDef<LlmCall<P>, LlmOk<P, O>>;
1567
1482
  }
1568
1483
  /** A verb taking the state + `Args`, returning the agent's `[State, Cmd[]]` tuple. */
1569
1484
  type AgentVerb1<Stage, P extends string, O extends Record<P, AgentTurn>, R, TC extends Cmd, Args extends readonly unknown[]> = (s: AgentState<Stage, P, O, R>, ...args: Args) => readonly [AgentState<Stage, P, O, R>, readonly AgentCmd<P, TC>[]];
1570
1485
  /** The brain-call SUCCESS settle Msg, inherited from `../llm-call`. */
1571
1486
  type AgentLlmOkMsg<P extends string, O extends Record<P, unknown>> = LlmSucceedMsg<P, O>;
1572
1487
  /**
1573
- * The brain-call FAILURE settle Msg, inherited from `../llm-call` — it re-enters
1574
- * the agent's `fail` verb, which backs off via the retry ladder rather than
1488
+ * The brain-call FAILURE settle Msg, inherited from `../llm-call` — the engine
1489
+ * mints it from the brain handler's outcome and it drives the agent's `fail` verb, which backs off via the retry ladder rather than
1575
1490
  * ending the run.
1576
1491
  */
1577
1492
  type AgentLlmErrMsg<P extends string> = LlmFailMsg<P>;
@@ -1579,35 +1494,11 @@ type AgentLlmErrMsg<P extends string> = LlmFailMsg<P>;
1579
1494
  * The timer Msg (retry + safety deadline) — `DeadlineExceeded`, the shared
1580
1495
  * shape of both composed wrappers' timer Msgs (`LlmTimerMsg` and `MonitoredRunTimerMsg`
1581
1496
  * are both `DeadlineExceeded`). One Msg variant covers both timers; `onTimer`
1582
- * disambiguates by Sub id. This is also the machine Msg the `subscribeDeadline`
1583
- * handler dispatches directly (no wrapping), matching the sibling gold standard.
1497
+ * disambiguates by deadline id. This is also the machine Msg the
1498
+ * `subscribeDeadline` runner dispatches directly (no wrapping), matching the
1499
+ * sibling gold standard.
1584
1500
  */
1585
1501
  type AgentTimerMsg = LlmTimerMsg;
1586
- /** Ports the consumer supplies to the llm-call handler — re-exported shape. */
1587
- type AgentPorts<P extends string, O extends Record<P, unknown>, M> = LlmCallPorts<P, O, M>;
1588
- /**
1589
- * The LEGACY detached brain-call handler dictionary `handlers(ports)` returns,
1590
- * superseded by the `Interpret` table `AgentKnob.toMachine()` wires — reach for
1591
- * `toMachine()` unless you are hand-wiring the verbs yourself.
1592
- *
1593
- * It is the inherited `../llm-call` detached form's exact shape, NOT an
1594
- * `Interpret`.
1595
- * The `resilient_run` handler runs the invoke inside `ctx.waitUntil` and dispatches
1596
- * the consumer's `onOk` / `onErr` Msg directly (returning `void`), so it is a
1597
- * fire-and-forget handler with a structural `{ waitUntil, dispatch }` ctx — it
1598
- * does not re-enter the resilient settle Msg and so does not drive the retry
1599
- * loop. Naming the type precisely (rather than laundering it through
1600
- * `as unknown as Interpret<...>`) keeps `agent.unsafeDetachedHandlers(ports)` honest: the
1601
- * consumer that wires the verbs by hand gets the real detached shape, and its
1602
- * `resilient_run` is callable with a plain Cmd + a `{ waitUntil, dispatch }` ctx
1603
- * with no `as never` at the call site.
1604
- */
1605
- type AgentDetachedHandlers<P extends string, M> = {
1606
- readonly resilient_run: (cmd: AgentLlmRunCmd<P>, ctx: {
1607
- waitUntil(p: Promise<unknown>): void;
1608
- dispatch(msg: M): unknown;
1609
- }) => void;
1610
- };
1611
1502
  /** The Msg `do/host`'s `autoBoot` fires to re-enter the agent's `boot` verb on rehydrate. */
1612
1503
  type AgentBootMsg = {
1613
1504
  readonly type: typeof MsgType.AgentBoot;
@@ -1637,16 +1528,16 @@ declare function agentCancelMsg(at: number): AgentCancelMsg;
1637
1528
  * The agent machine's Msg union — one variant per reducer entry point. A
1638
1529
  * consumer using `toMachine` dispatches `agent_start` to begin and `agent_tool_ok`
1639
1530
  * / `agent_tool_err` to route settled tools back; the brain-call settle Msgs
1640
- * (`resilient_ok` / `resilient_err`) RE-ENTER from the FIXED `brainHandlers`
1641
- * (the substrate enqueues an interpret handler's returned Msg as a follow-up),
1642
- * driving `succeed` / `fail`. Time enters via `at` on every variant — the
1531
+ * (`resilient_run_ok` / `resilient_run_err`) are minted by the engine from the
1532
+ * outcome the FIXED `brainHandlers` returns (ADR 0021), driving `succeed` /
1533
+ * `fail`. Time enters via `at` on every variant — the
1643
1534
  * reducer never reads the clock.
1644
1535
  *
1645
1536
  * There is deliberately NO `agent_turn` variant here. The wired loop folds a
1646
- * model turn INSIDE `succeed` from the re-entered `resilient_ok` — a single
1537
+ * model turn INSIDE `succeed` from the minted `resilient_run_ok` — a single
1647
1538
  * settle Msg advances both the retry slice and the conversation (the L3 fix).
1648
1539
  * Exposing `agent_turn` as a dispatchable Msg re-opened the stuck-`running` bug:
1649
- * a hand-fed turn folds the conversation without ever re-entering `resilient_ok`,
1540
+ * a hand-fed turn folds the conversation without ever settling `resilient_run_ok`,
1650
1541
  * so `succeed` never runs and the resilient slice stays `running`. The
1651
1542
  * `turn` verb remains on the handle for the consumer that wires the verbs by hand
1652
1543
  * (manual wiring), but it is not part of the one wired machine's Msg surface.
@@ -1678,7 +1569,7 @@ type AgentMachineMsg<P extends string, O extends Record<P, unknown>, R> = {
1678
1569
  * the retry plumbing is renamed.
1679
1570
  *
1680
1571
  * - `TurnSettled` — a brain turn settled (the model produced an `AgentTurn`).
1681
- * Projected off the private `resilient_ok` settle Msg; carries the parsed
1572
+ * Projected off the private `resilient_run_ok` settle Msg; carries the parsed
1682
1573
  * `turn` (the narration + tool calls the model asked for).
1683
1574
  * - `ToolSettled` — a tool call settled OK. Projected off the private
1684
1575
  * `agent_tool_ok` Msg; carries the `callId` and the tool `result`.
@@ -1704,7 +1595,7 @@ type AgentEvent<R> = {
1704
1595
  * `run(machine, { events: agentEvents() })` to light up `runtime.on(...)`.
1705
1596
  *
1706
1597
  * This is the ONE place the agent's PRIVATE Msg names are read: it maps
1707
- * `resilient_ok` → `TurnSettled` and `agent_tool_ok` → `ToolSettled`, and reads
1598
+ * `resilient_run_ok` → `TurnSettled` and `agent_tool_ok` → `ToolSettled`, and reads
1708
1599
  * the post-transition `run.phase` for `RunDone`. The mapping is total over the
1709
1600
  * Msg union (a `default`-free switch on the discriminant) and returns `[]` for
1710
1601
  * the transitions that carry no public event (start / boot / timer / the error
@@ -1712,7 +1603,7 @@ type AgentEvent<R> = {
1712
1603
  *
1713
1604
  * A single transition may emit more than one event: the brain turn that retires
1714
1605
  * the final stage settles a turn (`TurnSettled`) AND finishes the run
1715
- * (`RunDone`) — both are projected from that one `resilient_ok` transition.
1606
+ * (`RunDone`) — both are projected from that one `resilient_run_ok` transition.
1716
1607
  * `RunDone` is gated on `run.phase === "done"`, which the wired loop reaches
1717
1608
  * exactly once (the agent is terminal there and dispatches no further
1718
1609
  * transition), so the event fires once per run.
@@ -1770,4 +1661,4 @@ declare function liftAgent<S extends {
1770
1661
  agent: AgentState<Stage, P, O, R>;
1771
1662
  }, Stage, P extends string, O extends Record<P, unknown>, R, C extends Cmd>(state: S, [slice, cmds]: readonly [AgentState<Stage, P, O, R>, readonly C[]]): readonly [S, readonly C[]];
1772
1663
 
1773
- export { PLAIN_MODEL_MISROUTE_REASON as $, type AnyToolDef as A, type AgentSnapshotConfig as B, type Conversation as C, type AgentStatus as D, type AgentTerminalFailure as E, type AgentTimerMsg as F, type AgentToMachine as G, type Awaiting as H, COMPACTION_PURPOSE as I, type CompactInterpret as J, type CompactionOutputs as K, type CompactionPurpose as L, type CompactionSummary as M, type LlmCall as N, type LlmErr as O, type PlainModel as P, type LlmFailMsg as Q, type LlmOk as R, type StreamingModel as S, type ToolCall as T, type LlmRunCmd as U, type LlmSucceedMsg as V, type WiredToolMsg as W, type MessageLoader as X, type ModelFactory as Y, type ModelPort as Z, type ModelStream as _, type ToolOutcome as a, type ReservedToolName as a0, type Schema as a1, type SnapshotInterpret as a2, TOOL_RETRY_EXHAUSTED_TAG as a3, TOOL_TIMEOUT_TAG as a4, type TaggedFailure as a5, type ToolConstructors as a6, type ToolDef as a7, type ToolError as a8, type ToolFail as a9, liftAgent as aA, mergeInterpret as aB, plainModel as aC, status as aD, tool as aE, toolErrorReason as aF, toolRouter as aG, type ToolFailure as aa, type ToolHandler as ab, type ToolInput as ac, type ToolMsg as ad, type ToolOk as ae, type ToolRecord as af, type ToolRejectedCmd as ag, type ToolRejection as ah, type ToolResilience as ai, type ToolResilienceError as aj, type ToolRetryExhausted as ak, type ToolRouter as al, type ToolSettlement as am, type ToolThrown as an, type ToolTimedOut as ao, type WiredToolCmd as ap, agentBootMsg as aq, agentCancelMsg as ar, agentEvents as as, agentTurnSchema as at, compactionSummarySchema as au, fanOutInterpret as av, isAgentTurn as aw, isCompactionSummary as ax, isReservedToolName as ay, isStreamingModel as az, type AgentTurn as b, type AgentState as c, type ToolResult as d, type ToolFailureOf as e, type ToolCmd as f, type AgentEvent as g, type TurnChunk as h, type AgentMachineMsg as i, type AgentCmd as j, type AgentConfigCore as k, type CompactionPolicy as l, type AgentKnob as m, type AgentBootMsg as n, type AgentCancelMsg as o, type AgentCompactErrMsg as p, type AgentCompactOkMsg as q, type AgentCompactRunCmd as r, type AgentCompactionConfig as s, type AgentConfig as t, type AgentDetachedHandlers as u, type AgentFailure as v, type AgentLlmErrMsg as w, type AgentLlmOkMsg as x, type AgentLlmRunCmd as y, type AgentPorts as z };
1664
+ export { PLAIN_MODEL_MISROUTE_REASON as $, type AnyToolDef as A, type AgentStatus as B, type Conversation as C, type AgentTerminalFailure as D, type AgentTimerMsg as E, type AgentToMachine as F, type Awaiting as G, COMPACTION_PURPOSE as H, type CompactInterpret as I, type CompactionOutputs as J, type CompactionPurpose as K, type CompactionSummary as L, type Llm as M, type LlmCall as N, type LlmErr as O, type PlainModel as P, type LlmFailMsg as Q, type LlmOk as R, type StreamingModel as S, type ToolCall as T, type LlmRunCmd as U, type LlmSucceedMsg as V, type WiredToolMsg as W, type MessageLoader as X, type ModelFactory as Y, type ModelPort as Z, type ModelStream as _, type ToolOutcome as a, type ReservedToolName as a0, type Schema as a1, type SnapshotInterpret as a2, TOOL_RETRY_EXHAUSTED_TAG as a3, TOOL_TIMEOUT_TAG as a4, type TaggedFailure as a5, type ToolConstructors as a6, type ToolDef as a7, type ToolError as a8, type ToolFail as a9, liftAgent as aA, mergeInterpret as aB, plainModel as aC, status as aD, tool as aE, toolErrorReason as aF, toolRouter as aG, type ToolFailure as aa, type ToolHandler as ab, type ToolInput as ac, type ToolMsg as ad, type ToolOk as ae, type ToolRecord as af, type ToolRejectedCmd as ag, type ToolRejection as ah, type ToolResilience as ai, type ToolResilienceError as aj, type ToolRetryExhausted as ak, type ToolRouter as al, type ToolSettlement as am, type ToolThrown as an, type ToolTimedOut as ao, type WiredToolCmd as ap, agentBootMsg as aq, agentCancelMsg as ar, agentEvents as as, agentTurnSchema as at, compactionSummarySchema as au, fanOutInterpret as av, isAgentTurn as aw, isCompactionSummary as ax, isReservedToolName as ay, isStreamingModel as az, type AgentTurn as b, type AgentState as c, type ToolResult as d, type ToolFailureOf as e, type ToolsCtx as f, type AgentEvent as g, type TurnChunk as h, type AgentMachineMsg as i, type AgentCmd as j, type ToolCmd as k, type AgentConfigCore as l, type CompactionPolicy as m, type AgentKnob as n, type AgentBootMsg as o, type AgentCancelMsg as p, type AgentCompactErrMsg as q, type AgentCompactOkMsg as r, type AgentCompactRunCmd as s, type AgentCompactionConfig as t, type AgentConfig as u, type AgentFailure as v, type AgentLlmErrMsg as w, type AgentLlmOkMsg as x, type AgentLlmRunCmd as y, type AgentSnapshotConfig as z };