Class: Legion::Extensions::Llm::Vertex::Provider
- Inherits:
-
Provider
- Object
- Provider
- Legion::Extensions::Llm::Vertex::Provider
- Defined in:
- lib/legion/extensions/llm/vertex/provider.rb
Overview
Google Cloud Vertex AI provider implementation for the Legion::Extensions::Llm 0.8.0 canonical contract.
The base funnel (chat/stream_chat -> complete) is the single completion path: it enforces Canonical::Message inputs centrally and returns Canonical::Response (sync) or yields Canonical::Chunk (stream). This class owns the Vertex wire dialect only — render_payload renders FROM canonical values; parse_completion_response and build_chunk parse TO canonical types (08 R1-R4). The provider-native offering read path is gone: discover_offerings serves the SSOT registry snapshot (07 C5) and the discovery actor's writer is the sole publication path.
Defined Under Namespace
Modules: Capabilities
Constant Summary collapse
- STATIC_MODELS =
[ { model: 'gemini-2.5-flash', alias: 'gemini-flash', publisher: 'google', model_family: :gemini }, { model: 'gemini-2.5-pro', alias: 'gemini-pro', publisher: 'google', model_family: :gemini }, { model: 'gemini-embedding-001', alias: 'gemini-embedding', publisher: 'google', model_family: :gemini, usage_type: :embedding }, { model: 'text-embedding-005', alias: 'text-embedding', publisher: 'google', model_family: :gemini, usage_type: :embedding }, { model: 'claude-sonnet-4-5', alias: 'claude-sonnet', publisher: 'anthropic', model_family: :anthropic, api: :raw_predict }, { model: 'mistral-medium-3', alias: 'mistral-medium', publisher: 'mistralai', model_family: :mistral, api: :raw_predict }, { model: 'llama-4-maverick', alias: 'llama-4-maverick', publisher: 'meta', model_family: :meta, api: :raw_predict } ].freeze
- ALIASES =
STATIC_MODELS.to_h { |entry| [entry.fetch(:alias), entry.fetch(:model)] }.freeze
- PUBLISHERS =
STATIC_MODELS.to_h { |entry| [entry.fetch(:model), entry.fetch(:publisher)] }.freeze
- API_MODES =
STATIC_MODELS.to_h { |entry| [entry.fetch(:model), entry.fetch(:api, :generate_content)] }.freeze
Class Method Summary collapse
- .capabilities ⇒ Object
- .configuration_options ⇒ Object
- .configuration_requirements ⇒ Object
- .default_tier ⇒ Object
- .default_transport ⇒ Object
- .resolve_model_id(model_id, config: nil) ⇒ Object
- .slug ⇒ Object
Instance Method Summary collapse
- #api_base ⇒ Object
-
#completion_url ⇒ Object
The base funnel posts to these model-scoped endpoints.
- #count_tokens(messages:, model:, params: nil) ⇒ Object
- #count_tokens_url(model:) ⇒ Object
- #default_publisher ⇒ Object
- #embed(text:, model:, dimensions: nil, task_type: nil, title: nil, params: nil, headers: {}) ⇒ Object
- #embedding_url(model:) ⇒ Object
- #generate_content_url(model:) ⇒ Object
- #headers ⇒ Object
- #health(live: false) ⇒ Object
- #list_models(**_filters) ⇒ Object
- #location ⇒ Object
- #models_url ⇒ Object
- #project ⇒ Object
- #raw_predict_url(model:, stream: false) ⇒ Object
- #readiness(live: false) ⇒ Object
- #stream_generate_content_url(model:) ⇒ Object
- #stream_url ⇒ Object
Class Method Details
.capabilities ⇒ Object
61 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 61 def capabilities = Capabilities |
.configuration_options ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 48 def %i[ vertex_project vertex_location vertex_api_base vertex_access_token vertex_credentials vertex_model_aliases vertex_discovery_live ] end |
.configuration_requirements ⇒ Object
60 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 60 def configuration_requirements = [] |
.default_tier ⇒ Object
46 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 46 def default_tier = :cloud |
.default_transport ⇒ Object
45 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 45 def default_transport = :http |
.resolve_model_id(model_id, config: nil) ⇒ Object
63 64 65 66 67 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 63 def resolve_model_id(model_id, config: nil) configured_aliases = config&.vertex_model_aliases aliases = ALIASES.merge((configured_aliases || {}).transform_keys(&:to_s)) aliases.fetch(model_id.to_s, model_id.to_s) end |
.slug ⇒ Object
44 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 44 def slug = 'vertex' |
Instance Method Details
#api_base ⇒ Object
87 88 89 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 87 def api_base config.vertex_api_base || "https://#{location}-aiplatform.googleapis.com/v1" end |
#completion_url ⇒ Object
The base funnel posts to these model-scoped endpoints. render_payload pins @model before the base sync/stream response path resolves them.
103 104 105 106 107 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 103 def completion_url raise ArgumentError, 'model is required for completion_url' if @model.nil? chat_url(@model, stream: false) end |
#count_tokens(messages:, model:, params: nil) ⇒ Object
163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 163 def count_tokens(messages:, model:, params: nil) _ = [params] model_id = model_id(model) unless generate_content_model?(model_id) raise NotImplementedError, "Vertex countTokens for #{model_id} is not standardized" end () payload = { contents: () } response = connection.post(count_tokens_url(model: model_id), payload) response.body['totalTokens'] end |
#count_tokens_url(model:) ⇒ Object
115 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 115 def count_tokens_url(model:) = "#{publisher_model_path(model)}:countTokens" |
#default_publisher ⇒ Object
98 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 98 def default_publisher = 'google' |
#embed(text:, model:, dimensions: nil, task_type: nil, title: nil, params: nil, headers: {}) ⇒ Object
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 176 def (text:, model:, dimensions: nil, task_type: nil, title: nil, params: nil, headers: {}) _ = [params] enforce_model_allowed!(model) model_id = model_id(model) unless Capabilities.(model_id) raise NotImplementedError, "Vertex embedding payload for #{model_id} is not standardized" end instances = Array(text).map { |item| (item, task_type:, title:) } parameters = { outputDimensionality: dimensions }.compact payload = { instances: instances, parameters: parameters } response = connection.post((model: model_id), payload) do |req| req.headers = headers.merge(req.headers) unless headers.empty? end (response, model: model_id, text: text) end |
#embedding_url(model:) ⇒ Object
116 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 116 def (model:) = "#{publisher_model_path(model)}:predict" |
#generate_content_url(model:) ⇒ Object
118 119 120 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 118 def generate_content_url(model:) "#{publisher_model_path(model)}:generateContent" end |
#headers ⇒ Object
91 92 93 94 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 91 def headers identity_headers.merge({ 'Authorization' => bearer_token, 'Content-Type' => 'application/json; charset=utf-8' }.compact) end |
#health(live: false) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 138 def health(live: false) log.info { "checking health live=#{live} project=#{project} location=#{location}" } baseline = { provider: :vertex, project: project, location: location, configured: configured?, ready: configured?, live: live, credentials: credential_source } return baseline.merge(checked: false) unless live connection.get(models_url) baseline.merge(checked: true) rescue StandardError => e handle_exception(e, level: :warn, handled: true, operation: 'vertex.provider.health') baseline.merge(checked: true, ready: false, error: e.class.name, message: e.) end |
#list_models(**_filters) ⇒ Object
131 132 133 134 135 136 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 131 def list_models(**_filters) log.info { 'listing available Vertex models from static catalog' } STATIC_MODELS.map { |entry| entry[:model] }.tap do |models| log.info { "listed #{models.size} Vertex model(s)" } end end |
#location ⇒ Object
97 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 97 def location = config.vertex_location |
#models_url ⇒ Object
99 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 99 def models_url = publisher_parent |
#project ⇒ Object
96 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 96 def project = config.vertex_project || ENV.fetch('GOOGLE_CLOUD_PROJECT', nil) |
#raw_predict_url(model:, stream: false) ⇒ Object
126 127 128 129 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 126 def raw_predict_url(model:, stream: false) suffix = stream ? 'streamRawPredict' : 'rawPredict' "#{publisher_model_path(model)}:#{suffix}" end |
#readiness(live: false) ⇒ Object
158 159 160 161 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 158 def readiness(live: false) health(live:).merge(local: false, remote: true, api_base: api_base, endpoints: endpoint_manifest) end |
#stream_generate_content_url(model:) ⇒ Object
122 123 124 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 122 def stream_generate_content_url(model:) "#{publisher_model_path(model)}:streamGenerateContent?alt=sse" end |
#stream_url ⇒ Object
109 110 111 112 113 |
# File 'lib/legion/extensions/llm/vertex/provider.rb', line 109 def stream_url raise ArgumentError, 'model is required for stream_url' if @model.nil? chat_url(@model, stream: true) end |