/**
 * TopicIntentExtractor — converts a raw conversation turn into EvidenceEvents.
 *
 * Layer 1 component. Reads a new substantive message + the topic's existing
 * EstablishedRef set, asks a Tier-1 LLM to identify signal events (new
 * extractions, re-references, affirmations, contradictions), and persists
 * them via TopicIntentStore.appendEvidence.
 *
 * Framework-agnostic: the LLM call itself is injected. Production wires it
 * to Instar's LlmQueue + chosen provider; tests stub it.
 *
 * The extractor returns the events it CREATED so callers can act on them
 * (e.g., trigger conflict-mark when two refs come into conflict).
 */
import { TopicIntentStore, type EvidenceEvent, type RefKind, type EstablishedRef } from './TopicIntent.js';
import type { IntelligenceProvider } from './types.js';
export interface ExtractorInput {
    topicId: number;
    arcId: string;
    message: {
        id: string;
        text: string;
        fromUser: boolean;
        turn: number;
        at: string;
    };
    /** Existing refs on the topic, provided so the LLM can anchor signals. */
    existingRefs: EstablishedRef[];
    /**
     * Rolling conversational summary for the topic (from TopicMemory), giving the
     * extractor broader context to judge significance + horizon. Untrusted user
     * content — rendered inside a delimited data block, never as instructions.
     */
    rollingSummary?: string;
}
/**
 * The LLM is asked to return zero or more SignalProposals per message.
 * Each proposal references either an existing refId (re-reference,
 * affirmation, contradiction) OR a new ref proposition text (initial
 * extraction).
 *
 * The actual provider call is injected; this type is the contract.
 */
export interface SignalProposal {
    kind: 'new-ref' | 'reref' | 'affirm' | 'contradict';
    /** Required for reref / affirm / contradict; null for new-ref. */
    refId: string | null;
    /** Required for new-ref; describes the proposition being extracted. */
    propositionText?: string;
    /** Required for new-ref; the type of proposition. */
    refKind?: RefKind;
    /** Optional: extractor's confidence in this signal (for logging; not used in projection). */
    llmConfidence?: number;
}
export type ExtractFn = (input: ExtractorInput) => Promise<SignalProposal[]>;
export interface ExtractorResult {
    emitted: EvidenceEvent[];
    createdRefs: Array<{
        refId: string;
        kind: RefKind;
        text: string;
    }>;
    skipped: number;
}
export declare class TopicIntentExtractor {
    private store;
    private extractFn;
    constructor(store: TopicIntentStore, extractFn: ExtractFn);
    /**
     * Process a new message: run the LLM, translate proposals to events,
     * append to store, return what was created.
     */
    ingest(input: ExtractorInput): Promise<ExtractorResult>;
    /**
     * Translate a SignalProposal into the (refId, EvidenceEvent, refInit?) tuple
     * to be appended. Returns null if the proposal is invalid.
     */
    private translateProposal;
}
/**
 * Build the extractor prompt for production use. Separated so prompt
 * tuning can iterate without touching the extractor logic.
 *
 * The actual LLM provider call is wired in by the caller; this function
 * returns the prompt string + the JSON schema description for the
 * structured response.
 */
/** Hard length caps so a wall-of-text can't dominate the prompt (injection hardening). */
export declare const MAX_MESSAGE_CHARS = 4000;
export declare const MAX_REF_TEXT_CHARS = 400;
export declare const MAX_SUMMARY_CHARS = 2000;
export declare function buildExtractorPrompt(input: ExtractorInput): {
    systemPrompt: string;
    userPrompt: string;
};
/**
 * Parse the LLM's response into SignalProposal[]. Tolerates the LLM
 * wrapping the JSON in code fences or prose preamble.
 */
export declare function parseExtractorResponse(raw: string): SignalProposal[];
/**
 * Production ExtractFn factory: wires buildExtractorPrompt → an injected
 * IntelligenceProvider (fast tier) → parseExtractorResponse.
 *
 * Degrade-safe by design: if no provider is configured, OR the call
 * throws/times out, it returns [] — capture becomes a silent no-op rather than
 * breaking the conversation path it's attached to. The provider is responsible
 * for transport (subscription/REPL-pool, never raw API) and rate/cost limits;
 * production injects the shared-LlmQueue-backed provider.
 *
 * Framework-agnostic: the provider is injected, never a Claude/Codex import.
 *
 * `onDegrade` is an optional observability hook: it fires (with the topicId and
 * a reason) on each degrade path so the caller can meter it, WITHOUT weakening
 * degrade-safety — the function still returns [] regardless. This keeps
 * "observability from brick one" (spec §10) for the two degrade counters
 * (no-intelligence, cap-or-error) that captureTurn can't otherwise distinguish
 * from a genuine empty extraction.
 */
export type ExtractDegradeReason = 'no-intelligence' | 'error';
export declare function createLlmExtractFn(intelligence?: IntelligenceProvider, onDegrade?: (reason: ExtractDegradeReason, topicId: number) => void): ExtractFn;
//# sourceMappingURL=TopicIntentExtractor.d.ts.map