pycsamt.api.agents#
pycsamt.api.agents#
Global LLM provider configuration for all pycsamt agents.
Configure once — every agent inherits the active provider, API key, model, pricing overrides, and budget cap automatically.
Quick start#
from pycsamt.api.agents import AGENT_CONFIG
AGENT_CONFIG.configure(provider="claude", api_key="sk-ant-…")
from pycsamt.agents import DataQCAgent, PhaseAnalysisAgent
qc = DataQCAgent() # inherits provider + key automatically
pt = PhaseAnalysisAgent() # same
Or use the top-level convenience function:
from pycsamt.agents import configure_agents
configure_agents(provider="openai", api_key="sk-…")
Multi-provider workflow#
Store keys for several providers upfront, then switch freely:
AGENT_CONFIG.set_key("claude", "sk-ant-…")
AGENT_CONFIG.set_key("openai", "sk-…")
AGENT_CONFIG.set_key("gemini", "AIza…")
AGENT_CONFIG.switch("claude") # all agents use Claude
# … some work …
AGENT_CONFIG.switch("openai") # now all agents use OpenAI, no re-supply
Temporary override (context manager)#
with AGENT_CONFIG.using(provider="gemini", api_key="AIza…"):
r = DataQCAgent().execute({"path": "/data"})
# original config is automatically restored here
Pricing — custom rates#
Override any rate or add a model not in the built-in table:
# update a rate that changed (USD per 1 M tokens)
AGENT_CONFIG.set_rate("claude", "claude-opus-4-8", input=12.0, output=60.0)
# register a model that isn't in the table yet
AGENT_CONFIG.set_rate("openai", "gpt-5-turbo", input=5.0, output=20.0)
# inspect the resolved rate for any provider/model
print(AGENT_CONFIG.get_rate("claude", "claude-sonnet-4-6"))
# → {"input": 3.0, "output": 15.0}
Pricing — session budget cap#
AGENT_CONFIG.set_budget(usd=2.0) # raise BudgetExceededError above $2
AGENT_CONFIG.spent_usd # float — accumulated so far
AGENT_CONFIG.remaining_usd # float or None (None = no cap)
AGENT_CONFIG.reset_budget() # zero the spend counter; keeps the cap
AGENT_CONFIG.reset_budget(cap=True) # also remove the cap
Environment-variable fallback#
Keys are resolved in this order:
Explicit key stored via
AgentConfig.configure()/AgentConfig.set_key().Environment variable (first match wins per provider):
Provider
Environment variables checked
"claude"ANTHROPIC_API_KEY,PYCSAMT_CLAUDE_API_KEY"openai"OPENAI_API_KEY,PYCSAMT_OPENAI_API_KEY"gemini"GEMINI_API_KEY,GOOGLE_API_KEY,GOOGLE_GENERATIVEAI_API_KEY,PYCSAMT_GEMINI_API_KEY"deepseek"DEEPSEEK_API_KEY,PYCSAMT_DEEPSEEK_API_KEY"minimax"MINIMAX_API_KEY,MINIMAX_M3,PYCSAMT_MINIMAX_API_KEY
Keys are also loaded automatically from .env.local at the repo root
(without overwriting variables already set in the OS environment).
None— agent runs without LLM support (regex/rule-based fallback).
Module Attributes
Global singleton. |
Functions
|
Configure |
|
Reset |
Classes
Global LLM configuration singleton for all pycsamt agents. |
Exceptions
|
Raised when an LLM call would be made after the session budget is used. |
- class pycsamt.api.agents.AgentConfig[source]#
Bases:
objectGlobal LLM configuration singleton for all pycsamt agents.
BaseAgentcallsresolve()on every instantiation andget_rate()+_add_spend()on every LLM call, so keys, rates, and the budget cap set here apply automatically to every agent in the session.:param (none — use
configure()after construction):- Variables:
provider (str or None) – Currently active LLM provider.
model (str or None) – Resolved model (explicit override or provider default).
api_key (str or None) – Resolved key for the active provider (stored key → env var → None).
is_configured (bool) –
Truewhen a provider and a resolvable key are both present.spent_usd (float) – Accumulated LLM spend this session.
remaining_usd (float or None) – Remaining budget, or
Nonewhen no cap is set.
Examples
from pycsamt.api.agents import AGENT_CONFIG # one-call setup AGENT_CONFIG.configure(provider="claude", api_key="sk-ant-…") # pricing — override a rate (USD / 1 M tokens) AGENT_CONFIG.set_rate("claude", "claude-opus-4-8", input=12.0, output=60.0) # pricing — add a model not in the built-in table AGENT_CONFIG.set_rate("openai", "gpt-5-turbo", input=5.0, output=20.0) # budget cap AGENT_CONFIG.set_budget(usd=5.0) print(AGENT_CONFIG.remaining_usd) # 5.0 # inspect print(AGENT_CONFIG.info()) # reset AGENT_CONFIG.reset()
- configure(*, provider, api_key, model=None)[source]#
Set the active provider, key, and optional model in one call.
- Parameters:
- Returns:
self — allows chaining.
- Return type:
Examples
AGENT_CONFIG.configure(provider="claude", api_key="sk-ant-…") AGENT_CONFIG.configure( provider="openai", api_key="sk-…", model="gpt-4o-mini", )
- set_key(provider, api_key)[source]#
Store an API key for provider without changing the active provider.
Useful for pre-loading keys for multiple providers so you can
switch()between them without re-supplying credentials.- Parameters:
- Returns:
self.
- Return type:
Examples
AGENT_CONFIG.set_key("claude", "sk-ant-…") AGENT_CONFIG.set_key("openai", "sk-…") AGENT_CONFIG.set_key("gemini", "AIza…") AGENT_CONFIG.switch("claude")
- switch(provider, *, model=None)[source]#
Switch the active provider.
The key for provider must have been stored via
configure()orset_key(), or be available as an environment variable.- Parameters:
- Returns:
self.
- Return type:
Examples
AGENT_CONFIG.switch("openai") AGENT_CONFIG.switch("gemini", model="gemini-2.0-flash")
- reset(*, keys=True)[source]#
Clear the active configuration, custom rates, and budget.
- Parameters:
keys (bool) – When
True(default) also wipe all stored per-provider keys. PassFalseto clear only the active provider / model while keeping stored keys available for futureswitch()calls.- Returns:
self.
- Return type:
Notes
Custom rates and the budget cap/counter are always reset. Call
reset_budget()to zero only the spend counter.
- set_rate(provider, model, *, input, output)[source]#
Override or add the cost rate for a specific provider + model.
Custom rates take precedence over the built-in table for every cost estimate made by agents in this session.
- Parameters:
- Returns:
self.
- Return type:
Examples
# provider lowered their price AGENT_CONFIG.set_rate("claude", "claude-opus-4-8", input=12.0, output=60.0) # a new model not yet in the built-in table AGENT_CONFIG.set_rate("openai", "gpt-5-turbo", input=5.0, output=20.0)
- get_rate(provider, model)[source]#
Return the resolved
{"input": …, "output": …}rate.Resolution order: custom override → built-in table (exact match → prefix match) → provider default.
- Parameters:
- Return type:
dict with keys
"input"and"output"(USD / 1 M tokens).
Examples
rate = AGENT_CONFIG.get_rate("claude", "claude-sonnet-4-6") # {"input": 3.0, "output": 15.0}
- estimate_cost(provider, model, input_tokens, output_tokens)[source]#
Compute the USD cost for one LLM call using the resolved rate.
Respects any rate overrides set via
set_rate().- Parameters:
- Return type:
float — estimated cost in USD.
Examples
cost = AGENT_CONFIG.estimate_cost( "claude", "claude-sonnet-4-6", 500, 200 )
- list_rates(provider=None)[source]#
Return the effective rate table (custom overrides merged with built-in).
- Parameters:
provider (str or None) – When given, return only that provider’s table. When
None, return all providers.- Return type:
dict — same structure as the built-in table.
Examples
import pprint pprint.pprint(AGENT_CONFIG.list_rates("claude"))
- set_budget(*, usd)[source]#
Set a session spend cap.
Once
spent_usdreaches usd, any subsequent LLM call will raiseBudgetExceededErrorbefore the API call is made.- Parameters:
usd (float) – Maximum spend in USD for this session.
- Returns:
self.
- Return type:
Examples
AGENT_CONFIG.set_budget(usd=2.0) # … after several agent calls … print(f"${AGENT_CONFIG.spent_usd:.4f} used, " f"${AGENT_CONFIG.remaining_usd:.4f} left")
- reset_budget(*, cap=False)[source]#
Reset the session spend counter.
- Parameters:
cap (bool) – When
Truealso remove the budget cap (set_budgetmust be called again to re-enable it). DefaultFalse— zeroes the counter but keeps the existing cap.- Returns:
self.
- Return type:
Examples
AGENT_CONFIG.reset_budget() # zero counter, keep cap AGENT_CONFIG.reset_budget(cap=True) # zero counter and remove cap
- property api_key: str | None[source]#
Resolved key for the active provider.
Resolution order: stored key → environment variable →
None.
- resolve(provider, api_key, model)[source]#
Resolve the effective
(provider, api_key, model)for an agent.Called automatically by
__init__. Users should not call this directly.Resolution rules#
- If
api_keyis explicitly given: Use
provider,api_key, andmodel(or provider default) exactly as supplied. The global config is ignored.- If
api_keyisNone: If
providerequals the default"claude"and the global config has an active provider, inherit that provider.Look up the key: stored key → env var.
Inherit the model from the global config when the effective provider matches the globally active provider.
- If
- info()[source]#
Return a summary dict suitable for display or logging.
The API key is masked to its last four characters for safety.
- Returns:
Keys:
provider,model,has_key,key_source,stored_providers,custom_rate_models,budget_usd,spent_usd,remaining_usd.- Return type:
- using(*, provider=None, api_key=None, model=None)[source]#
Temporarily override the global config inside a
withblock.All arguments are optional; omitted values are left unchanged. The original config (including custom rates and budget) is restored on exit even if an exception occurs.
- Parameters:
- Yields:
AgentConfig – self with the override applied.
- Return type:
Generator[AgentConfig, None, None]
Examples
with AGENT_CONFIG.using(provider="gemini", api_key="AIza…"): r = DataQCAgent().execute(data) # original provider / key / model restored here
- offline()[source]#
Context manager: force truly offline mode in the current thread.
While active,
_resolve_key()will not inspect environment variables, so agents created inside the block receiveapi_key=Noneeven whenANTHROPIC_API_KEY(or similar) is set in the OS environment. Usesthreading.localso concurrent requests in other threads are unaffected.Examples
with AGENT_CONFIG.offline(): agent = DataQCAgent() # api_key will be None
- Return type:
Generator[AgentConfig, None, None]
- pycsamt.api.agents.AGENT_CONFIG: AgentConfig = AgentConfig(unconfigured)#
Global singleton. Import and configure this object once per session.
- exception pycsamt.api.agents.BudgetExceededError(spent, budget)[source]#
Bases:
RuntimeErrorRaised when an LLM call would be made after the session budget is used.
- pycsamt.api.agents.configure_agents(*, provider, api_key, model=None)[source]#
Configure
AGENT_CONFIGin one call and return it.Equivalent to
AGENT_CONFIG.configure(...).- Parameters:
- Return type:
Examples
from pycsamt.agents import configure_agents configure_agents(provider="claude", api_key="sk-ant-…")
- pycsamt.api.agents.reset_agents(*, keys=True)[source]#
Reset
AGENT_CONFIGto its unconfigured state.Equivalent to
AGENT_CONFIG.reset(...).- Parameters:
keys (bool) – When
True(default) also wipe stored per-provider keys.- Return type: