ai 7.0.101 → 7.0.103
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/CHANGELOG.md +49 -0
- package/dist/index.d.ts +138 -22
- package/dist/index.js +2373 -316
- package/dist/index.js.map +1 -1
- package/dist/internal/index.js +2 -1
- package/dist/internal/index.js.map +1 -1
- package/dist/test/index.d.ts +16 -2
- package/dist/test/index.js +17 -0
- package/dist/test/index.js.map +1 -1
- package/docs/03-agents/07-workflow-agent.mdx +1 -1
- package/docs/03-ai-sdk-core/18-code-mode.mdx +39 -0
- package/docs/03-ai-sdk-core/32-evaluation.mdx +110 -0
- package/docs/03-ai-sdk-core/36-realtime.mdx +41 -18
- package/docs/03-ai-sdk-core/42-batch.mdx +1 -2
- package/docs/04-ai-sdk-ui/03-chatbot-message-persistence.mdx +35 -0
- package/docs/04-ai-sdk-ui/21-transport.mdx +1 -1
- package/docs/06-advanced/11-secure-url-fetching.mdx +8 -2
- package/docs/07-reference/01-ai-sdk-core/14-evaluate.mdx +54 -0
- package/docs/07-reference/01-ai-sdk-core/32-validate-ui-messages.mdx +12 -0
- package/docs/07-reference/01-ai-sdk-core/33-safe-validate-ui-messages.mdx +12 -0
- package/docs/07-reference/02-ai-sdk-ui/05-use-realtime.mdx +364 -48
- package/docs/07-reference/02-ai-sdk-ui/31-convert-to-model-messages.mdx +12 -0
- package/docs/07-reference/04-ai-sdk-workflow/02-workflow-chat-transport.mdx +4 -4
- package/docs/07-reference/05-ai-sdk-errors/ai-evaluation-unsupported-question-type-error.mdx +31 -0
- package/docs/07-reference/05-ai-sdk-errors/index.mdx +131 -36
- package/package.json +12 -12
- package/src/error/index.ts +1 -0
- package/src/evaluate/evaluate.ts +112 -0
- package/src/evaluate/evaluation-result.ts +39 -0
- package/src/evaluate/index.ts +7 -0
- package/src/evaluate/validate-evaluation.ts +298 -0
- package/src/generate-text/execute-tools-from-stream.ts +7 -0
- package/src/generate-text/generate-text.ts +16 -12
- package/src/generate-text/stream-text.ts +9 -2
- package/src/generate-text/tool-caller-configuration.ts +58 -4
- package/src/index.ts +1 -0
- package/src/realtime/__fixtures__/fake-live-websocket.ts +71 -0
- package/src/realtime/__fixtures__/fake-realtime.ts +36 -0
- package/src/realtime/__fixtures__/fake-webrtc.ts +133 -0
- package/src/realtime/browser-realtime-audio.ts +107 -10
- package/src/realtime/browser-realtime-live-websocket.ts +247 -0
- package/src/realtime/browser-realtime-transport.ts +235 -69
- package/src/realtime/browser-realtime-webrtc.ts +582 -0
- package/src/realtime/encode-realtime-frame.ts +33 -0
- package/src/realtime/index.ts +1 -0
- package/src/realtime/realtime-attempt.ts +45 -0
- package/src/realtime/realtime-command-tracker.ts +81 -0
- package/src/realtime/realtime-event-channel.ts +170 -0
- package/src/realtime/realtime-event-reducer.ts +3 -0
- package/src/realtime/realtime-session-state.ts +65 -0
- package/src/realtime/realtime-session.ts +768 -218
- package/src/realtime/realtime-types.ts +1 -1
- package/src/realtime/validate-realtime-setup.ts +37 -0
- package/src/test/evaluation-mock-model-v4.ts +27 -0
- package/src/ui/convert-to-model-messages.ts +3 -0
- package/src/ui/process-ui-message-stream.ts +4 -0
- package/src/ui/ui-messages.ts +5 -1
- package/src/ui/validate-ui-messages.ts +3 -0
- package/src/ui/warn-if-ui-message-has-deprecated-raw-input.ts +36 -0
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
createIdGenerator as createIdGenerator9,
|
|
15
15
|
dynamicTool,
|
|
16
16
|
experimental_toolCaller,
|
|
17
|
-
generateId as
|
|
17
|
+
generateId as generateId4,
|
|
18
18
|
jsonSchema,
|
|
19
19
|
parseJsonEventStream as parseJsonEventStream3,
|
|
20
20
|
tool,
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
AISDKError as AISDKError25,
|
|
41
41
|
APICallError,
|
|
42
42
|
EmptyResponseBodyError,
|
|
43
|
+
Experimental_EvaluationUnsupportedQuestionTypeError,
|
|
43
44
|
InvalidPromptError,
|
|
44
45
|
InvalidResponseDataError,
|
|
45
46
|
JSONParseError,
|
|
@@ -1178,7 +1179,7 @@ import {
|
|
|
1178
1179
|
} from "@ai-sdk/provider-utils";
|
|
1179
1180
|
|
|
1180
1181
|
// src/version.ts
|
|
1181
|
-
var VERSION = true ? "7.0.
|
|
1182
|
+
var VERSION = true ? "7.0.103" : "0.0.0-test";
|
|
1182
1183
|
|
|
1183
1184
|
// src/util/download/download.ts
|
|
1184
1185
|
var download = async ({
|
|
@@ -5248,11 +5249,16 @@ function prepareToolsForToolCallers({
|
|
|
5248
5249
|
}) {
|
|
5249
5250
|
var _a25, _b25;
|
|
5250
5251
|
if (tools == null || toolCallers == null) {
|
|
5251
|
-
return {
|
|
5252
|
+
return {
|
|
5253
|
+
executionTools: tools,
|
|
5254
|
+
modelTools: tools,
|
|
5255
|
+
toolCallerMessages: []
|
|
5256
|
+
};
|
|
5252
5257
|
}
|
|
5253
5258
|
const executionTools = { ...tools };
|
|
5254
5259
|
const modelTools = { ...tools };
|
|
5255
5260
|
const localToolsByCaller = /* @__PURE__ */ new Map();
|
|
5261
|
+
const toolCallerMessages = [];
|
|
5256
5262
|
for (const [toolName, callerNames] of Object.entries(toolCallers)) {
|
|
5257
5263
|
const tool2 = executionTools[toolName];
|
|
5258
5264
|
if (tool2 == null) {
|
|
@@ -5296,13 +5302,44 @@ function prepareToolsForToolCallers({
|
|
|
5296
5302
|
if ((caller == null ? void 0 : caller.type) !== "local") {
|
|
5297
5303
|
continue;
|
|
5298
5304
|
}
|
|
5299
|
-
const
|
|
5305
|
+
const callerTools = (_b25 = localToolsByCaller.get(callerName)) != null ? _b25 : {};
|
|
5306
|
+
const boundCaller = caller.bind(callerTools);
|
|
5300
5307
|
executionTools[callerName] = boundCaller;
|
|
5301
5308
|
if (Object.prototype.hasOwnProperty.call(modelTools, callerName)) {
|
|
5302
|
-
|
|
5309
|
+
if (caller.prepareModelMessage == null) {
|
|
5310
|
+
modelTools[callerName] = boundCaller;
|
|
5311
|
+
} else {
|
|
5312
|
+
const content = caller.prepareModelMessage(callerTools);
|
|
5313
|
+
if (content != null) {
|
|
5314
|
+
toolCallerMessages.push({ role: "user", content });
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5303
5317
|
}
|
|
5304
5318
|
}
|
|
5305
|
-
return { executionTools, modelTools };
|
|
5319
|
+
return { executionTools, modelTools, toolCallerMessages };
|
|
5320
|
+
}
|
|
5321
|
+
function appendToolCallerMessages({
|
|
5322
|
+
messages,
|
|
5323
|
+
toolCallerMessages
|
|
5324
|
+
}) {
|
|
5325
|
+
var _a25;
|
|
5326
|
+
if (toolCallerMessages.length === 0) {
|
|
5327
|
+
return messages;
|
|
5328
|
+
}
|
|
5329
|
+
const latestUserText = (_a25 = messages.findLast(
|
|
5330
|
+
(message) => message.role === "user" && typeof message.content === "string"
|
|
5331
|
+
)) == null ? void 0 : _a25.content;
|
|
5332
|
+
const existingUserText = new Set(
|
|
5333
|
+
latestUserText == null ? [] : [latestUserText]
|
|
5334
|
+
);
|
|
5335
|
+
const additions = toolCallerMessages.filter((message) => {
|
|
5336
|
+
if (typeof message.content !== "string" || existingUserText.has(message.content)) {
|
|
5337
|
+
return false;
|
|
5338
|
+
}
|
|
5339
|
+
existingUserText.add(message.content);
|
|
5340
|
+
return true;
|
|
5341
|
+
});
|
|
5342
|
+
return additions.length === 0 ? messages : [...messages, ...additions];
|
|
5306
5343
|
}
|
|
5307
5344
|
|
|
5308
5345
|
// src/generate-text/tool-approval-signature.ts
|
|
@@ -5556,7 +5593,7 @@ async function generateText({
|
|
|
5556
5593
|
experimental_include,
|
|
5557
5594
|
include = experimental_include,
|
|
5558
5595
|
_internal: {
|
|
5559
|
-
generateId:
|
|
5596
|
+
generateId: generateId5 = originalGenerateId,
|
|
5560
5597
|
generateCallId = originalGenerateCallId,
|
|
5561
5598
|
now: now2 = now
|
|
5562
5599
|
} = {},
|
|
@@ -5825,7 +5862,7 @@ async function generateText({
|
|
|
5825
5862
|
type: "step",
|
|
5826
5863
|
event: { callId, stepNumber },
|
|
5827
5864
|
execute: async () => {
|
|
5828
|
-
var _a27, _b26, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p
|
|
5865
|
+
var _a27, _b26, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
5829
5866
|
const accumulatedResponseMessages = [
|
|
5830
5867
|
...initialResponseMessages,
|
|
5831
5868
|
...steps.flatMap((step) => step.response.messages)
|
|
@@ -5849,29 +5886,21 @@ async function generateText({
|
|
|
5849
5886
|
(_b26 = prepareStepResult == null ? void 0 : prepareStepResult.model) != null ? _b26 : model
|
|
5850
5887
|
);
|
|
5851
5888
|
const stepInstructions = (_d2 = (_c2 = prepareStepResult == null ? void 0 : prepareStepResult.instructions) != null ? _c2 : prepareStepResult == null ? void 0 : prepareStepResult.system) != null ? _d2 : instructionsForNextStep;
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
instructions: stepInstructions,
|
|
5855
|
-
messages: (_e = prepareStepResult == null ? void 0 : prepareStepResult.messages) != null ? _e : stepInputMessages
|
|
5856
|
-
},
|
|
5857
|
-
supportedUrls: await stepModel.supportedUrls,
|
|
5858
|
-
download: download2,
|
|
5859
|
-
provider: stepModel.provider.split(".")[0]
|
|
5860
|
-
});
|
|
5861
|
-
runtimeContext = (_f = prepareStepResult == null ? void 0 : prepareStepResult.runtimeContext) != null ? _f : runtimeContext;
|
|
5862
|
-
toolsContext = (_g = prepareStepResult == null ? void 0 : prepareStepResult.toolsContext) != null ? _g : toolsContext;
|
|
5889
|
+
runtimeContext = (_e = prepareStepResult == null ? void 0 : prepareStepResult.runtimeContext) != null ? _e : runtimeContext;
|
|
5890
|
+
toolsContext = (_f = prepareStepResult == null ? void 0 : prepareStepResult.toolsContext) != null ? _f : toolsContext;
|
|
5863
5891
|
const stepActiveTools = filterActiveTools({
|
|
5864
5892
|
tools,
|
|
5865
|
-
activeTools: (
|
|
5893
|
+
activeTools: (_g = prepareStepResult == null ? void 0 : prepareStepResult.activeTools) != null ? _g : activeTools
|
|
5866
5894
|
});
|
|
5867
5895
|
const {
|
|
5868
5896
|
executionTools: stepExecutionTools,
|
|
5869
|
-
modelTools: stepModelTools
|
|
5897
|
+
modelTools: stepModelTools,
|
|
5898
|
+
toolCallerMessages
|
|
5870
5899
|
} = prepareToolsForToolCallers({
|
|
5871
5900
|
tools: stepActiveTools,
|
|
5872
5901
|
toolCallers: resolvedToolCallers
|
|
5873
5902
|
});
|
|
5874
|
-
const stepToolOrder = (
|
|
5903
|
+
const stepToolOrder = (_h = prepareStepResult == null ? void 0 : prepareStepResult.toolOrder) != null ? _h : toolOrder;
|
|
5875
5904
|
const stepTools = await prepareTools({
|
|
5876
5905
|
tools: stepModelTools,
|
|
5877
5906
|
toolOrder: stepToolOrder,
|
|
@@ -5880,9 +5909,21 @@ async function generateText({
|
|
|
5880
5909
|
experimental_sandbox: stepSandbox
|
|
5881
5910
|
});
|
|
5882
5911
|
const stepToolChoice = prepareToolChoice({
|
|
5883
|
-
toolChoice: (
|
|
5912
|
+
toolChoice: (_i = prepareStepResult == null ? void 0 : prepareStepResult.toolChoice) != null ? _i : toolChoice
|
|
5913
|
+
});
|
|
5914
|
+
const stepMessages = appendToolCallerMessages({
|
|
5915
|
+
messages: (_j = prepareStepResult == null ? void 0 : prepareStepResult.messages) != null ? _j : stepInputMessages,
|
|
5916
|
+
toolCallerMessages
|
|
5917
|
+
});
|
|
5918
|
+
const promptMessages = await convertToLanguageModelPrompt({
|
|
5919
|
+
prompt: {
|
|
5920
|
+
instructions: stepInstructions,
|
|
5921
|
+
messages: stepMessages
|
|
5922
|
+
},
|
|
5923
|
+
supportedUrls: await stepModel.supportedUrls,
|
|
5924
|
+
download: download2,
|
|
5925
|
+
provider: stepModel.provider.split(".")[0]
|
|
5884
5926
|
});
|
|
5885
|
-
const stepMessages = (_k = prepareStepResult == null ? void 0 : prepareStepResult.messages) != null ? _k : stepInputMessages;
|
|
5886
5927
|
const stepProviderOptions = mergeObjects(
|
|
5887
5928
|
providerOptions,
|
|
5888
5929
|
prepareStepResult == null ? void 0 : prepareStepResult.providerOptions
|
|
@@ -5900,8 +5941,8 @@ async function generateText({
|
|
|
5900
5941
|
instructions: stepInstructions,
|
|
5901
5942
|
messages: stepMessages,
|
|
5902
5943
|
tools,
|
|
5903
|
-
toolChoice: (
|
|
5904
|
-
activeTools: (
|
|
5944
|
+
toolChoice: (_k = prepareStepResult == null ? void 0 : prepareStepResult.toolChoice) != null ? _k : toolChoice,
|
|
5945
|
+
activeTools: (_l = prepareStepResult == null ? void 0 : prepareStepResult.activeTools) != null ? _l : activeTools,
|
|
5905
5946
|
toolOrder: stepToolOrder,
|
|
5906
5947
|
steps: [...steps],
|
|
5907
5948
|
providerOptions: stepProviderOptions,
|
|
@@ -5937,7 +5978,7 @@ async function generateText({
|
|
|
5937
5978
|
telemetryDispatcher.onLanguageModelCallStart
|
|
5938
5979
|
]
|
|
5939
5980
|
});
|
|
5940
|
-
const executeLanguageModelCallInTelemetryContext = (
|
|
5981
|
+
const executeLanguageModelCallInTelemetryContext = (_m = telemetryDispatcher.executeLanguageModelCall) != null ? _m : (async ({ execute }) => await execute());
|
|
5941
5982
|
currentModelResponse = await retry(async () => {
|
|
5942
5983
|
var _a28, _b27, _c3, _d3, _e2, _f2, _g2, _h2;
|
|
5943
5984
|
const result = await executeLanguageModelCallInTelemetryContext(
|
|
@@ -5956,7 +5997,7 @@ async function generateText({
|
|
|
5956
5997
|
}
|
|
5957
5998
|
);
|
|
5958
5999
|
const responseData = {
|
|
5959
|
-
id: (_b27 = (_a28 = result.response) == null ? void 0 : _a28.id) != null ? _b27 :
|
|
6000
|
+
id: (_b27 = (_a28 = result.response) == null ? void 0 : _a28.id) != null ? _b27 : generateId5(),
|
|
5960
6001
|
timestamp: (_d3 = (_c3 = result.response) == null ? void 0 : _c3.timestamp) != null ? _d3 : /* @__PURE__ */ new Date(),
|
|
5961
6002
|
modelId: (_f2 = (_e2 = result.response) == null ? void 0 : _e2.modelId) != null ? _f2 : stepModel.modelId,
|
|
5962
6003
|
headers: (_g2 = result.response) == null ? void 0 : _g2.headers,
|
|
@@ -6076,7 +6117,7 @@ async function generateText({
|
|
|
6076
6117
|
if (toolApprovalStatus.type === "not-applicable") {
|
|
6077
6118
|
continue;
|
|
6078
6119
|
}
|
|
6079
|
-
const approvalId =
|
|
6120
|
+
const approvalId = generateId5();
|
|
6080
6121
|
const signature = await maybeSignApproval({
|
|
6081
6122
|
secret: experimental_toolApprovalSecret,
|
|
6082
6123
|
approvalId,
|
|
@@ -6246,7 +6287,7 @@ async function generateText({
|
|
|
6246
6287
|
});
|
|
6247
6288
|
const stepRequest = {
|
|
6248
6289
|
...currentModelResponse.request,
|
|
6249
|
-
body: include.requestBody ? (
|
|
6290
|
+
body: include.requestBody ? (_n = currentModelResponse.request) == null ? void 0 : _n.body : void 0,
|
|
6250
6291
|
messages: include.requestMessages ? cloneModelMessages(stepMessages) : void 0
|
|
6251
6292
|
};
|
|
6252
6293
|
const stepResponse = {
|
|
@@ -6254,7 +6295,7 @@ async function generateText({
|
|
|
6254
6295
|
// deep clone msgs to avoid mutating step results in multi-step:
|
|
6255
6296
|
messages: cloneModelMessages(stepResponseMessages),
|
|
6256
6297
|
// Conditionally include response body:
|
|
6257
|
-
body: include.responseBody ? (
|
|
6298
|
+
body: include.responseBody ? (_o = currentModelResponse.response) == null ? void 0 : _o.body : void 0
|
|
6258
6299
|
};
|
|
6259
6300
|
const currentStepResult = new DefaultStepResult({
|
|
6260
6301
|
callId,
|
|
@@ -6274,7 +6315,7 @@ async function generateText({
|
|
|
6274
6315
|
toolsContext
|
|
6275
6316
|
});
|
|
6276
6317
|
logWarnings({
|
|
6277
|
-
warnings: (
|
|
6318
|
+
warnings: (_p = currentModelResponse.warnings) != null ? _p : [],
|
|
6278
6319
|
provider: stepModel.provider,
|
|
6279
6320
|
model: stepModel.modelId
|
|
6280
6321
|
});
|
|
@@ -6970,6 +7011,25 @@ function getToolName(part) {
|
|
|
6970
7011
|
}
|
|
6971
7012
|
var getToolOrDynamicToolName = getToolName;
|
|
6972
7013
|
|
|
7014
|
+
// src/ui/warn-if-ui-message-has-deprecated-raw-input.ts
|
|
7015
|
+
var rawInputDeprecationWarning = {
|
|
7016
|
+
type: "deprecated",
|
|
7017
|
+
setting: "rawInput in output-error UI message parts",
|
|
7018
|
+
message: 'Use the "input" field instead. The "rawInput" field will be removed in the next major version.'
|
|
7019
|
+
};
|
|
7020
|
+
function warnIfUIMessageHasDeprecatedRawInput(messages) {
|
|
7021
|
+
const hasDeprecatedRawInput = messages.some(
|
|
7022
|
+
(message) => message.parts.some(
|
|
7023
|
+
(part) => part != null && typeof part === "object" && "type" in part && typeof part.type === "string" && (part.type === "dynamic-tool" || part.type.startsWith("tool-")) && "state" in part && part.state === "output-error" && Object.prototype.hasOwnProperty.call(part, "rawInput") && "rawInput" in part && part.rawInput !== void 0
|
|
7024
|
+
)
|
|
7025
|
+
);
|
|
7026
|
+
if (hasDeprecatedRawInput) {
|
|
7027
|
+
logWarnings({
|
|
7028
|
+
warnings: [rawInputDeprecationWarning]
|
|
7029
|
+
});
|
|
7030
|
+
}
|
|
7031
|
+
}
|
|
7032
|
+
|
|
6973
7033
|
// src/ui/process-ui-message-stream.ts
|
|
6974
7034
|
function createStreamingUIMessageState({
|
|
6975
7035
|
lastMessage,
|
|
@@ -7423,6 +7483,7 @@ function processUIMessageStream({
|
|
|
7423
7483
|
providerMetadata: chunk.providerMetadata,
|
|
7424
7484
|
toolMetadata: chunk.toolMetadata
|
|
7425
7485
|
});
|
|
7486
|
+
warnIfUIMessageHasDeprecatedRawInput([state.message]);
|
|
7426
7487
|
}
|
|
7427
7488
|
write();
|
|
7428
7489
|
break;
|
|
@@ -8400,7 +8461,7 @@ function executeToolsFromStream({
|
|
|
8400
8461
|
toolApproval,
|
|
8401
8462
|
runtimeContext,
|
|
8402
8463
|
toolApprovalSecret,
|
|
8403
|
-
generateId:
|
|
8464
|
+
generateId: generateId5,
|
|
8404
8465
|
onToolExecutionStart,
|
|
8405
8466
|
onToolExecutionEnd,
|
|
8406
8467
|
executeToolInTelemetryContext,
|
|
@@ -8439,7 +8500,7 @@ function executeToolsFromStream({
|
|
|
8439
8500
|
}
|
|
8440
8501
|
return;
|
|
8441
8502
|
}
|
|
8442
|
-
const approvalId =
|
|
8503
|
+
const approvalId = generateId5();
|
|
8443
8504
|
const signature = await maybeSignApproval({
|
|
8444
8505
|
secret: toolApprovalSecret,
|
|
8445
8506
|
approvalId,
|
|
@@ -8474,6 +8535,11 @@ function executeToolsFromStream({
|
|
|
8474
8535
|
reason: toolApprovalStatus.reason,
|
|
8475
8536
|
providerExecuted: chunk.providerExecuted
|
|
8476
8537
|
});
|
|
8538
|
+
controller.enqueue({
|
|
8539
|
+
type: "tool-output-denied",
|
|
8540
|
+
toolCallId: chunk.toolCallId,
|
|
8541
|
+
toolName: chunk.toolName
|
|
8542
|
+
});
|
|
8477
8543
|
return;
|
|
8478
8544
|
}
|
|
8479
8545
|
case "approved": {
|
|
@@ -8722,7 +8788,7 @@ async function streamLanguageModelCall({
|
|
|
8722
8788
|
toolsContext,
|
|
8723
8789
|
experimental_sandbox: sandbox,
|
|
8724
8790
|
_internal: {
|
|
8725
|
-
generateId:
|
|
8791
|
+
generateId: generateId5 = originalGenerateId2,
|
|
8726
8792
|
generateCallId = originalGenerateCallId2,
|
|
8727
8793
|
now: now2 = now
|
|
8728
8794
|
} = {},
|
|
@@ -8808,7 +8874,7 @@ async function streamLanguageModelCall({
|
|
|
8808
8874
|
provider: resolvedModel.provider,
|
|
8809
8875
|
modelId: resolvedModel.modelId,
|
|
8810
8876
|
toolChoice: stepToolChoice,
|
|
8811
|
-
generateId:
|
|
8877
|
+
generateId: generateId5,
|
|
8812
8878
|
now: now2,
|
|
8813
8879
|
callStartTimestampMs,
|
|
8814
8880
|
onLanguageModelCallEnd
|
|
@@ -8830,7 +8896,7 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform({
|
|
|
8830
8896
|
provider,
|
|
8831
8897
|
modelId,
|
|
8832
8898
|
toolChoice,
|
|
8833
|
-
generateId:
|
|
8899
|
+
generateId: generateId5,
|
|
8834
8900
|
now: now2,
|
|
8835
8901
|
callStartTimestampMs,
|
|
8836
8902
|
onLanguageModelCallEnd
|
|
@@ -8842,7 +8908,7 @@ function createLanguageModelV4StreamPartToLanguageModelStreamPartTransform({
|
|
|
8842
8908
|
const reasoningPartIndexes = /* @__PURE__ */ new Map();
|
|
8843
8909
|
const rawTextPartIndexes = /* @__PURE__ */ new Map();
|
|
8844
8910
|
const rawReasoningPartIndexes = /* @__PURE__ */ new Map();
|
|
8845
|
-
let responseId =
|
|
8911
|
+
let responseId = generateId5();
|
|
8846
8912
|
let responseModelId = modelId;
|
|
8847
8913
|
let timeToFirstOutputMs;
|
|
8848
8914
|
let previousOutputChunkTimestampMs;
|
|
@@ -9249,6 +9315,7 @@ var isOutputChunkType = {
|
|
|
9249
9315
|
"tool-call": true,
|
|
9250
9316
|
"tool-result": false,
|
|
9251
9317
|
"tool-error": false,
|
|
9318
|
+
"tool-output-denied": false,
|
|
9252
9319
|
"tool-execution-end": false,
|
|
9253
9320
|
"model-call-start": false,
|
|
9254
9321
|
"model-call-response-metadata": false,
|
|
@@ -9331,7 +9398,7 @@ function streamText({
|
|
|
9331
9398
|
include = experimental_include,
|
|
9332
9399
|
_internal: {
|
|
9333
9400
|
now: now2 = now,
|
|
9334
|
-
generateId:
|
|
9401
|
+
generateId: generateId5 = originalGenerateId3,
|
|
9335
9402
|
generateCallId = originalGenerateCallId3
|
|
9336
9403
|
} = {},
|
|
9337
9404
|
...settings
|
|
@@ -9410,7 +9477,7 @@ function streamText({
|
|
|
9410
9477
|
onToolExecutionStart: resolvedOnToolExecutionStart,
|
|
9411
9478
|
onToolExecutionEnd: resolvedOnToolExecutionEnd,
|
|
9412
9479
|
now: now2,
|
|
9413
|
-
generateId:
|
|
9480
|
+
generateId: generateId5,
|
|
9414
9481
|
generateCallId,
|
|
9415
9482
|
download: download2,
|
|
9416
9483
|
// assign default values to include:
|
|
@@ -9638,7 +9705,7 @@ var DefaultStreamTextResult = class {
|
|
|
9638
9705
|
providerOptions,
|
|
9639
9706
|
prepareStep,
|
|
9640
9707
|
now: now2,
|
|
9641
|
-
generateId:
|
|
9708
|
+
generateId: generateId5,
|
|
9642
9709
|
generateCallId,
|
|
9643
9710
|
timeout,
|
|
9644
9711
|
onChunk,
|
|
@@ -9693,7 +9760,7 @@ var DefaultStreamTextResult = class {
|
|
|
9693
9760
|
usedIds.add(id);
|
|
9694
9761
|
return id;
|
|
9695
9762
|
}
|
|
9696
|
-
const generatedId =
|
|
9763
|
+
const generatedId = generateId5();
|
|
9697
9764
|
let uniqueId = generatedId;
|
|
9698
9765
|
let suffix = 0;
|
|
9699
9766
|
while (usedIds.has(uniqueId)) {
|
|
@@ -10374,7 +10441,8 @@ var DefaultStreamTextResult = class {
|
|
|
10374
10441
|
});
|
|
10375
10442
|
const {
|
|
10376
10443
|
executionTools: stepExecutionTools,
|
|
10377
|
-
modelTools: stepModelTools
|
|
10444
|
+
modelTools: stepModelTools,
|
|
10445
|
+
toolCallerMessages
|
|
10378
10446
|
} = prepareToolsForToolCallers({
|
|
10379
10447
|
tools: stepActiveTools,
|
|
10380
10448
|
toolCallers: resolvedToolCallers
|
|
@@ -10390,7 +10458,10 @@ var DefaultStreamTextResult = class {
|
|
|
10390
10458
|
const stepToolChoice = prepareToolChoice({
|
|
10391
10459
|
toolChoice: (_h = prepareStepResult == null ? void 0 : prepareStepResult.toolChoice) != null ? _h : toolChoice
|
|
10392
10460
|
});
|
|
10393
|
-
const stepMessages = (
|
|
10461
|
+
const stepMessages = appendToolCallerMessages({
|
|
10462
|
+
messages: (_i = prepareStepResult == null ? void 0 : prepareStepResult.messages) != null ? _i : stepInputMessages,
|
|
10463
|
+
toolCallerMessages
|
|
10464
|
+
});
|
|
10394
10465
|
currentStepMessages = stepMessages;
|
|
10395
10466
|
const stepInstructions = (_k = (_j = prepareStepResult == null ? void 0 : prepareStepResult.instructions) != null ? _j : prepareStepResult == null ? void 0 : prepareStepResult.system) != null ? _k : instructionsForNextStep;
|
|
10396
10467
|
instructionsForNextStep = stepInstructions;
|
|
@@ -10628,7 +10699,7 @@ var DefaultStreamTextResult = class {
|
|
|
10628
10699
|
toolApproval,
|
|
10629
10700
|
runtimeContext,
|
|
10630
10701
|
toolApprovalSecret: experimental_toolApprovalSecret,
|
|
10631
|
-
generateId:
|
|
10702
|
+
generateId: generateId5,
|
|
10632
10703
|
// the callbacks need to be passed down and handled by executeToolCall
|
|
10633
10704
|
// to guarantee that the onToolExecutionStart callback is invoked before the tool execute function
|
|
10634
10705
|
onToolExecutionStart: filterNullable2(
|
|
@@ -10671,7 +10742,7 @@ var DefaultStreamTextResult = class {
|
|
|
10671
10742
|
let modelCallPerformance = createModelCallPerformance();
|
|
10672
10743
|
const toolExecutionMs = {};
|
|
10673
10744
|
const createStepResponse = () => ({
|
|
10674
|
-
id:
|
|
10745
|
+
id: generateId5(),
|
|
10675
10746
|
timestamp: /* @__PURE__ */ new Date(),
|
|
10676
10747
|
modelId: model.modelId
|
|
10677
10748
|
});
|
|
@@ -10737,7 +10808,8 @@ var DefaultStreamTextResult = class {
|
|
|
10737
10808
|
case "tool-input-start":
|
|
10738
10809
|
case "tool-input-end":
|
|
10739
10810
|
case "tool-input-delta":
|
|
10740
|
-
case "tool-approval-request":
|
|
10811
|
+
case "tool-approval-request":
|
|
10812
|
+
case "tool-output-denied": {
|
|
10741
10813
|
enqueueStepPart(controller, chunk);
|
|
10742
10814
|
break;
|
|
10743
10815
|
}
|
|
@@ -11501,7 +11573,7 @@ function createUIMessageStream({
|
|
|
11501
11573
|
onStepFinish,
|
|
11502
11574
|
onEnd,
|
|
11503
11575
|
onFinish,
|
|
11504
|
-
generateId:
|
|
11576
|
+
generateId: generateId5 = generateIdFunc
|
|
11505
11577
|
}) {
|
|
11506
11578
|
let controller;
|
|
11507
11579
|
const ongoingStreamPromises = [];
|
|
@@ -11593,7 +11665,7 @@ function createUIMessageStream({
|
|
|
11593
11665
|
});
|
|
11594
11666
|
return handleUIMessageStreamFinish({
|
|
11595
11667
|
stream,
|
|
11596
|
-
messageId:
|
|
11668
|
+
messageId: generateId5(),
|
|
11597
11669
|
originalMessages,
|
|
11598
11670
|
onStepEnd: onStepEnd != null ? onStepEnd : onStepFinish,
|
|
11599
11671
|
onEnd: onEnd != null ? onEnd : onFinish,
|
|
@@ -11677,6 +11749,7 @@ import {
|
|
|
11677
11749
|
} from "@ai-sdk/provider-utils";
|
|
11678
11750
|
async function convertToModelMessages(messages, options) {
|
|
11679
11751
|
const modelMessages = [];
|
|
11752
|
+
warnIfUIMessageHasDeprecatedRawInput(messages);
|
|
11680
11753
|
if (options == null ? void 0 : options.ignoreIncompleteToolCalls) {
|
|
11681
11754
|
messages = messages.map((message) => ({
|
|
11682
11755
|
...message,
|
|
@@ -12350,6 +12423,7 @@ async function safeValidateUIMessagesInternal({
|
|
|
12350
12423
|
value: messages,
|
|
12351
12424
|
schema: uiMessagesSchema
|
|
12352
12425
|
});
|
|
12426
|
+
warnIfUIMessageHasDeprecatedRawInput(validatedMessages);
|
|
12353
12427
|
if (metadataSchema) {
|
|
12354
12428
|
for (const [msgIdx, message] of validatedMessages.entries()) {
|
|
12355
12429
|
await validateTypes4({
|
|
@@ -13982,10 +14056,318 @@ var DefaultEmbedManyResult = class {
|
|
|
13982
14056
|
}
|
|
13983
14057
|
};
|
|
13984
14058
|
|
|
14059
|
+
// src/evaluate/evaluate.ts
|
|
14060
|
+
import {
|
|
14061
|
+
Experimental_EvaluationUnsupportedQuestionTypeError as EvaluationUnsupportedQuestionTypeError
|
|
14062
|
+
} from "@ai-sdk/provider";
|
|
14063
|
+
import {
|
|
14064
|
+
withUserAgentSuffix as withUserAgentSuffix8
|
|
14065
|
+
} from "@ai-sdk/provider-utils";
|
|
14066
|
+
|
|
14067
|
+
// src/evaluate/validate-evaluation.ts
|
|
14068
|
+
import {
|
|
14069
|
+
InvalidResponseDataError as InvalidResponseDataError3
|
|
14070
|
+
} from "@ai-sdk/provider";
|
|
14071
|
+
var tolerance = 1e-6;
|
|
14072
|
+
function isRecord(value) {
|
|
14073
|
+
if (value == null || typeof value !== "object" || Array.isArray(value))
|
|
14074
|
+
return false;
|
|
14075
|
+
const prototype = Object.getPrototypeOf(value);
|
|
14076
|
+
return prototype === Object.prototype || prototype === null;
|
|
14077
|
+
}
|
|
14078
|
+
function isJSON(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
14079
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
14080
|
+
return true;
|
|
14081
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
14082
|
+
if (typeof value !== "object" || !Array.isArray(value) && !isRecord(value))
|
|
14083
|
+
return false;
|
|
14084
|
+
if (ancestors.has(value)) return false;
|
|
14085
|
+
ancestors.add(value);
|
|
14086
|
+
const valid = Object.getOwnPropertySymbols(value).length === 0 && (Array.isArray(value) ? Array.from(value).every((item) => isJSON(item, ancestors)) : Object.values(value).every((item) => isJSON(item, ancestors)));
|
|
14087
|
+
ancestors.delete(value);
|
|
14088
|
+
return valid;
|
|
14089
|
+
}
|
|
14090
|
+
function isInput(value) {
|
|
14091
|
+
return (typeof value === "string" || Array.isArray(value) || isRecord(value)) && isJSON(value);
|
|
14092
|
+
}
|
|
14093
|
+
function invalidInput(parameter, value, message) {
|
|
14094
|
+
throw new InvalidArgumentError({ parameter, value, message });
|
|
14095
|
+
}
|
|
14096
|
+
function validateEvaluationInput({
|
|
14097
|
+
state,
|
|
14098
|
+
questions
|
|
14099
|
+
}) {
|
|
14100
|
+
if (!isInput(state)) {
|
|
14101
|
+
invalidInput(
|
|
14102
|
+
"state",
|
|
14103
|
+
state,
|
|
14104
|
+
"must be a JSON-compatible string, object, or array"
|
|
14105
|
+
);
|
|
14106
|
+
}
|
|
14107
|
+
if (!isRecord(questions) || Object.keys(questions).length === 0) {
|
|
14108
|
+
invalidInput("questions", questions, "must be a nonempty question map");
|
|
14109
|
+
}
|
|
14110
|
+
for (const [id, question] of Object.entries(questions)) {
|
|
14111
|
+
const parameter = `questions.${id}`;
|
|
14112
|
+
if (!isRecord(question) || !isInput(question.instructions)) {
|
|
14113
|
+
invalidInput(
|
|
14114
|
+
parameter,
|
|
14115
|
+
question,
|
|
14116
|
+
"instructions must be a JSON-compatible string, object, or array"
|
|
14117
|
+
);
|
|
14118
|
+
}
|
|
14119
|
+
const criteria = question.criteria;
|
|
14120
|
+
switch (question.type) {
|
|
14121
|
+
case "choice":
|
|
14122
|
+
if (!isRecord(criteria) || Object.keys(criteria).length === 0) {
|
|
14123
|
+
invalidInput(
|
|
14124
|
+
parameter,
|
|
14125
|
+
question,
|
|
14126
|
+
"choice criteria must be a nonempty option map"
|
|
14127
|
+
);
|
|
14128
|
+
}
|
|
14129
|
+
break;
|
|
14130
|
+
case "score":
|
|
14131
|
+
if (!Array.isArray(criteria) || criteria.length < 2) {
|
|
14132
|
+
invalidInput(
|
|
14133
|
+
parameter,
|
|
14134
|
+
question,
|
|
14135
|
+
"score criteria must contain at least two ordered levels"
|
|
14136
|
+
);
|
|
14137
|
+
}
|
|
14138
|
+
break;
|
|
14139
|
+
case "boolean":
|
|
14140
|
+
if (criteria === void 0) continue;
|
|
14141
|
+
if (!isRecord(criteria) || Object.keys(criteria).some((key) => key !== "true" && key !== "false")) {
|
|
14142
|
+
invalidInput(
|
|
14143
|
+
parameter,
|
|
14144
|
+
question,
|
|
14145
|
+
"boolean criteria may only describe true and false"
|
|
14146
|
+
);
|
|
14147
|
+
}
|
|
14148
|
+
break;
|
|
14149
|
+
default:
|
|
14150
|
+
invalidInput(
|
|
14151
|
+
parameter,
|
|
14152
|
+
question,
|
|
14153
|
+
"question type must be choice, score, or boolean"
|
|
14154
|
+
);
|
|
14155
|
+
}
|
|
14156
|
+
if (!isJSON(criteria) || Object.values(criteria).some((value) => value !== null && !isInput(value))) {
|
|
14157
|
+
invalidInput(
|
|
14158
|
+
parameter,
|
|
14159
|
+
question,
|
|
14160
|
+
"criteria descriptions must be JSON-compatible strings, objects, arrays, or null"
|
|
14161
|
+
);
|
|
14162
|
+
}
|
|
14163
|
+
}
|
|
14164
|
+
}
|
|
14165
|
+
function invalidAnswer(answers, message) {
|
|
14166
|
+
throw new InvalidResponseDataError3({ data: answers, message });
|
|
14167
|
+
}
|
|
14168
|
+
function isProbability(value) {
|
|
14169
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
|
|
14170
|
+
}
|
|
14171
|
+
function hasExactKeys(value, keys) {
|
|
14172
|
+
return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
14173
|
+
}
|
|
14174
|
+
function validateDistribution(value, keys, answers, id, roundingError) {
|
|
14175
|
+
if (!isRecord(value) || !hasExactKeys(value, keys) || !Object.values(value).every(isProbability)) {
|
|
14176
|
+
invalidAnswer(
|
|
14177
|
+
answers,
|
|
14178
|
+
`Question "${id}" must have a complete distribution of finite probabilities in [0, 1].`
|
|
14179
|
+
);
|
|
14180
|
+
}
|
|
14181
|
+
const sum = Object.values(value).reduce(
|
|
14182
|
+
(total, probability) => total + probability,
|
|
14183
|
+
0
|
|
14184
|
+
);
|
|
14185
|
+
if (Math.abs(sum - 1) > tolerance + keys.length * roundingError) {
|
|
14186
|
+
invalidAnswer(
|
|
14187
|
+
answers,
|
|
14188
|
+
`Question "${id}" probabilities must sum to 1 within the declared rounding precision.`
|
|
14189
|
+
);
|
|
14190
|
+
}
|
|
14191
|
+
}
|
|
14192
|
+
function validateEvaluationAnswers({
|
|
14193
|
+
questions,
|
|
14194
|
+
answers,
|
|
14195
|
+
rounding
|
|
14196
|
+
}) {
|
|
14197
|
+
function roundingError(decimals) {
|
|
14198
|
+
if (decimals === void 0) return 0;
|
|
14199
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 15) {
|
|
14200
|
+
invalidAnswer(
|
|
14201
|
+
answers,
|
|
14202
|
+
"Evaluation rounding decimals must be integers between 0 and 15."
|
|
14203
|
+
);
|
|
14204
|
+
}
|
|
14205
|
+
return 0.5 * 10 ** -decimals;
|
|
14206
|
+
}
|
|
14207
|
+
const probabilityError = roundingError(rounding == null ? void 0 : rounding.probabilityDecimals);
|
|
14208
|
+
const scoreError = roundingError(rounding == null ? void 0 : rounding.scoreDecimals);
|
|
14209
|
+
if (!isRecord(answers) || !hasExactKeys(answers, Object.keys(questions))) {
|
|
14210
|
+
invalidAnswer(
|
|
14211
|
+
answers,
|
|
14212
|
+
"Evaluation must return exactly one answer for every question."
|
|
14213
|
+
);
|
|
14214
|
+
}
|
|
14215
|
+
for (const [id, question] of Object.entries(questions)) {
|
|
14216
|
+
const answer = answers[id];
|
|
14217
|
+
if (!isRecord(answer) || answer.type !== question.type) {
|
|
14218
|
+
invalidAnswer(
|
|
14219
|
+
answers,
|
|
14220
|
+
`Question "${id}" returned an answer with the wrong type.`
|
|
14221
|
+
);
|
|
14222
|
+
}
|
|
14223
|
+
switch (question.type) {
|
|
14224
|
+
case "choice": {
|
|
14225
|
+
if (typeof answer.choice !== "string" || !Object.hasOwn(question.criteria, answer.choice)) {
|
|
14226
|
+
invalidAnswer(
|
|
14227
|
+
answers,
|
|
14228
|
+
`Question "${id}" selected an unknown option.`
|
|
14229
|
+
);
|
|
14230
|
+
}
|
|
14231
|
+
if (answer.probabilities !== void 0) {
|
|
14232
|
+
validateDistribution(
|
|
14233
|
+
answer.probabilities,
|
|
14234
|
+
Object.keys(question.criteria),
|
|
14235
|
+
answers,
|
|
14236
|
+
id,
|
|
14237
|
+
probabilityError
|
|
14238
|
+
);
|
|
14239
|
+
const selected = answer.probabilities[answer.choice];
|
|
14240
|
+
if (Object.values(answer.probabilities).some(
|
|
14241
|
+
(probability) => probability > selected + tolerance
|
|
14242
|
+
)) {
|
|
14243
|
+
invalidAnswer(
|
|
14244
|
+
answers,
|
|
14245
|
+
`Question "${id}" did not select a highest-probability option.`
|
|
14246
|
+
);
|
|
14247
|
+
}
|
|
14248
|
+
}
|
|
14249
|
+
break;
|
|
14250
|
+
}
|
|
14251
|
+
case "score": {
|
|
14252
|
+
if (typeof answer.score !== "number" || !Number.isFinite(answer.score) || answer.score < 0 || answer.score > question.criteria.length - 1) {
|
|
14253
|
+
invalidAnswer(
|
|
14254
|
+
answers,
|
|
14255
|
+
`Question "${id}" score must be in [0, ${question.criteria.length - 1}].`
|
|
14256
|
+
);
|
|
14257
|
+
}
|
|
14258
|
+
if (answer.probabilities !== void 0) {
|
|
14259
|
+
const keys = question.criteria.map((_, index) => String(index));
|
|
14260
|
+
validateDistribution(
|
|
14261
|
+
answer.probabilities,
|
|
14262
|
+
keys,
|
|
14263
|
+
answers,
|
|
14264
|
+
id,
|
|
14265
|
+
probabilityError
|
|
14266
|
+
);
|
|
14267
|
+
const mean = Object.entries(answer.probabilities).reduce(
|
|
14268
|
+
(total, [index, probability]) => total + Number(index) * probability,
|
|
14269
|
+
0
|
|
14270
|
+
);
|
|
14271
|
+
const meanRoundingError = keys.reduce(
|
|
14272
|
+
(total, index) => total + Number(index) * probabilityError,
|
|
14273
|
+
0
|
|
14274
|
+
);
|
|
14275
|
+
if (Math.abs(mean - answer.score) > tolerance + meanRoundingError + scoreError) {
|
|
14276
|
+
invalidAnswer(
|
|
14277
|
+
answers,
|
|
14278
|
+
`Question "${id}" score must equal the probability-weighted mean within the declared rounding precision.`
|
|
14279
|
+
);
|
|
14280
|
+
}
|
|
14281
|
+
}
|
|
14282
|
+
break;
|
|
14283
|
+
}
|
|
14284
|
+
case "boolean":
|
|
14285
|
+
if (!isProbability(answer.probability)) {
|
|
14286
|
+
invalidAnswer(
|
|
14287
|
+
answers,
|
|
14288
|
+
`Question "${id}" must return P(true) as a finite probability in [0, 1].`
|
|
14289
|
+
);
|
|
14290
|
+
}
|
|
14291
|
+
break;
|
|
14292
|
+
}
|
|
14293
|
+
}
|
|
14294
|
+
}
|
|
14295
|
+
|
|
14296
|
+
// src/evaluate/evaluate.ts
|
|
14297
|
+
async function evaluate({
|
|
14298
|
+
model,
|
|
14299
|
+
state,
|
|
14300
|
+
questions,
|
|
14301
|
+
maxRetries,
|
|
14302
|
+
abortSignal,
|
|
14303
|
+
headers,
|
|
14304
|
+
providerOptions = {}
|
|
14305
|
+
}) {
|
|
14306
|
+
var _a25, _b25, _c, _d, _e, _f;
|
|
14307
|
+
if (model.specificationVersion !== "v4") {
|
|
14308
|
+
throw new UnsupportedModelVersionError({
|
|
14309
|
+
version: model.specificationVersion,
|
|
14310
|
+
provider: model.provider,
|
|
14311
|
+
modelId: model.modelId
|
|
14312
|
+
});
|
|
14313
|
+
}
|
|
14314
|
+
validateEvaluationInput({ state, questions });
|
|
14315
|
+
for (const [questionId, question] of Object.entries(questions)) {
|
|
14316
|
+
if (!model.supportedQuestionTypes.includes(question.type)) {
|
|
14317
|
+
throw new EvaluationUnsupportedQuestionTypeError({
|
|
14318
|
+
questionId,
|
|
14319
|
+
questionType: question.type,
|
|
14320
|
+
provider: model.provider,
|
|
14321
|
+
modelId: model.modelId
|
|
14322
|
+
});
|
|
14323
|
+
}
|
|
14324
|
+
}
|
|
14325
|
+
const { retry } = prepareRetries({ maxRetries, abortSignal });
|
|
14326
|
+
const result = await retry(() => {
|
|
14327
|
+
abortSignal == null ? void 0 : abortSignal.throwIfAborted();
|
|
14328
|
+
return model.doEvaluate({
|
|
14329
|
+
state,
|
|
14330
|
+
questions,
|
|
14331
|
+
abortSignal,
|
|
14332
|
+
headers: withUserAgentSuffix8(headers != null ? headers : {}, `ai/${VERSION}`),
|
|
14333
|
+
providerOptions
|
|
14334
|
+
});
|
|
14335
|
+
});
|
|
14336
|
+
abortSignal == null ? void 0 : abortSignal.throwIfAborted();
|
|
14337
|
+
validateEvaluationAnswers({
|
|
14338
|
+
questions,
|
|
14339
|
+
answers: result.answers,
|
|
14340
|
+
rounding: result.rounding
|
|
14341
|
+
});
|
|
14342
|
+
logWarnings({
|
|
14343
|
+
warnings: result.warnings,
|
|
14344
|
+
provider: model.provider,
|
|
14345
|
+
model: model.modelId
|
|
14346
|
+
});
|
|
14347
|
+
const inputTokens = (_a25 = result.usage) == null ? void 0 : _a25.inputTokens;
|
|
14348
|
+
const outputTokens = (_b25 = result.usage) == null ? void 0 : _b25.outputTokens;
|
|
14349
|
+
return {
|
|
14350
|
+
answers: result.answers,
|
|
14351
|
+
usage: {
|
|
14352
|
+
inputTokens,
|
|
14353
|
+
outputTokens,
|
|
14354
|
+
totalTokens: inputTokens != null && outputTokens != null ? inputTokens + outputTokens : void 0
|
|
14355
|
+
},
|
|
14356
|
+
warnings: result.warnings,
|
|
14357
|
+
rounding: result.rounding,
|
|
14358
|
+
providerMetadata: result.providerMetadata,
|
|
14359
|
+
response: {
|
|
14360
|
+
...result.response,
|
|
14361
|
+
timestamp: (_d = (_c = result.response) == null ? void 0 : _c.timestamp) != null ? _d : /* @__PURE__ */ new Date(),
|
|
14362
|
+
modelId: (_f = (_e = result.response) == null ? void 0 : _e.modelId) != null ? _f : model.modelId
|
|
14363
|
+
}
|
|
14364
|
+
};
|
|
14365
|
+
}
|
|
14366
|
+
|
|
13985
14367
|
// src/generate-object/generate-object.ts
|
|
13986
14368
|
import {
|
|
13987
14369
|
createIdGenerator as createIdGenerator6,
|
|
13988
|
-
withUserAgentSuffix as
|
|
14370
|
+
withUserAgentSuffix as withUserAgentSuffix9
|
|
13989
14371
|
} from "@ai-sdk/provider-utils";
|
|
13990
14372
|
|
|
13991
14373
|
// src/generate-text/extract-reasoning-content.ts
|
|
@@ -14488,7 +14870,7 @@ async function generateObject(options) {
|
|
|
14488
14870
|
onStepFinish,
|
|
14489
14871
|
onFinish,
|
|
14490
14872
|
_internal: {
|
|
14491
|
-
generateId:
|
|
14873
|
+
generateId: generateId5 = originalGenerateId4,
|
|
14492
14874
|
currentDate = () => /* @__PURE__ */ new Date()
|
|
14493
14875
|
} = {},
|
|
14494
14876
|
...settings
|
|
@@ -14517,7 +14899,7 @@ async function generateObject(options) {
|
|
|
14517
14899
|
enumValues
|
|
14518
14900
|
});
|
|
14519
14901
|
const callSettings = prepareLanguageModelCallOptions(settings);
|
|
14520
|
-
const headersWithUserAgent =
|
|
14902
|
+
const headersWithUserAgent = withUserAgentSuffix9(
|
|
14521
14903
|
headers != null ? headers : {},
|
|
14522
14904
|
`ai/${VERSION}`
|
|
14523
14905
|
);
|
|
@@ -14528,7 +14910,7 @@ async function generateObject(options) {
|
|
|
14528
14910
|
const resolvedOnStepStart = onStepStart != null ? onStepStart : experimental_onStepStart;
|
|
14529
14911
|
const resolvedOnStepEnd = onStepEnd != null ? onStepEnd : onStepFinish;
|
|
14530
14912
|
const jsonSchema2 = await outputStrategy.jsonSchema();
|
|
14531
|
-
const callId =
|
|
14913
|
+
const callId = generateId5();
|
|
14532
14914
|
await notify({
|
|
14533
14915
|
event: {
|
|
14534
14916
|
callId,
|
|
@@ -14597,7 +14979,7 @@ async function generateObject(options) {
|
|
|
14597
14979
|
})
|
|
14598
14980
|
);
|
|
14599
14981
|
const responseData = {
|
|
14600
|
-
id: (_b25 = (_a25 = generateResult.response) == null ? void 0 : _a25.id) != null ? _b25 :
|
|
14982
|
+
id: (_b25 = (_a25 = generateResult.response) == null ? void 0 : _a25.id) != null ? _b25 : generateId5(),
|
|
14601
14983
|
timestamp: (_d = (_c = generateResult.response) == null ? void 0 : _c.timestamp) != null ? _d : currentDate(),
|
|
14602
14984
|
modelId: (_f = (_e = generateResult.response) == null ? void 0 : _e.modelId) != null ? _f : model.modelId,
|
|
14603
14985
|
headers: (_g = generateResult.response) == null ? void 0 : _g.headers,
|
|
@@ -14857,7 +15239,7 @@ function streamObject(options) {
|
|
|
14857
15239
|
},
|
|
14858
15240
|
onFinish,
|
|
14859
15241
|
_internal: {
|
|
14860
|
-
generateId:
|
|
15242
|
+
generateId: generateId5 = originalGenerateId5,
|
|
14861
15243
|
currentDate = () => /* @__PURE__ */ new Date(),
|
|
14862
15244
|
now: now2 = now
|
|
14863
15245
|
} = {},
|
|
@@ -14904,7 +15286,7 @@ function streamObject(options) {
|
|
|
14904
15286
|
onError,
|
|
14905
15287
|
onFinish,
|
|
14906
15288
|
download: download2,
|
|
14907
|
-
generateId:
|
|
15289
|
+
generateId: generateId5,
|
|
14908
15290
|
currentDate,
|
|
14909
15291
|
now: now2
|
|
14910
15292
|
});
|
|
@@ -14933,7 +15315,7 @@ var DefaultStreamObjectResult = class {
|
|
|
14933
15315
|
onError,
|
|
14934
15316
|
onFinish,
|
|
14935
15317
|
download: download2,
|
|
14936
|
-
generateId:
|
|
15318
|
+
generateId: generateId5,
|
|
14937
15319
|
currentDate,
|
|
14938
15320
|
now: now2
|
|
14939
15321
|
}) {
|
|
@@ -14967,7 +15349,7 @@ var DefaultStreamObjectResult = class {
|
|
|
14967
15349
|
}
|
|
14968
15350
|
});
|
|
14969
15351
|
this.baseStream = stitchableStream.stream.pipeThrough(eventProcessor);
|
|
14970
|
-
const callId =
|
|
15352
|
+
const callId = generateId5();
|
|
14971
15353
|
(async () => {
|
|
14972
15354
|
const jsonSchema2 = await outputStrategy.jsonSchema();
|
|
14973
15355
|
await notify({
|
|
@@ -15065,7 +15447,7 @@ var DefaultStreamObjectResult = class {
|
|
|
15065
15447
|
let accumulatedText = "";
|
|
15066
15448
|
let textDelta = "";
|
|
15067
15449
|
let fullResponse = {
|
|
15068
|
-
id:
|
|
15450
|
+
id: generateId5(),
|
|
15069
15451
|
timestamp: currentDate(),
|
|
15070
15452
|
modelId: model.modelId
|
|
15071
15453
|
};
|
|
@@ -15381,7 +15763,7 @@ var DefaultStreamObjectResult = class {
|
|
|
15381
15763
|
// src/generate-speech/generate-speech.ts
|
|
15382
15764
|
import {
|
|
15383
15765
|
detectMediaType as detectMediaType4,
|
|
15384
|
-
withUserAgentSuffix as
|
|
15766
|
+
withUserAgentSuffix as withUserAgentSuffix10
|
|
15385
15767
|
} from "@ai-sdk/provider-utils";
|
|
15386
15768
|
|
|
15387
15769
|
// src/generate-speech/generated-audio-file.ts
|
|
@@ -15428,7 +15810,7 @@ async function generateSpeech({
|
|
|
15428
15810
|
if (!resolvedModel) {
|
|
15429
15811
|
throw new Error("Model could not be resolved");
|
|
15430
15812
|
}
|
|
15431
|
-
const headersWithUserAgent =
|
|
15813
|
+
const headersWithUserAgent = withUserAgentSuffix10(
|
|
15432
15814
|
headers != null ? headers : {},
|
|
15433
15815
|
`ai/${VERSION}`
|
|
15434
15816
|
);
|
|
@@ -15738,7 +16120,7 @@ import {
|
|
|
15738
16120
|
convertBase64ToUint8Array as convertBase64ToUint8Array5,
|
|
15739
16121
|
delay as defaultDelay,
|
|
15740
16122
|
generateId,
|
|
15741
|
-
withUserAgentSuffix as
|
|
16123
|
+
withUserAgentSuffix as withUserAgentSuffix11,
|
|
15742
16124
|
detectMediaType as detectMediaType5
|
|
15743
16125
|
} from "@ai-sdk/provider-utils";
|
|
15744
16126
|
var defaultDownload = createDownload();
|
|
@@ -15765,7 +16147,7 @@ async function experimental_generateVideo({
|
|
|
15765
16147
|
}) {
|
|
15766
16148
|
var _a25;
|
|
15767
16149
|
const model = resolveVideoModel(modelArg);
|
|
15768
|
-
const headersWithUserAgent =
|
|
16150
|
+
const headersWithUserAgent = withUserAgentSuffix11(
|
|
15769
16151
|
headers != null ? headers : {},
|
|
15770
16152
|
`ai/${VERSION}`
|
|
15771
16153
|
);
|
|
@@ -16172,7 +16554,7 @@ async function invokeModelMaxVideosPerCall(model) {
|
|
|
16172
16554
|
// src/generate-video/start-video.ts
|
|
16173
16555
|
import {
|
|
16174
16556
|
generateId as generateId2,
|
|
16175
|
-
withUserAgentSuffix as
|
|
16557
|
+
withUserAgentSuffix as withUserAgentSuffix12
|
|
16176
16558
|
} from "@ai-sdk/provider-utils";
|
|
16177
16559
|
async function experimental_startVideo({
|
|
16178
16560
|
model: modelArg,
|
|
@@ -16238,7 +16620,7 @@ async function experimental_startVideo({
|
|
|
16238
16620
|
generateAudio,
|
|
16239
16621
|
providerOptions: providerOptions != null ? providerOptions : {},
|
|
16240
16622
|
headers: {
|
|
16241
|
-
...
|
|
16623
|
+
...withUserAgentSuffix12(headers != null ? headers : {}, `ai/${VERSION}`),
|
|
16242
16624
|
...callerIdempotencyKey ? {} : { "idempotency-key": `aisdk_vid_${generateId2()}` }
|
|
16243
16625
|
},
|
|
16244
16626
|
abortSignal,
|
|
@@ -16254,7 +16636,7 @@ async function experimental_startVideo({
|
|
|
16254
16636
|
}
|
|
16255
16637
|
|
|
16256
16638
|
// src/generate-video/get-video-status.ts
|
|
16257
|
-
import { withUserAgentSuffix as
|
|
16639
|
+
import { withUserAgentSuffix as withUserAgentSuffix13 } from "@ai-sdk/provider-utils";
|
|
16258
16640
|
async function experimental_getVideoStatus(modelArg, {
|
|
16259
16641
|
operation,
|
|
16260
16642
|
headers,
|
|
@@ -16274,7 +16656,7 @@ async function experimental_getVideoStatus(modelArg, {
|
|
|
16274
16656
|
return retry(
|
|
16275
16657
|
() => model.doStatus({
|
|
16276
16658
|
operation,
|
|
16277
|
-
headers:
|
|
16659
|
+
headers: withUserAgentSuffix13(headers != null ? headers : {}, `ai/${VERSION}`),
|
|
16278
16660
|
abortSignal
|
|
16279
16661
|
})
|
|
16280
16662
|
);
|
|
@@ -17029,6 +17411,9 @@ function resolveRealtimeToolDescription({
|
|
|
17029
17411
|
});
|
|
17030
17412
|
}
|
|
17031
17413
|
|
|
17414
|
+
// src/realtime/realtime-session.ts
|
|
17415
|
+
import { UnsupportedFunctionalityError as UnsupportedFunctionalityError6 } from "@ai-sdk/provider";
|
|
17416
|
+
|
|
17032
17417
|
// src/realtime/browser-realtime-audio.ts
|
|
17033
17418
|
var BrowserRealtimeAudio = class {
|
|
17034
17419
|
constructor(options) {
|
|
@@ -17036,16 +17421,23 @@ var BrowserRealtimeAudio = class {
|
|
|
17036
17421
|
this.captureProcessor = null;
|
|
17037
17422
|
this.captureSource = null;
|
|
17038
17423
|
this.captureStream = null;
|
|
17424
|
+
this.ownsCaptureStream = true;
|
|
17425
|
+
this.captureCleanup = [];
|
|
17426
|
+
this.captureGeneration = 0;
|
|
17039
17427
|
this.playbackContext = null;
|
|
17040
17428
|
this.playbackQueue = [];
|
|
17041
17429
|
this.playbackTime = 0;
|
|
17042
17430
|
this.playbackStartTime = 0;
|
|
17043
17431
|
this.activeSources = /* @__PURE__ */ new Set();
|
|
17044
17432
|
this.isPlaying = false;
|
|
17433
|
+
this.playbackPaused = false;
|
|
17434
|
+
var _a25;
|
|
17045
17435
|
this.captureSampleRate = options.captureSampleRate;
|
|
17046
17436
|
this.playbackSampleRate = options.playbackSampleRate;
|
|
17047
17437
|
this.onAudio = options.onAudio;
|
|
17048
17438
|
this.onPlayingChange = options.onPlayingChange;
|
|
17439
|
+
this.maxPlaybackSeconds = (_a25 = options.maxPlaybackSeconds) != null ? _a25 : Infinity;
|
|
17440
|
+
this.onError = options.onError;
|
|
17049
17441
|
this.onCapturingChange = options.onCapturingChange;
|
|
17050
17442
|
}
|
|
17051
17443
|
ensurePlaybackContext() {
|
|
@@ -17053,35 +17445,97 @@ var BrowserRealtimeAudio = class {
|
|
|
17053
17445
|
this.playbackContext = new AudioContext({
|
|
17054
17446
|
sampleRate: this.playbackSampleRate
|
|
17055
17447
|
});
|
|
17448
|
+
const context = this.playbackContext;
|
|
17449
|
+
context.onstatechange = () => {
|
|
17450
|
+
if (this.playbackContext === context)
|
|
17451
|
+
this.setPlaying(
|
|
17452
|
+
context.state === "running" && this.activeSources.size > 0
|
|
17453
|
+
);
|
|
17454
|
+
};
|
|
17056
17455
|
}
|
|
17057
17456
|
}
|
|
17058
|
-
|
|
17457
|
+
async resumePlayback() {
|
|
17458
|
+
var _a25;
|
|
17459
|
+
this.ensurePlaybackContext();
|
|
17460
|
+
const context = this.playbackContext;
|
|
17461
|
+
if (this.playbackPaused) this.stopPlayback();
|
|
17462
|
+
if (this.playbackContext !== context) return;
|
|
17463
|
+
await (context == null ? void 0 : context.resume());
|
|
17464
|
+
if (this.playbackContext !== context) return;
|
|
17465
|
+
this.playbackPaused = false;
|
|
17466
|
+
this.setPlaying(
|
|
17467
|
+
((_a25 = this.playbackContext) == null ? void 0 : _a25.state) === "running" && this.activeSources.size > 0
|
|
17468
|
+
);
|
|
17469
|
+
}
|
|
17470
|
+
startCapture(stream, options) {
|
|
17471
|
+
var _a25, _b25;
|
|
17472
|
+
const generation = this.captureGeneration + 1;
|
|
17473
|
+
this.stopCapture();
|
|
17474
|
+
if (generation !== this.captureGeneration) {
|
|
17475
|
+
if ((_a25 = options == null ? void 0 : options.ownsStream) != null ? _a25 : true)
|
|
17476
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
17477
|
+
return;
|
|
17478
|
+
}
|
|
17479
|
+
this.captureStream = stream;
|
|
17480
|
+
this.ownsCaptureStream = (_b25 = options == null ? void 0 : options.ownsStream) != null ? _b25 : true;
|
|
17059
17481
|
const ctx = new AudioContext({ sampleRate: this.captureSampleRate });
|
|
17060
17482
|
this.captureContext = ctx;
|
|
17061
|
-
|
|
17483
|
+
void ctx.resume().catch((error) => {
|
|
17484
|
+
var _a26;
|
|
17485
|
+
if (this.captureContext === ctx) (_a26 = this.onError) == null ? void 0 : _a26.call(this, error);
|
|
17486
|
+
});
|
|
17062
17487
|
const source = ctx.createMediaStreamSource(stream);
|
|
17063
17488
|
this.captureSource = source;
|
|
17064
|
-
const processor = ctx.createScriptProcessor(
|
|
17489
|
+
const processor = ctx.createScriptProcessor(1024, 1, 1);
|
|
17065
17490
|
this.captureProcessor = processor;
|
|
17066
17491
|
processor.onaudioprocess = (event) => {
|
|
17492
|
+
var _a26;
|
|
17493
|
+
if (this.captureContext !== ctx) return;
|
|
17067
17494
|
const inputData = event.inputBuffer.getChannelData(0);
|
|
17068
17495
|
const samples = resampleAudio(
|
|
17069
17496
|
new Float32Array(inputData),
|
|
17070
17497
|
ctx.sampleRate,
|
|
17071
17498
|
this.captureSampleRate
|
|
17072
17499
|
);
|
|
17073
|
-
|
|
17500
|
+
try {
|
|
17501
|
+
this.onAudio(encodeRealtimeAudio(samples));
|
|
17502
|
+
} catch (error) {
|
|
17503
|
+
(_a26 = this.onError) == null ? void 0 : _a26.call(
|
|
17504
|
+
this,
|
|
17505
|
+
error instanceof Error ? error : new Error(String(error))
|
|
17506
|
+
);
|
|
17507
|
+
}
|
|
17074
17508
|
};
|
|
17075
17509
|
source.connect(processor);
|
|
17076
17510
|
processor.connect(ctx.destination);
|
|
17077
|
-
this.onCapturingChange(
|
|
17511
|
+
const updateCapturing = () => this.onCapturingChange(
|
|
17512
|
+
stream.getAudioTracks().some(
|
|
17513
|
+
(track) => track.enabled && !track.muted && track.readyState === "live"
|
|
17514
|
+
)
|
|
17515
|
+
);
|
|
17516
|
+
for (const track of stream.getAudioTracks()) {
|
|
17517
|
+
for (const event of ["ended", "mute", "unmute"]) {
|
|
17518
|
+
track.addEventListener(event, updateCapturing);
|
|
17519
|
+
this.captureCleanup.push(
|
|
17520
|
+
() => track.removeEventListener(event, updateCapturing)
|
|
17521
|
+
);
|
|
17522
|
+
}
|
|
17523
|
+
}
|
|
17524
|
+
updateCapturing();
|
|
17078
17525
|
}
|
|
17079
17526
|
stopCapture() {
|
|
17080
17527
|
var _a25, _b25, _c, _d;
|
|
17528
|
+
this.captureGeneration++;
|
|
17529
|
+
if (this.captureProcessor != null)
|
|
17530
|
+
this.captureProcessor.onaudioprocess = null;
|
|
17531
|
+
for (const cleanup of this.captureCleanup) cleanup();
|
|
17532
|
+
this.captureCleanup = [];
|
|
17081
17533
|
(_a25 = this.captureProcessor) == null ? void 0 : _a25.disconnect();
|
|
17082
17534
|
(_b25 = this.captureSource) == null ? void 0 : _b25.disconnect();
|
|
17083
|
-
void ((_c = this.captureContext) == null ? void 0 : _c.close())
|
|
17084
|
-
|
|
17535
|
+
void ((_c = this.captureContext) == null ? void 0 : _c.close().catch(() => {
|
|
17536
|
+
}));
|
|
17537
|
+
if (this.ownsCaptureStream)
|
|
17538
|
+
(_d = this.captureStream) == null ? void 0 : _d.getTracks().forEach((track) => track.stop());
|
|
17085
17539
|
this.captureProcessor = null;
|
|
17086
17540
|
this.captureSource = null;
|
|
17087
17541
|
this.captureContext = null;
|
|
@@ -17089,15 +17543,34 @@ var BrowserRealtimeAudio = class {
|
|
|
17089
17543
|
this.onCapturingChange(false);
|
|
17090
17544
|
}
|
|
17091
17545
|
playAudio(base64Audio) {
|
|
17546
|
+
var _a25, _b25, _c;
|
|
17547
|
+
if (this.playbackPaused) return;
|
|
17092
17548
|
this.ensurePlaybackContext();
|
|
17093
|
-
|
|
17549
|
+
const samples = decodeRealtimeAudio(base64Audio);
|
|
17550
|
+
if (Math.max(
|
|
17551
|
+
0,
|
|
17552
|
+
this.playbackTime - ((_b25 = (_a25 = this.playbackContext) == null ? void 0 : _a25.currentTime) != null ? _b25 : 0)
|
|
17553
|
+
) + samples.length / this.playbackSampleRate > this.maxPlaybackSeconds) {
|
|
17554
|
+
this.playbackPaused = true;
|
|
17555
|
+
this.stopPlayback();
|
|
17556
|
+
(_c = this.onError) == null ? void 0 : _c.call(
|
|
17557
|
+
this,
|
|
17558
|
+
new Error(
|
|
17559
|
+
"Realtime audio playback buffer is full; playback paused, call resumePlayback() to resume at the live edge"
|
|
17560
|
+
)
|
|
17561
|
+
);
|
|
17562
|
+
return;
|
|
17563
|
+
}
|
|
17564
|
+
this.playbackQueue.push(samples);
|
|
17094
17565
|
this.schedulePlayback();
|
|
17095
17566
|
}
|
|
17096
17567
|
stopPlayback() {
|
|
17097
17568
|
this.playbackQueue = [];
|
|
17098
17569
|
for (const source of this.activeSources) {
|
|
17099
17570
|
try {
|
|
17571
|
+
source.onended = null;
|
|
17100
17572
|
source.stop();
|
|
17573
|
+
source.disconnect();
|
|
17101
17574
|
} catch (e) {
|
|
17102
17575
|
}
|
|
17103
17576
|
}
|
|
@@ -17116,8 +17589,12 @@ var BrowserRealtimeAudio = class {
|
|
|
17116
17589
|
var _a25;
|
|
17117
17590
|
this.stopCapture();
|
|
17118
17591
|
this.stopPlayback();
|
|
17119
|
-
|
|
17592
|
+
if (this.playbackContext != null) this.playbackContext.onstatechange = null;
|
|
17593
|
+
void ((_a25 = this.playbackContext) == null ? void 0 : _a25.close().catch(() => {
|
|
17594
|
+
}));
|
|
17120
17595
|
this.playbackContext = null;
|
|
17596
|
+
this.playbackTime = 0;
|
|
17597
|
+
this.playbackPaused = false;
|
|
17121
17598
|
}
|
|
17122
17599
|
setPlaying(isPlaying) {
|
|
17123
17600
|
var _a25, _b25;
|
|
@@ -17147,8 +17624,10 @@ var BrowserRealtimeAudio = class {
|
|
|
17147
17624
|
source.start(startTime);
|
|
17148
17625
|
this.playbackTime = startTime + buffer.duration;
|
|
17149
17626
|
this.activeSources.add(source);
|
|
17150
|
-
this.setPlaying(
|
|
17627
|
+
this.setPlaying(ctx.state === "running");
|
|
17628
|
+
if (this.playbackContext !== ctx) return;
|
|
17151
17629
|
source.onended = () => {
|
|
17630
|
+
source.disconnect();
|
|
17152
17631
|
this.activeSources.delete(source);
|
|
17153
17632
|
if (this.playbackQueue.length === 0 && this.activeSources.size === 0) {
|
|
17154
17633
|
this.setPlaying(false);
|
|
@@ -17158,103 +17637,1258 @@ var BrowserRealtimeAudio = class {
|
|
|
17158
17637
|
}
|
|
17159
17638
|
};
|
|
17160
17639
|
|
|
17161
|
-
// src/realtime/
|
|
17640
|
+
// src/realtime/realtime-event-channel.ts
|
|
17162
17641
|
import { safeParseJSON as safeParseJSON5 } from "@ai-sdk/provider-utils";
|
|
17642
|
+
var RealtimeEventChannel = class {
|
|
17643
|
+
constructor(options) {
|
|
17644
|
+
this.options = options;
|
|
17645
|
+
this.active = true;
|
|
17646
|
+
this.finishing = false;
|
|
17647
|
+
this.incoming = Promise.resolve();
|
|
17648
|
+
this.outgoing = Promise.resolve();
|
|
17649
|
+
this.incomingCount = 0;
|
|
17650
|
+
this.incomingBytes = 0;
|
|
17651
|
+
this.outgoingCount = 0;
|
|
17652
|
+
var _a25, _b25, _c;
|
|
17653
|
+
this.parse = (_c = (_b25 = (_a25 = options.model).createServerEventParser) == null ? void 0 : _b25.call(_a25)) != null ? _c : options.model.parseServerEvent.bind(options.model);
|
|
17654
|
+
}
|
|
17655
|
+
dispose() {
|
|
17656
|
+
this.active = false;
|
|
17657
|
+
}
|
|
17658
|
+
/** Stop accepting messages, but deliver already received terminal events. */
|
|
17659
|
+
async finish() {
|
|
17660
|
+
this.stopWriting();
|
|
17661
|
+
await this.incoming;
|
|
17662
|
+
this.dispose();
|
|
17663
|
+
}
|
|
17664
|
+
stopWriting() {
|
|
17665
|
+
this.finishing = true;
|
|
17666
|
+
}
|
|
17667
|
+
send(event, shouldSend) {
|
|
17668
|
+
var _a25;
|
|
17669
|
+
if (!this.active || this.finishing)
|
|
17670
|
+
throw new Error("Realtime connection is closed");
|
|
17671
|
+
if (this.outgoingCount >= ((_a25 = this.options.maxPending) != null ? _a25 : 512)) {
|
|
17672
|
+
throw new Error("Realtime outgoing queue is full");
|
|
17673
|
+
}
|
|
17674
|
+
this.outgoingCount++;
|
|
17675
|
+
const operation = this.outgoing.then(async () => {
|
|
17676
|
+
if (!this.active || this.finishing)
|
|
17677
|
+
throw new Error("Realtime connection is closed");
|
|
17678
|
+
if ((shouldSend == null ? void 0 : shouldSend()) === false) return;
|
|
17679
|
+
if (!this.active || this.finishing)
|
|
17680
|
+
throw new Error("Realtime connection is closed");
|
|
17681
|
+
const data = await this.options.model.serializeClientEvent(event);
|
|
17682
|
+
if (!this.active || this.finishing)
|
|
17683
|
+
throw new Error("Realtime connection is closed");
|
|
17684
|
+
if ((shouldSend == null ? void 0 : shouldSend()) === false) return;
|
|
17685
|
+
if (!this.active || this.finishing)
|
|
17686
|
+
throw new Error("Realtime connection is closed");
|
|
17687
|
+
if (data != null) this.options.send(data);
|
|
17688
|
+
});
|
|
17689
|
+
this.outgoing = operation.catch((error) => {
|
|
17690
|
+
if (!this.finishing) {
|
|
17691
|
+
if (event.type !== "input-audio-append" && event.type !== "session-close")
|
|
17692
|
+
this.report(error);
|
|
17693
|
+
}
|
|
17694
|
+
}).finally(() => {
|
|
17695
|
+
this.outgoingCount--;
|
|
17696
|
+
});
|
|
17697
|
+
return operation;
|
|
17698
|
+
}
|
|
17699
|
+
receive(data) {
|
|
17700
|
+
var _a25, _b25, _c;
|
|
17701
|
+
if (!this.active || this.finishing) return;
|
|
17702
|
+
const bytes = typeof data === "string" ? data.length * 2 : data instanceof Blob ? data.size : (_a25 = data.byteLength) != null ? _a25 : 0;
|
|
17703
|
+
if (this.incomingCount >= ((_b25 = this.options.maxPending) != null ? _b25 : 512) || this.incomingBytes + bytes > ((_c = this.options.maxPendingBytes) != null ? _c : 8 * 1024 * 1024)) {
|
|
17704
|
+
this.finishing = true;
|
|
17705
|
+
this.fatal(
|
|
17706
|
+
new Error(
|
|
17707
|
+
"Realtime incoming queue is full; input protocol continuity was lost"
|
|
17708
|
+
)
|
|
17709
|
+
);
|
|
17710
|
+
return;
|
|
17711
|
+
}
|
|
17712
|
+
this.incomingCount++;
|
|
17713
|
+
this.incomingBytes += bytes;
|
|
17714
|
+
this.incoming = this.incoming.then(async () => {
|
|
17715
|
+
var _a26, _b26;
|
|
17716
|
+
if (!this.active) return;
|
|
17717
|
+
const text2 = typeof data === "string" ? data : data instanceof Blob ? await data.text() : new TextDecoder().decode(data);
|
|
17718
|
+
const parsed = await safeParseJSON5({ text: text2 });
|
|
17719
|
+
if (!this.active) return;
|
|
17720
|
+
if (!parsed.success)
|
|
17721
|
+
throw new Error("Invalid JSON in realtime server message", {
|
|
17722
|
+
cause: parsed.error
|
|
17723
|
+
});
|
|
17724
|
+
const health = (_b26 = (_a26 = this.options.model).getHealthCheckResponse) == null ? void 0 : _b26.call(
|
|
17725
|
+
_a26,
|
|
17726
|
+
parsed.value
|
|
17727
|
+
);
|
|
17728
|
+
if (!this.active) return;
|
|
17729
|
+
if (health != null && !this.finishing) this.options.send(health);
|
|
17730
|
+
if (!this.active) return;
|
|
17731
|
+
const result = this.parse(parsed.value);
|
|
17732
|
+
for (const event of Array.isArray(result) ? result : [result]) {
|
|
17733
|
+
if (!this.active) return;
|
|
17734
|
+
try {
|
|
17735
|
+
await this.options.onEvent(event);
|
|
17736
|
+
} catch (error) {
|
|
17737
|
+
this.report(error);
|
|
17738
|
+
}
|
|
17739
|
+
}
|
|
17740
|
+
}).catch((error) => {
|
|
17741
|
+
this.finishing = true;
|
|
17742
|
+
this.fatal(error instanceof Error ? error : new Error(String(error)));
|
|
17743
|
+
}).finally(() => {
|
|
17744
|
+
this.incomingCount--;
|
|
17745
|
+
this.incomingBytes -= bytes;
|
|
17746
|
+
});
|
|
17747
|
+
}
|
|
17748
|
+
fatal(error) {
|
|
17749
|
+
if (!this.active) return;
|
|
17750
|
+
if (this.options.onFatalError != null) this.options.onFatalError(error);
|
|
17751
|
+
else this.report(error);
|
|
17752
|
+
}
|
|
17753
|
+
report(error) {
|
|
17754
|
+
if (!this.active) return;
|
|
17755
|
+
try {
|
|
17756
|
+
this.options.onError(
|
|
17757
|
+
error instanceof Error ? error : new Error(String(error))
|
|
17758
|
+
);
|
|
17759
|
+
} catch (e) {
|
|
17760
|
+
}
|
|
17761
|
+
}
|
|
17762
|
+
};
|
|
17763
|
+
|
|
17764
|
+
// src/realtime/encode-realtime-frame.ts
|
|
17765
|
+
var REALTIME_MAX_FRAME_BYTES = 128 * 1024;
|
|
17766
|
+
var REALTIME_MAX_BUFFERED_BYTES = 128 * 1024;
|
|
17767
|
+
function encodeRealtimeFrame(value) {
|
|
17768
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value))
|
|
17769
|
+
return { data: value, byteLength: value.byteLength };
|
|
17770
|
+
if (value instanceof Blob) return { data: value, byteLength: value.size };
|
|
17771
|
+
const data = typeof value === "string" ? value : JSON.stringify(value);
|
|
17772
|
+
if (data === void 0)
|
|
17773
|
+
throw new Error("Realtime event could not be encoded as JSON");
|
|
17774
|
+
return { data, byteLength: new TextEncoder().encode(data).byteLength };
|
|
17775
|
+
}
|
|
17776
|
+
function assertRealtimeFrameBudget(frame, bufferedAmount) {
|
|
17777
|
+
if (frame.byteLength > REALTIME_MAX_FRAME_BYTES)
|
|
17778
|
+
throw new Error(
|
|
17779
|
+
`Realtime frame exceeds the ${REALTIME_MAX_FRAME_BYTES}-byte limit; reduce the event payload`
|
|
17780
|
+
);
|
|
17781
|
+
if (bufferedAmount + frame.byteLength > REALTIME_MAX_BUFFERED_BYTES)
|
|
17782
|
+
throw new Error(
|
|
17783
|
+
`Realtime send buffer is full (${REALTIME_MAX_BUFFERED_BYTES}-byte limit); wait before retrying`
|
|
17784
|
+
);
|
|
17785
|
+
}
|
|
17786
|
+
|
|
17787
|
+
// src/realtime/browser-realtime-transport.ts
|
|
17788
|
+
function getCloseError(event) {
|
|
17789
|
+
if (event.code === 1e3 && event.wasClean) return void 0;
|
|
17790
|
+
return new Error(
|
|
17791
|
+
`Realtime WebSocket closed unexpectedly (code ${event.code}${event.reason === "" ? "" : `: ${event.reason}`})`
|
|
17792
|
+
);
|
|
17793
|
+
}
|
|
17163
17794
|
var BrowserRealtimeTransport = class {
|
|
17164
17795
|
constructor(options) {
|
|
17796
|
+
this.options = options;
|
|
17165
17797
|
this.ws = null;
|
|
17166
|
-
this.
|
|
17798
|
+
this.epoch = 0;
|
|
17799
|
+
this.failing = false;
|
|
17800
|
+
this.closing = false;
|
|
17801
|
+
var _a25;
|
|
17167
17802
|
this.model = options.model;
|
|
17803
|
+
this.continuous = ((_a25 = options.model.capabilities) == null ? void 0 : _a25.conversation) === "continuous";
|
|
17168
17804
|
this.onServerEvent = options.onServerEvent;
|
|
17169
17805
|
this.onError = options.onError;
|
|
17170
17806
|
this.onClose = options.onClose;
|
|
17171
17807
|
}
|
|
17808
|
+
get isOpen() {
|
|
17809
|
+
var _a25;
|
|
17810
|
+
return !this.closing && !this.failing && ((_a25 = this.ws) == null ? void 0 : _a25.readyState) === WebSocket.OPEN;
|
|
17811
|
+
}
|
|
17172
17812
|
connect({
|
|
17813
|
+
mode,
|
|
17173
17814
|
token,
|
|
17174
17815
|
url,
|
|
17175
|
-
onOpen
|
|
17816
|
+
onOpen,
|
|
17817
|
+
protocols
|
|
17176
17818
|
}) {
|
|
17177
|
-
var _a25;
|
|
17178
|
-
|
|
17179
|
-
|
|
17180
|
-
|
|
17181
|
-
|
|
17819
|
+
var _a25, _b25;
|
|
17820
|
+
this.disconnect();
|
|
17821
|
+
const epoch = this.epoch;
|
|
17822
|
+
if (mode !== "relay" && (mode !== "client-secret" || typeof token !== "string" || token.trim() === ""))
|
|
17823
|
+
throw new Error(
|
|
17824
|
+
"Realtime client-secret connection requires a nonempty token"
|
|
17825
|
+
);
|
|
17826
|
+
const wsConfig = mode === "relay" ? { url, protocols } : (_b25 = (_a25 = this.model).getWebSocketConfig) == null ? void 0 : _b25.call(_a25, { token, url });
|
|
17827
|
+
if (this.epoch !== epoch) return;
|
|
17828
|
+
if (wsConfig == null)
|
|
17829
|
+
throw new Error("Model does not support client-secret WebSockets");
|
|
17830
|
+
const finalUrl = wsConfig.url;
|
|
17831
|
+
const finalProtocols = wsConfig.protocols;
|
|
17832
|
+
if (this.epoch !== epoch) return;
|
|
17833
|
+
try {
|
|
17834
|
+
if (typeof finalUrl !== "string" || !/^wss?:\/\//i.test(finalUrl))
|
|
17835
|
+
throw new Error("Invalid realtime WebSocket URL");
|
|
17836
|
+
const parsed = new URL(finalUrl);
|
|
17837
|
+
if (!["ws:", "wss:"].includes(parsed.protocol) || parsed.hostname === "" || finalUrl.includes("#"))
|
|
17838
|
+
throw new Error("Invalid realtime WebSocket URL");
|
|
17839
|
+
} catch (e) {
|
|
17840
|
+
throw new Error(
|
|
17841
|
+
"Invalid realtime WebSocket URL; expected an absolute ws:// or wss:// URL with a host and no fragment"
|
|
17842
|
+
);
|
|
17843
|
+
}
|
|
17844
|
+
if (this.epoch !== epoch) return;
|
|
17845
|
+
const ws = new WebSocket(finalUrl, finalProtocols);
|
|
17182
17846
|
this.ws = ws;
|
|
17847
|
+
let starting = false;
|
|
17848
|
+
let connectionError;
|
|
17849
|
+
const codec = new RealtimeEventChannel({
|
|
17850
|
+
model: this.model,
|
|
17851
|
+
send: (data) => {
|
|
17852
|
+
if (this.epoch !== epoch || this.ws !== ws || !this.isOpen)
|
|
17853
|
+
throw new Error("Realtime WebSocket is not open");
|
|
17854
|
+
this.sendRaw(data);
|
|
17855
|
+
},
|
|
17856
|
+
onEvent: this.onServerEvent,
|
|
17857
|
+
onError: (error) => {
|
|
17858
|
+
if (!starting) this.onError(error);
|
|
17859
|
+
},
|
|
17860
|
+
onFatalError: (error) => this.fail(error)
|
|
17861
|
+
});
|
|
17862
|
+
if (this.epoch !== epoch) {
|
|
17863
|
+
codec.dispose();
|
|
17864
|
+
return;
|
|
17865
|
+
}
|
|
17866
|
+
this.codec = codec;
|
|
17183
17867
|
ws.onopen = () => {
|
|
17184
17868
|
if (this.ws !== ws) return;
|
|
17185
|
-
|
|
17869
|
+
starting = true;
|
|
17870
|
+
try {
|
|
17871
|
+
void Promise.resolve(onOpen()).catch((error) => {
|
|
17872
|
+
if (this.ws === ws)
|
|
17873
|
+
this.fail(
|
|
17874
|
+
error instanceof Error ? error : new Error(String(error))
|
|
17875
|
+
);
|
|
17876
|
+
}).finally(() => {
|
|
17877
|
+
starting = false;
|
|
17878
|
+
});
|
|
17879
|
+
} catch (error) {
|
|
17880
|
+
if (this.epoch === epoch)
|
|
17881
|
+
this.fail(error instanceof Error ? error : new Error(String(error)));
|
|
17882
|
+
}
|
|
17186
17883
|
};
|
|
17187
17884
|
ws.onmessage = (messageEvent) => {
|
|
17188
|
-
|
|
17885
|
+
var _a26;
|
|
17886
|
+
if (this.ws === ws) (_a26 = this.codec) == null ? void 0 : _a26.receive(messageEvent.data);
|
|
17189
17887
|
};
|
|
17190
17888
|
ws.onerror = () => {
|
|
17191
|
-
this.
|
|
17889
|
+
if (this.ws === ws) {
|
|
17890
|
+
connectionError = new Error("WebSocket connection error");
|
|
17891
|
+
this.failing = true;
|
|
17892
|
+
}
|
|
17192
17893
|
};
|
|
17193
|
-
ws.onclose = () => {
|
|
17894
|
+
ws.onclose = (event) => {
|
|
17895
|
+
var _a26;
|
|
17194
17896
|
if (this.ws === ws) {
|
|
17195
17897
|
this.ws = null;
|
|
17196
|
-
|
|
17898
|
+
const closeError = (_a26 = getCloseError(event)) != null ? _a26 : connectionError;
|
|
17899
|
+
codec.stopWriting();
|
|
17900
|
+
this.notifyClosing();
|
|
17901
|
+
if (this.epoch !== epoch) return;
|
|
17902
|
+
const complete = () => {
|
|
17903
|
+
if (this.epoch !== epoch) return;
|
|
17904
|
+
clearTimeout(this.drainTimer);
|
|
17905
|
+
this.epoch++;
|
|
17906
|
+
codec.dispose();
|
|
17907
|
+
try {
|
|
17908
|
+
this.onClose(closeError);
|
|
17909
|
+
} catch (error) {
|
|
17910
|
+
this.reportCallbackError(error);
|
|
17911
|
+
}
|
|
17912
|
+
};
|
|
17913
|
+
this.drainTimer = setTimeout(complete, 1e3);
|
|
17914
|
+
void this.awaitDrain(codec.finish(), complete);
|
|
17197
17915
|
}
|
|
17198
17916
|
};
|
|
17199
17917
|
}
|
|
17200
17918
|
disconnect() {
|
|
17201
17919
|
var _a25;
|
|
17202
|
-
|
|
17920
|
+
this.epoch++;
|
|
17921
|
+
clearTimeout(this.drainTimer);
|
|
17922
|
+
const ws = this.ws;
|
|
17203
17923
|
this.ws = null;
|
|
17924
|
+
(_a25 = this.codec) == null ? void 0 : _a25.dispose();
|
|
17925
|
+
this.codec = void 0;
|
|
17926
|
+
this.failing = false;
|
|
17927
|
+
this.closing = false;
|
|
17928
|
+
ws == null ? void 0 : ws.close();
|
|
17929
|
+
}
|
|
17930
|
+
sendEvent(event, shouldSend, automaticAudio = false) {
|
|
17931
|
+
if (this.failing || this.closing)
|
|
17932
|
+
throw new Error("Realtime connection is closed");
|
|
17933
|
+
if (this.codec == null) return Promise.resolve();
|
|
17934
|
+
const epoch = this.epoch;
|
|
17935
|
+
const failed = (error) => {
|
|
17936
|
+
if (automaticAudio && this.epoch === epoch && this.isOpen)
|
|
17937
|
+
this.fail(error instanceof Error ? error : new Error(String(error)));
|
|
17938
|
+
};
|
|
17939
|
+
try {
|
|
17940
|
+
const sent = this.codec.send(event, shouldSend);
|
|
17941
|
+
void sent.catch(failed);
|
|
17942
|
+
return sent;
|
|
17943
|
+
} catch (error) {
|
|
17944
|
+
failed(error);
|
|
17945
|
+
throw error;
|
|
17946
|
+
}
|
|
17204
17947
|
}
|
|
17205
|
-
|
|
17206
|
-
|
|
17207
|
-
|
|
17208
|
-
|
|
17209
|
-
|
|
17948
|
+
finish() {
|
|
17949
|
+
var _a25, _b25;
|
|
17950
|
+
return (_b25 = (_a25 = this.codec) == null ? void 0 : _a25.finish()) != null ? _b25 : Promise.resolve();
|
|
17951
|
+
}
|
|
17952
|
+
/** Drain accepted events when media or protocol continuity is lost. */
|
|
17953
|
+
fail(error) {
|
|
17954
|
+
var _a25;
|
|
17955
|
+
if (this.failing) return;
|
|
17956
|
+
this.failing = true;
|
|
17957
|
+
const epoch = this.epoch;
|
|
17958
|
+
const ws = this.ws;
|
|
17959
|
+
this.ws = null;
|
|
17960
|
+
(_a25 = this.codec) == null ? void 0 : _a25.stopWriting();
|
|
17961
|
+
ws == null ? void 0 : ws.close();
|
|
17962
|
+
this.notifyClosing();
|
|
17963
|
+
if (this.epoch !== epoch) return;
|
|
17964
|
+
const drain = this.finish();
|
|
17965
|
+
if (this.options.onFatalError != null)
|
|
17966
|
+
this.options.onFatalError(error, drain);
|
|
17967
|
+
else {
|
|
17968
|
+
const complete = () => {
|
|
17969
|
+
if (epoch !== this.epoch) return;
|
|
17970
|
+
this.disconnect();
|
|
17971
|
+
try {
|
|
17972
|
+
this.onClose();
|
|
17973
|
+
} catch (cause) {
|
|
17974
|
+
this.reportCallbackError(cause);
|
|
17975
|
+
}
|
|
17976
|
+
};
|
|
17977
|
+
this.drainTimer = setTimeout(complete, 1e3);
|
|
17978
|
+
void this.awaitDrain(drain, complete);
|
|
17979
|
+
this.reportCallbackError(error);
|
|
17980
|
+
}
|
|
17981
|
+
}
|
|
17982
|
+
notifyClosing() {
|
|
17983
|
+
var _a25, _b25;
|
|
17984
|
+
if (this.closing) return;
|
|
17985
|
+
this.closing = true;
|
|
17986
|
+
try {
|
|
17987
|
+
(_b25 = (_a25 = this.options).onClosing) == null ? void 0 : _b25.call(_a25);
|
|
17988
|
+
} catch (error) {
|
|
17989
|
+
this.reportCallbackError(error);
|
|
17990
|
+
}
|
|
17991
|
+
}
|
|
17992
|
+
async awaitDrain(drain, complete) {
|
|
17993
|
+
try {
|
|
17994
|
+
await drain;
|
|
17995
|
+
} catch (e) {
|
|
17996
|
+
}
|
|
17997
|
+
try {
|
|
17998
|
+
complete();
|
|
17999
|
+
} catch (error) {
|
|
18000
|
+
this.reportCallbackError(error);
|
|
18001
|
+
}
|
|
18002
|
+
}
|
|
18003
|
+
reportCallbackError(error) {
|
|
18004
|
+
try {
|
|
18005
|
+
this.onError(error instanceof Error ? error : new Error(String(error)));
|
|
18006
|
+
} catch (e) {
|
|
18007
|
+
}
|
|
18008
|
+
}
|
|
18009
|
+
sendRaw(data) {
|
|
18010
|
+
const ws = this.ws;
|
|
18011
|
+
const epoch = this.epoch;
|
|
18012
|
+
if (ws == null || !this.isOpen) return;
|
|
18013
|
+
const frame = encodeRealtimeFrame(data);
|
|
18014
|
+
if (this.epoch !== epoch || this.ws !== ws || !this.isOpen)
|
|
18015
|
+
throw new Error("Realtime connection is closed");
|
|
18016
|
+
if (this.continuous) assertRealtimeFrameBudget(frame, ws.bufferedAmount);
|
|
18017
|
+
ws.send(frame.data);
|
|
18018
|
+
}
|
|
18019
|
+
dispose() {
|
|
18020
|
+
this.disconnect();
|
|
18021
|
+
}
|
|
18022
|
+
};
|
|
18023
|
+
|
|
18024
|
+
// src/realtime/browser-realtime-live-websocket.ts
|
|
18025
|
+
import { UnsupportedFunctionalityError as UnsupportedFunctionalityError5 } from "@ai-sdk/provider";
|
|
18026
|
+
var BrowserRealtimeLiveWebSocket = class {
|
|
18027
|
+
constructor(options) {
|
|
18028
|
+
this.options = options;
|
|
18029
|
+
this.generation = 0;
|
|
18030
|
+
this.ready = false;
|
|
18031
|
+
this.capturingStarted = false;
|
|
18032
|
+
this.pendingAudio = 0;
|
|
18033
|
+
this.captureGeneration = 0;
|
|
18034
|
+
this.captureEnabled = true;
|
|
18035
|
+
var _a25, _b25, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
18036
|
+
const input = (_a25 = options.sessionConfig) == null ? void 0 : _a25.inputAudioFormat;
|
|
18037
|
+
const output = (_b25 = options.sessionConfig) == null ? void 0 : _b25.outputAudioFormat;
|
|
18038
|
+
const sampleRate = (_e = (_d = (_c = input == null ? void 0 : input.rate) != null ? _c : output == null ? void 0 : output.rate) != null ? _d : options.sampleRate) != null ? _e : 24e3;
|
|
18039
|
+
const format = {
|
|
18040
|
+
type: (_g = (_f = input == null ? void 0 : input.type) != null ? _f : output == null ? void 0 : output.type) != null ? _g : "audio/pcm",
|
|
18041
|
+
rate: sampleRate
|
|
18042
|
+
};
|
|
18043
|
+
this.config = {
|
|
18044
|
+
...options.sessionConfig,
|
|
18045
|
+
inputAudioFormat: {
|
|
18046
|
+
...format,
|
|
18047
|
+
...input
|
|
18048
|
+
},
|
|
18049
|
+
outputAudioFormat: {
|
|
18050
|
+
...format,
|
|
18051
|
+
...output
|
|
17210
18052
|
}
|
|
17211
|
-
}
|
|
17212
|
-
|
|
17213
|
-
|
|
18053
|
+
};
|
|
18054
|
+
this.transport = new BrowserRealtimeTransport({
|
|
18055
|
+
model: options.model,
|
|
18056
|
+
onServerEvent: options.onEvent,
|
|
18057
|
+
onError: options.onError,
|
|
18058
|
+
onFatalError: options.onFatalError,
|
|
18059
|
+
onClosing: () => {
|
|
18060
|
+
var _a26;
|
|
18061
|
+
const generation = this.generation;
|
|
18062
|
+
(_a26 = options.onClosing) == null ? void 0 : _a26.call(options);
|
|
18063
|
+
if (generation === this.generation) this.stopCapture();
|
|
18064
|
+
},
|
|
18065
|
+
onClose: options.onClose
|
|
18066
|
+
});
|
|
18067
|
+
this.audio = new BrowserRealtimeAudio({
|
|
18068
|
+
captureSampleRate: (_i = (_h = this.config.inputAudioFormat) == null ? void 0 : _h.rate) != null ? _i : sampleRate,
|
|
18069
|
+
playbackSampleRate: (_k = (_j = this.config.outputAudioFormat) == null ? void 0 : _j.rate) != null ? _k : sampleRate,
|
|
18070
|
+
maxPlaybackSeconds: (_l = options.maxPlaybackBufferSeconds) != null ? _l : 2,
|
|
18071
|
+
onAudio: (audio) => this.sendAudio(audio),
|
|
18072
|
+
onError: options.onError,
|
|
18073
|
+
onCapturingChange: options.onCapturing,
|
|
18074
|
+
onPlayingChange: options.onPlaying
|
|
18075
|
+
});
|
|
18076
|
+
}
|
|
18077
|
+
connect(options) {
|
|
18078
|
+
const generation = this.generation + 1;
|
|
18079
|
+
this.dispose();
|
|
18080
|
+
if (generation !== this.generation) return;
|
|
18081
|
+
for (const format of [
|
|
18082
|
+
this.config.inputAudioFormat,
|
|
18083
|
+
this.config.outputAudioFormat
|
|
18084
|
+
]) {
|
|
18085
|
+
if ((format == null ? void 0 : format.type) !== "audio/pcm")
|
|
18086
|
+
throw new UnsupportedFunctionalityError5({
|
|
18087
|
+
functionality: "Continuous browser WebSocket audio supports PCM16 only"
|
|
18088
|
+
});
|
|
18089
|
+
if (format.rate == null || !Number.isFinite(format.rate) || format.rate < 8e3 || format.rate > 96e3)
|
|
18090
|
+
throw new Error("Invalid realtime PCM sample rate");
|
|
18091
|
+
}
|
|
18092
|
+
this.stream = options.stream;
|
|
18093
|
+
this.captureEnabled = options.capture !== false;
|
|
18094
|
+
this.audio.ensurePlaybackContext();
|
|
18095
|
+
void this.audio.resumePlayback().catch((error) => {
|
|
18096
|
+
if (generation === this.generation) this.options.onError(error);
|
|
18097
|
+
});
|
|
18098
|
+
this.transport.connect({
|
|
18099
|
+
mode: "relay",
|
|
18100
|
+
url: options.url,
|
|
18101
|
+
protocols: options.protocols,
|
|
18102
|
+
onOpen: () => {
|
|
18103
|
+
var _a25, _b25;
|
|
18104
|
+
return this.transport.sendEvent({
|
|
18105
|
+
type: (_b25 = (_a25 = this.options.model.capabilities) == null ? void 0 : _a25.startup) != null ? _b25 : "session-update",
|
|
18106
|
+
config: this.config
|
|
18107
|
+
});
|
|
18108
|
+
}
|
|
18109
|
+
});
|
|
18110
|
+
}
|
|
18111
|
+
startCapture() {
|
|
18112
|
+
this.ready = true;
|
|
18113
|
+
if (!this.captureEnabled || this.capturingStarted) return;
|
|
18114
|
+
void this.resumeCapture().catch((error) => this.options.onError(error));
|
|
18115
|
+
}
|
|
18116
|
+
async resumeCapture(suppliedStream) {
|
|
18117
|
+
const generation = this.captureGeneration + 1;
|
|
18118
|
+
this.stopCapture();
|
|
18119
|
+
if (generation !== this.captureGeneration) return;
|
|
18120
|
+
this.ready = true;
|
|
18121
|
+
this.capturingStarted = true;
|
|
18122
|
+
this.captureEnabled = true;
|
|
18123
|
+
if (suppliedStream != null) this.stream = suppliedStream;
|
|
18124
|
+
const supplied = this.stream;
|
|
18125
|
+
const stream = supplied != null ? supplied : await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
18126
|
+
if (generation !== this.captureGeneration || !this.ready) {
|
|
18127
|
+
if (supplied == null) stream.getTracks().forEach((track) => track.stop());
|
|
18128
|
+
return;
|
|
18129
|
+
}
|
|
18130
|
+
if (!stream.getAudioTracks().some((track) => track.readyState === "live")) {
|
|
18131
|
+
if (supplied == null) stream.getTracks().forEach((track) => track.stop());
|
|
18132
|
+
throw new Error("Realtime requires a live audio track");
|
|
18133
|
+
}
|
|
18134
|
+
this.audio.startCapture(stream, { ownsStream: supplied == null });
|
|
18135
|
+
}
|
|
18136
|
+
sendAudio(audio) {
|
|
18137
|
+
if (!this.ready || !this.transport.isOpen) return;
|
|
18138
|
+
if (this.pendingAudio >= 8) {
|
|
18139
|
+
this.transport.fail(new Error("Realtime audio send queue is full"));
|
|
18140
|
+
return;
|
|
18141
|
+
}
|
|
18142
|
+
const generation = this.generation;
|
|
18143
|
+
let sent;
|
|
18144
|
+
try {
|
|
18145
|
+
sent = this.transport.sendEvent(
|
|
18146
|
+
{ type: "input-audio-append", audio },
|
|
18147
|
+
void 0,
|
|
18148
|
+
true
|
|
17214
18149
|
);
|
|
18150
|
+
} catch (error) {
|
|
18151
|
+
if (!this.ready || !this.transport.isOpen) return;
|
|
18152
|
+
throw error;
|
|
18153
|
+
}
|
|
18154
|
+
this.pendingAudio++;
|
|
18155
|
+
void sent.then(
|
|
18156
|
+
() => {
|
|
18157
|
+
if (generation === this.generation) this.pendingAudio--;
|
|
18158
|
+
},
|
|
18159
|
+
(error) => {
|
|
18160
|
+
if (generation === this.generation && this.ready && this.transport.isOpen)
|
|
18161
|
+
this.options.onFatalError(error);
|
|
18162
|
+
}
|
|
18163
|
+
);
|
|
18164
|
+
}
|
|
18165
|
+
sendEvent(event, shouldSend) {
|
|
18166
|
+
var _a25, _b25;
|
|
18167
|
+
if (event.type === "session-update") {
|
|
18168
|
+
for (const key of ["inputAudioFormat", "outputAudioFormat"]) {
|
|
18169
|
+
const update = event.config[key];
|
|
18170
|
+
if (update != null && (update.type !== ((_a25 = this.config[key]) == null ? void 0 : _a25.type) || update.rate != null && update.rate !== ((_b25 = this.config[key]) == null ? void 0 : _b25.rate))) {
|
|
18171
|
+
throw new Error(
|
|
18172
|
+
"Changing Live WebSocket audio format requires reconnecting"
|
|
18173
|
+
);
|
|
18174
|
+
}
|
|
18175
|
+
}
|
|
18176
|
+
}
|
|
18177
|
+
return this.transport.sendEvent(event, shouldSend);
|
|
18178
|
+
}
|
|
18179
|
+
playAudio(audio) {
|
|
18180
|
+
try {
|
|
18181
|
+
this.audio.playAudio(audio);
|
|
18182
|
+
} catch (error) {
|
|
18183
|
+
this.options.onError(
|
|
18184
|
+
error instanceof Error ? error : new Error(String(error))
|
|
18185
|
+
);
|
|
18186
|
+
}
|
|
18187
|
+
}
|
|
18188
|
+
stopPlayback() {
|
|
18189
|
+
this.audio.stopPlayback();
|
|
18190
|
+
}
|
|
18191
|
+
resumePlayback() {
|
|
18192
|
+
return this.audio.resumePlayback();
|
|
18193
|
+
}
|
|
18194
|
+
stopCapture() {
|
|
18195
|
+
this.captureGeneration++;
|
|
18196
|
+
this.ready = false;
|
|
18197
|
+
this.capturingStarted = false;
|
|
18198
|
+
this.captureEnabled = false;
|
|
18199
|
+
this.audio.stopCapture();
|
|
18200
|
+
}
|
|
18201
|
+
finish() {
|
|
18202
|
+
return this.transport.finish();
|
|
18203
|
+
}
|
|
18204
|
+
dispose() {
|
|
18205
|
+
this.generation++;
|
|
18206
|
+
this.stopCapture();
|
|
18207
|
+
this.ready = false;
|
|
18208
|
+
this.capturingStarted = false;
|
|
18209
|
+
this.pendingAudio = 0;
|
|
18210
|
+
this.stream = void 0;
|
|
18211
|
+
this.transport.disconnect();
|
|
18212
|
+
this.audio.dispose();
|
|
18213
|
+
}
|
|
18214
|
+
};
|
|
18215
|
+
|
|
18216
|
+
// src/realtime/browser-realtime-webrtc.ts
|
|
18217
|
+
import { safeParseJSON as safeParseJSON6 } from "@ai-sdk/provider-utils";
|
|
18218
|
+
var MAX_SESSION_ANSWER_BYTES = 1024 * 1024;
|
|
18219
|
+
async function readSessionAnswer(response) {
|
|
18220
|
+
var _a25;
|
|
18221
|
+
const reader = (_a25 = response.body) == null ? void 0 : _a25.getReader();
|
|
18222
|
+
if (reader == null) throw new Error("Invalid realtime session answer");
|
|
18223
|
+
const decoder = new TextDecoder();
|
|
18224
|
+
let bytes = 0;
|
|
18225
|
+
let text2 = "";
|
|
18226
|
+
try {
|
|
18227
|
+
if (Number(response.headers.get("content-length")) > MAX_SESSION_ANSWER_BYTES)
|
|
18228
|
+
throw new Error("Realtime session answer exceeds the 1 MiB limit");
|
|
18229
|
+
while (true) {
|
|
18230
|
+
const { done, value } = await reader.read();
|
|
18231
|
+
if (done) return text2 + decoder.decode();
|
|
18232
|
+
bytes += value.byteLength;
|
|
18233
|
+
if (bytes > MAX_SESSION_ANSWER_BYTES)
|
|
18234
|
+
throw new Error("Realtime session answer exceeds the 1 MiB limit");
|
|
18235
|
+
text2 += decoder.decode(value, { stream: true });
|
|
18236
|
+
}
|
|
18237
|
+
} catch (error) {
|
|
18238
|
+
void reader.cancel(error).catch(() => {
|
|
18239
|
+
});
|
|
18240
|
+
throw error;
|
|
18241
|
+
} finally {
|
|
18242
|
+
reader.releaseLock();
|
|
18243
|
+
}
|
|
18244
|
+
}
|
|
18245
|
+
function selectAudioTrack(stream) {
|
|
18246
|
+
var _a25;
|
|
18247
|
+
const live = stream.getAudioTracks().filter((track) => track.readyState === "live");
|
|
18248
|
+
return (_a25 = live.find((track) => track.enabled && !track.muted)) != null ? _a25 : live[0];
|
|
18249
|
+
}
|
|
18250
|
+
var BrowserRealtimeWebRTC = class {
|
|
18251
|
+
constructor(options) {
|
|
18252
|
+
this.options = options;
|
|
18253
|
+
this.ownsStream = false;
|
|
18254
|
+
this.generation = 0;
|
|
18255
|
+
this.closingNotified = false;
|
|
18256
|
+
this.captureGeneration = 0;
|
|
18257
|
+
this.senderOperations = Promise.resolve();
|
|
18258
|
+
this.trackCleanups = [];
|
|
18259
|
+
}
|
|
18260
|
+
async connect({
|
|
18261
|
+
api,
|
|
18262
|
+
sessionConfig,
|
|
18263
|
+
stream,
|
|
18264
|
+
timeoutMs,
|
|
18265
|
+
capture = true
|
|
18266
|
+
}) {
|
|
18267
|
+
var _a25, _b25;
|
|
18268
|
+
const generation = this.generation + 1;
|
|
18269
|
+
this.dispose();
|
|
18270
|
+
const current = () => generation === this.generation;
|
|
18271
|
+
if (!current()) return;
|
|
18272
|
+
const config = (_b25 = (_a25 = this.options.model).getWebRTCConfig) == null ? void 0 : _b25.call(_a25);
|
|
18273
|
+
if (!current()) return;
|
|
18274
|
+
if (config == null)
|
|
18275
|
+
throw new Error("This model does not support WebRTC configuration");
|
|
18276
|
+
const abort = new AbortController();
|
|
18277
|
+
this.abort = abort;
|
|
18278
|
+
const timeout = setTimeout(
|
|
18279
|
+
() => abort.abort(new Error("Realtime startup timed out")),
|
|
18280
|
+
timeoutMs
|
|
18281
|
+
);
|
|
18282
|
+
const cancelled = new Promise((_, reject) => {
|
|
18283
|
+
abort.signal.addEventListener(
|
|
18284
|
+
"abort",
|
|
18285
|
+
() => reject(abort.signal.reason),
|
|
18286
|
+
{ once: true }
|
|
18287
|
+
);
|
|
18288
|
+
});
|
|
18289
|
+
const start = async () => {
|
|
18290
|
+
var _a26;
|
|
18291
|
+
const captureGeneration = this.captureGeneration;
|
|
18292
|
+
let media = capture ? stream != null ? stream : await navigator.mediaDevices.getUserMedia({ audio: true }) : void 0;
|
|
18293
|
+
if (!current() || abort.signal.aborted) {
|
|
18294
|
+
if (stream == null) media == null ? void 0 : media.getTracks().forEach((track2) => track2.stop());
|
|
18295
|
+
throw new Error("Realtime connection cancelled");
|
|
18296
|
+
}
|
|
18297
|
+
if (captureGeneration !== this.captureGeneration) {
|
|
18298
|
+
if (stream == null) media == null ? void 0 : media.getTracks().forEach((track2) => track2.stop());
|
|
18299
|
+
media = void 0;
|
|
18300
|
+
}
|
|
18301
|
+
this.stream = media;
|
|
18302
|
+
this.ownsStream = stream == null;
|
|
18303
|
+
const track = media == null ? void 0 : selectAudioTrack(media);
|
|
18304
|
+
if (media != null && track == null) {
|
|
18305
|
+
throw new Error("Realtime requires a live audio track");
|
|
18306
|
+
}
|
|
18307
|
+
const pc = new RTCPeerConnection();
|
|
18308
|
+
this.pc = pc;
|
|
18309
|
+
const audio = document.createElement("audio");
|
|
18310
|
+
audio.autoplay = true;
|
|
18311
|
+
this.audio = audio;
|
|
18312
|
+
audio.onplaying = () => {
|
|
18313
|
+
if (current()) this.options.onPlaying(true);
|
|
18314
|
+
};
|
|
18315
|
+
const stopped = () => {
|
|
18316
|
+
if (current()) this.options.onPlaying(false);
|
|
18317
|
+
};
|
|
18318
|
+
audio.onpause = stopped;
|
|
18319
|
+
audio.onended = stopped;
|
|
18320
|
+
audio.onwaiting = stopped;
|
|
18321
|
+
pc.ontrack = (event) => {
|
|
18322
|
+
var _a27;
|
|
18323
|
+
if (!current()) return;
|
|
18324
|
+
audio.srcObject = (_a27 = event.streams[0]) != null ? _a27 : new MediaStream([event.track]);
|
|
18325
|
+
void audio.play().catch((error) => {
|
|
18326
|
+
if (current()) this.options.onError(error);
|
|
18327
|
+
});
|
|
18328
|
+
};
|
|
18329
|
+
pc.onconnectionstatechange = () => {
|
|
18330
|
+
var _a27;
|
|
18331
|
+
if (!current()) return;
|
|
18332
|
+
if (pc.connectionState === "connected")
|
|
18333
|
+
clearTimeout(this.disconnectTimer);
|
|
18334
|
+
else if (pc.connectionState === "disconnected") {
|
|
18335
|
+
clearTimeout(this.disconnectTimer);
|
|
18336
|
+
this.disconnectTimer = setTimeout(() => {
|
|
18337
|
+
if (current() && pc.connectionState === "disconnected")
|
|
18338
|
+
this.fail(
|
|
18339
|
+
new Error(
|
|
18340
|
+
"Realtime peer disconnected beyond recovery grace period"
|
|
18341
|
+
)
|
|
18342
|
+
);
|
|
18343
|
+
}, (_a27 = this.options.disconnectTimeoutMs) != null ? _a27 : 5e3);
|
|
18344
|
+
} else if (pc.connectionState === "closed") {
|
|
18345
|
+
this.drainClose(new Error("Realtime peer connection closed"));
|
|
18346
|
+
} else if (pc.connectionState === "failed") {
|
|
18347
|
+
this.fail(
|
|
18348
|
+
new Error(`Realtime peer connection ${pc.connectionState}`)
|
|
18349
|
+
);
|
|
18350
|
+
}
|
|
18351
|
+
};
|
|
18352
|
+
pc.oniceconnectionstatechange = () => {
|
|
18353
|
+
if (current() && pc.iceConnectionState === "failed")
|
|
18354
|
+
this.fail(new Error("Realtime ICE connection failed"));
|
|
18355
|
+
};
|
|
18356
|
+
const dc = pc.createDataChannel(config.dataChannelLabel);
|
|
18357
|
+
this.dc = dc;
|
|
18358
|
+
const codec = new RealtimeEventChannel({
|
|
18359
|
+
model: this.options.model,
|
|
18360
|
+
onEvent: this.options.onEvent,
|
|
18361
|
+
onError: this.options.onError,
|
|
18362
|
+
onFatalError: (error) => {
|
|
18363
|
+
if (current()) this.fail(error);
|
|
18364
|
+
},
|
|
18365
|
+
send: (data) => {
|
|
18366
|
+
if (!current() || this.finishing || dc.readyState !== "open")
|
|
18367
|
+
throw new Error("Realtime data channel is not open");
|
|
18368
|
+
if (dc.bufferedAmount > 1024 * 1024)
|
|
18369
|
+
throw new Error("Realtime data channel buffer is full");
|
|
18370
|
+
const encoded = typeof data === "string" ? data : JSON.stringify(data);
|
|
18371
|
+
if (!current() || this.finishing || dc.readyState !== "open")
|
|
18372
|
+
throw new Error("Realtime data channel is not open");
|
|
18373
|
+
dc.send(encoded);
|
|
18374
|
+
}
|
|
18375
|
+
});
|
|
18376
|
+
if (!current()) {
|
|
18377
|
+
codec.dispose();
|
|
18378
|
+
return;
|
|
18379
|
+
}
|
|
18380
|
+
this.codec = codec;
|
|
18381
|
+
dc.onmessage = (event) => {
|
|
18382
|
+
var _a27;
|
|
18383
|
+
if (current()) (_a27 = this.codec) == null ? void 0 : _a27.receive(event.data);
|
|
18384
|
+
};
|
|
18385
|
+
dc.onclose = () => {
|
|
18386
|
+
if (current())
|
|
18387
|
+
this.drainClose(new Error("Realtime data channel closed"));
|
|
18388
|
+
};
|
|
18389
|
+
dc.onerror = () => {
|
|
18390
|
+
if (current()) this.fail(new Error("Realtime data channel error"));
|
|
18391
|
+
};
|
|
18392
|
+
const opened = new Promise((resolve3, reject) => {
|
|
18393
|
+
this.rejectStartup = reject;
|
|
18394
|
+
dc.onopen = () => {
|
|
18395
|
+
this.rejectStartup = void 0;
|
|
18396
|
+
resolve3();
|
|
18397
|
+
};
|
|
18398
|
+
});
|
|
18399
|
+
void opened.catch(() => {
|
|
18400
|
+
});
|
|
18401
|
+
const gathered = new Promise((resolve3) => {
|
|
18402
|
+
pc.onicegatheringstatechange = () => {
|
|
18403
|
+
if (pc.iceGatheringState === "complete") resolve3();
|
|
18404
|
+
};
|
|
18405
|
+
});
|
|
18406
|
+
this.sender = media != null && track != null ? pc.addTrack(track, media) : pc.addTransceiver("audio", { direction: "sendrecv" }).sender;
|
|
18407
|
+
this.observeCapture();
|
|
18408
|
+
if (!current() || abort.signal.aborted) return;
|
|
18409
|
+
const offer = await pc.createOffer();
|
|
18410
|
+
if (!current() || abort.signal.aborted) return;
|
|
18411
|
+
await pc.setLocalDescription(offer);
|
|
18412
|
+
if (pc.iceGatheringState !== "complete")
|
|
18413
|
+
await Promise.race([gathered, cancelled]);
|
|
18414
|
+
if (!current() || abort.signal.aborted) return;
|
|
18415
|
+
const sdp = (_a26 = pc.localDescription) == null ? void 0 : _a26.sdp;
|
|
18416
|
+
if (sdp == null) throw new Error("Realtime offer has no SDP");
|
|
18417
|
+
const response = await fetch(api, {
|
|
18418
|
+
method: "POST",
|
|
18419
|
+
headers: { "Content-Type": "application/json" },
|
|
18420
|
+
body: JSON.stringify({ sdp, sessionConfig }),
|
|
18421
|
+
signal: abort.signal
|
|
18422
|
+
});
|
|
18423
|
+
if (!response.ok)
|
|
18424
|
+
throw new Error(
|
|
18425
|
+
`Failed to create realtime session: ${response.status}`
|
|
18426
|
+
);
|
|
18427
|
+
const parsed = await safeParseJSON6({
|
|
18428
|
+
text: await readSessionAnswer(response)
|
|
18429
|
+
});
|
|
18430
|
+
if (!current() || abort.signal.aborted) return;
|
|
18431
|
+
if (!parsed.success || typeof parsed.value !== "object" || parsed.value == null || !("sdp" in parsed.value) || typeof parsed.value.sdp !== "string" || parsed.value.sdp.trim().length === 0 || !("sessionId" in parsed.value) || typeof parsed.value.sessionId !== "string" || parsed.value.sessionId.trim().length === 0) {
|
|
18432
|
+
throw new Error("Invalid realtime session answer");
|
|
18433
|
+
}
|
|
18434
|
+
await pc.setRemoteDescription({ type: "answer", sdp: parsed.value.sdp });
|
|
18435
|
+
await Promise.race([opened, cancelled]);
|
|
18436
|
+
};
|
|
18437
|
+
try {
|
|
18438
|
+
await Promise.race([start(), cancelled]);
|
|
18439
|
+
} catch (error) {
|
|
18440
|
+
if (current()) this.dispose();
|
|
18441
|
+
throw error;
|
|
18442
|
+
} finally {
|
|
18443
|
+
clearTimeout(timeout);
|
|
18444
|
+
this.rejectStartup = void 0;
|
|
18445
|
+
}
|
|
18446
|
+
}
|
|
18447
|
+
sendEvent(event, shouldSend) {
|
|
18448
|
+
var _a25, _b25, _c;
|
|
18449
|
+
if (this.finishing || ((_a25 = this.dc) == null ? void 0 : _a25.readyState) !== "open")
|
|
18450
|
+
throw new Error("Realtime data channel is not open");
|
|
18451
|
+
return (_c = (_b25 = this.codec) == null ? void 0 : _b25.send(event, shouldSend)) != null ? _c : Promise.resolve();
|
|
18452
|
+
}
|
|
18453
|
+
async resumePlayback() {
|
|
18454
|
+
if (this.audio == null)
|
|
18455
|
+
throw new Error("Realtime playback is not connected");
|
|
18456
|
+
await this.audio.play();
|
|
18457
|
+
}
|
|
18458
|
+
stopPlayback() {
|
|
18459
|
+
var _a25;
|
|
18460
|
+
(_a25 = this.audio) == null ? void 0 : _a25.pause();
|
|
18461
|
+
}
|
|
18462
|
+
finish() {
|
|
18463
|
+
var _a25, _b25;
|
|
18464
|
+
return (_b25 = (_a25 = this.codec) == null ? void 0 : _a25.finish()) != null ? _b25 : Promise.resolve();
|
|
18465
|
+
}
|
|
18466
|
+
fail(error) {
|
|
18467
|
+
var _a25;
|
|
18468
|
+
if (this.finishing === "failure") return;
|
|
18469
|
+
this.finishing = "failure";
|
|
18470
|
+
clearTimeout(this.finishTimer);
|
|
18471
|
+
if (this.rejectStartup != null) {
|
|
18472
|
+
this.rejectStartup(error);
|
|
18473
|
+
(_a25 = this.abort) == null ? void 0 : _a25.abort(error);
|
|
18474
|
+
return;
|
|
18475
|
+
}
|
|
18476
|
+
const generation = this.generation;
|
|
18477
|
+
const drain = this.finish();
|
|
18478
|
+
this.notifyClosing();
|
|
18479
|
+
if (generation !== this.generation) return;
|
|
18480
|
+
void this.stopCaptureForShutdown(generation);
|
|
18481
|
+
if (generation !== this.generation) return;
|
|
18482
|
+
if (this.options.onFatalError != null) {
|
|
18483
|
+
this.options.onFatalError(error, drain);
|
|
18484
|
+
return;
|
|
18485
|
+
}
|
|
18486
|
+
const complete = () => {
|
|
18487
|
+
if (generation !== this.generation) return;
|
|
18488
|
+
this.dispose();
|
|
18489
|
+
try {
|
|
18490
|
+
this.options.onClose();
|
|
18491
|
+
} catch (cause) {
|
|
18492
|
+
this.reportCallbackError(cause);
|
|
18493
|
+
}
|
|
18494
|
+
};
|
|
18495
|
+
this.finishTimer = setTimeout(complete, 1e3);
|
|
18496
|
+
void this.awaitDrain(drain, complete);
|
|
18497
|
+
try {
|
|
18498
|
+
this.options.onError(error);
|
|
18499
|
+
} catch (e) {
|
|
18500
|
+
}
|
|
18501
|
+
}
|
|
18502
|
+
drainClose(error) {
|
|
18503
|
+
if (this.finishing) return;
|
|
18504
|
+
if (this.rejectStartup != null) {
|
|
18505
|
+
this.fail(error);
|
|
18506
|
+
return;
|
|
18507
|
+
}
|
|
18508
|
+
this.finishing = "close";
|
|
18509
|
+
const generation = this.generation;
|
|
18510
|
+
const complete = () => {
|
|
18511
|
+
if (generation !== this.generation || this.finishing !== "close") return;
|
|
18512
|
+
clearTimeout(this.finishTimer);
|
|
18513
|
+
try {
|
|
18514
|
+
this.options.onClose(error);
|
|
18515
|
+
} catch (cause) {
|
|
18516
|
+
this.reportCallbackError(cause);
|
|
18517
|
+
} finally {
|
|
18518
|
+
if (generation === this.generation) this.dispose();
|
|
18519
|
+
}
|
|
18520
|
+
};
|
|
18521
|
+
this.finishTimer = setTimeout(complete, 1e3);
|
|
18522
|
+
void this.awaitDrain(this.finish(), complete);
|
|
18523
|
+
this.notifyClosing();
|
|
18524
|
+
if (generation !== this.generation) return;
|
|
18525
|
+
void this.stopCaptureForShutdown(generation);
|
|
18526
|
+
}
|
|
18527
|
+
notifyClosing() {
|
|
18528
|
+
var _a25, _b25;
|
|
18529
|
+
if (this.closingNotified) return;
|
|
18530
|
+
this.closingNotified = true;
|
|
18531
|
+
try {
|
|
18532
|
+
(_b25 = (_a25 = this.options).onClosing) == null ? void 0 : _b25.call(_a25);
|
|
18533
|
+
} catch (error) {
|
|
18534
|
+
this.reportCallbackError(error);
|
|
18535
|
+
}
|
|
18536
|
+
}
|
|
18537
|
+
async stopCaptureForShutdown(generation) {
|
|
18538
|
+
try {
|
|
18539
|
+
await this.stopCapture();
|
|
18540
|
+
} catch (cause) {
|
|
18541
|
+
if (generation !== this.generation || this.finishing !== "close") return;
|
|
18542
|
+
try {
|
|
18543
|
+
this.fail(cause instanceof Error ? cause : new Error(String(cause)));
|
|
18544
|
+
} catch (error) {
|
|
18545
|
+
this.reportCallbackError(error);
|
|
18546
|
+
}
|
|
18547
|
+
}
|
|
18548
|
+
}
|
|
18549
|
+
async awaitDrain(drain, complete) {
|
|
18550
|
+
try {
|
|
18551
|
+
await drain;
|
|
18552
|
+
} catch (e) {
|
|
18553
|
+
}
|
|
18554
|
+
try {
|
|
18555
|
+
complete();
|
|
18556
|
+
} catch (error) {
|
|
18557
|
+
this.reportCallbackError(error);
|
|
18558
|
+
}
|
|
18559
|
+
}
|
|
18560
|
+
reportCallbackError(error) {
|
|
18561
|
+
try {
|
|
18562
|
+
this.options.onError(
|
|
18563
|
+
error instanceof Error ? error : new Error(String(error))
|
|
18564
|
+
);
|
|
18565
|
+
} catch (e) {
|
|
18566
|
+
}
|
|
18567
|
+
}
|
|
18568
|
+
async stopCapture() {
|
|
18569
|
+
var _a25;
|
|
18570
|
+
const generation = ++this.captureGeneration;
|
|
18571
|
+
for (const cleanup of this.trackCleanups) cleanup();
|
|
18572
|
+
this.trackCleanups = [];
|
|
18573
|
+
if (this.ownsStream)
|
|
18574
|
+
(_a25 = this.stream) == null ? void 0 : _a25.getTracks().forEach((track) => track.stop());
|
|
18575
|
+
this.stream = void 0;
|
|
18576
|
+
const pc = this.pc;
|
|
18577
|
+
const sender = this.sender;
|
|
18578
|
+
await this.queueSenderOperation(async () => {
|
|
18579
|
+
if (pc !== this.pc || sender !== this.sender) return;
|
|
18580
|
+
if (pc != null && sender != null) await this.detachSender(pc, sender);
|
|
18581
|
+
if (generation === this.captureGeneration && pc === this.pc)
|
|
18582
|
+
this.options.onCapturing(false);
|
|
18583
|
+
});
|
|
18584
|
+
}
|
|
18585
|
+
async startCapture(supplied) {
|
|
18586
|
+
const generation = this.captureGeneration + 1;
|
|
18587
|
+
await this.stopCapture();
|
|
18588
|
+
if (generation !== this.captureGeneration || this.pc == null || this.finishing)
|
|
18589
|
+
return;
|
|
18590
|
+
const media = supplied != null ? supplied : await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
18591
|
+
if (generation !== this.captureGeneration || this.pc == null || this.finishing) {
|
|
18592
|
+
if (supplied == null) media.getTracks().forEach((track2) => track2.stop());
|
|
18593
|
+
return;
|
|
18594
|
+
}
|
|
18595
|
+
const track = selectAudioTrack(media);
|
|
18596
|
+
if (track == null) {
|
|
18597
|
+
if (supplied == null) media.getTracks().forEach((track2) => track2.stop());
|
|
18598
|
+
throw new Error("Realtime requires a live audio track");
|
|
18599
|
+
}
|
|
18600
|
+
const pc = this.pc;
|
|
18601
|
+
const sender = this.sender;
|
|
18602
|
+
await this.queueSenderOperation(async () => {
|
|
18603
|
+
const current = () => generation === this.captureGeneration && pc === this.pc && sender === this.sender && pc.connectionState !== "closed" && !this.finishing;
|
|
18604
|
+
let attached = false;
|
|
18605
|
+
try {
|
|
18606
|
+
if (!current() || sender == null) return;
|
|
18607
|
+
await sender.replaceTrack(track);
|
|
18608
|
+
if (!current()) {
|
|
18609
|
+
if (pc === this.pc) await this.detachSender(pc, sender);
|
|
18610
|
+
return;
|
|
18611
|
+
}
|
|
18612
|
+
this.stream = media;
|
|
18613
|
+
this.ownsStream = supplied == null;
|
|
18614
|
+
attached = true;
|
|
18615
|
+
this.observeCapture();
|
|
18616
|
+
} finally {
|
|
18617
|
+
if (!attached && supplied == null)
|
|
18618
|
+
media.getTracks().forEach((track2) => track2.stop());
|
|
18619
|
+
}
|
|
18620
|
+
});
|
|
18621
|
+
}
|
|
18622
|
+
queueSenderOperation(operation) {
|
|
18623
|
+
const pending = this.senderOperations.then(operation);
|
|
18624
|
+
this.senderOperations = pending.catch(() => {
|
|
18625
|
+
});
|
|
18626
|
+
return pending;
|
|
18627
|
+
}
|
|
18628
|
+
async detachSender(pc, sender) {
|
|
18629
|
+
if (pc.connectionState === "closed") return;
|
|
18630
|
+
try {
|
|
18631
|
+
await sender.replaceTrack(null);
|
|
18632
|
+
} catch (error) {
|
|
18633
|
+
if (pc !== this.pc) return;
|
|
18634
|
+
this.closePeer(pc);
|
|
18635
|
+
this.fail(error instanceof Error ? error : new Error(String(error)));
|
|
18636
|
+
}
|
|
18637
|
+
}
|
|
18638
|
+
closePeer(pc) {
|
|
18639
|
+
pc.ontrack = null;
|
|
18640
|
+
pc.onconnectionstatechange = null;
|
|
18641
|
+
pc.oniceconnectionstatechange = null;
|
|
18642
|
+
pc.onicegatheringstatechange = null;
|
|
18643
|
+
if (pc.connectionState !== "closed") pc.close();
|
|
18644
|
+
}
|
|
18645
|
+
observeCapture() {
|
|
18646
|
+
const generation = this.captureGeneration;
|
|
18647
|
+
const sender = this.sender;
|
|
18648
|
+
const track = sender == null ? void 0 : sender.track;
|
|
18649
|
+
const update = () => {
|
|
18650
|
+
if (generation === this.captureGeneration && this.sender === sender)
|
|
18651
|
+
this.options.onCapturing(
|
|
18652
|
+
(sender == null ? void 0 : sender.track) != null && sender.track.readyState === "live" && sender.track.enabled && !sender.track.muted
|
|
18653
|
+
);
|
|
18654
|
+
};
|
|
18655
|
+
if (track != null) {
|
|
18656
|
+
for (const event of ["ended", "mute", "unmute"]) {
|
|
18657
|
+
track.addEventListener(event, update);
|
|
18658
|
+
this.trackCleanups.push(() => track.removeEventListener(event, update));
|
|
18659
|
+
}
|
|
18660
|
+
}
|
|
18661
|
+
update();
|
|
18662
|
+
}
|
|
18663
|
+
dispose() {
|
|
18664
|
+
var _a25, _b25, _c;
|
|
18665
|
+
this.generation++;
|
|
18666
|
+
this.captureGeneration++;
|
|
18667
|
+
clearTimeout(this.finishTimer);
|
|
18668
|
+
clearTimeout(this.disconnectTimer);
|
|
18669
|
+
this.finishing = void 0;
|
|
18670
|
+
this.closingNotified = false;
|
|
18671
|
+
this.senderOperations = Promise.resolve();
|
|
18672
|
+
(_a25 = this.abort) == null ? void 0 : _a25.abort(new Error("Realtime connection cancelled"));
|
|
18673
|
+
this.abort = void 0;
|
|
18674
|
+
(_b25 = this.codec) == null ? void 0 : _b25.dispose();
|
|
18675
|
+
this.codec = void 0;
|
|
18676
|
+
if (this.dc != null) {
|
|
18677
|
+
this.dc.onopen = null;
|
|
18678
|
+
this.dc.onclose = null;
|
|
18679
|
+
this.dc.onerror = null;
|
|
18680
|
+
this.dc.onmessage = null;
|
|
18681
|
+
this.dc.close();
|
|
18682
|
+
this.dc = void 0;
|
|
18683
|
+
}
|
|
18684
|
+
if (this.pc != null) {
|
|
18685
|
+
this.closePeer(this.pc);
|
|
18686
|
+
this.pc = void 0;
|
|
18687
|
+
}
|
|
18688
|
+
for (const cleanup of this.trackCleanups) cleanup();
|
|
18689
|
+
this.trackCleanups = [];
|
|
18690
|
+
if (this.ownsStream)
|
|
18691
|
+
(_c = this.stream) == null ? void 0 : _c.getTracks().forEach((track) => track.stop());
|
|
18692
|
+
this.stream = void 0;
|
|
18693
|
+
this.sender = void 0;
|
|
18694
|
+
if (this.audio != null) {
|
|
18695
|
+
this.audio.onplaying = null;
|
|
18696
|
+
this.audio.onpause = null;
|
|
18697
|
+
this.audio.onended = null;
|
|
18698
|
+
this.audio.onwaiting = null;
|
|
18699
|
+
this.audio.pause();
|
|
18700
|
+
this.audio.srcObject = null;
|
|
18701
|
+
this.audio = void 0;
|
|
18702
|
+
}
|
|
18703
|
+
this.options.onCapturing(false);
|
|
18704
|
+
this.options.onPlaying(false);
|
|
18705
|
+
}
|
|
18706
|
+
};
|
|
18707
|
+
|
|
18708
|
+
// src/realtime/realtime-attempt.ts
|
|
18709
|
+
var RealtimeAttempt = class {
|
|
18710
|
+
constructor() {
|
|
18711
|
+
this.abort = new AbortController();
|
|
18712
|
+
this.timers = /* @__PURE__ */ new Map();
|
|
18713
|
+
this.active = true;
|
|
18714
|
+
this.ready = false;
|
|
18715
|
+
this.closing = false;
|
|
18716
|
+
this.transportClosing = false;
|
|
18717
|
+
}
|
|
18718
|
+
timer(name25, duration, callback) {
|
|
18719
|
+
this.clearTimer(name25);
|
|
18720
|
+
this.timers.set(
|
|
18721
|
+
name25,
|
|
18722
|
+
setTimeout(() => {
|
|
18723
|
+
this.timers.delete(name25);
|
|
18724
|
+
if (this.active) callback();
|
|
18725
|
+
}, duration)
|
|
18726
|
+
);
|
|
18727
|
+
}
|
|
18728
|
+
clearTimer(name25) {
|
|
18729
|
+
clearTimeout(this.timers.get(name25));
|
|
18730
|
+
this.timers.delete(name25);
|
|
18731
|
+
}
|
|
18732
|
+
beginClose() {
|
|
18733
|
+
var _a25;
|
|
18734
|
+
this.closing = true;
|
|
18735
|
+
return (_a25 = this.closePromise) != null ? _a25 : this.closePromise = new Promise((resolve3) => {
|
|
18736
|
+
this.settleClose = resolve3;
|
|
17215
18737
|
});
|
|
17216
18738
|
}
|
|
17217
|
-
|
|
18739
|
+
retire() {
|
|
17218
18740
|
var _a25;
|
|
17219
|
-
if (
|
|
17220
|
-
|
|
17221
|
-
|
|
17222
|
-
|
|
17223
|
-
|
|
17224
|
-
|
|
17225
|
-
|
|
18741
|
+
if (!this.active) return;
|
|
18742
|
+
this.active = false;
|
|
18743
|
+
this.abort.abort();
|
|
18744
|
+
for (const timer of this.timers.values()) clearTimeout(timer);
|
|
18745
|
+
this.timers.clear();
|
|
18746
|
+
(_a25 = this.settleClose) == null ? void 0 : _a25.call(this);
|
|
18747
|
+
this.settleClose = void 0;
|
|
17226
18748
|
}
|
|
17227
|
-
|
|
17228
|
-
|
|
18749
|
+
};
|
|
18750
|
+
|
|
18751
|
+
// src/realtime/realtime-command-tracker.ts
|
|
18752
|
+
import { generateId as generateId3 } from "@ai-sdk/provider-utils";
|
|
18753
|
+
var RealtimeCommandTracker = class {
|
|
18754
|
+
constructor(sendCommand) {
|
|
18755
|
+
this.sendCommand = sendCommand;
|
|
18756
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
18757
|
+
this.recent = /* @__PURE__ */ new Set();
|
|
18758
|
+
}
|
|
18759
|
+
validateId(id) {
|
|
18760
|
+
if (this.pending.has(id) || this.recent.has(id))
|
|
18761
|
+
throw new Error(
|
|
18762
|
+
"Realtime command ID was already used; retry with a fresh eventId"
|
|
18763
|
+
);
|
|
18764
|
+
if (this.pending.size >= 512)
|
|
18765
|
+
throw new Error("Too many pending realtime commands");
|
|
17229
18766
|
}
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
if (
|
|
17233
|
-
|
|
17234
|
-
|
|
17235
|
-
|
|
17236
|
-
|
|
17237
|
-
|
|
17238
|
-
}
|
|
17239
|
-
const parseResult = await safeParseJSON5({ text: text2 });
|
|
17240
|
-
if (!parseResult.success) return;
|
|
17241
|
-
const rawEvent = parseResult.value;
|
|
17242
|
-
if (this.model.getHealthCheckResponse != null) {
|
|
17243
|
-
const autoResponse = this.model.getHealthCheckResponse(rawEvent);
|
|
17244
|
-
if (autoResponse != null) {
|
|
17245
|
-
this.sendRaw(autoResponse);
|
|
17246
|
-
}
|
|
18767
|
+
complete(id) {
|
|
18768
|
+
const command = this.pending.get(id);
|
|
18769
|
+
if (command == null) return;
|
|
18770
|
+
this.pending.delete(id);
|
|
18771
|
+
this.recent.add(id);
|
|
18772
|
+
if (this.recent.size > 4096) {
|
|
18773
|
+
const oldest = this.recent.values().next().value;
|
|
18774
|
+
if (oldest != null) this.recent.delete(oldest);
|
|
17247
18775
|
}
|
|
17248
|
-
|
|
17249
|
-
|
|
17250
|
-
|
|
17251
|
-
|
|
18776
|
+
return command;
|
|
18777
|
+
}
|
|
18778
|
+
send(event) {
|
|
18779
|
+
var _a25;
|
|
18780
|
+
const muted = event.type === "input-audio-mute" ? true : event.type === "input-audio-unmute" ? false : void 0;
|
|
18781
|
+
if (event.type === "input-audio-mute" || event.type === "input-audio-unmute")
|
|
18782
|
+
event = { ...event, eventId: (_a25 = event.eventId) != null ? _a25 : generateId3() };
|
|
18783
|
+
const id = "eventId" in event ? event.eventId : void 0;
|
|
18784
|
+
if (id != null) {
|
|
18785
|
+
this.validateId(id);
|
|
18786
|
+
this.pending.set(id, { muted });
|
|
18787
|
+
}
|
|
18788
|
+
const awaitsAcknowledgement = event.type === "context-append" || event.type === "session-update" || muted != null;
|
|
18789
|
+
try {
|
|
18790
|
+
const sent = this.sendCommand(event);
|
|
18791
|
+
void sent.then(
|
|
18792
|
+
() => {
|
|
18793
|
+
if (id != null && !awaitsAcknowledgement) this.complete(id);
|
|
18794
|
+
},
|
|
18795
|
+
() => {
|
|
18796
|
+
if (id != null) this.complete(id);
|
|
18797
|
+
}
|
|
18798
|
+
);
|
|
18799
|
+
return sent;
|
|
18800
|
+
} catch (error) {
|
|
18801
|
+
if (id != null) this.complete(id);
|
|
18802
|
+
throw error;
|
|
17252
18803
|
}
|
|
17253
18804
|
}
|
|
18805
|
+
receive(event) {
|
|
18806
|
+
if (event.type === "command-acknowledged" && event.clientEventId != null)
|
|
18807
|
+
return this.complete(event.clientEventId);
|
|
18808
|
+
if (event.type === "error" && event.clientEventId != null)
|
|
18809
|
+
this.complete(event.clientEventId);
|
|
18810
|
+
}
|
|
17254
18811
|
};
|
|
17255
18812
|
|
|
18813
|
+
// src/realtime/validate-realtime-setup.ts
|
|
18814
|
+
var setupSchema = z.object({
|
|
18815
|
+
token: z.string().refine((value) => value.trim().length > 0),
|
|
18816
|
+
url: z.string().refine((value) => {
|
|
18817
|
+
try {
|
|
18818
|
+
const url = new URL(value);
|
|
18819
|
+
return (url.protocol === "ws:" || url.protocol === "wss:") && url.hostname !== "";
|
|
18820
|
+
} catch (e) {
|
|
18821
|
+
return false;
|
|
18822
|
+
}
|
|
18823
|
+
}),
|
|
18824
|
+
expiresAt: z.number().positive().max(Number.MAX_SAFE_INTEGER).optional(),
|
|
18825
|
+
tools: z.array(
|
|
18826
|
+
z.object({
|
|
18827
|
+
type: z.literal("function"),
|
|
18828
|
+
name: z.string().min(1),
|
|
18829
|
+
description: z.string().optional(),
|
|
18830
|
+
parameters: z.record(z.string(), z.unknown())
|
|
18831
|
+
})
|
|
18832
|
+
).optional()
|
|
18833
|
+
});
|
|
18834
|
+
function validateRealtimeSetup(payload) {
|
|
18835
|
+
const result = setupSchema.safeParse(payload);
|
|
18836
|
+
if (!result.success)
|
|
18837
|
+
throw new Error(
|
|
18838
|
+
"Invalid realtime setup: expected a nonempty token, a ws(s) URL, and valid optional expiresAt/tools"
|
|
18839
|
+
);
|
|
18840
|
+
return result.data;
|
|
18841
|
+
}
|
|
18842
|
+
|
|
18843
|
+
// src/realtime/realtime-session-state.ts
|
|
18844
|
+
function createSessionState() {
|
|
18845
|
+
return {
|
|
18846
|
+
transcripts: [],
|
|
18847
|
+
delegations: [],
|
|
18848
|
+
isInputMuted: false,
|
|
18849
|
+
finalization: "pending"
|
|
18850
|
+
};
|
|
18851
|
+
}
|
|
18852
|
+
function reduceSessionState(state, event, limit, muted) {
|
|
18853
|
+
var _a25;
|
|
18854
|
+
switch (event.type) {
|
|
18855
|
+
case "session-started":
|
|
18856
|
+
return {
|
|
18857
|
+
...state,
|
|
18858
|
+
sessionId: event.sessionId,
|
|
18859
|
+
delegationMode: event.delegationMode
|
|
18860
|
+
};
|
|
18861
|
+
case "session-usage":
|
|
18862
|
+
return { ...state, usage: event.usage };
|
|
18863
|
+
case "session-closed":
|
|
18864
|
+
return {
|
|
18865
|
+
...state,
|
|
18866
|
+
sessionId: (_a25 = event.sessionId) != null ? _a25 : state.sessionId,
|
|
18867
|
+
usage: event.usage,
|
|
18868
|
+
terminationReason: event.reason,
|
|
18869
|
+
finalization: "confirmed"
|
|
18870
|
+
};
|
|
18871
|
+
case "transcript-fragment":
|
|
18872
|
+
return {
|
|
18873
|
+
...state,
|
|
18874
|
+
transcripts: [...state.transcripts, event].slice(-limit)
|
|
18875
|
+
};
|
|
18876
|
+
case "delegation-created":
|
|
18877
|
+
return state.delegations.some(
|
|
18878
|
+
(item) => item.delegationId === event.delegationId
|
|
18879
|
+
) ? state : {
|
|
18880
|
+
...state,
|
|
18881
|
+
delegations: [...state.delegations, event].slice(-limit)
|
|
18882
|
+
};
|
|
18883
|
+
case "command-acknowledged":
|
|
18884
|
+
return muted == null ? state : { ...state, isInputMuted: muted };
|
|
18885
|
+
default:
|
|
18886
|
+
return state;
|
|
18887
|
+
}
|
|
18888
|
+
}
|
|
18889
|
+
|
|
17256
18890
|
// src/realtime/realtime-event-reducer.ts
|
|
17257
|
-
import { safeParseJSON as
|
|
18891
|
+
import { safeParseJSON as safeParseJSON7 } from "@ai-sdk/provider-utils";
|
|
17258
18892
|
function createInitialRealtimeState() {
|
|
17259
18893
|
return {
|
|
17260
18894
|
status: "disconnected",
|
|
@@ -17383,7 +19017,7 @@ var RealtimeEventReducer = class {
|
|
|
17383
19017
|
case "function-call-arguments-done": {
|
|
17384
19018
|
this.toolArgAccumulators.delete(event.callId);
|
|
17385
19019
|
this.toolCallIdToName.set(event.callId, event.name);
|
|
17386
|
-
const parseResult = await
|
|
19020
|
+
const parseResult = await safeParseJSON7({ text: event.arguments });
|
|
17387
19021
|
const parsedInput = parseResult.success ? parseResult.value : {};
|
|
17388
19022
|
const messageId = this.toolCallIdToMessageId.get(event.callId);
|
|
17389
19023
|
if (messageId != null) {
|
|
@@ -17623,98 +19257,375 @@ var RealtimeEventReducer = class {
|
|
|
17623
19257
|
// src/realtime/realtime-session.ts
|
|
17624
19258
|
var AbstractRealtimeSession = class {
|
|
17625
19259
|
constructor(options) {
|
|
19260
|
+
this.options = options;
|
|
17626
19261
|
this.state = createInitialRealtimeState();
|
|
19262
|
+
this.publication = 0;
|
|
19263
|
+
this.captureGeneration = 0;
|
|
19264
|
+
this.captureRequested = false;
|
|
17627
19265
|
this.currentResponseItemId = null;
|
|
17628
|
-
// Tool calls requested by the current (tool-bearing) response, the outputs
|
|
17629
|
-
// that have been submitted for them, and whether that response has finished
|
|
17630
|
-
// delivering its tool calls. Used to request a single response only once
|
|
17631
|
-
// every tool output for the turn has been submitted.
|
|
17632
19266
|
this.toolCallsInResponse = /* @__PURE__ */ new Set();
|
|
17633
19267
|
this.submittedToolOutputs = /* @__PURE__ */ new Set();
|
|
17634
19268
|
this.responseToolCallsClosed = false;
|
|
17635
|
-
var _a25, _b25, _c, _d, _e
|
|
17636
|
-
|
|
17637
|
-
this.
|
|
17638
|
-
this.
|
|
19269
|
+
var _a25, _b25, _c, _d, _e;
|
|
19270
|
+
const capabilities = options.model.capabilities;
|
|
19271
|
+
this.sessionLifecycle = (capabilities == null ? void 0 : capabilities.startup) === "session-start" || (capabilities == null ? void 0 : capabilities.finalization) === "session-close";
|
|
19272
|
+
this.continuous = (capabilities == null ? void 0 : capabilities.conversation) === "continuous";
|
|
17639
19273
|
this.maxEvents = (_a25 = options.maxEvents) != null ? _a25 : 500;
|
|
19274
|
+
if (!Number.isSafeInteger(this.maxEvents) || this.maxEvents < 1)
|
|
19275
|
+
throw new Error("maxEvents must be a positive integer");
|
|
19276
|
+
for (const timeout of [
|
|
19277
|
+
(_b25 = options.startupTimeoutMs) != null ? _b25 : 3e4,
|
|
19278
|
+
(_c = options.closeTimeoutMs) != null ? _c : 15e3,
|
|
19279
|
+
(_d = options.rtcDisconnectTimeoutMs) != null ? _d : 5e3
|
|
19280
|
+
]) {
|
|
19281
|
+
if (!Number.isFinite(timeout) || timeout <= 0 || timeout > 2147483647)
|
|
19282
|
+
throw new Error(
|
|
19283
|
+
"Realtime timeouts must be positive finite timer durations"
|
|
19284
|
+
);
|
|
19285
|
+
}
|
|
19286
|
+
const budget = (_e = options.maxPlaybackBufferSeconds) != null ? _e : 2;
|
|
19287
|
+
if (!Number.isFinite(budget) || budget <= 0)
|
|
19288
|
+
throw new Error("maxPlaybackBufferSeconds must be positive and finite");
|
|
17640
19289
|
this.reducer = new RealtimeEventReducer(this.maxEvents);
|
|
17641
19290
|
this.onToolCall = options.onToolCall;
|
|
17642
19291
|
this.onEvent = options.onEvent;
|
|
17643
19292
|
this.onError = options.onError;
|
|
17644
|
-
const sampleRate = (_b25 = options.sampleRate) != null ? _b25 : 24e3;
|
|
17645
|
-
const captureSampleRate = (_e = (_d = (_c = options.sessionConfig) == null ? void 0 : _c.inputAudioFormat) == null ? void 0 : _d.rate) != null ? _e : sampleRate;
|
|
17646
|
-
const playbackSampleRate = (_h = (_g = (_f = options.sessionConfig) == null ? void 0 : _f.outputAudioFormat) == null ? void 0 : _g.rate) != null ? _h : sampleRate;
|
|
17647
|
-
this.transport = new BrowserRealtimeTransport({
|
|
17648
|
-
model: this.model,
|
|
17649
|
-
onServerEvent: (event) => this.handleServerEvent(event),
|
|
17650
|
-
onError: (error) => {
|
|
17651
|
-
var _a26;
|
|
17652
|
-
this.applyState(this.reducer.setStatus(this.state, "error"));
|
|
17653
|
-
(_a26 = this.onError) == null ? void 0 : _a26.call(this, error);
|
|
17654
|
-
},
|
|
17655
|
-
onClose: () => {
|
|
17656
|
-
this.applyState(this.reducer.setStatus(this.state, "disconnected"));
|
|
17657
|
-
}
|
|
17658
|
-
});
|
|
17659
|
-
this.audio = new BrowserRealtimeAudio({
|
|
17660
|
-
captureSampleRate,
|
|
17661
|
-
playbackSampleRate,
|
|
17662
|
-
onAudio: (audio) => this.sendAudio(audio),
|
|
17663
|
-
onCapturingChange: (isCapturing) => {
|
|
17664
|
-
this.applyState(this.reducer.setCapturing(this.state, isCapturing));
|
|
17665
|
-
},
|
|
17666
|
-
onPlayingChange: (isPlaying) => {
|
|
17667
|
-
this.applyState(this.reducer.setPlaying(this.state, isPlaying));
|
|
17668
|
-
}
|
|
17669
|
-
});
|
|
17670
19293
|
}
|
|
17671
|
-
|
|
17672
|
-
|
|
17673
|
-
|
|
17674
|
-
|
|
19294
|
+
validateConnection() {
|
|
19295
|
+
var _a25, _b25, _c;
|
|
19296
|
+
const { model, api } = this.options;
|
|
19297
|
+
if ((!this.continuous || api.session != null) && this.options.maxPlaybackBufferSeconds != null)
|
|
19298
|
+
throw new Error(
|
|
19299
|
+
"maxPlaybackBufferSeconds is supported only for continuous PCM sessions"
|
|
19300
|
+
);
|
|
19301
|
+
const connection = api.session != null ? "webrtc" : api.token != null ? "client-secret-websocket" : "server-websocket";
|
|
19302
|
+
if (!((_b25 = (_a25 = model.capabilities) == null ? void 0 : _a25.connections) != null ? _b25 : ["client-secret-websocket"]).includes(connection) || ((_c = model.capabilities) == null ? void 0 : _c.transports) != null && !model.capabilities.transports.includes(
|
|
19303
|
+
api.session != null ? "webrtc" : "websocket"
|
|
19304
|
+
))
|
|
19305
|
+
throw new Error(`Realtime model does not support ${connection}`);
|
|
19306
|
+
if (api.session != null) {
|
|
19307
|
+
if (model.getWebRTCConfig == null)
|
|
19308
|
+
throw new Error("Realtime model does not support WebRTC configuration");
|
|
19309
|
+
return;
|
|
19310
|
+
}
|
|
19311
|
+
if (this.continuous && api.websocket == null)
|
|
19312
|
+
throw new Error(
|
|
19313
|
+
"Continuous PCM sessions require an application WebSocket relay"
|
|
19314
|
+
);
|
|
19315
|
+
if (api.token != null && model.getWebSocketConfig == null)
|
|
19316
|
+
throw new Error(
|
|
19317
|
+
"Realtime model does not support client-secret WebSocket configuration"
|
|
19318
|
+
);
|
|
19319
|
+
}
|
|
19320
|
+
async connect(connectOptions) {
|
|
19321
|
+
var _a25, _b25, _c, _d;
|
|
19322
|
+
if ((_a25 = this.attempt) == null ? void 0 : _a25.active)
|
|
19323
|
+
throw new Error("Realtime session is already active");
|
|
19324
|
+
const attempt = new RealtimeAttempt();
|
|
19325
|
+
this.attempt = attempt;
|
|
19326
|
+
const current = () => this.attempt === attempt && attempt.active;
|
|
17675
19327
|
try {
|
|
17676
|
-
|
|
17677
|
-
|
|
17678
|
-
|
|
17679
|
-
|
|
19328
|
+
this.applyState({ ...this.state, status: "connecting" });
|
|
19329
|
+
if (!current()) return;
|
|
19330
|
+
this.validateConnection();
|
|
19331
|
+
const { model, api, sessionConfig } = this.options;
|
|
19332
|
+
if ((connectOptions == null ? void 0 : connectOptions.capture) === false) this.stopAudioCapture();
|
|
19333
|
+
if (!current()) return;
|
|
19334
|
+
if ((connectOptions == null ? void 0 : connectOptions.stream) != null && connectOptions.stream !== this.suppliedStream) {
|
|
19335
|
+
if (this.captureRequested && !this.sessionLifecycle && !this.continuous && api.session == null)
|
|
19336
|
+
this.startAudioCapture(connectOptions.stream);
|
|
19337
|
+
else this.suppliedStream = connectOptions.stream;
|
|
19338
|
+
}
|
|
19339
|
+
if (!current()) return;
|
|
19340
|
+
this.reducer = new RealtimeEventReducer(this.maxEvents);
|
|
19341
|
+
this.currentResponseItemId = null;
|
|
19342
|
+
this.toolCallsInResponse.clear();
|
|
19343
|
+
this.submittedToolOutputs.clear();
|
|
19344
|
+
this.responseToolCallsClosed = false;
|
|
19345
|
+
if (this.sessionLifecycle)
|
|
19346
|
+
this.applyState({ ...this.state, session: createSessionState() });
|
|
19347
|
+
if (!current()) return;
|
|
19348
|
+
this.commands = new RealtimeCommandTracker((event) => {
|
|
19349
|
+
const writable = () => current() && !attempt.transportClosing && attempt.cause == null && (!attempt.closing || event.type === "session-close");
|
|
19350
|
+
if (!writable()) throw new Error("Realtime connection is closed");
|
|
19351
|
+
return this.sendTransport(event, writable);
|
|
17680
19352
|
});
|
|
17681
|
-
|
|
17682
|
-
|
|
17683
|
-
|
|
17684
|
-
|
|
17685
|
-
const
|
|
17686
|
-
|
|
17687
|
-
|
|
17688
|
-
|
|
19353
|
+
attempt.timer("startup", (_b25 = this.options.startupTimeoutMs) != null ? _b25 : 3e4, () => {
|
|
19354
|
+
if (current())
|
|
19355
|
+
this.fail(new Error("Realtime session startup timed out"));
|
|
19356
|
+
});
|
|
19357
|
+
const callbacks = {
|
|
19358
|
+
model,
|
|
19359
|
+
onEvent: async (event) => {
|
|
19360
|
+
var _a26, _b26, _c2;
|
|
19361
|
+
if (!current()) return;
|
|
19362
|
+
try {
|
|
19363
|
+
await this.handleServerEvent(event, attempt);
|
|
19364
|
+
} catch (error) {
|
|
19365
|
+
if (current())
|
|
19366
|
+
this.fail(
|
|
19367
|
+
error,
|
|
19368
|
+
(_c2 = (_b26 = (_a26 = this.rtc) != null ? _a26 : this.pcm) != null ? _b26 : this.transport) == null ? void 0 : _c2.finish()
|
|
19369
|
+
);
|
|
19370
|
+
}
|
|
19371
|
+
},
|
|
19372
|
+
onError: (error) => {
|
|
19373
|
+
if (current()) void this.reportError(error, attempt);
|
|
19374
|
+
},
|
|
19375
|
+
onFatalError: (error, drain) => {
|
|
19376
|
+
if (current()) this.fail(error, drain);
|
|
19377
|
+
},
|
|
19378
|
+
onClosing: () => {
|
|
19379
|
+
if (!current()) return;
|
|
19380
|
+
attempt.beginClose();
|
|
19381
|
+
attempt.transportClosing = true;
|
|
19382
|
+
attempt.clearTimer("startup");
|
|
19383
|
+
attempt.clearTimer("close");
|
|
19384
|
+
this.stopAudioCapture();
|
|
19385
|
+
if (!current()) return;
|
|
19386
|
+
this.applyState({
|
|
19387
|
+
...this.state,
|
|
19388
|
+
status: attempt.cause == null ? "closing" : "error"
|
|
19389
|
+
});
|
|
19390
|
+
},
|
|
19391
|
+
onClose: (error) => {
|
|
19392
|
+
var _a26, _b26;
|
|
19393
|
+
if (!current()) return;
|
|
19394
|
+
const finalizationConfirmed = ((_a26 = model.capabilities) == null ? void 0 : _a26.finalization) === "session-close" && ((_b26 = this.state.session) == null ? void 0 : _b26.finalization) === "confirmed";
|
|
19395
|
+
if (error != null && !finalizationConfirmed) this.fail(error);
|
|
19396
|
+
else if (!attempt.ready && !finalizationConfirmed)
|
|
19397
|
+
this.fail(
|
|
19398
|
+
new Error("Realtime connection closed before becoming ready")
|
|
19399
|
+
);
|
|
19400
|
+
else this.disconnect();
|
|
19401
|
+
},
|
|
19402
|
+
onCapturing: (isCapturing) => {
|
|
19403
|
+
if (current()) this.applyState({ ...this.state, isCapturing });
|
|
19404
|
+
},
|
|
19405
|
+
onPlaying: (isPlaying) => {
|
|
19406
|
+
if (current()) this.applyState({ ...this.state, isPlaying });
|
|
19407
|
+
}
|
|
17689
19408
|
};
|
|
17690
|
-
|
|
17691
|
-
|
|
17692
|
-
|
|
17693
|
-
|
|
17694
|
-
|
|
17695
|
-
|
|
17696
|
-
|
|
17697
|
-
|
|
19409
|
+
if (api.session != null) {
|
|
19410
|
+
this.rtc = new BrowserRealtimeWebRTC({
|
|
19411
|
+
...callbacks,
|
|
19412
|
+
disconnectTimeoutMs: this.options.rtcDisconnectTimeoutMs
|
|
19413
|
+
});
|
|
19414
|
+
await this.rtc.connect({
|
|
19415
|
+
api: api.session,
|
|
19416
|
+
sessionConfig,
|
|
19417
|
+
stream: connectOptions == null ? void 0 : connectOptions.stream,
|
|
19418
|
+
capture: connectOptions == null ? void 0 : connectOptions.capture,
|
|
19419
|
+
timeoutMs: (_c = this.options.startupTimeoutMs) != null ? _c : 3e4
|
|
19420
|
+
});
|
|
19421
|
+
} else if (api.websocket != null && ((_d = model.capabilities) == null ? void 0 : _d.conversation) === "continuous") {
|
|
19422
|
+
this.pcm = new BrowserRealtimeLiveWebSocket({
|
|
19423
|
+
...callbacks,
|
|
19424
|
+
sessionConfig,
|
|
19425
|
+
sampleRate: this.options.sampleRate,
|
|
19426
|
+
maxPlaybackBufferSeconds: this.options.maxPlaybackBufferSeconds
|
|
19427
|
+
});
|
|
19428
|
+
this.pcm.connect({
|
|
19429
|
+
url: api.websocket,
|
|
19430
|
+
protocols: api.protocols,
|
|
19431
|
+
stream: connectOptions == null ? void 0 : connectOptions.stream,
|
|
19432
|
+
capture: connectOptions == null ? void 0 : connectOptions.capture
|
|
19433
|
+
});
|
|
19434
|
+
} else {
|
|
19435
|
+
this.ensureAudio();
|
|
19436
|
+
let config = sessionConfig != null ? sessionConfig : {};
|
|
19437
|
+
let token;
|
|
19438
|
+
let url = api.websocket;
|
|
19439
|
+
if (api.token != null) {
|
|
19440
|
+
const response = await fetch(api.token, {
|
|
19441
|
+
method: "POST",
|
|
19442
|
+
headers: { "Content-Type": "application/json" },
|
|
19443
|
+
body: JSON.stringify({ sessionConfig }),
|
|
19444
|
+
signal: attempt.abort.signal
|
|
19445
|
+
});
|
|
19446
|
+
if (!current()) return;
|
|
19447
|
+
if (!response.ok)
|
|
19448
|
+
throw new Error(
|
|
19449
|
+
`Failed to fetch realtime setup: ${response.status}`
|
|
19450
|
+
);
|
|
19451
|
+
const payload = await response.json().catch(() => {
|
|
19452
|
+
throw new Error("Invalid realtime setup response");
|
|
17698
19453
|
});
|
|
19454
|
+
if (!current() || attempt.closing) return;
|
|
19455
|
+
const setup = validateRealtimeSetup(payload);
|
|
19456
|
+
token = setup.token;
|
|
19457
|
+
url = setup.url;
|
|
19458
|
+
config = {
|
|
19459
|
+
...sessionConfig,
|
|
19460
|
+
...setup.tools == null ? {} : { tools: setup.tools }
|
|
19461
|
+
};
|
|
17699
19462
|
}
|
|
17700
|
-
|
|
19463
|
+
if (url == null) throw new Error("Realtime WebSocket URL is missing");
|
|
19464
|
+
if (api.token != null && token == null)
|
|
19465
|
+
throw new Error("Realtime client-secret connection requires a token");
|
|
19466
|
+
this.ensureAudio().ensurePlaybackContext();
|
|
19467
|
+
if (!current()) return;
|
|
19468
|
+
this.transport = new BrowserRealtimeTransport({
|
|
19469
|
+
...callbacks,
|
|
19470
|
+
onServerEvent: callbacks.onEvent
|
|
19471
|
+
});
|
|
19472
|
+
this.transport.connect({
|
|
19473
|
+
...token != null ? { mode: "client-secret", token } : { mode: "relay", protocols: api.protocols },
|
|
19474
|
+
url,
|
|
19475
|
+
onOpen: () => {
|
|
19476
|
+
var _a26, _b26;
|
|
19477
|
+
const writable = () => current() && !attempt.closing && attempt.cause == null;
|
|
19478
|
+
if (!writable()) return;
|
|
19479
|
+
return this.sendTransport(
|
|
19480
|
+
{
|
|
19481
|
+
type: (_b26 = (_a26 = model.capabilities) == null ? void 0 : _a26.startup) != null ? _b26 : "session-update",
|
|
19482
|
+
config
|
|
19483
|
+
},
|
|
19484
|
+
writable
|
|
19485
|
+
);
|
|
19486
|
+
}
|
|
19487
|
+
});
|
|
19488
|
+
}
|
|
17701
19489
|
} catch (error) {
|
|
17702
|
-
|
|
17703
|
-
|
|
17704
|
-
|
|
17705
|
-
|
|
17706
|
-
|
|
19490
|
+
if (current()) this.fail(error);
|
|
19491
|
+
}
|
|
19492
|
+
}
|
|
19493
|
+
fail(error, drain) {
|
|
19494
|
+
const attempt = this.attempt;
|
|
19495
|
+
if (attempt == null || !attempt.active || attempt.cause != null) return;
|
|
19496
|
+
attempt.cause = error instanceof Error ? error : new Error(String(error));
|
|
19497
|
+
if (drain != null) attempt.beginClose();
|
|
19498
|
+
this.applyState({ ...this.state, status: "error" });
|
|
19499
|
+
if (this.attempt !== attempt || !attempt.active) return;
|
|
19500
|
+
this.stopAudioCapture();
|
|
19501
|
+
if (this.attempt !== attempt || !attempt.active) return;
|
|
19502
|
+
if (drain == null) this.disconnect();
|
|
19503
|
+
else void this.drainAttempt(attempt, drain);
|
|
19504
|
+
void this.reportError(attempt.cause, attempt);
|
|
19505
|
+
}
|
|
19506
|
+
async drainAttempt(attempt, drain) {
|
|
19507
|
+
if (this.attempt === attempt && attempt.active)
|
|
19508
|
+
attempt.timer("drain", 1e3, () => this.finishAttempt(attempt));
|
|
19509
|
+
try {
|
|
19510
|
+
await drain;
|
|
19511
|
+
} catch (e) {
|
|
17707
19512
|
}
|
|
19513
|
+
this.finishAttempt(attempt);
|
|
19514
|
+
}
|
|
19515
|
+
finishAttempt(attempt) {
|
|
19516
|
+
if (this.attempt !== attempt || !attempt.active) return;
|
|
19517
|
+
try {
|
|
19518
|
+
this.disconnect();
|
|
19519
|
+
} catch (error) {
|
|
19520
|
+
void this.reportError(error, attempt);
|
|
19521
|
+
}
|
|
19522
|
+
}
|
|
19523
|
+
closeFailed(attempt, error) {
|
|
19524
|
+
var _a25, _b25;
|
|
19525
|
+
if (this.attempt !== attempt || !attempt.active || attempt.transportClosing)
|
|
19526
|
+
return;
|
|
19527
|
+
attempt.clearTimer("close");
|
|
19528
|
+
const transport = (_b25 = (_a25 = this.rtc) != null ? _a25 : this.pcm) != null ? _b25 : this.transport;
|
|
19529
|
+
void this.drainAttempt(attempt, transport == null ? void 0 : transport.finish());
|
|
19530
|
+
void this.reportError(error, attempt);
|
|
17708
19531
|
}
|
|
17709
19532
|
disconnect() {
|
|
17710
|
-
this.
|
|
17711
|
-
this.
|
|
19533
|
+
const attempt = this.attempt;
|
|
19534
|
+
this.captureGeneration++;
|
|
19535
|
+
this.captureRequested = false;
|
|
19536
|
+
this.suppliedStream = void 0;
|
|
19537
|
+
const transport = this.transport;
|
|
19538
|
+
const audio = this.audio;
|
|
19539
|
+
const pcm = this.pcm;
|
|
19540
|
+
const rtc = this.rtc;
|
|
19541
|
+
this.transport = void 0;
|
|
19542
|
+
this.audio = void 0;
|
|
19543
|
+
this.pcm = void 0;
|
|
19544
|
+
this.rtc = void 0;
|
|
19545
|
+
this.commands = void 0;
|
|
19546
|
+
attempt == null ? void 0 : attempt.retire();
|
|
19547
|
+
transport == null ? void 0 : transport.dispose();
|
|
19548
|
+
audio == null ? void 0 : audio.dispose();
|
|
19549
|
+
pcm == null ? void 0 : pcm.dispose();
|
|
19550
|
+
rtc == null ? void 0 : rtc.dispose();
|
|
19551
|
+
if (this.attempt !== attempt) return;
|
|
19552
|
+
const session = this.state.session;
|
|
19553
|
+
this.applyState({
|
|
19554
|
+
...this.state,
|
|
19555
|
+
status: (attempt == null ? void 0 : attempt.cause) != null ? "error" : "disconnected",
|
|
19556
|
+
isCapturing: false,
|
|
19557
|
+
isPlaying: false,
|
|
19558
|
+
...session != null ? {
|
|
19559
|
+
session: session.finalization === "confirmed" ? session : { ...session, finalization: "unconfirmed" }
|
|
19560
|
+
} : {}
|
|
19561
|
+
});
|
|
19562
|
+
}
|
|
19563
|
+
/** Wait for final usage when the model supports a session-close acknowledgement. */
|
|
19564
|
+
close(options) {
|
|
19565
|
+
var _a25, _b25, _c, _d;
|
|
19566
|
+
const attempt = this.attempt;
|
|
19567
|
+
if ((attempt == null ? void 0 : attempt.closePromise) != null) return attempt.closePromise;
|
|
19568
|
+
if (this.state.status !== "connected" || ((_a25 = this.options.model.capabilities) == null ? void 0 : _a25.finalization) !== "session-close" || attempt == null) {
|
|
19569
|
+
this.disconnect();
|
|
19570
|
+
return Promise.resolve();
|
|
19571
|
+
}
|
|
19572
|
+
if ((options == null ? void 0 : options.eventId) != null) (_b25 = this.commands) == null ? void 0 : _b25.validateId(options.eventId);
|
|
19573
|
+
const promise = attempt.beginClose();
|
|
19574
|
+
this.applyState({ ...this.state, status: "closing" });
|
|
19575
|
+
if (this.attempt !== attempt || !attempt.active || attempt.transportClosing)
|
|
19576
|
+
return promise;
|
|
19577
|
+
this.stopAudioCapture();
|
|
19578
|
+
if (this.attempt !== attempt || !attempt.active || attempt.transportClosing)
|
|
19579
|
+
return promise;
|
|
19580
|
+
attempt.timer(
|
|
19581
|
+
"close",
|
|
19582
|
+
(_c = this.options.closeTimeoutMs) != null ? _c : 15e3,
|
|
19583
|
+
() => this.finishAttempt(attempt)
|
|
19584
|
+
);
|
|
19585
|
+
const failed = (error) => this.closeFailed(attempt, error);
|
|
19586
|
+
try {
|
|
19587
|
+
void ((_d = this.commands) == null ? void 0 : _d.send({ type: "session-close", eventId: options == null ? void 0 : options.eventId }).catch(failed));
|
|
19588
|
+
} catch (error) {
|
|
19589
|
+
failed(error);
|
|
19590
|
+
}
|
|
19591
|
+
return promise;
|
|
19592
|
+
}
|
|
19593
|
+
sendTransport(event, guard, automaticAudio = false) {
|
|
19594
|
+
var _a25, _b25;
|
|
19595
|
+
const transport = (_b25 = (_a25 = this.rtc) != null ? _a25 : this.pcm) != null ? _b25 : this.transport;
|
|
19596
|
+
if (transport == null) throw new Error("Realtime connection is not open");
|
|
19597
|
+
if (transport === this.transport)
|
|
19598
|
+
return this.transport.sendEvent(event, guard, automaticAudio);
|
|
19599
|
+
return transport.sendEvent(event, guard);
|
|
17712
19600
|
}
|
|
17713
|
-
// ── Sending events ─────────────────────────────────────────────────
|
|
17714
19601
|
sendEvent(event) {
|
|
17715
|
-
|
|
19602
|
+
var _a25, _b25, _c, _d;
|
|
19603
|
+
if (this.state.status === "error" || this.state.status === "closing" || ((_a25 = this.attempt) == null ? void 0 : _a25.closing) || !((_b25 = this.attempt) == null ? void 0 : _b25.active))
|
|
19604
|
+
throw new Error("Realtime session is not accepting submissions");
|
|
19605
|
+
if (this.sessionLifecycle && this.state.status !== "connected")
|
|
19606
|
+
throw new Error("Realtime session is not accepting submissions");
|
|
19607
|
+
if (this.rtc != null && event.type === "input-audio-append" || (this.continuous || this.rtc != null) && (event.type === "input-audio-commit" || event.type === "input-audio-clear"))
|
|
19608
|
+
throw new UnsupportedFunctionalityError6({
|
|
19609
|
+
functionality: "JSON audio commands unsupported for this session transport"
|
|
19610
|
+
});
|
|
19611
|
+
if (event.type === "session-close")
|
|
19612
|
+
return this.close({ eventId: event.eventId });
|
|
19613
|
+
if (event.type === "session-start" && this.sessionLifecycle)
|
|
19614
|
+
throw new Error("Realtime session has already started");
|
|
19615
|
+
if (!this.sessionLifecycle && this.state.session == null) {
|
|
19616
|
+
const attempt = this.attempt;
|
|
19617
|
+
return this.sendTransport(
|
|
19618
|
+
event,
|
|
19619
|
+
() => this.attempt === attempt && attempt.active && !attempt.closing && attempt.cause == null
|
|
19620
|
+
);
|
|
19621
|
+
}
|
|
19622
|
+
return (_d = (_c = this.commands) == null ? void 0 : _c.send(event)) != null ? _d : this.sendTransport(event);
|
|
17716
19623
|
}
|
|
17717
19624
|
sendTextMessage(text2) {
|
|
19625
|
+
if (this.continuous)
|
|
19626
|
+
throw new UnsupportedFunctionalityError6({
|
|
19627
|
+
functionality: "sendTextMessage for continuous sessions; client-delegation text is application-owned, use context-append for context"
|
|
19628
|
+
});
|
|
17718
19629
|
this.sendEvent({
|
|
17719
19630
|
type: "conversation-item-create",
|
|
17720
19631
|
item: { type: "text-message", role: "user", text: text2 }
|
|
@@ -17722,8 +19633,12 @@ var AbstractRealtimeSession = class {
|
|
|
17722
19633
|
this.sendEvent({ type: "response-create" });
|
|
17723
19634
|
this.applyState(this.reducer.addUserTextMessage(this.state, text2));
|
|
17724
19635
|
}
|
|
17725
|
-
sendAudio(
|
|
17726
|
-
|
|
19636
|
+
sendAudio(audio) {
|
|
19637
|
+
const attempt = this.attempt;
|
|
19638
|
+
void this.sendEvent({ type: "input-audio-append", audio }).catch((error) => {
|
|
19639
|
+
if ((attempt == null ? void 0 : attempt.active) && this.attempt === attempt)
|
|
19640
|
+
void this.reportError(error, attempt);
|
|
19641
|
+
});
|
|
17727
19642
|
}
|
|
17728
19643
|
commitAudio() {
|
|
17729
19644
|
this.sendEvent({ type: "input-audio-commit" });
|
|
@@ -17740,161 +19655,301 @@ var AbstractRealtimeSession = class {
|
|
|
17740
19655
|
cancelResponse() {
|
|
17741
19656
|
this.sendEvent({ type: "response-cancel" });
|
|
17742
19657
|
}
|
|
17743
|
-
|
|
19658
|
+
sendAutomaticAudio(audio) {
|
|
19659
|
+
var _a25;
|
|
19660
|
+
if (this.state.status !== "connected" || !((_a25 = this.attempt) == null ? void 0 : _a25.active) || this.attempt.closing)
|
|
19661
|
+
return;
|
|
19662
|
+
const attempt = this.attempt;
|
|
19663
|
+
const failed = (error) => {
|
|
19664
|
+
if ((attempt == null ? void 0 : attempt.active) && this.attempt === attempt && !attempt.closing)
|
|
19665
|
+
this.fail(error);
|
|
19666
|
+
};
|
|
19667
|
+
try {
|
|
19668
|
+
void this.sendTransport(
|
|
19669
|
+
{ type: "input-audio-append", audio },
|
|
19670
|
+
() => this.attempt === attempt && attempt.active && !attempt.closing,
|
|
19671
|
+
true
|
|
19672
|
+
).catch(failed);
|
|
19673
|
+
} catch (error) {
|
|
19674
|
+
failed(error);
|
|
19675
|
+
}
|
|
19676
|
+
}
|
|
17744
19677
|
addToolOutput(callId, result) {
|
|
19678
|
+
if (this.continuous)
|
|
19679
|
+
throw new UnsupportedFunctionalityError6({
|
|
19680
|
+
functionality: "addToolOutput for continuous sessions; client delegation is application-owned"
|
|
19681
|
+
});
|
|
19682
|
+
const attempt = this.attempt;
|
|
19683
|
+
if (!(attempt == null ? void 0 : attempt.active) || attempt.closing || attempt.cause != null)
|
|
19684
|
+
throw new Error("Realtime session is not accepting submissions");
|
|
17745
19685
|
const { state, output } = this.reducer.addToolOutput(
|
|
17746
19686
|
this.state,
|
|
17747
19687
|
callId,
|
|
17748
19688
|
result
|
|
17749
19689
|
);
|
|
17750
19690
|
this.applyState(state);
|
|
19691
|
+
if (this.attempt !== attempt || !(attempt == null ? void 0 : attempt.active)) return;
|
|
17751
19692
|
this.sendEvent({
|
|
17752
19693
|
type: "conversation-item-create",
|
|
17753
|
-
item: {
|
|
17754
|
-
type: "function-call-output",
|
|
17755
|
-
callId: output.callId,
|
|
17756
|
-
name: output.name,
|
|
17757
|
-
output: output.output
|
|
17758
|
-
}
|
|
19694
|
+
item: { type: "function-call-output", ...output }
|
|
17759
19695
|
});
|
|
17760
19696
|
this.submittedToolOutputs.add(callId);
|
|
17761
19697
|
this.maybeRequestToolResponse();
|
|
17762
19698
|
}
|
|
17763
|
-
/**
|
|
17764
|
-
* Requests a single response once the tool-bearing response has finished
|
|
17765
|
-
* delivering its tool calls and every one of them has an output. Requesting a
|
|
17766
|
-
* response after each individual output can cause the model to continue
|
|
17767
|
-
* without the full tool context on multi-tool turns.
|
|
17768
|
-
*/
|
|
17769
19699
|
maybeRequestToolResponse() {
|
|
17770
|
-
|
|
17771
|
-
if (this.toolCallsInResponse.size === 0
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
19700
|
+
var _a25;
|
|
19701
|
+
if (this.state.status !== "connected" || ((_a25 = this.attempt) == null ? void 0 : _a25.closing) || !this.responseToolCallsClosed || this.toolCallsInResponse.size === 0 || [...this.toolCallsInResponse].some(
|
|
19702
|
+
(id) => !this.submittedToolOutputs.has(id)
|
|
19703
|
+
))
|
|
19704
|
+
return;
|
|
17775
19705
|
this.sendEvent({ type: "response-create" });
|
|
17776
19706
|
this.toolCallsInResponse.clear();
|
|
17777
19707
|
this.submittedToolOutputs.clear();
|
|
17778
19708
|
this.responseToolCallsClosed = false;
|
|
17779
19709
|
}
|
|
17780
|
-
// ── Audio capture ──────────────────────────────────────────────────
|
|
17781
19710
|
startAudioCapture(stream) {
|
|
17782
|
-
|
|
19711
|
+
var _a25;
|
|
19712
|
+
const legacy = !this.sessionLifecycle && !this.continuous && this.options.api.session == null;
|
|
19713
|
+
if (!legacy && this.state.status !== "connected")
|
|
19714
|
+
throw new Error("Realtime session is not accepting capture");
|
|
19715
|
+
if (((_a25 = this.attempt) == null ? void 0 : _a25.active) && (this.attempt.closing || this.attempt.cause != null))
|
|
19716
|
+
throw new Error("Realtime session is not accepting capture");
|
|
19717
|
+
this.suppliedStream = stream;
|
|
19718
|
+
if (legacy) {
|
|
19719
|
+
this.captureGeneration++;
|
|
19720
|
+
this.captureRequested = true;
|
|
19721
|
+
this.ensureAudio().startCapture(stream);
|
|
19722
|
+
return;
|
|
19723
|
+
}
|
|
19724
|
+
const attempt = this.attempt;
|
|
19725
|
+
void this.resumeAudioCapture().catch((error) => {
|
|
19726
|
+
if (attempt == null ? void 0 : attempt.active) void this.reportError(error, attempt);
|
|
19727
|
+
});
|
|
19728
|
+
}
|
|
19729
|
+
async resumeAudioCapture() {
|
|
19730
|
+
const accepting = () => {
|
|
19731
|
+
var _a25, _b25;
|
|
19732
|
+
return !((_a25 = this.attempt) == null ? void 0 : _a25.closing) && ((_b25 = this.attempt) == null ? void 0 : _b25.cause) == null && (this.state.status === "connected" || !this.sessionLifecycle && this.state.status === "connecting");
|
|
19733
|
+
};
|
|
19734
|
+
if (!accepting())
|
|
19735
|
+
throw new Error("Realtime session is not accepting capture");
|
|
19736
|
+
this.captureRequested = true;
|
|
19737
|
+
if (this.rtc != null) return this.rtc.startCapture(this.suppliedStream);
|
|
19738
|
+
if (this.pcm != null) return this.pcm.resumeCapture(this.suppliedStream);
|
|
19739
|
+
const audio = this.audio;
|
|
19740
|
+
if (audio == null)
|
|
19741
|
+
throw new Error("Realtime capture transport is not ready");
|
|
19742
|
+
const captureGeneration = ++this.captureGeneration;
|
|
19743
|
+
const attempt = this.attempt;
|
|
19744
|
+
const supplied = this.suppliedStream;
|
|
19745
|
+
const stream = supplied != null ? supplied : await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
19746
|
+
if (!(attempt == null ? void 0 : attempt.active) || this.attempt !== attempt || this.audio !== audio || !accepting() || captureGeneration !== this.captureGeneration) {
|
|
19747
|
+
if (supplied == null) stream.getTracks().forEach((track) => track.stop());
|
|
19748
|
+
return;
|
|
19749
|
+
}
|
|
19750
|
+
audio.startCapture(stream, {
|
|
19751
|
+
ownsStream: supplied == null || !this.sessionLifecycle || this.options.api.token != null
|
|
19752
|
+
});
|
|
17783
19753
|
}
|
|
17784
19754
|
stopAudioCapture() {
|
|
17785
|
-
this.
|
|
19755
|
+
this.captureGeneration++;
|
|
19756
|
+
this.captureRequested = false;
|
|
19757
|
+
if (this.audio != null && (!this.sessionLifecycle || this.options.api.token != null))
|
|
19758
|
+
this.suppliedStream = void 0;
|
|
19759
|
+
const pcm = this.pcm;
|
|
19760
|
+
const audio = this.audio;
|
|
19761
|
+
const rtc = this.rtc;
|
|
19762
|
+
const attempt = this.attempt;
|
|
19763
|
+
if (rtc != null)
|
|
19764
|
+
void rtc.stopCapture().catch((error) => {
|
|
19765
|
+
if ((attempt == null ? void 0 : attempt.active) && this.attempt === attempt)
|
|
19766
|
+
void this.reportError(error, attempt);
|
|
19767
|
+
});
|
|
19768
|
+
pcm == null ? void 0 : pcm.stopCapture();
|
|
19769
|
+
audio == null ? void 0 : audio.stopCapture();
|
|
17786
19770
|
}
|
|
17787
|
-
// ── Playback ───────────────────────────────────────────────────────
|
|
17788
19771
|
stopPlayback() {
|
|
17789
|
-
|
|
19772
|
+
var _a25, _b25, _c;
|
|
19773
|
+
(_c = (_b25 = (_a25 = this.rtc) != null ? _a25 : this.pcm) != null ? _b25 : this.audio) == null ? void 0 : _c.stopPlayback();
|
|
19774
|
+
}
|
|
19775
|
+
async resumePlayback() {
|
|
19776
|
+
var _a25, _b25, _c;
|
|
19777
|
+
await ((_c = (_b25 = (_a25 = this.rtc) != null ? _a25 : this.pcm) != null ? _b25 : this.audio) == null ? void 0 : _c.resumePlayback());
|
|
17790
19778
|
}
|
|
17791
|
-
// ── Cleanup ────────────────────────────────────────────────────────
|
|
17792
19779
|
dispose() {
|
|
17793
|
-
this.
|
|
17794
|
-
|
|
17795
|
-
|
|
17796
|
-
|
|
17797
|
-
|
|
17798
|
-
|
|
17799
|
-
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
)
|
|
17803
|
-
|
|
19780
|
+
this.disconnect();
|
|
19781
|
+
}
|
|
19782
|
+
ensureAudio() {
|
|
19783
|
+
var _a25, _b25, _c, _d, _e, _f;
|
|
19784
|
+
if (this.audio != null) return this.audio;
|
|
19785
|
+
const { sessionConfig, sampleRate } = this.options;
|
|
19786
|
+
const audio = new BrowserRealtimeAudio({
|
|
19787
|
+
captureSampleRate: (_c = (_b25 = (_a25 = sessionConfig == null ? void 0 : sessionConfig.inputAudioFormat) == null ? void 0 : _a25.rate) != null ? _b25 : sampleRate) != null ? _c : 24e3,
|
|
19788
|
+
playbackSampleRate: (_f = (_e = (_d = sessionConfig == null ? void 0 : sessionConfig.outputAudioFormat) == null ? void 0 : _d.rate) != null ? _e : sampleRate) != null ? _f : 24e3,
|
|
19789
|
+
onAudio: (value) => {
|
|
19790
|
+
if (this.audio === audio) this.sendAutomaticAudio(value);
|
|
19791
|
+
},
|
|
19792
|
+
onError: (error) => {
|
|
19793
|
+
if (this.audio !== audio) return;
|
|
19794
|
+
void this.reportError(error, this.attempt);
|
|
19795
|
+
},
|
|
19796
|
+
onCapturingChange: (isCapturing) => {
|
|
19797
|
+
if (this.audio === audio)
|
|
19798
|
+
this.applyState({ ...this.state, isCapturing });
|
|
19799
|
+
},
|
|
19800
|
+
onPlayingChange: (isPlaying) => {
|
|
19801
|
+
if (this.audio === audio) this.applyState({ ...this.state, isPlaying });
|
|
19802
|
+
}
|
|
19803
|
+
});
|
|
19804
|
+
this.audio = audio;
|
|
19805
|
+
return audio;
|
|
17804
19806
|
}
|
|
17805
|
-
// ── Private helpers ────────────────────────────────────────────────
|
|
17806
19807
|
applyState(nextState) {
|
|
17807
|
-
const
|
|
19808
|
+
const publication = ++this.publication;
|
|
19809
|
+
const previous = this.state;
|
|
17808
19810
|
this.state = nextState;
|
|
17809
|
-
|
|
17810
|
-
this.
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
17818
|
-
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
if (
|
|
17822
|
-
this.setState("isPlaying", nextState.isPlaying);
|
|
17823
|
-
}
|
|
17824
|
-
}
|
|
17825
|
-
async executeToolCall({
|
|
17826
|
-
name: name25,
|
|
17827
|
-
args,
|
|
17828
|
-
callId
|
|
17829
|
-
}) {
|
|
17830
|
-
var _a25, _b25;
|
|
17831
|
-
if (this.onToolCall == null) {
|
|
17832
|
-
(_a25 = this.onError) == null ? void 0 : _a25.call(this, new Error(`No handler provided for tool "${name25}"`));
|
|
19811
|
+
const update = (key) => {
|
|
19812
|
+
if (publication === this.publication && previous[key] !== nextState[key])
|
|
19813
|
+
this.setState(key, nextState[key]);
|
|
19814
|
+
};
|
|
19815
|
+
update("status");
|
|
19816
|
+
update("messages");
|
|
19817
|
+
update("events");
|
|
19818
|
+
update("isCapturing");
|
|
19819
|
+
update("isPlaying");
|
|
19820
|
+
update("session");
|
|
19821
|
+
}
|
|
19822
|
+
async executeTool(callId, name25, args, attempt) {
|
|
19823
|
+
if (this.continuous || this.attempt !== attempt || !attempt.active || attempt.closing || attempt.cause != null)
|
|
17833
19824
|
return;
|
|
17834
|
-
}
|
|
17835
19825
|
try {
|
|
19826
|
+
if (this.onToolCall == null) {
|
|
19827
|
+
void this.reportError(
|
|
19828
|
+
new Error(`No handler provided for tool "${name25}"`),
|
|
19829
|
+
attempt
|
|
19830
|
+
);
|
|
19831
|
+
return;
|
|
19832
|
+
}
|
|
17836
19833
|
const result = await this.onToolCall({
|
|
17837
19834
|
toolCall: { toolCallId: callId, toolName: name25, args }
|
|
17838
19835
|
});
|
|
17839
|
-
if (result !== void 0)
|
|
19836
|
+
if (result !== void 0 && this.attempt === attempt && (attempt == null ? void 0 : attempt.active) && this.state.status === "connected")
|
|
17840
19837
|
this.addToolOutput(callId, result);
|
|
17841
|
-
}
|
|
17842
19838
|
} catch (error) {
|
|
17843
|
-
(
|
|
17844
|
-
this,
|
|
17845
|
-
error instanceof Error ? error : new Error(`Client tool execution failed: ${String(error)}`)
|
|
17846
|
-
);
|
|
19839
|
+
if (attempt.active) void this.reportError(error, attempt);
|
|
17847
19840
|
}
|
|
17848
19841
|
}
|
|
17849
|
-
async handleServerEvent(event) {
|
|
17850
|
-
var _a25;
|
|
19842
|
+
async handleServerEvent(event, attempt) {
|
|
19843
|
+
var _a25, _b25, _c, _d, _e, _f;
|
|
19844
|
+
const current = () => this.attempt === attempt && attempt.active;
|
|
19845
|
+
if (!current()) return;
|
|
19846
|
+
if (event.type === "session-started" && event.delegationMode === "provider")
|
|
19847
|
+
throw new UnsupportedFunctionalityError6({
|
|
19848
|
+
functionality: "Provider delegation mode; this realtime runtime supports client delegation only"
|
|
19849
|
+
});
|
|
19850
|
+
if (this.continuous && event.type === "audio-delta")
|
|
19851
|
+
throw new UnsupportedFunctionalityError6({
|
|
19852
|
+
functionality: "Turn-based audio-delta in a continuous PCM session; use audio-chunk"
|
|
19853
|
+
});
|
|
19854
|
+
const command = (_a25 = this.commands) == null ? void 0 : _a25.receive(event);
|
|
17851
19855
|
const result = await this.reducer.reduceServerEvent(this.state, event);
|
|
17852
|
-
|
|
17853
|
-
(
|
|
19856
|
+
if (!current()) return;
|
|
19857
|
+
const session = (_b25 = this.state.session) != null ? _b25 : event.type === "session-started" ? createSessionState() : void 0;
|
|
19858
|
+
this.applyState({
|
|
19859
|
+
...result.state,
|
|
19860
|
+
status: this.state.status,
|
|
19861
|
+
...session == null ? {} : {
|
|
19862
|
+
session: reduceSessionState(
|
|
19863
|
+
session,
|
|
19864
|
+
event,
|
|
19865
|
+
this.maxEvents,
|
|
19866
|
+
command == null ? void 0 : command.muted
|
|
19867
|
+
)
|
|
19868
|
+
}
|
|
19869
|
+
});
|
|
19870
|
+
if (!current()) return;
|
|
17854
19871
|
for (const effect of result.effects) {
|
|
17855
|
-
this.handleReducerEffect(effect);
|
|
19872
|
+
this.handleReducerEffect(effect, attempt);
|
|
19873
|
+
if (!current()) return;
|
|
17856
19874
|
}
|
|
19875
|
+
if (event.type === "audio-chunk")
|
|
19876
|
+
(_d = (_c = this.pcm) != null ? _c : this.audio) == null ? void 0 : _d.playAudio(event.delta);
|
|
19877
|
+
if (!current()) return;
|
|
17857
19878
|
if (event.type === "response-done" && this.toolCallsInResponse.size > 0) {
|
|
17858
19879
|
this.responseToolCallsClosed = true;
|
|
17859
19880
|
this.maybeRequestToolResponse();
|
|
17860
19881
|
}
|
|
19882
|
+
if (!current()) return;
|
|
19883
|
+
if (event.type === "session-closed" && session != null) {
|
|
19884
|
+
this.disconnect();
|
|
19885
|
+
this.notifyEvent(event, attempt, true);
|
|
19886
|
+
return;
|
|
19887
|
+
}
|
|
19888
|
+
if ((event.type === "session-started" || event.type === "session-created" || event.type === "session-updated") && attempt.active && !attempt.closing && attempt.cause == null) {
|
|
19889
|
+
const ready = ((_e = this.options.model.capabilities) == null ? void 0 : _e.startup) === "session-start" ? event.type === "session-started" : event.type !== "session-started";
|
|
19890
|
+
if (ready) {
|
|
19891
|
+
attempt.ready = true;
|
|
19892
|
+
attempt.clearTimer("startup");
|
|
19893
|
+
this.applyState({ ...this.state, status: "connected" });
|
|
19894
|
+
if (!current() || attempt.closing) return;
|
|
19895
|
+
(_f = this.pcm) == null ? void 0 : _f.startCapture();
|
|
19896
|
+
}
|
|
19897
|
+
}
|
|
19898
|
+
if (current()) this.notifyEvent(event, attempt);
|
|
17861
19899
|
}
|
|
17862
|
-
handleReducerEffect(effect) {
|
|
17863
|
-
var _a25;
|
|
19900
|
+
handleReducerEffect(effect, attempt) {
|
|
19901
|
+
var _a25, _b25, _c, _d;
|
|
17864
19902
|
switch (effect.type) {
|
|
17865
|
-
case "play-audio":
|
|
19903
|
+
case "play-audio":
|
|
17866
19904
|
this.currentResponseItemId = effect.itemId;
|
|
17867
|
-
this.audio.playAudio(effect.delta);
|
|
19905
|
+
(_a25 = this.audio) == null ? void 0 : _a25.playAudio(effect.delta);
|
|
17868
19906
|
break;
|
|
17869
|
-
|
|
17870
|
-
|
|
17871
|
-
|
|
17872
|
-
const
|
|
17873
|
-
this.audio.stopPlayback();
|
|
17874
|
-
if (this.
|
|
19907
|
+
case "speech-started":
|
|
19908
|
+
if (!this.continuous && this.state.isPlaying) {
|
|
19909
|
+
const playedMs = (_c = (_b25 = this.audio) == null ? void 0 : _b25.getPlaybackOffsetMs()) != null ? _c : 0;
|
|
19910
|
+
const itemId = this.currentResponseItemId;
|
|
19911
|
+
(_d = this.audio) == null ? void 0 : _d.stopPlayback();
|
|
19912
|
+
if (this.attempt !== attempt || !attempt.active) return;
|
|
19913
|
+
if (itemId != null && !attempt.closing && attempt.cause == null)
|
|
17875
19914
|
this.sendEvent({
|
|
17876
19915
|
type: "conversation-item-truncate",
|
|
17877
|
-
itemId
|
|
19916
|
+
itemId,
|
|
17878
19917
|
contentIndex: 0,
|
|
17879
19918
|
audioEndMs: Math.round(playedMs)
|
|
17880
19919
|
});
|
|
17881
|
-
}
|
|
17882
19920
|
}
|
|
17883
19921
|
break;
|
|
17884
|
-
|
|
17885
|
-
|
|
19922
|
+
case "tool-call":
|
|
19923
|
+
if (this.continuous) break;
|
|
17886
19924
|
this.toolCallsInResponse.add(effect.callId);
|
|
17887
|
-
void this.
|
|
17888
|
-
name: effect.name,
|
|
17889
|
-
args: effect.args,
|
|
17890
|
-
callId: effect.callId
|
|
17891
|
-
});
|
|
19925
|
+
void this.executeTool(effect.callId, effect.name, effect.args, attempt);
|
|
17892
19926
|
break;
|
|
17893
|
-
|
|
17894
|
-
|
|
17895
|
-
(_a25 = this.onError) == null ? void 0 : _a25.call(this, effect.error);
|
|
19927
|
+
case "error":
|
|
19928
|
+
void this.reportError(effect.error, attempt);
|
|
17896
19929
|
break;
|
|
17897
|
-
|
|
19930
|
+
}
|
|
19931
|
+
}
|
|
19932
|
+
async reportError(error, attempt) {
|
|
19933
|
+
var _a25;
|
|
19934
|
+
if (this.attempt !== attempt) return;
|
|
19935
|
+
try {
|
|
19936
|
+
await ((_a25 = this.onError) == null ? void 0 : _a25.call(
|
|
19937
|
+
this,
|
|
19938
|
+
error instanceof Error ? error : new Error(String(error))
|
|
19939
|
+
));
|
|
19940
|
+
} catch (e) {
|
|
19941
|
+
}
|
|
19942
|
+
}
|
|
19943
|
+
notifyEvent(event, attempt, terminal = false) {
|
|
19944
|
+
var _a25;
|
|
19945
|
+
if (this.attempt !== attempt || !attempt.active && !terminal) return;
|
|
19946
|
+
const report = (error) => {
|
|
19947
|
+
if (attempt.active || terminal) void this.reportError(error, attempt);
|
|
19948
|
+
};
|
|
19949
|
+
try {
|
|
19950
|
+
void Promise.resolve((_a25 = this.onEvent) == null ? void 0 : _a25.call(this, event)).catch(report);
|
|
19951
|
+
} catch (error) {
|
|
19952
|
+
report(error);
|
|
17898
19953
|
}
|
|
17899
19954
|
}
|
|
17900
19955
|
};
|
|
@@ -18210,7 +20265,7 @@ var DefaultProviderRegistry = class {
|
|
|
18210
20265
|
|
|
18211
20266
|
// src/rerank/rerank.ts
|
|
18212
20267
|
import {
|
|
18213
|
-
InvalidResponseDataError as
|
|
20268
|
+
InvalidResponseDataError as InvalidResponseDataError4
|
|
18214
20269
|
} from "@ai-sdk/provider";
|
|
18215
20270
|
import {
|
|
18216
20271
|
createIdGenerator as createIdGenerator8
|
|
@@ -18456,7 +20511,7 @@ function validateRankingIndices({
|
|
|
18456
20511
|
}) {
|
|
18457
20512
|
for (const { index } of ranking) {
|
|
18458
20513
|
if (!Number.isInteger(index) || index < 0 || index >= documents.length) {
|
|
18459
|
-
throw new
|
|
20514
|
+
throw new InvalidResponseDataError4({
|
|
18460
20515
|
data: ranking,
|
|
18461
20516
|
message: `Invalid ranking index ${index}. Expected an integer between 0 and ${documents.length - 1}.`
|
|
18462
20517
|
});
|
|
@@ -18478,7 +20533,7 @@ var DefaultRerankResult = class {
|
|
|
18478
20533
|
// src/transcribe/transcribe.ts
|
|
18479
20534
|
import {
|
|
18480
20535
|
detectMediaType as detectMediaType6,
|
|
18481
|
-
withUserAgentSuffix as
|
|
20536
|
+
withUserAgentSuffix as withUserAgentSuffix14
|
|
18482
20537
|
} from "@ai-sdk/provider-utils";
|
|
18483
20538
|
var defaultDownload2 = createDownload();
|
|
18484
20539
|
async function transcribe({
|
|
@@ -18498,7 +20553,7 @@ async function transcribe({
|
|
|
18498
20553
|
maxRetries: maxRetriesArg,
|
|
18499
20554
|
abortSignal
|
|
18500
20555
|
});
|
|
18501
|
-
const headersWithUserAgent =
|
|
20556
|
+
const headersWithUserAgent = withUserAgentSuffix14(
|
|
18502
20557
|
headers != null ? headers : {},
|
|
18503
20558
|
`ai/${VERSION}`
|
|
18504
20559
|
);
|
|
@@ -18551,11 +20606,11 @@ var DefaultTranscriptionResult = class {
|
|
|
18551
20606
|
|
|
18552
20607
|
// src/transcribe/stream-transcribe.ts
|
|
18553
20608
|
import {
|
|
18554
|
-
UnsupportedFunctionalityError as
|
|
20609
|
+
UnsupportedFunctionalityError as UnsupportedFunctionalityError7
|
|
18555
20610
|
} from "@ai-sdk/provider";
|
|
18556
20611
|
import {
|
|
18557
20612
|
DelayedPromise as DelayedPromise3,
|
|
18558
|
-
withUserAgentSuffix as
|
|
20613
|
+
withUserAgentSuffix as withUserAgentSuffix15
|
|
18559
20614
|
} from "@ai-sdk/provider-utils";
|
|
18560
20615
|
function streamTranscribe({
|
|
18561
20616
|
model,
|
|
@@ -18574,12 +20629,12 @@ function streamTranscribe({
|
|
|
18574
20629
|
}
|
|
18575
20630
|
const doStream = (_a25 = resolvedModel.doStream) == null ? void 0 : _a25.bind(resolvedModel);
|
|
18576
20631
|
if (doStream == null) {
|
|
18577
|
-
throw new
|
|
20632
|
+
throw new UnsupportedFunctionalityError7({
|
|
18578
20633
|
functionality: "streaming transcription",
|
|
18579
20634
|
message: `The ${resolvedModel.provider} model "${resolvedModel.modelId}" does not support streaming transcription.` + (typeof model === "string" ? " String model IDs resolve through the global provider (AI Gateway by default). If that provider does not support streaming transcription, pass a provider model instance instead (e.g. openai.transcription('gpt-realtime-whisper')) or upgrade @ai-sdk/gateway to a version with streaming transcription support." : "")
|
|
18580
20635
|
});
|
|
18581
20636
|
}
|
|
18582
|
-
const headersWithUserAgent =
|
|
20637
|
+
const headersWithUserAgent = withUserAgentSuffix15(
|
|
18583
20638
|
headers != null ? headers : {},
|
|
18584
20639
|
`ai/${VERSION}`
|
|
18585
20640
|
);
|
|
@@ -18764,7 +20819,7 @@ var experimental_transcribe = transcribe;
|
|
|
18764
20819
|
// src/translate/stream-translate.ts
|
|
18765
20820
|
import {
|
|
18766
20821
|
DelayedPromise as DelayedPromise4,
|
|
18767
|
-
withUserAgentSuffix as
|
|
20822
|
+
withUserAgentSuffix as withUserAgentSuffix16
|
|
18768
20823
|
} from "@ai-sdk/provider-utils";
|
|
18769
20824
|
function streamTranslate({
|
|
18770
20825
|
model,
|
|
@@ -18781,7 +20836,7 @@ function streamTranslate({
|
|
|
18781
20836
|
}) {
|
|
18782
20837
|
const resolvedModel = resolveSpeechTranslationModel(model);
|
|
18783
20838
|
const doStream = resolvedModel.doStream.bind(resolvedModel);
|
|
18784
|
-
const headersWithUserAgent =
|
|
20839
|
+
const headersWithUserAgent = withUserAgentSuffix16(
|
|
18785
20840
|
headers != null ? headers : {},
|
|
18786
20841
|
`ai/${VERSION}`
|
|
18787
20842
|
);
|
|
@@ -18978,7 +21033,7 @@ function streamTranslate({
|
|
|
18978
21033
|
// src/ui/call-completion-api.ts
|
|
18979
21034
|
import {
|
|
18980
21035
|
parseJsonEventStream,
|
|
18981
|
-
withUserAgentSuffix as
|
|
21036
|
+
withUserAgentSuffix as withUserAgentSuffix17,
|
|
18982
21037
|
getRuntimeEnvironmentUserAgent as getRuntimeEnvironmentUserAgent2
|
|
18983
21038
|
} from "@ai-sdk/provider-utils";
|
|
18984
21039
|
import { EmptyResponseBodyError as EmptyResponseBodyError2 } from "@ai-sdk/provider";
|
|
@@ -19047,7 +21102,7 @@ async function callCompletionApi({
|
|
|
19047
21102
|
...body
|
|
19048
21103
|
}),
|
|
19049
21104
|
credentials,
|
|
19050
|
-
headers:
|
|
21105
|
+
headers: withUserAgentSuffix17(
|
|
19051
21106
|
{
|
|
19052
21107
|
"Content-Type": "application/json",
|
|
19053
21108
|
...headers
|
|
@@ -19150,13 +21205,13 @@ import {
|
|
|
19150
21205
|
} from "@ai-sdk/provider-utils";
|
|
19151
21206
|
|
|
19152
21207
|
// src/ui/convert-file-list-to-file-ui-parts.ts
|
|
19153
|
-
import { UnsupportedFunctionalityError as
|
|
21208
|
+
import { UnsupportedFunctionalityError as UnsupportedFunctionalityError8 } from "@ai-sdk/provider";
|
|
19154
21209
|
async function convertFileListToFileUIParts(files) {
|
|
19155
21210
|
if (files == null) {
|
|
19156
21211
|
return [];
|
|
19157
21212
|
}
|
|
19158
21213
|
if (!globalThis.FileList || !(files instanceof globalThis.FileList)) {
|
|
19159
|
-
throw new
|
|
21214
|
+
throw new UnsupportedFunctionalityError8({
|
|
19160
21215
|
functionality: "FileList",
|
|
19161
21216
|
message: "FileList is not supported in the current environment"
|
|
19162
21217
|
});
|
|
@@ -19340,8 +21395,8 @@ var DefaultChatTransport = class extends HttpChatTransport {
|
|
|
19340
21395
|
// src/ui/chat.ts
|
|
19341
21396
|
var AbstractChat = class {
|
|
19342
21397
|
constructor({
|
|
19343
|
-
generateId:
|
|
19344
|
-
id =
|
|
21398
|
+
generateId: generateId5 = generateIdFunc2,
|
|
21399
|
+
id = generateId5(),
|
|
19345
21400
|
transport = new DefaultChatTransport(),
|
|
19346
21401
|
messageMetadataSchema,
|
|
19347
21402
|
dataPartSchemas,
|
|
@@ -19553,7 +21608,7 @@ var AbstractChat = class {
|
|
|
19553
21608
|
};
|
|
19554
21609
|
this.id = id;
|
|
19555
21610
|
this.transport = transport;
|
|
19556
|
-
this.generateId =
|
|
21611
|
+
this.generateId = generateId5;
|
|
19557
21612
|
this.messageMetadataSchema = messageMetadataSchema;
|
|
19558
21613
|
this.dataPartSchemas = dataPartSchemas;
|
|
19559
21614
|
this.state = state;
|
|
@@ -20046,6 +22101,7 @@ export {
|
|
|
20046
22101
|
EmptyResponseBodyError,
|
|
20047
22102
|
AbstractRealtimeSession as Experimental_AbstractRealtimeSession,
|
|
20048
22103
|
ToolLoopAgent as Experimental_Agent,
|
|
22104
|
+
Experimental_EvaluationUnsupportedQuestionTypeError,
|
|
20049
22105
|
HttpChatTransport,
|
|
20050
22106
|
InvalidArgumentError,
|
|
20051
22107
|
InvalidDataContentError,
|
|
@@ -20119,6 +22175,7 @@ export {
|
|
|
20119
22175
|
experimental_createProviderRegistry,
|
|
20120
22176
|
decodeRealtimeAudio as experimental_decodeRealtimeAudio,
|
|
20121
22177
|
encodeRealtimeAudio as experimental_encodeRealtimeAudio,
|
|
22178
|
+
evaluate as experimental_evaluate,
|
|
20122
22179
|
filterActiveTools as experimental_filterActiveTools,
|
|
20123
22180
|
experimental_generateSpeech,
|
|
20124
22181
|
experimental_generateVideo,
|
|
@@ -20139,7 +22196,7 @@ export {
|
|
|
20139
22196
|
extractReasoningMiddleware,
|
|
20140
22197
|
fingerprintTools,
|
|
20141
22198
|
gateway3 as gateway,
|
|
20142
|
-
|
|
22199
|
+
generateId4 as generateId,
|
|
20143
22200
|
generateImage,
|
|
20144
22201
|
generateObject,
|
|
20145
22202
|
generateSpeech,
|