import { getCompanion } from './companion.js' type MessageLike = { type?: string message?: { content?: unknown } } function extractText(content: unknown): string { if (typeof content === 'string') return content if (!Array.isArray(content)) return '' return content .map(block => { if (!block || typeof block !== 'object') return '' const candidate = block as { type?: string; text?: string } return candidate.type === 'text' && typeof candidate.text === 'string' ? candidate.text : '' }) .join(' ') .trim() } function findLastText( messages: MessageLike[], targetType: 'assistant' | 'user', ): string { for (let i = messages.length - 1; i >= 0; i -= 1) { const message = messages[i] if (message?.type !== targetType) continue const text = extractText(message.message?.content) if (text) return text } return '' } function chooseReaction(userText: string, assistantText: string): string | undefined { const companion = getCompanion() if (!companion) return undefined const loweredUser = userText.toLowerCase() const loweredAssistant = assistantText.toLowerCase() const directMention = loweredUser.includes(companion.name.toLowerCase()) || loweredUser.includes('buddy') if (!directMention) return undefined if (/\b(thanks|thank you|nice|great|good job|cute)\b/.test(loweredUser)) { return `${companion.name} looks smug for exactly one second.` } if (/\b(help|idea|thought|opinion|what do you think)\b/.test(loweredUser)) { return `${companion.name} votes for the less cursed option.` } if (/\b(refactor|bug|error|failed|fix)\b/.test(loweredAssistant)) { return `${companion.name} squints at the bug like it owes rent.` } if (/\b(done|finished|fixed|works)\b/.test(loweredAssistant)) { return `${companion.name} seems satisfied with the outcome.` } return `${companion.name} is paying attention from the edge of the prompt box.` } export async function fireCompanionObserver( messages: MessageLike[], onReaction: (reaction: string | undefined) => void, ): Promise { const companion = getCompanion() if (!companion) { onReaction(undefined) return } const userText = findLastText(messages, 'user') const assistantText = findLastText(messages, 'assistant') onReaction(chooseReaction(userText, assistantText)) }