import type { Message, UserMessage } from '../../types/message/index.js'; /** User-role runtime reports are context, not new operator intent. */ export declare function isOperatorUserMessage(message: Message): message is UserMessage; /** * Guidance a host hands to a turn that is already running. * * The gap this closes is narrow and was documented rather than fixed: * `AgentManager` has had `queueMessage` / `drainMessages` for a while, and * nothing in the iteration loop ever read them — the type says so in as many * words. So a host watching a turn go the wrong way had two options, and both * are worse than they sound. Cancel and start over throws away every tool * result the turn had already paid for. Reject through the review gate only * works if a tool call happens to be pending approval, and it says "no" when * the host wanted to say "yes, but look at this first". * * **Why the text rides on a tool result rather than arriving as a user * message.** A `tool_use` block must be answered by a `tool_result` with the * same id — providers reject a user turn wedged between them — so there is no * legal place to insert a message mid-batch at all. The slot that already * exists is the tool result itself, and this codebase had already worked that * out for a neighbouring case: a denied call carries its reason INSIDE the * `tool_result`, and `executor.ts` notes that this is also what makes a * rejection *steer*, because the model reads it in the slot it already * attends to for tool outcomes. Steering is the same delivery with the * refusal removed. * * **What it deliberately is not.** It does not interrupt. The batch in flight * finishes, and the guidance lands where the model looks next. A host that * wants the current work stopped wants `AbortSignal`, which is a different * question with a different answer — and conflating the two is how "please * also check the tests" ends up killing a half-written file. */ export interface SteeringChannel { /** * Queue guidance for the running turn. * * Repeated calls before the next drain accumulate in order rather than * replacing each other: two corrections typed a second apart are two * things the model should see, and keeping only the last one silently * discards a host's instruction. * * Empty and whitespace-only text is ignored, so a stray keystroke does * not append a blank line to a tool result. */ steer(text: string): void; /** Take everything queued, leaving the channel empty. */ drain(): string | undefined; /** True while guidance is queued and undelivered. */ readonly pending: boolean; } export declare class SteeringBinding implements SteeringChannel { private queued; steer(text: string): void; drain(): string | undefined; get pending(): boolean; } /** * The frame the guidance arrives in. * * Labelled because the model is being handed text from a party other than the * tool whose result it is reading, in that tool's slot. Unlabelled, it reads * as something the tool said — so a steer saying "stop and ask me first" would * look like output from `bash`. * * This is NOT the untrusted-content envelope. The host operating the turn is * the one party whose words the agent SHOULD act on; framing them as material * to be worked with rather than followed would inverting the very thing the * host is trying to do. Different party, different frame, on purpose. */ /** The same slot as steering, for notices the kernel itself has to deliver. */ export declare function attachNotice(messages: readonly Message[], channel: SteeringChannel | undefined, format: (text: string) => string, /** * Told only when the text actually landed on a result the model will read. * * Not on the two paths above it: a batch with no tool result leaves the * notice queued, and a result whose content is not a string puts it back. * Draining is therefore not delivery, which matters to the caller that * keeps its own record of what the text accounts for — `AwaitedJobs` * drops an exit's entry here, and a premature drop would strand the exit. */ onDelivered?: () => void): readonly Message[]; /** What the model reads when a background job it started has ended. */ export declare function formatJobNote(text: string): string; export declare function formatSteeringNote(text: string): string; /** * The operator guidance the last steering note in a tool result carries, or * `undefined` when the result carries none. The inverse of * {@link formatSteeringNote} applied by {@link attachSteering}. */ export declare function readSteeringNote(content: string): string | undefined; /** * Append the guidance to the last tool result in a settled batch. * * The LAST one, so it is the final thing the model reads before deciding what * to do next — appending to the first would bury it under every later result. * * Returns the messages unchanged when there is nothing queued, and when the * batch carries no tool result to attach to. The second case is not a failure * to handle: a turn that called no tools has nothing in flight, so guidance * belongs to the next turn and stays queued for it. */ export declare function attachSteering(messages: readonly Message[], channel: SteeringChannel | undefined, /** Receives accepted operator text, never inferred from a tool's output. */ onDelivered?: (text: string) => void): readonly Message[]; //# sourceMappingURL=steering.d.ts.map