new-qwen/README.md

163 lines
6.4 KiB
Markdown
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.

# new-qwen
Клиент-серверная замена локального агента `qwen-code` с серверной оркестрацией моделей.
- `serv` отвечает за OAuth, сессии, маршрутизацию к model provider-ам и вызов инструментов.
- `bot` отвечает за Telegram и пересылку сообщений на сервер.
Проект написан на Python stdlib, чтобы не зависеть от Node/npm в текущем окружении.
## Архитектура
```text
Telegram User
|
v
bot/app.py
|
v
serv/app.py
|
v
Qwen OAuth + OpenAI-compatible endpoint
```
На стороне `serv` теперь есть отдельные слои:
- `model_router.py` - выбор провайдера и fallback policy
- `llm.py` - агентный цикл поверх абстракции провайдера
- `oauth.py` - auth only для Qwen path
## Что уже реализовано
- Qwen OAuth Device Flow, совместимый с `qwen-code`
- хранение токенов в `~/.qwen/oauth_creds.json`
- HTTP API сервера
- агентный цикл с tool calling
- инструменты: `list_files`, `glob_search`, `grep_text`, `stat_path`, `read_file`, `web_search`, `append_file`, `apply_unified_diff`, `replace_in_file`, `write_file`, `make_directory`, `delete_path`, `move_path`, `copy_path`, `git_status`, `git_diff`, `exec_command`
- Telegram polling без внешних библиотек
- JSON-хранилище сессий
- API списка и просмотра сессий
- автоматический polling OAuth flow в боте
- очередь сообщений, пришедших до завершения OAuth
- job-based chat polling между `bot` и `serv`
- persistence для chat jobs и pending OAuth flows на стороне `serv`
- policy mode для инструментов: `full-access`, `workspace-write`, `read-only`
- live approval flow для инструментов через Telegram
- provider-based web search с приоритетом DashScope через Qwen OAuth
- model router с `qwen` как первым провайдером и fallback-ready архитектурой для `gigachat` и `yandexgpt`
- router умеет fallback не только по конфигу, но и при runtime-ошибке провайдера
## Ограничения текущей реализации
- это упрощённая серверная архитектура, а не побайтный порт всего `qwen-code`
- пока нет MCP, skill system, subagents и rich-streaming UI
- Telegram-бот работает через long polling
## Roadmap
Текущий список работ вынесен в [TODO.md](./TODO.md).
Ближайший фокус:
- сериализация jobs на один Telegram chat
- cancel flow между `bot` и `serv`
- выравнивание approval semantics для всех chat API
## Переменные окружения
Сервер:
```bash
cp serv/.env.example serv/.env
```
Ключевые параметры сервера:
- `NEW_QWEN_STATE_DIR` - где хранить jobs и pending OAuth flows
- `NEW_QWEN_DEFAULT_PROVIDER` - основной model provider, сейчас по умолчанию `qwen`
- `NEW_QWEN_FALLBACK_PROVIDERS` - fallback-цепочка провайдеров через запятую
- `NEW_QWEN_GIGACHAT_MODEL` - имя модели для будущего GigaChat adapter
- `NEW_QWEN_YANDEXGPT_MODEL` - имя модели для будущего YandexGPT adapter
- `NEW_QWEN_TOOL_POLICY` - режим инструментов:
`full-access` - все инструменты
`workspace-write` - без `exec_command`
`read-only` - только чтение и поиск
`ask-shell` - shell только после подтверждения
`ask-write` - shell и записи только после подтверждения
`ask-all` - любой инструмент только после подтверждения
- `NEW_QWEN_APPROVAL_TIMEOUT_SECONDS` - сколько сервер ждёт решения по approval
- `NEW_QWEN_JOBS_RETENTION_SECONDS` - сколько хранить завершённые/failed jobs
- `NEW_QWEN_APPROVALS_RETENTION_SECONDS` - сколько хранить завершённые approvals
- `NEW_QWEN_TAVILY_API_KEY` - опциональный Tavily provider
- `NEW_QWEN_GOOGLE_SEARCH_API_KEY` и `NEW_QWEN_GOOGLE_SEARCH_ENGINE_ID` - опциональный Google Custom Search provider
Бот:
```bash
cp bot/.env.example bot/.env
```
## Запуск
Сервер:
```bash
python3 serv/app.py
```
Бот:
```bash
python3 bot/app.py
```
## Авторизация Qwen OAuth
1. Отправить боту `/auth`
2. Открыть ссылку подтверждения
3. Бот сам дождётся завершения OAuth и продолжит работу
Если пользователь отправит обычное сообщение до завершения OAuth, бот поставит его в очередь и автоматически отправит на сервер после успешной авторизации.
Либо можно вызвать API сервера напрямую:
```bash
curl -X POST http://127.0.0.1:8080/api/v1/auth/device/start
```
## API
- `GET /health`
- `GET /api/v1/auth/status`
- `POST /api/v1/auth/device/start`
- `POST /api/v1/auth/device/poll`
- `GET /api/v1/sessions`
- `GET /api/v1/approvals`
- `POST /api/v1/session/get`
- `POST /api/v1/session/clear`
- `POST /api/v1/chat`
- `POST /api/v1/chat/start`
- `POST /api/v1/chat/poll`
- `POST /api/v1/chat/cancel`
- `POST /api/v1/approval/respond`
`GET /api/v1/auth/status` теперь также показывает:
- `default_provider`
- `fallback_providers`
- список `providers` с availability и capabilities
## Telegram Approval Flow
Если политика инструментов настроена как `ask-shell`, `ask-write` или `ask-all`, бот пришлёт запрос на подтверждение с `approval_id`.
Дальше можно ответить одной из команд:
- `/approve <approval_id>`
- `/reject <approval_id>`
Управление job:
- `/cancel` - отменить активный запрос и очистить очередь сообщений в чате