Class: ConsoleAgent::Channel::Slack

Inherits:
Base
  • Object
show all
Defined in:
lib/console_agent/channel/slack.rb

Constant Summary collapse

ANSI_REGEX =
/\e\[[0-9;]*m/
THINKING_MESSAGES =
[
  "Thinking...",
  "Reticulating splines...",
  "Scrubbing encryption bits...",
  "Consulting the oracle...",
  "Rummaging through the database...",
  "Warming up the hamster wheel...",
  "Polishing the pixels...",
  "Untangling the spaghetti code...",
  "Asking the magic 8-ball...",
  "Counting all the things...",
  "Herding the electrons...",
  "Dusting off the old records...",
  "Feeding the algorithms...",
  "Shaking the data tree...",
  "Bribing the servers...",
].freeze

Instance Method Summary collapse

Methods inherited from Base

#edit_code

Constructor Details

#initialize(slack_bot:, channel_id:, thread_ts:, user_name: nil) ⇒ Slack

Returns a new instance of Slack.



26
27
28
29
30
31
32
33
34
35
# File 'lib/console_agent/channel/slack.rb', line 26

def initialize(slack_bot:, channel_id:, thread_ts:, user_name: nil)
  @slack_bot = slack_bot
  @channel_id = channel_id
  @thread_ts = thread_ts
  @user_name = user_name
  @reply_queue = Queue.new
  @cancelled = false
  @log_prefix = "[#{@channel_id}/#{@thread_ts}] @#{@user_name}"
  @output_log = StringIO.new
end

Instance Method Details

#cancel!Object



37
38
39
# File 'lib/console_agent/channel/slack.rb', line 37

def cancel!
  @cancelled = true
end

#cancelled?Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/console_agent/channel/slack.rb', line 41

def cancelled?
  @cancelled
end

#confirm(_text) ⇒ Object



92
93
94
# File 'lib/console_agent/channel/slack.rb', line 92

def confirm(_text)
  'y'
end

#console_capture_stringObject



154
155
156
# File 'lib/console_agent/channel/slack.rb', line 154

def console_capture_string
  @output_log.string
end

#display(text) ⇒ Object



45
46
47
# File 'lib/console_agent/channel/slack.rb', line 45

def display(text)
  post(strip_ansi(text))
end

#display_code(_code) ⇒ Object



70
71
72
73
# File 'lib/console_agent/channel/slack.rb', line 70

def display_code(_code)
  # Don't post raw code/plan steps to Slack — non-technical users don't need to see Ruby
  nil
end

#display_dim(text) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/console_agent/channel/slack.rb', line 49

def display_dim(text)
  stripped = strip_ansi(text).strip
  if stripped =~ /\AThinking\.\.\.|\ACalling LLM/
    post(random_thinking_message)
  elsif stripped =~ /\AAttempting to fix|\ACancelled|\A_session:/
    post(stripped)
  else
    # Log for engineers but don't post to Slack
    @output_log.write("#{stripped}\n")
    $stdout.puts "#{@log_prefix} (dim) #{stripped}"
  end
end

#display_error(text) ⇒ Object



66
67
68
# File 'lib/console_agent/channel/slack.rb', line 66

def display_error(text)
  post(":x: #{strip_ansi(text)}")
end

#display_result(_result) ⇒ Object



82
83
84
85
# File 'lib/console_agent/channel/slack.rb', line 82

def display_result(_result)
  # Don't post raw return values to Slack — the LLM formats output via puts
  nil
end

#display_result_output(output) ⇒ Object



75
76
77
78
79
80
# File 'lib/console_agent/channel/slack.rb', line 75

def display_result_output(output)
  text = strip_ansi(output).strip
  return if text.empty?
  text = text[0, 3000] + "\n... (truncated)" if text.length > 3000
  post("```#{text}```")
end

#display_warning(text) ⇒ Object



62
63
64
# File 'lib/console_agent/channel/slack.rb', line 62

def display_warning(text)
  post(":warning: #{strip_ansi(text)}")
end

#log_input(text) ⇒ Object



144
145
146
# File 'lib/console_agent/channel/slack.rb', line 144

def log_input(text)
  @output_log.write("@#{@user_name}: #{text}\n")
end

#modeObject



100
101
102
# File 'lib/console_agent/channel/slack.rb', line 100

def mode
  'slack'
end

#prompt(text) ⇒ Object



87
88
89
90
# File 'lib/console_agent/channel/slack.rb', line 87

def prompt(text)
  post(strip_ansi(text))
  @reply_queue.pop
end

#receive_reply(text) ⇒ Object

Called by SlackBot when a thread reply arrives



149
150
151
152
# File 'lib/console_agent/channel/slack.rb', line 149

def receive_reply(text)
  @output_log.write("@#{@user_name}: #{text}\n")
  @reply_queue.push(text)
end

#supports_danger?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/console_agent/channel/slack.rb', line 104

def supports_danger?
  false
end

#supports_editing?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/console_agent/channel/slack.rb', line 108

def supports_editing?
  false
end

#system_instructionsObject



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/console_agent/channel/slack.rb', line 116

def system_instructions
  <<~INSTRUCTIONS.strip
    ## Response Formatting (Slack Channel)

    You are responding to non-technical users in Slack. Follow these rules:

    - Slack does NOT support markdown tables. For tabular data, use `puts` to print
      a plain-text table inside a code block. Use fixed-width columns with padding so
      columns align. Example format:
      ```
      ID   Name              Email
      123  John Smith        [email protected]
      456  Jane Doe          [email protected]
      ```
    - Use `puts` with formatted output instead of returning arrays or hashes
    - Summarize findings in plain, simple language
    - Do NOT show technical details like SQL queries, token counts, or class names
    - Keep explanations simple and jargon-free
    - Never return raw Ruby objects — always present data in a human-readable way
    - The output of `puts` in your code is automatically shown to the user. Do NOT
      repeat or re-display data that your code already printed via `puts`.
      Just add a brief summary after (e.g. "10 events found" or "Let me know if you need more detail").
    - This is a live production database — other processes, users, and background jobs are
      constantly changing data. Never assume results will be the same as a previous query.
      Always re-run queries when asked, even if you just ran the same one.
  INSTRUCTIONS
end

#user_identityObject



96
97
98
# File 'lib/console_agent/channel/slack.rb', line 96

def user_identity
  @user_name
end

#wrap_llm_call(&block) ⇒ Object



112
113
114
# File 'lib/console_agent/channel/slack.rb', line 112

def wrap_llm_call(&block)
  yield
end