openclaw-freerouter 1.3.0 → 2.0.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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Default Routing Config — Customized for Direct API Keys
3
- * Forked from ClawRouter (MIT License). No payment dependencies.
3
+ * FreeRouter Default Routing Config
4
4
  *
5
5
  * Tier models are mapped to providers YOU have API keys for.
6
6
  * Edit the `tiers` section to match your configured providers.
@@ -13,7 +13,6 @@
13
13
  */
14
14
 
15
15
  import type { RoutingConfig } from "./types.js";
16
- import { getConfig } from "../config.js";
17
16
 
18
17
  export const DEFAULT_ROUTING_CONFIG: RoutingConfig = {
19
18
  version: "2.0-direct",
@@ -210,33 +209,47 @@ export const DEFAULT_ROUTING_CONFIG: RoutingConfig = {
210
209
  },
211
210
  };
212
211
 
213
-
214
212
  /**
215
- * Get the effective routing config, merging external config overrides.
216
- * External config can override: tiers, agenticTiers, tierBoundaries.
217
- * Scoring weights and keywords remain as coded defaults (advanced users edit source).
213
+ * Get the default routing config.
218
214
  */
219
215
  export function getRoutingConfig(): RoutingConfig {
220
- const extCfg = getConfig();
221
- const config = { ...DEFAULT_ROUTING_CONFIG };
216
+ return DEFAULT_ROUTING_CONFIG;
217
+ }
222
218
 
223
- // Override tiers from external config
224
- if (extCfg.tiers) {
225
- config.tiers = extCfg.tiers as RoutingConfig["tiers"];
219
+ /**
220
+ * Apply plugin config overrides to the routing config.
221
+ * Merges user-specified tiers, scoring, and defaultTier over defaults.
222
+ */
223
+ export function applyConfigOverrides(base: RoutingConfig, pluginConfig: Record<string, unknown>): RoutingConfig {
224
+ const result = JSON.parse(JSON.stringify(base)) as RoutingConfig;
225
+
226
+ // Override tiers if provided
227
+ if (pluginConfig.tiers && typeof pluginConfig.tiers === "object") {
228
+ const userTiers = pluginConfig.tiers as Record<string, { primary: string; fallback?: string[] }>;
229
+ for (const [tier, cfg] of Object.entries(userTiers)) {
230
+ if (result.tiers[tier as keyof typeof result.tiers]) {
231
+ result.tiers[tier as keyof typeof result.tiers] = {
232
+ primary: cfg.primary,
233
+ fallback: cfg.fallback ?? [],
234
+ };
235
+ }
236
+ }
226
237
  }
227
238
 
228
- // Override agentic tiers
229
- if (extCfg.agenticTiers) {
230
- config.agenticTiers = extCfg.agenticTiers as RoutingConfig["agenticTiers"];
239
+ // Override scoring config if provided
240
+ if (pluginConfig.scoring && typeof pluginConfig.scoring === "object") {
241
+ const userScoring = pluginConfig.scoring as Record<string, unknown>;
242
+ for (const [key, val] of Object.entries(userScoring)) {
243
+ if (key in result.scoring) {
244
+ (result.scoring as any)[key] = val;
245
+ }
246
+ }
231
247
  }
232
248
 
233
- // Override tier boundaries
234
- if (extCfg.tierBoundaries) {
235
- config.scoring = {
236
- ...config.scoring,
237
- tierBoundaries: extCfg.tierBoundaries,
238
- };
249
+ // Override default tier for ambiguous requests
250
+ if (pluginConfig.defaultTier && typeof pluginConfig.defaultTier === "string") {
251
+ result.overrides.ambiguousDefaultTier = pluginConfig.defaultTier as any;
239
252
  }
240
253
 
241
- return config;
254
+ return result;
242
255
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Smart Router Entry Point
3
- * Forked from ClawRouter (MIT License). No payment dependencies.
3
+ * FreeRouter Smart Router Entry Point
4
4
  *
5
5
  * Classifies requests and routes to the best model from YOUR configured providers.
6
6
  * 100% local — rules-based scoring handles all requests in <1ms.
@@ -32,14 +32,12 @@ export function route(
32
32
  ): RoutingDecision {
33
33
  const { config, modelPricing } = options;
34
34
 
35
- // Separate token counts: user prompt for complexity, total for context limits
36
- // WHY: System prompts (AGENTS.md, SOUL.md) inflate token count — a "hello" with
37
- // 10K system prompt shouldn't route to Opus. But total tokens still matter for context.
38
- const estimatedUserTokens = Math.ceil(prompt.length / 4);
39
- const estimatedTotalTokens = Math.ceil((`${systemPrompt ?? ""} ${prompt}`).length / 4);
35
+ // Estimate input tokens (~4 chars per token)
36
+ const fullText = `${systemPrompt ?? ""} ${prompt}`;
37
+ const estimatedTokens = Math.ceil(fullText.length / 4);
40
38
 
41
39
  // --- Rule-based classification ---
42
- const ruleResult = classifyByRules(prompt, systemPrompt, estimatedUserTokens, config.scoring);
40
+ const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);
43
41
 
44
42
  // Determine if agentic tiers should be used
45
43
  const agenticScore = ruleResult.agenticScore ?? 0;
@@ -49,7 +47,7 @@ export function route(
49
47
  const tierConfigs = useAgenticTiers ? config.agenticTiers! : config.tiers;
50
48
 
51
49
  // --- Override: large context → force COMPLEX ---
52
- if (estimatedTotalTokens > config.overrides.maxTokensForceComplex) {
50
+ if (estimatedTokens > config.overrides.maxTokensForceComplex) {
53
51
  return selectModel(
54
52
  "COMPLEX",
55
53
  0.95,
@@ -57,14 +55,13 @@ export function route(
57
55
  `Input exceeds ${config.overrides.maxTokensForceComplex} tokens${useAgenticTiers ? " | agentic" : ""}`,
58
56
  tierConfigs,
59
57
  modelPricing,
60
- estimatedTotalTokens,
58
+ estimatedTokens,
61
59
  maxOutputTokens,
62
60
  );
63
61
  }
64
62
 
65
63
  // Structured output detection
66
- // Only check user prompt for structured output request (system prompts often mention "json")
67
- const hasStructuredOutput = /json|structured|schema/i.test(prompt);
64
+ const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;
68
65
 
69
66
  let tier: Tier;
70
67
  let confidence: number;
@@ -103,7 +100,7 @@ export function route(
103
100
  reasoning,
104
101
  tierConfigs,
105
102
  modelPricing,
106
- estimatedTotalTokens,
103
+ estimatedTokens,
107
104
  maxOutputTokens,
108
105
  );
109
106
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Rule-Based Classifier (v2 — Weighted Scoring)
3
- * Forked from ClawRouter (MIT License). No payment dependencies.
3
+ * FreeRouter Rule-Based Classifier (Weighted Scoring)
4
4
  *
5
5
  * Scores a request across 14 weighted dimensions and maps the aggregate
6
6
  * score to a tier using configurable boundaries. Confidence is calibrated
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Tier → Model Selection
3
- * Forked from ClawRouter (MIT License). No payment dependencies.
3
+ * FreeRouter Tier to Model Selection
4
4
  *
5
5
  * Maps a classification tier to the best model from configured providers.
6
6
  * Builds RoutingDecision metadata with cost estimates and savings.
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Smart Router Types — Forked from ClawRouter (MIT License)
3
- * Stripped of x402/BlockRun payment layer.
2
+ * FreeRouter — Smart Router Types
4
3
  *
5
4
  * Four classification tiers — REASONING is distinct from COMPLEX because
6
5
  * reasoning tasks need different models (o3, deepseek-reasoner) than general