experimental-ash 0.2.0-alpha.21 → 0.2.0-alpha.23

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 (199) hide show
  1. package/dist/src/channel/slack-channel.d.ts +14 -7
  2. package/dist/src/channel/slack-channel.d.ts.map +1 -1
  3. package/dist/src/channel/slack-channel.js +21 -11
  4. package/dist/src/channel/slack-channel.js.map +1 -1
  5. package/dist/src/channel/types.d.ts +14 -14
  6. package/dist/src/channel/types.d.ts.map +1 -1
  7. package/dist/src/channel/types.js +6 -0
  8. package/dist/src/channel/types.js.map +1 -1
  9. package/dist/src/context/accessors.d.ts +24 -10
  10. package/dist/src/context/accessors.d.ts.map +1 -1
  11. package/dist/src/context/accessors.js +34 -16
  12. package/dist/src/context/accessors.js.map +1 -1
  13. package/dist/src/context/container.d.ts +43 -20
  14. package/dist/src/context/container.d.ts.map +1 -1
  15. package/dist/src/context/container.js +54 -22
  16. package/dist/src/context/container.js.map +1 -1
  17. package/dist/src/context/key.d.ts +68 -39
  18. package/dist/src/context/key.d.ts.map +1 -1
  19. package/dist/src/context/key.js +49 -62
  20. package/dist/src/context/key.js.map +1 -1
  21. package/dist/src/context/keys.d.ts +6 -6
  22. package/dist/src/context/keys.d.ts.map +1 -1
  23. package/dist/src/context/keys.js +7 -9
  24. package/dist/src/context/keys.js.map +1 -1
  25. package/dist/src/context/node.d.ts +2 -2
  26. package/dist/src/context/node.d.ts.map +1 -1
  27. package/dist/src/context/node.js +1 -1
  28. package/dist/src/context/node.js.map +1 -1
  29. package/dist/src/context/provider.d.ts +24 -11
  30. package/dist/src/context/provider.d.ts.map +1 -1
  31. package/dist/src/context/providers/connection.d.ts +2 -2
  32. package/dist/src/context/providers/connection.d.ts.map +1 -1
  33. package/dist/src/context/providers/connection.js +1 -1
  34. package/dist/src/context/providers/connection.js.map +1 -1
  35. package/dist/src/context/providers/sandbox.d.ts +2 -2
  36. package/dist/src/context/providers/sandbox.d.ts.map +1 -1
  37. package/dist/src/context/providers/sandbox.js +2 -2
  38. package/dist/src/context/providers/sandbox.js.map +1 -1
  39. package/dist/src/context/providers/session.d.ts +2 -2
  40. package/dist/src/context/providers/session.d.ts.map +1 -1
  41. package/dist/src/context/providers/session.js +4 -4
  42. package/dist/src/context/providers/session.js.map +1 -1
  43. package/dist/src/context/providers/skill.d.ts +2 -2
  44. package/dist/src/context/providers/skill.d.ts.map +1 -1
  45. package/dist/src/context/providers/skill.js +2 -2
  46. package/dist/src/context/providers/skill.js.map +1 -1
  47. package/dist/src/context/run-step.d.ts +9 -8
  48. package/dist/src/context/run-step.d.ts.map +1 -1
  49. package/dist/src/context/run-step.js +32 -22
  50. package/dist/src/context/run-step.js.map +1 -1
  51. package/dist/src/context/seed-keys.d.ts +7 -7
  52. package/dist/src/context/seed-keys.d.ts.map +1 -1
  53. package/dist/src/context/seed-keys.js +7 -19
  54. package/dist/src/context/seed-keys.js.map +1 -1
  55. package/dist/src/context/serialize.d.ts +10 -9
  56. package/dist/src/context/serialize.d.ts.map +1 -1
  57. package/dist/src/context/serialize.js +18 -30
  58. package/dist/src/context/serialize.js.map +1 -1
  59. package/dist/src/execution/continuous-entry.d.ts +8 -6
  60. package/dist/src/execution/continuous-entry.d.ts.map +1 -1
  61. package/dist/src/execution/continuous-entry.js +27 -25
  62. package/dist/src/execution/continuous-entry.js.map +1 -1
  63. package/dist/src/execution/continuous-runtime.d.ts.map +1 -1
  64. package/dist/src/execution/continuous-runtime.js +1 -4
  65. package/dist/src/execution/continuous-runtime.js.map +1 -1
  66. package/dist/src/execution/node-step.js +1 -0
  67. package/dist/src/execution/node-step.js.map +1 -1
  68. package/dist/src/execution/runtime-context.d.ts +3 -3
  69. package/dist/src/execution/runtime-context.d.ts.map +1 -1
  70. package/dist/src/execution/runtime-context.js +3 -3
  71. package/dist/src/execution/runtime-context.js.map +1 -1
  72. package/dist/src/execution/sandboxes/read-file-tool.js +2 -2
  73. package/dist/src/execution/sandboxes/read-file-tool.js.map +1 -1
  74. package/dist/src/execution/sandboxes/require-sandbox.js +2 -2
  75. package/dist/src/execution/sandboxes/require-sandbox.js.map +1 -1
  76. package/dist/src/execution/sandboxes/write-file-tool.d.ts.map +1 -1
  77. package/dist/src/execution/sandboxes/write-file-tool.js +3 -3
  78. package/dist/src/execution/sandboxes/write-file-tool.js.map +1 -1
  79. package/dist/src/execution/subagent-tool.js +6 -6
  80. package/dist/src/execution/subagent-tool.js.map +1 -1
  81. package/dist/src/execution/tool-compaction.d.ts +3 -1
  82. package/dist/src/execution/tool-compaction.d.ts.map +1 -1
  83. package/dist/src/execution/tool-compaction.js +19 -8
  84. package/dist/src/execution/tool-compaction.js.map +1 -1
  85. package/dist/src/execution/types.d.ts +1 -0
  86. package/dist/src/execution/types.d.ts.map +1 -1
  87. package/dist/src/execution/workflow-entry.d.ts +5 -4
  88. package/dist/src/execution/workflow-entry.d.ts.map +1 -1
  89. package/dist/src/execution/workflow-entry.js +8 -3
  90. package/dist/src/execution/workflow-entry.js.map +1 -1
  91. package/dist/src/execution/workflow-runtime.d.ts.map +1 -1
  92. package/dist/src/execution/workflow-runtime.js +2 -3
  93. package/dist/src/execution/workflow-runtime.js.map +1 -1
  94. package/dist/src/execution/workflow-steps.d.ts +2 -2
  95. package/dist/src/execution/workflow-steps.d.ts.map +1 -1
  96. package/dist/src/execution/workflow-steps.js +42 -17
  97. package/dist/src/execution/workflow-steps.js.map +1 -1
  98. package/dist/src/harness/emission.d.ts +1 -1
  99. package/dist/src/harness/emission.js +3 -3
  100. package/dist/src/harness/emission.js.map +1 -1
  101. package/dist/src/harness/execute-tool.d.ts +1 -0
  102. package/dist/src/harness/execute-tool.d.ts.map +1 -1
  103. package/dist/src/harness/execute-tool.js.map +1 -1
  104. package/dist/src/harness/input-requests.d.ts +2 -22
  105. package/dist/src/harness/input-requests.d.ts.map +1 -1
  106. package/dist/src/harness/input-requests.js +47 -41
  107. package/dist/src/harness/input-requests.js.map +1 -1
  108. package/dist/src/harness/tool-loop.d.ts.map +1 -1
  109. package/dist/src/harness/tool-loop.js +19 -1
  110. package/dist/src/harness/tool-loop.js.map +1 -1
  111. package/dist/src/harness/tools.js +5 -1
  112. package/dist/src/harness/tools.js.map +1 -1
  113. package/dist/src/harness/types.d.ts +3 -15
  114. package/dist/src/harness/types.d.ts.map +1 -1
  115. package/dist/src/harness/types.js +1 -6
  116. package/dist/src/harness/types.js.map +1 -1
  117. package/dist/src/internal/application/package.js +1 -1
  118. package/dist/src/internal/authored-definition/connection.d.ts.map +1 -1
  119. package/dist/src/internal/authored-definition/connection.js +14 -1
  120. package/dist/src/internal/authored-definition/connection.js.map +1 -1
  121. package/dist/src/internal/nitro/routes/runtime-stack.d.ts +3 -3
  122. package/dist/src/internal/nitro/routes/runtime-stack.js +3 -3
  123. package/dist/src/public/channels/slack/index.d.ts +0 -5
  124. package/dist/src/public/channels/slack/index.d.ts.map +1 -1
  125. package/dist/src/public/channels/slack/index.js.map +1 -1
  126. package/dist/src/public/context/index.d.ts +17 -0
  127. package/dist/src/public/context/index.d.ts.map +1 -0
  128. package/dist/src/public/context/index.js +15 -0
  129. package/dist/src/public/context/index.js.map +1 -0
  130. package/dist/src/public/definitions/connections/mcp.d.ts +13 -0
  131. package/dist/src/public/definitions/connections/mcp.d.ts.map +1 -1
  132. package/dist/src/public/definitions/connections/mcp.js.map +1 -1
  133. package/dist/src/public/definitions/tool.d.ts +10 -6
  134. package/dist/src/public/definitions/tool.d.ts.map +1 -1
  135. package/dist/src/public/definitions/tool.js.map +1 -1
  136. package/dist/src/public/index.d.ts +1 -6
  137. package/dist/src/public/index.d.ts.map +1 -1
  138. package/dist/src/public/index.js +0 -3
  139. package/dist/src/public/index.js.map +1 -1
  140. package/dist/src/public/sandboxes/index.d.ts +1 -0
  141. package/dist/src/public/sandboxes/index.d.ts.map +1 -1
  142. package/dist/src/public/sandboxes/index.js +1 -0
  143. package/dist/src/public/sandboxes/index.js.map +1 -1
  144. package/dist/src/public/skills/index.d.ts +24 -0
  145. package/dist/src/public/skills/index.d.ts.map +1 -0
  146. package/dist/src/public/skills/index.js +23 -0
  147. package/dist/src/public/skills/index.js.map +1 -0
  148. package/dist/src/public/tools/defaults.d.ts +4 -4
  149. package/dist/src/public/tools/defaults.js +4 -4
  150. package/dist/src/runtime/connections/registry.d.ts +6 -0
  151. package/dist/src/runtime/connections/registry.d.ts.map +1 -1
  152. package/dist/src/runtime/connections/registry.js +8 -0
  153. package/dist/src/runtime/connections/registry.js.map +1 -1
  154. package/dist/src/runtime/connections/types.d.ts +2 -0
  155. package/dist/src/runtime/connections/types.d.ts.map +1 -1
  156. package/dist/src/runtime/framework-tools/connection-execute.d.ts.map +1 -1
  157. package/dist/src/runtime/framework-tools/connection-execute.js +17 -6
  158. package/dist/src/runtime/framework-tools/connection-execute.js.map +1 -1
  159. package/dist/src/runtime/framework-tools/connection-search.d.ts +2 -2
  160. package/dist/src/runtime/framework-tools/connection-search.d.ts.map +1 -1
  161. package/dist/src/runtime/framework-tools/connection-search.js +4 -4
  162. package/dist/src/runtime/framework-tools/connection-search.js.map +1 -1
  163. package/dist/src/runtime/framework-tools/file-state.d.ts +5 -7
  164. package/dist/src/runtime/framework-tools/file-state.d.ts.map +1 -1
  165. package/dist/src/runtime/framework-tools/file-state.js +4 -6
  166. package/dist/src/runtime/framework-tools/file-state.js.map +1 -1
  167. package/dist/src/runtime/framework-tools/skill.js +3 -3
  168. package/dist/src/runtime/framework-tools/skill.js.map +1 -1
  169. package/dist/src/runtime/framework-tools/todo.js +3 -3
  170. package/dist/src/runtime/framework-tools/todo.js.map +1 -1
  171. package/dist/src/runtime/prompt/connections.d.ts.map +1 -1
  172. package/dist/src/runtime/prompt/connections.js +3 -2
  173. package/dist/src/runtime/prompt/connections.js.map +1 -1
  174. package/dist/src/runtime/resolve-agent-graph.js +3 -2
  175. package/dist/src/runtime/resolve-agent-graph.js.map +1 -1
  176. package/dist/src/runtime/resolve-connection.d.ts.map +1 -1
  177. package/dist/src/runtime/resolve-connection.js +3 -0
  178. package/dist/src/runtime/resolve-connection.js.map +1 -1
  179. package/dist/src/runtime/sessions/auth.d.ts +1 -1
  180. package/dist/src/runtime/types.d.ts +13 -0
  181. package/dist/src/runtime/types.d.ts.map +1 -1
  182. package/docs/internals/context.md +257 -81
  183. package/docs/public/README.md +17 -19
  184. package/docs/public/channels/README.md +9 -3
  185. package/docs/public/sandboxes.md +1 -1
  186. package/docs/public/session-context.md +97 -51
  187. package/docs/public/skills.md +2 -2
  188. package/docs/public/tools.md +26 -18
  189. package/docs/public/typescript-api.md +34 -29
  190. package/package.json +11 -1
  191. package/dist/src/context/durable-context.d.ts +0 -18
  192. package/dist/src/context/durable-context.d.ts.map +0 -1
  193. package/dist/src/context/durable-context.js +0 -49
  194. package/dist/src/context/durable-context.js.map +0 -1
  195. package/dist/src/execution/step-context.d.ts +0 -27
  196. package/dist/src/execution/step-context.d.ts.map +0 -1
  197. package/dist/src/execution/step-context.js +0 -54
  198. package/dist/src/execution/step-context.js.map +0 -1
  199. package/docs/public/migration-guide.md +0 -71
@@ -1,13 +1,15 @@
1
1
  # Session Context
2
2
 
3
- Ash exposes six runtime helpers for authored code:
3
+ Ash exposes runtime helpers for authored code:
4
4
 
5
5
  - `getSession()`
6
- - `getContext(key)`
7
- - `setContext(key, value)`
8
- - `ensureContext(key, valueOrFactory)`
9
6
  - `getSandbox(name)`
10
7
  - `getSkill(identifier)`
8
+ - `getContext(key)` — returns `T | undefined`
9
+ - `requireContext(key)` — returns `T`, throws if unset
10
+ - `hasContext(key)` — returns `boolean`
11
+ - `setContext(key, valueOrUpdater)` — returns `T`
12
+ - `ensureContext(key, factory)` — returns `T`
11
13
 
12
14
  These APIs work only inside active authored runtime execution such as tools and other Ash-invoked
13
15
  callbacks. Under the hood, they read from a single `AshContext` container that the framework binds
@@ -20,7 +22,7 @@ Use `getSession()` when you need durable runtime metadata about the current exec
20
22
  `agent/tools/who_called_me.ts`
21
23
 
22
24
  ```ts
23
- import { getSession } from "experimental-ash";
25
+ import { getSession } from "experimental-ash/context";
24
26
  import { defineTool } from "experimental-ash/tools";
25
27
 
26
28
  export default defineTool({
@@ -96,32 +98,11 @@ Important behavior:
96
98
 
97
99
  See [`skills.md`](./skills.md) for the full authoring model.
98
100
 
99
- ## Durable Authored Context
100
-
101
- `ContextKey` values are session-durable by default. Once authored code sets a key, Ash hydrates it
102
- from `session.context` before later steps and commits it back after each step.
103
-
104
- ```ts
105
- import { ContextKey, ensureContext, getContext, setContext } from "experimental-ash";
106
-
107
- const TenantKey = new ContextKey<string>("myapp.tenant");
108
- const NotesKey = new ContextKey<{ readonly notes: readonly string[] }>("myapp.notes");
109
-
110
- const tenant = getContext(TenantKey);
111
- const notes = ensureContext(NotesKey, () => ({ notes: [] }));
112
-
113
- setContext(NotesKey, {
114
- notes: [...notes.notes, `Handled tenant ${tenant}`],
115
- });
116
- ```
117
-
118
- Use `ensureContext` when a key needs a default value. `ContextKey({ initial })` no longer exists.
119
-
120
101
  ## Passing Custom Context From a Channel
121
102
 
122
- Channels can inject custom typed context into the agent inside `onDeliver`. This is useful when a
123
- channel needs to pass platform-specific metadata (tenant ID, feature flags, etc.) that authored
124
- tools can read.
103
+ Channels can inject custom typed durable context into the agent inside `onDeliver`. This is useful
104
+ when a channel needs to pass platform-specific metadata (tenant ID, feature flags, etc.) that
105
+ authored tools can read on the same turn and on later turns.
125
106
 
126
107
  ### Defining a key
127
108
 
@@ -131,7 +112,7 @@ read it.
131
112
  `agent/channels/keys.ts`
132
113
 
133
114
  ```ts
134
- import { ContextKey } from "experimental-ash";
115
+ import { ContextKey } from "experimental-ash/context";
135
116
 
136
117
  export const TenantKey = new ContextKey<string>("myapp.tenant");
137
118
  ```
@@ -139,9 +120,8 @@ export const TenantKey = new ContextKey<string>("myapp.tenant");
139
120
  ### Setting context from a channel
140
121
 
141
122
  Wrap an existing channel with `onDeliver` to set custom context keys. The hook receives a narrow
142
- `ContextAccessor` (`get`, `tryGet`, `has`, `set`, `ensure`) as its first argument and a
143
- `DeliverPayload` as the second. It runs on both `run()` and `deliver()`, after Ash has hydrated the
144
- durable context bag for that turn.
123
+ `ContextAccessor` (typed `get`/`set`) as its first argument and a `DeliverPayload` as the second. It
124
+ runs on both `run()` and `deliver()`.
145
125
 
146
126
  `agent/channels/slack.ts`
147
127
 
@@ -167,8 +147,8 @@ class TenantSlackChannel extends SlackChannel<TenantSlackState> {
167
147
  });
168
148
  }
169
149
 
170
- async onDeliver(ctx, payload) {
171
- ctx.set(TenantKey, this.state().tenantId);
150
+ override async onDeliver(ctx, payload) {
151
+ ctx.set(TenantKey, this.state.tenantId);
172
152
  return await super.onDeliver(ctx, payload);
173
153
  }
174
154
  }
@@ -181,30 +161,96 @@ export default slackRoute({
181
161
  Auth lives on `RunInput.auth` and `DeliverInput.auth`, not on the channel object. There is no
182
162
  `withAuth` or `withContext` wrapper.
183
163
 
184
- Keep channel constructor state immutable after the run starts. Stable transport identity belongs in
185
- serialized channel state; mutable per-session data belongs in durable context or `session.internal`.
186
-
187
164
  ### Reading context from a tool
188
165
 
189
166
  ```ts
190
- import { getContext } from "experimental-ash";
167
+ import { requireContext } from "experimental-ash/context";
191
168
  import { defineTool } from "experimental-ash/tools";
192
169
  import { TenantKey } from "../channels/keys.js";
193
170
 
194
171
  export default defineTool({
195
172
  description: "Return the active tenant.",
196
173
  async execute() {
197
- const tenant = getContext(TenantKey);
174
+ const tenant = requireContext(TenantKey);
198
175
  return { tenant };
199
176
  },
200
177
  });
201
178
  ```
202
179
 
180
+ ### Rebuilding virtual values with `ContextProvider`
181
+
182
+ If a channel needs to vend a live non-serializable object each step, declare a static
183
+ `contextProviders` array on the channel class. This must be a class field such as
184
+ `static readonly contextProviders = [...]`; the runtime reads providers from the channel class, not
185
+ from the channel instance.
186
+
187
+ For Slack subclasses, the intended pattern is:
188
+
189
+ - `onDeliver()` writes durable serializable facts such as tenant IDs, channel IDs, or installation
190
+ IDs.
191
+ - `static readonly contextProviders = [...]` derives live step-local values such as SDK clients
192
+ from those durable keys.
193
+ - tools and other authored step code read the derived value with `requireContext(...)` or
194
+ `getContext(...)`.
195
+
196
+ Providers run after `onDeliver()` and rebuild virtual values for the current step only, so
197
+ `onDeliver()` should not expect provider output to exist yet.
198
+
199
+ ```ts
200
+ import {
201
+ ContextKey,
202
+ type ContextProvider,
203
+ } from "experimental-ash/context";
204
+ import {
205
+ slackRoute,
206
+ SlackChannel,
207
+ type SlackChannelState,
208
+ } from "experimental-ash/channels/slack";
209
+
210
+ const TenantKey = new ContextKey<string>("myapp.tenant");
211
+ const SlackClientKey = new ContextKey<{ readonly tenantId: string }>("myapp.slackClient");
212
+
213
+ const slackClientProvider: ContextProvider<{ readonly tenantId: string }> = {
214
+ key: SlackClientKey,
215
+ create(ctx) {
216
+ return { tenantId: ctx.require(TenantKey) };
217
+ },
218
+ };
219
+
220
+ interface TenantSlackState extends SlackChannelState {
221
+ readonly tenantId: string;
222
+ }
223
+
224
+ class TenantSlackChannel extends SlackChannel<TenantSlackState> {
225
+ static override readonly kind = "tenant-slack";
226
+ static readonly contextProviders = [slackClientProvider];
227
+
228
+ constructor(state: SlackChannelState) {
229
+ super({
230
+ ...state,
231
+ tenantId: lookupTenant(state),
232
+ });
233
+ }
234
+
235
+ override async onDeliver(ctx, payload) {
236
+ ctx.set(TenantKey, this.state.tenantId);
237
+ return await super.onDeliver(ctx, payload);
238
+ }
239
+ }
240
+
241
+ export default slackRoute({
242
+ channel: TenantSlackChannel,
243
+ });
244
+ ```
245
+
246
+ Provider output is readable through `requireContext(SlackClientKey)` or
247
+ `getContext(SlackClientKey)` during that step, but it is not serialized.
248
+
203
249
  ### Context on deliver
204
250
 
205
251
  `onDeliver` runs on every turn, including `deliver()` follow-ups. The channel is deserialized from
206
- the session, so its stable serialized state (including custom fields like `tenantId`) is available
207
- on follow-up turns.
252
+ the session, so its state (including any custom fields like `tenantId`) is available on follow-up
253
+ turns.
208
254
 
209
255
  Auth on `deliver()` is also honored — `session.auth.current` reflects the caller of each follow-up
210
256
  message, not just the session initiator. Deliver-time auth is passed via `DeliverInput.auth` and the
@@ -229,18 +275,18 @@ explaining the required scope.
229
275
 
230
276
  ## How It Works
231
277
 
232
- All runtime helpers read from the same `AshContext` container bound by a single
233
- `AsyncLocalStorage`. The framework sets up this context before invoking authored code:
278
+ All three accessors read from the same `AshContext` container bound by a single `AsyncLocalStorage`.
279
+ The framework sets up this context before invoking authored code:
234
280
 
235
- 1. The runtime entry point creates an `AshContext` and serializes only runtime seed keys such as
236
- auth, session id, channel, and compiled bundle.
237
- 2. Before each step, Ash rebuilds a fresh context, hydrates durable authored context from
238
- `session.context`, seeds runtime-only bookkeeping, and runs `channel.onDeliver(...)`.
239
- 3. Providers create derived values such as session metadata, sandbox access, and skill access.
281
+ 1. The runtime entry point creates an `AshContext` and populates durable seed keys (auth, session
282
+ ID, channel, compiled bundle).
283
+ 2. `onDeliver()` can write durable authored context for the turn.
284
+ 3. Before each step, providers create virtual step-local values (session metadata, sandbox access,
285
+ skill access, channel-scoped live objects) from the current context.
240
286
  4. The step callback runs inside the `AsyncLocalStorage` scope, making the context available to
241
287
  all authored code in the call chain.
242
- 5. After the step, Ash commits the full durable context bag back to `session.context` and lets
243
- mutable providers persist any provider-owned state.
288
+ 5. After the step, framework providers with provider-owned mutable state (for example sandboxes)
289
+ commit those changes back onto the harness session.
244
290
 
245
291
  This lifecycle is fully managed by the framework. Authored code only needs to call the public
246
292
  accessors.
@@ -78,7 +78,7 @@ Packaged skills are useful when you want files like:
78
78
  Inside authored runtime code, you can read those packaged files through `getSkill(identifier)`.
79
79
 
80
80
  ```ts
81
- import { getSkill } from "experimental-ash";
81
+ import { getSkill } from "experimental-ash/skills";
82
82
  import { defineTool } from "experimental-ash/tools";
83
83
 
84
84
  export default defineTool({
@@ -138,7 +138,7 @@ Do not use a skill for:
138
138
  If markdown is not enough, you can author a skill in TypeScript with `defineSkill(...)`.
139
139
 
140
140
  ```ts
141
- import { defineSkill } from "experimental-ash";
141
+ import { defineSkill } from "experimental-ash/skills";
142
142
 
143
143
  export default defineSkill({
144
144
  name: "research",
@@ -10,7 +10,7 @@ back.
10
10
  `agent/tools/get_weather.ts`
11
11
 
12
12
  ```ts
13
- import { getSession } from "experimental-ash";
13
+ import { getSession } from "experimental-ash/context";
14
14
  import { defineTool } from "experimental-ash/tools";
15
15
  import { z } from "zod";
16
16
 
@@ -36,8 +36,8 @@ exposed to the model as `get_weather`; a file at `agent/tools/get-weather.ts` is
36
36
  `get-weather`. You can override that by setting `name` in the tool definition.
37
37
 
38
38
  `defineTool`, `disableTool`, `defineBashTool`, `defineReadFileTool`, and `defineWriteFileTool` live on the `experimental-ash/tools` subpath.
39
- Runtime helpers like `getSession`, `getContext`, `setContext`, `ensureContext`, `getSandbox`, and
40
- `getSkill` stay on the main `experimental-ash` barrel.
39
+ Runtime context helpers (`getSession`, `getContext`, `requireContext`, `hasContext`, `setContext`, `ensureContext`) live on `experimental-ash/context`.
40
+ `getSandbox` lives on `experimental-ash/sandboxes` and `getSkill` lives on `experimental-ash/skills`.
41
41
 
42
42
  ## What A Tool Definition Needs
43
43
 
@@ -106,8 +106,8 @@ execution surface by itself; executable behavior still comes from the tools the
106
106
 
107
107
  `read_file` reads a text file from the sandbox filesystem with line-numbered output. `write_file`
108
108
  writes a complete file, enforcing read-before-write for existing files and detecting stale reads.
109
- Both target the framework default sandbox. Compaction clears the durable read-file context so the
110
- model must re-read files before overwriting after compaction.
109
+ Both target the framework default sandbox. Compaction clears the durable read-file state so the model
110
+ must re-read files before overwriting after compaction.
111
111
 
112
112
  Authors can wrap, replace, or disable these defaults from `agent/tools/`.
113
113
 
@@ -225,23 +225,29 @@ export default defineWriteFileTool({
225
225
  ```
226
226
 
227
227
  When replacing the framework `read_file`, the authored version inherits the same compaction
228
- context-reset behavior by default. Provide an explicit `onCompact` to override that.
228
+ state-reset behavior by default. Provide an explicit `onCompact` to override that.
229
229
 
230
230
  ### Replace A Default With Custom Context
231
231
 
232
- `agent/tools/todo.ts` - replace the framework `todo` tool with a custom durable-context version.
233
- Declare your own `ContextKey` and use `ensureContext` / `setContext` to read and write it:
232
+ `agent/tools/todo.ts` - replace the framework `todo` tool with a custom durable context-backed
233
+ version. Declare your own `ContextKey`, initialize it with `ensureContext`, and read/write it with
234
+ `requireContext` / `setContext`:
234
235
 
235
236
  ```ts
236
- import { ContextKey, ensureContext, setContext } from "experimental-ash";
237
+ import {
238
+ ContextKey,
239
+ ensureContext,
240
+ requireContext,
241
+ setContext,
242
+ } from "experimental-ash/context";
237
243
  import { defineTool } from "experimental-ash/tools";
238
244
  import { z } from "zod";
239
245
 
240
- interface NoteListContext {
246
+ interface NoteListState {
241
247
  readonly notes: readonly string[];
242
248
  }
243
249
 
244
- const NoteListContextKey = new ContextKey<NoteListContext>("myapp.notes");
250
+ const NoteListStateKey = new ContextKey<NoteListState>("myapp.notes");
245
251
 
246
252
  export default defineTool({
247
253
  description: "Append a note or read the running list of notes.",
@@ -249,13 +255,15 @@ export default defineTool({
249
255
  note: z.string().optional(),
250
256
  }),
251
257
  async execute(input) {
258
+ ensureContext(NoteListStateKey, () => ({ notes: [] }));
259
+
252
260
  if (typeof input.note === "string" && input.note.length > 0) {
253
- const current = ensureContext(NoteListContextKey, () => ({ notes: [] }));
254
- setContext(NoteListContextKey, {
255
- notes: [...current.notes, input.note],
256
- });
261
+ const next = input.note;
262
+ setContext(NoteListStateKey, (current) => ({
263
+ notes: [...(current?.notes ?? []), next],
264
+ }));
257
265
  }
258
- return ensureContext(NoteListContextKey, () => ({ notes: [] }));
266
+ return requireContext(NoteListStateKey);
259
267
  },
260
268
  });
261
269
  ```
@@ -263,8 +271,8 @@ export default defineTool({
263
271
  ### Subtleties Worth Knowing
264
272
 
265
273
  - The filename is the default name. There is also an explicit `name` property when you need it.
266
- - Durable context is owned by the replacement. Replacing `todo` with a fresh `defineTool` does not
267
- inherit the framework's context key.
274
+ - Context is owned by the replacement. Replacing `todo` with a fresh `defineTool` does not inherit
275
+ the framework's durable context key.
268
276
  - Authored-vs-authored collisions are impossible by construction. Two files cannot share a slug under
269
277
  the same `agent/tools/` directory.
270
278
 
@@ -5,6 +5,8 @@ This page is the quick reference for Ash's public TypeScript surface.
5
5
  Source of truth:
6
6
 
7
7
  - main barrel: [`../../packages/ash/src/public/index.ts`](../../packages/ash/src/public/index.ts)
8
+ - context subpath: [`../../packages/ash/src/public/context/index.ts`](../../packages/ash/src/public/context/index.ts)
9
+ - skills subpath: [`../../packages/ash/src/public/skills/index.ts`](../../packages/ash/src/public/skills/index.ts)
8
10
  - tools subpath: [`../../packages/ash/src/public/tools/index.ts`](../../packages/ash/src/public/tools/index.ts)
9
11
  - sandboxes subpath: [`../../packages/ash/src/public/sandboxes/index.ts`](../../packages/ash/src/public/sandboxes/index.ts)
10
12
  - channel subpaths: [`../../packages/ash/src/public/channels/index.ts`](../../packages/ash/src/public/channels/index.ts)
@@ -12,24 +14,25 @@ Source of truth:
12
14
 
13
15
  ## Definition Helpers
14
16
 
15
- Use these to author the filesystem-backed surface. Tool authoring helpers live on
16
- `experimental-ash/tools`; sandbox helpers live on `experimental-ash/sandboxes`; everything else is
17
- on the main `experimental-ash` barrel.
17
+ Use these to author the filesystem-backed surface. Each concern has its own subpath:
18
+ `experimental-ash/tools` for tools, `experimental-ash/sandboxes` for sandboxes,
19
+ `experimental-ash/skills` for skills, `experimental-ash/context` for context helpers,
20
+ and the main `experimental-ash` barrel for agent config, routes, schedules, and systems.
18
21
 
19
22
  - `defineAgent(...)` - additive runtime config for `agent.ts`
20
23
  - `defineRoute(...)` - messaging-platform or HTTP route entrypoints in `channels/`
21
- - `defineSandbox(...)` - isolated bash-style environments in `sandboxes/`
24
+ - `defineSandbox(...)` - isolated bash-style environments in `sandboxes/` (`experimental-ash/sandboxes`)
22
25
  - `defineSchedule(...)` - recurring jobs in `schedules/`
23
- - `defineSkill(...)` - module-authored skills
26
+ - `defineSkill(...)` - module-authored skills (`experimental-ash/skills`)
24
27
  - `defineSubagent(...)` - local subagent entrypoint in `subagents/<id>/subagent.ts`
25
28
  - `defineSystem(...)` - module-authored system prompt
26
- - `defineTool(...)` - typed executable integration in `tools/<name>.ts`
27
- - `defineBashTool(...)` - model-visible shell tool targeting a named sandbox
28
- - `defineReadFileTool(...)` - model-visible file reader targeting a named sandbox
29
- - `defineWriteFileTool(...)` - model-visible file writer targeting a named sandbox
30
- - `disableTool()` - disable the framework default whose name matches `tools/<name>.ts`
29
+ - `defineTool(...)` - typed executable integration in `tools/<name>.ts` (`experimental-ash/tools`)
30
+ - `defineBashTool(...)` - model-visible shell tool targeting a named sandbox (`experimental-ash/tools`)
31
+ - `defineReadFileTool(...)` - model-visible file reader targeting a named sandbox (`experimental-ash/tools`)
32
+ - `defineWriteFileTool(...)` - model-visible file writer targeting a named sandbox (`experimental-ash/tools`)
33
+ - `disableTool()` - disable the framework default whose name matches `tools/<name>.ts` (`experimental-ash/tools`)
31
34
  - `disableRoute()` - disable a framework-owned route that matches the file path
32
- - `defineEvalSuite(...)` - repeatable eval suite under `evals/*.eval.ts`
35
+ - `defineEvalSuite(...)` - repeatable eval suite under `evals/*.eval.ts` (`experimental-ash/evals`)
33
36
 
34
37
  Framework defaults reachable for spread/wrap composition:
35
38
 
@@ -40,20 +43,19 @@ Most apps use `defineAgent`, `defineTool`, and `defineSandbox` the most.
40
43
 
41
44
  ## Runtime Helpers
42
45
 
43
- - `getSession()` - current session, turn, auth, and optional parent lineage
44
- - `getContext(key)` - read one durable authored context value
45
- - `setContext(key, value)` - write one durable authored context value
46
- - `ensureContext(key, valueOrFactory)` - read-or-create one durable context value
47
- - `getSandbox(name)` - live named sandbox session
48
- - `getSkill(identifier)` - handle for a named skill visible to the current agent
46
+ Each runtime accessor lives on the subpath that owns its concern:
49
47
 
50
- Related exported types:
48
+ - `getSession()` - current session, turn, auth, and optional parent lineage (`experimental-ash/context`)
49
+ - `getSandbox(name)` - live named sandbox session (`experimental-ash/sandboxes`)
50
+ - `getSkill(identifier)` - handle for a named skill visible to the current agent (`experimental-ash/skills`)
51
+ - `getContext(key)` / `requireContext(key)` / `hasContext(key)` / `setContext(key)` / `ensureContext(key, factory)` - unified context helpers (`experimental-ash/context`)
51
52
 
52
- - `Session`, `SessionAuth`, `SessionAuthContext`, `SessionParent`, `SessionTurn`
53
- - `SkillHandle`, `SkillResource`
54
- - `RunMode`
55
- - `ContextKey`, `ContextKeyOptions`, `AshContext`
56
- - eval types from `experimental-ash/evals`
53
+ Related exported types by subpath:
54
+
55
+ - `experimental-ash/context`: `Session`, `SessionAuth`, `SessionAuthContext`, `SessionParent`, `SessionTurn`, `ContextKey`, `ContextKeyOptions`, `ContextProvider`, `ContextReader`, `ContextAccessor`, `AshContext`
56
+ - `experimental-ash/skills`: `SkillHandle`, `SkillResource`, `SkillDefinition`
57
+ - `experimental-ash`: `RunMode`
58
+ - `experimental-ash/evals`: eval types
57
59
 
58
60
  Ash also exports lower-level runtime primitives such as `createToolLoopHarness(...)`,
59
61
  `createContinuousLoopRuntime(...)`, and `createWorkflowRuntime(...)`.
@@ -63,8 +65,6 @@ sessions must finish inside the current invocation.
63
65
 
64
66
  These helpers only work inside active authored runtime execution.
65
67
 
66
- Breaking change details and before/after examples live in [`migration-guide.md`](./migration-guide.md).
67
-
68
68
  ## Markdown Helpers
69
69
 
70
70
  Ash also exports helpers for turning markdown into the same shapes as module-authored definitions:
@@ -96,18 +96,24 @@ import { vercelOidc } from "experimental-ash/channels/auth";
96
96
  ### Typed Tool
97
97
 
98
98
  ```ts
99
- import { getSession } from "experimental-ash";
99
+ import { getSession } from "experimental-ash/context";
100
100
  import { defineTool } from "experimental-ash/tools";
101
101
  ```
102
102
 
103
103
  ### Sandbox Access
104
104
 
105
105
  ```ts
106
- import { getSandbox } from "experimental-ash";
106
+ import { getSandbox } from "experimental-ash/sandboxes";
107
107
  import { defineTool } from "experimental-ash/tools";
108
108
  import { defineBashTool } from "experimental-ash/tools";
109
109
  ```
110
110
 
111
+ ### Skill Access
112
+
113
+ ```ts
114
+ import { defineSkill, getSkill } from "experimental-ash/skills";
115
+ ```
116
+
111
117
  ### Wrapping Or Disabling A Framework Default
112
118
 
113
119
  ```ts
@@ -138,11 +144,10 @@ import { Braintrust } from "experimental-ash/evals/reporters";
138
144
  - `defineRoute` and route/channel factories -> [`channels/README.md`](./channels/README.md)
139
145
  - `defineTool`, `disableTool`, `defineBashTool`, `defineReadFileTool`, `defineWriteFileTool`, and `experimental-ash/tools/defaults` -> [`tools.md`](./tools.md)
140
146
  - `defineSandbox` and `getSandbox` -> [`sandboxes.md`](./sandboxes.md)
147
+ - `defineSkill` and `getSkill` -> [`skills.md`](./skills.md)
141
148
  - `getSession` -> [`session-context.md`](./session-context.md)
142
- - `getSkill` -> [`session-context.md`](./session-context.md)
143
149
  - `defineSubagent` -> [`subagents.md`](./subagents.md)
144
150
  - `defineSchedule` -> [`schedules.md`](./schedules.md)
145
- - `defineSkill` -> [`skills.md`](./skills.md)
146
151
  - `defineEvalSuite`, loaders, reporters, and scorers -> [`evals.md`](./evals.md)
147
152
 
148
153
  ## Practical Advice
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "experimental-ash",
3
- "version": "0.2.0-alpha.21",
3
+ "version": "0.2.0-alpha.23",
4
4
  "type": "module",
5
5
  "main": "./dist/src/index.js",
6
6
  "types": "./dist/src/index.d.ts",
@@ -82,6 +82,16 @@
82
82
  "import": "./dist/src/evals/scores/index.js",
83
83
  "default": "./dist/src/evals/scores/index.js"
84
84
  },
85
+ "./skills": {
86
+ "types": "./dist/src/public/skills/index.d.ts",
87
+ "import": "./dist/src/public/skills/index.js",
88
+ "default": "./dist/src/public/skills/index.js"
89
+ },
90
+ "./context": {
91
+ "types": "./dist/src/public/context/index.d.ts",
92
+ "import": "./dist/src/public/context/index.js",
93
+ "default": "./dist/src/public/context/index.js"
94
+ },
85
95
  "./channels": {
86
96
  "types": "./dist/src/public/channels/index.d.ts",
87
97
  "import": "./dist/src/public/channels/index.js",
@@ -1,18 +0,0 @@
1
- import type { HarnessSession } from "../harness/types.js";
2
- import type { AshContext } from "./container.js";
3
- /**
4
- * Hydrates all durable context values from `session.context`.
5
- *
6
- * Unknown keys are ignored. Keys without a persisted value remain absent until
7
- * authored code or a channel explicitly sets or ensures them.
8
- */
9
- export declare function hydrateDurableContext(ctx: AshContext, session: HarnessSession): Promise<void>;
10
- /**
11
- * Serializes all durable context values currently set on the context.
12
- */
13
- export declare function serializeDurableContext(ctx: AshContext): Record<string, unknown>;
14
- /**
15
- * Commits the full durable context bag back to `session.context`.
16
- */
17
- export declare function commitDurableContext(ctx: AshContext, session: HarnessSession): HarnessSession;
18
- //# sourceMappingURL=durable-context.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"durable-context.d.ts","sourceRoot":"","sources":["../../../src/context/durable-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYhF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,GAAG,cAAc,CAY7F"}
@@ -1,49 +0,0 @@
1
- import { isDeepStrictEqual } from "node:util";
2
- import { isDurableContextKey, resolveContextKey } from "./key.js";
3
- /**
4
- * Hydrates all durable context values from `session.context`.
5
- *
6
- * Unknown keys are ignored. Keys without a persisted value remain absent until
7
- * authored code or a channel explicitly sets or ensures them.
8
- */
9
- export async function hydrateDurableContext(ctx, session) {
10
- const data = session.context ?? {};
11
- for (const [name, raw] of Object.entries(data)) {
12
- if (raw === undefined) {
13
- continue;
14
- }
15
- const key = resolveContextKey(name);
16
- if (key === undefined) {
17
- continue;
18
- }
19
- ctx.set(key, key.codec ? await key.codec.deserialize(raw, ctx) : raw);
20
- }
21
- }
22
- /**
23
- * Serializes all durable context values currently set on the context.
24
- */
25
- export function serializeDurableContext(ctx) {
26
- const data = {};
27
- for (const [key, value] of ctx.entries()) {
28
- if (!isDurableContextKey(key) || value === undefined) {
29
- continue;
30
- }
31
- data[key.name] = key.codec ? key.codec.serialize(value) : value;
32
- }
33
- return data;
34
- }
35
- /**
36
- * Commits the full durable context bag back to `session.context`.
37
- */
38
- export function commitDurableContext(ctx, session) {
39
- const nextContext = serializeDurableContext(ctx);
40
- const currentContext = session.context ?? {};
41
- if (isDeepStrictEqual(nextContext, currentContext)) {
42
- return session;
43
- }
44
- return {
45
- ...session,
46
- context: Object.keys(nextContext).length > 0 ? nextContext : undefined,
47
- };
48
- }
49
- //# sourceMappingURL=durable-context.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"durable-context.js","sourceRoot":"","sources":["../../../src/context/durable-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAI9C,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAe,EACf,OAAuB;IAEvB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IAEnC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QAED,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAe;IACrD,MAAM,IAAI,GAA4B,EAAE,CAAC;IAEzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;QACzC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACrD,SAAS;QACX,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAe,EAAE,OAAuB;IAC3E,MAAM,WAAW,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IAE7C,IAAI,iBAAiB,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,GAAG,OAAO;QACV,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;KACvE,CAAC;AACJ,CAAC"}
@@ -1,27 +0,0 @@
1
- import type { Channel, DeliverPayload, SessionAuthContext } from "../channel/types.js";
2
- import type { AshContext } from "../context/container.js";
3
- import type { HarnessSession, StepInput, StepResult } from "../harness/types.js";
4
- export interface StepDeliveryInput {
5
- readonly auth?: SessionAuthContext | null;
6
- readonly payload: DeliverPayload;
7
- }
8
- export interface PreparedStepContext {
9
- readonly channel: Channel;
10
- readonly channelStateSnapshot: Record<string, unknown>;
11
- readonly ctx: AshContext;
12
- readonly input: StepInput | undefined;
13
- }
14
- export declare function prepareStepContext(input: {
15
- readonly delivery?: StepDeliveryInput;
16
- readonly serializedRuntimeContext: Record<string, unknown>;
17
- readonly session: HarnessSession;
18
- }): Promise<PreparedStepContext>;
19
- /**
20
- * Runs one step inside the provider lifecycle and asserts that the
21
- * channel's serialized state was not mutated during execution.
22
- *
23
- * Combines {@link runStep} with a post-step channel stability check so
24
- * callers do not need to repeat the three-call sequence themselves.
25
- */
26
- export declare function runStepWithChannelGuard(prepared: PreparedStepContext, session: HarnessSession, callback: (session: HarnessSession) => Promise<StepResult>): Promise<StepResult>;
27
- //# sourceMappingURL=step-context.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"step-context.d.ts","sourceRoot":"","sources":["../../../src/execution/step-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAM1D,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvD,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;CACvC;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3D,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;CAClC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA0B/B;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,UAAU,CAAC,GACzD,OAAO,CAAC,UAAU,CAAC,CAQrB"}