Files
cosmo-voice-assistant/cosmo/agent.py
d.klimov 6010816f1d Initial commit: Cosmo voice assistant
Полностью локальный голосовой ассистент на Python.

Стек:
- Wake word: openWakeWord (onnxruntime)
- STT: RealtimeSTT + faster-whisper + Silero VAD (CUDA)
- LLM-агент: smolagents ToolCallingAgent + Ollama qwen2.5:7b
- TTS: Silero V4 (torch.hub) + sounddevice
- Shell: Git Bash (Windows) / bash (macOS)

Поддерживает Windows и macOS. Агент с памятью и tool calling —
находит программы самостоятельно, запоминает пути, выполняет
произвольные shell-команды.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 15:58:12 +03:00

90 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Агент на базе smolagents + Ollama.
Использует ToolCallingAgent — LLM вызывает инструменты через JSON tool calling.
Продолжает работу пока задача не решена (до max_steps).
"""
import os
import platform
from loguru import logger
from smolagents import ToolCallingAgent, LiteLLMModel
from cosmo.memory import Memory
# Выбираем инструменты под текущую платформу
if platform.system() == "Darwin" or os.environ.get("COSMO_PLATFORM") == "mac":
from cosmo.tools_mac import ALL_TOOLS, set_memory
_PLATFORM_NOTE = "macOS. Используй bash, 'open -a AppName' для запуска приложений, mdfind для поиска файлов."
else:
from cosmo.tools import ALL_TOOLS, set_memory
_PLATFORM_NOTE = "Windows. Используй Git Bash, 'start' для запуска приложений."
SYSTEM_PROMPT = f"""Ты — Cosmo, умный голосовой ассистент. Платформа: {_PLATFORM_NOTE}
Правила:
1. Используй инструменты для выполнения задач — не выдумывай результаты
2. Если первая попытка не сработала — пробуй другой подход, не сдавайся
3. Перед поиском программы — проверь память (memory_get), может путь уже известен
4. Если нашёл путь к программе — сохрани в память (memory_set) чтобы не искать повторно
5. Отвечай коротко на русском языке — пользователь слушает голосом, не читает
Факты из памяти о пользователе и системе:
{memory_facts}
"""
class Agent:
def __init__(self, config: dict, memory: Memory):
self.memory = memory
self._cfg = config["ollama"]
# Передаём память в инструменты
set_memory(memory)
model_id = f"ollama/{self._cfg['model']}"
logger.info(f"Инициализирую smolagents с моделью {model_id}")
self._model = LiteLLMModel(
model_id=model_id,
api_base=self._cfg["base_url"],
temperature=self._cfg.get("temperature", 0.2),
max_tokens=self._cfg.get("max_tokens", 1024),
)
self._agent = ToolCallingAgent(
tools=ALL_TOOLS,
model=self._model,
max_steps=self._cfg.get("max_agent_steps", 10),
verbosity_level=1,
)
logger.info("Агент готов")
def run(self, user_input: str) -> str:
"""
Обработать команду пользователя.
Возвращает финальный текст ответа для TTS.
"""
logger.info(f"Агент: '{user_input}'")
# Сохраняем в историю
self.memory.add_message("user", user_input)
# Формируем промпт с текущей памятью
system = SYSTEM_PROMPT.format(memory_facts=self.memory.facts_as_text())
# smolagents принимает задачу и опциональный системный промпт
try:
result = self._agent.run(
user_input,
additional_args={"system_prompt_override": system},
)
response = str(result).strip() if result else "Готово"
except Exception as e:
logger.error(f"Ошибка агента: {e}")
response = "Произошла ошибка при выполнении команды"
self.memory.add_message("assistant", response)
logger.info(f"Агент ответил: '{response}'")
return response