/** * PreflightContextInjector — ADR-9 Primary KPI Lever. * * Runs deterministic per-role graph queries before each agent spawn. * Formats results as markdown and prepends to the agent's first message. * * Key invariants: * - DETERMINISTIC: same contract + role → same output. No LLM in this path. * - NEVER BLOCKS SPAWN: 5s timeout + try/catch; returns firstMessage unchanged on failure. * - RESEARCHER-PHASE2 ISOLATION: NEVER uses contract.title/description/feature text. * Uses ONLY overrides.questionKeywords. * - graph.enabled=false or engineHealth!='ready' → returns firstMessage unchanged. */ import type { GraphClient } from "./client.js"; import type { GraphSection } from "./types.js"; import type { SprintContract } from "../contracts/sprint-contract.js"; import type { IncidentLog } from "./incidents.js"; import type { PrefetchSpec } from "./types.js"; import type { GraphArtifactStore } from "./artifact-store.js"; export type BoberAgentRole = "planner" | "researcher-phase1" | "researcher-phase2" | "architect" | "curator" | "generator" | "evaluator"; /** Derived input for QUERY_BATCHES — computed from contract defensively. */ interface PreflightInput { symbols: string[]; keywords: string[]; questionKeywords: string[]; baselineSha: string; } /** Optional overrides for inject() callers (e.g. pipeline.ts Phase 2 call site). */ export interface InjectOverrides { questionKeywords?: string[]; baselineSha?: string; } /** * Per-role deterministic query batch factory functions. * * Each function receives a PreflightInput and returns a PrefetchSpec[]. * The batch is deterministic: same input → same specs → same output. * * CRITICAL: 'researcher-phase2' uses ONLY input.questionKeywords. * It MUST NOT access contract.title, contract.description, or contract.feature. * The PreflightInput for this role is built exclusively from overrides.questionKeywords. */ export declare const QUERY_BATCHES: Record PrefetchSpec[]>; /** * Derive PreflightInput fields from a SprintContract. * * SprintContract does NOT have symbols/keywords/questionKeywords/baselineSha fields. * This function derives them defensively: * * - symbols: file basenames from estimatedFiles, stripped of extensions. * These are the files the sprint will touch — a good proxy for affected symbols. * - keywords: unique tokens (length >= 4) from title + description, top 8. * Used by Curator search to find relevant code. * - questionKeywords: ALWAYS empty here. Populated only via overrides.questionKeywords * (for researcher-phase2 call sites that pass Phase 1 question tokens). * - baselineSha: defaults to "HEAD~1"; can be overridden via overrides.baselineSha. */ export declare function deriveFromContract(contract: SprintContract | null): PreflightInput; /** * Builds and injects deterministic graph context into agent first messages. * * Constructor takes a GraphClient (may be null if engine not ready) and a * GraphSection config. inject() is the only public method. * * Usage in agent files: * ```typescript * const injector = new PreflightContextInjector(graphPipelineLifecycle.getGraphClient(), config.graph); * const msg = await injector.inject("curator", contract, userMessage); * ``` */ export declare class PreflightContextInjector { private readonly client; private readonly config; private readonly incidents?; private readonly projectRoot?; private readonly artifactStore?; constructor(client: GraphClient | null, config: GraphSection | undefined, incidents?: IncidentLog | undefined, projectRoot?: string | undefined, artifactStore?: GraphArtifactStore | undefined); /** * Inject pre-flight graph context into a first message. * * Fast-path: returns firstMessage UNCHANGED when: * - graph.enabled !== true * - client is null * - engineHealth !== 'ready' * * Timeout: 5000ms. On timeout or any error, logs an incident and returns * firstMessage unchanged. Agent spawn is NEVER blocked. * * Researcher-Phase2 isolation: NEVER uses contract.title/description/feature. * Uses ONLY overrides.questionKeywords. Passing a non-null contract for * researcher-phase2 is defensively handled — feature text is still NOT used. * * @param role Agent role string. * @param contract Sprint contract (or null for research phase / architect). * @param firstMessage The agent's first user message. * @param overrides Optional overrides: questionKeywords, baselineSha. */ inject(role: BoberAgentRole, contract: SprintContract | null, firstMessage: string, overrides?: InjectOverrides): Promise; /** * Record one `graph-preflight` telemetry event to .bober/history.jsonl. * * Resolves a project root by preferring the constructor-injected projectRoot, * then the active pipeline lifecycle singleton — so telemetry fires for every * role even though most call sites construct the injector with only * (client, config). Best-effort: any failure is swallowed so telemetry can * NEVER break an agent spawn. * * Each row answers the runtime question directly: did graph context get added * (`injected`), roughly how many tokens (`approxTokensAdded`), under what * `outcome`, and how long the preflight took (`elapsedMs`). */ private recordTelemetry; /** Core injection logic — called by inject() within the timeout race. */ private runInject; /** Look up the token budget for a given role from config, with fallback to defaults. */ private getBudgetForRole; } /** * Extract meaningful search keywords from a block of text (e.g. Phase 1 questions). * * Used by pipeline.ts to derive overrides.questionKeywords for researcher-phase2 * from the Phase 1 questions array. * * Returns up to 10 unique tokens of length >= 5, lowercased. * Does NOT preserve the original text — the output is transformed tokens only, * which is safe to pass to researcher-phase2 (no feature text leak). */ export declare function extractKeywords(text: string): string[]; export {}; //# sourceMappingURL=preflight-injector.d.ts.map