@jeffusion/bungee-core 6.11.2 → 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.
@@ -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 !== undefined)
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
- fields2(c, ["index", "message", "finish_reason", "logprobs", "provider_specific_fields"], "choices", "unsupported_response");
5458
- if (c.provider_specific_fields !== undefined) {
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
- fields2(m, ["role", "content", "refusal", "reasoning_content", "reasoning", "tool_calls", "annotations"], "message", "unsupported_content");
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
- fields2(c, ["index", "delta", "finish_reason", "logprobs"], "choices", "unsupported_response");
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(422, `llm_adapter_${e.code}`, undefined, { message: e.message, param: e.param });
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=EA74ECD3BF3B21AA64756E2164756E21
7598
+ //# debugId=41F4B3D1EF2D68E564756E2164756E21