Module: SolidAgent::Reasonable

Extended by:
ActiveSupport::Concern
Defined in:
lib/solid_agent/reasonable.rb,
lib/solid_agent/reasonable/reason.rb

Overview

Reasonable provides AI reasoning/thinking trace support for models.

This concern enables models to track and store reasoning traces from LLMs that support extended thinking (like Claude's extended thinking or OpenAI's o1 reasoning models).

Reasoning traces help with:

  • Transparency: Understanding why an AI made certain decisions
  • Debugging: Identifying issues in AI logic
  • Auditing: Maintaining records of AI decision-making processes
  • Learning: Improving prompts based on reasoning patterns

Examples:

Basic usage in a model

class AgentGeneration < ApplicationRecord
  include SolidAgent::Reasonable
end

generation.store_reasoning!(response)
generation.reasoning_content     #=> "Let me think step by step..."
generation.reasoning_tokens      #=> 150
generation.has_reasoning?        #=> true

Configuring reasoning storage

class MyGeneration < ApplicationRecord
  include SolidAgent::Reasonable

  reasonable_config(
    column: :thinking_trace,    # Custom column name
    tokens_column: :think_tokens,
    auto_extract: true          # Auto-extract from responses
  )
end

Defined Under Namespace

Classes: Reason

Instance Method Summary collapse

Instance Method Details

#has_reasoning?Boolean

Check if this record has reasoning stored

Returns:

  • (Boolean)


119
120
121
# File 'lib/solid_agent/reasonable.rb', line 119

def has_reasoning?
  reasoning_content.present? || reasoning_tokens.positive?
end

#reasoning_contentString?

Get the stored reasoning content

Returns:

  • (String, nil)


95
96
97
98
# File 'lib/solid_agent/reasonable.rb', line 95

def reasoning_content
  column = _reasonable_config[:column]
  respond_to?(column) ? send(column) : nil
end

#reasoning_metadataHash

Get the stored reasoning metadata

Returns:

  • (Hash)


111
112
113
114
# File 'lib/solid_agent/reasonable.rb', line 111

def 
  column = _reasonable_config[:metadata_column]
  (respond_to?(column) ? send(column) : {}) || {}
end

#reasoning_redacted?Boolean

Check if reasoning was redacted

Returns:

  • (Boolean)


126
127
128
# File 'lib/solid_agent/reasonable.rb', line 126

def reasoning_redacted?
  ["redacted"] == true
end

#reasoning_summary(length: 200) ⇒ String

Get a summary of the reasoning

Parameters:

  • length (Integer) (defaults to: 200)

    Maximum length

Returns:

  • (String)


151
152
153
154
155
156
# File 'lib/solid_agent/reasonable.rb', line 151

def reasoning_summary(length: 200)
  return "[Redacted]" if reasoning_redacted?
  return "" if reasoning_content.blank?

  reasoning_content.truncate(length)
end

#reasoning_tokensInteger

Get the stored reasoning token count

Returns:

  • (Integer)


103
104
105
106
# File 'lib/solid_agent/reasonable.rb', line 103

def reasoning_tokens
  column = _reasonable_config[:tokens_column]
  (respond_to?(column) ? send(column) : 0).to_i
end

#store_reason!(reason) ⇒ Reason

Store reasoning from a Reason object

Parameters:

  • reason (Reason)

    The reason to store

Returns:

  • (Reason)

    The stored reason



85
86
87
88
89
90
# File 'lib/solid_agent/reasonable.rb', line 85

def store_reason!(reason)
  return nil unless reason.is_a?(Reason)

  update_reasoning_columns(reason)
  reason
end

#store_reasoning!(response) ⇒ Reason?

Store reasoning from an LLM response

Parameters:

  • response (Object)

    LLM response with reasoning data

Returns:

  • (Reason, nil)

    The extracted reason or nil



73
74
75
76
77
78
79
# File 'lib/solid_agent/reasonable.rb', line 73

def store_reasoning!(response)
  reason = Reason.from_response(response)
  return nil unless reason&.extended_thinking?

  update_reasoning_columns(reason)
  reason
end

#to_reasonReason?

Get a Reason object from stored data

Returns:



133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/solid_agent/reasonable.rb', line 133

def to_reason
  return nil unless has_reasoning?

  Reason.new(
    content: reasoning_content,
    tokens: reasoning_tokens,
    model: respond_to?(:model) ? model : nil,
    thinking_time_ms: ["thinking_time_ms"],
    redacted: reasoning_redacted?,
    metadata: ,
    created_at: respond_to?(:created_at) ? created_at : nil
  )
end