@nimblebrain/synapse 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -111
- package/dist/{chunk-SN7YXLAV.cjs → chunk-EHLQWCYV.cjs} +6 -6
- package/dist/{chunk-SN7YXLAV.cjs.map → chunk-EHLQWCYV.cjs.map} +1 -1
- package/dist/{chunk-ZMNYUGSF.cjs → chunk-FDMRJZKT.cjs} +576 -662
- package/dist/chunk-FDMRJZKT.cjs.map +1 -0
- package/dist/{chunk-E7OOOYVR.js → chunk-SRQNQ26I.js} +3 -3
- package/dist/{chunk-E7OOOYVR.js.map → chunk-SRQNQ26I.js.map} +1 -1
- package/dist/{chunk-RYWW6EHB.cjs → chunk-TXJMGQYF.cjs} +3 -5
- package/dist/chunk-TXJMGQYF.cjs.map +1 -0
- package/dist/{chunk-J5ICAHK2.js → chunk-UPDBDXQB.js} +4 -5
- package/dist/chunk-UPDBDXQB.js.map +1 -0
- package/dist/{chunk-GNTQJSQX.js → chunk-VYR6V47N.js} +573 -663
- package/dist/chunk-VYR6V47N.js.map +1 -0
- package/dist/codegen/cli.cjs +1 -1
- package/dist/codegen/cli.js +1 -1
- package/dist/codegen/index.d.cts +1 -1
- package/dist/codegen/index.d.ts +1 -1
- package/dist/connect.iife.global.js +28 -28
- package/dist/{detect-C_qmYsh9.d.cts → detect-BHYg26_d.d.cts} +1 -1
- package/dist/{detect-Dfd0upoz.d.ts → detect-Bf8Q_0dK.d.ts} +1 -1
- package/dist/host/index.cjs +14 -14
- package/dist/host/index.d.cts +3 -3
- package/dist/host/index.d.ts +3 -3
- package/dist/host/index.js +2 -2
- package/dist/index.cjs +28 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -26
- package/dist/index.d.ts +58 -26
- package/dist/index.js +3 -81
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +81 -140
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +66 -82
- package/dist/react/index.d.ts +66 -82
- package/dist/react/index.js +82 -136
- package/dist/react/index.js.map +1 -1
- package/dist/{server-ERRDGEZ7.js → server-5N76YCWC.js} +3 -3
- package/dist/{server-ERRDGEZ7.js.map → server-5N76YCWC.js.map} +1 -1
- package/dist/{server-P54IYX2G.cjs → server-QIYIJHD5.cjs} +3 -3
- package/dist/{server-P54IYX2G.cjs.map → server-QIYIJHD5.cjs.map} +1 -1
- package/dist/synapse-runtime.iife.global.js +28 -28
- package/dist/synapse-ui.iife.global.js +2 -2
- package/dist/{types-BSZasM8q.d.cts → types-uEO4VFJ2.d.cts} +87 -166
- package/dist/{types-BSZasM8q.d.ts → types-uEO4VFJ2.d.ts} +87 -166
- package/dist/vite/index.cjs +1 -1
- package/dist/vite/index.cjs.map +1 -1
- package/dist/vite/index.js +1 -1
- package/dist/vite/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-GNTQJSQX.js.map +0 -1
- package/dist/chunk-J5ICAHK2.js.map +0 -1
- package/dist/chunk-RYWW6EHB.cjs.map +0 -1
- package/dist/chunk-ZMNYUGSF.cjs.map +0 -1
|
@@ -1,446 +1,66 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { INITIALIZE_METHOD, LATEST_PROTOCOL_VERSION, HOST_CONTEXT_CHANGED_METHOD, INITIALIZED_METHOD, MESSAGE_METHOD, OPEN_LINK_METHOD,
|
|
1
|
+
import { detectHost, foldFontFaces, applyTheme, fontFacesKey, extractTheme } from './chunk-UPDBDXQB.js';
|
|
2
|
+
import { INITIALIZE_METHOD, LATEST_PROTOCOL_VERSION, HOST_CONTEXT_CHANGED_METHOD, INITIALIZED_METHOD, MESSAGE_METHOD, OPEN_LINK_METHOD, RESOURCE_TEARDOWN_METHOD, TOOL_CANCELLED_METHOD, TOOL_INPUT_PARTIAL_METHOD, TOOL_INPUT_METHOD, TOOL_RESULT_METHOD } from '@modelcontextprotocol/ext-apps';
|
|
3
3
|
|
|
4
|
-
// src/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
).map((block) => block.text);
|
|
16
|
-
if (texts.length > 0) {
|
|
17
|
-
const joined = texts.join("");
|
|
18
|
-
try {
|
|
19
|
-
return { content: JSON.parse(joined), structuredContent: null, raw };
|
|
20
|
-
} catch {
|
|
21
|
-
return { content: joined, structuredContent: null, raw };
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return { content: rawContent, structuredContent: null, raw };
|
|
25
|
-
}
|
|
26
|
-
if (typeof rawContent === "string") {
|
|
27
|
-
try {
|
|
28
|
-
return { content: JSON.parse(rawContent), structuredContent: null, raw };
|
|
29
|
-
} catch {
|
|
30
|
-
return { content: rawContent, structuredContent: null, raw };
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return { content: rawContent ?? null, structuredContent: null, raw };
|
|
34
|
-
}
|
|
35
|
-
var EVENT_MAP = {
|
|
36
|
-
"tool-result": TOOL_RESULT_METHOD,
|
|
37
|
-
"tool-input": TOOL_INPUT_METHOD,
|
|
38
|
-
"tool-input-partial": TOOL_INPUT_PARTIAL_METHOD,
|
|
39
|
-
"tool-cancelled": TOOL_CANCELLED_METHOD,
|
|
40
|
-
"theme-changed": HOST_CONTEXT_CHANGED_METHOD,
|
|
41
|
-
teardown: RESOURCE_TEARDOWN_METHOD
|
|
42
|
-
};
|
|
43
|
-
function resolveEventMethod(name) {
|
|
44
|
-
return EVENT_MAP[name] ?? name;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// src/resize.ts
|
|
48
|
-
function createResizer(send, autoResize) {
|
|
49
|
-
let destroyed = false;
|
|
50
|
-
let observer = null;
|
|
51
|
-
let rafId = null;
|
|
52
|
-
function measureAndSend() {
|
|
53
|
-
if (destroyed) return;
|
|
54
|
-
const width = document.body.scrollWidth;
|
|
55
|
-
const height = document.body.scrollHeight;
|
|
56
|
-
send("ui/notifications/size-changed", { width, height });
|
|
57
|
-
}
|
|
58
|
-
function resize(width, height) {
|
|
59
|
-
if (destroyed) return;
|
|
60
|
-
if (width !== void 0 && height !== void 0) {
|
|
61
|
-
send("ui/notifications/size-changed", { width, height });
|
|
62
|
-
} else {
|
|
63
|
-
measureAndSend();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if (autoResize && typeof ResizeObserver !== "undefined") {
|
|
67
|
-
observer = new ResizeObserver(() => {
|
|
68
|
-
if (destroyed) return;
|
|
69
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
70
|
-
rafId = requestAnimationFrame(() => {
|
|
71
|
-
rafId = null;
|
|
72
|
-
measureAndSend();
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
observer.observe(document.body);
|
|
76
|
-
}
|
|
77
|
-
function destroy() {
|
|
78
|
-
if (destroyed) return;
|
|
79
|
-
destroyed = true;
|
|
80
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
81
|
-
observer?.disconnect();
|
|
82
|
-
observer = null;
|
|
83
|
-
}
|
|
84
|
-
return { resize, measureAndSend, destroy };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/result-parser.ts
|
|
88
|
-
function parseToolResult(raw) {
|
|
89
|
-
if (raw == null) {
|
|
90
|
-
return { data: null, isError: false };
|
|
91
|
-
}
|
|
92
|
-
if (isCallToolResult(raw)) {
|
|
93
|
-
return parseCallToolResult(raw);
|
|
94
|
-
}
|
|
95
|
-
return { data: raw, isError: false };
|
|
96
|
-
}
|
|
97
|
-
function isCallToolResult(value) {
|
|
98
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
return Array.isArray(value.content);
|
|
102
|
-
}
|
|
103
|
-
function isTextBlock(block) {
|
|
104
|
-
if (block === null || typeof block !== "object" || Array.isArray(block)) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
const obj = block;
|
|
108
|
-
return obj.type === "text" && typeof obj.text === "string";
|
|
109
|
-
}
|
|
110
|
-
function extractMeta(result) {
|
|
111
|
-
const meta = result._meta;
|
|
112
|
-
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return void 0;
|
|
113
|
-
return { ...meta };
|
|
114
|
-
}
|
|
115
|
-
function parseCallToolResult(result) {
|
|
116
|
-
const isError = result.isError === true;
|
|
117
|
-
const content = result.content;
|
|
118
|
-
const meta = extractMeta(result);
|
|
119
|
-
if (content.length === 0) {
|
|
120
|
-
return { data: null, isError, content, ...meta && { _meta: meta } };
|
|
121
|
-
}
|
|
122
|
-
const firstText = content.find(isTextBlock);
|
|
123
|
-
if (!firstText) {
|
|
124
|
-
return { data: content, isError, content, ...meta && { _meta: meta } };
|
|
125
|
-
}
|
|
126
|
-
try {
|
|
127
|
-
return { data: JSON.parse(firstText.text), isError, content, ...meta && { _meta: meta } };
|
|
128
|
-
} catch {
|
|
129
|
-
return { data: firstText.text, isError, content, ...meta && { _meta: meta } };
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// src/transport.ts
|
|
134
|
-
var SynapseTransport = class {
|
|
135
|
-
counter = 0;
|
|
136
|
-
destroyed = false;
|
|
137
|
-
pending = /* @__PURE__ */ new Map();
|
|
138
|
-
handlers = /* @__PURE__ */ new Map();
|
|
139
|
-
listener;
|
|
140
|
-
constructor() {
|
|
141
|
-
this.listener = (event) => this.handleMessage(event);
|
|
142
|
-
window.addEventListener("message", this.listener);
|
|
143
|
-
}
|
|
144
|
-
send(method, params) {
|
|
145
|
-
if (this.destroyed) return;
|
|
146
|
-
const msg = {
|
|
147
|
-
jsonrpc: "2.0",
|
|
148
|
-
method,
|
|
149
|
-
...params !== void 0 && { params }
|
|
150
|
-
};
|
|
151
|
-
window.parent.postMessage(msg, "*");
|
|
152
|
-
}
|
|
153
|
-
request(method, params) {
|
|
154
|
-
if (this.destroyed) {
|
|
155
|
-
return Promise.reject(new Error("Transport destroyed"));
|
|
156
|
-
}
|
|
157
|
-
const id = `syn-${++this.counter}`;
|
|
158
|
-
const msg = {
|
|
159
|
-
jsonrpc: "2.0",
|
|
160
|
-
method,
|
|
161
|
-
id,
|
|
162
|
-
...params !== void 0 && { params }
|
|
163
|
-
};
|
|
164
|
-
return new Promise((resolve, reject) => {
|
|
165
|
-
this.pending.set(id, { resolve, reject });
|
|
166
|
-
window.parent.postMessage(msg, "*");
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
onMessage(method, callback) {
|
|
170
|
-
if (!this.handlers.has(method)) {
|
|
171
|
-
this.handlers.set(method, /* @__PURE__ */ new Set());
|
|
172
|
-
}
|
|
173
|
-
this.handlers.get(method)?.add(callback);
|
|
174
|
-
return () => {
|
|
175
|
-
const set = this.handlers.get(method);
|
|
176
|
-
if (set) {
|
|
177
|
-
set.delete(callback);
|
|
178
|
-
if (set.size === 0) {
|
|
179
|
-
this.handlers.delete(method);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
destroy() {
|
|
185
|
-
if (this.destroyed) return;
|
|
186
|
-
this.destroyed = true;
|
|
187
|
-
window.removeEventListener("message", this.listener);
|
|
188
|
-
const error = new Error("Transport destroyed");
|
|
189
|
-
for (const entry of this.pending.values()) {
|
|
190
|
-
entry.reject(error);
|
|
191
|
-
}
|
|
192
|
-
this.pending.clear();
|
|
193
|
-
this.handlers.clear();
|
|
194
|
-
}
|
|
195
|
-
handleMessage(event) {
|
|
196
|
-
if (this.destroyed) return;
|
|
197
|
-
const data = event.data;
|
|
198
|
-
if (!data || data.jsonrpc !== "2.0") return;
|
|
199
|
-
if ("id" in data && data.id && !("method" in data)) {
|
|
200
|
-
const response = data;
|
|
201
|
-
const entry = this.pending.get(response.id);
|
|
202
|
-
if (!entry) return;
|
|
203
|
-
this.pending.delete(response.id);
|
|
204
|
-
if (response.error) {
|
|
205
|
-
const err = new Error(response.error.message);
|
|
206
|
-
err.code = response.error.code;
|
|
207
|
-
err.data = response.error.data;
|
|
208
|
-
entry.reject(err);
|
|
209
|
-
} else {
|
|
210
|
-
entry.resolve(response.result);
|
|
211
|
-
}
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
if ("method" in data && !("id" in data && data.id)) {
|
|
215
|
-
const notification = data;
|
|
216
|
-
const set = this.handlers.get(notification.method);
|
|
217
|
-
if (set) {
|
|
218
|
-
for (const handler of set) {
|
|
219
|
-
handler(notification.params);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
// src/connect.ts
|
|
227
|
-
var READ_RESOURCE_METHOD = "resources/read";
|
|
228
|
-
async function connect(options) {
|
|
229
|
-
const { name, version, autoResize = false } = options;
|
|
230
|
-
const transport = new SynapseTransport();
|
|
231
|
-
let destroyed = false;
|
|
232
|
-
let currentTheme = { mode: "light", tokens: {} };
|
|
233
|
-
let hostInfo = { name: "unknown", version: "unknown" };
|
|
234
|
-
let toolInfo = null;
|
|
235
|
-
let containerDimensions = null;
|
|
236
|
-
const handlers = /* @__PURE__ */ new Map();
|
|
237
|
-
const resizer = createResizer((method, params) => transport.send(method, params), autoResize);
|
|
238
|
-
resizer.measureAndSend();
|
|
239
|
-
const initParams = {
|
|
240
|
-
protocolVersion: LATEST_PROTOCOL_VERSION,
|
|
241
|
-
appInfo: { name, version },
|
|
242
|
-
appCapabilities: {}
|
|
243
|
-
};
|
|
244
|
-
const result = await transport.request(
|
|
245
|
-
INITIALIZE_METHOD,
|
|
246
|
-
initParams
|
|
247
|
-
);
|
|
248
|
-
if (result) {
|
|
249
|
-
hostInfo = {
|
|
250
|
-
name: result.hostInfo?.name ?? "unknown",
|
|
251
|
-
version: result.hostInfo?.version ?? "unknown"
|
|
252
|
-
};
|
|
253
|
-
const ctx = result.hostContext;
|
|
254
|
-
if (ctx) {
|
|
255
|
-
const initialFontFaces = extractFontFaces(ctx);
|
|
256
|
-
currentTheme = {
|
|
257
|
-
mode: ctx.theme === "dark" ? "dark" : "light",
|
|
258
|
-
tokens: ctx.styles?.variables && typeof ctx.styles.variables === "object" ? ctx.styles.variables : {},
|
|
259
|
-
...initialFontFaces ? { fontFaces: initialFontFaces } : {}
|
|
260
|
-
};
|
|
261
|
-
if (ctx.toolInfo && typeof ctx.toolInfo === "object") {
|
|
262
|
-
toolInfo = { tool: ctx.toolInfo.tool ?? {} };
|
|
263
|
-
}
|
|
264
|
-
if (ctx.containerDimensions && typeof ctx.containerDimensions === "object") {
|
|
265
|
-
containerDimensions = ctx.containerDimensions;
|
|
266
|
-
}
|
|
267
|
-
applyTheme(currentTheme.mode, currentTheme.tokens, currentTheme.fontFaces);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
transport.onMessage(HOST_CONTEXT_CHANGED_METHOD, (params) => {
|
|
271
|
-
if (destroyed || !params) return;
|
|
272
|
-
const ctx = params;
|
|
273
|
-
const mode = ctx.theme === "dark" ? "dark" : "light";
|
|
274
|
-
const variables = ctx.styles?.variables;
|
|
275
|
-
const tokens = variables && typeof variables === "object" ? variables : currentTheme.tokens;
|
|
276
|
-
const fontFaces = foldFontFaces(currentTheme.fontFaces, ctx);
|
|
277
|
-
currentTheme = { mode, tokens, ...fontFaces ? { fontFaces } : {} };
|
|
278
|
-
applyTheme(mode, tokens, fontFaces);
|
|
279
|
-
const set = handlers.get(HOST_CONTEXT_CHANGED_METHOD);
|
|
280
|
-
if (set) {
|
|
281
|
-
for (const handler of set) handler(currentTheme);
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
const subscribedMethods = /* @__PURE__ */ new Set([HOST_CONTEXT_CHANGED_METHOD]);
|
|
285
|
-
function ensureTransportSub(method) {
|
|
286
|
-
if (subscribedMethods.has(method)) return;
|
|
287
|
-
subscribedMethods.add(method);
|
|
288
|
-
const isToolResult = method === TOOL_RESULT_METHOD;
|
|
289
|
-
transport.onMessage(method, (params) => {
|
|
290
|
-
if (destroyed) return;
|
|
291
|
-
const set = handlers.get(method);
|
|
292
|
-
if (!set) return;
|
|
293
|
-
for (const handler of set) {
|
|
294
|
-
if (isToolResult) {
|
|
295
|
-
handler(parseToolResultParams(params));
|
|
296
|
-
} else {
|
|
297
|
-
handler(params);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
if (options.on) {
|
|
303
|
-
for (const [event, handler] of Object.entries(options.on)) {
|
|
304
|
-
if (typeof handler === "function") {
|
|
305
|
-
const method = resolveEventMethod(event);
|
|
306
|
-
if (!handlers.has(method)) handlers.set(method, /* @__PURE__ */ new Set());
|
|
307
|
-
handlers.get(method)?.add(handler);
|
|
308
|
-
ensureTransportSub(method);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
transport.send(INITIALIZED_METHOD, {});
|
|
313
|
-
const app = {
|
|
314
|
-
get theme() {
|
|
315
|
-
return { ...currentTheme };
|
|
316
|
-
},
|
|
317
|
-
get hostInfo() {
|
|
318
|
-
return { ...hostInfo };
|
|
319
|
-
},
|
|
320
|
-
get toolInfo() {
|
|
321
|
-
return toolInfo;
|
|
322
|
-
},
|
|
323
|
-
get containerDimensions() {
|
|
324
|
-
return containerDimensions;
|
|
325
|
-
},
|
|
326
|
-
on(event, handler) {
|
|
327
|
-
const method = resolveEventMethod(event);
|
|
328
|
-
if (!handlers.has(method)) {
|
|
329
|
-
handlers.set(method, /* @__PURE__ */ new Set());
|
|
330
|
-
}
|
|
331
|
-
handlers.get(method)?.add(handler);
|
|
332
|
-
ensureTransportSub(method);
|
|
333
|
-
return () => {
|
|
334
|
-
const set = handlers.get(method);
|
|
335
|
-
if (set) {
|
|
336
|
-
set.delete(handler);
|
|
337
|
-
if (set.size === 0) handlers.delete(method);
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
},
|
|
341
|
-
resize(width, height) {
|
|
342
|
-
resizer.resize(width, height);
|
|
343
|
-
},
|
|
344
|
-
openLink(url) {
|
|
345
|
-
if (destroyed) return;
|
|
346
|
-
const params = { url };
|
|
347
|
-
transport.request(OPEN_LINK_METHOD, params).catch(() => {
|
|
348
|
-
});
|
|
349
|
-
},
|
|
350
|
-
updateModelContext(state, summary) {
|
|
351
|
-
if (destroyed) return;
|
|
352
|
-
const params = {
|
|
353
|
-
structuredContent: state,
|
|
354
|
-
...summary !== void 0 && {
|
|
355
|
-
content: [{ type: "text", text: summary }]
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
|
-
transport.send("ui/update-model-context", params);
|
|
359
|
-
},
|
|
360
|
-
async callTool(toolName, args) {
|
|
361
|
-
const params = {
|
|
362
|
-
name: toolName,
|
|
363
|
-
arguments: args ?? {}
|
|
364
|
-
};
|
|
365
|
-
const raw = await transport.request(
|
|
366
|
-
"tools/call",
|
|
367
|
-
params
|
|
368
|
-
);
|
|
369
|
-
return parseToolResult(raw);
|
|
370
|
-
},
|
|
371
|
-
async readServerResource(params) {
|
|
372
|
-
const raw = await transport.request(
|
|
373
|
-
READ_RESOURCE_METHOD,
|
|
374
|
-
params
|
|
375
|
-
);
|
|
376
|
-
return raw;
|
|
377
|
-
},
|
|
378
|
-
sendMessage(text, context) {
|
|
379
|
-
if (destroyed) return;
|
|
380
|
-
const textBlock = {
|
|
381
|
-
type: "text",
|
|
382
|
-
text,
|
|
383
|
-
...context && { _meta: { context } }
|
|
384
|
-
};
|
|
385
|
-
const params = {
|
|
386
|
-
role: "user",
|
|
387
|
-
content: [textBlock]
|
|
388
|
-
};
|
|
389
|
-
transport.send(MESSAGE_METHOD, params);
|
|
390
|
-
},
|
|
391
|
-
destroy() {
|
|
392
|
-
if (destroyed) return;
|
|
393
|
-
destroyed = true;
|
|
394
|
-
resizer.destroy();
|
|
395
|
-
handlers.clear();
|
|
396
|
-
transport.destroy();
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
return app;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// src/keyboard.ts
|
|
403
|
-
var KeyboardForwarder = class {
|
|
404
|
-
listener;
|
|
405
|
-
destroyed = false;
|
|
406
|
-
constructor(transport, customKeys) {
|
|
407
|
-
const config = customKeys ?? null;
|
|
408
|
-
this.listener = (event) => {
|
|
409
|
-
if (this.destroyed) return;
|
|
410
|
-
if (this.shouldForward(event, config)) {
|
|
411
|
-
event.preventDefault();
|
|
412
|
-
transport.send("synapse/keydown", {
|
|
413
|
-
key: event.key,
|
|
414
|
-
ctrlKey: event.ctrlKey,
|
|
415
|
-
metaKey: event.metaKey,
|
|
416
|
-
shiftKey: event.shiftKey,
|
|
417
|
-
altKey: event.altKey
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
};
|
|
421
|
-
document.addEventListener("keydown", this.listener);
|
|
4
|
+
// src/internals.ts
|
|
5
|
+
var INTERNALS = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
function registerInternals(app, internals) {
|
|
7
|
+
INTERNALS.set(app, internals);
|
|
8
|
+
}
|
|
9
|
+
function internalsFor(app) {
|
|
10
|
+
const internals = INTERNALS.get(app);
|
|
11
|
+
if (!internals) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
"This App did not come from this copy of @nimblebrain/synapse. Two copies of the package are installed (check for a duplicate in your lockfile, or a bundler resolving the ESM and CJS builds separately)."
|
|
14
|
+
);
|
|
422
15
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
16
|
+
return internals;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/result-parser.ts
|
|
20
|
+
function parseToolResult(raw) {
|
|
21
|
+
if (raw == null) {
|
|
22
|
+
return { data: null, isError: false };
|
|
427
23
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
if (event.key === "Escape") return true;
|
|
436
|
-
if (event.ctrlKey || event.metaKey) {
|
|
437
|
-
const key = event.key.toLowerCase();
|
|
438
|
-
if (key === "c" || key === "v" || key === "x" || key === "a") return false;
|
|
439
|
-
return true;
|
|
440
|
-
}
|
|
24
|
+
if (isCallToolResult(raw)) {
|
|
25
|
+
return parseCallToolResult(raw);
|
|
26
|
+
}
|
|
27
|
+
return { data: raw, isError: false };
|
|
28
|
+
}
|
|
29
|
+
function isCallToolResult(value) {
|
|
30
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
441
31
|
return false;
|
|
442
32
|
}
|
|
443
|
-
|
|
33
|
+
return Array.isArray(value.content);
|
|
34
|
+
}
|
|
35
|
+
function isTextBlock(block) {
|
|
36
|
+
if (block === null || typeof block !== "object" || Array.isArray(block)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const obj = block;
|
|
40
|
+
return obj.type === "text" && typeof obj.text === "string";
|
|
41
|
+
}
|
|
42
|
+
function extractMeta(result) {
|
|
43
|
+
const meta = result._meta;
|
|
44
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return void 0;
|
|
45
|
+
return { ...meta };
|
|
46
|
+
}
|
|
47
|
+
function parseCallToolResult(result) {
|
|
48
|
+
const isError = result.isError === true;
|
|
49
|
+
const content = result.content;
|
|
50
|
+
const meta = extractMeta(result);
|
|
51
|
+
if (content.length === 0) {
|
|
52
|
+
return { data: null, isError, content, ...meta && { _meta: meta } };
|
|
53
|
+
}
|
|
54
|
+
const firstText = content.find(isTextBlock);
|
|
55
|
+
if (!firstText) {
|
|
56
|
+
return { data: content, isError, content, ...meta && { _meta: meta } };
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
return { data: JSON.parse(firstText.text), isError, content, ...meta && { _meta: meta } };
|
|
60
|
+
} catch {
|
|
61
|
+
return { data: firstText.text, isError, content, ...meta && { _meta: meta } };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
444
64
|
|
|
445
65
|
// src/task-handle.ts
|
|
446
66
|
var TOOLS_CALL_METHOD = "tools/call";
|
|
@@ -485,11 +105,12 @@ function createTaskStatusRouter(transport) {
|
|
|
485
105
|
}
|
|
486
106
|
};
|
|
487
107
|
}
|
|
488
|
-
async function callToolAsTask(
|
|
489
|
-
const
|
|
108
|
+
async function callToolAsTask(app, toolName, args, options) {
|
|
109
|
+
const deps = internalsFor(app);
|
|
110
|
+
const hostTasks = deps.hostTasksCapability;
|
|
490
111
|
if (!hostTasks?.requests?.tools?.call) {
|
|
491
112
|
throw new Error(
|
|
492
|
-
"callToolAsTask: host did not advertise tasks.requests.tools.call in its capabilities. Per MCP 2025-11-25 \xA7, requestors MUST NOT task-augment a tools/call without matching receiver capability. Fall back to `
|
|
113
|
+
"callToolAsTask: host did not advertise tasks.requests.tools.call in its capabilities. Per MCP 2025-11-25 \xA7, requestors MUST NOT task-augment a tools/call without matching receiver capability. Fall back to `app.callTool`."
|
|
493
114
|
);
|
|
494
115
|
}
|
|
495
116
|
const taskParam = {};
|
|
@@ -501,7 +122,7 @@ async function callToolAsTask(deps, toolName, args, options) {
|
|
|
501
122
|
task: taskParam,
|
|
502
123
|
...crossServer ? { server: deps.appName } : {}
|
|
503
124
|
};
|
|
504
|
-
const raw = await deps.
|
|
125
|
+
const raw = await deps.request(
|
|
505
126
|
TOOLS_CALL_METHOD,
|
|
506
127
|
callParams
|
|
507
128
|
);
|
|
@@ -518,7 +139,7 @@ async function callToolAsTask(deps, toolName, args, options) {
|
|
|
518
139
|
task: initialTask,
|
|
519
140
|
async result() {
|
|
520
141
|
const params = { taskId };
|
|
521
|
-
const rawResult = await deps.
|
|
142
|
+
const rawResult = await deps.request(
|
|
522
143
|
TASKS_RESULT_METHOD,
|
|
523
144
|
params
|
|
524
145
|
);
|
|
@@ -527,7 +148,7 @@ async function callToolAsTask(deps, toolName, args, options) {
|
|
|
527
148
|
},
|
|
528
149
|
async refresh() {
|
|
529
150
|
const params = { taskId };
|
|
530
|
-
const raw2 = await deps.
|
|
151
|
+
const raw2 = await deps.request(
|
|
531
152
|
TASKS_GET_METHOD,
|
|
532
153
|
params
|
|
533
154
|
);
|
|
@@ -535,7 +156,7 @@ async function callToolAsTask(deps, toolName, args, options) {
|
|
|
535
156
|
},
|
|
536
157
|
async cancel() {
|
|
537
158
|
const params = { taskId };
|
|
538
|
-
const raw2 = await deps.
|
|
159
|
+
const raw2 = await deps.request(
|
|
539
160
|
TASKS_CANCEL_METHOD,
|
|
540
161
|
params
|
|
541
162
|
);
|
|
@@ -544,7 +165,7 @@ async function callToolAsTask(deps, toolName, args, options) {
|
|
|
544
165
|
onStatus(cb) {
|
|
545
166
|
const existing = localCallbacks.get(cb);
|
|
546
167
|
if (existing) return existing;
|
|
547
|
-
const wireUnsub = deps.
|
|
168
|
+
const wireUnsub = deps.taskRouter.subscribe(taskId, (update) => {
|
|
548
169
|
const merged = {
|
|
549
170
|
taskId: update.taskId,
|
|
550
171
|
status: update.status,
|
|
@@ -565,42 +186,269 @@ async function callToolAsTask(deps, toolName, args, options) {
|
|
|
565
186
|
localCallbacks.set(cb, unsub);
|
|
566
187
|
return unsub;
|
|
567
188
|
}
|
|
568
|
-
};
|
|
569
|
-
return handle;
|
|
570
|
-
}
|
|
571
|
-
function projectTask(raw) {
|
|
572
|
-
return {
|
|
573
|
-
taskId: raw.taskId,
|
|
574
|
-
status: raw.status,
|
|
575
|
-
ttl: raw.ttl,
|
|
576
|
-
createdAt: raw.createdAt,
|
|
577
|
-
lastUpdatedAt: raw.lastUpdatedAt,
|
|
578
|
-
...raw.pollInterval !== void 0 && { pollInterval: raw.pollInterval },
|
|
579
|
-
...raw.statusMessage !== void 0 && { statusMessage: raw.statusMessage }
|
|
580
|
-
};
|
|
581
|
-
}
|
|
189
|
+
};
|
|
190
|
+
return handle;
|
|
191
|
+
}
|
|
192
|
+
function projectTask(raw) {
|
|
193
|
+
return {
|
|
194
|
+
taskId: raw.taskId,
|
|
195
|
+
status: raw.status,
|
|
196
|
+
ttl: raw.ttl,
|
|
197
|
+
createdAt: raw.createdAt,
|
|
198
|
+
lastUpdatedAt: raw.lastUpdatedAt,
|
|
199
|
+
...raw.pollInterval !== void 0 && { pollInterval: raw.pollInterval },
|
|
200
|
+
...raw.statusMessage !== void 0 && { statusMessage: raw.statusMessage }
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/content-parser.ts
|
|
205
|
+
function parseToolResultParams(params) {
|
|
206
|
+
const raw = params ?? {};
|
|
207
|
+
const structuredContent = raw.structuredContent ?? null;
|
|
208
|
+
if (structuredContent != null) {
|
|
209
|
+
return { content: structuredContent, structuredContent, raw };
|
|
210
|
+
}
|
|
211
|
+
const rawContent = raw.content;
|
|
212
|
+
if (Array.isArray(rawContent)) {
|
|
213
|
+
const texts = rawContent.filter(
|
|
214
|
+
(block) => block != null && typeof block === "object" && block.type === "text" && typeof block.text === "string"
|
|
215
|
+
).map((block) => block.text);
|
|
216
|
+
if (texts.length > 0) {
|
|
217
|
+
const joined = texts.join("");
|
|
218
|
+
try {
|
|
219
|
+
return { content: JSON.parse(joined), structuredContent: null, raw };
|
|
220
|
+
} catch {
|
|
221
|
+
return { content: joined, structuredContent: null, raw };
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return { content: rawContent, structuredContent: null, raw };
|
|
225
|
+
}
|
|
226
|
+
if (typeof rawContent === "string") {
|
|
227
|
+
try {
|
|
228
|
+
return { content: JSON.parse(rawContent), structuredContent: null, raw };
|
|
229
|
+
} catch {
|
|
230
|
+
return { content: rawContent, structuredContent: null, raw };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return { content: rawContent ?? null, structuredContent: null, raw };
|
|
234
|
+
}
|
|
235
|
+
var DATA_CHANGED_METHOD = "synapse/data-changed";
|
|
236
|
+
var ACTION_METHOD = "synapse/action";
|
|
237
|
+
var REQUEST_FILE_METHOD = "synapse/request-file";
|
|
238
|
+
var DOWNLOAD_FILE_METHOD = "synapse/download-file";
|
|
239
|
+
var EVENT_MAP = {
|
|
240
|
+
"tool-result": TOOL_RESULT_METHOD,
|
|
241
|
+
"tool-input": TOOL_INPUT_METHOD,
|
|
242
|
+
"tool-input-partial": TOOL_INPUT_PARTIAL_METHOD,
|
|
243
|
+
"tool-cancelled": TOOL_CANCELLED_METHOD,
|
|
244
|
+
teardown: RESOURCE_TEARDOWN_METHOD
|
|
245
|
+
};
|
|
246
|
+
function resolveEventMethod(name) {
|
|
247
|
+
return EVENT_MAP[name] ?? name;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/keyboard.ts
|
|
251
|
+
var KeyboardForwarder = class {
|
|
252
|
+
listener;
|
|
253
|
+
destroyed = false;
|
|
254
|
+
constructor(transport, customKeys) {
|
|
255
|
+
const config = customKeys ?? null;
|
|
256
|
+
this.listener = (event) => {
|
|
257
|
+
if (this.destroyed) return;
|
|
258
|
+
if (this.shouldForward(event, config)) {
|
|
259
|
+
event.preventDefault();
|
|
260
|
+
transport.send("synapse/keydown", {
|
|
261
|
+
key: event.key,
|
|
262
|
+
ctrlKey: event.ctrlKey,
|
|
263
|
+
metaKey: event.metaKey,
|
|
264
|
+
shiftKey: event.shiftKey,
|
|
265
|
+
altKey: event.altKey
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
document.addEventListener("keydown", this.listener);
|
|
270
|
+
}
|
|
271
|
+
destroy() {
|
|
272
|
+
if (this.destroyed) return;
|
|
273
|
+
this.destroyed = true;
|
|
274
|
+
document.removeEventListener("keydown", this.listener);
|
|
275
|
+
}
|
|
276
|
+
shouldForward(event, config) {
|
|
277
|
+
if (config && config.length === 0) return false;
|
|
278
|
+
if (config) {
|
|
279
|
+
return config.some(
|
|
280
|
+
(k) => event.key.toLowerCase() === k.key.toLowerCase() && (k.ctrl === void 0 || event.ctrlKey === k.ctrl) && (k.meta === void 0 || event.metaKey === k.meta) && (k.shift === void 0 || event.shiftKey === k.shift) && (k.alt === void 0 || event.altKey === k.alt)
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
if (event.key === "Escape") return true;
|
|
284
|
+
if (event.ctrlKey || event.metaKey) {
|
|
285
|
+
const key = event.key.toLowerCase();
|
|
286
|
+
if (key === "c" || key === "v" || key === "x" || key === "a") return false;
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// src/resize.ts
|
|
294
|
+
function createResizer(send, autoResize) {
|
|
295
|
+
let destroyed = false;
|
|
296
|
+
let observer = null;
|
|
297
|
+
let rafId = null;
|
|
298
|
+
function measureAndSend() {
|
|
299
|
+
if (destroyed) return;
|
|
300
|
+
const width = document.body.scrollWidth;
|
|
301
|
+
const height = document.body.scrollHeight;
|
|
302
|
+
send("ui/notifications/size-changed", { width, height });
|
|
303
|
+
}
|
|
304
|
+
function resize(width, height) {
|
|
305
|
+
if (destroyed) return;
|
|
306
|
+
if (width !== void 0 && height !== void 0) {
|
|
307
|
+
send("ui/notifications/size-changed", { width, height });
|
|
308
|
+
} else {
|
|
309
|
+
measureAndSend();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (autoResize && typeof ResizeObserver !== "undefined") {
|
|
313
|
+
observer = new ResizeObserver(() => {
|
|
314
|
+
if (destroyed) return;
|
|
315
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
316
|
+
rafId = requestAnimationFrame(() => {
|
|
317
|
+
rafId = null;
|
|
318
|
+
measureAndSend();
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
observer.observe(document.body);
|
|
322
|
+
}
|
|
323
|
+
function destroy() {
|
|
324
|
+
if (destroyed) return;
|
|
325
|
+
destroyed = true;
|
|
326
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
327
|
+
observer?.disconnect();
|
|
328
|
+
observer = null;
|
|
329
|
+
}
|
|
330
|
+
return { resize, measureAndSend, destroy };
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/transport.ts
|
|
334
|
+
var SynapseTransport = class {
|
|
335
|
+
counter = 0;
|
|
336
|
+
destroyed = false;
|
|
337
|
+
pending = /* @__PURE__ */ new Map();
|
|
338
|
+
handlers = /* @__PURE__ */ new Map();
|
|
339
|
+
listener;
|
|
340
|
+
constructor() {
|
|
341
|
+
this.listener = (event) => this.handleMessage(event);
|
|
342
|
+
window.addEventListener("message", this.listener);
|
|
343
|
+
}
|
|
344
|
+
send(method, params) {
|
|
345
|
+
if (this.destroyed) return;
|
|
346
|
+
const msg = {
|
|
347
|
+
jsonrpc: "2.0",
|
|
348
|
+
method,
|
|
349
|
+
...params !== void 0 && { params }
|
|
350
|
+
};
|
|
351
|
+
window.parent.postMessage(msg, "*");
|
|
352
|
+
}
|
|
353
|
+
request(method, params) {
|
|
354
|
+
if (this.destroyed) {
|
|
355
|
+
return Promise.reject(new Error("Transport destroyed"));
|
|
356
|
+
}
|
|
357
|
+
const id = `syn-${++this.counter}`;
|
|
358
|
+
const msg = {
|
|
359
|
+
jsonrpc: "2.0",
|
|
360
|
+
method,
|
|
361
|
+
id,
|
|
362
|
+
...params !== void 0 && { params }
|
|
363
|
+
};
|
|
364
|
+
return new Promise((resolve, reject) => {
|
|
365
|
+
this.pending.set(id, { resolve, reject });
|
|
366
|
+
window.parent.postMessage(msg, "*");
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
onMessage(method, callback) {
|
|
370
|
+
if (!this.handlers.has(method)) {
|
|
371
|
+
this.handlers.set(method, /* @__PURE__ */ new Set());
|
|
372
|
+
}
|
|
373
|
+
this.handlers.get(method)?.add(callback);
|
|
374
|
+
return () => {
|
|
375
|
+
const set = this.handlers.get(method);
|
|
376
|
+
if (set) {
|
|
377
|
+
set.delete(callback);
|
|
378
|
+
if (set.size === 0) {
|
|
379
|
+
this.handlers.delete(method);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
destroy() {
|
|
385
|
+
if (this.destroyed) return;
|
|
386
|
+
this.destroyed = true;
|
|
387
|
+
window.removeEventListener("message", this.listener);
|
|
388
|
+
const error = new Error("Transport destroyed");
|
|
389
|
+
for (const entry of this.pending.values()) {
|
|
390
|
+
entry.reject(error);
|
|
391
|
+
}
|
|
392
|
+
this.pending.clear();
|
|
393
|
+
this.handlers.clear();
|
|
394
|
+
}
|
|
395
|
+
handleMessage(event) {
|
|
396
|
+
if (this.destroyed) return;
|
|
397
|
+
const data = event.data;
|
|
398
|
+
if (!data || data.jsonrpc !== "2.0") return;
|
|
399
|
+
if ("id" in data && data.id && !("method" in data)) {
|
|
400
|
+
const response = data;
|
|
401
|
+
const entry = this.pending.get(response.id);
|
|
402
|
+
if (!entry) return;
|
|
403
|
+
this.pending.delete(response.id);
|
|
404
|
+
if (response.error) {
|
|
405
|
+
const err = new Error(response.error.message);
|
|
406
|
+
err.code = response.error.code;
|
|
407
|
+
err.data = response.error.data;
|
|
408
|
+
entry.reject(err);
|
|
409
|
+
} else {
|
|
410
|
+
entry.resolve(response.result);
|
|
411
|
+
}
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
if ("method" in data && !("id" in data && data.id)) {
|
|
415
|
+
const notification = data;
|
|
416
|
+
const set = this.handlers.get(notification.method);
|
|
417
|
+
if (set) {
|
|
418
|
+
for (const handler of set) {
|
|
419
|
+
handler(notification.params);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
};
|
|
582
425
|
|
|
583
|
-
// src/
|
|
584
|
-
var
|
|
585
|
-
|
|
586
|
-
|
|
426
|
+
// src/connect.ts
|
|
427
|
+
var READ_RESOURCE_METHOD = "resources/read";
|
|
428
|
+
var UPDATE_MODEL_CONTEXT_METHOD = "ui/update-model-context";
|
|
429
|
+
async function connect(options) {
|
|
430
|
+
const { name, version, autoResize = false, internal = false, forwardKeys } = options;
|
|
587
431
|
const transport = new SynapseTransport();
|
|
588
|
-
let hostInfo = null;
|
|
589
|
-
let currentHostContext = {};
|
|
590
|
-
let currentFontFaces;
|
|
591
|
-
function syncFontFaces(ctx) {
|
|
592
|
-
currentFontFaces = foldFontFaces(currentFontFaces, ctx);
|
|
593
|
-
return currentFontFaces;
|
|
594
|
-
}
|
|
595
|
-
function resolveTheme(ctx) {
|
|
596
|
-
const theme = extractTheme(ctx);
|
|
597
|
-
return currentFontFaces ? { ...theme, fontFaces: currentFontFaces } : theme;
|
|
598
|
-
}
|
|
599
|
-
let hostTasksCapability = null;
|
|
600
432
|
let destroyed = false;
|
|
601
|
-
|
|
602
|
-
let
|
|
433
|
+
let hostContext = {};
|
|
434
|
+
let hostInfo = { name: "unknown", version: "unknown" };
|
|
435
|
+
let isNimbleBrainHost = false;
|
|
436
|
+
let toolInfo = null;
|
|
437
|
+
let containerDimensions = null;
|
|
438
|
+
let hostTasksCapability;
|
|
603
439
|
let keyboard = null;
|
|
440
|
+
let fontFaces;
|
|
441
|
+
function resolveTheme() {
|
|
442
|
+
const theme = extractTheme(hostContext);
|
|
443
|
+
return fontFaces ? { ...theme, fontFaces } : theme;
|
|
444
|
+
}
|
|
445
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
446
|
+
const themeCallbacks = /* @__PURE__ */ new Set();
|
|
447
|
+
const hostContextCallbacks = /* @__PURE__ */ new Set();
|
|
448
|
+
const dataCallbacks = /* @__PURE__ */ new Set();
|
|
449
|
+
const actionCallbacks = /* @__PURE__ */ new Set();
|
|
450
|
+
const resizer = createResizer((method, params) => transport.send(method, params), autoResize);
|
|
451
|
+
resizer.measureAndSend();
|
|
604
452
|
const appCapabilities = {
|
|
605
453
|
tasks: {
|
|
606
454
|
cancel: {},
|
|
@@ -612,30 +460,58 @@ function createSynapse(options) {
|
|
|
612
460
|
appInfo: { name, version },
|
|
613
461
|
appCapabilities
|
|
614
462
|
};
|
|
615
|
-
const
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
463
|
+
const result = await transport.request(
|
|
464
|
+
INITIALIZE_METHOD,
|
|
465
|
+
initParams
|
|
466
|
+
);
|
|
467
|
+
if (result) {
|
|
468
|
+
const detected = detectHost(result);
|
|
469
|
+
isNimbleBrainHost = detected.isNimbleBrain;
|
|
470
|
+
hostInfo = {
|
|
471
|
+
name: result.hostInfo?.name ?? "unknown",
|
|
472
|
+
version: result.hostInfo?.version ?? "unknown"
|
|
473
|
+
};
|
|
474
|
+
const rawTasks = result.hostCapabilities?.tasks;
|
|
620
475
|
hostTasksCapability = rawTasks && typeof rawTasks === "object" && !Array.isArray(rawTasks) ? rawTasks : void 0;
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
476
|
+
const ctx = result.hostContext;
|
|
477
|
+
if (ctx) {
|
|
478
|
+
hostContext = ctx;
|
|
479
|
+
fontFaces = foldFontFaces(fontFaces, ctx);
|
|
480
|
+
if (ctx.toolInfo && typeof ctx.toolInfo === "object") {
|
|
481
|
+
toolInfo = { tool: ctx.toolInfo.tool ?? {} };
|
|
482
|
+
}
|
|
483
|
+
if (ctx.containerDimensions && typeof ctx.containerDimensions === "object") {
|
|
484
|
+
containerDimensions = ctx.containerDimensions;
|
|
485
|
+
}
|
|
486
|
+
const theme = resolveTheme();
|
|
487
|
+
applyTheme(theme.mode, theme.tokens, theme.fontFaces);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (forwardKeys && isNimbleBrainHost) {
|
|
491
|
+
keyboard = new KeyboardForwarder(transport, forwardKeys === true ? void 0 : forwardKeys);
|
|
492
|
+
}
|
|
493
|
+
function fanOutRaw(method, params) {
|
|
494
|
+
const set = handlers.get(method);
|
|
495
|
+
if (!set) return;
|
|
496
|
+
for (const handler of set) handler(params);
|
|
497
|
+
}
|
|
498
|
+
transport.onMessage(HOST_CONTEXT_CHANGED_METHOD, (params) => {
|
|
499
|
+
if (destroyed) return;
|
|
500
|
+
const ctx = params ?? {};
|
|
501
|
+
const prevTheme = resolveTheme();
|
|
502
|
+
hostContext = { ...hostContext, ...ctx };
|
|
503
|
+
fontFaces = foldFontFaces(fontFaces, ctx);
|
|
504
|
+
const nextTheme = resolveTheme();
|
|
505
|
+
applyTheme(nextTheme.mode, nextTheme.tokens, nextTheme.fontFaces);
|
|
506
|
+
for (const cb of hostContextCallbacks) cb(hostContext);
|
|
507
|
+
fanOutRaw(HOST_CONTEXT_CHANGED_METHOD, params);
|
|
508
|
+
if (!themesEqual(prevTheme, nextTheme)) {
|
|
509
|
+
for (const cb of themeCallbacks) cb(nextTheme);
|
|
624
510
|
}
|
|
625
|
-
for (const cb of hostContextCallbacks) cb(currentHostContext);
|
|
626
|
-
transport.send(INITIALIZED_METHOD, {});
|
|
627
|
-
keyboard = new KeyboardForwarder(transport, forwardKeys);
|
|
628
|
-
});
|
|
629
|
-
const unsubHostContext = transport.onMessage(HOST_CONTEXT_CHANGED_METHOD, (params) => {
|
|
630
|
-
currentHostContext = params ?? {};
|
|
631
|
-
const theme = extractTheme(currentHostContext);
|
|
632
|
-
applyTheme(theme.mode, theme.tokens, syncFontFaces(currentHostContext));
|
|
633
|
-
for (const cb of hostContextCallbacks) cb(currentHostContext);
|
|
634
511
|
});
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
const unsubData = transport.onMessage("synapse/data-changed", (params) => {
|
|
512
|
+
transport.onMessage(DATA_CHANGED_METHOD, (params) => {
|
|
513
|
+
if (destroyed) return;
|
|
514
|
+
fanOutRaw(DATA_CHANGED_METHOD, params);
|
|
639
515
|
if (!params) return;
|
|
640
516
|
const event = {
|
|
641
517
|
source: "agent",
|
|
@@ -644,119 +520,157 @@ function createSynapse(options) {
|
|
|
644
520
|
};
|
|
645
521
|
for (const cb of dataCallbacks) cb(event);
|
|
646
522
|
});
|
|
647
|
-
|
|
523
|
+
transport.onMessage(ACTION_METHOD, (params) => {
|
|
524
|
+
if (destroyed) return;
|
|
525
|
+
fanOutRaw(ACTION_METHOD, params);
|
|
648
526
|
if (!params || typeof params.type !== "string") return;
|
|
649
|
-
const
|
|
527
|
+
const action2 = {
|
|
650
528
|
type: params.type,
|
|
651
529
|
payload: params.payload ?? {},
|
|
652
530
|
requiresConfirmation: params.requiresConfirmation === true,
|
|
653
531
|
label: typeof params.label === "string" ? params.label : void 0
|
|
654
532
|
};
|
|
655
|
-
for (const cb of actionCallbacks) cb(
|
|
533
|
+
for (const cb of actionCallbacks) cb(action2);
|
|
656
534
|
});
|
|
657
|
-
const
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
535
|
+
const subscribedMethods = /* @__PURE__ */ new Set([
|
|
536
|
+
HOST_CONTEXT_CHANGED_METHOD,
|
|
537
|
+
DATA_CHANGED_METHOD,
|
|
538
|
+
ACTION_METHOD
|
|
539
|
+
]);
|
|
540
|
+
function ensureTransportSub(method) {
|
|
541
|
+
if (subscribedMethods.has(method)) return;
|
|
542
|
+
subscribedMethods.add(method);
|
|
543
|
+
const isToolResult = method === TOOL_RESULT_METHOD;
|
|
544
|
+
transport.onMessage(method, (params) => {
|
|
545
|
+
if (destroyed) return;
|
|
546
|
+
const set = handlers.get(method);
|
|
547
|
+
if (!set) return;
|
|
548
|
+
for (const handler of set) {
|
|
549
|
+
if (isToolResult) {
|
|
550
|
+
handler(parseToolResultParams(params));
|
|
551
|
+
} else {
|
|
552
|
+
handler(params);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
function subscribe(event, handler) {
|
|
558
|
+
switch (event) {
|
|
559
|
+
case "theme-changed":
|
|
560
|
+
themeCallbacks.add(handler);
|
|
561
|
+
return () => {
|
|
562
|
+
themeCallbacks.delete(handler);
|
|
563
|
+
};
|
|
564
|
+
case "host-context-changed":
|
|
565
|
+
hostContextCallbacks.add(handler);
|
|
566
|
+
return () => {
|
|
567
|
+
hostContextCallbacks.delete(handler);
|
|
568
|
+
};
|
|
569
|
+
case "data-changed":
|
|
570
|
+
dataCallbacks.add(handler);
|
|
571
|
+
return () => {
|
|
572
|
+
dataCallbacks.delete(handler);
|
|
573
|
+
};
|
|
574
|
+
case "action":
|
|
575
|
+
actionCallbacks.add(handler);
|
|
576
|
+
return () => {
|
|
577
|
+
actionCallbacks.delete(handler);
|
|
578
|
+
};
|
|
579
|
+
default: {
|
|
580
|
+
const method = resolveEventMethod(event);
|
|
581
|
+
if (!handlers.has(method)) handlers.set(method, /* @__PURE__ */ new Set());
|
|
582
|
+
handlers.get(method)?.add(handler);
|
|
583
|
+
ensureTransportSub(method);
|
|
584
|
+
return () => {
|
|
585
|
+
const set = handlers.get(method);
|
|
586
|
+
if (set) {
|
|
587
|
+
set.delete(handler);
|
|
588
|
+
if (set.size === 0) handlers.delete(method);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
if (options.on) {
|
|
595
|
+
for (const [event, handler] of Object.entries(options.on)) {
|
|
596
|
+
if (typeof handler === "function") subscribe(event, handler);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
transport.send(INITIALIZED_METHOD, {});
|
|
600
|
+
const taskRouter = createTaskStatusRouter(transport);
|
|
601
|
+
const app = {
|
|
602
|
+
get theme() {
|
|
603
|
+
return resolveTheme();
|
|
604
|
+
},
|
|
605
|
+
get hostInfo() {
|
|
606
|
+
return { ...hostInfo };
|
|
607
|
+
},
|
|
608
|
+
get hostContext() {
|
|
609
|
+
return hostContext;
|
|
661
610
|
},
|
|
662
611
|
get isNimbleBrainHost() {
|
|
663
|
-
return
|
|
612
|
+
return isNimbleBrainHost;
|
|
613
|
+
},
|
|
614
|
+
get toolInfo() {
|
|
615
|
+
return toolInfo;
|
|
616
|
+
},
|
|
617
|
+
get containerDimensions() {
|
|
618
|
+
return containerDimensions;
|
|
664
619
|
},
|
|
665
620
|
get destroyed() {
|
|
666
621
|
return destroyed;
|
|
667
622
|
},
|
|
668
|
-
|
|
623
|
+
get supportsTasks() {
|
|
624
|
+
return hostTasksCapability?.requests?.tools?.call !== void 0;
|
|
625
|
+
},
|
|
626
|
+
on(event, handler) {
|
|
627
|
+
return subscribe(event, handler);
|
|
628
|
+
},
|
|
629
|
+
resize(width, height) {
|
|
630
|
+
resizer.resize(width, height);
|
|
631
|
+
},
|
|
632
|
+
openLink(url) {
|
|
633
|
+
if (destroyed) return;
|
|
634
|
+
const params = { url };
|
|
635
|
+
transport.request(OPEN_LINK_METHOD, params).catch(() => {
|
|
636
|
+
window.open(url, "_blank", "noopener");
|
|
637
|
+
});
|
|
638
|
+
},
|
|
639
|
+
updateModelContext(state, summary) {
|
|
640
|
+
if (destroyed) return;
|
|
641
|
+
const params = {
|
|
642
|
+
structuredContent: state,
|
|
643
|
+
...summary !== void 0 && {
|
|
644
|
+
content: [{ type: "text", text: summary }]
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
transport.send(UPDATE_MODEL_CONTEXT_METHOD, params);
|
|
648
|
+
},
|
|
649
|
+
async callTool(toolName, args, callOptions) {
|
|
650
|
+
const server = callOptions?.server ?? (internal ? name : void 0);
|
|
669
651
|
const params = {
|
|
670
652
|
name: toolName,
|
|
671
|
-
arguments: args ?? {}
|
|
653
|
+
arguments: args ?? {},
|
|
654
|
+
...server !== void 0 && { server }
|
|
672
655
|
};
|
|
673
|
-
|
|
674
|
-
params.server = name;
|
|
675
|
-
}
|
|
676
|
-
const raw = await transport.request("tools/call", params);
|
|
656
|
+
const raw = await transport.request(TOOLS_CALL_METHOD, params);
|
|
677
657
|
return parseToolResult(raw);
|
|
678
658
|
},
|
|
679
|
-
async
|
|
680
|
-
return callToolAsTask(
|
|
681
|
-
{
|
|
682
|
-
transport,
|
|
683
|
-
router: taskStatusRouter,
|
|
684
|
-
getHostTasksCapability: () => hostTasksCapability,
|
|
685
|
-
appName: name,
|
|
686
|
-
internalApp: internal
|
|
687
|
-
},
|
|
688
|
-
toolName,
|
|
689
|
-
args,
|
|
690
|
-
options2
|
|
691
|
-
);
|
|
692
|
-
},
|
|
693
|
-
async readResource(uri) {
|
|
694
|
-
const params = { uri };
|
|
659
|
+
async readServerResource(params) {
|
|
695
660
|
const raw = await transport.request(
|
|
696
|
-
|
|
661
|
+
READ_RESOURCE_METHOD,
|
|
697
662
|
params
|
|
698
663
|
);
|
|
699
664
|
return raw;
|
|
700
665
|
},
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
return () => {
|
|
704
|
-
dataCallbacks.delete(callback);
|
|
705
|
-
};
|
|
706
|
-
},
|
|
707
|
-
onAction(callback) {
|
|
708
|
-
actionCallbacks.add(callback);
|
|
709
|
-
return () => {
|
|
710
|
-
actionCallbacks.delete(callback);
|
|
711
|
-
};
|
|
712
|
-
},
|
|
713
|
-
getHostContext() {
|
|
714
|
-
return currentHostContext;
|
|
715
|
-
},
|
|
716
|
-
onHostContextChanged(callback) {
|
|
717
|
-
hostContextCallbacks.add(callback);
|
|
718
|
-
return () => {
|
|
719
|
-
hostContextCallbacks.delete(callback);
|
|
720
|
-
};
|
|
721
|
-
},
|
|
722
|
-
getTheme() {
|
|
723
|
-
return resolveTheme(currentHostContext);
|
|
724
|
-
},
|
|
725
|
-
// Selector over `onHostContextChanged`: only fires when the *derived*
|
|
726
|
-
// theme actually changes, so theme subscribers don't see spurious
|
|
727
|
-
// updates when other host-context fields (e.g. workspace) change.
|
|
728
|
-
//
|
|
729
|
-
// Subscriber timing matters:
|
|
730
|
-
// - Subscribed BEFORE handshake: `prev = null` sentinel. The first
|
|
731
|
-
// fire (the handshake dispatch) always invokes the callback,
|
|
732
|
-
// even if the host's theme happens to derive to the default.
|
|
733
|
-
// Otherwise consumers using `onThemeChanged` as their init
|
|
734
|
-
// signal would silently miss it.
|
|
735
|
-
// - Subscribed AFTER handshake: `prev` is pre-seeded with the
|
|
736
|
-
// current derived theme, so a workspace-only `host-context-changed`
|
|
737
|
-
// notification correctly filters as a no-op.
|
|
738
|
-
onThemeChanged(callback) {
|
|
739
|
-
let prev = hostInfo !== null ? resolveTheme(currentHostContext) : null;
|
|
740
|
-
const wrapped = (ctx) => {
|
|
741
|
-
const next = resolveTheme(ctx);
|
|
742
|
-
if (prev !== null && themesEqual(prev, next)) return;
|
|
743
|
-
prev = next;
|
|
744
|
-
callback(next);
|
|
745
|
-
};
|
|
746
|
-
hostContextCallbacks.add(wrapped);
|
|
747
|
-
return () => {
|
|
748
|
-
hostContextCallbacks.delete(wrapped);
|
|
749
|
-
};
|
|
750
|
-
},
|
|
751
|
-
action(action, params) {
|
|
752
|
-
if (!isNB()) return;
|
|
753
|
-
transport.send("synapse/action", { action, ...params });
|
|
754
|
-
},
|
|
755
|
-
chat(message, context) {
|
|
666
|
+
sendMessage(text, context) {
|
|
667
|
+
if (destroyed) return;
|
|
756
668
|
const textBlock = {
|
|
757
669
|
type: "text",
|
|
758
|
-
text
|
|
759
|
-
|
|
670
|
+
text,
|
|
671
|
+
// `_meta.context` is a NimbleBrain convention; other hosts ignore it,
|
|
672
|
+
// but there is no reason to spend the bytes off one.
|
|
673
|
+
...isNimbleBrainHost && context && { _meta: { context } }
|
|
760
674
|
};
|
|
761
675
|
const params = {
|
|
762
676
|
role: "user",
|
|
@@ -764,80 +678,87 @@ function createSynapse(options) {
|
|
|
764
678
|
};
|
|
765
679
|
transport.send(MESSAGE_METHOD, params);
|
|
766
680
|
},
|
|
767
|
-
setVisibleState(state, summary) {
|
|
768
|
-
if (stateTimer) clearTimeout(stateTimer);
|
|
769
|
-
stateTimer = setTimeout(() => {
|
|
770
|
-
const params = {
|
|
771
|
-
structuredContent: state,
|
|
772
|
-
...summary !== void 0 && {
|
|
773
|
-
content: [{ type: "text", text: summary }]
|
|
774
|
-
}
|
|
775
|
-
};
|
|
776
|
-
transport.send("ui/update-model-context", params);
|
|
777
|
-
stateTimer = null;
|
|
778
|
-
}, 250);
|
|
779
|
-
},
|
|
780
|
-
downloadFile(filename, content, mimeType) {
|
|
781
|
-
const resolvedMime = mimeType || (content instanceof Blob ? content.type : "") || "application/octet-stream";
|
|
782
|
-
const blob = content instanceof Blob ? content : new Blob([content], { type: resolvedMime });
|
|
783
|
-
transport.send("synapse/download-file", {
|
|
784
|
-
data: blob,
|
|
785
|
-
filename,
|
|
786
|
-
mimeType: resolvedMime
|
|
787
|
-
});
|
|
788
|
-
},
|
|
789
|
-
openLink(url) {
|
|
790
|
-
const params = { url };
|
|
791
|
-
transport.request(OPEN_LINK_METHOD, params).catch(() => {
|
|
792
|
-
window.open(url, "_blank", "noopener");
|
|
793
|
-
});
|
|
794
|
-
},
|
|
795
|
-
async pickFile(options2) {
|
|
796
|
-
if (!isNB()) {
|
|
797
|
-
throw new Error("pickFile is not supported in this host");
|
|
798
|
-
}
|
|
799
|
-
const result = await requestFile(transport, options2, false);
|
|
800
|
-
if (result === null) return null;
|
|
801
|
-
return Array.isArray(result) ? result[0] ?? null : result;
|
|
802
|
-
},
|
|
803
|
-
async pickFiles(options2) {
|
|
804
|
-
if (!isNB()) {
|
|
805
|
-
throw new Error("pickFiles is not supported in this host");
|
|
806
|
-
}
|
|
807
|
-
const result = await requestFile(transport, options2, true);
|
|
808
|
-
if (result === null) return [];
|
|
809
|
-
return Array.isArray(result) ? result : [result];
|
|
810
|
-
},
|
|
811
|
-
_onMessage(method, callback) {
|
|
812
|
-
return transport.onMessage(method, callback);
|
|
813
|
-
},
|
|
814
|
-
_request(method, params) {
|
|
815
|
-
return transport.request(method, params);
|
|
816
|
-
},
|
|
817
|
-
get _hostTasksCapability() {
|
|
818
|
-
return hostTasksCapability;
|
|
819
|
-
},
|
|
820
681
|
destroy() {
|
|
821
682
|
if (destroyed) return;
|
|
822
683
|
destroyed = true;
|
|
823
|
-
if (stateTimer) clearTimeout(stateTimer);
|
|
824
684
|
keyboard?.destroy();
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
685
|
+
resizer.destroy();
|
|
686
|
+
taskRouter.dispose();
|
|
687
|
+
handlers.clear();
|
|
688
|
+
themeCallbacks.clear();
|
|
829
689
|
hostContextCallbacks.clear();
|
|
830
690
|
dataCallbacks.clear();
|
|
831
691
|
actionCallbacks.clear();
|
|
832
692
|
transport.destroy();
|
|
833
693
|
}
|
|
834
694
|
};
|
|
835
|
-
|
|
695
|
+
registerInternals(app, {
|
|
696
|
+
send(method, params) {
|
|
697
|
+
if (destroyed) return;
|
|
698
|
+
transport.send(method, params);
|
|
699
|
+
},
|
|
700
|
+
request(method, params) {
|
|
701
|
+
return transport.request(method, params);
|
|
702
|
+
},
|
|
703
|
+
onMessage(method, handler) {
|
|
704
|
+
return transport.onMessage(method, handler);
|
|
705
|
+
},
|
|
706
|
+
taskRouter,
|
|
707
|
+
get hostTasksCapability() {
|
|
708
|
+
return hostTasksCapability;
|
|
709
|
+
},
|
|
710
|
+
appName: name,
|
|
711
|
+
internalApp: internal
|
|
712
|
+
});
|
|
713
|
+
return app;
|
|
714
|
+
}
|
|
715
|
+
function themesEqual(a, b) {
|
|
716
|
+
if (a.mode !== b.mode) return false;
|
|
717
|
+
if (fontFacesKey(a.fontFaces) !== fontFacesKey(b.fontFaces)) return false;
|
|
718
|
+
const aKeys = Object.keys(a.tokens);
|
|
719
|
+
const bKeys = Object.keys(b.tokens);
|
|
720
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
721
|
+
for (const k of aKeys) {
|
|
722
|
+
if (a.tokens[k] !== b.tokens[k]) return false;
|
|
723
|
+
}
|
|
724
|
+
return true;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// src/extensions.ts
|
|
728
|
+
var DEFAULT_MAX_FILE_SIZE = 26214400;
|
|
729
|
+
function action(app, name, params) {
|
|
730
|
+
if (!app.isNimbleBrainHost) return;
|
|
731
|
+
internalsFor(app).send(ACTION_METHOD, { action: name, ...params });
|
|
836
732
|
}
|
|
837
|
-
|
|
838
|
-
const
|
|
733
|
+
function downloadFile(app, filename, content, mimeType) {
|
|
734
|
+
const resolvedMime = mimeType || (content instanceof Blob ? content.type : "") || "application/octet-stream";
|
|
735
|
+
const blob = content instanceof Blob ? content : new Blob([content], { type: resolvedMime });
|
|
736
|
+
internalsFor(app).send(DOWNLOAD_FILE_METHOD, {
|
|
737
|
+
data: blob,
|
|
738
|
+
filename,
|
|
739
|
+
mimeType: resolvedMime
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
async function pickFile(app, options) {
|
|
743
|
+
if (!app.isNimbleBrainHost) {
|
|
744
|
+
throw new Error("pickFile is not supported in this host");
|
|
745
|
+
}
|
|
746
|
+
const result = await requestFile(app, options, false);
|
|
747
|
+
if (result === null) return null;
|
|
748
|
+
return Array.isArray(result) ? result[0] ?? null : result;
|
|
749
|
+
}
|
|
750
|
+
async function pickFiles(app, options) {
|
|
751
|
+
if (!app.isNimbleBrainHost) {
|
|
752
|
+
throw new Error("pickFiles is not supported in this host");
|
|
753
|
+
}
|
|
754
|
+
const result = await requestFile(app, options, true);
|
|
755
|
+
if (result === null) return [];
|
|
756
|
+
return Array.isArray(result) ? result : [result];
|
|
757
|
+
}
|
|
758
|
+
async function requestFile(app, options, multiple) {
|
|
759
|
+
const result = await internalsFor(app).request(REQUEST_FILE_METHOD, {
|
|
839
760
|
accept: options?.accept,
|
|
840
|
-
maxSize: options?.maxSize ??
|
|
761
|
+
maxSize: options?.maxSize ?? DEFAULT_MAX_FILE_SIZE,
|
|
841
762
|
multiple
|
|
842
763
|
});
|
|
843
764
|
if (result == null) return null;
|
|
@@ -854,18 +775,7 @@ function validateFileResult(value) {
|
|
|
854
775
|
}
|
|
855
776
|
return value;
|
|
856
777
|
}
|
|
857
|
-
function themesEqual(a, b) {
|
|
858
|
-
if (a.mode !== b.mode || a.primaryColor !== b.primaryColor) return false;
|
|
859
|
-
if (fontFacesKey(a.fontFaces) !== fontFacesKey(b.fontFaces)) return false;
|
|
860
|
-
const aKeys = Object.keys(a.tokens);
|
|
861
|
-
const bKeys = Object.keys(b.tokens);
|
|
862
|
-
if (aKeys.length !== bKeys.length) return false;
|
|
863
|
-
for (const k of aKeys) {
|
|
864
|
-
if (a.tokens[k] !== b.tokens[k]) return false;
|
|
865
|
-
}
|
|
866
|
-
return true;
|
|
867
|
-
}
|
|
868
778
|
|
|
869
|
-
export { connect,
|
|
870
|
-
//# sourceMappingURL=chunk-
|
|
871
|
-
//# sourceMappingURL=chunk-
|
|
779
|
+
export { action, callToolAsTask, connect, downloadFile, pickFile, pickFiles };
|
|
780
|
+
//# sourceMappingURL=chunk-VYR6V47N.js.map
|
|
781
|
+
//# sourceMappingURL=chunk-VYR6V47N.js.map
|