"""TUI agent turns use short lookup limits and adaptive coding turns.""" import json from routes.chat_routes import ( _effective_agent_rounds, _effective_native_output_tokens, _parse_client_runtime_context, ) from src.agent_loop import ( _looks_like_local_computer_request, _looks_like_explicit_tui_personal_domain_request, _looks_like_explicit_tui_app_or_external_request, _is_qwen_explicit_model_list_request, _is_qwen_explicit_latest_email_request, _route_tui_local_workspace_tools, _tui_local_fallback_shell_command, _tui_recover_invalid_local_tools, ToolBlock, _looks_like_malformed_tui_tool_call, _tui_project_discovery_summary, _parse_qwen_explicit_note_view, _ody_qwen_terminal_tool_summary, _tui_normalize_network_host_command, _tui_normalize_workspace_host_command, _tui_network_summary, _tui_local_workspace_turn, _web_search_unavailable_for_turn, _is_host_bridge_failure_result, _empty_response_fallback, _normalize_ody_qwen_text_artifacts, _workspace_coding_rules, _looks_like_workspace_coding_request, _workspace_pre_mutation_verification_block, _tui_local_test_runner_command, _tui_local_test_runner_host_shell_content, _tui_local_smoke_test_runner_command, _tui_normalize_pytest_command, _tui_smoke_test_request, _tui_explicit_full_test_request, _calendar_context_owns_ambiguous_mutation, _calendar_lookup_requires_fresh_tool, _parse_simple_calendar_tool_request, _memory_search_precedes_unrequested_list, ) def test_all_tui_bridge_mutation_failures_are_terminal_transport_errors(): for result in ( {"error": "apply_patch: host bridge request failed: connection refused"}, {"error": "edit_file: bridge returned HTTP 502"}, {"error": "write_file: bridge returned invalid payload"}, {"output": "host_shell: no TUI host bridge advertised", "exit_code": 1}, {"stderr": "host_shell: missing TUI host bridge", "exit_code": 1}, {"error": "host bridge unavailable", "exit_code": 1}, ): assert _is_host_bridge_failure_result(result) def test_tui_non_coding_turn_caps_stale_persisted_setting(): assert _effective_agent_rounds(100, {"surface": "odysseus-tui"}, 20) == 20 assert _effective_agent_rounds("bad", {"surface": "odysseus-tui"}, 20) == 20 def test_tui_coding_turn_uses_adaptive_stopping(): prompt = ( "Inspect this local repository, repair the parser, and run the focused tests." ) assert _effective_agent_rounds( 100, {"surface": "odysseus-tui"}, 20, message=prompt, ) is None def test_tui_read_only_turn_keeps_short_round_cap(): assert _effective_agent_rounds( 100, {"surface": "odysseus-tui"}, 20, message="Inspect this local repository and report its top-level files.", ) == 20 def test_existing_file_edits_allow_one_baseline_verification_command(): assert _workspace_pre_mutation_verification_block( ToolBlock("host_shell", json.dumps({"command": "pytest -q tests/test_parser.py"})) ) assert _workspace_pre_mutation_verification_block( ToolBlock("bash", "python -m pytest -q") ) assert not _workspace_pre_mutation_verification_block( ToolBlock("host_shell", json.dumps({"command": "pwd && ls"})) ) assert not _workspace_pre_mutation_verification_block( ToolBlock("edit_file", "config.py") ) def test_webui_non_workspace_turn_keeps_configured_round_limit(): assert _effective_agent_rounds(100, {"surface": "webui"}, 20) == 100 def test_unattended_native_terminal_agent_honors_explicit_round_budget(): assert _effective_agent_rounds( 6, { "surface": "odysseus-native", "terminal_agent": True, "unattended_mode": True, "max_agent_rounds": 30, }, 20, ) == 30 def test_unattended_native_terminal_agent_without_budget_is_finite(): assert _effective_agent_rounds( 6, { "surface": "odysseus-native", "terminal_agent": True, "unattended_mode": True, }, 20, ) == 6 def test_attended_native_terminal_agent_keeps_configured_round_limit(): assert _effective_agent_rounds( 6, { "surface": "odysseus-native", "terminal_agent": True, "unattended_mode": False, }, 20, ) == 6 def test_unattended_native_runtime_can_bound_output_without_changing_ui_preset(): native = { "surface": "odysseus-native", "terminal_agent": True, "unattended_mode": True, "max_output_tokens": 8192, } assert _effective_native_output_tokens(32768, native) == 8192 assert _effective_native_output_tokens( 32768, {"surface": "webui", "max_output_tokens": 512} ) == 32768 assert _effective_native_output_tokens( 32768, {**native, "max_output_tokens": "bad"} ) == 32768 assert _effective_native_output_tokens( 32768, {**native, "max_output_tokens": 1} ) == 256 def test_native_runtime_context_preserves_only_a_bounded_output_cap(): context = _parse_client_runtime_context({ "surface": "odysseus-native", "terminal_agent": True, "unattended_mode": True, "max_output_tokens": 8192, }) assert context["max_output_tokens"] == 8192 assert _parse_client_runtime_context({ "surface": "odysseus-tui", "terminal_agent": True, "unattended_mode": True, "max_output_tokens": 8192, }).get("max_output_tokens") is None def test_webui_workspace_coding_turn_uses_adaptive_stopping(): assert _effective_agent_rounds( 20, {"surface": "webui"}, 20, message="Repair the parser and verify the change.", workspace_agent_intent=True, ) is None def test_network_prompts_are_classified_as_local_computer_work(): for prompt in ( "Find the local IP to SSH into ajax.", "Resolve ajax on the local network and tell me its IP.", "Tailscale is down; resolve ajax on the LAN.", "Inspect DNS and the default route on this machine.", ): assert _looks_like_local_computer_request(prompt), prompt def test_network_lookup_replaces_ping_with_address_evidence(): normalized = _tui_normalize_network_host_command( "ping -c 4 ajax.local", "Resolve ajax on the local network and tell me its IP.", ) assert normalized is not None command, reason = normalized assert "getent hosts ajax.local" in command assert "ip -o -4 addr show" in command assert "ip route show default" in command assert "ping replaced" in reason def test_network_connectivity_request_preserves_ping(): assert _tui_normalize_network_host_command( "ping -c 4 ajax.local", "Ping ajax to test connectivity.", ) is None def test_network_fallback_includes_named_target_without_guessing_hosts(): command = _tui_local_fallback_shell_command( "Find the local IP for ajax so I can SSH to it; Tailscale is down." ) assert command is not None assert "getent hosts ajax" in command assert "ip route show default" in command assert _tui_local_fallback_shell_command( "Inspect the local network interfaces." ) == "ip -o -4 addr show; ip route show default" def test_stale_read_tools_on_coding_turn_recover_to_one_host_probe(): blocks, recovered = _tui_recover_invalid_local_tools( [ ToolBlock("get_workspace", "{}"), ToolBlock("ls", "{}"), ], "Fix the parser in this local TUI project.", ) assert recovered is True assert [block.tool_type for block in blocks] == ["host_shell"] assert "git_root=" in json.loads(blocks[0].content)["command"] def test_stale_mutating_tool_is_not_rewritten_to_shell(): blocks, recovered = _tui_recover_invalid_local_tools( [ToolBlock("manage_notes", "{}")], "Fix the parser in this local TUI project and run the tests.", ) assert recovered is False assert blocks == [] def test_workspace_host_command_replaces_metadata_placeholder(): normalized = _tui_normalize_workspace_host_command( "cd session_cwd && npm test", "/tmp/my project", ) assert normalized == ( "cd '/tmp/my project' && npm test", "metadata workspace placeholder replaced with active session cwd", ) def test_malformed_qwen_local_tool_markup_is_detected_narrowly(): assert _looks_like_malformed_tui_tool_call( "parameter=hos_shell parameter=command cd /repo python -m pytest" ) assert _looks_like_malformed_tui_tool_call( "hos_shell\ncommand\nls -la\n 2026-09-01T11:00:00: " "[Planning review](#event-planning-review)" ), "exit_code": 0, } ], ) assert "Planning review" in final_response assert '"type": "final_response"' in (chunk or "") def test_calendar_panel_open_beats_context_snapshot_for_blank_followup(): final_response, _ = _empty_response_fallback( full_response="", round_reasoning="", tool_events=[ { "tool": "ui_control", "command": "open_panel calendar", "output": "", "exit_code": 0, }, { "tool": "manage_calendar", "command": '{"action":"list_events"}', "output": ( "Found 1 event:\n" "- 2026-09-01T10:00:00 -> 2026-09-01T11:00:00: " "[Planning review](#event-planning-review)" ), "exit_code": 0, "context_only": True, }, ], ) assert final_response == "The calendar panel is open." def test_calendar_lookup_parser_does_not_override_create_then_show_request(): from src.agent_loop import _parse_simple_calendar_tool_request assert _parse_simple_calendar_tool_request( 'Create a one-hour event called "Ablation review" tomorrow at 2pm, ' "then show the calendar again so I can verify it." ) is None def test_calendar_bounds_include_both_today_and_tomorrow(): from src.agent_loop import _calendar_bounds_for_prompt assert _calendar_bounds_for_prompt( "What's scheduled for today and tomorrow?", today="2026-08-30" ) == ("2026-08-30", "2026-09-01") def test_recent_calendar_anchor_owns_ambiguous_delete_entry_followup(): messages = [{ "role": "assistant", "content": ( "View event: [Forecast lock prep, 9:00 AM]" "(#event-12345678-abcd-4321-abcd-123456789abc)" ), }] assert _calendar_context_owns_ambiguous_mutation( "I finished early - go ahead and delete the prep entry.", messages ) def test_explicit_task_language_overrides_recent_calendar_anchor(): messages = [{ "role": "assistant", "content": ( "View event: [Forecast lock prep, 9:00 AM]" "(#event-12345678-abcd-4321-abcd-123456789abc)" ), }] assert not _calendar_context_owns_ambiguous_mutation( "Delete the scheduled task instead.", messages ) def test_contextual_calendar_entry_lookup_requires_fresh_tool_and_title_query(): messages = [{ "role": "assistant", "content": ( "View event: [Forecast scenario prep, 9:00 AM]" "(#event-12345678-abcd-4321-abcd-123456789abc)" ), }] prompt = "Show me that prep entry so I can confirm it doesn't collide." assert _calendar_lookup_requires_fresh_tool( prompt, {"notes_calendar_tasks"}, {"manage_calendar"}, messages, ) tool, command = _parse_simple_calendar_tool_request(prompt, messages) assert tool == "manage_calendar" assert json.loads(command)["query"] == "Forecast scenario prep" def test_memory_search_blocks_unrequested_full_list_escalation(): events = [{ "tool": "manage_memory", "command": "search\nphone number", "output": "No memories found matching 'phone number'.", "exit_code": 0, }] assert _memory_search_precedes_unrequested_list(events, False) assert not _memory_search_precedes_unrequested_list(events, True) def test_explicit_note_contents_request_extracts_title_for_locator_followup(): assert _parse_qwen_explicit_note_view( "Find my note called Japan, then show me its contents." ) == "Japan" assert _parse_qwen_explicit_note_view("Find my note called Japan") is None def test_note_view_summary_preserves_body_content(): assert _ody_qwen_terminal_tool_summary({ "tool": "manage_notes", "command": '{"action":"view","id":"abc123"}', "output": "AI: - [abc123] **Japan**\nTokyo itinerary", }) == "- [abc123] **Japan**\nTokyo itinerary" def test_test_request_gets_a_bounded_project_runner_fallback(): command = _tui_local_fallback_shell_command("Run the tests in this repo") assert command is not None assert "runner=.venv/bin/python" in command assert "runner=venv/bin/python" in command assert "else runner=python" in command assert '"$runner" -m pytest -q' in command assert "tests/test_tui_round_cap.py" not in command assert "npm test" in command assert "find ." not in command def test_tui_test_runner_prefers_workspace_python_environment(): command = _tui_local_test_runner_command() assert "[ -x .venv/bin/python ]" in command assert "runner=.venv/bin/python" in command assert "[ -x venv/bin/python ]" in command assert "runner=venv/bin/python" in command assert "git rev-parse --path-format=absolute --git-common-dir" in command assert '$(dirname "$git_common")/.venv/bin/python' in command assert "else runner=python" in command assert '"$runner" -m pytest -q' in command assert "git diff --name-only --diff-filter=ACMR HEAD" in command assert 'tests/test_${stem}.py' in command def test_tui_smoke_test_runner_is_repository_agnostic(): assert _tui_smoke_test_request("test now") assert _tui_smoke_test_request("Run tests now") assert _tui_smoke_test_request("Run a quick smoke test in this repo") assert _tui_smoke_test_request("Run tests, but keep it bounded and small") assert not _tui_smoke_test_request("Run the tests in this repo") command = _tui_local_smoke_test_runner_command() assert "tests/test_tui_round_cap.py" not in command assert "runner=.venv/bin/python" in command assert '"$runner" -m pytest -q' in command assert "npm test" in command def test_tui_host_shell_test_content_never_assumes_odysseus_test_paths(): broad = json.loads(_tui_local_test_runner_host_shell_content("Run the tests")) smoke = json.loads(_tui_local_test_runner_host_shell_content("Run a quick smoke test")) full = json.loads(_tui_local_test_runner_host_shell_content("Run the full test suite")) assert _tui_explicit_full_test_request("Run the full test suite") assert not _tui_explicit_full_test_request("Run the tests") assert "tests/test_tui_round_cap.py" not in broad["command"] assert "tests/test_tui_round_cap.py" not in smoke["command"] assert "tests/test_tui_round_cap.py" not in full["command"] assert broad["command"] == smoke["command"] assert broad["command"] != full["command"] assert "git diff --name-only" in broad["command"] assert "git diff --name-only" not in full["command"] assert broad["timeout"] == 120 assert smoke["timeout"] == 120 assert full["timeout"] == 120 def test_tui_pytest_normalizer_preserves_target_and_uses_shared_runner(): command = _tui_normalize_pytest_command( "python3 -m pytest -q tests/test_client.py -k nested_error" ) assert command is not None assert '"$runner" -m pytest -q tests/test_client.py -k nested_error' in command assert "git rev-parse --path-format=absolute --git-common-dir" in command assert _tui_normalize_pytest_command("pytest -q | tee results.txt") is None def test_bash_block_request_gets_a_generic_workspace_probe(): command = _tui_local_fallback_shell_command("Do a bash block.") assert command == "pwd; whoami; uname -srm" def test_filename_edit_in_explicit_workspace_is_coding_request(): assert _looks_like_workspace_coding_request( 'Edit fixture.py in the active workspace: change VALUE from "before" to "after".' ) def test_coding_project_request_gets_a_bounded_workspace_probe(): command = _tui_local_fallback_shell_command("I want to work on the Odysseus tui") assert command is not None assert 'workspace=$PWD' in command assert "git rev-parse --show-toplevel" in command assert "git_roots:" in command assert "ls -la" in command assert "find /" not in command def test_invalid_backend_workspace_tools_collapse_to_one_host_action(): blocks, recovered = _tui_recover_invalid_local_tools( [ToolBlock("get_workspace", ""), ToolBlock("ls", '{"path":"/app/data"}')], "I want to work on the Odysseus tui", ) assert recovered is True assert [block.tool_type for block in blocks] == ["host_shell"] assert "workspace=$PWD" in blocks[0].content assert "/app/data" not in blocks[0].content def test_host_bridge_coding_rules_do_not_conflict_with_backend_workspace_rules(): rules = _workspace_coding_rules("/host/home/project", host_bridge=True) assert "host bridge owns" in rules assert "do not call backend `get_workspace`" in rules assert "Start by orienting with `get_workspace`" not in rules def test_qwen_transport_markers_do_not_leak_into_tui_answer(): assert _normalize_ody_qwen_text_artifacts( "|start|\nThe local IP for ajax is 192.168.1.20.\n|end|" ) == "The local IP for ajax is 192.168.1.20." def test_network_summary_distinguishes_tailscale_from_lan_address(): assert _tui_network_summary( "100.67.207.85 ajax.tail.example\n" "5: wlan0 inet 192.168.1.8/24 scope global\n", "ajax", ) == ( "ajax resolves to `100.67.207.85`.\n" "That is a Tailscale address, not a LAN address.\n" "This host's LAN address is `192.168.1.8`." ) def test_project_discovery_fallback_lists_real_project_markers_not_home_noise(): command = _tui_local_fallback_shell_command( "Search my computer for the local project I was working on" ) assert command is not None assert "git_roots:" in command assert "project_manifests:" in command assert "node_modules" in command assert "ls -la" not in command def test_project_discovery_summary_is_bounded_and_uses_only_git_roots(): summary = _tui_project_discovery_summary( "workspace=/home/user\n" "git_roots:\n./project-a\n./project-a\n./project-b\n" "project_manifests:\n./project-a/pyproject.toml\n" ) assert summary == ( "Projects found in the active workspace:\n" "- ./project-a\n" "- ./project-b\n" "Select a project path and I can inspect its files or run its tests." ) def test_model_listing_has_a_deterministic_terminal_summary(): assert _ody_qwen_terminal_tool_summary({ "tool": "list_models", "command": "", "output": "Models:\n- qwen\n- gpt", }) == "Models:\n- qwen\n- gpt" def test_model_listing_summary_is_bounded(): output = "Available models (100 total):\n" + "\n".join(f"- model-{i}" for i in range(100)) summary = _ody_qwen_terminal_tool_summary({ "tool": "list_models", "command": "", "output": output, }) assert "more models omitted" in summary assert len(summary.splitlines()) == 25 def test_network_prompt_routes_away_from_container_shell(): routed = _route_tui_local_workspace_tools( {"bash", "web_search"}, client_runtime_context={ "surface": "odysseus-tui", "session_cwd": "/home/tester", "host_shell_bridge": {"url": "http://host.docker.internal:17654/run"}, "runtime_execution_contract": { "local_workspace_tasks": "use_host_shell_bridge", }, }, text="Find the local IP to SSH into ajax.", workspace=None, ) assert routed is not None assert "host_shell" in routed assert "bash" not in routed def test_local_only_prompt_gets_a_small_tool_surface(): routed = _route_tui_local_workspace_tools( {"bash", "web_search", "web_fetch", "manage_memory", "mcp__builtin_browser__browser_click"}, client_runtime_context={ "surface": "odysseus-tui", "session_cwd": "/home/tester", "host_shell_bridge": {"url": "http://host.docker.internal:17654/run"}, "runtime_execution_contract": { "local_workspace_tasks": "use_host_shell_bridge", }, }, text="Inspect this local project using local tools only.", workspace=None, ) assert routed == { "host_shell", "ask_user", "update_plan", "grep", "ls", "glob", "read_file", } def test_named_private_repo_discovery_stays_on_tui_host_surface(): prompt = "can you find odysseus private maintainer repo" context = _host_bridge_context() assert _tui_local_workspace_turn( prompt, workspace="/home/pewds/odysseus", client_runtime_context=context, ) assert _route_tui_local_workspace_tools( {"get_workspace", "ls", "host_shell", "web_search"}, client_runtime_context=context, text=prompt, workspace="/home/pewds/odysseus", ) == {"host_shell", "ask_user", "update_plan"} def test_bash_block_prompt_stays_on_tui_host_shell_surface(): routed = _route_tui_local_workspace_tools( {"bash", "host_shell", "web_search"}, client_runtime_context=_host_bridge_context(), text="Do a bash block.", workspace=None, ) assert routed == {"host_shell", "ask_user", "update_plan"} def test_tui_session_cwd_test_now_routes_to_host_shell_without_bridge(): routed = _route_tui_local_workspace_tools( {"web_search"}, client_runtime_context={"surface": "odysseus-tui", "session_cwd": "/tmp/repo"}, text="test now", workspace="/tmp/repo", ) assert routed == {"host_shell", "ask_user", "update_plan"} def test_tui_session_cwd_personal_request_does_not_route_to_host_shell_without_bridge(): routed = _route_tui_local_workspace_tools( {"manage_notes"}, client_runtime_context={"surface": "odysseus-tui", "session_cwd": "/tmp/repo"}, text="What's my notes?", workspace="/tmp/repo", ) assert routed == {"manage_notes"} def test_tui_bridge_general_chat_does_not_route_to_host_shell(): for prompt in ("Where is Sweden on a map?", "sned links", "hi"): routed = _route_tui_local_workspace_tools( {"host_shell", "web_search"}, client_runtime_context=_host_bridge_context(), text=prompt, workspace=None, ) assert routed == {"host_shell", "web_search"} def test_local_coding_prompt_exposes_transactional_patch_tools(): routed = _route_tui_local_workspace_tools( {"bash", "apply_patch", "todowrite", "web_search"}, client_runtime_context={ "surface": "odysseus-tui", "session_cwd": "/home/tester/project", "host_shell_bridge": {"url": "http://host.docker.internal:17654/run", "token": "x"}, "runtime_execution_contract": { "local_workspace_tasks": "use_host_shell_bridge", }, }, text="Fix the parser bug in this local project and run the tests.", workspace=None, ) assert routed == { "host_shell", "ask_user", "update_plan", "read_file", "write_file", "apply_patch", "edit_file", "todowrite", "grep", "ls", "glob", } def test_local_coding_prompt_routes_exact_edits_to_the_host_bridge(): routed = _route_tui_local_workspace_tools( {"edit_file", "apply_patch", "todowrite"}, client_runtime_context={ "surface": "odysseus-tui", "session_cwd": "/home/tester/project", "host_shell_bridge": {"url": "http://host.docker.internal:17654/run", "token": "x"}, "runtime_execution_contract": { "local_workspace_tasks": "use_host_shell_bridge", }, }, text="Change status=old to status=new in the file config.txt and verify it.", workspace=None, ) assert "edit_file" in routed def test_explicit_external_lookup_keeps_web_tools(): routed = _route_tui_local_workspace_tools( {"bash", "web_search", "web_fetch"}, client_runtime_context={ "surface": "odysseus-tui", "session_cwd": "/home/tester", "host_shell_bridge": {"url": "http://host.docker.internal:17654/run"}, "runtime_execution_contract": { "local_workspace_tasks": "use_host_shell_bridge", }, }, text="Inspect this project, then check the latest GitHub issue online.", workspace=None, ) assert {"host_shell", "web_search", "web_fetch"}.issubset(routed) def test_negated_web_request_stays_local_only(): routed = _route_tui_local_workspace_tools( {"bash", "web_search", "web_fetch"}, client_runtime_context={ "surface": "odysseus-tui", "session_cwd": "/home/tester", "host_shell_bridge": {"url": "http://host.docker.internal:17654/run"}, "runtime_execution_contract": { "local_workspace_tasks": "use_host_shell_bridge", }, }, text="Inspect the local project. Do not search the web.", workspace=None, ) assert routed == { "host_shell", "ask_user", "update_plan", "grep", "ls", "glob", "read_file", } def test_negated_web_phrase_does_not_make_local_project_external(): prompt = "Search my computer for the local project I was working on. Do not use the web." assert not _looks_like_explicit_tui_app_or_external_request(prompt) assert _tui_local_workspace_turn( prompt, workspace=None, client_runtime_context=_host_bridge_context(), ) def test_tui_local_turn_is_explicitly_narrowed(): assert _tui_local_workspace_turn( "Find the local IP to SSH into ajax.", workspace="/home/tester", client_runtime_context={ "surface": "odysseus-tui", "session_cwd": "/home/tester", "host_shell_bridge": {"url": "http://host.docker.internal:17654/run"}, "runtime_execution_contract": { "local_workspace_tasks": "use_host_shell_bridge", }, }, ) def test_local_network_turn_is_not_short_circuited_by_web_disabled_guard(): context = _host_bridge_context() assert not _web_search_unavailable_for_turn( {"web", "files"}, {"web_search", "web_fetch"}, "Find the local IP for ajax; do not use web search.", context, None, ) assert _web_search_unavailable_for_turn( {"web"}, {"web_search", "web_fetch"}, "Search the web for the latest Qwen release.", context, None, ) def test_local_project_turn_is_not_short_circuited_by_web_disabled_guard(): assert not _web_search_unavailable_for_turn( {"web", "files"}, {"web_search", "web_fetch"}, "Find the local Odysseus TUI project; do not search the web.", _host_bridge_context(), None, ) def _host_bridge_context(): return { "surface": "odysseus-tui", "session_cwd": "/home/tester/project", "host_shell_bridge": {"url": "http://host.docker.internal:17654/run"}, "runtime_execution_contract": { "local_workspace_tasks": "use_host_shell_bridge", }, } def test_active_workspace_does_not_hijack_saved_memory_lookup(): prompt = "Search saved memory for the Harbor Guji delay." assert _looks_like_explicit_tui_personal_domain_request(prompt) assert not _tui_local_workspace_turn( prompt, workspace="/home/tester/project", client_runtime_context=_host_bridge_context(), ) assert _route_tui_local_workspace_tools( {"host_shell", "manage_memory", "search_chats"}, client_runtime_context=_host_bridge_context(), text=prompt, workspace="/home/tester/project", ) == {"host_shell", "manage_memory", "search_chats"} def test_active_workspace_does_not_hijack_task_list(): prompt = "List my tasks." assert _looks_like_explicit_tui_personal_domain_request(prompt) assert not _tui_local_workspace_turn( prompt, workspace="/home/tester/project", client_runtime_context=_host_bridge_context(), ) def test_active_workspace_does_not_hijack_chat_session_list(): prompt = "List my chat sessions." assert _looks_like_explicit_tui_personal_domain_request(prompt) assert not _tui_local_workspace_turn( prompt, workspace="/home/tester/project", client_runtime_context=_host_bridge_context(), ) def test_rejected_backend_workspace_does_not_hijack_saved_memory_lookup(): prompt = "Search saved memory for the Harbor Guji delay. Do not use the workspace." assert not _tui_local_workspace_turn( prompt, workspace=None, client_runtime_context=_host_bridge_context(), ) def test_active_workspace_does_not_hijack_prior_chat_search(): prompt = "Find the prior chat where we fixed the parser." assert _looks_like_explicit_tui_personal_domain_request(prompt) assert not _tui_local_workspace_turn( prompt, workspace="/home/tester/project", client_runtime_context=_host_bridge_context(), ) def test_code_file_named_notes_stays_on_host_workspace(): prompt = "Fix the parser bug in notes.py and run the tests." assert not _looks_like_explicit_tui_personal_domain_request(prompt) assert _tui_local_workspace_turn( prompt, workspace="/home/tester/project", client_runtime_context=_host_bridge_context(), ) def test_active_workspace_does_not_hijack_model_picker_or_cookbook_requests(): for prompt in ( "What models are running on Odysseus?", "Switch to the Qwen model.", ): assert _looks_like_explicit_tui_app_or_external_request(prompt) assert not _tui_local_workspace_turn( prompt, workspace="/home/tester/project", client_runtime_context=_host_bridge_context(), ) def test_model_registry_requests_are_distinct_from_model_switches(): for prompt in ( "What models are running on the server?", "List the available models.", "Show served models.", ): assert _is_qwen_explicit_model_list_request(prompt), prompt for prompt in ("Switch to the Qwen model.", "Use the model qwen35."): assert not _is_qwen_explicit_model_list_request(prompt), prompt def test_latest_email_request_is_singular_but_email_search_is_not(): for prompt in ("What's my latest email?", "Show the newest mail."): assert _is_qwen_explicit_latest_email_request(prompt), prompt for prompt in ("Find emails from Runpod", "Search my inbox for messages about invoices"): assert not _is_qwen_explicit_latest_email_request(prompt), prompt def test_active_workspace_does_not_hijack_explicit_web_search(): prompt = "Search the web for the latest Qwen release." assert _looks_like_explicit_tui_app_or_external_request(prompt) assert not _tui_local_workspace_turn( prompt, workspace="/home/tester/project", client_runtime_context=_host_bridge_context(), ) def test_tdd_skill_plus_parser_task_stays_on_host_workspace(): prompt = "Use the TDD skill to fix the parser and run tests." assert not _looks_like_explicit_tui_personal_domain_request(prompt) assert _tui_local_workspace_turn( prompt, workspace="/home/tester/project", client_runtime_context=_host_bridge_context(), ) routed = _route_tui_local_workspace_tools( {"host_shell", "manage_skills", "apply_patch", "todowrite"}, client_runtime_context=_host_bridge_context(), text=prompt, workspace="/home/tester/project", ) assert "host_shell" in routed assert "manage_skills" in routed