@7n/tauri-components 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7n/tauri-components",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "Shared LLM agent engine + Vue/Quasar UI for Tauri apps (chat, journal, trust-tier approval).",
6
6
  "license": "MIT",
@@ -0,0 +1,35 @@
1
+ ---
2
+ docgen:
3
+ source: npm/src/components/AgentDialog.vue
4
+ crc: 197cc9c0
5
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
6
+ ---
7
+
8
+ # AgentDialog.vue
9
+
10
+ Компонент відображає діалогове вікно для взаємодії з локальною мовною моделлю (LLM) через агент. Він дозволяє користувачеві вводити запити, налаштовувати конфігурацію агента та бачити історію чату.
11
+
12
+ ## Поведінка
13
+ 1. **При відкритті діалогу (`onShow`):**
14
+ * Очищається поле введення та історія чату.
15
+ * Ініціалізується конфігурація агента, завантажуючи налаштування з глобальних даних.
16
+ * Завантажується список доступних моделей від сервера LLM.
17
+ 2. **При зміні конфігурації:**
18
+ * Користувач може вказати базовий URL, вибрати модель або ввести API ключ.
19
+ 3. **При введенні запиту та натисканні "Запустити"/"Надіслати":**
20
+ * Запит знімається з поля введення.
21
+ * Запис користувача додається до історії чату.
22
+ * Статус "думає" активується.
23
+ * Викликається метод агента для виконання запиту (новий запит або продовження існуючої розмови).
24
+ * Після отримання відповіді від агента:
25
+ * Відповідь агента додається до історії чату.
26
+ * Статус "думає" деактивується.
27
+ * Історія чату автоматично прокручується до останнього повідомлення.
28
+ 4. **При завершенні операції:**
29
+ * Якщо операція була успішною, компонент може повідомити зовнішній контекст про завершення роботи агента.
30
+
31
+ ## Гарантії поведінки
32
+ * Діалогове вікно відображає історію чату у порядку чергування: повідомлення користувача, а потім відповідь агента.
33
+ * Під час обробки запиту (відправлення або отримання відповіді) інтерфейс блокується, і відображається індикатор "думає...".
34
+ * При відсутності введення або активній обробці запиту, кнопка відправки вимкнена.
35
+ * При відкритті діалогу, список моделей заповнюється асинхронно, відображаючи стан завантаження.
@@ -0,0 +1,28 @@
1
+ ---
2
+ docgen:
3
+ source: npm/src/components/AuditDialog.vue
4
+ crc: 963a61d8
5
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
6
+ ---
7
+
8
+ # AuditDialog.vue
9
+
10
+ Компонент відображає журнал аудиту, наданий зовнішнім агентом. Він дозволяє переглядати записи, розширювати їх для детального огляду та взаємодіяти з ними (наприклад, відповідати або затверджувати).
11
+
12
+ ## Поведінка
13
+ 1. При ініціалізації компонента, якщо не вказано інше, журнал аудиту не завантажується.
14
+ 2. При натисканні кнопки "Оновити" у заголовку, компонент ініціює завантаження списку записів журналу.
15
+ 3. Під час завантаження, відображається індикатор завантаження.
16
+ 4. Якщо список записів порожній і завантаження завершено, відображається повідомлення "No requests yet".
17
+ 5. Кожен запис журналу відображається як рядок.
18
+ 6. Натискання на заголовок рядка розкриває або приховує деталі цього запису.
19
+ 7. Якщо запис має статус "needs_approval" та потребує затвердження, відображаються кнопки "Підтвердити" та "Відхилити".
20
+ 8. При натисканні на "Підтвердити" або "Відхилити", компонент викликає відповідну дію агента, оновлює журнал і надсилає подію `changed`.
21
+ 9. При взаємодії з `RequestView` (наприклад, введення відповіді), компонент викликає дію агента `respond`, оновлює журнал і надсилає подію `changed`.
22
+ 10. При зміні властивості `modelValue` зовнішнім компонентом, компонент оновлює свій стан відображення.
23
+
24
+ ## Гарантії поведінки
25
+ * Компонент завжди відображає актуальний стан журналу після успішного виклику `refresh`.
26
+ * Під час виконання операцій (відповідь, затвердження) компонент блокує взаємодію з відповідним записом, щоб уникнути подвійних викликів.
27
+ * У разі помилки при завантаженні або взаємодії з агентом, користувачеві відображається сповіщення.
28
+ * Деталі запису відображаються лише тоді, коли відповідний запис розгорнутий.
@@ -0,0 +1,22 @@
1
+ ---
2
+ docgen:
3
+ source: npm/src/components/BaseDialog.vue
4
+ crc: 88aaae5f
5
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
6
+ ---
7
+
8
+ # BaseDialog.vue
9
+
10
+ Компонент надає універсальну структуру для діалогових вікон у застосунку. Він інкапсулює типовий макет діалогу, включаючи заголовок, тіло та кнопки дій.
11
+
12
+ ## Поведінка
13
+ 1. Відображає діалогове вікно, кероване станом `modelValue`.
14
+ 2. Відображає заголовок, що складається з іконки (за наявності), назви (`title`) та кнопки закриття.
15
+ 3. Дозволяє вставити контент у тіло діалогу через основний слот.
16
+ 4. Дозволяє вставити елементи керування (кнопки) у нижню частину діалогу через слот `actions`.
17
+ 5. При зміні стану `modelValue` зовнішнім компонентом, компонент емітує подію `update:modelValue` з новим значенням.
18
+
19
+ ## Гарантії поведінки
20
+ * Діалогове вікно завжди має визначену назву (`title`).
21
+ * Ширина діалогового вікна за замовчуванням становить 520 пікселів, але може бути перевизначена.
22
+ * Компонент коректно передає всі додаткові атрибути, отримані від батьківського елемента, до базового елемента діалогу.
@@ -0,0 +1,24 @@
1
+ ---
2
+ docgen:
3
+ source: npm/src/components/DialogActions.vue
4
+ crc: 7126e317
5
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
6
+ ---
7
+
8
+ # DialogActions.vue
9
+
10
+ Компонент надає стандартний нижній колонтитул для діалогових вікон, що містить кнопку скасування та основну кнопку дії. Він забезпечує канонічний патерн "скасувати + відправити" для діалогів.
11
+
12
+ ## Поведінка
13
+ 1. Відображає кнопку "Скасувати", яка закриває діалогове вікно при натисканні.
14
+ 2. Відображає основну кнопку дії, яка виконує наступне:
15
+ * При натисканні викликає подію `submit`.
16
+ * Може бути вимкнена (неактивна) відповідно до властивості `disable`.
17
+ * Може відображати індикатор завантаження відповідно до властивості `loading`.
18
+ * Відображає мітку, визначену властивістю `submitLabel`.
19
+ * Може відображати іконку, визначену властивістю `icon`.
20
+
21
+ ## Гарантії поведінки
22
+ * Кнопка "Скасувати" завжди присутня і закриває діалог.
23
+ * Основна кнопка дії завжди присутня і вимагає надання мітки.
24
+ * Компонент коректно реагує на стани `disable` та `loading` для керування поведінкою кнопки дії.
@@ -0,0 +1,25 @@
1
+ ---
2
+ docgen:
3
+ source: npm/src/components/RequestView.vue
4
+ crc: ce95caa9
5
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
6
+ ---
7
+
8
+ # RequestView.vue
9
+
10
+ Компонент відображає детальний вигляд результату виконання запиту. Він візуалізує статус, резюме, помилки та список виконаних дій.
11
+
12
+ ## Поведінка
13
+ 1. Відображає статус результату за допомогою компонента `StatePill`.
14
+ 2. Якщо у результаті є резюме, відображає його як текстовий блок.
15
+ 3. Якщо у результаті є питання, відображає його як текстовий блок.
16
+ 4. Якщо у результаті є помилка, відображає її як червоний текстовий блок.
17
+ 5. Якщо у результаті є список дій, відображає їх у вигляді окремих рядків.
18
+ 6. Для кожної дії відображає іконку, що вказує на успіх або помилку виконання дії.
19
+ 7. Для кожної дії відображає назву інструменту та його вхідні дані.
20
+
21
+ ## Гарантії поведінки
22
+ * Компонент завжди відображає статус результату, оскільки властивість `result` є обов'язковою.
23
+ * Текстові блоки (резюме, питання, помилка) відображаються лише за наявності відповідного поля у `result`.
24
+ * Список дій відображається лише за наявності елементів у масиві `actions` у `result`.
25
+ * Іконка для кожної дії коректно відображає стан виконання дії (успіх або помилка).
@@ -0,0 +1,20 @@
1
+ ---
2
+ docgen:
3
+ source: npm/src/components/StatePill.vue
4
+ crc: ccee8975
5
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
6
+ ---
7
+
8
+ # StatePill.vue
9
+
10
+ Компонент відображає візуальний маркер стану (pill). Він використовується для індикації статусу в різних частинах застосунку.
11
+
12
+ ## Поведінка
13
+ 1. Компонент отримує текстовий статус.
14
+ 2. Компонент визначає відповідний колір на основі отриманого статусу.
15
+ 3. Компонент відображає текстовий статус.
16
+ 4. Компонент відображає візуальний маркер (крапку) кольору, визначеного для цього статусу.
17
+
18
+ ## Гарантії поведінки
19
+ * Відображення завжди містить текстовий статус.
20
+ * Колір візуального маркера та фону компонента коректно відображається відповідно до наданого статусу.
@@ -0,0 +1,28 @@
1
+ ---
2
+ docgen:
3
+ source: npm/src/components/index.js
4
+ crc: 42b50c52
5
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
6
+ score: 100
7
+ judgeModel: openai-codex/gpt-5.4-mini
8
+ ---
9
+
10
+ # index.js
11
+
12
+ ## Огляд
13
+
14
+ Компоненти цього файлу керують відображенням діалогових вікон, які взаємодіють з агентом. Експортується базовий клас для діалогів, компоненти для відображення специфічних дій, деталей запиту та поточного стану, а також константи для визначення кольорів стану.
15
+
16
+ ## Поведінка
17
+
18
+ 1. Експортує компонент `AgentDialog` для відображення діалогових вікон, що взаємодіють з агентом.
19
+ 2. Експортує компонент `AuditDialog` для відображення діалогових вікон аудиту, що взаємодіють з агентом.
20
+ 3. Експортує компонент `BaseDialog` як базовий елемент для створення діалогових вікон.
21
+ 4. Експортує компонент `DialogActions` для відображення дій у діалогових вікнах.
22
+ 5. Експортує компонент `RequestView` для відображення деталей запиту.
23
+ 6. Експортує компонент `StatePill` для відображення стану.
24
+ 7. Експортує константи `STATUS_COLOR` та `statusColor` для визначення кольорів стану.
25
+
26
+ ## Гарантії поведінки
27
+
28
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,29 @@
1
+ ---
2
+ docgen:
3
+ source: npm/src/components/status.js
4
+ crc: 352af502
5
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
6
+ score: 100
7
+ issues: judge:inaccurate:0.96
8
+ judgeModel: openai-codex/gpt-5.4-mini
9
+ ---
10
+
11
+ # status.js
12
+
13
+ ## Огляд
14
+
15
+ Файл визначає кольорові значення, що відповідають різним станам запиту. Публічні функції `STATUS_COLOR` та `statusColor` повертають конкретний акцентний колір для заданого статусу або сірий колір у випадку невідомого статусу.
16
+
17
+ ## Поведінка
18
+
19
+ STATUS_COLOR — Надає об'єкт, що містить визначені кольори для різних станів запиту.
20
+ statusColor — Повертає відповідний акцентний колір для заданого статусу запиту, використовуючи сірий колір за замовчуванням для невідомих статусів.
21
+
22
+ ## Публічний API
23
+
24
+ STATUS_COLOR — встановлює колір, який відображає поточний статус.
25
+ statusColor — встановлює колір, який відображає поточний статус.
26
+
27
+ ## Гарантії поведінки
28
+
29
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,192 @@
1
+ import { invoke } from '@tauri-apps/api/core'
2
+ import { listen } from '@tauri-apps/api/event'
3
+
4
+ // ACP session driver: the replacement for llm.js's runAgent()/createOpenAiChat.
5
+ // Instead of running our own chat-completion loop, we spawn an external ACP
6
+ // agent (codex-acp/claude-agent-acp/cursor `agent acp`/pi-acp) via the Rust
7
+ // plugin's acp_* commands and stream its `session/update` notifications back
8
+ // into the same {content, trace, messages, stopped?} shape runAgent() used to
9
+ // return, so agent-handler.js's runAndJournal needs no structural changes —
10
+ // only which turn-runner it calls.
11
+ //
12
+ // Domain-tool approval (the MCP bridge's `acp://mcp-tool-call`) and native ACP
13
+ // permission requests (`acp://permission-request`) are separate event streams
14
+ // callers subscribe to independently — see onAcpToolCall / onAcpPermissionRequest.
15
+ // While either is pending, the underlying acp_prompt Tauri call simply stays
16
+ // unresolved (the agent's tools/call HTTP request is parked on the Rust side),
17
+ // so the turn transparently continues once the human answers.
18
+
19
+ /**
20
+ * Spawn an ACP agent subprocess and run its `initialize` + `session/new`
21
+ * handshake. Returns a session handle to pass to `runAcpTurn`/`cancelAcpSession`.
22
+ * @param {object} params spawn parameters
23
+ * @param {string} params.agentKind 'codex'|'claude'|'cursor'|'pi' (informational — passed through, not interpreted here)
24
+ * @param {string} params.command executable to spawn (e.g. 'npx')
25
+ * @param {string[]} [params.args] command arguments
26
+ * @param {Record<string,string>} [params.env] extra environment variables for the subprocess
27
+ * @param {string} params.cwd session working directory (absolute path)
28
+ * @param {string} [params.mcpBridgeUrl] this app's domain MCP bridge URL (from acpStartMcpBridge), omit for no domain tools
29
+ * @param {boolean} [params.allowFs] grant fs/read_text_file + fs/write_text_file
30
+ * @param {boolean} [params.allowTerminal] grant terminal/*
31
+ * @returns {Promise<{sessionKey: string, agentKind: string}>} session handle
32
+ */
33
+ export async function createAcpSession({ agentKind, command, args = [], env = {}, cwd, mcpBridgeUrl, allowFs = false, allowTerminal = false }) {
34
+ const sessionKey = await invoke('plugin:agent|acp_spawn_agent', {
35
+ args: { command, args, env, cwd, mcpBridgeUrl, allowFs, allowTerminal },
36
+ })
37
+ return { sessionKey, agentKind }
38
+ }
39
+
40
+ /**
41
+ * Map an ACP `stopReason` onto the `stopped` field runAgent() used to return
42
+ * (undefined means "ended normally", matching the old no-tool-call exit).
43
+ * @param {string} stopReason ACP PromptResponse.stopReason
44
+ * @returns {string|undefined} runAgent()-shaped stopped reason
45
+ */
46
+ function stoppedFromStopReason(stopReason) {
47
+ if (stopReason === 'end_turn') return
48
+ if (stopReason === 'cancelled') return 'cancelled'
49
+ if (stopReason === 'refusal') return 'refusal'
50
+ return 'max_steps' // max_tokens / max_turn_requests / anything unrecognized
51
+ }
52
+
53
+ /**
54
+ * Fold one `session/update` payload into the turn's running content/trace.
55
+ * @param {object} state mutable accumulator ({ text, messageId, calls: Map })
56
+ * @param {object} update the ACP SessionUpdate (already unwrapped from the event payload)
57
+ * @returns {void}
58
+ */
59
+ function applySessionUpdate(state, update) {
60
+ switch (update?.sessionUpdate) {
61
+ case 'agent_message_chunk': {
62
+ if (update.messageId !== state.messageId) {
63
+ state.messageId = update.messageId
64
+ state.text = ''
65
+ }
66
+ state.text += update.content?.text ?? ''
67
+ break
68
+ }
69
+ case 'tool_call': {
70
+ state.calls.set(update.toolCallId, {
71
+ tool: update.title ?? update.toolCallId,
72
+ input: update.rawInput ?? {},
73
+ envelope: null,
74
+ })
75
+ break
76
+ }
77
+ case 'tool_call_update': {
78
+ const call = state.calls.get(update.toolCallId)
79
+ const fields = update.fields ?? {}
80
+ if (call && fields.rawOutput !== undefined) {
81
+ call.envelope = { ok: fields.status !== 'failed', output: fields.rawOutput }
82
+ }
83
+ break
84
+ }
85
+ default: {
86
+ break
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Run one prompt turn on an already-spawned ACP session, streaming
93
+ * `session/update` chunks into the same shape `runAgent()` returned.
94
+ * @param {object} params turn parameters
95
+ * @param {string} params.sessionKey handle from `createAcpSession`
96
+ * @param {string} params.text prompt text for this turn
97
+ * @param {(update: object) => void} [params.onChunk] optional live callback for each raw session/update (UI streaming)
98
+ * @returns {Promise<{content: string, steps: number, trace: object[], messages: object[], stopped?: string}>} runAgent()-shaped result
99
+ */
100
+ export async function runAcpTurn({ sessionKey, text, onChunk }) {
101
+ const state = { text: '', messageId: null, calls: new Map() }
102
+
103
+ const unlisten = await listen('acp://session-update', (event) => {
104
+ if (event.payload?.sessionKey !== sessionKey) return
105
+ applySessionUpdate(state, event.payload.update)
106
+ onChunk?.(event.payload.update)
107
+ })
108
+
109
+ try {
110
+ const stopReason = await invoke('plugin:agent|acp_prompt', { sessionKey, text })
111
+ const trace = [...state.calls.values()]
112
+ const messages = state.text ? [{ role: 'assistant', content: state.text }] : []
113
+ return {
114
+ content: state.text,
115
+ steps: 1,
116
+ trace,
117
+ messages,
118
+ stopped: stoppedFromStopReason(stopReason),
119
+ }
120
+ }
121
+ finally {
122
+ unlisten()
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Ask the agent to cancel its in-flight prompt turn.
128
+ * @param {string} sessionKey handle from `createAcpSession`
129
+ * @returns {Promise<void>} resolves once the cancel notification is sent
130
+ */
131
+ export function cancelAcpSession(sessionKey) {
132
+ return invoke('plugin:agent|acp_cancel', { sessionKey })
133
+ }
134
+
135
+ /**
136
+ * Subscribe to `acp://mcp-tool-call` (a domain-catalog tool call the agent
137
+ * made through the MCP bridge, waiting on `acp_mcp_tool_result`).
138
+ * @param {(payload: {requestId: string, tool: string, input: object}) => void} handler callback
139
+ * @returns {Promise<() => void>} unlisten function
140
+ */
141
+ export function onAcpToolCall(handler) {
142
+ return listen('acp://mcp-tool-call', event => handler(event.payload))
143
+ }
144
+
145
+ /**
146
+ * Resolve a pending `acp://mcp-tool-call` with the same envelope shape
147
+ * `createDispatch` returns.
148
+ * @param {string} requestId id from the `acp://mcp-tool-call` payload
149
+ * @param {{ok: boolean, output?: unknown, error?: {code: string, message: string}}} envelope dispatch result
150
+ * @returns {Promise<void>} resolves once the reply reaches the Rust bridge
151
+ */
152
+ export function respondAcpToolCall(requestId, envelope) {
153
+ return invoke('plugin:agent|acp_mcp_tool_result', { requestId, envelope })
154
+ }
155
+
156
+ /**
157
+ * Subscribe to `acp://permission-request` (a native ACP `session/request_permission`
158
+ * call, e.g. the agent's own file-edit/bash tools asking before running).
159
+ * @param {(payload: {sessionKey: string, requestId: string, toolCall: object, options: {optionId: string, name: string}[]}) => void} handler callback
160
+ * @returns {Promise<() => void>} unlisten function
161
+ */
162
+ export function onAcpPermissionRequest(handler) {
163
+ return listen('acp://permission-request', event => handler(event.payload))
164
+ }
165
+
166
+ /**
167
+ * Resolve a pending `acp://permission-request` by selecting one of its options.
168
+ * @param {string} requestId id from the `acp://permission-request` payload
169
+ * @param {string} optionId one of the payload's `options[].optionId`
170
+ * @returns {Promise<void>} resolves once the permission response is sent
171
+ */
172
+ export function respondAcpPermission(requestId, optionId) {
173
+ return invoke('plugin:agent|acp_respond_permission', { requestId, optionId })
174
+ }
175
+
176
+ /**
177
+ * Register this app's tool catalog with the domain MCP bridge and start it.
178
+ * @param {object[]} catalog tool definitions (same shape passed to `createAgentKit`)
179
+ * @returns {Promise<string>} the bridge's loopback URL, e.g. `http://127.0.0.1:54321/`
180
+ */
181
+ export async function startAcpMcpBridge(catalog) {
182
+ await invoke('plugin:agent|acp_register_catalog', { tools: catalog })
183
+ return invoke('plugin:agent|acp_start_mcp_bridge')
184
+ }
185
+
186
+ /**
187
+ * Read the per-machine default agent kind (`ACP_DEFAULT_AGENT` env var).
188
+ * @returns {Promise<{defaultAgentKind: string|null}>} config
189
+ */
190
+ export function acpConfig() {
191
+ return invoke('plugin:agent|acp_config')
192
+ }