experimental-ash 0.62.0 → 0.64.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 (85) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/docs/public/advanced/auth-and-route-protection.mdx +26 -20
  3. package/dist/docs/public/advanced/hooks.mdx +8 -2
  4. package/dist/docs/public/advanced/runs-and-streaming.md +6 -3
  5. package/dist/docs/public/advanced/typescript-api.md +32 -0
  6. package/dist/docs/public/channels/ash.mdx +5 -1
  7. package/dist/docs/public/channels/custom.mdx +23 -0
  8. package/dist/docs/public/frontend/README.md +8 -4
  9. package/dist/docs/public/frontend/meta.json +9 -1
  10. package/dist/docs/public/frontend/nextjs.md +4 -4
  11. package/dist/docs/public/frontend/nuxt.md +168 -0
  12. package/dist/docs/public/frontend/sveltekit.md +177 -0
  13. package/dist/docs/public/frontend/use-ash-agent-svelte.md +185 -0
  14. package/dist/docs/public/frontend/use-ash-agent-vue.md +236 -0
  15. package/dist/docs/public/frontend/use-ash-agent.md +14 -14
  16. package/dist/docs/public/getting-started.mdx +2 -0
  17. package/dist/src/channel/websocket-upgrade-server.d.ts +26 -0
  18. package/dist/src/channel/websocket-upgrade-server.js +1 -0
  19. package/dist/src/chunks/use-ash-agent-DzoSHUCb.js +1197 -0
  20. package/dist/src/chunks/use-ash-agent-KtjpWd5l.js +1229 -0
  21. package/dist/src/client/ash-agent-store.d.ts +61 -0
  22. package/dist/src/client/ash-agent-store.js +2 -0
  23. package/dist/src/client/client-error.js +1 -1
  24. package/dist/src/client/index.d.ts +2 -0
  25. package/dist/src/client/index.js +1 -1
  26. package/dist/src/compiled/.vendor-stamp.json +3 -3
  27. package/dist/src/compiled/@chat-adapter/slack/index.js +25 -25
  28. package/dist/src/compiled/@workflow/core/events-consumer.d.ts +8 -0
  29. package/dist/src/compiled/@workflow/core/index.js +2 -2
  30. package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +1 -0
  31. package/dist/src/compiled/@workflow/core/runtime.js +29 -29
  32. package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
  33. package/dist/src/compiled/@workflow/core/workflow.js +1 -1
  34. package/dist/src/compiled/@workflow/errors/error-codes.d.ts +2 -0
  35. package/dist/src/compiled/@workflow/errors/index.d.ts +14 -0
  36. package/dist/src/compiled/@workflow/errors/index.js +1 -1
  37. package/dist/src/compiled/@workflow/world/queue.d.ts +8 -0
  38. package/dist/src/compiled/_chunks/workflow/dist-zpK2YVVA.js +3 -0
  39. package/dist/src/compiled/_chunks/workflow/resume-hook-BFK9mgsb.js +12 -0
  40. package/dist/src/compiled/_chunks/workflow/{sleep-Bg0t23kF.js → sleep-CeJckNg2.js} +1 -1
  41. package/dist/src/compiled/_chunks/workflow/{symbols-u476uwyR.js → symbols-BWCAoPHE.js} +1 -1
  42. package/dist/src/internal/application/package.d.ts +1 -0
  43. package/dist/src/internal/application/package.js +1 -1
  44. package/dist/src/internal/nitro/host/build-application.js +1 -1
  45. package/dist/src/internal/nitro/host/channel-routes.js +2 -2
  46. package/dist/src/internal/workflow-bundle/ash-service-route-output.js +11 -1
  47. package/dist/src/packages/ash-scaffold/src/channels.js +1 -1
  48. package/dist/src/packages/ash-scaffold/src/web-template.js +5 -16
  49. package/dist/src/public/channels/auth.d.ts +45 -3
  50. package/dist/src/public/channels/auth.js +1 -1
  51. package/dist/src/public/channels/index.d.ts +1 -0
  52. package/dist/src/public/channels/index.js +1 -1
  53. package/dist/src/public/channels/slack/inbound.d.ts +3 -1
  54. package/dist/src/public/channels/slack/inbound.js +1 -1
  55. package/dist/src/public/nuxt/dev-server.d.ts +24 -0
  56. package/dist/src/public/nuxt/dev-server.js +1 -0
  57. package/dist/src/public/nuxt/index.d.ts +1 -0
  58. package/dist/src/public/nuxt/index.js +1 -0
  59. package/dist/src/public/nuxt/module.d.ts +31 -0
  60. package/dist/src/public/nuxt/module.js +1 -0
  61. package/dist/src/public/nuxt/routing.d.ts +55 -0
  62. package/dist/src/public/nuxt/routing.js +1 -0
  63. package/dist/src/public/nuxt/vercel-json.d.ts +17 -0
  64. package/dist/src/public/nuxt/vercel-json.js +1 -0
  65. package/dist/src/public/sveltekit/dev-server.d.ts +24 -0
  66. package/dist/src/public/sveltekit/dev-server.js +1 -0
  67. package/dist/src/public/sveltekit/index.d.ts +39 -0
  68. package/dist/src/public/sveltekit/index.js +1 -0
  69. package/dist/src/public/sveltekit/routing.d.ts +32 -0
  70. package/dist/src/public/sveltekit/routing.js +1 -0
  71. package/dist/src/public/sveltekit/vercel-json.d.ts +17 -0
  72. package/dist/src/public/sveltekit/vercel-json.js +1 -0
  73. package/dist/src/react/use-ash-agent.d.ts +5 -27
  74. package/dist/src/react/use-ash-agent.js +1 -2
  75. package/dist/src/svelte/index.d.ts +3 -0
  76. package/dist/src/svelte/index.js +3 -0
  77. package/dist/src/svelte/use-ash-agent.d.ts +80 -0
  78. package/dist/src/svelte/use-ash-agent.js +3 -0
  79. package/dist/src/vue/index.d.ts +3 -0
  80. package/dist/src/vue/index.js +3 -0
  81. package/dist/src/vue/use-ash-agent.d.ts +78 -0
  82. package/dist/src/vue/use-ash-agent.js +3 -0
  83. package/package.json +51 -6
  84. package/dist/src/compiled/_chunks/workflow/dist-C4EHshZE.js +0 -3
  85. package/dist/src/compiled/_chunks/workflow/resume-hook-BlALLgSA.js +0 -12
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # experimental-ash
2
2
 
3
+ ## 0.64.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 76d7a1f: Add `placeholderAuth()` for scaffolded Web Chat channels so production requests return a structured 401 when app auth has not been configured. Generated apps now show setup guidance instead of an internal channel failure, and `ClientError` surfaces structured Ash error messages directly.
8
+
9
+ ### Patch Changes
10
+
11
+ - 030c0d1: Fix Slack direct messages dropping file uploads. `onDirectMessage` now receives `file_share` messages with their attachments intact, matching the existing `onAppMention` behavior; system subtypes (edits, deletes, joins) and bot-authored echoes are still filtered.
12
+
13
+ ## 0.63.0
14
+
15
+ ### Minor Changes
16
+
17
+ - 524cae7: Add `createWebSocketUpgradeServer()` as an escape hatch for `WS()` routes that need to adapt SDKs or frameworks which bind directly to Node `http.Server` upgrade events.
18
+ - a491826: Add Svelte 5 and SvelteKit integrations, including a `useAshAgent` binding, a SvelteKit Vite plugin for Ash route proxying, Vercel services configuration, docs, tests, and an example app.
19
+ - a491826: Add Vue composable (`useAshAgent`) and Nuxt module (`experimental-ash/nuxt`) for building agent UIs with Vue and Nuxt. The shared `AshAgentStore` class is now exported from `experimental-ash/client` for framework-agnostic consumption.
20
+
21
+ ## 0.62.1
22
+
23
+ ### Patch Changes
24
+
25
+ - d141e9e: Update `@workflow/*` dependencies to the latest beta: `@workflow/core` 5.0.0-beta.12, `@workflow/errors` 5.0.0-beta.7, `@workflow/world` 5.0.0-beta.7, and `@workflow/world-local` 5.0.0-beta.13.
26
+
3
27
  ## 0.62.0
4
28
 
5
29
  ### Minor Changes
@@ -18,13 +18,13 @@ These settings apply to:
18
18
  - `POST /ash/v1/session/:sessionId`
19
19
  - `GET /ash/v1/session/:sessionId/stream`
20
20
 
21
- <CopyPrompt text="Protect the user's Ash HTTP routes through the channel layer. In Ash, route auth and IP policy live on channel factories, usually agent/channels/ash.ts with ashChannel auth config, not in agent.ts. Inspect the existing channel file and app auth code, replace any generated exampleProductionAuth placeholder with the smallest AuthFn or helper composition, use helpers such as localDev, vercelOidc, none, httpBasic, jwtHmac, jwtEcdsa, or oidc as appropriate, keep secrets in environment variables, preserve localDev and vercelOidc behavior where useful, verify unauthenticated production browser requests are rejected with 401, and do not commit unless the user asks.">
21
+ <CopyPrompt text="Protect the user's Ash HTTP routes through the channel layer. In Ash, route auth and IP policy live on channel factories, usually agent/channels/ash.ts with ashChannel auth config, not in agent.ts. Inspect the existing channel file and app auth code, replace any generated placeholderAuth guardrail with the smallest AuthFn or helper composition, use helpers such as localDev, vercelOidc, none, httpBasic, jwtHmac, jwtEcdsa, or oidc as appropriate, keep secrets in environment variables, preserve localDev and vercelOidc behavior where useful, verify unauthenticated production browser requests are rejected with 401, and do not commit unless the user asks.">
22
22
  Protect the user's Ash HTTP routes through the channel layer. In Ash, route auth and IP policy
23
23
  live on channel factories, usually agent/channels/ash.ts with ashChannel auth config, not in
24
24
  agent.ts. Inspect the existing channel file and app auth code, replace any generated
25
- exampleProductionAuth placeholder with the smallest AuthFn or helper composition, use helpers such
26
- as localDev, vercelOidc, none, httpBasic, jwtHmac, jwtEcdsa, or oidc as appropriate, keep secrets
27
- in environment variables, preserve localDev and vercelOidc behavior where useful, verify
25
+ placeholderAuth guardrail with the smallest AuthFn or helper composition, use helpers such as
26
+ localDev, vercelOidc, none, httpBasic, jwtHmac, jwtEcdsa, or oidc as appropriate, keep secrets in
27
+ environment variables, preserve localDev and vercelOidc behavior where useful, verify
28
28
  unauthenticated production browser requests are rejected with 401, and do not commit unless the
29
29
  user asks.
30
30
  </CopyPrompt>
@@ -32,31 +32,24 @@ These settings apply to:
32
32
  ## Generated Web Chat Auth
33
33
 
34
34
  `pnpm create experimental-ash-agent` scaffolds `agent/channels/ash.ts` from the Web Chat example.
35
- Creating this file overrides the default Ash channel settings. The generated version permits Vercel
36
- OIDC and localhost requests and leaves end-user production auth as an explicit placeholder:
35
+ It permits Vercel OIDC and localhost requests, but it will not allow browser requests in
36
+ production until you replace the placeholder with your app's auth:
37
37
 
38
38
  ```ts
39
39
  // agent/channels/ash.ts
40
40
  import { ashChannel } from "experimental-ash/channels/ash";
41
- import { type AuthFn, localDev, vercelOidc } from "experimental-ash/channels/auth";
42
-
43
- function exampleProductionAuth(): AuthFn<Request> {
44
- return () => {
45
- if (process.env.VERCEL_ENV === "production") {
46
- throw new Error("Configure production auth in agent/channels/ash.ts.");
47
- }
48
- return null;
49
- };
50
- }
41
+ import { localDev, placeholderAuth, vercelOidc } from "experimental-ash/channels/auth";
51
42
 
52
43
  export default ashChannel({
53
- auth: [vercelOidc(), localDev(), exampleProductionAuth()],
44
+ auth: [localDev(), vercelOidc(), placeholderAuth()],
54
45
  });
55
46
  ```
56
47
 
57
- Replace `exampleProductionAuth()` before a browser user submits a production request. If you
58
- delete the authored file, Ash falls back to its framework default `[localDev(), vercelOidc()]`;
59
- that default also does not accept browser-user traffic in production.
48
+ Replace `placeholderAuth()` before a browser user submits a production request. It returns a
49
+ structured 401 in production so generated Web Chat apps can explain that auth is not configured
50
+ instead of showing an internal channel error. If you delete the authored file, Ash falls back to
51
+ its framework default `[localDev(), vercelOidc()]`; that default also does not accept browser
52
+ traffic in production.
60
53
 
61
54
  ## Walking The Auth Array
62
55
 
@@ -68,6 +61,19 @@ that default also does not accept browser-user traffic in production.
68
61
  If every entry skips, the request is rejected with `401`. An empty array `auth: []` therefore
69
62
  rejects every request.
70
63
 
64
+ To reject with a specific `401`, throw an `UnauthenticatedError`. To reject with a specific `403`,
65
+ throw a `ForbiddenError`. `routeAuth` turns those errors into HTTP responses; other thrown errors
66
+ still use the normal channel failure path.
67
+
68
+ ```ts
69
+ import { UnauthenticatedError } from "experimental-ash/channels/auth";
70
+
71
+ throw new UnauthenticatedError({
72
+ code: "authentication_required",
73
+ message: "Sign in to continue.",
74
+ });
75
+ ```
76
+
71
77
  To accept anonymous traffic, include `none()` as the final entry:
72
78
 
73
79
  ```ts
@@ -6,8 +6,10 @@ url: /hooks
6
6
 
7
7
  Hooks are Ash's authored extension points for the runtime event stream.
8
8
 
9
- This page is about `agent/hooks/*.ts` runtime hooks. For the React client hook,
10
- see [`useAshAgent`](../frontend/use-ash-agent.md).
9
+ This page is about `agent/hooks/*.ts` runtime hooks. For the client-side hook,
10
+ see [`useAshAgent`](../frontend/use-ash-agent.md) (React) or
11
+ [`useAshAgent` (Vue)](../frontend/use-ash-agent-vue.md) or
12
+ [`useAshAgent` (Svelte)](../frontend/use-ash-agent-svelte.md).
11
13
 
12
14
  Use a hook when you want to observe stream events (audit, metrics,
13
15
  alerting) without writing a tool, a context provider, or a channel
@@ -188,7 +190,11 @@ when both are registered.
188
190
  ## What to read next
189
191
 
190
192
  - [`useAshAgent`](../frontend/use-ash-agent.md)
193
+ - [`useAshAgent` (Vue)](../frontend/use-ash-agent-vue.md)
194
+ - [`useAshAgent` (Svelte)](../frontend/use-ash-agent-svelte.md)
191
195
  - [Next.js](../frontend/nextjs.md)
196
+ - [Nuxt](../frontend/nuxt.md)
197
+ - [SvelteKit](../frontend/sveltekit.md)
192
198
  - [Tools](./tools.mdx)
193
199
  - [Context Control](./context-control.md)
194
200
  - [Sessions And Streaming](./runs-and-streaming.md)
@@ -13,9 +13,10 @@ The key client model is:
13
13
  - `POST /ash/v1/session/:sessionId` sends a follow-up message
14
14
  - `GET /ash/v1/session/:sessionId/stream` lets you watch the session in real time
15
15
 
16
- React apps can use [`useAshAgent()`](../frontend/use-ash-agent.md) instead of calling these
17
- routes directly. Next.js apps can use [`withAsh()`](../frontend/nextjs.md) to proxy these
18
- routes to the Ash runtime from the same origin.
16
+ React apps can use [`useAshAgent()`](../frontend/use-ash-agent.md) and Vue apps can use
17
+ [`useAshAgent()` (Vue)](../frontend/use-ash-agent-vue.md) instead of calling these routes
18
+ directly. [Next.js](../frontend/nextjs.md) and [Nuxt](../frontend/nuxt.md) apps can proxy
19
+ these routes to the Ash runtime from the same origin.
19
20
 
20
21
  Ash keeps those separate on purpose:
21
22
 
@@ -127,7 +128,9 @@ channel has already updated its state and the projection is current.
127
128
  ## What To Read Next
128
129
 
129
130
  - [`useAshAgent`](../frontend/use-ash-agent.md)
131
+ - [`useAshAgent` (Vue)](../frontend/use-ash-agent-vue.md)
130
132
  - [Next.js](../frontend/nextjs.md)
133
+ - [Nuxt](../frontend/nuxt.md)
131
134
  - [Session Context](./session-context.md)
132
135
  - [Subagents](./subagents.mdx)
133
136
  - [Schedules](./schedules.mdx)
@@ -18,6 +18,10 @@ Source of truth:
18
18
  - React subpath: [`../../packages/ash/src/react/index.ts`](../../packages/ash/src/react/index.ts)
19
19
  - client subpath: [`../../packages/ash/src/client/index.ts`](../../packages/ash/src/client/index.ts)
20
20
  - evals subpath: [`../../packages/ash/src/evals/index.ts`](../../packages/ash/src/evals/index.ts)
21
+ - vue subpath: [`../../packages/ash/src/vue/index.ts`](../../packages/ash/src/vue/index.ts)
22
+ - nuxt subpath: [`../../packages/ash/src/public/nuxt/index.ts`](../../packages/ash/src/public/nuxt/index.ts)
23
+ - svelte subpath: [`../../packages/ash/src/svelte/index.ts`](../../packages/ash/src/svelte/index.ts)
24
+ - SvelteKit subpath: [`../../packages/ash/src/public/sveltekit/index.ts`](../../packages/ash/src/public/sveltekit/index.ts)
21
25
 
22
26
  ## Definition Helpers
23
27
 
@@ -85,6 +89,32 @@ React helpers exported from `experimental-ash/react`:
85
89
  - `UseAshAgentOptions`, `UseAshAgentHelpers`, `UseAshAgentSnapshot`, `UseAshAgentStatus` - hook configuration and state types
86
90
  - `AshMessageData`, `AshMessage`, `AshMessagePart`, `AshDynamicToolPart` - default message projection types
87
91
 
92
+ Nuxt helpers exported from `experimental-ash/nuxt`:
93
+
94
+ - `default` - the Nuxt module that runs the Ash agent alongside your Nuxt app
95
+ - `ASH_NUXT_SERVICE_PREFIX` - default private Vercel service prefix for the Ash service
96
+ - `AshNuxtModuleOptions` - options for `ashRoot`, `ashBuildCommand`, `configureVercelJson`, and `servicePrefix`
97
+
98
+ Vue helpers exported from `experimental-ash/vue`:
99
+
100
+ - `useAshAgent(options?)` - Vue composable for sending turns, streaming events, projecting reactive UI state, and tracking a session cursor
101
+ - `defaultMessageReducer()` - default chat-style event projection used by `useAshAgent()`
102
+ - `UseAshAgentOptions`, `UseAshAgentReturn`, `UseAshAgentSnapshot`, `UseAshAgentStatus`, `PrepareSend` - composable configuration and state types
103
+ - `AshAgentReducer`, `AshMessageData`, `AshMessage`, `AshMessagePart`, `AshDynamicToolPart` - reducer and default message projection types
104
+
105
+ SvelteKit helpers exported from `experimental-ash/sveltekit`:
106
+
107
+ - `ashSvelteKit(options?)` - Vite plugin that runs the Ash agent alongside your SvelteKit app
108
+ - `ASH_SVELTEKIT_SERVICE_PREFIX` - default private Vercel service prefix for the Ash service
109
+ - `AshSvelteKitPluginOptions` - options for `ashRoot`, `ashBuildCommand`, `configureVercelJson`, and `servicePrefix`
110
+
111
+ Svelte helpers exported from `experimental-ash/svelte`:
112
+
113
+ - `useAshAgent(options?)` - Svelte 5 binding for sending turns, streaming events, projecting rune-friendly UI state, and tracking a session cursor
114
+ - `defaultMessageReducer()` - default chat-style event projection used by `useAshAgent()`
115
+ - `UseAshAgentOptions`, `UseAshAgentReturn`, `UseAshAgentSnapshot`, `UseAshAgentStatus`, `PrepareSend` - binding configuration and state types
116
+ - `AshAgentReducer`, `AshMessageData`, `AshMessage`, `AshMessagePart`, `AshDynamicToolPart` - reducer and default message projection types
117
+
88
118
  Client helpers exported from `experimental-ash/client`:
89
119
 
90
120
  - `Client` - HTTP client for an Ash server
@@ -321,6 +351,8 @@ import { Braintrust } from "experimental-ash/evals/reporters";
321
351
  - `ctx.session` -> [Session Context](./session-context.md)
322
352
  - `withAsh` -> [Next.js](../frontend/nextjs.md)
323
353
  - `useAshAgent` -> [`useAshAgent`](../frontend/use-ash-agent.md)
354
+ - `useAshAgent` (Vue) and `defaultMessageReducer` -> [`useAshAgent` (Vue)](../frontend/use-ash-agent-vue.md)
355
+ - Nuxt module (`experimental-ash/nuxt`) -> [Nuxt](../frontend/nuxt.md)
324
356
  - subagents (authored with `defineAgent` under `subagents/<id>/agent.ts`) -> [Subagents](./subagents.mdx)
325
357
  - `defineSchedule` -> [Schedules](./schedules.mdx)
326
358
  - `defineEvalSuite`, loaders, reporters, and scorers -> [Evals](./evals.mdx)
@@ -58,7 +58,11 @@ wire the Ash channel to your app's auth system, such as Clerk, Auth.js, or your
58
58
  verification.
59
59
 
60
60
  `pnpm create experimental-ash-agent` scaffolds an example `agent/channels/ash.ts` with a production
61
- auth placeholder so you can replace it before exposing the API to real users.
61
+ auth placeholder so you can replace it before exposing the API to real users. The generated channel
62
+ permits Vercel OIDC and localhost requests and includes `placeholderAuth()`, which returns a
63
+ setup-focused 401 in production until you replace it with your app's auth. If you delete the
64
+ authored file, Ash falls back to `[localDev(), vercelOidc()]`; that default does not admit browser
65
+ users in production.
62
66
 
63
67
  For the full auth model and helper list, see
64
68
  [Auth and Route Protection](/docs/auth-and-route-protection).
@@ -89,6 +89,29 @@ export default defineChannel({
89
89
  `params`, `waitUntil`, and `requestIp`. The returned hooks are Ash-owned structural types compatible
90
90
  with Nitro/H3 websocket routing, including `upgrade`, `open`, `message`, `close`, and `error`.
91
91
 
92
+ ### Node upgrade server escape hatch
93
+
94
+ Prefer the `WS()` lifecycle hooks above when you own the websocket behavior. Ash also exposes
95
+ `createWebSocketUpgradeServer()` for the narrower case where a third-party SDK or framework expects
96
+ to bind directly to a Node `http.Server` with `server.on("upgrade", ...)`.
97
+
98
+ ```ts
99
+ import { defineChannel, WS, createWebSocketUpgradeServer } from "experimental-ash/channels";
100
+
101
+ const bridge = createWebSocketUpgradeServer();
102
+
103
+ thirdPartySdk.attach(bridge.server);
104
+
105
+ export default defineChannel({
106
+ routes: [WS("/vendor/ws", bridge.route)],
107
+ });
108
+ ```
109
+
110
+ The bridge server does not listen on its own port. It receives only upgrade events that matched the
111
+ Ash route, and only on hosts where Nitro exposes the raw Node upgrade request, socket, and head. Treat
112
+ it as a compatibility adapter for libraries with server-binding APIs, not as the primary way to build
113
+ websocket channels in Ash.
114
+
92
115
  ## Cross-channel hand-off
93
116
 
94
117
  Route handlers can start a session on a different channel via `args.receive(channel, ...)`. Use this
@@ -4,13 +4,17 @@ description: "Wire your web app to an Ash agent."
4
4
  url: /frontend
5
5
  ---
6
6
 
7
- Ash ships first-class helpers for the two most common ways to put an agent
7
+ Ash ships first-class helpers for the most common ways to put an agent
8
8
  behind a web UI:
9
9
 
10
10
  - [Next.js](./nextjs.md) — `withAsh()` runs the Ash agent alongside your
11
11
  Next.js app.
12
- - [`useAshAgent`](./use-ash-agent.md) — React hook for chat and agent UIs in any
13
- React app.
12
+ - [Nuxt](./nuxt.md) — `experimental-ash/nuxt` module runs the Ash agent
13
+ alongside your Nuxt app.
14
+ - [`useAshAgent` (React)](./use-ash-agent.md) — React hook for chat and agent
15
+ UIs in any React app.
16
+ - [`useAshAgent` (Vue)](./use-ash-agent-vue.md) — Vue composable for chat and
17
+ agent UIs in any Vue app.
14
18
 
15
19
  For other stacks, call Ash directly over its HTTP routes —
16
- see [Sessions And Streaming](../runs-and-streaming.md).
20
+ see [Sessions And Streaming](../advanced/runs-and-streaming.md).
@@ -1,3 +1,11 @@
1
1
  {
2
- "pages": ["README", "nextjs", "use-ash-agent"]
2
+ "pages": [
3
+ "README",
4
+ "nextjs",
5
+ "nuxt",
6
+ "sveltekit",
7
+ "use-ash-agent",
8
+ "use-ash-agent-vue",
9
+ "use-ash-agent-svelte"
10
+ ]
3
11
  }
@@ -198,11 +198,11 @@ next call only). See [`useAshAgent`](./use-ash-agent.md#add-per-turn-client-cont
198
198
  for the full pattern.
199
199
 
200
200
  For server-side enrichment (policy, durable context, dynamic skills), use
201
- runtime lifecycle hooks instead. See [Hooks](../hooks.md).
201
+ runtime lifecycle hooks instead. See [Hooks](../advanced/hooks.mdx).
202
202
 
203
203
  ## What To Read Next
204
204
 
205
205
  - [`useAshAgent`](./use-ash-agent.md)
206
- - [Auth And Route Protection](../auth-and-route-protection.md)
207
- - [Hooks](../hooks.md)
208
- - [Sessions And Streaming](../runs-and-streaming.md)
206
+ - [Auth And Route Protection](../advanced/auth-and-route-protection.mdx)
207
+ - [Hooks](../advanced/hooks.mdx)
208
+ - [Sessions And Streaming](../advanced/runs-and-streaming.md)
@@ -0,0 +1,168 @@
1
+ ---
2
+ title: "Nuxt"
3
+ description: "Add an Ash agent to a Nuxt app and call it from the browser."
4
+ ---
5
+
6
+ `experimental-ash/nuxt` lets you ship a Nuxt frontend and an Ash agent as
7
+ one project. Come in from either side: drop it into an existing Nuxt app
8
+ to add an agent, or start with an agent and point a Nuxt project at it.
9
+
10
+ - **One dev server.** `nuxt dev` runs the app and the agent together.
11
+ - **One deploy.** Vercel ships them as a single project; no extra service to operate.
12
+ - **Zero URL plumbing.** `useAshAgent()` finds the mounted routes automatically; no CORS, no env vars.
13
+
14
+ ## Add Ash To Nuxt
15
+
16
+ Register the module in your Nuxt config:
17
+
18
+ ```ts
19
+ // nuxt.config.ts
20
+ export default defineNuxtConfig({
21
+ modules: ["experimental-ash/nuxt"],
22
+ });
23
+ ```
24
+
25
+ By default, the module looks for an `agent/` folder inside your Nuxt
26
+ project root. Pass `ashRoot` when the agent lives somewhere else:
27
+
28
+ ```ts
29
+ export default defineNuxtConfig({
30
+ modules: ["experimental-ash/nuxt"],
31
+ ash: {
32
+ ashRoot: "../my-agent",
33
+ },
34
+ });
35
+ ```
36
+
37
+ ## Add The Ash Channel
38
+
39
+ Skip this section if the framework default channel works for you. The module
40
+ already wires Ash up without it.
41
+
42
+ Create `agent/channels/ash.ts` when you want to choose the route auth policy
43
+ explicitly:
44
+
45
+ ```ts
46
+ // agent/channels/ash.ts
47
+ import { ashChannel } from "experimental-ash/channels/ash";
48
+ import { none } from "experimental-ash/channels/auth";
49
+
50
+ export default ashChannel({
51
+ auth: none(),
52
+ });
53
+ ```
54
+
55
+ For protected apps, replace `none()` with a channel auth helper such as
56
+ `vercelOidc()`, `oidc(...)`, or `httpBasic(...)`.
57
+
58
+ ## Use The Vue Composable
59
+
60
+ Once the module is in `nuxt.config.ts`, browser code can use
61
+ [`useAshAgent()`](./use-ash-agent-vue.md) without a custom host. The module
62
+ auto-imports the composable, so no explicit import is needed:
63
+
64
+ ```vue
65
+ <script setup lang="ts">
66
+ const { status, sendMessage } = useAshAgent();
67
+
68
+ const isBusy = computed(() => status.value === "submitted" || status.value === "streaming");
69
+
70
+ const message = ref("");
71
+
72
+ async function handleSubmit() {
73
+ const text = message.value.trim();
74
+ if (!text || isBusy.value) return;
75
+ message.value = "";
76
+ await sendMessage(text);
77
+ }
78
+ </script>
79
+
80
+ <template>
81
+ <form @submit.prevent="handleSubmit">
82
+ <input v-model="message" :disabled="isBusy" />
83
+ <button type="submit" :disabled="isBusy">Send</button>
84
+ </form>
85
+ </template>
86
+ ```
87
+
88
+ The composable handles conversation state, streaming updates, errors, and
89
+ messages for you. See [`useAshAgent` (Vue)](./use-ash-agent-vue.md) for the
90
+ full API.
91
+
92
+ ## Local Development
93
+
94
+ `pnpm dev` is enough. The module boots the Ash dev server alongside Nuxt
95
+ and proxies the Ash routes to it, so your browser keeps talking to the
96
+ Nuxt origin.
97
+
98
+ ## Vercel Deployments
99
+
100
+ On Vercel, the module keeps the web app public and the Ash runtime tucked
101
+ behind it. Users visit the Nuxt app, and the browser talks to the agent
102
+ through the same site origin.
103
+
104
+ Use `ashBuildCommand` when the agent needs a project-specific build command:
105
+
106
+ ```ts
107
+ export default defineNuxtConfig({
108
+ modules: ["experimental-ash/nuxt"],
109
+ ash: {
110
+ ashBuildCommand: "pnpm build:ash",
111
+ },
112
+ });
113
+ ```
114
+
115
+ ## Non-Vercel Production Hosts
116
+
117
+ If you deploy somewhere other than Vercel and the Ash service runs on a
118
+ separate origin, point Nuxt at it with `ASH_NUXT_PRODUCTION_ORIGIN`:
119
+
120
+ ```bash
121
+ ASH_NUXT_PRODUCTION_ORIGIN=https://agent.example.com pnpm build
122
+ ```
123
+
124
+ Set `ASH_NUXT_PRODUCTION_PORT` to use a different local port (default `4274`):
125
+
126
+ ```bash
127
+ ASH_NUXT_PRODUCTION_PORT=5000 pnpm build && pnpm preview
128
+ ```
129
+
130
+ ## Authenticated Requests
131
+
132
+ Because the agent runs on the same origin as your Nuxt app, the auth you
133
+ already use for the rest of the app applies to it for free. Cookie-based
134
+ sessions work without extra wiring: the browser already sends those cookies
135
+ on every Ash request.
136
+
137
+ For non-cookie schemes (bearer tokens, custom headers), attach them from the
138
+ client instead:
139
+
140
+ ```vue
141
+ <script setup lang="ts">
142
+ const agent = useAshAgent({
143
+ headers: async () => ({
144
+ authorization: `Bearer ${await getAccessToken()}`,
145
+ }),
146
+ });
147
+ </script>
148
+ ```
149
+
150
+ Prefer function values for short-lived credentials. Ash re-resolves them
151
+ before each HTTP request, including reconnects.
152
+
153
+ ## Add Per-Turn Page Context
154
+
155
+ `useAshAgent()` accepts a `prepareSend` callback for attaching one-turn page
156
+ state (pathname, selected ids, anything else the model should see for the
157
+ next call only). See [`useAshAgent` (Vue)](./use-ash-agent-vue.md#add-per-turn-client-context)
158
+ for the full pattern.
159
+
160
+ For server-side enrichment (policy, durable context, dynamic skills), use
161
+ runtime lifecycle hooks instead. See [Hooks](../advanced/hooks.mdx).
162
+
163
+ ## What To Read Next
164
+
165
+ - [`useAshAgent` (Vue)](./use-ash-agent-vue.md)
166
+ - [Auth And Route Protection](../advanced/auth-and-route-protection.mdx)
167
+ - [Hooks](../advanced/hooks.mdx)
168
+ - [Sessions And Streaming](../advanced/runs-and-streaming.md)
@@ -0,0 +1,177 @@
1
+ ---
2
+ title: "SvelteKit"
3
+ description: "Add an Ash agent to a SvelteKit app and call it from the browser."
4
+ ---
5
+
6
+ `experimental-ash/sveltekit` lets you ship a SvelteKit frontend and an Ash
7
+ agent as one project. Add the Vite plugin to an existing SvelteKit app, or
8
+ start with an agent and point a SvelteKit project at it.
9
+
10
+ - **One dev server.** `vite dev` runs the app and the agent together.
11
+ - **One deploy.** Vercel ships them as a single project; no extra service to operate.
12
+ - **Zero URL plumbing.** `useAshAgent()` finds the mounted routes automatically; no CORS, no env vars.
13
+
14
+ ## Add Ash To SvelteKit
15
+
16
+ Register the plugin in your Vite config:
17
+
18
+ ```ts
19
+ // vite.config.ts
20
+ import { sveltekit } from "@sveltejs/kit/vite";
21
+ import { ashSvelteKit } from "experimental-ash/sveltekit";
22
+ import { defineConfig } from "vite";
23
+
24
+ export default defineConfig({
25
+ plugins: [ashSvelteKit(), sveltekit()],
26
+ });
27
+ ```
28
+
29
+ By default, the plugin looks for an `agent/` folder inside your SvelteKit
30
+ project root. Pass `ashRoot` when the agent lives somewhere else:
31
+
32
+ ```ts
33
+ export default defineConfig({
34
+ plugins: [
35
+ ashSvelteKit({
36
+ ashRoot: "../my-agent",
37
+ }),
38
+ sveltekit(),
39
+ ],
40
+ });
41
+ ```
42
+
43
+ ## Add The Ash Channel
44
+
45
+ Skip this section if the framework default channel works for you. The plugin
46
+ already wires Ash up without it.
47
+
48
+ Create `agent/channels/ash.ts` when you want to choose the route auth policy
49
+ explicitly:
50
+
51
+ ```ts
52
+ // agent/channels/ash.ts
53
+ import { ashChannel } from "experimental-ash/channels/ash";
54
+ import { none } from "experimental-ash/channels/auth";
55
+
56
+ export default ashChannel({
57
+ auth: none(),
58
+ });
59
+ ```
60
+
61
+ For protected apps, replace `none()` with a channel auth helper such as
62
+ `vercelOidc()`, `oidc(...)`, or `httpBasic(...)`.
63
+
64
+ ## Use The Svelte Binding
65
+
66
+ Once the plugin is in `vite.config.ts`, browser code can use
67
+ [`useAshAgent()`](./use-ash-agent-svelte.md) without a custom host:
68
+
69
+ ```svelte
70
+ <script lang="ts">
71
+ import { useAshAgent } from "experimental-ash/svelte";
72
+
73
+ const agent = useAshAgent();
74
+ let message = $state("");
75
+ let isBusy = $derived(agent.status === "submitted" || agent.status === "streaming");
76
+
77
+ async function handleSubmit() {
78
+ const text = message.trim();
79
+ if (!text || isBusy) return;
80
+ message = "";
81
+ await agent.sendMessage(text);
82
+ }
83
+ </script>
84
+
85
+ <form onsubmit={(event) => {
86
+ event.preventDefault();
87
+ void handleSubmit();
88
+ }}>
89
+ <input bind:value={message} disabled={isBusy} />
90
+ <button type="submit" disabled={isBusy}>Send</button>
91
+ </form>
92
+ ```
93
+
94
+ The binding handles conversation state, streaming updates, errors, and messages
95
+ for you. See [`useAshAgent` (Svelte)](./use-ash-agent-svelte.md) for the full
96
+ API.
97
+
98
+ ## Local Development
99
+
100
+ `pnpm dev` is enough. The plugin boots the Ash dev server alongside SvelteKit
101
+ and proxies the Ash routes to it, so your browser keeps talking to the
102
+ SvelteKit origin.
103
+
104
+ `pnpm build && pnpm preview` works the same way for local production preview:
105
+ the preview server gets its own Ash route proxy and reuses or starts the shared
106
+ Ash server automatically.
107
+
108
+ ## Vercel Deployments
109
+
110
+ On Vercel, the plugin keeps the web app public and the Ash runtime tucked
111
+ behind it. Users visit the SvelteKit app, and the browser talks to the agent
112
+ through the same site origin.
113
+
114
+ Use `ashBuildCommand` when the agent needs a project-specific build command:
115
+
116
+ ```ts
117
+ export default defineConfig({
118
+ plugins: [
119
+ ashSvelteKit({
120
+ ashBuildCommand: "pnpm build:ash",
121
+ }),
122
+ sveltekit(),
123
+ ],
124
+ });
125
+ ```
126
+
127
+ ## Non-Vercel Production Hosts
128
+
129
+ If you deploy somewhere other than Vercel and the Ash service runs on a
130
+ separate origin, pass `host` directly to `useAshAgent`:
131
+
132
+ ```ts
133
+ const agent = useAshAgent({
134
+ host: "https://agent.example.com",
135
+ });
136
+ ```
137
+
138
+ ## Authenticated Requests
139
+
140
+ Because the agent runs on the same origin as your SvelteKit app, the auth you
141
+ already use for the rest of the app applies to it for free. Cookie-based
142
+ sessions work without extra wiring: the browser already sends those cookies on
143
+ every Ash request.
144
+
145
+ For non-cookie schemes (bearer tokens, custom headers), attach them from the
146
+ client instead:
147
+
148
+ ```svelte
149
+ <script lang="ts">
150
+ const agent = useAshAgent({
151
+ headers: async () => ({
152
+ authorization: `Bearer ${await getAccessToken()}`,
153
+ }),
154
+ });
155
+ </script>
156
+ ```
157
+
158
+ Prefer function values for short-lived credentials. Ash re-resolves them before
159
+ each HTTP request, including reconnects.
160
+
161
+ ## Add Per-Turn Page Context
162
+
163
+ `useAshAgent()` accepts a `prepareSend` callback for attaching one-turn page
164
+ state (pathname, selected ids, anything else the model should see for the next
165
+ call only). See
166
+ [`useAshAgent` (Svelte)](./use-ash-agent-svelte.md#add-per-turn-client-context)
167
+ for the full pattern.
168
+
169
+ For server-side enrichment (policy, durable context, dynamic skills), use
170
+ runtime lifecycle hooks instead. See [Hooks](../advanced/hooks.mdx).
171
+
172
+ ## What To Read Next
173
+
174
+ - [`useAshAgent` (Svelte)](./use-ash-agent-svelte.md)
175
+ - [Auth And Route Protection](../advanced/auth-and-route-protection.mdx)
176
+ - [Hooks](../advanced/hooks.mdx)
177
+ - [Sessions And Streaming](../advanced/runs-and-streaming.md)