From 70c19d30642b709a6586da29ffc256450d3c0674 Mon Sep 17 00:00:00 2001 From: Roberto Date: Fri, 15 May 2026 18:56:29 +0200 Subject: [PATCH] chore(contextual): purge residual floating WsFrame defs + output_formatter branch After M6.5 deletion of run_floating_stream and the frame dispatch, WsFrameType.floating_request/floating_domain, WsFloatingRequest, WsFloatingDomain, WsFloatingScope, WsDomain, and the StreamFormatter's floating_domain branch were left as dead protocol surface. Remove them, along with the corresponding test cases in test_schemas_v3.py and test_output_formatter.py. --- app/core/output_formatter.py | 12 +---- app/schemas/__init__.py | 34 ------------ tests/test_output_formatter.py | 25 +-------- tests/test_schemas_v3.py | 99 ---------------------------------- 4 files changed, 3 insertions(+), 167 deletions(-) diff --git a/app/core/output_formatter.py b/app/core/output_formatter.py index 03026e1..185e931 100644 --- a/app/core/output_formatter.py +++ b/app/core/output_formatter.py @@ -6,7 +6,7 @@ import re from collections.abc import AsyncGenerator from typing import Any -from app.schemas import WsFloatingDomain, WsStreamEnd, WsStreamStart, WsStreamText +from app.schemas import WsStreamEnd, WsStreamStart, WsStreamText # Matches ... blocks (single-line or multiline). _CANVAS_BLOCK_RE = re.compile( @@ -31,7 +31,7 @@ def extract_canvas_block(text: str) -> tuple[str, str | None, str | None]: visible = visible.strip() return visible, canvas_content, canvas_kind -WsFrame = WsStreamStart | WsStreamText | WsStreamEnd | WsFloatingDomain +WsFrame = WsStreamStart | WsStreamText | WsStreamEnd class StreamFormatter: @@ -47,14 +47,6 @@ class StreamFormatter: started = False async for event_type, data in event_stream: - if event_type == "floating_domain": - if isinstance(data, dict): - yield WsFloatingDomain( - request_id=self.request_id, - domain=data, - ) - continue - if event_type != "token": continue diff --git a/app/schemas/__init__.py b/app/schemas/__init__.py index e372c5e..ca45c19 100644 --- a/app/schemas/__init__.py +++ b/app/schemas/__init__.py @@ -73,11 +73,9 @@ class WsFrameType(str, Enum): device_hello = "device_hello" # ── v3 frame types ───────────────────────────────────────────────── home_request = "home_request" - floating_request = "floating_request" stream_start = "stream_start" stream_text = "stream_text" stream_end = "stream_end" - floating_domain = "floating_domain" data_request = "data_request" data_response = "data_response" mutation = "mutation" @@ -165,13 +163,6 @@ class FormatPrefsModel(BaseModel): now_iso: str = "" -class WsFloatingScope(BaseModel): - """Scope for a floating request — narrows the agent to a specific entity.""" - - type: Literal["task", "project", "note", "timeline"] - id: str | None = None - - class WsHomeRequest(BaseModel): """Client → Server: Home chat message.""" @@ -181,15 +172,6 @@ class WsHomeRequest(BaseModel): format_prefs: FormatPrefsModel | None = None -class WsFloatingRequest(BaseModel): - """Client → Server: Floating chat message scoped to an entity.""" - - type: Literal[WsFrameType.floating_request] = WsFrameType.floating_request - message: str - scope: WsFloatingScope - format_prefs: FormatPrefsModel | None = None - - class WsBriefRequest(BaseModel): """Client → Server: Request a plain-text brief (home or project).""" @@ -225,22 +207,6 @@ class WsStreamEnd(BaseModel): mutations: list[dict[str, Any]] | None = None -class WsDomain(BaseModel): - """Structured floating domain payload for UI routing decisions.""" - - type: Literal["task", "timeline", "project", "node"] - id: str | None = None - section: Literal["task", "timeline", "note"] | None = None - - -class WsFloatingDomain(BaseModel): - """Server → Client: domain determined for a floating request.""" - - type: Literal[WsFrameType.floating_domain] = WsFrameType.floating_domain - request_id: str - domain: WsDomain - - # ── Agent Config V2 ─────────────────────────────────────────────────── diff --git a/tests/test_output_formatter.py b/tests/test_output_formatter.py index b9b6741..58fe8ad 100644 --- a/tests/test_output_formatter.py +++ b/tests/test_output_formatter.py @@ -5,7 +5,7 @@ from __future__ import annotations import pytest from app.core.output_formatter import StreamFormatter -from app.schemas import WsFloatingDomain, WsStreamEnd, WsStreamStart, WsStreamText +from app.schemas import WsStreamEnd, WsStreamStart, WsStreamText async def _stream(*events: tuple[str, object]): @@ -36,29 +36,6 @@ async def test_stream_formatter_text_stream() -> None: assert isinstance(frames[-1], WsStreamEnd) -@pytest.mark.asyncio -async def test_stream_formatter_floating_domain_first() -> None: - formatter = StreamFormatter(request_id="req-2") - frames = await _collect( - formatter, - _stream( - ( - "floating_domain", - {"type": "node", "id": "n-1", "section": None}, - ), - ("token", "Summary"), - ), - ) - - assert isinstance(frames[0], WsFloatingDomain) - assert frames[0].domain.type == "node" - assert frames[0].domain.id == "n-1" - assert isinstance(frames[1], WsStreamStart) - assert isinstance(frames[2], WsStreamText) - assert frames[2].chunk == "Summary" - assert isinstance(frames[-1], WsStreamEnd) - - @pytest.mark.asyncio async def test_stream_formatter_ignores_unknown_events() -> None: formatter = StreamFormatter(request_id="req-3") diff --git a/tests/test_schemas_v3.py b/tests/test_schemas_v3.py index 4e5a43b..cf2b0c0 100644 --- a/tests/test_schemas_v3.py +++ b/tests/test_schemas_v3.py @@ -4,12 +4,8 @@ import pytest from pydantic import ValidationError from app.schemas import ( - WsDomain, WsFrameType, WsHomeRequest, - WsFloatingDomain, - WsFloatingRequest, - WsFloatingScope, WsStreamEnd, WsStreamStart, WsStreamText, @@ -22,11 +18,9 @@ from app.schemas import ( def test_v3_frame_types_exist(): v3_types = [ "home_request", - "floating_request", "stream_start", "stream_text", "stream_end", - "floating_domain", "data_request", "data_response", "mutation", @@ -86,51 +80,6 @@ def test_home_request_requires_message(): WsHomeRequest.model_validate({"type": "home_request"}) -# ── WsFloatingRequest ──────────────────────────────────────────────────── - - -def test_floating_request_basic(): - frame = WsFloatingRequest( - message="Summarise", - scope=WsFloatingScope(type="task", id="task-123"), - ) - assert frame.type == WsFrameType.floating_request - assert frame.scope.type == "task" - assert frame.scope.id == "task-123" - - -def test_floating_request_scope_without_id(): - frame = WsFloatingRequest( - message="Show all", - scope=WsFloatingScope(type="project"), - ) - assert frame.scope.id is None - - -def test_floating_request_serializes(): - frame = WsFloatingRequest( - message="Test", - scope=WsFloatingScope(type="note", id="n-1"), - ) - data = frame.model_dump() - assert data["type"] == "floating_request" - assert data["scope"]["type"] == "note" - assert data["scope"]["id"] == "n-1" - - -def test_floating_request_invalid_scope_type(): - with pytest.raises(ValidationError): - WsFloatingRequest( - message="X", - scope=WsFloatingScope(type="unknown"), # type: ignore[arg-type] - ) - - -def test_floating_request_requires_scope(): - with pytest.raises(ValidationError): - WsFloatingRequest.model_validate({"type": "floating_request", "message": "X"}) - - # ── WsStreamStart ───────────────────────────────────────────────────── @@ -189,51 +138,3 @@ def test_stream_end_deserializes(): assert frame.request_id == "r3" -# ── WsFloatingDomain ───────────────────────────────────────────────────── - - -def test_floating_domain_tasks(): - frame = WsFloatingDomain(request_id="r1", domain=WsDomain(type="task")) - assert frame.type == WsFrameType.floating_domain - assert frame.domain.type == "task" - - -def test_floating_domain_valid_domains(): - frame = WsFloatingDomain( - request_id="r1", - domain=WsDomain(type="project", id="213213-312321-312312-421321", section="task"), - ) - assert frame.domain.type == "project" - assert frame.domain.id == "213213-312321-312312-421321" - assert frame.domain.section == "task" - - -def test_floating_domain_object_valid(): - frame = WsFloatingDomain( - request_id="r1", - domain=WsDomain(type="project", id="p1", section="task"), - ) - assert frame.domain.type == "project" - - -def test_floating_domain_serializes(): - d = WsFloatingDomain( - request_id="r1", - domain=WsDomain(type="timeline"), - ).model_dump() - assert d == { - "type": "floating_domain", - "request_id": "r1", - "domain": {"type": "timeline", "id": None, "section": None}, - } - - -def test_floating_domain_deserializes(): - raw = { - "type": "floating_domain", - "request_id": "r1", - "domain": {"type": "node", "id": "n-1", "section": None}, - } - frame = WsFloatingDomain.model_validate(raw) - assert frame.domain.type == "node" - assert frame.domain.id == "n-1"