@genkit-ai/vercel-ai 0.2.0-rc.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/LICENSE +202 -0
- package/README.md +415 -0
- package/lib/client.d.mts +95 -0
- package/lib/client.d.ts +95 -0
- package/lib/client.js +363 -0
- package/lib/client.js.map +1 -0
- package/lib/client.mjs +345 -0
- package/lib/client.mjs.map +1 -0
- package/lib/index.d.mts +3 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +45 -0
- package/lib/index.js.map +1 -0
- package/lib/index.mjs +23 -0
- package/lib/index.mjs.map +1 -0
- package/lib/mapping.d.mts +162 -0
- package/lib/mapping.d.ts +162 -0
- package/lib/mapping.js +280 -0
- package/lib/mapping.js.map +1 -0
- package/lib/mapping.mjs +247 -0
- package/lib/mapping.mjs.map +1 -0
- package/package.json +94 -0
package/lib/client.d.mts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ChatTransport, UIMessage, UIMessageChunk } from 'ai';
|
|
2
|
+
export { ChatTransport, UIMessage, UIMessageChunk } from 'ai';
|
|
3
|
+
export { ResolvedToolResult, RestartInterruptOutput, mapGenkitMessageToUI, messagesFromSnapshot, restartInterrupt } from './mapping.mjs';
|
|
4
|
+
import 'genkit';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Copyright 2026 Google LLC
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for {@link GenkitChatTransport}.
|
|
24
|
+
*/
|
|
25
|
+
interface GenkitChatTransportConfig {
|
|
26
|
+
/** URL of the Genkit agent endpoint (e.g. `/api/weatherAgent`). */
|
|
27
|
+
url: string;
|
|
28
|
+
/**
|
|
29
|
+
* Additional HTTP headers to include in every request.
|
|
30
|
+
* Can be a static object or a function that returns headers (useful for
|
|
31
|
+
* dynamic auth tokens).
|
|
32
|
+
*/
|
|
33
|
+
headers?: Record<string, string> | (() => Record<string, string>);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A Vercel AI SDK `ChatTransport` implementation that communicates with a
|
|
37
|
+
* Genkit agent using Genkit's native streaming protocol via `streamFlow`.
|
|
38
|
+
*
|
|
39
|
+
* Conversation state is **fully server-managed**: the transport sends the
|
|
40
|
+
* `useChat` `id` (the `chatId`) to the agent as its `sessionId`, and the agent
|
|
41
|
+
* persists per-session state in its configured `SessionStore`. Each turn
|
|
42
|
+
* resumes the session's latest snapshot automatically — there is no
|
|
43
|
+
* client-side snapshot bookkeeping to manage or persist.
|
|
44
|
+
*
|
|
45
|
+
* Because the agent server requires session ids to be bare UUIDs, the
|
|
46
|
+
* `chatId` (the `id` you pass to `useChat`) must be a UUID. Generate one with
|
|
47
|
+
* `crypto.randomUUID()`.
|
|
48
|
+
*
|
|
49
|
+
* Interrupt resumes are derived directly from the `messages` the SDK already
|
|
50
|
+
* holds: when the latest turn's assistant message carries resolved tool
|
|
51
|
+
* outputs (e.g. via `addToolResult`), the transport sends them back to the
|
|
52
|
+
* agent as a `resume` payload.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* import { useMemo } from 'react';
|
|
57
|
+
* import { useChat } from '@ai-sdk/react';
|
|
58
|
+
* import { GenkitChatTransport } from '@genkit-ai/vercel-ai/client';
|
|
59
|
+
*
|
|
60
|
+
* const chatId = useMemo(() => crypto.randomUUID(), []);
|
|
61
|
+
* const { messages, sendMessage } = useChat({
|
|
62
|
+
* id: chatId,
|
|
63
|
+
* transport: new GenkitChatTransport({
|
|
64
|
+
* url: '/api/weatherAgent',
|
|
65
|
+
* }),
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare class GenkitChatTransport implements ChatTransport<UIMessage> {
|
|
70
|
+
private readonly url;
|
|
71
|
+
private readonly headersConfig?;
|
|
72
|
+
constructor(config: GenkitChatTransportConfig);
|
|
73
|
+
private resolveHeaders;
|
|
74
|
+
sendMessages({ trigger, chatId, messages, abortSignal, headers, }: {
|
|
75
|
+
trigger: 'submit-message' | 'regenerate-message';
|
|
76
|
+
chatId: string;
|
|
77
|
+
messageId: string | undefined;
|
|
78
|
+
messages: UIMessage[];
|
|
79
|
+
abortSignal: AbortSignal | undefined;
|
|
80
|
+
headers?: Record<string, string> | Headers;
|
|
81
|
+
body?: object;
|
|
82
|
+
metadata?: unknown;
|
|
83
|
+
}): Promise<ReadableStream<UIMessageChunk>>;
|
|
84
|
+
/**
|
|
85
|
+
* Genkit transport does not support stream reconnection.
|
|
86
|
+
*
|
|
87
|
+
* Genkit has a durable streaming feature on the server side; support
|
|
88
|
+
* for reconnection may be added in a future version.
|
|
89
|
+
*
|
|
90
|
+
* @returns Always returns `null`.
|
|
91
|
+
*/
|
|
92
|
+
reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { GenkitChatTransport, type GenkitChatTransportConfig };
|
package/lib/client.d.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ChatTransport, UIMessage, UIMessageChunk } from 'ai';
|
|
2
|
+
export { ChatTransport, UIMessage, UIMessageChunk } from 'ai';
|
|
3
|
+
export { ResolvedToolResult, RestartInterruptOutput, mapGenkitMessageToUI, messagesFromSnapshot, restartInterrupt } from './mapping.js';
|
|
4
|
+
import 'genkit';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Copyright 2026 Google LLC
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for {@link GenkitChatTransport}.
|
|
24
|
+
*/
|
|
25
|
+
interface GenkitChatTransportConfig {
|
|
26
|
+
/** URL of the Genkit agent endpoint (e.g. `/api/weatherAgent`). */
|
|
27
|
+
url: string;
|
|
28
|
+
/**
|
|
29
|
+
* Additional HTTP headers to include in every request.
|
|
30
|
+
* Can be a static object or a function that returns headers (useful for
|
|
31
|
+
* dynamic auth tokens).
|
|
32
|
+
*/
|
|
33
|
+
headers?: Record<string, string> | (() => Record<string, string>);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A Vercel AI SDK `ChatTransport` implementation that communicates with a
|
|
37
|
+
* Genkit agent using Genkit's native streaming protocol via `streamFlow`.
|
|
38
|
+
*
|
|
39
|
+
* Conversation state is **fully server-managed**: the transport sends the
|
|
40
|
+
* `useChat` `id` (the `chatId`) to the agent as its `sessionId`, and the agent
|
|
41
|
+
* persists per-session state in its configured `SessionStore`. Each turn
|
|
42
|
+
* resumes the session's latest snapshot automatically — there is no
|
|
43
|
+
* client-side snapshot bookkeeping to manage or persist.
|
|
44
|
+
*
|
|
45
|
+
* Because the agent server requires session ids to be bare UUIDs, the
|
|
46
|
+
* `chatId` (the `id` you pass to `useChat`) must be a UUID. Generate one with
|
|
47
|
+
* `crypto.randomUUID()`.
|
|
48
|
+
*
|
|
49
|
+
* Interrupt resumes are derived directly from the `messages` the SDK already
|
|
50
|
+
* holds: when the latest turn's assistant message carries resolved tool
|
|
51
|
+
* outputs (e.g. via `addToolResult`), the transport sends them back to the
|
|
52
|
+
* agent as a `resume` payload.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* import { useMemo } from 'react';
|
|
57
|
+
* import { useChat } from '@ai-sdk/react';
|
|
58
|
+
* import { GenkitChatTransport } from '@genkit-ai/vercel-ai/client';
|
|
59
|
+
*
|
|
60
|
+
* const chatId = useMemo(() => crypto.randomUUID(), []);
|
|
61
|
+
* const { messages, sendMessage } = useChat({
|
|
62
|
+
* id: chatId,
|
|
63
|
+
* transport: new GenkitChatTransport({
|
|
64
|
+
* url: '/api/weatherAgent',
|
|
65
|
+
* }),
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare class GenkitChatTransport implements ChatTransport<UIMessage> {
|
|
70
|
+
private readonly url;
|
|
71
|
+
private readonly headersConfig?;
|
|
72
|
+
constructor(config: GenkitChatTransportConfig);
|
|
73
|
+
private resolveHeaders;
|
|
74
|
+
sendMessages({ trigger, chatId, messages, abortSignal, headers, }: {
|
|
75
|
+
trigger: 'submit-message' | 'regenerate-message';
|
|
76
|
+
chatId: string;
|
|
77
|
+
messageId: string | undefined;
|
|
78
|
+
messages: UIMessage[];
|
|
79
|
+
abortSignal: AbortSignal | undefined;
|
|
80
|
+
headers?: Record<string, string> | Headers;
|
|
81
|
+
body?: object;
|
|
82
|
+
metadata?: unknown;
|
|
83
|
+
}): Promise<ReadableStream<UIMessageChunk>>;
|
|
84
|
+
/**
|
|
85
|
+
* Genkit transport does not support stream reconnection.
|
|
86
|
+
*
|
|
87
|
+
* Genkit has a durable streaming feature on the server side; support
|
|
88
|
+
* for reconnection may be added in a future version.
|
|
89
|
+
*
|
|
90
|
+
* @returns Always returns `null`.
|
|
91
|
+
*/
|
|
92
|
+
reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { GenkitChatTransport, type GenkitChatTransportConfig };
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
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
|
+
var client_exports = {};
|
|
20
|
+
__export(client_exports, {
|
|
21
|
+
GenkitChatTransport: () => GenkitChatTransport,
|
|
22
|
+
mapGenkitMessageToUI: () => import_mapping2.mapGenkitMessageToUI,
|
|
23
|
+
messagesFromSnapshot: () => import_mapping2.messagesFromSnapshot,
|
|
24
|
+
restartInterrupt: () => import_mapping2.restartInterrupt
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(client_exports);
|
|
27
|
+
var import_client = require("genkit/beta/client");
|
|
28
|
+
var import_mapping = require("./mapping.js");
|
|
29
|
+
var import_mapping2 = require("./mapping.js");
|
|
30
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
31
|
+
function errorTextFromUnknown(err) {
|
|
32
|
+
if (err instanceof Error) {
|
|
33
|
+
return err.message || "Agent execution failed";
|
|
34
|
+
}
|
|
35
|
+
if (typeof err === "string") {
|
|
36
|
+
return err || "Agent execution failed";
|
|
37
|
+
}
|
|
38
|
+
if (err === void 0 || err === null) {
|
|
39
|
+
return "Agent execution failed";
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
return JSON.stringify(err);
|
|
43
|
+
} catch {
|
|
44
|
+
return String(err);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function errorStream(errorText) {
|
|
48
|
+
return new ReadableStream({
|
|
49
|
+
start(controller) {
|
|
50
|
+
controller.enqueue({
|
|
51
|
+
type: "start",
|
|
52
|
+
messageId: `msg-${crypto.randomUUID()}`
|
|
53
|
+
});
|
|
54
|
+
controller.enqueue({ type: "error", errorText });
|
|
55
|
+
controller.enqueue({ type: "finish" });
|
|
56
|
+
controller.close();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
class GenkitChatTransport {
|
|
61
|
+
url;
|
|
62
|
+
headersConfig;
|
|
63
|
+
constructor(config) {
|
|
64
|
+
this.url = config.url;
|
|
65
|
+
this.headersConfig = config.headers;
|
|
66
|
+
}
|
|
67
|
+
resolveHeaders(extra) {
|
|
68
|
+
const base = typeof this.headersConfig === "function" ? this.headersConfig() : this.headersConfig;
|
|
69
|
+
let extraRecord;
|
|
70
|
+
if (extra instanceof Headers) {
|
|
71
|
+
extraRecord = {};
|
|
72
|
+
extra.forEach((value, key) => {
|
|
73
|
+
extraRecord[key] = value;
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
extraRecord = extra;
|
|
77
|
+
}
|
|
78
|
+
if (!base && !extraRecord) return void 0;
|
|
79
|
+
return { ...base, ...extraRecord };
|
|
80
|
+
}
|
|
81
|
+
// The `trigger` parameter is either 'submit-message' (a new user turn) or
|
|
82
|
+
// 'regenerate-message' (re-run the last assistant response). Because state
|
|
83
|
+
// is server-managed by `sessionId`, regeneration is treated as a fresh turn
|
|
84
|
+
// from the current session state (there is no client-side snapshot pointer
|
|
85
|
+
// to rewind to).
|
|
86
|
+
async sendMessages({
|
|
87
|
+
trigger,
|
|
88
|
+
chatId,
|
|
89
|
+
messages,
|
|
90
|
+
abortSignal,
|
|
91
|
+
headers
|
|
92
|
+
}) {
|
|
93
|
+
if (!UUID_PATTERN.test(chatId)) {
|
|
94
|
+
return errorStream(
|
|
95
|
+
`Invalid chatId '${chatId}': the useChat 'id' is used as the Genkit sessionId and must be a UUID. Generate one with crypto.randomUUID().`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const isRegenerate = trigger === "regenerate-message";
|
|
99
|
+
const resolvedTools = isRegenerate ? [] : (0, import_mapping.currentTurnResolvedTools)(messages);
|
|
100
|
+
const isResume = resolvedTools.length > 0;
|
|
101
|
+
const init = { sessionId: chatId };
|
|
102
|
+
let agentInput;
|
|
103
|
+
const respondedInterruptIds = /* @__PURE__ */ new Set();
|
|
104
|
+
if (isResume) {
|
|
105
|
+
const respond = [];
|
|
106
|
+
const restart = [];
|
|
107
|
+
for (const tr of resolvedTools) {
|
|
108
|
+
const asRestart = (0, import_mapping.asRestartInterrupt)(tr.result);
|
|
109
|
+
if (asRestart) {
|
|
110
|
+
restart.push({
|
|
111
|
+
toolRequest: {
|
|
112
|
+
name: tr.toolName,
|
|
113
|
+
ref: tr.toolCallId,
|
|
114
|
+
input: tr.input
|
|
115
|
+
},
|
|
116
|
+
metadata: { resumed: asRestart.metadata ?? true }
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
respondedInterruptIds.add(tr.toolCallId);
|
|
120
|
+
respond.push({
|
|
121
|
+
toolResponse: {
|
|
122
|
+
name: tr.toolName,
|
|
123
|
+
ref: tr.toolCallId,
|
|
124
|
+
output: tr.result
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
agentInput = {
|
|
130
|
+
resume: {
|
|
131
|
+
...respond.length > 0 && { respond },
|
|
132
|
+
...restart.length > 0 && { restart }
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
} else {
|
|
136
|
+
const lastUserMsg = (0, import_mapping.findLastNonEmptyUserMessage)(messages);
|
|
137
|
+
if (!lastUserMsg) {
|
|
138
|
+
return errorStream("No user message found");
|
|
139
|
+
}
|
|
140
|
+
const genkitMsg = (0, import_mapping.mapUIMessageToGenkit)(lastUserMsg);
|
|
141
|
+
agentInput = { message: genkitMsg };
|
|
142
|
+
}
|
|
143
|
+
const response = (0, import_client.streamFlow)({
|
|
144
|
+
url: this.url,
|
|
145
|
+
input: agentInput,
|
|
146
|
+
init,
|
|
147
|
+
headers: this.resolveHeaders(headers),
|
|
148
|
+
abortSignal
|
|
149
|
+
});
|
|
150
|
+
let aborted = false;
|
|
151
|
+
return new ReadableStream({
|
|
152
|
+
start: async (controller) => {
|
|
153
|
+
const onAbort = () => {
|
|
154
|
+
aborted = true;
|
|
155
|
+
};
|
|
156
|
+
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
157
|
+
let started = false;
|
|
158
|
+
let textBlockId = null;
|
|
159
|
+
let reasoningBlockId = null;
|
|
160
|
+
let inStep = false;
|
|
161
|
+
let customState;
|
|
162
|
+
const emittedToolInputs = /* @__PURE__ */ new Set();
|
|
163
|
+
const pendingRefByToolName = /* @__PURE__ */ new Map();
|
|
164
|
+
const correlateRequestId = (name) => {
|
|
165
|
+
const id = crypto.randomUUID();
|
|
166
|
+
const queue = pendingRefByToolName.get(name) ?? [];
|
|
167
|
+
queue.push(id);
|
|
168
|
+
pendingRefByToolName.set(name, queue);
|
|
169
|
+
return id;
|
|
170
|
+
};
|
|
171
|
+
const correlateResponseId = (name) => {
|
|
172
|
+
const queue = pendingRefByToolName.get(name);
|
|
173
|
+
if (queue && queue.length > 0) {
|
|
174
|
+
return queue.shift();
|
|
175
|
+
}
|
|
176
|
+
return crypto.randomUUID();
|
|
177
|
+
};
|
|
178
|
+
const enqueue = (chunk) => {
|
|
179
|
+
try {
|
|
180
|
+
controller.enqueue(chunk);
|
|
181
|
+
} catch {
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const ensureStarted = () => {
|
|
185
|
+
if (!started) {
|
|
186
|
+
enqueue({
|
|
187
|
+
type: "start",
|
|
188
|
+
messageId: `msg-${crypto.randomUUID()}`
|
|
189
|
+
});
|
|
190
|
+
started = true;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
const ensureStep = () => {
|
|
194
|
+
if (!inStep) {
|
|
195
|
+
enqueue({ type: "start-step" });
|
|
196
|
+
inStep = true;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
const closeTextBlock = () => {
|
|
200
|
+
if (textBlockId) {
|
|
201
|
+
enqueue({ type: "text-end", id: textBlockId });
|
|
202
|
+
textBlockId = null;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const closeReasoningBlock = () => {
|
|
206
|
+
if (reasoningBlockId) {
|
|
207
|
+
enqueue({ type: "reasoning-end", id: reasoningBlockId });
|
|
208
|
+
reasoningBlockId = null;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const closeStep = () => {
|
|
212
|
+
if (inStep) {
|
|
213
|
+
enqueue({ type: "finish-step" });
|
|
214
|
+
inStep = false;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
try {
|
|
218
|
+
for await (const chunk of response.stream) {
|
|
219
|
+
if (aborted) break;
|
|
220
|
+
if (chunk?.customPatch) {
|
|
221
|
+
customState = (0, import_client.applyPatch)(customState, chunk.customPatch);
|
|
222
|
+
ensureStarted();
|
|
223
|
+
enqueue({
|
|
224
|
+
type: "data-custom",
|
|
225
|
+
data: customState,
|
|
226
|
+
transient: true
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const mc = chunk?.modelChunk;
|
|
230
|
+
if (!mc?.content) continue;
|
|
231
|
+
ensureStarted();
|
|
232
|
+
for (const part of mc.content) {
|
|
233
|
+
if (typeof part.reasoning === "string" && part.reasoning !== "") {
|
|
234
|
+
ensureStep();
|
|
235
|
+
if (!reasoningBlockId) {
|
|
236
|
+
reasoningBlockId = `reasoning-${crypto.randomUUID()}`;
|
|
237
|
+
enqueue({ type: "reasoning-start", id: reasoningBlockId });
|
|
238
|
+
}
|
|
239
|
+
enqueue({
|
|
240
|
+
type: "reasoning-delta",
|
|
241
|
+
id: reasoningBlockId,
|
|
242
|
+
delta: part.reasoning
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
if (part.text !== void 0 && part.text !== "") {
|
|
246
|
+
closeReasoningBlock();
|
|
247
|
+
ensureStep();
|
|
248
|
+
if (!textBlockId) {
|
|
249
|
+
textBlockId = `text-${crypto.randomUUID()}`;
|
|
250
|
+
enqueue({ type: "text-start", id: textBlockId });
|
|
251
|
+
}
|
|
252
|
+
enqueue({
|
|
253
|
+
type: "text-delta",
|
|
254
|
+
id: textBlockId,
|
|
255
|
+
delta: part.text
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (part.toolRequest) {
|
|
259
|
+
const tr = part.toolRequest;
|
|
260
|
+
const toolCallId = tr.ref ?? correlateRequestId(tr.name);
|
|
261
|
+
if (!emittedToolInputs.has(toolCallId)) {
|
|
262
|
+
emittedToolInputs.add(toolCallId);
|
|
263
|
+
closeReasoningBlock();
|
|
264
|
+
closeTextBlock();
|
|
265
|
+
ensureStep();
|
|
266
|
+
enqueue({
|
|
267
|
+
type: "tool-input-start",
|
|
268
|
+
toolCallId,
|
|
269
|
+
toolName: tr.name
|
|
270
|
+
});
|
|
271
|
+
enqueue({
|
|
272
|
+
type: "tool-input-available",
|
|
273
|
+
toolCallId,
|
|
274
|
+
toolName: tr.name,
|
|
275
|
+
input: tr.input
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (part.toolResponse) {
|
|
280
|
+
const tr = part.toolResponse;
|
|
281
|
+
const toolCallId = tr.ref ?? correlateResponseId(tr.name);
|
|
282
|
+
if (!respondedInterruptIds.has(toolCallId)) {
|
|
283
|
+
enqueue({
|
|
284
|
+
type: "tool-output-available",
|
|
285
|
+
toolCallId,
|
|
286
|
+
output: tr.output
|
|
287
|
+
});
|
|
288
|
+
closeStep();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (chunk?.turnEnd) {
|
|
293
|
+
closeReasoningBlock();
|
|
294
|
+
closeTextBlock();
|
|
295
|
+
closeStep();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (aborted) {
|
|
299
|
+
ensureStarted();
|
|
300
|
+
closeReasoningBlock();
|
|
301
|
+
closeTextBlock();
|
|
302
|
+
closeStep();
|
|
303
|
+
enqueue({ type: "abort", reason: "Request was aborted" });
|
|
304
|
+
enqueue({ type: "finish" });
|
|
305
|
+
try {
|
|
306
|
+
controller.close();
|
|
307
|
+
} catch {
|
|
308
|
+
}
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
await response.output;
|
|
312
|
+
} catch (err) {
|
|
313
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
314
|
+
ensureStarted();
|
|
315
|
+
closeReasoningBlock();
|
|
316
|
+
closeTextBlock();
|
|
317
|
+
closeStep();
|
|
318
|
+
enqueue({ type: "abort", reason: "Request was aborted" });
|
|
319
|
+
} else {
|
|
320
|
+
ensureStarted();
|
|
321
|
+
enqueue({
|
|
322
|
+
type: "error",
|
|
323
|
+
errorText: errorTextFromUnknown(err)
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
} finally {
|
|
327
|
+
closeReasoningBlock();
|
|
328
|
+
closeTextBlock();
|
|
329
|
+
closeStep();
|
|
330
|
+
ensureStarted();
|
|
331
|
+
enqueue({ type: "finish" });
|
|
332
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
333
|
+
try {
|
|
334
|
+
controller.close();
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
cancel: () => {
|
|
340
|
+
aborted = true;
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Genkit transport does not support stream reconnection.
|
|
346
|
+
*
|
|
347
|
+
* Genkit has a durable streaming feature on the server side; support
|
|
348
|
+
* for reconnection may be added in a future version.
|
|
349
|
+
*
|
|
350
|
+
* @returns Always returns `null`.
|
|
351
|
+
*/
|
|
352
|
+
async reconnectToStream() {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
357
|
+
0 && (module.exports = {
|
|
358
|
+
GenkitChatTransport,
|
|
359
|
+
mapGenkitMessageToUI,
|
|
360
|
+
messagesFromSnapshot,
|
|
361
|
+
restartInterrupt
|
|
362
|
+
});
|
|
363
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["/**\n * Copyright 2026 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ChatTransport, UIMessage, UIMessageChunk } from 'ai';\n// Type-only imports are erased at compile time, so importing from `genkit`\n// keeps this module browser-safe (no Node-only runtime code is pulled in)\n// while staying in sync with the canonical agent protocol types.\nimport type { AgentOutput, AgentStreamChunk } from 'genkit/beta';\nimport { applyPatch, streamFlow } from 'genkit/beta/client';\n\nimport {\n asRestartInterrupt,\n currentTurnResolvedTools,\n findLastNonEmptyUserMessage,\n mapUIMessageToGenkit,\n} from './mapping.js';\n\nexport {\n mapGenkitMessageToUI,\n messagesFromSnapshot,\n restartInterrupt,\n} from './mapping.js';\nexport type { ResolvedToolResult, RestartInterruptOutput } from './mapping.js';\n\nexport type { ChatTransport, UIMessage, UIMessageChunk };\n\n// A bare RFC-4122 UUID, used to validate `chatId` (which doubles as the Genkit\n// `sessionId`). The agent server requires session ids to be bare UUIDs, so we\n// validate client-side too for a clearer, earlier error.\nconst UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Derives a human-readable error message from an unknown thrown value,\n * preserving as much context as possible.\n *\n * `streamFlow` throws `Error`s whose `.message` already embeds the HTTP status\n * and any Genkit error status/message/details, so those are returned verbatim.\n * Non-Error throwables are stringified (JSON when possible) instead of being\n * collapsed to a generic label, so detail isn't silently lost.\n */\nfunction errorTextFromUnknown(err: unknown): string {\n if (err instanceof Error) {\n return err.message || 'Agent execution failed';\n }\n if (typeof err === 'string') {\n return err || 'Agent execution failed';\n }\n if (err === undefined || err === null) {\n return 'Agent execution failed';\n }\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\n/**\n * Builds a `ReadableStream` that emits a single error inside the standard\n * `start`/`error`/`finish` envelope, matching the shape of a normal stream.\n */\nfunction errorStream(errorText: string): ReadableStream<UIMessageChunk> {\n return new ReadableStream<UIMessageChunk>({\n start(controller) {\n controller.enqueue({\n type: 'start',\n messageId: `msg-${crypto.randomUUID()}`,\n });\n controller.enqueue({ type: 'error', errorText });\n controller.enqueue({ type: 'finish' });\n controller.close();\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// GenkitChatTransport\n// ---------------------------------------------------------------------------\n\n/**\n * Configuration for {@link GenkitChatTransport}.\n */\nexport interface GenkitChatTransportConfig {\n /** URL of the Genkit agent endpoint (e.g. `/api/weatherAgent`). */\n url: string;\n\n /**\n * Additional HTTP headers to include in every request.\n * Can be a static object or a function that returns headers (useful for\n * dynamic auth tokens).\n */\n headers?: Record<string, string> | (() => Record<string, string>);\n}\n\n/**\n * A Vercel AI SDK `ChatTransport` implementation that communicates with a\n * Genkit agent using Genkit's native streaming protocol via `streamFlow`.\n *\n * Conversation state is **fully server-managed**: the transport sends the\n * `useChat` `id` (the `chatId`) to the agent as its `sessionId`, and the agent\n * persists per-session state in its configured `SessionStore`. Each turn\n * resumes the session's latest snapshot automatically — there is no\n * client-side snapshot bookkeeping to manage or persist.\n *\n * Because the agent server requires session ids to be bare UUIDs, the\n * `chatId` (the `id` you pass to `useChat`) must be a UUID. Generate one with\n * `crypto.randomUUID()`.\n *\n * Interrupt resumes are derived directly from the `messages` the SDK already\n * holds: when the latest turn's assistant message carries resolved tool\n * outputs (e.g. via `addToolResult`), the transport sends them back to the\n * agent as a `resume` payload.\n *\n * @example\n * ```tsx\n * import { useMemo } from 'react';\n * import { useChat } from '@ai-sdk/react';\n * import { GenkitChatTransport } from '@genkit-ai/vercel-ai/client';\n *\n * const chatId = useMemo(() => crypto.randomUUID(), []);\n * const { messages, sendMessage } = useChat({\n * id: chatId,\n * transport: new GenkitChatTransport({\n * url: '/api/weatherAgent',\n * }),\n * });\n * ```\n */\nexport class GenkitChatTransport implements ChatTransport<UIMessage> {\n private readonly url: string;\n private readonly headersConfig?:\n | Record<string, string>\n | (() => Record<string, string>);\n\n constructor(config: GenkitChatTransportConfig) {\n this.url = config.url;\n this.headersConfig = config.headers;\n }\n\n private resolveHeaders(\n extra?: Record<string, string> | Headers\n ): Record<string, string> | undefined {\n const base =\n typeof this.headersConfig === 'function'\n ? this.headersConfig()\n : this.headersConfig;\n // Normalize Headers objects to plain records.\n let extraRecord: Record<string, string> | undefined;\n if (extra instanceof Headers) {\n extraRecord = {};\n extra.forEach((value, key) => {\n extraRecord![key] = value;\n });\n } else {\n extraRecord = extra;\n }\n if (!base && !extraRecord) return undefined;\n return { ...base, ...extraRecord };\n }\n\n // The `trigger` parameter is either 'submit-message' (a new user turn) or\n // 'regenerate-message' (re-run the last assistant response). Because state\n // is server-managed by `sessionId`, regeneration is treated as a fresh turn\n // from the current session state (there is no client-side snapshot pointer\n // to rewind to).\n async sendMessages({\n trigger,\n chatId,\n messages,\n abortSignal,\n headers,\n }: {\n trigger: 'submit-message' | 'regenerate-message';\n chatId: string;\n messageId: string | undefined;\n messages: UIMessage[];\n abortSignal: AbortSignal | undefined;\n headers?: Record<string, string> | Headers;\n body?: object;\n metadata?: unknown;\n }): Promise<ReadableStream<UIMessageChunk>> {\n // `chatId` doubles as the Genkit session id and must be a bare UUID.\n if (!UUID_PATTERN.test(chatId)) {\n return errorStream(\n `Invalid chatId '${chatId}': the useChat 'id' is used as the Genkit ` +\n `sessionId and must be a UUID. Generate one with crypto.randomUUID().`\n );\n }\n\n const isRegenerate = trigger === 'regenerate-message';\n\n // Detect an interrupt resume from the message history alone: the current\n // turn's assistant message(s) carry resolved tool outputs that have not\n // been followed by a new user message. Regeneration never resumes an\n // interrupt — it replays from the current session state.\n const resolvedTools = isRegenerate\n ? []\n : currentTurnResolvedTools(messages);\n const isResume = resolvedTools.length > 0;\n\n // The session id is always sent so the agent resumes (or seeds) the\n // server-managed session for this chat.\n const init: Record<string, unknown> = { sessionId: chatId };\n let agentInput: Record<string, unknown>;\n\n // Tool call ids that were resolved with a user-supplied *response* (not a\n // restart). Their outputs are already on the client, so the transport\n // suppresses re-emitting them. Restarted tools, by contrast, re-execute\n // server-side and produce a *fresh* output that the client must receive.\n const respondedInterruptIds = new Set<string>();\n\n if (isResume) {\n // Split resolutions into restarts (re-run the tool) and responds\n // (user-supplied output). A single resume turn can carry both.\n const respond: Array<Record<string, unknown>> = [];\n const restart: Array<Record<string, unknown>> = [];\n for (const tr of resolvedTools) {\n const asRestart = asRestartInterrupt(tr.result);\n if (asRestart) {\n // A restart re-runs the tool with the *original* input (the server\n // validates it matches the interrupted request exactly) and passes\n // any metadata through as the tool's `resumed` value.\n restart.push({\n toolRequest: {\n name: tr.toolName,\n ref: tr.toolCallId,\n input: tr.input,\n },\n metadata: { resumed: asRestart.metadata ?? true },\n });\n } else {\n respondedInterruptIds.add(tr.toolCallId);\n respond.push({\n toolResponse: {\n name: tr.toolName,\n ref: tr.toolCallId,\n output: tr.result,\n },\n });\n }\n }\n agentInput = {\n resume: {\n ...(respond.length > 0 && { respond }),\n ...(restart.length > 0 && { restart }),\n },\n };\n } else {\n const lastUserMsg = findLastNonEmptyUserMessage(messages);\n if (!lastUserMsg) {\n return errorStream('No user message found');\n }\n\n const genkitMsg = mapUIMessageToGenkit(lastUserMsg);\n agentInput = { message: genkitMsg };\n }\n\n // Call streamFlow — Genkit's native streaming protocol.\n const response = streamFlow<AgentOutput, AgentStreamChunk>({\n url: this.url,\n input: agentInput,\n init,\n headers: this.resolveHeaders(headers),\n abortSignal,\n });\n\n // Track whether the stream was aborted so we can emit a clean abort chunk.\n let aborted = false;\n\n return new ReadableStream<UIMessageChunk>({\n start: async (controller) => {\n // Listen for abort to break out of the streaming loop cleanly.\n const onAbort = () => {\n aborted = true;\n };\n abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n // Streaming state machine.\n let started = false;\n let textBlockId: string | null = null;\n let reasoningBlockId: string | null = null;\n let inStep = false;\n // Locally tracked agent custom state, kept live by applying each\n // streamed RFC 6902 JSON Patch (`chunk.customPatch`). The first patch\n // of a turn is a whole-document replace that re-bases us onto the\n // server's current baseline.\n let customState: unknown;\n const emittedToolInputs = new Set<string>();\n\n // Deterministic fallback for tool calls that arrive without a `ref`.\n // The model may omit refs, in which case the request and its matching\n // response must still share the same `toolCallId`.\n //\n // We pair each ref-less response with the *oldest* unmatched ref-less\n // request for the same tool name (FIFO by arrival order). Allocating a\n // fresh id per request — rather than reusing one id per tool name —\n // means two ref-less calls to the *same* tool in one turn don't share\n // an id and cross-wire each other's request/response. (In practice\n // Genkit tool requests carry refs, so this is a safety net.)\n const pendingRefByToolName = new Map<string, string[]>();\n const correlateRequestId = (name: string): string => {\n const id = crypto.randomUUID();\n const queue = pendingRefByToolName.get(name) ?? [];\n queue.push(id);\n pendingRefByToolName.set(name, queue);\n return id;\n };\n const correlateResponseId = (name: string): string => {\n const queue = pendingRefByToolName.get(name);\n if (queue && queue.length > 0) {\n return queue.shift()!;\n }\n // No matching request seen (shouldn't happen) — mint a new id.\n return crypto.randomUUID();\n };\n\n const enqueue = (chunk: UIMessageChunk) => {\n try {\n controller.enqueue(chunk);\n } catch {\n // Controller already closed (e.g. consumer cancelled).\n }\n };\n\n const ensureStarted = () => {\n if (!started) {\n enqueue({\n type: 'start',\n messageId: `msg-${crypto.randomUUID()}`,\n });\n started = true;\n }\n };\n\n const ensureStep = () => {\n if (!inStep) {\n enqueue({ type: 'start-step' });\n inStep = true;\n }\n };\n\n const closeTextBlock = () => {\n if (textBlockId) {\n enqueue({ type: 'text-end', id: textBlockId });\n textBlockId = null;\n }\n };\n\n const closeReasoningBlock = () => {\n if (reasoningBlockId) {\n enqueue({ type: 'reasoning-end', id: reasoningBlockId });\n reasoningBlockId = null;\n }\n };\n\n const closeStep = () => {\n if (inStep) {\n enqueue({ type: 'finish-step' });\n inStep = false;\n }\n };\n\n try {\n for await (const chunk of response.stream) {\n // If aborted during iteration, break out cleanly.\n if (aborted) break;\n\n // Agent custom-state update. The runtime auto-emits a `customPatch`\n // (RFC 6902 JSON Patch) whenever the session's custom state\n // mutates. Apply it to our locally tracked copy and surface the\n // full, post-patch state as a transient `data-custom` UI chunk so\n // the React app can render live progress. Must run BEFORE the\n // `modelChunk` early-continue below, since custom-only chunks carry\n // no `modelChunk`.\n if (chunk?.customPatch) {\n customState = applyPatch(customState, chunk.customPatch);\n ensureStarted();\n enqueue({\n type: 'data-custom',\n data: customState,\n transient: true,\n } as UIMessageChunk);\n }\n\n const mc = chunk?.modelChunk;\n if (!mc?.content) continue;\n\n ensureStarted();\n\n for (const part of mc.content) {\n // Reasoning delta (model's \"thinking\"). Genkit reasoning parts\n // use the `reasoning` field; map them to AI SDK reasoning chunks\n // so they can be surfaced separately from the final answer.\n if (typeof part.reasoning === 'string' && part.reasoning !== '') {\n ensureStep();\n if (!reasoningBlockId) {\n reasoningBlockId = `reasoning-${crypto.randomUUID()}`;\n enqueue({ type: 'reasoning-start', id: reasoningBlockId });\n }\n enqueue({\n type: 'reasoning-delta',\n id: reasoningBlockId,\n delta: part.reasoning,\n });\n }\n\n // Text delta\n if (part.text !== undefined && part.text !== '') {\n // Reasoning precedes the answer; close any open reasoning\n // block before streaming visible text.\n closeReasoningBlock();\n ensureStep();\n if (!textBlockId) {\n textBlockId = `text-${crypto.randomUUID()}`;\n enqueue({ type: 'text-start', id: textBlockId });\n }\n enqueue({\n type: 'text-delta',\n id: textBlockId,\n delta: part.text,\n });\n }\n\n // Tool request (tool call from model)\n if (part.toolRequest) {\n const tr = part.toolRequest;\n const toolCallId = tr.ref ?? correlateRequestId(tr.name);\n if (!emittedToolInputs.has(toolCallId)) {\n emittedToolInputs.add(toolCallId);\n closeReasoningBlock();\n closeTextBlock();\n ensureStep();\n enqueue({\n type: 'tool-input-start',\n toolCallId,\n toolName: tr.name,\n });\n enqueue({\n type: 'tool-input-available',\n toolCallId,\n toolName: tr.name,\n input: tr.input,\n });\n }\n }\n\n // Tool response (tool executed by agent)\n if (part.toolResponse) {\n const tr = part.toolResponse;\n const toolCallId = tr.ref ?? correlateResponseId(tr.name);\n\n // Skip interrupt responses the client already supplied — it\n // has the result and re-emitting would confuse the UI SDK.\n // Restarted tools are NOT skipped: they re-execute server-side\n // and produce a fresh output the client must receive.\n if (!respondedInterruptIds.has(toolCallId)) {\n enqueue({\n type: 'tool-output-available',\n toolCallId,\n output: tr.output,\n });\n closeStep();\n }\n }\n }\n\n // Handle turn end signals.\n if (chunk?.turnEnd) {\n closeReasoningBlock();\n closeTextBlock();\n closeStep();\n }\n }\n\n // If aborted, emit an abort chunk and skip output processing.\n if (aborted) {\n ensureStarted();\n closeReasoningBlock();\n closeTextBlock();\n closeStep();\n enqueue({ type: 'abort', reason: 'Request was aborted' });\n enqueue({ type: 'finish' });\n try {\n controller.close();\n } catch {\n /* already closed */\n }\n return;\n }\n\n // Wait for final output (drains the stream / surfaces server errors).\n await response.output;\n } catch (err: unknown) {\n // If the error is an AbortError, treat it as an abort, not an error.\n if (err instanceof DOMException && err.name === 'AbortError') {\n ensureStarted();\n closeReasoningBlock();\n closeTextBlock();\n closeStep();\n enqueue({ type: 'abort', reason: 'Request was aborted' });\n } else {\n ensureStarted();\n // `streamFlow` throws plain `Error`s whose message already embeds\n // the HTTP status and any Genkit error status/message/details\n // (e.g. `\"Server returned: 500: ...\"` or `\"<status>: <message>\\n\n // <details>\"`), so `err.message` preserves that context. For\n // non-Error throwables, stringify rather than collapsing to a\n // generic label so detail isn't lost.\n enqueue({\n type: 'error',\n errorText: errorTextFromUnknown(err),\n });\n }\n } finally {\n closeReasoningBlock();\n closeTextBlock();\n closeStep();\n ensureStarted();\n enqueue({ type: 'finish' });\n abortSignal?.removeEventListener('abort', onAbort);\n try {\n controller.close();\n } catch {\n /* already closed */\n }\n }\n },\n\n cancel: () => {\n // The ReadableStream consumer cancelled (e.g. useChat unmounted).\n // The abort signal (if provided) will handle the fetch cancellation.\n aborted = true;\n },\n });\n }\n\n /**\n * Genkit transport does not support stream reconnection.\n *\n * Genkit has a durable streaming feature on the server side; support\n * for reconnection may be added in a future version.\n *\n * @returns Always returns `null`.\n */\n async reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null> {\n return null;\n }\n}\n"],"mappings":"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","names":["import_mapping"]}
|