Skip to main content
Glama
README.md
# 🧭 Компас — переговорный тревел-агент для путешествий по России

Агент, которому семья из Екатеринбурга пишет одной фразой:

> «Хотим к морю, 45 000 на троих, с ребёнком, без долгих пересадок»

— а он сам находит **противоречие между бюджетом и пересадками**, показывает развилку прямо на
таймлайне, спрашивает чем пожертвовать, помнит ответы и держит наготове **план Б** на каждое
хрупкое звено маршрута.

Проект для ИИ-хакатона Туту MCP, 18–21 августа 2026. Работает поверх [Tutu MCP](https://mcp.tutu.ru/mcp)
(самолёты, поезда, электрички, автобусы, отели).

![Развилка: бюджет против «без поезда» — агент спрашивает, чем пожертвовать](docs/screenshots/05-conflict.png)

| | |
|---|---|
| ![Стартовый экран: карта с ценами до соседних городов](docs/screenshots/01-start.png) | ![Клик по городу: ближайшие рейсы и цены без единого токена LLM](docs/screenshots/02-city-price.png) |
| ![Сбой звена: «было → стало», план Б применён мгновенно](docs/screenshots/07-switched.png) | ![Тот же агент как MCP App: интерактивный виджет в чате Claude](docs/screenshots/08-mcp-widget.png) |

*Слева направо: стартовая карта-исследование (клики по городам не тратят токены — только Tutu MCP);
плашка города с рейсами и ±день; переключение на план Б после сбоя; MCP-виджет (SEP-1865).*

## Чем это отличается от «ещё одного поиска билетов»

| Обычный поиск | Компас |
|---|---|
| Форма с десятью полями | Одна фраза на естественном языке |
| «Ничего не найдено» | «Уложиться в бюджет **и** в пересадку < 1 ч одновременно нельзя — чем пожертвуем?» |
| Лучший вариант по формуле | Развилка с честным trade-off и памятью о вашем выборе |
| Билеты кончились — начинайте сначала | План Б просчитан заранее, переключение мгновенное |

## Быстрый старт

```bash
git clone https://github.com/svyatrunov/tutu-compass.git && cd tutu-compass
```

```bash
npm install
```

```bash
cp deploy/.env.example apps/server/.env
```

Заполните `OPENROUTER_API_KEY` в `apps/server/.env` и запустите:

```bash
npm run dev
```

Фронт — http://localhost:5173, API — http://localhost:8787 (Vite проксирует `/api`).

Демо без интернета и без ключей — на записанных фикстурах:

```bash
DEMO_MODE=replay npm run dev
```

Прод целиком в докере:

```bash
cd deploy && cp .env.example .env && docker compose up -d --build
```

## Компас как MCP-сервер

Тот же агент доступен как MCP-тул `plan_trip` — один вызов вместо ручной оркестрации
16 сырых тулов Туту. Endpoint: `http://localhost:8787/mcp` после `npm run dev`
(Streamable HTTP; на своём сервере — `https://<домен>/mcp`). Быстро посмотреть виджет
без MCP-хоста: `http://localhost:8787/api/dev/widget-preview`. В хостах
с поддержкой MCP Apps (Claude, Claude Desktop, VS Code Copilot, Goose) результат
рендерится интерактивным таймлайном прямо в чате (SEP-1865); остальные MCP-клиенты
получают текст + структурированный JSON. Память диалога — через `sessionId`
в аргументах тула. Веб-версия — основной канал и от MCP-канала не зависит:
оба живут в одном процессе поверх одного ядра `agent/*`.

Проверка канала: `npm run smoke:mcpapp` против запущенного сервера.

## Полезные команды

| Команда | Что делает |
|---|---|
| `npm run mcp:discover` | Снимает фактическую спецификацию тулов Туту → `docs/MCP-NOTES.md` |
| `npm run fixtures:record` | Записывает ответы MCP в `fixtures/recorded` для реплея |
| `npm test` | Unit-тесты конфликтов и плана Б + contract-тесты схем MCP |
| `npm run smoke` | E2E-прогон демо-сценария против поднятого сервера |
| `npm run lint` / `npm run typecheck` | ESLint / TypeScript strict |

## Документация

| Документ | Зачем |
|---|---|
| [`docs/AGENT-BRIEF.md`](docs/AGENT-BRIEF.md) | **Начните отсюда.** Самодостаточная справка для оценки: флоу, стек, бенчмарки, самооценка по трекам хакатона |
| [`docs/SYSTEM-MAP.md`](docs/SYSTEM-MAP.md) | Карта системы: 16 тулов Туту → наши модули → каналы + быстрые ответы на вопросы жюри |
| [`docs/ROADMAP.md`](docs/ROADMAP.md) | Рабочий план до code freeze, ранжирован по «баллам за час» |
| [`docs/MCP-FEEDBACK.md`](docs/MCP-FEEDBACK.md) | 12 структурированных предложений к спецификации Tutu MCP — с воспроизводимыми находками |
| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | Схема, цикл агента, детекция конфликтов |
| [`docs/ASSUMPTIONS.md`](docs/ASSUMPTIONS.md) | Честный список: что реально из MCP, что имитация |
| [`docs/MCP-NOTES.md`](docs/MCP-NOTES.md) | Фактическая (не заявленная) спецификация Tutu MCP |
| [`docs/EVALS.md`](docs/EVALS.md) | Стратегия моделей и журнал находок бенчмарка |
| [`docs/PITCH.md`](docs/PITCH.md) | Тезисы и тайминг питча |

## Где смотреть код по критериям хакатона

| Критерий | Где смотреть |
|---|---|
| Глубина функционала | [`agent/orchestrator.ts`](apps/server/src/agent/orchestrator.ts) — цикл агента |
| Инновационность | [`agent/conflicts.ts`](apps/server/src/agent/conflicts.ts) — конфликт как доказуемый факт, **без единого вызова LLM** |
| UX/UI | [`components/Timeline`](apps/web/src/components/Timeline/Timeline.tsx) — узел-конфликт и пунктир плана Б |
| Стабильность | [`mcp/client.ts`](apps/server/src/mcp/client.ts) — кэш, retry, реплей фикстур |
| Архитектура | [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) |
| Честность | [`docs/ASSUMPTIONS.md`](docs/ASSUMPTIONS.md) — что реально из MCP, а что имитация |
| Качество кода | `tsconfig.base.json` (strict + `noUncheckedIndexedAccess`), ESLint, CI |

## Правила репозитория

- Секреты только через env. `.env` в `.gitignore`, `.env.example` — в репозитории.
- LLM **никогда** не генерирует данные маршрута: цены, рейсы и ссылки приходят только из MCP,
  модель лишь выбирает среди них по `id`. Это защита от галлюцинаций поверх реальных данных.

## Лицензия

MIT — см. [LICENSE](LICENSE).