@@ -1,17 +1,13 @@ |
| 1 | 1 | """The main agent loop.""" |
| 2 | 2 | |
| 3 | | -import asyncio |
| 4 | | -import contextlib |
| 5 | 3 | from collections.abc import AsyncIterator, Awaitable, Callable |
| 6 | 4 | from dataclasses import dataclass |
| 7 | 5 | from pathlib import Path |
| 8 | 6 | |
| 9 | 7 | from ..context.project import ProjectContext, detect_project |
| 10 | 8 | from ..llm.base import LLMBackend, Message |
| 11 | | -from ..runtime.bootstrap import build_runtime_bootstrap_source |
| 12 | 9 | from ..runtime.capabilities import resolve_backend_capability_profile |
| 13 | 10 | from ..runtime.events import AgentEvent, TurnSummary |
| 14 | | -from ..runtime.launcher import build_runtime_launcher |
| 15 | 11 | from ..runtime.permissions import ( |
| 16 | 12 | PermissionMode, |
| 17 | 13 | build_permission_policy, |
@@ -19,13 +15,15 @@ from ..runtime.permissions import ( |
| 19 | 15 | ) |
| 20 | 16 | from ..runtime.public_shell import ( |
| 21 | 17 | SteeringMailbox, |
| 22 | | - build_event_emitter, |
| 23 | 18 | build_fresh_runtime_session_install, |
| 24 | 19 | build_runtime_few_shot_examples, |
| 25 | 20 | build_runtime_system_message, |
| 26 | 21 | clear_runtime_shell_history, |
| 27 | 22 | refresh_runtime_shell_capability_profile, |
| 28 | 23 | resume_runtime_shell_session, |
| 24 | + run_runtime_shell, |
| 25 | + run_runtime_shell_explore, |
| 26 | + stream_runtime_shell, |
| 29 | 27 | ) |
| 30 | 28 | from ..runtime.safeguards import RuntimeSafeguards |
| 31 | 29 | from ..runtime.workflow import WorkflowMode |
@@ -228,11 +226,6 @@ class Agent: |
| 228 | 226 | |
| 229 | 227 | self.steering.queue(message) |
| 230 | 228 | |
| 231 | | - def build_runtime_source(self): |
| 232 | | - """Build the explicit runtime bootstrap source for public entrypoints.""" |
| 233 | | - |
| 234 | | - return build_runtime_bootstrap_source(self) |
| 235 | | - |
| 236 | 229 | def drain_steering_messages(self) -> list[str]: |
| 237 | 230 | """Drain queued runtime steering messages.""" |
| 238 | 231 | |
@@ -262,56 +255,22 @@ class Agent: |
| 262 | 255 | Returns: |
| 263 | 256 | The final response text |
| 264 | 257 | """ |
| 265 | | - emit = build_event_emitter(on_event) |
| 266 | | - |
| 267 | | - # Mark agent as running (enables steering) |
| 268 | | - self.steering.mark_running() |
| 269 | | - try: |
| 270 | | - launcher = build_runtime_launcher(self.build_runtime_source()) |
| 271 | | - return await launcher.run_user_message( |
| 272 | | - user_message, |
| 273 | | - emit, |
| 274 | | - on_confirmation=on_confirmation, |
| 275 | | - on_user_question=on_user_question, |
| 276 | | - use_plan=use_plan, |
| 277 | | - ) |
| 278 | | - finally: |
| 279 | | - self.steering.mark_idle() |
| 258 | + return await run_runtime_shell( |
| 259 | + self, |
| 260 | + user_message, |
| 261 | + on_event=on_event, |
| 262 | + on_confirmation=on_confirmation, |
| 263 | + on_user_question=on_user_question, |
| 264 | + use_plan=use_plan, |
| 265 | + ) |
| 280 | 266 | |
| 281 | 267 | async def run_streaming( |
| 282 | 268 | self, |
| 283 | 269 | user_message: str, |
| 284 | 270 | ) -> AsyncIterator[AgentEvent]: |
| 285 | 271 | """Run the agent with streaming output from the primary runtime path.""" |
| 286 | | - |
| 287 | | - queue: asyncio.Queue[AgentEvent | BaseException | None] = asyncio.Queue() |
| 288 | | - |
| 289 | | - async def on_event(event: AgentEvent) -> None: |
| 290 | | - await queue.put(event) |
| 291 | | - |
| 292 | | - async def run_agent() -> None: |
| 293 | | - try: |
| 294 | | - await self.run(user_message, on_event=on_event) |
| 295 | | - except BaseException as exc: # pragma: no cover - propagated below |
| 296 | | - await queue.put(exc) |
| 297 | | - finally: |
| 298 | | - await queue.put(None) |
| 299 | | - |
| 300 | | - task = asyncio.create_task(run_agent()) |
| 301 | | - try: |
| 302 | | - while True: |
| 303 | | - item = await queue.get() |
| 304 | | - if item is None: |
| 305 | | - break |
| 306 | | - if isinstance(item, BaseException): |
| 307 | | - raise item |
| 308 | | - yield item |
| 309 | | - await task |
| 310 | | - finally: |
| 311 | | - if not task.done(): |
| 312 | | - task.cancel() |
| 313 | | - with contextlib.suppress(asyncio.CancelledError): |
| 314 | | - await task |
| 272 | + async for event in stream_runtime_shell(self, user_message): |
| 273 | + yield event |
| 315 | 274 | |
| 316 | 275 | async def run_explore( |
| 317 | 276 | self, |
@@ -321,15 +280,12 @@ class Agent: |
| 321 | 280 | fresh: bool = False, |
| 322 | 281 | ) -> str: |
| 323 | 282 | """Run one read-only explore query outside the main workflow runtime.""" |
| 324 | | - emit = build_event_emitter(on_event) |
| 325 | | - |
| 326 | | - launcher = build_runtime_launcher(self.build_runtime_source()) |
| 327 | | - self.last_turn_summary = await launcher.run_explore( |
| 283 | + return await run_runtime_shell_explore( |
| 284 | + self, |
| 328 | 285 | user_message, |
| 329 | | - emit, |
| 286 | + on_event=on_event, |
| 330 | 287 | fresh=fresh, |
| 331 | 288 | ) |
| 332 | | - return self.last_turn_summary.final_response |
| 333 | 289 | |
| 334 | 290 | def clear_history(self) -> None: |
| 335 | 291 | """Clear conversation history.""" |