Files
OmniRoute/scripts/ad-hoc/mesh-run.mjs
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

94 lines
3.2 KiB
JavaScript

// Runner generico para a mesh. Recebe um arquivo JSON de plano:
// [
// { "bucket": "A"|"B"|"C", "match": "<substring e lowercase do texto>", "text": "<resposta>" }
// ]
// Fases: A=reply (answered), B=notice mode:note (fica pending), C=recusa note + mark ignored (por ultimo).
// Envs: BOT_URL, BOT_TOKEN. Uso: node mesh-run.mjs <plano.json>
import { readFileSync } from "node:fs";
import { env } from "node:process";
const BOT_URL = env.BOT_URL;
const BOT_TOKEN = env.BOT_TOKEN;
const FILTER = "platform=discord&language=en&direct=only";
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function api(path, opts = {}) {
const res = await fetch(BOT_URL + path, {
...opts,
headers: {
Authorization: "Bearer " + BOT_TOKEN,
"Content-Type": "application/json",
...(opts.headers || {}),
},
});
return { status: res.status, json: await res.json().catch(() => null) };
}
const planPath = process.argv[2];
const plan = JSON.parse(readFileSync(planPath, "utf8"));
async function main() {
console.log("Fetching pendentes (" + FILTER + ")...");
const { json } = await api("/internal/bridge/questions?" + FILTER);
const pending = (json && json.data) || [];
console.log("-> " + pending.length + " pendentes");
const out = { A: [], B: [], C: [], U: [] };
// fase 1-2: A (reply) e B (notice)
for (const msg of pending) {
const t = (msg.text || "").toLowerCase();
const hit = plan.find((e) => t.includes(e.match.toLowerCase()));
if (!hit) {
out.U.push(msg.id + " :: " + (msg.text || "").slice(0, 60));
continue;
}
if (hit.bucket === "A") {
const r = await api("/internal/bridge/reply", {
method: "POST",
body: JSON.stringify({ messageId: msg.id, text: hit.text }),
});
out.A.push(r.status + " " + msg.id);
} else if (hit.bucket === "B") {
const r = await api("/internal/bridge/reply", {
method: "POST",
body: JSON.stringify({ messageId: msg.id, text: hit.text, mode: "note" }),
});
out.B.push(r.status + " " + msg.id);
} else if (hit.bucket === "C") {
out.C.push(msg.id);
}
await sleep(1000);
}
// fase 3: bucket C — nota de recusa + mark ignored (por último)
for (const id of out.C) {
const msg = pending.find((m) => m.id === id);
const t = (msg.text || "").toLowerCase();
const hit = plan.find((e) => e.bucket === "C" && t.includes(e.match.toLowerCase()));
if (!hit) continue;
const note = await api("/internal/bridge/reply", {
method: "POST",
body: JSON.stringify({ messageId: id, text: hit.text, mode: "note" }),
});
const mark = await api("/internal/bridge/mark", {
method: "POST",
body: JSON.stringify({ messageIds: [id], status: "ignored", ref: "auto-declined" }),
});
out.C[out.C.indexOf(id)] =
"note:" + note.status + " mark:" + (mark.json && mark.json.updated) + " " + id;
await sleep(1000);
}
console.log("\n=== RESUMO ===");
console.log("A (respondidas):", out.A);
console.log("B (notices, pending):", out.B);
console.log("C (recusa+ignoradas):", out.C);
console.log("U (nao classif., relatar):", out.U);
}
main().catch((e) => {
console.error("ERRO:", e);
process.exit(1);
});