@jeffusion/bungee-core 6.11.1 → 6.11.3
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/main.js +64 -44
- package/dist/plugins/anthropic-request-sanitizer/index.js.map +1 -1
- package/dist/plugins/anthropic-tool-name-transformer/index.js.map +1 -1
- package/dist/plugins/chatgpt-oauth/control.js.map +1 -1
- package/dist/plugins/chatgpt-oauth/index.js.map +1 -1
- package/dist/plugins/codex-router/control.js.map +1 -1
- package/dist/plugins/codex-router/index.js +4 -4
- package/dist/plugins/codex-router/index.js.map +5 -5
- package/dist/plugins/deepseek-reasoning-fix/index.js.map +1 -1
- package/dist/plugins/key-access/control.js.map +1 -1
- package/dist/plugins/key-access/index.js.map +1 -1
- package/dist/plugins/key-access/ingress.js.map +1 -1
- package/dist/plugins/key-rate-limit/index.js.map +1 -1
- package/dist/plugins/llm-protocol-adapter/control.js +53 -28
- package/dist/plugins/llm-protocol-adapter/control.js.map +9 -9
- package/dist/plugins/llm-protocol-adapter/index.js +58 -33
- package/dist/plugins/llm-protocol-adapter/index.js.map +10 -10
- package/dist/plugins/llm-tps/index.js.map +1 -1
- package/dist/plugins/model-mapping/index.js.map +1 -1
- package/dist/plugins/models-dev/index.js.map +1 -1
- package/dist/plugins/signature-repair/index.js.map +1 -1
- package/dist/plugins/token-budget/control.js.map +1 -1
- package/dist/plugins/token-budget/index.js.map +1 -1
- package/dist/plugins/token-metering/index.js.map +2 -2
- package/dist/plugins/token-stats/control.js.map +1 -1
- package/dist/plugins/token-stats/index.js.map +1 -1
- package/dist/plugins/user-auth/control.js.map +1 -1
- package/dist/plugins/user-auth/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -3817,6 +3817,8 @@ function decodeResponsesRequest(raw, protocol, capabilities = {}, options = {})
|
|
|
3817
3817
|
const callIds = new Set;
|
|
3818
3818
|
const callToolNames = new Map;
|
|
3819
3819
|
const answered = new Set;
|
|
3820
|
+
const deferredInstructions = [];
|
|
3821
|
+
const normalizeChatHistory = protocol === "chat_completions" && !options.preserveContentOrder;
|
|
3820
3822
|
const projectedToolImages = [];
|
|
3821
3823
|
let pendingReasoning = "";
|
|
3822
3824
|
const addMessage = (message) => {
|
|
@@ -3842,6 +3844,8 @@ function decodeResponsesRequest(raw, protocol, capabilities = {}, options = {})
|
|
|
3842
3844
|
flushToolImages();
|
|
3843
3845
|
if (item.type === "additional_tools")
|
|
3844
3846
|
return;
|
|
3847
|
+
if (deferredInstructions.length && item.type !== "function_call_output" && item.type !== "custom_tool_call_output" && !((item.type === undefined || item.type === "message") && (item.role === "system" || item.role === "developer")))
|
|
3848
|
+
fail("invalid_tool_history", "Only instructions and tool results may follow a deferred instruction until all tool results arrive", messageParam);
|
|
3845
3849
|
if (item.type === "agent_message") {
|
|
3846
3850
|
validateAgentMessage(item, messageParam, capabilities.limits);
|
|
3847
3851
|
if (capabilities.agentMessageDelivery !== "plaintext")
|
|
@@ -3920,6 +3924,13 @@ function decodeResponsesRequest(raw, protocol, capabilities = {}, options = {})
|
|
|
3920
3924
|
}
|
|
3921
3925
|
}
|
|
3922
3926
|
addMessage({ role: "tool", tool_call_id: id, content: output, ...item.is_error === true ? { is_error: true } : {} });
|
|
3927
|
+
if (callIds.size === answered.size) {
|
|
3928
|
+
for (const instruction of deferredInstructions) {
|
|
3929
|
+
messageParam = instruction.param;
|
|
3930
|
+
addMessage(instruction.message);
|
|
3931
|
+
}
|
|
3932
|
+
deferredInstructions.length = 0;
|
|
3933
|
+
}
|
|
3923
3934
|
return;
|
|
3924
3935
|
}
|
|
3925
3936
|
if (item.type !== undefined && item.type !== "message")
|
|
@@ -3936,6 +3947,11 @@ function decodeResponsesRequest(raw, protocol, capabilities = {}, options = {})
|
|
|
3936
3947
|
message.reasoning_content = pendingReasoning;
|
|
3937
3948
|
pendingReasoning = "";
|
|
3938
3949
|
}
|
|
3950
|
+
if (normalizeChatHistory && (role === "system" || role === "developer") && callIds.size !== answered.size) {
|
|
3951
|
+
deferredInstructions.push({ message, param: messageParam });
|
|
3952
|
+
diagnostics.push({ param: messageParam, action: "mapped", reason: "chat_instruction_deferred_until_tool_results" });
|
|
3953
|
+
return;
|
|
3954
|
+
}
|
|
3939
3955
|
if (protocol === "chat_completions" && !options.preserveContentOrder && role === "assistant") {
|
|
3940
3956
|
const previous = chat.at(-1);
|
|
3941
3957
|
if (previous?.role === "assistant") {
|
|
@@ -3949,6 +3965,8 @@ function decodeResponsesRequest(raw, protocol, capabilities = {}, options = {})
|
|
|
3949
3965
|
});
|
|
3950
3966
|
if (pendingReasoning)
|
|
3951
3967
|
fail("unsupported_reasoning", "Orphan reasoning history cannot be represented");
|
|
3968
|
+
if (deferredInstructions.length)
|
|
3969
|
+
fail("invalid_tool_history", "Deferred instructions require all pending tool results", deferredInstructions[0].param);
|
|
3952
3970
|
flushToolImages(true);
|
|
3953
3971
|
const result = { model, messages: chat };
|
|
3954
3972
|
const omittedAllTools = !tools.length && diagnostics.some((item) => item.reason === "optional_hosted_web_search_unavailable");
|
|
@@ -4052,6 +4070,28 @@ function decodeResponsesRequest(raw, protocol, capabilities = {}, options = {})
|
|
|
4052
4070
|
return { body: result, toolNames, canonicalInput, diagnostics };
|
|
4053
4071
|
}
|
|
4054
4072
|
// packages/llms/src/responses-codec/events.ts
|
|
4073
|
+
function chatOutput(raw) {
|
|
4074
|
+
const keys = ["role", "content", "refusal", "reasoning_content", "reasoning", "tool_calls", "function_call", "annotations"];
|
|
4075
|
+
const delta = Object.fromEntries(keys.filter((key) => raw[key] != null).map((key) => [key, raw[key]]));
|
|
4076
|
+
const provider = raw.provider_specific_fields == null ? {} : record(raw.provider_specific_fields, "provider_specific_fields");
|
|
4077
|
+
for (const key of ["refusal", "reasoning_content", "reasoning"]) {
|
|
4078
|
+
if (provider[key] == null)
|
|
4079
|
+
continue;
|
|
4080
|
+
if (delta[key] != null && delta[key] !== provider[key])
|
|
4081
|
+
fail("unsupported_content", "Conflicting provider output fields", `provider_specific_fields.${key}`);
|
|
4082
|
+
delta[key] = provider[key];
|
|
4083
|
+
}
|
|
4084
|
+
for (const key of ["audio", "thinking_blocks", "reasoning_details", "signature", "thought_signature", "thoughtSignature", "encrypted_content", "encrypted_function_args"])
|
|
4085
|
+
if (raw[key] != null || provider[key] != null)
|
|
4086
|
+
fail("unsupported_content", "Provider output authority cannot cross protocols", key);
|
|
4087
|
+
for (const key of ["content", "tool_calls", "function_call", "annotations"])
|
|
4088
|
+
if (provider[key] != null)
|
|
4089
|
+
fail("unsupported_content", "Nested provider output cannot cross protocols", `provider_specific_fields.${key}`);
|
|
4090
|
+
if (delta.reasoning_content != null && delta.reasoning != null && delta.reasoning_content !== delta.reasoning)
|
|
4091
|
+
fail("unsupported_content", "Conflicting reasoning fields", "reasoning");
|
|
4092
|
+
return delta;
|
|
4093
|
+
}
|
|
4094
|
+
|
|
4055
4095
|
class ResponsesEventEncoder {
|
|
4056
4096
|
protocol;
|
|
4057
4097
|
model;
|
|
@@ -4261,10 +4301,7 @@ class ResponsesEventEncoder {
|
|
|
4261
4301
|
const choice = record(choices[0], "choice");
|
|
4262
4302
|
if (choice.index !== undefined && choice.index !== 0)
|
|
4263
4303
|
fail("unsupported_response", "Only choice index 0 is supported");
|
|
4264
|
-
const delta = record(choice.delta ?? {}, "choice delta");
|
|
4265
|
-
for (const key of Object.keys(delta))
|
|
4266
|
-
if (!["role", "content", "refusal", "reasoning_content", "reasoning", "tool_calls", "function_call", "annotations"].includes(key))
|
|
4267
|
-
fail("unsupported_content", `Unsupported Chat output field ${key}`);
|
|
4304
|
+
const delta = chatOutput(record(choice.delta ?? {}, "choice delta"));
|
|
4268
4305
|
if (delta.annotations !== undefined && list(delta.annotations, "annotations").length)
|
|
4269
4306
|
fail("unsupported_content", "Chat output annotations cannot be faithfully converted");
|
|
4270
4307
|
if (delta.role !== undefined && delta.role !== "assistant")
|
|
@@ -4462,7 +4499,7 @@ function encodeResponsesResult(raw, protocol, model, toolNames = new Map, config
|
|
|
4462
4499
|
const choice = record(choices[0], "choice");
|
|
4463
4500
|
const message = record(choice.message, "message");
|
|
4464
4501
|
const delta = { ...message };
|
|
4465
|
-
if (message.tool_calls
|
|
4502
|
+
if (message.tool_calls != null)
|
|
4466
4503
|
delta.tool_calls = list(message.tool_calls, "tool_calls").map((tool, index) => ({ ...record(tool, "tool call"), index }));
|
|
4467
4504
|
encoder.push({ choices: [{ index: choice.index ?? 0, delta, finish_reason: choice.finish_reason }], usage: body.usage });
|
|
4468
4505
|
} else {
|
|
@@ -5192,7 +5229,7 @@ function convertProtocolRequest(raw, context) {
|
|
|
5192
5229
|
fail("unsupported_reasoning", "Source thinking mode needs an explicit target wire policy", "thinking");
|
|
5193
5230
|
}
|
|
5194
5231
|
if (target === "responses") {
|
|
5195
|
-
const validation = decodeResponsesRequest({ ...b, reasoning: reasoning ? { ...reasoning, effort: undefined } : undefined }, "chat_completions", { ...cap, reasoningHistory: true });
|
|
5232
|
+
const validation = decodeResponsesRequest({ ...b, reasoning: reasoning ? { ...reasoning, effort: undefined } : undefined }, "chat_completions", { ...cap, reasoningHistory: true }, { preserveContentOrder: true, toolOutputImages: true });
|
|
5196
5233
|
if (mappedEffort !== undefined)
|
|
5197
5234
|
b.reasoning = { ...reasoning, effort: mappedEffort };
|
|
5198
5235
|
else if (reasoning?.effort !== undefined)
|
|
@@ -5451,20 +5488,14 @@ function validateProviderResponse(raw, protocol) {
|
|
|
5451
5488
|
if (b.error !== undefined || b.type === "error")
|
|
5452
5489
|
return b;
|
|
5453
5490
|
if (protocol === "chat_completions") {
|
|
5454
|
-
fields2(b, ["id", "object", "created", "model", "choices", "usage", "system_fingerprint", "service_tier"], "", "unsupported_response");
|
|
5455
5491
|
for (const rawChoice of list(b.choices, "choices")) {
|
|
5456
5492
|
const c = record(rawChoice, "choice");
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
const providerFields = c.provider_specific_fields;
|
|
5460
|
-
if (providerFields === null || typeof providerFields !== "object" || Array.isArray(providerFields) || Object.keys(providerFields).length)
|
|
5461
|
-
fail("unsupported_response", "Only empty provider-specific choice fields are portable", "choices.provider_specific_fields");
|
|
5462
|
-
}
|
|
5493
|
+
if (c.provider_specific_fields != null)
|
|
5494
|
+
record(c.provider_specific_fields, "choices.provider_specific_fields");
|
|
5463
5495
|
if (c.logprobs != null)
|
|
5464
5496
|
fail("unsupported_response", "Log probabilities cannot cross protocols", "choices.logprobs");
|
|
5465
5497
|
const m = record(c.message, "message");
|
|
5466
|
-
|
|
5467
|
-
for (const [callIndex, rawCall] of (m.tool_calls === undefined ? [] : list(m.tool_calls, "tool_calls")).entries()) {
|
|
5498
|
+
for (const [callIndex, rawCall] of (m.tool_calls == null ? [] : list(m.tool_calls, "tool_calls")).entries()) {
|
|
5468
5499
|
const call = record(rawCall, "call");
|
|
5469
5500
|
fields2(call, ["id", "type", "function", "index"], "tool_calls", "unsupported_tool");
|
|
5470
5501
|
if (call.index !== undefined && integer(call.index, `tool_calls[${callIndex}].index`) !== callIndex)
|
|
@@ -5474,7 +5505,6 @@ function validateProviderResponse(raw, protocol) {
|
|
|
5474
5505
|
}
|
|
5475
5506
|
validateUsage(b.usage, protocol);
|
|
5476
5507
|
} else if (protocol === "anthropic_messages") {
|
|
5477
|
-
fields2(b, ["id", "type", "role", "model", "content", "stop_reason", "stop_sequence", "usage"], "", "unsupported_response");
|
|
5478
5508
|
if (b.role !== undefined && b.role !== "assistant")
|
|
5479
5509
|
fail("unsupported_response", "Response role must be assistant", "role");
|
|
5480
5510
|
for (const rawPart of list(b.content, "content"))
|
|
@@ -5680,7 +5710,6 @@ class GeminiCanonicalDecoder {
|
|
|
5680
5710
|
}
|
|
5681
5711
|
push(raw) {
|
|
5682
5712
|
const b = record(raw, "Gemini response");
|
|
5683
|
-
fields2(b, ["candidates", "usageMetadata", "modelVersion", "responseId", "promptFeedback", "error"], "", "unsupported_response");
|
|
5684
5713
|
if (b.error !== undefined)
|
|
5685
5714
|
return this.decorate(this.encoder.push({ error: safeProtocolError() }));
|
|
5686
5715
|
const events = [];
|
|
@@ -5697,7 +5726,6 @@ class GeminiCanonicalDecoder {
|
|
|
5697
5726
|
fail("unsupported_response", "Multiple Gemini candidates cannot cross protocols", "candidates");
|
|
5698
5727
|
if (candidates.length) {
|
|
5699
5728
|
const c = record(candidates[0], "candidate");
|
|
5700
|
-
fields2(c, ["index", "content", "finishReason", "safetyRatings", "finishMessage"], "candidates", "unsupported_response");
|
|
5701
5729
|
if (c.index !== undefined && c.index !== 0)
|
|
5702
5730
|
fail("unsupported_response", "Only candidate index zero is supported", "candidates.index");
|
|
5703
5731
|
if (c.content !== undefined && c.content !== null) {
|
|
@@ -6303,9 +6331,9 @@ function createProtocolSession(context) {
|
|
|
6303
6331
|
fail("invalid_session", "A session can convert one JSON response or one stream");
|
|
6304
6332
|
mode = "json";
|
|
6305
6333
|
finished = true;
|
|
6334
|
+
const body = record(raw, "response");
|
|
6335
|
+
serialized(body, limits(context.capabilities?.limits).maxOutputBytes, "response");
|
|
6306
6336
|
if (same) {
|
|
6307
|
-
const body = record(raw, "response");
|
|
6308
|
-
serialized(body, limits(context.capabilities?.limits).maxOutputBytes, "response");
|
|
6309
6337
|
return body;
|
|
6310
6338
|
}
|
|
6311
6339
|
const canonical = canonicalResponse(raw, context, names);
|
|
@@ -6319,9 +6347,9 @@ function createProtocolSession(context) {
|
|
|
6319
6347
|
if (finished || mode === "json")
|
|
6320
6348
|
fail("invalid_stream", "Event arrived after session completion");
|
|
6321
6349
|
mode = "stream";
|
|
6350
|
+
const e = record(raw, "event");
|
|
6351
|
+
serialized(e, limits(context.capabilities?.limits).maxOutputBytes, "event");
|
|
6322
6352
|
if (same) {
|
|
6323
|
-
const e = record(raw, "event");
|
|
6324
|
-
serialized(e, limits(context.capabilities?.limits).maxOutputBytes, "event");
|
|
6325
6353
|
if (context.targetProtocol === "anthropic_messages") {
|
|
6326
6354
|
if (passAnthropicStopped)
|
|
6327
6355
|
fail("invalid_stream", "Event arrived after message_stop");
|
|
@@ -6399,11 +6427,11 @@ function validateStreamEnvelope(raw, protocol) {
|
|
|
6399
6427
|
if (e.error !== undefined || e.type === "error")
|
|
6400
6428
|
return;
|
|
6401
6429
|
if (protocol === "chat_completions") {
|
|
6402
|
-
fields2(e, ["id", "object", "created", "model", "choices", "usage", "system_fingerprint", "service_tier"], "", "unsupported_response");
|
|
6403
6430
|
if (Array.isArray(e.choices))
|
|
6404
6431
|
for (const rawChoice of e.choices) {
|
|
6405
6432
|
const c = record(rawChoice, "choice");
|
|
6406
|
-
|
|
6433
|
+
if (c.provider_specific_fields != null)
|
|
6434
|
+
record(c.provider_specific_fields, "choices.provider_specific_fields");
|
|
6407
6435
|
if (c.logprobs != null)
|
|
6408
6436
|
fail("unsupported_response", "Log probabilities cannot cross protocols", "choices.logprobs");
|
|
6409
6437
|
const d = record(c.delta ?? {}, "delta");
|
|
@@ -6417,8 +6445,6 @@ function validateStreamEnvelope(raw, protocol) {
|
|
|
6417
6445
|
}
|
|
6418
6446
|
validateUsage(e.usage, protocol);
|
|
6419
6447
|
} else {
|
|
6420
|
-
const allowed = e.type === "message_start" ? ["type", "message"] : e.type === "message_delta" ? ["type", "delta", "usage"] : e.type === "content_block_start" ? ["type", "index", "content_block"] : e.type === "content_block_delta" ? ["type", "index", "delta"] : e.type === "content_block_stop" ? ["type", "index"] : ["type"];
|
|
6421
|
-
fields2(e, allowed, "", "unsupported_response");
|
|
6422
6448
|
if (e.type === "content_block_start")
|
|
6423
6449
|
validateAnthropicBlock(record(e.content_block, "block"), "content_block");
|
|
6424
6450
|
if (e.type === "content_block_delta") {
|
|
@@ -6431,7 +6457,6 @@ function validateStreamEnvelope(raw, protocol) {
|
|
|
6431
6457
|
fields2(record(e.delta, "delta"), ["stop_reason", "stop_sequence"], "delta", "unsupported_response");
|
|
6432
6458
|
if (e.type === "message_start") {
|
|
6433
6459
|
const m = record(e.message, "message");
|
|
6434
|
-
fields2(m, ["id", "type", "role", "model", "content", "stop_reason", "stop_sequence", "usage"], "message", "unsupported_response");
|
|
6435
6460
|
validateUsage(m.usage, protocol);
|
|
6436
6461
|
if (m.content !== undefined && (!Array.isArray(m.content) || m.content.length))
|
|
6437
6462
|
fail("unsupported_content", "Initial stream message content must be empty", "message.content");
|
|
@@ -7115,10 +7140,10 @@ function conversionService(catalog, worker, history, runBackground) {
|
|
|
7115
7140
|
}
|
|
7116
7141
|
|
|
7117
7142
|
// plugins/llm-protocol-adapter/server/handler.ts
|
|
7118
|
-
function adapterError(error) {
|
|
7143
|
+
function adapterError(error, status = 422) {
|
|
7119
7144
|
const e = error;
|
|
7120
7145
|
if (typeof e?.code === "string")
|
|
7121
|
-
throw new DataAdmissionError(
|
|
7146
|
+
throw new DataAdmissionError(status, `llm_adapter_${e.code}`, undefined, { message: e.message, param: e.param });
|
|
7122
7147
|
throw error;
|
|
7123
7148
|
}
|
|
7124
7149
|
function responseHandler(input) {
|
|
@@ -7168,7 +7193,7 @@ function responseHandler(input) {
|
|
|
7168
7193
|
try {
|
|
7169
7194
|
body = structuredClone(input.session.convertResponse(raw));
|
|
7170
7195
|
} catch (e) {
|
|
7171
|
-
adapterError(e);
|
|
7196
|
+
adapterError(e, 502);
|
|
7172
7197
|
}
|
|
7173
7198
|
if (body.status === "completed") {
|
|
7174
7199
|
check();
|
|
@@ -7192,7 +7217,7 @@ function responseHandler(input) {
|
|
|
7192
7217
|
try {
|
|
7193
7218
|
events = input.session.push(envelope.json);
|
|
7194
7219
|
} catch (e) {
|
|
7195
|
-
adapterError(e);
|
|
7220
|
+
adapterError(e, 502);
|
|
7196
7221
|
}
|
|
7197
7222
|
remember(events);
|
|
7198
7223
|
return protocolSSEOutput(events, input.sourceProtocol, envelope);
|
|
@@ -7206,7 +7231,7 @@ function responseHandler(input) {
|
|
|
7206
7231
|
try {
|
|
7207
7232
|
events = input.session.finish();
|
|
7208
7233
|
} catch (e) {
|
|
7209
|
-
adapterError(e);
|
|
7234
|
+
adapterError(e, 502);
|
|
7210
7235
|
}
|
|
7211
7236
|
remember(events);
|
|
7212
7237
|
if (terminal) {
|
|
@@ -7570,4 +7595,4 @@ export {
|
|
|
7570
7595
|
targetPath
|
|
7571
7596
|
};
|
|
7572
7597
|
|
|
7573
|
-
//# debugId=
|
|
7598
|
+
//# debugId=41F4B3D1EF2D68E564756E2164756E21
|