From 100c048539199a9eb1dcde0902573f8f0133afd8 Mon Sep 17 00:00:00 2001 From: "jatin.go" Date: Wed, 13 May 2026 13:35:17 +0530 Subject: [PATCH 1/5] feat(cli): add FastRouter as a built-in provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FastRouter (https://fastrouter.ai) is an OpenRouter-compatible AI gateway. The integration mirrors the existing `apertis` provider — a fully formed provider entry is injected into `ModelsDev.get()` from a public catalog (`https://go.fastrouter.ai/api/v1/models`), with the model fetcher living in `packages/opencode/src/kilocode/provider/fastrouter.ts` and the runtime loader registered through `kiloCustomLoaders`. No new SDK dependency: FastRouter reuses `@openrouter/ai-sdk-provider` since the wire format is identical. Highlights: - No `models.dev` involvement — `delete providers["fastrouter"]` runs unconditionally before injection so any stray upstream entry is always overwritten by the live FastRouter API response. - The `/models` endpoint is public, so the FastRouter provider and its catalog appear in the picker even before the user adds an API key. - API key resolution: `FASTROUTER_API_KEY` env var, `kilo auth fastrouter`, or `provider.fastrouter.options.apiKey` in `kilo.json` (matches OpenRouter). - TUI surfacing: `fastrouter` added to the Kilo `PROVIDER_PRIORITY` map so it shows under "Popular" alongside `openrouter`. - OpenRouter-compatible code paths in `transform.ts` extended to cover `model.providerID === "fastrouter"` (reasoning effort, prompt cache key). - Docs: new `ai-providers/fastrouter.md` page plus nav and gateways-index entries. Diff is intentionally minimal: 50 added / 2 changed lines across 5 shared files (each guarded by `kilocode_change` markers) plus 2 new files in kilocode-only directories that need no markers. Co-authored-by: Cursor --- .gitignore | 3 + packages/kilo-docs/lib/nav/ai-providers.ts | 1 + .../pages/ai-providers/fastrouter.md | 118 ++++++++++++++++++ .../kilo-docs/pages/ai-providers/index.md | 1 + .../cli/cmd/tui/component/dialog-provider.tsx | 2 + .../src/kilocode/provider/fastrouter.ts | 83 ++++++++++++ .../src/kilocode/provider/provider.ts | 20 +++ packages/opencode/src/provider/model-cache.ts | 5 + packages/opencode/src/provider/models.ts | 18 +++ packages/opencode/src/provider/transform.ts | 5 +- 10 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 packages/kilo-docs/pages/ai-providers/fastrouter.md create mode 100644 packages/opencode/src/kilocode/provider/fastrouter.ts diff --git a/.gitignore b/.gitignore index 91bf7230c02..9c058a3149d 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,6 @@ tsconfig.tsbuildinfo # Test Artifacts packages/app/.artifacts/ packages/opencode/.artifacts/ + +# Editor / agent artifacts +.cursor/ diff --git a/packages/kilo-docs/lib/nav/ai-providers.ts b/packages/kilo-docs/lib/nav/ai-providers.ts index 408598f0f52..69ae6526732 100644 --- a/packages/kilo-docs/lib/nav/ai-providers.ts +++ b/packages/kilo-docs/lib/nav/ai-providers.ts @@ -28,6 +28,7 @@ export const AiProvidersNav: NavSection[] = [ title: "AI Gateways", links: [ { href: "/ai-providers/openrouter", children: "OpenRouter" }, + { href: "/ai-providers/fastrouter", children: "FastRouter" }, { href: "/ai-providers/glama", children: "Glama" }, { href: "/ai-providers/requesty", children: "Requesty" }, { href: "/ai-providers/unbound", children: "Unbound" }, diff --git a/packages/kilo-docs/pages/ai-providers/fastrouter.md b/packages/kilo-docs/pages/ai-providers/fastrouter.md new file mode 100644 index 00000000000..3e103047c59 --- /dev/null +++ b/packages/kilo-docs/pages/ai-providers/fastrouter.md @@ -0,0 +1,118 @@ +--- +title: "Using FastRouter with Kilo Code | Unified AI API" +description: "Access models from Anthropic, OpenAI, Google, and more through FastRouter — an OpenRouter-compatible AI gateway — by configuring it in Kilo Code. Setup guide for VS Code and the CLI." +sidebar_label: FastRouter +--- + +# Using FastRouter With Kilo Code + +[FastRouter](https://fastrouter.ai) is an OpenRouter-compatible AI gateway that routes requests to many model providers (Anthropic, OpenAI, Google, Mistral, and more) through a single API. Because it speaks the same wire format as OpenRouter, Kilo Code talks to it through the same Vercel AI SDK and supports streaming, tool calling, multimodal inputs, and reasoning out of the box. + +**Website:** [https://fastrouter.ai](https://fastrouter.ai) + +## Getting an API Key + +1. **Sign up:** Go to the [FastRouter dashboard](https://go.fastrouter.ai) and create an account. +2. **Create a key:** Generate an API key from the keys page. +3. **Copy the key:** You will paste it into Kilo Code below. + +The model catalog at [`https://go.fastrouter.ai/api/v1/models`](https://go.fastrouter.ai/api/v1/models) is public — Kilo Code fetches it without an API key, so the FastRouter provider and its models always show up in the picker. The key is only used for chat completions. + +## Configuration in Kilo Code + +{% tabs %} +{% tab label="VSCode" %} + +Open **Settings** (gear icon), go to the **Providers** tab, add FastRouter, and enter your API key. + +The extension stores this in your `kilo.json` config file. You can also edit the config file directly — see the **CLI** tab for the file format. + +{% /tab %} +{% tab label="CLI" %} + +Set the API key as an environment variable or configure it in your `kilo.json` config file: + +**Environment variable:** + +```bash +export FASTROUTER_API_KEY="your-api-key" +``` + +**Config file** (`~/.config/kilo/kilo.json` or `./kilo.json`): + +```jsonc +{ + "provider": { + "fastrouter": { + "env": ["FASTROUTER_API_KEY"], + }, + }, +} +``` + +Then set your default model: + +```jsonc +{ + "model": "fastrouter/anthropic/claude-sonnet-4-5", +} +``` + +You can also store the key via `kilo auth fastrouter` so it lives in the shared auth store rather than your shell environment. + +{% /tab %} +{% /tabs %} + +## Supported Capabilities + +Because FastRouter mirrors the OpenRouter API surface, all of the following work without any FastRouter-specific configuration: + +- **Streaming responses** — token-by-token output for long generations. +- **Tool calling** — both single and parallel tool calls. Kilo Code's built-in tools and any MCP tools you connect work directly. +- **Multimodal inputs** — text, image, audio, video, and PDF where the underlying model supports them. The FastRouter `/models` catalog reports the supported modalities per model and Kilo Code reflects that in the picker. +- **Reasoning effort** — for reasoning-capable models, Kilo Code passes `reasoning: { effort: "minimal" | "low" | "medium" | "high" }` through to FastRouter the same way it does for OpenRouter. + +## Provider-Routing Options + +FastRouter accepts the same `provider` routing fields as OpenRouter (sort, order, only, data_collection, zdr). To pass them through, set them on the model's `options` in `kilo.json` — anything under `options` is forwarded verbatim: + +```jsonc +{ + "provider": { + "fastrouter": { + "models": { + "anthropic/claude-sonnet-4-5": { + "options": { + "provider": { + "sort": "price", + "order": ["Anthropic", "Google"], + "only": ["Anthropic"] + } + } + } + } + } + } +} +``` + +Refer to the FastRouter docs at [https://docs.fastrouter.ai](https://docs.fastrouter.ai) for the full list of accepted fields — Kilo Code does not validate them, so any future option works the moment FastRouter ships it. + +## Disabling FastRouter + +If you do not want FastRouter to load at all, add it to `disabled_providers` in `kilo.json`: + +```jsonc +{ + "$schema": "https://app.kilo.ai/config.json", + "disabled_providers": ["fastrouter"] +} +``` + +This skips both the model fetch and the provider injection. + +## Tips and Notes + +- **Model IDs** mirror the underlying provider — for example `anthropic/claude-sonnet-4-5`, `openai/gpt-5`, `google/gemini-2.0-pro`. Use `kilo` model picker (or `Ctrl+X m` in the TUI) to browse the live catalog. +- **Pricing** is reported by the `/models` endpoint and shown by Kilo Code's picker; FastRouter charges the underlying model's price. +- **Cache control** uses the OpenRouter-compatible `prompt_cache_key` automatically; you do not need to configure anything. diff --git a/packages/kilo-docs/pages/ai-providers/index.md b/packages/kilo-docs/pages/ai-providers/index.md index a7c8c05fee3..7af8a6e419c 100644 --- a/packages/kilo-docs/pages/ai-providers/index.md +++ b/packages/kilo-docs/pages/ai-providers/index.md @@ -42,6 +42,7 @@ Run models on your own hardware for privacy and offline use: Route requests through unified APIs with additional features: - **[OpenRouter](/docs/ai-providers/openrouter)** - Access multiple providers through one API +- **[FastRouter](/docs/ai-providers/fastrouter)** - OpenRouter-compatible router with low-latency, multimodal, and tool-calling support - **[Glama](/docs/ai-providers/glama)** - Enterprise AI gateway - **[Requesty](/docs/ai-providers/requesty)** - Smart routing and fallbacks - **[Cloudflare AI Gateway](/docs/ai-providers/cloudflare)** - Route providers through your Cloudflare account diff --git a/packages/opencode/src/kilocode/cli/cmd/tui/component/dialog-provider.tsx b/packages/opencode/src/kilocode/cli/cmd/tui/component/dialog-provider.tsx index 1b38f8b0d43..1ddf0717e4a 100644 --- a/packages/opencode/src/kilocode/cli/cmd/tui/component/dialog-provider.tsx +++ b/packages/opencode/src/kilocode/cli/cmd/tui/component/dialog-provider.tsx @@ -51,6 +51,8 @@ export const PROVIDER_PRIORITY: Record = { "github-copilot": 1, openai: 2, google: 3, + openrouter: 4, + fastrouter: 5, } // --------------------------------------------------------------------------- diff --git a/packages/opencode/src/kilocode/provider/fastrouter.ts b/packages/opencode/src/kilocode/provider/fastrouter.ts new file mode 100644 index 00000000000..c11ef4e6a3f --- /dev/null +++ b/packages/opencode/src/kilocode/provider/fastrouter.ts @@ -0,0 +1,83 @@ +// kilocode_change - new file +// +// FastRouter integration helpers. +// +// FastRouter (https://fastrouter.ai) is an OpenRouter-compatible AI gateway. +// We talk to it directly with the user's `FASTROUTER_API_KEY` — no Kilo +// gateway routing — and reuse the OpenRouter Vercel AI SDK since the wire +// format is identical. + +export const FASTROUTER_API = "https://go.fastrouter.ai/api/v1" +export const FASTROUTER_MODELS_URL = `${FASTROUTER_API}/models` +export const FASTROUTER_ENV = "FASTROUTER_API_KEY" + +const FETCH_TIMEOUT_MS = 10_000 + +type Pricing = { prompt?: string; completion?: string } +type Architecture = { input_modalities?: string[]; output_modalities?: string[] } +type Top = { + id: string + name?: string + description?: string + context_length?: number | null + max_completion_tokens?: number | null + pricing?: Pricing + architecture?: Architecture + supported_parameters?: string[] + created?: number +} + +type Models = { data?: Top[] } + +export async function fetchFastRouterModels(): Promise> { + // The /models endpoint is public — no Authorization header needed. We use + // `globalThis.fetch` explicitly to avoid accidentally hitting any local + // namespaced fetch helpers from the calling module. + const res = await globalThis.fetch(FASTROUTER_MODELS_URL, { + signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), + }) + if (!res.ok) return {} + + const json = (await res.json()) as Models + const out: Record = {} + + for (const m of json.data ?? []) { + if (!m.id) continue + const inputs = m.architecture?.input_modalities ?? ["text"] + const outputs = m.architecture?.output_modalities ?? ["text"] + const params = m.supported_parameters ?? [] + + out[m.id] = { + id: m.id, + name: m.name || m.id, + family: m.id.split("/")[0] || "", + // Use ISO date if `created` is a unix timestamp; else empty string. + release_date: m.created ? new Date(m.created * 1000).toISOString().slice(0, 10) : "", + attachment: inputs.includes("image"), + reasoning: params.includes("reasoning") || params.includes("include_reasoning"), + temperature: params.includes("temperature"), + tool_call: params.includes("tools") || params.includes("tool_choice"), + // `||` (not `??`) — FastRouter returns 0/null/empty-string for unknown + // pricing and limits; we want our defaults to apply in those cases too. + cost: { + input: parseFloat(m.pricing?.prompt || "0"), + output: parseFloat(m.pricing?.completion || "0"), + }, + limit: { + context: m.context_length || 128_000, + output: m.max_completion_tokens || 16_384, + }, + options: {}, + modalities: { + input: inputs.filter((x): x is "text" | "audio" | "image" | "video" | "pdf" => + ["text", "audio", "image", "video", "pdf"].includes(x), + ), + output: outputs.filter((x): x is "text" | "audio" | "image" | "video" | "pdf" => + ["text", "audio", "image", "video", "pdf"].includes(x), + ), + }, + } + } + + return out +} diff --git a/packages/opencode/src/kilocode/provider/provider.ts b/packages/opencode/src/kilocode/provider/provider.ts index a7720734aef..da2337763e2 100644 --- a/packages/opencode/src/kilocode/provider/provider.ts +++ b/packages/opencode/src/kilocode/provider/provider.ts @@ -12,6 +12,7 @@ import { ProviderID, ModelID } from "@/provider/schema" import { Effect, Schema } from "effect" import type { LanguageModelV3 } from "@ai-sdk/provider" import { mapValues, omit, pickBy } from "remeda" +import { FASTROUTER_API, FASTROUTER_ENV } from "./fastrouter" /** Default timeout (ms) for provider HTTP requests (connection phase). */ export const REQUEST_TIMEOUT_MS = 120_000 // 2 minutes @@ -152,6 +153,25 @@ export function kiloCustomLoaders(dep: CustomDep): Record autoload: false, options: { headers: DEFAULT_HEADERS }, }), + + fastrouter: Effect.fnUntraced(function* (input: any) { + const env = yield* dep.env() + const cfg = yield* dep.config() + const auth = yield* dep.auth(input.id) + const cfgKey = cfg?.provider?.["fastrouter"]?.options?.apiKey + const authKey = auth?.type === "api" ? auth.key : undefined + const envKey = env[FASTROUTER_ENV] + const hasKey = Boolean(cfgKey || authKey || envKey) + const hasModels = Object.keys(input.models ?? {}).length > 0 + + return { + autoload: hasKey && hasModels, + options: { + baseURL: FASTROUTER_API, + headers: { ...DEFAULT_HEADERS }, + }, + } + }), } } diff --git a/packages/opencode/src/provider/model-cache.ts b/packages/opencode/src/provider/model-cache.ts index 37cb47d53ef..bca682b4f83 100644 --- a/packages/opencode/src/provider/model-cache.ts +++ b/packages/opencode/src/provider/model-cache.ts @@ -3,6 +3,7 @@ import { fetchKiloModels, type KiloModelsResult } from "@kilocode/kilo-gateway" import { Config } from "../config/config" import { Auth } from "../auth" import * as Log from "@opencode-ai/core/util/log" +import { fetchFastRouterModels } from "../kilocode/provider/fastrouter" export namespace ModelCache { const log = Log.create({ service: "model-cache" }) @@ -189,6 +190,10 @@ export namespace ModelCache { const models = await fetchApertisModels(options) return { models } } + if (providerID === "fastrouter") { + const models = await fetchFastRouterModels() + return { models } + } // kilocode_change end // Other providers not implemented yet diff --git a/packages/opencode/src/provider/models.ts b/packages/opencode/src/provider/models.ts index 5aca1a394b8..5d2717ccc38 100644 --- a/packages/opencode/src/provider/models.ts +++ b/packages/opencode/src/provider/models.ts @@ -193,17 +193,35 @@ export const layer: Layer.Layer Config.get()) const disabled = new Set(config.disabled_providers ?? []) const enabled = config.enabled_providers ? new Set(config.enabled_providers) : undefined const kiloAllowed = (!enabled || enabled.has("kilo")) && !disabled.has("kilo") + const fastrouterAllowed = (!enabled || enabled.has("fastrouter")) && !disabled.has("fastrouter") const apt = config.provider?.apertis?.options const aptBase = apt?.baseURL ?? "https://api.apertis.ai/v1" const aptFetch = { ...(apt?.baseURL ? { baseURL: apt.baseURL } : {}), } + if (fastrouterAllowed) { + const fr = yield* Effect.promise(() => ModelCache.fetch("fastrouter").catch(() => ({}))) + providers["fastrouter"] = { + id: "fastrouter", + name: "FastRouter", + env: ["FASTROUTER_API_KEY"], + api: "https://go.fastrouter.ai/api/v1", + npm: "@openrouter/ai-sdk-provider", + models: fr, + } + if (Object.keys(fr).length === 0) { + yield* Effect.sync(() => void ModelCache.refresh("fastrouter").catch(() => {})) + } + } + if (kiloAllowed) { const opts = config.provider?.kilo?.options const auth = yield* Effect.promise(() => Auth.get("kilo")) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 35ea19b5f69..8fc506c026a 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -1025,7 +1025,7 @@ export function options(input: { result["promptCacheKey"] = input.sessionID } - if (input.model.providerID === "openrouter") { + if (input.model.providerID === "openrouter" || input.model.providerID === "fastrouter" /* kilocode_change */) { result["prompt_cache_key"] = input.sessionID } if (input.model.api.npm === "@ai-sdk/gateway") { @@ -1061,7 +1061,8 @@ export function smallOptions(model: Provider.Model) { if ( model.providerID === "openrouter" || model.providerID === "llmgateway" || - model.api.npm === "@kilocode/kilo-gateway" // kilocode_change + model.api.npm === "@kilocode/kilo-gateway" || // kilocode_change + model.providerID === "fastrouter" // kilocode_change ) { if (model.api.id.includes("google")) { return { reasoning: { enabled: false } } From 2bb40ececb4ed7faa7a5dff32178a7765385f3d2 Mon Sep 17 00:00:00 2001 From: "jatin.go" Date: Wed, 13 May 2026 17:35:30 +0530 Subject: [PATCH 2/5] fix(cli): gate FastRouter catalog fetch on key presence Addresses the kilo-code-bot warning on #10207. The previous catalog injection ran for every install regardless of whether a FastRouter API key was configured, which meant every Kilo CLI start spawned an HTTP request to go.fastrouter.ai with no user intent behind it. Now the inject + ModelCache.fetch + background refresh only fire when a key resolves from one of the three documented sources: kilo.json provider.fastrouter.options.apiKey, the auth store (kilo auth login), or the FASTROUTER_API_KEY env var. Matches how kilo and apertis gate their fetches inline in models.ts. The runtime path for users with a key is unchanged. Also addresses the bot's typing suggestion: fetchFastRouterModels now returns Record with a locally-defined shape type so future field-name drift is caught at compile time. A local type keeps us free of the models.ts -> model-cache.ts -> fastrouter.ts cycle a shared ModelsDev.Model import would create. Docs page updated to drop the "public catalog visible without a key" claim that no longer matches the runtime behavior. Co-authored-by: Cursor --- .../pages/ai-providers/fastrouter.md | 2 +- .../src/kilocode/provider/fastrouter.ts | 22 ++++++++++++-- packages/opencode/src/provider/models.ts | 30 ++++++++++++------- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/packages/kilo-docs/pages/ai-providers/fastrouter.md b/packages/kilo-docs/pages/ai-providers/fastrouter.md index 3e103047c59..e1ebeb50df9 100644 --- a/packages/kilo-docs/pages/ai-providers/fastrouter.md +++ b/packages/kilo-docs/pages/ai-providers/fastrouter.md @@ -16,7 +16,7 @@ sidebar_label: FastRouter 2. **Create a key:** Generate an API key from the keys page. 3. **Copy the key:** You will paste it into Kilo Code below. -The model catalog at [`https://go.fastrouter.ai/api/v1/models`](https://go.fastrouter.ai/api/v1/models) is public — Kilo Code fetches it without an API key, so the FastRouter provider and its models always show up in the picker. The key is only used for chat completions. +Kilo Code fetches the FastRouter model catalog only after you have added an API key (via env var, `kilo auth login`, or `kilo.json`). Once a key is set, the provider plus the full ~170-model catalog appears in the picker. ## Configuration in Kilo Code diff --git a/packages/opencode/src/kilocode/provider/fastrouter.ts b/packages/opencode/src/kilocode/provider/fastrouter.ts index c11ef4e6a3f..e73ae26fb40 100644 --- a/packages/opencode/src/kilocode/provider/fastrouter.ts +++ b/packages/opencode/src/kilocode/provider/fastrouter.ts @@ -29,7 +29,25 @@ type Top = { type Models = { data?: Top[] } -export async function fetchFastRouterModels(): Promise> { +type FastRouterModel = { + id: string + name: string + family: string + release_date: string + attachment: boolean + reasoning: boolean + temperature: boolean + tool_call: boolean + cost: { input: number; output: number } + limit: { context: number; output: number } + options: Record + modalities: { + input: Array<"text" | "audio" | "image" | "video" | "pdf"> + output: Array<"text" | "audio" | "image" | "video" | "pdf"> + } +} + +export async function fetchFastRouterModels(): Promise> { // The /models endpoint is public — no Authorization header needed. We use // `globalThis.fetch` explicitly to avoid accidentally hitting any local // namespaced fetch helpers from the calling module. @@ -39,7 +57,7 @@ export async function fetchFastRouterModels(): Promise> { if (!res.ok) return {} const json = (await res.json()) as Models - const out: Record = {} + const out: Record = {} for (const m of json.data ?? []) { if (!m.id) continue diff --git a/packages/opencode/src/provider/models.ts b/packages/opencode/src/provider/models.ts index 5d2717ccc38..40b9543e3da 100644 --- a/packages/opencode/src/provider/models.ts +++ b/packages/opencode/src/provider/models.ts @@ -208,17 +208,25 @@ export const layer: Layer.Layer ModelCache.fetch("fastrouter").catch(() => ({}))) - providers["fastrouter"] = { - id: "fastrouter", - name: "FastRouter", - env: ["FASTROUTER_API_KEY"], - api: "https://go.fastrouter.ai/api/v1", - npm: "@openrouter/ai-sdk-provider", - models: fr, - } - if (Object.keys(fr).length === 0) { - yield* Effect.sync(() => void ModelCache.refresh("fastrouter").catch(() => {})) + const cfgKey = config.provider?.["fastrouter"]?.options?.apiKey + const authEntry = yield* Effect.promise(() => Auth.get("fastrouter").catch(() => undefined)) + const authKey = authEntry?.type === "api" ? authEntry.key : undefined + const envKey = process.env["FASTROUTER_API_KEY"] + const hasKey = Boolean(cfgKey || authKey || envKey) + + if (hasKey) { + const fr = yield* Effect.promise(() => ModelCache.fetch("fastrouter").catch(() => ({}))) + providers["fastrouter"] = { + id: "fastrouter", + name: "FastRouter", + env: ["FASTROUTER_API_KEY"], + api: "https://go.fastrouter.ai/api/v1", + npm: "@openrouter/ai-sdk-provider", + models: fr, + } + if (Object.keys(fr).length === 0) { + yield* Effect.sync(() => void ModelCache.refresh("fastrouter").catch(() => {})) + } } } From 446174e61b6d214bca241bbc89148fedfa3580c2 Mon Sep 17 00:00:00 2001 From: "jatin.go" Date: Thu, 14 May 2026 17:55:13 +0530 Subject: [PATCH 3/5] docs(kilo-docs): fix dead FastRouter dashboard link The previous link pointed at https://go.fastrouter.ai/ which is the API host (only /api/v1/... routes resolve). Lychee link-check on CI flagged the root path as 404. Sign-up actually lives on the marketing site at https://fastrouter.ai/, so point the docs there. Co-authored-by: Cursor --- packages/kilo-docs/pages/ai-providers/fastrouter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kilo-docs/pages/ai-providers/fastrouter.md b/packages/kilo-docs/pages/ai-providers/fastrouter.md index e1ebeb50df9..8569d736e65 100644 --- a/packages/kilo-docs/pages/ai-providers/fastrouter.md +++ b/packages/kilo-docs/pages/ai-providers/fastrouter.md @@ -12,7 +12,7 @@ sidebar_label: FastRouter ## Getting an API Key -1. **Sign up:** Go to the [FastRouter dashboard](https://go.fastrouter.ai) and create an account. +1. **Sign up:** Go to [fastrouter.ai](https://fastrouter.ai) and create an account. 2. **Create a key:** Generate an API key from the keys page. 3. **Copy the key:** You will paste it into Kilo Code below. From 85ef6cd03989b99e6a8865e288692d1179fbabff Mon Sep 17 00:00:00 2001 From: "jatin.go" Date: Thu, 14 May 2026 18:07:32 +0530 Subject: [PATCH 4/5] chore(kilo-docs): regenerate source-links.md Adds the two FastRouter URLs (https://fastrouter.ai and https://go.fastrouter.ai/api/v1) referenced from packages/opencode/src/kilocode/provider/fastrouter.ts. Fixes the extract-source-links --check CI step. Generated by `bun run script/extract-source-links.ts`. Co-authored-by: Cursor --- packages/kilo-docs/source-links.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/kilo-docs/source-links.md b/packages/kilo-docs/source-links.md index 6172084ab0c..20c07b71e9d 100644 --- a/packages/kilo-docs/source-links.md +++ b/packages/kilo-docs/source-links.md @@ -1,7 +1,7 @@ # Source Code Links - + - @@ -40,6 +40,8 @@ - +- + - - @@ -78,6 +80,9 @@ - +- + + - - From 53fd98fbff20949e62aec482cbc6ea14a48c32b6 Mon Sep 17 00:00:00 2001 From: "jatin.go" Date: Thu, 14 May 2026 23:23:07 +0530 Subject: [PATCH 5/5] ci(kilo-docs): exclude FastRouter API base URL from lychee `https://go.fastrouter.ai/api/v1` is the FastRouter inference base URL referenced by the `FASTROUTER_API` constant in source code. lychee extracts it via source-links.md and a plain GET against the bare base returns 404 (only `/v1/models`, `/v1/chat/completions`, etc. are real paths). Mirror the existing apertis exclusion right above it. Verified locally with lychee v0.23.0 (the exact version used in CI): 0 errors across packages/kilo-docs/source-links.md and packages/kilo-docs/pages. Co-authored-by: Cursor --- packages/kilo-docs/lychee.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/kilo-docs/lychee.toml b/packages/kilo-docs/lychee.toml index 5d15d940df1..d791a4c60df 100644 --- a/packages/kilo-docs/lychee.toml +++ b/packages/kilo-docs/lychee.toml @@ -38,6 +38,7 @@ exclude = [ '^https?://vercel\.link/', # API base URL, returns 404 when fetched directly '^https?://api\.apertis\.ai/v1/?$', + '^https?://go\.fastrouter\.ai/api/v1/?$', # Redirects to authenticated Google Cloud console '^https?://console\.cloud\.google\.com', # Consistently times out in CI