@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/cli.mjs CHANGED
@@ -1578,12 +1578,19 @@ var StrategySchema = z.object({
1578
1578
  minConfidence: z.number().min(0).max(1).optional(),
1579
1579
  fallback: z.string().optional()
1580
1580
  });
1581
+ var AuthSchema = z.object({
1582
+ anthropicApiKey: z.string().optional(),
1583
+ anthropicMaxToken: z.string().optional(),
1584
+ useMaxForModels: z.array(z.string()).optional()
1585
+ // Default: ['opus']
1586
+ }).optional();
1581
1587
  var ConfigSchema = z.object({
1582
1588
  strategies: z.record(z.string(), StrategySchema).optional(),
1583
1589
  defaults: z.object({
1584
1590
  qualityModel: z.string().optional(),
1585
1591
  costModel: z.string().optional()
1586
- }).optional()
1592
+ }).optional(),
1593
+ auth: AuthSchema
1587
1594
  });
1588
1595
  var DEFAULT_CONFIG = {
1589
1596
  strategies: {
@@ -1643,6 +1650,19 @@ function loadConfig() {
1643
1650
  function getStrategy(config, taskType) {
1644
1651
  return config.strategies?.[taskType] ?? null;
1645
1652
  }
1653
+ function getAnthropicAuth(config, model) {
1654
+ const auth = config.auth;
1655
+ const useMaxForModels = auth?.useMaxForModels ?? ["opus"];
1656
+ const shouldUseMax = useMaxForModels.some((m) => model.toLowerCase().includes(m.toLowerCase()));
1657
+ if (shouldUseMax && auth?.anthropicMaxToken) {
1658
+ return { type: "max", value: auth.anthropicMaxToken };
1659
+ }
1660
+ const apiKey = auth?.anthropicApiKey ?? process.env["ANTHROPIC_API_KEY"];
1661
+ if (apiKey) {
1662
+ return { type: "apiKey", value: apiKey };
1663
+ }
1664
+ return null;
1665
+ }
1646
1666
  function watchConfig(onChange) {
1647
1667
  const configPath = getConfigPath();
1648
1668
  const dir = path2.dirname(configPath);
@@ -1663,7 +1683,7 @@ function watchConfig(onChange) {
1663
1683
  }
1664
1684
 
1665
1685
  // src/proxy.ts
1666
- var VERSION = "0.1.8";
1686
+ var VERSION = "0.1.9";
1667
1687
  var recentRuns = [];
1668
1688
  var MAX_RECENT_RUNS = 100;
1669
1689
  var modelCounts = {};
@@ -1731,13 +1751,17 @@ function extractPromptText(messages) {
1731
1751
  return "";
1732
1752
  }).join("\n");
1733
1753
  }
1734
- async function forwardToAnthropic(request, targetModel, apiKey, betaHeaders) {
1754
+ async function forwardToAnthropic(request, targetModel, auth, betaHeaders) {
1735
1755
  const anthropicBody = buildAnthropicBody(request, targetModel, false);
1736
1756
  const headers = {
1737
1757
  "Content-Type": "application/json",
1738
- "x-api-key": apiKey,
1739
1758
  "anthropic-version": "2023-06-01"
1740
1759
  };
1760
+ if (auth.type === "max") {
1761
+ headers["Authorization"] = `Bearer ${auth.value}`;
1762
+ } else {
1763
+ headers["x-api-key"] = auth.value;
1764
+ }
1741
1765
  if (betaHeaders) {
1742
1766
  headers["anthropic-beta"] = betaHeaders;
1743
1767
  }
@@ -1748,13 +1772,17 @@ async function forwardToAnthropic(request, targetModel, apiKey, betaHeaders) {
1748
1772
  });
1749
1773
  return response;
1750
1774
  }
1751
- async function forwardToAnthropicStream(request, targetModel, apiKey, betaHeaders) {
1775
+ async function forwardToAnthropicStream(request, targetModel, auth, betaHeaders) {
1752
1776
  const anthropicBody = buildAnthropicBody(request, targetModel, true);
1753
1777
  const headers = {
1754
1778
  "Content-Type": "application/json",
1755
- "x-api-key": apiKey,
1756
1779
  "anthropic-version": "2023-06-01"
1757
1780
  };
1781
+ if (auth.type === "max") {
1782
+ headers["Authorization"] = `Bearer ${auth.value}`;
1783
+ } else {
1784
+ headers["x-api-key"] = auth.value;
1785
+ }
1758
1786
  if (betaHeaders) {
1759
1787
  headers["anthropic-beta"] = betaHeaders;
1760
1788
  }
@@ -2560,12 +2588,24 @@ async function startProxy(config = {}) {
2560
2588
  }
2561
2589
  }
2562
2590
  log(`Routing to: ${targetProvider}/${targetModel}`);
2563
- const apiKeyEnv = DEFAULT_ENDPOINTS[targetProvider]?.apiKeyEnv ?? `${targetProvider.toUpperCase()}_API_KEY`;
2564
- const apiKey = process.env[apiKeyEnv];
2565
- if (!apiKey) {
2566
- res.writeHead(500, { "Content-Type": "application/json" });
2567
- res.end(JSON.stringify({ error: `Missing ${apiKeyEnv} environment variable` }));
2568
- return;
2591
+ let apiKey;
2592
+ let anthropicAuth = null;
2593
+ if (targetProvider === "anthropic") {
2594
+ anthropicAuth = getAnthropicAuth(currentConfig, targetModel);
2595
+ if (!anthropicAuth) {
2596
+ res.writeHead(500, { "Content-Type": "application/json" });
2597
+ res.end(JSON.stringify({ error: "No Anthropic auth configured (set ANTHROPIC_API_KEY or config.auth.anthropicMaxToken)" }));
2598
+ return;
2599
+ }
2600
+ log(`Using ${anthropicAuth.type === "max" ? "MAX token" : "API key"} auth for ${targetModel}`);
2601
+ } else {
2602
+ const apiKeyEnv = DEFAULT_ENDPOINTS[targetProvider]?.apiKeyEnv ?? `${targetProvider.toUpperCase()}_API_KEY`;
2603
+ apiKey = process.env[apiKeyEnv];
2604
+ if (!apiKey) {
2605
+ res.writeHead(500, { "Content-Type": "application/json" });
2606
+ res.end(JSON.stringify({ error: `Missing ${apiKeyEnv} environment variable` }));
2607
+ return;
2608
+ }
2569
2609
  }
2570
2610
  const startTime = Date.now();
2571
2611
  const betaHeaders = req.headers["anthropic-beta"];
@@ -2576,6 +2616,7 @@ async function startProxy(config = {}) {
2576
2616
  targetProvider,
2577
2617
  targetModel,
2578
2618
  apiKey,
2619
+ anthropicAuth,
2579
2620
  relay,
2580
2621
  promptText,
2581
2622
  taskType,
@@ -2592,6 +2633,7 @@ async function startProxy(config = {}) {
2592
2633
  targetProvider,
2593
2634
  targetModel,
2594
2635
  apiKey,
2636
+ anthropicAuth,
2595
2637
  relay,
2596
2638
  promptText,
2597
2639
  taskType,
@@ -2621,12 +2663,13 @@ async function startProxy(config = {}) {
2621
2663
  });
2622
2664
  });
2623
2665
  }
2624
- async function handleStreamingRequest(res, request, targetProvider, targetModel, apiKey, relay, promptText, taskType, confidence, routingMode, startTime, log, betaHeaders) {
2666
+ async function handleStreamingRequest(res, request, targetProvider, targetModel, apiKey, anthropicAuth, relay, promptText, taskType, confidence, routingMode, startTime, log, betaHeaders) {
2625
2667
  let providerResponse;
2626
2668
  try {
2627
2669
  switch (targetProvider) {
2628
2670
  case "anthropic":
2629
- providerResponse = await forwardToAnthropicStream(request, targetModel, apiKey, betaHeaders);
2671
+ if (!anthropicAuth) throw new Error("No Anthropic auth");
2672
+ providerResponse = await forwardToAnthropicStream(request, targetModel, anthropicAuth, betaHeaders);
2630
2673
  break;
2631
2674
  case "google":
2632
2675
  providerResponse = await forwardToGeminiStream(request, targetModel, apiKey);
@@ -2704,13 +2747,14 @@ async function handleStreamingRequest(res, request, targetProvider, targetModel,
2704
2747
  });
2705
2748
  res.end();
2706
2749
  }
2707
- async function handleNonStreamingRequest(res, request, targetProvider, targetModel, apiKey, relay, promptText, taskType, confidence, routingMode, startTime, log, betaHeaders) {
2750
+ async function handleNonStreamingRequest(res, request, targetProvider, targetModel, apiKey, anthropicAuth, relay, promptText, taskType, confidence, routingMode, startTime, log, betaHeaders) {
2708
2751
  let providerResponse;
2709
2752
  let responseData;
2710
2753
  try {
2711
2754
  switch (targetProvider) {
2712
2755
  case "anthropic": {
2713
- providerResponse = await forwardToAnthropic(request, targetModel, apiKey, betaHeaders);
2756
+ if (!anthropicAuth) throw new Error("No Anthropic auth");
2757
+ providerResponse = await forwardToAnthropic(request, targetModel, anthropicAuth, betaHeaders);
2714
2758
  const rawData = await providerResponse.json();
2715
2759
  if (!providerResponse.ok) {
2716
2760
  res.writeHead(providerResponse.status, { "Content-Type": "application/json" });