feat: add FastestStrategy routing + vendor-agnostic cleanup#140
feat: add FastestStrategy routing + vendor-agnostic cleanup#140
Conversation
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>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Summary of ChangesHello, 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 Highlights
Changelog
Activity
Using Gemini Code AssistThe 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
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 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
|
Greptile SummaryThis PR introduces Key changes:
Issues found:
Confidence Score: 4/5
Sequence DiagramsequenceDiagram
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
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (10)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR introduces the Changes
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)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes The review complexity spans multiple dimensions: the new Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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.
| logger.warning( | ||
| ROUTING_BUDGET_EXCEEDED, | ||
| remaining_budget=remaining_budget, | ||
| cheapest_cost=cheapest_cost, | ||
| ) |
There was a problem hiding this comment.
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.
| 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, | |
| ) |
| logger.warning( | ||
| ROUTING_BUDGET_EXCEEDED, | ||
| remaining_budget=remaining_budget, | ||
| fastest_cost=fastest_cost, | ||
| ) |
There was a problem hiding this comment.
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.
| 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, | |
| ) |
There was a problem hiding this comment.
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
FastestStrategyrouting strategy and register it in routing strategy maps/exports. - Add
estimated_latency_mstoProviderModelConfigandResolvedModel, wire it throughModelResolver, and addall_models_sorted_by_latency(). - Refactor routing helpers into
_strategy_helpers.pyand 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.
| # Pick fastest | ||
| model, budget_exceeded = _fastest_within_budget( | ||
| resolver, | ||
| request.remaining_budget, | ||
| ) | ||
| reason = f"Fastest available: {model.model_id}" |
There was a problem hiding this comment.
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.
| # 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)" | |
| ) |
| logger.info( | ||
| ROUTING_FALLBACK_ATTEMPTED, | ||
| source="fastest_within_budget", | ||
| reason="no latency data, delegating to cheapest", |
There was a problem hiding this comment.
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).
| reason="no latency data, delegating to cheapest", | |
| reason="no latency data, delegating to cheapest", | |
| ref=None, |
| logger.warning( | ||
| ROUTING_BUDGET_EXCEEDED, | ||
| remaining_budget=remaining_budget, | ||
| fastest_cost=fastest_cost, |
There was a problem hiding this comment.
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.
| fastest_cost=fastest_cost, | |
| selected_cost=fastest_cost, | |
| model=fastest.model_id, |
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. |
There was a problem hiding this comment.
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.
| - **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. |
| - **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 |
There was a problem hiding this comment.
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.
| - **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 |
There was a problem hiding this comment.
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 | 🟡 MinorAdd
_strategy_helpers.pyto 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 strategiesBased 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
📒 Files selected for processing (43)
CLAUDE.mdDESIGN_SPEC.mdREADME.mdsrc/ai_company/budget/config.pysrc/ai_company/config/schema.pysrc/ai_company/core/agent.pysrc/ai_company/providers/__init__.pysrc/ai_company/providers/capabilities.pysrc/ai_company/providers/drivers/__init__.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/models.pysrc/ai_company/providers/registry.pysrc/ai_company/providers/routing/__init__.pysrc/ai_company/providers/routing/_strategy_helpers.pysrc/ai_company/providers/routing/models.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/routing/strategies.pytests/integration/providers/conftest.pytests/integration/providers/test_anthropic_pipeline.pytests/integration/providers/test_error_scenarios.pytests/integration/providers/test_openrouter_pipeline.pytests/integration/providers/test_tool_calling_pipeline.pytests/unit/budget/conftest.pytests/unit/budget/test_config.pytests/unit/budget/test_cost_record.pytests/unit/config/conftest.pytests/unit/config/test_loader.pytests/unit/config/test_schema.pytests/unit/core/conftest.pytests/unit/core/test_agent.pytests/unit/providers/drivers/conftest.pytests/unit/providers/drivers/test_litellm_driver.pytests/unit/providers/routing/conftest.pytests/unit/providers/routing/test_models.pytests/unit/providers/routing/test_resolver.pytests/unit/providers/routing/test_router.pytests/unit/providers/routing/test_strategies.pytests/unit/providers/test_errors.pytests/unit/providers/test_registry.pytests/unit/templates/conftest.pytests/unit/templates/test_renderer.pytests/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: Nofrom __future__ import annotationsin Python code — Python 3.14 has PEP 649 native lazy annotations
Useexcept 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_fieldfor 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.pysrc/ai_company/providers/__init__.pytests/integration/providers/conftest.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/providers/routing/__init__.pytests/unit/providers/routing/test_router.pytests/unit/providers/test_registry.pytests/unit/core/conftest.pytests/unit/templates/test_renderer.pytests/unit/config/test_loader.pysrc/ai_company/providers/registry.pytests/unit/providers/routing/test_resolver.pytests/unit/providers/routing/test_models.pytests/unit/templates/conftest.pytests/unit/providers/routing/test_strategies.pytests/unit/core/test_agent.pytests/integration/providers/test_openrouter_pipeline.pytests/integration/providers/test_error_scenarios.pytests/unit/budget/test_cost_record.pytests/unit/providers/drivers/test_litellm_driver.pysrc/ai_company/providers/routing/models.pysrc/ai_company/providers/drivers/__init__.pytests/unit/budget/test_config.pysrc/ai_company/providers/models.pytests/unit/providers/test_errors.pysrc/ai_company/providers/capabilities.pytests/unit/templates/test_schema.pysrc/ai_company/core/agent.pytests/unit/config/test_schema.pysrc/ai_company/providers/drivers/mappers.pytests/unit/config/conftest.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/routing/strategies.pytests/integration/providers/test_anthropic_pipeline.pytests/unit/budget/conftest.pysrc/ai_company/budget/config.pytests/unit/providers/drivers/conftest.pytests/unit/providers/routing/conftest.pytests/integration/providers/test_tool_calling_pipeline.pysrc/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.pysrc/ai_company/providers/__init__.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/providers/routing/__init__.pysrc/ai_company/providers/registry.pysrc/ai_company/providers/routing/models.pysrc/ai_company/providers/drivers/__init__.pysrc/ai_company/providers/models.pysrc/ai_company/providers/capabilities.pysrc/ai_company/core/agent.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/routing/strategies.pysrc/ai_company/budget/config.pysrc/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__.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/providers/routing/__init__.pysrc/ai_company/providers/registry.pysrc/ai_company/providers/routing/models.pysrc/ai_company/providers/drivers/__init__.pysrc/ai_company/providers/models.pysrc/ai_company/providers/capabilities.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/routing/strategies.pysrc/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__.pysrc/ai_company/providers/drivers/litellm_driver.pysrc/ai_company/providers/routing/__init__.pysrc/ai_company/providers/registry.pysrc/ai_company/providers/routing/models.pysrc/ai_company/providers/drivers/__init__.pysrc/ai_company/providers/models.pysrc/ai_company/providers/capabilities.pysrc/ai_company/providers/drivers/mappers.pysrc/ai_company/providers/routing/resolver.pysrc/ai_company/providers/routing/strategies.pysrc/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.pytests/unit/providers/routing/test_router.pytests/unit/providers/test_registry.pytests/unit/core/conftest.pytests/unit/templates/test_renderer.pytests/unit/config/test_loader.pytests/unit/providers/routing/test_resolver.pytests/unit/providers/routing/test_models.pytests/unit/templates/conftest.pytests/unit/providers/routing/test_strategies.pytests/unit/core/test_agent.pytests/integration/providers/test_openrouter_pipeline.pytests/integration/providers/test_error_scenarios.pytests/unit/budget/test_cost_record.pytests/unit/providers/drivers/test_litellm_driver.pytests/unit/budget/test_config.pytests/unit/providers/test_errors.pytests/unit/templates/test_schema.pytests/unit/config/test_schema.pytests/unit/config/conftest.pytests/integration/providers/test_anthropic_pipeline.pytests/unit/budget/conftest.pytests/unit/providers/drivers/conftest.pytests/unit/providers/routing/conftest.pytests/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.pytests/integration/providers/conftest.pytests/unit/config/test_loader.pytests/unit/providers/routing/test_strategies.pytests/integration/providers/test_error_scenarios.pytests/unit/providers/drivers/test_litellm_driver.pytests/unit/providers/test_errors.pytests/unit/config/test_schema.pytests/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.pyCLAUDE.mdtests/unit/providers/test_registry.pytests/unit/core/conftest.pytests/unit/config/test_loader.pytests/unit/providers/routing/test_resolver.pytests/unit/providers/routing/test_models.pytests/unit/core/test_agent.pytests/integration/providers/test_error_scenarios.pytests/unit/providers/drivers/test_litellm_driver.pytests/unit/providers/test_errors.pytests/unit/config/test_schema.pytests/unit/config/conftest.pytests/integration/providers/test_anthropic_pipeline.pytests/unit/providers/drivers/conftest.pytests/unit/providers/routing/conftest.pytests/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.pytests/unit/providers/test_registry.pytests/integration/providers/test_error_scenarios.pytests/unit/providers/drivers/test_litellm_driver.pysrc/ai_company/providers/drivers/__init__.pytests/unit/providers/test_errors.pytests/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.mdDESIGN_SPEC.mdREADME.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.mdREADME.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.mdtests/unit/core/conftest.pytests/unit/providers/routing/test_resolver.pytests/unit/providers/routing/test_models.pytests/unit/templates/conftest.pytests/unit/core/test_agent.pytests/unit/providers/drivers/test_litellm_driver.pytests/unit/providers/test_errors.pytests/unit/config/test_schema.pytests/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.mdtests/unit/templates/conftest.pytests/unit/core/test_agent.pytests/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.mdtests/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.mdtests/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.mdREADME.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.mdtests/unit/core/test_agent.pysrc/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.pytests/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.pytests/unit/providers/drivers/test_litellm_driver.pytests/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-128and 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
BaseCompletionProvidercontract.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 withProviderError.__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 intest_agent.py(per the relevant code snippet showingassert 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_mapvalues are correctly updated to use vendor-agnostic tier aliases (large→medium→small), 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_dicthelper 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_msfield is well-defined with appropriate constraints:
- Optional (
int | None) withdefault=Nonefor backward compatibilitygt=0ensures positive values onlyle=300_000caps 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:
anthropic→example-provider- Model alias:
sonnet→medium- 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_URLtoEXAMPLE_PROVIDER_BASE_URLwith 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_msfield:
- Default
Nonevalue- Valid positive integer
- Zero rejection (validates
gt=0constraint)- Negative value rejection
- Upper bound violation (validates
le=300_000constraint)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 thesample_model_configfixture 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()tomake_provider_config()with all vendor-specific references removed:
- Provider key:
anthropic→example-provider- API key:
sk-ant-test-key→sk-test-key- Model aliases:
sonnet/haiku→medium/smallAll 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_msprovide good coverage of edge cases: defaultNone, 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_msfield is correctly wired frommodel_configto theResolvedModelconstructor, maintaining consistency with other config fields.
191-205: LGTM! Latency-sorted model retrieval.The implementation correctly handles
Nonelatency by treating it as infinity, ensuring models without latency data sort last. The approach mirrors the existingall_models_sorted_by_costpattern.src/ai_company/providers/__init__.py (1)
50-51: LGTM! Public API surface updated correctly.
STRATEGY_NAME_FASTESTandFastestStrategyare 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_msfield is properly defined with:
- Default
Nonefor models without latency data- Validation
gt=0to reject zero/negative values- Upper bound
le=300_000(5 minutes) as a reasonable ceilingThe frozen model ensures immutability after construction.
63-63: LGTM! Docstring updated for FastestStrategy.The
RoutingRequestdocstring correctly documents thatFastestStrategyusestask_typeandremaining_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()andregistry.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(formerlytest_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
TestResolverSortByLatencyclass provides thorough coverage:
test_sorted_ascending: Validates ascending latency ordertest_none_sorted_last: ConfirmsNonelatency models sort after those with valuestest_all_none_returns_all: Handles edge case where no models have latency datatest_wired_from_config: Validates latency propagation through the config pipelineAll 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
FastestStrategyin the protocol conformance check and verifies thatSTRATEGY_MAPnow 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_driverand_collect_streamhelper 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_budgetwhen 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
CostAwareStrategyfor consistency
45-47: LGTM! Strategy name constant properly defined.The
STRATEGY_NAME_FASTESTconstant follows the naming convention of other strategy constants.
527-539: LGTM! Strategy registry correctly updated.The
_FASTESTsingleton is properly instantiated and registered inSTRATEGY_MAPunder 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_candidatecorrectly handles deduplication.The function properly:
- Skips already-seen refs to avoid redundant resolution attempts
- Records failed attempts in both
triedlist andseenset- Logs fallback attempts at DEBUG level with structured data
47-93: LGTM!_try_resolve_with_fallbackimplements proper fallback hierarchy.The function correctly implements the three-stage resolution:
- Primary reference
- Rule-specific fallback
- Global fallback chain
Raises
NoAvailableModelErrorwith context when all candidates are exhausted.
148-156: LGTM!_within_budgetis a clean budget check utility.Simple and correct implementation that handles the
Nonebudget case (unlimited budget) properly.
158-196: LGTM!_cheapest_within_budgetcorrectly 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=Truewhen all models exceed budget- Logs appropriately at WARNING level when budget is exceeded
198-253: LGTM!_fastest_within_budgetimplements correct latency-based selection with fallback.The implementation correctly:
- Falls back to
_cheapest_within_budgetwhen 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_rulescleanly encapsulates task-type rule matching.The function properly:
- Returns
Noneearly if no task_type in request- Matches rules by task_type and resolves with fallback support
- Returns a complete
RoutingDecisionwith reason and fallbacks_tried- Logs at DEBUG when no rule matches
292-364: LGTM!_try_role_rulesand_try_seniority_defaultfollow consistent patterns.Both functions:
- Return
Noneearly when preconditions aren't met- Use appropriate logging levels (DEBUG for no match, WARNING/INFO for unexpected states)
- Return complete
RoutingDecisionobjects 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>
🤖 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).
🤖 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>
Summary
estimated_latency_msfield: Added toProviderModelConfigandResolvedModelwithgt=0, le=300_000boundsall_models_sorted_by_latency(): New method onModelResolverfor latency-ordered model retrievalstrategies.pyinto_strategy_helpers.pyto stay under the 800-line file limitsrc/docstrings and commentscloses #139
Files changed (13)
strategies.py,_strategy_helpers.py(new),resolver.py,models.pyschema.pycapabilities.py,mappers.py,litellm_driver.py,config.pyDESIGN_SPEC.mdtest_strategies.py,test_models.py,test_schema.pyTest plan
pytest -n auto)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