Class: SolidAgent::Reasonable::Reason

Inherits:
Object
  • Object
show all
Defined in:
lib/solid_agent/reasonable/reason.rb

Overview

Reason represents a single reasoning trace from an LLM's extended thinking.

LLMs like Claude (with extended thinking) and OpenAI's o1 models produce reasoning traces that explain their thought process before generating output. This class captures and structures that reasoning for persistence and analysis.

Examples:

Creating a reason from an LLM response

reason = Reason.new(
  content: "Let me think about this step by step...",
  tokens: 150,
  model: "claude-sonnet-4-20250514",
  thinking_time_ms: 2500
)

Checking if reasoning was used

reason.extended_thinking? #=> true
reason.summary(100) #=> "Let me think about this..."

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(content:, tokens: 0, model: nil, thinking_time_ms: nil, redacted: false, metadata: {}, created_at: nil) ⇒ Reason

Initialize a new Reason

Parameters:

  • content (String)

    The reasoning content/trace

  • tokens (Integer) (defaults to: 0)

    Number of reasoning tokens used

  • model (String) (defaults to: nil)

    The model that generated the reasoning

  • thinking_time_ms (Integer, nil) (defaults to: nil)

    Time spent on reasoning

  • redacted (Boolean) (defaults to: false)

    Whether content was redacted by provider

  • metadata (Hash) (defaults to: {})

    Additional provider-specific metadata



35
36
37
38
39
40
41
42
43
44
# File 'lib/solid_agent/reasonable/reason.rb', line 35

def initialize(content:, tokens: 0, model: nil, thinking_time_ms: nil,
               redacted: false, metadata: {}, created_at: nil)
  @content = content
  @tokens = tokens.to_i
  @model = model
  @thinking_time_ms = thinking_time_ms
  @redacted = redacted
  @metadata =  || {}
  @created_at = created_at || Time.current
end

Instance Attribute Details

#contentObject (readonly)

Returns the value of attribute content.



24
25
26
# File 'lib/solid_agent/reasonable/reason.rb', line 24

def content
  @content
end

#created_atObject (readonly)

Returns the value of attribute created_at.



24
25
26
# File 'lib/solid_agent/reasonable/reason.rb', line 24

def created_at
  @created_at
end

#metadataObject (readonly)

Returns the value of attribute metadata.



24
25
26
# File 'lib/solid_agent/reasonable/reason.rb', line 24

def 
  @metadata
end

#modelObject (readonly)

Returns the value of attribute model.



24
25
26
# File 'lib/solid_agent/reasonable/reason.rb', line 24

def model
  @model
end

#redactedObject (readonly)

Returns the value of attribute redacted.



24
25
26
# File 'lib/solid_agent/reasonable/reason.rb', line 24

def redacted
  @redacted
end

#thinking_time_msObject (readonly)

Returns the value of attribute thinking_time_ms.



24
25
26
# File 'lib/solid_agent/reasonable/reason.rb', line 24

def thinking_time_ms
  @thinking_time_ms
end

#tokensObject (readonly)

Returns the value of attribute tokens.



24
25
26
# File 'lib/solid_agent/reasonable/reason.rb', line 24

def tokens
  @tokens
end

Class Method Details

.from_h(hash) ⇒ Reason

Create from a hash (deserialization)

Parameters:

  • hash (Hash)

    Hash representation

Returns:



93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/solid_agent/reasonable/reason.rb', line 93

def self.from_h(hash)
  return nil unless hash.is_a?(Hash)

  new(
    content: hash[:content] || hash["content"],
    tokens: hash[:tokens] || hash["tokens"] || 0,
    model: hash[:model] || hash["model"],
    thinking_time_ms: hash[:thinking_time_ms] || hash["thinking_time_ms"],
    redacted: hash[:redacted] || hash["redacted"] || false,
    metadata: hash[:metadata] || hash["metadata"] || {},
    created_at: parse_time(hash[:created_at] || hash["created_at"])
  )
end

.from_response(response) ⇒ Reason?

Create from an ActiveAgent/LLM provider response

Parameters:

  • response (Object)

    Provider response object

Returns:



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/solid_agent/reasonable/reason.rb', line 111

def self.from_response(response)
  return nil unless response

  # Handle different response formats
  reasoning_content = extract_reasoning_content(response)
  reasoning_tokens = extract_reasoning_tokens(response)

  return nil if reasoning_content.blank? && reasoning_tokens.zero?

  new(
    content: reasoning_content,
    tokens: reasoning_tokens,
    model: response.respond_to?(:model) ? response.model : nil,
    thinking_time_ms: extract_thinking_time(response),
    redacted: reasoning_redacted?(response),
    metadata: (response)
  )
end

Instance Method Details

#extended_thinking?Boolean

Check if this represents extended thinking (vs. standard generation)

Returns:

  • (Boolean)


49
50
51
# File 'lib/solid_agent/reasonable/reason.rb', line 49

def extended_thinking?
  tokens.positive? || content.present?
end

#redacted?Boolean

Check if the reasoning content was redacted by the provider

Returns:

  • (Boolean)


56
57
58
# File 'lib/solid_agent/reasonable/reason.rb', line 56

def redacted?
  @redacted == true
end

#summary(length: 200) ⇒ String

Get a summary of the reasoning content

Parameters:

  • length (Integer) (defaults to: 200)

    Maximum length of summary

Returns:

  • (String)


64
65
66
67
68
69
70
71
72
# File 'lib/solid_agent/reasonable/reason.rb', line 64

def summary(length: 200)
  return "[Redacted]" if redacted?
  return "" if content.blank?

  str = content.to_s
  return str if str.length <= length

  "#{str[0, length - 3]}..."
end

#to_hHash

Convert to a hash for serialization

Returns:

  • (Hash)


77
78
79
80
81
82
83
84
85
86
87
# File 'lib/solid_agent/reasonable/reason.rb', line 77

def to_h
  {
    content: content,
    tokens: tokens,
    model: model,
    thinking_time_ms: thinking_time_ms,
    redacted: redacted,
    metadata: ,
    created_at: created_at&.iso8601
  }.compact
end