diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 630029a34..18cb4a404 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -5,7 +5,7 @@ ### Added - Added tokens-per-second throughput to RPC `get_state` responses for non-TUI clients. -- Added the RPC `set_fast_mode` command for live fast-mode control. +- Added the RPC `set_fast_mode` command and typed TypeScript/Python client methods for live fast-mode control. - Added `fastModeEnabled` and `fastModeActive` to RPC `get_state` responses. ## [17.1.8] - 2026-07-28 diff --git a/python/omp-rpc/src/omp_rpc/__init__.py b/python/omp-rpc/src/omp_rpc/__init__.py index d1fe16ec3..fd7ef107c 100644 --- a/python/omp-rpc/src/omp_rpc/__init__.py +++ b/python/omp-rpc/src/omp_rpc/__init__.py @@ -43,6 +43,7 @@ from .protocol import ( AutoRetryEndEvent, AutoRetryStartEvent, BashResult, + FastModeResult, BranchMessage, BranchResult, CancellationResult, @@ -109,6 +110,7 @@ __all__ = [ "AutoRetryEndEvent", "AutoRetryStartEvent", "BashResult", + "FastModeResult", "BranchMessage", "BranchResult", "CancellationResult", diff --git a/python/omp-rpc/src/omp_rpc/client.py b/python/omp-rpc/src/omp_rpc/client.py index 538e6c4ff..0f3b8983d 100644 --- a/python/omp-rpc/src/omp_rpc/client.py +++ b/python/omp-rpc/src/omp_rpc/client.py @@ -25,6 +25,7 @@ from .protocol import ( AutoRetryEndEvent, AutoRetryStartEvent, BashResult, + FastModeResult, BranchMessage, BranchResult, CancellationResult, @@ -67,6 +68,7 @@ from .protocol import ( assistant_text, parse_agent_messages, parse_bash_result, + parse_fast_mode_result, parse_branch_messages, parse_branch_result, parse_cancellation_result, @@ -916,6 +918,9 @@ class RpcClient: payload = self._request("get_state") return parse_session_state(payload) + def set_fast_mode(self, enabled: bool) -> FastModeResult: + return parse_fast_mode_result(self._request("set_fast_mode", enabled=enabled)) + def set_model(self, provider: str, model_id: str) -> ModelInfo: payload = self._request("set_model", provider=provider, modelId=model_id) model = parse_model_info(payload) diff --git a/python/omp-rpc/src/omp_rpc/protocol.py b/python/omp-rpc/src/omp_rpc/protocol.py index 1fa2cfc9a..248ca89b7 100644 --- a/python/omp-rpc/src/omp_rpc/protocol.py +++ b/python/omp-rpc/src/omp_rpc/protocol.py @@ -183,6 +183,13 @@ def _require_str(payload: JsonObject, field: str) -> str: return value +def _require_bool(payload: JsonObject, field: str) -> bool: + value = payload.get(field) + if not isinstance(value, bool): + raise ValueError(f"{field} must be a boolean") + return value + + def _optional_str(payload: JsonObject, field: str) -> str | None: value = payload.get(field) if value is None: @@ -803,6 +810,12 @@ class BashResult: artifact_id: str | None = None +@dataclass(slots=True, frozen=True) +class FastModeResult: + enabled: bool + active: bool + + @dataclass(slots=True, frozen=True) class CompactionResult: summary: str @@ -1376,6 +1389,13 @@ def parse_bash_result(payload: JsonObject) -> BashResult: ) +def parse_fast_mode_result(payload: JsonObject) -> FastModeResult: + return FastModeResult( + enabled=_require_bool(payload, "enabled"), + active=_require_bool(payload, "active"), + ) + + def parse_compaction_result(payload: JsonObject) -> CompactionResult: return CompactionResult( summary=str(payload.get("summary", "")), diff --git a/python/omp-rpc/tests/test_client.py b/python/omp-rpc/tests/test_client.py index 3ad15d703..4355ee4b8 100644 --- a/python/omp-rpc/tests/test_client.py +++ b/python/omp-rpc/tests/test_client.py @@ -322,6 +322,21 @@ FAKE_SERVER = textwrap.dedent( "compact", {"summary": "trimmed", "shortSummary": "trimmed", "firstKeptEntryId": "entry-1", "tokensBefore": 123}, ) + elif command_type == "set_fast_mode": + enabled = command.get("enabled") + if not isinstance(enabled, bool): + respond( + request_id, + "set_fast_mode", + success=False, + error="set_fast_mode requires boolean enabled", + ) + else: + respond( + request_id, + "set_fast_mode", + {"enabled": False, "active": True}, + ) elif command_type == "set_auto_compaction": auto_compaction_enabled = command["enabled"] respond(request_id, "set_auto_compaction", {}) @@ -888,6 +903,13 @@ class RpcClientTests(unittest.TestCase): self.assertEqual(result.output, "hello\n") self.assertEqual(result.exit_code, 0) + def test_set_fast_mode_preserves_provider_tier_state(self) -> None: + with self.make_client() as client: + result = client.set_fast_mode(False) + + self.assertFalse(result.enabled) + self.assertTrue(result.active) + def test_prompt_and_wait_returns_assistant_text(self) -> None: with self.make_client() as client: turn = client.prompt_and_wait("say hello", timeout=2.0)