@kafca/agentdock 0.1.41 → 0.1.43
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/README.md +10 -0
- package/dist/renderer/assets/{Badge-BX3RC8l6.js → Badge-CbG6yRSm.js} +1 -1
- package/dist/renderer/assets/{Chat-DJwIciel.js → Chat-BvNNWGGX.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-DfGbRR0S.js → ChatMarkdown-Ct-PvJB8.js} +1 -1
- package/dist/renderer/assets/{Config-2x2RDL3j.js → Config-lQX2qVVV.js} +2 -2
- package/dist/renderer/assets/CronList-Dj_3muVG.js +1 -0
- package/dist/renderer/assets/{Dashboard-2Wcx_bvJ.js → Dashboard-eh_RhGYb.js} +2 -2
- package/dist/renderer/assets/{EmptyState-DoCpF2tn.js → EmptyState-Bn2Qh14U.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-CBRu2bXX.js → KnowledgeDetail-Bsz6Ou41.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-CItdlDVR.js → KnowledgeHome-Cgj4XFXn.js} +2 -2
- package/dist/renderer/assets/{Logs-Cd_7ZOXc.js → Logs-Dp-NF6GN.js} +1 -1
- package/dist/renderer/assets/{Modal-B4eOiBsB.js → Modal-B6YPPBN6.js} +1 -1
- package/dist/renderer/assets/MonitorList-xEZWg460.js +1 -0
- package/dist/renderer/assets/{Page-C5VH4D9U.js → Page-Bn7RjGOS.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-D_DA--IP.js → ProjectDetail-Cv_jIE61.js} +2 -2
- package/dist/renderer/assets/{ProjectList-CtCXJ50u.js → ProjectList-BDk5_gqY.js} +1 -1
- package/dist/renderer/assets/{Select-B6E68LcN.js → Select-xshfMIEQ.js} +1 -1
- package/dist/renderer/assets/SessionChat-BkHy90z3.js +1 -0
- package/dist/renderer/assets/{SessionList-Do-5-Xx6.js → SessionList-BZyXT92L.js} +1 -1
- package/dist/renderer/assets/{ThreadChat-B1tEtE3V.js → ThreadChat-DUOIyXrS.js} +7 -7
- package/dist/renderer/assets/{Workspace-BlhS2RFw.js → Workspace-Dl80fNEC.js} +1 -1
- package/dist/renderer/assets/{arrow-left-DF1_F9Pk.js → arrow-left-C54ZI-AS.js} +1 -1
- package/dist/renderer/assets/{book-open-DxRTGpWO.js → book-open-Dl7GO0zn.js} +1 -1
- package/dist/renderer/assets/{check-BAqPPYkf.js → check-CiqgtrOL.js} +1 -1
- package/dist/renderer/assets/{chevron-down-DIZZgSb3.js → chevron-down-DTL2OuVh.js} +1 -1
- package/dist/renderer/assets/{circle-B5raL_XK.js → circle-DaVKfa3P.js} +1 -1
- package/dist/renderer/assets/desktop-C6q6wBae.js +5 -0
- package/dist/renderer/assets/desktop-jaAiayNB.js +1 -0
- package/dist/renderer/assets/en-D2SkCrhG.js +1 -0
- package/dist/renderer/assets/{funnel-BPjLpVSB.js → funnel-CrmnLMJI.js} +1 -1
- package/dist/renderer/assets/{heart-D2M1xN1N.js → heart-BMfQI7y_.js} +1 -1
- package/dist/renderer/assets/{index-Cx71F_Lz.js → index-HPNb1zfx.js} +39 -34
- package/dist/renderer/assets/{index-BijJAYmo.js → index-nreiKY1f.js} +3 -3
- package/dist/renderer/assets/{pencil-DlDr8Mmp.js → pencil-wTQ4l465.js} +1 -1
- package/dist/renderer/assets/{play-BOEG_mY8.js → play-BK--MXmw.js} +1 -1
- package/dist/renderer/assets/{plug-BI27elC-.js → plug-BIx9fjip.js} +1 -1
- package/dist/renderer/assets/{plus-BhURuFIQ.js → plus-Dn7JFWQ8.js} +1 -1
- package/dist/renderer/assets/projects-brJZgwEJ.js +1 -0
- package/dist/renderer/assets/{save-RwkHNm9e.js → save-CC3zOSWb.js} +1 -1
- package/dist/renderer/assets/{search-DMNtm2WP.js → search-CDTy9Czu.js} +1 -1
- package/dist/renderer/assets/{server-CNaxKyAq.js → server-DtQk3t2a.js} +1 -1
- package/dist/renderer/assets/{session-utils-vsALZkZN.js → session-utils-4ep5D66T.js} +1 -1
- package/dist/renderer/assets/{sessions-BY-R1IL_.js → sessions-Dor1LteH.js} +1 -1
- package/dist/renderer/assets/{shield-check-BF-4oJbj.js → shield-check-Cz2LpU6r.js} +1 -1
- package/dist/renderer/assets/{trash-2-DduflM4q.js → trash-2-C2EmWFZV.js} +1 -1
- package/dist/renderer/assets/{user-DBcvnuW4.js → user-I8B-cs5A.js} +1 -1
- package/dist/renderer/assets/{wifi-off-X1nXESYu.js → wifi-off-CPevTQJn.js} +1 -1
- package/dist/renderer/assets/zh-DIcdHycM.js +1 -0
- package/dist/renderer/index.html +1 -1
- package/dist-electron/packages/contracts/src/local-core.js +28 -0
- package/dist-electron/packages/core-sdk/src/index.js +32 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +76 -39
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +13 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +4 -1357
- package/dist-electron/services/local-ai-core/src/acp/local-core-slash-commands.js +28 -0
- package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +166 -0
- package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +231 -0
- package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +263 -0
- package/dist-electron/services/local-ai-core/src/acp/store/platform-store.js +186 -0
- package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +201 -0
- package/dist-electron/services/local-ai-core/src/acp/store/schema.js +275 -0
- package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +266 -0
- package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +232 -0
- package/dist-electron/services/local-ai-core/src/acp/store/utils.js +47 -0
- package/dist-electron/services/local-ai-core/src/acp/store/workspace-registry-store.js +109 -0
- package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js +136 -0
- package/dist-electron/services/local-ai-core/src/automation/automation-monitor-repository.js +56 -0
- package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +359 -0
- package/dist-electron/services/local-ai-core/src/automation/condition-evaluator.js +77 -0
- package/dist-electron/services/local-ai-core/src/automation/mock-stock-provider.js +40 -0
- package/dist-electron/services/local-ai-core/src/automation/monitor-id.js +10 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +55 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +101 -29
- package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +53 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +51 -33
- package/dist-electron/services/local-ai-core/src/cli/lac.js +196 -0
- package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +37 -0
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +43 -0
- package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +12 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/monitor-stock-plugin.js +30 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-router.js +40 -4
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +41 -0
- package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +31 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +36 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-bridge-session.js +25 -11
- package/dist-electron/services/local-ai-core/src/thread/session-command-service.js +275 -0
- package/dist-electron/services/local-ai-core/src/thread/slash-command-registry.js +27 -0
- package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +134 -0
- package/dist-electron/shared/desktop.js +21 -1
- package/dist-electron/tests/contracts/local-core-contracts.test.js +9 -0
- package/dist-electron/tests/electron/automation-monitor.test.js +38 -0
- package/dist-electron/tests/electron/lac-cli.test.js +146 -0
- package/dist-electron/tests/electron/plugin-kernel.test.js +26 -0
- package/dist-electron/tests/integration/local-core-refactor.test.js +359 -0
- package/package.json +1 -1
- package/dist/renderer/assets/CronList-C6nPAmEo.js +0 -1
- package/dist/renderer/assets/SessionChat-D1HtMdQS.js +0 -1
- package/dist/renderer/assets/desktop-CFcnzwcY.js +0 -1
- package/dist/renderer/assets/desktop-O8_6ZCVZ.js +0 -4
- package/dist/renderer/assets/en-CKhCF6St.js +0 -1
- package/dist/renderer/assets/projects-DpR972HM.js +0 -1
- package/dist/renderer/assets/zh-Dz5FLTBV.js +0 -1
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalThreadStore = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const index_js_1 = require("../../../../../packages/contracts/src/index.js");
|
|
6
|
+
const desktop_js_1 = require("../../../../../shared/desktop.js");
|
|
7
|
+
const workspace_thread_mappers_js_1 = require("../../thread/workspace-thread-mappers.js");
|
|
8
|
+
const workspace_thread_id_js_1 = require("../../thread/workspace-thread-id.js");
|
|
9
|
+
const utils_js_1 = require("./utils.js");
|
|
10
|
+
class LocalThreadStore {
|
|
11
|
+
db;
|
|
12
|
+
constructor(db) {
|
|
13
|
+
this.db = db;
|
|
14
|
+
}
|
|
15
|
+
listSummaries(workspaceId) {
|
|
16
|
+
const rows = this.db.prepare(`
|
|
17
|
+
SELECT id, workspace_id, session_id, bridge_session_key, title, agent_type, created_at, updated_at, history_count, excerpt, acp_session_id, acp_supports_load, agent_mode
|
|
18
|
+
FROM threads
|
|
19
|
+
WHERE workspace_id = ?
|
|
20
|
+
ORDER BY updated_at DESC
|
|
21
|
+
`).all(workspaceId);
|
|
22
|
+
return rows.map((row) => ({
|
|
23
|
+
id: row.id,
|
|
24
|
+
workspaceId: row.workspace_id,
|
|
25
|
+
title: row.title,
|
|
26
|
+
live: false,
|
|
27
|
+
updatedAt: row.updated_at,
|
|
28
|
+
createdAt: row.created_at,
|
|
29
|
+
historyCount: row.history_count,
|
|
30
|
+
excerpt: row.excerpt,
|
|
31
|
+
runId: undefined,
|
|
32
|
+
bridgeSessionKey: row.bridge_session_key,
|
|
33
|
+
agentType: row.agent_type,
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
count(workspaceId) {
|
|
37
|
+
const row = this.db.prepare('SELECT COUNT(*) AS total FROM threads WHERE workspace_id = ?').get(workspaceId);
|
|
38
|
+
return Number(row?.total || 0);
|
|
39
|
+
}
|
|
40
|
+
create(workspaceId, title, agentType = desktop_js_1.LOCALCORE_ACP_AGENT_TYPE, agentMode = 'default') {
|
|
41
|
+
const sessionId = (0, node_crypto_1.randomUUID)();
|
|
42
|
+
const threadId = (0, workspace_thread_id_js_1.encodeThreadId)(workspaceId, sessionId);
|
|
43
|
+
const now = new Date().toISOString();
|
|
44
|
+
const bridgeSessionKey = `${desktop_js_1.LOCALCORE_ACP_AGENT_TYPE}:${workspaceId}:${sessionId}`;
|
|
45
|
+
this.db.prepare(`
|
|
46
|
+
INSERT INTO threads (id, workspace_id, session_id, bridge_session_key, title, agent_type, created_at, updated_at, history_count, excerpt, agent_mode)
|
|
47
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, '', ?)
|
|
48
|
+
`).run(threadId, workspaceId, sessionId, bridgeSessionKey, title, agentType, now, now, agentMode || 'default');
|
|
49
|
+
return {
|
|
50
|
+
id: threadId,
|
|
51
|
+
workspaceId,
|
|
52
|
+
title,
|
|
53
|
+
live: false,
|
|
54
|
+
updatedAt: now,
|
|
55
|
+
createdAt: now,
|
|
56
|
+
historyCount: 0,
|
|
57
|
+
excerpt: '',
|
|
58
|
+
bridgeSessionKey,
|
|
59
|
+
agentType,
|
|
60
|
+
messages: [],
|
|
61
|
+
selectedKnowledgeBaseIds: [],
|
|
62
|
+
pendingPermissionRequest: null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
get(threadId, selectedKnowledgeBaseIds) {
|
|
66
|
+
const row = this.getRow(threadId);
|
|
67
|
+
if (!row) {
|
|
68
|
+
throw new Error(`Thread not found: ${threadId}`);
|
|
69
|
+
}
|
|
70
|
+
const messages = this.db.prepare(`
|
|
71
|
+
SELECT id, thread_id, role, content, tool_call_json, bridge_kind, bridge_status, timestamp, kind, seq
|
|
72
|
+
FROM messages
|
|
73
|
+
WHERE thread_id = ?
|
|
74
|
+
ORDER BY seq ASC
|
|
75
|
+
`).all(threadId);
|
|
76
|
+
return {
|
|
77
|
+
id: row.id,
|
|
78
|
+
workspaceId: row.workspace_id,
|
|
79
|
+
title: row.title,
|
|
80
|
+
live: false,
|
|
81
|
+
updatedAt: row.updated_at,
|
|
82
|
+
createdAt: row.created_at,
|
|
83
|
+
historyCount: row.history_count,
|
|
84
|
+
excerpt: row.excerpt,
|
|
85
|
+
bridgeSessionKey: row.bridge_session_key,
|
|
86
|
+
agentType: row.agent_type,
|
|
87
|
+
messages: messages.map((message) => ({
|
|
88
|
+
id: message.id,
|
|
89
|
+
role: message.role,
|
|
90
|
+
content: message.content,
|
|
91
|
+
toolCall: (0, utils_js_1.parseJson)(message.tool_call_json || 'null', null) || undefined,
|
|
92
|
+
bridgeKind: (0, utils_js_1.normalizeBridgeKind)(message.bridge_kind),
|
|
93
|
+
bridgeStatus: (0, utils_js_1.normalizeBridgeStatus)(message.bridge_status),
|
|
94
|
+
timestamp: message.timestamp,
|
|
95
|
+
kind: message.kind,
|
|
96
|
+
})),
|
|
97
|
+
selectedKnowledgeBaseIds,
|
|
98
|
+
pendingPermissionRequest: null,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
rename(threadId, title) {
|
|
102
|
+
const now = new Date().toISOString();
|
|
103
|
+
this.db.prepare('UPDATE threads SET title = ?, updated_at = ? WHERE id = ?').run(title, now, threadId);
|
|
104
|
+
}
|
|
105
|
+
delete(threadId) {
|
|
106
|
+
this.db.prepare('DELETE FROM threads WHERE id = ?').run(threadId);
|
|
107
|
+
}
|
|
108
|
+
appendMessage(threadId, role, content, kind, toolCall, bridgeKind, bridgeStatus) {
|
|
109
|
+
const timestamp = new Date().toISOString();
|
|
110
|
+
const nextSequenceRow = this.db.prepare('SELECT COALESCE(MAX(seq), -1) + 1 AS next_seq FROM messages WHERE thread_id = ?').get(threadId);
|
|
111
|
+
const nextSeq = Number(nextSequenceRow?.next_seq || 0);
|
|
112
|
+
const id = `${timestamp}-${role}-${nextSeq}`;
|
|
113
|
+
const excerpt = (0, workspace_thread_mappers_js_1.normalizeMessageContent)(content);
|
|
114
|
+
this.db.exec('BEGIN IMMEDIATE');
|
|
115
|
+
try {
|
|
116
|
+
this.db.prepare(`
|
|
117
|
+
INSERT INTO messages (id, thread_id, role, content, tool_call_json, bridge_kind, bridge_status, timestamp, kind, seq)
|
|
118
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
119
|
+
`).run(id, threadId, role, content, toolCall ? JSON.stringify(toolCall) : null, bridgeKind || null, bridgeStatus || null, timestamp, kind, nextSeq);
|
|
120
|
+
this.db.prepare(`
|
|
121
|
+
UPDATE threads
|
|
122
|
+
SET updated_at = ?, history_count = history_count + 1, excerpt = ?
|
|
123
|
+
WHERE id = ?
|
|
124
|
+
`).run(timestamp, excerpt, threadId);
|
|
125
|
+
this.db.exec('COMMIT');
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
this.db.exec('ROLLBACK');
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
return { id, timestamp };
|
|
132
|
+
}
|
|
133
|
+
upsertMessage(threadId, id, role, content, kind, toolCall, bridgeKind, bridgeStatus) {
|
|
134
|
+
const timestamp = new Date().toISOString();
|
|
135
|
+
const excerpt = (0, workspace_thread_mappers_js_1.normalizeMessageContent)(content);
|
|
136
|
+
const existing = this.db.prepare('SELECT id FROM messages WHERE id = ? AND thread_id = ?').get(id, threadId);
|
|
137
|
+
this.db.exec('BEGIN IMMEDIATE');
|
|
138
|
+
try {
|
|
139
|
+
if (existing) {
|
|
140
|
+
this.db.prepare(`
|
|
141
|
+
UPDATE messages
|
|
142
|
+
SET content = ?, tool_call_json = ?, bridge_kind = ?, bridge_status = ?, timestamp = ?, kind = ?
|
|
143
|
+
WHERE id = ? AND thread_id = ?
|
|
144
|
+
`).run(content, toolCall ? JSON.stringify(toolCall) : null, bridgeKind || null, bridgeStatus || null, timestamp, kind, id, threadId);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
const nextSequenceRow = this.db.prepare('SELECT COALESCE(MAX(seq), -1) + 1 AS next_seq FROM messages WHERE thread_id = ?').get(threadId);
|
|
148
|
+
const nextSeq = Number(nextSequenceRow?.next_seq || 0);
|
|
149
|
+
this.db.prepare(`
|
|
150
|
+
INSERT INTO messages (id, thread_id, role, content, tool_call_json, bridge_kind, bridge_status, timestamp, kind, seq)
|
|
151
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
152
|
+
`).run(id, threadId, role, content, toolCall ? JSON.stringify(toolCall) : null, bridgeKind || null, bridgeStatus || null, timestamp, kind, nextSeq);
|
|
153
|
+
this.db.prepare(`
|
|
154
|
+
UPDATE threads
|
|
155
|
+
SET history_count = history_count + 1
|
|
156
|
+
WHERE id = ?
|
|
157
|
+
`).run(threadId);
|
|
158
|
+
}
|
|
159
|
+
this.db.prepare(`
|
|
160
|
+
UPDATE threads
|
|
161
|
+
SET updated_at = ?, excerpt = ?
|
|
162
|
+
WHERE id = ?
|
|
163
|
+
`).run(timestamp, excerpt, threadId);
|
|
164
|
+
this.db.exec('COMMIT');
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
this.db.exec('ROLLBACK');
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
return { id, timestamp };
|
|
171
|
+
}
|
|
172
|
+
updateRun(runId, threadId, status) {
|
|
173
|
+
const now = new Date().toISOString();
|
|
174
|
+
const normalizedStatus = (0, index_js_1.normalizeRunStatus)(status);
|
|
175
|
+
const existing = this.db.prepare('SELECT id FROM runs WHERE id = ?').get(runId);
|
|
176
|
+
if (existing) {
|
|
177
|
+
this.db.prepare('UPDATE runs SET status = ?, updated_at = ? WHERE id = ?').run(normalizedStatus, now, runId);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this.db.prepare(`
|
|
181
|
+
INSERT INTO runs (id, thread_id, status, started_at, updated_at)
|
|
182
|
+
VALUES (?, ?, ?, ?, ?)
|
|
183
|
+
`).run(runId, threadId, normalizedStatus, now, now);
|
|
184
|
+
}
|
|
185
|
+
getLatestRunForThread(threadId) {
|
|
186
|
+
const row = this.db.prepare(`
|
|
187
|
+
SELECT id, thread_id, status, started_at, updated_at
|
|
188
|
+
FROM runs
|
|
189
|
+
WHERE thread_id = ?
|
|
190
|
+
ORDER BY updated_at DESC
|
|
191
|
+
LIMIT 1
|
|
192
|
+
`).get(threadId);
|
|
193
|
+
return row ? { ...row, status: (0, index_js_1.normalizeRunStatus)(row.status) } : undefined;
|
|
194
|
+
}
|
|
195
|
+
getRun(runId) {
|
|
196
|
+
const row = this.db.prepare(`
|
|
197
|
+
SELECT id, thread_id, status, started_at, updated_at
|
|
198
|
+
FROM runs
|
|
199
|
+
WHERE id = ?
|
|
200
|
+
`).get(runId);
|
|
201
|
+
return row ? { ...row, status: (0, index_js_1.normalizeRunStatus)(row.status) } : undefined;
|
|
202
|
+
}
|
|
203
|
+
getRow(threadId) {
|
|
204
|
+
return this.db.prepare(`
|
|
205
|
+
SELECT id, workspace_id, session_id, bridge_session_key, title, agent_type, created_at, updated_at, history_count, excerpt, acp_session_id, acp_supports_load, agent_mode
|
|
206
|
+
FROM threads
|
|
207
|
+
WHERE id = ?
|
|
208
|
+
`).get(threadId);
|
|
209
|
+
}
|
|
210
|
+
updateAgentMode(threadId, mode) {
|
|
211
|
+
this.db.prepare(`
|
|
212
|
+
UPDATE threads
|
|
213
|
+
SET agent_mode = ?, updated_at = ?
|
|
214
|
+
WHERE id = ?
|
|
215
|
+
`).run(mode, new Date().toISOString(), threadId);
|
|
216
|
+
}
|
|
217
|
+
updateAgentType(threadId, agentType) {
|
|
218
|
+
this.db.prepare(`
|
|
219
|
+
UPDATE threads
|
|
220
|
+
SET agent_type = ?, acp_session_id = NULL, acp_supports_load = 0, updated_at = ?
|
|
221
|
+
WHERE id = ?
|
|
222
|
+
`).run(agentType, new Date().toISOString(), threadId);
|
|
223
|
+
}
|
|
224
|
+
updateSession(threadId, sessionId, supportsLoad) {
|
|
225
|
+
this.db.prepare(`
|
|
226
|
+
UPDATE threads
|
|
227
|
+
SET acp_session_id = ?, acp_supports_load = ?, updated_at = COALESCE(updated_at, ?)
|
|
228
|
+
WHERE id = ?
|
|
229
|
+
`).run(sessionId, supportsLoad ? 1 : 0, new Date().toISOString(), threadId);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
exports.LocalThreadStore = LocalThreadStore;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseJson = parseJson;
|
|
4
|
+
exports.normalizeBridgeKind = normalizeBridgeKind;
|
|
5
|
+
exports.normalizeBridgeStatus = normalizeBridgeStatus;
|
|
6
|
+
exports.defaultPermissions = defaultPermissions;
|
|
7
|
+
exports.redactSecrets = redactSecrets;
|
|
8
|
+
function parseJson(value, fallback) {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(value);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return fallback;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function normalizeBridgeKind(value) {
|
|
17
|
+
switch (value) {
|
|
18
|
+
case 'assistant':
|
|
19
|
+
case 'thought':
|
|
20
|
+
case 'plan':
|
|
21
|
+
case 'tool':
|
|
22
|
+
case 'status':
|
|
23
|
+
case 'permission':
|
|
24
|
+
return value;
|
|
25
|
+
default:
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function normalizeBridgeStatus(value) {
|
|
30
|
+
return value === 'awaiting_input' ? value : undefined;
|
|
31
|
+
}
|
|
32
|
+
function defaultPermissions() {
|
|
33
|
+
return {
|
|
34
|
+
'workspace.read': 'allow',
|
|
35
|
+
'workspace.write': 'ask',
|
|
36
|
+
'command.execute': 'ask',
|
|
37
|
+
'network.access': 'ask',
|
|
38
|
+
'secrets.access': 'deny',
|
|
39
|
+
'git.modify': 'ask',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function redactSecrets(value) {
|
|
43
|
+
return value
|
|
44
|
+
.replace(/\b(sk-[A-Za-z0-9_-]{12,})\b/g, '[REDACTED_SECRET]')
|
|
45
|
+
.replace(/\b([A-Za-z0-9_]*TOKEN[A-Za-z0-9_]*|[A-Za-z0-9_]*SECRET[A-Za-z0-9_]*|[A-Za-z0-9_]*KEY[A-Za-z0-9_]*)=([^\s]+)/gi, '$1=[REDACTED_SECRET]')
|
|
46
|
+
.replace(/\b(Bearer\s+)[A-Za-z0-9._-]+/gi, '$1[REDACTED_SECRET]');
|
|
47
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalWorkspaceRegistryStore = void 0;
|
|
4
|
+
const utils_js_1 = require("./utils.js");
|
|
5
|
+
class LocalWorkspaceRegistryStore {
|
|
6
|
+
db;
|
|
7
|
+
constructor(db) {
|
|
8
|
+
this.db = db;
|
|
9
|
+
}
|
|
10
|
+
list() {
|
|
11
|
+
const rows = this.db.prepare(`
|
|
12
|
+
SELECT id, display_name, path, device_id, default_runtime_id, git_json, health_json, metadata_json, created_at, updated_at, last_opened_at
|
|
13
|
+
FROM workspace_registry
|
|
14
|
+
ORDER BY display_name ASC
|
|
15
|
+
`).all();
|
|
16
|
+
return rows.map((row) => this.toEntry(row));
|
|
17
|
+
}
|
|
18
|
+
get(workspaceId) {
|
|
19
|
+
const row = this.db.prepare(`
|
|
20
|
+
SELECT id, display_name, path, device_id, default_runtime_id, git_json, health_json, metadata_json, created_at, updated_at, last_opened_at
|
|
21
|
+
FROM workspace_registry
|
|
22
|
+
WHERE id = ?
|
|
23
|
+
`).get(workspaceId);
|
|
24
|
+
return row ? this.toEntry(row) : undefined;
|
|
25
|
+
}
|
|
26
|
+
upsert(input) {
|
|
27
|
+
const id = input.workspaceId || input.displayName;
|
|
28
|
+
const now = new Date().toISOString();
|
|
29
|
+
const existing = this.get(id);
|
|
30
|
+
const health = input.health || existing?.health || {
|
|
31
|
+
status: 'unknown',
|
|
32
|
+
summary: 'Workspace health has not been checked.',
|
|
33
|
+
issues: [],
|
|
34
|
+
};
|
|
35
|
+
this.db.prepare(`
|
|
36
|
+
INSERT INTO workspace_registry (
|
|
37
|
+
id, display_name, path, device_id, default_runtime_id, git_json, health_json, metadata_json, created_at, updated_at, last_opened_at
|
|
38
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
39
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
40
|
+
display_name = excluded.display_name,
|
|
41
|
+
path = excluded.path,
|
|
42
|
+
device_id = excluded.device_id,
|
|
43
|
+
default_runtime_id = excluded.default_runtime_id,
|
|
44
|
+
git_json = excluded.git_json,
|
|
45
|
+
health_json = excluded.health_json,
|
|
46
|
+
metadata_json = excluded.metadata_json,
|
|
47
|
+
updated_at = excluded.updated_at
|
|
48
|
+
`).run(id, input.displayName, input.path, input.deviceId, input.defaultRuntimeId || null, JSON.stringify(input.git || existing?.git || {}), JSON.stringify(health), JSON.stringify(input.metadata || existing?.metadata || {}), existing?.createdAt || now, now, existing?.lastOpenedAt || null);
|
|
49
|
+
return this.get(id);
|
|
50
|
+
}
|
|
51
|
+
update(workspaceId, input) {
|
|
52
|
+
const existing = this.get(workspaceId);
|
|
53
|
+
if (!existing) {
|
|
54
|
+
throw new Error(`Workspace not found: ${workspaceId}`);
|
|
55
|
+
}
|
|
56
|
+
return this.upsert({
|
|
57
|
+
workspaceId,
|
|
58
|
+
displayName: input.displayName || existing.displayName,
|
|
59
|
+
path: input.path || existing.path,
|
|
60
|
+
deviceId: existing.deviceId,
|
|
61
|
+
defaultRuntimeId: input.defaultRuntimeId === null ? undefined : input.defaultRuntimeId || existing.defaultRuntimeId,
|
|
62
|
+
git: existing.git,
|
|
63
|
+
health: existing.health,
|
|
64
|
+
metadata: input.metadata || existing.metadata,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
delete(workspaceId) {
|
|
68
|
+
this.db.prepare('DELETE FROM workspace_registry WHERE id = ?').run(workspaceId);
|
|
69
|
+
return { deleted: true };
|
|
70
|
+
}
|
|
71
|
+
touch(workspaceId) {
|
|
72
|
+
this.db.prepare('UPDATE workspace_registry SET last_opened_at = ?, updated_at = ? WHERE id = ?')
|
|
73
|
+
.run(new Date().toISOString(), new Date().toISOString(), workspaceId);
|
|
74
|
+
}
|
|
75
|
+
toEntry(row) {
|
|
76
|
+
const activeTaskCount = Number(this.db.prepare(`
|
|
77
|
+
SELECT COUNT(*) AS total
|
|
78
|
+
FROM agent_tasks
|
|
79
|
+
WHERE workspace_id = ? AND status IN ('created', 'queued', 'running', 'waiting_for_user')
|
|
80
|
+
`).get(row.id)?.total || 0);
|
|
81
|
+
const recentTaskRows = this.db.prepare(`
|
|
82
|
+
SELECT id
|
|
83
|
+
FROM agent_tasks
|
|
84
|
+
WHERE workspace_id = ?
|
|
85
|
+
ORDER BY updated_at DESC
|
|
86
|
+
LIMIT 8
|
|
87
|
+
`).all(row.id);
|
|
88
|
+
return {
|
|
89
|
+
workspaceId: row.id,
|
|
90
|
+
displayName: row.display_name,
|
|
91
|
+
path: row.path,
|
|
92
|
+
deviceId: row.device_id,
|
|
93
|
+
createdAt: row.created_at,
|
|
94
|
+
updatedAt: row.updated_at,
|
|
95
|
+
lastOpenedAt: row.last_opened_at || undefined,
|
|
96
|
+
defaultRuntimeId: row.default_runtime_id || undefined,
|
|
97
|
+
git: (0, utils_js_1.parseJson)(row.git_json, { isRepo: false }),
|
|
98
|
+
health: (0, utils_js_1.parseJson)(row.health_json, {
|
|
99
|
+
status: 'unknown',
|
|
100
|
+
summary: 'Workspace health has not been checked.',
|
|
101
|
+
issues: [],
|
|
102
|
+
}),
|
|
103
|
+
activeTaskCount,
|
|
104
|
+
recentTaskIds: recentTaskRows.map((item) => item.id),
|
|
105
|
+
metadata: (0, utils_js_1.parseJson)(row.metadata_json, {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.LocalWorkspaceRegistryStore = LocalWorkspaceRegistryStore;
|
package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AutomationConversationExecutor = void 0;
|
|
4
|
+
exports.renderMonitorPrompt = renderMonitorPrompt;
|
|
5
|
+
const scheduled_bridge_session_js_1 = require("../scheduler/scheduled-bridge-session.js");
|
|
6
|
+
const scheduled_job_route_js_1 = require("../scheduler/scheduled-job-route.js");
|
|
7
|
+
const TERMINAL_RUN_STATES = new Set(['completed', 'failed', 'interrupted']);
|
|
8
|
+
const MONITOR_RUN_PERMISSION_MODE = 'bypassPermissions';
|
|
9
|
+
class AutomationConversationExecutor {
|
|
10
|
+
options;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.options = options;
|
|
13
|
+
}
|
|
14
|
+
async execute(monitor, event, timeoutMs = 15 * 60 * 1000) {
|
|
15
|
+
const workspaceRouter = this.options.getWorkspaceRouter();
|
|
16
|
+
const threadId = await this.resolveThread(monitor);
|
|
17
|
+
const prompt = renderMonitorPrompt(monitor.promptTemplate, event, monitor);
|
|
18
|
+
const channelRuntime = monitor.platform === 'local' ? undefined : this.options.getChannelRuntime(monitor.platform);
|
|
19
|
+
const bridge = channelRuntime
|
|
20
|
+
? await scheduled_bridge_session_js_1.ScheduledBridgeSession.open({
|
|
21
|
+
target: {
|
|
22
|
+
id: monitor.id,
|
|
23
|
+
workspaceId: monitor.workspaceId,
|
|
24
|
+
platform: monitor.platform,
|
|
25
|
+
route: monitor.route,
|
|
26
|
+
title: monitor.title,
|
|
27
|
+
promptTemplate: monitor.promptTemplate,
|
|
28
|
+
},
|
|
29
|
+
threadId,
|
|
30
|
+
workspaceRouter,
|
|
31
|
+
getChannelRuntime: () => channelRuntime,
|
|
32
|
+
noticeIcon: monitor.sourceType === 'stock.quote' ? '📈' : '🔔',
|
|
33
|
+
noticeTitle: monitor.title,
|
|
34
|
+
})
|
|
35
|
+
: undefined;
|
|
36
|
+
try {
|
|
37
|
+
const sendResult = await workspaceRouter.sendThreadMessage(threadId, prompt, {
|
|
38
|
+
permissionMode: MONITOR_RUN_PERMISSION_MODE,
|
|
39
|
+
runtimeEnv: this.buildRuntimeEnv(monitor),
|
|
40
|
+
});
|
|
41
|
+
await this.waitForRun(sendResult.runId, timeoutMs);
|
|
42
|
+
const thread = await workspaceRouter.getThread(threadId);
|
|
43
|
+
const replyText = [...thread.messages]
|
|
44
|
+
.reverse()
|
|
45
|
+
.find((message) => message.role === 'assistant' && message.kind === 'final')
|
|
46
|
+
?.content;
|
|
47
|
+
return {
|
|
48
|
+
threadId,
|
|
49
|
+
runId: sendResult.runId,
|
|
50
|
+
replyText,
|
|
51
|
+
deliveryMode: bridge ? 'bridge-stream' : 'thread-only',
|
|
52
|
+
deliveryStatus: 'succeeded',
|
|
53
|
+
lastBridgeEventAt: bridge ? new Date().toISOString() : undefined,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
await bridge?.close();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async resolveThread(monitor) {
|
|
61
|
+
const workspaceRouter = this.options.getWorkspaceRouter();
|
|
62
|
+
if (monitor.executionMode === 'same-thread') {
|
|
63
|
+
const binding = this.options.store.getPlatformThreadBinding(monitor.workspaceId, monitor.route.channelId, monitor.route.participantId || '', monitor.platform);
|
|
64
|
+
if (binding?.thread_id && await this.threadExists(binding.thread_id)) {
|
|
65
|
+
return binding.thread_id;
|
|
66
|
+
}
|
|
67
|
+
if (monitor.route.threadId && await this.threadExists(monitor.route.threadId)) {
|
|
68
|
+
return monitor.route.threadId;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const title = monitor.platform === 'local'
|
|
72
|
+
? `[Monitor] ${monitor.title}`
|
|
73
|
+
: `[Monitor:${(0, scheduled_job_route_js_1.getChannelPlatformBase)(monitor.platform) || monitor.platform}] ${monitor.title}`;
|
|
74
|
+
const existing = (await workspaceRouter.listThreads(monitor.workspaceId))
|
|
75
|
+
.find((thread) => thread.title === title);
|
|
76
|
+
if (existing) {
|
|
77
|
+
return existing.id;
|
|
78
|
+
}
|
|
79
|
+
const created = await workspaceRouter.createThread(monitor.workspaceId, title);
|
|
80
|
+
return created.id;
|
|
81
|
+
}
|
|
82
|
+
async threadExists(threadId) {
|
|
83
|
+
try {
|
|
84
|
+
await this.options.getWorkspaceRouter().getThread(threadId);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
buildRuntimeEnv(monitor) {
|
|
92
|
+
const basePlatform = (0, scheduled_job_route_js_1.getChannelPlatformBase)(monitor.platform);
|
|
93
|
+
const env = {};
|
|
94
|
+
if (basePlatform && basePlatform !== 'local') {
|
|
95
|
+
env.LOCAL_AI_PLATFORM = basePlatform;
|
|
96
|
+
env.LOCAL_AI_ROUTE_TYPE = (0, scheduled_job_route_js_1.routeTypeForPlatform)(monitor.platform);
|
|
97
|
+
}
|
|
98
|
+
const instanceId = monitor.route.instanceId || (0, scheduled_job_route_js_1.getChannelPlatformInstanceId)(monitor.platform);
|
|
99
|
+
if (instanceId) {
|
|
100
|
+
env.LOCAL_AI_PLATFORM_INSTANCE_ID = instanceId;
|
|
101
|
+
}
|
|
102
|
+
if (monitor.route.channelId) {
|
|
103
|
+
env.LOCAL_AI_CHAT_ID = monitor.route.channelId;
|
|
104
|
+
}
|
|
105
|
+
if (monitor.route.participantId) {
|
|
106
|
+
env.LOCAL_AI_PLATFORM_USER_ID = monitor.route.participantId;
|
|
107
|
+
}
|
|
108
|
+
return env;
|
|
109
|
+
}
|
|
110
|
+
async waitForRun(runId, timeoutMs) {
|
|
111
|
+
const startedAt = Date.now();
|
|
112
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
113
|
+
const run = this.options.store.getRun(runId);
|
|
114
|
+
if (run && TERMINAL_RUN_STATES.has(run.status)) {
|
|
115
|
+
if (run.status !== 'completed') {
|
|
116
|
+
throw new Error(`Monitor run finished with status ${run.status}`);
|
|
117
|
+
}
|
|
118
|
+
return run;
|
|
119
|
+
}
|
|
120
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`Timed out waiting for monitor run ${runId}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.AutomationConversationExecutor = AutomationConversationExecutor;
|
|
126
|
+
function renderMonitorPrompt(template, event, monitor) {
|
|
127
|
+
const values = {
|
|
128
|
+
title: monitor.title,
|
|
129
|
+
sourceType: event.sourceType,
|
|
130
|
+
subject: event.subject,
|
|
131
|
+
summary: event.summary || '',
|
|
132
|
+
timestamp: event.occurredAt,
|
|
133
|
+
...event.payload,
|
|
134
|
+
};
|
|
135
|
+
return String(template || '').replace(/\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g, (_match, key) => String(values[key] ?? ''));
|
|
136
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AutomationMonitorRepository = void 0;
|
|
4
|
+
class AutomationMonitorRepository {
|
|
5
|
+
store;
|
|
6
|
+
constructor(store) {
|
|
7
|
+
this.store = store;
|
|
8
|
+
}
|
|
9
|
+
list(workspaceId) {
|
|
10
|
+
return this.store.listAutomationMonitors(workspaceId);
|
|
11
|
+
}
|
|
12
|
+
get(monitorId) {
|
|
13
|
+
return this.store.getAutomationMonitor(monitorId);
|
|
14
|
+
}
|
|
15
|
+
create(input) {
|
|
16
|
+
return this.store.createAutomationMonitor(input);
|
|
17
|
+
}
|
|
18
|
+
update(monitorId, input) {
|
|
19
|
+
return this.store.updateAutomationMonitor(monitorId, input);
|
|
20
|
+
}
|
|
21
|
+
updateState(monitorId, input) {
|
|
22
|
+
return this.store.updateAutomationMonitorState(monitorId, input);
|
|
23
|
+
}
|
|
24
|
+
delete(monitorId) {
|
|
25
|
+
return this.store.deleteAutomationMonitor(monitorId);
|
|
26
|
+
}
|
|
27
|
+
listRuns(monitorId) {
|
|
28
|
+
return this.store.listAutomationMonitorRuns(monitorId);
|
|
29
|
+
}
|
|
30
|
+
createRun(monitorId, status, input = {}) {
|
|
31
|
+
return this.store.createAutomationMonitorRun(monitorId, status, input);
|
|
32
|
+
}
|
|
33
|
+
updateRun(runId, input) {
|
|
34
|
+
return this.store.updateAutomationMonitorRun(runId, input);
|
|
35
|
+
}
|
|
36
|
+
getPlatformThreadBindingByThreadId(threadId) {
|
|
37
|
+
return this.store.getPlatformThreadBindingByThreadId(threadId);
|
|
38
|
+
}
|
|
39
|
+
toScheduledLike(monitor) {
|
|
40
|
+
return {
|
|
41
|
+
id: monitor.id,
|
|
42
|
+
workspaceId: monitor.workspaceId,
|
|
43
|
+
platform: monitor.platform,
|
|
44
|
+
route: monitor.route,
|
|
45
|
+
executionMode: monitor.executionMode,
|
|
46
|
+
triggerType: 'once',
|
|
47
|
+
promptTemplate: monitor.promptTemplate,
|
|
48
|
+
description: monitor.title,
|
|
49
|
+
enabled: monitor.enabled,
|
|
50
|
+
concurrencyPolicy: monitor.concurrencyPolicy,
|
|
51
|
+
createdAt: monitor.createdAt,
|
|
52
|
+
updatedAt: monitor.updatedAt,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.AutomationMonitorRepository = AutomationMonitorRepository;
|