import type { StreamFn } from "@oh-my-pi/pi-agent-core"; import type { AssistantMessageEventStream } from "@oh-my-pi/pi-ai"; import type { Settings } from "../config/settings.js"; /** `notice` source of cost-gate warnings and refusals. */ export declare const COST_GATE_NOTICE_SOURCE = "cost-gate"; /** A model request the cost gate refused to send. */ export interface CostCapRefusal { /** Session-tree spend in USD when the request was refused. */ readonly spent: number; /** The `session.maxCost` cap in USD. */ readonly cap: number; readonly message: string; } /** Rejects a model request the cost gate refused (the caller sends nothing). */ export declare class CostCapError extends Error { readonly refusal: CostCapRefusal; constructor(refusal: CostCapRefusal); } /** * The spend surface a session tree shares. {@link CostGate} implements it for the * root; a subagent worker holds a remote implementation that charges the root's * gate (`thread/services/runtime-remote.ts`). */ export interface CostGateApi { /** Session-tree spend in USD. */ readonly spent: number; /** Whether `session.maxCost` is set, so requests can be refused at all. */ readonly capped: boolean; /** Calls `onChange` after `session.maxCost` changes; returns the unsubscribe. */ onCapChange(onChange: () => void): () => void; /** The refusal for the next model request, or `undefined` to send it. */ check(): CostCapRefusal | undefined; /** Throws {@link CostCapError} when the next model request must not be sent. */ admit(): void; /** Adds a finished response's cost. */ record(cost: number): void; /** Records the response's cost once the provider finishes producing it. */ meter(stream: AssistantMessageEventStream): AssistantMessageEventStream; } /** * Running spend of one session tree: the root session, its subagents, and * their side requests share one gate. The total starts from the root's * recorded spend (so a resumed session keeps its history) and adds every * response's cost as it finishes. Thresholds are read from the root's * settings on each check, so setting or changing `session.warnCost` / * `session.maxCost` applies to the next request. */ export declare class CostGate implements CostGateApi { #private; constructor(settings: Settings, recordedSpend: number, warn: (message: string) => void); get spent(): number; /** Whether `session.maxCost` is set, so requests can be refused at all. */ get capped(): boolean; /** Calls `onChange` after `session.maxCost` changes in the gate's settings; returns the unsubscribe. */ onCapChange(onChange: () => void): () => void; /** The refusal for the next model request, or `undefined` to send it. */ check(): CostCapRefusal | undefined; /** Throws {@link CostCapError} when the next model request must not be sent. */ admit(): void; /** Adds a finished response's cost; warns once when the total first reaches `session.warnCost`. */ record(cost: number): void; /** Records the response's cost once the provider finishes producing it. */ meter(stream: AssistantMessageEventStream): AssistantMessageEventStream; } /** * Wraps a stream function so each request passes the gate current when it is * sent, and adds its cost to that gate. Wrap the function that sends one * provider attempt (inside concurrency slots and retry loops), so a request * that waited for a slot or retries is checked when it actually goes out. */ export declare function guardStreamFn(streamFn: StreamFn, currentGate: () => CostGateApi | undefined): StreamFn;