Module: Riffer::Agent::Session::Repair
Overview
Pure, stateless transformations keeping the tool_use ↔ tool_result
invariant on a message array. Each entry point no-ops when
Riffer.config.experimental_history_healing is off.
Constant Summary collapse
- ORPHAN_PLACEHOLDER =
Placeholder response filled in for an orphaned
tool_useon interrupt. ->(_tool_call) { Riffer::Tools::Response.error("Tool call interrupted before completion.", type: :interrupted) }
Instance Method Summary collapse
-
#fill_orphans(messages) ⇒ Object
Fills each orphaned
tool_useinmessageswith anORPHAN_PLACEHOLDERresult inserted after its parent. -
#prune_orphans(messages) ⇒ Object
Prunes a seeded message array to the invariant — dropping orphaned tool exchanges and parentless Tool messages, but preserving the pending tool_calls on the resume boundary (the last assistant) for
execute_pending_tool_calls.
Instance Method Details
#fill_orphans(messages) ⇒ Object
Fills each orphaned tool_use in messages with an ORPHAN_PLACEHOLDER
result inserted after its parent. Returns [new_messages, filled_call_ids].
: (Array) -> [Array[Riffer::Messages::Base], Array[String]]
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/riffer/agent/session/repair.rb', line 19 def fill_orphans() return [, []] unless Riffer.config.experimental_history_healing result_ids = .filter_map { |m| m.tool_call_id if m.is_a?(Riffer::Messages::Tool) } filled = [] #: Array[String] = [] #: Array[Riffer::Messages::Base] .each do |m| << m next unless m.is_a?(Riffer::Messages::Assistant) && !m.tool_calls.empty? m.tool_calls.each do |tc| next if result_ids.include?(tc.call_id) response = ORPHAN_PLACEHOLDER.call(tc) << Riffer::Messages::Tool.new( response.content, tool_call_id: tc.call_id, name: tc.name, error: response., error_type: response.error_type ) filled << tc.call_id end end [, filled] end |
#prune_orphans(messages) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/riffer/agent/session/repair.rb', line 54 def prune_orphans() return unless Riffer.config.experimental_history_healing resume_boundary = (.length - 1).downto(0).find { |idx| m = [idx] m.is_a?(Riffer::Messages::Assistant) && ([(idx + 1)..] || []).all? { |later| later.is_a?(Riffer::Messages::Tool) } } result_ids = .filter_map { |m| m.tool_call_id if m.is_a?(Riffer::Messages::Tool) } parent_ids = .flat_map { |m| m.is_a?(Riffer::Messages::Assistant) ? m.tool_calls.map(&:call_id) : [] } strip_offenders = .each_with_index.flat_map { |m, idx| next [] unless m.is_a?(Riffer::Messages::Assistant) && !m.tool_calls.empty? next [] if idx == resume_boundary # preserve pending exchange next [] if m.tool_calls.all? { |tc| result_ids.include?(tc.call_id) } m.tool_calls.map(&:call_id) } .reject { |m| case m when Riffer::Messages::Assistant !m.tool_calls.empty? && m.tool_calls.any? { |tc| strip_offenders.include?(tc.call_id) } when Riffer::Messages::Tool strip_offenders.include?(m.tool_call_id) || !parent_ids.include?(m.tool_call_id) else false end } end |