fix(providers): add ProviderType.GEMINI to ProviderRegistry.FALLBACK_ORDER #11003
@@ -344,6 +344,14 @@ ensuring data is stored with proper parameter values.
|
||||
|
||||
- **BDD Feature File Tag Coverage** (#9124): Added required `@a2a`, `@session`, and `@cli` Gherkin tags to all A2A, session, and CLI feature files (30 files) to enable tag-based test filtering via `behave --tags=a2a,session,cli`. This restores the ability to selectively run test categories and enables CI to execute targeted test suites without running the full suite.
|
||||
|
||||
- **`ProviderRegistry.FALLBACK_ORDER` missing `ProviderType.GEMINI`** (#10906): Added
|
||||
`ProviderType.GEMINI` to the fallback provider order list so that when only a
|
||||
Gemini API key is configured, the registry correctly selects it as the default
|
||||
provider instead of falling through to no provider. The enum value, capabilities,
|
||||
models, and the `_create_provider_instance()` factory already supported Gemini — this
|
||||
fix closes the gap in the fallback chain. Includes BDD regression scenarios in
|
||||
`features/fallback_gemini_provider.feature`.
|
||||
|
||||
- **Cross-actor subgraph cycle detection reads actor_ref field** (#1431): Fixed
|
||||
`_detect_subgraph_cycles()`, `_map_node()`, and the `compile_actor()` main loop
|
||||
in `src/cleveragents/actor/compiler.py` to read `actor_ref` from the top-level
|
||||
|
||||
@@ -117,3 +117,4 @@ Below are some specific details of individual PR contributions.
|
||||
* HAL 9000 has contributed the data-integrity fix for ProjectRepository (#8179): removed unconditional ``session.rollback()`` calls from exception handlers in ``ProjectRepository.create()`` and ``NamespacedProjectRepository.create/update/delete``, delegating transaction rollback to the Unit of Work outer-layer handler where it belongs.
|
||||
* Jeffrey Phillips Freeman has contributed the `--format`/`-f` flag to `agents session tell` (issue #10466): adds JSON envelope output for machine-readable workflows alongside existing Rich console output, with Behave BDD test coverage verifying all four non-rich format paths (JSON, YAML, plain, table) and the short `-f` flag alias.
|
||||
* HAL 9000 has contributed the Semgrep guard for broad exception suppression (PR #9185 / issue #9103): added two new Semgrep rules (`python-no-suppressed-exception` and `python-no-suppress-exception`) to automate enforcement of error propagation guidelines, integrated Semgrep into `nox -s lint` in audit mode with migration plan for ~337 existing violations, and comprehensive BDD test coverage across all rule patterns and escape hatch scenarios.
|
||||
* HAL 9000 has contributed the `ProviderRegistry.FALLBACK_ORDER` fix (#10906): added the missing `ProviderType.GEMINI` to the fallback provider order list so that when only a Gemini API key is configured, the registry correctly selects it as the default provider. Includes BDD regression scenarios in `features/fallback_gemini_provider.feature`.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
Feature: Fallback order includes ProviderType.GEMINI
|
||||
As a developer
|
||||
I want ProviderType.GEMINI to be included in ProviderRegistry.FALLBACK_ORDER
|
||||
So that Gemini becomes a valid fallback when no higher-priority provider is configured
|
||||
|
||||
@unit @providers @registry @fallback
|
||||
Scenario: GEMINI appears in FALLBACK_ORDER list
|
||||
Given I have the ProviderRegistry class
|
||||
When I check the FALLBACK_ORDER contents
|
||||
Then GEMINI should be present in the fallback order
|
||||
And OPENAI should still be first in the order
|
||||
And ANTHROPIC should still be second in the order
|
||||
|
||||
@unit @providers @registry @fallback
|
||||
Scenario: Gemini-only provider gets selected as default via fallback order
|
||||
Given a registry with only gemini API key set to "sk-gemini-test"
|
||||
And CLEVERAGENTS_DEFAULT_PROVIDER is not set
|
||||
|
|
||||
When I request the default provider type
|
||||
Then the gemini fallback default should be ProviderType "GEMINI"
|
||||
|
||||
@unit @providers @registry @fallback
|
||||
Scenario: Gemini fallback selected after OPENAI, ANTHROPIC, GOOGLE are unconfigured
|
||||
Given a registry with only gemini API key set to "sk-gemini-test"
|
||||
And CLEVERAGENTS_DEFAULT_PROVIDER is not set
|
||||
When I iterate through FALLBACK_ORDER and find the first configured provider
|
||||
Then GEMINI should be the first configured provider found
|
||||
|
||||
@unit @providers @registry @fallback
|
||||
Scenario: Gemini in fallback order does not affect explicit env override
|
||||
Given a registry with only gemini API key set to "sk-gemini-test"
|
||||
And CLEVERAGENTS_DEFAULT_PROVIDER is set to "gemini"
|
||||
|
HAL9001
commented
BLOCKING: Undefined step — The existing step def in This feature file text includes How to fix (choose one):
Automated by CleverAgents Bot **BLOCKING: Undefined step — `CLEVERAGENTS_DEFAULT_PROVIDER env var is set to "gemini"`**
The existing step def in `features/steps/provider_registry_steps.py` is:
```python
@given('CLEVERAGENTS_DEFAULT_PROVIDER is set to "{value}"')
```
This feature file text includes `env var` in the step, which the step def does not have. Behave will treat this as an undefined step, failing the scenario.
**How to fix (choose one):**
- Change this step text to `CLEVERAGENTS_DEFAULT_PROVIDER is set to "gemini"`, **OR**
- Add a new step def matching `CLEVERAGENTS_DEFAULT_PROVIDER env var is set to "{value}"`.
---
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
HAL9001
commented
BLOCKING [REPEAT]: Undefined step — The existing step def is: The Fix (choose one):
Automated by CleverAgents Bot **BLOCKING [REPEAT]: Undefined step — `CLEVERAGENTS_DEFAULT_PROVIDER env var is set to "gemini"`**
The existing step def is:
```python
@given('CLEVERAGENTS_DEFAULT_PROVIDER is set to "{value}"')
```
The `env var` in this step text has no matching definition. This causes Behave to report an `Undefined step` error.
**Fix (choose one):**
- Change step text to `CLEVERAGENTS_DEFAULT_PROVIDER is set to "gemini"`, **OR**
- Add `@given('CLEVERAGENTS_DEFAULT_PROVIDER env var is set to "{value}"')` to the steps file.
---
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
|
||||
When I request the default provider type
|
||||
Then the gemini fallback default should be ProviderType "GEMINI"
|
||||
|
||||
@unit @providers @registry @fallback
|
||||
Scenario: Gemini with all other providers unconfigured returns None only when GEMINI also has no key
|
||||
|
HAL9001
commented
BLOCKING: Undefined step — The existing step def in This step text includes How to fix (choose one):
Automated by CleverAgents Bot **BLOCKING: Undefined step — `CLEVERAGENTS_ALLOW_MOCK_PROVIDER env var is not set`**
The existing step def in `features/steps/provider_registry_steps.py` is:
```python
@given("CLEVERAGENTS_ALLOW_MOCK_PROVIDER is not set")
```
This step text includes `env var`, which the step def omits. Behave will report this as an `Undefined step`.
**How to fix (choose one):**
- Change this step text to `CLEVERAGENTS_ALLOW_MOCK_PROVIDER is not set`, **OR**
- Add a new step def matching `CLEVERAGENTS_ALLOW_MOCK_PROVIDER env var is not set`.
---
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
|
||||
Given a gemini-registry with no API keys configured
|
||||
And CLEVERAGENTS_ALLOW_MOCK_PROVIDER is not set
|
||||
|
HAL9001
commented
BLOCKING [REPEAT]: Undefined step — The existing step def is: The Fix (choose one):
Automated by CleverAgents Bot **BLOCKING [REPEAT]: Undefined step — `CLEVERAGENTS_ALLOW_MOCK_PROVIDER env var is not set`**
The existing step def is:
```python
@given("CLEVERAGENTS_ALLOW_MOCK_PROVIDER is not set")
```
The `env var` in this step text has no matching definition. Behave will skip this scenario as undefined.
**Fix (choose one):**
- Change step text to `CLEVERAGENTS_ALLOW_MOCK_PROVIDER is not set`, **OR**
- Add `@given("CLEVERAGENTS_ALLOW_MOCK_PROVIDER env var is not set")` to the steps file.
---
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
|
||||
When I request the default provider type from a clean registry
|
||||
Then the clean gemini registry default should be None
|
||||
@@ -0,0 +1,149 @@
|
||||
"""Step definitions for fallback_gemini_provider.feature.
|
||||
|
||||
Verifies that ProviderType.GEMINI is present in
|
||||
ProviderRegistry.FALLBACK_ORDER and selected as the default provider when
|
||||
only the Gemini API key is configured.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
HAL9001
commented
BLOCKING: Unused import os. Remove it. BLOCKING: Unused import os. Remove it.
HAL9001
commented
BLOCKING: Unused
Fix: Delete line 10 ( Automated by CleverAgents Bot **BLOCKING: Unused `import os`** — Ruff `F401` lint error
`import os` is imported on this line but never used anywhere in this file. This is one of the root causes of the `CI / lint` failure.
**Fix:** Delete line 10 (`import os`) from this file.
---
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
HAL9001
commented
BLOCKING [REPEAT]: Unused This line was flagged in the previous review and has not been removed. Fix: Delete this line. Automated by CleverAgents Bot **BLOCKING [REPEAT]: Unused `import os` — still present**
This line was flagged in the previous review and has not been removed. `import os` is imported but never referenced anywhere in this file. Ruff reports this as `F401` (unused import), which is one of the root causes of the `CI / lint` failure.
**Fix:** Delete this line.
---
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
|
||||
|
||||
from behave import given, then, when # type: ignore[import-untyped]
|
||||
|
||||
from cleveragents.providers.registry import (
|
||||
ProviderRegistry,
|
||||
ProviderType,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helper
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _make_gemini_settings(
|
||||
openai: str | None = None,
|
||||
anthropic: str | None = None,
|
||||
google: str | None = None,
|
||||
gemini: str | None = None,
|
||||
azure: str | None = None,
|
||||
openrouter: str | None = None,
|
||||
cohere: str | None = None,
|
||||
groq: str | None = None,
|
||||
together: str | None = None,
|
||||
default_provider: str | None = None,
|
||||
) -> object:
|
||||
"""Return a minimal Settings-like mock for BDD steps."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
settings = MagicMock()
|
||||
settings.openai_api_key = openai
|
||||
settings.anthropic_api_key = anthropic
|
||||
settings.google_api_key = google
|
||||
settings.gemini_api_key = gemini
|
||||
settings.azure_api_key = azure
|
||||
settings.openrouter_api_key = openrouter
|
||||
settings.cohere_api_key = cohere
|
||||
settings.groq_api_key = groq
|
||||
settings.together_api_key = together
|
||||
settings.default_provider = default_provider
|
||||
settings.default_model = None
|
||||
return settings
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Given
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@given('a registry with only gemini API key set to "{key}"')
|
||||
def step_gemini_only_registry(context: Any, key: str) -> None:
|
||||
settings = _make_gemini_settings(gemini=key)
|
||||
context.gemini_registry = ProviderRegistry(settings=settings)
|
||||
|
||||
|
||||
@given("a gemini-registry with no API keys configured")
|
||||
def step_no_keys_gemini_registry(context: Any) -> None:
|
||||
context.gemini_registry = ProviderRegistry(settings=_make_gemini_settings())
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# When
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@when("I check the FALLBACK_ORDER contents")
|
||||
def step_check_fallback_order(context: Any) -> None:
|
||||
"""Read the FALLBACK_ORDER class variable."""
|
||||
context.fallback_order = list(ProviderRegistry.FALLBACK_ORDER)
|
||||
|
||||
|
||||
@when("I request the default provider type")
|
||||
def step_request_default_provider_type(context: Any) -> None:
|
||||
result = context.gemini_registry.get_default_provider_type()
|
||||
context.gemini_default = result
|
||||
|
||||
|
||||
@when("I iterate through FALLBACK_ORDER and find the first configured provider")
|
||||
def step_iterate_fallback_order(context: Any) -> None:
|
||||
"""Manually walk FALLBACK_ORDER to verify GEMINI is checked."""
|
||||
found = None
|
||||
for pt in ProviderRegistry.FALLBACK_ORDER:
|
||||
if context.gemini_registry.is_provider_configured(pt):
|
||||
found = pt
|
||||
break
|
||||
context.fallback_iteration_result = found
|
||||
|
||||
|
||||
@when("I request the default provider type from a clean registry")
|
||||
def step_request_default_from_clean(context: Any) -> None:
|
||||
result = context.gemini_registry.get_default_provider_type()
|
||||
context.clean_default = result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Then
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@then("GEMINI should be present in the fallback order")
|
||||
def step_gemini_in_fallback_order(context: Any) -> None:
|
||||
assert ProviderType.GEMINI in context.fallback_order, (
|
||||
f"Expected GEMINI in FALLBACK_ORDER={context.fallback_order}"
|
||||
)
|
||||
|
||||
|
||||
@then("OPENAI should still be first in the order")
|
||||
def step_openai_first(context: Any) -> None:
|
||||
assert context.fallback_order[0] == ProviderType.OPENAI, (
|
||||
f"Expected OPENAI first, got {context.fallback_order[0]}"
|
||||
)
|
||||
|
||||
|
||||
@then("ANTHROPIC should still be second in the order")
|
||||
def step_anthropic_second(context: Any) -> None:
|
||||
assert context.fallback_order[1] == ProviderType.ANTHROPIC, (
|
||||
f"Expected ANTHROPIC second, got {context.fallback_order[1]}"
|
||||
)
|
||||
|
||||
|
||||
@then('the gemini fallback default should be ProviderType "GEMINI"')
|
||||
def step_result_is_gemini(context: Any) -> None:
|
||||
assert context.gemini_default == ProviderType.GEMINI, (
|
||||
f"Expected GEMINI, got {context.gemini_default!r}"
|
||||
)
|
||||
|
||||
|
||||
@then("GEMINI should be the first configured provider found")
|
||||
def step_gemini_first_configured(context: Any) -> None:
|
||||
assert context.fallback_iteration_result == ProviderType.GEMINI, (
|
||||
f"Expected GEMINI as first found, got {context.fallback_iteration_result!r}"
|
||||
)
|
||||
|
||||
|
||||
@then("the clean gemini registry default should be None")
|
||||
def step_result_is_none(context: Any) -> None:
|
||||
assert context.clean_default is None, (
|
||||
f"Expected None, got {context.clean_default!r}"
|
||||
)
|
||||
BLOCKING: Undefined step —
CLEVERAGENTS_DEFAULT_PROVIDER env var is not setThis
Andstep on this line (and on the near-identical scenario at line 24) has no matching step definition. The existing step def infeatures/steps/provider_registry_steps.pyis:Behave matches step text literally. Because this feature file includes
env varin the step text and the step def does not, Behave will report anUndefined steperror and skip the scenario — causingCI / unit_teststo fail.How to fix (choose one):
CLEVERAGENTS_DEFAULT_PROVIDER is not set(matches the existing step def), OR@given("CLEVERAGENTS_DEFAULT_PROVIDER env var is not set")in the steps file.Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
BLOCKING [REPEAT]: Undefined step —
CLEVERAGENTS_DEFAULT_PROVIDER env var is not setThis step (and a near-identical one at line 31) has no matching step definition. The existing step def in
provider_registry_steps.pyis:Behave matches step text literally — the inclusion of
env varmakes this a different (undefined) step, causingCI / unit_teststo fail.The new
fallback_gemini_provider_steps.pyalso has no definition for this variant.Fix (choose one):
CLEVERAGENTS_DEFAULT_PROVIDER is not set(uses the existing step def), OR@given("CLEVERAGENTS_DEFAULT_PROVIDER env var is not set")tofallback_gemini_provider_steps.py.Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker