Class: Legion::Extensions::Llm::Ollama::Translator
- Inherits:
-
Object
- Object
- Legion::Extensions::Llm::Ollama::Translator
- Includes:
- Logging::Helper
- Defined in:
- lib/legion/extensions/llm/ollama/translator.rb
Overview
Canonical provider translator for Ollama (/api/chat NDJSON wire format).
Implements render_request, parse_response, parse_chunk, and capabilities. Ollama uses NDJSON streaming (not SSE), native tool calling, and the ‘think` flag for extended thinking support.
Ollama quirks (declared in capabilities):
-
tool_calls_as_text: false — Ollama returns structured tool_calls natively.
-
forced_tool_choice: false — Ollama does not support forced tool selection.
-
assistant_prefill: false — Ollama does not support assistant prefill.
Constant Summary collapse
- OLLAMA_STOP_REASON_MAP =
Ollama-specific stop_reason mapping (done_reason field).
{ 'stop' => :end_turn, 'tool_use' => :tool_use, 'length' => :max_tokens }.freeze
- FALLBACK_STOP_REASON =
:end_turn- PARAM_OPTIONS_KEYS =
G18 parameter mapping: canonical params -> Ollama options keys.
{ max_tokens: :num_predict, temperature: :temperature, top_p: :top_p, top_k: :top_k, stop_sequences: :stop, seed: :seed, frequency_penalty: :frequency_penalty, presence_penalty: :presence_penalty }.freeze
- SUPPORTED_PARAMS =
%i[ max_tokens temperature top_p top_k stop_sequences seed frequency_penalty presence_penalty ].freeze
Instance Method Summary collapse
-
#capabilities ⇒ Object
Declared capabilities for the Ollama provider.
-
#initialize(config: nil) ⇒ Translator
constructor
A new instance of Translator.
-
#parse_chunk(raw) ⇒ Object
Parse a single NDJSON chunk into a Canonical::Chunk or nil.
-
#parse_response(wire) ⇒ Object
Parse an Ollama /api/chat completion response into a Canonical::Response.
-
#render_request(request) ⇒ Object
Render a canonical request into Ollama /api/chat wire payload.
Constructor Details
#initialize(config: nil) ⇒ Translator
Returns a new instance of Translator.
50 51 52 |
# File 'lib/legion/extensions/llm/ollama/translator.rb', line 50 def initialize(config: nil) @config = config end |
Instance Method Details
#capabilities ⇒ Object
Declared capabilities for the Ollama provider.
135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/legion/extensions/llm/ollama/translator.rb', line 135 def capabilities { provider: 'ollama', streaming: true, tool_calls: true, thinking: true, vision: true, embeddings: true, tool_calls_as_text: false, forced_tool_choice: false, assistant_prefill: false }.freeze end |
#parse_chunk(raw) ⇒ Object
Parse a single NDJSON chunk into a Canonical::Chunk or nil.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/legion/extensions/llm/ollama/translator.rb', line 119 def parse_chunk(raw) return nil if raw.nil? data = normalize_chunk_input(raw) return nil if data.nil? # Handle canonical-form chunks (from conformance fixtures) return handle_canonical_chunk(data) if data['type'] || data[:type] parse_ollama_chunk(data) rescue StandardError => e handle_exception(e, level: :error, handled: false, operation: 'ollama.translator.parse_chunk') raise end |
#parse_response(wire) ⇒ Object
Parse an Ollama /api/chat completion response into a Canonical::Response.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/legion/extensions/llm/ollama/translator.rb', line 78 def parse_response(wire) return canonical_error_response(wire) unless wire.is_a?(Hash) return Canonical::Response.from_hash(wire) if canonical_response?(wire) = wire[:message] || wire['message'] || {} content = [:content] || ['content'] || '' tool_calls_raw = [:tool_calls] || ['tool_calls'] model = wire[:model] || wire['model'] done_reason = wire[:done_reason] || wire['done_reason'] done = wire[:done] || wire['done'] extraction = Responses::ThinkingExtractor.extract( content, metadata: () ) text = extraction.content || '' thinking = build_canonical_thinking(extraction) tool_calls = parse_tool_calls(tool_calls_raw) stop_reason = map_stop_reason(done_reason, done) usage = Canonical::Usage.from_hash({ input_tokens: wire[:prompt_eval_count] || wire['prompt_eval_count'], output_tokens: wire[:eval_count] || wire['eval_count'] }) Canonical::Response.build( text: text.to_s, thinking: thinking, tool_calls: tool_calls, usage: usage, stop_reason: stop_reason, model: model, metadata: {} ) rescue StandardError => e handle_exception(e, level: :error, handled: false, operation: 'ollama.translator.parse_response') raise end |
#render_request(request) ⇒ Object
Render a canonical request into Ollama /api/chat wire payload.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/legion/extensions/llm/ollama/translator.rb', line 55 def render_request(request) model = request.&.dig(:model) || 'default' = (request) payload = { model: model, messages: , stream: request.stream } payload[:tools] = format_tools(request.tools) unless request.tools.to_h.empty? (payload, request.params) apply_thinking_config(payload, request) apply_response_format(payload, request.params) log.debug do "[llm][ollama-translator] action=render_request model=#{model} stream=#{request.stream} " \ "message_count=#{.size} tools=#{request.tools&.size || 0}" end payload.compact end |