omnigateway 0.4.12 → 0.5.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.
Files changed (47) hide show
  1. package/README.md +138 -239
  2. package/bin/omni.js +1111 -516
  3. package/gateway.js +2009 -474
  4. package/package.json +1 -1
  5. package/public/assets/{CopyValue-By5BAgv7.js → CopyValue-dQWAaTxf.js} +3 -3
  6. package/public/assets/{Field-B79Yxdit.js → Field-DTQ2LPzA.js} +1 -1
  7. package/public/assets/{Match-BWa6L0L1.js → Match-C85GObiU.js} +1 -1
  8. package/public/assets/{Panel-CoulMx6R.js → Panel-CQVz9yeR.js} +2 -2
  9. package/public/assets/Rack-V32CHmN6.js +316 -0
  10. package/public/assets/{Readout-D1XEfywe.js → Readout-DJR1qKja.js} +1 -1
  11. package/public/assets/States-CauIsA0N.js +54 -0
  12. package/public/assets/{Toggle-ClEeOh0F.js → Toggle-BQI8jz09.js} +1 -1
  13. package/public/assets/{TokenBreakdown-D70VeZ2N.js → TokenBreakdown-B2_gfuqt.js} +1 -1
  14. package/public/assets/_app-DzzXdoyU.js +1 -0
  15. package/public/assets/_app.accounts-owsnxlbn.js +64 -0
  16. package/public/assets/_app.console-bzKNP_8Y.js +44 -0
  17. package/public/assets/_app.database-CsJbkedE.js +24 -0
  18. package/public/assets/_app.index-D4ydl2mY.js +62 -0
  19. package/public/assets/_app.keys-DKX0smty.js +82 -0
  20. package/public/assets/_app.logs-CFFsj2zR.js +68 -0
  21. package/public/assets/_app.models-B0ZxWGHV.js +148 -0
  22. package/public/assets/{_app.plugins._pluginId-B-ZDQNPU.js → _app.plugins._pluginId-C5X4B1cE.js} +3 -3
  23. package/public/assets/{_app.settings-DTnFwTeA.js → _app.settings-Yg_6az-L.js} +4 -4
  24. package/public/assets/_app.usage-BRIz_GCn.js +83 -0
  25. package/public/assets/index-DiCU8bLB.js +178 -0
  26. package/public/assets/{login-DjfMomJJ.js → login-B4LoiALI.js} +3 -3
  27. package/public/assets/plus-xu9reaJp.js +1 -0
  28. package/public/assets/queries-DuSqKybM.js +145 -0
  29. package/public/assets/{shared-Cct_4xwp.js → shared-DYkFSPbd.js} +4 -4
  30. package/public/assets/stream-Dz5HjHBh.js +1 -0
  31. package/public/assets/{trash-2-U2ViYZum.js → trash-2-DbutVvFY.js} +1 -1
  32. package/public/index.html +3 -3
  33. package/public/shared/dashboard-sdk.js +1 -1
  34. package/public/assets/Rack-fDZClWZL.js +0 -314
  35. package/public/assets/States-DtkkMzEu.js +0 -54
  36. package/public/assets/_app-CDPKnQ72.js +0 -1
  37. package/public/assets/_app.accounts-Dz0ox4Br.js +0 -64
  38. package/public/assets/_app.console-hPUmmYjp.js +0 -44
  39. package/public/assets/_app.database-DGtP4NdG.js +0 -24
  40. package/public/assets/_app.index-COcCAmbH.js +0 -62
  41. package/public/assets/_app.keys-yTXTbKTA.js +0 -76
  42. package/public/assets/_app.logs-BhMvO_Fx.js +0 -68
  43. package/public/assets/_app.models-0S3rurIl.js +0 -148
  44. package/public/assets/_app.usage-C2-VLiq9.js +0 -83
  45. package/public/assets/index-COwhxKU7.js +0 -178
  46. package/public/assets/plus-UDQ_BTEr.js +0 -1
  47. package/public/assets/queries-CX9mStps.js +0 -145
package/gateway.js CHANGED
@@ -2763,8 +2763,8 @@ function checkBytes(buffer, headers, options) {
2763
2763
  return true;
2764
2764
  }
2765
2765
  function hasUnknownFileSize(tokenizer) {
2766
- const fileSize = tokenizer.fileInfo.size;
2767
- return !Number.isFinite(fileSize) || fileSize === Number.MAX_SAFE_INTEGER;
2766
+ const fileSize2 = tokenizer.fileInfo.size;
2767
+ return !Number.isFinite(fileSize2) || fileSize2 === Number.MAX_SAFE_INTEGER;
2768
2768
  }
2769
2769
  function hasExceededUnknownSizeScanBudget(tokenizer, startOffset, maximumBytes) {
2770
2770
  return hasUnknownFileSize(tokenizer) && tokenizer.position - startOffset > maximumBytes;
@@ -2822,8 +2822,8 @@ function mergeByteChunks(chunks, totalLength) {
2822
2822
  return merged;
2823
2823
  }
2824
2824
  function getMaximumZipBufferedReadLength(tokenizer) {
2825
- const fileSize = tokenizer.fileInfo.size;
2826
- const remainingBytes = Number.isFinite(fileSize) ? Math.max(0, fileSize - tokenizer.position) : Number.MAX_SAFE_INTEGER;
2825
+ const fileSize2 = tokenizer.fileInfo.size;
2826
+ const remainingBytes = Number.isFinite(fileSize2) ? Math.max(0, fileSize2 - tokenizer.position) : Number.MAX_SAFE_INTEGER;
2827
2827
  return Math.min(remainingBytes, maximumZipBufferedReadSizeInBytes);
2828
2828
  }
2829
2829
  function isRecoverableZipError(error51) {
@@ -3561,11 +3561,11 @@ function normalizeMpegOffsetTolerance(mpegOffsetTolerance) {
3561
3561
  }
3562
3562
  return Math.max(0, Math.min(maximumMpegOffsetTolerance, Math.trunc(mpegOffsetTolerance)));
3563
3563
  }
3564
- function getKnownFileSizeOrMaximum(fileSize) {
3565
- if (!Number.isFinite(fileSize)) {
3564
+ function getKnownFileSizeOrMaximum(fileSize2) {
3565
+ if (!Number.isFinite(fileSize2)) {
3566
3566
  return Number.MAX_SAFE_INTEGER;
3567
3567
  }
3568
- return Math.max(0, fileSize);
3568
+ return Math.max(0, fileSize2);
3569
3569
  }
3570
3570
  function importAtRuntime(specifier) {
3571
3571
  return import(specifier);
@@ -4683,8 +4683,8 @@ class FileTypeParser {
4683
4683
  if (jsonSize > 12 && this.buffer.length >= jsonSize + 16) {
4684
4684
  try {
4685
4685
  const header = new TextDecoder().decode(this.buffer.subarray(16, jsonSize + 16));
4686
- const json7 = JSON.parse(header);
4687
- if (json7.files) {
4686
+ const json8 = JSON.parse(header);
4687
+ if (json8.files) {
4688
4688
  return {
4689
4689
  ext: "asar",
4690
4690
  mime: "application/x-asar"
@@ -4804,8 +4804,8 @@ class FileTypeParser {
4804
4804
  };
4805
4805
  detectImprecise = async (tokenizer) => {
4806
4806
  this.buffer = new Uint8Array(reasonableDetectionSizeInBytes);
4807
- const fileSize = getKnownFileSizeOrMaximum(tokenizer.fileInfo.size);
4808
- await tokenizer.peekBuffer(this.buffer, { length: Math.min(8, fileSize), mayBeLess: true });
4807
+ const fileSize2 = getKnownFileSizeOrMaximum(tokenizer.fileInfo.size);
4808
+ await tokenizer.peekBuffer(this.buffer, { length: Math.min(8, fileSize2), mayBeLess: true });
4809
4809
  if (this.check([0, 0, 1, 186]) || this.check([0, 0, 1, 179])) {
4810
4810
  return {
4811
4811
  ext: "mpg",
@@ -4830,7 +4830,7 @@ class FileTypeParser {
4830
4830
  mime: "image/x-icon"
4831
4831
  };
4832
4832
  }
4833
- await tokenizer.peekBuffer(this.buffer, { length: Math.min(2 + this.options.mpegOffsetTolerance, fileSize), mayBeLess: true });
4833
+ await tokenizer.peekBuffer(this.buffer, { length: Math.min(2 + this.options.mpegOffsetTolerance, fileSize2), mayBeLess: true });
4834
4834
  if (this.buffer.length >= 2 + this.options.mpegOffsetTolerance) {
4835
4835
  for (let depth = 0;depth <= this.options.mpegOffsetTolerance; ++depth) {
4836
4836
  const type = this.scanMpeg(depth);
@@ -5523,6 +5523,15 @@ function parseLogLevel(value) {
5523
5523
  function cacheControlOf(block) {
5524
5524
  return block.type === "thinking" ? undefined : block.cacheControl;
5525
5525
  }
5526
+ var REASONING_EFFORTS = [
5527
+ "none",
5528
+ "minimal",
5529
+ "low",
5530
+ "medium",
5531
+ "high",
5532
+ "xhigh",
5533
+ "max"
5534
+ ];
5526
5535
  // packages/ir/src/stream.ts
5527
5536
  function usageFromPromptTotal(promptTokens, outputTokens, cacheReadTokens, cacheWriteTokens = 0) {
5528
5537
  return {
@@ -5751,7 +5760,6 @@ function loadConfig(env) {
5751
5760
  const baseUrl = optionalText(env.OMNI_BASE_URL, derivedBaseUrl).replace(/\/+$/, "") || derivedBaseUrl;
5752
5761
  const staticDir = env.OMNI_STATIC_DIR?.trim();
5753
5762
  const logFile = env.OMNI_LOG_FILE?.trim();
5754
- const exposeClaudeCodeAliases = TRUTHY.has((env.OMNI_EXPOSE_CLAUDE_CODE_ALIASES ?? "").trim().toLowerCase());
5755
5763
  const bodyLoggingAllowed = TRUTHY.has((env.OMNI_BODY_LOGGING_ALLOWED ?? "").trim().toLowerCase());
5756
5764
  const rawLogLevel = env.OMNI_LOG_LEVEL?.trim();
5757
5765
  const logLevel = parseLogLevel(rawLogLevel);
@@ -5764,7 +5772,6 @@ function loadConfig(env) {
5764
5772
  encryptionKey,
5765
5773
  baseUrl,
5766
5774
  staticDir: staticDir === undefined || staticDir.length === 0 ? null : staticDir,
5767
- exposeClaudeCodeAliases,
5768
5775
  bodyLoggingAllowed,
5769
5776
  logFile: logFile === undefined || logFile.length === 0 ? null : logFile
5770
5777
  };
@@ -7502,13 +7509,31 @@ var anthropicAdapter = {
7502
7509
  };
7503
7510
  }
7504
7511
  };
7505
- // packages/providers/src/kimi/decode.ts
7506
- var FINISH = {
7512
+ // packages/providers/src/custom/decode.ts
7513
+ var CHAT_FINISH = {
7507
7514
  stop: "endTurn",
7508
7515
  length: "maxTokens",
7509
7516
  tool_calls: "toolUse",
7510
7517
  content_filter: "contentFilter"
7511
7518
  };
7519
+ function reasoningText(delta) {
7520
+ if (typeof delta.reasoning === "string" && delta.reasoning.length > 0)
7521
+ return delta.reasoning;
7522
+ if (typeof delta.reasoning_content === "string" && delta.reasoning_content.length > 0) {
7523
+ return delta.reasoning_content;
7524
+ }
7525
+ if (!Array.isArray(delta.reasoning_details))
7526
+ return "";
7527
+ return delta.reasoning_details.flatMap((entry) => {
7528
+ if (entry === null || typeof entry !== "object")
7529
+ return [];
7530
+ if (typeof entry.text === "string" && entry.text.length > 0)
7531
+ return [entry.text];
7532
+ if (typeof entry.summary === "string" && entry.summary.length > 0)
7533
+ return [entry.summary];
7534
+ return [];
7535
+ }).join("");
7536
+ }
7512
7537
  function json2(data) {
7513
7538
  try {
7514
7539
  const v = JSON.parse(data);
@@ -7517,7 +7542,7 @@ function json2(data) {
7517
7542
  return null;
7518
7543
  }
7519
7544
  }
7520
- async function* decodeChat(messages) {
7545
+ async function* decodeCustomChat(messages) {
7521
7546
  let started = false;
7522
7547
  let done = false;
7523
7548
  let stopReason = "endTurn";
@@ -7546,6 +7571,21 @@ async function* decodeChat(messages) {
7546
7571
  if (!choice)
7547
7572
  continue;
7548
7573
  const delta = choice.delta ?? {};
7574
+ const reasoning = reasoningText(delta);
7575
+ if (reasoning.length > 0) {
7576
+ if (openKind !== "thinking") {
7577
+ if (openKind !== undefined)
7578
+ yield { type: "blockEnd", index: openIndex };
7579
+ openKind = "thinking";
7580
+ openIndex = nextIndex++;
7581
+ yield { type: "blockStart", index: openIndex, block: { type: "thinking" } };
7582
+ }
7583
+ yield {
7584
+ type: "blockDelta",
7585
+ index: openIndex,
7586
+ delta: { type: "thinking", text: reasoning }
7587
+ };
7588
+ }
7549
7589
  if (typeof delta.content === "string" && delta.content.length > 0) {
7550
7590
  if (openKind !== "text") {
7551
7591
  if (openKind !== undefined)
@@ -7586,7 +7626,7 @@ async function* decodeChat(messages) {
7586
7626
  }
7587
7627
  }
7588
7628
  if (typeof choice.finish_reason === "string") {
7589
- stopReason = FINISH[choice.finish_reason] ?? "endTurn";
7629
+ stopReason = CHAT_FINISH[choice.finish_reason] ?? "endTurn";
7590
7630
  }
7591
7631
  }
7592
7632
  if (done) {
@@ -7602,110 +7642,7 @@ async function* decodeChat(messages) {
7602
7642
  };
7603
7643
  }
7604
7644
  }
7605
-
7606
- // packages/providers/src/kimi/wire.ts
7607
- function encodeToolChoice2(c) {
7608
- switch (c.type) {
7609
- case "auto":
7610
- return "auto";
7611
- case "any":
7612
- return "required";
7613
- case "none":
7614
- return "none";
7615
- case "tool":
7616
- return { type: "function", function: { name: c.name } };
7617
- }
7618
- }
7619
- function toChatWire(req, model, vendor = "kimi") {
7620
- const degradations = [];
7621
- const note = (d) => {
7622
- if (!degradations.includes(d))
7623
- degradations.push(d);
7624
- };
7625
- if (req.betas?.includes(CONTEXT_1M_BETA))
7626
- note("kimi:context-1m-dropped");
7627
- const messages = [];
7628
- const system = req.system?.flatMap((b) => b.type === "text" ? [b.text] : []).join(`
7629
-
7630
- `);
7631
- if (system !== undefined && system.length > 0)
7632
- messages.push({ role: "system", content: system });
7633
- for (const message of req.messages) {
7634
- const text = [];
7635
- const toolCalls = [];
7636
- for (const block of message.content) {
7637
- switch (block.type) {
7638
- case "text":
7639
- text.push(block.text);
7640
- break;
7641
- case "image":
7642
- note("kimi:images-dropped");
7643
- break;
7644
- case "thinking":
7645
- note("kimi:thinking-dropped");
7646
- break;
7647
- case "toolUse":
7648
- toolCalls.push({
7649
- id: block.id,
7650
- type: "function",
7651
- function: { name: block.name, arguments: JSON.stringify(block.input) }
7652
- });
7653
- break;
7654
- case "toolResult":
7655
- messages.push({
7656
- role: "tool",
7657
- tool_call_id: block.toolUseId,
7658
- content: block.content
7659
- });
7660
- break;
7661
- case "anthropicNative":
7662
- note("kimi:anthropic-native-block-dropped");
7663
- break;
7664
- }
7665
- }
7666
- if (toolCalls.length > 0) {
7667
- messages.push({
7668
- role: message.role,
7669
- content: text.length > 0 ? text.join(`
7670
- `) : null,
7671
- tool_calls: toolCalls
7672
- });
7673
- } else if (text.length > 0) {
7674
- messages.push({ role: message.role, content: text.join(`
7675
- `) });
7676
- }
7677
- }
7678
- const body = {
7679
- model,
7680
- messages,
7681
- stream: req.stream,
7682
- stream_options: { include_usage: true }
7683
- };
7684
- if (req.maxTokens !== undefined)
7685
- body.max_tokens = req.maxTokens;
7686
- if (req.temperature !== undefined)
7687
- body.temperature = req.temperature;
7688
- if (req.stopSequences !== undefined)
7689
- body.stop = req.stopSequences;
7690
- if (req.tools !== undefined) {
7691
- const custom = req.tools.filter((t) => t.provider === "custom");
7692
- if (custom.length !== req.tools.length)
7693
- note("kimi:anthropic-tool-dropped");
7694
- body.tools = custom.map((t) => ({
7695
- type: "function",
7696
- function: { name: t.name, description: t.description, parameters: t.inputSchema }
7697
- }));
7698
- }
7699
- if (req.toolChoice !== undefined)
7700
- body.tool_choice = encodeToolChoice2(req.toolChoice);
7701
- if (req.reasoning !== undefined)
7702
- note("kimi:reasoning-dropped");
7703
- Object.assign(body, req.vendor?.[vendor] ?? {});
7704
- return { body, degradations };
7705
- }
7706
-
7707
- // packages/providers/src/openai/decode.ts
7708
- var ERROR_CODE = {
7645
+ var RESPONSES_ERROR_CODE = {
7709
7646
  rate_limit_exceeded: "RATE_LIMIT",
7710
7647
  insufficient_quota: "QUOTA_EXHAUSTED",
7711
7648
  invalid_api_key: "AUTH",
@@ -7713,15 +7650,7 @@ var ERROR_CODE = {
7713
7650
  context_length_exceeded: "BAD_REQUEST",
7714
7651
  content_policy_violation: "CONTENT_FILTER"
7715
7652
  };
7716
- function json3(data) {
7717
- try {
7718
- const v = JSON.parse(data);
7719
- return typeof v === "object" && v !== null ? v : null;
7720
- } catch {
7721
- return null;
7722
- }
7723
- }
7724
- async function* decodeResponses(messages) {
7653
+ async function* decodeCustomResponses(messages) {
7725
7654
  const indices = new Map;
7726
7655
  let next = 0;
7727
7656
  const irIndex = (outputIndex, contentIndex = 0) => {
@@ -7737,7 +7666,7 @@ async function* decodeResponses(messages) {
7737
7666
  let terminal = false;
7738
7667
  const ownsBlock = new Set;
7739
7668
  for await (const msg of messages) {
7740
- const d = json3(msg.data);
7669
+ const d = json2(msg.data);
7741
7670
  if (d === null)
7742
7671
  continue;
7743
7672
  switch (msg.event) {
@@ -7829,7 +7758,7 @@ async function* decodeResponses(messages) {
7829
7758
  case "error": {
7830
7759
  terminal = true;
7831
7760
  const err = d.response?.error ?? d.error ?? {};
7832
- const code = ERROR_CODE[String(err.code ?? err.type)] ?? "UPSTREAM";
7761
+ const code = RESPONSES_ERROR_CODE[String(err.code ?? err.type)] ?? "UPSTREAM";
7833
7762
  yield {
7834
7763
  type: "error",
7835
7764
  code,
@@ -7852,8 +7781,20 @@ async function* decodeResponses(messages) {
7852
7781
  }
7853
7782
  }
7854
7783
 
7855
- // packages/providers/src/openai/wire.ts
7856
- function encodeToolChoice3(c) {
7784
+ // packages/providers/src/custom/wire.ts
7785
+ function encodeChatToolChoice(c) {
7786
+ switch (c.type) {
7787
+ case "auto":
7788
+ return "auto";
7789
+ case "any":
7790
+ return "required";
7791
+ case "none":
7792
+ return "none";
7793
+ case "tool":
7794
+ return { type: "function", function: { name: c.name } };
7795
+ }
7796
+ }
7797
+ function encodeResponsesToolChoice(c) {
7857
7798
  switch (c.type) {
7858
7799
  case "auto":
7859
7800
  return "auto";
@@ -7865,20 +7806,115 @@ function encodeToolChoice3(c) {
7865
7806
  return { type: "function", name: c.name };
7866
7807
  }
7867
7808
  }
7868
- function toResponsesWire(req, model, opts = { oauth: false }) {
7809
+ function customEffort(reasoning) {
7810
+ if (reasoning === undefined || reasoning.mode !== "adaptive")
7811
+ return;
7812
+ return reasoning.effort ?? "medium";
7813
+ }
7814
+ function toCustomChatWire(req, model) {
7869
7815
  const degradations = [];
7870
- const input = [];
7871
7816
  const note = (d) => {
7872
7817
  if (!degradations.includes(d))
7873
7818
  degradations.push(d);
7874
7819
  };
7875
7820
  if (req.betas?.includes(CONTEXT_1M_BETA))
7876
- note("openai:context-1m-dropped");
7821
+ note("custom:context-1m-dropped");
7822
+ const messages = [];
7823
+ const system = req.system?.flatMap((b) => b.type === "text" ? [b.text] : []).join(`
7824
+
7825
+ `);
7826
+ if (system !== undefined && system.length > 0)
7827
+ messages.push({ role: "system", content: system });
7828
+ for (const message of req.messages) {
7829
+ const text = [];
7830
+ const toolCalls = [];
7831
+ for (const block of message.content) {
7832
+ switch (block.type) {
7833
+ case "text":
7834
+ text.push(block.text);
7835
+ break;
7836
+ case "image":
7837
+ note("custom:images-dropped");
7838
+ break;
7839
+ case "thinking":
7840
+ note("custom:thinking-dropped");
7841
+ break;
7842
+ case "toolUse":
7843
+ toolCalls.push({
7844
+ id: block.id,
7845
+ type: "function",
7846
+ function: { name: block.name, arguments: JSON.stringify(block.input) }
7847
+ });
7848
+ break;
7849
+ case "toolResult":
7850
+ messages.push({
7851
+ role: "tool",
7852
+ tool_call_id: block.toolUseId,
7853
+ content: block.content
7854
+ });
7855
+ break;
7856
+ case "anthropicNative":
7857
+ note("custom:anthropic-native-block-dropped");
7858
+ break;
7859
+ }
7860
+ }
7861
+ if (toolCalls.length > 0) {
7862
+ messages.push({
7863
+ role: message.role,
7864
+ content: text.length > 0 ? text.join(`
7865
+ `) : null,
7866
+ tool_calls: toolCalls
7867
+ });
7868
+ } else if (text.length > 0) {
7869
+ messages.push({ role: message.role, content: text.join(`
7870
+ `) });
7871
+ }
7872
+ }
7873
+ const body = {
7874
+ model,
7875
+ messages,
7876
+ stream: req.stream,
7877
+ stream_options: { include_usage: true }
7878
+ };
7879
+ if (req.maxTokens !== undefined)
7880
+ body.max_tokens = req.maxTokens;
7881
+ if (req.temperature !== undefined)
7882
+ body.temperature = req.temperature;
7883
+ if (req.stopSequences !== undefined)
7884
+ body.stop = req.stopSequences;
7885
+ if (req.tools !== undefined) {
7886
+ const portable = req.tools.filter((t) => t.provider === "custom");
7887
+ if (portable.length !== req.tools.length)
7888
+ note("custom:anthropic-tool-dropped");
7889
+ body.tools = portable.map((t) => ({
7890
+ type: "function",
7891
+ function: { name: t.name, description: t.description, parameters: t.inputSchema }
7892
+ }));
7893
+ }
7894
+ if (req.toolChoice !== undefined)
7895
+ body.tool_choice = encodeChatToolChoice(req.toolChoice);
7896
+ const effort = customEffort(req.reasoning);
7897
+ if (effort !== undefined)
7898
+ body.reasoning_effort = effort;
7899
+ else if (req.reasoning?.mode === "budget")
7900
+ note("custom:reasoning-budget-dropped");
7901
+ Object.assign(body, req.vendor?.openai ?? {});
7902
+ return { body, degradations };
7903
+ }
7904
+ function toCustomResponsesWire(req, model) {
7905
+ const degradations = [];
7906
+ const note = (d) => {
7907
+ if (!degradations.includes(d))
7908
+ degradations.push(d);
7909
+ };
7910
+ const input = [];
7911
+ if (req.betas?.includes(CONTEXT_1M_BETA))
7912
+ note("custom:context-1m-dropped");
7877
7913
  for (const message of req.messages) {
7878
7914
  const parts = [];
7879
7915
  const inlined = message.role === "system";
7880
7916
  if (inlined)
7881
- note("openai:system-turn-inlined");
7917
+ note("custom:system-turn-inlined");
7882
7918
  const role = inlined ? "user" : message.role;
7883
7919
  const flush = () => {
7884
7920
  if (parts.length === 0)
@@ -7903,9 +7939,7 @@ ${block.text}
7903
7939
  });
7904
7940
  break;
7905
7941
  case "thinking":
7906
- if (!degradations.includes("openai:thinking-dropped")) {
7907
- note("openai:thinking-dropped");
7908
- }
7942
+ note("custom:thinking-dropped");
7909
7943
  break;
7910
7944
  case "toolUse":
7911
7945
  flush();
@@ -7925,7 +7959,7 @@ ${block.text}
7925
7959
  });
7926
7960
  break;
7927
7961
  case "anthropicNative":
7928
- note("openai:anthropic-native-block-dropped");
7962
+ note("custom:anthropic-native-block-dropped");
7929
7963
  break;
7930
7964
  }
7931
7965
  }
@@ -7937,23 +7971,15 @@ ${block.text}
7937
7971
  `);
7938
7972
  if (instructions !== undefined && instructions.length > 0)
7939
7973
  body.instructions = instructions;
7940
- if (req.maxTokens !== undefined) {
7941
- if (opts.oauth)
7942
- note("openai:max-tokens-dropped");
7943
- else
7944
- body.max_output_tokens = req.maxTokens;
7945
- }
7946
- if (req.temperature !== undefined) {
7947
- if (opts.oauth)
7948
- note("openai:temperature-dropped");
7949
- else
7950
- body.temperature = req.temperature;
7951
- }
7974
+ if (req.maxTokens !== undefined)
7975
+ body.max_output_tokens = req.maxTokens;
7976
+ if (req.temperature !== undefined)
7977
+ body.temperature = req.temperature;
7952
7978
  if (req.tools !== undefined) {
7953
- const custom = req.tools.filter((t) => t.provider === "custom");
7954
- if (custom.length !== req.tools.length)
7955
- note("openai:anthropic-tool-dropped");
7956
- body.tools = custom.map((t) => ({
7979
+ const portable = req.tools.filter((t) => t.provider === "custom");
7980
+ if (portable.length !== req.tools.length)
7981
+ note("custom:anthropic-tool-dropped");
7982
+ body.tools = portable.map((t) => ({
7957
7983
  type: "function",
7958
7984
  name: t.name,
7959
7985
  description: t.description,
@@ -7961,20 +7987,12 @@ ${block.text}
7961
7987
  }));
7962
7988
  }
7963
7989
  if (req.toolChoice !== undefined)
7964
- body.tool_choice = encodeToolChoice3(req.toolChoice);
7965
- if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
7966
- const effort = req.reasoning.mode === "adaptive" ? req.reasoning.effort ?? "medium" : "medium";
7967
- if (effort === "xhigh" || effort === "max") {
7968
- degradations.push("openai:reasoning-effort-clamped");
7969
- }
7970
- body.reasoning = {
7971
- effort: effort === "xhigh" || effort === "max" ? "high" : effort,
7972
- summary: "auto"
7973
- };
7974
- if (req.reasoning.mode === "budget") {
7975
- degradations.push("openai:reasoning-budget-dropped");
7976
- }
7977
- }
7990
+ body.tool_choice = encodeResponsesToolChoice(req.toolChoice);
7991
+ const effort = customEffort(req.reasoning);
7992
+ if (effort !== undefined)
7993
+ body.reasoning = { effort, summary: "auto" };
7994
+ else if (req.reasoning?.mode === "budget")
7995
+ note("custom:reasoning-budget-dropped");
7978
7996
  Object.assign(body, req.vendor?.openai ?? {});
7979
7997
  return { body, degradations };
7980
7998
  }
@@ -7985,7 +8003,13 @@ function metadata(data) {
7985
8003
  if (typeof origin !== "string" || protocol !== "chat_completions" && protocol !== "responses") {
7986
8004
  throw new GatewayError("BAD_REQUEST", "custom credential has invalid endpoint metadata");
7987
8005
  }
7988
- return { origin, protocol };
8006
+ const basePath = typeof data.basePath === "string" ? data.basePath : "";
8007
+ return { origin, basePath, protocol };
8008
+ }
8009
+ function endpointUrl(origin, basePath, protocol) {
8010
+ const suffix = protocol === "chat_completions" ? "chat/completions" : "responses";
8011
+ const base = `${origin}${basePath}`.replace(/\/+$/, "");
8012
+ return base.endsWith("/v1") ? `${base}/${suffix}` : `${base}/v1/${suffix}`;
7989
8013
  }
7990
8014
  var customAdapter = {
7991
8015
  id: "custom",
@@ -7995,15 +8019,15 @@ var customAdapter = {
7995
8019
  if (apiKey === null) {
7996
8020
  throw new GatewayError("AUTH", "custom credential has no API key", { provider: "custom" });
7997
8021
  }
7998
- const { origin, protocol } = metadata(req.credentials.providerData);
7999
- const encoded = protocol === "chat_completions" ? toChatWire(req.request, req.model, "openai") : toResponsesWire(req.request, req.model);
8022
+ const { origin, basePath, protocol } = metadata(req.credentials.providerData);
8023
+ const encoded = protocol === "chat_completions" ? toCustomChatWire(req.request, req.model) : toCustomResponsesWire(req.request, req.model);
8000
8024
  const headers = [
8001
8025
  ["Content-Type", "application/json"],
8002
8026
  ["Authorization", `Bearer ${apiKey}`]
8003
8027
  ];
8004
8028
  const res = await req.http({
8005
8029
  provider: "custom",
8006
- url: `${origin}/v1/${protocol === "chat_completions" ? "chat/completions" : "responses"}`,
8030
+ url: endpointUrl(origin, basePath, protocol),
8007
8031
  method: "POST",
8008
8032
  headers,
8009
8033
  body: JSON.stringify({ ...encoded.body, stream: true }),
@@ -8015,8 +8039,8 @@ var customAdapter = {
8015
8039
  throw new GatewayError("UPSTREAM", "empty response body", { provider: "custom" });
8016
8040
  }
8017
8041
  return {
8018
- events: protocol === "chat_completions" ? decodeChat(parseSse(res.body)) : decodeResponses(parseSse(res.body)),
8019
- degradations: encoded.degradations.map((value) => value.replace(protocol === "chat_completions" ? /^kimi:/ : /^openai:/, "custom:"))
8042
+ events: protocol === "chat_completions" ? decodeCustomChat(parseSse(res.body)) : decodeCustomResponses(parseSse(res.body)),
8043
+ degradations: encoded.degradations
8020
8044
  };
8021
8045
  }
8022
8046
  };
@@ -8035,7 +8059,7 @@ function grokDeviceHeaders(providerData) {
8035
8059
  import { createHash as createHash2 } from "crypto";
8036
8060
 
8037
8061
  // packages/providers/src/grok/decode.ts
8038
- var ERROR_CODE2 = {
8062
+ var ERROR_CODE = {
8039
8063
  rate_limit_exceeded: "RATE_LIMIT",
8040
8064
  insufficient_quota: "QUOTA_EXHAUSTED",
8041
8065
  invalid_api_key: "AUTH",
@@ -8069,7 +8093,7 @@ var KNOWN_EVENTS2 = new Set([
8069
8093
  "response.failed",
8070
8094
  "error"
8071
8095
  ]);
8072
- function json4(data) {
8096
+ function json3(data) {
8073
8097
  try {
8074
8098
  const v = JSON.parse(data);
8075
8099
  return typeof v === "object" && v !== null ? v : null;
@@ -8104,7 +8128,7 @@ async function* decodeGrokResponses(messages) {
8104
8128
  };
8105
8129
  return;
8106
8130
  }
8107
- const d = json4(msg.data);
8131
+ const d = json3(msg.data);
8108
8132
  if (d === null)
8109
8133
  continue;
8110
8134
  switch (msg.event) {
@@ -8197,7 +8221,7 @@ async function* decodeGrokResponses(messages) {
8197
8221
  case "error": {
8198
8222
  terminal = true;
8199
8223
  const err = d.response?.error ?? d.error ?? {};
8200
- const code = ERROR_CODE2[String(err.code ?? err.type)] ?? "UPSTREAM";
8224
+ const code = ERROR_CODE[String(err.code ?? err.type)] ?? "UPSTREAM";
8201
8225
  yield {
8202
8226
  type: "error",
8203
8227
  code,
@@ -8223,7 +8247,7 @@ async function* decodeGrokResponses(messages) {
8223
8247
  // packages/providers/src/grok/wire.ts
8224
8248
  import { createHash } from "crypto";
8225
8249
  var MAX_TOOLS = 200;
8226
- function encodeToolChoice4(c) {
8250
+ function encodeToolChoice2(c) {
8227
8251
  switch (c.type) {
8228
8252
  case "auto":
8229
8253
  return "auto";
@@ -8334,12 +8358,14 @@ ${block.text}
8334
8358
  }));
8335
8359
  }
8336
8360
  if (req.toolChoice !== undefined)
8337
- body.tool_choice = encodeToolChoice4(req.toolChoice);
8361
+ body.tool_choice = encodeToolChoice2(req.toolChoice);
8338
8362
  if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
8339
- const effort = req.reasoning.mode === "adaptive" ? req.reasoning.effort ?? "medium" : "medium";
8340
- body.reasoning = { effort, summary: "concise" };
8341
- if (req.reasoning.mode === "budget")
8363
+ if (req.reasoning.mode === "budget") {
8342
8364
  note("grok:reasoning-budget-dropped");
8365
+ } else {
8366
+ const effort = req.reasoning.effort ?? "medium";
8367
+ body.reasoning = { effort, summary: "concise" };
8368
+ }
8343
8369
  }
8344
8370
  Object.assign(body, req.vendor?.grok ?? {});
8345
8371
  return { body, degradations };
@@ -8497,13 +8523,13 @@ function hasHeader(req, lowerName) {
8497
8523
  return req.headers.some(([name]) => name.toLowerCase() === lowerName);
8498
8524
  }
8499
8525
  // packages/providers/src/kilo/decode.ts
8500
- var FINISH2 = {
8526
+ var FINISH = {
8501
8527
  stop: "endTurn",
8502
8528
  length: "maxTokens",
8503
8529
  tool_calls: "toolUse",
8504
8530
  content_filter: "contentFilter"
8505
8531
  };
8506
- function reasoningText(delta) {
8532
+ function reasoningText2(delta) {
8507
8533
  if (typeof delta.reasoning === "string" && delta.reasoning.length > 0)
8508
8534
  return delta.reasoning;
8509
8535
  if (typeof delta.reasoning_content === "string" && delta.reasoning_content.length > 0) {
@@ -8521,7 +8547,7 @@ function reasoningText(delta) {
8521
8547
  return [];
8522
8548
  }).join("");
8523
8549
  }
8524
- function json5(data) {
8550
+ function json4(data) {
8525
8551
  try {
8526
8552
  const v = JSON.parse(data);
8527
8553
  return typeof v === "object" && v !== null ? v : null;
@@ -8543,7 +8569,7 @@ async function* decodeKiloChat(messages) {
8543
8569
  done = true;
8544
8570
  break;
8545
8571
  }
8546
- const d = json5(msg.data);
8572
+ const d = json4(msg.data);
8547
8573
  if (d === null)
8548
8574
  continue;
8549
8575
  if (!started && (d.id !== undefined || d.model !== undefined)) {
@@ -8558,7 +8584,7 @@ async function* decodeKiloChat(messages) {
8558
8584
  if (!choice)
8559
8585
  continue;
8560
8586
  const delta = choice.delta ?? {};
8561
- const reasoning = reasoningText(delta);
8587
+ const reasoning = reasoningText2(delta);
8562
8588
  if (reasoning.length > 0) {
8563
8589
  if (openKind !== "thinking") {
8564
8590
  if (openKind !== undefined)
@@ -8614,7 +8640,7 @@ async function* decodeKiloChat(messages) {
8614
8640
  }
8615
8641
  }
8616
8642
  if (typeof choice.finish_reason === "string") {
8617
- stopReason = FINISH2[choice.finish_reason] ?? "endTurn";
8643
+ stopReason = FINISH[choice.finish_reason] ?? "endTurn";
8618
8644
  }
8619
8645
  }
8620
8646
  if (done) {
@@ -8632,7 +8658,7 @@ async function* decodeKiloChat(messages) {
8632
8658
  }
8633
8659
 
8634
8660
  // packages/providers/src/kilo/wire.ts
8635
- function encodeToolChoice5(c) {
8661
+ function encodeToolChoice3(c) {
8636
8662
  switch (c.type) {
8637
8663
  case "auto":
8638
8664
  return "auto";
@@ -8745,15 +8771,12 @@ function toKiloWire(req, model) {
8745
8771
  }));
8746
8772
  }
8747
8773
  if (req.toolChoice !== undefined)
8748
- body.tool_choice = encodeToolChoice5(req.toolChoice);
8774
+ body.tool_choice = encodeToolChoice3(req.toolChoice);
8749
8775
  if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
8750
8776
  if (req.reasoning.mode === "budget") {
8751
8777
  body.reasoning = { max_tokens: req.reasoning.budgetTokens };
8752
8778
  } else {
8753
- const effort = req.reasoning.effort ?? "medium";
8754
- if (effort === "xhigh" || effort === "max")
8755
- note("kilo:reasoning-effort-clamped");
8756
- body.reasoning = { effort: effort === "xhigh" || effort === "max" ? "high" : effort };
8779
+ body.reasoning = { effort: req.reasoning.effort ?? "medium" };
8757
8780
  }
8758
8781
  }
8759
8782
  Object.assign(body, req.vendor?.kilo ?? {});
@@ -8823,6 +8846,208 @@ function kimiDeviceHeaders(providerData) {
8823
8846
  ["X-Msh-Os-Version", str(providerData.osVersion)]
8824
8847
  ];
8825
8848
  }
8849
+ // packages/providers/src/kimi/decode.ts
8850
+ var FINISH2 = {
8851
+ stop: "endTurn",
8852
+ length: "maxTokens",
8853
+ tool_calls: "toolUse",
8854
+ content_filter: "contentFilter"
8855
+ };
8856
+ function json5(data) {
8857
+ try {
8858
+ const v = JSON.parse(data);
8859
+ return typeof v === "object" && v !== null ? v : null;
8860
+ } catch {
8861
+ return null;
8862
+ }
8863
+ }
8864
+ async function* decodeChat(messages) {
8865
+ let started = false;
8866
+ let done = false;
8867
+ let stopReason = "endTurn";
8868
+ let usage = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };
8869
+ const toolIndex = new Map;
8870
+ let nextIndex = 0;
8871
+ let openKind;
8872
+ let openIndex = 0;
8873
+ for await (const msg of messages) {
8874
+ if (msg.data === "[DONE]") {
8875
+ done = true;
8876
+ break;
8877
+ }
8878
+ const d = json5(msg.data);
8879
+ if (d === null)
8880
+ continue;
8881
+ if (!started && (d.id !== undefined || d.model !== undefined)) {
8882
+ started = true;
8883
+ yield { type: "start", id: String(d.id ?? ""), model: String(d.model ?? "") };
8884
+ }
8885
+ if (d.usage) {
8886
+ const details = d.usage.prompt_tokens_details;
8887
+ usage = usageFromPromptTotal(d.usage.prompt_tokens ?? 0, d.usage.completion_tokens ?? 0, details?.cached_tokens ?? d.usage.prompt_cache_hit_tokens ?? 0, details?.cache_creation_tokens ?? details?.cache_write_tokens ?? 0);
8888
+ }
8889
+ const choice = d.choices?.[0];
8890
+ if (!choice)
8891
+ continue;
8892
+ const delta = choice.delta ?? {};
8893
+ if (typeof delta.content === "string" && delta.content.length > 0) {
8894
+ if (openKind !== "text") {
8895
+ if (openKind !== undefined)
8896
+ yield { type: "blockEnd", index: openIndex };
8897
+ openKind = "text";
8898
+ openIndex = nextIndex++;
8899
+ yield { type: "blockStart", index: openIndex, block: { type: "text" } };
8900
+ }
8901
+ yield {
8902
+ type: "blockDelta",
8903
+ index: openIndex,
8904
+ delta: { type: "text", text: delta.content }
8905
+ };
8906
+ }
8907
+ for (const call of delta.tool_calls ?? []) {
8908
+ const wireIndex = call.index ?? 0;
8909
+ let index = toolIndex.get(wireIndex);
8910
+ if (index === undefined) {
8911
+ if (openKind !== undefined)
8912
+ yield { type: "blockEnd", index: openIndex };
8913
+ index = nextIndex++;
8914
+ toolIndex.set(wireIndex, index);
8915
+ openKind = "tool";
8916
+ openIndex = index;
8917
+ yield {
8918
+ type: "blockStart",
8919
+ index,
8920
+ block: {
8921
+ type: "toolUse",
8922
+ id: String(call.id ?? `call_${wireIndex}`),
8923
+ name: String(call.function?.name ?? "")
8924
+ }
8925
+ };
8926
+ }
8927
+ const args = call.function?.arguments;
8928
+ if (typeof args === "string" && args.length > 0) {
8929
+ yield { type: "blockDelta", index, delta: { type: "toolJson", partial: args } };
8930
+ }
8931
+ }
8932
+ if (typeof choice.finish_reason === "string") {
8933
+ stopReason = FINISH2[choice.finish_reason] ?? "endTurn";
8934
+ }
8935
+ }
8936
+ if (done) {
8937
+ if (openKind !== undefined)
8938
+ yield { type: "blockEnd", index: openIndex };
8939
+ yield { type: "end", stopReason, usage };
8940
+ } else {
8941
+ yield {
8942
+ type: "error",
8943
+ code: "UPSTREAM",
8944
+ message: "upstream stream ended before [DONE]",
8945
+ retryable: RETRYABLE.UPSTREAM
8946
+ };
8947
+ }
8948
+ }
8949
+
8950
+ // packages/providers/src/kimi/wire.ts
8951
+ function encodeToolChoice4(c) {
8952
+ switch (c.type) {
8953
+ case "auto":
8954
+ return "auto";
8955
+ case "any":
8956
+ return "required";
8957
+ case "none":
8958
+ return "none";
8959
+ case "tool":
8960
+ return { type: "function", function: { name: c.name } };
8961
+ }
8962
+ }
8963
+ function toChatWire(req, model, vendor = "kimi") {
8964
+ const degradations = [];
8965
+ const note = (d) => {
8966
+ if (!degradations.includes(d))
8967
+ degradations.push(d);
8968
+ };
8969
+ if (req.betas?.includes(CONTEXT_1M_BETA))
8970
+ note("kimi:context-1m-dropped");
8971
+ const messages = [];
8972
+ const system = req.system?.flatMap((b) => b.type === "text" ? [b.text] : []).join(`
8973
+
8974
+ `);
8975
+ if (system !== undefined && system.length > 0)
8976
+ messages.push({ role: "system", content: system });
8977
+ for (const message of req.messages) {
8978
+ const text = [];
8979
+ const toolCalls = [];
8980
+ for (const block of message.content) {
8981
+ switch (block.type) {
8982
+ case "text":
8983
+ text.push(block.text);
8984
+ break;
8985
+ case "image":
8986
+ note("kimi:images-dropped");
8987
+ break;
8988
+ case "thinking":
8989
+ note("kimi:thinking-dropped");
8990
+ break;
8991
+ case "toolUse":
8992
+ toolCalls.push({
8993
+ id: block.id,
8994
+ type: "function",
8995
+ function: { name: block.name, arguments: JSON.stringify(block.input) }
8996
+ });
8997
+ break;
8998
+ case "toolResult":
8999
+ messages.push({
9000
+ role: "tool",
9001
+ tool_call_id: block.toolUseId,
9002
+ content: block.content
9003
+ });
9004
+ break;
9005
+ case "anthropicNative":
9006
+ note("kimi:anthropic-native-block-dropped");
9007
+ break;
9008
+ }
9009
+ }
9010
+ if (toolCalls.length > 0) {
9011
+ messages.push({
9012
+ role: message.role,
9013
+ content: text.length > 0 ? text.join(`
9014
+ `) : null,
9015
+ tool_calls: toolCalls
9016
+ });
9017
+ } else if (text.length > 0) {
9018
+ messages.push({ role: message.role, content: text.join(`
9019
+ `) });
9020
+ }
9021
+ }
9022
+ const body = {
9023
+ model,
9024
+ messages,
9025
+ stream: req.stream,
9026
+ stream_options: { include_usage: true }
9027
+ };
9028
+ if (req.maxTokens !== undefined)
9029
+ body.max_tokens = req.maxTokens;
9030
+ if (req.temperature !== undefined)
9031
+ body.temperature = req.temperature;
9032
+ if (req.stopSequences !== undefined)
9033
+ body.stop = req.stopSequences;
9034
+ if (req.tools !== undefined) {
9035
+ const custom = req.tools.filter((t) => t.provider === "custom");
9036
+ if (custom.length !== req.tools.length)
9037
+ note("kimi:anthropic-tool-dropped");
9038
+ body.tools = custom.map((t) => ({
9039
+ type: "function",
9040
+ function: { name: t.name, description: t.description, parameters: t.inputSchema }
9041
+ }));
9042
+ }
9043
+ if (req.toolChoice !== undefined)
9044
+ body.tool_choice = encodeToolChoice4(req.toolChoice);
9045
+ if (req.reasoning !== undefined)
9046
+ note("kimi:reasoning-dropped");
9047
+ Object.assign(body, req.vendor?.[vendor] ?? {});
9048
+ return { body, degradations };
9049
+ }
9050
+
8826
9051
  // packages/providers/src/kimi/index.ts
8827
9052
  var BASE_URL2 = "https://api.kimi.com/coding/v1/chat/completions";
8828
9053
  var kimiAdapter = {
@@ -8857,6 +9082,276 @@ var kimiAdapter = {
8857
9082
  return { events: decodeChat(parseSse(res.body)), degradations };
8858
9083
  }
8859
9084
  };
9085
+ // packages/providers/src/openai/decode.ts
9086
+ var ERROR_CODE2 = {
9087
+ rate_limit_exceeded: "RATE_LIMIT",
9088
+ insufficient_quota: "QUOTA_EXHAUSTED",
9089
+ invalid_api_key: "AUTH",
9090
+ server_error: "UPSTREAM",
9091
+ context_length_exceeded: "BAD_REQUEST",
9092
+ content_policy_violation: "CONTENT_FILTER"
9093
+ };
9094
+ function json6(data) {
9095
+ try {
9096
+ const v = JSON.parse(data);
9097
+ return typeof v === "object" && v !== null ? v : null;
9098
+ } catch {
9099
+ return null;
9100
+ }
9101
+ }
9102
+ async function* decodeResponses(messages) {
9103
+ const indices = new Map;
9104
+ let next = 0;
9105
+ const irIndex = (outputIndex, contentIndex = 0) => {
9106
+ const key = `${outputIndex}:${contentIndex}`;
9107
+ const existing = indices.get(key);
9108
+ if (existing !== undefined)
9109
+ return existing;
9110
+ const assigned = next++;
9111
+ indices.set(key, assigned);
9112
+ return assigned;
9113
+ };
9114
+ let sawToolCall = false;
9115
+ let terminal = false;
9116
+ const ownsBlock = new Set;
9117
+ for await (const msg of messages) {
9118
+ const d = json6(msg.data);
9119
+ if (d === null)
9120
+ continue;
9121
+ switch (msg.event) {
9122
+ case "response.created":
9123
+ yield {
9124
+ type: "start",
9125
+ id: String(d.response?.id ?? ""),
9126
+ model: String(d.response?.model ?? "")
9127
+ };
9128
+ break;
9129
+ case "response.output_item.added": {
9130
+ const item = d.item ?? {};
9131
+ if (item.type === "reasoning") {
9132
+ ownsBlock.add(d.output_index ?? 0);
9133
+ yield {
9134
+ type: "blockStart",
9135
+ index: irIndex(d.output_index ?? 0),
9136
+ block: { type: "thinking" }
9137
+ };
9138
+ } else if (item.type === "function_call") {
9139
+ sawToolCall = true;
9140
+ ownsBlock.add(d.output_index ?? 0);
9141
+ yield {
9142
+ type: "blockStart",
9143
+ index: irIndex(d.output_index ?? 0),
9144
+ block: { type: "toolUse", id: String(item.call_id), name: String(item.name) }
9145
+ };
9146
+ }
9147
+ break;
9148
+ }
9149
+ case "response.content_part.added":
9150
+ if (d.part?.type === "output_text") {
9151
+ yield {
9152
+ type: "blockStart",
9153
+ index: irIndex(d.output_index ?? 0, d.content_index ?? 0),
9154
+ block: { type: "text" }
9155
+ };
9156
+ }
9157
+ break;
9158
+ case "response.output_text.delta":
9159
+ yield {
9160
+ type: "blockDelta",
9161
+ index: irIndex(d.output_index ?? 0, d.content_index ?? 0),
9162
+ delta: { type: "text", text: String(d.delta ?? "") }
9163
+ };
9164
+ break;
9165
+ case "response.reasoning_summary_text.delta":
9166
+ yield {
9167
+ type: "blockDelta",
9168
+ index: irIndex(d.output_index ?? 0),
9169
+ delta: { type: "thinking", text: String(d.delta ?? "") }
9170
+ };
9171
+ break;
9172
+ case "response.function_call_arguments.delta":
9173
+ yield {
9174
+ type: "blockDelta",
9175
+ index: irIndex(d.output_index ?? 0),
9176
+ delta: { type: "toolJson", partial: String(d.delta ?? "") }
9177
+ };
9178
+ break;
9179
+ case "response.content_part.done":
9180
+ yield { type: "blockEnd", index: irIndex(d.output_index ?? 0, d.content_index ?? 0) };
9181
+ break;
9182
+ case "response.output_item.done": {
9183
+ const outputIndex = d.output_index ?? 0;
9184
+ if (ownsBlock.delete(outputIndex)) {
9185
+ yield { type: "blockEnd", index: irIndex(outputIndex) };
9186
+ }
9187
+ break;
9188
+ }
9189
+ case "response.completed":
9190
+ case "response.incomplete": {
9191
+ terminal = true;
9192
+ const r = d.response ?? {};
9193
+ const reason = r.incomplete_details?.reason;
9194
+ let stopReason = sawToolCall ? "toolUse" : "endTurn";
9195
+ if (reason === "max_output_tokens")
9196
+ stopReason = "maxTokens";
9197
+ else if (reason === "content_filter")
9198
+ stopReason = "contentFilter";
9199
+ yield {
9200
+ type: "end",
9201
+ stopReason,
9202
+ usage: usageFromPromptTotal(r.usage?.input_tokens ?? 0, r.usage?.output_tokens ?? 0, r.usage?.input_tokens_details?.cached_tokens ?? r.usage?.prompt_tokens_details?.cached_tokens ?? 0)
9203
+ };
9204
+ break;
9205
+ }
9206
+ case "response.failed":
9207
+ case "error": {
9208
+ terminal = true;
9209
+ const err = d.response?.error ?? d.error ?? {};
9210
+ const code = ERROR_CODE2[String(err.code ?? err.type)] ?? "UPSTREAM";
9211
+ yield {
9212
+ type: "error",
9213
+ code,
9214
+ message: String(err.message ?? "upstream error"),
9215
+ retryable: RETRYABLE[code]
9216
+ };
9217
+ break;
9218
+ }
9219
+ default:
9220
+ break;
9221
+ }
9222
+ }
9223
+ if (!terminal) {
9224
+ yield {
9225
+ type: "error",
9226
+ code: "UPSTREAM",
9227
+ message: "upstream stream ended before response completion",
9228
+ retryable: RETRYABLE.UPSTREAM
9229
+ };
9230
+ }
9231
+ }
9232
+
9233
+ // packages/providers/src/openai/wire.ts
9234
+ function encodeToolChoice5(c) {
9235
+ switch (c.type) {
9236
+ case "auto":
9237
+ return "auto";
9238
+ case "any":
9239
+ return "required";
9240
+ case "none":
9241
+ return "none";
9242
+ case "tool":
9243
+ return { type: "function", name: c.name };
9244
+ }
9245
+ }
9246
+ function toResponsesWire(req, model, opts = { oauth: false }) {
9247
+ const degradations = [];
9248
+ const input = [];
9249
+ const note = (d) => {
9250
+ if (!degradations.includes(d))
9251
+ degradations.push(d);
9252
+ };
9253
+ if (req.betas?.includes(CONTEXT_1M_BETA))
9254
+ note("openai:context-1m-dropped");
9255
+ for (const message of req.messages) {
9256
+ const parts = [];
9257
+ const inlined = message.role === "system";
9258
+ if (inlined)
9259
+ note("openai:system-turn-inlined");
9260
+ const role = inlined ? "user" : message.role;
9261
+ const flush = () => {
9262
+ if (parts.length === 0)
9263
+ return;
9264
+ input.push({ type: "message", role, content: [...parts] });
9265
+ parts.length = 0;
9266
+ };
9267
+ for (const block of message.content) {
9268
+ switch (block.type) {
9269
+ case "text":
9270
+ parts.push({
9271
+ type: role === "assistant" ? "output_text" : "input_text",
9272
+ text: inlined ? `<system-reminder>
9273
+ ${block.text}
9274
+ </system-reminder>` : block.text
9275
+ });
9276
+ break;
9277
+ case "image":
9278
+ parts.push({
9279
+ type: "input_image",
9280
+ image_url: `data:${block.mediaType};base64,${block.data}`
9281
+ });
9282
+ break;
9283
+ case "thinking":
9284
+ if (!degradations.includes("openai:thinking-dropped")) {
9285
+ note("openai:thinking-dropped");
9286
+ }
9287
+ break;
9288
+ case "toolUse":
9289
+ flush();
9290
+ input.push({
9291
+ type: "function_call",
9292
+ call_id: block.id,
9293
+ name: block.name,
9294
+ arguments: JSON.stringify(block.input)
9295
+ });
9296
+ break;
9297
+ case "toolResult":
9298
+ flush();
9299
+ input.push({
9300
+ type: "function_call_output",
9301
+ call_id: block.toolUseId,
9302
+ output: block.content
9303
+ });
9304
+ break;
9305
+ case "anthropicNative":
9306
+ note("openai:anthropic-native-block-dropped");
9307
+ break;
9308
+ }
9309
+ }
9310
+ flush();
9311
+ }
9312
+ const body = { model, input, stream: req.stream, store: false };
9313
+ const instructions = req.system?.flatMap((b) => b.type === "text" ? [b.text] : []).join(`
9314
+
9315
+ `);
9316
+ if (instructions !== undefined && instructions.length > 0)
9317
+ body.instructions = instructions;
9318
+ if (req.maxTokens !== undefined) {
9319
+ if (opts.oauth)
9320
+ note("openai:max-tokens-dropped");
9321
+ else
9322
+ body.max_output_tokens = req.maxTokens;
9323
+ }
9324
+ if (req.temperature !== undefined) {
9325
+ if (opts.oauth)
9326
+ note("openai:temperature-dropped");
9327
+ else
9328
+ body.temperature = req.temperature;
9329
+ }
9330
+ if (req.tools !== undefined) {
9331
+ const custom = req.tools.filter((t) => t.provider === "custom");
9332
+ if (custom.length !== req.tools.length)
9333
+ note("openai:anthropic-tool-dropped");
9334
+ body.tools = custom.map((t) => ({
9335
+ type: "function",
9336
+ name: t.name,
9337
+ description: t.description,
9338
+ parameters: t.inputSchema
9339
+ }));
9340
+ }
9341
+ if (req.toolChoice !== undefined)
9342
+ body.tool_choice = encodeToolChoice5(req.toolChoice);
9343
+ if (req.reasoning !== undefined && req.reasoning.mode !== "off") {
9344
+ if (req.reasoning.mode === "budget") {
9345
+ degradations.push("openai:reasoning-budget-dropped");
9346
+ } else {
9347
+ const effort = req.reasoning.effort ?? "medium";
9348
+ body.reasoning = { effort, summary: "auto" };
9349
+ }
9350
+ }
9351
+ Object.assign(body, req.vendor?.openai ?? {});
9352
+ return { body, degradations };
9353
+ }
9354
+
8860
9355
  // packages/providers/src/openai/index.ts
8861
9356
  var OAUTH_URL2 = "https://chatgpt.com/backend-api/codex/responses";
8862
9357
  var API_URL3 = "https://api.openai.com/v1/responses";
@@ -9268,7 +9763,7 @@ __export(exports_external, {
9268
9763
  ipv4: () => ipv42,
9269
9764
  ipv6: () => ipv62,
9270
9765
  iso: () => exports_iso,
9271
- json: () => json6,
9766
+ json: () => json7,
9272
9767
  jwt: () => jwt,
9273
9768
  keyof: () => keyof,
9274
9769
  ksuid: () => ksuid2,
@@ -20709,29 +21204,29 @@ var formatMap = {
20709
21204
  regex: ""
20710
21205
  };
20711
21206
  var stringProcessor = (schema, ctx, _json, _params) => {
20712
- const json6 = _json;
20713
- json6.type = "string";
21207
+ const json7 = _json;
21208
+ json7.type = "string";
20714
21209
  const { minimum, maximum, format, patterns, contentEncoding } = schema._zod.bag;
20715
21210
  if (typeof minimum === "number")
20716
- json6.minLength = minimum;
21211
+ json7.minLength = minimum;
20717
21212
  if (typeof maximum === "number")
20718
- json6.maxLength = maximum;
21213
+ json7.maxLength = maximum;
20719
21214
  if (format) {
20720
- json6.format = formatMap[format] ?? format;
20721
- if (json6.format === "")
20722
- delete json6.format;
21215
+ json7.format = formatMap[format] ?? format;
21216
+ if (json7.format === "")
21217
+ delete json7.format;
20723
21218
  if (format === "time") {
20724
- delete json6.format;
21219
+ delete json7.format;
20725
21220
  }
20726
21221
  }
20727
21222
  if (contentEncoding)
20728
- json6.contentEncoding = contentEncoding;
21223
+ json7.contentEncoding = contentEncoding;
20729
21224
  if (patterns && patterns.size > 0) {
20730
21225
  const regexes = [...patterns];
20731
21226
  if (regexes.length === 1)
20732
- json6.pattern = regexes[0].source;
21227
+ json7.pattern = regexes[0].source;
20733
21228
  else if (regexes.length > 1) {
20734
- json6.allOf = [
21229
+ json7.allOf = [
20735
21230
  ...regexes.map((regex) => ({
20736
21231
  ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {},
20737
21232
  pattern: regex.source
@@ -20741,40 +21236,40 @@ var stringProcessor = (schema, ctx, _json, _params) => {
20741
21236
  }
20742
21237
  };
20743
21238
  var numberProcessor = (schema, ctx, _json, _params) => {
20744
- const json6 = _json;
21239
+ const json7 = _json;
20745
21240
  const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag;
20746
21241
  if (typeof format === "string" && format.includes("int"))
20747
- json6.type = "integer";
21242
+ json7.type = "integer";
20748
21243
  else
20749
- json6.type = "number";
21244
+ json7.type = "number";
20750
21245
  const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
20751
21246
  const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
20752
21247
  const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
20753
21248
  if (exMin) {
20754
21249
  if (legacy) {
20755
- json6.minimum = exclusiveMinimum;
20756
- json6.exclusiveMinimum = true;
21250
+ json7.minimum = exclusiveMinimum;
21251
+ json7.exclusiveMinimum = true;
20757
21252
  } else {
20758
- json6.exclusiveMinimum = exclusiveMinimum;
21253
+ json7.exclusiveMinimum = exclusiveMinimum;
20759
21254
  }
20760
21255
  } else if (typeof minimum === "number") {
20761
- json6.minimum = minimum;
21256
+ json7.minimum = minimum;
20762
21257
  }
20763
21258
  if (exMax) {
20764
21259
  if (legacy) {
20765
- json6.maximum = exclusiveMaximum;
20766
- json6.exclusiveMaximum = true;
21260
+ json7.maximum = exclusiveMaximum;
21261
+ json7.exclusiveMaximum = true;
20767
21262
  } else {
20768
- json6.exclusiveMaximum = exclusiveMaximum;
21263
+ json7.exclusiveMaximum = exclusiveMaximum;
20769
21264
  }
20770
21265
  } else if (typeof maximum === "number") {
20771
- json6.maximum = maximum;
21266
+ json7.maximum = maximum;
20772
21267
  }
20773
21268
  if (typeof multipleOf === "number")
20774
- json6.multipleOf = multipleOf;
21269
+ json7.multipleOf = multipleOf;
20775
21270
  };
20776
- var booleanProcessor = (_schema, _ctx, json6, _params) => {
20777
- json6.type = "boolean";
21271
+ var booleanProcessor = (_schema, _ctx, json7, _params) => {
21272
+ json7.type = "boolean";
20778
21273
  };
20779
21274
  var bigintProcessor = (_schema, ctx, _json, _params) => {
20780
21275
  if (ctx.unrepresentable === "throw") {
@@ -20786,13 +21281,13 @@ var symbolProcessor = (_schema, ctx, _json, _params) => {
20786
21281
  throw new Error("Symbols cannot be represented in JSON Schema");
20787
21282
  }
20788
21283
  };
20789
- var nullProcessor = (_schema, ctx, json6, _params) => {
21284
+ var nullProcessor = (_schema, ctx, json7, _params) => {
20790
21285
  if (ctx.target === "openapi-3.0") {
20791
- json6.type = "string";
20792
- json6.nullable = true;
20793
- json6.enum = [null];
21286
+ json7.type = "string";
21287
+ json7.nullable = true;
21288
+ json7.enum = [null];
20794
21289
  } else {
20795
- json6.type = "null";
21290
+ json7.type = "null";
20796
21291
  }
20797
21292
  };
20798
21293
  var undefinedProcessor = (_schema, ctx, _json, _params) => {
@@ -20805,8 +21300,8 @@ var voidProcessor = (_schema, ctx, _json, _params) => {
20805
21300
  throw new Error("Void cannot be represented in JSON Schema");
20806
21301
  }
20807
21302
  };
20808
- var neverProcessor = (_schema, _ctx, json6, _params) => {
20809
- json6.not = {};
21303
+ var neverProcessor = (_schema, _ctx, json7, _params) => {
21304
+ json7.not = {};
20810
21305
  };
20811
21306
  var anyProcessor = (_schema, _ctx, _json, _params) => {};
20812
21307
  var unknownProcessor = (_schema, _ctx, _json, _params) => {};
@@ -20815,16 +21310,16 @@ var dateProcessor = (_schema, ctx, _json, _params) => {
20815
21310
  throw new Error("Date cannot be represented in JSON Schema");
20816
21311
  }
20817
21312
  };
20818
- var enumProcessor = (schema, _ctx, json6, _params) => {
21313
+ var enumProcessor = (schema, _ctx, json7, _params) => {
20819
21314
  const def = schema._zod.def;
20820
21315
  const values = getEnumValues(def.entries);
20821
21316
  if (values.every((v) => typeof v === "number"))
20822
- json6.type = "number";
21317
+ json7.type = "number";
20823
21318
  if (values.every((v) => typeof v === "string"))
20824
- json6.type = "string";
20825
- json6.enum = values;
21319
+ json7.type = "string";
21320
+ json7.enum = values;
20826
21321
  };
20827
- var literalProcessor = (schema, ctx, json6, _params) => {
21322
+ var literalProcessor = (schema, ctx, json7, _params) => {
20828
21323
  const def = schema._zod.def;
20829
21324
  const vals = [];
20830
21325
  for (const val of def.values) {
@@ -20844,22 +21339,22 @@ var literalProcessor = (schema, ctx, json6, _params) => {
20844
21339
  }
20845
21340
  if (vals.length === 0) {} else if (vals.length === 1) {
20846
21341
  const val = vals[0];
20847
- json6.type = val === null ? "null" : typeof val;
21342
+ json7.type = val === null ? "null" : typeof val;
20848
21343
  if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
20849
- json6.enum = [val];
21344
+ json7.enum = [val];
20850
21345
  } else {
20851
- json6.const = val;
21346
+ json7.const = val;
20852
21347
  }
20853
21348
  } else {
20854
21349
  if (vals.every((v) => typeof v === "number"))
20855
- json6.type = "number";
21350
+ json7.type = "number";
20856
21351
  if (vals.every((v) => typeof v === "string"))
20857
- json6.type = "string";
21352
+ json7.type = "string";
20858
21353
  if (vals.every((v) => typeof v === "boolean"))
20859
- json6.type = "boolean";
21354
+ json7.type = "boolean";
20860
21355
  if (vals.every((v) => v === null))
20861
- json6.type = "null";
20862
- json6.enum = vals;
21356
+ json7.type = "null";
21357
+ json7.enum = vals;
20863
21358
  }
20864
21359
  };
20865
21360
  var nanProcessor = (_schema, ctx, _json, _params) => {
@@ -20867,16 +21362,16 @@ var nanProcessor = (_schema, ctx, _json, _params) => {
20867
21362
  throw new Error("NaN cannot be represented in JSON Schema");
20868
21363
  }
20869
21364
  };
20870
- var templateLiteralProcessor = (schema, _ctx, json6, _params) => {
20871
- const _json = json6;
21365
+ var templateLiteralProcessor = (schema, _ctx, json7, _params) => {
21366
+ const _json = json7;
20872
21367
  const pattern = schema._zod.pattern;
20873
21368
  if (!pattern)
20874
21369
  throw new Error("Pattern not found in template literal");
20875
21370
  _json.type = "string";
20876
21371
  _json.pattern = pattern.source;
20877
21372
  };
20878
- var fileProcessor = (schema, _ctx, json6, _params) => {
20879
- const _json = json6;
21373
+ var fileProcessor = (schema, _ctx, json7, _params) => {
21374
+ const _json = json7;
20880
21375
  const file = {
20881
21376
  type: "string",
20882
21377
  format: "binary",
@@ -20899,8 +21394,8 @@ var fileProcessor = (schema, _ctx, json6, _params) => {
20899
21394
  Object.assign(_json, file);
20900
21395
  }
20901
21396
  };
20902
- var successProcessor = (_schema, _ctx, json6, _params) => {
20903
- json6.type = "boolean";
21397
+ var successProcessor = (_schema, _ctx, json7, _params) => {
21398
+ json7.type = "boolean";
20904
21399
  };
20905
21400
  var customProcessor = (_schema, ctx, _json, _params) => {
20906
21401
  if (ctx.unrepresentable === "throw") {
@@ -20928,27 +21423,27 @@ var setProcessor = (_schema, ctx, _json, _params) => {
20928
21423
  }
20929
21424
  };
20930
21425
  var arrayProcessor = (schema, ctx, _json, params) => {
20931
- const json6 = _json;
21426
+ const json7 = _json;
20932
21427
  const def = schema._zod.def;
20933
21428
  const { minimum, maximum } = schema._zod.bag;
20934
21429
  if (typeof minimum === "number")
20935
- json6.minItems = minimum;
21430
+ json7.minItems = minimum;
20936
21431
  if (typeof maximum === "number")
20937
- json6.maxItems = maximum;
20938
- json6.type = "array";
20939
- json6.items = process2(def.element, ctx, {
21432
+ json7.maxItems = maximum;
21433
+ json7.type = "array";
21434
+ json7.items = process2(def.element, ctx, {
20940
21435
  ...params,
20941
21436
  path: [...params.path, "items"]
20942
21437
  });
20943
21438
  };
20944
21439
  var objectProcessor = (schema, ctx, _json, params) => {
20945
- const json6 = _json;
21440
+ const json7 = _json;
20946
21441
  const def = schema._zod.def;
20947
- json6.type = "object";
20948
- json6.properties = {};
21442
+ json7.type = "object";
21443
+ json7.properties = {};
20949
21444
  const shape = def.shape;
20950
21445
  for (const key in shape) {
20951
- json6.properties[key] = process2(shape[key], ctx, {
21446
+ json7.properties[key] = process2(shape[key], ctx, {
20952
21447
  ...params,
20953
21448
  path: [...params.path, "properties", key]
20954
21449
  });
@@ -20963,21 +21458,21 @@ var objectProcessor = (schema, ctx, _json, params) => {
20963
21458
  }
20964
21459
  }));
20965
21460
  if (requiredKeys.size > 0) {
20966
- json6.required = Array.from(requiredKeys);
21461
+ json7.required = Array.from(requiredKeys);
20967
21462
  }
20968
21463
  if (def.catchall?._zod.def.type === "never") {
20969
- json6.additionalProperties = false;
21464
+ json7.additionalProperties = false;
20970
21465
  } else if (!def.catchall) {
20971
21466
  if (ctx.io === "output")
20972
- json6.additionalProperties = false;
21467
+ json7.additionalProperties = false;
20973
21468
  } else if (def.catchall) {
20974
- json6.additionalProperties = process2(def.catchall, ctx, {
21469
+ json7.additionalProperties = process2(def.catchall, ctx, {
20975
21470
  ...params,
20976
21471
  path: [...params.path, "additionalProperties"]
20977
21472
  });
20978
21473
  }
20979
21474
  };
20980
- var unionProcessor = (schema, ctx, json6, params) => {
21475
+ var unionProcessor = (schema, ctx, json7, params) => {
20981
21476
  const def = schema._zod.def;
20982
21477
  const isExclusive = def.inclusive === false;
20983
21478
  const options = def.options.map((x, i) => process2(x, ctx, {
@@ -20985,12 +21480,12 @@ var unionProcessor = (schema, ctx, json6, params) => {
20985
21480
  path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
20986
21481
  }));
20987
21482
  if (isExclusive) {
20988
- json6.oneOf = options;
21483
+ json7.oneOf = options;
20989
21484
  } else {
20990
- json6.anyOf = options;
21485
+ json7.anyOf = options;
20991
21486
  }
20992
21487
  };
20993
- var intersectionProcessor = (schema, ctx, json6, params) => {
21488
+ var intersectionProcessor = (schema, ctx, json7, params) => {
20994
21489
  const def = schema._zod.def;
20995
21490
  const a = process2(def.left, ctx, {
20996
21491
  ...params,
@@ -21005,12 +21500,12 @@ var intersectionProcessor = (schema, ctx, json6, params) => {
21005
21500
  ...isSimpleIntersection(a) ? a.allOf : [a],
21006
21501
  ...isSimpleIntersection(b) ? b.allOf : [b]
21007
21502
  ];
21008
- json6.allOf = allOf;
21503
+ json7.allOf = allOf;
21009
21504
  };
21010
21505
  var tupleProcessor = (schema, ctx, _json, params) => {
21011
- const json6 = _json;
21506
+ const json7 = _json;
21012
21507
  const def = schema._zod.def;
21013
- json6.type = "array";
21508
+ json7.type = "array";
21014
21509
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
21015
21510
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
21016
21511
  const prefixItems = def.items.map((x, i) => process2(x, ctx, {
@@ -21022,37 +21517,37 @@ var tupleProcessor = (schema, ctx, _json, params) => {
21022
21517
  path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
21023
21518
  }) : null;
21024
21519
  if (ctx.target === "draft-2020-12") {
21025
- json6.prefixItems = prefixItems;
21520
+ json7.prefixItems = prefixItems;
21026
21521
  if (rest) {
21027
- json6.items = rest;
21522
+ json7.items = rest;
21028
21523
  }
21029
21524
  } else if (ctx.target === "openapi-3.0") {
21030
- json6.items = {
21525
+ json7.items = {
21031
21526
  anyOf: prefixItems
21032
21527
  };
21033
21528
  if (rest) {
21034
- json6.items.anyOf.push(rest);
21529
+ json7.items.anyOf.push(rest);
21035
21530
  }
21036
- json6.minItems = prefixItems.length;
21531
+ json7.minItems = prefixItems.length;
21037
21532
  if (!rest) {
21038
- json6.maxItems = prefixItems.length;
21533
+ json7.maxItems = prefixItems.length;
21039
21534
  }
21040
21535
  } else {
21041
- json6.items = prefixItems;
21536
+ json7.items = prefixItems;
21042
21537
  if (rest) {
21043
- json6.additionalItems = rest;
21538
+ json7.additionalItems = rest;
21044
21539
  }
21045
21540
  }
21046
21541
  const { minimum, maximum } = schema._zod.bag;
21047
21542
  if (typeof minimum === "number")
21048
- json6.minItems = minimum;
21543
+ json7.minItems = minimum;
21049
21544
  if (typeof maximum === "number")
21050
- json6.maxItems = maximum;
21545
+ json7.maxItems = maximum;
21051
21546
  };
21052
21547
  var recordProcessor = (schema, ctx, _json, params) => {
21053
- const json6 = _json;
21548
+ const json7 = _json;
21054
21549
  const def = schema._zod.def;
21055
- json6.type = "object";
21550
+ json7.type = "object";
21056
21551
  const keyType = def.keyType;
21057
21552
  const keyBag = keyType._zod.bag;
21058
21553
  const patterns = keyBag?.patterns;
@@ -21061,18 +21556,18 @@ var recordProcessor = (schema, ctx, _json, params) => {
21061
21556
  ...params,
21062
21557
  path: [...params.path, "patternProperties", "*"]
21063
21558
  });
21064
- json6.patternProperties = {};
21559
+ json7.patternProperties = {};
21065
21560
  for (const pattern of patterns) {
21066
- json6.patternProperties[pattern.source] = valueSchema;
21561
+ json7.patternProperties[pattern.source] = valueSchema;
21067
21562
  }
21068
21563
  } else {
21069
21564
  if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
21070
- json6.propertyNames = process2(def.keyType, ctx, {
21565
+ json7.propertyNames = process2(def.keyType, ctx, {
21071
21566
  ...params,
21072
21567
  path: [...params.path, "propertyNames"]
21073
21568
  });
21074
21569
  }
21075
- json6.additionalProperties = process2(def.valueType, ctx, {
21570
+ json7.additionalProperties = process2(def.valueType, ctx, {
21076
21571
  ...params,
21077
21572
  path: [...params.path, "additionalProperties"]
21078
21573
  });
@@ -21081,19 +21576,19 @@ var recordProcessor = (schema, ctx, _json, params) => {
21081
21576
  if (keyValues) {
21082
21577
  const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
21083
21578
  if (validKeyValues.length > 0) {
21084
- json6.required = validKeyValues;
21579
+ json7.required = validKeyValues;
21085
21580
  }
21086
21581
  }
21087
21582
  };
21088
- var nullableProcessor = (schema, ctx, json6, params) => {
21583
+ var nullableProcessor = (schema, ctx, json7, params) => {
21089
21584
  const def = schema._zod.def;
21090
21585
  const inner = process2(def.innerType, ctx, params);
21091
21586
  const seen = ctx.seen.get(schema);
21092
21587
  if (ctx.target === "openapi-3.0") {
21093
21588
  seen.ref = def.innerType;
21094
- json6.nullable = true;
21589
+ json7.nullable = true;
21095
21590
  } else {
21096
- json6.anyOf = [inner, { type: "null" }];
21591
+ json7.anyOf = [inner, { type: "null" }];
21097
21592
  }
21098
21593
  };
21099
21594
  var nonoptionalProcessor = (schema, ctx, _json, params) => {
@@ -21102,22 +21597,22 @@ var nonoptionalProcessor = (schema, ctx, _json, params) => {
21102
21597
  const seen = ctx.seen.get(schema);
21103
21598
  seen.ref = def.innerType;
21104
21599
  };
21105
- var defaultProcessor = (schema, ctx, json6, params) => {
21600
+ var defaultProcessor = (schema, ctx, json7, params) => {
21106
21601
  const def = schema._zod.def;
21107
21602
  process2(def.innerType, ctx, params);
21108
21603
  const seen = ctx.seen.get(schema);
21109
21604
  seen.ref = def.innerType;
21110
- json6.default = JSON.parse(JSON.stringify(def.defaultValue));
21605
+ json7.default = JSON.parse(JSON.stringify(def.defaultValue));
21111
21606
  };
21112
- var prefaultProcessor = (schema, ctx, json6, params) => {
21607
+ var prefaultProcessor = (schema, ctx, json7, params) => {
21113
21608
  const def = schema._zod.def;
21114
21609
  process2(def.innerType, ctx, params);
21115
21610
  const seen = ctx.seen.get(schema);
21116
21611
  seen.ref = def.innerType;
21117
21612
  if (ctx.io === "input")
21118
- json6._prefault = JSON.parse(JSON.stringify(def.defaultValue));
21613
+ json7._prefault = JSON.parse(JSON.stringify(def.defaultValue));
21119
21614
  };
21120
- var catchProcessor = (schema, ctx, json6, params) => {
21615
+ var catchProcessor = (schema, ctx, json7, params) => {
21121
21616
  const def = schema._zod.def;
21122
21617
  process2(def.innerType, ctx, params);
21123
21618
  const seen = ctx.seen.get(schema);
@@ -21128,7 +21623,7 @@ var catchProcessor = (schema, ctx, json6, params) => {
21128
21623
  } catch {
21129
21624
  throw new Error("Dynamic catch values are not supported in JSON Schema");
21130
21625
  }
21131
- json6.default = catchValue;
21626
+ json7.default = catchValue;
21132
21627
  };
21133
21628
  var pipeProcessor = (schema, ctx, _json, params) => {
21134
21629
  const def = schema._zod.def;
@@ -21138,12 +21633,12 @@ var pipeProcessor = (schema, ctx, _json, params) => {
21138
21633
  const seen = ctx.seen.get(schema);
21139
21634
  seen.ref = innerType;
21140
21635
  };
21141
- var readonlyProcessor = (schema, ctx, json6, params) => {
21636
+ var readonlyProcessor = (schema, ctx, json7, params) => {
21142
21637
  const def = schema._zod.def;
21143
21638
  process2(def.innerType, ctx, params);
21144
21639
  const seen = ctx.seen.get(schema);
21145
21640
  seen.ref = def.innerType;
21146
- json6.readOnly = true;
21641
+ json7.readOnly = true;
21147
21642
  };
21148
21643
  var promiseProcessor = (schema, ctx, _json, params) => {
21149
21644
  const def = schema._zod.def;
@@ -21413,7 +21908,7 @@ __export(exports_schemas2, {
21413
21908
  invertCodec: () => invertCodec,
21414
21909
  ipv4: () => ipv42,
21415
21910
  ipv6: () => ipv62,
21416
- json: () => json6,
21911
+ json: () => json7,
21417
21912
  jwt: () => jwt,
21418
21913
  keyof: () => keyof,
21419
21914
  ksuid: () => ksuid2,
@@ -21764,7 +22259,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
21764
22259
  var _ZodString = /* @__PURE__ */ $constructor("_ZodString", (inst, def) => {
21765
22260
  $ZodString.init(inst, def);
21766
22261
  ZodType.init(inst, def);
21767
- inst._zod.processJSONSchema = (ctx, json6, params) => stringProcessor(inst, ctx, json6, params);
22262
+ inst._zod.processJSONSchema = (ctx, json7, params) => stringProcessor(inst, ctx, json7, params);
21768
22263
  const bag = inst._zod.bag;
21769
22264
  inst.format = bag.format ?? null;
21770
22265
  inst.minLength = bag.minimum ?? null;
@@ -22035,7 +22530,7 @@ function hash2(alg, params) {
22035
22530
  var ZodNumber = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => {
22036
22531
  $ZodNumber.init(inst, def);
22037
22532
  ZodType.init(inst, def);
22038
- inst._zod.processJSONSchema = (ctx, json6, params) => numberProcessor(inst, ctx, json6, params);
22533
+ inst._zod.processJSONSchema = (ctx, json7, params) => numberProcessor(inst, ctx, json7, params);
22039
22534
  _installLazyMethods(inst, "ZodNumber", {
22040
22535
  gt(value, params) {
22041
22536
  return this.check(_gt(value, params));
@@ -22115,7 +22610,7 @@ function uint32(params) {
22115
22610
  var ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
22116
22611
  $ZodBoolean.init(inst, def);
22117
22612
  ZodType.init(inst, def);
22118
- inst._zod.processJSONSchema = (ctx, json6, params) => booleanProcessor(inst, ctx, json6, params);
22613
+ inst._zod.processJSONSchema = (ctx, json7, params) => booleanProcessor(inst, ctx, json7, params);
22119
22614
  });
22120
22615
  function boolean2(params) {
22121
22616
  return _boolean(ZodBoolean, params);
@@ -22123,7 +22618,7 @@ function boolean2(params) {
22123
22618
  var ZodBigInt = /* @__PURE__ */ $constructor("ZodBigInt", (inst, def) => {
22124
22619
  $ZodBigInt.init(inst, def);
22125
22620
  ZodType.init(inst, def);
22126
- inst._zod.processJSONSchema = (ctx, json6, params) => bigintProcessor(inst, ctx, json6, params);
22621
+ inst._zod.processJSONSchema = (ctx, json7, params) => bigintProcessor(inst, ctx, json7, params);
22127
22622
  inst.gte = (value, params) => inst.check(_gte(value, params));
22128
22623
  inst.min = (value, params) => inst.check(_gte(value, params));
22129
22624
  inst.gt = (value, params) => inst.check(_gt(value, params));
@@ -22158,7 +22653,7 @@ function uint64(params) {
22158
22653
  var ZodSymbol = /* @__PURE__ */ $constructor("ZodSymbol", (inst, def) => {
22159
22654
  $ZodSymbol.init(inst, def);
22160
22655
  ZodType.init(inst, def);
22161
- inst._zod.processJSONSchema = (ctx, json6, params) => symbolProcessor(inst, ctx, json6, params);
22656
+ inst._zod.processJSONSchema = (ctx, json7, params) => symbolProcessor(inst, ctx, json7, params);
22162
22657
  });
22163
22658
  function symbol(params) {
22164
22659
  return _symbol(ZodSymbol, params);
@@ -22166,7 +22661,7 @@ function symbol(params) {
22166
22661
  var ZodUndefined = /* @__PURE__ */ $constructor("ZodUndefined", (inst, def) => {
22167
22662
  $ZodUndefined.init(inst, def);
22168
22663
  ZodType.init(inst, def);
22169
- inst._zod.processJSONSchema = (ctx, json6, params) => undefinedProcessor(inst, ctx, json6, params);
22664
+ inst._zod.processJSONSchema = (ctx, json7, params) => undefinedProcessor(inst, ctx, json7, params);
22170
22665
  });
22171
22666
  function _undefined3(params) {
22172
22667
  return _undefined2(ZodUndefined, params);
@@ -22174,7 +22669,7 @@ function _undefined3(params) {
22174
22669
  var ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
22175
22670
  $ZodNull.init(inst, def);
22176
22671
  ZodType.init(inst, def);
22177
- inst._zod.processJSONSchema = (ctx, json6, params) => nullProcessor(inst, ctx, json6, params);
22672
+ inst._zod.processJSONSchema = (ctx, json7, params) => nullProcessor(inst, ctx, json7, params);
22178
22673
  });
22179
22674
  function _null3(params) {
22180
22675
  return _null2(ZodNull, params);
@@ -22182,7 +22677,7 @@ function _null3(params) {
22182
22677
  var ZodAny = /* @__PURE__ */ $constructor("ZodAny", (inst, def) => {
22183
22678
  $ZodAny.init(inst, def);
22184
22679
  ZodType.init(inst, def);
22185
- inst._zod.processJSONSchema = (ctx, json6, params) => anyProcessor(inst, ctx, json6, params);
22680
+ inst._zod.processJSONSchema = (ctx, json7, params) => anyProcessor(inst, ctx, json7, params);
22186
22681
  });
22187
22682
  function any() {
22188
22683
  return _any(ZodAny);
@@ -22190,7 +22685,7 @@ function any() {
22190
22685
  var ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
22191
22686
  $ZodUnknown.init(inst, def);
22192
22687
  ZodType.init(inst, def);
22193
- inst._zod.processJSONSchema = (ctx, json6, params) => unknownProcessor(inst, ctx, json6, params);
22688
+ inst._zod.processJSONSchema = (ctx, json7, params) => unknownProcessor(inst, ctx, json7, params);
22194
22689
  });
22195
22690
  function unknown() {
22196
22691
  return _unknown(ZodUnknown);
@@ -22198,7 +22693,7 @@ function unknown() {
22198
22693
  var ZodNever = /* @__PURE__ */ $constructor("ZodNever", (inst, def) => {
22199
22694
  $ZodNever.init(inst, def);
22200
22695
  ZodType.init(inst, def);
22201
- inst._zod.processJSONSchema = (ctx, json6, params) => neverProcessor(inst, ctx, json6, params);
22696
+ inst._zod.processJSONSchema = (ctx, json7, params) => neverProcessor(inst, ctx, json7, params);
22202
22697
  });
22203
22698
  function never(params) {
22204
22699
  return _never(ZodNever, params);
@@ -22206,7 +22701,7 @@ function never(params) {
22206
22701
  var ZodVoid = /* @__PURE__ */ $constructor("ZodVoid", (inst, def) => {
22207
22702
  $ZodVoid.init(inst, def);
22208
22703
  ZodType.init(inst, def);
22209
- inst._zod.processJSONSchema = (ctx, json6, params) => voidProcessor(inst, ctx, json6, params);
22704
+ inst._zod.processJSONSchema = (ctx, json7, params) => voidProcessor(inst, ctx, json7, params);
22210
22705
  });
22211
22706
  function _void2(params) {
22212
22707
  return _void(ZodVoid, params);
@@ -22214,7 +22709,7 @@ function _void2(params) {
22214
22709
  var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
22215
22710
  $ZodDate.init(inst, def);
22216
22711
  ZodType.init(inst, def);
22217
- inst._zod.processJSONSchema = (ctx, json6, params) => dateProcessor(inst, ctx, json6, params);
22712
+ inst._zod.processJSONSchema = (ctx, json7, params) => dateProcessor(inst, ctx, json7, params);
22218
22713
  inst.min = (value, params) => inst.check(_gte(value, params));
22219
22714
  inst.max = (value, params) => inst.check(_lte(value, params));
22220
22715
  const c = inst._zod.bag;
@@ -22227,7 +22722,7 @@ function date3(params) {
22227
22722
  var ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => {
22228
22723
  $ZodArray.init(inst, def);
22229
22724
  ZodType.init(inst, def);
22230
- inst._zod.processJSONSchema = (ctx, json6, params) => arrayProcessor(inst, ctx, json6, params);
22725
+ inst._zod.processJSONSchema = (ctx, json7, params) => arrayProcessor(inst, ctx, json7, params);
22231
22726
  inst.element = def.element;
22232
22727
  _installLazyMethods(inst, "ZodArray", {
22233
22728
  min(n, params) {
@@ -22257,7 +22752,7 @@ function keyof(schema) {
22257
22752
  var ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
22258
22753
  $ZodObjectJIT.init(inst, def);
22259
22754
  ZodType.init(inst, def);
22260
- inst._zod.processJSONSchema = (ctx, json6, params) => objectProcessor(inst, ctx, json6, params);
22755
+ inst._zod.processJSONSchema = (ctx, json7, params) => objectProcessor(inst, ctx, json7, params);
22261
22756
  exports_util.defineLazy(inst, "shape", () => {
22262
22757
  return def.shape;
22263
22758
  });
@@ -22330,7 +22825,7 @@ function looseObject(shape, params) {
22330
22825
  var ZodUnion = /* @__PURE__ */ $constructor("ZodUnion", (inst, def) => {
22331
22826
  $ZodUnion.init(inst, def);
22332
22827
  ZodType.init(inst, def);
22333
- inst._zod.processJSONSchema = (ctx, json6, params) => unionProcessor(inst, ctx, json6, params);
22828
+ inst._zod.processJSONSchema = (ctx, json7, params) => unionProcessor(inst, ctx, json7, params);
22334
22829
  inst.options = def.options;
22335
22830
  });
22336
22831
  function union(options, params) {
@@ -22343,7 +22838,7 @@ function union(options, params) {
22343
22838
  var ZodXor = /* @__PURE__ */ $constructor("ZodXor", (inst, def) => {
22344
22839
  ZodUnion.init(inst, def);
22345
22840
  $ZodXor.init(inst, def);
22346
- inst._zod.processJSONSchema = (ctx, json6, params) => unionProcessor(inst, ctx, json6, params);
22841
+ inst._zod.processJSONSchema = (ctx, json7, params) => unionProcessor(inst, ctx, json7, params);
22347
22842
  inst.options = def.options;
22348
22843
  });
22349
22844
  function xor(options, params) {
@@ -22369,7 +22864,7 @@ function discriminatedUnion(discriminator, options, params) {
22369
22864
  var ZodIntersection = /* @__PURE__ */ $constructor("ZodIntersection", (inst, def) => {
22370
22865
  $ZodIntersection.init(inst, def);
22371
22866
  ZodType.init(inst, def);
22372
- inst._zod.processJSONSchema = (ctx, json6, params) => intersectionProcessor(inst, ctx, json6, params);
22867
+ inst._zod.processJSONSchema = (ctx, json7, params) => intersectionProcessor(inst, ctx, json7, params);
22373
22868
  });
22374
22869
  function intersection(left, right) {
22375
22870
  return new ZodIntersection({
@@ -22381,7 +22876,7 @@ function intersection(left, right) {
22381
22876
  var ZodTuple = /* @__PURE__ */ $constructor("ZodTuple", (inst, def) => {
22382
22877
  $ZodTuple.init(inst, def);
22383
22878
  ZodType.init(inst, def);
22384
- inst._zod.processJSONSchema = (ctx, json6, params) => tupleProcessor(inst, ctx, json6, params);
22879
+ inst._zod.processJSONSchema = (ctx, json7, params) => tupleProcessor(inst, ctx, json7, params);
22385
22880
  inst.rest = (rest) => inst.clone({
22386
22881
  ...inst._zod.def,
22387
22882
  rest
@@ -22401,7 +22896,7 @@ function tuple(items, _paramsOrRest, _params) {
22401
22896
  var ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
22402
22897
  $ZodRecord.init(inst, def);
22403
22898
  ZodType.init(inst, def);
22404
- inst._zod.processJSONSchema = (ctx, json6, params) => recordProcessor(inst, ctx, json6, params);
22899
+ inst._zod.processJSONSchema = (ctx, json7, params) => recordProcessor(inst, ctx, json7, params);
22405
22900
  inst.keyType = def.keyType;
22406
22901
  inst.valueType = def.valueType;
22407
22902
  });
@@ -22443,7 +22938,7 @@ function looseRecord(keyType, valueType, params) {
22443
22938
  var ZodMap = /* @__PURE__ */ $constructor("ZodMap", (inst, def) => {
22444
22939
  $ZodMap.init(inst, def);
22445
22940
  ZodType.init(inst, def);
22446
- inst._zod.processJSONSchema = (ctx, json6, params) => mapProcessor(inst, ctx, json6, params);
22941
+ inst._zod.processJSONSchema = (ctx, json7, params) => mapProcessor(inst, ctx, json7, params);
22447
22942
  inst.keyType = def.keyType;
22448
22943
  inst.valueType = def.valueType;
22449
22944
  inst.min = (...args) => inst.check(_minSize(...args));
@@ -22462,7 +22957,7 @@ function map(keyType, valueType, params) {
22462
22957
  var ZodSet = /* @__PURE__ */ $constructor("ZodSet", (inst, def) => {
22463
22958
  $ZodSet.init(inst, def);
22464
22959
  ZodType.init(inst, def);
22465
- inst._zod.processJSONSchema = (ctx, json6, params) => setProcessor(inst, ctx, json6, params);
22960
+ inst._zod.processJSONSchema = (ctx, json7, params) => setProcessor(inst, ctx, json7, params);
22466
22961
  inst.min = (...args) => inst.check(_minSize(...args));
22467
22962
  inst.nonempty = (params) => inst.check(_minSize(1, params));
22468
22963
  inst.max = (...args) => inst.check(_maxSize(...args));
@@ -22478,7 +22973,7 @@ function set(valueType, params) {
22478
22973
  var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
22479
22974
  $ZodEnum.init(inst, def);
22480
22975
  ZodType.init(inst, def);
22481
- inst._zod.processJSONSchema = (ctx, json6, params) => enumProcessor(inst, ctx, json6, params);
22976
+ inst._zod.processJSONSchema = (ctx, json7, params) => enumProcessor(inst, ctx, json7, params);
22482
22977
  inst.enum = def.entries;
22483
22978
  inst.options = Object.values(def.entries);
22484
22979
  const keys = new Set(Object.keys(def.entries));
@@ -22531,7 +23026,7 @@ function nativeEnum(entries, params) {
22531
23026
  var ZodLiteral = /* @__PURE__ */ $constructor("ZodLiteral", (inst, def) => {
22532
23027
  $ZodLiteral.init(inst, def);
22533
23028
  ZodType.init(inst, def);
22534
- inst._zod.processJSONSchema = (ctx, json6, params) => literalProcessor(inst, ctx, json6, params);
23029
+ inst._zod.processJSONSchema = (ctx, json7, params) => literalProcessor(inst, ctx, json7, params);
22535
23030
  inst.values = new Set(def.values);
22536
23031
  Object.defineProperty(inst, "value", {
22537
23032
  get() {
@@ -22552,7 +23047,7 @@ function literal(value, params) {
22552
23047
  var ZodFile = /* @__PURE__ */ $constructor("ZodFile", (inst, def) => {
22553
23048
  $ZodFile.init(inst, def);
22554
23049
  ZodType.init(inst, def);
22555
- inst._zod.processJSONSchema = (ctx, json6, params) => fileProcessor(inst, ctx, json6, params);
23050
+ inst._zod.processJSONSchema = (ctx, json7, params) => fileProcessor(inst, ctx, json7, params);
22556
23051
  inst.min = (size, params) => inst.check(_minSize(size, params));
22557
23052
  inst.max = (size, params) => inst.check(_maxSize(size, params));
22558
23053
  inst.mime = (types2, params) => inst.check(_mime(Array.isArray(types2) ? types2 : [types2], params));
@@ -22563,7 +23058,7 @@ function file(params) {
22563
23058
  var ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) => {
22564
23059
  $ZodTransform.init(inst, def);
22565
23060
  ZodType.init(inst, def);
22566
- inst._zod.processJSONSchema = (ctx, json6, params) => transformProcessor(inst, ctx, json6, params);
23061
+ inst._zod.processJSONSchema = (ctx, json7, params) => transformProcessor(inst, ctx, json7, params);
22567
23062
  inst._zod.parse = (payload, _ctx) => {
22568
23063
  if (_ctx.direction === "backward") {
22569
23064
  throw new $ZodEncodeError(inst.constructor.name);
@@ -22603,7 +23098,7 @@ function transform(fn) {
22603
23098
  var ZodOptional = /* @__PURE__ */ $constructor("ZodOptional", (inst, def) => {
22604
23099
  $ZodOptional.init(inst, def);
22605
23100
  ZodType.init(inst, def);
22606
- inst._zod.processJSONSchema = (ctx, json6, params) => optionalProcessor(inst, ctx, json6, params);
23101
+ inst._zod.processJSONSchema = (ctx, json7, params) => optionalProcessor(inst, ctx, json7, params);
22607
23102
  inst.unwrap = () => inst._zod.def.innerType;
22608
23103
  });
22609
23104
  function optional(innerType) {
@@ -22615,7 +23110,7 @@ function optional(innerType) {
22615
23110
  var ZodExactOptional = /* @__PURE__ */ $constructor("ZodExactOptional", (inst, def) => {
22616
23111
  $ZodExactOptional.init(inst, def);
22617
23112
  ZodType.init(inst, def);
22618
- inst._zod.processJSONSchema = (ctx, json6, params) => optionalProcessor(inst, ctx, json6, params);
23113
+ inst._zod.processJSONSchema = (ctx, json7, params) => optionalProcessor(inst, ctx, json7, params);
22619
23114
  inst.unwrap = () => inst._zod.def.innerType;
22620
23115
  });
22621
23116
  function exactOptional(innerType) {
@@ -22627,7 +23122,7 @@ function exactOptional(innerType) {
22627
23122
  var ZodNullable = /* @__PURE__ */ $constructor("ZodNullable", (inst, def) => {
22628
23123
  $ZodNullable.init(inst, def);
22629
23124
  ZodType.init(inst, def);
22630
- inst._zod.processJSONSchema = (ctx, json6, params) => nullableProcessor(inst, ctx, json6, params);
23125
+ inst._zod.processJSONSchema = (ctx, json7, params) => nullableProcessor(inst, ctx, json7, params);
22631
23126
  inst.unwrap = () => inst._zod.def.innerType;
22632
23127
  });
22633
23128
  function nullable(innerType) {
@@ -22642,7 +23137,7 @@ function nullish2(innerType) {
22642
23137
  var ZodDefault = /* @__PURE__ */ $constructor("ZodDefault", (inst, def) => {
22643
23138
  $ZodDefault.init(inst, def);
22644
23139
  ZodType.init(inst, def);
22645
- inst._zod.processJSONSchema = (ctx, json6, params) => defaultProcessor(inst, ctx, json6, params);
23140
+ inst._zod.processJSONSchema = (ctx, json7, params) => defaultProcessor(inst, ctx, json7, params);
22646
23141
  inst.unwrap = () => inst._zod.def.innerType;
22647
23142
  inst.removeDefault = inst.unwrap;
22648
23143
  });
@@ -22658,7 +23153,7 @@ function _default2(innerType, defaultValue) {
22658
23153
  var ZodPrefault = /* @__PURE__ */ $constructor("ZodPrefault", (inst, def) => {
22659
23154
  $ZodPrefault.init(inst, def);
22660
23155
  ZodType.init(inst, def);
22661
- inst._zod.processJSONSchema = (ctx, json6, params) => prefaultProcessor(inst, ctx, json6, params);
23156
+ inst._zod.processJSONSchema = (ctx, json7, params) => prefaultProcessor(inst, ctx, json7, params);
22662
23157
  inst.unwrap = () => inst._zod.def.innerType;
22663
23158
  });
22664
23159
  function prefault(innerType, defaultValue) {
@@ -22673,7 +23168,7 @@ function prefault(innerType, defaultValue) {
22673
23168
  var ZodNonOptional = /* @__PURE__ */ $constructor("ZodNonOptional", (inst, def) => {
22674
23169
  $ZodNonOptional.init(inst, def);
22675
23170
  ZodType.init(inst, def);
22676
- inst._zod.processJSONSchema = (ctx, json6, params) => nonoptionalProcessor(inst, ctx, json6, params);
23171
+ inst._zod.processJSONSchema = (ctx, json7, params) => nonoptionalProcessor(inst, ctx, json7, params);
22677
23172
  inst.unwrap = () => inst._zod.def.innerType;
22678
23173
  });
22679
23174
  function nonoptional(innerType, params) {
@@ -22686,7 +23181,7 @@ function nonoptional(innerType, params) {
22686
23181
  var ZodSuccess = /* @__PURE__ */ $constructor("ZodSuccess", (inst, def) => {
22687
23182
  $ZodSuccess.init(inst, def);
22688
23183
  ZodType.init(inst, def);
22689
- inst._zod.processJSONSchema = (ctx, json6, params) => successProcessor(inst, ctx, json6, params);
23184
+ inst._zod.processJSONSchema = (ctx, json7, params) => successProcessor(inst, ctx, json7, params);
22690
23185
  inst.unwrap = () => inst._zod.def.innerType;
22691
23186
  });
22692
23187
  function success(innerType) {
@@ -22698,7 +23193,7 @@ function success(innerType) {
22698
23193
  var ZodCatch = /* @__PURE__ */ $constructor("ZodCatch", (inst, def) => {
22699
23194
  $ZodCatch.init(inst, def);
22700
23195
  ZodType.init(inst, def);
22701
- inst._zod.processJSONSchema = (ctx, json6, params) => catchProcessor(inst, ctx, json6, params);
23196
+ inst._zod.processJSONSchema = (ctx, json7, params) => catchProcessor(inst, ctx, json7, params);
22702
23197
  inst.unwrap = () => inst._zod.def.innerType;
22703
23198
  inst.removeCatch = inst.unwrap;
22704
23199
  });
@@ -22712,7 +23207,7 @@ function _catch2(innerType, catchValue) {
22712
23207
  var ZodNaN = /* @__PURE__ */ $constructor("ZodNaN", (inst, def) => {
22713
23208
  $ZodNaN.init(inst, def);
22714
23209
  ZodType.init(inst, def);
22715
- inst._zod.processJSONSchema = (ctx, json6, params) => nanProcessor(inst, ctx, json6, params);
23210
+ inst._zod.processJSONSchema = (ctx, json7, params) => nanProcessor(inst, ctx, json7, params);
22716
23211
  });
22717
23212
  function nan(params) {
22718
23213
  return _nan(ZodNaN, params);
@@ -22720,7 +23215,7 @@ function nan(params) {
22720
23215
  var ZodPipe = /* @__PURE__ */ $constructor("ZodPipe", (inst, def) => {
22721
23216
  $ZodPipe.init(inst, def);
22722
23217
  ZodType.init(inst, def);
22723
- inst._zod.processJSONSchema = (ctx, json6, params) => pipeProcessor(inst, ctx, json6, params);
23218
+ inst._zod.processJSONSchema = (ctx, json7, params) => pipeProcessor(inst, ctx, json7, params);
22724
23219
  inst.in = def.in;
22725
23220
  inst.out = def.out;
22726
23221
  });
@@ -22761,7 +23256,7 @@ var ZodPreprocess = /* @__PURE__ */ $constructor("ZodPreprocess", (inst, def) =>
22761
23256
  var ZodReadonly = /* @__PURE__ */ $constructor("ZodReadonly", (inst, def) => {
22762
23257
  $ZodReadonly.init(inst, def);
22763
23258
  ZodType.init(inst, def);
22764
- inst._zod.processJSONSchema = (ctx, json6, params) => readonlyProcessor(inst, ctx, json6, params);
23259
+ inst._zod.processJSONSchema = (ctx, json7, params) => readonlyProcessor(inst, ctx, json7, params);
22765
23260
  inst.unwrap = () => inst._zod.def.innerType;
22766
23261
  });
22767
23262
  function readonly(innerType) {
@@ -22773,7 +23268,7 @@ function readonly(innerType) {
22773
23268
  var ZodTemplateLiteral = /* @__PURE__ */ $constructor("ZodTemplateLiteral", (inst, def) => {
22774
23269
  $ZodTemplateLiteral.init(inst, def);
22775
23270
  ZodType.init(inst, def);
22776
- inst._zod.processJSONSchema = (ctx, json6, params) => templateLiteralProcessor(inst, ctx, json6, params);
23271
+ inst._zod.processJSONSchema = (ctx, json7, params) => templateLiteralProcessor(inst, ctx, json7, params);
22777
23272
  });
22778
23273
  function templateLiteral(parts, params) {
22779
23274
  return new ZodTemplateLiteral({
@@ -22785,7 +23280,7 @@ function templateLiteral(parts, params) {
22785
23280
  var ZodLazy = /* @__PURE__ */ $constructor("ZodLazy", (inst, def) => {
22786
23281
  $ZodLazy.init(inst, def);
22787
23282
  ZodType.init(inst, def);
22788
- inst._zod.processJSONSchema = (ctx, json6, params) => lazyProcessor(inst, ctx, json6, params);
23283
+ inst._zod.processJSONSchema = (ctx, json7, params) => lazyProcessor(inst, ctx, json7, params);
22789
23284
  inst.unwrap = () => inst._zod.def.getter();
22790
23285
  });
22791
23286
  function lazy(getter) {
@@ -22797,7 +23292,7 @@ function lazy(getter) {
22797
23292
  var ZodPromise = /* @__PURE__ */ $constructor("ZodPromise", (inst, def) => {
22798
23293
  $ZodPromise.init(inst, def);
22799
23294
  ZodType.init(inst, def);
22800
- inst._zod.processJSONSchema = (ctx, json6, params) => promiseProcessor(inst, ctx, json6, params);
23295
+ inst._zod.processJSONSchema = (ctx, json7, params) => promiseProcessor(inst, ctx, json7, params);
22801
23296
  inst.unwrap = () => inst._zod.def.innerType;
22802
23297
  });
22803
23298
  function promise(innerType) {
@@ -22809,7 +23304,7 @@ function promise(innerType) {
22809
23304
  var ZodFunction = /* @__PURE__ */ $constructor("ZodFunction", (inst, def) => {
22810
23305
  $ZodFunction.init(inst, def);
22811
23306
  ZodType.init(inst, def);
22812
- inst._zod.processJSONSchema = (ctx, json6, params) => functionProcessor(inst, ctx, json6, params);
23307
+ inst._zod.processJSONSchema = (ctx, json7, params) => functionProcessor(inst, ctx, json7, params);
22813
23308
  });
22814
23309
  function _function(params) {
22815
23310
  return new ZodFunction({
@@ -22821,7 +23316,7 @@ function _function(params) {
22821
23316
  var ZodCustom = /* @__PURE__ */ $constructor("ZodCustom", (inst, def) => {
22822
23317
  $ZodCustom.init(inst, def);
22823
23318
  ZodType.init(inst, def);
22824
- inst._zod.processJSONSchema = (ctx, json6, params) => customProcessor(inst, ctx, json6, params);
23319
+ inst._zod.processJSONSchema = (ctx, json7, params) => customProcessor(inst, ctx, json7, params);
22825
23320
  });
22826
23321
  function check(fn) {
22827
23322
  const ch = new $ZodCheck({
@@ -22868,7 +23363,7 @@ var stringbool = (...args) => _stringbool({
22868
23363
  Boolean: ZodBoolean,
22869
23364
  String: ZodString
22870
23365
  }, ...args);
22871
- function json6(params) {
23366
+ function json7(params) {
22872
23367
  const jsonSchema = lazy(() => {
22873
23368
  return union([string2(params), number2(), boolean2(), _null3(), array(jsonSchema), record(string2(), jsonSchema)]);
22874
23369
  });
@@ -23476,6 +23971,7 @@ var targetSchema = exports_external.discriminatedUnion("provider", [
23476
23971
  }),
23477
23972
  contextWindow: exports_external.number().int().positive().optional(),
23478
23973
  maxOutputTokens: exports_external.number().int().positive().optional(),
23974
+ credentialId: exports_external.string().trim().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/, "credentialId must be an account id").optional(),
23479
23975
  capabilities: exports_external.object({
23480
23976
  tools: exports_external.boolean(),
23481
23977
  images: exports_external.boolean(),
@@ -23497,6 +23993,7 @@ var targetSchema = exports_external.discriminatedUnion("provider", [
23497
23993
  }),
23498
23994
  contextWindow: exports_external.number().int().positive().optional(),
23499
23995
  maxOutputTokens: exports_external.number().int().positive().optional(),
23996
+ credentialId: exports_external.string().trim().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/, "credentialId must be an account id").optional(),
23500
23997
  capabilities: exports_external.object({
23501
23998
  tools: exports_external.boolean(),
23502
23999
  images: exports_external.boolean(),
@@ -23505,9 +24002,7 @@ var targetSchema = exports_external.discriminatedUnion("provider", [
23505
24002
  }).strict()
23506
24003
  ]);
23507
24004
  var modelSchema = exports_external.object({
23508
- id: exports_external.string().min(1).refine((value) => !value.toLowerCase().startsWith("claude/"), {
23509
- message: 'model id must not start with "claude/": that prefix is reserved for discovery mirrors'
23510
- }),
24005
+ id: exports_external.string().min(1),
23511
24006
  strategy: exports_external.enum(["score", "priority", "roundRobin", "weighted"]),
23512
24007
  isAlias: exports_external.boolean(),
23513
24008
  targets: exports_external.array(targetSchema).min(1, "a virtual model needs at least one target")
@@ -23519,6 +24014,9 @@ var keyCreateSchema = exports_external.object({
23519
24014
  bodyLoggingOptOut: exports_external.boolean().default(false)
23520
24015
  }).strict();
23521
24016
  var keyLimitsSchema = exports_external.object({ limits: limitConfigSchema }).strict();
24017
+ var keyModelsSchema = exports_external.object({
24018
+ modelAllowlist: exports_external.array(exports_external.string().min(1)).nullable()
24019
+ }).strict();
23522
24020
  var retentionSchema = exports_external.object({
23523
24021
  keepLatest: exports_external.number().int().min(1).max(100),
23524
24022
  maxAgeDays: exports_external.number().int().min(1).max(3650)
@@ -23616,13 +24114,65 @@ async function readSource(deps, source, lines) {
23616
24114
  ]);
23617
24115
  return result.code === 0 ? result.stdout : "";
23618
24116
  }
24117
+ function parseConsoleLines(text, query) {
24118
+ const lines = consoleLimit(query.lines);
24119
+ return text.split(`
24120
+ `).filter((raw) => raw.trim().length > 0).map(parseLine).filter((line) => keep(line, query)).slice(-lines);
24121
+ }
23619
24122
  async function readConsole(deps, source, query) {
23620
24123
  const limited = { ...query, lines: consoleLimit(query.lines) };
23621
24124
  const text = await readSource(deps, source, scanWidth(limited));
23622
- const lines = text.split(`
23623
- `).filter((raw) => raw.trim().length > 0).map(parseLine).filter((line) => keep(line, limited)).slice(-limited.lines);
24125
+ const lines = parseConsoleLines(text, limited);
23624
24126
  return source.kind === "file" ? { source: "file", path: source.path, lines } : { source: source.kind, lines };
23625
24127
  }
24128
+ // packages/store/src/types.ts
24129
+ var WINDOW_DURATION_MS = {
24130
+ fiveHour: 5 * 60 * 60 * 1000,
24131
+ daily: 24 * 60 * 60 * 1000,
24132
+ weekly: 7 * 24 * 60 * 60 * 1000
24133
+ };
24134
+ function durationFor(windowType, windowMs) {
24135
+ return windowMs !== null && windowMs > 0 ? windowMs : WINDOW_DURATION_MS[windowType];
24136
+ }
24137
+ var SAME_WINDOW_TOLERANCE_MS = 60000;
24138
+ function sameWindow(a, b) {
24139
+ if (a === null || b === null)
24140
+ return a === b;
24141
+ return Math.abs(a - b) <= SAME_WINDOW_TOLERANCE_MS;
24142
+ }
24143
+ var READ_OVER_INPUT = 0.1;
24144
+ function cacheReadRate(prices) {
24145
+ return prices.cacheRead ?? prices.input * READ_OVER_INPUT;
24146
+ }
24147
+ function servesTarget(target, account) {
24148
+ if (account.provider !== target.provider)
24149
+ return false;
24150
+ if (target.provider === "custom" && account.providerData.endpointId !== target.endpointId) {
24151
+ return false;
24152
+ }
24153
+ return target.credentialId === undefined || account.id === target.credentialId;
24154
+ }
24155
+ function resolvePin(target, accounts) {
24156
+ if (target.credentialId === undefined)
24157
+ return;
24158
+ return accounts.find((account) => servesTarget(target, account));
24159
+ }
24160
+ var DEFAULT_SETTINGS = {
24161
+ weights: { tier: 10, health: 3, quota: 2, load: 2, cost: 1, latency: 1 },
24162
+ maxAttempts: 3,
24163
+ requestDeadlineMs: 120000,
24164
+ breakerThreshold: 3,
24165
+ breakerCooldownMs: 30000,
24166
+ logRetentionDays: 30,
24167
+ quotaPollIntervalMs: 300000,
24168
+ rtkEnabled: false,
24169
+ autoCacheEnabled: true,
24170
+ bodyLoggingEnabled: false,
24171
+ bodyLoggingCaptureStreamChunks: false,
24172
+ snapshotKeepLatest: 5,
24173
+ snapshotMaxAgeDays: 30
24174
+ };
24175
+
23626
24176
  // packages/router/src/snapshot.ts
23627
24177
  var HEALTH_KEY_SEP = "::";
23628
24178
  function healthKey(credentialId, model) {
@@ -23682,12 +24232,11 @@ function eligible(input) {
23682
24232
  const excluded = [];
23683
24233
  for (const target of model.targets) {
23684
24234
  const missing = needNative && !ANTHROPIC_NATIVE_TOOLS[target.provider] ? "anthropicTools" : ["tools", "images", "reasoning"].find((cap) => need[cap] && !target.capabilities[cap]);
24235
+ let pinSeen = false;
23685
24236
  for (const credential of snapshot.credentials) {
23686
- if (credential.provider !== target.provider)
23687
- continue;
23688
- if (target.provider === "custom" && credential.providerData.endpointId !== target.endpointId) {
24237
+ if (!servesTarget(target, credential))
23689
24238
  continue;
23690
- }
24239
+ pinSeen = target.credentialId !== undefined;
23691
24240
  const drop = (reason) => {
23692
24241
  excluded.push({ credentialId: credential.id, model: target.model, reason });
23693
24242
  };
@@ -23724,45 +24273,17 @@ function eligible(input) {
23724
24273
  }
23725
24274
  pairs.push({ credential, target });
23726
24275
  }
24276
+ if (target.credentialId !== undefined && !pinSeen) {
24277
+ excluded.push({
24278
+ credentialId: target.credentialId,
24279
+ model: target.model,
24280
+ reason: "pin:missing"
24281
+ });
24282
+ }
23727
24283
  }
23728
24284
  return { pairs, excluded };
23729
24285
  }
23730
24286
 
23731
- // packages/store/src/types.ts
23732
- var WINDOW_DURATION_MS = {
23733
- fiveHour: 5 * 60 * 60 * 1000,
23734
- daily: 24 * 60 * 60 * 1000,
23735
- weekly: 7 * 24 * 60 * 60 * 1000
23736
- };
23737
- function durationFor(windowType, windowMs) {
23738
- return windowMs !== null && windowMs > 0 ? windowMs : WINDOW_DURATION_MS[windowType];
23739
- }
23740
- var SAME_WINDOW_TOLERANCE_MS = 60000;
23741
- function sameWindow(a, b) {
23742
- if (a === null || b === null)
23743
- return a === b;
23744
- return Math.abs(a - b) <= SAME_WINDOW_TOLERANCE_MS;
23745
- }
23746
- var READ_OVER_INPUT = 0.1;
23747
- function cacheReadRate(prices) {
23748
- return prices.cacheRead ?? prices.input * READ_OVER_INPUT;
23749
- }
23750
- var DEFAULT_SETTINGS = {
23751
- weights: { tier: 10, health: 3, quota: 2, load: 2, cost: 1, latency: 1 },
23752
- maxAttempts: 3,
23753
- requestDeadlineMs: 120000,
23754
- breakerThreshold: 3,
23755
- breakerCooldownMs: 30000,
23756
- logRetentionDays: 30,
23757
- quotaPollIntervalMs: 300000,
23758
- rtkEnabled: false,
23759
- autoCacheEnabled: true,
23760
- bodyLoggingEnabled: false,
23761
- bodyLoggingCaptureStreamChunks: false,
23762
- snapshotKeepLatest: 5,
23763
- snapshotMaxAgeDays: 30
23764
- };
23765
-
23766
24287
  // packages/router/src/quota.ts
23767
24288
  var UNKNOWN_QUOTA = 0.5;
23768
24289
  var QUOTA_FLOOR = 0.1;
@@ -24225,10 +24746,10 @@ function prepareArtifact(input) {
24225
24746
  attempts,
24226
24747
  error: error51.value
24227
24748
  };
24228
- const json7 = JSON.stringify(bounded);
24229
- const size = encoder2.encode(json7).length;
24749
+ const json8 = JSON.stringify(bounded);
24750
+ const size = encoder2.encode(json8).length;
24230
24751
  if (size <= MAX_ARTIFACT_BYTES)
24231
- return { artifact: bounded, json: json7 };
24752
+ return { artifact: bounded, json: json8 };
24232
24753
  const marker = omission(size);
24233
24754
  const omitted = omitBodies(bounded, marker);
24234
24755
  const omittedJson = JSON.stringify(omitted);
@@ -24238,8 +24759,8 @@ function prepareArtifact(input) {
24238
24759
  const stripped = { ...omitted, error: marker };
24239
24760
  return { artifact: stripped, json: JSON.stringify(stripped) };
24240
24761
  }
24241
- async function sealArtifact(key, json7) {
24242
- const bytes = encoder2.encode(await encrypt(key, json7));
24762
+ async function sealArtifact(key, json8) {
24763
+ const bytes = encoder2.encode(await encrypt(key, json8));
24243
24764
  return { bytes, sha256: await sha256Hex(bytes) };
24244
24765
  }
24245
24766
  async function readArtifact(key, dir, relPath, expectedSha256) {
@@ -25558,6 +26079,12 @@ function createKeyRepo(db, logger2 = noopLogger) {
25558
26079
  id
25559
26080
  ]);
25560
26081
  },
26082
+ async setModelAllowlist(id, modelAllowlist) {
26083
+ db.run("UPDATE api_keys SET model_allowlist = ? WHERE id = ?", [
26084
+ modelAllowlist === null ? null : JSON.stringify(modelAllowlist),
26085
+ id
26086
+ ]);
26087
+ },
25561
26088
  async revoke(id) {
25562
26089
  db.run("UPDATE api_keys SET revoked_at = ? WHERE id = ?", [Date.now(), id]);
25563
26090
  }
@@ -26186,6 +26713,7 @@ async function createStore(opts) {
26186
26713
  findByHash: (hash3) => handle.keys.findByHash(hash3),
26187
26714
  create: (input) => handle.keys.create(input),
26188
26715
  setLimits: (id, limits) => handle.keys.setLimits(id, limits),
26716
+ setModelAllowlist: (id, modelAllowlist) => handle.keys.setModelAllowlist(id, modelAllowlist),
26189
26717
  revoke: (id) => handle.keys.revoke(id)
26190
26718
  },
26191
26719
  usage: {
@@ -26329,13 +26857,15 @@ function customProviderData(input) {
26329
26857
  } catch {
26330
26858
  throw new GatewayError("BAD_REQUEST", "origin: must be a valid URL");
26331
26859
  }
26332
- if (url2.protocol !== "http:" && url2.protocol !== "https:" || url2.hostname.length === 0 || url2.username.length > 0 || url2.password.length > 0 || url2.pathname !== "" && url2.pathname !== "/" || url2.search.length > 0 || url2.hash.length > 0) {
26860
+ if (url2.protocol !== "http:" && url2.protocol !== "https:" || url2.hostname.length === 0 || url2.username.length > 0 || url2.password.length > 0 || url2.search.length > 0 || url2.hash.length > 0) {
26333
26861
  throw new GatewayError("BAD_REQUEST", "origin: must be an HTTP(S) server origin");
26334
26862
  }
26335
- return { endpointId, endpointLabel, origin: url2.origin, protocol: input.protocol };
26863
+ const basePath = url2.pathname.replace(/\/+$/, "");
26864
+ return { endpointId, endpointLabel, origin: url2.origin, basePath, protocol: input.protocol };
26336
26865
  }
26337
26866
  function sameCustomEndpoint(a, b) {
26338
- return a.endpointId === b.endpointId && a.endpointLabel === b.endpointLabel && a.origin === b.origin && a.protocol === b.protocol;
26867
+ const basePath = typeof a.basePath === "string" ? a.basePath : "";
26868
+ return a.endpointId === b.endpointId && a.endpointLabel === b.endpointLabel && a.origin === b.origin && basePath === b.basePath && a.protocol === b.protocol;
26339
26869
  }
26340
26870
  async function createApiKeyCredential(store, input, logger2 = noopLogger) {
26341
26871
  const provider = parseOrThrow(providerIdSchema, input.provider);
@@ -26853,6 +27383,14 @@ async function setKeyLimits(store, id, input, now = Date.now()) {
26853
27383
  await store.keys.setLimits(id, body2.limits);
26854
27384
  return toSummary(store, { ...key, limits: body2.limits }, now);
26855
27385
  }
27386
+ async function setKeyModels(store, id, input, now = Date.now()) {
27387
+ const body2 = parseOrThrow(keyModelsSchema, input);
27388
+ const key = (await store.keys.list()).find((entry) => entry.id === id);
27389
+ if (key === undefined)
27390
+ throw new GatewayError("BAD_REQUEST", "no such api key");
27391
+ await store.keys.setModelAllowlist(id, body2.modelAllowlist);
27392
+ return toSummary(store, { ...key, modelAllowlist: body2.modelAllowlist }, now);
27393
+ }
26856
27394
  async function revokeKey(store, id) {
26857
27395
  await store.keys.revoke(id);
26858
27396
  }
@@ -26913,8 +27451,8 @@ function narrower(a, b) {
26913
27451
  ...output.length === 0 ? {} : { maxOutputTokens: Math.min(...output) }
26914
27452
  };
26915
27453
  }
26916
- function targetLimits(target, auths) {
26917
- const ways = auths.size === 0 ? ["apiKey"] : [...auths];
27454
+ function targetLimits(target, auths, pinned) {
27455
+ const ways = pinned !== undefined ? [pinned.authType] : auths.size === 0 ? ["apiKey"] : [...auths];
26918
27456
  let listed = {};
26919
27457
  for (const auth of ways) {
26920
27458
  const entry = catalogLimits(target.provider, target.model, auth);
@@ -26934,20 +27472,22 @@ function targetLimits(target, auths) {
26934
27472
  }
26935
27473
  function servingAuths(credentials) {
26936
27474
  const byProvider = new Map;
27475
+ const routable = [];
26937
27476
  for (const credential of credentials) {
26938
27477
  if (!credential.enabled)
26939
27478
  continue;
26940
27479
  const ways = byProvider.get(credential.provider) ?? new Set;
26941
27480
  ways.add(credential.authType);
26942
27481
  byProvider.set(credential.provider, ways);
27482
+ routable.push(credential);
26943
27483
  }
26944
- return byProvider;
27484
+ return { byProvider, routable };
26945
27485
  }
26946
27486
  function resolveModelLimits(model, credentials) {
26947
- const auths = servingAuths(credentials);
27487
+ const { byProvider, routable } = servingAuths(credentials);
26948
27488
  let limits = {};
26949
27489
  for (const target of model.targets) {
26950
- limits = narrower(limits, targetLimits(target, auths.get(target.provider) ?? new Set));
27490
+ limits = narrower(limits, targetLimits(target, byProvider.get(target.provider) ?? new Set, resolvePin(target, routable)));
26951
27491
  }
26952
27492
  return limits;
26953
27493
  }
@@ -26985,15 +27525,18 @@ function unreachable(model, credentials, stored) {
26985
27525
  const held = heldAuths(credentials);
26986
27526
  const grandfathered = new Set((stored?.targets ?? []).map(pairOf));
26987
27527
  for (const target of model.targets) {
26988
- if (grandfathered.has(pairOf(target)))
27528
+ const pinned = resolvePin(target, credentials);
27529
+ if (pinned === undefined && grandfathered.has(pairOf(target)))
26989
27530
  continue;
26990
- const have = held.get(target.provider);
27531
+ const have = pinned === undefined ? held.get(target.provider) : new Set([pinned.authType]);
26991
27532
  if (have === undefined)
26992
27533
  continue;
26993
27534
  const reach = catalogModelAuths(target.provider, target.model);
26994
27535
  if (reach.some((auth) => have.has(auth)))
26995
27536
  continue;
26996
- return new GatewayError("BAD_REQUEST", `${target.provider} serves "${target.model}" to ${phrase(reach)} credentials only, ` + `and every ${target.provider} credential here is ${phrase([...have])} \u2014 ` + `connect the other kind, or pick a model this one can reach`);
27537
+ const holds = pinned === undefined ? `every ${target.provider} credential here is ${phrase([...have])}` : `this target is pinned to "${pinned.label}", which is ${phrase([...have])}`;
27538
+ const fix = pinned === undefined ? "connect the other kind, or pick a model this one can reach" : "pin it to the other kind, or pick a model this account can reach";
27539
+ return new GatewayError("BAD_REQUEST", `${target.provider} serves "${target.model}" to ${phrase(reach)} credentials only, ` + `and ${holds} \u2014 ${fix}`);
26997
27540
  }
26998
27541
  return null;
26999
27542
  }
@@ -27033,14 +27576,15 @@ import { join as join3 } from "path";
27033
27576
 
27034
27577
  // packages/plugin-api/src/version.ts
27035
27578
  var PLUGIN_API_VERSION = 1;
27036
- var DASHBOARD_SDK_VERSION = "0.1.1";
27579
+ var DASHBOARD_SDK_VERSION = "0.1.2";
27037
27580
  // packages/plugin-api/src/manifest.ts
27038
27581
  var CAPABILITIES = [
27039
27582
  "storage",
27040
27583
  "files",
27041
27584
  "net:outbound",
27042
27585
  "events:request",
27043
- "events:limit"
27586
+ "events:limit",
27587
+ "channels"
27044
27588
  ];
27045
27589
  var ID_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
27046
27590
  var idSchema = exports_external.string().regex(ID_PATTERN, "id must match /^[a-z][a-z0-9-]{0,31}$/");
@@ -27465,10 +28009,10 @@ function emailFromIdToken(idToken) {
27465
28009
  if (parts.length !== 3 || payload === undefined || payload.length === 0)
27466
28010
  return null;
27467
28011
  try {
27468
- const json7 = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
27469
- if (!isRecord2(json7))
28012
+ const json8 = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
28013
+ if (!isRecord2(json8))
27470
28014
  return null;
27471
- return typeof json7.email === "string" && json7.email.trim().length > 0 ? json7.email : null;
28015
+ return typeof json8.email === "string" && json8.email.trim().length > 0 ? json8.email : null;
27472
28016
  } catch {
27473
28017
  return null;
27474
28018
  }
@@ -27871,12 +28415,12 @@ function decodeClaims(idToken) {
27871
28415
  return { email: null, accountId: null };
27872
28416
  }
27873
28417
  try {
27874
- const json7 = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
27875
- if (!isRecord5(json7))
28418
+ const json8 = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
28419
+ if (!isRecord5(json8))
27876
28420
  return { email: null, accountId: null };
27877
- const auth = json7["https://api.openai.com/auth"];
28421
+ const auth = json8["https://api.openai.com/auth"];
27878
28422
  return {
27879
- email: typeof json7.email === "string" ? json7.email : null,
28423
+ email: typeof json8.email === "string" ? json8.email : null,
27880
28424
  accountId: isRecord5(auth) ? nonBlankStringOrNull(auth.chatgpt_account_id) : null
27881
28425
  };
27882
28426
  } catch {
@@ -28214,9 +28758,11 @@ var KEY_PLACEHOLDER = "<your OmniGateway key>";
28214
28758
  async function describeModelsForSetup(store) {
28215
28759
  const models = await listModels(store);
28216
28760
  const credentials = (await listCredentials(store)).map((credential) => ({
28761
+ id: credential.id,
28217
28762
  provider: credential.provider,
28218
28763
  authType: credential.authType,
28219
- enabled: credential.enabled
28764
+ enabled: credential.enabled,
28765
+ providerData: credential.providerData
28220
28766
  }));
28221
28767
  return models.map((model) => ({
28222
28768
  model,
@@ -28252,8 +28798,7 @@ function claudeSettings(described, input, mapping, existing) {
28252
28798
  const visibleId = (slot, id) => {
28253
28799
  if (!ids.has(id))
28254
28800
  throw new Error(`${slot} names unknown virtual model "${id}"`);
28255
- const useMirror = input.discoveryMirrors === true && !/^(?:claude|anthropic)/i.test(id);
28256
- return useMirror ? `claude/${id}` : id;
28801
+ return id;
28257
28802
  };
28258
28803
  const settings = settingsObject(existing);
28259
28804
  const currentEnv = settings.env;
@@ -28362,6 +28907,43 @@ function tailFile(path, lines) {
28362
28907
  closeSync(fd);
28363
28908
  }
28364
28909
  }
28910
+ function fileSize(path) {
28911
+ try {
28912
+ const stat = statSync2(path);
28913
+ return stat.isFile() ? stat.size : null;
28914
+ } catch {
28915
+ return null;
28916
+ }
28917
+ }
28918
+ function readFrom(path, offset) {
28919
+ let fd;
28920
+ try {
28921
+ fd = openSync(path, "r");
28922
+ } catch {
28923
+ return null;
28924
+ }
28925
+ try {
28926
+ const size = fstatSync(fd).size;
28927
+ const shrank = size < offset;
28928
+ const from = shrank ? 0 : offset;
28929
+ const available = size - from;
28930
+ if (available <= 0)
28931
+ return { text: "", offset: size, gap: shrank };
28932
+ const span = Math.min(available, MAX_BYTES);
28933
+ const start = from + (available - span);
28934
+ const buffer = Buffer.allocUnsafe(span);
28935
+ const read = readSync(fd, buffer, 0, span, start);
28936
+ return {
28937
+ text: buffer.subarray(0, read).toString("utf8"),
28938
+ offset: start + read,
28939
+ gap: shrank || span < available
28940
+ };
28941
+ } catch {
28942
+ return null;
28943
+ } finally {
28944
+ closeSync(fd);
28945
+ }
28946
+ }
28365
28947
  // packages/control/src/usage.ts
28366
28948
  var MAX_LOG_LIMIT = 500;
28367
28949
  var DEFAULT_LOG_LIMIT = 100;
@@ -43479,6 +44061,15 @@ async function* openaiStream(events, requestId, created) {
43479
44061
  finish_reason: null
43480
44062
  }));
43481
44063
  }
44064
+ } else if (event.block.type === "thinking") {
44065
+ if (!roleSent) {
44066
+ roleSent = true;
44067
+ yield emit(chunk(requestId, created, model, {
44068
+ index: 0,
44069
+ delta: { role: "assistant" },
44070
+ finish_reason: null
44071
+ }));
44072
+ }
43482
44073
  } else if (event.block.type === "toolUse") {
43483
44074
  const index = toolIndex.size;
43484
44075
  toolIndex.set(event.index, index);
@@ -43510,6 +44101,12 @@ async function* openaiStream(events, requestId, created) {
43510
44101
  delta: { content: d.text },
43511
44102
  finish_reason: null
43512
44103
  }));
44104
+ } else if (d.type === "thinking") {
44105
+ yield emit(chunk(requestId, created, model, {
44106
+ index: 0,
44107
+ delta: { reasoning_content: d.text },
44108
+ finish_reason: null
44109
+ }));
43513
44110
  } else if (d.type === "toolJson") {
43514
44111
  const index = toolIndex.get(event.index) ?? 0;
43515
44112
  yield emit(chunk(requestId, created, model, {
@@ -43538,6 +44135,7 @@ async function* openaiStream(events, requestId, created) {
43538
44135
  }
43539
44136
  function openaiResponse(collected, requestId, created) {
43540
44137
  const text = collected.content.flatMap((b) => b.type === "text" ? [b.text] : []).join("");
44138
+ const reasoning = collected.content.flatMap((b) => b.type === "thinking" ? [b.text] : []).join("");
43541
44139
  const toolCalls = collected.content.flatMap((b) => b.type === "toolUse" ? [
43542
44140
  {
43543
44141
  id: b.id,
@@ -43556,6 +44154,7 @@ function openaiResponse(collected, requestId, created) {
43556
44154
  message: {
43557
44155
  role: "assistant",
43558
44156
  content: toolCalls.length > 0 && text.length === 0 ? null : text,
44157
+ ...reasoning.length > 0 ? { reasoning_content: reasoning } : {},
43559
44158
  ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
43560
44159
  },
43561
44160
  finish_reason: FINISH3[collected.stopReason]
@@ -43956,6 +44555,7 @@ function createQuiesceLatch() {
43956
44555
  // apps/gateway/src/routes/admin.ts
43957
44556
  function adminRoutes(deps) {
43958
44557
  const logger2 = deps.logger ?? noopLogger;
44558
+ const changed = (topic) => deps.broadcaster?.invalidate(topic);
43959
44559
  return new Elysia().onError(apiErrorHandler).get("/api/status", async ({ request: request2 }) => {
43960
44560
  const token = readCookie(request2, ADMIN_COOKIE);
43961
44561
  return {
@@ -44015,9 +44615,9 @@ function adminRoutes(deps) {
44015
44615
  const body2 = await readJsonRecord(request2);
44016
44616
  if (body2 === null)
44017
44617
  throw new GatewayError("BAD_REQUEST", "credential body is required");
44018
- return {
44019
- credential: await createApiKeyCredential(deps.store, { provider: body2.provider, apiKey: body2.apiKey, ...body2 }, logger2)
44020
- };
44618
+ const credential = await createApiKeyCredential(deps.store, { provider: body2.provider, apiKey: body2.apiKey, ...body2 }, logger2);
44619
+ changed("res:credentials");
44620
+ return { credential };
44021
44621
  }).get("/api/credentials/health", async ({ request: request2 }) => {
44022
44622
  await requireAdmin(request2, deps.admin);
44023
44623
  return credentialHealth(deps);
@@ -44031,10 +44631,12 @@ function adminRoutes(deps) {
44031
44631
  }).patch("/api/credentials/:id", async ({ request: request2, params }) => {
44032
44632
  await requireAdmin(request2, deps.admin);
44033
44633
  await patchCredential(deps, params.id, await readJson(request2));
44634
+ changed("res:credentials");
44034
44635
  return { ok: true };
44035
44636
  }).delete("/api/credentials/:id", async ({ request: request2, params }) => {
44036
44637
  await requireAdmin(request2, deps.admin);
44037
44638
  await removeCredential(deps.store, params.id);
44639
+ changed("res:credentials");
44038
44640
  return { ok: true };
44039
44641
  }).get("/api/models", async ({ request: request2 }) => {
44040
44642
  await requireAdmin(request2, deps.admin);
@@ -44042,10 +44644,12 @@ function adminRoutes(deps) {
44042
44644
  }).put("/api/models/:id", async ({ request: request2, params }) => {
44043
44645
  await requireAdmin(request2, deps.admin);
44044
44646
  await putModel(deps.store, params.id, await readJson(request2));
44647
+ changed("res:models");
44045
44648
  return { ok: true };
44046
44649
  }).delete("/api/models/:id", async ({ request: request2, params }) => {
44047
44650
  await requireAdmin(request2, deps.admin);
44048
44651
  await removeModel(deps.store, params.id);
44652
+ changed("res:models");
44049
44653
  return { ok: true };
44050
44654
  }).get("/api/agent-setup", async ({ request: request2, query }) => {
44051
44655
  await requireAdmin(request2, deps.admin);
@@ -44057,10 +44661,7 @@ function adminRoutes(deps) {
44057
44661
  try {
44058
44662
  return {
44059
44663
  client,
44060
- files: await setupFiles(deps.store, client, {
44061
- baseUrl: deps.baseUrl,
44062
- discoveryMirrors: deps.discoveryMirrors === true
44063
- }, {
44664
+ files: await setupFiles(deps.store, client, { baseUrl: deps.baseUrl }, {
44064
44665
  defaultModel,
44065
44666
  ...query.fableModel ? { fableModel: query.fableModel } : {},
44066
44667
  ...query.opusModel ? { opusModel: query.opusModel } : {},
@@ -44076,13 +44677,23 @@ function adminRoutes(deps) {
44076
44677
  return { keys: await listKeys(deps.store) };
44077
44678
  }).post("/api/keys", async ({ request: request2 }) => {
44078
44679
  await requireAdmin(request2, deps.admin);
44079
- return createKey(deps.store, await readJson(request2));
44680
+ const created = await createKey(deps.store, await readJson(request2));
44681
+ changed("res:keys");
44682
+ return created;
44080
44683
  }).put("/api/keys/:id/limits", async ({ request: request2, params }) => {
44081
44684
  await requireAdmin(request2, deps.admin);
44082
- return setKeyLimits(deps.store, params.id, await readJson(request2));
44685
+ const key = await setKeyLimits(deps.store, params.id, await readJson(request2));
44686
+ changed("res:keys");
44687
+ return key;
44688
+ }).put("/api/keys/:id/models", async ({ request: request2, params }) => {
44689
+ await requireAdmin(request2, deps.admin);
44690
+ const key = await setKeyModels(deps.store, params.id, await readJson(request2));
44691
+ changed("res:keys");
44692
+ return key;
44083
44693
  }).delete("/api/keys/:id", async ({ request: request2, params }) => {
44084
44694
  await requireAdmin(request2, deps.admin);
44085
44695
  await revokeKey(deps.store, params.id);
44696
+ changed("res:keys");
44086
44697
  return { ok: true };
44087
44698
  }).get("/api/settings", async ({ request: request2 }) => {
44088
44699
  await requireAdmin(request2, deps.admin);
@@ -44093,6 +44704,7 @@ function adminRoutes(deps) {
44093
44704
  }).put("/api/settings", async ({ request: request2 }) => {
44094
44705
  await requireAdmin(request2, deps.admin);
44095
44706
  await putSettings(deps.store, await readJson(request2));
44707
+ changed("res:settings");
44096
44708
  return { ok: true };
44097
44709
  }).post("/api/models/:id/dry-run", async ({ request: request2, params }) => {
44098
44710
  await requireAdmin(request2, deps.admin);
@@ -44177,6 +44789,7 @@ async function swap(deps, logger2, label2, operation) {
44177
44789
  reason: label2
44178
44790
  });
44179
44791
  }
44792
+ deps.broadcaster?.invalidateAll();
44180
44793
  return result;
44181
44794
  } catch (error51) {
44182
44795
  if (error51 instanceof SwapFailedError) {
@@ -46341,24 +46954,44 @@ function report(logger2, what, requestId, error51) {
46341
46954
  reason: describeError(error51, "unknown")
46342
46955
  });
46343
46956
  }
46344
- async function beginLog(store, log, keyId, logger2 = noopLogger) {
46957
+ async function beginLog(store, log, keyId, logger2 = noopLogger, broadcast) {
46958
+ let began = false;
46345
46959
  try {
46346
46960
  await store.usage.begin({ ...log, state: "pending", apiKeyId: keyId });
46961
+ began = true;
46347
46962
  } catch (error51) {
46348
46963
  report(logger2, "failed to record request start", log.id, error51);
46349
46964
  }
46965
+ if (began && broadcast !== undefined) {
46966
+ try {
46967
+ broadcast.invalidate("res:logs");
46968
+ } catch (error51) {
46969
+ report(logger2, "failed to publish a resource invalidation", log.id, error51);
46970
+ }
46971
+ }
46350
46972
  }
46351
- async function routeLog(store, requestId, target, logger2 = noopLogger) {
46973
+ async function routeLog(store, requestId, target, logger2 = noopLogger, broadcast) {
46974
+ let routed = false;
46352
46975
  try {
46353
46976
  await store.usage.route(requestId, target);
46977
+ routed = true;
46354
46978
  } catch (error51) {
46355
46979
  report(logger2, "failed to record request route", requestId, error51);
46356
46980
  }
46981
+ if (routed && broadcast !== undefined) {
46982
+ try {
46983
+ broadcast.invalidate("res:logs");
46984
+ } catch (error51) {
46985
+ report(logger2, "failed to publish a resource invalidation", requestId, error51);
46986
+ }
46987
+ }
46357
46988
  }
46358
- async function finishLog(store, log, keyId, logger2 = noopLogger, bodies, debit, emit) {
46989
+ async function finishLog(store, log, keyId, logger2 = noopLogger, bodies, debit, emit, broadcast) {
46990
+ let appended = true;
46359
46991
  try {
46360
46992
  await store.usage.append({ ...log, apiKeyId: keyId });
46361
46993
  } catch (error51) {
46994
+ appended = false;
46362
46995
  report(logger2, "failed to persist request log", log.id, error51);
46363
46996
  }
46364
46997
  if (keyId !== null && debit !== undefined) {
@@ -46389,6 +47022,14 @@ async function finishLog(store, log, keyId, logger2 = noopLogger, bodies, debit,
46389
47022
  report(logger2, "failed to emit plugin event", log.id, error51);
46390
47023
  }
46391
47024
  }
47025
+ if (appended && broadcast !== undefined) {
47026
+ try {
47027
+ broadcast.invalidate("res:usage");
47028
+ broadcast.invalidate("res:logs");
47029
+ } catch (error51) {
47030
+ report(logger2, "failed to publish a resource invalidation", log.id, error51);
47031
+ }
47032
+ }
46392
47033
  if (bodies === undefined)
46393
47034
  return;
46394
47035
  try {
@@ -47115,7 +47756,6 @@ function mcpServerNames(body2) {
47115
47756
  }
47116
47757
 
47117
47758
  // apps/gateway/src/ingress/model.ts
47118
- var DISCOVERY_PREFIX = "claude/";
47119
47759
  var ONE_M_SUFFIX2 = "[1m]";
47120
47760
  function normalizeClientModel(raw, betas2 = []) {
47121
47761
  let model = raw.trim();
@@ -47127,11 +47767,6 @@ function normalizeClientModel(raw, betas2 = []) {
47127
47767
  wantsOneM = true;
47128
47768
  }
47129
47769
  }
47130
- if (model.toLowerCase().startsWith(DISCOVERY_PREFIX)) {
47131
- const stripped = model.slice(DISCOVERY_PREFIX.length);
47132
- if (stripped.length > 0)
47133
- model = stripped;
47134
- }
47135
47770
  const merged = [...betas2];
47136
47771
  if (wantsOneM && !merged.includes(CONTEXT_1M_BETA))
47137
47772
  merged.push(CONTEXT_1M_BETA);
@@ -47470,7 +48105,7 @@ function readBlock(raw, role, path) {
47470
48105
  function toIrToolChoice(c) {
47471
48106
  return c.type === "tool" ? { type: "tool", name: c.name } : { type: c.type };
47472
48107
  }
47473
- var EFFORTS = ["low", "medium", "high", "xhigh", "max"];
48108
+ var EFFORTS = REASONING_EFFORTS;
47474
48109
  function readEffort(body2) {
47475
48110
  if (!isRecord6(body2))
47476
48111
  return;
@@ -47627,7 +48262,7 @@ var schema2 = exports_external.object({
47627
48262
  exports_external.enum(["auto", "none", "required"]),
47628
48263
  exports_external.object({ type: exports_external.literal("function"), function: exports_external.object({ name: exports_external.string() }) })
47629
48264
  ]).optional(),
47630
- reasoning_effort: exports_external.enum(["low", "medium", "high"]).optional()
48265
+ reasoning_effort: exports_external.enum(REASONING_EFFORTS).optional()
47631
48266
  });
47632
48267
  var KNOWN2 = [
47633
48268
  "model",
@@ -47778,29 +48413,8 @@ function describeModel(model, credentials) {
47778
48413
  ...limits.maxOutputTokens === undefined ? {} : { max_tokens: limits.maxOutputTokens }
47779
48414
  };
47780
48415
  }
47781
- var ALREADY_CLAUDE = /^(?:claude|anthropic)/i;
47782
- var MIRROR_PREFIX = "claude/";
47783
- function discoveryMirrors(data) {
47784
- const taken = new Set(data.map((entry) => entry.id));
47785
- const mirrors = [];
47786
- for (const entry of data) {
47787
- if (ALREADY_CLAUDE.test(entry.id))
47788
- continue;
47789
- const id = `${MIRROR_PREFIX}${entry.id}`;
47790
- if (taken.has(id))
47791
- continue;
47792
- mirrors.push({
47793
- ...entry,
47794
- id,
47795
- root: entry.id,
47796
- display_name: `${entry.display_name} (OmniGateway)`
47797
- });
47798
- }
47799
- return mirrors;
47800
- }
47801
- function modelListBody(models, credentials, options = {}) {
47802
- const described = models.map((model) => describeModel(model, credentials));
47803
- const data = options.discoveryMirrors === true ? [...described, ...discoveryMirrors(described)] : described;
48416
+ function modelListBody(models, credentials) {
48417
+ const data = models.map((model) => describeModel(model, credentials));
47804
48418
  return {
47805
48419
  object: "list",
47806
48420
  data,
@@ -48000,7 +48614,7 @@ async function handle(deps, rateLimiter, surface, request2) {
48000
48614
  ...captured === null ? {} : { http: captured.wrap(deps.http) },
48001
48615
  async onRoute(target) {
48002
48616
  if (began) {
48003
- await routeLog(deps.store, requestId, target, deps.logger);
48617
+ await routeLog(deps.store, requestId, target, deps.logger, deps.broadcaster);
48004
48618
  return;
48005
48619
  }
48006
48620
  began = true;
@@ -48012,7 +48626,7 @@ async function handle(deps, rateLimiter, surface, request2) {
48012
48626
  resolvedModel: target.model,
48013
48627
  credentialId: target.credentialId
48014
48628
  });
48015
- await beginLog(deps.store, log2, keyId, deps.logger);
48629
+ await beginLog(deps.store, log2, keyId, deps.logger, deps.broadcaster);
48016
48630
  }
48017
48631
  }, request2.signal, requestId);
48018
48632
  outcome = dispatched;
@@ -48035,7 +48649,7 @@ async function handle(deps, rateLimiter, surface, request2) {
48035
48649
  reportRejection(deps.logger, requestId, completed, gatewayError, surface);
48036
48650
  }
48037
48651
  logged = true;
48038
- await finishLog(deps.store, completed, keyId, deps.logger, writeBodies, debit, deps.emit);
48652
+ await finishLog(deps.store, completed, keyId, deps.logger, writeBodies, debit, deps.emit, deps.broadcaster);
48039
48653
  };
48040
48654
  if (chatRequest.stream) {
48041
48655
  const frames = surface === "anthropic" ? anthropicStream(dispatched.events, requestId) : openaiStream(dispatched.events, requestId, Math.floor(deps.now() / 1000));
@@ -48076,7 +48690,7 @@ async function handle(deps, rateLimiter, surface, request2) {
48076
48690
  if (collector !== null && !logged)
48077
48691
  collector.client.response = rejection;
48078
48692
  if (!logged)
48079
- await finishLog(deps.store, completed, keyId, deps.logger, writeBodies, debit, deps.emit);
48693
+ await finishLog(deps.store, completed, keyId, deps.logger, writeBodies, debit, deps.emit, deps.broadcaster);
48080
48694
  if (!cancelled)
48081
48695
  reportRejection(deps.logger, requestId, completed, gatewayError, surface);
48082
48696
  return jsonResponse(rejection, HTTP_STATUS[gatewayError.code], {
@@ -48110,9 +48724,7 @@ function proxyRoutes(deps) {
48110
48724
  const snapshot = await dispatchDeps.snapshots.get(deps.now());
48111
48725
  const models = [...snapshot.models.values()];
48112
48726
  const visibleModels = key.modelAllowlist === null ? models : models.filter((model) => key.modelAllowlist?.includes(model.id));
48113
- return Response.json(modelListBody(visibleModels, snapshot.credentials, {
48114
- discoveryMirrors: deps.discoveryMirrors === true
48115
- }));
48727
+ return Response.json(modelListBody(visibleModels, snapshot.credentials));
48116
48728
  } catch (error51) {
48117
48729
  const gatewayError = asGatewayError(error51);
48118
48730
  logger2.error("model listing failed", {
@@ -48152,6 +48764,684 @@ function proxyRoutes(deps) {
48152
48764
  });
48153
48765
  }
48154
48766
 
48767
+ // apps/gateway/src/stream/broadcaster.ts
48768
+ var INVALIDATION_FLOORS = {
48769
+ "res:usage": 1000,
48770
+ "res:logs": 1000,
48771
+ "res:quota": 5000,
48772
+ "res:credentials": 5000
48773
+ };
48774
+ var DEFAULT_FLOOR_MS = 1000;
48775
+ var GLOBAL_INVALIDATE = "res:*";
48776
+ function createBroadcaster(deps) {
48777
+ const streams = new Set;
48778
+ return {
48779
+ invalidate(topic, keys) {
48780
+ deps.coalescer.emit(topic, keys === undefined ? undefined : { keys });
48781
+ },
48782
+ invalidateAll() {
48783
+ deps.registry.publish(GLOBAL_INVALIDATE, {
48784
+ type: "event",
48785
+ topic: GLOBAL_INVALIDATE
48786
+ });
48787
+ },
48788
+ declareStream(topic) {
48789
+ streams.add(topic);
48790
+ },
48791
+ declared(topic) {
48792
+ return streams.has(topic);
48793
+ },
48794
+ stream(topic, payload) {
48795
+ const seq = deps.ring.push(topic, payload);
48796
+ deps.registry.publish(topic, { type: "event", topic, seq, payload });
48797
+ },
48798
+ resetStream(topic) {
48799
+ deps.ring.reset(topic);
48800
+ },
48801
+ stop() {
48802
+ deps.coalescer.stop();
48803
+ }
48804
+ };
48805
+ }
48806
+
48807
+ // apps/gateway/src/stream/protocol.ts
48808
+ function topicClass(topic) {
48809
+ if (topic.startsWith("res:") && topic.length > 4)
48810
+ return "res";
48811
+ if (topic.startsWith("stream:") && topic.length > 7)
48812
+ return "stream";
48813
+ if (topic.startsWith("plugin:")) {
48814
+ const rest = topic.slice(7);
48815
+ const colon = rest.indexOf(":");
48816
+ return colon > 0 && colon < rest.length - 1 ? "plugin" : null;
48817
+ }
48818
+ return null;
48819
+ }
48820
+ var MAX_TOPIC = 128;
48821
+ function isRecord7(value) {
48822
+ return typeof value === "object" && value !== null && !Array.isArray(value);
48823
+ }
48824
+ function parseClientFrame(raw) {
48825
+ if (!isRecord7(raw))
48826
+ return null;
48827
+ const { id, type, topic } = raw;
48828
+ if (id !== undefined && typeof id !== "string")
48829
+ return null;
48830
+ if (typeof topic !== "string" || topic.length === 0 || topic.length > MAX_TOPIC)
48831
+ return null;
48832
+ if (topicClass(topic) === null)
48833
+ return null;
48834
+ const head = id === undefined ? { topic } : { id, topic };
48835
+ if (type === "unsubscribe")
48836
+ return { ...head, type: "unsubscribe" };
48837
+ if (type === "send") {
48838
+ return "payload" in raw ? { ...head, type: "send", payload: raw.payload } : { ...head, type: "send" };
48839
+ }
48840
+ if (type === "subscribe") {
48841
+ const { sinceSeq } = raw;
48842
+ if (sinceSeq === undefined)
48843
+ return { ...head, type: "subscribe" };
48844
+ if (typeof sinceSeq !== "number" || !Number.isInteger(sinceSeq) || sinceSeq < 0)
48845
+ return null;
48846
+ return { ...head, type: "subscribe", sinceSeq };
48847
+ }
48848
+ return null;
48849
+ }
48850
+
48851
+ // apps/gateway/src/routes/stream.ts
48852
+ function authorised(channels, principal, topic) {
48853
+ const kind = topicClass(topic);
48854
+ if (kind === null)
48855
+ return false;
48856
+ if (kind === "plugin") {
48857
+ if (!channels.opened(topic))
48858
+ return false;
48859
+ if (principal.kind === "admin")
48860
+ return true;
48861
+ return topic.startsWith(`plugin:${principal.pluginId}:`);
48862
+ }
48863
+ return principal.kind === "admin";
48864
+ }
48865
+ function streamRoutes(deps) {
48866
+ const logger2 = deps.logger ?? noopLogger;
48867
+ const nextId = deps.connectionId ?? (() => `ws_${crypto.randomUUID()}`);
48868
+ const resolved = new WeakMap;
48869
+ const ids = new WeakMap;
48870
+ const send = (ws, frame2) => {
48871
+ ws.send(JSON.stringify(frame2));
48872
+ };
48873
+ return new Elysia().onError(apiErrorHandler).ws("/api/stream", {
48874
+ beforeHandle: async ({ request: request2 }) => {
48875
+ if (resolved.has(request2))
48876
+ return;
48877
+ const bearer = request2.headers.get("authorization");
48878
+ const cookie = readCookie(request2, ADMIN_COOKIE);
48879
+ if (bearer !== null && cookie !== null) {
48880
+ throw new GatewayError("AUTH", "present one credential, not two");
48881
+ }
48882
+ await requireAdmin(request2, deps.admin);
48883
+ if (cookie === null)
48884
+ throw new GatewayError("AUTH", "admin session required");
48885
+ resolved.set(request2, {
48886
+ principal: { kind: "admin" },
48887
+ revalidate: () => deps.admin.verify(cookie)
48888
+ });
48889
+ },
48890
+ open(ws) {
48891
+ const credential = resolved.get(ws.data.request);
48892
+ if (credential === undefined) {
48893
+ ws.close(1011, "unauthenticated");
48894
+ return;
48895
+ }
48896
+ const id = nextId();
48897
+ ids.set(ws.raw, id);
48898
+ deps.registry.add(id, ws.raw, credential);
48899
+ deps.registry.subscribe(id, GLOBAL_INVALIDATE);
48900
+ },
48901
+ message(ws, raw) {
48902
+ const id = ids.get(ws.raw);
48903
+ if (id === undefined)
48904
+ return;
48905
+ const frame2 = parseClientFrame(raw);
48906
+ if (frame2 === null) {
48907
+ send(ws, { type: "error", message: "malformed frame" });
48908
+ return;
48909
+ }
48910
+ const principal = deps.registry.principal(id);
48911
+ if (principal === null)
48912
+ return;
48913
+ const head = frame2.id === undefined ? {} : { id: frame2.id };
48914
+ if (!authorised(deps.channels, principal, frame2.topic)) {
48915
+ send(ws, { ...head, type: "error", topic: frame2.topic, message: "not permitted" });
48916
+ return;
48917
+ }
48918
+ if (frame2.type === "unsubscribe") {
48919
+ deps.registry.unsubscribe(id, frame2.topic);
48920
+ send(ws, { ...head, type: "ack", topic: frame2.topic });
48921
+ return;
48922
+ }
48923
+ if (frame2.type === "send") {
48924
+ if (topicClass(frame2.topic) !== "plugin") {
48925
+ send(ws, { ...head, type: "error", topic: frame2.topic, message: "topic is read-only" });
48926
+ return;
48927
+ }
48928
+ if (!deps.channels.deliver(frame2.topic, id, frame2.payload)) {
48929
+ send(ws, {
48930
+ ...head,
48931
+ type: "error",
48932
+ topic: frame2.topic,
48933
+ message: "subscribe before sending"
48934
+ });
48935
+ return;
48936
+ }
48937
+ send(ws, { ...head, type: "ack", topic: frame2.topic });
48938
+ return;
48939
+ }
48940
+ if (topicClass(frame2.topic) === "stream" && !deps.broadcaster.declared(frame2.topic)) {
48941
+ send(ws, { ...head, type: "error", topic: frame2.topic, message: "no source" });
48942
+ return;
48943
+ }
48944
+ deps.registry.subscribe(id, frame2.topic);
48945
+ send(ws, { ...head, type: "ack", topic: frame2.topic });
48946
+ if (frame2.sinceSeq !== undefined) {
48947
+ const slice = deps.ring.since(frame2.topic, frame2.sinceSeq);
48948
+ if (slice.kind === "gap") {
48949
+ send(ws, { type: "gap", topic: frame2.topic, seq: slice.seq });
48950
+ } else {
48951
+ for (const item of slice.frames) {
48952
+ send(ws, { type: "event", topic: frame2.topic, seq: item.seq, payload: item.payload });
48953
+ }
48954
+ }
48955
+ }
48956
+ },
48957
+ pong(ws) {
48958
+ const id = ids.get(ws.raw);
48959
+ if (id !== undefined)
48960
+ deps.registry.pong(id);
48961
+ },
48962
+ drain(ws) {
48963
+ const id = ids.get(ws.raw);
48964
+ if (id !== undefined)
48965
+ deps.registry.drain(id);
48966
+ },
48967
+ close(ws) {
48968
+ const id = ids.get(ws.raw);
48969
+ if (id === undefined)
48970
+ return;
48971
+ deps.channels.closed(id, deps.registry.topics(id));
48972
+ deps.registry.remove(id);
48973
+ ids.delete(ws.raw);
48974
+ logger2.debug("stream closed");
48975
+ }
48976
+ }).get("/api/stream", ({ set: set2 }) => {
48977
+ set2.status = 426;
48978
+ return { error: { code: "BAD_REQUEST", message: "websocket upgrade required" } };
48979
+ });
48980
+ }
48981
+
48982
+ // apps/gateway/src/stream/channels.ts
48983
+ var NAME_PATTERN = /^[a-z0-9][a-z0-9:._-]{0,63}$/;
48984
+ var defaultScheduler = (run) => {
48985
+ const timer = setTimeout(run, 0);
48986
+ timer.unref?.();
48987
+ return () => clearTimeout(timer);
48988
+ };
48989
+ function createChannelRegistry(deps) {
48990
+ const logger2 = deps.logger ?? noopLogger;
48991
+ const scheduler = deps.scheduler ?? defaultScheduler;
48992
+ const channels = new Map;
48993
+ let handlerErrors = 0;
48994
+ let live = true;
48995
+ let cancelReport;
48996
+ const errorsSinceReport = new Map;
48997
+ const report2 = () => {
48998
+ cancelReport = undefined;
48999
+ if (!live)
49000
+ return;
49001
+ for (const [pluginId, count] of errorsSinceReport) {
49002
+ logger2.warn("plugin channel handler failed", { plugin: pluginId, count });
49003
+ }
49004
+ errorsSinceReport.clear();
49005
+ };
49006
+ const countFailure = (pluginId) => {
49007
+ handlerErrors++;
49008
+ errorsSinceReport.set(pluginId, (errorsSinceReport.get(pluginId) ?? 0) + 1);
49009
+ if (cancelReport !== undefined || !live)
49010
+ return;
49011
+ cancelReport = scheduler(report2);
49012
+ };
49013
+ const holds = (connectionId, topic) => deps.sockets.has(connectionId, topic);
49014
+ const openChannel = (pluginId, name) => {
49015
+ if (!NAME_PATTERN.test(name)) {
49016
+ throw new Error(`channel name must match ${String(NAME_PATTERN)}, got ${name}`);
49017
+ }
49018
+ const topic = `plugin:${pluginId}:${name}`;
49019
+ const existing = channels.get(topic);
49020
+ if (existing !== undefined)
49021
+ return existing.facade;
49022
+ const channel = {
49023
+ pluginId,
49024
+ topic,
49025
+ onMessage: [],
49026
+ onClose: [],
49027
+ facade: { onMessage: () => {}, send: () => {}, onClose: () => {} }
49028
+ };
49029
+ channel.facade = {
49030
+ onMessage(handler) {
49031
+ channel.onMessage.push(handler);
49032
+ },
49033
+ onClose(handler) {
49034
+ channel.onClose.push(handler);
49035
+ },
49036
+ send(connectionId, payload) {
49037
+ if (!live)
49038
+ return;
49039
+ if (!holds(connectionId, topic))
49040
+ return;
49041
+ deps.sockets.sendTo(connectionId, { type: "event", topic, payload });
49042
+ }
49043
+ };
49044
+ channels.set(topic, channel);
49045
+ return channel.facade;
49046
+ };
49047
+ return {
49048
+ for(pluginId) {
49049
+ return { open: (name) => openChannel(pluginId, name) };
49050
+ },
49051
+ opened(topic) {
49052
+ return channels.has(topic);
49053
+ },
49054
+ deliver(topic, connectionId, payload) {
49055
+ if (!live)
49056
+ return false;
49057
+ const channel = channels.get(topic);
49058
+ if (channel === undefined)
49059
+ return false;
49060
+ if (!holds(connectionId, topic))
49061
+ return false;
49062
+ for (const handler of channel.onMessage) {
49063
+ try {
49064
+ handler({ connectionId, payload });
49065
+ } catch {
49066
+ countFailure(channel.pluginId);
49067
+ }
49068
+ }
49069
+ return true;
49070
+ },
49071
+ closed(connectionId, topics) {
49072
+ if (!live)
49073
+ return;
49074
+ for (const topic of topics) {
49075
+ const channel = channels.get(topic);
49076
+ if (channel === undefined)
49077
+ continue;
49078
+ for (const handler of channel.onClose) {
49079
+ try {
49080
+ handler(connectionId);
49081
+ } catch {
49082
+ countFailure(channel.pluginId);
49083
+ }
49084
+ }
49085
+ }
49086
+ },
49087
+ stats() {
49088
+ return { channels: channels.size, handlerErrors };
49089
+ },
49090
+ stop() {
49091
+ live = false;
49092
+ channels.clear();
49093
+ cancelReport?.();
49094
+ cancelReport = undefined;
49095
+ errorsSinceReport.clear();
49096
+ }
49097
+ };
49098
+ }
49099
+
49100
+ // apps/gateway/src/stream/coalescer.ts
49101
+ var defaultSchedule = (run, ms) => {
49102
+ const timer = setTimeout(run, ms);
49103
+ return () => clearTimeout(timer);
49104
+ };
49105
+ function createCoalescer(deps) {
49106
+ const now = deps.now ?? Date.now;
49107
+ const schedule = deps.schedule ?? defaultSchedule;
49108
+ const lastSent = new Map;
49109
+ const pending = new Map;
49110
+ const floorFor = (topic) => deps.floors[topic] ?? deps.defaultFloorMs;
49111
+ const send = (topic, payload) => {
49112
+ lastSent.set(topic, now());
49113
+ deps.sink(topic, payload);
49114
+ };
49115
+ const fire = (topic) => {
49116
+ const item = pending.get(topic);
49117
+ if (item === undefined)
49118
+ return;
49119
+ pending.delete(topic);
49120
+ send(topic, item.payload);
49121
+ };
49122
+ return {
49123
+ emit(topic, payload) {
49124
+ const floor = floorFor(topic);
49125
+ const previous = lastSent.get(topic);
49126
+ const elapsed = previous === undefined ? Number.POSITIVE_INFINITY : now() - previous;
49127
+ const waiting = pending.get(topic);
49128
+ if (waiting !== undefined) {
49129
+ waiting.payload = payload;
49130
+ return;
49131
+ }
49132
+ if (elapsed >= floor) {
49133
+ send(topic, payload);
49134
+ return;
49135
+ }
49136
+ const cancel = schedule(() => fire(topic), floor - elapsed);
49137
+ pending.set(topic, { payload, cancel });
49138
+ },
49139
+ flush() {
49140
+ for (const [topic, item] of [...pending]) {
49141
+ item.cancel();
49142
+ pending.delete(topic);
49143
+ send(topic, item.payload);
49144
+ }
49145
+ },
49146
+ stop() {
49147
+ for (const item of pending.values())
49148
+ item.cancel();
49149
+ pending.clear();
49150
+ lastSent.clear();
49151
+ }
49152
+ };
49153
+ }
49154
+
49155
+ // apps/gateway/src/stream/registry.ts
49156
+ var DEFAULT_QUEUE_CAPACITY = 1000;
49157
+ var MAX_TOPICS_PER_CONNECTION = 256;
49158
+ var HIGH_WATER_BYTES = 512 * 1024;
49159
+ var HEARTBEAT_MS = 20000;
49160
+ var PONG_DEADLINE_MS = 60000;
49161
+ var CHECK_STALE_MS = 60000;
49162
+ var CLOSE_UNAUTHENTICATED = 4401;
49163
+ function createSocketRegistry(deps = {}) {
49164
+ const logger2 = deps.logger ?? noopLogger;
49165
+ const onDetach = deps.onDetach;
49166
+ const now = deps.now ?? Date.now;
49167
+ const schedule = deps.schedule ?? ((run, ms) => {
49168
+ const timer = setTimeout(run, ms);
49169
+ timer.unref?.();
49170
+ return () => clearTimeout(timer);
49171
+ });
49172
+ const capacity = deps.queueCapacity ?? DEFAULT_QUEUE_CAPACITY;
49173
+ const heartbeatMs = deps.heartbeatMs ?? HEARTBEAT_MS;
49174
+ const pongDeadlineMs = deps.pongDeadlineMs ?? PONG_DEADLINE_MS;
49175
+ const checkStaleMs = deps.checkStaleMs ?? CHECK_STALE_MS;
49176
+ const connections = new Map;
49177
+ const index = new Map;
49178
+ let dropped = 0;
49179
+ let live = true;
49180
+ let cancelTick;
49181
+ let droppedSinceReport = 0;
49182
+ const flush = (connection) => {
49183
+ while (connection.queue.length > 0) {
49184
+ if ((connection.socket.getBufferedAmount?.() ?? 0) >= HIGH_WATER_BYTES)
49185
+ return;
49186
+ const frame2 = connection.queue[0];
49187
+ if (frame2 === undefined)
49188
+ break;
49189
+ let status2;
49190
+ try {
49191
+ status2 = connection.socket.send(JSON.stringify(frame2));
49192
+ } catch {
49193
+ return;
49194
+ }
49195
+ if (status2 === 0)
49196
+ return;
49197
+ connection.queue.shift();
49198
+ }
49199
+ };
49200
+ const deliver = (connection, frame2) => {
49201
+ if (connection.queue.length >= capacity) {
49202
+ connection.queue.shift();
49203
+ dropped++;
49204
+ droppedSinceReport++;
49205
+ }
49206
+ connection.queue.push(frame2);
49207
+ flush(connection);
49208
+ };
49209
+ const detach = (connection) => {
49210
+ for (const topic of connection.topics) {
49211
+ const subscribers = index.get(topic);
49212
+ if (subscribers === undefined)
49213
+ continue;
49214
+ subscribers.delete(connection.id);
49215
+ if (subscribers.size === 0)
49216
+ index.delete(topic);
49217
+ }
49218
+ connections.delete(connection.id);
49219
+ };
49220
+ const closeOne = (connection, code, reason) => {
49221
+ onDetach?.(connection.id, [...connection.topics]);
49222
+ detach(connection);
49223
+ try {
49224
+ connection.socket.close(code, reason);
49225
+ } catch {}
49226
+ };
49227
+ const tick = () => {
49228
+ cancelTick = undefined;
49229
+ if (!live)
49230
+ return;
49231
+ const at = now();
49232
+ for (const connection of [...connections.values()]) {
49233
+ if (at - connection.lastPongAt > pongDeadlineMs) {
49234
+ closeOne(connection, 1001, "pong deadline");
49235
+ continue;
49236
+ }
49237
+ try {
49238
+ connection.socket.ping?.();
49239
+ } catch {
49240
+ closeOne(connection, 1001, "ping failed");
49241
+ continue;
49242
+ }
49243
+ if (connection.checking) {
49244
+ if (at - connection.checkingSince < checkStaleMs)
49245
+ continue;
49246
+ connection.generation += 1;
49247
+ connection.checking = false;
49248
+ }
49249
+ connection.checking = true;
49250
+ connection.checkingSince = at;
49251
+ const generation = connection.generation;
49252
+ connection.credential.revalidate().then((valid) => {
49253
+ if (connection.generation !== generation)
49254
+ return;
49255
+ connection.checking = false;
49256
+ if (!valid && connections.has(connection.id)) {
49257
+ closeOne(connection, CLOSE_UNAUTHENTICATED, "session expired");
49258
+ }
49259
+ }).catch(() => {
49260
+ if (connection.generation !== generation)
49261
+ return;
49262
+ connection.checking = false;
49263
+ });
49264
+ }
49265
+ if (droppedSinceReport > 0) {
49266
+ logger2.warn("stream queue overflowed", { count: droppedSinceReport });
49267
+ droppedSinceReport = 0;
49268
+ }
49269
+ arm();
49270
+ };
49271
+ const arm = () => {
49272
+ if (!live || cancelTick !== undefined)
49273
+ return;
49274
+ cancelTick = schedule(tick, heartbeatMs);
49275
+ };
49276
+ arm();
49277
+ return {
49278
+ add(id, socket, credential) {
49279
+ if (!live) {
49280
+ socket.close(1001, "shutting down");
49281
+ return;
49282
+ }
49283
+ connections.set(id, {
49284
+ id,
49285
+ socket,
49286
+ credential,
49287
+ topics: new Set,
49288
+ queue: [],
49289
+ lastPongAt: now(),
49290
+ checking: false,
49291
+ checkingSince: 0,
49292
+ generation: 0
49293
+ });
49294
+ },
49295
+ remove(id) {
49296
+ const connection = connections.get(id);
49297
+ if (connection !== undefined)
49298
+ detach(connection);
49299
+ },
49300
+ subscribe(id, topic) {
49301
+ const connection = connections.get(id);
49302
+ if (connection === undefined)
49303
+ return;
49304
+ if (connection.topics.size >= MAX_TOPICS_PER_CONNECTION && !connection.topics.has(topic)) {
49305
+ return;
49306
+ }
49307
+ connection.topics.add(topic);
49308
+ const subscribers = index.get(topic) ?? new Set;
49309
+ subscribers.add(id);
49310
+ index.set(topic, subscribers);
49311
+ },
49312
+ unsubscribe(id, topic) {
49313
+ const connection = connections.get(id);
49314
+ if (connection === undefined)
49315
+ return;
49316
+ connection.topics.delete(topic);
49317
+ const subscribers = index.get(topic);
49318
+ if (subscribers === undefined)
49319
+ return;
49320
+ subscribers.delete(id);
49321
+ if (subscribers.size === 0)
49322
+ index.delete(topic);
49323
+ },
49324
+ topics(id) {
49325
+ return [...connections.get(id)?.topics ?? []];
49326
+ },
49327
+ has(id, topic) {
49328
+ return connections.get(id)?.topics.has(topic) ?? false;
49329
+ },
49330
+ principal(id) {
49331
+ return connections.get(id)?.credential.principal ?? null;
49332
+ },
49333
+ pong(id) {
49334
+ const connection = connections.get(id);
49335
+ if (connection !== undefined)
49336
+ connection.lastPongAt = now();
49337
+ },
49338
+ drain(id) {
49339
+ const connection = connections.get(id);
49340
+ if (connection !== undefined)
49341
+ flush(connection);
49342
+ },
49343
+ publish(topic, frame2) {
49344
+ const subscribers = index.get(topic);
49345
+ if (subscribers === undefined)
49346
+ return;
49347
+ for (const id of subscribers) {
49348
+ const connection = connections.get(id);
49349
+ if (connection !== undefined)
49350
+ deliver(connection, frame2);
49351
+ }
49352
+ },
49353
+ sendTo(id, frame2) {
49354
+ const connection = connections.get(id);
49355
+ if (connection !== undefined)
49356
+ deliver(connection, frame2);
49357
+ },
49358
+ closeAll(code, reason) {
49359
+ for (const connection of [...connections.values()])
49360
+ closeOne(connection, code, reason);
49361
+ index.clear();
49362
+ },
49363
+ stats() {
49364
+ let queued = 0;
49365
+ for (const connection of connections.values())
49366
+ queued += connection.queue.length;
49367
+ return { connections: connections.size, dropped, queued };
49368
+ },
49369
+ stop() {
49370
+ live = false;
49371
+ cancelTick?.();
49372
+ cancelTick = undefined;
49373
+ }
49374
+ };
49375
+ }
49376
+
49377
+ // apps/gateway/src/stream/ring.ts
49378
+ function sizeOf(payload) {
49379
+ try {
49380
+ return JSON.stringify(payload)?.length ?? 0;
49381
+ } catch {
49382
+ return 0;
49383
+ }
49384
+ }
49385
+ function createRing(limits) {
49386
+ const topics = new Map;
49387
+ const stateFor = (topic) => {
49388
+ const existing = topics.get(topic);
49389
+ if (existing !== undefined)
49390
+ return existing;
49391
+ const created = { entries: [], bytes: 0, seq: 0 };
49392
+ topics.set(topic, created);
49393
+ return created;
49394
+ };
49395
+ return {
49396
+ push(topic, payload) {
49397
+ const state = stateFor(topic);
49398
+ state.seq += 1;
49399
+ const bytes = sizeOf(payload);
49400
+ state.entries.push({ seq: state.seq, payload, bytes });
49401
+ state.bytes += bytes;
49402
+ while (state.entries.length > limits.frames || state.bytes > limits.bytes && state.entries.length > 1) {
49403
+ const evicted = state.entries.shift();
49404
+ if (evicted === undefined)
49405
+ break;
49406
+ state.bytes -= evicted.bytes;
49407
+ }
49408
+ return state.seq;
49409
+ },
49410
+ since(topic, sinceSeq) {
49411
+ const state = topics.get(topic);
49412
+ if (state === undefined) {
49413
+ return sinceSeq === 0 ? { kind: "frames", frames: [] } : { kind: "gap", seq: 0 };
49414
+ }
49415
+ if (sinceSeq > state.seq)
49416
+ return { kind: "gap", seq: state.seq };
49417
+ if (sinceSeq === state.seq)
49418
+ return { kind: "frames", frames: [] };
49419
+ const oldest = state.entries[0];
49420
+ if (oldest === undefined)
49421
+ return { kind: "gap", seq: state.seq };
49422
+ if (oldest.seq > sinceSeq + 1)
49423
+ return { kind: "gap", seq: state.seq };
49424
+ return {
49425
+ kind: "frames",
49426
+ frames: state.entries.filter((entry) => entry.seq > sinceSeq).map(({ seq, payload }) => ({ seq, payload }))
49427
+ };
49428
+ },
49429
+ head(topic) {
49430
+ return topics.get(topic)?.seq ?? 0;
49431
+ },
49432
+ reset(topic) {
49433
+ const state = topics.get(topic);
49434
+ if (state === undefined)
49435
+ return;
49436
+ state.entries = [];
49437
+ state.bytes = 0;
49438
+ },
49439
+ drop(topic) {
49440
+ topics.delete(topic);
49441
+ }
49442
+ };
49443
+ }
49444
+
48155
49445
  // apps/gateway/src/app.ts
48156
49446
  var ADMIN_SESSION_TTL_MS = 12 * 60 * 60 * 1000;
48157
49447
  var QUIESCE_MESSAGE = "the gateway is briefly quiesced for database maintenance";
@@ -48201,6 +49491,29 @@ function createApp(deps) {
48201
49491
  } catch {}
48202
49492
  }
48203
49493
  const latch = deps.latch ?? createQuiesceLatch();
49494
+ let channelsRef;
49495
+ const registry2 = deps.registry ?? createSocketRegistry({
49496
+ logger: logger2,
49497
+ now,
49498
+ onDetach: (id, topics) => channelsRef?.closed(id, topics)
49499
+ });
49500
+ const channels = deps.channels ?? createChannelRegistry({ sockets: registry2, logger: logger2 });
49501
+ channelsRef = channels;
49502
+ const ring = deps.ring ?? createRing({ frames: 500, bytes: 2 * 1024 * 1024 });
49503
+ const broadcaster = deps.broadcaster ?? createBroadcaster({
49504
+ registry: registry2,
49505
+ ring,
49506
+ coalescer: createCoalescer({
49507
+ floors: INVALIDATION_FLOORS,
49508
+ defaultFloorMs: DEFAULT_FLOOR_MS,
49509
+ now,
49510
+ sink: (topic, payload) => registry2.publish(topic, {
49511
+ type: "event",
49512
+ topic,
49513
+ ...payload === undefined ? {} : { payload }
49514
+ })
49515
+ })
49516
+ });
48204
49517
  const admitted = new WeakMap;
48205
49518
  return new Elysia().onRequest(({ request: request2 }) => {
48206
49519
  const path = new URL(request2.url).pathname;
@@ -48225,18 +49538,18 @@ function createApp(deps) {
48225
49538
  rateLimiter,
48226
49539
  logger: logger2,
48227
49540
  ...deps.loadRegistry === undefined ? {} : { loadRegistry: deps.loadRegistry },
48228
- discoveryMirrors: deps.discoveryMirrors === true,
48229
49541
  bodyLoggingAllowed: deps.bodyLoggingAllowed === true,
48230
- ...deps.emit === undefined ? {} : { emit: deps.emit }
49542
+ ...deps.emit === undefined ? {} : { emit: deps.emit },
49543
+ broadcaster
48231
49544
  })).use(adminRoutes({
48232
49545
  store: deps.store,
48233
49546
  admin,
48234
49547
  baseUrl: deps.baseUrl,
48235
- discoveryMirrors: deps.discoveryMirrors === true,
48236
49548
  bodyLoggingAllowed: deps.bodyLoggingAllowed === true,
48237
49549
  now,
48238
49550
  sessionTtlMs: ADMIN_SESSION_TTL_MS,
48239
49551
  logger: logger2,
49552
+ broadcaster,
48240
49553
  ...deps.console === undefined ? {} : { console: deps.console }
48241
49554
  })).use(databaseRoutes({
48242
49555
  store: deps.store,
@@ -48244,6 +49557,7 @@ function createApp(deps) {
48244
49557
  admin,
48245
49558
  latch,
48246
49559
  snapshots,
49560
+ broadcaster,
48247
49561
  fs: deps.databaseFs ?? nodeDatabaseFs(),
48248
49562
  now,
48249
49563
  logger: logger2,
@@ -48263,6 +49577,13 @@ function createApp(deps) {
48263
49577
  admin,
48264
49578
  plugins: deps.pluginUi ?? [],
48265
49579
  logger: logger2
49580
+ })).use(streamRoutes({
49581
+ admin,
49582
+ registry: registry2,
49583
+ broadcaster,
49584
+ ring,
49585
+ channels,
49586
+ logger: logger2
48266
49587
  })).get("/*", ({ path, request: request2, set: set2 }) => {
48267
49588
  const rawPath = new URL(request2.url).pathname;
48268
49589
  const error51 = () => {
@@ -48419,6 +49740,7 @@ async function sweep(deps) {
48419
49740
  const logger2 = deps.logger ?? noopLogger;
48420
49741
  const credentials = await deps.store.credentials.list();
48421
49742
  let refreshed = 0;
49743
+ let touched = 0;
48422
49744
  for (const credential of due(credentials, deps.now())) {
48423
49745
  if (!credential.hasRefreshToken) {
48424
49746
  if (credential.expiresAt !== null && credential.expiresAt <= deps.now()) {
@@ -48427,14 +49749,18 @@ async function sweep(deps) {
48427
49749
  disabledReason: "expiredNoRefresh",
48428
49750
  disabledAt: deps.now()
48429
49751
  });
49752
+ touched += 1;
48430
49753
  }
48431
49754
  continue;
48432
49755
  }
48433
49756
  try {
48434
49757
  await deps.refresh(credential);
48435
49758
  refreshed += 1;
49759
+ touched += 1;
48436
49760
  } catch (error51) {
48437
49761
  const code = error51 instanceof GatewayError ? error51.code : "INTERNAL";
49762
+ if (code === "AUTH")
49763
+ touched += 1;
48438
49764
  logger2.warn("scheduled token refresh failed", {
48439
49765
  provider: credential.provider,
48440
49766
  credentialId: credential.id,
@@ -48443,6 +49769,8 @@ async function sweep(deps) {
48443
49769
  });
48444
49770
  }
48445
49771
  }
49772
+ if (touched > 0)
49773
+ deps.broadcaster?.invalidate("res:credentials");
48446
49774
  return refreshed;
48447
49775
  }
48448
49776
  function startRefreshScheduler(deps) {
@@ -48466,14 +49794,14 @@ function startRefreshScheduler(deps) {
48466
49794
 
48467
49795
  // apps/gateway/src/plugins/events.ts
48468
49796
  var DEFAULT_CAPACITY = 1000;
48469
- var defaultScheduler = (run) => {
49797
+ var defaultScheduler2 = (run) => {
48470
49798
  const timer = setTimeout(run, 0);
48471
49799
  return () => clearTimeout(timer);
48472
49800
  };
48473
49801
  function createPluginEventBus(opts) {
48474
49802
  const logger2 = opts.logger ?? noopLogger;
48475
49803
  const capacity = opts.capacity ?? DEFAULT_CAPACITY;
48476
- const scheduler = opts.scheduler ?? defaultScheduler;
49804
+ const scheduler = opts.scheduler ?? defaultScheduler2;
48477
49805
  const requestHandlers = [];
48478
49806
  const limitHandlers = [];
48479
49807
  const queue = [];
@@ -48681,6 +50009,7 @@ function buildContext(deps) {
48681
50009
  const events = createPluginEvents(manifest, deps.events);
48682
50010
  return events === undefined ? {} : { events };
48683
50011
  })(),
50012
+ ...declared.includes("channels") ? { channels: deps.channels.for(manifest.id) } : {},
48684
50013
  config: manifest.defaults ?? {}
48685
50014
  };
48686
50015
  }
@@ -48761,6 +50090,7 @@ async function loadPlugins(deps) {
48761
50090
  home,
48762
50091
  store: deps.store,
48763
50092
  events: deps.events,
50093
+ channels: deps.channels,
48764
50094
  logger: logger2,
48765
50095
  now
48766
50096
  });
@@ -48809,6 +50139,7 @@ async function startQuotaPoller(deps) {
48809
50139
  });
48810
50140
  }).finally(() => {
48811
50141
  running = false;
50142
+ deps.broadcaster?.invalidate("res:quota");
48812
50143
  });
48813
50144
  };
48814
50145
  pass();
@@ -48817,6 +50148,169 @@ async function startQuotaPoller(deps) {
48817
50148
  return () => clearInterval(timer);
48818
50149
  }
48819
50150
 
50151
+ // apps/gateway/src/stream/console.ts
50152
+ import { watch } from "fs";
50153
+ var CONSOLE_TOPIC = "stream:console";
50154
+ var CONSOLE_FLOOR_MS = 250;
50155
+ var JOURNAL_POLL_MS = 1000;
50156
+ var REWATCH_ATTEMPTS = 5;
50157
+ var defaultSchedule2 = (run, ms) => {
50158
+ const timer = setTimeout(run, ms);
50159
+ return () => clearTimeout(timer);
50160
+ };
50161
+ function startConsoleStream(deps) {
50162
+ const logger2 = deps.logger ?? noopLogger;
50163
+ const { source } = deps.console;
50164
+ if (source.kind === "none")
50165
+ return () => {};
50166
+ if (source.kind === "journal")
50167
+ return startJournalPoll(deps, source, logger2);
50168
+ return startFileWatch(deps, source, logger2);
50169
+ }
50170
+ function startFileWatch(deps, source, logger2) {
50171
+ const { broadcaster } = deps;
50172
+ const read = deps.read ?? readFrom;
50173
+ const size = deps.size ?? fileSize;
50174
+ const floorMs = deps.floorMs ?? CONSOLE_FLOOR_MS;
50175
+ let offset = size(source.path) ?? 0;
50176
+ let stopped = false;
50177
+ let watcher = null;
50178
+ let rotated = false;
50179
+ let rewatchAttempts = 0;
50180
+ let cancelRewatch = null;
50181
+ const rewatchSchedule = deps.schedule ?? defaultSchedule2;
50182
+ const pump = () => {
50183
+ const delta2 = read(source.path, offset);
50184
+ if (delta2 === null) {
50185
+ rotate();
50186
+ return;
50187
+ }
50188
+ offset = delta2.offset;
50189
+ const lines = parseConsoleLines(delta2.text, { lines: MAX_CONSOLE_LINES });
50190
+ if (lines.length > 0)
50191
+ broadcaster.stream(CONSOLE_TOPIC, { lines });
50192
+ if (delta2.gap || rotated) {
50193
+ rotated = false;
50194
+ broadcaster.resetStream(CONSOLE_TOPIC);
50195
+ }
50196
+ };
50197
+ const coalescer = createCoalescer({
50198
+ floors: { [CONSOLE_TOPIC]: floorMs },
50199
+ defaultFloorMs: floorMs,
50200
+ ...deps.now === undefined ? {} : { now: deps.now },
50201
+ ...deps.schedule === undefined ? {} : { schedule: deps.schedule },
50202
+ sink: () => pump()
50203
+ });
50204
+ function rotate() {
50205
+ if (stopped)
50206
+ return;
50207
+ offset = 0;
50208
+ rotated = true;
50209
+ watcher?.close();
50210
+ watcher = startWatcher(deps, source.path, onWatchEvent, logger2);
50211
+ if (watcher === null) {
50212
+ if (rewatchAttempts >= REWATCH_ATTEMPTS) {
50213
+ logger2.warn("console stream ended", { path: source.path });
50214
+ return;
50215
+ }
50216
+ rewatchAttempts += 1;
50217
+ cancelRewatch?.();
50218
+ cancelRewatch = rewatchSchedule(() => rotate(), floorMs);
50219
+ return;
50220
+ }
50221
+ rewatchAttempts = 0;
50222
+ coalescer.emit(CONSOLE_TOPIC);
50223
+ }
50224
+ function onWatchEvent(event) {
50225
+ if (event === "rename") {
50226
+ rotate();
50227
+ return;
50228
+ }
50229
+ coalescer.emit(CONSOLE_TOPIC);
50230
+ }
50231
+ watcher = startWatcher(deps, source.path, onWatchEvent, logger2);
50232
+ if (watcher === null) {
50233
+ coalescer.stop();
50234
+ return () => {};
50235
+ }
50236
+ broadcaster.declareStream(CONSOLE_TOPIC);
50237
+ logger2.info("console stream watching", { path: source.path });
50238
+ return () => {
50239
+ stopped = true;
50240
+ cancelRewatch?.();
50241
+ watcher?.close();
50242
+ coalescer.stop();
50243
+ };
50244
+ }
50245
+ function startWatcher(deps, path, onChange, logger2) {
50246
+ const create2 = deps.watch ?? ((target, changed) => {
50247
+ const watcher = watch(target, (event) => changed(event));
50248
+ watcher.on("error", (error51) => {
50249
+ logger2.error("console watch failed", { reason: describeError(error51, "unknown") });
50250
+ });
50251
+ return watcher;
50252
+ });
50253
+ try {
50254
+ return create2(path, onChange);
50255
+ } catch (error51) {
50256
+ logger2.warn("console stream unavailable", {
50257
+ path,
50258
+ reason: describeError(error51, "unknown")
50259
+ });
50260
+ return null;
50261
+ }
50262
+ }
50263
+ function startJournalPoll(deps, source, logger2) {
50264
+ const { broadcaster } = deps;
50265
+ const now = deps.now ?? Date.now;
50266
+ const schedule = deps.schedule ?? defaultSchedule2;
50267
+ const pollMs = deps.pollMs ?? JOURNAL_POLL_MS;
50268
+ let cursor = now();
50269
+ let stopped = false;
50270
+ let cancel = null;
50271
+ let publishedAtCursor = new Set;
50272
+ const arm = () => {
50273
+ if (stopped)
50274
+ return;
50275
+ cancel = schedule(() => void tick(), pollMs);
50276
+ };
50277
+ const tick = async () => {
50278
+ try {
50279
+ const read = await readConsole(deps.console.deps, source, {
50280
+ lines: MAX_CONSOLE_LINES,
50281
+ since: cursor - 1
50282
+ });
50283
+ const fresh = read.lines.filter((line) => line.at !== cursor || !publishedAtCursor.has(line.raw));
50284
+ if (fresh.length > 0) {
50285
+ let newest = cursor;
50286
+ for (const line of fresh) {
50287
+ if (line.at !== null && line.at > newest)
50288
+ newest = line.at;
50289
+ }
50290
+ if (newest > cursor) {
50291
+ cursor = newest;
50292
+ publishedAtCursor = new Set;
50293
+ }
50294
+ for (const line of fresh) {
50295
+ if (line.at === cursor)
50296
+ publishedAtCursor.add(line.raw);
50297
+ }
50298
+ broadcaster.stream(CONSOLE_TOPIC, { lines: fresh });
50299
+ }
50300
+ } catch (error51) {
50301
+ logger2.error("console poll failed", { reason: describeError(error51, "unknown") });
50302
+ } finally {
50303
+ arm();
50304
+ }
50305
+ };
50306
+ broadcaster.declareStream(CONSOLE_TOPIC);
50307
+ arm();
50308
+ return () => {
50309
+ stopped = true;
50310
+ cancel?.();
50311
+ };
50312
+ }
50313
+
48820
50314
  // apps/gateway/src/index.ts
48821
50315
  function stdoutLogger(level) {
48822
50316
  return createLogger({
@@ -48895,10 +50389,19 @@ async function main() {
48895
50389
  const installRoot = process.env.OMNI_ROOT ?? dirname5(config2.databasePath);
48896
50390
  const pluginRoot = resolve6(installRoot, "plugins");
48897
50391
  const pluginEvents = createPluginEventBus({ logger: logger2 });
50392
+ let pluginChannelsRef;
50393
+ const streamRegistry = createSocketRegistry({
50394
+ logger: logger2,
50395
+ now,
50396
+ onDetach: (id, topics) => pluginChannelsRef?.closed(id, topics)
50397
+ });
50398
+ const pluginChannels = createChannelRegistry({ sockets: streamRegistry, logger: logger2 });
50399
+ pluginChannelsRef = pluginChannels;
48898
50400
  const loadedPlugins = await loadPlugins({
48899
50401
  root: pluginRoot,
48900
50402
  store,
48901
50403
  events: pluginEvents,
50404
+ channels: pluginChannels,
48902
50405
  sdkVersion: DASHBOARD_SDK_VERSION,
48903
50406
  logger: logger2,
48904
50407
  now
@@ -48907,6 +50410,21 @@ async function main() {
48907
50410
  logger2.warn("plugin unavailable", { plugin: failure.id, reason: failure.reason });
48908
50411
  }
48909
50412
  logger2.info("plugins resolved", { count: loadedPlugins.plugins.length, path: pluginRoot });
50413
+ const streamRing = createRing({ frames: 500, bytes: 2 * 1024 * 1024 });
50414
+ const broadcaster = createBroadcaster({
50415
+ registry: streamRegistry,
50416
+ ring: streamRing,
50417
+ coalescer: createCoalescer({
50418
+ floors: INVALIDATION_FLOORS,
50419
+ defaultFloorMs: DEFAULT_FLOOR_MS,
50420
+ now,
50421
+ sink: (topic, payload) => streamRegistry.publish(topic, {
50422
+ type: "event",
50423
+ topic,
50424
+ ...payload === undefined ? {} : { payload }
50425
+ })
50426
+ })
50427
+ });
48910
50428
  const app = createApp({
48911
50429
  store,
48912
50430
  baseUrl: config2.baseUrl,
@@ -48916,7 +50434,10 @@ async function main() {
48916
50434
  staticDir,
48917
50435
  logger: logger2,
48918
50436
  console: console2,
48919
- discoveryMirrors: config2.exposeClaudeCodeAliases,
50437
+ registry: streamRegistry,
50438
+ broadcaster,
50439
+ ring: streamRing,
50440
+ channels: pluginChannels,
48920
50441
  bodyLoggingAllowed: config2.bodyLoggingAllowed,
48921
50442
  plugins: loadedPlugins.plugins.map((plugin) => ({ id: plugin.id, routes: plugin.routes })),
48922
50443
  pluginUi: loadedPlugins.plugins,
@@ -48939,20 +50460,34 @@ async function main() {
48939
50460
  }
48940
50461
  });
48941
50462
  const stopMaintenance = startMaintenance({ store, now, logger: logger2 });
48942
- const stopRefreshScheduler = startRefreshScheduler({ store, refresh, now, logger: logger2 });
50463
+ const stopRefreshScheduler = startRefreshScheduler({ store, refresh, now, logger: logger2, broadcaster });
48943
50464
  const stopQuotaPoller = await startQuotaPoller({
48944
50465
  store,
48945
50466
  providers: OAUTH_PROVIDERS,
48946
50467
  http,
48947
50468
  refresh,
48948
50469
  now,
48949
- logger: logger2
50470
+ logger: logger2,
50471
+ broadcaster
48950
50472
  });
50473
+ const stopConsoleStream = startConsoleStream({ console: console2, broadcaster, logger: logger2, now });
48951
50474
  app.listen({ port: config2.port, hostname: config2.host, idleTimeout: 255 });
48952
50475
  logger2.info("omnigateway listening", { host: config2.host, port: config2.port });
48953
50476
  shutdown = createShutdown({
48954
50477
  logger: logger2,
48955
- stopLoops: [stopMaintenance, stopRefreshScheduler, stopQuotaPoller, () => pluginEvents.stop()],
50478
+ stopLoops: [
50479
+ stopMaintenance,
50480
+ stopRefreshScheduler,
50481
+ stopQuotaPoller,
50482
+ stopConsoleStream,
50483
+ () => pluginEvents.stop(),
50484
+ () => {
50485
+ streamRegistry.closeAll(1001, "restart");
50486
+ streamRegistry.stop();
50487
+ broadcaster.stop();
50488
+ pluginChannels.stop();
50489
+ }
50490
+ ],
48956
50491
  stopServer: async () => {
48957
50492
  await app.stop();
48958
50493
  },