import type { RawSource } from "./types.js"; import type { ClaimTargetHint, ReviewItem, ReviewValueType } from "./review-resource.js"; import { type PortablePdfLayout } from "./pdf-layout.js"; /** The upstream-owned portable extraction-result wire identifiers accepted by this adapter. */ export declare const portableExtractionResultFormat = "traverse-extraction-result"; export declare const portableExtractionResultVersion = 1; export declare const extractionEnvelopeImportApiVersion = "survey.kontourai.io/v1alpha1"; export interface PortableExtractionOccurrence { resolverVersion: "exact-occurrence-v1"; count: number; selected: { index: number; start: number; end: number; }; selection: "source-order" | "occurrence-hint"; hintUsed: boolean; ambiguous: boolean; } /** Which model produced one proposal, as the extractor recorded it for that proposal's own request. */ export interface PortableExtractionProducedBy { model: string; modelSource: "provider-reported" | "configured"; /** Content-free digest of the provider request (`sha256:`). */ requestDigest: string; } /** * Deterministic, versioned facts about how a proposal's value relates to the * declared schema and to its own excerpt. Annotations only: Survey carries * them to review and does not route or block on them. */ export interface PortableExtractionEvidenceMatch { checkerVersion: string; schema: "ok" | "type-mismatch" | "enum-mismatch" | "format-invalid"; valueInExcerpt: "match" | "mismatch" | "not-evaluated" | "not-applicable"; tokenBoundary?: boolean; } export interface PortableExtractionProposal { fieldPath: string; candidateValue: unknown; /** * The proposer's own uncalibrated self-report in `0..1`, absent when the * proposer reported none. Survey carries it only when present and never * substitutes a default. */ confidence?: number; provenance: { excerpt: string; locator: string; occurrence: PortableExtractionOccurrence; }; extractor: string; pathIndices?: number[]; inferenceType?: "explicit" | "inferred"; valueType?: ReviewValueType; enumValues?: string[]; producedBy?: PortableExtractionProducedBy; evidenceMatch?: PortableExtractionEvidenceMatch; } export type PortablePreparedArtifactState = { status: "available" | "unavailable" | "storage-error"; requestedRef: string; canonicalRef: string; } | { status: "identity-mismatch"; requestedRef: string; canonicalRef: string; } | { status: "invalid-artifact"; reason: string; canonicalRef: string; } | { status: "digest-mismatch"; requestedRef: string; canonicalRef: string; actualDigest: string; actualContentLength: number; }; /** * Why a run stopped short. The first four are early stops; the last three mean * a dispatched chunk was not (fully) read or answered, and such an envelope * names the affected ranges in `result.coverage`. */ export type PortableExtractionPartialReason = "cancelled" | "max-provider-calls" | "max-total-tokens" | "max-chunks" | "provider-failure" | "content-truncated" | "output-truncated"; /** * One prepared-text range (UTF-16 offsets, the space of `chars:` locators) and * whether it was read and answered. `reason` is present exactly when `status` * is `unread`, and then covers exactly the unread span. */ export interface PortableExtractionCoverageEntry { /** 1-based chunk number. */ chunk: number; start: number; end: number; status: "complete" | "unread" | "output-truncated"; reason?: "provider-failure" | "content-truncated" | "missing-tool-call" | "not-dispatched"; } export interface PortableExtractionResultEnvelope { format: typeof portableExtractionResultFormat; version: typeof portableExtractionResultVersion; source: { ref: string; snapshotRef?: string; }; result: { proposals: PortableExtractionProposal[]; provider: string; model?: string; runId: string; raw: { tokensUsed?: number; }; outcome: { status: "success"; } | { status: "partial"; reason: PortableExtractionPartialReason; } | { status: "failure"; category: "invalid-config" | "invalid-task" | "preparation" | "provider" | "unexpected"; code: string; }; warningClassifications?: Array<{ category: "provider" | "normalization" | "preparation" | "limit" | "storage" | "content" | "other"; code: string; }>; extractedAt: string; providerCalls: number; totalTokensUsed: number; partial?: { reason: PortableExtractionPartialReason; completedChunks: number; remainingChunks: number; tokenOvershoot?: number; }; /** Per-chunk read coverage, ordered by `start`; ranges may overlap. Requires `preparedArtifact`. */ coverage?: PortableExtractionCoverageEntry[]; /** `code` is the upstream error code, informational only; `kind` stays authoritative. */ providerFailures?: Array<{ provider: string; kind: "authentication" | "rate-limit" | "timeout" | "invalid-request" | "unavailable" | "unknown"; retryable: boolean; code?: string; }>; taskDigest?: string; exampleDigests?: string[]; pdfPageOffsets?: number[]; pdfLayout?: PortablePdfLayout; ocrDerived?: true; preparedArtifact?: { format: "traverse-prepared-artifact"; version: 1; digest: string; ref: string; preparationMode: string; preparationVersion: string; contentLength: number; sourceSnapshotRef?: string; }; preparedArtifactState?: PortablePreparedArtifactState; }; } export interface ExtractionEnvelopeImportOptions { /** Stable Survey import identity. Defaults to the upstream run id. */ importName?: string; /** Producer namespace used to avoid cross-producer identity collisions. */ producerNamespace?: string; sourceKind: RawSource["kind"]; /** Survey meaning is supplied at the boundary; it is not added to the upstream wire contract. */ claimTarget: (proposal: PortableExtractionProposal, index: number) => ClaimTargetHint; /** * The prepared artifact as the caller resolved it (the same shape the source * inspector takes). When supplied, the import checks the text against the * envelope's prepared-artifact digest and length, and every proposal's span * against its excerpt: a proposal whose span does not match gets no * ReviewItem and an `excerpt-mismatch` diagnostic, and an artifact that does * not verify makes the import `unresolved`. The text is not stored in the * record. Without it the import records `status.provenance: "unverified"`. */ artifact?: ResolvedExtractionArtifact; } export type ArtifactUnavailableCode = "not-found" | "storage-error" | "access-denied" | "invalid-artifact" | "unknown"; /** A prepared artifact as a caller resolved it: its text and digest, or why it could not be read. */ export type ResolvedExtractionArtifact = { status: "available"; text: string; actualDigest: string; } | { status: "unavailable"; code: ArtifactUnavailableCode; } | { status: "digest-mismatch"; actualDigest: string; }; /** * Whether the import checked its proposals' excerpts against the prepared * artifact text. `verified` means the supplied text matched the envelope's * digest and length and every proposal that produced a ReviewItem matched its * span; `unverified` means no text was supplied, or the text did not verify * (a diagnostic then says why). Required: a record without it, or with any * other value, is refused, so a record whose provenance was stripped cannot * pass as the one-item-per-proposal shape Survey wrote before 6.0.0. */ export type ExtractionEnvelopeImportProvenance = "verified" | "unverified"; /** * Why an import is `unresolved`: its prepared artifact did not resolve, or the * extraction itself produced nothing reviewable. `extraction-failed` is a * failure outcome; `extraction-incomplete` is a partial outcome that proposed * nothing, so no candidate can carry the reason. Either way the import is not * a complete run that found no values. */ export type ExtractionEnvelopeImportDiagnostic = { kind: "artifact-unavailable"; status: "unavailable" | "storage-error" | "identity-mismatch" | "invalid-artifact"; artifactRef?: string; /** The caller's resolver code, present when the artifact supplied at import could not be read. */ code?: ArtifactUnavailableCode; message: string; } | { kind: "digest-mismatch"; artifactRef: string; expectedDigest: string; actualDigest: string; message: string; } | { kind: "extraction-failed"; category: string; code: string; message: string; } | { kind: "extraction-incomplete"; reason: PortableExtractionPartialReason; message: string; } /** The prepared text at this proposal's span is not its excerpt; the proposal produced no ReviewItem. */ | { kind: "excerpt-mismatch"; proposalIndex: number; locator: string; message: string; }; export interface ExtractionEnvelopeImport { apiVersion: typeof extractionEnvelopeImportApiVersion; kind: "ExtractionEnvelopeImport"; metadata: { name: string; producerNamespace: string; }; spec: { envelope: PortableExtractionResultEnvelope; sourceKind: RawSource["kind"]; claimTargets: ClaimTargetHint[]; }; status: { state: "grounded" | "unresolved"; diagnostics: ExtractionEnvelopeImportDiagnostic[]; provenance: ExtractionEnvelopeImportProvenance; }; } export interface ExtractionEnvelopeImportResult { record: ExtractionEnvelopeImport; reviewItems: ReviewItem[]; } export interface ExtractionEnvelopeResolutionIdentity { evidenceId: string; eventId: string; } /** Parse an untrusted upstream document and create Survey's durable import projection. */ export declare function importExtractionEnvelope(serialized: string | PortableExtractionResultEnvelope, options: ExtractionEnvelopeImportOptions): ExtractionEnvelopeImportResult; /** * One ReviewItem per claim slot: every proposal whose claim target names the * same claim (subject, facet, claim type, field or behavior, and claim id when * one is set) at the same `pathIndices` is one candidate set, so two values for * one claim can never be accepted as two separate verified claims. The slot is * the claim the proposal would project to, not the upstream `fieldPath` (two * field paths mapped to one claim are one slot) and not the value. * * Within a slot there is one candidate per distinct canonical value; further * proposals of an already-seen value are recorded on that candidate as * `sameValueProposals`. Two or more distinct values make the set `conflict`. * Distinct `pathIndices` (array items) or distinct claim ids are separate slots, * which is how a producer declares a multi-valued field. */ export declare function buildReviewItemsFromExtractionEnvelopeImport(record: ExtractionEnvelopeImport): ReviewItem[]; export declare function exportExtractionEnvelopeImport(record: ExtractionEnvelopeImport): string; export declare function reimportExtractionEnvelope(serialized: string): ExtractionEnvelopeImport; export declare function createExtractionEnvelopeResolutionIdentity(record: ExtractionEnvelopeImport, proposalIndex: number): ExtractionEnvelopeResolutionIdentity; /** Proposals the import excluded because their span did not match their excerpt. */ export declare function excerptMismatchProposalIndices(record: ExtractionEnvelopeImport): Set; /** Validate the caller-resolved artifact shape; resolver detail beyond the code is refused. */ export declare function assertResolvedExtractionArtifact(artifact: unknown): asserts artifact is ResolvedExtractionArtifact; export type PreparedArtifactCheck = { status: "aligned"; text: string; } | { status: "unavailable"; code: ArtifactUnavailableCode; } | { status: "digest-mismatch"; actualDigest: string; } | { status: "wrong-length"; }; /** * Checks resolved text against the envelope's prepared-artifact identity: the * caller's reported digest, the digest of the text itself, and the declared * length. Shared by import-time verification and the source inspector. */ export declare function checkPreparedArtifact(prepared: PortableExtractionResultEnvelope["result"]["preparedArtifact"], artifact: ResolvedExtractionArtifact): PreparedArtifactCheck; /** Whether the verified prepared text at a proposal's `chars:` span is exactly its excerpt. */ export declare function proposalSpanMatches(text: string, proposal: PortableExtractionProposal): boolean; /** Validate and defensively clone a persisted or browser-delivered import. */ export declare function validateExtractionEnvelopeImport(value: unknown): ExtractionEnvelopeImport;