@usekaval/kaval
Advanced tools
+524
| /** Public proof-protocol types. Field names intentionally match the hosted REST JSON exactly. */ | ||
| export type IsoTimestamp = string; | ||
| export type ContentDigest = string; | ||
| export type ScalarValue = string | number | boolean | null; | ||
| export type Materiality = "low" | "medium" | "high" | "critical"; | ||
| export type ActionReversibility = "reversible" | "partially_reversible" | "irreversible" | "unknown"; | ||
| export type ActionDisposition = "ALLOW" | "BLOCK" | "REVIEW"; | ||
| export type SystemState = "complete" | "degraded" | "source_unavailable"; | ||
| export interface RecordRef { | ||
| system: string; | ||
| id: string; | ||
| table?: string; | ||
| } | ||
| export interface ActionContext { | ||
| description: string; | ||
| materiality: Materiality; | ||
| reversibility: ActionReversibility; | ||
| false_allow_cost_usd?: number; | ||
| false_block_cost_usd?: number; | ||
| wait_cost_usd?: number; | ||
| } | ||
| export interface DecisionThreshold { | ||
| policy_id: string; | ||
| policy_version: string; | ||
| materiality: Materiality; | ||
| maximum_false_allow_risk: number; | ||
| minimum_evidence_coverage: number; | ||
| } | ||
| export interface HumanActionOverride { | ||
| override_id: string; | ||
| review_case_id: string; | ||
| action_key: string; | ||
| action_context_sha256: string; | ||
| approved_by: string; | ||
| reason: string; | ||
| original_decision: ActionDisposition; | ||
| created_at: IsoTimestamp; | ||
| expires_at: IsoTimestamp; | ||
| } | ||
| export interface CalibratedRisk { | ||
| kind: "calibrated"; | ||
| point_estimate: number; | ||
| upper_bound: number; | ||
| calibration_version: string; | ||
| confidence_level: number; | ||
| } | ||
| export interface UnavailableRisk { | ||
| kind: "unavailable"; | ||
| reason: string; | ||
| evidence_strength: "weak" | "moderate" | "strong" | "decisive"; | ||
| } | ||
| export type RiskEstimate = CalibratedRisk | UnavailableRisk; | ||
| export interface ActionDecision { | ||
| action_decision_id: string; | ||
| proof_id: string; | ||
| decision: ActionDisposition; | ||
| system_state: SystemState; | ||
| material_claim_ids: string[]; | ||
| risk: RiskEstimate; | ||
| threshold: DecisionThreshold; | ||
| reason_codes: string[]; | ||
| summary: string; | ||
| unresolved_gap_ids: string[]; | ||
| human_override?: HumanActionOverride; | ||
| decided_at: IsoTimestamp; | ||
| expires_at: IsoTimestamp; | ||
| } | ||
| export interface EntityRef { | ||
| name: string; | ||
| id?: string; | ||
| type?: string; | ||
| } | ||
| export interface TemporalInterval { | ||
| from?: IsoTimestamp; | ||
| to?: IsoTimestamp; | ||
| } | ||
| export type CanonicalClaimType = "identity" | "relationship" | "numeric" | "temporal" | "quote" | "existence" | "policy" | "legal" | "scientific" | "causal" | "comparison" | "media_authenticity" | "generic"; | ||
| export type ClaimModality = "asserted" | "scheduled" | "forecast" | "conditional" | "opinion" | "alleged" | "estimated"; | ||
| export interface CanonicalClaim { | ||
| id: string; | ||
| text: string; | ||
| subject: EntityRef; | ||
| predicate: string; | ||
| object?: EntityRef | ScalarValue; | ||
| claim_type: CanonicalClaimType; | ||
| negated: boolean; | ||
| modality: ClaimModality; | ||
| as_of: IsoTimestamp; | ||
| valid_time?: TemporalInterval; | ||
| jurisdiction?: string; | ||
| geography?: string; | ||
| units?: string; | ||
| denominator?: string; | ||
| definition?: string; | ||
| materiality: Materiality; | ||
| dependencies: string[]; | ||
| } | ||
| export interface ClaimDependency { | ||
| claim_id: string; | ||
| depends_on_claim_id: string; | ||
| requirement: "required" | "supporting"; | ||
| rationale?: string; | ||
| } | ||
| export interface ClaimDag { | ||
| schema_version: string; | ||
| claims: CanonicalClaim[]; | ||
| roots: string[]; | ||
| dependency_edges: ClaimDependency[]; | ||
| } | ||
| export type SourceClass = "system_of_record" | "regulator" | "official_registry" | "filing" | "audited_report" | "primary_document" | "first_party" | "peer_reviewed" | "dataset" | "archive" | "expert_analysis" | "reputable_secondary" | "aggregator" | "user_supplied" | "web"; | ||
| export type ArtifactKind = "html" | "json" | "xml" | "pdf" | "text" | "database_row" | "api_response" | "image" | "audio" | "video" | "other"; | ||
| export type LegacyAuthority = "primary" | "secondary" | "aggregator"; | ||
| export type SourceProximity = "direct_record" | "direct_measurement" | "participant" | "primary_analysis" | "secondary_analysis" | "hearsay"; | ||
| export interface ProofAdmissibility { | ||
| allowed_source_classes: SourceClass[]; | ||
| forbidden_source_classes: SourceClass[]; | ||
| allowed_artifact_kinds: ArtifactKind[]; | ||
| required_structured_fields: string[]; | ||
| require_raw_artifact: boolean; | ||
| allow_user_supplied_as_decisive: boolean; | ||
| } | ||
| export interface ProofAuthorityRule { | ||
| minimum_legacy_authority: LegacyAuthority; | ||
| minimum_proximity: SourceProximity; | ||
| must_include_any_source_class: SourceClass[]; | ||
| require_authenticity: boolean; | ||
| require_claim_specific_fitness: boolean; | ||
| claim_specific_rule: string; | ||
| } | ||
| export interface IndependenceRule { | ||
| minimum_evidence_families: number; | ||
| minimum_publishers: number; | ||
| maximum_members_per_family_counted: number; | ||
| require_lineage_resolution: boolean; | ||
| require_source_family_removal_test: boolean; | ||
| maximum_family_removal_delta: number; | ||
| } | ||
| export interface TemporalProofRule { | ||
| maximum_evidence_age_s: number; | ||
| require_valid_time_overlap: boolean; | ||
| require_published_by_as_of: boolean; | ||
| require_known_by_as_of: boolean; | ||
| allow_future_effective_evidence: boolean; | ||
| future_effective_grace_s: number; | ||
| archive_requirement: "never" | "when_historical" | "always"; | ||
| } | ||
| export type ChallengeStrategy = "explicit_counter_hypothesis" | "negated_search" | "current_holder_search" | "primary_source_recovery" | "correction_retraction_search" | "source_family_removal" | "evidence_order_perturbation" | "adversarial_near_miss"; | ||
| export interface ChallengeRule { | ||
| required: boolean; | ||
| strategies: ChallengeStrategy[]; | ||
| minimum_counterevidence_queries: number; | ||
| require_strongest_opposing_interpretation: boolean; | ||
| require_stopping_reason: boolean; | ||
| } | ||
| export type InvalidationTrigger = "source_changed" | "source_retracted" | "source_unavailable" | "newer_authoritative_evidence" | "entity_resolution_changed" | "policy_changed" | "calibration_changed" | "valid_time_boundary" | "manual_correction"; | ||
| export interface PolicyExpiryRule { | ||
| ttl_s: number; | ||
| recheck_before_expiry_s: number; | ||
| invalidation_triggers: InvalidationTrigger[]; | ||
| } | ||
| export interface ActionThreshold { | ||
| materiality: Materiality; | ||
| maximum_false_allow_risk: number; | ||
| minimum_evidence_coverage: number; | ||
| minimum_support_probability: number; | ||
| on_uncalibrated: "BLOCK" | "REVIEW"; | ||
| on_degraded: "BLOCK" | "REVIEW"; | ||
| } | ||
| export interface ProofPolicy { | ||
| policy_id: string; | ||
| version: string; | ||
| effective_from: IsoTimestamp; | ||
| superseded_at?: IsoTimestamp; | ||
| claim_types: CanonicalClaimType[]; | ||
| semantics: "open_world" | "closed_world"; | ||
| admissibility: ProofAdmissibility; | ||
| authority: ProofAuthorityRule; | ||
| independence: IndependenceRule; | ||
| temporal: TemporalProofRule; | ||
| challenge: ChallengeRule; | ||
| conflict_resolution: string[]; | ||
| force_review_conditions: string[]; | ||
| expiry: PolicyExpiryRule; | ||
| action_thresholds: ActionThreshold[]; | ||
| } | ||
| export interface RawArtifactMetadata { | ||
| artifact_id: string; | ||
| storage_ref: string; | ||
| kind: ArtifactKind; | ||
| media_type: string; | ||
| byte_length: number; | ||
| content_hash: ContentDigest; | ||
| captured_at: IsoTimestamp; | ||
| compression: "none" | "gzip" | "br" | "zstd" | "other"; | ||
| encryption?: { | ||
| scheme: string; | ||
| key_reference: string; | ||
| }; | ||
| redaction_state: "none" | "metadata_only" | "redacted" | "sealed"; | ||
| } | ||
| export interface HttpArtifactMetadata { | ||
| status: number; | ||
| etag?: string; | ||
| last_modified?: string; | ||
| content_type?: string; | ||
| final_url?: string; | ||
| } | ||
| export interface SourceVersion { | ||
| source_version_id: string; | ||
| source_id: string; | ||
| source_signature: string; | ||
| source_class: SourceClass; | ||
| legacy_authority: LegacyAuthority; | ||
| canonical_url?: string; | ||
| raw_artifact: RawArtifactMetadata; | ||
| http?: HttpArtifactMetadata; | ||
| version_state: "active" | "superseded" | "corrected" | "retracted" | "unavailable"; | ||
| published_at?: IsoTimestamp; | ||
| modified_at?: IsoTimestamp; | ||
| observed_at: IsoTimestamp; | ||
| known_at?: IsoTimestamp; | ||
| valid_time?: TemporalInterval; | ||
| publisher_id?: string; | ||
| author_id?: string; | ||
| owner_id?: string; | ||
| discovery_providers: string[]; | ||
| acquisition_activity_id: string; | ||
| supersedes_source_version_id?: string; | ||
| correction_notice_source_version_id?: string; | ||
| } | ||
| export type EvidenceLocator = { | ||
| kind: "text_offsets"; | ||
| start: number; | ||
| end: number; | ||
| } | { | ||
| kind: "json_pointer"; | ||
| pointer: string; | ||
| } | { | ||
| kind: "html_selector"; | ||
| selector: string; | ||
| text_start?: number; | ||
| text_end?: number; | ||
| } | { | ||
| kind: "pdf_region"; | ||
| page: number; | ||
| bounding_box: [number, number, number, number]; | ||
| } | { | ||
| kind: "table_cell"; | ||
| table: string; | ||
| row: string | number; | ||
| column: string | number; | ||
| } | { | ||
| kind: "record_field"; | ||
| system: string; | ||
| table: string; | ||
| record_id: string; | ||
| field: string; | ||
| } | { | ||
| kind: "media_time"; | ||
| start_ms: number; | ||
| end_ms: number; | ||
| }; | ||
| export interface EvidenceSpan { | ||
| evidence_span_id: string; | ||
| source_version_id: string; | ||
| locator: EvidenceLocator; | ||
| quote?: string; | ||
| structured_value?: ScalarValue; | ||
| span_hash: ContentDigest; | ||
| language?: string; | ||
| extracted_at: IsoTimestamp; | ||
| visibility: "public" | "tenant_private" | "restricted"; | ||
| quarantined: boolean; | ||
| injection_detected: boolean; | ||
| } | ||
| export interface LineageEdge { | ||
| lineage_edge_id: string; | ||
| from_source_version_id: string; | ||
| to_source_version_id: string; | ||
| relationship: "derived_from" | "copied_from" | "syndicated_from" | "quotes" | "cites" | "updates" | "supersedes" | "corrects" | "retracts"; | ||
| confidence: number; | ||
| explicit_attribution: boolean; | ||
| evidence_span_ids: string[]; | ||
| } | ||
| export interface EvidenceFamily { | ||
| evidence_family_id: string; | ||
| label: string; | ||
| member_source_version_ids: string[]; | ||
| origin_source_version_ids: string[]; | ||
| lineage_edge_ids: string[]; | ||
| methods: Array<"explicit_attribution" | "exact_text" | "near_duplicate" | "shared_origin" | "publisher_ownership" | "manual">; | ||
| publisher_group_id?: string; | ||
| upstream_dataset_id?: string; | ||
| confidence: number; | ||
| independence_rationale: string; | ||
| } | ||
| export interface StanceProbabilities { | ||
| support: number; | ||
| refute: number; | ||
| neutral: number; | ||
| } | ||
| export interface EvidenceAssessment { | ||
| evidence_assessment_id: string; | ||
| claim_id: string; | ||
| evidence_span_id: string; | ||
| evidence_family_id: string; | ||
| stance: StanceProbabilities; | ||
| entity_match: { | ||
| state: "match" | "partial" | "mismatch" | "unknown"; | ||
| score: number; | ||
| rationale: string; | ||
| }; | ||
| scope_fit: { | ||
| state: "exact" | "partial" | "mismatch" | "unknown"; | ||
| score: number; | ||
| rationale: string; | ||
| }; | ||
| temporal_fit: { | ||
| state: "applicable" | "partial" | "inapplicable" | "unknown"; | ||
| score: number; | ||
| rationale: string; | ||
| }; | ||
| extraction_confidence: number; | ||
| source_fitness: number; | ||
| support_mode: "direct" | "inferential"; | ||
| admissible: boolean; | ||
| exclusion_reason?: string; | ||
| } | ||
| export type AssessmentGapKind = "missing_authority" | "missing_independence" | "missing_counterevidence_search" | "entity_ambiguity" | "scope_mismatch" | "temporal_ambiguity" | "source_unavailable" | "conflict_unresolved" | "calibration_unavailable" | "policy_incomplete" | "other"; | ||
| export interface AssessmentGap { | ||
| gap_id: string; | ||
| kind: AssessmentGapKind; | ||
| severity: "informational" | "material" | "blocking"; | ||
| description: string; | ||
| resolvable: boolean; | ||
| required_evidence: string[]; | ||
| } | ||
| /** Exact server-derived cohort identity used to issue this claim assessment. */ | ||
| export interface CalibrationSupportIdentity { | ||
| feature_schema_version: string; | ||
| feature_schema_hash: ContentDigest; | ||
| support_fingerprint: ContentDigest; | ||
| feature_vector: Record<string, unknown>; | ||
| } | ||
| export interface ClaimAssessment { | ||
| claim_assessment_id: string; | ||
| claim_id: string; | ||
| claim_state: "supported" | "refuted" | "mixed" | "unresolved" | "unverifiable"; | ||
| temporal_state: "current" | "superseded" | "future" | "expired" | "unknown"; | ||
| system_state: SystemState; | ||
| stance: StanceProbabilities; | ||
| evidence_coverage: number; | ||
| calibrated_support?: { | ||
| probability: number; | ||
| calibration_version: string; | ||
| }; | ||
| /** Always present on claim assessments inside an issued ProofPacket. */ | ||
| calibration_support: CalibrationSupportIdentity; | ||
| risk_upper_bound?: number; | ||
| evidence_assessments: EvidenceAssessment[]; | ||
| decisive_evidence_span_ids: string[]; | ||
| counterevidence_span_ids: string[]; | ||
| unresolved_gaps: AssessmentGap[]; | ||
| what_would_change_this: string[]; | ||
| assessed_at: IsoTimestamp; | ||
| } | ||
| export interface ProtocolManifest { | ||
| protocol: "kaval-proof"; | ||
| protocol_version: string; | ||
| schema_version: string; | ||
| compiler_version: string; | ||
| planner_version: string; | ||
| adjudicator_version: string; | ||
| model_versions: Record<string, string>; | ||
| tool_versions: Record<string, string>; | ||
| parser_versions: Record<string, string>; | ||
| } | ||
| export interface PolicyBinding { | ||
| claim_id: string; | ||
| policy_id: string; | ||
| policy_version: string; | ||
| policy_hash: ContentDigest; | ||
| } | ||
| export interface CalibrationMetrics { | ||
| brier_score: number; | ||
| log_loss: number; | ||
| expected_calibration_error: number; | ||
| sample_size: number; | ||
| } | ||
| export type CalibrationManifest = { | ||
| status: "calibrated"; | ||
| version: string; | ||
| protocol_version: string; | ||
| training_dataset_hash: ContentDigest; | ||
| evaluation_dataset_hash: ContentDigest; | ||
| feature_schema_version: string; | ||
| feature_schema_hash: ContentDigest; | ||
| method: string; | ||
| trained_through: IsoTimestamp; | ||
| applicable_claim_types: string[]; | ||
| applicable_domains: string[]; | ||
| metrics: CalibrationMetrics; | ||
| } | { | ||
| status: "withheld"; | ||
| reason: string; | ||
| evidence_strength_scale_version: string; | ||
| }; | ||
| export type ProvenanceActivityKind = "compile" | "plan" | "search" | "fetch" | "render" | "parse" | "extract" | "entity_resolve" | "lineage_cluster" | "adjudicate" | "challenge" | "calibrate" | "decide"; | ||
| export interface ProvenanceActivity { | ||
| activity_id: string; | ||
| kind: ProvenanceActivityKind; | ||
| parent_activity_ids: string[]; | ||
| status: "completed" | "failed" | "cancelled" | "timed_out"; | ||
| provider?: string; | ||
| tool_version?: string; | ||
| model_version?: string; | ||
| parser_version?: string; | ||
| parameters_hash: ContentDigest; | ||
| input_hashes: ContentDigest[]; | ||
| output_hashes: ContentDigest[]; | ||
| started_at: IsoTimestamp; | ||
| completed_at: IsoTimestamp; | ||
| error_code?: string; | ||
| } | ||
| export interface ProofPacket { | ||
| proof_id: string; | ||
| created_at: IsoTimestamp; | ||
| research_contract: { | ||
| held_belief: string; | ||
| as_of: IsoTimestamp; | ||
| action: ActionContext; | ||
| domain?: string; | ||
| subject_hint?: string; | ||
| jurisdiction?: string; | ||
| geography?: string; | ||
| units?: string; | ||
| }; | ||
| protocol: ProtocolManifest; | ||
| claim_dag: ClaimDag; | ||
| policies: ProofPolicy[]; | ||
| policy_bindings: PolicyBinding[]; | ||
| source_versions: SourceVersion[]; | ||
| evidence_spans: EvidenceSpan[]; | ||
| evidence_families: EvidenceFamily[]; | ||
| lineage_edges: LineageEdge[]; | ||
| claim_assessments: ClaimAssessment[]; | ||
| action_decision: ActionDecision; | ||
| calibration: CalibrationManifest; | ||
| provenance: { | ||
| activities: ProvenanceActivity[]; | ||
| root_activity_ids: string[]; | ||
| research_stopping_reason: string; | ||
| }; | ||
| expiry: { | ||
| issued_at: IsoTimestamp; | ||
| expires_at: IsoTimestamp; | ||
| recheck_at: IsoTimestamp; | ||
| invalidation_triggers: InvalidationTrigger[]; | ||
| monitor_id?: string; | ||
| }; | ||
| signature?: { | ||
| algorithm: string; | ||
| key_id: string; | ||
| signature: string; | ||
| }; | ||
| } | ||
| /** POST /v1/audit body. `domain` is descriptive metadata; it never expands calibration support. */ | ||
| export interface AuditInput { | ||
| text: string; | ||
| as_of: IsoTimestamp; | ||
| materiality?: Materiality; | ||
| intended_action?: string; | ||
| reversibility?: ActionReversibility; | ||
| false_allow_cost_usd?: number; | ||
| false_block_cost_usd?: number; | ||
| wait_cost_usd?: number; | ||
| domain?: string; | ||
| subject_hint?: string; | ||
| jurisdiction?: string; | ||
| geography?: string; | ||
| units?: string; | ||
| context?: string; | ||
| aliases?: string[]; | ||
| primary_domains?: string[]; | ||
| origin_urls?: string[]; | ||
| record?: RecordRef; | ||
| record_field?: string; | ||
| } | ||
| interface ProofGateInputBase { | ||
| expected_dependency_versions?: Record<string, string>; | ||
| material_claim_ids: string[]; | ||
| threshold: DecisionThreshold; | ||
| action: ActionContext; | ||
| } | ||
| /** POST /v1/gate requires exactly one durable proof locator. */ | ||
| export type ProofGateInput = ProofGateInputBase & ({ | ||
| proof_id: string; | ||
| proof_key?: never; | ||
| } | { | ||
| proof_key: string; | ||
| proof_id?: never; | ||
| }); | ||
| export type ProofGateState = "current" | "expired" | "not_yet_valid" | "invalidated" | "dependency_changed" | "integrity_failed" | "policy_mismatch" | "not_found" | "operational_failure"; | ||
| export type ProofBillingClass = "action_gate" | "direct_refresh" | "web_refresh" | "deep_refresh" | "operational_failure"; | ||
| export interface ProofEnforcementResult { | ||
| mode: "shadow" | "block_only" | "bounded"; | ||
| controlApplied: boolean; | ||
| executionAllowed: boolean | null; | ||
| wouldAllow: boolean; | ||
| reason: string; | ||
| } | ||
| export interface ProofGateResult { | ||
| proofId: string; | ||
| state: ProofGateState; | ||
| decision: ActionDecision; | ||
| billingClass: ProofBillingClass; | ||
| proofReused: boolean; | ||
| researchPerformed: false; | ||
| humanOverrideApplied?: true; | ||
| latencyMs: number; | ||
| reason?: string; | ||
| enforcement?: ProofEnforcementResult; | ||
| } | ||
| export {}; |
| /** Public proof-protocol types. Field names intentionally match the hosted REST JSON exactly. */ | ||
| export {}; |
+15
-0
@@ -5,2 +5,4 @@ /** | ||
| */ | ||
| import type { AuditInput, ProofGateInput, ProofGateResult, ProofPacket } from "./proof.js"; | ||
| export type * from "./proof.js"; | ||
| export type VerdictStatus = "current" | "stale" | "contradicted" | "unsupported" | "conflicting" | "insufficient"; | ||
@@ -143,2 +145,4 @@ /** Speed/depth tier for a verify() call. */ | ||
| fetch?: typeof fetch; | ||
| /** Default deadline for each HTTP operation. Defaults to 30 seconds; set null to disable. */ | ||
| timeoutMs?: number | null; | ||
| } | ||
@@ -149,2 +153,6 @@ /** Transport options for one billable API operation. Kaval generates a UUID by default. Supply the | ||
| idempotencyKey?: string; | ||
| /** Cancels the operation and every bounded retry. */ | ||
| signal?: AbortSignal; | ||
| /** Per-call deadline override. Set null to disable the constructor default. */ | ||
| timeoutMs?: number | null; | ||
| } | ||
@@ -159,2 +167,3 @@ export interface KavalBatchOptions extends RequestOptions { | ||
| private readonly f; | ||
| private readonly timeoutMs; | ||
| constructor(opts?: KavalOptions); | ||
@@ -179,2 +188,8 @@ private billablePost; | ||
| monitor(input: MonitorInput, options?: RequestOptions): Promise<MonitorResult>; | ||
| /** Build, sign, and persist a complete action-bound proof packet. */ | ||
| audit(input: AuditInput, options?: RequestOptions): Promise<ProofPacket>; | ||
| /** Apply a current durable proof to the exact action without repeating research. */ | ||
| gateAction(input: ProofGateInput, options?: RequestOptions): Promise<ProofGateResult>; | ||
| /** Short alias for gateAction(). */ | ||
| gate(input: ProofGateInput, options?: RequestOptions): Promise<ProofGateResult>; | ||
| /** Report what actually happened, to calibrate trust over time. */ | ||
@@ -181,0 +196,0 @@ reportOutcome(input: { |
+84
-35
@@ -83,2 +83,23 @@ /** | ||
| } | ||
| function requestSignal(external, timeoutMs) { | ||
| if (timeoutMs !== null && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) { | ||
| throw new RangeError("timeoutMs must be a positive finite number or null"); | ||
| } | ||
| if (timeoutMs === null) | ||
| return { signal: external, cleanup() { } }; | ||
| const controller = new AbortController(); | ||
| const onAbort = () => controller.abort(external?.reason); | ||
| if (external?.aborted) | ||
| onAbort(); | ||
| else | ||
| external?.addEventListener("abort", onAbort, { once: true }); | ||
| const timer = setTimeout(() => controller.abort(new Error(`kaval request timed out after ${timeoutMs}ms`)), timeoutMs); | ||
| return { | ||
| signal: controller.signal, | ||
| cleanup() { | ||
| clearTimeout(timer); | ||
| external?.removeEventListener("abort", onAbort); | ||
| }, | ||
| }; | ||
| } | ||
| /** The kaval client: a belief your system holds in, a typed freshness verdict out. */ | ||
@@ -89,5 +110,11 @@ export class Kaval { | ||
| f; | ||
| timeoutMs; | ||
| constructor(opts = {}) { | ||
| this.base = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, ""); | ||
| this.f = opts.fetch ?? fetch; | ||
| this.timeoutMs = opts.timeoutMs === undefined ? 30_000 : opts.timeoutMs; | ||
| if (this.timeoutMs !== null && | ||
| (!Number.isFinite(this.timeoutMs) || this.timeoutMs <= 0)) { | ||
| throw new RangeError("timeoutMs must be a positive finite number or null"); | ||
| } | ||
| this.headers = { "content-type": "application/json" }; | ||
@@ -100,40 +127,50 @@ if (opts.apiKey) | ||
| const headers = { ...this.headers, "idempotency-key": idempotencyKey }; | ||
| for (let attempt = 0; attempt < MAX_BILLABLE_ATTEMPTS; attempt += 1) { | ||
| let res; | ||
| try { | ||
| res = await this.f(`${this.base}${path}`, { | ||
| method: "POST", | ||
| headers, | ||
| // JSON.stringify omits `undefined` keys, so optional params drop out automatically. | ||
| body: JSON.stringify(body), | ||
| }); | ||
| } | ||
| catch (error) { | ||
| // A fetch rejection is transport-ambiguous: the server may have committed before the | ||
| // connection failed. Retry once with the SAME key so it replays instead of double-billing. | ||
| if (attempt + 1 < MAX_BILLABLE_ATTEMPTS) | ||
| const request = requestSignal(options.signal, options.timeoutMs === undefined ? this.timeoutMs : options.timeoutMs); | ||
| try { | ||
| for (let attempt = 0; attempt < MAX_BILLABLE_ATTEMPTS; attempt += 1) { | ||
| let res; | ||
| try { | ||
| res = await this.f(`${this.base}${path}`, { | ||
| method: "POST", | ||
| headers, | ||
| signal: request.signal, | ||
| // JSON.stringify omits `undefined` keys, so optional params drop out automatically. | ||
| body: JSON.stringify(body), | ||
| }); | ||
| } | ||
| catch (error) { | ||
| if (request.signal?.aborted) { | ||
| throw attachIdempotencyKey(error, idempotencyKey); | ||
| } | ||
| // A fetch rejection is transport-ambiguous: the server may have committed before the | ||
| // connection failed. Retry once with the SAME key so it replays instead of double-billing. | ||
| if (attempt + 1 < MAX_BILLABLE_ATTEMPTS) | ||
| continue; | ||
| throw attachIdempotencyKey(error, idempotencyKey); | ||
| } | ||
| let payload; | ||
| try { | ||
| payload = await res.json(); | ||
| } | ||
| catch (error) { | ||
| // A 2xx without the promised JSON contract is a protocol failure, not a successful null | ||
| // result. Error responses may legitimately come from a non-Kaval intermediary as text. | ||
| if (res.ok) | ||
| throw attachIdempotencyKey(error, idempotencyKey); | ||
| payload = null; | ||
| } | ||
| if (res.ok) | ||
| return payload; | ||
| const code = apiErrorCode(payload); | ||
| if (attempt + 1 < MAX_BILLABLE_ATTEMPTS && | ||
| code !== undefined && | ||
| AMBIGUOUS_IDEMPOTENCY_CODES.has(code)) { | ||
| continue; | ||
| throw attachIdempotencyKey(error, idempotencyKey); | ||
| } | ||
| throw new KavalError(res.status, payload, idempotencyKey); | ||
| } | ||
| let payload; | ||
| try { | ||
| payload = await res.json(); | ||
| } | ||
| catch (error) { | ||
| // A 2xx without the promised JSON contract is a protocol failure, not a successful null | ||
| // result. Error responses may legitimately come from a non-Kaval intermediary as text. | ||
| if (res.ok) | ||
| throw attachIdempotencyKey(error, idempotencyKey); | ||
| payload = null; | ||
| } | ||
| if (res.ok) | ||
| return payload; | ||
| const code = apiErrorCode(payload); | ||
| if (attempt + 1 < MAX_BILLABLE_ATTEMPTS && | ||
| code !== undefined && | ||
| AMBIGUOUS_IDEMPOTENCY_CODES.has(code)) { | ||
| continue; | ||
| } | ||
| throw new KavalError(res.status, payload, idempotencyKey); | ||
| } | ||
| finally { | ||
| request.cleanup(); | ||
| } | ||
| throw new Error("unreachable billable request state"); | ||
@@ -173,2 +210,14 @@ } | ||
| } | ||
| /** Build, sign, and persist a complete action-bound proof packet. */ | ||
| audit(input, options) { | ||
| return this.billablePost("/v1/audit", input, options); | ||
| } | ||
| /** Apply a current durable proof to the exact action without repeating research. */ | ||
| gateAction(input, options) { | ||
| return this.billablePost("/v1/gate", input, options); | ||
| } | ||
| /** Short alias for gateAction(). */ | ||
| gate(input, options) { | ||
| return this.gateAction(input, options); | ||
| } | ||
| /** Report what actually happened, to calibrate trust over time. */ | ||
@@ -175,0 +224,0 @@ reportOutcome(input) { |
+2
-2
| { | ||
| "name": "@usekaval/kaval", | ||
| "version": "0.2.1", | ||
| "version": "0.3.0", | ||
| "license": "Apache-2.0", | ||
| "description": "The freshness gate for AI — verify a belief your system already holds is still true.", | ||
| "description": "Action-bound verification for AI agents — signed proof packets plus ALLOW/BLOCK/REVIEW gates.", | ||
| "type": "module", | ||
@@ -7,0 +7,0 @@ "main": "./dist/index.js", |
+55
-5
@@ -24,2 +24,49 @@ # @usekaval/kaval | ||
| ## Build a proof, then gate the action | ||
| ```ts | ||
| import { Kaval } from "@usekaval/kaval"; | ||
| const kaval = new Kaval({ apiKey: process.env.KAVAL_API_KEY }); | ||
| const proof = await kaval.audit({ | ||
| text: "Acme is eligible for a $12,000 refund", | ||
| as_of: new Date().toISOString(), | ||
| intended_action: "Issue Acme a $12,000 refund", | ||
| materiality: "critical", | ||
| reversibility: "irreversible", | ||
| false_allow_cost_usd: 12_000, | ||
| record: { system: "billing", table: "refunds", id: "acme-2026" }, | ||
| }); | ||
| const gate = await kaval.gateAction({ | ||
| proof_id: proof.proof_id, | ||
| material_claim_ids: proof.action_decision.material_claim_ids, | ||
| threshold: proof.action_decision.threshold, | ||
| action: proof.research_contract.action, | ||
| }); | ||
| if (gate.enforcement?.controlApplied === true) { | ||
| if (gate.enforcement.executionAllowed !== true) { | ||
| throw new Error("Kaval blocked the action"); | ||
| } | ||
| } else if ( | ||
| gate.enforcement === undefined && | ||
| (gate.state !== "current" || gate.decision.decision !== "ALLOW") | ||
| ) { | ||
| // A direct integration without staged enforcement fails closed. | ||
| throw new Error("Kaval did not allow the action"); | ||
| } | ||
| // controlApplied === false is shadow mode: record wouldAllow, but keep the customer's existing | ||
| // action policy authoritative. | ||
| ``` | ||
| `audit()` returns the complete typed `ProofPacket`: atomic claims, policy bindings, immutable source | ||
| versions, exact evidence spans, lineage families, claim assessments, calibrated/withheld risk, | ||
| provenance, expiry, and signature. `gateAction()` is the cheap action-time check and includes staged | ||
| `enforcement` (`shadow`, `block_only`, or `bounded`) when configured by the deployment. | ||
| Only `enforcement.controlApplied === true` may control execution. Shadow mode returns | ||
| `controlApplied: false`, `executionAllowed: null`, and a counterfactual `wouldAllow` for calibration. | ||
| Both methods accept `{ idempotencyKey?, signal?, timeoutMs? }`. The constructor defaults to a | ||
| 30-second deadline; override per call or set `timeoutMs: null` to disable it. Cancellation and timeout | ||
| errors retain `error.idempotencyKey`, because an interrupted billable request can be ambiguous. | ||
| ## Gate a belief before you act on it | ||
@@ -67,3 +114,6 @@ | ||
| ```ts | ||
| const decision = await kaval.verify({ belief: "Acme's CEO is Jane Doe", mode: "deep" }); | ||
| const decision = await kaval.verify({ | ||
| belief: "Acme's CEO is Jane Doe", | ||
| mode: "deep", | ||
| }); | ||
@@ -97,6 +147,6 @@ decision.tier; // "deep" — the tier that ran (echoes your `mode`) | ||
| `verify` · `check` · `extractAndCheck` · `scanStore` · `monitor` · `reportOutcome` · `kaval` · | ||
| `kavalBatch` · `health`. Billable methods accept a final `{ idempotencyKey? }` request-options | ||
| argument (`kavalBatch` includes it alongside `concurrency`). Construct with `{ apiKey, baseUrl?, | ||
| fetch? }` — `baseUrl` defaults to | ||
| `audit` · `gateAction` (`gate` alias) · `verify` · `check` · `extractAndCheck` · `scanStore` · | ||
| `monitor` · `reportOutcome` · `kaval` · `kavalBatch` · `health`. Billable methods accept a final | ||
| `{ idempotencyKey?, signal?, timeoutMs? }` request-options argument (`kavalBatch` includes it alongside | ||
| `concurrency`). Construct with `{ apiKey, baseUrl?, fetch?, timeoutMs? }` — `baseUrl` defaults to | ||
| `https://api.usekaval.com`. Works in Node 18+, browsers, and edge runtimes (uses the global `fetch`). | ||
@@ -103,0 +153,0 @@ |
55935
70.6%7
40%985
150%156
47.17%