-
Notifications
You must be signed in to change notification settings - Fork 6
Result Object
adham90 edited this page Feb 16, 2026
·
4 revisions
Every agent call returns a Result object containing the response and rich metadata.
result = MyAgent.call(query: "test")
# The LLM's response
result.content # => { key: "value", ... }result.content
# => { refined_query: "red dress", filters: ["color:red"] }Deprecated (v0.4.0): Direct hash-style access on the result object is deprecated. Use
result.content[:key]instead ofresult[:key].
The Result object delegates to content for backward compatibility, but this will be removed in a future version:
# Deprecated - avoid this pattern
result[:refined_query] # => "red dress"
# Preferred - use content explicitly
result.content[:refined_query] # => "red dress"
result.content.dig(:nested, :key) # => "value"
result.content.fetch(:key, "default") # => "default"result.each { |k, v| puts "#{k}: #{v}" }
result.keys # => [:refined_query, :filters]
result.values # => ["red dress", ["color:red"]]result.input_tokens # => 150 - Tokens in the prompt
result.output_tokens # => 50 - Tokens in the response
result.total_tokens # => 200 - Total tokens used
result.cached_tokens # => 0 - Tokens from cache (some providers)result.input_cost # => 0.000150 - Cost of input tokens
result.output_cost # => 0.000100 - Cost of output tokens
result.total_cost # => 0.000250 - Total cost in USDresult.model_id # => "gpt-4o" - Model used
result.chosen_model_id # => "gpt-4o" - Final model (may differ if fallback used)
result.temperature # => 0.0 - Temperature settingresult.duration_ms # => 1234 - Total execution time
result.started_at # => 2024-01-15 10:30:00 UTC
result.completed_at # => 2024-01-15 10:30:01 UTC
result.time_to_first_token_ms # => 245 - Streaming onlyresult.success? # => true - Did the call succeed?
result.finish_reason # => "stop", "length", "tool_calls", etc.
result.streaming? # => false - Was streaming enabled?
result.truncated? # => false - Was output truncated (hit max_tokens)?| Reason | Meaning |
|---|---|
"stop" |
Normal completion |
"length" |
Hit max_tokens limit |
"tool_calls" |
Model wants to call tools |
"content_filter" |
Content was filtered |
For agents using tools:
result.tool_calls # => [{ "id" => "call_abc", "name" => "search", ... }]
result.tool_calls_count # => 1
result.has_tool_calls? # => trueFor agents with extended thinking enabled:
result.thinking_text # => "Let me work through this step by step..."
result.thinking_signature # => "sig_abc123" (for multi-turn, Claude)
result.thinking_tokens # => 500 - Tokens used for thinking
result.has_thinking? # => true - Whether thinking was usedresult = ReasoningAgent.call(query: "Complex problem")
if result.has_thinking?
puts "Reasoning:"
puts result.thinking_text
puts "\nThinking tokens used: #{result.thinking_tokens}"
end
puts "\nAnswer:"
puts result.contentSee Thinking for configuration details.
When using retries or fallbacks:
result.attempts_count # => 3 - Number of attempts made
result.used_fallback? # => true - Was a fallback model used?
result.chosen_model_id # => "gpt-4o-mini" - The model that succeededGet detailed information about each attempt:
result.attempts
# => [
# { model: "gpt-4o", status: "error", error: "Rate limit", duration_ms: 150 },
# { model: "gpt-4o", status: "error", error: "Rate limit", duration_ms: 320 },
# { model: "gpt-4o-mini", status: "success", duration_ms: 850 }
# ]
# Check specific conditions
result.attempts.any? { |a| a[:status] == "error" } # => true
result.attempts.last[:model] # => "gpt-4o-mini"Get everything as a hash:
result.to_h
# => {
# content: { refined_query: "red dress", ... },
# input_tokens: 150,
# output_tokens: 50,
# total_tokens: 200,
# cached_tokens: 0,
# cache_creation_tokens: 0,
# input_cost: 0.000150,
# output_cost: 0.000100,
# total_cost: 0.000250,
# model_id: "gpt-4o",
# chosen_model_id: "gpt-4o",
# temperature: 0.0,
# duration_ms: 1234,
# started_at: 2024-01-15 10:30:00 UTC,
# completed_at: 2024-01-15 10:30:01 UTC,
# time_to_first_token_ms: nil,
# finish_reason: "stop",
# streaming: false,
# error_class: nil,
# error_message: nil,
# attempts_count: 1,
# attempts: [],
# tool_calls: [],
# tool_calls_count: 0,
# thinking_text: nil,
# thinking_signature: nil,
# thinking_tokens: nil
# }When using dry_run: true:
result = MyAgent.call(query: "test", dry_run: true)
result[:dry_run] # => true
result[:agent] # => "MyAgent"
result[:model] # => "gpt-4o"
result[:temperature] # => 0.0
result[:system_prompt] # => "You are..."
result[:user_prompt] # => "Process: test"
result[:schema] # => "RubyLLM::Schema"When an execution fails:
result = MyAgent.call(query: "test")
if result.success?
process(result.content)
else
handle_error(result.error_message)
end
# Error information
result.error? # => true
result.error_class # => "Faraday::TooManyRequestsError"
result.error_message # => "Rate limit exceeded"class SearchController < ApplicationController
def search
result = SearchAgent.call(query: params[:q])
if result.success?
render json: {
results: result.content,
meta: {
tokens: result.total_tokens,
cost: result.total_cost,
duration_ms: result.duration_ms
}
}
else
render json: { error: result.error_message }, status: :service_unavailable
end
end
endresult = MyAgent.call(query: query)
Rails.logger.info({
agent: "MyAgent",
success: result.success?,
tokens: result.total_tokens,
cost: result.total_cost,
duration_ms: result.duration_ms,
model: result.chosen_model_id
}.to_json)# Track metrics over time
results = queries.map { |q| MyAgent.call(query: q) }
avg_cost = results.sum(&:total_cost) / results.size
avg_tokens = results.sum(&:total_tokens) / results.size
avg_duration = results.sum(&:duration_ms) / results.size
puts "Average cost: $#{avg_cost.round(6)}"
puts "Average tokens: #{avg_tokens}"
puts "Average duration: #{avg_duration}ms"- Agent DSL - Configuring agents
- Prompts and Schemas - Structuring outputs
- Execution Tracking - Persisted execution data
- Reliability - Retries and fallbacks