/** Contracts-core run-limits family (0.2.5 plan 025 Task 1 split). * Moved verbatim from contracts-core.ts; public surface unchanged behind the barrel. */ import type { ProviderTurnResult, ToolResult } from "../contracts-protocol.js"; import type { Message, ToolCallContent } from "./content.js"; /** * Host-authored run limits. Policy axes accept `null` to explicitly disable the cap * (process safety still caps request/response bytes, which reject `null`). Omitted keys * resolve to `DEFAULT_RUN_LIMITS`. */ export interface RunLimits { readonly maxTurns?: number | null; readonly maxProviderAttempts?: number | null; readonly maxToolRounds?: number | null; readonly maxToolCalls?: number | null; readonly maxWallTimeMs?: number | null; readonly maxRequestBytes?: number; readonly maxResponseBytes?: number; readonly maxInputTokens?: number | null; readonly maxOutputTokens?: number | null; readonly maxTotalTokens?: number | null; readonly maxCost?: { readonly amount: number; readonly currency: string; }; /** * Clean cap on stop-hook continuations in one run (plan 106 R1). Default 3; `0` observes stop * hooks but never continues; `null` disables the cap. Layers narrow by min like every other * policy axis, and the cap ends the run with `stopReason: "hook_limit"` (no limit breach). */ readonly maxStopContinuations?: number | null; } /** Fully resolved limits after `resolveRunLimits`: every policy axis is a finite cap or `null` (disabled). */ export interface ResolvedRunLimits { readonly maxTurns: number | null; readonly maxProviderAttempts: number | null; readonly maxToolRounds: number | null; readonly maxToolCalls: number | null; readonly maxWallTimeMs: number | null; readonly maxRequestBytes: number; readonly maxResponseBytes: number; readonly maxInputTokens: number | null; readonly maxOutputTokens: number | null; readonly maxTotalTokens: number | null; readonly maxCost?: { readonly amount: number; readonly currency: string; }; /** Stop-hook continuation cap (plan 106 R1); not a run-limit counter axis. */ readonly maxStopContinuations: number | null; } /** Counter-backed limit axes; `maxStopContinuations` caps a clean stop instead of a breach. */ export type RunLimitName = Exclude, "maxStopContinuations">; export interface RunLimitCounters { readonly turns: number; readonly providerAttempts: number; readonly toolRounds: number; readonly toolCalls: number; readonly wallTimeMs: number; readonly requestBytes: number; readonly responseBytes: number; readonly inputTokens: number; readonly outputTokens: number; readonly totalTokens: number; readonly cost: number; } export interface RunLimitBreach { readonly limit: RunLimitName; readonly maximum: number; readonly observed: number; readonly currency?: string; } /** One dispatched host tool call, bounded to id + name + argument hash (plan 087 T2). */ export interface ToolCallSummary { readonly id: string; readonly name: string; /** `sha256:<64 hex>` over the canonicalized arguments; raw arguments never enter events. */ readonly argHash: string; } /** One run-limit axis and how close it came to its cap: `used / cap` in [0, 1] (plan 087 T2). */ export interface BudgetAxisUsage { readonly axis: RunLimitName; readonly usedRatio: number; } /** Run counters at exhaustion (plan 087 T2): the axes a host reads first when attributing a death. */ export interface BudgetConsumedCounters { readonly turns: number; readonly inputTokens: number; readonly providerAttempts: number; readonly requestBytes: number; } export type GuardrailStage = "input" | "output" | "tool_input" | "tool_output"; export type GuardrailAction = "allow" | "block" | "tripwire" | "interrupt"; export type GuardrailValue = S extends "input" ? readonly Message[] : S extends "output" ? ProviderTurnResult : S extends "tool_input" ? ToolCallContent : ToolResult; export interface GuardrailContext { readonly stage: S; readonly value: GuardrailValue; readonly sessionId: string; readonly runId: string; readonly toolCallId?: string; readonly toolName?: string; /** Same-run completed host tool results, available only at the output stage. */ readonly toolResults?: S extends "output" ? readonly ToolResult[] : never; readonly metadata: Readonly>; readonly signal: AbortSignal; } export interface GuardrailDecision { readonly action: GuardrailAction; readonly reason?: string; /** Public data only; Prism JSON-normalizes, bounds, and redacts it before emission. */ readonly metadata?: Readonly>; } export interface Guardrail { readonly name: string; readonly stage: S; /** Host-authored stable identity for durable definitions; unused by ordinary runs. */ readonly revision?: string; evaluate(context: GuardrailContext): GuardrailDecision | Promise; } export interface GuardrailRecord { readonly guardrail: string; readonly stage: GuardrailStage; readonly action: GuardrailAction; readonly reason?: string; readonly metadata?: Readonly>; } export interface Guardrails { readonly input?: readonly Guardrail<"input">[]; readonly output?: readonly Guardrail<"output">[]; readonly toolInput?: readonly Guardrail<"tool_input">[]; readonly toolOutput?: readonly Guardrail<"tool_output">[]; /** Defaults to sequential; at most 16 stage evaluations run at once. */ readonly maxConcurrency?: number; }