@yourgpt/llm-sdk 2.6.0-beta.3 → 2.6.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 +21 -0
- package/README.md +46 -10
- package/dist/adapters/index.d.mts +11 -13
- package/dist/adapters/index.d.ts +11 -13
- package/dist/adapters/index.js +327 -100
- package/dist/adapters/index.mjs +327 -100
- package/dist/audio-K-Z3-Bce.d.mts +191 -0
- package/dist/audio-K-Z3-Bce.d.ts +191 -0
- package/dist/{base-BICaQaRS.d.mts → base-6LzczuCg.d.ts} +8 -1
- package/dist/{base-CpRPB8u8.d.ts → base-DySbTP8C.d.mts} +8 -1
- package/dist/decisions-CJzOt87t.d.mts +137 -0
- package/dist/decisions-CJzOt87t.d.ts +137 -0
- package/dist/fallback/index.d.mts +4 -4
- package/dist/fallback/index.d.ts +4 -4
- package/dist/http-BQxUT5A9.d.mts +9 -0
- package/dist/http-BQxUT5A9.d.ts +9 -0
- package/dist/index.d.mts +14 -8
- package/dist/index.d.ts +14 -8
- package/dist/index.js +599 -195
- package/dist/index.mjs +596 -196
- package/dist/providers/anthropic/index.d.mts +7 -4
- package/dist/providers/anthropic/index.d.ts +7 -4
- package/dist/providers/anthropic/index.js +383 -102
- package/dist/providers/anthropic/index.mjs +383 -102
- package/dist/providers/azure/index.d.mts +3 -3
- package/dist/providers/azure/index.d.ts +3 -3
- package/dist/providers/cloudflare/index.d.mts +11 -0
- package/dist/providers/cloudflare/index.d.ts +11 -0
- package/dist/providers/cloudflare/index.js +743 -0
- package/dist/providers/cloudflare/index.mjs +741 -0
- package/dist/providers/fireworks/index.d.mts +3 -3
- package/dist/providers/fireworks/index.d.ts +3 -3
- package/dist/providers/fireworks/index.js +108 -59
- package/dist/providers/fireworks/index.mjs +108 -59
- package/dist/providers/google/index.d.mts +3 -3
- package/dist/providers/google/index.d.ts +3 -3
- package/dist/providers/google/index.js +108 -59
- package/dist/providers/google/index.mjs +108 -59
- package/dist/providers/ollama/index.d.mts +4 -4
- package/dist/providers/ollama/index.d.ts +4 -4
- package/dist/providers/openai/index.d.mts +38 -6
- package/dist/providers/openai/index.d.ts +38 -6
- package/dist/providers/openai/index.js +1378 -84
- package/dist/providers/openai/index.mjs +1376 -85
- package/dist/providers/openrouter/index.d.mts +21 -4
- package/dist/providers/openrouter/index.d.ts +21 -4
- package/dist/providers/openrouter/index.js +967 -130
- package/dist/providers/openrouter/index.mjs +967 -131
- package/dist/providers/togetherai/index.d.mts +3 -3
- package/dist/providers/togetherai/index.d.ts +3 -3
- package/dist/providers/togetherai/index.js +108 -59
- package/dist/providers/togetherai/index.mjs +108 -59
- package/dist/providers/typesafe/index.d.mts +8 -0
- package/dist/providers/typesafe/index.d.ts +8 -0
- package/dist/providers/typesafe/index.js +735 -0
- package/dist/providers/typesafe/index.mjs +733 -0
- package/dist/providers/xai/index.d.mts +3 -3
- package/dist/providers/xai/index.d.ts +3 -3
- package/dist/providers/xai/index.js +108 -59
- package/dist/providers/xai/index.mjs +108 -59
- package/dist/{types-DCFqkJAy.d.ts → types-B0y6VZSQ.d.ts} +1 -1
- package/dist/{types-DHQEMFHA.d.mts → types-BXQMtaCX.d.ts} +17 -3
- package/dist/{types-C3RgRbEC.d.mts → types-BY6BVhFg.d.mts} +1 -1
- package/dist/{types-Dikj3En4.d.ts → types-C7_qVSSd.d.mts} +17 -3
- package/dist/{types-Dg1Bcg1k.d.mts → types-D7lzMMLu.d.mts} +13 -1
- package/dist/{types-Dg1Bcg1k.d.ts → types-D7lzMMLu.d.ts} +13 -1
- package/dist/yourgpt/index.d.mts +1 -1
- package/dist/yourgpt/index.d.ts +1 -1
- package/docs/decisions.md +174 -0
- package/docs/media.md +201 -0
- package/docs/multimodal-and-audio.md +9 -2
- package/package.json +34 -12
- package/dist/audio-BBSwnjo8.d.mts +0 -92
- package/dist/audio-BBSwnjo8.d.ts +0 -92
package/dist/index.mjs
CHANGED
|
@@ -150,7 +150,22 @@ function zodToJsonSchema(schema) {
|
|
|
150
150
|
case "ZodString":
|
|
151
151
|
return { type: "string", description };
|
|
152
152
|
case "ZodNumber":
|
|
153
|
-
return {
|
|
153
|
+
return {
|
|
154
|
+
type: def.checks?.some(
|
|
155
|
+
(check) => check.kind === "int"
|
|
156
|
+
) ? "integer" : "number",
|
|
157
|
+
description
|
|
158
|
+
};
|
|
159
|
+
case "ZodNull":
|
|
160
|
+
return { type: "null", description };
|
|
161
|
+
case "ZodAny":
|
|
162
|
+
case "ZodUnknown":
|
|
163
|
+
return { description };
|
|
164
|
+
case "ZodEffects":
|
|
165
|
+
return {
|
|
166
|
+
...zodToJsonSchema(def.schema),
|
|
167
|
+
...description ? { description } : {}
|
|
168
|
+
};
|
|
154
169
|
case "ZodBoolean":
|
|
155
170
|
return { type: "boolean", description };
|
|
156
171
|
case "ZodEnum": {
|
|
@@ -171,10 +186,13 @@ function zodToJsonSchema(schema) {
|
|
|
171
186
|
const properties = {};
|
|
172
187
|
const required = [];
|
|
173
188
|
for (const [key, value] of Object.entries(shapeObj)) {
|
|
174
|
-
properties
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
189
|
+
Object.defineProperty(properties, key, {
|
|
190
|
+
value: zodToJsonSchema(value),
|
|
191
|
+
enumerable: true,
|
|
192
|
+
configurable: true,
|
|
193
|
+
writable: true
|
|
194
|
+
});
|
|
195
|
+
if (!acceptsMissingInput(value)) {
|
|
178
196
|
required.push(key);
|
|
179
197
|
}
|
|
180
198
|
}
|
|
@@ -185,8 +203,13 @@ function zodToJsonSchema(schema) {
|
|
|
185
203
|
description
|
|
186
204
|
};
|
|
187
205
|
}
|
|
188
|
-
case "ZodOptional":
|
|
189
206
|
case "ZodNullable": {
|
|
207
|
+
return {
|
|
208
|
+
anyOf: [zodToJsonSchema(def.innerType), { type: "null" }],
|
|
209
|
+
description
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
case "ZodOptional": {
|
|
190
213
|
const innerType = def.innerType;
|
|
191
214
|
return zodToJsonSchema(innerType);
|
|
192
215
|
}
|
|
@@ -196,6 +219,7 @@ function zodToJsonSchema(schema) {
|
|
|
196
219
|
}
|
|
197
220
|
case "ZodLiteral": {
|
|
198
221
|
const value = def.value;
|
|
222
|
+
if (value === null) return { type: "null", description };
|
|
199
223
|
if (typeof value === "string") {
|
|
200
224
|
return { type: "string", enum: [value], description };
|
|
201
225
|
}
|
|
@@ -219,12 +243,21 @@ function zodToJsonSchema(schema) {
|
|
|
219
243
|
if (stringLiterals.length === options.length) {
|
|
220
244
|
return { type: "string", enum: stringLiterals, description };
|
|
221
245
|
}
|
|
222
|
-
return zodToJsonSchema
|
|
246
|
+
return { anyOf: options.map(zodToJsonSchema), description };
|
|
223
247
|
}
|
|
224
248
|
default:
|
|
225
249
|
return { type: "string", description };
|
|
226
250
|
}
|
|
227
251
|
}
|
|
252
|
+
function acceptsMissingInput(schema) {
|
|
253
|
+
const def = schema._def;
|
|
254
|
+
if (["ZodOptional", "ZodDefault", "ZodAny", "ZodUnknown"].includes(def.typeName))
|
|
255
|
+
return true;
|
|
256
|
+
if (def.typeName === "ZodNullable") return acceptsMissingInput(def.innerType);
|
|
257
|
+
if (def.typeName === "ZodEffects") return acceptsMissingInput(def.schema);
|
|
258
|
+
if (def.typeName === "ZodUnion") return def.options.some(acceptsMissingInput);
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
228
261
|
function formatToolsForOpenAI(tools) {
|
|
229
262
|
return Object.entries(tools).map(([name, toolDef]) => ({
|
|
230
263
|
type: "function",
|
|
@@ -255,6 +288,27 @@ function formatToolsForGoogle(tools) {
|
|
|
255
288
|
}
|
|
256
289
|
|
|
257
290
|
// src/core/provider-error.ts
|
|
291
|
+
function invalidProviderResponse(message) {
|
|
292
|
+
return Object.assign(new Error(message), {
|
|
293
|
+
name: "InvalidProviderResponseError",
|
|
294
|
+
status: 502,
|
|
295
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
function providerErrorEvent(error, code) {
|
|
299
|
+
const details = error ?? {};
|
|
300
|
+
const event = {
|
|
301
|
+
type: "error",
|
|
302
|
+
message: error instanceof Error ? error.message : String(error),
|
|
303
|
+
code,
|
|
304
|
+
...typeof details.status === "number" ? { status: details.status } : {},
|
|
305
|
+
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
306
|
+
...typeof details.param === "string" ? { param: details.param } : {},
|
|
307
|
+
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
308
|
+
};
|
|
309
|
+
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
310
|
+
return event;
|
|
311
|
+
}
|
|
258
312
|
function throwIfAborted(signal) {
|
|
259
313
|
if (!signal?.aborted) return;
|
|
260
314
|
const error = new Error("The operation was aborted");
|
|
@@ -262,9 +316,42 @@ function throwIfAborted(signal) {
|
|
|
262
316
|
throw error;
|
|
263
317
|
}
|
|
264
318
|
|
|
319
|
+
// src/core/tool-validation.ts
|
|
320
|
+
function parseToolArguments(value) {
|
|
321
|
+
let args = value;
|
|
322
|
+
if (typeof value === "string") {
|
|
323
|
+
try {
|
|
324
|
+
args = JSON.parse(value || "{}");
|
|
325
|
+
} catch {
|
|
326
|
+
throw invalidProviderResponse("Tool arguments are not valid JSON");
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (args === null || typeof args !== "object" || Array.isArray(args))
|
|
330
|
+
throw invalidProviderResponse("Tool arguments must be a JSON object");
|
|
331
|
+
return args;
|
|
332
|
+
}
|
|
333
|
+
function validateToolCalls(calls) {
|
|
334
|
+
const ids = /* @__PURE__ */ new Set();
|
|
335
|
+
for (const call of calls) {
|
|
336
|
+
if (!call || typeof call.id !== "string" || !call.id || typeof call.name !== "string" || !call.name || ids.has(call.id))
|
|
337
|
+
throw invalidProviderResponse(
|
|
338
|
+
"Tool calls have missing or duplicate identities"
|
|
339
|
+
);
|
|
340
|
+
ids.add(call.id);
|
|
341
|
+
if (typeof call.args === "string")
|
|
342
|
+
throw invalidProviderResponse("Parsed tool arguments must be an object");
|
|
343
|
+
parseToolArguments(call.args);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function validateMaxSteps(value) {
|
|
347
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
348
|
+
throw new Error("maxSteps must be a positive safe integer");
|
|
349
|
+
}
|
|
350
|
+
|
|
265
351
|
// src/core/generate-text.ts
|
|
266
352
|
async function generateText(params) {
|
|
267
353
|
const { model, tools, maxSteps = 1, signal } = params;
|
|
354
|
+
validateMaxSteps(maxSteps);
|
|
268
355
|
if (params.responseFormat && model.capabilities.supportsJsonMode === false) {
|
|
269
356
|
console.warn(
|
|
270
357
|
`[llm-sdk] ${model.provider}/${model.modelId} does not support structured output (responseFormat); the request will be sent but the provider may ignore it.`
|
|
@@ -289,12 +376,13 @@ async function generateText(params) {
|
|
|
289
376
|
});
|
|
290
377
|
throwIfAborted(signal);
|
|
291
378
|
const toolCalls = result.toolCalls ?? [];
|
|
379
|
+
validateToolCalls(toolCalls);
|
|
380
|
+
allToolCalls.push(...toolCalls);
|
|
292
381
|
const stepToolResults = [];
|
|
293
382
|
if (toolCalls.length > 0 && tools) {
|
|
294
|
-
allToolCalls.push(...toolCalls);
|
|
295
383
|
for (const call of toolCalls) {
|
|
296
384
|
throwIfAborted(signal);
|
|
297
|
-
const toolDef = tools[call.name];
|
|
385
|
+
const toolDef = Object.prototype.hasOwnProperty.call(tools, call.name) ? tools[call.name] : void 0;
|
|
298
386
|
if (!toolDef) {
|
|
299
387
|
const errorResult = {
|
|
300
388
|
toolCallId: call.id,
|
|
@@ -337,6 +425,7 @@ async function generateText(params) {
|
|
|
337
425
|
}
|
|
338
426
|
steps.push({
|
|
339
427
|
text: result.text,
|
|
428
|
+
...result.reasoningText !== void 0 ? { reasoningText: result.reasoningText } : {},
|
|
340
429
|
toolCalls,
|
|
341
430
|
toolResults: stepToolResults,
|
|
342
431
|
finishReason: result.finishReason,
|
|
@@ -350,12 +439,12 @@ async function generateText(params) {
|
|
|
350
439
|
...result.providerMetadata ? { providerMetadata: responseReplayMetadata(result.providerMetadata) } : {}
|
|
351
440
|
};
|
|
352
441
|
messages = [...messages, assistantMessage];
|
|
353
|
-
if (toolCalls.length === 0) break;
|
|
442
|
+
if (toolCalls.length === 0 || !tools) break;
|
|
354
443
|
for (const tr of stepToolResults) {
|
|
355
444
|
const toolMessage = {
|
|
356
445
|
role: "tool",
|
|
357
446
|
toolCallId: tr.toolCallId,
|
|
358
|
-
content: tr.modelOutput ? "[Tool returned content]" : JSON.stringify(tr.result),
|
|
447
|
+
content: tr.modelOutput ? "[Tool returned content]" : JSON.stringify(tr.result ?? null),
|
|
359
448
|
...tr.modelOutput ? { modelOutput: tr.modelOutput } : {}
|
|
360
449
|
};
|
|
361
450
|
messages = [...messages, toolMessage];
|
|
@@ -364,6 +453,7 @@ async function generateText(params) {
|
|
|
364
453
|
const lastStep = steps[steps.length - 1];
|
|
365
454
|
return {
|
|
366
455
|
text: lastStep?.text ?? "",
|
|
456
|
+
...lastStep?.reasoningText !== void 0 ? { reasoningText: lastStep.reasoningText } : {},
|
|
367
457
|
providerMetadata: lastStep?.providerMetadata,
|
|
368
458
|
usage: sumUsage(steps),
|
|
369
459
|
finishReason: lastStep?.finishReason ?? "stop",
|
|
@@ -410,9 +500,250 @@ function sumUsage(steps) {
|
|
|
410
500
|
);
|
|
411
501
|
}
|
|
412
502
|
|
|
503
|
+
// src/core/image.ts
|
|
504
|
+
async function generateImage({
|
|
505
|
+
model,
|
|
506
|
+
...options
|
|
507
|
+
}) {
|
|
508
|
+
options.signal?.throwIfAborted();
|
|
509
|
+
if (typeof options.prompt !== "string" || !options.prompt.trim())
|
|
510
|
+
throw new MediaAPIError("Image prompt must not be empty", "invalid_input");
|
|
511
|
+
const result = await model.doGenerate(options);
|
|
512
|
+
options.signal?.throwIfAborted();
|
|
513
|
+
if (!result.images?.length || result.images.some(
|
|
514
|
+
(image) => !(image.uint8Array instanceof Uint8Array) || !image.uint8Array.length
|
|
515
|
+
))
|
|
516
|
+
throw new MediaAPIError(
|
|
517
|
+
"Image provider returned empty images",
|
|
518
|
+
"invalid_response"
|
|
519
|
+
);
|
|
520
|
+
return result;
|
|
521
|
+
}
|
|
522
|
+
var marker = /* @__PURE__ */ Symbol.for("@yourgpt/llm-sdk/MediaAPIError");
|
|
523
|
+
var _a;
|
|
524
|
+
var MediaAPIError = class extends Error {
|
|
525
|
+
constructor(message, code, status, requestId) {
|
|
526
|
+
super(message);
|
|
527
|
+
this.code = code;
|
|
528
|
+
this.status = status;
|
|
529
|
+
this.requestId = requestId;
|
|
530
|
+
this[_a] = true;
|
|
531
|
+
this.name = "MediaAPIError";
|
|
532
|
+
}
|
|
533
|
+
static [(_a = marker, Symbol.hasInstance)](value) {
|
|
534
|
+
return !!value && typeof value === "object" && value[marker] === true;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// src/core/decision-validation.ts
|
|
539
|
+
function decisionInputError(message) {
|
|
540
|
+
throw new DecisionAPIError(message, "invalid_input");
|
|
541
|
+
}
|
|
542
|
+
function decisionResponseError(message) {
|
|
543
|
+
throw new DecisionAPIError(message, "invalid_response");
|
|
544
|
+
}
|
|
545
|
+
function isDecisionRecord(value) {
|
|
546
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
547
|
+
return false;
|
|
548
|
+
const proto = Object.getPrototypeOf(value);
|
|
549
|
+
return proto === Object.prototype || proto === null;
|
|
550
|
+
}
|
|
551
|
+
function json(value, seen = /* @__PURE__ */ new Set(), depth = 0) {
|
|
552
|
+
if (depth > 64) return false;
|
|
553
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
554
|
+
return true;
|
|
555
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
556
|
+
if (typeof value !== "object" || !Array.isArray(value) && !isDecisionRecord(value) || seen.has(value))
|
|
557
|
+
return false;
|
|
558
|
+
seen.add(value);
|
|
559
|
+
const valid = Object.getOwnPropertySymbols(value).length === 0 && (Array.isArray(value) ? Array.from(value) : Object.values(value)).every(
|
|
560
|
+
(item) => json(item, seen, depth + 1)
|
|
561
|
+
);
|
|
562
|
+
seen.delete(value);
|
|
563
|
+
return valid;
|
|
564
|
+
}
|
|
565
|
+
function input(value) {
|
|
566
|
+
return (typeof value === "string" || Array.isArray(value) || isDecisionRecord(value)) && json(value);
|
|
567
|
+
}
|
|
568
|
+
function assertDecisionKeys(value, allowed, label) {
|
|
569
|
+
if (Object.keys(value).some((key) => !allowed.includes(key)))
|
|
570
|
+
decisionInputError(`${label} contains an unsupported field`);
|
|
571
|
+
}
|
|
572
|
+
function validateDecisionInput(options) {
|
|
573
|
+
if (!isDecisionRecord(options))
|
|
574
|
+
decisionInputError("Decisions options must be an object");
|
|
575
|
+
assertDecisionKeys(
|
|
576
|
+
options,
|
|
577
|
+
["state", "questions", "images", "signal", "timeoutMs", "providerOptions"],
|
|
578
|
+
"Decisions options"
|
|
579
|
+
);
|
|
580
|
+
if (!input(options.state))
|
|
581
|
+
decisionInputError(
|
|
582
|
+
"state must be finite, acyclic JSON text, object, or array (maximum depth 64)"
|
|
583
|
+
);
|
|
584
|
+
if (!isDecisionRecord(options.questions) || Object.keys(options.questions).length === 0)
|
|
585
|
+
decisionInputError("questions must be a nonempty map");
|
|
586
|
+
for (const [id, question] of Object.entries(options.questions)) {
|
|
587
|
+
if (!id.length || !isDecisionRecord(question) || !input(question.instructions))
|
|
588
|
+
decisionInputError(
|
|
589
|
+
"Every question needs a nonempty ID and JSON-compatible instructions"
|
|
590
|
+
);
|
|
591
|
+
assertDecisionKeys(
|
|
592
|
+
question,
|
|
593
|
+
["type", "instructions", "criteria"],
|
|
594
|
+
"Question"
|
|
595
|
+
);
|
|
596
|
+
if (question.type === "boolean") {
|
|
597
|
+
if (question.criteria !== void 0 && (!isDecisionRecord(question.criteria) || Object.entries(question.criteria).some(
|
|
598
|
+
([key, value]) => !["true", "false"].includes(key) || !input(value)
|
|
599
|
+
)))
|
|
600
|
+
decisionInputError("Boolean criteria may describe only true and false");
|
|
601
|
+
} else if (question.type === "choice") {
|
|
602
|
+
if (!isDecisionRecord(question.criteria) || Object.keys(question.criteria).length < 2 || Object.keys(question.criteria).length > 255 || Object.entries(question.criteria).some(
|
|
603
|
+
([key, value]) => !key.length || value !== null && !input(value)
|
|
604
|
+
))
|
|
605
|
+
decisionInputError(
|
|
606
|
+
"Choice criteria require 2\u2013255 named options with JSON descriptions or null"
|
|
607
|
+
);
|
|
608
|
+
} else if (question.type === "score") {
|
|
609
|
+
if (!Array.isArray(question.criteria) || question.criteria.length < 2 || !Array.from(question.criteria).every(input))
|
|
610
|
+
decisionInputError(
|
|
611
|
+
"Score criteria require at least two ordered JSON descriptions"
|
|
612
|
+
);
|
|
613
|
+
} else
|
|
614
|
+
decisionInputError("Question type must be boolean, choice, or score");
|
|
615
|
+
}
|
|
616
|
+
if (options.timeoutMs !== void 0 && (!Number.isInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 2147483647))
|
|
617
|
+
decisionInputError("timeoutMs must be a positive 32-bit integer");
|
|
618
|
+
if (options.providerOptions !== void 0 && (!isDecisionRecord(options.providerOptions) || !json(options.providerOptions)))
|
|
619
|
+
decisionInputError("providerOptions must be a JSON object");
|
|
620
|
+
if (options.images !== void 0 && (!Array.isArray(options.images) || !Array.from(options.images).every(
|
|
621
|
+
(image) => isDecisionRecord(image) && image.data instanceof Uint8Array
|
|
622
|
+
)))
|
|
623
|
+
decisionInputError(
|
|
624
|
+
"Decision images must contain encoded bytes; hosted image URLs are unsupported"
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
function probability(value) {
|
|
628
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
|
|
629
|
+
}
|
|
630
|
+
function exactKeys(value, keys) {
|
|
631
|
+
return Object.keys(value).length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
|
|
632
|
+
}
|
|
633
|
+
function validateDecisionResult(questions, result) {
|
|
634
|
+
if (!isDecisionRecord(result) || !isDecisionRecord(result.answers) || !exactKeys(result.answers, Object.keys(questions)))
|
|
635
|
+
decisionResponseError(
|
|
636
|
+
"Decisions must return exactly one answer per question"
|
|
637
|
+
);
|
|
638
|
+
const rounding = result.rounding;
|
|
639
|
+
let pError = 0, sError = 0;
|
|
640
|
+
if (rounding !== void 0) {
|
|
641
|
+
if (!isDecisionRecord(rounding) || ![rounding.probabilityDecimals, rounding.scoreDecimals].every(
|
|
642
|
+
(v) => typeof v === "number" && Number.isInteger(v) && v >= 0 && v <= 15
|
|
643
|
+
))
|
|
644
|
+
decisionResponseError("Invalid decision rounding precision");
|
|
645
|
+
pError = 0.5 * 10 ** -rounding.probabilityDecimals;
|
|
646
|
+
sError = 0.5 * 10 ** -rounding.scoreDecimals;
|
|
647
|
+
}
|
|
648
|
+
const epsilon = 1e-6;
|
|
649
|
+
for (const [id, question] of Object.entries(questions)) {
|
|
650
|
+
const answer = result.answers[id];
|
|
651
|
+
if (!isDecisionRecord(answer))
|
|
652
|
+
decisionResponseError("Invalid decision answer");
|
|
653
|
+
if (answer.type === "refusal") continue;
|
|
654
|
+
if (answer.type !== question.type)
|
|
655
|
+
decisionResponseError("Decision answer type does not match its question");
|
|
656
|
+
if (answer.confidence !== void 0 && !probability(answer.confidence))
|
|
657
|
+
decisionResponseError(
|
|
658
|
+
"Confidence must be finite and between zero and one"
|
|
659
|
+
);
|
|
660
|
+
if (question.type === "boolean") {
|
|
661
|
+
if (!probability(answer.probability))
|
|
662
|
+
decisionResponseError(
|
|
663
|
+
"Boolean probability must be between zero and one"
|
|
664
|
+
);
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
const keys = question.type === "choice" ? Object.keys(question.criteria) : question.criteria.map((_, index) => String(index));
|
|
668
|
+
if (question.type === "choice" && (typeof answer.choice !== "string" || !keys.includes(answer.choice)))
|
|
669
|
+
decisionResponseError("Decision selected an unknown choice");
|
|
670
|
+
if (question.type === "score" && (typeof answer.score !== "number" || !Number.isFinite(answer.score) || answer.score < 0 || answer.score > keys.length - 1))
|
|
671
|
+
decisionResponseError("Decision score is outside its ordered levels");
|
|
672
|
+
if (answer.probabilities === void 0) continue;
|
|
673
|
+
const distribution = answer.probabilities;
|
|
674
|
+
if (!isDecisionRecord(distribution) || !exactKeys(distribution, keys) || !Object.values(distribution).every(probability))
|
|
675
|
+
decisionResponseError(
|
|
676
|
+
"Decision distribution must contain every option exactly once with finite probabilities"
|
|
677
|
+
);
|
|
678
|
+
const values = Object.values(distribution);
|
|
679
|
+
if (Math.abs(values.reduce((a, b) => a + b, 0) - 1) > epsilon + keys.length * pError)
|
|
680
|
+
decisionResponseError("Decision probabilities do not sum to one");
|
|
681
|
+
if (question.type === "choice") {
|
|
682
|
+
if (values.some(
|
|
683
|
+
(v) => v > distribution[answer.choice] + epsilon + 2 * pError
|
|
684
|
+
))
|
|
685
|
+
decisionResponseError(
|
|
686
|
+
"Decision choice is not a highest-probability option"
|
|
687
|
+
);
|
|
688
|
+
} else {
|
|
689
|
+
const mean = keys.reduce(
|
|
690
|
+
(sum, key) => sum + Number(key) * distribution[key],
|
|
691
|
+
0
|
|
692
|
+
);
|
|
693
|
+
const tolerance = epsilon + sError + pError * keys.reduce((sum, key) => sum + Number(key), 0);
|
|
694
|
+
if (Math.abs(answer.score - mean) > tolerance)
|
|
695
|
+
decisionResponseError(
|
|
696
|
+
"Decision score does not match its probability-weighted levels"
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// src/core/decisions.ts
|
|
703
|
+
var decisionErrorMarker = /* @__PURE__ */ Symbol.for("yourgpt.llm-sdk.DecisionAPIError");
|
|
704
|
+
var _a2, _b;
|
|
705
|
+
var DecisionAPIError = class extends (_b = Error, _a2 = decisionErrorMarker, _b) {
|
|
706
|
+
constructor(message, code, status, requestId) {
|
|
707
|
+
super(message);
|
|
708
|
+
this.code = code;
|
|
709
|
+
this.status = status;
|
|
710
|
+
this.requestId = requestId;
|
|
711
|
+
this.name = "DecisionAPIError";
|
|
712
|
+
this[_a2] = true;
|
|
713
|
+
}
|
|
714
|
+
/** Works across CJS/ESM and separately bundled provider entry points. */
|
|
715
|
+
static isInstance(error) {
|
|
716
|
+
return typeof error === "object" && error !== null && /* @__PURE__ */ Symbol.for("yourgpt.llm-sdk.DecisionAPIError") in error;
|
|
717
|
+
}
|
|
718
|
+
/** Advisory only: this SDK does not retry Decisions automatically. */
|
|
719
|
+
get retryable() {
|
|
720
|
+
return this.code === "network_error" || this.code === "http_error" && (this.status === 408 || this.status === 429 || this.status != null && this.status >= 500);
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
async function experimental_decide(options) {
|
|
724
|
+
const { model, ...request } = options;
|
|
725
|
+
validateDecisionInput(request);
|
|
726
|
+
request.signal?.throwIfAborted();
|
|
727
|
+
const result = await model.doDecide(request);
|
|
728
|
+
request.signal?.throwIfAborted();
|
|
729
|
+
validateDecisionResult(request.questions, result);
|
|
730
|
+
return result;
|
|
731
|
+
}
|
|
732
|
+
|
|
413
733
|
// src/core/stream-text.ts
|
|
414
734
|
async function streamText(params) {
|
|
415
|
-
const { model, tools, maxSteps = 1, signal } = params;
|
|
735
|
+
const { model, tools, maxSteps = 1, signal: callerSignal } = params;
|
|
736
|
+
validateMaxSteps(maxSteps);
|
|
737
|
+
const controller = new AbortController();
|
|
738
|
+
const signal = controller.signal;
|
|
739
|
+
const relayAbort = () => controller.abort(callerSignal?.reason);
|
|
740
|
+
if (callerSignal?.aborted) relayAbort();
|
|
741
|
+
else callerSignal?.addEventListener("abort", relayAbort, { once: true });
|
|
742
|
+
const cleanup = () => callerSignal?.removeEventListener("abort", relayAbort);
|
|
743
|
+
const cancel = () => {
|
|
744
|
+
controller.abort();
|
|
745
|
+
cleanup();
|
|
746
|
+
};
|
|
416
747
|
if (params.responseFormat && model.capabilities.supportsJsonMode === false) {
|
|
417
748
|
console.warn(
|
|
418
749
|
`[llm-sdk] ${model.provider}/${model.modelId} does not support structured output (responseFormat); the request will be sent but the provider may ignore it.`
|
|
@@ -439,6 +770,7 @@ async function streamText(params) {
|
|
|
439
770
|
let stepProviderMetadata;
|
|
440
771
|
const toolCalls = [];
|
|
441
772
|
let stepFinishReason = "stop";
|
|
773
|
+
let receivedFinish = false;
|
|
442
774
|
try {
|
|
443
775
|
for await (const chunk of model.doStream({
|
|
444
776
|
messages,
|
|
@@ -452,6 +784,9 @@ async function streamText(params) {
|
|
|
452
784
|
})) {
|
|
453
785
|
throwIfAborted(signal);
|
|
454
786
|
switch (chunk.type) {
|
|
787
|
+
case "reasoning-delta":
|
|
788
|
+
yield chunk;
|
|
789
|
+
break;
|
|
455
790
|
case "text-delta":
|
|
456
791
|
stepText += chunk.text;
|
|
457
792
|
fullText += chunk.text;
|
|
@@ -465,6 +800,11 @@ async function streamText(params) {
|
|
|
465
800
|
};
|
|
466
801
|
break;
|
|
467
802
|
case "finish":
|
|
803
|
+
if (receivedFinish)
|
|
804
|
+
throw invalidProviderResponse(
|
|
805
|
+
"Model stream returned multiple finish events"
|
|
806
|
+
);
|
|
807
|
+
receivedFinish = true;
|
|
468
808
|
stepProviderMetadata = chunk.providerMetadata;
|
|
469
809
|
finalProviderMetadata = chunk.providerMetadata;
|
|
470
810
|
stepFinishReason = chunk.finishReason;
|
|
@@ -482,6 +822,12 @@ async function streamText(params) {
|
|
|
482
822
|
return;
|
|
483
823
|
}
|
|
484
824
|
}
|
|
825
|
+
throwIfAborted(signal);
|
|
826
|
+
if (!receivedFinish)
|
|
827
|
+
throw invalidProviderResponse(
|
|
828
|
+
"Model stream ended without a finish event"
|
|
829
|
+
);
|
|
830
|
+
validateToolCalls(toolCalls);
|
|
485
831
|
} catch (error) {
|
|
486
832
|
yield {
|
|
487
833
|
type: "error",
|
|
@@ -507,7 +853,7 @@ async function streamText(params) {
|
|
|
507
853
|
if (toolCalls.length === 0 || !tools) break;
|
|
508
854
|
for (const call of toolCalls) {
|
|
509
855
|
throwIfAborted(signal);
|
|
510
|
-
const toolDef = tools[call.name];
|
|
856
|
+
const toolDef = Object.prototype.hasOwnProperty.call(tools, call.name) ? tools[call.name] : void 0;
|
|
511
857
|
if (!toolDef) {
|
|
512
858
|
const errorResult = { error: `Tool not found: ${call.name}` };
|
|
513
859
|
yield {
|
|
@@ -548,7 +894,7 @@ async function streamText(params) {
|
|
|
548
894
|
{
|
|
549
895
|
role: "tool",
|
|
550
896
|
toolCallId: call.id,
|
|
551
|
-
content: modelOutput ? "[Tool returned content]" : JSON.stringify(result),
|
|
897
|
+
content: modelOutput ? "[Tool returned content]" : JSON.stringify(result ?? null),
|
|
552
898
|
...modelOutput ? { modelOutput } : {}
|
|
553
899
|
}
|
|
554
900
|
];
|
|
@@ -590,11 +936,17 @@ async function streamText(params) {
|
|
|
590
936
|
pending = (async () => {
|
|
591
937
|
try {
|
|
592
938
|
const next = await source.next();
|
|
593
|
-
if (next.done)
|
|
594
|
-
|
|
939
|
+
if (next.done) {
|
|
940
|
+
finished = true;
|
|
941
|
+
cleanup();
|
|
942
|
+
} else {
|
|
943
|
+
parts.push(next.value);
|
|
944
|
+
if (next.value.type === "error") cleanup();
|
|
945
|
+
}
|
|
595
946
|
} catch (error) {
|
|
596
947
|
failure = error;
|
|
597
948
|
finished = true;
|
|
949
|
+
cleanup();
|
|
598
950
|
}
|
|
599
951
|
})();
|
|
600
952
|
}
|
|
@@ -645,7 +997,7 @@ async function streamText(params) {
|
|
|
645
997
|
return consumeStream().then(() => finalFinishReason);
|
|
646
998
|
},
|
|
647
999
|
toTextStreamResponse(options) {
|
|
648
|
-
const stream = createTextStreamReadable(createTextStream());
|
|
1000
|
+
const stream = createTextStreamReadable(createTextStream(), cancel);
|
|
649
1001
|
return new Response(stream, {
|
|
650
1002
|
status: options?.status ?? 200,
|
|
651
1003
|
headers: {
|
|
@@ -657,7 +1009,7 @@ async function streamText(params) {
|
|
|
657
1009
|
});
|
|
658
1010
|
},
|
|
659
1011
|
toDataStreamResponse(options) {
|
|
660
|
-
const stream = createDataStreamReadable(sharedStream());
|
|
1012
|
+
const stream = createDataStreamReadable(sharedStream(), cancel);
|
|
661
1013
|
return new Response(stream, {
|
|
662
1014
|
status: options?.status ?? 200,
|
|
663
1015
|
headers: {
|
|
@@ -694,35 +1046,51 @@ function formatToolsForProvider2(tools, provider) {
|
|
|
694
1046
|
return formatToolsForOpenAI(tools);
|
|
695
1047
|
}
|
|
696
1048
|
}
|
|
697
|
-
function createTextStreamReadable(textStream) {
|
|
1049
|
+
function createTextStreamReadable(textStream, abort) {
|
|
698
1050
|
const encoder = new TextEncoder();
|
|
1051
|
+
const iterator = textStream[Symbol.asyncIterator]();
|
|
1052
|
+
let cancelled = false;
|
|
699
1053
|
return new ReadableStream({
|
|
700
|
-
async
|
|
1054
|
+
async pull(controller) {
|
|
701
1055
|
try {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
controller.
|
|
1056
|
+
const next = await iterator.next();
|
|
1057
|
+
if (cancelled) return;
|
|
1058
|
+
if (next.done) controller.close();
|
|
1059
|
+
else controller.enqueue(encoder.encode(next.value));
|
|
706
1060
|
} catch (error) {
|
|
707
|
-
controller.error(error);
|
|
1061
|
+
if (!cancelled) controller.error(error);
|
|
708
1062
|
}
|
|
1063
|
+
},
|
|
1064
|
+
cancel() {
|
|
1065
|
+
cancelled = true;
|
|
1066
|
+
abort();
|
|
1067
|
+
void iterator.return?.().catch(() => {
|
|
1068
|
+
});
|
|
709
1069
|
}
|
|
710
1070
|
});
|
|
711
1071
|
}
|
|
712
|
-
function createDataStreamReadable(fullStream) {
|
|
1072
|
+
function createDataStreamReadable(fullStream, abort) {
|
|
713
1073
|
const encoder = new TextEncoder();
|
|
1074
|
+
const iterator = fullStream[Symbol.asyncIterator]();
|
|
1075
|
+
let cancelled = false;
|
|
714
1076
|
return new ReadableStream({
|
|
715
|
-
async
|
|
1077
|
+
async pull(controller) {
|
|
716
1078
|
try {
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
1079
|
+
const next = await iterator.next();
|
|
1080
|
+
if (cancelled) return;
|
|
1081
|
+
if (next.done) {
|
|
1082
|
+
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
1083
|
+
controller.close();
|
|
1084
|
+
return;
|
|
722
1085
|
}
|
|
723
|
-
|
|
724
|
-
controller.
|
|
1086
|
+
if (next.value.type === "error") throw next.value.error;
|
|
1087
|
+
controller.enqueue(
|
|
1088
|
+
encoder.encode(`data: ${JSON.stringify(next.value)}
|
|
1089
|
+
|
|
1090
|
+
`)
|
|
1091
|
+
);
|
|
725
1092
|
} catch (error) {
|
|
1093
|
+
if (cancelled) return;
|
|
726
1094
|
const errorData = JSON.stringify({
|
|
727
1095
|
type: "error",
|
|
728
1096
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -731,7 +1099,15 @@ function createDataStreamReadable(fullStream) {
|
|
|
731
1099
|
|
|
732
1100
|
`));
|
|
733
1101
|
controller.close();
|
|
1102
|
+
void iterator.return?.().catch(() => {
|
|
1103
|
+
});
|
|
734
1104
|
}
|
|
1105
|
+
},
|
|
1106
|
+
cancel() {
|
|
1107
|
+
cancelled = true;
|
|
1108
|
+
abort();
|
|
1109
|
+
void iterator.return?.().catch(() => {
|
|
1110
|
+
});
|
|
735
1111
|
}
|
|
736
1112
|
});
|
|
737
1113
|
}
|
|
@@ -1267,6 +1643,9 @@ var StreamResult = class {
|
|
|
1267
1643
|
}
|
|
1268
1644
|
break;
|
|
1269
1645
|
}
|
|
1646
|
+
case "error":
|
|
1647
|
+
collected.error = { message: event.message, code: event.code };
|
|
1648
|
+
break;
|
|
1270
1649
|
case "done":
|
|
1271
1650
|
if (event.messages) {
|
|
1272
1651
|
collected.messages.push(...event.messages);
|
|
@@ -1733,7 +2112,7 @@ function buildToolResultForAI(tool2, result, args) {
|
|
|
1733
2112
|
return aiContext ?? `[Tool ${tool2?.name ?? "unknown"} executed successfully]`;
|
|
1734
2113
|
case "full":
|
|
1735
2114
|
default:
|
|
1736
|
-
const fullData = JSON.stringify(result);
|
|
2115
|
+
const fullData = JSON.stringify(result ?? null);
|
|
1737
2116
|
return aiContext ? `${aiContext}
|
|
1738
2117
|
|
|
1739
2118
|
Full data: ${fullData}` : fullData;
|
|
@@ -2413,7 +2792,8 @@ var Runtime = class {
|
|
|
2413
2792
|
const systemPrompt = request.systemPrompt || this.config.systemPrompt || "";
|
|
2414
2793
|
let accumulatedText = "";
|
|
2415
2794
|
const toolCalls = [];
|
|
2416
|
-
|
|
2795
|
+
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
2796
|
+
const endedToolIds = /* @__PURE__ */ new Set();
|
|
2417
2797
|
const serverToolResults = [];
|
|
2418
2798
|
const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
|
|
2419
2799
|
let adapterProviderMetadata;
|
|
@@ -2438,147 +2818,151 @@ var Runtime = class {
|
|
|
2438
2818
|
debug
|
|
2439
2819
|
};
|
|
2440
2820
|
const stream = this.adapter.stream(completionRequest);
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
name
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2821
|
+
try {
|
|
2822
|
+
for await (const event of stream) {
|
|
2823
|
+
throwIfAborted(signal);
|
|
2824
|
+
switch (event.type) {
|
|
2825
|
+
case "message:start":
|
|
2826
|
+
yield event;
|
|
2827
|
+
break;
|
|
2828
|
+
case "message:end":
|
|
2829
|
+
yield {
|
|
2830
|
+
...event,
|
|
2831
|
+
providerMetadata: responseReplayMetadata(event.providerMetadata)
|
|
2832
|
+
};
|
|
2833
|
+
break;
|
|
2834
|
+
case "message:delta":
|
|
2835
|
+
accumulatedText += event.content;
|
|
2836
|
+
yield event;
|
|
2837
|
+
break;
|
|
2838
|
+
case "action:start":
|
|
2839
|
+
if (!event.id || !event.name || pendingToolCalls.has(event.id) || toolCalls.some((call) => call.id === event.id))
|
|
2840
|
+
throw invalidProviderResponse(
|
|
2841
|
+
"Tool calls have missing or duplicate identities"
|
|
2842
|
+
);
|
|
2843
|
+
pendingToolCalls.set(event.id, {
|
|
2844
|
+
id: event.id,
|
|
2845
|
+
name: event.name,
|
|
2846
|
+
...event.extra_content ? { extra_content: event.extra_content } : {}
|
|
2847
|
+
});
|
|
2848
|
+
if (debug) {
|
|
2849
|
+
console.log(`[Copilot SDK] Tool call started: ${event.name}`);
|
|
2850
|
+
}
|
|
2851
|
+
yield event;
|
|
2852
|
+
break;
|
|
2853
|
+
case "action:args": {
|
|
2854
|
+
const current = pendingToolCalls.get(event.id);
|
|
2855
|
+
if (!current)
|
|
2856
|
+
throw invalidProviderResponse(
|
|
2857
|
+
"Tool arguments have no matching call"
|
|
2858
|
+
);
|
|
2859
|
+
toolCalls.push({
|
|
2860
|
+
...current,
|
|
2861
|
+
args: parseToolArguments(event.args)
|
|
2862
|
+
});
|
|
2863
|
+
pendingToolCalls.delete(event.id);
|
|
2864
|
+
yield event;
|
|
2865
|
+
break;
|
|
2465
2866
|
}
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2867
|
+
case "action:end": {
|
|
2868
|
+
const tc = toolCalls.find((t) => t.id === event.id);
|
|
2869
|
+
const eventName = event.name;
|
|
2870
|
+
if (!tc || eventName && eventName !== tc.name || endedToolIds.has(event.id))
|
|
2871
|
+
throw invalidProviderResponse(
|
|
2872
|
+
"Tool completion has no matching unexecuted call"
|
|
2873
|
+
);
|
|
2874
|
+
endedToolIds.add(event.id);
|
|
2875
|
+
const toolName = tc.name;
|
|
2876
|
+
const tool2 = toolName ? selectedToolMap.get(toolName) : void 0;
|
|
2877
|
+
if (tool2?.location === "server" && tool2.handler) {
|
|
2472
2878
|
if (debug) {
|
|
2473
2879
|
console.log(
|
|
2474
|
-
`[Copilot SDK]
|
|
2475
|
-
parsedArgs
|
|
2880
|
+
`[Copilot SDK] Executing server-side tool: ${toolName}`
|
|
2476
2881
|
);
|
|
2477
2882
|
}
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
console.error(
|
|
2486
|
-
"[Copilot SDK] Failed to parse tool args:",
|
|
2487
|
-
event.args,
|
|
2488
|
-
e
|
|
2883
|
+
const args = tc.args;
|
|
2884
|
+
const toolContext = buildToolContext(
|
|
2885
|
+
event.id,
|
|
2886
|
+
signal,
|
|
2887
|
+
request.threadId,
|
|
2888
|
+
_httpRequest,
|
|
2889
|
+
toolContextData
|
|
2489
2890
|
);
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2891
|
+
try {
|
|
2892
|
+
throwIfAborted(signal);
|
|
2893
|
+
const result = await tool2.handler(args, toolContext);
|
|
2894
|
+
throwIfAborted(signal);
|
|
2895
|
+
const modelOutput = resolveToolOutput(
|
|
2896
|
+
result,
|
|
2897
|
+
tool2.toModelOutput?.(result)
|
|
2898
|
+
);
|
|
2899
|
+
serverToolResults.push({
|
|
2900
|
+
id: event.id,
|
|
2901
|
+
name: toolName,
|
|
2902
|
+
args,
|
|
2903
|
+
result,
|
|
2904
|
+
modelOutput,
|
|
2905
|
+
tool: tool2
|
|
2906
|
+
});
|
|
2907
|
+
yield {
|
|
2908
|
+
type: "action:end",
|
|
2909
|
+
id: event.id,
|
|
2910
|
+
name: toolName,
|
|
2911
|
+
result,
|
|
2912
|
+
modelOutput
|
|
2913
|
+
};
|
|
2914
|
+
} catch (error) {
|
|
2915
|
+
throwIfAborted(signal);
|
|
2916
|
+
const errorResult = {
|
|
2917
|
+
success: false,
|
|
2918
|
+
error: error instanceof Error ? error.message : "Tool execution failed"
|
|
2919
|
+
};
|
|
2920
|
+
serverToolResults.push({
|
|
2921
|
+
id: event.id,
|
|
2922
|
+
name: toolName,
|
|
2923
|
+
args,
|
|
2924
|
+
result: errorResult,
|
|
2925
|
+
tool: tool2
|
|
2926
|
+
});
|
|
2927
|
+
yield {
|
|
2928
|
+
type: "action:end",
|
|
2929
|
+
id: event.id,
|
|
2930
|
+
name: toolName,
|
|
2931
|
+
error: error instanceof Error ? error.message : "Tool execution failed"
|
|
2932
|
+
};
|
|
2933
|
+
}
|
|
2934
|
+
} else {
|
|
2935
|
+
yield event;
|
|
2496
2936
|
}
|
|
2497
|
-
|
|
2937
|
+
break;
|
|
2498
2938
|
}
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
}
|
|
2510
|
-
const tc = toolCalls.find((t) => t.id === event.id);
|
|
2511
|
-
const args = tc?.args ?? {};
|
|
2512
|
-
const toolContext = buildToolContext(
|
|
2513
|
-
event.id,
|
|
2514
|
-
signal,
|
|
2515
|
-
request.threadId,
|
|
2516
|
-
_httpRequest,
|
|
2517
|
-
toolContextData
|
|
2939
|
+
case "citation":
|
|
2940
|
+
yield event;
|
|
2941
|
+
break;
|
|
2942
|
+
case "error":
|
|
2943
|
+
yield event;
|
|
2944
|
+
return;
|
|
2945
|
+
// Exit on error
|
|
2946
|
+
case "done":
|
|
2947
|
+
adapterProviderMetadata = responseReplayMetadata(
|
|
2948
|
+
event.providerMetadata
|
|
2518
2949
|
);
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
const modelOutput = resolveToolOutput(
|
|
2522
|
-
result,
|
|
2523
|
-
tool2.toModelOutput?.(result)
|
|
2524
|
-
);
|
|
2525
|
-
serverToolResults.push({
|
|
2526
|
-
id: event.id,
|
|
2527
|
-
name: toolName,
|
|
2528
|
-
args,
|
|
2529
|
-
result,
|
|
2530
|
-
modelOutput,
|
|
2531
|
-
tool: tool2
|
|
2532
|
-
});
|
|
2533
|
-
yield {
|
|
2534
|
-
type: "action:end",
|
|
2535
|
-
id: event.id,
|
|
2536
|
-
name: toolName,
|
|
2537
|
-
result,
|
|
2538
|
-
modelOutput
|
|
2539
|
-
};
|
|
2540
|
-
} catch (error) {
|
|
2541
|
-
const errorResult = {
|
|
2542
|
-
success: false,
|
|
2543
|
-
error: error instanceof Error ? error.message : "Tool execution failed"
|
|
2544
|
-
};
|
|
2545
|
-
serverToolResults.push({
|
|
2546
|
-
id: event.id,
|
|
2547
|
-
name: toolName,
|
|
2548
|
-
args,
|
|
2549
|
-
result: errorResult,
|
|
2550
|
-
tool: tool2
|
|
2551
|
-
});
|
|
2552
|
-
yield {
|
|
2553
|
-
type: "action:end",
|
|
2554
|
-
id: event.id,
|
|
2555
|
-
name: toolName,
|
|
2556
|
-
error: error instanceof Error ? error.message : "Tool execution failed"
|
|
2557
|
-
};
|
|
2950
|
+
if (event.usage) {
|
|
2951
|
+
adapterUsage = event.usage;
|
|
2558
2952
|
}
|
|
2559
|
-
|
|
2953
|
+
break;
|
|
2954
|
+
default:
|
|
2560
2955
|
yield event;
|
|
2561
|
-
}
|
|
2562
|
-
break;
|
|
2563
2956
|
}
|
|
2564
|
-
case "citation":
|
|
2565
|
-
yield event;
|
|
2566
|
-
break;
|
|
2567
|
-
case "error":
|
|
2568
|
-
yield event;
|
|
2569
|
-
return;
|
|
2570
|
-
// Exit on error
|
|
2571
|
-
case "done":
|
|
2572
|
-
adapterProviderMetadata = responseReplayMetadata(
|
|
2573
|
-
event.providerMetadata
|
|
2574
|
-
);
|
|
2575
|
-
if (event.usage) {
|
|
2576
|
-
adapterUsage = event.usage;
|
|
2577
|
-
}
|
|
2578
|
-
break;
|
|
2579
|
-
default:
|
|
2580
|
-
yield event;
|
|
2581
2957
|
}
|
|
2958
|
+
throwIfAborted(signal);
|
|
2959
|
+
if (pendingToolCalls.size || toolCalls.some((call) => !endedToolIds.has(call.id)))
|
|
2960
|
+
throw invalidProviderResponse(
|
|
2961
|
+
"Stream ended with incomplete tool calls"
|
|
2962
|
+
);
|
|
2963
|
+
} catch (error) {
|
|
2964
|
+
yield providerErrorEvent(error, "RUNTIME_STREAM_ERROR");
|
|
2965
|
+
return;
|
|
2582
2966
|
}
|
|
2583
2967
|
if (toolCalls.length > 0) {
|
|
2584
2968
|
if (debug) {
|
|
@@ -2687,7 +3071,18 @@ var Runtime = class {
|
|
|
2687
3071
|
nextToolSearchState,
|
|
2688
3072
|
_iteration + 1
|
|
2689
3073
|
)) {
|
|
2690
|
-
|
|
3074
|
+
if (event.type === "done" && adapterUsage) {
|
|
3075
|
+
const promptTokens = adapterUsage.prompt_tokens + (event.usage?.prompt_tokens ?? 0);
|
|
3076
|
+
const completionTokens = adapterUsage.completion_tokens + (event.usage?.completion_tokens ?? 0);
|
|
3077
|
+
yield {
|
|
3078
|
+
...event,
|
|
3079
|
+
usage: {
|
|
3080
|
+
prompt_tokens: promptTokens,
|
|
3081
|
+
completion_tokens: completionTokens,
|
|
3082
|
+
total_tokens: (adapterUsage.total_tokens ?? adapterUsage.prompt_tokens + adapterUsage.completion_tokens) + (event.usage?.total_tokens ?? (event.usage?.prompt_tokens ?? 0) + (event.usage?.completion_tokens ?? 0))
|
|
3083
|
+
}
|
|
3084
|
+
};
|
|
3085
|
+
} else yield event;
|
|
2691
3086
|
}
|
|
2692
3087
|
return;
|
|
2693
3088
|
}
|
|
@@ -2823,6 +3218,8 @@ var Runtime = class {
|
|
|
2823
3218
|
};
|
|
2824
3219
|
try {
|
|
2825
3220
|
const result = await this.adapter.complete(completionRequest);
|
|
3221
|
+
throwIfAborted(signal);
|
|
3222
|
+
validateToolCalls(result.toolCalls);
|
|
2826
3223
|
if (result.usage) {
|
|
2827
3224
|
accumulatedUsage.prompt_tokens += result.usage.promptTokens;
|
|
2828
3225
|
accumulatedUsage.completion_tokens += result.usage.completionTokens;
|
|
@@ -2876,6 +3273,7 @@ var Runtime = class {
|
|
|
2876
3273
|
const serverToolResults = [];
|
|
2877
3274
|
const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
|
|
2878
3275
|
for (const tc of serverToolCalls) {
|
|
3276
|
+
throwIfAborted(signal);
|
|
2879
3277
|
const tool2 = selectedToolMap.get(tc.name);
|
|
2880
3278
|
if (tool2?.handler) {
|
|
2881
3279
|
if (debug) {
|
|
@@ -2890,6 +3288,7 @@ var Runtime = class {
|
|
|
2890
3288
|
);
|
|
2891
3289
|
try {
|
|
2892
3290
|
const toolResult = await tool2.handler(tc.args, toolContext);
|
|
3291
|
+
throwIfAborted(signal);
|
|
2893
3292
|
const modelOutput = resolveToolOutput(
|
|
2894
3293
|
toolResult,
|
|
2895
3294
|
tool2.toModelOutput?.(toolResult)
|
|
@@ -2910,6 +3309,7 @@ var Runtime = class {
|
|
|
2910
3309
|
modelOutput
|
|
2911
3310
|
};
|
|
2912
3311
|
} catch (error) {
|
|
3312
|
+
throwIfAborted(signal);
|
|
2913
3313
|
const errorResult = {
|
|
2914
3314
|
success: false,
|
|
2915
3315
|
error: error instanceof Error ? error.message : "Tool execution failed"
|
|
@@ -3572,20 +3972,11 @@ function parseToolCalls(response) {
|
|
|
3572
3972
|
const message = choices?.[0]?.message;
|
|
3573
3973
|
const toolCalls = message?.tool_calls || [];
|
|
3574
3974
|
return toolCalls.map((tc) => {
|
|
3575
|
-
|
|
3576
|
-
try {
|
|
3577
|
-
input = JSON.parse(tc.function.arguments);
|
|
3578
|
-
} catch (e) {
|
|
3579
|
-
console.error(
|
|
3580
|
-
"Failed to parse tool arguments:",
|
|
3581
|
-
tc.function.arguments,
|
|
3582
|
-
e
|
|
3583
|
-
);
|
|
3584
|
-
}
|
|
3975
|
+
const input2 = parseToolArguments(tc.function.arguments);
|
|
3585
3976
|
return {
|
|
3586
3977
|
id: tc.id,
|
|
3587
3978
|
name: tc.function.name,
|
|
3588
|
-
input
|
|
3979
|
+
input: input2
|
|
3589
3980
|
};
|
|
3590
3981
|
});
|
|
3591
3982
|
}
|
|
@@ -3666,7 +4057,7 @@ function parseToolCalls2(response) {
|
|
|
3666
4057
|
return content.filter((block) => block?.type === "tool_use").map((block) => ({
|
|
3667
4058
|
id: block.id,
|
|
3668
4059
|
name: block.name,
|
|
3669
|
-
input: block.input
|
|
4060
|
+
input: parseToolArguments(block.input)
|
|
3670
4061
|
}));
|
|
3671
4062
|
}
|
|
3672
4063
|
function extractTextContent2(response) {
|
|
@@ -4000,7 +4391,11 @@ async function* runAgentLoop(options) {
|
|
|
4000
4391
|
providerTools,
|
|
4001
4392
|
providerToolOptions
|
|
4002
4393
|
);
|
|
4394
|
+
throwIfAborted(signal);
|
|
4003
4395
|
const toolCalls = formatter.parseToolCalls(response);
|
|
4396
|
+
validateToolCalls(
|
|
4397
|
+
toolCalls.map((call) => ({ ...call, args: call.input }))
|
|
4398
|
+
);
|
|
4004
4399
|
const textContent = formatter.extractTextContent(response);
|
|
4005
4400
|
if (textContent) {
|
|
4006
4401
|
const messageId = generateMessageId();
|
|
@@ -4015,15 +4410,13 @@ async function* runAgentLoop(options) {
|
|
|
4015
4410
|
toolCalls.map((tc) => tc.name)
|
|
4016
4411
|
);
|
|
4017
4412
|
}
|
|
4018
|
-
const results =
|
|
4413
|
+
const results = yield* executeToolCalls(
|
|
4019
4414
|
toolCalls,
|
|
4020
4415
|
effectiveSelectedTools,
|
|
4021
4416
|
executeServerTool,
|
|
4022
4417
|
waitForClientToolResult,
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
},
|
|
4026
|
-
debug
|
|
4418
|
+
debug,
|
|
4419
|
+
signal
|
|
4027
4420
|
);
|
|
4028
4421
|
for (const result of results) {
|
|
4029
4422
|
const toolCall = toolCalls.find((tc) => tc.id === result.toolCallId);
|
|
@@ -4112,9 +4505,10 @@ function buildConversation(messages, systemPrompt) {
|
|
|
4112
4505
|
}
|
|
4113
4506
|
return conversation;
|
|
4114
4507
|
}
|
|
4115
|
-
async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClientToolResult,
|
|
4508
|
+
async function* executeToolCalls(toolCalls, tools, executeServerTool, waitForClientToolResult, debug, signal) {
|
|
4116
4509
|
const results = [];
|
|
4117
4510
|
for (const toolCall of toolCalls) {
|
|
4511
|
+
throwIfAborted(signal);
|
|
4118
4512
|
const tool2 = tools.find((t) => t.name === toolCall.name);
|
|
4119
4513
|
if (!tool2) {
|
|
4120
4514
|
if (debug) {
|
|
@@ -4131,22 +4525,26 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
|
|
|
4131
4525
|
});
|
|
4132
4526
|
continue;
|
|
4133
4527
|
}
|
|
4134
|
-
|
|
4528
|
+
yield {
|
|
4135
4529
|
type: "action:start",
|
|
4136
4530
|
id: toolCall.id,
|
|
4137
4531
|
name: toolCall.name,
|
|
4138
4532
|
hidden: tool2.hidden ?? false
|
|
4139
|
-
}
|
|
4140
|
-
|
|
4533
|
+
};
|
|
4534
|
+
yield {
|
|
4141
4535
|
type: "action:args",
|
|
4142
4536
|
id: toolCall.id,
|
|
4143
4537
|
args: JSON.stringify(toolCall.input)
|
|
4144
|
-
}
|
|
4538
|
+
};
|
|
4145
4539
|
try {
|
|
4146
4540
|
let response;
|
|
4541
|
+
throwIfAborted(signal);
|
|
4147
4542
|
if (tool2.location === "server") {
|
|
4148
4543
|
if (tool2.handler) {
|
|
4149
|
-
response = await tool2.handler(toolCall.input
|
|
4544
|
+
response = await tool2.handler(toolCall.input, {
|
|
4545
|
+
signal,
|
|
4546
|
+
toolCallId: toolCall.id
|
|
4547
|
+
});
|
|
4150
4548
|
} else if (executeServerTool) {
|
|
4151
4549
|
response = await executeServerTool(toolCall.name, toolCall.input);
|
|
4152
4550
|
} else {
|
|
@@ -4169,12 +4567,13 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
|
|
|
4169
4567
|
};
|
|
4170
4568
|
}
|
|
4171
4569
|
}
|
|
4172
|
-
|
|
4570
|
+
throwIfAborted(signal);
|
|
4571
|
+
yield {
|
|
4173
4572
|
type: "action:end",
|
|
4174
4573
|
id: toolCall.id,
|
|
4175
4574
|
name: toolCall.name,
|
|
4176
4575
|
result: response
|
|
4177
|
-
}
|
|
4576
|
+
};
|
|
4178
4577
|
results.push({
|
|
4179
4578
|
toolCallId: toolCall.id,
|
|
4180
4579
|
content: JSON.stringify(response),
|
|
@@ -4182,13 +4581,14 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
|
|
|
4182
4581
|
error: response.error
|
|
4183
4582
|
});
|
|
4184
4583
|
} catch (error) {
|
|
4584
|
+
throwIfAborted(signal);
|
|
4185
4585
|
const errorMessage = error instanceof Error ? error.message : "Tool execution failed";
|
|
4186
|
-
|
|
4586
|
+
yield {
|
|
4187
4587
|
type: "action:end",
|
|
4188
4588
|
id: toolCall.id,
|
|
4189
4589
|
name: toolCall.name,
|
|
4190
4590
|
error: errorMessage
|
|
4191
|
-
}
|
|
4591
|
+
};
|
|
4192
4592
|
results.push({
|
|
4193
4593
|
toolCallId: toolCall.id,
|
|
4194
4594
|
content: JSON.stringify({
|
|
@@ -4205,17 +4605,17 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
|
|
|
4205
4605
|
|
|
4206
4606
|
// src/core/audio.ts
|
|
4207
4607
|
var audioErrorMarker = /* @__PURE__ */ Symbol.for("@yourgpt/llm-sdk/AudioAPIError");
|
|
4208
|
-
var
|
|
4608
|
+
var _a3;
|
|
4209
4609
|
var AudioAPIError = class extends Error {
|
|
4210
4610
|
constructor(message, code, status, requestId) {
|
|
4211
4611
|
super(message);
|
|
4212
4612
|
this.code = code;
|
|
4213
4613
|
this.status = status;
|
|
4214
4614
|
this.requestId = requestId;
|
|
4215
|
-
this[
|
|
4615
|
+
this[_a3] = true;
|
|
4216
4616
|
this.name = "AudioAPIError";
|
|
4217
4617
|
}
|
|
4218
|
-
static [(
|
|
4618
|
+
static [(_a3 = audioErrorMarker, Symbol.hasInstance)](value) {
|
|
4219
4619
|
return !!value && typeof value === "object" && value[audioErrorMarker] === true;
|
|
4220
4620
|
}
|
|
4221
4621
|
};
|
|
@@ -4250,6 +4650,6 @@ async function transcribe({
|
|
|
4250
4650
|
return result;
|
|
4251
4651
|
}
|
|
4252
4652
|
|
|
4253
|
-
export { AudioAPIError, DEFAULT_CAPABILITIES, DEFAULT_MAX_ITERATIONS, GenerateResult, Runtime, StreamResult, buildProviderToolOptions, createEventStream, createExpressHandler, createExpressMiddleware, createHonoApp, createNextHandler, createNodeHandler, createRuntime, createSSEHeaders, createSSEResponse, createStreamResult, createTextStreamHeaders, createTextStreamResponse, extractInputMessages, formatSSEData, formatToolsForAnthropic, formatToolsForGoogle, formatToolsForOpenAI, generateMessageId, generateSpeech, generateText, generateThreadId, generateToolCallId, mapOutputMessages, pipeSSEToResponse, pipeTextToResponse, runAgentLoop, searchTools, selectTools, shouldExposeToolSearch, streamText, tool, transcribe };
|
|
4653
|
+
export { AudioAPIError, DEFAULT_CAPABILITIES, DEFAULT_MAX_ITERATIONS, DecisionAPIError, GenerateResult, MediaAPIError, Runtime, StreamResult, buildProviderToolOptions, createEventStream, createExpressHandler, createExpressMiddleware, createHonoApp, createNextHandler, createNodeHandler, createRuntime, createSSEHeaders, createSSEResponse, createStreamResult, createTextStreamHeaders, createTextStreamResponse, experimental_decide, extractInputMessages, formatSSEData, formatToolsForAnthropic, formatToolsForGoogle, formatToolsForOpenAI, generateImage, generateMessageId, generateSpeech, generateText, generateThreadId, generateToolCallId, mapOutputMessages, pipeSSEToResponse, pipeTextToResponse, runAgentLoop, searchTools, selectTools, shouldExposeToolSearch, streamText, tool, transcribe };
|
|
4254
4654
|
//# sourceMappingURL=index.mjs.map
|
|
4255
4655
|
//# sourceMappingURL=index.mjs.map
|