import type { IntegrationErrorCode, Judge } from "pi-typesafe"; import type { ContextConfig, SecurityConfig } from "./config.js"; import type { OutputFormat } from "./excerpt.js"; import type { TaskMessage } from "./guard.js"; export type Retention = "all" | "errors_and_summary" | "summary_only"; /** Learn from compression outcomes to improve future decisions. */ export interface CompressionOutcome { tool: string; retention: Retention; format: OutputFormat | undefined; recalled: boolean; timestamp: number; } /** Track compression outcomes to learn which formats work best. */ export declare class CompressionLearner { private outcomes; private readonly maxOutcomes; /** Record a compression outcome. */ record(tool: string, retention: Retention, format: OutputFormat | undefined, recalled: boolean): void; /** Mark the most recent compression for a tool as recalled (agent needed the full output later). */ noteRecall(tool: string): void; /** Get the best retention strategy for a tool based on past outcomes. */ bestRetention(tool: string): Retention | undefined; /** Get compression statistics for a tool. */ stats(tool: string): { total: number; recalled: number; byRetention: Record; }; /** Reset the learner. */ reset(): void; } export declare const outputQuestions: { injection: import("pi-typesafe").NoulQuestion; exfiltration: import("pi-typesafe").NoulQuestion; }; export declare function buildOutputRequest(tool: string, text: string, task: string | undefined, security: boolean, compress: boolean, context?: readonly TaskMessage[]): { state: { tool: string; task: string; chars: number; lines: number; distinctLines: number; distinctLinesCapped: boolean; output: string; context: { role: "user" | "assistant"; text: string; }[]; }; questions: { format?: import("pi-typesafe").ChoiceQuestion<{ readonly vitest_jest: "A Vitest or Jest run: ✓/✗/× or PASS/FAIL per test, a 'Test Files' or 'Tests:' summary."; readonly node_test: "Node's built-in test runner: TAP lines 'ok'/'not ok' with '# tests', or the spec reporter with ✔/✖ and 'ℹ tests'."; readonly tsc: "TypeScript compiler diagnostics: 'file(line,col): error TSnnnn:' lines, 'Found N errors'."; readonly eslint: "ESLint report: a file path line followed by 'line:col error|warning message rule', then '✖ N problems'."; readonly pytest: "pytest: dots/F per test, '___ test_name ___' failure headers, 'E ' assertion lines, 'FAILED'/'PASSED' lines, '=== N passed/failed ===' summary."; readonly git_diff: "A unified diff: 'diff --git', '---'/'+++', '@@' hunks with +/- lines."; readonly git_log: "git log or git status output: 'commit ' blocks or one-line hashes with subjects; 'modified:'/'new file:' status lines."; readonly npm_install: "npm, pnpm, or yarn install: 'added N packages', 'npm warn', 'deprecated', 'vulnerabilities', 'up to date'."; readonly other: "Anything else: source code, data, documentation, a shell listing, a mixed or unknown log."; }>; retention?: import("pi-typesafe").ChoiceQuestion<{ readonly all: "Keep the full output: source code, structured data, exact requested text, or unique details may be needed. Also use this when unsure."; readonly errors_and_summary: "This is operational output whose value sits in a few lines: failing tests with their assertions, errors with file and line, changed files with counts, commit hashes with subjects, package manager notices, plus a short head/tail. Code keeps exactly those lines; the full text remains in a local file."; readonly summary_only: "This is repetitive successful operational output; a short tail with the final status and a size/removal note suffice. The full text remains in a local file."; }>; injection?: import("pi-typesafe").NoulQuestion; exfiltration?: import("pi-typesafe").NoulQuestion; }; }; export interface OutputVerdict { /** True when the output carries credential-shaped values (not names of credentials); see findSecrets. */ secret: boolean; /** Stable id of the set of secrets found, so the same secret seen again in a session is noted once. */ secretId?: string; /** One fingerprint per distinct credential-shaped value; repeats are per value, not per set. */ secretIds?: string[]; /** One fingerprint per stand-in value (fixture or documentation shape); traced once, never announced. */ syntheticIds?: string[]; suspicious: boolean; retention: Retention; /** Set when Jev named a known output format with at least `context.formatConfidence`; drives the parser choice. */ format?: OutputFormat; formatConfidence?: number; injection?: number; exfiltration?: number; confidence?: number; model?: string; elapsedMs?: number; error?: string; errorCode?: IntegrationErrorCode; } export interface OutputOptions { security: SecurityConfig; context: ContextConfig; judge?: Judge | undefined; timeoutMs: number; signal?: AbortSignal | undefined; /** Multiple text/image blocks keep their positions; do not flatten them for compression. */ compressible?: boolean; taskContext?: readonly TaskMessage[]; } export declare function evaluateOutput(tool: string, text: string, task: string | undefined, options: OutputOptions, compressionLearner?: CompressionLearner): Promise; /** Session-bookkeeping view of per-block verdicts: the worst security signal wins, and retention stays per block. */ export declare function mergeOutput(blocks: readonly OutputVerdict[]): OutputVerdict; /** No copied tool text enters the instruction channel. A warning is not proof of an attack. */ export declare function securityNotice(verdict: OutputVerdict): string | undefined; /** * Deterministic excerpts, not an AI-written summary. At most 6K characters, including diagnostic lines. A recognised * `format` uses its parser (exact failing tests, errors with file:line, changed files); otherwise head/diagnostics/tail. */ export declare function compressOutput(text: string, retention: Retention, format?: OutputFormat): string | undefined; /** Identity of a text result for duplicate detection: ANSI colour and trailing whitespace do not make a new output. */ export declare function outputKey(text: string): string; /** Replacement for a result that repeats an earlier one of this session. The earlier text is unchanged; nothing new to read. */ export declare function duplicateNote(text: string, earlierTool: string): string; /** Never trust a path advertised in untrusted tool text. Store our own exact copy before replacing it. */ export declare function saveOutput(text: string): Promise;