@jeffusion/bungee-core 6.5.0 → 6.6.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.
@@ -4918,7 +4918,21 @@ function validateUsage(raw, protocol) {
4918
4918
  if (raw === undefined || raw === null)
4919
4919
  return;
4920
4920
  const u = record(raw, "usage");
4921
- const keys = protocol === "chat_completions" ? ["prompt_tokens", "completion_tokens", "total_tokens", "prompt_tokens_details", "completion_tokens_details"] : protocol === "anthropic_messages" ? ["input_tokens", "output_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"] : ["input_tokens", "output_tokens", "total_tokens", "input_tokens_details", "output_tokens_details"];
4921
+ if (protocol === "chat_completions") {
4922
+ for (const key of ["prompt_tokens", "completion_tokens", "total_tokens"])
4923
+ if (u[key] !== undefined && u[key] !== null)
4924
+ integer(u[key], `usage.${key}`);
4925
+ for (const [container, counter] of [["prompt_tokens_details", "cached_tokens"], ["completion_tokens_details", "reasoning_tokens"]]) {
4926
+ const value = u[container];
4927
+ if (value === undefined || value === null)
4928
+ continue;
4929
+ const details = record(value, `usage.${container}`);
4930
+ if (details[counter] !== undefined && details[counter] !== null)
4931
+ integer(details[counter], `usage.${container}.${counter}`);
4932
+ }
4933
+ return;
4934
+ }
4935
+ const keys = protocol === "anthropic_messages" ? ["input_tokens", "output_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"] : ["input_tokens", "output_tokens", "total_tokens", "input_tokens_details", "output_tokens_details"];
4922
4936
  fields2(u, keys, "usage", "unsupported_response");
4923
4937
  for (const [key, value] of Object.entries(u)) {
4924
4938
  if (key.endsWith("_details")) {
@@ -6246,8 +6260,10 @@ class AgentRelay {
6246
6260
  }
6247
6261
 
6248
6262
  // plugins/llm-protocol-adapter/server/service.ts
6249
- var REASONING_RULES_VERSION = "2026-10-12.1";
6263
+ var REASONING_RULES_VERSION = "2026-10-24.1";
6250
6264
  var concrete = new Set(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
6265
+ var effortProtocols = new Set(["responses", "chat_completions", "anthropic_messages"]);
6266
+ var anthropicEfforts = new Set(["low", "medium", "high", "xhigh", "max"]);
6251
6267
  function identityError(code, message) {
6252
6268
  throw new ResponsesCodecError(code, message, "modelIdentity");
6253
6269
  }
@@ -6266,41 +6282,29 @@ function checkedIdentity(value, model) {
6266
6282
  identityError("model_identity_mismatch", "Declared wire model differs from the actual target");
6267
6283
  return identity;
6268
6284
  }
6269
- function rule(provider, model, protocol) {
6270
- if (provider === "zai" && ["glm-5.3", "glm-5.3-flash"].includes(model) && protocol === "chat_completions")
6271
- return { values: ["low", "high", "max"], default: "max", kind: "chat" };
6272
- if (provider === "anthropic" && protocol === "anthropic_messages") {
6273
- if (["claude-opus-4-7", "claude-opus-4-8", "claude-opus-5", "claude-opus-5-5", "claude-sonnet-5", "claude-sonnet-5-5", "claude-haiku-5-5"].includes(model))
6274
- return { values: ["low", "medium", "high", "xhigh", "max"], default: ["claude-opus-5-5", "claude-haiku-5-5"].includes(model) ? "medium" : "high", kind: "anthropic" };
6275
- if (["claude-opus-4-6", "claude-sonnet-4-6"].includes(model))
6276
- return { values: ["low", "medium", "high", "max"], default: "high", kind: "anthropic" };
6277
- }
6278
- return null;
6279
- }
6280
6285
  function resolveCapabilities(catalog, context) {
6281
6286
  const info = catalog.model(context);
6282
6287
  if (!info)
6283
6288
  return null;
6284
- const mapping = rule(context.provider, context.model, context.targetProtocol), restrictions = context.restrictions;
6285
- const candidates = info.reasoningOptionsStatus === "known" ? info.reasoningOptions?.flatMap((option) => option.type === "effort" ? option.values.filter((value) => typeof value === "string" && concrete.has(value)) : []) ?? [] : [];
6286
- const selected = mapping && info.reasoning && restrictions?.reasoning !== false ? [...new Set(candidates)].filter((v) => mapping.values.includes(v)) : [];
6287
- const supportedEfforts = mapping && selected.includes(mapping.default) ? selected : [];
6288
- const defaultEffort = supportedEfforts.length ? mapping.default : null;
6289
- const wirePolicy = supportedEfforts.length ? { effortMap: Object.fromEntries(supportedEfforts.map((value) => [value, value])), ...mapping.kind === "anthropic" ? { anthropicThinkingMode: "adaptive" } : {} } : null;
6289
+ const restrictions = context.restrictions, reasoningAllowed = info.reasoning && restrictions?.reasoning !== false;
6290
+ const allowed = context.targetProtocol === "anthropic_messages" ? anthropicEfforts : concrete;
6291
+ const candidates = reasoningAllowed && effortProtocols.has(context.targetProtocol) && info.reasoningOptionsStatus === "known" ? info.reasoningOptions?.flatMap((option) => option.type === "effort" ? option.values.filter((value) => typeof value === "string" && allowed.has(value)) : []) ?? [] : [];
6292
+ const supportedEfforts = [...new Set(candidates)];
6293
+ const wirePolicy = supportedEfforts.length ? { effortMap: Object.fromEntries(supportedEfforts.map((value) => [value, value])) } : null;
6290
6294
  return {
6291
6295
  ...info,
6292
6296
  contextWindow: info.contextWindow === null ? null : Math.min(info.contextWindow, restrictions?.contextWindow ?? info.contextWindow),
6293
6297
  toolCall: info.toolCall && restrictions?.tools !== false,
6294
6298
  inputModalities: info.inputModalities.filter((v) => v !== "image" || restrictions?.images !== false),
6295
6299
  supportedEfforts,
6296
- defaultEffort,
6300
+ defaultEffort: null,
6297
6301
  rulesVersion: REASONING_RULES_VERSION,
6298
6302
  wirePolicy,
6299
6303
  codecCapabilities: {
6300
6304
  maxOutputTokens: info.outputLimit ?? undefined,
6301
- reasoningHistory: info.reasoning && restrictions?.reasoning !== false,
6305
+ reasoningHistory: reasoningAllowed,
6302
6306
  reasoningEffort: supportedEfforts.length > 0,
6303
- anthropicEffort: mapping?.kind === "anthropic" && supportedEfforts.length > 0,
6307
+ anthropicEffort: supportedEfforts.length > 0,
6304
6308
  anthropicStructuredOutput: context.provider === "anthropic" && /^claude-(?:opus-(?:4-[5678]|5(?:-5)?)|sonnet-(?:4-[56]|5(?:-5)?)|haiku-(?:4-5|5-5))$/.test(context.model),
6305
6309
  anthropicStrictTools: context.provider === "anthropic" && /^claude-(?:opus-(?:4-[5678]|5(?:-5)?)|sonnet-(?:4-[56]|5(?:-5)?)|haiku-(?:4-5|5-5))$/.test(context.model),
6306
6310
  geminiJsonSchema: false
@@ -6313,6 +6317,10 @@ function fail2(param) {
6313
6317
  function wireEffort(body, protocol) {
6314
6318
  return protocol === "responses" ? body?.reasoning?.effort : protocol === "chat_completions" ? body?.reasoning_effort : protocol === "anthropic_messages" ? body?.output_config?.effort : body?.generationConfig?.thinkingConfig?.thinkingLevel;
6315
6319
  }
6320
+ function chatMessages(body) {
6321
+ const messages = body && typeof body === "object" ? body.messages : undefined;
6322
+ return Array.isArray(messages) ? messages : [];
6323
+ }
6316
6324
  function conversionService(catalog, worker, history, runBackground) {
6317
6325
  const relay = new AgentRelay(history, Date.now, runBackground);
6318
6326
  return {
@@ -6348,7 +6356,7 @@ function conversionService(catalog, worker, history, runBackground) {
6348
6356
  identityError("model_identity_unavailable", "Declared catalog model is unavailable");
6349
6357
  const entryProfile = profile;
6350
6358
  let catalogVersion = profile?.catalogVersion ?? null;
6351
- let selected = context.selectedEffort;
6359
+ let selected = context.selectedEffort, rewrittenDeveloper = false;
6352
6360
  const passthrough = context.sourceProtocol === context.targetProtocol;
6353
6361
  if (!passthrough && selected !== undefined && (!profile || !profile.supportedEfforts.includes(selected)))
6354
6362
  fail2("reasoning.effort");
@@ -6357,6 +6365,7 @@ function conversionService(catalog, worker, history, runBackground) {
6357
6365
  capabilities: profile?.codecCapabilities ?? context.capabilities,
6358
6366
  reasoningPolicy: profile?.wirePolicy ?? context.reasoningPolicy
6359
6367
  });
6368
+ const deepseekChat = context.sourceProtocol === "responses" && context.targetProtocol === "chat_completions" && profile?.provider === "deepseek";
6360
6369
  let disposed = false;
6361
6370
  const session = {
6362
6371
  convertRequest(raw) {
@@ -6367,8 +6376,14 @@ function conversionService(catalog, worker, history, runBackground) {
6367
6376
  selected = effort;
6368
6377
  }
6369
6378
  const result = engine.convertRequest(raw);
6370
- if (!passthrough && selected !== undefined && context.targetProtocol === "chat_completions" && profile?.provider === "zai")
6371
- result.body.thinking = { type: "enabled" };
6379
+ rewrittenDeveloper = false;
6380
+ if (deepseekChat) {
6381
+ for (const message of chatMessages(result.body))
6382
+ if (message.role === "developer") {
6383
+ message.role = "system";
6384
+ rewrittenDeveloper = true;
6385
+ }
6386
+ }
6372
6387
  return result;
6373
6388
  },
6374
6389
  convertResponse: (raw) => engine.convertResponse(raw),
@@ -6409,15 +6424,15 @@ function conversionService(catalog, worker, history, runBackground) {
6409
6424
  identityError("model_identity_unavailable", "Declared catalog model is unavailable");
6410
6425
  if (actual && catalogVersion !== null && actual.catalogVersion !== catalogVersion)
6411
6426
  identityError("model_identity_catalog_changed", "Target catalog version differs from the generation snapshot");
6427
+ if (rewrittenDeveloper && actual?.provider !== "deepseek")
6428
+ throw new ResponsesCodecError("unsupported_content", "DeepSeek developer-role conversion cannot be sent to another target provider", "messages");
6429
+ if (context.sourceProtocol === "responses" && protocol === "chat_completions" && actual?.provider === "deepseek" && chatMessages(body).some((message) => message?.role === "developer"))
6430
+ throw new ResponsesCodecError("unsupported_content", "DeepSeek target requires developer messages to be converted", "messages");
6412
6431
  const sameNativeIdentity = entryProfile ? !!actual && actual.provider === entryProfile.provider && actual.model === entryProfile.model : !identity && model === context.model;
6413
6432
  if (selected !== undefined) {
6414
6433
  if (!(passthrough && sameNativeIdentity && wireEffort(body, protocol) === selected)) {
6415
6434
  if (!entryProfile || !actual || actual.rulesVersion !== entryProfile.rulesVersion || !actual.supportedEfforts.includes(selected) || wireEffort(body, protocol) !== selected)
6416
6435
  fail2("reasoning.effort");
6417
- if (protocol === "anthropic_messages" && body?.thinking?.type !== "adaptive")
6418
- fail2("thinking.type");
6419
- if (protocol === "chat_completions" && actual.provider === "zai" && body?.thinking?.type !== "enabled")
6420
- fail2("thinking.type");
6421
6436
  }
6422
6437
  } else if (!profile && actual && identity) {
6423
6438
  profile = structuredClone(actual);
@@ -6469,4 +6484,4 @@ export {
6469
6484
  control_default as default
6470
6485
  };
6471
6486
 
6472
- //# debugId=53F531283A2005E364756E2164756E21
6487
+ //# debugId=62FD9644C2CB7DAB64756E2164756E21