openclaw-freerouter 2.0.1 → 2.1.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/README.md CHANGED
@@ -7,6 +7,7 @@
7
7
  - 🔥 **Wasted money** — Running Claude Opus ($15/$75 per 1M tokens) for every message, even "what's 2+2?"
8
8
  - 🤷 **No control** — Can't switch models mid-conversation without editing config files and restarting
9
9
  - 📊 **Blind routing** — Your AI shows "freerouter/auto" instead of telling you which model actually answered
10
+ - 🧠 **No adaptive thinking** — OpenClaw's built-in thinking levels (`/think low`, `/think high`) are just prompt hints. Anthropic deprecated manual thinking for Opus 4.6 — it now requires the native `thinking: { type: "adaptive" }` API parameter, which OpenClaw doesn't send
10
11
  - 🔧 **Complex setup** — Existing routers need separate servers, Docker, complex infra
11
12
 
12
13
  ## The Solution
@@ -14,6 +15,7 @@
14
15
  FreeRouter is an OpenClaw plugin that:
15
16
  - **Classifies every request in <1ms** using a 14-dimension weighted scorer (no LLM needed for classification)
16
17
  - **Routes to the cheapest model that can handle it** — Kimi for "hello", Opus for architecture design
18
+ - **Sends native adaptive thinking** — Automatically passes `thinking: { type: "adaptive" }` to Anthropic's API for Opus 4.6, and `thinking: { type: "enabled", budget_tokens: N }` for Sonnet. No prompt hacks — real API-level thinking control that OpenClaw doesn't support natively
17
19
  - **Reports the real model name** — You see `anthropic/claude-opus-4-6`, not `freerouter/auto`
18
20
  - **Lets you override anytime** — Just say "use opus" in plain English
19
21
 
@@ -100,6 +102,36 @@ This prevents accidental switches when you're just talking *about* a model.
100
102
  | `haiku`, `haiku-4`, `haiku-4.5` | anthropic/claude-haiku-4-5 |
101
103
  | `kimi`, `kimi-k2`, `k2.5` | kimi-coding/kimi-for-coding |
102
104
 
105
+ ## Adaptive Thinking (Native API-Level)
106
+
107
+ This is a key reason FreeRouter exists.
108
+
109
+ **The problem:** OpenClaw's built-in `/think low|medium|high` commands are prompt-level hints — they add text like "think harder" to your prompt. This is unreliable and doesn't use Anthropic's actual thinking API. Worse, **Anthropic deprecated manual thinking (`type: "enabled"`) for Opus 4.6** — it now only supports `type: "adaptive"`, where the model decides how much to think based on the task.
110
+
111
+ **What FreeRouter does:** Sends the real `thinking` parameter directly to Anthropic's API:
112
+
113
+ | Model | Thinking Mode | What's Sent |
114
+ |---|---|---|
115
+ | Claude Opus 4.6 | **Adaptive** (always) | `thinking: { type: "adaptive" }` |
116
+ | Claude Sonnet 4.5 | Enabled with budget | `thinking: { type: "enabled", budget_tokens: 4096 }` |
117
+ | Others (Kimi, Haiku) | Off | No thinking parameter |
118
+
119
+ **Why this matters:**
120
+ - Adaptive thinking lets Opus 4.6 decide how much reasoning it needs — simple questions get quick answers, complex proofs get deep thinking chains
121
+ - You get the full benefit of Claude's extended thinking without managing budgets
122
+ - The `X-FreeRouter-Thinking` response header tells you exactly which thinking mode was used
123
+
124
+ Configure in your plugin config:
125
+ ```json5
126
+ "thinking": {
127
+ "adaptive": ["claude-opus-4-6"], // Models that use adaptive (always-on)
128
+ "enabled": {
129
+ "models": ["claude-sonnet-4-5"], // Models that get explicit thinking
130
+ "budget": 4096 // Token budget for thinking
131
+ }
132
+ }
133
+ ```
134
+
103
135
  ## How Routing Works
104
136
 
105
137
  1. You send a message → OpenClaw forwards to FreeRouter
@@ -154,7 +186,7 @@ After install, add to your `openclaw.json`:
154
186
  // 3. Plugin config
155
187
  "plugins": {
156
188
  "entries": {
157
- "freerouter": {
189
+ "openclaw-freerouter": {
158
190
  "enabled": true,
159
191
  "config": {
160
192
  "port": 18801,
@@ -202,7 +234,7 @@ Then restart: `openclaw gateway restart`
202
234
  If port 18801 is in use, change it:
203
235
 
204
236
  ```json5
205
- { "plugins": { "entries": { "freerouter": { "config": { "port": 18802 } } } } }
237
+ { "plugins": { "entries": { "openclaw-freerouter": { "config": { "port": 18802 } } } } }
206
238
  ```
207
239
 
208
240
  Set `"port": 0` to disable the HTTP proxy entirely.
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "freerouter",
2
+ "id": "openclaw-freerouter",
3
3
  "name": "FreeRouter",
4
4
  "version": "2.0.0",
5
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.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-freerouter",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
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
6
  "openclaw": {
package/src/cli.ts CHANGED
@@ -16,7 +16,7 @@ import { buildPricingMap } from "./models.js";
16
16
  export function registerCli(api: any) {
17
17
  const logger = api.logger ?? console;
18
18
 
19
- const getPluginConfig = () => api.config?.plugins?.entries?.freerouter?.config ?? {};
19
+ const getPluginConfig = () => api.config?.plugins?.entries?.["openclaw-freerouter"]?.config ?? {};
20
20
 
21
21
  api.registerCli(
22
22
  ({ program }: any) => {
@@ -162,8 +162,8 @@ export function registerCli(api: any) {
162
162
  enabled: { models: ["claude-sonnet-4-5"], budget: 4096 },
163
163
  },
164
164
  }, null, 2));
165
- console.log("\n Copy this into plugins.entries.freerouter.config in openclaw.json");
166
- console.log(" Or run: openclaw config set plugins.entries.freerouter.config '{...}'");
165
+ console.log('\n Copy this into plugins.entries["openclaw-freerouter"].config in openclaw.json');
166
+ console.log(' Or run: openclaw config set plugins.entries["openclaw-freerouter"].config \'{...}\'');
167
167
  console.log();
168
168
  });
169
169
 
@@ -335,7 +335,7 @@ export function registerCli(api: any) {
335
335
 
336
336
  Step 1: Add this to your openclaw.json under "plugins.entries":
337
337
 
338
- "freerouter": {
338
+ "openclaw-freerouter": {
339
339
  "enabled": true,
340
340
  "config": ${JSON.stringify(pluginConfig, null, 6).split("\n").map((l, i) => i === 0 ? l : " " + l).join("\n")}
341
341
  }
package/src/index.ts CHANGED
@@ -22,7 +22,7 @@ export const id = "freerouter";
22
22
  export default function register(api: any) {
23
23
  const logger = api.logger ?? console;
24
24
  const getPluginConfig = () => {
25
- const cfg = api.config?.plugins?.entries?.freerouter?.config ?? {};
25
+ const cfg = api.config?.plugins?.entries?.["openclaw-freerouter"]?.config ?? {};
26
26
  return cfg;
27
27
  };
28
28
 
@@ -55,7 +55,7 @@ export default function register(api: any) {
55
55
  server.on("error", (err: any) => {
56
56
  if (err.code === "EADDRINUSE") {
57
57
  logger.error(`[freerouter] Port ${port} is already in use. Run: openclaw freerouter doctor`);
58
- logger.error(`[freerouter] To change port: set plugins.entries.freerouter.config.port in openclaw.json`);
58
+ logger.error(`[freerouter] To change port: set plugins.entries["openclaw-freerouter"].config.port in openclaw.json`);
59
59
  } else {
60
60
  logger.error(`[freerouter] Server error: ${err.message}`);
61
61
  }
package/src/service.ts CHANGED
@@ -624,11 +624,15 @@ export function createProxyServer(options: ProxyOptions): { server: Server; stat
624
624
  }
625
625
 
626
626
  // Determine thinking mode
627
+ // Opus 4.6 REQUIRES adaptive thinking — manual mode is deprecated by Anthropic
628
+ // Other models can use enabled(budget) for explicit thinking control
627
629
  const thinkingCfg = pluginConfig.thinking as any;
628
630
  const adaptivePatterns = thinkingCfg?.adaptive ?? ["claude-opus-4-6"];
629
631
  const enabledCfg = thinkingCfg?.enabled;
630
632
 
631
- if (adaptivePatterns.some((p: string) => routedModel.includes(p)) && (tier === "COMPLEX" || tier === "REASONING")) {
633
+ if (adaptivePatterns.some((p: string) => routedModel.includes(p))) {
634
+ // Adaptive thinking models (e.g., Opus 4.6) — always use adaptive
635
+ // Anthropic deprecated manual thinking for Opus 4.6
632
636
  thinkingMode = "adaptive";
633
637
  } else if (enabledCfg?.models?.some((p: string) => routedModel.includes(p))) {
634
638
  thinkingMode = `enabled(${enabledCfg.budget ?? 4096})`;