Add Requesty as a provider option#7
Conversation
Mirror the existing @openrouter/ai-sdk-provider usage to add Requesty (https://router.requesty.ai/v1) via @requesty/ai-sdk, an OpenAI-compatible LLM router. Requesty is selected when a Requesty key is present; the OpenRouter path is unchanged. Signed-off-by: Thibault Jaigu <thibault.jaigu@gmail.com>
Greptile SummaryThis PR adds Requesty as an OpenAI-compatible provider alternative to OpenRouter, mirroring the existing
Confidence Score: 3/5Not safe to merge in current form — a Requesty-only user running the CLI will hit auth errors on the first scan turn because the majority of agents still call OpenRouter with the Requesty key. The attacker and evaluator changes are correct, but four other agents (Strategist, Mutator, Inspector, Target) and the injection evaluator remain OpenRouter-only. ScanEngine passes the resolved API key to all of them, so a Requesty key ends up at the OpenRouter endpoint and triggers authentication failures before the first attack turn completes. The model-name default issue compounds this: even if the other agents were fixed, the dot-vs-hyphen model ID mismatch could break Requesty calls when model names flow in from ScanEngine's defaults. src/agents/engine.ts and the unmodified agent files (strategist.ts, mutator.ts, inspector.ts, injection-evaluator.ts, target.ts) need Requesty support added to match what was done in attacker.ts and evaluator.ts. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
CLI["CLI: zeroleaks scan --provider requesty"]
ENV["Sets process.env.REQUESTY_API_KEY = apiKey"]
RUN["runSecurityScan({ apiKey: requestyKey })"]
ENGINE["ScanEngine constructor\napiKey = config.apiKey (requestyKey)"]
ENGINE --> ATK["createAttacker({ apiKey: requestyKey })\n✅ Auto-detects REQUESTY_API_KEY\nUses createRequesty()"]
ENGINE --> EVAL["createEvaluator({ apiKey: requestyKey })\n✅ Auto-detects REQUESTY_API_KEY\nUses createRequesty()"]
ENGINE --> STRAT["createStrategist({ apiKey: requestyKey })\n❌ Uses createOpenRouter(requestyKey)\n→ 401 on OpenRouter"]
ENGINE --> MUT["createMutator({ apiKey: requestyKey })\n❌ Uses createOpenRouter(requestyKey)\n→ 401 on OpenRouter"]
ENGINE --> INSP["createInspector(..., requestyKey)\n❌ Uses createOpenRouter(requestyKey)\n→ 401 on OpenRouter"]
ENGINE --> TARGET["createTarget(prompt, { apiKey: requestyKey })\n❌ Uses createOpenRouter(requestyKey)\n→ 401 on OpenRouter"]
CLI --> ENV --> RUN --> ENGINE
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
CLI["CLI: zeroleaks scan --provider requesty"]
ENV["Sets process.env.REQUESTY_API_KEY = apiKey"]
RUN["runSecurityScan({ apiKey: requestyKey })"]
ENGINE["ScanEngine constructor\napiKey = config.apiKey (requestyKey)"]
ENGINE --> ATK["createAttacker({ apiKey: requestyKey })\n✅ Auto-detects REQUESTY_API_KEY\nUses createRequesty()"]
ENGINE --> EVAL["createEvaluator({ apiKey: requestyKey })\n✅ Auto-detects REQUESTY_API_KEY\nUses createRequesty()"]
ENGINE --> STRAT["createStrategist({ apiKey: requestyKey })\n❌ Uses createOpenRouter(requestyKey)\n→ 401 on OpenRouter"]
ENGINE --> MUT["createMutator({ apiKey: requestyKey })\n❌ Uses createOpenRouter(requestyKey)\n→ 401 on OpenRouter"]
ENGINE --> INSP["createInspector(..., requestyKey)\n❌ Uses createOpenRouter(requestyKey)\n→ 401 on OpenRouter"]
ENGINE --> TARGET["createTarget(prompt, { apiKey: requestyKey })\n❌ Uses createOpenRouter(requestyKey)\n→ 401 on OpenRouter"]
CLI --> ENV --> RUN --> ENGINE
Reviews (1): Last reviewed commit: "Add Requesty as a provider option" | Re-trigger Greptile |
| if (useRequesty) { | ||
| this.provider = createRequesty({ | ||
| apiKey: config?.apiKey || requestyKey, | ||
| }); | ||
| this.model = config?.model || "anthropic/claude-sonnet-4-5"; | ||
| } else { | ||
| this.provider = createOpenRouter({ | ||
| apiKey: config?.apiKey || openrouterKey, | ||
| }); | ||
| this.model = config?.model || "anthropic/claude-sonnet-4.5"; | ||
| } |
There was a problem hiding this comment.
Requesty model-name default unreachable via
ScanEngine
The Requesty branch sets this.model = config?.model || "anthropic/claude-sonnet-4-5" (hyphens), but ScanEngine.DEFAULT_CONFIG always provides a model ("anthropic/claude-sonnet-4.5" with dots). Because config?.model is always truthy when called from the engine, the hyphenated Requesty default is never used in the CLI path — the agent always receives the dot-format model name. If Requesty strictly requires hyphenated model IDs, every call from ScanEngine will fail. The same issue exists identically in evaluator.ts.
| const provider: "openrouter" | "requesty" = | ||
| options.provider === "requesty" || options.provider === "openrouter" | ||
| ? options.provider | ||
| : requestyEnvKey && !openrouterEnvKey | ||
| ? "requesty" | ||
| : "openrouter"; |
There was a problem hiding this comment.
An unrecognized
--provider value (e.g. --provider gpt) silently falls through to "openrouter" with no warning. Users who make a typo will get a confusing auth failure instead of a clear validation error.
| const provider: "openrouter" | "requesty" = | |
| options.provider === "requesty" || options.provider === "openrouter" | |
| ? options.provider | |
| : requestyEnvKey && !openrouterEnvKey | |
| ? "requesty" | |
| : "openrouter"; | |
| if (options.provider && options.provider !== "requesty" && options.provider !== "openrouter") { | |
| console.error( | |
| `Error: Unknown provider "${options.provider}". Valid values: openrouter, requesty`, | |
| ); | |
| process.exit(1); | |
| } | |
| const provider: "openrouter" | "requesty" = | |
| options.provider === "requesty" || options.provider === "openrouter" | |
| ? options.provider | |
| : requestyEnvKey && !openrouterEnvKey | |
| ? "requesty" | |
| : "openrouter"; |
| | `REQUESTY_API_KEY` | Your Requesty API key — Requesty is an OpenAI-compatible alternative to OpenRouter (base URL `https://router.requesty.ai/v1`). Used automatically when set and `OPENROUTER_API_KEY` is not, or force it with `--provider requesty`. | | ||
|
|
||
| Get your API key at [openrouter.ai](https://openrouter.ai) | ||
| Get your API key at [openrouter.ai](https://openrouter.ai) or [requesty.ai](https://router.requesty.ai/v1) |
There was a problem hiding this comment.
The "get your API key" link points to
https://router.requesty.ai/v1, which is the API base URL, not the web dashboard where users sign up and obtain keys.
| Get your API key at [openrouter.ai](https://openrouter.ai) or [requesty.ai](https://router.requesty.ai/v1) | |
| Get your API key at [openrouter.ai](https://openrouter.ai) or [requesty.ai](https://requesty.ai) |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
x1xhlol
left a comment
There was a problem hiding this comment.
Reviewed the provider-selection path across the CLI, attacker, evaluator, and docs. The OpenRouter default appears preserved, and Requesty is only selected explicitly or when REQUESTY_API_KEY is present without OPENROUTER_API_KEY, which keeps existing users on the current path. No blocking changes from this pass; the main thing I would consider before merge is a small unit/CLI coverage check around provider resolution so the auto-detection rules do not regress later.
This adds Requesty as an OpenAI-compatible provider option, mirroring the existing
@openrouter/ai-sdk-providerusage.Requesty (
https://router.requesty.ai/v1) is an OpenAI-compatible LLM router. I used@requesty/ai-sdk@0.0.9to match this repo's AI SDK v4 (@ai-sdk/provider@1.0.9, same as@openrouter/ai-sdk-provider@0.4.3).Changes:
attacker.ts/evaluator.tsselect Requesty when a Requesty key is present (viacreateRequesty), the CLI acceptsREQUESTY_API_KEY/--provider, and README/AGENTS note the option. The existing OpenRouter path is unchanged and remains the default.I work at Requesty. This mirrors the existing OpenRouter provider as closely as possible. Happy to adjust or close it if it's not a fit.