Module: Ask::Agent::Streaming

Defined in:
lib/ask/agent/streaming.rb

Overview

Framework-agnostic SSE streaming for agent sessions.

Returns a Rack-compatible Enumerator that yields SSE-formatted strings as the agent runs. Works with any Rack server (Puma, Falcon, etc.) without requiring ActionController::Live or Rails.

Examples:

In a Rails controller (with ActionController::Live::SSE)

def create
  response.headers["Content-Type"] = "text/event-stream"
  sse = SSE.new(response.stream)

  Ask::Agent::Streaming.run(session, prompt) do |type, data|
    sse.write(data, event: type)
  end
ensure
  sse&.close
end

In a Rack app (raw Enumerator)

stream = Ask::Agent::Streaming.run(session, prompt)
[200, { "Content-Type" => "text/event-stream" }, stream]

With custom event mapping

stream = Ask::Agent::Streaming.run(session, prompt) do |event|
  case event
  when Events::TextDelta
    { type: "delta", data: { content: event.content } }
  when Events::ToolExecutionStart
    { type: "tool_start", data: { name: event.name, id: event.id } }
  else
    nil # skip unhandled events
  end
end

Constant Summary collapse

DEFAULT_EVENT_MAP =
{
  Events::TextDelta => "delta",
  Events::ThinkingDelta => "thinking",
  Events::ToolCallDelta => "tool_call_delta",
  Events::ToolExecutionStart => "tool_start",
  Events::ToolExecutionUpdate => "tool_update",
  Events::ToolExecutionEnd => "tool_end",
  Events::SessionEnd => "done",
  Events::Error => "error"
}.freeze

Class Method Summary collapse

Class Method Details

.run(session, prompt, event_map: {}) {|type, data| ... } ⇒ Enumerator?

Run an agent session and stream events as SSE-formatted strings.

Two modes:

  1. No block — returns a Rack-compatible Enumerator that yields raw SSE strings: "data: \"type\":\"delta\",\"content\":\"..\"type\":\"delta\",\"content\":\"...\"\n\n"

  2. With block — calls the block for each event with (event_type_string, data_hash). The block is responsible for writing/handling the data. This mode is designed for use with Rails' ActionController::Live::SSE#write.

Parameters:

  • session (Session)

    the agent session to run

  • prompt (String)

    the user's message

  • event_map (Hash<Class, String>) (defaults to: {})

    optional custom event-to-type mapping

Yields:

  • (type, data)

    called for each event (only in block mode)

Yield Parameters:

  • type (String)

    the SSE event type name

  • data (Hash)

    the event data payload

Returns:

  • (Enumerator, nil)

    Enumerator in no-block mode, nil in block mode



72
73
74
75
76
77
78
79
80
81
# File 'lib/ask/agent/streaming.rb', line 72

def run(session, prompt, event_map: {}, &block)
  mapping = DEFAULT_EVENT_MAP.merge(event_map)

  if block
    run_with_block(session, prompt, mapping, &block)
    nil
  else
    run_with_enumerator(session, prompt, mapping)
  end
end