@demlik/tea 0.17.0 → 0.18.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 (119) hide show
  1. package/README.md +3 -2
  2. package/dist/agent/index.d.ts +182 -35
  3. package/dist/agent/index.js +11 -11
  4. package/dist/{chunk-KWNCM6XM.js → chunk-AHW2CLPT.js} +65 -18
  5. package/dist/chunk-AHW2CLPT.js.map +1 -0
  6. package/dist/{chunk-K4ETBNKS.js → chunk-AIIXV4XB.js} +38 -9
  7. package/dist/chunk-AIIXV4XB.js.map +1 -0
  8. package/dist/{chunk-LYVOGOBC.js → chunk-BRX3243I.js} +3 -3
  9. package/dist/{chunk-LYVOGOBC.js.map → chunk-BRX3243I.js.map} +1 -1
  10. package/dist/{chunk-GWWCCSDH.js → chunk-C3G2QFEZ.js} +4 -4
  11. package/dist/{chunk-GWWCCSDH.js.map → chunk-C3G2QFEZ.js.map} +1 -1
  12. package/dist/{chunk-C4U5D5HP.js → chunk-FNGZMVIT.js} +3 -3
  13. package/dist/chunk-FNGZMVIT.js.map +1 -0
  14. package/dist/{chunk-QWIPH4YH.js → chunk-H2ELKHI6.js} +16 -6
  15. package/dist/chunk-H2ELKHI6.js.map +1 -0
  16. package/dist/chunk-H3MWNH7A.js +119 -0
  17. package/dist/chunk-H3MWNH7A.js.map +1 -0
  18. package/dist/chunk-I7E7AD2S.js +213 -0
  19. package/dist/chunk-I7E7AD2S.js.map +1 -0
  20. package/dist/{chunk-OYR7ENKU.js → chunk-IHUNKHDX.js} +3 -3
  21. package/dist/{chunk-OYR7ENKU.js.map → chunk-IHUNKHDX.js.map} +1 -1
  22. package/dist/chunk-JVE2LBFJ.js +21 -0
  23. package/dist/chunk-JVE2LBFJ.js.map +1 -0
  24. package/dist/chunk-JVKU2UQC.js +34 -0
  25. package/dist/chunk-JVKU2UQC.js.map +1 -0
  26. package/dist/{chunk-OPH6Y4UT.js → chunk-JYNYG5SF.js} +4 -4
  27. package/dist/{chunk-OPH6Y4UT.js.map → chunk-JYNYG5SF.js.map} +1 -1
  28. package/dist/{chunk-XBZQT2TD.js → chunk-PCJA2HTZ.js} +437 -162
  29. package/dist/chunk-PCJA2HTZ.js.map +1 -0
  30. package/dist/{chunk-DFUEAA6L.js → chunk-PQSDUX6B.js} +3 -3
  31. package/dist/{chunk-DFUEAA6L.js.map → chunk-PQSDUX6B.js.map} +1 -1
  32. package/dist/{chunk-6XBEYZME.js → chunk-WTSOW2MD.js} +5 -5
  33. package/dist/{chunk-6XBEYZME.js.map → chunk-WTSOW2MD.js.map} +1 -1
  34. package/dist/{chunk-4PXNZ5UY.js → chunk-XVIKSRCK.js} +4 -4
  35. package/dist/{chunk-4PXNZ5UY.js.map → chunk-XVIKSRCK.js.map} +1 -1
  36. package/dist/{chunk-4NTCPTNQ.js → chunk-YIMOFXST.js} +3 -3
  37. package/dist/{chunk-4NTCPTNQ.js.map → chunk-YIMOFXST.js.map} +1 -1
  38. package/dist/{core-rDbOaJTN.d.ts → core-Ce9ncpuv.d.ts} +5 -4
  39. package/dist/do/index.d.ts +140 -64
  40. package/dist/do/index.js +17 -18
  41. package/dist/do/index.js.map +1 -1
  42. package/dist/drive-loop-CsUsW3Wo.d.ts +127 -0
  43. package/dist/{durable-effects-CNaw97Be.d.ts → durable-effects-BmUrRA-h.d.ts} +1 -1
  44. package/dist/effect/index.d.ts +6 -150
  45. package/dist/effect/index.js +4 -96
  46. package/dist/effect/index.js.map +1 -1
  47. package/dist/extension/index.d.ts +7 -5
  48. package/dist/extension/index.js +2 -3
  49. package/dist/extension/index.js.map +1 -1
  50. package/dist/flow/index.d.ts +13 -13
  51. package/dist/flow/index.js +13 -12
  52. package/dist/flow/index.js.map +1 -1
  53. package/dist/idempotency/index.d.ts +3 -3
  54. package/dist/idempotency/index.js +4 -4
  55. package/dist/{index-q1PoukOZ.d.ts → index-2kNxy6az.d.ts} +2 -2
  56. package/dist/{index-B_BxplWi.d.ts → index-B1Wzarkl.d.ts} +1 -1
  57. package/dist/{index-Cberb5Rr.d.ts → index-Bf9_bNql.d.ts} +2 -2
  58. package/dist/index-BnsAqn0-.d.ts +286 -0
  59. package/dist/{index-Cx0F2M34.d.ts → index-Ce5GYAuI.d.ts} +2 -2
  60. package/dist/{index-CWmsXNdX.d.ts → index-D8sYVzCI.d.ts} +1 -1
  61. package/dist/{index-CcrKLtse.d.ts → index-DWdg7R1l.d.ts} +1 -1
  62. package/dist/{index-BOrsbdAf.d.ts → index-Dy3379ve.d.ts} +5 -5
  63. package/dist/{index-DaX_P35Q.d.ts → index-e36uEyl4.d.ts} +3 -3
  64. package/dist/index.d.ts +109 -36
  65. package/dist/index.js +2 -2
  66. package/dist/jev/index.d.ts +8 -8
  67. package/dist/jev/index.js +6 -7
  68. package/dist/jev/index.js.map +1 -1
  69. package/dist/{machine-BcfCFMYF.d.ts → machine-CuojfZup.d.ts} +353 -57
  70. package/dist/machine-viz/index.d.ts +1 -1
  71. package/dist/machine-viz/index.js +2 -2
  72. package/dist/mem/index.d.ts +6 -6
  73. package/dist/mem/index.js +6 -2
  74. package/dist/mem/index.js.map +1 -1
  75. package/dist/node/index.d.ts +16 -10
  76. package/dist/node/index.js +22 -3
  77. package/dist/node/index.js.map +1 -1
  78. package/dist/otel/index.d.ts +161 -0
  79. package/dist/otel/index.js +403 -0
  80. package/dist/otel/index.js.map +1 -0
  81. package/dist/paginate/index.d.ts +4 -4
  82. package/dist/paginate/index.js +5 -5
  83. package/dist/parity/index.d.ts +3 -3
  84. package/dist/parity/index.js +3 -3
  85. package/dist/pbt/index.d.ts +166 -53
  86. package/dist/pbt/index.js +2 -2
  87. package/dist/pbt/index.js.map +1 -1
  88. package/dist/persistence/index.d.ts +5 -5
  89. package/dist/persistence/index.js +5 -5
  90. package/dist/promise/index.d.ts +2 -2
  91. package/dist/promise/index.js +4 -3
  92. package/dist/react/index.d.ts +2 -2
  93. package/dist/resilience/index.d.ts +13 -9
  94. package/dist/resilience/index.js +5 -5
  95. package/dist/resilience/index.js.map +1 -1
  96. package/dist/{runtime-types-B62Ucnxr.d.ts → runtime-types-BKg2CGMx.d.ts} +88 -14
  97. package/dist/testing/effect/index.d.ts +65 -0
  98. package/dist/testing/effect/index.js +148 -0
  99. package/dist/testing/effect/index.js.map +1 -0
  100. package/dist/testing/index.d.ts +12 -158
  101. package/dist/testing/index.js +4 -130
  102. package/dist/testing/index.js.map +1 -1
  103. package/dist/testing/promise/index.d.ts +41 -0
  104. package/dist/testing/promise/index.js +37 -0
  105. package/dist/testing/promise/index.js.map +1 -0
  106. package/dist/timing/index.d.ts +4 -4
  107. package/dist/timing/index.js +4 -4
  108. package/dist/{types-DPm5YCDQ.d.ts → types-SzNSHKlV.d.ts} +1 -1
  109. package/dist/work-queue/index.d.ts +4 -4
  110. package/dist/work-queue/index.js +4 -3
  111. package/dist/work-queue/index.js.map +1 -1
  112. package/package.json +25 -13
  113. package/dist/chunk-C4U5D5HP.js.map +0 -1
  114. package/dist/chunk-G5E74IJB.js +0 -8
  115. package/dist/chunk-G5E74IJB.js.map +0 -1
  116. package/dist/chunk-K4ETBNKS.js.map +0 -1
  117. package/dist/chunk-KWNCM6XM.js.map +0 -1
  118. package/dist/chunk-QWIPH4YH.js.map +0 -1
  119. package/dist/chunk-XBZQT2TD.js.map +0 -1
package/README.md CHANGED
@@ -55,8 +55,9 @@ file imports only the core, so it runs unchanged on either engine.
55
55
  imports no engine.
56
56
  - `@demlik/tea/promise` — the Promise engine. Handlers return Promises.
57
57
  - `@demlik/tea/effect` — the Effect engine (`experimental`, Effect v4). Handlers
58
- return Effects, services come from your Layers, and closing the scope
59
- interrupts whatever is in flight.
58
+ return Effects, services come from your Layers, the handle's verbs return
59
+ Effects with typed errors, and closing the scope interrupts whatever is in
60
+ flight.
60
61
 
61
62
  [Run a machine on the Promise engine](https://github.com/kamp-us/demlik/blob/main/docs/how-to/run-on-the-promise-engine.md)
62
63
  and [on the Effect engine](https://github.com/kamp-us/demlik/blob/main/docs/how-to/run-on-the-effect-engine.md)
@@ -1,19 +1,19 @@
1
- import { M as Machine, o as Interpret, d as Subscribe, C as Cmd } from '../core-rDbOaJTN.js';
2
- import { b as DeadlinesSub } from '../index-DaX_P35Q.js';
3
- export { a as DeadlineSub, c as deadlineSub, e as deadlinesSub, s as subscribeDeadline } from '../index-DaX_P35Q.js';
4
- import { T as ToolCall, a as ToolOutcome, C as Conversation, A as AnyToolDef, P as PlainModel, b as AgentTurn, S as StreamingModel, c as AgentState, d as ToolResult, e as ToolFailureOf, f as ToolsCtx, g as AgentEvent, h as TurnChunk, i as AgentMachineMsg, W as WiredToolMsg, j as AgentCmd, k as ToolCmd, l as AgentConfigCore, m as CompactionPolicy, n as AgentKnob } from '../machine-BcfCFMYF.js';
5
- export { o as AgentBootMsg, p as AgentCancelMsg, q as AgentCompactErrMsg, r as AgentCompactOkMsg, s as AgentCompactRunCmd, t as AgentCompactionConfig, u as AgentConfig, v as AgentFailure, w as AgentLlmErrMsg, x as AgentLlmOkMsg, y as AgentLlmRunCmd, z as AgentSnapshotConfig, B as AgentStatus, D as AgentTerminalFailure, E as AgentTimerMsg, F as AgentToMachine, G as Awaiting, H as COMPACTION_PURPOSE, I as CompactInterpret, J as CompactionOutputs, K as CompactionPurpose, L as CompactionSummary, M as Llm, N as LlmCall, O as LlmErr, Q as LlmFailMsg, R as LlmOk, U as LlmRunCmd, V as LlmSucceedMsg, X as MessageLoader, Y as ModelFactory, Z as ModelPort, _ as ModelStream, $ as PLAIN_MODEL_MISROUTE_REASON, a0 as ReservedToolName, a1 as Schema, a2 as SnapshotInterpret, a3 as TOOL_RETRY_EXHAUSTED_TAG, a4 as TOOL_TIMEOUT_TAG, a5 as TaggedFailure, a6 as ToolConstructors, a7 as ToolDef, a8 as ToolError, a9 as ToolFail, aa as ToolFailure, ab as ToolHandler, ac as ToolInput, ad as ToolMsg, ae as ToolOk, af as ToolRecord, ag as ToolRejectedCmd, ah as ToolRejection, ai as ToolResilience, aj as ToolResilienceError, ak as ToolRetryExhausted, al as ToolRouter, am as ToolSettlement, an as ToolThrown, ao as ToolTimedOut, ap as WiredToolCmd, aq as agentBootMsg, ar as agentCancelMsg, as as agentEvents, at as agentTurnSchema, au as compactionSummarySchema, av as fanOutInterpret, aw as isAgentTurn, ax as isCompactionSummary, ay as isReservedToolName, az as isStreamingModel, aA as liftAgent, aB as mergeInterpret, aC as plainModel, aD as status, aE as tool, aF as toolErrorReason, aG as toolRouter } from '../machine-BcfCFMYF.js';
6
- import { C as CtxArg, S as Store } from '../runtime-types-B62Ucnxr.js';
7
- import { E as EndedRun } from '../index-BOrsbdAf.js';
8
- export { M as MonitoredRunCmd, R as RunFailure } from '../index-BOrsbdAf.js';
1
+ import { M as Machine, I as Interpret, S as Subscribe, H as HandlerCtx, C as Cmd } from '../core-Ce9ncpuv.js';
2
+ import { b as DeadlinesSub } from '../index-e36uEyl4.js';
3
+ export { a as DeadlineSub, m as deadlineSub, o as deadlinesSub, s as subscribeDeadline } from '../index-e36uEyl4.js';
4
+ import { M as MessageContent, T as ToolCall, a as ToolOutcome, C as ContentPart, b as Conversation, c as AnyToolDef, d as ToolsCtx, e as AgentState, f as AgentTurn, g as ToolResult, A as AgentEvent, h as TurnChunk, i as AgentMachineMsg, W as WiredToolMsg, j as AgentCmd, k as ToolCmd, P as PlainModel, S as StreamingModel, l as ToolFailureOf, m as AgentTerminalFailure, N as NotReserved, n as ToolDef, o as ToolThrown, p as AgentEndedStatus, q as AgentConfigCore, r as CompactionPolicy, s as AgentKnob } from '../machine-CuojfZup.js';
5
+ export { t as AGENT_EVENT_TYPES, u as AgentBootMsg, v as AgentCancelMsg, w as AgentCompactErrMsg, x as AgentCompactOkMsg, y as AgentCompactRunCmd, z as AgentCompactionConfig, B as AgentConfig, D as AgentEventHead, E as AgentFailure, F as AgentLifecycleNote, G as AgentLlmErrMsg, H as AgentLlmOkMsg, I as AgentLlmRunCmd, J as AgentSnapshotConfig, K as AgentStatus, L as AgentTimerMsg, O as AgentToMachine, Q as Awaiting, R as COMPACTION_PURPOSE, U as CompactInterpret, V as CompactionOutputs, X as CompactionPurpose, Y as CompactionSummary, Z as FILE_OMITTED, _ as FilePart, $ as IMAGE_OMITTED, a0 as ImagePart, a1 as Llm, a2 as LlmCall, a3 as LlmErr, a4 as LlmFailMsg, a5 as LlmOk, a6 as LlmRunCmd, a7 as LlmSucceedMsg, a8 as MediaSource, a9 as MessageLoader, aa as ModelFactory, ab as ModelPort, ac as ModelStream, ad as PLAIN_MODEL_MISROUTE_REASON, ae as ReservedToolName, af as Schema, ag as SnapshotInterpret, ah as TOOL_RETRY_EXHAUSTED_TAG, ai as TOOL_TIMEOUT_TAG, aj as TaggedFailure, ak as TextPart, al as ToolConstructors, am as ToolError, an as ToolFail, ao as ToolFailure, ap as ToolHandler, aq as ToolInput, ar as ToolMsg, as as ToolOk, at as ToolRecord, au as ToolRejectedCmd, av as ToolRejection, aw as ToolResilience, ax as ToolResilienceError, ay as ToolRetryExhausted, az as ToolRouter, aA as ToolSettlement, aB as ToolTimedOut, aC as TurnUsage, aD as WiredToolCmd, aE as agentBootMsg, aF as agentCancelMsg, aG as agentEvents, aH as agentTurnSchema, aI as compactionSummarySchema, aJ as contentParts, aK as fanOutInterpret, aL as isAgentTurn, aM as isCompactionSummary, aN as isReservedToolName, aO as isStreamingModel, aP as isTurnUsage, aQ as liftAgent, aR as mergeInterpret, aS as omitMedia, aT as plainModel, aU as status, aV as tool, aW as toolErrorReason, aX as toolRouter } from '../machine-CuojfZup.js';
6
+ import { StandardSchemaV1 } from '@standard-schema/spec';
7
+ import { C as CtxArg, S as Store } from '../runtime-types-BKg2CGMx.js';
8
+ import { E as EndedRun } from '../index-Dy3379ve.js';
9
+ export { M as MonitoredRunCmd, R as RunFailure } from '../index-Dy3379ve.js';
9
10
  import { RetryPolicy } from '../retry-backoff/index.js';
10
- import '@standard-schema/spec';
11
- import '../types-DPm5YCDQ.js';
12
- import '../index-q1PoukOZ.js';
11
+ import '../types-SzNSHKlV.js';
12
+ import '../index-2kNxy6az.js';
13
13
  import '../protocol-ClRZBhHQ.js';
14
- import '../index-Cx0F2M34.js';
15
- import '../index-CcrKLtse.js';
16
- import '../index-CWmsXNdX.js';
14
+ import '../index-Ce5GYAuI.js';
15
+ import '../index-DWdg7R1l.js';
16
+ import '../index-D8sYVzCI.js';
17
17
 
18
18
  /**
19
19
  * @demlik/tea/agent — `defineAgent`, the convenience layer over `createAgent`.
@@ -35,13 +35,19 @@ import '../index-CWmsXNdX.js';
35
35
  * adapter decides how a failure reads to its model. An `assistant` message
36
36
  * carries the turn's opaque `provider` slot exactly as the adapter returned it
37
37
  * (see `AgentTurn`), present only when the stored turn has one.
38
+ *
39
+ * A `user` message's content is a string or a list of {@link ContentPart}s —
40
+ * `contentParts` reads either as parts. A `tool` message carries `parts` beside
41
+ * its outcome when the tool declared `content` and settled `ok`: those parts
42
+ * are what the model should see (a screenshot, say), so an adapter sends them
43
+ * in place of the stringified result. No `parts` → the outcome is the payload.
38
44
  */
39
45
  type AgentMessage = {
40
46
  readonly role: "system";
41
47
  readonly content: string;
42
48
  } | {
43
49
  readonly role: "user";
44
- readonly content: string;
50
+ readonly content: MessageContent;
45
51
  } | {
46
52
  readonly role: "assistant";
47
53
  readonly content: string;
@@ -52,7 +58,13 @@ type AgentMessage = {
52
58
  readonly callId: string;
53
59
  readonly name: string;
54
60
  readonly outcome: ToolOutcome<unknown>;
61
+ readonly parts?: readonly ContentPart[];
55
62
  };
63
+ /**
64
+ * How `renderPrompt` reads the parts a settled call shows the model — a
65
+ * `ToolRouter`'s `partsOf`. `null` → the message carries no `parts`.
66
+ */
67
+ type ToolPartsOf = (call: ToolCall, outcome: ToolOutcome<unknown>) => readonly ContentPart[] | null;
56
68
  /**
57
69
  * The brain-call payload `defineAgent` builds from the durable state — everything
58
70
  * `messagesOf` renders, so the prompt is a pure function of the Model and the
@@ -202,8 +214,9 @@ interface DefineAgentConfig<T extends AnyToolDef> {
202
214
  * the same terminal an aborted `signal` reaches, with the transcript intact
203
215
  * and no further model call made. Where `maxTurns` and `maxElapsedMs` bound
204
216
  * a quantity the agent counts for you and `deadlineMs` watches for a stall,
205
- * this bounds whatever you name — a token ledger you keep, an external flag,
206
- * a condition on the turns so far. Omit → no predicate.
217
+ * this bounds whatever you name — a token budget over `state.usage` (the
218
+ * run's provider-reported total), an external flag, a condition on the turns
219
+ * so far. Omit → no predicate.
207
220
  *
208
221
  * It must be PURE: the reducer calls it, so a replay hands it the same state
209
222
  * and must get the same answer. And it is config rather than Model — a
@@ -291,9 +304,14 @@ interface DefineAgentConfig<T extends AnyToolDef> {
291
304
  readonly toolConcurrency?: number;
292
305
  }
293
306
  /**
294
- * The lid's compaction budget: the two numbers that say when a transcript is
295
- * too long and how much of it survives the fold. Both are plain counts, so the
296
- * trigger they build is PURE — a replay re-decides identically, and no clock or
307
+ * The lid's compaction budget: when a transcript is too long, and how much of
308
+ * it survives the fold. "Too long" is a turn count (`afterTurns`), a context
309
+ * size (`afterContextTokens`), or both — whichever is reached first folds — and
310
+ * a budget naming neither is a compile error, because it could never fire.
311
+ *
312
+ * Both triggers read durable facts, so the trigger they build is PURE — a replay
313
+ * re-decides identically. The context size is what the PROVIDER reported on the
314
+ * last brain turn, journaled with that turn like its `content`; no clock and no
297
315
  * token estimate enters the Model (ADR 0004).
298
316
  *
299
317
  * This is deliberately a threshold rather than the core's `planCompaction`
@@ -302,12 +320,32 @@ interface DefineAgentConfig<T extends AnyToolDef> {
302
320
  * run that needs its own heuristic descends to `createAgent`, whose
303
321
  * `CompactionPolicy` this is built from.
304
322
  */
305
- interface DefineAgentCompaction {
323
+ type DefineAgentCompaction = (CompactionTriggers & {
324
+ readonly afterTurns: number;
325
+ readonly afterContextTokens?: number;
326
+ }) | (CompactionTriggers & {
327
+ readonly afterTurns?: number;
328
+ readonly afterContextTokens: number;
329
+ });
330
+ /** The fields every {@link DefineAgentCompaction} arm shares. */
331
+ interface CompactionTriggers {
306
332
  /**
307
333
  * Fold once the conversation holds at least this many turns, counted BEFORE
308
334
  * the brain call about to fire. Must be at least `1`.
309
335
  */
310
- readonly afterTurns: number;
336
+ readonly afterTurns?: number;
337
+ /**
338
+ * Fold once the latest context size — `inputTokens + outputTokens` the
339
+ * provider reported for the most recent brain turn — reaches this many
340
+ * tokens, checked BEFORE the brain call about to fire (#332). The number is
341
+ * yours: tea keeps no per-model window registry.
342
+ *
343
+ * A turn that reported no usage never fires it, and a fold clears the
344
+ * reading, so one reading folds at most once: the next fold waits for a turn
345
+ * to report what the shrunk transcript costs. It needs a `model` whose turns
346
+ * carry `usage`; with one that never reports it, this trigger never fires.
347
+ */
348
+ readonly afterContextTokens?: number;
311
349
  /**
312
350
  * How many of the NEWEST turns survive the fold intact, beside the summary.
313
351
  * Everything older becomes the summary's one synthetic head turn. Omit → `0`:
@@ -505,8 +543,119 @@ interface DefinedAgent<T extends AnyToolDef> {
505
543
  * defined agent, so `createAgent` is for a rebuild rather than for a detour.
506
544
  */
507
545
  declare function defineAgent<T extends AnyToolDef>(config: DefineAgentConfig<T>): DefinedAgent<T>;
508
- /** The prompt as messages: the head, then each turn with its tool outcomes. PURE. */
509
- declare function renderPrompt(prompt: AgentPrompt<unknown>): AgentMessage[];
546
+ /**
547
+ * The prompt as messages: the head, then each turn with its tool outcomes.
548
+ * `partsOf` reads the parts a settled call shows the model; omit it and no
549
+ * `tool` message carries `parts`. PURE.
550
+ */
551
+ declare function renderPrompt(prompt: AgentPrompt<unknown>, partsOf?: ToolPartsOf): AgentMessage[];
552
+
553
+ /**
554
+ * @demlik/tea/agent — `agentTool()`: a child `defineAgent` as one tool a parent
555
+ * agent calls and awaits.
556
+ *
557
+ * The child is a durable run of its own, never a slice of the parent's Model:
558
+ * its `Store` and `runId` are keyed by the parent call's `callId` under a
559
+ * namespace the consumer reads off the parent's ctx. That key is the whole
560
+ * durability story. A parent resumed after an eviction re-fires the tool Cmd it
561
+ * was waiting on; the re-fired call reaches the same key, so `defineAgent`'s own
562
+ * `run` boots the child where its Store left it, or resolves a child that
563
+ * already ended without calling its model again. This is Temporal's child
564
+ * workflow (a re-issued start with the same id attaches to the same run),
565
+ * LangGraph's namespaced subgraph checkpoint and the OpenAI Agents SDK's
566
+ * `agent.as_tool()` (the parent keeps control and gets a result back).
567
+ */
568
+
569
+ /** Why a child run ended `failed` — the reason `status()` reports for it. */
570
+ type ChildFailureReason = AgentTerminalFailure<string>["reason"];
571
+ /**
572
+ * The failures an agent tool settles with beside `thrown`. Each carries the
573
+ * child's `childRunId`, so the parent model's reason names the run a human can
574
+ * go and read. A child that `failed` also carries why — `turn_limit` when it hit
575
+ * its own `maxTurns`, `elapsed_limit`, `llm`, `deadline` or `stage`. A child that
576
+ * was `cancelled` (its `stopWhen` answered `true`) carries nothing more, because
577
+ * nothing went wrong.
578
+ */
579
+ type AgentToolError = {
580
+ readonly _tag: "child_failed";
581
+ readonly childRunId: string;
582
+ readonly failure: ChildFailureReason;
583
+ } | {
584
+ readonly _tag: "child_cancelled";
585
+ readonly childRunId: string;
586
+ };
587
+ /**
588
+ * How the child's ctx is derived from the parent's. Required when the child's
589
+ * tools read a ctx, and optional — defaulting to none — when they read nothing,
590
+ * the same rule `run`'s own `ctx` option follows.
591
+ */
592
+ type ChildCtxOption<CT extends AnyToolDef, Ctx> = [
593
+ Record<never, never>
594
+ ] extends [DefinedAgentCtx<CT>] ? {
595
+ readonly childCtx?: (ctx: HandlerCtx<Ctx>) => DefinedAgentCtx<CT>;
596
+ } : {
597
+ readonly childCtx: (ctx: HandlerCtx<Ctx>) => DefinedAgentCtx<CT>;
598
+ };
599
+ /** What `agentTool` takes. */
600
+ type AgentToolSpec<Args, Ok, CT extends AnyToolDef, Ctx> = {
601
+ /** The model-facing sentence — the same field `tool()` declares. */
602
+ readonly description: string;
603
+ /** Parses the parent model's `args`. */
604
+ readonly input: StandardSchemaV1<unknown, Args>;
605
+ /** Parses what `result` returns, at the edge, like any tool's `ok`. */
606
+ readonly ok: StandardSchemaV1<unknown, Ok>;
607
+ /**
608
+ * The child. Its bounds (`maxTurns`, `maxElapsedMs`, `stopWhen`), its tools
609
+ * and its instructions are all its own definition's; the helper adds none.
610
+ */
611
+ readonly agent: DefinedAgent<CT>;
612
+ /**
613
+ * The child's whole input, derived from the call's args. It is the only thing
614
+ * the child is told: the parent's conversation never reaches it.
615
+ */
616
+ readonly prompt: (args: Args) => string;
617
+ /** The value the parent call settles with, read off the child's final turn. */
618
+ readonly result: (output: AgentTurn) => Ok;
619
+ /**
620
+ * The namespace the child run's key sits under, read off the parent's ctx —
621
+ * the parent run's id, a tenant, whatever keeps two parents' calls apart.
622
+ * The key is `<namespace>/<callId>`.
623
+ */
624
+ readonly namespace: (ctx: HandlerCtx<Ctx>) => string;
625
+ /**
626
+ * The child run's Store at `key`. The same key must reach the same durable
627
+ * cell on every call, in every process — that is what makes a re-fired call
628
+ * resume the child instead of restarting it.
629
+ */
630
+ readonly store: (key: string, ctx: HandlerCtx<Ctx>) => Store<DefinedAgentState<CT>>;
631
+ } & ChildCtxOption<CT, Ctx>;
632
+ /**
633
+ * Wrap a child `defineAgent` as a tool a parent `defineAgent` calls and awaits
634
+ * — pass it the child, how to phrase its input and how to read its answer, and
635
+ * get back a tool definition the parent's `tools` accepts like any `tool()`.
636
+ *
637
+ * A call runs the child to the end of its run and settles the parent's call:
638
+ *
639
+ * - child `done` → `ok(result(output))`;
640
+ * - child `failed` → `{ _tag: "child_failed", childRunId, failure }`;
641
+ * - child `cancelled` → `{ _tag: "child_cancelled", childRunId }`.
642
+ *
643
+ * Both failures are data the parent model reads as the call's reason, so the
644
+ * parent run neither rejects nor throws when its child fails; it takes its next
645
+ * turn.
646
+ *
647
+ * The child's Store and `runId` are both the key `<namespace>/<callId>`. Firing
648
+ * the same call twice reaches the same child run, and a different call reaches
649
+ * a different one. So a parent killed while its child runs resumes the child
650
+ * from its Store when the tool Cmd re-fires: no settled child turn calls the
651
+ * model again, and no settled child tool runs again. A child that had already
652
+ * ended resolves with the outcome it recorded.
653
+ *
654
+ * It declares no `timeoutMs` and no `retry`. A timeout would settle the parent
655
+ * call while the child keeps running under the same key, and a retry of a child
656
+ * that ended `failed` reaches that same ended run and reads the same failure.
657
+ */
658
+ declare function agentTool<const Name extends string, Args, Ok, CT extends AnyToolDef, Ctx = unknown>(name: Name & NotReserved<Name>, spec: AgentToolSpec<Args, Ok, CT, Ctx>): ToolDef<Name, Args, Ok, AgentToolError | ToolThrown, Ctx>;
510
659
 
511
660
  /**
512
661
  * @packageDocumentation
@@ -553,26 +702,24 @@ interface TranscriptToolResult<R> {
553
702
  readonly result: R;
554
703
  }
555
704
  /**
556
- * Whether the run has finished, and its terminal turn once it has.
705
+ * Whether the run has ended, and how: `running` until `RunDone`, then the
706
+ * ending it carried — `done` with the terminal turn, `failed` with the
707
+ * failure, or `cancelled`.
557
708
  *
558
- * The two cases are a union rather than a nullable `output` field because
559
- * `output` is legitimately `null` on a finished run — a `RunDone` with no
560
- * terminating turn — and a single field would make "not finished yet" and
561
- * "finished with nothing" the same reading.
709
+ * `done` keeps `output` inside its own arm because `output` is legitimately
710
+ * `null` on a finished run, and a single nullable field would make "not
711
+ * finished yet" and "finished with nothing" the same reading.
562
712
  */
563
713
  type TranscriptOutcome = {
564
714
  readonly kind: "running";
565
- } | {
566
- readonly kind: "done";
567
- readonly output: AgentTurn | null;
568
- };
715
+ } | AgentEndedStatus;
569
716
  /** What a collector holds right now — a plain, immutable read. */
570
717
  interface TranscriptSnapshot<R> {
571
718
  /** Every model turn the transcript holds, in order. */
572
719
  readonly turns: readonly AgentTurn[];
573
720
  /** Every tool call that settled OK, in settle order. */
574
721
  readonly tools: readonly TranscriptToolResult<R>[];
575
- /** Whether `RunDone` has been seen, and the terminal turn if so. */
722
+ /** Whether `RunDone` has been seen, and how the run ended if so. */
576
723
  readonly outcome: TranscriptOutcome;
577
724
  }
578
725
  /**
@@ -757,4 +904,4 @@ declare function createAgent<Stage, P extends string, O extends Record<P, AgentT
757
904
  readonly compaction?: never;
758
905
  }): AgentKnob<Stage, P, O, R, TC, false, false>;
759
906
 
760
- export { AgentCmd, AgentConfigCore, AgentEvent, AgentKnob, AgentMachineMsg, type AgentMessage, type AgentPrompt, AgentState, AgentTurn, AnyToolDef, CompactionPolicy, Conversation, DeadlinesSub, type DefineAgentCompaction, type DefineAgentConfig, type DefinedAgent, type DefinedAgentCmd, type DefinedAgentCtx, type DefinedAgentEvent, type DefinedAgentInterpret, type DefinedAgentMachine, type DefinedAgentModel, type DefinedAgentMsg, type DefinedAgentOverlay, type DefinedAgentResolvedState, type DefinedAgentRunOptions, type DefinedAgentState, type DefinedAgentWired, EndedRun, type InterpretOverlay, type LidPurpose, PlainModel, StreamingModel, ToolCall, ToolCmd, type ToolErrorContext, ToolFailureOf, ToolOutcome, ToolResult, ToolsCtx, type Transcript, type TranscriptOutcome, type TranscriptSeed, type TranscriptSnapshot, type TranscriptToolResult, TurnChunk, WiredToolMsg, createAgent, defineAgent, renderPrompt, transcript };
907
+ export { AgentCmd, AgentConfigCore, AgentEndedStatus, AgentEvent, AgentKnob, AgentMachineMsg, type AgentMessage, type AgentPrompt, AgentState, AgentTerminalFailure, type AgentToolError, type AgentToolSpec, AgentTurn, AnyToolDef, type ChildFailureReason, CompactionPolicy, ContentPart, Conversation, DeadlinesSub, type DefineAgentCompaction, type DefineAgentConfig, type DefinedAgent, type DefinedAgentCmd, type DefinedAgentCtx, type DefinedAgentEvent, type DefinedAgentInterpret, type DefinedAgentMachine, type DefinedAgentModel, type DefinedAgentMsg, type DefinedAgentOverlay, type DefinedAgentResolvedState, type DefinedAgentRunOptions, type DefinedAgentState, type DefinedAgentWired, EndedRun, type InterpretOverlay, type LidPurpose, MessageContent, PlainModel, StreamingModel, ToolCall, ToolCmd, ToolDef, type ToolErrorContext, ToolFailureOf, ToolOutcome, type ToolPartsOf, ToolResult, ToolThrown, ToolsCtx, type Transcript, type TranscriptOutcome, type TranscriptSeed, type TranscriptSnapshot, type TranscriptToolResult, TurnChunk, WiredToolMsg, agentTool, createAgent, defineAgent, renderPrompt, transcript };
@@ -1,16 +1,16 @@
1
- export { COMPACTION_PURPOSE, PLAIN_MODEL_MISROUTE_REASON, TOOL_RETRY_EXHAUSTED_TAG, TOOL_TIMEOUT_TAG, agentBootMsg, agentCancelMsg, agentEvents, agentTurnSchema, compactionSummarySchema, createAgent, defineAgent, fanOutInterpret, isAgentTurn, isCompactionSummary, isReservedToolName, isStreamingModel, liftAgent, mergeInterpret, plainModel, renderPrompt, status, tool, toolErrorReason, toolRouter, transcript } from '../chunk-XBZQT2TD.js';
2
- import '../chunk-G5E74IJB.js';
3
- import '../chunk-4PXNZ5UY.js';
4
- import '../chunk-4NTCPTNQ.js';
1
+ export { AGENT_EVENT_TYPES, COMPACTION_PURPOSE, FILE_OMITTED, IMAGE_OMITTED, PLAIN_MODEL_MISROUTE_REASON, TOOL_RETRY_EXHAUSTED_TAG, TOOL_TIMEOUT_TAG, agentBootMsg, agentCancelMsg, agentEvents, agentTool, agentTurnSchema, compactionSummarySchema, contentParts, createAgent, defineAgent, fanOutInterpret, isAgentTurn, isCompactionSummary, isReservedToolName, isStreamingModel, isTurnUsage, liftAgent, mergeInterpret, omitMedia, plainModel, renderPrompt, status, tool, toolErrorReason, toolRouter, transcript } from '../chunk-PCJA2HTZ.js';
2
+ import '../chunk-XVIKSRCK.js';
3
+ import '../chunk-YIMOFXST.js';
5
4
  import '../chunk-QNGYQMZB.js';
6
- import '../chunk-TXN2KFHF.js';
7
- import '../chunk-6XBEYZME.js';
5
+ import '../chunk-WTSOW2MD.js';
6
+ export { deadlineSub, deadlinesSub, subscribeDeadline } from '../chunk-C3G2QFEZ.js';
8
7
  import '../chunk-VBDU4JL6.js';
9
8
  import '../chunk-4LPY67E4.js';
10
- export { deadlineSub, deadlinesSub, subscribeDeadline } from '../chunk-GWWCCSDH.js';
11
- import '../chunk-QWIPH4YH.js';
12
- import '../chunk-KWNCM6XM.js';
13
- import '../chunk-C4U5D5HP.js';
14
- import '../chunk-K4ETBNKS.js';
9
+ import '../chunk-TXN2KFHF.js';
10
+ import '../chunk-H2ELKHI6.js';
11
+ import '../chunk-AHW2CLPT.js';
12
+ import '../chunk-JVE2LBFJ.js';
13
+ import '../chunk-FNGZMVIT.js';
14
+ import '../chunk-AIIXV4XB.js';
15
15
  //# sourceMappingURL=index.js.map
16
16
  //# sourceMappingURL=index.js.map
@@ -1,13 +1,15 @@
1
- import { detachWork, DispatchDiscardedError, QuiescenceTimeoutError, RuntimeDiscardedError, IdentityDropNotice, checkedStep, cmdContractOver, Outcome, cmdEdge, isFencedStore, RuntimeDiscardNotice, DisposeTimeoutNotice, structuralHash, desiredSub } from './chunk-K4ETBNKS.js';
1
+ import { restore } from './chunk-JVE2LBFJ.js';
2
+ import { RuntimeDiscardNotice, detachWork, DispatchDiscardedError, QuiescenceTimeoutError, RuntimeDiscardedError, IdentityDropNotice, checkedStep, cmdContractOver, Outcome, cmdEdge, isFencedStore, DisposeTimeoutNotice, NoCellError, lookupCell, structuralHash, desiredSub, followUps } from './chunk-AIIXV4XB.js';
2
3
 
3
4
  // src/internal/engine/builtins.ts
4
- function supervision(declared) {
5
+ function supervision(declared, machine) {
5
6
  const policy = declared === void 0 ? { strategy: "stop" } : typeof declared === "string" ? { strategy: declared } : declared;
6
7
  return (loop) => ({
7
8
  update: (next) => (state, msg) => {
8
9
  try {
9
10
  return next(state, msg);
10
11
  } catch (reduceError) {
12
+ if (isRefusal(machine, reduceError, state, msg)) throw reduceError;
11
13
  loop.report(reduceError, "reduce");
12
14
  switch (policy.strategy) {
13
15
  case "restart":
@@ -22,6 +24,9 @@ function supervision(declared) {
22
24
  }
23
25
  });
24
26
  }
27
+ function isRefusal(machine, error, state, msg) {
28
+ return error instanceof NoCellError && lookupCell(machine, state, msg).cell === void 0;
29
+ }
25
30
  function identityFilter(identity) {
26
31
  return (loop) => {
27
32
  if (identity === void 0) return {};
@@ -246,7 +251,7 @@ function telemetry(sink, clock) {
246
251
  function builtinExtensions(machine, opts) {
247
252
  const clock = opts.clock ?? Date.now;
248
253
  return [
249
- supervision(opts.supervision),
254
+ supervision(opts.supervision, machine),
250
255
  identityFilter(machine.identity),
251
256
  devChecks(),
252
257
  cmdDefinitions(machine.cmds ?? [], clock),
@@ -270,6 +275,22 @@ function defaultOnError(error, _context) {
270
275
  throw error;
271
276
  }, 0);
272
277
  }
278
+ var RuntimeStoppedError = class extends Error {
279
+ constructor(msgType) {
280
+ super("@demlik/tea: runtime stopped");
281
+ this.msgType = msgType;
282
+ }
283
+ msgType;
284
+ };
285
+ var RunningSub = class {
286
+ constructor(type) {
287
+ this.type = type;
288
+ }
289
+ type;
290
+ dispose = () => {
291
+ };
292
+ failed = false;
293
+ };
273
294
  function startLoop(config) {
274
295
  const { idleCap, disposeTimeoutMs } = config;
275
296
  const onError = config.onError ?? defaultOnError;
@@ -387,7 +408,8 @@ function startLoop(config) {
387
408
  ([id, running]) => desired.has(id) || unreadTypes.has(running.type) ? [] : [id]
388
409
  )
389
410
  );
390
- for (const [id, sub] of desired) {
411
+ const starting = gate === "open" ? desired : /* @__PURE__ */ new Map();
412
+ for (const [id, sub] of starting) {
391
413
  if (subRegistry.has(id)) continue;
392
414
  const runner = config.runnerFor(sub.type);
393
415
  if (runner === void 0) {
@@ -398,15 +420,40 @@ function startLoop(config) {
398
420
  );
399
421
  continue;
400
422
  }
423
+ const running = new RunningSub(sub.type);
401
424
  try {
402
- const dispose = runner(sub, config.ctx, dispatchUnawaited);
403
- subRegistry.set(id, { type: sub.type, dispose });
425
+ running.dispose = runner(
426
+ sub,
427
+ config.ctx,
428
+ dispatchUnawaited,
429
+ (error) => subFailed(id, running, error)
430
+ );
404
431
  } catch (err) {
405
432
  remember(err);
433
+ subFailed(id, running, err);
434
+ continue;
435
+ }
436
+ if (!running.failed) {
437
+ subRegistry.set(id, running);
438
+ continue;
439
+ }
440
+ try {
441
+ trackDisposal(running.dispose());
442
+ } catch (err) {
443
+ report(err, "sub-cleanup");
406
444
  }
407
445
  }
408
446
  if (firstError !== null) throw firstError;
409
447
  }
448
+ function subFailed(id, running, error) {
449
+ if (running.failed) return;
450
+ running.failed = true;
451
+ if (subRegistry.get(id) === running) subRegistry.delete(id);
452
+ report(error, "sub");
453
+ if (gate !== "open") return;
454
+ gate = "draining";
455
+ config.stopOnSubFailure(error);
456
+ }
410
457
  function dispatchUnawaited(msg) {
411
458
  enqueueDispatch(msg).catch(reportUndelivered);
412
459
  }
@@ -437,8 +484,8 @@ function startLoop(config) {
437
484
  }
438
485
  async function runCmds(cmds) {
439
486
  for (const cmd of cmds) {
440
- const follow = await interpret(cmd, dispatchUnawaited);
441
- if (follow !== void 0 && follow !== null) {
487
+ const returned = await interpret(cmd, dispatchUnawaited);
488
+ for (const follow of followUps(returned)) {
442
489
  enqueueDispatch(follow).catch(reportUndelivered);
443
490
  }
444
491
  }
@@ -447,8 +494,11 @@ function startLoop(config) {
447
494
  state = next;
448
495
  if (store) await store.save(next);
449
496
  reconcileSubs();
450
- await runCmds(cmds);
451
- for (const callback of commitCallbacks) callback(msg, next);
497
+ try {
498
+ await runCmds(cmds);
499
+ } finally {
500
+ for (const callback of commitCallbacks) callback(msg, next);
501
+ }
452
502
  }
453
503
  async function stepDispatch(msg) {
454
504
  if (state === void 0) {
@@ -461,16 +511,13 @@ function startLoop(config) {
461
511
  const storeless = store === void 0 ? config.init(null, config.ctx) : null;
462
512
  if (storeless !== null) state = storeless[0];
463
513
  async function boot() {
464
- const [initial, cmds] = storeless ?? config.init(
465
- store.migrate(await store.load()),
466
- config.ctx
467
- );
514
+ const [initial, cmds] = storeless ?? config.init(await restore(store), config.ctx);
468
515
  await commit(initial, void 0, cmds);
469
516
  }
470
517
  function enqueueDispatch(msg) {
471
518
  if (gate !== "open") {
472
519
  return Promise.reject(
473
- gate === "draining" ? new DispatchDiscardedError(msg.type) : new Error("@demlik/tea: runtime stopped")
520
+ gate === "draining" ? new DispatchDiscardedError(msg.type) : new RuntimeStoppedError(msg.type)
474
521
  );
475
522
  }
476
523
  const next = tail.then(() => {
@@ -534,6 +581,6 @@ function startLoop(config) {
534
581
  return handle;
535
582
  }
536
583
 
537
- export { builtinExtensions, liveWork, startLoop };
538
- //# sourceMappingURL=chunk-KWNCM6XM.js.map
539
- //# sourceMappingURL=chunk-KWNCM6XM.js.map
584
+ export { RuntimeStoppedError, builtinExtensions, defaultOnError, liveWork, startLoop };
585
+ //# sourceMappingURL=chunk-AHW2CLPT.js.map
586
+ //# sourceMappingURL=chunk-AHW2CLPT.js.map