Python · 5313 bytes Raw Blame History
1 """Tests for the runtime-first internal handle below Agent."""
2
3 from __future__ import annotations
4
5 from pathlib import Path
6
7 import pytest
8
9 from loader.agent.loop import AgentConfig
10 from loader.llm.base import CompletionResponse, StreamChunk
11 from loader.runtime.bootstrap import RuntimeBootstrapView, build_runtime_context
12 from loader.runtime.conversation import ConversationRuntime
13 from loader.runtime.launcher import RuntimeLauncher, build_runtime_launcher
14 from loader.runtime.runtime_handle import RuntimeHandle
15 from tests.helpers.runtime_harness import ScriptedBackend, run_explore_scenario, run_scenario
16
17
18 def test_runtime_handle_builds_runtime_bootstrap_contract(
19 temp_dir: Path,
20 ) -> None:
21 handle = RuntimeHandle(
22 backend=ScriptedBackend(),
23 config=AgentConfig(auto_context=False),
24 project_root=temp_dir,
25 )
26
27 launcher = build_runtime_launcher(handle)
28 context = build_runtime_context(handle)
29
30 assert isinstance(launcher, RuntimeLauncher)
31 assert isinstance(launcher.source, RuntimeBootstrapView)
32 assert launcher.source is not handle
33 assert launcher.source.metadata == {"owner_type": "RuntimeHandle"}
34 assert context.project_root == temp_dir.resolve()
35 assert context.backend is handle.backend
36 assert context.registry is handle.registry
37 assert context.session is handle.session
38 assert context.permission_policy is handle.permission_policy
39 assert context.workflow_mode == handle.workflow_mode
40
41
42 @pytest.mark.asyncio
43 async def test_runtime_handle_runs_conversation_runtime_without_agent(
44 temp_dir: Path,
45 ) -> None:
46 handle = RuntimeHandle(
47 backend=ScriptedBackend(
48 completions=[CompletionResponse(content="Runtime handle reply.")]
49 ),
50 config=AgentConfig(auto_context=False, stream=False),
51 project_root=temp_dir,
52 )
53 runtime = ConversationRuntime(handle)
54 events = []
55
56 async def emit(event) -> None:
57 events.append(event)
58
59 summary = await runtime.run_turn(
60 "Explain why runtime-first seams matter here.",
61 emit,
62 requested_mode="execute",
63 )
64
65 assert summary.final_response == "Runtime handle reply."
66 assert runtime.source.metadata == {"owner_type": "RuntimeHandle"}
67 assert any(event.type == "response" for event in events)
68
69
70 @pytest.mark.asyncio
71 async def test_runtime_handle_runs_public_shell_entrypoint_without_agent(
72 temp_dir: Path,
73 ) -> None:
74 handle = RuntimeHandle(
75 backend=ScriptedBackend(
76 completions=[CompletionResponse(content="Runtime handle shell reply.")]
77 ),
78 config=AgentConfig(auto_context=False, stream=False),
79 project_root=temp_dir,
80 )
81 events = []
82
83 async def emit(event) -> None:
84 events.append(event)
85
86 response = await handle.run(
87 "Summarize the runtime-first shell path.",
88 on_event=emit,
89 use_plan=False,
90 )
91
92 assert response == "Runtime handle shell reply."
93 assert handle.last_turn_summary is not None
94 assert handle.last_turn_summary.final_response == "Runtime handle shell reply."
95 assert any(event.type == "response" for event in events)
96
97
98 @pytest.mark.asyncio
99 async def test_runtime_handle_runs_explore_and_streaming_entrypoints_without_agent(
100 temp_dir: Path,
101 ) -> None:
102 handle = RuntimeHandle(
103 backend=ScriptedBackend(
104 completions=[CompletionResponse(content="Explore with runtime handle.")],
105 streams=[
106 [
107 StreamChunk(content="Streamed ", is_done=False),
108 StreamChunk(
109 content="runtime reply.",
110 full_content="Streamed runtime reply.",
111 is_done=True,
112 ),
113 ]
114 ],
115 ),
116 config=AgentConfig(auto_context=False),
117 project_root=temp_dir,
118 )
119
120 stream_events = [event async for event in handle.run_streaming("thanks")]
121 explore_response = await handle.run_explore(
122 "Where should I start in this repo?",
123 )
124
125 assert any(
126 event.type == "response" and event.content == "Streamed runtime reply."
127 for event in stream_events
128 )
129 assert explore_response == "Explore with runtime handle."
130 assert handle.last_turn_summary is not None
131 assert handle.last_turn_summary.workflow_mode == "explore"
132
133
134 @pytest.mark.asyncio
135 async def test_runtime_harness_uses_runtime_handle_for_scripted_runs(
136 temp_dir: Path,
137 ) -> None:
138 run = await run_scenario(
139 "Summarize the runtime-first harness.",
140 ScriptedBackend(
141 completions=[CompletionResponse(content="Runtime harness reply.")]
142 ),
143 config=AgentConfig(auto_context=False, stream=False),
144 project_root=temp_dir,
145 )
146 explore_run = await run_explore_scenario(
147 "Where should I start?",
148 ScriptedBackend(
149 completions=[CompletionResponse(content="Explore harness reply.")]
150 ),
151 config=AgentConfig(auto_context=False, stream=False),
152 project_root=temp_dir,
153 )
154
155 assert isinstance(run.agent, RuntimeHandle)
156 assert run.response == "Runtime harness reply."
157 assert isinstance(explore_run.agent, RuntimeHandle)
158 assert explore_run.response == "Explore harness reply."