Skip to content

feat: add FastestStrategy routing + vendor-agnostic cleanup#140

Merged
Aureliolo merged 3 commits intomainfrom
feat/fastest-strategy-vendor-cleanup
Mar 6, 2026
Merged

feat: add FastestStrategy routing + vendor-agnostic cleanup#140
Aureliolo merged 3 commits intomainfrom
feat/fastest-strategy-vendor-cleanup

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • FastestStrategy: New routing strategy that selects the lowest-latency model within budget, falling back to cheapest when no latency data is available
  • estimated_latency_ms field: Added to ProviderModelConfig and ResolvedModel with gt=0, le=300_000 bounds
  • all_models_sorted_by_latency(): New method on ModelResolver for latency-ordered model retrieval
  • Helper extraction: Moved ~336 lines of private helper functions from strategies.py into _strategy_helpers.py to stay under the 800-line file limit
  • Vendor-agnostic cleanup: Replaced all vendor-specific names (OpenAI, GPT) with generic equivalents across src/ docstrings and comments
  • DESIGN_SPEC.md: Updated strategy count from 5 to 6

closes #139

Files changed (13)

Area Files
Routing strategies.py, _strategy_helpers.py (new), resolver.py, models.py
Config schema.py
Vendor cleanup capabilities.py, mappers.py, litellm_driver.py, config.py
Docs DESIGN_SPEC.md
Tests test_strategies.py, test_models.py, test_schema.py

Test plan

  • All 1854 tests pass (pytest -n auto)
  • Coverage at 95.04% (threshold: 80%)
  • mypy clean (211 source files)
  • ruff check + format clean
  • New tests: test_task_type_rule_skipped_when_over_budget, test_budget_exceeded_with_latency_models_only, test_estimated_latency_ms_exceeds_upper_bound (×2)

Review coverage

Pre-reviewed by 10 agents: code-reviewer, python-reviewer, pr-test-analyzer, silent-failure-hunter, comment-analyzer, type-design-analyzer, logging-audit, resilience-audit, security-reviewer, docs-consistency

16 findings triaged → 15 implemented, 1 deferred (no-op)

🤖 Generated with Claude Code

Aureliolo and others added 2 commits March 6, 2026 16:27
Add FastestStrategy that selects the model with lowest
estimated_latency_ms, falling back to cheapest when no latency
data is available. Includes estimated_latency_ms field on
ProviderModelConfig and ResolvedModel, all_models_sorted_by_latency()
on ModelResolver, and full test coverage.

Also removes all vendor-specific names (Anthropic, Claude, Opus,
Sonnet, Haiku) from source code, tests, and documentation. Replaced
with generic names (example-provider, example-large-001, large/
medium/small). Added vendor-agnostic rule to CLAUDE.md to prevent
future vendor coupling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add FastestStrategy (selects lowest-latency model within budget,
  falls back to cheapest when no latency data available)
- Add estimated_latency_ms field to ProviderModelConfig and ResolvedModel
  with gt=0, le=300_000 bounds
- Add all_models_sorted_by_latency() to ModelResolver
- Extract _strategy_helpers.py from strategies.py (800-line limit)
- Replace vendor-specific names (OpenAI, GPT) with generic equivalents
  across src/ docstrings and comments
- Update DESIGN_SPEC.md strategy count from 5 to 6

Pre-reviewed by 10 agents, 15 findings addressed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 6, 2026 15:52
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 6, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the model routing capabilities by introducing a new FastestStrategy that prioritizes low-latency models, complemented by the addition of latency metadata to model configurations. Beyond this new feature, a substantial effort was made to refactor internal routing helpers and standardize naming conventions across the project, moving away from vendor-specific terms to a more generic and extensible vocabulary. These changes collectively improve the system's flexibility, performance optimization options, and maintainability.

Highlights

  • New Routing Strategy: FastestStrategy: Introduced a new model routing strategy that prioritizes selecting the lowest-latency model available within a specified budget. If no latency data is available, it intelligently falls back to the cheapest model, assuming lower-cost models are generally faster.
  • Latency Metadata for Models: Added an estimated_latency_ms field to ProviderModelConfig and ResolvedModel to store the median latency of models, with validation ensuring values are positive and within a reasonable range (0 to 300,000 ms).
  • Routing Logic Refactoring: Extracted approximately 336 lines of private helper functions from strategies.py into a new dedicated module, _strategy_helpers.py, to improve modularity and maintainability of the routing logic.
  • Comprehensive Vendor-Agnostic Cleanup: Performed a widespread cleanup across the codebase, replacing all vendor-specific names (e.g., Anthropic, OpenAI, Claude, GPT) with generic equivalents (e.g., example-provider, large, medium, small) in docstrings, comments, configuration examples, and documentation files like DESIGN_SPEC.md and README.md.
  • Updated Model Resolver Capabilities: Implemented a new method all_models_sorted_by_latency() in ModelResolver to retrieve models ordered by their estimated latency, which is crucial for the new FastestStrategy.
Changelog
  • CLAUDE.md
    • Updated vendor-agnostic guidelines to emphasize generic naming conventions everywhere.
  • DESIGN_SPEC.md
    • Updated the description of 'Provider Agnostic' to be more generic.
    • Replaced vendor-specific model names (e.g., 'anthropic', 'claude-sonnet-4-6', 'opus', 'haiku') with generic examples (e.g., 'example-provider', 'example-medium-001', 'large', 'small') in configuration examples and tables.
    • Updated the count of model routing strategies from 5 to 6 to reflect the addition of FastestStrategy.
  • README.md
    • Updated the 'Multi-Provider' feature description to use more generic language.
  • src/ai_company/budget/config.py
    • Updated comments to reflect generic model naming conventions (e.g., 'large' instead of 'gpt-4').
  • src/ai_company/config/schema.py
    • Added estimated_latency_ms field to ProviderModelConfig with validation for positive values up to 300,000 ms.
    • Updated example model identifiers in docstrings to use generic names.
  • src/ai_company/core/agent.py
    • Updated example provider and model names in docstrings to be vendor-agnostic.
  • src/ai_company/providers/init.py
    • Imported STRATEGY_NAME_FASTEST and FastestStrategy to expose the new routing strategy.
  • src/ai_company/providers/capabilities.py
    • Updated example model IDs and provider names in docstrings to generic equivalents.
  • src/ai_company/providers/drivers/init.py
    • Generalized docstring by removing specific mentions of 'native Anthropic SDK'.
  • src/ai_company/providers/drivers/litellm_driver.py
    • Updated docstrings to replace 'OpenAI-compatible' with 'chat-completion' and removed vendor-specific model examples.
    • Updated example provider and model names in docstrings to generic equivalents.
  • src/ai_company/providers/drivers/mappers.py
    • Replaced 'OpenAI-compatible' with 'chat-completion' in docstrings for message and tool mapping functions.
  • src/ai_company/providers/models.py
    • Added estimated_latency_ms field to ResolvedModel with validation.
    • Updated docstring for ToolDefinition to remove vendor-specific provider examples.
    • Updated RoutingRequest docstring to include FastestStrategy in the list of strategies.
  • src/ai_company/providers/registry.py
    • Updated example provider and model names in docstrings to generic equivalents.
  • src/ai_company/providers/routing/init.py
    • Imported STRATEGY_NAME_FASTEST and FastestStrategy for routing module exposure.
  • src/ai_company/providers/routing/_strategy_helpers.py
    • Added new file to house private helper functions extracted from strategies.py.
    • Implemented helper functions for candidate resolution, fallback logic, budget checking, and rule matching.
    • Included _fastest_within_budget logic to select models based on latency and budget.
  • src/ai_company/providers/routing/resolver.py
    • Included estimated_latency_ms when creating ResolvedModel instances from configuration.
    • Added all_models_sorted_by_latency() method to retrieve models ordered by their estimated latency.
  • src/ai_company/providers/routing/strategies.py
    • Imported shared helper functions from _strategy_helpers.py.
    • Defined STRATEGY_NAME_FASTEST constant.
    • Implemented the FastestStrategy class, which selects models based on latency and budget, with task-type rule prioritization.
    • Updated STRATEGY_MAP to include the new FastestStrategy.
    • Removed duplicated helper functions, delegating to the new _strategy_helpers.py module.
  • tests/integration/providers/conftest.py
    • Refactored make_anthropic_config to make_provider_config and updated it to use generic provider and model names.
    • Updated OpenRouter model aliases to generic names.
  • tests/integration/providers/test_anthropic_pipeline.py
    • Renamed test file to reflect generic provider testing.
    • Updated test cases to use generic provider and model names (e.g., 'example-provider', 'medium') instead of 'anthropic' and 'sonnet'.
  • tests/integration/providers/test_error_scenarios.py
    • Updated test cases to use generic provider and model names (e.g., 'example-provider', 'medium') instead of 'anthropic' and 'sonnet' in error contexts and assertions.
  • tests/integration/providers/test_openrouter_pipeline.py
    • Updated test cases to use generic model aliases (e.g., 'or-medium') instead of 'or-sonnet'.
  • tests/integration/providers/test_tool_calling_pipeline.py
    • Updated test cases to use generic provider and model names (e.g., 'example-provider', 'medium') instead of 'anthropic' and 'sonnet'.
  • tests/unit/budget/conftest.py
    • Updated downgrade_map examples to use generic model aliases ('large', 'medium', 'small').
    • Updated CostRecord example to use a generic provider name ('example-provider').
  • tests/unit/budget/test_config.py
    • Updated test cases for AutoDowngradeConfig to use generic model aliases ('large', 'medium', 'small').
  • tests/unit/budget/test_cost_record.py
    • Updated test cases to use a generic provider name ('example-provider').
  • tests/unit/config/conftest.py
    • Updated example YAML configurations to use generic provider and model names (e.g., 'example-provider', 'medium') and environment variables.
  • tests/unit/config/test_loader.py
    • Updated test cases to assert against generic provider names (e.g., 'example-provider') in loaded configurations.
  • tests/unit/config/test_schema.py
    • Updated test cases for ProviderModelConfig to use generic model aliases ('medium').
    • Added new test cases for estimated_latency_ms validation in ProviderModelConfig.
    • Updated test cases for RoutingRuleConfig and RootConfig to use generic model aliases and provider names.
  • tests/unit/core/conftest.py
    • Updated sample_model_config to use generic model IDs and fallback model names ('test-model-medium-001', 'test-model-small').
  • tests/unit/core/test_agent.py
    • Updated test cases to assert against generic model IDs ('test-model-medium-001').
  • tests/unit/providers/drivers/conftest.py
    • Updated make_provider_config to use generic model aliases ('medium', 'small').
  • tests/unit/providers/drivers/test_litellm_driver.py
    • Updated test cases to use generic provider and model names (e.g., 'example-provider', 'medium', 'small') in driver instantiation, completion calls, and assertions.
    • Updated error contexts to reflect generic provider names.
  • tests/unit/providers/routing/conftest.py
    • Updated ResolvedModelFactory to use a generic model ID ('test-medium-001') and added estimated_latency_ms.
    • Updated ProviderModelConfig fixtures (HAIKU_MODEL, SONNET_MODEL, OPUS_MODEL renamed to SMALL_MODEL, MEDIUM_MODEL, LARGE_MODEL) to include estimated_latency_ms and use generic names.
  • tests/unit/providers/routing/test_models.py
    • Updated test cases for ResolvedModel to use generic model IDs ('test-medium-001').
    • Added new test cases for estimated_latency_ms validation in ResolvedModel.
    • Updated RoutingRequest test cases to use generic model overrides ('medium').
  • tests/unit/providers/routing/test_resolver.py
    • Updated test cases to use generic model IDs and aliases (e.g., 'test-medium-001', 'small', 'large') for model resolution and sorting.
    • Added new test cases for all_models_sorted_by_latency() method, including scenarios with None latency values.
  • tests/unit/providers/routing/test_router.py
    • Updated test cases to assert against generic model IDs ('test-large-001').
  • tests/unit/providers/routing/test_strategies.py
    • Updated TestRoutingStrategyProtocol to include FastestStrategy.
    • Updated STRATEGY_MAP assertions to include 'fastest' strategy name.
    • Updated test cases for ManualStrategy to use generic model IDs and aliases ('test-medium-001', 'test-large-001').
    • Updated test cases for RoleBasedStrategy to reflect generic model tiers ('medium', 'small') and fallback behavior.
    • Added comprehensive test cases for the new FastestStrategy, covering model selection, budget adherence, task-type rule prioritization, and handling of missing latency data.
    • Updated test cases for SmartStrategy and fallback scenarios to use generic model aliases ('large', 'small').
  • tests/unit/providers/test_errors.py
    • Updated error context examples to use generic provider and model names (e.g., 'example-provider', 'medium', 'test-provider', 'test-model').
  • tests/unit/providers/test_registry.py
    • Updated test cases for ProviderRegistry to use generic provider names (e.g., 'example-provider', 'provider-c', 'provider-b').
  • tests/unit/templates/conftest.py
    • Updated example YAML templates to use generic model names ('medium').
  • tests/unit/templates/test_renderer.py
    • Updated example YAML for template rendering tests to use generic model names ('medium').
  • tests/unit/templates/test_schema.py
    • Updated test cases for AgentTemplateConfig to use generic model names ('large').
Activity
  • Pre-reviewed by 10 agents: code-reviewer, python-reviewer, pr-test-analyzer, silent-failure-hunter, comment-analyzer, type-design-analyzer, logging-audit, resilience-audit, security-reviewer, docs-consistency.
  • 16 findings triaged, with 15 implemented and 1 deferred (no-op).
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 6, 2026

Greptile Summary

This PR introduces FastestStrategy as the 6th routing strategy, selecting the lowest-latency model within budget (falling back to cheapest when no estimated_latency_ms data is available), and extracts ~336 lines of shared routing helpers from strategies.py into a new _strategy_helpers.py module to stay under the 800-line file limit. It also adds estimated_latency_ms to both ProviderModelConfig and ResolvedModel, propagates it through ModelResolver.from_config, and exposes all_models_sorted_by_latency() for latency-ordered retrieval. All vendor-specific names (Anthropic, OpenAI, Claude, GPT, etc.) across src/ docstrings, comments, and config examples are replaced with generic equivalents.

Key changes:

  • FastestStrategy follows the same task-type rule → budget-aware fallback pattern as CostAwareStrategy, with latency as the primary sort key and cost as a proxy when no latency data exists
  • _strategy_helpers.py cleanly separates shared resolution helpers (_try_resolve_with_fallback, _cheapest_within_budget, _fastest_within_budget, etc.) from strategy class logic
  • estimated_latency_ms: int | None is validated with gt=0, le=300_000 bounds on both the config and domain models
  • Test file test_anthropic_pipeline.py was renamed to test_provider_pipeline.py for vendor-agnostic cleanup

Issues found:

  • tests/integration/providers/test_openrouter_pipeline.py still carries the "openrouter" vendor name in its filename and in registry.get("openrouter") calls, which is inconsistent with the vendor-agnostic rule now enforced by CLAUDE.md and applied to test_provider_pipeline.py in this same PR.

Confidence Score: 4/5

  • PR is safe to merge; one minor style-level finding with no impact on correctness.
  • The core logic is correct, well-tested (new TestFastestStrategy class covers budget, latency ordering, no-data fallback, and task-rule skipping), and cleanly integrated. The single finding is a non-blocking style issue: incomplete vendor-name cleanup in one test filename that should be consistent with changes made to test_provider_pipeline.py in the same PR.
  • tests/integration/providers/test_openrouter_pipeline.py (vendor name in filename and registry.get() calls)

Sequence Diagram

sequenceDiagram
    participant Caller
    participant FastestStrategy
    participant _strategy_helpers
    participant ModelResolver

    Caller->>FastestStrategy: select(request, config, resolver)

    FastestStrategy->>_strategy_helpers: _try_task_type_rules(request, config, resolver)
    _strategy_helpers->>ModelResolver: resolve_safe(rule.preferred_model)
    ModelResolver-->>_strategy_helpers: ResolvedModel | None
    _strategy_helpers-->>FastestStrategy: RoutingDecision | None

    alt task-type rule matched AND within budget
        FastestStrategy-->>Caller: RoutingDecision (task-type rule)
    else no rule matched OR over budget
        FastestStrategy->>_strategy_helpers: _fastest_within_budget(resolver, remaining_budget)
        _strategy_helpers->>ModelResolver: all_models_sorted_by_latency()
        ModelResolver-->>_strategy_helpers: tuple[ResolvedModel, ...]

        alt some models have estimated_latency_ms
            _strategy_helpers->>_strategy_helpers: filter models_with_latency
            note over _strategy_helpers: iterate sorted by latency asc,<br/>pick first within budget
            _strategy_helpers-->>FastestStrategy: (fastest_model, budget_exceeded)
        else no latency data at all
            _strategy_helpers->>_strategy_helpers: _cheapest_within_budget(resolver, budget)
            note over _strategy_helpers: cost used as proxy for speed
            _strategy_helpers-->>FastestStrategy: (cheapest_model, budget_exceeded)
        end

        FastestStrategy-->>Caller: RoutingDecision (fastest | cheapest-proxy)
    end
Loading

Comments Outside Diff (1)

  1. tests/integration/providers/test_openrouter_pipeline.py, line 1-20 (link)

    Vendor name in test filename and provider key

    The updated CLAUDE.md rule states:

    Vendor-agnostic everywhere: NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples.

    The filename test_openrouter_pipeline.py contains the vendor name "openrouter". Additionally, the test code calls registry.get("openrouter") on lines 31, 49, 67, 85, and 109.

    This is the same pattern that was addressed for test_anthropic_pipeline.pytest_provider_pipeline.py in this PR. For consistency, consider:

    1. Renaming this file to something vendor-agnostic (e.g., test_routing_aggregator_pipeline.py or similar)
    2. Making make_openrouter_config() return a generic provider key instead of "openrouter", so the fixture name itself is the only place the vendor is referenced in test code

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Context Used: Rule from dashboard - CLAUDE.md (source)

Last reviewed commit: a945fc3

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 6, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 004926d7-c5bd-426c-8299-5275e8cd55c3

📥 Commits

Reviewing files that changed from the base of the PR and between aebeb30 and a945fc3.

📒 Files selected for processing (10)
  • CLAUDE.md
  • DESIGN_SPEC.md
  • src/ai_company/providers/registry.py
  • src/ai_company/providers/routing/_strategy_helpers.py
  • src/ai_company/providers/routing/strategies.py
  • tests/integration/providers/conftest.py
  • tests/integration/providers/test_provider_pipeline.py
  • tests/unit/providers/drivers/conftest.py
  • tests/unit/providers/routing/test_router.py
  • tests/unit/providers/routing/test_strategies.py

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added latency-aware model selection with estimated latency tracking (milliseconds).
    • Introduced "Fastest" routing strategy to prioritize models by response latency.
    • Added model sorting utility for latency-based ordering.
  • Documentation

    • Updated documentation and examples to use generic vendor-agnostic naming conventions.
    • Refined "vendor-agnostic everywhere" policy for configuration and test examples.
  • Refactoring

    • Reorganized routing strategy implementations with shared helper utilities.
    • Improved routing logic structure for strategy variants.

Walkthrough

This PR introduces the FastestStrategy routing strategy that selects the lowest-latency model within budget constraints, backed by a new estimated_latency_ms field on ProviderModelConfig and ResolvedModel. Concurrently, it systematically replaces all vendor-specific names (Anthropic, Claude, Opus, Sonnet, Haiku) with generic placeholders (example-provider, large/medium/small) across source code, tests, and documentation to enforce vendor-agnostic naming throughout the project.

Changes

Cohort / File(s) Summary
Latency field introduction
src/ai_company/config/schema.py, src/ai_company/providers/routing/models.py
Added estimated_latency_ms: int | None field with validation (gt=0, le=300000) to ProviderModelConfig and ResolvedModel classes.
Routing resolver updates
src/ai_company/providers/routing/resolver.py
Wired estimated_latency_ms from config into ResolvedModel constructor; added all_models_sorted_by_latency() method to return models sorted by latency ascending with None values last.
Routing strategy helpers
src/ai_company/providers/routing/_strategy_helpers.py
New module with 361 lines of shared helper functions for strategy implementations: fallback resolution (_try_resolve_with_fallback, _walk_fallback_chain), budget enforcement (_within_budget, _cheapest_within_budget, _fastest_within_budget), and decision pathways for task-type/role/seniority rules with logging and error handling.
FastestStrategy implementation
src/ai_company/providers/routing/strategies.py
Added FastestStrategy class and STRATEGY_NAME_FASTEST constant; refactored existing helpers into _strategy_helpers.py; strategy prioritizes task-type rules, then selects fastest model within budget, falling back to cheapest when latency data unavailable.
Routing exports
src/ai_company/providers/routing/__init__.py, src/ai_company/providers/__init__.py
Re-exported STRATEGY_NAME_FASTEST constant and FastestStrategy class through public API.
Vendor-agnostic docstring updates
src/ai_company/core/agent.py, src/ai_company/providers/capabilities.py, src/ai_company/providers/drivers/litellm_driver.py, src/ai_company/providers/drivers/mappers.py, src/ai_company/providers/models.py, src/ai_company/providers/registry.py, src/ai_company/providers/drivers/__init__.py, src/ai_company/budget/config.py
Updated docstring examples and terminology: replaced vendor names (Anthropic, Claude) with generic placeholders (example-provider); simplified terminology from OpenAI-compatible to chat-completion format; removed vendor-specific SDK references.
Documentation updates
CLAUDE.md, DESIGN_SPEC.md, README.md
Enforced vendor-agnostic naming policy; updated provider/model examples from Anthropic/Sonnet/Haiku to example-provider/medium/small; broadened README feature description from vendor-specific to generic LLM support.
Integration test fixtures
tests/integration/providers/conftest.py
Renamed factory from make_anthropic_config to make_provider_config; updated provider key from "anthropic" to "example-provider"; updated model aliases from "sonnet"/"haiku" to "medium"/"small".
Integration test data and assertions
tests/integration/providers/test_error_scenarios.py, tests/integration/providers/test_provider_pipeline.py, tests/integration/providers/test_openrouter_pipeline.py, tests/integration/providers/test_tool_calling_pipeline.py
Updated provider/model references and test expectations from vendor-specific names to generic placeholders throughout error mapping, streaming, and tool-calling scenarios.
Unit test fixtures and data
tests/unit/budget/conftest.py, tests/unit/config/conftest.py, tests/unit/core/conftest.py, tests/unit/templates/conftest.py, tests/unit/providers/drivers/conftest.py, tests/unit/providers/routing/conftest.py
Updated model fixture names and aliases; renamed constants (OPUS_MODEL → LARGE_MODEL, SONNET_MODEL → MEDIUM_MODEL, HAIKU_MODEL → SMALL_MODEL); added estimated_latency_ms values to routing test fixtures.
Unit test validation and expectations
tests/unit/budget/test_config.py, tests/unit/budget/test_cost_record.py, tests/unit/config/test_loader.py, tests/unit/config/test_schema.py, tests/unit/core/test_agent.py, tests/unit/providers/drivers/test_litellm_driver.py, tests/unit/providers/routing/test_models.py, tests/unit/providers/routing/test_resolver.py, tests/unit/providers/test_registry.py, tests/unit/providers/test_errors.py, tests/unit/templates/test_renderer.py, tests/unit/templates/test_schema.py
Updated test expectations to use generic names; added comprehensive validation tests for estimated_latency_ms field (default None, valid values, boundary violations); added new latency-sorting tests.
FastestStrategy test coverage
tests/unit/providers/routing/test_strategies.py, tests/unit/providers/routing/test_router.py
Expanded test suite with 263+ new lines covering FastestStrategy protocol conformance, task-type rule priority, budget-aware selection, latency fallback behavior, mixed latency data scenarios, and edge cases.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant RoutingRequest
    participant FastestStrategy
    participant StrategyHelpers as _strategy_helpers
    participant ModelResolver
    participant ProviderConfig

    Client->>RoutingRequest: create routing request (task_type, role, budget)
    Client->>FastestStrategy: select(request, config, resolver)
    
    FastestStrategy->>StrategyHelpers: _try_task_type_rules(request, ...)
    alt task_type rule found
        StrategyHelpers->>ModelResolver: resolve model from task_type rule
        ModelResolver->>ProviderConfig: fetch ProviderModelConfig
        StrategyHelpers->>StrategyHelpers: _within_budget(model, remaining_budget)
        alt within budget
            StrategyHelpers-->>FastestStrategy: RoutingDecision (rule match)
        else budget exceeded
            StrategyHelpers->>StrategyHelpers: _fastest_within_budget(resolver, ...)
            StrategyHelpers-->>FastestStrategy: RoutingDecision (fastest fallback)
        end
    else no task_type rule
        FastestStrategy->>StrategyHelpers: _fastest_within_budget(resolver, budget)
        StrategyHelpers->>ModelResolver: all_models_sorted_by_latency()
        ModelResolver-->>StrategyHelpers: models sorted by estimated_latency_ms
        alt models have latency data
            StrategyHelpers->>StrategyHelpers: select fastest within budget
            StrategyHelpers-->>FastestStrategy: ResolvedModel (fastest)
        else no latency data
            StrategyHelpers->>StrategyHelpers: _cheapest_within_budget(resolver, budget)
            StrategyHelpers-->>FastestStrategy: ResolvedModel (cheapest fallback)
        end
    end
    
    FastestStrategy-->>Client: RoutingDecision (model, strategy="fastest", reason)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

The review complexity spans multiple dimensions: the new _strategy_helpers.py module introduces 361 lines of non-trivial logic with fallback chains, budget constraints, and error handling that requires careful trace-through; the FastestStrategy implementation interacts with this logic in budget-aware decision flows; the new estimated_latency_ms field requires validation of constraints across three related classes; and while vendor-name replacements are repetitive, they span 40 files and must be verified for completeness to avoid future regressions. The heterogeneous mix of new feature logic, field additions, and widespread naming changes demands separate reasoning for different sections.

Possibly related PRs

  • PR #140 — Identical feature implementation: both add FastestStrategy, estimated_latency_ms field, all_models_sorted_by_latency(), and _strategy_helpers.py module with the same vendor-agnostic renaming strategy.
  • PR #99 — Foundational routing subsystem that this PR extends: introduces base RoutingStrategy protocol and initial strategy implementations that FastestStrategy now conforms to and integrates with.
  • PR #75 — Shares code-level changes to ProviderModelConfig in src/ai_company/config/schema.py; both PRs add fields to the same class definition.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.13% which is insufficient. The required threshold is 100.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly summarizes the two main features added: FastestStrategy routing and vendor-agnostic cleanup, matching the primary objectives of the PR.
Description check ✅ Passed The description comprehensively explains FastestStrategy implementation, latency field addition, vendor-agnostic cleanup, test coverage, and references issue #139 which aligns with the changeset.
Linked Issues check ✅ Passed The PR implements all FastestStrategy success criteria: estimated_latency_ms fields with proper bounds, all_models_sorted_by_latency() method, FastestStrategy class with budget-aware selection, proper exports, and DESIGN_SPEC updates. Vendor-agnostic cleanup completely replaces Anthropic/Claude/Opus/Sonnet/Haiku with generic equivalents across src/ and tests. Quality gates met: 1854 tests pass, 95.04% coverage, mypy and ruff clean.
Out of Scope Changes check ✅ Passed All changes align with PR objectives: routing strategy implementation, latency field additions, vendor cleanup across documentation and tests, helper function extraction. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/fastest-strategy-vendor-cleanup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This is an excellent pull request that accomplishes three major goals effectively: it introduces the new FastestStrategy for model routing, refactors routing helpers for better maintainability, and performs a comprehensive vendor-agnostic cleanup across the codebase. The new strategy is well-designed, handling edge cases like missing latency data gracefully. The refactoring of strategies.py into _strategy_helpers.py significantly improves code organization. The vendor-agnostic cleanup is thorough and consistently applied, which is a great step for the project's neutrality. The test coverage for the new functionality is also impressive. I have a couple of minor suggestions to improve logging consistency.

Comment on lines +190 to +194
logger.warning(
ROUTING_BUDGET_EXCEEDED,
remaining_budget=remaining_budget,
cheapest_cost=cheapest_cost,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

For consistency in structured logging, consider using a generic key like model_cost for the cost parameter. This function uses cheapest_cost, while _fastest_within_budget uses fastest_cost. Standardizing on a single key simplifies log querying and analysis for the ROUTING_BUDGET_EXCEEDED event.

Suggested change
logger.warning(
ROUTING_BUDGET_EXCEEDED,
remaining_budget=remaining_budget,
cheapest_cost=cheapest_cost,
)
logger.warning(
ROUTING_BUDGET_EXCEEDED,
remaining_budget=remaining_budget,
model_cost=cheapest_cost,
)

Comment on lines +247 to +251
logger.warning(
ROUTING_BUDGET_EXCEEDED,
remaining_budget=remaining_budget,
fastest_cost=fastest_cost,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

To align with the suggestion for _cheapest_within_budget, please use the generic key model_cost here as well. This will ensure that all logs for the ROUTING_BUDGET_EXCEEDED event have a consistent structure, improving maintainability.

Suggested change
logger.warning(
ROUTING_BUDGET_EXCEEDED,
remaining_budget=remaining_budget,
fastest_cost=fastest_cost,
)
logger.warning(
ROUTING_BUDGET_EXCEEDED,
remaining_budget=remaining_budget,
model_cost=fastest_cost,
)

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new latency-aware routing strategy and introduces an estimated_latency_ms model attribute end-to-end, while also continuing the repo-wide vendor-agnostic naming cleanup across code, tests, and docs.

Changes:

  • Add FastestStrategy routing strategy and register it in routing strategy maps/exports.
  • Add estimated_latency_ms to ProviderModelConfig and ResolvedModel, wire it through ModelResolver, and add all_models_sorted_by_latency().
  • Refactor routing helpers into _strategy_helpers.py and update tests/docs to use vendor-neutral provider/model naming.

Reviewed changes

Copilot reviewed 43 out of 43 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/ai_company/config/schema.py Adds estimated_latency_ms to provider model configuration with validation bounds.
src/ai_company/providers/routing/models.py Adds estimated_latency_ms to ResolvedModel; updates routing request docs to include FastestStrategy.
src/ai_company/providers/routing/resolver.py Wires latency from config into resolved models and adds all_models_sorted_by_latency().
src/ai_company/providers/routing/_strategy_helpers.py Extracts shared strategy helper functions and adds fastest-within-budget selection helper.
src/ai_company/providers/routing/strategies.py Introduces FastestStrategy, registers it, and imports extracted helpers.
src/ai_company/providers/routing/init.py Re-exports FastestStrategy and STRATEGY_NAME_FASTEST.
src/ai_company/providers/init.py Re-exports FastestStrategy and strategy name constant at providers package level.
src/ai_company/providers/registry.py Updates examples/docstrings to vendor-neutral provider/model naming.
src/ai_company/providers/models.py Removes vendor-specific wording from tool schema docstring.
src/ai_company/providers/drivers/mappers.py Updates docstrings/comments to vendor-neutral “chat-completion” terminology.
src/ai_company/providers/drivers/litellm_driver.py Updates driver docstrings/examples to vendor-neutral naming.
src/ai_company/providers/drivers/init.py Updates driver module docstring to remove vendor-specific mention.
src/ai_company/providers/capabilities.py Updates example provider/model identifiers to vendor-neutral naming.
src/ai_company/core/agent.py Updates model config docstring examples to vendor-neutral naming.
src/ai_company/budget/config.py Updates downgrade-map normalization docstring example to vendor-neutral aliases.
tests/unit/providers/routing/conftest.py Updates canonical test models to small/medium/large and adds latency values.
tests/unit/providers/routing/test_strategies.py Adds FastestStrategy tests and updates existing routing tests for new alias/model naming.
tests/unit/providers/routing/test_resolver.py Adds latency sorting tests and updates resolver tests for renamed model IDs/aliases.
tests/unit/providers/routing/test_models.py Adds ResolvedModel.estimated_latency_ms validation tests and updates fixtures.
tests/unit/providers/routing/test_router.py Updates expected resolved model IDs for renamed tiers.
tests/unit/config/test_schema.py Adds ProviderModelConfig.estimated_latency_ms validation tests and updates naming.
tests/unit/config/test_loader.py Updates provider/env-var naming in loader tests.
tests/unit/config/conftest.py Updates YAML fixture provider/model naming and env-var names.
tests/unit/providers/test_registry.py Updates provider naming and provider list ordering assertions.
tests/unit/providers/test_errors.py Updates error-context fixtures to vendor-neutral provider/model identifiers.
tests/unit/providers/drivers/conftest.py Updates driver test fixtures model aliases to vendor-neutral tiers.
tests/unit/providers/drivers/test_litellm_driver.py Updates provider/model identifiers in LiteLLM driver tests.
tests/unit/core/conftest.py Updates ModelConfig fixture values to vendor-neutral identifiers.
tests/unit/core/test_agent.py Updates assertions for renamed model IDs.
tests/unit/budget/conftest.py Updates budget fixtures for provider name and downgrade tiers.
tests/unit/budget/test_cost_record.py Updates cost record fixture assertion to vendor-neutral provider name.
tests/unit/budget/test_config.py Updates downgrade-map test cases to vendor-neutral tiers.
tests/unit/templates/conftest.py Updates template fixtures to use vendor-neutral model aliases.
tests/unit/templates/test_renderer.py Updates template YAML sample to use vendor-neutral model alias.
tests/unit/templates/test_schema.py Updates template schema test to use vendor-neutral model alias.
tests/integration/providers/conftest.py Renames provider config factory and updates test model aliases.
tests/integration/providers/test_anthropic_pipeline.py Updates integration pipeline tests to use vendor-neutral config factory and naming.
tests/integration/providers/test_error_scenarios.py Updates integration error scenarios to vendor-neutral provider/model naming.
tests/integration/providers/test_openrouter_pipeline.py Updates OpenRouter integration tests to use renamed alias.
tests/integration/providers/test_tool_calling_pipeline.py Updates tool-calling integration tests to use vendor-neutral config factory and naming.
README.md Updates multi-provider feature line to more vendor-neutral wording.
DESIGN_SPEC.md Updates examples/tables to vendor-neutral naming and notes routing now has 6 strategies.
CLAUDE.md Adds/updates vendor-agnostic guidance for code/tests/docs examples.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +375 to +380
# Pick fastest
model, budget_exceeded = _fastest_within_budget(
resolver,
request.remaining_budget,
)
reason = f"Fastest available: {model.model_id}"
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

FastestStrategy always sets the decision reason to "Fastest available". When _fastest_within_budget() falls back to _cheapest_within_budget() due to missing latency data, this reason becomes misleading (the selection was cost-based, not latency-based). Consider returning a flag/enum from _fastest_within_budget() (e.g., selection_basis="latency"|"cost_fallback") and incorporating it into the reason text.

Suggested change
# Pick fastest
model, budget_exceeded = _fastest_within_budget(
resolver,
request.remaining_budget,
)
reason = f"Fastest available: {model.model_id}"
# Pick fastest (falls back to cheapest within budget when no latency data)
model, budget_exceeded = _fastest_within_budget(
resolver,
request.remaining_budget,
)
reason = (
"Selected model "
f"{model.model_id!r} "
"(fastest within budget when latency data is available; "
"otherwise cheapest within budget as a fallback)"
)

Copilot uses AI. Check for mistakes.
logger.info(
ROUTING_FALLBACK_ATTEMPTED,
source="fastest_within_budget",
reason="no latency data, delegating to cheapest",
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

ROUTING_FALLBACK_ATTEMPTED is logged here without a ref, while other uses of this event (e.g., _try_candidate) always include ref. This makes the structured log fields inconsistent for the same event name and can break downstream log queries/alerts. Consider using a different event for “latency data missing” or include a consistent key (e.g., ref=None or candidate_count).

Suggested change
reason="no latency data, delegating to cheapest",
reason="no latency data, delegating to cheapest",
ref=None,

Copilot uses AI. Check for mistakes.
logger.warning(
ROUTING_BUDGET_EXCEEDED,
remaining_budget=remaining_budget,
fastest_cost=fastest_cost,
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

ROUTING_BUDGET_EXCEEDED is emitted with fastest_cost here, but the same event is emitted elsewhere with different keys (e.g., cheapest_cost in _cheapest_within_budget, or model/cost in strategies). For consistent observability, prefer a shared field name (e.g., selected_cost or min_cost) and include model where applicable.

Suggested change
fastest_cost=fastest_cost,
selected_cost=fastest_cost,
model=fastest.model_id,

Copilot uses AI. Check for mistakes.
CLAUDE.md Outdated
- **Timeout**: 30 seconds per test
- **Parallelism**: `pytest-xdist` via `-n auto`
- **Vendor-agnostic fixtures**: use fake model IDs/names in tests (e.g. `test-haiku-001`, `test-provider`), never real vendor model IDs — tests must not be coupled to external providers
- **Vendor-agnostic everywhere**: NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in code, docstrings, comments, tests, or config examples. Use generic names: `example-provider`, `example-large-001`, `example-medium-001`, `example-small-001`, `large`/`medium`/`small` as aliases. Vendor names may only appear in: (1) DESIGN_SPEC.md provider list (listing supported providers), (2) `.claude/` skill/agent files. Tests must use `test-provider`, `test-small-001`, etc.
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

This new “vendor-agnostic everywhere” rule appears stricter than the rest of the repo: the codebase still legitimately references provider names like OpenRouter/Ollama in docs, and some tests/imports necessarily include vendor names via third-party modules (e.g., litellm.types.llms.openai). Consider clarifying the scope (project-owned identifiers vs dependency module paths) and/or expanding the documented exceptions so the rule is enforceable and consistent.

Suggested change
- **Vendor-agnostic everywhere**: NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in code, docstrings, comments, tests, or config examples. Use generic names: `example-provider`, `example-large-001`, `example-medium-001`, `example-small-001`, `large`/`medium`/`small` as aliases. Vendor names may only appear in: (1) DESIGN_SPEC.md provider list (listing supported providers), (2) `.claude/` skill/agent files. Tests must use `test-provider`, `test-small-001`, etc.
- **Vendor-agnostic in project-owned code and examples**: NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: `example-provider`, `example-large-001`, `example-medium-001`, `example-small-001`, `large`/`medium`/`small` as aliases. Vendor names may only appear in: (1) `DESIGN_SPEC.md` provider list (listing supported providers), (2) `.claude/` skill/agent files, (3) third-party module paths/imports (e.g., dependency namespaces), and (4) external-facing docs that must describe real providers at a high level. Tests must use `test-provider`, `test-small-001`, etc.

Copilot uses AI. Check for mistakes.
- **Any Company Structure** - From a 2-person startup to a 50+ enterprise, defined via config/templates
- **Deep Agent Identity** - Names, personalities, skills, seniority levels, performance tracking
- **Multi-Provider** - Anthropic Claude, OpenRouter (400+ models), local Ollama, and more via LiteLLM
- **Multi-Provider** - Any LLM via LiteLLM — cloud APIs, OpenRouter (400+ models), local Ollama, and more
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

This README line introduces vendor/provider names ("OpenRouter", "Ollama"), but CLAUDE.md now states vendor names may only appear in DESIGN_SPEC.md’s provider list. Either update the README to stay vendor-neutral or relax/clarify the CLAUDE.md rule so these references are allowed.

Suggested change
- **Multi-Provider** - Any LLM via LiteLLM — cloud APIs, OpenRouter (400+ models), local Ollama, and more
- **Multi-Provider** - Any LLM via LiteLLM — cloud APIs, local runtimes, and more

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
DESIGN_SPEC.md (1)

2145-2150: ⚠️ Potential issue | 🟡 Minor

Add _strategy_helpers.py to the project tree.

The PR adds src/ai_company/providers/routing/_strategy_helpers.py, but Lines 2145-2150 still omit it from the documented repository structure. That leaves §15.3 stale immediately after this refactor.

Suggested doc patch
 │       │   ├── routing/            # Model routing (6 strategies)
 │       │   │   ├── errors.py      # Routing errors
 │       │   │   ├── models.py      # Routing models (candidates, results)
+│       │   │   ├── _strategy_helpers.py  # Shared routing helpers
 │       │   │   ├── resolver.py    # Model resolver
 │       │   │   ├── router.py      # Router orchestrator
 │       │   │   └── strategies.py  # Routing strategies

Based on learnings: When making changes that affect architecture, services, key files, settings, or workflows, update the relevant sections of existing documentation (CLAUDE.md, README.md, etc.) to reflect those changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@DESIGN_SPEC.md` around lines 2145 - 2150, The project tree in DESIGN_SPEC.md
was not updated to include the new routing helper file; add
"_strategy_helpers.py" to the routing file list in the project structure (the
same place listing errors.py, models.py, resolver.py, router.py, strategies.py)
and update the related doc reference (section §15.3) to reflect the refactor so
the doc and code stay in sync; ensure the filename "_strategy_helpers.py" is
mentioned and any brief description of its purpose is added to the routing tree.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@DESIGN_SPEC.md`:
- Around line 1237-1252: The provider example models list omits the new
estimated_latency_ms field required by the latency-based "fastest" strategy;
update each example model entry (e.g., id "example-large-001",
"example-medium-001", "example-small-001") to include an estimated_latency_ms
value (in milliseconds) and a brief comment if desired, so the sample config
demonstrates how to set latency for the fastest selection strategy and users can
see the format and units to supply.
- Around line 1391-1395: The example for downgrade_map is wrong: the config
model expects an ordered collection of (source, target) pairs, not a simple
mapping; update the downgrade_map example to be a YAML sequence of pair entries
that match the validator (e.g., an ordered list where each item is a two-element
pair or a mapping with explicit source and target fields) so it aligns with the
config model and tests; ensure references to downgrade_map in the docs use that
sequence shape and update any nearby explanatory text to reflect the
ordered-pair schema.

---

Outside diff comments:
In `@DESIGN_SPEC.md`:
- Around line 2145-2150: The project tree in DESIGN_SPEC.md was not updated to
include the new routing helper file; add "_strategy_helpers.py" to the routing
file list in the project structure (the same place listing errors.py, models.py,
resolver.py, router.py, strategies.py) and update the related doc reference
(section §15.3) to reflect the refactor so the doc and code stay in sync; ensure
the filename "_strategy_helpers.py" is mentioned and any brief description of
its purpose is added to the routing tree.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 56c174fe-48f8-4563-bb3f-fea84b85d3a7

📥 Commits

Reviewing files that changed from the base of the PR and between 2f39c1b and aebeb30.

📒 Files selected for processing (43)
  • CLAUDE.md
  • DESIGN_SPEC.md
  • README.md
  • src/ai_company/budget/config.py
  • src/ai_company/config/schema.py
  • src/ai_company/core/agent.py
  • src/ai_company/providers/__init__.py
  • src/ai_company/providers/capabilities.py
  • src/ai_company/providers/drivers/__init__.py
  • src/ai_company/providers/drivers/litellm_driver.py
  • src/ai_company/providers/drivers/mappers.py
  • src/ai_company/providers/models.py
  • src/ai_company/providers/registry.py
  • src/ai_company/providers/routing/__init__.py
  • src/ai_company/providers/routing/_strategy_helpers.py
  • src/ai_company/providers/routing/models.py
  • src/ai_company/providers/routing/resolver.py
  • src/ai_company/providers/routing/strategies.py
  • tests/integration/providers/conftest.py
  • tests/integration/providers/test_anthropic_pipeline.py
  • tests/integration/providers/test_error_scenarios.py
  • tests/integration/providers/test_openrouter_pipeline.py
  • tests/integration/providers/test_tool_calling_pipeline.py
  • tests/unit/budget/conftest.py
  • tests/unit/budget/test_config.py
  • tests/unit/budget/test_cost_record.py
  • tests/unit/config/conftest.py
  • tests/unit/config/test_loader.py
  • tests/unit/config/test_schema.py
  • tests/unit/core/conftest.py
  • tests/unit/core/test_agent.py
  • tests/unit/providers/drivers/conftest.py
  • tests/unit/providers/drivers/test_litellm_driver.py
  • tests/unit/providers/routing/conftest.py
  • tests/unit/providers/routing/test_models.py
  • tests/unit/providers/routing/test_resolver.py
  • tests/unit/providers/routing/test_router.py
  • tests/unit/providers/routing/test_strategies.py
  • tests/unit/providers/test_errors.py
  • tests/unit/providers/test_registry.py
  • tests/unit/templates/conftest.py
  • tests/unit/templates/test_renderer.py
  • tests/unit/templates/test_schema.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Agent
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: No from __future__ import annotations in Python code — Python 3.14 has PEP 649 native lazy annotations
Use except A, B: syntax (no parentheses) for multiple exception handling in Python 3.14 per PEP 758
All public functions and classes must have type hints; mypy strict mode is enforced
Docstrings must follow Google style and are required on all public classes and functions (enforced by ruff D rules)
Create new objects rather than mutating existing ones — use copy.deepcopy() at construction and MappingProxyType wrapping for read-only enforcement in non-Pydantic internal collections
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models for runtime state that evolves
Use Pydantic v2 BaseModel, model_validator, computed_field, and ConfigDict; use @computed_field for derived values instead of storing redundant fields
Use NotBlankStr from core.types for all identifier and name fields instead of manual whitespace validators
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g. multiple tool invocations, parallel agent calls) over bare create_task
Line length must not exceed 88 characters (ruff enforced)
Functions must be less than 50 lines and files must be less than 800 lines
Handle errors explicitly; never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)

Files:

  • src/ai_company/config/schema.py
  • src/ai_company/providers/__init__.py
  • tests/integration/providers/conftest.py
  • src/ai_company/providers/drivers/litellm_driver.py
  • src/ai_company/providers/routing/__init__.py
  • tests/unit/providers/routing/test_router.py
  • tests/unit/providers/test_registry.py
  • tests/unit/core/conftest.py
  • tests/unit/templates/test_renderer.py
  • tests/unit/config/test_loader.py
  • src/ai_company/providers/registry.py
  • tests/unit/providers/routing/test_resolver.py
  • tests/unit/providers/routing/test_models.py
  • tests/unit/templates/conftest.py
  • tests/unit/providers/routing/test_strategies.py
  • tests/unit/core/test_agent.py
  • tests/integration/providers/test_openrouter_pipeline.py
  • tests/integration/providers/test_error_scenarios.py
  • tests/unit/budget/test_cost_record.py
  • tests/unit/providers/drivers/test_litellm_driver.py
  • src/ai_company/providers/routing/models.py
  • src/ai_company/providers/drivers/__init__.py
  • tests/unit/budget/test_config.py
  • src/ai_company/providers/models.py
  • tests/unit/providers/test_errors.py
  • src/ai_company/providers/capabilities.py
  • tests/unit/templates/test_schema.py
  • src/ai_company/core/agent.py
  • tests/unit/config/test_schema.py
  • src/ai_company/providers/drivers/mappers.py
  • tests/unit/config/conftest.py
  • src/ai_company/providers/routing/resolver.py
  • src/ai_company/providers/routing/strategies.py
  • tests/integration/providers/test_anthropic_pipeline.py
  • tests/unit/budget/conftest.py
  • src/ai_company/budget/config.py
  • tests/unit/providers/drivers/conftest.py
  • tests/unit/providers/routing/conftest.py
  • tests/integration/providers/test_tool_calling_pipeline.py
  • src/ai_company/providers/routing/_strategy_helpers.py
src/ai_company/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/ai_company/**/*.py: Every module with business logic must have: from ai_company.observability import get_logger then logger = get_logger(name); never use import logging or print()
Always use logger variable name (not _logger or log)
Use event name constants from ai_company.observability.events domain-specific modules instead of string literals
Always use structured logging with logger.info(EVENT, key=value) format; never use logger.info('msg %s', val)
All error paths must log at WARNING or ERROR with context before raising
All state transitions must log at INFO level
Use DEBUG level for object creation, internal flow, and entry/exit of key functions

Files:

  • src/ai_company/config/schema.py
  • src/ai_company/providers/__init__.py
  • src/ai_company/providers/drivers/litellm_driver.py
  • src/ai_company/providers/routing/__init__.py
  • src/ai_company/providers/registry.py
  • src/ai_company/providers/routing/models.py
  • src/ai_company/providers/drivers/__init__.py
  • src/ai_company/providers/models.py
  • src/ai_company/providers/capabilities.py
  • src/ai_company/core/agent.py
  • src/ai_company/providers/drivers/mappers.py
  • src/ai_company/providers/routing/resolver.py
  • src/ai_company/providers/routing/strategies.py
  • src/ai_company/budget/config.py
  • src/ai_company/providers/routing/_strategy_helpers.py
src/ai_company/providers/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/ai_company/providers/**/*.py: All provider calls must go through BaseCompletionProvider which applies retry and rate limiting automatically; never implement retry logic in driver subclasses or calling code
RetryConfig and RateLimiterConfig are set per-provider in ProviderConfig
Retryable errors (RateLimitError, ProviderTimeoutError, ProviderConnectionError, ProviderInternalError) are automatically retried; non-retryable errors raise immediately

Files:

  • src/ai_company/providers/__init__.py
  • src/ai_company/providers/drivers/litellm_driver.py
  • src/ai_company/providers/routing/__init__.py
  • src/ai_company/providers/registry.py
  • src/ai_company/providers/routing/models.py
  • src/ai_company/providers/drivers/__init__.py
  • src/ai_company/providers/models.py
  • src/ai_company/providers/capabilities.py
  • src/ai_company/providers/drivers/mappers.py
  • src/ai_company/providers/routing/resolver.py
  • src/ai_company/providers/routing/strategies.py
  • src/ai_company/providers/routing/_strategy_helpers.py
src/ai_company/{providers,engine}/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

RetryExhaustedError signals that all retries failed — the engine layer catches this to trigger fallback chains

Files:

  • src/ai_company/providers/__init__.py
  • src/ai_company/providers/drivers/litellm_driver.py
  • src/ai_company/providers/routing/__init__.py
  • src/ai_company/providers/registry.py
  • src/ai_company/providers/routing/models.py
  • src/ai_company/providers/drivers/__init__.py
  • src/ai_company/providers/models.py
  • src/ai_company/providers/capabilities.py
  • src/ai_company/providers/drivers/mappers.py
  • src/ai_company/providers/routing/resolver.py
  • src/ai_company/providers/routing/strategies.py
  • src/ai_company/providers/routing/_strategy_helpers.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use fake model IDs and names in tests (e.g. test-haiku-001, test-provider), never real vendor model IDs — tests must not be coupled to external providers
Mark tests with @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, or @pytest.mark.slow

Files:

  • tests/integration/providers/conftest.py
  • tests/unit/providers/routing/test_router.py
  • tests/unit/providers/test_registry.py
  • tests/unit/core/conftest.py
  • tests/unit/templates/test_renderer.py
  • tests/unit/config/test_loader.py
  • tests/unit/providers/routing/test_resolver.py
  • tests/unit/providers/routing/test_models.py
  • tests/unit/templates/conftest.py
  • tests/unit/providers/routing/test_strategies.py
  • tests/unit/core/test_agent.py
  • tests/integration/providers/test_openrouter_pipeline.py
  • tests/integration/providers/test_error_scenarios.py
  • tests/unit/budget/test_cost_record.py
  • tests/unit/providers/drivers/test_litellm_driver.py
  • tests/unit/budget/test_config.py
  • tests/unit/providers/test_errors.py
  • tests/unit/templates/test_schema.py
  • tests/unit/config/test_schema.py
  • tests/unit/config/conftest.py
  • tests/integration/providers/test_anthropic_pipeline.py
  • tests/unit/budget/conftest.py
  • tests/unit/providers/drivers/conftest.py
  • tests/unit/providers/routing/conftest.py
  • tests/integration/providers/test_tool_calling_pipeline.py
🧠 Learnings (27)
📚 Learning: 2026-03-06T13:28:37.851Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T13:28:37.851Z
Learning: Applies to src/ai_company/providers/**/*.py : RetryConfig and RateLimiterConfig are set per-provider in ProviderConfig

Applied to files:

  • src/ai_company/config/schema.py
  • tests/integration/providers/conftest.py
  • tests/unit/config/test_loader.py
  • tests/unit/providers/routing/test_strategies.py
  • tests/integration/providers/test_error_scenarios.py
  • tests/unit/providers/drivers/test_litellm_driver.py
  • tests/unit/providers/test_errors.py
  • tests/unit/config/test_schema.py
  • tests/unit/providers/routing/conftest.py
📚 Learning: 2026-03-06T13:28:37.851Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T13:28:37.851Z
Learning: Applies to tests/**/*.py : Use fake model IDs and names in tests (e.g. test-haiku-001, test-provider), never real vendor model IDs — tests must not be coupled to external providers

Applied to files:

  • tests/integration/providers/conftest.py
  • CLAUDE.md
  • tests/unit/providers/test_registry.py
  • tests/unit/core/conftest.py
  • tests/unit/config/test_loader.py
  • tests/unit/providers/routing/test_resolver.py
  • tests/unit/providers/routing/test_models.py
  • tests/unit/core/test_agent.py
  • tests/integration/providers/test_error_scenarios.py
  • tests/unit/providers/drivers/test_litellm_driver.py
  • tests/unit/providers/test_errors.py
  • tests/unit/config/test_schema.py
  • tests/unit/config/conftest.py
  • tests/integration/providers/test_anthropic_pipeline.py
  • tests/unit/providers/drivers/conftest.py
  • tests/unit/providers/routing/conftest.py
  • tests/integration/providers/test_tool_calling_pipeline.py
📚 Learning: 2026-03-06T13:28:37.851Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T13:28:37.851Z
Learning: Applies to src/ai_company/providers/**/*.py : All provider calls must go through BaseCompletionProvider which applies retry and rate limiting automatically; never implement retry logic in driver subclasses or calling code

Applied to files:

  • src/ai_company/providers/drivers/litellm_driver.py
  • tests/unit/providers/test_registry.py
  • tests/integration/providers/test_error_scenarios.py
  • tests/unit/providers/drivers/test_litellm_driver.py
  • src/ai_company/providers/drivers/__init__.py
  • tests/unit/providers/test_errors.py
  • tests/integration/providers/test_tool_calling_pipeline.py
📚 Learning: 2026-02-26T17:43:50.902Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-26T17:43:50.902Z
Learning: When making changes that affect architecture, services, key files, settings, or workflows, update the relevant sections of existing documentation (CLAUDE.md, README.md, etc.) to reflect those changes.

Applied to files:

  • CLAUDE.md
  • DESIGN_SPEC.md
  • README.md
📚 Learning: 2026-01-26T08:59:32.818Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-26T08:59:32.818Z
Learning: Applies to README.md : Update README.md for significant feature changes

Applied to files:

  • CLAUDE.md
  • README.md
📚 Learning: 2026-02-26T17:43:50.902Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-26T17:43:50.902Z
Learning: Applies to tests/**/*.py : Tests must use fake model names (e.g., `test-model:8b`, `fake-writer:latest`)—never use real model IDs from `RECOMMENDED_MODELS`.

Applied to files:

  • CLAUDE.md
  • tests/unit/core/conftest.py
  • tests/unit/providers/routing/test_resolver.py
  • tests/unit/providers/routing/test_models.py
  • tests/unit/templates/conftest.py
  • tests/unit/core/test_agent.py
  • tests/unit/providers/drivers/test_litellm_driver.py
  • tests/unit/providers/test_errors.py
  • tests/unit/config/test_schema.py
  • tests/integration/providers/test_anthropic_pipeline.py
📚 Learning: 2026-01-24T09:54:56.100Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/test-files.instructions.md:0-0
Timestamp: 2026-01-24T09:54:56.100Z
Learning: Each test should be independent and not rely on other tests; use pytest fixtures for test setup (shared fixtures in `tests/conftest.py`); clean up resources in teardown/fixtures

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-01-24T09:54:56.100Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/test-files.instructions.md:0-0
Timestamp: 2026-01-24T09:54:56.100Z
Learning: Applies to **/test_*.py : Use `async def` for async test functions; pytest-asyncio is configured with `asyncio_mode = "auto"`; mark async tests with `pytest.mark.asyncio` if needed

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-01-24T09:54:56.100Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/test-files.instructions.md:0-0
Timestamp: 2026-01-24T09:54:56.100Z
Learning: Applies to **/test_*.py : Use appropriate fixture scopes (`function`, `class`, `module`, `session`) and document complex fixtures with docstrings

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-01-31T13:51:16.868Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-31T13:51:16.868Z
Learning: Applies to tests/**/*.py : Mock models in tests must use a name from `RECOMMENDED_MODELS` (e.g., `huihui_ai/dolphin3-abliterated:8b`) - fake model names cause `ValueError: No model tagged for role`.

Applied to files:

  • CLAUDE.md
  • tests/unit/templates/conftest.py
  • tests/unit/core/test_agent.py
  • tests/unit/config/test_schema.py
📚 Learning: 2026-03-06T13:28:37.851Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T13:28:37.851Z
Learning: Set asyncio_mode = 'auto' in pytest configuration; do not use manual pytest.mark.asyncio

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-01-26T08:59:32.818Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-26T08:59:32.818Z
Learning: Applies to tests/**/*.py : Use pytest fixtures for test setup. Shared fixtures should be in `tests/conftest.py`

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-01-24T09:54:45.426Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/agents.instructions.md:0-0
Timestamp: 2026-01-24T09:54:45.426Z
Learning: Applies to agents/test*.py : Agent tests should cover: successful generation with valid output, handling malformed LLM responses, error conditions (network errors, timeouts), output format validation, and integration with story state

Applied to files:

  • CLAUDE.md
  • tests/unit/core/test_agent.py
📚 Learning: 2026-01-24T16:33:29.354Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-24T16:33:29.354Z
Learning: Applies to tests/**/*.py : Mock Ollama in tests to avoid requiring running instance - use model names from `RECOMMENDED_MODELS` (e.g., `huihui_ai/dolphin3-abliterated:8b`)

Applied to files:

  • CLAUDE.md
  • tests/unit/core/conftest.py
📚 Learning: 2026-03-06T13:28:37.851Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T13:28:37.851Z
Learning: If implementation deviates from DESIGN_SPEC.md, alert the user and explain why — user decides whether to proceed or update the spec

Applied to files:

  • DESIGN_SPEC.md
📚 Learning: 2026-03-06T13:28:37.851Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T13:28:37.851Z
Learning: Always read DESIGN_SPEC.md before implementing any feature or planning any issue

Applied to files:

  • DESIGN_SPEC.md
📚 Learning: 2026-01-24T16:33:29.354Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-24T16:33:29.354Z
Learning: Applies to {src/agents/**/*.py,src/services/**/*.py} : Ollama Integration - all AI agents use Ollama for local LLM serving with default endpoint `http://localhost:11434`

Applied to files:

  • DESIGN_SPEC.md
  • README.md
📚 Learning: 2026-01-26T08:59:32.818Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-26T08:59:32.818Z
Learning: Applies to src/services/model_service.py : Default Ollama endpoint is `http://localhost:11434`. Respect existing model configuration patterns.

Applied to files:

  • DESIGN_SPEC.md
📚 Learning: 2026-01-24T16:33:29.354Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-24T16:33:29.354Z
Learning: Applies to {src/agents/**/*.py,src/services/model_service.py} : Respect existing model configuration patterns in Ollama integration

Applied to files:

  • DESIGN_SPEC.md
  • tests/unit/core/test_agent.py
  • src/ai_company/core/agent.py
📚 Learning: 2026-02-26T17:43:50.902Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-26T17:43:50.902Z
Learning: Applies to src/settings.py : Recommended Ollama model is `huihui_ai/dolphin3-abliterated:8b`.

Applied to files:

  • DESIGN_SPEC.md
📚 Learning: 2026-02-26T17:43:50.902Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-26T17:43:50.902Z
Learning: Applies to src/**/*.py : Default Ollama endpoint is `http://localhost:11434`. Configurable via settings.

Applied to files:

  • DESIGN_SPEC.md
📚 Learning: 2026-01-24T09:54:45.426Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/agents.instructions.md:0-0
Timestamp: 2026-01-24T09:54:45.426Z
Learning: Keep agent logic focused on its specific role - don't mix agent responsibilities (Interviewer, Architect, Writer, Editor, Continuity)

Applied to files:

  • README.md
📚 Learning: 2026-01-24T09:54:45.426Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/agents.instructions.md:0-0
Timestamp: 2026-01-24T09:54:45.426Z
Learning: Applies to agents/test*.py : In agent tests, mock Ollama API calls using `unittest.mock` and patch `agents.base.ollama.Client`

Applied to files:

  • tests/integration/providers/test_openrouter_pipeline.py
  • tests/integration/providers/test_anthropic_pipeline.py
📚 Learning: 2026-03-06T13:28:37.851Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T13:28:37.851Z
Learning: Applies to src/ai_company/providers/**/*.py : Retryable errors (RateLimitError, ProviderTimeoutError, ProviderConnectionError, ProviderInternalError) are automatically retried; non-retryable errors raise immediately

Applied to files:

  • tests/integration/providers/test_error_scenarios.py
  • tests/unit/providers/drivers/test_litellm_driver.py
  • tests/unit/providers/test_errors.py
📚 Learning: 2026-01-24T09:54:56.100Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/test-files.instructions.md:0-0
Timestamp: 2026-01-24T09:54:56.100Z
Learning: Applies to **/tests/{unit,integration,smoke,e2e}/test_*.py : Test files should mirror the structure of the code they test: `tests/unit/test_<module>.py` for unit tests, `tests/integration/test_<feature>.py` for integration tests, `tests/smoke/test_<component>.py` for smoke tests, `tests/e2e/test_<workflow>.py` for end-to-end tests

Applied to files:

  • tests/integration/providers/test_anthropic_pipeline.py
📚 Learning: 2026-01-24T09:54:56.100Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/test-files.instructions.md:0-0
Timestamp: 2026-01-24T09:54:56.100Z
Learning: Applies to **/test_*.py : Test files must be named `test_*.py`

Applied to files:

  • tests/integration/providers/test_anthropic_pipeline.py
📚 Learning: 2026-01-24T09:54:56.100Z
Learnt from: CR
Repo: Aureliolo/story-factory PR: 0
File: .github/instructions/test-files.instructions.md:0-0
Timestamp: 2026-01-24T09:54:56.100Z
Learning: Applies to **/test_*.py : Test classes must be named `Test*` (e.g., `TestStoryService`)

Applied to files:

  • tests/integration/providers/test_anthropic_pipeline.py
🪛 LanguageTool
README.md

[typographical] ~15-~15: To join two clauses or introduce examples, consider using an em dash.
Context: ...erformance tracking - Multi-Provider - Any LLM via LiteLLM — cloud APIs, OpenRo...

(DASH_RULE)

🔇 Additional comments (73)
tests/unit/budget/test_cost_record.py (1)

23-23: Vendor-agnostic expectation matches the fixture.

This assertion now lines up with tests/unit/budget/conftest.py:119-128 and keeps the test decoupled from real providers. As per coding guidelines, "Use fake model IDs and names in tests (e.g. test-haiku-001, test-provider), never real vendor model IDs — tests must not be coupled to external providers".

src/ai_company/providers/drivers/__init__.py (1)

3-4: Accurate and appropriately scoped docstring.

This keeps the module description aligned with the current export while preserving the BaseCompletionProvider contract.

As per coding guidelines, "All provider calls must go through BaseCompletionProvider which applies retry and rate limiting automatically; never implement retry logic in driver subclasses or calling code".

tests/unit/providers/test_errors.py (4)

32-35: Nice vendor-neutral fixture update.

This keeps the test focused on context preservation without coupling it to a real provider/model naming scheme. Based on learnings: Applies to tests/**/*.py : Use fake model IDs and names in tests (e.g. test-haiku-001, test-provider), never real vendor model IDs — tests must not be coupled to external providers


116-123: Good use of fake provider context here.

The renamed context still exercises pass-through behavior and stays aligned with the test-data guideline. Based on learnings: Applies to tests/**/*.py : Use fake model IDs and names in tests (e.g. test-haiku-001, test-provider), never real vendor model IDs — tests must not be coupled to external providers


130-154: Formatting assertions stay consistent with ProviderError.__str__().

These updated expectations remain vendor-agnostic and still validate both normal rendering and sensitive-key redaction correctly against the current formatter behavior.


187-191: Good immutability test cleanup.

Switching to a fake provider name preserves the copy-on-construction check while avoiding external-provider coupling in the fixture data. Based on learnings: Applies to tests/**/*.py : Use fake model IDs and names in tests (e.g. test-haiku-001, test-provider), never real vendor model IDs — tests must not be coupled to external providers

tests/unit/core/conftest.py (1)

174-181: LGTM! Vendor-agnostic fixture naming.

The changes correctly replace vendor-specific names (Sonnet, Haiku) with generic size descriptors (medium, small) while maintaining the test- prefix convention. The updated values align with expectations in test_agent.py (per the relevant code snippet showing assert sample_model_config.model_id == "test-model-medium-001").

src/ai_company/providers/drivers/mappers.py (2)

1-5: Docstrings stay accurate while removing vendor-specific wording.

Nice cleanup. These updates keep the docs aligned with the actual chat-completion contract used here without reintroducing vendor-specific terminology.

Also applies to: 25-34, 68-82, 131-143


93-94: The finish-reason note keeps the right interoperability nuance.

Good rewording: it stays generic while still documenting that some raw provider values can pass through LiteLLM.

src/ai_company/providers/drivers/litellm_driver.py (2)

4-4: LGTM! Vendor-agnostic docstring updates.

The docstring changes successfully replace vendor-specific references with generic examples ("example-provider", "example-medium-001"), aligning with the PR's vendor-agnostic cleanup objective while maintaining clear documentation.

Also applies to: 111-112, 115-115


563-563: No action required — Python 3.14 PEP 758 syntax is correct.

The code correctly uses except A, B: syntax for catching multiple exceptions without parentheses, which is valid in Python 3.14 per PEP 758. This syntax applies to all three instances at lines 563, 584, and 717 and aligns with the coding guidelines.

src/ai_company/providers/capabilities.py (1)

17-18: LGTM!

The docstring example values are correctly updated to use vendor-agnostic placeholders ("example-large-001", "example-provider"), aligning with the PR objective of removing vendor-specific names from source code.

tests/unit/templates/test_schema.py (1)

88-88: LGTM!

The model value is correctly updated from the vendor-specific "opus" to the generic alias "large", consistent with the PR's vendor-agnostic naming convention and the coding guidelines requiring fake model IDs in tests.

src/ai_company/budget/config.py (1)

102-103: LGTM!

The docstring example is correctly updated to use the generic alias "large" instead of vendor-specific model names, while accurately demonstrating the whitespace normalization behavior.

tests/unit/budget/conftest.py (2)

114-114: LGTM!

The downgrade_map values are correctly updated to use vendor-agnostic tier aliases (largemediumsmall), aligning with the PR's naming convention and the coding guidelines requiring fake model IDs in tests.


124-124: LGTM!

The provider name is correctly updated from the vendor-specific "anthropic" to the generic placeholder "example-provider", consistent with the coding guidelines and the PR's vendor-agnostic cleanup objective.

src/ai_company/providers/models.py (1)

68-68: LGTM!

The docstring is correctly simplified to remove vendor-specific names (OpenAI, Anthropic), making it provider-agnostic while preserving the technical meaning.

src/ai_company/providers/registry.py (2)

43-44: LGTM!

The docstring examples are correctly updated to use vendor-agnostic placeholders ("example-provider", "medium"), demonstrating the API usage without coupling documentation to specific vendors.


70-70: LGTM!

The docstring example is appropriately updated to use "example-provider" instead of vendor-specific names.

tests/unit/templates/conftest.py (4)

30-30: LGTM!

The model value is correctly updated from "sonnet" to the generic alias "medium" in the test template YAML fixture.


63-63: LGTM!

Consistent with other fixture updates—model value updated to generic alias "medium".


85-85: LGTM!

Model value consistently updated to "medium" in the required variable template fixture.


114-114: LGTM!

The _make_template_dict helper function is correctly updated to use the generic alias "medium" as the default model value, ensuring consistency across all template test fixtures.

src/ai_company/core/agent.py (1)

79-80: LGTM!

The docstring attribute examples are correctly updated to use vendor-agnostic placeholders ("example-provider", "example-medium-001"), removing vendor-specific names while maintaining clear documentation.

README.md (1)

15-15: LGTM!

The documentation update correctly removes vendor-specific references (Anthropic Claude) and uses vendor-agnostic language, aligning with the PR's objective of vendor-neutral cleanup.

src/ai_company/config/schema.py (1)

135-140: LGTM!

The estimated_latency_ms field is well-defined with appropriate constraints:

  • Optional (int | None) with default=None for backward compatibility
  • gt=0 ensures positive values only
  • le=300_000 caps at a reasonable 5-minute maximum
  • Integrates cleanly with the frozen Pydantic model
tests/unit/config/conftest.py (2)

97-104: LGTM!

Test fixtures correctly updated to use vendor-agnostic naming:

  • Provider key: anthropicexample-provider
  • Model alias: sonnetmedium
  • Fallback chain updated accordingly

This aligns with the coding guidelines requiring fake model IDs and names in tests.


135-137: LGTM!

Environment variable naming consistently updated from ANTHROPIC_BASE_URL to EXAMPLE_PROVIDER_BASE_URL with an appropriate generic default URL.

tests/unit/config/test_loader.py (2)

240-240: LGTM!

Test assertion correctly updated to check for "example-provider" instead of the vendor-specific name, consistent with the fixture changes.


595-599: LGTM!

Environment variable and provider key assertions properly updated to match the vendor-agnostic fixture naming.

tests/unit/config/test_schema.py (5)

70-88: LGTM!

Excellent test coverage for the new estimated_latency_ms field:

  • Default None value
  • Valid positive integer
  • Zero rejection (validates gt=0 constraint)
  • Negative value rejection
  • Upper bound violation (validates le=300_000 constraint)

The test cases comprehensively validate all boundary conditions.


41-46: LGTM!

Model alias correctly updated from vendor-specific to generic naming ("medium").


157-180: LGTM!

Routing rule tests consistently updated to use vendor-agnostic model aliases ("medium", "large").


262-262: LGTM!

Agent config test updated to use "example-provider" instead of vendor-specific provider names.


313-321: LGTM!

Root config tests consistently updated to use "example-provider".

tests/unit/core/test_agent.py (1)

161-161: LGTM!

Test assertion correctly updated to match the fixture's vendor-agnostic model ID ("test-model-medium-001"), consistent with the sample_model_config fixture definition.

tests/integration/providers/conftest.py (2)

70-70: LGTM!

OpenRouter model alias consistently updated from "or-sonnet" to "or-medium".


33-57: LGTM!

Factory function correctly renamed from make_anthropic_config() to make_provider_config() with all vendor-specific references removed:

  • Provider key: anthropicexample-provider
  • API key: sk-ant-test-keysk-test-key
  • Model aliases: sonnet/haikumedium/small

All callers across integration and unit tests have been updated.

tests/unit/providers/test_registry.py (4)

94-99: LGTM!

Registry get test correctly updated to use vendor-agnostic provider name "example-provider".


121-130: LGTM!

List providers test updated with generic provider names. The sorted output expectation ("example-provider", "provider-b", "provider-c") is correct for alphabetical ordering.


144-148: LGTM!

Contains test correctly updated to use "example-provider".


261-266: LGTM!

Default LiteLLM factory resolution test correctly updated to use "example-provider".

tests/unit/providers/routing/test_models.py (2)

83-121: LGTM! Comprehensive latency validation tests.

The new tests for estimated_latency_ms provide good coverage of edge cases: default None, valid values, zero rejection, negative rejection, and upper bound validation. The test naming follows existing conventions and uses fake model IDs per coding guidelines.


25-25: LGTM! Vendor-agnostic naming updates.

Model identifiers correctly updated from vendor-specific names (sonnet) to generic equivalents (medium, test-medium-001), aligning with the PR objectives for vendor-neutral test fixtures.

Also applies to: 187-192

src/ai_company/providers/routing/resolver.py (2)

110-110: LGTM! Latency field propagation.

The estimated_latency_ms field is correctly wired from model_config to the ResolvedModel constructor, maintaining consistency with other config fields.


191-205: LGTM! Latency-sorted model retrieval.

The implementation correctly handles None latency by treating it as infinity, ensuring models without latency data sort last. The approach mirrors the existing all_models_sorted_by_cost pattern.

src/ai_company/providers/__init__.py (1)

50-51: LGTM! Public API surface updated correctly.

STRATEGY_NAME_FASTEST and FastestStrategy are properly imported and exported, maintaining alphabetical ordering in __all__. This enables downstream code to access the new fastest routing strategy.

Also applies to: 55-56, 75-75, 91-91

src/ai_company/providers/routing/__init__.py (1)

20-20: LGTM! Routing package exports updated.

The fastest strategy symbols are correctly exported from the routing package, enabling the re-export chain through providers/__init__.py.

Also applies to: 25-25, 36-36, 41-41

src/ai_company/providers/routing/models.py (2)

42-47: LGTM! Well-constrained latency field.

The estimated_latency_ms field is properly defined with:

  • Default None for models without latency data
  • Validation gt=0 to reject zero/negative values
  • Upper bound le=300_000 (5 minutes) as a reasonable ceiling

The frozen model ensures immutability after construction.


63-63: LGTM! Docstring updated for FastestStrategy.

The RoutingRequest docstring correctly documents that FastestStrategy uses task_type and remaining_budget, maintaining consistency with other strategy documentation.

tests/integration/providers/test_tool_calling_pipeline.py (2)

32-32: LGTM! Provider configuration updated to vendor-agnostic naming.

The test helper and driver construction correctly use generic identifiers (make_provider_config, example-provider) instead of vendor-specific names, aligning with the PR's vendor-agnostic cleanup objectives. Based on learnings: "Use fake model IDs and names in tests (e.g. test-haiku-001, test-provider), never real vendor model IDs."

Also applies to: 40-44


68-68: LGTM! Model alias updates consistent throughout.

All model alias references correctly updated from vendor-specific ("sonnet") to generic ("medium") across all test cases. Test behavior and assertions remain unchanged.

Also applies to: 102-102, 120-120, 144-144, 169-169, 213-213, 242-242, 275-275, 305-305, 341-341

tests/integration/providers/test_anthropic_pipeline.py (3)

1-1: LGTM! Module docstring and imports updated.

The docstring now uses generic "provider end-to-end pipeline" terminology, and imports reference the vendor-agnostic helper.

Also applies to: 25-26


40-46: LGTM! Config and driver construction vendor-agnostic.

All test setup correctly uses make_provider_config() and registry.get("example-provider") with generic model aliases.

Also applies to: 55-70


169-190: LGTM! Test renamed to vendor-agnostic naming.

The test test_small_model (formerly test_haiku_model) correctly references the generic "small" model alias and validates cost computation with the updated model identifier.

tests/unit/providers/routing/test_resolver.py (2)

18-19: LGTM! Model ID updates consistent with vendor-agnostic naming.

All model identifiers correctly updated to generic equivalents (test-medium-001, test-small-001, test-large-001), maintaining test isolation from external providers.

Also applies to: 28-28, 39-40, 63-64, 68-68, 84-84


111-169: LGTM! Comprehensive latency sorting test coverage.

The new TestResolverSortByLatency class provides thorough coverage:

  • test_sorted_ascending: Validates ascending latency order
  • test_none_sorted_last: Confirms None latency models sort after those with values
  • test_all_none_returns_all: Handles edge case where no models have latency data
  • test_wired_from_config: Validates latency propagation through the config pipeline

All tests use generic model names per coding guidelines.

tests/integration/providers/test_error_scenarios.py (1)

1-393: LGTM! Vendor-agnostic cleanup is thorough and consistent.

All references have been correctly updated from vendor-specific names (Anthropic, sonnet, haiku) to generic equivalents (example-provider, medium, small). The test logic remains intact, and the fake model IDs comply with the testing guidelines.

tests/unit/providers/routing/test_strategies.py (2)

324-509: LGTM! Comprehensive test coverage for FastestStrategy.

The new test suite covers all critical behaviors:

  • Basic fastest selection
  • Task-type rule priority with budget awareness
  • Budget constraints and exceeded budget fallback
  • No models registered error case
  • Fallback to cheapest when no latency data available
  • Mixed latency data handling (ignores None values)

Test fixtures use appropriate fake model IDs per guidelines.


37-56: LGTM! Protocol conformance and strategy map tests updated correctly.

The test correctly includes FastestStrategy in the protocol conformance check and verifies that STRATEGY_MAP now contains all six expected strategies including "fastest".

tests/unit/providers/drivers/test_litellm_driver.py (2)

56-81: LGTM! Driver test helpers updated with vendor-agnostic defaults.

The _make_driver and _collect_stream helper functions now use generic provider/model names ("example-provider", "medium") instead of vendor-specific ones.


1-797: LGTM! Vendor-agnostic cleanup throughout the file is consistent.

All test references have been correctly updated from vendor-specific names to generic equivalents. The test logic remains intact while ensuring tests are not coupled to external providers, as required by the coding guidelines.

src/ai_company/providers/routing/strategies.py (3)

330-389: LGTM! FastestStrategy implementation is clean and follows established patterns.

The implementation correctly:

  • Matches task-type rules first with budget awareness
  • Falls back to _fastest_within_budget when rules don't apply or exceed budget
  • Tracks skipped rules for informative reason strings
  • Uses structured logging with event constants
  • Follows the same pattern as CostAwareStrategy for consistency

45-47: LGTM! Strategy name constant properly defined.

The STRATEGY_NAME_FASTEST constant follows the naming convention of other strategy constants.


527-539: LGTM! Strategy registry correctly updated.

The _FASTEST singleton is properly instantiated and registered in STRATEGY_MAP under the "fastest" key.

src/ai_company/providers/routing/_strategy_helpers.py (8)

1-22: LGTM! Module setup follows conventions.

The module correctly:

  • Imports the logger from observability
  • Uses event constants from ai_company.observability.events.routing
  • Maintains a clear docstring explaining the module's purpose

24-44: LGTM! _try_candidate correctly handles deduplication.

The function properly:

  • Skips already-seen refs to avoid redundant resolution attempts
  • Records failed attempts in both tried list and seen set
  • Logs fallback attempts at DEBUG level with structured data

47-93: LGTM! _try_resolve_with_fallback implements proper fallback hierarchy.

The function correctly implements the three-stage resolution:

  1. Primary reference
  2. Rule-specific fallback
  3. Global fallback chain

Raises NoAvailableModelError with context when all candidates are exhausted.


148-156: LGTM! _within_budget is a clean budget check utility.

Simple and correct implementation that handles the None budget case (unlimited budget) properly.


158-196: LGTM! _cheapest_within_budget correctly implements budget-aware selection.

The function:

  • Returns immediately when no budget constraint exists
  • Iterates cost-sorted models to find the cheapest within budget
  • Falls back to absolute cheapest with budget_exceeded=True when all models exceed budget
  • Logs appropriately at WARNING level when budget is exceeded

198-253: LGTM! _fastest_within_budget implements correct latency-based selection with fallback.

The implementation correctly:

  • Falls back to _cheapest_within_budget when no models have latency data
  • Filters to only consider models with latency data for the fastest selection
  • Returns the fastest model within budget, or the absolute fastest with budget_exceeded=True
  • Logs the fallback delegation at INFO level and budget exceeded at WARNING level

255-290: LGTM! _try_task_type_rules cleanly encapsulates task-type rule matching.

The function properly:

  • Returns None early if no task_type in request
  • Matches rules by task_type and resolves with fallback support
  • Returns a complete RoutingDecision with reason and fallbacks_tried
  • Logs at DEBUG when no rule matches

292-364: LGTM! _try_role_rules and _try_seniority_default follow consistent patterns.

Both functions:

  • Return None early when preconditions aren't met
  • Use appropriate logging levels (DEBUG for no match, WARNING/INFO for unexpected states)
  • Return complete RoutingDecision objects with informative reasons

…t, and Gemini

DESIGN_SPEC.md:
- Add _strategy_helpers.py to §15.3 project structure tree
- Add estimated_latency_ms to §9.2 provider YAML example
- Add strategy behavior descriptions to §9.4
- Fix downgrade_map example shape (mapping -> sequence of pairs)
- Clarify latency_ms vs estimated_latency_ms in §10.5

Source fixes:
- Add logging to SmartStrategy._try_cheapest on NoAvailableModelError
- Standardize ROUTING_BUDGET_EXCEEDED log keys (model_cost + model)
- Add ref=None to ROUTING_FALLBACK_ATTEMPTED for consistency
- Remove duplicate ROUTING_FALLBACK_EXHAUSTED log in safe wrapper
- Add debug logging for LookupError in _raise_no_available
- Fix FastestStrategy reason text when falling back to cheapest
- Replace "openrouter" with "example-provider" in registry docstring

Vendor-agnostic:
- Rename test_anthropic_pipeline.py -> test_provider_pipeline.py
- Replace "OpenAI format" with "chat-completion format" in test docstrings
- Clarify CLAUDE.md vendor-agnostic rule scope (third-party imports exempt)

Tests:
- Add test_routes_fastest to TestModelRouterRoute
- Add test_budget_picks_slower_when_fastest_exceeds to TestFastestStrategy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Aureliolo Aureliolo merged commit 09619cb into main Mar 6, 2026
8 of 9 checks passed
@Aureliolo Aureliolo deleted the feat/fastest-strategy-vendor-cleanup branch March 6, 2026 17:19
Aureliolo added a commit that referenced this pull request Mar 10, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.1](ai-company-v0.1.0...ai-company-v0.1.1)
(2026-03-10)


### Features

* add autonomy levels and approval timeout policies
([#42](#42),
[#126](#126))
([#197](#197))
([eecc25a](eecc25a))
* add CFO cost optimization service with anomaly detection, reports, and
approval decisions
([#186](#186))
([a7fa00b](a7fa00b))
* add code quality toolchain (ruff, mypy, pre-commit, dependabot)
([#63](#63))
([36681a8](36681a8))
* add configurable cost tiers and subscription/quota-aware tracking
([#67](#67))
([#185](#185))
([9baedfa](9baedfa))
* add container packaging, Docker Compose, and CI pipeline
([#269](#269))
([435bdfe](435bdfe)),
closes [#267](#267)
* add coordination error taxonomy classification pipeline
([#146](#146))
([#181](#181))
([70c7480](70c7480))
* add cost-optimized, hierarchical, and auction assignment strategies
([#175](#175))
([ce924fa](ce924fa)),
closes [#173](#173)
* add design specification, license, and project setup
([8669a09](8669a09))
* add env var substitution and config file auto-discovery
([#77](#77))
([7f53832](7f53832))
* add FastestStrategy routing + vendor-agnostic cleanup
([#140](#140))
([09619cb](09619cb)),
closes [#139](#139)
* add HR engine and performance tracking
([#45](#45),
[#47](#47))
([#193](#193))
([2d091ea](2d091ea))
* add issue auto-search and resolution verification to PR review skill
([#119](#119))
([deecc39](deecc39))
* add memory retrieval, ranking, and context injection pipeline
([#41](#41))
([873b0aa](873b0aa))
* add pluggable MemoryBackend protocol with models, config, and events
([#180](#180))
([46cfdd4](46cfdd4))
* add pluggable MemoryBackend protocol with models, config, and events
([#32](#32))
([46cfdd4](46cfdd4))
* add pluggable PersistenceBackend protocol with SQLite implementation
([#36](#36))
([f753779](f753779))
* add progressive trust and promotion/demotion subsystems
([#43](#43),
[#49](#49))
([3a87c08](3a87c08))
* add retry handler, rate limiter, and provider resilience
([#100](#100))
([b890545](b890545))
* add SecOps security agent with rule engine, audit log, and ToolInvoker
integration ([#40](#40))
([83b7b6c](83b7b6c))
* add shared org memory and memory consolidation/archival
([#125](#125),
[#48](#48))
([4a0832b](4a0832b))
* design unified provider interface
([#86](#86))
([3e23d64](3e23d64))
* expand template presets, rosters, and add inheritance
([#80](#80),
[#81](#81),
[#84](#84))
([15a9134](15a9134))
* implement agent runtime state vs immutable config split
([#115](#115))
([4cb1ca5](4cb1ca5))
* implement AgentEngine core orchestrator
([#11](#11))
([#143](#143))
([f2eb73a](f2eb73a))
* implement basic tool system (registry, invocation, results)
([#15](#15))
([c51068b](c51068b))
* implement built-in file system tools
([#18](#18))
([325ef98](325ef98))
* implement communication foundation — message bus, dispatcher, and
messenger ([#157](#157))
([8e71bfd](8e71bfd))
* implement company template system with 7 built-in presets
([#85](#85))
([cbf1496](cbf1496))
* implement conflict resolution protocol
([#122](#122))
([#166](#166))
([e03f9f2](e03f9f2))
* implement core entity and role system models
([#69](#69))
([acf9801](acf9801))
* implement crash recovery with fail-and-reassign strategy
([#149](#149))
([e6e91ed](e6e91ed))
* implement engine extensions — Plan-and-Execute loop and call
categorization
([#134](#134),
[#135](#135))
([#159](#159))
([9b2699f](9b2699f))
* implement enterprise logging system with structlog
([#73](#73))
([2f787e5](2f787e5))
* implement graceful shutdown with cooperative timeout strategy
([#130](#130))
([6592515](6592515))
* implement hierarchical delegation and loop prevention
([#12](#12),
[#17](#17))
([6be60b6](6be60b6))
* implement LiteLLM driver and provider registry
([#88](#88))
([ae3f18b](ae3f18b)),
closes [#4](#4)
* implement LLM decomposition strategy and workspace isolation
([#174](#174))
([aa0eefe](aa0eefe))
* implement meeting protocol system
([#123](#123))
([ee7caca](ee7caca))
* implement message and communication domain models
([#74](#74))
([560a5d2](560a5d2))
* implement model routing engine
([#99](#99))
([d3c250b](d3c250b))
* implement parallel agent execution
([#22](#22))
([#161](#161))
([65940b3](65940b3))
* implement per-call cost tracking service
([#7](#7))
([#102](#102))
([c4f1f1c](c4f1f1c))
* implement personality injection and system prompt construction
([#105](#105))
([934dd85](934dd85))
* implement single-task execution lifecycle
([#21](#21))
([#144](#144))
([c7e64e4](c7e64e4))
* implement subprocess sandbox for tool execution isolation
([#131](#131))
([#153](#153))
([3c8394e](3c8394e))
* implement task assignment subsystem with pluggable strategies
([#172](#172))
([c7f1b26](c7f1b26)),
closes [#26](#26)
[#30](#30)
* implement task decomposition and routing engine
([#14](#14))
([9c7fb52](9c7fb52))
* implement Task, Project, Artifact, Budget, and Cost domain models
([#71](#71))
([81eabf1](81eabf1))
* implement tool permission checking
([#16](#16))
([833c190](833c190))
* implement YAML config loader with Pydantic validation
([#59](#59))
([ff3a2ba](ff3a2ba))
* implement YAML config loader with Pydantic validation
([#75](#75))
([ff3a2ba](ff3a2ba))
* initialize project with uv, hatchling, and src layout
([39005f9](39005f9))
* initialize project with uv, hatchling, and src layout
([#62](#62))
([39005f9](39005f9))
* Litestar REST API, WebSocket feed, and approval queue (M6)
([#189](#189))
([29fcd08](29fcd08))
* make TokenUsage.total_tokens a computed field
([#118](#118))
([c0bab18](c0bab18)),
closes [#109](#109)
* parallel tool execution in ToolInvoker.invoke_all
([#137](#137))
([58517ee](58517ee))
* testing framework, CI pipeline, and M0 gap fixes
([#64](#64))
([f581749](f581749))
* wire all modules into observability system
([#97](#97))
([f7a0617](f7a0617))


### Bug Fixes

* address Greptile post-merge review findings from PRs
[#170](https://github.com/Aureliolo/ai-company/issues/170)-[#175](https://github.com/Aureliolo/ai-company/issues/175)
([#176](#176))
([c5ca929](c5ca929))
* address post-merge review feedback from PRs
[#164](https://github.com/Aureliolo/ai-company/issues/164)-[#167](https://github.com/Aureliolo/ai-company/issues/167)
([#170](#170))
([3bf897a](3bf897a)),
closes [#169](#169)
* enforce strict mypy on test files
([#89](#89))
([aeeff8c](aeeff8c))
* harden Docker sandbox, MCP bridge, and code runner
([#50](#50),
[#53](#53))
([d5e1b6e](d5e1b6e))
* harden git tools security + code quality improvements
([#150](#150))
([000a325](000a325))
* harden subprocess cleanup, env filtering, and shutdown resilience
([#155](#155))
([d1fe1fb](d1fe1fb))
* incorporate post-merge feedback + pre-PR review fixes
([#164](#164))
([c02832a](c02832a))
* pre-PR review fixes for post-merge findings
([#183](#183))
([26b3108](26b3108))
* strengthen immutability for BaseTool schema and ToolInvoker boundaries
([#117](#117))
([7e5e861](7e5e861))


### Performance

* harden non-inferable principle implementation
([#195](#195))
([02b5f4e](02b5f4e)),
closes [#188](#188)


### Refactoring

* adopt NotBlankStr across all models
([#108](#108))
([#120](#120))
([ef89b90](ef89b90))
* extract _SpendingTotals base class from spending summary models
([#111](#111))
([2f39c1b](2f39c1b))
* harden BudgetEnforcer with error handling, validation extraction, and
review fixes
([#182](#182))
([c107bf9](c107bf9))
* harden personality profiles, department validation, and template
rendering ([#158](#158))
([10b2299](10b2299))
* pre-PR review improvements for ExecutionLoop + ReAct loop
([#124](#124))
([8dfb3c0](8dfb3c0))
* split events.py into per-domain event modules
([#136](#136))
([e9cba89](e9cba89))


### Documentation

* add ADR-001 memory layer evaluation and selection
([#178](#178))
([db3026f](db3026f)),
closes [#39](#39)
* add agent scaling research findings to DESIGN_SPEC
([#145](#145))
([57e487b](57e487b))
* add CLAUDE.md, contributing guide, and dev documentation
([#65](#65))
([55c1025](55c1025)),
closes [#54](#54)
* add crash recovery, sandboxing, analytics, and testing decisions
([#127](#127))
([5c11595](5c11595))
* address external review feedback with MVP scope and new protocols
([#128](#128))
([3b30b9a](3b30b9a))
* expand design spec with pluggable strategy protocols
([#121](#121))
([6832db6](6832db6))
* finalize 23 design decisions (ADR-002)
([#190](#190))
([8c39742](8c39742))
* update project docs for M2.5 conventions and add docs-consistency
review agent
([#114](#114))
([99766ee](99766ee))


### Tests

* add e2e single agent integration tests
([#24](#24))
([#156](#156))
([f566fb4](f566fb4))
* add provider adapter integration tests
([#90](#90))
([40a61f4](40a61f4))


### CI/CD

* add Release Please for automated versioning and GitHub Releases
([#278](#278))
([a488758](a488758))
* bump actions/checkout from 4 to 6
([#95](#95))
([1897247](1897247))
* bump actions/upload-artifact from 4 to 7
([#94](#94))
([27b1517](27b1517))
* harden CI/CD pipeline
([#92](#92))
([ce4693c](ce4693c))
* split vulnerability scans into critical-fail and high-warn tiers
([#277](#277))
([aba48af](aba48af))


### Maintenance

* add /worktree skill for parallel worktree management
([#171](#171))
([951e337](951e337))
* add design spec context loading to research-link skill
([8ef9685](8ef9685))
* add post-merge-cleanup skill
([#70](#70))
([f913705](f913705))
* add pre-pr-review skill and update CLAUDE.md
([#103](#103))
([92e9023](92e9023))
* add research-link skill and rename skill files to SKILL.md
([#101](#101))
([651c577](651c577))
* bump aiosqlite from 0.21.0 to 0.22.1
([#191](#191))
([3274a86](3274a86))
* bump pyyaml from 6.0.2 to 6.0.3 in the minor-and-patch group
([#96](#96))
([0338d0c](0338d0c))
* bump ruff from 0.15.4 to 0.15.5
([a49ee46](a49ee46))
* fix M0 audit items
([#66](#66))
([c7724b5](c7724b5))
* pin setup-uv action to full SHA
([#281](#281))
([4448002](4448002))
* post-audit cleanup — PEP 758, loggers, bug fixes, refactoring, tests,
hookify rules
([#148](#148))
([c57a6a9](c57a6a9))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
Aureliolo added a commit that referenced this pull request Mar 11, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.0](v0.0.0...v0.1.0)
(2026-03-11)


### Features

* add autonomy levels and approval timeout policies
([#42](#42),
[#126](#126))
([#197](#197))
([eecc25a](eecc25a))
* add CFO cost optimization service with anomaly detection, reports, and
approval decisions
([#186](#186))
([a7fa00b](a7fa00b))
* add code quality toolchain (ruff, mypy, pre-commit, dependabot)
([#63](#63))
([36681a8](36681a8))
* add configurable cost tiers and subscription/quota-aware tracking
([#67](#67))
([#185](#185))
([9baedfa](9baedfa))
* add container packaging, Docker Compose, and CI pipeline
([#269](#269))
([435bdfe](435bdfe)),
closes [#267](#267)
* add coordination error taxonomy classification pipeline
([#146](#146))
([#181](#181))
([70c7480](70c7480))
* add cost-optimized, hierarchical, and auction assignment strategies
([#175](#175))
([ce924fa](ce924fa)),
closes [#173](#173)
* add design specification, license, and project setup
([8669a09](8669a09))
* add env var substitution and config file auto-discovery
([#77](#77))
([7f53832](7f53832))
* add FastestStrategy routing + vendor-agnostic cleanup
([#140](#140))
([09619cb](09619cb)),
closes [#139](#139)
* add HR engine and performance tracking
([#45](#45),
[#47](#47))
([#193](#193))
([2d091ea](2d091ea))
* add issue auto-search and resolution verification to PR review skill
([#119](#119))
([deecc39](deecc39))
* add mandatory JWT + API key authentication
([#256](#256))
([c279cfe](c279cfe))
* add memory retrieval, ranking, and context injection pipeline
([#41](#41))
([873b0aa](873b0aa))
* add pluggable MemoryBackend protocol with models, config, and events
([#180](#180))
([46cfdd4](46cfdd4))
* add pluggable MemoryBackend protocol with models, config, and events
([#32](#32))
([46cfdd4](46cfdd4))
* add pluggable output scan response policies
([#263](#263))
([b9907e8](b9907e8))
* add pluggable PersistenceBackend protocol with SQLite implementation
([#36](#36))
([f753779](f753779))
* add progressive trust and promotion/demotion subsystems
([#43](#43),
[#49](#49))
([3a87c08](3a87c08))
* add retry handler, rate limiter, and provider resilience
([#100](#100))
([b890545](b890545))
* add SecOps security agent with rule engine, audit log, and ToolInvoker
integration ([#40](#40))
([83b7b6c](83b7b6c))
* add shared org memory and memory consolidation/archival
([#125](#125),
[#48](#48))
([4a0832b](4a0832b))
* design unified provider interface
([#86](#86))
([3e23d64](3e23d64))
* expand template presets, rosters, and add inheritance
([#80](#80),
[#81](#81),
[#84](#84))
([15a9134](15a9134))
* implement agent runtime state vs immutable config split
([#115](#115))
([4cb1ca5](4cb1ca5))
* implement AgentEngine core orchestrator
([#11](#11))
([#143](#143))
([f2eb73a](f2eb73a))
* implement AuditRepository for security audit log persistence
([#279](#279))
([94bc29f](94bc29f))
* implement basic tool system (registry, invocation, results)
([#15](#15))
([c51068b](c51068b))
* implement built-in file system tools
([#18](#18))
([325ef98](325ef98))
* implement communication foundation — message bus, dispatcher, and
messenger ([#157](#157))
([8e71bfd](8e71bfd))
* implement company template system with 7 built-in presets
([#85](#85))
([cbf1496](cbf1496))
* implement conflict resolution protocol
([#122](#122))
([#166](#166))
([e03f9f2](e03f9f2))
* implement core entity and role system models
([#69](#69))
([acf9801](acf9801))
* implement crash recovery with fail-and-reassign strategy
([#149](#149))
([e6e91ed](e6e91ed))
* implement engine extensions — Plan-and-Execute loop and call
categorization
([#134](#134),
[#135](#135))
([#159](#159))
([9b2699f](9b2699f))
* implement enterprise logging system with structlog
([#73](#73))
([2f787e5](2f787e5))
* implement graceful shutdown with cooperative timeout strategy
([#130](#130))
([6592515](6592515))
* implement hierarchical delegation and loop prevention
([#12](#12),
[#17](#17))
([6be60b6](6be60b6))
* implement LiteLLM driver and provider registry
([#88](#88))
([ae3f18b](ae3f18b)),
closes [#4](#4)
* implement LLM decomposition strategy and workspace isolation
([#174](#174))
([aa0eefe](aa0eefe))
* implement meeting protocol system
([#123](#123))
([ee7caca](ee7caca))
* implement message and communication domain models
([#74](#74))
([560a5d2](560a5d2))
* implement model routing engine
([#99](#99))
([d3c250b](d3c250b))
* implement parallel agent execution
([#22](#22))
([#161](#161))
([65940b3](65940b3))
* implement per-call cost tracking service
([#7](#7))
([#102](#102))
([c4f1f1c](c4f1f1c))
* implement personality injection and system prompt construction
([#105](#105))
([934dd85](934dd85))
* implement single-task execution lifecycle
([#21](#21))
([#144](#144))
([c7e64e4](c7e64e4))
* implement subprocess sandbox for tool execution isolation
([#131](#131))
([#153](#153))
([3c8394e](3c8394e))
* implement task assignment subsystem with pluggable strategies
([#172](#172))
([c7f1b26](c7f1b26)),
closes [#26](#26)
[#30](#30)
* implement task decomposition and routing engine
([#14](#14))
([9c7fb52](9c7fb52))
* implement Task, Project, Artifact, Budget, and Cost domain models
([#71](#71))
([81eabf1](81eabf1))
* implement tool permission checking
([#16](#16))
([833c190](833c190))
* implement YAML config loader with Pydantic validation
([#59](#59))
([ff3a2ba](ff3a2ba))
* implement YAML config loader with Pydantic validation
([#75](#75))
([ff3a2ba](ff3a2ba))
* initialize project with uv, hatchling, and src layout
([39005f9](39005f9))
* initialize project with uv, hatchling, and src layout
([#62](#62))
([39005f9](39005f9))
* Litestar REST API, WebSocket feed, and approval queue (M6)
([#189](#189))
([29fcd08](29fcd08))
* make TokenUsage.total_tokens a computed field
([#118](#118))
([c0bab18](c0bab18)),
closes [#109](#109)
* parallel tool execution in ToolInvoker.invoke_all
([#137](#137))
([58517ee](58517ee))
* testing framework, CI pipeline, and M0 gap fixes
([#64](#64))
([f581749](f581749))
* wire all modules into observability system
([#97](#97))
([f7a0617](f7a0617))


### Bug Fixes

* address Greptile post-merge review findings from PRs
[#170](https://github.com/Aureliolo/ai-company/issues/170)-[#175](https://github.com/Aureliolo/ai-company/issues/175)
([#176](#176))
([c5ca929](c5ca929))
* address post-merge review feedback from PRs
[#164](https://github.com/Aureliolo/ai-company/issues/164)-[#167](https://github.com/Aureliolo/ai-company/issues/167)
([#170](#170))
([3bf897a](3bf897a)),
closes [#169](#169)
* enforce strict mypy on test files
([#89](#89))
([aeeff8c](aeeff8c))
* harden Docker sandbox, MCP bridge, and code runner
([#50](#50),
[#53](#53))
([d5e1b6e](d5e1b6e))
* harden git tools security + code quality improvements
([#150](#150))
([000a325](000a325))
* harden subprocess cleanup, env filtering, and shutdown resilience
([#155](#155))
([d1fe1fb](d1fe1fb))
* incorporate post-merge feedback + pre-PR review fixes
([#164](#164))
([c02832a](c02832a))
* pre-PR review fixes for post-merge findings
([#183](#183))
([26b3108](26b3108))
* resolve circular imports, bump litellm, fix release tag format
([#286](#286))
([a6659b5](a6659b5))
* strengthen immutability for BaseTool schema and ToolInvoker boundaries
([#117](#117))
([7e5e861](7e5e861))


### Performance

* harden non-inferable principle implementation
([#195](#195))
([02b5f4e](02b5f4e)),
closes [#188](#188)


### Refactoring

* adopt NotBlankStr across all models
([#108](#108))
([#120](#120))
([ef89b90](ef89b90))
* extract _SpendingTotals base class from spending summary models
([#111](#111))
([2f39c1b](2f39c1b))
* harden BudgetEnforcer with error handling, validation extraction, and
review fixes
([#182](#182))
([c107bf9](c107bf9))
* harden personality profiles, department validation, and template
rendering ([#158](#158))
([10b2299](10b2299))
* pre-PR review improvements for ExecutionLoop + ReAct loop
([#124](#124))
([8dfb3c0](8dfb3c0))
* split events.py into per-domain event modules
([#136](#136))
([e9cba89](e9cba89))


### Documentation

* add ADR-001 memory layer evaluation and selection
([#178](#178))
([db3026f](db3026f)),
closes [#39](#39)
* add agent scaling research findings to DESIGN_SPEC
([#145](#145))
([57e487b](57e487b))
* add CLAUDE.md, contributing guide, and dev documentation
([#65](#65))
([55c1025](55c1025)),
closes [#54](#54)
* add crash recovery, sandboxing, analytics, and testing decisions
([#127](#127))
([5c11595](5c11595))
* address external review feedback with MVP scope and new protocols
([#128](#128))
([3b30b9a](3b30b9a))
* expand design spec with pluggable strategy protocols
([#121](#121))
([6832db6](6832db6))
* finalize 23 design decisions (ADR-002)
([#190](#190))
([8c39742](8c39742))
* update project docs for M2.5 conventions and add docs-consistency
review agent
([#114](#114))
([99766ee](99766ee))


### Tests

* add e2e single agent integration tests
([#24](#24))
([#156](#156))
([f566fb4](f566fb4))
* add provider adapter integration tests
([#90](#90))
([40a61f4](40a61f4))


### CI/CD

* add Release Please for automated versioning and GitHub Releases
([#278](#278))
([a488758](a488758))
* bump actions/checkout from 4 to 6
([#95](#95))
([1897247](1897247))
* bump actions/upload-artifact from 4 to 7
([#94](#94))
([27b1517](27b1517))
* bump anchore/scan-action from 6.5.1 to 7.3.2
([#271](#271))
([80a1c15](80a1c15))
* bump docker/build-push-action from 6.19.2 to 7.0.0
([#273](#273))
([dd0219e](dd0219e))
* bump docker/login-action from 3.7.0 to 4.0.0
([#272](#272))
([33d6238](33d6238))
* bump docker/metadata-action from 5.10.0 to 6.0.0
([#270](#270))
([baee04e](baee04e))
* bump docker/setup-buildx-action from 3.12.0 to 4.0.0
([#274](#274))
([5fc06f7](5fc06f7))
* bump sigstore/cosign-installer from 3.9.1 to 4.1.0
([#275](#275))
([29dd16c](29dd16c))
* harden CI/CD pipeline
([#92](#92))
([ce4693c](ce4693c))
* split vulnerability scans into critical-fail and high-warn tiers
([#277](#277))
([aba48af](aba48af))


### Maintenance

* add /worktree skill for parallel worktree management
([#171](#171))
([951e337](951e337))
* add design spec context loading to research-link skill
([8ef9685](8ef9685))
* add post-merge-cleanup skill
([#70](#70))
([f913705](f913705))
* add pre-pr-review skill and update CLAUDE.md
([#103](#103))
([92e9023](92e9023))
* add research-link skill and rename skill files to SKILL.md
([#101](#101))
([651c577](651c577))
* bump aiosqlite from 0.21.0 to 0.22.1
([#191](#191))
([3274a86](3274a86))
* bump pyyaml from 6.0.2 to 6.0.3 in the minor-and-patch group
([#96](#96))
([0338d0c](0338d0c))
* bump ruff from 0.15.4 to 0.15.5
([a49ee46](a49ee46))
* fix M0 audit items
([#66](#66))
([c7724b5](c7724b5))
* **main:** release ai-company 0.1.1
([#282](#282))
([2f4703d](2f4703d))
* pin setup-uv action to full SHA
([#281](#281))
([4448002](4448002))
* post-audit cleanup — PEP 758, loggers, bug fixes, refactoring, tests,
hookify rules
([#148](#148))
([c57a6a9](c57a6a9))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Signed-off-by: Aurelio <19254254+Aureliolo@users.noreply.github.com>
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.

feat: add FastestStrategy routing + vendor-agnostic cleanup

2 participants