@7n/tauri-components 0.10.1 → 0.11.1
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/CHANGELOG.md +12 -0
- package/package.json +1 -4
- package/src/components/AgentDialog.vue +21 -46
- package/src/components/AuditDialog.vue +9 -17
- package/src/components/BaseDialog.vue +2 -6
- package/src/components/DialogActions.vue +2 -3
- package/src/components/RequestView.vue +2 -3
- package/src/components/StatePill.vue +1 -1
- package/src/components/docs/AgentDialog.md +4 -4
- package/src/components/docs/AuditDialog.md +4 -4
- package/src/components/docs/BaseDialog.md +4 -4
- package/src/components/docs/DialogActions.md +4 -4
- package/src/components/docs/RequestView.md +4 -4
- package/src/components/docs/StatePill.md +4 -4
- package/src/components/docs/index.md +4 -4
- package/src/components/docs/status.md +4 -4
- package/src/components/index.js +2 -2
- package/src/components/status.js +1 -1
- package/src/core/acp-agent-presets.js +2 -2
- package/src/core/acp-agent.js +21 -15
- package/src/core/acp-kit.js +79 -30
- package/src/core/dispatch.js +3 -3
- package/src/core/docs/acp-agent-presets.md +4 -4
- package/src/core/docs/acp-agent.md +4 -4
- package/src/core/docs/acp-kit.md +4 -4
- package/src/core/docs/dispatch.md +4 -4
- package/src/core/docs/manifest.md +4 -4
- package/src/core/manifest.js +10 -8
- package/src/docs/index.md +4 -4
- package/src/index.js +3 -8
- package/src/testing/docs/quasar.md +4 -4
- package/src/testing/quasar.js +2 -2
- package/src/vue/docs/index.md +4 -4
- package/src/vue/docs/journal-store-tauri.md +4 -4
- package/src/vue/docs/use-acp-agent.md +4 -4
- package/src/vue/docs/use-updater.md +4 -4
- package/src/vue/index.js +4 -6
- package/src/vue/journal-store-tauri.js +2 -2
- package/src/vue/use-acp-agent.js +22 -14
- package/src/vue/use-updater.js +4 -6
- package/types/core/dispatch.d.ts +5 -2
- package/types/core/manifest.d.ts +14 -9
- package/types/core/scope.d.ts +24 -11
- package/types/core/tools.d.ts +1 -1
- package/types/index.d.ts +4 -9
- package/src/core/agent-handler.js +0 -171
- package/src/core/agent-kit.js +0 -43
- package/src/core/docs/agent-handler.md +0 -31
- package/src/core/docs/agent-kit.md +0 -25
- package/src/core/docs/llm.md +0 -29
- package/src/core/docs/omlx-models.md +0 -30
- package/src/core/docs/resolve-omlx-base-url.md +0 -40
- package/src/core/llm.js +0 -90
- package/src/core/omlx-models.js +0 -34
- package/src/core/resolve-omlx-base-url.js +0 -84
- package/src/vue/docs/use-agent.md +0 -29
- package/src/vue/docs/use-omlx.md +0 -30
- package/src/vue/use-agent.js +0 -60
- package/src/vue/use-omlx.js +0 -102
- package/types/core/agent-handler.d.ts +0 -43
- package/types/core/agent-kit.d.ts +0 -30
- package/types/core/llm.d.ts +0 -52
- package/types/core/omlx-models.d.ts +0 -17
- package/types/core/resolve-omlx-base-url.d.ts +0 -42
package/src/vue/use-updater.js
CHANGED
|
@@ -45,14 +45,13 @@ export function useUpdater() {
|
|
|
45
45
|
message: `Версія ${update.version} готова. Встановити зараз?`,
|
|
46
46
|
cancel: { label: 'Пізніше', flat: true },
|
|
47
47
|
ok: { label: 'Встановити', color: 'primary' },
|
|
48
|
-
persistent: true
|
|
48
|
+
persistent: true
|
|
49
49
|
})
|
|
50
50
|
.onOk(() => installAndRelaunch(update))
|
|
51
51
|
.onCancel(() => {
|
|
52
52
|
busy = false
|
|
53
53
|
})
|
|
54
|
-
}
|
|
55
|
-
catch (error) {
|
|
54
|
+
} catch (error) {
|
|
56
55
|
// No network, or the updater isn't configured/permitted — don't bother
|
|
57
56
|
// the user, but leave a trace for diagnosis.
|
|
58
57
|
console.error('[updater] check failed:', error)
|
|
@@ -94,10 +93,9 @@ export function useUpdater() {
|
|
|
94
93
|
message: `Перезапустити зараз, щоб перейти на версію ${update.version}?`,
|
|
95
94
|
cancel: { label: 'Пізніше', flat: true },
|
|
96
95
|
ok: { label: 'Перезапустити', color: 'primary' },
|
|
97
|
-
persistent: true
|
|
96
|
+
persistent: true
|
|
98
97
|
}).onOk(() => relaunch())
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
98
|
+
} catch (error) {
|
|
101
99
|
dismiss()
|
|
102
100
|
busy = false
|
|
103
101
|
console.error('[updater] install failed:', error)
|
package/types/core/dispatch.d.ts
CHANGED
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* @param {object} [input] candidate input
|
|
5
5
|
* @returns {string|null} error message, or null when valid
|
|
6
6
|
*/
|
|
7
|
-
export function validateInput(tool: object, input?: object): string | null
|
|
7
|
+
export function validateInput(tool: object, input?: object): string | null
|
|
8
8
|
/**
|
|
9
9
|
* Build a dispatch function bound to a catalog and a transport.
|
|
10
10
|
* @param {object[]} catalog tool definitions
|
|
11
11
|
* @param {(tool: object, input: object) => unknown} transport runs the tool's backend call
|
|
12
12
|
* @returns {(name: string, input?: object) => Promise<object>} dispatch returning an envelope
|
|
13
13
|
*/
|
|
14
|
-
export function createDispatch(
|
|
14
|
+
export function createDispatch(
|
|
15
|
+
catalog: object[],
|
|
16
|
+
transport: (tool: object, input: object) => unknown
|
|
17
|
+
): (name: string, input?: object) => Promise<object>
|
package/types/core/manifest.d.ts
CHANGED
|
@@ -3,24 +3,29 @@
|
|
|
3
3
|
* @param {Record<string, {type: string, required?: boolean, description?: string}>} input tool input spec
|
|
4
4
|
* @returns {object} JSON Schema for the parameters object
|
|
5
5
|
*/
|
|
6
|
-
export function toJsonSchema(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
export function toJsonSchema(
|
|
7
|
+
input: Record<
|
|
8
|
+
string,
|
|
9
|
+
{
|
|
10
|
+
type: string
|
|
11
|
+
required?: boolean
|
|
12
|
+
description?: string
|
|
13
|
+
}
|
|
14
|
+
>
|
|
15
|
+
): object
|
|
11
16
|
/**
|
|
12
17
|
* OpenAI function-calling tool definitions, optionally filtered (e.g. by scope).
|
|
13
18
|
* @param {object[]} catalog tool definitions
|
|
14
19
|
* @param {(tool: object) => boolean} [allow] predicate; default includes all tools
|
|
15
20
|
* @returns {object[]} OpenAI `tools` array
|
|
16
21
|
*/
|
|
17
|
-
export function toolManifest(catalog: object[], allow?: (tool: object) => boolean): object[]
|
|
22
|
+
export function toolManifest(catalog: object[], allow?: (tool: object) => boolean): object[]
|
|
18
23
|
/**
|
|
19
24
|
* Compact catalog listing (name + summary).
|
|
20
25
|
* @param {object[]} catalog tool definitions
|
|
21
26
|
* @returns {{name: string, summary: string}[]} tool list
|
|
22
27
|
*/
|
|
23
28
|
export function listTools(catalog: object[]): {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}[]
|
|
29
|
+
name: string
|
|
30
|
+
summary: string
|
|
31
|
+
}[]
|
package/types/core/scope.d.ts
CHANGED
|
@@ -6,9 +6,14 @@
|
|
|
6
6
|
* @param {string} toolName tool name
|
|
7
7
|
* @returns {'allow'|'approval'|'deny'} decision
|
|
8
8
|
*/
|
|
9
|
-
export function classify(
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export function classify(
|
|
10
|
+
catalog: object[],
|
|
11
|
+
actorTiers: Record<string, number> | undefined,
|
|
12
|
+
actor: {
|
|
13
|
+
kind?: string
|
|
14
|
+
},
|
|
15
|
+
toolName: string
|
|
16
|
+
): 'allow' | 'approval' | 'deny'
|
|
12
17
|
/**
|
|
13
18
|
* LLM tool manifest visible to the actor (everything it may run OR request approval for).
|
|
14
19
|
* @param {object[]} catalog tool definitions
|
|
@@ -16,9 +21,13 @@ export function classify(catalog: object[], actorTiers: Record<string, number> |
|
|
|
16
21
|
* @param {{ kind?: string }} actor caller identity
|
|
17
22
|
* @returns {object[]} OpenAI tools array
|
|
18
23
|
*/
|
|
19
|
-
export function scopedManifest(
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
export function scopedManifest(
|
|
25
|
+
catalog: object[],
|
|
26
|
+
actorTiers: Record<string, number> | undefined,
|
|
27
|
+
actor: {
|
|
28
|
+
kind?: string
|
|
29
|
+
}
|
|
30
|
+
): object[]
|
|
22
31
|
/**
|
|
23
32
|
* Tool names visible to the actor.
|
|
24
33
|
* @param {object[]} catalog tool definitions
|
|
@@ -26,10 +35,14 @@ export function scopedManifest(catalog: object[], actorTiers: Record<string, num
|
|
|
26
35
|
* @param {{ kind?: string }} actor caller identity
|
|
27
36
|
* @returns {string[]} visible tool names
|
|
28
37
|
*/
|
|
29
|
-
export function scopedToolNames(
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
export function scopedToolNames(
|
|
39
|
+
catalog: object[],
|
|
40
|
+
actorTiers: Record<string, number> | undefined,
|
|
41
|
+
actor: {
|
|
42
|
+
kind?: string
|
|
43
|
+
}
|
|
44
|
+
): string[]
|
|
32
45
|
export namespace DEFAULT_ACTOR_TIERS {
|
|
33
|
-
|
|
34
|
-
|
|
46
|
+
let human: number
|
|
47
|
+
let agent: number
|
|
35
48
|
}
|
package/types/core/tools.d.ts
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export { createOpenAiChat, runAgent } from "./core/llm.js";
|
|
6
|
-
export { listOmlxModels, resolveModel } from "./core/omlx-models.js";
|
|
7
|
-
export { DIRECT_OMLX_BASE_URL, isDirectOmlxUrl, PROXY_OMLX_BASE_URL, resolveOmlxBaseUrl, resolveOmlxBaseUrlCached } from "./core/resolve-omlx-base-url.js";
|
|
8
|
-
export { listTools, toJsonSchema, toolManifest } from "./core/manifest.js";
|
|
9
|
-
export { classify, DEFAULT_ACTOR_TIERS, scopedManifest, scopedToolNames } from "./core/scope.js";
|
|
1
|
+
export { getTool } from './core/tools.js'
|
|
2
|
+
export { createDispatch, validateInput } from './core/dispatch.js'
|
|
3
|
+
export { listTools, toJsonSchema, toolManifest } from './core/manifest.js'
|
|
4
|
+
export { classify, DEFAULT_ACTOR_TIERS, scopedManifest, scopedToolNames } from './core/scope.js'
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { runAgent } from './llm.js'
|
|
2
|
-
|
|
3
|
-
// Agent-gateway handlers — start / resume / approve the agent loop on behalf of a
|
|
4
|
-
// caller (human via UI or agent via MCP). They own the journal lifecycle and
|
|
5
|
-
// return a structured result contract.
|
|
6
|
-
//
|
|
7
|
-
// All collaborators are injected (no module-level singletons): `dispatch`,
|
|
8
|
-
// `journal`, the scoped `tools` manifest, the `gate` decision fn, `buildSystem`
|
|
9
|
-
// (turns optional grounding context into a system prompt) and `grounding` (an
|
|
10
|
-
// optional read tool whose output grounds the prompt). createAgentKit wires
|
|
11
|
-
// these from an app catalog; tests pass fakes.
|
|
12
|
-
//
|
|
13
|
-
// Trust: destructive tool calls from an agent pause as `needs_approval` (the
|
|
14
|
-
// loop never executes them); a human approves later via handleApprove.
|
|
15
|
-
|
|
16
|
-
const QUESTION_RE = /\?\s*$/
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param {string} text candidate text
|
|
20
|
-
* @returns {boolean} true when text ends with a question mark
|
|
21
|
-
*/
|
|
22
|
-
function isQuestion(text) {
|
|
23
|
-
return typeof text === 'string' && QUESTION_RE.test(text.trim())
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Derive the structured result fields from a runAgent result.
|
|
28
|
-
* @param {object} result runAgent result
|
|
29
|
-
* @returns {{ status: string, summary: string|null, question: string|null, pendingApproval: object|null }} fields
|
|
30
|
-
*/
|
|
31
|
-
function finalize(result) {
|
|
32
|
-
const question = isQuestion(result.content) ? result.content : null
|
|
33
|
-
let status = 'done'
|
|
34
|
-
if (result.stopped === 'needs_approval') status = 'needs_approval'
|
|
35
|
-
else if (result.stopped === 'max_steps') status = 'partial'
|
|
36
|
-
else if (question) status = 'needs_clarification'
|
|
37
|
-
return {
|
|
38
|
-
status,
|
|
39
|
-
summary: question ? null : (result.content || null),
|
|
40
|
-
question,
|
|
41
|
-
pendingApproval: result.pendingApproval ?? null,
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Run the loop (fresh or resumed), persist to the journal, return the envelope.
|
|
47
|
-
* @param {{ requestId: string, runArgs: object, baseActions: object[], journal: object }} ctx run context
|
|
48
|
-
* @returns {Promise<object>} structured result envelope
|
|
49
|
-
*/
|
|
50
|
-
async function runAndJournal({ requestId, runArgs, baseActions, journal }) {
|
|
51
|
-
let result
|
|
52
|
-
try {
|
|
53
|
-
result = await runAgent(runArgs)
|
|
54
|
-
}
|
|
55
|
-
catch (error) {
|
|
56
|
-
await journal.update(requestId, { status: 'failed', error: String(error?.message ?? error) })
|
|
57
|
-
return { requestId, status: 'failed', summary: null, actions: baseActions, question: null, pendingApproval: null }
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const fields = finalize(result)
|
|
61
|
-
const actions = [...baseActions, ...result.trace]
|
|
62
|
-
await journal.update(requestId, { ...fields, messages: result.messages, actions })
|
|
63
|
-
return { requestId, ...fields, actions }
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Fetch optional grounding context via a read tool; {} when not configured / on failure.
|
|
68
|
-
* @param {Function} dispatch tool dispatcher
|
|
69
|
-
* @param {{ tool: string, key?: string, fallback?: unknown }} [grounding] grounding config
|
|
70
|
-
* @returns {Promise<object>} context object keyed by grounding.key (default "grounding")
|
|
71
|
-
*/
|
|
72
|
-
async function groundingContext(dispatch, grounding) {
|
|
73
|
-
if (!grounding?.tool) return {}
|
|
74
|
-
const key = grounding.key ?? 'grounding'
|
|
75
|
-
const fallback = grounding.fallback ?? []
|
|
76
|
-
try {
|
|
77
|
-
const res = await dispatch(grounding.tool, {})
|
|
78
|
-
return { [key]: res?.ok ? res.output : fallback }
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
return { [key]: fallback }
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Start a new agent request.
|
|
87
|
-
* @param {{ intent: string, actor: object, chat: Function, dispatch: Function, journal: object, tools: object[], gate: Function, buildSystem?: Function, grounding?: object }} opts request parameters
|
|
88
|
-
* @returns {Promise<object>} structured result envelope
|
|
89
|
-
*/
|
|
90
|
-
export async function handleRequest({ intent, actor, chat, dispatch, journal, tools, gate, buildSystem, grounding }) {
|
|
91
|
-
const id = await journal.create({ intent, actor })
|
|
92
|
-
await journal.update(id, { status: 'running' })
|
|
93
|
-
const ctx = await groundingContext(dispatch, grounding)
|
|
94
|
-
const system = buildSystem ? buildSystem(ctx) : undefined
|
|
95
|
-
return runAndJournal({
|
|
96
|
-
requestId: id,
|
|
97
|
-
baseActions: [],
|
|
98
|
-
journal,
|
|
99
|
-
runArgs: { system, prompt: intent, chat, dispatch, tools, gate },
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Resume a conversation with a follow-up / clarification answer.
|
|
105
|
-
* @param {{ requestId: string, message: string, actor: object, chat: Function, dispatch: Function, journal: object, tools: object[], gate: Function }} opts resume parameters
|
|
106
|
-
* @returns {Promise<object>} updated result envelope
|
|
107
|
-
*/
|
|
108
|
-
export async function handleRespond({ requestId, message, chat, dispatch, journal, tools, gate }) {
|
|
109
|
-
let record
|
|
110
|
-
try {
|
|
111
|
-
record = await journal.load(requestId)
|
|
112
|
-
}
|
|
113
|
-
catch {
|
|
114
|
-
return { requestId, status: 'failed', summary: null, actions: [], question: 'Request not found.', pendingApproval: null }
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (record.status === 'running' || !Array.isArray(record.messages) || record.messages.length === 0) {
|
|
118
|
-
return { requestId, status: record.status, summary: record.summary, actions: record.actions, question: null, pendingApproval: record.pendingApproval ?? null }
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
await journal.update(requestId, { status: 'running' })
|
|
122
|
-
return runAndJournal({
|
|
123
|
-
requestId,
|
|
124
|
-
baseActions: record.actions ?? [],
|
|
125
|
-
journal,
|
|
126
|
-
runArgs: { messages: [...record.messages, { role: 'user', content: message }], chat, dispatch, tools, gate },
|
|
127
|
-
})
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Approve (or reject) a pending destructive action. Executes with the approver's
|
|
132
|
-
* (human) authority via the injected dispatch — no gate.
|
|
133
|
-
* @param {{ requestId: string, approve: boolean, dispatch: Function, journal: object }} opts approval parameters
|
|
134
|
-
* @returns {Promise<object>} updated result envelope
|
|
135
|
-
*/
|
|
136
|
-
export async function handleApprove({ requestId, approve, dispatch, journal }) {
|
|
137
|
-
let record
|
|
138
|
-
try {
|
|
139
|
-
record = await journal.load(requestId)
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
return { requestId, status: 'failed', summary: null, actions: [], question: 'Request not found.', pendingApproval: null }
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (record.status !== 'needs_approval' || !record.pendingApproval) {
|
|
146
|
-
return { requestId, status: record.status, summary: record.summary, actions: record.actions ?? [], question: null, pendingApproval: null }
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (!approve) {
|
|
150
|
-
const fields = { status: 'rejected', summary: 'Rejected by human.', pendingApproval: null }
|
|
151
|
-
await journal.update(requestId, fields)
|
|
152
|
-
return { requestId, ...fields, actions: record.actions ?? [], question: null }
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const { tool, input } = record.pendingApproval
|
|
156
|
-
await journal.update(requestId, { status: 'running' })
|
|
157
|
-
const envelope = await dispatch(tool, input)
|
|
158
|
-
const actions = [...(record.actions ?? []), { tool, input, envelope }]
|
|
159
|
-
|
|
160
|
-
if (!envelope.ok) {
|
|
161
|
-
// Execution failed (e.g. transient) — stay needs_approval so the human can
|
|
162
|
-
// retry after fixing; keep pendingApproval, record the error and the attempt.
|
|
163
|
-
const error = envelope.error?.message ?? 'execution failed'
|
|
164
|
-
await journal.update(requestId, { status: 'needs_approval', actions, error })
|
|
165
|
-
return { requestId, status: 'needs_approval', summary: null, actions, error, question: null, pendingApproval: record.pendingApproval }
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const summary = `Approved: ${tool} executed.`
|
|
169
|
-
await journal.update(requestId, { status: 'done', actions, summary, error: null, pendingApproval: null })
|
|
170
|
-
return { requestId, status: 'done', summary, actions, question: null, pendingApproval: null }
|
|
171
|
-
}
|
package/src/core/agent-kit.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { handleApprove, handleRequest, handleRespond } from './agent-handler.js'
|
|
2
|
-
import { createDispatch } from './dispatch.js'
|
|
3
|
-
import { toolManifest } from './manifest.js'
|
|
4
|
-
import { classify, DEFAULT_ACTOR_TIERS, scopedManifest } from './scope.js'
|
|
5
|
-
|
|
6
|
-
// createAgentKit binds the generic agent machinery to ONE app's tool catalog.
|
|
7
|
-
// It is the single integration seam: an app supplies its catalog, a domain
|
|
8
|
-
// system prompt, a transport (Tauri invoke / CLI spawn / fetch), a journal store
|
|
9
|
-
// and optional grounding, and gets back request/respond/approve plus the derived
|
|
10
|
-
// manifest + scope helpers — all pre-bound, so callers never re-thread the
|
|
11
|
-
// catalog. The `chat` fn stays per-call (its config can change between requests).
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param {object} config kit configuration
|
|
15
|
-
* @param {object[]} config.catalog tool definitions (required)
|
|
16
|
-
* @param {string|((ctx: object) => string)} [config.systemPrompt] domain system prompt (or builder from grounding ctx)
|
|
17
|
-
* @param {(tool: object, input: object) => unknown} [config.transport] backend runner; omit to build the kit without dispatch (manifest/scope only)
|
|
18
|
-
* @param {object} [config.journal] journal store { create, load, update, list }
|
|
19
|
-
* @param {Record<string, number>} [config.actorTiers] max executable tier rank per actor kind
|
|
20
|
-
* @param {{ tool: string, key?: string, fallback?: unknown }} [config.grounding] optional read tool to ground the prompt
|
|
21
|
-
* @returns {{ dispatch: Function|null, classify: Function, scopedManifest: Function, toolManifest: Function, request: Function, respond: Function, approve: Function }} bound kit
|
|
22
|
-
*/
|
|
23
|
-
export function createAgentKit({ catalog, systemPrompt = '', transport, journal, actorTiers = DEFAULT_ACTOR_TIERS, grounding } = {}) {
|
|
24
|
-
if (!Array.isArray(catalog)) throw new Error('createAgentKit: catalog (array) is required')
|
|
25
|
-
|
|
26
|
-
const dispatch = transport ? createDispatch(catalog, transport) : null
|
|
27
|
-
const buildSystem = typeof systemPrompt === 'function' ? systemPrompt : () => systemPrompt
|
|
28
|
-
const toolsFor = actor => scopedManifest(catalog, actorTiers, actor)
|
|
29
|
-
const gateFor = actor => name => classify(catalog, actorTiers, actor, name)
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
dispatch,
|
|
33
|
-
classify: (actor, name) => classify(catalog, actorTiers, actor, name),
|
|
34
|
-
scopedManifest: actor => toolsFor(actor),
|
|
35
|
-
toolManifest: allow => toolManifest(catalog, allow),
|
|
36
|
-
request: ({ intent, actor, chat }) =>
|
|
37
|
-
handleRequest({ intent, actor, chat, dispatch, journal, tools: toolsFor(actor), gate: gateFor(actor), buildSystem, grounding }),
|
|
38
|
-
respond: ({ requestId, message, actor, chat }) =>
|
|
39
|
-
handleRespond({ requestId, message, actor, chat, dispatch, journal, tools: toolsFor(actor), gate: gateFor(actor) }),
|
|
40
|
-
approve: ({ requestId, approve }) =>
|
|
41
|
-
handleApprove({ requestId, approve, dispatch, journal }),
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
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).
|
|
@@ -1,25 +0,0 @@
|
|
|
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
|
-
- (специфічних машинно-виведених гарантій немає)
|
package/src/core/docs/llm.md
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
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: не виконує операцій запису (ФС/БД).
|
|
@@ -1,30 +0,0 @@
|
|
|
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).
|
|
@@ -1,40 +0,0 @@
|
|
|
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
|
-
- Кешує результати в межах одного прогону.
|
package/src/core/llm.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
// The tool-calling loop and an OpenAI-compatible chat adapter. Both are
|
|
2
|
-
// stateless and domain-agnostic: the system prompt and tool manifest are passed
|
|
3
|
-
// in by the caller (an app builds them from its catalog — see agent-kit.js).
|
|
4
|
-
|
|
5
|
-
const DEFAULT_SYSTEM = 'You are a tool-using assistant. Call one tool at a time and wait for its result. If the request is ambiguous, ask a clarifying question with no tool call. When done, reply with a plain-text summary and no tool call.'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Run the tool-calling loop until the model answers without a tool call.
|
|
9
|
-
* Accepts either a fresh prompt or an existing messages[] for sessional resume.
|
|
10
|
-
* @param {object} params loop parameters
|
|
11
|
-
* @param {string} [params.prompt] user request (fresh start)
|
|
12
|
-
* @param {object[]} [params.messages] existing conversation to resume (takes priority over prompt)
|
|
13
|
-
* @param {(name: string, input: object) => Promise<object>} params.dispatch tool dispatcher returning an envelope
|
|
14
|
-
* @param {(req: {messages: object[], tools: object[]}) => Promise<object>} params.chat model call returning an assistant message
|
|
15
|
-
* @param {number} [params.maxSteps] safety cap on loop iterations
|
|
16
|
-
* @param {string} [params.system] system prompt (only used when building fresh from prompt)
|
|
17
|
-
* @param {object[]} [params.tools] LLM tool manifest (pass a scoped manifest to restrict)
|
|
18
|
-
* @param {(name: string) => 'allow'|'approval'|'deny'} [params.gate] per-call decision (default: allow)
|
|
19
|
-
* @returns {Promise<{content: string, steps: number, trace: object[], messages: object[], stopped?: string, pendingApproval?: object}>} loop result
|
|
20
|
-
*/
|
|
21
|
-
export async function runAgent({ prompt, messages: initialMessages, dispatch, chat, maxSteps = 6, system = DEFAULT_SYSTEM, tools = [], gate = () => 'allow' }) {
|
|
22
|
-
const messages = initialMessages
|
|
23
|
-
? [...initialMessages]
|
|
24
|
-
: [
|
|
25
|
-
{ role: 'system', content: system },
|
|
26
|
-
{ role: 'user', content: prompt },
|
|
27
|
-
]
|
|
28
|
-
const trace = []
|
|
29
|
-
|
|
30
|
-
for (let step = 0; step < maxSteps; step++) {
|
|
31
|
-
const reply = await chat({ messages, tools })
|
|
32
|
-
messages.push(reply)
|
|
33
|
-
|
|
34
|
-
const calls = reply.tool_calls ?? []
|
|
35
|
-
if (calls.length === 0) {
|
|
36
|
-
return { content: reply.content ?? '', steps: step + 1, trace, messages }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
for (const call of calls) {
|
|
40
|
-
let input = {}
|
|
41
|
-
try {
|
|
42
|
-
input = call.function.arguments ? JSON.parse(call.function.arguments) : {}
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
// leave input empty — dispatch's schema validation reports the problem
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const decision = gate(call.function.name)
|
|
49
|
-
if (decision === 'approval') {
|
|
50
|
-
// Destructive request from a non-human: pause for human approval.
|
|
51
|
-
return { content: reply.content ?? '', steps: step + 1, trace, messages, stopped: 'needs_approval', pendingApproval: { tool: call.function.name, input } }
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const envelope = decision === 'deny'
|
|
55
|
-
? { ok: false, error: { code: 'forbidden', message: `Tool "${call.function.name}" is not allowed.` } }
|
|
56
|
-
: await dispatch(call.function.name, input)
|
|
57
|
-
trace.push({ tool: call.function.name, input, envelope })
|
|
58
|
-
messages.push({ role: 'tool', tool_call_id: call.id, content: JSON.stringify(envelope) })
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return { content: '', steps: maxSteps, trace, messages, stopped: 'max_steps' }
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Build a `chat` function that calls an OpenAI-compatible endpoint (omlx).
|
|
67
|
-
* @param {object} params config
|
|
68
|
-
* @param {string} params.baseUrl base URL incl. /v1 (e.g. http://127.0.0.1:10240/v1)
|
|
69
|
-
* @param {string} params.model served model id
|
|
70
|
-
* @param {string} [params.apiKey] optional bearer token
|
|
71
|
-
* @param {typeof fetch} [params.fetchFn] fetch implementation (injectable for tests / tauri-http)
|
|
72
|
-
* @returns {(req: {messages: object[], tools: object[]}) => Promise<object>} chat function
|
|
73
|
-
*/
|
|
74
|
-
export function createOpenAiChat({ baseUrl, model, apiKey, fetchFn = fetch }) {
|
|
75
|
-
return async function chat({ messages, tools }) {
|
|
76
|
-
const response = await fetchFn(`${baseUrl}/chat/completions`, {
|
|
77
|
-
method: 'POST',
|
|
78
|
-
headers: {
|
|
79
|
-
'content-type': 'application/json',
|
|
80
|
-
...(apiKey ? { authorization: `Bearer ${apiKey}` } : {}),
|
|
81
|
-
},
|
|
82
|
-
body: JSON.stringify({ model, messages, tools, tool_choice: 'auto' }),
|
|
83
|
-
})
|
|
84
|
-
if (!response.ok) {
|
|
85
|
-
throw new Error(`omlx ${response.status}: ${await response.text()}`)
|
|
86
|
-
}
|
|
87
|
-
const data = await response.json()
|
|
88
|
-
return data.choices[0].message
|
|
89
|
-
}
|
|
90
|
-
}
|