Skip to content

Commit 033dce6

Browse files
Mcy0618tjb-tech
authored andcommitted
fix(runtime): refresh prompt for permission mode changes
Inject the active permission mode into the runtime system prompt so plan/default/full-auto state is visible to the model. Refresh the engine model, effort, permission checker, and system prompt when runtime-affecting slash commands update settings. Based-on: #268
1 parent 4c3bf5b commit 033dce6

4 files changed

Lines changed: 102 additions & 0 deletions

File tree

src/openharness/prompts/context.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from openharness.memory.relevance import format_relevant_memories, select_relevant_memories
1717
from openharness.memory.usage import mark_memory_used
1818
from openharness.personalization.rules import load_local_rules
19+
from openharness.permissions.modes import PermissionMode
1920
from openharness.prompts.claudemd import load_claude_md_prompt
2021
from openharness.prompts.system_prompt import build_system_prompt
2122
from openharness.skills.loader import load_skill_registry
@@ -76,6 +77,28 @@ def _build_delegation_section() -> str:
7677
)
7778

7879

80+
def _build_permission_mode_section(settings: Settings) -> str:
81+
"""Build current permission-mode guidance for the model."""
82+
mode = settings.permission.mode
83+
if mode == PermissionMode.PLAN:
84+
guidance = (
85+
"Plan mode is enabled. Treat this session as read-only planning and analysis. "
86+
"Do not call mutating tools such as file writes, edits, package installs, "
87+
"state-changing shell commands, or task-spawning actions unless the user exits plan mode."
88+
)
89+
elif mode == PermissionMode.FULL_AUTO:
90+
guidance = (
91+
"Full-auto permission mode is enabled. You may use mutating tools when they are necessary "
92+
"for the user's request, while still keeping changes scoped and intentional."
93+
)
94+
else:
95+
guidance = (
96+
"Default permission mode is enabled. Read-only tools can run directly; mutating tools "
97+
"may require explicit user approval."
98+
)
99+
return f"# Current Permission Mode\n{guidance}"
100+
101+
79102
def build_runtime_system_prompt(
80103
settings: Settings,
81104
*,
@@ -94,6 +117,8 @@ def build_runtime_system_prompt(
94117
if not is_coordinator_mode() and settings.system_prompt is None:
95118
sections[0] = build_system_prompt(cwd=str(cwd))
96119

120+
sections.append(_build_permission_mode_section(settings))
121+
97122
if settings.fast_mode:
98123
sections.append(
99124
"# Session Mode\nFast mode is enabled. Prefer concise replies, minimal tool use, and quicker progress over exhaustive exploration."

src/openharness/ui/runtime.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,17 @@ def refresh_runtime_client(bundle: RuntimeBundle) -> None:
601601
default_model=settings.model,
602602
)
603603
bundle.engine.set_model(settings.model)
604+
bundle.engine.set_effort(settings.effort)
605+
bundle.engine.set_permission_checker(PermissionChecker(settings.permission))
606+
system_prompt = build_runtime_system_prompt(
607+
settings,
608+
cwd=bundle.cwd,
609+
latest_user_prompt=_last_user_text(bundle.engine.messages),
610+
extra_skill_dirs=bundle.extra_skill_dirs,
611+
extra_plugin_roots=bundle.extra_plugin_roots,
612+
include_project_memory=bundle.include_project_memory,
613+
)
614+
bundle.engine.set_system_prompt(system_prompt)
604615
sync_app_state(bundle)
605616

606617

tests/test_prompts/test_claudemd.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,23 @@ def test_build_runtime_system_prompt_combines_sections(tmp_path: Path, monkeypat
5858
assert "Memory" in prompt
5959

6060

61+
def test_build_runtime_system_prompt_includes_plan_mode_guidance(tmp_path: Path, monkeypatch):
62+
monkeypatch.setenv("OPENHARNESS_DATA_DIR", str(tmp_path / "data"))
63+
repo = tmp_path / "repo"
64+
repo.mkdir()
65+
66+
prompt = build_runtime_system_prompt(
67+
Settings(permission={"mode": "plan"}),
68+
cwd=repo,
69+
latest_user_prompt="inspect only",
70+
)
71+
72+
assert "Current Permission Mode" in prompt
73+
assert "Plan mode is enabled" in prompt
74+
assert "read-only planning and analysis" in prompt
75+
assert "Do not call mutating tools" in prompt
76+
77+
6178
def test_build_runtime_system_prompt_includes_project_context_and_fast_mode(tmp_path: Path, monkeypatch):
6279
monkeypatch.setenv("OPENHARNESS_DATA_DIR", str(tmp_path / "data"))
6380
repo = tmp_path / "repo"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
5+
import pytest
6+
7+
from openharness.ui.runtime import build_runtime, close_runtime, handle_line
8+
9+
10+
class _StaticApiClient:
11+
async def stream_message(self, request):
12+
del request
13+
if False:
14+
yield None
15+
16+
17+
@pytest.mark.asyncio
18+
async def test_plan_command_refreshes_engine_system_prompt(tmp_path: Path, monkeypatch):
19+
monkeypatch.setenv("OPENHARNESS_CONFIG_DIR", str(tmp_path / "config"))
20+
monkeypatch.setenv("OPENHARNESS_DATA_DIR", str(tmp_path / "data"))
21+
monkeypatch.setenv("OPENHARNESS_LOGS_DIR", str(tmp_path / "logs"))
22+
23+
bundle = await build_runtime(cwd=str(tmp_path), api_client=_StaticApiClient())
24+
try:
25+
assert "Plan mode is enabled" not in bundle.engine.system_prompt
26+
27+
async def print_system(text: str) -> None:
28+
del text
29+
30+
async def render_event(event) -> None:
31+
del event
32+
33+
async def clear_output() -> None:
34+
pass
35+
36+
should_continue = await handle_line(
37+
bundle,
38+
"/plan on",
39+
print_system=print_system,
40+
render_event=render_event,
41+
clear_output=clear_output,
42+
)
43+
44+
assert should_continue is True
45+
assert bundle.app_state.get().permission_mode == "plan"
46+
assert "Plan mode is enabled" in bundle.engine.system_prompt
47+
assert "Do not call mutating tools" in bundle.engine.system_prompt
48+
finally:
49+
await close_runtime(bundle)

0 commit comments

Comments
 (0)