/** * Session connection layer for the Ink TUI. * * Drives the headless conversation session and translates its results into * outcomes the React tree renders. Nothing in this module writes to the * terminal — the provider runs in `silent` output mode and reports progress * through the per-submission stream sink. */ import { SlashCommand } from '../../shared/constants.js'; import { type CommandAvailability } from '../interactive/slashCommandRegistry.js'; import { type ConversationPlan } from '../interactive/conversationPlan.js'; import type { InteractiveModeResult } from '../interactive/interactive.js'; import type { WorkflowContext } from '../interactive/interactive-summary-types.js'; import type { ConversationMessage } from '../interactive/interactiveApplication.js'; import { type ImageAttachmentStore } from '../interactive/imageAttachments.js'; import type { PastedImage } from '../interactive/inlineImagePaste.js'; /** * Which command path a task came from. Every mode carries it — the conversation * needs it to pick the right selector and to decide what a rejected draft means * — but only the modes that rewrite `order.md` publish it on the result. */ export type InteractiveResultSource = NonNullable; export interface TuiConversationOptions { cwd: string; /** Mode-specific system prompt, tools and permission mode. */ plan: ConversationPlan; /** Left out by a mode that has no workflow to describe to the summary prompt. */ workflowContext?: WorkflowContext; /** Images pasted during this run; referenced from prompts by placeholder. */ attachmentStore: ImageAttachmentStore; /** Task text supplied on the command line; seeds the conversation history. */ userMessage?: string; /** Previous session transcript included once as reference on the first provider call. */ handoffHistory?: readonly ConversationMessage[]; /** Keep temporary provider/model sessions out of persisted `/continue` metadata. */ persistSession?: boolean; sourceContext?: string; /** Enable settings handoffs owned by the resident interactive TUI. */ enableSettingsCommands?: boolean; } type SettingsSlashCommand = typeof SlashCommand.Workflow | typeof SlashCommand.Mode | typeof SlashCommand.Provider | typeof SlashCommand.Model | typeof SlashCommand.Effort; export type TuiHandoffId = 'workflow' | 'mode' | 'provider' | 'model' | 'effort' | 'tell' | 'open' | 'exec-setup' | 'exec-go'; export declare const TUI_HANDOFF_IDS: Readonly>; export interface TuiSubmitInput { text: string; abortSignal: AbortSignal; onAssistantChunk: (chunk: string) => void; } /** * `commit` applies whatever the turn leaves behind outside the view — the * transcript the caller summarizes from, the session to resume. The view calls * it only for a turn that is still the current one and was not interrupted, so * an adapter must do nothing on its own until then. */ export type TuiSubmission = { kind: 'assistant_response'; content: string; notices?: readonly string[]; commit?: () => void; } | { kind: 'task_instruction'; task: string; /** The command path that produced it. */ origin?: InteractiveResultSource; notices?: readonly string[]; commit?: () => void; } | { kind: 'error'; message: string; notices?: readonly string[]; commit?: () => void; }; /** Commands the TUI settles itself, without contacting the provider. */ export type TuiLocalCommand = { kind: 'cancel'; } | { kind: 'execute'; task: string; origin?: InteractiveResultSource; } | { kind: 'choose_action'; task: string; origin?: InteractiveResultSource; } | { kind: 'resume_session'; } /** * Something the caller has to run with the terminal to itself — a settings * menu, a workflow — after which the conversation picks up again. The id is * the caller's own name for it. */ | { kind: 'handoff'; id: TuiHandoffId; /** What was typed alongside the command, for the run that carries it out. */ text?: string; } | { kind: 'paste_image'; } | { kind: 'notice'; message: string; }; export interface TuiConversation { /** * True when the line means an operation on the conversation rather than * something to say. A queue may merge what the user typed into one message, * and a command must never be merged into one — but a line that merely starts * with a slash (`/usr/bin/env is missing`) is text like any other. */ isCommandLine(text: string): boolean; readonly lang: 'en' | 'ja'; /** Which commands this run can offer, and which it refuses outright. */ readonly commandAvailability: CommandAvailability; /** True when the mode records on its result which command path produced it. */ readonly tracksResultSource: boolean; /** * Commands the TUI resolves on its own. Callers consult this before `submit` * so a local command never raises the thinking indicator. */ resolveLocalCommand(text: string): TuiLocalCommand | null; submit(input: TuiSubmitInput): Promise; /** Summarize straight into a task instruction, skipping the chat turn. */ createInstruction(input: TuiSubmitInput): Promise; /** Continue from a session picked with /resume, or return a notice to show. */ resumeSession(sessionId: string): Promise; /** * Put a `/go` draft the user rejected back into the conversation, so the next * revision starts from what was proposed. Left out by a front-end whose * session keeps no transcript of its own (exec). */ recordRejectedDraft?(task: string): void; /** Snapshot all user/assistant context needed by a recreated provider session. */ snapshotHistory?(): readonly ConversationMessage[]; /** Latest run confirmed by a successful task-state lookup in this conversation. */ getReferenceRunSlug?(): string | undefined; /** Apply an effort override to future calls on the active session. */ setEffort?(effort: string): void; /** Capture the clipboard image and return the placeholder to insert. */ pasteClipboardImage(abortSignal: AbortSignal): Promise; /** Refuse further images once the run ended, so a late save leaves no temp file. */ sealImages(): void; /** Store an image the terminal pasted inline and return its placeholder. */ saveInlineImage(image: PastedImage): Promise; } export declare function createTuiConversation(options: TuiConversationOptions): TuiConversation; export {}; //# sourceMappingURL=tuiConversation.d.ts.map