Files
hermes-agent/gateway/session_clarify_lock.py
Teknium 433046b399 refactor(gateway): move the owner's server-request registry out of session_sudo_prompt
The registry behind sudo, secret, batch clarify and the Desktop UI
requests (_Pending, _open, _ask, resolve, lock_answer, may_settle,
owned_by, ask_viewer, ask_viewer_result) lived in session_sudo_prompt.py
because sudo was its first user. It now has its own module,
gateway/session_server_requests.py, the owner-side counterpart of the
sidecar's tui_gateway/server_requests.py. session_sudo_prompt.py keeps
only ask_sudo and sudo_prompt_scope. Every caller and test imports from
the new module directly, with no re-export shim. No behaviour change.

Review finding by @alt-glitch on #140472
Refs #134889 (TUI-18)
Refs #140337
2026-10-17 08:03:51 -07:00

39 lines
2.1 KiB
Python

"""``clarify.lock`` on the session owner (#140400).
The owner sends a local viewer's clarify batch as one ``clarify`` server request
(``gateway/session_clarify_batch.py``). Ink's batch panel and Desktop's batch card answer it one
question at a time with ``clarify.lock {request_id, question_id, answer}`` (``ClarifyLockParams`` /
``ClarifyLockResult``), as they did against main's sidecar; the owner had no such verb, so every
answer was refused as an unknown method and the turn waited out ``clarify_timeout``. Only a viewer
attached to the request's session with ``session:respond`` may lock its answers.
"""
import json
from hermes_state_runtime import RuntimeStoreError
async def clarify_lock(connection, ref, params):
from gateway.session_server_requests import lock_answer, may_settle
# The dispatcher already refused unknown keys and mistyped fields against the declared
# ``ClarifyLockParams`` (``tui_gateway/contracts/canonical.py``); a missing or empty id is ours to refuse.
# ``profile`` naming another served profile was routed to its owner by ``dispatch``.
request_id, question_id = params.get('request_id'), params.get('question_id')
if not isinstance(request_id, str) or not request_id or not isinstance(question_id, str) or not question_id:
raise RuntimeStoreError('invalid_params')
answer = params.get('answer', '')
if answer is not None and not isinstance(answer, str):
answer = json.dumps(answer, ensure_ascii=False)
authority, actor = connection.authority, connection.actor
def entitled(session_id, events):
# The same rule the closing response frame for this request id goes through.
return may_settle(authority, actor, session_id, events)
try:
remaining = lock_answer(request_id, question_id, answer, session_ok=entitled)
except ValueError:
raise RuntimeStoreError('invalid_params') from None
if remaining is None:
# The wait already ended (timeout / cancel) while the card was still visible: not an error.
return {'status': 'expired'}
return {'status': 'ok', 'remaining': remaining}