Class: RailsErrorDashboard::Subscribers::LlmCallSubscriber
- Inherits:
-
Object
- Object
- RailsErrorDashboard::Subscribers::LlmCallSubscriber
- Defined in:
- lib/rails_error_dashboard/subscribers/llm_call_subscriber.rb
Overview
ActiveSupport::Notifications subscriber for manually-instrumented LLM calls. The Tier 3 path — for hosts that don’t run OpenTelemetry AND don’t use Faraday-based LLM SDKs (e.g., direct Net::HTTP, gRPC clients, custom adapters, or hosts that want to layer in extra LLM activity that the automatic paths can’t see, like local inference servers).
Usage in the host app:
ActiveSupport::Notifications.instrument("red.llm_call",
provider: "ollama",
model: "llama3:8b",
input_tokens: 1200,
output_tokens: 350
) do
# ... call your LLM ...
end
# Tool execution
ActiveSupport::Notifications.instrument("red.llm_tool_call",
tool_name: "search_database",
tool_arguments: { query: "..." },
tool_result: "[...]"
) do
# ... execute tool ...
end
Payload contract = LlmCallEvent constructor kwargs:
:provider, :model, :status, :input_tokens, :output_tokens,
:duration_ms, :error_class, :error_message, :tool_name,
:tool_arguments, :tool_result, :cost_usd_estimate
Duration: defaults to ‘event.duration` (host wraps `.instrument` around the work); payload `:duration_ms` overrides if explicitly supplied. Cost: auto-estimated from provider/model/tokens unless payload supplies `:cost_usd_estimate`.
SAFETY RULES (HOST_APP_SAFETY.md):
-
Every callback wrapped in rescue => e; nil
-
Never raise from subscriber callbacks
-
Skip if buffer is nil (not in a request context)
-
Re-read config on every event (host may toggle at runtime)
Constant Summary collapse
- CHAT_EVENT =
"red.llm_call"- TOOL_EVENT =
"red.llm_tool_call"- EVENTS =
[ CHAT_EVENT, TOOL_EVENT ].freeze
Class Attribute Summary collapse
-
.subscriptions ⇒ Object
readonly
Returns the value of attribute subscriptions.
Class Method Summary collapse
-
.subscribe! ⇒ Object
Idempotent — re-subscribing first tears down previous subscriptions so Spring reloads / repeated engine boots don’t pile up duplicates.
- .unsubscribe! ⇒ Object
Class Attribute Details
.subscriptions ⇒ Object (readonly)
Returns the value of attribute subscriptions.
54 55 56 |
# File 'lib/rails_error_dashboard/subscribers/llm_call_subscriber.rb', line 54 def subscriptions @subscriptions end |
Class Method Details
.subscribe! ⇒ Object
Idempotent — re-subscribing first tears down previous subscriptions so Spring reloads / repeated engine boots don’t pile up duplicates.
58 59 60 61 |
# File 'lib/rails_error_dashboard/subscribers/llm_call_subscriber.rb', line 58 def subscribe! unsubscribe! @subscriptions = EVENTS.map { |name| subscribe_event(name) } end |
.unsubscribe! ⇒ Object
63 64 65 66 67 68 69 70 |
# File 'lib/rails_error_dashboard/subscribers/llm_call_subscriber.rb', line 63 def unsubscribe! (@subscriptions || []).each do |sub| ActiveSupport::Notifications.unsubscribe(sub) if sub rescue StandardError nil end @subscriptions = [] end |