@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 +1 -1
- package/src/components/docs/AgentDialog.md +35 -0
- package/src/components/docs/AuditDialog.md +28 -0
- package/src/components/docs/BaseDialog.md +22 -0
- package/src/components/docs/DialogActions.md +24 -0
- package/src/components/docs/RequestView.md +25 -0
- package/src/components/docs/StatePill.md +20 -0
- package/src/components/docs/index.md +28 -0
- package/src/components/docs/status.md +29 -0
- package/src/core/acp-agent.js +192 -0
- package/src/core/acp-kit.js +260 -0
- package/src/core/docs/acp-agent.md +43 -0
- package/src/core/docs/acp-kit.md +50 -0
- package/src/core/docs/agent-handler.md +31 -0
- package/src/core/docs/agent-kit.md +25 -0
- package/src/core/docs/dispatch.md +30 -0
- package/src/core/docs/llm.md +29 -0
- package/src/core/docs/manifest.md +30 -0
- package/src/core/docs/omlx-models.md +30 -0
- package/src/core/docs/resolve-omlx-base-url.md +40 -0
- package/src/core/docs/scope.md +32 -0
- package/src/core/docs/tools.md +28 -0
- package/src/docs/index.md +54 -0
- package/src/index.js +12 -0
- package/src/testing/docs/index.md +24 -0
- package/src/testing/docs/quasar.md +28 -0
- package/src/vue/docs/index.md +28 -0
- package/src/vue/docs/journal-store-tauri.md +27 -0
- package/src/vue/docs/transports.md +25 -0
- package/src/vue/docs/use-acp-agent.md +29 -0
- package/src/vue/docs/use-agent.md +29 -0
- package/src/vue/docs/use-omlx.md +30 -0
- package/src/vue/docs/use-updater.md +31 -0
- package/src/vue/index.js +1 -0
- package/src/vue/use-acp-agent.js +109 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import * as acpAgent from './acp-agent.js'
|
|
2
|
+
import { createDispatch } from './dispatch.js'
|
|
3
|
+
import { classify, DEFAULT_ACTOR_TIERS } from './scope.js'
|
|
4
|
+
|
|
5
|
+
// createAcpAgentKit binds an app's catalog + journal to the ACP execution
|
|
6
|
+
// engine — the ACP-flavored sibling of createAgentKit (agent-kit.js), added
|
|
7
|
+
// alongside it so existing consumers keep working on the old omlx/runAgent
|
|
8
|
+
// path while migrating at their own pace (see SPEC / plan for the sequencing).
|
|
9
|
+
//
|
|
10
|
+
// The two engines differ in where tool dispatch happens: runAgent() drove its
|
|
11
|
+
// own tool-calling loop and dispatched synchronously inside handleRequest.
|
|
12
|
+
// Here the ACP agent process drives its OWN loop and calls domain tools
|
|
13
|
+
// through the Rust-side MCP bridge — so dispatch is triggered by a STANDING
|
|
14
|
+
// listener on `acp://mcp-tool-call`, not by anything in request()/respond().
|
|
15
|
+
// Every such call is tier-classified as an `{kind:'agent'}` actor, since by
|
|
16
|
+
// construction only an autonomous agent process can reach the bridge.
|
|
17
|
+
//
|
|
18
|
+
// Scope: one active session/request at a time, matching how AgentDialog is
|
|
19
|
+
// actually used today (a single live conversation). A tool call or permission
|
|
20
|
+
// request always attaches its `needs_approval` state to whichever journal
|
|
21
|
+
// request is currently active — concurrent sessions would need per-session
|
|
22
|
+
// routing, which isn't attempted here.
|
|
23
|
+
|
|
24
|
+
const AGENT_ACTOR = { kind: 'agent', id: 'acp' }
|
|
25
|
+
const QUESTION_RE = /\?\s*$/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} text candidate text
|
|
29
|
+
* @returns {boolean} true when text ends with a question mark
|
|
30
|
+
*/
|
|
31
|
+
function isQuestion(text) {
|
|
32
|
+
return typeof text === 'string' && QUESTION_RE.test(text.trim())
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Derive the structured result fields from a runAcpTurn() result.
|
|
37
|
+
* @param {{content: string, stopped?: string}} turn runAcpTurn result
|
|
38
|
+
* @returns {{status: string, summary: string|null, question: string|null}} fields
|
|
39
|
+
*/
|
|
40
|
+
function finalizeTurn(turn) {
|
|
41
|
+
const question = isQuestion(turn.content) ? turn.content : null
|
|
42
|
+
let status = 'done'
|
|
43
|
+
if (turn.stopped === 'max_steps' || turn.stopped === 'refusal') status = 'partial'
|
|
44
|
+
else if (turn.stopped === 'cancelled') status = 'partial'
|
|
45
|
+
else if (question) status = 'needs_clarification'
|
|
46
|
+
return { status, summary: question ? null : (turn.content || null), question }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {object} config kit configuration
|
|
51
|
+
* @param {object[]} config.catalog tool definitions (required)
|
|
52
|
+
* @param {object} config.journal journal store { create, load, update, list }
|
|
53
|
+
* @param {(tool: object, input: object) => unknown} [config.transport] backend runner for domain tools; omit for a chat-only kit (no domain MCP tools)
|
|
54
|
+
* @param {Record<string, number>} [config.actorTiers] max executable tier rank per actor kind
|
|
55
|
+
* @param {object} [config.deps] injectable `acp-agent.js` functions (tests only — defaults to the real module)
|
|
56
|
+
* @returns {{request: Function, respond: Function, approve: Function}} bound kit
|
|
57
|
+
*/
|
|
58
|
+
export function createAcpAgentKit({ catalog, journal, transport, actorTiers = DEFAULT_ACTOR_TIERS, deps = acpAgent } = {}) {
|
|
59
|
+
if (!Array.isArray(catalog)) throw new Error('createAcpAgentKit: catalog (array) is required')
|
|
60
|
+
|
|
61
|
+
const dispatch = transport ? createDispatch(catalog, transport) : null
|
|
62
|
+
let activeSessionKey = null
|
|
63
|
+
let activeRequestId = null
|
|
64
|
+
let listening = false
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolve one pending MCP tools/call per the tier decision. Called once per
|
|
68
|
+
* `acp://mcp-tool-call` event.
|
|
69
|
+
* @param {{requestId: string, tool: string, input: object}} payload event payload
|
|
70
|
+
* @returns {Promise<void>} resolves once the bridge has an answer
|
|
71
|
+
*/
|
|
72
|
+
async function handleToolCall({ requestId, tool, input }) {
|
|
73
|
+
if (!dispatch) {
|
|
74
|
+
await deps.respondAcpToolCall(requestId, { ok: false, error: { code: 'forbidden', message: 'No transport configured.' } })
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
const decision = classify(catalog, actorTiers, AGENT_ACTOR, tool)
|
|
78
|
+
if (decision === 'deny') {
|
|
79
|
+
await deps.respondAcpToolCall(requestId, { ok: false, error: { code: 'forbidden', message: `Tool "${tool}" is not allowed.` } })
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
if (decision === 'approval') {
|
|
83
|
+
if (activeRequestId) {
|
|
84
|
+
await journal.update(activeRequestId, { status: 'needs_approval', pendingApproval: { kind: 'mcp', requestId, tool, input } })
|
|
85
|
+
}
|
|
86
|
+
return // acp_mcp_tool_result comes later, from approve()
|
|
87
|
+
}
|
|
88
|
+
await deps.respondAcpToolCall(requestId, await dispatch(tool, input))
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Mirror a native ACP `session/request_permission` into the same
|
|
93
|
+
* `pendingApproval` shape as an MCP tool-call pause, so `AuditDialog` only
|
|
94
|
+
* has to understand one contract.
|
|
95
|
+
* @param {{requestId: string, toolCall: object, options: {optionId: string, name: string, kind: string}[]}} payload event payload
|
|
96
|
+
* @returns {Promise<void>} resolves once the journal is updated
|
|
97
|
+
*/
|
|
98
|
+
async function handlePermissionRequest(payload) {
|
|
99
|
+
if (!activeRequestId) return
|
|
100
|
+
await journal.update(activeRequestId, { status: 'needs_approval', pendingApproval: { kind: 'acp', ...payload } })
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Start listening for domain tool calls and native permission requests —
|
|
105
|
+
* lazy, once per kit, since it applies to every session this kit drives.
|
|
106
|
+
* @returns {Promise<void>} resolves once both listeners are attached
|
|
107
|
+
*/
|
|
108
|
+
async function ensureListening() {
|
|
109
|
+
if (listening) return
|
|
110
|
+
listening = true
|
|
111
|
+
await deps.onAcpToolCall(handleToolCall)
|
|
112
|
+
await deps.onAcpPermissionRequest(handlePermissionRequest)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Run one turn, journal the result, and reset `pendingApproval`. Callers
|
|
117
|
+
* must set `activeRequestId` themselves *before* starting the turn — a
|
|
118
|
+
* tool-call/permission-request can arrive (and needs to see the right id)
|
|
119
|
+
* while the turn's own promise is still pending, so setting it here as a
|
|
120
|
+
* side effect of awaiting would be too late.
|
|
121
|
+
* @param {string} requestId journal record id
|
|
122
|
+
* @param {object[]} baseActions actions already recorded for this request
|
|
123
|
+
* @param {Promise<object>} turnPromise the in-flight `runAcpTurn` call
|
|
124
|
+
* @returns {Promise<object>} structured result envelope
|
|
125
|
+
*/
|
|
126
|
+
async function runAndJournal(requestId, baseActions, turnPromise) {
|
|
127
|
+
let turn
|
|
128
|
+
try {
|
|
129
|
+
turn = await turnPromise
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
await journal.update(requestId, { status: 'failed', error: String(error?.message ?? error) })
|
|
133
|
+
return { requestId, status: 'failed', summary: null, actions: baseActions, question: null, pendingApproval: null }
|
|
134
|
+
}
|
|
135
|
+
const fields = finalizeTurn(turn)
|
|
136
|
+
const actions = [...baseActions, ...turn.trace]
|
|
137
|
+
await journal.update(requestId, { ...fields, messages: turn.messages, actions, pendingApproval: null })
|
|
138
|
+
return { requestId, ...fields, actions, pendingApproval: null }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
/**
|
|
143
|
+
* Start a new ACP-backed request: spawns the agent session and runs the
|
|
144
|
+
* first prompt turn.
|
|
145
|
+
* @param {{intent: string, agent: object}} opts `agent` is passed straight to `createAcpSession` (agentKind/command/args/env/cwd/…)
|
|
146
|
+
* @returns {Promise<object>} structured result envelope
|
|
147
|
+
*/
|
|
148
|
+
async request({ intent, agent }) {
|
|
149
|
+
await ensureListening()
|
|
150
|
+
const id = await journal.create({ intent, actor: AGENT_ACTOR })
|
|
151
|
+
await journal.update(id, { status: 'running' })
|
|
152
|
+
const session = await deps.createAcpSession(agent)
|
|
153
|
+
activeSessionKey = session.sessionKey
|
|
154
|
+
activeRequestId = id
|
|
155
|
+
await journal.update(id, { acp: { agentKind: session.agentKind, sessionKey: session.sessionKey } })
|
|
156
|
+
return runAndJournal(id, [], deps.runAcpTurn({ sessionKey: activeSessionKey, text: intent }))
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Continue the active session with a follow-up message.
|
|
161
|
+
* @param {{requestId: string, message: string}} opts resume parameters
|
|
162
|
+
* @returns {Promise<object>} updated result envelope
|
|
163
|
+
*/
|
|
164
|
+
async respond({ requestId, message }) {
|
|
165
|
+
if (!activeSessionKey) {
|
|
166
|
+
return { requestId, status: 'failed', summary: null, actions: [], question: 'No active ACP session.', pendingApproval: null }
|
|
167
|
+
}
|
|
168
|
+
let record
|
|
169
|
+
try {
|
|
170
|
+
record = await journal.load(requestId)
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return { requestId, status: 'failed', summary: null, actions: [], question: 'Request not found.', pendingApproval: null }
|
|
174
|
+
}
|
|
175
|
+
await journal.update(requestId, { status: 'running' })
|
|
176
|
+
activeRequestId = requestId
|
|
177
|
+
return runAndJournal(requestId, record.actions ?? [], deps.runAcpTurn({ sessionKey: activeSessionKey, text: message }))
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Resolve a pending approval — either an MCP domain-tool call or a native
|
|
182
|
+
* ACP permission request, whichever is attached to this journal record.
|
|
183
|
+
* @param {{requestId: string, approve: boolean}} opts approval parameters
|
|
184
|
+
* @returns {Promise<object>} updated result envelope
|
|
185
|
+
*/
|
|
186
|
+
async approve({ requestId, approve: decision }) {
|
|
187
|
+
let record
|
|
188
|
+
try {
|
|
189
|
+
record = await journal.load(requestId)
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return { requestId, status: 'failed', summary: null, actions: [], question: 'Request not found.', pendingApproval: null }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const pending = record.pendingApproval
|
|
196
|
+
if (record.status !== 'needs_approval' || !pending) {
|
|
197
|
+
return { requestId, status: record.status, summary: record.summary, actions: record.actions ?? [], question: null, pendingApproval: null }
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (pending.kind === 'acp') return approveAcpPermission(deps, journal, requestId, record, pending, decision)
|
|
201
|
+
return approveMcpToolCall(deps, dispatch, journal, requestId, record, pending, decision)
|
|
202
|
+
},
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Resolve a pending MCP domain-tool call (reject with a forbidden envelope,
|
|
208
|
+
* or dispatch and forward the real envelope) and unblock the agent.
|
|
209
|
+
*
|
|
210
|
+
* Deliberately does **not** declare a terminal `done`/`rejected` status: once
|
|
211
|
+
* we reply to the agent's `tools/call`, its turn keeps running in the
|
|
212
|
+
* background — the in-flight `request()`/`respond()` call's `runAndJournal`
|
|
213
|
+
* is the only thing that will observe how the turn actually concludes (it
|
|
214
|
+
* may make more tool calls, or answer differently than a flat "done" would
|
|
215
|
+
* suggest), so it's the sole writer of the final journal state. This also
|
|
216
|
+
* means the old "retry a failed dispatch" UX doesn't carry over: once the
|
|
217
|
+
* agent has been told a tool call failed, it has already moved on.
|
|
218
|
+
* @param {object} deps injected acp-agent.js functions
|
|
219
|
+
* @param {Function} dispatch bound `createDispatch` result
|
|
220
|
+
* @param {object} journal journal store
|
|
221
|
+
* @param {string} requestId journal record id
|
|
222
|
+
* @param {object} record loaded journal record
|
|
223
|
+
* @param {{requestId: string, tool: string, input: object}} pending the paused MCP call
|
|
224
|
+
* @param {boolean} decision approve (true) or reject (false)
|
|
225
|
+
* @returns {Promise<object>} immediate (non-terminal) result envelope
|
|
226
|
+
*/
|
|
227
|
+
async function approveMcpToolCall(deps, dispatch, journal, requestId, record, pending, decision) {
|
|
228
|
+
const envelope = decision
|
|
229
|
+
? await dispatch(pending.tool, pending.input)
|
|
230
|
+
: { ok: false, error: { code: 'forbidden', message: 'Rejected by human.' } }
|
|
231
|
+
await deps.respondAcpToolCall(pending.requestId, envelope)
|
|
232
|
+
|
|
233
|
+
const actions = [...(record.actions ?? []), { tool: pending.tool, input: pending.input, envelope }]
|
|
234
|
+
await journal.update(requestId, { status: 'running', actions, pendingApproval: null })
|
|
235
|
+
return { requestId, status: 'running', summary: null, actions, question: null, pendingApproval: null }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Resolve a native ACP `session/request_permission` by selecting the
|
|
240
|
+
* matching allow/reject option (`kind` from `PermissionOptionView`, see
|
|
241
|
+
* `tauri-plugin-agent/src/acp/mod.rs`) and unblock the agent. Falls back to
|
|
242
|
+
* the first option if none of the requested kind is offered. Same
|
|
243
|
+
* non-terminal-status rule as `approveMcpToolCall` — the agent's turn is
|
|
244
|
+
* still running.
|
|
245
|
+
* @param {object} deps injected acp-agent.js functions
|
|
246
|
+
* @param {object} journal journal store
|
|
247
|
+
* @param {string} requestId journal record id
|
|
248
|
+
* @param {object} record loaded journal record
|
|
249
|
+
* @param {{requestId: string, options: {optionId: string, kind: string}[]}} pending the paused permission request
|
|
250
|
+
* @param {boolean} decision approve (true) or reject (false)
|
|
251
|
+
* @returns {Promise<object>} immediate (non-terminal) result envelope
|
|
252
|
+
*/
|
|
253
|
+
async function approveAcpPermission(deps, journal, requestId, record, pending, decision) {
|
|
254
|
+
const wantPrefix = decision ? 'allow' : 'reject'
|
|
255
|
+
const option = pending.options?.find(o => o.kind?.startsWith(wantPrefix)) ?? pending.options?.[0]
|
|
256
|
+
await deps.respondAcpPermission(pending.requestId, option?.optionId)
|
|
257
|
+
|
|
258
|
+
await journal.update(requestId, { status: 'running', pendingApproval: null })
|
|
259
|
+
return { requestId, status: 'running', summary: null, actions: record.actions ?? [], question: null, pendingApproval: null }
|
|
260
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/acp-agent.js
|
|
4
|
+
crc: e30fb954
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
issues: judge:inaccurate:0.98
|
|
8
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# acp-agent.js
|
|
12
|
+
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
Модуль керує життєвим циклом сесій агента ACP. Він дозволяє ініціалізувати сесії за допомогою `createAcpSession`, виконувати ходи промпта через `runAcpTurn` та скасовувати сесії за допомогою `cancelAcpSession`. Модуль встановлює мережевий зв'язок через http://127.0.0.1:54321/ та ініціалізує MCP-міст за допомогою `startAcpMcpBridge`. Він реєструє інструменти та обробляє запити на виклики інструментів через `onAcpToolCall` та відповіді на них через `respondAcpToolCall`. Модуль також обробляє запити на дозволи через `onAcpPermissionRequest` та надає відповіді за допомогою `respondAcpPermission`. Модуль надає конфігурацію типу агента за допомогою `acpConfig`. Усі помилки перехоплюються (fail-safe), і винятки не викидаються назовні.
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
createAcpSession запускає підпроцес агента ACP та ініціалізує його сесію, повертаючи ключ сесії.
|
|
20
|
+
runAcpTurn виконує один хід промпта для існуючої сесії ACP, потоково передаючи оновлення сесії.
|
|
21
|
+
cancelAcpSession відсилає команду на скасування поточного промпт-ходу для сесії ACP.
|
|
22
|
+
onAcpToolCall підписується на події виклику інструменту, ініційовані агентом через MCP-міст.
|
|
23
|
+
respondAcpToolCall вирішує очікуваний виклик інструменту, надаючи результат агенту.
|
|
24
|
+
onAcpPermissionRequest підписується на запити дозволу від агента, наприклад, на доступ до файлової системи.
|
|
25
|
+
respondAcpPermission вирішує очікуваний запит дозволу, обираючи один із запропонованих варіантів.
|
|
26
|
+
startAcpMcpBridge реєструє каталог інструментів цього застосунку в доменному MCP-міст та запускає його, повертаючи URL, наприклад, http://127.0.0.1:54321/.
|
|
27
|
+
acpConfig зчитує за замовчуванням тип агента для машини.
|
|
28
|
+
|
|
29
|
+
## Публічний API
|
|
30
|
+
|
|
31
|
+
createAcpSession — Запускає підпроцес агента ACP та виконує ініціалізацію з'єднання, повертаючи ідентифікатор сесії.
|
|
32
|
+
runAcpTurn — Виконує один раунд взаємодії з агентом у вже ініційованій сесії, передаючи оновлення сесії.
|
|
33
|
+
cancelAcpSession — Змушує агента припинити поточний раунд взаємодії.
|
|
34
|
+
onAcpToolCall — Підписується на виклик інструменту, який агент ініціював через MCP-міст, очікуючи на результат.
|
|
35
|
+
respondAcpToolCall — Надає відповідь на очікуваний виклик інструменту, який був ініційований агентом.
|
|
36
|
+
onAcpPermissionRequest — Підписується на запит дозволу від агента (наприклад, на виконання команд або редагування файлів).
|
|
37
|
+
respondAcpPermission — Приймає рішення щодо запиту дозволу, ініційованого агентом.
|
|
38
|
+
startAcpMcpBridge — Реєструє каталог інструментів цього застосунку в доменному MCP-міст і запускає його.
|
|
39
|
+
acpConfig — Зчитує за замовчуванням тип агента для цієї машини з змінної середовища. Доступні дані можна переглянути за адресою http://127.0.0.1:54321/.
|
|
40
|
+
|
|
41
|
+
## Гарантії поведінки
|
|
42
|
+
|
|
43
|
+
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/acp-kit.js
|
|
4
|
+
crc: caab4cf6
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# acp-kit.js
|
|
11
|
+
|
|
12
|
+
## Огляд
|
|
13
|
+
|
|
14
|
+
Модуль ініціалізує агента та керує життєвим циклом його запитів. Функція `createAcpAgentKit` створює агента на основі заданих компонентів. Модуль дозволяє розпочинати нові запити, продовжувати активні сесії або вирішувати відкладені питання, такі як виклики інструментів чи запити на дозвіл.
|
|
15
|
+
|
|
16
|
+
## Поведінка
|
|
17
|
+
|
|
18
|
+
1. Викликати createAcpAgentKit, надаючи каталог інструментів, сховище журналу та, за бажанням, транспортний механізм, набір рівнів акторів та залежності.
|
|
19
|
+
2. При виклику createAcpAgentKit, якщо надано транспортний механізм, створюється механізм диспетчеризації.
|
|
20
|
+
3. Викликати request, щоб розпочати новий запит:
|
|
21
|
+
а. Забезпечити активне прослуховування подій.
|
|
22
|
+
б. Створити новий запис у журналі з інформацією про намір та актора.
|
|
23
|
+
в. Оновити запис у журналі на статус "running".
|
|
24
|
+
г. Створити сесію агента.
|
|
25
|
+
д. Встановити ключ сесії та ідентифікатор запиту як активні.
|
|
26
|
+
е. Оновити запис у журналі з метаданими сесії.
|
|
27
|
+
ж. Виконати перший хід агента, використовуючи наданий текст наміру, і зафіксувати результат у журналі.
|
|
28
|
+
4. Викликати respond, щоб продовжити активну сесію:
|
|
29
|
+
а. Перевірити наявність активної сесії.
|
|
30
|
+
б. Завантажити поточний запис із журналу.
|
|
31
|
+
в. Оновити запис у журналі на статус "running".
|
|
32
|
+
г. Встановити ідентифікатор запиту як активний.
|
|
33
|
+
г. Виконати наступний хід агента, використовуючи надане повідомлення, і зафіксувати результат у журналі.
|
|
34
|
+
5. Викликати approve, щоб вирішити відкладене схвалення:
|
|
35
|
+
а. Завантажити відповідний запис із журналу.
|
|
36
|
+
б. Перевірити, чи запис перебуває у стані "needs_approval" та має відкладене схвалення.
|
|
37
|
+
в. Якщо відкладене схвалення є MCP-виклик інструменту, викликати approveMcpToolCall:
|
|
38
|
+
а. Виконати диспетчеризацію інструменту або створити відповідь про заборону.
|
|
39
|
+
б. Надіслати відповідь агенту про результат виклику інструменту.
|
|
40
|
+
в. Оновити запис у журналі, додавши інформацію про виклик інструменту та скинувши відкладене схвалення.
|
|
41
|
+
в. Повернути результат, що вказує на статус "running".
|
|
42
|
+
г. Якщо відкладене схвалення є запит на дозвіл ACP, викликати approveAcpPermission:
|
|
43
|
+
а. Знайти відповідний варіант дозвілу або обрати перший варіант.
|
|
44
|
+
б. Надіслати відповідь агенту з обраним ідентифікатором варіанта.
|
|
45
|
+
в. Оновити запис у журналі, скинувши відкладене схвалення.
|
|
46
|
+
в. Повернути результат, що вказує на статус "running".
|
|
47
|
+
|
|
48
|
+
## Гарантії поведінки
|
|
49
|
+
|
|
50
|
+
- (специфічних машинно-виведених гарантій немає)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/agent-handler.js
|
|
4
|
+
crc: 8ef1230c
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
issues: judge:inaccurate:0.97
|
|
8
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# agent-handler.js
|
|
12
|
+
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
Модуль керує життєвим циклом агентського запиту. Він ініціює запит через `handleRequest`, підтримує діалог з користувачем через `handleRespond` та реалізує логіку схвалення через `handleApprove`.
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
handleRequest ініціює новий агентський запит, створює запис у журналі та запускає цикл агента.
|
|
20
|
+
handleRespond продовжує розмову, використовуючи попередній стан запису та нове повідомлення користувача.
|
|
21
|
+
handleApprove виконує або відхиляє заплановану деструктивну дію, якщо запис перебуває у стані очікування схвалення.
|
|
22
|
+
|
|
23
|
+
## Публічний API
|
|
24
|
+
|
|
25
|
+
handleRequest — Ініціює новий запит до агента.
|
|
26
|
+
handleRespond — Продовжує діалог, надаючи відповідь або уточнення.
|
|
27
|
+
handleApprove — Підтверджує (або відхиляє) заплановану руйнівну дію, виконуючи її з дозволу користувача.
|
|
28
|
+
|
|
29
|
+
## Гарантії поведінки
|
|
30
|
+
|
|
31
|
+
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/agent-kit.js
|
|
4
|
+
crc: 27461b4b
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# agent-kit.js
|
|
11
|
+
|
|
12
|
+
## Огляд
|
|
13
|
+
|
|
14
|
+
Цей модуль відповідає за ініціалізацію та конфігурування набору інструментів для агента. Функція `createAgentKit` створює об'єкт, що містить необхідні методи та механізми для роботи агента, забезпечуючи його доступ до інструментів та системних налаштувань.
|
|
15
|
+
|
|
16
|
+
## Поведінка
|
|
17
|
+
|
|
18
|
+
1. Викликати `createAgentKit` для створення набору інструментів агента.
|
|
19
|
+
2. Надати `createAgentKit` каталог інструментів.
|
|
20
|
+
3. За бажанням надати системний підказку, транспортний механізм, сховище журналу, рівні акторів та інструмент для заземлення.
|
|
21
|
+
4. Отримати об'єкт набору інструментів, що містить функції для диспетчеризації, класифікації, отримання маніфесту інструментів, створення запитів, відповідей та схвалення.
|
|
22
|
+
|
|
23
|
+
## Гарантії поведінки
|
|
24
|
+
|
|
25
|
+
- (специфічних машинно-виведених гарантій немає)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/dispatch.js
|
|
4
|
+
crc: 57a74200
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
issues: judge:inaccurate:0.98
|
|
8
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# dispatch.js
|
|
12
|
+
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
Модуль забезпечує валідацію вхідних даних та диспетчеризацію виконання інструментів. Функція `validateInput` перевіряє вхідні дані на відповідність визначеній схемі. Після успішної валідації функція `createDispatch` створює механізм виконання інструменту. Модуль гарантує перехоплення всіх помилок (fail-safe) та не генерує винятків назовні. Модуль не виконує операцій, що змінюють стан (не пише у ФС/БД).
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
validateInput перевіряє вхідні дані на відповідність схемі інструменту та кастомному валідатору.
|
|
20
|
+
createDispatch створює функцію, яка виконує інструмент після валідації вхідних даних, повертаючи обгортку з результатом або помилкою.
|
|
21
|
+
|
|
22
|
+
## Публічний API
|
|
23
|
+
|
|
24
|
+
validateInput — порівнює об'єкт вхідних даних зі схемою інструменту та користувацьким валідатором.
|
|
25
|
+
createDispatch — створює функцію для відправки, прив'язану до каталогу та системи транспортування.
|
|
26
|
+
|
|
27
|
+
## Гарантії поведінки
|
|
28
|
+
|
|
29
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
30
|
+
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/llm.js
|
|
4
|
+
crc: 2f379651
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
issues: judge:inaccurate:0.98
|
|
8
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# llm.js
|
|
12
|
+
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
Модуль дозволяє ініціювати сеанс чату з мовною моделлю через мережевий ендпоінт http://127.0.0.1:10240/v1. Функціонал реалізується через публічні функції `runAgent` та `createOpenAiChat`. Код виконує виклик API та керує циклом виклику інструментів у контексті агента, доки модель не надасть фінальну відповідь або не буде перевищено ліміт кроків. Робота залежить від конфігурації, описаної у `response.json`.
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
runAgent виконує цикл виклику інструментів, поки модель не надасть відповідь без виклику інструменту, або доки не буде досягнуто максимальної кількості кроків.
|
|
20
|
+
createOpenAiChat створює функцію, яка викликає мережевий ендпоінт OpenAI-сумісного API (наприклад, http://127.0.0.1:10240/v1) для отримання відповіді моделі.
|
|
21
|
+
|
|
22
|
+
## Публічний API
|
|
23
|
+
|
|
24
|
+
runAgent — Запускає цикл виклику інструментів до моменту, коли модель надає відповідь без виклику інструменту. Може використовувати новий запит або продовжувати сесію на основі існуючої історії повідомлень.
|
|
25
|
+
createOpenAiChat — Створює функцію для взаємодії з кінцевою точкою, сумісною з OpenAI (omlx).
|
|
26
|
+
|
|
27
|
+
## Гарантії поведінки
|
|
28
|
+
|
|
29
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/manifest.js
|
|
4
|
+
crc: 0db5edce
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# manifest.js
|
|
11
|
+
|
|
12
|
+
## Огляд
|
|
13
|
+
|
|
14
|
+
Модуль реалізує функції для роботи зі специфікаціями інструментів. Він перетворює специфікації інструментів у формат JSON Schema. Модуль генерує повний маніфест інструментів у форматі OpenAI та створює спрощені списки інструментів, що містять їхні імена та описи.
|
|
15
|
+
|
|
16
|
+
## Поведінка
|
|
17
|
+
|
|
18
|
+
toJsonSchema перетворює специфікацію вхідних даних інструменту на об'єкт JSON Schema.
|
|
19
|
+
toolManifest створює масив визначень інструментів у форматі OpenAI, фільтруючи їх за наданим предикатом.
|
|
20
|
+
listTools створює компактний список інструментів, що містить лише їхні імена та короткі описи.
|
|
21
|
+
|
|
22
|
+
## Публічний API
|
|
23
|
+
|
|
24
|
+
toJsonSchema — перетворює опис вхідних даних інструменту на об'єкт JSON Schema.
|
|
25
|
+
toolManifest — надає визначення інструментів для виклику функцій OpenAI, з можливістю фільтрації.
|
|
26
|
+
listTools — виводить стислий перелік доступних інструментів (назва та короткий опис).
|
|
27
|
+
|
|
28
|
+
## Гарантії поведінки
|
|
29
|
+
|
|
30
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/omlx-models.js
|
|
4
|
+
crc: 81a5dc3a
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
issues: judge:inaccurate:0.97
|
|
8
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# omlx-models.js
|
|
12
|
+
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
Модуль надає публічні механізми для взаємодії з локально завантаженими моделями. Він дозволяє отримати повний список доступних моделей та вибрати конкретну модель із цього списку. Функціонал працює в режимі, що перехоплює помилки (fail-safe), і не здійснює запису у файлову систему чи бази даних. Робота модуля залежить від конфігурацій, зокрема `response.json`.
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
listOmlxModels отримує список ідентифікаторів моделей, завантажених локальним сервером, або повертає порожній масив у разі будь-якої помилки.
|
|
20
|
+
resolveModel обирає модель з наданого списку, надаючи пріоритет обраній моделі, або повертає першу доступну модель, якщо пріоритетна відсутня.
|
|
21
|
+
|
|
22
|
+
## Публічний API
|
|
23
|
+
|
|
24
|
+
listOmlxModels — отримує список доступних моделей.
|
|
25
|
+
resolveModel — вибирає модель: обрану, якщо вона завантажена, інакше першу доступну, або порожній рядок.
|
|
26
|
+
|
|
27
|
+
## Гарантії поведінки
|
|
28
|
+
|
|
29
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
30
|
+
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/resolve-omlx-base-url.js
|
|
4
|
+
crc: 36c282c7
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
issues: judge:inaccurate:0.99
|
|
8
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# resolve-omlx-base-url.js
|
|
12
|
+
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
Модуль визначає та надає базові URL для взаємодії з серверами omlx. Він експортує константи: DIRECT_OMLX_BASE_URL="http://127.0.0.1:8000/v1" для прямого доступу та PROXY_OMLX_BASE_URL="http://127.0.0.1:8088/v1" для проксі-доступу. Модуль звертається до мережі для визначення робочого URL, перевіряючи доступність проксі-сервера. Вибір URL кешується у межах прогону. При помилках мережевого доступу модуль перехоплює їх (fail-safe) і повертає порожнє значення замість кидання винятків. Модуль є лише для читання (не виконує операцій з ФС/БД).
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
DIRECT_OMLX_BASE_URL: Надає базовий URL для прямого доступу до сервера omlx, який є http://127.0.0.1:8000/v1.
|
|
20
|
+
PROXY_OMLX_BASE_URL: Надає базовий URL для доступу через проксі-сервер omlx, який є http://127.0.0.1:8088/v1.
|
|
21
|
+
isDirectOmlxUrl: Перевіряє, чи вказаний URL є стандартним локальним сервером omlx (http://127.0.0.1:8000 або localhost:8000).
|
|
22
|
+
resolveOmlxBaseUrl: Визначає ефективний базовий URL omlx, перевіряючи доступність проксі-сервера через зондування `/health`; у разі успіху повертає URL проксі, інакше — прямий URL.
|
|
23
|
+
resolveOmlxBaseUrlCached: Визначає ефективний базовий URL omlx, використовуючи кешування для уникнення повторних зондувань протягом заданого часу життя (TTL).
|
|
24
|
+
__resetOmlxBaseUrlCache: Очищає кеш результатів зондування базового URL omlx.
|
|
25
|
+
|
|
26
|
+
## Публічний API
|
|
27
|
+
|
|
28
|
+
DIRECT_OMLX_BASE_URL — Базовий URL для прямого доступу до локального OMLX сервера, що вказує на http://127.0.0.1:8000/v1.
|
|
29
|
+
PROXY_OMLX_BASE_URL — Базовий URL для проксі-доступу до OMLX сервера, що вказує на http://127.0.0.1:8088/v1.
|
|
30
|
+
isDirectOmlxUrl — Визначає, чи є URL основним локальним сервером OMLX, який не повинен бути перенаправлений через проксі.
|
|
31
|
+
resolveOmlxBaseUrl — Перевіряє доступність проксі-сервера шляхом виконання GET-запиту до http://127.0.0.1:8088/v1; якщо відповідь успішна, використовується проксі, інакше — прямий URL.
|
|
32
|
+
resolveOmlxBaseUrlCached — Виконує перевірку доступності проксі-сервера з кешуванням, щоб уникнути повторних перевірок при кожному виклику LLM.
|
|
33
|
+
__resetOmlxBaseUrlCache — Очищає всі збережені результати перевірки доступності базового URL OMLX.
|
|
34
|
+
|
|
35
|
+
## Гарантії поведінки
|
|
36
|
+
|
|
37
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
38
|
+
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
39
|
+
- За певних помилок повертає порожнє значення (напр. `null`) замість винятку.
|
|
40
|
+
- Кешує результати в межах одного прогону.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/scope.js
|
|
4
|
+
crc: e3226974
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# scope.js
|
|
11
|
+
|
|
12
|
+
## Огляд
|
|
13
|
+
|
|
14
|
+
Модуль визначає та керує дозволами акторів на використання інструментів. Він встановлює рівні акторів за допомогою `DEFAULT_ACTOR_TIERS`, визначає доступні інструменти для кожного актора через `scopedToolNames` та надає маніфест дозволів за допомогою `scopedManifest`.
|
|
15
|
+
|
|
16
|
+
## Поведінка
|
|
17
|
+
|
|
18
|
+
DEFAULT_ACTOR_TIERS визначає максимальний рівень виконання для різних типів акторів.
|
|
19
|
+
classify визначає, чи дозволено актору викликати інструмент, чи потрібне схвалення, чи заборонено.
|
|
20
|
+
scopedManifest повертає перелік інструментів, які актор може виконати або для яких потрібне схвалення.
|
|
21
|
+
scopedToolNames повертає список назв інструментів, які актор бачить.
|
|
22
|
+
|
|
23
|
+
## Публічний API
|
|
24
|
+
|
|
25
|
+
DEFAULT_ACTOR_TIERS — Визначає рівні доступу для акторів.
|
|
26
|
+
classify — Визначає, до якого актора належить виклик інструменту.
|
|
27
|
+
scopedManifest — Перелік інструментів, доступних актору для виконання або запиту дозволу.
|
|
28
|
+
scopedToolNames — Список назв інструментів, видимих актору.
|
|
29
|
+
|
|
30
|
+
## Гарантії поведінки
|
|
31
|
+
|
|
32
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
docgen:
|
|
3
|
+
source: npm/src/core/tools.js
|
|
4
|
+
crc: 9fa4e875
|
|
5
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
6
|
+
score: 100
|
|
7
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# tools.js
|
|
11
|
+
|
|
12
|
+
## Огляд
|
|
13
|
+
|
|
14
|
+
Модуль сканує заданий каталог для пошуку визначень інструментів. Він встановлює наявність інструменту за його ім'ям і повертає його визначення або `null`, якщо інструмент не знайдено.
|
|
15
|
+
|
|
16
|
+
## Поведінка
|
|
17
|
+
|
|
18
|
+
1. Визначає, чи існує інструмент у наданому каталозі, порівнюючи його ім'я з вказаним.
|
|
19
|
+
2. Повертає визначення інструмента, якщо він знайдений.
|
|
20
|
+
3. Повертає `null`, якщо інструмент не знайдено в каталозі.
|
|
21
|
+
|
|
22
|
+
## Публічний API
|
|
23
|
+
|
|
24
|
+
getTool — знаходить інструмент за його назвою у каталозі.
|
|
25
|
+
|
|
26
|
+
## Гарантії поведінки
|
|
27
|
+
|
|
28
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|