@ably/ai-transport 0.1.0 → 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 +91 -100
- package/dist/ably-ai-transport.js +1553 -1238
- 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 +116 -42
- 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 +407 -115
- 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 +96 -18
- package/dist/core/transport/index.d.ts +5 -6
- 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 -9
- package/dist/core/transport/run-manager.d.ts +78 -0
- package/dist/core/transport/tree.d.ts +373 -109
- 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 -553
- package/dist/core/transport/view.d.ts +272 -84
- package/dist/errors.d.ts +21 -10
- package/dist/index.d.ts +6 -8
- package/dist/logger.d.ts +12 -0
- package/dist/react/ably-ai-transport-react.js +976 -990
- 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 +12 -12
- package/dist/react/internal/use-resolved-session.d.ts +36 -0
- package/dist/react/use-ably-messages.d.ts +17 -14
- package/dist/react/use-client-session.d.ts +81 -0
- package/dist/react/use-create-view.d.ts +14 -13
- package/dist/react/use-tree.d.ts +30 -15
- package/dist/react/use-view.d.ts +82 -51
- package/dist/utils.d.ts +32 -23
- package/dist/vercel/ably-ai-transport-vercel.js +2573 -2086
- 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 +2 -2
- package/dist/vercel/index.d.ts +4 -5
- package/dist/vercel/react/ably-ai-transport-vercel-react.js +3907 -3266
- package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +33 -8
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
- package/dist/vercel/react/contexts/chat-transport-context.d.ts +7 -6
- package/dist/vercel/react/contexts/chat-transport-provider.d.ts +53 -41
- package/dist/vercel/react/index.d.ts +1 -2
- package/dist/vercel/react/use-chat-transport.d.ts +30 -26
- package/dist/vercel/react/use-message-sync.d.ts +17 -30
- package/dist/vercel/run-end-reason.d.ts +29 -0
- package/dist/vercel/transport/chat-transport.d.ts +43 -24
- package/dist/vercel/transport/index.d.ts +25 -21
- package/dist/vercel/transport/run-output-stream.d.ts +56 -0
- package/dist/version.d.ts +2 -0
- package/package.json +30 -23
- package/src/constants.ts +124 -51
- package/src/core/agent.ts +68 -0
- package/src/core/codec/decoder.ts +71 -98
- package/src/core/codec/encoder.ts +113 -65
- package/src/core/codec/index.ts +13 -6
- package/src/core/codec/lifecycle-tracker.ts +10 -9
- package/src/core/codec/types.ts +436 -120
- 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 +181 -22
- package/src/core/transport/index.ts +25 -26
- 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 +54 -39
- package/src/core/transport/run-manager.ts +249 -0
- package/src/core/transport/tree.ts +926 -308
- 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 -706
- package/src/core/transport/view.ts +864 -433
- package/src/errors.ts +22 -9
- package/src/event-emitter.ts +3 -2
- package/src/index.ts +52 -41
- 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 +23 -13
- package/src/react/internal/use-resolved-session.ts +63 -0
- package/src/react/use-ably-messages.ts +32 -22
- package/src/react/use-client-session.ts +201 -0
- package/src/react/use-create-view.ts +33 -29
- package/src/react/use-tree.ts +61 -30
- package/src/react/use-view.ts +139 -97
- package/src/utils.ts +63 -45
- package/src/vercel/codec/decoder.ts +336 -258
- package/src/vercel/codec/encoder.ts +343 -205
- package/src/vercel/codec/events.ts +87 -0
- package/src/vercel/codec/index.ts +60 -13
- package/src/vercel/codec/reducer.ts +977 -0
- package/src/vercel/codec/tool-transitions.ts +2 -2
- package/src/vercel/index.ts +6 -19
- package/src/vercel/react/contexts/chat-transport-context.ts +7 -6
- package/src/vercel/react/contexts/chat-transport-provider.tsx +87 -59
- package/src/vercel/react/index.ts +3 -5
- package/src/vercel/react/use-chat-transport.ts +47 -49
- package/src/vercel/react/use-message-sync.ts +80 -39
- package/src/vercel/run-end-reason.ts +78 -0
- package/src/vercel/transport/chat-transport.ts +392 -98
- package/src/vercel/transport/index.ts +39 -38
- 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/decode-history.d.ts +0 -43
- package/dist/core/transport/server-transport.d.ts +0 -7
- package/dist/core/transport/stream-router.d.ts +0 -29
- package/dist/core/transport/turn-manager.d.ts +0 -37
- package/dist/react/contexts/transport-context.d.ts +0 -31
- package/dist/react/contexts/transport-provider.d.ts +0 -49
- package/dist/react/create-transport-hooks.d.ts +0 -124
- package/dist/react/use-active-turns.d.ts +0 -12
- package/dist/react/use-client-transport.d.ts +0 -80
- package/dist/vercel/codec/accumulator.d.ts +0 -21
- package/dist/vercel/react/use-staged-add-tool-approval-response.d.ts +0 -30
- package/dist/vercel/tool-approvals.d.ts +0 -124
- package/dist/vercel/tool-events.d.ts +0 -26
- package/src/core/transport/client-transport.ts +0 -977
- package/src/core/transport/decode-history.ts +0 -485
- package/src/core/transport/server-transport.ts +0 -612
- package/src/core/transport/stream-router.ts +0 -136
- package/src/core/transport/turn-manager.ts +0 -165
- package/src/react/contexts/transport-context.ts +0 -37
- package/src/react/contexts/transport-provider.tsx +0 -164
- package/src/react/create-transport-hooks.ts +0 -144
- package/src/react/use-active-turns.ts +0 -72
- package/src/react/use-client-transport.ts +0 -197
- package/src/vercel/codec/accumulator.ts +0 -588
- package/src/vercel/react/use-staged-add-tool-approval-response.ts +0 -87
- package/src/vercel/tool-approvals.ts +0 -380
- package/src/vercel/tool-events.ts +0 -53
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared tool part transition logic for the Vercel AI SDK codec.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Keeps the tool output state transition logic in one place, reusable by the
|
|
5
|
+
* Vercel codec reducer and any other callers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type * as AI from 'ai';
|
package/src/vercel/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Vercel AI SDK codec
|
|
2
|
+
export type { VercelInput, VercelOutput, VercelProjection } from './codec/index.js';
|
|
2
3
|
export { UIMessageCodec } from './codec/index.js';
|
|
3
4
|
|
|
4
5
|
// Vercel AI SDK transport wrappers (pre-bound to UIMessageCodec)
|
|
@@ -6,24 +7,10 @@ export type {
|
|
|
6
7
|
ChatTransport,
|
|
7
8
|
ChatTransportOptions,
|
|
8
9
|
SendMessagesRequestContext,
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
VercelAgentSessionOptions,
|
|
11
|
+
VercelClientSessionOptions,
|
|
11
12
|
} from './transport/index.js';
|
|
12
|
-
export {
|
|
13
|
+
export { createAgentSession, createChatTransport, createClientSession } from './transport/index.js';
|
|
13
14
|
|
|
14
|
-
//
|
|
15
|
-
export {
|
|
16
|
-
|
|
17
|
-
// Server-side tool approval helpers
|
|
18
|
-
export type {
|
|
19
|
-
PrepareApprovalTurnOptions,
|
|
20
|
-
PrepareApprovalTurnResult,
|
|
21
|
-
StreamResponseWithApprovalRedirectOptions,
|
|
22
|
-
ToolApprovalDecision,
|
|
23
|
-
} from './tool-approvals.js';
|
|
24
|
-
export {
|
|
25
|
-
applyToolApprovalsToHistory,
|
|
26
|
-
extractApprovalDecisionsFromHistory,
|
|
27
|
-
prepareApprovalTurn,
|
|
28
|
-
streamResponseWithApprovalRedirect,
|
|
29
|
-
} from './tool-approvals.js';
|
|
15
|
+
// Vercel-shaped helpers
|
|
16
|
+
export { vercelRunOutcome } from './run-end-reason.js';
|
|
@@ -2,18 +2,19 @@ import type * as Ably from 'ably';
|
|
|
2
2
|
import type * as AI from 'ai';
|
|
3
3
|
import { createContext } from 'react';
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { ClientSession } from '../../../core/transport/types.js';
|
|
6
|
+
import type { VercelInput, VercelOutput, VercelProjection } from '../../codec/index.js';
|
|
6
7
|
import type { ChatTransport } from '../../transport/chat-transport.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* A single entry in the chat transport registry, holding both the
|
|
10
|
-
* underlying {@link
|
|
11
|
+
* underlying {@link ClientSession} and the {@link ChatTransport} wrapping it.
|
|
11
12
|
*/
|
|
12
13
|
export interface ChatTransportSlot {
|
|
13
|
-
/** The underlying client
|
|
14
|
-
readonly
|
|
15
|
-
/** Construction error from the underlying {@link
|
|
16
|
-
readonly
|
|
14
|
+
/** The underlying client session used to create the chat transport. */
|
|
15
|
+
readonly session: ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
|
|
16
|
+
/** Construction error from the underlying {@link ClientSession}, or `undefined` on success. */
|
|
17
|
+
readonly sessionError?: Ably.ErrorInfo | undefined;
|
|
17
18
|
/** The chat transport adapter for use with Vercel's useChat hook. */
|
|
18
19
|
readonly chatTransport: ChatTransport;
|
|
19
20
|
}
|
|
@@ -1,92 +1,100 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ChatTransportProvider: creates a ChatTransport from a
|
|
2
|
+
* ChatTransportProvider: creates a ChatTransport from a ClientSession and makes it
|
|
3
3
|
* available to descendants via ChatTransportContext.
|
|
4
4
|
*
|
|
5
|
-
* Wraps children with
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Wraps children with ClientSessionProvider (using UIMessageCodec). The
|
|
6
|
+
* surrounding `<AblyProvider>` supplies the Realtime client; the session
|
|
7
|
+
* resolves the channel from `channelName` itself. An inner component reads
|
|
8
|
+
* the ClientSession via useClientSession() and creates the ChatTransport
|
|
9
|
+
* via useMemo, keyed on the session and transport options.
|
|
9
10
|
*
|
|
10
|
-
* The ChatTransport is NOT closed on unmount — the underlying
|
|
11
|
-
* lifecycle is managed by the wrapping
|
|
12
|
-
* React Strict Mode, and ChatTransport.close() delegates to
|
|
13
|
-
* which
|
|
11
|
+
* The ChatTransport is NOT closed on unmount — the underlying ClientSession
|
|
12
|
+
* lifecycle is managed by the wrapping ClientSessionProvider. Auto-closing would break
|
|
13
|
+
* React Strict Mode, and ChatTransport.close() delegates to ClientSession.close()
|
|
14
|
+
* which ClientSessionProvider already calls.
|
|
14
15
|
*
|
|
15
16
|
* Multiple ChatTransportProviders can be nested using distinct channelNames.
|
|
16
|
-
* Each provider merges its
|
|
17
|
-
* can access all registered
|
|
17
|
+
* Each provider merges its session into the parent registry, so descendants
|
|
18
|
+
* can access all registered sessions via useChatTransport({ channelName }).
|
|
18
19
|
*/
|
|
19
20
|
|
|
20
21
|
import type * as AI from 'ai';
|
|
21
22
|
import { type PropsWithChildren, type ReactNode, useContext, useMemo } from 'react';
|
|
22
23
|
|
|
23
|
-
import {
|
|
24
|
-
import { UIMessageCodec } from '../../codec/index.js';
|
|
25
|
-
import {
|
|
24
|
+
import { type ClientSessionProviderProps, createSessionHooks } from '../../../react/index.js';
|
|
25
|
+
import { UIMessageCodec, type VercelInput, type VercelOutput, type VercelProjection } from '../../codec/index.js';
|
|
26
|
+
import type { ChatTransportOptions } from '../../transport/index.js';
|
|
26
27
|
import { createChatTransport } from '../../transport/index.js';
|
|
27
28
|
import type { ChatTransportSlot } from './chat-transport-context.js';
|
|
28
29
|
import { ChatTransportContext } from './chat-transport-context.js';
|
|
29
30
|
|
|
30
|
-
export const {
|
|
31
|
-
|
|
32
|
-
useAblyMessages,
|
|
33
|
-
useActiveTurns,
|
|
34
|
-
useClientTransport,
|
|
35
|
-
useCreateView,
|
|
36
|
-
useTree,
|
|
37
|
-
useView,
|
|
38
|
-
} = createTransportHooks<AI.UIMessageChunk, AI.UIMessage>();
|
|
31
|
+
export const { ClientSessionProvider, useAblyMessages, useClientSession, useCreateView, useTree, useView } =
|
|
32
|
+
createSessionHooks<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>();
|
|
39
33
|
|
|
40
|
-
type
|
|
41
|
-
|
|
34
|
+
type CoreClientSessionProviderProps = Omit<
|
|
35
|
+
ClientSessionProviderProps<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>,
|
|
36
|
+
'codec'
|
|
37
|
+
>;
|
|
42
38
|
|
|
43
39
|
/**
|
|
44
40
|
* Props for {@link ChatTransportProvider}.
|
|
45
41
|
*
|
|
46
|
-
* All {@link
|
|
47
|
-
* plus `
|
|
42
|
+
* All {@link ClientSessionProviderProps} for Vercel types except `codec` (baked as UIMessageCodec),
|
|
43
|
+
* plus the transport-owned invocation POST options (`api` / `credentials` / `fetch`) and
|
|
44
|
+
* `chatOptions` for customizing chat request construction.
|
|
48
45
|
*/
|
|
49
|
-
export interface ChatTransportProviderProps extends
|
|
46
|
+
export interface ChatTransportProviderProps extends CoreClientSessionProviderProps {
|
|
47
|
+
/** Endpoint the chat transport POSTs the invocation to, to wake the agent. Default `/api/chat`. */
|
|
48
|
+
api?: string;
|
|
49
|
+
/** Fetch credentials mode for the invocation POST. */
|
|
50
|
+
credentials?: RequestCredentials;
|
|
51
|
+
/** Custom fetch implementation for the invocation POST. Defaults to `globalThis.fetch`. */
|
|
52
|
+
fetch?: typeof globalThis.fetch;
|
|
50
53
|
/**
|
|
51
|
-
* Optional
|
|
54
|
+
* Optional transport options for customizing chat request construction (e.g. the `prepareSendMessagesRequest` hook).
|
|
52
55
|
* Must be stable across renders — wrap in `useMemo` or define outside the component.
|
|
53
56
|
* A new object reference triggers ChatTransport recreation.
|
|
57
|
+
* If this object also sets `api`/`credentials`/`fetch`, the dedicated top-level props of the same name take precedence.
|
|
54
58
|
*/
|
|
55
59
|
chatOptions?: ChatTransportOptions;
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
const ChatTransportProviderInner = ({
|
|
59
63
|
channelName,
|
|
60
|
-
|
|
64
|
+
chatTransportOptions,
|
|
61
65
|
children,
|
|
62
66
|
}: {
|
|
63
67
|
channelName: string;
|
|
64
|
-
|
|
68
|
+
chatTransportOptions: ChatTransportOptions;
|
|
65
69
|
children: ReactNode;
|
|
66
70
|
}) => {
|
|
67
|
-
const {
|
|
71
|
+
const { session, sessionError } = useClientSession();
|
|
68
72
|
const { providers: parentProviders } = useContext(ChatTransportContext);
|
|
69
|
-
const chatTransport = useMemo(
|
|
73
|
+
const chatTransport = useMemo(
|
|
74
|
+
() => createChatTransport(session, chatTransportOptions),
|
|
75
|
+
[session, chatTransportOptions],
|
|
76
|
+
);
|
|
70
77
|
const contextValue = useMemo(() => {
|
|
71
|
-
const slot: ChatTransportSlot = {
|
|
78
|
+
const slot: ChatTransportSlot = { session, sessionError, chatTransport };
|
|
72
79
|
return {
|
|
73
80
|
nearest: slot,
|
|
74
81
|
providers: { ...parentProviders, [channelName]: slot },
|
|
75
82
|
};
|
|
76
|
-
}, [channelName, parentProviders, chatTransport,
|
|
83
|
+
}, [channelName, parentProviders, chatTransport, session, sessionError]);
|
|
77
84
|
|
|
78
85
|
return <ChatTransportContext.Provider value={contextValue}>{children}</ChatTransportContext.Provider>;
|
|
79
86
|
};
|
|
80
87
|
|
|
81
88
|
/**
|
|
82
|
-
* Provide a {@link ChatTransport} and its underlying {@link
|
|
89
|
+
* Provide a {@link ChatTransport} and its underlying {@link ClientSession} to descendant components.
|
|
83
90
|
*
|
|
84
|
-
* Wraps children with
|
|
85
|
-
*
|
|
91
|
+
* Wraps children with `ClientSessionProvider` using `channelName` (the Realtime
|
|
92
|
+
* client is read from the surrounding `<AblyProvider>`), creates a
|
|
93
|
+
* {@link ClientSession} with UIMessageCodec, wraps it in a {@link ChatTransport},
|
|
86
94
|
* and registers the full slot in `ChatTransportContext` under `channelName`. Descendants call
|
|
87
|
-
* {@link useChatTransport} with the same `channelName` to access both
|
|
95
|
+
* {@link useChatTransport} with the same `channelName` to access both.
|
|
88
96
|
*
|
|
89
|
-
* `
|
|
97
|
+
* `useClientSession` is also available inside this provider's subtree.
|
|
90
98
|
*
|
|
91
99
|
* ```tsx
|
|
92
100
|
* <ChatTransportProvider channelName="ai:demo">
|
|
@@ -94,29 +102,49 @@ const ChatTransportProviderInner = ({
|
|
|
94
102
|
* </ChatTransportProvider>
|
|
95
103
|
*
|
|
96
104
|
* // Inside Chat:
|
|
97
|
-
* const { chatTransport,
|
|
98
|
-
* const {
|
|
105
|
+
* const { chatTransport, session } = useChatTransport();
|
|
106
|
+
* const { session } = useClientSession(); // also available
|
|
99
107
|
* ```
|
|
100
|
-
* @param props - Provider configuration including `channelName`, optional `chatOptions`, and all other
|
|
108
|
+
* @param props - Provider configuration including `channelName`, the invocation POST options (`api` / `credentials` / `fetch`), optional `chatOptions`, and all other session options.
|
|
109
|
+
* @param props.api - Endpoint the chat transport POSTs the invocation to. Default `/api/chat`.
|
|
110
|
+
* @param props.credentials - Fetch credentials mode for the invocation POST.
|
|
111
|
+
* @param props.fetch - Custom fetch implementation for the invocation POST.
|
|
101
112
|
* @param props.chatOptions - Optional hooks for customizing chat request construction. Must be stable (memoized) — a new reference recreates the ChatTransport.
|
|
102
|
-
* @param props.children - Descendant components that consume the transport via hooks.
|
|
103
|
-
* @returns A React element wrapping children with
|
|
113
|
+
* @param props.children - Descendant components that consume the chat transport via hooks.
|
|
114
|
+
* @returns A React element wrapping children with ClientSessionContext and ChatTransportContext.
|
|
104
115
|
*/
|
|
105
116
|
export const ChatTransportProvider = ({
|
|
117
|
+
api,
|
|
118
|
+
credentials,
|
|
119
|
+
fetch,
|
|
106
120
|
chatOptions,
|
|
107
121
|
children,
|
|
108
|
-
...
|
|
109
|
-
}: ChatTransportProviderProps & PropsWithChildren): ReactNode =>
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
122
|
+
...sessionProps
|
|
123
|
+
}: ChatTransportProviderProps & PropsWithChildren): ReactNode => {
|
|
124
|
+
// Fold the transport-owned POST options into a single ChatTransportOptions.
|
|
125
|
+
// Memoized so the ChatTransport isn't recreated each render — createChatTransport
|
|
126
|
+
// is keyed on this object's identity.
|
|
127
|
+
const chatTransportOptions = useMemo<ChatTransportOptions>(
|
|
128
|
+
() => ({
|
|
129
|
+
...chatOptions,
|
|
130
|
+
...(api !== undefined && { api }),
|
|
131
|
+
...(credentials !== undefined && { credentials }),
|
|
132
|
+
...(fetch !== undefined && { fetch }),
|
|
133
|
+
}),
|
|
134
|
+
[api, credentials, fetch, chatOptions],
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<ClientSessionProvider
|
|
139
|
+
{...sessionProps}
|
|
140
|
+
codec={UIMessageCodec}
|
|
118
141
|
>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
142
|
+
<ChatTransportProviderInner
|
|
143
|
+
channelName={sessionProps.channelName}
|
|
144
|
+
chatTransportOptions={chatTransportOptions}
|
|
145
|
+
>
|
|
146
|
+
{children}
|
|
147
|
+
</ChatTransportProviderInner>
|
|
148
|
+
</ClientSessionProvider>
|
|
149
|
+
);
|
|
150
|
+
};
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
// Vercel-specific React hooks
|
|
1
|
+
// Vercel-specific React entry point: providers, hooks, and their types
|
|
2
2
|
export type { ChatTransport } from '../transport/chat-transport.js';
|
|
3
3
|
export type { ChatTransportProviderProps } from './contexts/chat-transport-provider.js';
|
|
4
4
|
export {
|
|
5
5
|
ChatTransportProvider,
|
|
6
|
-
|
|
6
|
+
ClientSessionProvider,
|
|
7
7
|
useAblyMessages,
|
|
8
|
-
|
|
9
|
-
useClientTransport,
|
|
8
|
+
useClientSession,
|
|
10
9
|
useCreateView,
|
|
11
10
|
useTree,
|
|
12
11
|
useView,
|
|
@@ -15,4 +14,3 @@ export type { ChatTransportHandle, UseChatTransportOptions } from './use-chat-tr
|
|
|
15
14
|
export { useChatTransport } from './use-chat-transport.js';
|
|
16
15
|
export type { UseMessageSyncOptions } from './use-message-sync.js';
|
|
17
16
|
export { useMessageSync } from './use-message-sync.js';
|
|
18
|
-
export { useStagedAddToolApprovalResponse } from './use-staged-add-tool-approval-response.js';
|
|
@@ -1,47 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* useChatTransport: reads a ChatTransport and its underlying
|
|
2
|
+
* useChatTransport: reads a ChatTransport and its underlying ClientSession from
|
|
3
3
|
* the nearest ChatTransportProvider.
|
|
4
4
|
*
|
|
5
|
-
* The transport is created by ChatTransportProvider, which
|
|
6
|
-
* with
|
|
7
|
-
*
|
|
5
|
+
* The chat transport is created by ChatTransportProvider, which wraps the subtree
|
|
6
|
+
* with ClientSessionProvider. The Ably Realtime client is read from the
|
|
7
|
+
* surrounding `<AblyProvider>`. This hook is a thin context reader — it does
|
|
8
|
+
* not create or manage any session/transport state.
|
|
8
9
|
*
|
|
9
10
|
* Pass `channelName` to look up a specific provider by name. Omit to use the nearest
|
|
10
11
|
* provider in the tree. Pass `skip: true` to defer (e.g. when auth is not yet resolved)
|
|
11
|
-
* — returns
|
|
12
|
+
* — returns stubs whose properties throw with a descriptive error.
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
import * as Ably from 'ably';
|
|
15
16
|
import type * as AI from 'ai';
|
|
16
17
|
import { useContext } from 'react';
|
|
17
18
|
|
|
18
|
-
import type {
|
|
19
|
+
import type { ClientSession, Tree, View } from '../../core/transport/types.js';
|
|
19
20
|
import { ErrorCode } from '../../errors.js';
|
|
21
|
+
import type { VercelInput, VercelOutput, VercelProjection } from '../codec/index.js';
|
|
20
22
|
import type { ChatTransport } from '../transport/index.js';
|
|
21
23
|
import { ChatTransportContext } from './contexts/chat-transport-context.js';
|
|
22
24
|
|
|
23
|
-
const
|
|
24
|
-
get tree(): Tree<
|
|
25
|
+
const SKIPPED_CLIENT_SESSION: ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage> = {
|
|
26
|
+
get tree(): Tree<VercelOutput, VercelProjection> {
|
|
25
27
|
throw new Ably.ErrorInfo('unable to access tree; hook is skipped', ErrorCode.InvalidArgument, 400);
|
|
26
28
|
},
|
|
27
|
-
get view(): View<
|
|
29
|
+
get view(): View<VercelInput, AI.UIMessage> {
|
|
28
30
|
throw new Ably.ErrorInfo('unable to access view; hook is skipped', ErrorCode.InvalidArgument, 400);
|
|
29
31
|
},
|
|
30
|
-
|
|
32
|
+
connect: () => {
|
|
33
|
+
throw new Ably.ErrorInfo('unable to connect; hook is skipped', ErrorCode.InvalidArgument, 400);
|
|
34
|
+
},
|
|
35
|
+
createView: (): View<VercelInput, AI.UIMessage> => {
|
|
31
36
|
throw new Ably.ErrorInfo('unable to create view; hook is skipped', ErrorCode.InvalidArgument, 400);
|
|
32
37
|
},
|
|
33
38
|
cancel: () => {
|
|
34
39
|
throw new Ably.ErrorInfo('unable to cancel; hook is skipped', ErrorCode.InvalidArgument, 400);
|
|
35
40
|
},
|
|
36
|
-
stageEvents: () => {
|
|
37
|
-
throw new Ably.ErrorInfo('unable to stage events; hook is skipped', ErrorCode.InvalidArgument, 400);
|
|
38
|
-
},
|
|
39
|
-
stageMessage: () => {
|
|
40
|
-
throw new Ably.ErrorInfo('unable to stage message; hook is skipped', ErrorCode.InvalidArgument, 400);
|
|
41
|
-
},
|
|
42
|
-
waitForTurn: () => {
|
|
43
|
-
throw new Ably.ErrorInfo('unable to wait for turn; hook is skipped', ErrorCode.InvalidArgument, 400);
|
|
44
|
-
},
|
|
45
41
|
on: () => {
|
|
46
42
|
throw new Ably.ErrorInfo('unable to subscribe; hook is skipped', ErrorCode.InvalidArgument, 400);
|
|
47
43
|
},
|
|
@@ -76,76 +72,78 @@ const SKIPPED_CHAT_TRANSPORT: ChatTransport = {
|
|
|
76
72
|
export interface UseChatTransportOptions {
|
|
77
73
|
/** Channel name to look up; omit to use the nearest {@link ChatTransportProvider}. */
|
|
78
74
|
channelName?: string;
|
|
79
|
-
/** When `true`, return
|
|
75
|
+
/** When `true`, return stubs that throw on any access. */
|
|
80
76
|
skip?: boolean;
|
|
81
77
|
}
|
|
82
78
|
|
|
83
79
|
/**
|
|
84
80
|
* The value returned by {@link useChatTransport}.
|
|
85
|
-
* Provides both the underlying {@link
|
|
81
|
+
* Provides both the underlying {@link ClientSession} and the {@link ChatTransport}
|
|
86
82
|
* adapter for Vercel's useChat hook.
|
|
87
83
|
*/
|
|
88
84
|
export interface ChatTransportHandle {
|
|
89
85
|
/**
|
|
90
|
-
* The underlying client
|
|
91
|
-
* A throwing stub when `skip` is `true`, when no matching {@link
|
|
92
|
-
* was found in the tree, or when
|
|
86
|
+
* The underlying client session, also available via {@link useClientSession}.
|
|
87
|
+
* A throwing stub when `skip` is `true`, when no matching {@link ClientSessionProvider}
|
|
88
|
+
* was found in the tree, or when session construction failed. Check `sessionError` before use.
|
|
93
89
|
*/
|
|
94
|
-
|
|
90
|
+
session: ClientSession<VercelInput, VercelOutput, VercelProjection, AI.UIMessage>;
|
|
95
91
|
|
|
96
92
|
/**
|
|
97
93
|
* The chat transport adapter for use with Vercel's `useChat` hook.
|
|
98
94
|
*
|
|
99
|
-
* A throwing stub when `skip` is `true
|
|
100
|
-
* {@link ChatTransportProvider} was found in the tree
|
|
101
|
-
* {@link
|
|
102
|
-
* and `
|
|
95
|
+
* A throwing stub when `skip` is `true` or when no matching
|
|
96
|
+
* {@link ChatTransportProvider} was found in the tree. When a provider is found
|
|
97
|
+
* but the underlying {@link ClientSession} failed to construct, this is the real
|
|
98
|
+
* transport and `sessionError` is set instead. Check `chatTransportError` and
|
|
99
|
+
* `sessionError` before use.
|
|
103
100
|
*/
|
|
104
101
|
chatTransport: ChatTransport;
|
|
105
102
|
|
|
106
103
|
/**
|
|
107
|
-
* Set when no matching {@link
|
|
104
|
+
* Set when no matching {@link ClientSessionProvider} was found, when session
|
|
108
105
|
* construction failed, and `skip` is `false`.
|
|
109
|
-
* `undefined` when the
|
|
106
|
+
* `undefined` when the session resolved successfully or when `skip` is `true`.
|
|
110
107
|
*/
|
|
111
|
-
|
|
108
|
+
sessionError?: Ably.ErrorInfo | undefined;
|
|
112
109
|
/**
|
|
113
|
-
* Set when no matching {@link ChatTransportProvider} was found
|
|
114
|
-
*
|
|
115
|
-
* `undefined` when the transport resolved successfully
|
|
110
|
+
* Set only when no matching {@link ChatTransportProvider} was found and `skip` is
|
|
111
|
+
* `false`.
|
|
112
|
+
* `undefined` when the chat transport resolved successfully (even if session
|
|
113
|
+
* construction failed — see `sessionError`) or when `skip` is `true`.
|
|
116
114
|
*/
|
|
117
115
|
chatTransportError?: Ably.ErrorInfo | undefined;
|
|
118
116
|
}
|
|
119
117
|
|
|
120
118
|
/**
|
|
121
|
-
* Access a {@link ChatTransport} and {@link
|
|
119
|
+
* Access a {@link ChatTransport} and {@link ClientSession} from the nearest {@link ChatTransportProvider}.
|
|
122
120
|
*
|
|
123
121
|
* When `channelName` is omitted, the innermost `ChatTransportProvider` in the tree is used.
|
|
124
|
-
* When `skip` is `true`, returns
|
|
122
|
+
* When `skip` is `true`, returns stubs whose every property and method throws
|
|
125
123
|
* an {@link Ably.ErrorInfo} — safe to hold in state before conditions are ready.
|
|
126
124
|
* When no provider is found, returns stubs with `chatTransportError` set instead of throwing.
|
|
127
|
-
* @param props - Options for selecting the transport.
|
|
125
|
+
* @param props - Options for selecting the chat transport.
|
|
128
126
|
* @param props.channelName - The channel name passed to the enclosing `ChatTransportProvider`. Omit to use the nearest.
|
|
129
127
|
* @param props.skip - When `true`, return stubs that throw on any access instead of reading from context.
|
|
130
|
-
* @returns The `ChatTransportHandle` containing both the chat transport adapter and the underlying client
|
|
128
|
+
* @returns The `ChatTransportHandle` containing both the chat transport adapter and the underlying client session.
|
|
131
129
|
*/
|
|
132
130
|
export const useChatTransport = ({ channelName, skip }: UseChatTransportOptions = {}): ChatTransportHandle => {
|
|
133
131
|
const { nearest, providers } = useContext(ChatTransportContext);
|
|
134
132
|
|
|
135
133
|
if (skip) {
|
|
136
|
-
return {
|
|
134
|
+
return { session: SKIPPED_CLIENT_SESSION, chatTransport: SKIPPED_CHAT_TRANSPORT };
|
|
137
135
|
}
|
|
138
136
|
|
|
139
137
|
if (channelName !== undefined) {
|
|
140
138
|
const slot = providers[channelName];
|
|
141
139
|
if (slot) {
|
|
142
|
-
return {
|
|
140
|
+
return { session: slot.session, chatTransport: slot.chatTransport, sessionError: slot.sessionError };
|
|
143
141
|
}
|
|
144
142
|
return {
|
|
145
|
-
|
|
143
|
+
session: SKIPPED_CLIENT_SESSION,
|
|
146
144
|
chatTransport: SKIPPED_CHAT_TRANSPORT,
|
|
147
|
-
|
|
148
|
-
`unable to use client
|
|
145
|
+
sessionError: new Ably.ErrorInfo(
|
|
146
|
+
`unable to use client session; no ClientSessionProvider found for channelName "${channelName}"`,
|
|
149
147
|
ErrorCode.BadRequest,
|
|
150
148
|
400,
|
|
151
149
|
),
|
|
@@ -159,17 +157,17 @@ export const useChatTransport = ({ channelName, skip }: UseChatTransportOptions
|
|
|
159
157
|
|
|
160
158
|
if (nearest) {
|
|
161
159
|
return {
|
|
162
|
-
|
|
160
|
+
session: nearest.session,
|
|
163
161
|
chatTransport: nearest.chatTransport,
|
|
164
|
-
|
|
162
|
+
sessionError: nearest.sessionError,
|
|
165
163
|
};
|
|
166
164
|
}
|
|
167
165
|
|
|
168
166
|
return {
|
|
169
|
-
|
|
167
|
+
session: SKIPPED_CLIENT_SESSION,
|
|
170
168
|
chatTransport: SKIPPED_CHAT_TRANSPORT,
|
|
171
|
-
|
|
172
|
-
'unable to use
|
|
169
|
+
sessionError: new Ably.ErrorInfo(
|
|
170
|
+
'unable to use session; no ClientSessionProvider found in the tree',
|
|
173
171
|
ErrorCode.BadRequest,
|
|
174
172
|
400,
|
|
175
173
|
),
|