@tanstack/ai-solid 0.19.4 → 0.21.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.
@@ -0,0 +1,39 @@
1
+ import { UseChatOptions, UseChatReturn } from "./types.js";
2
+ import { InferredClientContext } from "@tanstack/ai-client";
3
+ import { AnyClientTool as AnyClientTool$1, InterruptDefinition, SchemaInput } from "@tanstack/ai";
4
+
5
+ //#region src/create-chat-hook.d.ts
6
+ type ChatHookOverrides<TTools extends ReadonlyArray<AnyClientTool$1>, TSchema extends SchemaInput | undefined, TContext, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>>> = {
7
+ threadId?: string;
8
+ live?: boolean;
9
+ forwardedProps?: Record<string, any>;
10
+ body?: Record<string, any>;
11
+ initialMessages?: UseChatOptions<TTools, TSchema, TContext, TInterrupts>['initialMessages'];
12
+ };
13
+ /**
14
+ * Bind chat options once at module scope. The returned `useChat` primitive
15
+ * creates a chat instance from those options.
16
+ *
17
+ * Pass per-call overrides for instance keys such as `threadId`,
18
+ * `initialMessages`, `live`, and `forwardedProps`. Do not change `tools`,
19
+ * `interrupts`, or `outputSchema` here. Those stay on the factory options.
20
+ *
21
+ * Rename the primitive at the call site if you already import `useChat` from
22
+ * `@tanstack/ai-solid`: `const { useChat: useAppChat } = createChatHook(chatOptions)`.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * const { useChat } = createChatHook(chatOptions)
27
+ *
28
+ * function Support() {
29
+ * const chat = useChat({ threadId: 'support-1' })
30
+ * return <UI.Chat chat={chat} components={components} />
31
+ * }
32
+ * ```
33
+ */
34
+ declare function createChatHook<const TTools extends ReadonlyArray<AnyClientTool$1> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, const TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []>(options: UseChatOptions<TTools, TSchema, TContext, TInterrupts>): {
35
+ useChat: (overrides?: ChatHookOverrides<TTools, TSchema, TContext, TInterrupts>) => UseChatReturn<TTools, TSchema, TInterrupts>;
36
+ };
37
+ //#endregion
38
+ export { createChatHook };
39
+ //# sourceMappingURL=create-chat-hook.d.ts.map
@@ -0,0 +1,38 @@
1
+ import { useChat } from "./use-chat.js";
2
+
3
+ //#region src/create-chat-hook.ts
4
+ /**
5
+ * Bind chat options once at module scope. The returned `useChat` primitive
6
+ * creates a chat instance from those options.
7
+ *
8
+ * Pass per-call overrides for instance keys such as `threadId`,
9
+ * `initialMessages`, `live`, and `forwardedProps`. Do not change `tools`,
10
+ * `interrupts`, or `outputSchema` here. Those stay on the factory options.
11
+ *
12
+ * Rename the primitive at the call site if you already import `useChat` from
13
+ * `@tanstack/ai-solid`: `const { useChat: useAppChat } = createChatHook(chatOptions)`.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * const { useChat } = createChatHook(chatOptions)
18
+ *
19
+ * function Support() {
20
+ * const chat = useChat({ threadId: 'support-1' })
21
+ * return <UI.Chat chat={chat} components={components} />
22
+ * }
23
+ * ```
24
+ */
25
+ function createChatHook(options) {
26
+ function useChat$1(overrides) {
27
+ if (!overrides) return useChat(options);
28
+ return useChat({
29
+ ...options,
30
+ ...overrides
31
+ });
32
+ }
33
+ return { useChat: useChat$1 };
34
+ }
35
+
36
+ //#endregion
37
+ export { createChatHook };
38
+ //# sourceMappingURL=create-chat-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-chat-hook.js","names":["useChat","useUnboundChat"],"sources":["../src/create-chat-hook.ts"],"sourcesContent":["import { useChat as useUnboundChat } from './use-chat'\nimport type {\n AnyClientTool,\n InterruptDefinition,\n SchemaInput,\n} from '@tanstack/ai'\nimport type { InferredClientContext } from '@tanstack/ai-client'\nimport type { UseChatOptions } from './types'\n\ntype ChatHookOverrides<\n TTools extends ReadonlyArray<AnyClientTool>,\n TSchema extends SchemaInput | undefined,\n TContext,\n TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>>,\n> = {\n threadId?: string\n live?: boolean\n forwardedProps?: Record<string, any>\n body?: Record<string, any>\n initialMessages?: UseChatOptions<\n TTools,\n TSchema,\n TContext,\n TInterrupts\n >['initialMessages']\n}\n\n/**\n * Bind chat options once at module scope. The returned `useChat` primitive\n * creates a chat instance from those options.\n *\n * Pass per-call overrides for instance keys such as `threadId`,\n * `initialMessages`, `live`, and `forwardedProps`. Do not change `tools`,\n * `interrupts`, or `outputSchema` here. Those stay on the factory options.\n *\n * Rename the primitive at the call site if you already import `useChat` from\n * `@tanstack/ai-solid`: `const { useChat: useAppChat } = createChatHook(chatOptions)`.\n *\n * @example\n * ```tsx\n * const { useChat } = createChatHook(chatOptions)\n *\n * function Support() {\n * const chat = useChat({ threadId: 'support-1' })\n * return <UI.Chat chat={chat} components={components} />\n * }\n * ```\n */\nexport function createChatHook<\n const TTools extends ReadonlyArray<AnyClientTool> = any,\n TSchema extends SchemaInput | undefined = undefined,\n TContext = InferredClientContext<TTools>,\n const TInterrupts extends ReadonlyArray<\n InterruptDefinition<any, any, any, any>\n > = readonly [],\n>(options: UseChatOptions<TTools, TSchema, TContext, TInterrupts>) {\n function useChat(\n overrides?: ChatHookOverrides<TTools, TSchema, TContext, TInterrupts>,\n ) {\n if (!overrides) {\n return useUnboundChat(options)\n }\n return useUnboundChat({ ...options, ...overrides })\n }\n\n return { useChat }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAgB,eAOd,SAAiE;CACjE,SAASA,UACP,WACA;AACA,MAAI,CAAC,UACH,QAAOC,QAAe,QAAQ;AAEhC,SAAOA,QAAe;GAAE,GAAG;GAAS,GAAG;GAAW,CAAC;;AAGrD,QAAO,EAAE,oBAAS"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { ChatRequestBody, DeepPartial, QueueConfig, QueueOption, QueueStrategy, QueuedMessage, SendMessageOptions, UIMessage, UseChatOptions, UseChatReturn, WhenBusy } from "./types.js";
2
2
  import { useChat } from "./use-chat.js";
3
+ import { createChatHook } from "./create-chat-hook.js";
3
4
  import { useByok } from "./use-byok.js";
5
+ import { UseWebMCPToolsOptions, useWebMCPTools } from "./use-web-mcp-tools.js";
4
6
  import { UseGenerationOptions, UseGenerationReturn, useGeneration } from "./use-generation.js";
5
7
  import { UseGenerateImageOptions, UseGenerateImageReturn, useGenerateImage } from "./use-generate-image.js";
6
8
  import { UseGenerateAudioOptions, UseGenerateAudioReturn, useGenerateAudio } from "./use-generate-audio.js";
@@ -10,4 +12,4 @@ import { UseSummarizeOptions, UseSummarizeReturn, useSummarize } from "./use-sum
10
12
  import { UseGenerateVideoOptions, UseGenerateVideoReturn, useGenerateVideo } from "./use-generate-video.js";
11
13
  import { UseAudioRecorderOptions, UseAudioRecorderReturn, useAudioRecorder } from "./use-audio-recorder.js";
12
14
  import { AudioGenerateInput, ChatClientPersistence, ChatPersistedState, ChatPersistenceOption, ChatStorageAdapter, ConnectConnectionAdapter, ConnectionAdapter, FetchConnectionOptions, GenerationClientState, ImageGenerateInput, IndexedDBPersistenceOptions, InferChatMessages, RunAgentInputContext, SpeechGenerateInput, StorageUnavailableError, SubscribeConnectionAdapter, SummarizeGenerateInput, TranscriptionGenerateInput, VideoGenerateInput, VideoGenerateResult, VideoStatusInfo, WebSocketConnectionOptions, WebStoragePersistenceOptions, XhrConnectionOptions, createChatClientOptions, fetchHttpStream, fetchServerSentEvents, indexedDBPersistence, localStoragePersistence, rpcStream, sessionStoragePersistence, stream, webSocket, xhrHttpStream, xhrServerSentEvents } from "@tanstack/ai-client";
13
- export { type AudioGenerateInput, type ChatClientPersistence, type ChatPersistedState, type ChatPersistenceOption, type ChatRequestBody, type ChatStorageAdapter, type ConnectConnectionAdapter, type ConnectionAdapter, type DeepPartial, type FetchConnectionOptions, type GenerationClientState, type ImageGenerateInput, type IndexedDBPersistenceOptions, type InferChatMessages, type QueueConfig, type QueueOption, type QueueStrategy, type QueuedMessage, type RunAgentInputContext, type SendMessageOptions, type SpeechGenerateInput, StorageUnavailableError, type SubscribeConnectionAdapter, type SummarizeGenerateInput, type TranscriptionGenerateInput, type UIMessage, type UseAudioRecorderOptions, type UseAudioRecorderReturn, type UseChatOptions, type UseChatReturn, type UseGenerateAudioOptions, type UseGenerateAudioReturn, type UseGenerateImageOptions, type UseGenerateImageReturn, type UseGenerateSpeechOptions, type UseGenerateSpeechReturn, type UseGenerateVideoOptions, type UseGenerateVideoReturn, type UseGenerationOptions, type UseGenerationReturn, type UseSummarizeOptions, type UseSummarizeReturn, type UseTranscriptionOptions, type UseTranscriptionReturn, type VideoGenerateInput, type VideoGenerateResult, type VideoStatusInfo, type WebSocketConnectionOptions, type WebStoragePersistenceOptions, type WhenBusy, type XhrConnectionOptions, createChatClientOptions, fetchHttpStream, fetchServerSentEvents, indexedDBPersistence, localStoragePersistence, rpcStream, sessionStoragePersistence, stream, useAudioRecorder, useByok, useChat, useGenerateAudio, useGenerateImage, useGenerateSpeech, useGenerateVideo, useGeneration, useSummarize, useTranscription, webSocket, xhrHttpStream, xhrServerSentEvents };
15
+ export { type AudioGenerateInput, type ChatClientPersistence, type ChatPersistedState, type ChatPersistenceOption, type ChatRequestBody, type ChatStorageAdapter, type ConnectConnectionAdapter, type ConnectionAdapter, type DeepPartial, type FetchConnectionOptions, type GenerationClientState, type ImageGenerateInput, type IndexedDBPersistenceOptions, type InferChatMessages, type QueueConfig, type QueueOption, type QueueStrategy, type QueuedMessage, type RunAgentInputContext, type SendMessageOptions, type SpeechGenerateInput, StorageUnavailableError, type SubscribeConnectionAdapter, type SummarizeGenerateInput, type TranscriptionGenerateInput, type UIMessage, type UseAudioRecorderOptions, type UseAudioRecorderReturn, type UseChatOptions, type UseChatReturn, type UseGenerateAudioOptions, type UseGenerateAudioReturn, type UseGenerateImageOptions, type UseGenerateImageReturn, type UseGenerateSpeechOptions, type UseGenerateSpeechReturn, type UseGenerateVideoOptions, type UseGenerateVideoReturn, type UseGenerationOptions, type UseGenerationReturn, type UseSummarizeOptions, type UseSummarizeReturn, type UseTranscriptionOptions, type UseTranscriptionReturn, type UseWebMCPToolsOptions, type VideoGenerateInput, type VideoGenerateResult, type VideoStatusInfo, type WebSocketConnectionOptions, type WebStoragePersistenceOptions, type WhenBusy, type XhrConnectionOptions, createChatClientOptions, createChatHook, fetchHttpStream, fetchServerSentEvents, indexedDBPersistence, localStoragePersistence, rpcStream, sessionStoragePersistence, stream, useAudioRecorder, useByok, useChat, useGenerateAudio, useGenerateImage, useGenerateSpeech, useGenerateVideo, useGeneration, useSummarize, useTranscription, useWebMCPTools, webSocket, xhrHttpStream, xhrServerSentEvents };
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { useChat } from "./use-chat.js";
2
+ import { createChatHook } from "./create-chat-hook.js";
2
3
  import { useByok } from "./use-byok.js";
4
+ import { useWebMCPTools } from "./use-web-mcp-tools.js";
3
5
  import { useGeneration } from "./use-generation.js";
4
6
  import { useGenerateImage } from "./use-generate-image.js";
5
7
  import { useGenerateAudio } from "./use-generate-audio.js";
@@ -10,4 +12,4 @@ import { useGenerateVideo } from "./use-generate-video.js";
10
12
  import { useAudioRecorder } from "./use-audio-recorder.js";
11
13
  import { StorageUnavailableError, createChatClientOptions, fetchHttpStream, fetchServerSentEvents, indexedDBPersistence, localStoragePersistence, rpcStream, sessionStoragePersistence, stream, webSocket, xhrHttpStream, xhrServerSentEvents } from "@tanstack/ai-client";
12
14
 
13
- export { StorageUnavailableError, createChatClientOptions, fetchHttpStream, fetchServerSentEvents, indexedDBPersistence, localStoragePersistence, rpcStream, sessionStoragePersistence, stream, useAudioRecorder, useByok, useChat, useGenerateAudio, useGenerateImage, useGenerateSpeech, useGenerateVideo, useGeneration, useSummarize, useTranscription, webSocket, xhrHttpStream, xhrServerSentEvents };
15
+ export { StorageUnavailableError, createChatClientOptions, createChatHook, fetchHttpStream, fetchServerSentEvents, indexedDBPersistence, localStoragePersistence, rpcStream, sessionStoragePersistence, stream, useAudioRecorder, useByok, useChat, useGenerateAudio, useGenerateImage, useGenerateSpeech, useGenerateVideo, useGeneration, useSummarize, useTranscription, useWebMCPTools, webSocket, xhrHttpStream, xhrServerSentEvents };
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Accessor } from "solid-js";
2
2
  import { AIDevtoolsDisplayOptions, BoundInterrupts, ChatClientOptions, ChatClientState, ChatInterruptState, ChatRequestBody, ChatResumeState, ClientContextOptionFromTools, ConnectionStatus, DistributedOmit, InferredClientContext, MultimodalContent, QueueConfig, QueueOption, QueueStrategy, QueuedMessage, ResolvableChatInterrupt, SendMessageOptions, UIMessage, WhenBusy } from "@tanstack/ai-client";
3
- import { AnyClientTool, InferSchemaType, InterruptDefinition, ModelMessage, RunAgentResumeItem, SchemaInput } from "@tanstack/ai";
3
+ import { AnyClientTool as AnyClientTool$1, InferSchemaType, InterruptDefinition, ModelMessage, RunAgentResumeItem, SchemaInput } from "@tanstack/ai";
4
4
 
5
5
  //#region src/types.d.ts
6
6
 
@@ -31,7 +31,7 @@ type DeepPartial<T> = T extends ReadonlyArray<infer U> ? Array<DeepPartial<U>> :
31
31
  * Note: Connection and body changes will recreate the ChatClient instance.
32
32
  * To update these options, remount the component or use a key prop.
33
33
  */
34
- type UseChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> = DistributedOmit<ChatClientOptions<TTools, TContext, TInterrupts>, 'onMessagesChange' | 'onLoadingChange' | 'onErrorChange' | 'onStatusChange' | 'onSubscriptionChange' | 'onConnectionStatusChange' | 'onSessionGeneratingChange' | 'onQueueChange' | 'onResumeStateChange' | 'onRunIdChange' | 'context' | 'devtools'> & {
34
+ type UseChatOptions<TTools extends ReadonlyArray<AnyClientTool$1> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> = DistributedOmit<ChatClientOptions<TTools, TContext, TInterrupts>, 'onMessagesChange' | 'onLoadingChange' | 'onErrorChange' | 'onStatusChange' | 'onSubscriptionChange' | 'onConnectionStatusChange' | 'onSessionGeneratingChange' | 'onQueueChange' | 'onResumeStateChange' | 'onRunIdChange' | 'context' | 'devtools'> & {
35
35
  /** Display options for TanStack AI Devtools. */
36
36
  devtools?: AIDevtoolsDisplayOptions;
37
37
  live?: boolean;
@@ -45,7 +45,7 @@ type UseChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema e
45
45
  * Discriminated return shape: when `outputSchema` is supplied, the hook adds
46
46
  * typed `partial` / `final` accessors; otherwise the return is unchanged.
47
47
  */
48
- type UseChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> = BaseUseChatReturn<TTools, TSchema extends SchemaInput ? InferSchemaType<TSchema> : unknown, TInterrupts> & (TSchema extends SchemaInput ? {
48
+ type UseChatReturn<TTools extends ReadonlyArray<AnyClientTool$1> = any, TSchema extends SchemaInput | undefined = undefined, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> = BaseUseChatReturn<TTools, TSchema extends SchemaInput ? InferSchemaType<TSchema> : unknown, TInterrupts> & (TSchema extends SchemaInput ? {
49
49
  /**
50
50
  * Live progressively-parsed structured output. Derived from the
51
51
  * latest assistant message's structured-output part.
@@ -57,7 +57,7 @@ type UseChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TSchema ex
57
57
  */
58
58
  final: Accessor<InferSchemaType<TSchema> | null>;
59
59
  } : Record<never, never>);
60
- interface BaseUseChatReturn<TTools extends ReadonlyArray<AnyClientTool> = any, TData = unknown, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> {
60
+ interface BaseUseChatReturn<TTools extends ReadonlyArray<AnyClientTool$1> = any, TData = unknown, TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []> {
61
61
  /**
62
62
  * Current messages in the conversation. When `outputSchema` is supplied,
63
63
  * `messages()[i].parts.find(p => p.type === 'structured-output')` is typed
@@ -1,9 +1,9 @@
1
1
  import { UseChatOptions, UseChatReturn } from "./types.js";
2
2
  import { InferredClientContext } from "@tanstack/ai-client";
3
- import { AnyClientTool, InterruptDefinition, SchemaInput } from "@tanstack/ai";
3
+ import { AnyClientTool as AnyClientTool$1, InterruptDefinition, SchemaInput } from "@tanstack/ai";
4
4
 
5
5
  //#region src/use-chat.d.ts
6
- declare function useChat<const TTools extends ReadonlyArray<AnyClientTool> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, const TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []>(options?: UseChatOptions<TTools, TSchema, TContext, TInterrupts>): UseChatReturn<TTools, TSchema, TInterrupts>;
6
+ declare function useChat<const TTools extends ReadonlyArray<AnyClientTool$1> = any, TSchema extends SchemaInput | undefined = undefined, TContext = InferredClientContext<TTools>, const TInterrupts extends ReadonlyArray<InterruptDefinition<any, any, any, any>> = readonly []>(options?: UseChatOptions<TTools, TSchema, TContext, TInterrupts>): UseChatReturn<TTools, TSchema, TInterrupts>;
7
7
  //#endregion
8
8
  export { useChat };
9
9
  //# sourceMappingURL=use-chat.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { AnyClientTool, InferredClientContext, RegisterWebMCPToolsOptions } from "@tanstack/ai-client";
2
+
3
+ //#region src/use-web-mcp-tools.d.ts
4
+ /** Options for {@link useWebMCPTools}. */
5
+ type UseWebMCPToolsOptions<TTools extends ReadonlyArray<AnyClientTool>, TContext = InferredClientContext<TTools>> = Omit<RegisterWebMCPToolsOptions<TTools, TContext>, 'signal'> & {
6
+ /** Receives an asynchronous registration error. */
7
+ onError?: (error: unknown) => void;
8
+ };
9
+ type UseWebMCPToolsArguments<TTools extends ReadonlyArray<AnyClientTool>, TContext> = {} extends UseWebMCPToolsOptions<TTools, TContext> ? [options?: UseWebMCPToolsOptions<TTools, TContext>] : [options: UseWebMCPToolsOptions<TTools, TContext>];
10
+ /**
11
+ * Registers executable client tools with WebMCP for the current Solid owner.
12
+ *
13
+ * The owner cleanup removes every tool registered by this call.
14
+ *
15
+ * @param tools - The executable client tools to expose through WebMCP.
16
+ * @param options - Runtime context, per-tool options, and error handling.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * useWebMCPTools([searchProducts])
21
+ * ```
22
+ */
23
+ declare function useWebMCPTools<const TTools extends ReadonlyArray<AnyClientTool>, TContext = InferredClientContext<TTools>>(tools: TTools, ...[options]: UseWebMCPToolsArguments<TTools, TContext>): void;
24
+ //#endregion
25
+ export { UseWebMCPToolsOptions, useWebMCPTools };
26
+ //# sourceMappingURL=use-web-mcp-tools.d.ts.map
@@ -0,0 +1,31 @@
1
+ import { onCleanup } from "solid-js";
2
+ import { registerWebMCPTools } from "@tanstack/ai-client";
3
+
4
+ //#region src/use-web-mcp-tools.ts
5
+ /**
6
+ * Registers executable client tools with WebMCP for the current Solid owner.
7
+ *
8
+ * The owner cleanup removes every tool registered by this call.
9
+ *
10
+ * @param tools - The executable client tools to expose through WebMCP.
11
+ * @param options - Runtime context, per-tool options, and error handling.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * useWebMCPTools([searchProducts])
16
+ * ```
17
+ */
18
+ function useWebMCPTools(tools, ...[options]) {
19
+ const controller = new AbortController();
20
+ registerWebMCPTools(tools, {
21
+ ...options,
22
+ signal: controller.signal
23
+ }).catch((error) => {
24
+ if (!controller.signal.aborted) options?.onError?.(error);
25
+ });
26
+ onCleanup(() => controller.abort());
27
+ }
28
+
29
+ //#endregion
30
+ export { useWebMCPTools };
31
+ //# sourceMappingURL=use-web-mcp-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-web-mcp-tools.js","names":[],"sources":["../src/use-web-mcp-tools.ts"],"sourcesContent":["import { onCleanup } from 'solid-js'\nimport { registerWebMCPTools } from '@tanstack/ai-client'\nimport type {\n AnyClientTool,\n InferredClientContext,\n RegisterWebMCPToolsOptions,\n} from '@tanstack/ai-client'\n\n/** Options for {@link useWebMCPTools}. */\nexport type UseWebMCPToolsOptions<\n TTools extends ReadonlyArray<AnyClientTool>,\n TContext = InferredClientContext<TTools>,\n> = Omit<RegisterWebMCPToolsOptions<TTools, TContext>, 'signal'> & {\n /** Receives an asynchronous registration error. */\n onError?: (error: unknown) => void\n}\n\ntype UseWebMCPToolsArguments<\n TTools extends ReadonlyArray<AnyClientTool>,\n TContext,\n> =\n {} extends UseWebMCPToolsOptions<TTools, TContext>\n ? [options?: UseWebMCPToolsOptions<TTools, TContext>]\n : [options: UseWebMCPToolsOptions<TTools, TContext>]\n\n/**\n * Registers executable client tools with WebMCP for the current Solid owner.\n *\n * The owner cleanup removes every tool registered by this call.\n *\n * @param tools - The executable client tools to expose through WebMCP.\n * @param options - Runtime context, per-tool options, and error handling.\n *\n * @example\n * ```ts\n * useWebMCPTools([searchProducts])\n * ```\n */\nexport function useWebMCPTools<\n const TTools extends ReadonlyArray<AnyClientTool>,\n TContext = InferredClientContext<TTools>,\n>(tools: TTools, ...[options]: UseWebMCPToolsArguments<TTools, TContext>) {\n const controller = new AbortController()\n\n void registerWebMCPTools(tools, {\n ...options,\n signal: controller.signal,\n }).catch((error) => {\n if (!controller.signal.aborted) {\n options?.onError?.(error)\n }\n })\n\n onCleanup(() => controller.abort())\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAsCA,SAAgB,eAGd,OAAe,GAAG,CAAC,UAAqD;CACxE,MAAM,aAAa,IAAI,iBAAiB;AAExC,CAAK,oBAAoB,OAAO;EAC9B,GAAG;EACH,QAAQ,WAAW;EACpB,CAAC,CAAC,OAAO,UAAU;AAClB,MAAI,CAAC,WAAW,OAAO,QACrB,UAAS,UAAU,MAAM;GAE3B;AAEF,iBAAgB,WAAW,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-solid",
3
- "version": "0.19.4",
3
+ "version": "0.21.0",
4
4
  "description": "Solid hooks for TanStack AI streaming chat, structured outputs, and media generation.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -24,6 +24,11 @@
24
24
  ".": {
25
25
  "types": "./dist/index.d.ts",
26
26
  "import": "./dist/index.js"
27
+ },
28
+ "./ui": {
29
+ "solid": "./src/ui.ts",
30
+ "types": "./src/ui.ts",
31
+ "import": "./src/ui.ts"
27
32
  }
28
33
  },
29
34
  "files": [
@@ -45,11 +50,16 @@
45
50
  "media-generation"
46
51
  ],
47
52
  "dependencies": {
48
- "@tanstack/ai-client": "^0.29.2"
53
+ "rehype-highlight": "^7.0.2",
54
+ "rehype-raw": "^7.0.0",
55
+ "rehype-sanitize": "^6.0.0",
56
+ "remark-gfm": "^4.0.1",
57
+ "solid-markdown": "^2.1.0",
58
+ "@tanstack/ai-client": "^0.31.0"
49
59
  },
50
60
  "peerDependencies": {
51
61
  "solid-js": ">=1.9.10",
52
- "@tanstack/ai": "^0.52.0"
62
+ "@tanstack/ai": "^0.53.0"
53
63
  },
54
64
  "devDependencies": {
55
65
  "@solidjs/testing-library": "^0.8.10",
@@ -60,8 +70,10 @@
60
70
  "solid-js": "^1.9.10",
61
71
  "tsdown": "^0.17.0-beta.6",
62
72
  "typescript": "5.9.3",
73
+ "vite": "^8.2.1",
74
+ "vite-plugin-solid": "^2.11.14",
63
75
  "vitest": "^4.1.10",
64
- "@tanstack/ai": "0.52.0"
76
+ "@tanstack/ai": "0.53.0"
65
77
  },
66
78
  "scripts": {
67
79
  "clean": "premove ./build ./dist",
@@ -0,0 +1,168 @@
1
+ import { createSignal } from 'solid-js'
2
+ import { useChatContext } from './chat'
3
+ import type { JSX } from 'solid-js'
4
+
5
+ export interface ChatInputRenderProps {
6
+ /** Current input value */
7
+ value: string
8
+ /** Set input value */
9
+ onChange: (value: string) => void
10
+ /** Submit the message */
11
+ onSubmit: () => void
12
+ /** Is the chat currently loading */
13
+ isLoading: boolean
14
+ /** Is input disabled */
15
+ disabled: boolean
16
+ /** Ref callback for the input element */
17
+ ref: (el: HTMLInputElement | HTMLTextAreaElement) => void
18
+ }
19
+
20
+ /** @deprecated Use `createChatUI()` and an application-owned input component. Deprecated in 0.8.0. Removed in 1.0.0. */
21
+ export interface ChatInputProps {
22
+ /** Render prop for full control */
23
+ children?: (props: ChatInputRenderProps) => JSX.Element
24
+ /** CSS class name */
25
+ class?: string
26
+ /** Placeholder text */
27
+ placeholder?: string
28
+ /** Disable input */
29
+ disabled?: boolean
30
+ /** Submit on Enter (Shift+Enter for new line) */
31
+ submitOnEnter?: boolean
32
+ }
33
+
34
+ /**
35
+ * @deprecated Use `createChatUI()` and an application-owned input component. Deprecated in 0.8.0. Removed in 1.0.0.
36
+ *
37
+ * Chat input component - handles message input and submission
38
+ *
39
+ * Features:
40
+ * - Auto-growing textarea
41
+ * - Submit on Enter (Shift+Enter for new line)
42
+ * - Loading state management
43
+ * - Full render prop support for custom UIs
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * <Chat.Input placeholder="Type your message..." />
48
+ * ```
49
+ *
50
+ * @example Custom UI with render prop
51
+ * ```tsx
52
+ * <Chat.Input>
53
+ * {({ value, onChange, onSubmit, isLoading }) => (
54
+ * <div>
55
+ * <textarea value={value} onInput={(e) => onChange(e.target.value)} />
56
+ * <button onClick={onSubmit} disabled={isLoading}>Send</button>
57
+ * </div>
58
+ * )}
59
+ * </Chat.Input>
60
+ * ```
61
+ */
62
+ export function ChatInput(props: ChatInputProps) {
63
+ const { sendMessage, isLoading } = useChatContext()
64
+ const [value, setValue] = createSignal('')
65
+
66
+ const disabled = () => props.disabled || isLoading()
67
+
68
+ const handleSubmit = () => {
69
+ if (!value().trim() || disabled()) return
70
+ void sendMessage(value())
71
+ setValue('')
72
+ }
73
+
74
+ const renderProps = (): ChatInputRenderProps => ({
75
+ value: value(),
76
+ onChange: setValue,
77
+ onSubmit: handleSubmit,
78
+ isLoading: isLoading(),
79
+ disabled: disabled(),
80
+
81
+ ref: () => {},
82
+ })
83
+
84
+ // Render prop pattern
85
+ if (props.children) {
86
+ return <>{props.children(renderProps())}</>
87
+ }
88
+
89
+ // Default implementation
90
+ return (
91
+ <div
92
+ class={props.class}
93
+ data-chat-input
94
+ style={{
95
+ display: 'flex',
96
+ gap: '0.75rem',
97
+ 'align-items': 'center',
98
+ width: '100%',
99
+ }}
100
+ >
101
+ <input
102
+ type="text"
103
+ value={value()}
104
+ onInput={(e) => setValue(e.currentTarget.value)}
105
+ onKeyDown={(e) => {
106
+ if ((props.submitOnEnter ?? true) && e.key === 'Enter') {
107
+ e.preventDefault()
108
+ handleSubmit()
109
+ }
110
+ }}
111
+ placeholder={props.placeholder ?? 'Type a message...'}
112
+ disabled={disabled()}
113
+ data-chat-textarea
114
+ style={{
115
+ flex: 1,
116
+ padding: '0.75rem 1rem',
117
+ 'font-size': '0.875rem',
118
+ border: '1px solid rgba(255, 255, 255, 0.1)',
119
+ 'border-radius': '0.75rem',
120
+ 'background-color': 'rgba(31, 41, 55, 0.5)',
121
+ color: 'white',
122
+ outline: 'none',
123
+ transition: 'all 0.2s',
124
+ }}
125
+ onFocus={(e) => {
126
+ e.currentTarget.style.borderColor = 'rgba(249, 115, 22, 0.4)'
127
+ e.currentTarget.style.boxShadow = '0 0 0 2px rgba(249, 115, 22, 0.2)'
128
+ }}
129
+ onBlur={(e) => {
130
+ e.currentTarget.style.borderColor = 'rgba(255, 255, 255, 0.1)'
131
+ e.currentTarget.style.boxShadow = 'none'
132
+ }}
133
+ />
134
+ <button
135
+ onClick={handleSubmit}
136
+ disabled={disabled() || !value().trim()}
137
+ data-chat-submit
138
+ style={{
139
+ padding: '0.75rem 1.5rem',
140
+ 'font-size': '0.875rem',
141
+ 'font-weight': 500,
142
+ color: 'white',
143
+ 'background-color':
144
+ disabled() || !value().trim()
145
+ ? 'rgba(107, 114, 128, 0.5)'
146
+ : 'rgb(249, 115, 22)',
147
+ border: 'none',
148
+ 'border-radius': '0.75rem',
149
+ cursor: disabled() || !value().trim() ? 'not-allowed' : 'pointer',
150
+ transition: 'all 0.2s',
151
+ 'white-space': 'nowrap',
152
+ }}
153
+ onMouseEnter={(e) => {
154
+ if (!disabled() && value().trim()) {
155
+ e.currentTarget.style.backgroundColor = 'rgb(234, 88, 12)'
156
+ }
157
+ }}
158
+ onMouseLeave={(e) => {
159
+ if (!disabled() && value().trim()) {
160
+ e.currentTarget.style.backgroundColor = 'rgb(249, 115, 22)'
161
+ }
162
+ }}
163
+ >
164
+ {isLoading() ? 'Sending...' : 'Send'}
165
+ </button>
166
+ </div>
167
+ )
168
+ }