// POST bot cycle outcomes to the observer on :3800 so they accumulate // in the KB alongside scenario + autotune events. Non-fatal on failure: // the cycle result is also written to disk so observability isn't a // single point of failure. const OBSERVER_URL = process.env.LH_OBSERVER_URL ?? "http://localhost:3800"; export interface BotObserverEvent { source: "bot"; cycle_id: string; sig_hash: string; // stable hash of the gap + proposal for dedup event_kind: string; // cycle outcome (ok, tests_failed, ...) ok: boolean; staffer_id?: string; // the model used, e.g. "gpt-oss:120b" turns?: number; // number of cloud calls this cycle duration_ms?: number; extra?: Record; } export async function postEvent(ev: BotObserverEvent): Promise { try { const r = await fetch(`${OBSERVER_URL}/event`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(ev), signal: AbortSignal.timeout(3000), }); if (!r.ok) { console.error(`[bot/observer] ${r.status}: ${await r.text()}`); } } catch (e) { console.error(`[bot/observer] POST failed: ${(e as Error).message}`); } }