@jeffusion/bungee-core 5.19.0 → 5.21.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/dist/config-worker/private-transport.d.ts +2 -0
- package/dist/data-admission/errors.d.ts +6 -1
- package/dist/gateway/contracts.d.ts +16 -3
- package/dist/gateway/forward-plugin.d.ts +2 -0
- package/dist/gateway/plugin.js +12 -2
- package/dist/gateway/request-plugin.d.ts +6 -0
- package/dist/gateway/responses-websocket-session.d.ts +18 -0
- package/dist/gateway/runtime.d.ts +1 -0
- package/dist/gateway/websocket-contracts.d.ts +1 -0
- package/dist/hooks/plugin-hooks.d.ts +2 -0
- package/dist/logger/access-log-writer.d.ts +2 -2
- package/dist/main.js +1234 -191
- package/dist/plugins/ai-transformer/index.js +11 -1
- package/dist/plugins/ai-transformer/index.js.map +5 -3
- package/dist/plugins/codex-router/control.js +677 -2
- package/dist/plugins/codex-router/control.js.map +19 -4
- package/dist/plugins/codex-router/index.js +4123 -33
- package/dist/plugins/codex-router/index.js.map +25 -7
- package/dist/plugins/codex-router/manifest.json +139 -9
- package/dist/plugins/key-access/index.js +12 -2
- package/dist/plugins/key-access/index.js.map +3 -3
- package/dist/plugins/key-access/ingress.js +12 -2
- package/dist/plugins/key-access/ingress.js.map +3 -3
- package/dist/plugins/openai-messages-to-chat/index.js +693 -543
- package/dist/plugins/openai-messages-to-chat/index.js.map +8 -4
- package/dist/plugins/token-metering/index.js +652 -71
- package/dist/plugins/token-metering/index.js.map +5 -3
- package/dist/plugins/token-stats/manifest.json +16 -6
- package/dist/plugins/token-stats/ui/ClientModelPicker.svelte +13 -61
- package/dist/plugins/token-stats/ui/PriceModelPicker.svelte +18 -74
- package/dist/plugins/token-stats/ui/TokenStatsSettings.svelte +3 -2
- package/dist/plugins/token-stats/ui/model-search.ts +2 -45
- package/dist/plugins/token-stats/ui/pricing-catalog.ts +2 -1
- package/dist/scoped-plugin-registry.d.ts +11 -2
- package/dist/websocket/index.d.ts +1 -1
- package/dist/websocket/transport.d.ts +40 -18
- package/package.json +2 -2
- package/dist/plugins/chatgpt-oauth/ui/account-model.test.js +0 -69
- package/dist/plugins/local-accounts/ui/login-errors.test.ts +0 -22
- package/dist/plugins/token-stats/ui/client-model-search.test.ts +0 -58
- package/dist/plugins/token-stats/ui/pricing-catalog.test.ts +0 -114
|
@@ -5337,6 +5337,601 @@ var PROVIDER_ADAPTERS = {
|
|
|
5337
5337
|
anthropic: createAnthropicAdapter(),
|
|
5338
5338
|
gemini: createGeminiAdapter()
|
|
5339
5339
|
};
|
|
5340
|
+
// packages/llms/src/responses-codec/common.ts
|
|
5341
|
+
var DEFAULT_RESPONSES_CODEC_LIMITS = Object.freeze({
|
|
5342
|
+
maxRequestBytes: 8 * 1024 * 1024,
|
|
5343
|
+
maxOutputBytes: 8 * 1024 * 1024,
|
|
5344
|
+
maxArgumentBytes: 1024 * 1024,
|
|
5345
|
+
maxItems: 1024
|
|
5346
|
+
});
|
|
5347
|
+
|
|
5348
|
+
class ResponsesCodecError extends Error {
|
|
5349
|
+
code;
|
|
5350
|
+
param;
|
|
5351
|
+
constructor(code, message, param) {
|
|
5352
|
+
super(message);
|
|
5353
|
+
this.code = code;
|
|
5354
|
+
this.param = param;
|
|
5355
|
+
this.name = "ResponsesCodecError";
|
|
5356
|
+
}
|
|
5357
|
+
}
|
|
5358
|
+
function fail(code, message, param) {
|
|
5359
|
+
throw new ResponsesCodecError(code, message, param);
|
|
5360
|
+
}
|
|
5361
|
+
function record(value, where) {
|
|
5362
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
5363
|
+
fail("invalid_payload", `${where} must be an object`);
|
|
5364
|
+
return value;
|
|
5365
|
+
}
|
|
5366
|
+
function string(value, where, nonempty = false) {
|
|
5367
|
+
if (typeof value !== "string" || nonempty && !value)
|
|
5368
|
+
fail("invalid_payload", `${where} must be a${nonempty ? " non-empty" : ""} string`);
|
|
5369
|
+
return value;
|
|
5370
|
+
}
|
|
5371
|
+
function list(value, where) {
|
|
5372
|
+
if (!Array.isArray(value))
|
|
5373
|
+
fail("invalid_payload", `${where} must be an array`);
|
|
5374
|
+
return value;
|
|
5375
|
+
}
|
|
5376
|
+
function limits(overrides) {
|
|
5377
|
+
const result = { ...DEFAULT_RESPONSES_CODEC_LIMITS, ...overrides };
|
|
5378
|
+
for (const [key, value] of Object.entries(result)) {
|
|
5379
|
+
if (!Number.isSafeInteger(value) || value <= 0)
|
|
5380
|
+
fail("invalid_limit", `${key} must be a positive integer`);
|
|
5381
|
+
}
|
|
5382
|
+
return result;
|
|
5383
|
+
}
|
|
5384
|
+
function bytes(value) {
|
|
5385
|
+
return new TextEncoder().encode(value).byteLength;
|
|
5386
|
+
}
|
|
5387
|
+
function bounded(value, max, where) {
|
|
5388
|
+
if (bytes(value) > max)
|
|
5389
|
+
fail("resource_limit", `${where} exceeds ${max} bytes`);
|
|
5390
|
+
return value;
|
|
5391
|
+
}
|
|
5392
|
+
function serialized(value, max, where) {
|
|
5393
|
+
let result;
|
|
5394
|
+
try {
|
|
5395
|
+
result = JSON.stringify(value);
|
|
5396
|
+
} catch {
|
|
5397
|
+
fail("invalid_payload", `${where} must be serializable JSON`);
|
|
5398
|
+
}
|
|
5399
|
+
if (result === undefined)
|
|
5400
|
+
fail("invalid_payload", `${where} must be serializable JSON`);
|
|
5401
|
+
return bounded(result, max, where);
|
|
5402
|
+
}
|
|
5403
|
+
function argumentObject(text) {
|
|
5404
|
+
let value;
|
|
5405
|
+
try {
|
|
5406
|
+
value = JSON.parse(text);
|
|
5407
|
+
} catch {
|
|
5408
|
+
fail("invalid_tool_arguments", "Tool arguments must be complete JSON");
|
|
5409
|
+
}
|
|
5410
|
+
return record(value, "tool arguments");
|
|
5411
|
+
}
|
|
5412
|
+
function restoreTool(name, names) {
|
|
5413
|
+
const result = names.get(name);
|
|
5414
|
+
if (result)
|
|
5415
|
+
return result;
|
|
5416
|
+
if (names.size)
|
|
5417
|
+
fail("unknown_tool", `Provider returned undeclared tool ${name}`);
|
|
5418
|
+
return { name, custom: false };
|
|
5419
|
+
}
|
|
5420
|
+
function customInput(text) {
|
|
5421
|
+
const value = argumentObject(text);
|
|
5422
|
+
if (Object.keys(value).length !== 1 || typeof value.input !== "string") {
|
|
5423
|
+
fail("invalid_tool_arguments", "Custom tools require exactly one string input property");
|
|
5424
|
+
}
|
|
5425
|
+
return value.input;
|
|
5426
|
+
}
|
|
5427
|
+
function customInputPrefix(text) {
|
|
5428
|
+
const prefix = /^\s*\{\s*"input"\s*:\s*"/.exec(text);
|
|
5429
|
+
if (!prefix)
|
|
5430
|
+
return "";
|
|
5431
|
+
let result = "";
|
|
5432
|
+
for (let i = prefix[0].length;i < text.length; ) {
|
|
5433
|
+
const char = text[i];
|
|
5434
|
+
if (char === '"')
|
|
5435
|
+
break;
|
|
5436
|
+
if (char !== "\\") {
|
|
5437
|
+
if (char.charCodeAt(0) < 32)
|
|
5438
|
+
fail("invalid_tool_arguments", "Invalid JSON string character");
|
|
5439
|
+
result += char;
|
|
5440
|
+
i++;
|
|
5441
|
+
continue;
|
|
5442
|
+
}
|
|
5443
|
+
const escape = text[i + 1];
|
|
5444
|
+
if (escape === undefined)
|
|
5445
|
+
break;
|
|
5446
|
+
const size = escape === "u" ? 6 : 2;
|
|
5447
|
+
if (i + size > text.length)
|
|
5448
|
+
break;
|
|
5449
|
+
try {
|
|
5450
|
+
result += JSON.parse(`"${text.slice(i, i + size)}"`);
|
|
5451
|
+
} catch {
|
|
5452
|
+
fail("invalid_tool_arguments", "Invalid JSON string escape");
|
|
5453
|
+
}
|
|
5454
|
+
i += size;
|
|
5455
|
+
}
|
|
5456
|
+
return result;
|
|
5457
|
+
}
|
|
5458
|
+
function terminal(reason, protocol) {
|
|
5459
|
+
if (typeof reason !== "string" || !reason)
|
|
5460
|
+
fail("missing_terminal", "Upstream has no explicit completion reason");
|
|
5461
|
+
const completed = protocol === "chat_completions" ? ["stop", "tool_calls", "function_call"] : ["end_turn", "tool_use", "stop_sequence"];
|
|
5462
|
+
if (completed.includes(reason))
|
|
5463
|
+
return { status: "completed", reason };
|
|
5464
|
+
if (reason === "length" || reason === "max_tokens" || reason === "model_context_window_exceeded")
|
|
5465
|
+
return { status: "incomplete", reason: "max_output_tokens" };
|
|
5466
|
+
if (reason === "content_filter" || reason === "refusal")
|
|
5467
|
+
return { status: "incomplete", reason: "content_filter" };
|
|
5468
|
+
if (reason === "error")
|
|
5469
|
+
return { status: "failed", reason: "upstream_error" };
|
|
5470
|
+
fail("unknown_terminal", `Unsupported upstream completion reason: ${reason}`);
|
|
5471
|
+
}
|
|
5472
|
+
function tokens(value, where) {
|
|
5473
|
+
if (value === undefined)
|
|
5474
|
+
return 0;
|
|
5475
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
5476
|
+
fail("invalid_usage", `${where} must be a non-negative integer`);
|
|
5477
|
+
return value;
|
|
5478
|
+
}
|
|
5479
|
+
function normalizeUsage(raw, protocol, prior = {}) {
|
|
5480
|
+
if (raw === undefined || raw === null)
|
|
5481
|
+
return prior;
|
|
5482
|
+
const usage = record(raw, "usage");
|
|
5483
|
+
const chat = protocol === "chat_completions";
|
|
5484
|
+
const input = tokens(usage[chat ? "prompt_tokens" : "input_tokens"] ?? prior.input_tokens, "input_tokens");
|
|
5485
|
+
const output = tokens(usage[chat ? "completion_tokens" : "output_tokens"] ?? prior.output_tokens, "output_tokens");
|
|
5486
|
+
const details = chat ? usage.prompt_tokens_details : undefined;
|
|
5487
|
+
const cached = chat ? details ? record(details, "prompt_tokens_details").cached_tokens : undefined : usage.cache_read_input_tokens;
|
|
5488
|
+
const cacheRead = tokens(cached ?? prior.input_tokens_details?.cached_tokens, "cached_tokens");
|
|
5489
|
+
const cacheWrite = chat ? 0 : tokens(usage.cache_creation_input_tokens, "cache_creation_input_tokens");
|
|
5490
|
+
const totalInput = chat ? input : usage.input_tokens === undefined ? input : input + cacheRead + cacheWrite;
|
|
5491
|
+
const reasoning = chat && usage.completion_tokens_details ? record(usage.completion_tokens_details, "completion_tokens_details").reasoning_tokens : undefined;
|
|
5492
|
+
return {
|
|
5493
|
+
input_tokens: totalInput,
|
|
5494
|
+
output_tokens: output,
|
|
5495
|
+
total_tokens: totalInput + output,
|
|
5496
|
+
input_tokens_details: { cached_tokens: cacheRead },
|
|
5497
|
+
output_tokens_details: { reasoning_tokens: tokens(reasoning ?? prior.output_tokens_details?.reasoning_tokens, "reasoning_tokens") }
|
|
5498
|
+
};
|
|
5499
|
+
}
|
|
5500
|
+
function toolItem(id, name, args, names, status = "completed") {
|
|
5501
|
+
const original = restoreTool(name, names);
|
|
5502
|
+
const item = { id: `fc_${id}`, type: original.custom ? "custom_tool_call" : "function_call", call_id: id, name: original.name, status };
|
|
5503
|
+
if (original.namespace)
|
|
5504
|
+
item.namespace = original.namespace;
|
|
5505
|
+
if (original.custom)
|
|
5506
|
+
item.input = customInput(args);
|
|
5507
|
+
else {
|
|
5508
|
+
argumentObject(args);
|
|
5509
|
+
item.arguments = args;
|
|
5510
|
+
}
|
|
5511
|
+
return item;
|
|
5512
|
+
}
|
|
5513
|
+
function responsePayload(id, model, output, end, usage, error, createdAt = Math.floor(Date.now() / 1000)) {
|
|
5514
|
+
const result = { id, object: "response", created_at: createdAt, model, status: end.status, output, usage: Object.keys(usage).length ? usage : null };
|
|
5515
|
+
if (end.status === "incomplete")
|
|
5516
|
+
result.incomplete_details = { reason: end.reason };
|
|
5517
|
+
if (end.status === "failed")
|
|
5518
|
+
result.error = error ?? { code: end.reason, message: end.reason };
|
|
5519
|
+
return result;
|
|
5520
|
+
}
|
|
5521
|
+
|
|
5522
|
+
// packages/llms/src/responses-codec/request.ts
|
|
5523
|
+
var contentNormalizer = new OpenAIProtocolConversion({ trimWhitespace: false });
|
|
5524
|
+
// packages/llms/src/responses-codec/events.ts
|
|
5525
|
+
class ResponsesEventEncoder {
|
|
5526
|
+
protocol;
|
|
5527
|
+
model;
|
|
5528
|
+
toolNames;
|
|
5529
|
+
budget;
|
|
5530
|
+
id = `resp_${crypto.randomUUID().replaceAll("-", "")}`;
|
|
5531
|
+
createdAt = Math.floor(Date.now() / 1000);
|
|
5532
|
+
output = [];
|
|
5533
|
+
states = new Map;
|
|
5534
|
+
anthropicBlocks = new Map;
|
|
5535
|
+
usage = {};
|
|
5536
|
+
end;
|
|
5537
|
+
error;
|
|
5538
|
+
started = false;
|
|
5539
|
+
anthropicStarted = false;
|
|
5540
|
+
anthropicStopped = false;
|
|
5541
|
+
finalized = false;
|
|
5542
|
+
poisoned = false;
|
|
5543
|
+
sequence = 0;
|
|
5544
|
+
retained = 0;
|
|
5545
|
+
constructor(protocol, model, toolNames = new Map, configuredLimits) {
|
|
5546
|
+
this.protocol = protocol;
|
|
5547
|
+
this.model = model;
|
|
5548
|
+
this.toolNames = toolNames;
|
|
5549
|
+
this.budget = limits(configuredLimits);
|
|
5550
|
+
}
|
|
5551
|
+
event(type, fields = {}) {
|
|
5552
|
+
return { type, sequence_number: this.sequence++, ...fields };
|
|
5553
|
+
}
|
|
5554
|
+
start(events) {
|
|
5555
|
+
if (this.started)
|
|
5556
|
+
return;
|
|
5557
|
+
this.started = true;
|
|
5558
|
+
const payload = { id: this.id, object: "response", created_at: this.createdAt, model: this.model, status: "in_progress", output: [], usage: null };
|
|
5559
|
+
events.push(this.event("response.created", { response: payload }), this.event("response.in_progress", { response: { ...payload } }));
|
|
5560
|
+
}
|
|
5561
|
+
retain(text) {
|
|
5562
|
+
this.retained += bytes(text);
|
|
5563
|
+
if (this.retained > this.budget.maxOutputBytes)
|
|
5564
|
+
fail("resource_limit", "Accumulated response output exceeds maxOutputBytes");
|
|
5565
|
+
}
|
|
5566
|
+
state(key, kind) {
|
|
5567
|
+
const existing = this.states.get(key);
|
|
5568
|
+
if (existing) {
|
|
5569
|
+
if (existing.kind !== kind)
|
|
5570
|
+
fail("invalid_stream", "Output item changed kind");
|
|
5571
|
+
return existing;
|
|
5572
|
+
}
|
|
5573
|
+
if (this.output.length >= this.budget.maxItems)
|
|
5574
|
+
fail("resource_limit", "Too many output items");
|
|
5575
|
+
const state = { key, index: this.output.length, kind, id: `${this.id}_item_${this.output.length}`, text: "", name: "", callId: "", args: "", emittedInput: "", added: false, closed: false };
|
|
5576
|
+
this.states.set(key, state);
|
|
5577
|
+
this.output.push(state);
|
|
5578
|
+
return state;
|
|
5579
|
+
}
|
|
5580
|
+
fields(state) {
|
|
5581
|
+
return { response_id: this.id, item_id: state.id, output_index: state.index };
|
|
5582
|
+
}
|
|
5583
|
+
item(state, status, strict = false) {
|
|
5584
|
+
if (state.kind === "tool") {
|
|
5585
|
+
if (strict)
|
|
5586
|
+
return { ...toolItem(state.callId, state.name, state.args || "{}", this.toolNames, status), id: state.id };
|
|
5587
|
+
const original = state.original ?? restoreTool(state.name, this.toolNames);
|
|
5588
|
+
return {
|
|
5589
|
+
id: state.id,
|
|
5590
|
+
type: original.custom ? "custom_tool_call" : "function_call",
|
|
5591
|
+
call_id: state.callId,
|
|
5592
|
+
name: original.name,
|
|
5593
|
+
...original.namespace ? { namespace: original.namespace } : {},
|
|
5594
|
+
status,
|
|
5595
|
+
...original.custom ? { input: state.emittedInput } : { arguments: state.args }
|
|
5596
|
+
};
|
|
5597
|
+
}
|
|
5598
|
+
if (state.kind === "reasoning")
|
|
5599
|
+
return { id: state.id, type: "reasoning", summary: status === "in_progress" ? [] : [{ type: "summary_text", text: state.text }] };
|
|
5600
|
+
return {
|
|
5601
|
+
id: state.id,
|
|
5602
|
+
type: "message",
|
|
5603
|
+
role: "assistant",
|
|
5604
|
+
status,
|
|
5605
|
+
content: status === "in_progress" ? [] : [this.part(state)]
|
|
5606
|
+
};
|
|
5607
|
+
}
|
|
5608
|
+
part(state) {
|
|
5609
|
+
return state.kind === "refusal" ? { type: "refusal", refusal: state.text } : state.kind === "reasoning" ? { type: "summary_text", text: state.text } : { type: "output_text", text: state.text, annotations: [] };
|
|
5610
|
+
}
|
|
5611
|
+
add(state, events, final = false) {
|
|
5612
|
+
if (state.added)
|
|
5613
|
+
return;
|
|
5614
|
+
if (state.kind === "tool") {
|
|
5615
|
+
if (!state.callId || !state.name || this.toolNames.size && !this.toolNames.has(state.name))
|
|
5616
|
+
return;
|
|
5617
|
+
if (!final && !state.args && [...this.toolNames.keys()].some((name) => name !== state.name && name.startsWith(state.name)))
|
|
5618
|
+
return;
|
|
5619
|
+
state.original = restoreTool(state.name, this.toolNames);
|
|
5620
|
+
}
|
|
5621
|
+
state.added = true;
|
|
5622
|
+
const initial = this.item(state, "in_progress");
|
|
5623
|
+
if (state.kind === "tool") {
|
|
5624
|
+
if (state.original?.custom)
|
|
5625
|
+
initial.input = "";
|
|
5626
|
+
else
|
|
5627
|
+
initial.arguments = "";
|
|
5628
|
+
}
|
|
5629
|
+
events.push(this.event("response.output_item.added", { response_id: this.id, output_index: state.index, item: initial }));
|
|
5630
|
+
if (state.kind !== "tool") {
|
|
5631
|
+
const part = state.kind === "reasoning" ? { type: "summary_text", text: "" } : state.kind === "refusal" ? { type: "refusal", refusal: "" } : { type: "output_text", text: "", annotations: [] };
|
|
5632
|
+
events.push(this.event(state.kind === "reasoning" ? "response.reasoning_summary_part.added" : "response.content_part.added", { ...this.fields(state), [state.kind === "reasoning" ? "summary_index" : "content_index"]: 0, part }));
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
appendText(state, delta, events) {
|
|
5636
|
+
if (state.closed)
|
|
5637
|
+
fail("invalid_stream", "Delta arrived after content block stop");
|
|
5638
|
+
this.retain(delta);
|
|
5639
|
+
state.text += delta;
|
|
5640
|
+
this.add(state, events);
|
|
5641
|
+
const type = state.kind === "reasoning" ? "response.reasoning_summary_text.delta" : state.kind === "refusal" ? "response.refusal.delta" : "response.output_text.delta";
|
|
5642
|
+
if (delta)
|
|
5643
|
+
events.push(this.event(type, { ...this.fields(state), [state.kind === "reasoning" ? "summary_index" : "content_index"]: 0, delta }));
|
|
5644
|
+
}
|
|
5645
|
+
emitArgs(state, events, fragment = "", first = false) {
|
|
5646
|
+
if (!state.added)
|
|
5647
|
+
return;
|
|
5648
|
+
if (state.original?.custom) {
|
|
5649
|
+
const prefix = customInputPrefix(state.args);
|
|
5650
|
+
if (!prefix.startsWith(state.emittedInput))
|
|
5651
|
+
fail("invalid_tool_arguments", "Custom input prefix changed");
|
|
5652
|
+
const delta = prefix.slice(state.emittedInput.length);
|
|
5653
|
+
state.emittedInput = prefix;
|
|
5654
|
+
if (delta)
|
|
5655
|
+
events.push(this.event("response.custom_tool_call_input.delta", { ...this.fields(state), delta }));
|
|
5656
|
+
} else {
|
|
5657
|
+
const delta = first ? state.args : fragment;
|
|
5658
|
+
if (delta)
|
|
5659
|
+
events.push(this.event("response.function_call_arguments.delta", { ...this.fields(state), delta }));
|
|
5660
|
+
}
|
|
5661
|
+
}
|
|
5662
|
+
toolDelta(state, raw, events) {
|
|
5663
|
+
if (state.closed)
|
|
5664
|
+
fail("invalid_stream", "Tool delta arrived after content block stop");
|
|
5665
|
+
if (raw.id !== undefined) {
|
|
5666
|
+
const id = string(raw.id, "tool call id", true);
|
|
5667
|
+
if (state.callId && state.callId !== id)
|
|
5668
|
+
fail("invalid_stream", "Tool call id changed");
|
|
5669
|
+
if (!state.callId)
|
|
5670
|
+
this.retain(id);
|
|
5671
|
+
state.callId = id;
|
|
5672
|
+
}
|
|
5673
|
+
const fn = raw.function === undefined ? {} : record(raw.function, "tool function");
|
|
5674
|
+
if (fn.name !== undefined) {
|
|
5675
|
+
const name = string(fn.name, "tool name");
|
|
5676
|
+
if (state.added && name)
|
|
5677
|
+
fail("invalid_stream", "Tool name changed after output_item.added");
|
|
5678
|
+
this.retain(name);
|
|
5679
|
+
state.name += name;
|
|
5680
|
+
}
|
|
5681
|
+
const args = fn.arguments === undefined ? "" : string(fn.arguments, "tool arguments delta");
|
|
5682
|
+
this.retain(args);
|
|
5683
|
+
state.args = bounded(state.args + args, this.budget.maxArgumentBytes, "tool arguments");
|
|
5684
|
+
const wasAdded = state.added;
|
|
5685
|
+
this.add(state, events);
|
|
5686
|
+
this.emitArgs(state, events, args, !wasAdded);
|
|
5687
|
+
}
|
|
5688
|
+
push(raw) {
|
|
5689
|
+
if (this.poisoned)
|
|
5690
|
+
fail("invalid_stream", "Encoder cannot continue after a codec error");
|
|
5691
|
+
if (this.finalized)
|
|
5692
|
+
fail("invalid_stream", "Event arrived after response terminal");
|
|
5693
|
+
try {
|
|
5694
|
+
const chunk = record(raw, "stream event");
|
|
5695
|
+
serialized(chunk, this.budget.maxOutputBytes, "stream event");
|
|
5696
|
+
const events = [];
|
|
5697
|
+
this.start(events);
|
|
5698
|
+
if (chunk.error !== undefined || chunk.type === "error") {
|
|
5699
|
+
this.error = record(chunk.error, "upstream error");
|
|
5700
|
+
this.end = { status: "failed", reason: "upstream_error" };
|
|
5701
|
+
this.anthropicStopped = true;
|
|
5702
|
+
return [...events, ...this.complete()];
|
|
5703
|
+
}
|
|
5704
|
+
if (this.protocol === "chat_completions")
|
|
5705
|
+
this.chat(chunk, events);
|
|
5706
|
+
else
|
|
5707
|
+
this.anthropic(chunk, events);
|
|
5708
|
+
return events;
|
|
5709
|
+
} catch (error) {
|
|
5710
|
+
this.poisoned = true;
|
|
5711
|
+
throw error;
|
|
5712
|
+
}
|
|
5713
|
+
}
|
|
5714
|
+
chat(chunk, events) {
|
|
5715
|
+
const choices = list(chunk.choices, "choices");
|
|
5716
|
+
if (choices.length > 1)
|
|
5717
|
+
fail("unsupported_response", "Multiple response candidates are not supported");
|
|
5718
|
+
if (choices.length) {
|
|
5719
|
+
const choice = record(choices[0], "choice");
|
|
5720
|
+
if (choice.index !== undefined && choice.index !== 0)
|
|
5721
|
+
fail("unsupported_response", "Only choice index 0 is supported");
|
|
5722
|
+
const delta = record(choice.delta ?? {}, "choice delta");
|
|
5723
|
+
for (const key of Object.keys(delta))
|
|
5724
|
+
if (!["role", "content", "refusal", "reasoning_content", "reasoning", "tool_calls", "function_call", "annotations"].includes(key))
|
|
5725
|
+
fail("unsupported_content", `Unsupported Chat output field ${key}`);
|
|
5726
|
+
if (delta.annotations !== undefined && list(delta.annotations, "annotations").length)
|
|
5727
|
+
fail("unsupported_content", "Chat output annotations cannot be faithfully converted");
|
|
5728
|
+
if (delta.role !== undefined && delta.role !== "assistant")
|
|
5729
|
+
fail("unsupported_response", "Response role must be assistant");
|
|
5730
|
+
if (this.end && Object.values(delta).some((v) => v !== undefined && v !== null && v !== "" && (!Array.isArray(v) || v.length)))
|
|
5731
|
+
fail("invalid_stream", "Output arrived after finish_reason");
|
|
5732
|
+
const reasoning = delta.reasoning_content ?? delta.reasoning;
|
|
5733
|
+
if (reasoning !== undefined && reasoning !== null)
|
|
5734
|
+
this.appendText(this.state("reasoning", "reasoning"), string(reasoning, "reasoning delta"), events);
|
|
5735
|
+
if (delta.content !== undefined && delta.content !== null)
|
|
5736
|
+
this.appendText(this.state("text", "text"), string(delta.content, "text delta"), events);
|
|
5737
|
+
if (delta.refusal !== undefined && delta.refusal !== null)
|
|
5738
|
+
this.appendText(this.state("refusal", "refusal"), string(delta.refusal, "refusal delta"), events);
|
|
5739
|
+
if (delta.tool_calls !== undefined) {
|
|
5740
|
+
for (const rawTool of list(delta.tool_calls, "tool_calls")) {
|
|
5741
|
+
const tool = record(rawTool, "tool call");
|
|
5742
|
+
if (!Number.isSafeInteger(tool.index) || tool.index < 0)
|
|
5743
|
+
fail("invalid_stream", "Streamed tool requires a non-negative integer index");
|
|
5744
|
+
if (tool.type !== undefined && tool.type !== "function")
|
|
5745
|
+
fail("unsupported_tool", "Unknown upstream tool call type");
|
|
5746
|
+
this.toolDelta(this.state(`tool:${tool.index}`, "tool"), tool, events);
|
|
5747
|
+
}
|
|
5748
|
+
}
|
|
5749
|
+
if (delta.function_call !== undefined)
|
|
5750
|
+
fail("unsupported_response", "Legacy function_call lacks a stable call_id");
|
|
5751
|
+
if (choice.finish_reason !== undefined && choice.finish_reason !== null) {
|
|
5752
|
+
const next = terminal(choice.finish_reason, this.protocol);
|
|
5753
|
+
if (this.end && (this.end.status !== next.status || this.end.reason !== next.reason))
|
|
5754
|
+
fail("invalid_stream", "Conflicting finish reasons");
|
|
5755
|
+
this.end = next;
|
|
5756
|
+
}
|
|
5757
|
+
}
|
|
5758
|
+
this.usage = normalizeUsage(chunk.usage, this.protocol, this.usage);
|
|
5759
|
+
}
|
|
5760
|
+
anthropic(chunk, events) {
|
|
5761
|
+
if (chunk.type === "ping")
|
|
5762
|
+
return;
|
|
5763
|
+
if (this.anthropicStopped)
|
|
5764
|
+
fail("invalid_stream", "Event arrived after message_stop");
|
|
5765
|
+
if (chunk.type === "message_start") {
|
|
5766
|
+
if (this.anthropicStarted)
|
|
5767
|
+
fail("invalid_stream", "Duplicate message_start");
|
|
5768
|
+
const message = record(chunk.message, "message");
|
|
5769
|
+
this.anthropicStarted = true;
|
|
5770
|
+
this.usage = normalizeUsage(message.usage, this.protocol, this.usage);
|
|
5771
|
+
return;
|
|
5772
|
+
}
|
|
5773
|
+
if (!this.anthropicStarted)
|
|
5774
|
+
fail("invalid_stream", "Anthropic event arrived before message_start");
|
|
5775
|
+
if (chunk.type === "message_delta") {
|
|
5776
|
+
const delta = record(chunk.delta, "message delta");
|
|
5777
|
+
if (delta.stop_reason != null) {
|
|
5778
|
+
const next = terminal(delta.stop_reason, this.protocol);
|
|
5779
|
+
if (this.end && (this.end.status !== next.status || this.end.reason !== next.reason))
|
|
5780
|
+
fail("invalid_stream", "Conflicting stop reasons");
|
|
5781
|
+
this.end = next;
|
|
5782
|
+
}
|
|
5783
|
+
this.usage = normalizeUsage(chunk.usage, this.protocol, this.usage);
|
|
5784
|
+
return;
|
|
5785
|
+
}
|
|
5786
|
+
if (chunk.type === "message_stop") {
|
|
5787
|
+
if (!this.end)
|
|
5788
|
+
fail("missing_terminal", "message_stop has no preceding stop_reason");
|
|
5789
|
+
if ([...this.anthropicBlocks.values()].some((s) => !s.closed))
|
|
5790
|
+
fail("invalid_stream", "message_stop arrived before content_block_stop");
|
|
5791
|
+
this.anthropicStopped = true;
|
|
5792
|
+
return;
|
|
5793
|
+
}
|
|
5794
|
+
if (!Number.isSafeInteger(chunk.index) || chunk.index < 0)
|
|
5795
|
+
fail("invalid_stream", "Anthropic content requires a non-negative integer index");
|
|
5796
|
+
const index = chunk.index;
|
|
5797
|
+
if (this.end)
|
|
5798
|
+
fail("invalid_stream", "Content arrived after stop_reason");
|
|
5799
|
+
if (chunk.type === "content_block_start") {
|
|
5800
|
+
if (this.anthropicBlocks.has(index))
|
|
5801
|
+
fail("invalid_stream", "Duplicate content_block_start");
|
|
5802
|
+
const block = record(chunk.content_block, "content block");
|
|
5803
|
+
const kind = block.type === "tool_use" ? "tool" : block.type === "text" ? "text" : block.type === "thinking" ? "reasoning" : undefined;
|
|
5804
|
+
if (!kind)
|
|
5805
|
+
fail("unsupported_content", `Unsupported Anthropic block ${String(block.type)}`);
|
|
5806
|
+
const state = this.state(`block:${index}`, kind);
|
|
5807
|
+
this.anthropicBlocks.set(index, state);
|
|
5808
|
+
if (kind === "tool") {
|
|
5809
|
+
const input = record(block.input ?? {}, "tool input");
|
|
5810
|
+
this.toolDelta(state, { id: block.id, function: { name: block.name, ...Object.keys(input).length ? { arguments: serialized(input, this.budget.maxArgumentBytes, "tool input") } : {} } }, events);
|
|
5811
|
+
} else
|
|
5812
|
+
this.appendText(state, string(block[kind === "text" ? "text" : "thinking"] ?? "", "block text"), events);
|
|
5813
|
+
return;
|
|
5814
|
+
}
|
|
5815
|
+
const state = this.anthropicBlocks.get(index);
|
|
5816
|
+
if (!state || state.closed)
|
|
5817
|
+
fail("invalid_stream", "Content event has no open block");
|
|
5818
|
+
if (chunk.type === "content_block_stop") {
|
|
5819
|
+
state.closed = true;
|
|
5820
|
+
return;
|
|
5821
|
+
}
|
|
5822
|
+
if (chunk.type !== "content_block_delta")
|
|
5823
|
+
fail("unsupported_response", `Unknown Anthropic event ${String(chunk.type)}`);
|
|
5824
|
+
const delta = record(chunk.delta, "content delta");
|
|
5825
|
+
if (delta.type === "input_json_delta" && state.kind === "tool")
|
|
5826
|
+
this.toolDelta(state, { function: { arguments: delta.partial_json } }, events);
|
|
5827
|
+
else if (delta.type === "text_delta" && state.kind === "text")
|
|
5828
|
+
this.appendText(state, string(delta.text, "text delta"), events);
|
|
5829
|
+
else if (delta.type === "thinking_delta" && state.kind === "reasoning")
|
|
5830
|
+
this.appendText(state, string(delta.thinking, "thinking delta"), events);
|
|
5831
|
+
else if (delta.type === "signature_delta" && state.kind === "reasoning") {
|
|
5832
|
+
bounded(string(delta.signature, "signature"), this.budget.maxArgumentBytes, "signature");
|
|
5833
|
+
} else
|
|
5834
|
+
fail("unsupported_content", `Unsupported content delta ${String(delta.type)}`);
|
|
5835
|
+
}
|
|
5836
|
+
complete() {
|
|
5837
|
+
if (!this.end)
|
|
5838
|
+
fail("missing_terminal", "Stream ended without an explicit upstream terminal");
|
|
5839
|
+
const events = [];
|
|
5840
|
+
const items = [];
|
|
5841
|
+
const callIds = new Set;
|
|
5842
|
+
for (const state of this.output) {
|
|
5843
|
+
const strict = this.end.status === "completed";
|
|
5844
|
+
if (state.kind === "tool") {
|
|
5845
|
+
if (!state.callId || !state.name)
|
|
5846
|
+
fail("invalid_tool_arguments", "Tool call is missing id or name");
|
|
5847
|
+
if (callIds.has(state.callId))
|
|
5848
|
+
fail("invalid_tool_arguments", "Duplicate provider call_id");
|
|
5849
|
+
callIds.add(state.callId);
|
|
5850
|
+
state.original ??= restoreTool(state.name, this.toolNames);
|
|
5851
|
+
this.add(state, events, true);
|
|
5852
|
+
if (!state.added)
|
|
5853
|
+
fail("unknown_tool", `Unknown tool ${state.name}`);
|
|
5854
|
+
if (strict) {
|
|
5855
|
+
argumentObject(state.args || "{}");
|
|
5856
|
+
if (state.original.custom) {
|
|
5857
|
+
const text = customInput(state.args);
|
|
5858
|
+
if (!text.startsWith(state.emittedInput))
|
|
5859
|
+
fail("invalid_tool_arguments", "Custom tool input changed");
|
|
5860
|
+
if (text.length > state.emittedInput.length)
|
|
5861
|
+
events.push(this.event("response.custom_tool_call_input.delta", { ...this.fields(state), delta: text.slice(state.emittedInput.length) }));
|
|
5862
|
+
state.emittedInput = text;
|
|
5863
|
+
}
|
|
5864
|
+
}
|
|
5865
|
+
}
|
|
5866
|
+
const item = this.item(state, this.end.status === "completed" ? "completed" : "incomplete", strict);
|
|
5867
|
+
const fields = this.fields(state);
|
|
5868
|
+
if (state.kind === "tool") {
|
|
5869
|
+
const custom = state.original.custom;
|
|
5870
|
+
events.push(this.event(custom ? "response.custom_tool_call_input.done" : "response.function_call_arguments.done", { ...fields, [custom ? "input" : "arguments"]: custom ? item.input : item.arguments }));
|
|
5871
|
+
} else {
|
|
5872
|
+
const reasoning = state.kind === "reasoning";
|
|
5873
|
+
const textField = state.kind === "refusal" ? "refusal" : "text";
|
|
5874
|
+
events.push(this.event(reasoning ? "response.reasoning_summary_text.done" : state.kind === "refusal" ? "response.refusal.done" : "response.output_text.done", { ...fields, [reasoning ? "summary_index" : "content_index"]: 0, [textField]: state.text }));
|
|
5875
|
+
events.push(this.event(reasoning ? "response.reasoning_summary_part.done" : "response.content_part.done", { ...fields, [reasoning ? "summary_index" : "content_index"]: 0, part: this.part(state) }));
|
|
5876
|
+
}
|
|
5877
|
+
events.push(this.event("response.output_item.done", { response_id: this.id, output_index: state.index, item }));
|
|
5878
|
+
items.push(item);
|
|
5879
|
+
}
|
|
5880
|
+
const response = responsePayload(this.id, this.model, items, this.end, this.usage, this.error, this.createdAt);
|
|
5881
|
+
serialized(response, this.budget.maxOutputBytes, "final response");
|
|
5882
|
+
events.push(this.event(`response.${this.end.status}`, { response }));
|
|
5883
|
+
this.finalized = true;
|
|
5884
|
+
return events;
|
|
5885
|
+
}
|
|
5886
|
+
finish() {
|
|
5887
|
+
if (this.poisoned)
|
|
5888
|
+
fail("invalid_stream", "Encoder cannot finish after a codec error");
|
|
5889
|
+
if (this.finalized)
|
|
5890
|
+
return [];
|
|
5891
|
+
try {
|
|
5892
|
+
if (this.protocol === "anthropic_messages" && !this.anthropicStopped)
|
|
5893
|
+
fail("missing_terminal", "Anthropic stream ended before message_stop");
|
|
5894
|
+
return this.complete();
|
|
5895
|
+
} catch (error) {
|
|
5896
|
+
this.poisoned = true;
|
|
5897
|
+
throw error;
|
|
5898
|
+
}
|
|
5899
|
+
}
|
|
5900
|
+
}
|
|
5901
|
+
|
|
5902
|
+
// packages/llms/src/responses-codec/result.ts
|
|
5903
|
+
function encodeResponsesResult(raw, protocol, model, toolNames = new Map, configuredLimits) {
|
|
5904
|
+
const body = record(raw, "upstream response");
|
|
5905
|
+
const budget = limits(configuredLimits);
|
|
5906
|
+
serialized(body, budget.maxOutputBytes, "upstream response");
|
|
5907
|
+
if (body.error !== undefined || body.type === "error")
|
|
5908
|
+
return responsePayload(`resp_${crypto.randomUUID().replaceAll("-", "")}`, model, [], { status: "failed", reason: "upstream_error" }, {}, record(body.error, "upstream error"));
|
|
5909
|
+
const encoder = new ResponsesEventEncoder(protocol, model, toolNames, configuredLimits);
|
|
5910
|
+
if (protocol === "chat_completions") {
|
|
5911
|
+
const choices = list(body.choices, "choices");
|
|
5912
|
+
if (choices.length !== 1)
|
|
5913
|
+
fail("unsupported_response", "Exactly one response choice is required");
|
|
5914
|
+
const choice = record(choices[0], "choice");
|
|
5915
|
+
const message = record(choice.message, "message");
|
|
5916
|
+
const delta = { ...message };
|
|
5917
|
+
if (message.tool_calls !== undefined)
|
|
5918
|
+
delta.tool_calls = list(message.tool_calls, "tool_calls").map((tool, index) => ({ ...record(tool, "tool call"), index }));
|
|
5919
|
+
encoder.push({ choices: [{ index: choice.index ?? 0, delta, finish_reason: choice.finish_reason }], usage: body.usage });
|
|
5920
|
+
} else {
|
|
5921
|
+
encoder.push({ type: "message_start", message: { usage: body.usage } });
|
|
5922
|
+
for (const [index, rawBlock] of list(body.content, "content").entries()) {
|
|
5923
|
+
const block = record(rawBlock, "content block");
|
|
5924
|
+
encoder.push({ type: "content_block_start", index, content_block: block });
|
|
5925
|
+
encoder.push({ type: "content_block_stop", index });
|
|
5926
|
+
}
|
|
5927
|
+
encoder.push({ type: "message_delta", delta: { stop_reason: body.stop_reason } });
|
|
5928
|
+
encoder.push({ type: "message_stop" });
|
|
5929
|
+
}
|
|
5930
|
+
const end = encoder.finish().at(-1);
|
|
5931
|
+
if (!end)
|
|
5932
|
+
fail("missing_terminal", "JSON response has no terminal result");
|
|
5933
|
+
return record(end.response, "Responses result");
|
|
5934
|
+
}
|
|
5340
5935
|
// plugins/openai-messages-to-chat/server/index.ts
|
|
5341
5936
|
var RESPONSE_STATE_REFERENCE_FIELDS = [
|
|
5342
5937
|
"previous_response_id",
|
|
@@ -5354,7 +5949,7 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5354
5949
|
adaptedRequestIds = new Set;
|
|
5355
5950
|
responsesAdaptedRequestIds = new Set;
|
|
5356
5951
|
streamConversionRequestIds = new Set;
|
|
5357
|
-
|
|
5952
|
+
responsesRequestModels = new Map;
|
|
5358
5953
|
responsesRequestMessages = new Map;
|
|
5359
5954
|
responsesRequestConversationIds = new Map;
|
|
5360
5955
|
responsesHistoryByResponseId = new Map;
|
|
@@ -5384,7 +5979,7 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5384
5979
|
this.adaptedRequestIds.delete(ctx.requestId);
|
|
5385
5980
|
this.responsesAdaptedRequestIds.delete(ctx.requestId);
|
|
5386
5981
|
this.streamConversionRequestIds.delete(ctx.requestId);
|
|
5387
|
-
this.
|
|
5982
|
+
this.responsesRequestModels.delete(ctx.requestId);
|
|
5388
5983
|
this.responsesRequestMessages.delete(ctx.requestId);
|
|
5389
5984
|
this.responsesRequestConversationIds.delete(ctx.requestId);
|
|
5390
5985
|
this.validationErrors.delete(ctx.requestId);
|
|
@@ -5414,6 +6009,7 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5414
6009
|
ctx.url.pathname = "/v1/chat/completions";
|
|
5415
6010
|
ctx.body = this.normalizeAssistantToolCallReasoningContent(validation.body);
|
|
5416
6011
|
this.responsesAdaptedRequestIds.add(ctx.requestId);
|
|
6012
|
+
this.responsesRequestModels.set(ctx.requestId, String(validation.body.model));
|
|
5417
6013
|
this.responsesRequestMessages.set(ctx.requestId, this.extractMessagesFromDowngradedBody(validation.body));
|
|
5418
6014
|
if (stateReference.conversationId) {
|
|
5419
6015
|
this.responsesRequestConversationIds.set(ctx.requestId, stateReference.conversationId);
|
|
@@ -5443,20 +6039,21 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5443
6039
|
if (!isRecord4(parsedBody)) {
|
|
5444
6040
|
return response;
|
|
5445
6041
|
}
|
|
5446
|
-
const converted = this.convertChatCompletionToResponsesPayload(parsedBody);
|
|
5447
|
-
if (
|
|
5448
|
-
|
|
6042
|
+
const converted = this.convertChatCompletionToResponsesPayload(parsedBody, this.responsesRequestModels.get(ctx.requestId) ?? "");
|
|
6043
|
+
if (converted.status !== "failed") {
|
|
6044
|
+
const conversationId = this.responsesRequestConversationIds.get(ctx.requestId);
|
|
6045
|
+
const baseMessages = this.responsesRequestMessages.get(ctx.requestId) ?? [];
|
|
6046
|
+
const assistantMessage = this.extractAssistantMessageFromChatCompletionPayload(parsedBody);
|
|
6047
|
+
const history = assistantMessage ? [...baseMessages, assistantMessage] : baseMessages;
|
|
6048
|
+
this.storeResponsesState(String(converted.id), history, conversationId);
|
|
5449
6049
|
}
|
|
5450
|
-
const
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
const assistantMessage = this.extractAssistantMessageFromChatCompletionPayload(parsedBody);
|
|
5454
|
-
const history = assistantMessage ? [...baseMessages, assistantMessage] : baseMessages;
|
|
5455
|
-
this.storeResponsesState(responseId, history, conversationId);
|
|
6050
|
+
const headers = new Headers(response.headers);
|
|
6051
|
+
headers.delete("content-length");
|
|
6052
|
+
headers.delete("content-encoding");
|
|
5456
6053
|
return new Response(JSON.stringify(converted), {
|
|
5457
6054
|
status: response.status,
|
|
5458
6055
|
statusText: response.statusText,
|
|
5459
|
-
headers
|
|
6056
|
+
headers
|
|
5460
6057
|
});
|
|
5461
6058
|
}
|
|
5462
6059
|
if (!this.adaptedRequestIds.has(ctx.requestId)) {
|
|
@@ -5476,20 +6073,21 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5476
6073
|
});
|
|
5477
6074
|
hooks.onStreamChunk.tapPromise({ name: "openai-messages-to-chat", stage: 10 }, async (envelope, ctx) => {
|
|
5478
6075
|
const chunk = structuredClone(envelope.json);
|
|
5479
|
-
if (chunk === undefined)
|
|
5480
|
-
return null;
|
|
5481
6076
|
const converterContext = { ...ctx, sseEvent: envelope };
|
|
5482
6077
|
if (this.responsesAdaptedRequestIds.has(ctx.requestId)) {
|
|
5483
|
-
if (
|
|
5484
|
-
return
|
|
6078
|
+
if (envelope.data === "[DONE]")
|
|
6079
|
+
return [];
|
|
6080
|
+
const encoder = this.getResponsesEncoder(ctx, isRecord4(chunk) ? chunk.model : undefined);
|
|
6081
|
+
let normalized = chunk;
|
|
6082
|
+
if (!ctx.streamState.has("responses_legacy_message") && isRecord4(chunk) && Array.isArray(chunk.choices) && chunk.choices.length === 1 && isRecord4(chunk.choices[0])) {
|
|
6083
|
+
const choice = chunk.choices[0];
|
|
6084
|
+
const delta = isRecord4(choice.delta) ? choice.delta : {};
|
|
6085
|
+
normalized = { ...chunk, choices: [{ ...choice, delta: { ...delta, content: delta.content ?? "" } }] };
|
|
6086
|
+
ctx.streamState.set("responses_legacy_message", true);
|
|
5485
6087
|
}
|
|
5486
|
-
|
|
5487
|
-
if (converted.length > 0) {
|
|
5488
|
-
this.responsesStreamConversionRequestIds.add(ctx.requestId);
|
|
5489
|
-
}
|
|
5490
|
-
return protocolSSEOutput(converted, "responses", envelope);
|
|
6088
|
+
return protocolSSEOutput(encoder.push(normalized), "responses", envelope);
|
|
5491
6089
|
}
|
|
5492
|
-
if (!this.adaptedRequestIds.has(ctx.requestId)) {
|
|
6090
|
+
if (chunk === undefined || !this.adaptedRequestIds.has(ctx.requestId)) {
|
|
5493
6091
|
return null;
|
|
5494
6092
|
}
|
|
5495
6093
|
if (!this.messagesCompatibilityNormalizer.isOpenAIStreamChunk(chunk)) {
|
|
@@ -5503,10 +6101,13 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5503
6101
|
return protocolSSEOutput(this.protocolConversion.ensureMessagesStreamCompatibility(converted, ctx), "anthropic", envelope);
|
|
5504
6102
|
});
|
|
5505
6103
|
hooks.onFlushStream.tapPromise({ name: "openai-messages-to-chat", stage: 10 }, async (chunks, ctx) => {
|
|
5506
|
-
if (this.
|
|
5507
|
-
this.
|
|
5508
|
-
const
|
|
5509
|
-
|
|
6104
|
+
if (this.responsesAdaptedRequestIds.has(ctx.requestId)) {
|
|
6105
|
+
const completionEvents = this.getResponsesEncoder(ctx).finish();
|
|
6106
|
+
for (const event of completionEvents) {
|
|
6107
|
+
if (isRecord4(event.response) && event.response.status !== "failed") {
|
|
6108
|
+
this.persistResponsesStateFromResult(ctx.requestId, event.response);
|
|
6109
|
+
}
|
|
6110
|
+
}
|
|
5510
6111
|
return [...chunks, ...protocolSSEOutput(completionEvents, "responses")];
|
|
5511
6112
|
}
|
|
5512
6113
|
if (!this.streamConversionRequestIds.has(ctx.requestId)) {
|
|
@@ -5521,7 +6122,7 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5521
6122
|
this.adaptedRequestIds.delete(ctx.requestId);
|
|
5522
6123
|
this.responsesAdaptedRequestIds.delete(ctx.requestId);
|
|
5523
6124
|
this.streamConversionRequestIds.delete(ctx.requestId);
|
|
5524
|
-
this.
|
|
6125
|
+
this.responsesRequestModels.delete(ctx.requestId);
|
|
5525
6126
|
this.responsesRequestMessages.delete(ctx.requestId);
|
|
5526
6127
|
this.responsesRequestConversationIds.delete(ctx.requestId);
|
|
5527
6128
|
this.validationErrors.delete(ctx.requestId);
|
|
@@ -5531,7 +6132,7 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5531
6132
|
this.adaptedRequestIds.clear();
|
|
5532
6133
|
this.responsesAdaptedRequestIds.clear();
|
|
5533
6134
|
this.streamConversionRequestIds.clear();
|
|
5534
|
-
this.
|
|
6135
|
+
this.responsesRequestModels.clear();
|
|
5535
6136
|
this.responsesRequestMessages.clear();
|
|
5536
6137
|
this.responsesRequestConversationIds.clear();
|
|
5537
6138
|
this.responsesHistoryByResponseId.clear();
|
|
@@ -5734,32 +6335,40 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5734
6335
|
}
|
|
5735
6336
|
return null;
|
|
5736
6337
|
}
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
if (!streamState) {
|
|
6338
|
+
persistResponsesStateFromResult(requestId, response) {
|
|
6339
|
+
if (response.status === "failed" || !Array.isArray(response.output))
|
|
5740
6340
|
return;
|
|
5741
|
-
}
|
|
5742
|
-
const
|
|
5743
|
-
const
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
6341
|
+
const assistant = { role: "assistant", content: null };
|
|
6342
|
+
const text = [];
|
|
6343
|
+
const reasoning = [];
|
|
6344
|
+
const tools = [];
|
|
6345
|
+
for (const item of response.output) {
|
|
6346
|
+
if (!isRecord4(item))
|
|
6347
|
+
continue;
|
|
6348
|
+
if (item.type === "message" && Array.isArray(item.content)) {
|
|
6349
|
+
for (const part of item.content) {
|
|
6350
|
+
if (isRecord4(part) && part.type === "output_text" && typeof part.text === "string")
|
|
6351
|
+
text.push(part.text);
|
|
6352
|
+
if (isRecord4(part) && part.type === "refusal" && typeof part.refusal === "string")
|
|
6353
|
+
assistant.refusal = part.refusal;
|
|
6354
|
+
}
|
|
6355
|
+
} else if (item.type === "function_call") {
|
|
6356
|
+
tools.push({ id: item.call_id, type: "function", function: { name: item.name, arguments: item.arguments } });
|
|
6357
|
+
} else if (item.type === "reasoning" && Array.isArray(item.summary)) {
|
|
6358
|
+
for (const part of item.summary)
|
|
6359
|
+
if (isRecord4(part) && typeof part.text === "string")
|
|
6360
|
+
reasoning.push(part.text);
|
|
6361
|
+
}
|
|
6362
|
+
}
|
|
6363
|
+
if (text.length)
|
|
6364
|
+
assistant.content = text.join("");
|
|
6365
|
+
if (tools.length)
|
|
6366
|
+
assistant.tool_calls = tools;
|
|
6367
|
+
if (reasoning.length)
|
|
6368
|
+
assistant.reasoning_content = reasoning.join("");
|
|
6369
|
+
const base = this.responsesRequestMessages.get(requestId) ?? [];
|
|
6370
|
+
const history = text.length || tools.length || reasoning.length || assistant.refusal ? [...base, assistant] : base;
|
|
6371
|
+
this.storeResponsesState(String(response.id), history, this.responsesRequestConversationIds.get(requestId));
|
|
5763
6372
|
}
|
|
5764
6373
|
storeResponsesState(responseId, history, conversationId) {
|
|
5765
6374
|
const normalizedResponseId = this.normalizeNonEmptyString(responseId);
|
|
@@ -5887,500 +6496,41 @@ var OpenAIMessagesToChatPlugin = definePlugin(class {
|
|
|
5887
6496
|
}
|
|
5888
6497
|
return { message: rawMessage, changed: false };
|
|
5889
6498
|
}
|
|
5890
|
-
convertChatCompletionToResponsesPayload(payload) {
|
|
5891
|
-
if (payload.object === "response")
|
|
6499
|
+
convertChatCompletionToResponsesPayload(payload, requestModel) {
|
|
6500
|
+
if (payload.object === "response")
|
|
5892
6501
|
return payload;
|
|
5893
|
-
|
|
5894
|
-
if (!Array.isArray(payload.choices)) {
|
|
5895
|
-
return
|
|
5896
|
-
}
|
|
5897
|
-
const
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
for (let choiceIndex = 0;choiceIndex < choices.length; choiceIndex += 1) {
|
|
5907
|
-
const choice = choices[choiceIndex];
|
|
5908
|
-
const message = choice.message;
|
|
5909
|
-
const content = this.normalizeChatMessageContentToResponseOutputText(message.content);
|
|
5910
|
-
const messageId = choices.length === 1 ? `${responseId}_msg` : `${responseId}_msg_${choiceIndex}`;
|
|
5911
|
-
const messageContent = content ? [
|
|
5912
|
-
{
|
|
5913
|
-
type: "output_text",
|
|
5914
|
-
text: content,
|
|
5915
|
-
annotations: []
|
|
5916
|
-
}
|
|
5917
|
-
] : [];
|
|
5918
|
-
output.push({
|
|
5919
|
-
id: messageId,
|
|
5920
|
-
type: "message",
|
|
5921
|
-
role: "assistant",
|
|
5922
|
-
status: "completed",
|
|
5923
|
-
content: messageContent
|
|
5924
|
-
});
|
|
5925
|
-
const toolCalls = this.normalizeToolCalls(message.tool_calls) ?? [];
|
|
5926
|
-
for (let toolCallIndex = 0;toolCallIndex < toolCalls.length; toolCallIndex += 1) {
|
|
5927
|
-
const toolCall = toolCalls[toolCallIndex];
|
|
5928
|
-
const toolFunction = isRecord4(toolCall.function) ? toolCall.function : undefined;
|
|
5929
|
-
const toolCallId = typeof toolCall.id === "string" && toolCall.id.trim().length > 0 ? toolCall.id.trim() : `${responseId}_choice_${choiceIndex}_call_${toolCallIndex}`;
|
|
5930
|
-
const argumentsPayload = typeof toolFunction?.arguments === "string" ? toolFunction.arguments : JSON.stringify(toolFunction?.arguments ?? {});
|
|
5931
|
-
output.push({
|
|
5932
|
-
id: toolCallId,
|
|
5933
|
-
type: "function_call",
|
|
5934
|
-
call_id: toolCallId,
|
|
5935
|
-
name: typeof toolFunction?.name === "string" ? toolFunction.name : "",
|
|
5936
|
-
arguments: argumentsPayload,
|
|
5937
|
-
status: "completed"
|
|
5938
|
-
});
|
|
5939
|
-
}
|
|
5940
|
-
if (typeof choice.finish_reason === "string" && choice.finish_reason.length > 0) {
|
|
5941
|
-
finishReasons.push(choice.finish_reason);
|
|
5942
|
-
}
|
|
5943
|
-
}
|
|
5944
|
-
const usage = isRecord4(payload.usage) ? payload.usage : {};
|
|
5945
|
-
const terminal = this.aggregateTerminalFromFinishReasons(finishReasons);
|
|
5946
|
-
const converted = {
|
|
5947
|
-
id: responseId,
|
|
5948
|
-
object: "response",
|
|
5949
|
-
created_at: createdAt,
|
|
5950
|
-
model,
|
|
5951
|
-
status: this.terminalStatusFromType(terminal.type),
|
|
5952
|
-
output,
|
|
5953
|
-
usage: {
|
|
5954
|
-
input_tokens: typeof usage.prompt_tokens === "number" ? usage.prompt_tokens : 0,
|
|
5955
|
-
output_tokens: typeof usage.completion_tokens === "number" ? usage.completion_tokens : 0,
|
|
5956
|
-
total_tokens: typeof usage.total_tokens === "number" ? usage.total_tokens : (typeof usage.prompt_tokens === "number" ? usage.prompt_tokens : 0) + (typeof usage.completion_tokens === "number" ? usage.completion_tokens : 0)
|
|
5957
|
-
}
|
|
5958
|
-
};
|
|
5959
|
-
if (terminal.type === "response.incomplete") {
|
|
5960
|
-
converted.incomplete_details = {
|
|
5961
|
-
reason: terminal.reason
|
|
5962
|
-
};
|
|
5963
|
-
}
|
|
5964
|
-
if (terminal.type === "response.failed") {
|
|
5965
|
-
converted.error = {
|
|
5966
|
-
code: "completion_terminated",
|
|
5967
|
-
message: terminal.reason
|
|
5968
|
-
};
|
|
5969
|
-
}
|
|
5970
|
-
if (finishReasons.length > 0) {
|
|
5971
|
-
converted.metadata = {
|
|
5972
|
-
finish_reason: finishReasons[0],
|
|
5973
|
-
finish_reasons: finishReasons
|
|
5974
|
-
};
|
|
5975
|
-
}
|
|
5976
|
-
return converted;
|
|
5977
|
-
}
|
|
5978
|
-
convertChatCompletionChunkToResponsesEvents(chunk, ctx) {
|
|
5979
|
-
if (!isRecord4(chunk) || !Array.isArray(chunk.choices)) {
|
|
5980
|
-
return [];
|
|
5981
|
-
}
|
|
5982
|
-
const state = this.getOrCreateResponsesStreamState(chunk, ctx.streamState);
|
|
5983
|
-
const events = [];
|
|
5984
|
-
if (ctx.streamState.get("responses_stream_started") !== true) {
|
|
5985
|
-
events.push({
|
|
5986
|
-
type: "response.created",
|
|
5987
|
-
response: {
|
|
5988
|
-
id: state.responseId,
|
|
5989
|
-
object: "response",
|
|
5990
|
-
created_at: state.createdAt,
|
|
5991
|
-
model: state.model,
|
|
5992
|
-
status: "in_progress",
|
|
5993
|
-
output: []
|
|
5994
|
-
}
|
|
5995
|
-
});
|
|
5996
|
-
events.push({
|
|
5997
|
-
type: "response.in_progress",
|
|
5998
|
-
response: {
|
|
5999
|
-
id: state.responseId,
|
|
6000
|
-
object: "response",
|
|
6001
|
-
created_at: state.createdAt,
|
|
6002
|
-
model: state.model,
|
|
6003
|
-
status: "in_progress",
|
|
6004
|
-
output: []
|
|
6005
|
-
}
|
|
6006
|
-
});
|
|
6007
|
-
events.push({
|
|
6008
|
-
type: "response.output_item.added",
|
|
6009
|
-
response_id: state.responseId,
|
|
6010
|
-
output_index: 0,
|
|
6011
|
-
item: {
|
|
6012
|
-
id: state.messageId,
|
|
6013
|
-
type: "message",
|
|
6014
|
-
role: "assistant",
|
|
6015
|
-
status: "in_progress",
|
|
6016
|
-
content: []
|
|
6017
|
-
}
|
|
6018
|
-
});
|
|
6019
|
-
ctx.streamState.set("responses_stream_started", true);
|
|
6020
|
-
}
|
|
6021
|
-
for (const choice of chunk.choices) {
|
|
6022
|
-
if (!isRecord4(choice)) {
|
|
6023
|
-
continue;
|
|
6024
|
-
}
|
|
6025
|
-
const delta = isRecord4(choice.delta) ? choice.delta : undefined;
|
|
6026
|
-
if (delta) {
|
|
6027
|
-
if (typeof delta.content === "string" && delta.content.length > 0) {
|
|
6028
|
-
if (!state.hasTextContentPart) {
|
|
6029
|
-
events.push({
|
|
6030
|
-
type: "response.content_part.added",
|
|
6031
|
-
response_id: state.responseId,
|
|
6032
|
-
item_id: state.messageId,
|
|
6033
|
-
output_index: 0,
|
|
6034
|
-
content_index: 0,
|
|
6035
|
-
part: {
|
|
6036
|
-
type: "output_text",
|
|
6037
|
-
text: "",
|
|
6038
|
-
annotations: []
|
|
6039
|
-
}
|
|
6040
|
-
});
|
|
6041
|
-
state.hasTextContentPart = true;
|
|
6042
|
-
}
|
|
6043
|
-
state.messageText += delta.content;
|
|
6044
|
-
events.push({
|
|
6045
|
-
type: "response.output_text.delta",
|
|
6046
|
-
response_id: state.responseId,
|
|
6047
|
-
item_id: state.messageId,
|
|
6048
|
-
output_index: 0,
|
|
6049
|
-
content_index: 0,
|
|
6050
|
-
delta: delta.content
|
|
6051
|
-
});
|
|
6052
|
-
}
|
|
6053
|
-
if (Array.isArray(delta.tool_calls)) {
|
|
6054
|
-
for (const rawToolCall of delta.tool_calls) {
|
|
6055
|
-
if (!isRecord4(rawToolCall)) {
|
|
6056
|
-
continue;
|
|
6057
|
-
}
|
|
6058
|
-
const toolCallIndex = typeof rawToolCall.index === "number" ? rawToolCall.index : state.toolCalls.length;
|
|
6059
|
-
const functionData = isRecord4(rawToolCall.function) ? rawToolCall.function : {};
|
|
6060
|
-
const idFromDelta = typeof rawToolCall.id === "string" && rawToolCall.id.trim().length > 0 ? rawToolCall.id.trim() : undefined;
|
|
6061
|
-
const existingId = state.toolCallIndexToId.get(toolCallIndex);
|
|
6062
|
-
const toolCallId = existingId ?? idFromDelta ?? `${state.responseId}_call_${toolCallIndex}`;
|
|
6063
|
-
let toolCall = state.toolCalls.find((item) => item.id === toolCallId);
|
|
6064
|
-
const firstSeen = !toolCall;
|
|
6065
|
-
if (!toolCall) {
|
|
6066
|
-
toolCall = {
|
|
6067
|
-
id: toolCallId,
|
|
6068
|
-
name: "",
|
|
6069
|
-
arguments: ""
|
|
6070
|
-
};
|
|
6071
|
-
state.toolCalls.push(toolCall);
|
|
6072
|
-
state.toolCallIndexToId.set(toolCallIndex, toolCallId);
|
|
6073
|
-
}
|
|
6074
|
-
if (typeof functionData.name === "string" && functionData.name.length > 0) {
|
|
6075
|
-
toolCall.name = functionData.name;
|
|
6076
|
-
}
|
|
6077
|
-
if (firstSeen) {
|
|
6078
|
-
events.push({
|
|
6079
|
-
type: "response.output_item.added",
|
|
6080
|
-
response_id: state.responseId,
|
|
6081
|
-
output_index: state.toolCalls.length,
|
|
6082
|
-
item: {
|
|
6083
|
-
id: toolCall.id,
|
|
6084
|
-
type: "function_call",
|
|
6085
|
-
call_id: toolCall.id,
|
|
6086
|
-
name: toolCall.name,
|
|
6087
|
-
arguments: "",
|
|
6088
|
-
status: "in_progress"
|
|
6089
|
-
}
|
|
6090
|
-
});
|
|
6091
|
-
}
|
|
6092
|
-
if (typeof functionData.arguments === "string" && functionData.arguments.length > 0) {
|
|
6093
|
-
toolCall.arguments += functionData.arguments;
|
|
6094
|
-
const toolOutputIndex = state.toolCalls.indexOf(toolCall) + 1;
|
|
6095
|
-
events.push({
|
|
6096
|
-
type: "response.function_call_arguments.delta",
|
|
6097
|
-
response_id: state.responseId,
|
|
6098
|
-
item_id: toolCall.id,
|
|
6099
|
-
output_index: toolOutputIndex,
|
|
6100
|
-
delta: functionData.arguments
|
|
6101
|
-
});
|
|
6102
|
-
}
|
|
6103
|
-
}
|
|
6104
|
-
}
|
|
6105
|
-
}
|
|
6106
|
-
if (typeof choice.finish_reason === "string" && choice.finish_reason.length > 0) {
|
|
6107
|
-
state.finishReason = choice.finish_reason;
|
|
6108
|
-
const terminal = this.mapFinishReasonToTerminalEvent(choice.finish_reason);
|
|
6109
|
-
if (terminal) {
|
|
6110
|
-
state.terminalEventType = terminal.type;
|
|
6111
|
-
state.terminalReason = terminal.reason;
|
|
6112
|
-
}
|
|
6113
|
-
}
|
|
6114
|
-
}
|
|
6115
|
-
if (isRecord4(chunk.usage)) {
|
|
6116
|
-
state.usage = {
|
|
6117
|
-
input_tokens: typeof chunk.usage.prompt_tokens === "number" ? chunk.usage.prompt_tokens : state.usage.input_tokens,
|
|
6118
|
-
output_tokens: typeof chunk.usage.completion_tokens === "number" ? chunk.usage.completion_tokens : state.usage.output_tokens,
|
|
6119
|
-
total_tokens: typeof chunk.usage.total_tokens === "number" ? chunk.usage.total_tokens : state.usage.total_tokens
|
|
6120
|
-
};
|
|
6121
|
-
}
|
|
6122
|
-
return events;
|
|
6123
|
-
}
|
|
6124
|
-
buildResponsesStreamCompletionEvents(ctx) {
|
|
6125
|
-
const state = ctx.streamState.get("responses_stream_state");
|
|
6126
|
-
if (!state) {
|
|
6127
|
-
return [];
|
|
6128
|
-
}
|
|
6129
|
-
const events = [];
|
|
6130
|
-
const output = [];
|
|
6131
|
-
const messageContentPart = {
|
|
6132
|
-
type: "output_text",
|
|
6133
|
-
text: state.messageText,
|
|
6134
|
-
annotations: []
|
|
6135
|
-
};
|
|
6136
|
-
const messageContent = state.hasTextContentPart ? [messageContentPart] : [];
|
|
6137
|
-
const messageItem = {
|
|
6138
|
-
id: state.messageId,
|
|
6139
|
-
type: "message",
|
|
6140
|
-
role: "assistant",
|
|
6141
|
-
status: "completed",
|
|
6142
|
-
content: messageContent
|
|
6143
|
-
};
|
|
6144
|
-
output.push(messageItem);
|
|
6145
|
-
if (state.hasTextContentPart) {
|
|
6146
|
-
events.push({
|
|
6147
|
-
type: "response.output_text.done",
|
|
6148
|
-
response_id: state.responseId,
|
|
6149
|
-
item_id: state.messageId,
|
|
6150
|
-
output_index: 0,
|
|
6151
|
-
content_index: 0,
|
|
6152
|
-
text: state.messageText
|
|
6153
|
-
});
|
|
6154
|
-
events.push({
|
|
6155
|
-
type: "response.content_part.done",
|
|
6156
|
-
response_id: state.responseId,
|
|
6157
|
-
item_id: state.messageId,
|
|
6158
|
-
output_index: 0,
|
|
6159
|
-
content_index: 0,
|
|
6160
|
-
part: messageContentPart
|
|
6161
|
-
});
|
|
6162
|
-
}
|
|
6163
|
-
events.push({
|
|
6164
|
-
type: "response.output_item.done",
|
|
6165
|
-
response_id: state.responseId,
|
|
6166
|
-
output_index: 0,
|
|
6167
|
-
item: messageItem
|
|
6502
|
+
const model = typeof payload.model === "string" ? payload.model : requestModel;
|
|
6503
|
+
if (!Array.isArray(payload.choices) || payload.choices.length === 0) {
|
|
6504
|
+
return encodeResponsesResult(payload, "chat_completions", model);
|
|
6505
|
+
}
|
|
6506
|
+
const candidates = payload.choices.map((rawChoice) => {
|
|
6507
|
+
if (!isRecord4(rawChoice) || !isRecord4(rawChoice.message)) {
|
|
6508
|
+
return encodeResponsesResult({ ...payload, choices: [rawChoice] }, "chat_completions", model);
|
|
6509
|
+
}
|
|
6510
|
+
const message = { ...rawChoice.message, content: rawChoice.message.content ?? "" };
|
|
6511
|
+
const toolCalls = this.normalizeToolCalls(message.tool_calls);
|
|
6512
|
+
if (toolCalls !== undefined)
|
|
6513
|
+
message.tool_calls = toolCalls;
|
|
6514
|
+
return encodeResponsesResult({ ...payload, choices: [{ ...rawChoice, index: 0, message }] }, "chat_completions", model);
|
|
6168
6515
|
});
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
arguments: toolCall.arguments,
|
|
6177
|
-
status: "completed"
|
|
6178
|
-
};
|
|
6179
|
-
events.push({
|
|
6180
|
-
type: "response.function_call_arguments.done",
|
|
6181
|
-
response_id: state.responseId,
|
|
6182
|
-
item_id: toolCall.id,
|
|
6183
|
-
output_index: toolOutputIndex,
|
|
6184
|
-
arguments: toolCall.arguments
|
|
6185
|
-
});
|
|
6186
|
-
events.push({
|
|
6187
|
-
type: "response.output_item.done",
|
|
6188
|
-
response_id: state.responseId,
|
|
6189
|
-
output_index: toolOutputIndex,
|
|
6190
|
-
item: toolItem
|
|
6191
|
-
});
|
|
6192
|
-
output.push(toolItem);
|
|
6193
|
-
}
|
|
6194
|
-
const normalizedUsage = {
|
|
6195
|
-
input_tokens: state.usage.input_tokens,
|
|
6196
|
-
output_tokens: state.usage.output_tokens,
|
|
6197
|
-
total_tokens: state.usage.total_tokens > 0 ? state.usage.total_tokens : state.usage.input_tokens + state.usage.output_tokens
|
|
6198
|
-
};
|
|
6199
|
-
const terminal = this.resolveTerminalEvent(state);
|
|
6200
|
-
const responsePayload = {
|
|
6201
|
-
id: state.responseId,
|
|
6202
|
-
object: "response",
|
|
6203
|
-
created_at: state.createdAt,
|
|
6204
|
-
model: state.model,
|
|
6205
|
-
status: terminal.status,
|
|
6206
|
-
output,
|
|
6207
|
-
usage: normalizedUsage,
|
|
6208
|
-
metadata: {
|
|
6209
|
-
finish_reason: state.finishReason || terminal.reason
|
|
6210
|
-
}
|
|
6211
|
-
};
|
|
6212
|
-
if (terminal.type === "response.incomplete") {
|
|
6213
|
-
responsePayload.incomplete_details = {
|
|
6214
|
-
reason: terminal.reason
|
|
6215
|
-
};
|
|
6516
|
+
const priority = (status) => status === "failed" ? 3 : status === "incomplete" ? 2 : 1;
|
|
6517
|
+
const terminal = candidates.reduce((selected, candidate) => priority(candidate.status) > priority(selected.status) ? candidate : selected);
|
|
6518
|
+
const converted = { ...terminal, id: candidates[0].id, output: candidates.flatMap((candidate) => candidate.output) };
|
|
6519
|
+
const finishReasons = payload.choices.filter(isRecord4).map((choice) => choice.finish_reason);
|
|
6520
|
+
converted.metadata = { finish_reason: finishReasons[0], finish_reasons: finishReasons };
|
|
6521
|
+
if (converted.status === "failed" && isRecord4(converted.error)) {
|
|
6522
|
+
converted.error = { ...converted.error, code: "completion_terminated" };
|
|
6216
6523
|
}
|
|
6217
|
-
|
|
6218
|
-
responsePayload.error = {
|
|
6219
|
-
code: "stream_terminated",
|
|
6220
|
-
message: terminal.reason
|
|
6221
|
-
};
|
|
6222
|
-
}
|
|
6223
|
-
events.push({
|
|
6224
|
-
type: terminal.type,
|
|
6225
|
-
response: responsePayload
|
|
6226
|
-
});
|
|
6227
|
-
return events;
|
|
6524
|
+
return converted;
|
|
6228
6525
|
}
|
|
6229
|
-
|
|
6230
|
-
const existing = streamState.get("
|
|
6231
|
-
if (existing)
|
|
6526
|
+
getResponsesEncoder(ctx, upstreamModel) {
|
|
6527
|
+
const existing = ctx.streamState.get("responses_shared_encoder");
|
|
6528
|
+
if (existing)
|
|
6232
6529
|
return existing;
|
|
6233
|
-
|
|
6234
|
-
const
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
const created = {
|
|
6238
|
-
responseId,
|
|
6239
|
-
messageId: `${responseId}_msg`,
|
|
6240
|
-
createdAt,
|
|
6241
|
-
model,
|
|
6242
|
-
messageText: "",
|
|
6243
|
-
finishReason: "",
|
|
6244
|
-
usage: {
|
|
6245
|
-
input_tokens: 0,
|
|
6246
|
-
output_tokens: 0,
|
|
6247
|
-
total_tokens: 0
|
|
6248
|
-
},
|
|
6249
|
-
hasTextContentPart: false,
|
|
6250
|
-
toolCalls: [],
|
|
6251
|
-
toolCallIndexToId: new Map,
|
|
6252
|
-
terminalEventType: null,
|
|
6253
|
-
terminalReason: ""
|
|
6254
|
-
};
|
|
6255
|
-
streamState.set("responses_stream_state", created);
|
|
6256
|
-
return created;
|
|
6257
|
-
}
|
|
6258
|
-
resolveTerminalEvent(state) {
|
|
6259
|
-
if (state.terminalEventType) {
|
|
6260
|
-
return {
|
|
6261
|
-
type: state.terminalEventType,
|
|
6262
|
-
status: this.terminalStatusFromType(state.terminalEventType),
|
|
6263
|
-
reason: state.terminalReason || state.finishReason || (state.terminalEventType === "response.incomplete" ? "unknown" : "stop")
|
|
6264
|
-
};
|
|
6265
|
-
}
|
|
6266
|
-
const mappedByFinishReason = this.mapFinishReasonToTerminalEvent(state.finishReason);
|
|
6267
|
-
if (mappedByFinishReason) {
|
|
6268
|
-
return {
|
|
6269
|
-
type: mappedByFinishReason.type,
|
|
6270
|
-
status: this.terminalStatusFromType(mappedByFinishReason.type),
|
|
6271
|
-
reason: mappedByFinishReason.reason
|
|
6272
|
-
};
|
|
6273
|
-
}
|
|
6274
|
-
if (state.messageText.length === 0 && state.toolCalls.length === 0) {
|
|
6275
|
-
return {
|
|
6276
|
-
type: "response.failed",
|
|
6277
|
-
status: "failed",
|
|
6278
|
-
reason: "empty_stream_output"
|
|
6279
|
-
};
|
|
6280
|
-
}
|
|
6281
|
-
return {
|
|
6282
|
-
type: "response.incomplete",
|
|
6283
|
-
status: "incomplete",
|
|
6284
|
-
reason: "unknown"
|
|
6285
|
-
};
|
|
6286
|
-
}
|
|
6287
|
-
mapFinishReasonToTerminalEvent(finishReason) {
|
|
6288
|
-
const normalizedFinishReason = finishReason.trim();
|
|
6289
|
-
if (!normalizedFinishReason) {
|
|
6290
|
-
return;
|
|
6291
|
-
}
|
|
6292
|
-
if (normalizedFinishReason === "stop" || normalizedFinishReason === "tool_calls") {
|
|
6293
|
-
return {
|
|
6294
|
-
type: "response.completed",
|
|
6295
|
-
reason: normalizedFinishReason
|
|
6296
|
-
};
|
|
6297
|
-
}
|
|
6298
|
-
if (normalizedFinishReason === "length") {
|
|
6299
|
-
return {
|
|
6300
|
-
type: "response.incomplete",
|
|
6301
|
-
reason: "max_output_tokens"
|
|
6302
|
-
};
|
|
6303
|
-
}
|
|
6304
|
-
if (normalizedFinishReason === "content_filter") {
|
|
6305
|
-
return {
|
|
6306
|
-
type: "response.incomplete",
|
|
6307
|
-
reason: "content_filter"
|
|
6308
|
-
};
|
|
6309
|
-
}
|
|
6310
|
-
if (normalizedFinishReason === "error") {
|
|
6311
|
-
return {
|
|
6312
|
-
type: "response.failed",
|
|
6313
|
-
reason: "upstream_error"
|
|
6314
|
-
};
|
|
6315
|
-
}
|
|
6316
|
-
return {
|
|
6317
|
-
type: "response.completed",
|
|
6318
|
-
reason: normalizedFinishReason
|
|
6319
|
-
};
|
|
6320
|
-
}
|
|
6321
|
-
aggregateTerminalFromFinishReasons(finishReasons) {
|
|
6322
|
-
let selectedTerminal;
|
|
6323
|
-
let selectedPriority = -1;
|
|
6324
|
-
for (const finishReason of finishReasons) {
|
|
6325
|
-
const mapped = this.mapFinishReasonToTerminalEvent(finishReason);
|
|
6326
|
-
if (!mapped) {
|
|
6327
|
-
continue;
|
|
6328
|
-
}
|
|
6329
|
-
const priority = this.terminalPriority(mapped.type);
|
|
6330
|
-
if (priority > selectedPriority) {
|
|
6331
|
-
selectedTerminal = mapped;
|
|
6332
|
-
selectedPriority = priority;
|
|
6333
|
-
}
|
|
6334
|
-
}
|
|
6335
|
-
return selectedTerminal ?? {
|
|
6336
|
-
type: "response.completed",
|
|
6337
|
-
reason: "stop"
|
|
6338
|
-
};
|
|
6339
|
-
}
|
|
6340
|
-
terminalPriority(type) {
|
|
6341
|
-
if (type === "response.failed") {
|
|
6342
|
-
return 3;
|
|
6343
|
-
}
|
|
6344
|
-
if (type === "response.incomplete") {
|
|
6345
|
-
return 2;
|
|
6346
|
-
}
|
|
6347
|
-
return 1;
|
|
6348
|
-
}
|
|
6349
|
-
terminalStatusFromType(type) {
|
|
6350
|
-
if (type === "response.completed") {
|
|
6351
|
-
return "completed";
|
|
6352
|
-
}
|
|
6353
|
-
if (type === "response.incomplete") {
|
|
6354
|
-
return "incomplete";
|
|
6355
|
-
}
|
|
6356
|
-
return "failed";
|
|
6357
|
-
}
|
|
6358
|
-
normalizeChatMessageContentToResponseOutputText(content) {
|
|
6359
|
-
if (typeof content === "string") {
|
|
6360
|
-
return content;
|
|
6361
|
-
}
|
|
6362
|
-
if (!Array.isArray(content)) {
|
|
6363
|
-
return "";
|
|
6364
|
-
}
|
|
6365
|
-
const textSegments = [];
|
|
6366
|
-
for (const item of content) {
|
|
6367
|
-
if (!isRecord4(item)) {
|
|
6368
|
-
continue;
|
|
6369
|
-
}
|
|
6370
|
-
if (typeof item.text === "string") {
|
|
6371
|
-
textSegments.push(item.text);
|
|
6372
|
-
}
|
|
6373
|
-
}
|
|
6374
|
-
return textSegments.join("");
|
|
6375
|
-
}
|
|
6376
|
-
toResponsesId(rawId) {
|
|
6377
|
-
if (typeof rawId !== "string" || rawId.trim().length === 0) {
|
|
6378
|
-
return `resp_${Date.now()}`;
|
|
6379
|
-
}
|
|
6380
|
-
if (rawId.startsWith("resp_")) {
|
|
6381
|
-
return rawId;
|
|
6382
|
-
}
|
|
6383
|
-
return `resp_${rawId}`;
|
|
6530
|
+
const model = typeof upstreamModel === "string" ? upstreamModel : this.responsesRequestModels.get(ctx.requestId) ?? "";
|
|
6531
|
+
const encoder = new ResponsesEventEncoder("chat_completions", model);
|
|
6532
|
+
ctx.streamState.set("responses_shared_encoder", encoder);
|
|
6533
|
+
return encoder;
|
|
6384
6534
|
}
|
|
6385
6535
|
normalizeAssistantToolCallReasoningContent(body) {
|
|
6386
6536
|
const rawMessages = body.messages;
|
|
@@ -6494,4 +6644,4 @@ export {
|
|
|
6494
6644
|
server_default as default
|
|
6495
6645
|
};
|
|
6496
6646
|
|
|
6497
|
-
//# debugId=
|
|
6647
|
+
//# debugId=50667B5F9ABB6B8964756E2164756E21
|