@relayplane/proxy 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1580,12 +1580,19 @@ var StrategySchema = z.object({
1580
1580
  minConfidence: z.number().min(0).max(1).optional(),
1581
1581
  fallback: z.string().optional()
1582
1582
  });
1583
+ var AuthSchema = z.object({
1584
+ anthropicApiKey: z.string().optional(),
1585
+ anthropicMaxToken: z.string().optional(),
1586
+ useMaxForModels: z.array(z.string()).optional()
1587
+ // Default: ['opus']
1588
+ }).optional();
1583
1589
  var ConfigSchema = z.object({
1584
1590
  strategies: z.record(z.string(), StrategySchema).optional(),
1585
1591
  defaults: z.object({
1586
1592
  qualityModel: z.string().optional(),
1587
1593
  costModel: z.string().optional()
1588
- }).optional()
1594
+ }).optional(),
1595
+ auth: AuthSchema
1589
1596
  });
1590
1597
  var DEFAULT_CONFIG = {
1591
1598
  strategies: {
@@ -1645,6 +1652,19 @@ function loadConfig() {
1645
1652
  function getStrategy(config, taskType) {
1646
1653
  return config.strategies?.[taskType] ?? null;
1647
1654
  }
1655
+ function getAnthropicAuth(config, model) {
1656
+ const auth = config.auth;
1657
+ const useMaxForModels = auth?.useMaxForModels ?? ["opus"];
1658
+ const shouldUseMax = useMaxForModels.some((m) => model.toLowerCase().includes(m.toLowerCase()));
1659
+ if (shouldUseMax && auth?.anthropicMaxToken) {
1660
+ return { type: "max", value: auth.anthropicMaxToken };
1661
+ }
1662
+ const apiKey = auth?.anthropicApiKey ?? process.env["ANTHROPIC_API_KEY"];
1663
+ if (apiKey) {
1664
+ return { type: "apiKey", value: apiKey };
1665
+ }
1666
+ return null;
1667
+ }
1648
1668
  function watchConfig(onChange) {
1649
1669
  const configPath = getConfigPath();
1650
1670
  const dir = path2.dirname(configPath);
@@ -1665,7 +1685,7 @@ function watchConfig(onChange) {
1665
1685
  }
1666
1686
 
1667
1687
  // src/proxy.ts
1668
- var VERSION = "0.1.8";
1688
+ var VERSION = "0.1.9";
1669
1689
  var recentRuns = [];
1670
1690
  var MAX_RECENT_RUNS = 100;
1671
1691
  var modelCounts = {};
@@ -1733,13 +1753,17 @@ function extractPromptText(messages) {
1733
1753
  return "";
1734
1754
  }).join("\n");
1735
1755
  }
1736
- async function forwardToAnthropic(request, targetModel, apiKey, betaHeaders) {
1756
+ async function forwardToAnthropic(request, targetModel, auth, betaHeaders) {
1737
1757
  const anthropicBody = buildAnthropicBody(request, targetModel, false);
1738
1758
  const headers = {
1739
1759
  "Content-Type": "application/json",
1740
- "x-api-key": apiKey,
1741
1760
  "anthropic-version": "2023-06-01"
1742
1761
  };
1762
+ if (auth.type === "max") {
1763
+ headers["Authorization"] = `Bearer ${auth.value}`;
1764
+ } else {
1765
+ headers["x-api-key"] = auth.value;
1766
+ }
1743
1767
  if (betaHeaders) {
1744
1768
  headers["anthropic-beta"] = betaHeaders;
1745
1769
  }
@@ -1750,13 +1774,17 @@ async function forwardToAnthropic(request, targetModel, apiKey, betaHeaders) {
1750
1774
  });
1751
1775
  return response;
1752
1776
  }
1753
- async function forwardToAnthropicStream(request, targetModel, apiKey, betaHeaders) {
1777
+ async function forwardToAnthropicStream(request, targetModel, auth, betaHeaders) {
1754
1778
  const anthropicBody = buildAnthropicBody(request, targetModel, true);
1755
1779
  const headers = {
1756
1780
  "Content-Type": "application/json",
1757
- "x-api-key": apiKey,
1758
1781
  "anthropic-version": "2023-06-01"
1759
1782
  };
1783
+ if (auth.type === "max") {
1784
+ headers["Authorization"] = `Bearer ${auth.value}`;
1785
+ } else {
1786
+ headers["x-api-key"] = auth.value;
1787
+ }
1760
1788
  if (betaHeaders) {
1761
1789
  headers["anthropic-beta"] = betaHeaders;
1762
1790
  }
@@ -2562,12 +2590,24 @@ async function startProxy(config = {}) {
2562
2590
  }
2563
2591
  }
2564
2592
  log(`Routing to: ${targetProvider}/${targetModel}`);
2565
- const apiKeyEnv = DEFAULT_ENDPOINTS[targetProvider]?.apiKeyEnv ?? `${targetProvider.toUpperCase()}_API_KEY`;
2566
- const apiKey = process.env[apiKeyEnv];
2567
- if (!apiKey) {
2568
- res.writeHead(500, { "Content-Type": "application/json" });
2569
- res.end(JSON.stringify({ error: `Missing ${apiKeyEnv} environment variable` }));
2570
- return;
2593
+ let apiKey;
2594
+ let anthropicAuth = null;
2595
+ if (targetProvider === "anthropic") {
2596
+ anthropicAuth = getAnthropicAuth(currentConfig, targetModel);
2597
+ if (!anthropicAuth) {
2598
+ res.writeHead(500, { "Content-Type": "application/json" });
2599
+ res.end(JSON.stringify({ error: "No Anthropic auth configured (set ANTHROPIC_API_KEY or config.auth.anthropicMaxToken)" }));
2600
+ return;
2601
+ }
2602
+ log(`Using ${anthropicAuth.type === "max" ? "MAX token" : "API key"} auth for ${targetModel}`);
2603
+ } else {
2604
+ const apiKeyEnv = DEFAULT_ENDPOINTS[targetProvider]?.apiKeyEnv ?? `${targetProvider.toUpperCase()}_API_KEY`;
2605
+ apiKey = process.env[apiKeyEnv];
2606
+ if (!apiKey) {
2607
+ res.writeHead(500, { "Content-Type": "application/json" });
2608
+ res.end(JSON.stringify({ error: `Missing ${apiKeyEnv} environment variable` }));
2609
+ return;
2610
+ }
2571
2611
  }
2572
2612
  const startTime = Date.now();
2573
2613
  const betaHeaders = req.headers["anthropic-beta"];
@@ -2578,6 +2618,7 @@ async function startProxy(config = {}) {
2578
2618
  targetProvider,
2579
2619
  targetModel,
2580
2620
  apiKey,
2621
+ anthropicAuth,
2581
2622
  relay,
2582
2623
  promptText,
2583
2624
  taskType,
@@ -2594,6 +2635,7 @@ async function startProxy(config = {}) {
2594
2635
  targetProvider,
2595
2636
  targetModel,
2596
2637
  apiKey,
2638
+ anthropicAuth,
2597
2639
  relay,
2598
2640
  promptText,
2599
2641
  taskType,
@@ -2623,12 +2665,13 @@ async function startProxy(config = {}) {
2623
2665
  });
2624
2666
  });
2625
2667
  }
2626
- async function handleStreamingRequest(res, request, targetProvider, targetModel, apiKey, relay, promptText, taskType, confidence, routingMode, startTime, log, betaHeaders) {
2668
+ async function handleStreamingRequest(res, request, targetProvider, targetModel, apiKey, anthropicAuth, relay, promptText, taskType, confidence, routingMode, startTime, log, betaHeaders) {
2627
2669
  let providerResponse;
2628
2670
  try {
2629
2671
  switch (targetProvider) {
2630
2672
  case "anthropic":
2631
- providerResponse = await forwardToAnthropicStream(request, targetModel, apiKey, betaHeaders);
2673
+ if (!anthropicAuth) throw new Error("No Anthropic auth");
2674
+ providerResponse = await forwardToAnthropicStream(request, targetModel, anthropicAuth, betaHeaders);
2632
2675
  break;
2633
2676
  case "google":
2634
2677
  providerResponse = await forwardToGeminiStream(request, targetModel, apiKey);
@@ -2706,13 +2749,14 @@ async function handleStreamingRequest(res, request, targetProvider, targetModel,
2706
2749
  });
2707
2750
  res.end();
2708
2751
  }
2709
- async function handleNonStreamingRequest(res, request, targetProvider, targetModel, apiKey, relay, promptText, taskType, confidence, routingMode, startTime, log, betaHeaders) {
2752
+ async function handleNonStreamingRequest(res, request, targetProvider, targetModel, apiKey, anthropicAuth, relay, promptText, taskType, confidence, routingMode, startTime, log, betaHeaders) {
2710
2753
  let providerResponse;
2711
2754
  let responseData;
2712
2755
  try {
2713
2756
  switch (targetProvider) {
2714
2757
  case "anthropic": {
2715
- providerResponse = await forwardToAnthropic(request, targetModel, apiKey, betaHeaders);
2758
+ if (!anthropicAuth) throw new Error("No Anthropic auth");
2759
+ providerResponse = await forwardToAnthropic(request, targetModel, anthropicAuth, betaHeaders);
2716
2760
  const rawData = await providerResponse.json();
2717
2761
  if (!providerResponse.ok) {
2718
2762
  res.writeHead(providerResponse.status, { "Content-Type": "application/json" });