Files
strix/strix/interface/tui/backend/protocol.py
T
oyasumiandClaude Opus 4.8 ccbd8c7b58 feat(safety): workspace-file reads, approval UX, and integration hardening
Engine + integration:
- Reviewer inspection now surfaces the real frozen source of an already-frozen
  workspace script/dependency instead of an empty string, so workspace-resident
  scripts resolve without a needless human defer.
- Guard effectful static tools via an explicit, documented set plus the SDK's
  per-tool needs_approval signal; give the exec/stdin wrappers the same
  idempotency guard as their sibling wrappers.
- Centralize DEFAULT_SAFETY_MODE and share one resume safety-mode rule between the
  CLI and runner so the two cannot drift; type InspectionContext.runner, reuse
  RUNTIME_STATE_DIR_NAME, and drop a dead workdir parameter and a write-only field.

TUI approval experience:
- Approve All drops the run into dangerous mode: it approves the pending call and
  turns review off for the rest of the run, with a standing "review off" status flag.
- The status row shows the owning agent as paused while it waits on a decision.
- Redesigned prompt: a risk + tool header, a collapsible command/reason preview
  that expands (e) and scrolls, and no internal digest, agent, or request ids.

Full Python (1138) and Go suites, ruff, and mypy strix/ pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 05:33:47 +00:00

42 lines
1.0 KiB
Python

"""Versioned JSON protocol shared with the Go TUI."""
from __future__ import annotations
from typing import Any
PROTOCOL_VERSION = 5
PROTOCOL_CAPABILITIES = (
"state-revisions",
"collection-deltas",
"structured-command-errors",
"agents-collection",
"safety-approvals",
)
# Commands and control messages are intentionally small. Event and finding
# history uses a separate bounded collection stream so a resumed run can be
# larger than any individual frame.
MAX_COMMAND_BYTES = 64 * 1024
MAX_COLLECTION_FRAME_BYTES = 4 * 1024 * 1024
class ProtocolHandshakeError(RuntimeError):
"""Raised before the Go TUI is activated when protocol negotiation fails."""
def envelope(
message_type: str,
payload: dict[str, Any],
*,
request_id: str | None = None,
) -> dict[str, Any]:
message: dict[str, Any] = {
"version": PROTOCOL_VERSION,
"type": message_type,
"payload": payload,
}
if request_id:
message["request_id"] = request_id
return message