Skip to content

Feat/litellm unified adapters 379#388

Merged
Nicola Franco (franconicola) merged 23 commits into
mainfrom
feat/litellm-unified-adapters-379
May 23, 2026
Merged

Feat/litellm unified adapters 379#388
Nicola Franco (franconicola) merged 23 commits into
mainfrom
feat/litellm-unified-adapters-379

Conversation

@franconicola
Copy link
Copy Markdown
Member

No description provided.

Route every chat-completion AgentType through `litellm.completion`. The
LiteLLMAgent base now owns provider-prefix routing, the unified
`thinking` knob, tool-calls, and reasoning-content extraction. OpenAI
and Ollama agents collapse to thin subclasses that pin the provider
prefix (`openai`, `ollama_chat`) and translate `thinking` to
`reasoning_effort` or Ollama's `think` field.

ADK still requires HTTP transport LiteLLM doesn't speak natively, so
the adapter registers a per-instance `litellm.CustomLLM` handler that
implements the `POST /run` + sessions + events protocol and packages
the result into a `ModelResponse`. From the router's perspective ADK
is now just another LiteLLM provider.

Router config branches collapse: all chat AgentTypes share the same
metadata-merge path; ADK only adds `user_id`. Unit tests for OpenAI,
Ollama, and ADK rewritten against `litellm.completion` patching, and
the OpenAI integration test no longer asserts on a non-existent SDK
client. LITELLM_ROUTER_REFACTOR_PLAN.md captures the follow-up plan to
move the call site into `router.py` and shrink the adapters folder
further.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase A of the LiteLLM router refactor plan: pull the response-shaping
logic out of the adapter classes into pure functions in
``hackagent/router/envelope.py``. Adapter classes now delegate to those
helpers; the public dict shape returned by ``handle_request`` is
unchanged (snapshot tests in test_envelope.py).

Also lands ``hackagent/router/provider_config.py`` — the AgentType →
provider-prefix + thinking-translator + extra-passthrough-keys table
that Phase C will use to bypass the adapter classes entirely. The
table isn't wired in yet; this commit just ships the lookup module
with its own unit tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase B of the LiteLLM router refactor. LiteLLMAgent.__init__ now
accepts an optional ProviderConfig. OpenAIAgent and OllamaAgent look
their config up from hackagent/router/provider_config.py instead of
overriding ``_apply_thinking`` and ``PROVIDER_PREFIX``.

The class-level ``PROVIDER_PREFIX`` path stays for backwards
compatibility (and is still how ADKAgent injects its per-instance
provider name). Phase C will use this same ProviderConfig lookup
inside ``AgentRouter`` to bypass the adapter classes entirely for
chat-completion agent types.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase C of the LiteLLM router refactor. ``AgentRouter.route_request``
now dispatches chat-completion AgentTypes (LITELLM, OPENAI_SDK,
OLLAMA, LANGCHAIN) directly through ``litellm.completion`` via the new
``_dispatch_via_litellm`` method, looking up the provider prefix,
thinking translator, and passthrough keys from
``hackagent/router/provider_config.py``.

The adapter classes are still instantiated and still expose
``handle_request`` for backwards compatibility — that's the path
GOOGLE_ADK and any future protocol-specific AgentType continue to use.
For chat types, ``handle_request`` is no longer on the hot path; the
adapter instance is consulted only for its already-resolved model
name, endpoint, API key, and generation defaults.

The HackAgent envelope dict shape is byte-identical to the previous
adapter-driven path (verified by leaving all existing adapter tests
green plus six new tests covering the new dispatch path).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase D of the LiteLLM router refactor. Adds
``hackagent/router/tracking_logger.py`` — a ``CustomLogger`` subclass
that hooks ``log_pre_api_call``, ``log_success_event``, and
``log_failure_event``, emitting structured records via
``hackagent.logger`` that downstream sinks (TUI, dashboard) can pick
up.

``AgentRouter.__init__`` registers the logger on ``litellm.callbacks``
exactly once per process. ``_dispatch_via_litellm`` attaches
``metadata={"hackagent_agent_id": ..., "hackagent_adapter_type": ...}``
to every call so the logger can filter HackAgent-owned traffic and
correlate input ↔ output ↔ cost via LiteLLM's call_id. Caller-supplied
``metadata`` (e.g. trace_id for Langfuse/OTEL) is merged in and wins
on collision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase E (partial) of the LiteLLM router refactor. The Google ADK
provider — which is fundamentally a ``litellm.CustomLLM`` wrapping the
ADK ``POST /run`` + sessions + events protocol — now lives at
``hackagent/router/providers/adk.py``, its logical home. The old
``hackagent/router/adapters/google_adk.py`` path is preserved as a
thin re-export shim so existing imports keep working.

The chat adapter classes (``LiteLLMAgent``, ``OpenAIAgent``,
``OllamaAgent``) stay in ``hackagent/router/adapters/`` for now. They
no longer run on the hot path — ``AgentRouter._dispatch_via_litellm``
calls ``litellm.completion`` directly — but their public symbols are
still imported by external callers, so deleting them is a separate
decision documented as Phase E.2 in
``LITELLM_ROUTER_REFACTOR_PLAN.md``.

The plan markdown is updated with a Status section enumerating which
commits landed which phase and what's deferred.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Phase F.1)

Phase F.1 of the LiteLLM router refactor.

- ``hackagent/router/envelope.py`` gains ``extract_response_cost`` and
  ``extract_litellm_call_id`` helpers that pull LiteLLM's
  ``_hidden_params['response_cost']`` and ``_hidden_params['litellm_call_id']``
  (falling back to ``response.id``). Both fields, when present, flow
  through ``build_agent_specific_data`` into the envelope so downstream
  traces can correlate input ↔ output ↔ spend without rooting in the
  raw response object.
- ``AgentRouter._build_error_response`` now sets ``status_code`` (the
  canonical field used by the chat-dispatch envelope) alongside the
  legacy ``raw_response_status`` alias, eliminating the inconsistency
  between the two error paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase E.2a of the LiteLLM router refactor. ``ADKAgent`` no longer
inherits from ``LiteLLMAgent``; it extends :class:`Agent` directly and
implements ``handle_request`` itself, calling
``litellm.completion(model="hackagent_adk_<id>/<app>", messages=…)``
which still routes through the per-instance ``_ADKCustomLLM``.

The lazy ``_get_litellm`` helper is now defined locally in this module
so ADK doesn't depend on ``hackagent.router.adapters.litellm``, which
Phase E.2c is about to delete. All ADK public attributes
(``litellm_model``, ``name``, ``endpoint``, ``user_id``, ``timeout``,
``session_id``, ``fresh_session_per_request``, ``default_*``) are
preserved so the router's dispatch path and external code that pokes
at the adapter keep working unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
….2b)

Phase E.2b of the LiteLLM router refactor. ``AgentRouter`` no longer
instantiates ``LiteLLMAgent`` / ``OpenAIAgent`` / ``OllamaAgent`` for
chat-completion AgentTypes; it builds a lightweight
``_ChatRegistration`` config holder instead. The dispatch path is
unchanged — it reads the same attribute names (``litellm_model``,
``api_base_url``, ``actual_api_key``, ``default_*``…) off whichever
object is stored in ``_agent_registry``.

``_ChatRegistration`` covers the two adapter-class quirks the dispatch
path didn't yet own:

  - OpenAI custom endpoint without API key → placeholder ``"not-required"``.
  - OpenAI custom endpoint without model name → defaults to ``"default"``.
  - Ollama default endpoint resolution + trailing ``/api/*`` stripping.

ADK still uses ``ADKAgent`` because its CustomLLM registration with
LiteLLM is a per-instance side-effect.

The chat adapter classes (``LiteLLMAgent`` / ``OpenAIAgent`` /
``OllamaAgent``) remain importable but are no longer on any hot path
or instantiated by the router. Integration tests updated to assert
against the ``_ChatRegistration`` shape; Phase E.2c will delete the
adapter classes and the obsolete unit tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase E.2c (final phase) of the LiteLLM router refactor. Deletes:

  - hackagent/router/adapters/litellm.py
  - hackagent/router/adapters/openai.py
  - hackagent/router/adapters/ollama.py
  - tests/unit/adapters/test_{litellm,openai,ollama}.py
  - tests/integration/adapters/test_{litellm,openai,ollama}.py

These adapter classes haven't been on the hot path since Phase C and
the router stopped instantiating them in Phase E.2b — every chat
AgentType now goes through ``AgentRouter._dispatch_via_litellm`` with
config supplied by ``_ChatRegistration``. Coverage moves to
``tests/unit/router/test_dispatch.py`` and
``tests/unit/router/test_chat_registration.py``.

``hackagent/router/adapters/__init__.py`` is reduced to the exception
classes + an ``ADKAgent`` re-export. ``hackagent/router/__init__.py``
drops the public ``OllamaAgent`` symbol. ``AGENT_TYPE_TO_ADAPTER_MAP``
now only carries the ADK entry; chat-type validation goes through
``get_provider_config``.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Phase F.2)

Phase F.2 cleans up the LiteLLM ``metadata`` correlation keys. Instead
of flat ``"hackagent_agent_id"`` / ``"hackagent_adapter_type"`` keys
that sit alongside whatever the caller (Langfuse, OTEL, user code…)
also stuffs into ``metadata``, the router now writes a nested block:

    metadata = {
        "hackagent": {"id": "<registration_key>", "adapter_type": "<label>"},
        # caller-supplied keys preserved verbatim
        "trace_id": "...", "user_id": "...",
    }

``HackAgentTrackingLogger._extract_hackagent_metadata`` reads
``metadata["hackagent"]`` instead of scanning for the flat prefix.
Calls without that namespace are ignored, so other tools' callbacks
aren't accidentally double-logged.

Callers who want to override or extend the namespace can supply their
own ``metadata={"hackagent": {"id": "override", ...}}`` — their keys
win on collision inside the namespace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase F.3 finishes the cleanup. The ``adapters/`` directory no longer
holds anything that's actually an adapter, so it's gone:

  - ``adapters/base.py`` → ``hackagent/router/agent.py`` (just the
    ``Agent`` ABC + the three ``Adapter*Error`` exceptions; the dead
    ``ChatCompletionsAgent`` template is removed since nothing
    inherits from it any more).
  - ``adapters/google_adk.py`` back-compat shim deleted; callers
    should import from ``hackagent.router.providers.adk`` (the new
    canonical home, also re-exported from ``hackagent.router``).
  - ``adapters/__init__.py`` deleted.
  - ``tests/unit/adapters/test_google_adk.py`` →
    ``tests/unit/router/test_adk_agent.py``.
  - ``tests/integration/adapters/test_google_adk.py`` →
    ``tests/integration/router/test_adk_agent.py``.
  - ``hackagent.router`` now re-exports ``Agent`` plus the three
    exceptions for the small amount of external code that catches them.

The hierarchical logger name ``hackagent.router.adapters.{type}.{id}``
becomes ``hackagent.router.{type}.{id}`` to match the new module path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Since #379 every chat-completion AgentType goes through LiteLLM, so
HackAgent transparently supports the ~140 providers LiteLLM speaks.
Picking a different provider is a model-string change, not a different
adapter — but the examples folder didn't show this.

Adds ``hackagent/examples/litellm_multi_provider/`` with a runnable
``demo.py`` that targets Anthropic, Gemini, Bedrock, Groq, Mistral,
Together, OpenRouter, or OpenAI via the same HackAgent config (only
the model string and API-key env var change). README explains the
LiteLLM ``"<provider>/<model>"`` convention.

The ``AgentTypeEnum`` docstring is rewritten to make clear that
``LITELLM`` is the general path; ``OPENAI_SDK`` / ``OLLAMA`` /
``LANGCHAIN`` are convenience aliases over the same LiteLLM dispatch.
Gap-filler types (``GOOGLE_ADK`` today, ``MCP``/``A2A`` later) keep
their own slots because LiteLLM doesn't speak those protocols natively.

Includes a small ``tests/unit/examples/`` smoke-test that the provider
table is well-formed and the config builder produces valid LiteLLM
configurations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tests

Closes the issue #379 refactor:

  - ``tests/integration/router/test_litellm_dispatch.py`` replaces the
    coverage of the deleted per-adapter integration tests
    (``test_litellm.py``, ``test_openai.py``, ``test_ollama.py`` —
    removed in Phase E.2c). The new file exercises
    ``AgentRouter.route_request`` end-to-end against a real
    OpenAI-compatible endpoint, asserts the envelope shape (status,
    processed_response, agent_specific_data with usage +
    finish_reason), confirms the ``prompt`` shorthand still works, and
    verifies the ``metadata['hackagent']`` namespace makes it onto
    every ``litellm.completion`` call.

  - ``LITELLM_ROUTER_REFACTOR_PLAN.md`` is removed now that all phases
    A–F.4 landed; the commit chain is the canonical record.

  - One stale docstring in ``router/providers/adk.py`` that mentioned
    the deleted ``LiteLLMAgent`` base is corrected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
try:
import litellm

_litellm_module = litellm
None, lambda: self.completion(*args, **kwargs)
)

_ADK_CUSTOM_LLM_CLASS = _ADKCustomLLM
litellm.callbacks = callbacks

_LOGGER_INSTANCE = instance
_REGISTERED = True
model_response.choices[0].message.content = final_text # type: ignore[attr-defined]
try:
model_response.choices[0].finish_reason = "stop" # type: ignore[attr-defined]
except Exception:
"adk_raw_request": result["raw_request"],
"adk_status_code": result["status_code"],
}
except Exception:
completion_result["tool_calls"] = tool_calls
try:
completion_result["finish_reason"] = response.choices[0].finish_reason
except (AttributeError, IndexError, TypeError):
try:
if response.usage is not None:
completion_result["usage"] = response.usage.model_dump()
except AttributeError:
pass
try:
completion_result["provider_model"] = response.model
except AttributeError:
duration_ms = None
try:
duration_ms = (end_time - start_time).total_seconds() * 1000
except (AttributeError, TypeError):
duration_ms = None
try:
duration_ms = (end_time - start_time).total_seconds() * 1000
except (AttributeError, TypeError):
The Docusaurus sidebar still referenced the deleted
``hackagent.router.adapters.*`` module pages, which made
``npm run build`` fail in CI for PR #388 with
"sidebar document ids do not exist".

Updated to point at the post-refactor modules:

  - ``hackagent/router/agent`` (Agent ABC + exceptions, replaces
    ``adapters/base``)
  - ``hackagent/router/envelope`` (envelope helpers)
  - ``hackagent/router/provider_config`` (AgentType → ProviderConfig)
  - ``hackagent/router/tracking_logger`` (CustomLogger)
  - ``hackagent/router/providers/adk`` (the only remaining gap-filler;
    replaces the old ``adapters/google_adk``)

The chat adapter modules (``adapters/litellm``, ``adapters/openai``,
``adapters/ollama``) are deleted and have no sidebar entry.

Verified locally with ``cd docs && npm run build``.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Ollama-integration job in ``.github/workflows/ci.yml`` and the
slow-integration job in ``.github/workflows/nightly.yml`` were still
collecting tests from ``tests/integration/adapters/`` — a path that
no longer exists after Phase F.3 of #379 moved the ADK integration
test to ``tests/integration/router/test_adk_agent.py``.

Pytest exits with code 4 when given a non-existent collection path,
so the job failed before running any tests. Updated both workflow
files to point at ``tests/integration/router/`` (which holds the new
``test_litellm_dispatch.py`` and the moved ``test_adk_agent.py``).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…in CI

Two fixes prompted by the failing Integration Tests (Ollama) job on
PR #388:

1. ``_ChatRegistration`` now discards any ``api_key`` for OLLAMA
   AgentTypes. The orchestrator's category classifier
   (``hackagent/router/tracking/category_classifier.py``) and the
   attack router factory both forward ``backend.get_api_key()`` — the
   HackAgent backend token — into the adapter's ``api_key`` config.
   With LiteLLM's ``ollama_chat`` provider, that key was being sent as
   ``Authorization: Bearer <hackagent-token>`` to local Ollama,
   visible in the failing job's litellm curl trace. Ollama ignored it
   so the request still succeeded, but the leak is real and would
   be a credential issue against any auth-checking proxy.

2. ``.github/workflows/ci.yml`` and ``nightly.yml`` now pull
   ``gemma3:4b`` alongside ``tinyllama``. The default
   ``category_classifier`` uses ``gemma3:4b``
   (``DEFAULT_CATEGORY_CLASSIFIER_IDENTIFIER``), so the baseline e2e
   test was hitting a 404 on ``/api/show`` for that model. The
   classifier endpoint check is stricter under LiteLLM's
   ``ollama_chat`` provider than the previous direct-HTTP
   ``OllamaAgent`` was, which is why it surfaced now.

New unit test ``test_backend_api_key_is_dropped_for_ollama`` covers
the leak fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@franconicola Nicola Franco (franconicola) temporarily deployed to feat/litellm-unified-adapters-379 - Docs PR #388 May 23, 2026 17:10 — with Render Destroyed
Three related fixes prompted by the failing Integration Tests (Ollama)
job on PR #388:

1. ``test_session_creation`` in tests/integration/router/test_adk_agent.py
   was still calling ``adapter._initialize_session(...)`` — a method
   that lived on the pre-Phase-E.2a ``ADKAgent``. Session management
   moved into the per-instance ``_ADKCustomLLM`` handler; the test
   now uses ``adapter._custom_handler._create_session(...)``.

2. ``test_same_attack_different_frameworks`` and
   ``test_advprefix_with_ollama_judges`` were passing the default
   ``category_classifier`` config (``gemma3:4b``) which is a 4B-param
   model running on CPU-only GitHub runners — 9 judgments blew the
   120s pytest-timeout. Replaced ``_explicit_default_category_classifier``
   (hardcoded to ``gemma3:4b``) with ``_fast_classifier_config`` that
   takes ``ollama_model`` and ``ollama_base_url`` fixtures so the
   classifier reuses whichever small model CI pulls (``tinyllama``).

3. Deleted ``.github/workflows/nightly.yml``. Three @pytest.mark.slow
   tests don't justify a separate cron workflow whose failures land
   on whoever happens to be working that morning. The slow filter
   (``-m "not slow"``) is removed from ``.github/workflows/ci.yml``,
   so all integration tests now run on every PR with a clear failure
   owner (the PR author). Reverted the gemma3:4b pull from ci.yml
   since nothing in the test suite uses it anymore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three integration tests were failing on the post-#379 CI with
``Failed: Timeout (>120.0s) from pytest-timeout``. Verified locally
inside a singularity sandbox running Ollama + tinyllama; with the
two fixes below all three now pass.

1. ``_explicit_default_category_classifier`` in tests/integration/conftest.py
   was hardcoded to ``gemma3:4b``. Made it accept ``model`` /
   ``endpoint`` arguments, and updated ``basic_attack_config``,
   ``advprefix_attack_config``, and
   ``advprefix_attack_config_with_ollama_judges`` to pass
   ``ollama_model`` + ``ollama_base_url`` from existing fixtures. Local
   suites still get the hardcoded gemma3:4b by default; CI gets
   whichever model is pulled (``tinyllama``).

2. Added per-test ``@pytest.mark.timeout(...)`` markers on the three
   heavy LLM-pipeline tests:

     - ``test_same_attack_different_frameworks``: 600s (passed in 130s).
     - ``test_advprefix_with_ollama_judges``: 900s (passed in ~14m).
     - ``test_hackagent_google_adk_baseline_attack``: 600s.

   The global ``--timeout=120`` in pyproject.toml stays for everything
   else — these three just need more head-room because each runs a
   full attack pipeline with LLM-backed judges on CPU.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…outs

Three changes prompted by PR #388 friction (slow tests blocking
commits and CI):

1. ``.pre-commit-config.yaml`` no longer runs integration tests.
   Local pre-commit now executes ``pytest tests/unit/ -n 4`` only
   (~10s instead of ~20 min). Integration coverage stays in GitHub
   Actions. Capped at ``-n 4`` rather than ``-n auto`` so the hook
   works on HPC login nodes (Leonardo advertises 64 logical CPUs but
   enforces per-user thread limits — OpenBLAS hits the cap on a
   bare ``-n auto``).

2. ``.github/workflows/ci.yml`` ``integration-ollama`` job is now a
   2-way matrix (``shard: [fast, slow]``). Each shard runs on its
   own ubuntu-latest runner, so the ~14-minute advprefix test on the
   ``slow`` shard no longer blocks the rest of the suite. Within
   each shard pytest-xdist uses ``-n auto`` (resolves to 4 on the
   runner) and Ollama serves multiple concurrent requests via
   ``OLLAMA_NUM_PARALLEL=4``. Coverage artifacts get the shard name
   appended; the merge job picks both up via the existing
   ``coverage-*`` glob.

3. Added ``@pytest.mark.timeout(900)`` to the two remaining heavy
   ADK tests (``test_hackagent_google_adk_advprefix_attack`` and
   ``test_hackagent_google_adk_with_ollama_judges``) that the earlier
   pass missed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Audit pass to deduplicate and correctly classify the test suite.

1. **Deleted real duplicate**: ``tests/e2e/test_google_adk.py`` ran an
   advprefix attack against a Google ADK target, which is already
   covered by both ``test_hackagent_google_adk_advprefix_attack`` and
   ``test_hackagent_google_adk_with_ollama_judges`` in
   ``tests/integration/router/test_adk_agent.py``. Worse, the e2e
   version swallowed every exception, had no assertions, and used
   nonexistent endpoint URLs (``HACKAGENT_API_BASE_URL/api/generate``,
   ``/api/judge``) — it was a test that could never actually fail.
   Its supporting infrastructure (``tests/e2e/google_adk/``) was only
   referenced by this file and is removed too.

2. **Relocated misclassified integration tests** to ``tests/unit/``.
   These were tagged ``@pytest.mark.integration`` but use only
   in-process mocks / pure-Python — they don't need a backend, an
   Ollama server, or any LLM API. Moving them out of
   ``tests/integration/`` shrinks that suite to actual integration
   coverage and lets the unit suite (which runs on every PR matrix
   entry) cover them:

     - tests/integration/attacks/test_advprefix_evaluation.py
         → tests/unit/attacks/advprefix/test_advprefix_evaluation_extended.py
     - tests/integration/attacks/test_evaluation_step.py
         → tests/unit/attacks/test_evaluation_step.py
     - tests/integration/attacks/flipattack/test_flipattack_*.py (5 files)
         → tests/unit/attacks/flipattack/test_flipattack_*.py
     - tests/integration/storage/test_local_backend_e2e.py
         → tests/unit/server/storage/test_local_backend_e2e.py

   The ``@pytest.mark.integration`` decorator is dropped from the
   moved files. Empty integration subdirectories
   (``tests/integration/storage/``, ``tests/integration/attacks/flipattack/``)
   are removed.

Net effect:

  - Unit suite: +177 tests (1753 → 1930), still <11s with ``-n 4``.
  - Integration suite: ~115 tests left, all genuinely needing a
    real backend / Ollama / OpenAI / ADK server.
  - e2e suite: just the auth smoke test now, unique.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous commit (a3c9b5d) moved
``tests/integration/storage/test_local_backend_e2e.py`` to
``tests/unit/server/storage/`` and removed the now-empty
``tests/integration/storage/`` directory. The ``integration-offline``
job in ``.github/workflows/ci.yml`` still passed that path to pytest,
so the job failed with exit code 5 ("no tests collected").

Path list now contains only ``tests/integration/tui/`` (90 mock-based
TUI integration tests). Updated the job's comment to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 23, 2026

@franconicola Nicola Franco (franconicola) merged commit 3551aee into main May 23, 2026
23 checks passed
@franconicola Nicola Franco (franconicola) deleted the feat/litellm-unified-adapters-379 branch May 23, 2026 19:23
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.

1 participant