Direction shift 2026-04-22: docs/CONTROL_PLANE_PRD.md becomes the long-horizon architecture target. Existing Lakehouse (docs/PRD.md, Phases 0-37) is preserved as the reference implementation and first consumer. New 6-layer architecture: L1 Universal API /v1/chat /v1/usage /v1/sessions /v1/tools /v1/context L2 Routing & Policy Engine (rules, fallback chains, cost gating) L3 Provider Adapter Layer (Ollama + OpenRouter + Gemini + Claude) L4 Knowledge + Memory + Playbooks (already built) L5 Execution Loop (scenarios + bot/cycle.ts instances) L6 Observability + token accounting Phases 38-44 sequenced with detailed per-phase specs in the PRD. Current scope: staffing domain (synthetic workers_500k, contracts, emails, SMS, playbooks). DevOps (Terraform/Ansible) is long-horizon target — architecture-compatible but not current. Files added: - docs/CONTROL_PLANE_PRD.md — 6-layer architecture, Phase 38-44 sequencing with staffing-first Truth Layer + Validation pipeline - bot/ — manual-only PR bot scaffold. First consumer test-bed for /v1/chat (Phase 38). Mem0-aligned ADD/UPDATE/NOOP apply semantics; KB feedback loop reads prior cycles on same gap and injects into cloud prompt so bot cycles compound like scenario.ts runs do. - tests/multi-agent/run_stress.ts — the 6-task diverse stress test referenced in the previous commit but missing from its staging Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
35 lines
1.2 KiB
TypeScript
35 lines
1.2 KiB
TypeScript
// 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<string, any>;
|
|
}
|
|
|
|
export async function postEvent(ev: BotObserverEvent): Promise<void> {
|
|
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}`);
|
|
}
|
|
}
|