Skip to content

Add Requesty as a provider option - #7

Closed
Thibaultjaigu wants to merge 1 commit into
ZeroLeaks:mainfrom
Thibaultjaigu:add-requesty-provider
Closed

Thibaultjaigu wants to merge 1 commit into
ZeroLeaks:mainfrom
Thibaultjaigu:add-requesty-provider

Conversation

@Thibaultjaigu

@Thibaultjaigu Thibaultjaigu commented Jul 1, 2026 •

Copy link
Copy Markdown

This adds Requesty as an opt in router for the scanner, next to the existing OpenRouter and OpenAI paths in resolveModel.

Requesty (https://router.requesty.ai/v1) is an OpenAI compatible LLM router with the same provider/model id format as OpenRouter. It is never picked automatically: OpenRouter stays the default for every model, and setting REQUESTY_API_KEY alone changes nothing. Requesty is only used when you ask for it with --provider requesty (or ZEROLEAKS_PROVIDER=requesty), or when a single model id carries a requesty/ prefix.

Changes:

Rebased on current main. The first version added a @requesty/ai-sdk dependency and picked Requesty whenever a key was present. Since upstream centralised provider selection in src/provider.ts, the PR was redone on top of that: no new dependency (Requesty is created with the existing @ai-sdk/openai client pointed at the Requesty base URL), the key based auto detection is gone, and there is an explicit --provider flag plus a requesty/ model id prefix instead.

  • src/provider.ts: RouterProvider type, parseProvider (unknown values throw instead of silently falling back), isRequestyModel, and a Requesty branch in resolveModel that strips the requesty/ prefix before sending the id. OpenAI ids keep the OpenAI direct path when OPENAI_API_KEY is set, exactly as before.
  • src/bin/cli.ts: --provider <openrouter|requesty> and --requesty-api-key, with REQUESTY_API_KEY and ZEROLEAKS_PROVIDER as env equivalents. --provider requesty without a Requesty key exits with a clear error, and a Requesty key alone now satisfies the "at least one key" check.
  • Because attacker, evaluator, strategist, mutator, inspector, injection evaluator and target all go through resolveModel, the flag covers every agent with no per agent changes.
  • tests/provider.test.ts: covers the default (OpenRouter even when only a Requesty key is set), the prefix, the flag and env var, the OpenAI direct path, and the CLI validation.
  • README.md, AGENTS.md, .env.example: document the option and the model library (https://app.requesty.ai/model-library).

Usage:

export REQUESTY_API_KEY=...            # keys: https://app.requesty.ai/api-keys
zeroleaks scan -f ./prompt.txt --provider requesty

# only the target through Requesty, everything else stays on OpenRouter
zeroleaks scan -f ./prompt.txt --target-model "requesty/anthropic/claude-sonnet-4-5"

Docs: https://docs.requesty.ai

Disclosure: I work at Requesty. Happy to adjust anything to match project conventions.

@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds Requesty as an OpenAI-compatible provider alternative to OpenRouter, mirroring the existing @openrouter/ai-sdk-provider integration in attacker.ts and evaluator.ts, with CLI support via --provider requesty and REQUESTY_API_KEY.

  • Partial agent coverage: Only Attacker and Evaluator were updated; Strategist, Mutator, Inspector, InjectionEvaluator, and Target still call createOpenRouter unconditionally. When --provider requesty is used, ScanEngine passes the Requesty API key to all those agents, which then send it to the OpenRouter endpoint and receive auth errors — the scan fails on the first turn.
  • Model-name default bypass: The Requesty branches in attacker.ts/evaluator.ts default to hyphenated model IDs (anthropic/claude-sonnet-4-5), but ScanEngine.DEFAULT_CONFIG always supplies a dot-format model name, so the hyphenated fallback is never reached from the CLI path.
  • CLI and docs: Provider auto-detection and env-var propagation are logically sound; invalid --provider values are silently ignored rather than rejected, and the README "get your key" link points to the API endpoint instead of the web dashboard.

Confidence Score: 3/5

Not 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

Filename Overview
src/agents/engine.ts Not directly changed, but exposes a gap: ScanEngine passes the resolved API key to Strategist, Mutator, Inspector, InjectionEvaluator, and Target without any Requesty awareness — these agents will send Requesty keys to OpenRouter, causing auth failures for Requesty-only users.
src/agents/attacker.ts Provider selection logic is correct in isolation, but the Requesty-specific hyphenated model default is never reached when called from ScanEngine because the engine always supplies a dot-format model name from DEFAULT_CONFIG.
src/agents/evaluator.ts Same provider-selection pattern as attacker.ts with the same model-name default reachability issue; otherwise mirrors the attacker change cleanly.
src/bin/cli.ts Provider resolution and env-var propagation are logically correct; invalid provider values are silently ignored rather than rejected, which is a minor UX gap.
package.json Adds @requesty/ai-sdk@0.0.9 as a dependency; version is pinned exactly (no caret), matching the PR's rationale about AI SDK v4 compatibility.
README.md Documentation is clear and accurate; the "get your API key" URL points to the router endpoint rather than the website dashboard.
AGENTS.md Updated cleanly to reflect both providers in the tech-stack and environment-variable sections.

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
Loading
%%{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
Loading

Reviews (1): Last reviewed commit: "Add Requesty as a provider option" | Re-trigger Greptile

Comment thread src/agents/attacker.ts Outdated
Comment thread src/bin/cli.ts Outdated
Comment thread README.md Outdated

@x1xhlol x1xhlol left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Requesty (https://router.requesty.ai/v1) is an OpenAI-compatible LLM
router. It is wired into resolveModel, the single place every agent
(attacker, evaluator, strategist, mutator, inspector, injection
evaluator and target) gets its model from, so no agent code changes.

Requesty is never picked automatically. It is used only when selected
explicitly: the CLI flag --provider requesty (or ZEROLEAKS_PROVIDER),
opts.provider on resolveModel, or a requesty/ prefix on a single model
id. Unknown --provider values are rejected instead of falling back.
The key comes from REQUESTY_API_KEY or --requesty-api-key. OpenRouter
stays the default and the OpenAI direct path is unchanged.

Adds tests/provider.test.ts covering the selection rules and the CLI
validation, plus README, AGENTS.md and .env.example notes.
@Thibaultjaigu

Copy link
Copy Markdown
Author

@x1xhlol thanks for the pass. I reworked the branch after your review and it now has the coverage you asked for.

Provider resolution lives in one place, src/provider.ts, and tests/provider.test.ts covers it with 8 cases: the OpenRouter default, rejection of unknown names, OpenRouter staying the default even when only REQUESTY_API_KEY is set, the requesty/ prefix routing a single model, --provider requesty and ZEROLEAKS_PROVIDER routing every agent, OpenAI ids keeping the direct OpenAI path, the CLI rejecting an unknown --provider, and the CLI requiring a Requesty key when Requesty is selected. bun test passes locally (8 pass, 0 fail) on 94efded, which is rebased on current main.

One behaviour change from the first version, in line with your note about keeping existing users on the current path: Requesty is never auto detected any more. It is only used when asked for explicitly, so a Requesty key sitting in the environment changes nothing.

@neoarz

neoarz commented Sep 25, 2026

Copy link
Copy Markdown
Member

Thanks for the PR, and for reworking it after the review!

#10 was just merged and and adds a --base-url flag for any OpenAI-compatible endpoint, so Requesty works now without any provider-specific code:

zeroleaks scan -f ./prompt.txt \
  --base-url https://router.requesty.ai/v1 \
  --openai-api-key $REQUESTY_API_KEY

Model ids like anthropic/claude-sonnet-4-5 go to Requesty unchanged, as long as OPENROUTER_API_KEY isn't also set.

Since that covers it, I'm going to close this one. If anything doesn't work with Requesty, open an issue and we'll take a look.

@neoarz neoarz closed this Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants