# Живой прогон: что нашли и починили (28.09.2026) Первый прогон десктопа не на фейках, а на живом `:standalone`-агенте (Qwen через vLLM на 192.168.88.135) с настоящим GUI: окно Compose, клики/печать через `ydotool`, проверка скриншотов. ## Что проверено вживую | Шаг | Результат | | --- | --- | | Приложение подключается к агенту | шапка: «Локальный агент» + зелёное «на связи» | | Список диалогов | подтягивается с сервера (33 диалога), поиск/время/аватары на месте | | «+» (новый диалог) | сервер вернул новый диалог, счётчик на сервере 33 → 34 | | Отправка сообщения | текст ушёл, ответ LLM пришёл в UI, в истории обе реплики | | Голос (`Ctrl+M`) | «идёт запись» (микрофон красный) → повторное нажатие → «Речь не распознана», **без падения JVM** | Ход агента при этом длинный: ответ занял 0.5 с, а один разбор с длинным промптом — 144 с; это важно для бага №1 ниже. ## Починенные баги ### 1. `:client`: `POST /messages` умирал по таймауту 15 с (upstream) Сервер отвечает на `POST /conversations/{id}/messages` только по завершении всего хода агента (LLM + тулы), а это минуты. Клиент шёл с дефолтным request-timeout Ktor → любая длинная реплика обрывалась на 15-й секунде (`RealServerIT` показал реальные 144 с). Фикс в `agentik/client/.../ConversationClient.kt`: у запроса отправки снят таймаут чтения (`noReadTimeout()`, тот же приём, что для SSE). Регрессионный тест — в `RealServerIT`. ### 2. Конфликт skiko и нативных ASR-библиотек → SIGSEGV Найдено при добавлении тестов голоса: если onnxruntime/Vosk инициализируются **после** skia, JVM падает в C++-логах. В проде это был бы краш при первом нажатии микрофона (окно-то уже нарисовано). Подробности и таблица порядка загрузки — в `MIC-ASR-SEARCH.md` §8. Фикс: `VoiceNative.warmUp()` в `main()` до `application {}`, плюс `forkEvery = 1` в тестах. ### 3. Список диалогов не обновлялся никогда `AgentConnection.listConversations()` читал `agent.conversationStore.list(...)` один раз — а встроенный кэш либы наполняется асинхронно (`listFlow`), так что даже «один раз» приходилось на пустой кэш. Итог: сервер отдаёт 33 диалога, а в UI список пуст, и обновить его было нечем. Фикс: `AgentConnection.conversationsFlow` — опрос встроенного кэша с warmup-циклом на старте + подписка на SSE-поток (`outbox.agentEvents`) для появления/удаления диалогов, созданных другими клиентами, + явный `refresh()` после своих create/delete/rename. ### 4. Enter не отправлял сообщение, хотя подсказка это обещала Поле многострочное, Enter вставлял перевод строки. Фикс: `onPreviewKeyEvent` в композере — Enter отправляет, Shift+Enter переносит строку (тогда подсказка «отправка Enter» становится правдой). ### 5. Клик по нижней/верхней части поля ввода не фокусировал его `BasicTextField` высотой в строку внутри `Box` с паддингами: клик мимо самой строки текста фокуса не давал. Фикс: клик по всему боксу запрашивает фокус (`clickable` + `focusRequester`). ### 6. Ложный красный баннер «StandaloneCoroutine was cancelled» `refresh()` отменяет предыдущий job, а `runCatching { ... }.onFailure { error = it.message }` показывал отмену корутины как ошибку пользователя. Фикс: `AppState.reportError()` игнорирует `CancellationException` (все 11 мест переведены на него). ### 7. Микрофон с клавиатуры Мышиную кнопку микрофона удобно не всегда, а для проверки голоса без мыши — критично: добавлен `Ctrl+M` из чата (и подсказка обновлена). ## Как повторить ```bash # 1. живой агент (в фоне, из папки проекта) cd /home/subochev/common-projects/WORK/ai/agentik/standalone AGENTIK_SKILLS_DIR=./agentik/skills AGENTIK_SYSTEM_PROMPT='Ты полезный ассистент.' \ OPENAI_BASE_URL=http://192.168.88.135:8001/v1 AGENTIK_DB_PATH=./agentik/db.db \ OPENAI_CONTEXT_WINDOW=115000 AGENTIK_MEMORY_DIR=./agentik/memory \ OPENAI_LLM_BACKEND=openai AGENTIK_PORT=8080 OPENAI_API_KEY=... \ OPENAI_MODEL=... AGENTIK_SOUL=./agentik/SOUL.md ./gradlew run # 2. десктоп (окно) cd /home/subochev/common-projects/WORK/ai/agentik-desktop AGENTIK_DESKTOP_HOME=/tmp/opencode/ak-real ./gradlew run # 3. интеграционные тесты против живого агента AGENTIK_E2E_URL=http://127.0.0.1:8080/agentik ./gradlew jvmTest \ --tests '*RealServerIT' --tests '*RealAppStateIT' --tests '*RealSpeechIT' ```