content-agent 0.2.0 → 0.4.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/README.md +38 -0
- package/dist/index.d.ts +500 -52
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +240 -78
- package/dist/index.js.map +1 -1
- package/package.json +9 -6
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/generated/openapi.ts","../src/types.ts","../src/sanity-agent-language-model.ts","../src/sanity-agent-provider.ts","../src/utils.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/generated/openapi.ts","../src/types.ts","../src/sanity-agent-language-model.ts","../src/sanity-agent-provider.ts","../src/utils.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { pickBy, isString } from "es-toolkit";
|
|
1
|
+
import { pickBy, isString, groupBy } from "es-toolkit";
|
|
2
|
+
import { HEADLESS_ERROR_CODES } from "@sanity/agent-types";
|
|
2
3
|
function buildHeaders(configHeaders, additionalHeaders) {
|
|
3
4
|
return pickBy(
|
|
4
5
|
{
|
|
@@ -15,10 +16,34 @@ function buildApiUrl(baseURL, apiVersion, endpoint) {
|
|
|
15
16
|
class SanityAgentError extends Error {
|
|
16
17
|
status;
|
|
17
18
|
isRetryable;
|
|
19
|
+
body;
|
|
18
20
|
constructor(status, message) {
|
|
19
|
-
super(`Sanity Agent API error: ${status} ${message}`), this.name = "SanityAgentError", this.status = status, this.isRetryable = status >= 500;
|
|
21
|
+
super(`Sanity Agent API error: ${status} ${message}`), this.name = "SanityAgentError", this.status = status, this.isRetryable = status >= 500, this.body = SanityAgentError.parseBody(message);
|
|
22
|
+
}
|
|
23
|
+
static parseBody(message) {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(message);
|
|
26
|
+
} catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const GENERIC_ERROR_MESSAGE = "Sorry, something went wrong. Please try again.";
|
|
32
|
+
function classifyAgentError(error) {
|
|
33
|
+
if (!(error instanceof SanityAgentError) || error.status !== 400)
|
|
34
|
+
return { type: "unknown" };
|
|
35
|
+
switch (error.body.code) {
|
|
36
|
+
case HEADLESS_ERROR_CODES.NO_COMPATIBLE_APPLICATIONS:
|
|
37
|
+
return { type: "no_applications" };
|
|
38
|
+
case HEADLESS_ERROR_CODES.APPLICATION_NOT_FOUND:
|
|
39
|
+
return { type: "application_not_found" };
|
|
40
|
+
default:
|
|
41
|
+
return { type: "unknown" };
|
|
20
42
|
}
|
|
21
43
|
}
|
|
44
|
+
function getAgentErrorMessage(error) {
|
|
45
|
+
return error instanceof SanityAgentError && error.body.message ? error.body.message : GENERIC_ERROR_MESSAGE;
|
|
46
|
+
}
|
|
22
47
|
async function fetchApi(options) {
|
|
23
48
|
const response = await (options.fetch ?? globalThis.fetch)(options.url, {
|
|
24
49
|
method: "POST",
|
|
@@ -38,71 +63,116 @@ function extractTextFromParts(content) {
|
|
|
38
63
|
).map((part) => part.text).join(`
|
|
39
64
|
`);
|
|
40
65
|
}
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
function parseStreamLine(line) {
|
|
54
|
-
const trimmed = line.trim();
|
|
55
|
-
if (!trimmed) return null;
|
|
56
|
-
if (trimmed.startsWith("0:"))
|
|
57
|
-
try {
|
|
58
|
-
const text = JSON.parse(trimmed.slice(2));
|
|
59
|
-
if (typeof text == "string")
|
|
60
|
-
return { type: "text-delta", textDelta: text };
|
|
61
|
-
} catch {
|
|
66
|
+
function createEmptyUsage() {
|
|
67
|
+
return {
|
|
68
|
+
inputTokens: {
|
|
69
|
+
total: 0,
|
|
70
|
+
noCache: void 0,
|
|
71
|
+
cacheRead: void 0,
|
|
72
|
+
cacheWrite: void 0
|
|
73
|
+
},
|
|
74
|
+
outputTokens: {
|
|
75
|
+
total: 0,
|
|
76
|
+
text: void 0,
|
|
77
|
+
reasoning: void 0
|
|
62
78
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function mapFinishReason(reason) {
|
|
82
|
+
return { unified: (() => {
|
|
83
|
+
switch (reason) {
|
|
84
|
+
case "stop":
|
|
85
|
+
case "length":
|
|
86
|
+
case "content-filter":
|
|
87
|
+
case "tool-calls":
|
|
88
|
+
case "error":
|
|
89
|
+
return reason;
|
|
90
|
+
default:
|
|
91
|
+
return "other";
|
|
69
92
|
}
|
|
70
|
-
|
|
93
|
+
})(), raw: reason };
|
|
71
94
|
}
|
|
72
|
-
function
|
|
95
|
+
function parseStreamLine(line, textContentId) {
|
|
73
96
|
const trimmed = line.trim();
|
|
74
|
-
if (!trimmed.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
if (!trimmed || trimmed.length < 2 || trimmed[1] !== ":") return null;
|
|
98
|
+
const prefix = trimmed[0], payload = trimmed.slice(2);
|
|
99
|
+
switch (prefix) {
|
|
100
|
+
case "0": {
|
|
101
|
+
try {
|
|
102
|
+
const text = JSON.parse(payload);
|
|
103
|
+
if (typeof text == "string")
|
|
104
|
+
return { kind: "part", part: { type: "text-delta", id: textContentId, delta: text } };
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
case "3":
|
|
110
|
+
try {
|
|
111
|
+
const msg = JSON.parse(payload);
|
|
112
|
+
return {
|
|
113
|
+
kind: "part",
|
|
114
|
+
part: {
|
|
115
|
+
type: "error",
|
|
116
|
+
error: new Error(typeof msg == "string" ? msg : "Unknown error")
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
} catch {
|
|
120
|
+
return {
|
|
121
|
+
kind: "part",
|
|
122
|
+
part: { type: "error", error: new Error("Unknown streaming error") }
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
case "b":
|
|
126
|
+
try {
|
|
127
|
+
const data = JSON.parse(payload);
|
|
128
|
+
return {
|
|
129
|
+
kind: "part",
|
|
130
|
+
part: {
|
|
131
|
+
type: "tool-call",
|
|
132
|
+
toolCallId: data.toolCallId,
|
|
133
|
+
toolName: data.toolName,
|
|
134
|
+
input: typeof data.args == "string" ? data.args : JSON.stringify(data.args)
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
} catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
case "d":
|
|
141
|
+
case "e":
|
|
142
|
+
try {
|
|
143
|
+
const data = JSON.parse(payload);
|
|
144
|
+
return { kind: "finish", finishReason: mapFinishReason(data.finishReason) };
|
|
145
|
+
} catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
default:
|
|
149
|
+
return null;
|
|
80
150
|
}
|
|
81
151
|
}
|
|
82
152
|
async function extractTextFromStream(responseBody) {
|
|
83
|
-
const reader = responseBody.getReader(), decoder = new TextDecoder();
|
|
153
|
+
const reader = responseBody.getReader(), decoder = new TextDecoder(), textContentId = "extract";
|
|
84
154
|
let text = "";
|
|
85
155
|
for (; ; ) {
|
|
86
156
|
const { done, value } = await reader.read();
|
|
87
157
|
if (done) break;
|
|
88
158
|
const chunk = decoder.decode(value, { stream: !0 });
|
|
89
159
|
for (const line of chunk.split(`
|
|
90
|
-
`))
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
typeof parsed == "string" && (text += parsed);
|
|
95
|
-
} catch {
|
|
96
|
-
}
|
|
160
|
+
`)) {
|
|
161
|
+
const parsed = parseStreamLine(line, textContentId);
|
|
162
|
+
parsed?.kind === "part" && parsed.part.type === "text-delta" && (text += parsed.part.delta);
|
|
163
|
+
}
|
|
97
164
|
}
|
|
98
165
|
return text;
|
|
99
166
|
}
|
|
100
|
-
function createSSEStream(responseBody) {
|
|
101
|
-
let finishReason = "other";
|
|
167
|
+
function createSSEStream(responseBody, warnings) {
|
|
168
|
+
let finishReason = { unified: "other", raw: void 0 };
|
|
169
|
+
const textContentId = crypto.randomUUID();
|
|
170
|
+
let textStarted = !1, hasToolCalls = !1;
|
|
102
171
|
return new ReadableStream({
|
|
103
172
|
async start(controller) {
|
|
104
173
|
const reader = responseBody.getReader(), decoder = new TextDecoder();
|
|
105
174
|
let buffer = "";
|
|
175
|
+
controller.enqueue({ type: "stream-start", warnings });
|
|
106
176
|
try {
|
|
107
177
|
for (; ; ) {
|
|
108
178
|
const { done, value } = await reader.read();
|
|
@@ -112,20 +182,18 @@ function createSSEStream(responseBody) {
|
|
|
112
182
|
`);
|
|
113
183
|
buffer = lines.pop() ?? "";
|
|
114
184
|
for (const line of lines) {
|
|
115
|
-
const parsed = parseStreamLine(line);
|
|
116
|
-
parsed && controller.enqueue(parsed);
|
|
117
|
-
const finish = parseFinishLine(line);
|
|
118
|
-
finish && (finishReason = finish);
|
|
185
|
+
const parsed = parseStreamLine(line, textContentId);
|
|
186
|
+
parsed?.kind === "part" ? (parsed.part.type === "text-delta" && !textStarted && (controller.enqueue({ type: "text-start", id: textContentId }), textStarted = !0), parsed.part.type === "tool-call" && (textStarted && (controller.enqueue({ type: "text-end", id: textContentId }), textStarted = !1), hasToolCalls = !0), controller.enqueue(parsed.part)) : parsed?.kind === "finish" && (finishReason = parsed.finishReason);
|
|
119
187
|
}
|
|
120
188
|
}
|
|
121
189
|
if (buffer.trim()) {
|
|
122
|
-
const parsed = parseStreamLine(buffer);
|
|
123
|
-
parsed && controller.enqueue(parsed);
|
|
190
|
+
const parsed = parseStreamLine(buffer, textContentId);
|
|
191
|
+
parsed?.kind === "part" ? (parsed.part.type === "text-delta" && !textStarted && (controller.enqueue({ type: "text-start", id: textContentId }), textStarted = !0), parsed.part.type === "tool-call" && (textStarted && (controller.enqueue({ type: "text-end", id: textContentId }), textStarted = !1), hasToolCalls = !0), controller.enqueue(parsed.part)) : parsed?.kind === "finish" && (finishReason = parsed.finishReason);
|
|
124
192
|
}
|
|
125
|
-
controller.enqueue({
|
|
193
|
+
textStarted && controller.enqueue({ type: "text-end", id: textContentId }), hasToolCalls && finishReason.unified !== "tool-calls" && (finishReason = { unified: "tool-calls", raw: finishReason.raw ?? "tool-calls" }), controller.enqueue({
|
|
126
194
|
type: "finish",
|
|
127
195
|
finishReason,
|
|
128
|
-
usage:
|
|
196
|
+
usage: createEmptyUsage()
|
|
129
197
|
});
|
|
130
198
|
} catch (error) {
|
|
131
199
|
controller.enqueue({
|
|
@@ -139,7 +207,7 @@ function createSSEStream(responseBody) {
|
|
|
139
207
|
});
|
|
140
208
|
}
|
|
141
209
|
const UNSUPPORTED_SETTINGS = [
|
|
142
|
-
"
|
|
210
|
+
"maxOutputTokens",
|
|
143
211
|
"temperature",
|
|
144
212
|
"topP",
|
|
145
213
|
"topK",
|
|
@@ -148,39 +216,96 @@ const UNSUPPORTED_SETTINGS = [
|
|
|
148
216
|
"seed"
|
|
149
217
|
];
|
|
150
218
|
class ContentAgentModel {
|
|
151
|
-
specificationVersion = "
|
|
219
|
+
specificationVersion = "v3";
|
|
152
220
|
provider;
|
|
153
221
|
modelId;
|
|
154
|
-
|
|
222
|
+
supportedUrls = {};
|
|
155
223
|
config;
|
|
156
224
|
threadId;
|
|
157
225
|
settings;
|
|
158
226
|
constructor(threadId, settings, config) {
|
|
159
227
|
this.threadId = threadId, this.modelId = `content-agent:${threadId}`, this.provider = config.provider, this.settings = settings ?? {}, this.config = config;
|
|
160
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Converts a LanguageModelV3Prompt into wire messages for the agent API.
|
|
231
|
+
*
|
|
232
|
+
* Handles all message roles:
|
|
233
|
+
* - system: plain text system messages
|
|
234
|
+
* - user: extracts text from content parts
|
|
235
|
+
* - assistant: extracts text and/or tool-call parts
|
|
236
|
+
* - tool: converts tool-result parts for the API
|
|
237
|
+
*/
|
|
161
238
|
convertPromptToMessages(prompt) {
|
|
162
239
|
const messages = [];
|
|
163
240
|
for (const message of prompt) {
|
|
164
|
-
if (message.role === "
|
|
165
|
-
|
|
166
|
-
|
|
241
|
+
if (message.role === "system") {
|
|
242
|
+
message.content && messages.push({ role: "system", content: message.content });
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (message.role === "tool") {
|
|
246
|
+
const toolResults = message.content.filter((part) => part.type === "tool-result").map((part) => {
|
|
247
|
+
const p = part;
|
|
248
|
+
return {
|
|
249
|
+
type: "tool-result",
|
|
250
|
+
toolCallId: p.toolCallId,
|
|
251
|
+
toolName: p.toolName,
|
|
252
|
+
output: p.output && typeof p.output == "object" && "value" in p.output ? p.output.value : p.output
|
|
253
|
+
};
|
|
254
|
+
});
|
|
255
|
+
toolResults.length > 0 && messages.push({ role: "tool", content: toolResults });
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (message.role === "assistant") {
|
|
259
|
+
const content = message.content, grouped = groupBy(content, (p) => p.type), toolCalls = grouped["tool-call"] ?? [], textParts = grouped.text ?? [];
|
|
260
|
+
if (toolCalls.length > 0) {
|
|
261
|
+
const parts = [
|
|
262
|
+
...textParts.filter((p) => p.text).map((p) => ({ type: "text", text: p.text })),
|
|
263
|
+
...toolCalls.map((tc) => ({
|
|
264
|
+
type: "tool-call",
|
|
265
|
+
toolCallId: tc.toolCallId,
|
|
266
|
+
toolName: tc.toolName,
|
|
267
|
+
input: tc.input
|
|
268
|
+
}))
|
|
269
|
+
];
|
|
270
|
+
parts.length > 0 && messages.push({ role: "assistant", content: parts });
|
|
271
|
+
} else {
|
|
272
|
+
const text2 = extractTextFromParts(content);
|
|
273
|
+
text2 && messages.push({ role: "assistant", content: text2 });
|
|
274
|
+
}
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
const text = extractTextFromParts(message.content);
|
|
278
|
+
text && messages.push({ role: message.role, content: text });
|
|
167
279
|
}
|
|
168
280
|
return messages;
|
|
169
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Extracts client tool definitions from the model call options.
|
|
284
|
+
* Only the schemas are sent — execute functions stay on the client.
|
|
285
|
+
*/
|
|
286
|
+
extractClientTools(options) {
|
|
287
|
+
if (!options.tools?.length) return;
|
|
288
|
+
const clientTools = options.tools.filter((t) => t.type === "function").map((t) => ({
|
|
289
|
+
type: "function",
|
|
290
|
+
name: t.name,
|
|
291
|
+
description: t.description,
|
|
292
|
+
inputSchema: t.inputSchema
|
|
293
|
+
}));
|
|
294
|
+
return clientTools.length > 0 ? clientTools : void 0;
|
|
295
|
+
}
|
|
170
296
|
collectWarnings(options) {
|
|
171
297
|
const warnings = [];
|
|
172
|
-
options.mode.type === "regular" && (options.mode.tools?.length && warnings.push({ type: "other", message: "Tools are not supported by Content Agent API" }), options.mode.toolChoice && warnings.push({
|
|
173
|
-
type: "other",
|
|
174
|
-
message: "Tool choice is not supported by Content Agent API"
|
|
175
|
-
}));
|
|
176
298
|
for (const setting of UNSUPPORTED_SETTINGS)
|
|
177
|
-
options[setting] !== void 0 && warnings.push({ type: "unsupported
|
|
178
|
-
return options.stopSequences?.length && warnings.push({ type: "unsupported
|
|
299
|
+
options[setting] !== void 0 && warnings.push({ type: "unsupported", feature: setting });
|
|
300
|
+
return options.stopSequences?.length && warnings.push({ type: "unsupported", feature: "stopSequences" }), options.responseFormat && options.responseFormat.type !== "text" && warnings.push({ type: "unsupported", feature: "responseFormat" }), warnings;
|
|
179
301
|
}
|
|
180
302
|
buildRequestBody(options, stream) {
|
|
303
|
+
const clientTools = this.extractClientTools(options), toolChoice = options.toolChoice;
|
|
181
304
|
return {
|
|
182
305
|
messages: this.convertPromptToMessages(options.prompt),
|
|
183
306
|
stream,
|
|
307
|
+
...clientTools && { clientTools },
|
|
308
|
+
...toolChoice && { toolChoice },
|
|
184
309
|
...this.settings.application && { application: this.settings.application },
|
|
185
310
|
...this.settings.config && { config: this.settings.config },
|
|
186
311
|
...this.settings.format && { format: this.settings.format }
|
|
@@ -190,7 +315,7 @@ class ContentAgentModel {
|
|
|
190
315
|
return Object.fromEntries(response.headers.entries());
|
|
191
316
|
}
|
|
192
317
|
async doGenerate(options) {
|
|
193
|
-
const body = this.buildRequestBody(options, !
|
|
318
|
+
const body = this.buildRequestBody(options, !0), warnings = this.collectWarnings(options), response = await fetchApi({
|
|
194
319
|
url: buildApiUrl(
|
|
195
320
|
this.config.baseURL,
|
|
196
321
|
this.config.apiVersion,
|
|
@@ -201,15 +326,51 @@ class ContentAgentModel {
|
|
|
201
326
|
signal: options.abortSignal,
|
|
202
327
|
fetch: this.config.fetch
|
|
203
328
|
});
|
|
329
|
+
if (!response.body)
|
|
330
|
+
throw new Error("No response body for generate request");
|
|
331
|
+
const { content, finishReason } = await this.extractContentFromStream(response.body);
|
|
204
332
|
return {
|
|
205
|
-
|
|
206
|
-
finishReason
|
|
207
|
-
usage:
|
|
208
|
-
|
|
209
|
-
|
|
333
|
+
content,
|
|
334
|
+
finishReason,
|
|
335
|
+
usage: createEmptyUsage(),
|
|
336
|
+
request: { body },
|
|
337
|
+
response: { headers: this.getResponseHeaders(response) },
|
|
210
338
|
warnings
|
|
211
339
|
};
|
|
212
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Parses a streamed response body into content parts (text and tool calls)
|
|
343
|
+
* and a finish reason. Used by doGenerate to buffer the full response.
|
|
344
|
+
*/
|
|
345
|
+
async extractContentFromStream(responseBody) {
|
|
346
|
+
const reader = responseBody.getReader(), decoder = new TextDecoder(), textContentId = "generate";
|
|
347
|
+
let text = "", hasToolCalls = !1;
|
|
348
|
+
const content = [];
|
|
349
|
+
for (; ; ) {
|
|
350
|
+
const { done, value } = await reader.read();
|
|
351
|
+
if (done) break;
|
|
352
|
+
const chunk = decoder.decode(value, { stream: !0 });
|
|
353
|
+
for (const line of chunk.split(`
|
|
354
|
+
`)) {
|
|
355
|
+
const parsed = parseStreamLine(line, textContentId);
|
|
356
|
+
if (parsed?.kind === "part") {
|
|
357
|
+
if (parsed.part.type === "text-delta")
|
|
358
|
+
text += parsed.part.delta;
|
|
359
|
+
else if (parsed.part.type === "tool-call") {
|
|
360
|
+
hasToolCalls = !0;
|
|
361
|
+
const tc = parsed.part;
|
|
362
|
+
content.push({
|
|
363
|
+
type: "tool-call",
|
|
364
|
+
toolCallId: tc.toolCallId,
|
|
365
|
+
toolName: tc.toolName,
|
|
366
|
+
input: tc.input
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return text && content.unshift({ type: "text", text }), { content, finishReason: hasToolCalls ? { unified: "tool-calls", raw: "tool-calls" } : { unified: "stop", raw: void 0 } };
|
|
373
|
+
}
|
|
213
374
|
async doStream(options) {
|
|
214
375
|
const body = this.buildRequestBody(options, !0), warnings = this.collectWarnings(options), response = await fetchApi({
|
|
215
376
|
url: buildApiUrl(
|
|
@@ -225,10 +386,9 @@ class ContentAgentModel {
|
|
|
225
386
|
if (!response.body)
|
|
226
387
|
throw new Error("No response body for streaming request");
|
|
227
388
|
return {
|
|
228
|
-
stream: createSSEStream(response.body),
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
warnings
|
|
389
|
+
stream: createSSEStream(response.body, warnings),
|
|
390
|
+
request: { body },
|
|
391
|
+
response: { headers: this.getResponseHeaders(response) }
|
|
232
392
|
};
|
|
233
393
|
}
|
|
234
394
|
}
|
|
@@ -278,16 +438,18 @@ function createContentAgent(options) {
|
|
|
278
438
|
}
|
|
279
439
|
export {
|
|
280
440
|
ContentAgentModel,
|
|
441
|
+
GENERIC_ERROR_MESSAGE,
|
|
281
442
|
SanityAgentError,
|
|
282
443
|
buildApiUrl,
|
|
283
444
|
buildHeaders,
|
|
445
|
+
classifyAgentError,
|
|
284
446
|
createContentAgent,
|
|
285
447
|
createSSEStream,
|
|
286
448
|
extractTextFromParts,
|
|
287
449
|
extractTextFromStream,
|
|
288
450
|
fetchApi,
|
|
451
|
+
getAgentErrorMessage,
|
|
289
452
|
mapFinishReason,
|
|
290
|
-
parseFinishLine,
|
|
291
453
|
parseStreamLine
|
|
292
454
|
};
|
|
293
455
|
//# sourceMappingURL=index.js.map
|