@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.
- package/README.md +114 -116
- package/dist/ably-ai-transport.js +1743 -961
- package/dist/ably-ai-transport.js.map +1 -1
- package/dist/ably-ai-transport.umd.cjs +1 -1
- package/dist/ably-ai-transport.umd.cjs.map +1 -1
- package/dist/constants.d.ts +117 -39
- package/dist/core/agent.d.ts +29 -0
- package/dist/core/codec/decoder.d.ts +20 -23
- package/dist/core/codec/encoder.d.ts +11 -8
- package/dist/core/codec/index.d.ts +1 -2
- package/dist/core/codec/lifecycle-tracker.d.ts +10 -9
- package/dist/core/codec/types.d.ts +410 -101
- package/dist/core/transport/agent-session.d.ts +10 -0
- package/dist/core/transport/branch-chain.d.ts +43 -0
- package/dist/core/transport/client-session.d.ts +13 -0
- package/dist/core/transport/decode-fold.d.ts +47 -0
- package/dist/core/transport/headers.d.ts +97 -17
- package/dist/core/transport/index.d.ts +5 -3
- package/dist/core/transport/internal/bounded-map.d.ts +20 -0
- package/dist/core/transport/invocation.d.ts +74 -0
- package/dist/core/transport/load-conversation.d.ts +128 -0
- package/dist/core/transport/load-history.d.ts +39 -0
- package/dist/core/transport/pipe-stream.d.ts +9 -8
- package/dist/core/transport/run-manager.d.ts +78 -0
- package/dist/core/transport/tree.d.ts +435 -0
- package/dist/core/transport/types/agent.d.ts +353 -0
- package/dist/core/transport/types/client.d.ts +168 -0
- package/dist/core/transport/types/shared.d.ts +24 -0
- package/dist/core/transport/types/tree.d.ts +315 -0
- package/dist/core/transport/types/view.d.ts +222 -0
- package/dist/core/transport/types.d.ts +13 -402
- package/dist/core/transport/view.d.ts +354 -0
- package/dist/errors.d.ts +37 -9
- package/dist/index.d.ts +6 -6
- package/dist/logger.d.ts +12 -0
- package/dist/react/ably-ai-transport-react.js +1164 -645
- package/dist/react/ably-ai-transport-react.js.map +1 -1
- package/dist/react/ably-ai-transport-react.umd.cjs +1 -1
- package/dist/react/ably-ai-transport-react.umd.cjs.map +1 -1
- package/dist/react/contexts/client-session-context.d.ts +36 -0
- package/dist/react/contexts/client-session-provider.d.ts +53 -0
- package/dist/react/create-session-hooks.d.ts +116 -0
- package/dist/react/index.d.ts +16 -10
- package/dist/react/internal/use-resolved-session.d.ts +36 -0
- package/dist/react/use-ably-messages.d.ts +20 -11
- package/dist/react/use-client-session.d.ts +81 -0
- package/dist/react/use-create-view.d.ts +23 -0
- package/dist/react/use-tree.d.ts +35 -0
- package/dist/react/use-view.d.ts +110 -0
- package/dist/utils.d.ts +32 -23
- package/dist/vercel/ably-ai-transport-vercel.js +2748 -1625
- package/dist/vercel/ably-ai-transport-vercel.js.map +1 -1
- package/dist/vercel/ably-ai-transport-vercel.umd.cjs +1 -1
- package/dist/vercel/ably-ai-transport-vercel.umd.cjs.map +1 -1
- package/dist/vercel/codec/decoder.d.ts +5 -18
- package/dist/vercel/codec/encoder.d.ts +6 -36
- package/dist/vercel/codec/events.d.ts +51 -0
- package/dist/vercel/codec/index.d.ts +24 -12
- package/dist/vercel/codec/reducer.d.ts +144 -0
- package/dist/vercel/codec/tool-transitions.d.ts +50 -0
- package/dist/vercel/index.d.ts +4 -2
- package/dist/vercel/react/ably-ai-transport-vercel-react.js +10298 -1410
- package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +70 -1
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
- package/dist/vercel/react/contexts/chat-transport-context.d.ts +33 -0
- package/dist/vercel/react/contexts/chat-transport-provider.d.ts +96 -0
- package/dist/vercel/react/index.d.ts +4 -0
- package/dist/vercel/react/use-chat-transport.d.ts +66 -21
- package/dist/vercel/react/use-message-sync.d.ts +31 -12
- package/dist/vercel/run-end-reason.d.ts +29 -0
- package/dist/vercel/transport/chat-transport.d.ts +71 -30
- package/dist/vercel/transport/index.d.ts +25 -18
- package/dist/vercel/transport/run-output-stream.d.ts +56 -0
- package/dist/version.d.ts +2 -0
- package/package.json +47 -34
- package/src/constants.ts +126 -47
- package/src/core/agent.ts +68 -0
- package/src/core/codec/decoder.ts +71 -98
- package/src/core/codec/encoder.ts +115 -58
- package/src/core/codec/index.ts +13 -6
- package/src/core/codec/lifecycle-tracker.ts +10 -9
- package/src/core/codec/types.ts +438 -106
- package/src/core/transport/agent-session.ts +1344 -0
- package/src/core/transport/branch-chain.ts +58 -0
- package/src/core/transport/client-session.ts +775 -0
- package/src/core/transport/decode-fold.ts +91 -0
- package/src/core/transport/headers.ts +182 -19
- package/src/core/transport/index.ts +29 -22
- package/src/core/transport/internal/bounded-map.ts +27 -0
- package/src/core/transport/invocation.ts +98 -0
- package/src/core/transport/load-conversation.ts +355 -0
- package/src/core/transport/load-history.ts +269 -0
- package/src/core/transport/pipe-stream.ts +58 -40
- package/src/core/transport/run-manager.ts +249 -0
- package/src/core/transport/tree.ts +1167 -0
- package/src/core/transport/types/agent.ts +407 -0
- package/src/core/transport/types/client.ts +211 -0
- package/src/core/transport/types/shared.ts +27 -0
- package/src/core/transport/types/tree.ts +344 -0
- package/src/core/transport/types/view.ts +259 -0
- package/src/core/transport/types.ts +13 -527
- package/src/core/transport/view.ts +1271 -0
- package/src/errors.ts +42 -9
- package/src/event-emitter.ts +3 -2
- package/src/index.ts +55 -39
- package/src/logger.ts +14 -1
- package/src/react/contexts/client-session-context.ts +41 -0
- package/src/react/contexts/client-session-provider.tsx +186 -0
- package/src/react/create-session-hooks.ts +141 -0
- package/src/react/index.ts +27 -10
- package/src/react/internal/use-resolved-session.ts +63 -0
- package/src/react/use-ably-messages.ts +47 -19
- package/src/react/use-client-session.ts +201 -0
- package/src/react/use-create-view.ts +72 -0
- package/src/react/use-tree.ts +84 -0
- package/src/react/use-view.ts +275 -0
- package/src/react/vite.config.ts +4 -1
- package/src/utils.ts +63 -45
- package/src/vercel/codec/decoder.ts +336 -255
- package/src/vercel/codec/encoder.ts +348 -196
- package/src/vercel/codec/events.ts +87 -0
- package/src/vercel/codec/index.ts +59 -14
- package/src/vercel/codec/reducer.ts +977 -0
- package/src/vercel/codec/tool-transitions.ts +122 -0
- package/src/vercel/index.ts +7 -3
- package/src/vercel/react/contexts/chat-transport-context.ts +41 -0
- package/src/vercel/react/contexts/chat-transport-provider.tsx +150 -0
- package/src/vercel/react/index.ts +13 -1
- package/src/vercel/react/use-chat-transport.ts +162 -42
- package/src/vercel/react/use-message-sync.ts +121 -22
- package/src/vercel/react/vite.config.ts +4 -2
- package/src/vercel/run-end-reason.ts +78 -0
- package/src/vercel/transport/chat-transport.ts +553 -113
- package/src/vercel/transport/index.ts +40 -28
- package/src/vercel/transport/run-output-stream.ts +170 -0
- package/src/version.ts +2 -0
- package/dist/core/transport/client-transport.d.ts +0 -10
- package/dist/core/transport/conversation-tree.d.ts +0 -9
- package/dist/core/transport/decode-history.d.ts +0 -41
- package/dist/core/transport/server-transport.d.ts +0 -7
- package/dist/core/transport/stream-router.d.ts +0 -19
- package/dist/core/transport/turn-manager.d.ts +0 -34
- package/dist/react/use-active-turns.d.ts +0 -8
- package/dist/react/use-client-transport.d.ts +0 -7
- package/dist/react/use-conversation-tree.d.ts +0 -20
- package/dist/react/use-edit.d.ts +0 -7
- package/dist/react/use-history.d.ts +0 -19
- package/dist/react/use-messages.d.ts +0 -7
- package/dist/react/use-regenerate.d.ts +0 -7
- package/dist/react/use-send.d.ts +0 -7
- package/dist/vercel/codec/accumulator.d.ts +0 -21
- package/src/core/transport/client-transport.ts +0 -959
- package/src/core/transport/conversation-tree.ts +0 -434
- package/src/core/transport/decode-history.ts +0 -337
- package/src/core/transport/server-transport.ts +0 -458
- package/src/core/transport/stream-router.ts +0 -118
- package/src/core/transport/turn-manager.ts +0 -147
- package/src/react/use-active-turns.ts +0 -61
- package/src/react/use-client-transport.ts +0 -37
- package/src/react/use-conversation-tree.ts +0 -71
- package/src/react/use-edit.ts +0 -24
- package/src/react/use-history.ts +0 -111
- package/src/react/use-messages.ts +0 -32
- package/src/react/use-regenerate.ts +0 -24
- package/src/react/use-send.ts +0 -25
- 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 {
|
|
8
|
+
* import { createClientSession } from '@ably/ai-transport/vercel';
|
|
9
9
|
*
|
|
10
|
-
* const
|
|
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 {
|
|
21
|
-
import {
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
/**
|
|
31
|
-
|
|
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
|
|
34
|
-
export type
|
|
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
|
|
44
|
+
* Create a client-side session pre-configured with the Vercel AI SDK codec.
|
|
38
45
|
*
|
|
39
|
-
* Equivalent to calling the core `
|
|
40
|
-
*
|
|
41
|
-
*
|
|
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
|
|
44
|
-
options:
|
|
45
|
-
):
|
|
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
|
|
59
|
+
* Create an agent (server-side) session pre-configured with the Vercel AI SDK codec.
|
|
49
60
|
*
|
|
50
|
-
* Equivalent to calling the core `
|
|
51
|
-
* @param options - Configuration for the
|
|
52
|
-
* @returns A new {@link
|
|
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
|
|
55
|
-
options:
|
|
56
|
-
):
|
|
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
|
@@ -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>;
|
package/dist/react/use-edit.d.ts
DELETED
|
@@ -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>>);
|
package/dist/react/use-send.d.ts
DELETED
|
@@ -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>;
|