tenseleyflow/loader / 5b9c14f

Browse files

Move conversational fast path into runtime launcher

Authored by espadonne
SHA
5b9c14f85ebea90049931c329e1b983ab91d2c38
Parents
c61058b
Tree
b7a78b3

3 changed files

StatusFile+-
M src/loader/agent/loop.py 2 48
A src/loader/runtime/chat_lane.py 55 0
M src/loader/runtime/launcher.py 11 0
src/loader/agent/loop.pymodified
@@ -375,53 +375,6 @@ class Agent:
375375
         )
376376
         return parse_decomposition(response.content, task)
377377
 
378
-    async def _handle_conversational(
379
-        self,
380
-        user_message: str,
381
-        emit: Callable[[AgentEvent], Awaitable[None]],
382
-    ) -> str:
383
-        """Fast path for conversational messages - no tools, quick response."""
384
-        await emit(AgentEvent(type="thinking"))
385
-
386
-        # Add to history
387
-        self.session.append(Message(role=Role.USER, content=user_message))
388
-
389
-        # Simple system prompt for chat (no tools)
390
-        chat_system = Message(
391
-            role=Role.SYSTEM,
392
-            content=(
393
-                "You are Loader, a friendly local coding assistant. "
394
-                "Respond naturally and briefly to conversational messages. "
395
-                "If the user wants to do a coding task, tell them to describe it. "
396
-                "Keep responses short (1-3 sentences)."
397
-            ),
398
-        )
399
-
400
-        # Use only recent context for speed
401
-        recent_messages = self.messages[-4:] if len(self.messages) > 4 else self.messages
402
-
403
-        # Stream the response
404
-        full_content = ""
405
-        async for chunk in self.backend.stream(
406
-            messages=[chat_system] + recent_messages,
407
-            tools=None,  # No tools for chat
408
-            temperature=0.7,  # More natural
409
-            max_tokens=256,  # Short response
410
-        ):
411
-            if chunk.content:
412
-                await emit(AgentEvent(
413
-                    type="stream",
414
-                    content=chunk.content,
415
-                    is_stream_end=chunk.is_done,
416
-                ))
417
-                full_content += chunk.content
418
-
419
-        # Add to history
420
-        self.session.append(Message(role=Role.ASSISTANT, content=full_content))
421
-
422
-        await emit(AgentEvent(type="response", content=full_content))
423
-        return full_content
424
-
425378
     async def run(
426379
         self,
427380
         user_message: str,
@@ -474,10 +427,11 @@ class Agent:
474427
     ) -> str:
475428
         """Internal run method that supports steering."""
476429
         cfg = self.config.reasoning
430
+        launcher = build_runtime_launcher(self)
477431
 
478432
         # Fast path: conversational messages don't need tools
479433
         if is_conversational(user_message):
480
-            return await self._handle_conversational(user_message, emit)
434
+            return await launcher.run_conversational(user_message, emit)
481435
 
482436
         # Track original task for multi-turn conversations
483437
         # Only set on first non-conversational message
src/loader/runtime/chat_lane.pyadded
@@ -0,0 +1,55 @@
1
+"""Runtime-owned conversational fast path for non-tool chat turns."""
2
+
3
+from __future__ import annotations
4
+
5
+from ..llm.base import Message, Role
6
+from .bootstrap import RuntimeBootstrapSource
7
+from .events import AgentEvent
8
+
9
+CHAT_SYSTEM_PROMPT = (
10
+    "You are Loader, a friendly local coding assistant. "
11
+    "Respond naturally and briefly to conversational messages. "
12
+    "If the user wants to do a coding task, tell them to describe it. "
13
+    "Keep responses short (1-3 sentences)."
14
+)
15
+
16
+
17
+class ConversationalTurnRunner:
18
+    """Own the non-tool conversational fast path outside the agent shell."""
19
+
20
+    def __init__(self, source: RuntimeBootstrapSource) -> None:
21
+        self.source = source
22
+
23
+    async def run(self, user_message: str, emit) -> str:
24
+        """Stream one short conversational reply and persist the transcript."""
25
+
26
+        await emit(AgentEvent(type="thinking"))
27
+        self.source.session.append(Message(role=Role.USER, content=user_message))
28
+
29
+        recent_messages = (
30
+            self.source.session.messages[-4:]
31
+            if len(self.source.session.messages) > 4
32
+            else self.source.session.messages
33
+        )
34
+        chat_system = Message(role=Role.SYSTEM, content=CHAT_SYSTEM_PROMPT)
35
+
36
+        full_content = ""
37
+        async for chunk in self.source.backend.stream(
38
+            messages=[chat_system] + recent_messages,
39
+            tools=None,
40
+            temperature=0.7,
41
+            max_tokens=256,
42
+        ):
43
+            if chunk.content:
44
+                await emit(
45
+                    AgentEvent(
46
+                        type="stream",
47
+                        content=chunk.content,
48
+                        is_stream_end=chunk.is_done,
49
+                    )
50
+                )
51
+                full_content += chunk.content
52
+
53
+        self.source.session.append(Message(role=Role.ASSISTANT, content=full_content))
54
+        await emit(AgentEvent(type="response", content=full_content))
55
+        return full_content
src/loader/runtime/launcher.pymodified
@@ -3,6 +3,7 @@
33
 from __future__ import annotations
44
 
55
 from .bootstrap import RuntimeBootstrapSource
6
+from .chat_lane import ConversationalTurnRunner
67
 from .conversation import ConfirmationHandler, ConversationRuntime, EventSink, UserQuestionHandler
78
 from .events import TurnSummary
89
 from .explore import ExploreRuntime
@@ -14,6 +15,16 @@ class RuntimeLauncher:
1415
     def __init__(self, source: RuntimeBootstrapSource) -> None:
1516
         self.source = source
1617
 
18
+    async def run_conversational(
19
+        self,
20
+        user_message: str,
21
+        emit: EventSink,
22
+    ) -> str:
23
+        """Run the runtime-owned conversational fast path."""
24
+
25
+        runner = ConversationalTurnRunner(self.source)
26
+        return await runner.run(user_message, emit)
27
+
1728
     async def run_turn(
1829
         self,
1930
         task: str,