@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
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { ref, readonly } from "#imports";
|
|
2
|
+
import { routeAgent } from "#blokkli-build/agent-client";
|
|
3
|
+
const PING_INTERVAL_MS = 3e4;
|
|
4
|
+
const RECONNECT_DELAY_MS = 3e3;
|
|
5
|
+
const MAX_RECONNECT_ATTEMPTS = 10;
|
|
6
|
+
export default function socketProvider() {
|
|
7
|
+
let ws = null;
|
|
8
|
+
let pingInterval = null;
|
|
9
|
+
let reconnectTimeout = null;
|
|
10
|
+
let reconnectAttempts = 0;
|
|
11
|
+
const isConnected = ref(false);
|
|
12
|
+
let messageHandler = null;
|
|
13
|
+
let lifecycle = {};
|
|
14
|
+
function setMessageHandler(handler) {
|
|
15
|
+
messageHandler = handler;
|
|
16
|
+
}
|
|
17
|
+
function setLifecycleHandlers(handlers) {
|
|
18
|
+
lifecycle = handlers;
|
|
19
|
+
}
|
|
20
|
+
function send(message) {
|
|
21
|
+
if (ws?.readyState === WebSocket.OPEN) {
|
|
22
|
+
ws.send(JSON.stringify(message));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function detachListeners(socket) {
|
|
26
|
+
socket.removeEventListener("open", onWebSocketOpen);
|
|
27
|
+
socket.removeEventListener("close", onWebSocketClose);
|
|
28
|
+
socket.removeEventListener("error", onWebSocketError);
|
|
29
|
+
socket.removeEventListener("message", onWebSocketMessage);
|
|
30
|
+
}
|
|
31
|
+
function clearTimers() {
|
|
32
|
+
if (pingInterval) {
|
|
33
|
+
window.clearInterval(pingInterval);
|
|
34
|
+
pingInterval = null;
|
|
35
|
+
}
|
|
36
|
+
if (reconnectTimeout) {
|
|
37
|
+
window.clearTimeout(reconnectTimeout);
|
|
38
|
+
reconnectTimeout = null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function onWebSocketOpen() {
|
|
42
|
+
isConnected.value = true;
|
|
43
|
+
reconnectAttempts = 0;
|
|
44
|
+
pingInterval = window.setInterval(() => {
|
|
45
|
+
send({ type: "ping" });
|
|
46
|
+
}, PING_INTERVAL_MS);
|
|
47
|
+
lifecycle.onOpen?.();
|
|
48
|
+
}
|
|
49
|
+
function onWebSocketClose() {
|
|
50
|
+
if (pingInterval) {
|
|
51
|
+
window.clearInterval(pingInterval);
|
|
52
|
+
pingInterval = null;
|
|
53
|
+
}
|
|
54
|
+
isConnected.value = false;
|
|
55
|
+
lifecycle.onClose?.();
|
|
56
|
+
reconnectAttempts++;
|
|
57
|
+
if (reconnectAttempts > MAX_RECONNECT_ATTEMPTS) {
|
|
58
|
+
lifecycle.onMaxReconnects?.();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
reconnectTimeout = window.setTimeout(() => {
|
|
62
|
+
if (!isConnected.value) connect();
|
|
63
|
+
}, RECONNECT_DELAY_MS);
|
|
64
|
+
}
|
|
65
|
+
function onWebSocketError(error) {
|
|
66
|
+
console.error("WebSocket error:", error);
|
|
67
|
+
lifecycle.onError?.(error);
|
|
68
|
+
}
|
|
69
|
+
function onWebSocketMessage(event) {
|
|
70
|
+
try {
|
|
71
|
+
const data = JSON.parse(event.data);
|
|
72
|
+
messageHandler?.(data);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error("Failed to parse WebSocket message:", error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function connect() {
|
|
78
|
+
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (ws) {
|
|
82
|
+
detachListeners(ws);
|
|
83
|
+
ws = null;
|
|
84
|
+
}
|
|
85
|
+
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
86
|
+
const url = `${protocol}//${window.location.host}${routeAgent}`;
|
|
87
|
+
ws = new WebSocket(url);
|
|
88
|
+
ws.addEventListener("open", onWebSocketOpen);
|
|
89
|
+
ws.addEventListener("close", onWebSocketClose);
|
|
90
|
+
ws.addEventListener("error", onWebSocketError);
|
|
91
|
+
ws.addEventListener("message", onWebSocketMessage);
|
|
92
|
+
}
|
|
93
|
+
function disconnect() {
|
|
94
|
+
clearTimers();
|
|
95
|
+
if (ws) {
|
|
96
|
+
detachListeners(ws);
|
|
97
|
+
ws.close();
|
|
98
|
+
ws = null;
|
|
99
|
+
}
|
|
100
|
+
isConnected.value = false;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
isConnected: readonly(isConnected),
|
|
104
|
+
send,
|
|
105
|
+
connect,
|
|
106
|
+
disconnect,
|
|
107
|
+
setMessageHandler,
|
|
108
|
+
setLifecycleHandlers
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type Ref } from '#imports';
|
|
2
|
+
import type { MutationAction } from '#blokkli/agent/app/types';
|
|
3
|
+
import type { PageContext } from '#blokkli/agent/shared/types';
|
|
4
|
+
import type { BlokkliApp } from '#blokkli/editor/types/app';
|
|
5
|
+
import type { FullBlokkliAdapter } from '#blokkli/editor/adapter';
|
|
6
|
+
import type { AgentToolName, AgentToolMap } from '#blokkli-build/agent-client';
|
|
7
|
+
import type { SocketProvider } from './socketProvider.js';
|
|
8
|
+
import type { ConversationProvider } from './conversationProvider.js';
|
|
9
|
+
export type PendingMutationState = {
|
|
10
|
+
action: MutationAction;
|
|
11
|
+
resolve: (approved: boolean) => void;
|
|
12
|
+
};
|
|
13
|
+
export type PendingToolCall = {
|
|
14
|
+
toolName: string;
|
|
15
|
+
params: Record<string, unknown>;
|
|
16
|
+
};
|
|
17
|
+
export type ToolsProvider = {
|
|
18
|
+
pendingMutation: Ref<PendingMutationState | null>;
|
|
19
|
+
pendingToolCall: Ref<PendingToolCall | null>;
|
|
20
|
+
autoApprove: Ref<boolean>;
|
|
21
|
+
pageContext: Readonly<Ref<PageContext | null>>;
|
|
22
|
+
init: () => Promise<{
|
|
23
|
+
toolNames: string[];
|
|
24
|
+
}>;
|
|
25
|
+
setPageContext: (ctx: PageContext) => void;
|
|
26
|
+
dispatch: (callId: string, tool: string, params: Record<string, unknown>) => Promise<void>;
|
|
27
|
+
runForPrompt: <T extends AgentToolName>(toolName: T, params: AgentToolMap[T]['params']) => Promise<{
|
|
28
|
+
toolName: T;
|
|
29
|
+
params: AgentToolMap[T]['params'];
|
|
30
|
+
result: AgentToolMap[T]['result'];
|
|
31
|
+
label: string;
|
|
32
|
+
}>;
|
|
33
|
+
approve: () => void;
|
|
34
|
+
reject: () => void;
|
|
35
|
+
setAutoApprove: (value: boolean) => void;
|
|
36
|
+
onComponentDone: (result: unknown) => void;
|
|
37
|
+
cancelPending: () => void;
|
|
38
|
+
};
|
|
39
|
+
export default function toolsProvider({ app, adapter, socket, conversation, }: {
|
|
40
|
+
app: BlokkliApp;
|
|
41
|
+
adapter: FullBlokkliAdapter<any>;
|
|
42
|
+
socket: SocketProvider;
|
|
43
|
+
conversation: ConversationProvider;
|
|
44
|
+
}): ToolsProvider;
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { ref, shallowRef, readonly } from "#imports";
|
|
2
|
+
import {
|
|
3
|
+
createToolMap,
|
|
4
|
+
executeTool,
|
|
5
|
+
getToolCategory,
|
|
6
|
+
getToolDefinition,
|
|
7
|
+
getToolInfoForServer,
|
|
8
|
+
isMutationAction,
|
|
9
|
+
isQueryResult,
|
|
10
|
+
isToolError,
|
|
11
|
+
resolveTools,
|
|
12
|
+
asRecord,
|
|
13
|
+
splitMeta
|
|
14
|
+
} from "#blokkli/agent/app/helpers";
|
|
15
|
+
import { mcpTools } from "#blokkli-build/agent-client";
|
|
16
|
+
import { itemEntityType } from "#blokkli-build/config";
|
|
17
|
+
function generateId() {
|
|
18
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
19
|
+
}
|
|
20
|
+
export default function toolsProvider({
|
|
21
|
+
app,
|
|
22
|
+
adapter,
|
|
23
|
+
socket,
|
|
24
|
+
conversation
|
|
25
|
+
}) {
|
|
26
|
+
const { $t, state } = app;
|
|
27
|
+
const pendingMutation = ref(null);
|
|
28
|
+
const pendingToolCall = ref(null);
|
|
29
|
+
const autoApprove = ref(false);
|
|
30
|
+
const pageContext = shallowRef(null);
|
|
31
|
+
let toolMap = {};
|
|
32
|
+
let pendingToolCallResolve = null;
|
|
33
|
+
function createToolContext() {
|
|
34
|
+
return {
|
|
35
|
+
app,
|
|
36
|
+
itemEntityType,
|
|
37
|
+
adapter,
|
|
38
|
+
pageContext: pageContext.value
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function init() {
|
|
42
|
+
const ctx = createToolContext();
|
|
43
|
+
const resolved = await resolveTools(mcpTools, ctx);
|
|
44
|
+
toolMap = createToolMap(resolved);
|
|
45
|
+
const toolNames = await getToolInfoForServer(
|
|
46
|
+
resolved,
|
|
47
|
+
state.editMode.value,
|
|
48
|
+
app,
|
|
49
|
+
adapter
|
|
50
|
+
);
|
|
51
|
+
return { toolNames };
|
|
52
|
+
}
|
|
53
|
+
function setPageContext(ctx) {
|
|
54
|
+
pageContext.value = ctx;
|
|
55
|
+
}
|
|
56
|
+
function waitForToolComponent(toolName, params) {
|
|
57
|
+
return new Promise((resolve) => {
|
|
58
|
+
pendingToolCall.value = { toolName, params };
|
|
59
|
+
pendingToolCallResolve = resolve;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function waitForApproval(action) {
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
pendingMutation.value = { action, resolve };
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async function executeLocally(toolName, params, setLabel) {
|
|
68
|
+
const ctx = createToolContext();
|
|
69
|
+
const toolDef = getToolDefinition(toolMap, toolName);
|
|
70
|
+
if (toolDef.component) {
|
|
71
|
+
const preparedParams = await executeTool(toolMap, toolName, ctx, params);
|
|
72
|
+
if (isToolError(preparedParams)) {
|
|
73
|
+
return { ok: false, error: preparedParams.error };
|
|
74
|
+
}
|
|
75
|
+
const raw = await waitForToolComponent(
|
|
76
|
+
toolDef.name,
|
|
77
|
+
preparedParams
|
|
78
|
+
);
|
|
79
|
+
const { payload, meta } = splitMeta(raw);
|
|
80
|
+
const payloadObj = asRecord(payload);
|
|
81
|
+
if (setLabel && payloadObj && typeof payloadObj.label === "string") {
|
|
82
|
+
setLabel(payloadObj.label);
|
|
83
|
+
}
|
|
84
|
+
return { ok: true, result: payload, meta };
|
|
85
|
+
}
|
|
86
|
+
const category = getToolCategory(toolMap, toolName);
|
|
87
|
+
const result = await executeTool(toolMap, toolName, ctx, params);
|
|
88
|
+
if (isToolError(result)) return { ok: false, error: result.error };
|
|
89
|
+
if (category === "query") {
|
|
90
|
+
if (isQueryResult(result)) {
|
|
91
|
+
if (setLabel) setLabel(result.label);
|
|
92
|
+
if (result.affectedUuids?.length) {
|
|
93
|
+
app.eventBus.emit("select", result.affectedUuids);
|
|
94
|
+
app.eventBus.emit("scrollSelectionIntoView", {});
|
|
95
|
+
}
|
|
96
|
+
return { ok: true, result: result.result, meta: {} };
|
|
97
|
+
}
|
|
98
|
+
return { ok: true, result, meta: {} };
|
|
99
|
+
}
|
|
100
|
+
if (!isMutationAction(result)) {
|
|
101
|
+
return { ok: false, error: "Invalid mutation tool result" };
|
|
102
|
+
}
|
|
103
|
+
const action = result;
|
|
104
|
+
if (setLabel) setLabel(action.label);
|
|
105
|
+
async function applyMutation() {
|
|
106
|
+
const uuidsBefore = state.getAllUuids();
|
|
107
|
+
await state.mutateWithLoadingState(() => action.apply(adapter));
|
|
108
|
+
const newUuids = state.getAllUuids().filter((uuid) => !uuidsBefore.includes(uuid));
|
|
109
|
+
const selectUuids = newUuids.length ? newUuids : action.affectedUuids || [];
|
|
110
|
+
if (selectUuids.length) {
|
|
111
|
+
app.eventBus.emit("select", selectUuids);
|
|
112
|
+
app.eventBus.emit("scrollSelectionIntoView", {});
|
|
113
|
+
}
|
|
114
|
+
return newUuids;
|
|
115
|
+
}
|
|
116
|
+
function buildMutationResult(newUuids) {
|
|
117
|
+
const newParagraphs = action.type === "add" && newUuids.length ? newUuids.map((uuid) => {
|
|
118
|
+
const block = app.blocks.getBlock(uuid);
|
|
119
|
+
if (!block) return null;
|
|
120
|
+
const blockFieldNames = app.types.fieldConfig.forEntityTypeAndBundle(itemEntityType, block.bundle).map((f) => f.name);
|
|
121
|
+
return {
|
|
122
|
+
uuid,
|
|
123
|
+
bundle: block.bundle,
|
|
124
|
+
...blockFieldNames.length ? { paragraphFields: blockFieldNames } : {}
|
|
125
|
+
};
|
|
126
|
+
}).filter(
|
|
127
|
+
(b) => b !== null
|
|
128
|
+
) : void 0;
|
|
129
|
+
return {
|
|
130
|
+
success: true,
|
|
131
|
+
historyIndex: state.currentMutationIndex.value,
|
|
132
|
+
newParagraphs: newParagraphs?.length ? newParagraphs : void 0,
|
|
133
|
+
...action.result
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (autoApprove.value || !toolDef.requiresApproval) {
|
|
137
|
+
const newUuids = await applyMutation();
|
|
138
|
+
return { ok: true, result: buildMutationResult(newUuids), meta: {} };
|
|
139
|
+
}
|
|
140
|
+
const approved = await waitForApproval(action);
|
|
141
|
+
if (approved) {
|
|
142
|
+
const newUuids = await applyMutation();
|
|
143
|
+
return { ok: true, result: buildMutationResult(newUuids), meta: {} };
|
|
144
|
+
}
|
|
145
|
+
if (action.revert) action.revert();
|
|
146
|
+
return { ok: true, result: { success: false, rejected: true }, meta: {} };
|
|
147
|
+
}
|
|
148
|
+
async function dispatch(callId, tool, params) {
|
|
149
|
+
const toolDef = getToolDefinition(toolMap, tool);
|
|
150
|
+
const initialLabel = toolDef.label($t);
|
|
151
|
+
const toolId = generateId();
|
|
152
|
+
const timestamp = Date.now();
|
|
153
|
+
let currentLabel = initialLabel;
|
|
154
|
+
conversation.setActive({
|
|
155
|
+
type: "tool",
|
|
156
|
+
id: toolId,
|
|
157
|
+
callId,
|
|
158
|
+
tool,
|
|
159
|
+
label: initialLabel,
|
|
160
|
+
status: "active",
|
|
161
|
+
timestamp
|
|
162
|
+
});
|
|
163
|
+
function finishItem(status) {
|
|
164
|
+
conversation.pushTool({
|
|
165
|
+
type: "tool",
|
|
166
|
+
id: toolId,
|
|
167
|
+
callId,
|
|
168
|
+
tool,
|
|
169
|
+
label: currentLabel,
|
|
170
|
+
status,
|
|
171
|
+
timestamp
|
|
172
|
+
});
|
|
173
|
+
conversation.setActive(null);
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const outcome = await executeLocally(tool, params, (label) => {
|
|
177
|
+
currentLabel = label;
|
|
178
|
+
const active = conversation.activeItem.value;
|
|
179
|
+
if (active?.type === "tool" && active.callId === callId) {
|
|
180
|
+
conversation.setActive({ ...active, label });
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
if (!outcome.ok) {
|
|
184
|
+
finishItem("error");
|
|
185
|
+
socket.send({
|
|
186
|
+
type: "tool_result",
|
|
187
|
+
callId,
|
|
188
|
+
result: null,
|
|
189
|
+
error: outcome.error
|
|
190
|
+
});
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
finishItem("success");
|
|
194
|
+
if (toolDef.buildDetails) {
|
|
195
|
+
try {
|
|
196
|
+
const detailsSource = outcome.meta.details ?? outcome.result;
|
|
197
|
+
const details = toolDef.buildDetails(detailsSource);
|
|
198
|
+
if (details != null) {
|
|
199
|
+
conversation.setToolDetail(callId, details);
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (outcome.meta.usage) {
|
|
205
|
+
conversation.pushUsage(outcome.meta.usage);
|
|
206
|
+
}
|
|
207
|
+
let resultForServer = outcome.result;
|
|
208
|
+
const resultObj = asRecord(resultForServer);
|
|
209
|
+
if (toolDef.prunedSummary && resultObj) {
|
|
210
|
+
try {
|
|
211
|
+
const summary = toolDef.prunedSummary(resultObj);
|
|
212
|
+
if (summary) {
|
|
213
|
+
resultForServer = { ...resultObj, _summary: summary };
|
|
214
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
socket.send({
|
|
219
|
+
type: "tool_result",
|
|
220
|
+
callId,
|
|
221
|
+
result: resultForServer,
|
|
222
|
+
skipLlmResponse: outcome.meta.skipLlmResponse
|
|
223
|
+
});
|
|
224
|
+
} catch (error) {
|
|
225
|
+
finishItem("error");
|
|
226
|
+
socket.send({
|
|
227
|
+
type: "tool_result",
|
|
228
|
+
callId,
|
|
229
|
+
result: null,
|
|
230
|
+
error: error.message
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async function runForPrompt(toolName, params) {
|
|
235
|
+
const ctx = createToolContext();
|
|
236
|
+
if (!Object.keys(toolMap).length) {
|
|
237
|
+
const resolved = await resolveTools(mcpTools, ctx);
|
|
238
|
+
toolMap = createToolMap(resolved);
|
|
239
|
+
}
|
|
240
|
+
const toolDef = getToolDefinition(toolMap, toolName);
|
|
241
|
+
const rawResult = await executeTool(toolMap, toolName, ctx, params);
|
|
242
|
+
const label = isQueryResult(rawResult) ? rawResult.label : toolDef.label($t);
|
|
243
|
+
const result = isQueryResult(rawResult) ? rawResult.result : rawResult;
|
|
244
|
+
return { toolName, params, result, label };
|
|
245
|
+
}
|
|
246
|
+
function approve() {
|
|
247
|
+
if (pendingMutation.value) {
|
|
248
|
+
pendingMutation.value.resolve(true);
|
|
249
|
+
pendingMutation.value = null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function reject() {
|
|
253
|
+
if (pendingMutation.value) {
|
|
254
|
+
pendingMutation.value.resolve(false);
|
|
255
|
+
pendingMutation.value = null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function setAutoApprove(value) {
|
|
259
|
+
autoApprove.value = value;
|
|
260
|
+
if (value) approve();
|
|
261
|
+
}
|
|
262
|
+
function onComponentDone(result) {
|
|
263
|
+
if (pendingToolCallResolve) {
|
|
264
|
+
pendingToolCallResolve(result);
|
|
265
|
+
pendingToolCallResolve = null;
|
|
266
|
+
}
|
|
267
|
+
pendingToolCall.value = null;
|
|
268
|
+
}
|
|
269
|
+
function cancelPending() {
|
|
270
|
+
if (pendingMutation.value) {
|
|
271
|
+
if (pendingMutation.value.action.revert) {
|
|
272
|
+
pendingMutation.value.action.revert();
|
|
273
|
+
}
|
|
274
|
+
pendingMutation.value.resolve(false);
|
|
275
|
+
pendingMutation.value = null;
|
|
276
|
+
}
|
|
277
|
+
if (pendingToolCallResolve) {
|
|
278
|
+
pendingToolCallResolve({ cancelled: true });
|
|
279
|
+
pendingToolCallResolve = null;
|
|
280
|
+
}
|
|
281
|
+
pendingToolCall.value = null;
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
pendingMutation,
|
|
285
|
+
pendingToolCall,
|
|
286
|
+
autoApprove,
|
|
287
|
+
pageContext: readonly(pageContext),
|
|
288
|
+
init,
|
|
289
|
+
setPageContext,
|
|
290
|
+
dispatch,
|
|
291
|
+
runForPrompt,
|
|
292
|
+
approve,
|
|
293
|
+
reject,
|
|
294
|
+
setAutoApprove,
|
|
295
|
+
onComponentDone,
|
|
296
|
+
cancelPending
|
|
297
|
+
};
|
|
298
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BlokkliApp } from '#blokkli/editor/types/app';
|
|
2
2
|
import type { FullBlokkliAdapter, MutationResponseLike, AdapterMethods } from '#blokkli/editor/adapter';
|
|
3
3
|
import type { EditMode } from '#blokkli/editor/types/state';
|
|
4
|
+
import { type UsageTurn } from '#blokkli/agent/shared/types';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
import type { Component } from 'vue';
|
|
6
7
|
import type { AgentToolName, AgentSkillName, AgentToolMap } from '#blokkli-build/agent-client';
|
|
@@ -55,6 +56,52 @@ export type QueryResult<T = unknown> = {
|
|
|
55
56
|
export type ToolError = {
|
|
56
57
|
error: string;
|
|
57
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* Side-channel data that interactive tool components can attach to their
|
|
61
|
+
* emitted result alongside the LLM-facing payload. The provider strips
|
|
62
|
+
* these underscore-prefixed properties at the boundary so they never reach
|
|
63
|
+
* the server: `details` feeds `buildDetails()`, `usage` is folded into the
|
|
64
|
+
* conversation usage display, and `skipLlmResponse` ends the agent loop
|
|
65
|
+
* without an LLM reply when the user fully accepted the changes.
|
|
66
|
+
*/
|
|
67
|
+
export type ToolMeta = {
|
|
68
|
+
details?: unknown;
|
|
69
|
+
usage?: UsageTurn;
|
|
70
|
+
skipLlmResponse?: boolean;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Shape an interactive tool component emits: the LLM-facing payload merged
|
|
74
|
+
* with optional side-channel metadata. Components can use this to type
|
|
75
|
+
* their `emit('done', ...)` payloads in a single place.
|
|
76
|
+
*/
|
|
77
|
+
export type ComponentToolResult<T = Record<string, unknown>> = T & {
|
|
78
|
+
_details?: ToolMeta['details'];
|
|
79
|
+
_usage?: ToolMeta['usage'];
|
|
80
|
+
_skipLlmResponse?: ToolMeta['skipLlmResponse'];
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Discriminated outcome returned by `executeToolLocally`. Callers branch
|
|
84
|
+
* on `ok` instead of runtime-checking the shape of an `unknown` result.
|
|
85
|
+
*/
|
|
86
|
+
export type ToolOutcome = {
|
|
87
|
+
ok: false;
|
|
88
|
+
error: string;
|
|
89
|
+
} | {
|
|
90
|
+
ok: true;
|
|
91
|
+
result: unknown;
|
|
92
|
+
meta: ToolMeta;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Hierarchical API surface exposed via `provide(INJECT_AGENT_APP, ...)`.
|
|
96
|
+
* Mirrors `BlokkliApp` for the editor — each member is a provider, and the
|
|
97
|
+
* orchestrator's flat state/actions sit at the top level.
|
|
98
|
+
*/
|
|
99
|
+
export type AgentApp = {
|
|
100
|
+
socket: import('../providers/socketProvider').SocketProvider;
|
|
101
|
+
conversation: import('../providers/conversationProvider').ConversationProvider;
|
|
102
|
+
plan: import('../providers/planProvider').PlanProvider;
|
|
103
|
+
tools: import('../providers/toolsProvider').ToolsProvider;
|
|
104
|
+
} & import('../providers/agentProvider').AgentOrchestrator;
|
|
58
105
|
/**
|
|
59
106
|
* Makes specified adapter methods required (non-optional).
|
|
60
107
|
*/
|
|
@@ -197,6 +197,7 @@ export function pruneMessages(messages, keepRecentTurns, toolMetadata) {
|
|
|
197
197
|
}
|
|
198
198
|
continue;
|
|
199
199
|
}
|
|
200
|
+
const hasToolResult = content.some((b) => b.type === "tool_result");
|
|
200
201
|
for (let j = content.length - 1; j >= 0; j--) {
|
|
201
202
|
const block = content[j];
|
|
202
203
|
if (block.type === "tool_result") {
|
|
@@ -207,7 +208,7 @@ export function pruneMessages(messages, keepRecentTurns, toolMetadata) {
|
|
|
207
208
|
} else {
|
|
208
209
|
block.content = compressToolResult(block.content);
|
|
209
210
|
}
|
|
210
|
-
} else if (block.type === "text" || block.type === "skill") {
|
|
211
|
+
} else if (hasToolResult && (block.type === "text" || block.type === "skill")) {
|
|
211
212
|
content.splice(j, 1);
|
|
212
213
|
}
|
|
213
214
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as BlokkliModule } from '../../shared/editor.
|
|
1
|
+
import { B as BlokkliModule } from '../../shared/editor.Bpw1EP57.mjs';
|
|
2
2
|
import 'nuxt/schema';
|
|
3
3
|
import 'consola';
|
|
4
4
|
import '../../../dist/global/types/definitions.js';
|
|
@@ -14,7 +14,7 @@ declare const _default: (options?: {
|
|
|
14
14
|
* template entity.
|
|
15
15
|
*/
|
|
16
16
|
templateEditRouteName?: string;
|
|
17
|
-
}) => BlokkliModule<{
|
|
17
|
+
} | undefined) => BlokkliModule<{
|
|
18
18
|
/**
|
|
19
19
|
* The name of the route that is used for editing template entities.
|
|
20
20
|
*
|
package/dist/modules/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { b as Blokkli, B as BlokkliModule, d as defineBlokkliModule } from '../shared/editor.
|
|
1
|
+
export { b as Blokkli, B as BlokkliModule, d as defineBlokkliModule } from '../shared/editor.Bpw1EP57.mjs';
|
|
2
2
|
import 'nuxt/schema';
|
|
3
3
|
import 'consola';
|
|
4
4
|
import '../../dist/global/types/definitions.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as BlokkliModule } from '../../shared/editor.
|
|
1
|
+
import { B as BlokkliModule } from '../../shared/editor.Bpw1EP57.mjs';
|
|
2
2
|
import 'nuxt/schema';
|
|
3
3
|
import 'consola';
|
|
4
4
|
import '../../../dist/global/types/definitions.js';
|
|
@@ -6,6 +6,6 @@ import '../../../dist/global/types/theme.js';
|
|
|
6
6
|
import '@nuxt/kit';
|
|
7
7
|
import '../../../dist/global/types/features.js';
|
|
8
8
|
|
|
9
|
-
declare const _default: (options?: object) => BlokkliModule<object>;
|
|
9
|
+
declare const _default: (options?: object | undefined) => BlokkliModule<object>;
|
|
10
10
|
|
|
11
11
|
export { _default as default };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as BlokkliModule } from '../../shared/editor.
|
|
1
|
+
import { B as BlokkliModule } from '../../shared/editor.Bpw1EP57.mjs';
|
|
2
2
|
import 'nuxt/schema';
|
|
3
3
|
import 'consola';
|
|
4
4
|
import '../../../dist/global/types/definitions.js';
|
|
@@ -6,6 +6,6 @@ import '../../../dist/global/types/theme.js';
|
|
|
6
6
|
import '@nuxt/kit';
|
|
7
7
|
import '../../../dist/global/types/features.js';
|
|
8
8
|
|
|
9
|
-
declare const _default: (options?: object) => BlokkliModule<object>;
|
|
9
|
+
declare const _default: (options?: object | undefined) => BlokkliModule<object>;
|
|
10
10
|
|
|
11
11
|
export { _default as default };
|