100 lines
3.8 KiB
Python
100 lines
3.8 KiB
Python
from __future__ import annotations
|
|
import asyncio
|
|
import sys
|
|
|
|
from agent.kernel import Event, EventType, AgentRuntime
|
|
from agent.llm import LLMClient
|
|
from agent.personality import Personality
|
|
from agent.conversation import ConversationManager
|
|
from agent.interruption import InterruptionEngine, InterruptionDecision
|
|
from agent.thinker import Thinker
|
|
from agent.orchestrator import Orchestrator
|
|
from agent.stream_input import StreamInput
|
|
from agent.display import Display
|
|
|
|
from config.settings import AppSettings
|
|
|
|
|
|
class ChatCLI:
|
|
def __init__(self, config: AppSettings):
|
|
self.config = config
|
|
self.runtime = AgentRuntime(config)
|
|
self.llm = LLMClient(config.llm)
|
|
self.bus = self.runtime.bus
|
|
self.personality = Personality.from_config({
|
|
"name": config.personality.name,
|
|
"style": config.personality.style,
|
|
"proactive_chat": config.personality.proactive_chat,
|
|
"idle_timeout": config.personality.idle_timeout,
|
|
"humor_enabled": config.personality.humor_enabled,
|
|
"empathy_enabled": config.personality.empathy_enabled,
|
|
})
|
|
self.conversation = ConversationManager()
|
|
self.interruption = InterruptionEngine(llm=self.llm, config=config)
|
|
self.thinker = Thinker(self.bus, self.llm, self.conversation, config)
|
|
self.orchestrator = Orchestrator(
|
|
self.runtime, self.llm, self.personality,
|
|
self.conversation, self.interruption, self.thinker,
|
|
)
|
|
self.display = Display(self.bus)
|
|
self.stream_input = StreamInput(self.bus)
|
|
self.conversation.create_topic("general")
|
|
|
|
self.bus.on(EventType.USER_PAUSE, self._on_user_pause)
|
|
self.bus.on(EventType.AGENT_THOUGHT, self._on_thought)
|
|
|
|
async def _on_thought(self, event: Event):
|
|
data = event.data
|
|
if data.get("type") == "idle_chat":
|
|
topic = data.get("suggestion", "")
|
|
print(f"\n\033[90m[AI 在想:{topic}]\033[0m")
|
|
|
|
async def _on_user_pause(self, event: Event):
|
|
data = event.data
|
|
text = data.get("text", "")
|
|
pause = data.get("pause", 0)
|
|
context = self.conversation.get_context_window(6)
|
|
decision = await self.interruption.evaluate(
|
|
text, pause, False, context=context,
|
|
)
|
|
if decision.should_interrupt:
|
|
self.thinker.notify_user_activity()
|
|
resp = decision.suggested_response or "..."
|
|
print(f"\n\033[33m[打断]\033[0m \033[36m{self.personality.name}\033[0m {resp}")
|
|
self.display.show_prompt()
|
|
|
|
async def _handle_message(self, text: str):
|
|
self.thinker.notify_user_activity()
|
|
self.conversation.add_message("user", text)
|
|
system_prompt = self.personality.build_system_prompt()
|
|
messages = [{"role": "system", "content": system_prompt}]
|
|
messages.extend(self.conversation.get_context_window(20))
|
|
print(f"\n\033[36m{self.personality.name}\033[0m ", end="")
|
|
full = ""
|
|
try:
|
|
async for chunk in self.llm.chat_stream_iter(messages):
|
|
print(chunk, end="", flush=True)
|
|
full += chunk
|
|
print()
|
|
except Exception as e:
|
|
print(f"\n\033[31m[错误: {e}]\033[0m")
|
|
if full.strip():
|
|
self.conversation.add_message("assistant", full)
|
|
|
|
async def run(self):
|
|
self.display.show_startup()
|
|
await self.runtime.start()
|
|
thinker_task = self.runtime.create_task(self.thinker.run())
|
|
|
|
async def on_sentence(text: str):
|
|
await self._handle_message(text)
|
|
|
|
try:
|
|
self.display.show_prompt()
|
|
await self.stream_input.listen_cli(on_sentence=on_sentence)
|
|
except KeyboardInterrupt:
|
|
print("\n再见!")
|
|
finally:
|
|
await self.runtime.stop()
|
|
await self.llm.close()
|