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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 OpenFreeRouter
3
+ Copyright (c) 2026 OpenFreeRouter
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,48 +1,63 @@
1
- # @openfreerouter/openclaw-freerouter
1
+ # FreeRouter — OpenClaw Plugin
2
2
 
3
- **FreeRouter** — Smart model router for OpenClaw. Auto-classifies requests using a 14-dimension weighted scorer and routes to the cheapest capable model using your own API keys.
3
+ Smart LLM router that classifies your requests and routes them to the best model automatically. Uses a 14-dimension weighted scorer (<1ms) with configurable tier→model mapping.
4
4
 
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- openclaw plugins install @openfreerouter/openclaw-freerouter
9
- ```
10
-
11
- Or install from local path:
8
+ # From local directory
9
+ openclaw plugins install -l /path/to/freerouter-plugin
12
10
 
13
- ```bash
14
- openclaw plugins install ./openclaw-freerouter
11
+ # Or copy to extensions
12
+ openclaw plugins install /path/to/freerouter-plugin
15
13
  ```
16
14
 
17
- ## Configuration
15
+ ## Configure
18
16
 
19
- Add to your `openclaw.json`:
17
+ After install, configure tiers in `openclaw.json`:
20
18
 
21
- ```json
19
+ ```json5
22
20
  {
23
- "plugins": {
24
- "entries": {
25
- "freerouter": {
26
- "config": {
27
- "port": 18800,
28
- "host": "127.0.0.1",
29
- "providers": {
30
- "anthropic": {
31
- "baseUrl": "https://api.anthropic.com",
32
- "api": "anthropic"
33
- },
34
- "kimi-coding": {
35
- "baseUrl": "https://api.kimi.com/coding/v1",
36
- "api": "openai",
37
- "headers": { "User-Agent": "KimiCLI/0.77" }
38
- }
21
+ // Set FreeRouter as your default model
22
+ agents: {
23
+ defaults: {
24
+ model: { primary: "freerouter/auto" }
25
+ }
26
+ },
27
+
28
+ // Add FreeRouter as a provider pointing to its HTTP proxy
29
+ providers: {
30
+ freerouter: {
31
+ baseUrl: "http://127.0.0.1:18801/v1",
32
+ api: "openai-completions"
33
+ }
34
+ },
35
+
36
+ // Plugin config
37
+ plugins: {
38
+ entries: {
39
+ freerouter: {
40
+ enabled: true,
41
+ config: {
42
+ port: 18801, // HTTP proxy port (0 = disabled)
43
+ host: "127.0.0.1", // Bind address
44
+
45
+ // Customize which models handle each tier
46
+ tiers: {
47
+ SIMPLE: { primary: "kimi-coding/kimi-for-coding", fallback: ["anthropic/claude-haiku-4-5"] },
48
+ MEDIUM: { primary: "anthropic/claude-sonnet-4-5", fallback: ["anthropic/claude-opus-4-6"] },
49
+ COMPLEX: { primary: "anthropic/claude-opus-4-6", fallback: [] },
50
+ REASONING: { primary: "anthropic/claude-opus-4-6", fallback: [] }
39
51
  },
40
- "tiers": {
41
- "SIMPLE": { "primary": "kimi-coding/kimi-for-coding", "fallback": ["anthropic/claude-haiku-4-5"] },
42
- "MEDIUM": { "primary": "anthropic/claude-sonnet-4-5", "fallback": ["anthropic/claude-opus-4-6"] },
43
- "COMPLEX": { "primary": "anthropic/claude-opus-4-6", "fallback": ["anthropic/claude-haiku-4-5"] },
44
- "REASONING": { "primary": "anthropic/claude-opus-4-6", "fallback": ["anthropic/claude-haiku-4-5"] }
45
- }
52
+
53
+ // Thinking/reasoning config
54
+ thinking: {
55
+ adaptive: ["claude-opus-4-6"],
56
+ enabled: { models: ["claude-sonnet-4-5"], budget: 4096 }
57
+ },
58
+
59
+ // Default tier for ambiguous requests
60
+ defaultTier: "MEDIUM"
46
61
  }
47
62
  }
48
63
  }
@@ -50,54 +65,98 @@ Add to your `openclaw.json`:
50
65
  }
51
66
  ```
52
67
 
53
- All config fields are optional — sensible defaults are built in.
54
-
55
68
  ## How It Works
56
69
 
57
- 1. **Classify**: Each request is scored across 14 dimensions (code presence, reasoning markers, technical terms, creativity, etc.)
58
- 2. **Route**: Score maps to a tier (SIMPLE → MEDIUM → COMPLEX → REASONING)
59
- 3. **Forward**: Request is forwarded to the tier's primary model, with automatic fallback
60
- 4. **Translate**: Anthropic Messages API OpenAI format translation happens transparently
70
+ 1. OpenClaw sends a request with model `freerouter/auto`
71
+ 2. FreeRouter's HTTP proxy receives it
72
+ 3. The 14-dimension classifier scores the request in <1ms
73
+ 4. Routes to the best model for the task (e.g., Kimi for simple, Opus for reasoning)
74
+ 5. Forwards to the real provider API
75
+ 6. **Returns the actual model name** (e.g., `anthropic/claude-opus-4-6`) so OpenClaw displays what's really running
61
76
 
62
77
  ## Tiers
63
78
 
64
79
  | Tier | Default Model | Use Case |
65
80
  |------|--------------|----------|
66
- | SIMPLE | Kimi K2.5 | Greetings, facts, translations |
67
- | MEDIUM | Claude Sonnet 4.5 | Code, conversation, tool use |
68
- | COMPLEX | Claude Opus 4.6 | Architecture, debugging, analysis |
69
- | REASONING | Claude Opus 4.6 | Proofs, formal reasoning, deep analysis |
81
+ | SIMPLE | kimi-coding/kimi-for-coding | Quick lookups, translations, simple Q&A |
82
+ | MEDIUM | anthropic/claude-sonnet-4-5 | Code generation, creative writing, moderate complexity |
83
+ | COMPLEX | anthropic/claude-opus-4-6 | Architecture design, multi-step reasoning |
84
+ | REASONING | anthropic/claude-opus-4-6 | Mathematical proofs, formal logic, deep analysis |
70
85
 
71
- ## Mode Overrides
86
+ ## Per-Prompt Model Override
72
87
 
73
- Force a specific tier in your prompt:
88
+ Force a specific model for one message:
74
89
 
75
- - `/max prove that P ≠ NP` → REASONING
76
- - `simple mode: what's 2+2` → SIMPLE
77
- - `[complex] review this architecture` COMPLEX
90
+ - `/opus Explain quantum computing` → Claude Opus 4.6
91
+ - `/sonnet Write a poem` → Claude Sonnet 4.5
92
+ - `/kimi What's 2+2?`Kimi K2.5
93
+ - `/haiku Translate this` → Claude Haiku 4.5
94
+ - `[opus] Deep analysis...` → Claude Opus 4.6
78
95
 
79
- ## Endpoints
96
+ ## Per-Prompt Tier Override
80
97
 
81
- | Endpoint | Method | Description |
82
- |----------|--------|-------------|
83
- | `/v1/chat/completions` | POST | OpenAI-compatible chat |
84
- | `/v1/models` | GET | List available models |
85
- | `/health` | GET | Health check |
86
- | `/stats` | GET | Request statistics |
87
- | `/config` | GET | Show sanitized config |
88
- | `/reload` | POST | Reload auth keys |
89
- | `/reload-config` | POST | Reload config + auth |
98
+ Force a tier (uses that tier's primary model):
90
99
 
91
- ## Use as Default Model
100
+ - `/simple What's 2+2?` → SIMPLE tier
101
+ - `/max Prove the Riemann hypothesis` → REASONING tier
102
+ - `[reasoning] Analyze this code...` → REASONING tier
92
103
 
93
- Set your default model to `freerouter/auto` in openclaw.json:
104
+ ## Session Lock
94
105
 
95
- ```json
96
- {
97
- "model": "freerouter/auto"
98
- }
106
+ Lock an entire session to a specific model:
107
+
108
+ - `/lock opus` → 🔒 All messages use Opus until unlocked
109
+ - `/lock sonnet` → 🔒 All messages use Sonnet
110
+ - `/lock simple` → 🔒 Lock to SIMPLE tier's primary model
111
+ - `/lock anthropic/claude-opus-4-6` → 🔒 Full model ID
112
+ - `/unlock` → 🔓 Return to auto-routing
113
+ - `/lock auto` → 🔓 Same as unlock
114
+ - `/lock status` → Show current lock state
115
+
116
+ Session locks expire after 4 hours of inactivity.
117
+
118
+ ### Supported Aliases
119
+
120
+ | Alias | Model |
121
+ |-------|-------|
122
+ | `opus`, `opus-4`, `opus-4.6` | anthropic/claude-opus-4-6 |
123
+ | `sonnet`, `sonnet-4`, `sonnet-4.5` | anthropic/claude-sonnet-4-5 |
124
+ | `sonnet-4.6` | anthropic/claude-sonnet-4-6 |
125
+ | `haiku`, `haiku-4`, `haiku-4.5` | anthropic/claude-haiku-4-5 |
126
+ | `kimi`, `kimi-k2`, `k2.5` | kimi-coding/kimi-for-coding |
127
+
128
+ ## Scoring Dimensions
129
+
130
+ The classifier evaluates 14 weighted dimensions:
131
+ - Token count, code presence, reasoning markers, technical terms
132
+ - Creative markers, simple indicators, multi-step patterns
133
+ - Question complexity, imperative verbs, constraints
134
+ - Output format, references, negation, domain specificity
135
+ - Agentic task indicators
136
+
137
+ ## Port Conflicts
138
+
139
+ If port 18801 is in use, change it in the plugin config:
140
+
141
+ ```json5
142
+ { plugins: { entries: { freerouter: { config: { port: 18802 } } } } }
99
143
  ```
100
144
 
145
+ Set `port: 0` to disable the HTTP proxy entirely.
146
+
147
+ ## Commands
148
+
149
+ - `/freerouter` — Show routing stats in chat
150
+ - `openclaw freerouter status` — CLI status and stats
151
+
152
+ ## Response Headers
153
+
154
+ Every proxied response includes:
155
+ - `X-FreeRouter-Model` — Actual model used
156
+ - `X-FreeRouter-Tier` — Classification tier
157
+ - `X-FreeRouter-Thinking` — Thinking mode (off/adaptive/enabled)
158
+ - `X-FreeRouter-Reasoning` — Classification reasoning
159
+
101
160
  ## License
102
161
 
103
162
  MIT
@@ -1,25 +1,109 @@
1
1
  {
2
2
  "id": "freerouter",
3
3
  "name": "FreeRouter",
4
- "description": "Smart model router — auto-classify requests and route to the cheapest capable model using your own API keys",
5
- "version": "1.3.0",
4
+ "version": "2.0.0",
5
+ "description": "Smart LLM router — classify requests and route to the best model using your own API keys. 14-dimension weighted scoring, <1ms classification, configurable tiers.",
6
6
  "providers": ["freerouter"],
7
7
  "configSchema": {
8
8
  "type": "object",
9
9
  "additionalProperties": false,
10
10
  "properties": {
11
- "port": { "type": "number", "default": 18800 },
12
- "host": { "type": "string", "default": "127.0.0.1" },
13
- "providers": { "type": "object" },
14
- "tiers": { "type": "object" },
15
- "agenticTiers": { "type": "object" },
16
- "tierBoundaries": { "type": "object" },
17
- "thinking": { "type": "object" },
18
- "auth": { "type": "object" }
11
+ "port": {
12
+ "type": "number",
13
+ "description": "HTTP proxy port (0 = disabled, in-process only)",
14
+ "default": 18801
15
+ },
16
+ "host": {
17
+ "type": "string",
18
+ "description": "HTTP proxy bind address",
19
+ "default": "127.0.0.1"
20
+ },
21
+ "tiers": {
22
+ "type": "object",
23
+ "description": "Model assignments per classification tier",
24
+ "additionalProperties": false,
25
+ "properties": {
26
+ "SIMPLE": { "$ref": "#/$defs/tierConfig" },
27
+ "MEDIUM": { "$ref": "#/$defs/tierConfig" },
28
+ "COMPLEX": { "$ref": "#/$defs/tierConfig" },
29
+ "REASONING": { "$ref": "#/$defs/tierConfig" }
30
+ }
31
+ },
32
+ "thinking": {
33
+ "type": "object",
34
+ "description": "Thinking/reasoning config per tier",
35
+ "additionalProperties": false,
36
+ "properties": {
37
+ "adaptive": {
38
+ "type": "array",
39
+ "items": { "type": "string" },
40
+ "description": "Model patterns that support adaptive thinking (e.g. ['claude-opus-4-6'])"
41
+ },
42
+ "enabled": {
43
+ "type": "object",
44
+ "properties": {
45
+ "models": {
46
+ "type": "array",
47
+ "items": { "type": "string" },
48
+ "description": "Model patterns that get thinking enabled"
49
+ },
50
+ "budget": {
51
+ "type": "number",
52
+ "description": "Thinking token budget",
53
+ "default": 4096
54
+ }
55
+ }
56
+ }
57
+ }
58
+ },
59
+ "scoring": {
60
+ "type": "object",
61
+ "description": "Override scoring weights, boundaries, or keyword lists",
62
+ "additionalProperties": true
63
+ },
64
+ "defaultTier": {
65
+ "type": "string",
66
+ "enum": ["SIMPLE", "MEDIUM", "COMPLEX", "REASONING"],
67
+ "description": "Default tier when classification is ambiguous",
68
+ "default": "MEDIUM"
69
+ },
70
+ "logLevel": {
71
+ "type": "string",
72
+ "enum": ["debug", "info", "warn", "error"],
73
+ "default": "info"
74
+ }
75
+ },
76
+ "$defs": {
77
+ "tierConfig": {
78
+ "type": "object",
79
+ "properties": {
80
+ "primary": {
81
+ "type": "string",
82
+ "description": "Primary model (e.g. 'anthropic/claude-opus-4-6')"
83
+ },
84
+ "fallback": {
85
+ "type": "array",
86
+ "items": { "type": "string" },
87
+ "description": "Fallback models if primary fails"
88
+ }
89
+ },
90
+ "required": ["primary"]
91
+ }
19
92
  }
20
93
  },
21
94
  "uiHints": {
22
- "port": { "label": "Proxy Port", "placeholder": "18800" },
23
- "host": { "label": "Bind Address", "placeholder": "127.0.0.1" }
95
+ "port": {
96
+ "label": "Proxy Port",
97
+ "placeholder": "18801 (0 to disable HTTP proxy)"
98
+ },
99
+ "tiers": {
100
+ "label": "Tier → Model Mapping"
101
+ },
102
+ "defaultTier": {
103
+ "label": "Default Tier (ambiguous requests)"
104
+ },
105
+ "logLevel": {
106
+ "label": "Log Level"
107
+ }
24
108
  }
25
109
  }
package/package.json CHANGED
@@ -1,37 +1,49 @@
1
1
  {
2
2
  "name": "openclaw-freerouter",
3
- "version": "1.3.0",
4
- "description": "FreeRouter plugin for OpenClaw — smart model routing with your own API keys",
3
+ "version": "2.0.0",
4
+ "description": "Smart LLM router plugin for OpenClaw — classify requests and route to the best model using your own API keys. 14-dimension scoring, <1ms classification, per-prompt/session model switching.",
5
5
  "type": "module",
6
- "main": "index.ts",
7
- "exports": {
8
- ".": "./index.ts"
6
+ "openclaw": {
7
+ "extensions": ["./src/index.ts"]
8
+ },
9
+ "main": "src/index.ts",
10
+ "scripts": {
11
+ "test": "npx tsx test/test-freerouter.mjs && npx tsx test/test-resilience.mjs && npx tsx test/test-overrides.mjs",
12
+ "test:classification": "npx tsx test/test-freerouter.mjs",
13
+ "test:resilience": "npx tsx test/test-resilience.mjs",
14
+ "test:overrides": "npx tsx test/test-overrides.mjs",
15
+ "typecheck": "tsc --noEmit"
9
16
  },
10
- "files": [
11
- "index.ts",
12
- "src/",
13
- "openclaw.plugin.json",
14
- "README.md",
15
- "LICENSE",
16
- "CHANGELOG.md"
17
- ],
18
17
  "keywords": [
19
18
  "openclaw",
20
19
  "openclaw-plugin",
21
- "ai-router",
20
+ "llm-router",
22
21
  "model-router",
22
+ "smart-routing",
23
23
  "freerouter",
24
- "llm",
25
- "proxy"
24
+ "anthropic",
25
+ "claude",
26
+ "kimi",
27
+ "openai"
26
28
  ],
27
- "author": "OpenFreeRouter",
28
- "license": "MIT",
29
29
  "repository": {
30
30
  "type": "git",
31
31
  "url": "https://github.com/openfreerouter/openclaw-freerouter"
32
32
  },
33
+ "homepage": "https://github.com/openfreerouter/openclaw-freerouter#readme",
34
+ "bugs": {
35
+ "url": "https://github.com/openfreerouter/openclaw-freerouter/issues"
36
+ },
37
+ "author": "dusama",
38
+ "license": "MIT",
39
+ "files": [
40
+ "src/",
41
+ "openclaw.plugin.json",
42
+ "README.md",
43
+ "LICENSE"
44
+ ],
33
45
  "devDependencies": {
34
- "@types/node": "^22.19.11",
35
- "typescript": "^5.9.3"
46
+ "@types/node": "^22.0.0",
47
+ "typescript": "^5.7.0"
36
48
  }
37
49
  }