@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
@@ -1,558 +1,18 @@
1
- import { Logger } from '../../logger.js';
2
- import { Codec, WriteOptions } from '../codec/types.js';
3
1
  /**
4
2
  * Core transport types, parameterized by codec event and message types.
5
3
  *
6
- * These types define the contract for both client and server transport
7
- * implementations, independent of which codec (Vercel AI SDK, etc.) is used.
8
- */
9
- import type * as Ably from 'ably';
10
- /** Why a turn ended. */
11
- export type TurnEndReason = 'complete' | 'cancelled' | 'error';
12
- /** Filter for cancel operations. At most one field should be set. */
13
- export interface CancelFilter {
14
- /** Cancel a specific turn by ID. */
15
- turnId?: string;
16
- /** Cancel all turns belonging to the sender's clientId. */
17
- own?: boolean;
18
- /** Cancel all turns belonging to a specific clientId. */
19
- clientId?: string;
20
- /** Cancel all turns on the channel. */
21
- all?: boolean;
22
- }
23
- /**
24
- * Passed to the server's `onCancel` hook for authorization decisions.
25
- * The hook inspects the incoming cancel message and decides whether to
26
- * allow each matched turn to be aborted.
27
- */
28
- export interface CancelRequest {
29
- /** The raw Ably message that carried the cancel signal. */
30
- message: Ably.InboundMessage;
31
- /** The parsed cancel scope from the message headers. */
32
- filter: CancelFilter;
33
- /** Which active turnIds would be cancelled if allowed. */
34
- matchedTurnIds: string[];
35
- /** Map of turnId to the ownerClientId for the matched turns. */
36
- turnOwners: Map<string, string>;
37
- }
38
- /** Options for creating a server transport. */
39
- export interface ServerTransportOptions<TEvent, TMessage> {
40
- /** The Ably channel to publish to. Must match the client's channel. */
41
- channel: Ably.RealtimeChannel;
42
- /** The codec to use for encoding events and messages. */
43
- codec: Codec<TEvent, TMessage>;
44
- /** Logger instance for diagnostic output. */
45
- logger?: Logger;
46
- /**
47
- * Called with non-fatal transport-level errors not scoped to any turn.
48
- * Examples: cancel listener subscription failure, channel attach errors,
49
- * channel continuity loss (FAILED/SUSPENDED/DETACHED or re-attach with
50
- * `resumed: false`).
51
- */
52
- onError?: (error: Ably.ErrorInfo) => void;
53
- }
54
- /** Options for addMessages — per-operation overrides for attribution. */
55
- export interface AddMessageOptions {
56
- /** The user's clientId for attribution. */
57
- clientId?: string;
58
- }
59
- /** Result of publishing user messages via addMessages. */
60
- export interface AddMessagesResult {
61
- /** The `x-ably-msg-id` of each published message, in order. */
62
- msgIds: string[];
63
- }
64
- /**
65
- * A batch of events targeting an existing message.
66
- * Each node specifies the target message and the events to apply to it.
67
- * Used for cross-turn updates such as tool result delivery.
68
- */
69
- export interface EventsNode<TEvent> {
70
- /** Discriminator — identifies this as an events node. */
71
- kind: 'event';
72
- /** The `x-ably-msg-id` of the existing message to update. */
73
- msgId: string;
74
- /** Events to apply to the target message. */
75
- events: TEvent[];
76
- }
77
- /** @deprecated Use {@link EventsNode} instead. */
78
- export type EventNode<TEvent> = EventsNode<TEvent>;
79
- /**
80
- * Options for streamResponse — per-operation overrides for the assistant message.
81
- * @template TEvent - The codec event type carried by the stream; used by the `resolveWriteOptions` hook.
82
- */
83
- export interface StreamResponseOptions<TEvent> {
84
- /** The msg-id of the immediately preceding message in this branch. */
85
- parent?: string;
86
- /** The msg-id of the message this response replaces (for regeneration). */
87
- forkOf?: string;
88
- /**
89
- * Optional per-event hook invoked before each event is encoded. The
90
- * returned {@link WriteOptions} (if any) override the stream's default
91
- * headers and `msgId` for that one encode call only; return `undefined`
92
- * to use the stream defaults.
93
- *
94
- * Used to carry a subset of events within the stream to a different
95
- * message (e.g. `tool-output-available` chunks that belong on a prior
96
- * assistant message, stamped with `x-ably-amend`). Must not be used
97
- * for events that participate in the encoder's stream-append pipeline
98
- * — streaming state (stream tracker, append ordering) is anchored to
99
- * the stream's default identity and is not affected by per-event
100
- * overrides.
101
- * @param event - The event about to be encoded.
102
- * @returns Per-write overrides for this event, or undefined.
103
- */
104
- resolveWriteOptions?: (event: TEvent) => WriteOptions | undefined;
105
- }
106
- /** The result of streaming a response through the encoder. */
107
- export interface StreamResult {
108
- /** Why the stream ended. */
109
- reason: TurnEndReason;
110
- /**
111
- * The error that caused the stream to fail, present when `reason` is
112
- * `'error'`. This is the original error (e.g. from the LLM provider)
113
- * preserved so the caller can inspect provider-specific fields. The
114
- * turn's `onError` callback also fires with a wrapped `Ably.ErrorInfo`
115
- * (code `StreamError`) for standardized observability.
116
- */
117
- error?: Error;
118
- }
119
- /** Options passed to newTurn for configuring the turn lifecycle. */
120
- export interface NewTurnOptions<TEvent> {
121
- /** The turn identifier (generated by the client transport or the server). */
122
- turnId: string;
123
- /** The user's clientId for attribution. */
124
- clientId?: string;
125
- /**
126
- * The msg-id of the immediately preceding message in this branch.
127
- * Used as the default parent for user messages (via addMessages) and
128
- * assistant messages (via streamResponse) when not overridden per-operation.
129
- */
130
- parent?: string;
131
- /**
132
- * The msg-id of the message this turn replaces (creates a fork).
133
- * Stamped on user messages (for edits) or assistant messages
134
- * (for regeneration).
135
- */
136
- forkOf?: string;
137
- /**
138
- * Called before each Ably message is published in this turn.
139
- * Mutate the Ably message in place to add custom extras.headers.
140
- */
141
- onMessage?: (message: Ably.Message) => void;
142
- /**
143
- * Called when the turn's stream is aborted (by cancel or server).
144
- * Receives a write function to publish final events before the abort finalises.
145
- */
146
- onAbort?: (write: (event: TEvent) => Promise<void>) => void | Promise<void>;
147
- /**
148
- * Called when a cancel message arrives matching this turn.
149
- * Return true to allow cancellation (fires abortSignal, stream aborts).
150
- * Return false to reject (cancel ignored, stream continues).
151
- * If not provided, all cancels are accepted.
152
- */
153
- onCancel?: (request: CancelRequest) => Promise<boolean>;
154
- /**
155
- * Called with non-fatal turn-scoped errors that have no other delivery
156
- * path. Fires in two scenarios:
157
- * - Stream failures in `streamResponse` — the underlying error is also
158
- * returned on `StreamResult.error`, but this callback delivers it
159
- * wrapped as an `Ably.ErrorInfo` (code `StreamError`) for standardized
160
- * observability.
161
- * - Failures in the `onCancel` handler.
162
- *
163
- * Publish failures in `start`, `addMessages`, `addEvents`, and `end`
164
- * are not delivered here — those methods reject their returned promise
165
- * with an `Ably.ErrorInfo`, and the caller should handle it at the await
166
- * site. Turn errors never render the transport unusable, but the turn
167
- * may be in an inconsistent state; the caller should typically `end` it
168
- * with reason `'error'`.
169
- *
170
- * Channel-wide events (e.g. continuity loss) are delivered via the
171
- * transport-level `onError` on {@link ServerTransportOptions}, not here.
172
- */
173
- onError?: (error: Ably.ErrorInfo) => void;
174
- /**
175
- * An external abort signal (typically the HTTP request's `req.signal`) that,
176
- * when fired, aborts this turn. This allows platform-level cancellation —
177
- * request cancellation, serverless function timeout — to stop LLM generation
178
- * and stream piping gracefully.
179
- */
180
- signal?: AbortSignal;
181
- }
182
- /** A server-side turn with explicit lifecycle methods. */
183
- export interface Turn<TEvent, TMessage> {
184
- /** The turn's unique identifier. */
185
- readonly turnId: string;
186
- /** Abort signal scoped to this turn. Fires when a cancel event arrives for this turnId. */
187
- readonly abortSignal: AbortSignal;
188
- /** Publish turn-start event to the channel. Must be called before addMessages or streamResponse. */
189
- start(): Promise<void>;
190
- /**
191
- * Publish user messages to the channel, scoped to this turn.
192
- * Each node's `msgId`, `parentId`, and `forkOf` are used for message identity
193
- * and branching. The node's `headers` override transport-generated defaults
194
- * (e.g. for optimistic reconciliation with the client's inserts).
195
- * @returns The msg-ids of all published messages, in order.
196
- */
197
- addMessages(messages: MessageNode<TMessage>[], options?: AddMessageOptions): Promise<AddMessagesResult>;
198
- /**
199
- * Pipe a ReadableStream through the encoder to the channel.
200
- * Returns when the stream completes, is cancelled, or errors.
201
- * Does NOT call end() — the caller must call end() after streamResponse returns.
202
- */
203
- streamResponse(stream: ReadableStream<TEvent>, options?: StreamResponseOptions<TEvent>): Promise<StreamResult>;
204
- /**
205
- * Publish events targeting existing messages in the tree. Each node
206
- * specifies a target message (by `msgId`) and the events to apply.
207
- * Events are encoded and published with the target's `x-ably-msg-id`,
208
- * so receiving clients apply them to the existing node rather than
209
- * creating a new one.
210
- *
211
- * Used for cross-turn updates such as tool result delivery after
212
- * approval or client-side tool execution.
213
- */
214
- addEvents(nodes: EventsNode<TEvent>[]): Promise<void>;
215
- /** Publish turn-end event to the channel and clean up. */
216
- end(reason: TurnEndReason): Promise<void>;
217
- }
218
- /** Server-side transport that manages turn lifecycles over an Ably channel. */
219
- export interface ServerTransport<TEvent, TMessage> {
220
- /**
221
- * Create a new turn. Synchronous — no channel activity until start() is called.
222
- * The turn is registered for cancel routing immediately so that early cancels
223
- * fire the abort signal.
224
- */
225
- newTurn(options: NewTurnOptions<TEvent>): Turn<TEvent, TMessage>;
226
- /** Unsubscribe from cancel messages, abort all active turns, and clean up. */
227
- close(): void;
228
- }
229
- /** Options for creating a client transport. */
230
- export interface ClientTransportOptions<TEvent, TMessage> {
231
- /** The Ably channel to receive responses on and publish cancel signals to. */
232
- channel: Ably.RealtimeChannel;
233
- /** The codec to use for encoding/decoding. */
234
- codec: Codec<TEvent, TMessage>;
235
- /** The client's identity. Sent to the server in the POST body. */
236
- clientId?: string;
237
- /** Server endpoint URL for the HTTP POST. */
238
- api: string;
239
- /** Headers for the HTTP POST. Function form for dynamic values (e.g. auth tokens). */
240
- headers?: Record<string, string> | (() => Record<string, string>);
241
- /** Additional body fields merged into the HTTP POST. Function form for dynamic values. */
242
- body?: Record<string, unknown> | (() => Record<string, unknown>);
243
- /** Fetch credentials mode for the HTTP POST. */
244
- credentials?: RequestCredentials;
245
- /** Custom fetch implementation. Defaults to `globalThis.fetch`. */
246
- fetch?: typeof globalThis.fetch;
247
- /** Initial messages to seed the conversation tree with. Forms a linear chain. */
248
- messages?: TMessage[];
249
- /** Logger instance for diagnostic output. */
250
- logger?: Logger;
251
- }
252
- /** Per-send options for customizing the HTTP POST and branching metadata. */
253
- export interface SendOptions {
254
- /** Additional fields merged into the HTTP POST body. */
255
- body?: Record<string, unknown>;
256
- /** Additional headers for the HTTP POST. */
257
- headers?: Record<string, string>;
258
- /**
259
- * The msg-id of the message this send replaces (fork).
260
- * Set for regeneration (forkOf an assistant message) or
261
- * edit (forkOf a user message).
262
- */
263
- forkOf?: string;
264
- /**
265
- * The msg-id of the message that precedes this one in the
266
- * conversation thread. If omitted, auto-computed from the last
267
- * message in the view.
268
- */
269
- parent?: string;
270
- }
271
- /** A structured event describing a turn starting or ending. */
272
- export type TurnLifecycleEvent = {
273
- type: 'x-ably-turn-start';
274
- turnId: string;
275
- clientId: string;
276
- /** The msg-id of the parent message, if known. Omitted for root turns. */
277
- parent?: string;
278
- /** The msg-id being forked/replaced, if this is a regeneration or edit. */
279
- forkOf?: string;
280
- } | {
281
- type: 'x-ably-turn-end';
282
- turnId: string;
283
- clientId: string;
284
- reason: TurnEndReason;
285
- };
286
- /** A handle to an active client-side turn, returned by `send()`, `regenerate()`, and `edit()`. */
287
- export interface ActiveTurn<TEvent> {
288
- /** The decoded event stream for this turn. May error if the delivery guarantee is broken (e.g. POST failure, channel continuity loss). */
289
- stream: ReadableStream<TEvent>;
290
- /** The turn's unique identifier. */
291
- turnId: string;
292
- /** Cancel this specific turn. Publishes a cancel message and closes the local stream. */
293
- cancel(): Promise<void>;
294
- /**
295
- * The msg-ids of optimistically inserted user messages, in order.
296
- * Present when the send included user messages (edit); empty for
297
- * regeneration (no user messages to insert optimistically).
298
- */
299
- optimisticMsgIds: string[];
300
- }
301
- /** Options for closing a client transport. */
302
- export interface CloseOptions {
303
- /** Cancel in-progress turns before closing. Publishes a cancel message to the channel. */
304
- cancel?: CancelFilter;
305
- }
306
- /** A single decoded history item with its transport metadata. */
307
- export interface HistoryItem<TMessage> {
308
- /** The decoded domain message. */
309
- message: TMessage;
310
- /** Transport headers for tree identity and ordering. */
311
- headers: Record<string, string>;
312
- /** Ably serial for tree ordering. */
313
- serial: string;
314
- }
315
- /** A page of decoded history from the channel. Internal to View/decodeHistory. */
316
- export interface HistoryPage<TMessage> {
317
- /** Decoded items in chronological order (oldest first). */
318
- items: HistoryItem<TMessage>[];
319
- /** Raw Ably messages that produced this page, in chronological order. */
320
- rawMessages: Ably.InboundMessage[];
321
- /** Whether there are older pages available. */
322
- hasNext(): boolean;
323
- /** Fetch the next (older) page. Returns undefined if no more pages. */
324
- next(): Promise<HistoryPage<TMessage> | undefined>;
325
- }
326
- /** Options for loading channel history. */
327
- export interface LoadHistoryOptions {
328
- /** Max messages per page. Default: 100. */
329
- limit?: number;
330
- }
331
- /** A node in the conversation tree, representing a single domain message. */
332
- export interface MessageNode<TMessage> {
333
- /** Discriminator — identifies this as a message node. */
334
- kind: 'message';
335
- /** The domain message. */
336
- message: TMessage;
337
- /** The x-ably-msg-id of this node — primary key in the tree. */
338
- msgId: string;
339
- /** Parent node's msg-id (x-ably-parent), or undefined for root messages. */
340
- parentId: string | undefined;
341
- /** The msg-id this node forks from (x-ably-fork-of), or undefined if first version. */
342
- forkOf: string | undefined;
343
- /** Full Ably headers for this message. */
344
- headers: Record<string, string>;
345
- /**
346
- * Ably serial for this message. Lexicographically comparable for total order.
347
- * Used to sort siblings deterministically regardless of delivery/history order.
348
- * Absent for optimistic messages (set when the server relay arrives).
349
- */
350
- serial: string | undefined;
351
- }
352
- /** @deprecated Use {@link MessageNode} instead. */
353
- export type TreeNode<TMessage> = MessageNode<TMessage>;
354
- /**
355
- * Materializes a branching conversation tree from a flat oplog.
356
- *
357
- * Owns the complete conversation state — every node from live messages and
358
- * history. `flattenNodes()` returns the linear message list for the currently
359
- * selected branches. Events fire for any change across the full tree.
360
- */
361
- export interface Tree<TMessage> {
362
- /**
363
- * Get all messages that are siblings (alternatives) at a given
364
- * fork point. Returns an array ordered chronologically by serial.
365
- * The message identified by msgId is always included.
366
- */
367
- getSiblings(msgId: string): TMessage[];
368
- /** Whether a message has sibling alternatives (i.e., show navigation arrows). */
369
- hasSiblings(msgId: string): boolean;
370
- /** Get a node by msgId, or undefined if not found. */
371
- getNode(msgId: string): MessageNode<TMessage> | undefined;
372
- /** Get the stored headers for a node by msgId, or undefined if not found. */
373
- getHeaders(msgId: string): Record<string, string> | undefined;
374
- /**
375
- * Insert or update a message in the tree. Reads parent/forkOf from the
376
- * provided headers. If the message already exists (by msgId), updates
377
- * it in place. The optional serial is the Ably message serial used for
378
- * deterministic sibling ordering.
379
- */
380
- upsert(msgId: string, message: TMessage, headers: Record<string, string>, serial?: string): void;
381
- /** Remove a message from the tree. */
382
- delete(msgId: string): void;
383
- /** Active turn IDs grouped by clientId (all turns, not just visible). */
384
- getActiveTurnIds(): Map<string, Set<string>>;
385
- /** Subscribe to tree structure changes (insert, update, delete). */
386
- on(event: 'update', handler: () => void): () => void;
387
- /** Subscribe to raw Ably messages arriving on the channel. */
388
- on(event: 'ably-message', handler: (msg: Ably.InboundMessage) => void): () => void;
389
- /** Subscribe to turn lifecycle events (start and end). */
390
- on(event: 'turn', handler: (event: TurnLifecycleEvent) => void): () => void;
391
- }
392
- /**
393
- * A paginated, branch-aware projection of the conversation tree.
4
+ * The definitions live in `./types/`, split along the Tree / View / Session
5
+ * boundary. This barrel re-exports them so consumers keep importing from a
6
+ * single module:
394
7
  *
395
- * Returns only the visible portion of the selected branch. New live messages
396
- * appear immediately; older messages are revealed progressively via
397
- * `loadOlder()`. Events are scoped to the visible window — subscribers
398
- * are only notified when the visible output changes.
8
+ * - `shared.ts` cross-cutting (RunEndReason, CancelRequest).
9
+ * - `agent.ts` agent session, run runtime, Run / AgentSession.
10
+ * - `tree.ts` conversation-tree nodes, lifecycle events, Tree.
11
+ * - `view.ts` history pagination, branch selection, View.
12
+ * - `client.ts` — client session options, ActiveRun, ClientSession.
399
13
  */
400
- export interface View<TEvent, TMessage> {
401
- /** The visible domain messages along the selected branch. Shorthand for `flattenNodes().map(n => n.message)`. */
402
- getMessages(): TMessage[];
403
- /** Visible nodes along the selected branch, filtered by the pagination window. */
404
- flattenNodes(): MessageNode<TMessage>[];
405
- /** Whether there are older messages that can be loaded or revealed. */
406
- hasOlder(): boolean;
407
- /**
408
- * Reveal older messages. Loads from channel history if the tree doesn't
409
- * have enough, then advances the window to show up to `limit` more messages.
410
- * Emits 'update' when the visible list changes.
411
- * @param limit - Maximum number of older messages to reveal. Defaults to 100.
412
- */
413
- loadOlder(limit?: number): Promise<void>;
414
- /**
415
- * Select a sibling at a fork point by index. Updates this view's
416
- * branch selection. Index is clamped to `[0, siblings.length - 1]`.
417
- * Emits 'update' when the visible output changes.
418
- */
419
- select(msgId: string, index: number): void;
420
- /** Get the index of the currently selected sibling at a fork point. */
421
- getSelectedIndex(msgId: string): number;
422
- /**
423
- * Get all messages that are siblings (alternatives) at a given
424
- * fork point. Returns an array ordered chronologically by serial.
425
- */
426
- getSiblings(msgId: string): TMessage[];
427
- /** Whether a message has sibling alternatives (i.e., show navigation arrows). */
428
- hasSiblings(msgId: string): boolean;
429
- /** Get a node by msgId, or undefined if not found. */
430
- getNode(msgId: string): MessageNode<TMessage> | undefined;
431
- /**
432
- * Send one or more messages and start a new turn. The parent is
433
- * auto-computed from this view's selected branch unless overridden.
434
- * The HTTP POST is fire-and-forget — the returned stream is available
435
- * immediately. If the POST fails, the error is surfaced via the
436
- * transport's `on("error")` and the stream is errored.
437
- */
438
- send(messages: TMessage | TMessage[], options?: SendOptions): Promise<ActiveTurn<TEvent>>;
439
- /**
440
- * Regenerate an assistant message. Creates a new turn that forks the
441
- * target message with no new user messages. Automatically computes
442
- * `forkOf`, `parent`, and truncated `history` from this view's branch.
443
- */
444
- regenerate(messageId: string, options?: SendOptions): Promise<ActiveTurn<TEvent>>;
445
- /**
446
- * Edit a user message. Creates a new turn that forks the target message
447
- * with replacement content. Automatically computes `forkOf`, `parent`,
448
- * and `history` from this view's branch.
449
- */
450
- edit(messageId: string, newMessages: TMessage | TMessage[], options?: SendOptions): Promise<ActiveTurn<TEvent>>;
451
- /**
452
- * Update an existing message and start a continuation turn.
453
- * The local tree is updated optimistically, then the events are sent
454
- * to the server in the POST body. The server publishes them to the channel
455
- * and streams a continuation response.
456
- * @param msgId - The `x-ably-msg-id` of the existing message to amend.
457
- * @param events - Events to apply to the target message (e.g. tool output).
458
- * @param options - Optional send options (body, headers).
459
- * @returns An active turn with the continuation response stream.
460
- */
461
- update(msgId: string, events: TEvent[], options?: SendOptions): Promise<ActiveTurn<TEvent>>;
462
- /** Active turn IDs for turns with visible messages, grouped by clientId. */
463
- getActiveTurnIds(): Map<string, Set<string>>;
464
- /** The visible message list changed (new visible node, branch switch, window shift). */
465
- on(event: 'update', handler: () => void): () => void;
466
- /** A raw Ably message arrived that corresponds to a visible node. */
467
- on(event: 'ably-message', handler: (msg: Ably.InboundMessage) => void): () => void;
468
- /** A turn event occurred for a turn with visible messages in the window. */
469
- on(event: 'turn', handler: (event: TurnLifecycleEvent) => void): () => void;
470
- /** Tear down the view — unsubscribe from tree events and clear internal state. */
471
- close(): void;
472
- }
473
- /** Entry in the StreamRouter's turn map. Not part of the public API. */
474
- export interface TurnEntry<TEvent> {
475
- /** The ReadableStream controller for this turn. */
476
- controller: ReadableStreamDefaultController<TEvent>;
477
- /** The turn's unique identifier. */
478
- turnId: string;
479
- }
480
- /** Client-side transport that manages conversation state over an Ably channel. */
481
- export interface ClientTransport<TEvent, TMessage> {
482
- /** The complete conversation tree — all known nodes, events for any change. */
483
- readonly tree: Tree<TMessage>;
484
- /** The default paginated, branch-aware view for rendering — events scoped to visible messages. */
485
- readonly view: View<TEvent, TMessage>;
486
- /**
487
- * Create an additional view over the same conversation tree.
488
- * Each view has independent branch selections and pagination state.
489
- * The caller is responsible for calling `close()` on the returned view
490
- * when it is no longer needed, or it will be closed when the transport closes.
491
- */
492
- createView(): View<TEvent, TMessage>;
493
- /** Cancel turns matching the filter. Defaults to `{ own: true }` (all own turns). */
494
- cancel(filter?: CancelFilter): Promise<void>;
495
- /**
496
- * Apply events to an existing tree message locally and queue them for
497
- * delivery on the next send.
498
- *
499
- * Use for cross-turn updates where the event value is produced on the
500
- * client (e.g. after `addToolResult` resolves a client-executed tool) and
501
- * must appear in the tree immediately so downstream observers — such as a
502
- * destructive `setMessages(...)` mirror — cannot wipe it before it lands
503
- * on the wire.
504
- *
505
- * The events are applied to the tree via the codec's accumulator
506
- * (tree `update` fires once with the merged message) and queued on the
507
- * transport. The next send operation flushes the queue into the POST
508
- * body's `events` field so the server can republish them over the channel.
509
- *
510
- * If `msgId` is not present in the tree, the call is a no-op and a
511
- * warning is logged.
512
- * @param msgId - The x-ably-msg-id of the existing message to amend.
513
- * @param events - Events to apply and later ship.
514
- */
515
- stageEvents(msgId: string, events: TEvent[]): void;
516
- /**
517
- * Replace the tree's copy of an existing message with a caller-provided
518
- * version, preserving headers and serial.
519
- *
520
- * Use for useChat-style state transitions the codec can't express as
521
- * chunks — the canonical example is `addToolApprovalResponse`, which
522
- * sets `state: 'approval-responded'` on a `dynamic-tool` part directly
523
- * on the UIMessage and has no corresponding chunk variant.
524
- *
525
- * Unlike {@link stageEvents}, staged messages are NOT queued for the
526
- * next send: the tree is authoritative for the POST body's history,
527
- * so updating it is sufficient.
528
- *
529
- * Runs synchronously. Subsequent tree observers (e.g. useMessageSync)
530
- * see the patched state on the next tick, so an interleaved
531
- * observer-turn sync can't clobber it back.
532
- *
533
- * If `msgId` is not present in the tree, the call is a no-op and a
534
- * warning is logged.
535
- * @param msgId - The x-ably-msg-id of the existing message to replace.
536
- * @param message - The patched message to store.
537
- */
538
- stageMessage(msgId: string, message: TMessage): void;
539
- /**
540
- * Returns a promise that resolves when all active turns matching the filter
541
- * have completed. Resolves immediately if no matching turns are active.
542
- * Defaults to `{ own: true }`.
543
- */
544
- waitForTurn(filter?: CancelFilter): Promise<void>;
545
- /**
546
- * Subscribe to non-fatal transport errors. These indicate something went
547
- * wrong but the transport is still operational. Returns an unsubscribe function.
548
- */
549
- on(event: 'error', handler: (error: Ably.ErrorInfo) => void): () => void;
550
- /**
551
- * Tear down the transport: unsubscribe from the channel, close active
552
- * streams, clear all handlers, and prevent further operations.
553
- *
554
- * Pass `cancel` to publish a cancel message before closing. Without it,
555
- * only local state is torn down (the server keeps streaming).
556
- */
557
- close(options?: CloseOptions): Promise<void>;
558
- }
14
+ export type * from './types/agent.js';
15
+ export type * from './types/client.js';
16
+ export type * from './types/shared.js';
17
+ export type * from './types/tree.js';
18
+ export type * from './types/view.js';