phase 44 (part 1): migrate TS callers to /v1/chat + add regression guard
lakehouse/auditor 16 blocking issues: cloud: claim not backed — "Verified end-to-end:"

Migrates the four TypeScript /generate callers to the gateway's
/v1/chat surface so every LLM call lands on /v1/usage and Langfuse:

  tests/multi-agent/agent.ts::generate()      provider="ollama"
  tests/agent_test/agent_harness.ts::callAgent provider="ollama"
  bot/propose.ts::generateProposal             provider="ollama_cloud"
  mcp-server/observer.ts (error analysis)      provider="ollama"

Each migration follows the same pattern as the prior generateCloud()
migration (already on /v1/chat from 2026-04-24): replace
`fetch(SIDECAR/generate)` with `fetch(GATEWAY/v1/chat)`, swap the
prompt-style body for OpenAI-compat messages array, extract
content from `choices[0].message.content` instead of `text`.

Same upstream models in every case — gateway is the new home for
the call, transport otherwise unchanged.

Adds scripts/check_phase44_callers.sh — fail-loud regression guard
that exits non-zero if any non-adapter file fetches /generate or
api/generate. Adapter files (crates/gateway, crates/aibridge,
sidecar/) are exempt. Pre-tightening regex flagged prose mentions
in comments; the shipped regex requires `fetch(...)` or
`client.post(...)` shape so comments don't trip it.

Verification:
  bun build mcp-server/observer.ts                       compiles
  bun build tests/multi-agent/agent.ts                   compiles
  bun build tests/agent_test/agent_harness.ts            compiles
  bun build bot/propose.ts                               compiles
  ./scripts/check_phase44_callers.sh                     ✅ clean
  systemctl restart lakehouse-observer                   active

Phase 44 part 2 (deferred):
  - crates/aibridge/src/client.rs:118 still posts to sidecar /generate
    directly. AiClient is the foundational Rust LLM caller used by
    8+ vectord modules; migrating it is a workspace-wide refactor
    that needs its own commit. Plan: keep AiClient as the local-
    transport layer for the gateway's `provider=ollama` arm, but
    introduce a thin `/v1/chat` wrapper for external callers (vectord
    autotune, agent, rag, refresh, supervisor, playbook_memory).
  - tests/real-world/hard_task_escalation.ts: comment mentions
    /api/generate but doesn't actually call it. Comment is left
    intentionally as historical context; regex no longer flags it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-04-27 07:33:06 -05:00
co-authored by Claude Opus 4.7
parent bfe1ea9d1c
commit f6af0fd409
5 changed files with 108 additions and 26 deletions
+15 -8
View File
@@ -550,13 +550,19 @@ async function analyzeErrors() {
`[${f.endpoint}] ${f.input_summary}: ${f.error}`
).join("\n");
// Ask local model to diagnose
// Ask local model to diagnose. Phase 44 migration (2026-04-27):
// /v1/chat instead of legacy /ai/generate so /v1/usage tracks the
// call + Langfuse traces it. Same upstream model (qwen2.5 local).
try {
const resp = await fetch(`${LAKEHOUSE}/ai/generate`, {
const resp = await fetch(`${LAKEHOUSE}/v1/chat`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
prompt: `You are a system reliability observer. Analyze these recent failures and suggest fixes:
model: "qwen2.5",
provider: "ollama",
messages: [{
role: "user",
content: `You are a system reliability observer. Analyze these recent failures and suggest fixes:
${errorSummary}
@@ -566,14 +572,15 @@ For each error:
3. Should this be added to the playbook as a "don't do this"?
Be specific and actionable. Under 200 words.`,
model: "qwen2.5",
}],
max_tokens: 400,
temperature: 0.2,
}),
});
const analysis = await resp.json();
if (analysis.text) {
console.error(`[observer] Error analysis:\n${analysis.text}`);
const analysis = await resp.json() as any;
const analysisText = analysis?.choices?.[0]?.message?.content ?? "";
if (analysisText) {
console.error(`[observer] Error analysis:\n${analysisText}`);
// Log the analysis as a playbook entry
await fetch(`${GATEWAY}/log`, {
method: "POST",
@@ -581,7 +588,7 @@ Be specific and actionable. Under 200 words.`,
body: JSON.stringify({
operation: `error_analysis: ${failures.length} failures`,
approach: "LLM-analyzed error patterns",
result: analysis.text.slice(0, 500),
result: analysisText.slice(0, 500),
context: errorSummary.slice(0, 500),
}),
});