fix: comprehensive QA — resolve 13 bugs, add UX improvements across all services

Client SDK: add .catch() to graphRagStreaming/documentRagStreaming (silent timeout),
null-guard JSON.parse in getPrompts/getSystemPrompt/getPrompt.

Backend: implement "getvalues" config operation for token costs, null-check
createTerm() in FalkorDB triples query, add knowledge-cores service entrypoint
and Docker entry, return proper HTTP 400/404 for gateway error responses.

Workbench: cancel button + elapsed timer for chat, clear agent spinner on error,
flow dialog inline validation, responsive header wrapping, knowledge cores
loading timeout, sidebar/page naming consistency, theme toggle indicator.

Infrastructure: enable Grafana Explore for viewers, add gateway Prometheus
scrape target, fix RAG pipeline dashboard layout (6 panels visible),
filter Service Health to configured targets only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
elpresidank 2026-04-07 05:20:10 -05:00
parent 72870a7e2e
commit 3a80872482
22 changed files with 202 additions and 54 deletions

View file

@ -129,6 +129,9 @@ export class ConfigService extends AsyncProcessor {
case "config":
return this.handleConfigDump();
case "getvalues":
return this.handleGetValues(request);
default:
throw new Error(`Unknown config operation: ${op as string}`);
}
@ -237,6 +240,22 @@ export class ConfigService extends AsyncProcessor {
};
}
private handleGetValues(request: ConfigRequest): ConfigResponse {
const type = request.type ?? "";
const values: { key: string; value: unknown }[] = [];
for (const [namespace, subMap] of this.store) {
if (!type || namespace === type || namespace.startsWith(`${type}.`) || namespace.startsWith(`${type}/`)) {
for (const [k, v] of subMap) {
values.push({ key: `${namespace}.${k}`, value: v });
}
}
}
return { version: this.version, values: values as unknown as Record<string, unknown> };
}
private handleConfigDump(): ConfigResponse {
const config: Record<string, unknown> = {};

View file

@ -47,7 +47,12 @@ export async function createGateway(config: GatewayConfig) {
const body = request.body as Record<string, unknown>;
try {
const result = await dispatcher.dispatchGlobalService(kind, body);
const result = await dispatcher.dispatchGlobalService(kind, body) as Record<string, unknown>;
const err = result?.error as { type?: string; message?: string } | undefined;
if (err) {
const statusCode = err.type === "not-found" ? 404 : 400;
return reply.code(statusCode).send(result);
}
return result;
} catch (err) {
reply.code(500).send({ error: { type: "internal", message: String(err) } });
@ -62,7 +67,12 @@ export async function createGateway(config: GatewayConfig) {
const body = request.body as Record<string, unknown>;
try {
const result = await dispatcher.dispatchFlowService(flow, kind, body);
const result = await dispatcher.dispatchFlowService(flow, kind, body) as Record<string, unknown>;
const err = result?.error as { type?: string; message?: string } | undefined;
if (err) {
const statusCode = err.type === "not-found" ? 404 : 400;
return reply.code(statusCode).send(result);
}
return result;
} catch (err) {
reply.code(500).send({ error: { type: "internal", message: String(err) } });

View file

@ -25,6 +25,9 @@ function termToValue(term: Term | undefined): string | null {
}
function createTerm(value: string): Term {
if (!value) {
return { type: "LITERAL", value: "" };
}
if (value.startsWith("http://") || value.startsWith("https://")) {
return { type: "IRI", iri: value };
}
@ -90,11 +93,14 @@ export class FalkorDBTriplesQuery {
await this.matchAll(rawTriples, limit);
}
return rawTriples.slice(0, limit).map(([s, p, o]) => ({
s: createTerm(s),
p: createTerm(p),
o: createTerm(o),
}));
return rawTriples
.filter(([s, p, o]) => s != null && p != null && o != null)
.slice(0, limit)
.map(([s, p, o]) => ({
s: createTerm(s),
p: createTerm(p),
o: createTerm(o),
}));
}
private async matchPattern(