feat(connectors): add Ollama and LM Studio as a local auth kind
Both servers expose OpenAI-compatible /v1/chat/completions and /v1/models, so we route them through pi-ai's `openai-completions` API the same way Fireworks does — but with a per-installation base URL the user enters during onboarding instead of a hardcoded one. The shared schemas grow a `local` credential payload carrying just the baseUrl; the credential resolver surfaces it on `ResolvedCredential.baseUrl`, the runtime bridge forwards it through `prepareRun`, and the worker plumbs it into `resolveModel` so the streamed Model<openai-completions> targets the user's server. The local-cost path short-circuits to zero in cost-writer since users bill their own hardware, and the live model list is fetched from the saved baseUrl by `fetchLocalConnectorModels` (Ollama and LM Studio both speak the standard OpenAI catalog shape). Onboarding ships a new LocalProviderCard and the Settings panel a LocalForm; both default to the catalog's per-connector localhost URL and accept any custom URL.
This commit is contained in:
1 parent
07d9c00fab
commit
a532120649
26 files changed
+504
-18
No files matched your search
@@ -16,20 +16,22 @@ export type PiOAuthProviderId =
|
||||
| "google-gemini-cli"
|
||||
| "google-antigravity";
|
||||
|
||||
export type ConnectorAuthKind = "oauth" | "api_key" | "aws" | "azure" | "gcp_adc";
|
||||
export type ConnectorAuthKind = "oauth" | "api_key" | "aws" | "azure" | "gcp_adc" | "local";
|
||||
|
||||
export interface ConnectorAuthOAuth { type: "oauth"; oauthId: PiOAuthProviderId }
|
||||
export interface ConnectorAuthApiKey { type: "api_key"; envKey: string }
|
||||
export interface ConnectorAuthAws { type: "aws" }
|
||||
export interface ConnectorAuthAzure { type: "azure" }
|
||||
export interface ConnectorAuthGcpAdc { type: "gcp_adc" }
|
||||
export interface ConnectorAuthLocal { type: "local"; defaultBaseUrl: string }
|
||||
|
||||
export type ConnectorAuth =
|
||||
| ConnectorAuthOAuth
|
||||
| ConnectorAuthApiKey
|
||||
| ConnectorAuthAws
|
||||
| ConnectorAuthAzure
|
||||
| ConnectorAuthGcpAdc;
|
||||
| ConnectorAuthGcpAdc
|
||||
| ConnectorAuthLocal;
|
||||
|
||||
export interface ConnectorCatalogEntry {
|
||||
id: ConnectorId;
|
||||
@@ -242,6 +244,27 @@ const API_KEY_ENTRIES: ConnectorCatalogEntry[] = [
|
||||
},
|
||||
];
|
||||
|
||||
const LOCAL_ENTRIES: ConnectorCatalogEntry[] = [
|
||||
{
|
||||
id: "ollama",
|
||||
provider: "ollama",
|
||||
label: "Ollama",
|
||||
description: "Local Ollama server — open-weights models on your own machine via the OpenAI-compatible endpoint.",
|
||||
defaultModel: "llama3.2",
|
||||
auth: { type: "local", defaultBaseUrl: "http://localhost:11434/v1" },
|
||||
notes: "Default port 11434. Override if you launched `ollama serve` elsewhere.",
|
||||
},
|
||||
{
|
||||
id: "lm-studio",
|
||||
provider: "lm-studio",
|
||||
label: "LM Studio",
|
||||
description: "Local LM Studio server — host any loaded model via the OpenAI-compatible endpoint.",
|
||||
defaultModel: "local-model",
|
||||
auth: { type: "local", defaultBaseUrl: "http://localhost:1234/v1" },
|
||||
notes: "Enable LM Studio's local server from the Developer tab. Default port 1234.",
|
||||
},
|
||||
];
|
||||
|
||||
const CLOUD_ENTRIES: ConnectorCatalogEntry[] = [
|
||||
{
|
||||
id: "amazon-bedrock",
|
||||
@@ -277,6 +300,7 @@ export const CONNECTOR_CATALOG: ConnectorCatalogEntry[] = [
|
||||
...OAUTH_ENTRIES,
|
||||
...API_KEY_ENTRIES,
|
||||
...CLOUD_ENTRIES,
|
||||
...LOCAL_ENTRIES,
|
||||
];
|
||||
|
||||
export function findConnectorCatalogEntry(id: string): ConnectorCatalogEntry | undefined {
|
||||
|
||||
@@ -49,6 +49,9 @@ export const connectorIdEnum = z.enum([
|
||||
"amazon-bedrock",
|
||||
"azure-openai",
|
||||
"google-vertex",
|
||||
// Local (2)
|
||||
"ollama",
|
||||
"lm-studio",
|
||||
]);
|
||||
|
||||
export type ConnectorId = z.infer<typeof connectorIdEnum>;
|
||||
|
||||
@@ -6,6 +6,7 @@ export const credentialKindSchema = z.enum([
|
||||
"aws",
|
||||
"azure",
|
||||
"gcp_adc",
|
||||
"local",
|
||||
]);
|
||||
|
||||
export const credentialStatusSchema = z.enum([
|
||||
@@ -49,11 +50,16 @@ export const gcpAdcCredentialSchema = z.object({
|
||||
credentialsPath: z.string().optional(),
|
||||
});
|
||||
|
||||
export const localCredentialSchema = z.object({
|
||||
baseUrl: z.string().url(),
|
||||
});
|
||||
|
||||
export const credentialPayloadSchema = z.discriminatedUnion("kind", [
|
||||
z.object({ kind: z.literal("api_key"), value: apiKeyValueSchema }),
|
||||
z.object({ kind: z.literal("azure"), value: azureCredentialSchema }),
|
||||
z.object({ kind: z.literal("aws"), value: awsCredentialSchema }),
|
||||
z.object({ kind: z.literal("gcp_adc"), value: gcpAdcCredentialSchema }),
|
||||
z.object({ kind: z.literal("local"), value: localCredentialSchema }),
|
||||
]);
|
||||
|
||||
export const saveCredentialInputSchema = z.object({
|
||||
@@ -85,4 +91,5 @@ export type SaveCredentialInput = z.infer<typeof saveCredentialInputSchema>;
|
||||
export type AwsCredential = z.infer<typeof awsCredentialSchema>;
|
||||
export type AzureCredential = z.infer<typeof azureCredentialSchema>;
|
||||
export type GcpAdcCredential = z.infer<typeof gcpAdcCredentialSchema>;
|
||||
export type LocalCredential = z.infer<typeof localCredentialSchema>;
|
||||
export type ApiKeyValue = z.infer<typeof apiKeyValueSchema>;
|
||||
Reference in new issue
Block a user