@blokkli/editor 2.0.0-alpha.56 → 2.0.0-alpha.58
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/dist/module.d.mts +2 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +2 -2
- package/dist/modules/agent/index.d.mts +1 -1
- package/dist/modules/agent/index.mjs +19 -19
- package/dist/modules/agent/runtime/app/composables/index.d.ts +3 -1
- package/dist/modules/agent/runtime/app/composables/index.js +1 -0
- package/dist/modules/agent/runtime/app/composables/useAgent.d.ts +6 -0
- package/dist/modules/agent/runtime/app/composables/useAgent.js +11 -0
- package/dist/modules/agent/runtime/app/features/agent/Container.vue +83 -88
- package/dist/modules/agent/runtime/app/helpers/buildPageContext.d.ts +7 -0
- package/dist/modules/agent/runtime/app/helpers/buildPageContext.js +81 -0
- package/dist/modules/agent/runtime/app/helpers/index.d.ts +15 -1
- package/dist/modules/agent/runtime/app/helpers/index.js +16 -0
- package/dist/modules/agent/runtime/app/helpers/injections.d.ts +3 -0
- package/dist/modules/agent/runtime/app/helpers/injections.js +3 -0
- package/dist/modules/agent/runtime/app/providers/agentProvider.d.ts +33 -0
- package/dist/modules/agent/runtime/app/providers/agentProvider.js +315 -0
- package/dist/modules/agent/runtime/app/providers/conversationProvider.d.ts +50 -0
- package/dist/modules/agent/runtime/app/providers/conversationProvider.js +263 -0
- package/dist/modules/agent/runtime/app/providers/planProvider.d.ts +15 -0
- package/dist/modules/agent/runtime/app/providers/planProvider.js +34 -0
- package/dist/modules/agent/runtime/app/providers/socketProvider.d.ts +17 -0
- package/dist/modules/agent/runtime/app/providers/socketProvider.js +110 -0
- package/dist/modules/agent/runtime/app/providers/toolsProvider.d.ts +44 -0
- package/dist/modules/agent/runtime/app/providers/toolsProvider.js +298 -0
- package/dist/modules/agent/runtime/app/types/index.d.ts +47 -0
- package/dist/modules/agent/runtime/app/types/index.js +3 -1
- package/dist/modules/agent/runtime/server/helpers.js +2 -1
- package/dist/modules/charts/index.d.mts +1 -1
- package/dist/modules/drupal/index.d.mts +2 -2
- package/dist/modules/iframes/index.d.mts +1 -1
- package/dist/modules/index.d.mts +1 -1
- package/dist/modules/readability/index.d.mts +2 -2
- package/dist/modules/table-of-contents/index.d.mts +2 -2
- package/dist/runtime/editor/components/DiffViewer/State.vue +51 -67
- package/dist/runtime/editor/components/EditProvider.vue +30 -10
- package/dist/runtime/editor/components/PreviewProvider.vue +14 -8
- package/dist/runtime/editor/css/output.css +1 -1
- package/dist/runtime/editor/events/index.d.ts +4 -3
- package/dist/runtime/editor/features/add-list/index.vue +2 -1
- package/dist/runtime/editor/features/changelog/changelog.json +8 -0
- package/dist/runtime/editor/features/dev-mode/index.vue +1 -10
- package/dist/runtime/editor/features/responsive-preview/Frame/index.vue +2 -2
- package/dist/runtime/editor/features/translations/index.vue +1 -0
- package/dist/runtime/editor/plugins/Sidebar/index.vue +9 -2
- package/dist/runtime/editor/providers/state.js +4 -1
- package/dist/shared/{editor.BTOBvmaz.d.mts → editor.Bpw1EP57.d.mts} +3 -3
- package/dist/shared/{editor.9vf8ZnOp.mjs → editor.FygP6XeF.mjs} +2 -2
- package/dist/types.d.mts +1 -1
- package/package.json +30 -7
- package/dist/modules/agent/runtime/app/composables/agentProvider.d.ts +0 -62
- package/dist/modules/agent/runtime/app/composables/agentProvider.js +0 -1048
|
@@ -1,1048 +0,0 @@
|
|
|
1
|
-
import { ref, shallowRef, readonly, reactive, watch } from "#imports";
|
|
2
|
-
import {
|
|
3
|
-
conversationItemSchema
|
|
4
|
-
} from "#blokkli/agent/app/types";
|
|
5
|
-
import {
|
|
6
|
-
createToolMap,
|
|
7
|
-
executeTool,
|
|
8
|
-
getToolCategory,
|
|
9
|
-
getToolInfoForServer,
|
|
10
|
-
getToolDefinition,
|
|
11
|
-
isMutationAction,
|
|
12
|
-
isQueryResult,
|
|
13
|
-
isToolError,
|
|
14
|
-
resolveTools
|
|
15
|
-
} from "#blokkli/agent/app/helpers";
|
|
16
|
-
import { mcpTools, routeAgent, routeRoute } from "#blokkli-build/agent-client";
|
|
17
|
-
import { generateUUID } from "#blokkli/editor/helpers/uuid";
|
|
18
|
-
import { itemEntityType } from "#blokkli-build/config";
|
|
19
|
-
export default function(app, adapter, agentName) {
|
|
20
|
-
const { $t, state, ui, context } = app;
|
|
21
|
-
let ws = null;
|
|
22
|
-
let reconnectTimeout = null;
|
|
23
|
-
let pingInterval = null;
|
|
24
|
-
let reconnectAttempts = 0;
|
|
25
|
-
const MAX_RECONNECT_ATTEMPTS = 10;
|
|
26
|
-
const isConnected = ref(false);
|
|
27
|
-
const isReady = ref(false);
|
|
28
|
-
const hasBeenReady = ref(false);
|
|
29
|
-
let pendingPrompt = null;
|
|
30
|
-
let pendingInit = null;
|
|
31
|
-
let toolMap = {};
|
|
32
|
-
let sentToolNames = [];
|
|
33
|
-
const storedPageContext = shallowRef(null);
|
|
34
|
-
const isProcessing = ref(false);
|
|
35
|
-
const isThinking = ref(false);
|
|
36
|
-
const usageTurns = ref([]);
|
|
37
|
-
const conversation = ref([]);
|
|
38
|
-
const activeItem = ref(null);
|
|
39
|
-
const autoApprove = ref(false);
|
|
40
|
-
const pendingMutation = ref(null);
|
|
41
|
-
const pendingToolCall = ref(null);
|
|
42
|
-
let pendingToolCallResolve = null;
|
|
43
|
-
const plan = ref(null);
|
|
44
|
-
const transcriptContent = ref(null);
|
|
45
|
-
const showTranscript = ref(false);
|
|
46
|
-
const activeConversationId = ref(null);
|
|
47
|
-
const conversationList = ref([]);
|
|
48
|
-
const showConversationList = ref(false);
|
|
49
|
-
const feedbackItemIds = ref(/* @__PURE__ */ new Set());
|
|
50
|
-
const toolDetails = reactive(/* @__PURE__ */ new Map());
|
|
51
|
-
async function saveCurrentConversation(serverState) {
|
|
52
|
-
if (!adapter.agentConversations) return;
|
|
53
|
-
if (!conversation.value.length) return;
|
|
54
|
-
if (!activeConversationId.value) {
|
|
55
|
-
activeConversationId.value = generateUUID();
|
|
56
|
-
}
|
|
57
|
-
const firstUser = conversation.value.find((item) => item.type === "user");
|
|
58
|
-
const titleText = firstUser && "content" in firstUser ? firstUser.content : "";
|
|
59
|
-
const title = titleText.length > 80 ? titleText.slice(0, 80) + "\u2026" : titleText;
|
|
60
|
-
try {
|
|
61
|
-
await adapter.agentConversations.upsert({
|
|
62
|
-
uuid: activeConversationId.value,
|
|
63
|
-
title,
|
|
64
|
-
clientState: JSON.stringify({
|
|
65
|
-
conversation: conversation.value.filter(
|
|
66
|
-
(item) => item.type !== "error"
|
|
67
|
-
),
|
|
68
|
-
usageTurns: usageTurns.value
|
|
69
|
-
}),
|
|
70
|
-
serverState: JSON.stringify({
|
|
71
|
-
messages: serverState.messages,
|
|
72
|
-
activatedLazyTools: serverState.activatedLazyTools
|
|
73
|
-
}),
|
|
74
|
-
hash: serverState.hash
|
|
75
|
-
});
|
|
76
|
-
} catch (e) {
|
|
77
|
-
console.warn("[blokkli agent] Failed to save conversation:", e);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function parseConversationData(data) {
|
|
81
|
-
try {
|
|
82
|
-
const parsed = JSON.parse(data.clientState);
|
|
83
|
-
if (!parsed.conversation?.length) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
const clientConversation = parsed.conversation.map(
|
|
87
|
-
(item) => {
|
|
88
|
-
const result = conversationItemSchema.safeParse(item);
|
|
89
|
-
if (result.success) {
|
|
90
|
-
return result.data;
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
type: "unknown",
|
|
94
|
-
id: generateId(),
|
|
95
|
-
timestamp: Date.now()
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
);
|
|
99
|
-
const serverParsed = JSON.parse(data.serverState);
|
|
100
|
-
if (!serverParsed?.messages?.length) {
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
return {
|
|
104
|
-
conversation: clientConversation,
|
|
105
|
-
usageTurns: parsed.usageTurns ?? [],
|
|
106
|
-
feedbackItemIds: data.feedbackItemIds ?? [],
|
|
107
|
-
serverState: {
|
|
108
|
-
messages: serverParsed.messages,
|
|
109
|
-
activatedLazyTools: serverParsed.activatedLazyTools,
|
|
110
|
-
hash: data.hash
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
} catch {
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
async function loadConversation(uuid) {
|
|
118
|
-
if (!adapter.agentConversations) return null;
|
|
119
|
-
try {
|
|
120
|
-
const data = await adapter.agentConversations.load(uuid);
|
|
121
|
-
if (!data) return null;
|
|
122
|
-
return parseConversationData(data);
|
|
123
|
-
} catch (e) {
|
|
124
|
-
console.warn("[blokkli agent] Failed to load conversation:", e);
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
async function deleteConversation(id) {
|
|
129
|
-
if (adapter.agentConversations) {
|
|
130
|
-
try {
|
|
131
|
-
await adapter.agentConversations.delete(id);
|
|
132
|
-
} catch (e) {
|
|
133
|
-
console.warn("[blokkli agent] Failed to delete conversation:", e);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
if (activeConversationId.value === id) {
|
|
137
|
-
activeConversationId.value = null;
|
|
138
|
-
conversation.value = [];
|
|
139
|
-
activeItem.value = null;
|
|
140
|
-
isProcessing.value = false;
|
|
141
|
-
isThinking.value = false;
|
|
142
|
-
send({ type: "new_conversation" });
|
|
143
|
-
}
|
|
144
|
-
await refreshConversationList();
|
|
145
|
-
}
|
|
146
|
-
async function switchConversation(id) {
|
|
147
|
-
if (isProcessing.value) return;
|
|
148
|
-
const loaded = await loadConversation(id);
|
|
149
|
-
if (!loaded) return;
|
|
150
|
-
conversation.value = loaded.conversation;
|
|
151
|
-
usageTurns.value = loaded.usageTurns;
|
|
152
|
-
feedbackItemIds.value = new Set(loaded.feedbackItemIds);
|
|
153
|
-
activeItem.value = null;
|
|
154
|
-
activeConversationId.value = id;
|
|
155
|
-
send({ type: "restore_conversation", state: loaded.serverState });
|
|
156
|
-
showConversationList.value = false;
|
|
157
|
-
}
|
|
158
|
-
async function refreshConversationList() {
|
|
159
|
-
if (!adapter.agentConversations) {
|
|
160
|
-
conversationList.value = [];
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
try {
|
|
164
|
-
const list = await adapter.agentConversations.list();
|
|
165
|
-
conversationList.value = list.sort(
|
|
166
|
-
(a, b) => b.updatedAt.localeCompare(a.updatedAt)
|
|
167
|
-
);
|
|
168
|
-
} catch (e) {
|
|
169
|
-
console.warn("[blokkli agent] Failed to list conversations:", e);
|
|
170
|
-
conversationList.value = [];
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
watch(isProcessing, (processing) => {
|
|
174
|
-
if (processing) {
|
|
175
|
-
ui.setTransform(agentName);
|
|
176
|
-
} else {
|
|
177
|
-
ui.setTransform(null);
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
function send(message) {
|
|
181
|
-
if (ws?.readyState === WebSocket.OPEN) {
|
|
182
|
-
ws.send(JSON.stringify(message));
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
function onWebSocketOpen() {
|
|
186
|
-
isConnected.value = true;
|
|
187
|
-
reconnectAttempts = 0;
|
|
188
|
-
pingInterval = window.setInterval(() => {
|
|
189
|
-
send({ type: "ping" });
|
|
190
|
-
}, 3e4);
|
|
191
|
-
onConnect();
|
|
192
|
-
}
|
|
193
|
-
function onWebSocketClose() {
|
|
194
|
-
if (pingInterval) {
|
|
195
|
-
window.clearInterval(pingInterval);
|
|
196
|
-
pingInterval = null;
|
|
197
|
-
}
|
|
198
|
-
isConnected.value = false;
|
|
199
|
-
isReady.value = false;
|
|
200
|
-
isProcessing.value = false;
|
|
201
|
-
reconnectAttempts++;
|
|
202
|
-
if (reconnectAttempts > MAX_RECONNECT_ATTEMPTS) {
|
|
203
|
-
conversation.value.push({
|
|
204
|
-
type: "error",
|
|
205
|
-
id: generateId(),
|
|
206
|
-
errorType: "connection",
|
|
207
|
-
timestamp: Date.now()
|
|
208
|
-
});
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
reconnectTimeout = window.setTimeout(() => {
|
|
212
|
-
if (!isConnected.value) {
|
|
213
|
-
connect();
|
|
214
|
-
}
|
|
215
|
-
}, 3e3);
|
|
216
|
-
}
|
|
217
|
-
function onWebSocketError(error) {
|
|
218
|
-
console.error("WebSocket error:", error);
|
|
219
|
-
}
|
|
220
|
-
function onWebSocketMessage(event) {
|
|
221
|
-
try {
|
|
222
|
-
const data = JSON.parse(event.data);
|
|
223
|
-
handleServerMessage(data);
|
|
224
|
-
} catch (error) {
|
|
225
|
-
console.error("Failed to parse WebSocket message:", error);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
function connect() {
|
|
229
|
-
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
if (ws) {
|
|
233
|
-
ws.removeEventListener("open", onWebSocketOpen);
|
|
234
|
-
ws.removeEventListener("close", onWebSocketClose);
|
|
235
|
-
ws.removeEventListener("error", onWebSocketError);
|
|
236
|
-
ws.removeEventListener("message", onWebSocketMessage);
|
|
237
|
-
ws = null;
|
|
238
|
-
}
|
|
239
|
-
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
240
|
-
const url = `${protocol}//${window.location.host}${routeAgent}`;
|
|
241
|
-
ws = new WebSocket(url);
|
|
242
|
-
ws.addEventListener("open", onWebSocketOpen);
|
|
243
|
-
ws.addEventListener("close", onWebSocketClose);
|
|
244
|
-
ws.addEventListener("error", onWebSocketError);
|
|
245
|
-
ws.addEventListener("message", onWebSocketMessage);
|
|
246
|
-
}
|
|
247
|
-
function disconnect() {
|
|
248
|
-
if (pingInterval) {
|
|
249
|
-
window.clearInterval(pingInterval);
|
|
250
|
-
pingInterval = null;
|
|
251
|
-
}
|
|
252
|
-
if (reconnectTimeout) {
|
|
253
|
-
window.clearTimeout(reconnectTimeout);
|
|
254
|
-
reconnectTimeout = null;
|
|
255
|
-
}
|
|
256
|
-
if (ws) {
|
|
257
|
-
ws.removeEventListener("open", onWebSocketOpen);
|
|
258
|
-
ws.removeEventListener("close", onWebSocketClose);
|
|
259
|
-
ws.removeEventListener("error", onWebSocketError);
|
|
260
|
-
ws.removeEventListener("message", onWebSocketMessage);
|
|
261
|
-
ws.close();
|
|
262
|
-
ws = null;
|
|
263
|
-
}
|
|
264
|
-
isConnected.value = false;
|
|
265
|
-
isReady.value = false;
|
|
266
|
-
ui.setTransform(null);
|
|
267
|
-
if (pendingMutation.value) {
|
|
268
|
-
if (pendingMutation.value.action.revert) {
|
|
269
|
-
pendingMutation.value.action.revert();
|
|
270
|
-
}
|
|
271
|
-
pendingMutation.value.resolve(false);
|
|
272
|
-
pendingMutation.value = null;
|
|
273
|
-
}
|
|
274
|
-
if (pendingToolCallResolve) {
|
|
275
|
-
pendingToolCallResolve({ cancelled: true });
|
|
276
|
-
pendingToolCallResolve = null;
|
|
277
|
-
}
|
|
278
|
-
pendingToolCall.value = null;
|
|
279
|
-
}
|
|
280
|
-
async function onConnect() {
|
|
281
|
-
const ctx = createToolContext();
|
|
282
|
-
const resolved = await resolveTools(mcpTools, ctx);
|
|
283
|
-
toolMap = createToolMap(resolved);
|
|
284
|
-
const toolNames = await getToolInfoForServer(
|
|
285
|
-
resolved,
|
|
286
|
-
state.editMode.value,
|
|
287
|
-
app,
|
|
288
|
-
adapter
|
|
289
|
-
);
|
|
290
|
-
let contentSearchTabs;
|
|
291
|
-
if (adapter.getContentSearchTabs) {
|
|
292
|
-
try {
|
|
293
|
-
contentSearchTabs = await adapter.getContentSearchTabs();
|
|
294
|
-
} catch (e) {
|
|
295
|
-
console.warn("[blokkli agent] Failed to fetch content search tabs:", e);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
if (adapter.getAgentAuthToken) {
|
|
299
|
-
try {
|
|
300
|
-
const authToken = await adapter.getAgentAuthToken();
|
|
301
|
-
if (!authToken) {
|
|
302
|
-
conversation.value.push({
|
|
303
|
-
type: "error",
|
|
304
|
-
id: generateId(),
|
|
305
|
-
errorType: "unauthorized",
|
|
306
|
-
timestamp: Date.now()
|
|
307
|
-
});
|
|
308
|
-
disconnect();
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
const pageContext2 = await buildPageContext(contentSearchTabs);
|
|
312
|
-
storedPageContext.value = pageContext2;
|
|
313
|
-
pendingInit = { toolNames, pageContext: pageContext2 };
|
|
314
|
-
send({ type: "authenticate", authToken });
|
|
315
|
-
return;
|
|
316
|
-
} catch (e) {
|
|
317
|
-
console.error("Failed to obtain agent auth token:", e);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
const pageContext = await buildPageContext(contentSearchTabs);
|
|
321
|
-
storedPageContext.value = pageContext;
|
|
322
|
-
sendInit(toolNames, pageContext);
|
|
323
|
-
}
|
|
324
|
-
async function sendInit(toolNames, pageContext) {
|
|
325
|
-
sentToolNames = toolNames;
|
|
326
|
-
send({ type: "init", toolNames, pageContext });
|
|
327
|
-
isReady.value = true;
|
|
328
|
-
hasBeenReady.value = true;
|
|
329
|
-
if (adapter.agentConversations && !pendingPrompt) {
|
|
330
|
-
try {
|
|
331
|
-
const latest = await adapter.agentConversations.loadLatest();
|
|
332
|
-
if (latest) {
|
|
333
|
-
const parsed = parseConversationData(latest);
|
|
334
|
-
if (parsed) {
|
|
335
|
-
activeConversationId.value = latest.uuid;
|
|
336
|
-
conversation.value = parsed.conversation;
|
|
337
|
-
usageTurns.value = parsed.usageTurns;
|
|
338
|
-
feedbackItemIds.value = new Set(parsed.feedbackItemIds);
|
|
339
|
-
send({ type: "restore_conversation", state: parsed.serverState });
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
} catch (e) {
|
|
343
|
-
console.warn("[blokkli agent] Failed to load latest conversation:", e);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
if (pendingPrompt) {
|
|
347
|
-
const {
|
|
348
|
-
prompt,
|
|
349
|
-
displayPrompt,
|
|
350
|
-
selectedUuids,
|
|
351
|
-
attachments,
|
|
352
|
-
autoLoadTools,
|
|
353
|
-
autoLoadSkills,
|
|
354
|
-
preSeededResults,
|
|
355
|
-
autoExecuteTools
|
|
356
|
-
} = pendingPrompt;
|
|
357
|
-
pendingPrompt = null;
|
|
358
|
-
sendPrompt(
|
|
359
|
-
prompt,
|
|
360
|
-
displayPrompt,
|
|
361
|
-
selectedUuids,
|
|
362
|
-
attachments,
|
|
363
|
-
autoLoadTools,
|
|
364
|
-
autoLoadSkills,
|
|
365
|
-
preSeededResults,
|
|
366
|
-
autoExecuteTools
|
|
367
|
-
);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
async function buildPageContext(contentSearchTabs) {
|
|
371
|
-
const { types, definitions } = app;
|
|
372
|
-
const bundles = [];
|
|
373
|
-
for (const bundle of types.generallyAvailableBundles) {
|
|
374
|
-
const contentFields = [
|
|
375
|
-
...types.editableFieldConfig.forEntityTypeAndBundle(itemEntityType, bundle.id).filter((f) => f.type !== "table").map((f) => ({
|
|
376
|
-
name: f.name,
|
|
377
|
-
label: f.label,
|
|
378
|
-
type: f.type === "frame" || f.type === "markup" ? "markup" : "plain"
|
|
379
|
-
})),
|
|
380
|
-
...types.droppableFieldConfig.forEntityTypeAndBundle(itemEntityType, bundle.id).map((f) => ({
|
|
381
|
-
name: f.name,
|
|
382
|
-
label: f.label,
|
|
383
|
-
type: f.type,
|
|
384
|
-
allowed: f.allowed
|
|
385
|
-
}))
|
|
386
|
-
];
|
|
387
|
-
const paragraphFields = types.fieldConfig.forEntityTypeAndBundle(itemEntityType, bundle.id).map((f) => ({
|
|
388
|
-
name: f.name,
|
|
389
|
-
label: f.label,
|
|
390
|
-
allowedBundles: f.allowedBundles,
|
|
391
|
-
cardinality: f.cardinality
|
|
392
|
-
}));
|
|
393
|
-
bundles.push({
|
|
394
|
-
id: bundle.id,
|
|
395
|
-
label: bundle.label,
|
|
396
|
-
description: bundle.description,
|
|
397
|
-
contentFields,
|
|
398
|
-
paragraphFields
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
const fragments = definitions.fragmentDefinitions.value.map((f) => ({
|
|
402
|
-
name: f.name,
|
|
403
|
-
label: f.label,
|
|
404
|
-
description: f.description
|
|
405
|
-
}));
|
|
406
|
-
const entityContentFields = [
|
|
407
|
-
...types.editableFieldConfig.forEntityTypeAndBundle(
|
|
408
|
-
context.value.entityType,
|
|
409
|
-
context.value.entityBundle
|
|
410
|
-
).filter((f) => f.type !== "table").map((f) => ({
|
|
411
|
-
name: f.name,
|
|
412
|
-
label: f.label,
|
|
413
|
-
type: f.type === "frame" || f.type === "markup" ? "markup" : "plain"
|
|
414
|
-
})),
|
|
415
|
-
...types.droppableFieldConfig.forEntityTypeAndBundle(
|
|
416
|
-
context.value.entityType,
|
|
417
|
-
context.value.entityBundle
|
|
418
|
-
).map((f) => ({
|
|
419
|
-
name: f.name,
|
|
420
|
-
label: f.label,
|
|
421
|
-
type: f.type,
|
|
422
|
-
allowed: f.allowed
|
|
423
|
-
}))
|
|
424
|
-
];
|
|
425
|
-
await app.analyze.ensureInitialized();
|
|
426
|
-
const analyzersList = app.analyze.analyzers.value.filter((a) => !a.requireRawPage).map((a) => ({
|
|
427
|
-
id: a.id,
|
|
428
|
-
type: a.type,
|
|
429
|
-
label: typeof a.label === "function" ? a.label(context.value.language, $t) : a.label,
|
|
430
|
-
description: typeof a.description === "function" ? a.description(context.value.language, $t) : a.description
|
|
431
|
-
}));
|
|
432
|
-
const pageContext = {
|
|
433
|
-
title: state.entity.value.label || "",
|
|
434
|
-
entityType: context.value.entityType,
|
|
435
|
-
entityUuid: context.value.entityUuid,
|
|
436
|
-
entityBundle: context.value.entityBundle,
|
|
437
|
-
bundleLabel: state.entity.value.bundleLabel || "",
|
|
438
|
-
itemEntityType,
|
|
439
|
-
bundles,
|
|
440
|
-
interfaceLanguage: ui.interfaceLanguage.value,
|
|
441
|
-
entityLanguage: context.value.language,
|
|
442
|
-
isPublished: state.entity.value.status ?? null,
|
|
443
|
-
editMode: state.editMode.value,
|
|
444
|
-
fragments,
|
|
445
|
-
entityContentFields,
|
|
446
|
-
...contentSearchTabs?.length ? { contentSearchTabs } : {},
|
|
447
|
-
...analyzersList.length ? { analyzers: analyzersList } : {}
|
|
448
|
-
};
|
|
449
|
-
return pageContext;
|
|
450
|
-
}
|
|
451
|
-
function generateId() {
|
|
452
|
-
return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
453
|
-
}
|
|
454
|
-
function finalizeActiveItem() {
|
|
455
|
-
const item = activeItem.value;
|
|
456
|
-
if (!item) return;
|
|
457
|
-
if (item.type === "assistant" && item.content) {
|
|
458
|
-
conversation.value.push({
|
|
459
|
-
type: "assistant",
|
|
460
|
-
id: item.id,
|
|
461
|
-
content: item.content,
|
|
462
|
-
timestamp: item.timestamp
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
activeItem.value = null;
|
|
466
|
-
}
|
|
467
|
-
function handleTextContent(content) {
|
|
468
|
-
if (activeItem.value?.type === "assistant") {
|
|
469
|
-
activeItem.value = {
|
|
470
|
-
...activeItem.value,
|
|
471
|
-
content: activeItem.value.content + content
|
|
472
|
-
};
|
|
473
|
-
} else {
|
|
474
|
-
activeItem.value = {
|
|
475
|
-
type: "assistant",
|
|
476
|
-
id: generateId(),
|
|
477
|
-
content,
|
|
478
|
-
timestamp: Date.now()
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
function handleServerMessage(data) {
|
|
483
|
-
switch (data.type) {
|
|
484
|
-
case "authenticated":
|
|
485
|
-
if (pendingInit) {
|
|
486
|
-
sendInit(pendingInit.toolNames, pendingInit.pageContext);
|
|
487
|
-
pendingInit = null;
|
|
488
|
-
}
|
|
489
|
-
break;
|
|
490
|
-
case "thinking":
|
|
491
|
-
activeItem.value = null;
|
|
492
|
-
isThinking.value = true;
|
|
493
|
-
break;
|
|
494
|
-
case "text":
|
|
495
|
-
isThinking.value = false;
|
|
496
|
-
handleTextContent(data.content);
|
|
497
|
-
break;
|
|
498
|
-
case "text_delta":
|
|
499
|
-
isThinking.value = false;
|
|
500
|
-
handleTextContent(data.content);
|
|
501
|
-
break;
|
|
502
|
-
case "tool_call":
|
|
503
|
-
finalizeActiveItem();
|
|
504
|
-
handleToolCall(data.callId, data.tool, data.params);
|
|
505
|
-
break;
|
|
506
|
-
case "usage":
|
|
507
|
-
usageTurns.value = [...usageTurns.value, data.usage];
|
|
508
|
-
break;
|
|
509
|
-
case "done":
|
|
510
|
-
finalizeActiveItem();
|
|
511
|
-
isThinking.value = false;
|
|
512
|
-
isProcessing.value = false;
|
|
513
|
-
if (data.message) {
|
|
514
|
-
const lastItem = conversation.value[conversation.value.length - 1];
|
|
515
|
-
const isDuplicate = lastItem?.type === "assistant" && lastItem.content === data.message;
|
|
516
|
-
if (!isDuplicate) {
|
|
517
|
-
conversation.value.push({
|
|
518
|
-
type: "assistant",
|
|
519
|
-
id: generateId(),
|
|
520
|
-
content: data.message,
|
|
521
|
-
timestamp: Date.now()
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
break;
|
|
526
|
-
case "error":
|
|
527
|
-
finalizeActiveItem();
|
|
528
|
-
isThinking.value = false;
|
|
529
|
-
isProcessing.value = false;
|
|
530
|
-
if (data.detail) {
|
|
531
|
-
console.warn(`[blokkli agent] ${data.errorType} error:`, data.detail);
|
|
532
|
-
}
|
|
533
|
-
conversation.value.push({
|
|
534
|
-
type: "error",
|
|
535
|
-
id: generateId(),
|
|
536
|
-
errorType: data.errorType,
|
|
537
|
-
timestamp: Date.now(),
|
|
538
|
-
...data.retryable ? { retryable: true } : {}
|
|
539
|
-
});
|
|
540
|
-
break;
|
|
541
|
-
case "server_tool_result":
|
|
542
|
-
finalizeActiveItem();
|
|
543
|
-
conversation.value.push({
|
|
544
|
-
type: "server_tool",
|
|
545
|
-
id: generateId(),
|
|
546
|
-
tool: data.tool,
|
|
547
|
-
label: data.label,
|
|
548
|
-
timestamp: Date.now()
|
|
549
|
-
});
|
|
550
|
-
break;
|
|
551
|
-
case "plan_update":
|
|
552
|
-
if (data.plan && data.plan.steps.length > 0 && data.plan.steps.every((s) => s.status === "completed")) {
|
|
553
|
-
conversation.value.push({
|
|
554
|
-
type: "server_tool",
|
|
555
|
-
id: generateId(),
|
|
556
|
-
tool: "plan_completed",
|
|
557
|
-
label: data.plan.title,
|
|
558
|
-
timestamp: Date.now()
|
|
559
|
-
});
|
|
560
|
-
plan.value = null;
|
|
561
|
-
} else {
|
|
562
|
-
plan.value = data.plan;
|
|
563
|
-
}
|
|
564
|
-
break;
|
|
565
|
-
case "transcript":
|
|
566
|
-
transcriptContent.value = data.transcript;
|
|
567
|
-
showTranscript.value = true;
|
|
568
|
-
break;
|
|
569
|
-
case "conversation_state":
|
|
570
|
-
saveCurrentConversation(data.state);
|
|
571
|
-
break;
|
|
572
|
-
case "conversation_restored":
|
|
573
|
-
break;
|
|
574
|
-
case "conversation_restore_failed":
|
|
575
|
-
console.warn(
|
|
576
|
-
"[blokkli agent] Conversation restore failed:",
|
|
577
|
-
data.reason
|
|
578
|
-
);
|
|
579
|
-
conversation.value = [];
|
|
580
|
-
if (activeConversationId.value) {
|
|
581
|
-
const failedId = activeConversationId.value;
|
|
582
|
-
activeConversationId.value = null;
|
|
583
|
-
if (adapter.agentConversations) {
|
|
584
|
-
adapter.agentConversations.delete(failedId).catch(() => {
|
|
585
|
-
});
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
break;
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
async function handleToolCall(callId, tool, params) {
|
|
592
|
-
const toolDef = getToolDefinition(toolMap, tool);
|
|
593
|
-
const initialLabel = toolDef.label($t);
|
|
594
|
-
const toolId = generateId();
|
|
595
|
-
const timestamp = Date.now();
|
|
596
|
-
let currentLabel = initialLabel;
|
|
597
|
-
activeItem.value = {
|
|
598
|
-
type: "tool",
|
|
599
|
-
id: toolId,
|
|
600
|
-
callId,
|
|
601
|
-
tool,
|
|
602
|
-
label: initialLabel,
|
|
603
|
-
status: "active",
|
|
604
|
-
timestamp
|
|
605
|
-
};
|
|
606
|
-
try {
|
|
607
|
-
const result = await executeToolLocally(tool, params, (label) => {
|
|
608
|
-
currentLabel = label;
|
|
609
|
-
if (activeItem.value?.type === "tool" && activeItem.value.callId === callId) {
|
|
610
|
-
activeItem.value = { ...activeItem.value, label };
|
|
611
|
-
}
|
|
612
|
-
});
|
|
613
|
-
if (isToolError(result)) {
|
|
614
|
-
conversation.value.push({
|
|
615
|
-
type: "tool",
|
|
616
|
-
id: toolId,
|
|
617
|
-
callId,
|
|
618
|
-
tool,
|
|
619
|
-
label: currentLabel,
|
|
620
|
-
status: "error",
|
|
621
|
-
timestamp
|
|
622
|
-
});
|
|
623
|
-
activeItem.value = null;
|
|
624
|
-
send({
|
|
625
|
-
type: "tool_result",
|
|
626
|
-
callId,
|
|
627
|
-
result: null,
|
|
628
|
-
error: result.error
|
|
629
|
-
});
|
|
630
|
-
} else {
|
|
631
|
-
conversation.value.push({
|
|
632
|
-
type: "tool",
|
|
633
|
-
id: toolId,
|
|
634
|
-
callId,
|
|
635
|
-
tool,
|
|
636
|
-
label: currentLabel,
|
|
637
|
-
status: "success",
|
|
638
|
-
timestamp
|
|
639
|
-
});
|
|
640
|
-
activeItem.value = null;
|
|
641
|
-
if (toolDef.buildDetails) {
|
|
642
|
-
try {
|
|
643
|
-
const detailsSource = typeof result === "object" && result !== null && "_details" in result ? result._details : result;
|
|
644
|
-
const details = toolDef.buildDetails(detailsSource);
|
|
645
|
-
if (details != null) {
|
|
646
|
-
toolDetails.set(callId, details);
|
|
647
|
-
}
|
|
648
|
-
} catch {
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
let resultForServer = result;
|
|
652
|
-
let skipLlmResponse;
|
|
653
|
-
if (typeof result === "object" && result !== null) {
|
|
654
|
-
const rec = result;
|
|
655
|
-
if ("_usage" in rec && rec._usage) {
|
|
656
|
-
usageTurns.value = [...usageTurns.value, rec._usage];
|
|
657
|
-
}
|
|
658
|
-
if (rec._skipLlmResponse === true) {
|
|
659
|
-
skipLlmResponse = true;
|
|
660
|
-
}
|
|
661
|
-
if ("_details" in rec || "_usage" in rec || "_skipLlmResponse" in rec) {
|
|
662
|
-
const {
|
|
663
|
-
_details: _,
|
|
664
|
-
_usage: __,
|
|
665
|
-
_skipLlmResponse: ___,
|
|
666
|
-
...rest
|
|
667
|
-
} = rec;
|
|
668
|
-
resultForServer = rest;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
if (toolDef.prunedSummary && typeof resultForServer === "object" && resultForServer !== null) {
|
|
672
|
-
try {
|
|
673
|
-
const summary = toolDef.prunedSummary(resultForServer);
|
|
674
|
-
if (summary) {
|
|
675
|
-
resultForServer = {
|
|
676
|
-
...resultForServer,
|
|
677
|
-
_summary: summary
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
} catch {
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
send({
|
|
684
|
-
type: "tool_result",
|
|
685
|
-
callId,
|
|
686
|
-
result: resultForServer,
|
|
687
|
-
skipLlmResponse
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
} catch (error) {
|
|
691
|
-
conversation.value.push({
|
|
692
|
-
type: "tool",
|
|
693
|
-
id: toolId,
|
|
694
|
-
callId,
|
|
695
|
-
tool,
|
|
696
|
-
label: currentLabel,
|
|
697
|
-
status: "error",
|
|
698
|
-
timestamp
|
|
699
|
-
});
|
|
700
|
-
activeItem.value = null;
|
|
701
|
-
send({
|
|
702
|
-
type: "tool_result",
|
|
703
|
-
callId,
|
|
704
|
-
result: null,
|
|
705
|
-
error: error.message
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
function createToolContext() {
|
|
710
|
-
return {
|
|
711
|
-
app,
|
|
712
|
-
itemEntityType,
|
|
713
|
-
adapter,
|
|
714
|
-
pageContext: storedPageContext.value
|
|
715
|
-
};
|
|
716
|
-
}
|
|
717
|
-
async function runToolForPrompt(toolName, params) {
|
|
718
|
-
const ctx = createToolContext();
|
|
719
|
-
if (!Object.keys(toolMap).length) {
|
|
720
|
-
const resolved = await resolveTools(mcpTools, ctx);
|
|
721
|
-
toolMap = createToolMap(resolved);
|
|
722
|
-
}
|
|
723
|
-
const toolDef = getToolDefinition(toolMap, toolName);
|
|
724
|
-
const rawResult = await executeTool(toolMap, toolName, ctx, params);
|
|
725
|
-
const label = isQueryResult(rawResult) ? rawResult.label : toolDef.label($t);
|
|
726
|
-
const result = isQueryResult(rawResult) ? rawResult.result : rawResult;
|
|
727
|
-
return { toolName, params, result, label };
|
|
728
|
-
}
|
|
729
|
-
function waitForToolComponent(toolName, params) {
|
|
730
|
-
return new Promise((resolve) => {
|
|
731
|
-
pendingToolCall.value = { toolName, params };
|
|
732
|
-
pendingToolCallResolve = resolve;
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
async function executeToolLocally(toolName, params, setLabel) {
|
|
736
|
-
const toolContext = createToolContext();
|
|
737
|
-
const toolDef = getToolDefinition(toolMap, toolName);
|
|
738
|
-
if (toolDef.component) {
|
|
739
|
-
const preparedParams = await executeTool(
|
|
740
|
-
toolMap,
|
|
741
|
-
toolName,
|
|
742
|
-
toolContext,
|
|
743
|
-
params
|
|
744
|
-
);
|
|
745
|
-
if (typeof preparedParams === "object" && preparedParams !== null && "error" in preparedParams) {
|
|
746
|
-
return preparedParams;
|
|
747
|
-
}
|
|
748
|
-
const result2 = await waitForToolComponent(
|
|
749
|
-
toolDef.name,
|
|
750
|
-
preparedParams
|
|
751
|
-
);
|
|
752
|
-
if (setLabel && typeof result2 === "object" && result2 !== null && "label" in result2) {
|
|
753
|
-
setLabel(result2.label);
|
|
754
|
-
}
|
|
755
|
-
return result2;
|
|
756
|
-
}
|
|
757
|
-
const category = getToolCategory(toolMap, toolName);
|
|
758
|
-
const result = await executeTool(toolMap, toolName, toolContext, params);
|
|
759
|
-
if (category === "query") {
|
|
760
|
-
if (isQueryResult(result)) {
|
|
761
|
-
if (setLabel) {
|
|
762
|
-
setLabel(result.label);
|
|
763
|
-
}
|
|
764
|
-
if (result.affectedUuids?.length) {
|
|
765
|
-
app.eventBus.emit("select", result.affectedUuids);
|
|
766
|
-
app.eventBus.emit("scrollSelectionIntoView", {});
|
|
767
|
-
}
|
|
768
|
-
return result.result;
|
|
769
|
-
}
|
|
770
|
-
return result;
|
|
771
|
-
}
|
|
772
|
-
if (typeof result === "object" && result !== null && "error" in result) {
|
|
773
|
-
return result;
|
|
774
|
-
}
|
|
775
|
-
if (!isMutationAction(result)) {
|
|
776
|
-
return { error: "Invalid mutation tool result" };
|
|
777
|
-
}
|
|
778
|
-
const action = result;
|
|
779
|
-
if (setLabel) {
|
|
780
|
-
setLabel(action.label);
|
|
781
|
-
}
|
|
782
|
-
async function applyMutation() {
|
|
783
|
-
const uuidsBefore = state.getAllUuids();
|
|
784
|
-
await state.mutateWithLoadingState(() => action.apply(adapter));
|
|
785
|
-
const newUuids = state.getAllUuids().filter((uuid) => !uuidsBefore.includes(uuid));
|
|
786
|
-
const selectUuids = newUuids.length ? newUuids : action.affectedUuids || [];
|
|
787
|
-
if (selectUuids.length) {
|
|
788
|
-
app.eventBus.emit("select", selectUuids);
|
|
789
|
-
app.eventBus.emit("scrollSelectionIntoView", {});
|
|
790
|
-
}
|
|
791
|
-
return newUuids;
|
|
792
|
-
}
|
|
793
|
-
function buildMutationResult(newUuids) {
|
|
794
|
-
const newParagraphs = action.type === "add" && newUuids.length ? newUuids.map((uuid) => {
|
|
795
|
-
const block = app.blocks.getBlock(uuid);
|
|
796
|
-
if (!block) return null;
|
|
797
|
-
const blockFieldNames = app.types.fieldConfig.forEntityTypeAndBundle(itemEntityType, block.bundle).map((f) => f.name);
|
|
798
|
-
return {
|
|
799
|
-
uuid,
|
|
800
|
-
bundle: block.bundle,
|
|
801
|
-
...blockFieldNames.length ? { paragraphFields: blockFieldNames } : {}
|
|
802
|
-
};
|
|
803
|
-
}).filter(
|
|
804
|
-
(b) => b !== null
|
|
805
|
-
) : void 0;
|
|
806
|
-
return {
|
|
807
|
-
success: true,
|
|
808
|
-
historyIndex: state.currentMutationIndex.value,
|
|
809
|
-
newParagraphs: newParagraphs?.length ? newParagraphs : void 0,
|
|
810
|
-
...action.result
|
|
811
|
-
};
|
|
812
|
-
}
|
|
813
|
-
if (autoApprove.value || !toolDef.requiresApproval) {
|
|
814
|
-
const newUuids = await applyMutation();
|
|
815
|
-
return buildMutationResult(newUuids);
|
|
816
|
-
}
|
|
817
|
-
const approved = await waitForApproval(action);
|
|
818
|
-
if (approved) {
|
|
819
|
-
const newUuids = await applyMutation();
|
|
820
|
-
return buildMutationResult(newUuids);
|
|
821
|
-
} else {
|
|
822
|
-
if (action.revert) {
|
|
823
|
-
action.revert();
|
|
824
|
-
}
|
|
825
|
-
return { success: false, rejected: true };
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
function waitForApproval(action) {
|
|
829
|
-
return new Promise((resolve) => {
|
|
830
|
-
pendingMutation.value = { action, resolve };
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
async function sendPrompt(prompt, displayPrompt, selectedUuids, attachments, autoLoadTools, autoLoadSkills, preSeededResults, autoExecuteTools) {
|
|
834
|
-
if (!prompt.trim() || isProcessing.value) return;
|
|
835
|
-
if (!isReady.value) {
|
|
836
|
-
pendingPrompt = {
|
|
837
|
-
prompt,
|
|
838
|
-
displayPrompt,
|
|
839
|
-
selectedUuids,
|
|
840
|
-
attachments,
|
|
841
|
-
autoLoadTools,
|
|
842
|
-
autoLoadSkills,
|
|
843
|
-
preSeededResults,
|
|
844
|
-
autoExecuteTools
|
|
845
|
-
};
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
isProcessing.value = true;
|
|
849
|
-
if (!activeConversationId.value) {
|
|
850
|
-
activeConversationId.value = generateUUID();
|
|
851
|
-
}
|
|
852
|
-
conversation.value.push({
|
|
853
|
-
type: "user",
|
|
854
|
-
id: generateId(),
|
|
855
|
-
content: displayPrompt ?? prompt,
|
|
856
|
-
timestamp: Date.now(),
|
|
857
|
-
attachments: attachments?.length ? attachments : void 0
|
|
858
|
-
});
|
|
859
|
-
isThinking.value = true;
|
|
860
|
-
const isFirstMessage = conversation.value.filter((v) => v.type === "user").length === 1;
|
|
861
|
-
const hasClientDirectives = !!(autoLoadTools?.length || autoLoadSkills?.length);
|
|
862
|
-
let resolvedAutoLoadTools = autoLoadTools;
|
|
863
|
-
let resolvedAutoLoadSkills = autoLoadSkills;
|
|
864
|
-
if (isFirstMessage && !hasClientDirectives && storedPageContext.value) {
|
|
865
|
-
try {
|
|
866
|
-
const routingResult = await fetch(routeRoute, {
|
|
867
|
-
method: "POST",
|
|
868
|
-
headers: { "Content-Type": "application/json" },
|
|
869
|
-
body: JSON.stringify({
|
|
870
|
-
prompt,
|
|
871
|
-
toolNames: sentToolNames,
|
|
872
|
-
pageContext: storedPageContext.value
|
|
873
|
-
})
|
|
874
|
-
}).then(
|
|
875
|
-
(r) => r.json()
|
|
876
|
-
);
|
|
877
|
-
if (routingResult.usage) {
|
|
878
|
-
usageTurns.value = [...usageTurns.value, routingResult.usage];
|
|
879
|
-
}
|
|
880
|
-
if (routingResult.tools?.length) {
|
|
881
|
-
resolvedAutoLoadTools = [
|
|
882
|
-
...resolvedAutoLoadTools || [],
|
|
883
|
-
...routingResult.tools
|
|
884
|
-
];
|
|
885
|
-
}
|
|
886
|
-
if (routingResult.skills?.length) {
|
|
887
|
-
resolvedAutoLoadSkills = [
|
|
888
|
-
...resolvedAutoLoadSkills || [],
|
|
889
|
-
...routingResult.skills
|
|
890
|
-
];
|
|
891
|
-
}
|
|
892
|
-
} catch {
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
const serverPreSeeded = preSeededResults?.length ? preSeededResults.map(({ toolName, params, result }) => ({
|
|
896
|
-
toolName,
|
|
897
|
-
params,
|
|
898
|
-
result
|
|
899
|
-
})) : void 0;
|
|
900
|
-
send({
|
|
901
|
-
type: "start",
|
|
902
|
-
prompt,
|
|
903
|
-
selectedUuids: selectedUuids?.length ? selectedUuids : void 0,
|
|
904
|
-
autoLoadTools: resolvedAutoLoadTools?.length ? resolvedAutoLoadTools : void 0,
|
|
905
|
-
autoLoadSkills: resolvedAutoLoadSkills?.length ? resolvedAutoLoadSkills : void 0,
|
|
906
|
-
preSeededResults: serverPreSeeded,
|
|
907
|
-
autoExecuteTools: autoExecuteTools?.length ? autoExecuteTools : void 0
|
|
908
|
-
});
|
|
909
|
-
}
|
|
910
|
-
function retry() {
|
|
911
|
-
if (isProcessing.value || !isReady.value) return;
|
|
912
|
-
const lastUserItem = [...conversation.value].reverse().find((item) => item.type === "user");
|
|
913
|
-
if (!lastUserItem || lastUserItem.type !== "user") return;
|
|
914
|
-
conversation.value = conversation.value.filter(
|
|
915
|
-
(item) => !(item.type === "error" && "retryable" in item && item.retryable)
|
|
916
|
-
);
|
|
917
|
-
isProcessing.value = true;
|
|
918
|
-
send({
|
|
919
|
-
type: "start",
|
|
920
|
-
prompt: lastUserItem.content
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
function approve() {
|
|
924
|
-
if (pendingMutation.value) {
|
|
925
|
-
pendingMutation.value.resolve(true);
|
|
926
|
-
pendingMutation.value = null;
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
function reject() {
|
|
930
|
-
if (pendingMutation.value) {
|
|
931
|
-
pendingMutation.value.resolve(false);
|
|
932
|
-
pendingMutation.value = null;
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
function setAutoApprove(value) {
|
|
936
|
-
autoApprove.value = value;
|
|
937
|
-
if (value) {
|
|
938
|
-
approve();
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
function cancel() {
|
|
942
|
-
if (pendingMutation.value) {
|
|
943
|
-
pendingMutation.value.resolve(false);
|
|
944
|
-
pendingMutation.value = null;
|
|
945
|
-
}
|
|
946
|
-
if (pendingToolCallResolve) {
|
|
947
|
-
pendingToolCallResolve({ cancelled: true });
|
|
948
|
-
pendingToolCallResolve = null;
|
|
949
|
-
}
|
|
950
|
-
pendingToolCall.value = null;
|
|
951
|
-
activeItem.value = null;
|
|
952
|
-
send({ type: "cancel" });
|
|
953
|
-
isProcessing.value = false;
|
|
954
|
-
conversation.value.push({
|
|
955
|
-
type: "assistant",
|
|
956
|
-
id: generateId(),
|
|
957
|
-
content: $t("aiAgentCancelled", "Cancelled"),
|
|
958
|
-
timestamp: Date.now()
|
|
959
|
-
});
|
|
960
|
-
}
|
|
961
|
-
function approvePlan() {
|
|
962
|
-
send({ type: "plan_approve" });
|
|
963
|
-
}
|
|
964
|
-
function rejectPlan() {
|
|
965
|
-
send({ type: "plan_reject" });
|
|
966
|
-
}
|
|
967
|
-
function newConversation() {
|
|
968
|
-
if (pendingMutation.value) {
|
|
969
|
-
pendingMutation.value.resolve(false);
|
|
970
|
-
pendingMutation.value = null;
|
|
971
|
-
}
|
|
972
|
-
if (pendingToolCallResolve) {
|
|
973
|
-
pendingToolCallResolve({ cancelled: true });
|
|
974
|
-
pendingToolCallResolve = null;
|
|
975
|
-
}
|
|
976
|
-
pendingToolCall.value = null;
|
|
977
|
-
conversation.value = [];
|
|
978
|
-
activeItem.value = null;
|
|
979
|
-
isProcessing.value = false;
|
|
980
|
-
isThinking.value = false;
|
|
981
|
-
activeConversationId.value = null;
|
|
982
|
-
plan.value = null;
|
|
983
|
-
usageTurns.value = [];
|
|
984
|
-
feedbackItemIds.value = /* @__PURE__ */ new Set();
|
|
985
|
-
toolDetails.clear();
|
|
986
|
-
send({ type: "new_conversation" });
|
|
987
|
-
}
|
|
988
|
-
function getTranscript() {
|
|
989
|
-
send({ type: "get_transcript" });
|
|
990
|
-
}
|
|
991
|
-
function onToolComponentDone(result) {
|
|
992
|
-
if (pendingToolCallResolve) {
|
|
993
|
-
pendingToolCallResolve(result);
|
|
994
|
-
pendingToolCallResolve = null;
|
|
995
|
-
}
|
|
996
|
-
pendingToolCall.value = null;
|
|
997
|
-
}
|
|
998
|
-
return {
|
|
999
|
-
// Connection state
|
|
1000
|
-
isConnected: readonly(isConnected),
|
|
1001
|
-
isReady: readonly(isReady),
|
|
1002
|
-
hasBeenReady: readonly(hasBeenReady),
|
|
1003
|
-
connect,
|
|
1004
|
-
disconnect,
|
|
1005
|
-
// Conversation state
|
|
1006
|
-
conversation,
|
|
1007
|
-
activeItem,
|
|
1008
|
-
isProcessing,
|
|
1009
|
-
isThinking,
|
|
1010
|
-
// Mutation/tool approval state
|
|
1011
|
-
autoApprove,
|
|
1012
|
-
pendingMutation,
|
|
1013
|
-
pendingToolCall,
|
|
1014
|
-
// Plan state
|
|
1015
|
-
plan,
|
|
1016
|
-
approvePlan,
|
|
1017
|
-
rejectPlan,
|
|
1018
|
-
// Token usage
|
|
1019
|
-
usageTurns,
|
|
1020
|
-
// Actions
|
|
1021
|
-
sendPrompt,
|
|
1022
|
-
runToolForPrompt,
|
|
1023
|
-
retry,
|
|
1024
|
-
approve,
|
|
1025
|
-
reject,
|
|
1026
|
-
setAutoApprove,
|
|
1027
|
-
cancel,
|
|
1028
|
-
newConversation,
|
|
1029
|
-
getTranscript,
|
|
1030
|
-
onToolComponentDone,
|
|
1031
|
-
// Tool details (ephemeral)
|
|
1032
|
-
toolDetails,
|
|
1033
|
-
// Transcript dialog state
|
|
1034
|
-
transcriptContent,
|
|
1035
|
-
showTranscript,
|
|
1036
|
-
// Conversation list
|
|
1037
|
-
conversationList,
|
|
1038
|
-
showConversationList,
|
|
1039
|
-
activeConversationId: readonly(activeConversationId),
|
|
1040
|
-
switchConversation,
|
|
1041
|
-
deleteConversation,
|
|
1042
|
-
refreshConversationList,
|
|
1043
|
-
// Feedback
|
|
1044
|
-
feedbackItemIds,
|
|
1045
|
-
// Page context (built once during connection)
|
|
1046
|
-
pageContext: storedPageContext
|
|
1047
|
-
};
|
|
1048
|
-
}
|