feat(buffer): ContextualBufferProxy + append_system_message

_SessionBuffer.append_system_message(user_id, session_id, text) injects a
synthetic SystemMessage into the named session slot (creating it if absent).

ContextualBufferProxy closes over user_id + session_id so call sites need
only call proxy.append_system_message(text).

get_session_buffer(user_id, session_id, channel) in device_ws returns a
ContextualBufferProxy, keeping the test-patchable function signature intact.
This commit is contained in:
Roberto
2026-05-14 21:11:13 +02:00
parent 6188ae15b3
commit 2b71469e86
2 changed files with 44 additions and 6 deletions

View File

@@ -374,14 +374,15 @@ async def _handle_floating_request(
# ── v8 Contextual Sidebar Handlers ───────────────────────────────────
def get_session_buffer(session_id: str, channel: str = "contextual"):
"""Return the session buffer for the given session.
def get_session_buffer(user_id: str, session_id: str, channel: str = "contextual"):
"""Return a session-scoped buffer proxy for the given user+session.
The channel kwarg is accepted for forward-compatibility but not used for
namespacing yet (session ids are UUIDs so collisions are negligible).
Returns a _ContextualBufferProxy that exposes append_system_message().
Defined at module level so tests can monkeypatch it.
The channel kwarg is accepted for forward-compatibility.
"""
return session_buffer
from app.core.agent_session_buffer import ContextualBufferProxy # noqa: PLC0415
return ContextualBufferProxy(session_buffer, user_id, session_id)
async def _handle_contextual_request(
@@ -472,7 +473,7 @@ async def _handle_contextual_scope_update(
session_id: str = frame.get("session_id") or str(uuid4())
scope = ContextualScope.model_validate(frame.get("scope", {}))
block = render_scope_block(scope)
buf = get_session_buffer(session_id, channel="contextual")
buf = get_session_buffer(user_id, session_id, channel="contextual")
buf.append_system_message(
f"User navigated to a new view. {block} Treat this as the new active context."
)