@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.
- package/dist/config-storage-worker.js +3 -1
- package/dist/main.js +2756 -295
- package/dist/plugins/chatgpt-oauth/index.js +92 -20
- package/dist/plugins/chatgpt-oauth/index.js.map +4 -4
- package/dist/plugins/codex-router/control.js +606 -2
- package/dist/plugins/codex-router/control.js.map +20 -5
- package/dist/plugins/codex-router/index.js +2459 -94
- package/dist/plugins/codex-router/index.js.map +20 -8
- package/dist/plugins/codex-router/manifest.json +14 -14
- package/dist/plugins/llm-protocol-adapter/control.js +96 -21
- package/dist/plugins/llm-protocol-adapter/control.js.map +8 -7
- package/dist/plugins/llm-protocol-adapter/index.js +134 -38
- package/dist/plugins/llm-protocol-adapter/index.js.map +11 -10
- package/dist/plugins/model-mapping/control.js +1 -1
- package/dist/plugins/model-mapping/control.js.map +3 -3
- package/dist/plugins/model-mapping/index.js +48 -17
- package/dist/plugins/model-mapping/index.js.map +6 -5
- package/dist/plugins/model-mapping/manifest.json +50 -6
- package/dist/plugins/models-dev/control.js +1 -1
- package/dist/plugins/models-dev/control.js.map +3 -3
- package/dist/plugins/models-dev/index.js +1 -1
- package/dist/plugins/models-dev/index.js.map +3 -3
- package/dist/plugins/token-metering/index.js +1 -1
- package/dist/plugins/token-metering/index.js.map +1 -1
- package/dist/plugins/token-stats/control.js +1 -1
- package/dist/plugins/token-stats/control.js.map +3 -3
- package/dist/plugins/token-stats/index.js +1 -1
- package/dist/plugins/token-stats/index.js.map +3 -3
- 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
|
-
|
|
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 (
|
|
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-
|
|
6514
|
+
var REASONING_RULES_VERSION = "2026-10-12.1";
|
|
6484
6515
|
var concrete = new Set(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
6485
|
-
function
|
|
6486
|
-
|
|
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
|
|
6563
|
-
const
|
|
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
|
-
|
|
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
|
|
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 &&
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
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 {
|
|
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.
|
|
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 (
|
|
7004
|
-
|
|
7005
|
-
|
|
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
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
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 (
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
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
|
|
7110
|
+
session?.dispose();
|
|
7021
7111
|
adapterError(error);
|
|
7022
7112
|
}
|
|
7023
|
-
const handler = responseHandler({
|
|
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=
|
|
7146
|
+
//# debugId=40CBB2F3F4855EA864756E2164756E21
|