experimental-ash 0.8.3 → 0.10.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 (58) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/dist/docs/public/channels/slack.md +76 -25
  3. package/dist/src/compiled/.vendor-stamp.json +14 -14
  4. package/dist/src/compiled/@ai-sdk/anthropic/index.js +2 -2
  5. package/dist/src/compiled/@ai-sdk/google/index.js +4 -4
  6. package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
  7. package/dist/src/compiled/@ai-sdk/openai/index.js +6 -6
  8. package/dist/src/compiled/@ai-sdk/otel/index.js +1 -1
  9. package/dist/src/compiled/@ai-sdk/provider/_json-schema.d.ts +5 -0
  10. package/dist/src/compiled/@ai-sdk/provider/index.d.ts +6632 -1
  11. package/dist/src/compiled/@chat-adapter/slack/_chat-adapter-shared.d.ts +9 -0
  12. package/dist/src/compiled/@chat-adapter/slack/index.d.ts +632 -54
  13. package/dist/src/compiled/@chat-adapter/slack/index.js +25 -29
  14. package/dist/src/compiled/@chat-adapter/slack/package.json +1 -1
  15. package/dist/src/compiled/@chat-adapter/state-memory/index.d.ts +41 -25
  16. package/dist/src/compiled/@chat-adapter/state-memory/package.json +1 -1
  17. package/dist/src/compiled/@standard-schema/spec/index.d.ts +115 -62
  18. package/dist/src/compiled/@vercel/sandbox/index.d.ts +4 -1
  19. package/dist/src/compiled/@vercel/sandbox/index.js +5 -5
  20. package/dist/src/compiled/@workflow/core/index.js +1 -1
  21. package/dist/src/compiled/@workflow/core/runtime.d.ts +6 -2
  22. package/dist/src/compiled/@workflow/core/runtime.js +4 -4
  23. package/dist/src/compiled/@workflow/core/workflow.js +1 -1
  24. package/dist/src/compiled/@workflow/errors/_ms.d.ts +4 -0
  25. package/dist/src/compiled/@workflow/errors/error-codes.d.ts +17 -0
  26. package/dist/src/compiled/@workflow/errors/index.d.ts +438 -56
  27. package/dist/src/compiled/@workflow/errors/index.js +1 -1
  28. package/dist/src/compiled/_chunks/node/{auth-CdwuOxMs.js → auth-vbe4XEEK.js} +2 -2
  29. package/dist/src/compiled/_chunks/node/{dist-B6IOtzm1.js → dist-BdWHjlRQ.js} +12 -12
  30. package/dist/src/compiled/_chunks/node/retry-BOcy5BbJ.js +1 -0
  31. package/dist/src/compiled/_chunks/workflow/{context-errors-CXifqq6a.js → context-errors-zbKocOyk.js} +1 -1
  32. package/dist/src/compiled/_chunks/workflow/{dist-BuELZxm6.js → dist-Ci2brnHh.js} +3 -3
  33. package/dist/src/compiled/_chunks/workflow/{resume-hook-CgfgCU87.js → resume-hook-CL8Ed91K.js} +2 -2
  34. package/dist/src/compiled/_chunks/workflow/sleep-Dn3i9nxI.js +1 -0
  35. package/dist/src/compiled/chat/_mdast.d.ts +24 -0
  36. package/dist/src/compiled/chat/_workflow-serde.d.ts +5 -0
  37. package/dist/src/compiled/chat/index.d.ts +3851 -72
  38. package/dist/src/compiled/chat/index.js +1 -1
  39. package/dist/src/compiled/chat/jsx-runtime-DxGwoLu2.d.ts +782 -0
  40. package/dist/src/compiled/chat/package.json +1 -1
  41. package/dist/src/compiled/just-bash/index.js +1 -1
  42. package/dist/src/execution/authorization-challenge-defaults.d.ts +1 -1
  43. package/dist/src/execution/authorization-challenge-defaults.js +1 -1
  44. package/dist/src/internal/application/package.js +1 -1
  45. package/dist/src/public/channels/slack/index.d.ts +1 -1
  46. package/dist/src/public/channels/slack/slack.d.ts +2 -1
  47. package/dist/src/public/channels/slack/slack.js +5 -1
  48. package/dist/src/public/channels/slack/slackChannel.d.ts +67 -5
  49. package/dist/src/public/channels/slack/slackChannel.js +40 -15
  50. package/dist/src/runtime/connections/authorization-tokens.d.ts +1 -1
  51. package/dist/src/runtime/connections/authorization-tokens.js +1 -1
  52. package/package.json +16 -16
  53. package/dist/src/compiled/_chunks/node/ms-B2k_qBoq.js +0 -1
  54. package/dist/src/compiled/_chunks/workflow/sleep-BzS_cSYx.js +0 -1
  55. /package/dist/src/compiled/_chunks/workflow/{dist-C9DdsXoK.js → dist-0iNBqPYp.js} +0 -0
  56. /package/dist/src/compiled/_chunks/workflow/{dist-BHbmiLmM.js → dist-D774SUM4.js} +0 -0
  57. /package/dist/src/compiled/_chunks/workflow/{src-CidBwKAD.js → src-ClRYdO4-.js} +0 -0
  58. /package/dist/src/compiled/_chunks/workflow/{symbols-BC0BVTM7.js → symbols-D-4tVV8x.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,97 @@
1
1
  # experimental-ash
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5bc39de: feat(slack): pluggable `stateAdapter` for production persistence
8
+
9
+ `slackChannel` and `slack()` now accept a `stateAdapter` option implementing the chat SDK `StateAdapter` contract. Used for callback URLs on posted cards, `thread.state` / `thread.setState`, `thread.subscribe`, message queues, and locks. Defaults to an in-memory adapter (development only — loses state on restart, not shared across processes). Pass a Redis/Postgres-backed adapter for production.
10
+
11
+ The supplied instance is shared across the inbound webhook path (`Chat` constructor) and every event-handler context rebuild, so state stays coherent within a single agent run. The default in-memory adapter is now constructed once at channel-construction time and shared the same way, replacing the previous behavior where the inbound path and each rebuild call each got their own isolated memory adapter.
12
+
13
+ A new exported type alias `SlackStateAdapter` aliases the chat SDK's `StateAdapter` interface.
14
+
15
+ ## 0.9.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 6a3f538: feat(slack): async `run`, new `onMention` pre-dispatch hook, and `onInteraction` docs
20
+
21
+ The previous `slackChannel` shape had a single Nitro-side callback — `run(ctx, message)` — that was synchronous and could only return `{ auth } | null`. That made it impossible to do any awaited pre-dispatch work (DB lookups, OAuth refresh, etc.) or to fire awaited side effects on the inbound webhook side before the workflow runtime cold-starts.
22
+
23
+ Three additive changes:
24
+
25
+ - **`run` is now sync-or-async.** Return type is `SlackRunResult | Promise<SlackRunResult>`. The framework `await`s the result before dispatching. Existing sync `run()` callers continue to work unchanged.
26
+ - **New `onMention(ctx, message)` hook.** Fires after `run()` accepts and before `send()` enqueues the turn. The framework awaits it; thrown errors are caught and logged so a misbehaving handler cannot block dispatch. Use this for free-form pre-dispatch side effects — starting a typing indicator, logging, etc. The framework still owns dispatch; to skip a turn, return `null` from `run()`.
27
+ - **`onInteraction` JSDoc.** Documented the existing handler's semantics: HITL `action_id` routing (`ash_input:*` is consumed by the framework before reaching this handler), `waitUntil` execution, error swallowing, and the limitations of the rebuilt `SlackContext`.
28
+
29
+ The higher-level `slack()` wrapper moves its `Thinking...` typing indicator into `onMention` so it fires on the inbound webhook side, not after the workflow runtime materializes. The existing `events["turn.started"]` handler still fires the indicator for subsequent in-session turns (HITL follow-ups, multi-turn tool loops).
30
+
31
+ Docs updated:
32
+
33
+ - `docs/public/channels/slack.md` now has a `Hooks` section explaining `run` vs `onMention` vs `onInteraction` vs `events`, and the `Typing Indicators` section uses `onMention` instead of an un-awaited `startTyping()` inside `run()` (which was a dangling-promise footgun).
34
+ - The `Customize Delivery` example now correctly nests event handlers under `events: { ... }` (the previous example showed them flat on the config object, which never worked).
35
+
36
+ No breaking changes.
37
+
38
+ ### Patch Changes
39
+
40
+ - 41947c0: fix(slack): forward `webhookVerifier` to the adapter rebuilt for event-handler context
41
+
42
+ Follow-up to the previous webhook-verifier fix. `slackChannel` instantiates Slack adapters in two places: `getChat()` for inbound webhook routing and `rebuildSlackContext()` for outbound event-handler dispatch (e.g. delivering `session.failed` at the end of a turn). The previous fix only plumbed `webhookVerifier` and `signingSecret` through the first site, so a Connect-credentialed channel that successfully accepted the inbound webhook would later crash when the runtime tried to materialize the channel context for terminal events:
43
+
44
+ ```
45
+ ValidationError: signingSecret or webhookVerifier is required.
46
+ at rebuildSlackContext (..., adapter: 'slack', code: 'VALIDATION_ERROR')
47
+ ```
48
+
49
+ Concretely:
50
+
51
+ - Extracted a single `resolveSlackAdapterCredentials(credentials)` helper that returns `{ botToken, signingSecret, webhookVerifier }` with the env-var fallback rules (skipping `SLACK_SIGNING_SECRET` when a verifier is supplied).
52
+ - Both `getChat()` and `rebuildSlackContext()` now resolve credentials through that helper and pass the full triple into `createSlackAdapter`, keeping the two adapter instantiation sites in lockstep so a future credential field cannot drift again.
53
+ - `rebuildSlackContext`'s signature now takes the full `SlackChannelCredentials | undefined` instead of just `botToken`.
54
+
55
+ No public API change.
56
+
57
+ - 06cd322: chore(vendor): vendor the `chat` package's real `.d.ts` instead of a hand-written stub so `ctx.thread` and friends expose the actual chat surface (`refresh()`, `startTyping()`, `post()`, `postEphemeral()`, …) instead of `any`.
58
+
59
+ Previously, `#compiled/chat/index.js` shipped an Ash-owned hand-written declaration that declared `Thread = any`, `Message = any`, `Author = any`, etc. The runtime value of `ctx.thread` was always a real `ThreadImpl` from the bundled chat package, so methods like `thread.refresh()` worked at runtime — they just typechecked as `any` regardless of whether the method existed. Hand-written stubs also silently drifted from upstream on every `chat` version bump.
60
+
61
+ What changed:
62
+
63
+ - The vendor step now copies `chat`'s real `dist/index.d.ts` verbatim into `.generated/compiled/chat/index.d.ts`, with three transforms applied at copy time:
64
+ - The sibling `jsx-runtime-<hash>.d.ts` chunk is co-copied so chat's relative import resolves locally. The chunk filename has a content hash, so it's discovered dynamically.
65
+ - `from '@workflow/serde'` is rewritten to a locally-emitted stub that declares just the `unique symbol`s chat references.
66
+ - `from 'mdast'` is rewritten to a locally-emitted stub that aliases the names chat references to `unknown` — consumers don't need to install `@types/mdast`.
67
+ - Any external the upstream `.d.ts` reaches for that has no rewrite rule is a hard error at vendor time so a future chat version can't sneak a new dependency past us.
68
+ - The same copy-from-package treatment is applied to `@chat-adapter/slack` and `@chat-adapter/state-memory`, whose types extend chat's `Adapter` / `StateAdapter` interfaces and have to satisfy them after the chat copy.
69
+ - `chat`, `@chat-adapter/slack`, and `@chat-adapter/state-memory` are bumped from `^4.27.0` to `4.28.1`. Every other direct dependency in `packages/ash/package.json` is also locked (no `^` ranges) so the vendored output is reproducible. Peer deps still use ranges so consumers control compatibility.
70
+ - `slackChannel.rebuildSlackContext` was assigning to `thread._adapter` directly; that field is `private` in the real chat types. Switched to `Reflect.set(thread, "_adapter", adapter)` which preserves runtime behavior without an unsafe cast.
71
+
72
+ What this means for agent code:
73
+
74
+ ```ts
75
+ // Before — typechecked as `any`, no autocomplete:
76
+ await ctx.thread.refresh();
77
+ await ctx.thread.startTyping("Working on it…");
78
+ const participants = await ctx.thread.getParticipants();
79
+
80
+ // After — typechecked against the actual chat@4.28.1 Thread interface
81
+ // with full autocomplete, JSDoc, and error reporting:
82
+ await ctx.thread.refresh();
83
+ await ctx.thread.startTyping("Working on it…");
84
+ const participants = await ctx.thread.getParticipants();
85
+ ```
86
+
87
+ If your handlers were calling methods that don't exist on `Thread` and were passing typecheck through `any`, you'll see real type errors now. The runtime behavior is unchanged.
88
+
89
+ Vendor-script refactor (internal, no public-API impact):
90
+
91
+ - `scripts/vendor-compiled.mjs` shrank from ~1500 lines to ~36 lines. Per-package configs moved to one file each under `scripts/vendor-compiled/`, mirroring npm package names (`@chat-adapter/slack.mjs`, `@workflow/core.mjs`, etc.).
92
+ - Inline `.d.ts` template-literal strings moved to real `.d.ts` files under `scripts/vendor-compiled/declarations/` with editor syntax highlighting.
93
+ - Reusable bundling primitives (`runVendor`, `createDeclarationCopier`, `buildUniqueSymbolStub`, `buildOpaqueTypesStub`, `createOptionalNativeStubPlugin`, `collectFilesRecursively`) live in `scripts/vendor-compiled/_shared.mjs` so other packages in the monorepo can adopt the same vendoring pipeline without duplication.
94
+
3
95
  ## 0.8.3
4
96
 
5
97
  ### Patch Changes
@@ -127,6 +127,7 @@ import { slackChannelCredentials } from "@vercel/connex/ash";
127
127
  import { slackChannel } from "experimental-ash/channels/slack";
128
128
 
129
129
  export default slackChannel({
130
+ credentials: slackChannelCredentials("slack/my-agent"),
130
131
  run(ctx, message) {
131
132
  return {
132
133
  auth: {
@@ -137,37 +138,80 @@ export default slackChannel({
137
138
  },
138
139
  };
139
140
  },
140
- "message.completed"(event, ctx) {
141
- if (event.finishReason === "tool-calls") return;
142
- if (event.message) ctx.thread.post(event.message);
143
- },
144
- "session.failed"(event, ctx) {
145
- ctx.thread.post("Something went wrong.");
141
+ events: {
142
+ "message.completed"(event, ctx) {
143
+ if (event.finishReason === "tool-calls") return;
144
+ if (event.message) ctx.thread.post(event.message);
145
+ },
146
+ "session.failed"(event, ctx) {
147
+ ctx.thread.post("Something went wrong.");
148
+ },
146
149
  },
147
- credentials: slackChannelCredentials("slack/my-agent"),
148
150
  });
149
151
  ```
150
152
 
153
+ ## Hooks
154
+
155
+ `slackChannel` exposes three places to plug in custom behavior:
156
+
157
+ - **`run(ctx, message)`** -- decides whether to dispatch a turn for an inbound `app_mention` and
158
+ with what `auth` context. Returns `{ auth }` to dispatch or `null` to silently drop the mention.
159
+ May be sync or async; the framework awaits the result before dispatching.
160
+ - **`onMention(ctx, message)`** -- free-form pre-dispatch side effects, invoked on the inbound
161
+ webhook side after `run()` accepts and before the turn is enqueued. Use it for work that should
162
+ fire immediately, before the workflow runtime cold-starts -- starting a typing indicator,
163
+ logging, etc. Errors are caught and logged; the turn still dispatches.
164
+ - **`onInteraction(action, ctx)`** -- handler for Slack `block_actions` callbacks (button clicks,
165
+ selects, etc.) that are not consumed by the framework's HITL pipeline. Runs on the inbound
166
+ webhook side via `waitUntil`, so the channel returns `200 OK` to Slack immediately.
167
+
168
+ `events: { ... }` handlers receive runtime events emitted by the harness after the turn dispatches
169
+ (`turn.started`, `message.completed`, `session.failed`, etc.). They run inside the workflow context,
170
+ not on the inbound webhook side.
171
+
172
+ ## State Persistence
173
+
174
+ The Slack channel uses a state backend for callback URLs on posted cards, `thread.state` /
175
+ `thread.setState`, `thread.subscribe`, message queues, and locks. By default this is an in-memory
176
+ adapter scoped to the current process, which loses state on restart and is not coherent across
177
+ processes. For deployed agents, pass a production adapter (Redis, Postgres, etc.) implementing the
178
+ chat SDK `StateAdapter` contract. Construct it once at module top-level so all requests share one
179
+ connection pool:
180
+
181
+ ```ts
182
+ import { createRedisState } from "@chat-adapter/state-redis";
183
+ import { slack } from "experimental-ash/channels/slack";
184
+
185
+ const stateAdapter = createRedisState({ url: process.env.REDIS_URL! });
186
+
187
+ export default slack({
188
+ stateAdapter,
189
+ });
190
+ ```
191
+
192
+ The same instance is reused across the inbound webhook path and every event-handler context rebuild,
193
+ so state stays coherent within a single agent run.
194
+
151
195
  ## Typing Indicators
152
196
 
153
197
  Out of the box, `slack()` posts typing statuses so the user sees feedback before the agent starts
154
198
  thinking:
155
199
 
156
- - **`Thinking...`** -- posted by the default handler the moment a mention arrives, before the agent
157
- run starts.
200
+ - **`Thinking...`** -- posted by the default `onMention` hook the moment a mention arrives, on the
201
+ inbound webhook side, before the workflow runtime starts.
202
+ - **`Working...`** -- posted by the default `turn.started` event handler at the start of each turn
203
+ within the session, refreshing the typing indicator after the workflow runtime materializes.
158
204
  - **Tool status** -- when an `actions.requested` event fires, the default handler updates the typing
159
205
  indicator to show which tools are running.
160
206
 
161
- To customize typing indicators, use `slackChannel` and write your own event handlers:
207
+ To customize typing indicators, use `slackChannel` and supply your own `onMention` plus event
208
+ handlers:
162
209
 
163
210
  ```ts
164
211
  import { slackChannel } from "experimental-ash/channels/slack";
165
212
 
166
213
  export default slackChannel({
167
- run(ctx, message) {
168
- ctx.thread.startTyping(
169
- message.text.includes("weather") ? "Checking the weather..." : "Thinking...",
170
- );
214
+ run(_ctx, message) {
171
215
  return {
172
216
  auth: {
173
217
  principalId: message.author.userId,
@@ -177,21 +221,28 @@ export default slackChannel({
177
221
  },
178
222
  };
179
223
  },
180
- "actions.requested"(event, ctx) {
181
- const labels = event.actions.map((a) => (a.kind === "tool-call" ? a.toolName : a.kind));
182
- ctx.thread.startTyping(`Running ${labels.join(", ")}...`);
183
- },
184
- "message.completed"(event, ctx) {
185
- if (event.finishReason === "tool-calls") return;
186
- if (event.message) ctx.thread.post(event.message);
224
+ async onMention(ctx, message) {
225
+ await ctx.thread.startTyping(
226
+ message.text.includes("weather") ? "Checking the weather..." : "Thinking...",
227
+ );
187
228
  },
188
- "session.failed"(event, ctx) {
189
- ctx.thread.post("Something went wrong.");
229
+ events: {
230
+ async "actions.requested"(event, ctx) {
231
+ const labels = event.actions.map((a) => (a.kind === "tool-call" ? a.toolName : a.kind));
232
+ await ctx.thread.startTyping(`Running ${labels.join(", ")}...`);
233
+ },
234
+ async "message.completed"(event, ctx) {
235
+ if (event.finishReason === "tool-calls") return;
236
+ if (event.message) await ctx.thread.post(event.message);
237
+ },
238
+ async "session.failed"(_event, ctx) {
239
+ await ctx.thread.post("Something went wrong.");
240
+ },
190
241
  },
191
242
  });
192
243
  ```
193
244
 
194
- Event handlers are declared as named properties on the config object. They receive `(eventData, ctx)`
195
- where `ctx` carries platform handles like `ctx.thread` and `ctx.session`.
245
+ Event handlers are nested under `events: { ... }` and receive `(eventData, ctx)` where `ctx`
246
+ carries platform handles like `ctx.thread` and `ctx.slack`.
196
247
 
197
248
  See [Channels](/docs/channels) for the full channel surface.
@@ -1,24 +1,24 @@
1
1
  {
2
2
  "moduleVersions": {
3
- "turndown": "7.2.4",
4
- "zod-validation-error": "5.0.0",
5
- "zod": "4.4.3",
6
- "chat": "4.27.0",
7
- "@vercel/sandbox": "2.0.0-beta.14",
8
- "@ai-sdk/provider": "4.0.0-canary.16",
9
3
  "@ai-sdk/anthropic": "4.0.0-canary.46",
4
+ "chat": "4.28.1",
5
+ "@chat-adapter/slack": "4.28.1",
6
+ "@chat-adapter/state-memory": "4.28.1",
10
7
  "@ai-sdk/google": "4.0.0-canary.53",
11
- "@ai-sdk/openai": "4.0.0-canary.49",
8
+ "jose": "6.2.3",
9
+ "just-bash": "2.14.5",
12
10
  "@ai-sdk/mcp": "2.0.0-canary.41",
11
+ "@ai-sdk/openai": "4.0.0-canary.49",
13
12
  "@opentelemetry/api": "1.9.1",
13
+ "@ai-sdk/otel": "1.0.0-canary.77",
14
+ "@ai-sdk/provider": "4.0.0-canary.16",
15
+ "@standard-schema/spec": "1.1.0",
16
+ "turndown": "7.2.4",
17
+ "@vercel/sandbox": "2.0.0-beta.14",
14
18
  "@workflow/core": "5.0.0-beta.5",
15
19
  "@workflow/errors": "5.0.0-beta.2",
16
- "@ai-sdk/otel": "1.0.0-canary.77",
17
- "@chat-adapter/slack": "4.27.0",
18
- "@chat-adapter/state-memory": "4.27.0",
19
- "jose": "6.2.3",
20
- "just-bash": "2.14.5",
21
- "@standard-schema/spec": "1.1.0"
20
+ "zod": "4.4.3",
21
+ "zod-validation-error": "5.0.0"
22
22
  },
23
- "scriptHash": "520ce458abd555329457db163ebe68cdefda54855571c6d96b4f2a0fb76aa0c9"
23
+ "scriptHash": "ae1e079196d6cbf9f9fec8b3083fba06192d71d35e09f8980a9b99415c0d463a"
24
24
  }