lex-llm 0.7.6 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +87 -0
- data/RULES.md +97 -0
- data/lib/legion/extensions/llm/auto_registration.rb +4 -13
- data/lib/legion/extensions/llm/canonical/chunk.rb +106 -92
- data/lib/legion/extensions/llm/canonical/content_block.rb +66 -75
- data/lib/legion/extensions/llm/canonical/message.rb +52 -67
- data/lib/legion/extensions/llm/canonical/params.rb +59 -33
- data/lib/legion/extensions/llm/canonical/request.rb +67 -54
- data/lib/legion/extensions/llm/canonical/response.rb +61 -76
- data/lib/legion/extensions/llm/canonical/strict.rb +105 -0
- data/lib/legion/extensions/llm/canonical/thinking.rb +99 -51
- data/lib/legion/extensions/llm/canonical/tool_call.rb +42 -51
- data/lib/legion/extensions/llm/canonical/tool_definition.rb +56 -46
- data/lib/legion/extensions/llm/canonical/tool_schema.rb +15 -22
- data/lib/legion/extensions/llm/canonical/usage.rb +47 -40
- data/lib/legion/extensions/llm/canonical.rb +6 -5
- data/lib/legion/extensions/llm/configuration.rb +40 -10
- data/lib/legion/extensions/llm/connection.rb +8 -30
- data/lib/legion/extensions/llm/credential_sources.rb +32 -49
- data/lib/legion/extensions/llm/discovery/actor.rb +92 -0
- data/lib/legion/extensions/llm/discovery/pipeline.rb +604 -0
- data/lib/legion/extensions/llm/error.rb +0 -14
- data/lib/legion/extensions/llm/fleet/contract_error.rb +15 -0
- data/lib/legion/extensions/llm/fleet/envelope_validation.rb +7 -6
- data/lib/legion/extensions/llm/fleet/fleet_envelope.rb +66 -0
- data/lib/legion/extensions/llm/fleet/protocol.rb +18 -5
- data/lib/legion/extensions/llm/fleet/provider_responder.rb +58 -156
- data/lib/legion/extensions/llm/fleet/token_validator.rb +15 -21
- data/lib/legion/extensions/llm/fleet/worker_execution.rb +107 -154
- data/lib/legion/extensions/llm/inventory/errors.rb +0 -1
- data/lib/legion/extensions/llm/inventory/evidence.rb +1 -1
- data/lib/legion/extensions/llm/inventory/identity.rb +55 -39
- data/lib/legion/extensions/llm/inventory/probe_token.rb +9 -12
- data/lib/legion/extensions/llm/inventory/publisher.rb +15 -53
- data/lib/legion/extensions/llm/inventory/records.rb +36 -100
- data/lib/legion/extensions/llm/inventory/registry.rb +54 -48
- data/lib/legion/extensions/llm/inventory/snapshot.rb +7 -21
- data/lib/legion/extensions/llm/inventory/weight_reconciler.rb +13 -6
- data/lib/legion/extensions/llm/inventory/weight_schema.rb +47 -8
- data/lib/legion/extensions/llm/provider/open_ai_compatible.rb +172 -182
- data/lib/legion/extensions/llm/provider.rb +192 -315
- data/lib/legion/extensions/llm/provider_contract.rb +25 -8
- data/lib/legion/extensions/llm/provider_settings.rb +5 -26
- data/lib/legion/extensions/llm/responses/thinking_extractor.rb +8 -1
- data/lib/legion/extensions/llm/responses/tool_arguments.rb +34 -0
- data/lib/legion/extensions/llm/routing/provider_outcome.rb +25 -0
- data/lib/legion/extensions/llm/routing/records.rb +34 -17
- data/lib/legion/extensions/llm/stream_accumulator.rb +186 -270
- data/lib/legion/extensions/llm/streaming.rb +50 -35
- data/lib/legion/extensions/llm/taxonomies.rb +14 -26
- data/lib/legion/extensions/llm/transport/fleet_lane.rb +8 -10
- data/lib/legion/extensions/llm/transport/messages/fleet_error.rb +3 -2
- data/lib/legion/extensions/llm/transport/messages/fleet_request.rb +6 -8
- data/lib/legion/extensions/llm/transport/messages/fleet_response.rb +10 -9
- data/lib/legion/extensions/llm/utils.rb +23 -5
- data/lib/legion/extensions/llm/version.rb +1 -1
- data/lib/legion/extensions/llm.rb +8 -98
- data/spec/legion/extensions/llm/auto_registration_spec.rb +4 -9
- data/spec/legion/extensions/llm/canonical/chunk_spec.rb +66 -252
- data/spec/legion/extensions/llm/canonical/content_block_spec.rb +52 -197
- data/spec/legion/extensions/llm/canonical/message_spec.rb +89 -204
- data/spec/legion/extensions/llm/canonical/params_spec.rb +57 -136
- data/spec/legion/extensions/llm/canonical/request_spec.rb +81 -143
- data/spec/legion/extensions/llm/canonical/response_spec.rb +68 -204
- data/spec/legion/extensions/llm/canonical/thinking_spec.rb +68 -148
- data/spec/legion/extensions/llm/canonical/tool_call_spec.rb +59 -162
- data/spec/legion/extensions/llm/canonical/tool_definition_spec.rb +55 -191
- data/spec/legion/extensions/llm/canonical/tool_schema_spec.rb +26 -67
- data/spec/legion/extensions/llm/canonical/usage_spec.rb +46 -155
- data/spec/legion/extensions/llm/configuration_spec.rb +31 -5
- data/spec/legion/extensions/llm/conformance/canonical_type_examples.rb +106 -0
- data/spec/legion/extensions/llm/conformance/conformance.rb +10 -2
- data/spec/legion/extensions/llm/conformance/provider_translator_examples.rb +1 -1
- data/spec/legion/extensions/llm/conformance/ssot_contract_conformance_spec.rb +130 -0
- data/spec/legion/extensions/llm/conformance/ssot_contract_examples.rb +507 -0
- data/spec/legion/extensions/llm/conformance/ssot_provider_examples.rb +11 -10
- data/spec/legion/extensions/llm/credential_sources_spec.rb +12 -13
- data/spec/legion/extensions/llm/error_spec.rb +2 -12
- data/spec/legion/extensions/llm/fleet/exact_offering_spec.rb +59 -45
- data/spec/legion/extensions/llm/fleet/provider_responder_spec.rb +173 -95
- data/spec/legion/extensions/llm/fleet/token_validator_spec.rb +7 -2
- data/spec/legion/extensions/llm/fleet/worker_execution_spec.rb +93 -74
- data/spec/legion/extensions/llm/fleet_messages_spec.rb +118 -123
- data/spec/legion/extensions/llm/inventory/boot_spec.rb +4 -4
- data/spec/legion/extensions/llm/inventory/identity_spec.rb +127 -110
- data/spec/legion/extensions/llm/inventory/probe_token_spec.rb +4 -4
- data/spec/legion/extensions/llm/inventory/publisher_spec.rb +8 -61
- data/spec/legion/extensions/llm/inventory/records_spec.rb +82 -47
- data/spec/legion/extensions/llm/inventory/registry_activation_spec.rb +49 -16
- data/spec/legion/extensions/llm/inventory/registry_replacement_spec.rb +5 -4
- data/spec/legion/extensions/llm/inventory/snapshot_spec.rb +11 -5
- data/spec/legion/extensions/llm/inventory/weight_reconciler_spec.rb +7 -3
- data/spec/legion/extensions/llm/inventory/weight_schema_spec.rb +60 -10
- data/spec/legion/extensions/llm/provider/open_ai_compatible_spec.rb +105 -68
- data/spec/legion/extensions/llm/provider/open_ai_compatible_tool_calls_array_spec.rb +7 -31
- data/spec/legion/extensions/llm/provider_contract_spec.rb +10 -15
- data/spec/legion/extensions/llm/provider_spec.rb +98 -78
- data/spec/legion/extensions/llm/routing/records_spec.rb +38 -5
- data/spec/legion/extensions/llm/stream_accumulator_spec.rb +174 -144
- data/spec/legion/extensions/llm/streaming_spec.rb +27 -0
- data/spec/legion/extensions/llm/taxonomies_spec.rb +43 -43
- data/spec/legion/extensions/llm/transport/fleet_lane_spec.rb +1 -1
- data/spec/legion/extensions/llm/utils_spec.rb +26 -7
- data/spec/legion/extensions/llm_base_contract_spec.rb +55 -90
- data/spec/legion/extensions/llm_extension_spec.rb +5 -5
- data/spec/support/fake_llm_provider.rb +45 -39
- data/spec/support/fake_ssot_harness.rb +7 -2
- metadata +11 -54
- data/lib/legion/extensions/llm/agent.rb +0 -366
- data/lib/legion/extensions/llm/aliases.json +0 -436
- data/lib/legion/extensions/llm/aliases.rb +0 -67
- data/lib/legion/extensions/llm/attachment.rb +0 -229
- data/lib/legion/extensions/llm/chat.rb +0 -354
- data/lib/legion/extensions/llm/chunk.rb +0 -10
- data/lib/legion/extensions/llm/content.rb +0 -81
- data/lib/legion/extensions/llm/context.rb +0 -33
- data/lib/legion/extensions/llm/embedding.rb +0 -33
- data/lib/legion/extensions/llm/image.rb +0 -109
- data/lib/legion/extensions/llm/inventory/capabilities.rb +0 -40
- data/lib/legion/extensions/llm/inventory/scoped_refresher.rb +0 -310
- data/lib/legion/extensions/llm/message.rb +0 -118
- data/lib/legion/extensions/llm/mime_type.rb +0 -75
- data/lib/legion/extensions/llm/model/info.rb +0 -286
- data/lib/legion/extensions/llm/model/modalities.rb +0 -26
- data/lib/legion/extensions/llm/model/pricing.rb +0 -52
- data/lib/legion/extensions/llm/model/pricing_category.rb +0 -50
- data/lib/legion/extensions/llm/model/pricing_tier.rb +0 -37
- data/lib/legion/extensions/llm/model.rb +0 -11
- data/lib/legion/extensions/llm/models.json +0 -57313
- data/lib/legion/extensions/llm/models.rb +0 -530
- data/lib/legion/extensions/llm/models_schema.json +0 -168
- data/lib/legion/extensions/llm/moderation.rb +0 -60
- data/lib/legion/extensions/llm/registry_event_builder.rb +0 -141
- data/lib/legion/extensions/llm/registry_publisher.rb +0 -107
- data/lib/legion/extensions/llm/responses/chat_response.rb +0 -43
- data/lib/legion/extensions/llm/responses/embedding_response.rb +0 -38
- data/lib/legion/extensions/llm/responses/stream_chunk.rb +0 -43
- data/lib/legion/extensions/llm/routing/lane_key.rb +0 -66
- data/lib/legion/extensions/llm/routing/model_offering.rb +0 -241
- data/lib/legion/extensions/llm/routing/offering_registry.rb +0 -101
- data/lib/legion/extensions/llm/routing/registry_event.rb +0 -167
- data/lib/legion/extensions/llm/thinking.rb +0 -53
- data/lib/legion/extensions/llm/tokens.rb +0 -51
- data/lib/legion/extensions/llm/tool_call.rb +0 -34
- data/lib/legion/extensions/llm/transcription.rb +0 -39
- data/lib/legion/extensions/llm/transport/messages/registry_event.rb +0 -44
- data/spec/legion/extensions/llm/agent_spec.rb +0 -179
- data/spec/legion/extensions/llm/attachment_spec.rb +0 -25
- data/spec/legion/extensions/llm/conformance/fixtures/ssot_identity_vectors.json +0 -84
- data/spec/legion/extensions/llm/context_spec.rb +0 -127
- data/spec/legion/extensions/llm/inventory/capabilities_spec.rb +0 -43
- data/spec/legion/extensions/llm/inventory/scoped_refresher_spec.rb +0 -340
- data/spec/legion/extensions/llm/message_spec.rb +0 -64
- data/spec/legion/extensions/llm/model/info_spec.rb +0 -222
- data/spec/legion/extensions/llm/models_spec.rb +0 -104
- data/spec/legion/extensions/llm/registry_event_builder_spec.rb +0 -68
- data/spec/legion/extensions/llm/registry_publisher_spec.rb +0 -22
- data/spec/legion/extensions/llm/responses/response_objects_spec.rb +0 -75
- data/spec/legion/extensions/llm/routing/model_offering_spec.rb +0 -281
- data/spec/legion/extensions/llm/routing/offering_registry_spec.rb +0 -50
- data/spec/legion/extensions/llm/routing/registry_event_spec.rb +0 -120
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Legion
|
|
4
|
-
module Extensions
|
|
5
|
-
module Llm
|
|
6
|
-
module Model
|
|
7
|
-
CAPABILITY_ALIASES = {
|
|
8
|
-
function_calling: :tools,
|
|
9
|
-
functions: :tools,
|
|
10
|
-
tool: :tools,
|
|
11
|
-
tool_use: :tools,
|
|
12
|
-
stream: :streaming,
|
|
13
|
-
stream_chat: :streaming
|
|
14
|
-
}.freeze
|
|
15
|
-
|
|
16
|
-
Info = ::Data.define(
|
|
17
|
-
:id, :name, :provider, :instance, :family,
|
|
18
|
-
:capabilities, :context_length, :parameter_count,
|
|
19
|
-
:parameter_size, :quantization, :size_bytes,
|
|
20
|
-
:modalities_input, :modalities_output, :metadata
|
|
21
|
-
) do
|
|
22
|
-
# rubocop:disable Metrics/ParameterLists
|
|
23
|
-
def initialize(
|
|
24
|
-
id:, name: nil, provider: nil, instance: :default,
|
|
25
|
-
family: nil, capabilities: [], context_length: nil,
|
|
26
|
-
parameter_count: nil, parameter_size: nil, quantization: nil,
|
|
27
|
-
size_bytes: nil, modalities_input: [], modalities_output: [],
|
|
28
|
-
metadata: {}
|
|
29
|
-
)
|
|
30
|
-
normalized_family = family.nil? ? nil : family.to_s.downcase.strip
|
|
31
|
-
|
|
32
|
-
super(
|
|
33
|
-
id: id.to_s.strip,
|
|
34
|
-
name: (name || id).to_s.strip,
|
|
35
|
-
provider: provider.to_s.downcase.to_sym,
|
|
36
|
-
instance: (instance || :default).to_s.downcase.to_sym,
|
|
37
|
-
family: normalized_family,
|
|
38
|
-
capabilities: normalize_capabilities(capabilities),
|
|
39
|
-
context_length: to_int(context_length),
|
|
40
|
-
parameter_count: to_int(parameter_count),
|
|
41
|
-
parameter_size: parameter_size&.to_s&.strip,
|
|
42
|
-
quantization: quantization&.to_s&.strip,
|
|
43
|
-
size_bytes: to_int(size_bytes),
|
|
44
|
-
modalities_input: normalize_symbols(modalities_input),
|
|
45
|
-
modalities_output: normalize_symbols(modalities_output),
|
|
46
|
-
metadata: metadata.is_a?(Hash) ? metadata : {}
|
|
47
|
-
)
|
|
48
|
-
end
|
|
49
|
-
# rubocop:enable Metrics/ParameterLists
|
|
50
|
-
|
|
51
|
-
# ── Capability predicates ─────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
def completion? = capabilities.include?(:completion)
|
|
54
|
-
def embedding? = capabilities.include?(:embedding)
|
|
55
|
-
def vision? = capabilities.include?(:vision)
|
|
56
|
-
def tools? = capabilities.include?(:tools)
|
|
57
|
-
def thinking? = capabilities.include?(:thinking)
|
|
58
|
-
|
|
59
|
-
# Returns true if the model supports prompt caching (Anthropic Claude 4.x, 3.5 Sonnet+).
|
|
60
|
-
# Checks the explicit `prompt_caching` capability flag in the capabilities array.
|
|
61
|
-
def supports_prompt_caching?
|
|
62
|
-
capabilities.include?(:prompt_caching)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def supports?(capability)
|
|
66
|
-
capabilities.include?(capability.to_s.downcase.to_sym)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# ── Backward-compatible accessors ─────────────────────────────
|
|
70
|
-
# These bridge the legacy Model::Info class API used by Models,
|
|
71
|
-
# OpenAICompatible, and provider gems. They read from metadata
|
|
72
|
-
# where the old fields were stored.
|
|
73
|
-
|
|
74
|
-
def context_window
|
|
75
|
-
context_length || metadata[:context_window]
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def max_output_tokens
|
|
79
|
-
metadata[:max_output_tokens]
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def max_tokens
|
|
83
|
-
max_output_tokens
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def created_at
|
|
87
|
-
metadata[:created_at]
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def knowledge_cutoff
|
|
91
|
-
metadata[:knowledge_cutoff]
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def modalities
|
|
95
|
-
Modalities.new(input: modalities_input.map(&:to_s), output: modalities_output.map(&:to_s))
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def pricing
|
|
99
|
-
Pricing.new(metadata[:pricing] || {})
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def display_name
|
|
103
|
-
name
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def label
|
|
107
|
-
"#{provider} - #{display_name}"
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def input_price_per_million
|
|
111
|
-
pricing.text_tokens.input
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def output_price_per_million
|
|
115
|
-
pricing.text_tokens.output
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def supports_vision?
|
|
119
|
-
vision? || modalities_input.include?(:image)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def supports_video?
|
|
123
|
-
modalities_input.include?(:video)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def supports_functions?
|
|
127
|
-
tools? || capabilities.include?(:function_calling)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
# Legacy capability predicates (string-based)
|
|
131
|
-
%w[function_calling structured_output batch reasoning citations streaming prompt_caching].each do |cap|
|
|
132
|
-
define_method "#{cap}?" do
|
|
133
|
-
supports?(cap)
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def type
|
|
138
|
-
output = modalities_output.map(&:to_s)
|
|
139
|
-
return 'embedding' if output.include?('embeddings') || embedding?
|
|
140
|
-
return 'moderation' if output.include?('moderation')
|
|
141
|
-
return 'image' if output.include?('image')
|
|
142
|
-
return 'audio' if output.include?('audio')
|
|
143
|
-
return 'video' if output.include?('video')
|
|
144
|
-
|
|
145
|
-
'chat'
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
# Factory for assumed-to-exist models without full metadata.
|
|
149
|
-
def self.default(model_id, provider)
|
|
150
|
-
new(
|
|
151
|
-
id: model_id,
|
|
152
|
-
name: model_id.tr('-', ' ').capitalize,
|
|
153
|
-
provider: provider,
|
|
154
|
-
capabilities: %w[function_calling streaming vision structured_output],
|
|
155
|
-
modalities_input: %w[text image],
|
|
156
|
-
modalities_output: %w[text],
|
|
157
|
-
metadata: { warning: 'Assuming model exists, capabilities may not be accurate' }
|
|
158
|
-
)
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
# Factory that accepts both legacy and new-style hashes and maps
|
|
162
|
-
# them to the new struct fields. Handles round-tripping through to_h.
|
|
163
|
-
def self.from_hash(data)
|
|
164
|
-
data = data.transform_keys(&:to_sym) if data.is_a?(Hash)
|
|
165
|
-
|
|
166
|
-
input_mods, output_mods = extract_modalities(data)
|
|
167
|
-
|
|
168
|
-
new(
|
|
169
|
-
id: data[:id],
|
|
170
|
-
name: data[:name],
|
|
171
|
-
provider: data[:provider],
|
|
172
|
-
instance: data[:instance],
|
|
173
|
-
family: data[:family],
|
|
174
|
-
capabilities: data[:capabilities] || [],
|
|
175
|
-
context_length: data[:context_length] || data[:context_window],
|
|
176
|
-
parameter_count: data[:parameter_count],
|
|
177
|
-
parameter_size: data[:parameter_size],
|
|
178
|
-
quantization: data[:quantization],
|
|
179
|
-
size_bytes: data[:size_bytes],
|
|
180
|
-
modalities_input: input_mods,
|
|
181
|
-
modalities_output: output_mods,
|
|
182
|
-
metadata: build_metadata(data)
|
|
183
|
-
)
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
private
|
|
187
|
-
|
|
188
|
-
def normalize_capabilities(value)
|
|
189
|
-
raw = Array(value).compact.filter_map do |cap|
|
|
190
|
-
next unless cap.respond_to?(:to_s)
|
|
191
|
-
|
|
192
|
-
sym = cap.to_s.downcase.strip.tr('-', '_').to_sym
|
|
193
|
-
sym unless sym.to_s.empty?
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
(raw + Legion::Extensions::Llm::Capabilities.normalize(raw)).uniq.freeze
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def normalize_symbols(value)
|
|
200
|
-
Array(value).compact.each_with_object([]) do |item, normalized|
|
|
201
|
-
symbol = item.to_s.downcase.strip.to_sym
|
|
202
|
-
next if symbol.to_s.empty?
|
|
203
|
-
|
|
204
|
-
normalized << symbol
|
|
205
|
-
alias_symbol = CAPABILITY_ALIASES[symbol]
|
|
206
|
-
normalized << alias_symbol if alias_symbol
|
|
207
|
-
end.uniq
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def to_int(value)
|
|
211
|
-
return nil if value.nil?
|
|
212
|
-
|
|
213
|
-
value.to_i
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
# Class-level helpers for from_hash normalization
|
|
217
|
-
class << self
|
|
218
|
-
private
|
|
219
|
-
|
|
220
|
-
def extract_modalities(data)
|
|
221
|
-
# New-style keys take priority (round-trip from to_h)
|
|
222
|
-
return [Array(data[:modalities_input]), Array(data[:modalities_output])] if data.key?(:modalities_input) || data.key?(:modalities_output)
|
|
223
|
-
|
|
224
|
-
# Legacy: modalities is a hash or Modalities object
|
|
225
|
-
modalities_data = data[:modalities]
|
|
226
|
-
input_mods = if modalities_data.respond_to?(:input)
|
|
227
|
-
modalities_data.input
|
|
228
|
-
elsif modalities_data.is_a?(Hash)
|
|
229
|
-
Array(modalities_data[:input])
|
|
230
|
-
else
|
|
231
|
-
[]
|
|
232
|
-
end
|
|
233
|
-
output_mods = if modalities_data.respond_to?(:output)
|
|
234
|
-
modalities_data.output
|
|
235
|
-
elsif modalities_data.is_a?(Hash)
|
|
236
|
-
Array(modalities_data[:output])
|
|
237
|
-
else
|
|
238
|
-
[]
|
|
239
|
-
end
|
|
240
|
-
[input_mods, output_mods]
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
def build_metadata(data)
|
|
244
|
-
extra = {}
|
|
245
|
-
extra[:created_at] = normalize_created_at(data[:created_at]) if data.key?(:created_at)
|
|
246
|
-
if data.key?(:knowledge_cutoff)
|
|
247
|
-
extra[:knowledge_cutoff] =
|
|
248
|
-
normalize_knowledge_cutoff(data[:knowledge_cutoff])
|
|
249
|
-
end
|
|
250
|
-
extra[:max_output_tokens] = data[:max_output_tokens] if data.key?(:max_output_tokens)
|
|
251
|
-
extra[:pricing] = normalize_pricing(data[:pricing]) if data.key?(:pricing)
|
|
252
|
-
|
|
253
|
-
base = data[:metadata] || {}
|
|
254
|
-
base.merge(extra).compact
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
def normalize_created_at(value)
|
|
258
|
-
return nil if value.nil?
|
|
259
|
-
return value if value.is_a?(Time)
|
|
260
|
-
|
|
261
|
-
Utils.to_time(value)&.utc
|
|
262
|
-
rescue StandardError
|
|
263
|
-
nil
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
def normalize_knowledge_cutoff(value)
|
|
267
|
-
return nil if value.nil?
|
|
268
|
-
return value if value.is_a?(Date)
|
|
269
|
-
|
|
270
|
-
Utils.to_date(value)
|
|
271
|
-
rescue StandardError
|
|
272
|
-
nil
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def normalize_pricing(value)
|
|
276
|
-
return nil if value.nil?
|
|
277
|
-
return value.to_h if value.respond_to?(:to_h)
|
|
278
|
-
|
|
279
|
-
value
|
|
280
|
-
end
|
|
281
|
-
end
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Legion
|
|
4
|
-
module Extensions
|
|
5
|
-
module Llm
|
|
6
|
-
module Model
|
|
7
|
-
# Holds and manages input and output modalities for a language model
|
|
8
|
-
class Modalities
|
|
9
|
-
attr_reader :input, :output
|
|
10
|
-
|
|
11
|
-
def initialize(data)
|
|
12
|
-
@input = Array(data[:input]).map(&:to_s)
|
|
13
|
-
@output = Array(data[:output]).map(&:to_s)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def to_h
|
|
17
|
-
{
|
|
18
|
-
input: input,
|
|
19
|
-
output: output
|
|
20
|
-
}
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Legion
|
|
4
|
-
module Extensions
|
|
5
|
-
module Llm
|
|
6
|
-
module Model
|
|
7
|
-
# A collection that manages and provides access to different categories of pricing information
|
|
8
|
-
class Pricing
|
|
9
|
-
def initialize(data)
|
|
10
|
-
@data = {}
|
|
11
|
-
|
|
12
|
-
%i[text_tokens images audio_tokens embeddings].each do |category|
|
|
13
|
-
@data[category] = PricingCategory.new(data[category]) if data[category] && !empty_pricing?(data[category])
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def method_missing(method, *args)
|
|
18
|
-
if respond_to_missing?(method)
|
|
19
|
-
@data[method.to_sym] || PricingCategory.new
|
|
20
|
-
else
|
|
21
|
-
super
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def respond_to_missing?(method, include_private = false)
|
|
26
|
-
%i[text_tokens images audio_tokens embeddings].include?(method.to_sym) || super
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def to_h
|
|
30
|
-
@data.transform_values(&:to_h)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
private
|
|
34
|
-
|
|
35
|
-
def empty_pricing?(data)
|
|
36
|
-
return true unless data
|
|
37
|
-
|
|
38
|
-
%i[standard batch].each do |tier|
|
|
39
|
-
next unless data[tier]
|
|
40
|
-
|
|
41
|
-
data[tier].each_value do |value|
|
|
42
|
-
return false if value && value != 0.0
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
true
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Legion
|
|
4
|
-
module Extensions
|
|
5
|
-
module Llm
|
|
6
|
-
module Model
|
|
7
|
-
# Represents pricing tiers for different usage categories (standard and batch)
|
|
8
|
-
class PricingCategory
|
|
9
|
-
attr_reader :standard, :batch
|
|
10
|
-
|
|
11
|
-
def initialize(data = {})
|
|
12
|
-
@standard = PricingTier.new(data[:standard] || {}) unless empty_tier?(data[:standard])
|
|
13
|
-
@batch = PricingTier.new(data[:batch] || {}) unless empty_tier?(data[:batch])
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def input
|
|
17
|
-
standard&.input_per_million
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def output
|
|
21
|
-
standard&.output_per_million
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def cached_input
|
|
25
|
-
standard&.cached_input_per_million
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def [](key)
|
|
29
|
-
key == :batch ? batch : standard
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def to_h
|
|
33
|
-
result = {}
|
|
34
|
-
result[:standard] = standard.to_h if standard
|
|
35
|
-
result[:batch] = batch.to_h if batch
|
|
36
|
-
result
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
private
|
|
40
|
-
|
|
41
|
-
def empty_tier?(tier_data)
|
|
42
|
-
return true unless tier_data
|
|
43
|
-
|
|
44
|
-
tier_data.values.all? { |v| v.nil? || v == 0.0 }
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Legion
|
|
4
|
-
module Extensions
|
|
5
|
-
module Llm
|
|
6
|
-
module Model
|
|
7
|
-
# A dynamic class for storing non-zero pricing values with flexible attribute access
|
|
8
|
-
class PricingTier
|
|
9
|
-
def initialize(data = {})
|
|
10
|
-
@values = {}
|
|
11
|
-
|
|
12
|
-
data.each do |key, value|
|
|
13
|
-
@values[key.to_sym] = value if value && value != 0.0
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def method_missing(method, *args)
|
|
18
|
-
if method.to_s.end_with?('=')
|
|
19
|
-
key = method.to_s.chomp('=').to_sym
|
|
20
|
-
@values[key] = args.first if args.first && args.first != 0.0
|
|
21
|
-
elsif @values.key?(method)
|
|
22
|
-
@values[method]
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def respond_to_missing?(method, include_private = false)
|
|
27
|
-
method.to_s.end_with?('=') || @values.key?(method.to_sym) || super
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def to_h
|
|
31
|
-
@values
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|