/** * Wire protocols and worker-side implementations of the per-root runtime * objects a subagent run receives by reference: the tree's {@link CostGate}, * {@link EventBus}es, {@link ArtifactManager}, and main's {@link AgentStorage}. * The main-side halves live in `./runtime`. */ import type { AssistantMessageEventStream, ServiceTier, StoredAuthCredential } from "@oh-my-pi/pi-ai"; import { type ArtifactManagerApi } from "../../session/artifacts.js"; import type { AgentStorageApi, ModelPerfSample, ModelPerfStats } from "../../session/agent-storage.js"; import { type CostCapRefusal, type CostGateApi } from "../../session/cost-gate.js"; import { EventBus } from "../../utils/event-bus.js"; import type { RemoteObject, RpcMethod } from "../rpc.js"; import { type WireCallback, type WireUnsubscribe } from "./support.js"; /** Remote-object kind of a session tree's cost gate. */ export declare const COST_GATE_KIND = "cost-gate"; /** Remote-object kind of an event bus. */ export declare const EVENT_BUS_KIND = "event-bus"; /** Remote-object kind of a session tree's artifact manager. */ export declare const ARTIFACT_MANAGER_KIND = "artifact-manager"; /** Remote-object kind of an open agent.db handle. */ export declare const AGENT_STORAGE_KIND = "agent-storage"; /** Protocol of kind {@link COST_GATE_KIND}. */ export type CostGateProtocol = { spent: RpcMethod<[], number>; check: RpcMethod<[], CostCapRefusal | undefined>; record: RpcMethod<[cost: number], void>; /** * Subscribe `listener` to `session.maxCost` changes, each carrying whether a cap is set * afterwards; returns whether one is set now. Main drops the subscription once the listener * returns `false` (its worker gate was collected) or the worker exits. */ watchCap: RpcMethod<[listener: (capped: boolean) => boolean | Promise], boolean>; }; /** Protocol of kind {@link EVENT_BUS_KIND}. */ export type EventBusProtocol = { emit: RpcMethod<[channel: string, data: unknown], void>; on: RpcMethod<[channel: string, handler: WireCallback<[data: unknown]>], WireUnsubscribe>; /** Subscribe to listener-presence changes of `channel`; returns whether it has listeners now. */ watch: RpcMethod<[channel: string, onChange: WireCallback<[present: boolean]>], boolean>; }; /** Protocol of kind {@link ARTIFACT_MANAGER_KIND}. */ export type ArtifactManagerProtocol = { dir: RpcMethod<[], string>; allocateId: RpcMethod<[], number>; allocatePath: RpcMethod<[toolType: string], { id: string; path: string; }>; exists: RpcMethod<[id: string], boolean>; listFiles: RpcMethod<[], string[]>; getPath: RpcMethod<[id: string], string | null>; }; /** Protocol of kind {@link AGENT_STORAGE_KIND}. */ export type AgentStorageProtocol = { getCache: RpcMethod<[key: string], string | null>; setCache: RpcMethod<[key: string, value: string, expiresAtSec: number], void>; listAuthCredentials: RpcMethod<[provider: string | undefined, includeDisabled: boolean], StoredAuthCredential[]>; recordModelUsage: RpcMethod<[modelKey: string], void>; getModelUsageOrder: RpcMethod<[], string[]>; recordModelPerf: RpcMethod<[ modelKey: string, sample: ModelPerfSample, serviceTier: ServiceTier | null | undefined ], void>; getModelPerf: RpcMethod<[], Map>; claimNotice: RpcMethod<[key: string, expiresAtMs: number], boolean>; }; /** * Worker-side {@link CostGateApi}: the spend total and cap live on main's gate. Whether a cap * is set is mirrored here by one watch on main, made on first use, so an uncapped tree (the * default) checks every request without a blocking call; a capped one asks main each time. */ export declare class RemoteCostGate implements CostGateApi { #private; constructor(remote: RemoteObject); get spent(): number; get capped(): boolean; /** Listeners run after {@link capped} has adopted the change. */ onCapChange(onChange: () => void): () => void; check(): CostCapRefusal | undefined; admit(): void; /** Ordered ahead of any later {@link check} on the same link, so the next request sees the cost. */ record(cost: number): void; meter(stream: AssistantMessageEventStream): AssistantMessageEventStream; } /** * Worker-side view of a main-thread {@link EventBus}. It subclasses `EventBus` so every holder * typed `EventBus` (extension APIs, executor options, RPC mode) takes it unchanged. * * - `emit` forwards to main's bus as a notification, and drops frames for channels main has no * listener on (task subagents stream every delta on `task:subagent:event`). Presence is learned * with one sync call per channel and kept current by main's pushes; a listener added on main * while a push is in flight misses the frames emitted meanwhile. * - `on` subscribes on main, so a frame reaches every listener exactly once wherever it was * emitted; `clear` drops only this proxy's subscriptions. * - Two proxies of the same main bus are one object, so `emitSubagentFrame`'s identity check still * prevents double delivery. */ export declare class RemoteEventBus extends EventBus { #private; constructor(remote: RemoteObject); emit: (channel: string, data: unknown) => void; on: (channel: string, handler: (data: unknown) => void) => (() => void); hasListeners: (channel: string) => boolean; watchListeners: (channel: string, onChange: (present: boolean) => void) => (() => void); clear: () => void; } /** Worker-side {@link ArtifactManagerApi}: ids and paths come from main; content is written here. */ export declare class RemoteArtifactManager implements ArtifactManagerApi { #private; constructor(remote: RemoteObject); get dir(): string; allocateId(): number; allocatePath(toolType: string): Promise<{ id: string; path: string; }>; save(content: string, toolType: string): Promise; exists(id: string): Promise; listFiles(): Promise; getPath(id: string): Promise; } /** Worker-side {@link AgentStorageApi}: every call runs on main's open agent.db. */ export declare class RemoteAgentStorage implements AgentStorageApi { #private; constructor(remote: RemoteObject); getCache(key: string): string | null; setCache(key: string, value: string, expiresAtSec: number): void; listAuthCredentials(provider?: string, includeDisabled?: boolean): StoredAuthCredential[]; recordModelUsage(modelKey: string): void; getModelUsageOrder(): string[]; recordModelPerf(modelKey: string, sample: ModelPerfSample, serviceTier?: ServiceTier | null): Promise; getModelPerf(): Map; claimNotice(key: string, expiresAtMs: number): boolean; }