@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.
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/index.js +67 -3
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
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.
|
|
19
|
+
const VERSION = "0.1.2";
|
|
20
20
|
const DEFAULT_PORT = 8403;
|
|
21
|
-
const DEFAULT_UPSTREAM = "
|
|
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
|
-
|
|
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",
|