@ably/ai-transport 0.0.1 → 0.2.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 (167) hide show
  1. package/README.md +114 -116
  2. package/dist/ably-ai-transport.js +1743 -961
  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 +117 -39
  7. package/dist/core/agent.d.ts +29 -0
  8. package/dist/core/codec/decoder.d.ts +20 -23
  9. package/dist/core/codec/encoder.d.ts +11 -8
  10. package/dist/core/codec/index.d.ts +1 -2
  11. package/dist/core/codec/lifecycle-tracker.d.ts +10 -9
  12. package/dist/core/codec/types.d.ts +410 -101
  13. package/dist/core/transport/agent-session.d.ts +10 -0
  14. package/dist/core/transport/branch-chain.d.ts +43 -0
  15. package/dist/core/transport/client-session.d.ts +13 -0
  16. package/dist/core/transport/decode-fold.d.ts +47 -0
  17. package/dist/core/transport/headers.d.ts +97 -17
  18. package/dist/core/transport/index.d.ts +5 -3
  19. package/dist/core/transport/internal/bounded-map.d.ts +20 -0
  20. package/dist/core/transport/invocation.d.ts +74 -0
  21. package/dist/core/transport/load-conversation.d.ts +128 -0
  22. package/dist/core/transport/load-history.d.ts +39 -0
  23. package/dist/core/transport/pipe-stream.d.ts +9 -8
  24. package/dist/core/transport/run-manager.d.ts +78 -0
  25. package/dist/core/transport/tree.d.ts +435 -0
  26. package/dist/core/transport/types/agent.d.ts +353 -0
  27. package/dist/core/transport/types/client.d.ts +168 -0
  28. package/dist/core/transport/types/shared.d.ts +24 -0
  29. package/dist/core/transport/types/tree.d.ts +315 -0
  30. package/dist/core/transport/types/view.d.ts +222 -0
  31. package/dist/core/transport/types.d.ts +13 -402
  32. package/dist/core/transport/view.d.ts +354 -0
  33. package/dist/errors.d.ts +37 -9
  34. package/dist/index.d.ts +6 -6
  35. package/dist/logger.d.ts +12 -0
  36. package/dist/react/ably-ai-transport-react.js +1164 -645
  37. package/dist/react/ably-ai-transport-react.js.map +1 -1
  38. package/dist/react/ably-ai-transport-react.umd.cjs +1 -1
  39. package/dist/react/ably-ai-transport-react.umd.cjs.map +1 -1
  40. package/dist/react/contexts/client-session-context.d.ts +36 -0
  41. package/dist/react/contexts/client-session-provider.d.ts +53 -0
  42. package/dist/react/create-session-hooks.d.ts +116 -0
  43. package/dist/react/index.d.ts +16 -10
  44. package/dist/react/internal/use-resolved-session.d.ts +36 -0
  45. package/dist/react/use-ably-messages.d.ts +20 -11
  46. package/dist/react/use-client-session.d.ts +81 -0
  47. package/dist/react/use-create-view.d.ts +23 -0
  48. package/dist/react/use-tree.d.ts +35 -0
  49. package/dist/react/use-view.d.ts +110 -0
  50. package/dist/utils.d.ts +32 -23
  51. package/dist/vercel/ably-ai-transport-vercel.js +2748 -1625
  52. package/dist/vercel/ably-ai-transport-vercel.js.map +1 -1
  53. package/dist/vercel/ably-ai-transport-vercel.umd.cjs +1 -1
  54. package/dist/vercel/ably-ai-transport-vercel.umd.cjs.map +1 -1
  55. package/dist/vercel/codec/decoder.d.ts +5 -18
  56. package/dist/vercel/codec/encoder.d.ts +6 -36
  57. package/dist/vercel/codec/events.d.ts +51 -0
  58. package/dist/vercel/codec/index.d.ts +24 -12
  59. package/dist/vercel/codec/reducer.d.ts +144 -0
  60. package/dist/vercel/codec/tool-transitions.d.ts +50 -0
  61. package/dist/vercel/index.d.ts +4 -2
  62. package/dist/vercel/react/ably-ai-transport-vercel-react.js +10298 -1410
  63. package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
  64. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +70 -1
  65. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
  66. package/dist/vercel/react/contexts/chat-transport-context.d.ts +33 -0
  67. package/dist/vercel/react/contexts/chat-transport-provider.d.ts +96 -0
  68. package/dist/vercel/react/index.d.ts +4 -0
  69. package/dist/vercel/react/use-chat-transport.d.ts +66 -21
  70. package/dist/vercel/react/use-message-sync.d.ts +31 -12
  71. package/dist/vercel/run-end-reason.d.ts +29 -0
  72. package/dist/vercel/transport/chat-transport.d.ts +71 -30
  73. package/dist/vercel/transport/index.d.ts +25 -18
  74. package/dist/vercel/transport/run-output-stream.d.ts +56 -0
  75. package/dist/version.d.ts +2 -0
  76. package/package.json +47 -34
  77. package/src/constants.ts +126 -47
  78. package/src/core/agent.ts +68 -0
  79. package/src/core/codec/decoder.ts +71 -98
  80. package/src/core/codec/encoder.ts +115 -58
  81. package/src/core/codec/index.ts +13 -6
  82. package/src/core/codec/lifecycle-tracker.ts +10 -9
  83. package/src/core/codec/types.ts +438 -106
  84. package/src/core/transport/agent-session.ts +1344 -0
  85. package/src/core/transport/branch-chain.ts +58 -0
  86. package/src/core/transport/client-session.ts +775 -0
  87. package/src/core/transport/decode-fold.ts +91 -0
  88. package/src/core/transport/headers.ts +182 -19
  89. package/src/core/transport/index.ts +29 -22
  90. package/src/core/transport/internal/bounded-map.ts +27 -0
  91. package/src/core/transport/invocation.ts +98 -0
  92. package/src/core/transport/load-conversation.ts +355 -0
  93. package/src/core/transport/load-history.ts +269 -0
  94. package/src/core/transport/pipe-stream.ts +58 -40
  95. package/src/core/transport/run-manager.ts +249 -0
  96. package/src/core/transport/tree.ts +1167 -0
  97. package/src/core/transport/types/agent.ts +407 -0
  98. package/src/core/transport/types/client.ts +211 -0
  99. package/src/core/transport/types/shared.ts +27 -0
  100. package/src/core/transport/types/tree.ts +344 -0
  101. package/src/core/transport/types/view.ts +259 -0
  102. package/src/core/transport/types.ts +13 -527
  103. package/src/core/transport/view.ts +1271 -0
  104. package/src/errors.ts +42 -9
  105. package/src/event-emitter.ts +3 -2
  106. package/src/index.ts +55 -39
  107. package/src/logger.ts +14 -1
  108. package/src/react/contexts/client-session-context.ts +41 -0
  109. package/src/react/contexts/client-session-provider.tsx +186 -0
  110. package/src/react/create-session-hooks.ts +141 -0
  111. package/src/react/index.ts +27 -10
  112. package/src/react/internal/use-resolved-session.ts +63 -0
  113. package/src/react/use-ably-messages.ts +47 -19
  114. package/src/react/use-client-session.ts +201 -0
  115. package/src/react/use-create-view.ts +72 -0
  116. package/src/react/use-tree.ts +84 -0
  117. package/src/react/use-view.ts +275 -0
  118. package/src/react/vite.config.ts +4 -1
  119. package/src/utils.ts +63 -45
  120. package/src/vercel/codec/decoder.ts +336 -255
  121. package/src/vercel/codec/encoder.ts +348 -196
  122. package/src/vercel/codec/events.ts +87 -0
  123. package/src/vercel/codec/index.ts +59 -14
  124. package/src/vercel/codec/reducer.ts +977 -0
  125. package/src/vercel/codec/tool-transitions.ts +122 -0
  126. package/src/vercel/index.ts +7 -3
  127. package/src/vercel/react/contexts/chat-transport-context.ts +41 -0
  128. package/src/vercel/react/contexts/chat-transport-provider.tsx +150 -0
  129. package/src/vercel/react/index.ts +13 -1
  130. package/src/vercel/react/use-chat-transport.ts +162 -42
  131. package/src/vercel/react/use-message-sync.ts +121 -22
  132. package/src/vercel/react/vite.config.ts +4 -2
  133. package/src/vercel/run-end-reason.ts +78 -0
  134. package/src/vercel/transport/chat-transport.ts +553 -113
  135. package/src/vercel/transport/index.ts +40 -28
  136. package/src/vercel/transport/run-output-stream.ts +170 -0
  137. package/src/version.ts +2 -0
  138. package/dist/core/transport/client-transport.d.ts +0 -10
  139. package/dist/core/transport/conversation-tree.d.ts +0 -9
  140. package/dist/core/transport/decode-history.d.ts +0 -41
  141. package/dist/core/transport/server-transport.d.ts +0 -7
  142. package/dist/core/transport/stream-router.d.ts +0 -19
  143. package/dist/core/transport/turn-manager.d.ts +0 -34
  144. package/dist/react/use-active-turns.d.ts +0 -8
  145. package/dist/react/use-client-transport.d.ts +0 -7
  146. package/dist/react/use-conversation-tree.d.ts +0 -20
  147. package/dist/react/use-edit.d.ts +0 -7
  148. package/dist/react/use-history.d.ts +0 -19
  149. package/dist/react/use-messages.d.ts +0 -7
  150. package/dist/react/use-regenerate.d.ts +0 -7
  151. package/dist/react/use-send.d.ts +0 -7
  152. package/dist/vercel/codec/accumulator.d.ts +0 -21
  153. package/src/core/transport/client-transport.ts +0 -959
  154. package/src/core/transport/conversation-tree.ts +0 -434
  155. package/src/core/transport/decode-history.ts +0 -337
  156. package/src/core/transport/server-transport.ts +0 -458
  157. package/src/core/transport/stream-router.ts +0 -118
  158. package/src/core/transport/turn-manager.ts +0 -147
  159. package/src/react/use-active-turns.ts +0 -61
  160. package/src/react/use-client-transport.ts +0 -37
  161. package/src/react/use-conversation-tree.ts +0 -71
  162. package/src/react/use-edit.ts +0 -24
  163. package/src/react/use-history.ts +0 -111
  164. package/src/react/use-messages.ts +0 -32
  165. package/src/react/use-regenerate.ts +0 -24
  166. package/src/react/use-send.ts +0 -25
  167. package/src/vercel/codec/accumulator.ts +0 -603
@@ -5,52 +5,64 @@
5
5
  * explicitly when using the Vercel AI SDK integration.
6
6
  *
7
7
  * ```ts
8
- * import { createClientTransport } from '@ably/ai-transport/vercel';
8
+ * import { createClientSession } from '@ably/ai-transport/vercel';
9
9
  *
10
- * const transport = createClientTransport({ channel });
10
+ * const session = createClientSession({ client, channelName: 'ai:demo' });
11
+ * await session.connect();
11
12
  * ```
12
13
  */
13
14
 
14
15
  // Chat transport adapter
15
16
  export type { ChatTransport, ChatTransportOptions, SendMessagesRequestContext } from './chat-transport.js';
16
- export { createChatTransport } from './chat-transport.js';
17
+ export { createChatTransport, DEFAULT_VERCEL_API } from './chat-transport.js';
17
18
 
18
19
  import type * as AI from 'ai';
19
20
 
20
- import { createClientTransport as createCoreClientTransport } from '../../core/transport/client-transport.js';
21
- import { createServerTransport as createCoreServerTransport } from '../../core/transport/server-transport.js';
21
+ import { createAgentSession as createCoreAgentSession } from '../../core/transport/agent-session.js';
22
+ import { createClientSession as createCoreClientSession } from '../../core/transport/client-session.js';
22
23
  import type {
23
- ClientTransport,
24
- ClientTransportOptions,
25
- ServerTransport,
26
- ServerTransportOptions,
24
+ AgentSession,
25
+ AgentSessionOptions,
26
+ ClientSession,
27
+ ClientSessionOptions,
27
28
  } from '../../core/transport/types.js';
28
- import { UIMessageCodec } from '../codec/index.js';
29
+ import { UIMessageCodec, type VercelInput, type VercelOutput, type VercelProjection } from '../codec/index.js';
29
30
 
30
- /** Options for creating a Vercel client transport. Same as core options but without the codec field. */
31
- export type VercelClientTransportOptions = Omit<ClientTransportOptions<AI.UIMessageChunk, AI.UIMessage>, 'codec'>;
31
+ /** Core client session options with Vercel AI SDK types pre-applied. */
32
+ type CoreClientOpts = ClientSessionOptions<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
32
33
 
33
- /** Options for creating a Vercel server transport. Same as core options but without the codec field. */
34
- export type VercelServerTransportOptions = Omit<ServerTransportOptions<AI.UIMessageChunk, AI.UIMessage>, 'codec'>;
34
+ /** Options for creating a Vercel client session. Same as core options but without the codec field. */
35
+ export type VercelClientSessionOptions = Omit<CoreClientOpts, 'codec'>;
36
+
37
+ /** Options for creating a Vercel agent session. Same as core options but without the codec field. */
38
+ export type VercelAgentSessionOptions = Omit<
39
+ AgentSessionOptions<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>,
40
+ 'codec'
41
+ >;
35
42
 
36
43
  /**
37
- * Create a client-side transport pre-configured with the Vercel AI SDK codec.
44
+ * Create a client-side session pre-configured with the Vercel AI SDK codec.
38
45
  *
39
- * Equivalent to calling the core `createClientTransport` with `codec: UIMessageCodec`.
40
- * @param options - Configuration for the client transport (codec is provided automatically).
41
- * @returns A new {@link ClientTransport} for Vercel AI SDK UIMessage/UIMessageChunk types.
46
+ * Equivalent to calling the core `createClientSession` with `codec: UIMessageCodec`.
47
+ * The core session is a pure Ably-channel transport it never sends HTTP.
48
+ * To wake a serverless agent over HTTP, POST `run.toInvocation().toJSON()`
49
+ * yourself, or use `createChatTransport` (which does it for useChat parity).
50
+ * @param options - Configuration for the client session (codec is provided automatically).
51
+ * @returns A new {@link ClientSession} for Vercel AI SDK UIMessage/UIMessageChunk types.
42
52
  */
43
- export const createClientTransport = (
44
- options: VercelClientTransportOptions,
45
- ): ClientTransport<AI.UIMessageChunk, AI.UIMessage> => createCoreClientTransport({ ...options, codec: UIMessageCodec });
53
+ export const createClientSession = (
54
+ options: VercelClientSessionOptions,
55
+ ): ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage> =>
56
+ createCoreClientSession({ ...options, codec: UIMessageCodec });
46
57
 
47
58
  /**
48
- * Create a server-side transport pre-configured with the Vercel AI SDK codec.
59
+ * Create an agent (server-side) session pre-configured with the Vercel AI SDK codec.
49
60
  *
50
- * Equivalent to calling the core `createServerTransport` with `codec: UIMessageCodec`.
51
- * @param options - Configuration for the server transport (codec is provided automatically).
52
- * @returns A new {@link ServerTransport} for Vercel AI SDK UIMessage/UIMessageChunk types.
61
+ * Equivalent to calling the core `createAgentSession` with `codec: UIMessageCodec`.
62
+ * @param options - Configuration for the agent session (codec is provided automatically).
63
+ * @returns A new {@link AgentSession} for Vercel AI SDK UIMessage/UIMessageChunk types.
53
64
  */
54
- export const createServerTransport = (
55
- options: VercelServerTransportOptions,
56
- ): ServerTransport<AI.UIMessageChunk, AI.UIMessage> => createCoreServerTransport({ ...options, codec: UIMessageCodec });
65
+ export const createAgentSession = (
66
+ options: VercelAgentSessionOptions,
67
+ ): AgentSession<VercelOutput, VercelProjection, AI.UIMessage> =>
68
+ createCoreAgentSession({ ...options, codec: UIMessageCodec });
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Vercel-owned per-run output stream.
3
+ *
4
+ * Builds the `ReadableStream<UIMessageChunk>` that `useChat` consumes by
5
+ * subscribing to the session Tree's `output` and `run` events for a single
6
+ * run. Streaming is a useChat-integration concern, so it lives in the Vercel
7
+ * layer rather than the generic core: the core Tree is the fan-out point, and
8
+ * this projects its events into the shape `useChat` expects.
9
+ *
10
+ * Close semantics — the stream the consumer reads ends when:
11
+ * - a **terminal chunk** (`finish` / `error` / `abort`) is folded for the run.
12
+ * This is the signal `useChat`'s `sendAutomaticallyWhen` waits for, and it
13
+ * fires even when the run merely *suspends* for a tool call (a tool-calls
14
+ * `finish` ends the consumer stream while the core run stays alive in the
15
+ * Tree for the continuation); or
16
+ * - the run reaches `run-end`, which is always terminal (safety net for a run
17
+ * that ends without emitting a terminal chunk). A `run-suspend` keeps the
18
+ * core run alive and does not close the consumer stream.
19
+ *
20
+ * It errors when the session emits a non-fatal `error` (e.g. channel
21
+ * continuity loss, or an agent-reported mid-run error), so the consumer's
22
+ * reader rejects rather than hanging.
23
+ */
24
+
25
+ import * as Ably from 'ably';
26
+ import type * as AI from 'ai';
27
+
28
+ import type { ClientSession } from '../../core/transport/types.js';
29
+ import { ErrorCode } from '../../errors.js';
30
+ import type { VercelInput, VercelOutput, VercelProjection } from '../codec/index.js';
31
+
32
+ type VercelSession = ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
33
+
34
+ /**
35
+ * Whether a Vercel output chunk ends the consumer-facing stream. The terminal
36
+ * variants are `finish` (end of an LLM turn, including tool-calls), `error`,
37
+ * and `abort`.
38
+ * @param output - The decoded output chunk.
39
+ * @returns True when the chunk should close the consumer stream.
40
+ */
41
+ const isTerminalChunk = (output: VercelOutput): boolean =>
42
+ output.type === 'finish' || output.type === 'error' || output.type === 'abort';
43
+
44
+ /** A consumer-facing run output stream plus the handles to settle it externally. */
45
+ export interface RunOutputStream {
46
+ /** The stream of decoded outputs for the run, as `useChat` consumes it. */
47
+ stream: ReadableStream<VercelOutput>;
48
+ /** Close the stream now (e.g. on local cancel). Idempotent. */
49
+ close: () => void;
50
+ /** Error the stream now (e.g. on a failed agent-invocation POST). Idempotent. */
51
+ error: (reason: Ably.ErrorInfo) => void;
52
+ }
53
+
54
+ /**
55
+ * Create a consumer-facing output stream for a send, sourced from the session
56
+ * Tree's events. See the module docs for close/error semantics. The returned
57
+ * `close`/`error` let the caller settle the stream for conditions the Tree
58
+ * doesn't surface (local cancel, POST failure).
59
+ *
60
+ * Outputs route PURELY by the triggering input's codec-message-id — the key the
61
+ * client owns from send time, before the agent mints the runId. The agent's
62
+ * minted runId is supplied as a promise so the run-end safety-net can still
63
+ * close the stream once it resolves.
64
+ * @param session - The Vercel client session whose Tree to observe.
65
+ * @param runId - The agent-minted runId, resolved when run-start is observed.
66
+ * Used only by the run-end safety-net; routing keys on `inputCodecMessageId`.
67
+ * @param inputCodecMessageId - The triggering input's codec-message-id. An
68
+ * output routes to this stream when it carries this id.
69
+ * @returns The stream and its external settle handles.
70
+ */
71
+ export const createRunOutputStream = (
72
+ session: VercelSession,
73
+ runId: Promise<string>,
74
+ inputCodecMessageId: string,
75
+ ): RunOutputStream => {
76
+ const holder: { controller?: ReadableStreamDefaultController<VercelOutput> } = {};
77
+ // ReadableStream's start() runs synchronously, so the controller is captured
78
+ // before the constructor returns.
79
+ const unsubscribe: (() => void)[] = [];
80
+ const stream = new ReadableStream<VercelOutput>({
81
+ start: (controller) => {
82
+ holder.controller = controller;
83
+ },
84
+ cancel: () => {
85
+ teardown();
86
+ },
87
+ });
88
+ const { controller } = holder;
89
+ if (!controller) {
90
+ throw new Ably.ErrorInfo(
91
+ 'unable to create run stream; ReadableStream start() was not called synchronously',
92
+ ErrorCode.SessionSubscriptionError,
93
+ 500,
94
+ );
95
+ }
96
+
97
+ // The agent mints the runId; learn it (for the run-end safety-net) when the
98
+ // promise resolves. Fire-and-forget: the stream opens on the input key, so a
99
+ // never-resolving runId only forgoes the safety-net, not normal close.
100
+ let resolvedRunId: string | undefined;
101
+ // Best-effort: failure only disables the run-end safety-net; normal close is
102
+ // the terminal chunk. `void` discards the promise (no await needed here).
103
+ void runId.then(
104
+ (id) => {
105
+ resolvedRunId = id;
106
+ },
107
+ () => {
108
+ /* session closed before run-start; safety-net stays disarmed */
109
+ },
110
+ );
111
+
112
+ let settled = false;
113
+ const teardown = (): void => {
114
+ for (const unsub of unsubscribe) unsub();
115
+ unsubscribe.length = 0;
116
+ };
117
+ // Settle the stream at most once: run the controller action (close/error),
118
+ // swallow the throw if the consumer already cancelled, then tear down.
119
+ const settle = (action: () => void): void => {
120
+ if (settled) return;
121
+ settled = true;
122
+ try {
123
+ action();
124
+ } catch {
125
+ /* consumer already cancelled the stream */
126
+ }
127
+ teardown();
128
+ };
129
+ const close = (): void => {
130
+ settle(() => {
131
+ controller.close();
132
+ });
133
+ };
134
+ const error = (reason: Ably.ErrorInfo): void => {
135
+ settle(() => {
136
+ controller.error(reason);
137
+ });
138
+ };
139
+
140
+ unsubscribe.push(
141
+ session.tree.on('output', (event) => {
142
+ if (event.inputCodecMessageId !== inputCodecMessageId) return;
143
+ for (const output of event.events) {
144
+ try {
145
+ controller.enqueue(output);
146
+ } catch {
147
+ close();
148
+ return;
149
+ }
150
+ if (isTerminalChunk(output)) {
151
+ close();
152
+ return;
153
+ }
154
+ }
155
+ }),
156
+ session.tree.on('run', (event) => {
157
+ // run-end is always terminal; a run-suspend (event.type === 'suspend')
158
+ // keeps the core run alive and must not close the consumer stream. Match
159
+ // against the resolved runId once the agent has minted it.
160
+ if (event.type === 'end' && resolvedRunId !== undefined && event.runId === resolvedRunId) {
161
+ close();
162
+ }
163
+ }),
164
+ session.on('error', (reason) => {
165
+ error(reason);
166
+ }),
167
+ );
168
+
169
+ return { stream, close, error };
170
+ };
package/src/version.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** SDK version. Kept in sync with `package.json` by the `/release` workflow. */
2
+ export const VERSION = '0.2.0';
@@ -1,10 +0,0 @@
1
- import { ClientTransport, ClientTransportOptions } from './types.js';
2
- /**
3
- * Create a client-side transport that manages conversation state over an Ably channel.
4
- *
5
- * Subscribes to the channel immediately (before attach per RTL7g). The caller should
6
- * ensure the channel is attached or will be attached shortly after creation.
7
- * @param options - Configuration for the client transport.
8
- * @returns A new {@link ClientTransport} instance.
9
- */
10
- export declare const createClientTransport: <TEvent, TMessage>(options: ClientTransportOptions<TEvent, TMessage>) => ClientTransport<TEvent, TMessage>;
@@ -1,9 +0,0 @@
1
- import { Logger } from '../../logger.js';
2
- import { ConversationTree } from './types.js';
3
- /**
4
- * Create a ConversationTree that materializes branching history from a flat oplog.
5
- * @param getKey - Codec function that returns a stable key for a domain message.
6
- * @param logger - Logger for diagnostic output.
7
- * @returns A new {@link ConversationTree} instance.
8
- */
9
- export declare const createConversationTree: <TMessage>(getKey: (message: TMessage) => string, logger: Logger) => ConversationTree<TMessage>;
@@ -1,41 +0,0 @@
1
- import { Logger } from '../../logger.js';
2
- import { Codec } from '../codec/types.js';
3
- import { LoadHistoryOptions, PaginatedMessages } from './types.js';
4
- /**
5
- * decodeHistory — load conversation history from an Ably channel and
6
- * return decoded messages as a PaginatedMessages result.
7
- *
8
- * Uses a fresh decoder (not shared with the live subscription) to avoid
9
- * state conflicts. Per-turn accumulators handle interleaved turns correctly.
10
- *
11
- * The `limit` option controls the number of **messages** returned,
12
- * not the number of Ably wire messages fetched. The implementation pages
13
- * back through Ably history until `limit` complete messages have
14
- * been assembled. Partial turns (incomplete at the page boundary) are
15
- * buffered internally and completed when `next()` fetches more pages.
16
- *
17
- * Only completed messages appear in `items`. A message is complete when
18
- * its terminal event (finish/abort/error) has been received.
19
- *
20
- * Because Ably history returns newest-first while the decoder requires
21
- * chronological order, all collected Ably messages are re-decoded from
22
- * oldest to newest after each page fetch. This handles turns that span
23
- * page boundaries correctly.
24
- */
25
- import type * as Ably from 'ably';
26
- /**
27
- * Load conversation history from a channel and return decoded messages.
28
- *
29
- * Attaches the channel if not already attached, then calls
30
- * `channel.history({ untilAttach: true })` to guarantee no gap between
31
- * historical and live messages. The attach is idempotent.
32
- *
33
- * The `limit` option controls the number of complete messages
34
- * returned per page, not the number of Ably wire messages fetched.
35
- * @param channel - The Ably channel to load history from.
36
- * @param codec - The codec for decoding wire messages into domain messages.
37
- * @param options - Pagination options.
38
- * @param logger - Logger for diagnostic output.
39
- * @returns The first page of decoded history messages.
40
- */
41
- export declare const decodeHistory: <TEvent, TMessage>(channel: Ably.RealtimeChannel, codec: Codec<TEvent, TMessage>, options: LoadHistoryOptions | undefined, logger: Logger) => Promise<PaginatedMessages<TMessage>>;
@@ -1,7 +0,0 @@
1
- import { ServerTransport, ServerTransportOptions } from './types.js';
2
- /**
3
- * Create a server transport bound to the given channel and codec.
4
- * @param options - Transport configuration.
5
- * @returns A new {@link ServerTransport} instance.
6
- */
7
- export declare const createServerTransport: <TEvent, TMessage>(options: ServerTransportOptions<TEvent, TMessage>) => ServerTransport<TEvent, TMessage>;
@@ -1,19 +0,0 @@
1
- import { Logger } from '../../logger.js';
2
- /** Routes decoded events to the correct turn's ReadableStream. */
3
- export interface StreamRouter<TEvent> {
4
- /** Register a new stream for a turnId. Returns the ReadableStream the consumer reads from. */
5
- createStream(turnId: string): ReadableStream<TEvent>;
6
- /** Close the stream for a turnId. Returns true if a stream was closed. */
7
- closeStream(turnId: string): boolean;
8
- /** Enqueue an event to the correct stream. Returns true if routed successfully. */
9
- route(turnId: string, event: TEvent): boolean;
10
- /** Whether a specific turnId has an active stream. */
11
- has(turnId: string): boolean;
12
- }
13
- /**
14
- * Create a StreamRouter that routes decoded events to per-turn ReadableStreams.
15
- * @param isTerminal - Predicate that returns true for events that close the stream.
16
- * @param logger - Logger for diagnostic output.
17
- * @returns A new {@link StreamRouter} instance.
18
- */
19
- export declare const createStreamRouter: <TEvent>(isTerminal: (event: TEvent) => boolean, logger: Logger) => StreamRouter<TEvent>;
@@ -1,34 +0,0 @@
1
- import { Logger } from '../../logger.js';
2
- import { TurnEndReason } from './types.js';
3
- /**
4
- * Server-side turn state management and lifecycle event publishing.
5
- *
6
- * Owns the authoritative turn lifecycle. Tracks active turns with their
7
- * AbortControllers and clientIds. Publishes turn-start and turn-end events
8
- * on the Ably channel so all clients can react to turn state changes.
9
- */
10
- import type * as Ably from 'ably';
11
- /** Manages active turns and publishes turn lifecycle events on the channel. */
12
- export interface TurnManager {
13
- /** Register a new turn. Publishes turn-start on the channel. Returns AbortSignal. */
14
- startTurn(turnId: string, clientId?: string, controller?: AbortController): Promise<AbortSignal>;
15
- /** End a turn. Publishes turn-end on the channel. Cleans up internal state. */
16
- endTurn(turnId: string, reason: TurnEndReason): Promise<void>;
17
- /** Get the AbortSignal for a turn. */
18
- getSignal(turnId: string): AbortSignal | undefined;
19
- /** Get the clientId that owns a turn. */
20
- getClientId(turnId: string): string | undefined;
21
- /** Abort the signal for a turn. */
22
- abort(turnId: string): void;
23
- /** Get all active turn IDs. */
24
- getActiveTurnIds(): string[];
25
- /** Abort all active turns and clear state. */
26
- close(): void;
27
- }
28
- /**
29
- * Create a turn manager bound to the given channel.
30
- * @param channel - The Ably channel to publish lifecycle events on.
31
- * @param logger - Optional logger for diagnostic output.
32
- * @returns A new {@link TurnManager} instance.
33
- */
34
- export declare const createTurnManager: (channel: Ably.RealtimeChannel, logger?: Logger) => TurnManager;
@@ -1,8 +0,0 @@
1
- import { ClientTransport } from '../core/transport/types.js';
2
- /**
3
- * Returns a reactive Map of all active turns on the channel, keyed by clientId.
4
- * Updates when turns start or end.
5
- * @param transport - The client transport to observe, or null/undefined if not yet available.
6
- * @returns A Map where keys are clientIds and values are Sets of active turnIds.
7
- */
8
- export declare const useActiveTurns: <TEvent, TMessage>(transport: ClientTransport<TEvent, TMessage> | null | undefined) => Map<string, Set<string>>;
@@ -1,7 +0,0 @@
1
- import { ClientTransport, ClientTransportOptions } from '../core/transport/types.js';
2
- /**
3
- * Create and memoize a {@link ClientTransport} across renders.
4
- * @param options - Configuration for the client transport.
5
- * @returns The memoized transport instance.
6
- */
7
- export declare const useClientTransport: <TEvent, TMessage>(options: ClientTransportOptions<TEvent, TMessage>) => ClientTransport<TEvent, TMessage>;
@@ -1,20 +0,0 @@
1
- import { ClientTransport } from '../core/transport/types.js';
2
- /** Handle for navigating the branching conversation tree. */
3
- export interface ConversationTreeHandle<TMessage> {
4
- /** Linear message list for the currently selected branch. */
5
- messages: TMessage[];
6
- /** Get all sibling messages at a fork point. */
7
- getSiblings: (msgId: string) => TMessage[];
8
- /** Whether a message has siblings (should show navigation arrows). */
9
- hasSiblings: (msgId: string) => boolean;
10
- /** Index of the currently selected sibling. */
11
- getSelectedIndex: (msgId: string) => number;
12
- /** Navigate to a sibling. Triggers re-render with updated messages. */
13
- selectSibling: (msgId: string, index: number) => void;
14
- }
15
- /**
16
- * Subscribe to transport message updates and provide branch navigation primitives.
17
- * @param transport - The client transport whose conversation tree to navigate.
18
- * @returns A {@link ConversationTreeHandle} with the current messages and navigation methods.
19
- */
20
- export declare const useConversationTree: <TEvent, TMessage>(transport: ClientTransport<TEvent, TMessage>) => ConversationTreeHandle<TMessage>;
@@ -1,7 +0,0 @@
1
- import { ActiveTurn, ClientTransport, SendOptions } from '../core/transport/types.js';
2
- /**
3
- * Return a stable `edit` callback bound to the given transport.
4
- * @param transport - The client transport to edit through.
5
- * @returns A function that edits a user message and returns an {@link ActiveTurn} handle.
6
- */
7
- export declare const useEdit: <TEvent, TMessage>(transport: ClientTransport<TEvent, TMessage>) => ((messageId: string, newMessages: TMessage | TMessage[], options?: SendOptions) => Promise<ActiveTurn<TEvent>>);
@@ -1,19 +0,0 @@
1
- import { ClientTransport, LoadHistoryOptions } from '../core/transport/types.js';
2
- /** Handle for paginated history loading. */
3
- export interface HistoryHandle {
4
- /** Are there older pages available? False until `load()` has been called. */
5
- hasNext: boolean;
6
- /** Is a page being fetched? */
7
- loading: boolean;
8
- /** Load the first page (or re-load with different options). Inserts into the conversation tree. */
9
- load: (options?: LoadHistoryOptions) => Promise<void>;
10
- /** Fetch the next (older) page. No-op if loading or no more pages. Inserts into the conversation tree. */
11
- next: () => Promise<void>;
12
- }
13
- /**
14
- * Paginated history handle for a client transport.
15
- * @param transport - The client transport to load history from, or null/undefined if not yet available.
16
- * @param options - When provided, auto-loads the first page on mount. Omit or pass null for manual loading.
17
- * @returns A {@link HistoryHandle} for loading and paginating through history.
18
- */
19
- export declare const useHistory: <TEvent, TMessage>(transport: ClientTransport<TEvent, TMessage> | null | undefined, options?: LoadHistoryOptions | null) => HistoryHandle;
@@ -1,7 +0,0 @@
1
- import { ClientTransport } from '../core/transport/types.js';
2
- /**
3
- * Subscribe to transport message updates and return the current message list.
4
- * @param transport - The client transport to observe.
5
- * @returns The current list of decoded messages.
6
- */
7
- export declare const useMessages: <TEvent, TMessage>(transport: ClientTransport<TEvent, TMessage>) => TMessage[];
@@ -1,7 +0,0 @@
1
- import { ActiveTurn, ClientTransport, SendOptions } from '../core/transport/types.js';
2
- /**
3
- * Return a stable `regenerate` callback bound to the given transport.
4
- * @param transport - The client transport to regenerate through.
5
- * @returns A function that regenerates an assistant message and returns an {@link ActiveTurn} handle.
6
- */
7
- export declare const useRegenerate: <TEvent, TMessage>(transport: ClientTransport<TEvent, TMessage>) => ((messageId: string, options?: SendOptions) => Promise<ActiveTurn<TEvent>>);
@@ -1,7 +0,0 @@
1
- import { ActiveTurn, ClientTransport, SendOptions } from '../core/transport/types.js';
2
- /**
3
- * Return a stable `send` callback bound to the given transport.
4
- * @param transport - The client transport to send through.
5
- * @returns A function that sends messages and returns an {@link ActiveTurn} handle.
6
- */
7
- export declare const useSend: <TEvent, TMessage>(transport: ClientTransport<TEvent, TMessage>) => ((messages: TMessage[], options?: SendOptions) => Promise<ActiveTurn<TEvent>>);
@@ -1,21 +0,0 @@
1
- import { MessageAccumulator } from '../../core/codec/types.js';
2
- /**
3
- * Vercel AI SDK Message Accumulator
4
- *
5
- * Builds and maintains a UIMessage[] list from decoder outputs.
6
- * Implements MessageAccumulator<UIMessageChunk, UIMessage>.
7
- *
8
- * The accumulator consumes DecoderOutput[] from the decoder and groups
9
- * streaming events into UIMessage objects using lifecycle boundaries
10
- * (start/finish). Complete messages (from writeMessages) are inserted
11
- * directly.
12
- *
13
- * Multiple messages can be in-progress concurrently — each is identified
14
- * by the `messageId` field on DecoderOutput (read from x-ably-msg-id).
15
- */
16
- import type * as AI from 'ai';
17
- /**
18
- * Create a Vercel AI SDK accumulator that builds UIMessage[] from decoder outputs.
19
- * @returns A {@link MessageAccumulator} for UIMessageChunk/UIMessage.
20
- */
21
- export declare const createAccumulator: () => MessageAccumulator<AI.UIMessageChunk, AI.UIMessage>;