Skip to content

Bind dedupe LLM credentials to the model instead of extra_args - #1100

Open
AmIrRX0 wants to merge 1 commit into
usestrix:mainfrom
AmIrRX0:fix/1095-dedupe-duplicate-api-key
Open

Bind dedupe LLM credentials to the model instead of extra_args#1100
AmIrRX0 wants to merge 1 commit into
usestrix:mainfrom
AmIrRX0:fix/1095-dedupe-duplicate-api-key

Conversation

@AmIrRX0

@AmIrRX0 AmIrRX0 commented Aug 18, 2026

Copy link
Copy Markdown

Fixes #1095

Root cause

Not the module-level litellm.api_key global the issue suspected — those globals
are fine, litellm falls back to them cleanly.

A dedicated dedupe model (STRIX_DEDUPE_MODEL) carried its own
DEDUPE_LLM_API_KEY / DEDUPE_LLM_API_BASE through ModelSettings.extra_args
(_dedupe_extra_args). LitellmModel._fetch_response passes
api_key=self.api_key explicitly and splats extra_args into the same
litellm.acompletion() call, so the key arrived twice:

TypeError: litellm.main.acompletion() got multiple values for keyword argument 'api_key'

The OpenAI route was broken the same way — chat.completions.create() has no
api_key parameter at all, so a dedupe model on that route failed with an
unexpected-keyword error.

Reproducing

export STRIX_LLM="openai/gpt-5.4"
export LLM_API_KEY="..."
export STRIX_DEDUPE_MODEL="deepseek/cheap"
export DEDUPE_LLM_API_KEY="..."          # this is what triggers it
strix --target https://example.com

Before: warm-up dies at the dedupe model with
TypeError: litellm.main.acompletion() got multiple values for keyword argument 'api_key'.

After: the dedupe model connects, with its own key and endpoint still isolated
from the main model's.

Fix

Credentials ride on the model rather than on the request:

  • StrixProvider takes optional api_key/api_base. They go to MultiProvider
    for the OpenAI route and are bound onto the LitellmModel for the LiteLLM
    route — which is what LitellmModel(model, base_url, api_key) exists for.
  • _dedupe_extra_argsdedupe_model_provider(), used by both check_duplicate
    and the warm-up path in warm_up_llm.

Behaviour is unchanged: a dedicated dedupe model still keeps its endpoint and key
isolated from the main model's process-wide config, and base_url overrides
api_base inside litellm.completion() exactly as the old
extra_args["api_base"] did.

Tests

  • New regression test drives a dedupe call through the real LitellmModel to
    litellm.acompletion — it fails with the reported TypeError before this change.
  • Existing dedupe tests updated to assert credentials are bound to the model and
    never present in extra_args.
  • Full suite: 933 passed. ruff check, ruff format --check, mypy strix/ and
    bandit -r strix/ -c pyproject.toml clean on the changed files.

A dedicated dedupe model (STRIX_DEDUPE_MODEL) carried its own
DEDUPE_LLM_API_KEY / DEDUPE_LLM_API_BASE through
ModelSettings.extra_args. LitellmModel already passes api_key= to
litellm.acompletion() explicitly and then splats extra_args into the
same call, so the key arrived twice and every dedupe request died
before it was sent:

    TypeError: litellm.main.acompletion() got multiple values for
    keyword argument 'api_key'

The OpenAI route was broken the same way: chat.completions.create()
has no api_key parameter at all.

Credentials now ride on the model rather than on the request.
StrixProvider takes optional api_key/api_base, forwarding them to
MultiProvider for the OpenAI route and binding them onto the
LitellmModel for the LiteLLM route, which is what those constructor
arguments are for. dedupe_model_provider() builds that provider, so a
dedicated dedupe model keeps its endpoint and key separate from the
main model's process-wide config exactly as before.

Fixes usestrix#1095
@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR moves dedicated dedupe credentials from per-request extra_args onto the provider/model that owns the dedupe route, preventing duplicate or unsupported credential arguments.

  • Adds route-scoped API key and base URL support to StrixProvider.
  • Uses a shared dedupe-provider factory in both startup warm-up and report deduplication.
  • Adds regression coverage for LiteLLM credential binding, endpoint isolation, fallback behavior, and duplicate-key prevention.

Confidence Score: 5/5

The PR appears safe to merge, with dedicated dedupe credentials consistently scoped to the selected provider and no concrete regression identified.

Both warm-up and runtime deduplication now use the same credential-aware provider path, while the tests cover credential binding, endpoint isolation, fallback to global configuration, and the original duplicate-key failure.

Important Files Changed

Filename Overview
strix/config/models.py Adds provider-scoped credential handling and binds dedicated credentials to raw LiteLLM models before applying local wrappers.
strix/interface/main.py Updates dedupe warm-up to resolve its model through the same credential-aware provider used at runtime.
strix/report/dedupe.py Replaces request-level credential arguments with a dedicated provider factory while preserving model settings and fallback behavior.
tests/test_dedupe_model.py Adds focused coverage proving credentials stay off extra_args, remain model-scoped, and reach a real LiteLLM call without duplicate keywords.

Reviews (1): Last reviewed commit: "Bind dedupe LLM credentials to the model..." | Re-trigger Greptile

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.

LLM CONNECTION FAILED — duplicate api_key keyword argument when LLM_API_BASE is set to a custom endpoint

1 participant