#94

feat(llm): add named OrcaRouter provider (orcarouter/* model aliases)

OpenJinhaoSong322wants to merge intofrom

Summary

Adds first-class support for OrcaRouter as a named provider. Models using an orcarouter/* alias (e.g. orcarouter/auto) now route through the OrcaRouter OpenAI-compatible gateway at https://api.orcarouter.ai/v1 using ORCAROUTER_API_KEY, mirroring the existing openai/ relay pattern already used for custom API bases.

It also runs gateway-level, zero-trust security for AI agents on the same endpoint — screening every prompt/response and governing every tool call on a default-deny basis, with no application code changes.

What changed

  • pentestagent/llm/llm.py: _is_orcarouter_model() detection + _apply_orcarouter() which injects custom_llm_provider="openai", api_base, and api_key for orcarouter/* models. Wired into generate, generate_stream, and _summarize_call. get_available_models() includes orcarouter/auto and orcarouter/fusion.
  • pentestagent/llm/config.py / pentestagent/config/settings.py: orcarouter_api_base (defaults to https://api.orcarouter.ai/v1, override via ORCAROUTER_BASE_URL) and orcarouter_api_key (ORCAROUTER_API_KEY). Key is masked in repr/str.
  • pentestagent/config/constants.py: ORCAROUTER_API_BASE + get_orcarouter_api_base().
  • pentestagent/knowledge/embeddings.py: orcarouter/* embedding models route through the gateway; should_use_local_embeddings() recognizes ORCAROUTER_API_KEY.
  • .env.example / README.md: documented the named OrcaRouter provider with a config example and a Docker run example.
  • Tests: prefix detection, routing kwargs (chat + stream + embeddings), env defaults, non-OrcaRouter isolation, and key masking.

Verification

  • pytest tests/unit/ tests/security/ — 627 passed (includes new orcarouter tests)
  • ruff check on all changed files — clean
  • Black: no new violations vs upstream (CI runs black with continue-on-error)
  • L3 live test with a real OrcaRouter key through the production LLM path (orcarouter/auto → https://api.orcarouter.ai/v1): non-streaming returned ORCA-OK, streaming returned STREAM-OK

Disclosure: I'm an engineer on the OrcaRouter team.