diff --git a/README.md b/README.md index 02406d7de..74da0359a 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Gini is not just a chat box, CLI, messaging bot, or pile of tools. Chat is an in - [Memory](docs/memory.md): retain, recall, embeddings, reranking, review, and storage - [Skill Learning From Skills](docs/skill-learning.md): how Gini improves its own skills from task outcomes (two-tier reward, attribution, the daily review, the human gate) - [Runtime Capabilities](docs/runtime-capabilities.md): current CLI/API capability map and verification commands -- [Model Providers](docs/providers/README.md): per-provider setup guides (credentials, prerequisites, CLI/web config) for OpenAI, Anthropic, Bedrock, Azure, OpenRouter, DeepSeek, Codex, and Local +- [Model Providers](docs/providers/README.md): per-provider setup guides (credentials, prerequisites, CLI/web config) for OpenAI, Anthropic, Bedrock, Azure, OpenRouter, Requesty, DeepSeek, Codex, and Local - [Operations](docs/operations.md): install, start, stop, smoke, diagnostics, and cleanup - [Remote Access](docs/remote-access.md): tunnel modes and confirmation, plus a self-contained guide per tunnel provider — [Gini Relay](docs/remote-access/gini-relay.md), [Tailscale](docs/remote-access/tailscale.md), [ngrok](docs/remote-access/ngrok.md), [Cloudflare](docs/remote-access/cloudflare.md) — the same pages the app opens inline - [Releases](docs/releases.md): versioning, CHANGELOG conventions, and the release process @@ -45,7 +45,7 @@ Gini's **runtime is the gateway**: a single Bun process per instance owns state - Authenticated localhost gateway and a Next.js + Tailwind + shadcn/ui control plane - Persistent chat, runs, tasks, approvals, traces, audit events, jobs, memories, and skills - Approval-gated file, terminal, and code tools -- Provider support: Codex OAuth; OpenAI / Azure OpenAI / DeepSeek / OpenRouter API keys; the first-party Anthropic Claude API; Amazon Bedrock (model-agnostic Converse, AWS SigV4 — Claude, Nova, Llama, Mistral, DeepSeek); and any OpenAI-compatible local server +- Provider support: Codex OAuth; OpenAI / Azure OpenAI / DeepSeek / OpenRouter / Requesty API keys; the first-party Anthropic Claude API; Amazon Bedrock (model-agnostic Converse, AWS SigV4 — Claude, Nova, Llama, Mistral, DeepSeek); and any OpenAI-compatible local server - Local embeddings, reranking, and voice-message speech-to-text by default - Parallel instances with isolated state, ports, and logs @@ -57,7 +57,7 @@ See the [Whitepaper](docs/whitepaper.md) and [Architecture Overview](docs/archit curl -fsSL https://raw.githubusercontent.com/Lilac-Labs/gini-agent/main/scripts/install.sh | bash ``` -On macOS the installer enables autostart (per-user LaunchAgents for the runtime and webapp), waits for the webapp to come up, and opens the `/setup` page in your browser. The form offers the full provider catalog — OpenAI, Codex, Anthropic, Amazon Bedrock, Azure OpenAI, OpenRouter, DeepSeek, and Local — and prompts for whatever the one you pick needs (an API key, the AWS access key pair for Bedrock, the resource endpoint for Azure, or your existing `codex login` auth). Save it and you land on the running app. The runtime stays alive across reboots and crashes until you explicitly run `gini stop` or `gini autostart disable`. +On macOS the installer enables autostart (per-user LaunchAgents for the runtime and webapp), waits for the webapp to come up, and opens the `/setup` page in your browser. The form offers the full provider catalog — OpenAI, Codex, Anthropic, Amazon Bedrock, Azure OpenAI, OpenRouter, Requesty, DeepSeek, and Local — and prompts for whatever the one you pick needs (an API key, the AWS access key pair for Bedrock, the resource endpoint for Azure, or your existing `codex login` auth). Save it and you land on the running app. The runtime stays alive across reboots and crashes until you explicitly run `gini stop` or `gini autostart disable`. If the browser doesn't open automatically (or you want to navigate manually), run `gini status` to print the actual web URL. The installed `default` instance always lives at `:7777`; other instances get hash-derived ports, so check `gini status` rather than guessing. The installer also prints the URL right before opening the browser. @@ -114,6 +114,7 @@ Run `gini setup` for an interactive picker, or configure directly: gini provider set codex gpt-5.5 # Codex OAuth (reads ~/.codex/auth.json) gini provider set openai gpt-5.4-mini # uses $OPENAI_API_KEY gini provider set openrouter # uses $OPENROUTER_API_KEY +gini provider set requesty # uses $REQUESTY_API_KEY gini provider set local --base-url http://127.0.0.1:8000/v1 gini provider set anthropic claude-opus-4-8 # first-party Claude API, uses $ANTHROPIC_API_KEY # Amazon Bedrock: model-agnostic Converse, SigV4-signed with AWS keys you enter via the web form or `gini setup` @@ -124,11 +125,11 @@ gini provider set azure gpt-4o \ --deployment --api-version 2024-10-21 --auth-scheme api-key # uses $AZURE_OPENAI_API_KEY ``` -For step-by-step setup of each provider — getting credentials, installing any prerequisite tooling (Ollama, …), and configuring it in the CLI or web — see the per-provider guides: [OpenAI](docs/providers/openai.md), [Anthropic](docs/providers/anthropic.md), [Amazon Bedrock](docs/providers/bedrock.md), [Azure OpenAI](docs/providers/azure.md), [OpenRouter](docs/providers/openrouter.md), [DeepSeek](docs/providers/deepseek.md), [Codex](docs/providers/codex.md), and [Local](docs/providers/local.md). The [providers index](docs/providers/README.md) lists them all with their auth model at a glance. +For step-by-step setup of each provider — getting credentials, installing any prerequisite tooling (Ollama, …), and configuring it in the CLI or web — see the per-provider guides: [OpenAI](docs/providers/openai.md), [Anthropic](docs/providers/anthropic.md), [Amazon Bedrock](docs/providers/bedrock.md), [Azure OpenAI](docs/providers/azure.md), [OpenRouter](docs/providers/openrouter.md), [Requesty](docs/providers/requesty.md), [DeepSeek](docs/providers/deepseek.md), [Codex](docs/providers/codex.md), and [Local](docs/providers/local.md). The [providers index](docs/providers/README.md) lists them all with their auth model at a glance. The `local` provider works with any OpenAI-compatible server (oMLX, vLLM, LM Studio, llama.cpp). The `azure` provider targets an Azure OpenAI resource: set `--base-url` to `https://.openai.azure.com` and pick a deployment; `--api-version` defaults to a GA value and `--auth-scheme` defaults to `api-key` (a resource key), with `bearer` available for an Entra token. API keys are read from environment variables, and Codex OAuth is read from `~/.codex/auth.json` (or `CODEX_AUTH_JSON`) — nothing is written to Gini config. Run `gini --help` for the full flag set, or see [provider-extra-body.md](docs/adr/provider-extra-body.md) for the `--extra-body` contract and [Azure OpenAI As A First-Class Provider](docs/adr/azure-provider.md) for the Azure routing contract. When a credential fails mid-chat, see [Codex re-authentication](docs/providers/codex.md#re-authentication) and [Provider Re-Authentication Guidance](docs/adr/provider-reauth-guidance.md). -`gini setup`'s interactive picker covers every provider — OpenAI, Codex, Anthropic, Amazon Bedrock, Azure OpenAI, OpenRouter, DeepSeek, and Local — prompting for whatever each one needs (an API key, the AWS access key + secret for Bedrock, the resource endpoint and deployment for Azure, the base URL for Local). `gini provider set …` (above) and the web **Settings → Add provider** form remain available for scripted or non-interactive configuration. +`gini setup`'s interactive picker covers every provider — OpenAI, Codex, Anthropic, Amazon Bedrock, Azure OpenAI, OpenRouter, Requesty, DeepSeek, and Local — prompting for whatever each one needs (an API key, the AWS access key + secret for Bedrock, the resource endpoint and deployment for Azure, the base URL for Local). `gini provider set …` (above) and the web **Settings → Add provider** form remain available for scripted or non-interactive configuration. ## Parallel Instances diff --git a/docs/providers/README.md b/docs/providers/README.md index 7ec917201..317f5050a 100644 --- a/docs/providers/README.md +++ b/docs/providers/README.md @@ -11,6 +11,7 @@ provider in Gini (both the CLI and the web Add Provider form). | Amazon Bedrock | AWS SigV4 | AWS access key + secret you enter (stored in `~/.gini/secrets.env`) | [bedrock.md](bedrock.md) | | Azure OpenAI | API key / Entra | `AZURE_OPENAI_API_KEY` | [azure.md](azure.md) | | OpenRouter | API key | `OPENROUTER_API_KEY` | [openrouter.md](openrouter.md) | +| Requesty | API key | `REQUESTY_API_KEY` | [requesty.md](requesty.md) | | DeepSeek | API key | `DEEPSEEK_API_KEY` | [deepseek.md](deepseek.md) | | Codex (OpenAI OAuth) | OAuth / CLI | `~/.codex/auth.json` (no key) | [codex.md](codex.md) | | Local (OpenAI-compatible) | none / optional key | `GINI_LOCAL_API_KEY` (optional) | [local.md](local.md) | diff --git a/docs/providers/requesty.md b/docs/providers/requesty.md new file mode 100644 index 000000000..f6467f6d7 --- /dev/null +++ b/docs/providers/requesty.md @@ -0,0 +1,50 @@ +# Requesty + +Requesty is an OpenAI-compatible API-key provider that routes a single key to +models from many vendors. Gini talks to `https://router.requesty.ai/v1` and +authenticates with a Bearer key. + +## Step 1 — Get an API key + +1. Sign in at [requesty.ai](https://requesty.ai/). +2. Create a key on the [API keys page](https://app.requesty.ai/api-keys) and copy it. +3. Add credit (Requesty is pay-as-you-go and bills per model). See the + [Requesty docs](https://docs.requesty.ai/) for the model catalog. + +See the [Requesty docs](https://docs.requesty.ai/) for the full API reference. + +## Step 2 — Set the key + +Gini reads the key from the `REQUESTY_API_KEY` environment variable. Set it in +your shell or in `~/.gini/secrets.env` for persistence: + +```bash +# ~/.gini/secrets.env (created mode 0600) +REQUESTY_API_KEY=rqsty-sk-... +``` + +The web Add Provider form writes this for you. + +## Step 3 — Configure the provider in Gini + +### CLI + +```bash +gini provider set requesty openai/gpt-4o-mini +``` + +Requesty uses `provider/model` slugs (e.g. `openai/gpt-4o-mini`, +`anthropic/claude-opus-4-8`). The base URL defaults to +`https://router.requesty.ai/v1`; override it only for a proxy with `--base-url`. + +### Web + +Open **Settings → Add provider → Requesty**, paste the key, and pick or type a +model slug. + +## Re-authentication + +Requesty is an API-key provider, so a credential failure surfaces Requesty's own +message and links to **Settings → Providers** to paste a new key. Rotate keys on +the [API keys page](https://app.requesty.ai/api-keys). See ADR +[provider-reauth-guidance.md](../adr/provider-reauth-guidance.md). diff --git a/src/cli/commands/provider.ts b/src/cli/commands/provider.ts index c0a2d846e..df90f54c1 100644 --- a/src/cli/commands/provider.ts +++ b/src/cli/commands/provider.ts @@ -44,6 +44,7 @@ export async function provider(ctx: CliContext): Promise { name !== "openai" && name !== "codex" && name !== "openrouter" && + name !== "requesty" && name !== "local" && name !== "deepseek" && name !== "anthropic" && @@ -169,7 +170,7 @@ export async function provider(ctx: CliContext): Promise { config.provider = normalizeProvider({ name, - model: model ?? (name === "echo" ? "gini-echo-v0" : name === "codex" ? "gpt-5.5" : name === "openrouter" ? "openrouter/auto" : name === "local" ? "local/default" : name === "deepseek" ? "deepseek-v4-flash" : name === "anthropic" ? "claude-opus-4-8" : name === "bedrock" ? "us.anthropic.claude-opus-4-8" : name === "azure" ? "gpt-5.5" : "gpt-5.4-mini"), + model: model ?? (name === "echo" ? "gini-echo-v0" : name === "codex" ? "gpt-5.5" : name === "openrouter" ? "openrouter/auto" : name === "requesty" ? "openai/gpt-4o-mini" : name === "local" ? "local/default" : name === "deepseek" ? "deepseek-v4-flash" : name === "anthropic" ? "claude-opus-4-8" : name === "bedrock" ? "us.anthropic.claude-opus-4-8" : name === "azure" ? "gpt-5.5" : "gpt-5.4-mini"), ...(baseUrl ? { baseUrl } : {}), ...(apiKeyEnv ? { apiKeyEnv } : {}), ...(extraBody ? { extraBody } : {}), diff --git a/src/cli/commands/setup.ts b/src/cli/commands/setup.ts index e78ac1746..a83df310f 100644 --- a/src/cli/commands/setup.ts +++ b/src/cli/commands/setup.ts @@ -123,7 +123,7 @@ export interface ProviderExtraConfig { } export interface ProviderModule { - id: "openai" | "codex" | "anthropic" | "bedrock" | "azure" | "openrouter" | "deepseek" | "local"; + id: "openai" | "codex" | "anthropic" | "bedrock" | "azure" | "openrouter" | "requesty" | "deepseek" | "local"; kind: ProviderKind; label: string; description: string; @@ -231,6 +231,16 @@ const openrouterProvider: ProviderModule = apiKeyProvider({ keyHint: "sk-or-" }); +const requestyProvider: ProviderModule = apiKeyProvider({ + id: "requesty", + label: "Requesty", + description: "Multi-model router — rqsty-sk-...", + apiKeyEnv: "REQUESTY_API_KEY", + defaultModel: "openai/gpt-4o-mini", + suggestedModels: ["openai/gpt-4o-mini", "openai/gpt-4o", "anthropic/claude-opus-4-8"], + keyHint: "rqsty-sk-" +}); + const deepseekProvider: ProviderModule = apiKeyProvider({ id: "deepseek", label: "DeepSeek", @@ -460,6 +470,7 @@ const PROVIDERS: ProviderModule[] = [ bedrockProvider, azureProvider, openrouterProvider, + requestyProvider, deepseekProvider, localProvider ]; @@ -528,6 +539,7 @@ const AUTO_CONFIGURABLE: ProviderModule[] = [ openaiProvider, anthropicProvider, openrouterProvider, + requestyProvider, deepseekProvider, bedrockProvider ]; @@ -722,6 +734,7 @@ export const __testing = { bedrockProvider, azureProvider, openrouterProvider, + requestyProvider, deepseekProvider, localProvider, PROVIDERS, diff --git a/src/cli/output.ts b/src/cli/output.ts index b7c3f31e2..206fb94f3 100644 --- a/src/cli/output.ts +++ b/src/cli/output.ts @@ -112,16 +112,16 @@ Usage: bun run gini notifications list|queue|send|ack bun run gini promotions list|propose|approve|reject bun run gini snapshots list|create|restore - bun run gini provider show|catalog|set echo|openai|codex|openrouter|local|deepseek|azure [model] + bun run gini provider show|catalog|set echo|openai|codex|openrouter|requesty|local|deepseek|azure [model] [--base-url ] [--api-key-env ] [--extra-body ] [--api-version ] [--deployment ] [--auth-scheme bearer|api-key] --base-url and --api-key-env work for every OpenAI-compatible - provider (local / openai / openrouter / deepseek / azure — + provider (local / openai / openrouter / requesty / deepseek / azure — point at servers like oMLX, vLLM, LM Studio) AND for codex (override the backend URL or auth-file env var). --extra-body forwards server-specific request fields like \`chat_template_kwargs\` and applies to the chat-completions - calls of local / openai / openrouter / deepseek / azure; + calls of local / openai / openrouter / requesty / deepseek / azure; codex (/responses) and echo ignore it. --api-version, --deployment, and --auth-scheme configure the azure provider (Azure OpenAI): set --base-url to https://.openai.azure.com; diff --git a/src/embeddings.ts b/src/embeddings.ts index 83eb083b0..5356f973a 100644 --- a/src/embeddings.ts +++ b/src/embeddings.ts @@ -378,7 +378,7 @@ async function embedOpenAIBatch(config: RuntimeConfig, texts: string[]): Promise // the request and leak the chat key to that host (e.g. the Anthropic key to // api.anthropic.com/embeddings). Those fall back to the canonical OpenAI // endpoint + OPENAI_API_KEY instead. -const OPENAI_EMBEDDING_COMPATIBLE = new Set(["openai", "openrouter", "deepseek", "local"]); +const OPENAI_EMBEDDING_COMPATIBLE = new Set(["openai", "openrouter", "requesty", "deepseek", "local"]); function openAIEmbeddingBaseUrl(config: RuntimeConfig): string { const reuse = OPENAI_EMBEDDING_COMPATIBLE.has(config.provider.name) && config.provider.baseUrl; diff --git a/src/model-routes.ts b/src/model-routes.ts index 169b38d9e..eb4a807bc 100644 --- a/src/model-routes.ts +++ b/src/model-routes.ts @@ -40,7 +40,7 @@ export const MODEL_ALIASES: Record/ slug scheme as OpenRouter, + // so the per-vendor context-window lookup applies unchanged. + return openrouterContextWindowTokens(model); case "deepseek": return deepseekContextWindowTokens(model); case "anthropic": @@ -187,6 +191,9 @@ export function resolveProviderModality(provider: ProviderConfig): ProviderModal : { vision: false, nativeDocs: false }; case "openrouter": return openrouterModality(model); + case "requesty": + // Same / slug scheme as OpenRouter; reuse its modality map. + return openrouterModality(model); case "deepseek": // Confirmed text-only API — no image/file content part. return { vision: false, nativeDocs: false }; diff --git a/src/provider.ts b/src/provider.ts index cab266edb..33f3e943f 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -136,6 +136,7 @@ export function providerHealth(config: RuntimeConfig) { const PROVIDER_API_KEY_ENV: Record = { openai: "OPENAI_API_KEY", openrouter: "OPENROUTER_API_KEY", + requesty: "REQUESTY_API_KEY", deepseek: "DEEPSEEK_API_KEY", local: "GINI_LOCAL_API_KEY", anthropic: "ANTHROPIC_API_KEY", @@ -376,6 +377,16 @@ export function providerCatalog(): ProviderCatalogItem[] { capabilities: ["chat-completions", "model-routing"], costHint: "external" }, + { + id: "requesty", + name: "requesty", + displayName: "Requesty Compatible", + baseUrl: "https://router.requesty.ai/v1", + auth: "env", + models: ["openai/gpt-4o-mini"], + capabilities: ["chat-completions", "model-routing"], + costHint: "external" + }, { id: "deepseek", name: "deepseek", @@ -429,6 +440,8 @@ export function providerDisplayLabel(name: ProviderName): string { return "OpenAI"; case "openrouter": return "OpenRouter"; + case "requesty": + return "Requesty"; case "deepseek": return "DeepSeek"; case "anthropic": @@ -3082,6 +3095,7 @@ export async function generateTaskSummary( } if ( provider.name === "openrouter" || + provider.name === "requesty" || provider.name === "local" || provider.name === "deepseek" || // Azure OpenAI exposes deployment-scoped chat/completions, not the flat @@ -3225,6 +3239,7 @@ export async function generateStructured( // many compat providers reject the field. Validator re-checks shape. if ( provider.name === "openrouter" || + provider.name === "requesty" || provider.name === "local" || provider.name === "openai" || provider.name === "deepseek" || @@ -3436,6 +3451,15 @@ export function normalizeProvider(provider: ProviderConfig): ProviderConfig { ...(provider.extraBody ? { extraBody: provider.extraBody } : {}) }; } + if (provider.name === "requesty") { + return { + name: "requesty", + model: provider.model || "openai/gpt-4o-mini", + baseUrl: pickBaseUrl(provider.baseUrl, "https://router.requesty.ai/v1"), + apiKeyEnv: provider.apiKeyEnv ?? "REQUESTY_API_KEY", + ...(provider.extraBody ? { extraBody: provider.extraBody } : {}) + }; + } if (provider.name === "local") { return { name: "local", @@ -4329,6 +4353,7 @@ function resolveBaseUrl(baseUrl: string | undefined, fallback: string): string { function defaultBaseUrl(provider: ProviderConfig): string { if (provider.name === "codex") return DEFAULT_CODEX_BASE_URL; if (provider.name === "openrouter") return "https://openrouter.ai/api/v1"; + if (provider.name === "requesty") return "https://router.requesty.ai/v1"; if (provider.name === "local") return "http://127.0.0.1:11434/v1"; if (provider.name === "deepseek") return DEFAULT_DEEPSEEK_BASE_URL; if (provider.name === "anthropic") return DEFAULT_ANTHROPIC_BASE_URL; diff --git a/src/runtime/setup-api.ts b/src/runtime/setup-api.ts index d2286826a..1c58221b3 100644 --- a/src/runtime/setup-api.ts +++ b/src/runtime/setup-api.ts @@ -56,7 +56,7 @@ import { isValidEnvVarName, removeKeyFromSecretsEnv, writeKeyToSecretsEnv } from import { requestAutostartRefresh } from "./autostart-refresh"; import type { ProviderConfig, ProviderName, RuntimeConfig } from "../types"; -const SUPPORTED_PROVIDERS = ["openai", "codex", "openrouter", "deepseek", "local", "anthropic", "bedrock", "azure"] as const; +const SUPPORTED_PROVIDERS = ["openai", "codex", "openrouter", "requesty", "deepseek", "local", "anthropic", "bedrock", "azure"] as const; type SupportedProvider = (typeof SUPPORTED_PROVIDERS)[number]; // Env-keyed providers that authenticate via an env var written to @@ -71,6 +71,7 @@ type SupportedProvider = (typeof SUPPORTED_PROVIDERS)[number]; const ENV_KEY_PROVIDERS: Record = { openai: { envVar: "OPENAI_API_KEY", allowEmptyKey: false, defaultModel: "gpt-5.4-mini" }, openrouter: { envVar: "OPENROUTER_API_KEY", allowEmptyKey: false, defaultModel: "openrouter/auto" }, + requesty: { envVar: "REQUESTY_API_KEY", allowEmptyKey: false, defaultModel: "openai/gpt-4o-mini" }, deepseek: { envVar: "DEEPSEEK_API_KEY", allowEmptyKey: false, defaultModel: "deepseek-v4-flash" }, local: { envVar: "GINI_LOCAL_API_KEY", allowEmptyKey: true, defaultModel: "local/default" }, // First-party Anthropic Messages API key. @@ -107,7 +108,7 @@ export function getSetupStatus(config: RuntimeConfig): SetupStatus { // for browser onboarding. Anyone on echo needs to pick a real // provider in /setup. Other configured providers (openai with key, // codex with auth.json) pass through. - const isRealProvider = current === "openai" || current === "codex" || current === "openrouter" || current === "local" || current === "deepseek" || current === "anthropic" || current === "bedrock" || current === "azure"; + const isRealProvider = current === "openai" || current === "codex" || current === "openrouter" || current === "requesty" || current === "local" || current === "deepseek" || current === "anthropic" || current === "bedrock" || current === "azure"; // A graceful, transient fallback (the selected provider is unconfigured but // another real one is) keeps the app usable instead of bouncing to /setup: // resolveDispatchProvider returns usingFallback when a configured fallback diff --git a/src/types.ts b/src/types.ts index 847a2f3d2..4fd48a8f8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -23,7 +23,7 @@ export type SkillStatus = "enabled" | "disabled" | "archived"; export type JobStatus = "active" | "paused" | "failed"; -export type ProviderName = "echo" | "openai" | "codex" | "openrouter" | "local" | "deepseek" | "anthropic" | "bedrock" | "azure"; +export type ProviderName = "echo" | "openai" | "codex" | "openrouter" | "requesty" | "local" | "deepseek" | "anthropic" | "bedrock" | "azure"; export type ImprovementStatus = "proposed" | "approved" | "rejected" | "applied"; diff --git a/web/src/app/settings/_components/ProviderCard.tsx b/web/src/app/settings/_components/ProviderCard.tsx index 54f2002c2..f85a63391 100644 --- a/web/src/app/settings/_components/ProviderCard.tsx +++ b/web/src/app/settings/_components/ProviderCard.tsx @@ -29,11 +29,11 @@ import { EditProviderDialog } from "./EditProviderDialog"; // and the trash button is disabled for that row — a permanently-dead affordance. // Azure is managed by re-add via Add Provider; key cleanup is the CLI `gini // provider` path. -const REMOVABLE_PROVIDERS = new Set(["openai", "openrouter", "deepseek", "anthropic", "bedrock"]); +const REMOVABLE_PROVIDERS = new Set(["openai", "openrouter", "requesty", "deepseek", "anthropic", "bedrock"]); // Provider rows shown on the Settings page, in display order. Echo is // dev-only and never configured, so it can't appear. -const SELECTABLE_PROVIDERS = ["codex", "openai", "anthropic", "bedrock", "deepseek", "openrouter", "azure", "local"] as const; +const SELECTABLE_PROVIDERS = ["codex", "openai", "anthropic", "bedrock", "deepseek", "openrouter", "requesty", "azure", "local"] as const; // Friendly labels for how each provider authenticates; the brand icons live // in the shared PROVIDER_ICONS map (provider-logos.tsx). @@ -44,6 +44,7 @@ const PROVIDER_AUTH_LABEL: Record = { bedrock: "AWS", deepseek: "API key", openrouter: "API key", + requesty: "API key", azure: "API key", local: "Local" }; diff --git a/web/src/app/setup/page.tsx b/web/src/app/setup/page.tsx index f24b8fb85..6966086b5 100644 --- a/web/src/app/setup/page.tsx +++ b/web/src/app/setup/page.tsx @@ -13,7 +13,7 @@ import { ProviderPicker } from "@/components/ProviderPicker"; // On mount we call /api/setup/status. If providerConfigured is true the user // got here by mistake (or backed into the URL) and we redirect home. Otherwise // we render the shared ProviderPicker, which offers the full provider catalog -// (OpenAI, Codex, Anthropic, Bedrock, OpenRouter, DeepSeek, Azure, Local) and +// (OpenAI, Codex, Anthropic, Bedrock, OpenRouter, Requesty, DeepSeek, Azure, Local) and // POSTs the choice to /api/setup/provider — the same surface Settings → Add // provider uses. diff --git a/web/src/components/ProviderPicker.tsx b/web/src/components/ProviderPicker.tsx index 203a47045..2cec7a68e 100644 --- a/web/src/components/ProviderPicker.tsx +++ b/web/src/components/ProviderPicker.tsx @@ -40,6 +40,7 @@ export const SELECTABLE_PROVIDERS = [ "anthropic", "bedrock", "openrouter", + "requesty", "deepseek", "azure", "local" @@ -53,6 +54,7 @@ export const PROVIDER_DESCRIPTION: Record = { anthropic: "Claude (first-party API key)", bedrock: "Claude, Nova, Llama… on AWS", openrouter: "Multi-model router", + requesty: "Multi-model router", deepseek: "DeepSeek V4 family", azure: "Azure OpenAI deployments", local: "Ollama, LM Studio, vLLM" diff --git a/web/src/components/provider-logos.tsx b/web/src/components/provider-logos.tsx index 3f4b44e5f..ad232dfa1 100644 --- a/web/src/components/provider-logos.tsx +++ b/web/src/components/provider-logos.tsx @@ -10,7 +10,7 @@ // the others rather than its teal service tile. import * as React from "react"; -import { SparklesIcon, Terminal as TerminalIcon, ZapIcon } from "lucide-react"; +import { RouteIcon, SparklesIcon, Terminal as TerminalIcon, ZapIcon } from "lucide-react"; type LogoProps = React.SVGAttributes; @@ -105,8 +105,8 @@ export function AzureLogo({ className, ...rest }: LogoProps) { // Brand icon per model-provider name, shared by the Settings provider rows // and the model picker (trigger + route flyout) so the surfaces can't drift. -// Codex (Terminal) and OpenRouter (Zap) use Lucide because neither has a -// widely-recognized brand mark; the rest are the brand SVGs above. +// Codex (Terminal), OpenRouter (Zap), and Requesty (Route) use Lucide because +// none has a widely-recognized brand mark; the rest are the brand SVGs above. export const PROVIDER_ICONS: Record> = { codex: TerminalIcon, openai: OpenAILogo, @@ -114,6 +114,7 @@ export const PROVIDER_ICONS: Record