File size: 2,392 Bytes
064bfd6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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<void> {
  const companion = getCompanion()
  if (!companion) {
    onReaction(undefined)
    return
  }

  const userText = findLastText(messages, 'user')
  const assistantText = findLastText(messages, 'assistant')
  onReaction(chooseReaction(userText, assistantText))
}