feat: история общения (SQLite) + Koog LLM-клиент в app-phone

SQLite (голый SQLiteOpenHelper, без ORM — как решили):
- sessions (id, title, created_at, updated_at) + messages (role, content,
  tool_call_id, tool_calls JSON, attachments JSON, created_at) по утверждённой
  схеме; FK-каскад; CHECK на роли.
- ChatDb + ChatDao (createSession/listSessions/rename/touch/delete, addMessage,
  messagesForSession), доступ через PhoneApp.chatDao.
- Unit: ModelsTest (роли, JSON tool_calls/attachments). androidTest:
  ChatDaoTest — CRUD-круг + каскад — OK (3 tests) на эмуляторе.

Koog (JetBrains) — базовый LLM-клиент, без агентного слоя:
- ai.koog:prompt-executor-openai-client:1.1.1 + http-client-okhttp
- LlmClient: OpenAILLMClient(apiKey, baseUrl=llm.binom.pw) → chat(история)
- BuildConfig LLM_API_KEY/LLM_MODEL из local.properties (вне git); llm_debug
  smoke (--ez llm_debug true) — проверен на эмуляторе: реальный ответ от
  llm.binom.pw (deepseek-v4-flash).
- ЗАГЛУШКА Coroutines_jvmKt: дефект публикации Koog 1.1.1 — utils-android не
  включает jvm-класс, который зовёт OkHttpKoogHttpClient (без неё
  NoClassDefFoundError на первом вызове). Сигнатура сверена с utils-jvm.
  Убрать после фикса JetBrains.
This commit is contained in:
Hermes Agent
2026-08-20 11:52:50 +03:00
parent 3ed63012f4
commit d9d34e9277
12 changed files with 591 additions and 0 deletions
@@ -20,6 +20,8 @@ import pw.binom.viewmate.core.phone.PhoneActions
import pw.binom.viewmate.core.phone.PhoneState
import pw.binom.viewmate.core.protocol.SttCancel
import pw.binom.viewmate.core.protocol.SttPhrase
import pw.binom.viewmate.phone.agent.ChatDao
import pw.binom.viewmate.phone.agent.ChatDb
import pw.binom.viewmate.phone.stt.SttStreamer
import pw.binom.viewmate.phone.stt.WhisperStt
@@ -51,6 +53,9 @@ class PhoneApp : Application() {
/** Синхронизированный аудио-плеер (звук на телефоне при просмотре на очках). */
val audioSync: AudioSyncPlayer by lazy { AudioSyncPlayer(this) }
/** История общения с ассистентом (SQLite, "assistant.db"). */
val chatDao: ChatDao by lazy { ChatDao(ChatDb(this)) }
/** Автоматика паузы/продолжения звука при обрыве связи. */
private val connectionAutoResume = ConnectionAutoResume()