@omnicross/core 0.1.4 → 0.1.5

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 (67) hide show
  1. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +6 -5
  2. package/dist/auth/GeminiCodeAssistProjectResolver.js +4 -3
  3. package/dist/{chunk-SU2GCLAC.cjs → chunk-3Q6Z6JTO.cjs} +124 -16
  4. package/dist/chunk-3Z5BQZFM.cjs +52 -0
  5. package/dist/{chunk-4VAVYUZS.cjs → chunk-4XMYPW46.cjs} +9 -9
  6. package/dist/{chunk-S4WBV25P.js → chunk-6QZGDLL4.js} +106 -23
  7. package/dist/{chunk-C72S6TTV.cjs → chunk-7FEBOPJO.cjs} +5 -4
  8. package/dist/{chunk-TIER4SUC.js → chunk-BODMAL6G.js} +119 -11
  9. package/dist/{chunk-DKPXN34V.cjs → chunk-CGKLE6IW.cjs} +145 -30
  10. package/dist/{chunk-XK5CIRMQ.js → chunk-D3TDKWRP.js} +60 -2
  11. package/dist/{chunk-RSJ3TWJQ.cjs → chunk-DDMRUL76.cjs} +5 -5
  12. package/dist/{chunk-QYTT6GE3.js → chunk-FH2P4OCD.js} +124 -9
  13. package/dist/{chunk-Z7LUNECE.js → chunk-IB3FDI4O.js} +5 -4
  14. package/dist/{chunk-7Y47UCF2.js → chunk-IFXJ2BG7.js} +5 -38
  15. package/dist/{chunk-C7PSERMH.js → chunk-IWQAX3CS.js} +1 -1
  16. package/dist/{chunk-YGXJGRFI.cjs → chunk-JWVTXXPX.cjs} +106 -23
  17. package/dist/{chunk-7YN22L2H.cjs → chunk-K52THW2C.cjs} +5 -5
  18. package/dist/{chunk-Z7Y2NPHY.js → chunk-MFZ5437A.js} +1 -1
  19. package/dist/{chunk-VPBAUQ2M.js → chunk-OQWKZCXP.js} +15 -8
  20. package/dist/{chunk-OCEUVQHW.cjs → chunk-PG7PS2NN.cjs} +61 -3
  21. package/dist/chunk-SYQF7OIR.js +52 -0
  22. package/dist/{chunk-E3UCVHLP.cjs → chunk-UNWKG6EI.cjs} +5 -38
  23. package/dist/{chunk-RGTR7CIO.cjs → chunk-ZCIQ3L3R.cjs} +19 -12
  24. package/dist/completion/CompletionService.cjs +13 -12
  25. package/dist/completion/CompletionService.js +12 -11
  26. package/dist/completion.cjs +13 -12
  27. package/dist/completion.js +12 -11
  28. package/dist/index.cjs +15 -14
  29. package/dist/index.js +14 -13
  30. package/dist/outbound-api/auditCapture.cjs +2 -2
  31. package/dist/outbound-api/auditCapture.d.cts +5 -3
  32. package/dist/outbound-api/auditCapture.d.ts +5 -3
  33. package/dist/outbound-api/auditCapture.js +1 -1
  34. package/dist/outbound-api.cjs +13 -12
  35. package/dist/outbound-api.js +12 -11
  36. package/dist/pipeline/upstreamFetch.cjs +3 -2
  37. package/dist/pipeline/upstreamFetch.d.cts +6 -0
  38. package/dist/pipeline/upstreamFetch.d.ts +6 -0
  39. package/dist/pipeline/upstreamFetch.js +2 -1
  40. package/dist/pipeline/upstreamTrace.cjs +14 -0
  41. package/dist/pipeline/upstreamTrace.d.cts +85 -0
  42. package/dist/pipeline/upstreamTrace.d.ts +85 -0
  43. package/dist/pipeline/upstreamTrace.js +14 -0
  44. package/dist/provider-proxy/ProviderProxy.cjs +13 -12
  45. package/dist/provider-proxy/ProviderProxy.js +12 -11
  46. package/dist/provider-proxy/ingress/providerProxyShared.cjs +15 -12
  47. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +17 -1
  48. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +17 -1
  49. package/dist/provider-proxy/ingress/providerProxyShared.js +14 -11
  50. package/dist/provider-proxy.cjs +13 -12
  51. package/dist/provider-proxy.js +12 -11
  52. package/dist/transformer/transformers/AnthropicTransformer.cjs +2 -2
  53. package/dist/transformer/transformers/AnthropicTransformer.js +1 -1
  54. package/dist/transformer/transformers/GeminiCodeAssistTransformer.cjs +3 -3
  55. package/dist/transformer/transformers/GeminiCodeAssistTransformer.js +2 -2
  56. package/dist/transformer/transformers/GeminiTransformer.cjs +3 -3
  57. package/dist/transformer/transformers/GeminiTransformer.js +2 -2
  58. package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +2 -2
  59. package/dist/transformer/transformers/OpenAIResponseTransformer.js +1 -1
  60. package/dist/transformer/transformers/OpenCodeGoTransformer.cjs +2 -2
  61. package/dist/transformer/transformers/OpenCodeGoTransformer.js +1 -1
  62. package/dist/transformer/transformers.cjs +9 -9
  63. package/dist/transformer/transformers.js +9 -9
  64. package/dist/transformer.cjs +11 -11
  65. package/dist/transformer.js +10 -10
  66. package/package.json +1 -1
  67. package/dist/{chunk-FTQ7IQUC.js → chunk-C6OV7GCC.js} +8 -8
@@ -45,10 +45,12 @@ var OpenAIResponseTransformer = class {
45
45
  if (msg.role === "assistant" && msg.tool_calls?.length) {
46
46
  input.push(entry);
47
47
  for (const tc of msg.tool_calls) {
48
+ const callId = tc.id;
49
+ const itemId = callId.startsWith("fc_") ? callId : `fc_${callId.replace(/^(call_|fc_)/, "")}`;
48
50
  input.push({
49
51
  type: "function_call",
50
- id: tc.id,
51
- call_id: tc.id,
52
+ id: itemId,
53
+ call_id: callId,
52
54
  name: tc.function.name,
53
55
  arguments: tc.function.arguments
54
56
  });
@@ -61,7 +63,11 @@ var OpenAIResponseTransformer = class {
61
63
  const body = {
62
64
  model: request.model,
63
65
  input,
64
- stream: request.stream ?? false,
66
+ // codex's backend REQUIRES `stream:true` (it 400s with "Stream must be
67
+ // set to true" otherwise). Always force it; a non-streaming CLIENT is
68
+ // served by aggregating the SSE upstream of the wire (the ingress buffers
69
+ // it into a single message), not by asking codex for a non-streaming reply.
70
+ stream: true,
65
71
  // `store:false` is required by the codex backend and accepted by the
66
72
  // public Responses API (which defaults to store:true). Always set it so
67
73
  // codex relays (no discoverable url token) work without configuration.
@@ -335,6 +341,7 @@ function convertResponseApiStreamToOpenAI(responseApiStream) {
335
341
  const messageId = `chatcmpl-${Date.now()}`;
336
342
  let model = "unknown";
337
343
  let hasEmittedRole = false;
344
+ let hasToolCalls = false;
338
345
  const safeEnqueue = (str) => {
339
346
  if (!isClosed) {
340
347
  try {
@@ -391,6 +398,42 @@ function convertResponseApiStreamToOpenAI(responseApiStream) {
391
398
  }]);
392
399
  }
393
400
  break;
401
+ case "response.output_item.added": {
402
+ const item = event.item;
403
+ if (item?.type !== "function_call") break;
404
+ if (!hasEmittedRole) {
405
+ emitChunk([{ index: 0, delta: { role: "assistant", content: null }, finish_reason: null }]);
406
+ hasEmittedRole = true;
407
+ }
408
+ hasToolCalls = true;
409
+ emitChunk([{
410
+ index: 0,
411
+ delta: {
412
+ tool_calls: [{
413
+ index: event.output_index ?? 0,
414
+ id: item.call_id,
415
+ type: "function",
416
+ function: { name: item.name, arguments: "" }
417
+ }]
418
+ },
419
+ finish_reason: null
420
+ }]);
421
+ break;
422
+ }
423
+ case "response.function_call_arguments.delta": {
424
+ hasToolCalls = true;
425
+ emitChunk([{
426
+ index: 0,
427
+ delta: {
428
+ tool_calls: [{
429
+ index: event.output_index ?? 0,
430
+ function: { arguments: event.delta ?? "" }
431
+ }]
432
+ },
433
+ finish_reason: null
434
+ }]);
435
+ break;
436
+ }
394
437
  case "response.completed": {
395
438
  const resp = event.response;
396
439
  const respUsage = resp?.usage;
@@ -399,7 +442,7 @@ function convertResponseApiStreamToOpenAI(responseApiStream) {
399
442
  completion_tokens: respUsage.output_tokens || 0,
400
443
  total_tokens: (respUsage.input_tokens || 0) + (respUsage.output_tokens || 0)
401
444
  } : void 0;
402
- emitChunk([{ index: 0, delta: {}, finish_reason: "stop" }], usage);
445
+ emitChunk([{ index: 0, delta: {}, finish_reason: hasToolCalls ? "tool_calls" : "stop" }], usage);
403
446
  safeEnqueue("data: [DONE]\n\n");
404
447
  break;
405
448
  }
@@ -442,6 +485,9 @@ function convertOpenAIStreamToResponseApi(openaiStream) {
442
485
  let accumulatedContent = "";
443
486
  let model = "unknown";
444
487
  const responseId = `resp_${Date.now()}`;
488
+ const toolCalls = /* @__PURE__ */ new Map();
489
+ const toolOutputIndex = /* @__PURE__ */ new Map();
490
+ let nextOutputIndex = 1;
445
491
  const safeEnqueue = (str) => {
446
492
  if (!isClosed) {
447
493
  try {
@@ -487,21 +533,83 @@ function convertOpenAIStreamToResponseApi(openaiStream) {
487
533
  delta: choice.delta.thinking.content
488
534
  });
489
535
  }
536
+ if (choice.delta?.tool_calls) {
537
+ for (const tc of choice.delta.tool_calls) {
538
+ const tcIndex = typeof tc["index"] === "number" ? tc["index"] : 0;
539
+ const func = tc["function"] ?? {};
540
+ let entry = toolCalls.get(tcIndex);
541
+ if (!entry) {
542
+ const callId = typeof tc["id"] === "string" ? tc["id"] : `call_${Date.now()}_${tcIndex}`;
543
+ const name = typeof func["name"] === "string" ? func["name"] : "";
544
+ entry = { callId, name, arguments: "" };
545
+ toolCalls.set(tcIndex, entry);
546
+ const outIdx = nextOutputIndex++;
547
+ toolOutputIndex.set(tcIndex, outIdx);
548
+ const itemId = callId.startsWith("fc_") ? callId : `fc_${callId.replace(/^(call_|fc_)/, "")}`;
549
+ emitEvent({
550
+ type: "response.output_item.added",
551
+ output_index: outIdx,
552
+ item: {
553
+ id: itemId,
554
+ type: "function_call",
555
+ status: "in_progress",
556
+ call_id: callId,
557
+ name,
558
+ arguments: ""
559
+ }
560
+ });
561
+ }
562
+ const argsFragment = typeof func["arguments"] === "string" ? func["arguments"] : "";
563
+ if (argsFragment) {
564
+ entry.arguments += argsFragment;
565
+ emitEvent({
566
+ type: "response.function_call_arguments.delta",
567
+ output_index: toolOutputIndex.get(tcIndex),
568
+ delta: argsFragment
569
+ });
570
+ }
571
+ }
572
+ }
490
573
  if (choice.finish_reason) {
491
574
  emitEvent({ type: "response.output_text.done", text: accumulatedContent });
575
+ const output = [];
576
+ if (accumulatedContent) {
577
+ output.push({
578
+ type: "message",
579
+ role: "assistant",
580
+ content: [{ type: "output_text", text: accumulatedContent }]
581
+ });
582
+ }
583
+ for (const [tcIndex, entry] of toolCalls) {
584
+ const itemId = entry.callId.startsWith("fc_") ? entry.callId : `fc_${entry.callId.replace(/^(call_|fc_)/, "")}`;
585
+ output.push({
586
+ id: itemId,
587
+ type: "function_call",
588
+ status: "completed",
589
+ call_id: entry.callId,
590
+ name: entry.name,
591
+ arguments: entry.arguments
592
+ });
593
+ emitEvent({
594
+ type: "response.output_item.done",
595
+ output_index: toolOutputIndex.get(tcIndex),
596
+ item: {
597
+ id: itemId,
598
+ type: "function_call",
599
+ status: "completed",
600
+ call_id: entry.callId,
601
+ name: entry.name,
602
+ arguments: entry.arguments
603
+ }
604
+ });
605
+ }
492
606
  emitEvent({
493
607
  type: "response.completed",
494
608
  response: {
495
609
  id: responseId,
496
610
  status: "completed",
497
611
  model,
498
- output: [
499
- {
500
- type: "message",
501
- role: "assistant",
502
- content: [{ type: "output_text", text: accumulatedContent }]
503
- }
504
- ],
612
+ output,
505
613
  usage: chunk.usage ? {
506
614
  input_tokens: chunk.usage.prompt_tokens || 0,
507
615
  output_tokens: chunk.usage.completion_tokens || 0,
@@ -3,16 +3,16 @@
3
3
  var _chunkHQP3K7PUcjs = require('./chunk-HQP3K7PU.cjs');
4
4
 
5
5
 
6
- var _chunk4VAVYUZScjs = require('./chunk-4VAVYUZS.cjs');
6
+ var _chunk46ZIFWYGcjs = require('./chunk-46ZIFWYG.cjs');
7
7
 
8
8
 
9
- var _chunk7YN22L2Hcjs = require('./chunk-7YN22L2H.cjs');
9
+ var _chunk4XMYPW46cjs = require('./chunk-4XMYPW46.cjs');
10
10
 
11
11
 
12
- var _chunkSU2GCLACcjs = require('./chunk-SU2GCLAC.cjs');
12
+ var _chunkK52THW2Ccjs = require('./chunk-K52THW2C.cjs');
13
13
 
14
14
 
15
- var _chunk46ZIFWYGcjs = require('./chunk-46ZIFWYG.cjs');
15
+ var _chunk3Q6Z6JTOcjs = require('./chunk-3Q6Z6JTO.cjs');
16
16
 
17
17
 
18
18
  var _chunkGBHYAGX3cjs = require('./chunk-GBHYAGX3.cjs');
@@ -80,14 +80,14 @@ var _chunkVACWOIREcjs = require('./chunk-VACWOIRE.cjs');
80
80
  var _chunkA2YMUCBTcjs = require('./chunk-A2YMUCBT.cjs');
81
81
 
82
82
 
83
- var _chunkE3UCVHLPcjs = require('./chunk-E3UCVHLP.cjs');
83
+ var _chunkUNWKG6EIcjs = require('./chunk-UNWKG6EI.cjs');
84
84
 
85
85
 
86
86
 
87
87
  var _chunkSUEGJ75Dcjs = require('./chunk-SUEGJ75D.cjs');
88
88
 
89
89
 
90
- var _chunkOCEUVQHWcjs = require('./chunk-OCEUVQHW.cjs');
90
+ var _chunkPG7PS2NNcjs = require('./chunk-PG7PS2NN.cjs');
91
91
 
92
92
 
93
93
  var _chunkJMJBSACDcjs = require('./chunk-JMJBSACD.cjs');
@@ -517,17 +517,17 @@ function getSharedExecutor() {
517
517
  }
518
518
  var sharedResponses = null;
519
519
  function getResponsesEndpointTransformer() {
520
- if (!sharedResponses) sharedResponses = new (0, _chunkSU2GCLACcjs.OpenAIResponseTransformer)();
520
+ if (!sharedResponses) sharedResponses = new (0, _chunk3Q6Z6JTOcjs.OpenAIResponseTransformer)();
521
521
  return sharedResponses;
522
522
  }
523
523
  var sharedAnthropic = null;
524
524
  function getAnthropicEndpointTransformer() {
525
- if (!sharedAnthropic) sharedAnthropic = new (0, _chunk4VAVYUZScjs.AnthropicTransformer)();
525
+ if (!sharedAnthropic) sharedAnthropic = new (0, _chunk4XMYPW46cjs.AnthropicTransformer)();
526
526
  return sharedAnthropic;
527
527
  }
528
528
  var sharedGemini = null;
529
529
  function getGeminiEndpointTransformer() {
530
- if (!sharedGemini) sharedGemini = new (0, _chunk7YN22L2Hcjs.GeminiTransformer)();
530
+ if (!sharedGemini) sharedGemini = new (0, _chunkK52THW2Ccjs.GeminiTransformer)();
531
531
  return sharedGemini;
532
532
  }
533
533
  function readBody(req) {
@@ -651,6 +651,95 @@ async function relayResponse(res, providerResponse, isStream, rewriteModel) {
651
651
  res.end(clientText);
652
652
  return bodyText;
653
653
  }
654
+ async function aggregateAnthropicSseToJsonBody(response, rewriteModel) {
655
+ const text = await response.text();
656
+ const message = {
657
+ type: "message",
658
+ role: "assistant",
659
+ content: [],
660
+ stop_reason: null,
661
+ stop_sequence: null,
662
+ usage: {}
663
+ };
664
+ const blocks = /* @__PURE__ */ new Map();
665
+ for (const raw of text.split("\n")) {
666
+ const line = raw.trim();
667
+ if (!line.startsWith("data:")) continue;
668
+ const payload = line.slice(5).trim();
669
+ if (!payload || payload === "[DONE]") continue;
670
+ let ev;
671
+ try {
672
+ ev = JSON.parse(payload);
673
+ } catch (e7) {
674
+ continue;
675
+ }
676
+ switch (ev["type"]) {
677
+ case "message_start": {
678
+ const m = _nullishCoalesce(ev["message"], () => ( {}));
679
+ if (typeof m["id"] === "string") message["id"] = m["id"];
680
+ if (typeof m["model"] === "string") message["model"] = m["model"];
681
+ if (m["usage"]) message["usage"] = { ...m["usage"] };
682
+ break;
683
+ }
684
+ case "content_block_start": {
685
+ const idx = Number(ev["index"]);
686
+ const cb = _nullishCoalesce(ev["content_block"], () => ( {}));
687
+ blocks.set(idx, {
688
+ type: typeof cb["type"] === "string" ? cb["type"] : "text",
689
+ text: typeof cb["text"] === "string" ? cb["text"] : "",
690
+ id: typeof cb["id"] === "string" ? cb["id"] : void 0,
691
+ name: typeof cb["name"] === "string" ? cb["name"] : void 0,
692
+ inputJson: ""
693
+ });
694
+ break;
695
+ }
696
+ case "content_block_delta": {
697
+ const b = blocks.get(Number(ev["index"]));
698
+ if (!b) break;
699
+ const d = _nullishCoalesce(ev["delta"], () => ( {}));
700
+ if (d["type"] === "text_delta" && typeof d["text"] === "string") b.text += d["text"];
701
+ else if (d["type"] === "input_json_delta" && typeof d["partial_json"] === "string")
702
+ b.inputJson += d["partial_json"];
703
+ else if (d["type"] === "thinking_delta" && typeof d["thinking"] === "string")
704
+ b.text += d["thinking"];
705
+ else if (d["type"] === "signature_delta" && typeof d["signature"] === "string")
706
+ b.signature = (b.signature || "") + d["signature"];
707
+ break;
708
+ }
709
+ case "message_delta": {
710
+ const d = _nullishCoalesce(ev["delta"], () => ( {}));
711
+ if (d["stop_reason"] !== void 0) message["stop_reason"] = d["stop_reason"];
712
+ if (d["stop_sequence"] !== void 0) message["stop_sequence"] = d["stop_sequence"];
713
+ if (ev["usage"])
714
+ message["usage"] = { ...message["usage"], ...ev["usage"] };
715
+ break;
716
+ }
717
+ default:
718
+ break;
719
+ }
720
+ }
721
+ message["content"] = [...blocks.keys()].sort((a, b) => a - b).map((idx) => {
722
+ const blk = blocks.get(idx);
723
+ if (!blk) return void 0;
724
+ if (blk.type === "tool_use") {
725
+ let input = {};
726
+ try {
727
+ input = blk.inputJson ? JSON.parse(blk.inputJson) : {};
728
+ } catch (e8) {
729
+ input = {};
730
+ }
731
+ return { type: "tool_use", id: _nullishCoalesce(blk.id, () => ( "")), name: _nullishCoalesce(blk.name, () => ( "")), input };
732
+ }
733
+ if (blk.type === "thinking") {
734
+ const out = { type: "thinking", thinking: blk.text };
735
+ if (blk.signature) out.signature = blk.signature;
736
+ return out;
737
+ }
738
+ return { type: blk.type || "text", text: blk.text };
739
+ }).filter((b) => b !== void 0);
740
+ if (rewriteModel) message["model"] = rewriteModel;
741
+ return JSON.stringify(message);
742
+ }
654
743
  function writeError(res, status, message) {
655
744
  if (res.headersSent) return;
656
745
  res.writeHead(status, { "Content-Type": "application/json" });
@@ -816,7 +905,7 @@ async function runPipeline(anthropicBody, plan, reportSelection) {
816
905
  },
817
906
  fetchFn: (url, headers, body) => {
818
907
  console.info(`[ProviderProxy:anthropic] -> ${url} model=${resolvedModel} stream=${isStream}`);
819
- return _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
908
+ return _chunkPG7PS2NNcjs.fetchUpstream.call(void 0,
820
909
  url,
821
910
  { method: "POST", headers, body: JSON.stringify(body) },
822
911
  { providerId: proxyProviderId(plan), accountId: proxyAccountId }
@@ -859,7 +948,7 @@ async function runSubscriptionSameFormatFetch(rawBody, plan, reportSelection, op
859
948
  console.info(
860
949
  `[ProviderProxy:anthropic] (subscription same-format) -> ${plan.upstreamUrl} model=${outboundModel} stream=${plan.isStream}`
861
950
  );
862
- const response = await _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
951
+ const response = await _chunkPG7PS2NNcjs.fetchUpstream.call(void 0,
863
952
  plan.upstreamUrl,
864
953
  { method: "POST", headers, body: outboundBody },
865
954
  { providerId: proxyProviderId(plan), accountId: proxyAccountId }
@@ -875,7 +964,7 @@ function rewriteBodyModel(rawBody, model) {
875
964
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return rawBody;
876
965
  parsed.model = model;
877
966
  return JSON.stringify(parsed);
878
- } catch (e7) {
967
+ } catch (e9) {
879
968
  return rawBody;
880
969
  }
881
970
  }
@@ -903,7 +992,7 @@ async function readBoundedBody(response, max = 2048) {
903
992
  try {
904
993
  const text = await response.clone().text();
905
994
  return text.slice(0, max);
906
- } catch (e8) {
995
+ } catch (e10) {
907
996
  return void 0;
908
997
  }
909
998
  }
@@ -1014,7 +1103,7 @@ async function handleAnthropicMessagesByo(res, rawBody, route, deps, options = {
1014
1103
  let anthropicBody;
1015
1104
  try {
1016
1105
  anthropicBody = JSON.parse(rawBody);
1017
- } catch (e9) {
1106
+ } catch (e11) {
1018
1107
  writeError(res, 400, "Invalid JSON in request body");
1019
1108
  return;
1020
1109
  }
@@ -1026,7 +1115,21 @@ async function handleAnthropicMessagesByo(res, rawBody, route, deps, options = {
1026
1115
  if (!plan) return;
1027
1116
  anthropicBody.model = plan.resolvedModel;
1028
1117
  const providerResponse = route.authMode === "subscription" ? await runPipelineWithSubscriptionRetry(anthropicBody, rawBody, plan, route, deps, options) : await runPipelineWithPoolReporting(anthropicBody, rawBody, plan, options);
1029
- const bodyText = await relayResponse(res, providerResponse.response, isStream, route.requestedModel);
1118
+ const upstreamResponse = providerResponse.response;
1119
+ const upstreamSse = (_nullishCoalesce(upstreamResponse.headers.get("content-type"), () => ( ""))).includes(
1120
+ "text/event-stream"
1121
+ );
1122
+ let bodyText;
1123
+ if (!isStream && upstreamSse) {
1124
+ bodyText = await aggregateAnthropicSseToJsonBody(upstreamResponse, route.requestedModel);
1125
+ res.writeHead(
1126
+ upstreamResponse.status && upstreamResponse.status >= 100 ? upstreamResponse.status : 200,
1127
+ { "Content-Type": "application/json" }
1128
+ );
1129
+ res.end(bodyText);
1130
+ } else {
1131
+ bodyText = await relayResponse(res, upstreamResponse, isStream, route.requestedModel);
1132
+ }
1030
1133
  if (bodyText && deps.usageRecorder) {
1031
1134
  recordAnthropicNonStreamUsage(deps.usageRecorder, bodyText, {
1032
1135
  sessionId: route.sessionId,
@@ -1111,7 +1214,7 @@ async function runSameFormatFetch(bodyToSend, plan, options, keyOverride) {
1111
1214
  _chunkGBHYAGX3cjs.injectExtendedContextBeta.call(void 0, headers, resolvedModel, _nullishCoalesce(extendedContextEnabled, () => ( false)));
1112
1215
  const url = _chunkA2YMUCBTcjs.buildProviderApiUrl.call(void 0, provider, { model: resolvedModel, stream: isStream });
1113
1216
  console.info(`[ProviderProxy:anthropic] (same-format) -> ${url} model=${resolvedModel} stream=${isStream}`);
1114
- const response = await _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
1217
+ const response = await _chunkPG7PS2NNcjs.fetchUpstream.call(void 0,
1115
1218
  url,
1116
1219
  { method: "POST", headers, body: bodyToSend },
1117
1220
  { providerId: "byo" }
@@ -1123,7 +1226,7 @@ function resolveSameFormatBody(anthropicBody, rawBody, plan) {
1123
1226
  try {
1124
1227
  const m = JSON.parse(rawBody).model;
1125
1228
  originalModel = typeof m === "string" ? m : void 0;
1126
- } catch (e10) {
1229
+ } catch (e12) {
1127
1230
  originalModel = void 0;
1128
1231
  }
1129
1232
  return plan.resolvedModel !== originalModel ? JSON.stringify(anthropicBody) : rawBody;
@@ -1223,7 +1326,7 @@ function recordGeminiNonStreamUsage(recorder, bodyText, attribution) {
1223
1326
  usage: tapped,
1224
1327
  rawUsage: parsed.usageMetadata
1225
1328
  });
1226
- } catch (e11) {
1329
+ } catch (e13) {
1227
1330
  }
1228
1331
  }
1229
1332
 
@@ -1247,7 +1350,7 @@ async function handleGeminiGenerateContentRequest(res, rawBody, url, route, deps
1247
1350
  let geminiBody;
1248
1351
  try {
1249
1352
  geminiBody = JSON.parse(rawBody);
1250
- } catch (e12) {
1353
+ } catch (e14) {
1251
1354
  writeError(res, 400, "Invalid JSON in request body");
1252
1355
  return;
1253
1356
  }
@@ -1346,7 +1449,7 @@ async function runPipeline2(geminiBody, plan) {
1346
1449
  },
1347
1450
  fetchFn: (url, headers, body) => {
1348
1451
  console.log(`[ProviderProxy:gemini] -> ${url} model=${resolvedModel} stream=${isStream}`);
1349
- return _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
1452
+ return _chunkPG7PS2NNcjs.fetchUpstream.call(void 0,
1350
1453
  url,
1351
1454
  { method: "POST", headers, body: JSON.stringify(body) },
1352
1455
  { providerId: "byo" }
@@ -1408,7 +1511,7 @@ function recordChatCompletionsNonStreamUsage(recorder, bodyText, attribution) {
1408
1511
  usage: tapped,
1409
1512
  rawUsage: parsed.usage
1410
1513
  });
1411
- } catch (e13) {
1514
+ } catch (e15) {
1412
1515
  }
1413
1516
  }
1414
1517
 
@@ -1424,7 +1527,7 @@ async function handleOpenAIChatRequest(res, rawBody, route, deps) {
1424
1527
  let chatBody;
1425
1528
  try {
1426
1529
  chatBody = JSON.parse(rawBody);
1427
- } catch (e14) {
1530
+ } catch (e16) {
1428
1531
  writeError(res, 400, "Invalid JSON in request body");
1429
1532
  return;
1430
1533
  }
@@ -1569,7 +1672,7 @@ async function runPipeline3(chatBody, plan) {
1569
1672
  },
1570
1673
  fetchFn: (url, headers, body) => {
1571
1674
  console.log(`[ProviderProxy:chat] -> ${url} model=${resolvedModel} stream=${isStream}`);
1572
- return _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
1675
+ return _chunkPG7PS2NNcjs.fetchUpstream.call(void 0,
1573
1676
  url,
1574
1677
  { method: "POST", headers, body: JSON.stringify(body) },
1575
1678
  { providerId: plan.proxyProviderId, accountId: proxyAccountId }
@@ -1642,7 +1745,7 @@ function recordResponsesNonStreamUsage(recorder, bodyText, attribution) {
1642
1745
  usage: tapped,
1643
1746
  rawUsage: parsed.usage
1644
1747
  });
1645
- } catch (e15) {
1748
+ } catch (e17) {
1646
1749
  }
1647
1750
  }
1648
1751
 
@@ -1656,7 +1759,7 @@ async function handleOpenAIResponsesRequest(res, rawBody, route, deps) {
1656
1759
  let responsesBody;
1657
1760
  try {
1658
1761
  responsesBody = JSON.parse(rawBody);
1659
- } catch (e16) {
1762
+ } catch (e18) {
1660
1763
  writeError(res, 400, "Invalid JSON in request body");
1661
1764
  return;
1662
1765
  }
@@ -1815,7 +1918,7 @@ async function runPipeline4(responsesBody, plan) {
1815
1918
  },
1816
1919
  fetchFn: (url, headers, body) => {
1817
1920
  console.log(`[ProviderProxy:responses] -> ${url} model=${resolvedModel} stream=${isStream}`);
1818
- return _chunkOCEUVQHWcjs.fetchUpstream.call(void 0,
1921
+ return _chunkPG7PS2NNcjs.fetchUpstream.call(void 0,
1819
1922
  url,
1820
1923
  { method: "POST", headers, body: JSON.stringify(body) },
1821
1924
  { providerId: plan.proxyProviderId, accountId: proxyAccountId }
@@ -3096,7 +3199,7 @@ async function handleVoucherRedeem(req, res, deps, voucherEnabled, redeemLimiter
3096
3199
  let code;
3097
3200
  try {
3098
3201
  code = raw ? JSON.parse(raw)["code"] : void 0;
3099
- } catch (e17) {
3202
+ } catch (e19) {
3100
3203
  writeErr(res, 400, "Invalid JSON in request body");
3101
3204
  return;
3102
3205
  }
@@ -3255,7 +3358,7 @@ function shimAuthHeader(req, routeToken) {
3255
3358
  }
3256
3359
  async function handleOutboundRequest(req, res, deps, config, rateLimiter, serialQueue, concurrencyGate, redeemLimiter, redeemMutex) {
3257
3360
  const now = Date.now();
3258
- const audit = _chunkE3UCVHLPcjs.beginAuditCapture.call(void 0, req, res, now);
3361
+ const audit = _chunkUNWKG6EIcjs.beginAuditCapture.call(void 0, req, res, now);
3259
3362
  const billing = _chunkAPYG5QD7cjs.beginBillingCapture.call(void 0, req, res, now);
3260
3363
  const presented = extractPresentedKey(req);
3261
3364
  const verification = await verifyKey(deps.db, presented, now);
@@ -3366,7 +3469,7 @@ async function handleOutboundRequest(req, res, deps, config, rateLimiter, serial
3366
3469
  let parsedBody = {};
3367
3470
  try {
3368
3471
  parsedBody = rawBody ? JSON.parse(rawBody) : {};
3369
- } catch (e18) {
3472
+ } catch (e20) {
3370
3473
  writeJsonError(res, 400, "Invalid JSON in request body");
3371
3474
  return;
3372
3475
  }
@@ -3595,6 +3698,7 @@ var OutboundApiServer = (_class11 = class {
3595
3698
  }
3596
3699
  /** Per-request handler. Auth is enforced on EVERY request (incl. loopback). */
3597
3700
  onRequest(req, res) {
3701
+ if (req.url) req.url = normalizeDoubledEndpointPath(req.url);
3598
3702
  if (this.deps.healthReportProvider && this.tryServeHealth(req, res)) return;
3599
3703
  handleOutboundRequest(
3600
3704
  req,
@@ -3717,6 +3821,16 @@ function firstLanIPv4() {
3717
3821
  }
3718
3822
  return null;
3719
3823
  }
3824
+ function normalizeDoubledEndpointPath(url) {
3825
+ const queryIdx = url.indexOf("?");
3826
+ const path = queryIdx === -1 ? url : url.slice(0, queryIdx);
3827
+ const query = queryIdx === -1 ? "" : url.slice(queryIdx);
3828
+ const collapsed = path.replace(
3829
+ /^(.*?)(\/v1\/(?:messages|responses|chat\/completions))\2$/,
3830
+ "$1$2"
3831
+ );
3832
+ return collapsed + query;
3833
+ }
3720
3834
 
3721
3835
  // src/outbound-api/keySpendTracker.ts
3722
3836
  function startOfLocalDay(ts) {
@@ -5967,4 +6081,5 @@ ${description}`;
5967
6081
 
5968
6082
 
5969
6083
 
5970
- exports.CompletionService = CompletionService; exports.register = register; exports.emit = emit; exports.attach = attach; exports.release = release; exports.convertMessageToOpenAI = convertMessageToOpenAI; exports.convertMessageToAnthropic = convertMessageToAnthropic; exports.convertMessageToGemini = convertMessageToGemini; exports.getOpenRouterProviderConfig = getOpenRouterProviderConfig; exports.addOpenRouterProviderToRequest = addOpenRouterProviderToRequest; exports.DEFAULT_ROUTE_IDLE_MS = DEFAULT_ROUTE_IDLE_MS; exports.ProviderProxyRouteMap = ProviderProxyRouteMap; exports.getSharedExecutor = getSharedExecutor; exports.getResponsesEndpointTransformer = getResponsesEndpointTransformer; exports.getAnthropicEndpointTransformer = getAnthropicEndpointTransformer; exports.getGeminiEndpointTransformer = getGeminiEndpointTransformer; exports.readBody = readBody; exports.relayResponse = relayResponse; exports.writeError = writeError; exports.resolvePoolBoundKey = resolvePoolBoundKey; exports.extractRouteToken = extractRouteToken; exports.isLoopbackAddress = isLoopbackAddress; exports.ProviderProxy = ProviderProxy; exports.getProviderProxy = getProviderProxy; exports.__resetProviderProxyForTests = __resetProviderProxyForTests; exports.KeyedMutex = KeyedMutex; exports.OUTBOUND_API_SERVER_CONFIG_KEY = OUTBOUND_API_SERVER_CONFIG_KEY; exports.DEFAULT_USER_MESSAGE_QUEUE = DEFAULT_USER_MESSAGE_QUEUE; exports.DEFAULT_CONCURRENCY_QUEUE = DEFAULT_CONCURRENCY_QUEUE; exports.DEFAULT_ACCOUNT_PROBE = DEFAULT_ACCOUNT_PROBE; exports.normalizeAccountProbe = normalizeAccountProbe; exports.normalizeAudit = normalizeAudit; exports.normalizeBilling = normalizeBilling; exports.DEFAULT_FINGERPRINT = DEFAULT_FINGERPRINT; exports.normalizeFingerprint = normalizeFingerprint; exports.normalizeVoucher = normalizeVoucher; exports.normalizeProxyConfig = normalizeProxyConfig; exports.normalizeProxySegment = normalizeProxySegment; exports.normalizeWebhookDestination = normalizeWebhookDestination; exports.normalizeWebhookSegment = normalizeWebhookSegment; exports.normalizeQueueSegments = normalizeQueueSegments; exports.normalizePrefixTargets = normalizePrefixTargets; exports.defaultServerConfig = defaultServerConfig; exports.normalizeServerConfig = normalizeServerConfig; exports.loadServerConfig = loadServerConfig; exports.saveServerConfig = saveServerConfig; exports.mergeServerConfig = mergeServerConfig; exports.computeKeyExpiry = computeKeyExpiry; exports.checkKeyQuota = checkKeyQuota; exports.randomBase62 = randomBase62; exports.hashKey = hashKey; exports.createNamedKey = createNamedKey; exports.verifyKey = verifyKey; exports.verifyPresentedKey = verifyPresentedKey; exports.ConcurrencyQueueFullError = ConcurrencyQueueFullError; exports.ConcurrencyWaitTimeoutError = ConcurrencyWaitTimeoutError; exports.ConcurrencyWaitCancelledError = ConcurrencyWaitCancelledError; exports.isConcurrencyRejection = isConcurrencyRejection; exports.OutboundConcurrencyGate = OutboundConcurrencyGate; exports.OutboundRateLimiter = OutboundRateLimiter; exports.isUserMessageRequest = isUserMessageRequest; exports.SerialQueueTimeoutError = SerialQueueTimeoutError; exports.isSerialQueueTimeout = isSerialQueueTimeout; exports.UserMessageSerialQueue = UserMessageSerialQueue; exports.generateVoucherCode = generateVoucherCode; exports.hashVoucherCode = hashVoucherCode; exports.voucherCodePrefix = voucherCodePrefix; exports.newVoucherId = newVoucherId; exports.computeVoucherGrant = computeVoucherGrant; exports.toVoucherInfo = toVoucherInfo; exports.isRedeemRequest = isRedeemRequest; exports.handleVoucherRedeem = handleVoucherRedeem; exports.DEFAULT_OUTBOUND_PORT = DEFAULT_OUTBOUND_PORT; exports.OutboundApiConfigError = OutboundApiConfigError; exports.OutboundApiServer = OutboundApiServer; exports.formatUrls = formatUrls; exports.startOfLocalDay = startOfLocalDay; exports.startOfLocalWeek = startOfLocalWeek; exports.KeySpendTracker = KeySpendTracker; exports.getOutboundApiServer = getOutboundApiServer; exports.__resetOutboundApiServerForTests = __resetOutboundApiServerForTests;
6084
+
6085
+ exports.CompletionService = CompletionService; exports.register = register; exports.emit = emit; exports.attach = attach; exports.release = release; exports.convertMessageToOpenAI = convertMessageToOpenAI; exports.convertMessageToAnthropic = convertMessageToAnthropic; exports.convertMessageToGemini = convertMessageToGemini; exports.getOpenRouterProviderConfig = getOpenRouterProviderConfig; exports.addOpenRouterProviderToRequest = addOpenRouterProviderToRequest; exports.DEFAULT_ROUTE_IDLE_MS = DEFAULT_ROUTE_IDLE_MS; exports.ProviderProxyRouteMap = ProviderProxyRouteMap; exports.getSharedExecutor = getSharedExecutor; exports.getResponsesEndpointTransformer = getResponsesEndpointTransformer; exports.getAnthropicEndpointTransformer = getAnthropicEndpointTransformer; exports.getGeminiEndpointTransformer = getGeminiEndpointTransformer; exports.readBody = readBody; exports.relayResponse = relayResponse; exports.aggregateAnthropicSseToJsonBody = aggregateAnthropicSseToJsonBody; exports.writeError = writeError; exports.resolvePoolBoundKey = resolvePoolBoundKey; exports.extractRouteToken = extractRouteToken; exports.isLoopbackAddress = isLoopbackAddress; exports.ProviderProxy = ProviderProxy; exports.getProviderProxy = getProviderProxy; exports.__resetProviderProxyForTests = __resetProviderProxyForTests; exports.KeyedMutex = KeyedMutex; exports.OUTBOUND_API_SERVER_CONFIG_KEY = OUTBOUND_API_SERVER_CONFIG_KEY; exports.DEFAULT_USER_MESSAGE_QUEUE = DEFAULT_USER_MESSAGE_QUEUE; exports.DEFAULT_CONCURRENCY_QUEUE = DEFAULT_CONCURRENCY_QUEUE; exports.DEFAULT_ACCOUNT_PROBE = DEFAULT_ACCOUNT_PROBE; exports.normalizeAccountProbe = normalizeAccountProbe; exports.normalizeAudit = normalizeAudit; exports.normalizeBilling = normalizeBilling; exports.DEFAULT_FINGERPRINT = DEFAULT_FINGERPRINT; exports.normalizeFingerprint = normalizeFingerprint; exports.normalizeVoucher = normalizeVoucher; exports.normalizeProxyConfig = normalizeProxyConfig; exports.normalizeProxySegment = normalizeProxySegment; exports.normalizeWebhookDestination = normalizeWebhookDestination; exports.normalizeWebhookSegment = normalizeWebhookSegment; exports.normalizeQueueSegments = normalizeQueueSegments; exports.normalizePrefixTargets = normalizePrefixTargets; exports.defaultServerConfig = defaultServerConfig; exports.normalizeServerConfig = normalizeServerConfig; exports.loadServerConfig = loadServerConfig; exports.saveServerConfig = saveServerConfig; exports.mergeServerConfig = mergeServerConfig; exports.computeKeyExpiry = computeKeyExpiry; exports.checkKeyQuota = checkKeyQuota; exports.randomBase62 = randomBase62; exports.hashKey = hashKey; exports.createNamedKey = createNamedKey; exports.verifyKey = verifyKey; exports.verifyPresentedKey = verifyPresentedKey; exports.ConcurrencyQueueFullError = ConcurrencyQueueFullError; exports.ConcurrencyWaitTimeoutError = ConcurrencyWaitTimeoutError; exports.ConcurrencyWaitCancelledError = ConcurrencyWaitCancelledError; exports.isConcurrencyRejection = isConcurrencyRejection; exports.OutboundConcurrencyGate = OutboundConcurrencyGate; exports.OutboundRateLimiter = OutboundRateLimiter; exports.isUserMessageRequest = isUserMessageRequest; exports.SerialQueueTimeoutError = SerialQueueTimeoutError; exports.isSerialQueueTimeout = isSerialQueueTimeout; exports.UserMessageSerialQueue = UserMessageSerialQueue; exports.generateVoucherCode = generateVoucherCode; exports.hashVoucherCode = hashVoucherCode; exports.voucherCodePrefix = voucherCodePrefix; exports.newVoucherId = newVoucherId; exports.computeVoucherGrant = computeVoucherGrant; exports.toVoucherInfo = toVoucherInfo; exports.isRedeemRequest = isRedeemRequest; exports.handleVoucherRedeem = handleVoucherRedeem; exports.DEFAULT_OUTBOUND_PORT = DEFAULT_OUTBOUND_PORT; exports.OutboundApiConfigError = OutboundApiConfigError; exports.OutboundApiServer = OutboundApiServer; exports.formatUrls = formatUrls; exports.startOfLocalDay = startOfLocalDay; exports.startOfLocalWeek = startOfLocalWeek; exports.KeySpendTracker = KeySpendTracker; exports.getOutboundApiServer = getOutboundApiServer; exports.__resetOutboundApiServerForTests = __resetOutboundApiServerForTests;
@@ -1,3 +1,9 @@
1
+ import {
2
+ getUpstreamTracePath,
3
+ redactHeaders,
4
+ writeUpstreamTrace
5
+ } from "./chunk-SYQF7OIR.js";
6
+
1
7
  // src/pipeline/upstreamFetch.ts
2
8
  import { Agent, buildConnector, ProxyAgent } from "undici";
3
9
  import { SocksClient } from "socks";
@@ -95,8 +101,60 @@ function resolveUpstreamDispatcher(ctx) {
95
101
  }
96
102
  function fetchUpstream(url, init, ctx) {
97
103
  const dispatcher = resolveUpstreamDispatcher({ ...ctx ?? {}, url });
98
- if (!dispatcher) return fetch(url, init);
99
- return fetch(url, { ...init, dispatcher });
104
+ const doFetch = dispatcher ? () => fetch(url, { ...init, dispatcher }) : () => fetch(url, init);
105
+ const tracePath = getUpstreamTracePath();
106
+ if (!tracePath || !ctx?.providerId) return doFetch();
107
+ const startedAt = Date.now();
108
+ const method = typeof init.method === "string" ? init.method : "GET";
109
+ const requestHeaders = redactHeaders(
110
+ init.headers
111
+ );
112
+ const requestBody = typeof init.body === "string" ? init.body : null;
113
+ const providerId = ctx.providerId;
114
+ const accountId = ctx.accountId;
115
+ return doFetch().then((res) => {
116
+ const clone = res.clone();
117
+ const status = res.status;
118
+ const statusText = res.statusText;
119
+ const responseHeaders = redactHeaders(res.headers);
120
+ void clone.text().then((body) => {
121
+ writeUpstreamTrace({
122
+ ts: startedAt,
123
+ durationMs: Date.now() - startedAt,
124
+ providerId,
125
+ accountId,
126
+ url,
127
+ method,
128
+ requestHeaders,
129
+ requestBody,
130
+ status,
131
+ statusText,
132
+ responseHeaders,
133
+ responseBody: body,
134
+ responseBytes: Buffer.byteLength(body, "utf8")
135
+ });
136
+ }).catch(() => {
137
+ });
138
+ return res;
139
+ }).catch((err) => {
140
+ const msg = err instanceof Error ? err.message : String(err);
141
+ writeUpstreamTrace({
142
+ ts: startedAt,
143
+ durationMs: Date.now() - startedAt,
144
+ providerId,
145
+ accountId,
146
+ url,
147
+ method,
148
+ requestHeaders,
149
+ requestBody,
150
+ status: 0,
151
+ statusText: "",
152
+ responseHeaders: {},
153
+ responseBody: `<UPSTREAM FETCH ERROR: ${msg}>`,
154
+ responseBytes: 0
155
+ });
156
+ throw err;
157
+ });
100
158
  }
101
159
  function __resetUpstreamProxyForTests() {
102
160
  resolver = null;