refactor(ai): share the Vertex OAuth route setup (#61160)

This commit is contained in:
Aiden Cline 2026-11-01 21:21:46 -06:00 • committed by GitHub
parent 5d24e0dc5b
commit ff5be41bf7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 108 additions and 158 deletions

View file

@ -2,7 +2,7 @@ import type { ProviderPackage } from "../provider-package.js"
import { OpenAIChat } from "../protocols/openai-chat.js"
import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { ProviderConfigurationError, ProviderID, type ModelID } from "../schema/index.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { GoogleVertexShared } from "./google-vertex-shared.js"
import type { OpenAIProviderOptionsInput } from "./openai-options.js"
@ -36,29 +36,14 @@ const route = Route.make({
export const routes = [route]
const configuredRoute = (input: Config) => {
if ("apiKey" in input && input.apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: "Google Vertex Chat does not support API keys" })
const {
accessToken: _accessToken,
auth: _auth,
baseURL,
location: inputLocation,
project: inputProject,
...rest
} = input
const location = GoogleVertexShared.location(inputLocation)
const project = GoogleVertexShared.project(inputProject)
return route.with({
...rest,
endpoint: {
baseURL:
baseURL ??
`https://aiplatform.googleapis.com/v1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}/endpoints/openapi`,
},
auth: GoogleVertexShared.oauth(input, project),
})
}
const configuredRoute = (input: Config) =>
GoogleVertexShared.oauthRoute(
route,
"Chat",
input,
(project, location) =>
`https://aiplatform.googleapis.com/v1/projects/${project}/locations/${location}/endpoints/openapi`,
)
export const configure = (input: Config = {}) => {
const route = configuredRoute(input)
@ -74,19 +59,5 @@ export const provider = {
configure,
}
export const model: ProviderPackage.Model<Settings, OpenAIProviderOptionsInput> = (
modelID,
{ accessToken, apiKey, baseURL, body, headers, location, project, ...providerOptions }: Settings = {},
) => {
if (apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: "Google Vertex Chat does not support API keys" })
return configure({
accessToken,
baseURL,
headers,
http: body === undefined ? undefined : { body },
location,
project,
providerOptions,
}).model(modelID)
}
export const model: ProviderPackage.Model<Settings, OpenAIProviderOptionsInput> = (modelID, settings = {}) =>
configure(GoogleVertexShared.oauthSettings<OpenAIProviderOptionsInput>("Chat", settings)).model(modelID)

View file

@ -5,7 +5,7 @@ import { Auth } from "../route/auth.js"
import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Protocol } from "../route/protocol.js"
import { ProviderConfigurationError, ProviderID, type ModelID } from "../schema/index.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { GoogleVertexShared } from "./google-vertex-shared.js"
export type AnthropicOptionsInput = AnthropicMessages.OptionsInput
@ -66,29 +66,14 @@ const route = Route.make({
export const routes = [route]
const configuredRoute = (input: Config) => {
if ("apiKey" in input && input.apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: "Google Vertex Messages does not support API keys" })
const {
accessToken: _accessToken,
auth: _auth,
baseURL,
location: inputLocation,
project: inputProject,
...rest
} = input
const location = GoogleVertexShared.location(inputLocation)
const project = GoogleVertexShared.project(inputProject)
return route.with({
...rest,
endpoint: {
baseURL:
baseURL ??
`https://${GoogleVertexShared.host(location)}/v1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}/publishers/anthropic/models`,
},
auth: GoogleVertexShared.oauth(input, project),
})
}
const configuredRoute = (input: Config) =>
GoogleVertexShared.oauthRoute(
route,
"Messages",
input,
(project, location) =>
`https://${GoogleVertexShared.host(location)}/v1/projects/${project}/locations/${location}/publishers/anthropic/models`,
)
export const configure = (input: Config = {}) => {
const route = configuredRoute(input)
@ -106,17 +91,8 @@ export const provider = {
export const model: ProviderPackage.Model<Settings, AnthropicMessages.ProviderOptionsInput> = (
modelID,
{ accessToken, apiKey, baseURL, body, headers, location, project, ...providerOptions }: Settings = {},
) => {
if (apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: "Google Vertex Messages does not support API keys" })
return configure({
accessToken,
baseURL,
headers,
http: body === undefined ? undefined : { body },
location,
project,
providerOptions,
}).model(modelID)
}
settings = {},
) =>
configure(GoogleVertexShared.oauthSettings<AnthropicMessages.ProviderOptionsInput>("Messages", settings)).model(
modelID,
)

View file

@ -6,7 +6,7 @@ import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Protocol } from "../route/protocol.js"
import { HttpTransport } from "../route/transport/index.js"
import { ProviderConfigurationError, ProviderID, type ModelID } from "../schema/index.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { GoogleVertexShared } from "./google-vertex-shared.js"
export const id = ProviderID.make("google-vertex")
@ -52,29 +52,14 @@ const route = Route.make({
export const routes = [route]
const configuredRoute = (input: Config) => {
if ("apiKey" in input && input.apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: "Google Vertex Mistral does not support API keys" })
const {
accessToken: _accessToken,
auth: _auth,
baseURL,
location: inputLocation,
project: inputProject,
...rest
} = input
const location = GoogleVertexShared.location(inputLocation)
const project = GoogleVertexShared.project(inputProject)
return route.with({
...rest,
endpoint: {
baseURL:
baseURL ??
`https://${GoogleVertexShared.host(location)}/v1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}/publishers/mistralai/models`,
},
auth: GoogleVertexShared.oauth(input, project),
})
}
const configuredRoute = (input: Config) =>
GoogleVertexShared.oauthRoute(
route,
"Mistral",
input,
(project, location) =>
`https://${GoogleVertexShared.host(location)}/v1/projects/${project}/locations/${location}/publishers/mistralai/models`,
)
export const configure = (input: Config = {}) => {
const route = configuredRoute(input)
@ -90,19 +75,5 @@ export const provider = {
configure,
}
export const model: ProviderPackage.Model<Settings, MistralChat.ProviderOptionsInput> = (
modelID,
{ accessToken, apiKey, baseURL, body, headers, location, project, ...providerOptions }: Settings = {},
) => {
if (apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: "Google Vertex Mistral does not support API keys" })
return configure({
accessToken,
baseURL,
headers,
http: body === undefined ? undefined : { body },
location,
project,
providerOptions,
}).model(modelID)
}
export const model: ProviderPackage.Model<Settings, MistralChat.ProviderOptionsInput> = (modelID, settings = {}) =>
configure(GoogleVertexShared.oauthSettings<MistralChat.ProviderOptionsInput>("Mistral", settings)).model(modelID)

View file

@ -2,7 +2,7 @@ import type { ProviderPackage } from "../provider-package.js"
import { OpenResponses } from "../protocols/open-responses.js"
import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { ProviderConfigurationError, ProviderID, type ModelID } from "../schema/index.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { GoogleVertexShared } from "./google-vertex-shared.js"
import type { OpenResponsesProviderOptionsInput } from "./open-responses-options.js"
@ -37,29 +37,14 @@ const route = Route.make({
export const routes = [route]
const configuredRoute = (input: Config) => {
if ("apiKey" in input && input.apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: "Google Vertex Responses does not support API keys" })
const {
accessToken: _accessToken,
auth: _auth,
baseURL,
location: inputLocation,
project: inputProject,
...rest
} = input
const location = GoogleVertexShared.location(inputLocation)
const project = GoogleVertexShared.project(inputProject)
return route.with({
...rest,
endpoint: {
baseURL:
baseURL ??
`https://aiplatform.googleapis.com/v1/projects/${GoogleVertexShared.requireProject(project)}/locations/${location}/endpoints/openapi`,
},
auth: GoogleVertexShared.oauth(input, project),
})
}
const configuredRoute = (input: Config) =>
GoogleVertexShared.oauthRoute(
route,
"Responses",
input,
(project, location) =>
`https://aiplatform.googleapis.com/v1/projects/${project}/locations/${location}/endpoints/openapi`,
)
export const configure = (input: Config = {}) => {
const route = configuredRoute(input)
@ -75,19 +60,5 @@ export const provider = {
configure,
}
export const model: ProviderPackage.Model<Settings, OpenResponsesProviderOptionsInput> = (
modelID,
{ accessToken, apiKey, baseURL, body, headers, location, project, ...providerOptions }: Settings = {},
) => {
if (apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: "Google Vertex Responses does not support API keys" })
return configure({
accessToken,
baseURL,
headers,
http: body === undefined ? undefined : { body },
location,
project,
providerOptions,
}).model(modelID)
}
export const model: ProviderPackage.Model<Settings, OpenResponsesProviderOptionsInput> = (modelID, settings = {}) =>
configure(GoogleVertexShared.oauthSettings<OpenResponsesProviderOptionsInput>("Responses", settings)).model(modelID)

View file

@ -1,6 +1,8 @@
import type { AnyAuthClient, GoogleAuthOptions } from "google-auth-library"
import { Effect, Redacted } from "effect"
import type { ProviderPackage } from "../provider-package.js"
import { Auth, MissingCredentialError } from "../route/auth.js"
import type { CompactionOperations, Route, RouteDefaultsInput } from "../route/client.js"
import { ProviderConfigurationError, ProviderID } from "../schema/index.js"
const SCOPE = "https://www.googleapis.com/auth/cloud-platform"
@ -112,4 +114,63 @@ export const oauth = (input: OAuthOptions, project?: string) => {
return adc(project)
}
export const oauthRoute = <Body, Prepared, Compact extends CompactionOperations | undefined>(
route: Route<Body, Prepared, Compact>,
label: string,
input: RouteDefaultsInput &
OAuthOptions & { readonly baseURL?: string; readonly location?: string; readonly project?: string },
url: (project: string, location: string) => string,
) => {
if ("apiKey" in input && input.apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: `Google Vertex ${label} does not support API keys` })
const {
accessToken: _accessToken,
auth: _auth,
baseURL,
location: inputLocation,
project: inputProject,
...rest
} = input
const resolvedLocation = location(inputLocation)
const resolvedProject = project(inputProject)
return route.with({
...rest,
endpoint: { baseURL: baseURL ?? url(requireProject(resolvedProject), resolvedLocation) },
auth: oauth(input, resolvedProject),
})
}
export const oauthSettings = <Options>(
label: string,
{
accessToken,
apiKey,
baseURL,
body,
headers,
location,
project,
...providerOptions
}: ProviderPackage.Settings &
Options & {
readonly accessToken?: string
readonly apiKey?: never
readonly baseURL?: string
readonly location?: string
readonly project?: string
},
) => {
if (apiKey !== undefined)
throw new ProviderConfigurationError({ provider: id, message: `Google Vertex ${label} does not support API keys` })
return {
accessToken,
baseURL,
headers,
http: body === undefined ? undefined : { body },
location,
project,
providerOptions,
}
}
export * as GoogleVertexShared from "./google-vertex-shared.js"