fix(commands): keep session transcript commands local-only

This commit is contained in:
hinotoi-agent
2026-05-22 13:19:37 +08:00
parent 09bc641aad
commit 9a24b8dfe2
3 changed files with 100 additions and 3 deletions
+18 -2
View File
@@ -2325,7 +2325,15 @@ def create_default_command_registry(
registry.register(SlashCommand("version", "Show the installed OpenHarness version", _version_handler))
registry.register(SlashCommand("status", "Show session status", _status_handler))
registry.register(SlashCommand("context", "Show the active runtime system prompt", _context_handler))
registry.register(SlashCommand("summary", "Summarize conversation history", _summary_handler))
registry.register(
SlashCommand(
"summary",
"Summarize conversation history",
_summary_handler,
remote_invocable=False,
remote_admin_opt_in=True,
)
)
registry.register(SlashCommand("compact", "Compact older conversation history", _compact_handler))
registry.register(SlashCommand("cost", "Show token usage and estimated cost", _cost_handler))
registry.register(SlashCommand("usage", "Show usage and token estimates", _usage_handler))
@@ -2333,7 +2341,15 @@ def create_default_command_registry(
registry.register(SlashCommand("dream", "Consolidate memory", _dream_handler))
registry.register(SlashCommand("memory", "Inspect and manage project memory", _memory_handler))
registry.register(SlashCommand("hooks", "Show configured hooks", _hooks_handler))
registry.register(SlashCommand("resume", "Restore the latest saved session", _resume_handler))
registry.register(
SlashCommand(
"resume",
"Restore the latest saved session",
_resume_handler,
remote_invocable=False,
remote_admin_opt_in=True,
)
)
registry.register(SlashCommand("session", "Inspect the current session storage", _session_handler))
registry.register(SlashCommand("export", "Export the current transcript", _export_handler))
registry.register(SlashCommand("share", "Create a shareable transcript snapshot", _share_handler))
+3
View File
@@ -235,6 +235,9 @@ async def test_sensitive_control_plane_commands_are_local_only(tmp_path: Path, m
"/model show",
"/commit remote requested commit",
"/ship",
"/resume",
"/resume session-from-another-sender",
"/summary 10",
):
command, _ = registry.lookup(payload)
assert command is not None
+79 -1
View File
@@ -293,10 +293,88 @@ async def test_runtime_pool_summary_does_not_restore_other_slack_thread_sender(t
updates = [u async for u in pool.stream_message(bob_message, bob_key)]
assert updates[-1].kind == "final"
assert updates[-1].text == "No conversation content to summarize."
assert updates[-1].text == "/summary is only available in the local OpenHarness UI."
assert "ALICE_PRIVATE_SUMMARY_SECRET" not in updates[-1].text
@pytest.mark.asyncio
async def test_runtime_pool_blocks_registered_resume_without_listing_or_loading_other_sessions(
tmp_path, monkeypatch
):
workspace = tmp_path / ".ohmo-home"
initialize_workspace(workspace)
registry = create_default_command_registry()
command, _ = registry.lookup("/resume alice-session")
assert command is not None
assert command.name == "resume"
assert command.remote_invocable is False
alice_secret = "ALICE_PRIVATE_RESUME_SECRET"
alice_key = "slack:C_SHARED:thread1:U_ALICE"
bob_key = "slack:C_SHARED:thread1:U_BOB"
save_session_snapshot(
cwd=tmp_path,
workspace=workspace,
model="gpt-5.4",
system_prompt="test",
session_id="alice-session",
session_key=alice_key,
usage=UsageSnapshot(),
messages=[ConversationMessage.from_user_text(f"Alice private note: {alice_secret}")],
)
async def fake_build_runtime(**kwargs):
class FakeEngine:
messages = []
total_usage = UsageSnapshot()
def set_system_prompt(self, prompt):
return None
def load_messages(self, messages):
raise AssertionError("remote /resume must not load saved messages")
return SimpleNamespace(
engine=FakeEngine(),
cwd=str(tmp_path),
session_id="bob-session",
current_settings=lambda: SimpleNamespace(model="gpt-5.4"),
commands=registry,
tool_registry=None,
app_state=None,
session_backend=None,
extra_skill_dirs=(),
extra_plugin_roots=(),
hook_summary=lambda: "",
mcp_summary=lambda: "",
plugin_summary=lambda: "",
)
async def fake_start_runtime(bundle):
return None
monkeypatch.setattr("ohmo.gateway.runtime.build_runtime", fake_build_runtime)
monkeypatch.setattr("ohmo.gateway.runtime.start_runtime", fake_start_runtime)
pool = OhmoSessionRuntimePool(cwd=tmp_path, workspace=workspace, provider_profile="codex")
for payload in ("/resume", "/resume alice-session"):
message = InboundMessage(
channel="slack",
sender_id="U_BOB",
chat_id="C_SHARED",
content=payload,
timestamp=datetime.utcnow(),
metadata={"thread_ts": "thread1", "chat_type": "group"},
)
updates = [u async for u in pool.stream_message(message, bob_key)]
assert updates[-1].kind == "final"
assert updates[-1].text == "/resume is only available in the local OpenHarness UI."
assert "alice-session" not in updates[-1].text
assert alice_secret not in updates[-1].text
def test_gateway_error_formats_claude_refresh_failure():
exc = ValueError("Claude OAuth refresh failed: HTTP Error 400: Bad Request")
assert "claude-login" in _format_gateway_error(exc)