diff --git a/docs/operations.md b/docs/operations.md index 204e88b..c47b4d0 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -95,8 +95,9 @@ All of these can go in `.env` (auto-loaded) or your shell. | `ANTHROPIC_API_KEY` | (none) | Set if not using subscription auth. | | `OPENAI_API_KEY` | (none) | Same. | | `EXXETA_KB_VAULTS` | (none) | Optional override/additional Markdown vault config for the knowledge tools. Primary persistent config is `~/.exxperts/app/kb-vaults.json`. | -| `EXXETA_SEARCH_PROVIDER` | (unset = built-in DuckDuckGo) | Web search provider: unset for the built-in DuckDuckGo backend, `searxng` for a local SearXNG, `disabled` to turn web search off. | +| `EXXETA_SEARCH_PROVIDER` | (unset = built-in DuckDuckGo) | Web search provider: unset for the built-in DuckDuckGo backend, `searxng` for a local SearXNG, `youcom` for You.com search, `disabled` to turn web search off. | | `EXXETA_SEARCH_BASE_URL` | (none) | Required when `EXXETA_SEARCH_PROVIDER=searxng`, for example `http://127.0.0.1:8888`. Start a local instance with `./scripts/searxng start`. | +| `YOU_API_KEY` or `YDC_API_KEY` | (none) | Required when `EXXETA_SEARCH_PROVIDER=youcom`. Get your API key at [you.com/platform/api-keys](https://you.com/platform/api-keys). | | `PORT` | `8787` | Web server port. | ## Local SearXNG @@ -110,11 +111,18 @@ node scripts\searxng.mjs start # Windows (PowerShell or cmd) The helper writes `~/.exxperts/app/web-search.json` if no web-search config exists yet. Equivalent `.env` overrides are: +**For SearXNG:** ```bash EXXETA_SEARCH_PROVIDER=searxng EXXETA_SEARCH_BASE_URL=http://127.0.0.1:8888 ``` +**For You.com:** +```bash +EXXETA_SEARCH_PROVIDER=youcom +YOU_API_KEY=your_api_key_here +``` + The helper writes generated SearXNG settings to `~/.exxperts/app/searxng/settings.yml` with SearXNG JSON output enabled because `web_search` calls `/search?format=json`. Full reference: [`web-search.md`](web-search.md). ## Ports diff --git a/docs/web-search.md b/docs/web-search.md index fb890ff..530e652 100644 --- a/docs/web-search.md +++ b/docs/web-search.md @@ -6,7 +6,9 @@ DuckDuckGo rate-limits automated queries, and on some networks it blocks them outright; when that happens the room shows an honest error naming the block. For heavy use, or on a network where DuckDuckGo blocks searches, a **local SearXNG container** is the reliable path: it aggregates several -engines and is not subject to DuckDuckGo's limits. When SearXNG is configured it is always preferred; +engines and is not subject to DuckDuckGo's limits. **You.com** provides +enhanced web search with an optional API key for improved results and +higher quotas. When SearXNG is configured it is always preferred; if it stops answering, searches fall back to the built-in DuckDuckGo backend until it is back. Setting `EXXETA_SEARCH_PROVIDER=disabled` turns web search off entirely. @@ -16,6 +18,30 @@ search engine (DuckDuckGo directly, or the engines SearXNG aggregates), so search terms do leave the machine; results and the rest of your data do not. Avoid searching confidential client/internal content. +The following sections cover optional search provider setup. For SearXNG, +the standard way to turn it on is `exxperts setup search`; for You.com, +set the environment variables described below. + +## Setup (optional You.com) + +You.com provides enhanced web search with better result quality and higher +quotas compared to the default DuckDuckGo backend. + +1. **Get an API key** (one-time): Visit [you.com/platform/api-keys](https://you.com/platform/api-keys) + to create a free account and generate your API key. +2. **Set environment variables** before starting exxperts: + ```bash + export EXXETA_SEARCH_PROVIDER=youcom + export YOU_API_KEY=your_api_key_here + # OR alternatively: + # export YDC_API_KEY=your_api_key_here + ``` +3. **Start exxperts** as usual (`exxperts web`, `exxperts cli`, or the desktop app). + +That's it: web search now uses You.com for all queries. You.com does not +require any additional setup like Docker containers, and provides consistent +results without rate limiting issues. + The rest of this page covers the optional SearXNG setup. The standard way to turn it on, on any install type, is `exxperts setup search`; the setup below walks through it, with the script-level detail for developers working from a @@ -87,3 +113,7 @@ exists yet, plus generated SearXNG settings to `~/.exxperts/app/searxng/settings.yml` (JSON output enabled, because `web_search` calls `/search?format=json`). Environment variables override the shared config; see [`operations.md`](operations.md) for `EXXETA_SEARCH_*`. + +**You.com configuration:** +- `EXXETA_SEARCH_PROVIDER=youcom` - Enable You.com search provider +- `YOU_API_KEY` or `YDC_API_KEY` - Your You.com API key from [you.com/platform/api-keys](https://you.com/platform/api-keys) diff --git a/package-lock.json b/package-lock.json index 4dd840c..23350f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3359,9 +3359,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3378,9 +3375,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3397,9 +3391,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3416,9 +3407,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3435,9 +3423,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3694,9 +3679,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3717,9 +3699,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3740,9 +3719,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3763,9 +3739,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3786,9 +3759,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4021,9 +3991,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4038,9 +4005,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4055,9 +4019,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4072,9 +4033,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4089,9 +4047,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4106,9 +4061,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4123,9 +4075,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4140,9 +4089,6 @@ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4157,9 +4103,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4174,9 +4117,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4191,9 +4131,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4208,9 +4145,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4225,9 +4159,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -11347,11 +11278,7 @@ "@types/node": "^20.0.0" } }, - "runtime": { - "dev": true, - "optional": true, - "peer": true - }, + "runtime": {}, "runtime/node_modules/@lit-labs/ssr-dom-shim": { "version": "1.5.1", "license": "BSD-3-Clause", diff --git a/pi-package/extensions/web-search/index.ts b/pi-package/extensions/web-search/index.ts index 6ab32ce..7b8350c 100644 --- a/pi-package/extensions/web-search/index.ts +++ b/pi-package/extensions/web-search/index.ts @@ -6,9 +6,10 @@ import { productAppStatePath } from "../../product-state-paths.js"; // Search backends: DuckDuckGo's HTML endpoint is the zero-setup default // (works out of the box, no Docker); a local SearXNG instance is the // preferred/power path whenever one is configured, with DuckDuckGo as the -// fallback when SearXNG is configured but not answering. An explicit +// fallback when SearXNG is configured but not answering. You.com provides +// enhanced web search with an optional API key. An explicit // EXXETA_SEARCH_PROVIDER=disabled turns web search off entirely. -type SearchProvider = "duckduckgo" | "searxng" | "disabled"; +type SearchProvider = "duckduckgo" | "searxng" | "youcom" | "disabled"; // Setup command shown in user-facing messages, shell-appropriate per platform // (the bash entry point does not run from PowerShell/cmd). @@ -54,6 +55,7 @@ function sharedConfig(): SharedSearchConfig { function getProvider(): SearchProvider { const raw = String(process.env.EXXETA_SEARCH_PROVIDER || sharedConfig().provider || "").trim().toLowerCase(); if (raw === "searxng") return "searxng"; + if (raw === "youcom") return "youcom"; if (raw === "disabled") return "disabled"; return "duckduckgo"; } @@ -153,6 +155,69 @@ async function searchSearxng(query: string, limit: number): Promise { + const apiKey = process.env.YOU_API_KEY || process.env.YDC_API_KEY; + + const url = new URL("https://api.you.com/web_search"); + url.searchParams.set("query", query); + url.searchParams.set("count", String(limit)); + + const headers: Record = { + "accept": "application/json", + "user-agent": "exxperts-web-search/1.0", + }; + + if (apiKey) { + headers.authorization = `Bearer ${apiKey}`; + } + + let res: Response; + try { + res = await fetch(url, { + headers, + signal: AbortSignal.timeout(15_000) + }); + } catch (e) { + throw new Error(`You.com search is not reachable. ${(e as Error).message}`); + } + + if (!res.ok) { + if (res.status === 401) { + const msg = apiKey + ? "You.com API key is invalid. Check your YOU_API_KEY or YDC_API_KEY environment variable." + : "You.com search requires an API key. Set YOU_API_KEY or YDC_API_KEY environment variable. Get your key at https://you.com/platform/api-keys"; + throw new Error(msg); + } + if (res.status === 429) { + throw new Error("You.com rate limit exceeded. Please wait before trying again or check your API key quota."); + } + const body = await res.text().catch(() => ""); + throw new Error(`You.com search failed (${res.status} ${res.statusText}). ${body}`.trim()); + } + + const data = await res.json() as YouSearchResponse; + const results = data.results || data.hits || []; + + return results.slice(0, limit).map((r) => ({ + title: r.title || "Untitled", + url: r.url || "", + snippet: r.description || "", + })); +} + // --- DuckDuckGo HTML endpoint ------------------------------------------------ function decodeEntities(s: string): string { @@ -260,7 +325,7 @@ export default function (pi: ExtensionAPI) { name: "web_search", label: "Web search", description: - "Search the public web. Works out of the box (DuckDuckGo); a local SearXNG instance is used instead when one is configured (optional, for heavier use).", + "Search the public web. Works out of the box (DuckDuckGo); a local SearXNG instance is used when configured (optional, for heavier use); You.com provides enhanced search with an API key (optional, set EXXETA_SEARCH_PROVIDER=youcom).", promptSnippet: "Use `web_search` when the user asks for latest/current web information, market/client research, trends, or sourced briefings. Cite URLs in the final answer.", parameters: Type.Object({ @@ -284,6 +349,23 @@ export default function (pi: ExtensionAPI) { }; } + // You.com when configured (returns immediately, no fallback needed) + if (provider === "youcom") { + try { + const results = await searchYoucom(query, maxResults); + return { + content: [{ type: "text", text: formatResults(query, results) }], + details: { configured: true, provider, query, count: results.length, results }, + }; + } catch (e) { + return { + content: [{ type: "text", text: `You.com search failed: ${(e as Error).message}` }], + details: { configured: true, provider, error: (e as Error).message }, + isError: true, + }; + } + } + // SearXNG when configured, DuckDuckGo as the fallback when it is not // answering; plain DuckDuckGo otherwise. let searxngError: string | null = null; diff --git a/runtime/packages/ai/src/models.generated.ts b/runtime/packages/ai/src/models.generated.ts index 9a9f64f..a9196b8 100644 --- a/runtime/packages/ai/src/models.generated.ts +++ b/runtime/packages/ai/src/models.generated.ts @@ -1372,7 +1372,7 @@ export const MODELS = { cacheRead: 0.022, cacheWrite: 0.275, }, - contextWindow: 272000, + contextWindow: 1050000, maxTokens: 128000, } satisfies Model<"bedrock-converse-stream">, "openai.gpt-5.6-sol": { @@ -1387,9 +1387,9 @@ export const MODELS = { input: 5.5, output: 33, cacheRead: 0.55, - cacheWrite: 6.88, + cacheWrite: 6.875, }, - contextWindow: 272000, + contextWindow: 1050000, maxTokens: 128000, } satisfies Model<"bedrock-converse-stream">, "openai.gpt-5.6-terra": { @@ -1406,7 +1406,7 @@ export const MODELS = { cacheRead: 0.22, cacheWrite: 2.75, }, - contextWindow: 272000, + contextWindow: 1050000, maxTokens: 128000, } satisfies Model<"bedrock-converse-stream">, "openai.gpt-oss-120b": { @@ -3957,7 +3957,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 262144, + maxTokens: 256000, } satisfies Model<"openai-completions">, }, "deepseek": { @@ -4895,40 +4895,6 @@ export const MODELS = { contextWindow: 131072, maxTokens: 65536, } satisfies Model<"google-generative-ai">, - "gemini-2.0-flash": { - id: "gemini-2.0-flash", - name: "Gemini 2.0 Flash", - api: "google-generative-ai", - provider: "google", - baseUrl: "https://generativelanguage.googleapis.com/v1beta", - reasoning: false, - input: ["text", "image"], - cost: { - input: 0.1, - output: 0.4, - cacheRead: 0.025, - cacheWrite: 0, - }, - contextWindow: 1048576, - maxTokens: 8192, - } satisfies Model<"google-generative-ai">, - "gemini-2.0-flash-lite": { - id: "gemini-2.0-flash-lite", - name: "Gemini 2.0 Flash-Lite", - api: "google-generative-ai", - provider: "google", - baseUrl: "https://generativelanguage.googleapis.com/v1beta", - reasoning: false, - input: ["text", "image"], - cost: { - input: 0.075, - output: 0.3, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 1048576, - maxTokens: 8192, - } satisfies Model<"google-generative-ai">, "gemini-2.5-computer-use-preview-10-2025": { id: "gemini-2.5-computer-use-preview-10-2025", name: "Gemini 2.5 Computer Use Preview 10-2025", @@ -5015,24 +4981,6 @@ export const MODELS = { contextWindow: 1048576, maxTokens: 65536, } satisfies Model<"google-generative-ai">, - "gemini-3-pro-preview": { - id: "gemini-3-pro-preview", - name: "Gemini 3 Pro Preview", - api: "google-generative-ai", - provider: "google", - baseUrl: "https://generativelanguage.googleapis.com/v1beta", - reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":"LOW","medium":null,"high":"HIGH"}, - input: ["text", "image"], - cost: { - input: 2, - output: 12, - cacheRead: 0.2, - cacheWrite: 0, - }, - contextWindow: 1048576, - maxTokens: 65536, - } satisfies Model<"google-generative-ai">, "gemini-3.1-flash-lite": { id: "gemini-3.1-flash-lite", name: "Gemini 3.1 Flash Lite", @@ -9434,6 +9382,23 @@ export const MODELS = { contextWindow: 256000, maxTokens: 256000, } satisfies Model<"openai-responses">, + "hy3-free": { + id: "hy3-free", + name: "Hy3 Free", + api: "openai-completions", + provider: "opencode", + baseUrl: "https://opencode.ai/zen/v1", + reasoning: true, + input: ["text"], + cost: { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 190000, + maxTokens: 64000, + } satisfies Model<"openai-completions">, "kimi-k2.5": { id: "kimi-k2.5", name: "Kimi K2.5", @@ -9536,23 +9501,6 @@ export const MODELS = { contextWindow: 262144, maxTokens: 32768, } satisfies Model<"openai-completions">, - "longcat-2.0-free": { - id: "longcat-2.0-free", - name: "LongCat-2.0 Free", - api: "openai-completions", - provider: "opencode", - baseUrl: "https://opencode.ai/zen/v1", - reasoning: true, - input: ["text"], - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 1000000, - maxTokens: 131072, - } satisfies Model<"openai-completions">, "mimo-v2.5-free": { id: "mimo-v2.5-free", name: "MiMo V2.5 Free", @@ -9638,9 +9586,9 @@ export const MODELS = { contextWindow: 1000000, maxTokens: 128000, } satisfies Model<"openai-completions">, - "north-mini-code-free": { - id: "north-mini-code-free", - name: "North Mini Code Free", + "nemotron-3.5-lightning-free": { + id: "nemotron-3.5-lightning-free", + name: "Nemotron 3.5 Lightning Free", api: "openai-completions", provider: "opencode", baseUrl: "https://opencode.ai/zen/v1", @@ -9652,8 +9600,8 @@ export const MODELS = { cacheRead: 0, cacheWrite: 0, }, - contextWindow: 256000, - maxTokens: 64000, + contextWindow: 262144, + maxTokens: 262144, } satisfies Model<"openai-completions">, "qwen3.5-plus": { id: "qwen3.5-plus", @@ -10724,6 +10672,23 @@ export const MODELS = { contextWindow: 262144, maxTokens: 32768, } satisfies Model<"openai-completions">, + "bytedance-seed/seed-2.0-code": { + id: "bytedance-seed/seed-2.0-code", + name: "ByteDance Seed: Seed-2.0-Code", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + reasoning: true, + input: ["text", "image"], + cost: { + input: 0.5, + output: 3, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 262144, + maxTokens: 131072, + } satisfies Model<"openai-completions">, "bytedance-seed/seed-2.0-lite": { id: "bytedance-seed/seed-2.0-lite", name: "ByteDance Seed: Seed-2.0-Lite", @@ -10904,8 +10869,8 @@ export const MODELS = { input: ["text"], cost: { input: 0.27, - output: 1, - cacheRead: 0.135, + output: 0.95, + cacheRead: 0.13, cacheWrite: 0, }, contextWindow: 163840, @@ -10975,9 +10940,9 @@ export const MODELS = { thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, input: ["text"], cost: { - input: 0.09, + input: 0.08, output: 0.18, - cacheRead: 0.018, + cacheRead: 0.016, cacheWrite: 0, }, contextWindow: 1048576, @@ -10994,13 +10959,13 @@ export const MODELS = { thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, input: ["text"], cost: { - input: 0.435, - output: 0.87, - cacheRead: 0.003625, + input: 0.63168, + output: 1.26336, + cacheRead: 0.053298, cacheWrite: 0, }, contextWindow: 1048576, - maxTokens: 384000, + maxTokens: 393216, } satisfies Model<"openai-completions">, "google/gemini-2.5-flash": { id: "google/gemini-2.5-flash", @@ -11436,13 +11401,13 @@ export const MODELS = { reasoning: true, input: ["text", "image"], cost: { - input: 0.07, - output: 0.33999999999999997, - cacheRead: 0, + input: 0.12, + output: 0.39999999999999997, + cacheRead: 0.049999999999999996, cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 16384, + maxTokens: 262144, } satisfies Model<"openai-completions">, "google/gemma-4-26b-a4b-it:free": { id: "google/gemma-4-26b-a4b-it:free", @@ -11665,6 +11630,23 @@ export const MODELS = { contextWindow: 256000, maxTokens: 80000, } satisfies Model<"openai-completions">, + "liquid/lfm-2.5-2.6b:free": { + id: "liquid/lfm-2.5-2.6b:free", + name: "LiquidAI: LFM2.5-2.6B (free)", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + reasoning: true, + input: ["text"], + cost: { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 128000, + maxTokens: 32768, + } satisfies Model<"openai-completions">, "meituan/longcat-2.0": { id: "meituan/longcat-2.0", name: "Meituan: LongCat 2.0", @@ -11743,12 +11725,12 @@ export const MODELS = { input: ["text", "image"], cost: { input: 0.19999999999999998, - output: 0.7999999999999999, + output: 0.696, cacheRead: 0, cacheWrite: 0, }, contextWindow: 1048576, - maxTokens: 16384, + maxTokens: 4096, } satisfies Model<"openai-completions">, "meta-llama/llama-4-scout": { id: "meta-llama/llama-4-scout", @@ -11767,6 +11749,23 @@ export const MODELS = { contextWindow: 1310720, maxTokens: 16384, } satisfies Model<"openai-completions">, + "meta/muse-glimmer-30b": { + id: "meta/muse-glimmer-30b", + name: "Meta: Muse Glimmer 30B", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + reasoning: true, + input: ["text", "image"], + cost: { + input: 0.35, + output: 1.5, + cacheRead: 0.04, + cacheWrite: 0, + }, + contextWindow: 131072, + maxTokens: 4096, + } satisfies Model<"openai-completions">, "meta/muse-spark-1.1": { id: "meta/muse-spark-1.1", name: "Meta: Muse Spark 1.1", @@ -12269,9 +12268,9 @@ export const MODELS = { reasoning: true, input: ["text", "image"], cost: { - input: 0.5795, - output: 2.44, - cacheRead: 0.0976, + input: 0.95, + output: 4, + cacheRead: 0.16, cacheWrite: 0, }, contextWindow: 262144, @@ -12373,11 +12372,11 @@ export const MODELS = { cost: { input: 0.049999999999999996, output: 0.19999999999999998, - cacheRead: 0.03, + cacheRead: 0.024999999999999998, cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 262144, + maxTokens: 228000, } satisfies Model<"openai-completions">, "nvidia/nemotron-3-nano-30b-a3b:free": { id: "nvidia/nemotron-3-nano-30b-a3b:free", @@ -12422,13 +12421,13 @@ export const MODELS = { reasoning: true, input: ["text"], cost: { - input: 0.3, - output: 0.8999999999999999, + input: 0.08499999999999999, + output: 0.39999999999999997, cacheRead: 0, cacheWrite: 0, }, contextWindow: 1000000, - maxTokens: 4096, + maxTokens: 16384, } satisfies Model<"openai-completions">, "nvidia/nemotron-3-super-120b-a12b:free": { id: "nvidia/nemotron-3-super-120b-a12b:free", @@ -12498,6 +12497,23 @@ export const MODELS = { contextWindow: 1000000, maxTokens: 65536, } satisfies Model<"openai-completions">, + "nvidia/nemotron-3.5-lightning:free": { + id: "nvidia/nemotron-3.5-lightning:free", + name: "NVIDIA: Nemotron 3.5 Lightning (free)", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + reasoning: true, + input: ["text"], + cost: { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 1000000, + maxTokens: 65536, + } satisfies Model<"openai-completions">, "nvidia/nemotron-nano-12b-v2-vl:free": { id: "nvidia/nemotron-nano-12b-v2-vl:free", name: "NVIDIA: Nemotron Nano 12B 2 VL (free)", @@ -13161,7 +13177,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 128000, - maxTokens: 16384, + maxTokens: 32000, } satisfies Model<"openai-completions">, "openai/gpt-5.2-codex": { id: "openai/gpt-5.2-codex", @@ -13235,24 +13251,6 @@ export const MODELS = { contextWindow: 400000, maxTokens: 128000, } satisfies Model<"openai-completions">, - "openai/gpt-5.3-chat": { - id: "openai/gpt-5.3-chat", - name: "OpenAI: GPT-5.3 Chat", - api: "openai-completions", - provider: "openrouter", - baseUrl: "https://openrouter.ai/api/v1", - reasoning: false, - thinkingLevelMap: {"xhigh":"xhigh"}, - input: ["text", "image"], - cost: { - input: 1.75, - output: 14, - cacheRead: 0.175, - cacheWrite: 0, - }, - contextWindow: 128000, - maxTokens: 16384, - } satisfies Model<"openai-completions">, "openai/gpt-5.3-codex": { id: "openai/gpt-5.3-codex", name: "OpenAI: GPT-5.3-Codex", @@ -13768,9 +13766,9 @@ export const MODELS = { reasoning: true, input: ["text"], cost: { - input: 0.037, + input: 0.03, output: 0.16999999999999998, - cacheRead: 0, + cacheRead: 0.03, cacheWrite: 0, }, contextWindow: 131072, @@ -14278,13 +14276,13 @@ export const MODELS = { reasoning: true, input: ["text"], cost: { - input: 0.22749999999999998, - output: 0.9099999999999999, + input: 0.12, + output: 0.24, cacheRead: 0, cacheWrite: 0, }, contextWindow: 131072, - maxTokens: 8192, + maxTokens: 16384, } satisfies Model<"openai-completions">, "qwen/qwen3-235b-a22b": { id: "qwen/qwen3-235b-a22b", @@ -14449,12 +14447,12 @@ export const MODELS = { input: ["text"], cost: { input: 0.07, - output: 0.27, + output: 0.28, cacheRead: 0, cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 32768, + maxTokens: 262144, } satisfies Model<"openai-completions">, "qwen/qwen3-coder-flash": { id: "qwen/qwen3-coder-flash", @@ -14584,9 +14582,9 @@ export const MODELS = { reasoning: false, input: ["text", "image"], cost: { - input: 0.21, - output: 1.9, - cacheRead: 0.09999999999999999, + input: 0.26, + output: 1.04, + cacheRead: 0, cacheWrite: 0, }, contextWindow: 262144, @@ -14754,13 +14752,13 @@ export const MODELS = { reasoning: true, input: ["text", "image"], cost: { - input: 0.39, - output: 2.34, - cacheRead: 0, + input: 0.5, + output: 3.5999999999999996, + cacheRead: 0.3, cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 65536, + maxTokens: 262144, } satisfies Model<"openai-completions">, "qwen/qwen3.5-9b": { id: "qwen/qwen3.5-9b", @@ -15034,6 +15032,23 @@ export const MODELS = { contextWindow: 1000000, maxTokens: 128000, } satisfies Model<"openai-completions">, + "sakana/sakana-namazu": { + id: "sakana/sakana-namazu", + name: "Sakana: Sakana Namazu", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + reasoning: true, + input: ["text", "image"], + cost: { + input: 0.95, + output: 4, + cacheRead: 0.15, + cacheWrite: 0, + }, + contextWindow: 262144, + maxTokens: 65536, + } satisfies Model<"openai-completions">, "sao10k/l3.1-euryale-70b": { id: "sao10k/l3.1-euryale-70b", name: "Sao10K: Llama 3.1 Euryale 70B v2.2", @@ -15204,6 +15219,23 @@ export const MODELS = { contextWindow: 131072, maxTokens: 131072, } satisfies Model<"openai-completions">, + "upstage/solar-pro4": { + id: "upstage/solar-pro4", + name: "Upstage: Solar Pro 4", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + reasoning: true, + input: ["text"], + cost: { + input: 0.03, + output: 0.12, + cacheRead: 0.006, + cacheWrite: 0, + }, + contextWindow: 524288, + maxTokens: 131072, + } satisfies Model<"openai-completions">, "x-ai/grok-4.20": { id: "x-ai/grok-4.20", name: "SpaceXAI: Grok 4.20", @@ -15366,9 +15398,9 @@ export const MODELS = { reasoning: true, input: ["text"], cost: { - input: 0.5, - output: 2, - cacheRead: 0.09999999999999999, + input: 0.55, + output: 2.2, + cacheRead: 0.11, cacheWrite: 0, }, contextWindow: 204800, @@ -15468,9 +15500,9 @@ export const MODELS = { reasoning: true, input: ["text"], cost: { - input: 0.952, - output: 2.992, - cacheRead: 0.17679999999999998, + input: 1.4, + output: 4.4, + cacheRead: 0.26, cacheWrite: 0, }, contextWindow: 204800, @@ -15485,13 +15517,13 @@ export const MODELS = { reasoning: true, input: ["text"], cost: { - input: 0.07, - output: 0.22, - cacheRead: 0.013000000000000001, + input: 0.5, + output: 3.15, + cacheRead: 0.09999999999999999, cacheWrite: 0, }, contextWindow: 1048576, - maxTokens: 128000, + maxTokens: 131072, } satisfies Model<"openai-completions">, "z-ai/glm-5.2:batch": { id: "z-ai/glm-5.2:batch", @@ -16054,7 +16086,7 @@ export const MODELS = { cacheRead: 0.26, cacheWrite: 0, }, - contextWindow: 262144, + contextWindow: 512000, maxTokens: 164000, } satisfies Model<"openai-completions">, }, @@ -16741,6 +16773,23 @@ export const MODELS = { contextWindow: 1000000, maxTokens: 128000, } satisfies Model<"anthropic-messages">, + "anthropic/claude-opus-5-fast": { + id: "anthropic/claude-opus-5-fast", + name: "Claude Opus 5 (Fast)", + api: "anthropic-messages", + provider: "vercel-ai-gateway", + baseUrl: "https://ai-gateway.vercel.sh", + reasoning: true, + input: ["text", "image"], + cost: { + input: 10, + output: 50, + cacheRead: 1, + cacheWrite: 12.5, + }, + contextWindow: 1000000, + maxTokens: 128000, + } satisfies Model<"anthropic-messages">, "anthropic/claude-sonnet-4": { id: "anthropic/claude-sonnet-4", name: "Claude Sonnet 4", @@ -17202,7 +17251,7 @@ export const MODELS = { } satisfies Model<"anthropic-messages">, "google/gemma-4-26b-a4b-it": { id: "google/gemma-4-26b-a4b-it", - name: "Gemma 4 26B A4B IT", + name: "Google Gemma 4 26B A4B", api: "anthropic-messages", provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", @@ -17472,6 +17521,23 @@ export const MODELS = { contextWindow: 128000, maxTokens: 8192, } satisfies Model<"anthropic-messages">, + "meta/muse-glimmer-30b": { + id: "meta/muse-glimmer-30b", + name: "Muse Glimmer 30B", + api: "anthropic-messages", + provider: "vercel-ai-gateway", + baseUrl: "https://ai-gateway.vercel.sh", + reasoning: true, + input: ["text", "image"], + cost: { + input: 0.35, + output: 1.5, + cacheRead: 0.04, + cacheWrite: 0, + }, + contextWindow: 131072, + maxTokens: 131072, + } satisfies Model<"anthropic-messages">, "meta/muse-spark-1.1": { id: "meta/muse-spark-1.1", name: "Muse Spark 1.1", @@ -18444,24 +18510,6 @@ export const MODELS = { contextWindow: 400000, maxTokens: 128000, } satisfies Model<"anthropic-messages">, - "openai/gpt-5.3-chat": { - id: "openai/gpt-5.3-chat", - name: "GPT-5.3 Chat", - api: "anthropic-messages", - provider: "vercel-ai-gateway", - baseUrl: "https://ai-gateway.vercel.sh", - reasoning: false, - thinkingLevelMap: {"xhigh":"xhigh"}, - input: ["text", "image"], - cost: { - input: 1.75, - output: 14, - cacheRead: 0.175, - cacheWrite: 0, - }, - contextWindow: 128000, - maxTokens: 16384, - } satisfies Model<"anthropic-messages">, "openai/gpt-5.3-codex": { id: "openai/gpt-5.3-codex", name: "GPT 5.3 Codex", @@ -18843,6 +18891,23 @@ export const MODELS = { contextWindow: 1000000, maxTokens: 1000000, } satisfies Model<"anthropic-messages">, + "sakana/namazu": { + id: "sakana/namazu", + name: "Sakana Namazu", + api: "anthropic-messages", + provider: "vercel-ai-gateway", + baseUrl: "https://ai-gateway.vercel.sh", + reasoning: true, + input: ["text", "image"], + cost: { + input: 0.95, + output: 4, + cacheRead: 0.15, + cacheWrite: 0, + }, + contextWindow: 256000, + maxTokens: 256000, + } satisfies Model<"anthropic-messages">, "stepfun/step-3.5-flash": { id: "stepfun/step-3.5-flash", name: "StepFun 3.5 Flash",