AAYMA
RU
Войти

FixPoint — Saqta Voice Agent

Голосовой агент контакт-центра вымышленной страховой компании: распознаёт речь (RU/KK/смешанную), маршрутизирует обращение в один из 40 сценариев…

Рабочий MVP
Команда «FixPoint» 18💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: FixPoint
Кейс HackAlem.ai: Коммуникации — Halyk Bank · кейс 2
Стадия: Рабочий MVP

Задача кейса: «Voice Router»: голосовой AI, маршрутизирующий звонки в контакт-центре страховой компании

Суть

Голосовой агент контакт-центра вымышленной страховой компании: распознаёт речь (RU/KK/смешанную), маршрутизирует обращение в один из 40 сценариев, собирает параметры, выполняет мок-действия и отвечает голосом.

Как устроено

Браузер записывает речь до паузы (собственный энергетический VAD) и отправляет запись по HTTP/WebSocket в FastAPI. STT gpt-transcribe переводит речь в текст, LLM-маршрутизатор на gpt-4o-mini через структурированный ответ по Pydantic-схеме выбирает сценарии, язык и параметры. Контроллер диалога собирает недостающие слоты, проверяет идентификаторы (телефон, ИИН), перед необратимыми операциями делает preview и запрашивает согласие, затем вызывает 31 мок-действие. Ответ озвучивается gpt-4o-mini-tts. Трассировки и история сохраняются в JSON-архив.

Ключевые решения

  • LLM intent routing
  • structured outputs (Pydantic)
  • slot filling
  • dialogue state machine
  • preview + consent
  • idempotency keys
  • energy-based VAD
  • spoken identifier validation

Особенности

LLM не пишет данные напрямую: формулы, согласие и изменения выполняет код, а у каждого разговора своя копия мок-данных. Есть защита от повторного исполнения по id операции и повторный запрос неполностью распознанных ИИН и телефонов. Известные ограничения README честно перечисляет.

Стек

Python · FastAPI · Uvicorn · Pydantic · React · TypeScript · Vite · WebSocket · Streamlit · Docker Compose · Caddy

Модели

gpt-4o-mini · gpt-transcribe · gpt-4o-mini-tts


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-19a8b765-fixpoint.

README

README.md

FixPoint — Saqta Voice Agent

Голосовой ИИ-помощник контакт-центра вымышленной страховой компании Saqta Insurance. Хакатонный прототип для клиентов, которым нужно узнать условия страхования, рассчитать стоимость, получить сведения о полисе или заявлении, изменить данные либо обратиться к оператору.

Проект решает задачу выбора страхового сценария из разговорной речи: похожие формулировки могут означать покупку полиса, страховой случай или жалобу. Агент использует LLM для понимания русского, казахского и смешанного ввода, а расчёты и изменения выполняет программный контроллер на тестовых данных.

Статус: работающий прототип с реальными AI-интеграциями и локальными моками — имитациями страхового бэкенда. Полная приёмка всех сценариев и голосового общения RU/KK/mixed не завершена. Известные ошибки перечислены ниже; наличие сценария в каталоге не означает, что все его варианты работают корректно.

Что реализовано

  • Веб-интерфейс с кнопкой начала/завершения разговора, записью с микрофона, определением паузы и автоматическим воспроизведением ответа. После ответа запись возобновляется.
  • Текстовый ввод для диагностики через тот же серверный конвейер, история реплик и панель dev с трассировкой.
  • LLM-маршрутизатор с каталогом 40 бизнес-сценариев и 3 системных намерений. Он возвращает структурированные данные: сценарии, уверенность, язык, извлечённые параметры и краткое основание выбора.
  • Состояние диалога: сбор недостающих параметров, идентификация клиента, очередь запросов, сохранение прерванной темы и возврат к ней. Сложные сочетания этих возможностей ещё требуют доработки.
  • 31 мок-действие: чтение полисов и заявлений, расчёты, создание и изменение записей, бронирование, демонстрационные SMS и передача контекста оператору.
  • Подготовка необратимой операции до исполнения (preview), запрос согласия и защита от повторного исполнения по идентификаторам операции и запроса.
  • Проверка формата идентификаторов, в том числе продиктованных телефонов, ИИН и номеров документов. Неполное распознанное значение должно запрашиваться повторно.
  • Локальный архив разговоров: история, трассировки, результаты моков и экспорт JSON. Аудиозаписи и ключи API в архив не включаются.

SMS, почта, платежи, CRM и звонок живому оператору не подключены. Их результаты имитируются и фиксируются в журнале действий. Статус handoff_prepared означает подготовленную мок-передачу, а не реальное соединение.

Как работает решение

  1. Пользователь открывает сайт, нажимает кнопку микрофона и разрешает запись.
  2. Браузер записывает речь до паузы и отправляет завершённую запись на сервер. STT преобразует её в текст.
  3. LLM выбирает сценарии с учётом каталога и контекста, определяет язык ответа и извлекает параметры запроса.
  4. Контроллер проверяет параметры, задаёт уточняющие вопросы и вызывает нужные мок-действия. Перед необратимым изменением он подготавливает операцию и запрашивает согласие.
  5. Ответ формируется по базе знаний и результатам действий, преобразуется в аудио и воспроизводится в браузере. Разговор продолжается автоматически.
  6. В панели dev можно проверить выбранный сценарий, параметры, действия и задержки, а затем открыть сохранённый разговор.

Например, запрос «Где находится офис в Алматы?» должен пройти через SC33 и get_offices, после чего агент сообщит адрес из базы знаний. Текстовый ввод начинает обработку с шага маршрутизации; его ответы автоматически не озвучиваются.

Технологии

КомпонентИспользуется в репозитории
BackendPython, FastAPI, Uvicorn, Pydantic / pydantic-settings, HTTPX
FrontendTypeScript, React 19, Vite 7, CSS, pnpm
Запись и воспроизведениеБраузерные MediaRecorder, Web Audio API, HTMLAudioElement; собственный энергетический детектор активности речи
Обмен даннымиHTTP API и WebSocket
LLMOpenAI Python SDK, Responses API, структурированный ответ по Pydantic-схеме; LLM_MODEL=gpt-4o-mini
Распознавание речи (STT)OpenAI Audio Transcriptions; STT_MODEL=gpt-transcribe
Синтез речи (TTS)OpenAI Audio Speech, MP3; TTS_MODEL=gpt-4o-mini-tts, голос marin
ДанныеJSON-датасет, мок-состояние в памяти, JSON-архивы на диске; отдельной БД нет
Проверкиpytest, встроенный test runner Node.js, TypeScript, скрипт оценки из датасета
Дополнительный интерфейсStreamlit для разработки и диагностики
Подготовка развёртыванияDocker Compose, Caddy, Cloudflare Quick Tunnel

Имена AI-моделей выше — значения конфигурации репозитория, а не гарантия доступности для любого API-ключа. Нужны доступ к соответствующим моделям и сеть. Модели настраиваются отдельно, но текущие адаптеры используют общий клиент OpenAI и один серверный ключ. Groq в активной конфигурации не используется.

Архитектура

Браузер: React, микрофон, детектор паузы
    │ завершённая запись / текст через HTTP и WebSocket
    ▼
FastAPI: сессии, запросы, события
    ├─ STT → текст
    └─ LLM-маршрутизатор → сценарии, язык, параметры
                             │
                             ▼
                   Контроллер диалога
                   проверка → сбор данных → preview → согласие
                             │
                             ▼
                   Мок-действия и база знаний
                             │
                             ▼
                   Текст ответа → TTS → браузер

Состояние, события и результаты → трассировка → JSON-архив

LLM не записывает данные напрямую. Формулы, проверки согласия и изменения выполняются кодом. Каждый разговор получает собственную копию исходных мок-данных.

КаталогНазначение
backend/app/core/Каталог, схемы, маршрутизатор, нормализация, состояние и исполнитель диалога
backend/app/services/Мок-действия, адаптеры OpenAI и архив сессий
backend/app/main.pyHTTP/WS API и жизненный цикл сессии
backend/fixtures/Отдельное синтетическое расписание для записей
frontend/src/Экран разговора, запись, воспроизведение, трассировка и архив
case/voice_router_dataset/Исходные требования и страховые данные
tests/, scripts/Проверки и диагностические прогоны
docs/Решения, план разработки, отчёты и примеры для проверки

Установка и запуск

Требования

  • Python 3.12+.
  • Node.js 22.12+, pnpm. В Docker-сборке frontend закреплён pnpm 10.17.1.
  • API-ключ OpenAI с доступом к настроенным моделям и доступ в интернет.
  • Браузер с поддержкой записи и воспроизведения аудио, микрофон и динамики/наушники.

Команды ниже выполняются из корня скачанного или клонированного проекта. Основной локальный вариант — FastAPI и React в двух терминалах.

1. Подготовить Python-окружение

Windows / PowerShell:

python -m venv .venv
.venv\Scripts\python.exe -m pip install -r backend/requirements.txt
if (-not (Test-Path .env)) { Copy-Item .env.example .env }

Linux / macOS:

python3 -m venv .venv
.venv/bin/python -m pip install -r backend/requirements.txt
test -f .env || cp .env.example .env

2. Настроить сервер

В корневом .env заполнить OPENAI_API_KEY. Исходные настройки доступны в .env.example:

OPENAI_API_KEY=ваш_ключ
LLM_PROVIDER=openai
STT_PROVIDER=openai
TTS_PROVIDER=openai
LLM_MODEL=gpt-4o-mini
STT_MODEL=gpt-transcribe
TTS_MODEL=gpt-4o-mini-tts
TTS_VOICE=marin
MOCK_MODE=false
REQUEST_TIMEOUT=35

Ключ читается сервером. Не помещайте его во frontend или Git. Без ключа приложение может запуститься, но реальные LLM/STT/TTS-запросы не работают. MOCK_MODE=true предназначен для диагностики: он не заменяет понимание произвольной речи и не отключает отдельно настроенные STT/TTS.

3. Запустить backend — терминал 1

Windows:

.venv\Scripts\python.exe -m uvicorn app.main:app --app-dir backend --host 127.0.0.1 --port 8000

Linux / macOS:

.venv/bin/python -m uvicorn app.main:app --app-dir backend --host 127.0.0.1 --port 8000

Проверка запуска: API health. Описание HTTP API: Swagger UI. Поля *_ready в health показывают наличие конфигурации и ключа, а не успешный тест внешнего сервиса.

4. Запустить frontend — терминал 2

Если pnpm ещё не установлен:

npm install --global [email protected]

Затем из корня проекта:

cd frontend
pnpm install --frozen-lockfile
pnpm dev

Открыть http://127.0.0.1:4173. Vite перенаправляет /api и WebSocket на локальный backend. Оба терминала должны оставаться запущенными; остановка — Ctrl+C.

Микрофону нужен localhost или HTTPS. Для удалённого запуска предусмотрена отдельная инструкция VPS. start.ps1, run.py и основной docker-compose.yml запускают вспомогательный Streamlit; для главного React-демо используйте команды выше или docker-compose.vps.yml. Docker-сборка и запуск на VPS в текущем отчёте проекта ещё не подтверждены.

Как проверить решение жюри

Быстрая проверка: адрес офиса

  1. Открыть сайт и нажать кнопку микрофона с подписью «Начать разговор». Разрешить доступ к микрофону.
  2. Сказать: «Где находится офис в Алматы и когда он работает?», затем сделать паузу.
  3. Проверить ответ по данным knowledge_base.json: Abai Ave 150; понедельник–пятница 09:00–18:00, суббота 10:00–15:00. Это адрес и расписание вымышленной компании из датасета.
  4. Завершить разговор и открыть dev → Диагностика разговора. Ожидаются сценарий SC33, действие get_offices, распознанный текст и измерения. Формулировка ответа может отличаться; факты должны совпадать.
  5. В dev → Сохранённые разговоры обновить список, выбрать этот разговор и проверить историю или скачать JSON.

При проблеме с микрофоном ту же фразу можно ввести в текстовое поле. Это проверит текстовый конвейер, но не засчитывается как проверка голоса.

Расчёт и подтверждение операции

Для каждой независимой проверки начинайте новый разговор. Все идентификаторы ниже — синтетические данные из мока.

ПроверкаРеплики и ожидаемый результат
Расчёт ОГПО«Рассчитайте ОГПО на год для легковой машины в Алматы». На вопрос об ИИН: [ИИН скрыт]. Ожидается SC01, calc_ogpo_price и 38 000 тенге; новый полис не создаётся.
Изменение адреса«Хочу изменить контактный адрес». Для идентификации: +77010000001; новый адрес: Алматы, Тестовая улица, 10. До согласия должен быть только update_contact:preview. Ответить отдельной репликой «Да»: ожидается update_contact:execute и изменение адреса в мок-данных архива.
ОтказПовторить изменение адреса в новой сессии, но на подтверждение ответить «Нет». Изменения быть не должно.
Казахский вводВ новой сессии: «Алматыдағы кеңсенің мекенжайы қандай?». Ожидаются SC33 и ответ на казахском с тем же адресом. Это проверочный пример, а не заявление о завершённой приёмке KK.

ИИН и телефон можно сначала ввести текстом, затем повторить голосом, чтобы раздельно проверить исполнение сценария и качество STT. Не добавляйте новый вопрос к «Да» в базовом демонстрационном пути: составное подтверждение — известная недоработка.

Больше примеров: 40 бизнес-сценариев и системные намерения для ручной проверки. В этом документе описано ожидаемое поведение, включая ещё не закрытые требования; это не протокол успешных прогонов.

Тесты и оценка маршрутизатора

Из корня проекта, Windows:

.venv\Scripts\python.exe -m pytest -q
.venv\Scripts\python.exe -X utf8 scripts/validate_dataset.py

На Linux / macOS замените .venv\Scripts\python.exe на .venv/bin/python. Проверки frontend:

cd frontend
pnpm test
pnpm run build

Полный прогон 104 реплик через реальный платный API — отдельно, из корня:

.venv\Scripts\python.exe -X utf8 scripts/evaluate_router.py

Прогнозы, трассы и метрики сохраняются в reports/, который исключён из Git. Если прогнозы уже есть, их можно оценить без повторных API-запросов:

.venv\Scripts\python.exe -X utf8 case/voice_router_dataset/evaluate.py reports/predictions.json case/voice_router_dataset/dev_utterances.json

По аудиту от 23.09.2026, локально проходили 149 backend-тестов, 20 frontend-тестов и production build. Часть тестов подаёт заранее подготовленные решения маршрутизатора: эти тесты проверяют контроллер, а не качество LLM или распознавания речи.

Сохранённый прогон маршрутизатора показал:

МетрикаРезультат
Правильный первый сценарий91/104 — 87,5%
Полное совпадение набора сценариев76/104 — 73,1%
Полнота распознавания намерений в многоцелевых запросах18/26 — 69,2%

После этого прогона код менялся. Эти числа относятся к сохранённому прогону, а не доказывают качество последней версии. Полная приёмка десяти примерных диалогов с реальной LLM и голоса RU/KK/mixed ещё не выполнена.

Данные и интеграции

Единственный источник страховых фактов — case/voice_router_dataset. Все данные синтетические; расчётное «сегодня» всегда 2026-10-01, независимо от даты компьютера.

ИсточникИспользование
scenarios.json40 бизнес-сценариев, 3 системных намерения, границы выбора и условия передачи оператору
slots.json43 параметра: типы, форматы и вопросы на RU/KK
actions.json31 мок-действие, включая 9 необратимых, ошибки и очереди операторов
knowledge_base.jsonПродукты, тарифы, правила, офисы, клиники и документы
mock_backend.json11 клиентов, 11 полисов, 4 заявления и 2 платежа
dialogs_sample.json10 примеров диалогов
dev_utterances.json, evaluate.py104 размеченные реплики и эталонный оценщик
backend/fixtures/schedule.jsonОтдельное синтетическое расширение: доступность записей

Внешний AI-сервис — OpenAI: в него передаются аудио для STT, текст и контекст для LLM, текст ответа для TTS. Cloudflare используется только в подготовленной схеме публичного доступа; страховых интеграций с реальными организациями нет.

Исходные JSON не изменяются действиями агента. Новая сессия получает исходные моки; изменения других разговоров в неё не переносятся. Архивы сохраняются в runtime/sessions/<UUID>.json; путь можно изменить серверной настройкой SESSION_ARCHIVE_DIR. После рестарта старый разговор доступен для просмотра, но автоматически не продолжается. Хранилище рассчитано на один серверный процесс.

Ограничения, ошибки и недоработки

Это демо на тестовых данных. Ни реальные страховые операции, ни реальные платежи, SMS, почта, CRM или телефония не выполняются. У приложения нет авторизации: пользователи с доступом к серверу могут обращаться к API и архивам.

В аудите зафиксированы следующие проблемы, которые сохраняются в проверенной реализации:

ПроблемаПроявление
Роль полиса в SC12Может подставиться собственный полис потерпевшего вместо полиса виновника.
Срочная помощь в SC15При недостающих данных исполнителю передаются факты о мошенничестве вместо медицинского случая за границей.
Параметры продуктаЯвные 6 месяцев ОГПО и пакет КАСКО Lite теряются при валидации; расчёт может использовать неверный срок или пакет.
Запись после previewЕсли показанное время стало занято, execute может выбрать другое без нового согласия.
Составное подтверждение«Да, подтверждаю. А где офис?» повторяет подготовку операции вместо полного исполнения обеих частей запроса.
Документы в SC18Для вопроса о конкретном заявлении не вызывается необходимое чтение get_claim.
Ошибки действийНет требуемой автоматической повторной попытки при service_unavailable; обработка разных кодов недостаточно разделена.
Условность SMSНекоторые справочные сценарии отправляют мок-SMS по известному телефону без отдельного запроса пользователя.
ТрассировкаНекоторые ранние передачи оператору отсутствуют в trace.actions; предупреждения TTS не включаются в trace.errors, хотя сохраняются в событиях.
Потеря соединенияFrontend предлагает новый разговор вместо восстановления текущего из серверного снимка.

Другие ограничения текущей версии:

  • Многоцелевые и неясные запросы распознаются нестабильно. В сохранённом прогоне полностью совпали 5 из 13 многоцелевых запросов и ни один из трёх SYS_UNCLEAR.
  • STT обрабатывает законченную запись; промежуточных транскрипций нет. Микрофон не записывает во время ответа бота. Отдельного повтора только озвучивания сохранённого ответа нет.
  • Распознавание госномеров и аббревиатур нестабильно; полная проверка живой RU/KK/mixed-речи, чисел и смены языка не завершена. Наличие адаптеров не гарантирует качество речи.
  • В архивном срезе аудита медиана 19 голосовых ходов с измерением составляла 6,17 с. Это неконтролируемая выборка, не финальный бенчмарк. Бонус ТЗ за задержку до 3 секунд не подтверждён.
  • Смена автомобиля с перерасчётом, часть изменений премии, КАСКО для возраста без ставки и запись к специалистам кроме терапевта ограничены пробелами данных и требуют оператора. Успешный SC16 не проверен: в исходном моке нет подходящего полиса от несчастного случая.
  • В текущем интерфейсе текстовый ввод и история видны на основном экране. ?dev=1 и ?jury=1 открывают одну модальную панель; отдельной постоянной панели жюри нет. Чтобы управлять разговором, её нужно закрыть. Confidence находится в dev, а не на главном экране.
  • JSON-архив не является транзакционной БД. После аварии во время хода результат может быть неизвестен; операции из архива автоматически не повторяются.

Развёрнутая версия

Постоянная работающая deployed-версия в репозитории не подтверждена. В локальном runtime/tunnel/url.txt сохранена временная ссылка Quick Tunnel; её доступность при подготовке README подтвердить не удалось. Она зависит от работающего туннеля и может устареть.

Для самостоятельного развёртывания подготовлены docker-compose.vps.yml, deploy/ и инструкция VPS. По текущему журналу работ, Docker-сборка и запуск на VPS ещё не проверены. Скрипт развёртывания сохраняет полученный временный адрес в runtime/public-url.txt на машине запуска.

Дополнительные материалы

Звёзды
⭐ 1
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
16
Авторы
4
Файлы
99
Ветки
4

Авторы коммитов

Rakhim 8Aleks-48 4Adil 3Codex 1

История коммитов

  • 2026-09-23 17:56docs: prepare README for hackathon juryRakhim
  • 2026-09-23 17:47Add VPS deployment and scenario audit documentationRakhim
  • 2026-09-23 17:39Fix voice endpointing under background noiseRakhim
  • 2026-09-23 17:31feat(frontend): preview confirmation and handoff statesAdil
  • 2026-09-23 17:25docs: point Streamlit deployment to integration branchAleks-48
  • 2026-09-23 17:18Merge remote-tracking branch 'origin/codex/voice-dialogue-confidence' into codex/streamlit-cloudAleks-48
  • 2026-09-23 17:16Validate spoken identifiers before scenario actionsRakhim
  • 2026-09-23 16:58Add session archive and improve voice interactionRakhim
Все коммиты (16)
  • 2026-09-23 16:10docs: align README and harden backend acceptanceAleks-48
  • 2026-09-23 15:48Integrate OpenAI voice dialogue and confidence displayRakhim
  • 2026-09-23 15:18feat(frontend): add design preview and conversation completion stateAdil
  • 2026-09-23 15:10fix(backend): complete dialogue action flows and acceptance checksAleks-48
  • 2026-09-23 14:22Ignore local pnpm store cacheRakhim
  • 2026-09-23 14:20feat(backend): add session-based voice router API and Streamlit demoCodex
  • 2026-09-23 13:57feat(frontend): add Saqta chat UI with browser speech recognitionAdil
  • 2026-09-23 13:35Add voice agent dataset, architecture and implementation planRakhim
Структура репозитория (99 файлов)
.dockerignore
.env.example
.gitignore
AGENTS.md
Dockerfile
README.md
backend/app/__init__.py
backend/app/config.py
backend/app/core/__init__.py
backend/app/core/context.py
backend/app/core/contracts.py
backend/app/core/engine.py
backend/app/core/executor.py
backend/app/core/fast_answers.py
backend/app/core/identifiers.py
backend/app/core/latency.py
backend/app/core/models.py
backend/app/core/router.py
backend/app/core/scenarios.py
backend/app/core/slots.py
backend/app/main.py
backend/app/services/__init__.py
backend/app/services/actions.py
backend/app/services/llm.py
backend/app/services/session_archive.py
backend/app/services/stt.py
backend/app/services/tts.py
backend/fixtures/schedule.json
backend/requirements.txt
case/voice_router_dataset/README.kz.md
case/voice_router_dataset/README.md
case/voice_router_dataset/README.ru.md
case/voice_router_dataset/actions.json
case/voice_router_dataset/dev_utterances.json
case/voice_router_dataset/dialogs_sample.json
case/voice_router_dataset/evaluate.py
case/voice_router_dataset/knowledge_base.json
case/voice_router_dataset/mock_backend.json
case/voice_router_dataset/scenarios.json
case/voice_router_dataset/slots.json
deploy/Caddyfile
deploy/Dockerfile.web
docker-compose.vps.yml
docker-compose.yml
docs/backend-api.md
docs/backend-validation.md
docs/compliance-audit-2026-09-23.md
docs/dataset-validation.json
docs/decisions.md
docs/frontend-integration.md
docs/iin-recognition-2026-09-23.md
docs/implementation-plan.md
docs/manual-scenario-dialogues.md
docs/progress.md
docs/project-audit-2026-09-23.md
docs/roadmap.md
docs/scenario-validation-2026-09-23.md
docs/vps.md
frontend/index.html
frontend/package.json
frontend/pnpm-lock.yaml
frontend/pnpm-workspace.yaml
frontend/src/App.tsx
frontend/src/components/AudioVisualizer.tsx
frontend/src/components/SessionArchive.tsx
frontend/src/components/TracePanel.tsx
frontend/src/confidence.test.ts
frontend/src/confidence.ts
frontend/src/hooks/useMicrophone.ts
frontend/src/hooks/useSession.ts
frontend/src/main.tsx
frontend/src/state/sessionReducer.test.ts
frontend/src/state/sessionReducer.ts
frontend/src/styles.css
frontend/src/types.ts
frontend/src/voiceActivity.test.ts
frontend/src/voiceActivity.ts
frontend/tsconfig.json
frontend/vite.config.ts
pytest.ini
requirements.lock.txt
requirements.txt
run.py
scripts/audit_compliance.py
scripts/evaluate_router.py
scripts/probe_iin_route.py
scripts/probe_iin_stt.py
scripts/probe_spoken_identifiers.py
scripts/validate_dataset.py
scripts/vps-up.sh
start.ps1
streamlit_app.py
tests/conftest.py
tests/test_api.py
tests/test_domain.py
tests/test_identifiers.py
tests/test_scenario_paths.py
tests/test_session_archive.py
tests/test_trace_regression.py
Ветки (4)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.