|
| 1 | +# Локальна офлайн-модель через omlx як LLM-провайдер агента |
| 2 | + |
| 3 | +**Status:** Accepted |
| 4 | +**Date:** 2026-06-14 |
| 5 | + |
| 6 | +## Context and Problem Statement |
| 7 | + |
| 8 | +Для in-app agent-loop потрібен LLM-провайдер. Вимоги: приватність, офлайн-доступність, сумісність із наявною інфраструктурою (`tauri-plugin-http`). Обирали між хмарним Claude, локальною офлайн-моделлю та провайдер-агностичним інтерфейсом. |
| 9 | + |
| 10 | +## Considered Options |
| 11 | + |
| 12 | +- Claude (Anthropic) через `tauri-plugin-http` — хмарний, потребує API-ключа і мережі. |
| 13 | +- Локальна офлайн-модель через omlx (OpenAI-сумісний MLX-сервер) + Gemma 4 E4B. |
| 14 | +- Провайдер-агностичний інтерфейс із кількома бекендами — відкладено як передчасне для MVP. |
| 15 | + |
| 16 | +## Decision Outcome |
| 17 | + |
| 18 | +Chosen option: "Локальна офлайн-модель Gemma через omlx", because вимога — офлайн і приватність; omlx говорить OpenAI API, тому `tauri-plugin-http` підходить без змін, а формат tool-маніфесту — стандартний OpenAI function-calling із того самого `src/tool/catalog.js`. MCP залишається ціллю після MVP. |
| 19 | + |
| 20 | +### Consequences |
| 21 | + |
| 22 | +- Good, because end-to-end цикл підтверджено наживо: `gemma-4-e2b-it-4bit` через omlx самостійно обрала тул `create`, `dispatch` виконав через `mt-scanner`, файли `task.md` + `a.md` реально створено. |
| 23 | +- Bad, because `gemma-4-e4b-it-OptiQ-4bit` впала з HTTP 507 (memory ceiling 11.84 GB, зайнято 10.57 GB) — потрібно звільняти RAM або використовувати меншу модель. |
| 24 | +- Bad, because ~4B-модель нестабільна в генерації коректного JSON для `tool_calls` — необхідний constrained decoding як наступний крок. |
| 25 | + |
| 26 | +## More Information |
| 27 | + |
| 28 | +Конфіг: `OMLX_BASE_URL` (дефолт `http://127.0.0.1:8000/v1`), `OMLX_MODEL` (дефолт `gemma-4-e4b-it-OptiQ-4bit`), `OMLX_API_KEY`. Файли: `app/src/tool/llm.js` (`createOpenAiChat`, `runAgent`), `app/src/composables/use-omlx.js` (localStorage), `app/bin/task.mjs` (команда `task agent "<prompt>"`). Модель підтверджено через `/v1/models` на сервері. MCP-обгортка — ціль на потім. |
| 29 | + |
| 30 | +## Update 2026-06-15 |
| 31 | + |
| 32 | +Додаткові деталі реалізації (сесія `e8e91f68`): `createOpenAiChat({ baseUrl, model, apiKey, fetchFn })` — `fetchFn` інжектується як залежність: Tauri використовує `@tauri-apps/plugin-http`, CLI — node `fetch`, тести — mock; єдиний код обслуговує всі три контексти. `runAgent({ prompt, dispatch, chat, maxSteps })` — до 3–5 кроків за прогін. |
| 33 | + |
| 34 | +Підтверджено наживо: `gemma-4-e2b-it-4bit` на порту `:8000` завершила повний tool-call цикл → `mt-scanner create` → файли `demo-llm/task.md` + `demo-llm/a.md`. `gemma-4-e4b-it-OptiQ-4bit` впала з HTTP 507 (потребує 17.89 GB, ceiling 11.84 GB). |
| 35 | + |
| 36 | +Рекомендація надійності: тримати малий набір тулів (≤3), по 1 за хід; наступний крок — constrained decoding для гарантованого JSON у `tool_calls`. |
| 37 | + |
| 38 | +Пер-stack реалізація `n-tool-surface` у `n-tauri` (версія `1.5`): один Rust-fn на тул, `#[tauri::command]`, dispatch-invoke через camelCase-ключі, конверт `{ok,output}` / `{ok:false,error}`. Правило `n-tool-surface` авто-активується через `depInAnyPackageJson` для `vue`/`react`/`svelte`/`@tauri-apps/api`/`@capacitor/core`. |
0 commit comments