Class: Assistant::RestoreToolResultBuilder
- Inherits:
-
Object
- Object
- Assistant::RestoreToolResultBuilder
- Defined in:
- app/services/assistant/restore_tool_result_builder.rb
Overview
Builds the +restore_tool_result+ tool: retrieves the full, uncompressed
output of an earlier tool result that ContextCompactor truncated to save
context. The original is stashed in +assistant_messages.compacted_content+
keyed by the message id, so — unlike a stateless compression proxy —
there is no hash store; the message id shown in the truncated result's
+_restore+ marker is the key.
Gated by +ContextCompactor.restore_enabled?+ (env SUNNY_TOOL_RESULT_RESTORE):
no point offering the tool when nothing is being stashed to restore.
Class Method Summary collapse
Class Method Details
.tool(conversation_id) ⇒ RubyLLM::Tool
18 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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'app/services/assistant/restore_tool_result_builder.rb', line 18 def tool(conversation_id) captured_conversation_id = conversation_id Class.new(RubyLLM::Tool) do description <<~DESC.squish Retrieve the full, uncompressed output of an earlier tool result that was truncated to save context. When a tool result shows a "_restore" field with a message_id, call this with that message_id to get the complete original output — use it when the truncated version dropped rows, fields, or detail you now need. DESC parameters type: 'object', properties: { message_id: { type: 'integer', description: 'The assistant_message id from the truncated result\'s "_restore" field.' } }, required: %w[message_id] define_method(:name) { 'restore_tool_result' } define_method(:execute) do |message_id:, **_| id = .to_i return { error: 'message_id is required' }.to_json if id.zero? # Conversation-scoped: never a bare AssistantMessage.find, or one # tenant's Sunny could read another conversation's tool output. original = AssistantMessage .where(assistant_conversation_id: captured_conversation_id, id: id) .pick(:compacted_content) if original.blank? { error: "No stored original for message #{id} (never truncated, already expired, or not in this conversation)." }.to_json else Rails.logger.info("[Sunny] tool-result restore hit: msg=#{id} conv=#{captured_conversation_id} chars=#{original.length}") original end rescue StandardError => e Rails.logger.warn("[Sunny] restore_tool_result failed: #{e.class}: #{e.}") { error: "restore failed: #{e.}" }.to_json end end.new end |