@anjieyang/uncommon-route 0.1.0 → 0.1.2

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.
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "upstream": {
38
38
  "label": "Upstream API URL",
39
- "placeholder": "https://api.commonstack.ai/v1"
39
+ "placeholder": "https://openrouter.ai/api/v1"
40
40
  },
41
41
  "pythonPath": {
42
42
  "label": "Python Path",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anjieyang/uncommon-route",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "OpenClaw plugin — UncommonRoute smart LLM router, 98% accuracy, <1ms local routing",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -16,9 +16,9 @@
16
16
  import { spawn, execSync } from "node:child_process";
17
17
  import { setTimeout as sleep } from "node:timers/promises";
18
18
 
19
- const VERSION = "0.1.0";
19
+ const VERSION = "0.1.2";
20
20
  const DEFAULT_PORT = 8403;
21
- const DEFAULT_UPSTREAM = "https://api.commonstack.ai/v1";
21
+ const DEFAULT_UPSTREAM = "";
22
22
  const HEALTH_TIMEOUT_MS = 15_000;
23
23
  const HEALTH_POLL_MS = 500;
24
24
  const PY_PACKAGE = "uncommon-route";
@@ -207,6 +207,11 @@ const plugin = {
207
207
  const upstream = cfg.upstream || process.env.UNCOMMON_ROUTE_UPSTREAM || DEFAULT_UPSTREAM;
208
208
  const baseUrl = `http://127.0.0.1:${port}/v1`;
209
209
 
210
+ if (!upstream) {
211
+ api.logger.warn("UncommonRoute: No upstream configured. Set UNCOMMON_ROUTE_UPSTREAM or configure 'upstream' in plugin config.");
212
+ api.logger.warn(" Example: UNCOMMON_ROUTE_UPSTREAM=https://openrouter.ai/api/v1 UNCOMMON_ROUTE_API_KEY=sk-or-...");
213
+ }
214
+
210
215
  // 1. Register provider immediately (sync, models available right away)
211
216
  api.registerProvider({
212
217
  id: "uncommon-route",
@@ -240,8 +245,14 @@ const plugin = {
240
245
  body: JSON.stringify({ model: "uncommon-route/auto", messages: [{ role: "user", content: `/debug ${prompt}` }] }),
241
246
  signal: AbortSignal.timeout(5000),
242
247
  });
248
+ lastRequestId = resp.headers.get("x-uncommon-route-request-id");
249
+ lastTier = resp.headers.get("x-uncommon-route-tier");
243
250
  const data = await resp.json();
244
- return { text: data?.choices?.[0]?.message?.content || "No response" };
251
+ let text = data?.choices?.[0]?.message?.content || "No response";
252
+ if (lastRequestId) {
253
+ text += `\n\n_Rate this: \`/feedback ok\` · \`/feedback weak\` · \`/feedback strong\`_`;
254
+ }
255
+ return { text };
245
256
  } catch (err) {
246
257
  return { text: `Error: ${err.message}. Is proxy running?`, isError: true };
247
258
  }
@@ -282,6 +293,59 @@ const plugin = {
282
293
  },
283
294
  });
284
295
 
296
+ let lastRequestId = null;
297
+ let lastTier = null;
298
+
299
+ api.registerCommand({
300
+ name: "feedback",
301
+ description: "Rate last routing decision: /feedback ok|weak|strong|status",
302
+ acceptsArgs: true,
303
+ requireAuth: false,
304
+ handler: async (ctx) => {
305
+ const args = (ctx.args || "").trim().toLowerCase();
306
+ const feedbackUrl = `http://127.0.0.1:${port}/v1/feedback`;
307
+
308
+ if (!args || args === "status") {
309
+ const data = await fetchJson(feedbackUrl);
310
+ if (!data) return { text: "Proxy not running.", isError: true };
311
+ const lines = [
312
+ "**Online Learning Status**",
313
+ "",
314
+ `Pending contexts: ${data.pending_contexts}`,
315
+ `Total updates: ${data.total_online_updates}`,
316
+ `Updates (last hour): ${data.updates_last_hour}`,
317
+ `Online model: ${data.online_model_active ? "active" : "inactive (base model)"}`,
318
+ "",
319
+ "Usage: `/feedback ok` (correct) | `/feedback weak` (should be harder) | `/feedback strong` (should be easier)",
320
+ ];
321
+ return { text: lines.join("\n") };
322
+ }
323
+
324
+ if (["ok", "weak", "strong"].includes(args)) {
325
+ if (!lastRequestId) {
326
+ return { text: "No recent routing decision to give feedback on. Send a message with `uncommon-route/auto` first.", isError: true };
327
+ }
328
+ const result = await postJson(feedbackUrl, { request_id: lastRequestId, signal: args });
329
+ if (!result) return { text: "Proxy not running.", isError: true };
330
+ if (!result.ok) return { text: `Feedback failed: ${result.reason || result.action}`, isError: true };
331
+
332
+ const emoji = { reinforced: "✓", updated: "↑", no_change: "—" }[result.action] || "•";
333
+ const tierInfo = result.from_tier === result.to_tier
334
+ ? `${result.from_tier} (reinforced)`
335
+ : `${result.from_tier} → ${result.to_tier}`;
336
+ lastRequestId = null;
337
+ return { text: `${emoji} Feedback applied: ${tierInfo} (total updates: ${result.total_updates})` };
338
+ }
339
+
340
+ if (args === "rollback") {
341
+ const result = await postJson(feedbackUrl, { action: "rollback" });
342
+ return { text: result?.ok ? "✓ Online weights rolled back to base model" : "Rollback failed" };
343
+ }
344
+
345
+ return { text: "Usage: `/feedback [ok|weak|strong|status|rollback]`\n• **ok** — tier was correct\n• **weak** — model was too weak, should route to harder tier\n• **strong** — model was overkill, should route to easier tier" };
346
+ },
347
+ });
348
+
285
349
  api.registerCommand({
286
350
  name: "sessions",
287
351
  description: "View active routing sessions",