@dainprotocol/service-sdk 2.0.90 → 2.0.91
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/client/api-sdk.js +2 -20
- package/dist/client/api-sdk.js.map +1 -1
- package/dist/client/client.d.ts +7 -39
- package/dist/client/client.js +30 -267
- package/dist/client/client.js.map +1 -1
- package/dist/client/types.d.ts +6 -273
- package/dist/client/types.js +5 -129
- package/dist/client/types.js.map +1 -1
- package/dist/lib/schemaStructure.js +0 -1
- package/dist/lib/schemaStructure.js.map +1 -1
- package/dist/service/auth.js +1 -10
- package/dist/service/auth.js.map +1 -1
- package/dist/service/core.js +1 -50
- package/dist/service/core.js.map +1 -1
- package/dist/service/server.js +72 -569
- package/dist/service/server.js.map +1 -1
- package/dist/service/types.d.ts +4 -133
- package/dist/service/webhooks.d.ts +8 -8
- package/dist/service/webhooks.js +12 -16
- package/dist/service/webhooks.js.map +1 -1
- package/package.json +5 -5
- package/dist/lib/toolDiscovery.d.ts +0 -20
- package/dist/lib/toolDiscovery.js +0 -30
- package/dist/lib/toolDiscovery.js.map +0 -1
package/dist/service/server.js
CHANGED
|
@@ -9,7 +9,6 @@ const cors_1 = require("hono/cors");
|
|
|
9
9
|
const http_exception_1 = require("hono/http-exception");
|
|
10
10
|
const auth_1 = require("./auth");
|
|
11
11
|
const schemaStructure_1 = require("../lib/schemaStructure");
|
|
12
|
-
const toolDiscovery_1 = require("../lib/toolDiscovery");
|
|
13
12
|
const oauth2_1 = require("./oauth2");
|
|
14
13
|
const bs58_1 = tslib_1.__importDefault(require("bs58"));
|
|
15
14
|
const processes_1 = require("./processes");
|
|
@@ -33,46 +32,6 @@ function debugWarn(...args) {
|
|
|
33
32
|
console.warn(...args);
|
|
34
33
|
}
|
|
35
34
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Extract a user-safe error message. If `err` is a ZodError (or `err.message`
|
|
38
|
-
* looks like a raw Zod v4 issue-array JSON `"[{...}]"`), re-summarize as
|
|
39
|
-
* `"<path>: <msg>; <path>: <msg>"` so it never lands verbatim in chat text.
|
|
40
|
-
*
|
|
41
|
-
* Backstop for the tool-output validation leak: the 2026-04-17 whitelist
|
|
42
|
-
* regression surfaced `[{"code":"invalid_type","path":["markets"],...}]` in
|
|
43
|
-
* user-visible chat because the four SSE/non-SSE error exits below all do
|
|
44
|
-
* `text: \`Error: ${error.message}\``. This helper neutralizes that class
|
|
45
|
-
* of bug for ANY ZodError thrown anywhere in the tool-exec pipeline, not
|
|
46
|
-
* just the one we already fixed at the source in core.ts.
|
|
47
|
-
*/
|
|
48
|
-
function sanitizeErrorMessage(err) {
|
|
49
|
-
if (err instanceof zod_1.z.ZodError) {
|
|
50
|
-
const summary = err.issues
|
|
51
|
-
.map((i) => `${i.path.join(".") || "root"}: ${i.message}`)
|
|
52
|
-
.join("; ");
|
|
53
|
-
return summary || "Validation failed";
|
|
54
|
-
}
|
|
55
|
-
const raw = err?.message;
|
|
56
|
-
if (typeof raw !== "string" || raw.length === 0)
|
|
57
|
-
return "Unknown error";
|
|
58
|
-
const trimmed = raw.trimStart();
|
|
59
|
-
if (trimmed.startsWith("[{") || trimmed.startsWith("[ {")) {
|
|
60
|
-
try {
|
|
61
|
-
const parsed = JSON.parse(trimmed);
|
|
62
|
-
if (Array.isArray(parsed)) {
|
|
63
|
-
const summary = parsed
|
|
64
|
-
.map((i) => `${Array.isArray(i.path) ? i.path.join(".") || "root" : "root"}: ${i.message ?? "invalid"}`)
|
|
65
|
-
.join("; ");
|
|
66
|
-
if (summary)
|
|
67
|
-
return summary;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
/* fall through, return raw message */
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return raw;
|
|
75
|
-
}
|
|
76
35
|
function getFirstForwardedValue(value) {
|
|
77
36
|
if (!value)
|
|
78
37
|
return undefined;
|
|
@@ -119,30 +78,23 @@ function requireScope(requiredScope) {
|
|
|
119
78
|
// Helper to sign and stream SSE events
|
|
120
79
|
function signedStreamSSE(c, privateKey, config, handler) {
|
|
121
80
|
return (0, streaming_1.streamSSE)(c, async (stream) => {
|
|
122
|
-
const requestSignal = c.req.raw?.signal;
|
|
123
|
-
const isAborted = () => stream.aborted || stream.closed || requestSignal?.aborted === true;
|
|
124
81
|
const signedStream = {
|
|
125
82
|
writeSSE: async (event) => {
|
|
126
|
-
if (isAborted())
|
|
127
|
-
return;
|
|
128
83
|
const timestamp = Date.now().toString();
|
|
129
84
|
const message = `${event.data}:${timestamp}`;
|
|
130
85
|
const messageHash = (0, sha256_1.sha256)(message);
|
|
131
86
|
const signatureBytes = ed25519_1.ed25519.sign(messageHash, privateKey);
|
|
132
87
|
const signature = (0, utils_1.bytesToHex)(signatureBytes);
|
|
133
88
|
// Fast path for non-critical events (progress/UI updates)
|
|
134
|
-
const isCriticalEvent = event.event === 'result' ||
|
|
135
|
-
event.event === 'process-created' ||
|
|
136
|
-
event.event === 'datasource-update';
|
|
89
|
+
const isCriticalEvent = event.event === 'result' || event.event === 'process-created';
|
|
137
90
|
const dataWithSignature = isCriticalEvent
|
|
138
91
|
? JSON.stringify({
|
|
139
92
|
data: JSON.parse(event.data),
|
|
140
93
|
_signature: { signature, timestamp, agentId: config.identity.agentId, orgId: config.identity.orgId, address: config.identity.publicKey }
|
|
141
94
|
})
|
|
142
95
|
: `{"data":${event.data},"_signature":{"signature":"${signature}","timestamp":"${timestamp}","agentId":"${config.identity.agentId}","orgId":"${config.identity.orgId}","address":"${config.identity.publicKey}"}}`;
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
isAborted,
|
|
96
|
+
return stream.writeSSE({ event: event.event, data: dataWithSignature, id: event.id });
|
|
97
|
+
}
|
|
146
98
|
};
|
|
147
99
|
await handler(signedStream);
|
|
148
100
|
});
|
|
@@ -222,7 +174,11 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
222
174
|
const isHITLPath = hitlPath && c.req.path === hitlPath;
|
|
223
175
|
if (c.req.path.startsWith("/oauth2/callback/") ||
|
|
224
176
|
c.req.path.startsWith("/addons") ||
|
|
177
|
+
c.req.path.startsWith("/getAllToolsAsJsonSchema") ||
|
|
178
|
+
c.req.path.startsWith("/getSkills") ||
|
|
179
|
+
c.req.path.startsWith("/getWebhookTriggers") ||
|
|
225
180
|
c.req.path.startsWith("/metadata") ||
|
|
181
|
+
c.req.path.startsWith("/recommendations") ||
|
|
226
182
|
c.req.path.startsWith("/ping") ||
|
|
227
183
|
isWebhookPath ||
|
|
228
184
|
isHITLPath) {
|
|
@@ -344,73 +300,15 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
344
300
|
debugLog("[getAgentInfo] API Key - Returning agent info:", agentInfo);
|
|
345
301
|
return agentInfo;
|
|
346
302
|
}
|
|
347
|
-
async function resolveHealthStatus() {
|
|
348
|
-
if (!config.healthCheck)
|
|
349
|
-
return true;
|
|
350
|
-
try {
|
|
351
|
-
return await config.healthCheck();
|
|
352
|
-
}
|
|
353
|
-
catch {
|
|
354
|
-
return false;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
303
|
// Setup default ping route
|
|
358
|
-
app.get("/ping",
|
|
359
|
-
const healthy = await resolveHealthStatus();
|
|
360
|
-
return c.json({
|
|
361
|
-
message: healthy ? "pong" : "unhealthy",
|
|
362
|
-
platform: "DAIN",
|
|
363
|
-
service_version: metadata.version,
|
|
364
|
-
dain_sdk_version: package_json_1.default.version,
|
|
365
|
-
}, healthy ? 200 : 503);
|
|
366
|
-
});
|
|
304
|
+
app.get("/ping", (c) => c.json({ message: "pong", platform: "DAIN", service_version: metadata.version, dain_sdk_version: package_json_1.default.version }));
|
|
367
305
|
// Metadata endpoint - includes computed supportsUserActions from tools
|
|
368
306
|
app.get("/metadata", (c) => {
|
|
369
307
|
// Compute service-level capability: does ANY tool support user actions (HITL)?
|
|
370
308
|
const supportsUserActions = tools.some((tool) => tool.supportsUserActions === true);
|
|
371
|
-
const requestedContract = c.req.header("x-butterfly-contract") || c.req.header("X-Butterfly-Contract");
|
|
372
|
-
const sdkMajor = Number.parseInt(String(package_json_1.default.version).split(".")[0] || "0", 10);
|
|
373
|
-
const contractVersion = Number.isFinite(sdkMajor) && sdkMajor > 0 ? `${sdkMajor}.0.0` : "0.0.0";
|
|
374
|
-
const capabilities = {
|
|
375
|
-
tools: true,
|
|
376
|
-
contexts: true,
|
|
377
|
-
widgets: true,
|
|
378
|
-
datasources: true,
|
|
379
|
-
streamingTools: true,
|
|
380
|
-
streamingDatasources: true,
|
|
381
|
-
datasourcePolicy: true,
|
|
382
|
-
widgetPolicy: true,
|
|
383
|
-
toolSafety: true,
|
|
384
|
-
};
|
|
385
|
-
const compatibility = (() => {
|
|
386
|
-
if (!requestedContract)
|
|
387
|
-
return undefined;
|
|
388
|
-
const requestedMajor = Number.parseInt(String(requestedContract).split(".")[0] || "0", 10);
|
|
389
|
-
if (!Number.isFinite(requestedMajor) || requestedMajor <= 0) {
|
|
390
|
-
return {
|
|
391
|
-
requested: requestedContract,
|
|
392
|
-
contractVersion,
|
|
393
|
-
ok: false,
|
|
394
|
-
reason: "Invalid requested contract version",
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
const ok = requestedMajor === sdkMajor;
|
|
398
|
-
return ok
|
|
399
|
-
? { requested: requestedContract, contractVersion, ok: true }
|
|
400
|
-
: {
|
|
401
|
-
requested: requestedContract,
|
|
402
|
-
contractVersion,
|
|
403
|
-
ok: false,
|
|
404
|
-
reason: `Requested major ${requestedMajor} does not match service major ${sdkMajor}`,
|
|
405
|
-
};
|
|
406
|
-
})();
|
|
407
309
|
return c.json({
|
|
408
310
|
...metadata,
|
|
409
311
|
supportsUserActions,
|
|
410
|
-
dainSdkVersion: package_json_1.default.version,
|
|
411
|
-
contractVersion,
|
|
412
|
-
capabilities,
|
|
413
|
-
...(compatibility ? { compatibility } : {}),
|
|
414
312
|
});
|
|
415
313
|
});
|
|
416
314
|
// Tools list endpoint
|
|
@@ -429,10 +327,6 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
429
327
|
outputSchema,
|
|
430
328
|
interface: tool.interface,
|
|
431
329
|
suggestConfirmation: tool.suggestConfirmation,
|
|
432
|
-
sideEffectClass: tool.sideEffectClass,
|
|
433
|
-
supportsParallel: tool.supportsParallel,
|
|
434
|
-
idempotencyScope: tool.idempotencyScope,
|
|
435
|
-
maxConcurrencyHint: tool.maxConcurrencyHint,
|
|
436
330
|
supportsUserActions: tool.supportsUserActions,
|
|
437
331
|
};
|
|
438
332
|
});
|
|
@@ -533,26 +427,14 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
533
427
|
oauth2Client,
|
|
534
428
|
app
|
|
535
429
|
});
|
|
536
|
-
|
|
430
|
+
return {
|
|
537
431
|
id: widget.id,
|
|
538
432
|
name: widget.name,
|
|
539
433
|
description: widget.description,
|
|
540
434
|
icon: widget.icon,
|
|
541
435
|
size: widget.size || "sm",
|
|
542
|
-
refreshIntervalMs: widget.refreshIntervalMs,
|
|
543
436
|
...widgetData
|
|
544
437
|
};
|
|
545
|
-
if (!("freshness" in response)) {
|
|
546
|
-
response.freshness = {
|
|
547
|
-
freshAt: Date.now(),
|
|
548
|
-
transport: "poll",
|
|
549
|
-
requestedPolicy: {
|
|
550
|
-
refreshIntervalMs: widget.refreshIntervalMs,
|
|
551
|
-
},
|
|
552
|
-
scope: "account",
|
|
553
|
-
};
|
|
554
|
-
}
|
|
555
|
-
return response;
|
|
556
438
|
}));
|
|
557
439
|
const validWidgets = widgetsFull.filter(w => w !== null);
|
|
558
440
|
const processedResponse = await processPluginsForResponse(validWidgets, body, { extraData: { plugins: processedPluginData.plugins } });
|
|
@@ -593,19 +475,8 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
593
475
|
description: widget.description,
|
|
594
476
|
icon: widget.icon,
|
|
595
477
|
size: widget.size || "sm",
|
|
596
|
-
refreshIntervalMs: widget.refreshIntervalMs,
|
|
597
478
|
...widgetData
|
|
598
479
|
};
|
|
599
|
-
if (!("freshness" in response)) {
|
|
600
|
-
response.freshness = {
|
|
601
|
-
freshAt: Date.now(),
|
|
602
|
-
transport: "poll",
|
|
603
|
-
requestedPolicy: {
|
|
604
|
-
refreshIntervalMs: widget.refreshIntervalMs,
|
|
605
|
-
},
|
|
606
|
-
scope: "account",
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
480
|
const processedResponse = await processPluginsForResponse(response, body, { extraData: { plugins: processedPluginData.plugins } });
|
|
610
481
|
return c.json(processedResponse);
|
|
611
482
|
});
|
|
@@ -635,12 +506,6 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
635
506
|
name: datasource.name,
|
|
636
507
|
description: datasource.description,
|
|
637
508
|
type: datasource.type,
|
|
638
|
-
refreshIntervalMs: datasource.refreshIntervalMs,
|
|
639
|
-
maxStalenessMs: datasource.maxStalenessMs,
|
|
640
|
-
transport: datasource.transport,
|
|
641
|
-
priority: datasource.priority,
|
|
642
|
-
scope: datasource.scope,
|
|
643
|
-
dataClass: datasource.dataClass,
|
|
644
509
|
inputSchema: (0, schemaStructure_1.getDetailedSchemaStructure)(datasource.input),
|
|
645
510
|
};
|
|
646
511
|
}
|
|
@@ -678,32 +543,12 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
678
543
|
plugins: pluginsData,
|
|
679
544
|
oauth2Client
|
|
680
545
|
});
|
|
681
|
-
const requestedPolicy = {
|
|
682
|
-
refreshIntervalMs: datasource.refreshIntervalMs,
|
|
683
|
-
maxStalenessMs: datasource.maxStalenessMs,
|
|
684
|
-
transport: datasource.transport,
|
|
685
|
-
priority: datasource.priority,
|
|
686
|
-
scope: datasource.scope,
|
|
687
|
-
dataClass: datasource.dataClass,
|
|
688
|
-
};
|
|
689
546
|
const response = {
|
|
690
547
|
id: datasource.id,
|
|
691
548
|
name: datasource.name,
|
|
692
549
|
description: datasource.description,
|
|
693
550
|
type: datasource.type,
|
|
694
|
-
refreshIntervalMs: datasource.refreshIntervalMs,
|
|
695
|
-
maxStalenessMs: datasource.maxStalenessMs,
|
|
696
|
-
transport: datasource.transport,
|
|
697
|
-
priority: datasource.priority,
|
|
698
|
-
scope: datasource.scope,
|
|
699
|
-
dataClass: datasource.dataClass,
|
|
700
551
|
data,
|
|
701
|
-
freshness: {
|
|
702
|
-
freshAt: Date.now(),
|
|
703
|
-
transport: datasource.transport || "poll",
|
|
704
|
-
requestedPolicy,
|
|
705
|
-
scope: datasource.scope,
|
|
706
|
-
},
|
|
707
552
|
};
|
|
708
553
|
const processedResponse = await processPluginsForResponse(response, { plugins: pluginsData }, { extraData: { plugins: pluginsData } });
|
|
709
554
|
return c.json(processedResponse);
|
|
@@ -721,149 +566,6 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
721
566
|
throw error;
|
|
722
567
|
}
|
|
723
568
|
});
|
|
724
|
-
// Stream datasource updates over SSE. This is primarily used for "fresh" UIs
|
|
725
|
-
// (positions/orders) where clients want stream-first updates with a poll fallback.
|
|
726
|
-
//
|
|
727
|
-
// Note: This does not require services to implement a separate streaming backend.
|
|
728
|
-
// The server re-runs the datasource handler on an interval and streams results.
|
|
729
|
-
app.post("/datasources/:datasourceId/stream", async (c) => {
|
|
730
|
-
const datasource = datasources.find((ds) => ds.id === c.req.param("datasourceId"));
|
|
731
|
-
if (!datasource) {
|
|
732
|
-
throw new http_exception_1.HTTPException(404, { message: "Datasource not found" });
|
|
733
|
-
}
|
|
734
|
-
const agentInfo = await getAgentInfo(c);
|
|
735
|
-
const rawBody = await safeParseBody(c);
|
|
736
|
-
const hasWrappedParams = rawBody &&
|
|
737
|
-
typeof rawBody === "object" &&
|
|
738
|
-
!Array.isArray(rawBody) &&
|
|
739
|
-
"params" in rawBody;
|
|
740
|
-
const requestedIntervalMsRaw = hasWrappedParams ? rawBody.intervalMs : undefined;
|
|
741
|
-
const requestParamsRaw = hasWrappedParams ? rawBody.params : rawBody;
|
|
742
|
-
let params = await processPluginsForRequest(requestParamsRaw && typeof requestParamsRaw === "object" ? requestParamsRaw : {}, agentInfo);
|
|
743
|
-
const pluginsData = (params.plugins && typeof params.plugins === "object"
|
|
744
|
-
? params.plugins
|
|
745
|
-
: {});
|
|
746
|
-
delete params.plugins;
|
|
747
|
-
let parsedParams;
|
|
748
|
-
try {
|
|
749
|
-
parsedParams = datasource.input.parse(params);
|
|
750
|
-
}
|
|
751
|
-
catch (error) {
|
|
752
|
-
if (error instanceof zod_1.z.ZodError) {
|
|
753
|
-
const missingParams = error.issues
|
|
754
|
-
.map((issue) => issue.path.join("."))
|
|
755
|
-
.join(", ");
|
|
756
|
-
return c.json({
|
|
757
|
-
error: `Missing or invalid parameters: ${missingParams}`,
|
|
758
|
-
code: "INVALID_PARAMS"
|
|
759
|
-
}, 400);
|
|
760
|
-
}
|
|
761
|
-
throw error;
|
|
762
|
-
}
|
|
763
|
-
const pluginRequestContext = hasWrappedParams
|
|
764
|
-
? {
|
|
765
|
-
params: parsedParams,
|
|
766
|
-
intervalMs: requestedIntervalMsRaw,
|
|
767
|
-
plugins: pluginsData,
|
|
768
|
-
}
|
|
769
|
-
: {
|
|
770
|
-
...(typeof parsedParams === "object" && parsedParams !== null
|
|
771
|
-
? parsedParams
|
|
772
|
-
: {}),
|
|
773
|
-
plugins: pluginsData,
|
|
774
|
-
};
|
|
775
|
-
const oauth2Client = app.oauth2?.getClient();
|
|
776
|
-
const requestedPolicy = {
|
|
777
|
-
refreshIntervalMs: datasource.refreshIntervalMs,
|
|
778
|
-
maxStalenessMs: datasource.maxStalenessMs,
|
|
779
|
-
transport: datasource.transport,
|
|
780
|
-
priority: datasource.priority,
|
|
781
|
-
scope: datasource.scope,
|
|
782
|
-
dataClass: datasource.dataClass,
|
|
783
|
-
};
|
|
784
|
-
const requestedIntervalMs = typeof requestedIntervalMsRaw === "number" && Number.isFinite(requestedIntervalMsRaw) && requestedIntervalMsRaw > 0
|
|
785
|
-
? requestedIntervalMsRaw
|
|
786
|
-
: null;
|
|
787
|
-
const baseIntervalMs = requestedIntervalMs ??
|
|
788
|
-
(typeof datasource.refreshIntervalMs === "number" && datasource.refreshIntervalMs > 0
|
|
789
|
-
? datasource.refreshIntervalMs
|
|
790
|
-
: 15_000);
|
|
791
|
-
const intervalMs = Math.max(1_000, Math.floor(baseIntervalMs));
|
|
792
|
-
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
793
|
-
debugLog(`[SSE] Datasource ${datasource.id} stream start (${intervalMs}ms interval)`);
|
|
794
|
-
return signedStreamSSE(c, privateKey, config, async (stream) => {
|
|
795
|
-
let eventId = 0;
|
|
796
|
-
const emitUpdate = async () => {
|
|
797
|
-
const data = await datasource.getDatasource(agentInfo, parsedParams, {
|
|
798
|
-
plugins: pluginsData,
|
|
799
|
-
oauth2Client,
|
|
800
|
-
});
|
|
801
|
-
const response = {
|
|
802
|
-
id: datasource.id,
|
|
803
|
-
name: datasource.name,
|
|
804
|
-
description: datasource.description,
|
|
805
|
-
type: datasource.type,
|
|
806
|
-
refreshIntervalMs: datasource.refreshIntervalMs,
|
|
807
|
-
maxStalenessMs: datasource.maxStalenessMs,
|
|
808
|
-
transport: datasource.transport,
|
|
809
|
-
priority: datasource.priority,
|
|
810
|
-
scope: datasource.scope,
|
|
811
|
-
dataClass: datasource.dataClass,
|
|
812
|
-
data,
|
|
813
|
-
freshness: {
|
|
814
|
-
freshAt: Date.now(),
|
|
815
|
-
transport: "stream",
|
|
816
|
-
requestedPolicy,
|
|
817
|
-
scope: datasource.scope,
|
|
818
|
-
},
|
|
819
|
-
};
|
|
820
|
-
const processedResponse = await processPluginsForResponse(response, pluginRequestContext, { extraData: { plugins: pluginsData } });
|
|
821
|
-
await stream.writeSSE({
|
|
822
|
-
event: "datasource-update",
|
|
823
|
-
data: JSON.stringify(processedResponse),
|
|
824
|
-
id: String(eventId++),
|
|
825
|
-
});
|
|
826
|
-
};
|
|
827
|
-
// Send initial snapshot immediately.
|
|
828
|
-
try {
|
|
829
|
-
await emitUpdate();
|
|
830
|
-
}
|
|
831
|
-
catch (error) {
|
|
832
|
-
console.error(`[SSE] Datasource ${datasource.id} initial update failed:`, error);
|
|
833
|
-
if (!stream.isAborted()) {
|
|
834
|
-
await stream.writeSSE({
|
|
835
|
-
event: "error",
|
|
836
|
-
data: JSON.stringify({ message: error?.message || "Datasource stream error" }),
|
|
837
|
-
});
|
|
838
|
-
}
|
|
839
|
-
return;
|
|
840
|
-
}
|
|
841
|
-
// Continue sending updates until client disconnects.
|
|
842
|
-
// Hono exposes the underlying Request via c.req.raw, which includes an AbortSignal.
|
|
843
|
-
const signal = c.req.raw?.signal;
|
|
844
|
-
while (!stream.isAborted() && !signal?.aborted) {
|
|
845
|
-
await sleep(intervalMs);
|
|
846
|
-
if (stream.isAborted() || signal?.aborted)
|
|
847
|
-
break;
|
|
848
|
-
try {
|
|
849
|
-
await emitUpdate();
|
|
850
|
-
}
|
|
851
|
-
catch (error) {
|
|
852
|
-
if (stream.isAborted() || signal?.aborted)
|
|
853
|
-
break;
|
|
854
|
-
console.error(`[SSE] Datasource ${datasource.id} update failed:`, error);
|
|
855
|
-
// Keep the stream alive; clients should rely on poll fallback if needed.
|
|
856
|
-
if (!stream.isAborted()) {
|
|
857
|
-
await stream.writeSSE({
|
|
858
|
-
event: "error",
|
|
859
|
-
data: JSON.stringify({ message: error?.message || "Datasource stream error" }),
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
debugLog(`[SSE] Datasource ${datasource.id} stream end`);
|
|
865
|
-
});
|
|
866
|
-
});
|
|
867
569
|
function mapAgentInfo(agent) {
|
|
868
570
|
return {
|
|
869
571
|
id: agent.id,
|
|
@@ -940,23 +642,13 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
940
642
|
outputSchema,
|
|
941
643
|
interface: tool.interface,
|
|
942
644
|
suggestConfirmation: tool.suggestConfirmation,
|
|
943
|
-
sideEffectClass: tool.sideEffectClass,
|
|
944
|
-
supportsParallel: tool.supportsParallel,
|
|
945
|
-
idempotencyScope: tool.idempotencyScope,
|
|
946
|
-
maxConcurrencyHint: tool.maxConcurrencyHint,
|
|
947
645
|
supportsUserActions: tool.supportsUserActions,
|
|
948
646
|
};
|
|
949
647
|
}
|
|
950
648
|
app.get("/getAllToolsAsJsonSchema", (c) => {
|
|
951
|
-
const toolInfo = tools.map(mapToolToJsonSchema);
|
|
952
|
-
const reccomendedPrompts = toolboxes.map((toolbox) => toolbox.recommendedPrompt);
|
|
953
649
|
return c.json({
|
|
954
|
-
tools:
|
|
955
|
-
reccomendedPrompts,
|
|
956
|
-
schemaVersion: (0, toolDiscovery_1.computeToolDiscoverySchemaVersion)({
|
|
957
|
-
tools: toolInfo,
|
|
958
|
-
reccomendedPrompts,
|
|
959
|
-
}),
|
|
650
|
+
tools: tools.map(mapToolToJsonSchema),
|
|
651
|
+
reccomendedPrompts: toolboxes.map((toolbox) => toolbox.recommendedPrompt),
|
|
960
652
|
});
|
|
961
653
|
});
|
|
962
654
|
app.post("/getAllToolsAsJsonSchema", async (c) => {
|
|
@@ -965,14 +657,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
965
657
|
const processedPluginData = await processPluginsForRequest(body, agentInfo);
|
|
966
658
|
const toolInfo = tools.map(mapToolToJsonSchema);
|
|
967
659
|
debugLog(`[getAllToolsAsJsonSchema POST] Returning ${toolInfo.length} tools`);
|
|
968
|
-
const reccomendedPrompts = toolboxes.map((toolbox) => toolbox.recommendedPrompt);
|
|
969
660
|
const response = {
|
|
970
661
|
tools: toolInfo,
|
|
971
|
-
reccomendedPrompts,
|
|
972
|
-
schemaVersion: (0, toolDiscovery_1.computeToolDiscoverySchemaVersion)({
|
|
973
|
-
tools: toolInfo,
|
|
974
|
-
reccomendedPrompts,
|
|
975
|
-
}),
|
|
662
|
+
reccomendedPrompts: toolboxes.map((toolbox) => toolbox.recommendedPrompt),
|
|
976
663
|
};
|
|
977
664
|
const processedResponse = await processPluginsForResponse(response, body, { extraData: { plugins: processedPluginData.plugins } });
|
|
978
665
|
return c.json(processedResponse);
|
|
@@ -1159,10 +846,6 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1159
846
|
outputSchema: (0, schemaStructure_1.getDetailedSchemaStructure)(tool.output),
|
|
1160
847
|
interface: tool.interface,
|
|
1161
848
|
suggestConfirmation: tool.suggestConfirmation,
|
|
1162
|
-
sideEffectClass: tool.sideEffectClass,
|
|
1163
|
-
supportsParallel: tool.supportsParallel,
|
|
1164
|
-
idempotencyScope: tool.idempotencyScope,
|
|
1165
|
-
maxConcurrencyHint: tool.maxConcurrencyHint,
|
|
1166
849
|
};
|
|
1167
850
|
return c.json(toolDetails);
|
|
1168
851
|
}
|
|
@@ -1190,11 +873,6 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1190
873
|
pricing: tool.pricing,
|
|
1191
874
|
inputSchema: (0, schemaStructure_1.getDetailedSchemaStructure)(tool.input),
|
|
1192
875
|
outputSchema: (0, schemaStructure_1.getDetailedSchemaStructure)(tool.output),
|
|
1193
|
-
suggestConfirmation: tool.suggestConfirmation,
|
|
1194
|
-
sideEffectClass: tool.sideEffectClass,
|
|
1195
|
-
supportsParallel: tool.supportsParallel,
|
|
1196
|
-
idempotencyScope: tool.idempotencyScope,
|
|
1197
|
-
maxConcurrencyHint: tool.maxConcurrencyHint,
|
|
1198
876
|
}
|
|
1199
877
|
: {
|
|
1200
878
|
id: toolId,
|
|
@@ -1220,13 +898,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1220
898
|
}
|
|
1221
899
|
});
|
|
1222
900
|
// Health check endpoint
|
|
1223
|
-
app.get("/health",
|
|
1224
|
-
const healthy = await resolveHealthStatus();
|
|
1225
|
-
return c.json({
|
|
1226
|
-
status: healthy ? "healthy" : "unhealthy",
|
|
1227
|
-
timestamp: new Date().toISOString(),
|
|
1228
|
-
}, healthy ? 200 : 503);
|
|
1229
|
-
});
|
|
901
|
+
app.get("/health", (c) => c.json({ status: "healthy", timestamp: new Date().toISOString() }));
|
|
1230
902
|
// Setup custom routes if provided
|
|
1231
903
|
if (config.routes) {
|
|
1232
904
|
config.routes(app);
|
|
@@ -1510,231 +1182,64 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1510
1182
|
});
|
|
1511
1183
|
// Toolboxes list endpoint
|
|
1512
1184
|
app.get("/toolboxes", (c) => c.json(toolboxes));
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
function tokenizeRecommendationQuery(query) {
|
|
1517
|
-
const normalized = normalizeRecommendationText(query);
|
|
1518
|
-
if (!normalized)
|
|
1519
|
-
return [];
|
|
1520
|
-
return Array.from(new Set(normalized.split(/\s+/).filter((token) => token.length >= 2)));
|
|
1521
|
-
}
|
|
1522
|
-
function buildRecommendationIndex() {
|
|
1523
|
-
const index = new Map();
|
|
1185
|
+
// Recommendations endpoint - returns cards for AI selection
|
|
1186
|
+
app.get("/recommendations", (c) => {
|
|
1187
|
+
const cards = [];
|
|
1524
1188
|
for (const tool of tools) {
|
|
1525
|
-
if (
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1189
|
+
if (tool.recommendations?.length) {
|
|
1190
|
+
for (const card of tool.recommendations) {
|
|
1191
|
+
const hasDynamicSchema = !!card.inputSchema;
|
|
1192
|
+
cards.push({
|
|
1193
|
+
id: card.id,
|
|
1194
|
+
tags: card.tags,
|
|
1195
|
+
ui: hasDynamicSchema ? undefined : card.ui,
|
|
1196
|
+
inputSchema: hasDynamicSchema ? (0, schemaStructure_1.zodToJsonSchema)(card.inputSchema) : undefined,
|
|
1197
|
+
toolId: tool.id,
|
|
1198
|
+
toolName: tool.name,
|
|
1199
|
+
});
|
|
1531
1200
|
}
|
|
1532
|
-
const isDynamic = !!card.inputSchema;
|
|
1533
|
-
const inputSchema = isDynamic ? (0, schemaStructure_1.zodToJsonSchema)(card.inputSchema) : undefined;
|
|
1534
|
-
const searchText = normalizeRecommendationText([tool.id, tool.name, card.id, ...card.tags].join(" "));
|
|
1535
|
-
index.set(scopedCardId, {
|
|
1536
|
-
cardId: scopedCardId,
|
|
1537
|
-
localCardId: card.id,
|
|
1538
|
-
toolId: tool.id,
|
|
1539
|
-
toolName: tool.name,
|
|
1540
|
-
tags: card.tags,
|
|
1541
|
-
inputSchema,
|
|
1542
|
-
ui: isDynamic ? undefined : card.ui,
|
|
1543
|
-
isDynamic,
|
|
1544
|
-
card,
|
|
1545
|
-
searchText,
|
|
1546
|
-
});
|
|
1547
|
-
}
|
|
1548
|
-
}
|
|
1549
|
-
return index;
|
|
1550
|
-
}
|
|
1551
|
-
function scoreRecommendationCard(card, tokens) {
|
|
1552
|
-
if (tokens.length === 0)
|
|
1553
|
-
return 0;
|
|
1554
|
-
let score = 0;
|
|
1555
|
-
const tagSet = new Set(card.tags.map((tag) => normalizeRecommendationText(tag)));
|
|
1556
|
-
const scopedId = normalizeRecommendationText(card.cardId);
|
|
1557
|
-
const toolName = normalizeRecommendationText(card.toolName);
|
|
1558
|
-
for (const token of tokens) {
|
|
1559
|
-
if (scopedId === token || card.localCardId.toLowerCase() === token) {
|
|
1560
|
-
score += 6;
|
|
1561
|
-
continue;
|
|
1562
|
-
}
|
|
1563
|
-
if (tagSet.has(token)) {
|
|
1564
|
-
score += 4;
|
|
1565
|
-
}
|
|
1566
|
-
if (toolName.includes(token)) {
|
|
1567
|
-
score += 3;
|
|
1568
|
-
}
|
|
1569
|
-
if (card.searchText.includes(token)) {
|
|
1570
|
-
score += 1;
|
|
1571
1201
|
}
|
|
1572
1202
|
}
|
|
1573
|
-
return
|
|
1574
|
-
}
|
|
1575
|
-
const recommendationCardsById = buildRecommendationIndex();
|
|
1576
|
-
const recommendationSearchSchema = zod_1.z.object({
|
|
1577
|
-
query: zod_1.z.string().optional(),
|
|
1578
|
-
limit: zod_1.z.number().int().min(1).max(50).optional().default(12),
|
|
1579
|
-
toolIds: zod_1.z.array(zod_1.z.string()).optional(),
|
|
1580
|
-
includeStaticUI: zod_1.z.boolean().optional().default(false),
|
|
1203
|
+
return c.json({ cards, count: cards.length });
|
|
1581
1204
|
});
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
const
|
|
1585
|
-
const
|
|
1586
|
-
const
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
const toolIdSet = toolIds?.length ? new Set(toolIds) : null;
|
|
1597
|
-
const filteredCards = Array.from(recommendationCardsById.values()).filter((card) => !toolIdSet || toolIdSet.has(card.toolId));
|
|
1598
|
-
const tokens = tokenizeRecommendationQuery(query ?? "");
|
|
1599
|
-
const ranked = filteredCards
|
|
1600
|
-
.map((card, index) => ({
|
|
1601
|
-
...card,
|
|
1602
|
-
score: scoreRecommendationCard(card, tokens),
|
|
1603
|
-
index,
|
|
1604
|
-
}))
|
|
1605
|
-
.sort((a, b) => {
|
|
1606
|
-
if (tokens.length === 0)
|
|
1607
|
-
return a.index - b.index;
|
|
1608
|
-
if (b.score !== a.score)
|
|
1609
|
-
return b.score - a.score;
|
|
1610
|
-
if (a.toolName !== b.toolName)
|
|
1611
|
-
return a.toolName.localeCompare(b.toolName);
|
|
1612
|
-
return a.localCardId.localeCompare(b.localCardId);
|
|
1613
|
-
})
|
|
1614
|
-
.slice(0, limit);
|
|
1615
|
-
const cards = ranked.map((card) => ({
|
|
1616
|
-
cardId: card.cardId,
|
|
1617
|
-
localCardId: card.localCardId,
|
|
1618
|
-
toolId: card.toolId,
|
|
1619
|
-
toolName: card.toolName,
|
|
1620
|
-
tags: card.tags,
|
|
1621
|
-
score: card.score,
|
|
1622
|
-
inputSchema: card.inputSchema,
|
|
1623
|
-
ui: includeStaticUI && !card.isDynamic ? card.ui : undefined,
|
|
1624
|
-
isDynamic: card.isDynamic,
|
|
1625
|
-
}));
|
|
1626
|
-
const response = {
|
|
1627
|
-
cards,
|
|
1628
|
-
count: cards.length,
|
|
1629
|
-
query,
|
|
1630
|
-
};
|
|
1631
|
-
const processedResponse = await processPluginsForResponse(response, body, { extraData: { plugins: processedPluginData.plugins } });
|
|
1632
|
-
return c.json(processedResponse);
|
|
1633
|
-
});
|
|
1634
|
-
const recommendationRenderSchema = zod_1.z.object({
|
|
1635
|
-
cards: zod_1.z
|
|
1636
|
-
.array(zod_1.z.object({
|
|
1637
|
-
cardId: zod_1.z.string().min(1),
|
|
1638
|
-
params: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
|
|
1639
|
-
context: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
|
|
1640
|
-
}))
|
|
1641
|
-
.min(1)
|
|
1642
|
-
.max(8),
|
|
1643
|
-
continueOnError: zod_1.z.boolean().optional().default(true),
|
|
1644
|
-
});
|
|
1645
|
-
app.post("/recommendations/render", async (c) => {
|
|
1646
|
-
const agentInfo = await getAgentInfo(c);
|
|
1647
|
-
const body = await safeParseBody(c);
|
|
1648
|
-
const processedPluginData = await processPluginsForRequest(body, agentInfo);
|
|
1649
|
-
const requestData = { ...processedPluginData };
|
|
1650
|
-
delete requestData.plugins;
|
|
1651
|
-
const parsed = recommendationRenderSchema.safeParse(requestData);
|
|
1652
|
-
if (!parsed.success) {
|
|
1653
|
-
return c.json({
|
|
1654
|
-
error: "Invalid recommendation render request",
|
|
1655
|
-
details: parsed.error.format(),
|
|
1656
|
-
}, 400);
|
|
1657
|
-
}
|
|
1658
|
-
const { cards: requestedCards, continueOnError } = parsed.data;
|
|
1659
|
-
const renderedCards = [];
|
|
1660
|
-
const renderErrors = [];
|
|
1661
|
-
for (const requested of requestedCards) {
|
|
1662
|
-
const card = recommendationCardsById.get(requested.cardId);
|
|
1663
|
-
if (!card) {
|
|
1664
|
-
renderErrors.push({
|
|
1665
|
-
cardId: requested.cardId,
|
|
1666
|
-
code: "not_found",
|
|
1667
|
-
message: `Card not found: ${requested.cardId}`,
|
|
1668
|
-
});
|
|
1669
|
-
if (!continueOnError)
|
|
1670
|
-
break;
|
|
1671
|
-
continue;
|
|
1672
|
-
}
|
|
1673
|
-
if (!card.isDynamic) {
|
|
1674
|
-
renderedCards.push({
|
|
1675
|
-
cardId: card.cardId,
|
|
1676
|
-
localCardId: card.localCardId,
|
|
1677
|
-
toolId: card.toolId,
|
|
1678
|
-
toolName: card.toolName,
|
|
1679
|
-
tags: card.tags,
|
|
1680
|
-
ui: card.card.ui,
|
|
1681
|
-
});
|
|
1682
|
-
continue;
|
|
1683
|
-
}
|
|
1684
|
-
const paramsInput = requested.params ?? {};
|
|
1685
|
-
const parseResult = card.card.inputSchema.safeParse(paramsInput);
|
|
1686
|
-
if (!parseResult.success) {
|
|
1687
|
-
renderErrors.push({
|
|
1688
|
-
cardId: card.cardId,
|
|
1689
|
-
code: "invalid_params",
|
|
1690
|
-
message: "Invalid parameters",
|
|
1691
|
-
details: parseResult.error.format(),
|
|
1692
|
-
});
|
|
1693
|
-
if (!continueOnError)
|
|
1694
|
-
break;
|
|
1695
|
-
continue;
|
|
1696
|
-
}
|
|
1697
|
-
if (typeof card.card.ui !== "function") {
|
|
1698
|
-
renderErrors.push({
|
|
1699
|
-
cardId: card.cardId,
|
|
1700
|
-
code: "render_failed",
|
|
1701
|
-
message: `Card "${card.cardId}" is dynamic but has no UI generator function`,
|
|
1702
|
-
});
|
|
1703
|
-
if (!continueOnError)
|
|
1704
|
-
break;
|
|
1705
|
-
continue;
|
|
1706
|
-
}
|
|
1707
|
-
try {
|
|
1708
|
-
const ui = await card.card.ui(parseResult.data, requested.context ?? {});
|
|
1709
|
-
renderedCards.push({
|
|
1710
|
-
cardId: card.cardId,
|
|
1711
|
-
localCardId: card.localCardId,
|
|
1712
|
-
toolId: card.toolId,
|
|
1713
|
-
toolName: card.toolName,
|
|
1714
|
-
tags: card.tags,
|
|
1715
|
-
ui,
|
|
1716
|
-
params: parseResult.data,
|
|
1717
|
-
});
|
|
1718
|
-
}
|
|
1719
|
-
catch (error) {
|
|
1720
|
-
renderErrors.push({
|
|
1721
|
-
cardId: card.cardId,
|
|
1722
|
-
code: "render_failed",
|
|
1723
|
-
message: error instanceof Error ? error.message : "Failed to render recommendation card",
|
|
1724
|
-
});
|
|
1725
|
-
if (!continueOnError)
|
|
1726
|
-
break;
|
|
1205
|
+
// Generate recommendation card UI
|
|
1206
|
+
app.post("/recommendations/:id/generate", async (c) => {
|
|
1207
|
+
const cardId = c.req.param("id");
|
|
1208
|
+
const body = await c.req.json().catch(() => ({}));
|
|
1209
|
+
const params = body.params ?? {};
|
|
1210
|
+
const context = body.context ?? {};
|
|
1211
|
+
let foundCard;
|
|
1212
|
+
let foundTool;
|
|
1213
|
+
for (const tool of tools) {
|
|
1214
|
+
const card = tool.recommendations?.find((r) => r.id === cardId);
|
|
1215
|
+
if (card) {
|
|
1216
|
+
foundCard = card;
|
|
1217
|
+
foundTool = tool;
|
|
1218
|
+
break;
|
|
1727
1219
|
}
|
|
1728
1220
|
}
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
const
|
|
1737
|
-
|
|
1221
|
+
if (!foundCard) {
|
|
1222
|
+
return c.json({ error: `Card not found: ${cardId}` }, 404);
|
|
1223
|
+
}
|
|
1224
|
+
const baseResponse = { id: cardId, toolId: foundTool?.id, toolName: foundTool?.name };
|
|
1225
|
+
if (!foundCard.inputSchema) {
|
|
1226
|
+
return c.json({ ...baseResponse, ui: foundCard.ui });
|
|
1227
|
+
}
|
|
1228
|
+
const parseResult = foundCard.inputSchema.safeParse(params);
|
|
1229
|
+
if (!parseResult.success) {
|
|
1230
|
+
return c.json({ error: "Invalid parameters", details: parseResult.error.format() }, 400);
|
|
1231
|
+
}
|
|
1232
|
+
if (typeof foundCard.ui !== "function") {
|
|
1233
|
+
return c.json({ error: `Card ${cardId} has inputSchema but ui is not a function` }, 500);
|
|
1234
|
+
}
|
|
1235
|
+
try {
|
|
1236
|
+
const ui = await foundCard.ui(parseResult.data, context);
|
|
1237
|
+
return c.json({ ...baseResponse, ui, params: parseResult.data });
|
|
1238
|
+
}
|
|
1239
|
+
catch (e) {
|
|
1240
|
+
const message = e instanceof Error ? e.message : "Unknown error";
|
|
1241
|
+
return c.json({ error: `Failed to generate UI: ${message}` }, 500);
|
|
1242
|
+
}
|
|
1738
1243
|
});
|
|
1739
1244
|
// Process request with plugins
|
|
1740
1245
|
async function processPluginsForRequest(request, agentInfo) {
|
|
@@ -1915,7 +1420,6 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1915
1420
|
}
|
|
1916
1421
|
catch (error) {
|
|
1917
1422
|
console.error(`Error in stream for ${tool.id}:`, error);
|
|
1918
|
-
const safeMsg = sanitizeErrorMessage(error);
|
|
1919
1423
|
// Send an error result rather than letting the stream end without a response
|
|
1920
1424
|
try {
|
|
1921
1425
|
if (withContext) {
|
|
@@ -1923,8 +1427,8 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1923
1427
|
event: 'result',
|
|
1924
1428
|
data: JSON.stringify({
|
|
1925
1429
|
toolResult: {
|
|
1926
|
-
error:
|
|
1927
|
-
text: `Error: ${
|
|
1430
|
+
error: error.message || "Unknown error",
|
|
1431
|
+
text: `Error: ${error.message || "Unknown error"}`,
|
|
1928
1432
|
data: null,
|
|
1929
1433
|
ui: null
|
|
1930
1434
|
},
|
|
@@ -1937,8 +1441,8 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1937
1441
|
await stream.writeSSE({
|
|
1938
1442
|
event: 'result',
|
|
1939
1443
|
data: JSON.stringify({
|
|
1940
|
-
error:
|
|
1941
|
-
text: `Error: ${
|
|
1444
|
+
error: error.message || "Unknown error",
|
|
1445
|
+
text: `Error: ${error.message || "Unknown error"}`,
|
|
1942
1446
|
data: null,
|
|
1943
1447
|
ui: null
|
|
1944
1448
|
}),
|
|
@@ -2030,14 +1534,13 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2030
1534
|
}
|
|
2031
1535
|
catch (error) {
|
|
2032
1536
|
console.error(`Error executing tool ${tool.id} (non-streaming):`, error);
|
|
2033
|
-
const safeMsg = sanitizeErrorMessage(error);
|
|
2034
1537
|
// Return formatted error response to match streaming behavior
|
|
2035
1538
|
let errorResponse;
|
|
2036
1539
|
if (withContext) {
|
|
2037
1540
|
errorResponse = {
|
|
2038
1541
|
toolResult: {
|
|
2039
|
-
error:
|
|
2040
|
-
text: `Error: ${
|
|
1542
|
+
error: error.message || "Unknown error",
|
|
1543
|
+
text: `Error: ${error.message || "Unknown error"}`,
|
|
2041
1544
|
data: null,
|
|
2042
1545
|
ui: null
|
|
2043
1546
|
},
|
|
@@ -2046,8 +1549,8 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2046
1549
|
}
|
|
2047
1550
|
else {
|
|
2048
1551
|
errorResponse = {
|
|
2049
|
-
error:
|
|
2050
|
-
text: `Error: ${
|
|
1552
|
+
error: error.message || "Unknown error",
|
|
1553
|
+
text: `Error: ${error.message || "Unknown error"}`,
|
|
2051
1554
|
data: null,
|
|
2052
1555
|
ui: null
|
|
2053
1556
|
};
|