diff --git a/api/services/agent/composer_service.py b/api/services/agent/composer_service.py index 13924aae4b1..f90f9eec4dd 100644 --- a/api/services/agent/composer_service.py +++ b/api/services/agent/composer_service.py @@ -813,7 +813,11 @@ class AgentComposerService: account_id=account_id, ) if build_draft is None: - raise AgentVersionNotFoundError() + # A freshly-created agent has no DEBUG_BUILD row yet. Return an + # empty build-draft state (keeps the existing schema + # contract: variant, draft, agent_soul) so the UI can stay on + # the normal draft screen instead of toasting a 404. + return cls._empty_build_draft_state() return cls._serialize_build_draft_state(build_draft) @classmethod @@ -2243,6 +2247,18 @@ class AgentComposerService: "agent_soul": draft.config_snapshot_dict, } + @classmethod + def _empty_build_draft_state(cls) -> dict[str, Any]: + # Empty payload for a not-yet-created DEBUG_BUILD draft. Keeps + # the AgentBuildDraftResponse schema (variant/draft/agent_soul) so + # the front-end can render a fresh draft screen without a 404 + # toast. Regression for #40733. + return { + "variant": ComposerVariant.AGENT_APP.value, + "draft": None, + "agent_soul": None, + } + @classmethod def _get_draft_workflow(cls, *, session: Session, tenant_id: str, app_id: str) -> Workflow: workflow = session.scalar( diff --git a/api/tests/unit_tests/services/agent/test_agent_services.py b/api/tests/unit_tests/services/agent/test_agent_services.py index 479324c3167..413476ebd98 100644 --- a/api/tests/unit_tests/services/agent/test_agent_services.py +++ b/api/tests/unit_tests/services/agent/test_agent_services.py @@ -2170,8 +2170,36 @@ def test_agent_app_build_draft_apply_marks_unpublished_when_build_draft_differs( ) +def test_load_agent_app_build_draft_returns_empty_state_when_missing( + monkeypatch: pytest.MonkeyPatch, sqlite_session: Session +): + """Regression for #40733: a freshly-created agent has no DEBUG_BUILD row. + + GET /agent//build-draft used to return 404 "Agent config version + not found" and the front-end toasted it as a version error. The fix + returns an empty build-draft state so the UI stays on the normal + draft screen with no toast. + """ + session = sqlite_session + monkeypatch.setattr(AgentComposerService, "_get_agent_draft", lambda **kwargs: None) + + result = AgentComposerService.load_agent_app_build_draft( + session=session, + tenant_id="tenant-1", + agent_id="agent-1", + account_id="account-1", + ) + + # Schema contract (variant/draft/agent_soul) preserved; draft and + # agent_soul are None so the UI can render an empty draft. + assert result["variant"] == "agent_app" + assert result["draft"] is None + assert result["agent_soul"] is None + + def test_agent_app_composer_candidates_and_impact(monkeypatch: pytest.MonkeyPatch, sqlite_session: Session): session = sqlite_session + bindings = [ WorkflowAgentNodeBinding( tenant_id="tenant-1",