@surf-kit/ai 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ Copyright (c) 2026 surf-kit contributors
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted.
5
+
6
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
7
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
8
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
9
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
10
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
11
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
12
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # @surf-kit/ai
2
+
3
+ Adapter package bridging [surf-kit](https://github.com/barney-w/surf-kit) agent components with [Vercel AI SDK v6](https://sdk.vercel.ai/).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @surf-kit/ai ai @ai-sdk/react
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### useAIChat
14
+
15
+ Wraps `useChat` from `@ai-sdk/react` and maps to surf-kit types (`ChatMessage`, `StreamState`).
16
+
17
+ ```tsx
18
+ import { useAIChat } from '@surf-kit/ai'
19
+
20
+ function Chat() {
21
+ const { messages, streamState, sendMessage, input, setInput, handleSubmit } =
22
+ useAIChat({ api: '/api/chat' })
23
+
24
+ return (
25
+ <form onSubmit={handleSubmit}>
26
+ <input value={input} onChange={(e) => setInput(e.target.value)} />
27
+ <button type="submit">Send</button>
28
+ </form>
29
+ )
30
+ }
31
+ ```
32
+
33
+ ### useAIStream
34
+
35
+ Wraps `useCompletion` from `@ai-sdk/react` for simple text streaming without chat history.
36
+
37
+ ```tsx
38
+ import { useAIStream } from '@surf-kit/ai'
39
+
40
+ function Completion() {
41
+ const { streamState, complete } = useAIStream({ api: '/api/complete' })
42
+ // ...
43
+ }
44
+ ```
45
+
46
+ ### AIChat
47
+
48
+ Drop-in chat component powered by surf-kit agent UI and the AI SDK.
49
+
50
+ ```tsx
51
+ import { AIChat } from '@surf-kit/ai'
52
+
53
+ function App() {
54
+ return <AIChat api="/api/chat" title="Assistant" />
55
+ }
56
+ ```
57
+
58
+ ## When to Use This vs `@surf-kit/agent`
59
+
60
+ | | `@surf-kit/agent` | `@surf-kit/ai` |
61
+ |---|---|---|
62
+ | **Backend** | Custom SSE with surf-kit's bespoke protocol | Vercel AI SDK v6 (`/api/chat`) |
63
+ | **Entry point** | `<AgentChat>` | `<AIChat>` |
64
+ | **UI components** | surf-kit agent UI | Same surf-kit agent UI |
65
+ | **Best for** | Full control over streaming protocol | Standard AI SDK backends (OpenAI, Anthropic, etc.) |
66
+
67
+ Both packages render the same surf-kit UI components — the difference is how they connect to your backend.
68
+
69
+ ## License
70
+
71
+ 0BSD
package/dist/index.cjs ADDED
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AIChat: () => AIChat,
24
+ useAIChat: () => useAIChat,
25
+ useAIStream: () => useAIStream
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/hooks/useAIChat.ts
30
+ var import_react = require("@ai-sdk/react");
31
+ var import_ai = require("ai");
32
+ function getTextContent(message) {
33
+ return message.parts.filter((part) => part.type === "text").map((part) => part.text).join("");
34
+ }
35
+ function useAIChat(options = {}) {
36
+ const chat = (0, import_react.useChat)({
37
+ transport: new import_ai.DefaultChatTransport({
38
+ api: options.api,
39
+ headers: options.headers,
40
+ body: options.body
41
+ }),
42
+ onError: options.onError,
43
+ onFinish: options.onFinish
44
+ });
45
+ const messages = chat.messages.map((m) => ({
46
+ id: m.id,
47
+ role: m.role,
48
+ content: getTextContent(m),
49
+ timestamp: /* @__PURE__ */ new Date()
50
+ }));
51
+ const isStreaming = chat.status === "streaming";
52
+ const lastMessageContent = chat.messages.length > 0 ? getTextContent(chat.messages[chat.messages.length - 1]) : "";
53
+ const streamState = {
54
+ active: isStreaming,
55
+ phase: isStreaming ? "generating" : "idle",
56
+ content: isStreaming ? lastMessageContent : "",
57
+ sources: [],
58
+ agent: null,
59
+ agentLabel: null
60
+ };
61
+ return {
62
+ messages,
63
+ streamState,
64
+ sendMessage: (content) => {
65
+ void chat.sendMessage({ text: content });
66
+ },
67
+ isLoading: isStreaming || chat.status === "submitted",
68
+ error: chat.error,
69
+ stop: chat.stop,
70
+ regenerate: () => {
71
+ void chat.regenerate();
72
+ }
73
+ };
74
+ }
75
+
76
+ // src/hooks/useAIStream.ts
77
+ var import_react2 = require("@ai-sdk/react");
78
+ function useAIStream(options = {}) {
79
+ const completion = (0, import_react2.useCompletion)({
80
+ api: options.api,
81
+ onFinish: options.onFinish,
82
+ onError: options.onError,
83
+ headers: options.headers,
84
+ body: options.body
85
+ });
86
+ const streamState = {
87
+ active: completion.isLoading,
88
+ phase: completion.isLoading ? "generating" : "idle",
89
+ content: completion.completion,
90
+ sources: [],
91
+ agent: null,
92
+ agentLabel: null
93
+ };
94
+ return {
95
+ streamState,
96
+ completion: completion.completion,
97
+ complete: (prompt) => {
98
+ void completion.complete(prompt);
99
+ },
100
+ isLoading: completion.isLoading,
101
+ error: completion.error,
102
+ stop: completion.stop,
103
+ input: completion.input,
104
+ setInput: completion.setInput,
105
+ handleSubmit: completion.handleSubmit
106
+ };
107
+ }
108
+
109
+ // src/components/AIChat.tsx
110
+ var import_agent = require("@surf-kit/agent");
111
+ var import_jsx_runtime = require("react/jsx-runtime");
112
+ function AIChat({
113
+ title = "Chat",
114
+ welcomeMessage = "How can I help you today?",
115
+ suggestedQuestions = [],
116
+ showHeader = true,
117
+ showSources,
118
+ showConfidence,
119
+ className,
120
+ ...chatOptions
121
+ }) {
122
+ const { messages, streamState, sendMessage, isLoading } = useAIChat(chatOptions);
123
+ const hasMessages = messages.length > 0;
124
+ const handleQuestionSelect = (question) => {
125
+ sendMessage(question);
126
+ };
127
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
128
+ "div",
129
+ {
130
+ className: [
131
+ "flex flex-col h-full bg-canvas border border-border rounded-xl overflow-hidden",
132
+ className
133
+ ].filter(Boolean).join(" "),
134
+ children: [
135
+ showHeader && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-center justify-between border-b border-border px-4 py-3 bg-surface-raised shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-base font-semibold text-text-primary", children: title }) }),
136
+ hasMessages ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
137
+ import_agent.MessageThread,
138
+ {
139
+ messages,
140
+ streamingSlot: streamState.active ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_agent.StreamingMessage, { stream: streamState }) : void 0,
141
+ showSources,
142
+ showConfidence
143
+ }
144
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
145
+ import_agent.WelcomeScreen,
146
+ {
147
+ title,
148
+ message: welcomeMessage,
149
+ suggestedQuestions,
150
+ onQuestionSelect: handleQuestionSelect
151
+ }
152
+ ),
153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_agent.MessageComposer, { onSend: sendMessage, isLoading })
154
+ ]
155
+ }
156
+ );
157
+ }
158
+ // Annotate the CommonJS export names for ESM import in node:
159
+ 0 && (module.exports = {
160
+ AIChat,
161
+ useAIChat,
162
+ useAIStream
163
+ });
164
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/hooks/useAIChat.ts","../src/hooks/useAIStream.ts","../src/components/AIChat.tsx"],"sourcesContent":["// Types\nexport type {\n UseAIChatOptions,\n UseAIChatReturn,\n UseAIStreamOptions,\n UseAIStreamReturn,\n} from './types'\n\n// Re-exported surf-kit types for convenience\nexport type { ChatMessage, StreamState } from './types'\n\n// Hooks\nexport { useAIChat } from './hooks/useAIChat'\nexport { useAIStream } from './hooks/useAIStream'\n\n// Components\nexport { AIChat } from './components/AIChat'\nexport type { AIChatProps } from './components/AIChat'\n","import { useChat } from '@ai-sdk/react'\nimport { DefaultChatTransport } from 'ai'\nimport type { UIMessage } from 'ai'\nimport type { ChatMessage, StreamState } from '@surf-kit/agent'\nimport type { UseAIChatOptions, UseAIChatReturn } from '../types'\n\n/**\n * Extract the text content from a UIMessage by concatenating all text parts.\n */\nfunction getTextContent(message: UIMessage): string {\n return message.parts\n .filter((part): part is { type: 'text'; text: string } => part.type === 'text')\n .map((part) => part.text)\n .join('')\n}\n\n/**\n * Adapter hook that wraps Vercel AI SDK v6's `useChat` and maps\n * its state to surf-kit `ChatMessage` and `StreamState` types.\n */\nexport function useAIChat(options: UseAIChatOptions = {}): UseAIChatReturn {\n const chat = useChat({\n transport: new DefaultChatTransport({\n api: options.api,\n headers: options.headers,\n body: options.body,\n }),\n onError: options.onError,\n onFinish: options.onFinish,\n })\n\n // Convert AI SDK v6 UIMessage (parts-based) to surf-kit ChatMessage format\n const messages: ChatMessage[] = chat.messages.map((m) => ({\n id: m.id,\n role: m.role as 'user' | 'assistant',\n content: getTextContent(m),\n timestamp: new Date(),\n }))\n\n const isStreaming = chat.status === 'streaming'\n const lastMessageContent = chat.messages.length > 0\n ? getTextContent(chat.messages[chat.messages.length - 1])\n : ''\n\n const streamState: StreamState = {\n active: isStreaming,\n phase: isStreaming ? 'generating' : 'idle',\n content: isStreaming ? lastMessageContent : '',\n sources: [],\n agent: null,\n agentLabel: null,\n }\n\n return {\n messages,\n streamState,\n sendMessage: (content: string) => {\n void chat.sendMessage({ text: content })\n },\n isLoading: isStreaming || chat.status === 'submitted',\n error: chat.error,\n stop: chat.stop,\n regenerate: () => {\n void chat.regenerate()\n },\n }\n}\n","import { useCompletion } from '@ai-sdk/react'\nimport type { StreamState } from '@surf-kit/agent'\nimport type { UseAIStreamOptions, UseAIStreamReturn } from '../types'\n\n/**\n * Adapter hook that wraps Vercel AI SDK v6's `useCompletion` for simple\n * text streaming (no chat history). Maps state to surf-kit `StreamState`.\n */\nexport function useAIStream(options: UseAIStreamOptions = {}): UseAIStreamReturn {\n const completion = useCompletion({\n api: options.api,\n onFinish: options.onFinish,\n onError: options.onError,\n headers: options.headers,\n body: options.body,\n })\n\n const streamState: StreamState = {\n active: completion.isLoading,\n phase: completion.isLoading ? 'generating' : 'idle',\n content: completion.completion,\n sources: [],\n agent: null,\n agentLabel: null,\n }\n\n return {\n streamState,\n completion: completion.completion,\n complete: (prompt: string) => {\n void completion.complete(prompt)\n },\n isLoading: completion.isLoading,\n error: completion.error,\n stop: completion.stop,\n input: completion.input,\n setInput: completion.setInput,\n handleSubmit: completion.handleSubmit,\n }\n}\n","import React from 'react'\nimport { MessageThread, MessageComposer, WelcomeScreen, StreamingMessage } from '@surf-kit/agent'\nimport { useAIChat } from '../hooks/useAIChat'\nimport type { UseAIChatOptions } from '../types'\n\nexport interface AIChatProps extends UseAIChatOptions {\n /** Title shown in the header */\n title?: string\n /** Message displayed on the welcome screen */\n welcomeMessage?: string\n /** Suggested questions shown on the welcome screen */\n suggestedQuestions?: string[]\n /** Whether to show the header bar */\n showHeader?: boolean\n /** Whether to show source citations */\n showSources?: boolean\n /** Whether to show confidence indicators */\n showConfidence?: boolean\n /** Additional CSS class names */\n className?: string\n}\n\n/**\n * Drop-in chat component powered by Vercel AI SDK v6 and surf-kit agent UI.\n * Composes `MessageThread`, `MessageComposer`, `StreamingMessage`, and\n * `WelcomeScreen` from `@surf-kit/agent`.\n */\nexport function AIChat({\n title = 'Chat',\n welcomeMessage = 'How can I help you today?',\n suggestedQuestions = [],\n showHeader = true,\n showSources,\n showConfidence,\n className,\n ...chatOptions\n}: AIChatProps) {\n const { messages, streamState, sendMessage, isLoading } = useAIChat(chatOptions)\n\n const hasMessages = messages.length > 0\n\n const handleQuestionSelect = (question: string) => {\n sendMessage(question)\n }\n\n return (\n <div\n className={[\n 'flex flex-col h-full bg-canvas border border-border rounded-xl overflow-hidden',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {showHeader && (\n <div className=\"flex items-center justify-between border-b border-border px-4 py-3 bg-surface-raised shrink-0\">\n <h1 className=\"text-base font-semibold text-text-primary\">{title}</h1>\n </div>\n )}\n\n {hasMessages ? (\n <MessageThread\n messages={messages}\n streamingSlot={\n streamState.active ? <StreamingMessage stream={streamState} /> : undefined\n }\n showSources={showSources}\n showConfidence={showConfidence}\n />\n ) : (\n <WelcomeScreen\n title={title}\n message={welcomeMessage}\n suggestedQuestions={suggestedQuestions}\n onQuestionSelect={handleQuestionSelect}\n />\n )}\n\n <MessageComposer onSend={sendMessage} isLoading={isLoading} />\n </div>\n )\n}\n"],"mappings":"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","names":["import_react"]}
@@ -0,0 +1,109 @@
1
+ import { ChatMessage, StreamState } from '@surf-kit/agent';
2
+ export { ChatMessage, StreamState } from '@surf-kit/agent';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+
5
+ /** Options for the useAIChat hook */
6
+ interface UseAIChatOptions {
7
+ /** API endpoint for chat completions. Defaults to '/api/chat'. */
8
+ api?: string;
9
+ /** Callback when a response finishes streaming */
10
+ onFinish?: (params: {
11
+ messages: unknown[];
12
+ }) => void;
13
+ /** Callback on error */
14
+ onError?: (error: Error) => void;
15
+ /** Additional headers to send with requests */
16
+ headers?: Record<string, string>;
17
+ /** Additional body fields to send with requests */
18
+ body?: Record<string, unknown>;
19
+ }
20
+ /** Return type for the useAIChat hook */
21
+ interface UseAIChatReturn {
22
+ /** Messages converted to surf-kit ChatMessage format */
23
+ messages: ChatMessage[];
24
+ /** Current streaming state in surf-kit StreamState format */
25
+ streamState: StreamState;
26
+ /** Send a new user message */
27
+ sendMessage: (content: string) => void;
28
+ /** Whether a response is currently streaming */
29
+ isLoading: boolean;
30
+ /** Current error, if any */
31
+ error: Error | undefined;
32
+ /** Stop the current stream */
33
+ stop: () => void;
34
+ /** Regenerate the last assistant message */
35
+ regenerate: () => void;
36
+ }
37
+ /** Options for the useAIStream hook */
38
+ interface UseAIStreamOptions {
39
+ /** API endpoint for completions */
40
+ api?: string;
41
+ /** Callback when a completion finishes */
42
+ onFinish?: (prompt: string, completion: string) => void;
43
+ /** Callback on error */
44
+ onError?: (error: Error) => void;
45
+ /** Additional headers to send with requests */
46
+ headers?: Record<string, string>;
47
+ /** Additional body fields to send with requests */
48
+ body?: Record<string, unknown>;
49
+ }
50
+ /** Return type for the useAIStream hook */
51
+ interface UseAIStreamReturn {
52
+ /** Current streaming state in surf-kit StreamState format */
53
+ streamState: StreamState;
54
+ /** The completed text */
55
+ completion: string;
56
+ /** Trigger a completion */
57
+ complete: (prompt: string) => void;
58
+ /** Whether a completion is currently streaming */
59
+ isLoading: boolean;
60
+ /** Current error, if any */
61
+ error: Error | undefined;
62
+ /** Stop the current stream */
63
+ stop: () => void;
64
+ /** Controlled input value */
65
+ input: string;
66
+ /** Set the controlled input value */
67
+ setInput: (input: string) => void;
68
+ /** Form submit handler */
69
+ handleSubmit: (e?: {
70
+ preventDefault?: () => void;
71
+ }) => void;
72
+ }
73
+
74
+ /**
75
+ * Adapter hook that wraps Vercel AI SDK v6's `useChat` and maps
76
+ * its state to surf-kit `ChatMessage` and `StreamState` types.
77
+ */
78
+ declare function useAIChat(options?: UseAIChatOptions): UseAIChatReturn;
79
+
80
+ /**
81
+ * Adapter hook that wraps Vercel AI SDK v6's `useCompletion` for simple
82
+ * text streaming (no chat history). Maps state to surf-kit `StreamState`.
83
+ */
84
+ declare function useAIStream(options?: UseAIStreamOptions): UseAIStreamReturn;
85
+
86
+ interface AIChatProps extends UseAIChatOptions {
87
+ /** Title shown in the header */
88
+ title?: string;
89
+ /** Message displayed on the welcome screen */
90
+ welcomeMessage?: string;
91
+ /** Suggested questions shown on the welcome screen */
92
+ suggestedQuestions?: string[];
93
+ /** Whether to show the header bar */
94
+ showHeader?: boolean;
95
+ /** Whether to show source citations */
96
+ showSources?: boolean;
97
+ /** Whether to show confidence indicators */
98
+ showConfidence?: boolean;
99
+ /** Additional CSS class names */
100
+ className?: string;
101
+ }
102
+ /**
103
+ * Drop-in chat component powered by Vercel AI SDK v6 and surf-kit agent UI.
104
+ * Composes `MessageThread`, `MessageComposer`, `StreamingMessage`, and
105
+ * `WelcomeScreen` from `@surf-kit/agent`.
106
+ */
107
+ declare function AIChat({ title, welcomeMessage, suggestedQuestions, showHeader, showSources, showConfidence, className, ...chatOptions }: AIChatProps): react_jsx_runtime.JSX.Element;
108
+
109
+ export { AIChat, type AIChatProps, type UseAIChatOptions, type UseAIChatReturn, type UseAIStreamOptions, type UseAIStreamReturn, useAIChat, useAIStream };
@@ -0,0 +1,109 @@
1
+ import { ChatMessage, StreamState } from '@surf-kit/agent';
2
+ export { ChatMessage, StreamState } from '@surf-kit/agent';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+
5
+ /** Options for the useAIChat hook */
6
+ interface UseAIChatOptions {
7
+ /** API endpoint for chat completions. Defaults to '/api/chat'. */
8
+ api?: string;
9
+ /** Callback when a response finishes streaming */
10
+ onFinish?: (params: {
11
+ messages: unknown[];
12
+ }) => void;
13
+ /** Callback on error */
14
+ onError?: (error: Error) => void;
15
+ /** Additional headers to send with requests */
16
+ headers?: Record<string, string>;
17
+ /** Additional body fields to send with requests */
18
+ body?: Record<string, unknown>;
19
+ }
20
+ /** Return type for the useAIChat hook */
21
+ interface UseAIChatReturn {
22
+ /** Messages converted to surf-kit ChatMessage format */
23
+ messages: ChatMessage[];
24
+ /** Current streaming state in surf-kit StreamState format */
25
+ streamState: StreamState;
26
+ /** Send a new user message */
27
+ sendMessage: (content: string) => void;
28
+ /** Whether a response is currently streaming */
29
+ isLoading: boolean;
30
+ /** Current error, if any */
31
+ error: Error | undefined;
32
+ /** Stop the current stream */
33
+ stop: () => void;
34
+ /** Regenerate the last assistant message */
35
+ regenerate: () => void;
36
+ }
37
+ /** Options for the useAIStream hook */
38
+ interface UseAIStreamOptions {
39
+ /** API endpoint for completions */
40
+ api?: string;
41
+ /** Callback when a completion finishes */
42
+ onFinish?: (prompt: string, completion: string) => void;
43
+ /** Callback on error */
44
+ onError?: (error: Error) => void;
45
+ /** Additional headers to send with requests */
46
+ headers?: Record<string, string>;
47
+ /** Additional body fields to send with requests */
48
+ body?: Record<string, unknown>;
49
+ }
50
+ /** Return type for the useAIStream hook */
51
+ interface UseAIStreamReturn {
52
+ /** Current streaming state in surf-kit StreamState format */
53
+ streamState: StreamState;
54
+ /** The completed text */
55
+ completion: string;
56
+ /** Trigger a completion */
57
+ complete: (prompt: string) => void;
58
+ /** Whether a completion is currently streaming */
59
+ isLoading: boolean;
60
+ /** Current error, if any */
61
+ error: Error | undefined;
62
+ /** Stop the current stream */
63
+ stop: () => void;
64
+ /** Controlled input value */
65
+ input: string;
66
+ /** Set the controlled input value */
67
+ setInput: (input: string) => void;
68
+ /** Form submit handler */
69
+ handleSubmit: (e?: {
70
+ preventDefault?: () => void;
71
+ }) => void;
72
+ }
73
+
74
+ /**
75
+ * Adapter hook that wraps Vercel AI SDK v6's `useChat` and maps
76
+ * its state to surf-kit `ChatMessage` and `StreamState` types.
77
+ */
78
+ declare function useAIChat(options?: UseAIChatOptions): UseAIChatReturn;
79
+
80
+ /**
81
+ * Adapter hook that wraps Vercel AI SDK v6's `useCompletion` for simple
82
+ * text streaming (no chat history). Maps state to surf-kit `StreamState`.
83
+ */
84
+ declare function useAIStream(options?: UseAIStreamOptions): UseAIStreamReturn;
85
+
86
+ interface AIChatProps extends UseAIChatOptions {
87
+ /** Title shown in the header */
88
+ title?: string;
89
+ /** Message displayed on the welcome screen */
90
+ welcomeMessage?: string;
91
+ /** Suggested questions shown on the welcome screen */
92
+ suggestedQuestions?: string[];
93
+ /** Whether to show the header bar */
94
+ showHeader?: boolean;
95
+ /** Whether to show source citations */
96
+ showSources?: boolean;
97
+ /** Whether to show confidence indicators */
98
+ showConfidence?: boolean;
99
+ /** Additional CSS class names */
100
+ className?: string;
101
+ }
102
+ /**
103
+ * Drop-in chat component powered by Vercel AI SDK v6 and surf-kit agent UI.
104
+ * Composes `MessageThread`, `MessageComposer`, `StreamingMessage`, and
105
+ * `WelcomeScreen` from `@surf-kit/agent`.
106
+ */
107
+ declare function AIChat({ title, welcomeMessage, suggestedQuestions, showHeader, showSources, showConfidence, className, ...chatOptions }: AIChatProps): react_jsx_runtime.JSX.Element;
108
+
109
+ export { AIChat, type AIChatProps, type UseAIChatOptions, type UseAIChatReturn, type UseAIStreamOptions, type UseAIStreamReturn, useAIChat, useAIStream };
package/dist/index.js ADDED
@@ -0,0 +1,135 @@
1
+ // src/hooks/useAIChat.ts
2
+ import { useChat } from "@ai-sdk/react";
3
+ import { DefaultChatTransport } from "ai";
4
+ function getTextContent(message) {
5
+ return message.parts.filter((part) => part.type === "text").map((part) => part.text).join("");
6
+ }
7
+ function useAIChat(options = {}) {
8
+ const chat = useChat({
9
+ transport: new DefaultChatTransport({
10
+ api: options.api,
11
+ headers: options.headers,
12
+ body: options.body
13
+ }),
14
+ onError: options.onError,
15
+ onFinish: options.onFinish
16
+ });
17
+ const messages = chat.messages.map((m) => ({
18
+ id: m.id,
19
+ role: m.role,
20
+ content: getTextContent(m),
21
+ timestamp: /* @__PURE__ */ new Date()
22
+ }));
23
+ const isStreaming = chat.status === "streaming";
24
+ const lastMessageContent = chat.messages.length > 0 ? getTextContent(chat.messages[chat.messages.length - 1]) : "";
25
+ const streamState = {
26
+ active: isStreaming,
27
+ phase: isStreaming ? "generating" : "idle",
28
+ content: isStreaming ? lastMessageContent : "",
29
+ sources: [],
30
+ agent: null,
31
+ agentLabel: null
32
+ };
33
+ return {
34
+ messages,
35
+ streamState,
36
+ sendMessage: (content) => {
37
+ void chat.sendMessage({ text: content });
38
+ },
39
+ isLoading: isStreaming || chat.status === "submitted",
40
+ error: chat.error,
41
+ stop: chat.stop,
42
+ regenerate: () => {
43
+ void chat.regenerate();
44
+ }
45
+ };
46
+ }
47
+
48
+ // src/hooks/useAIStream.ts
49
+ import { useCompletion } from "@ai-sdk/react";
50
+ function useAIStream(options = {}) {
51
+ const completion = useCompletion({
52
+ api: options.api,
53
+ onFinish: options.onFinish,
54
+ onError: options.onError,
55
+ headers: options.headers,
56
+ body: options.body
57
+ });
58
+ const streamState = {
59
+ active: completion.isLoading,
60
+ phase: completion.isLoading ? "generating" : "idle",
61
+ content: completion.completion,
62
+ sources: [],
63
+ agent: null,
64
+ agentLabel: null
65
+ };
66
+ return {
67
+ streamState,
68
+ completion: completion.completion,
69
+ complete: (prompt) => {
70
+ void completion.complete(prompt);
71
+ },
72
+ isLoading: completion.isLoading,
73
+ error: completion.error,
74
+ stop: completion.stop,
75
+ input: completion.input,
76
+ setInput: completion.setInput,
77
+ handleSubmit: completion.handleSubmit
78
+ };
79
+ }
80
+
81
+ // src/components/AIChat.tsx
82
+ import { MessageThread, MessageComposer, WelcomeScreen, StreamingMessage } from "@surf-kit/agent";
83
+ import { jsx, jsxs } from "react/jsx-runtime";
84
+ function AIChat({
85
+ title = "Chat",
86
+ welcomeMessage = "How can I help you today?",
87
+ suggestedQuestions = [],
88
+ showHeader = true,
89
+ showSources,
90
+ showConfidence,
91
+ className,
92
+ ...chatOptions
93
+ }) {
94
+ const { messages, streamState, sendMessage, isLoading } = useAIChat(chatOptions);
95
+ const hasMessages = messages.length > 0;
96
+ const handleQuestionSelect = (question) => {
97
+ sendMessage(question);
98
+ };
99
+ return /* @__PURE__ */ jsxs(
100
+ "div",
101
+ {
102
+ className: [
103
+ "flex flex-col h-full bg-canvas border border-border rounded-xl overflow-hidden",
104
+ className
105
+ ].filter(Boolean).join(" "),
106
+ children: [
107
+ showHeader && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between border-b border-border px-4 py-3 bg-surface-raised shrink-0", children: /* @__PURE__ */ jsx("h1", { className: "text-base font-semibold text-text-primary", children: title }) }),
108
+ hasMessages ? /* @__PURE__ */ jsx(
109
+ MessageThread,
110
+ {
111
+ messages,
112
+ streamingSlot: streamState.active ? /* @__PURE__ */ jsx(StreamingMessage, { stream: streamState }) : void 0,
113
+ showSources,
114
+ showConfidence
115
+ }
116
+ ) : /* @__PURE__ */ jsx(
117
+ WelcomeScreen,
118
+ {
119
+ title,
120
+ message: welcomeMessage,
121
+ suggestedQuestions,
122
+ onQuestionSelect: handleQuestionSelect
123
+ }
124
+ ),
125
+ /* @__PURE__ */ jsx(MessageComposer, { onSend: sendMessage, isLoading })
126
+ ]
127
+ }
128
+ );
129
+ }
130
+ export {
131
+ AIChat,
132
+ useAIChat,
133
+ useAIStream
134
+ };
135
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useAIChat.ts","../src/hooks/useAIStream.ts","../src/components/AIChat.tsx"],"sourcesContent":["import { useChat } from '@ai-sdk/react'\nimport { DefaultChatTransport } from 'ai'\nimport type { UIMessage } from 'ai'\nimport type { ChatMessage, StreamState } from '@surf-kit/agent'\nimport type { UseAIChatOptions, UseAIChatReturn } from '../types'\n\n/**\n * Extract the text content from a UIMessage by concatenating all text parts.\n */\nfunction getTextContent(message: UIMessage): string {\n return message.parts\n .filter((part): part is { type: 'text'; text: string } => part.type === 'text')\n .map((part) => part.text)\n .join('')\n}\n\n/**\n * Adapter hook that wraps Vercel AI SDK v6's `useChat` and maps\n * its state to surf-kit `ChatMessage` and `StreamState` types.\n */\nexport function useAIChat(options: UseAIChatOptions = {}): UseAIChatReturn {\n const chat = useChat({\n transport: new DefaultChatTransport({\n api: options.api,\n headers: options.headers,\n body: options.body,\n }),\n onError: options.onError,\n onFinish: options.onFinish,\n })\n\n // Convert AI SDK v6 UIMessage (parts-based) to surf-kit ChatMessage format\n const messages: ChatMessage[] = chat.messages.map((m) => ({\n id: m.id,\n role: m.role as 'user' | 'assistant',\n content: getTextContent(m),\n timestamp: new Date(),\n }))\n\n const isStreaming = chat.status === 'streaming'\n const lastMessageContent = chat.messages.length > 0\n ? getTextContent(chat.messages[chat.messages.length - 1])\n : ''\n\n const streamState: StreamState = {\n active: isStreaming,\n phase: isStreaming ? 'generating' : 'idle',\n content: isStreaming ? lastMessageContent : '',\n sources: [],\n agent: null,\n agentLabel: null,\n }\n\n return {\n messages,\n streamState,\n sendMessage: (content: string) => {\n void chat.sendMessage({ text: content })\n },\n isLoading: isStreaming || chat.status === 'submitted',\n error: chat.error,\n stop: chat.stop,\n regenerate: () => {\n void chat.regenerate()\n },\n }\n}\n","import { useCompletion } from '@ai-sdk/react'\nimport type { StreamState } from '@surf-kit/agent'\nimport type { UseAIStreamOptions, UseAIStreamReturn } from '../types'\n\n/**\n * Adapter hook that wraps Vercel AI SDK v6's `useCompletion` for simple\n * text streaming (no chat history). Maps state to surf-kit `StreamState`.\n */\nexport function useAIStream(options: UseAIStreamOptions = {}): UseAIStreamReturn {\n const completion = useCompletion({\n api: options.api,\n onFinish: options.onFinish,\n onError: options.onError,\n headers: options.headers,\n body: options.body,\n })\n\n const streamState: StreamState = {\n active: completion.isLoading,\n phase: completion.isLoading ? 'generating' : 'idle',\n content: completion.completion,\n sources: [],\n agent: null,\n agentLabel: null,\n }\n\n return {\n streamState,\n completion: completion.completion,\n complete: (prompt: string) => {\n void completion.complete(prompt)\n },\n isLoading: completion.isLoading,\n error: completion.error,\n stop: completion.stop,\n input: completion.input,\n setInput: completion.setInput,\n handleSubmit: completion.handleSubmit,\n }\n}\n","import React from 'react'\nimport { MessageThread, MessageComposer, WelcomeScreen, StreamingMessage } from '@surf-kit/agent'\nimport { useAIChat } from '../hooks/useAIChat'\nimport type { UseAIChatOptions } from '../types'\n\nexport interface AIChatProps extends UseAIChatOptions {\n /** Title shown in the header */\n title?: string\n /** Message displayed on the welcome screen */\n welcomeMessage?: string\n /** Suggested questions shown on the welcome screen */\n suggestedQuestions?: string[]\n /** Whether to show the header bar */\n showHeader?: boolean\n /** Whether to show source citations */\n showSources?: boolean\n /** Whether to show confidence indicators */\n showConfidence?: boolean\n /** Additional CSS class names */\n className?: string\n}\n\n/**\n * Drop-in chat component powered by Vercel AI SDK v6 and surf-kit agent UI.\n * Composes `MessageThread`, `MessageComposer`, `StreamingMessage`, and\n * `WelcomeScreen` from `@surf-kit/agent`.\n */\nexport function AIChat({\n title = 'Chat',\n welcomeMessage = 'How can I help you today?',\n suggestedQuestions = [],\n showHeader = true,\n showSources,\n showConfidence,\n className,\n ...chatOptions\n}: AIChatProps) {\n const { messages, streamState, sendMessage, isLoading } = useAIChat(chatOptions)\n\n const hasMessages = messages.length > 0\n\n const handleQuestionSelect = (question: string) => {\n sendMessage(question)\n }\n\n return (\n <div\n className={[\n 'flex flex-col h-full bg-canvas border border-border rounded-xl overflow-hidden',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {showHeader && (\n <div className=\"flex items-center justify-between border-b border-border px-4 py-3 bg-surface-raised shrink-0\">\n <h1 className=\"text-base font-semibold text-text-primary\">{title}</h1>\n </div>\n )}\n\n {hasMessages ? (\n <MessageThread\n messages={messages}\n streamingSlot={\n streamState.active ? <StreamingMessage stream={streamState} /> : undefined\n }\n showSources={showSources}\n showConfidence={showConfidence}\n />\n ) : (\n <WelcomeScreen\n title={title}\n message={welcomeMessage}\n suggestedQuestions={suggestedQuestions}\n onQuestionSelect={handleQuestionSelect}\n />\n )}\n\n <MessageComposer onSend={sendMessage} isLoading={isLoading} />\n </div>\n )\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@surf-kit/ai",
3
+ "version": "0.1.1",
4
+ "description": "Adapter bridging surf-kit agent components with Vercel AI SDK v6",
5
+ "keywords": [
6
+ "react",
7
+ "ai",
8
+ "vercel-ai-sdk",
9
+ "adapter",
10
+ "chat",
11
+ "streaming",
12
+ "design-system"
13
+ ],
14
+ "license": "0BSD",
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/barney-w/surf-kit.git",
23
+ "directory": "packages/ai"
24
+ },
25
+ "homepage": "https://github.com/barney-w/surf-kit#readme",
26
+ "bugs": {
27
+ "url": "https://github.com/barney-w/surf-kit/issues"
28
+ },
29
+ "type": "module",
30
+ "main": "dist/index.js",
31
+ "types": "dist/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js",
36
+ "require": "./dist/index.cjs"
37
+ }
38
+ },
39
+ "dependencies": {
40
+ "ai": "^6.0.0",
41
+ "@ai-sdk/react": "^3.0.0",
42
+ "@surf-kit/agent": "0.2.0"
43
+ },
44
+ "devDependencies": {
45
+ "@testing-library/jest-dom": "^6.9.0",
46
+ "@testing-library/react": "^16.3.0",
47
+ "@types/react": "^19.2.0",
48
+ "@types/react-dom": "^19.2.0",
49
+ "jsdom": "^28.1.0",
50
+ "react": "^19.2.0",
51
+ "react-dom": "^19.2.0",
52
+ "tsup": "^8.0.0",
53
+ "typescript": "^5.9.0",
54
+ "vitest": "^4.0.0",
55
+ "@surf-kit/tsconfig": "0.1.0"
56
+ },
57
+ "peerDependencies": {
58
+ "react": ">=19",
59
+ "react-dom": ">=19"
60
+ },
61
+ "publishConfig": {
62
+ "access": "public"
63
+ },
64
+ "scripts": {
65
+ "build": "tsup",
66
+ "dev": "tsup --watch",
67
+ "test": "vitest run",
68
+ "test:watch": "vitest",
69
+ "typecheck": "tsc --noEmit"
70
+ }
71
+ }