/** * @license * Copyright 2026 Steven Roussey * SPDX-License-Identifier: Apache-2.0 */ import type { AgentApprovalMode, ToolDefinition } from "@workglow/ai"; import { ServiceRegistry } from "@workglow/util"; import type { DataPortSchema } from "@workglow/util/schema"; /** * The session's two ends, injectable so the loop can be driven without a * terminal. Defaults are readline and stdout. */ export interface AgentChatIo { /** One line from the person, or `undefined` at end of input. */ readonly ask: (prompt: string) => Promise; readonly write: (text: string) => void; } export interface AgentChatOptions { readonly model: string; readonly tools: readonly ToolDefinition[]; readonly systemPrompt: string | undefined; readonly maxRounds: number | undefined; readonly approval: AgentApprovalMode; } /** * The schema of the one thing this loop asks a person for. * * `format` is the marker a renderer keys on: the console draws a chat composer * for it rather than the one-line text field every other string port gets, and * folds the answer into the transcript instead of showing it as a form it once * filled in. */ export declare const CHAT_MESSAGE_SCHEMA: DataPortSchema; /** * A child of the host's registry carrying the connector this session prompts * through — but ONLY when the session owns a terminal. * * A run reporting to a parent process already has a connector wired to that * channel, installed with the channel itself. Overriding it here would point a * console session's approvals at an Ink prompt nobody can see, on a process * whose stdout is a pipe. * * `--no-approval` is granted here rather than left to the turn's input: the * turn reads the grant off the registry, which is this process stating it, and * not off a tool list a saved graph could have written. */ export declare function chatRegistry(parent: ServiceRegistry, reported: boolean, approval?: AgentApprovalMode): ServiceRegistry; /** * The next message, asked through whoever is listening. * * A reported run has no terminal to read a line from — its stdin is not a * person — so the question goes up the same channel every other question does * and the answer comes back down it. Declining or dismissing ends the session, * which is what closing the composer means. */ export declare function askThroughConnector(registry: ServiceRegistry, signal: AbortSignal): () => Promise; /** * The chat loop: read a line, run one {@link AgentTask} turn, carry the * conversation forward. * * `messages` is this loop's only state — the task takes the history in and * hands it back with the turn appended, so nothing here has to know what a * tool result or a tool-call id looks like. */ export declare function runAgentChat(options: AgentChatOptions, io?: AgentChatIo): Promise;