/** * Chat Types Module * * Type definitions for the chat-based dashboard. Provides a conversational * interface with the Orchestrator, transforming raw terminal output into * clean, formatted chat messages. * * @module types/chat */ /** * Valid channel types for chat conversations */ export declare const CHAT_CHANNEL_TYPES: readonly ["crewly_chat", "slack", "telegram", "api"]; /** * Channel type for a chat conversation */ export type ChatChannelType = (typeof CHAT_CHANNEL_TYPES)[number]; /** * Infer the channel type from a conversation ID. * * Conversation IDs follow naming conventions: * - `slack-{channel}-{threadTs}` → 'slack' * - UUIDs or other formats → 'crewly_chat' * * @param conversationId - The conversation ID to analyze * @returns The inferred ChatChannelType * * @example * ```typescript * inferChannelTypeFromConversationId('slack-D0AC7NF5N7L-1772987441-763389'); // 'slack' * inferChannelTypeFromConversationId('a1b2c3d4-e5f6-7890-abcd-ef1234567890'); // 'crewly_chat' * ``` */ export declare function inferChannelTypeFromConversationId(conversationId: string): ChatChannelType; /** * Check if a value is a valid ChatChannelType * * @param value - Value to check * @returns True if value is a valid ChatChannelType */ export declare function isValidChannelType(value: string): value is ChatChannelType; /** * Valid sender types for chat messages */ export declare const CHAT_SENDER_TYPES: readonly ["user", "orchestrator", "agent", "system"]; /** * Valid content types for chat messages */ export declare const CHAT_CONTENT_TYPES: readonly ["text", "status", "task", "error", "system", "code", "markdown"]; /** * Valid message status values */ export declare const CHAT_MESSAGE_STATUSES: readonly ["sending", "sent", "delivered", "error"]; /** * Chat-related constants */ export declare const CHAT_CONSTANTS: { /** Default limits */ readonly DEFAULTS: { /** Default message limit for pagination */ readonly MESSAGE_LIMIT: 100; /** Default conversation limit for pagination */ readonly CONVERSATION_LIMIT: 50; /** Maximum content length for last message preview */ readonly PREVIEW_LENGTH: 100; }; /** Response extraction patterns */ readonly PATTERNS: { /** Pattern names */ readonly EXPLICIT: "explicit"; readonly CHAT: "chat"; readonly CODEBLOCK: "codeblock"; }; }; /** * Sender type for chat messages */ export type ChatSenderType = (typeof CHAT_SENDER_TYPES)[number]; /** * Message content type */ export type ChatContentType = (typeof CHAT_CONTENT_TYPES)[number]; /** * Message delivery status */ export type ChatMessageStatus = (typeof CHAT_MESSAGE_STATUSES)[number]; /** * Sender information for a chat message */ export interface ChatSender { /** Type of sender */ type: ChatSenderType; /** ID of the agent/session if applicable */ id?: string; /** Display name */ name?: string; /** Role name if sender is an agent */ role?: string; } /** * Valid Slack delivery statuses for NOTIFY reconciliation */ export declare const SLACK_DELIVERY_STATUSES: readonly ["pending", "delivered", "failed"]; /** * Slack delivery status type */ export type SlackDeliveryStatus = (typeof SLACK_DELIVERY_STATUSES)[number]; /** * Metadata attached to a chat message */ export interface ChatMessageMetadata { /** ID of skill used to generate this response */ skillUsed?: string; /** ID of task created as a result of this message */ taskCreated?: string; /** ID of project created */ projectCreated?: string; /** Original raw terminal output (for debugging) */ rawOutput?: string; /** Agent session ID that generated this message */ sessionId?: string; /** Time taken to generate response in ms */ responseTimeMs?: number; /** Slack delivery status for NOTIFY reconciliation */ slackDeliveryStatus?: SlackDeliveryStatus; /** ISO timestamp of last Slack delivery attempt */ slackDeliveryAttemptedAt?: string; /** Number of Slack delivery attempts */ slackDeliveryAttempts?: number; /** Error message from last failed Slack delivery attempt */ slackDeliveryError?: string; /** Slack channel ID for delivery/reconciliation */ slackChannelId?: string; /** Slack thread timestamp for threaded replies */ slackThreadTs?: string; /** NOTIFY type (e.g. task_completed, agent_error) */ notifyType?: string; /** NOTIFY title header */ notifyTitle?: string; /** NOTIFY urgency level */ notifyUrgency?: string; /** Additional custom metadata */ [key: string]: unknown; } /** * A single chat message */ export interface ChatMessage { /** Unique message ID */ id: string; /** Conversation this message belongs to */ conversationId: string; /** Sender information */ from: ChatSender; /** Message content (may be markdown formatted) */ content: string; /** Type of content */ contentType: ChatContentType; /** Optional metadata */ metadata?: ChatMessageMetadata; /** Delivery status */ status: ChatMessageStatus; /** ISO timestamp */ timestamp: string; /** Parent message ID for threading (optional) */ parentId?: string; } /** * Last message preview in a conversation */ export interface LastMessagePreview { /** Truncated content preview */ content: string; /** ISO timestamp of the message */ timestamp: string; /** Sender information */ from: ChatSender; } /** * A chat conversation (collection of messages) */ export interface ChatConversation { /** Unique conversation ID */ id: string; /** Conversation title (auto-generated or user-set) */ title?: string; /** IDs of participants (user, orchestrator, agents) */ participantIds: string[]; /** ISO timestamp of creation */ createdAt: string; /** ISO timestamp of last update */ updatedAt: string; /** Whether this conversation is archived */ isArchived: boolean; /** Number of messages in conversation */ messageCount: number; /** Last message preview */ lastMessage?: LastMessagePreview; /** Channel type (slack, crewly_chat, etc.) — inferred from conversationId if not set */ channelType?: ChatChannelType; } /** * Input for sending a new message */ export interface SendMessageInput { /** Message content */ content: string; /** Conversation ID (creates new if not provided) */ conversationId?: string; /** Optional metadata to attach */ metadata?: Record; } /** * Response from sending a message */ export interface SendMessageResult { /** The sent message */ message: ChatMessage; /** The conversation (may be newly created) */ conversation: ChatConversation; } /** * Filter options for listing messages */ export interface ChatMessageFilter { /** Filter by conversation */ conversationId?: string; /** Filter by sender type */ senderType?: ChatSenderType; /** Filter by content type */ contentType?: ChatContentType; /** Filter by channel type (via conversation lookup) */ channelType?: ChatChannelType; /** Messages after this timestamp */ after?: string; /** Messages before this timestamp */ before?: string; /** Maximum number of messages to return */ limit?: number; /** Offset for pagination */ offset?: number; } /** * Filter options for listing conversations */ export interface ConversationFilter { /** Include archived conversations */ includeArchived?: boolean; /** Search in title and messages */ search?: string; /** Filter by channel type */ channelType?: ChatChannelType; /** Limit number of results */ limit?: number; /** Offset for pagination */ offset?: number; } /** * Response extraction pattern configuration */ export interface ResponsePattern { /** Pattern name for identification */ name: string; /** Regex pattern to match */ pattern: RegExp; /** Extraction group index (default 1) */ groupIndex?: number; } /** * Chat message WebSocket event */ export interface ChatMessageEvent { type: 'chat_message'; data: ChatMessage; } /** * Typing indicator WebSocket event */ export interface ChatTypingEvent { type: 'chat_typing'; data: { conversationId: string; sender: ChatSender; isTyping: boolean; }; } /** * Message status update WebSocket event */ export interface ChatStatusEvent { type: 'chat_status'; data: { messageId: string; status: ChatMessageStatus; }; } /** * Conversation update WebSocket event */ export interface ConversationUpdatedEvent { type: 'conversation_updated'; data: ChatConversation; } /** * Union type for all chat WebSocket events */ export type ChatWebSocketEvent = ChatMessageEvent | ChatTypingEvent | ChatStatusEvent | ConversationUpdatedEvent; /** * Input for creating a chat message */ export interface CreateChatMessageInput { /** Conversation ID */ conversationId: string; /** Message content */ content: string; /** Sender information */ from: ChatSender; /** Optional content type (defaults to 'text') */ contentType?: ChatContentType; /** Optional status (defaults to 'sent') */ status?: ChatMessageStatus; /** Optional metadata */ metadata?: ChatMessageMetadata; /** Optional timestamp (defaults to now) */ timestamp?: string; /** Optional parent message ID for threading */ parentId?: string; } /** * Urgency levels for notifications */ export declare const NOTIFY_URGENCY_LEVELS: readonly ["low", "normal", "high", "critical"]; /** * Urgency level type */ export type NotifyUrgency = (typeof NOTIFY_URGENCY_LEVELS)[number]; /** * Unified notification payload from [NOTIFY]...[/NOTIFY] markers. * * The orchestrator outputs header+body content inside [NOTIFY] markers to route * messages to chat, Slack, or both depending on which header fields are present: * - `conversationId` present -> route to chat UI * - `channelId` present -> route to Slack * - Both -> both (common case) * - Neither + activeConversationId exists -> fallback to chat * * Format: * ``` * [NOTIFY] * conversationId: conv-abc123 * channelId: D0AC7NF5N7L * type: task_completed * --- * ## Message body here * [/NOTIFY] * ``` */ export interface NotifyPayload { /** Required -- markdown content for the notification */ message: string; /** Route to chat UI conversation (copied from incoming [CHAT:convId]) */ conversationId?: string; /** Route to Slack channel */ channelId?: string; /** Slack thread timestamp for threaded replies */ threadTs?: string; /** Notification type (e.g. task_completed, agent_error, project_update) */ type?: string; /** Header text for Slack notifications */ title?: string; /** Urgency level for notification routing */ urgency?: NotifyUrgency; } /** * Check if a value is a valid NotifyPayload * * Validates that the payload has a required `message` string field * and that optional fields have correct types when present. * * @param value - Value to check * @returns True if value is a valid NotifyPayload */ export declare function isValidNotifyPayload(value: unknown): value is NotifyPayload; /** * Parse raw content from a [NOTIFY]...[/NOTIFY] block into a NotifyPayload. * * Supports three formats: * 1. **Header+body with `---`** (preferred): key-value headers before a `---` separator, * with the message body after it. Headers are short (~25 chars), so they are * never corrupted by PTY line-wrapping. * 2. **Header+body with blank line** (fallback): same as above but with a blank * line instead of `---`. Activated only when the first line is a known header. * 3. **Legacy JSON** (fallback): if the content starts with `{`, it is parsed as * JSON with PTY artifact cleanup for backward compatibility. * * @param raw - Raw content between [NOTIFY] and [/NOTIFY] markers * @returns Parsed NotifyPayload or null if content is invalid * * @example * ```typescript * // Header+body format * const payload = parseNotifyContent( * 'conversationId: conv-abc\ntype: task_completed\n---\n## Done\nTask finished.' * ); * // => { message: '## Done\nTask finished.', conversationId: 'conv-abc', type: 'task_completed' } * * // Legacy JSON format (auto-detected) * const legacy = parseNotifyContent('{"message":"Hello","conversationId":"conv-1"}'); * // => { message: 'Hello', conversationId: 'conv-1' } * ``` */ export declare function parseNotifyContent(raw: string): NotifyPayload | null; /** * Storage format for chat data */ export interface ChatStorageFormat { /** The conversation */ conversation: ChatConversation; /** Messages in the conversation */ messages: ChatMessage[]; } /** * Check if a value is a valid sender type * * @param value - Value to check * @returns True if value is a valid ChatSenderType */ export declare function isValidSenderType(value: string): value is ChatSenderType; /** * Check if a value is a valid content type * * @param value - Value to check * @returns True if value is a valid ChatContentType */ export declare function isValidContentType(value: string): value is ChatContentType; /** * Check if a value is a valid message status * * @param value - Value to check * @returns True if value is a valid ChatMessageStatus */ export declare function isValidMessageStatus(value: string): value is ChatMessageStatus; /** * Check if an object is a valid ChatSender * * @param value - Value to check * @returns True if value is a valid ChatSender object */ export declare function isValidChatSender(value: unknown): value is ChatSender; /** * Check if an object is a valid ChatMessage * * @param value - Value to check * @returns True if value is a valid ChatMessage object */ export declare function isValidChatMessage(value: unknown): value is ChatMessage; /** * Check if an object is a valid ChatConversation * * @param value - Value to check * @returns True if value is a valid ChatConversation object */ export declare function isValidChatConversation(value: unknown): value is ChatConversation; /** * Generate a unique ID for chat entities * * @returns A unique identifier string */ export declare function generateChatId(): string; /** * Create a chat message with defaults * * @param input - Partial message input with required fields * @returns A complete ChatMessage object * * @example * ```typescript * const message = createChatMessage({ * conversationId: 'conv-1', * content: 'Hello!', * from: { type: 'user' }, * }); * ``` */ export declare function createChatMessage(input: CreateChatMessageInput): ChatMessage; /** * Create a conversation with defaults * * @param title - Optional title for the conversation * @returns A new ChatConversation object * * @example * ```typescript * const conversation = createConversation('Project Discussion'); * ``` */ export declare function createConversation(title?: string, idOverride?: string, channelType?: ChatChannelType): ChatConversation; /** * Format message content by cleaning terminal output * * Removes ANSI escape codes, control characters, carriage returns (which cause * text to overwrite itself in terminals), and trims whitespace. * * @param content - Raw content to format * @returns Cleaned content string * * @example * ```typescript * const clean = formatMessageContent('\x1b[32mGreen text\x1b[0m'); * // Returns: 'Green text' * ``` */ export declare function formatMessageContent(content: string): string; /** * Default response extraction patterns */ export declare const DEFAULT_RESPONSE_PATTERNS: ResponsePattern[]; /** * Extract response from raw output using patterns * * Tries multiple patterns to extract the clean response from * raw terminal output. Returns the original output if no pattern matches. * * @param rawOutput - Raw terminal output * @param customPatterns - Optional custom patterns to use instead of defaults * @returns Extracted response content * * @example * ```typescript * const response = extractResponseFromOutput( * 'some text [RESPONSE]Hello World[/RESPONSE] more text' * ); * // Returns: 'Hello World' * ``` */ export declare function extractResponseFromOutput(rawOutput: string, customPatterns?: ResponsePattern[]): string; /** * Detect the content type of a message based on its content * * @param content - Message content to analyze * @returns Detected content type * * @example * ```typescript * const type = detectContentType('## Heading\n- Item'); * // Returns: 'markdown' * ``` */ export declare function detectContentType(content: string): ChatContentType; /** * Create a last message preview from a chat message * * @param message - The chat message to create preview from * @param maxLength - Maximum content length (default: CHAT_CONSTANTS.DEFAULTS.PREVIEW_LENGTH) * @returns A LastMessagePreview object */ export declare function createLastMessagePreview(message: ChatMessage, maxLength?: number): LastMessagePreview; /** * Validate SendMessageInput * * @param input - Input to validate * @returns Object with valid flag and optional error message */ export declare function validateSendMessageInput(input: unknown): { valid: boolean; error?: string; }; /** * Validate ChatMessageFilter * * @param filter - Filter to validate * @returns Object with valid flag and optional error message */ export declare function validateChatMessageFilter(filter: unknown): { valid: boolean; error?: string; }; /** * Validate ConversationFilter * * @param filter - Filter to validate * @returns Object with valid flag and optional error message */ export declare function validateConversationFilter(filter: unknown): { valid: boolean; error?: string; }; //# sourceMappingURL=chat.types.d.ts.map