@dainprotocol/service-sdk 2.0.95 → 2.1.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 +29 -0
- package/dist/client/types.d.ts +252 -0
- package/dist/client/types.js +159 -31
- package/dist/client/types.js.map +1 -1
- package/dist/protocol/grants.d.ts +12 -0
- package/dist/protocol/registry.d.ts +6 -4
- package/dist/service/auth.d.ts +15 -1
- package/dist/service/auth.js +156 -35
- package/dist/service/auth.js.map +1 -1
- package/dist/service/server.js +306 -183
- package/dist/service/server.js.map +1 -1
- package/dist/service/service.js +6 -8
- package/dist/service/service.js.map +1 -1
- package/dist/service/types.d.ts +10 -9
- package/package.json +1 -1
package/dist/service/server.js
CHANGED
|
@@ -142,20 +142,26 @@ function getRuntimeContextFromJwtPayload(payload, options = {}) {
|
|
|
142
142
|
const account = getObjectClaim(payload, "account_context");
|
|
143
143
|
const group = getObjectClaim(payload, "group_context");
|
|
144
144
|
const auth = getObjectClaim(payload, "auth_context");
|
|
145
|
-
const dainAccountId = getStringClaim(payload, "dain_account_id", "account_id") ??
|
|
146
|
-
|
|
147
|
-
const dainGroupId = getStringClaim(payload, "dain_group_id", "group_id") ??
|
|
148
|
-
group?.id;
|
|
145
|
+
const dainAccountId = getStringClaim(payload, "dain_account_id", "account_id") ?? account?.id;
|
|
146
|
+
const dainGroupId = getStringClaim(payload, "dain_group_id", "group_id") ?? group?.id;
|
|
149
147
|
const smartAccountPDA = getStringClaim(payload, "smart_account_pda") ??
|
|
150
148
|
options.fallbackSmartAccountPDA;
|
|
151
149
|
if (account?.id && dainAccountId && account.id !== dainAccountId) {
|
|
152
|
-
throw new http_exception_1.HTTPException(401, {
|
|
150
|
+
throw new http_exception_1.HTTPException(401, {
|
|
151
|
+
message: "JWT DAIN context mismatch: dain_account_id does not match account_context.id",
|
|
152
|
+
});
|
|
153
153
|
}
|
|
154
154
|
if (group?.id && dainGroupId && group.id !== dainGroupId) {
|
|
155
|
-
throw new http_exception_1.HTTPException(401, {
|
|
155
|
+
throw new http_exception_1.HTTPException(401, {
|
|
156
|
+
message: "JWT DAIN context mismatch: dain_group_id does not match group_context.id",
|
|
157
|
+
});
|
|
156
158
|
}
|
|
157
|
-
if (account?.smartAccount?.pda &&
|
|
158
|
-
|
|
159
|
+
if (account?.smartAccount?.pda &&
|
|
160
|
+
smartAccountPDA &&
|
|
161
|
+
account.smartAccount.pda !== smartAccountPDA) {
|
|
162
|
+
throw new http_exception_1.HTTPException(401, {
|
|
163
|
+
message: "JWT DAIN context mismatch: smart_account_pda does not match account_context.smartAccount.pda",
|
|
164
|
+
});
|
|
159
165
|
}
|
|
160
166
|
const grants = getArrayClaim(payload, "action_grants");
|
|
161
167
|
const dataPermissions = getArrayClaim(payload, "data_permissions");
|
|
@@ -184,15 +190,23 @@ function getRuntimeContextFromJwtPayload(payload, options = {}) {
|
|
|
184
190
|
}
|
|
185
191
|
function getRuntimeContextFromAgentInfo(agentInfo) {
|
|
186
192
|
return {
|
|
187
|
-
...(agentInfo.dainAccountId
|
|
193
|
+
...(agentInfo.dainAccountId
|
|
194
|
+
? { dainAccountId: agentInfo.dainAccountId }
|
|
195
|
+
: {}),
|
|
188
196
|
...(agentInfo.dainGroupId ? { dainGroupId: agentInfo.dainGroupId } : {}),
|
|
189
|
-
...(agentInfo.smartAccountPDA
|
|
197
|
+
...(agentInfo.smartAccountPDA
|
|
198
|
+
? { smartAccountPDA: agentInfo.smartAccountPDA }
|
|
199
|
+
: {}),
|
|
190
200
|
...(agentInfo.account ? { account: agentInfo.account } : {}),
|
|
191
201
|
...(agentInfo.group ? { group: agentInfo.group } : {}),
|
|
192
202
|
...(agentInfo.auth ? { auth: agentInfo.auth } : {}),
|
|
193
203
|
...(agentInfo.grants ? { grants: agentInfo.grants } : {}),
|
|
194
|
-
...(agentInfo.dataPermissions
|
|
195
|
-
|
|
204
|
+
...(agentInfo.dataPermissions
|
|
205
|
+
? { dataPermissions: agentInfo.dataPermissions }
|
|
206
|
+
: {}),
|
|
207
|
+
...(agentInfo.registryPolicy
|
|
208
|
+
? { registryPolicy: agentInfo.registryPolicy }
|
|
209
|
+
: {}),
|
|
196
210
|
};
|
|
197
211
|
}
|
|
198
212
|
function getRequestExtraData(request) {
|
|
@@ -221,12 +235,14 @@ function buildServiceExtraData(agentInfo, options = {}) {
|
|
|
221
235
|
*/
|
|
222
236
|
function requireScope(requiredScope) {
|
|
223
237
|
return async (c, next) => {
|
|
224
|
-
const scopes = c.get(
|
|
225
|
-
const requiredScopes = Array.isArray(requiredScope)
|
|
226
|
-
|
|
238
|
+
const scopes = c.get("scope") || [];
|
|
239
|
+
const requiredScopes = Array.isArray(requiredScope)
|
|
240
|
+
? requiredScope
|
|
241
|
+
: [requiredScope];
|
|
242
|
+
const hasRequiredScope = requiredScopes.some((scope) => (0, auth_2.hasScope)(scopes, scope));
|
|
227
243
|
if (!hasRequiredScope) {
|
|
228
244
|
throw new http_exception_1.HTTPException(403, {
|
|
229
|
-
message: `Insufficient scope. Required: ${requiredScopes.join(
|
|
245
|
+
message: `Insufficient scope. Required: ${requiredScopes.join(" OR ")}, Have: ${scopes.join(", ")}`,
|
|
230
246
|
});
|
|
231
247
|
}
|
|
232
248
|
await next();
|
|
@@ -256,16 +272,26 @@ function signedStreamSSE(c, privateKey, config, handler) {
|
|
|
256
272
|
const messageHash = (0, sseSignature_1.hashEventMessage)(event.data, timestamp);
|
|
257
273
|
const signature = (0, utils_js_1.bytesToHex)(sseSignature_1.ed25519.sign(messageHash, privateKey));
|
|
258
274
|
// Fast path for non-critical events (progress/UI updates)
|
|
259
|
-
const isCriticalEvent = event.event ===
|
|
260
|
-
event.event ===
|
|
261
|
-
event.event ===
|
|
275
|
+
const isCriticalEvent = event.event === "result" ||
|
|
276
|
+
event.event === "process-created" ||
|
|
277
|
+
event.event === "datasource-update";
|
|
262
278
|
const dataWithSignature = isCriticalEvent
|
|
263
279
|
? JSON.stringify({
|
|
264
280
|
data: JSON.parse(event.data),
|
|
265
|
-
_signature: {
|
|
281
|
+
_signature: {
|
|
282
|
+
signature,
|
|
283
|
+
timestamp,
|
|
284
|
+
agentId: config.identity.agentId,
|
|
285
|
+
orgId: config.identity.orgId,
|
|
286
|
+
address: config.identity.publicKey,
|
|
287
|
+
},
|
|
266
288
|
})
|
|
267
289
|
: `{"data":${event.data},"_signature":{"signature":"${signature}","timestamp":"${timestamp}","agentId":"${config.identity.agentId}","orgId":"${config.identity.orgId}","address":"${config.identity.publicKey}"}}`;
|
|
268
|
-
await stream.writeSSE({
|
|
290
|
+
await stream.writeSSE({
|
|
291
|
+
event: event.event,
|
|
292
|
+
data: dataWithSignature,
|
|
293
|
+
id: event.id,
|
|
294
|
+
});
|
|
269
295
|
},
|
|
270
296
|
isAborted,
|
|
271
297
|
onAbort: (listener) => stream.onAbort(listener),
|
|
@@ -285,7 +311,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
285
311
|
serviceId: "service_" + config.identity.orgId + "_" + config.identity.agentId,
|
|
286
312
|
privateKey,
|
|
287
313
|
store: config.processStore,
|
|
288
|
-
onHumanActionResponse: config.onHumanActionResponse
|
|
314
|
+
onHumanActionResponse: config.onHumanActionResponse,
|
|
289
315
|
});
|
|
290
316
|
app.processes = processHandler;
|
|
291
317
|
// CORS middleware - apply to all routes
|
|
@@ -334,7 +360,8 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
334
360
|
const isStreaming = acceptHeader.includes("text/event-stream");
|
|
335
361
|
await next();
|
|
336
362
|
// Skip signature for streaming responses
|
|
337
|
-
if (isStreaming ||
|
|
363
|
+
if (isStreaming ||
|
|
364
|
+
c.res.headers.get("content-type")?.includes("text/event-stream")) {
|
|
338
365
|
return;
|
|
339
366
|
}
|
|
340
367
|
const body = await c.res.clone().text();
|
|
@@ -347,12 +374,14 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
347
374
|
});
|
|
348
375
|
// Get all webhook paths for auth bypass
|
|
349
376
|
const webhookPaths = config.webhookTriggers?.getWebhookPaths() || [];
|
|
350
|
-
const hitlPath = config.hitl?.enabled
|
|
377
|
+
const hitlPath = config.hitl?.enabled
|
|
378
|
+
? config.hitl.webhookPath || "/actions"
|
|
379
|
+
: null;
|
|
351
380
|
// Dual Authentication: JWT (users) or API Key (services)
|
|
352
381
|
app.use("*", async (c, next) => {
|
|
353
382
|
debugLog(`[Auth Middleware] Path: ${c.req.path}, Method: ${c.req.method}`);
|
|
354
383
|
// Check if path is a webhook path (auth bypass)
|
|
355
|
-
const isWebhookPath = webhookPaths.some(path => c.req.path === path);
|
|
384
|
+
const isWebhookPath = webhookPaths.some((path) => c.req.path === path);
|
|
356
385
|
const isHITLPath = hitlPath && c.req.path === hitlPath;
|
|
357
386
|
if (c.req.path.startsWith("/oauth2/callback/") ||
|
|
358
387
|
c.req.path.startsWith("/addons") ||
|
|
@@ -374,16 +403,20 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
374
403
|
const host = getFirstForwardedValue(c.req.header("x-forwarded-host")) ||
|
|
375
404
|
getFirstForwardedValue(c.req.header("host"));
|
|
376
405
|
if (!host) {
|
|
377
|
-
throw new http_exception_1.HTTPException(400, {
|
|
406
|
+
throw new http_exception_1.HTTPException(400, {
|
|
407
|
+
message: "Unable to determine service URL. Host header is required.",
|
|
408
|
+
});
|
|
378
409
|
}
|
|
379
410
|
// Validate host format to prevent obvious attacks
|
|
380
|
-
if (host.includes(
|
|
411
|
+
if (host.includes(" ") || host.includes("\n") || host.includes("\r")) {
|
|
381
412
|
throw new http_exception_1.HTTPException(400, { message: "Invalid Host header format" });
|
|
382
413
|
}
|
|
383
414
|
const xForwardedProto = getFirstForwardedValue(c.req.header("x-forwarded-proto"));
|
|
384
415
|
const protocol = xForwardedProto === "http" || xForwardedProto === "https"
|
|
385
416
|
? xForwardedProto
|
|
386
|
-
:
|
|
417
|
+
: host.includes("localhost") || host.startsWith("127.")
|
|
418
|
+
? "http"
|
|
419
|
+
: "https";
|
|
387
420
|
const forwardedPrefix = normalizeForwardedPrefix(getFirstForwardedValue(c.req.header("x-forwarded-prefix")));
|
|
388
421
|
const jwtAudiences = [`${protocol}://${host}`];
|
|
389
422
|
if (forwardedPrefix) {
|
|
@@ -396,7 +429,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
396
429
|
audience: jwtAudiences,
|
|
397
430
|
});
|
|
398
431
|
if (!result.valid) {
|
|
399
|
-
throw new http_exception_1.HTTPException(401, {
|
|
432
|
+
throw new http_exception_1.HTTPException(401, {
|
|
433
|
+
message: `JWT verification failed: ${result.error}`,
|
|
434
|
+
});
|
|
400
435
|
}
|
|
401
436
|
// Defense in depth: double-check audience claim
|
|
402
437
|
const tokenAudiences = Array.isArray(result.payload?.aud)
|
|
@@ -406,21 +441,21 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
406
441
|
const audienceMatched = tokenAudiences.some((aud) => aud && expectedAudienceSet.has(aud));
|
|
407
442
|
if (!audienceMatched) {
|
|
408
443
|
throw new http_exception_1.HTTPException(403, {
|
|
409
|
-
message: `JWT audience mismatch. Expected one of: ${jwtAudiences.join(", ")}, Got: ${tokenAudiences.filter(Boolean).join(", ")}
|
|
444
|
+
message: `JWT audience mismatch. Expected one of: ${jwtAudiences.join(", ")}, Got: ${tokenAudiences.filter(Boolean).join(", ")}`,
|
|
410
445
|
});
|
|
411
446
|
}
|
|
412
|
-
c.set(
|
|
413
|
-
c.set(
|
|
414
|
-
c.set(
|
|
415
|
-
c.set(
|
|
416
|
-
c.set(
|
|
447
|
+
c.set("authMethod", "jwt");
|
|
448
|
+
c.set("smartAccountId", result.smartAccountId);
|
|
449
|
+
c.set("address", result.smartAccountId); // Use smartAccountId as address for JWT auth
|
|
450
|
+
c.set("scope", result.scope);
|
|
451
|
+
c.set("jwtPayload", result.payload);
|
|
417
452
|
const jwtRuntimeContext = getRuntimeContextFromJwtPayload(result.payload, {
|
|
418
453
|
scopes: result.scope,
|
|
419
454
|
smartAccountId: result.smartAccountId,
|
|
420
455
|
fallbackSmartAccountPDA: c.req.header("X-DAIN-SMART-ACCOUNT-PDA"),
|
|
421
456
|
});
|
|
422
|
-
c.set(
|
|
423
|
-
c.set(
|
|
457
|
+
c.set("dainRuntimeContext", jwtRuntimeContext);
|
|
458
|
+
c.set("smartAccountPDA", jwtRuntimeContext.smartAccountPDA);
|
|
424
459
|
debugLog(`[Auth Middleware] JWT auth SUCCESS - smartAccountId: ${result.smartAccountId}`);
|
|
425
460
|
}
|
|
426
461
|
else if (apiKey) {
|
|
@@ -438,15 +473,21 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
438
473
|
throw new http_exception_1.HTTPException(401, { message: "Invalid API key" });
|
|
439
474
|
}
|
|
440
475
|
}
|
|
441
|
-
c.set(
|
|
442
|
-
c.set(
|
|
443
|
-
c.set(
|
|
444
|
-
c.set(
|
|
445
|
-
c.set(
|
|
446
|
-
c.set(
|
|
447
|
-
...(c.req.header("X-DAIN-ACCOUNT-ID")
|
|
448
|
-
|
|
449
|
-
|
|
476
|
+
c.set("authMethod", "apiKey");
|
|
477
|
+
c.set("agentId", parsed.agentId);
|
|
478
|
+
c.set("orgId", parsed.orgId);
|
|
479
|
+
c.set("address", parsed.agentId); // Use agentId as address for API key auth
|
|
480
|
+
c.set("smartAccountPDA", c.req.header("X-DAIN-SMART-ACCOUNT-PDA"));
|
|
481
|
+
c.set("dainRuntimeContext", {
|
|
482
|
+
...(c.req.header("X-DAIN-ACCOUNT-ID")
|
|
483
|
+
? { dainAccountId: c.req.header("X-DAIN-ACCOUNT-ID") }
|
|
484
|
+
: {}),
|
|
485
|
+
...(c.req.header("X-DAIN-GROUP-ID")
|
|
486
|
+
? { dainGroupId: c.req.header("X-DAIN-GROUP-ID") }
|
|
487
|
+
: {}),
|
|
488
|
+
...(c.req.header("X-DAIN-SMART-ACCOUNT-PDA")
|
|
489
|
+
? { smartAccountPDA: c.req.header("X-DAIN-SMART-ACCOUNT-PDA") }
|
|
490
|
+
: {}),
|
|
450
491
|
});
|
|
451
492
|
debugLog(`[Auth Middleware] API Key auth SUCCESS - agentId: ${parsed.agentId}, orgId: ${parsed.orgId}`);
|
|
452
493
|
}
|
|
@@ -458,14 +499,17 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
458
499
|
});
|
|
459
500
|
async function getAgentInfo(c) {
|
|
460
501
|
debugLog("[getAgentInfo] START");
|
|
461
|
-
debugLog("[getAgentInfo] Auth method:", c.get(
|
|
462
|
-
const runtimeContext = (c.get(
|
|
463
|
-
|
|
502
|
+
debugLog("[getAgentInfo] Auth method:", c.get("authMethod"));
|
|
503
|
+
const runtimeContext = (c.get("dainRuntimeContext") ||
|
|
504
|
+
{});
|
|
505
|
+
const smartAccountPDA = runtimeContext.smartAccountPDA ||
|
|
506
|
+
c.get("smartAccountPDA") ||
|
|
507
|
+
c.req.header("X-DAIN-SMART-ACCOUNT-PDA");
|
|
464
508
|
const webhookUrl = c.req.header("X-DAIN-WEBHOOK-URL");
|
|
465
509
|
debugLog("[getAgentInfo] smartAccountPDA:", smartAccountPDA);
|
|
466
510
|
debugLog("[getAgentInfo] webhookUrl:", webhookUrl);
|
|
467
|
-
if (c.get(
|
|
468
|
-
const smartAccountId = c.get(
|
|
511
|
+
if (c.get("authMethod") === "jwt") {
|
|
512
|
+
const smartAccountId = c.get("smartAccountId");
|
|
469
513
|
debugLog("[getAgentInfo] JWT auth - smartAccountId:", smartAccountId);
|
|
470
514
|
const agentInfo = {
|
|
471
515
|
agentId: smartAccountId,
|
|
@@ -481,14 +525,16 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
481
525
|
registryPolicy: runtimeContext.registryPolicy,
|
|
482
526
|
id: runtimeContext.dainAccountId ??
|
|
483
527
|
runtimeContext.dainGroupId ??
|
|
484
|
-
(smartAccountPDA
|
|
528
|
+
(smartAccountPDA
|
|
529
|
+
? `dain_id_${smartAccountPDA}`
|
|
530
|
+
: `smart_account_${smartAccountId}`),
|
|
485
531
|
webhookUrl,
|
|
486
532
|
};
|
|
487
533
|
debugLog("[getAgentInfo] JWT - Returning agent info:", agentInfo);
|
|
488
534
|
return agentInfo;
|
|
489
535
|
}
|
|
490
|
-
const agentId = c.get(
|
|
491
|
-
const address = c.get(
|
|
536
|
+
const agentId = c.get("agentId");
|
|
537
|
+
const address = c.get("address");
|
|
492
538
|
debugLog("[getAgentInfo] API Key auth - agentId:", agentId, "address:", address);
|
|
493
539
|
const agentInfo = {
|
|
494
540
|
agentId,
|
|
@@ -534,7 +580,8 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
534
580
|
app.get("/metadata", (c) => {
|
|
535
581
|
// Compute service-level capability: does ANY tool support user actions (HITL)?
|
|
536
582
|
const supportsUserActions = tools.some((tool) => tool.supportsUserActions === true);
|
|
537
|
-
const requestedContract = c.req.header("x-butterfly-contract") ||
|
|
583
|
+
const requestedContract = c.req.header("x-butterfly-contract") ||
|
|
584
|
+
c.req.header("X-Butterfly-Contract");
|
|
538
585
|
const sdkMajor = Number.parseInt(String(package_json_1.default.version).split(".")[0] || "0", 10);
|
|
539
586
|
const contractVersion = Number.isFinite(sdkMajor) && sdkMajor > 0 ? `${sdkMajor}.0.0` : "0.0.0";
|
|
540
587
|
const capabilities = {
|
|
@@ -553,6 +600,8 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
553
600
|
actionGrants: true,
|
|
554
601
|
smartAccountTransactions: true,
|
|
555
602
|
payments: true,
|
|
603
|
+
registryPolicy: true,
|
|
604
|
+
grantPolicies: true,
|
|
556
605
|
};
|
|
557
606
|
const compatibility = (() => {
|
|
558
607
|
if (!requestedContract)
|
|
@@ -619,7 +668,11 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
619
668
|
const autoContexts = app.oauth2?.getDirectProviderContexts?.() || [];
|
|
620
669
|
const serviceSlug = (0, core_1.toSlug)(metadata.title);
|
|
621
670
|
const skillsContext = config.skills?.getSkillsContext?.(serviceSlug);
|
|
622
|
-
const allContexts = [
|
|
671
|
+
const allContexts = [
|
|
672
|
+
...contexts,
|
|
673
|
+
...autoContexts,
|
|
674
|
+
...(skillsContext ? [skillsContext] : []),
|
|
675
|
+
];
|
|
623
676
|
const contextInfo = allContexts.map((context) => ({
|
|
624
677
|
id: context.id,
|
|
625
678
|
name: context.name,
|
|
@@ -638,7 +691,11 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
638
691
|
const autoContexts = app.oauth2?.getDirectProviderContexts?.() || [];
|
|
639
692
|
const serviceSlug = (0, core_1.toSlug)(metadata.title);
|
|
640
693
|
const skillsContext = config.skills?.getSkillsContext?.(serviceSlug);
|
|
641
|
-
const allContexts = [
|
|
694
|
+
const allContexts = [
|
|
695
|
+
...contexts,
|
|
696
|
+
...autoContexts,
|
|
697
|
+
...(skillsContext ? [skillsContext] : []),
|
|
698
|
+
];
|
|
642
699
|
const context = allContexts.find((ctx) => ctx.id === c.req.param("contextId"));
|
|
643
700
|
if (context) {
|
|
644
701
|
const agentInfo = await getAgentInfo(c);
|
|
@@ -655,7 +712,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
655
712
|
id: context.id,
|
|
656
713
|
name: context.name,
|
|
657
714
|
description: context.description,
|
|
658
|
-
data: contextData
|
|
715
|
+
data: contextData,
|
|
659
716
|
};
|
|
660
717
|
const processedResponse = await processPluginsForResponse(response, body, { extraData });
|
|
661
718
|
return c.json(processedResponse);
|
|
@@ -677,7 +734,11 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
677
734
|
const autoContexts = app.oauth2?.getDirectProviderContexts?.() || [];
|
|
678
735
|
const serviceSlug = (0, core_1.toSlug)(metadata.title);
|
|
679
736
|
const skillsContext = config.skills?.getSkillsContext?.(serviceSlug);
|
|
680
|
-
const allContexts = [
|
|
737
|
+
const allContexts = [
|
|
738
|
+
...contexts,
|
|
739
|
+
...autoContexts,
|
|
740
|
+
...(skillsContext ? [skillsContext] : []),
|
|
741
|
+
];
|
|
681
742
|
const contextsFull = await Promise.all(allContexts.map(async (ctx) => ({
|
|
682
743
|
id: ctx.id,
|
|
683
744
|
name: ctx.name,
|
|
@@ -697,8 +758,10 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
697
758
|
});
|
|
698
759
|
const widgetIds = config.getUserWidgets
|
|
699
760
|
? await config.getUserWidgets(agentInfo, extraData)
|
|
700
|
-
: widgets.map(widget => widget.id);
|
|
701
|
-
const processedResponse = await processPluginsForResponse(widgetIds, body, {
|
|
761
|
+
: widgets.map((widget) => widget.id);
|
|
762
|
+
const processedResponse = await processPluginsForResponse(widgetIds, body, {
|
|
763
|
+
extraData,
|
|
764
|
+
});
|
|
702
765
|
return c.json(processedResponse);
|
|
703
766
|
});
|
|
704
767
|
app.post("/widgets/all", async (c) => {
|
|
@@ -710,7 +773,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
710
773
|
request: processedPluginData,
|
|
711
774
|
plugins: processedPluginData.plugins,
|
|
712
775
|
}))
|
|
713
|
-
: widgets.map(widget => widget.id);
|
|
776
|
+
: widgets.map((widget) => widget.id);
|
|
714
777
|
const oauth2Client = app.oauth2?.getClient();
|
|
715
778
|
const extraData = buildServiceExtraData(agentInfo, {
|
|
716
779
|
request: processedPluginData,
|
|
@@ -719,7 +782,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
719
782
|
app,
|
|
720
783
|
});
|
|
721
784
|
const widgetsFull = await Promise.all(widgetIds.map(async (widgetId) => {
|
|
722
|
-
const widget = widgets.find(w => w.id === widgetId);
|
|
785
|
+
const widget = widgets.find((w) => w.id === widgetId);
|
|
723
786
|
if (!widget)
|
|
724
787
|
return null;
|
|
725
788
|
const widgetData = await widget.getWidget(agentInfo, extraData);
|
|
@@ -730,7 +793,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
730
793
|
icon: widget.icon,
|
|
731
794
|
size: widget.size || "sm",
|
|
732
795
|
refreshIntervalMs: widget.refreshIntervalMs,
|
|
733
|
-
...widgetData
|
|
796
|
+
...widgetData,
|
|
734
797
|
};
|
|
735
798
|
if (!("freshness" in response)) {
|
|
736
799
|
response.freshness = {
|
|
@@ -744,13 +807,13 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
744
807
|
}
|
|
745
808
|
return response;
|
|
746
809
|
}));
|
|
747
|
-
const validWidgets = widgetsFull.filter(w => w !== null);
|
|
810
|
+
const validWidgets = widgetsFull.filter((w) => w !== null);
|
|
748
811
|
const processedResponse = await processPluginsForResponse(validWidgets, body, { extraData });
|
|
749
812
|
return c.json(processedResponse);
|
|
750
813
|
});
|
|
751
814
|
app.post("/widgets/:widgetId", async (c) => {
|
|
752
815
|
const widgetId = c.req.param("widgetId");
|
|
753
|
-
const widget = widgets.find(w => w.id === widgetId);
|
|
816
|
+
const widget = widgets.find((w) => w.id === widgetId);
|
|
754
817
|
if (!widget) {
|
|
755
818
|
throw new http_exception_1.HTTPException(404, { message: "Widget not found" });
|
|
756
819
|
}
|
|
@@ -763,16 +826,19 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
763
826
|
plugins: processedPluginData.plugins,
|
|
764
827
|
});
|
|
765
828
|
const userWidgetIds = await config.getUserWidgets(agentInfo, {
|
|
766
|
-
...accessExtraData
|
|
829
|
+
...accessExtraData,
|
|
767
830
|
});
|
|
768
831
|
let homeUIWidgetId = null;
|
|
769
832
|
if (config.homeUI) {
|
|
770
|
-
homeUIWidgetId =
|
|
771
|
-
|
|
772
|
-
|
|
833
|
+
homeUIWidgetId =
|
|
834
|
+
typeof config.homeUI === "string"
|
|
835
|
+
? config.homeUI
|
|
836
|
+
: await config.homeUI(agentInfo, accessExtraData);
|
|
773
837
|
}
|
|
774
838
|
if (!userWidgetIds.includes(widgetId) && widgetId !== homeUIWidgetId) {
|
|
775
|
-
throw new http_exception_1.HTTPException(403, {
|
|
839
|
+
throw new http_exception_1.HTTPException(403, {
|
|
840
|
+
message: "Access denied to this widget",
|
|
841
|
+
});
|
|
776
842
|
}
|
|
777
843
|
}
|
|
778
844
|
const oauth2Client = app.oauth2?.getClient();
|
|
@@ -790,7 +856,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
790
856
|
icon: widget.icon,
|
|
791
857
|
size: widget.size || "sm",
|
|
792
858
|
refreshIntervalMs: widget.refreshIntervalMs,
|
|
793
|
-
...widgetData
|
|
859
|
+
...widgetData,
|
|
794
860
|
};
|
|
795
861
|
if (!("freshness" in response)) {
|
|
796
862
|
response.freshness = {
|
|
@@ -802,7 +868,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
802
868
|
scope: "account",
|
|
803
869
|
};
|
|
804
870
|
}
|
|
805
|
-
const processedResponse = await processPluginsForResponse(response, body, {
|
|
871
|
+
const processedResponse = await processPluginsForResponse(response, body, {
|
|
872
|
+
extraData,
|
|
873
|
+
});
|
|
806
874
|
return c.json(processedResponse);
|
|
807
875
|
});
|
|
808
876
|
app.post("/homeUI", async (c) => {
|
|
@@ -816,13 +884,13 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
816
884
|
request: processedPluginData,
|
|
817
885
|
plugins: processedPluginData.plugins,
|
|
818
886
|
});
|
|
819
|
-
const homeUIWidgetId = typeof config.homeUI ===
|
|
887
|
+
const homeUIWidgetId = typeof config.homeUI === "string"
|
|
820
888
|
? config.homeUI
|
|
821
889
|
: await config.homeUI(agentInfo, extraData);
|
|
822
890
|
if (!homeUIWidgetId) {
|
|
823
891
|
return c.json({ widgetId: null });
|
|
824
892
|
}
|
|
825
|
-
const widget = widgets.find(w => w.id === homeUIWidgetId);
|
|
893
|
+
const widget = widgets.find((w) => w.id === homeUIWidgetId);
|
|
826
894
|
if (!widget) {
|
|
827
895
|
return c.json({ widgetId: null });
|
|
828
896
|
}
|
|
@@ -927,7 +995,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
927
995
|
.join(", ");
|
|
928
996
|
return c.json({
|
|
929
997
|
error: `Missing or invalid parameters: ${missingParams}`,
|
|
930
|
-
code: "INVALID_PARAMS"
|
|
998
|
+
code: "INVALID_PARAMS",
|
|
931
999
|
}, 400);
|
|
932
1000
|
}
|
|
933
1001
|
throw error;
|
|
@@ -960,17 +1028,23 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
960
1028
|
typeof rawBody === "object" &&
|
|
961
1029
|
!Array.isArray(rawBody) &&
|
|
962
1030
|
"params" in rawBody;
|
|
963
|
-
const requestedIntervalMsRaw = hasWrappedParams
|
|
964
|
-
|
|
1031
|
+
const requestedIntervalMsRaw = hasWrappedParams
|
|
1032
|
+
? rawBody.intervalMs
|
|
1033
|
+
: undefined;
|
|
1034
|
+
const requestedStreamIdRaw = hasWrappedParams
|
|
1035
|
+
? rawBody.streamId
|
|
1036
|
+
: undefined;
|
|
965
1037
|
const streamId = typeof requestedStreamIdRaw === "string" &&
|
|
966
1038
|
/^[A-Za-z0-9._:-]{1,128}$/.test(requestedStreamIdRaw)
|
|
967
1039
|
? requestedStreamIdRaw
|
|
968
1040
|
: null;
|
|
969
|
-
const requestParamsRaw = hasWrappedParams
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1041
|
+
const requestParamsRaw = hasWrappedParams
|
|
1042
|
+
? rawBody.params
|
|
1043
|
+
: rawBody;
|
|
1044
|
+
let params = await processPluginsForRequest(requestParamsRaw && typeof requestParamsRaw === "object"
|
|
1045
|
+
? requestParamsRaw
|
|
1046
|
+
: {}, agentInfo);
|
|
1047
|
+
const pluginsData = (params.plugins && typeof params.plugins === "object" ? params.plugins : {});
|
|
974
1048
|
delete params.plugins;
|
|
975
1049
|
let parsedParams;
|
|
976
1050
|
try {
|
|
@@ -983,7 +1057,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
983
1057
|
.join(", ");
|
|
984
1058
|
return c.json({
|
|
985
1059
|
error: `Missing or invalid parameters: ${missingParams}`,
|
|
986
|
-
code: "INVALID_PARAMS"
|
|
1060
|
+
code: "INVALID_PARAMS",
|
|
987
1061
|
}, 400);
|
|
988
1062
|
}
|
|
989
1063
|
throw error;
|
|
@@ -1016,11 +1090,14 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1016
1090
|
scope: datasource.scope,
|
|
1017
1091
|
dataClass: datasource.dataClass,
|
|
1018
1092
|
};
|
|
1019
|
-
const requestedIntervalMs = typeof requestedIntervalMsRaw === "number" &&
|
|
1093
|
+
const requestedIntervalMs = typeof requestedIntervalMsRaw === "number" &&
|
|
1094
|
+
Number.isFinite(requestedIntervalMsRaw) &&
|
|
1095
|
+
requestedIntervalMsRaw > 0
|
|
1020
1096
|
? requestedIntervalMsRaw
|
|
1021
1097
|
: null;
|
|
1022
1098
|
const baseIntervalMs = requestedIntervalMs ??
|
|
1023
|
-
(typeof datasource.refreshIntervalMs === "number" &&
|
|
1099
|
+
(typeof datasource.refreshIntervalMs === "number" &&
|
|
1100
|
+
datasource.refreshIntervalMs > 0
|
|
1024
1101
|
? datasource.refreshIntervalMs
|
|
1025
1102
|
: 15_000);
|
|
1026
1103
|
const intervalMs = Math.max(1_000, Math.floor(baseIntervalMs));
|
|
@@ -1033,7 +1110,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1033
1110
|
if (streamKey) {
|
|
1034
1111
|
datasourceStreamAbortControllers.set(streamKey, streamAbortController);
|
|
1035
1112
|
}
|
|
1036
|
-
const isCancelled = () => stream.isAborted() ||
|
|
1113
|
+
const isCancelled = () => stream.isAborted() ||
|
|
1114
|
+
signal?.aborted === true ||
|
|
1115
|
+
streamAbortController.signal.aborted;
|
|
1037
1116
|
const emitUpdate = async () => {
|
|
1038
1117
|
if (isCancelled())
|
|
1039
1118
|
return false;
|
|
@@ -1081,7 +1160,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1081
1160
|
if (!isCancelled()) {
|
|
1082
1161
|
await stream.writeSSE({
|
|
1083
1162
|
event: "error",
|
|
1084
|
-
data: JSON.stringify({
|
|
1163
|
+
data: JSON.stringify({
|
|
1164
|
+
message: error?.message || "Datasource stream error",
|
|
1165
|
+
}),
|
|
1085
1166
|
});
|
|
1086
1167
|
}
|
|
1087
1168
|
return;
|
|
@@ -1118,7 +1199,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1118
1199
|
if (!isCancelled()) {
|
|
1119
1200
|
await stream.writeSSE({
|
|
1120
1201
|
event: "error",
|
|
1121
|
-
data: JSON.stringify({
|
|
1202
|
+
data: JSON.stringify({
|
|
1203
|
+
message: error?.message || "Datasource stream error",
|
|
1204
|
+
}),
|
|
1122
1205
|
});
|
|
1123
1206
|
}
|
|
1124
1207
|
}
|
|
@@ -1139,7 +1222,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1139
1222
|
context: agent.context,
|
|
1140
1223
|
prompt: agent.prompt,
|
|
1141
1224
|
resolveCondition: agent.resolveCondition,
|
|
1142
|
-
serviceConnections: agent.serviceConnections || [
|
|
1225
|
+
serviceConnections: agent.serviceConnections || [
|
|
1226
|
+
process.env.BASE_URL || "http://localhost:3000",
|
|
1227
|
+
],
|
|
1143
1228
|
inputSchema: (0, schemaStructure_1.zodToJsonSchema)(agent.input),
|
|
1144
1229
|
outputSchema: (0, schemaStructure_1.zodToJsonSchema)(agent.output),
|
|
1145
1230
|
};
|
|
@@ -1183,14 +1268,16 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1183
1268
|
return c.json(processedResponse);
|
|
1184
1269
|
});
|
|
1185
1270
|
function fixEmptySchemas(schema) {
|
|
1186
|
-
if (!schema || typeof schema !==
|
|
1271
|
+
if (!schema || typeof schema !== "object")
|
|
1187
1272
|
return;
|
|
1188
|
-
if (schema.properties && typeof schema.properties ===
|
|
1273
|
+
if (schema.properties && typeof schema.properties === "object") {
|
|
1189
1274
|
const props = schema.properties;
|
|
1190
1275
|
for (const key of Object.keys(props)) {
|
|
1191
1276
|
const prop = props[key];
|
|
1192
|
-
if (prop &&
|
|
1193
|
-
|
|
1277
|
+
if (prop &&
|
|
1278
|
+
typeof prop === "object" &&
|
|
1279
|
+
Object.keys(prop).length === 0) {
|
|
1280
|
+
props[key] = { type: "object" };
|
|
1194
1281
|
}
|
|
1195
1282
|
fixEmptySchemas(prop);
|
|
1196
1283
|
}
|
|
@@ -1203,10 +1290,10 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1203
1290
|
let inputSchema = (0, schemaStructure_1.zodToJsonSchema)(tool.input);
|
|
1204
1291
|
let outputSchema = (0, schemaStructure_1.zodToJsonSchema)(tool.output);
|
|
1205
1292
|
if (!inputSchema.type) {
|
|
1206
|
-
inputSchema = { ...inputSchema, type:
|
|
1293
|
+
inputSchema = { ...inputSchema, type: "object" };
|
|
1207
1294
|
}
|
|
1208
1295
|
if (!outputSchema.type) {
|
|
1209
|
-
outputSchema = { ...outputSchema, type:
|
|
1296
|
+
outputSchema = { ...outputSchema, type: "object" };
|
|
1210
1297
|
}
|
|
1211
1298
|
fixEmptySchemas(inputSchema);
|
|
1212
1299
|
fixEmptySchemas(outputSchema);
|
|
@@ -1273,11 +1360,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1273
1360
|
// Configure trigger forwarding (uses HITL config for automation API)
|
|
1274
1361
|
if (config.webhookTriggers) {
|
|
1275
1362
|
// Resolve automation API URL (priority: hitl config > env)
|
|
1276
|
-
const automationApiUrl = config.hitl?.automationApiUrl ||
|
|
1277
|
-
process.env.AUTOMATION_API_URL;
|
|
1363
|
+
const automationApiUrl = config.hitl?.automationApiUrl || process.env.AUTOMATION_API_URL;
|
|
1278
1364
|
// Resolve API key
|
|
1279
|
-
const automationApiKey = config.hitl?.automationApiKey ||
|
|
1280
|
-
process.env.AUTOMATION_API_KEY;
|
|
1365
|
+
const automationApiKey = config.hitl?.automationApiKey || process.env.AUTOMATION_API_KEY;
|
|
1281
1366
|
// Resolve service URL (priority: oauth2.baseUrl > env)
|
|
1282
1367
|
const serviceUrl = config.oauth2?.baseUrl ||
|
|
1283
1368
|
process.env.SERVICE_BASE_URL ||
|
|
@@ -1300,10 +1385,12 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1300
1385
|
try {
|
|
1301
1386
|
const registerUrl = `${automationApiUrl}/webhooks/register-triggers`;
|
|
1302
1387
|
const response = await fetch(registerUrl, {
|
|
1303
|
-
method:
|
|
1388
|
+
method: "POST",
|
|
1304
1389
|
headers: {
|
|
1305
|
-
|
|
1306
|
-
...(automationApiKey
|
|
1390
|
+
"Content-Type": "application/json",
|
|
1391
|
+
...(automationApiKey
|
|
1392
|
+
? { Authorization: `Bearer ${automationApiKey}` }
|
|
1393
|
+
: {}),
|
|
1307
1394
|
},
|
|
1308
1395
|
body: JSON.stringify({
|
|
1309
1396
|
serviceUrl,
|
|
@@ -1328,10 +1415,10 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1328
1415
|
}
|
|
1329
1416
|
else {
|
|
1330
1417
|
if (!automationApiUrl) {
|
|
1331
|
-
console.warn(
|
|
1418
|
+
console.warn("[Webhook] Trigger forwarding disabled: missing automationApiUrl (set hitl.automationApiUrl or AUTOMATION_API_URL)");
|
|
1332
1419
|
}
|
|
1333
1420
|
if (!serviceUrl) {
|
|
1334
|
-
console.warn(
|
|
1421
|
+
console.warn("[Webhook] Trigger forwarding disabled: missing serviceUrl (set oauth2.baseUrl or SERVICE_BASE_URL)");
|
|
1335
1422
|
}
|
|
1336
1423
|
}
|
|
1337
1424
|
}
|
|
@@ -1356,7 +1443,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1356
1443
|
success: true,
|
|
1357
1444
|
triggerId: result.triggerId,
|
|
1358
1445
|
triggerName: result.triggerName,
|
|
1359
|
-
data: result.data
|
|
1446
|
+
data: result.data,
|
|
1360
1447
|
});
|
|
1361
1448
|
}
|
|
1362
1449
|
else {
|
|
@@ -1364,7 +1451,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1364
1451
|
// No trigger matched - return 200 OK but with success: false
|
|
1365
1452
|
return c.json({
|
|
1366
1453
|
success: false,
|
|
1367
|
-
message:
|
|
1454
|
+
message: "No trigger matched",
|
|
1368
1455
|
}, 200);
|
|
1369
1456
|
}
|
|
1370
1457
|
}
|
|
@@ -1372,22 +1459,22 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1372
1459
|
console.error(`[Webhook] Error processing webhook at ${path}:`, error);
|
|
1373
1460
|
// Return error response
|
|
1374
1461
|
throw new http_exception_1.HTTPException(500, {
|
|
1375
|
-
message: `Webhook processing failed: ${error.message}
|
|
1462
|
+
message: `Webhook processing failed: ${error.message}`,
|
|
1376
1463
|
});
|
|
1377
1464
|
}
|
|
1378
1465
|
});
|
|
1379
1466
|
}
|
|
1380
|
-
console.log(`[Webhook] Registered ${webhookPaths.length} webhook endpoint(s): ${webhookPaths.join(
|
|
1467
|
+
console.log(`[Webhook] Registered ${webhookPaths.length} webhook endpoint(s): ${webhookPaths.join(", ")}`);
|
|
1381
1468
|
}
|
|
1382
1469
|
// Auto-register HITL action webhook
|
|
1383
1470
|
if (config.hitl?.enabled) {
|
|
1384
|
-
const hitlPath = config.hitl.webhookPath ||
|
|
1471
|
+
const hitlPath = config.hitl.webhookPath || "/actions";
|
|
1385
1472
|
const automationApiUrl = config.hitl.automationApiUrl ||
|
|
1386
1473
|
process.env.AUTOMATION_API_URL ||
|
|
1387
|
-
|
|
1474
|
+
"http://localhost:3000";
|
|
1388
1475
|
const automationApiKey = config.hitl.automationApiKey || process.env.AUTOMATION_API_KEY;
|
|
1389
1476
|
if (!automationApiUrl) {
|
|
1390
|
-
console.warn(
|
|
1477
|
+
console.warn("[HITL] Enabled but missing automationApiUrl - HITL webhook will not work correctly");
|
|
1391
1478
|
}
|
|
1392
1479
|
const hitlHandler = new hitl_1.HITLHandler({
|
|
1393
1480
|
automationApiUrl,
|
|
@@ -1398,19 +1485,19 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1398
1485
|
try {
|
|
1399
1486
|
const body = await c.req.json();
|
|
1400
1487
|
const { action, context } = body;
|
|
1401
|
-
if (!action || typeof action !==
|
|
1488
|
+
if (!action || typeof action !== "string") {
|
|
1402
1489
|
throw new http_exception_1.HTTPException(400, {
|
|
1403
1490
|
message: 'Missing or invalid "action" field in request body',
|
|
1404
1491
|
});
|
|
1405
1492
|
}
|
|
1406
|
-
if (!context || typeof context !==
|
|
1493
|
+
if (!context || typeof context !== "object") {
|
|
1407
1494
|
throw new http_exception_1.HTTPException(400, {
|
|
1408
1495
|
message: 'Missing or invalid "context" field in request body',
|
|
1409
1496
|
});
|
|
1410
1497
|
}
|
|
1411
1498
|
if (!hitlHandler.isValidAction(action)) {
|
|
1412
1499
|
throw new http_exception_1.HTTPException(400, {
|
|
1413
|
-
message:
|
|
1500
|
+
message: "Invalid action format. Expected: scope:id:action[:payload]",
|
|
1414
1501
|
});
|
|
1415
1502
|
}
|
|
1416
1503
|
const result = await hitlHandler.handleAction(action, context);
|
|
@@ -1420,7 +1507,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1420
1507
|
if (error instanceof http_exception_1.HTTPException) {
|
|
1421
1508
|
throw error;
|
|
1422
1509
|
}
|
|
1423
|
-
console.error(
|
|
1510
|
+
console.error("[HITL] Error processing action:", error);
|
|
1424
1511
|
throw new http_exception_1.HTTPException(500, {
|
|
1425
1512
|
message: `Action processing failed: ${error.message}`,
|
|
1426
1513
|
});
|
|
@@ -1532,7 +1619,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1532
1619
|
const oauthTool = (0, core_1.createOAuth2Tool)(providerName, serviceSlug, {
|
|
1533
1620
|
logoUrl: providerConfig.logoUrl,
|
|
1534
1621
|
reason: providerConfig.reason,
|
|
1535
|
-
requiredTools: providerConfig.requiredTools
|
|
1622
|
+
requiredTools: providerConfig.requiredTools,
|
|
1536
1623
|
});
|
|
1537
1624
|
autoOAuth2Tools.push(oauthTool);
|
|
1538
1625
|
});
|
|
@@ -1562,11 +1649,17 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1562
1649
|
}
|
|
1563
1650
|
try {
|
|
1564
1651
|
await app.oauth2.handleCallback(code, state);
|
|
1565
|
-
return c.html("<html><body><script>window.opener.postMessage({ type: 'oauth2-success', provider: '" +
|
|
1652
|
+
return c.html("<html><body><script>window.opener.postMessage({ type: 'oauth2-success', provider: '" +
|
|
1653
|
+
provider +
|
|
1654
|
+
"' }, '*');window.close();</script><h1>Authentication successful! You can close this window.</h1></body></html>");
|
|
1566
1655
|
}
|
|
1567
1656
|
catch (error) {
|
|
1568
1657
|
console.error("OAuth callback error:", error);
|
|
1569
|
-
return c.html("<html><body><script>window.opener.postMessage({ type: 'oauth2-error', provider: '" +
|
|
1658
|
+
return c.html("<html><body><script>window.opener.postMessage({ type: 'oauth2-error', provider: '" +
|
|
1659
|
+
provider +
|
|
1660
|
+
"', error: '" +
|
|
1661
|
+
error.message +
|
|
1662
|
+
"' }, '*');window.close();</script><h1>Authentication failed! You can close this window.</h1></body></html>");
|
|
1570
1663
|
}
|
|
1571
1664
|
});
|
|
1572
1665
|
// Make oauth2Handler available to tools
|
|
@@ -1585,7 +1678,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1585
1678
|
}
|
|
1586
1679
|
catch (error) {
|
|
1587
1680
|
if (error.message === "Unauthorized access to process") {
|
|
1588
|
-
throw new http_exception_1.HTTPException(403, {
|
|
1681
|
+
throw new http_exception_1.HTTPException(403, {
|
|
1682
|
+
message: "Unauthorized access to process",
|
|
1683
|
+
});
|
|
1589
1684
|
}
|
|
1590
1685
|
throw error;
|
|
1591
1686
|
}
|
|
@@ -1601,7 +1696,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1601
1696
|
const providersWithStatus = await Promise.all(providers.map(async ({ name, config }) => ({
|
|
1602
1697
|
name,
|
|
1603
1698
|
config,
|
|
1604
|
-
connected: await app.oauth2.hasValidTokens(name, agentInfo.id)
|
|
1699
|
+
connected: await app.oauth2.hasValidTokens(name, agentInfo.id),
|
|
1605
1700
|
})));
|
|
1606
1701
|
return c.json(providersWithStatus);
|
|
1607
1702
|
});
|
|
@@ -1618,7 +1713,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1618
1713
|
app.get("/oauth2/connect/:provider", async (c) => {
|
|
1619
1714
|
debugLog("[OAuth2 Connect] Route hit - START");
|
|
1620
1715
|
debugLog("[OAuth2 Connect] Provider param:", c.req.param("provider"));
|
|
1621
|
-
debugLog("[OAuth2 Connect] Auth method:", c.get(
|
|
1716
|
+
debugLog("[OAuth2 Connect] Auth method:", c.get("authMethod"));
|
|
1622
1717
|
debugLog("[OAuth2 Connect] Headers:", {
|
|
1623
1718
|
authorization: c.req.header("Authorization"),
|
|
1624
1719
|
apiKey: c.req.header("X-DAIN-API-KEY"),
|
|
@@ -1649,7 +1744,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1649
1744
|
catch (error) {
|
|
1650
1745
|
debugLog("[OAuth2 Connect] ERROR generating auth URL:", error);
|
|
1651
1746
|
throw new http_exception_1.HTTPException(400, {
|
|
1652
|
-
message: `Invalid provider: ${provider}
|
|
1747
|
+
message: `Invalid provider: ${provider}`,
|
|
1653
1748
|
});
|
|
1654
1749
|
}
|
|
1655
1750
|
});
|
|
@@ -1667,8 +1762,8 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1667
1762
|
if (isComplete) {
|
|
1668
1763
|
const config = await setupManager.getProviderConfig(agentInfo.id, provider);
|
|
1669
1764
|
return c.json({
|
|
1670
|
-
status:
|
|
1671
|
-
config: config ? { configuredAt: config.configuredAt } : undefined
|
|
1765
|
+
status: "complete",
|
|
1766
|
+
config: config ? { configuredAt: config.configuredAt } : undefined,
|
|
1672
1767
|
});
|
|
1673
1768
|
}
|
|
1674
1769
|
// Check if there's a pending setup
|
|
@@ -1676,15 +1771,15 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1676
1771
|
if (pendingSetup) {
|
|
1677
1772
|
const expiresIn = Math.max(0, Math.floor((pendingSetup.expiresAt - Date.now()) / 1000));
|
|
1678
1773
|
return c.json({
|
|
1679
|
-
status:
|
|
1774
|
+
status: "authorization_pending",
|
|
1680
1775
|
expires_in: expiresIn,
|
|
1681
|
-
interval: 5 // Poll every 5 seconds
|
|
1776
|
+
interval: 5, // Poll every 5 seconds
|
|
1682
1777
|
});
|
|
1683
1778
|
}
|
|
1684
1779
|
// No setup in progress
|
|
1685
1780
|
return c.json({
|
|
1686
|
-
status:
|
|
1687
|
-
error:
|
|
1781
|
+
status: "not_found",
|
|
1782
|
+
error: "No setup in progress for this provider",
|
|
1688
1783
|
});
|
|
1689
1784
|
});
|
|
1690
1785
|
// Get all human actions for a process
|
|
@@ -1697,13 +1792,15 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1697
1792
|
}
|
|
1698
1793
|
if (process.agentId !== agentInfo.id) {
|
|
1699
1794
|
debugLog("Unauthorized access to process", process.agentId, agentInfo.id);
|
|
1700
|
-
throw new http_exception_1.HTTPException(403, {
|
|
1795
|
+
throw new http_exception_1.HTTPException(403, {
|
|
1796
|
+
message: "Unauthorized access to process",
|
|
1797
|
+
});
|
|
1701
1798
|
}
|
|
1702
1799
|
return c.json(process.humanActions);
|
|
1703
1800
|
});
|
|
1704
1801
|
// Get specific human action
|
|
1705
1802
|
app.get("/processes/:processId/human-actions/:stepId", async (c) => {
|
|
1706
|
-
debugLog(
|
|
1803
|
+
debugLog("GET human action request:", c.req.path);
|
|
1707
1804
|
const processId = c.req.param("processId");
|
|
1708
1805
|
const stepId = c.req.param("stepId");
|
|
1709
1806
|
const agentInfo = await getAgentInfo(c);
|
|
@@ -1713,7 +1810,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1713
1810
|
}
|
|
1714
1811
|
if (process.agentId !== agentInfo.id) {
|
|
1715
1812
|
debugLog("Unauthorized access to process", process.agentId, agentInfo.id);
|
|
1716
|
-
throw new http_exception_1.HTTPException(403, {
|
|
1813
|
+
throw new http_exception_1.HTTPException(403, {
|
|
1814
|
+
message: "Unauthorized access to process",
|
|
1815
|
+
});
|
|
1717
1816
|
}
|
|
1718
1817
|
const step = await app.processes.checkHumanAction(processId, stepId);
|
|
1719
1818
|
if (!step) {
|
|
@@ -1732,7 +1831,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1732
1831
|
}
|
|
1733
1832
|
if (process.agentId !== agentInfo.id) {
|
|
1734
1833
|
debugLog("Unauthorized access to process", process.agentId, agentInfo.id);
|
|
1735
|
-
throw new http_exception_1.HTTPException(403, {
|
|
1834
|
+
throw new http_exception_1.HTTPException(403, {
|
|
1835
|
+
message: "Unauthorized access to process",
|
|
1836
|
+
});
|
|
1736
1837
|
}
|
|
1737
1838
|
const body = await c.req.json();
|
|
1738
1839
|
const { actionId, responseText, data } = body;
|
|
@@ -1763,7 +1864,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1763
1864
|
}
|
|
1764
1865
|
catch (error) {
|
|
1765
1866
|
console.error(`Error generating confirmation UI for tool ${tool.id}:`, error);
|
|
1766
|
-
throw new http_exception_1.HTTPException(500, {
|
|
1867
|
+
throw new http_exception_1.HTTPException(500, {
|
|
1868
|
+
message: "Error generating confirmation UI",
|
|
1869
|
+
});
|
|
1767
1870
|
}
|
|
1768
1871
|
});
|
|
1769
1872
|
app.get("/exampleQueries", (c) => {
|
|
@@ -1799,7 +1902,10 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1799
1902
|
// Toolboxes list endpoint
|
|
1800
1903
|
app.get("/toolboxes", (c) => c.json(toolboxes));
|
|
1801
1904
|
function normalizeRecommendationText(value) {
|
|
1802
|
-
return value
|
|
1905
|
+
return value
|
|
1906
|
+
.toLowerCase()
|
|
1907
|
+
.replace(/[^a-z0-9]+/g, " ")
|
|
1908
|
+
.trim();
|
|
1803
1909
|
}
|
|
1804
1910
|
function tokenizeRecommendationQuery(query) {
|
|
1805
1911
|
const normalized = normalizeRecommendationText(query);
|
|
@@ -1818,7 +1924,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1818
1924
|
throw new Error(`Duplicate recommendation card ID "${scopedCardId}". Card IDs must be unique per tool.`);
|
|
1819
1925
|
}
|
|
1820
1926
|
const isDynamic = !!card.inputSchema;
|
|
1821
|
-
const inputSchema = isDynamic
|
|
1927
|
+
const inputSchema = isDynamic
|
|
1928
|
+
? (0, schemaStructure_1.zodToJsonSchema)(card.inputSchema)
|
|
1929
|
+
: undefined;
|
|
1822
1930
|
const searchText = normalizeRecommendationText([tool.id, tool.name, card.id, ...card.tags].join(" "));
|
|
1823
1931
|
index.set(scopedCardId, {
|
|
1824
1932
|
cardId: scopedCardId,
|
|
@@ -1880,7 +1988,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
1880
1988
|
details: parsed.error.format(),
|
|
1881
1989
|
}, 400);
|
|
1882
1990
|
}
|
|
1883
|
-
const { query, limit, toolIds, includeStaticUI
|
|
1991
|
+
const { query, limit, toolIds, includeStaticUI } = parsed.data;
|
|
1884
1992
|
const toolIdSet = toolIds?.length ? new Set(toolIds) : null;
|
|
1885
1993
|
const filteredCards = Array.from(recommendationCardsById.values()).filter((card) => !toolIdSet || toolIdSet.has(card.toolId));
|
|
1886
1994
|
const tokens = tokenizeRecommendationQuery(query ?? "");
|
|
@@ -2013,7 +2121,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2013
2121
|
renderErrors.push({
|
|
2014
2122
|
cardId: card.cardId,
|
|
2015
2123
|
code: "render_failed",
|
|
2016
|
-
message: error instanceof Error
|
|
2124
|
+
message: error instanceof Error
|
|
2125
|
+
? error.message
|
|
2126
|
+
: "Failed to render recommendation card",
|
|
2017
2127
|
});
|
|
2018
2128
|
if (!continueOnError)
|
|
2019
2129
|
break;
|
|
@@ -2048,21 +2158,22 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2048
2158
|
// Auto-inject smartAccountPDA into CryptoPlugin wallet context for automations
|
|
2049
2159
|
// This allows automation wallets to work seamlessly without manual configuration
|
|
2050
2160
|
if (agentInfo.smartAccountPDA) {
|
|
2051
|
-
processedRequest.plugins[
|
|
2052
|
-
|
|
2053
|
-
|
|
2161
|
+
processedRequest.plugins["crypto-plugin"] =
|
|
2162
|
+
processedRequest.plugins["crypto-plugin"] || {};
|
|
2163
|
+
const cryptoData = isRecord(processedRequest.plugins["crypto-plugin"])
|
|
2164
|
+
? stripRuntimeContextFields(processedRequest.plugins["crypto-plugin"])
|
|
2054
2165
|
: {};
|
|
2055
|
-
processedRequest.plugins[
|
|
2166
|
+
processedRequest.plugins["crypto-plugin"] = cryptoData;
|
|
2056
2167
|
const smartAccountWallet = {
|
|
2057
|
-
chain:
|
|
2168
|
+
chain: "sol",
|
|
2058
2169
|
address: agentInfo.smartAccountPDA,
|
|
2059
2170
|
accountId: agentInfo.dainAccountId ?? agentInfo.dainGroupId,
|
|
2060
|
-
kind:
|
|
2061
|
-
capabilities: [
|
|
2171
|
+
kind: "smart_account_vault",
|
|
2172
|
+
capabilities: ["solana-smart-account"],
|
|
2062
2173
|
};
|
|
2063
2174
|
if (Array.isArray(cryptoData.wallets)) {
|
|
2064
2175
|
const hasSmartAccountWallet = cryptoData.wallets.some((wallet) => isRecord(wallet) &&
|
|
2065
|
-
wallet.chain ===
|
|
2176
|
+
wallet.chain === "sol" &&
|
|
2066
2177
|
wallet.address === agentInfo.smartAccountPDA);
|
|
2067
2178
|
if (!hasSmartAccountWallet) {
|
|
2068
2179
|
cryptoData.wallets = [smartAccountWallet, ...cryptoData.wallets];
|
|
@@ -2081,9 +2192,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2081
2192
|
cryptoData.wallets = [smartAccountWallet];
|
|
2082
2193
|
}
|
|
2083
2194
|
}
|
|
2084
|
-
if (processedRequest.plugins[
|
|
2085
|
-
processedRequest.plugins[
|
|
2086
|
-
...stripRuntimeContextFields(processedRequest.plugins[
|
|
2195
|
+
if (processedRequest.plugins["crypto-plugin"]) {
|
|
2196
|
+
processedRequest.plugins["crypto-plugin"] = {
|
|
2197
|
+
...stripRuntimeContextFields(processedRequest.plugins["crypto-plugin"]),
|
|
2087
2198
|
...getRuntimeContextFromAgentInfo(agentInfo),
|
|
2088
2199
|
};
|
|
2089
2200
|
}
|
|
@@ -2115,7 +2226,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2115
2226
|
processedResponse.plugins = processedResponse.plugins || {};
|
|
2116
2227
|
const extraData = isRecord(context?.extraData)
|
|
2117
2228
|
? context.extraData
|
|
2118
|
-
:
|
|
2229
|
+
: isRecord(context)
|
|
2230
|
+
? context
|
|
2231
|
+
: {};
|
|
2119
2232
|
for (const plugin of config.plugins) {
|
|
2120
2233
|
if (plugin.processOutputService) {
|
|
2121
2234
|
// Provide context to the plugin
|
|
@@ -2123,8 +2236,8 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2123
2236
|
...processedResponse,
|
|
2124
2237
|
context: {
|
|
2125
2238
|
request,
|
|
2126
|
-
extraData
|
|
2127
|
-
}
|
|
2239
|
+
extraData,
|
|
2240
|
+
},
|
|
2128
2241
|
});
|
|
2129
2242
|
if (pluginOutput) {
|
|
2130
2243
|
processedResponse.plugins[plugin.id] = pluginOutput;
|
|
@@ -2172,22 +2285,25 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2172
2285
|
return signedStreamSSE(c, privateKey, config, async (stream) => {
|
|
2173
2286
|
try {
|
|
2174
2287
|
// Execute the tool first
|
|
2175
|
-
debugLog(`[SSE] Executing tool ${tool.id} in streaming mode${withContext ?
|
|
2288
|
+
debugLog(`[SSE] Executing tool ${tool.id} in streaming mode${withContext ? " with context" : ""}`);
|
|
2176
2289
|
const { DAIN_EXTRA_DATA: _dainExtraData, ...toolInput } = body;
|
|
2177
2290
|
const result = await tool.handler(toolInput, agentInfo, buildToolContext(agentInfo, body, pluginsData, {
|
|
2178
2291
|
updateUI: async (update) => {
|
|
2179
2292
|
try {
|
|
2180
2293
|
// Check if this is a progress update
|
|
2181
|
-
if (update.type ===
|
|
2294
|
+
if (update.type === "progress") {
|
|
2182
2295
|
await stream.writeSSE({
|
|
2183
|
-
event:
|
|
2184
|
-
data: JSON.stringify({
|
|
2296
|
+
event: "progress",
|
|
2297
|
+
data: JSON.stringify({
|
|
2298
|
+
text: update.text,
|
|
2299
|
+
data: update.data,
|
|
2300
|
+
}),
|
|
2185
2301
|
});
|
|
2186
2302
|
}
|
|
2187
2303
|
else {
|
|
2188
2304
|
// Legacy UI page updates for Canvas rendering
|
|
2189
2305
|
await stream.writeSSE({
|
|
2190
|
-
event:
|
|
2306
|
+
event: "uipage-update",
|
|
2191
2307
|
data: JSON.stringify(update),
|
|
2192
2308
|
});
|
|
2193
2309
|
}
|
|
@@ -2199,7 +2315,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2199
2315
|
addProcess: async (processId) => {
|
|
2200
2316
|
try {
|
|
2201
2317
|
await stream.writeSSE({
|
|
2202
|
-
event:
|
|
2318
|
+
event: "process-created",
|
|
2203
2319
|
data: JSON.stringify({ processId }),
|
|
2204
2320
|
id: Date.now().toString(),
|
|
2205
2321
|
});
|
|
@@ -2207,7 +2323,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2207
2323
|
catch (error) {
|
|
2208
2324
|
console.error(`Error sending process update in ${tool.id}:`, error);
|
|
2209
2325
|
}
|
|
2210
|
-
}
|
|
2326
|
+
},
|
|
2211
2327
|
}));
|
|
2212
2328
|
// If we need to include context data
|
|
2213
2329
|
let response = result;
|
|
@@ -2226,7 +2342,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2226
2342
|
...buildServiceExtraData(agentInfo, {
|
|
2227
2343
|
request: body,
|
|
2228
2344
|
plugins: pluginsData,
|
|
2229
|
-
oauth2Client: app.oauth2
|
|
2345
|
+
oauth2Client: app.oauth2
|
|
2346
|
+
? app.oauth2.getClient()
|
|
2347
|
+
: undefined,
|
|
2230
2348
|
}),
|
|
2231
2349
|
}),
|
|
2232
2350
|
};
|
|
@@ -2245,11 +2363,11 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2245
2363
|
// Use Promise.allSettled to continue even if some contexts fail
|
|
2246
2364
|
const settledContexts = await Promise.allSettled(contextPromises);
|
|
2247
2365
|
contextsNow = settledContexts
|
|
2248
|
-
.filter(result => result.status ===
|
|
2249
|
-
.map(result => result.value);
|
|
2250
|
-
// Log any rejected promises
|
|
2366
|
+
.filter((result) => result.status === "fulfilled")
|
|
2367
|
+
.map((result) => result.value);
|
|
2368
|
+
// Log any rejected promises
|
|
2251
2369
|
settledContexts
|
|
2252
|
-
.filter(result => result.status ===
|
|
2370
|
+
.filter((result) => result.status === "rejected")
|
|
2253
2371
|
.forEach((result, index) => {
|
|
2254
2372
|
console.error(`Context at index ${index} failed:`, result.reason);
|
|
2255
2373
|
});
|
|
@@ -2270,12 +2388,12 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2270
2388
|
const processedResult = await processPluginsForResponse(response, body, {
|
|
2271
2389
|
extraData: {
|
|
2272
2390
|
...body.DAIN_EXTRA_DATA,
|
|
2273
|
-
plugins: pluginsData
|
|
2274
|
-
}
|
|
2391
|
+
plugins: pluginsData,
|
|
2392
|
+
},
|
|
2275
2393
|
});
|
|
2276
2394
|
// Send the final result
|
|
2277
2395
|
await stream.writeSSE({
|
|
2278
|
-
event:
|
|
2396
|
+
event: "result",
|
|
2279
2397
|
data: JSON.stringify(processedResult),
|
|
2280
2398
|
id: Date.now().toString(),
|
|
2281
2399
|
});
|
|
@@ -2287,13 +2405,13 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2287
2405
|
try {
|
|
2288
2406
|
if (withContext) {
|
|
2289
2407
|
await stream.writeSSE({
|
|
2290
|
-
event:
|
|
2408
|
+
event: "result",
|
|
2291
2409
|
data: JSON.stringify({
|
|
2292
2410
|
toolResult: {
|
|
2293
2411
|
error: safeMsg,
|
|
2294
2412
|
text: `Error: ${safeMsg}`,
|
|
2295
2413
|
data: null,
|
|
2296
|
-
ui: null
|
|
2414
|
+
ui: null,
|
|
2297
2415
|
},
|
|
2298
2416
|
context: [],
|
|
2299
2417
|
}),
|
|
@@ -2302,12 +2420,12 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2302
2420
|
}
|
|
2303
2421
|
else {
|
|
2304
2422
|
await stream.writeSSE({
|
|
2305
|
-
event:
|
|
2423
|
+
event: "result",
|
|
2306
2424
|
data: JSON.stringify({
|
|
2307
2425
|
error: safeMsg,
|
|
2308
2426
|
text: `Error: ${safeMsg}`,
|
|
2309
2427
|
data: null,
|
|
2310
|
-
ui: null
|
|
2428
|
+
ui: null,
|
|
2311
2429
|
}),
|
|
2312
2430
|
id: Date.now().toString(),
|
|
2313
2431
|
});
|
|
@@ -2331,8 +2449,11 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2331
2449
|
const result = await tool.handler(toolInput, agentInfo, buildToolContext(agentInfo, body, pluginsData, {
|
|
2332
2450
|
updateUI: (update) => {
|
|
2333
2451
|
// Collect UI updates instead of streaming them (synchronous for performance)
|
|
2334
|
-
if (update.type ===
|
|
2335
|
-
progressUpdates.push({
|
|
2452
|
+
if (update.type === "progress") {
|
|
2453
|
+
progressUpdates.push({
|
|
2454
|
+
text: update.text,
|
|
2455
|
+
data: update.data,
|
|
2456
|
+
});
|
|
2336
2457
|
}
|
|
2337
2458
|
else {
|
|
2338
2459
|
uiUpdates.push(update);
|
|
@@ -2343,7 +2464,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2343
2464
|
// Collect process IDs (synchronous for performance)
|
|
2344
2465
|
processes.push(processId);
|
|
2345
2466
|
return Promise.resolve();
|
|
2346
|
-
}
|
|
2467
|
+
},
|
|
2347
2468
|
}));
|
|
2348
2469
|
// If we need to include context data
|
|
2349
2470
|
let response = result;
|
|
@@ -2358,7 +2479,9 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2358
2479
|
...buildServiceExtraData(agentInfo, {
|
|
2359
2480
|
request: body,
|
|
2360
2481
|
plugins: pluginsData,
|
|
2361
|
-
oauth2Client: app.oauth2
|
|
2482
|
+
oauth2Client: app.oauth2
|
|
2483
|
+
? app.oauth2.getClient()
|
|
2484
|
+
: undefined,
|
|
2362
2485
|
}),
|
|
2363
2486
|
}),
|
|
2364
2487
|
})));
|
|
@@ -2381,15 +2504,15 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2381
2504
|
const processedResult = await processPluginsForResponse(response, body, {
|
|
2382
2505
|
extraData: {
|
|
2383
2506
|
...body.DAIN_EXTRA_DATA,
|
|
2384
|
-
plugins: pluginsData
|
|
2385
|
-
}
|
|
2507
|
+
plugins: pluginsData,
|
|
2508
|
+
},
|
|
2386
2509
|
});
|
|
2387
2510
|
// Add collected updates to response for non-streaming clients
|
|
2388
2511
|
const finalResponse = {
|
|
2389
2512
|
...processedResult,
|
|
2390
2513
|
_updates: uiUpdates.length > 0 ? uiUpdates : undefined,
|
|
2391
2514
|
_progress: progressUpdates.length > 0 ? progressUpdates : undefined,
|
|
2392
|
-
_processes: processes.length > 0 ? processes : undefined
|
|
2515
|
+
_processes: processes.length > 0 ? processes : undefined,
|
|
2393
2516
|
};
|
|
2394
2517
|
return c.json(finalResponse);
|
|
2395
2518
|
}
|
|
@@ -2404,7 +2527,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2404
2527
|
error: safeMsg,
|
|
2405
2528
|
text: `Error: ${safeMsg}`,
|
|
2406
2529
|
data: null,
|
|
2407
|
-
ui: null
|
|
2530
|
+
ui: null,
|
|
2408
2531
|
},
|
|
2409
2532
|
context: [],
|
|
2410
2533
|
};
|
|
@@ -2414,7 +2537,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2414
2537
|
error: safeMsg,
|
|
2415
2538
|
text: `Error: ${safeMsg}`,
|
|
2416
2539
|
data: null,
|
|
2417
|
-
ui: null
|
|
2540
|
+
ui: null,
|
|
2418
2541
|
};
|
|
2419
2542
|
}
|
|
2420
2543
|
// We return status 200 with error details in the body
|
|
@@ -2428,7 +2551,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2428
2551
|
debugLog(`[Tool ${tool.id}] ========== TOOL EXECUTION START ==========`);
|
|
2429
2552
|
debugLog(`[Tool ${tool.id}] Path: ${c.req.path}`);
|
|
2430
2553
|
debugLog(`[Tool ${tool.id}] Method: ${c.req.method}`);
|
|
2431
|
-
debugLog(`[Tool ${tool.id}] Auth Method: ${c.get(
|
|
2554
|
+
debugLog(`[Tool ${tool.id}] Auth Method: ${c.get("authMethod")}`);
|
|
2432
2555
|
debugLog(`[Tool ${tool.id}] Headers:`, {
|
|
2433
2556
|
authorization: c.req.header("Authorization") ? "Bearer ***" : undefined,
|
|
2434
2557
|
apiKey: c.req.header("X-DAIN-API-KEY") ? "***" : undefined,
|
|
@@ -2465,7 +2588,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2465
2588
|
debugLog(`[Tool ${tool.id} +Context] ========== TOOL EXECUTION START (WITH CONTEXT) ==========`);
|
|
2466
2589
|
debugLog(`[Tool ${tool.id} +Context] Path: ${c.req.path}`);
|
|
2467
2590
|
debugLog(`[Tool ${tool.id} +Context] Method: ${c.req.method}`);
|
|
2468
|
-
debugLog(`[Tool ${tool.id} +Context] Auth Method: ${c.get(
|
|
2591
|
+
debugLog(`[Tool ${tool.id} +Context] Auth Method: ${c.get("authMethod")}`);
|
|
2469
2592
|
debugLog(`[Tool ${tool.id} +Context] Headers:`, {
|
|
2470
2593
|
authorization: c.req.header("Authorization") ? "Bearer ***" : undefined,
|
|
2471
2594
|
apiKey: c.req.header("X-DAIN-API-KEY") ? "***" : undefined,
|
|
@@ -2498,7 +2621,7 @@ function setupHttpServer(config, tools, services, toolboxes, metadata, privateKe
|
|
|
2498
2621
|
console.error(`[Tool ${tool.id} +Context] Stack:`, error?.stack);
|
|
2499
2622
|
throw new http_exception_1.HTTPException(500, {
|
|
2500
2623
|
message: error?.message || "Internal server error",
|
|
2501
|
-
cause: error
|
|
2624
|
+
cause: error,
|
|
2502
2625
|
});
|
|
2503
2626
|
}
|
|
2504
2627
|
});
|