Class: AgUi::RunLoop

Inherits:
Object
  • Object
show all
Defined in:
lib/ag_ui/run_loop.rb

Overview

The run loop: drives one AG-UI run through a brute turn pipeline.

The terminal block is the LLM call (ruby_llm or anything else) — it receives brute's env (events:, ...), streams deltas into env (translated live to SSE by EventBridge) and appends the assistant message to env. The gem stays LLM-agnostic.

run_loop = AgUi::RunLoop.new(system_prompt: PROMPT) do |env|
env[:events] << { type: :text_message_start, data: { message_id: id } }
... stream provider chunks ...
env[:events] << { type: :text_message_end, data: { message_id: id } }
env[:messages].assistant(full_text)
end

app = AgUi.agent(agent_id: "default", &run_loop)

Lifecycle per run (the AG-UI contract): RUN_STARTED first; then the pipeline streams; then RUN_FINISHED — or RUN_ERROR if the pipeline raised. Schema-validation failures are wire-contract bugs and re-raise after RUN_ERROR so they fail loudly in dev.

Instance Method Summary collapse

Constructor Details

#initialize(system_prompt: nil, validate: true, middleware: [], a2ui: nil, server_tools: [], max_iterations: 10, &terminal) ⇒ RunLoop

a2ui: nil/false = off; an AgUi::A2ui::Catalog = on with that catalog; true = on degraded (tool injected, no component schema). server_tools: [description:, parameters:, handler:] execute inline and the turn loops (Loop::ToolResult) until the model answers in text, a client tool defers to the browser, or max_iterations hits.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ag_ui/run_loop.rb', line 34

def initialize(system_prompt: nil, validate: true, middleware: [], a2ui: nil,
               server_tools: [], max_iterations: 10, &terminal)
  unless terminal
    raise ArgumentError, "RunLoop requires a terminal block (the LLM call)"
  end

  @system_prompt = system_prompt
  @validate = validate
  @middleware = middleware
  @a2ui = a2ui
  @server_tools = server_tools
  @max_iterations = max_iterations
  @terminal = terminal
end

Instance Method Details

#a2ui_enabled?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/ag_ui/run_loop.rb', line 49

def a2ui_enabled?
  !(@a2ui.nil? || @a2ui == false)
end

#handle(rack_env) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ag_ui/run_loop.rb', line 59

def handle(rack_env)
  input = rack_env["ag_ui.input"]

  rack_env["ag_ui.stream"].open(
    thread_id: input.thread_id,
    run_id: input.run_id,
    validate: @validate,
  ) do |stream|
    stream.run_started
    run(stream, input)
  end
end

#to_procObject

AgUi.agent takes a block; RunLoop quacks like one.



54
55
56
57
# File 'lib/ag_ui/run_loop.rb', line 54

def to_proc
  run_loop = self
  proc { |rack_env| run_loop.handle(rack_env) }
end