Class: Rubino::Tools::Result
- Inherits:
-
Object
- Object
- Rubino::Tools::Result
- Defined in:
- lib/rubino/tools/result.rb
Overview
Encapsulates the result of a tool execution.
Constant Summary collapse
- EMPTY_OUTPUT_PLACEHOLDER =
Substituted when a tool legitimately produces no output (e.g. ‘touch`). The string survives persistence and load_history, where nil/“” would be dropped and leave a tool_call orphaned — the provider then 400s the next turn for a tool_call with no matching tool_result.
"(no output)"- DENIED_OUTPUTS =
Model-facing text per denial reason (#143). Only a real human decision may read “denied by user” — an automatic denial must name the policy that fired, otherwise a child agent reports (and propagates upward) that “the user denied my tools” when no human ever decided anything.
{ user: "Tool execution denied by user.", policy: "Tool execution denied by policy (not by the user).", hardline: "Tool execution blocked by policy (hardline safety floor, not by the user): " \ "this command is never allowed.", permission_rule: "Tool execution blocked by policy (a configured permissions deny rule, " \ "not by the user).", doom_loop: "Tool execution blocked by the doom-loop guard (policy, not by the user): " \ "this exact call was already made repeatedly. Change strategy instead of " \ "retrying it — e.g. wait for the background-task completion notice instead " \ "of polling." }.freeze
Instance Attribute Summary collapse
-
#artifact ⇒ Object
readonly
Returns the value of attribute artifact.
-
#call_id ⇒ Object
readonly
Returns the value of attribute call_id.
-
#error ⇒ Object
readonly
Returns the value of attribute error.
-
#error_code ⇒ Object
readonly
Returns the value of attribute error_code.
-
#metrics ⇒ Object
readonly
Returns the value of attribute metrics.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#output ⇒ Object
readonly
Returns the value of attribute output.
-
#session_id ⇒ Object
readonly
Returns the value of attribute session_id.
-
#status ⇒ Object
readonly
Returns the value of attribute status.
Class Method Summary collapse
- .denied(name:, call_id:, reason: :user) ⇒ Object
- .error(name:, call_id:, error:, error_code: nil) ⇒ Object
- .normalize_output(output) ⇒ Object
-
.success(name:, call_id:, output:, metrics: nil, error_code: nil, artifact: nil) ⇒ Object
Factory methods.
Instance Method Summary collapse
- #denied? ⇒ Boolean
-
#errorish? ⇒ Boolean
True when this result represents a failure for DISPLAY purposes, even when the tool didn’t raise.
- #failed? ⇒ Boolean
-
#initialize(name:, call_id:, output:, status:, error: nil, metrics: nil, error_code: nil, artifact: nil) ⇒ Result
constructor
‘error_code` is an optional Symbol surface for callers (UI badges, automation, future contract tests) that want to branch on the failure mode without parsing the human-facing error string.
- #success? ⇒ Boolean
-
#truncated_preview(max_length: 80) ⇒ Object
Returns a truncated preview for display.
Constructor Details
#initialize(name:, call_id:, output:, status:, error: nil, metrics: nil, error_code: nil, artifact: nil) ⇒ Result
‘error_code` is an optional Symbol surface for callers (UI badges, automation, future contract tests) that want to branch on the failure mode without parsing the human-facing error string. Today the canonical signal is still the output text — the symbol is a belt-and-suspenders next to it, not a replacement.
‘artifact` is an optional Hash carrying { path:, filename:, content_type:, byte_size: } when a tool produced a downloadable user-facing file. The agent loop reads this and emits an ARTIFACT_CREATED bus event so SSE consumers (the web UI, the CLI) can offer a download.
21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/rubino/tools/result.rb', line 21 def initialize(name:, call_id:, output:, status:, error: nil, metrics: nil, error_code: nil, artifact: nil) @name = name @call_id = call_id @output = output @status = status @error = error @metrics = metrics @error_code = error_code @artifact = artifact @session_id = nil end |
Instance Attribute Details
#artifact ⇒ Object (readonly)
Returns the value of attribute artifact.
7 8 9 |
# File 'lib/rubino/tools/result.rb', line 7 def artifact @artifact end |
#call_id ⇒ Object (readonly)
Returns the value of attribute call_id.
7 8 9 |
# File 'lib/rubino/tools/result.rb', line 7 def call_id @call_id end |
#error ⇒ Object (readonly)
Returns the value of attribute error.
7 8 9 |
# File 'lib/rubino/tools/result.rb', line 7 def error @error end |
#error_code ⇒ Object (readonly)
Returns the value of attribute error_code.
7 8 9 |
# File 'lib/rubino/tools/result.rb', line 7 def error_code @error_code end |
#metrics ⇒ Object (readonly)
Returns the value of attribute metrics.
7 8 9 |
# File 'lib/rubino/tools/result.rb', line 7 def metrics @metrics end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
7 8 9 |
# File 'lib/rubino/tools/result.rb', line 7 def name @name end |
#output ⇒ Object (readonly)
Returns the value of attribute output.
7 8 9 |
# File 'lib/rubino/tools/result.rb', line 7 def output @output end |
#session_id ⇒ Object (readonly)
Returns the value of attribute session_id.
7 8 9 |
# File 'lib/rubino/tools/result.rb', line 7 def session_id @session_id end |
#status ⇒ Object (readonly)
Returns the value of attribute status.
7 8 9 |
# File 'lib/rubino/tools/result.rb', line 7 def status @status end |
Class Method Details
.denied(name:, call_id:, reason: :user) ⇒ Object
102 103 104 105 |
# File 'lib/rubino/tools/result.rb', line 102 def self.denied(name:, call_id:, reason: :user) key = DENIED_OUTPUTS.key?(reason) ? reason : :policy new(name: name, call_id: call_id, output: DENIED_OUTPUTS[key], status: :denied) end |
.error(name:, call_id:, error:, error_code: nil) ⇒ Object
78 79 80 81 82 83 |
# File 'lib/rubino/tools/result.rb', line 78 def self.error(name:, call_id:, error:, error_code: nil) msg = error.to_s msg = "unknown error" if msg.empty? new(name: name, call_id: call_id, output: "Error: #{msg}", status: :error, error: error, error_code: error_code) end |
.normalize_output(output) ⇒ Object
107 108 109 110 |
# File 'lib/rubino/tools/result.rb', line 107 def self.normalize_output(output) text = output.to_s text.empty? ? EMPTY_OUTPUT_PLACEHOLDER : text end |
.success(name:, call_id:, output:, metrics: nil, error_code: nil, artifact: nil) ⇒ Object
Factory methods
73 74 75 76 |
# File 'lib/rubino/tools/result.rb', line 73 def self.success(name:, call_id:, output:, metrics: nil, error_code: nil, artifact: nil) new(name: name, call_id: call_id, output: normalize_output(output), status: :success, metrics: metrics, error_code: error_code, artifact: artifact) end |
Instance Method Details
#denied? ⇒ Boolean
42 43 44 |
# File 'lib/rubino/tools/result.rb', line 42 def denied? @status == :denied end |
#errorish? ⇒ Boolean
True when this result represents a failure for DISPLAY purposes, even when the tool didn’t raise. Many tools (read, edit, …) report a soft failure by RETURNING an “Error: …” string (status stays :success) or by setting an error_code, instead of raising. The CLI used to render those as a green “✓ done” because it only checked #success?. This is the single predicate the UI uses so an errored tool shows “✗” regardless of which failure convention the tool used.
53 54 55 56 57 58 |
# File 'lib/rubino/tools/result.rb', line 53 def errorish? return true unless success? return true unless @error_code.nil? @output.to_s.start_with?("Error:") end |
#failed? ⇒ Boolean
38 39 40 |
# File 'lib/rubino/tools/result.rb', line 38 def failed? @status == :error end |
#success? ⇒ Boolean
34 35 36 |
# File 'lib/rubino/tools/result.rb', line 34 def success? @status == :success end |
#truncated_preview(max_length: 80) ⇒ Object
Returns a truncated preview for display
61 62 63 64 |
# File 'lib/rubino/tools/result.rb', line 61 def truncated_preview(max_length: 80) text = @output.to_s text.length > max_length ? "#{text[0...max_length]}..." : text end |