import { A as AppToolSettingChangeFn, a as AppToolConfirmFn, b as AppToolRegisterFn, c as AppTool, d as AppToolFailureResult, e as AppToolSuccessPayload, f as AppToolResult, g as AppToolCancelledResult, h as AppToolDataPayload, i as AppToolDataReadyResult, j as AppToolDataPartialResult, k as AppToolDataNotReadyPayload, l as AppToolNotReadyResult, m as AppToolFailurePayload, N as NextAction, n as AppToolErrorPayload, o as AppToolLegacyErrorResult, p as AppToolReadyResult, q as AppToolFactory, D as DataCoverage, S as SampleRows, F as FieldSummary, G as GoalSummary, r as GroupSummary, s as NumericSummary, R as RatioSummary, W as WeightedSummary } from './types-DSDLWvXe.js'; export { t as AppToolClass, u as AppToolConfirmation, v as AppToolConfirmationPolicy, w as AppToolConfirmationRequest, x as AppToolDataOutcome, y as AppToolDefinition, z as AppToolFailureOutcome, B as AppToolHandler, C as AppToolOutcome, E as AppToolParametersSchema, H as AppToolPartialResult, I as AppToolResultExtra, J as AppToolSchema, K as DataCoverageInput, L as DataProvenance, M as DataScope, O as RatioBasisSummary, P as RowBasisSummary, T as TimeRange, Q as WeightedBasisSummary } from './types-DSDLWvXe.js'; type UseEvalModeParams = { getState: () => unknown; applyOverrides: (overrides: Record) => void; }; /** * Exposes `window.__evalGetAppState` and `__evalSetAppState` for the grader when * `__askCorvaEvalMode` is set; a no-op in production. Helpers attach to the top * window (DC apps run in a same-origin iframe the harness polls), falling back * to the own window when the top is cross-origin. */ declare function useEvalMode({ getState, applyOverrides }: UseEvalModeParams): void; type UseEvalShadowParams = { onSettingChange: AppToolSettingChangeFn; /** Setting keys mirrored into the shadow in eval mode; MUST be reference-stable. */ shadowKeys: ReadonlySet; }; type UseEvalShadowResult = { evalShadow: Record; wrappedOnSettingChange: AppToolSettingChangeFn; }; /** * Eval-mode shadow: a synchronous source of truth for setting keys, immune to * prop round-trip drift. In production `__askCorvaEvalMode` is unset and the * shadow stays empty. */ declare function useEvalShadow({ onSettingChange, shadowKeys, }: UseEvalShadowParams): UseEvalShadowResult; /** * Receiver side of the class-host bridge: the class hands over a typed object * (or null) via `onBridgeReady`; tools reach it through `getBridge`. Both * callbacks are reference-stable. */ declare function useHostBridge(): { getBridge: () => T | null; onBridgeReady: (bridge: T | null) => void; }; type RegisterAppToolsOptions = { /** * How this host asks the user. A host that cannot ask passes nothing, and a * gated call then declines rather than proceeding unconfirmed. */ confirm?: AppToolConfirmFn | null; }; /** * Registers app tools through the host callback. The registry receives proxies * that read the latest tools per render, so re-registration happens only when * the roster (names/order) changes; cleanup re-registers an empty list. */ declare function useRegisterAppTools(registerAppTools: AppToolRegisterFn | null, tools: AppTool[], options?: RegisterAppToolsOptions): void; /** * What a command actually changed, against what the app already held. * * `changed: { severeDataDelay: 60 }` when the setting was already 60 tells the * agent it moved something it did not, and the agent then reports that to the * user. A command's `changed` is a diff or it is fiction. */ type ValueEquality = (left: unknown, right: unknown) => boolean; /** Value equality for JSON-shaped settings, independent of object identity. */ declare function jsonValueEqual(left: unknown, right: unknown): boolean; declare function diffSettings({ requested, current, equals, }: { requested: Record; current: Current; equals?: ValueEquality; }): { changed: Record; isNoOp: boolean; }; /** The message a no-op command returns, so "nothing happened" is stated once. */ declare const NO_OP_MESSAGE = "The app already had the requested values; nothing changed."; type AppCommandPatch = { [Key in Extract]?: State[Key]; }; type RequireStringStateKey = [ Extract ] extends [never] ? { readonly __appCommandRequiresStringKey: never; } : object; type AppCommandAccepted = { ok: true; /** Complete desired values for every key this command owns. */ requested: AppCommandPatch; /** App-specific, already-validated information passed only to the writer. */ meta?: Meta; }; type AppCommandRejected = { ok: false; result: AppToolFailureResult; }; type AppCommandPreparation = AppCommandAccepted | AppCommandRejected; type AppCommandWriteContext = { /** Scope/version that was validated and must be used by the writer. */ scopeToken: ScopeToken; /** Effective rendered state used for validation. */ before: State; /** Host-confirmed state used for changed/no-op truth. */ confirmedBefore: State; requested: AppCommandPatch; changed: Record; meta: Meta | undefined; }; type AppCommandUnconfirmedContext = AppCommandWriteContext & { after: State; unconfirmedKeys: string[]; }; type AppCommandSuccessContext = AppCommandWriteContext & { after: State; actualChanged: Record; }; type RunAppCommandOptions = { toolName: string; /** Stable scope/version token; re-read immediately before write to close races. */ readScopeToken: () => ScopeToken | Promise; /** Reads the effective rendered state. Pending writes belong in this source. */ readState: (scopeToken: ScopeToken) => State | Promise; /** Host props without pending/eval overlays; defaults to `readState`. */ readConfirmedState?: (scopeToken: ScopeToken) => State | Promise; /** Strict parsing and all cross-field validation happen here, before `write`. */ prepare: (current: State) => AppCommandPreparation | Promise>; /** Receives only a completely validated plan. */ write: (context: AppCommandWriteContext) => void | Promise; /** * App-owned post-write view. For an asynchronous host this may include pending * intent; eventual host acceptance must still be proved by an echo test/live probe. */ readBack?: (scopeToken: ScopeToken) => State | Promise; equals?: ValueEquality; scopeEquals?: (left: ScopeToken, right: ScopeToken) => boolean; selectResultingState?: (state: State) => ResultingState; noOpMessage?: string; decorateNoOp?: (current: State) => Pick; decorateSuccess?: (context: AppCommandSuccessContext) => Pick; onUnconfirmed?: (context: AppCommandUnconfirmedContext) => AppToolFailureResult; } & RequireStringStateKey; /** * One safe command transaction: plan everything, diff, write once, then prove the * state that actually became visible. Domain parsing and ownership stay in the app. */ declare function runAppCommand({ toolName, readScopeToken, readState, readConfirmedState, prepare, write, readBack, equals, scopeEquals, selectResultingState, noOpMessage, decorateNoOp, decorateSuccess, onUnconfirmed, }: RunAppCommandOptions): Promise; /** The user was asked and said no. */ declare const CONFIRMATION_DECLINED_CODE = "user_cancelled"; /** * There was nobody to ask: the host registered app tools without a confirmation * adapter. Distinct from a decline because the operator can fix it, and the agent * should not tell the user they refused something they never saw. */ declare const CONFIRMATION_UNAVAILABLE_CODE = "confirmation_unavailable"; type ConfirmationDecision = 'run' | 'declined' | 'unavailable'; type ResolveConfirmationParams = { tool: AppTool; params: Record; confirm: AppToolConfirmFn | null; isEvalMode: boolean; }; /** * True when a tool declares any intent to gate — deliberately either half, not * both. A half-declaration is a broken gate, and treating it as "no gate" is how * a tool whose author asked for confirmation writes without one. */ declare function isConfirmationGated(tool: AppTool): boolean; /** * Decides whether a gated call may reach its handler. * * The one outcome this must never produce is `run` because no host adapter was * present. A destructive write that proceeds for want of anyone to ask is exactly * the failure the gate exists to prevent, so an unavailable host declines. */ declare function resolveConfirmation({ tool, params, confirm, isEvalMode, }: ResolveConfirmationParams): Promise; type CancelledParams = { toolName: string; decision: Exclude; }; /** * Reports a call that never ran. `nextAction` is `NONE` in both cases: a decline * is not an invitation to retry, and a missing adapter will not appear because the * agent asked again. */ declare function appToolCancelled({ toolName, decision, }: CancelledParams): AppToolCancelledResult; /** * Result envelope for a data digest. * * The outcome is DERIVED from coverage rather than declared: an app cannot report * READY over a set it only partly analysed, which is the failure mode that makes * "the average of page one" read as the average of everything. */ declare function appToolData>(payload: AppToolDataPayload, now?: () => string): AppToolDataReadyResult | AppToolDataPartialResult; /** * The handler ran and there is nothing true to report yet — still loading, no * asset in scope, a pipeline that never populated. * * A completed call, not a failure: routing this through the transport's error * channel takes the real failure path, which on some branches stops the agent's * turn altogether. And reporting zeros instead is what turns "no data" into a * confidently wrong answer. */ declare function appToolDataNotReady>(message: string, payload: AppToolDataNotReadyPayload): AppToolNotReadyResult; /** * Bounds an advertised wait. `delayMs: number` cannot express "positive and sane" * in the type, and both ends are harmful: a zero or negative delay reads as * "call again immediately", and an hour-long one strands the user while a page * fetch finishes. */ declare const MIN_WAIT_DELAY_MS = 500; declare const MAX_WAIT_DELAY_MS = 60000; declare function boundWaitDelay(nextAction: NextAction): NextAction; /** * A refusal the agent can act on rather than merely report. * * The request was understood and the app declined — a call that never executed * (a throw, a vanished iframe, a timeout) belongs to the transport's error * channel instead. `outcome` says which kind of refusal it is, `code` names the * specific one for evals and branching, `nextAction` names the only move that can * change the answer, and `message` is the half the agent quotes. */ declare function appToolFailure(message: string, payload: AppToolFailurePayload): AppToolFailureResult; /** * A command whose writer was never wired up. * * Hosts pass setters optionally (`onSettingChange?.(key, value)`), so a tool can * be registered, do nothing, and report success — the worst outcome available, * because the agent tells the user a setting changed. This is a real dependency * failure and no argument can fix it. */ declare function writerUnavailable({ toolName, code, writer, }: { toolName: string; code: string; writer: string; }): AppToolResult; /** * A command that did what it was asked. * * `changed` must be the real diff: echoing a value the app already held tells the * agent it moved something it did not, and the agent repeats that to the user. * `message` is where a no-op says so. */ declare function appToolSuccess(payload?: AppToolSuccessPayload): AppToolReadyResult; /** * The v1 refusal: a sentence and nothing else. Kept for the apps that predate the * contract; the conformance suite flags it, because an agent cannot branch on it. */ declare function appToolError(error: string, payload?: AppToolErrorPayload): AppToolLegacyErrorResult; /** Composes per-tool factories into the app's single `createAllTools(deps)`. */ declare function createToolset(factories: ReadonlyArray>): (deps: Deps) => AppTool[]; /** * Default ceiling on rows returned to the agent. A data digest exists so the * agent does not have to page through raw rows; handing it thousands of them * blows the turn's context for no gain. */ declare const DEFAULT_ROW_LIMIT = 200; /** * Aggregate raw values into one honest summary. `count` is how many values were * actually numeric — the agent needs it to say "averaged over N", and a blank * or non-numeric cell must not be counted as a zero. */ declare function summarizeNumbers(values: readonly unknown[]): NumericSummary; /** * Weighted summary for a per-entity average — a column already holding "average * connection time for this well" cannot be averaged again across wells: wells * with 12 connections and 200 connections would count the same. Weighting by * the event count gives the figure a user computing by hand would get * (combined time ÷ combined event count). * * `weightedAverage` is null when no row carries both a value and a weight, so a * caller must fall back to `average` and say which basis it used. */ declare function summarizeWeighted({ values, weights, }: { values: readonly unknown[]; weights: readonly unknown[]; }): WeightedSummary; /** * The exact cross-entity average from a total and a count column: * sum(total) / sum(count). Prefer this over weighting per-entity averages — * `tripping_connection_time` / `tripping_connection_count` beats re-weighting * `tripping_connection_average`, because the means were already rounded and a * missing weight would drop the entity entirely. */ declare function summarizeRatio({ rows, numeratorField, denominatorField, }: { rows: readonly Record[]; numeratorField: string; denominatorField: string; }): RatioSummary; /** * Per-field summaries over the rows the app currently has loaded. * * `weightOf` is the app's say in how a field must be aggregated: it names the * field carrying that field's weights (an event count, an interval length, a * stage count) or null for a plain mean. Only the app knows which of its metrics * are per-entity averages, while deciding what that means for the resulting * figure — and stating the basis it used — is the same everywhere, so it lives * here instead of being re-derived in every app. */ declare function summarizeField({ rows, field, weightField, ratioFields, }: { rows: readonly Record[]; field: string; weightField?: string | null; ratioFields?: { numerator: string; denominator: string; } | null; }): FieldSummary; /** * Per-field summaries over the rows the app currently has loaded. * * `ratioOf` and `weightOf` are the app's say in how a field must be aggregated, * in that order of preference: a total/count pair is exact, weighting a * per-entity average is a good approximation, and a plain mean is neither. * Only the app knows which of its metrics are per-entity averages, while what * that means for the resulting figure — and stating the basis it used — is the * same everywhere, so it lives here instead of in every app. */ declare function summarizeFields({ rows, fields, weightOf, weightBy, ratioOf, }: { rows: readonly Record[]; fields: readonly string[]; weightOf?: (field: string) => string | null; /** Simple form of `weightOf` for callers with a static mapping. */ weightBy?: Record; ratioOf?: (field: string) => { numerator: string; denominator: string; } | null; }): Record; /** * How much of what was asked the digest actually covers. * * `isComplete` is derived, never declared: it is the one field that separates * "the average of everything shown" from "the average of page one", and the * envelope reads it to decide READY against PARTIAL — so an app cannot claim * completeness over a set it only partly analysed. A named omission is itself * incompleteness, even when the counts happen to line up. */ declare function buildCoverage({ requestedEntities, analysedEntities, requestedRows, analysedRows, omissions, }: { requestedEntities: number; analysedEntities: number; requestedRows?: number; analysedRows: number; omissions?: readonly string[]; }): DataCoverage; /** * Example rows, in their own block with their own counts. * * `totalAnalysed` is what the aggregates were computed over, `returned` is what * fitted in the turn, and `truncated` states the gap. Kept apart from the * aggregates because a capped list sitting beside them gets quoted as the * dataset — "these are the wells" about page one of forty. */ declare function buildSampleRows({ rows, totalAnalysed, limit, }: { rows: readonly Row[]; totalAnalysed: number; limit?: number; }): SampleRows; /** * Same summaries, computed per group — "average per well", "total hours per * operation", "ROP per hole section". Grouping lives here because an agent * re-deriving it from returned rows can only see the rows that survived the row * cap, which silently turns a per-group figure into a partial one. * * Rows whose group field is empty are reported as `ungroupedRowCount` rather than * bucketed under a made-up key. */ declare function summarizeGroups({ rows, fields, groupBy, weightOf, weightBy, ratioOf, }: { rows: readonly Record[]; fields: readonly string[]; groupBy: string; weightOf?: (field: string) => string | null; weightBy?: Record; ratioOf?: (field: string) => { numerator: string; denominator: string; } | null; }): { groups: GroupSummary[]; ungroupedRowCount: number; }; /** * A figure against the target the app displays for it. `direction` decides what * "met" means: a connection time of 4.2 beats a goal of 5, an ROP of 4.2 does * not, and the sign of the delta alone cannot tell them apart. */ declare function summarizeGoal({ metric, target, actual, direction, source, }: { metric: string; target: number | null; actual: number | null; direction: GoalSummary['direction']; source?: string; }): GoalSummary; type PendingWriteSnapshot = Record; type PendingHostUpdate = { origin?: 'auto'; } | { origin: 'external'; changedKeys: readonly Extract[]; }; type PendingWriteOverlay = { /** Clears pending intent whenever the rendered entity/time/view scope changes. */ setScope(scope: unknown): void; /** Call immediately before/with the app-owned writer. */ record>(key: Key, value: State[Key], hostState: State): void; /** Feed each new host-confirmed snapshot before reading effective state. */ reconcile(hostState: State, update?: PendingHostUpdate): void; /** Host props plus only the newest still-pending value per key. */ getEffective(hostState: State): State; /** Diagnostic/test view; values are ordered oldest to newest. */ getPending(): PendingWriteSnapshot; clear(): void; }; /** * Tracks host-round-trip writes without confusing an older echo with the newest * intent. It never observes eval shadow and it owns no React lifecycle. */ declare function createPendingWriteOverlay({ initialScope, equals, scopeEquals, }?: { initialScope?: unknown; equals?: ValueEquality; /** Scope tokens are identities by default; customize only for normalized value tokens. */ scopeEquals?: ValueEquality; }): PendingWriteOverlay; type ResultBudget = { bytes: number; maxBytes: number; withinBudget: boolean; }; type CappedItems = { items: Item[]; returned: number; total: number; truncated: boolean; omittedIdentities: Identity[]; }; type CappedEntityRows = { rows: Row[]; returned: number; total: number; truncated: boolean; coveredEntityIds: Identity[]; omittedEntityIds: Identity[]; omittedRowsByEntity: Array<{ entityId: Identity; count: number; }>; }; /** Exact UTF-8 size of a JSON tool result; throws for non-serializable values. */ declare function measureSerializedBytes(value: unknown): number; declare function checkResultBudget(value: unknown, maxBytes: number): ResultBudget; /** Caps a named catalogue and preserves the identities that were not returned. */ declare function capNamedItems(items: readonly Item[], limit: number, getIdentity: (item: Item) => Identity): CappedItems; /** * Fair row cap: round-robin across entities so an early entity cannot consume the * whole payload. The caller receives exact omissions instead of a bare boolean. */ declare function capRowsByEntity({ rows, getEntityId, perEntityLimit, totalLimit, }: { rows: readonly Row[]; getEntityId: (row: Row) => Identity; perEntityLimit: number; totalLimit: number; }): CappedEntityRows; /** * Typed readers for a tool's untyped `params` (`Record`) — the * single ingress where the model's arguments are narrowed, so handlers stay * cast-free. Numbers are coerced from strings (the model sometimes serializes * numeric arguments as `"123"`). */ type Params$1 = Record | undefined; declare function isRecord(value: unknown): value is Record; declare function getString(params: Params$1, key: string): string | null; declare function getNumber(params: Params$1, key: string): number | null; declare function getBoolean(params: Params$1, key: string): boolean | null; declare function getRecord(params: Params$1, key: string): Record | null; /** Numeric array with non-finite entries dropped; `[]` when absent or not an array. */ declare function getNumberArray(params: Params$1, key: string): number[]; /** String array filtered to string entries; `[]` when absent or not an array. */ declare function getStringArray(params: Params$1, key: string): string[]; /** Array filtered to entries that pass `guard`; `[]` when absent or not an array. */ declare function getTypedArray(params: Params$1, key: string, guard: (value: unknown) => value is T): T[]; /** * Three-state readers for a tool's untyped `params`. * * The lenient `get*` readers collapse "absent" and "garbage" into `null`, which * hides a whole class of silent bug: a handler that guards with `value === null` * treats `{ moderateDataDelay: 'banana' }` as "not sent", ignores it, applies the * OTHER arguments in the same call, and reports success — so the agent believes a * threshold it never set. Absent means the caller said nothing; invalid means the * caller said something wrong, and those need different answers. */ type Params = Record | undefined; type ParamRead = { state: 'absent'; } | { state: 'valid'; value: T; } | { state: 'invalid'; received: unknown; }; /** * JSON numbers only — no numeric strings. `Number('0x10')` is 16 and `Number('')` * is 0, so accepting strings quietly widens a numeric field into JS literal * syntax; a threshold is worth rejecting rather than guessing at. */ declare function readNumber(params: Params, key: string): ParamRead; declare function readBoolean(params: Params, key: string): ParamRead; declare function readString(params: Params, key: string): ParamRead; /** One of a closed set of values, so a handler does not re-check the enum itself. */ declare function readEnum(params: Params, key: string, allowed: readonly T[]): ParamRead; /** The value when the caller sent a usable one, else null. */ declare function valueOf(read: ParamRead): T | null; declare function isSent(read: ParamRead): boolean; /** * The first argument the caller got wrong, so a handler can reject the whole call * before applying any of it. Reporting one field at a time is enough: the agent * fixes it and re-sends, and a partial apply is what this prevents. */ declare function firstInvalid(reads: Record>): { field: string; received: unknown; } | null; /** Whether the caller sent at least one of a set where one is required. */ declare function hasAnyOf(reads: Record>, fields: readonly string[]): boolean; export { type AppCommandAccepted, type AppCommandPreparation, type AppCommandRejected, type AppCommandSuccessContext, type AppCommandUnconfirmedContext, type AppCommandWriteContext, AppTool, AppToolCancelledResult, AppToolConfirmFn, AppToolDataNotReadyPayload, AppToolDataPartialResult, AppToolDataPayload, AppToolDataReadyResult, AppToolErrorPayload, AppToolFactory, AppToolFailurePayload, AppToolFailureResult, AppToolLegacyErrorResult, AppToolNotReadyResult, AppToolReadyResult, AppToolRegisterFn, AppToolResult, AppToolSettingChangeFn, AppToolSuccessPayload, CONFIRMATION_DECLINED_CODE, CONFIRMATION_UNAVAILABLE_CODE, type CappedEntityRows, type CappedItems, type ConfirmationDecision, DEFAULT_ROW_LIMIT, DataCoverage, FieldSummary, GoalSummary, GroupSummary, MAX_WAIT_DELAY_MS, MIN_WAIT_DELAY_MS, NO_OP_MESSAGE, NextAction, NumericSummary, type ParamRead, type PendingHostUpdate, type PendingWriteOverlay, type PendingWriteSnapshot, RatioSummary, type RegisterAppToolsOptions, type ResultBudget, type RunAppCommandOptions, SampleRows, type ValueEquality, WeightedSummary, appToolCancelled, appToolData, appToolDataNotReady, appToolError, appToolFailure, appToolSuccess, boundWaitDelay, buildCoverage, buildSampleRows, capNamedItems, capRowsByEntity, checkResultBudget, createPendingWriteOverlay, createToolset, diffSettings, firstInvalid, getBoolean, getNumber, getNumberArray, getRecord, getString, getStringArray, getTypedArray, hasAnyOf, isConfirmationGated, isRecord, isSent, jsonValueEqual, measureSerializedBytes, readBoolean, readEnum, readNumber, readString, resolveConfirmation, runAppCommand, summarizeField, summarizeFields, summarizeGoal, summarizeGroups, summarizeNumbers, summarizeRatio, summarizeWeighted, useEvalMode, useEvalShadow, useHostBridge, useRegisterAppTools, valueOf, writerUnavailable };