From ab847fe2c4007ce0afc9ca6986092bb8cccd8a40 Mon Sep 17 00:00:00 2001 From: ciregenz Date: Sat, 8 Aug 2026 02:14:27 -0700 Subject: [PATCH] [eric] apps: a spawned agent lands on the most-recent dashboard when the app names none, so the card is visible not just real --- backend/apps/apps_sdk/apps_sdk.py | 11 +++++++++-- backend/tests/test_apps_sdk.py | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/backend/apps/apps_sdk/apps_sdk.py b/backend/apps/apps_sdk/apps_sdk.py index 39de0e4d..635b4523 100644 --- a/backend/apps/apps_sdk/apps_sdk.py +++ b/backend/apps/apps_sdk/apps_sdk.py @@ -103,18 +103,25 @@ async def spawn_agent(body: SpawnAgentRequest) -> SpawnAgentReply: if not body.prompt.strip(): raise HTTPException(status_code=422, detail="prompt is empty") + dashboard_id = body.dashboard_id + if dashboard_id is None: + # An app webview has no idea which dashboard it lives on; without one the canvas lifecycle + # never creates a card, so the spawn is real but invisible. Most-recent dashboard wins. + from backend.apps.dashboards.dashboards import load_all + boards = sorted(load_all(), key=lambda d: d.updated_at, reverse=True) + dashboard_id = boards[0].id if boards else None config = AgentConfig( name=body.name, prompt=body.prompt, model=body.model or "sonnet", - dashboard_id=body.dashboard_id, + dashboard_id=dashboard_id, ) session = await agent_manager.launch_agent(config) asyncio.create_task(agent_manager.send_message(session.id, body.prompt)) if body.x is not None and body.y is not None: await ws_manager.broadcast_global("apps_sdk:place_agent_card", { "session_id": session.id, - "dashboard_id": body.dashboard_id, + "dashboard_id": dashboard_id, "x": body.x, "y": body.y, }) diff --git a/backend/tests/test_apps_sdk.py b/backend/tests/test_apps_sdk.py index a992164d..7f5012e1 100644 --- a/backend/tests/test_apps_sdk.py +++ b/backend/tests/test_apps_sdk.py @@ -89,10 +89,12 @@ def test_llm_rejects_an_empty_prompt(): def test_spawn_agent_launches_and_broadcasts_position(monkeypatch): + import backend.apps.dashboards.dashboards as dash_mod from backend.apps.agents import agent_manager as am_mod from backend.apps.agents.core import ws_manager as ws_mod from backend.apps.agents.core.models import AgentSession + monkeypatch.setattr(dash_mod, "load_all", lambda: [], raising=True) launched = [] messaged = [] broadcasts = [] @@ -122,10 +124,12 @@ def test_spawn_agent_launches_and_broadcasts_position(monkeypatch): def test_spawn_agent_without_position_skips_the_broadcast(monkeypatch): + import backend.apps.dashboards.dashboards as dash_mod from backend.apps.agents import agent_manager as am_mod from backend.apps.agents.core import ws_manager as ws_mod from backend.apps.agents.core.models import AgentSession + monkeypatch.setattr(dash_mod, "load_all", lambda: [], raising=True) broadcasts = [] async def p_launch(config):