Vertex AI adapter #1617
Replies: 6 comments 6 replies
|
I think this might be merged into codecompanion as pr? |
|
Love this @JPFrancoia and thanks for sharing! |
|
Hi, I have a stupid question. I followed the exact instruction above, saved the adapter code to I am assuming the |
|
The example in the original post works for me, but I get this error after a couple of minutes idle time in codecompanion, when using vertex: Error: [{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "CREDENTIALS_MISSING",
"domain": "googleapis.com",
"metadata": {
"method": "google.cloud.aiplatform.v1.PredictionService.ChatCompletions",
"service": "aiplatform.googleapis.com"
}
}
]
}
}
]Is this something you have also encountered, and any idea to mitigate? |
|
This is the new version of the adapter, after the addition of the http/acp distinction. It's just a matter of copying the gemini adapter and changing the urls/model names. local openai = require("codecompanion.adapters.http.openai")
---@class CodeCompanion.HTTPAdapter.Gemini : CodeCompanion.HTTPAdapter
return {
name = "vertex",
formatted_name = "Vertex AI",
roles = {
llm = "assistant",
user = "user",
},
opts = {
stream = true,
tools = true,
vision = true,
},
features = {
text = true,
tokens = true,
},
-- Availability of models: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/locations
-- url = "https://${region}-aiplatform.googleapis.com/v1/projects/${project_id}/locations/${region}/endpoints/openapi/chat/completions",
url = "https://aiplatform.googleapis.com/v1/projects/${project_id}/locations/global/endpoints/openapi/chat/completions",
env = {
project_id = "YOUR_PROJECT_ID",
api_key = "VERTEX_API_KEY",
},
headers = {
Authorization = "Bearer ${api_key}",
["Content-Type"] = "application/json",
},
handlers = {
setup = function(self)
-- Make sure the individual model options are set
local model = self.schema.model.default
local model_opts = self.schema.model.choices[model]
if model_opts and model_opts.opts then
self.opts = vim.tbl_deep_extend("force", self.opts, model_opts.opts)
if not model_opts.opts.has_vision then
self.opts.vision = false
end
end
if self.opts and self.opts.stream then
self.parameters = self.parameters or {}
self.parameters.stream = true
self.parameters.stream_options = { include_usage = true }
end
return true
end,
--- Use the OpenAI adapter for the bulk of the work
tokens = function(self, data)
return openai.handlers.tokens(self, data)
end,
form_parameters = function(self, params, messages)
return openai.handlers.form_parameters(self, params, messages)
end,
form_tools = function(self, tools)
return openai.handlers.form_tools(self, tools)
end,
form_messages = function(self, messages)
return openai.handlers.form_messages(self, messages)
end,
chat_output = function(self, data, tools)
return openai.handlers.chat_output(self, data, tools)
end,
tools = {
format_tool_calls = function(self, tools)
return openai.handlers.tools.format_tool_calls(self, tools)
end,
output_response = function(self, tool_call, output)
return openai.handlers.tools.output_response(self, tool_call, output)
end,
},
inline_output = function(self, data, context)
return openai.handlers.inline_output(self, data, context)
end,
on_exit = function(self, data)
return openai.handlers.on_exit(self, data)
end,
},
schema = {
---@type CodeCompanion.Schema
model = {
order = 1,
mapping = "parameters",
type = "enum",
desc = "The model that will complete your prompt. See https://ai.google.dev/gemini-api/docs/models/gemini#model-variations for additional details and options.",
default = "google/gemini-2.5-flash",
choices = {
["google/gemini-2.5-pro"] = { nice_name = "Gemini 2.5 Pro", opts = { can_reason = true, has_vision = true } },
["google/gemini-2.5-flash"] = { nice_name = "Gemini 2.5 Flash", opts = { can_reason = true, has_vision = true } },
["google/gemini-2.5-flash-preview-05-20"] = {
nice_name = "Gemini 2.5 Flash Preview",
opts = { can_reason = true, has_vision = true },
},
["google/gemini-2.0-flash"] = { nice_name = "Gemini 2.0 Flash", opts = { has_vision = true } },
["googl/gemini-2.0-flash-lite"] = { nice_name = "Gemini 2.0 Flash Lite", opts = { has_vision = true } },
["google/gemini-1.5-pro"] = { nice_name = "Gemini 1.5 Pro", opts = { has_vision = true } },
["google/gemini-1.5-flash"] = { nice_name = "Gemini 1.5 Flash", opts = { has_vision = true } },
},
},
---@type CodeCompanion.Schema
max_tokens = {
order = 2,
mapping = "parameters",
type = "integer",
optional = true,
default = nil,
desc = "The maximum number of tokens to include in a response candidate. Note: The default value varies by model",
validate = function(n)
return n > 0, "Must be greater than 0"
end,
},
---@type CodeCompanion.Schema
temperature = {
order = 3,
mapping = "parameters",
type = "number",
optional = true,
default = nil,
desc = "Controls the randomness of the output.",
validate = function(n)
return n >= 0 and n <= 2, "Must be between 0 and 2"
end,
},
---@type CodeCompanion.Schema
top_p = {
order = 4,
mapping = "parameters",
type = "integer",
optional = true,
default = nil,
desc = "The maximum cumulative probability of tokens to consider when sampling. The model uses combined Top-k and Top-p (nucleus) sampling. Tokens are sorted based on their assigned probabilities so that only the most likely tokens are considered. Top-k sampling directly limits the maximum number of tokens to consider, while Nucleus sampling limits the number of tokens based on the cumulative probability.",
validate = function(n)
return n > 0, "Must be greater than 0"
end,
},
---@type CodeCompanion.Schema
reasoning_effort = {
order = 5,
mapping = "parameters",
type = "string",
optional = true,
---@param self CodeCompanion.HTTPAdapter
condition = function(self)
local model = self.schema.model.default
if type(model) == "function" then
model = model()
end
if self.schema.model.choices[model] and self.schema.model.choices[model].opts then
return self.schema.model.choices[model].opts.can_reason
end
return false
end,
default = "medium",
desc = "Constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response.",
choices = {
"high",
"medium",
"low",
"none",
},
},
},
} |
|
I’ve shared 3 new Vertex AI adapters (Gemini, Anthropic, and MaaS) that you can use directly with I've opened a new discussion with all the details here: 2875 You can find the repo at: viespejo/cc-adapter-vertex-ai.nvim Give it a spin and let me know if it works for your setup! |
Uh oh!
There was an error while loading. Please reload this page.
Hi all, I would like to give this adapter to the community. Here is some context:
Google provides the Gemini developer API, which I believe most people are familiar with. This API requires an API key. There is an official adapter for this API (the
geminione). However people might not be able to use it in an enterprise setting, because of licensing, compliance, security, etc. For example, if a team works with a GCP project, you can't really create an API key per person (well you could, but then you must ensure that person A can't see person B's API key). You also can't create just one common API key, because then you can't track usage per person.Google's answer to these problems is to use Vertex AI. They have a page explaining the difference between Gemini Developer API and Vertex AI. With Vertex AI, users can login with their user credentials, no need for an API key.
The two APIs are actually very similar, so the vertex AI adapter is largely inspired from the gemini one.
Configuration example:
{ "olimorris/codecompanion.nvim", dependencies = { "nvim-lua/plenary.nvim", "nvim-treesitter/nvim-treesitter", "j-hui/fidget.nvim" }, opts = { adapters = { copilot = function() return require("codecompanion.adapters").extend("copilot", { schema = {model = {default = "claude-sonnet-4"}} }) end, vertex = function() return require("codecompanion.adapters").extend("vertex", { env = { project_id = "project_name_here", api_key = "cmd: gcloud auth application-default print-access-token", }, schema = {model = {default = "google/gemini-2.5-pro-preview-06-05"}} }) end }, strategies = { chat = {adapter = "vertex"}, inline = {adapter = "vertex"}, }, -- truncatedI also found out a few things:
The global endpoint is formatted like this:
The regional endpoints are formatted like this:
I hope this saves someone else's time, cheers!
All reactions