feat(tui_gateway): real JSON-RPC server→client requests replace the *.request / *.respond notification pair
The backend never sent a JSON-RPC request; when it needed an answer from the
renderer it hand-correlated a `*.request` notification with a later `*.respond`
method through four module-level dicts, a timeout thread and 13 derived
`*.expire` names, plus a separate reconnect snapshot per prompt kind. That is a
second request/response layer built on a protocol that already has one.
`tui_gateway/server_requests.py` sends `{id: "srq-…", method, params}` and
blocks on the response frame with that id (string ids never collide with the
clients' integer ids). One `request.cancel {id, method, reason}` notification
withdraws a request on timeout / interrupt / session close. `open_requests` on
`session.resume` / `session.activate` / `session.events.since` re-delivers
unanswered requests after a reconnect; the shared TypeScript channel does that
itself before the caller sees the result. Batch clarify keeps its per-question
locks as a normal `clarify.lock` RPC (the last lock resolves the request).
Approvals stay queue-backed (`tools.approval` owns the timeout, `/approve all`,
coalescing): the request resolves the queue entry and the entry's own
resolution withdraws the request through `register_gateway_settle`.
Deleted: `_block`, `_respond`, `_pending`, `_answers`,
`_pending_prompt_payloads`, `_batch_clarify`, `_EXPIRING_REQUESTS`, the
`*.respond` methods, every `*.request` / `*.expire` event, `pending_clarify`.
Compute-host (turn isolation) mirrors the child's open request and relays the
response frame / lock to it. Desktop, TUI and shared clients register
`onRequest` handlers where they used to switch on `*.request` events; answers
are response frames over the socket the request arrived on, so #91684's
owner-routing class cannot recur for prompts.
This commit is contained in:
@@ -177,6 +177,17 @@ def list_gateway_approvals(session_key: str) -> list[dict]:
|
||||
return [dict(entry.data) for entry in _gateway_queues.get(session_key, [])]
|
||||
|
||||
|
||||
def register_gateway_settle(session_key: str, request_id: str, settle) -> bool:
|
||||
"""Attach ``settle(reason)`` to one pending approval; it runs once when that wait ends by any path.
|
||||
False when the request is no longer pending (the surface should withdraw its prompt itself)."""
|
||||
with _lock:
|
||||
for entry in _gateway_queues.get(session_key, []):
|
||||
if entry.data.get("request_id") == request_id:
|
||||
entry.settle = settle
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def ack_gateway_approval(session_key: str, request_id: str) -> bool:
|
||||
"""Record that a client received a particular pending approval request."""
|
||||
with _lock:
|
||||
|
||||
Reference in New Issue
Block a user