LLM authentication, provider routing, and tier management

Failure modes

Symptom Cause Fix Severity
ValueError from get_model Provider other than "anthropic" passed Pass "anthropic"; this provider set is single today high
get_model(...) returns None No model registered for that provider/tier Check the tier value (ModelTier.CHEAP.value, not the enum) and guard the result high
ValueError from get_tasks_for_tier Unknown tier argument Pass a real ModelTier, not a raw string medium
A task routes to CAPABLE unexpectedly The task string is unknown, so it defaulted Call is_known_task first; add the task to the tier map if it should be classified medium
AUTO returns API on a PRO account regardless of module size get_recommended_mode resolves by tier first; PRO/API_ONLY always return API Expected — only MAX/ENTERPRISE tiers use size-based selection medium
Auth always picks the mode you set, ignoring AUTO logic default_mode is SUBSCRIPTION or API, not AUTO Set default_mode = AuthMode.AUTO so it defers to get_recommended_mode medium
await error calling an executor's run LLMExecutor.run is async and was called without await await executor.run(...) or drive it with asyncio.run medium
AdaptiveModelRouter returns the same model regardless of cost Fewer than MIN_SAMPLE_SIZE calls recorded Accumulate telemetry; until then it falls back to static defaults low

Risk areas

Diagnosis order

  1. Print the resolved tier: get_tier_for_task(task) — confirms the classification before any model lookup.
  2. Print the model: get_model("anthropic", tier.value)None means a registry gap or a tier passed as an enum instead of .value.
  3. Inspect auth: attune auth status --json — confirms setup_completed and the active mode.
  4. Inspect provider: attune provider show — confirms the provider and mode the lookups will use.
  5. For routing surprises, read AdaptiveModelRouter.get_routing_stats( workflow, stage) to see sample size and per-model performance.