diff --git a/src/langbot/pkg/api/http/service/monitoring.py b/src/langbot/pkg/api/http/service/monitoring.py index 1cb70f0b8..dbc4eefb0 100644 --- a/src/langbot/pkg/api/http/service/monitoring.py +++ b/src/langbot/pkg/api/http/service/monitoring.py @@ -1674,6 +1674,15 @@ class MonitoringService(ExecutionDetailsMixin): } async def get_inflight_snapshot(self, context: TenantContext, previous: list[dict] | None = None) -> dict: + """SSE producers outlive the HTTP handler's tenant scope.""" + workspace = require_workspace_uuid(context) + tenant_scope = getattr(self.ap.persistence_mgr, 'tenant_scope', None) + if callable(tenant_scope): + async with tenant_scope(workspace): + return await self._get_inflight_snapshot(context, previous) + return await self._get_inflight_snapshot(context, previous) + + async def _get_inflight_snapshot(self, context: TenantContext, previous: list[dict] | None = None) -> dict: """Bounded Workspace snapshot without dashboard aggregates or token payloads.""" from ....utils.inflight import inflight_hub diff --git a/tests/unit_tests/api/service/test_monitoring_executions.py b/tests/unit_tests/api/service/test_monitoring_executions.py index 7b8f027e8..5d2ba0168 100644 --- a/tests/unit_tests/api/service/test_monitoring_executions.py +++ b/tests/unit_tests/api/service/test_monitoring_executions.py @@ -759,6 +759,24 @@ async def test_inflight_snapshot_is_scoped_and_keeps_terminal_transition(engine, ) session.add(persistence_agent_run.AgentRunEvent(run_id='flight-visible', sequence=1, type='tool.started')) await session.commit() + # SSE loaders execute after the HTTP handler's tenant scope has exited. + # Cloud persistence rejects implicit execute_async calls in that context. + from contextlib import asynccontextmanager + + original_execute = service.ap.persistence_mgr.execute_async + unscoped_execute = AsyncMock(side_effect=AssertionError('Cloud persistence requires an explicit tenant scope')) + + @asynccontextmanager + async def tenant_scope(workspace): + assert workspace == WORKSPACE + service.ap.persistence_mgr.execute_async = original_execute + try: + yield + finally: + service.ap.persistence_mgr.execute_async = unscoped_execute + + service.ap.persistence_mgr.tenant_scope = tenant_scope + service.ap.persistence_mgr.execute_async = unscoped_execute snapshot = await service.get_inflight_snapshot(WORKSPACE) rows = {r['id']: r for r in snapshot['items']} assert 'flight-secret' not in rows diff --git a/web/src/app/home/monitoring/components/filters/MonitoringFilters.tsx b/web/src/app/home/monitoring/components/filters/MonitoringFilters.tsx index 7f982dbd5..ec3fb963b 100644 --- a/web/src/app/home/monitoring/components/filters/MonitoringFilters.tsx +++ b/web/src/app/home/monitoring/components/filters/MonitoringFilters.tsx @@ -201,7 +201,7 @@ export default function MonitoringFilters({ onPipelinesChange([...next]); }; return ( -
+
{/* Bot Filter */}