Class: Legion::Extensions::Llm::Openai::Translator

Inherits:
Object
  • Object
show all
Includes:
Logging::Helper
Defined in:
lib/legion/extensions/llm/openai/translator.rb

Overview

Canonical <-> OpenAI wire-format translator.

Implements the provider-boundary contract (Amendment A) so that canonical requests/responses/chunks cross exactly one translation layer per provider. Extracted from OpenAICompatible mixin methods; semantics preserved, not rewritten.

Capabilities (declarative, per the design doc):

- reasoning_effort: true            (gpt-5.x / o-series)
- responses_api: true               (chat/completions wire format)
- thinking_metadata_keys: [...]     (metadata keys for thinking)
- stop_reason_map: { openai -> canonical }

Constant Summary collapse

STOP_REASON_MAP =

OpenAI finish_reason -> canonical stop_reason (G18 stop-reason matrix)

{
  'stop' => :end_turn,
  'tool_calls' => :tool_use,
  'function_call' => :tool_use,
  'length' => :max_tokens,
  'content_filter' => :content_filter
}.freeze
THINKING_METADATA_KEYS =

Metadata keys carrying thinking/reasoning in OpenAI responses

%i[
  reasoning_content reasoning thinking thinking_text
  thinking_signature reasoning_signature
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(api_base: nil, headers: nil) ⇒ Translator

Returns a new instance of Translator.



37
38
39
40
# File 'lib/legion/extensions/llm/openai/translator.rb', line 37

def initialize(api_base: nil, headers: nil)
  @api_base = api_base
  @headers = headers || {}
end

Instance Method Details

#capabilitiesHash

Returns declarative capabilities consumed by routing/dispatch.

Returns:

  • (Hash)

    declarative capabilities consumed by routing/dispatch



43
44
45
46
47
48
49
50
51
# File 'lib/legion/extensions/llm/openai/translator.rb', line 43

def capabilities
  {
    provider: 'openai',
    reasoning_effort: true,
    responses_api: true,
    thinking_metadata_keys: THINKING_METADATA_KEYS,
    stop_reason_map: STOP_REASON_MAP
  }
end

#parse_chunk(raw) ⇒ Canonical::Chunk?

Parameters:

  • raw (Hash)

    single SSE data payload or canonical chunk

Returns:

  • (Canonical::Chunk, nil)


84
85
86
87
88
89
90
91
92
# File 'lib/legion/extensions/llm/openai/translator.rb', line 84

def parse_chunk(raw)
  return nil if raw.nil? || raw.to_h.empty?
  return Canonical::Chunk.from_hash(raw) if canonical_chunk_form?(raw)

  parse_raw_chunk(raw.to_h)
rescue StandardError => e
  handle_exception(e, level: :error, handled: true, operation: 'openai.translator.parse_chunk')
  Canonical::Chunk.error_chunk(error: e.message, request_id: raw.to_h['id'])
end

#parse_response(wire) ⇒ Canonical::Response

Parameters:

  • wire (Hash)

    OpenAI API response body (string-keyed)

Returns:

  • (Canonical::Response)


73
74
75
76
77
78
79
80
# File 'lib/legion/extensions/llm/openai/translator.rb', line 73

def parse_response(wire)
  return Canonical::Response.from_hash(wire) if canonical_form?(wire)

  build_canonical_response(wire.to_h)
rescue StandardError => e
  handle_exception(e, level: :error, handled: true, operation: 'openai.translator.parse_response')
  Canonical::Response.build(text: '', stop_reason: :error, metadata: { error: e.message })
end

#render_request(canonical_request) ⇒ Hash

Returns OpenAI wire-format payload for /v1/chat/completions.

Parameters:

  • canonical_request (Canonical::Request)

Returns:

  • (Hash)

    OpenAI wire-format payload for /v1/chat/completions



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/legion/extensions/llm/openai/translator.rb', line 55

def render_request(canonical_request)
  wire = {
    model: resolve_model(canonical_request),
    messages: render_messages(canonical_request),
    stream: canonical_request.stream
  }.compact

  apply_params(wire, canonical_request.params) if canonical_request.params
  apply_tools(wire, canonical_request) if canonical_request.tools&.any?
  apply_tool_choice(wire, canonical_request.tool_choice) if canonical_request.tool_choice
  apply_thinking(wire, canonical_request)
  use_stream_usage(wire) if canonical_request.stream

  wire
end