Cost Guard component for Strands-based multi-agent systems with budget enforcement, adaptive routing, and OpenTelemetry metrics
Project description
Strands CostGuard
A Strands-native cost management library for multi-agent systems with budget enforcement, adaptive model routing, and OpenTelemetry-compatible metrics.
Features
- Budget Enforcement: Define budgets at tenant, strand, workflow, and run levels with configurable limits and actions
- Adaptive Model Routing: Automatically route to fallback models based on budget utilization and other conditions
- Cost Tracking: Track and attribute costs by tenant, strand, workflow, run, model, and tool
- OpenTelemetry Metrics: Emit cost metrics compatible with OTel collectors for long-term storage and analysis
- Flexible Policies: Configure via YAML files or environment variables
- Persistent Budget State: Optional Valkey/Redis persistence for budget state across restarts
Installation
pip install strands-costguard
For persistence support:
pip install strands-costguard[valkey]
Quick Start
from strands_costguard import (
CostGuard,
CostGuardConfig,
FilePolicySource,
ModelUsage,
)
# Initialize Cost Guard
config = CostGuardConfig(
policy_source=FilePolicySource(path="./policies"),
enable_budget_enforcement=True,
enable_routing=True,
enable_metrics=True,
)
guard = CostGuard(config=config)
# Start a run
decision = guard.on_run_start(
tenant_id="prod-tenant",
strand_id="analytics_assistant",
workflow_id="data_analysis",
run_id="run-123",
)
if not decision.allowed:
print(f"Run rejected: {decision.reason}")
else:
# Execute your agent loop...
# Before model calls
model_decision = guard.before_model_call(
run_id="run-123",
model_name="gpt-4o",
stage="planning",
prompt_tokens_estimate=500,
)
# Use the effective model (may be downgraded)
effective_model = model_decision.effective_model
# After model calls
guard.after_model_call(
run_id="run-123",
usage=ModelUsage.from_response(
model_name=effective_model,
prompt_tokens=500,
completion_tokens=200,
),
)
# End the run
guard.on_run_end("run-123", "completed")
# Shutdown (flushes metrics)
guard.shutdown()
Configuration
Budget Policies (budgets.yaml)
budgets:
- id: "tenant-default"
scope: "tenant"
match:
tenant_id: "*"
period: "monthly"
max_cost: 1000.0
soft_thresholds: [0.7, 0.9, 1.0]
hard_limit: true
on_soft_threshold_exceeded: "DOWNGRADE_MODEL"
on_hard_limit_exceeded: "REJECT_NEW_RUNS"
- id: "analytics-strand"
scope: "strand"
match:
strand_id: "analytics_assistant"
period: "daily"
max_cost: 50.0
max_runs_per_period: 1000
max_concurrent_runs: 100
constraints:
max_iterations_per_run: 8
max_tool_calls_per_run: 20
max_model_tokens_per_run: 30000
Routing Policies (routing.yaml)
routing_policies:
- id: "default-routing"
match:
strand_id: "*"
stages:
- stage: "planning"
default_model: "gpt-4o-mini"
max_tokens: 2000
- stage: "synthesis"
default_model: "gpt-4o"
fallback_model: "gpt-4o-mini"
trigger_downgrade_on:
soft_threshold_exceeded: true
remaining_budget_below: 5.0
Pricing Table (pricing.yaml)
pricing:
currency: "USD"
models:
"gpt-4o":
input_per_1k: 2.50
output_per_1k: 10.00
"gpt-4o-mini":
input_per_1k: 0.15
output_per_1k: 0.60
tools:
"web_search":
cost_per_call: 0.01
Lifecycle Hooks
Cost Guard integrates with your agent runtime via lifecycle hooks:
| Hook | When Called | Returns |
|---|---|---|
on_run_start() |
Before starting a new run | AdmissionDecision |
on_run_end() |
After a run completes | None |
before_iteration() |
Before each agent loop iteration | IterationDecision |
after_iteration() |
After each iteration completes | None |
before_model_call() |
Before each model call | ModelDecision |
after_model_call() |
After each model call | None |
before_tool_call() |
Before each tool call | ToolDecision |
after_tool_call() |
After each tool call | None |
OpenTelemetry Metrics
Cost Guard emits the following metrics:
| Metric | Type | Description |
|---|---|---|
genai.cost.total |
Counter | Total cost in currency units |
genai.cost.model |
Counter | Cost per model |
genai.cost.tool |
Counter | Cost per tool |
genai.tokens.input |
Counter | Total input tokens |
genai.tokens.output |
Counter | Total output tokens |
genai.agent.iterations |
Counter | Agent loop iterations |
genai.agent.tool_calls |
Counter | Tool calls |
genai.cost.downgrade_events |
Counter | Model downgrade events |
genai.cost.rejection_events |
Counter | Run rejection events |
Metrics include resource attributes:
service.name,service.namespace,deployment.environmentstrands.tenant_id,strands.strand_id,strands.workflow_id
Budget Scopes and Priority
Budgets can be defined at multiple scopes, with higher priority scopes taking precedence:
- Global (lowest priority) - Default limits for all
- Tenant - Organization-level limits
- Strand - Agent definition limits
- Workflow (highest priority) - Specific workflow limits
When multiple budgets match, constraints are merged with more specific budgets taking priority.
Threshold Actions
When budget soft thresholds are exceeded:
| Action | Effect |
|---|---|
LOG_ONLY |
Log warning, continue normally |
DOWNGRADE_MODEL |
Switch to fallback models |
LIMIT_CAPABILITIES |
Reduce max tokens/iterations |
HALT_NEW_RUNS |
Reject new runs |
When hard limits are exceeded:
| Action | Effect |
|---|---|
HALT_RUN |
Stop the current run |
REJECT_NEW_RUNS |
Reject new runs only |
Development
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Type checking
mypy src/
# Linting
ruff check src/
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file strands_costguard-0.1.0.tar.gz.
File metadata
- Download URL: strands_costguard-0.1.0.tar.gz
- Upload date:
- Size: 72.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1716de129eb9a4bbd1d8aeda67539c2791286f1d0a150725be81626f02180063
|
|
| MD5 |
3880e4cb7a3dc800ab78d68543a69ef2
|
|
| BLAKE2b-256 |
9e40c289f851d2338e111924b2b1d9130bd19cc0b5ee0a7dd2d8b2e426c29823
|
Provenance
The following attestation bundles were made for strands_costguard-0.1.0.tar.gz:
Publisher:
publish.yml on wisemanIV/strands-costguard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
strands_costguard-0.1.0.tar.gz -
Subject digest:
1716de129eb9a4bbd1d8aeda67539c2791286f1d0a150725be81626f02180063 - Sigstore transparency entry: 757496133
- Sigstore integration time:
-
Permalink:
wisemanIV/strands-costguard@0c6e6ad75ba2c27221e6035c16d7bb303abb966f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/wisemanIV
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0c6e6ad75ba2c27221e6035c16d7bb303abb966f -
Trigger Event:
release
-
Statement type:
File details
Details for the file strands_costguard-0.1.0-py3-none-any.whl.
File metadata
- Download URL: strands_costguard-0.1.0-py3-none-any.whl
- Upload date:
- Size: 39.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d093534dea6de5ef3c2433e955881632440e81bf0cc63a5fbf1f4625cbc13bb9
|
|
| MD5 |
f6179294cd0eee63bdc296f8ea2180a6
|
|
| BLAKE2b-256 |
178aef4b520aedfd4af43350073feea4c4b776e5c4eec0065f172b38ebea0fb1
|
Provenance
The following attestation bundles were made for strands_costguard-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on wisemanIV/strands-costguard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
strands_costguard-0.1.0-py3-none-any.whl -
Subject digest:
d093534dea6de5ef3c2433e955881632440e81bf0cc63a5fbf1f4625cbc13bb9 - Sigstore transparency entry: 757496134
- Sigstore integration time:
-
Permalink:
wisemanIV/strands-costguard@0c6e6ad75ba2c27221e6035c16d7bb303abb966f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/wisemanIV
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0c6e6ad75ba2c27221e6035c16d7bb303abb966f -
Trigger Event:
release
-
Statement type: