@cydm/pie 2.6.12 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -3
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +130 -21
- package/dist/builtin/extensions/subagent/index.js +15 -6
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/computer-use-axi/SKILL.md +172 -0
- package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-broker.js} +2122 -708
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-runtime.js +728 -0
- package/dist/builtin/skills/computer-use-axi/package.json +11 -0
- package/dist/chunks/{chunk-PPEWRUMQ.js → chunk-M44CWVDZ.js} +1249 -752
- package/dist/chunks/{chunk-HHNOENEH.js → chunk-NJFPBU36.js} +14 -1
- package/dist/chunks/{chunk-AAEBH6KX.js → chunk-W74NRSRV.js} +239 -231
- package/dist/chunks/{chunk-7B4IIBVS.js → chunk-XUROMYTT.js} +1747 -14
- package/dist/chunks/{src-OWQI5M6W.js → src-C4KA4G75.js} +2 -2
- package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-A5ZELKNG.js} +1 -1
- package/dist/cli.js +863 -305
- package/models.schema.json +57 -0
- package/package.json +3 -3
- package/dist/builtin/extensions/computer-use/package.json +0 -14
- package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +0 -278
- package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +0 -204
- package/dist/chunks/chunk-5353DEEC.js +0 -130
- package/dist/chunks/webapi-MBCKO7ZV.js +0 -2481
- package/dist/code-intel-worker.cjs +0 -211227
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/arm64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/x64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/arm64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/x64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/windows/windows-bridge.exe +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/helper-path.mjs +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/setup-helper.mjs +0 -0
|
@@ -474,12 +474,20 @@ function calculateCost(model, usage) {
|
|
|
474
474
|
const output = model.cost.output / 1e6 * usage.output;
|
|
475
475
|
const cacheRead = model.cost.cacheRead / 1e6 * usage.cacheRead;
|
|
476
476
|
const cacheWrite = model.cost.cacheWrite / 1e6 * usage.cacheWrite;
|
|
477
|
+
const cacheWriteLongTokens = usage.cacheWriteLong ?? 0;
|
|
478
|
+
const hasExplicitLongRate = model.cost.cacheWriteLong !== void 0;
|
|
479
|
+
const cacheWriteLongRate = model.cost.cacheWriteLong ?? model.cost.input * 2;
|
|
480
|
+
const cacheWriteLong = cacheWriteLongTokens > 0 ? cacheWriteLongRate / 1e6 * cacheWriteLongTokens : 0;
|
|
477
481
|
return {
|
|
478
482
|
input,
|
|
479
483
|
output,
|
|
480
484
|
cacheRead,
|
|
481
485
|
cacheWrite,
|
|
482
|
-
|
|
486
|
+
...cacheWriteLongTokens > 0 ? {
|
|
487
|
+
cacheWriteLong,
|
|
488
|
+
...hasExplicitLongRate ? {} : { cacheWriteLongEstimated: true }
|
|
489
|
+
} : {},
|
|
490
|
+
total: input + output + cacheRead + cacheWrite + cacheWriteLong
|
|
483
491
|
};
|
|
484
492
|
}
|
|
485
493
|
|
|
@@ -1868,6 +1876,8 @@ function getHttpAgent() {
|
|
|
1868
1876
|
return globalHttpAgent;
|
|
1869
1877
|
}
|
|
1870
1878
|
var NodeHttpClient = class {
|
|
1879
|
+
/** The Node client never re-sends a request: one `request()` call is one submission. */
|
|
1880
|
+
transportCapabilities = { singleAttempt: true };
|
|
1871
1881
|
async request(url, options = {}) {
|
|
1872
1882
|
const requestStartTime = Date.now();
|
|
1873
1883
|
const requestId = `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
@@ -2190,6 +2200,8 @@ var NodeHttpClient = class {
|
|
|
2190
2200
|
}
|
|
2191
2201
|
};
|
|
2192
2202
|
var PuerTSHttpClient = class {
|
|
2203
|
+
/** No internal re-send: each call starts exactly one bridge request. */
|
|
2204
|
+
transportCapabilities = { singleAttempt: true };
|
|
2193
2205
|
async request(url, options = {}) {
|
|
2194
2206
|
logHttp("DEBUG", `PuerTS Request started`, {
|
|
2195
2207
|
url: url.slice(0, 100),
|
|
@@ -3047,6 +3059,227 @@ function deletePuertsDirectoryByEnumeration(path, recursive) {
|
|
|
3047
3059
|
warnPuertsDeletionShellsOnce(path);
|
|
3048
3060
|
}
|
|
3049
3061
|
|
|
3062
|
+
// ../../packages/platform/src/websocket-node.ts
|
|
3063
|
+
import { createRequire as createRequire5 } from "node:module";
|
|
3064
|
+
var require5 = createRequire5(import.meta.url);
|
|
3065
|
+
var failure = (kind, message) => new WebSocketTransportError(kind, message);
|
|
3066
|
+
var NodeWebSocketClient = class {
|
|
3067
|
+
async connect(url, options = {}) {
|
|
3068
|
+
if (options.signal?.aborted) throw failure("aborted", "Connection aborted");
|
|
3069
|
+
for (const field of ["maxMessageBytes", "maxBufferedBytes", "maxBufferedMessages", "connectTimeoutMs"]) {
|
|
3070
|
+
const value = options[field];
|
|
3071
|
+
if (value !== void 0 && (!Number.isFinite(value) || value <= 0)) throw failure("protocol", `Invalid ${field}`);
|
|
3072
|
+
}
|
|
3073
|
+
const WS = require5("ws");
|
|
3074
|
+
const socket = new WS(url, {
|
|
3075
|
+
headers: options.headers,
|
|
3076
|
+
maxPayload: options.maxMessageBytes ?? 32 * 1024 * 1024
|
|
3077
|
+
});
|
|
3078
|
+
return new Promise((resolve, reject) => {
|
|
3079
|
+
const connection = new NodeConnection(socket, options);
|
|
3080
|
+
const timeout = setTimeout(() => connection.fail(failure("timeout", "WebSocket handshake timed out")), options.connectTimeoutMs ?? 3e4);
|
|
3081
|
+
const cleanup = () => {
|
|
3082
|
+
clearTimeout(timeout);
|
|
3083
|
+
socket.off("open", opened);
|
|
3084
|
+
socket.off("error", error);
|
|
3085
|
+
socket.off("close", closed);
|
|
3086
|
+
socket.off("unexpected-response", refused);
|
|
3087
|
+
};
|
|
3088
|
+
const opened = () => {
|
|
3089
|
+
cleanup();
|
|
3090
|
+
resolve(connection);
|
|
3091
|
+
};
|
|
3092
|
+
const error = () => {
|
|
3093
|
+
cleanup();
|
|
3094
|
+
reject(connection.error ?? failure("handshake", "WebSocket connection failed"));
|
|
3095
|
+
};
|
|
3096
|
+
const closed = () => {
|
|
3097
|
+
cleanup();
|
|
3098
|
+
reject(connection.error ?? failure("handshake", "Connection closed before opening"));
|
|
3099
|
+
};
|
|
3100
|
+
const refused = (_, response) => {
|
|
3101
|
+
cleanup();
|
|
3102
|
+
const err = new WebSocketTransportError("handshake", "WebSocket upgrade refused", { status: response.statusCode });
|
|
3103
|
+
connection.fail(err);
|
|
3104
|
+
response.destroy();
|
|
3105
|
+
reject(err);
|
|
3106
|
+
};
|
|
3107
|
+
socket.once("open", opened);
|
|
3108
|
+
socket.once("error", error);
|
|
3109
|
+
socket.once("close", closed);
|
|
3110
|
+
socket.once("unexpected-response", refused);
|
|
3111
|
+
});
|
|
3112
|
+
}
|
|
3113
|
+
};
|
|
3114
|
+
var NodeConnection = class {
|
|
3115
|
+
constructor(socket, options) {
|
|
3116
|
+
this.socket = socket;
|
|
3117
|
+
this.options = options;
|
|
3118
|
+
this.closed = new Promise((resolve) => {
|
|
3119
|
+
this.resolveClosed = resolve;
|
|
3120
|
+
});
|
|
3121
|
+
socket.on("error", (error) => this.fail(failure(
|
|
3122
|
+
error.code === "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" ? "overflow" : this.opened ? "protocol" : "handshake",
|
|
3123
|
+
"WebSocket transport failed"
|
|
3124
|
+
)));
|
|
3125
|
+
socket.on("open", () => {
|
|
3126
|
+
this.opened = true;
|
|
3127
|
+
this.armIdle();
|
|
3128
|
+
});
|
|
3129
|
+
socket.on("message", (data, isBinary) => {
|
|
3130
|
+
if (this.ended || this.error) return;
|
|
3131
|
+
const buffer = Array.isArray(data) ? Buffer.concat(data) : Buffer.from(data);
|
|
3132
|
+
const bytes = buffer.byteLength;
|
|
3133
|
+
if (bytes > (options.maxMessageBytes ?? 32 * 1024 * 1024) || this.queue.length >= (options.maxBufferedMessages ?? 256) || this.queuedBytes + bytes > (options.maxBufferedBytes ?? 32 * 1024 * 1024)) {
|
|
3134
|
+
this.fail(failure("overflow", "Incoming WebSocket buffer exceeded"));
|
|
3135
|
+
return;
|
|
3136
|
+
}
|
|
3137
|
+
this.queue.push({ data: buffer.toString("utf8"), isBinary, bytes });
|
|
3138
|
+
this.queuedBytes += bytes;
|
|
3139
|
+
this.armIdle();
|
|
3140
|
+
this.wake?.();
|
|
3141
|
+
});
|
|
3142
|
+
socket.once("close", (code, reason) => {
|
|
3143
|
+
this.ended = true;
|
|
3144
|
+
clearTimeout(this.idle);
|
|
3145
|
+
clearTimeout(this.closeTimer);
|
|
3146
|
+
options.signal?.removeEventListener("abort", this.abort);
|
|
3147
|
+
this.resolveClosed({ code, reason: reason.toString() });
|
|
3148
|
+
this.wake?.();
|
|
3149
|
+
});
|
|
3150
|
+
options.signal?.addEventListener("abort", this.abort, { once: true });
|
|
3151
|
+
if (options.signal?.aborted) this.abort();
|
|
3152
|
+
}
|
|
3153
|
+
socket;
|
|
3154
|
+
options;
|
|
3155
|
+
closed;
|
|
3156
|
+
error;
|
|
3157
|
+
resolveClosed;
|
|
3158
|
+
queue = [];
|
|
3159
|
+
queuedBytes = 0;
|
|
3160
|
+
pendingBytes = 0;
|
|
3161
|
+
pendingMessages = 0;
|
|
3162
|
+
sending = Promise.resolve();
|
|
3163
|
+
wake;
|
|
3164
|
+
receiving = false;
|
|
3165
|
+
ended = false;
|
|
3166
|
+
opened = false;
|
|
3167
|
+
idle;
|
|
3168
|
+
closeTimer;
|
|
3169
|
+
abort = () => this.fail(failure("aborted", "Connection aborted"));
|
|
3170
|
+
fail(error) {
|
|
3171
|
+
if (this.ended || this.error) return;
|
|
3172
|
+
this.error = error;
|
|
3173
|
+
this.queue = [];
|
|
3174
|
+
this.queuedBytes = 0;
|
|
3175
|
+
clearTimeout(this.idle);
|
|
3176
|
+
this.socket.terminate();
|
|
3177
|
+
this.wake?.();
|
|
3178
|
+
}
|
|
3179
|
+
armIdle() {
|
|
3180
|
+
clearTimeout(this.idle);
|
|
3181
|
+
if (this.options.idleTimeoutMs && this.options.idleTimeoutMs > 0) {
|
|
3182
|
+
this.idle = setTimeout(() => this.fail(failure("timeout", "WebSocket idle timeout")), this.options.idleTimeoutMs);
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
async send(message, options) {
|
|
3186
|
+
const bytes = Buffer.byteLength(message);
|
|
3187
|
+
if (bytes > (this.options.maxMessageBytes ?? 32 * 1024 * 1024) || this.pendingBytes + bytes > (this.options.maxBufferedBytes ?? 32 * 1024 * 1024) || this.pendingMessages >= (this.options.maxBufferedMessages ?? 256)) {
|
|
3188
|
+
throw failure("overflow", "Outgoing WebSocket buffer exceeded");
|
|
3189
|
+
}
|
|
3190
|
+
const signal = options?.signal;
|
|
3191
|
+
if (signal?.aborted) {
|
|
3192
|
+
this.abort();
|
|
3193
|
+
throw failure("aborted", "Send aborted");
|
|
3194
|
+
}
|
|
3195
|
+
const abortSend = () => this.abort();
|
|
3196
|
+
signal?.addEventListener("abort", abortSend, { once: true });
|
|
3197
|
+
this.pendingBytes += bytes;
|
|
3198
|
+
this.pendingMessages++;
|
|
3199
|
+
const operation = this.sending.then(() => new Promise((resolve, reject) => {
|
|
3200
|
+
if (this.error) {
|
|
3201
|
+
reject(this.error);
|
|
3202
|
+
return;
|
|
3203
|
+
}
|
|
3204
|
+
if (this.socket.readyState !== 1) {
|
|
3205
|
+
reject(failure("closed", "Connection is not open"));
|
|
3206
|
+
return;
|
|
3207
|
+
}
|
|
3208
|
+
this.socket.send(message, (error) => error ? reject(this.error ?? failure("closed", "Send failed")) : resolve());
|
|
3209
|
+
}));
|
|
3210
|
+
this.sending = operation.catch(() => {
|
|
3211
|
+
});
|
|
3212
|
+
try {
|
|
3213
|
+
await operation;
|
|
3214
|
+
} finally {
|
|
3215
|
+
this.pendingBytes -= bytes;
|
|
3216
|
+
this.pendingMessages--;
|
|
3217
|
+
signal?.removeEventListener("abort", abortSend);
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
async *receive(signal) {
|
|
3221
|
+
if (this.receiving) throw failure("protocol", "Only one receiver is permitted");
|
|
3222
|
+
this.receiving = true;
|
|
3223
|
+
const abortReceive = () => this.abort();
|
|
3224
|
+
signal?.addEventListener("abort", abortReceive, { once: true });
|
|
3225
|
+
try {
|
|
3226
|
+
while (true) {
|
|
3227
|
+
if (signal?.aborted) this.abort();
|
|
3228
|
+
if (this.error) throw this.error;
|
|
3229
|
+
const item = this.queue.shift();
|
|
3230
|
+
if (item) {
|
|
3231
|
+
this.queuedBytes -= item.bytes;
|
|
3232
|
+
yield item;
|
|
3233
|
+
continue;
|
|
3234
|
+
}
|
|
3235
|
+
if (this.ended) return;
|
|
3236
|
+
await new Promise((resolve) => {
|
|
3237
|
+
this.wake = resolve;
|
|
3238
|
+
});
|
|
3239
|
+
this.wake = void 0;
|
|
3240
|
+
}
|
|
3241
|
+
} finally {
|
|
3242
|
+
this.receiving = false;
|
|
3243
|
+
this.wake = void 0;
|
|
3244
|
+
signal?.removeEventListener("abort", abortReceive);
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
async close(code = 1e3, reason = "") {
|
|
3248
|
+
if (!this.ended && this.socket.readyState < 2) {
|
|
3249
|
+
this.socket.close(code, reason);
|
|
3250
|
+
this.closeTimer = setTimeout(() => this.socket.terminate(), 1e3);
|
|
3251
|
+
}
|
|
3252
|
+
await this.closed;
|
|
3253
|
+
}
|
|
3254
|
+
state() {
|
|
3255
|
+
return ["connecting", "open", "closing", "closed"][this.socket.readyState];
|
|
3256
|
+
}
|
|
3257
|
+
};
|
|
3258
|
+
|
|
3259
|
+
// ../../packages/platform/src/websocket.ts
|
|
3260
|
+
var WebSocketTransportError = class extends Error {
|
|
3261
|
+
kind;
|
|
3262
|
+
/** HTTP status of a refused handshake, when the transport reports one. */
|
|
3263
|
+
status;
|
|
3264
|
+
/** Close code carried by the failure, when one exists. */
|
|
3265
|
+
closeCode;
|
|
3266
|
+
constructor(kind, message, details = {}) {
|
|
3267
|
+
super(`[websocket:${kind}] ${message}`);
|
|
3268
|
+
this.name = "WebSocketTransportError";
|
|
3269
|
+
this.kind = kind;
|
|
3270
|
+
if (details.status !== void 0) this.status = details.status;
|
|
3271
|
+
if (details.closeCode !== void 0) this.closeCode = details.closeCode;
|
|
3272
|
+
}
|
|
3273
|
+
};
|
|
3274
|
+
var webSocketClientInstance;
|
|
3275
|
+
function getNodeWebSocketClient() {
|
|
3276
|
+
return detectPlatform() === "node" ? new NodeWebSocketClient() : void 0;
|
|
3277
|
+
}
|
|
3278
|
+
function getWebSocketClient() {
|
|
3279
|
+
if (webSocketClientInstance === void 0) webSocketClientInstance = getNodeWebSocketClient() ?? null;
|
|
3280
|
+
return webSocketClientInstance ?? void 0;
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3050
3283
|
// ../../packages/platform/src/index.ts
|
|
3051
3284
|
var fileSystemInstance = null;
|
|
3052
3285
|
var httpClientInstance = null;
|
|
@@ -3091,6 +3324,9 @@ function getHttpClient() {
|
|
|
3091
3324
|
}
|
|
3092
3325
|
|
|
3093
3326
|
// ../../packages/ai/src/utils/http.ts
|
|
3327
|
+
function getHttpTransport() {
|
|
3328
|
+
return getHttpClient();
|
|
3329
|
+
}
|
|
3094
3330
|
function httpRequest(url, options = {}) {
|
|
3095
3331
|
const client = getHttpClient();
|
|
3096
3332
|
return client.request(url, options);
|
|
@@ -3123,6 +3359,8 @@ function buildBaseOptions(model, options, apiKey) {
|
|
|
3123
3359
|
const modelMaxTokens = positiveFiniteOrInfinity(model.maxTokens);
|
|
3124
3360
|
return {
|
|
3125
3361
|
temperature: options?.temperature,
|
|
3362
|
+
transport: options?.transport ?? model.transport,
|
|
3363
|
+
transportOwner: options?.transportOwner,
|
|
3126
3364
|
maxTokens: options?.maxTokens || Math.min(modelMaxTokens, DEFAULT_MAX_TOKENS),
|
|
3127
3365
|
signal: options?.signal,
|
|
3128
3366
|
apiKey: apiKey || options?.apiKey,
|
|
@@ -3131,6 +3369,8 @@ function buildBaseOptions(model, options, apiKey) {
|
|
|
3131
3369
|
headers: options?.headers,
|
|
3132
3370
|
timeoutMs: options?.timeoutMs,
|
|
3133
3371
|
onPayload: options?.onPayload,
|
|
3372
|
+
onTransportDiagnostic: options?.onTransportDiagnostic,
|
|
3373
|
+
onTransportLifecycle: options?.onTransportLifecycle,
|
|
3134
3374
|
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
3135
3375
|
metadata: options?.metadata
|
|
3136
3376
|
};
|
|
@@ -3729,6 +3969,7 @@ function tryParseFinalToolArguments(partialArgs) {
|
|
|
3729
3969
|
}
|
|
3730
3970
|
}
|
|
3731
3971
|
var streamOpenAICompletions = (model, context, options) => {
|
|
3972
|
+
if ((options?.transport ?? model.transport) === "websocket") throw new Error(`API ${model.api} does not support WebSocket transport.`);
|
|
3732
3973
|
const stream = new AssistantMessageEventStream();
|
|
3733
3974
|
(async () => {
|
|
3734
3975
|
const output = {
|
|
@@ -4182,6 +4423,35 @@ import Anthropic from "@anthropic-ai/sdk";
|
|
|
4182
4423
|
function sanitizeSurrogates(text) {
|
|
4183
4424
|
return text.replace(/[\uD800-\uDFFF]/g, "");
|
|
4184
4425
|
}
|
|
4426
|
+
function applyAnthropicUsageUpdate(model, usage, payload) {
|
|
4427
|
+
if (payload.input_tokens != null) usage.input = Math.max(0, payload.input_tokens);
|
|
4428
|
+
if (payload.output_tokens != null) usage.output = Math.max(0, payload.output_tokens);
|
|
4429
|
+
if (payload.cache_read_input_tokens != null) usage.cacheRead = Math.max(0, payload.cache_read_input_tokens);
|
|
4430
|
+
const reportedWriteTotal = payload.cache_creation_input_tokens;
|
|
4431
|
+
const breakdown = payload.cache_creation ?? void 0;
|
|
4432
|
+
const breakdownTotal = (breakdown?.ephemeral_5m_input_tokens ?? 0) + (breakdown?.ephemeral_1h_input_tokens ?? 0);
|
|
4433
|
+
if (reportedWriteTotal == null && breakdown !== void 0 && breakdownTotal === 0) {
|
|
4434
|
+
usage.cacheWrite = Math.max(0, usage.cacheWrite);
|
|
4435
|
+
} else if (reportedWriteTotal != null || breakdown !== void 0) {
|
|
4436
|
+
const previousLong = usage.cacheWriteLong ?? 0;
|
|
4437
|
+
const previousTotal = usage.cacheWrite + previousLong;
|
|
4438
|
+
const writeTotal = Math.max(
|
|
4439
|
+
0,
|
|
4440
|
+
reportedWriteTotal != null ? reportedWriteTotal : breakdownTotal > 0 ? breakdownTotal : previousTotal
|
|
4441
|
+
);
|
|
4442
|
+
const longTokens = breakdown?.ephemeral_1h_input_tokens ?? 0;
|
|
4443
|
+
if (longTokens > 0) {
|
|
4444
|
+
const long = Math.min(longTokens, writeTotal);
|
|
4445
|
+
usage.cacheWriteLong = long;
|
|
4446
|
+
usage.cacheWrite = writeTotal - long;
|
|
4447
|
+
} else {
|
|
4448
|
+
delete usage.cacheWriteLong;
|
|
4449
|
+
usage.cacheWrite = writeTotal;
|
|
4450
|
+
}
|
|
4451
|
+
}
|
|
4452
|
+
usage.totalTokens = usage.input + usage.output + usage.cacheRead + usage.cacheWrite + (usage.cacheWriteLong ?? 0);
|
|
4453
|
+
usage.cost = calculateCost(model, usage);
|
|
4454
|
+
}
|
|
4185
4455
|
var ANTHROPIC_PROVIDER_HEADERS = {
|
|
4186
4456
|
accept: "application/json",
|
|
4187
4457
|
"anthropic-dangerous-direct-browser-access": "true",
|
|
@@ -4395,6 +4665,7 @@ function applyCacheBreakpoints(params, retention) {
|
|
|
4395
4665
|
}
|
|
4396
4666
|
}
|
|
4397
4667
|
var streamAnthropic = (model, context, options) => {
|
|
4668
|
+
if ((options?.transport ?? model.transport) === "websocket") throw new Error(`API ${model.api} does not support WebSocket transport.`);
|
|
4398
4669
|
const stream = new AssistantMessageEventStream();
|
|
4399
4670
|
(async () => {
|
|
4400
4671
|
const output = {
|
|
@@ -4466,12 +4737,7 @@ var streamAnthropic = (model, context, options) => {
|
|
|
4466
4737
|
const blocks = output.content;
|
|
4467
4738
|
for await (const event of anthropicStream) {
|
|
4468
4739
|
if (event.type === "message_start") {
|
|
4469
|
-
output.usage
|
|
4470
|
-
output.usage.output = event.message.usage.output_tokens || 0;
|
|
4471
|
-
output.usage.cacheRead = event.message.usage.cache_read_input_tokens || 0;
|
|
4472
|
-
output.usage.cacheWrite = event.message.usage.cache_creation_input_tokens || 0;
|
|
4473
|
-
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
4474
|
-
calculateCost(model, output.usage);
|
|
4740
|
+
applyAnthropicUsageUpdate(model, output.usage, event.message.usage);
|
|
4475
4741
|
} else if (event.type === "content_block_start") {
|
|
4476
4742
|
if (event.content_block.type === "text") {
|
|
4477
4743
|
const block = { type: "text", text: "", index: event.index };
|
|
@@ -4575,13 +4841,7 @@ var streamAnthropic = (model, context, options) => {
|
|
|
4575
4841
|
if (event.delta.stop_reason) {
|
|
4576
4842
|
output.stopReason = mapStopReason(event.delta.stop_reason);
|
|
4577
4843
|
}
|
|
4578
|
-
|
|
4579
|
-
if (event.usage.output_tokens != null) output.usage.output = event.usage.output_tokens;
|
|
4580
|
-
if (event.usage.cache_read_input_tokens != null) output.usage.cacheRead = event.usage.cache_read_input_tokens;
|
|
4581
|
-
if (event.usage.cache_creation_input_tokens != null)
|
|
4582
|
-
output.usage.cacheWrite = event.usage.cache_creation_input_tokens;
|
|
4583
|
-
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
4584
|
-
calculateCost(model, output.usage);
|
|
4844
|
+
applyAnthropicUsageUpdate(model, output.usage, event.usage);
|
|
4585
4845
|
}
|
|
4586
4846
|
}
|
|
4587
4847
|
if (options?.signal?.aborted) {
|
|
@@ -4619,6 +4879,1473 @@ var streamSimpleAnthropic = (model, context, options) => {
|
|
|
4619
4879
|
});
|
|
4620
4880
|
};
|
|
4621
4881
|
|
|
4882
|
+
// ../../packages/ai/src/providers/responses/responses-compat.ts
|
|
4883
|
+
function getResponsesCompat(model) {
|
|
4884
|
+
const compat = model.compat ?? {};
|
|
4885
|
+
return {
|
|
4886
|
+
store: compat.store ?? false,
|
|
4887
|
+
supportsStore: compat.supportsStore ?? true,
|
|
4888
|
+
supportsReasoningEffort: compat.supportsReasoningEffort ?? true,
|
|
4889
|
+
supportsEncryptedReasoning: compat.supportsEncryptedReasoning ?? true,
|
|
4890
|
+
responsesContinuation: compat.responsesContinuation ?? false
|
|
4891
|
+
};
|
|
4892
|
+
}
|
|
4893
|
+
|
|
4894
|
+
// ../../packages/ai/src/providers/responses/responses-wire.ts
|
|
4895
|
+
var RESPONSES_PROTOCOL_ERROR_CODE = "responses_protocol_error";
|
|
4896
|
+
var ResponsesProtocolError = class extends Error {
|
|
4897
|
+
code = RESPONSES_PROTOCOL_ERROR_CODE;
|
|
4898
|
+
constructor(message) {
|
|
4899
|
+
super(`${RESPONSES_PROTOCOL_ERROR_CODE}: ${message}`);
|
|
4900
|
+
this.name = "ResponsesProtocolError";
|
|
4901
|
+
}
|
|
4902
|
+
};
|
|
4903
|
+
function isRecord2(value) {
|
|
4904
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4905
|
+
}
|
|
4906
|
+
function isResponsesEventLike(value) {
|
|
4907
|
+
return isRecord2(value) && typeof value.type === "string";
|
|
4908
|
+
}
|
|
4909
|
+
function formatResponsesErrorEvent(event) {
|
|
4910
|
+
const source = isRecord2(event.error) ? event.error : event;
|
|
4911
|
+
const message = typeof source.message === "string" && source.message.length > 0 ? source.message : "Responses stream returned an error";
|
|
4912
|
+
const metadata = [];
|
|
4913
|
+
if (typeof source.code === "string" && source.code.length > 0) {
|
|
4914
|
+
metadata.push(`code=${source.code}`);
|
|
4915
|
+
}
|
|
4916
|
+
if (typeof source.param === "string" && source.param.length > 0) {
|
|
4917
|
+
metadata.push(`param=${source.param}`);
|
|
4918
|
+
}
|
|
4919
|
+
if (typeof event.status === "number") {
|
|
4920
|
+
metadata.push(`status=${event.status}`);
|
|
4921
|
+
}
|
|
4922
|
+
return metadata.length > 0 ? `${message} (${metadata.join(", ")})` : message;
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4925
|
+
// ../../packages/ai/src/providers/responses/responses-request.ts
|
|
4926
|
+
var MAX_REASONING_ENVELOPE_BYTES = 512 * 1024;
|
|
4927
|
+
function decodeReasoningEnvelope(signature) {
|
|
4928
|
+
if (typeof signature !== "string" || signature.length === 0 || signature.length > MAX_REASONING_ENVELOPE_BYTES) {
|
|
4929
|
+
return null;
|
|
4930
|
+
}
|
|
4931
|
+
let parsed;
|
|
4932
|
+
try {
|
|
4933
|
+
parsed = JSON.parse(signature);
|
|
4934
|
+
} catch {
|
|
4935
|
+
return null;
|
|
4936
|
+
}
|
|
4937
|
+
if (!isRecord2(parsed) || parsed.v !== 1 || typeof parsed.id !== "string" || parsed.id.length === 0) {
|
|
4938
|
+
return null;
|
|
4939
|
+
}
|
|
4940
|
+
const encrypted = parsed.encrypted_content;
|
|
4941
|
+
if (encrypted !== void 0 && encrypted !== null && typeof encrypted !== "string") {
|
|
4942
|
+
return null;
|
|
4943
|
+
}
|
|
4944
|
+
return { v: 1, id: parsed.id, encrypted_content: encrypted };
|
|
4945
|
+
}
|
|
4946
|
+
function buildResponsesInput(model, context) {
|
|
4947
|
+
const items = [];
|
|
4948
|
+
const isSameModel = (msg) => msg.provider === model.provider && msg.api === model.api && msg.model === model.id;
|
|
4949
|
+
const transformed = transformMessages(context.messages, model);
|
|
4950
|
+
for (const msg of transformed) {
|
|
4951
|
+
if (msg.role === "user") {
|
|
4952
|
+
items.push(encodeUserMessage(msg.content, model));
|
|
4953
|
+
} else if (msg.role === "assistant") {
|
|
4954
|
+
encodeAssistantMessage(msg, isSameModel, items);
|
|
4955
|
+
} else if (msg.role === "toolResult") {
|
|
4956
|
+
items.push(encodeToolResult(msg, model));
|
|
4957
|
+
}
|
|
4958
|
+
}
|
|
4959
|
+
return items;
|
|
4960
|
+
}
|
|
4961
|
+
function encodeUserMessage(content, model) {
|
|
4962
|
+
if (typeof content === "string") {
|
|
4963
|
+
return { role: "user", type: "message", content };
|
|
4964
|
+
}
|
|
4965
|
+
const parts = [];
|
|
4966
|
+
for (const block of content) {
|
|
4967
|
+
parts.push(...encodeUserContentBlock(block, model));
|
|
4968
|
+
}
|
|
4969
|
+
if (parts.length === 0) {
|
|
4970
|
+
return { role: "user", type: "message", content: "" };
|
|
4971
|
+
}
|
|
4972
|
+
return { role: "user", type: "message", content: parts };
|
|
4973
|
+
}
|
|
4974
|
+
function encodeUserContentBlock(block, model) {
|
|
4975
|
+
const modality = block.type === "fileRef" ? block.modality : block.type;
|
|
4976
|
+
if (modality !== "text" && !model.input.includes(modality)) {
|
|
4977
|
+
throw new ResponsesProtocolError(`Current model does not support ${modality} input.`);
|
|
4978
|
+
}
|
|
4979
|
+
switch (block.type) {
|
|
4980
|
+
case "text":
|
|
4981
|
+
return [{ type: "input_text", text: block.text }];
|
|
4982
|
+
case "image":
|
|
4983
|
+
return [{ type: "input_image", image_url: `data:${block.mimeType};base64,${block.data}` }];
|
|
4984
|
+
case "video":
|
|
4985
|
+
case "audio":
|
|
4986
|
+
throw new ResponsesProtocolError(`Responses ${block.type} input is not supported by this provider.`);
|
|
4987
|
+
case "fileRef": {
|
|
4988
|
+
const ref = block;
|
|
4989
|
+
if (ref.modality === "image") {
|
|
4990
|
+
return [{ type: "input_image", image_url: ref.url }];
|
|
4991
|
+
}
|
|
4992
|
+
throw new ResponsesProtocolError(`Responses ${ref.modality} file references are not supported by this provider.`);
|
|
4993
|
+
}
|
|
4994
|
+
default:
|
|
4995
|
+
throw new ResponsesProtocolError("Unsupported Responses content block.");
|
|
4996
|
+
}
|
|
4997
|
+
}
|
|
4998
|
+
function encodeAssistantMessage(msg, isSameModel, items) {
|
|
4999
|
+
for (const block of msg.content) {
|
|
5000
|
+
if (block.type === "thinking") {
|
|
5001
|
+
const thinking = block;
|
|
5002
|
+
if (isSameModel(msg)) {
|
|
5003
|
+
const envelope = decodeReasoningEnvelope(thinking.thinkingSignature);
|
|
5004
|
+
if (thinking.thinkingSignature && !envelope) {
|
|
5005
|
+
throw new ResponsesProtocolError("Invalid Responses reasoning signature.");
|
|
5006
|
+
}
|
|
5007
|
+
if (envelope) {
|
|
5008
|
+
items.push({
|
|
5009
|
+
type: "reasoning",
|
|
5010
|
+
id: envelope.id,
|
|
5011
|
+
summary: thinking.thinking.trim() ? [{ type: "summary_text", text: thinking.thinking }] : [],
|
|
5012
|
+
...envelope.encrypted_content ? { encrypted_content: envelope.encrypted_content } : {}
|
|
5013
|
+
});
|
|
5014
|
+
continue;
|
|
5015
|
+
}
|
|
5016
|
+
}
|
|
5017
|
+
if (thinking.thinking && thinking.thinking.trim().length > 0) {
|
|
5018
|
+
items.push({ role: "assistant", type: "message", content: thinking.thinking });
|
|
5019
|
+
}
|
|
5020
|
+
continue;
|
|
5021
|
+
}
|
|
5022
|
+
if (block.type === "text") {
|
|
5023
|
+
const text = block;
|
|
5024
|
+
if (text.text && text.text.trim().length > 0) {
|
|
5025
|
+
items.push({ role: "assistant", type: "message", content: text.text });
|
|
5026
|
+
}
|
|
5027
|
+
continue;
|
|
5028
|
+
}
|
|
5029
|
+
if (block.type === "toolCall") {
|
|
5030
|
+
const call = block;
|
|
5031
|
+
items.push({
|
|
5032
|
+
type: "function_call",
|
|
5033
|
+
call_id: call.id,
|
|
5034
|
+
name: call.name,
|
|
5035
|
+
arguments: JSON.stringify(call.arguments ?? {})
|
|
5036
|
+
});
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
function buildResponsesOutput(message) {
|
|
5041
|
+
const items = [];
|
|
5042
|
+
encodeAssistantMessage(message, () => true, items);
|
|
5043
|
+
return items;
|
|
5044
|
+
}
|
|
5045
|
+
function encodeToolResult(msg, model) {
|
|
5046
|
+
const output = msg.content.every((block) => block.type === "text") ? msg.content.map((block) => block.text).join("\n") || "(empty result)" : msg.content.flatMap((block) => encodeUserContentBlock(block, model));
|
|
5047
|
+
return { type: "function_call_output", call_id: msg.toolCallId, output };
|
|
5048
|
+
}
|
|
5049
|
+
function encodeTools(tools) {
|
|
5050
|
+
return tools.map((tool) => ({
|
|
5051
|
+
type: "function",
|
|
5052
|
+
name: tool.name,
|
|
5053
|
+
description: tool.description,
|
|
5054
|
+
parameters: tool.parameters ?? { type: "object", properties: {} },
|
|
5055
|
+
strict: false
|
|
5056
|
+
}));
|
|
5057
|
+
}
|
|
5058
|
+
function buildResponsesRequest(model, context, options, compat = getResponsesCompat(model)) {
|
|
5059
|
+
const params = {
|
|
5060
|
+
model: model.id,
|
|
5061
|
+
input: buildResponsesInput(model, context)
|
|
5062
|
+
};
|
|
5063
|
+
if (context.systemPrompt !== void 0 && context.systemPrompt !== null && context.systemPrompt.length > 0) {
|
|
5064
|
+
params.instructions = context.systemPrompt;
|
|
5065
|
+
}
|
|
5066
|
+
if (compat.supportsStore) {
|
|
5067
|
+
params.store = compat.store;
|
|
5068
|
+
}
|
|
5069
|
+
if (options?.maxTokens !== void 0 && options.maxTokens > 0) {
|
|
5070
|
+
params.max_output_tokens = options.maxTokens;
|
|
5071
|
+
}
|
|
5072
|
+
if (options?.temperature !== void 0) params.temperature = options.temperature;
|
|
5073
|
+
if (options?.topP !== void 0) params.top_p = options.topP;
|
|
5074
|
+
if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {
|
|
5075
|
+
params.reasoning = { effort: options.reasoningEffort };
|
|
5076
|
+
}
|
|
5077
|
+
if (compat.supportsEncryptedReasoning && model.reasoning) {
|
|
5078
|
+
params.include = ["reasoning.encrypted_content"];
|
|
5079
|
+
}
|
|
5080
|
+
if (context.tools && context.tools.length > 0) {
|
|
5081
|
+
params.tools = encodeTools(context.tools);
|
|
5082
|
+
params.parallel_tool_calls = true;
|
|
5083
|
+
}
|
|
5084
|
+
if (options?.toolChoice !== void 0) {
|
|
5085
|
+
params.tool_choice = options.toolChoice === "required" ? "required" : options.toolChoice;
|
|
5086
|
+
}
|
|
5087
|
+
return params;
|
|
5088
|
+
}
|
|
5089
|
+
function buildResponsesSSEPayload(model, context, options) {
|
|
5090
|
+
return { ...buildResponsesRequest(model, context, options), stream: true };
|
|
5091
|
+
}
|
|
5092
|
+
function buildResponsesCreateEvent(model, context, options) {
|
|
5093
|
+
const params = buildResponsesRequest(model, context, options);
|
|
5094
|
+
delete params.stream;
|
|
5095
|
+
return { type: "response.create", ...params };
|
|
5096
|
+
}
|
|
5097
|
+
|
|
5098
|
+
// ../../packages/ai/src/providers/responses/responses-usage.ts
|
|
5099
|
+
function tokenCount(value) {
|
|
5100
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
|
|
5101
|
+
return Math.floor(value);
|
|
5102
|
+
}
|
|
5103
|
+
function normalizeResponsesUsage(model, usage) {
|
|
5104
|
+
const inputTokens = tokenCount(usage?.input_tokens);
|
|
5105
|
+
const cachedTokens = tokenCount(usage?.input_tokens_details?.cached_tokens) ?? 0;
|
|
5106
|
+
const cacheWriteTokens = tokenCount(usage?.input_tokens_details?.cache_write_tokens) ?? 0;
|
|
5107
|
+
const outputTokens = tokenCount(usage?.output_tokens);
|
|
5108
|
+
const reasoningTokens = tokenCount(usage?.output_tokens_details?.reasoning_tokens);
|
|
5109
|
+
const totalTokens = tokenCount(usage?.total_tokens);
|
|
5110
|
+
const input = inputTokens ?? (totalTokens !== void 0 && outputTokens !== void 0 ? Math.max(cachedTokens + cacheWriteTokens, totalTokens - outputTokens) : cachedTokens + cacheWriteTokens);
|
|
5111
|
+
const output = outputTokens ?? (totalTokens !== void 0 ? Math.max(reasoningTokens ?? 0, totalTokens - input) : reasoningTokens ?? 0);
|
|
5112
|
+
const cacheRead = Math.min(cachedTokens, input);
|
|
5113
|
+
const cacheWrite = Math.min(cacheWriteTokens, input - cacheRead);
|
|
5114
|
+
const inputExclusive = input - cacheRead - cacheWrite;
|
|
5115
|
+
const partitionTotal = input + output;
|
|
5116
|
+
const base = {
|
|
5117
|
+
input: inputExclusive,
|
|
5118
|
+
output,
|
|
5119
|
+
cacheRead,
|
|
5120
|
+
cacheWrite,
|
|
5121
|
+
totalTokens: Math.max(totalTokens ?? 0, partitionTotal)
|
|
5122
|
+
};
|
|
5123
|
+
return { ...base, cost: calculateCost(model, base) };
|
|
5124
|
+
}
|
|
5125
|
+
|
|
5126
|
+
// ../../packages/ai/src/providers/responses/responses-events.ts
|
|
5127
|
+
var ResponsesEventReducer = class {
|
|
5128
|
+
output;
|
|
5129
|
+
model;
|
|
5130
|
+
started = false;
|
|
5131
|
+
terminal = null;
|
|
5132
|
+
items = /* @__PURE__ */ new Map();
|
|
5133
|
+
toolCallStates = [];
|
|
5134
|
+
diagnostics = { unknownEventTypes: /* @__PURE__ */ new Set(), ignoredItemTypes: /* @__PURE__ */ new Set(), terminalType: null };
|
|
5135
|
+
constructor(model) {
|
|
5136
|
+
this.model = model;
|
|
5137
|
+
this.output = {
|
|
5138
|
+
role: "assistant",
|
|
5139
|
+
content: [],
|
|
5140
|
+
api: model.api,
|
|
5141
|
+
provider: model.provider,
|
|
5142
|
+
model: model.id,
|
|
5143
|
+
usageReported: false,
|
|
5144
|
+
usage: {
|
|
5145
|
+
input: 0,
|
|
5146
|
+
output: 0,
|
|
5147
|
+
cacheRead: 0,
|
|
5148
|
+
cacheWrite: 0,
|
|
5149
|
+
totalTokens: 0,
|
|
5150
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
5151
|
+
},
|
|
5152
|
+
stopReason: "stop",
|
|
5153
|
+
timestamp: Date.now()
|
|
5154
|
+
};
|
|
5155
|
+
}
|
|
5156
|
+
get message() {
|
|
5157
|
+
return this.output;
|
|
5158
|
+
}
|
|
5159
|
+
get isTerminal() {
|
|
5160
|
+
return this.terminal !== null;
|
|
5161
|
+
}
|
|
5162
|
+
/** Terminal response object (present on completed/incomplete/failed). */
|
|
5163
|
+
get terminalResponse() {
|
|
5164
|
+
return this.terminal?.response;
|
|
5165
|
+
}
|
|
5166
|
+
/** Feed one raw wire event; returns the AssistantMessageEvents to emit. */
|
|
5167
|
+
feed(raw) {
|
|
5168
|
+
const events = [];
|
|
5169
|
+
if (!isResponsesEventLike(raw)) {
|
|
5170
|
+
throw new ResponsesProtocolError("Responses stream returned an event without a string type.");
|
|
5171
|
+
}
|
|
5172
|
+
if (this.terminal) return events;
|
|
5173
|
+
switch (raw.type) {
|
|
5174
|
+
case "response.created":
|
|
5175
|
+
case "response.in_progress":
|
|
5176
|
+
case "response.queued":
|
|
5177
|
+
if (!this.started) {
|
|
5178
|
+
this.started = true;
|
|
5179
|
+
events.push({ type: "start", partial: this.output });
|
|
5180
|
+
}
|
|
5181
|
+
break;
|
|
5182
|
+
case "response.output_item.added":
|
|
5183
|
+
events.push(...this.onOutputItemAdded(raw));
|
|
5184
|
+
break;
|
|
5185
|
+
case "response.output_item.done":
|
|
5186
|
+
events.push(...this.onOutputItemDone(raw));
|
|
5187
|
+
break;
|
|
5188
|
+
case "response.content_part.added":
|
|
5189
|
+
events.push(...this.onContentPartAdded(raw));
|
|
5190
|
+
break;
|
|
5191
|
+
case "response.content_part.done":
|
|
5192
|
+
break;
|
|
5193
|
+
case "response.output_text.delta":
|
|
5194
|
+
events.push(...this.appendTextDelta(raw, "text"));
|
|
5195
|
+
break;
|
|
5196
|
+
case "response.output_text.done":
|
|
5197
|
+
this.validateTextDone(raw);
|
|
5198
|
+
break;
|
|
5199
|
+
case "response.refusal.delta":
|
|
5200
|
+
events.push(...this.appendTextDelta(raw, "refusal"));
|
|
5201
|
+
break;
|
|
5202
|
+
case "response.refusal.done":
|
|
5203
|
+
break;
|
|
5204
|
+
case "response.reasoning_summary_text.delta":
|
|
5205
|
+
case "response.reasoning_text.delta":
|
|
5206
|
+
events.push(...this.appendReasoningDelta(raw));
|
|
5207
|
+
break;
|
|
5208
|
+
case "response.reasoning_summary_text.done":
|
|
5209
|
+
case "response.reasoning_text.done":
|
|
5210
|
+
break;
|
|
5211
|
+
case "response.reasoning_summary_part.added":
|
|
5212
|
+
case "response.reasoning_summary_part.done":
|
|
5213
|
+
break;
|
|
5214
|
+
case "response.function_call_arguments.delta":
|
|
5215
|
+
events.push(...this.appendFunctionCallArgsDelta(raw));
|
|
5216
|
+
break;
|
|
5217
|
+
case "response.function_call_arguments.done":
|
|
5218
|
+
this.onFunctionCallArgsDone(raw);
|
|
5219
|
+
break;
|
|
5220
|
+
case "response.completed":
|
|
5221
|
+
events.push(...this.onTerminal(raw, "response.completed"));
|
|
5222
|
+
break;
|
|
5223
|
+
case "response.incomplete":
|
|
5224
|
+
events.push(...this.onIncomplete(raw));
|
|
5225
|
+
break;
|
|
5226
|
+
case "response.failed":
|
|
5227
|
+
events.push(...this.onTerminal(raw, "response.failed", "error", this.failedText(raw)));
|
|
5228
|
+
break;
|
|
5229
|
+
case "error":
|
|
5230
|
+
events.push(...this.onTerminal(raw, "error", "error", formatResponsesErrorEvent(raw)));
|
|
5231
|
+
break;
|
|
5232
|
+
default:
|
|
5233
|
+
this.diagnostics.unknownEventTypes.add(raw.type);
|
|
5234
|
+
break;
|
|
5235
|
+
}
|
|
5236
|
+
return events;
|
|
5237
|
+
}
|
|
5238
|
+
/** Stream ended without a terminal event. Caller decides how to fail. */
|
|
5239
|
+
finishWithoutTerminal() {
|
|
5240
|
+
return new ResponsesProtocolError(
|
|
5241
|
+
`Responses stream ended without a terminal event (${this.diagnostics.terminalType ?? "none"} seen).`
|
|
5242
|
+
);
|
|
5243
|
+
}
|
|
5244
|
+
// ─── item lifecycle ─────────────────────────────────────────────────────
|
|
5245
|
+
ensureStarted() {
|
|
5246
|
+
if (this.started) return [];
|
|
5247
|
+
this.started = true;
|
|
5248
|
+
return [{ type: "start", partial: this.output }];
|
|
5249
|
+
}
|
|
5250
|
+
requireItemIndex(raw) {
|
|
5251
|
+
const index = raw.output_index;
|
|
5252
|
+
if (typeof index !== "number" || !Number.isInteger(index) || index < 0) {
|
|
5253
|
+
throw new ResponsesProtocolError(`Responses event "${raw.type}" is missing a valid output_index.`);
|
|
5254
|
+
}
|
|
5255
|
+
return index;
|
|
5256
|
+
}
|
|
5257
|
+
onOutputItemAdded(raw) {
|
|
5258
|
+
const outputIndex = this.requireItemIndex(raw);
|
|
5259
|
+
const item = raw.item;
|
|
5260
|
+
if (!isRecord2(item)) {
|
|
5261
|
+
throw new ResponsesProtocolError(`response.output_item.added at index ${outputIndex} is missing the item.`);
|
|
5262
|
+
}
|
|
5263
|
+
if (this.items.has(outputIndex)) {
|
|
5264
|
+
throw new ResponsesProtocolError(`Responses stream reused output_index ${outputIndex}.`);
|
|
5265
|
+
}
|
|
5266
|
+
const itemId = typeof item.id === "string" ? item.id : "";
|
|
5267
|
+
if (item.type === "message") {
|
|
5268
|
+
this.items.set(outputIndex, { kind: "message", itemId, blocks: /* @__PURE__ */ new Map() });
|
|
5269
|
+
return this.ensureStarted();
|
|
5270
|
+
}
|
|
5271
|
+
if (item.type === "reasoning") {
|
|
5272
|
+
const block = { type: "thinking", thinking: "" };
|
|
5273
|
+
this.output.content.push(block);
|
|
5274
|
+
this.items.set(outputIndex, { kind: "reasoning", itemId, block, lastSummaryIndex: null });
|
|
5275
|
+
const startEvents = this.ensureStarted();
|
|
5276
|
+
return [
|
|
5277
|
+
...startEvents,
|
|
5278
|
+
{ type: "thinking_start", contentIndex: this.output.content.length - 1, partial: this.output }
|
|
5279
|
+
];
|
|
5280
|
+
}
|
|
5281
|
+
if (item.type === "function_call") {
|
|
5282
|
+
const callId = typeof item.call_id === "string" ? item.call_id : "";
|
|
5283
|
+
if (!callId) {
|
|
5284
|
+
throw new ResponsesProtocolError(`function_call output item at index ${outputIndex} is missing call_id.`);
|
|
5285
|
+
}
|
|
5286
|
+
const name = typeof item.name === "string" ? item.name : "";
|
|
5287
|
+
if (!name || !itemId) throw new ResponsesProtocolError("function_call requires name and item id.");
|
|
5288
|
+
const block = { type: "toolCall", id: callId, name, arguments: {} };
|
|
5289
|
+
this.output.content.push(block);
|
|
5290
|
+
const state = {
|
|
5291
|
+
kind: "function_call",
|
|
5292
|
+
itemId,
|
|
5293
|
+
block,
|
|
5294
|
+
partialArgs: "",
|
|
5295
|
+
finalArgs: null,
|
|
5296
|
+
completed: false,
|
|
5297
|
+
contentIndex: this.output.content.length - 1
|
|
5298
|
+
};
|
|
5299
|
+
this.items.set(outputIndex, state);
|
|
5300
|
+
this.toolCallStates.push(state);
|
|
5301
|
+
const startEvents = this.ensureStarted();
|
|
5302
|
+
return [
|
|
5303
|
+
...startEvents,
|
|
5304
|
+
{ type: "toolcall_start", contentIndex: state.contentIndex, partial: this.output }
|
|
5305
|
+
];
|
|
5306
|
+
}
|
|
5307
|
+
this.items.set(outputIndex, { kind: "ignored", itemType: String(item.type) });
|
|
5308
|
+
this.diagnostics.ignoredItemTypes.add(String(item.type));
|
|
5309
|
+
return [];
|
|
5310
|
+
}
|
|
5311
|
+
lookupItem(raw, kinds, label) {
|
|
5312
|
+
const outputIndex = this.requireItemIndex(raw);
|
|
5313
|
+
let state = this.items.get(outputIndex);
|
|
5314
|
+
if (!state || !kinds.includes(state.kind)) {
|
|
5315
|
+
throw new ResponsesProtocolError(
|
|
5316
|
+
`Responses event "${raw.type ?? label}" references ${label} output_index ${outputIndex} that was never added (or is of the wrong item type).`
|
|
5317
|
+
);
|
|
5318
|
+
}
|
|
5319
|
+
if (state.kind !== "ignored" && raw.item_id !== void 0 && raw.item_id !== state.itemId) throw new ResponsesProtocolError("Response item identity changed.");
|
|
5320
|
+
return { state, outputIndex };
|
|
5321
|
+
}
|
|
5322
|
+
onContentPartAdded(raw) {
|
|
5323
|
+
const part = raw.part;
|
|
5324
|
+
const partType = isRecord2(part) ? part.type : void 0;
|
|
5325
|
+
const kind = partType === "reasoning_text" ? "reasoning" : "message";
|
|
5326
|
+
const { state } = this.lookupItem(raw, [kind], kind);
|
|
5327
|
+
const partIndex = raw.content_index;
|
|
5328
|
+
if (typeof partIndex !== "number" || !Number.isInteger(partIndex) || partIndex < 0) {
|
|
5329
|
+
throw new ResponsesProtocolError("response.content_part.added is missing a valid content_index.");
|
|
5330
|
+
}
|
|
5331
|
+
if (state.kind !== "message") return [];
|
|
5332
|
+
if (state.blocks.has(partIndex)) {
|
|
5333
|
+
throw new ResponsesProtocolError(`Responses stream reused content_index ${partIndex} on one message item.`);
|
|
5334
|
+
}
|
|
5335
|
+
if (partType !== "output_text" && partType !== "refusal") {
|
|
5336
|
+
return [];
|
|
5337
|
+
}
|
|
5338
|
+
const block = { type: "text", text: "" };
|
|
5339
|
+
this.output.content.push(block);
|
|
5340
|
+
state.blocks.set(partIndex, { block, contentIndex: this.output.content.length - 1 });
|
|
5341
|
+
return [{ type: "text_start", contentIndex: this.output.content.length - 1, partial: this.output }];
|
|
5342
|
+
}
|
|
5343
|
+
messageBlockFor(raw) {
|
|
5344
|
+
const { state } = this.lookupItem(raw, ["message"], "message");
|
|
5345
|
+
if (state.kind !== "message") throw new ResponsesProtocolError("internal: expected message item");
|
|
5346
|
+
const partIndex = raw.content_index;
|
|
5347
|
+
if (typeof partIndex !== "number" || !Number.isInteger(partIndex) || partIndex < 0) {
|
|
5348
|
+
throw new ResponsesProtocolError(`Responses event "${raw.type}" is missing a valid content_index.`);
|
|
5349
|
+
}
|
|
5350
|
+
const entry = state.blocks.get(partIndex);
|
|
5351
|
+
if (!entry) {
|
|
5352
|
+
throw new ResponsesProtocolError(
|
|
5353
|
+
`Responses event "${raw.type}" references content_index ${partIndex} that was never added.`
|
|
5354
|
+
);
|
|
5355
|
+
}
|
|
5356
|
+
return entry;
|
|
5357
|
+
}
|
|
5358
|
+
appendTextDelta(raw, kind) {
|
|
5359
|
+
const delta = raw.delta;
|
|
5360
|
+
if (typeof delta !== "string" || delta.length === 0) return [];
|
|
5361
|
+
const entry = this.messageBlockFor(raw);
|
|
5362
|
+
entry.block.text += delta;
|
|
5363
|
+
return [{ type: "text_delta", contentIndex: entry.contentIndex, delta, partial: this.output }];
|
|
5364
|
+
}
|
|
5365
|
+
validateTextDone(raw) {
|
|
5366
|
+
this.messageBlockFor(raw);
|
|
5367
|
+
}
|
|
5368
|
+
appendReasoningDelta(raw) {
|
|
5369
|
+
const delta = raw.delta;
|
|
5370
|
+
if (typeof delta !== "string" || delta.length === 0) return [];
|
|
5371
|
+
const { state } = this.lookupItem(raw, ["reasoning"], "reasoning");
|
|
5372
|
+
if (state.kind !== "reasoning") return [];
|
|
5373
|
+
let text = delta;
|
|
5374
|
+
const summaryIndex = raw.summary_index;
|
|
5375
|
+
if (typeof summaryIndex === "number" && Number.isInteger(summaryIndex)) {
|
|
5376
|
+
if (state.lastSummaryIndex !== null && summaryIndex !== state.lastSummaryIndex) {
|
|
5377
|
+
text = `
|
|
5378
|
+
|
|
5379
|
+
${delta}`;
|
|
5380
|
+
}
|
|
5381
|
+
state.lastSummaryIndex = summaryIndex;
|
|
5382
|
+
}
|
|
5383
|
+
state.block.thinking += text;
|
|
5384
|
+
return [{ type: "thinking_delta", contentIndex: this.output.content.indexOf(state.block), delta: text, partial: this.output }];
|
|
5385
|
+
}
|
|
5386
|
+
appendFunctionCallArgsDelta(raw) {
|
|
5387
|
+
const delta = raw.delta ?? raw.arguments;
|
|
5388
|
+
if (typeof delta !== "string" || delta.length === 0) return [];
|
|
5389
|
+
const { state } = this.lookupItem(raw, ["function_call"], "function_call");
|
|
5390
|
+
if (state.kind !== "function_call") return [];
|
|
5391
|
+
state.partialArgs += delta;
|
|
5392
|
+
state.block.arguments = parseStreamingJson(state.partialArgs);
|
|
5393
|
+
return [{ type: "toolcall_delta", contentIndex: state.contentIndex, delta, partial: this.output }];
|
|
5394
|
+
}
|
|
5395
|
+
onFunctionCallArgsDone(raw) {
|
|
5396
|
+
const { state } = this.lookupItem(raw, ["function_call"], "function_call");
|
|
5397
|
+
if (state.kind !== "function_call") return;
|
|
5398
|
+
if (typeof raw.arguments === "string") {
|
|
5399
|
+
state.finalArgs = raw.arguments;
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
5402
|
+
onOutputItemDone(raw) {
|
|
5403
|
+
const outputIndex = this.requireItemIndex(raw);
|
|
5404
|
+
const item = raw.item;
|
|
5405
|
+
if (!isRecord2(item)) {
|
|
5406
|
+
throw new ResponsesProtocolError(`response.output_item.done at index ${outputIndex} is missing the item.`);
|
|
5407
|
+
}
|
|
5408
|
+
const state = this.items.get(outputIndex);
|
|
5409
|
+
if (!state) {
|
|
5410
|
+
throw new ResponsesProtocolError(`response.output_item.done references output_index ${outputIndex} that was never added.`);
|
|
5411
|
+
}
|
|
5412
|
+
if (state.kind !== "ignored" && (item.id !== state.itemId || item.type !== state.kind)) throw new ResponsesProtocolError("Response done item identity changed.");
|
|
5413
|
+
switch (state.kind) {
|
|
5414
|
+
case "message": {
|
|
5415
|
+
const events = [];
|
|
5416
|
+
for (const { block, contentIndex } of state.blocks.values()) {
|
|
5417
|
+
events.push({ type: "text_end", contentIndex, content: block.text, partial: this.output });
|
|
5418
|
+
}
|
|
5419
|
+
return events;
|
|
5420
|
+
}
|
|
5421
|
+
case "reasoning": {
|
|
5422
|
+
const events = [];
|
|
5423
|
+
const encrypted = typeof item.encrypted_content === "string" ? item.encrypted_content : null;
|
|
5424
|
+
const itemId = typeof item.id === "string" && item.id.length > 0 ? item.id : state.itemId;
|
|
5425
|
+
if (itemId) {
|
|
5426
|
+
state.block.thinkingSignature = JSON.stringify({ v: 1, id: itemId, encrypted_content: encrypted });
|
|
5427
|
+
}
|
|
5428
|
+
events.push({
|
|
5429
|
+
type: "thinking_end",
|
|
5430
|
+
contentIndex: this.output.content.indexOf(state.block),
|
|
5431
|
+
content: state.block.thinking,
|
|
5432
|
+
partial: this.output
|
|
5433
|
+
});
|
|
5434
|
+
return events;
|
|
5435
|
+
}
|
|
5436
|
+
case "function_call": {
|
|
5437
|
+
const finalText = typeof item.arguments === "string" && item.arguments.length > 0 ? item.arguments : state.finalArgs ?? state.partialArgs;
|
|
5438
|
+
if (typeof item.call_id === "string" && item.call_id.length > 0 && item.call_id !== state.block.id) {
|
|
5439
|
+
throw new ResponsesProtocolError(`function_call item changed call_id from "${state.block.id}" to "${item.call_id}".`);
|
|
5440
|
+
}
|
|
5441
|
+
if (typeof item.name === "string" && item.name.length > 0 && item.name !== state.block.name) {
|
|
5442
|
+
throw new ResponsesProtocolError(`function_call item changed name from "${state.block.name}" to "${item.name}".`);
|
|
5443
|
+
}
|
|
5444
|
+
state.completed = true;
|
|
5445
|
+
state.finalArgs = finalText;
|
|
5446
|
+
if (this.canParseArgs(state)) {
|
|
5447
|
+
return this.finalizeFunctionCall(state, finalText);
|
|
5448
|
+
}
|
|
5449
|
+
return [];
|
|
5450
|
+
}
|
|
5451
|
+
case "ignored":
|
|
5452
|
+
return [];
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
5455
|
+
finalizeFunctionCall(state, argsText) {
|
|
5456
|
+
const text = argsText.trim();
|
|
5457
|
+
let parsed;
|
|
5458
|
+
if (text.length === 0) {
|
|
5459
|
+
parsed = {};
|
|
5460
|
+
} else {
|
|
5461
|
+
try {
|
|
5462
|
+
const value = JSON.parse(text);
|
|
5463
|
+
if (!isRecord2(value)) {
|
|
5464
|
+
throw new ResponsesProtocolError(`function_call "${state.block.name || "unknown"}" arguments are not a JSON object.`);
|
|
5465
|
+
}
|
|
5466
|
+
parsed = value;
|
|
5467
|
+
} catch (error) {
|
|
5468
|
+
if (error instanceof ResponsesProtocolError) throw error;
|
|
5469
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5470
|
+
throw new ResponsesProtocolError(
|
|
5471
|
+
`function_call "${state.block.name || "unknown"}" returned incomplete or invalid JSON arguments: ${message}`
|
|
5472
|
+
);
|
|
5473
|
+
}
|
|
5474
|
+
}
|
|
5475
|
+
state.block.arguments = parsed;
|
|
5476
|
+
return [{ type: "toolcall_end", contentIndex: state.contentIndex, toolCall: state.block, partial: this.output }];
|
|
5477
|
+
}
|
|
5478
|
+
// ─── terminals ──────────────────────────────────────────────────────────
|
|
5479
|
+
requireTerminalResponse(raw) {
|
|
5480
|
+
const response = raw.response;
|
|
5481
|
+
const expected = raw.type.slice("response.".length);
|
|
5482
|
+
if (!isRecord2(response) || typeof response.id !== "string" || !response.id || response.status !== expected) {
|
|
5483
|
+
throw new ResponsesProtocolError(`Malformed ${raw.type}: requires response id and status ${expected}.`);
|
|
5484
|
+
}
|
|
5485
|
+
return response;
|
|
5486
|
+
}
|
|
5487
|
+
onTerminal(raw, type, reason = "stop", errorText) {
|
|
5488
|
+
this.diagnostics.terminalType = type;
|
|
5489
|
+
const response = type === "error" ? void 0 : this.requireTerminalResponse(raw);
|
|
5490
|
+
this.terminal = { reason, response, errorText };
|
|
5491
|
+
return this.closeResponse(type);
|
|
5492
|
+
}
|
|
5493
|
+
onIncomplete(raw) {
|
|
5494
|
+
this.diagnostics.terminalType = "response.incomplete";
|
|
5495
|
+
const response = this.requireTerminalResponse(raw);
|
|
5496
|
+
const reason = response?.incomplete_details?.reason;
|
|
5497
|
+
if (reason === "content_filter" || reason === "steered" || reason === void 0) {
|
|
5498
|
+
this.terminal = {
|
|
5499
|
+
reason: "error",
|
|
5500
|
+
response,
|
|
5501
|
+
errorText: reason === "steered" ? "Response ended incomplete with reason 'steered' but no steering was sent." : `Response ended incomplete${reason ? ` (${reason})` : " without a reason"}.`
|
|
5502
|
+
};
|
|
5503
|
+
return this.closeResponse("response.incomplete");
|
|
5504
|
+
}
|
|
5505
|
+
this.terminal = { reason: "length", response };
|
|
5506
|
+
return this.closeResponse("response.incomplete");
|
|
5507
|
+
}
|
|
5508
|
+
failedText(raw) {
|
|
5509
|
+
const response = isRecord2(raw.response) ? raw.response : void 0;
|
|
5510
|
+
const error = isRecord2(response?.error) ? response?.error : void 0;
|
|
5511
|
+
const message = typeof error?.message === "string" && error.message.length > 0 ? error.message : "Response failed";
|
|
5512
|
+
const code = typeof error?.code === "string" && error.code.length > 0 ? ` (code=${error.code})` : "";
|
|
5513
|
+
return `${message}${code}`;
|
|
5514
|
+
}
|
|
5515
|
+
/** Apply terminal semantics and produce the final event. */
|
|
5516
|
+
closeResponse(terminalType) {
|
|
5517
|
+
const terminal = this.terminal;
|
|
5518
|
+
const response = terminal.response;
|
|
5519
|
+
if (response && isRecord2(response.usage)) {
|
|
5520
|
+
this.output.usage = normalizeResponsesUsage(this.model, response.usage);
|
|
5521
|
+
this.output.usageReported = [response.usage.input_tokens, response.usage.output_tokens].every((value) => typeof value === "number" && Number.isFinite(value) && value >= 0);
|
|
5522
|
+
}
|
|
5523
|
+
if (terminal.reason === "error") {
|
|
5524
|
+
this.output.stopReason = "error";
|
|
5525
|
+
this.output.errorMessage = terminal.errorText ?? "Response failed";
|
|
5526
|
+
return [{ type: "error", reason: "error", error: this.output }];
|
|
5527
|
+
}
|
|
5528
|
+
let stopReason = terminal.reason === "length" ? "length" : "stop";
|
|
5529
|
+
if (this.toolCallStates.length > 0) {
|
|
5530
|
+
stopReason = "toolUse";
|
|
5531
|
+
}
|
|
5532
|
+
if (terminal.reason === "length") {
|
|
5533
|
+
const truncated = this.toolCallStates.filter((state) => !state.completed || !this.canParseArgs(state));
|
|
5534
|
+
if (truncated.length > 0) {
|
|
5535
|
+
const dropped = new Set(truncated.map((state) => state.block));
|
|
5536
|
+
this.output.content = this.output.content.filter(
|
|
5537
|
+
(block) => block.type !== "toolCall" || !dropped.has(block)
|
|
5538
|
+
);
|
|
5539
|
+
this.toolCallStates = this.toolCallStates.filter((state) => !dropped.has(state.block));
|
|
5540
|
+
const names = truncated.map((state) => `"${state.block.name || "unnamed"}"`).sort().join(", ");
|
|
5541
|
+
this.output.content.push({
|
|
5542
|
+
type: "text",
|
|
5543
|
+
text: `[output truncated: max_output_tokens cut ${truncated.length === 1 ? "a tool call" : `${truncated.length} tool calls`} mid-arguments (${names}); the call${truncated.length === 1 ? " was" : "s were"} dropped. Re-issue the call or continue with fewer/smaller requests.]`
|
|
5544
|
+
});
|
|
5545
|
+
if (this.toolCallStates.length === 0) {
|
|
5546
|
+
stopReason = "length";
|
|
5547
|
+
}
|
|
5548
|
+
}
|
|
5549
|
+
} else if (terminal.reason === "stop") {
|
|
5550
|
+
const brokenCalls = this.toolCallStates.filter((state) => !state.completed || !this.canParseArgs(state));
|
|
5551
|
+
if (brokenCalls.length > 0) {
|
|
5552
|
+
const first = brokenCalls[0];
|
|
5553
|
+
this.output.stopReason = "error";
|
|
5554
|
+
this.output.errorMessage = `function_call "${first.block.name || "unknown"}" returned incomplete or invalid JSON arguments on a completed response.`;
|
|
5555
|
+
return [{ type: "error", reason: "error", error: this.output }];
|
|
5556
|
+
}
|
|
5557
|
+
}
|
|
5558
|
+
if (stopReason === "toolUse" && this.toolCallStates.length === 0) {
|
|
5559
|
+
stopReason = "stop";
|
|
5560
|
+
}
|
|
5561
|
+
this.output.stopReason = stopReason;
|
|
5562
|
+
void terminalType;
|
|
5563
|
+
return [{ type: "done", reason: stopReason, message: this.output }];
|
|
5564
|
+
}
|
|
5565
|
+
canParseArgs(state) {
|
|
5566
|
+
const text = (state.finalArgs ?? state.partialArgs).trim();
|
|
5567
|
+
if (text.length === 0) return false;
|
|
5568
|
+
try {
|
|
5569
|
+
return isRecord2(JSON.parse(text));
|
|
5570
|
+
} catch {
|
|
5571
|
+
return false;
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5574
|
+
};
|
|
5575
|
+
|
|
5576
|
+
// ../../packages/ai/src/providers/responses/responses-diagnostics.ts
|
|
5577
|
+
function reportSubmission(options, body, details) {
|
|
5578
|
+
if (!options?.onTransportDiagnostic) return;
|
|
5579
|
+
let requestBytes = 0;
|
|
5580
|
+
for (const character of body) {
|
|
5581
|
+
const point = character.codePointAt(0);
|
|
5582
|
+
requestBytes += point <= 127 ? 1 : point <= 2047 ? 2 : point <= 65535 ? 3 : 4;
|
|
5583
|
+
}
|
|
5584
|
+
try {
|
|
5585
|
+
options.onTransportDiagnostic({ ...details, requestBytes });
|
|
5586
|
+
} catch {
|
|
5587
|
+
}
|
|
5588
|
+
}
|
|
5589
|
+
function reportLifecycle(options, event) {
|
|
5590
|
+
if (!options?.onTransportLifecycle) return;
|
|
5591
|
+
try {
|
|
5592
|
+
options.onTransportLifecycle({ ...event });
|
|
5593
|
+
} catch {
|
|
5594
|
+
}
|
|
5595
|
+
}
|
|
5596
|
+
var localRequestCounter = 0;
|
|
5597
|
+
function nextLocalRequestId(prefix = "req") {
|
|
5598
|
+
localRequestCounter += 1;
|
|
5599
|
+
return `${prefix}-${localRequestCounter}-${Math.random().toString(36).slice(2, 8)}`;
|
|
5600
|
+
}
|
|
5601
|
+
function monotonicNow() {
|
|
5602
|
+
const perf = globalThis.performance;
|
|
5603
|
+
return typeof perf?.now === "function" ? perf.now() : Date.now();
|
|
5604
|
+
}
|
|
5605
|
+
|
|
5606
|
+
// ../../packages/ai/src/providers/responses/responses-sse.ts
|
|
5607
|
+
var DEFAULT_RESPONSES_STREAM_IDLE_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
5608
|
+
var DEFAULT_RESPONSES_FIRST_BYTE_TIMEOUT_MS = 3 * 60 * 1e3;
|
|
5609
|
+
function parseSSEDataLine2(line) {
|
|
5610
|
+
const trimmed = line.trim();
|
|
5611
|
+
if (!trimmed || trimmed.startsWith(":")) return null;
|
|
5612
|
+
if (!trimmed.startsWith("data:")) return null;
|
|
5613
|
+
const data = trimmed.slice(5);
|
|
5614
|
+
return data.startsWith(" ") ? data.slice(1) : data;
|
|
5615
|
+
}
|
|
5616
|
+
function singleAttemptSupport() {
|
|
5617
|
+
let capabilities;
|
|
5618
|
+
try {
|
|
5619
|
+
capabilities = getHttpTransport().transportCapabilities;
|
|
5620
|
+
} catch {
|
|
5621
|
+
capabilities = void 0;
|
|
5622
|
+
}
|
|
5623
|
+
return capabilities?.singleAttempt === true ? "verified" : "unverified";
|
|
5624
|
+
}
|
|
5625
|
+
function assertSingleAttempt() {
|
|
5626
|
+
if (singleAttemptSupport() === "verified") return;
|
|
5627
|
+
throw new ResponsesProtocolError(
|
|
5628
|
+
"Responses SSE requires the platform HTTP adapter to declare transportCapabilities.singleAttempt; refusing to submit because a submitted generation must not be re-sent by the transport."
|
|
5629
|
+
);
|
|
5630
|
+
}
|
|
5631
|
+
function explicitBudget(value, field) {
|
|
5632
|
+
if (value === void 0) return void 0;
|
|
5633
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
5634
|
+
throw new ResponsesProtocolError(`Invalid ${field}: expected a finite positive number of milliseconds.`);
|
|
5635
|
+
}
|
|
5636
|
+
return value;
|
|
5637
|
+
}
|
|
5638
|
+
function resolveSSEBudgets(options) {
|
|
5639
|
+
const firstResponse = explicitBudget(options?.firstResponseTimeoutMs, "firstResponseTimeoutMs");
|
|
5640
|
+
const streamIdle = explicitBudget(options?.streamIdleTimeoutMs, "streamIdleTimeoutMs");
|
|
5641
|
+
const requestTimeoutMs = explicitBudget(options?.requestTimeoutMs, "requestTimeoutMs");
|
|
5642
|
+
explicitBudget(options?.connectionIdleTimeoutMs, "connectionIdleTimeoutMs");
|
|
5643
|
+
if (firstResponse !== void 0 || streamIdle !== void 0) {
|
|
5644
|
+
return {
|
|
5645
|
+
http: {
|
|
5646
|
+
firstByteTimeoutMs: firstResponse ?? DEFAULT_RESPONSES_FIRST_BYTE_TIMEOUT_MS,
|
|
5647
|
+
streamIdleTimeoutMs: streamIdle ?? DEFAULT_RESPONSES_STREAM_IDLE_TIMEOUT_MS
|
|
5648
|
+
},
|
|
5649
|
+
requestTimeoutMs
|
|
5650
|
+
};
|
|
5651
|
+
}
|
|
5652
|
+
if (options?.timeoutMs !== void 0) return { http: { timeoutMs: options.timeoutMs }, requestTimeoutMs };
|
|
5653
|
+
return {
|
|
5654
|
+
http: {
|
|
5655
|
+
firstByteTimeoutMs: DEFAULT_RESPONSES_FIRST_BYTE_TIMEOUT_MS,
|
|
5656
|
+
streamIdleTimeoutMs: DEFAULT_RESPONSES_STREAM_IDLE_TIMEOUT_MS
|
|
5657
|
+
},
|
|
5658
|
+
requestTimeoutMs
|
|
5659
|
+
};
|
|
5660
|
+
}
|
|
5661
|
+
function streamResponsesSSE(model, context, options) {
|
|
5662
|
+
const stream = new AssistantMessageEventStream();
|
|
5663
|
+
void (async () => {
|
|
5664
|
+
const reducer = new ResponsesEventReducer(model);
|
|
5665
|
+
const localRequestId = nextLocalRequestId("sse");
|
|
5666
|
+
const startedAt = monotonicNow();
|
|
5667
|
+
let lastReceiveAt = startedAt;
|
|
5668
|
+
let receivedMessageCount = 0;
|
|
5669
|
+
let sawModelContent = false;
|
|
5670
|
+
let submitted = false;
|
|
5671
|
+
let terminalAccepted = false;
|
|
5672
|
+
let phase = "request_start";
|
|
5673
|
+
let budgets = {};
|
|
5674
|
+
let totalTimer;
|
|
5675
|
+
let internalTimeout;
|
|
5676
|
+
let localFailure = false;
|
|
5677
|
+
const requestAbort = new AbortController();
|
|
5678
|
+
const onUserAbort = () => requestAbort.abort();
|
|
5679
|
+
const clearTotalTimer = () => {
|
|
5680
|
+
if (totalTimer !== void 0) {
|
|
5681
|
+
clearTimeout(totalTimer);
|
|
5682
|
+
totalTimer = void 0;
|
|
5683
|
+
}
|
|
5684
|
+
};
|
|
5685
|
+
const lifecycle = (extra = {}) => reportLifecycle(options, {
|
|
5686
|
+
...extra,
|
|
5687
|
+
transport: "sse",
|
|
5688
|
+
localRequestId,
|
|
5689
|
+
requestGeneration: 1,
|
|
5690
|
+
reusedConnection: false,
|
|
5691
|
+
phase,
|
|
5692
|
+
requestAgeMs: Math.round(monotonicNow() - startedAt),
|
|
5693
|
+
lastReceiveAgeMs: Math.round(monotonicNow() - lastReceiveAt),
|
|
5694
|
+
budgets,
|
|
5695
|
+
receivedMessageCount,
|
|
5696
|
+
sawModelContent,
|
|
5697
|
+
submissionAttempted: submitted,
|
|
5698
|
+
terminalAccepted,
|
|
5699
|
+
singleAttempt: singleAttemptSupport()
|
|
5700
|
+
});
|
|
5701
|
+
try {
|
|
5702
|
+
let resolved;
|
|
5703
|
+
try {
|
|
5704
|
+
resolved = resolveSSEBudgets(options);
|
|
5705
|
+
} catch (error) {
|
|
5706
|
+
localFailure = true;
|
|
5707
|
+
throw error;
|
|
5708
|
+
}
|
|
5709
|
+
budgets = {
|
|
5710
|
+
firstResponseTimeoutMs: resolved.http.firstByteTimeoutMs ?? resolved.http.timeoutMs,
|
|
5711
|
+
streamIdleTimeoutMs: resolved.http.streamIdleTimeoutMs ?? resolved.http.timeoutMs,
|
|
5712
|
+
requestTimeoutMs: resolved.requestTimeoutMs
|
|
5713
|
+
};
|
|
5714
|
+
options?.signal?.addEventListener("abort", onUserAbort, { once: true });
|
|
5715
|
+
if (options?.signal?.aborted) requestAbort.abort();
|
|
5716
|
+
if (resolved.requestTimeoutMs !== void 0) {
|
|
5717
|
+
totalTimer = setTimeout(() => {
|
|
5718
|
+
totalTimer = void 0;
|
|
5719
|
+
if (terminalAccepted || requestAbort.signal.aborted) return;
|
|
5720
|
+
internalTimeout = "request_total";
|
|
5721
|
+
phase = "timeout";
|
|
5722
|
+
lifecycle({
|
|
5723
|
+
timeoutKind: "request_total",
|
|
5724
|
+
terminalAccepted: false,
|
|
5725
|
+
cancelSource: "internal_timeout",
|
|
5726
|
+
retryAllowed: !submitted,
|
|
5727
|
+
retryDecision: submitted ? "not_retryable_after_submission" : "not_submitted"
|
|
5728
|
+
});
|
|
5729
|
+
requestAbort.abort();
|
|
5730
|
+
}, resolved.requestTimeoutMs);
|
|
5731
|
+
totalTimer.unref?.();
|
|
5732
|
+
}
|
|
5733
|
+
lifecycle();
|
|
5734
|
+
const apiKey = options?.apiKey || getEnvApiKey(model.provider, model.apiKeyEnv) || "";
|
|
5735
|
+
if (!apiKey) {
|
|
5736
|
+
throw new Error(`No API key for provider: ${model.provider}`);
|
|
5737
|
+
}
|
|
5738
|
+
try {
|
|
5739
|
+
assertSingleAttempt();
|
|
5740
|
+
} catch (error) {
|
|
5741
|
+
localFailure = true;
|
|
5742
|
+
throw error;
|
|
5743
|
+
}
|
|
5744
|
+
const payload = buildResponsesSSEPayload(model, context, options);
|
|
5745
|
+
options?.onPayload?.(payload);
|
|
5746
|
+
const headers = {
|
|
5747
|
+
"Content-Type": "application/json",
|
|
5748
|
+
Accept: "text/event-stream",
|
|
5749
|
+
Authorization: `Bearer ${apiKey}`,
|
|
5750
|
+
...model.headers || {},
|
|
5751
|
+
...options?.headers || {}
|
|
5752
|
+
};
|
|
5753
|
+
const body = JSON.stringify(payload);
|
|
5754
|
+
reportSubmission(options, body, { transport: "sse", reusedConnection: false, continuation: false, attempt: 1 });
|
|
5755
|
+
submitted = true;
|
|
5756
|
+
phase = "submission_attempted";
|
|
5757
|
+
lifecycle();
|
|
5758
|
+
const response = await httpRequest(`${model.baseUrl}/responses`, {
|
|
5759
|
+
method: "POST",
|
|
5760
|
+
headers,
|
|
5761
|
+
body,
|
|
5762
|
+
signal: requestAbort.signal,
|
|
5763
|
+
// The transport must not re-send a submitted generation.
|
|
5764
|
+
retryPolicy: "never",
|
|
5765
|
+
...resolved.http,
|
|
5766
|
+
label: `${model.provider}/${model.id}`
|
|
5767
|
+
});
|
|
5768
|
+
if (!response.ok) {
|
|
5769
|
+
const errorBody = await response.text().catch(() => "");
|
|
5770
|
+
throw new Error(`API error ${response.status}: ${errorBody}`);
|
|
5771
|
+
}
|
|
5772
|
+
if (!response.readSSELines) {
|
|
5773
|
+
throw new Error("SSE streaming not supported on this platform");
|
|
5774
|
+
}
|
|
5775
|
+
for await (const line of response.readSSELines(requestAbort.signal)) {
|
|
5776
|
+
receivedMessageCount += 1;
|
|
5777
|
+
lastReceiveAt = monotonicNow();
|
|
5778
|
+
const data = parseSSEDataLine2(line);
|
|
5779
|
+
if (data === null) continue;
|
|
5780
|
+
if (phase === "submission_attempted") {
|
|
5781
|
+
phase = "first_application_message";
|
|
5782
|
+
lifecycle();
|
|
5783
|
+
}
|
|
5784
|
+
if (data === "[DONE]") {
|
|
5785
|
+
continue;
|
|
5786
|
+
}
|
|
5787
|
+
let event;
|
|
5788
|
+
try {
|
|
5789
|
+
event = JSON.parse(data);
|
|
5790
|
+
} catch (error) {
|
|
5791
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5792
|
+
throw new ResponsesProtocolError(`Responses SSE stream returned malformed JSON: ${message}`);
|
|
5793
|
+
}
|
|
5794
|
+
if (!isResponsesEventLike(event)) {
|
|
5795
|
+
throw new ResponsesProtocolError("Responses SSE payload is not an event object with a string type.");
|
|
5796
|
+
}
|
|
5797
|
+
if (typeof event.type === "string" && (event.type.startsWith("response.output") || event.type.startsWith("response.content") || event.type.startsWith("response.reasoning"))) {
|
|
5798
|
+
sawModelContent = true;
|
|
5799
|
+
}
|
|
5800
|
+
for (const assistantEvent of reducer.feed(event)) {
|
|
5801
|
+
stream.push(assistantEvent);
|
|
5802
|
+
}
|
|
5803
|
+
if (reducer.isTerminal) {
|
|
5804
|
+
terminalAccepted = true;
|
|
5805
|
+
phase = "terminal_accepted";
|
|
5806
|
+
clearTotalTimer();
|
|
5807
|
+
lifecycle({ retryAllowed: reducer.message.retryable !== false, retryDecision: "terminal" });
|
|
5808
|
+
break;
|
|
5809
|
+
}
|
|
5810
|
+
}
|
|
5811
|
+
if (reducer.isTerminal) {
|
|
5812
|
+
stream.end();
|
|
5813
|
+
return;
|
|
5814
|
+
}
|
|
5815
|
+
if (requestAbort.signal.aborted) {
|
|
5816
|
+
throw new Error(internalTimeout ? `Responses request timeout (${internalTimeout})` : "Request was aborted");
|
|
5817
|
+
}
|
|
5818
|
+
throw reducer.finishWithoutTerminal();
|
|
5819
|
+
} catch (error) {
|
|
5820
|
+
if (reducer.isTerminal) {
|
|
5821
|
+
stream.end();
|
|
5822
|
+
return;
|
|
5823
|
+
}
|
|
5824
|
+
const message = reducer.message;
|
|
5825
|
+
const userAborted = options?.signal?.aborted === true;
|
|
5826
|
+
message.stopReason = userAborted ? "aborted" : "error";
|
|
5827
|
+
message.errorMessage = internalTimeout ? `Responses request timeout (${internalTimeout}) after ${Math.round(monotonicNow() - startedAt)}ms` : error instanceof Error ? error.message : JSON.stringify(error);
|
|
5828
|
+
if (submitted || localFailure) message.retryable = false;
|
|
5829
|
+
phase = "cleanup";
|
|
5830
|
+
lifecycle({
|
|
5831
|
+
timeoutKind: internalTimeout,
|
|
5832
|
+
retryAllowed: !submitted && !userAborted && !localFailure,
|
|
5833
|
+
retryDecision: submitted ? "not_retryable_after_submission" : localFailure ? "local_configuration_error" : "not_submitted",
|
|
5834
|
+
cancelSource: userAborted ? "user" : internalTimeout ? "internal_timeout" : "none",
|
|
5835
|
+
cleanupOutcome: "request_abandoned"
|
|
5836
|
+
});
|
|
5837
|
+
stream.push({ type: "error", reason: message.stopReason, error: message });
|
|
5838
|
+
stream.end();
|
|
5839
|
+
} finally {
|
|
5840
|
+
clearTotalTimer();
|
|
5841
|
+
options?.signal?.removeEventListener("abort", onUserAbort);
|
|
5842
|
+
}
|
|
5843
|
+
})();
|
|
5844
|
+
return stream;
|
|
5845
|
+
}
|
|
5846
|
+
|
|
5847
|
+
// ../../packages/ai/src/providers/responses/responses-ws.ts
|
|
5848
|
+
var owners = /* @__PURE__ */ new WeakMap();
|
|
5849
|
+
var MAX_ANCHOR_BYTES = 1024 * 1024;
|
|
5850
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
|
|
5851
|
+
var DEFAULT_FIRST_RESPONSE_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
5852
|
+
var DEFAULT_STREAM_IDLE_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
5853
|
+
var DEFAULT_CONNECTION_IDLE_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
5854
|
+
var ITERATOR_CLEANUP_TIMEOUT_MS = 1e3;
|
|
5855
|
+
function explicitBudget2(value, field) {
|
|
5856
|
+
if (value === void 0) return void 0;
|
|
5857
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
5858
|
+
throw new ResponsesProtocolError(`Invalid ${field}: expected a finite positive number of milliseconds.`);
|
|
5859
|
+
}
|
|
5860
|
+
return value;
|
|
5861
|
+
}
|
|
5862
|
+
function resolveBudgets(options) {
|
|
5863
|
+
const firstResponse = explicitBudget2(options?.firstResponseTimeoutMs, "firstResponseTimeoutMs");
|
|
5864
|
+
const streamIdle = explicitBudget2(options?.streamIdleTimeoutMs, "streamIdleTimeoutMs");
|
|
5865
|
+
const requestTimeout = explicitBudget2(options?.requestTimeoutMs, "requestTimeoutMs");
|
|
5866
|
+
const connectionIdle = explicitBudget2(options?.connectionIdleTimeoutMs, "connectionIdleTimeoutMs");
|
|
5867
|
+
const legacy = options?.timeoutMs !== void 0 && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : void 0;
|
|
5868
|
+
return {
|
|
5869
|
+
connectTimeoutMs: legacy ?? DEFAULT_CONNECT_TIMEOUT_MS,
|
|
5870
|
+
firstResponseTimeoutMs: firstResponse ?? legacy ?? DEFAULT_FIRST_RESPONSE_TIMEOUT_MS,
|
|
5871
|
+
streamIdleTimeoutMs: streamIdle ?? legacy ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS,
|
|
5872
|
+
requestTimeoutMs: requestTimeout,
|
|
5873
|
+
connectionIdleTimeoutMs: connectionIdle ?? DEFAULT_CONNECTION_IDLE_TIMEOUT_MS
|
|
5874
|
+
};
|
|
5875
|
+
}
|
|
5876
|
+
function disposeModelTransports(owner) {
|
|
5877
|
+
const state = owners.get(owner);
|
|
5878
|
+
if (!state) return;
|
|
5879
|
+
disposeState(owner, state);
|
|
5880
|
+
}
|
|
5881
|
+
function clearConnectionIdleTimer(state) {
|
|
5882
|
+
if (state.idleTimer !== void 0) {
|
|
5883
|
+
clearTimeout(state.idleTimer);
|
|
5884
|
+
state.idleTimer = void 0;
|
|
5885
|
+
}
|
|
5886
|
+
}
|
|
5887
|
+
function disposeState(owner, state) {
|
|
5888
|
+
if (owners.get(owner) === state) owners.delete(owner);
|
|
5889
|
+
clearConnectionIdleTimer(state);
|
|
5890
|
+
state.anchor = void 0;
|
|
5891
|
+
state.abort.abort();
|
|
5892
|
+
const connection = state.connection;
|
|
5893
|
+
state.connection = void 0;
|
|
5894
|
+
void connection?.close().catch(() => {
|
|
5895
|
+
});
|
|
5896
|
+
}
|
|
5897
|
+
function stateFor(owner) {
|
|
5898
|
+
let state = owners.get(owner);
|
|
5899
|
+
if (!state) {
|
|
5900
|
+
state = { busy: false, abort: new AbortController(), requestGeneration: 0, connectionGeneration: 0 };
|
|
5901
|
+
owners.set(owner, state);
|
|
5902
|
+
}
|
|
5903
|
+
return state;
|
|
5904
|
+
}
|
|
5905
|
+
function armConnectionIdleRecycle(state, connection, generation, timeoutMs) {
|
|
5906
|
+
clearConnectionIdleTimer(state);
|
|
5907
|
+
if (!(timeoutMs > 0)) return;
|
|
5908
|
+
const timer = setTimeout(() => {
|
|
5909
|
+
if (state.idleTimer !== timer) return;
|
|
5910
|
+
state.idleTimer = void 0;
|
|
5911
|
+
if (state.busy || state.connectionGeneration !== generation || state.connection !== connection) return;
|
|
5912
|
+
state.connection = void 0;
|
|
5913
|
+
state.anchor = void 0;
|
|
5914
|
+
state.identity = void 0;
|
|
5915
|
+
void connection.close().catch(() => {
|
|
5916
|
+
});
|
|
5917
|
+
}, timeoutMs);
|
|
5918
|
+
timer.unref?.();
|
|
5919
|
+
state.idleTimer = timer;
|
|
5920
|
+
}
|
|
5921
|
+
function websocketUrl(base) {
|
|
5922
|
+
const url = new URL(`${base.replace(/\/$/, "")}/responses`);
|
|
5923
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") throw new ResponsesProtocolError("Responses requires an HTTP(S) API root.");
|
|
5924
|
+
return `${url.protocol === "https:" ? "wss:" : "ws:"}${url.toString().slice(url.protocol.length)}`;
|
|
5925
|
+
}
|
|
5926
|
+
function streamResponsesWS(model, context, options) {
|
|
5927
|
+
const stream = new AssistantMessageEventStream();
|
|
5928
|
+
const owner = options?.transportOwner ?? {};
|
|
5929
|
+
const state = stateFor(owner);
|
|
5930
|
+
const reducer = new ResponsesEventReducer(model);
|
|
5931
|
+
if (state.busy) {
|
|
5932
|
+
reducer.message.stopReason = "error";
|
|
5933
|
+
reducer.message.errorMessage = "Responses owner already has an in-flight request.";
|
|
5934
|
+
stream.push({ type: "error", reason: "error", error: reducer.message });
|
|
5935
|
+
stream.end();
|
|
5936
|
+
return stream;
|
|
5937
|
+
}
|
|
5938
|
+
let budgets;
|
|
5939
|
+
try {
|
|
5940
|
+
budgets = resolveBudgets(options);
|
|
5941
|
+
} catch (error) {
|
|
5942
|
+
reducer.message.stopReason = "error";
|
|
5943
|
+
reducer.message.errorMessage = error instanceof Error ? error.message : String(error);
|
|
5944
|
+
reducer.message.retryable = false;
|
|
5945
|
+
stream.push({ type: "error", reason: "error", error: reducer.message });
|
|
5946
|
+
stream.end();
|
|
5947
|
+
return stream;
|
|
5948
|
+
}
|
|
5949
|
+
state.busy = true;
|
|
5950
|
+
const localRequestId = nextLocalRequestId("ws");
|
|
5951
|
+
const requestGeneration = ++state.requestGeneration;
|
|
5952
|
+
const startedAt = monotonicNow();
|
|
5953
|
+
let lastReceiveAt = startedAt;
|
|
5954
|
+
let receivedMessageCount = 0;
|
|
5955
|
+
let sawResponseCreated = false;
|
|
5956
|
+
let sawModelContent = false;
|
|
5957
|
+
let reusedConnection = false;
|
|
5958
|
+
let connectionGeneration = state.connectionGeneration;
|
|
5959
|
+
void (async () => {
|
|
5960
|
+
let sent = false;
|
|
5961
|
+
let finished = false;
|
|
5962
|
+
let terminalEvents = [];
|
|
5963
|
+
let fallback = false;
|
|
5964
|
+
let timedOut;
|
|
5965
|
+
let retryDecision = "none";
|
|
5966
|
+
let requestTimer;
|
|
5967
|
+
let totalTimer;
|
|
5968
|
+
let receiveCleanupFailed = false;
|
|
5969
|
+
let cleanupCancelSource;
|
|
5970
|
+
const requestAbort = new AbortController();
|
|
5971
|
+
const publish = (event) => {
|
|
5972
|
+
if (event.type === "done" || event.type === "error") terminalEvents.push(event);
|
|
5973
|
+
else stream.push(event);
|
|
5974
|
+
};
|
|
5975
|
+
const ageMs = () => Math.round(monotonicNow() - startedAt);
|
|
5976
|
+
const lastReceiveAgeMs = () => Math.round(monotonicNow() - lastReceiveAt);
|
|
5977
|
+
const lifecycle = (phase, extra = {}) => reportLifecycle(options, {
|
|
5978
|
+
...extra,
|
|
5979
|
+
transport: "websocket",
|
|
5980
|
+
localRequestId,
|
|
5981
|
+
requestGeneration,
|
|
5982
|
+
connectionGeneration,
|
|
5983
|
+
reusedConnection,
|
|
5984
|
+
phase,
|
|
5985
|
+
requestAgeMs: ageMs(),
|
|
5986
|
+
lastReceiveAgeMs: lastReceiveAgeMs(),
|
|
5987
|
+
budgets,
|
|
5988
|
+
receivedMessageCount,
|
|
5989
|
+
sawResponseCreated,
|
|
5990
|
+
sawModelContent,
|
|
5991
|
+
// The WS transport never re-sends a submitted frame (no hidden retry).
|
|
5992
|
+
singleAttempt: "verified"
|
|
5993
|
+
});
|
|
5994
|
+
const clearRequestTimers = () => {
|
|
5995
|
+
if (requestTimer !== void 0) {
|
|
5996
|
+
clearTimeout(requestTimer);
|
|
5997
|
+
requestTimer = void 0;
|
|
5998
|
+
}
|
|
5999
|
+
if (totalTimer !== void 0) {
|
|
6000
|
+
clearTimeout(totalTimer);
|
|
6001
|
+
totalTimer = void 0;
|
|
6002
|
+
}
|
|
6003
|
+
};
|
|
6004
|
+
const armTotalTimer = () => {
|
|
6005
|
+
if (budgets.requestTimeoutMs === void 0 || totalTimer !== void 0) return;
|
|
6006
|
+
const generation = requestGeneration;
|
|
6007
|
+
totalTimer = setTimeout(() => {
|
|
6008
|
+
totalTimer = void 0;
|
|
6009
|
+
if (generation !== requestGeneration || finished || requestAbort.signal.aborted) return;
|
|
6010
|
+
timedOut = "request_total";
|
|
6011
|
+
retryDecision = sent ? "not_retryable_after_submission" : "not_submitted";
|
|
6012
|
+
lifecycle("timeout", {
|
|
6013
|
+
timeoutKind: "request_total",
|
|
6014
|
+
terminalAccepted: false,
|
|
6015
|
+
cancelSource: "internal_timeout",
|
|
6016
|
+
retryAllowed: !sent,
|
|
6017
|
+
retryDecision,
|
|
6018
|
+
submissionAttempted: sent
|
|
6019
|
+
});
|
|
6020
|
+
requestAbort.abort();
|
|
6021
|
+
}, budgets.requestTimeoutMs);
|
|
6022
|
+
totalTimer.unref?.();
|
|
6023
|
+
};
|
|
6024
|
+
const remainingRequestBudget = () => {
|
|
6025
|
+
if (budgets.requestTimeoutMs === void 0) return void 0;
|
|
6026
|
+
return Math.max(0, Math.floor(budgets.requestTimeoutMs - ageMs()));
|
|
6027
|
+
};
|
|
6028
|
+
let fallbackAbort;
|
|
6029
|
+
let detachFallbackAbort;
|
|
6030
|
+
const fallbackSignal = () => {
|
|
6031
|
+
if (!fallbackAbort) {
|
|
6032
|
+
const controller = new AbortController();
|
|
6033
|
+
const onAbort = () => controller.abort();
|
|
6034
|
+
options?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
6035
|
+
state.abort.signal.addEventListener("abort", onAbort, { once: true });
|
|
6036
|
+
if (options?.signal?.aborted || state.abort.signal.aborted) controller.abort();
|
|
6037
|
+
fallbackAbort = controller;
|
|
6038
|
+
detachFallbackAbort = () => {
|
|
6039
|
+
options?.signal?.removeEventListener("abort", onAbort);
|
|
6040
|
+
state.abort.signal.removeEventListener("abort", onAbort);
|
|
6041
|
+
};
|
|
6042
|
+
}
|
|
6043
|
+
return fallbackAbort.signal;
|
|
6044
|
+
};
|
|
6045
|
+
const closeReceiveIterator = async (iterator) => {
|
|
6046
|
+
const returnFn = iterator.return;
|
|
6047
|
+
if (typeof returnFn !== "function") return;
|
|
6048
|
+
let timer;
|
|
6049
|
+
try {
|
|
6050
|
+
await Promise.race([
|
|
6051
|
+
Promise.resolve().then(() => returnFn.call(iterator)),
|
|
6052
|
+
new Promise((_, reject) => {
|
|
6053
|
+
timer = setTimeout(() => reject(new Error("bounded iterator cleanup")), ITERATOR_CLEANUP_TIMEOUT_MS);
|
|
6054
|
+
timer.unref?.();
|
|
6055
|
+
})
|
|
6056
|
+
]);
|
|
6057
|
+
} catch {
|
|
6058
|
+
receiveCleanupFailed = true;
|
|
6059
|
+
state.connection = void 0;
|
|
6060
|
+
state.anchor = void 0;
|
|
6061
|
+
requestAbort.abort();
|
|
6062
|
+
} finally {
|
|
6063
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
6064
|
+
}
|
|
6065
|
+
};
|
|
6066
|
+
const armPhaseTimer = (kind, timeoutMs) => {
|
|
6067
|
+
if (requestTimer !== void 0) {
|
|
6068
|
+
clearTimeout(requestTimer);
|
|
6069
|
+
requestTimer = void 0;
|
|
6070
|
+
}
|
|
6071
|
+
if (timeoutMs === void 0 || timeoutMs <= 0 || finished) return;
|
|
6072
|
+
const generation = requestGeneration;
|
|
6073
|
+
requestTimer = setTimeout(() => {
|
|
6074
|
+
requestTimer = void 0;
|
|
6075
|
+
if (generation !== requestGeneration || finished || requestAbort.signal.aborted) return;
|
|
6076
|
+
timedOut = kind;
|
|
6077
|
+
retryDecision = sent ? "not_retryable_after_submission" : "not_submitted";
|
|
6078
|
+
lifecycle("timeout", {
|
|
6079
|
+
timeoutKind: kind,
|
|
6080
|
+
terminalAccepted: false,
|
|
6081
|
+
cancelSource: "internal_timeout",
|
|
6082
|
+
retryAllowed: !sent,
|
|
6083
|
+
retryDecision,
|
|
6084
|
+
submissionAttempted: sent
|
|
6085
|
+
});
|
|
6086
|
+
requestAbort.abort();
|
|
6087
|
+
}, timeoutMs);
|
|
6088
|
+
requestTimer.unref?.();
|
|
6089
|
+
};
|
|
6090
|
+
const onOwnerAbort = () => requestAbort.abort();
|
|
6091
|
+
if (state.abort.signal.aborted) requestAbort.abort();
|
|
6092
|
+
else state.abort.signal.addEventListener("abort", onOwnerAbort, { once: true });
|
|
6093
|
+
const abort = () => disposeState(owner, state);
|
|
6094
|
+
options?.signal?.addEventListener("abort", abort, { once: true });
|
|
6095
|
+
const runSSEFallback = async () => {
|
|
6096
|
+
const remaining = remainingRequestBudget();
|
|
6097
|
+
if (remaining !== void 0 && remaining <= 0) {
|
|
6098
|
+
timedOut = "request_total";
|
|
6099
|
+
retryDecision = sent ? "not_retryable_after_submission" : "not_submitted";
|
|
6100
|
+
lifecycle("timeout", {
|
|
6101
|
+
timeoutKind: "request_total",
|
|
6102
|
+
terminalAccepted: false,
|
|
6103
|
+
cancelSource: "internal_timeout",
|
|
6104
|
+
retryAllowed: !sent,
|
|
6105
|
+
retryDecision,
|
|
6106
|
+
submissionAttempted: sent
|
|
6107
|
+
});
|
|
6108
|
+
throw new Error("Responses request timeout (request_total)");
|
|
6109
|
+
}
|
|
6110
|
+
clearRequestTimers();
|
|
6111
|
+
fallback = true;
|
|
6112
|
+
const fallbackOptions = {
|
|
6113
|
+
...options,
|
|
6114
|
+
signal: fallbackSignal(),
|
|
6115
|
+
...remaining !== void 0 ? { requestTimeoutMs: remaining } : {}
|
|
6116
|
+
};
|
|
6117
|
+
for await (const event of streamResponsesSSE(model, context, fallbackOptions)) publish(event);
|
|
6118
|
+
finished = true;
|
|
6119
|
+
};
|
|
6120
|
+
try {
|
|
6121
|
+
armTotalTimer();
|
|
6122
|
+
if (options?.signal?.aborted) {
|
|
6123
|
+
abort();
|
|
6124
|
+
throw new Error("Request aborted");
|
|
6125
|
+
}
|
|
6126
|
+
const key = options?.apiKey || getEnvApiKey(model.provider, model.apiKeyEnv);
|
|
6127
|
+
if (!key) throw new Error(`No API key for provider: ${model.provider}`);
|
|
6128
|
+
const payload = buildResponsesCreateEvent(model, context, options);
|
|
6129
|
+
const headers = { Authorization: `Bearer ${key}`, ...model.headers, ...options?.headers };
|
|
6130
|
+
const { input, ...settings } = payload;
|
|
6131
|
+
const identity = JSON.stringify([model.provider, model.api, model.id, model.baseUrl, headers, settings]);
|
|
6132
|
+
clearConnectionIdleTimer(state);
|
|
6133
|
+
if (state.identity !== identity || state.connection?.state() !== "open") {
|
|
6134
|
+
const stale = state.connection;
|
|
6135
|
+
state.connection = void 0;
|
|
6136
|
+
state.anchor = void 0;
|
|
6137
|
+
state.identity = identity;
|
|
6138
|
+
await stale?.close().catch(() => {
|
|
6139
|
+
});
|
|
6140
|
+
}
|
|
6141
|
+
reusedConnection = !!state.connection;
|
|
6142
|
+
if (state.abort.signal.aborted) throw new Error("Request aborted");
|
|
6143
|
+
lifecycle("request_start");
|
|
6144
|
+
const client = getWebSocketClient();
|
|
6145
|
+
if (!client) {
|
|
6146
|
+
if (options?.transport === "auto") {
|
|
6147
|
+
await runSSEFallback();
|
|
6148
|
+
return;
|
|
6149
|
+
}
|
|
6150
|
+
throw new Error("WebSocket transport is not available on this host.");
|
|
6151
|
+
}
|
|
6152
|
+
let connection = state.connection;
|
|
6153
|
+
if (!connection) {
|
|
6154
|
+
try {
|
|
6155
|
+
connection = await client.connect(websocketUrl(model.baseUrl), {
|
|
6156
|
+
headers,
|
|
6157
|
+
signal: requestAbort.signal,
|
|
6158
|
+
connectTimeoutMs: budgets.connectTimeoutMs
|
|
6159
|
+
});
|
|
6160
|
+
} catch (error) {
|
|
6161
|
+
if (error instanceof WebSocketTransportError && error.kind === "timeout") timedOut = "connect";
|
|
6162
|
+
if (options?.transport === "auto" && error instanceof WebSocketTransportError && error.kind === "handshake" && [404, 405, 426, 501].includes(error.status ?? 0) && !options.signal?.aborted && !state.abort.signal.aborted) {
|
|
6163
|
+
await runSSEFallback();
|
|
6164
|
+
return;
|
|
6165
|
+
}
|
|
6166
|
+
throw error;
|
|
6167
|
+
}
|
|
6168
|
+
state.connection = connection;
|
|
6169
|
+
connectionGeneration = ++state.connectionGeneration;
|
|
6170
|
+
if (state.abort.signal.aborted || requestAbort.signal.aborted) {
|
|
6171
|
+
state.connection = void 0;
|
|
6172
|
+
void connection.close().catch(() => {
|
|
6173
|
+
});
|
|
6174
|
+
throw new Error("Request aborted");
|
|
6175
|
+
}
|
|
6176
|
+
}
|
|
6177
|
+
const activeConnection = connection;
|
|
6178
|
+
const fullInput = input;
|
|
6179
|
+
const anchor = state.anchor;
|
|
6180
|
+
if (!options?.onPayload && model.compat?.responsesContinuation && anchor && fullInput.length > anchor.count && JSON.stringify(fullInput.slice(0, anchor.count)) === anchor.prefix) {
|
|
6181
|
+
payload.previous_response_id = anchor.id;
|
|
6182
|
+
payload.input = fullInput.slice(anchor.count);
|
|
6183
|
+
}
|
|
6184
|
+
state.anchor = void 0;
|
|
6185
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
6186
|
+
let rebuild = false;
|
|
6187
|
+
options?.onPayload?.(payload);
|
|
6188
|
+
if (state.abort.signal.aborted || requestAbort.signal.aborted) throw new Error("Request aborted");
|
|
6189
|
+
sent = true;
|
|
6190
|
+
const body = JSON.stringify(payload);
|
|
6191
|
+
reportSubmission(options, body, { transport: "websocket", reusedConnection: reusedConnection || attempt > 0, continuation: !!payload.previous_response_id, attempt: attempt + 1 });
|
|
6192
|
+
lifecycle("submission_attempted", { submissionAttempted: true });
|
|
6193
|
+
armPhaseTimer("first_response", budgets.firstResponseTimeoutMs);
|
|
6194
|
+
await activeConnection.send(body, { signal: requestAbort.signal });
|
|
6195
|
+
let started = false;
|
|
6196
|
+
let responseId;
|
|
6197
|
+
const receiveIterator = activeConnection.receive(requestAbort.signal)[Symbol.asyncIterator]();
|
|
6198
|
+
let receiveDone = false;
|
|
6199
|
+
try {
|
|
6200
|
+
while (true) {
|
|
6201
|
+
const step = await receiveIterator.next();
|
|
6202
|
+
if (step.done) {
|
|
6203
|
+
receiveDone = true;
|
|
6204
|
+
break;
|
|
6205
|
+
}
|
|
6206
|
+
const message = step.value;
|
|
6207
|
+
receivedMessageCount += 1;
|
|
6208
|
+
lastReceiveAt = monotonicNow();
|
|
6209
|
+
armPhaseTimer("stream_idle", budgets.streamIdleTimeoutMs);
|
|
6210
|
+
if (receivedMessageCount === 1) lifecycle("first_application_message");
|
|
6211
|
+
if (state.abort.signal.aborted || requestAbort.signal.aborted) {
|
|
6212
|
+
throw new Error(timedOut ? `Responses request timeout (${timedOut})` : "Request aborted");
|
|
6213
|
+
}
|
|
6214
|
+
if (message.isBinary) throw new ResponsesProtocolError("Responses requires JSON text messages.");
|
|
6215
|
+
const event = JSON.parse(message.data);
|
|
6216
|
+
if (!isRecord2(event)) throw new ResponsesProtocolError("Invalid Responses WebSocket event.");
|
|
6217
|
+
if (typeof event.type === "string") {
|
|
6218
|
+
if (event.type === "response.created") sawResponseCreated = true;
|
|
6219
|
+
else if (event.type.startsWith("response.output") || event.type.startsWith("response.content") || event.type.startsWith("response.reasoning")) sawModelContent = true;
|
|
6220
|
+
}
|
|
6221
|
+
if (!started && attempt === 0 && payload.previous_response_id && event.type === "error" && event.status === 400 && isRecord2(event.error) && event.error.code === "previous_response_not_found" && event.error.param === "previous_response_id") {
|
|
6222
|
+
delete payload.previous_response_id;
|
|
6223
|
+
payload.input = fullInput;
|
|
6224
|
+
rebuild = true;
|
|
6225
|
+
break;
|
|
6226
|
+
}
|
|
6227
|
+
if (!started && typeof event.type === "string" && event.type !== "error" && !event.type.startsWith("response.")) continue;
|
|
6228
|
+
if (!started && event.type !== "error") {
|
|
6229
|
+
if (event.type !== "response.created" || !isRecord2(event.response) || typeof event.response.id !== "string" || event.response.id === state.lastResponseId) {
|
|
6230
|
+
throw new ResponsesProtocolError("Expected a new response.created before output.");
|
|
6231
|
+
}
|
|
6232
|
+
started = true;
|
|
6233
|
+
responseId = event.response.id;
|
|
6234
|
+
}
|
|
6235
|
+
if (responseId && isRecord2(event.response) && event.response.id !== responseId) throw new ResponsesProtocolError("Response identity changed within a request.");
|
|
6236
|
+
const events = reducer.feed(event);
|
|
6237
|
+
if (reducer.isTerminal) {
|
|
6238
|
+
if (reducer.message.stopReason === "error") reducer.message.retryable = false;
|
|
6239
|
+
const response = reducer.terminalResponse;
|
|
6240
|
+
state.lastResponseId = response?.id;
|
|
6241
|
+
if (!options?.onPayload && response?.status === "completed" && reducer.message.stopReason !== "error") {
|
|
6242
|
+
const prefixItems = [...fullInput, ...buildResponsesOutput(reducer.message)];
|
|
6243
|
+
const prefix = JSON.stringify(prefixItems);
|
|
6244
|
+
if (prefix.length * 2 <= MAX_ANCHOR_BYTES) state.anchor = { id: response.id, prefix, count: prefixItems.length };
|
|
6245
|
+
}
|
|
6246
|
+
finished = true;
|
|
6247
|
+
clearRequestTimers();
|
|
6248
|
+
lifecycle("terminal_accepted", {
|
|
6249
|
+
terminalAccepted: true,
|
|
6250
|
+
retryAllowed: reducer.message.retryable !== false,
|
|
6251
|
+
retryDecision: "terminal"
|
|
6252
|
+
});
|
|
6253
|
+
for (const e of events) publish(e);
|
|
6254
|
+
break;
|
|
6255
|
+
}
|
|
6256
|
+
for (const e of events) publish(e);
|
|
6257
|
+
}
|
|
6258
|
+
} finally {
|
|
6259
|
+
if (!receiveDone) await closeReceiveIterator(receiveIterator);
|
|
6260
|
+
}
|
|
6261
|
+
if (rebuild) {
|
|
6262
|
+
retryDecision = "rebuild_previous_response";
|
|
6263
|
+
continue;
|
|
6264
|
+
}
|
|
6265
|
+
if (!reducer.isTerminal) throw reducer.finishWithoutTerminal();
|
|
6266
|
+
break;
|
|
6267
|
+
}
|
|
6268
|
+
} catch (error) {
|
|
6269
|
+
if (!finished) {
|
|
6270
|
+
const message = reducer.message;
|
|
6271
|
+
const userAborted = options?.signal?.aborted === true;
|
|
6272
|
+
const ownerDisposed = !userAborted && !timedOut && state.abort.signal.aborted;
|
|
6273
|
+
message.stopReason = userAborted || ownerDisposed ? "aborted" : "error";
|
|
6274
|
+
const cause = timedOut ? `Responses request timeout (${timedOut}) after ${ageMs()}ms` : error instanceof Error ? error.message : String(error);
|
|
6275
|
+
message.errorMessage = cause;
|
|
6276
|
+
if (sent) {
|
|
6277
|
+
message.retryable = false;
|
|
6278
|
+
retryDecision = "not_retryable_after_submission";
|
|
6279
|
+
}
|
|
6280
|
+
cleanupCancelSource = userAborted ? "user" : timedOut ? "internal_timeout" : ownerDisposed ? "owner_disposal" : "none";
|
|
6281
|
+
stream.push({ type: "error", reason: message.stopReason, error: message });
|
|
6282
|
+
}
|
|
6283
|
+
} finally {
|
|
6284
|
+
clearRequestTimers();
|
|
6285
|
+
detachFallbackAbort?.();
|
|
6286
|
+
state.abort.signal.removeEventListener("abort", onOwnerAbort);
|
|
6287
|
+
options?.signal?.removeEventListener("abort", abort);
|
|
6288
|
+
state.busy = false;
|
|
6289
|
+
const cancelSource = cleanupCancelSource ?? (options?.signal?.aborted ? "user" : timedOut ? "internal_timeout" : state.abort.signal.aborted ? "owner_disposal" : "none");
|
|
6290
|
+
const retain = finished && !fallback && !receiveCleanupFailed && !!options?.transportOwner && reducer.message.stopReason !== "error" && !timedOut && state.connection !== void 0 && !state.abort.signal.aborted;
|
|
6291
|
+
if (!retain) disposeState(owner, state);
|
|
6292
|
+
else if (state.connection) {
|
|
6293
|
+
armConnectionIdleRecycle(state, state.connection, connectionGeneration, budgets.connectionIdleTimeoutMs);
|
|
6294
|
+
}
|
|
6295
|
+
const cleanupOutcome = receiveCleanupFailed ? "cleanup_failed" : retain ? "connection_reused" : finished ? "connection_closed" : "request_abandoned";
|
|
6296
|
+
lifecycle("cleanup", {
|
|
6297
|
+
terminalAccepted: finished,
|
|
6298
|
+
timeoutKind: timedOut,
|
|
6299
|
+
submissionAttempted: sent,
|
|
6300
|
+
retryAllowed: !finished && !sent && reducer.message.stopReason !== "aborted" && reducer.message.retryable !== false,
|
|
6301
|
+
cancelSource,
|
|
6302
|
+
retryDecision,
|
|
6303
|
+
cleanupOutcome
|
|
6304
|
+
});
|
|
6305
|
+
for (const event of terminalEvents) stream.push(event);
|
|
6306
|
+
stream.end();
|
|
6307
|
+
}
|
|
6308
|
+
})();
|
|
6309
|
+
return stream;
|
|
6310
|
+
}
|
|
6311
|
+
|
|
6312
|
+
// ../../packages/ai/src/providers/openai-responses.ts
|
|
6313
|
+
var streamResponses = (model, context, options) => {
|
|
6314
|
+
const transport = options?.transport ?? model.transport ?? "sse";
|
|
6315
|
+
if (transport === "websocket" || transport === "auto") return streamResponsesWS(model, context, { ...options, transport });
|
|
6316
|
+
if (transport !== "sse") throw new Error(`Unsupported transport: ${transport}`);
|
|
6317
|
+
return streamResponsesSSE(model, context, options);
|
|
6318
|
+
};
|
|
6319
|
+
var streamSimpleResponses = (model, context, options) => {
|
|
6320
|
+
const apiKey = options?.apiKey || getEnvApiKey(model.provider, model.apiKeyEnv);
|
|
6321
|
+
if (!apiKey) {
|
|
6322
|
+
throw new Error(`No API key for provider: ${model.provider}`);
|
|
6323
|
+
}
|
|
6324
|
+
const base = buildBaseOptions(model, options, apiKey);
|
|
6325
|
+
const needsThinkingAllowance = Boolean(model.reasoning) && options?.reasoning !== void 0;
|
|
6326
|
+
let maxTokens = base.maxTokens;
|
|
6327
|
+
if (needsThinkingAllowance) {
|
|
6328
|
+
const adjusted = adjustMaxTokensForThinking(
|
|
6329
|
+
base.maxTokens || 0,
|
|
6330
|
+
model.maxTokens,
|
|
6331
|
+
options.reasoning,
|
|
6332
|
+
options?.thinkingBudgets
|
|
6333
|
+
);
|
|
6334
|
+
maxTokens = adjusted.maxTokens;
|
|
6335
|
+
}
|
|
6336
|
+
if (maxTokens === void 0) {
|
|
6337
|
+
maxTokens = DEFAULT_MAX_TOKENS;
|
|
6338
|
+
}
|
|
6339
|
+
const reasoningEffort = model.reasoning ? options?.reasoning : void 0;
|
|
6340
|
+
return streamResponses(model, context, {
|
|
6341
|
+
...base,
|
|
6342
|
+
maxTokens,
|
|
6343
|
+
// Responses accepts the full effort vocabulary verified in the SDK
|
|
6344
|
+
// ("none" excluded from Pie's ThinkingLevel); pass through unchanged.
|
|
6345
|
+
reasoningEffort
|
|
6346
|
+
});
|
|
6347
|
+
};
|
|
6348
|
+
|
|
4622
6349
|
// ../../packages/ai/src/stream.ts
|
|
4623
6350
|
function resolveApiProvider(api) {
|
|
4624
6351
|
const provider = getApiProvider(api);
|
|
@@ -8079,6 +9806,11 @@ registerApiProvider({
|
|
|
8079
9806
|
stream: streamAnthropic,
|
|
8080
9807
|
streamSimple: streamSimpleAnthropic
|
|
8081
9808
|
});
|
|
9809
|
+
registerApiProvider({
|
|
9810
|
+
api: "openai-responses",
|
|
9811
|
+
stream: streamResponses,
|
|
9812
|
+
streamSimple: streamSimpleResponses
|
|
9813
|
+
});
|
|
8082
9814
|
|
|
8083
9815
|
export {
|
|
8084
9816
|
hashText,
|
|
@@ -8097,6 +9829,7 @@ export {
|
|
|
8097
9829
|
getModelCacheCapability,
|
|
8098
9830
|
EMPTY_ASSISTANT_CONTENT_ERROR,
|
|
8099
9831
|
OPENAI_COMPAT_PROTOCOL_ERROR_CODE,
|
|
9832
|
+
disposeModelTransports,
|
|
8100
9833
|
streamSimple,
|
|
8101
9834
|
completeSimple,
|
|
8102
9835
|
MODEL_CLASS_FALLBACK_ORDER,
|