@tanstack/ai-remix 0.4.3 → 0.5.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/package.json +4 -4
- package/src/create-chat.ts +21 -1
- package/src/create-web-mcp-tools.ts +79 -10
- package/src/index.ts +15 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-remix",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Remix 3 bindings for TanStack AI streaming chat, structured outputs, and media generation.",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
"README.md"
|
|
48
48
|
],
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@tanstack/ai-client": "^0.
|
|
50
|
+
"@tanstack/ai-client": "^0.35.1"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"remix": "^3.0.0-rc.1",
|
|
54
|
-
"@tanstack/ai": "^0.
|
|
54
|
+
"@tanstack/ai": "^0.61.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/node": "^24.10.1",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"remix": "^3.0.0-rc.1",
|
|
61
61
|
"vite": "^8.2.1",
|
|
62
62
|
"vitest": "^4.1.10",
|
|
63
|
-
"@tanstack/ai": "0.
|
|
63
|
+
"@tanstack/ai": "0.61.0"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
66
|
"lint:fix": "oxlint src --type-aware --fix",
|
package/src/create-chat.ts
CHANGED
|
@@ -245,10 +245,20 @@ export function createChat<
|
|
|
245
245
|
client.mountDevtools()
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
// Remix has no effects, so read `options.tools` before each call that can
|
|
249
|
+
// start a run. A getter such as `get tools() { return page.tools }` then
|
|
250
|
+
// sends the current tools.
|
|
251
|
+
const syncTools = () => {
|
|
252
|
+
if (options.tools !== undefined) {
|
|
253
|
+
client.updateOptions({ tools: options.tools })
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
248
257
|
const sendMessage = async (
|
|
249
258
|
content: string | MultimodalContent,
|
|
250
259
|
sendOptions?: SendMessageOptions,
|
|
251
260
|
) => {
|
|
261
|
+
syncTools()
|
|
252
262
|
try {
|
|
253
263
|
await client.sendMessage(content, undefined, sendOptions)
|
|
254
264
|
} finally {
|
|
@@ -259,6 +269,7 @@ export function createChat<
|
|
|
259
269
|
const cancelQueued = (id: string) => client.cancelQueued(id)
|
|
260
270
|
|
|
261
271
|
const append = async (message: ModelMessage | UIMessage<TTools>) => {
|
|
272
|
+
syncTools()
|
|
262
273
|
try {
|
|
263
274
|
await client.append(message)
|
|
264
275
|
} finally {
|
|
@@ -267,6 +278,7 @@ export function createChat<
|
|
|
267
278
|
}
|
|
268
279
|
|
|
269
280
|
const reload = async () => {
|
|
281
|
+
syncTools()
|
|
270
282
|
try {
|
|
271
283
|
await client.reload()
|
|
272
284
|
} finally {
|
|
@@ -300,6 +312,7 @@ export function createChat<
|
|
|
300
312
|
state?: 'output-available' | 'output-error'
|
|
301
313
|
errorText?: string
|
|
302
314
|
}) => {
|
|
315
|
+
syncTools()
|
|
303
316
|
await client.addToolResult(result)
|
|
304
317
|
}
|
|
305
318
|
|
|
@@ -308,6 +321,7 @@ export function createChat<
|
|
|
308
321
|
id: string
|
|
309
322
|
approved: boolean
|
|
310
323
|
}) => {
|
|
324
|
+
syncTools()
|
|
311
325
|
await client.addToolApprovalResponse(response)
|
|
312
326
|
syncResumeState()
|
|
313
327
|
}
|
|
@@ -316,6 +330,7 @@ export function createChat<
|
|
|
316
330
|
resumeItems: Array<RunAgentResumeItem>,
|
|
317
331
|
state?: ChatResumeState,
|
|
318
332
|
) => {
|
|
333
|
+
syncTools()
|
|
319
334
|
const result = await client.resumeInterrupts(resumeItems, state)
|
|
320
335
|
syncResumeState()
|
|
321
336
|
return result
|
|
@@ -328,6 +343,7 @@ export function createChat<
|
|
|
328
343
|
interrupt: ResolvableChatInterrupt<TTools, TInterrupts>,
|
|
329
344
|
) => undefined),
|
|
330
345
|
) => {
|
|
346
|
+
syncTools()
|
|
331
347
|
if (typeof resolution === 'boolean') {
|
|
332
348
|
client.resolveInterrupts(resolution)
|
|
333
349
|
} else {
|
|
@@ -340,13 +356,17 @@ export function createChat<
|
|
|
340
356
|
}
|
|
341
357
|
|
|
342
358
|
const retryInterrupts = () => {
|
|
359
|
+
syncTools()
|
|
343
360
|
client.retryInterrupts()
|
|
344
361
|
}
|
|
345
362
|
|
|
346
363
|
const resumeInterruptsUnsafe = (
|
|
347
364
|
resumeItems: Array<RunAgentResumeItem>,
|
|
348
365
|
state?: ChatResumeState,
|
|
349
|
-
) =>
|
|
366
|
+
) => {
|
|
367
|
+
syncTools()
|
|
368
|
+
return client.resumeInterruptsUnsafe(resumeItems, state)
|
|
369
|
+
}
|
|
350
370
|
|
|
351
371
|
function activeStructuredPart(): StructuredOutputPart | null {
|
|
352
372
|
let lastUserIndex = -1
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { registerWebMCPTools } from '@tanstack/ai-client'
|
|
1
|
+
import { registerWebMCPTools, subscribeWebMCPTools } from '@tanstack/ai-client'
|
|
2
2
|
import type {
|
|
3
3
|
AnyClientTool,
|
|
4
4
|
InferredClientContext,
|
|
5
5
|
RegisterWebMCPToolsOptions,
|
|
6
|
+
SubscribeWebMCPToolsOptions,
|
|
6
7
|
} from '@tanstack/ai-client'
|
|
7
8
|
import type { Handle } from 'remix/ui'
|
|
8
9
|
|
|
9
|
-
/** Options for {@link
|
|
10
|
-
export type
|
|
10
|
+
/** Options for {@link createRegisterWebMCPTools}. */
|
|
11
|
+
export type CreateRegisterWebMCPToolsOptions<
|
|
11
12
|
TTools extends ReadonlyArray<AnyClientTool>,
|
|
12
13
|
TContext = InferredClientContext<TTools>,
|
|
13
14
|
> = Omit<RegisterWebMCPToolsOptions<TTools, TContext>, 'signal'> & {
|
|
@@ -15,13 +16,19 @@ export type CreateWebMCPToolsOptions<
|
|
|
15
16
|
onError?: (error: unknown) => void
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
/** @deprecated Use `CreateRegisterWebMCPToolsOptions`. Removed in 1.0.0. */
|
|
20
|
+
export type CreateWebMCPToolsOptions<
|
|
21
|
+
TTools extends ReadonlyArray<AnyClientTool>,
|
|
22
|
+
TContext = InferredClientContext<TTools>,
|
|
23
|
+
> = CreateRegisterWebMCPToolsOptions<TTools, TContext>
|
|
24
|
+
|
|
25
|
+
type CreateRegisterWebMCPToolsArguments<
|
|
19
26
|
TTools extends ReadonlyArray<AnyClientTool>,
|
|
20
27
|
TContext,
|
|
21
28
|
> =
|
|
22
|
-
{} extends
|
|
23
|
-
? [options?:
|
|
24
|
-
: [options:
|
|
29
|
+
{} extends CreateRegisterWebMCPToolsOptions<TTools, TContext>
|
|
30
|
+
? [options?: CreateRegisterWebMCPToolsOptions<TTools, TContext>]
|
|
31
|
+
: [options: CreateRegisterWebMCPToolsOptions<TTools, TContext>]
|
|
25
32
|
|
|
26
33
|
/**
|
|
27
34
|
* Registers executable client tools with WebMCP for a Remix component.
|
|
@@ -35,18 +42,18 @@ type CreateWebMCPToolsArguments<
|
|
|
35
42
|
* @example
|
|
36
43
|
* ```tsx
|
|
37
44
|
* function Products(handle: Handle) {
|
|
38
|
-
*
|
|
45
|
+
* createRegisterWebMCPTools(handle, [searchProducts])
|
|
39
46
|
* return () => <ProductList />
|
|
40
47
|
* }
|
|
41
48
|
* ```
|
|
42
49
|
*/
|
|
43
|
-
export function
|
|
50
|
+
export function createRegisterWebMCPTools<
|
|
44
51
|
const TTools extends ReadonlyArray<AnyClientTool>,
|
|
45
52
|
TContext = InferredClientContext<TTools>,
|
|
46
53
|
>(
|
|
47
54
|
handle: Pick<Handle, 'signal'>,
|
|
48
55
|
tools: TTools,
|
|
49
|
-
...[options]:
|
|
56
|
+
...[options]: CreateRegisterWebMCPToolsArguments<TTools, TContext>
|
|
50
57
|
) {
|
|
51
58
|
void registerWebMCPTools(tools, {
|
|
52
59
|
...options,
|
|
@@ -57,3 +64,65 @@ export function createWebMCPTools<
|
|
|
57
64
|
}
|
|
58
65
|
})
|
|
59
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @deprecated Use `createRegisterWebMCPTools`. Removed in 1.0.0.
|
|
70
|
+
* @alias
|
|
71
|
+
*/
|
|
72
|
+
export const createWebMCPTools = createRegisterWebMCPTools
|
|
73
|
+
|
|
74
|
+
/** Options for {@link createPageWebMCPTools}. */
|
|
75
|
+
export type CreatePageWebMCPToolsOptions = Omit<
|
|
76
|
+
SubscribeWebMCPToolsOptions,
|
|
77
|
+
'signal'
|
|
78
|
+
>
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Reads the WebMCP tools on the page as client tools for `createChat`.
|
|
82
|
+
*
|
|
83
|
+
* `tools` starts empty. When the page registers or removes a tool, the
|
|
84
|
+
* helper updates `tools` and calls `handle.update()`. The Handle signal stops
|
|
85
|
+
* the updates. Unsupported browsers and server rendering keep an empty array.
|
|
86
|
+
*
|
|
87
|
+
* @param handle - The Remix component Handle from setup.
|
|
88
|
+
* @param options - A filter that skips tools, and an error callback.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```tsx
|
|
92
|
+
* function Chat(handle: Handle) {
|
|
93
|
+
* const page = createPageWebMCPTools(handle)
|
|
94
|
+
* const chat = createChat(handle, {
|
|
95
|
+
* connection,
|
|
96
|
+
* get tools() {
|
|
97
|
+
* return page.tools
|
|
98
|
+
* },
|
|
99
|
+
* })
|
|
100
|
+
* return () => <Messages chat={chat} />
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function createPageWebMCPTools(
|
|
105
|
+
handle: Pick<Handle, 'signal' | 'update'>,
|
|
106
|
+
options?: CreatePageWebMCPToolsOptions,
|
|
107
|
+
) {
|
|
108
|
+
let tools: Array<AnyClientTool> = []
|
|
109
|
+
|
|
110
|
+
subscribeWebMCPTools(
|
|
111
|
+
(nextTools) => {
|
|
112
|
+
tools = nextTools
|
|
113
|
+
void handle.update()
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
signal: handle.signal,
|
|
117
|
+
filter: (tool) => options?.filter?.(tool) ?? true,
|
|
118
|
+
onError: (error) => options?.onError?.(error),
|
|
119
|
+
},
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
/** The current page tools. */
|
|
124
|
+
get tools() {
|
|
125
|
+
return tools
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -3,8 +3,16 @@ export { createByok } from './create-byok.ts'
|
|
|
3
3
|
export { createRealtimeChat } from './create-realtime-chat.ts'
|
|
4
4
|
export { createMcpAppBridge } from './create-mcp-app-bridge.ts'
|
|
5
5
|
export type { CreateMcpAppBridgeOptions } from './create-mcp-app-bridge.ts'
|
|
6
|
-
export {
|
|
7
|
-
|
|
6
|
+
export {
|
|
7
|
+
createPageWebMCPTools,
|
|
8
|
+
createRegisterWebMCPTools,
|
|
9
|
+
createWebMCPTools,
|
|
10
|
+
} from './create-web-mcp-tools.ts'
|
|
11
|
+
export type {
|
|
12
|
+
CreatePageWebMCPToolsOptions,
|
|
13
|
+
CreateRegisterWebMCPToolsOptions,
|
|
14
|
+
CreateWebMCPToolsOptions,
|
|
15
|
+
} from './create-web-mcp-tools.ts'
|
|
8
16
|
export type {
|
|
9
17
|
DeepPartial,
|
|
10
18
|
CreateChatOptions,
|
|
@@ -97,6 +105,11 @@ export {
|
|
|
97
105
|
PartialJSONParser,
|
|
98
106
|
defaultJSONParser,
|
|
99
107
|
registerWebMCPTools,
|
|
108
|
+
getWebMCPTools,
|
|
109
|
+
subscribeWebMCPTools,
|
|
110
|
+
type GetWebMCPToolsOptions,
|
|
111
|
+
type SubscribeWebMCPToolsOptions,
|
|
112
|
+
type WebMCPPageTool,
|
|
100
113
|
clientTools,
|
|
101
114
|
webSocket,
|
|
102
115
|
fetchServerSentEvents,
|