/** * Custom message types and transformers for the coding agent. * * Extends the base AgentMessage type with coding-agent specific message types, * and provides a transformer to convert them to LLM-compatible messages. */ import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import { type BranchSummaryMessage, type CompactionSummaryMessage } from "@oh-my-pi/pi-agent-core/compaction/messages"; import type { AssistantMessage, ImageContent, Message, MessageAttribution, TextContent } from "@oh-my-pi/pi-ai"; export { type BranchSummaryMessage, type CompactionSummaryMessage, createBranchSummaryMessage, createCompactionSummaryMessage, } from "@oh-my-pi/pi-agent-core/compaction/messages"; import type { OutputMeta } from "../tools/output-meta"; export declare const SKILL_PROMPT_MESSAGE_TYPE = "skill-prompt"; export interface SkillPromptDetails { name: string; path: string; args?: string; lineCount: number; /** Internal: tag used by AgentSession to remove the pending-display chip * from `#steeringMessages` / `#followUpMessages` when the agent consumes * this message. Not surfaced to renderers; the `__` prefix signals * "private". Optional — non-streaming skill prompts never set it. Stripped * from persisted `details` by `SessionManager.appendCustomMessageEntry` * via the `INTERNAL_DETAILS_FIELDS` allowlist below. */ __pendingDisplayTag?: string; } /** Sentinel value for `AssistantMessage.errorMessage` indicating that the abort * was an *expected internal transition* (plan-mode → execution compaction) * and must NOT surface as a red "Operation aborted" line. Distinct from * `undefined` (default) so user-cancel aborts with no errorMessage still * render normally. Persists through SessionManager so history replay * branches identically. * * Consumers: `AgentSession.#handleAgentEvent` (stamper) writes this value; * `EventController.#handleMessageEnd`, `AssistantMessageComponent`, * `ui-helpers.addMessageToChat` (renderers), `SessionObserverOverlay * #buildTranscriptLines`, `runPrintMode`, and `AcpAgent#replayAssistantMessage` * (fallback error emission) read it via `isSilentAbort`. */ export declare const SILENT_ABORT_MARKER = "__omp.silent_abort__"; /** Type-guard for `SILENT_ABORT_MARKER`. Renderers MUST branch on this rather * than string-comparing inline so refactors to the marker constant (e.g., * namespacing changes) propagate through every consumer in lockstep. */ export declare function isSilentAbort(errorMessage: string | undefined): boolean; /** Extract the optional `__pendingDisplayTag` field from a CustomMessage's * `details` blob. Safe over `unknown`; returns undefined when the field is * absent or non-string. */ export declare function readPendingDisplayTag(details: unknown): string | undefined; /** Explicit allowlist of `details` field names that are AgentSession-internal * transient bookkeeping and MUST be removed before SessionManager persists * the CustomMessageEntry to disk. Scoped intentionally narrow: only fields * declared here are stripped. Adding a new entry is a deliberate, reviewed * change — unrelated future payload fields are never silently dropped. */ export declare const INTERNAL_DETAILS_FIELDS: readonly ["__pendingDisplayTag"]; /** Return a `details` copy with every key in `INTERNAL_DETAILS_FIELDS` * removed. Returns the input unchanged when there is nothing to strip * (null/non-object, or no listed fields present) so callers don't pay a * clone cost on the common path. */ export declare function stripInternalDetailsFields(details: T | undefined): T | undefined; /** * Message type for bash executions via the ! command. */ export interface BashExecutionMessage { role: "bashExecution"; command: string; output: string; exitCode: number | undefined; cancelled: boolean; truncated: boolean; meta?: OutputMeta; timestamp: number; /** If true, this message is excluded from LLM context (!! prefix) */ excludeFromContext?: boolean; } /** * Message type for user-initiated Python executions via the $ command. * Shares the same kernel session as eval's Python backend. */ export interface PythonExecutionMessage { role: "pythonExecution"; code: string; output: string; exitCode: number | undefined; cancelled: boolean; truncated: boolean; meta?: OutputMeta; timestamp: number; /** If true, this message is excluded from LLM context ($$ prefix) */ excludeFromContext?: boolean; } /** * Message type for extension-injected messages via sendMessage(). */ export interface CustomMessage { role: "custom"; customType: string; content: string | (TextContent | ImageContent)[]; display: boolean; details?: T; /** Who initiated this message for billing/attribution semantics. */ attribution?: MessageAttribution; timestamp: number; } /** * Legacy hook message type (pre-extensions). Kept for session migration. */ export interface HookMessage { role: "hookMessage"; customType: string; content: string | (TextContent | ImageContent)[]; display: boolean; details?: T; /** Who initiated this message for billing/attribution semantics. */ attribution?: MessageAttribution; timestamp: number; } /** * Message type for auto-read file mentions via @filepath syntax. */ export interface FileMentionMessage { role: "fileMention"; files: Array<{ path: string; content: string; lineCount?: number; /** File size in bytes, if known. */ byteSize?: number; /** Why the file contents were omitted from auto-read. */ skippedReason?: "tooLarge"; image?: ImageContent; }>; timestamp: number; } declare module "@oh-my-pi/pi-agent-core" { interface CustomAgentMessages { bashExecution: BashExecutionMessage; pythonExecution: PythonExecutionMessage; custom: CustomMessage; hookMessage: HookMessage; branchSummary: BranchSummaryMessage; compactionSummary: CompactionSummaryMessage; fileMention: FileMentionMessage; } } /** * Convert a BashExecutionMessage to user message text for LLM context. */ export declare function bashExecutionToText(msg: BashExecutionMessage): string; /** * Convert a PythonExecutionMessage to user message text for LLM context. */ export declare function pythonExecutionToText(msg: PythonExecutionMessage): string; export declare function sanitizeRehydratedOpenAIResponsesAssistantMessage(message: AssistantMessage): AssistantMessage; /** Convert CustomMessageEntry to AgentMessage format */ export declare function createCustomMessage(customType: string, content: string | (TextContent | ImageContent)[], display: boolean, details: unknown | undefined, timestamp: string, attribution?: MessageAttribution): CustomMessage; /** * Transform AgentMessages (including custom types) to LLM-compatible Messages. * * This is used by: * - Agent's transormToLlm option (for prompt calls and queued messages) * - Compaction's generateSummary (for summarization) * - Custom extensions and tools */ export declare function convertToLlm(messages: AgentMessage[]): Message[];