feat: phase 5 of AI pipeline hardening — R42 retrieval & telemetry
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 32s
On Pull Request to Main / publish (pull_request) Successful in 57s
On Pull Request to Main / deploy-dev (pull_request) Successful in 1m34s

- Add dependency-free TF-IDF retrieval (src/lib/retrieval.js) with NL+EN
  stopwords and a WeakMap-cached index.
- Rewrite buildKbContext to ship the top-K relevant topics + verbatim-
  mentioned ids only, filter relations to the included set, and append a
  [kb_hash: <8 hex>] suffix so the ephemeral prompt cache busts when the
  graph changes. Returns { context, retrievedTopics, allTopics }.
- Add LOOKUP_TOPIC_TOOL and drive useChat through callLLM directly with a
  multi-hop tool_result loop capped at 3 hops; preserve Anthropic-provided
  tool_use ids through callLLM so the loop can echo correct tool_use_id.
- Truncate R42 history to the last 12 turns and prepend a single
  "(earlier conversation truncated)" assistant message.
- Set R42 chat defaults: temperature 0.3, maxTokens 2048.
- Add pb_migrations/1780500002_created_llm_calls.js (the best-effort
  logger in callLLM was already wired) and a new Admin → Diagnostics
  view showing the last 100 calls with token usage, cache-hit rate, and
  USD cost from a local Anthropic price table.
- Finalize AI_PIPELINE_HARDENING_PLAN.md: mark Phases 1–5 shipped and
  Phase 6 (eval harness) explicitly out of scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
RaymondVerhoef
2026-05-20 21:36:40 +02:00
parent 66e0c275da
commit 229246f7b6
11 changed files with 753 additions and 56 deletions

View File

@@ -68,6 +68,22 @@ export function buildSystemPrompt({ userName, isAdmin, kbContext }) {
];
}
export const LOOKUP_TOPIC_TOOL = {
name: 'lookup_topic',
description:
'Haal de volledige beschrijving en eventuele leerinhoud van één topic op uit de kennisgraaf. Gebruik dit wanneer de samenvattende KENNISGRAAF in de systeemprompt niet genoeg informatie bevat om de vraag te beantwoorden.',
input_schema: {
type: 'object',
properties: {
id: {
type: 'string',
description: 'Het exacte topic id (kebab-case) zoals het in de kennisgraaf staat.',
},
},
required: ['id'],
},
};
export const PROPOSE_GRAPH_DELTA_TOOL = {
name: 'propose_graph_delta',
description: