@relayplane/proxy 0.1.6 → 0.1.8

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.js CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ DEFAULT_CONFIG: () => DEFAULT_CONFIG,
33
34
  DEFAULT_ENDPOINTS: () => DEFAULT_ENDPOINTS,
34
35
  MODEL_MAPPING: () => MODEL_MAPPING,
35
36
  MODEL_PRICING: () => MODEL_PRICING,
@@ -44,15 +45,20 @@ __export(index_exports, {
44
45
  TaskTypes: () => TaskTypes,
45
46
  calculateCost: () => calculateCost,
46
47
  calculateSavings: () => calculateSavings,
48
+ getConfigPath: () => getConfigPath,
47
49
  getInferenceConfidence: () => getInferenceConfidence,
48
50
  getModelPricing: () => getModelPricing,
51
+ getStrategy: () => getStrategy,
49
52
  inferTaskType: () => inferTaskType,
50
- startProxy: () => startProxy
53
+ loadConfig: () => loadConfig,
54
+ startProxy: () => startProxy,
55
+ watchConfig: () => watchConfig
51
56
  });
52
57
  module.exports = __toCommonJS(index_exports);
53
58
 
54
59
  // src/proxy.ts
55
60
  var http = __toESM(require("http"));
61
+ var url = __toESM(require("url"));
56
62
 
57
63
  // src/storage/store.ts
58
64
  var import_better_sqlite3 = __toESM(require("better-sqlite3"));
@@ -1622,7 +1628,107 @@ ${input.prompt}` : input.prompt;
1622
1628
  }
1623
1629
  };
1624
1630
 
1631
+ // src/config.ts
1632
+ var fs2 = __toESM(require("fs"));
1633
+ var path2 = __toESM(require("path"));
1634
+ var os2 = __toESM(require("os"));
1635
+ var import_zod = require("zod");
1636
+ var StrategySchema = import_zod.z.object({
1637
+ model: import_zod.z.string(),
1638
+ minConfidence: import_zod.z.number().min(0).max(1).optional(),
1639
+ fallback: import_zod.z.string().optional()
1640
+ });
1641
+ var ConfigSchema = import_zod.z.object({
1642
+ strategies: import_zod.z.record(import_zod.z.string(), StrategySchema).optional(),
1643
+ defaults: import_zod.z.object({
1644
+ qualityModel: import_zod.z.string().optional(),
1645
+ costModel: import_zod.z.string().optional()
1646
+ }).optional()
1647
+ });
1648
+ var DEFAULT_CONFIG = {
1649
+ strategies: {
1650
+ code_review: { model: "anthropic:claude-sonnet-4-20250514" },
1651
+ code_generation: { model: "anthropic:claude-3-5-haiku-latest" },
1652
+ analysis: { model: "anthropic:claude-sonnet-4-20250514" },
1653
+ summarization: { model: "anthropic:claude-3-5-haiku-latest" },
1654
+ creative_writing: { model: "anthropic:claude-sonnet-4-20250514" },
1655
+ data_extraction: { model: "anthropic:claude-3-5-haiku-latest" },
1656
+ translation: { model: "anthropic:claude-3-5-haiku-latest" },
1657
+ question_answering: { model: "anthropic:claude-3-5-haiku-latest" },
1658
+ general: { model: "anthropic:claude-3-5-haiku-latest" }
1659
+ },
1660
+ defaults: {
1661
+ qualityModel: "claude-sonnet-4-20250514",
1662
+ costModel: "claude-3-5-haiku-latest"
1663
+ }
1664
+ };
1665
+ function getConfigPath() {
1666
+ return path2.join(os2.homedir(), ".relayplane", "config.json");
1667
+ }
1668
+ function writeDefaultConfig() {
1669
+ const configPath = getConfigPath();
1670
+ const dir = path2.dirname(configPath);
1671
+ if (!fs2.existsSync(dir)) {
1672
+ fs2.mkdirSync(dir, { recursive: true });
1673
+ }
1674
+ if (!fs2.existsSync(configPath)) {
1675
+ fs2.writeFileSync(
1676
+ configPath,
1677
+ JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n",
1678
+ "utf-8"
1679
+ );
1680
+ console.log(`[relayplane] Created default config at ${configPath}`);
1681
+ }
1682
+ }
1683
+ function loadConfig() {
1684
+ const configPath = getConfigPath();
1685
+ writeDefaultConfig();
1686
+ try {
1687
+ const raw = fs2.readFileSync(configPath, "utf-8");
1688
+ const parsed = JSON.parse(raw);
1689
+ const validated = ConfigSchema.parse(parsed);
1690
+ return validated;
1691
+ } catch (err) {
1692
+ if (err instanceof import_zod.z.ZodError) {
1693
+ console.error(`[relayplane] Invalid config: ${err.message}`);
1694
+ } else if (err instanceof SyntaxError) {
1695
+ console.error(`[relayplane] Config JSON parse error: ${err.message}`);
1696
+ } else {
1697
+ console.error(`[relayplane] Failed to load config: ${err}`);
1698
+ }
1699
+ console.log("[relayplane] Using default config");
1700
+ return DEFAULT_CONFIG;
1701
+ }
1702
+ }
1703
+ function getStrategy(config, taskType) {
1704
+ return config.strategies?.[taskType] ?? null;
1705
+ }
1706
+ function watchConfig(onChange) {
1707
+ const configPath = getConfigPath();
1708
+ const dir = path2.dirname(configPath);
1709
+ if (!fs2.existsSync(dir)) {
1710
+ fs2.mkdirSync(dir, { recursive: true });
1711
+ }
1712
+ let debounceTimer = null;
1713
+ fs2.watch(dir, (eventType, filename) => {
1714
+ if (filename === "config.json") {
1715
+ if (debounceTimer) clearTimeout(debounceTimer);
1716
+ debounceTimer = setTimeout(() => {
1717
+ console.log("[relayplane] Config file changed, reloading...");
1718
+ const newConfig = loadConfig();
1719
+ onChange(newConfig);
1720
+ }, 100);
1721
+ }
1722
+ });
1723
+ }
1724
+
1625
1725
  // src/proxy.ts
1726
+ var VERSION = "0.1.8";
1727
+ var recentRuns = [];
1728
+ var MAX_RECENT_RUNS = 100;
1729
+ var modelCounts = {};
1730
+ var serverStartTime = 0;
1731
+ var currentConfig = loadConfig();
1626
1732
  var DEFAULT_ENDPOINTS = {
1627
1733
  anthropic: {
1628
1734
  baseUrl: "https://api.anthropic.com/v1",
@@ -1919,9 +2025,9 @@ function convertMessagesToGemini(messages) {
1919
2025
  return { text: p.text };
1920
2026
  }
1921
2027
  if (p.type === "image_url" && p.image_url?.url) {
1922
- const url = p.image_url.url;
1923
- if (url.startsWith("data:")) {
1924
- const match = url.match(/^data:([^;]+);base64,(.+)$/);
2028
+ const url2 = p.image_url.url;
2029
+ if (url2.startsWith("data:")) {
2030
+ const match = url2.match(/^data:([^;]+);base64,(.+)$/);
1925
2031
  if (match) {
1926
2032
  return {
1927
2033
  inline_data: {
@@ -1931,7 +2037,7 @@ function convertMessagesToGemini(messages) {
1931
2037
  };
1932
2038
  }
1933
2039
  }
1934
- return { text: `[Image: ${url}]` };
2040
+ return { text: `[Image: ${url2}]` };
1935
2041
  }
1936
2042
  return { text: "" };
1937
2043
  });
@@ -2345,28 +2451,88 @@ async function startProxy(config = {}) {
2345
2451
  };
2346
2452
  const server = http.createServer(async (req, res) => {
2347
2453
  res.setHeader("Access-Control-Allow-Origin", "*");
2348
- res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
2454
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
2349
2455
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
2350
2456
  if (req.method === "OPTIONS") {
2351
2457
  res.writeHead(204);
2352
2458
  res.end();
2353
2459
  return;
2354
2460
  }
2355
- if (req.method !== "POST" || !req.url?.includes("/chat/completions")) {
2356
- if (req.method === "GET" && req.url?.includes("/models")) {
2357
- res.writeHead(200, { "Content-Type": "application/json" });
2358
- res.end(
2359
- JSON.stringify({
2360
- object: "list",
2361
- data: [
2362
- { id: "relayplane:auto", object: "model", owned_by: "relayplane" },
2363
- { id: "relayplane:cost", object: "model", owned_by: "relayplane" },
2364
- { id: "relayplane:quality", object: "model", owned_by: "relayplane" }
2365
- ]
2366
- })
2367
- );
2368
- return;
2461
+ const parsedUrl = url.parse(req.url || "", true);
2462
+ const pathname = parsedUrl.pathname || "";
2463
+ if (req.method === "GET" && pathname === "/health") {
2464
+ const uptimeMs = Date.now() - serverStartTime;
2465
+ const uptimeSecs = Math.floor(uptimeMs / 1e3);
2466
+ const hours = Math.floor(uptimeSecs / 3600);
2467
+ const mins = Math.floor(uptimeSecs % 3600 / 60);
2468
+ const secs = uptimeSecs % 60;
2469
+ const providers = {};
2470
+ for (const [name, config2] of Object.entries(DEFAULT_ENDPOINTS)) {
2471
+ providers[name] = !!process.env[config2.apiKeyEnv];
2472
+ }
2473
+ res.writeHead(200, { "Content-Type": "application/json" });
2474
+ res.end(JSON.stringify({
2475
+ status: "ok",
2476
+ version: VERSION,
2477
+ uptime: `${hours}h ${mins}m ${secs}s`,
2478
+ uptimeMs,
2479
+ providers,
2480
+ totalRuns: recentRuns.length > 0 ? Object.values(modelCounts).reduce((a, b) => a + b, 0) : 0
2481
+ }));
2482
+ return;
2483
+ }
2484
+ if (req.method === "GET" && pathname === "/stats") {
2485
+ const stats = relay.stats();
2486
+ const savings = relay.savingsReport(30);
2487
+ const totalRuns = Object.values(modelCounts).reduce((a, b) => a + b, 0);
2488
+ const modelDistribution = {};
2489
+ for (const [model, count] of Object.entries(modelCounts)) {
2490
+ modelDistribution[model] = {
2491
+ count,
2492
+ percentage: totalRuns > 0 ? (count / totalRuns * 100).toFixed(1) + "%" : "0%"
2493
+ };
2369
2494
  }
2495
+ res.writeHead(200, { "Content-Type": "application/json" });
2496
+ res.end(JSON.stringify({
2497
+ totalRuns,
2498
+ savings: {
2499
+ estimatedSavingsPercent: savings.savingsPercent.toFixed(1) + "%",
2500
+ actualCostUsd: savings.actualCost.toFixed(4),
2501
+ baselineCostUsd: savings.baselineCost.toFixed(4),
2502
+ savedUsd: savings.savings.toFixed(4)
2503
+ },
2504
+ modelDistribution,
2505
+ byTaskType: stats.byTaskType,
2506
+ period: stats.period
2507
+ }));
2508
+ return;
2509
+ }
2510
+ if (req.method === "GET" && pathname === "/runs") {
2511
+ const limitParam = parsedUrl.query["limit"];
2512
+ const parsedLimit = limitParam ? parseInt(String(limitParam), 10) : 20;
2513
+ const limit = Math.min(Number.isNaN(parsedLimit) ? 20 : parsedLimit, MAX_RECENT_RUNS);
2514
+ res.writeHead(200, { "Content-Type": "application/json" });
2515
+ res.end(JSON.stringify({
2516
+ runs: recentRuns.slice(0, limit),
2517
+ total: recentRuns.length
2518
+ }));
2519
+ return;
2520
+ }
2521
+ if (req.method === "GET" && pathname.includes("/models")) {
2522
+ res.writeHead(200, { "Content-Type": "application/json" });
2523
+ res.end(
2524
+ JSON.stringify({
2525
+ object: "list",
2526
+ data: [
2527
+ { id: "relayplane:auto", object: "model", owned_by: "relayplane" },
2528
+ { id: "relayplane:cost", object: "model", owned_by: "relayplane" },
2529
+ { id: "relayplane:quality", object: "model", owned_by: "relayplane" }
2530
+ ]
2531
+ })
2532
+ );
2533
+ return;
2534
+ }
2535
+ if (req.method !== "POST" || !pathname.includes("/chat/completions")) {
2370
2536
  res.writeHead(404, { "Content-Type": "application/json" });
2371
2537
  res.end(JSON.stringify({ error: "Not found" }));
2372
2538
  return;
@@ -2413,33 +2579,44 @@ async function startProxy(config = {}) {
2413
2579
  const confidence = getInferenceConfidence(promptText, taskType);
2414
2580
  log(`Inferred task: ${taskType} (confidence: ${confidence.toFixed(2)})`);
2415
2581
  if (routingMode !== "passthrough") {
2416
- const rule = relay.routing.get(taskType);
2417
- if (rule && rule.preferredModel) {
2418
- const parsed = parsePreferredModel(rule.preferredModel);
2582
+ const configStrategy = getStrategy(currentConfig, taskType);
2583
+ if (configStrategy) {
2584
+ const parsed = parsePreferredModel(configStrategy.model);
2419
2585
  if (parsed) {
2420
2586
  targetProvider = parsed.provider;
2421
2587
  targetModel = parsed.model;
2422
- log(`Using learned rule: ${rule.preferredModel}`);
2588
+ log(`Using config strategy: ${configStrategy.model}`);
2589
+ }
2590
+ }
2591
+ if (!configStrategy) {
2592
+ const rule = relay.routing.get(taskType);
2593
+ if (rule && rule.preferredModel) {
2594
+ const parsed = parsePreferredModel(rule.preferredModel);
2595
+ if (parsed) {
2596
+ targetProvider = parsed.provider;
2597
+ targetModel = parsed.model;
2598
+ log(`Using learned rule: ${rule.preferredModel}`);
2599
+ } else {
2600
+ const defaultRoute = DEFAULT_ROUTING[taskType];
2601
+ targetProvider = defaultRoute.provider;
2602
+ targetModel = defaultRoute.model;
2603
+ }
2423
2604
  } else {
2424
2605
  const defaultRoute = DEFAULT_ROUTING[taskType];
2425
2606
  targetProvider = defaultRoute.provider;
2426
2607
  targetModel = defaultRoute.model;
2427
2608
  }
2428
- } else {
2429
- const defaultRoute = DEFAULT_ROUTING[taskType];
2430
- targetProvider = defaultRoute.provider;
2431
- targetModel = defaultRoute.model;
2432
2609
  }
2433
2610
  if (routingMode === "cost") {
2434
- const simpleTasks = ["summarization", "data_extraction", "translation", "question_answering"];
2435
- if (simpleTasks.includes(taskType)) {
2436
- targetModel = "claude-3-5-haiku-latest";
2437
- targetProvider = "anthropic";
2438
- }
2611
+ const costModel = currentConfig.defaults?.costModel || "claude-3-5-haiku-latest";
2612
+ targetModel = costModel;
2613
+ targetProvider = "anthropic";
2614
+ log(`Cost mode: using ${costModel}`);
2439
2615
  } else if (routingMode === "quality") {
2440
- const qualityModel = process.env["RELAYPLANE_QUALITY_MODEL"] || "claude-sonnet-4-20250514";
2616
+ const qualityModel = currentConfig.defaults?.qualityModel || process.env["RELAYPLANE_QUALITY_MODEL"] || "claude-sonnet-4-20250514";
2441
2617
  targetModel = qualityModel;
2442
2618
  targetProvider = "anthropic";
2619
+ log(`Quality mode: using ${qualityModel}`);
2443
2620
  }
2444
2621
  }
2445
2622
  log(`Routing to: ${targetProvider}/${targetModel}`);
@@ -2486,12 +2663,19 @@ async function startProxy(config = {}) {
2486
2663
  );
2487
2664
  }
2488
2665
  });
2666
+ watchConfig((newConfig) => {
2667
+ currentConfig = newConfig;
2668
+ console.log("[relayplane] Config reloaded");
2669
+ });
2489
2670
  return new Promise((resolve, reject) => {
2490
2671
  server.on("error", reject);
2491
2672
  server.listen(port, host, () => {
2673
+ serverStartTime = Date.now();
2492
2674
  console.log(`RelayPlane proxy listening on http://${host}:${port}`);
2493
2675
  console.log(` Models: relayplane:auto, relayplane:cost, relayplane:quality`);
2494
2676
  console.log(` Endpoint: POST /v1/chat/completions`);
2677
+ console.log(` Stats: GET /stats, /runs, /health`);
2678
+ console.log(` Config: ~/.relayplane/config.json (hot-reload enabled)`);
2495
2679
  console.log(` Streaming: \u2705 Enabled`);
2496
2680
  resolve(server);
2497
2681
  });
@@ -2554,11 +2738,26 @@ async function handleStreamingRequest(res, request, targetProvider, targetModel,
2554
2738
  log(`Streaming error: ${err}`);
2555
2739
  }
2556
2740
  const durationMs = Date.now() - startTime;
2741
+ const modelKey = `${targetProvider}/${targetModel}`;
2742
+ modelCounts[modelKey] = (modelCounts[modelKey] || 0) + 1;
2557
2743
  relay.run({
2558
2744
  prompt: promptText.slice(0, 500),
2559
2745
  taskType,
2560
2746
  model: `${targetProvider}:${targetModel}`
2561
2747
  }).then((runResult) => {
2748
+ recentRuns.unshift({
2749
+ runId: runResult.runId,
2750
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2751
+ model: modelKey,
2752
+ taskType,
2753
+ confidence,
2754
+ mode: routingMode,
2755
+ durationMs,
2756
+ promptPreview: promptText.slice(0, 100) + (promptText.length > 100 ? "..." : "")
2757
+ });
2758
+ if (recentRuns.length > MAX_RECENT_RUNS) {
2759
+ recentRuns.pop();
2760
+ }
2562
2761
  log(`Completed streaming in ${durationMs}ms, runId: ${runResult.runId}`);
2563
2762
  }).catch((err) => {
2564
2763
  log(`Failed to record run: ${err}`);
@@ -2629,15 +2828,30 @@ async function handleNonStreamingRequest(res, request, targetProvider, targetMod
2629
2828
  return;
2630
2829
  }
2631
2830
  const durationMs = Date.now() - startTime;
2831
+ const modelKey = `${targetProvider}/${targetModel}`;
2832
+ modelCounts[modelKey] = (modelCounts[modelKey] || 0) + 1;
2632
2833
  try {
2633
2834
  const runResult = await relay.run({
2634
2835
  prompt: promptText.slice(0, 500),
2635
2836
  taskType,
2636
2837
  model: `${targetProvider}:${targetModel}`
2637
2838
  });
2839
+ recentRuns.unshift({
2840
+ runId: runResult.runId,
2841
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2842
+ model: modelKey,
2843
+ taskType,
2844
+ confidence,
2845
+ mode: routingMode,
2846
+ durationMs,
2847
+ promptPreview: promptText.slice(0, 100) + (promptText.length > 100 ? "..." : "")
2848
+ });
2849
+ if (recentRuns.length > MAX_RECENT_RUNS) {
2850
+ recentRuns.pop();
2851
+ }
2638
2852
  responseData["_relayplane"] = {
2639
2853
  runId: runResult.runId,
2640
- routedTo: `${targetProvider}/${targetModel}`,
2854
+ routedTo: modelKey,
2641
2855
  taskType,
2642
2856
  confidence,
2643
2857
  durationMs,
@@ -2652,7 +2866,7 @@ async function handleNonStreamingRequest(res, request, targetProvider, targetMod
2652
2866
  }
2653
2867
 
2654
2868
  // src/types.ts
2655
- var import_zod = require("zod");
2869
+ var import_zod2 = require("zod");
2656
2870
  var TaskTypes = [
2657
2871
  "code_generation",
2658
2872
  "code_review",
@@ -2664,64 +2878,65 @@ var TaskTypes = [
2664
2878
  "question_answering",
2665
2879
  "general"
2666
2880
  ];
2667
- var TaskTypeSchema = import_zod.z.enum(TaskTypes);
2881
+ var TaskTypeSchema = import_zod2.z.enum(TaskTypes);
2668
2882
  var Providers = ["openai", "anthropic", "google", "xai", "moonshot", "local"];
2669
- var ProviderSchema = import_zod.z.enum(Providers);
2670
- var RelayPlaneConfigSchema = import_zod.z.object({
2671
- dbPath: import_zod.z.string().optional(),
2672
- providers: import_zod.z.record(ProviderSchema, import_zod.z.object({
2673
- apiKey: import_zod.z.string().optional(),
2674
- baseUrl: import_zod.z.string().optional()
2883
+ var ProviderSchema = import_zod2.z.enum(Providers);
2884
+ var RelayPlaneConfigSchema = import_zod2.z.object({
2885
+ dbPath: import_zod2.z.string().optional(),
2886
+ providers: import_zod2.z.record(ProviderSchema, import_zod2.z.object({
2887
+ apiKey: import_zod2.z.string().optional(),
2888
+ baseUrl: import_zod2.z.string().optional()
2675
2889
  })).optional(),
2676
2890
  defaultProvider: ProviderSchema.optional(),
2677
- defaultModel: import_zod.z.string().optional()
2891
+ defaultModel: import_zod2.z.string().optional()
2678
2892
  });
2679
- var RunInputSchema = import_zod.z.object({
2680
- prompt: import_zod.z.string().min(1),
2681
- systemPrompt: import_zod.z.string().optional(),
2893
+ var RunInputSchema = import_zod2.z.object({
2894
+ prompt: import_zod2.z.string().min(1),
2895
+ systemPrompt: import_zod2.z.string().optional(),
2682
2896
  taskType: TaskTypeSchema.optional(),
2683
- model: import_zod.z.string().optional(),
2684
- metadata: import_zod.z.record(import_zod.z.unknown()).optional()
2897
+ model: import_zod2.z.string().optional(),
2898
+ metadata: import_zod2.z.record(import_zod2.z.unknown()).optional()
2685
2899
  });
2686
2900
  var RuleSources = ["default", "user", "learned"];
2687
- var RoutingRuleSchema = import_zod.z.object({
2688
- id: import_zod.z.string(),
2901
+ var RoutingRuleSchema = import_zod2.z.object({
2902
+ id: import_zod2.z.string(),
2689
2903
  taskType: TaskTypeSchema,
2690
- preferredModel: import_zod.z.string(),
2691
- source: import_zod.z.enum(RuleSources),
2692
- confidence: import_zod.z.number().min(0).max(1).optional(),
2693
- sampleCount: import_zod.z.number().int().positive().optional(),
2694
- createdAt: import_zod.z.string(),
2695
- updatedAt: import_zod.z.string()
2904
+ preferredModel: import_zod2.z.string(),
2905
+ source: import_zod2.z.enum(RuleSources),
2906
+ confidence: import_zod2.z.number().min(0).max(1).optional(),
2907
+ sampleCount: import_zod2.z.number().int().positive().optional(),
2908
+ createdAt: import_zod2.z.string(),
2909
+ updatedAt: import_zod2.z.string()
2696
2910
  });
2697
2911
  var OutcomeQualities = ["excellent", "good", "acceptable", "poor", "failed"];
2698
- var OutcomeInputSchema = import_zod.z.object({
2699
- runId: import_zod.z.string().min(1),
2700
- success: import_zod.z.boolean(),
2701
- quality: import_zod.z.enum(OutcomeQualities).optional(),
2702
- latencySatisfactory: import_zod.z.boolean().optional(),
2703
- costSatisfactory: import_zod.z.boolean().optional(),
2704
- feedback: import_zod.z.string().optional()
2912
+ var OutcomeInputSchema = import_zod2.z.object({
2913
+ runId: import_zod2.z.string().min(1),
2914
+ success: import_zod2.z.boolean(),
2915
+ quality: import_zod2.z.enum(OutcomeQualities).optional(),
2916
+ latencySatisfactory: import_zod2.z.boolean().optional(),
2917
+ costSatisfactory: import_zod2.z.boolean().optional(),
2918
+ feedback: import_zod2.z.string().optional()
2705
2919
  });
2706
- var SuggestionSchema = import_zod.z.object({
2707
- id: import_zod.z.string(),
2920
+ var SuggestionSchema = import_zod2.z.object({
2921
+ id: import_zod2.z.string(),
2708
2922
  taskType: TaskTypeSchema,
2709
- currentModel: import_zod.z.string(),
2710
- suggestedModel: import_zod.z.string(),
2711
- reason: import_zod.z.string(),
2712
- confidence: import_zod.z.number().min(0).max(1),
2713
- expectedImprovement: import_zod.z.object({
2714
- successRate: import_zod.z.number().optional(),
2715
- latency: import_zod.z.number().optional(),
2716
- cost: import_zod.z.number().optional()
2923
+ currentModel: import_zod2.z.string(),
2924
+ suggestedModel: import_zod2.z.string(),
2925
+ reason: import_zod2.z.string(),
2926
+ confidence: import_zod2.z.number().min(0).max(1),
2927
+ expectedImprovement: import_zod2.z.object({
2928
+ successRate: import_zod2.z.number().optional(),
2929
+ latency: import_zod2.z.number().optional(),
2930
+ cost: import_zod2.z.number().optional()
2717
2931
  }),
2718
- sampleCount: import_zod.z.number().int().positive(),
2719
- createdAt: import_zod.z.string(),
2720
- accepted: import_zod.z.boolean().optional(),
2721
- acceptedAt: import_zod.z.string().optional()
2932
+ sampleCount: import_zod2.z.number().int().positive(),
2933
+ createdAt: import_zod2.z.string(),
2934
+ accepted: import_zod2.z.boolean().optional(),
2935
+ acceptedAt: import_zod2.z.string().optional()
2722
2936
  });
2723
2937
  // Annotate the CommonJS export names for ESM import in node:
2724
2938
  0 && (module.exports = {
2939
+ DEFAULT_CONFIG,
2725
2940
  DEFAULT_ENDPOINTS,
2726
2941
  MODEL_MAPPING,
2727
2942
  MODEL_PRICING,
@@ -2736,9 +2951,13 @@ var SuggestionSchema = import_zod.z.object({
2736
2951
  TaskTypes,
2737
2952
  calculateCost,
2738
2953
  calculateSavings,
2954
+ getConfigPath,
2739
2955
  getInferenceConfidence,
2740
2956
  getModelPricing,
2957
+ getStrategy,
2741
2958
  inferTaskType,
2742
- startProxy
2959
+ loadConfig,
2960
+ startProxy,
2961
+ watchConfig
2743
2962
  });
2744
2963
  //# sourceMappingURL=index.js.map