updates on the ui changes and changed into doormile
This commit is contained in:
66
src/lib/assistant/ragRouter.js
Normal file
66
src/lib/assistant/ragRouter.js
Normal file
@@ -0,0 +1,66 @@
|
||||
// ==============================|| Doormile AI — semantic routing client ||============================== //
|
||||
//
|
||||
// Talks to the retrieval sidecar (services/ai) to decide WHICH QUESTION was
|
||||
// asked. It never returns data — every figure still comes from the intent's own
|
||||
// deterministic run(), through the same typed API functions the pages use.
|
||||
//
|
||||
// The whole module is optional by design:
|
||||
//
|
||||
// • REACT_APP_AI_URL unset → disabled, regex matcher only (production today)
|
||||
// • sidecar unreachable → disabled for this call, regex matcher
|
||||
// • slow → aborted at ROUTE_TIMEOUT_MS, regex matcher
|
||||
// • low confidence → not used, regex matcher
|
||||
//
|
||||
// Today's behaviour is the floor. This can raise it, never lower it.
|
||||
|
||||
const BASE = import.meta.env.VITE_AI_URL || import.meta.env.REACT_APP_AI_URL || '';
|
||||
const ROUTE_TIMEOUT_MS = 400;
|
||||
|
||||
export const isRagEnabled = () => Boolean(BASE);
|
||||
|
||||
// Once the sidecar has failed we stop hammering it on every keystroke-fast
|
||||
// question. Re-armed after a cool-off so a restarted container is picked up
|
||||
// without a page reload.
|
||||
let disabledUntil = 0;
|
||||
const COOL_OFF_MS = 30000;
|
||||
|
||||
const post = async (path, body) => {
|
||||
if (!BASE || Date.now() < disabledUntil) return null;
|
||||
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), ROUTE_TIMEOUT_MS);
|
||||
try {
|
||||
const res = await fetch(`${BASE}${path}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
signal: controller.signal
|
||||
});
|
||||
if (!res.ok) throw new Error(`${res.status}`);
|
||||
return await res.json();
|
||||
} catch {
|
||||
// Any failure — offline, timeout, 5xx — is silent by design. The operator
|
||||
// gets the deterministic answer; they should never see plumbing.
|
||||
disabledUntil = Date.now() + COOL_OFF_MS;
|
||||
return null;
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
};
|
||||
|
||||
// Returns { intentId, confidence, score, margin, alternatives } or null.
|
||||
export const routeQuestion = (text) => post('/route', { text });
|
||||
|
||||
// Documentation passages, verbatim with attribution. No generation step —
|
||||
// summarising would need a hosted model (assistant/CLAUDE.md §2) and would let
|
||||
// a paraphrase drift from what the doc actually says.
|
||||
export const askDocs = (text) => post('/ask', { text });
|
||||
|
||||
// A semantic near-miss must never open a create form. Write intents require
|
||||
// high confidence AND corroboration from the deterministic trigger, so the
|
||||
// worst case is that the operator types the phrase the regex already knows.
|
||||
export const isRouteTrustworthy = (routed) => {
|
||||
if (!routed?.intentId) return false;
|
||||
if (routed.isWrite) return routed.confidence === 'high';
|
||||
return routed.confidence === 'high' || routed.confidence === 'medium';
|
||||
};
|
||||
Reference in New Issue
Block a user