@@ -352,6 +352,72 @@ locals {
352352 },
353353 ] : []
354354
355+ # ── Anthropic / Claude models (ADR 09) ─────────────────────────────────
356+ # Enables Claude Code CLI and other Anthropic-SDK callers to route through
357+ # Sluice on API-key billing (ADR 09: "API-key billing = through Sluice").
358+ # The `agent-default` alias is what non-interactive CI agents request; it
359+ # maps to the cheap Claude tier as primary (order 1) and degrades to the
360+ # mid tier via the fallback chain, so Sluice picks the concrete model and
361+ # can re-route later without touching CI workflows. Activated by supplying
362+ # an "anthropic" entry in extra_providers (env_name = LITELLM_ANTHROPIC_API_KEY).
363+ has_anthropic = contains (local. active_provider_names , " anthropic" )
364+ anthropic_models = local. has_anthropic ? [
365+ # Concrete Claude models (current Anthropic model ids).
366+ # Cheap tier — Claude Haiku 4.5 ($1 / $5 per 1M tokens).
367+ {
368+ model_name = " claude-haiku-4-5"
369+ litellm_params = {
370+ model = " anthropic/claude-haiku-4-5"
371+ api_key = " os.environ/LITELLM_ANTHROPIC_API_KEY"
372+ }
373+ model_info = {
374+ input_cost_per_token = 0.000001
375+ output_cost_per_token = 0.000005
376+ }
377+ },
378+ # Mid tier — Claude Sonnet 4.6 ($3 / $15 per 1M tokens).
379+ {
380+ model_name = " claude-sonnet-4-6"
381+ litellm_params = {
382+ model = " anthropic/claude-sonnet-4-6"
383+ api_key = " os.environ/LITELLM_ANTHROPIC_API_KEY"
384+ }
385+ model_info = {
386+ input_cost_per_token = 0.000003
387+ output_cost_per_token = 0.000015
388+ }
389+ },
390+ # agent-default group — CI agents request model="agent-default".
391+ # Cheap Claude tier is primary (order 1) so Sluice picks the concrete
392+ # model; degrades to the mid tier (order 2) then to `premium` (Azure,
393+ # always present) via the fallback chain below.
394+ {
395+ model_name = " agent-default"
396+ litellm_params = {
397+ model = " anthropic/claude-haiku-4-5"
398+ api_key = " os.environ/LITELLM_ANTHROPIC_API_KEY"
399+ order = 1
400+ }
401+ model_info = {
402+ input_cost_per_token = 0.000001
403+ output_cost_per_token = 0.000005
404+ }
405+ },
406+ # agent-default fallback member — mid Claude tier (order 2).
407+ {
408+ model_name = " agent-default"
409+ litellm_params = {
410+ model = " anthropic/claude-sonnet-4-6"
411+ api_key = " os.environ/LITELLM_ANTHROPIC_API_KEY"
412+ order = 2
413+ }
414+ model_info = {
415+ input_cost_per_token = 0.000003
416+ output_cost_per_token = 0.000015
417+ }
418+ },
419+ ] : []
420+
355421 # ── "auto" alias — points to cheapest entry with fallback chain ────────
356422 # auto is a model group with a single entry (Groq gpt-oss-20b if available,
357423 # otherwise Together, otherwise Fireworks). Fallback chains handle the rest.
@@ -407,9 +473,28 @@ locals {
407473 local. gemini_models ,
408474 local. openrouter_models ,
409475 local. moonshot_models ,
476+ local. anthropic_models ,
410477 local. auto_models ,
411478 )
412479
480+ # ── Fallback chains ────────────────────────────────────────────────────
481+ # auto/cheap-* chains exist only with an extra provider (ADR 11); the
482+ # agent-default chain exists only with Anthropic (ADR 09). Built
483+ # separately and concatenated so either can appear on its own.
484+ # Each entry is a single-key map(list(string)); tomap() keeps the element
485+ # type uniform so concat() doesn't choke on differing object attribute sets.
486+ extra_fallbacks = local. has_any_extra ? [
487+ tomap ({ auto = [" cheap-fast" , " cheap-reasoning" , " cheap-long-context" , " premium" ] }),
488+ tomap ({ cheap-fast = [" cheap-reasoning" , " premium" ] }),
489+ tomap ({ cheap-reasoning = [" premium" ] }),
490+ tomap ({ cheap-long-context = [" premium" ] }),
491+ ] : []
492+ # agent-default degrades cheap Claude → mid Claude → premium (Azure).
493+ anthropic_fallbacks = local. has_anthropic ? [
494+ tomap ({ " agent-default" = [" claude-sonnet-4-6" , " premium" ] }),
495+ ] : []
496+ combined_fallbacks = concat (local. extra_fallbacks , local. anthropic_fallbacks )
497+
413498 # Build with nullable optional keys, then filter out the nulls. Terraform's
414499 # ternary requires both branches to share a type, so the cleaner-looking
415500 # `condition ? {extras} : {}` doesn't compile against typed objects.
@@ -442,14 +527,11 @@ locals {
442527 budget_duration = var.budget_duration != " " ? var.budget_duration : null
443528 rpm_limit = var.rpm_limit > 0 ? var.rpm_limit : null
444529 tpm_limit = var.tpm_limit > 0 ? var.tpm_limit : null
445- # Multi-provider fallback chains (ADR 11). Only added when at least one
446- # extra provider is active; otherwise LiteLLM runs with Azure-only.
447- fallbacks = local.has_any_extra ? [
448- { auto = [" cheap-fast" , " cheap-reasoning" , " cheap-long-context" , " premium" ] },
449- { cheap-fast = [" cheap-reasoning" , " premium" ] },
450- { cheap-reasoning = [" premium" ] },
451- { cheap-long-context = [" premium" ] },
452- ] : null
530+ # Multi-provider fallback chains (ADR 11 + ADR 09). The auto/cheap-*
531+ # chains are added when an extra provider is active; the agent-default
532+ # chain is added when Anthropic is active. Concatenated so either set can
533+ # appear independently; null only when neither is present (Azure-only).
534+ fallbacks = length (local. combined_fallbacks ) > 0 ? local.combined_fallbacks : null
453535 context_window_fallbacks = local.has_any_extra ? [
454536 { cheap-fast = [" cheap-long-context" ] },
455537 { cheap-reasoning = [" cheap-long-context" ] },
0 commit comments