Initial commit: Air Agent Framework v2:全双工对话智能体(打断、插话、主动开口)

This commit is contained in:
WpyQwq
2026-09-19 12:09:51 +08:00
commit fa0cb5824d
26 changed files with 2362 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
from __future__ import annotations
import asyncio
import sys
import shutil
from datetime import datetime
from .kernel import EventBus, Event, EventType
COLOR_RESET = "\033[0m"
COLOR_CYAN = "\033[36m"
COLOR_GREEN = "\033[32m"
COLOR_YELLOW = "\033[33m"
COLOR_GRAY = "\033[90m"
COLOR_RED = "\033[31m"
COLOR_BOLD = "\033[1m"
USE_COLOR = sys.stdout.isatty()
GRAY = "\033[90m"
CYAN = "\033[36m"
GREEN = "\033[32m"
YELLOW = "\033[33m"
RED = "\033[31m"
BOLD = "\033[1m"
RESET = "\033[0m"
class Display:
def __init__(self, bus: EventBus):
self.bus = bus
self._output_buffer = ""
self._input_line = ""
self._running = False
bus.on(EventType.AGENT_STREAM_CHUNK, self._on_chunk)
bus.on(EventType.AGENT_MESSAGE, self._on_message)
bus.on(EventType.AGENT_THOUGHT, self._on_thought)
bus.on(EventType.INTERRUPT, self._on_interrupt)
bus.on(EventType.ERROR, self._on_error)
bus.on(EventType.USER_INPUT_CHANGE, self._on_input_change)
async def _on_chunk(self, event: Event):
data = event.data
chunk = data["chunk"]
if not USE_COLOR:
print(chunk, end="", flush=True)
return
print(chunk, end="", flush=True)
async def _on_message(self, event: Event):
if USE_COLOR:
print(f"\n{GREEN}───{RESET}")
else:
print()
async def _on_thought(self, event: Event):
data = event.data
if data.get("type") == "idle_chat":
suggestion = data.get("suggestion", "")
if USE_COLOR:
print(f"\n{GRAY}[思考中... {suggestion}]{RESET}")
else:
print(f"\n[思考中... {suggestion}]")
async def _on_interrupt(self, event: Event):
if not USE_COLOR:
print("\n[打断]")
return
print(f"\n{YELLOW}⚡ [打断]{RESET}")
async def _on_error(self, event: Event):
msg = event.data
if USE_COLOR:
print(f"\n{RED}✗ 错误: {msg}{RESET}")
else:
print(f"\n✗ 错误: {msg}")
async def _on_input_change(self, event: Event):
pass
def show_prompt(self):
prompt = f"\n{COLOR_CYAN}你{COLOR_RESET} "
print(prompt, end="", flush=True)
def show_startup(self):
cols = shutil.get_terminal_size().columns
print(f"{GREEN}{'='*cols}{RESET}")
print(f"{GREEN}{BOLD} Air Agent 🤖 — 随时插嘴,想聊就聊{RESET}")
print(f"{GREEN}{'='*cols}{RESET}")
print(f"{GRAY} 直接打字聊天,试试说到一半停顿一下...{RESET}")
print()