From 46704cf5803f349193e0538a0ce4c41dc5b8a7fe Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Thu, 27 Nov 2025 19:06:27 +0300 Subject: [PATCH 01/11] Add support for multimodal embedding --- lib/ruby_llm/embedding.rb | 4 +- lib/ruby_llm/provider.rb | 4 +- lib/ruby_llm/providers/vertexai/embeddings.rb | 68 ++++++- .../providers/vertex_ai/embeddings_spec.rb | 178 ++++++++++++++++++ 4 files changed, 247 insertions(+), 7 deletions(-) create mode 100644 spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb diff --git a/lib/ruby_llm/embedding.rb b/lib/ruby_llm/embedding.rb index 159620f83..3d70193d7 100644 --- a/lib/ruby_llm/embedding.rb +++ b/lib/ruby_llm/embedding.rb @@ -12,6 +12,8 @@ def initialize(vectors:, model:, input_tokens: 0) end def self.embed(text, # rubocop:disable Metrics/ParameterLists + image: nil, + video: nil, model: nil, provider: nil, assume_model_exists: false, @@ -23,7 +25,7 @@ def self.embed(text, # rubocop:disable Metrics/ParameterLists config: config) model_id = model.id - provider_instance.embed(text, model: model_id, dimensions:) + provider_instance.embed(text, image:, video:, model: model_id, dimensions:) end end end diff --git a/lib/ruby_llm/provider.rb b/lib/ruby_llm/provider.rb index 2fdb3ca11..25df62fcb 100644 --- a/lib/ruby_llm/provider.rb +++ b/lib/ruby_llm/provider.rb @@ -64,8 +64,8 @@ def list_models parse_list_models_response response, slug, capabilities end - def embed(text, model:, dimensions:) - payload = render_embedding_payload(text, model:, dimensions:) + def embed(text, model:, image:, video:, dimensions:) + payload = render_embedding_payload(text, model:, image:, video:, dimensions:) response = @connection.post(embedding_url(model:), payload) parse_embedding_response(response, model:, text:) end diff --git a/lib/ruby_llm/providers/vertexai/embeddings.rb b/lib/ruby_llm/providers/vertexai/embeddings.rb index 7dc974546..36cda6503 100644 --- a/lib/ruby_llm/providers/vertexai/embeddings.rb +++ b/lib/ruby_llm/providers/vertexai/embeddings.rb @@ -11,21 +11,81 @@ def embedding_url(model:) "projects/#{@config.vertexai_project_id}/locations/#{@config.vertexai_location}/publishers/google/models/#{model}:predict" # rubocop:disable Layout/LineLength end - def render_embedding_payload(text, model:, dimensions:) # rubocop:disable Lint/UnusedMethodArgument + def render_embedding_payload(text, model:, image: nil, video: nil, dimensions: nil) # rubocop:disable Lint/UnusedMethodArgument + # Edited here, changed content to text **** + is_multimodal = image.present? || video.present? + + if is_multimodal + render_multimodal_payload(text, image: image, video: video, dimensions: dimensions) + else + { + instances: [text].flatten.map { |t| { text: t.to_s } } + }.tap do |payload| + payload[:parameters] = { outputDimensionality: dimensions } if dimensions + end + end + end + + def render_multimodal_payload(text, image:, video:, dimensions:) + instance = {} + instance[:text] = text.to_s if text + add_image_instance(instance, image: image) + add_video_instance(instance, video: video) + { - instances: [text].flatten.map { |t| { content: t.to_s } } + instances: [instance] }.tap do |payload| payload[:parameters] = { outputDimensionality: dimensions } if dimensions end end + def add_image_instance(instance, image:) + return unless image.present? + + require 'base64' + image_data = image.respond_to?(:read) ? image.read : image + instance[:image] = { bytesBase64Encoded: Base64.strict_encode64(image_data) } + end + + def add_video_instance(instance, video:) + return unless video.present? + + require 'base64' + if video.is_a?(String) && video.start_with?('gs://') + # GCS URI + instance[:video] = { gcsUri: video } + else + # Base64 encoded video + video_data = video.respond_to?(:read) ? video.read : video + instance[:video] = { bytesBase64Encoded: Base64.strict_encode64(video_data) } + end + end + def parse_embedding_response(response, model:, text:) predictions = response.body['predictions'] - vectors = predictions&.map { |p| p.dig('embeddings', 'values') } - vectors = vectors.first if vectors&.length == 1 && !text.is_a?(Array) + # Edited here to support multi-modal embeddings **** + + if model == 'multimodalembedding' + vectors = parse_multimodal_embeddings(predictions) + else + vectors = predictions&.map { |p| p.dig('embeddings', 'values') } + vectors = vectors.first if vectors&.length == 1 && !text.is_a?(Array) + end Embedding.new(vectors:, model:, input_tokens: 0) end + + def parse_multimodal_embeddings(predictions) + text_embedding = predictions&.dig(0, 'textEmbedding') + image_embedding = predictions&.dig(0, 'imageEmbedding') + video_embedding = predictions&.dig(0, 'videoEmbedding') + + vectors = {} + vectors[:text] = text_embedding if text_embedding + vectors[:image] = image_embedding if image_embedding + vectors[:video] = video_embedding if video_embedding + vectors + end end end end diff --git a/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb new file mode 100644 index 000000000..f3094dd70 --- /dev/null +++ b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb @@ -0,0 +1,178 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe RubyLLM::Providers::VertexAI::Embeddings do + let(:test_class) do + Class.new do + include RubyLLM::Providers::VertexAI::Embeddings + + attr_reader :config + + def initialize(config) + @config = config + end + end + end + + let(:config) do + double( # rubocop:disable RSpec/VerifiedDoubles + 'config', + vertexai_project_id: 'test-project', + vertexai_location: 'us-central1' + ) + end + + let(:embeddings) { + test_class.new(config) + } + + describe '#embedding_url' do + it 'constructs the correct URL' do + url = embeddings.send(:embedding_url, model: 'multimodalembedding') + expect(url).to eq( + 'projects/test-project/locations/us-central1/publishers/google/models/multimodalembedding:predict' + ) + end + end + + describe '#render_embedding_payload' do + context 'with text only' do + it 'renders single text payload with a text embedding model' do + payload = embeddings.send(:render_embedding_payload, 'Hello!', model: 'gemini-embedding-001') + expect(payload[:instances]).to eq([{ text: 'Hello!' }]) + end + + it 'renders single text payload with a multimodal embedding model' do + payload = embeddings.send(:render_embedding_payload, 'Hello!', model: 'multimodalembedding') + expect(payload[:instances]).to eq([{ text: 'Hello!' }]) + end + + it 'renders multiple batch text payloads' do + payload = embeddings.send(:render_embedding_payload, ['Hello!', 'Hi there!'], model: 'text-embedding-005') + expect(payload[:instances]).to eq([{ text: 'Hello!' }, { text: 'Hi there!' }]) + end + end + + context 'with multimodal content payload' do + it 'renders payload with multimodal content' do + image_data = 'fake_image_data' + video_data = 'fake_video_data' + + payload = embeddings.send( + :render_embedding_payload, + 'Test multimodal input', + model: 'multimodalembedding', + image: image_data, + video: video_data + ) + expect(payload[:instances].first[:text]).to eq('Test multimodal input') + expect(payload[:instances].first).to have_key(:image) + expect(payload[:instances].first).to have_key(:video) + end + + it 'renders payload wtih dimensions parameter' do + payload = embeddings.send( + :render_embedding_payload, + 'Hello!', + model: 'multimodalembedding', + dimensions: 512 + ) + expect(payload[:parameters]).to eq({ outputDimensionality: 512 }) + end + end + end + + describe '#parse_embedding_response' do + context 'with text only embeddings' do + it 'parses text only embedding response' do + embedding_response = instance_double( + Faraday::Response, body: { + 'predictions' => [ + 'embeddings' => { + 'statistics' => { + 'truncated' => false, + 'token_count' => 6 + }, + 'values' => ['...'] + } + ] + } + ) + embedding = embeddings.send( + :parse_embedding_response, + embedding_response, + model: 'gemini-embedding-001', + text: 'Hello!' + ) + expect(embedding.vectors).to eq(['...']) + expect(embedding.model).to eq('gemini-embedding-001') + end + + it 'parses batch text embedding response' do + embedding_response = instance_double( + Faraday::Response, body: { + 'predictions' => [ + { + 'embeddings' => { + 'statistics' => { + 'token_count' => 8, + 'truncated' => false + }, + 'values' => ['0.1,....'] + } + }, + { + 'embeddings' => { + 'statistics' => { + 'token_count' => 3, + 'truncated' => false + }, + 'values' => ['0.2,....'] + } + } + ] + } + ) + embedding = embeddings.send( + :parse_embedding_response, + embedding_response, + model: 'text-embedding-004', + text: ['Hello!', 'Hi there!'] + ) + expect(embedding.vectors).to eq([['0.1,....'], ['0.2,....']]) + expect(embedding.model).to eq('text-embedding-004') + end + end + + context 'with multimodal embeddings' do + it 'parses multimodal embedding response' do + embedding_response = instance_double( + Faraday::Response, body: { + 'predictions' => [ + { + 'textEmbedding' => ['0.1,....'], + 'imageEmbedding' => ['0.2,....'], + 'videoEmbedding' => ['0.3,....'] + } + ] + } + ) + embedding = embeddings.send( + :parse_embedding_response, + embedding_response, + model: 'multimodalembedding', + text: 'Multimodal input' + ) + expect(embedding.vectors).to eq( + { + text: ['0.1,....'], + image: ['0.2,....'], + video: ['0.3,....'] + } + ) + expect(embedding.model).to eq('multimodalembedding') + end + end + end +end From 1df5fe5cba575f5bd3b167011eb7d74efdae6fa9 Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Tue, 2 Dec 2025 18:25:34 +0300 Subject: [PATCH 02/11] Remove brackets --- spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb index f3094dd70..b26204fcb 100644 --- a/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb +++ b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb @@ -23,9 +23,9 @@ def initialize(config) ) end - let(:embeddings) { + let(:embeddings) do test_class.new(config) - } + end describe '#embedding_url' do it 'constructs the correct URL' do From ffe5c2a387e6c1936a30a9f6f5b6603cf835664f Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Fri, 5 Dec 2025 18:14:25 +0300 Subject: [PATCH 03/11] Enable embeddings with and without text --- lib/ruby_llm/embedding.rb | 31 ++++++++++++++++--- lib/ruby_llm/provider.rb | 8 +++-- lib/ruby_llm/providers/vertexai/embeddings.rb | 4 +-- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/lib/ruby_llm/embedding.rb b/lib/ruby_llm/embedding.rb index 3d70193d7..e9a48ee70 100644 --- a/lib/ruby_llm/embedding.rb +++ b/lib/ruby_llm/embedding.rb @@ -11,11 +11,11 @@ def initialize(vectors:, model:, input_tokens: 0) @input_tokens = input_tokens end - def self.embed(text, # rubocop:disable Metrics/ParameterLists - image: nil, - video: nil, + def self.embed(text = nil, # rubocop:disable Metrics/ParameterLists model: nil, provider: nil, + image: nil, + video: nil, assume_model_exists: false, context: nil, dimensions: nil) @@ -24,8 +24,31 @@ def self.embed(text, # rubocop:disable Metrics/ParameterLists model, provider_instance = Models.resolve(model, provider: provider, assume_exists: assume_model_exists, config: config) model_id = model.id + args = set_embedding_params( + provider_instance, + text: text, + model_id: model_id, + dimensions: dimensions, + image: image, + video: video + ) + + provider_instance.embed(**args) + end - provider_instance.embed(text, image:, video:, model: model_id, dimensions:) + def self.set_embedding_params(provider_instance, # rubocop:disable Metrics/ParameterLists + text: nil, + model_id: nil, + dimensions: nil, + image: nil, + video: nil) + embed_params = provider_instance.method(:embed).parameters.map(&:last) + args = { model: model_id } + args[:text] = text if text + args[:dimensions] = dimensions if dimensions + args[:image] = image if image && embed_params.include?(:image) + args[:video] = video if video && embed_params.include?(:video) + args end end end diff --git a/lib/ruby_llm/provider.rb b/lib/ruby_llm/provider.rb index 25df62fcb..96ce86f83 100644 --- a/lib/ruby_llm/provider.rb +++ b/lib/ruby_llm/provider.rb @@ -64,8 +64,12 @@ def list_models parse_list_models_response response, slug, capabilities end - def embed(text, model:, image:, video:, dimensions:) - payload = render_embedding_payload(text, model:, image:, video:, dimensions:) + def embed(model:, text: nil, image: nil, video: nil, dimensions: nil) + payload = if image || video + render_embedding_payload(text, model:, image:, video:, dimensions:) + else + render_embedding_payload(text, model:, dimensions:) + end response = @connection.post(embedding_url(model:), payload) parse_embedding_response(response, model:, text:) end diff --git a/lib/ruby_llm/providers/vertexai/embeddings.rb b/lib/ruby_llm/providers/vertexai/embeddings.rb index 36cda6503..6270493ee 100644 --- a/lib/ruby_llm/providers/vertexai/embeddings.rb +++ b/lib/ruby_llm/providers/vertexai/embeddings.rb @@ -16,7 +16,7 @@ def render_embedding_payload(text, model:, image: nil, video: nil, dimensions: n is_multimodal = image.present? || video.present? if is_multimodal - render_multimodal_payload(text, image: image, video: video, dimensions: dimensions) + render_multimodal_payload(text:, image:, video:, dimensions:) else { instances: [text].flatten.map { |t| { text: t.to_s } } @@ -26,7 +26,7 @@ def render_embedding_payload(text, model:, image: nil, video: nil, dimensions: n end end - def render_multimodal_payload(text, image:, video:, dimensions:) + def render_multimodal_payload(text:, image:, video:, dimensions:) instance = {} instance[:text] = text.to_s if text add_image_instance(instance, image: image) From 8ce3654f539276c046fbd5730dc598812a9aaa0f Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Fri, 5 Dec 2025 18:16:17 +0300 Subject: [PATCH 04/11] Clean up comments --- lib/ruby_llm/providers/vertexai/embeddings.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/ruby_llm/providers/vertexai/embeddings.rb b/lib/ruby_llm/providers/vertexai/embeddings.rb index 6270493ee..64101c117 100644 --- a/lib/ruby_llm/providers/vertexai/embeddings.rb +++ b/lib/ruby_llm/providers/vertexai/embeddings.rb @@ -12,7 +12,6 @@ def embedding_url(model:) end def render_embedding_payload(text, model:, image: nil, video: nil, dimensions: nil) # rubocop:disable Lint/UnusedMethodArgument - # Edited here, changed content to text **** is_multimodal = image.present? || video.present? if is_multimodal @@ -52,10 +51,8 @@ def add_video_instance(instance, video:) require 'base64' if video.is_a?(String) && video.start_with?('gs://') - # GCS URI instance[:video] = { gcsUri: video } else - # Base64 encoded video video_data = video.respond_to?(:read) ? video.read : video instance[:video] = { bytesBase64Encoded: Base64.strict_encode64(video_data) } end @@ -64,8 +61,6 @@ def add_video_instance(instance, video:) def parse_embedding_response(response, model:, text:) predictions = response.body['predictions'] - # Edited here to support multi-modal embeddings **** - if model == 'multimodalembedding' vectors = parse_multimodal_embeddings(predictions) else From da901df3d0547831cf8a7e3b48ec7791e7e7a6b8 Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Wed, 14 Jan 2026 10:36:25 +0300 Subject: [PATCH 05/11] Fix dimensions parameter for VertexAI embeddings From 9297de7a4eb02ca3224675f542d387813fe5fea2 Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Wed, 14 Jan 2026 11:07:05 +0300 Subject: [PATCH 06/11] Fix dimension argument to allow embedding of any size --- lib/ruby_llm/providers/vertexai/embeddings.rb | 4 ++-- spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ruby_llm/providers/vertexai/embeddings.rb b/lib/ruby_llm/providers/vertexai/embeddings.rb index 64101c117..50c472ed0 100644 --- a/lib/ruby_llm/providers/vertexai/embeddings.rb +++ b/lib/ruby_llm/providers/vertexai/embeddings.rb @@ -20,7 +20,7 @@ def render_embedding_payload(text, model:, image: nil, video: nil, dimensions: n { instances: [text].flatten.map { |t| { text: t.to_s } } }.tap do |payload| - payload[:parameters] = { outputDimensionality: dimensions } if dimensions + payload[:parameters] = { dimension: dimensions } if dimensions end end end @@ -34,7 +34,7 @@ def render_multimodal_payload(text:, image:, video:, dimensions:) { instances: [instance] }.tap do |payload| - payload[:parameters] = { outputDimensionality: dimensions } if dimensions + payload[:parameters] = { dimension: dimensions } if dimensions end end diff --git a/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb index b26204fcb..d8f176f7c 100644 --- a/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb +++ b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb @@ -78,7 +78,7 @@ def initialize(config) model: 'multimodalembedding', dimensions: 512 ) - expect(payload[:parameters]).to eq({ outputDimensionality: 512 }) + expect(payload[:parameters]).to eq({ dimension: 512 }) end end end From 979b176d4868c9d24d9184134e2bb20cfbad33a0 Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Tue, 27 Jan 2026 12:00:50 +0300 Subject: [PATCH 07/11] Add the multimodalembedding model by VertexAI --- lib/ruby_llm/models.json | 1297 ++++++++--------- .../providers/vertexai/capabilities.rb | 190 +++ lib/ruby_llm/providers/vertexai/models.rb | 16 +- 3 files changed, 829 insertions(+), 674 deletions(-) create mode 100644 lib/ruby_llm/providers/vertexai/capabilities.rb diff --git a/lib/ruby_llm/models.json b/lib/ruby_llm/models.json index 2ae165391..b49b1d432 100644 --- a/lib/ruby_llm/models.json +++ b/lib/ruby_llm/models.json @@ -4,7 +4,7 @@ "name": "Claude Haiku 3.5", "provider": "anthropic", "family": "claude-haiku", - "created_at": "2024-10-22 00:00:00 +0200", + "created_at": "2024-10-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": "2024-07-31", @@ -58,7 +58,7 @@ "name": "Claude Haiku 3.5 (latest)", "provider": "anthropic", "family": "claude-haiku", - "created_at": "2024-10-22 00:00:00 +0200", + "created_at": "2024-10-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": "2024-07-31", @@ -110,7 +110,7 @@ "name": "Claude Sonnet 3.5", "provider": "anthropic", "family": "claude-sonnet", - "created_at": "2024-06-20 00:00:00 +0200", + "created_at": "2024-06-20 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": "2024-04-30", @@ -162,7 +162,7 @@ "name": "Claude Sonnet 3.5 v2", "provider": "anthropic", "family": "claude-sonnet", - "created_at": "2024-10-22 00:00:00 +0200", + "created_at": "2024-10-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": "2024-04-30", @@ -214,7 +214,7 @@ "name": "Claude Sonnet 3.7", "provider": "anthropic", "family": "claude-sonnet", - "created_at": "2025-02-19 00:00:00 +0100", + "created_at": "2025-02-19 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2024-10-31", @@ -270,7 +270,7 @@ "name": "Claude Sonnet 3.7 (latest)", "provider": "anthropic", "family": "claude-sonnet", - "created_at": "2025-02-19 00:00:00 +0100", + "created_at": "2025-02-19 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2024-10-31", @@ -323,7 +323,7 @@ "name": "Claude Haiku 3", "provider": "anthropic", "family": "claude-haiku", - "created_at": "2024-03-13 00:00:00 +0100", + "created_at": "2024-03-13 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": "2023-08-31", @@ -377,7 +377,7 @@ "name": "Claude Opus 3", "provider": "anthropic", "family": "claude-opus", - "created_at": "2024-02-29 00:00:00 +0100", + "created_at": "2024-02-29 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": "2023-08-31", @@ -429,7 +429,7 @@ "name": "Claude Sonnet 3", "provider": "anthropic", "family": "claude-sonnet", - "created_at": "2024-03-04 00:00:00 +0100", + "created_at": "2024-03-04 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": "2023-08-31", @@ -481,7 +481,7 @@ "name": "Claude Haiku 4.5 (latest)", "provider": "anthropic", "family": "claude-haiku", - "created_at": "2025-10-15 00:00:00 +0200", + "created_at": "2025-10-15 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-02-28", @@ -534,7 +534,7 @@ "name": "Claude Haiku 4.5", "provider": "anthropic", "family": "claude-haiku", - "created_at": "2025-10-15 00:00:00 +0200", + "created_at": "2025-10-15 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-02-28", @@ -588,7 +588,7 @@ "name": "Claude Opus 4 (latest)", "provider": "anthropic", "family": "claude-opus", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": "2025-03-31", @@ -641,7 +641,7 @@ "name": "Claude Opus 4.1 (latest)", "provider": "anthropic", "family": "claude-opus", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": "2025-03-31", @@ -694,7 +694,7 @@ "name": "Claude Opus 4.1", "provider": "anthropic", "family": "claude-opus", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": "2025-03-31", @@ -748,7 +748,7 @@ "name": "Claude Opus 4", "provider": "anthropic", "family": "claude-opus", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": "2025-03-31", @@ -802,7 +802,7 @@ "name": "Claude Opus 4.5 (latest)", "provider": "anthropic", "family": "claude-opus", - "created_at": "2025-11-24 00:00:00 +0100", + "created_at": "2025-11-24 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-03-31", @@ -855,7 +855,7 @@ "name": "Claude Opus 4.5", "provider": "anthropic", "family": "claude-opus", - "created_at": "2025-11-01 00:00:00 +0100", + "created_at": "2025-11-01 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-03-31", @@ -909,7 +909,7 @@ "name": "Claude Sonnet 4 (latest)", "provider": "anthropic", "family": "claude-sonnet", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-03-31", @@ -962,7 +962,7 @@ "name": "Claude Sonnet 4", "provider": "anthropic", "family": "claude-sonnet", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-03-31", @@ -1016,7 +1016,7 @@ "name": "Claude Sonnet 4.5 (latest)", "provider": "anthropic", "family": "claude-sonnet", - "created_at": "2025-09-29 00:00:00 +0200", + "created_at": "2025-09-29 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-07-31", @@ -1069,7 +1069,7 @@ "name": "Claude Sonnet 4.5", "provider": "anthropic", "family": "claude-sonnet", - "created_at": "2025-09-29 00:00:00 +0200", + "created_at": "2025-09-29 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-07-31", @@ -1123,7 +1123,7 @@ "name": "Jamba 1.5 Large", "provider": "bedrock", "family": "jamba", - "created_at": "2024-08-15 00:00:00 +0200", + "created_at": "2024-08-15 00:00:00 +0300", "context_window": 256000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -1169,7 +1169,7 @@ "name": "Jamba 1.5 Mini", "provider": "bedrock", "family": "jamba", - "created_at": "2024-08-15 00:00:00 +0200", + "created_at": "2024-08-15 00:00:00 +0300", "context_window": 256000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -1215,7 +1215,7 @@ "name": "Nova 2 Lite", "provider": "bedrock", "family": "nova", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -1263,7 +1263,7 @@ "name": "Nova Lite", "provider": "bedrock", "family": "nova-lite", - "created_at": "2024-12-03 00:00:00 +0100", + "created_at": "2024-12-03 00:00:00 +0300", "context_window": 300000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -1314,7 +1314,7 @@ "name": "Nova Micro", "provider": "bedrock", "family": "nova-micro", - "created_at": "2024-12-03 00:00:00 +0100", + "created_at": "2024-12-03 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -1362,7 +1362,7 @@ "name": "Nova Premier", "provider": "bedrock", "family": "nova", - "created_at": "2024-12-03 00:00:00 +0100", + "created_at": "2024-12-03 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -1412,7 +1412,7 @@ "name": "Nova Pro", "provider": "bedrock", "family": "nova-pro", - "created_at": "2024-12-03 00:00:00 +0100", + "created_at": "2024-12-03 00:00:00 +0300", "context_window": 300000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -1463,7 +1463,7 @@ "name": "Titan Text G1 - Express", "provider": "bedrock", "family": "titan", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -1508,7 +1508,7 @@ "name": "Titan Text G1 - Express", "provider": "bedrock", "family": "titan", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -1553,7 +1553,7 @@ "name": "Claude Haiku 3.5", "provider": "bedrock", "family": "claude-haiku", - "created_at": "2024-10-22 00:00:00 +0200", + "created_at": "2024-10-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -1617,7 +1617,7 @@ "name": "Claude Sonnet 3.5", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-06-20 00:00:00 +0200", + "created_at": "2024-06-20 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -1683,7 +1683,7 @@ "name": "Claude Sonnet 3.5", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-06-20 00:00:00 +0200", + "created_at": "2024-06-20 00:00:00 +0300", "context_window": 18000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -1748,7 +1748,7 @@ "name": "Claude Sonnet 3.5", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-06-20 00:00:00 +0200", + "created_at": "2024-06-20 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -1813,7 +1813,7 @@ "name": "Claude Sonnet 3.5", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-06-20 00:00:00 +0200", + "created_at": "2024-06-20 00:00:00 +0300", "context_window": 51000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -1878,7 +1878,7 @@ "name": "Claude Sonnet 3.5 v2", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-10-22 00:00:00 +0200", + "created_at": "2024-10-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -1943,7 +1943,7 @@ "name": "Claude Sonnet 3.5 v2", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-10-22 00:00:00 +0200", + "created_at": "2024-10-22 00:00:00 +0300", "context_window": 18000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -2008,7 +2008,7 @@ "name": "Claude Sonnet 3.5 v2", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-10-22 00:00:00 +0200", + "created_at": "2024-10-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -2073,7 +2073,7 @@ "name": "Claude Sonnet 3.5 v2", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-10-22 00:00:00 +0200", + "created_at": "2024-10-22 00:00:00 +0300", "context_window": 51000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -2138,7 +2138,7 @@ "name": "Claude Sonnet 3.7", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2025-02-19 00:00:00 +0100", + "created_at": "2025-02-19 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -2190,7 +2190,7 @@ "name": "Claude Haiku 3", "provider": "bedrock", "family": "claude-haiku", - "created_at": "2024-03-13 00:00:00 +0100", + "created_at": "2024-03-13 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2252,7 +2252,7 @@ "name": "Claude Haiku 3", "provider": "bedrock", "family": "claude-haiku", - "created_at": "2024-03-13 00:00:00 +0100", + "created_at": "2024-03-13 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2314,7 +2314,7 @@ "name": "Claude Haiku 3", "provider": "bedrock", "family": "claude-haiku", - "created_at": "2024-03-13 00:00:00 +0100", + "created_at": "2024-03-13 00:00:00 +0300", "context_window": 48000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2376,7 +2376,7 @@ "name": "Claude Opus 3", "provider": "bedrock", "family": "claude-opus", - "created_at": "2024-02-29 00:00:00 +0100", + "created_at": "2024-02-29 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2438,7 +2438,7 @@ "name": "Claude Opus 3", "provider": "bedrock", "family": "claude-opus", - "created_at": "2024-02-29 00:00:00 +0100", + "created_at": "2024-02-29 00:00:00 +0300", "context_window": 12000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2498,7 +2498,7 @@ "name": "Claude Opus 3", "provider": "bedrock", "family": "claude-opus", - "created_at": "2024-02-29 00:00:00 +0100", + "created_at": "2024-02-29 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2558,7 +2558,7 @@ "name": "Claude Opus 3", "provider": "bedrock", "family": "claude-opus", - "created_at": "2024-02-29 00:00:00 +0100", + "created_at": "2024-02-29 00:00:00 +0300", "context_window": 28000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2618,7 +2618,7 @@ "name": "Claude Sonnet 3", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-03-04 00:00:00 +0100", + "created_at": "2024-03-04 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2680,7 +2680,7 @@ "name": "Claude Sonnet 3", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-03-04 00:00:00 +0100", + "created_at": "2024-03-04 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2742,7 +2742,7 @@ "name": "Claude Sonnet 3", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2024-03-04 00:00:00 +0100", + "created_at": "2024-03-04 00:00:00 +0300", "context_window": 28000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2804,7 +2804,7 @@ "name": "Claude Haiku 4.5", "provider": "bedrock", "family": "claude-haiku", - "created_at": "2025-10-15 00:00:00 +0200", + "created_at": "2025-10-15 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-02-28", @@ -2857,7 +2857,7 @@ "name": "Claude Instant", "provider": "bedrock", "family": "claude", - "created_at": "2023-03-01 00:00:00 +0100", + "created_at": "2023-03-01 00:00:00 +0300", "context_window": 100000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -2950,7 +2950,7 @@ "name": "Claude Opus 4.1", "provider": "bedrock", "family": "claude-opus", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": "2025-03-31", @@ -3003,7 +3003,7 @@ "name": "Claude Opus 4", "provider": "bedrock", "family": "claude-opus", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": null, @@ -3056,7 +3056,7 @@ "name": "Claude Opus 4.5", "provider": "bedrock", "family": "claude-opus", - "created_at": "2025-11-24 00:00:00 +0100", + "created_at": "2025-11-24 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-03-31", @@ -3109,7 +3109,7 @@ "name": "Claude Sonnet 4", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": null, @@ -3162,7 +3162,7 @@ "name": "Claude Sonnet 4.5", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2025-09-29 00:00:00 +0200", + "created_at": "2025-09-29 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-07-31", @@ -3215,7 +3215,7 @@ "name": "Claude 2", "provider": "bedrock", "family": "claude", - "created_at": "2023-07-11 00:00:00 +0200", + "created_at": "2023-07-11 00:00:00 +0300", "context_window": 100000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -3357,7 +3357,7 @@ "name": "Claude 2.1", "provider": "bedrock", "family": "claude", - "created_at": "2023-11-21 00:00:00 +0100", + "created_at": "2023-11-21 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -3401,7 +3401,7 @@ "name": "Claude 2.1", "provider": "bedrock", "family": "claude", - "created_at": "2023-11-21 00:00:00 +0100", + "created_at": "2023-11-21 00:00:00 +0300", "context_window": 18000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -3459,7 +3459,7 @@ "name": "Claude 2.1", "provider": "bedrock", "family": "claude", - "created_at": "2023-11-21 00:00:00 +0100", + "created_at": "2023-11-21 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -3517,7 +3517,7 @@ "name": "Command Light", "provider": "bedrock", "family": "command-light", - "created_at": "2023-11-01 00:00:00 +0100", + "created_at": "2023-11-01 00:00:00 +0300", "context_window": 4096, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -3561,7 +3561,7 @@ "name": "Command R+", "provider": "bedrock", "family": "command-r", - "created_at": "2024-04-04 00:00:00 +0200", + "created_at": "2024-04-04 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -3607,7 +3607,7 @@ "name": "Command R", "provider": "bedrock", "family": "command-r", - "created_at": "2024-03-11 00:00:00 +0100", + "created_at": "2024-03-11 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -3653,7 +3653,7 @@ "name": "Command", "provider": "bedrock", "family": "command", - "created_at": "2023-11-01 00:00:00 +0100", + "created_at": "2023-11-01 00:00:00 +0300", "context_window": 4096, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -3697,7 +3697,7 @@ "name": "DeepSeek-R1", "provider": "bedrock", "family": "deepseek-thinking", - "created_at": "2025-01-20 00:00:00 +0100", + "created_at": "2025-01-20 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -3744,7 +3744,7 @@ "name": "DeepSeek-V3.1", "provider": "bedrock", "family": "deepseek", - "created_at": "2025-09-18 00:00:00 +0200", + "created_at": "2025-09-18 00:00:00 +0300", "context_window": 163840, "max_output_tokens": 81920, "knowledge_cutoff": null, @@ -3791,7 +3791,7 @@ "name": "Claude Opus 4.5 (Global)", "provider": "bedrock", "family": "claude-opus", - "created_at": "2025-11-24 00:00:00 +0100", + "created_at": "2025-11-24 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-03-31", @@ -3844,7 +3844,7 @@ "name": "Google Gemma 3 12B", "provider": "bedrock", "family": "gemma", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -3891,7 +3891,7 @@ "name": "Google Gemma 3 27B Instruct", "provider": "bedrock", "family": "gemma", - "created_at": "2025-07-27 00:00:00 +0200", + "created_at": "2025-07-27 00:00:00 +0300", "context_window": 202752, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -3939,7 +3939,7 @@ "name": "Gemma 3 4B IT", "provider": "bedrock", "family": "gemma", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -3986,7 +3986,7 @@ "name": "Llama 3.1 70B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2024-07-23 00:00:00 +0200", + "created_at": "2024-07-23 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4032,7 +4032,7 @@ "name": "Llama 3.1 8B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2024-07-23 00:00:00 +0200", + "created_at": "2024-07-23 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4078,7 +4078,7 @@ "name": "Llama 3.2 11B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2024-09-25 00:00:00 +0200", + "created_at": "2024-09-25 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4126,7 +4126,7 @@ "name": "Llama 3.2 1B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2024-09-25 00:00:00 +0200", + "created_at": "2024-09-25 00:00:00 +0300", "context_window": 131000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4172,7 +4172,7 @@ "name": "Llama 3.2 3B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2024-09-25 00:00:00 +0200", + "created_at": "2024-09-25 00:00:00 +0300", "context_window": 131000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4218,7 +4218,7 @@ "name": "Llama 3.2 90B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2024-09-25 00:00:00 +0200", + "created_at": "2024-09-25 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4266,7 +4266,7 @@ "name": "Llama 3.3 70B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2024-12-06 00:00:00 +0100", + "created_at": "2024-12-06 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4312,7 +4312,7 @@ "name": "Llama 3 70B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2024-07-23 00:00:00 +0200", + "created_at": "2024-07-23 00:00:00 +0300", "context_window": 8192, "max_output_tokens": 2048, "knowledge_cutoff": null, @@ -4356,7 +4356,7 @@ "name": "Llama 3 8B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2024-07-23 00:00:00 +0200", + "created_at": "2024-07-23 00:00:00 +0300", "context_window": 8192, "max_output_tokens": 2048, "knowledge_cutoff": null, @@ -4400,7 +4400,7 @@ "name": "Llama 4 Maverick 17B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2025-04-05 00:00:00 +0200", + "created_at": "2025-04-05 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -4448,7 +4448,7 @@ "name": "Llama 4 Scout 17B Instruct", "provider": "bedrock", "family": "llama", - "created_at": "2025-04-05 00:00:00 +0200", + "created_at": "2025-04-05 00:00:00 +0300", "context_window": 3500000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -4496,7 +4496,7 @@ "name": "MiniMax M2", "provider": "bedrock", "family": "minimax", - "created_at": "2025-10-27 00:00:00 +0100", + "created_at": "2025-10-27 00:00:00 +0300", "context_window": 204608, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -4542,7 +4542,7 @@ "name": "Ministral 14B 3.0", "provider": "bedrock", "family": "ministral", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4587,7 +4587,7 @@ "name": "Ministral 3 8B", "provider": "bedrock", "family": "ministral", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4632,7 +4632,7 @@ "name": "Mistral-7B-Instruct-v0.3", "provider": "bedrock", "family": "mistral", - "created_at": "2025-04-01 00:00:00 +0200", + "created_at": "2025-04-01 00:00:00 +0300", "context_window": 127000, "max_output_tokens": 127000, "knowledge_cutoff": null, @@ -4678,7 +4678,7 @@ "name": "Mistral Large (24.02)", "provider": "bedrock", "family": "mistral-large", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4723,7 +4723,7 @@ "name": "Mixtral-8x7B-Instruct-v0.1", "provider": "bedrock", "family": "mixtral", - "created_at": "2025-04-01 00:00:00 +0200", + "created_at": "2025-04-01 00:00:00 +0300", "context_window": 32000, "max_output_tokens": 32000, "knowledge_cutoff": null, @@ -4768,7 +4768,7 @@ "name": "Voxtral Mini 3B 2507", "provider": "bedrock", "family": "mistral", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4814,7 +4814,7 @@ "name": "Voxtral Small 24B 2507", "provider": "bedrock", "family": "mistral", - "created_at": "2025-07-01 00:00:00 +0200", + "created_at": "2025-07-01 00:00:00 +0300", "context_window": 32000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -4860,7 +4860,7 @@ "name": "Kimi K2 Thinking", "provider": "bedrock", "family": null, - "created_at": "2025-12-02 00:00:00 +0100", + "created_at": "2025-12-02 00:00:00 +0300", "context_window": 256000, "max_output_tokens": 256000, "knowledge_cutoff": null, @@ -4907,7 +4907,7 @@ "name": "NVIDIA Nemotron Nano 12B v2 VL BF16", "provider": "bedrock", "family": "nemotron", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4954,7 +4954,7 @@ "name": "NVIDIA Nemotron Nano 9B v2", "provider": "bedrock", "family": "nemotron", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -4999,7 +4999,7 @@ "name": "gpt-oss-120b", "provider": "bedrock", "family": "gpt-oss", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -5044,7 +5044,7 @@ "name": "gpt-oss-20b", "provider": "bedrock", "family": "gpt-oss", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -5089,7 +5089,7 @@ "name": "GPT OSS Safeguard 120B", "provider": "bedrock", "family": "gpt-oss", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -5134,7 +5134,7 @@ "name": "GPT OSS Safeguard 20B", "provider": "bedrock", "family": "gpt-oss", - "created_at": "2024-12-01 00:00:00 +0100", + "created_at": "2024-12-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -5179,7 +5179,7 @@ "name": "Qwen3 235B A22B 2507", "provider": "bedrock", "family": "qwen", - "created_at": "2025-09-18 00:00:00 +0200", + "created_at": "2025-09-18 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -5225,7 +5225,7 @@ "name": "Qwen3 32B (dense)", "provider": "bedrock", "family": "qwen", - "created_at": "2025-09-18 00:00:00 +0200", + "created_at": "2025-09-18 00:00:00 +0300", "context_window": 16384, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -5272,7 +5272,7 @@ "name": "Qwen3 Coder 30B A3B Instruct", "provider": "bedrock", "family": "qwen", - "created_at": "2025-09-18 00:00:00 +0200", + "created_at": "2025-09-18 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -5318,7 +5318,7 @@ "name": "Qwen3 Coder 480B A35B Instruct", "provider": "bedrock", "family": "qwen", - "created_at": "2025-09-18 00:00:00 +0200", + "created_at": "2025-09-18 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -5364,7 +5364,7 @@ "name": "Qwen/Qwen3-Next-80B-A3B-Instruct", "provider": "bedrock", "family": "qwen", - "created_at": "2025-09-18 00:00:00 +0200", + "created_at": "2025-09-18 00:00:00 +0300", "context_window": 262000, "max_output_tokens": 262000, "knowledge_cutoff": null, @@ -5410,7 +5410,7 @@ "name": "Qwen/Qwen3-VL-235B-A22B-Instruct", "provider": "bedrock", "family": "qwen", - "created_at": "2025-10-04 00:00:00 +0200", + "created_at": "2025-10-04 00:00:00 +0300", "context_window": 262000, "max_output_tokens": 262000, "knowledge_cutoff": null, @@ -5458,7 +5458,7 @@ "name": "Claude Sonnet 3.7", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2025-02-19 00:00:00 +0100", + "created_at": "2025-02-19 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -5526,7 +5526,7 @@ "name": "Claude Haiku 4.5", "provider": "bedrock", "family": "claude-haiku", - "created_at": "2025-10-15 00:00:00 +0200", + "created_at": "2025-10-15 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-02-28", @@ -5592,7 +5592,7 @@ "name": "Claude Opus 4.1", "provider": "bedrock", "family": "claude-opus", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": "2025-03-31", @@ -5658,7 +5658,7 @@ "name": "Claude Opus 4", "provider": "bedrock", "family": "claude-opus", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": null, @@ -5724,7 +5724,7 @@ "name": "Claude Opus 4.5", "provider": "bedrock", "family": "claude-opus", - "created_at": "2025-11-24 00:00:00 +0100", + "created_at": "2025-11-24 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-03-31", @@ -5790,7 +5790,7 @@ "name": "Claude Sonnet 4", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": null, @@ -5856,7 +5856,7 @@ "name": "Claude Sonnet 4.5", "provider": "bedrock", "family": "claude-sonnet", - "created_at": "2025-09-29 00:00:00 +0200", + "created_at": "2025-09-29 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-07-31", @@ -5922,7 +5922,7 @@ "name": "DeepSeek Chat", "provider": "deepseek", "family": "deepseek", - "created_at": "2024-12-26 00:00:00 +0100", + "created_at": "2024-12-26 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -5973,7 +5973,7 @@ "name": "DeepSeek Reasoner", "provider": "deepseek", "family": "deepseek-thinking", - "created_at": "2025-01-20 00:00:00 +0100", + "created_at": "2025-01-20 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -6178,7 +6178,7 @@ "name": "Gemini 1.5 Flash", "provider": "gemini", "family": "gemini-flash", - "created_at": "2024-05-14 00:00:00 +0200", + "created_at": "2024-05-14 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -6230,7 +6230,7 @@ "name": "Gemini 1.5 Flash-8B", "provider": "gemini", "family": "gemini-flash", - "created_at": "2024-10-03 00:00:00 +0200", + "created_at": "2024-10-03 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -6282,7 +6282,7 @@ "name": "Gemini 1.5 Pro", "provider": "gemini", "family": "gemini-pro", - "created_at": "2024-02-15 00:00:00 +0100", + "created_at": "2024-02-15 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -6334,7 +6334,7 @@ "name": "Gemini 2.0 Flash", "provider": "gemini", "family": "gemini-flash", - "created_at": "2024-12-11 00:00:00 +0100", + "created_at": "2024-12-11 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -6498,7 +6498,7 @@ "name": "Gemini 2.0 Flash Lite", "provider": "gemini", "family": "gemini-flash-lite", - "created_at": "2024-12-11 00:00:00 +0100", + "created_at": "2024-12-11 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -6748,7 +6748,7 @@ "name": "Gemini 2.5 Flash", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-03-20 00:00:00 +0100", + "created_at": "2025-03-20 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -6820,7 +6820,7 @@ "name": "Gemini 2.5 Flash Image", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-08-26 00:00:00 +0200", + "created_at": "2025-08-26 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -6883,7 +6883,7 @@ "name": "Gemini 2.5 Flash Image (Preview)", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-08-26 00:00:00 +0200", + "created_at": "2025-08-26 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -6934,7 +6934,7 @@ "name": "Gemini 2.5 Flash Lite", "provider": "gemini", "family": "gemini-flash-lite", - "created_at": "2025-06-17 00:00:00 +0200", + "created_at": "2025-06-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -6999,7 +6999,7 @@ "name": "Gemini 2.5 Flash Lite Preview 06-17", "provider": "gemini", "family": "gemini-flash-lite", - "created_at": "2025-06-17 00:00:00 +0200", + "created_at": "2025-06-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -7059,7 +7059,7 @@ "name": "Gemini 2.5 Flash Lite Preview 09-25", "provider": "gemini", "family": "gemini-flash-lite", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -7173,7 +7173,7 @@ "name": "Gemini 2.5 Flash Preview 04-17", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-04-17 00:00:00 +0200", + "created_at": "2025-04-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -7227,7 +7227,7 @@ "name": "Gemini 2.5 Flash Preview 05-20", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-05-20 00:00:00 +0200", + "created_at": "2025-05-20 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -7282,7 +7282,7 @@ "name": "Gemini 2.5 Flash Preview 09-25", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -7354,7 +7354,7 @@ "name": "Gemini 2.5 Flash Preview TTS", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-05-01 00:00:00 +0200", + "created_at": "2025-05-01 00:00:00 +0300", "context_window": 8000, "max_output_tokens": 16000, "knowledge_cutoff": null, @@ -7410,7 +7410,7 @@ "name": "Gemini 2.5 Pro", "provider": "gemini", "family": "gemini-pro", - "created_at": "2025-03-20 00:00:00 +0100", + "created_at": "2025-03-20 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -7475,7 +7475,7 @@ "name": "Gemini 2.5 Pro Preview 05-06", "provider": "gemini", "family": "gemini-pro", - "created_at": "2025-05-06 00:00:00 +0200", + "created_at": "2025-05-06 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -7530,7 +7530,7 @@ "name": "Gemini 2.5 Pro Preview 06-05", "provider": "gemini", "family": "gemini-pro", - "created_at": "2025-06-05 00:00:00 +0200", + "created_at": "2025-06-05 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -7585,7 +7585,7 @@ "name": "Gemini 2.5 Pro Preview TTS", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-05-01 00:00:00 +0200", + "created_at": "2025-05-01 00:00:00 +0300", "context_window": 8000, "max_output_tokens": 16000, "knowledge_cutoff": null, @@ -7641,7 +7641,7 @@ "name": "Gemini 3 Flash Preview", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-12-17 00:00:00 +0100", + "created_at": "2025-12-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -7760,7 +7760,7 @@ "name": "Gemini 3 Pro Preview", "provider": "gemini", "family": "gemini-pro", - "created_at": "2025-11-18 00:00:00 +0100", + "created_at": "2025-11-18 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 64000, "knowledge_cutoff": null, @@ -7830,7 +7830,7 @@ "name": "Gemini Embedding 001", "provider": "gemini", "family": "gemini", - "created_at": "2025-05-20 00:00:00 +0200", + "created_at": "2025-05-20 00:00:00 +0300", "context_window": 2048, "max_output_tokens": 3072, "knowledge_cutoff": null, @@ -8043,7 +8043,7 @@ "name": "Gemini Flash Latest", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -8115,7 +8115,7 @@ "name": "Gemini Flash-Lite Latest", "provider": "gemini", "family": "gemini-flash-lite", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -8180,7 +8180,7 @@ "name": "Gemini Live 2.5 Flash", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-09-01 00:00:00 +0200", + "created_at": "2025-09-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 8000, "knowledge_cutoff": null, @@ -8240,7 +8240,7 @@ "name": "Gemini Live 2.5 Flash Preview Native Audio", "provider": "gemini", "family": "gemini-flash", - "created_at": "2025-06-17 00:00:00 +0200", + "created_at": "2025-06-17 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -9252,7 +9252,7 @@ "name": "Codestral", "provider": "mistral", "family": "codestral", - "created_at": "2024-05-29 00:00:00 +0200", + "created_at": "2024-05-29 00:00:00 +0300", "context_window": 256000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -9304,7 +9304,7 @@ "name": "Devstral 2", "provider": "mistral", "family": "devstral", - "created_at": "2025-12-09 00:00:00 +0100", + "created_at": "2025-12-09 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -9379,7 +9379,7 @@ "name": "Devstral Medium", "provider": "mistral", "family": "devstral", - "created_at": "2025-07-10 00:00:00 +0200", + "created_at": "2025-07-10 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -9431,7 +9431,7 @@ "name": "Devstral 2", "provider": "mistral", "family": "devstral", - "created_at": "2025-12-02 00:00:00 +0100", + "created_at": "2025-12-02 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -9483,7 +9483,7 @@ "name": "Devstral Small 2505", "provider": "mistral", "family": "devstral", - "created_at": "2025-05-07 00:00:00 +0200", + "created_at": "2025-05-07 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -9529,7 +9529,7 @@ "name": "Devstral Small", "provider": "mistral", "family": "devstral", - "created_at": "2025-07-10 00:00:00 +0200", + "created_at": "2025-07-10 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -9611,7 +9611,7 @@ "name": "Devstral Small 2", "provider": "mistral", "family": "devstral", - "created_at": "2025-12-09 00:00:00 +0100", + "created_at": "2025-12-09 00:00:00 +0300", "context_window": 256000, "max_output_tokens": 256000, "knowledge_cutoff": null, @@ -9718,7 +9718,7 @@ "name": "Magistral Medium", "provider": "mistral", "family": "magistral-medium", - "created_at": "2025-03-17 00:00:00 +0100", + "created_at": "2025-03-17 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -9770,7 +9770,7 @@ "name": "Magistral Small", "provider": "mistral", "family": "magistral-small", - "created_at": "2025-03-17 00:00:00 +0100", + "created_at": "2025-03-17 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -9997,7 +9997,7 @@ "name": "Ministral 3B", "provider": "mistral", "family": "ministral", - "created_at": "2024-10-01 00:00:00 +0200", + "created_at": "2024-10-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -10109,7 +10109,7 @@ "name": "Ministral 8B", "provider": "mistral", "family": "ministral", - "created_at": "2024-10-01 00:00:00 +0200", + "created_at": "2024-10-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -10161,7 +10161,7 @@ "name": "Mistral Embed", "provider": "mistral", "family": "mistral-embed", - "created_at": "2023-12-11 00:00:00 +0100", + "created_at": "2023-12-11 00:00:00 +0300", "context_window": 8000, "max_output_tokens": 3072, "knowledge_cutoff": null, @@ -10229,7 +10229,7 @@ "name": "Mistral Large 2.1", "provider": "mistral", "family": "mistral-large", - "created_at": "2024-11-01 00:00:00 +0100", + "created_at": "2024-11-01 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -10281,7 +10281,7 @@ "name": "Mistral Large 3", "provider": "mistral", "family": "mistral-large", - "created_at": "2024-11-01 00:00:00 +0100", + "created_at": "2024-11-01 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -10335,7 +10335,7 @@ "name": "Mistral Large", "provider": "mistral", "family": "mistral-large", - "created_at": "2024-11-01 00:00:00 +0100", + "created_at": "2024-11-01 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -10452,7 +10452,7 @@ "name": "Mistral Medium 3", "provider": "mistral", "family": "mistral-medium", - "created_at": "2025-05-07 00:00:00 +0200", + "created_at": "2025-05-07 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -10506,7 +10506,7 @@ "name": "Mistral Medium 3.1", "provider": "mistral", "family": "mistral-medium", - "created_at": "2025-08-12 00:00:00 +0200", + "created_at": "2025-08-12 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -10560,7 +10560,7 @@ "name": "Mistral Medium", "provider": "mistral", "family": "mistral-medium", - "created_at": "2025-05-07 00:00:00 +0200", + "created_at": "2025-05-07 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -10666,7 +10666,7 @@ "name": "Mistral Nemo", "provider": "mistral", "family": "mistral-nemo", - "created_at": "2024-07-01 00:00:00 +0200", + "created_at": "2024-07-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -10846,7 +10846,7 @@ "name": "Mistral Small 3.2", "provider": "mistral", "family": "mistral-small", - "created_at": "2025-06-20 00:00:00 +0200", + "created_at": "2025-06-20 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -10900,7 +10900,7 @@ "name": "Mistral Small", "provider": "mistral", "family": "mistral-small", - "created_at": "2024-09-01 00:00:00 +0200", + "created_at": "2024-09-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -11097,7 +11097,7 @@ "name": "Mistral 7B", "provider": "mistral", "family": "mistral", - "created_at": "2023-09-27 00:00:00 +0200", + "created_at": "2023-09-27 00:00:00 +0300", "context_window": 8000, "max_output_tokens": 8000, "knowledge_cutoff": null, @@ -11206,7 +11206,7 @@ "name": "Mixtral 8x22B", "provider": "mistral", "family": "mixtral", - "created_at": "2024-04-17 00:00:00 +0200", + "created_at": "2024-04-17 00:00:00 +0300", "context_window": 64000, "max_output_tokens": 64000, "knowledge_cutoff": null, @@ -11252,7 +11252,7 @@ "name": "Mixtral 8x7B", "provider": "mistral", "family": "mixtral", - "created_at": "2023-12-11 00:00:00 +0100", + "created_at": "2023-12-11 00:00:00 +0300", "context_window": 32000, "max_output_tokens": 32000, "knowledge_cutoff": null, @@ -11298,7 +11298,7 @@ "name": "Pixtral 12B", "provider": "mistral", "family": "pixtral", - "created_at": "2024-09-01 00:00:00 +0200", + "created_at": "2024-09-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -11444,7 +11444,7 @@ "name": "Pixtral Large", "provider": "mistral", "family": "pixtral", - "created_at": "2024-11-01 00:00:00 +0100", + "created_at": "2024-11-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -11730,7 +11730,7 @@ "name": "Codex Mini", "provider": "openai", "family": "gpt-codex-mini", - "created_at": "2025-05-16 00:00:00 +0200", + "created_at": "2025-05-16 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -11883,7 +11883,7 @@ "name": "GPT-3.5-turbo", "provider": "openai", "family": "gpt", - "created_at": "2023-03-01 00:00:00 +0100", + "created_at": "2023-03-01 00:00:00 +0300", "context_window": 16385, "max_output_tokens": 4096, "knowledge_cutoff": "2021-09-01", @@ -12098,7 +12098,7 @@ "name": "GPT-4", "provider": "openai", "family": "gpt", - "created_at": "2023-11-06 00:00:00 +0100", + "created_at": "2023-11-06 00:00:00 +0300", "context_window": 8192, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -12246,7 +12246,7 @@ "name": "GPT-4 Turbo", "provider": "openai", "family": "gpt", - "created_at": "2023-11-06 00:00:00 +0100", + "created_at": "2023-11-06 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -12369,7 +12369,7 @@ "name": "GPT-4.1", "provider": "openai", "family": "gpt", - "created_at": "2025-04-14 00:00:00 +0200", + "created_at": "2025-04-14 00:00:00 +0300", "context_window": 1047576, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -12461,7 +12461,7 @@ "name": "GPT-4.1 mini", "provider": "openai", "family": "gpt-mini", - "created_at": "2025-04-14 00:00:00 +0200", + "created_at": "2025-04-14 00:00:00 +0300", "context_window": 1047576, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -12553,7 +12553,7 @@ "name": "GPT-4.1 nano", "provider": "openai", "family": "gpt-nano", - "created_at": "2025-04-14 00:00:00 +0200", + "created_at": "2025-04-14 00:00:00 +0300", "context_window": 1047576, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -12644,7 +12644,7 @@ "name": "GPT-4o", "provider": "openai", "family": "gpt", - "created_at": "2024-05-13 00:00:00 +0200", + "created_at": "2024-05-13 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -12698,7 +12698,7 @@ "name": "GPT-4o (2024-05-13)", "provider": "openai", "family": "gpt", - "created_at": "2024-05-13 00:00:00 +0200", + "created_at": "2024-05-13 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": null, @@ -12750,7 +12750,7 @@ "name": "GPT-4o (2024-08-06)", "provider": "openai", "family": "gpt", - "created_at": "2024-08-06 00:00:00 +0200", + "created_at": "2024-08-06 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -12804,7 +12804,7 @@ "name": "GPT-4o (2024-11-20)", "provider": "openai", "family": "gpt", - "created_at": "2024-11-20 00:00:00 +0100", + "created_at": "2024-11-20 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -12969,7 +12969,7 @@ "name": "GPT-4o mini", "provider": "openai", "family": "gpt-mini", - "created_at": "2024-07-18 00:00:00 +0200", + "created_at": "2024-07-18 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -13710,7 +13710,7 @@ "name": "GPT-5", "provider": "openai", "family": "gpt", - "created_at": "2025-08-07 00:00:00 +0200", + "created_at": "2025-08-07 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -13735,7 +13735,7 @@ "standard": { "input_per_million": 1.25, "output_per_million": 10, - "cached_input_per_million": 0.13 + "cached_input_per_million": 0.125 } } }, @@ -13751,10 +13751,11 @@ "cost": { "input": 1.25, "output": 10, - "cache_read": 0.13 + "cache_read": 0.125 }, "limit": { "context": 400000, + "input": 272000, "output": 128000 }, "knowledge": "2024-09-30" @@ -13804,7 +13805,7 @@ "name": "GPT-5 Chat (latest)", "provider": "openai", "family": "gpt-codex", - "created_at": "2025-08-07 00:00:00 +0200", + "created_at": "2025-08-07 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -13847,6 +13848,7 @@ }, "limit": { "context": 400000, + "input": 272000, "output": 128000 }, "knowledge": "2024-09-30" @@ -13857,7 +13859,7 @@ "name": "GPT-5-Codex", "provider": "openai", "family": "gpt-codex", - "created_at": "2025-09-15 00:00:00 +0200", + "created_at": "2025-09-15 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -13902,6 +13904,7 @@ }, "limit": { "context": 400000, + "input": 272000, "output": 128000 }, "knowledge": "2024-09-30" @@ -13912,7 +13915,7 @@ "name": "GPT-5 Mini", "provider": "openai", "family": "gpt-mini", - "created_at": "2025-08-07 00:00:00 +0200", + "created_at": "2025-08-07 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-05-30", @@ -13937,7 +13940,7 @@ "standard": { "input_per_million": 0.25, "output_per_million": 2, - "cached_input_per_million": 0.03 + "cached_input_per_million": 0.025 } } }, @@ -13953,10 +13956,11 @@ "cost": { "input": 0.25, "output": 2, - "cache_read": 0.03 + "cache_read": 0.025 }, "limit": { "context": 400000, + "input": 272000, "output": 128000 }, "knowledge": "2024-05-30" @@ -14006,7 +14010,7 @@ "name": "GPT-5 Nano", "provider": "openai", "family": "gpt-nano", - "created_at": "2025-08-07 00:00:00 +0200", + "created_at": "2025-08-07 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-05-30", @@ -14031,7 +14035,7 @@ "standard": { "input_per_million": 0.05, "output_per_million": 0.4, - "cached_input_per_million": 0.01 + "cached_input_per_million": 0.005 } } }, @@ -14047,10 +14051,11 @@ "cost": { "input": 0.05, "output": 0.4, - "cache_read": 0.01 + "cache_read": 0.005 }, "limit": { "context": 400000, + "input": 272000, "output": 128000 }, "knowledge": "2024-05-30" @@ -14100,7 +14105,7 @@ "name": "GPT-5 Pro", "provider": "openai", "family": "gpt-pro", - "created_at": "2025-10-06 00:00:00 +0200", + "created_at": "2025-10-06 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 272000, "knowledge_cutoff": "2024-09-30", @@ -14143,6 +14148,7 @@ }, "limit": { "context": 400000, + "input": 272000, "output": 272000 }, "knowledge": "2024-09-30" @@ -14270,7 +14276,7 @@ "name": "GPT-5.1", "provider": "openai", "family": "gpt", - "created_at": "2025-11-13 00:00:00 +0100", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -14315,6 +14321,7 @@ }, "limit": { "context": 400000, + "input": 272000, "output": 128000 }, "knowledge": "2024-09-30" @@ -14364,7 +14371,7 @@ "name": "GPT-5.1 Chat", "provider": "openai", "family": "gpt-codex", - "created_at": "2025-11-13 00:00:00 +0100", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": "2024-09-30", @@ -14419,7 +14426,7 @@ "name": "GPT-5.1 Codex", "provider": "openai", "family": "gpt-codex", - "created_at": "2025-11-13 00:00:00 +0100", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -14475,7 +14482,7 @@ "name": "GPT-5.1 Codex Max", "provider": "openai", "family": "gpt-codex", - "created_at": "2025-11-13 00:00:00 +0100", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -14531,7 +14538,7 @@ "name": "GPT-5.1 Codex mini", "provider": "openai", "family": "gpt-codex", - "created_at": "2025-11-13 00:00:00 +0100", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -14587,7 +14594,7 @@ "name": "GPT-5.2", "provider": "openai", "family": "gpt", - "created_at": "2025-12-11 00:00:00 +0100", + "created_at": "2025-12-11 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2025-08-31", @@ -14632,6 +14639,7 @@ }, "limit": { "context": 400000, + "input": 272000, "output": 128000 }, "knowledge": "2025-08-31" @@ -14681,7 +14689,7 @@ "name": "GPT-5.2 Chat", "provider": "openai", "family": "gpt-codex", - "created_at": "2025-12-11 00:00:00 +0100", + "created_at": "2025-12-11 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": "2025-08-31", @@ -14736,14 +14744,15 @@ "name": "GPT-5.2 Codex", "provider": "openai", "family": "gpt-codex", - "created_at": "2025-12-11 00:00:00 +0100", + "created_at": "2025-12-11 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2025-08-31", "modalities": { "input": [ "text", - "image" + "image", + "pdf" ], "output": [ "text" @@ -14792,7 +14801,7 @@ "name": "GPT-5.2 Pro", "provider": "openai", "family": "gpt-pro", - "created_at": "2025-12-11 00:00:00 +0100", + "created_at": "2025-12-11 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2025-08-31", @@ -14835,6 +14844,7 @@ }, "limit": { "context": 400000, + "input": 272000, "output": 128000 }, "knowledge": "2025-08-31" @@ -15326,7 +15336,7 @@ "name": "o1", "provider": "openai", "family": "o", - "created_at": "2024-12-05 00:00:00 +0100", + "created_at": "2024-12-05 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -15419,7 +15429,7 @@ "name": "o1-mini", "provider": "openai", "family": "o-mini", - "created_at": "2024-09-12 00:00:00 +0200", + "created_at": "2024-09-12 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -15468,7 +15478,7 @@ "name": "o1-preview", "provider": "openai", "family": "o", - "created_at": "2024-09-12 00:00:00 +0200", + "created_at": "2024-09-12 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -15516,7 +15526,7 @@ "name": "o1-pro", "provider": "openai", "family": "o-pro", - "created_at": "2025-03-19 00:00:00 +0100", + "created_at": "2025-03-19 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -15607,7 +15617,7 @@ "name": "o3", "provider": "openai", "family": "o", - "created_at": "2025-04-16 00:00:00 +0200", + "created_at": "2025-04-16 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -15696,7 +15706,7 @@ "name": "o3-deep-research", "provider": "openai", "family": "o", - "created_at": "2024-06-26 00:00:00 +0200", + "created_at": "2024-06-26 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -15784,7 +15794,7 @@ "name": "o3-mini", "provider": "openai", "family": "o-mini", - "created_at": "2024-12-20 00:00:00 +0100", + "created_at": "2024-12-20 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -15873,7 +15883,7 @@ "name": "o3-pro", "provider": "openai", "family": "o-pro", - "created_at": "2025-06-10 00:00:00 +0200", + "created_at": "2025-06-10 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -15960,7 +15970,7 @@ "name": "o4-mini", "provider": "openai", "family": "o-mini", - "created_at": "2025-04-16 00:00:00 +0200", + "created_at": "2025-04-16 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -16049,7 +16059,7 @@ "name": "o4-mini-deep-research", "provider": "openai", "family": "o-mini", - "created_at": "2024-06-26 00:00:00 +0200", + "created_at": "2024-06-26 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -16257,7 +16267,7 @@ "name": "text-embedding-3-large", "provider": "openai", "family": "text-embedding", - "created_at": "2024-01-25 00:00:00 +0100", + "created_at": "2024-01-25 00:00:00 +0300", "context_window": 8191, "max_output_tokens": 3072, "knowledge_cutoff": null, @@ -16304,7 +16314,7 @@ "name": "text-embedding-3-small", "provider": "openai", "family": "text-embedding", - "created_at": "2024-01-25 00:00:00 +0100", + "created_at": "2024-01-25 00:00:00 +0300", "context_window": 8191, "max_output_tokens": 1536, "knowledge_cutoff": null, @@ -16351,7 +16361,7 @@ "name": "text-embedding-ada-002", "provider": "openai", "family": "text-embedding", - "created_at": "2022-12-15 00:00:00 +0100", + "created_at": "2022-12-15 00:00:00 +0300", "context_window": 8192, "max_output_tokens": 1536, "knowledge_cutoff": null, @@ -17936,7 +17946,7 @@ "name": "Claude Haiku 3.5", "provider": "openrouter", "family": "claude-haiku", - "created_at": "2024-10-22 00:00:00 +0200", + "created_at": "2024-10-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": "2024-07-31", @@ -18080,7 +18090,7 @@ "name": "Claude Sonnet 3.7", "provider": "openrouter", "family": "claude-sonnet", - "created_at": "2025-02-19 00:00:00 +0100", + "created_at": "2025-02-19 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -18230,7 +18240,7 @@ "name": "Claude Haiku 4.5", "provider": "openrouter", "family": "claude-haiku", - "created_at": "2025-10-15 00:00:00 +0200", + "created_at": "2025-10-15 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-02-28", @@ -18314,7 +18324,7 @@ "name": "Claude Opus 4", "provider": "openrouter", "family": "claude-opus", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": "2025-03-31", @@ -18399,7 +18409,7 @@ "name": "Claude Opus 4.1", "provider": "openrouter", "family": "claude-opus", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": "2025-03-31", @@ -18487,7 +18497,7 @@ "name": "Claude Opus 4.5", "provider": "openrouter", "family": "claude-opus", - "created_at": "2025-11-24 00:00:00 +0100", + "created_at": "2025-11-24 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 32000, "knowledge_cutoff": "2025-05-30", @@ -18575,7 +18585,7 @@ "name": "Claude Sonnet 4", "provider": "openrouter", "family": "claude-sonnet", - "created_at": "2025-05-22 00:00:00 +0200", + "created_at": "2025-05-22 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-03-31", @@ -18666,7 +18676,7 @@ "name": "Claude Sonnet 4.5", "provider": "openrouter", "family": "claude-sonnet", - "created_at": "2025-09-29 00:00:00 +0200", + "created_at": "2025-09-29 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 64000, "knowledge_cutoff": "2025-07-31", @@ -19710,7 +19720,7 @@ "name": "Dolphin3.0 Mistral 24B", "provider": "openrouter", "family": "mistral", - "created_at": "2025-02-13 00:00:00 +0100", + "created_at": "2025-02-13 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -19749,7 +19759,7 @@ "name": "Dolphin3.0 R1 Mistral 24B", "provider": "openrouter", "family": "mistral", - "created_at": "2025-02-13 00:00:00 +0100", + "created_at": "2025-02-13 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -20386,7 +20396,7 @@ "name": "DeepSeek V3 0324", "provider": "openrouter", "family": "deepseek", - "created_at": "2025-03-24 00:00:00 +0100", + "created_at": "2025-03-24 00:00:00 +0300", "context_window": 16384, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -20473,7 +20483,7 @@ "name": "DeepSeek-V3.1", "provider": "openrouter", "family": "deepseek", - "created_at": "2025-08-21 00:00:00 +0200", + "created_at": "2025-08-21 00:00:00 +0300", "context_window": 163840, "max_output_tokens": 163840, "knowledge_cutoff": null, @@ -20700,7 +20710,7 @@ "name": "Deepseek R1 0528 Qwen3 8B (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-05-29 00:00:00 +0200", + "created_at": "2025-05-29 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -20740,7 +20750,7 @@ "name": "R1 0528 (free)", "provider": "openrouter", "family": "deepseek", - "created_at": "2025-05-28 00:00:00 +0200", + "created_at": "2025-05-28 00:00:00 +0300", "context_window": 163840, "max_output_tokens": 163840, "knowledge_cutoff": null, @@ -20808,7 +20818,7 @@ "name": "DeepSeek R1 Distill Llama 70B", "provider": "openrouter", "family": "deepseek-thinking", - "created_at": "2025-01-23 00:00:00 +0100", + "created_at": "2025-01-23 00:00:00 +0300", "context_window": 8192, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -20895,7 +20905,7 @@ "name": "DeepSeek R1 Distill Qwen 14B", "provider": "openrouter", "family": "qwen", - "created_at": "2025-01-29 00:00:00 +0100", + "created_at": "2025-01-29 00:00:00 +0300", "context_window": 64000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -20999,7 +21009,7 @@ "name": "R1 (free)", "provider": "openrouter", "family": "deepseek", - "created_at": "2025-01-20 00:00:00 +0100", + "created_at": "2025-01-20 00:00:00 +0300", "context_window": 163840, "max_output_tokens": 163840, "knowledge_cutoff": null, @@ -21039,7 +21049,7 @@ "name": "DeepSeek V3 Base (free)", "provider": "openrouter", "family": "deepseek", - "created_at": "2025-03-29 00:00:00 +0100", + "created_at": "2025-03-29 00:00:00 +0300", "context_window": 163840, "max_output_tokens": 163840, "knowledge_cutoff": null, @@ -21076,7 +21086,7 @@ "name": "DeepSeek V3.1 Terminus", "provider": "openrouter", "family": "deepseek", - "created_at": "2025-09-22 00:00:00 +0200", + "created_at": "2025-09-22 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -21161,7 +21171,7 @@ "name": "DeepSeek V3.1 Terminus (exacto)", "provider": "openrouter", "family": "deepseek", - "created_at": "2025-09-22 00:00:00 +0200", + "created_at": "2025-09-22 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -21246,7 +21256,7 @@ "name": "DeepSeek V3.2", "provider": "openrouter", "family": "deepseek", - "created_at": "2025-12-01 00:00:00 +0100", + "created_at": "2025-12-01 00:00:00 +0300", "context_window": 163840, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -21403,7 +21413,7 @@ "name": "DeepSeek V3.2 Speciale", "provider": "openrouter", "family": "deepseek", - "created_at": "2025-12-01 00:00:00 +0100", + "created_at": "2025-12-01 00:00:00 +0300", "context_window": 163840, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -21613,7 +21623,7 @@ "name": "Qwerky 72B", "provider": "openrouter", "family": "qwerky", - "created_at": "2025-03-20 00:00:00 +0100", + "created_at": "2025-03-20 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -21650,7 +21660,7 @@ "name": "Gemini 2.0 Flash", "provider": "openrouter", "family": "gemini-flash", - "created_at": "2024-12-11 00:00:00 +0100", + "created_at": "2024-12-11 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -21738,7 +21748,7 @@ "name": "Gemini 2.0 Flash Experimental (free)", "provider": "openrouter", "family": "gemini-flash", - "created_at": "2024-12-11 00:00:00 +0100", + "created_at": "2024-12-11 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 1048576, "knowledge_cutoff": null, @@ -21880,7 +21890,7 @@ "name": "Gemini 2.5 Flash", "provider": "openrouter", "family": "gemini-flash", - "created_at": "2025-07-17 00:00:00 +0200", + "created_at": "2025-07-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -22033,7 +22043,7 @@ "name": "Gemini 2.5 Flash Lite", "provider": "openrouter", "family": "gemini-flash-lite", - "created_at": "2025-06-17 00:00:00 +0200", + "created_at": "2025-06-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -22124,7 +22134,7 @@ "name": "Gemini 2.5 Flash Lite Preview 09-25", "provider": "openrouter", "family": "gemini-flash-lite", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -22215,7 +22225,7 @@ "name": "Gemini 2.5 Flash Preview 09-25", "provider": "openrouter", "family": "gemini-flash", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -22306,7 +22316,7 @@ "name": "Gemini 2.5 Pro", "provider": "openrouter", "family": "gemini-pro", - "created_at": "2025-03-20 00:00:00 +0100", + "created_at": "2025-03-20 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -22468,7 +22478,7 @@ "name": "Gemini 2.5 Pro Preview 05-06", "provider": "openrouter", "family": "gemini-pro", - "created_at": "2025-05-06 00:00:00 +0200", + "created_at": "2025-05-06 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -22559,7 +22569,7 @@ "name": "Gemini 2.5 Pro Preview 06-05", "provider": "openrouter", "family": "gemini-pro", - "created_at": "2025-06-05 00:00:00 +0200", + "created_at": "2025-06-05 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -22613,7 +22623,7 @@ "name": "Gemini 3 Flash Preview", "provider": "openrouter", "family": "gemini-flash", - "created_at": "2025-12-17 00:00:00 +0100", + "created_at": "2025-12-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -22772,7 +22782,7 @@ "name": "Gemini 3 Pro Preview", "provider": "openrouter", "family": "gemini-pro", - "created_at": "2025-11-18 00:00:00 +0100", + "created_at": "2025-11-18 00:00:00 +0300", "context_window": 1050000, "max_output_tokens": 66000, "knowledge_cutoff": null, @@ -22982,7 +22992,7 @@ "name": "Gemma 2 9B (free)", "provider": "openrouter", "family": "gemma", - "created_at": "2024-06-28 00:00:00 +0200", + "created_at": "2024-06-28 00:00:00 +0300", "context_window": 8192, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -23021,7 +23031,7 @@ "name": "Gemma 3 12B IT", "provider": "openrouter", "family": "gemma", - "created_at": "2025-03-13 00:00:00 +0100", + "created_at": "2025-03-13 00:00:00 +0300", "context_window": 96000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -23157,7 +23167,7 @@ "name": "Gemma 3 27B IT", "provider": "openrouter", "family": "gemma", - "created_at": "2025-03-12 00:00:00 +0100", + "created_at": "2025-03-12 00:00:00 +0300", "context_window": 96000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -23474,7 +23484,7 @@ "name": "Gemma 3n E4B IT", "provider": "openrouter", "family": "gemma", - "created_at": "2025-05-20 00:00:00 +0200", + "created_at": "2025-05-20 00:00:00 +0300", "context_window": 8192, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -23554,7 +23564,7 @@ "name": "Gemma 3n 4B (free)", "provider": "openrouter", "family": "gemma", - "created_at": "2025-05-20 00:00:00 +0200", + "created_at": "2025-05-20 00:00:00 +0300", "context_window": 8192, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -24059,7 +24069,7 @@ "name": "Kat Coder Pro (free)", "provider": "openrouter", "family": "kat-coder", - "created_at": "2025-11-10 00:00:00 +0100", + "created_at": "2025-11-10 00:00:00 +0300", "context_window": 256000, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -24796,7 +24806,7 @@ "name": "Llama 3.2 11B Vision Instruct", "provider": "openrouter", "family": "llama", - "created_at": "2024-09-25 00:00:00 +0200", + "created_at": "2024-09-25 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -25125,7 +25135,7 @@ "name": "Llama 3.3 70B Instruct (free)", "provider": "openrouter", "family": "llama", - "created_at": "2024-12-06 00:00:00 +0100", + "created_at": "2024-12-06 00:00:00 +0300", "context_window": 65536, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -25340,7 +25350,7 @@ "name": "Llama 4 Scout (free)", "provider": "openrouter", "family": "llama", - "created_at": "2025-04-05 00:00:00 +0200", + "created_at": "2025-04-05 00:00:00 +0300", "context_window": 64000, "max_output_tokens": 64000, "knowledge_cutoff": null, @@ -25569,7 +25579,7 @@ "name": "MAI DS R1 (free)", "provider": "openrouter", "family": "mai", - "created_at": "2025-04-21 00:00:00 +0200", + "created_at": "2025-04-21 00:00:00 +0300", "context_window": 163840, "max_output_tokens": 163840, "knowledge_cutoff": null, @@ -25736,7 +25746,7 @@ "name": "MiniMax-01", "provider": "openrouter", "family": "minimax", - "created_at": "2025-01-15 00:00:00 +0100", + "created_at": "2025-01-15 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 1000000, "knowledge_cutoff": null, @@ -25809,7 +25819,7 @@ "name": "MiniMax M1", "provider": "openrouter", "family": "minimax", - "created_at": "2025-06-17 00:00:00 +0200", + "created_at": "2025-06-17 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 40000, "knowledge_cutoff": null, @@ -25889,7 +25899,7 @@ "name": "MiniMax M2", "provider": "openrouter", "family": "minimax", - "created_at": "2025-10-23 00:00:00 +0200", + "created_at": "2025-10-23 00:00:00 +0300", "context_window": 196600, "max_output_tokens": 118000, "knowledge_cutoff": null, @@ -25979,7 +25989,7 @@ "name": "MiniMax M2.1", "provider": "openrouter", "family": "minimax", - "created_at": "2025-12-23 00:00:00 +0100", + "created_at": "2025-12-23 00:00:00 +0300", "context_window": 204800, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -26070,7 +26080,7 @@ "name": "Codestral 2508", "provider": "openrouter", "family": "codestral", - "created_at": "2025-08-01 00:00:00 +0200", + "created_at": "2025-08-01 00:00:00 +0300", "context_window": 256000, "max_output_tokens": 256000, "knowledge_cutoff": null, @@ -26149,7 +26159,7 @@ "name": "Devstral 2 2512", "provider": "openrouter", "family": "devstral", - "created_at": "2025-09-12 00:00:00 +0200", + "created_at": "2025-09-12 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -26230,7 +26240,7 @@ "name": "Devstral 2 2512 (free)", "provider": "openrouter", "family": "devstral", - "created_at": "2025-09-12 00:00:00 +0200", + "created_at": "2025-09-12 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -26366,7 +26376,7 @@ "name": "Devstral Medium", "provider": "openrouter", "family": "devstral", - "created_at": "2025-07-10 00:00:00 +0200", + "created_at": "2025-07-10 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -26476,7 +26486,7 @@ "name": "Devstral Small", "provider": "openrouter", "family": "devstral", - "created_at": "2025-05-07 00:00:00 +0200", + "created_at": "2025-05-07 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -26522,7 +26532,7 @@ "name": "Devstral Small 2505 (free)", "provider": "openrouter", "family": "devstral", - "created_at": "2025-05-21 00:00:00 +0200", + "created_at": "2025-05-21 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -26561,7 +26571,7 @@ "name": "Devstral Small 1.1", "provider": "openrouter", "family": "devstral", - "created_at": "2025-07-10 00:00:00 +0200", + "created_at": "2025-07-10 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -27183,7 +27193,7 @@ "name": "Mistral 7B Instruct (free)", "provider": "openrouter", "family": "mistral", - "created_at": "2024-05-27 00:00:00 +0200", + "created_at": "2024-05-27 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -27480,7 +27490,7 @@ "name": "Mistral Medium 3", "provider": "openrouter", "family": "mistral-medium", - "created_at": "2025-05-07 00:00:00 +0200", + "created_at": "2025-05-07 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -27562,7 +27572,7 @@ "name": "Mistral Medium 3.1", "provider": "openrouter", "family": "mistral-medium", - "created_at": "2025-08-12 00:00:00 +0200", + "created_at": "2025-08-12 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -27710,7 +27720,7 @@ "name": "Mistral Nemo (free)", "provider": "openrouter", "family": "mistral-nemo", - "created_at": "2024-07-19 00:00:00 +0200", + "created_at": "2024-07-19 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -27882,7 +27892,7 @@ "name": "Mistral Small 3.1 24B Instruct", "provider": "openrouter", "family": "mistral-small", - "created_at": "2025-03-17 00:00:00 +0100", + "created_at": "2025-03-17 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -28025,7 +28035,7 @@ "name": "Mistral Small 3.2 24B Instruct", "provider": "openrouter", "family": "mistral-small", - "created_at": "2025-06-20 00:00:00 +0200", + "created_at": "2025-06-20 00:00:00 +0300", "context_window": 96000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -28112,7 +28122,7 @@ "name": "Mistral Small 3.2 24B (free)", "provider": "openrouter", "family": "mistral-small", - "created_at": "2025-06-20 00:00:00 +0200", + "created_at": "2025-06-20 00:00:00 +0300", "context_window": 96000, "max_output_tokens": 96000, "knowledge_cutoff": null, @@ -28666,7 +28676,7 @@ "name": "Kimi Dev 72b (free)", "provider": "openrouter", "family": "kimi", - "created_at": "2025-06-16 00:00:00 +0200", + "created_at": "2025-06-16 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -28705,7 +28715,7 @@ "name": "Kimi K2", "provider": "openrouter", "family": "kimi", - "created_at": "2025-07-11 00:00:00 +0200", + "created_at": "2025-07-11 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -28789,7 +28799,7 @@ "name": "Kimi K2 Instruct 0905", "provider": "openrouter", "family": "kimi", - "created_at": "2025-09-05 00:00:00 +0200", + "created_at": "2025-09-05 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -28875,7 +28885,7 @@ "name": "Kimi K2 Instruct 0905 (exacto)", "provider": "openrouter", "family": "kimi", - "created_at": "2025-09-05 00:00:00 +0200", + "created_at": "2025-09-05 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -28954,7 +28964,7 @@ "name": "Kimi K2 Thinking", "provider": "openrouter", "family": "kimi-thinking", - "created_at": "2025-11-06 00:00:00 +0100", + "created_at": "2025-11-06 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -29048,7 +29058,7 @@ "name": "Kimi K2 (free)", "provider": "openrouter", "family": "kimi", - "created_at": "2025-07-11 00:00:00 +0200", + "created_at": "2025-07-11 00:00:00 +0300", "context_window": 32800, "max_output_tokens": 32800, "knowledge_cutoff": null, @@ -29410,7 +29420,7 @@ "name": "DeepHermes 3 Llama 3 8B Preview", "provider": "openrouter", "family": "llama", - "created_at": "2025-02-28 00:00:00 +0100", + "created_at": "2025-02-28 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -29759,7 +29769,7 @@ "name": "Hermes 4 405B", "provider": "openrouter", "family": "hermes", - "created_at": "2025-08-25 00:00:00 +0200", + "created_at": "2025-08-25 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -29838,7 +29848,7 @@ "name": "Hermes 4 70B", "provider": "openrouter", "family": "hermes", - "created_at": "2025-08-25 00:00:00 +0200", + "created_at": "2025-08-25 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -30367,7 +30377,7 @@ "name": "nvidia-nemotron-nano-9b-v2", "provider": "openrouter", "family": "nemotron", - "created_at": "2025-08-18 00:00:00 +0200", + "created_at": "2025-08-18 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -31177,7 +31187,7 @@ "name": "GPT-4.1", "provider": "openrouter", "family": "gpt", - "created_at": "2025-04-14 00:00:00 +0200", + "created_at": "2025-04-14 00:00:00 +0300", "context_window": 1047576, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -31259,7 +31269,7 @@ "name": "GPT-4.1 Mini", "provider": "openrouter", "family": "gpt-mini", - "created_at": "2025-04-14 00:00:00 +0200", + "created_at": "2025-04-14 00:00:00 +0300", "context_window": 1047576, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -31767,7 +31777,7 @@ "name": "GPT-4o-mini", "provider": "openrouter", "family": "gpt-mini", - "created_at": "2024-07-18 00:00:00 +0200", + "created_at": "2024-07-18 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -32113,7 +32123,7 @@ "name": "GPT-5", "provider": "openrouter", "family": "gpt", - "created_at": "2025-08-07 00:00:00 +0200", + "created_at": "2025-08-07 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-10-01", @@ -32194,7 +32204,7 @@ "name": "GPT-5 Chat (latest)", "provider": "openrouter", "family": "gpt-codex", - "created_at": "2025-08-07 00:00:00 +0200", + "created_at": "2025-08-07 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -32270,7 +32280,7 @@ "name": "GPT-5 Codex", "provider": "openrouter", "family": "gpt-codex", - "created_at": "2025-09-15 00:00:00 +0200", + "created_at": "2025-09-15 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-10-01", @@ -32352,7 +32362,7 @@ "name": "GPT-5 Image", "provider": "openrouter", "family": "gpt", - "created_at": "2025-10-14 00:00:00 +0200", + "created_at": "2025-10-14 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-10-01", @@ -32522,7 +32532,7 @@ "name": "GPT-5 Mini", "provider": "openrouter", "family": "gpt-mini", - "created_at": "2025-08-07 00:00:00 +0200", + "created_at": "2025-08-07 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-10-01", @@ -32603,7 +32613,7 @@ "name": "GPT-5 Nano", "provider": "openrouter", "family": "gpt-nano", - "created_at": "2025-08-07 00:00:00 +0200", + "created_at": "2025-08-07 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-10-01", @@ -32684,7 +32694,7 @@ "name": "GPT-5 Pro", "provider": "openrouter", "family": "gpt-pro", - "created_at": "2025-10-06 00:00:00 +0200", + "created_at": "2025-10-06 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 272000, "knowledge_cutoff": "2024-09-30", @@ -32765,7 +32775,7 @@ "name": "GPT-5.1", "provider": "openrouter", "family": "gpt", - "created_at": "2025-11-13 00:00:00 +0100", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -32848,7 +32858,7 @@ "name": "GPT-5.1 Chat", "provider": "openrouter", "family": "gpt-codex", - "created_at": "2025-11-13 00:00:00 +0100", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": "2024-09-30", @@ -32929,7 +32939,7 @@ "name": "GPT-5.1-Codex", "provider": "openrouter", "family": "gpt-codex", - "created_at": "2025-11-13 00:00:00 +0100", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2024-09-30", @@ -33008,13 +33018,13 @@ }, { "id": "openai/gpt-5.1-codex-max", - "name": "OpenAI: GPT-5.1-Codex-Max", + "name": "GPT-5.1-Codex-Max", "provider": "openrouter", - "family": "openai", - "created_at": "2025-12-04 21:08:54 +0100", + "family": "gpt-codex", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, - "knowledge_cutoff": null, + "knowledge_cutoff": "2024-09-30", "modalities": { "input": [ "text", @@ -33025,16 +33035,18 @@ ] }, "capabilities": [ - "streaming", "function_calling", - "structured_output" + "structured_output", + "reasoning", + "vision", + "streaming" ], "pricing": { "text_tokens": { "standard": { - "input_per_million": 1.25, - "output_per_million": 10.0, - "cached_input_per_million": 0.125 + "input_per_million": 1.1, + "output_per_million": 9, + "cached_input_per_million": 0.11 } } }, @@ -33067,7 +33079,23 @@ "structured_outputs", "tool_choice", "tools" - ] + ], + "source": "models.dev", + "provider_id": "openrouter", + "open_weights": false, + "attachment": true, + "temperature": true, + "last_updated": "2025-11-13", + "cost": { + "input": 1.1, + "output": 9, + "cache_read": 0.11 + }, + "limit": { + "context": 400000, + "output": 128000 + }, + "knowledge": "2024-09-30" } }, { @@ -33075,7 +33103,7 @@ "name": "GPT-5.1-Codex-Mini", "provider": "openrouter", "family": "gpt-codex", - "created_at": "2025-11-13 00:00:00 +0100", + "created_at": "2025-11-13 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 100000, "knowledge_cutoff": "2024-09-30", @@ -33157,7 +33185,7 @@ "name": "GPT-5.2", "provider": "openrouter", "family": "gpt", - "created_at": "2025-12-11 00:00:00 +0100", + "created_at": "2025-12-11 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2025-08-31", @@ -33304,7 +33332,7 @@ "name": "GPT-5.2 Chat", "provider": "openrouter", "family": "gpt-codex", - "created_at": "2025-12-11 00:00:00 +0100", + "created_at": "2025-12-11 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 16384, "knowledge_cutoff": "2025-08-31", @@ -33356,7 +33384,7 @@ "name": "GPT-5.2-Codex", "provider": "openrouter", "family": "gpt-codex", - "created_at": "2026-01-14 00:00:00 +0100", + "created_at": "2026-01-14 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2025-08-31", @@ -33444,7 +33472,7 @@ "name": "GPT-5.2 Pro", "provider": "openrouter", "family": "gpt-pro", - "created_at": "2025-12-11 00:00:00 +0100", + "created_at": "2025-12-11 00:00:00 +0300", "context_window": 400000, "max_output_tokens": 128000, "knowledge_cutoff": "2025-08-31", @@ -33525,7 +33553,7 @@ "name": "GPT OSS 120B", "provider": "openrouter", "family": "gpt-oss", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -33614,7 +33642,7 @@ "name": "GPT OSS 120B (exacto)", "provider": "openrouter", "family": "gpt-oss", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -33751,7 +33779,7 @@ "name": "GPT OSS 20B", "provider": "openrouter", "family": "gpt-oss", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -33891,7 +33919,7 @@ "name": "GPT OSS Safeguard 20B", "provider": "openrouter", "family": "gpt-oss", - "created_at": "2025-10-29 00:00:00 +0100", + "created_at": "2025-10-29 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -34424,7 +34452,7 @@ "name": "o4 Mini", "provider": "openrouter", "family": "o-mini", - "created_at": "2025-04-16 00:00:00 +0200", + "created_at": "2025-04-16 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 100000, "knowledge_cutoff": null, @@ -34798,7 +34826,7 @@ "name": "Sherlock Dash Alpha", "provider": "openrouter", "family": "sherlock", - "created_at": "2025-11-15 00:00:00 +0100", + "created_at": "2025-11-15 00:00:00 +0300", "context_window": 1840000, "max_output_tokens": 0, "knowledge_cutoff": null, @@ -34839,7 +34867,7 @@ "name": "Sherlock Think Alpha", "provider": "openrouter", "family": "sherlock", - "created_at": "2025-11-15 00:00:00 +0100", + "created_at": "2025-11-15 00:00:00 +0300", "context_window": 1840000, "max_output_tokens": 0, "knowledge_cutoff": null, @@ -35392,7 +35420,7 @@ "name": "Qwen2.5 Coder 32B Instruct", "provider": "openrouter", "family": "qwen", - "created_at": "2024-11-11 00:00:00 +0100", + "created_at": "2024-11-11 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -36155,7 +36183,7 @@ "name": "Qwen2.5 VL 32B Instruct (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-03-24 00:00:00 +0100", + "created_at": "2025-03-24 00:00:00 +0300", "context_window": 8192, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -36197,7 +36225,7 @@ "name": "Qwen2.5 VL 72B Instruct", "provider": "openrouter", "family": "qwen", - "created_at": "2025-02-01 00:00:00 +0100", + "created_at": "2025-02-01 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -36281,7 +36309,7 @@ "name": "Qwen2.5 VL 72B Instruct (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-02-01 00:00:00 +0100", + "created_at": "2025-02-01 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -36391,7 +36419,7 @@ "name": "Qwen3 14B (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-04-28 00:00:00 +0200", + "created_at": "2025-04-28 00:00:00 +0300", "context_window": 40960, "max_output_tokens": 40960, "knowledge_cutoff": null, @@ -36504,7 +36532,7 @@ "name": "Qwen3 235B A22B Instruct 2507", "provider": "openrouter", "family": "qwen", - "created_at": "2025-04-28 00:00:00 +0200", + "created_at": "2025-04-28 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -36550,7 +36578,7 @@ "name": "Qwen3 235B A22B Instruct 2507 (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-04-28 00:00:00 +0200", + "created_at": "2025-04-28 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -36663,7 +36691,7 @@ "name": "Qwen3 235B A22B Thinking 2507", "provider": "openrouter", "family": "qwen", - "created_at": "2025-07-25 00:00:00 +0200", + "created_at": "2025-07-25 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 81920, "knowledge_cutoff": null, @@ -36750,7 +36778,7 @@ "name": "Qwen3 235B A22B (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-04-28 00:00:00 +0200", + "created_at": "2025-04-28 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -36863,7 +36891,7 @@ "name": "Qwen3 30B A3B Instruct 2507", "provider": "openrouter", "family": "qwen", - "created_at": "2025-07-29 00:00:00 +0200", + "created_at": "2025-07-29 00:00:00 +0300", "context_window": 262000, "max_output_tokens": 262000, "knowledge_cutoff": null, @@ -36944,7 +36972,7 @@ "name": "Qwen3 30B A3B Thinking 2507", "provider": "openrouter", "family": "qwen", - "created_at": "2025-07-29 00:00:00 +0200", + "created_at": "2025-07-29 00:00:00 +0300", "context_window": 262000, "max_output_tokens": 262000, "knowledge_cutoff": null, @@ -37027,7 +37055,7 @@ "name": "Qwen3 30B A3B (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-04-28 00:00:00 +0200", + "created_at": "2025-04-28 00:00:00 +0300", "context_window": 40960, "max_output_tokens": 40960, "knowledge_cutoff": null, @@ -37138,7 +37166,7 @@ "name": "Qwen3 32B (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-04-28 00:00:00 +0200", + "created_at": "2025-04-28 00:00:00 +0300", "context_window": 40960, "max_output_tokens": 40960, "knowledge_cutoff": null, @@ -37308,7 +37336,7 @@ "name": "Qwen3 8B (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-04-28 00:00:00 +0200", + "created_at": "2025-04-28 00:00:00 +0300", "context_window": 40960, "max_output_tokens": 40960, "knowledge_cutoff": null, @@ -37348,7 +37376,7 @@ "name": "Qwen3 Coder", "provider": "openrouter", "family": "qwen", - "created_at": "2025-07-23 00:00:00 +0200", + "created_at": "2025-07-23 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 66536, "knowledge_cutoff": null, @@ -37435,7 +37463,7 @@ "name": "Qwen3 Coder 30B A3B Instruct", "provider": "openrouter", "family": "qwen", - "created_at": "2025-07-31 00:00:00 +0200", + "created_at": "2025-07-31 00:00:00 +0300", "context_window": 160000, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -37516,7 +37544,7 @@ "name": "Qwen3 Coder Flash", "provider": "openrouter", "family": "qwen", - "created_at": "2025-07-23 00:00:00 +0200", + "created_at": "2025-07-23 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 66536, "knowledge_cutoff": null, @@ -37655,7 +37683,7 @@ "name": "Qwen3 Coder (exacto)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-07-23 00:00:00 +0200", + "created_at": "2025-07-23 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -37737,7 +37765,7 @@ "name": "Qwen3 Coder 480B A35B Instruct (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-07-23 00:00:00 +0200", + "created_at": "2025-07-23 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 66536, "knowledge_cutoff": null, @@ -37807,7 +37835,7 @@ "name": "Qwen3 Max", "provider": "openrouter", "family": "qwen", - "created_at": "2025-09-05 00:00:00 +0200", + "created_at": "2025-09-05 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -37883,7 +37911,7 @@ "name": "Qwen3 Next 80B A3B Instruct", "provider": "openrouter", "family": "qwen", - "created_at": "2025-09-11 00:00:00 +0200", + "created_at": "2025-09-11 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -38024,7 +38052,7 @@ "name": "Qwen3 Next 80B A3B Thinking", "provider": "openrouter", "family": "qwen", - "created_at": "2025-09-11 00:00:00 +0200", + "created_at": "2025-09-11 00:00:00 +0300", "context_window": 262144, "max_output_tokens": 262144, "knowledge_cutoff": null, @@ -38672,7 +38700,7 @@ "name": "QwQ 32B (free)", "provider": "openrouter", "family": "qwen", - "created_at": "2025-03-05 00:00:00 +0100", + "created_at": "2025-03-05 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -38775,7 +38803,7 @@ "name": "Reka Flash 3", "provider": "openrouter", "family": "reka", - "created_at": "2025-03-12 00:00:00 +0100", + "created_at": "2025-03-12 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -39249,7 +39277,7 @@ "name": "Sarvam-M (free)", "provider": "openrouter", "family": "sarvam", - "created_at": "2025-05-25 00:00:00 +0200", + "created_at": "2025-05-25 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -39732,7 +39760,7 @@ "name": "GLM Z1 32B (free)", "provider": "openrouter", "family": "glm-z", - "created_at": "2025-04-17 00:00:00 +0200", + "created_at": "2025-04-17 00:00:00 +0300", "context_window": 32768, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -39960,7 +39988,7 @@ "name": "DeepSeek R1T2 Chimera (free)", "provider": "openrouter", "family": "deepseek-thinking", - "created_at": "2025-07-08 00:00:00 +0200", + "created_at": "2025-07-08 00:00:00 +0300", "context_window": 163840, "max_output_tokens": 163840, "knowledge_cutoff": null, @@ -40229,7 +40257,7 @@ "name": "Grok 3", "provider": "openrouter", "family": "grok", - "created_at": "2025-02-17 00:00:00 +0100", + "created_at": "2025-02-17 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -40313,7 +40341,7 @@ "name": "Grok 3 Beta", "provider": "openrouter", "family": "grok", - "created_at": "2025-02-17 00:00:00 +0100", + "created_at": "2025-02-17 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -40396,7 +40424,7 @@ "name": "Grok 3 Mini", "provider": "openrouter", "family": "grok", - "created_at": "2025-02-17 00:00:00 +0100", + "created_at": "2025-02-17 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -40481,7 +40509,7 @@ "name": "Grok 3 Mini Beta", "provider": "openrouter", "family": "grok", - "created_at": "2025-02-17 00:00:00 +0100", + "created_at": "2025-02-17 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -40565,7 +40593,7 @@ "name": "Grok 4", "provider": "openrouter", "family": "grok", - "created_at": "2025-07-09 00:00:00 +0200", + "created_at": "2025-07-09 00:00:00 +0300", "context_window": 256000, "max_output_tokens": 64000, "knowledge_cutoff": null, @@ -40650,7 +40678,7 @@ "name": "Grok 4 Fast", "provider": "openrouter", "family": "grok", - "created_at": "2025-08-19 00:00:00 +0200", + "created_at": "2025-08-19 00:00:00 +0300", "context_window": 2000000, "max_output_tokens": 30000, "knowledge_cutoff": null, @@ -40737,7 +40765,7 @@ "name": "Grok 4.1 Fast", "provider": "openrouter", "family": "grok", - "created_at": "2025-11-19 00:00:00 +0100", + "created_at": "2025-11-19 00:00:00 +0300", "context_window": 2000000, "max_output_tokens": 30000, "knowledge_cutoff": null, @@ -40824,7 +40852,7 @@ "name": "Grok Code Fast 1", "provider": "openrouter", "family": "grok", - "created_at": "2025-08-26 00:00:00 +0200", + "created_at": "2025-08-26 00:00:00 +0300", "context_window": 256000, "max_output_tokens": 10000, "knowledge_cutoff": null, @@ -41091,7 +41119,7 @@ "name": "GLM 4.5", "provider": "openrouter", "family": "glm", - "created_at": "2025-07-28 00:00:00 +0200", + "created_at": "2025-07-28 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 96000, "knowledge_cutoff": null, @@ -41175,7 +41203,7 @@ "name": "GLM 4.5 Air", "provider": "openrouter", "family": "glm-air", - "created_at": "2025-07-28 00:00:00 +0200", + "created_at": "2025-07-28 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 96000, "knowledge_cutoff": null, @@ -41259,7 +41287,7 @@ "name": "GLM 4.5 Air (free)", "provider": "openrouter", "family": "glm-air", - "created_at": "2025-07-28 00:00:00 +0200", + "created_at": "2025-07-28 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 96000, "knowledge_cutoff": null, @@ -41327,7 +41355,7 @@ "name": "GLM 4.5V", "provider": "openrouter", "family": "glm", - "created_at": "2025-08-11 00:00:00 +0200", + "created_at": "2025-08-11 00:00:00 +0300", "context_window": 64000, "max_output_tokens": 16384, "knowledge_cutoff": null, @@ -41415,7 +41443,7 @@ "name": "GLM 4.6", "provider": "openrouter", "family": "glm", - "created_at": "2025-09-30 00:00:00 +0200", + "created_at": "2025-09-30 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -41507,7 +41535,7 @@ "name": "GLM 4.6 (exacto)", "provider": "openrouter", "family": "glm", - "created_at": "2025-09-30 00:00:00 +0200", + "created_at": "2025-09-30 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 128000, "knowledge_cutoff": null, @@ -41668,7 +41696,7 @@ "name": "GLM-4.7", "provider": "openrouter", "family": "glm", - "created_at": "2025-12-22 00:00:00 +0100", + "created_at": "2025-12-22 00:00:00 +0300", "context_window": 204800, "max_output_tokens": 131072, "knowledge_cutoff": null, @@ -41763,7 +41791,7 @@ "name": "Sonar", "provider": "perplexity", "family": "sonar", - "created_at": "2024-01-01 00:00:00 +0100", + "created_at": "2024-01-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": "2025-09-01", @@ -41846,7 +41874,7 @@ "name": "Sonar Pro", "provider": "perplexity", "family": "sonar-pro", - "created_at": "2024-01-01 00:00:00 +0100", + "created_at": "2024-01-01 00:00:00 +0300", "context_window": 200000, "max_output_tokens": 8192, "knowledge_cutoff": "2025-09-01", @@ -41927,7 +41955,7 @@ "name": "Sonar Reasoning Pro", "provider": "perplexity", "family": "sonar-reasoning", - "created_at": "2024-01-01 00:00:00 +0100", + "created_at": "2024-01-01 00:00:00 +0300", "context_window": 128000, "max_output_tokens": 4096, "knowledge_cutoff": "2025-09-01", @@ -41977,7 +42005,7 @@ "name": "Gemini 1.5 Flash", "provider": "vertexai", "family": "gemini-flash", - "created_at": "2024-05-14 00:00:00 +0200", + "created_at": "2024-05-14 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -42044,55 +42072,7 @@ ], "pricing": {}, "metadata": { - "version_id": "default", - "open_source_category": "PROPRIETARY", - "launch_stage": "GA", - "supported_actions": { - "openNotebook": { - "references": { - "global": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_1_5_flash.ipynb" - } - }, - "title": "Open Notebook" - }, - "openGenerationAiStudio": { - "references": { - "global": { - "uri": "https://console.cloud.google.com/vertex-ai/studio/freeform?model=gemini-1.5-flash-002" - } - } - }, - "openEvaluationPipeline": { - "references": { - "global": { - "uri": "https://console.cloud.google.com/vertex-ai/pipelines/vertex-ai-templates/autosxs-template" - } - }, - "title": "Evaluate" - }, - "openNotebooks": { - "notebooks": [ - { - "references": { - "global": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_1_5_flash.ipynb" - } - }, - "title": "Open Notebook" - }, - { - "references": { - "global": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_1_5_flash.ipynb" - } - }, - "title": "Open Notebook" - } - ] - } - }, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-1.5-flash-002@default" + "source": "known_models" } }, { @@ -42100,7 +42080,7 @@ "name": "Gemini 1.5 Flash-8B", "provider": "vertexai", "family": "gemini-flash", - "created_at": "2024-10-03 00:00:00 +0200", + "created_at": "2024-10-03 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -42153,7 +42133,7 @@ "name": "Gemini 1.5 Pro", "provider": "vertexai", "family": "gemini-pro", - "created_at": "2024-02-15 00:00:00 +0100", + "created_at": "2024-02-15 00:00:00 +0300", "context_window": 1000000, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -42220,72 +42200,7 @@ ], "pricing": {}, "metadata": { - "version_id": "default", - "open_source_category": "PROPRIETARY", - "launch_stage": "GA", - "supported_actions": { - "openNotebook": { - "references": { - "us-central1": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/use-cases/retail/product_attributes_extraction.ipynb" - } - }, - "title": "Open Notebook", - "resourceTitle": "Notebook", - "resourceUseCase": "Product Attributes Extraction", - "resourceDescription": "Extract product descriptions and attribute json from images using Gemini 1.5 Pro. This notebook also shows the use of self-correcting prompt to improve the quality of the output." - }, - "openGenerationAiStudio": { - "references": { - "us-central1": { - "uri": "https://console.cloud.google.com/vertex-ai/studio/freeform?model=gemini-1.5-pro-002" - } - } - }, - "openEvaluationPipeline": { - "references": { - "us-central1": { - "uri": "https://console.cloud.google.com/vertex-ai/pipelines/vertex-ai-templates/autosxs-template" - } - }, - "title": "Evaluate" - }, - "openNotebooks": { - "notebooks": [ - { - "references": { - "us-central1": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_1_5_pro.ipynb" - } - }, - "title": "Open Notebook" - }, - { - "references": { - "us-central1": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_1_5_pro.ipynb" - } - }, - "title": "Open Notebook", - "resourceTitle": "Notebook", - "resourceUseCase": "Vertex AI Gemini API 1.5 Pro", - "resourceDescription": "Use the Vertex AI Gemini API 1.5 Pro model to process images, video, audio, and text simultaneously." - }, - { - "references": { - "us-central1": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/use-cases/retail/product_attributes_extraction.ipynb" - } - }, - "title": "Open Notebook", - "resourceTitle": "Notebook", - "resourceUseCase": "Product Attributes Extraction", - "resourceDescription": "Extract product descriptions and attribute json from images using Gemini 1.5 Pro. This notebook also shows the use of self-correcting prompt to improve the quality of the output." - } - ] - } - }, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-1.5-pro-002@default" + "source": "known_models" } }, { @@ -42293,7 +42208,7 @@ "name": "Gemini 2.0 Flash", "provider": "vertexai", "family": "gemini-flash", - "created_at": "2024-12-11 00:00:00 +0100", + "created_at": "2024-12-11 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -42317,8 +42232,8 @@ "pricing": { "text_tokens": { "standard": { - "input_per_million": 0.1, - "output_per_million": 0.4, + "input_per_million": 0.15, + "output_per_million": 0.6, "cached_input_per_million": 0.025 } } @@ -42331,8 +42246,8 @@ "temperature": true, "last_updated": "2024-12-11", "cost": { - "input": 0.1, - "output": 0.4, + "input": 0.15, + "output": 0.6, "cache_read": 0.025 }, "limit": { @@ -42361,43 +42276,7 @@ ], "pricing": {}, "metadata": { - "version_id": "default", - "open_source_category": null, - "launch_stage": "GA", - "supported_actions": { - "openNotebook": { - "references": { - "us-central1": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_2_0_flash.ipynb" - } - }, - "resourceTitle": "Notebook", - "resourceUseCase": "Vertex Serving", - "resourceDescription": "Intro to Gemini 2.0 Flash." - }, - "openGenerationAiStudio": { - "references": { - "us-central1": { - "uri": "https://console.cloud.google.com/vertex-ai/generative/multimodal/create/text?model=gemini-2.0-flash-001" - } - } - }, - "openNotebooks": { - "notebooks": [ - { - "references": { - "us-central1": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_2_0_flash.ipynb" - } - }, - "resourceTitle": "Notebook", - "resourceUseCase": "Vertex Serving", - "resourceDescription": "Intro to Gemini 2.0 Flash." - } - ] - } - }, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-2.0-flash-001@default" + "source": "known_models" } }, { @@ -42427,7 +42306,7 @@ "name": "Gemini 2.0 Flash Lite", "provider": "vertexai", "family": "gemini-flash-lite", - "created_at": "2024-12-11 00:00:00 +0100", + "created_at": "2024-12-11 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 8192, "knowledge_cutoff": null, @@ -42492,37 +42371,7 @@ ], "pricing": {}, "metadata": { - "version_id": "default", - "open_source_category": null, - "launch_stage": "GA", - "supported_actions": null, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-2.0-flash-lite-001@default" - } - }, - { - "id": "gemini-2.0-flash-preview-image-generation", - "name": "gemini-2.0-flash-preview-image-generation", - "provider": "vertexai", - "family": "gemini-2", - "created_at": null, - "context_window": null, - "max_output_tokens": null, - "knowledge_cutoff": null, - "modalities": { - "input": [], - "output": [] - }, - "capabilities": [ - "streaming", - "function_calling" - ], - "pricing": {}, - "metadata": { - "version_id": "default", - "open_source_category": null, - "launch_stage": null, - "supported_actions": null, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-2.0-flash-preview-image-generation@default" + "source": "known_models" } }, { @@ -42530,7 +42379,7 @@ "name": "Gemini 2.5 Flash", "provider": "vertexai", "family": "gemini-flash", - "created_at": "2025-06-17 00:00:00 +0200", + "created_at": "2025-06-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -42562,11 +42411,6 @@ } }, "metadata": { - "version_id": "default", - "open_source_category": null, - "launch_stage": "GA", - "supported_actions": null, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-2.5-flash@default", "source": "models.dev", "provider_id": "google-vertex", "open_weights": false, @@ -42591,7 +42435,7 @@ "name": "Gemini 2.5 Flash Lite", "provider": "vertexai", "family": "gemini-flash-lite", - "created_at": "2025-06-17 00:00:00 +0200", + "created_at": "2025-06-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -42623,11 +42467,6 @@ } }, "metadata": { - "version_id": "default", - "open_source_category": null, - "launch_stage": "GA", - "supported_actions": null, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-2.5-flash-lite@default", "source": "models.dev", "provider_id": "google-vertex", "open_weights": false, @@ -42651,7 +42490,7 @@ "name": "Gemini 2.5 Flash Lite Preview 06-17", "provider": "vertexai", "family": "gemini-flash-lite", - "created_at": "2025-06-17 00:00:00 +0200", + "created_at": "2025-06-17 00:00:00 +0300", "context_window": 65536, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -42705,7 +42544,7 @@ "name": "Gemini 2.5 Flash Lite Preview 09-25", "provider": "vertexai", "family": "gemini-flash-lite", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -42759,7 +42598,7 @@ "name": "Gemini 2.5 Flash Preview 04-17", "provider": "vertexai", "family": "gemini-flash", - "created_at": "2025-04-17 00:00:00 +0200", + "created_at": "2025-04-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -42778,8 +42617,7 @@ "capabilities": [ "function_calling", "reasoning", - "vision", - "streaming" + "vision" ], "pricing": { "text_tokens": { @@ -42791,19 +42629,6 @@ } }, "metadata": { - "version_id": "default", - "open_source_category": null, - "launch_stage": "PUBLIC_PREVIEW", - "supported_actions": { - "openGenerationAiStudio": { - "references": { - "us-central1": { - "uri": "https://console.cloud.google.com/vertex-ai/generative/multimodal/create/text?model=gemini-2.5-flash-preview-04-17" - } - } - } - }, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-2.5-flash-preview-04-17@default", "source": "models.dev", "provider_id": "google-vertex", "open_weights": false, @@ -42827,7 +42652,7 @@ "name": "Gemini 2.5 Flash Preview 05-20", "provider": "vertexai", "family": "gemini-flash", - "created_at": "2025-05-20 00:00:00 +0200", + "created_at": "2025-05-20 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -42881,7 +42706,7 @@ "name": "Gemini 2.5 Flash Preview 09-25", "provider": "vertexai", "family": "gemini-flash", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -42936,7 +42761,7 @@ "name": "Gemini 2.5 Pro", "provider": "vertexai", "family": "gemini-pro", - "created_at": "2025-03-20 00:00:00 +0100", + "created_at": "2025-03-20 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -42968,11 +42793,6 @@ } }, "metadata": { - "version_id": "default", - "open_source_category": null, - "launch_stage": "GA", - "supported_actions": null, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-2.5-pro@default", "source": "models.dev", "provider_id": "google-vertex", "open_weights": false, @@ -42991,70 +42811,12 @@ "knowledge": "2025-01" } }, - { - "id": "gemini-2.5-pro-exp-03-25", - "name": "gemini-2.5-pro-exp-03-25", - "provider": "vertexai", - "family": "gemini-2", - "created_at": null, - "context_window": null, - "max_output_tokens": null, - "knowledge_cutoff": null, - "modalities": { - "input": [], - "output": [] - }, - "capabilities": [ - "streaming", - "function_calling" - ], - "pricing": {}, - "metadata": { - "version_id": "default", - "open_source_category": null, - "launch_stage": "EXPERIMENTAL", - "supported_actions": { - "openNotebook": { - "references": { - "us-central1": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_2_5_pro.ipynb" - } - }, - "resourceTitle": "Notebook", - "resourceUseCase": "Vertex Serving", - "resourceDescription": "Intro to Gemini 2.5 Pro." - }, - "openGenerationAiStudio": { - "references": { - "us-central1": { - "uri": "https://console.cloud.google.com/vertex-ai/generative/multimodal/create/text?model=gemini-2.5-pro-exp-03-25" - } - } - }, - "openNotebooks": { - "notebooks": [ - { - "references": { - "us-central1": { - "uri": "https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_2_5_pro.ipynb" - } - }, - "resourceTitle": "Notebook", - "resourceUseCase": "Vertex Serving", - "resourceDescription": "Intro to Gemini 2.5 Pro." - } - ] - } - }, - "publisher_model_template": "projects/{project}/locations/{location}/publishers/google/models/gemini-2.5-pro-exp-03-25@default" - } - }, { "id": "gemini-2.5-pro-preview-05-06", "name": "Gemini 2.5 Pro Preview 05-06", "provider": "vertexai", "family": "gemini-pro", - "created_at": "2025-05-06 00:00:00 +0200", + "created_at": "2025-05-06 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -43108,7 +42870,7 @@ "name": "Gemini 2.5 Pro Preview 06-05", "provider": "vertexai", "family": "gemini-pro", - "created_at": "2025-06-05 00:00:00 +0200", + "created_at": "2025-06-05 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -43162,7 +42924,7 @@ "name": "Gemini 3 Flash Preview", "provider": "vertexai", "family": "gemini-flash", - "created_at": "2025-12-17 00:00:00 +0100", + "created_at": "2025-12-17 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -43222,7 +42984,7 @@ "name": "Gemini 3 Pro Preview", "provider": "vertexai", "family": "gemini-pro", - "created_at": "2025-11-18 00:00:00 +0100", + "created_at": "2025-11-18 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -43282,7 +43044,7 @@ "name": "Gemini Embedding 001", "provider": "vertexai", "family": "gemini", - "created_at": "2025-05-20 00:00:00 +0200", + "created_at": "2025-05-20 00:00:00 +0300", "context_window": 2048, "max_output_tokens": 3072, "knowledge_cutoff": null, @@ -43372,7 +43134,7 @@ "name": "Gemini Flash Latest", "provider": "vertexai", "family": "gemini-flash", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -43427,7 +43189,7 @@ "name": "Gemini Flash-Lite Latest", "provider": "vertexai", "family": "gemini-flash-lite", - "created_at": "2025-09-25 00:00:00 +0200", + "created_at": "2025-09-25 00:00:00 +0300", "context_window": 1048576, "max_output_tokens": 65536, "knowledge_cutoff": null, @@ -43520,12 +43282,168 @@ "source": "known_models" } }, + { + "id": "multimodalembedding", + "name": "multimodalembedding", + "provider": "vertexai", + "family": "multimodalembedding", + "created_at": null, + "context_window": 32, + "max_output_tokens": 1048, + "knowledge_cutoff": null, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "embeddings" + ] + }, + "capabilities": [ + "vision" + ], + "pricing": { + "text_tokens": { + "standard": { + "input_per_million": 0.2 + } + }, + "images": { + "standard": { + "input": 0.0001 + } + } + }, + "metadata": { + "source": "known_models", + "model_type": "embedding", + "modality_limits": { + "text": { + "max_tokens": 32, + "description": "Text input limited to 32 tokens" + }, + "image": { + "max_count": 1, + "max_size_mb": 20, + "formats": [ + "bmp", + "gif", + "jpeg", + "png" + ], + "description": "Single image up to 20MB" + }, + "video": { + "max_duration_seconds": 120, + "formats": [ + "avi", + "flv", + "mkv", + "mov", + "mp4", + "mpeg", + "mpg", + "webm", + "wmv" + ], + "description": "Video up to 120 seconds" + } + }, + "max_embedding_dimensions": 1408, + "allowed_dimensions": { + "text": { + "default": 1408, + "options": [ + 128, + 256, + 512, + 1408 + ], + "description": "Supports lower-dimension embeddings. Default is 1408" + }, + "image": { + "default": 1408, + "options": [ + 128, + 256, + 512, + 1408 + ], + "description": "Supports lower-dimension embeddings. Default is 1408" + }, + "video": { + "default": 1408, + "options": [ + 1408 + ], + "description": "Only 1408-dimensional embeddings supported for video" + } + }, + "supported_formats": { + "image": [ + "bmp", + "gif", + "jpeg", + "png" + ], + "video": [ + "avi", + "flv", + "mkv", + "mov", + "mp4", + "mpeg", + "mpg", + "webm", + "wmv" + ] + }, + "detailed_pricing": { + "text": { + "per_1k_characters": 0.0002, + "per_million_characters": 0.2, + "description": "Text embedding pricing" + }, + "image": { + "per_image": 0.0001, + "per_1000_images": 0.1, + "per_million_images": 100.0, + "description": "Image embedding pricing" + }, + "video": { + "plus": { + "per_second": 0.002, + "per_1000_seconds": 2.0, + "per_million_seconds": 2000.0, + "embeddings_per_minute": 15, + "description": "Up to 15 embeddings per minute of video" + }, + "standard": { + "per_second": 0.001, + "per_1000_seconds": 1.0, + "per_million_seconds": 1000.0, + "embeddings_per_minute": 8, + "description": "Up to 8 embeddings per minute of video" + }, + "essential": { + "per_second": 0.0005, + "per_1000_seconds": 0.5, + "per_million_seconds": 500.0, + "embeddings_per_minute": 4, + "description": "Up to 4 embeddings per minute of video" + } + } + } + } + }, { "id": "openai/gpt-oss-120b-maas", "name": "GPT OSS 120B", "provider": "vertexai", "family": "gpt-oss", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -43571,7 +43489,7 @@ "name": "GPT OSS 20B", "provider": "vertexai", "family": "gpt-oss", - "created_at": "2025-08-05 00:00:00 +0200", + "created_at": "2025-08-05 00:00:00 +0300", "context_window": 131072, "max_output_tokens": 32768, "knowledge_cutoff": null, @@ -43626,8 +43544,7 @@ "output": [] }, "capabilities": [ - "streaming", - "function_calling" + "streaming" ], "pricing": {}, "metadata": { @@ -43648,8 +43565,7 @@ "output": [] }, "capabilities": [ - "streaming", - "function_calling" + "streaming" ], "pricing": {}, "metadata": { @@ -43670,14 +43586,63 @@ "output": [] }, "capabilities": [ - "streaming", - "function_calling" + "streaming" ], "pricing": {}, "metadata": { "source": "known_models" } }, + { + "id": "zai-org/glm-4.7-maas", + "name": "GLM-4.7", + "provider": "vertexai", + "family": "glm", + "created_at": "2025-12-22 00:00:00 +0300", + "context_window": 204800, + "max_output_tokens": 131072, + "knowledge_cutoff": null, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "capabilities": [ + "function_calling", + "reasoning" + ], + "pricing": { + "text_tokens": { + "standard": { + "input_per_million": 0.6, + "output_per_million": 2.2 + } + } + }, + "metadata": { + "source": "models.dev", + "provider_id": "google-vertex", + "open_weights": true, + "attachment": false, + "temperature": true, + "last_updated": "2025-12-22", + "interleaved": { + "field": "reasoning_content" + }, + "cost": { + "input": 0.6, + "output": 2.2 + }, + "limit": { + "context": 204800, + "output": 131072 + }, + "knowledge": "2025-04" + } + }, { "id": "grok-2-1212", "name": "Grok 2 1212", diff --git a/lib/ruby_llm/providers/vertexai/capabilities.rb b/lib/ruby_llm/providers/vertexai/capabilities.rb new file mode 100644 index 000000000..4f438a3a8 --- /dev/null +++ b/lib/ruby_llm/providers/vertexai/capabilities.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +module RubyLLM + module Providers + class VertexAI + # Determines capabilities for Google Vertex AI models + module Capabilities + module_function + + def context_window_for(model_id) + case model_id + when /multimodalembedding/ then 32 + end + end + + def max_tokens_for(model_id) + case model_id + when /multimodalembedding/ then 1048 + end + end + + def modalities_for(model_id) + case model_id + when /multimodalembedding/ then { + input: %w[text image video], + output: ['embeddings'] + } + end + end + + def modality_limits_for(model_id) + return nil unless model_id.match?(/multimodalembedding/) + + { + text: { + max_tokens: 32, + description: 'Text input limited to 32 tokens' + }, + image: { + max_count: 1, + max_size_mb: 20, + formats: %w[bmp gif jpeg png], + description: 'Single image up to 20MB' + }, + video: { + max_duration_seconds: 120, + formats: %w[avi flv mkv mov mp4 mpeg mpg webm wmv], + description: 'Video up to 120 seconds' + } + } + end + + def max_embedding_dimensions_for(model_id) + case model_id + when /multimodalembedding/ then 1408 + end + end + + def allowed_dimensions_for(model_id) + case model_id + when /multimodalembedding/ + { + text: { + default: 1408, + options: [128, 256, 512, 1408], + description: 'Supports lower-dimension embeddings. Default is 1408' + }, + image: { + default: 1408, + options: [128, 256, 512, 1408], + description: 'Supports lower-dimension embeddings. Default is 1408' + }, + video: { + default: 1408, + options: [1408], + description: 'Only 1408-dimensional embeddings supported for video' + } + } + end + end + + def supports_vision?(model_id) + model_id.match?(/multimodalembedding/) + end + + def supports_video?(model_id) + model_id.match?(/multimodalembedding/) + end + + def supports_functions?(model_id) + false if model_id.match?(/multimodalembedding/) + end + + def model_type(model_id) + case model_id + when /embedding/ then 'embedding' + else 'chat' + end + end + + def capabilities_for(model_id) + return ['vision'] if model_id.match?(/multimodalembedding/) + + capabilities = ['streaming'] + capabilities << 'function_calling' if model_id.include?('gemini') + capabilities.uniq + end + + def supported_formats_for(model_id) + return nil unless model_id.match?(/multimodalembedding/) + + { + image: %w[bmp gif jpeg png], + video: %w[avi flv mkv mov mp4 mpeg mpg webm wmv] + } + end + + def pricing_for(model_id) + case model_id + when /multimodalembedding/ + { + text_tokens: { + standard: { + input_per_million: 0.2 + } + }, + images: { + standard: { + input: 0.0001 + } + } + } + end + end + + def determine_metadata(model_id) + case model_id + when /multimodalembedding/ + { + source: 'known_models', + model_type: 'embedding', + modality_limits: modality_limits_for(model_id), + max_embedding_dimensions: max_embedding_dimensions_for(model_id), + allowed_dimensions: allowed_dimensions_for(model_id), + supported_formats: supported_formats_for(model_id), + detailed_pricing: { + text: { + per_1k_characters: 0.0002, + per_million_characters: 0.2, + description: 'Text embedding pricing' + }, + image: { + per_image: 0.0001, + per_1000_images: 0.1, + per_million_images: 100.0, + description: 'Image embedding pricing' + }, + video: { + plus: { + per_second: 0.0020, + per_1000_seconds: 2.0, + per_million_seconds: 2000.0, + embeddings_per_minute: 15, + description: 'Up to 15 embeddings per minute of video' + }, + standard: { + per_second: 0.0010, + per_1000_seconds: 1.0, + per_million_seconds: 1000.0, + embeddings_per_minute: 8, + description: 'Up to 8 embeddings per minute of video' + }, + essential: { + per_second: 0.0005, + per_1000_seconds: 0.5, + per_million_seconds: 500.0, + embeddings_per_minute: 4, + description: 'Up to 4 embeddings per minute of video' + } + } + } + } + else + { source: 'known_models' } + end + end + end + end + end +end diff --git a/lib/ruby_llm/providers/vertexai/models.rb b/lib/ruby_llm/providers/vertexai/models.rb index 196e9620f..72d3754e3 100644 --- a/lib/ruby_llm/providers/vertexai/models.rb +++ b/lib/ruby_llm/providers/vertexai/models.rb @@ -27,6 +27,7 @@ module Models text-embedding-005 text-embedding-004 text-multilingual-embedding-002 + multimodalembedding ].freeze def list_models @@ -70,14 +71,12 @@ def build_known_models provider: slug, family: determine_model_family(model_id), created_at: nil, - context_window: nil, - max_output_tokens: nil, - modalities: nil, - capabilities: %w[streaming function_calling], - pricing: nil, - metadata: { - source: 'known_models' - } + context_window: Capabilities.context_window_for(model_id), + max_output_tokens: Capabilities.max_tokens_for(model_id), + modalities: Capabilities.modalities_for(model_id), + capabilities: Capabilities.capabilities_for(model_id), + pricing: Capabilities.pricing_for(model_id), + metadata: Capabilities.determine_metadata(model_id) ) end end @@ -114,6 +113,7 @@ def determine_model_family(model_id) when /^gemini-1\.\d+/ then 'gemini-1.5' when /^text-embedding/ then 'text-embedding' when /bison/ then 'palm' + when /multimodalembedding/ then 'multimodalembedding' else 'gemini' end end From 62a4dd7838f87d668e449ca7906e9d2b7df393ca Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Wed, 28 Jan 2026 19:01:51 +0300 Subject: [PATCH 08/11] Add with parameter to hold all media arguments --- lib/ruby_llm/embedding.rb | 16 +- lib/ruby_llm/provider.rb | 6 +- lib/ruby_llm/providers/vertexai/embeddings.rb | 53 ++++- .../providers/vertex_ai/embeddings_spec.rb | 217 +++++++++++++++++- 4 files changed, 268 insertions(+), 24 deletions(-) diff --git a/lib/ruby_llm/embedding.rb b/lib/ruby_llm/embedding.rb index e9a48ee70..189700cc2 100644 --- a/lib/ruby_llm/embedding.rb +++ b/lib/ruby_llm/embedding.rb @@ -14,11 +14,10 @@ def initialize(vectors:, model:, input_tokens: 0) def self.embed(text = nil, # rubocop:disable Metrics/ParameterLists model: nil, provider: nil, - image: nil, - video: nil, assume_model_exists: false, context: nil, - dimensions: nil) + dimensions: nil, + with: nil) config = context&.config || RubyLLM.config model ||= config.default_embedding_model model, provider_instance = Models.resolve(model, provider: provider, assume_exists: assume_model_exists, @@ -29,25 +28,22 @@ def self.embed(text = nil, # rubocop:disable Metrics/ParameterLists text: text, model_id: model_id, dimensions: dimensions, - image: image, - video: video + with: with ) provider_instance.embed(**args) end - def self.set_embedding_params(provider_instance, # rubocop:disable Metrics/ParameterLists + def self.set_embedding_params(provider_instance, text: nil, model_id: nil, dimensions: nil, - image: nil, - video: nil) + with: nil) embed_params = provider_instance.method(:embed).parameters.map(&:last) args = { model: model_id } args[:text] = text if text args[:dimensions] = dimensions if dimensions - args[:image] = image if image && embed_params.include?(:image) - args[:video] = video if video && embed_params.include?(:video) + args[:with] = with if with && embed_params.include?(:with) args end end diff --git a/lib/ruby_llm/provider.rb b/lib/ruby_llm/provider.rb index 5a362eb99..369870ddd 100644 --- a/lib/ruby_llm/provider.rb +++ b/lib/ruby_llm/provider.rb @@ -65,9 +65,9 @@ def list_models parse_list_models_response response, slug, capabilities end - def embed(model:, text: nil, image: nil, video: nil, dimensions: nil) - payload = if image || video - render_embedding_payload(text, model:, image:, video:, dimensions:) + def embed(model:, text: nil, dimensions: nil, with: nil) + payload = if with + render_embedding_payload(text, model:, dimensions:, with:) else render_embedding_payload(text, model:, dimensions:) end diff --git a/lib/ruby_llm/providers/vertexai/embeddings.rb b/lib/ruby_llm/providers/vertexai/embeddings.rb index 50c472ed0..14eb1d519 100644 --- a/lib/ruby_llm/providers/vertexai/embeddings.rb +++ b/lib/ruby_llm/providers/vertexai/embeddings.rb @@ -11,11 +11,11 @@ def embedding_url(model:) "projects/#{@config.vertexai_project_id}/locations/#{@config.vertexai_location}/publishers/google/models/#{model}:predict" # rubocop:disable Layout/LineLength end - def render_embedding_payload(text, model:, image: nil, video: nil, dimensions: nil) # rubocop:disable Lint/UnusedMethodArgument - is_multimodal = image.present? || video.present? + def render_embedding_payload(text, model:, dimensions: nil, with: nil) # rubocop:disable Lint/UnusedMethodArgument + is_multimodal = with.present? if is_multimodal - render_multimodal_payload(text:, image:, video:, dimensions:) + render_multimodal_payload(text:, with:, dimensions:) else { instances: [text].flatten.map { |t| { text: t.to_s } } @@ -25,11 +25,15 @@ def render_embedding_payload(text, model:, image: nil, video: nil, dimensions: n end end - def render_multimodal_payload(text:, image:, video:, dimensions:) + def render_multimodal_payload(text:, with:, dimensions:) + files = categorize_files(with) + + validate_multimodal_inputs(files) + instance = {} instance[:text] = text.to_s if text - add_image_instance(instance, image: image) - add_video_instance(instance, video: video) + add_image_instance(instance, image: files[:image].first) if files[:image].any? + add_video_instance(instance, video: files[:video].first) if files[:video].any? { instances: [instance] @@ -38,6 +42,43 @@ def render_multimodal_payload(text:, image:, video:, dimensions:) end end + def validate_multimodal_inputs(files) + raise ArgumentError, 'This model only supports one image at a time.' if files[:image].size > 1 + raise ArgumentError, 'This model only supports one video at a time.' if files[:video].size > 1 + end + + def categorize_files(files) + result = { image: [], video: [] } + + Array(files).each do |file| + case detect_file_type(file) + when :image + result[:image] << file + when :video + result[:video] << file + else + raise ArgumentError, "Unsupported file type for file: #{file}" + end + end + result + end + + def detect_file_type(file) + filename = if file.respond_to?(:path) + file.path + elsif file.is_a?(String) + file + else + return :unknown + end + extension = File.extname(filename).downcase + + return :image if %w[.jpg .jpeg .png .gif .bmp].include?(extension) + return :video if %w[.avi .flv .mkv .mov .mp4 .mpeg .mpg .webm .wmv].include?(extension) + + :unknown + end + def add_image_instance(instance, image:) return unless image.present? diff --git a/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb index d8f176f7c..f3c7aa9a5 100644 --- a/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb +++ b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb @@ -55,20 +55,152 @@ def initialize(config) end context 'with multimodal content payload' do - it 'renders payload with multimodal content' do - image_data = 'fake_image_data' - video_data = 'fake_video_data' + it 'renders payload with image file' do + image_file = Tempfile.new(['test_image', '.png']) + image_file.write('fake_image_data') + image_file.rewind payload = embeddings.send( :render_embedding_payload, 'Test multimodal input', model: 'multimodalembedding', - image: image_data, - video: video_data + with: [image_file] ) expect(payload[:instances].first[:text]).to eq('Test multimodal input') expect(payload[:instances].first).to have_key(:image) + expect(payload[:instances].first).not_to have_key(:video) + + image_file.close + image_file.unlink + end + + it 'renders payload with video file' do + video_file = Tempfile.new(['test_video', '.mp4']) + video_file.write('fake_video_data') + video_file.rewind + + payload = embeddings.send( + :render_embedding_payload, + 'Test multimodal input', + model: 'multimodalembedding', + with: [video_file] + ) + expect(payload[:instances].first[:text]).to eq('Test multimodal input') + expect(payload[:instances].first).to have_key(:video) + expect(payload[:instances].first).not_to have_key(:image) + + video_file.close + video_file.unlink + end + + it 'renders payload with GCS video URI' do + payload = embeddings.send( + :render_embedding_payload, + 'Test multimodal input', + model: 'multimodalembedding', + with: ['gs://my-bucket/my-video.mp4'] + ) + expect(payload[:instances].first[:text]).to eq('Test multimodal input') expect(payload[:instances].first).to have_key(:video) + expect(payload[:instances].first).not_to have_key(:image) + end + + it 'renders both image and video in payload' do + image_file = Tempfile.new(['test_image', '.png']) + image_file.write('fake_image_data') + image_file.rewind + + video_file = Tempfile.new(['test_video', '.mp4']) + video_file.write('fake_video_data') + video_file.rewind + + payload = embeddings.send( + :render_embedding_payload, + 'Test multimodal input', + model: 'multimodalembedding', + with: [image_file, video_file] + ) + expect(payload[:instances].first[:text]).to eq('Test multimodal input') + expect(payload[:instances].first).to have_key(:image) + expect(payload[:instances].first).to have_key(:video) + + image_file.close + image_file.unlink + video_file.close + video_file.unlink + end + + it 'renders payload with no multimodal content' do + payload = embeddings.send( + :render_embedding_payload, + 'Test multimodal input', + model: 'multimodalembedding' + ) + expect(payload[:instances].first[:text]).to eq('Test multimodal input') + expect(payload[:instances].first).not_to have_key(:image) + expect(payload[:instances].first).not_to have_key(:video) + end + + it 'raises error for unsupported file type' do + unsupported_file = Tempfile.new(['test_unsupported', '.txt']) + unsupported_file.write('some text data') + unsupported_file.rewind + + expect do + embeddings.send( + :render_embedding_payload, + 'Test multimodal input', + model: 'multimodalembedding', + with: [unsupported_file] + ) + end.to raise_error(ArgumentError, /Unsupported file type for file/) + + unsupported_file.close + unsupported_file.unlink + end + + it 'raises error for multiple images' do + image_file1 = Tempfile.new(['test_image1', '.png']) + image_file2 = Tempfile.new(['test_image2', '.jpg']) + image_file1.write('fake_image_data_1') + image_file2.write('fake_image_data_2') + image_file1.rewind + image_file2.rewind + + expect do + embeddings.send( + :render_embedding_payload, + 'Test multimodal input', + model: 'multimodalembedding', + with: [image_file1, image_file2] + ) + end.to raise_error(ArgumentError, 'This model only supports one image at a time.') + image_file1.close + image_file1.unlink + image_file2.close + image_file2.unlink + end + + it 'raises error for multiple videos' do + video_file1 = Tempfile.new(['test_video1', '.mp4']) + video_file2 = Tempfile.new(['test_video2', '.avi']) + video_file1.write('fake_video_data_1') + video_file2.write('fake_video_data_2') + video_file1.rewind + video_file2.rewind + + expect do + embeddings.send( + :render_embedding_payload, + 'Test multimodal input', + model: 'multimodalembedding', + with: [video_file1, video_file2] + ) + end.to raise_error(ArgumentError, /This model only supports one video at a time/) + video_file1.close + video_file1.unlink + video_file2.close + video_file2.unlink end it 'renders payload wtih dimensions parameter' do @@ -83,6 +215,81 @@ def initialize(config) end end + describe '#categorize_files' do + it 'categorizes image files correctly' do + files = embeddings.send(:categorize_files, ['image.jpg', 'photo.png']) + expect(files[:image].length).to eq(2) + expect(files[:video].length).to eq(0) + end + + it 'categorizes video files correctly' do + files = embeddings.send(:categorize_files, ['video.mp4', 'movie.mov']) + expect(files[:image].length).to eq(0) + expect(files[:video].length).to eq(2) + end + + it 'categorizes mixed files correctly' do + files = embeddings.send(:categorize_files, ['image.jpg', 'video.mp4']) + expect(files[:image].length).to eq(1) + expect(files[:video].length).to eq(1) + end + + it 'raises error for unsupported file types' do + expect do + embeddings.send(:categorize_files, ['document.pdf']) + end.to raise_error(ArgumentError, /Unsupported file type/) + end + end + + describe '#detect_file_type' do + it 'detects image formats' do + expect(embeddings.send(:detect_file_type, 'photo.jpg')).to eq(:image) + expect(embeddings.send(:detect_file_type, 'image.png')).to eq(:image) + expect(embeddings.send(:detect_file_type, 'pic.gif')).to eq(:image) + end + + it 'detects video formats' do + expect(embeddings.send(:detect_file_type, 'video.mp4')).to eq(:video) + expect(embeddings.send(:detect_file_type, 'movie.mov')).to eq(:video) + expect(embeddings.send(:detect_file_type, 'clip.webm')).to eq(:video) + end + + it 'handles file objects with path method' do + file = double('file', path: 'image.jpg') # rubocop:disable RSpec/VerifiedDoubles + expect(embeddings.send(:detect_file_type, file)).to eq(:image) + end + + it 'returns unknown for unsupported types' do + expect(embeddings.send(:detect_file_type, 'doc.pdf')).to eq(:unknown) + end + end + + describe '#validate_multimodal_inputs' do + it 'allows single image' do + files = { image: ['image.jpg'], video: [] } + expect { embeddings.send(:validate_multimodal_inputs, files) }.not_to raise_error + end + + it 'allows single video' do + files = { image: [], video: ['video.mp4'] } + expect { embeddings.send(:validate_multimodal_inputs, files) }.not_to raise_error + end + + it 'raises error for multiple images' do + files = { image: ['img1.jpg', 'img2.jpg'], video: [] } + expect do + embeddings.send(:validate_multimodal_inputs, files) + end.to raise_error(ArgumentError, 'This model only supports one image at a time.') + end + + it 'raises error for multiple videos' do + files = { image: [], video: ['vid1.mp4', 'vid2.mp4'] } + expect do + embeddings.send(:validate_multimodal_inputs, files) + end.to raise_error(ArgumentError, 'This model only supports one video at a time.') + end + end + describe '#parse_embedding_response' do context 'with text only embeddings' do it 'parses text only embedding response' do From 8caa042f67e2e91a4ea228d2eda12ae55d7e2c4e Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Thu, 29 Jan 2026 19:08:45 +0300 Subject: [PATCH 09/11] Fix image and video input bug --- lib/ruby_llm/providers/vertexai/embeddings.rb | 24 +++++++++++++++---- .../providers/vertex_ai/embeddings_spec.rb | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/ruby_llm/providers/vertexai/embeddings.rb b/lib/ruby_llm/providers/vertexai/embeddings.rb index 14eb1d519..0e0fd8a99 100644 --- a/lib/ruby_llm/providers/vertexai/embeddings.rb +++ b/lib/ruby_llm/providers/vertexai/embeddings.rb @@ -83,7 +83,14 @@ def add_image_instance(instance, image:) return unless image.present? require 'base64' - image_data = image.respond_to?(:read) ? image.read : image + image_data = if image.respond_to?(:read) + image.read + elsif image.is_a?(String) && File.exist?(image) + File.binread(image) + else + image + end + instance[:image] = { bytesBase64Encoded: Base64.strict_encode64(image_data) } end @@ -93,10 +100,17 @@ def add_video_instance(instance, video:) require 'base64' if video.is_a?(String) && video.start_with?('gs://') instance[:video] = { gcsUri: video } - else - video_data = video.respond_to?(:read) ? video.read : video - instance[:video] = { bytesBase64Encoded: Base64.strict_encode64(video_data) } + return end + + video_data = if video.respond_to?(:read) + video.read + elsif video.is_a?(String) && File.exist?(video) + File.binread(video) + else + video + end + instance[:video] = { bytesBase64Encoded: Base64.strict_encode64(video_data) } end def parse_embedding_response(response, model:, text:) @@ -114,7 +128,7 @@ def parse_embedding_response(response, model:, text:) def parse_multimodal_embeddings(predictions) text_embedding = predictions&.dig(0, 'textEmbedding') image_embedding = predictions&.dig(0, 'imageEmbedding') - video_embedding = predictions&.dig(0, 'videoEmbedding') + video_embedding = predictions&.dig(0, 'videoEmbeddings') vectors = {} vectors[:text] = text_embedding if text_embedding diff --git a/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb index f3c7aa9a5..bad2dccc6 100644 --- a/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb +++ b/spec/ruby_llm/providers/vertex_ai/embeddings_spec.rb @@ -360,7 +360,7 @@ def initialize(config) { 'textEmbedding' => ['0.1,....'], 'imageEmbedding' => ['0.2,....'], - 'videoEmbedding' => ['0.3,....'] + 'videoEmbeddings' => ['0.3,....'] } ] } From 73f2e5e4a25f9b3c44a50a08c457deaed4ac3df3 Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Fri, 30 Jan 2026 16:14:02 +0300 Subject: [PATCH 10/11] Edit README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f398e68ba..0c2805560 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,9 @@ RubyLLM.paint "a sunset over mountains in watercolor style" ```ruby # Create embeddings RubyLLM.embed "Ruby is elegant and expressive" + +# Create multimodal embeddings (with supported models) +RubyLLM.embed "Ruby is elegant and expressive", with: ["image.png", "video.mp4"], model: multimodalembedding ``` ```ruby From ef4c6a23786cfc27f7098b25ab3ffe42b148395e Mon Sep 17 00:00:00 2001 From: Ndunge-Makau Date: Tue, 3 Mar 2026 17:32:44 +0300 Subject: [PATCH 11/11] Fix potential regression issue --- lib/ruby_llm/providers/vertexai/embeddings.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/ruby_llm/providers/vertexai/embeddings.rb b/lib/ruby_llm/providers/vertexai/embeddings.rb index 0e0fd8a99..0117dd01f 100644 --- a/lib/ruby_llm/providers/vertexai/embeddings.rb +++ b/lib/ruby_llm/providers/vertexai/embeddings.rb @@ -116,7 +116,7 @@ def add_video_instance(instance, video:) def parse_embedding_response(response, model:, text:) predictions = response.body['predictions'] - if model == 'multimodalembedding' + if multimodal_embedding_response?(predictions) vectors = parse_multimodal_embeddings(predictions) else vectors = predictions&.map { |p| p.dig('embeddings', 'values') } @@ -125,6 +125,12 @@ def parse_embedding_response(response, model:, text:) Embedding.new(vectors:, model:, input_tokens: 0) end + def multimodal_embedding_response?(predictions) + predictions&.dig(0, 'textEmbedding') || + predictions&.dig(0, 'imageEmbedding') || + predictions&.dig(0, 'videoEmbeddings') + end + def parse_multimodal_embeddings(predictions) text_embedding = predictions&.dig(0, 'textEmbedding') image_embedding = predictions&.dig(0, 'imageEmbedding')