diff --git a/apps/cli/package-lock.json b/apps/cli/package-lock.json index b54512a7..e7ac73b5 100644 --- a/apps/cli/package-lock.json +++ b/apps/cli/package-lock.json @@ -1,13 +1,13 @@ { "name": "@rowboatlabs/rowboatx", - "version": "0.3.0", + "version": "0.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rowboatlabs/rowboatx", - "version": "0.3.0", - "license": "MIT", + "version": "0.9.0", + "license": "Apache-2.0", "dependencies": { "@ai-sdk/anthropic": "^2.0.44", "@ai-sdk/google": "^2.0.25", @@ -16,6 +16,7 @@ "ai": "^5.0.78", "json-schema-to-zod": "^2.6.1", "nanoid": "^5.1.6", + "ollama-ai-provider-v2": "^1.5.4", "yargs": "^18.0.0", "zod": "^4.1.12" }, @@ -1099,6 +1100,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ollama-ai-provider-v2": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ollama-ai-provider-v2/-/ollama-ai-provider-v2-1.5.4.tgz", + "integrity": "sha512-OTxzIvxW7GutgkyYe55Y4lJeUbnDjH1jDkAQhjGiynffkDn0wyWbv/dD92A8HX1ni5Ec+i+ksYMXXlVOYPQR4g==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "^2.0.0", + "@ai-sdk/provider-utils": "^3.0.17" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^4.0.16" + } + }, + "node_modules/ollama-ai-provider-v2/node_modules/@ai-sdk/provider-utils": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.17.tgz", + "integrity": "sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", diff --git a/apps/cli/package.json b/apps/cli/package.json index d0e26bb7..39cfd474 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -32,6 +32,7 @@ "ai": "^5.0.78", "json-schema-to-zod": "^2.6.1", "nanoid": "^5.1.6", + "ollama-ai-provider-v2": "^1.5.4", "yargs": "^18.0.0", "zod": "^4.1.12" } diff --git a/apps/cli/src/application/config/config.ts b/apps/cli/src/application/config/config.ts index 7b94d5dd..ac0d866a 100644 --- a/apps/cli/src/application/config/config.ts +++ b/apps/cli/src/application/config/config.ts @@ -35,8 +35,11 @@ const baseModelConfig: z.infer = { flavor: "anthropic", }, google: { - flavor: "google" + flavor: "google", }, + ollama: { + flavor: "ollama", + } }, defaults: { provider: "openai", diff --git a/apps/cli/src/application/entities/models.ts b/apps/cli/src/application/entities/models.ts index 69c7e573..68f6dcfb 100644 --- a/apps/cli/src/application/entities/models.ts +++ b/apps/cli/src/application/entities/models.ts @@ -1,9 +1,10 @@ import z from "zod"; export const Provider = z.object({ - flavor: z.enum(["openai", "anthropic", "google"]), + flavor: z.enum(["openai", "anthropic", "google", "ollama"]), apiKey: z.string().optional(), baseURL: z.string().optional(), + headers: z.record(z.string(), z.string()).optional(), }); export const ModelConfig = z.object({ diff --git a/apps/cli/src/application/lib/models.ts b/apps/cli/src/application/lib/models.ts index de35dba3..35e62e72 100644 --- a/apps/cli/src/application/lib/models.ts +++ b/apps/cli/src/application/lib/models.ts @@ -1,9 +1,10 @@ import { createOpenAI, OpenAIProvider } from "@ai-sdk/openai"; import { createGoogleGenerativeAI, GoogleGenerativeAIProvider } from "@ai-sdk/google"; import { AnthropicProvider, createAnthropic } from "@ai-sdk/anthropic"; +import { OllamaProvider, createOllama } from "ollama-ai-provider-v2"; import { ModelConfig } from "../config/config.js"; -const providerMap: Record = {}; +const providerMap: Record = {}; export function getProvider(name: string = "") { if (!name) { @@ -21,18 +22,27 @@ export function getProvider(name: string = "") { providerMap[name] = createOpenAI({ apiKey: providerConfig.apiKey, baseURL: providerConfig.baseURL, + headers: providerConfig.headers, }); break; case "anthropic": providerMap[name] = createAnthropic({ apiKey: providerConfig.apiKey, baseURL: providerConfig.baseURL, + headers: providerConfig.headers, }); break; case "google": providerMap[name] = createGoogleGenerativeAI({ apiKey: providerConfig.apiKey, baseURL: providerConfig.baseURL, + headers: providerConfig.headers, + }); + break; + case "ollama": + providerMap[name] = createOllama({ + baseURL: providerConfig.baseURL, + headers: providerConfig.headers, }); break; }