Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ uv run pre-commit run --all-files # all pre-commit hooks
```text
src/ai_company/
api/ # FastAPI REST + WebSocket routes
budget/ # Cost tracking, budget enforcement (pre-flight/in-flight checks, auto-downgrade), billing periods, cost tiers, quota/subscription tracking
budget/ # Cost tracking, budget enforcement (pre-flight/in-flight checks, auto-downgrade), billing periods, cost tiers, quota/subscription tracking, CFO cost optimization (anomaly detection, efficiency analysis, downgrade recommendations, approval decisions), spending reports
cli/ # Typer CLI commands
communication/ # Message bus, dispatcher, messenger, channels, delegation, loop prevention, conflict resolution, meeting protocol
config/ # YAML company config loading and validation
Expand Down Expand Up @@ -83,7 +83,7 @@ src/ai_company/
- **Every module** with business logic MUST have: `from ai_company.observability import get_logger` then `logger = get_logger(__name__)`
- **Never** use `import logging` / `logging.getLogger()` / `print()` in application code
- **Variable name**: always `logger` (not `_logger`, not `log`)
- **Event names**: always use constants from the domain-specific module under `ai_company.observability.events` (e.g. `PROVIDER_CALL_START` from `events.provider`, `BUDGET_RECORD_ADDED` from `events.budget`, `CONFLICT_DETECTED` from `events.conflict`, `MEETING_STARTED` from `events.meeting`, `CLASSIFICATION_START` from `events.classification`). Import directly: `from ai_company.observability.events.<domain> import EVENT_CONSTANT`
- **Event names**: always use constants from the domain-specific module under `ai_company.observability.events` (e.g. `PROVIDER_CALL_START` from `events.provider`, `BUDGET_RECORD_ADDED` from `events.budget`, `CFO_ANOMALY_DETECTED` from `events.cfo`, `CONFLICT_DETECTED` from `events.conflict`, `MEETING_STARTED` from `events.meeting`, `CLASSIFICATION_START` from `events.classification`). Import directly: `from ai_company.observability.events.<domain> import EVENT_CONSTANT`
- **Structured kwargs**: always `logger.info(EVENT, key=value)` — never `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
Expand Down
11 changes: 10 additions & 1 deletion DESIGN_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -1845,6 +1845,13 @@ The CFO agent (when enabled) acts as a cost management system:
- Blocks tasks that would exceed remaining budget
- Optimizes model routing for cost/quality balance

> **Implementation note (M5):** `CostOptimizer` service (`budget/optimizer.py`)
> implements anomaly detection (sigma + spike factor), per-agent efficiency
> analysis, model downgrade recommendations (via `ModelResolver`), and
> operation approval evaluation. `ReportGenerator` service
> (`budget/reports.py`) produces multi-dimensional spending reports with
> task/provider/model breakdowns and period-over-period comparison.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

### 10.4 Cost Controls

> **Minimal config:**
Expand Down Expand Up @@ -2839,6 +2846,7 @@ ai-company/
│ │ ├── events/ # Per-domain event constants
│ │ │ ├── __init__.py # Package marker with usage docs; no re-exports
│ │ │ ├── budget.py # BUDGET_* constants
│ │ │ ├── cfo.py # CFO_* constants
│ │ │ ├── classification.py # CLASSIFICATION_* constants
│ │ │ ├── company.py # COMPANY_* constants
│ │ │ ├── communication.py # COMM_* constants
Expand Down Expand Up @@ -2942,7 +2950,8 @@ ai-company/
│ │ ├── enums.py # Budget-related enums
│ │ ├── billing.py # Billing period computation utilities
│ │ ├── enforcer.py # BudgetEnforcer service (pre-flight, in-flight, auto-downgrade)
│ │ ├── optimizer.py # Cost optimization / CFO logic (M5)
│ │ ├── optimizer.py # CostOptimizer service — anomaly detection, efficiency analysis, downgrade recommendations, approval decisions (M5)
│ │ ├── optimizer_models.py # CostOptimizer domain models — anomaly, efficiency, downgrade, approval, config (M5)
│ │ ├── quota.py # Quota/subscription models, degradation config, quota snapshots
│ │ ├── quota_tracker.py # QuotaTracker service: per-provider request/token quota enforcement
│ │ └── reports.py # Spending reports (M5)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ AI Company lets you spin up a virtual organization staffed entirely by AI agents
- **Persistence Layer (M5)** - Pluggable `PersistenceBackend` protocol with SQLite backend (aiosqlite), repository protocols, schema migrations
- **Memory Interface (M5)** - Pluggable `MemoryBackend` protocol with capability discovery, shared knowledge protocol, domain models, config, factory, and context injection retrieval pipeline (ranking, token-budget formatting)
- **Coordination Error Taxonomy (M5)** - Post-execution classification pipeline detecting logical contradictions, numerical drift, context omissions, and coordination failures
- **Budget Enforcement (M5)** - `BudgetEnforcer` service with pre-flight checks, in-flight budget checking, auto-downgrade, configurable cost tiers, and quota/subscription tracking; CFO agent and advanced reporting pending
- **Budget Enforcement (M5)** - `BudgetEnforcer` service with pre-flight checks, in-flight budget checking, auto-downgrade, configurable cost tiers, and quota/subscription tracking; `CostOptimizer` CFO service with anomaly detection, efficiency analysis, downgrade recommendations, and approval decisions; `ReportGenerator` for multi-dimensional spending reports

### Not implemented yet (planned milestones)

Expand Down
40 changes: 40 additions & 0 deletions src/ai_company/budget/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@
DepartmentBudget,
TeamBudget,
)
from ai_company.budget.optimizer import CostOptimizer
from ai_company.budget.optimizer_models import (
AgentEfficiency,
AnomalyDetectionResult,
AnomalySeverity,
AnomalyType,
ApprovalDecision,
CostOptimizerConfig,
DowngradeAnalysis,
DowngradeRecommendation,
EfficiencyAnalysis,
EfficiencyRating,
SpendingAnomaly,
)
from ai_company.budget.quota import (
DegradationAction,
DegradationConfig,
Expand All @@ -55,6 +69,14 @@
effective_cost_per_1k,
)
from ai_company.budget.quota_tracker import QuotaTracker
from ai_company.budget.reports import (
ModelDistribution,
PeriodComparison,
ProviderDistribution,
ReportGenerator,
SpendingReport,
TaskSpending,
)
from ai_company.budget.spending_summary import (
AgentSpending,
DepartmentSpending,
Expand All @@ -65,7 +87,12 @@

__all__ = [
"BUILTIN_TIERS",
"AgentEfficiency",
"AgentSpending",
"AnomalyDetectionResult",
"AnomalySeverity",
"AnomalyType",
"ApprovalDecision",
"AutoDowngradeConfig",
"BudgetAlertConfig",
"BudgetAlertLevel",
Expand All @@ -78,6 +105,8 @@
"CoordinationMetrics",
"CoordinationMetricsConfig",
"CoordinationOverhead",
"CostOptimizer",
"CostOptimizerConfig",
"CostRecord",
"CostTierDefinition",
"CostTiersConfig",
Expand All @@ -86,24 +115,35 @@
"DegradationConfig",
"DepartmentBudget",
"DepartmentSpending",
"DowngradeAnalysis",
"DowngradeRecommendation",
"EfficiencyAnalysis",
"EfficiencyRating",
"ErrorAmplification",
"ErrorCategory",
"ErrorTaxonomyConfig",
"LLMCallCategory",
"MessageDensity",
"ModelDistribution",
"OrchestrationAlertLevel",
"OrchestrationAlertThresholds",
"OrchestrationRatio",
"PeriodComparison",
"PeriodSpending",
"ProviderCostModel",
"ProviderDistribution",
"QuotaCheckResult",
"QuotaLimit",
"QuotaSnapshot",
"QuotaTracker",
"QuotaWindow",
"RedundancyRate",
"ReportGenerator",
"SpendingAnomaly",
"SpendingReport",
"SpendingSummary",
"SubscriptionConfig",
"TaskSpending",
"TeamBudget",
"billing_period_start",
"classify_model_tier",
Expand Down
Loading