y83 code / инструмент

Vision

Экран «Vision» отвечает на один вопрос: кто смотрит картинки за агента. Это выбор цепочки источников распознавания — основной и страховщик.

раздел реестра
AI и агенты
код
1 071 строк в 2 файлах
документ
12-vision.md
Раздел: AI & Agents
Идентификатор: vision · Экран: ui/vision/VisionScreen.kt (473) + VisionViewModel.kt (206)
Снимок: 2026-10-11

1. Зачем и что это

Ключевая архитектурная особенность: конфиг цепочки живёт на бэкенде (~/.y83-ws/vision.json), и его читают три потребителя:

  1. экран Vision (выбор и проверка),
  2. MCP-инструменты ai_vision, browser_look, screen_look,
  3. композер чата при обработке вложения.

Поэтому «кто отвечает» совпадает везде: настроили один раз — одинаково работает на телефоне и в чате агента.

Пиксели в контекст модели не попадают: снимок сохраняется файлом, а в тред уходит путь и текстовый ответ. Поэтому картинка не платит vision-токенами на каждом ходе.

2. Как попасть

Хаб инструментов → секция AI & Agents → карточка «Vision» (hub_vision_title). Также экран открывается из хаба инструментов Codex: Vision идёт в общий список «кто отвечает», а не в настройки конкретного агента.

Откуда ещёПуть
Мостapp_navigate с screen: "vision"

Маршрут: Screen.kt:130 ("vision" -> Screen.Vision) → MainScreen.kt:176 (Screen.Vision -> "vision").

3. Экран: элементы и действия

ЭлементЧто делаетГде в коде
Секция // chainДва слота: «основной» и «страховщик»ChainLine (слот 0/1)
Кнопка «Убрать» в слотеСнимает выбор источникаonClear → setSource(slot, null)
Список источниковSelectChip на каждый доступный источникSourceRow
Метка источникаПодпись + «основной»/«страховщик», если он в цепочкеSourceRow:413
Секция «как это работает»Пояснения: пиксели не уходят, источник один для всехmedia_reading_config, media_pixels_are_not_sent_to_the_model
Секция // testКнопка «Проверить цепочку» + результатviewModel::test
Результат проверкиТекст, источник, задержка, попытки по каждому звенуtestText, testSource, testLatencyMs, testAttempts
meta шапки«N src · цепочка» или «доступные/видимые»visionMetaLabel

Пустая цепочка подписывается как «авто»: источники выбираются автоматически.

4. Возможности подробно

Слоты цепочки

Константы в VisionViewModel.kt: VISION_PRIMARY = 0 (основной), VISION_FALLBACK = 1 (страховщик). Функции:

ФункцияЧто делает
visionSourceId(source)id источника в виде, который ждёт бэкенд: webai:deepseek, provider:<id>/<model>, local
visionSlotOf(chain, id)в каком слоте стоит источник, null если не выбран
visionChainLabel(chain, sources)подпись цепочки для шапки: «WebAI → провайдер»
visionChainWith(chain, sources, slot, id)чистая перестановка источника (есть тест)

Правило visionChainWith:

  • один источник не может занимать оба слота — повторный выбор просто переносит его (next = current.filter { visionSourceId(it) != target }, затем вставка в слот);
  • id = null снимает выбор в слоте;
  • источники с пустым kind, а также local без baseUrl отбрасываются: легаси-конфиги без baseUrl бэкенд всё равно выбросит при сохранении;
  • вставка в слот 1 при цепочке длины 1 делается через slot.coerceAtMost(next.size) — то есть страховщик встаёт в конец.

Сохранение

setSource(slot, id) вызывает save(VisionConfigDto(chain, native), key = "slot:$slot"). Сохранение идёт на backend, и в состоянии есть множество busy — по нему видно, какой слот пишется. Бэкенд нормализует конфиг (SetConfig в backend/internal/vision/vision.go) и обрезает цепочку до maxChain = 4.

native — отдельный флаг конфигурации (Config.Native); в экране он не переключается, но сохраняется при каждой записи, чтобы не затереть его.

Какие источники доступны

Список источников приходит с сервера (repo.config() → config, sources). На клиенте видны источники, которые либо available, либо уже стоят в цепочке (visibleVisionSources) — то есть выбранный, но ставший недоступным источник не исчезает из экрана молча, и его можно снять.

В meta шапки видно, все ли видимые источники доступны: «3 src» (все) или «2/3 src» (часть недоступна).

Кто может быть источником

По коду backend:

  • WebAI DeepSeek — источник webai:deepseek;
  • vision-модели провайдеров — provider:<id>/<model>, отбираются по providers.VisionCapable(model): ручной флаг model.Vision ИЛИ автоопределение по имени (LooksVisionID);
  • local — вид источника, который поддерживается в коде и на клиенте, но локального сервера в списке нет (по AGENTS.md), поэтому на практике не используется.

LooksVisionID смотрит на маркеры vision, -vl, vl-, /vl, vl2, vl3, multimodal в id модели и на префиксы gpt-4o, gpt-4.1, gpt-5, claude-, gemini-, qwen-vl, qwen2-vl, qwen2.5-vl, qwen3-vl, glm-4v, internvl, llava, pixtral, grok-2, grok-3. Так модель с картинками попадает в цепочку без ручной настройки; модель без подсказки в имени добавляется кнопкой «+ модель» — пикер ставит ручной флаг model.Vision и перечитывает источники.

Проверка цепочки

Кнопка «Проверить цепочку» отправляет на backend встроенную картинку (BridgeState.TEST_IMAGE_B64 — base64 PNG 512×512 прямо в коде) с вопросом «Describe this test image briefly: what is shown and what text is visible».

Ответ показывает:

ПолеЧто значит
testTextчто ответил источник
testSourceкто именно ответил (visionSourceLabel)
testLatencyMsзадержка, форматируется как 830ms или 1.2s (visionLatencyLabel)
testAttemptsпопытки по каждому звену: ok/fail · источник · задержка · ошибка (visionAttemptLabel)
testErrorошибка, если res.ok == false

Повторное нажатие во время проверки игнорируется (if (_ui.value.testing) return) — это защита от двойного запроса.

5. Данные: БД, файлы, настройки

ЧтоГде лежитКак меняетсяКто читает
Конфиг цепочки~/.y83-ws/vision.json (backend)PUT /api/v1/vision/configai_vision, browser_look, screen_look, композер
Снимки~/.y83-ws/downloads/screenshots/browser_shot, app_screenshotЗатем ai_vision по пути
Тестовая картинкаКонстанта BridgeState.TEST_IMAGE_B64Не меняетсяКнопка «Проверить цепочку»
Локальные настройкиGlobalVisionConfig prefs (инициализируется в App.init)Клиентский кэшПриложение

БД backend (ws-backend.db) цепочку vision не хранит — только файл vision.json. Это сделано, чтобы конфиг можно было прочитать и положить в backup рядом с остальными json-файлами .y83-ws.

6. Backend: REST/роуты

Метод и путьНазначениеОбработчик
GET /api/v1/vision/configтекущий конфиг + список источниковvh.Config
PUT /api/v1/vision/configсохранить конфиг (нормализация, обрезка до 4)vh.Config
POST /api/v1/vision/describeраспознать картинку (используется кнопкой проверки и MCP)vh.Describe

Роуты: backend/internal/api/v1/routes.go:147–149. Логика — backend/internal/vision/vision.go, отбор моделей — backend/internal/providers/catalog.go.

7. Мост и MCP

ИнструментЧто делаетВызывается откуда
ai_vision {imagePath, question, region?}распознать файл по путискилл y83-imagegen/y83-bridge, разработка
browser_look {region?}снимок страницы встроенного браузера → описаниескиллы y83-browser-product, y83-browser-testing
screen_look {region?}снимок экрана приложения → описаниескилл y83-bridge
app_navigate screen: "vision"открыть экранMainScreen.kt:176

Все три возвращают {path, description, source} — одинаковый контракт, поэтому агенту не важно, смотрит он страницу или экран. region: {x,y,w,h} кропается до отправки в координатах исходного кадра.

Отдельной bridge-команды «прочитать vision-конфиг» в коде моста не найдено: агент управляет цепочкой через MCP-вызовы, а этот экран — для человека.

8. Настройки, конфиг, квоты и лимиты

ПараметрЗначениеГде задаётся
Максимум источников в цепочке4 (maxChain)backend/internal/vision/vision.go:204
Слотов в UI2 (основной, страховщик)VISION_PRIMARY, VISION_FALLBACK
Тестовая картинкаPNG 512×512, base64 в кодеBridgeState.TEST_IMAGE_B64
Формат результата проверкиN src или N/M srcvisionMetaLabel
Формат задержки830ms / 1.2svisionLatencyLabel

9. Ловушки и ограничения

  • Цепочка обрезается до 4 источников на сервере. Экран показывает только два слота, но в конфиге их может быть больше после ручной правки файла — лишнее молча исчезнет при следующем сохранении.
  • В UI два слота, в конфиге — до четырёх. Это разные вещи: chain на бэкенде упорядоченный список, slot в приложении — только первые две позиции.
  • native не переключается в UI, но сохраняется при каждой записи. Если его сбросить вручную в vision.json, экран при первом же сохранении перезапишет конфиг текущим значением из загруженного состояния.
  • Выбранный, но недоступный источник остаётся видимым — специально, чтобы его можно было снять. Поэтому «N/M src» в шапке — это не баг.
  • Пустая цепочка означает «авто», а не « vision выключен»: источники выбираются автоматически, и подпись «авто» это прямо показывает.
  • local без baseUrl отбрасывается и на клиенте, и на сервере — легаси-конфиг с таким источником не восстановить через экран.
  • Проверка тратит реальный запрос к модели (встроенная картинка) — её не стоит жать часто при лимитах.
  • Модель с картинками определяется по имени. Если провайдер не даёт модели id с маркером vision/vl/multimodal и не выставил ручной флаг Vision, она не появится в списке источников.

10. Источники правды

  • app/src/main/java/com/y83/ws/ui/vision/VisionScreen.kt — экран, фильтр видимых источников, форматирование.
  • app/src/main/java/com/y83/ws/ui/vision/VisionViewModel.kt — слоты, чистая функция цепочки, сохранение, проверка.
  • app/src/main/java/com/y83/ws/bridge/BridgeState.kt — встроенная тестовая картинка.
  • app/src/main/java/com/y83/ws/data/repo/VisionRepository.kt, data/api/ — клиент REST.
  • backend/internal/vision/vision.go — конфиг, maxChain, нормализация, Describe.
  • backend/internal/handlers/vision/ — HTTP-обработчики.
  • backend/internal/providers/catalog.go — VisionCapable, LooksVisionID.
  • backend/internal/api/v1/routes.go:147–149 — роуты.
  • app/src/main/res/values/strings.xml (media_*) — подписи экрана.

Источник: docs/project/hub/12-vision.md · AI и агенты · 1 071 строк в 2 файлах. Страница собирается из документации проекта при сборке сайта.