experimental-ash 0.22.2 → 0.24.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 (172) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/docs/internals/hooks.md +13 -16
  3. package/dist/docs/internals/message-runtime.md +1 -1
  4. package/dist/docs/public/auth-and-route-protection.md +3 -3
  5. package/dist/docs/public/faqs.md +67 -0
  6. package/dist/docs/public/meta.json +1 -0
  7. package/dist/docs/public/schedules.md +11 -0
  8. package/dist/docs/public/session-context.md +46 -89
  9. package/dist/docs/public/skills.md +13 -0
  10. package/dist/docs/public/subagents.md +12 -6
  11. package/dist/docs/public/tools.md +9 -13
  12. package/dist/docs/public/typescript-api.md +4 -4
  13. package/dist/src/channel/types.d.ts +10 -12
  14. package/dist/src/chunks/{client-CKsU8Li3.js → client-nshDsWNF.js} +1 -1
  15. package/dist/src/chunks/{dev-authored-source-watcher-BLzYWh05.js → dev-authored-source-watcher-B4PaZGUr.js} +1 -1
  16. package/dist/src/chunks/host-DsW72Q-w.js +65 -0
  17. package/dist/src/chunks/paths-OknjaYR8.js +89 -0
  18. package/dist/src/chunks/prewarm-B4YblQ5m.js +6 -0
  19. package/dist/src/cli/commands/info.js +1 -1
  20. package/dist/src/cli/dev/repl.js +2 -2
  21. package/dist/src/cli/run.js +1 -1
  22. package/dist/src/client/session.js +8 -0
  23. package/dist/src/client/types.d.ts +12 -1
  24. package/dist/src/compiled/.vendor-stamp.json +3 -3
  25. package/dist/src/compiled/@workflow/core/_ms.d.ts +4 -0
  26. package/dist/src/compiled/@workflow/core/_workflow-serde.d.ts +5 -0
  27. package/dist/src/compiled/@workflow/core/_workflow-utils.d.ts +8 -0
  28. package/dist/src/compiled/@workflow/core/_workflow-world.d.ts +59 -0
  29. package/dist/src/compiled/@workflow/core/capabilities.d.ts +45 -0
  30. package/dist/src/compiled/@workflow/core/capture-stack.d.ts +16 -0
  31. package/dist/src/compiled/@workflow/core/class-serialization.d.ts +31 -0
  32. package/dist/src/compiled/@workflow/core/classify-error.d.ts +20 -0
  33. package/dist/src/compiled/@workflow/core/context-errors.d.ts +27 -0
  34. package/dist/src/compiled/@workflow/core/context-violation-error.d.ts +97 -0
  35. package/dist/src/compiled/@workflow/core/create-hook.d.ts +179 -0
  36. package/dist/src/compiled/@workflow/core/define-hook.d.ts +68 -0
  37. package/dist/src/compiled/@workflow/core/describe-error.d.ts +70 -0
  38. package/dist/src/compiled/@workflow/core/encryption.d.ts +51 -0
  39. package/dist/src/compiled/@workflow/core/events-consumer.d.ts +64 -0
  40. package/dist/src/compiled/@workflow/core/flushable-stream.d.ts +82 -0
  41. package/dist/src/compiled/@workflow/core/global.d.ts +48 -0
  42. package/dist/src/compiled/@workflow/core/index.d.ts +19 -38
  43. package/dist/src/compiled/@workflow/core/index.js +2 -2
  44. package/dist/src/compiled/@workflow/core/log-format.d.ts +25 -0
  45. package/dist/src/compiled/@workflow/core/logger.d.ts +29 -0
  46. package/dist/src/compiled/@workflow/core/package.json +1 -1
  47. package/dist/src/compiled/@workflow/core/private.d.ts +59 -10
  48. package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +51 -0
  49. package/dist/src/compiled/@workflow/core/runtime/get-port-lazy.d.ts +10 -0
  50. package/dist/src/compiled/@workflow/core/runtime/get-world-lazy.d.ts +32 -0
  51. package/dist/src/compiled/@workflow/core/runtime/helpers.d.ts +97 -0
  52. package/dist/src/compiled/@workflow/core/runtime/replay-budget.d.ts +98 -0
  53. package/dist/src/compiled/@workflow/core/runtime/resume-hook.d.ts +77 -0
  54. package/dist/src/compiled/@workflow/core/runtime/run.d.ts +134 -0
  55. package/dist/src/compiled/@workflow/core/runtime/runs.d.ts +50 -0
  56. package/dist/src/compiled/@workflow/core/runtime/start.d.ts +59 -0
  57. package/dist/src/compiled/@workflow/core/runtime/step-executor.d.ts +40 -0
  58. package/dist/src/compiled/@workflow/core/runtime/step-handler.d.ts +2 -0
  59. package/dist/src/compiled/@workflow/core/runtime/suspension-handler.d.ts +42 -0
  60. package/dist/src/compiled/@workflow/core/runtime/world-init.d.ts +75 -0
  61. package/dist/src/compiled/@workflow/core/runtime/world.d.ts +32 -0
  62. package/dist/src/compiled/@workflow/core/runtime.d.ts +22 -67
  63. package/dist/src/compiled/@workflow/core/runtime.js +27 -27
  64. package/dist/src/compiled/@workflow/core/schemas.d.ts +15 -0
  65. package/dist/src/compiled/@workflow/core/serialization/client.d.ts +17 -0
  66. package/dist/src/compiled/@workflow/core/serialization/codec-devalue.d.ts +14 -0
  67. package/dist/src/compiled/@workflow/core/serialization/codec.d.ts +90 -0
  68. package/dist/src/compiled/@workflow/core/serialization/encryption.d.ts +32 -0
  69. package/dist/src/compiled/@workflow/core/serialization/errors.d.ts +21 -0
  70. package/dist/src/compiled/@workflow/core/serialization/format.d.ts +60 -0
  71. package/dist/src/compiled/@workflow/core/serialization/index.d.ts +18 -0
  72. package/dist/src/compiled/@workflow/core/serialization/reducers/class.d.ts +11 -0
  73. package/dist/src/compiled/@workflow/core/serialization/reducers/common.d.ts +16 -0
  74. package/dist/src/compiled/@workflow/core/serialization/reducers/step-function.d.ts +35 -0
  75. package/dist/src/compiled/@workflow/core/serialization/step.d.ts +17 -0
  76. package/dist/src/compiled/@workflow/core/serialization/types.d.ts +215 -0
  77. package/dist/src/compiled/@workflow/core/serialization/workflow.d.ts +29 -0
  78. package/dist/src/compiled/@workflow/core/serialization-format.d.ts +171 -0
  79. package/dist/src/compiled/@workflow/core/serialization.d.ts +337 -0
  80. package/dist/src/compiled/@workflow/core/sleep.d.ts +33 -0
  81. package/dist/src/compiled/@workflow/core/source-map.d.ts +10 -0
  82. package/dist/src/compiled/@workflow/core/step/context-storage.d.ts +13 -0
  83. package/dist/src/compiled/@workflow/core/step/get-closure-vars.d.ts +9 -0
  84. package/dist/src/compiled/@workflow/core/step/get-step-metadata.d.ts +42 -0
  85. package/dist/src/compiled/@workflow/core/step/get-workflow-metadata.d.ts +7 -0
  86. package/dist/src/compiled/@workflow/core/step/writable-stream.d.ts +22 -0
  87. package/dist/src/compiled/@workflow/core/step.d.ts +4 -0
  88. package/dist/src/compiled/@workflow/core/symbols.d.ts +36 -0
  89. package/dist/src/compiled/@workflow/core/telemetry/semantic-conventions.d.ts +283 -0
  90. package/dist/src/compiled/@workflow/core/telemetry.d.ts +53 -0
  91. package/dist/src/compiled/@workflow/core/types.d.ts +14 -0
  92. package/dist/src/compiled/@workflow/core/util.d.ts +40 -0
  93. package/dist/src/compiled/@workflow/core/version.d.ts +2 -0
  94. package/dist/src/compiled/@workflow/core/vm/index.d.ts +17 -0
  95. package/dist/src/compiled/@workflow/core/vm/uint8array-base64.d.ts +21 -0
  96. package/dist/src/compiled/@workflow/core/vm/uuid.d.ts +10 -0
  97. package/dist/src/compiled/@workflow/core/workflow/abort-controller.d.ts +65 -0
  98. package/dist/src/compiled/@workflow/core/workflow/create-hook.d.ts +7 -0
  99. package/dist/src/compiled/@workflow/core/workflow/define-hook.d.ts +10 -0
  100. package/dist/src/compiled/@workflow/core/workflow/get-workflow-metadata.d.ts +32 -0
  101. package/dist/src/compiled/@workflow/core/workflow/hook.d.ts +4 -0
  102. package/dist/src/compiled/@workflow/core/workflow/index.d.ts +11 -0
  103. package/dist/src/compiled/@workflow/core/workflow/sleep.d.ts +4 -0
  104. package/dist/src/compiled/@workflow/core/workflow/world-init-stub.d.ts +15 -0
  105. package/dist/src/compiled/@workflow/core/workflow/writable-stream.d.ts +3 -0
  106. package/dist/src/compiled/@workflow/core/workflow.d.ts +1 -38
  107. package/dist/src/compiled/@workflow/core/workflow.js +1 -1
  108. package/dist/src/compiled/@workflow/errors/error-codes.d.ts +5 -1
  109. package/dist/src/compiled/@workflow/errors/index.d.ts +15 -1
  110. package/dist/src/compiled/@workflow/errors/index.js +1 -1
  111. package/dist/src/compiled/@workflow/errors/package.json +1 -1
  112. package/dist/src/compiled/_chunks/workflow/{context-errors-zbKocOyk.js → context-errors-Bbvvp-li.js} +2 -2
  113. package/dist/src/compiled/_chunks/workflow/{dist-0iNBqPYp.js → dist-C7wPwOI9.js} +2 -2
  114. package/dist/src/compiled/_chunks/workflow/{dist-D774SUM4.js → dist-C_oiE-l7.js} +1 -1
  115. package/dist/src/compiled/_chunks/workflow/resume-hook-C3VWUPii.js +12 -0
  116. package/dist/src/compiled/_chunks/workflow/sleep-QTkC1VFe.js +1 -0
  117. package/dist/src/compiled/_chunks/workflow/{symbols-D-4tVV8x.js → symbols-QezhMuLg.js} +1 -1
  118. package/dist/src/evals/cli/eval.js +1 -1
  119. package/dist/src/execution/await-authorization-orchestrator.d.ts +2 -1
  120. package/dist/src/execution/await-authorization-orchestrator.js +4 -0
  121. package/dist/src/execution/connection-auth-steps.d.ts +4 -0
  122. package/dist/src/execution/connection-auth-steps.js +9 -11
  123. package/dist/src/execution/node-step.d.ts +4 -5
  124. package/dist/src/execution/subagent-adapter.d.ts +0 -27
  125. package/dist/src/execution/subagent-adapter.js +2 -66
  126. package/dist/src/execution/subagent-hitl-proxy.d.ts +2 -2
  127. package/dist/src/execution/subagent-hitl-proxy.js +2 -2
  128. package/dist/src/execution/task-mode.d.ts +3 -3
  129. package/dist/src/execution/task-mode.js +3 -3
  130. package/dist/src/execution/turn-workflow.d.ts +41 -0
  131. package/dist/src/execution/turn-workflow.js +96 -0
  132. package/dist/src/execution/workflow-entry.js +77 -87
  133. package/dist/src/execution/workflow-errors.d.ts +14 -0
  134. package/dist/src/execution/workflow-errors.js +54 -0
  135. package/dist/src/execution/workflow-runtime.d.ts +34 -3
  136. package/dist/src/execution/workflow-runtime.js +52 -10
  137. package/dist/src/execution/workflow-steps.d.ts +27 -2
  138. package/dist/src/execution/workflow-steps.js +31 -26
  139. package/dist/src/harness/instrumentation-config.js +14 -7
  140. package/dist/src/harness/messages.d.ts +7 -7
  141. package/dist/src/harness/messages.js +4 -4
  142. package/dist/src/harness/runtime-actions.d.ts +4 -4
  143. package/dist/src/internal/application/package.js +1 -1
  144. package/dist/src/internal/workflow-bundle/workflow-builders.d.ts +1 -1
  145. package/dist/src/internal/workflow-bundle/workflow-builders.js +20 -8
  146. package/dist/src/internal/workflow-bundle/workflow-transformer.d.ts +13 -0
  147. package/dist/src/internal/workflow-bundle/workflow-transformer.js +10 -4
  148. package/dist/src/protocol/message.d.ts +6 -1
  149. package/dist/src/public/channels/ash.js +50 -3
  150. package/dist/src/public/context/index.d.ts +4 -7
  151. package/dist/src/public/context/index.js +4 -5
  152. package/dist/src/public/definitions/state.d.ts +33 -0
  153. package/dist/src/public/definitions/state.js +34 -0
  154. package/dist/src/public/next/index.d.ts +7 -0
  155. package/dist/src/public/next/index.js +2 -0
  156. package/dist/src/public/next/vercel-json.d.ts +1 -0
  157. package/dist/src/public/next/vercel-json.js +1 -0
  158. package/dist/src/react/index.d.ts +1 -1
  159. package/dist/src/react/use-ash-agent.d.ts +8 -0
  160. package/dist/src/react/use-ash-agent.js +26 -4
  161. package/dist/src/services/dev-client.d.ts +4 -1
  162. package/dist/src/services/dev-client.js +1 -0
  163. package/package.json +4 -4
  164. package/dist/src/chunks/host-DREC8e8Z.js +0 -65
  165. package/dist/src/chunks/paths-C6sp4T2U.js +0 -88
  166. package/dist/src/chunks/prewarm-hz8p2jlZ.js +0 -6
  167. package/dist/src/compiled/_chunks/workflow/resume-hook-CL8Ed91K.js +0 -12
  168. package/dist/src/compiled/_chunks/workflow/sleep-Dn3i9nxI.js +0 -1
  169. package/dist/src/execution/continuous-entry.d.ts +0 -59
  170. package/dist/src/execution/continuous-entry.js +0 -487
  171. package/dist/src/execution/continuous-runtime.d.ts +0 -17
  172. package/dist/src/execution/continuous-runtime.js +0 -123
@@ -1,487 +0,0 @@
1
- import { buildAdapterContext } from "#channel/adapter-context.js";
2
- import { defaultDeliverResult } from "#channel/adapter.js";
3
- import { toContextAccessor } from "#context/container.js";
4
- import { runHookLifecycleStep } from "#context/hook-lifecycle.js";
5
- import { AuthKey, BundleKey, CapabilitiesKey, ChannelKey, ContinuationTokenKey, InitiatorAuthKey, ModeKey, SessionIdKey, } from "#context/keys.js";
6
- import { runStep } from "#context/run-step.js";
7
- import { getHarnessEmissionState, isHarnessBetweenTurns } from "#harness/emission.js";
8
- import { hasPendingInputBatch } from "#harness/input-requests.js";
9
- import { coalesceDeliveries, coalesceTurnInputs } from "#harness/messages.js";
10
- import { hasProxyInputRequests, upsertProxyInputRequests } from "#harness/proxy-input-requests.js";
11
- import { accumulateRuntimeActionResults, getPendingRuntimeActionBatch, hasPendingRuntimeActionBatch, recordPendingSubagentChildToken, } from "#harness/runtime-actions.js";
12
- import { createErrorId, createLogger } from "#internal/logging.js";
13
- import { createSubagentCalledEvent } from "#protocol/message.js";
14
- import { drainPendingConnectionAuthorizations } from "#runtime/framework-tools/connection-search.js";
15
- import { toErrorMessage } from "#shared/errors.js";
16
- import { isRuntimeNoActiveSessionError } from "#execution/runtime-errors.js";
17
- import { registerContinuousSubagentInputRequestDispatcher, unregisterContinuousSubagentInputRequestDispatcher, } from "#execution/subagent-adapter.js";
18
- import { createExecutionNodeStep } from "#execution/node-step.js";
19
- import { emitProxiedInputRequest, routeDeliverPayload } from "#execution/subagent-hitl-proxy.js";
20
- import { createSession } from "#execution/session.js";
21
- import { buildSubagentRunInput } from "#execution/subagent-tool.js";
22
- import { createTaskModeWaitError } from "#execution/task-mode.js";
23
- const log = createLogger("execution.continuous-entry");
24
- /**
25
- * Main body of a continuous (in-memory) run.
26
- */
27
- export async function continuousEntry(input) {
28
- const { createRuntime, ctx, emit, input: entryInput, park, queue, wake } = input;
29
- const bundle = ctx.require(BundleKey);
30
- const capabilities = ctx.get(CapabilitiesKey);
31
- const mode = ctx.require(ModeKey);
32
- const session = createSession({
33
- compactionOverrides: {
34
- thresholdPercent: bundle.resolvedAgent.config.compaction?.thresholdPercent,
35
- },
36
- continuationToken: ctx.require(ContinuationTokenKey),
37
- sessionId: ctx.require(SessionIdKey),
38
- turnAgent: bundle.turnAgent,
39
- });
40
- const rawStep = createExecutionNodeStep({
41
- capabilities,
42
- compiledArtifactsSource: bundle.compiledArtifactsSource,
43
- createRuntime,
44
- emit,
45
- mode,
46
- node: bundle.graph.root,
47
- });
48
- // Every step in the continuous runtime runs inside `runStep(ctx, ...)`.
49
- // After each step returns we drain any `connection.authorization_required`
50
- // events that tools flagged during the step so the channel sees them
51
- // while the scope is still active. Keeping this here (and not in the
52
- // harness) preserves the channel-harness-runtime split.
53
- const runScopedStep = async (stepSession, body) => {
54
- return runStep(ctx, stepSession, async (enrichedSession) => {
55
- const result = await body(enrichedSession);
56
- await drainPendingConnectionAuthorizations({
57
- ctx,
58
- emit,
59
- state: getHarnessEmissionState(result.session),
60
- });
61
- return result;
62
- });
63
- };
64
- const deliverStep = (item) => {
65
- return async (stepSession, _stepInput) => {
66
- ctx.clearVirtualContext();
67
- if (item.auth !== undefined) {
68
- ctx.set(AuthKey, item.auth ?? null);
69
- }
70
- // Split the payload into parent-local and proxied-child buckets
71
- // before handing any of it to the parent's own adapter. Each
72
- // proxied bucket is pushed onto the target child's queue and
73
- // wakes the child runtime; the parent processes only the
74
- // residual payload (if any).
75
- const routed = await routeDeliverQueueItem(stepSession, item);
76
- if (routed === undefined) {
77
- return { next: null, session: stepSession };
78
- }
79
- const remainders = routed.payloads;
80
- // Re-read adapter from context each delivery so state mutations
81
- // from previous deliveries are visible.
82
- const adapter = ctx.require(ChannelKey);
83
- const adapterCtx = buildAdapterContext(adapter, toContextAccessor(ctx));
84
- const results = [];
85
- for (const payload of remainders) {
86
- const result = adapter.deliver
87
- ? await adapter.deliver(payload, adapterCtx)
88
- : defaultDeliverResult(payload);
89
- if (result !== undefined && result !== null) {
90
- results.push(result);
91
- }
92
- }
93
- // Update adapter state after deliver mutations.
94
- const updatedAdapter = { ...adapter, state: { ...adapterCtx.state } };
95
- ctx.set(ChannelKey, updatedAdapter);
96
- // Adapter handled all deliveries inline — re-park without a model turn.
97
- if (results.length === 0) {
98
- return { next: null, session: stepSession };
99
- }
100
- const resolved = results.reduce(coalesceTurnInputs);
101
- return await runScopedStep(stepSession, (enrichedSession) => {
102
- // Gate lifecycle dispatch on the harness being between turns —
103
- // same contract as the workflow runtime. A fresh delivery is
104
- // the start of a new turn; a deliver carrying HITL
105
- // `inputResponses` while the harness still owns a turn is a
106
- // continuation of that turn, and lifecycle hooks must not
107
- // re-fire.
108
- if (isHarnessBetweenTurns(enrichedSession)) {
109
- return runHookLifecycleStep({
110
- ctx,
111
- emit,
112
- input: resolved,
113
- mode,
114
- registry: bundle.hookRegistry,
115
- session: enrichedSession,
116
- }, rawStep);
117
- }
118
- return rawStep(enrichedSession, resolved);
119
- });
120
- };
121
- };
122
- const subagentInputRequestStep = async (sessionIn, item) => {
123
- ctx.clearVirtualContext();
124
- // `emitProxiedInputRequest` fires the `input.requested` event
125
- // through the parent's adapter (the outer-scope `emit` applies the
126
- // transform) and, when the parent is in conversation mode, follows
127
- // it with a `turn.completed` + `session.waiting` pair so HTTP /
128
- // REPL clients can stop draining the stream and prompt the user
129
- // for HITL input. The parent session's emission state advances
130
- // through the pseudo-turn and is returned on `result.session`.
131
- const result = await emitProxiedInputRequest({
132
- emit,
133
- hookPayload: {
134
- callId: item.callId,
135
- childContinuationToken: item.childContinuationToken,
136
- childSessionId: item.childSessionId,
137
- event: item.event,
138
- kind: "subagent-input-request",
139
- subagentName: item.subagentName,
140
- },
141
- mode,
142
- session: sessionIn,
143
- });
144
- return upsertProxyInputRequests({
145
- entries: result.entries,
146
- forChildContinuationToken: item.childContinuationToken,
147
- session: result.session,
148
- });
149
- };
150
- const runtimeActionResultStep = (item) => {
151
- return async (stepSession, _stepInput) => await runScopedStep(stepSession, (enrichedSession) => rawStep(enrichedSession, {
152
- runtimeActionResults: item.results,
153
- }));
154
- };
155
- /**
156
- * Routes one inbound deliver queue item to any descendant subagents
157
- * whose proxied HITL requests match the payload's `inputResponses`.
158
- * Returns the parent-local remainder (`undefined` means the whole
159
- * item was routed away). Short-circuits when the session has no
160
- * proxy entries so the common path skips the routing loop entirely.
161
- */
162
- const routeDeliverQueueItem = async (sessionIn, item) => {
163
- if (!hasProxyInputRequests(sessionIn)) {
164
- return item;
165
- }
166
- const remainders = await routeProxiedDeliverPayloads({
167
- auth: item.auth,
168
- createRuntime,
169
- ctx,
170
- payloads: item.payloads,
171
- session: sessionIn,
172
- });
173
- if (remainders.length === 0) {
174
- return undefined;
175
- }
176
- return { ...item, payloads: remainders };
177
- };
178
- const wrapContinuation = (innerStep) => {
179
- return async (stepSession, stepInput) => await runScopedStep(stepSession, (enrichedSession) => innerStep(enrichedSession, stepInput));
180
- };
181
- let currentStep = deliverStep({
182
- kind: "deliver",
183
- payloads: [{ message: entryInput.message }],
184
- });
185
- let currentSession = session;
186
- const bufferedDeliveries = [];
187
- while (true) {
188
- const stepResult = await currentStep(currentSession, undefined);
189
- currentSession = stepResult.session;
190
- if (stepResult.next !== null &&
191
- typeof stepResult.next === "object" &&
192
- "done" in stepResult.next) {
193
- return { output: stepResult.next.output, status: "completed" };
194
- }
195
- if (stepResult.next === null) {
196
- if (hasPendingRuntimeActionBatch(currentSession)) {
197
- currentSession = dispatchPendingRuntimeActions({
198
- createRuntime,
199
- ctx,
200
- emit,
201
- queue,
202
- session: currentSession,
203
- wake,
204
- });
205
- const waited = await waitForRuntimeActionResults({
206
- bufferedDeliveries,
207
- park,
208
- proxyInputRequestStep: subagentInputRequestStep,
209
- queue,
210
- routeDeliver: routeDeliverQueueItem,
211
- session: currentSession,
212
- });
213
- currentSession = waited.session;
214
- currentStep = runtimeActionResultStep(waited.result);
215
- continue;
216
- }
217
- // Task-mode HITL park is allowed when the session has HITL
218
- // capabilities — the proxy bridge will forward the request up
219
- // to a capable ancestor. Conversation mode always allows a park
220
- // for the next user message.
221
- if (capabilities?.requestInput === true && hasPendingInputBatch(currentSession)) {
222
- const waited = await waitForDeliverQueueItem({
223
- bufferedDeliveries,
224
- park,
225
- proxyInputRequestStep: subagentInputRequestStep,
226
- queue,
227
- session: currentSession,
228
- });
229
- currentSession = waited.session;
230
- currentStep = deliverStep(waited.item);
231
- continue;
232
- }
233
- if (mode === "task") {
234
- throw createTaskModeWaitError();
235
- }
236
- const waited = await waitForDeliverQueueItem({
237
- bufferedDeliveries,
238
- park,
239
- proxyInputRequestStep: subagentInputRequestStep,
240
- queue,
241
- session: currentSession,
242
- });
243
- currentSession = waited.session;
244
- currentStep = deliverStep(waited.item);
245
- continue;
246
- }
247
- currentStep = wrapContinuation(stepResult.next);
248
- }
249
- }
250
- async function routeProxiedDeliverPayloads(input) {
251
- const remainders = [];
252
- const compiledArtifactsSource = input.ctx.require(BundleKey).compiledArtifactsSource;
253
- for (const payload of input.payloads) {
254
- const routed = routeDeliverPayload({ payload, session: input.session });
255
- for (const forChild of routed.forChildren) {
256
- // The child runtime owns its own queue. Reach it through the
257
- // shared `createRuntime` closure — the continuous runtime's
258
- // `deliver` implementation looks up the queue by continuation
259
- // token and wakes the parked child.
260
- const childRuntime = input.createRuntime({ compiledArtifactsSource });
261
- try {
262
- await childRuntime.deliver({
263
- auth: input.auth ?? null,
264
- continuationToken: forChild.childContinuationToken,
265
- payload: forChild.payload,
266
- });
267
- }
268
- catch (error) {
269
- // The child session may have already completed or failed
270
- // between the HITL emission and the user's response. Treat
271
- // the deliver as a no-op — the response effectively falls
272
- // through to the parent as stale input.
273
- if (!isRuntimeNoActiveSessionError(error)) {
274
- throw error;
275
- }
276
- // Breadcrumb the drop so an operator chasing a "user
277
- // clicked approve and nothing happened" report can correlate
278
- // the request ids to the child session that had already
279
- // completed. Warn-level because the condition is expected
280
- // (races between child completion and parent delivery) but
281
- // worth surfacing.
282
- log.warn("dropped stale HITL response for completed subagent", {
283
- childContinuationToken: forChild.childContinuationToken,
284
- errorId: createErrorId(),
285
- requestIds: forChild.payload.inputResponses.map((response) => response.requestId),
286
- sessionId: input.session.sessionId,
287
- });
288
- }
289
- }
290
- if (routed.forSelf !== undefined) {
291
- remainders.push(routed.forSelf);
292
- }
293
- }
294
- return remainders;
295
- }
296
- function dispatchPendingRuntimeActions(input) {
297
- const batch = getPendingRuntimeActionBatch(input.session);
298
- if (batch === undefined) {
299
- return input.session;
300
- }
301
- const bundle = input.ctx.require(BundleKey);
302
- const auth = input.ctx.get(AuthKey) ?? null;
303
- const capabilities = input.ctx.get(CapabilitiesKey);
304
- const initiatorAuth = input.ctx.get(InitiatorAuthKey) ?? null;
305
- let nextSession = input.session;
306
- for (const action of batch.actions) {
307
- if (action.kind !== "subagent-call") {
308
- throw new Error(`Unsupported runtime action kind "${action.kind}" in continuous runtime.`);
309
- }
310
- const childRuntime = input.createRuntime({
311
- compiledArtifactsSource: bundle.compiledArtifactsSource,
312
- nodeId: action.nodeId,
313
- });
314
- const { childContinuationToken, runInput } = buildSubagentRunInput({
315
- action,
316
- auth,
317
- batchEvent: batch.event,
318
- capabilities,
319
- initiatorAuth,
320
- session: input.session,
321
- });
322
- nextSession = recordPendingSubagentChildToken({
323
- callId: action.callId,
324
- childContinuationToken,
325
- session: nextSession,
326
- });
327
- // Register the continuous-runtime dispatcher for this child so
328
- // its subagent-adapter `input.requested` handler can forward
329
- // HITL requests to this parent's queue without going through
330
- // the workflow `resumeHook` path.
331
- registerContinuousSubagentInputRequestDispatcher({
332
- childContinuationToken,
333
- dispatcher: (payload) => {
334
- input.queue.push(payload);
335
- input.wake();
336
- },
337
- });
338
- void childRuntime
339
- .run(runInput)
340
- .then(async (handle) => {
341
- await input.emit(createSubagentCalledEvent({
342
- callId: action.callId,
343
- childSessionId: handle.sessionId,
344
- name: action.name,
345
- sequence: batch.event.sequence,
346
- sessionId: input.session.sessionId,
347
- toolName: action.subagentName,
348
- turnId: batch.event.turnId,
349
- workflowId: "continuous://subagent",
350
- }));
351
- const result = await handle.result;
352
- if (result.status !== "completed") {
353
- throw new Error(`Subagent "${action.subagentName}" did not complete (status: ${result.status}).`);
354
- }
355
- return result.output;
356
- })
357
- .then((output) => {
358
- input.queue.push({
359
- kind: "runtime-action-result",
360
- results: [
361
- {
362
- callId: action.callId,
363
- kind: "subagent-result",
364
- output,
365
- subagentName: action.subagentName,
366
- },
367
- ],
368
- });
369
- input.wake();
370
- }, (error) => {
371
- // Surface the failure through the shared structured-log path
372
- // (`log.error` records on the active OTel span and walks
373
- // the `error` cause chain via `formatError`) before
374
- // enqueueing the result. Without this log the
375
- // fire-and-forget rejection branch silently stuffed a
376
- // generic "SUBAGENT_EXECUTION_FAILED" message into the queue
377
- // with no operator-visible breadcrumb.
378
- const errorId = createErrorId();
379
- log.error("subagent child run failed", {
380
- callId: action.callId,
381
- childContinuationToken,
382
- errorId,
383
- sessionId: input.session.sessionId,
384
- subagentName: action.subagentName,
385
- error,
386
- });
387
- input.queue.push({
388
- kind: "runtime-action-result",
389
- results: [
390
- {
391
- callId: action.callId,
392
- isError: true,
393
- kind: "subagent-result",
394
- output: {
395
- code: "SUBAGENT_EXECUTION_FAILED",
396
- message: toErrorMessage(error),
397
- },
398
- subagentName: action.subagentName,
399
- },
400
- ],
401
- });
402
- input.wake();
403
- })
404
- .finally(() => {
405
- unregisterContinuousSubagentInputRequestDispatcher(childContinuationToken);
406
- });
407
- }
408
- return nextSession;
409
- }
410
- async function waitForRuntimeActionResults(input) {
411
- let currentSession = input.session;
412
- const results = await accumulateRuntimeActionResults({
413
- bufferedDeliveries: input.bufferedDeliveries,
414
- async getNext() {
415
- while (true) {
416
- const item = await takeNextQueueItem(input.queue, input.park);
417
- if (item.kind === "deliver") {
418
- // Inbound deliveries mid-wait may carry `inputResponses`
419
- // bound to a descendant's pending HITL batch. Route them
420
- // down **before** buffering — otherwise the response would
421
- // sit in `bufferedDeliveries` until the child completes,
422
- // which it can never do without the response. That
423
- // asymmetry is the parent↔child deadlock this branch
424
- // exists to prevent.
425
- const remainder = await input.routeDeliver(currentSession, item);
426
- if (remainder === undefined) {
427
- continue;
428
- }
429
- return { kind: "deliver", value: remainder };
430
- }
431
- if (item.kind === "runtime-action-result") {
432
- return { kind: "runtime-action-result", results: item.results };
433
- }
434
- // subagent-input-request: proxy the child's HITL up through
435
- // the parent's adapter and keep waiting.
436
- currentSession = await input.proxyInputRequestStep(currentSession, item);
437
- }
438
- },
439
- session: currentSession,
440
- });
441
- return {
442
- result: {
443
- kind: "runtime-action-result",
444
- results: (results ?? []),
445
- },
446
- session: currentSession,
447
- };
448
- }
449
- async function waitForDeliverQueueItem(input) {
450
- let currentSession = input.session;
451
- if (input.bufferedDeliveries.length > 0) {
452
- return {
453
- item: coalesceDeliveries(input.bufferedDeliveries.splice(0)),
454
- session: currentSession,
455
- };
456
- }
457
- while (true) {
458
- const first = await takeNextQueueItem(input.queue, input.park);
459
- if (first.kind === "subagent-input-request") {
460
- currentSession = await input.proxyInputRequestStep(currentSession, first);
461
- continue;
462
- }
463
- if (first.kind !== "deliver") {
464
- continue;
465
- }
466
- const deliveries = [first];
467
- await Promise.resolve();
468
- while (input.queue[0]?.kind === "deliver") {
469
- deliveries.push(input.queue.shift());
470
- }
471
- return {
472
- item: coalesceDeliveries(deliveries),
473
- session: currentSession,
474
- };
475
- }
476
- }
477
- async function takeNextQueueItem(queue, park) {
478
- while (queue.length === 0) {
479
- await park();
480
- await Promise.resolve();
481
- }
482
- const next = queue.shift();
483
- if (next === undefined) {
484
- throw new Error("Expected one queued runtime item.");
485
- }
486
- return next;
487
- }
@@ -1,17 +0,0 @@
1
- import type { Runtime } from "#channel/types.js";
2
- import type { RuntimeCompiledArtifactsSource } from "#runtime/compiled-artifacts-source.js";
3
- import type { CreateRuntime } from "#execution/node-step.js";
4
- export { RuntimeNoActiveSessionError, isRuntimeNoActiveSessionError, } from "#execution/runtime-errors.js";
5
- /**
6
- * Creates a {@link CreateRuntime} factory for the continuous
7
- * (non-durable) runtime.
8
- */
9
- export declare function createContinuousLoopRuntimeFactory(): CreateRuntime;
10
- /**
11
- * Creates an in-memory runtime that provides the delivery shell for a
12
- * continuous (non-durable) run.
13
- */
14
- export declare function createContinuousLoopRuntime(config: {
15
- readonly compiledArtifactsSource: RuntimeCompiledArtifactsSource;
16
- readonly nodeId?: string;
17
- }): Runtime;
@@ -1,123 +0,0 @@
1
- import { buildAdapterContext } from "#channel/adapter-context.js";
2
- import { callAdapterEventHandler } from "#channel/adapter.js";
3
- import { toContextAccessor } from "#context/container.js";
4
- import { dispatchStreamEventHooks } from "#context/hook-lifecycle.js";
5
- import { BundleKey, ChannelKey, SessionIdKey } from "#context/keys.js";
6
- import { getCompiledRuntimeAgentBundle } from "#runtime/sessions/compiled-agent-cache.js";
7
- import { continuousEntry } from "#execution/continuous-entry.js";
8
- import { buildRunContext } from "#execution/runtime-context.js";
9
- import { RuntimeNoActiveSessionError } from "#execution/runtime-errors.js";
10
- export { RuntimeNoActiveSessionError, isRuntimeNoActiveSessionError, } from "#execution/runtime-errors.js";
11
- /**
12
- * Creates a {@link CreateRuntime} factory for the continuous
13
- * (non-durable) runtime.
14
- */
15
- export function createContinuousLoopRuntimeFactory() {
16
- const state = {
17
- queues: new Map(),
18
- parked: new Map(),
19
- };
20
- return function createRuntime(config) {
21
- return buildContinuousRuntime({ config, createRuntime, state });
22
- };
23
- }
24
- /**
25
- * Creates an in-memory runtime that provides the delivery shell for a
26
- * continuous (non-durable) run.
27
- */
28
- export function createContinuousLoopRuntime(config) {
29
- const factory = createContinuousLoopRuntimeFactory();
30
- return factory(config);
31
- }
32
- function buildContinuousRuntime(input) {
33
- const { config, createRuntime, state } = input;
34
- const { queues, parked } = state;
35
- return {
36
- async run(input) {
37
- const bundle = await getCompiledRuntimeAgentBundle({
38
- compiledArtifactsSource: config.compiledArtifactsSource,
39
- nodeId: config.nodeId,
40
- });
41
- const sessionId = crypto.randomUUID();
42
- const ctx = buildRunContext({ bundle, run: input });
43
- ctx.set(SessionIdKey, sessionId);
44
- const eventStream = new TransformStream(undefined, undefined, new CountQueuingStrategy({ highWaterMark: 1024 }));
45
- const queue = [];
46
- const effectiveToken = input.continuationToken ?? `continuous:${crypto.randomUUID()}`;
47
- queues.set(effectiveToken, queue);
48
- const result = (async () => {
49
- const writer = eventStream.writable.getWriter();
50
- const wake = () => {
51
- const signal = parked.get(effectiveToken);
52
- if (signal !== undefined) {
53
- parked.delete(effectiveToken);
54
- signal();
55
- }
56
- };
57
- const adapter = ctx.require(ChannelKey);
58
- const adapterCtx = buildAdapterContext(adapter, toContextAccessor(ctx));
59
- const bundle = ctx.require(BundleKey);
60
- const hookRegistry = bundle.hookRegistry;
61
- const emit = async (event) => {
62
- const toEmit = await callAdapterEventHandler(adapter, event, adapterCtx);
63
- await writer.write(toEmit);
64
- await dispatchStreamEventHooks({ ctx, registry: hookRegistry, event: toEmit });
65
- };
66
- try {
67
- const entryResult = await continuousEntry({
68
- createRuntime,
69
- ctx,
70
- emit,
71
- input: input.input,
72
- park: () => new Promise((resolve) => {
73
- parked.set(effectiveToken, resolve);
74
- }),
75
- queue,
76
- wake,
77
- });
78
- await writer.close();
79
- return entryResult;
80
- }
81
- catch (error) {
82
- await writer.abort(error);
83
- throw error;
84
- }
85
- finally {
86
- queues.delete(effectiveToken);
87
- parked.delete(effectiveToken);
88
- }
89
- })();
90
- return {
91
- continuationToken: effectiveToken,
92
- events: eventStream.readable,
93
- result,
94
- sessionId,
95
- };
96
- },
97
- async deliver(input) {
98
- const queue = queues.get(input.continuationToken);
99
- if (queue === undefined) {
100
- throw new RuntimeNoActiveSessionError(input.continuationToken);
101
- }
102
- queue.push({
103
- auth: input.auth,
104
- kind: "deliver",
105
- payloads: [input.payload],
106
- });
107
- const signal = parked.get(input.continuationToken);
108
- if (signal !== undefined) {
109
- parked.delete(input.continuationToken);
110
- signal();
111
- }
112
- return { sessionId: input.continuationToken };
113
- },
114
- async getEventStream(_sessionId, _options) {
115
- // The continuous runtime delivers events synchronously through the
116
- // `RunHandle.events` stream returned by `run()`. There is no
117
- // out-of-band durable event store to read from, so a separate
118
- // event-stream lookup by session id is unsupported here. Routes
119
- // that need this method should target the workflow runtime.
120
- throw new Error("createContinuousLoopRuntime does not support getEventStream(); read events from RunHandle.events instead.");
121
- },
122
- };
123
- }