@cydm/pie 2.6.11 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -2
- 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 +4 -5
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/computer-use-axi/SKILL.md +103 -0
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
- package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-runtime.js} +754 -642
- package/dist/builtin/skills/computer-use-axi/package.json +11 -0
- package/dist/chunks/{chunk-ZVM234WE.js → chunk-6RBSTII7.js} +669 -594
- package/dist/chunks/{chunk-MA4CHFN4.js → chunk-IPNAFMOJ.js} +172 -230
- package/dist/chunks/{chunk-7B4IIBVS.js → chunk-R5I2QLF2.js} +1269 -4
- package/dist/chunks/{chunk-PAC62XU4.js → chunk-TWILEFLD.js} +25 -3
- package/dist/chunks/{src-HPIBCE2I.js → src-E7NCXMU5.js} +2 -2
- package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-BWBJTFNI.js} +1 -1
- package/dist/cli.js +1979 -384
- package/models.schema.json +52 -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,16 @@ 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 cacheWriteLongRate = model.cost.cacheWriteLong ?? model.cost.input * 2;
|
|
479
|
+
const cacheWriteLong = cacheWriteLongTokens > 0 ? cacheWriteLongRate / 1e6 * cacheWriteLongTokens : 0;
|
|
477
480
|
return {
|
|
478
481
|
input,
|
|
479
482
|
output,
|
|
480
483
|
cacheRead,
|
|
481
484
|
cacheWrite,
|
|
482
|
-
|
|
485
|
+
...cacheWriteLongTokens > 0 ? { cacheWriteLong } : {},
|
|
486
|
+
total: input + output + cacheRead + cacheWrite + cacheWriteLong
|
|
483
487
|
};
|
|
484
488
|
}
|
|
485
489
|
|
|
@@ -3047,6 +3051,227 @@ function deletePuertsDirectoryByEnumeration(path, recursive) {
|
|
|
3047
3051
|
warnPuertsDeletionShellsOnce(path);
|
|
3048
3052
|
}
|
|
3049
3053
|
|
|
3054
|
+
// ../../packages/platform/src/websocket-node.ts
|
|
3055
|
+
import { createRequire as createRequire5 } from "node:module";
|
|
3056
|
+
var require5 = createRequire5(import.meta.url);
|
|
3057
|
+
var failure = (kind, message) => new WebSocketTransportError(kind, message);
|
|
3058
|
+
var NodeWebSocketClient = class {
|
|
3059
|
+
async connect(url, options = {}) {
|
|
3060
|
+
if (options.signal?.aborted) throw failure("aborted", "Connection aborted");
|
|
3061
|
+
for (const field of ["maxMessageBytes", "maxBufferedBytes", "maxBufferedMessages", "connectTimeoutMs"]) {
|
|
3062
|
+
const value = options[field];
|
|
3063
|
+
if (value !== void 0 && (!Number.isFinite(value) || value <= 0)) throw failure("protocol", `Invalid ${field}`);
|
|
3064
|
+
}
|
|
3065
|
+
const WS = require5("ws");
|
|
3066
|
+
const socket = new WS(url, {
|
|
3067
|
+
headers: options.headers,
|
|
3068
|
+
maxPayload: options.maxMessageBytes ?? 32 * 1024 * 1024
|
|
3069
|
+
});
|
|
3070
|
+
return new Promise((resolve, reject) => {
|
|
3071
|
+
const connection = new NodeConnection(socket, options);
|
|
3072
|
+
const timeout = setTimeout(() => connection.fail(failure("timeout", "WebSocket handshake timed out")), options.connectTimeoutMs ?? 3e4);
|
|
3073
|
+
const cleanup = () => {
|
|
3074
|
+
clearTimeout(timeout);
|
|
3075
|
+
socket.off("open", opened);
|
|
3076
|
+
socket.off("error", error);
|
|
3077
|
+
socket.off("close", closed);
|
|
3078
|
+
socket.off("unexpected-response", refused);
|
|
3079
|
+
};
|
|
3080
|
+
const opened = () => {
|
|
3081
|
+
cleanup();
|
|
3082
|
+
resolve(connection);
|
|
3083
|
+
};
|
|
3084
|
+
const error = () => {
|
|
3085
|
+
cleanup();
|
|
3086
|
+
reject(connection.error ?? failure("handshake", "WebSocket connection failed"));
|
|
3087
|
+
};
|
|
3088
|
+
const closed = () => {
|
|
3089
|
+
cleanup();
|
|
3090
|
+
reject(connection.error ?? failure("handshake", "Connection closed before opening"));
|
|
3091
|
+
};
|
|
3092
|
+
const refused = (_, response) => {
|
|
3093
|
+
cleanup();
|
|
3094
|
+
const err = new WebSocketTransportError("handshake", "WebSocket upgrade refused", { status: response.statusCode });
|
|
3095
|
+
connection.fail(err);
|
|
3096
|
+
response.destroy();
|
|
3097
|
+
reject(err);
|
|
3098
|
+
};
|
|
3099
|
+
socket.once("open", opened);
|
|
3100
|
+
socket.once("error", error);
|
|
3101
|
+
socket.once("close", closed);
|
|
3102
|
+
socket.once("unexpected-response", refused);
|
|
3103
|
+
});
|
|
3104
|
+
}
|
|
3105
|
+
};
|
|
3106
|
+
var NodeConnection = class {
|
|
3107
|
+
constructor(socket, options) {
|
|
3108
|
+
this.socket = socket;
|
|
3109
|
+
this.options = options;
|
|
3110
|
+
this.closed = new Promise((resolve) => {
|
|
3111
|
+
this.resolveClosed = resolve;
|
|
3112
|
+
});
|
|
3113
|
+
socket.on("error", (error) => this.fail(failure(
|
|
3114
|
+
error.code === "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" ? "overflow" : this.opened ? "protocol" : "handshake",
|
|
3115
|
+
"WebSocket transport failed"
|
|
3116
|
+
)));
|
|
3117
|
+
socket.on("open", () => {
|
|
3118
|
+
this.opened = true;
|
|
3119
|
+
this.armIdle();
|
|
3120
|
+
});
|
|
3121
|
+
socket.on("message", (data, isBinary) => {
|
|
3122
|
+
if (this.ended || this.error) return;
|
|
3123
|
+
const buffer = Array.isArray(data) ? Buffer.concat(data) : Buffer.from(data);
|
|
3124
|
+
const bytes = buffer.byteLength;
|
|
3125
|
+
if (bytes > (options.maxMessageBytes ?? 32 * 1024 * 1024) || this.queue.length >= (options.maxBufferedMessages ?? 256) || this.queuedBytes + bytes > (options.maxBufferedBytes ?? 32 * 1024 * 1024)) {
|
|
3126
|
+
this.fail(failure("overflow", "Incoming WebSocket buffer exceeded"));
|
|
3127
|
+
return;
|
|
3128
|
+
}
|
|
3129
|
+
this.queue.push({ data: buffer.toString("utf8"), isBinary, bytes });
|
|
3130
|
+
this.queuedBytes += bytes;
|
|
3131
|
+
this.armIdle();
|
|
3132
|
+
this.wake?.();
|
|
3133
|
+
});
|
|
3134
|
+
socket.once("close", (code, reason) => {
|
|
3135
|
+
this.ended = true;
|
|
3136
|
+
clearTimeout(this.idle);
|
|
3137
|
+
clearTimeout(this.closeTimer);
|
|
3138
|
+
options.signal?.removeEventListener("abort", this.abort);
|
|
3139
|
+
this.resolveClosed({ code, reason: reason.toString() });
|
|
3140
|
+
this.wake?.();
|
|
3141
|
+
});
|
|
3142
|
+
options.signal?.addEventListener("abort", this.abort, { once: true });
|
|
3143
|
+
if (options.signal?.aborted) this.abort();
|
|
3144
|
+
}
|
|
3145
|
+
socket;
|
|
3146
|
+
options;
|
|
3147
|
+
closed;
|
|
3148
|
+
error;
|
|
3149
|
+
resolveClosed;
|
|
3150
|
+
queue = [];
|
|
3151
|
+
queuedBytes = 0;
|
|
3152
|
+
pendingBytes = 0;
|
|
3153
|
+
pendingMessages = 0;
|
|
3154
|
+
sending = Promise.resolve();
|
|
3155
|
+
wake;
|
|
3156
|
+
receiving = false;
|
|
3157
|
+
ended = false;
|
|
3158
|
+
opened = false;
|
|
3159
|
+
idle;
|
|
3160
|
+
closeTimer;
|
|
3161
|
+
abort = () => this.fail(failure("aborted", "Connection aborted"));
|
|
3162
|
+
fail(error) {
|
|
3163
|
+
if (this.ended || this.error) return;
|
|
3164
|
+
this.error = error;
|
|
3165
|
+
this.queue = [];
|
|
3166
|
+
this.queuedBytes = 0;
|
|
3167
|
+
clearTimeout(this.idle);
|
|
3168
|
+
this.socket.terminate();
|
|
3169
|
+
this.wake?.();
|
|
3170
|
+
}
|
|
3171
|
+
armIdle() {
|
|
3172
|
+
clearTimeout(this.idle);
|
|
3173
|
+
if (this.options.idleTimeoutMs && this.options.idleTimeoutMs > 0) {
|
|
3174
|
+
this.idle = setTimeout(() => this.fail(failure("timeout", "WebSocket idle timeout")), this.options.idleTimeoutMs);
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
async send(message, options) {
|
|
3178
|
+
const bytes = Buffer.byteLength(message);
|
|
3179
|
+
if (bytes > (this.options.maxMessageBytes ?? 32 * 1024 * 1024) || this.pendingBytes + bytes > (this.options.maxBufferedBytes ?? 32 * 1024 * 1024) || this.pendingMessages >= (this.options.maxBufferedMessages ?? 256)) {
|
|
3180
|
+
throw failure("overflow", "Outgoing WebSocket buffer exceeded");
|
|
3181
|
+
}
|
|
3182
|
+
const signal = options?.signal;
|
|
3183
|
+
if (signal?.aborted) {
|
|
3184
|
+
this.abort();
|
|
3185
|
+
throw failure("aborted", "Send aborted");
|
|
3186
|
+
}
|
|
3187
|
+
const abortSend = () => this.abort();
|
|
3188
|
+
signal?.addEventListener("abort", abortSend, { once: true });
|
|
3189
|
+
this.pendingBytes += bytes;
|
|
3190
|
+
this.pendingMessages++;
|
|
3191
|
+
const operation = this.sending.then(() => new Promise((resolve, reject) => {
|
|
3192
|
+
if (this.error) {
|
|
3193
|
+
reject(this.error);
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
3196
|
+
if (this.socket.readyState !== 1) {
|
|
3197
|
+
reject(failure("closed", "Connection is not open"));
|
|
3198
|
+
return;
|
|
3199
|
+
}
|
|
3200
|
+
this.socket.send(message, (error) => error ? reject(this.error ?? failure("closed", "Send failed")) : resolve());
|
|
3201
|
+
}));
|
|
3202
|
+
this.sending = operation.catch(() => {
|
|
3203
|
+
});
|
|
3204
|
+
try {
|
|
3205
|
+
await operation;
|
|
3206
|
+
} finally {
|
|
3207
|
+
this.pendingBytes -= bytes;
|
|
3208
|
+
this.pendingMessages--;
|
|
3209
|
+
signal?.removeEventListener("abort", abortSend);
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
async *receive(signal) {
|
|
3213
|
+
if (this.receiving) throw failure("protocol", "Only one receiver is permitted");
|
|
3214
|
+
this.receiving = true;
|
|
3215
|
+
const abortReceive = () => this.abort();
|
|
3216
|
+
signal?.addEventListener("abort", abortReceive, { once: true });
|
|
3217
|
+
try {
|
|
3218
|
+
while (true) {
|
|
3219
|
+
if (signal?.aborted) this.abort();
|
|
3220
|
+
if (this.error) throw this.error;
|
|
3221
|
+
const item = this.queue.shift();
|
|
3222
|
+
if (item) {
|
|
3223
|
+
this.queuedBytes -= item.bytes;
|
|
3224
|
+
yield item;
|
|
3225
|
+
continue;
|
|
3226
|
+
}
|
|
3227
|
+
if (this.ended) return;
|
|
3228
|
+
await new Promise((resolve) => {
|
|
3229
|
+
this.wake = resolve;
|
|
3230
|
+
});
|
|
3231
|
+
this.wake = void 0;
|
|
3232
|
+
}
|
|
3233
|
+
} finally {
|
|
3234
|
+
this.receiving = false;
|
|
3235
|
+
this.wake = void 0;
|
|
3236
|
+
signal?.removeEventListener("abort", abortReceive);
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
async close(code = 1e3, reason = "") {
|
|
3240
|
+
if (!this.ended && this.socket.readyState < 2) {
|
|
3241
|
+
this.socket.close(code, reason);
|
|
3242
|
+
this.closeTimer = setTimeout(() => this.socket.terminate(), 1e3);
|
|
3243
|
+
}
|
|
3244
|
+
await this.closed;
|
|
3245
|
+
}
|
|
3246
|
+
state() {
|
|
3247
|
+
return ["connecting", "open", "closing", "closed"][this.socket.readyState];
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
|
|
3251
|
+
// ../../packages/platform/src/websocket.ts
|
|
3252
|
+
var WebSocketTransportError = class extends Error {
|
|
3253
|
+
kind;
|
|
3254
|
+
/** HTTP status of a refused handshake, when the transport reports one. */
|
|
3255
|
+
status;
|
|
3256
|
+
/** Close code carried by the failure, when one exists. */
|
|
3257
|
+
closeCode;
|
|
3258
|
+
constructor(kind, message, details = {}) {
|
|
3259
|
+
super(`[websocket:${kind}] ${message}`);
|
|
3260
|
+
this.name = "WebSocketTransportError";
|
|
3261
|
+
this.kind = kind;
|
|
3262
|
+
if (details.status !== void 0) this.status = details.status;
|
|
3263
|
+
if (details.closeCode !== void 0) this.closeCode = details.closeCode;
|
|
3264
|
+
}
|
|
3265
|
+
};
|
|
3266
|
+
var webSocketClientInstance;
|
|
3267
|
+
function getNodeWebSocketClient() {
|
|
3268
|
+
return detectPlatform() === "node" ? new NodeWebSocketClient() : void 0;
|
|
3269
|
+
}
|
|
3270
|
+
function getWebSocketClient() {
|
|
3271
|
+
if (webSocketClientInstance === void 0) webSocketClientInstance = getNodeWebSocketClient() ?? null;
|
|
3272
|
+
return webSocketClientInstance ?? void 0;
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3050
3275
|
// ../../packages/platform/src/index.ts
|
|
3051
3276
|
var fileSystemInstance = null;
|
|
3052
3277
|
var httpClientInstance = null;
|
|
@@ -3123,6 +3348,8 @@ function buildBaseOptions(model, options, apiKey) {
|
|
|
3123
3348
|
const modelMaxTokens = positiveFiniteOrInfinity(model.maxTokens);
|
|
3124
3349
|
return {
|
|
3125
3350
|
temperature: options?.temperature,
|
|
3351
|
+
transport: options?.transport ?? model.transport,
|
|
3352
|
+
transportOwner: options?.transportOwner,
|
|
3126
3353
|
maxTokens: options?.maxTokens || Math.min(modelMaxTokens, DEFAULT_MAX_TOKENS),
|
|
3127
3354
|
signal: options?.signal,
|
|
3128
3355
|
apiKey: apiKey || options?.apiKey,
|
|
@@ -3131,6 +3358,7 @@ function buildBaseOptions(model, options, apiKey) {
|
|
|
3131
3358
|
headers: options?.headers,
|
|
3132
3359
|
timeoutMs: options?.timeoutMs,
|
|
3133
3360
|
onPayload: options?.onPayload,
|
|
3361
|
+
onTransportDiagnostic: options?.onTransportDiagnostic,
|
|
3134
3362
|
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
3135
3363
|
metadata: options?.metadata
|
|
3136
3364
|
};
|
|
@@ -3729,6 +3957,7 @@ function tryParseFinalToolArguments(partialArgs) {
|
|
|
3729
3957
|
}
|
|
3730
3958
|
}
|
|
3731
3959
|
var streamOpenAICompletions = (model, context, options) => {
|
|
3960
|
+
if ((options?.transport ?? model.transport) === "websocket") throw new Error(`API ${model.api} does not support WebSocket transport.`);
|
|
3732
3961
|
const stream = new AssistantMessageEventStream();
|
|
3733
3962
|
(async () => {
|
|
3734
3963
|
const output = {
|
|
@@ -4395,6 +4624,7 @@ function applyCacheBreakpoints(params, retention) {
|
|
|
4395
4624
|
}
|
|
4396
4625
|
}
|
|
4397
4626
|
var streamAnthropic = (model, context, options) => {
|
|
4627
|
+
if ((options?.transport ?? model.transport) === "websocket") throw new Error(`API ${model.api} does not support WebSocket transport.`);
|
|
4398
4628
|
const stream = new AssistantMessageEventStream();
|
|
4399
4629
|
(async () => {
|
|
4400
4630
|
const output = {
|
|
@@ -4470,7 +4700,12 @@ var streamAnthropic = (model, context, options) => {
|
|
|
4470
4700
|
output.usage.output = event.message.usage.output_tokens || 0;
|
|
4471
4701
|
output.usage.cacheRead = event.message.usage.cache_read_input_tokens || 0;
|
|
4472
4702
|
output.usage.cacheWrite = event.message.usage.cache_creation_input_tokens || 0;
|
|
4473
|
-
|
|
4703
|
+
const creation = event.message.usage.cache_creation;
|
|
4704
|
+
if (creation?.ephemeral_1h_input_tokens) {
|
|
4705
|
+
output.usage.cacheWriteLong = creation.ephemeral_1h_input_tokens;
|
|
4706
|
+
output.usage.cacheWrite = Math.max(0, output.usage.cacheWrite - creation.ephemeral_1h_input_tokens);
|
|
4707
|
+
}
|
|
4708
|
+
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite + (output.usage.cacheWriteLong ?? 0);
|
|
4474
4709
|
calculateCost(model, output.usage);
|
|
4475
4710
|
} else if (event.type === "content_block_start") {
|
|
4476
4711
|
if (event.content_block.type === "text") {
|
|
@@ -4578,9 +4813,15 @@ var streamAnthropic = (model, context, options) => {
|
|
|
4578
4813
|
if (event.usage.input_tokens != null) output.usage.input = event.usage.input_tokens;
|
|
4579
4814
|
if (event.usage.output_tokens != null) output.usage.output = event.usage.output_tokens;
|
|
4580
4815
|
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)
|
|
4816
|
+
if (event.usage.cache_creation_input_tokens != null) {
|
|
4582
4817
|
output.usage.cacheWrite = event.usage.cache_creation_input_tokens;
|
|
4583
|
-
|
|
4818
|
+
const creationDelta = event.usage.cache_creation;
|
|
4819
|
+
if (creationDelta?.ephemeral_1h_input_tokens) {
|
|
4820
|
+
output.usage.cacheWriteLong = creationDelta.ephemeral_1h_input_tokens;
|
|
4821
|
+
output.usage.cacheWrite = Math.max(0, output.usage.cacheWrite - creationDelta.ephemeral_1h_input_tokens);
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4824
|
+
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite + (output.usage.cacheWriteLong ?? 0);
|
|
4584
4825
|
calculateCost(model, output.usage);
|
|
4585
4826
|
}
|
|
4586
4827
|
}
|
|
@@ -4619,6 +4860,1024 @@ var streamSimpleAnthropic = (model, context, options) => {
|
|
|
4619
4860
|
});
|
|
4620
4861
|
};
|
|
4621
4862
|
|
|
4863
|
+
// ../../packages/ai/src/providers/responses/responses-compat.ts
|
|
4864
|
+
function getResponsesCompat(model) {
|
|
4865
|
+
const compat = model.compat ?? {};
|
|
4866
|
+
return {
|
|
4867
|
+
store: compat.store ?? false,
|
|
4868
|
+
supportsStore: compat.supportsStore ?? true,
|
|
4869
|
+
supportsReasoningEffort: compat.supportsReasoningEffort ?? true,
|
|
4870
|
+
supportsEncryptedReasoning: compat.supportsEncryptedReasoning ?? true,
|
|
4871
|
+
responsesContinuation: compat.responsesContinuation ?? false
|
|
4872
|
+
};
|
|
4873
|
+
}
|
|
4874
|
+
|
|
4875
|
+
// ../../packages/ai/src/providers/responses/responses-wire.ts
|
|
4876
|
+
var RESPONSES_PROTOCOL_ERROR_CODE = "responses_protocol_error";
|
|
4877
|
+
var ResponsesProtocolError = class extends Error {
|
|
4878
|
+
code = RESPONSES_PROTOCOL_ERROR_CODE;
|
|
4879
|
+
constructor(message) {
|
|
4880
|
+
super(`${RESPONSES_PROTOCOL_ERROR_CODE}: ${message}`);
|
|
4881
|
+
this.name = "ResponsesProtocolError";
|
|
4882
|
+
}
|
|
4883
|
+
};
|
|
4884
|
+
function isRecord2(value) {
|
|
4885
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4886
|
+
}
|
|
4887
|
+
function isResponsesEventLike(value) {
|
|
4888
|
+
return isRecord2(value) && typeof value.type === "string";
|
|
4889
|
+
}
|
|
4890
|
+
function formatResponsesErrorEvent(event) {
|
|
4891
|
+
const source = isRecord2(event.error) ? event.error : event;
|
|
4892
|
+
const message = typeof source.message === "string" && source.message.length > 0 ? source.message : "Responses stream returned an error";
|
|
4893
|
+
const metadata = [];
|
|
4894
|
+
if (typeof source.code === "string" && source.code.length > 0) {
|
|
4895
|
+
metadata.push(`code=${source.code}`);
|
|
4896
|
+
}
|
|
4897
|
+
if (typeof source.param === "string" && source.param.length > 0) {
|
|
4898
|
+
metadata.push(`param=${source.param}`);
|
|
4899
|
+
}
|
|
4900
|
+
if (typeof event.status === "number") {
|
|
4901
|
+
metadata.push(`status=${event.status}`);
|
|
4902
|
+
}
|
|
4903
|
+
return metadata.length > 0 ? `${message} (${metadata.join(", ")})` : message;
|
|
4904
|
+
}
|
|
4905
|
+
|
|
4906
|
+
// ../../packages/ai/src/providers/responses/responses-request.ts
|
|
4907
|
+
var MAX_REASONING_ENVELOPE_BYTES = 512 * 1024;
|
|
4908
|
+
function decodeReasoningEnvelope(signature) {
|
|
4909
|
+
if (typeof signature !== "string" || signature.length === 0 || signature.length > MAX_REASONING_ENVELOPE_BYTES) {
|
|
4910
|
+
return null;
|
|
4911
|
+
}
|
|
4912
|
+
let parsed;
|
|
4913
|
+
try {
|
|
4914
|
+
parsed = JSON.parse(signature);
|
|
4915
|
+
} catch {
|
|
4916
|
+
return null;
|
|
4917
|
+
}
|
|
4918
|
+
if (!isRecord2(parsed) || parsed.v !== 1 || typeof parsed.id !== "string" || parsed.id.length === 0) {
|
|
4919
|
+
return null;
|
|
4920
|
+
}
|
|
4921
|
+
const encrypted = parsed.encrypted_content;
|
|
4922
|
+
if (encrypted !== void 0 && encrypted !== null && typeof encrypted !== "string") {
|
|
4923
|
+
return null;
|
|
4924
|
+
}
|
|
4925
|
+
return { v: 1, id: parsed.id, encrypted_content: encrypted };
|
|
4926
|
+
}
|
|
4927
|
+
function buildResponsesInput(model, context) {
|
|
4928
|
+
const items = [];
|
|
4929
|
+
const isSameModel = (msg) => msg.provider === model.provider && msg.api === model.api && msg.model === model.id;
|
|
4930
|
+
const transformed = transformMessages(context.messages, model);
|
|
4931
|
+
for (const msg of transformed) {
|
|
4932
|
+
if (msg.role === "user") {
|
|
4933
|
+
items.push(encodeUserMessage(msg.content, model));
|
|
4934
|
+
} else if (msg.role === "assistant") {
|
|
4935
|
+
encodeAssistantMessage(msg, isSameModel, items);
|
|
4936
|
+
} else if (msg.role === "toolResult") {
|
|
4937
|
+
items.push(encodeToolResult(msg, model));
|
|
4938
|
+
}
|
|
4939
|
+
}
|
|
4940
|
+
return items;
|
|
4941
|
+
}
|
|
4942
|
+
function encodeUserMessage(content, model) {
|
|
4943
|
+
if (typeof content === "string") {
|
|
4944
|
+
return { role: "user", type: "message", content };
|
|
4945
|
+
}
|
|
4946
|
+
const parts = [];
|
|
4947
|
+
for (const block of content) {
|
|
4948
|
+
parts.push(...encodeUserContentBlock(block, model));
|
|
4949
|
+
}
|
|
4950
|
+
if (parts.length === 0) {
|
|
4951
|
+
return { role: "user", type: "message", content: "" };
|
|
4952
|
+
}
|
|
4953
|
+
return { role: "user", type: "message", content: parts };
|
|
4954
|
+
}
|
|
4955
|
+
function encodeUserContentBlock(block, model) {
|
|
4956
|
+
const modality = block.type === "fileRef" ? block.modality : block.type;
|
|
4957
|
+
if (modality !== "text" && !model.input.includes(modality)) {
|
|
4958
|
+
throw new ResponsesProtocolError(`Current model does not support ${modality} input.`);
|
|
4959
|
+
}
|
|
4960
|
+
switch (block.type) {
|
|
4961
|
+
case "text":
|
|
4962
|
+
return [{ type: "input_text", text: block.text }];
|
|
4963
|
+
case "image":
|
|
4964
|
+
return [{ type: "input_image", image_url: `data:${block.mimeType};base64,${block.data}` }];
|
|
4965
|
+
case "video":
|
|
4966
|
+
case "audio":
|
|
4967
|
+
throw new ResponsesProtocolError(`Responses ${block.type} input is not supported by this provider.`);
|
|
4968
|
+
case "fileRef": {
|
|
4969
|
+
const ref = block;
|
|
4970
|
+
if (ref.modality === "image") {
|
|
4971
|
+
return [{ type: "input_image", image_url: ref.url }];
|
|
4972
|
+
}
|
|
4973
|
+
throw new ResponsesProtocolError(`Responses ${ref.modality} file references are not supported by this provider.`);
|
|
4974
|
+
}
|
|
4975
|
+
default:
|
|
4976
|
+
throw new ResponsesProtocolError("Unsupported Responses content block.");
|
|
4977
|
+
}
|
|
4978
|
+
}
|
|
4979
|
+
function encodeAssistantMessage(msg, isSameModel, items) {
|
|
4980
|
+
for (const block of msg.content) {
|
|
4981
|
+
if (block.type === "thinking") {
|
|
4982
|
+
const thinking = block;
|
|
4983
|
+
if (isSameModel(msg)) {
|
|
4984
|
+
const envelope = decodeReasoningEnvelope(thinking.thinkingSignature);
|
|
4985
|
+
if (thinking.thinkingSignature && !envelope) {
|
|
4986
|
+
throw new ResponsesProtocolError("Invalid Responses reasoning signature.");
|
|
4987
|
+
}
|
|
4988
|
+
if (envelope) {
|
|
4989
|
+
items.push({
|
|
4990
|
+
type: "reasoning",
|
|
4991
|
+
id: envelope.id,
|
|
4992
|
+
summary: thinking.thinking.trim() ? [{ type: "summary_text", text: thinking.thinking }] : [],
|
|
4993
|
+
...envelope.encrypted_content ? { encrypted_content: envelope.encrypted_content } : {}
|
|
4994
|
+
});
|
|
4995
|
+
continue;
|
|
4996
|
+
}
|
|
4997
|
+
}
|
|
4998
|
+
if (thinking.thinking && thinking.thinking.trim().length > 0) {
|
|
4999
|
+
items.push({ role: "assistant", type: "message", content: thinking.thinking });
|
|
5000
|
+
}
|
|
5001
|
+
continue;
|
|
5002
|
+
}
|
|
5003
|
+
if (block.type === "text") {
|
|
5004
|
+
const text = block;
|
|
5005
|
+
if (text.text && text.text.trim().length > 0) {
|
|
5006
|
+
items.push({ role: "assistant", type: "message", content: text.text });
|
|
5007
|
+
}
|
|
5008
|
+
continue;
|
|
5009
|
+
}
|
|
5010
|
+
if (block.type === "toolCall") {
|
|
5011
|
+
const call = block;
|
|
5012
|
+
items.push({
|
|
5013
|
+
type: "function_call",
|
|
5014
|
+
call_id: call.id,
|
|
5015
|
+
name: call.name,
|
|
5016
|
+
arguments: JSON.stringify(call.arguments ?? {})
|
|
5017
|
+
});
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
}
|
|
5021
|
+
function buildResponsesOutput(message) {
|
|
5022
|
+
const items = [];
|
|
5023
|
+
encodeAssistantMessage(message, () => true, items);
|
|
5024
|
+
return items;
|
|
5025
|
+
}
|
|
5026
|
+
function encodeToolResult(msg, model) {
|
|
5027
|
+
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));
|
|
5028
|
+
return { type: "function_call_output", call_id: msg.toolCallId, output };
|
|
5029
|
+
}
|
|
5030
|
+
function encodeTools(tools) {
|
|
5031
|
+
return tools.map((tool) => ({
|
|
5032
|
+
type: "function",
|
|
5033
|
+
name: tool.name,
|
|
5034
|
+
description: tool.description,
|
|
5035
|
+
parameters: tool.parameters ?? { type: "object", properties: {} },
|
|
5036
|
+
strict: false
|
|
5037
|
+
}));
|
|
5038
|
+
}
|
|
5039
|
+
function buildResponsesRequest(model, context, options, compat = getResponsesCompat(model)) {
|
|
5040
|
+
const params = {
|
|
5041
|
+
model: model.id,
|
|
5042
|
+
input: buildResponsesInput(model, context)
|
|
5043
|
+
};
|
|
5044
|
+
if (context.systemPrompt !== void 0 && context.systemPrompt !== null && context.systemPrompt.length > 0) {
|
|
5045
|
+
params.instructions = context.systemPrompt;
|
|
5046
|
+
}
|
|
5047
|
+
if (compat.supportsStore) {
|
|
5048
|
+
params.store = compat.store;
|
|
5049
|
+
}
|
|
5050
|
+
if (options?.maxTokens !== void 0 && options.maxTokens > 0) {
|
|
5051
|
+
params.max_output_tokens = options.maxTokens;
|
|
5052
|
+
}
|
|
5053
|
+
if (options?.temperature !== void 0) params.temperature = options.temperature;
|
|
5054
|
+
if (options?.topP !== void 0) params.top_p = options.topP;
|
|
5055
|
+
if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {
|
|
5056
|
+
params.reasoning = { effort: options.reasoningEffort };
|
|
5057
|
+
}
|
|
5058
|
+
if (compat.supportsEncryptedReasoning && model.reasoning) {
|
|
5059
|
+
params.include = ["reasoning.encrypted_content"];
|
|
5060
|
+
}
|
|
5061
|
+
if (context.tools && context.tools.length > 0) {
|
|
5062
|
+
params.tools = encodeTools(context.tools);
|
|
5063
|
+
params.parallel_tool_calls = true;
|
|
5064
|
+
}
|
|
5065
|
+
if (options?.toolChoice !== void 0) {
|
|
5066
|
+
params.tool_choice = options.toolChoice === "required" ? "required" : options.toolChoice;
|
|
5067
|
+
}
|
|
5068
|
+
return params;
|
|
5069
|
+
}
|
|
5070
|
+
function buildResponsesSSEPayload(model, context, options) {
|
|
5071
|
+
return { ...buildResponsesRequest(model, context, options), stream: true };
|
|
5072
|
+
}
|
|
5073
|
+
function buildResponsesCreateEvent(model, context, options) {
|
|
5074
|
+
const params = buildResponsesRequest(model, context, options);
|
|
5075
|
+
delete params.stream;
|
|
5076
|
+
return { type: "response.create", ...params };
|
|
5077
|
+
}
|
|
5078
|
+
|
|
5079
|
+
// ../../packages/ai/src/providers/responses/responses-usage.ts
|
|
5080
|
+
function tokenCount(value) {
|
|
5081
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
|
|
5082
|
+
return Math.floor(value);
|
|
5083
|
+
}
|
|
5084
|
+
function normalizeResponsesUsage(model, usage) {
|
|
5085
|
+
const inputTokens = tokenCount(usage?.input_tokens);
|
|
5086
|
+
const cachedTokens = tokenCount(usage?.input_tokens_details?.cached_tokens) ?? 0;
|
|
5087
|
+
const cacheWriteTokens = tokenCount(usage?.input_tokens_details?.cache_write_tokens) ?? 0;
|
|
5088
|
+
const outputTokens = tokenCount(usage?.output_tokens);
|
|
5089
|
+
const reasoningTokens = tokenCount(usage?.output_tokens_details?.reasoning_tokens);
|
|
5090
|
+
const totalTokens = tokenCount(usage?.total_tokens);
|
|
5091
|
+
const input = inputTokens ?? (totalTokens !== void 0 && outputTokens !== void 0 ? Math.max(cachedTokens + cacheWriteTokens, totalTokens - outputTokens) : cachedTokens + cacheWriteTokens);
|
|
5092
|
+
const output = outputTokens ?? (totalTokens !== void 0 ? Math.max(reasoningTokens ?? 0, totalTokens - input) : reasoningTokens ?? 0);
|
|
5093
|
+
const cacheRead = Math.min(cachedTokens, input);
|
|
5094
|
+
const cacheWrite = Math.min(cacheWriteTokens, input - cacheRead);
|
|
5095
|
+
const inputExclusive = input - cacheRead - cacheWrite;
|
|
5096
|
+
const partitionTotal = input + output;
|
|
5097
|
+
const base = {
|
|
5098
|
+
input: inputExclusive,
|
|
5099
|
+
output,
|
|
5100
|
+
cacheRead,
|
|
5101
|
+
cacheWrite,
|
|
5102
|
+
totalTokens: Math.max(totalTokens ?? 0, partitionTotal)
|
|
5103
|
+
};
|
|
5104
|
+
return { ...base, cost: calculateCost(model, base) };
|
|
5105
|
+
}
|
|
5106
|
+
|
|
5107
|
+
// ../../packages/ai/src/providers/responses/responses-events.ts
|
|
5108
|
+
var ResponsesEventReducer = class {
|
|
5109
|
+
output;
|
|
5110
|
+
model;
|
|
5111
|
+
started = false;
|
|
5112
|
+
terminal = null;
|
|
5113
|
+
items = /* @__PURE__ */ new Map();
|
|
5114
|
+
toolCallStates = [];
|
|
5115
|
+
diagnostics = { unknownEventTypes: /* @__PURE__ */ new Set(), ignoredItemTypes: /* @__PURE__ */ new Set(), terminalType: null };
|
|
5116
|
+
constructor(model) {
|
|
5117
|
+
this.model = model;
|
|
5118
|
+
this.output = {
|
|
5119
|
+
role: "assistant",
|
|
5120
|
+
content: [],
|
|
5121
|
+
api: model.api,
|
|
5122
|
+
provider: model.provider,
|
|
5123
|
+
model: model.id,
|
|
5124
|
+
usageReported: false,
|
|
5125
|
+
usage: {
|
|
5126
|
+
input: 0,
|
|
5127
|
+
output: 0,
|
|
5128
|
+
cacheRead: 0,
|
|
5129
|
+
cacheWrite: 0,
|
|
5130
|
+
totalTokens: 0,
|
|
5131
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
5132
|
+
},
|
|
5133
|
+
stopReason: "stop",
|
|
5134
|
+
timestamp: Date.now()
|
|
5135
|
+
};
|
|
5136
|
+
}
|
|
5137
|
+
get message() {
|
|
5138
|
+
return this.output;
|
|
5139
|
+
}
|
|
5140
|
+
get isTerminal() {
|
|
5141
|
+
return this.terminal !== null;
|
|
5142
|
+
}
|
|
5143
|
+
/** Terminal response object (present on completed/incomplete/failed). */
|
|
5144
|
+
get terminalResponse() {
|
|
5145
|
+
return this.terminal?.response;
|
|
5146
|
+
}
|
|
5147
|
+
/** Feed one raw wire event; returns the AssistantMessageEvents to emit. */
|
|
5148
|
+
feed(raw) {
|
|
5149
|
+
const events = [];
|
|
5150
|
+
if (!isResponsesEventLike(raw)) {
|
|
5151
|
+
throw new ResponsesProtocolError("Responses stream returned an event without a string type.");
|
|
5152
|
+
}
|
|
5153
|
+
if (this.terminal) return events;
|
|
5154
|
+
switch (raw.type) {
|
|
5155
|
+
case "response.created":
|
|
5156
|
+
case "response.in_progress":
|
|
5157
|
+
case "response.queued":
|
|
5158
|
+
if (!this.started) {
|
|
5159
|
+
this.started = true;
|
|
5160
|
+
events.push({ type: "start", partial: this.output });
|
|
5161
|
+
}
|
|
5162
|
+
break;
|
|
5163
|
+
case "response.output_item.added":
|
|
5164
|
+
events.push(...this.onOutputItemAdded(raw));
|
|
5165
|
+
break;
|
|
5166
|
+
case "response.output_item.done":
|
|
5167
|
+
events.push(...this.onOutputItemDone(raw));
|
|
5168
|
+
break;
|
|
5169
|
+
case "response.content_part.added":
|
|
5170
|
+
events.push(...this.onContentPartAdded(raw));
|
|
5171
|
+
break;
|
|
5172
|
+
case "response.content_part.done":
|
|
5173
|
+
break;
|
|
5174
|
+
case "response.output_text.delta":
|
|
5175
|
+
events.push(...this.appendTextDelta(raw, "text"));
|
|
5176
|
+
break;
|
|
5177
|
+
case "response.output_text.done":
|
|
5178
|
+
this.validateTextDone(raw);
|
|
5179
|
+
break;
|
|
5180
|
+
case "response.refusal.delta":
|
|
5181
|
+
events.push(...this.appendTextDelta(raw, "refusal"));
|
|
5182
|
+
break;
|
|
5183
|
+
case "response.refusal.done":
|
|
5184
|
+
break;
|
|
5185
|
+
case "response.reasoning_summary_text.delta":
|
|
5186
|
+
case "response.reasoning_text.delta":
|
|
5187
|
+
events.push(...this.appendReasoningDelta(raw));
|
|
5188
|
+
break;
|
|
5189
|
+
case "response.reasoning_summary_text.done":
|
|
5190
|
+
case "response.reasoning_text.done":
|
|
5191
|
+
break;
|
|
5192
|
+
case "response.reasoning_summary_part.added":
|
|
5193
|
+
case "response.reasoning_summary_part.done":
|
|
5194
|
+
break;
|
|
5195
|
+
case "response.function_call_arguments.delta":
|
|
5196
|
+
events.push(...this.appendFunctionCallArgsDelta(raw));
|
|
5197
|
+
break;
|
|
5198
|
+
case "response.function_call_arguments.done":
|
|
5199
|
+
this.onFunctionCallArgsDone(raw);
|
|
5200
|
+
break;
|
|
5201
|
+
case "response.completed":
|
|
5202
|
+
events.push(...this.onTerminal(raw, "response.completed"));
|
|
5203
|
+
break;
|
|
5204
|
+
case "response.incomplete":
|
|
5205
|
+
events.push(...this.onIncomplete(raw));
|
|
5206
|
+
break;
|
|
5207
|
+
case "response.failed":
|
|
5208
|
+
events.push(...this.onTerminal(raw, "response.failed", "error", this.failedText(raw)));
|
|
5209
|
+
break;
|
|
5210
|
+
case "error":
|
|
5211
|
+
events.push(...this.onTerminal(raw, "error", "error", formatResponsesErrorEvent(raw)));
|
|
5212
|
+
break;
|
|
5213
|
+
default:
|
|
5214
|
+
this.diagnostics.unknownEventTypes.add(raw.type);
|
|
5215
|
+
break;
|
|
5216
|
+
}
|
|
5217
|
+
return events;
|
|
5218
|
+
}
|
|
5219
|
+
/** Stream ended without a terminal event. Caller decides how to fail. */
|
|
5220
|
+
finishWithoutTerminal() {
|
|
5221
|
+
return new ResponsesProtocolError(
|
|
5222
|
+
`Responses stream ended without a terminal event (${this.diagnostics.terminalType ?? "none"} seen).`
|
|
5223
|
+
);
|
|
5224
|
+
}
|
|
5225
|
+
// ─── item lifecycle ─────────────────────────────────────────────────────
|
|
5226
|
+
ensureStarted() {
|
|
5227
|
+
if (this.started) return [];
|
|
5228
|
+
this.started = true;
|
|
5229
|
+
return [{ type: "start", partial: this.output }];
|
|
5230
|
+
}
|
|
5231
|
+
requireItemIndex(raw) {
|
|
5232
|
+
const index = raw.output_index;
|
|
5233
|
+
if (typeof index !== "number" || !Number.isInteger(index) || index < 0) {
|
|
5234
|
+
throw new ResponsesProtocolError(`Responses event "${raw.type}" is missing a valid output_index.`);
|
|
5235
|
+
}
|
|
5236
|
+
return index;
|
|
5237
|
+
}
|
|
5238
|
+
onOutputItemAdded(raw) {
|
|
5239
|
+
const outputIndex = this.requireItemIndex(raw);
|
|
5240
|
+
const item = raw.item;
|
|
5241
|
+
if (!isRecord2(item)) {
|
|
5242
|
+
throw new ResponsesProtocolError(`response.output_item.added at index ${outputIndex} is missing the item.`);
|
|
5243
|
+
}
|
|
5244
|
+
if (this.items.has(outputIndex)) {
|
|
5245
|
+
throw new ResponsesProtocolError(`Responses stream reused output_index ${outputIndex}.`);
|
|
5246
|
+
}
|
|
5247
|
+
const itemId = typeof item.id === "string" ? item.id : "";
|
|
5248
|
+
if (item.type === "message") {
|
|
5249
|
+
this.items.set(outputIndex, { kind: "message", itemId, blocks: /* @__PURE__ */ new Map() });
|
|
5250
|
+
return this.ensureStarted();
|
|
5251
|
+
}
|
|
5252
|
+
if (item.type === "reasoning") {
|
|
5253
|
+
const block = { type: "thinking", thinking: "" };
|
|
5254
|
+
this.output.content.push(block);
|
|
5255
|
+
this.items.set(outputIndex, { kind: "reasoning", itemId, block, lastSummaryIndex: null });
|
|
5256
|
+
const startEvents = this.ensureStarted();
|
|
5257
|
+
return [
|
|
5258
|
+
...startEvents,
|
|
5259
|
+
{ type: "thinking_start", contentIndex: this.output.content.length - 1, partial: this.output }
|
|
5260
|
+
];
|
|
5261
|
+
}
|
|
5262
|
+
if (item.type === "function_call") {
|
|
5263
|
+
const callId = typeof item.call_id === "string" ? item.call_id : "";
|
|
5264
|
+
if (!callId) {
|
|
5265
|
+
throw new ResponsesProtocolError(`function_call output item at index ${outputIndex} is missing call_id.`);
|
|
5266
|
+
}
|
|
5267
|
+
const name = typeof item.name === "string" ? item.name : "";
|
|
5268
|
+
if (!name || !itemId) throw new ResponsesProtocolError("function_call requires name and item id.");
|
|
5269
|
+
const block = { type: "toolCall", id: callId, name, arguments: {} };
|
|
5270
|
+
this.output.content.push(block);
|
|
5271
|
+
const state = {
|
|
5272
|
+
kind: "function_call",
|
|
5273
|
+
itemId,
|
|
5274
|
+
block,
|
|
5275
|
+
partialArgs: "",
|
|
5276
|
+
finalArgs: null,
|
|
5277
|
+
completed: false,
|
|
5278
|
+
contentIndex: this.output.content.length - 1
|
|
5279
|
+
};
|
|
5280
|
+
this.items.set(outputIndex, state);
|
|
5281
|
+
this.toolCallStates.push(state);
|
|
5282
|
+
const startEvents = this.ensureStarted();
|
|
5283
|
+
return [
|
|
5284
|
+
...startEvents,
|
|
5285
|
+
{ type: "toolcall_start", contentIndex: state.contentIndex, partial: this.output }
|
|
5286
|
+
];
|
|
5287
|
+
}
|
|
5288
|
+
this.items.set(outputIndex, { kind: "ignored", itemType: String(item.type) });
|
|
5289
|
+
this.diagnostics.ignoredItemTypes.add(String(item.type));
|
|
5290
|
+
return [];
|
|
5291
|
+
}
|
|
5292
|
+
lookupItem(raw, kinds, label) {
|
|
5293
|
+
const outputIndex = this.requireItemIndex(raw);
|
|
5294
|
+
let state = this.items.get(outputIndex);
|
|
5295
|
+
if (!state || !kinds.includes(state.kind)) {
|
|
5296
|
+
throw new ResponsesProtocolError(
|
|
5297
|
+
`Responses event "${raw.type ?? label}" references ${label} output_index ${outputIndex} that was never added (or is of the wrong item type).`
|
|
5298
|
+
);
|
|
5299
|
+
}
|
|
5300
|
+
if (state.kind !== "ignored" && raw.item_id !== void 0 && raw.item_id !== state.itemId) throw new ResponsesProtocolError("Response item identity changed.");
|
|
5301
|
+
return { state, outputIndex };
|
|
5302
|
+
}
|
|
5303
|
+
onContentPartAdded(raw) {
|
|
5304
|
+
const part = raw.part;
|
|
5305
|
+
const partType = isRecord2(part) ? part.type : void 0;
|
|
5306
|
+
const kind = partType === "reasoning_text" ? "reasoning" : "message";
|
|
5307
|
+
const { state } = this.lookupItem(raw, [kind], kind);
|
|
5308
|
+
const partIndex = raw.content_index;
|
|
5309
|
+
if (typeof partIndex !== "number" || !Number.isInteger(partIndex) || partIndex < 0) {
|
|
5310
|
+
throw new ResponsesProtocolError("response.content_part.added is missing a valid content_index.");
|
|
5311
|
+
}
|
|
5312
|
+
if (state.kind !== "message") return [];
|
|
5313
|
+
if (state.blocks.has(partIndex)) {
|
|
5314
|
+
throw new ResponsesProtocolError(`Responses stream reused content_index ${partIndex} on one message item.`);
|
|
5315
|
+
}
|
|
5316
|
+
if (partType !== "output_text" && partType !== "refusal") {
|
|
5317
|
+
return [];
|
|
5318
|
+
}
|
|
5319
|
+
const block = { type: "text", text: "" };
|
|
5320
|
+
this.output.content.push(block);
|
|
5321
|
+
state.blocks.set(partIndex, { block, contentIndex: this.output.content.length - 1 });
|
|
5322
|
+
return [{ type: "text_start", contentIndex: this.output.content.length - 1, partial: this.output }];
|
|
5323
|
+
}
|
|
5324
|
+
messageBlockFor(raw) {
|
|
5325
|
+
const { state } = this.lookupItem(raw, ["message"], "message");
|
|
5326
|
+
if (state.kind !== "message") throw new ResponsesProtocolError("internal: expected message item");
|
|
5327
|
+
const partIndex = raw.content_index;
|
|
5328
|
+
if (typeof partIndex !== "number" || !Number.isInteger(partIndex) || partIndex < 0) {
|
|
5329
|
+
throw new ResponsesProtocolError(`Responses event "${raw.type}" is missing a valid content_index.`);
|
|
5330
|
+
}
|
|
5331
|
+
const entry = state.blocks.get(partIndex);
|
|
5332
|
+
if (!entry) {
|
|
5333
|
+
throw new ResponsesProtocolError(
|
|
5334
|
+
`Responses event "${raw.type}" references content_index ${partIndex} that was never added.`
|
|
5335
|
+
);
|
|
5336
|
+
}
|
|
5337
|
+
return entry;
|
|
5338
|
+
}
|
|
5339
|
+
appendTextDelta(raw, kind) {
|
|
5340
|
+
const delta = raw.delta;
|
|
5341
|
+
if (typeof delta !== "string" || delta.length === 0) return [];
|
|
5342
|
+
const entry = this.messageBlockFor(raw);
|
|
5343
|
+
entry.block.text += delta;
|
|
5344
|
+
return [{ type: "text_delta", contentIndex: entry.contentIndex, delta, partial: this.output }];
|
|
5345
|
+
}
|
|
5346
|
+
validateTextDone(raw) {
|
|
5347
|
+
this.messageBlockFor(raw);
|
|
5348
|
+
}
|
|
5349
|
+
appendReasoningDelta(raw) {
|
|
5350
|
+
const delta = raw.delta;
|
|
5351
|
+
if (typeof delta !== "string" || delta.length === 0) return [];
|
|
5352
|
+
const { state } = this.lookupItem(raw, ["reasoning"], "reasoning");
|
|
5353
|
+
if (state.kind !== "reasoning") return [];
|
|
5354
|
+
let text = delta;
|
|
5355
|
+
const summaryIndex = raw.summary_index;
|
|
5356
|
+
if (typeof summaryIndex === "number" && Number.isInteger(summaryIndex)) {
|
|
5357
|
+
if (state.lastSummaryIndex !== null && summaryIndex !== state.lastSummaryIndex) {
|
|
5358
|
+
text = `
|
|
5359
|
+
|
|
5360
|
+
${delta}`;
|
|
5361
|
+
}
|
|
5362
|
+
state.lastSummaryIndex = summaryIndex;
|
|
5363
|
+
}
|
|
5364
|
+
state.block.thinking += text;
|
|
5365
|
+
return [{ type: "thinking_delta", contentIndex: this.output.content.indexOf(state.block), delta: text, partial: this.output }];
|
|
5366
|
+
}
|
|
5367
|
+
appendFunctionCallArgsDelta(raw) {
|
|
5368
|
+
const delta = raw.delta ?? raw.arguments;
|
|
5369
|
+
if (typeof delta !== "string" || delta.length === 0) return [];
|
|
5370
|
+
const { state } = this.lookupItem(raw, ["function_call"], "function_call");
|
|
5371
|
+
if (state.kind !== "function_call") return [];
|
|
5372
|
+
state.partialArgs += delta;
|
|
5373
|
+
state.block.arguments = parseStreamingJson(state.partialArgs);
|
|
5374
|
+
return [{ type: "toolcall_delta", contentIndex: state.contentIndex, delta, partial: this.output }];
|
|
5375
|
+
}
|
|
5376
|
+
onFunctionCallArgsDone(raw) {
|
|
5377
|
+
const { state } = this.lookupItem(raw, ["function_call"], "function_call");
|
|
5378
|
+
if (state.kind !== "function_call") return;
|
|
5379
|
+
if (typeof raw.arguments === "string") {
|
|
5380
|
+
state.finalArgs = raw.arguments;
|
|
5381
|
+
}
|
|
5382
|
+
}
|
|
5383
|
+
onOutputItemDone(raw) {
|
|
5384
|
+
const outputIndex = this.requireItemIndex(raw);
|
|
5385
|
+
const item = raw.item;
|
|
5386
|
+
if (!isRecord2(item)) {
|
|
5387
|
+
throw new ResponsesProtocolError(`response.output_item.done at index ${outputIndex} is missing the item.`);
|
|
5388
|
+
}
|
|
5389
|
+
const state = this.items.get(outputIndex);
|
|
5390
|
+
if (!state) {
|
|
5391
|
+
throw new ResponsesProtocolError(`response.output_item.done references output_index ${outputIndex} that was never added.`);
|
|
5392
|
+
}
|
|
5393
|
+
if (state.kind !== "ignored" && (item.id !== state.itemId || item.type !== state.kind)) throw new ResponsesProtocolError("Response done item identity changed.");
|
|
5394
|
+
switch (state.kind) {
|
|
5395
|
+
case "message": {
|
|
5396
|
+
const events = [];
|
|
5397
|
+
for (const { block, contentIndex } of state.blocks.values()) {
|
|
5398
|
+
events.push({ type: "text_end", contentIndex, content: block.text, partial: this.output });
|
|
5399
|
+
}
|
|
5400
|
+
return events;
|
|
5401
|
+
}
|
|
5402
|
+
case "reasoning": {
|
|
5403
|
+
const events = [];
|
|
5404
|
+
const encrypted = typeof item.encrypted_content === "string" ? item.encrypted_content : null;
|
|
5405
|
+
const itemId = typeof item.id === "string" && item.id.length > 0 ? item.id : state.itemId;
|
|
5406
|
+
if (itemId) {
|
|
5407
|
+
state.block.thinkingSignature = JSON.stringify({ v: 1, id: itemId, encrypted_content: encrypted });
|
|
5408
|
+
}
|
|
5409
|
+
events.push({
|
|
5410
|
+
type: "thinking_end",
|
|
5411
|
+
contentIndex: this.output.content.indexOf(state.block),
|
|
5412
|
+
content: state.block.thinking,
|
|
5413
|
+
partial: this.output
|
|
5414
|
+
});
|
|
5415
|
+
return events;
|
|
5416
|
+
}
|
|
5417
|
+
case "function_call": {
|
|
5418
|
+
const finalText = typeof item.arguments === "string" && item.arguments.length > 0 ? item.arguments : state.finalArgs ?? state.partialArgs;
|
|
5419
|
+
if (typeof item.call_id === "string" && item.call_id.length > 0 && item.call_id !== state.block.id) {
|
|
5420
|
+
throw new ResponsesProtocolError(`function_call item changed call_id from "${state.block.id}" to "${item.call_id}".`);
|
|
5421
|
+
}
|
|
5422
|
+
if (typeof item.name === "string" && item.name.length > 0 && item.name !== state.block.name) {
|
|
5423
|
+
throw new ResponsesProtocolError(`function_call item changed name from "${state.block.name}" to "${item.name}".`);
|
|
5424
|
+
}
|
|
5425
|
+
state.completed = true;
|
|
5426
|
+
state.finalArgs = finalText;
|
|
5427
|
+
if (this.canParseArgs(state)) {
|
|
5428
|
+
return this.finalizeFunctionCall(state, finalText);
|
|
5429
|
+
}
|
|
5430
|
+
return [];
|
|
5431
|
+
}
|
|
5432
|
+
case "ignored":
|
|
5433
|
+
return [];
|
|
5434
|
+
}
|
|
5435
|
+
}
|
|
5436
|
+
finalizeFunctionCall(state, argsText) {
|
|
5437
|
+
const text = argsText.trim();
|
|
5438
|
+
let parsed;
|
|
5439
|
+
if (text.length === 0) {
|
|
5440
|
+
parsed = {};
|
|
5441
|
+
} else {
|
|
5442
|
+
try {
|
|
5443
|
+
const value = JSON.parse(text);
|
|
5444
|
+
if (!isRecord2(value)) {
|
|
5445
|
+
throw new ResponsesProtocolError(`function_call "${state.block.name || "unknown"}" arguments are not a JSON object.`);
|
|
5446
|
+
}
|
|
5447
|
+
parsed = value;
|
|
5448
|
+
} catch (error) {
|
|
5449
|
+
if (error instanceof ResponsesProtocolError) throw error;
|
|
5450
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5451
|
+
throw new ResponsesProtocolError(
|
|
5452
|
+
`function_call "${state.block.name || "unknown"}" returned incomplete or invalid JSON arguments: ${message}`
|
|
5453
|
+
);
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
state.block.arguments = parsed;
|
|
5457
|
+
return [{ type: "toolcall_end", contentIndex: state.contentIndex, toolCall: state.block, partial: this.output }];
|
|
5458
|
+
}
|
|
5459
|
+
// ─── terminals ──────────────────────────────────────────────────────────
|
|
5460
|
+
requireTerminalResponse(raw) {
|
|
5461
|
+
const response = raw.response;
|
|
5462
|
+
const expected = raw.type.slice("response.".length);
|
|
5463
|
+
if (!isRecord2(response) || typeof response.id !== "string" || !response.id || response.status !== expected) {
|
|
5464
|
+
throw new ResponsesProtocolError(`Malformed ${raw.type}: requires response id and status ${expected}.`);
|
|
5465
|
+
}
|
|
5466
|
+
return response;
|
|
5467
|
+
}
|
|
5468
|
+
onTerminal(raw, type, reason = "stop", errorText) {
|
|
5469
|
+
this.diagnostics.terminalType = type;
|
|
5470
|
+
const response = type === "error" ? void 0 : this.requireTerminalResponse(raw);
|
|
5471
|
+
this.terminal = { reason, response, errorText };
|
|
5472
|
+
return this.closeResponse(type);
|
|
5473
|
+
}
|
|
5474
|
+
onIncomplete(raw) {
|
|
5475
|
+
this.diagnostics.terminalType = "response.incomplete";
|
|
5476
|
+
const response = this.requireTerminalResponse(raw);
|
|
5477
|
+
const reason = response?.incomplete_details?.reason;
|
|
5478
|
+
if (reason === "content_filter" || reason === "steered" || reason === void 0) {
|
|
5479
|
+
this.terminal = {
|
|
5480
|
+
reason: "error",
|
|
5481
|
+
response,
|
|
5482
|
+
errorText: reason === "steered" ? "Response ended incomplete with reason 'steered' but no steering was sent." : `Response ended incomplete${reason ? ` (${reason})` : " without a reason"}.`
|
|
5483
|
+
};
|
|
5484
|
+
return this.closeResponse("response.incomplete");
|
|
5485
|
+
}
|
|
5486
|
+
this.terminal = { reason: "length", response };
|
|
5487
|
+
return this.closeResponse("response.incomplete");
|
|
5488
|
+
}
|
|
5489
|
+
failedText(raw) {
|
|
5490
|
+
const response = isRecord2(raw.response) ? raw.response : void 0;
|
|
5491
|
+
const error = isRecord2(response?.error) ? response?.error : void 0;
|
|
5492
|
+
const message = typeof error?.message === "string" && error.message.length > 0 ? error.message : "Response failed";
|
|
5493
|
+
const code = typeof error?.code === "string" && error.code.length > 0 ? ` (code=${error.code})` : "";
|
|
5494
|
+
return `${message}${code}`;
|
|
5495
|
+
}
|
|
5496
|
+
/** Apply terminal semantics and produce the final event. */
|
|
5497
|
+
closeResponse(terminalType) {
|
|
5498
|
+
const terminal = this.terminal;
|
|
5499
|
+
const response = terminal.response;
|
|
5500
|
+
if (response && isRecord2(response.usage)) {
|
|
5501
|
+
this.output.usage = normalizeResponsesUsage(this.model, response.usage);
|
|
5502
|
+
this.output.usageReported = [response.usage.input_tokens, response.usage.output_tokens].every((value) => typeof value === "number" && Number.isFinite(value) && value >= 0);
|
|
5503
|
+
}
|
|
5504
|
+
if (terminal.reason === "error") {
|
|
5505
|
+
this.output.stopReason = "error";
|
|
5506
|
+
this.output.errorMessage = terminal.errorText ?? "Response failed";
|
|
5507
|
+
return [{ type: "error", reason: "error", error: this.output }];
|
|
5508
|
+
}
|
|
5509
|
+
let stopReason = terminal.reason === "length" ? "length" : "stop";
|
|
5510
|
+
if (this.toolCallStates.length > 0) {
|
|
5511
|
+
stopReason = "toolUse";
|
|
5512
|
+
}
|
|
5513
|
+
if (terminal.reason === "length") {
|
|
5514
|
+
const truncated = this.toolCallStates.filter((state) => !state.completed || !this.canParseArgs(state));
|
|
5515
|
+
if (truncated.length > 0) {
|
|
5516
|
+
const dropped = new Set(truncated.map((state) => state.block));
|
|
5517
|
+
this.output.content = this.output.content.filter(
|
|
5518
|
+
(block) => block.type !== "toolCall" || !dropped.has(block)
|
|
5519
|
+
);
|
|
5520
|
+
this.toolCallStates = this.toolCallStates.filter((state) => !dropped.has(state.block));
|
|
5521
|
+
const names = truncated.map((state) => `"${state.block.name || "unnamed"}"`).sort().join(", ");
|
|
5522
|
+
this.output.content.push({
|
|
5523
|
+
type: "text",
|
|
5524
|
+
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.]`
|
|
5525
|
+
});
|
|
5526
|
+
if (this.toolCallStates.length === 0) {
|
|
5527
|
+
stopReason = "length";
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
} else if (terminal.reason === "stop") {
|
|
5531
|
+
const brokenCalls = this.toolCallStates.filter((state) => !state.completed || !this.canParseArgs(state));
|
|
5532
|
+
if (brokenCalls.length > 0) {
|
|
5533
|
+
const first = brokenCalls[0];
|
|
5534
|
+
this.output.stopReason = "error";
|
|
5535
|
+
this.output.errorMessage = `function_call "${first.block.name || "unknown"}" returned incomplete or invalid JSON arguments on a completed response.`;
|
|
5536
|
+
return [{ type: "error", reason: "error", error: this.output }];
|
|
5537
|
+
}
|
|
5538
|
+
}
|
|
5539
|
+
if (stopReason === "toolUse" && this.toolCallStates.length === 0) {
|
|
5540
|
+
stopReason = "stop";
|
|
5541
|
+
}
|
|
5542
|
+
this.output.stopReason = stopReason;
|
|
5543
|
+
void terminalType;
|
|
5544
|
+
return [{ type: "done", reason: stopReason, message: this.output }];
|
|
5545
|
+
}
|
|
5546
|
+
canParseArgs(state) {
|
|
5547
|
+
const text = (state.finalArgs ?? state.partialArgs).trim();
|
|
5548
|
+
if (text.length === 0) return false;
|
|
5549
|
+
try {
|
|
5550
|
+
return isRecord2(JSON.parse(text));
|
|
5551
|
+
} catch {
|
|
5552
|
+
return false;
|
|
5553
|
+
}
|
|
5554
|
+
}
|
|
5555
|
+
};
|
|
5556
|
+
|
|
5557
|
+
// ../../packages/ai/src/providers/responses/responses-diagnostics.ts
|
|
5558
|
+
function reportSubmission(options, body, details) {
|
|
5559
|
+
if (!options?.onTransportDiagnostic) return;
|
|
5560
|
+
let requestBytes = 0;
|
|
5561
|
+
for (const character of body) {
|
|
5562
|
+
const point = character.codePointAt(0);
|
|
5563
|
+
requestBytes += point <= 127 ? 1 : point <= 2047 ? 2 : point <= 65535 ? 3 : 4;
|
|
5564
|
+
}
|
|
5565
|
+
try {
|
|
5566
|
+
options.onTransportDiagnostic({ ...details, requestBytes });
|
|
5567
|
+
} catch {
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
|
|
5571
|
+
// ../../packages/ai/src/providers/responses/responses-sse.ts
|
|
5572
|
+
var DEFAULT_RESPONSES_STREAM_IDLE_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
5573
|
+
var DEFAULT_RESPONSES_FIRST_BYTE_TIMEOUT_MS = 3 * 60 * 1e3;
|
|
5574
|
+
function parseSSEDataLine2(line) {
|
|
5575
|
+
const trimmed = line.trim();
|
|
5576
|
+
if (!trimmed || trimmed.startsWith(":")) return null;
|
|
5577
|
+
if (!trimmed.startsWith("data:")) return null;
|
|
5578
|
+
const data = trimmed.slice(5);
|
|
5579
|
+
return data.startsWith(" ") ? data.slice(1) : data;
|
|
5580
|
+
}
|
|
5581
|
+
function streamResponsesSSE(model, context, options) {
|
|
5582
|
+
const stream = new AssistantMessageEventStream();
|
|
5583
|
+
void (async () => {
|
|
5584
|
+
const reducer = new ResponsesEventReducer(model);
|
|
5585
|
+
try {
|
|
5586
|
+
const apiKey = options?.apiKey || getEnvApiKey(model.provider, model.apiKeyEnv) || "";
|
|
5587
|
+
if (!apiKey) {
|
|
5588
|
+
throw new Error(`No API key for provider: ${model.provider}`);
|
|
5589
|
+
}
|
|
5590
|
+
const payload = buildResponsesSSEPayload(model, context, options);
|
|
5591
|
+
options?.onPayload?.(payload);
|
|
5592
|
+
const headers = {
|
|
5593
|
+
"Content-Type": "application/json",
|
|
5594
|
+
Accept: "text/event-stream",
|
|
5595
|
+
Authorization: `Bearer ${apiKey}`,
|
|
5596
|
+
...model.headers || {},
|
|
5597
|
+
...options?.headers || {}
|
|
5598
|
+
};
|
|
5599
|
+
const body = JSON.stringify(payload);
|
|
5600
|
+
reportSubmission(options, body, { transport: "sse", reusedConnection: false, continuation: false, attempt: 1 });
|
|
5601
|
+
const response = await httpRequest(`${model.baseUrl}/responses`, {
|
|
5602
|
+
method: "POST",
|
|
5603
|
+
headers,
|
|
5604
|
+
body,
|
|
5605
|
+
signal: options?.signal,
|
|
5606
|
+
...options?.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {
|
|
5607
|
+
firstByteTimeoutMs: DEFAULT_RESPONSES_FIRST_BYTE_TIMEOUT_MS,
|
|
5608
|
+
streamIdleTimeoutMs: DEFAULT_RESPONSES_STREAM_IDLE_TIMEOUT_MS
|
|
5609
|
+
},
|
|
5610
|
+
label: `${model.provider}/${model.id}`
|
|
5611
|
+
});
|
|
5612
|
+
if (!response.ok) {
|
|
5613
|
+
const errorBody = await response.text().catch(() => "");
|
|
5614
|
+
throw new Error(`API error ${response.status}: ${errorBody}`);
|
|
5615
|
+
}
|
|
5616
|
+
if (!response.readSSELines) {
|
|
5617
|
+
throw new Error("SSE streaming not supported on this platform");
|
|
5618
|
+
}
|
|
5619
|
+
for await (const line of response.readSSELines(options?.signal)) {
|
|
5620
|
+
const data = parseSSEDataLine2(line);
|
|
5621
|
+
if (data === null) continue;
|
|
5622
|
+
if (data === "[DONE]") {
|
|
5623
|
+
continue;
|
|
5624
|
+
}
|
|
5625
|
+
let event;
|
|
5626
|
+
try {
|
|
5627
|
+
event = JSON.parse(data);
|
|
5628
|
+
} catch (error) {
|
|
5629
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5630
|
+
throw new ResponsesProtocolError(`Responses SSE stream returned malformed JSON: ${message}`);
|
|
5631
|
+
}
|
|
5632
|
+
if (!isResponsesEventLike(event)) {
|
|
5633
|
+
throw new ResponsesProtocolError("Responses SSE payload is not an event object with a string type.");
|
|
5634
|
+
}
|
|
5635
|
+
for (const assistantEvent of reducer.feed(event)) {
|
|
5636
|
+
stream.push(assistantEvent);
|
|
5637
|
+
}
|
|
5638
|
+
if (reducer.isTerminal) break;
|
|
5639
|
+
}
|
|
5640
|
+
if (reducer.isTerminal) {
|
|
5641
|
+
stream.end();
|
|
5642
|
+
return;
|
|
5643
|
+
}
|
|
5644
|
+
if (options?.signal?.aborted) {
|
|
5645
|
+
throw new Error("Request was aborted");
|
|
5646
|
+
}
|
|
5647
|
+
if (!reducer.isTerminal) {
|
|
5648
|
+
throw reducer.finishWithoutTerminal();
|
|
5649
|
+
}
|
|
5650
|
+
if (reducer.message.stopReason === "error" || reducer.message.stopReason === "aborted") {
|
|
5651
|
+
throw new Error(reducer.message.errorMessage ?? "An unknown error occurred");
|
|
5652
|
+
}
|
|
5653
|
+
stream.end();
|
|
5654
|
+
} catch (error) {
|
|
5655
|
+
if (reducer.isTerminal) {
|
|
5656
|
+
stream.end();
|
|
5657
|
+
return;
|
|
5658
|
+
}
|
|
5659
|
+
const message = reducer.message;
|
|
5660
|
+
message.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
5661
|
+
message.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
5662
|
+
stream.push({ type: "error", reason: message.stopReason, error: message });
|
|
5663
|
+
stream.end();
|
|
5664
|
+
}
|
|
5665
|
+
})();
|
|
5666
|
+
return stream;
|
|
5667
|
+
}
|
|
5668
|
+
|
|
5669
|
+
// ../../packages/ai/src/providers/responses/responses-ws.ts
|
|
5670
|
+
var owners = /* @__PURE__ */ new WeakMap();
|
|
5671
|
+
var MAX_ANCHOR_BYTES = 1024 * 1024;
|
|
5672
|
+
function disposeModelTransports(owner) {
|
|
5673
|
+
const state = owners.get(owner);
|
|
5674
|
+
if (!state) return;
|
|
5675
|
+
disposeState(owner, state);
|
|
5676
|
+
}
|
|
5677
|
+
function disposeState(owner, state) {
|
|
5678
|
+
if (owners.get(owner) === state) owners.delete(owner);
|
|
5679
|
+
state.anchor = void 0;
|
|
5680
|
+
state.abort.abort();
|
|
5681
|
+
void state.connection?.close().catch(() => {
|
|
5682
|
+
});
|
|
5683
|
+
}
|
|
5684
|
+
function stateFor(owner) {
|
|
5685
|
+
let state = owners.get(owner);
|
|
5686
|
+
if (!state) {
|
|
5687
|
+
state = { busy: false, abort: new AbortController() };
|
|
5688
|
+
owners.set(owner, state);
|
|
5689
|
+
}
|
|
5690
|
+
return state;
|
|
5691
|
+
}
|
|
5692
|
+
function websocketUrl(base) {
|
|
5693
|
+
const url = new URL(`${base.replace(/\/$/, "")}/responses`);
|
|
5694
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") throw new ResponsesProtocolError("Responses requires an HTTP(S) API root.");
|
|
5695
|
+
return `${url.protocol === "https:" ? "wss:" : "ws:"}${url.toString().slice(url.protocol.length)}`;
|
|
5696
|
+
}
|
|
5697
|
+
function streamResponsesWS(model, context, options) {
|
|
5698
|
+
const stream = new AssistantMessageEventStream();
|
|
5699
|
+
const owner = options?.transportOwner ?? {};
|
|
5700
|
+
const state = stateFor(owner);
|
|
5701
|
+
const reducer = new ResponsesEventReducer(model);
|
|
5702
|
+
if (state.busy) {
|
|
5703
|
+
reducer.message.stopReason = "error";
|
|
5704
|
+
reducer.message.errorMessage = "Responses owner already has an in-flight request.";
|
|
5705
|
+
stream.push({ type: "error", reason: "error", error: reducer.message });
|
|
5706
|
+
stream.end();
|
|
5707
|
+
return stream;
|
|
5708
|
+
}
|
|
5709
|
+
state.busy = true;
|
|
5710
|
+
void (async () => {
|
|
5711
|
+
let sent = false;
|
|
5712
|
+
let finished = false;
|
|
5713
|
+
let terminalEvents = [];
|
|
5714
|
+
let fallback = false;
|
|
5715
|
+
const publish = (event) => {
|
|
5716
|
+
if (event.type === "done" || event.type === "error") terminalEvents.push(event);
|
|
5717
|
+
else stream.push(event);
|
|
5718
|
+
};
|
|
5719
|
+
const abort = () => disposeState(owner, state);
|
|
5720
|
+
options?.signal?.addEventListener("abort", abort, { once: true });
|
|
5721
|
+
try {
|
|
5722
|
+
if (options?.signal?.aborted) {
|
|
5723
|
+
abort();
|
|
5724
|
+
throw new Error("Request aborted");
|
|
5725
|
+
}
|
|
5726
|
+
const key = options?.apiKey || getEnvApiKey(model.provider, model.apiKeyEnv);
|
|
5727
|
+
if (!key) throw new Error(`No API key for provider: ${model.provider}`);
|
|
5728
|
+
const payload = buildResponsesCreateEvent(model, context, options);
|
|
5729
|
+
const headers = { Authorization: `Bearer ${key}`, ...model.headers, ...options?.headers };
|
|
5730
|
+
const { input, ...settings } = payload;
|
|
5731
|
+
const identity = JSON.stringify([model.provider, model.api, model.id, model.baseUrl, headers, settings]);
|
|
5732
|
+
if (state.identity !== identity || state.connection?.state() !== "open") {
|
|
5733
|
+
await state.connection?.close();
|
|
5734
|
+
state.connection = void 0;
|
|
5735
|
+
state.anchor = void 0;
|
|
5736
|
+
state.identity = identity;
|
|
5737
|
+
}
|
|
5738
|
+
if (state.abort.signal.aborted) throw new Error("Request aborted");
|
|
5739
|
+
const client = getWebSocketClient();
|
|
5740
|
+
if (!client) {
|
|
5741
|
+
if (options?.transport === "auto") {
|
|
5742
|
+
fallback = true;
|
|
5743
|
+
for await (const event of streamResponsesSSE(model, context, { ...options, signal: state.abort.signal })) publish(event);
|
|
5744
|
+
finished = true;
|
|
5745
|
+
return;
|
|
5746
|
+
}
|
|
5747
|
+
throw new Error("WebSocket transport is not available on this host.");
|
|
5748
|
+
}
|
|
5749
|
+
const reusedConnection = !!state.connection;
|
|
5750
|
+
if (!state.connection) {
|
|
5751
|
+
try {
|
|
5752
|
+
state.connection = await client.connect(websocketUrl(model.baseUrl), {
|
|
5753
|
+
headers,
|
|
5754
|
+
signal: state.abort.signal,
|
|
5755
|
+
connectTimeoutMs: options?.timeoutMs ?? 3e4,
|
|
5756
|
+
idleTimeoutMs: options?.timeoutMs ?? 12e4
|
|
5757
|
+
});
|
|
5758
|
+
} catch (error) {
|
|
5759
|
+
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) {
|
|
5760
|
+
fallback = true;
|
|
5761
|
+
for await (const event of streamResponsesSSE(model, context, { ...options, signal: state.abort.signal })) publish(event);
|
|
5762
|
+
finished = true;
|
|
5763
|
+
return;
|
|
5764
|
+
}
|
|
5765
|
+
throw error;
|
|
5766
|
+
}
|
|
5767
|
+
}
|
|
5768
|
+
const fullInput = input;
|
|
5769
|
+
const anchor = state.anchor;
|
|
5770
|
+
if (!options?.onPayload && model.compat?.responsesContinuation && anchor && fullInput.length > anchor.count && JSON.stringify(fullInput.slice(0, anchor.count)) === anchor.prefix) {
|
|
5771
|
+
payload.previous_response_id = anchor.id;
|
|
5772
|
+
payload.input = fullInput.slice(anchor.count);
|
|
5773
|
+
}
|
|
5774
|
+
state.anchor = void 0;
|
|
5775
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
5776
|
+
let rebuild = false;
|
|
5777
|
+
options?.onPayload?.(payload);
|
|
5778
|
+
if (state.abort.signal.aborted) throw new Error("Request aborted");
|
|
5779
|
+
sent = true;
|
|
5780
|
+
const body = JSON.stringify(payload);
|
|
5781
|
+
reportSubmission(options, body, { transport: "websocket", reusedConnection: reusedConnection || attempt > 0, continuation: !!payload.previous_response_id, attempt: attempt + 1 });
|
|
5782
|
+
await state.connection.send(body, { signal: state.abort.signal });
|
|
5783
|
+
let started = false;
|
|
5784
|
+
let responseId;
|
|
5785
|
+
for await (const message of state.connection.receive(state.abort.signal)) {
|
|
5786
|
+
if (state.abort.signal.aborted) throw new Error("Request aborted");
|
|
5787
|
+
if (message.isBinary) throw new ResponsesProtocolError("Responses requires JSON text messages.");
|
|
5788
|
+
const event = JSON.parse(message.data);
|
|
5789
|
+
if (!isRecord2(event)) throw new ResponsesProtocolError("Invalid Responses WebSocket event.");
|
|
5790
|
+
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") {
|
|
5791
|
+
delete payload.previous_response_id;
|
|
5792
|
+
payload.input = fullInput;
|
|
5793
|
+
rebuild = true;
|
|
5794
|
+
break;
|
|
5795
|
+
}
|
|
5796
|
+
if (!started && typeof event.type === "string" && event.type !== "error" && !event.type.startsWith("response.")) continue;
|
|
5797
|
+
if (!started && event.type !== "error") {
|
|
5798
|
+
if (event.type !== "response.created" || !isRecord2(event.response) || typeof event.response.id !== "string" || event.response.id === state.lastResponseId) {
|
|
5799
|
+
throw new ResponsesProtocolError("Expected a new response.created before output.");
|
|
5800
|
+
}
|
|
5801
|
+
started = true;
|
|
5802
|
+
responseId = event.response.id;
|
|
5803
|
+
}
|
|
5804
|
+
if (responseId && isRecord2(event.response) && event.response.id !== responseId) throw new ResponsesProtocolError("Response identity changed within a request.");
|
|
5805
|
+
const events = reducer.feed(event);
|
|
5806
|
+
if (reducer.isTerminal) {
|
|
5807
|
+
if (reducer.message.stopReason === "error") reducer.message.retryable = false;
|
|
5808
|
+
const response = reducer.terminalResponse;
|
|
5809
|
+
state.lastResponseId = response?.id;
|
|
5810
|
+
if (!options?.onPayload && response?.status === "completed" && reducer.message.stopReason !== "error") {
|
|
5811
|
+
const prefixItems = [...fullInput, ...buildResponsesOutput(reducer.message)];
|
|
5812
|
+
const prefix = JSON.stringify(prefixItems);
|
|
5813
|
+
if (prefix.length * 2 <= MAX_ANCHOR_BYTES) state.anchor = { id: response.id, prefix, count: prefixItems.length };
|
|
5814
|
+
}
|
|
5815
|
+
finished = true;
|
|
5816
|
+
for (const e of events) publish(e);
|
|
5817
|
+
break;
|
|
5818
|
+
}
|
|
5819
|
+
for (const e of events) publish(e);
|
|
5820
|
+
}
|
|
5821
|
+
if (rebuild) continue;
|
|
5822
|
+
if (!reducer.isTerminal) throw reducer.finishWithoutTerminal();
|
|
5823
|
+
break;
|
|
5824
|
+
}
|
|
5825
|
+
} catch (error) {
|
|
5826
|
+
if (!finished) {
|
|
5827
|
+
const message = reducer.message;
|
|
5828
|
+
message.stopReason = options?.signal?.aborted || state.abort.signal.aborted ? "aborted" : "error";
|
|
5829
|
+
message.errorMessage = error instanceof Error ? error.message : String(error);
|
|
5830
|
+
if (sent) message.retryable = false;
|
|
5831
|
+
stream.push({ type: "error", reason: message.stopReason, error: message });
|
|
5832
|
+
}
|
|
5833
|
+
} finally {
|
|
5834
|
+
options?.signal?.removeEventListener("abort", abort);
|
|
5835
|
+
state.busy = false;
|
|
5836
|
+
if (fallback || !finished || !options?.transportOwner || reducer.message.stopReason === "error") disposeState(owner, state);
|
|
5837
|
+
for (const event of terminalEvents) stream.push(event);
|
|
5838
|
+
stream.end();
|
|
5839
|
+
}
|
|
5840
|
+
})();
|
|
5841
|
+
return stream;
|
|
5842
|
+
}
|
|
5843
|
+
|
|
5844
|
+
// ../../packages/ai/src/providers/openai-responses.ts
|
|
5845
|
+
var streamResponses = (model, context, options) => {
|
|
5846
|
+
const transport = options?.transport ?? model.transport ?? "sse";
|
|
5847
|
+
if (transport === "websocket" || transport === "auto") return streamResponsesWS(model, context, { ...options, transport });
|
|
5848
|
+
if (transport !== "sse") throw new Error(`Unsupported transport: ${transport}`);
|
|
5849
|
+
return streamResponsesSSE(model, context, options);
|
|
5850
|
+
};
|
|
5851
|
+
var streamSimpleResponses = (model, context, options) => {
|
|
5852
|
+
const apiKey = options?.apiKey || getEnvApiKey(model.provider, model.apiKeyEnv);
|
|
5853
|
+
if (!apiKey) {
|
|
5854
|
+
throw new Error(`No API key for provider: ${model.provider}`);
|
|
5855
|
+
}
|
|
5856
|
+
const base = buildBaseOptions(model, options, apiKey);
|
|
5857
|
+
const needsThinkingAllowance = Boolean(model.reasoning) && options?.reasoning !== void 0;
|
|
5858
|
+
let maxTokens = base.maxTokens;
|
|
5859
|
+
if (needsThinkingAllowance) {
|
|
5860
|
+
const adjusted = adjustMaxTokensForThinking(
|
|
5861
|
+
base.maxTokens || 0,
|
|
5862
|
+
model.maxTokens,
|
|
5863
|
+
options.reasoning,
|
|
5864
|
+
options?.thinkingBudgets
|
|
5865
|
+
);
|
|
5866
|
+
maxTokens = adjusted.maxTokens;
|
|
5867
|
+
}
|
|
5868
|
+
if (maxTokens === void 0) {
|
|
5869
|
+
maxTokens = DEFAULT_MAX_TOKENS;
|
|
5870
|
+
}
|
|
5871
|
+
const reasoningEffort = model.reasoning ? options?.reasoning : void 0;
|
|
5872
|
+
return streamResponses(model, context, {
|
|
5873
|
+
...base,
|
|
5874
|
+
maxTokens,
|
|
5875
|
+
// Responses accepts the full effort vocabulary verified in the SDK
|
|
5876
|
+
// ("none" excluded from Pie's ThinkingLevel); pass through unchanged.
|
|
5877
|
+
reasoningEffort
|
|
5878
|
+
});
|
|
5879
|
+
};
|
|
5880
|
+
|
|
4622
5881
|
// ../../packages/ai/src/stream.ts
|
|
4623
5882
|
function resolveApiProvider(api) {
|
|
4624
5883
|
const provider = getApiProvider(api);
|
|
@@ -8079,6 +9338,11 @@ registerApiProvider({
|
|
|
8079
9338
|
stream: streamAnthropic,
|
|
8080
9339
|
streamSimple: streamSimpleAnthropic
|
|
8081
9340
|
});
|
|
9341
|
+
registerApiProvider({
|
|
9342
|
+
api: "openai-responses",
|
|
9343
|
+
stream: streamResponses,
|
|
9344
|
+
streamSimple: streamSimpleResponses
|
|
9345
|
+
});
|
|
8082
9346
|
|
|
8083
9347
|
export {
|
|
8084
9348
|
hashText,
|
|
@@ -8097,6 +9361,7 @@ export {
|
|
|
8097
9361
|
getModelCacheCapability,
|
|
8098
9362
|
EMPTY_ASSISTANT_CONTENT_ERROR,
|
|
8099
9363
|
OPENAI_COMPAT_PROTOCOL_ERROR_CODE,
|
|
9364
|
+
disposeModelTransports,
|
|
8100
9365
|
streamSimple,
|
|
8101
9366
|
completeSimple,
|
|
8102
9367
|
MODEL_CLASS_FALLBACK_ORDER,
|