[eric] workflows: a new workflow runs on the model you actually configured, not Anthropic's API lane

This commit is contained in:
ciregenz
2026-08-07 17:06:48 -07:00
parent b16c31b8c2
commit 050a02fc52
3 changed files with 48 additions and 5 deletions
+42
View File
@@ -0,0 +1,42 @@
"""Which model a workflow runs on when nobody picked one.
`DEFAULT_MODEL` is `opus-5`, and that is Anthropic's API-KEY lane: the Claude subscription lane is a
separate id (`opus-5-cc`). Defaulting every workflow to the literal therefore billed an API key a
subscriber may not even have, and named a model a Codex or Gemini subscriber cannot run at all.
Lives in its own module because both the routes and the executor need it, and importing one from the
other is a cycle.
"""
import logging
from typing import Optional
from typeguard import typechecked
from backend.apps.settings.models import DEFAULT_MODEL
logger = logging.getLogger(__name__)
@typechecked
def user_default_model() -> str:
"""The model this user actually configured, never a vendor literal."""
try:
from backend.apps.settings.settings import load_settings
chosen = (getattr(load_settings(), "default_model", "") or "").strip()
return chosen or DEFAULT_MODEL
except Exception:
logger.debug("could not read the user's default model", exc_info=True)
return DEFAULT_MODEL
@typechecked
def provider_for_model(model: Optional[str]) -> str:
"""Derive the provider from the model instead of assuming Anthropic."""
if not model:
return "anthropic"
try:
from backend.apps.agents.providers.registry import get_api_type
return get_api_type(model) or "anthropic"
except Exception:
logger.debug("could not derive a provider for %s", model, exc_info=True)
return "anthropic"
+3 -3
View File
@@ -14,7 +14,7 @@ from typing import Optional
from backend.apps.agents.core.models import AgentConfig
from backend.apps.workflows.models import Workflow, WorkflowRun
from backend.apps.workflows import storage
from backend.apps.settings.models import DEFAULT_MODEL
from backend.apps.workflows.default_model import provider_for_model, user_default_model
logger = logging.getLogger(__name__)
@@ -302,9 +302,9 @@ async def execute(
resolved_allowed_tools = _resolve_allowed_tools(wf)
config = AgentConfig(
name=wf.title or "Workflow",
model=wf.model or DEFAULT_MODEL,
model=wf.model or user_default_model(),
mode=wf.mode or "agent",
provider=wf.provider or "anthropic",
provider=wf.provider or provider_for_model(wf.model or user_default_model()),
system_prompt=_resolve_system_prompt(wf),
# None when the user has not frozen the Actions set, which means the workflow runs with the mode's full surface exactly like a chat does.
allowed_tools=resolved_allowed_tools,
+3 -2
View File
@@ -22,6 +22,7 @@ from backend.apps.workflows.models import (
from backend.apps.workflows import storage, scheduler, executor, audit, escalation
from backend.apps.workflows.cloud.handover import release_before_removing
from backend.apps.settings.models import DEFAULT_MODEL
from backend.apps.workflows.default_model import provider_for_model, user_default_model
logger = logging.getLogger(__name__)
@@ -292,9 +293,9 @@ async def create_workflow(body: WorkflowCreate):
permissions=body.permissions or [],
source_session_id=body.source_session_id,
dashboard_id=body.dashboard_id,
model=body.model or DEFAULT_MODEL,
model=body.model or user_default_model(),
mode=body.mode or "agent",
provider=body.provider or "anthropic",
provider=body.provider or provider_for_model(body.model or user_default_model()),
cost_cap_usd_monthly=body.cost_cap_usd_monthly,
auto_named=body.auto_named,
unsaved=body.unsaved,