diff --git a/.gitignore b/.gitignore index 4f97f90..b266ab5 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ db.sqlite* .agents/ .claude/ +.augment/ .cursor/ .playwright-mcp/ .antigravity/ diff --git a/app/extension/package.json b/app/extension/package.json index c64ce1a..1fad168 100644 --- a/app/extension/package.json +++ b/app/extension/package.json @@ -20,23 +20,22 @@ "url": "https://github.com/lcomplete/huntly" }, "dependencies": { - "@ai-sdk/anthropic": "^1.2.12", - "@ai-sdk/azure": "^1.3.24", - "@ai-sdk/deepseek": "^0.1.8", - "@ai-sdk/google": "^1.2.20", - "@ai-sdk/groq": "^1.1.14", - "@ai-sdk/openai": "^1.3.22", + "@ai-sdk/anthropic": "^3.0.58", + "@ai-sdk/azure": "^3.0.42", + "@ai-sdk/deepseek": "^2.0.24", + "@ai-sdk/google": "^3.0.43", + "@ai-sdk/groq": "^3.0.29", + "@ai-sdk/openai": "^3.0.41", "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", "@mozilla/readability": "^0.6.0", "@mui/icons-material": "^5.11.11", "@mui/material": "^5.11.14", "@types/turndown": "^5.0.6", - "ai": "^6.0.127", + "ai": "^6.0.116", "defuddle": "^0.6.6", "formik": "^2.2.9", "html2canvas": "^1.4.1", - "ollama-ai-provider": "^1.2.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-markdown": "^10.1.0", @@ -67,6 +66,6 @@ "style-loader": "^3.3.1", "tailwindcss": "^3.3.2", "ts-jest": "^27.0.5", - "typescript": "^4.4.3 " + "typescript": "^5.9.3" } } diff --git a/app/extension/src/__tests__/providers.test.ts b/app/extension/src/__tests__/providers.test.ts index 63a1da2..f4e5275 100644 --- a/app/extension/src/__tests__/providers.test.ts +++ b/app/extension/src/__tests__/providers.test.ts @@ -1,5 +1,7 @@ import { getOpenAICompatibleBaseUrl, + getOllamaBaseUrl, + getOllamaOpenAIBaseUrl, isDashScopeCompatibleBaseUrl, usesRawOpenAICompatibleStream, } from "../ai/openAICompatibleProviders"; @@ -90,4 +92,18 @@ describe("providers helpers", () => { }) ).toBe("https://example.com/v1"); }); + + it("normalizes Ollama base urls for model and chat endpoints", () => { + expect(getOllamaBaseUrl("http://localhost:11434/v1")).toBe( + "http://localhost:11434" + ); + expect(getOllamaBaseUrl(undefined)).toBe("http://localhost:11434"); + + expect(getOllamaOpenAIBaseUrl("http://localhost:11434")).toBe( + "http://localhost:11434/v1" + ); + expect(getOllamaOpenAIBaseUrl("http://localhost:11434/v1")).toBe( + "http://localhost:11434/v1" + ); + }); }); diff --git a/app/extension/src/ai/openAICompatibleProviders.ts b/app/extension/src/ai/openAICompatibleProviders.ts index 41d80bd..dd99b9c 100644 --- a/app/extension/src/ai/openAICompatibleProviders.ts +++ b/app/extension/src/ai/openAICompatibleProviders.ts @@ -34,3 +34,23 @@ export function getOpenAICompatibleBaseUrl( ): string | undefined { return config.baseUrl || PROVIDER_REGISTRY[config.type]?.defaultBaseUrl || undefined; } + +function trimTrailingSlash(url: string): string { + return url.replace(/\/+$/, ""); +} + +export function getOllamaBaseUrl(baseUrl?: string): string { + const normalizedBaseUrl = trimTrailingSlash( + baseUrl || PROVIDER_REGISTRY.ollama.defaultBaseUrl + ); + + return normalizedBaseUrl.endsWith("/v1") + ? normalizedBaseUrl.slice(0, -3) + : normalizedBaseUrl; +} + +export function getOllamaOpenAIBaseUrl(baseUrl?: string): string { + const normalizedBaseUrl = getOllamaBaseUrl(baseUrl); + + return `${normalizedBaseUrl}/v1`; +} diff --git a/app/extension/src/ai/providers.ts b/app/extension/src/ai/providers.ts index e7dfcf2..9e61f0f 100644 --- a/app/extension/src/ai/providers.ts +++ b/app/extension/src/ai/providers.ts @@ -4,19 +4,22 @@ import { createGoogleGenerativeAI } from '@ai-sdk/google'; import { createDeepSeek } from '@ai-sdk/deepseek'; import { createGroq } from '@ai-sdk/groq'; import { createAzure } from '@ai-sdk/azure'; -import { ollama, createOllama } from 'ollama-ai-provider'; -import { generateText, LanguageModelV1 } from 'ai'; +import { generateText, LanguageModel } from 'ai'; import { AIProviderConfig, ConnectionTestResult, PROVIDER_REGISTRY, } from './types'; -import { getOpenAICompatibleBaseUrl } from './openAICompatibleProviders'; +import { + getOpenAICompatibleBaseUrl, + getOllamaBaseUrl, + getOllamaOpenAIBaseUrl, +} from './openAICompatibleProviders'; export function createProviderModel( config: AIProviderConfig, modelId?: string -): LanguageModelV1 | null { +): LanguageModel | null { const model = modelId || config.enabledModels[0]; if (!model) return null; @@ -28,7 +31,7 @@ export function createProviderModel( apiKey: config.apiKey, baseURL: getOpenAICompatibleBaseUrl(config), }); - return provider(model) as LanguageModelV1; + return provider(model) as LanguageModel; } case 'anthropic': { @@ -39,7 +42,7 @@ export function createProviderModel( 'anthropic-dangerous-direct-browser-access': 'true', }, }); - return provider(model) as LanguageModelV1; + return provider(model) as LanguageModel; } case 'google': { @@ -47,7 +50,7 @@ export function createProviderModel( apiKey: config.apiKey, baseURL: config.baseUrl || undefined, }); - return provider(model) as LanguageModelV1; + return provider(model) as LanguageModel; } case 'deepseek': { @@ -55,24 +58,22 @@ export function createProviderModel( apiKey: config.apiKey, baseURL: config.baseUrl || undefined, }); - return provider(model) as LanguageModelV1; + return provider(model) as LanguageModel; } case 'groq': { const provider = createGroq({ apiKey: config.apiKey, }); - return provider(model) as LanguageModelV1; + return provider(model) as LanguageModel; } case 'ollama': { - if (config.baseUrl) { - const provider = createOllama({ - baseURL: config.baseUrl, - }); - return provider(model) as LanguageModelV1; - } - return ollama(model) as LanguageModelV1; + const provider = createOpenAI({ + apiKey: config.apiKey || 'ollama', + baseURL: getOllamaOpenAIBaseUrl(config.baseUrl), + }); + return provider(model) as LanguageModel; } case 'azure-openai': @@ -82,7 +83,7 @@ export function createProviderModel( apiKey: config.apiKey, baseURL: config.baseUrl, }); - return provider(model) as LanguageModelV1; + return provider(model) as LanguageModel; } case 'qwen': { @@ -91,7 +92,7 @@ export function createProviderModel( apiKey: config.apiKey, baseURL: getOpenAICompatibleBaseUrl(config), }); - return provider(model) as LanguageModelV1; + return provider(model) as LanguageModel; } case 'zhipu': { @@ -100,7 +101,7 @@ export function createProviderModel( apiKey: config.apiKey, baseURL: getOpenAICompatibleBaseUrl(config), }); - return provider(model) as LanguageModelV1; + return provider(model) as LanguageModel; } case 'minimax': { @@ -109,7 +110,7 @@ export function createProviderModel( apiKey: config.apiKey, baseURL: getOpenAICompatibleBaseUrl(config), }); - return provider(model) as LanguageModelV1; + return provider(model) as LanguageModel; } case 'huntly-server': { @@ -180,7 +181,7 @@ export async function testProviderConnection( const result = await generateText({ model, prompt: 'Say "OK" in one word.', - maxTokens: 5, + maxOutputTokens: 5, }); // Check if we got a valid response - result.text can be empty string for some models @@ -223,7 +224,7 @@ export async function testProviderConnection( export async function fetchOllamaModels(baseUrl?: string): Promise { try { - const url = (baseUrl || 'http://localhost:11434') + '/api/tags'; + const url = getOllamaBaseUrl(baseUrl) + '/api/tags'; const response = await fetch(url); if (!response.ok) { return []; diff --git a/app/extension/src/ai/streamingPreview.ts b/app/extension/src/ai/streamingPreview.ts index af4c123..2810e48 100644 --- a/app/extension/src/ai/streamingPreview.ts +++ b/app/extension/src/ai/streamingPreview.ts @@ -8,6 +8,7 @@ export interface StreamingPreviewState { export interface StreamingPreviewChunk { type: string; + text?: string; textDelta?: string; } @@ -31,7 +32,7 @@ export function applyStreamingPreviewChunk( options: StreamingPreviewOptions = {} ): StreamingPreviewState { const includeReasoning = options.includeReasoning ?? true; - const textDelta = chunk.textDelta || ""; + const textDelta = chunk.text || chunk.textDelta || ""; if (!textDelta) { return state; } @@ -47,7 +48,7 @@ export function applyStreamingPreviewChunk( }; } - if (chunk.type === "reasoning") { + if (chunk.type === "reasoning" || chunk.type === "reasoning-delta") { if (!includeReasoning) { return state; } diff --git a/app/extension/src/background.ts b/app/extension/src/background.ts index 0e6ee24..60ee623 100644 --- a/app/extension/src/background.ts +++ b/app/extension/src/background.ts @@ -49,6 +49,7 @@ const vercelAIAbortControllers = new Map(); const badgeCache = new Map(); const SAVED_BADGE_TEXT = "✓"; const SAVED_BADGE_BG = "#15803D"; +const AI_MAX_OUTPUT_TOKENS = 20000; function arrayBufferToBase64(buffer: ArrayBuffer): string { const bytes = new Uint8Array(buffer); @@ -379,7 +380,7 @@ async function startProcessingWithVercelAI(task: any) { modelId, systemPrompt, userPrompt, - maxTokens: 8000, + maxTokens: AI_MAX_OUTPUT_TOKENS, requestBodyExtras: getThinkingModeOptions(Boolean(thinkingModeEnabled)), abortSignal: abortController.signal, onDelta: ({ contentDelta, reasoningDelta }) => { @@ -420,11 +421,11 @@ async function startProcessingWithVercelAI(task: any) { } // Use streamText for streaming response with abort signal - const result = await streamText({ + const result = streamText({ model, system: systemPrompt, prompt: userPrompt, - maxTokens: 8000, + maxOutputTokens: AI_MAX_OUTPUT_TOKENS, abortSignal: abortController.signal, }); @@ -448,8 +449,8 @@ async function startProcessingWithVercelAI(task: any) { try { sendStreamingPreviewUpdate( streamState, - chunk.type === "text-delta" || chunk.type === "reasoning" - ? chunk.textDelta + chunk.type === "text-delta" || chunk.type === "reasoning-delta" + ? chunk.text : "" ); } catch (error) { diff --git a/app/extension/src/components/ArticlePreview.tsx b/app/extension/src/components/ArticlePreview.tsx index 6625cf0..dc44ca9 100644 --- a/app/extension/src/components/ArticlePreview.tsx +++ b/app/extension/src/components/ArticlePreview.tsx @@ -2,7 +2,12 @@ import React, { useState, useEffect, useCallback, useRef, forwardRef, useImperat import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import TurndownService from "turndown"; -import { ContentParserType, readSyncStorageSettings } from "../storage"; +import { + ContentParserType, + readSyncStorageSettings, + getThinkingModeEnabled, + saveThinkingModeEnabled, +} from "../storage"; import { PageOperateResult } from "../model/pageOperateResult"; import { parseDocument } from "../parser/contentParser"; import AIToolbar, { @@ -222,7 +227,7 @@ export const ArticlePreview: React.FC = ({ } | null>(null); const [serverConfigured, setServerConfigured] = useState(false); const [thinkingModeEnabled, setThinkingModeEnabled] = useState( - initialThinkingModeEnabled + initialThinkingModeEnabled ?? false ); // Refs for export functionality @@ -236,6 +241,35 @@ export const ArticlePreview: React.FC = ({ }); }, []); + useEffect(() => { + let cancelled = false; + + if (typeof initialThinkingModeEnabled === "boolean") { + setThinkingModeEnabled(initialThinkingModeEnabled); + return () => { + cancelled = true; + }; + } + + getThinkingModeEnabled().then((savedThinkingModeEnabled) => { + if (!cancelled) { + setThinkingModeEnabled(savedThinkingModeEnabled); + } + }); + + return () => { + cancelled = true; + }; + }, [initialThinkingModeEnabled]); + + const handleThinkingModeToggle = useCallback(() => { + setThinkingModeEnabled((prev) => { + const next = !prev; + void saveThinkingModeEnabled(next); + return next; + }); + }, []); + // Get shadow container for MUI Menu components const shadowContainer = useShadowContainer(); @@ -500,9 +534,7 @@ export const ArticlePreview: React.FC = ({ initialSelectedModel={autoSelectedModel} showThinkingToggle={true} thinkingModeEnabled={thinkingModeEnabled} - onThinkingModeToggle={() => - setThinkingModeEnabled((prev) => !prev) - } + onThinkingModeToggle={handleThinkingModeToggle} /> {/* Right section: Export group, Edit button, Parser selector and Close button */} diff --git a/app/extension/src/popup.tsx b/app/extension/src/popup.tsx index cb5f72d..4ea51ad 100644 --- a/app/extension/src/popup.tsx +++ b/app/extension/src/popup.tsx @@ -22,7 +22,13 @@ import { TextField, Tooltip, Typography } from "@mui/material"; -import { readSyncStorageSettings, StorageSettings, ContentParserType } from "./storage"; +import { + readSyncStorageSettings, + StorageSettings, + ContentParserType, + getThinkingModeEnabled, + saveThinkingModeEnabled, +} from "./storage"; import { combineUrl } from "./utils"; import PersonPinIcon from '@mui/icons-material/PersonPin'; import ArticleIcon from '@mui/icons-material/Article'; @@ -280,17 +286,28 @@ const Popup = () => { useEffect(() => { let cancelled = false; - readSyncStorageSettings().then((settings) => { - if (!cancelled) { - setSettingsState(settings); + Promise.all([readSyncStorageSettings(), getThinkingModeEnabled()]).then( + ([settings, savedThinkingModeEnabled]) => { + if (!cancelled) { + setThinkingModeEnabled(savedThinkingModeEnabled); + setSettingsState(settings); + } } - }); + ); return () => { cancelled = true; }; }, [setSettingsState]); + const handleThinkingModeToggle = useCallback(() => { + setThinkingModeEnabled((prev) => { + const next = !prev; + void saveThinkingModeEnabled(next); + return next; + }); + }, []); + useEffect(() => { let cancelled = false; @@ -919,9 +936,7 @@ const Popup = () => { hideHuntlyAI={hideHuntlyAI} showThinkingToggle={true} thinkingModeEnabled={thinkingModeEnabled} - onThinkingModeToggle={() => - setThinkingModeEnabled((prev) => !prev) - } + onThinkingModeToggle={handleThinkingModeToggle} /> diff --git a/app/extension/src/storage.ts b/app/extension/src/storage.ts index 54567ec..d70558d 100644 --- a/app/extension/src/storage.ts +++ b/app/extension/src/storage.ts @@ -17,6 +17,7 @@ export const STORAGE_USER_PROMPTS = "userPrompts"; // User-created prompts only export const STORAGE_ENABLED_SYSTEM_PROMPTS = "enabledSystemPrompts"; // IDs of enabled system prompts export const STORAGE_HUNTLY_SHORTCUTS_ENABLED = "huntlyShortcutsEnabled"; export const STORAGE_SELECTED_MODEL_ID = "selectedModelId"; // Remember last selected model +export const STORAGE_THINKING_MODE_ENABLED = "thinkingModeEnabled"; // Remember last thinking mode state export type ServerUrlItem = { url: string, @@ -210,3 +211,14 @@ export async function getSelectedModelId(): Promise { const items = await chrome.storage.sync.get({ [STORAGE_SELECTED_MODEL_ID]: null }); return items[STORAGE_SELECTED_MODEL_ID]; } + +export async function saveThinkingModeEnabled(enabled: boolean): Promise { + await chrome.storage.sync.set({ [STORAGE_THINKING_MODE_ENABLED]: enabled }); +} + +export async function getThinkingModeEnabled(): Promise { + const items = await chrome.storage.sync.get({ + [STORAGE_THINKING_MODE_ENABLED]: false, + }); + return Boolean(items[STORAGE_THINKING_MODE_ENABLED]); +} diff --git a/app/extension/yarn.lock b/app/extension/yarn.lock index 9b0251b..2cd017d 100644 --- a/app/extension/yarn.lock +++ b/app/extension/yarn.lock @@ -2,115 +2,73 @@ # yarn lockfile v1 -"@ai-sdk/anthropic@^1.2.12": - version "1.2.12" - resolved "https://registry.npmmirror.com/@ai-sdk/anthropic/-/anthropic-1.2.12.tgz#80a4b2527c6bb120778fbc83da4af775aae953a5" - integrity sha512-YSzjlko7JvuiyQFmI9RN1tNZdEiZxc+6xld/0tq/VkJaHpEzGAb1yiNxxvmYVcjvfu/PcvCxAAYXmTYQQ63IHQ== +"@ai-sdk/anthropic@^3.0.58": + version "3.0.58" + resolved "https://registry.npmmirror.com/@ai-sdk/anthropic/-/anthropic-3.0.58.tgz#de49aa3cb7e8a0115eb9d42da05f108d23a90822" + integrity sha512-/53SACgmVukO4bkms4dpxpRlYhW8Ct6QZRe6sj1Pi5H00hYhxIrqfiLbZBGxkdRvjsBQeP/4TVGsXgH5rQeb8Q== dependencies: - "@ai-sdk/provider" "1.1.3" - "@ai-sdk/provider-utils" "2.2.8" + "@ai-sdk/provider" "3.0.8" + "@ai-sdk/provider-utils" "4.0.19" -"@ai-sdk/azure@^1.3.24": - version "1.3.25" - resolved "https://registry.npmmirror.com/@ai-sdk/azure/-/azure-1.3.25.tgz#6cb113b95b4d02ea8cf0eb23a6393ee5e9ec09e6" - integrity sha512-cTME89A9UYrza0t5pbY9b80yYY02Q5ALQdB2WP3R7/Yl1PLwbFChx994Q3Un0G2XV5h3arlm4fZTViY10isjhQ== +"@ai-sdk/azure@^3.0.42": + version "3.0.42" + resolved "https://registry.npmmirror.com/@ai-sdk/azure/-/azure-3.0.42.tgz#57775e9d00b14fdc699ccf0b1359266b6ce949e7" + integrity sha512-BGg0e3GEI7KHkwUv7d5f9rXzDlTiWhQ4xzVakdHLV/OP24jvXes5X7fI3QZ0rbKBop6URq0yaxomBfwEqqRlzw== dependencies: - "@ai-sdk/openai" "1.3.24" - "@ai-sdk/provider" "1.1.3" - "@ai-sdk/provider-utils" "2.2.8" + "@ai-sdk/openai" "3.0.41" + "@ai-sdk/provider" "3.0.8" + "@ai-sdk/provider-utils" "4.0.19" -"@ai-sdk/deepseek@^0.1.8": - version "0.1.17" - resolved "https://registry.npmmirror.com/@ai-sdk/deepseek/-/deepseek-0.1.17.tgz#f76155ee7018f1218bc7e2d06126aac474ad4410" - integrity sha512-UGVPYJSgV8Z4mbEUhqh/uRM2mBUS5VoWA3MUN+gg4xPjh3IvwQwVHAYWNzEhmlTbySIv3DE6x7oTyuS73gHGbg== +"@ai-sdk/deepseek@^2.0.24": + version "2.0.24" + resolved "https://registry.npmmirror.com/@ai-sdk/deepseek/-/deepseek-2.0.24.tgz#c2e8aa1af5b7e4c7c21b355408ee58f659581163" + integrity sha512-4vOEekW4TAYVHN0qgiwoUOQZhguGwZBiEw8LDeUmpWBm07QkLRAtxYCaSoMiA4hZZojao5mj6NRGEBW1CnDPtg== dependencies: - "@ai-sdk/openai-compatible" "0.1.17" - "@ai-sdk/provider" "1.0.12" - "@ai-sdk/provider-utils" "2.1.15" + "@ai-sdk/provider" "3.0.8" + "@ai-sdk/provider-utils" "4.0.19" -"@ai-sdk/gateway@3.0.73": - version "3.0.73" - resolved "https://registry.npmmirror.com/@ai-sdk/gateway/-/gateway-3.0.73.tgz#e64dae6d8c5e133f0a38585fc44d118a74ff23ae" - integrity sha512-i8eSbEjmYSb8SPUW28DGRKjvxrzI4RVauISvFfbQUlNf4a4tu6gMXmuGcOZWhs1AvAIswP1nPFTltmJXrxPFcA== +"@ai-sdk/gateway@3.0.66": + version "3.0.66" + resolved "https://registry.npmmirror.com/@ai-sdk/gateway/-/gateway-3.0.66.tgz#64ad8f7b45acaa4c93c53be2bb39e772e49e31b5" + integrity sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A== dependencies: "@ai-sdk/provider" "3.0.8" - "@ai-sdk/provider-utils" "4.0.20" + "@ai-sdk/provider-utils" "4.0.19" "@vercel/oidc" "3.1.0" -"@ai-sdk/google@^1.2.20": - version "1.2.22" - resolved "https://registry.npmmirror.com/@ai-sdk/google/-/google-1.2.22.tgz#9993e4781c9a773cd17d47490b9efdc90895abd2" - integrity sha512-Ppxu3DIieF1G9pyQ5O1Z646GYR0gkC57YdBqXJ82qvCdhEhZHu0TWhmnOoeIWe2olSbuDeoOY+MfJrW8dzS3Hw== - dependencies: - "@ai-sdk/provider" "1.1.3" - "@ai-sdk/provider-utils" "2.2.8" - -"@ai-sdk/groq@^1.1.14": - version "1.2.9" - resolved "https://registry.npmmirror.com/@ai-sdk/groq/-/groq-1.2.9.tgz#e3987bae374a714ab9dd3589bbf5e1e13e5f5751" - integrity sha512-7MoDaxm8yWtiRbD1LipYZG0kBl+Xe0sv/EeyxnHnGPZappXdlgtdOgTZVjjXkT3nWP30jjZi9A45zoVrBMb3Xg== - dependencies: - "@ai-sdk/provider" "1.1.3" - "@ai-sdk/provider-utils" "2.2.8" - -"@ai-sdk/openai-compatible@0.1.17": - version "0.1.17" - resolved "https://registry.npmmirror.com/@ai-sdk/openai-compatible/-/openai-compatible-0.1.17.tgz#1d85158879ead78ad5e126d0dc62f2297a18b143" - integrity sha512-e60+yxQ29e8RlsTWBW4kLuQJMpVJzH5+cpOeUXLXU6M9wc8BOQCyYg4jYh2ldnfvYCKXYxb2kYeLW7L9fqhhMw== +"@ai-sdk/google@^3.0.43": + version "3.0.43" + resolved "https://registry.npmmirror.com/@ai-sdk/google/-/google-3.0.43.tgz#e955d8cb8a598bc75d5aa39d4eaf1cc580dc1ac8" + integrity sha512-NGCgP5g8HBxrNdxvF8Dhww+UKfqAkZAmyYBvbu9YLoBkzAmGKDBGhVptN/oXPB5Vm0jggMdoLycZ8JReQM8Zqg== dependencies: - "@ai-sdk/provider" "1.0.12" - "@ai-sdk/provider-utils" "2.1.15" - -"@ai-sdk/openai@1.3.24", "@ai-sdk/openai@^1.3.22": - version "1.3.24" - resolved "https://registry.npmmirror.com/@ai-sdk/openai/-/openai-1.3.24.tgz#169b78a1ccf338e5dbd8696a55f57d3ca2e3d6bc" - integrity sha512-GYXnGJTHRTZc4gJMSmFRgEQudjqd4PUN0ZjQhPwOAYH1yOAvQoG/Ikqs+HyISRbLPCrhbZnPKCNHuRU4OfpW0Q== - dependencies: - "@ai-sdk/provider" "1.1.3" - "@ai-sdk/provider-utils" "2.2.8" + "@ai-sdk/provider" "3.0.8" + "@ai-sdk/provider-utils" "4.0.19" -"@ai-sdk/provider-utils@2.1.15": - version "2.1.15" - resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-2.1.15.tgz#20d23dfada7d988bebf176fdfc62b48fca7bd822" - integrity sha512-ndMVtDm2xS86t45CJZSfyl7UblZFewRB8gZkXQHeNi7BhjCYkhE+XQMwfDl6UOAO7kaV60IC1R4JLDWxWiiHug== +"@ai-sdk/groq@^3.0.29": + version "3.0.29" + resolved "https://registry.npmmirror.com/@ai-sdk/groq/-/groq-3.0.29.tgz#f9160dee6a67a69e71119b12b2ab30299f2a0870" + integrity sha512-I/tUoHuOvGXbIr1dJ0CLRLA7W0UPDMtrYT5mgeb3O+P+6I5BAm/7riPwr22Xw5YTzpwQxcoDQlIczOU9XDXBpA== dependencies: - "@ai-sdk/provider" "1.0.12" - eventsource-parser "^3.0.0" - nanoid "^3.3.8" - secure-json-parse "^2.7.0" + "@ai-sdk/provider" "3.0.8" + "@ai-sdk/provider-utils" "4.0.19" -"@ai-sdk/provider-utils@2.2.8", "@ai-sdk/provider-utils@^2.0.0": - version "2.2.8" - resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz#ad11b92d5a1763ab34ba7b5fc42494bfe08b76d1" - integrity sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA== +"@ai-sdk/openai@3.0.41", "@ai-sdk/openai@^3.0.41": + version "3.0.41" + resolved "https://registry.npmmirror.com/@ai-sdk/openai/-/openai-3.0.41.tgz#22f559888cd4f9bb312c5c576441c3412f442e7b" + integrity sha512-IZ42A+FO+vuEQCVNqlnAPYQnnUpUfdJIwn1BEDOBywiEHa23fw7PahxVtlX9zm3/zMvTW4JKPzWyvAgDu+SQ2A== dependencies: - "@ai-sdk/provider" "1.1.3" - nanoid "^3.3.8" - secure-json-parse "^2.7.0" + "@ai-sdk/provider" "3.0.8" + "@ai-sdk/provider-utils" "4.0.19" -"@ai-sdk/provider-utils@4.0.20": - version "4.0.20" - resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-4.0.20.tgz#4dc0ea5cfdb2c0fbac375342d689f11fb0b8185e" - integrity sha512-gpUIj9uDhIGbuo9afKEgQ074BWmhvK4THJAAeBjRnroTy2yQYo6rbtGD7pQDMZM8ouXPYmT/SCdkWVJ0KcpX8A== +"@ai-sdk/provider-utils@4.0.19": + version "4.0.19" + resolved "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-4.0.19.tgz#535f87c34f19d5584068c522005780ba59123093" + integrity sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg== dependencies: "@ai-sdk/provider" "3.0.8" "@standard-schema/spec" "^1.1.0" eventsource-parser "^3.0.6" -"@ai-sdk/provider@1.0.12": - version "1.0.12" - resolved "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-1.0.12.tgz#f2df2b1f17863e213b5138d27cd5d09bcb6f976c" - integrity sha512-88Uu1zJIE1UUOVJWfE2ybJXgiH8JJ97QY9fbmplErEbfa/k/1kF+tWMVAAJolF2aOGmazQGyQLhv4I9CCuVACw== - dependencies: - json-schema "^0.4.0" - -"@ai-sdk/provider@1.1.3", "@ai-sdk/provider@^1.0.0": - version "1.1.3" - resolved "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-1.1.3.tgz#ebdda8077b8d2b3f290dcba32c45ad19b2704681" - integrity sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg== - dependencies: - json-schema "^0.4.0" - "@ai-sdk/provider@3.0.8": version "3.0.8" resolved "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-3.0.8.tgz#fd7fac7533c03534ac1d3fb710a6b96e2aa00263" @@ -1908,14 +1866,14 @@ agent-base@6: dependencies: debug "4" -ai@^6.0.127: - version "6.0.127" - resolved "https://registry.npmmirror.com/ai/-/ai-6.0.127.tgz#3b05b8c08b95e9dffb73af438e373fa10fe24e08" - integrity sha512-DKl0MJRuf3DUg+YHThbPXx9Jhd4vTZ6xAKXhVpy+WUrxSC2MgwA+V80ftx89JHGSTD1RVc0d3yIpKPNU4VKsAg== +ai@^6.0.116: + version "6.0.116" + resolved "https://registry.npmmirror.com/ai/-/ai-6.0.116.tgz#dc1c3d929453e165fcd3f188d8663617ecf94129" + integrity sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA== dependencies: - "@ai-sdk/gateway" "3.0.73" + "@ai-sdk/gateway" "3.0.66" "@ai-sdk/provider" "3.0.8" - "@ai-sdk/provider-utils" "4.0.20" + "@ai-sdk/provider-utils" "4.0.19" "@opentelemetry/api" "1.9.0" ajv-formats@^2.1.1: @@ -2896,7 +2854,7 @@ eventemitter3@^4.0.0: resolved "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -eventsource-parser@^3.0.0, eventsource-parser@^3.0.6: +eventsource-parser@^3.0.6: version "3.0.6" resolved "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-3.0.6.tgz#292e165e34cacbc936c3c92719ef326d4aeb4e90" integrity sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg== @@ -4887,11 +4845,6 @@ nanoid@^3.3.6: resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== -nanoid@^3.3.8: - version "3.3.11" - resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" - integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" @@ -4964,15 +4917,6 @@ obuf@^1.0.0, obuf@^1.1.2: resolved "https://registry.npmmirror.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -ollama-ai-provider@^1.2.0: - version "1.2.0" - resolved "https://registry.npmmirror.com/ollama-ai-provider/-/ollama-ai-provider-1.2.0.tgz#b052c8ad96ef8048185a7ac01ee9351a0cedf0ce" - integrity sha512-jTNFruwe3O/ruJeppI/quoOUxG7NA6blG3ZyQj3lei4+NnJo7bi3eIRWqlVpRlu/mbzbFXeJSBuYQWF6pzGKww== - dependencies: - "@ai-sdk/provider" "^1.0.0" - "@ai-sdk/provider-utils" "^2.0.0" - partial-json "0.1.7" - on-finished@^2.4.1, on-finished@~2.4.1: version "2.4.1" resolved "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -5094,11 +5038,6 @@ parseurl@~1.3.3: resolved "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -partial-json@0.1.7: - version "0.1.7" - resolved "https://registry.npmmirror.com/partial-json/-/partial-json-0.1.7.tgz#b735a89edb3e25f231a3c4caeaae71dc9f578605" - integrity sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" @@ -5899,11 +5838,6 @@ schema-utils@^4.0.0, schema-utils@^4.2.0: ajv-formats "^2.1.1" ajv-keywords "^5.1.0" -secure-json-parse@^2.7.0: - version "2.7.0" - resolved "https://registry.npmmirror.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" - integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== - select-hose@^2.0.0: version "2.0.0" resolved "https://registry.npmmirror.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -6515,10 +6449,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -"typescript@^4.4.3 ": - version "4.9.5" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@^5.9.3: + version "5.9.3" + resolved "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== unified@^11.0.0: version "11.0.5"