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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # experimental-ash
2
2
 
3
+ ## 0.24.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1a43bef: Remove `result` from `RunHandle`. The workflow runtime's terminal state is observed through the durable event stream's `session.completed` / `session.failed` events. The continuous runtime keeps `result` via a new `ContinuousRunHandle` subtype (in-process resolution; no polling).
8
+ - 5a9f798: Split the durable workflow runtime into a long-lived session driver plus per-turn child workflows. The driver acquires the session's writable once in its workflow body and forwards it to each turn workflow as the second positional `start()` argument; the per-turn child writes directly to the driver's stream, preserving the stable client session stream while preparing turn execution for deployment updates. Requires `@workflow/core` ≥ 5.0.0-beta.6 ([vercel/workflow#2059](https://github.com/vercel/workflow/pull/2059)), which routes child writes to the parent run's stream with a parent-key encrypt-only handshake.
9
+ - 8b2957a: Remove the continuous (in-memory, non-durable) runtime and its supporting
10
+ machinery. The workflow runtime is now the only runtime. Deleted public
11
+ exports: `createContinuousLoopRuntime`, `createContinuousLoopRuntimeFactory`,
12
+ `ContinuousRuntime`, `ContinuousCreateRuntime`, `ContinuousRunHandle`. The
13
+ process-local subagent HITL dispatcher registry
14
+ (`registerContinuousSubagentInputRequestDispatcher` /
15
+ `unregisterContinuousSubagentInputRequestDispatcher`) is also removed —
16
+ subagent `input.requested` events now always forward to the parent via the
17
+ workflow `resumeHook` path.
18
+
19
+ ### Patch Changes
20
+
21
+ - 8ca8600: fix(ash): honor `defineInstrumentation` exports when running under Nitro
22
+
23
+ Nitro evaluates the harness's instrumentation-config module twice (once via the generated plugin's `file://` URL, once via the inlined `#harness/*` alias), so a module-local store left the harness reading `undefined` even after the plugin registered a config. The config now lives on `globalThis` under a stable `Symbol.for(...)`, so telemetry actually flows when an `agent/instrumentation.ts` default export is present.
24
+
25
+ ## 0.23.0
26
+
27
+ ### Minor Changes
28
+
29
+ - 316f6c5: feat(ash): add `defineState` for typed durable state, remove raw `ContextKey` from public API
30
+
31
+ `defineState(name, initial)` creates a typed state handle with `get()` and `update()`. All operations throw outside the Ash context scope. Replaces the `ContextKey` + `ensureContext` / `setContext` / `requireContext` pattern with a single primitive.
32
+
33
+ Breaking: `ContextKey`, `ensureContext`, `getContext`, `setContext`, `requireContext`, `hasContext`, `ContextAccessor`, `AshContext`, `ContextProvider`, and `ContextReader` are no longer exported from `experimental-ash/context`.
34
+
35
+ ### Patch Changes
36
+
37
+ - 5aedab4: Add browser client support for one-turn `clientContext`, React `prepareSend`, and AI SDK `UserContent` messages.
38
+
3
39
  ## 0.22.2
4
40
 
5
41
  ### Patch Changes
@@ -84,22 +84,19 @@ the workflow path.
84
84
 
85
85
  ## Dispatch
86
86
 
87
- Lifecycle dispatch lives in `src/context/hook-lifecycle.ts`. Both
88
- runtime entry points (`execution/workflow-steps.ts` for the durable
89
- workflow path and `execution/continuous-entry.ts` for the in-memory
90
- continuous path) call `runHookLifecycleStep` once per turn, **inside**
91
- the active ALS scope so hook code can read and write `ctx.ash` like
92
- every other authored function. `runHookLifecycleStep` wraps
93
- `dispatchHookLifecycle`, lowers a `turn-failed` outcome into a parking
94
- `StepResult` (`{ next: null }` for conversation mode,
95
- `{ next: { done: true, output } }` for task mode), and otherwise hands
96
- off to the supplied harness step callback with the (possibly
97
- augmented) input.
98
-
99
- Both runtime entry points gate dispatch on
100
- `getHarnessEmissionState(session).turnId === ""` so tool-loop
101
- continuations and runtime-action resumes (which are continuations of
102
- an existing turn) skip the lifecycle stack.
87
+ Lifecycle dispatch lives in `src/context/hook-lifecycle.ts`. The
88
+ workflow runtime entry point (`execution/workflow-steps.ts`) calls
89
+ `runHookLifecycleStep` once per turn, **inside** the active ALS scope
90
+ so hook code can read and write `ctx.ash` like every other authored
91
+ function. `runHookLifecycleStep` wraps `dispatchHookLifecycle`, lowers
92
+ a `turn-failed` outcome into a parking `StepResult` (`{ next: null }`
93
+ for conversation mode, `{ next: { done: true, output } }` for task
94
+ mode), and otherwise hands off to the supplied harness step callback
95
+ with the (possibly augmented) input.
96
+
97
+ Dispatch is gated on `getHarnessEmissionState(session).turnId === ""`
98
+ so tool-loop continuations and runtime-action resumes (which are
99
+ continuations of an existing turn) skip the lifecycle stack.
103
100
 
104
101
  Stages, in order:
105
102
 
@@ -64,4 +64,4 @@ The runtime stores both `auth.current` and `auth.initiator`. Follow-up messages
64
64
 
65
65
  The runtime owns stream plumbing; the channel owns delivery policy. The runtime calls `channel.onEvent(event)` for each lifecycle event — the channel may transform it or perform platform side effects. The harness emits events without knowing the transport.
66
66
 
67
- Authored stream-event hooks fan out alongside `callAdapterEventHandler` from the same `HarnessEmitFn` composer (`workflow-steps.ts` and `continuous-runtime.ts`). Hook errors propagate through the emit composer and are caught by the existing harness error path, which emits the recoverable `turn.failed` cascade. See [Hooks](./hooks.md).
67
+ Authored stream-event hooks fan out alongside `callAdapterEventHandler` from the same `HarnessEmitFn` composer (`workflow-steps.ts`). Hook errors propagate through the emit composer and are caught by the existing harness error path, which emits the recoverable `turn.failed` cascade. See [Hooks](./hooks.md).
@@ -110,9 +110,9 @@ Important behavior:
110
110
  - follow-up messages update `auth.current` without changing `auth.initiator`
111
111
  - unprotected agents expose both as `null`
112
112
 
113
- Auth on follow-up messages (`deliver()`) is honored by both the workflow and continuous runtimes.
114
- When a different user sends a follow-up to the same session, `session.auth.current` reflects the
115
- new caller on that turn while `session.auth.initiator` stays the same.
113
+ Auth on follow-up messages (`deliver()`) is honored by the workflow runtime. When a different
114
+ user sends a follow-up to the same session, `session.auth.current` reflects the new caller on
115
+ that turn while `session.auth.initiator` stays the same.
116
116
 
117
117
  ## What Ash Does Not Do
118
118
 
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: "FAQs"
3
+ description: "Frequently asked questions about Ash."
4
+ ---
5
+
6
+ # FAQs
7
+
8
+ ## How do I view my agent's observability and drill into conversation traces?
9
+
10
+ When you deploy an Ash agent to Vercel, the platform auto-detects `ash` as the
11
+ framework, which surfaces an **Agent Runs** tab under your project's
12
+ **Observability** view in the Vercel dashboard. From there you can browse
13
+ sessions and drill into each conversation's trace.
14
+
15
+ > The Agent Runs tab is currently gated — your Vercel team needs the feature
16
+ > enabled before it appears. If you don't see it, reach out to your Vercel
17
+ > contact to get your team enabled.
18
+
19
+ Agent Runs is separate from the OpenTelemetry exporters configured in
20
+ [`instrumentation.ts`](./instrumentation.md) — those still work and are the
21
+ recommended path if you want spans in Braintrust, Datadog, or another
22
+ third-party backend.
23
+
24
+ ## Does Ash use the Chat SDK?
25
+
26
+ Ash uses Chat SDK's **card-builder components** (Cards, Buttons,
27
+ Actions, etc.) for composing rich Slack messages — when you build a card with
28
+ Ash's Slack channel, the underlying primitives come from Chat SDK and get
29
+ converted to Slack Block Kit at post time.
30
+
31
+ Ash does **not** use Chat SDK's runtime. The `Chat`, `Adapter`, and `Thread`
32
+ primitives are never imported or reachable through Ash's public API. Ash's
33
+ channel layer — webhook handling, signature verification, event parsing, and
34
+ thread management — is implemented inside Ash itself (see [Channels](./channels/)).
35
+
36
+ In short:
37
+
38
+ - **Building Slack messages** → the components feel just like Chat SDK cards.
39
+ - **Wiring a channel** → you author against Ash's `defineChannel(...)` API, not
40
+ a Chat SDK adapter.
41
+
42
+ ## How is session data persisted?
43
+
44
+ Ash persists session state automatically using the
45
+ [Workflow SDK](https://workflow-sdk.dev) — an open-source TypeScript
46
+ library that makes ordinary functions durable, resumable, and crash-safe.
47
+ Each Ash session corresponds to one workflow run: when a new message comes in,
48
+ the runtime either starts a new workflow or resumes an existing one, and the
49
+ durable context is serialized and threaded forward across each model-call
50
+ boundary so the session can be reloaded on the next turn.
51
+
52
+ You don't write workflow code directly. Workflow primitives (`start()`,
53
+ `resumeHook()`, etc.) are an implementation detail of Ash's runtime layer —
54
+ channels, tools, and hooks never touch them. This separation is enforced by
55
+ the framework's mechanical invariants.
56
+
57
+ If you want session data from your own code, there are two supported surfaces:
58
+
59
+ - **Tools** can read the current session's metadata (sessionId, turn, auth,
60
+ parent lineage) via `getSession()` from `experimental-ash/context`. This is
61
+ read-only.
62
+ - **Durable context keys + `ContextProvider`** are the supported pattern for
63
+ reading or writing session-scoped durable state from authored code — see
64
+ [Session Context](./session-context.md).
65
+
66
+ For the wire-level session lifecycle (creating sessions, streaming events,
67
+ reconnecting by event index) see [Sessions And Streaming](./runs-and-streaming.md).
@@ -25,6 +25,7 @@
25
25
  "cli-build-and-debugging",
26
26
  "typescript-api",
27
27
  "...",
28
+ "faqs",
28
29
  "---",
29
30
  "research"
30
31
  ]
@@ -166,6 +166,17 @@ In both cases, the schedule session uses the **app principal**: `getSession().au
166
166
 
167
167
  The session goes through the same durable runtime engine as any other Ash session.
168
168
 
169
+ ## On Vercel
170
+
171
+ On hosted Vercel builds, Ash compiles every `defineSchedule(...)` into a Vercel Cron Job. Each schedule's `cron` expression becomes an entry in `.vercel/output/config.json` `crons[]`, which the platform reads at deploy time.
172
+
173
+ You can view and monitor your schedules in two places in the Vercel dashboard:
174
+
175
+ - **Settings → Cron Jobs** — lists every schedule the deployment registered, with its cron expression and target path. Use this to confirm a schedule was discovered and shipped.
176
+ - **Observability → Cron Jobs** — shows execution history (when each schedule fired, success/failure, latency). Use this to confirm a schedule is actually firing on cadence.
177
+
178
+ The execution itself runs through the same durable runtime engine as any other Ash session, so per-run logs also appear under **Observability → Logs**.
179
+
169
180
  ## When to use a schedule
170
181
 
171
182
  Use a schedule when the agent should initiate work on its own cadence:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "Session Context"
3
- description: "Runtime helpers: getSession, getSandbox, getSkill, and ContextKey."
3
+ description: "Runtime helpers: getSession, getSandbox, getSkill, and defineState."
4
4
  ---
5
5
 
6
6
  Ash exposes runtime helpers for authored code:
@@ -8,16 +8,10 @@ Ash exposes runtime helpers for authored code:
8
8
  - `getSession()`
9
9
  - `getSandbox()`
10
10
  - `getSkill(identifier)`
11
- - `getContext(key)` -- returns `T | undefined`
12
- - `requireContext(key)` -- returns `T`, throws if unset
13
- - `hasContext(key)` -- returns `boolean`
14
- - `setContext(key, valueOrUpdater)` -- returns `T`
15
- - `ensureContext(key, factory)` -- returns `T`
11
+ - `defineState(name, initial)` -- typed durable state with `get()` and `update()`
16
12
 
17
13
  These APIs work only inside active authored runtime execution such as tools, channel event
18
- handlers, and authored hooks. Under the hood, they read from a single `AshContext` container that
19
- the framework binds to the current async call chain via `AsyncLocalStorage`. Authored hooks
20
- receive the same `ContextAccessor` on `HookContext.ash` -- see [Hooks](./hooks.md).
14
+ handlers, and authored hooks. They throw when called outside a managed context.
21
15
 
22
16
  ## `getSession()`
23
17
 
@@ -107,112 +101,75 @@ Important behavior:
107
101
 
108
102
  See [Skills](./skills.md) for the full authoring model.
109
103
 
110
- ## Passing Custom Context From a Channel
104
+ ## Custom State With `defineState`
111
105
 
112
- Channels can inject custom typed durable context into the agent via the channel's `state` and
113
- `context()` properties on `defineChannel`, or via the auth attributes returned from `onAppMention`
114
- or `onDirectMessage` on `slackChannel()`. This is useful when a channel needs to pass
115
- platform-specific metadata (tenant ID, feature flags, etc.) that authored tools can read on the
116
- same turn and on later turns.
106
+ Use `defineState` when your agent needs durable typed state that tools, hooks, and channel
107
+ handlers can share. State survives across workflow step boundaries.
117
108
 
118
- ### Defining a key
109
+ ### Defining state
119
110
 
120
- Declare a `ContextKey` at module scope. The key is shared between the channel and the tools that
121
- read it.
111
+ Declare the state handle at module scope. The handle is shared between all code that imports it.
122
112
 
123
- `agent/channels/keys.ts`
113
+ `agent/lib/budget.ts`
124
114
 
125
115
  ```ts
126
- import { ContextKey } from "experimental-ash/context";
116
+ import { defineState } from "experimental-ash/context";
127
117
 
128
- export const TenantKey = new ContextKey<string>("myapp.tenant");
129
- ```
130
-
131
- ### Setting context from a channel
132
-
133
- Use `slackChannel()` and seed context via the `onAppMention` return value's auth attributes:
134
-
135
- `agent/channels/slack.ts`
118
+ interface BudgetState {
119
+ readonly count: number;
120
+ readonly cap: number;
121
+ }
136
122
 
137
- ```ts
138
- import { slackChannel } from "experimental-ash/channels/slack";
139
- import { TenantKey } from "./keys.js";
140
-
141
- export default slackChannel({
142
- onAppMention(ctx, message) {
143
- if (!message.author) return null;
144
- const tenantId = lookupTenant(message);
145
- return {
146
- auth: {
147
- principalId: message.author.userId,
148
- principalType: "user",
149
- authenticator: "slack",
150
- attributes: { tenantId },
151
- },
152
- };
153
- },
154
- events: {
155
- "message.completed"(event, ctx) {
156
- if (event.finishReason === "tool-calls") return;
157
- if (event.message) ctx.thread.post(event.message);
158
- },
159
- "session.failed"(event, ctx) {
160
- ctx.thread.post("Something went wrong.");
161
- },
162
- },
163
- });
123
+ export const budget = defineState<BudgetState>("myapp.budget", () => ({
124
+ count: 0,
125
+ cap: 25,
126
+ }));
164
127
  ```
165
128
 
166
- Auth lives on the return value of `onAppMention` (or `onDirectMessage` for 1:1 DMs), not on a
167
- separate channel object.
168
-
169
- ### Reading context from a tool
129
+ ### Reading and writing from tools
170
130
 
171
131
  ```ts
172
- import { requireContext } from "experimental-ash/context";
173
132
  import { defineTool } from "experimental-ash/tools";
174
133
  import { z } from "zod";
175
- import { TenantKey } from "../channels/keys.js";
134
+ import { budget } from "../lib/budget.js";
176
135
 
177
136
  export default defineTool({
178
- description: "Return the active tenant.",
137
+ description: "Check the remaining tool budget.",
179
138
  inputSchema: z.object({}),
180
139
  async execute() {
181
- const tenant = requireContext(TenantKey);
182
- return { tenant };
140
+ const current = budget.get();
141
+ return { remaining: current.cap - current.count };
183
142
  },
184
143
  });
185
144
  ```
186
145
 
187
- ### Rebuilding virtual values with `ContextProvider`
188
-
189
- If a channel needs to vend a live non-serializable object each step, declare a `ContextProvider`.
190
- Providers derive live step-local values from durable context keys.
191
-
192
- The intended pattern is:
193
-
194
- - The channel's event handler or `run()` setup writes durable serializable facts such as
195
- tenant IDs, channel IDs, or installation IDs.
196
- - A `ContextProvider` derives live step-local values such as SDK clients from those durable keys.
197
- - Tools and other authored step code read the derived value with `requireContext(...)` or
198
- `getContext(...)`.
146
+ ### Updating from hooks
199
147
 
200
148
  ```ts
201
- import { ContextKey, type ContextProvider } from "experimental-ash/context";
202
-
203
- const TenantKey = new ContextKey<string>("myapp.tenant");
204
- const SlackClientKey = new ContextKey<{ readonly tenantId: string }>("myapp.slackClient");
205
-
206
- const slackClientProvider: ContextProvider<{ readonly tenantId: string }> = {
207
- key: SlackClientKey,
208
- create(ctx) {
209
- return { tenantId: ctx.require(TenantKey) };
149
+ import { defineHook } from "experimental-ash/hooks";
150
+ import { budget } from "../lib/budget.js";
151
+
152
+ export default defineHook({
153
+ lifecycle: {
154
+ turn() {
155
+ // Reset budget each turn
156
+ budget.update(() => ({ count: 0, cap: 25 }));
157
+ },
158
+ },
159
+ events: {
160
+ "actions.requested"() {
161
+ budget.update((s) => ({ ...s, count: s.count + 1 }));
162
+ },
210
163
  },
211
- };
164
+ });
212
165
  ```
213
166
 
214
- Provider output is readable through `requireContext(SlackClientKey)` or
215
- `getContext(SlackClientKey)` during that step, but it is not serialized.
167
+ ### API
168
+
169
+ | Method | Description |
170
+ | ------------ | -------------------------------------------------------------------------------- |
171
+ | `get()` | Read the current value. Returns `initial()` on first access. Throws outside ALS. |
172
+ | `update(fn)` | Apply a function to the current value. Throws outside ALS. |
216
173
 
217
174
  ## Where These APIs Work
218
175
 
@@ -233,7 +190,7 @@ explaining the required scope.
233
190
 
234
191
  ## How It Works
235
192
 
236
- All three accessors read from the same `AshContext` container bound by a single `AsyncLocalStorage`.
193
+ All runtime accessors read from the same `AshContext` container bound by a single `AsyncLocalStorage`.
237
194
  The framework sets up this context before invoking authored code:
238
195
 
239
196
  1. The runtime entry point creates an `AshContext` and populates durable seed keys (auth, session
@@ -137,6 +137,19 @@ Do not use a skill for:
137
137
  - shell or filesystem setup for the agent -> use `sandbox/`
138
138
  - a truly separate specialist surface -> use a subagent
139
139
 
140
+ ## Skill Scoping Across Agents
141
+
142
+ Skills are scoped to the agent that declares them. The root agent's `skills/` are available only
143
+ to the root agent; a subagent's `skills/` (under `agent/subagents/<id>/skills/`) are available
144
+ only to that subagent.
145
+
146
+ There is no shared-skill mechanism. If two agents need the same procedure, either duplicate the
147
+ markdown under each agent's `skills/`, or — if both agents really need the _same_ identity around
148
+ it — reconsider whether the subagent boundary makes sense.
149
+
150
+ For sharing executable helpers (not skill instructions), use `lib/` — modules under `lib/` are not
151
+ indexed as skills, but can be imported from any tool or hook in the same agent tree.
152
+
140
153
  ## TypeScript-Authored Skills
141
154
 
142
155
  If markdown is not enough, you can author a skill in TypeScript with `defineSkill(...)`.
@@ -69,14 +69,20 @@ Subagent execution gets:
69
69
  - its own instructions prompt
70
70
  - its own tools
71
71
  - its own sandbox (independent of the parent's sandbox)
72
- - its own skill activation state
72
+ - its own `skills/` set (independent of the parent's skills)
73
73
  - immediate parent lineage in `getSession().parent`
74
74
 
75
- The subagent's sandbox does not inherit from the parent. Different agents generally have different
76
- skills, so sharing a filesystem would be confusing. Each subagent gets the framework default
77
- sandbox unless it authors its own override at `subagents/<name>/sandbox.ts` (or
78
- `subagents/<name>/sandbox/sandbox.ts` when paired with a `workspace/` folder). A subagent can also
79
- author only `subagents/<name>/sandbox/workspace/` to seed files without overriding the definition.
75
+ Skills and sandboxes do not cross the parent/child boundary. The subagent only sees skills
76
+ authored under `agent/subagents/<id>/skills/`; skills under the root `agent/skills/` are not
77
+ available inside the subagent's turns. If two subagents need the same procedure, duplicate the
78
+ markdown under each subagent's `skills/` (or, for typed code reuse, share helpers via `lib/`).
79
+
80
+ The subagent's sandbox follows the same rule: it does not inherit from the parent, since different
81
+ agents generally have different skills and sharing a filesystem would be confusing. Each subagent
82
+ gets the framework default sandbox unless it authors its own override at
83
+ `subagents/<name>/sandbox.ts` (or `subagents/<name>/sandbox/sandbox.ts` when paired with a
84
+ `workspace/` folder). A subagent can also author only `subagents/<name>/sandbox/workspace/` to seed
85
+ files without overriding the definition.
80
86
 
81
87
  ## Stream Behavior
82
88
 
@@ -40,7 +40,7 @@ There is no `name` override and no compile-time normalization — if you want a
40
40
  identifier, name the file in snake_case.
41
41
 
42
42
  `defineTool`, `disableTool`, `defineBashTool`, `defineReadFileTool`, and `defineWriteFileTool` live on the `experimental-ash/tools` subpath.
43
- Runtime context helpers (`getSession`, `getContext`, `requireContext`, `hasContext`, `setContext`, `ensureContext`) live on `experimental-ash/context`.
43
+ Runtime context helpers (`getSession`, `defineState`) live on `experimental-ash/context`.
44
44
  `getSandbox` lives on `experimental-ash/sandbox` and `getSkill` lives on `experimental-ash/skills`.
45
45
 
46
46
  ## What A Tool Definition Needs
@@ -205,14 +205,13 @@ The runtime tool name comes from the filename (here, `repo_shell`, `read_file`,
205
205
  When replacing the framework `read_file`, the authored version inherits the same compaction
206
206
  state-reset behavior by default. Provide an explicit `onCompact` to override that.
207
207
 
208
- ### Replace A Default With Custom Context
208
+ ### Replace A Default With Custom State
209
209
 
210
- `agent/tools/todo.ts` - replace the framework `todo` tool with a custom durable context-backed
211
- version. Declare your own `ContextKey`, initialize it with `ensureContext`, and read/write it with
212
- `requireContext` / `setContext`:
210
+ `agent/tools/todo.ts` - replace the framework `todo` tool with a custom durable state-backed
211
+ version using `defineState`:
213
212
 
214
213
  ```ts
215
- import { ContextKey, ensureContext, requireContext, setContext } from "experimental-ash/context";
214
+ import { defineState } from "experimental-ash/context";
216
215
  import { defineTool } from "experimental-ash/tools";
217
216
  import { z } from "zod";
218
217
 
@@ -220,7 +219,7 @@ interface NoteListState {
220
219
  readonly notes: readonly string[];
221
220
  }
222
221
 
223
- const NoteListStateKey = new ContextKey<NoteListState>("myapp.notes");
222
+ const noteList = defineState<NoteListState>("myapp.notes", () => ({ notes: [] }));
224
223
 
225
224
  export default defineTool({
226
225
  description: "Append a note or read the running list of notes.",
@@ -228,15 +227,12 @@ export default defineTool({
228
227
  note: z.string().optional(),
229
228
  }),
230
229
  async execute(input) {
231
- ensureContext(NoteListStateKey, () => ({ notes: [] }));
232
-
233
230
  if (typeof input.note === "string" && input.note.length > 0) {
234
- const next = input.note;
235
- setContext(NoteListStateKey, (current) => ({
236
- notes: [...(current?.notes ?? []), next],
231
+ noteList.update((current) => ({
232
+ notes: [...current.notes, input.note!],
237
233
  }));
238
234
  }
239
- return requireContext(NoteListStateKey);
235
+ return noteList.get();
240
236
  },
241
237
  });
242
238
  ```
@@ -53,17 +53,17 @@ Each runtime accessor lives on the subpath that owns its concern:
53
53
  - `getSession()` - current session, turn, auth, and optional parent lineage (`experimental-ash/context`)
54
54
  - `getSandbox()` - live sandbox handle for the current agent (`experimental-ash/sandbox`)
55
55
  - `getSkill(identifier)` - handle for a named skill visible to the current agent (`experimental-ash/skills`)
56
- - `getContext(key)` / `requireContext(key)` / `hasContext(key)` / `setContext(key)` / `ensureContext(key, factory)` - unified context helpers (`experimental-ash/context`)
56
+ - `defineState(name, initial)` - typed durable state with `get()` and `update()` (`experimental-ash/context`)
57
57
 
58
58
  Related exported types by subpath:
59
59
 
60
- - `experimental-ash/context`: `Session`, `SessionAuth`, `SessionAuthContext`, `SessionParent`, `SessionTurn`, `ContextKey`, `ContextKeyOptions`, `ContextProvider`, `ContextReader`, `ContextAccessor`, `AshContext`
60
+ - `experimental-ash/context`: `Session`, `SessionAuth`, `SessionAuthContext`, `SessionParent`, `SessionTurn`, `StateHandle`
61
61
  - `experimental-ash/skills`: `SkillHandle`, `SkillFile`, `SkillDefinition`
62
62
  - `experimental-ash`: `RunMode`
63
63
  - `experimental-ash/evals`: eval types
64
64
 
65
- Ash also exports lower-level runtime primitives such as `createToolLoopHarness(...)`,
66
- `createContinuousLoopRuntime(...)`, and `createWorkflowRuntime(...)`.
65
+ Ash also exports lower-level runtime primitives such as `createToolLoopHarness(...)`
66
+ and `createWorkflowRuntime(...)`.
67
67
 
68
68
  Channel and Slack types exported from `experimental-ash/channels/slack`:
69
69
 
@@ -38,9 +38,9 @@ export interface SessionAuthContext {
38
38
  /**
39
39
  * Function provided by the runtime that writes one event to the event stream.
40
40
  *
41
- * Backed by `getWritable()` in the workflow runtime or a `TransformStream`
42
- * in the continuous loop runtime. Not part of the adapter interface —
43
- * the runtime always writes events to the stream itself.
41
+ * Backed by `getWritable()` in the workflow runtime. Not part of the
42
+ * adapter interface the runtime always writes events to the stream
43
+ * itself.
44
44
  */
45
45
  export type EventEmitFn = (event: HandleMessageStreamEvent) => Promise<void>;
46
46
  /**
@@ -195,7 +195,10 @@ export interface DeliverInput {
195
195
  readonly payload: DeliverPayload;
196
196
  }
197
197
  /**
198
- * Terminal outcome of a runtime turn, resolved via `RunHandle.result`.
198
+ * Terminal outcome of a runtime run.
199
+ *
200
+ * Terminal state on the workflow runtime is observed through the durable
201
+ * event stream's `session.completed` / `session.failed` events.
199
202
  */
200
203
  export type RunResult = {
201
204
  readonly status: "completed";
@@ -207,19 +210,14 @@ export type RunResult = {
207
210
  * Handle returned immediately by `runtime.run()` before the step loop
208
211
  * completes.
209
212
  *
210
- * Carries the identifiers needed for stream endpoints and the eventual
211
- * result as a promise.
213
+ * Carries the identifiers needed for stream endpoints.
212
214
  */
213
215
  export interface RunHandle {
214
216
  readonly continuationToken: string;
215
217
  readonly events: ReadableStream<HandleMessageStreamEvent>;
216
- readonly result: Promise<RunResult>;
217
218
  /**
218
- * Runtime-owned identifier for this session.
219
- *
220
- * Used for stream and inspection APIs. Workflow-backed runs expose
221
- * the workflow run id; continuous runs mint an in-memory session id
222
- * when the run starts.
219
+ * Runtime-owned identifier for this session. Used for stream and
220
+ * inspection APIs — workflow-backed runs expose the workflow run id.
223
221
  */
224
222
  readonly sessionId: string;
225
223
  }
@@ -1,4 +1,4 @@
1
1
  import{i as e,t}from"./chunk-8L7ocgPr.js";import{_ as n,f as r,g as i,l as a,p as o,v as s}from"./types-MZUhN0Zy.js";import{n as c,r as l,t as u}from"./token-util-CHjOk3A7.js";var d=class extends Error{status;body;constructor(e,t){super(t||`Server returned ${e}.`),this.name=`ClientError`,this.status=e,this.body=t}};function f(e){if(e instanceof DOMException)return e.name===`AbortError`;if(!(e instanceof Error))return!1;let t=`code`in e&&typeof e.code==`string`?e.code:void 0;return e.name===`AbortError`||e.message===`terminated`||t===`UND_ERR_SOCKET`||/abort|cancel|disconnect|premature close|socket|terminated/i.test(e.message)}async function*p(e){let t=e.getReader(),n=new TextDecoder,r=``;try{for(;;){let e=await t.read();if(e.done){r+=n.decode();break}e.value&&(r+=n.decode(e.value,{stream:!0}));let i=r.indexOf(`
2
2
  `);for(;i!==-1;){let e=r.slice(0,i).trim();r=r.slice(i+1),e.length>0&&(yield JSON.parse(e)),i=r.indexOf(`
3
3
  `)}}let e=r.trim();e.length>0&&(yield JSON.parse(e))}finally{t.releaseLock()}}function m(e,t,n){let r=t.startsWith(`/`)?t:`/${t}`,i=_(n);if(h(e)){let t=new URL(e);return t.pathname=`${g(t.pathname)}${r}`,t.search=i,t.hash=``,t.toString()}return`${g(e)}${r}${i}`}function h(e){return/^[a-z][a-z\d+\-.]*:/i.test(e)}function g(e){return e===`/`?``:e.endsWith(`/`)?e.slice(0,-1):e}function _(e){return!e||Object.keys(e).length===0?``:`?${new URLSearchParams(e).toString()}`}async function*v(e){let t=e.startIndex,n=e.maxReconnectAttempts;for(;;){let r=m(e.host,s(e.sessionId),t>0?{startIndex:String(t)}:void 0),i=await e.resolveHeaders(),a=await fetch(r,{headers:i,signal:e.signal??null});if(!a.ok){let e=await a.text();throw new d(a.status,e)}if(!a.body)throw new d(a.status,`Response body is null.`);let o=!1;try{for await(let e of p(a.body))t+=1,yield e}catch(e){if(!f(e))throw e;o=!0}if(!o||n<=0)return;--n}}var y=t(((e,t)=>{var n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,o=(e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})},s=(e,t,o,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(let c of i(t))!a.call(e,c)&&c!==o&&n(e,c,{get:()=>t[c],enumerable:!(s=r(t,c))||s.enumerable});return e},c=e=>s(n({},`__esModule`,{value:!0}),e),l={};o(l,{SYMBOL_FOR_REQ_CONTEXT:()=>u,getContext:()=>d}),t.exports=c(l);let u=Symbol.for(`@vercel/request-context`);function d(){return globalThis[u]?.get?.()??{}}})),b=t(((t,n)=>{var r=Object.defineProperty,i=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,s=(e,t)=>{for(var n in t)r(e,n,{get:t[n],enumerable:!0})},c=(e,t,n,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(let c of a(t))!o.call(e,c)&&c!==n&&r(e,c,{get:()=>t[c],enumerable:!(s=i(t,c))||s.enumerable});return e},u=e=>c(r({},`__esModule`,{value:!0}),e),d={};s(d,{getVercelOidcToken:()=>m,getVercelOidcTokenSync:()=>h}),n.exports=u(d);var f=y(),p=l();async function m(t){let n=``,r;try{n=h()}catch(e){r=e}try{let[{getTokenPayload:r,isExpired:i},{refreshToken:a}]=await Promise.all([await import(`./token-util-CHjOk3A7.js`).then(t=>e(t.t())),await import(`./token-DtoyQZy2.js`).then(t=>e(t.default))]);(!n||i(r(n),t?.expirationBufferMs))&&(await a(t),n=h())}catch(e){let t=r instanceof Error?r.message:``;throw e instanceof Error&&(t=`${t}
4
- ${e.message}`),t?new p.VercelOidcTokenError(t):e}return n}function h(){let e=(0,f.getContext)().headers?.[`x-vercel-oidc-token`]??process.env.VERCEL_OIDC_TOKEN;if(!e)throw Error(`The 'x-vercel-oidc-token' header is missing from the request. Do you have the OIDC option enabled in the Vercel project settings?`);return e}})),x=t(((e,t)=>{var n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,o=(e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})},s=(e,t,o,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(let c of i(t))!a.call(e,c)&&c!==o&&n(e,c,{get:()=>t[c],enumerable:!(s=r(t,c))||s.enumerable});return e},l=e=>s(n({},`__esModule`,{value:!0}),e),d={};o(d,{AccessTokenMissingError:()=>m.AccessTokenMissingError,RefreshAccessTokenFailedError:()=>m.RefreshAccessTokenFailedError,getContext:()=>p.getContext,getVercelOidcToken:()=>f.getVercelOidcToken,getVercelOidcTokenSync:()=>f.getVercelOidcTokenSync,getVercelToken:()=>h.getVercelToken}),t.exports=l(d);var f=b(),p=y(),m=c(),h=u()})),S=x();const C=`${i}/`,w=new Set([`localhost`,`127.0.0.1`,`0.0.0.0`,`::1`,`[::1]`]);function T(e){return w.has(e.hostname)}const E=`x-vercel-protection-bypass`,D=`x-vercel-trusted-oidc-idp-token`;function O(e){return e.pathname.endsWith(`/ash/v1`)||e.pathname.includes(C)}async function k(e){let t=A(e),n=await M(t,e.resourceUrl);return n!==null&&j(t,n),t}function A(e){let t=new Headers(F(e.headers)),n=process.env.VERCEL_AUTOMATION_BYPASS_SECRET?.trim();return n&&O(e.resourceUrl)&&t.set(E,n),t}function j(e,t){e.has(`authorization`)||e.set(`authorization`,`Bearer ${t}`),e.set(D,t)}async function M(e,t){return N(t)?e.get(`x-vercel-oidc-token`)?.trim()||await P():null}function N(e){return!(!O(e)||T(e))}async function P(){let e=process.env.VERCEL_OIDC_TOKEN?.trim();try{let e=(await(0,S.getVercelOidcToken)()).trim();if(e.length>0)return e}catch{return e??null}return e??null}function F(e){if(e!==void 0)return e instanceof Headers?e:Array.isArray(e)?e.map(([e,t])=>[e,t]):e}function I(){return{streamIndex:0}}function L(e){let t=B(e.events),n=e.session.streamIndex+e.events.length;return t?.type===`session.waiting`?{continuationToken:e.continuationToken??e.session.continuationToken,sessionId:e.sessionId,streamIndex:n}:I()}function R(e){let t;for(let n of e)V(n)&&(t=n.data.message??void 0);return t}function z(e){let t=B(e);return t?.type===`session.waiting`?`waiting`:t?.type===`session.failed`?`failed`:`completed`}function B(e){for(let t=e.length-1;t>=0;t--){let n=e[t];if(n!==void 0&&a(n))return n}}function V(e){return e.type===`message.completed`&&e.data.finishReason!==`tool-calls`}var H=class{continuationToken;sessionId;#e=!1;#t;constructor(e){this.continuationToken=e.continuationToken,this.sessionId=e.sessionId,this.#t=e.createStream}async result(){let e=[];for await(let t of this)e.push(t);return{events:e,message:R(e),sessionId:this.sessionId,status:z(e)}}[Symbol.asyncIterator](){if(this.#e)throw Error(`MessageResponse has already been consumed.`);return this.#e=!0,this.#t()}},U=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}get state(){return this.#t}async sendMessage(e,t){return this.send({message:e},t)}async send(e,t){let n=this.#t,{continuationToken:r,sessionId:i}=await this.#n(e,n,t);return new H({continuationToken:r,createStream:()=>this.#r(i,r,n,t),sessionId:i})}openStream(e){let t=this.#t.sessionId;if(!t)throw Error(`Session has no session ID. Send a message first.`);return v({host:this.#e.host,maxReconnectAttempts:this.#e.maxReconnectAttempts,resolveHeaders:()=>this.#e.resolveHeaders(),sessionId:t,signal:e?.signal,startIndex:e?.startIndex??this.#t.streamIndex})}async#n(e,t,i){let a=t.sessionId?n(t.sessionId):r,o=m(this.#e.host,a),s=await this.#e.resolveHeaders(i?.headers);s.set(`content-type`,`application/json`);let c=W({input:e,session:t});if(c===null)throw Error(`Session.send requires a non-empty message, inputResponses, or both.`);let l=await fetch(o,{body:JSON.stringify(c),headers:s,method:`POST`,signal:i?.signal??null});if(!l.ok){let e=await l.text();throw new d(l.status,e)}let u=await l.json(),f=(typeof u.sessionId==`string`?u.sessionId:void 0)??l.headers.get(`x-ash-session-id`)?.trim()??t.sessionId;if(!f)throw Error(`Message route did not return a session id.`);return{continuationToken:typeof u.continuationToken==`string`?u.continuationToken:void 0,sessionId:f}}async*#r(e,t,n,r){let i=[];try{let t=n.sessionId===e?n.streamIndex:0,o=this.#e.maxReconnectAttempts;for(;;){let n=await this.#i(e,t,r?.signal),s=!1;try{for await(let e of p(n))if(i.push(e),t+=1,yield e,a(e)){s=!0;break}}catch(e){if(!f(e))throw e}if(s||o<=0)break;--o}}finally{this.#t=L({continuationToken:t,events:i,sessionId:e,session:n})}}async#i(e,t,n){let r=m(this.#e.host,s(e),t>0?{startIndex:String(t)}:void 0),i=await this.#e.resolveHeaders(),a=await fetch(r,{headers:i,signal:n??null});if(!a.ok){let e=await a.text();throw new d(a.status,e)}if(!a.body)throw new d(a.status,`Response body is null.`);return a.body}};function W(e){let t={};return e.input.message!==void 0&&(t.message=e.input.message),e.input.inputResponses!==void 0&&e.input.inputResponses.length>0&&(t.inputResponses=e.input.inputResponses),e.session.continuationToken!==void 0&&(t.continuationToken=e.session.continuationToken),Object.keys(t).length===0||e.session.continuationToken===void 0&&t.message===void 0||`continuationToken`in t&&Object.keys(t).length===1?null:t}var G=class{#e;#t;#n;#r;constructor(e){this.#n=e.host,this.#e=e.auth,this.#t=e.headers,this.#r=e.maxReconnectAttempts??3}async health(){let e=m(this.#n,o),t=await this.#i(),n=await fetch(e,{headers:t});if(!n.ok){let e=await n.text();throw new d(n.status,e)}return await n.json()}session(e){let t;return t=typeof e==`string`?{continuationToken:e,streamIndex:0}:e||I(),new U({host:this.#n,maxReconnectAttempts:this.#r,resolveHeaders:e=>this.#i(e)},t)}async#i(e){let t=new Headers,n=await q(this.#t);for(let[e,r]of Object.entries(n))t.set(e,r);if(e)for(let[n,r]of Object.entries(e))t.set(n,r);let r=await this.#a();return r&&t.set(`authorization`,r),t}async#a(){let e=this.#e;if(e){if(`bearer`in e){let t=(await K(e.bearer)).trim();return t.length===0?void 0:`Bearer ${t}`}if(`basic`in e){let t=await K(e.basic.password);return`Basic ${J(e.basic.username,t)}`}}}};async function K(e){return typeof e==`function`?e():e}async function q(e){return e===void 0?{}:typeof e==`function`?await e():e}function J(e,t){let n=new TextEncoder().encode(`${e}:${t}`),r=Array.from(n,e=>String.fromCodePoint(e)).join(``);return btoa(r)}export{x as a,k as i,E as n,v as o,D as r,d as s,G as t};
4
+ ${e.message}`),t?new p.VercelOidcTokenError(t):e}return n}function h(){let e=(0,f.getContext)().headers?.[`x-vercel-oidc-token`]??process.env.VERCEL_OIDC_TOKEN;if(!e)throw Error(`The 'x-vercel-oidc-token' header is missing from the request. Do you have the OIDC option enabled in the Vercel project settings?`);return e}})),x=t(((e,t)=>{var n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,o=(e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})},s=(e,t,o,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(let c of i(t))!a.call(e,c)&&c!==o&&n(e,c,{get:()=>t[c],enumerable:!(s=r(t,c))||s.enumerable});return e},l=e=>s(n({},`__esModule`,{value:!0}),e),d={};o(d,{AccessTokenMissingError:()=>m.AccessTokenMissingError,RefreshAccessTokenFailedError:()=>m.RefreshAccessTokenFailedError,getContext:()=>p.getContext,getVercelOidcToken:()=>f.getVercelOidcToken,getVercelOidcTokenSync:()=>f.getVercelOidcTokenSync,getVercelToken:()=>h.getVercelToken}),t.exports=l(d);var f=b(),p=y(),m=c(),h=u()})),S=x();const C=`${i}/`,w=new Set([`localhost`,`127.0.0.1`,`0.0.0.0`,`::1`,`[::1]`]);function T(e){return w.has(e.hostname)}const E=`x-vercel-protection-bypass`,D=`x-vercel-trusted-oidc-idp-token`;function O(e){return e.pathname.endsWith(`/ash/v1`)||e.pathname.includes(C)}async function k(e){let t=A(e),n=await M(t,e.resourceUrl);return n!==null&&j(t,n),t}function A(e){let t=new Headers(F(e.headers)),n=process.env.VERCEL_AUTOMATION_BYPASS_SECRET?.trim();return n&&O(e.resourceUrl)&&t.set(E,n),t}function j(e,t){e.has(`authorization`)||e.set(`authorization`,`Bearer ${t}`),e.set(D,t)}async function M(e,t){return N(t)?e.get(`x-vercel-oidc-token`)?.trim()||await P():null}function N(e){return!(!O(e)||T(e))}async function P(){let e=process.env.VERCEL_OIDC_TOKEN?.trim();try{let e=(await(0,S.getVercelOidcToken)()).trim();if(e.length>0)return e}catch{return e??null}return e??null}function F(e){if(e!==void 0)return e instanceof Headers?e:Array.isArray(e)?e.map(([e,t])=>[e,t]):e}function I(){return{streamIndex:0}}function L(e){let t=B(e.events),n=e.session.streamIndex+e.events.length;return t?.type===`session.waiting`?{continuationToken:e.continuationToken??e.session.continuationToken,sessionId:e.sessionId,streamIndex:n}:I()}function R(e){let t;for(let n of e)V(n)&&(t=n.data.message??void 0);return t}function z(e){let t=B(e);return t?.type===`session.waiting`?`waiting`:t?.type===`session.failed`?`failed`:`completed`}function B(e){for(let t=e.length-1;t>=0;t--){let n=e[t];if(n!==void 0&&a(n))return n}}function V(e){return e.type===`message.completed`&&e.data.finishReason!==`tool-calls`}var H=class{continuationToken;sessionId;#e=!1;#t;constructor(e){this.continuationToken=e.continuationToken,this.sessionId=e.sessionId,this.#t=e.createStream}async result(){let e=[];for await(let t of this)e.push(t);return{events:e,message:R(e),sessionId:this.sessionId,status:z(e)}}[Symbol.asyncIterator](){if(this.#e)throw Error(`MessageResponse has already been consumed.`);return this.#e=!0,this.#t()}},U=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}get state(){return this.#t}async sendMessage(e,t){return this.send({message:e},t)}async send(e,t){let n=this.#t,{continuationToken:r,sessionId:i}=await this.#n(e,n,t);return new H({continuationToken:r,createStream:()=>this.#r(i,r,n,t),sessionId:i})}openStream(e){let t=this.#t.sessionId;if(!t)throw Error(`Session has no session ID. Send a message first.`);return v({host:this.#e.host,maxReconnectAttempts:this.#e.maxReconnectAttempts,resolveHeaders:()=>this.#e.resolveHeaders(),sessionId:t,signal:e?.signal,startIndex:e?.startIndex??this.#t.streamIndex})}async#n(e,t,i){let a=t.sessionId?n(t.sessionId):r,o=m(this.#e.host,a),s=await this.#e.resolveHeaders(i?.headers);s.set(`content-type`,`application/json`);let c=W({input:e,session:t});if(c===null)throw Error(`Session.send requires a non-empty message, inputResponses, or both.`);let l=await fetch(o,{body:JSON.stringify(c),headers:s,method:`POST`,signal:i?.signal??null});if(!l.ok){let e=await l.text();throw new d(l.status,e)}let u=await l.json(),f=(typeof u.sessionId==`string`?u.sessionId:void 0)??l.headers.get(`x-ash-session-id`)?.trim()??t.sessionId;if(!f)throw Error(`Message route did not return a session id.`);return{continuationToken:typeof u.continuationToken==`string`?u.continuationToken:void 0,sessionId:f}}async*#r(e,t,n,r){let i=[];try{let t=n.sessionId===e?n.streamIndex:0,o=this.#e.maxReconnectAttempts;for(;;){let n=await this.#i(e,t,r?.signal),s=!1;try{for await(let e of p(n))if(i.push(e),t+=1,yield e,a(e)){s=!0;break}}catch(e){if(!f(e))throw e}if(s||o<=0)break;--o}}finally{this.#t=L({continuationToken:t,events:i,sessionId:e,session:n})}}async#i(e,t,n){let r=m(this.#e.host,s(e),t>0?{startIndex:String(t)}:void 0),i=await this.#e.resolveHeaders(),a=await fetch(r,{headers:i,signal:n??null});if(!a.ok){let e=await a.text();throw new d(a.status,e)}if(!a.body)throw new d(a.status,`Response body is null.`);return a.body}};function W(e){let t={};return e.input.message!==void 0&&(t.message=e.input.message),e.input.inputResponses!==void 0&&e.input.inputResponses.length>0&&(t.inputResponses=e.input.inputResponses),e.input.clientContext!==void 0&&(t.clientContext=e.input.clientContext),e.session.continuationToken!==void 0&&(t.continuationToken=e.session.continuationToken),Object.keys(t).length===0||e.session.continuationToken===void 0&&t.message===void 0||e.session.continuationToken!==void 0&&t.message===void 0&&t.inputResponses===void 0||`continuationToken`in t&&Object.keys(t).length===1?null:t}var G=class{#e;#t;#n;#r;constructor(e){this.#n=e.host,this.#e=e.auth,this.#t=e.headers,this.#r=e.maxReconnectAttempts??3}async health(){let e=m(this.#n,o),t=await this.#i(),n=await fetch(e,{headers:t});if(!n.ok){let e=await n.text();throw new d(n.status,e)}return await n.json()}session(e){let t;return t=typeof e==`string`?{continuationToken:e,streamIndex:0}:e||I(),new U({host:this.#n,maxReconnectAttempts:this.#r,resolveHeaders:e=>this.#i(e)},t)}async#i(e){let t=new Headers,n=await q(this.#t);for(let[e,r]of Object.entries(n))t.set(e,r);if(e)for(let[n,r]of Object.entries(e))t.set(n,r);let r=await this.#a();return r&&t.set(`authorization`,r),t}async#a(){let e=this.#e;if(e){if(`bearer`in e){let t=(await K(e.bearer)).trim();return t.length===0?void 0:`Bearer ${t}`}if(`basic`in e){let t=await K(e.basic.password);return`Basic ${J(e.basic.username,t)}`}}}};async function K(e){return typeof e==`function`?e():e}async function q(e){return e===void 0?{}:typeof e==`function`?await e():e}function J(e,t){let n=new TextEncoder().encode(`${e}:${t}`),r=Array.from(n,e=>String.fromCodePoint(e)).join(``);return btoa(r)}export{x as a,k as i,E as n,v as o,D as r,d as s,G as t};