Class: Silas::Channels::SlackController

Inherits:
BaseController
  • Object
show all
Defined in:
app/controllers/silas/channels/slack_controller.rb

Overview

Slack transport webhooks. Inbound messages start/continue a session; interactive button clicks map to the existing invocation.approve!/decline!. Requires app/agent/channels/slack.rb (Agent::Channels::Slack) to exist.

Instance Method Summary collapse

Instance Method Details

#actionsObject

POST /channels/slack/actions



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'app/controllers/silas/channels/slack_controller.rb', line 31

def actions
  return unless verify_slack!

  payload = JSON.parse(params[:payload])
  action = payload.fetch("actions").first
  invocation = Silas::ToolInvocation.find(action["value"])
  who = "slack:#{payload.dig('user', 'username') || payload.dig('user', 'id')}"

  if action["action_id"] == "silas_approve"
    invocation.approve!(by: who)
    render json: { replace_original: true, text: ":white_check_mark: Approved by @#{who}" }
  else
    invocation.decline!(reason: "declined in Slack", by: who)
    render json: { replace_original: true, text: ":x: Declined by @#{who}" }
  end
rescue Silas::Error => e
  render json: { replace_original: false, text: "Could not record: #{e.message}" }
end

#eventsObject

POST /channels/slack/events



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'app/controllers/silas/channels/slack_controller.rb', line 8

def events
  return unless verify_slack!
  return render(json: { challenge: params[:challenge] }) if params[:type] == "url_verification"
  # Slack retries deliver at-least-once; ignore retries (continuation-token
  # uniqueness + single-active-turn are the real dedup).
  return head(:ok) if request.headers["X-Slack-Retry-Num"].present?

  event = params[:event]
  if event && event[:type] == "message" && event[:bot_id].blank? && event[:subtype].blank?
    thread_key = "#{params[:team_id]}:#{event[:channel]}:#{event[:thread_ts] || event[:ts]}"
    channel_class.dispatch(
      thread_key: thread_key, input: event[:text].to_s,
      metadata: { "slack" => { "channel" => event[:channel],
                               "thread_ts" => event[:thread_ts] || event[:ts],
                               "user" => event[:user] } }
    )
  end
  head :ok
rescue Silas::TurnInProgressError
  head :ok # single-active-turn: a reply mid-turn is dropped (v1 policy)
end