Class: OpenRouter::JsonHealer

Inherits:
Object
  • Object
show all
Defined in:
lib/open_router/json_healer.rb

Overview

A dedicated class for extracting, cleaning, and healing malformed JSON responses from language models.

Constant Summary collapse

CODE_BLOCK_JSON_REGEX =

Regex to find a JSON object or array within a markdown code block. It handles optional “json” language identifier. Non-greedy ‘.*?` is key.

/```(?:json)?\s*\n?(.*?)\n?```/m
LOOSE_JSON_REGEX =

Regex to find JSON that isn’t in a code block. Looks for the first ‘or `[` and captures until the matching last `` or `]`. This is a heuristic and might not be perfect for all cases.

/(\{.*\}|\[.*\])/m

Instance Method Summary collapse

Constructor Details

#initialize(client) ⇒ JsonHealer

Returns a new instance of JsonHealer.



18
19
20
21
# File 'lib/open_router/json_healer.rb', line 18

def initialize(client)
  @client = client
  @configuration = client.configuration
end

Instance Method Details

#heal(raw_text, schema, context: :generic) ⇒ Object

Enhanced heal method that supports different healing contexts



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
# File 'lib/open_router/json_healer.rb', line 24

def heal(raw_text, schema, context: :generic)
  candidate_json = extract_json_candidate(raw_text)
  raise StructuredOutputError, "No JSON-like content found in the response." if candidate_json.nil?

  attempts = 0
  max_attempts = @configuration.max_heal_attempts
  original_content = raw_text # Keep track of original for forced extraction context
  all_errors = [] # Track all errors encountered during healing

  loop do
    # Attempt to parse after simple cleanup
    parsed_json = JSON.parse(cleanup_syntax(candidate_json))

    # If parsing succeeds, validate against the schema
    if schema.validation_available? && !schema.validate(parsed_json)
      errors = schema.validation_errors(parsed_json)
      raise SchemaValidationError, "Schema validation failed: #{errors.join(", ")}"
    end

    return parsed_json # Success!
  rescue JSON::ParserError, SchemaValidationError => e
    attempts += 1
    all_errors << e.message

    if attempts > max_attempts
      final_error_message = build_final_error_message(e, schema, candidate_json, max_attempts)
      raise StructuredOutputError, final_error_message
    end

    # Escalate to LLM-based healing with proper context
    candidate_json = fix_with_healer_model(candidate_json, schema, e.message, e.class, original_content, context)
  end
end