@ably/ai-transport 0.1.0 → 0.3.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 (221) hide show
  1. package/README.md +93 -111
  2. package/dist/ably-ai-transport.js +2401 -1387
  3. package/dist/ably-ai-transport.js.map +1 -1
  4. package/dist/ably-ai-transport.umd.cjs +1 -1
  5. package/dist/ably-ai-transport.umd.cjs.map +1 -1
  6. package/dist/constants.d.ts +116 -42
  7. package/dist/core/agent.d.ts +44 -0
  8. package/dist/core/channel-options.d.ts +57 -0
  9. package/dist/core/codec/codec-event.d.ts +9 -0
  10. package/dist/core/codec/decoder.d.ts +24 -24
  11. package/dist/core/codec/define-codec.d.ts +100 -0
  12. package/dist/core/codec/encoder.d.ts +10 -12
  13. package/dist/core/codec/field-bag.d.ts +85 -0
  14. package/dist/core/codec/fields.d.ts +141 -0
  15. package/dist/core/codec/index.d.ts +8 -2
  16. package/dist/core/codec/input-descriptor-decoder.d.ts +19 -0
  17. package/dist/core/codec/input-descriptor-encoder.d.ts +22 -0
  18. package/dist/core/codec/input-descriptors.d.ts +281 -0
  19. package/dist/core/codec/lifecycle-tracker.d.ts +10 -9
  20. package/dist/core/codec/output-descriptor-decoder.d.ts +29 -0
  21. package/dist/core/codec/output-descriptor-encoder.d.ts +31 -0
  22. package/dist/core/codec/output-descriptors.d.ts +237 -0
  23. package/dist/core/codec/types.d.ts +470 -119
  24. package/dist/core/codec/well-known-inputs.d.ts +52 -0
  25. package/dist/core/transport/agent-session.d.ts +10 -0
  26. package/dist/core/transport/agent-view.d.ts +296 -0
  27. package/dist/core/transport/client-session.d.ts +13 -0
  28. package/dist/core/transport/decode-fold.d.ts +55 -0
  29. package/dist/core/transport/headers.d.ts +121 -14
  30. package/dist/core/transport/index.d.ts +5 -6
  31. package/dist/core/transport/internal/bounded-map.d.ts +20 -0
  32. package/dist/core/transport/invocation.d.ts +74 -0
  33. package/dist/core/transport/load-history-pages.d.ts +71 -0
  34. package/dist/core/transport/load-history.d.ts +44 -0
  35. package/dist/core/transport/pipe-stream.d.ts +9 -9
  36. package/dist/core/transport/run-manager.d.ts +76 -0
  37. package/dist/core/transport/session-support.d.ts +55 -0
  38. package/dist/core/transport/tree.d.ts +523 -109
  39. package/dist/core/transport/types/agent.d.ts +375 -0
  40. package/dist/core/transport/types/client.d.ts +201 -0
  41. package/dist/core/transport/types/shared.d.ts +24 -0
  42. package/dist/core/transport/types/tree.d.ts +357 -0
  43. package/dist/core/transport/types/view.d.ts +249 -0
  44. package/dist/core/transport/types.d.ts +13 -553
  45. package/dist/core/transport/view.d.ts +390 -84
  46. package/dist/core/transport/wire-log.d.ts +102 -0
  47. package/dist/errors.d.ts +27 -10
  48. package/dist/index.d.ts +8 -9
  49. package/dist/logger.d.ts +12 -0
  50. package/dist/react/ably-ai-transport-react.js +1365 -1010
  51. package/dist/react/ably-ai-transport-react.js.map +1 -1
  52. package/dist/react/ably-ai-transport-react.umd.cjs +1 -1
  53. package/dist/react/ably-ai-transport-react.umd.cjs.map +1 -1
  54. package/dist/react/contexts/client-session-context.d.ts +37 -0
  55. package/dist/react/contexts/client-session-provider.d.ts +56 -0
  56. package/dist/react/create-session-hooks.d.ts +116 -0
  57. package/dist/react/index.d.ts +13 -12
  58. package/dist/react/internal/skipped-session.d.ts +8 -0
  59. package/dist/react/internal/use-resolved-session.d.ts +36 -0
  60. package/dist/react/use-ably-messages.d.ts +17 -14
  61. package/dist/react/use-client-session.d.ts +81 -0
  62. package/dist/react/use-create-view.d.ts +14 -13
  63. package/dist/react/use-tree.d.ts +30 -15
  64. package/dist/react/use-view.d.ts +81 -50
  65. package/dist/utils.d.ts +48 -71
  66. package/dist/vercel/ably-ai-transport-vercel.js +3257 -2499
  67. package/dist/vercel/ably-ai-transport-vercel.js.map +1 -1
  68. package/dist/vercel/ably-ai-transport-vercel.umd.cjs +1 -1
  69. package/dist/vercel/ably-ai-transport-vercel.umd.cjs.map +1 -1
  70. package/dist/vercel/codec/decode-lifecycle.d.ts +9 -0
  71. package/dist/vercel/codec/events.d.ts +50 -0
  72. package/dist/vercel/codec/fields.d.ts +44 -0
  73. package/dist/vercel/codec/fold-content.d.ts +16 -0
  74. package/dist/vercel/codec/fold-data.d.ts +16 -0
  75. package/dist/vercel/codec/fold-input.d.ts +67 -0
  76. package/dist/vercel/codec/fold-lifecycle.d.ts +16 -0
  77. package/dist/vercel/codec/fold-text.d.ts +16 -0
  78. package/dist/vercel/codec/fold-tool-input.d.ts +17 -0
  79. package/dist/vercel/codec/fold-tool-output.d.ts +16 -0
  80. package/dist/vercel/codec/index.d.ts +7 -20
  81. package/dist/vercel/codec/inputs.d.ts +11 -0
  82. package/dist/vercel/codec/outputs.d.ts +11 -0
  83. package/dist/vercel/codec/reducer-state.d.ts +121 -0
  84. package/dist/vercel/codec/reducer.d.ts +62 -0
  85. package/dist/vercel/codec/tool-transitions.d.ts +2 -8
  86. package/dist/vercel/codec/wire-data.d.ts +34 -0
  87. package/dist/vercel/index.d.ts +5 -5
  88. package/dist/vercel/react/ably-ai-transport-vercel-react.js +2859 -9705
  89. package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
  90. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +1 -45
  91. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
  92. package/dist/vercel/react/contexts/chat-transport-context.d.ts +9 -7
  93. package/dist/vercel/react/contexts/chat-transport-provider.d.ts +53 -41
  94. package/dist/vercel/react/index.d.ts +1 -2
  95. package/dist/vercel/react/use-chat-transport.d.ts +30 -26
  96. package/dist/vercel/react/use-message-sync.d.ts +17 -30
  97. package/dist/vercel/run-end-reason.d.ts +84 -0
  98. package/dist/vercel/tool-part.d.ts +21 -0
  99. package/dist/vercel/transport/chat-transport.d.ts +41 -24
  100. package/dist/vercel/transport/index.d.ts +24 -20
  101. package/dist/vercel/transport/run-output-stream.d.ts +54 -0
  102. package/dist/version.d.ts +2 -0
  103. package/package.json +31 -24
  104. package/src/constants.ts +124 -51
  105. package/src/core/agent.ts +92 -0
  106. package/src/core/channel-options.ts +89 -0
  107. package/src/core/codec/codec-event.ts +27 -0
  108. package/src/core/codec/decoder.ts +202 -105
  109. package/src/core/codec/define-codec.ts +432 -0
  110. package/src/core/codec/encoder.ts +114 -107
  111. package/src/core/codec/field-bag.ts +142 -0
  112. package/src/core/codec/fields.ts +193 -0
  113. package/src/core/codec/index.ts +56 -6
  114. package/src/core/codec/input-descriptor-decoder.ts +97 -0
  115. package/src/core/codec/input-descriptor-encoder.ts +150 -0
  116. package/src/core/codec/input-descriptors.ts +373 -0
  117. package/src/core/codec/lifecycle-tracker.ts +10 -9
  118. package/src/core/codec/output-descriptor-decoder.ts +139 -0
  119. package/src/core/codec/output-descriptor-encoder.ts +101 -0
  120. package/src/core/codec/output-descriptors.ts +307 -0
  121. package/src/core/codec/types.ts +505 -126
  122. package/src/core/codec/well-known-inputs.ts +96 -0
  123. package/src/core/transport/agent-session.ts +1085 -0
  124. package/src/core/transport/agent-view.ts +738 -0
  125. package/src/core/transport/client-session.ts +780 -0
  126. package/src/core/transport/decode-fold.ts +101 -0
  127. package/src/core/transport/headers.ts +234 -22
  128. package/src/core/transport/index.ts +27 -27
  129. package/src/core/transport/internal/bounded-map.ts +27 -0
  130. package/src/core/transport/invocation.ts +98 -0
  131. package/src/core/transport/load-history-pages.ts +220 -0
  132. package/src/core/transport/load-history.ts +271 -0
  133. package/src/core/transport/pipe-stream.ts +63 -39
  134. package/src/core/transport/run-manager.ts +243 -0
  135. package/src/core/transport/session-support.ts +96 -0
  136. package/src/core/transport/tree.ts +1293 -308
  137. package/src/core/transport/types/agent.ts +434 -0
  138. package/src/core/transport/types/client.ts +247 -0
  139. package/src/core/transport/types/shared.ts +27 -0
  140. package/src/core/transport/types/tree.ts +393 -0
  141. package/src/core/transport/types/view.ts +288 -0
  142. package/src/core/transport/types.ts +13 -706
  143. package/src/core/transport/view.ts +1229 -450
  144. package/src/core/transport/wire-log.ts +189 -0
  145. package/src/errors.ts +29 -9
  146. package/src/event-emitter.ts +3 -2
  147. package/src/index.ts +86 -42
  148. package/src/logger.ts +14 -1
  149. package/src/react/contexts/client-session-context.ts +41 -0
  150. package/src/react/contexts/client-session-provider.tsx +222 -0
  151. package/src/react/create-session-hooks.ts +141 -0
  152. package/src/react/index.ts +24 -13
  153. package/src/react/internal/skipped-session.ts +62 -0
  154. package/src/react/internal/use-resolved-session.ts +63 -0
  155. package/src/react/use-ably-messages.ts +32 -22
  156. package/src/react/use-client-session.ts +178 -0
  157. package/src/react/use-create-view.ts +33 -29
  158. package/src/react/use-tree.ts +61 -30
  159. package/src/react/use-view.ts +138 -96
  160. package/src/utils.ts +83 -131
  161. package/src/vercel/codec/decode-lifecycle.ts +70 -0
  162. package/src/vercel/codec/events.ts +85 -0
  163. package/src/vercel/codec/fields.ts +58 -0
  164. package/src/vercel/codec/fold-content.ts +54 -0
  165. package/src/vercel/codec/fold-data.ts +46 -0
  166. package/src/vercel/codec/fold-input.ts +255 -0
  167. package/src/vercel/codec/fold-lifecycle.ts +85 -0
  168. package/src/vercel/codec/fold-text.ts +55 -0
  169. package/src/vercel/codec/fold-tool-input.ts +86 -0
  170. package/src/vercel/codec/fold-tool-output.ts +79 -0
  171. package/src/vercel/codec/index.ts +28 -21
  172. package/src/vercel/codec/inputs.ts +116 -0
  173. package/src/vercel/codec/outputs.ts +207 -0
  174. package/src/vercel/codec/reducer-state.ts +169 -0
  175. package/src/vercel/codec/reducer.ts +191 -0
  176. package/src/vercel/codec/tool-transitions.ts +3 -14
  177. package/src/vercel/codec/wire-data.ts +64 -0
  178. package/src/vercel/index.ts +7 -19
  179. package/src/vercel/react/contexts/chat-transport-context.ts +8 -7
  180. package/src/vercel/react/contexts/chat-transport-provider.tsx +87 -59
  181. package/src/vercel/react/index.ts +3 -5
  182. package/src/vercel/react/use-chat-transport.ts +44 -66
  183. package/src/vercel/react/use-message-sync.ts +75 -39
  184. package/src/vercel/run-end-reason.ts +157 -0
  185. package/src/vercel/tool-part.ts +25 -0
  186. package/src/vercel/transport/chat-transport.ts +380 -98
  187. package/src/vercel/transport/index.ts +38 -37
  188. package/src/vercel/transport/run-output-stream.ts +169 -0
  189. package/src/version.ts +2 -0
  190. package/dist/core/transport/client-transport.d.ts +0 -10
  191. package/dist/core/transport/decode-history.d.ts +0 -43
  192. package/dist/core/transport/server-transport.d.ts +0 -7
  193. package/dist/core/transport/stream-router.d.ts +0 -29
  194. package/dist/core/transport/turn-manager.d.ts +0 -37
  195. package/dist/react/contexts/transport-context.d.ts +0 -31
  196. package/dist/react/contexts/transport-provider.d.ts +0 -49
  197. package/dist/react/create-transport-hooks.d.ts +0 -124
  198. package/dist/react/use-active-turns.d.ts +0 -12
  199. package/dist/react/use-client-transport.d.ts +0 -80
  200. package/dist/vercel/codec/accumulator.d.ts +0 -21
  201. package/dist/vercel/codec/decoder.d.ts +0 -22
  202. package/dist/vercel/codec/encoder.d.ts +0 -41
  203. package/dist/vercel/react/use-staged-add-tool-approval-response.d.ts +0 -30
  204. package/dist/vercel/tool-approvals.d.ts +0 -124
  205. package/dist/vercel/tool-events.d.ts +0 -26
  206. package/src/core/transport/client-transport.ts +0 -977
  207. package/src/core/transport/decode-history.ts +0 -485
  208. package/src/core/transport/server-transport.ts +0 -612
  209. package/src/core/transport/stream-router.ts +0 -136
  210. package/src/core/transport/turn-manager.ts +0 -165
  211. package/src/react/contexts/transport-context.ts +0 -37
  212. package/src/react/contexts/transport-provider.tsx +0 -164
  213. package/src/react/create-transport-hooks.ts +0 -144
  214. package/src/react/use-active-turns.ts +0 -72
  215. package/src/react/use-client-transport.ts +0 -197
  216. package/src/vercel/codec/accumulator.ts +0 -588
  217. package/src/vercel/codec/decoder.ts +0 -618
  218. package/src/vercel/codec/encoder.ts +0 -410
  219. package/src/vercel/react/use-staged-add-tool-approval-response.ts +0 -87
  220. package/src/vercel/tool-approvals.ts +0 -380
  221. package/src/vercel/tool-events.ts +0 -53
@@ -0,0 +1,9 @@
1
+ import { LifecyclePolicy } from '../../core/codec/index.js';
2
+ import { VercelOutput } from './events.js';
3
+ /**
4
+ * Build a fresh Vercel decode lifecycle policy (with its own tracker). Passed
5
+ * to `defineCodec` as the `decodeLifecycle` factory so each decoder instance
6
+ * gets independent per-run phase state.
7
+ * @returns A {@link LifecyclePolicy} for the Vercel output union.
8
+ */
9
+ export declare const createVercelDecodeLifecycle: () => LifecyclePolicy<VercelOutput>;
@@ -0,0 +1,50 @@
1
+ import { Regenerate, ToolApprovalResponse, ToolResult, ToolResultError, UserMessage } from '../../core/codec/index.js';
2
+ /**
3
+ * Vercel codec input/output unions.
4
+ *
5
+ * The codec splits cleanly along the protocol's `ai-input` / `ai-output`
6
+ * wire seam:
7
+ *
8
+ * - **`VercelOutput`** = `AI.UIMessageChunk` — the AI SDK's streamed-output
9
+ * domain model, published by the agent on `ai-output`.
10
+ * - **`VercelInput`** = a discriminated union of the SDK's well-known
11
+ * input shapes — published by the client on `ai-input`. The Vercel
12
+ * codec has no codec-local input variants today: every variant comes
13
+ * from `@ably/ai-transport`'s well-known set.
14
+ */
15
+ import type * as AI from 'ai';
16
+ /** Vercel domain payload for a {@link ToolResult}. */
17
+ export interface VercelToolResultPayload {
18
+ /** The tool call this result corresponds to. */
19
+ toolCallId: string;
20
+ /** The tool's output value. Tool-defined shape. */
21
+ output: unknown;
22
+ }
23
+ /** Vercel domain payload for a {@link ToolResultError}. */
24
+ export interface VercelToolResultErrorPayload {
25
+ /** The tool call this error corresponds to. */
26
+ toolCallId: string;
27
+ /** Human-readable description of the failure. */
28
+ message: string;
29
+ }
30
+ /** Vercel domain payload for a {@link ToolApprovalResponse}. */
31
+ export interface VercelToolApprovalResponsePayload {
32
+ /** The tool call this approval responds to. */
33
+ toolCallId: string;
34
+ /** Whether the user approved the tool execution. */
35
+ approved: boolean;
36
+ /** Optional human-readable reason (typically used on denial). */
37
+ reason?: string;
38
+ }
39
+ /**
40
+ * The Vercel codec's `TInput` — every record-shape a client publishes on
41
+ * the `ai-input` wire. Composed from the SDK's well-known input shapes,
42
+ * with the tool variants parameterized by the Vercel domain payloads above.
43
+ */
44
+ export type VercelInput = UserMessage<AI.UIMessage> | Regenerate | ToolResult<VercelToolResultPayload> | ToolResultError<VercelToolResultErrorPayload> | ToolApprovalResponse<VercelToolApprovalResponsePayload>;
45
+ /**
46
+ * The Vercel codec's `TOutput` — every record-shape the agent publishes
47
+ * on the `ai-output` wire. The Vercel codec passes the AI SDK's
48
+ * `UIMessageChunk` through unchanged.
49
+ */
50
+ export type VercelOutput = AI.UIMessageChunk;
@@ -0,0 +1,44 @@
1
+ import { HeaderField } from '../../core/codec/index.js';
2
+ /**
3
+ * Shared Vercel codec header-field bindings.
4
+ *
5
+ * Each field binds a codec header key to its value type once (see
6
+ * {@link HeaderField}); the output/input descriptors and escape hatches all
7
+ * read and write through these bindings, so a header key cannot drift between
8
+ * the encode and decode side. Domain field names live in the Vercel layer, not
9
+ * core, per the header-discipline rule.
10
+ */
11
+ import type * as AI from 'ai';
12
+ /** Stream / message id (text & reasoning streams). */
13
+ export declare const fId: HeaderField<string | undefined, "id">;
14
+ /**
15
+ * Provider metadata envelope, typed to the AI SDK shape. Annotated explicitly:
16
+ * the inferred type resolves to the AI SDK's internal `SharedV3ProviderMetadata`
17
+ * alias, which isn't portably nameable across the package boundary.
18
+ */
19
+ export declare const fMeta: HeaderField<AI.ProviderMetadata | undefined, 'providerMetadata'>;
20
+ /** Tool call id — defaulted to total: an absent header reads as `''`. */
21
+ export declare const fToolCallId: HeaderField<string, "toolCallId">;
22
+ /** Tool name — defaulted to total. */
23
+ export declare const fToolName: HeaderField<string, "toolName">;
24
+ /** Whether the tool is a dynamic tool. */
25
+ export declare const fDynamic: HeaderField<boolean | undefined, "dynamic">;
26
+ /** Optional human-readable title. */
27
+ export declare const fTitle: HeaderField<string | undefined, "title">;
28
+ /** Whether the provider executed the tool. */
29
+ export declare const fProviderExecuted: HeaderField<boolean | undefined, "providerExecuted">;
30
+ /** Media type for file / source-document parts — defaulted to total. */
31
+ export declare const fMediaType: HeaderField<string, "mediaType">;
32
+ /** Source id for source-url / source-document parts — defaulted to total. */
33
+ export declare const fSourceId: HeaderField<string, "sourceId">;
34
+ /** Domain message id (`message.id`) stamped on every user-message part — distinct from the wire codec-message-id transport header. */
35
+ export declare const fMessageId: HeaderField<string | undefined, "messageId">;
36
+ /** Whether the user approved a tool execution — defaulted to total so an absent header reads `false`. */
37
+ export declare const fApproved: HeaderField<boolean, "approved">;
38
+ /** Optional human-readable reason on a tool-approval response. */
39
+ export declare const fReason: HeaderField<string | undefined, "reason">;
40
+ /**
41
+ * Validated finish reason. Mirrors the AI SDK's `FinishReason` literals and
42
+ * falls back to `'stop'` for an absent or unrecognized value.
43
+ */
44
+ export declare const fFinishReason: HeaderField<"error" | "length" | "stop" | "content-filter" | "tool-calls" | "other", "finishReason">;
@@ -0,0 +1,16 @@
1
+ import { VercelProjection } from './reducer-state.js';
2
+ /**
3
+ * File and source content-part folds: file / source-url / source-document.
4
+ * These are independent attachments — each appends a part, never dedups.
5
+ */
6
+ import type * as AI from 'ai';
7
+ /**
8
+ * Fold a file or source content chunk into the projection.
9
+ * @param state - Projection to fold into.
10
+ * @param chunk - The file, source-url, or source-document chunk.
11
+ * @param messageId - The target codec-message-id.
12
+ * @returns The same projection reference.
13
+ */
14
+ export declare const foldContentPart: (state: VercelProjection, chunk: Extract<AI.UIMessageChunk, {
15
+ type: "file" | "source-url" | "source-document";
16
+ }>, messageId: string) => VercelProjection;
@@ -0,0 +1,16 @@
1
+ import { VercelProjection } from './reducer-state.js';
2
+ /**
3
+ * data-* part folds. Transient data parts are dropped; persistent ones are
4
+ * appended, or replaced in place when a matching `id` is already present.
5
+ */
6
+ import type * as AI from 'ai';
7
+ /**
8
+ * Fold a `data-*` chunk into the projection.
9
+ * @param state - Projection to fold into.
10
+ * @param chunk - The data-* chunk.
11
+ * @param messageId - The target codec-message-id.
12
+ * @returns The same projection reference.
13
+ */
14
+ export declare const foldDataPart: (state: VercelProjection, chunk: Extract<AI.UIMessageChunk, {
15
+ type: `data-${string}`;
16
+ }>, messageId: string) => VercelProjection;
@@ -0,0 +1,67 @@
1
+ import { ReducerMeta, ToolApprovalResponse, ToolResult, ToolResultError } from '../../core/codec/index.js';
2
+ import { VercelToolApprovalResponsePayload, VercelToolResultErrorPayload, VercelToolResultPayload } from './events.js';
3
+ import { VercelProjection } from './reducer-state.js';
4
+ /**
5
+ * Client-published input folds and the pending-resolution buffering.
6
+ *
7
+ * Tool resolutions (`ToolResult`, `ToolResultError`, `ToolApprovalResponse`)
8
+ * carry a `codecMessageId` targeting the assistant they amend. When that
9
+ * assistant (or its tool part) has not yet arrived, the resolution is buffered
10
+ * in `pendingToolResolutions` and {@link retryPendingResolutions} re-evaluates
11
+ * it after every subsequent fold.
12
+ */
13
+ import type * as AI from 'ai';
14
+ /**
15
+ * Fold a user message into the projection, correlating on the wire
16
+ * codec-message-id (the caller's `message.id` is preserved verbatim). A
17
+ * multi-part user message fans out into one wire event per part, all sharing
18
+ * the codec-message-id — folding appends the incoming parts to the existing
19
+ * entry, reassembling the message part by part. The transport delivers each
20
+ * wire exactly once (its per-message version high-water-mark drops replays),
21
+ * so the merge sees every part once and stays consistent.
22
+ *
23
+ * Optimistic (serial-less) seeds need no special handling here: the transport
24
+ * refolds the node from its log when the echo's serial arrives, rebuilding the
25
+ * projection from a fresh `init` so the seed never coexists with its echo.
26
+ * @param state - Projection to fold into.
27
+ * @param message - The user message (or one decoded part of it) to add or merge.
28
+ * @param meta - Transport-derived metadata carrying the codec-message-id.
29
+ * @returns The same projection reference.
30
+ */
31
+ export declare const foldUserMessage: (state: VercelProjection, message: AI.UIMessage, meta: ReducerMeta) => VercelProjection;
32
+ /**
33
+ * Fold a client-published `ToolResult`. The input carries
34
+ * `codecMessageId` pointing at the assistant whose `dynamic-tool` part
35
+ * holds the matching `toolCallId`. If the assistant and its matching
36
+ * `dynamic-tool` part are both present, fold directly; otherwise pend
37
+ * until that tool part arrives.
38
+ * @param state - Projection to fold into.
39
+ * @param event - The tool-result input (codecMessageId + domain payload).
40
+ * @returns The same projection reference.
41
+ */
42
+ export declare const foldClientToolResult: (state: VercelProjection, event: ToolResult<VercelToolResultPayload>) => VercelProjection;
43
+ /**
44
+ * Fold a client-published `ToolResultError`. Mirrors
45
+ * {@link foldClientToolResult} but with the error transition.
46
+ * @param state - Projection to fold into.
47
+ * @param event - The tool-result-error input (codecMessageId + domain payload).
48
+ * @returns The same projection reference.
49
+ */
50
+ export declare const foldClientToolResultError: (state: VercelProjection, event: ToolResultError<VercelToolResultErrorPayload>) => VercelProjection;
51
+ /**
52
+ * Fold a client-published `ToolApprovalResponse`. The input carries
53
+ * `codecMessageId` pointing at the assistant whose `dynamic-tool` part
54
+ * holds the matching `toolCallId`. Approval → `approval-responded`;
55
+ * denial → `output-denied` via {@link transitionToolPart}.
56
+ * @param state - Projection to fold into.
57
+ * @param event - The approval-response input.
58
+ * @returns The same projection reference.
59
+ */
60
+ export declare const foldToolApprovalResponse: (state: VercelProjection, event: ToolApprovalResponse<VercelToolApprovalResponsePayload>) => VercelProjection;
61
+ /**
62
+ * Re-attempt every pending tool resolution against the current projection.
63
+ * Successfully promoted entries are removed from the pending list. Cheap:
64
+ * bounded by the number of pending entries.
65
+ * @param state - Projection to walk and mutate.
66
+ */
67
+ export declare const retryPendingResolutions: (state: VercelProjection) => void;
@@ -0,0 +1,16 @@
1
+ import { VercelProjection } from './reducer-state.js';
2
+ /**
3
+ * Lifecycle chunk folds: start, start-step, finish-step, finish, abort,
4
+ * error, message-metadata.
5
+ */
6
+ import type * as AI from 'ai';
7
+ /**
8
+ * Fold a message-lifecycle chunk into the projection.
9
+ * @param state - Projection to fold into.
10
+ * @param chunk - The lifecycle chunk.
11
+ * @param messageId - The target codec-message-id.
12
+ * @returns The same projection reference.
13
+ */
14
+ export declare const foldLifecycle: (state: VercelProjection, chunk: Extract<AI.UIMessageChunk, {
15
+ type: "start" | "start-step" | "finish-step" | "finish" | "abort" | "error" | "message-metadata";
16
+ }>, messageId: string) => VercelProjection;
@@ -0,0 +1,16 @@
1
+ import { VercelProjection } from './reducer-state.js';
2
+ /**
3
+ * Text and reasoning streaming folds: the {start, delta, end} lifecycle for
4
+ * both `text-*` and `reasoning-*` chunks, which share the same shape.
5
+ */
6
+ import type * as AI from 'ai';
7
+ /**
8
+ * Fold a text or reasoning streaming chunk into the projection.
9
+ * @param state - Projection to fold into.
10
+ * @param chunk - The text/reasoning start, delta, or end chunk.
11
+ * @param messageId - The target codec-message-id.
12
+ * @returns The same projection reference.
13
+ */
14
+ export declare const foldTextOrReasoning: (state: VercelProjection, chunk: Extract<AI.UIMessageChunk, {
15
+ type: "text-start" | "text-delta" | "text-end" | "reasoning-start" | "reasoning-delta" | "reasoning-end";
16
+ }>, messageId: string) => VercelProjection;
@@ -0,0 +1,17 @@
1
+ import { VercelProjection } from './reducer-state.js';
2
+ /**
3
+ * Tool-input streaming folds: tool-input-start / -delta / -available / -error.
4
+ * Tool deltas arrive as raw JSON fragments accumulated in the tracker's
5
+ * `inputText` buffer and parsed on each delta.
6
+ */
7
+ import type * as AI from 'ai';
8
+ /**
9
+ * Fold a tool-input streaming chunk into the projection.
10
+ * @param state - Projection to fold into.
11
+ * @param chunk - The tool-input start, delta, available, or error chunk.
12
+ * @param messageId - The target codec-message-id.
13
+ * @returns The same projection reference.
14
+ */
15
+ export declare const foldToolInput: (state: VercelProjection, chunk: Extract<AI.UIMessageChunk, {
16
+ type: "tool-input-start" | "tool-input-delta" | "tool-input-available" | "tool-input-error";
17
+ }>, messageId: string) => VercelProjection;
@@ -0,0 +1,16 @@
1
+ import { VercelProjection } from './reducer-state.js';
2
+ /**
3
+ * Agent-published tool-output transitions: tool-output-available /
4
+ * tool-output-error / tool-output-denied / tool-approval-request.
5
+ */
6
+ import type * as AI from 'ai';
7
+ /**
8
+ * Fold an agent-published tool-output chunk into the projection.
9
+ * @param state - Projection to fold into.
10
+ * @param chunk - The tool-output-available/-error/-denied or tool-approval-request chunk.
11
+ * @param messageId - The target codec-message-id (used for the approval-request / denied paths).
12
+ * @returns The same projection reference.
13
+ */
14
+ export declare const foldToolOutput: (state: VercelProjection, chunk: Extract<AI.UIMessageChunk, {
15
+ type: "tool-output-available" | "tool-output-error" | "tool-output-denied" | "tool-approval-request";
16
+ }>, messageId: string) => VercelProjection;
@@ -1,22 +1,9 @@
1
- import { Codec } from '../../core/codec/types.js';
1
+ import { VercelInput, VercelOutput } from './events.js';
2
2
  /**
3
- * Vercel AI SDK codec — maps UIMessageChunk events and UIMessage objects
4
- * to/from native Ably message primitives (publish, append, update, delete).
5
- *
6
- * ```ts
7
- * import { UIMessageCodec } from '@ably/ai-transport/vercel';
8
- *
9
- * const encoder = UIMessageCodec.createEncoder(writer, options);
10
- * const decoder = UIMessageCodec.createDecoder();
11
- * const accumulator = UIMessageCodec.createAccumulator();
12
- * ```
3
+ * Vercel AI SDK codec implementing
4
+ * `Codec<VercelInput, VercelOutput, VercelProjection, UIMessage>`. `VercelProjection`
5
+ * and `UIMessage` are inferred from the reducer.
13
6
  */
14
- import type * as AI from 'ai';
15
- /**
16
- * Vercel AI SDK codec implementing `Codec<UIMessageChunk, UIMessage>`.
17
- *
18
- * Provides factory methods for creating encoders, decoders, and accumulators
19
- * that map between Vercel's UIMessageChunk/UIMessage types and Ably's native
20
- * message primitives.
21
- */
22
- export declare const UIMessageCodec: Codec<AI.UIMessageChunk, AI.UIMessage>;
7
+ export declare const UIMessageCodec: import('../../core/codec/define-codec.js').DefinedCodec<VercelInput, VercelOutput, import('./reducer-state.js').VercelProjection, import('ai').UIMessage<unknown, import('ai').UIDataTypes, import('ai').UITools>>;
8
+ export type { VercelInput, VercelOutput } from './events.js';
9
+ export { type VercelProjection } from './reducer.js';
@@ -0,0 +1,11 @@
1
+ import { InputBuilder, InputDescriptor } from '../../core/codec/index.js';
2
+ import { VercelInput } from './events.js';
3
+ /**
4
+ * The Vercel codec's `ai-input` descriptors, built from the injected
5
+ * direction-scoped builder.
6
+ * @param builder - The `{ event, batch }` builder curried on `VercelInput`.
7
+ * @param builder.event - Define a single-event input (payload-nested, or `wireOnly`).
8
+ * @param builder.batch - Define a multi-part (batch) input that fans out into one wire event per part.
9
+ * @returns The input descriptor table the generic input drivers consume.
10
+ */
11
+ export declare const inputs: ({ event, batch }: InputBuilder<VercelInput>) => readonly InputDescriptor<VercelInput>[];
@@ -0,0 +1,11 @@
1
+ import { OutputBuilder, OutputDescriptor } from '../../core/codec/index.js';
2
+ import { VercelOutput } from './events.js';
3
+ /**
4
+ * The Vercel codec's `ai-output` descriptors, built from the injected
5
+ * direction-scoped builder.
6
+ * @param builder - The `{ event, stream }` builder curried on `VercelOutput`.
7
+ * @param builder.event - Define a single discrete output event.
8
+ * @param builder.stream - Define a streamed output family (start / delta / end).
9
+ * @returns The output descriptor table the generic output drivers consume.
10
+ */
11
+ export declare const outputs: ({ event, stream }: OutputBuilder<VercelOutput>) => readonly OutputDescriptor<VercelOutput>[];
@@ -0,0 +1,121 @@
1
+ import { CodecMessage } from '../../core/codec/index.js';
2
+ /**
3
+ * Shared reducer state: the projection shape, its internal tracker types,
4
+ * `init`, and the message/tracker lookup helpers the per-concern fold modules
5
+ * build on. This module is the base of the reducer's import DAG — the fold
6
+ * modules depend on it; it depends on none of them.
7
+ */
8
+ import type * as AI from 'ai';
9
+ /**
10
+ * Tracks an in-progress tool part within a UIMessage. Text and reasoning
11
+ * parts don't need this — we write to them directly via partIndex. Tool
12
+ * parts need an extra `inputText` buffer because deltas arrive as raw
13
+ * JSON fragments that must be accumulated before parsing.
14
+ */
15
+ export interface ToolPartTracker {
16
+ /** Index in the message's parts array. */
17
+ partIndex: number;
18
+ /** Accumulated streaming input text (for JSON parsing on completion). */
19
+ inputText: string;
20
+ }
21
+ /** Per-codecMessageId tracking state for in-progress streams within a UIMessage. */
22
+ export interface MessageTrackers {
23
+ /** Text stream id → partIndex. */
24
+ text: Map<string, number>;
25
+ /** Reasoning stream id → partIndex. */
26
+ reasoning: Map<string, number>;
27
+ /** Tool call id → tracker. */
28
+ tools: Map<string, ToolPartTracker>;
29
+ }
30
+ /**
31
+ * The per-Run state produced by the Vercel codec's reducer.
32
+ *
33
+ * The SDK reads only `messages` (via `Codec.getMessages`). The remaining
34
+ * fields are internal to the reducer; they happen to live on the
35
+ * projection because the projection is the only thing the reducer can
36
+ * carry from fold to fold (it has no instance state).
37
+ */
38
+ export interface VercelProjection {
39
+ /**
40
+ * UIMessages produced or modified in this Run, in publication order,
41
+ * each paired with its codec-message-id. The reducer correlates strictly
42
+ * on `codecMessageId`; `message.id` is preserved verbatim from the source
43
+ * (the AI SDK stream's `start.messageId` for assistants, the caller's id
44
+ * for user messages) and is never used as an identity key.
45
+ */
46
+ messages: CodecMessage<AI.UIMessage>[];
47
+ /** Per-codecMessageId tracker state for streamed parts. Internal — do not access. */
48
+ trackers: Map<string, MessageTrackers>;
49
+ /**
50
+ * Tool-resolution events that arrived before any assistant in this
51
+ * projection had a matching `toolCallId`. Re-evaluated on every
52
+ * subsequent fold so that an out-of-order tool output is folded as
53
+ * soon as the corresponding assistant lands.
54
+ */
55
+ pendingToolResolutions: PendingToolResolution[];
56
+ }
57
+ /**
58
+ * A buffered tool resolution waiting for its assistant message to arrive.
59
+ * The reducer scans pending entries after every successful fold so an
60
+ * out-of-order tool output is promoted as soon as the matching assistant
61
+ * is added to the projection.
62
+ */
63
+ export interface PendingToolResolution {
64
+ /** The codec-message-id of the assistant the resolution targets. */
65
+ targetCodecMessageId: string;
66
+ /** Tool call this resolution targets. */
67
+ toolCallId: string;
68
+ /** Variant of the tool-resolution used to transition the assistant's tool part. */
69
+ resolution: {
70
+ kind: 'tool-result';
71
+ output: unknown;
72
+ } | {
73
+ kind: 'tool-result-error';
74
+ message: string;
75
+ } | {
76
+ kind: 'tool-approval-response';
77
+ approved: boolean;
78
+ reason?: string;
79
+ };
80
+ }
81
+ /** A located `dynamic-tool` part with its owning message and tracker. */
82
+ export interface OwnerLookup {
83
+ /** The message owning the tool part. */
84
+ message: AI.UIMessage;
85
+ /** The tracker pointing at the part's index. */
86
+ tracker: ToolPartTracker;
87
+ /** The resolved `dynamic-tool` part itself. */
88
+ part: AI.DynamicToolUIPart;
89
+ }
90
+ /**
91
+ * Build an empty initial projection.
92
+ * @returns A fresh VercelProjection with no messages and no tracker state.
93
+ */
94
+ export declare const init: () => VercelProjection;
95
+ /**
96
+ * Resolve the assistant message for a codec-message-id, creating an empty
97
+ * placeholder when none exists yet.
98
+ * @param state - Projection to read or extend.
99
+ * @param codecMessageId - The codec-message-id to resolve.
100
+ * @returns The existing or newly-seeded UIMessage for that id.
101
+ */
102
+ export declare const ensureMessage: (state: VercelProjection, codecMessageId: string) => AI.UIMessage;
103
+ /**
104
+ * Resolve the stream trackers for a codec-message-id, creating empty maps
105
+ * when none exist yet.
106
+ * @param state - Projection to read or extend.
107
+ * @param messageId - The codec-message-id whose trackers to resolve.
108
+ * @returns The existing or newly-created tracker maps for that id.
109
+ */
110
+ export declare const ensureTrackers: (state: VercelProjection, messageId: string) => MessageTrackers;
111
+ /**
112
+ * Resolve the `dynamic-tool` part tracked for a toolCallId within a message.
113
+ * @param message - The message whose parts to read.
114
+ * @param trackers - The message's tracker maps.
115
+ * @param toolCallId - The tool call to resolve.
116
+ * @returns The tracker and part, or `undefined` if untracked or the part is not a dynamic-tool.
117
+ */
118
+ export declare const getToolPart: (message: AI.UIMessage, trackers: MessageTrackers, toolCallId: string) => {
119
+ tracker: ToolPartTracker;
120
+ part: AI.DynamicToolUIPart;
121
+ } | undefined;
@@ -0,0 +1,62 @@
1
+ import { CodecEvent, CodecMessage, ReducerMeta } from '../../core/codec/index.js';
2
+ import { VercelInput, VercelOutput } from './events.js';
3
+ import { VercelProjection } from './reducer-state.js';
4
+ /**
5
+ * Vercel AI SDK reducer.
6
+ *
7
+ * Pure `(init, fold)` over the `VercelInput | VercelOutput` union. Folds
8
+ * input variants (user-message, tool-result, tool-result-error,
9
+ * tool-approval-response) and `UIMessageChunk` outputs into a
10
+ * VercelProjection holding `UIMessage[]` plus internal stream-tracker
11
+ * state.
12
+ *
13
+ * The reducer is stateless: every fold is `(state, event, meta) → state'`,
14
+ * with no instance state. Mutation in place is allowed — the projection
15
+ * is single-owner.
16
+ *
17
+ * The reducer does not dedup or reorder. The transport sequences events
18
+ * canonically — ascending by wire serial across messages, in decode order
19
+ * within a wire — and delivers each exactly once, so the reducer folds
20
+ * unconditionally. Last-writer-wins for events competing over the same
21
+ * logical state (e.g. two `tool-output-available` for one `toolCallId`)
22
+ * falls out of fold order: the highest-serial event folds last.
23
+ *
24
+ * Client-published tool resolutions (`ToolResult`, `ToolResultError`,
25
+ * `ToolApprovalResponse`) carry `codecMessageId` targeting the assistant
26
+ * they amend; the reducer applies the resolution onto that assistant's
27
+ * `dynamic-tool` part directly. If the assistant has not yet arrived in
28
+ * the projection (out-of-order delivery), the resolution is buffered in
29
+ * `pendingToolResolutions` and re-evaluated on each subsequent fold.
30
+ *
31
+ * This file is the reducer's public facade and dispatch: `init`,
32
+ * `getMessages`, `fold`, and the output-chunk router. The per-concern fold
33
+ * logic lives in the sibling `fold-*` modules over a shared `reducer-state`
34
+ * base; the import graph is an acyclic DAG rooted here.
35
+ */
36
+ import type * as AI from 'ai';
37
+ /**
38
+ * Fold one input or output event into the projection. Mutates and returns
39
+ * `state`.
40
+ *
41
+ * The transport invokes `fold` exactly once per event, in canonical order,
42
+ * so the reducer folds unconditionally — no dedup or high-water-mark here.
43
+ * Competing events resolve by order (the highest-serial event folds last
44
+ * and wins). Orphan events (e.g. tool-output for an unknown toolCallId) are
45
+ * dropped silently inside the per-variant fold helpers.
46
+ * @param state - Projection to fold into (may be mutated in place).
47
+ * @param event - Input or output event to fold.
48
+ * @param meta - Transport-derived metadata (serial, optional messageId).
49
+ * @returns The same projection reference, possibly mutated.
50
+ */
51
+ export declare const fold: (state: VercelProjection, event: CodecEvent<VercelInput, VercelOutput>, meta: ReducerMeta) => VercelProjection;
52
+ /**
53
+ * Extract the UIMessage list from a projection, each paired with its
54
+ * codec-message-id. Client-published tool resolutions amend existing
55
+ * assistants in place via `kind: 'tool-result'` etc. — they never
56
+ * materialise as their own UIMessage in the projection, so no filtering is
57
+ * needed here.
58
+ * @param projection - Projection produced by `init` + repeated `fold` calls.
59
+ * @returns The visible messages with their codec-message-ids, in publication order.
60
+ */
61
+ export declare const getMessages: (projection: VercelProjection) => CodecMessage<AI.UIMessage>[];
62
+ export { init, type VercelProjection } from './reducer-state.js';
@@ -1,20 +1,14 @@
1
1
  /**
2
2
  * Shared tool part transition logic for the Vercel AI SDK codec.
3
3
  *
4
- * Extracted from the accumulator so the tool output state transition logic
5
- * lives in one place, reusable by the accumulator and any other callers.
4
+ * Keeps the tool output state transition logic in one place, reusable by the
5
+ * Vercel codec reducer and any other callers.
6
6
  */
7
7
  import type * as AI from 'ai';
8
8
  /** The set of UIMessageChunk types that represent tool output transitions. */
9
9
  export type ToolOutputChunk = Extract<AI.UIMessageChunk, {
10
10
  type: 'tool-output-available' | 'tool-output-error' | 'tool-output-denied' | 'tool-approval-request';
11
11
  }>;
12
- /**
13
- * Whether a UIMessageChunk is a tool output transition event.
14
- * @param chunk - The chunk to test.
15
- * @returns True if the chunk is a tool output transition type.
16
- */
17
- export declare const isToolOutputChunk: (chunk: AI.UIMessageChunk) => chunk is ToolOutputChunk;
18
12
  /** Fields shared by all DynamicToolUIPart state variants. */
19
13
  interface ToolBaseFields {
20
14
  type: 'dynamic-tool';
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Wire-data shapes and runtime guards for the tool payloads whose `data`
3
+ * envelope is JSON-parsed from the network (a trust boundary). The guards
4
+ * validate the typed envelope fields; tool-defined `output`/`input` stay
5
+ * unconstrained. Shared by the output and input descriptor tables.
6
+ */
7
+ /** Wire format for the agent-side `tool-input-error` chunk data payload. */
8
+ export interface ToolInputErrorWireData {
9
+ errorText?: string;
10
+ input?: unknown;
11
+ }
12
+ /** Wire format for the `tool-output-available` (agent) / `tool-result` (client) data payload. */
13
+ export interface ToolOutputAvailableWireData {
14
+ output?: unknown;
15
+ }
16
+ /** Wire format for the agent-side `tool-output-error` chunk data payload. */
17
+ export interface AgentToolOutputErrorWireData {
18
+ errorText?: string;
19
+ }
20
+ /** Wire format for the client-side `tool-result-error` input data payload. */
21
+ export interface ClientToolResultErrorWireData {
22
+ message?: string;
23
+ }
24
+ /**
25
+ * Coerce wire `data` to a string, falling back to `''` for any non-string
26
+ * payload — the defensive read for descriptors whose data is plain text.
27
+ * @param data - The inbound wire data.
28
+ * @returns The string payload, or `''` when the data is not a string.
29
+ */
30
+ export declare const asString: (data: unknown) => string;
31
+ export declare const isToolInputErrorWireData: (data: unknown) => data is ToolInputErrorWireData;
32
+ export declare const isToolOutputAvailableWireData: (data: unknown) => data is ToolOutputAvailableWireData;
33
+ export declare const isAgentToolOutputErrorWireData: (data: unknown) => data is AgentToolOutputErrorWireData;
34
+ export declare const isClientToolResultErrorWireData: (data: unknown) => data is ClientToolResultErrorWireData;
@@ -1,6 +1,6 @@
1
+ export type { VercelInput, VercelOutput, VercelProjection } from './codec/index.js';
1
2
  export { UIMessageCodec } from './codec/index.js';
2
- export type { ChatTransport, ChatTransportOptions, SendMessagesRequestContext, VercelClientTransportOptions, VercelServerTransportOptions, } from './transport/index.js';
3
- export { createChatTransport, createClientTransport, createServerTransport } from './transport/index.js';
4
- export { applyToolEventsToHistory } from './tool-events.js';
5
- export type { PrepareApprovalTurnOptions, PrepareApprovalTurnResult, StreamResponseWithApprovalRedirectOptions, ToolApprovalDecision, } from './tool-approvals.js';
6
- export { applyToolApprovalsToHistory, extractApprovalDecisionsFromHistory, prepareApprovalTurn, streamResponseWithApprovalRedirect, } from './tool-approvals.js';
3
+ export type { ChatTransport, ChatTransportOptions, SendMessagesRequestContext, VercelAgentSessionOptions, VercelClientSessionOptions, } from './transport/index.js';
4
+ export { createAgentSession, createChatTransport, createClientSession } from './transport/index.js';
5
+ export type { VercelRunOutcome } from './run-end-reason.js';
6
+ export { vercelRunOutcome } from './run-end-reason.js';