@jeffusion/bungee-core 5.23.0 → 5.23.2

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.
Files changed (29) hide show
  1. package/dist/config-storage-worker.js +3 -1
  2. package/dist/main.js +2756 -295
  3. package/dist/plugins/chatgpt-oauth/index.js +92 -20
  4. package/dist/plugins/chatgpt-oauth/index.js.map +4 -4
  5. package/dist/plugins/codex-router/control.js +606 -2
  6. package/dist/plugins/codex-router/control.js.map +20 -5
  7. package/dist/plugins/codex-router/index.js +2459 -94
  8. package/dist/plugins/codex-router/index.js.map +20 -8
  9. package/dist/plugins/codex-router/manifest.json +14 -14
  10. package/dist/plugins/llm-protocol-adapter/control.js +96 -21
  11. package/dist/plugins/llm-protocol-adapter/control.js.map +8 -7
  12. package/dist/plugins/llm-protocol-adapter/index.js +134 -38
  13. package/dist/plugins/llm-protocol-adapter/index.js.map +11 -10
  14. package/dist/plugins/model-mapping/control.js +1 -1
  15. package/dist/plugins/model-mapping/control.js.map +3 -3
  16. package/dist/plugins/model-mapping/index.js +48 -17
  17. package/dist/plugins/model-mapping/index.js.map +6 -5
  18. package/dist/plugins/model-mapping/manifest.json +50 -6
  19. package/dist/plugins/models-dev/control.js +1 -1
  20. package/dist/plugins/models-dev/control.js.map +3 -3
  21. package/dist/plugins/models-dev/index.js +1 -1
  22. package/dist/plugins/models-dev/index.js.map +3 -3
  23. package/dist/plugins/token-metering/index.js +1 -1
  24. package/dist/plugins/token-metering/index.js.map +1 -1
  25. package/dist/plugins/token-stats/control.js +1 -1
  26. package/dist/plugins/token-stats/control.js.map +3 -3
  27. package/dist/plugins/token-stats/index.js +1 -1
  28. package/dist/plugins/token-stats/index.js.map +3 -3
  29. package/package.json +2 -2
@@ -851,6 +851,7 @@ var retryActionBrand = Symbol.for("@jeffusion/bungee/request-retry-action");
851
851
  var HOUR = 3600000;
852
852
  var TOKEN_STATS_RETENTION_MS = 31 * 24 * HOUR;
853
853
  // plugins/models-dev/contract.ts
854
+ var MODEL_IDENTITY_ANNOTATION_KEY = "models-dev.model-identity";
854
855
  var MODELS_DEV_CATALOG_SNAPSHOT_ID = "models-dev.catalog.snapshot.v1";
855
856
  var MODELS_DEV_CATALOG_SNAPSHOT_CONTRACT_VERSION = 1;
856
857
  var MODELS_DEV_CATALOG_SNAPSHOT_SCHEMA = Object.freeze({
@@ -909,6 +910,9 @@ function historyClient(rpc) {
909
910
  }
910
911
  };
911
912
  }
913
+ function readModelIdentity(annotations) {
914
+ return annotations?.[MODEL_IDENTITY_ANNOTATION_KEY];
915
+ }
912
916
  // node_modules/base64-js/index.js
913
917
  var $toByteArray = toByteArray;
914
918
  var lookup = [];
@@ -6031,6 +6035,32 @@ function validateStreamEnvelope(raw, protocol) {
6031
6035
  validateUsage(e.usage, protocol);
6032
6036
  }
6033
6037
  }
6038
+ // packages/llms/src/protocol-session/endpoint.ts
6039
+ function protocolRequestModel(protocol, body, url) {
6040
+ if (protocol === "gemini_generate_content") {
6041
+ let path;
6042
+ try {
6043
+ path = new URL(url).pathname;
6044
+ } catch {
6045
+ return fail("invalid_payload", "A valid Gemini target URL is required", "url");
6046
+ }
6047
+ const match = path.match(/\/models\/([^/]+):(?:streamGenerateContent|generateContent)$/);
6048
+ if (!match)
6049
+ return fail("invalid_payload", "Gemini target URL has no terminal model", "url");
6050
+ try {
6051
+ const model = decodeURIComponent(match[1]);
6052
+ if (model)
6053
+ return model;
6054
+ } catch {
6055
+ return fail("invalid_payload", "Gemini target model encoding is invalid", "url");
6056
+ }
6057
+ return fail("invalid_payload", "Gemini target model is required", "url");
6058
+ }
6059
+ const model = body?.model;
6060
+ if (typeof model !== "string" || !model)
6061
+ return fail("invalid_payload", "Target model is required", "model");
6062
+ return model;
6063
+ }
6034
6064
  // plugins/llm-protocol-adapter/server/relay.ts
6035
6065
  import { createHash } from "crypto";
6036
6066
 
@@ -6151,7 +6181,8 @@ async function relayPayload(result, param, signal) {
6151
6181
  if (result.status < 200 || result.status >= 300)
6152
6182
  throw new DataAdmissionError(result.status === 401 || result.status === 429 ? result.status : 502, "llm_adapter_relay_upstream_failed", undefined, { param, message: `Relay upstream rejected the request (HTTP ${result.status})` });
6153
6183
  let response;
6154
- if (result.bodyHandle.identity.contentType.includes("text/event-stream") || result.bodyHandle.identity.contentType.includes("application/octet-stream")) {
6184
+ const contentType = result.bodyHandle.identity.contentType;
6185
+ if (contentType === "" || contentType.includes("text/event-stream") || contentType.includes("application/octet-stream")) {
6155
6186
  const iterator = result.bodyHandle.events({ id: "llm-adapter.relay", mandatory: true, signal })[Symbol.asyncIterator]();
6156
6187
  let call, callIndex, args = "", argumentBytes = 0, argumentsDone, outputDone = false, terminal = false, done = false;
6157
6188
  const reasoning = new Map;
@@ -6241,7 +6272,7 @@ async function relayPayload(result, param, signal) {
6241
6272
  } finally {
6242
6273
  await iterator.return?.();
6243
6274
  }
6244
- } else if (result.bodyHandle.identity.contentType.includes("json"))
6275
+ } else if (contentType.includes("json"))
6245
6276
  response = await result.bodyHandle.json({ id: "llm-adapter.relay", mandatory: true, signal });
6246
6277
  else
6247
6278
  invalid(param);
@@ -6480,10 +6511,25 @@ class AgentRelay {
6480
6511
  }
6481
6512
 
6482
6513
  // plugins/llm-protocol-adapter/server/service.ts
6483
- var REASONING_RULES_VERSION = "2026-10-10.3";
6514
+ var REASONING_RULES_VERSION = "2026-10-12.1";
6484
6515
  var concrete = new Set(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
6485
- function catalogModel(provider, model) {
6486
- return provider === "zai" && model === "GLM-5.3-Flash" ? "glm-5.3-flash" : model;
6516
+ function identityError(code, message) {
6517
+ throw new ResponsesCodecError(code, message, "modelIdentity");
6518
+ }
6519
+ function parseModelIdentity(value) {
6520
+ if (value === undefined)
6521
+ return;
6522
+ const object = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
6523
+ const identifier = (v) => typeof v === "string" && v.length > 0 && v === v.trim();
6524
+ if (!object(value) || Object.keys(value).length !== 2 || !Object.keys(value).every((key) => ["wireModel", "catalogModel"].includes(key)) || !identifier(value.wireModel) || !object(value.catalogModel) || Object.keys(value.catalogModel).length !== 2 || !Object.keys(value.catalogModel).every((key) => ["provider", "model"].includes(key)) || !identifier(value.catalogModel.provider) || !identifier(value.catalogModel.model))
6525
+ throw new ResponsesCodecError("invalid_model_identity", "Model identity declaration is invalid", "modelIdentity");
6526
+ return { wireModel: value.wireModel, catalogModel: { provider: value.catalogModel.provider, model: value.catalogModel.model } };
6527
+ }
6528
+ function checkedIdentity(value, model) {
6529
+ const identity = parseModelIdentity(value);
6530
+ if (identity && identity.wireModel !== model)
6531
+ identityError("model_identity_mismatch", "Declared wire model differs from the actual target");
6532
+ return identity;
6487
6533
  }
6488
6534
  function rule(provider, model, protocol) {
6489
6535
  if (provider === "zai" && ["glm-5.3", "glm-5.3-flash"].includes(model) && protocol === "chat_completions")
@@ -6497,7 +6543,6 @@ function rule(provider, model, protocol) {
6497
6543
  return null;
6498
6544
  }
6499
6545
  function resolveCapabilities(catalog, context) {
6500
- context = { ...context, model: catalogModel(context.provider, context.model) };
6501
6546
  const info = catalog.model(context);
6502
6547
  if (!info)
6503
6548
  return null;
@@ -6559,8 +6604,15 @@ function conversionService(catalog, worker, history, runBackground) {
6559
6604
  createSession(context) {
6560
6605
  if (!worker)
6561
6606
  throw new Error("llm_adapter_conversion_requires_worker");
6562
- const info = context.profile ?? catalog.model({ provider: context.provider, model: catalogModel(context.provider, context.model) });
6563
- const profile = context.profile ? structuredClone(context.profile) : info ? resolveCapabilities(catalog, { provider: info.provider, model: context.model, targetProtocol: context.targetProtocol }) : undefined;
6607
+ const declaration = checkedIdentity(context.modelIdentity, context.model);
6608
+ const restrictions = context.restrictions ? structuredClone(context.restrictions) : undefined;
6609
+ const reference = declaration?.catalogModel ?? { provider: context.provider, model: context.model };
6610
+ const info = context.profile ?? catalog.model(reference);
6611
+ let profile = context.profile ? structuredClone(context.profile) : info ? resolveCapabilities(catalog, { provider: info.provider, model: info.model, targetProtocol: context.targetProtocol, restrictions }) : null;
6612
+ if (declaration && (!profile || profile.provider !== reference.provider || profile.model !== reference.model))
6613
+ identityError("model_identity_unavailable", "Declared catalog model is unavailable");
6614
+ const entryProfile = profile;
6615
+ let catalogVersion = profile?.catalogVersion ?? null;
6564
6616
  let selected = context.selectedEffort;
6565
6617
  const passthrough = context.sourceProtocol === context.targetProtocol;
6566
6618
  if (!passthrough && selected !== undefined && (!profile || !profile.supportedEfforts.includes(selected)))
@@ -6593,29 +6645,56 @@ function conversionService(catalog, worker, history, runBackground) {
6593
6645
  engine.dispose();
6594
6646
  }
6595
6647
  },
6596
- validateAttempt({ model, protocol, body, url }) {
6648
+ validateAttempt({ model, protocol, body, url, modelIdentity }) {
6597
6649
  if (disposed)
6598
6650
  throw new Error("llm_adapter_session_disposed");
6599
6651
  if (protocol !== context.targetProtocol)
6600
6652
  throw new ResponsesCodecError("target_protocol_mismatch", "Actual target protocol differs from the session", "url");
6601
6653
  if (url) {
6602
- const path = new URL(url).pathname;
6654
+ let path;
6655
+ try {
6656
+ path = new URL(url).pathname;
6657
+ } catch {
6658
+ throw new ResponsesCodecError("target_protocol_mismatch", "Actual target URL is invalid", "url");
6659
+ }
6603
6660
  const valid = protocol === "responses" ? /\/responses$/.test(path) : protocol === "chat_completions" ? /\/chat\/completions$/.test(path) : protocol === "anthropic_messages" ? /\/messages$/.test(path) : /:(?:streamGenerateContent|generateContent)$/.test(path);
6604
6661
  if (!valid)
6605
6662
  throw new ResponsesCodecError("target_protocol_mismatch", "Actual target URL does not implement the session protocol", "url");
6606
6663
  }
6607
- const actual = profile && profile.model === catalogModel(profile.provider, model) ? profile : profile ? resolveCapabilities(catalog, { provider: profile.provider, model, targetProtocol: protocol }) : null;
6664
+ const actualModel = protocolRequestModel(protocol, body, url);
6665
+ const identity = checkedIdentity(modelIdentity, actualModel);
6666
+ if (model !== actualModel)
6667
+ identityError("model_identity_mismatch", "Model argument differs from the actual target");
6668
+ model = actualModel;
6669
+ const reference = identity?.catalogModel ?? { provider: profile?.provider ?? context.provider, model };
6670
+ const sameIdentity = !!profile && reference.provider === profile.provider && reference.model === profile.model;
6671
+ const info = sameIdentity ? profile : catalog.model(reference);
6672
+ const actual = sameIdentity ? profile : info ? resolveCapabilities(catalog, { provider: info.provider, model: info.model, targetProtocol: protocol, restrictions }) : null;
6673
+ if (identity && !actual)
6674
+ identityError("model_identity_unavailable", "Declared catalog model is unavailable");
6675
+ if (actual && catalogVersion !== null && actual.catalogVersion !== catalogVersion)
6676
+ identityError("model_identity_catalog_changed", "Target catalog version differs from the generation snapshot");
6677
+ const sameNativeIdentity = entryProfile ? !!actual && actual.provider === entryProfile.provider && actual.model === entryProfile.model : !identity && model === context.model;
6608
6678
  if (selected !== undefined) {
6609
- if (passthrough && model === context.model && wireEffort(body, protocol) === selected)
6610
- return { model, effort: selected, catalogVersion: profile?.catalogVersion ?? null, rulesVersion: REASONING_RULES_VERSION };
6611
- if (!actual || actual.catalogVersion !== profile?.catalogVersion || actual.rulesVersion !== profile?.rulesVersion || !actual.supportedEfforts.includes(selected) || wireEffort(body, protocol) !== selected)
6612
- fail2("reasoning.effort");
6613
- if (protocol === "anthropic_messages" && body?.thinking?.type !== "adaptive")
6614
- fail2("thinking.type");
6615
- if (protocol === "chat_completions" && profile?.provider === "zai" && body?.thinking?.type !== "enabled")
6616
- fail2("thinking.type");
6679
+ if (!(passthrough && sameNativeIdentity && wireEffort(body, protocol) === selected)) {
6680
+ if (!entryProfile || !actual || actual.rulesVersion !== entryProfile.rulesVersion || !actual.supportedEfforts.includes(selected) || wireEffort(body, protocol) !== selected)
6681
+ fail2("reasoning.effort");
6682
+ if (protocol === "anthropic_messages" && body?.thinking?.type !== "adaptive")
6683
+ fail2("thinking.type");
6684
+ if (protocol === "chat_completions" && actual.provider === "zai" && body?.thinking?.type !== "enabled")
6685
+ fail2("thinking.type");
6686
+ }
6687
+ } else if (!profile && actual && identity) {
6688
+ profile = structuredClone(actual);
6689
+ catalogVersion = actual.catalogVersion;
6617
6690
  }
6618
- return { model, effort: selected ?? null, catalogVersion: profile?.catalogVersion ?? null, rulesVersion: REASONING_RULES_VERSION };
6691
+ return {
6692
+ model,
6693
+ catalogModel: actual ? { provider: actual.provider, model: actual.model } : null,
6694
+ effort: selected ?? null,
6695
+ catalogVersion,
6696
+ rulesVersion: REASONING_RULES_VERSION
6697
+ };
6619
6698
  }
6620
6699
  };
6621
6700
  return session;
@@ -6650,7 +6729,7 @@ function responseHandler(input) {
6650
6729
  hooks.onValidateOutbound.tapPromise("llm-adapter.target", async (outbound) => {
6651
6730
  check();
6652
6731
  try {
6653
- const result = input.session.validateAttempt({ model: outbound.model ?? input.model, protocol: input.targetProtocol, body: outbound.body, url: outbound.url });
6732
+ const result = input.session.validateAttempt({ model: protocolRequestModel(input.targetProtocol, outbound.body, outbound.url), modelIdentity: readModelIdentity(outbound.annotations), protocol: input.targetProtocol, body: outbound.body, url: outbound.url });
6654
6733
  logger.info({ requestId: outbound.requestId, attemptId: outbound.attemptId, ...result }, "llm_adapter_target_validated");
6655
6734
  input.log?.(result);
6656
6735
  } catch (e) {
@@ -6658,6 +6737,8 @@ function responseHandler(input) {
6658
6737
  }
6659
6738
  return outbound;
6660
6739
  });
6740
+ if (input.validationOnly)
6741
+ return;
6661
6742
  hooks.onResponse.tapPromise("llm-adapter.response", async (response, ctx) => {
6662
6743
  context = ctx;
6663
6744
  if (!response.ok || !response.headers.get("content-type")?.includes("json"))
@@ -6984,7 +7065,7 @@ var server_default = definePlugin(class {
6984
7065
  });
6985
7066
  }
6986
7067
  bodyRequirements(ctx) {
6987
- return this.applied && ctx.method === "POST" && protocolForPath(ctx.url.pathname) !== null ? { request: "json-write", response: ["json", "sse-json"] } : { request: "none" };
7068
+ return this.applied && ctx.method === "POST" && protocolForPath(ctx.url.pathname) !== null ? { request: "json-write", ...this.options?.sourceProtocol !== this.options?.targetProtocol ? { response: ["json", "sse-json"] } : {} } : { request: "none" };
6988
7069
  }
6989
7070
  register(hooks) {
6990
7071
  if (!this.applied)
@@ -7000,27 +7081,42 @@ var server_default = definePlugin(class {
7000
7081
  }
7001
7082
  if (source !== this.options.sourceProtocol)
7002
7083
  throw new DataAdmissionError(422, "llm_adapter_source_protocol_mismatch");
7003
- if (source === this.options.targetProtocol)
7004
- return ctx;
7005
- if (this.active.has(ctx.requestId))
7084
+ if (this.active.has(ctx.requestId)) {
7085
+ if (source === this.options.targetProtocol)
7086
+ return ctx;
7006
7087
  throw new DataAdmissionError(422, "llm_adapter_duplicate_conversion");
7007
- const model = source === "gemini_generate_content" ? decodeURIComponent(ctx.url.pathname.match(/\/models\/([^/]+):/)[1]) : ctx.body?.model;
7008
- if (typeof model !== "string" || !model)
7009
- throw new DataAdmissionError(422, "llm_adapter_model_required");
7010
- const session = this.service.createSession({ sourceProtocol: source, targetProtocol: this.options.targetProtocol, model, ...source === "gemini_generate_content" ? { streaming: ctx.url.pathname.endsWith(":streamGenerateContent") } : {} });
7088
+ }
7089
+ let session;
7090
+ let model;
7011
7091
  try {
7092
+ model = protocolRequestModel(source, ctx.body, ctx.url);
7093
+ session = this.service.createSession({
7094
+ sourceProtocol: source,
7095
+ targetProtocol: this.options.targetProtocol,
7096
+ model,
7097
+ modelIdentity: readModelIdentity(ctx.annotations),
7098
+ ...source === "gemini_generate_content" ? { streaming: ctx.url.pathname.endsWith(":streamGenerateContent") } : {}
7099
+ });
7012
7100
  const result = session.convertRequest(ctx.body);
7013
- if (result.diagnostics.length)
7014
- logger.info({ requestId: ctx.requestId, diagnostics: structuredClone(result.diagnostics) }, "llm_adapter_request_diagnostics");
7015
- ctx.body = structuredClone(result.body);
7016
- ctx.url.pathname = targetPath(ctx.url.pathname, this.options.targetProtocol, model, result.streaming);
7017
- if (this.options.targetProtocol === "gemini_generate_content" && result.streaming)
7018
- ctx.url.searchParams.set("alt", "sse");
7101
+ if (source !== this.options.targetProtocol) {
7102
+ if (result.diagnostics.length)
7103
+ logger.info({ requestId: ctx.requestId, diagnostics: structuredClone(result.diagnostics) }, "llm_adapter_request_diagnostics");
7104
+ ctx.body = structuredClone(result.body);
7105
+ ctx.url.pathname = targetPath(ctx.url.pathname, this.options.targetProtocol, model, result.streaming);
7106
+ if (this.options.targetProtocol === "gemini_generate_content" && result.streaming)
7107
+ ctx.url.searchParams.set("alt", "sse");
7108
+ }
7019
7109
  } catch (error) {
7020
- session.dispose();
7110
+ session?.dispose();
7021
7111
  adapterError(error);
7022
7112
  }
7023
- const handler = responseHandler({ session, sourceProtocol: source, targetProtocol: this.options.targetProtocol, model });
7113
+ const handler = responseHandler({
7114
+ session,
7115
+ sourceProtocol: source,
7116
+ targetProtocol: this.options.targetProtocol,
7117
+ model,
7118
+ validationOnly: source === this.options.targetProtocol
7119
+ });
7024
7120
  this.active.set(ctx.requestId, { handler, session });
7025
7121
  return ctx;
7026
7122
  });
@@ -7047,4 +7143,4 @@ export {
7047
7143
  targetPath
7048
7144
  };
7049
7145
 
7050
- //# debugId=04C6BEB6A1F100D964756E2164756E21
7146
+ //# debugId=40CBB2F3F4855EA864756E2164756E21