import type { ToolChoice } from "@oh-my-pi/pi-ai"; export interface ResolveInfo { /** The ToolChoice that was served to the LLM. */ choice: ToolChoice; } export interface RejectInfo { /** The ToolChoice that was yielded but never (or unsuccessfully) served. */ choice: ToolChoice; reason: "aborted" | "error" | "cleared" | "removed"; } /** "requeue" replays the lost yield next turn; "drop" (or void/undefined) discards it. */ export type RejectOutcome = "requeue" | "drop"; export interface DirectiveCallbacks { /** Fires when the yield was served (LLM call completed). The directive is consumed. */ onResolved?: (info: ResolveInfo) => void; /** * Fires when the yield is being discarded. Return "requeue" to replay the * same value at the head of the queue for the next turn. Default: "drop". */ onRejected?: (info: RejectInfo) => RejectOutcome | undefined; /** * Handler invoked when the model actually calls the forced tool. The queue * directive carries the real execution logic; the tool's own execute() is * bypassed. Returns the tool result directly. */ onInvoked?: (input: unknown) => Promise | unknown; } export interface ToolChoiceDirective { generator: Iterator; /** Stable label for targeted removal and debugging (e.g. "user-force"). */ label: string; callbacks: DirectiveCallbacks; } export interface PushOptions { /** Prepend to head instead of appending to tail. Default: false. */ now?: boolean; label?: string; /** Lifecycle callbacks for this directive. */ onResolved?: DirectiveCallbacks["onResolved"]; onRejected?: DirectiveCallbacks["onRejected"]; onInvoked?: DirectiveCallbacks["onInvoked"]; } export declare function onceGen(choice: ToolChoice): Generator; export declare class ToolChoiceQueue { #private; pushOnce(choice: ToolChoice, options?: PushOptions): void; pushSequence(choices: ToolChoice[], options?: PushOptions): void; push(generator: Iterable, options?: PushOptions): void; /** * Advance the head directive and return its next yield. Records the value * as in-flight until resolve() or reject() is called. */ nextToolChoice(): ToolChoice | undefined; /** * The in-flight yield was served — the LLM call completed normally. * Fires onResolved, then clears in-flight state. The directive's generator * remains in the queue if it has more values to yield. */ resolve(): void; /** * The in-flight yield was not served, or the turn aborted/errored. * Fires onRejected to let the caller decide: "requeue" replays the exact * lost value at the head of the queue; anything else drops it. */ reject(reason: RejectInfo["reason"]): void; /** True if there is an in-flight yield that hasn't been resolved or rejected. */ get hasInFlight(): boolean; /** Peek the in-flight directive's onInvoked handler, if any. */ peekInFlightInvoker(): ((input: unknown) => Promise | unknown) | undefined; /** Remove all directives with the given label. Rejects in-flight if it matches. */ removeByLabel(label: string): void; /** Empty the queue and reject any in-flight yield. */ clear(): void; /** Return the label of the most recently resolved directive, then clear it. */ consumeLastServedLabel(): string | undefined; /** For tests/debug: labels of currently queued directives in order. */ inspect(): readonly string[]; }