core: expose provider discovery api

- Expose all available providers and their default models to enable frontend discovery features.
- Return connection status per provider to allow clients to distinguish between active and potential integrations.
This commit is contained in:
Dax Raad 2025-11-19 21:45:16 -05:00
parent d9d372bddd
commit 54f48ec66b
3 changed files with 72 additions and 1 deletions

View file

@ -8,7 +8,7 @@ import { proxy } from "hono/proxy"
import { Session } from "../session"
import z from "zod"
import { Provider } from "../provider/provider"
import { mapValues } from "remeda"
import { map, mapValues, pipe, values } from "remeda"
import { NamedError } from "../util/error"
import { ModelsDev } from "../provider/models"
import { Ripgrep } from "../file/ripgrep"
@ -1163,6 +1163,38 @@ export namespace Server {
})
},
)
.get(
"/provider",
describeRoute({
description: "List all providers",
operationId: "provider.list",
responses: {
200: {
description: "List of providers",
content: {
"application/json": {
schema: resolver(
z.object({
all: ModelsDev.Provider.array(),
default: z.record(z.string(), z.string()),
connected: z.array(z.string()),
}),
),
},
},
},
},
}),
async (c) => {
const providers = await ModelsDev.get()
const connected = await Provider.list().then((x) => Object.keys(x))
return c.json({
all: Object.values(providers),
default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
connected,
})
},
)
.get(
"/find",
describeRoute({

View file

@ -92,6 +92,8 @@ import type {
CommandListResponses,
ConfigProvidersData,
ConfigProvidersResponses,
ProviderListData,
ProviderListResponses,
FindTextData,
FindTextResponses,
FindFilesData,
@ -554,6 +556,18 @@ class Command extends _HeyApiClient {
}
}
class Provider extends _HeyApiClient {
/**
* List all providers
*/
public list<ThrowOnError extends boolean = false>(options?: Options<ProviderListData, ThrowOnError>) {
return (options?.client ?? this._client).get<ProviderListResponses, unknown, ThrowOnError>({
url: "/provider",
...options,
})
}
}
class Find extends _HeyApiClient {
/**
* Find text in files
@ -894,6 +908,7 @@ export class OpencodeClient extends _HeyApiClient {
path = new Path({ client: this._client })
session = new Session({ client: this._client })
command = new Command({ client: this._client })
provider = new Provider({ client: this._client })
find = new Find({ client: this._client })
file = new File({ client: this._client })
app = new App({ client: this._client })

View file

@ -2482,6 +2482,30 @@ export type ConfigProvidersResponses = {
export type ConfigProvidersResponse = ConfigProvidersResponses[keyof ConfigProvidersResponses]
export type ProviderListData = {
body?: never
path?: never
query?: {
directory?: string
}
url: "/provider"
}
export type ProviderListResponses = {
/**
* List of providers
*/
200: {
all: Array<Provider>
default: {
[key: string]: string
}
connected: Array<string>
}
}
export type ProviderListResponse = ProviderListResponses[keyof ProviderListResponses]
export type FindTextData = {
body?: never
path?: never