Class: SessionChannel

Inherits:
ApplicationCable::Channel show all
Defined in:
app/channels/session_channel.rb

Overview

Streams events for a specific session to connected clients. Part of the Brain/TUI separation: the Brain broadcasts events through this channel, and any number of clients (TUI, web, API) can subscribe.

On subscription, sends the session’s chat history so the client can render previous messages without a separate API call.

Examples:

Client subscribes to a session

App.cable.subscriptions.create({ channel: "SessionChannel", session_id: 42 })

Constant Summary collapse

DEFAULT_LIST_LIMIT =
10
MAX_LIST_LIMIT =
50

Instance Method Summary collapse

Instance Method Details

#change_view_mode(data) ⇒ Object

Changes the session’s view mode and re-broadcasts the viewport. All clients on the session receive the mode change and fresh history.

Parameters:

  • data (Hash)

    must include “view_mode” (one of Session::VIEW_MODES)



93
94
95
96
97
98
99
100
101
102
103
104
# File 'app/channels/session_channel.rb', line 93

def change_view_mode(data)
  mode = data["view_mode"].to_s
  return transmit_error("Invalid view mode") unless Session::VIEW_MODES.include?(mode)

  session = Session.find(@current_session_id)
  session.update!(view_mode: mode)

  ActionCable.server.broadcast(stream_name, {"action" => "view_mode_changed", "view_mode" => mode})
  broadcast_viewport(session)
rescue ActiveRecord::RecordNotFound
  transmit_error("Session not found")
end

#create_session(_data) ⇒ Object

Creates a new session and switches the channel stream to it. The client receives a session_changed signal followed by (empty) history.



71
72
73
74
# File 'app/channels/session_channel.rb', line 71

def create_session(_data)
  session = Session.create!
  switch_to_session(session.id)
end

#list_sessions(data) ⇒ Object

Returns recent sessions with metadata for session picker UI.

Parameters:

  • data (Hash)

    optional “limit” (default 10, max 50)



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'app/channels/session_channel.rb', line 53

def list_sessions(data)
  limit = (data["limit"] || DEFAULT_LIST_LIMIT).to_i.clamp(1, MAX_LIST_LIMIT)
  sessions = Session.recent(limit)
  counts = Event.where(session_id: sessions.select(:id)).llm_messages.group(:session_id).count

  result = sessions.map do |session|
    {
      id: session.id,
      created_at: session.created_at.iso8601,
      updated_at: session.updated_at.iso8601,
      message_count: counts[session.id] || 0
    }
  end
  transmit({"action" => "sessions_list", "sessions" => result})
end

#receive(data) ⇒ Object

Receives messages from clients and broadcasts them to all session subscribers.

Parameters:

  • data (Hash)

    arbitrary message payload



35
36
37
# File 'app/channels/session_channel.rb', line 35

def receive(data)
  ActionCable.server.broadcast(stream_name, data)
end

#speak(data) ⇒ Object

Processes user input: persists the message and enqueues LLM processing.

Parameters:

  • data (Hash)

    must include “content” with the user’s message text



42
43
44
45
46
47
48
# File 'app/channels/session_channel.rb', line 42

def speak(data)
  content = data["content"].to_s.strip
  return if content.empty? || !Session.exists?(@current_session_id)

  Events::Bus.emit(Events::UserMessage.new(content: content, session_id: @current_session_id))
  AgentRequestJob.perform_later(@current_session_id)
end

#subscribedObject

Subscribes the client to the session-specific stream. Rejects the subscription if no valid session_id is provided. Transmits the current view_mode and chat history to the subscribing client.

Parameters:

  • params (Hash)

    must include :session_id (positive integer)



21
22
23
24
25
26
27
28
29
30
# File 'app/channels/session_channel.rb', line 21

def subscribed
  @current_session_id = params[:session_id].to_i
  if @current_session_id > 0
    stream_from stream_name
    transmit_view_mode
    transmit_history
  else
    reject
  end
end

#switch_session(data) ⇒ Object

Switches the channel stream to an existing session. The client receives a session_changed signal followed by chat history.

Parameters:

  • data (Hash)

    must include “session_id” (positive integer)



80
81
82
83
84
85
86
87
# File 'app/channels/session_channel.rb', line 80

def switch_session(data)
  target_id = data["session_id"].to_i
  return transmit_error("Session not found") unless target_id > 0

  switch_to_session(target_id)
rescue ActiveRecord::RecordNotFound
  transmit_error("Session not found")
end