diff --git a/README.md b/README.md index 20dafa5..53e1ef4 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ Environment variable overrides: "openai": { "apiKey": "..." }, "google": { "apiKey": "..." }, "openrouter": { "apiKey": "..." }, - "ollama": { "apiBase": "http://localhost:11434/api" } + "ollama": { "apiBase": "http://localhost:11434" } }, "channels": { "sendProgress": true, @@ -192,7 +192,7 @@ The `agent.model` field is also **required** and should be the model ID without | `openrouter` | `anthropic/claude-sonnet-4-5` (OpenRouter uses its own model IDs) | | `ollama` | `llama3.2`, `qwen2.5` | -For Ollama, set `providers.ollama.apiBase` (default: `http://localhost:11434/api`). +For Ollama, set `providers.ollama.apiBase` (default: `http://localhost:11434`). ### Mattermost setup diff --git a/bun.lock b/bun.lock index 3c04bdd..61e29f7 100644 --- a/bun.lock +++ b/bun.lock @@ -11,12 +11,12 @@ "@mozilla/readability": "^0.6.0", "@openrouter/ai-sdk-provider": "^2.3.0", "ai": "^6.0.116", + "ai-sdk-ollama": "^3.8.0", "commander": "^14.0.3", "cron-parser": "^5.5.0", "js-tiktoken": "^1.0.21", "jsonrepair": "^3.13.3", "node-html-parser": "^7.1.0", - "ollama-ai-provider": "^1.2.0", "picocolors": "^1.1.1", "zod": "^4.3.6", }, @@ -151,6 +151,8 @@ "ai": ["ai@6.0.116", "", { "dependencies": { "@ai-sdk/gateway": "3.0.66", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA=="], + "ai-sdk-ollama": ["ai-sdk-ollama@3.8.0", "", { "dependencies": { "@ai-sdk/provider": "^3.0.8", "@ai-sdk/provider-utils": "^4.0.15", "jsonrepair": "^3.13.2", "ollama": "^0.6.3" }, "peerDependencies": { "ai": "^6.0.89" } }, "sha512-Nlla8FpK8QFMNh9m8sPCZoNqnr+n+Ud0QTqpXNds4j/b/lbVZGaji13ZcRuuFvBwPwd4xnFkNrijJzi70Ih1Tg=="], + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], @@ -187,13 +189,11 @@ "luxon": ["luxon@3.7.2", "", {}, "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew=="], - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "node-html-parser": ["node-html-parser@7.1.0", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-iJo8b2uYGT40Y8BTyy5ufL6IVbN8rbm/1QK2xffXU/1a/v3AAa0d1YAoqBNYqaS4R/HajkWIpIfdE6KcyFh1AQ=="], "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], - "ollama-ai-provider": ["ollama-ai-provider@1.2.0", "", { "dependencies": { "@ai-sdk/provider": "^1.0.0", "@ai-sdk/provider-utils": "^2.0.0", "partial-json": "0.1.7" }, "peerDependencies": { "zod": "^3.0.0" }, "optionalPeers": ["zod"] }, "sha512-jTNFruwe3O/ruJeppI/quoOUxG7NA6blG3ZyQj3lei4+NnJo7bi3eIRWqlVpRlu/mbzbFXeJSBuYQWF6pzGKww=="], + "ollama": ["ollama@0.6.3", "", { "dependencies": { "whatwg-fetch": "^3.6.20" } }, "sha512-KEWEhIqE5wtfzEIZbDCLH51VFZ6Z3ZSa6sIOg/E/tBV8S51flyqBOXi+bRxlOYKDf8i327zG9eSTb8IJxvm3Zg=="], "oxfmt": ["oxfmt@0.40.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.40.0", "@oxfmt/binding-android-arm64": "0.40.0", "@oxfmt/binding-darwin-arm64": "0.40.0", "@oxfmt/binding-darwin-x64": "0.40.0", "@oxfmt/binding-freebsd-x64": "0.40.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.40.0", "@oxfmt/binding-linux-arm-musleabihf": "0.40.0", "@oxfmt/binding-linux-arm64-gnu": "0.40.0", "@oxfmt/binding-linux-arm64-musl": "0.40.0", "@oxfmt/binding-linux-ppc64-gnu": "0.40.0", "@oxfmt/binding-linux-riscv64-gnu": "0.40.0", "@oxfmt/binding-linux-riscv64-musl": "0.40.0", "@oxfmt/binding-linux-s390x-gnu": "0.40.0", "@oxfmt/binding-linux-x64-gnu": "0.40.0", "@oxfmt/binding-linux-x64-musl": "0.40.0", "@oxfmt/binding-openharmony-arm64": "0.40.0", "@oxfmt/binding-win32-arm64-msvc": "0.40.0", "@oxfmt/binding-win32-ia32-msvc": "0.40.0", "@oxfmt/binding-win32-x64-msvc": "0.40.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-g0C3I7xUj4b4DcagevM9kgH6+pUHytikxUcn3/VUkvzTNaaXBeyZqb7IBsHwojeXm4mTBEC/aBjBTMVUkZwWUQ=="], @@ -201,22 +201,16 @@ "oxlint-tsgolint": ["oxlint-tsgolint@0.16.0", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.16.0", "@oxlint-tsgolint/darwin-x64": "0.16.0", "@oxlint-tsgolint/linux-arm64": "0.16.0", "@oxlint-tsgolint/linux-x64": "0.16.0", "@oxlint-tsgolint/win32-arm64": "0.16.0", "@oxlint-tsgolint/win32-x64": "0.16.0" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-4RuJK2jP08XwqtUu+5yhCbxEauCm6tv2MFHKEMsjbosK2+vy5us82oI3VLuHwbNyZG7ekZA26U2LLHnGR4frIA=="], - "partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="], - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], - "tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], + "whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], - - "ollama-ai-provider/@ai-sdk/provider": ["@ai-sdk/provider@1.1.3", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="], - - "ollama-ai-provider/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="], } } diff --git a/memory-bank/activeContext.md b/memory-bank/activeContext.md index 239d4c2..6f1bb1c 100644 --- a/memory-bank/activeContext.md +++ b/memory-bank/activeContext.md @@ -26,14 +26,15 @@ Docs directory created with 4 files (PRD.md, Architecture.md, API.md, Discoverie 5. [x] Provider resolution uses explicit provider from config (no model prefix parsing) 6. [x] Typecheck and lint pass (0 errors) 7. [x] Test onboard and agent commands work correctly -8. [ ] Test with a real Mattermost config (optional — user can do this) +8. [x] Updated Ollama provider from `ollama-ai-provider` to `ai-sdk-ollama` +9. [ ] Test with a real Mattermost config (optional — user can do this) ## Key Decisions Made - Mattermost channel uses raw WebSocket + fetch (no mattermostdriver, no SSL hack) - No MCP support (use shell tools / CLI instead) - No reasoning/thinking token handling (can add later) - Config is fresh Zod schema (no migration from Python config needed) -- `ollama-ai-provider` package (not `@ai-sdk/ollama` which 404s on npm) +- `ai-sdk-ollama` package for Ollama provider (replaced old `ollama-ai-provider`) - `strArg(args, key, fallback?)` helper exported from `agent/tools/base.ts` for safe unknown→string extraction - Agent config requires explicit `provider` field (no more model prefix like "anthropic/claude-...") - Model names are now just the raw model ID (e.g., "claude-sonnet-4-5" not "anthropic/claude-sonnet-4-5") diff --git a/package.json b/package.json index 4a7596c..c6a50c0 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,12 @@ "@mozilla/readability": "^0.6.0", "@openrouter/ai-sdk-provider": "^2.3.0", "ai": "^6.0.116", + "ai-sdk-ollama": "^3.8.0", "commander": "^14.0.3", "cron-parser": "^5.5.0", "js-tiktoken": "^1.0.21", "jsonrepair": "^3.13.3", "node-html-parser": "^7.1.0", - "ollama-ai-provider": "^1.2.0", "picocolors": "^1.1.1", "zod": "^4.3.6" }, diff --git a/src/provider/index.ts b/src/provider/index.ts index 3c509aa..6a02229 100644 --- a/src/provider/index.ts +++ b/src/provider/index.ts @@ -4,7 +4,7 @@ import { createOpenAI } from '@ai-sdk/openai'; import { createOpenRouter } from '@openrouter/ai-sdk-provider'; import { type ModelMessage, generateText, stepCountIs } from 'ai'; import { jsonrepair } from 'jsonrepair'; -import { createOllama } from 'ollama-ai-provider'; +import { createOllama } from 'ai-sdk-ollama'; import type { AgentProvider, ProvidersConfig } from '../config/types.ts'; import type { ChatOptions, LLMResponse, ToolDefinition } from './types.ts'; @@ -109,10 +109,7 @@ export class LLMProvider { } case 'ollama': { const cfg = this._providers.ollama; - // ollama-ai-provider returns LanguageModelV1; cast to LanguageModel (compatible at runtime) - return createOllama({ baseURL: cfg?.apiBase ?? 'http://localhost:11434/api' })( - model, - ) as unknown as LanguageModel; + return createOllama({ apiKey: cfg?.apiKey, baseURL: cfg?.apiBase })(model); } } }