import type { ChildStdin, InteractionChannel } from "@claudexor/core"; import type { HarnessEvent, HarnessRunSpec, InteractionAnswerSet, InteractionRequest } from "@claudexor/schema"; type Json = any; /** * Claude Code bidirectional stream-json control protocol (the same channel the * Agent SDK's `canUseTool` rides on): * * CLI -> client : {"type":"control_request","request_id":X, * "request":{"subtype":"can_use_tool","tool_name":T,"input":I,...}} * client -> CLI : {"type":"control_response","response":{"subtype":"success", * "request_id":X,"response":{"behavior":"allow"|"deny",...}}} * * For AskUserQuestion the answers ride in `updatedInput.answers` as a record of * question text -> selected label(s) (docs: "Handle approvals and user input"). * Frame shapes are LIVE-VERIFIED against Claude Code 2.1.165: the full * bidirectional exchange (initialize -> can_use_tool -> allow -> ok * tool_result -> result) is recorded in fixtures/protocol/control-handshake.jsonl. * The control channel only activates with `--permission-prompt-tool stdio`; * without it the headless CLI auto-denies interactive tools itself. */ /** * Request id of the ONE initialize handshake this adapter sends. Interactive * runs write it as the first stdin frame; the prompt-free model probe sends the * same frame alone and selects the CLI's answer by this id (hook frames may * precede it), so both must share one literal. */ export declare const CLAUDE_INIT_REQUEST_ID = "req_claudexor_init"; export declare function isControlRequestFrame(obj: Json): boolean; export declare function isResultFrame(obj: Json): boolean; /** A Claude stream-json image content block (base64 source). Claude carries * images ONLY on the stdin stream-json transport — a one-shot `-p` argv run * cannot, so a turn with attachments must use the interactive path. */ export interface ClaudeImageBlock { type: "image"; source: { type: "base64"; media_type: string; data: string; }; } export interface ClaudeTextBlock { type: "text"; text: string; } export type ClaudeAttachmentBlock = ClaudeImageBlock | ClaudeTextBlock; /** Bind finalized bytes once, then build Claude stream-json content blocks. */ export declare function claudeAttachmentBlocks(attachments: HarnessRunSpec["attachments"] | undefined): ClaudeAttachmentBlock[]; /** Initial user message frame for `--input-format stream-json` sessions. */ export declare function initialUserMessageFrame(prompt: string, attachments?: ClaudeAttachmentBlock[]): string; /** * Initial stdin block for an interactive session: the initialize handshake * (announces a live control-protocol client) followed by the user message. * Live-verified against Claude Code 2.1.165: both frames may be written in * one block without waiting for the initialize response * (fixtures/protocol/control-handshake.jsonl). */ export declare function initialSessionFrames(prompt: string, attachments?: ClaudeAttachmentBlock[]): string; /** Map the native AskUserQuestion input into the typed InteractionRequest. */ export declare function interactionRequestFromNative(requestId: string, input: Json): InteractionRequest; /** * Build the allow control_response carrying the user's answers. * Per the documented contract, `answers` maps the QUESTION TEXT to the * selected label, multi-select labels joined with ", ", free text passed * through verbatim. */ export declare function allowResponseFrame(requestId: string, nativeInput: Json, request: InteractionRequest, answers: InteractionAnswerSet): string; /** Deny control_response: benign decline; the model continues with assumptions. */ export declare function denyResponseFrame(requestId: string, message: string): string; /** Error control_response for request subtypes this adapter does not handle. */ export declare function errorResponseFrame(requestId: string, error: string): string; export declare const DECLINE_MESSAGE = "No user answer is available (declined or timed out). Continue with your best assumptions and state them explicitly."; /** * Handle one control_request frame. AskUserQuestion is routed through the * orchestrator's InteractionChannel (pausing only this tool); every other * permission request is DENIED — flag-based permission modes already encode * the run's policy, and headless print-mode behavior (no interactive approver) * must not be silently liberalized by the control channel. */ export declare function handleControlRequestFrame(obj: Json, io: ChildStdin, sessionId: string, channel: InteractionChannel | undefined): AsyncGenerator; export {}; //# sourceMappingURL=interactive.d.ts.map