Однооконный Tetris, в котором фигурой управляет модель через NVIDIA NOOA. Игра не использует таймер: каждый тик длится ровно столько, сколько модели нужно на ответ.
Цикл одного тика:
- Движок рендерит PNG и точную текстовую сетку игрового поля.
- Выбранный адаптер отправляет совместимый формат, компактное состояние и пользовательский промпт в модель.
PredictStrategyвалидирует ответ по строгой Pydantic-схеме.- Ровно одна команда применяется к фигуре, затем выполняется один шаг гравитации.
NOOA здесь работает в single-shot режиме и не исполняет сгенерированный моделью Python-код.
Безопасность: приложение отправляет игровое состояние и выбранный режим представления в настроенный пользователем LLM endpoint. Не помещайте в prompt, provider-конфиг или логи секреты и персональные данные. API-ключи хранятся только локально — через environment variables или
config/providers.local.json.
Требования: macOS/Linux и uv. Для локальных Gemma нужен LM Studio server на
http://localhost:1234; для Eliza — непустой ~/.tokens/eliza_token.
cd ~/programming/my/tetris-agent-lab
uv sync
uv run tetris-agentМеню модели содержит:
- LM Studio ·
google/gemma-4-12b— изображение или текстовая сетка; - LM Studio ·
google/gemma-4-31b— изображение или текстовая сетка; - Eliza ·
qwen/qwen3.7-max— только текстовая сетка, поскольку endpoint модели объявляетtext→textи отвергает image input. - Настраиваемые OpenAI-compatible провайдеры из
config/providers.local.json. Для них появляется редактируемое поле поиска и кнопкаОБНОВИТЬ /MODELS. Список загружается с provider-specific/models, а режим изображения доступен только моделям сcapabilities.vision=true(или совпавшим с fallback-pattern).
Локальный конфиг намеренно находится в .gitignore и не попадает в коммиты.
Рабочий пример структуры лежит в config/providers.example.json:
{
"openai_compatible_providers": [
{
"key": "my-provider",
"label": "My Provider",
"base_url": "https://api.example.com/v1",
"api_key": "replace-me",
"models_path": "models",
"default_model": "model-id",
"default_vision": false,
"vision_model_patterns": ["vision", "-vl"]
}
]
}Вместо api_key можно указать api_key_env; путь к конфигу переопределяется
через TETRIS_AGENT_PROVIDERS_CONFIG. Локальному файлу рекомендуется mode 0600.
Текущая настройка AnyModel использует https://anymodel.org/v1; /models
на момент проверки вернул 101 модель, из них 50 с vision. Стартовая проверенная
модель — gc/gemini-2.5-flash-lite.
По умолчанию выбрана Gemma 4 12B в режиме изображения. Если выбранная локальная модель скачана, но не загружена, адаптер загрузит её через native LM Studio API с контекстом 8192 токенов.
Настройка без изменения кода:
LM_STUDIO_MODEL=google/gemma-4-31b uv run tetris-agent
LM_STUDIO_BASE_URL=http://localhost:1234/v1 uv run tetris-agent
LM_STUDIO_CONTEXT_LENGTH=16384 uv run tetris-agent
ELIZA_TOKEN=... uv run tetris-agent # необязательная альтернатива token-файлуВ UI нет клавиатурного или ручного управления фигурой: только Start/Stop и
редактируемый промпт. Опциональная тень места приземления выключена по умолчанию;
галочка доступна только между играми и одновременно управляет UI и PNG модели.
Галочка «Включить историю» также доступна только между играми. По умолчанию она
выключена: каждый тик получает свежий разговорный контекст без прошлых ответов,
recent_actions и previous_note. При включении один
NOOA-агент и его чат сохраняются до Stop/Game Over, поэтому модель видит прошлые
наблюдения и собственные ответы. Длинная история, особенно с PNG, увеличивает
контекст, задержку и расход памяти модели.
Solid-блоки — зафиксированные клетки и текущая фигура. Справа ведётся журнал
ответов: список тиков переключает показанный JSON. Пока выбран последний тик, список автоматически
следует за новыми ответами; выбор старого тика приостанавливает auto-follow.
Текстовая сетка всегда содержит 20 строк по 10 клеток: . — пусто, заглавные
IOTSZJL — зафиксированные блоки, @ — текущая падающая фигура, * —
опциональная тень. Все четыре координаты текущей фигуры перечисляются отдельно,
включая клетки выше видимого поля. Также observation содержит число закреплённых
клеток, высоты и дыры колонок, а для допустимых прямых приземлений — точные
конечные клетки и метрики. Это снимает с text-only модели ненадёжный мысленный
расчёт геометрии; команда остаётся решением агента.
Модель обязана вернуть объект вида:
{"action":"rotate_cw","note":"Flatten the right side"}action допускает только:
left,rightrotate_cw,rotate_ccwsoft_drop,hard_dropwait
Лишние поля, неизвестные действия и note длиннее 160 символов отвергаются.
NOOA делает до трёх попыток исправить невалидный структурированный ответ.
uv run pytest
uv run ruff check .
uv run python scripts/smoke_ui.py
uv run python scripts/smoke_lmstudio.py
uv run python scripts/smoke_provider.py --profile eliza-qwen-3-7-max --mode text_grid
uv run python scripts/smoke_provider.py --profile eliza-qwen-3-7-max --mode text_grid --history --ticks 2
uv run python scripts/smoke_provider.py --profile openai-compatible:anymodel --mode image --ticks 1
uv run python scripts/smoke_provider.py --profile openai-compatible:anymodel --model am/gemma-4-31b-it --mode image --ticks 1Две последние команды выполняют реальные provider-запросы. Каждая игровая сессия
пишется в logs/session-*.jsonl; логи не коммитятся.
game.py— детерминированный Tetris state machine.render.py— синхронные PNG и text-grid представления поля.placement.py— точный анализ и ранжирование конечных приземлений text-grid.protocol.py— строгий JSON-контракт.prompts.py— полный редактируемый prompt с правилами и стратегией размещения.adapters/base.py— универсальный порт провайдера.adapters/catalog.py— подключённые модели и capability-матрица.adapters/nooa_openai.py— общий OpenAI-compatible NOOA-движок.adapters/lmstudio.py,adapters/eliza.py— provider-specific подключение.adapters/openai_compatible.py—/models, capability parsing и generic adapter.provider_config.py— безопасная загрузка локального provider-конфига.runner.py— прерываемый пошаговый цикл.app.py— единственное окно PySide6.DEVLOG.md— журнал разработки, решений и известных ограничений.
Код этого репозитория распространяется по Apache License 2.0. Сторонние Python-пакеты и внешние LLM-провайдеры сохраняют собственные условия; подробности — в THIRD_PARTY_NOTICES.md.