import type { IntegrationErrorCode, Judge } from "pi-typesafe"; import type { ProseConfig } from "./config.js"; export type ProseSymptom = "wordy" | "cliches" | "jargon"; export declare const PROSE_SYMPTOMS: readonly ProseSymptom[]; export declare const proseQuestions: { wordy: import("pi-typesafe").NoulQuestion; cliches: import("pi-typesafe").NoulQuestion; jargon: import("pi-typesafe").NoulQuestion; }; export declare const PROSE_LABELS: Record; /** Map the two built-in audience names to descriptions Jev can judge against; anything else is used as written. */ export declare function describeAudience(audience: string): string; export interface ProseVerdict { scores?: Record; /** Symptoms at or above the threshold for this reply, strongest first. */ flagged: ProseSymptom[]; /** Set by the caller when a nudge was sent. */ nudged?: boolean; model?: string; elapsedMs?: number; error?: string; errorCode?: IntegrationErrorCode; } export declare function buildProseRequest(task: string | undefined, reply: string, audience: string): { state: { task: string; audience: string; reply: string; }; questions: { wordy: import("pi-typesafe").NoulQuestion; cliches: import("pi-typesafe").NoulQuestion; jargon: import("pi-typesafe").NoulQuestion; }; }; export interface ProseOptions { config: ProseConfig; judge: Judge; timeoutMs: number; signal?: AbortSignal | undefined; } export declare function evaluateProse(task: string | undefined, reply: string, options: ProseOptions): Promise; /** * Remembers the last three replies' symptoms. A nudge needs a symptom in `trend` of them, so one long answer to a long * question is not punished, and after a nudge the next two replies are given time to change. */ export declare class ProseTrend { private readonly history; private cooldown; readonly counts: Record; record(flagged: readonly ProseSymptom[]): void; /** Symptoms that crossed the trend requirement, or an empty list during cool-down. */ due(trend: number): ProseSymptom[]; markNudged(): void; reset(): void; } /** Sentences shorter than this (as content words) carry nothing worth comparing. */ export declare const SENTENCE_MIN_CHARS = 24; /** A sentence sharing this share of another's content words restates it. */ export declare const SENTENCE_OVERLAP = 0.7; /** A reply restates when at least this share of its substantive sentences was already sent this run. */ export declare const RESTATE_SHARE = 0.5; /** Restatement needs more than one substantive sentence, so a one-line acknowledgement never flags. */ export declare const RESTATE_MIN_SENTENCES = 2; /** The substantive sentences of a reply, as content-word sets. */ export declare function substantiveSentences(text: string): Array>; /** Share of `reply`'s substantive sentences that restate a sentence of `earlier` replies (0..1). */ export declare function restatedShare(reply: string, earlier: readonly string[]): number; /** Remembers the final messages of the current run; reset with each user prompt, since answering the user is never a restatement. */ export declare class RestatementWindow { private readonly limit; private readonly finals; constructor(limit?: number); /** 0..1 share of the reply already stated in an earlier final of this run. */ share(reply: string): number; record(reply: string): void; reset(): void; } /** Queued for the next user prompt, so it shapes the next reply without spending a turn. */ export declare function proseNudge(symptoms: readonly ProseSymptom[], audience: string, counts: Record): string;