experimental-ash 0.61.0 → 0.63.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 (130) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/dist/docs/public/advanced/hooks.mdx +8 -2
  3. package/dist/docs/public/advanced/runs-and-streaming.md +6 -3
  4. package/dist/docs/public/advanced/typescript-api.md +32 -0
  5. package/dist/docs/public/channels/custom.mdx +23 -0
  6. package/dist/docs/public/frontend/README.md +8 -4
  7. package/dist/docs/public/frontend/meta.json +9 -1
  8. package/dist/docs/public/frontend/nextjs.md +4 -4
  9. package/dist/docs/public/frontend/nuxt.md +168 -0
  10. package/dist/docs/public/frontend/sveltekit.md +177 -0
  11. package/dist/docs/public/frontend/use-ash-agent-svelte.md +185 -0
  12. package/dist/docs/public/frontend/use-ash-agent-vue.md +236 -0
  13. package/dist/docs/public/frontend/use-ash-agent.md +14 -14
  14. package/dist/docs/public/getting-started.mdx +2 -0
  15. package/dist/skills/ash-add-agent/SKILL.md +29 -17
  16. package/dist/skills/ash-add-next/SKILL.md +58 -8
  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-BQJLh7KU.js +1224 -0
  20. package/dist/src/chunks/use-ash-agent-CRWVA4i-.js +1192 -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/index.d.ts +2 -0
  24. package/dist/src/client/index.js +1 -1
  25. package/dist/src/compiled/.vendor-stamp.json +9 -9
  26. package/dist/src/compiled/@ai-sdk/anthropic/_provider-utils.d.ts +1 -1
  27. package/dist/src/compiled/@ai-sdk/anthropic/index.d.ts +3 -3
  28. package/dist/src/compiled/@ai-sdk/anthropic/index.js +2 -2
  29. package/dist/src/compiled/@ai-sdk/google/index.d.ts +52 -2
  30. package/dist/src/compiled/@ai-sdk/google/index.js +6 -6
  31. package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
  32. package/dist/src/compiled/@ai-sdk/openai/index.d.ts +32 -2
  33. package/dist/src/compiled/@ai-sdk/openai/index.js +2 -2
  34. package/dist/src/compiled/@ai-sdk/provider/index.d.ts +507 -1
  35. package/dist/src/compiled/@chat-adapter/slack/index.js +25 -25
  36. package/dist/src/compiled/@workflow/core/events-consumer.d.ts +8 -0
  37. package/dist/src/compiled/@workflow/core/index.js +2 -2
  38. package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +1 -0
  39. package/dist/src/compiled/@workflow/core/runtime.js +29 -29
  40. package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
  41. package/dist/src/compiled/@workflow/core/workflow.js +1 -1
  42. package/dist/src/compiled/@workflow/errors/error-codes.d.ts +2 -0
  43. package/dist/src/compiled/@workflow/errors/index.d.ts +14 -0
  44. package/dist/src/compiled/@workflow/errors/index.js +1 -1
  45. package/dist/src/compiled/@workflow/world/queue.d.ts +8 -0
  46. package/dist/src/compiled/_chunks/workflow/{dist-Chj-QcBs.js → dist-gEXVSMPU.js} +1 -1
  47. package/dist/src/compiled/_chunks/workflow/dist-zpK2YVVA.js +3 -0
  48. package/dist/src/compiled/_chunks/workflow/resume-hook-BFK9mgsb.js +12 -0
  49. package/dist/src/compiled/_chunks/workflow/{sleep-Bg0t23kF.js → sleep-CeJckNg2.js} +1 -1
  50. package/dist/src/compiled/_chunks/workflow/{symbols-u476uwyR.js → symbols-BWCAoPHE.js} +1 -1
  51. package/dist/src/compiler/manifest.d.ts +12 -0
  52. package/dist/src/compiler/manifest.js +1 -1
  53. package/dist/src/compiler/normalize-connection.d.ts +10 -2
  54. package/dist/src/compiler/normalize-connection.js +1 -1
  55. package/dist/src/execution/sandbox/bindings/local.js +1 -1
  56. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  57. package/dist/src/internal/application/package.d.ts +1 -0
  58. package/dist/src/internal/application/package.js +1 -1
  59. package/dist/src/internal/authored-definition/connection.d.ts +9 -0
  60. package/dist/src/internal/authored-definition/connection.js +1 -1
  61. package/dist/src/internal/nitro/host/build-application.js +1 -1
  62. package/dist/src/internal/nitro/host/build-vercel-agent-summary.js +1 -1
  63. package/dist/src/internal/nitro/host/channel-routes.js +2 -2
  64. package/dist/src/internal/vercel-agent-summary.d.ts +6 -4
  65. package/dist/src/internal/workflow-bundle/ash-service-route-output.js +11 -1
  66. package/dist/src/packages/ash-scaffold/src/channels.js +1 -1
  67. package/dist/src/public/channels/auth.d.ts +1 -1
  68. package/dist/src/public/channels/index.d.ts +1 -0
  69. package/dist/src/public/channels/index.js +1 -1
  70. package/dist/src/public/connections/index.d.ts +3 -2
  71. package/dist/src/public/connections/index.js +1 -1
  72. package/dist/src/public/definitions/connections/mcp.d.ts +4 -12
  73. package/dist/src/public/definitions/connections/mcp.js +1 -1
  74. package/dist/src/public/definitions/connections/openapi.d.ts +100 -0
  75. package/dist/src/public/definitions/connections/openapi.js +1 -0
  76. package/dist/src/public/definitions/connections/protocol.d.ts +12 -0
  77. package/dist/src/public/definitions/connections/protocol.js +1 -0
  78. package/dist/src/public/next/index.d.ts +6 -6
  79. package/dist/src/public/next/index.js +1 -1
  80. package/dist/src/public/next/{vercel-json.d.ts → vercel-output-config.d.ts} +3 -3
  81. package/dist/src/public/next/vercel-output-config.js +1 -0
  82. package/dist/src/public/nuxt/dev-server.d.ts +24 -0
  83. package/dist/src/public/nuxt/dev-server.js +1 -0
  84. package/dist/src/public/nuxt/index.d.ts +1 -0
  85. package/dist/src/public/nuxt/index.js +1 -0
  86. package/dist/src/public/nuxt/module.d.ts +31 -0
  87. package/dist/src/public/nuxt/module.js +1 -0
  88. package/dist/src/public/nuxt/routing.d.ts +55 -0
  89. package/dist/src/public/nuxt/routing.js +1 -0
  90. package/dist/src/public/nuxt/vercel-json.d.ts +17 -0
  91. package/dist/src/public/{next → nuxt}/vercel-json.js +1 -1
  92. package/dist/src/public/sveltekit/dev-server.d.ts +24 -0
  93. package/dist/src/public/sveltekit/dev-server.js +1 -0
  94. package/dist/src/public/sveltekit/index.d.ts +39 -0
  95. package/dist/src/public/sveltekit/index.js +1 -0
  96. package/dist/src/public/sveltekit/routing.d.ts +32 -0
  97. package/dist/src/public/sveltekit/routing.js +1 -0
  98. package/dist/src/public/sveltekit/vercel-json.d.ts +17 -0
  99. package/dist/src/public/sveltekit/vercel-json.js +1 -0
  100. package/dist/src/react/use-ash-agent.d.ts +5 -27
  101. package/dist/src/react/use-ash-agent.js +1 -2
  102. package/dist/src/runtime/connections/openapi-client.d.ts +43 -0
  103. package/dist/src/runtime/connections/openapi-client.js +1 -0
  104. package/dist/src/runtime/connections/openapi-operations.d.ts +30 -0
  105. package/dist/src/runtime/connections/openapi-operations.js +1 -0
  106. package/dist/src/runtime/connections/openapi-schema.d.ts +39 -0
  107. package/dist/src/runtime/connections/openapi-schema.js +1 -0
  108. package/dist/src/runtime/connections/openapi-security.d.ts +41 -0
  109. package/dist/src/runtime/connections/openapi-security.js +1 -0
  110. package/dist/src/runtime/connections/openapi-spec.d.ts +20 -0
  111. package/dist/src/runtime/connections/openapi-spec.js +1 -0
  112. package/dist/src/runtime/connections/registry.d.ts +5 -7
  113. package/dist/src/runtime/connections/registry.js +1 -1
  114. package/dist/src/runtime/connections/types.d.ts +23 -0
  115. package/dist/src/runtime/resolve-connection.js +1 -1
  116. package/dist/src/runtime/types.d.ts +15 -1
  117. package/dist/src/shared/sandbox-session.d.ts +1 -1
  118. package/dist/src/shared/vercel-output-directory.d.ts +2 -0
  119. package/dist/src/shared/vercel-output-directory.js +1 -0
  120. package/dist/src/svelte/index.d.ts +3 -0
  121. package/dist/src/svelte/index.js +3 -0
  122. package/dist/src/svelte/use-ash-agent.d.ts +80 -0
  123. package/dist/src/svelte/use-ash-agent.js +3 -0
  124. package/dist/src/vue/index.d.ts +3 -0
  125. package/dist/src/vue/index.js +3 -0
  126. package/dist/src/vue/use-ash-agent.d.ts +78 -0
  127. package/dist/src/vue/use-ash-agent.js +3 -0
  128. package/package.json +59 -14
  129. package/dist/src/compiled/_chunks/workflow/dist-C4EHshZE.js +0 -3
  130. package/dist/src/compiled/_chunks/workflow/resume-hook-BlALLgSA.js +0 -12
@@ -0,0 +1,185 @@
1
+ ---
2
+ title: "useAshAgent (Svelte)"
3
+ description: "Svelte 5 binding that drives an Ash agent session from the browser."
4
+ ---
5
+
6
+ `useAshAgent()` is a Svelte 5 binding that opens a long-lived Ash session in
7
+ the browser, lets the user send turns, and projects every stream event into
8
+ rune-friendly reactive data for your template.
9
+
10
+ The simplest usage:
11
+
12
+ ```svelte
13
+ <script lang="ts">
14
+ import { useAshAgent } from "experimental-ash/svelte";
15
+
16
+ const agent = useAshAgent();
17
+ </script>
18
+
19
+ {#each agent.data.messages as message}
20
+ <p>{message.role}: {JSON.stringify(message.parts)}</p>
21
+ {/each}
22
+ ```
23
+
24
+ ## What It Returns
25
+
26
+ `useAshAgent()` returns an object with reactive properties and action methods:
27
+
28
+ | Property | Type | Description |
29
+ | ------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
30
+ | `data` | `TData` | Projected state built by reducing every stream event through the reducer. With the default reducer this is `AshMessageData` containing a `messages` array. |
31
+ | `status` | `UseAshAgentStatus` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"` |
32
+ | `error` | `Error \| undefined` | Last transport-level error |
33
+ | `events` | `readonly HandleMessageStreamEvent[]` | Raw server events for this session |
34
+ | `session` | `SessionState` | Snapshot of session state |
35
+ | `send` | `(input, options?) => Promise<void>` | Send a turn with full options |
36
+ | `sendMessage` | `(message, options?) => Promise<void>` | Shorthand: send a plain text turn |
37
+ | `stop` | `() => void` | Abort the in-flight request |
38
+ | `reset` | `() => void` | Clear state and start a new session |
39
+
40
+ The state fields are reactive getters. Read them directly from templates,
41
+ `$derived`, or `$effect`; do not prefix them with `$` like Svelte stores.
42
+
43
+ ## Send A Message
44
+
45
+ ```svelte
46
+ <script lang="ts">
47
+ import { useAshAgent } from "experimental-ash/svelte";
48
+
49
+ const agent = useAshAgent();
50
+ let message = $state("");
51
+
52
+ async function handleSubmit() {
53
+ const text = message.trim();
54
+ if (!text) return;
55
+ message = "";
56
+ await agent.sendMessage(text);
57
+ }
58
+ </script>
59
+
60
+ <form onsubmit={(event) => {
61
+ event.preventDefault();
62
+ void handleSubmit();
63
+ }}>
64
+ <input bind:value={message} placeholder="Type a message..." />
65
+ <button type="submit">Send</button>
66
+ </form>
67
+ ```
68
+
69
+ ## Send Attachments
70
+
71
+ Use `send()` for structured input. Attachments use the AI SDK `UserContent`
72
+ format:
73
+
74
+ ```ts
75
+ await agent.send({
76
+ message: [
77
+ { type: "text", text: "Describe this image." },
78
+ { type: "file", data: fileBytes, mimeType: "image/png" },
79
+ ],
80
+ });
81
+ ```
82
+
83
+ ## Respond To Human-In-The-Loop Prompts
84
+
85
+ When the agent requests human input (tool approvals, confirmations), the
86
+ `inputRequest` shows up inside `message.parts` on `dynamic-tool` parts. Send
87
+ `inputResponses` back:
88
+
89
+ ```ts
90
+ await agent.send({
91
+ inputResponses: [{ requestId: inputRequest.requestId, optionId: "approve" }],
92
+ });
93
+ ```
94
+
95
+ ## Stop And Reset
96
+
97
+ ```ts
98
+ agent.stop(); // abort the in-flight stream
99
+ agent.reset(); // wipe state and create a new session
100
+ ```
101
+
102
+ ## Resumable Sessions
103
+
104
+ Pass `initialSession` to restore a session from a prior page load:
105
+
106
+ ```ts
107
+ const agent = useAshAgent({
108
+ initialSession: savedSessionState,
109
+ initialEvents: savedEvents,
110
+ });
111
+ ```
112
+
113
+ ## Add Per-Turn Client Context
114
+
115
+ Use `prepareSend` to attach short-lived page state to each turn:
116
+
117
+ ```ts
118
+ const agent = useAshAgent({
119
+ prepareSend(input) {
120
+ return {
121
+ ...input,
122
+ clientContext: {
123
+ pathname: window.location.pathname,
124
+ },
125
+ };
126
+ },
127
+ });
128
+ ```
129
+
130
+ ## Custom Host And Auth
131
+
132
+ Use `host` for non-standard routing, and `auth` or `headers` for credentials:
133
+
134
+ ```ts
135
+ const agent = useAshAgent({
136
+ host: "https://agent.example.com",
137
+ headers: async () => ({
138
+ authorization: `Bearer ${await getAccessToken()}`,
139
+ }),
140
+ });
141
+ ```
142
+
143
+ ## Custom Reducer
144
+
145
+ Pass a custom `reducer` to control how stream events project into `data`:
146
+
147
+ ```ts
148
+ import { useAshAgent, type AshAgentReducer } from "experimental-ash/svelte";
149
+
150
+ interface MyData {
151
+ turns: number;
152
+ }
153
+
154
+ const reducer: AshAgentReducer<MyData> = {
155
+ initial: () => ({ turns: 0 }),
156
+ reduce: (data, event) => {
157
+ if (event.type === "turn.completed") {
158
+ return { turns: data.turns + 1 };
159
+ }
160
+ return data;
161
+ },
162
+ };
163
+
164
+ const agent = useAshAgent({ reducer });
165
+ // agent.data is MyData
166
+ ```
167
+
168
+ ## Lifecycle Callbacks
169
+
170
+ ```ts
171
+ const agent = useAshAgent({
172
+ onError: (error) => console.error(error),
173
+ onEvent: (event) => console.log(event.type),
174
+ onFinish: (snapshot) => console.log("done", snapshot.status),
175
+ onSessionChange: (session) => {
176
+ localStorage.setItem("ash-session", JSON.stringify(session));
177
+ },
178
+ });
179
+ ```
180
+
181
+ ## What To Read Next
182
+
183
+ - [SvelteKit](./sveltekit.md) - framework setup
184
+ - [Sessions And Streaming](../advanced/runs-and-streaming.md) - under the hood
185
+ - [TypeScript API](../advanced/typescript-api.md) - client exports
@@ -0,0 +1,236 @@
1
+ ---
2
+ title: "useAshAgent (Vue)"
3
+ description: "Vue composable that drives an Ash agent session from the browser."
4
+ ---
5
+
6
+ `useAshAgent()` is a Vue composable that opens a long-lived Ash session
7
+ in the browser, lets the user send turns, and projects every stream event
8
+ into reactive data for your template.
9
+
10
+ The simplest usage:
11
+
12
+ ```vue
13
+ <script setup lang="ts">
14
+ import { useAshAgent } from "experimental-ash/vue";
15
+
16
+ const { data } = useAshAgent();
17
+ </script>
18
+
19
+ <template>
20
+ <div v-for="message in data.messages" :key="message.id">
21
+ <p>{{ message.role }}: {{ message.parts }}</p>
22
+ </div>
23
+ </template>
24
+ ```
25
+
26
+ ## What It Returns
27
+
28
+ `useAshAgent()` returns an object of computed refs and action methods:
29
+
30
+ | Property | Type | Description |
31
+ | ------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
32
+ | `data` | `ComputedRef<TData>` | Projected state built by reducing every stream event through the reducer. With the default reducer this is `AshMessageData` containing a `messages` array. |
33
+ | `status` | `ComputedRef<UseAshAgentStatus>` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"` |
34
+ | `error` | `ComputedRef<Error \| undefined>` | Last transport-level error |
35
+ | `events` | `ComputedRef<readonly HandleMessageStreamEvent[]>` | Raw server events for this session |
36
+ | `session` | `ComputedRef<SessionState>` | Snapshot of session state |
37
+ | `send` | `(input, options?) => Promise<void>` | Send a turn with full options |
38
+ | `sendMessage` | `(message, options?) => Promise<void>` | Shorthand: send a plain text turn |
39
+ | `stop` | `() => void` | Abort the in-flight request |
40
+ | `reset` | `() => void` | Clear state and start a new session |
41
+
42
+ The state properties (`data`, `status`, `error`, `events`, `session`) are
43
+ `ComputedRef`s; the rest are methods. Destructure whatever you need — refs keep
44
+ their reactivity through destructuring — and read them with `.value` in
45
+ `<script>` or unwrapped (no `.value`) in `<template>`.
46
+
47
+ ## Send A Message
48
+
49
+ ```vue
50
+ <script setup lang="ts">
51
+ import { useAshAgent } from "experimental-ash/vue";
52
+
53
+ const { sendMessage } = useAshAgent();
54
+ const message = ref("");
55
+
56
+ async function handleSubmit() {
57
+ const text = message.value.trim();
58
+ if (!text) return;
59
+ message.value = "";
60
+ await sendMessage(text);
61
+ }
62
+ </script>
63
+
64
+ <template>
65
+ <form @submit.prevent="handleSubmit">
66
+ <input v-model="message" placeholder="Type a message..." />
67
+ <button type="submit">Send</button>
68
+ </form>
69
+ </template>
70
+ ```
71
+
72
+ ## Send Attachments
73
+
74
+ Use `send()` for structured input. Attachments use the AI SDK `UserContent`
75
+ format:
76
+
77
+ ```vue
78
+ <script setup lang="ts">
79
+ import { useAshAgent } from "experimental-ash/vue";
80
+
81
+ const { send } = useAshAgent();
82
+
83
+ async function onFileChange(event: Event) {
84
+ const file = (event.target as HTMLInputElement).files?.[0];
85
+ if (!file) return;
86
+ await send({
87
+ message: [
88
+ { type: "text", text: "Describe this image." },
89
+ { type: "file", data: new Uint8Array(await file.arrayBuffer()), mediaType: file.type },
90
+ ],
91
+ });
92
+ }
93
+ </script>
94
+
95
+ <template>
96
+ <input type="file" accept="image/*" @change="onFileChange" />
97
+ </template>
98
+ ```
99
+
100
+ ## Respond To Human-In-The-Loop Prompts
101
+
102
+ When the agent requests human input (tool approvals, confirmations),
103
+ the `inputRequest` shows up inside `message.parts` on `dynamic-tool` parts.
104
+ Send `inputResponses` back:
105
+
106
+ ```vue
107
+ <script setup lang="ts">
108
+ import { useAshAgent, type AshDynamicToolPart } from "experimental-ash/vue";
109
+
110
+ const props = defineProps<{ part: AshDynamicToolPart }>();
111
+
112
+ const { send } = useAshAgent();
113
+
114
+ const inputRequest = computed(() => props.part.toolMetadata?.ash?.inputRequest);
115
+
116
+ function respond(optionId: string) {
117
+ const request = inputRequest.value;
118
+ if (!request) return;
119
+ void send({ inputResponses: [{ requestId: request.requestId, optionId }] });
120
+ }
121
+ </script>
122
+
123
+ <template>
124
+ <div v-if="inputRequest">
125
+ <p>{{ inputRequest.prompt }}</p>
126
+ <button v-for="option in inputRequest.options" :key="option.id" @click="respond(option.id)">
127
+ {{ option.label }}
128
+ </button>
129
+ </div>
130
+ </template>
131
+ ```
132
+
133
+ ## Stop And Reset
134
+
135
+ Abort the in-flight stream, or wipe state and start a fresh session:
136
+
137
+ ```vue
138
+ <script setup lang="ts">
139
+ import { useAshAgent } from "experimental-ash/vue";
140
+
141
+ const { status, stop, reset } = useAshAgent();
142
+
143
+ const isBusy = computed(() => status.value === "submitted" || status.value === "streaming");
144
+ </script>
145
+
146
+ <template>
147
+ <button :disabled="!isBusy" @click="stop()">Stop</button>
148
+ <button @click="reset()">Reset</button>
149
+ </template>
150
+ ```
151
+
152
+ ## Resumable Sessions
153
+
154
+ Pass `initialSession` to restore a session from a prior page load:
155
+
156
+ ```ts
157
+ const agent = useAshAgent({
158
+ initialSession: savedSessionState,
159
+ initialEvents: savedEvents,
160
+ });
161
+ ```
162
+
163
+ ## Add Per-Turn Client Context
164
+
165
+ Use `prepareSend` to attach short-lived page state to each turn:
166
+
167
+ ```ts
168
+ const agent = useAshAgent({
169
+ prepareSend(input) {
170
+ return {
171
+ ...input,
172
+ clientContext: {
173
+ pathname: window.location.pathname,
174
+ },
175
+ };
176
+ },
177
+ });
178
+ ```
179
+
180
+ ## Custom Host And Auth
181
+
182
+ Use `host` for non-standard routing, and `auth` or `headers` for
183
+ credentials:
184
+
185
+ ```ts
186
+ const agent = useAshAgent({
187
+ host: "https://agent.example.com",
188
+ headers: async () => ({
189
+ authorization: `Bearer ${await getAccessToken()}`,
190
+ }),
191
+ });
192
+ ```
193
+
194
+ ## Custom Reducer
195
+
196
+ Pass a custom `reducer` to control how stream events project into `data`:
197
+
198
+ ```ts
199
+ import { useAshAgent, type AshAgentReducer } from "experimental-ash/vue";
200
+
201
+ interface MyData {
202
+ turns: number;
203
+ }
204
+
205
+ const reducer: AshAgentReducer<MyData> = {
206
+ initial: () => ({ turns: 0 }),
207
+ reduce: (data, event) => {
208
+ if (event.type === "turn.completed") {
209
+ return { turns: data.turns + 1 };
210
+ }
211
+ return data;
212
+ },
213
+ };
214
+
215
+ const { data } = useAshAgent({ reducer });
216
+ // data.value is MyData
217
+ ```
218
+
219
+ ## Lifecycle Callbacks
220
+
221
+ ```ts
222
+ const agent = useAshAgent({
223
+ onError: (error) => console.error(error),
224
+ onEvent: (event) => console.log(event.type),
225
+ onFinish: (snapshot) => console.log("done", snapshot.status),
226
+ onSessionChange: (session) => {
227
+ localStorage.setItem("ash-session", JSON.stringify(session));
228
+ },
229
+ });
230
+ ```
231
+
232
+ ## What To Read Next
233
+
234
+ - [Nuxt](./nuxt.md) — module setup
235
+ - [Sessions And Streaming](../advanced/runs-and-streaming.md) — under the hood
236
+ - [TypeScript API](../advanced/typescript-api.md) — client exports
@@ -60,17 +60,17 @@ your component can call the agent without configuring a separate URL.
60
60
 
61
61
  `useAshAgent()` returns the current UI state plus commands:
62
62
 
63
- | Field | What it is |
64
- | ------------- | ------------------------------------------------------------------------------------------------ |
65
- | `data` | Projected UI state from the reducer. Defaults to `{ messages }`. |
66
- | `status` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. Drives the composer. |
67
- | `error` | The last `Error` thrown, if any. |
68
- | `events` | Raw Ash stream events for this session — see [Sessions And Streaming](../runs-and-streaming.md). |
69
- | `session` | Serializable session cursor (`sessionId`, `continuationToken`, `streamIndex`). |
70
- | `sendMessage` | Send plain text. |
71
- | `send` | Send the full turn payload (multi-part messages, HITL responses). |
72
- | `stop` | Abort the active request. |
73
- | `reset` | Clear local events, data, errors, and the local session cursor. |
63
+ | Field | What it is |
64
+ | ------------- | --------------------------------------------------------------------------------------------------------- |
65
+ | `data` | Projected UI state from the reducer. Defaults to `{ messages }`. |
66
+ | `status` | `"ready"`, `"submitted"`, `"streaming"`, or `"error"`. Drives the composer. |
67
+ | `error` | The last `Error` thrown, if any. |
68
+ | `events` | Raw Ash stream events for this session — see [Sessions And Streaming](../advanced/runs-and-streaming.md). |
69
+ | `session` | Serializable session cursor (`sessionId`, `continuationToken`, `streamIndex`). |
70
+ | `sendMessage` | Send plain text. |
71
+ | `send` | Send the full turn payload (multi-part messages, HITL responses). |
72
+ | `stop` | Abort the active request. |
73
+ | `reset` | Clear local events, data, errors, and the local session cursor. |
74
74
 
75
75
  Most chat UIs only need `data.messages` and `status`. Reach for `events` when
76
76
  you want to render lower-level activity (tool calls, reasoning deltas) the
@@ -286,7 +286,7 @@ const agent = useAshAgent({
286
286
  ```
287
287
 
288
288
  `agent.data.tools` now drives the UI. The reducer sees the full Ash event
289
- stream — see [Sessions And Streaming](../runs-and-streaming.md) — plus
289
+ stream — see [Sessions And Streaming](../advanced/runs-and-streaming.md) — plus
290
290
  client-side projection events (`client.message.submitted`,
291
291
  `client.message.failed`, `client.input.responded`) for optimistic updates.
292
292
 
@@ -323,6 +323,6 @@ To change credentials without remounting, pass a function to `auth` or
323
323
  ## What To Read Next
324
324
 
325
325
  - [Next.js](./nextjs.md)
326
- - [Sessions And Streaming](../runs-and-streaming.md)
326
+ - [Sessions And Streaming](../advanced/runs-and-streaming.md)
327
327
  - [Human In The Loop](../human-in-the-loop.md)
328
- - [Hooks](../hooks.md)
328
+ - [Hooks](../advanced/hooks.mdx)
@@ -174,3 +174,5 @@ curl -X POST http://127.0.0.1:3000/ash/v1/session/<sessionId> \
174
174
  - [Skills](./skills.md) for on-demand procedures
175
175
  - [Tools](./tools.mdx) for typed integrations
176
176
  - [Sessions And Streaming](./runs-and-streaming.md) for the durable session model
177
+ - [Nuxt Integration](./frontend/nuxt.md) for Nuxt apps
178
+ - [`useAshAgent` (Vue)](./frontend/use-ash-agent-vue.md) for Vue composable usage
@@ -20,7 +20,6 @@ app/
20
20
  next.config.ts
21
21
  package.json
22
22
  tsconfig.json
23
- vercel.json # generated/updated by withAsh()
24
23
  ```
25
24
 
26
25
  ## Steps
@@ -52,28 +51,43 @@ Use the model requested by the user or the project standard.
52
51
 
53
52
  3. Add the Ash HTTP channel:
54
53
 
54
+ First inspect the existing Next.js app for authentication. Reuse its current provider and session
55
+ model instead of introducing a second auth system. Look for Auth.js, Clerk, application session
56
+ cookies, bearer-token middleware, or another established request-auth helper.
57
+
55
58
  ```ts
56
59
  // agent/channels/ash.ts
57
60
  import { ashChannel } from "experimental-ash/channels/ash";
58
61
  import { type AuthFn, localDev, vercelOidc } from "experimental-ash/channels/auth";
59
62
 
60
- function exampleProductionAuth(): AuthFn<Request> {
61
- return () => {
62
- if (process.env.VERCEL_ENV === "production") {
63
- throw new Error(
64
- "Configure production auth in agent/channels/ash.ts (e.g. Auth.js or Clerk).",
65
- );
66
- }
67
- return null;
63
+ const authenticateUser: AuthFn = async (request) => {
64
+ // Replace this call with the app's existing Auth.js, Clerk, or session helper.
65
+ const user = await authenticate(request);
66
+ if (!user) return null;
67
+
68
+ return {
69
+ attributes: {},
70
+ authenticator: "app",
71
+ issuer: "nextjs",
72
+ principalId: user.id,
73
+ principalType: "user",
68
74
  };
69
- }
75
+ };
70
76
 
71
77
  export default ashChannel({
72
- auth: [localDev(), vercelOidc(), exampleProductionAuth()],
78
+ auth: [localDev(), vercelOidc(), authenticateUser],
73
79
  });
74
80
  ```
75
81
 
76
- An authored `agent/channels/ash.ts` replaces Ash's framework default `ash` channel. Keep `localDev()` for localhost and the REPL, keep `vercelOidc()` so Vercel services can reach the deployed agent, and replace `exampleProductionAuth()` with the app's real user auth before production. If the app already uses Auth.js, Clerk, or another session provider, wire it here instead of leaving the placeholder.
82
+ An authored `agent/channels/ash.ts` replaces Ash's framework default `ash` channel. Keep
83
+ `localDev()` for localhost and the REPL, keep `vercelOidc()` so Vercel services can reach the
84
+ deployed agent, and implement `authenticateUser` with the app's real user auth. If the app already
85
+ uses Auth.js, Clerk, or another session provider, wire that existing provider here.
86
+
87
+ For same-origin cookie auth, the browser already sends the session cookie and the channel should
88
+ validate it from `request`. For bearer or custom-header auth, also configure the frontend's
89
+ `useAshAgent({ auth })` or `useAshAgent({ headers })` call. Do not report the frontend as
90
+ production-ready until unauthenticated requests are rejected.
77
91
 
78
92
  4. Merge package imports only when agent files use `#...` aliases:
79
93
 
@@ -149,10 +163,6 @@ Keep an existing `typecheck` unless it excludes `agent/**/*.ts`.
149
163
 
150
164
  Add `paths` only if the project uses those aliases.
151
165
 
152
- 8. Let `withAsh()` generate or update `vercel.json`.
153
-
154
- After adding `withAsh()`, run `pnpm dev` or the relevant build command. Do not hand-author the Vercel services config unless generation fails or the user explicitly wants manual control. If `vercel.json` is created or changed, review and commit it.
155
-
156
166
  ## Verify
157
167
 
158
168
  ```bash
@@ -163,4 +173,6 @@ curl http://localhost:3000/ash/v1/health
163
173
 
164
174
  Use `pnpm info:ash` or `pnpm dev:ash` to inspect Ash directly.
165
175
 
166
- If `agent/channels/ash.ts` throws in production, that is intentional until production auth is wired.
176
+ Verify the selected auth path as well as the health route. Local development may be accepted by
177
+ `localDev()`, but a production-style unauthenticated request must be rejected by the end-user auth
178
+ policy.
@@ -13,6 +13,8 @@ Convert an Ash-only project into a combined Next.js app plus Ash agent. Preserve
13
13
  ```txt
14
14
  agent/
15
15
  agent.ts
16
+ channels/
17
+ ash.ts
16
18
  instructions.md
17
19
  app/
18
20
  globals.css
@@ -22,7 +24,6 @@ next.config.ts
22
24
  next-env.d.ts
23
25
  package.json
24
26
  tsconfig.json
25
- vercel.json # generated/updated by withAsh()
26
27
  ```
27
28
 
28
29
  ## Steps
@@ -78,7 +79,57 @@ const nextConfig: NextConfig = {};
78
79
  export default withAsh(nextConfig);
79
80
  ```
80
81
 
81
- 4. Make Next own the main scripts:
82
+ 4. Choose how frontend users authenticate to the Ash channel.
83
+
84
+ Inspect `agent/channels/ash.ts` first and preserve any existing auth policy. A channel configured
85
+ only with `localDev()` and `vercelOidc()` does not have end-user authentication. If the project does
86
+ not already have end-user authentication, ask the user which production access model they want
87
+ before adding one:
88
+
89
+ - **Clerk or Auth.js** for a normal signed-in web application.
90
+ - **Existing cookie/session auth** when another application auth system is already planned.
91
+ - **Bearer/JWT auth** when a separate client or identity provider supplies access tokens.
92
+ - **HTTP Basic** for a small private or internal frontend where a shared credential is acceptable.
93
+ - **Local-only for now** when they are only prototyping. Keep `localDev()` and `vercelOidc()`, clearly
94
+ state that browser users cannot access the deployed agent, and do not describe production setup as
95
+ complete.
96
+
97
+ Do not choose Clerk, Auth.js, or another provider on the user's behalf when starting from an
98
+ Ash-only project. Once the user chooses, install and configure that provider using its established
99
+ Next.js pattern, then connect the resulting request identity to `agent/channels/ash.ts`.
100
+
101
+ For cookie or session authentication, use this channel shape:
102
+
103
+ ```ts
104
+ // agent/channels/ash.ts
105
+ import { ashChannel } from "experimental-ash/channels/ash";
106
+ import { type AuthFn, localDev, vercelOidc } from "experimental-ash/channels/auth";
107
+
108
+ const authenticateUser: AuthFn = async (request) => {
109
+ // Implement this with the selected Clerk, Auth.js, or application session API.
110
+ const user = await authenticate(request);
111
+ if (!user) return null;
112
+
113
+ return {
114
+ attributes: {},
115
+ authenticator: "app",
116
+ issuer: "nextjs",
117
+ principalId: user.id,
118
+ principalType: "user",
119
+ };
120
+ };
121
+
122
+ export default ashChannel({
123
+ auth: [localDev(), vercelOidc(), authenticateUser],
124
+ });
125
+ ```
126
+
127
+ Same-origin cookie sessions need no client credential plumbing. For bearer/JWT or custom-header
128
+ auth, also configure the generated frontend with `useAshAgent({ auth })` or
129
+ `useAshAgent({ headers })`. For HTTP Basic, use the Ash channel auth helper and keep the credential
130
+ outside source control.
131
+
132
+ 5. Make Next own the main scripts:
82
133
 
83
134
  ```json
84
135
  {
@@ -93,7 +144,7 @@ export default withAsh(nextConfig);
93
144
  }
94
145
  ```
95
146
 
96
- 5. Use a Next-compatible `tsconfig.json`, keep `.ash/**/*.d.ts` in `include`, and preserve Ash aliases:
147
+ 6. Use a Next-compatible `tsconfig.json`, keep `.ash/**/*.d.ts` in `include`, and preserve Ash aliases:
97
148
 
98
149
  ```json
99
150
  {
@@ -122,11 +173,7 @@ export default withAsh(nextConfig);
122
173
 
123
174
  Merge matching `package.json` `imports` when Ash files use `#...`.
124
175
 
125
- 6. Let `withAsh()` generate or update `vercel.json`.
126
-
127
- After adding `withAsh()`, run `pnpm dev` or the relevant build command. Do not hand-author the Vercel services config unless generation fails or the user explicitly wants manual control. If `vercel.json` is created or changed, review and commit it.
128
-
129
- 7. Ignore generated artifacts if needed: `.next`, `.ash`, `.output`, `*.tsbuildinfo`. Do not ignore `vercel.json` when it is generated for the app.
176
+ 7. Ignore generated artifacts if needed: `.next`, `.vercel`, `.ash`, `.output`, `*.tsbuildinfo`.
130
177
 
131
178
  ## Verify
132
179
 
@@ -135,3 +182,6 @@ pnpm install
135
182
  pnpm dev
136
183
  curl http://localhost:3000/ash/v1/health
137
184
  ```
185
+
186
+ Also verify the chosen authentication path. A signed-in or correctly credentialed request should
187
+ reach the Ash session API, while an unauthenticated production-style request should return `401`.