@agent-native/core 0.84.18 → 0.84.21
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +21 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/caller-auth.ts +37 -8
- package/corpus/core/src/a2a/client.ts +178 -67
- package/corpus/core/src/agent/production-agent.ts +19 -3
- package/corpus/core/src/agent/run-store.ts +180 -13
- package/corpus/core/src/agent/types.ts +1 -1
- package/corpus/core/src/cli/pr-visual-recap-workflow.ts +1 -1
- package/corpus/core/src/cli/recap.ts +43 -34
- package/corpus/core/src/client/AssistantChat.tsx +49 -0
- package/corpus/core/src/client/PoweredByBadge.tsx +70 -17
- package/corpus/core/src/client/active-run-state.ts +30 -0
- package/corpus/core/src/client/agent-chat-adapter.ts +5 -1
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +41 -3
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +133 -0
- package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +2 -2
- package/corpus/core/src/client/i18n.tsx +10 -5
- package/corpus/core/src/client/sse-event-processor.ts +147 -5
- package/corpus/core/src/extensions/html-shell.ts +17 -3
- package/corpus/core/src/extensions/theme.ts +39 -0
- package/corpus/core/src/file-upload/builder.ts +35 -14
- package/corpus/core/src/file-upload/types.ts +3 -0
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +49 -24
- package/corpus/core/src/mcp/builtin-tools.ts +3 -0
- package/corpus/core/src/mcp/org-directory.ts +66 -20
- package/corpus/core/src/scripts/call-agent.ts +7 -2
- package/corpus/templates/analytics/actions/provider-api-request.ts +8 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +2 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +91 -33
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +161 -12
- package/corpus/templates/analytics/changelog/2026-07-01-session-replays-load-large-production-recordings-from-scoped.md +6 -0
- package/corpus/templates/calendar/app/pages/BookingPage.tsx +14 -8
- package/corpus/templates/calendar/changelog/2026-07-01-meeting-invite-pages-have-cleaner-branding-a-black-dark-mo.md +6 -0
- package/corpus/templates/clips/actions/create-recording.ts +7 -2
- package/corpus/templates/clips/actions/finalize-recording.ts +11 -0
- package/corpus/templates/clips/actions/get-recording-player-data.ts +4 -2
- package/corpus/templates/clips/actions/import-loom-recording.ts +1 -0
- package/corpus/templates/clips/actions/lib/loom-video.ts +16 -0
- package/corpus/templates/clips/app/components/player/scrubber.tsx +2 -2
- package/corpus/templates/clips/app/components/recorder/countdown-overlay.tsx +4 -3
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +39 -12
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +65 -1
- package/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +1 -22
- package/corpus/templates/clips/app/routes/record.tsx +48 -8
- package/corpus/templates/clips/changelog/2026-07-01-chrome-recording-uploads-now-serialize-chunks-to-avoid-resum.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-clip-uploads-and-loom-imports-finish-sooner-by-skipping-the-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-clip-uploads-and-playback-recover-more-reliably-from-storage.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-desktop-recording-avoids-unsupported-browser-tab-capture.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-embedded-player-progress-is-easier-to-see-on-dark-videos.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-loom-imports-show-clear-guidance-when-loom-does-not-provide-a-downloadable-video.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-preserve-in-flight-streaming-uploads-when-the-streaming-kill.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-recording-controls-are-cleaner-and-the-countdown-uses-shadow.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-recordings-now-recover-when-final-upload-status-gets-lost.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +7 -224
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +94 -29
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +87 -5
- package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +7 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +14 -1
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +4 -1
- package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +96 -1
- package/corpus/templates/clips/shared/finalize-recovery.ts +242 -0
- package/corpus/templates/design/changelog/2026-07-01-design-recovers-sooner-when-an-agent-gets-stuck-preparing-a-.md +6 -0
- package/corpus/templates/plan/app/global.css +1 -1
- package/dist/a2a/caller-auth.d.ts +1 -0
- package/dist/a2a/caller-auth.d.ts.map +1 -1
- package/dist/a2a/caller-auth.js +34 -8
- package/dist/a2a/caller-auth.js.map +1 -1
- package/dist/a2a/client.d.ts +4 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +148 -58
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +19 -4
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-store.d.ts +19 -6
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +163 -13
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/types.d.ts +1 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +1 -1
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts +3 -3
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +41 -34
- package/dist/cli/recap.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +36 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/PoweredByBadge.d.ts +9 -3
- package/dist/client/PoweredByBadge.d.ts.map +1 -1
- package/dist/client/PoweredByBadge.js +47 -15
- package/dist/client/PoweredByBadge.js.map +1 -1
- package/dist/client/active-run-state.d.ts +3 -0
- package/dist/client/active-run-state.d.ts.map +1 -1
- package/dist/client/active-run-state.js +24 -0
- package/dist/client/active-run-state.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +5 -1
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +32 -3
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +59 -2
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +2 -2
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/i18n.d.ts +1 -1
- package/dist/client/i18n.d.ts.map +1 -1
- package/dist/client/i18n.js +6 -2
- package/dist/client/i18n.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +2 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +121 -5
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js +17 -3
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/theme.d.ts +9 -0
- package/dist/extensions/theme.d.ts.map +1 -1
- package/dist/extensions/theme.js +38 -0
- package/dist/extensions/theme.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/file-upload/builder.d.ts.map +1 -1
- package/dist/file-upload/builder.js +22 -8
- package/dist/file-upload/builder.js.map +1 -1
- package/dist/file-upload/types.d.ts +5 -1
- package/dist/file-upload/types.d.ts.map +1 -1
- package/dist/file-upload/types.js.map +1 -1
- package/dist/integrations/a2a-continuation-processor.js +43 -18
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +3 -0
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/mcp/org-directory.d.ts.map +1 -1
- package/dist/mcp/org-directory.js +58 -20
- package/dist/mcp/org-directory.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +2 -2
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
|
@@ -150,11 +150,11 @@ async function processClaimedContinuation(
|
|
|
150
150
|
return;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
{
|
|
157
|
-
);
|
|
153
|
+
const auth = await signContinuationToken(continuation);
|
|
154
|
+
const client = new A2AClient(continuation.agentUrl, auth.apiKey, {
|
|
155
|
+
requestTimeoutMs: POLL_REQUEST_TIMEOUT_MS,
|
|
156
|
+
...(auth.apiKeyFallbacks ? { fallbackApiKeys: auth.apiKeyFallbacks } : {}),
|
|
157
|
+
});
|
|
158
158
|
const deadline = Date.now() + PROCESSOR_WAIT_MS;
|
|
159
159
|
let task: Task | null = null;
|
|
160
160
|
|
|
@@ -438,28 +438,35 @@ function sanitizeFailureReason(reason: string): string {
|
|
|
438
438
|
|
|
439
439
|
async function signContinuationToken(
|
|
440
440
|
continuation: A2AContinuation,
|
|
441
|
-
): Promise<string
|
|
441
|
+
): Promise<{ apiKey?: string; apiKeyFallbacks?: string[] }> {
|
|
442
442
|
if (continuation.a2aAuthToken === "") {
|
|
443
|
-
return
|
|
443
|
+
return {};
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
const storedToken = continuation.a2aAuthToken;
|
|
447
|
-
if (storedToken && !isLikelyJwt(storedToken)) return storedToken;
|
|
448
|
-
|
|
449
|
-
const
|
|
450
|
-
if (
|
|
451
|
-
|
|
447
|
+
if (storedToken && !isLikelyJwt(storedToken)) return { apiKey: storedToken };
|
|
448
|
+
|
|
449
|
+
const freshTokens = await signFreshContinuationTokens(continuation);
|
|
450
|
+
if (freshTokens.length > 0) {
|
|
451
|
+
return {
|
|
452
|
+
apiKey: freshTokens[0],
|
|
453
|
+
...(freshTokens.length > 1
|
|
454
|
+
? { apiKeyFallbacks: freshTokens.slice(1) }
|
|
455
|
+
: {}),
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
if (!storedToken) return {};
|
|
452
459
|
|
|
453
460
|
// Older continuations may have persisted the initial short-lived JWT. Avoid
|
|
454
461
|
// replaying it forever after expiry; opaque legacy bearer keys can still be
|
|
455
462
|
// reused because we cannot re-mint those.
|
|
456
|
-
if (isLikelyJwt(storedToken)) return
|
|
457
|
-
return storedToken;
|
|
463
|
+
if (isLikelyJwt(storedToken)) return {};
|
|
464
|
+
return { apiKey: storedToken };
|
|
458
465
|
}
|
|
459
466
|
|
|
460
|
-
async function
|
|
467
|
+
async function signFreshContinuationTokens(
|
|
461
468
|
continuation: A2AContinuation,
|
|
462
|
-
): Promise<string
|
|
469
|
+
): Promise<string[]> {
|
|
463
470
|
let orgDomain: string | undefined;
|
|
464
471
|
let orgSecret: string | undefined;
|
|
465
472
|
if (continuation.orgId) {
|
|
@@ -472,17 +479,35 @@ async function signFreshContinuationToken(
|
|
|
472
479
|
}
|
|
473
480
|
|
|
474
481
|
if (!continuation.ownerEmail || !(orgSecret || process.env.A2A_SECRET)) {
|
|
475
|
-
return
|
|
482
|
+
return [];
|
|
476
483
|
}
|
|
477
484
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
+
const tokens: string[] = [];
|
|
486
|
+
const add = (token: string | undefined) => {
|
|
487
|
+
if (token && !tokens.includes(token)) tokens.push(token);
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
if (process.env.A2A_SECRET?.trim()) {
|
|
491
|
+
try {
|
|
492
|
+
add(
|
|
493
|
+
await signA2AToken(continuation.ownerEmail, orgDomain, orgSecret, {
|
|
494
|
+
expiresIn: "30m",
|
|
495
|
+
preferGlobalSecret: true,
|
|
496
|
+
}),
|
|
497
|
+
);
|
|
498
|
+
} catch {}
|
|
499
|
+
}
|
|
500
|
+
if (orgSecret) {
|
|
501
|
+
try {
|
|
502
|
+
add(
|
|
503
|
+
await signA2AToken(continuation.ownerEmail, orgDomain, orgSecret, {
|
|
504
|
+
expiresIn: "30m",
|
|
505
|
+
preferGlobalSecret: false,
|
|
506
|
+
}),
|
|
507
|
+
);
|
|
508
|
+
} catch {}
|
|
485
509
|
}
|
|
510
|
+
return tokens;
|
|
486
511
|
}
|
|
487
512
|
|
|
488
513
|
function isLikelyJwt(token: string): boolean {
|
|
@@ -260,6 +260,9 @@ async function createA2AClientForAskApp(origin: string): Promise<{
|
|
|
260
260
|
return {
|
|
261
261
|
client: new A2AClient(origin, auth.apiKey, {
|
|
262
262
|
requestTimeoutMs: ASK_APP_A2A_REQUEST_TIMEOUT_MS,
|
|
263
|
+
...(auth.apiKeyFallbacks
|
|
264
|
+
? { fallbackApiKeys: auth.apiKeyFallbacks }
|
|
265
|
+
: {}),
|
|
263
266
|
}),
|
|
264
267
|
metadata,
|
|
265
268
|
};
|
|
@@ -146,6 +146,15 @@ function scopedCacheKey(
|
|
|
146
146
|
].join("|");
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
function authTokenAttempts(auth: {
|
|
150
|
+
apiKey?: string;
|
|
151
|
+
apiKeyFallbacks?: string[];
|
|
152
|
+
}): string[] {
|
|
153
|
+
return [auth.apiKey, ...(auth.apiKeyFallbacks ?? [])].filter(
|
|
154
|
+
(token): token is string => typeof token === "string" && token.length > 0,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
149
158
|
function serviceScopedCacheKey(origin: string, orgId: string): string {
|
|
150
159
|
return [origin, `service-org:${orgId}`].join("|");
|
|
151
160
|
}
|
|
@@ -200,7 +209,8 @@ export async function fetchOrgApps(opts?: {
|
|
|
200
209
|
const auth = serviceOrgId
|
|
201
210
|
? await resolveOrgDirectoryServiceAuth(serviceOrgId)
|
|
202
211
|
: await resolveOrgDirectoryCallerAuth();
|
|
203
|
-
|
|
212
|
+
const attempts = authTokenAttempts(auth);
|
|
213
|
+
if (attempts.length === 0) {
|
|
204
214
|
// No signed token available (no A2A secret / no caller identity) — the
|
|
205
215
|
// directory requires the org bearer, so degrade silently to local-only.
|
|
206
216
|
return [];
|
|
@@ -215,19 +225,23 @@ export async function fetchOrgApps(opts?: {
|
|
|
215
225
|
}
|
|
216
226
|
}
|
|
217
227
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
for (let i = 0; i < attempts.length; i++) {
|
|
229
|
+
const res = await fetch(`${origin}/_agent-native/org/apps`, {
|
|
230
|
+
method: "GET",
|
|
231
|
+
headers: {
|
|
232
|
+
Authorization: `Bearer ${attempts[i]}`,
|
|
233
|
+
Accept: "application/json",
|
|
234
|
+
},
|
|
235
|
+
signal: AbortSignal.timeout(4000),
|
|
236
|
+
});
|
|
237
|
+
if (res.ok) {
|
|
238
|
+
const json = (await res.json()) as { apps?: unknown };
|
|
239
|
+
const list = Array.isArray(json?.apps) ? json.apps : [];
|
|
240
|
+
apps = list.map(normalizeApp).filter((a): a is OrgApp => a !== null);
|
|
241
|
+
ttl = SUCCESS_TTL_MS;
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
if (res.status !== 401 || i >= attempts.length - 1) break;
|
|
231
245
|
}
|
|
232
246
|
// Non-2xx ⇒ leave apps=[] with the short EMPTY_TTL (silent degrade).
|
|
233
247
|
} catch {
|
|
@@ -252,6 +266,7 @@ export function _resetOrgDirectoryCache(): void {
|
|
|
252
266
|
|
|
253
267
|
async function resolveOrgDirectoryCallerAuth(): Promise<{
|
|
254
268
|
apiKey?: string;
|
|
269
|
+
apiKeyFallbacks?: string[];
|
|
255
270
|
userEmail?: string;
|
|
256
271
|
orgId?: string;
|
|
257
272
|
orgDomain?: string;
|
|
@@ -266,6 +281,7 @@ async function resolveOrgDirectoryCallerAuth(): Promise<{
|
|
|
266
281
|
|
|
267
282
|
async function resolveOrgDirectoryServiceAuth(orgId: string): Promise<{
|
|
268
283
|
apiKey?: string;
|
|
284
|
+
apiKeyFallbacks?: string[];
|
|
269
285
|
userEmail?: string;
|
|
270
286
|
orgId?: string;
|
|
271
287
|
orgDomain?: string;
|
|
@@ -285,12 +301,42 @@ async function resolveOrgDirectoryServiceAuth(orgId: string): Promise<{
|
|
|
285
301
|
import("./connect-store.js"),
|
|
286
302
|
]);
|
|
287
303
|
const userEmail = serviceIdentityEmail("mcp-client", trimmedOrgId);
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
|
|
304
|
+
const apiKeyAttempts: string[] = [];
|
|
305
|
+
const addApiKeyAttempt = (token: string | undefined) => {
|
|
306
|
+
if (!token || apiKeyAttempts.includes(token)) return;
|
|
307
|
+
apiKeyAttempts.push(token);
|
|
308
|
+
};
|
|
309
|
+
if (process.env.A2A_SECRET?.trim()) {
|
|
310
|
+
try {
|
|
311
|
+
addApiKeyAttempt(
|
|
312
|
+
await signA2AToken(userEmail, orgDomain, orgSecret, {
|
|
313
|
+
expiresIn: "5m",
|
|
314
|
+
preferGlobalSecret: true,
|
|
315
|
+
extraClaims: { org_id: trimmedOrgId },
|
|
316
|
+
}),
|
|
317
|
+
);
|
|
318
|
+
} catch {}
|
|
319
|
+
}
|
|
320
|
+
if (orgSecret) {
|
|
321
|
+
try {
|
|
322
|
+
addApiKeyAttempt(
|
|
323
|
+
await signA2AToken(userEmail, orgDomain, orgSecret, {
|
|
324
|
+
expiresIn: "5m",
|
|
325
|
+
preferGlobalSecret: false,
|
|
326
|
+
extraClaims: { org_id: trimmedOrgId },
|
|
327
|
+
}),
|
|
328
|
+
);
|
|
329
|
+
} catch {}
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
apiKey: apiKeyAttempts[0],
|
|
333
|
+
...(apiKeyAttempts.length > 1
|
|
334
|
+
? { apiKeyFallbacks: apiKeyAttempts.slice(1) }
|
|
335
|
+
: {}),
|
|
336
|
+
userEmail,
|
|
337
|
+
orgId: trimmedOrgId,
|
|
338
|
+
orgDomain,
|
|
339
|
+
};
|
|
294
340
|
} catch {
|
|
295
341
|
return { orgId: trimmedOrgId, orgDomain };
|
|
296
342
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
A2ATaskTimeoutError,
|
|
5
|
+
callAgent,
|
|
6
|
+
shouldPreferGlobalA2ASecret,
|
|
7
|
+
signA2AToken,
|
|
8
|
+
} from "../a2a/client.js";
|
|
4
9
|
import {
|
|
5
10
|
formatLlmCredentialErrorMessage,
|
|
6
11
|
isLlmCredentialError,
|
|
@@ -162,7 +167,7 @@ export async function run(
|
|
|
162
167
|
callerOrgSecret,
|
|
163
168
|
{
|
|
164
169
|
expiresIn: INTEGRATION_A2A_TOKEN_TTL,
|
|
165
|
-
preferGlobalSecret:
|
|
170
|
+
preferGlobalSecret: shouldPreferGlobalA2ASecret(callerOrgSecret),
|
|
166
171
|
},
|
|
167
172
|
);
|
|
168
173
|
} catch {}
|
|
@@ -213,7 +213,14 @@ export default defineAction({
|
|
|
213
213
|
"Enable cursor-based pagination. After each response, reads cursorPath from the JSON body and re-issues the request with cursorParam or cursorBodyPath set, accumulating items from itemsPath (or whole bodies) until cursor is empty or maxPages is reached. Combine with saveToFile to write the full dataset to a workspace file; use scratch/... for temporary staging.",
|
|
214
214
|
),
|
|
215
215
|
}),
|
|
216
|
-
|
|
216
|
+
// Mounted over HTTP (POST) so the agent and frontend (`useActionMutation`)
|
|
217
|
+
// can reach it, consistent with provider-api-catalog / provider-api-docs.
|
|
218
|
+
// toolCallable: false blocks the extension iframe bridge — this action
|
|
219
|
+
// accepts arbitrary methods (PUT/DELETE/etc.) against provider APIs, so
|
|
220
|
+
// allowing shared extensions to call it would let malicious extension authors
|
|
221
|
+
// mutate provider data under the opener's credentials.
|
|
222
|
+
http: { method: "POST" },
|
|
223
|
+
toolCallable: false,
|
|
217
224
|
run: async (args) => {
|
|
218
225
|
if (args.stageAs) {
|
|
219
226
|
const ctx = requireRequestCredentialContext("provider-api staging");
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
IconStar,
|
|
8
8
|
IconPencil,
|
|
9
9
|
IconSettings,
|
|
10
|
+
IconFilter,
|
|
10
11
|
IconGripVertical,
|
|
11
12
|
IconBook2,
|
|
12
13
|
IconDatabase,
|
|
@@ -251,7 +252,7 @@ function SidebarSectionSettingsPopover({
|
|
|
251
252
|
className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground/65 opacity-0 transition-all hover:bg-sidebar-accent hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring group-hover/section:opacity-100 data-[state=open]:opacity-100"
|
|
252
253
|
aria-label={settingsLabel}
|
|
253
254
|
>
|
|
254
|
-
<
|
|
255
|
+
<IconFilter className="h-3.5 w-3.5" />
|
|
255
256
|
</button>
|
|
256
257
|
</PopoverTrigger>
|
|
257
258
|
</TooltipTrigger>
|
|
@@ -3,6 +3,7 @@ import { useDraggable } from "@dnd-kit/core";
|
|
|
3
3
|
import {
|
|
4
4
|
IconGripVertical,
|
|
5
5
|
IconDotsVertical,
|
|
6
|
+
IconExternalLink,
|
|
6
7
|
IconMaximize,
|
|
7
8
|
IconPencil,
|
|
8
9
|
IconRefresh,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
} from "@tabler/icons-react";
|
|
13
14
|
import { useIsFetching, useQueryClient } from "@tanstack/react-query";
|
|
14
15
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
16
|
+
import { useNavigate } from "react-router";
|
|
15
17
|
|
|
16
18
|
import { ChartFillHeight, SqlChart } from "@/components/dashboard/SqlChart";
|
|
17
19
|
import {
|
|
@@ -119,6 +121,8 @@ export function SqlChartCard({
|
|
|
119
121
|
|
|
120
122
|
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
121
123
|
const [expanded, setExpanded] = useState(false);
|
|
124
|
+
const [extRefreshKey, setExtRefreshKey] = useState(0);
|
|
125
|
+
const navigate = useNavigate();
|
|
122
126
|
const [exportCsv, setExportCsv] = useState<(() => void) | null>(null);
|
|
123
127
|
const [shouldLoadData, setShouldLoadData] = useState(
|
|
124
128
|
eagerLoad ||
|
|
@@ -291,10 +295,12 @@ export function SqlChartCard({
|
|
|
291
295
|
}
|
|
292
296
|
|
|
293
297
|
// Extension panels render their sandboxed iframe full-bleed with no card chrome
|
|
294
|
-
// or title — the extension owns its own UI.
|
|
295
|
-
//
|
|
296
|
-
//
|
|
298
|
+
// or title — the extension owns its own UI. All viewers get the read-only
|
|
299
|
+
// actions (full screen, refresh, open extension); editable dashboards also get
|
|
300
|
+
// delete and drag.
|
|
297
301
|
if (panel.chartType === "extension") {
|
|
302
|
+
const extensionId = (panel.config as Record<string, unknown> | undefined)
|
|
303
|
+
?.extensionId as string | undefined;
|
|
298
304
|
return (
|
|
299
305
|
<div
|
|
300
306
|
ref={setCardNodeRef}
|
|
@@ -302,45 +308,97 @@ export function SqlChartCard({
|
|
|
302
308
|
data-dragging={isDragSource ? "true" : undefined}
|
|
303
309
|
className="dashboard-extension-card group relative h-full"
|
|
304
310
|
>
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
311
|
+
{!expanded && (
|
|
312
|
+
<SqlChart
|
|
313
|
+
key={extRefreshKey}
|
|
314
|
+
panel={panel}
|
|
315
|
+
resolvedSql={resolvedSql}
|
|
316
|
+
loadData
|
|
317
|
+
/>
|
|
318
|
+
)}
|
|
319
|
+
<div className="absolute right-1 top-1 flex items-center gap-1 opacity-0 group-hover:opacity-100">
|
|
320
|
+
<DropdownMenu>
|
|
321
|
+
<Tooltip>
|
|
322
|
+
<TooltipTrigger asChild>
|
|
323
|
+
<DropdownMenuTrigger asChild>
|
|
324
|
+
<button
|
|
325
|
+
className="p-1 rounded bg-background/80 text-muted-foreground hover:text-foreground"
|
|
326
|
+
aria-label={t("sqlDashboard.panelOptions")}
|
|
327
|
+
>
|
|
328
|
+
<IconDotsVertical className="h-3.5 w-3.5" />
|
|
329
|
+
</button>
|
|
330
|
+
</DropdownMenuTrigger>
|
|
331
|
+
</TooltipTrigger>
|
|
332
|
+
<TooltipContent>{t("sqlDashboard.panelOptions")}</TooltipContent>
|
|
333
|
+
</Tooltip>
|
|
334
|
+
<DropdownMenuContent align="end" className="w-44">
|
|
335
|
+
<DropdownMenuItem onSelect={() => setExpanded(true)}>
|
|
336
|
+
<IconMaximize className="h-4 w-4 mr-2" />
|
|
337
|
+
{t("sqlDashboard.fullScreen")}
|
|
338
|
+
</DropdownMenuItem>
|
|
339
|
+
{extensionId ? (
|
|
325
340
|
<DropdownMenuItem
|
|
326
|
-
onSelect={(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
341
|
+
onSelect={() =>
|
|
342
|
+
navigate(
|
|
343
|
+
`/extensions/${extensionId}/${encodeURIComponent(
|
|
344
|
+
(panel.title ?? "extension")
|
|
345
|
+
.toLowerCase()
|
|
346
|
+
.replace(/[^a-z0-9]+/g, "-"),
|
|
347
|
+
)}`,
|
|
348
|
+
)
|
|
349
|
+
}
|
|
330
350
|
>
|
|
331
|
-
<
|
|
332
|
-
{
|
|
351
|
+
<IconExternalLink className="h-4 w-4 mr-2" />
|
|
352
|
+
Open extension {/* i18n-ignore */}
|
|
333
353
|
</DropdownMenuItem>
|
|
334
|
-
|
|
335
|
-
|
|
354
|
+
) : null}
|
|
355
|
+
<DropdownMenuSeparator />
|
|
356
|
+
<DropdownMenuItem onSelect={() => setExtRefreshKey((k) => k + 1)}>
|
|
357
|
+
<IconRefresh className="h-4 w-4 mr-2" />
|
|
358
|
+
{t("sqlDashboard.refresh")}
|
|
359
|
+
</DropdownMenuItem>
|
|
360
|
+
{editable ? (
|
|
361
|
+
<>
|
|
362
|
+
<DropdownMenuSeparator />
|
|
363
|
+
<DropdownMenuItem
|
|
364
|
+
onSelect={(e) => {
|
|
365
|
+
e.preventDefault();
|
|
366
|
+
setConfirmOpen(true);
|
|
367
|
+
}}
|
|
368
|
+
>
|
|
369
|
+
<IconTrash className="h-4 w-4 mr-2" />
|
|
370
|
+
{t("sidebar.delete")}
|
|
371
|
+
</DropdownMenuItem>
|
|
372
|
+
</>
|
|
373
|
+
) : null}
|
|
374
|
+
</DropdownMenuContent>
|
|
375
|
+
</DropdownMenu>
|
|
376
|
+
{editable ? (
|
|
336
377
|
<PanelDragHandle
|
|
337
378
|
panelId={panel.id}
|
|
338
379
|
label={t("sqlDashboard.dragToReorder")}
|
|
339
380
|
className="p-1 rounded bg-background/80 cursor-grab active:cursor-grabbing text-muted-foreground/50 hover:text-muted-foreground"
|
|
340
381
|
iconClassName="h-3.5 w-3.5"
|
|
341
382
|
/>
|
|
342
|
-
|
|
343
|
-
|
|
383
|
+
) : null}
|
|
384
|
+
</div>
|
|
385
|
+
<Dialog open={expanded} onOpenChange={setExpanded}>
|
|
386
|
+
<DialogContent className="flex h-[90vh] w-[95vw] max-w-[1400px] flex-col gap-4">
|
|
387
|
+
<DialogHeader className="shrink-0 pr-8 text-left">
|
|
388
|
+
<DialogTitle className="truncate">{panel.title}</DialogTitle>
|
|
389
|
+
</DialogHeader>
|
|
390
|
+
<div className="flex min-h-0 flex-1 flex-col overflow-auto">
|
|
391
|
+
<ChartFillHeight>
|
|
392
|
+
<SqlChart
|
|
393
|
+
key={extRefreshKey}
|
|
394
|
+
panel={panel}
|
|
395
|
+
resolvedSql={resolvedSql}
|
|
396
|
+
loadData
|
|
397
|
+
/>
|
|
398
|
+
</ChartFillHeight>
|
|
399
|
+
</div>
|
|
400
|
+
</DialogContent>
|
|
401
|
+
</Dialog>
|
|
344
402
|
{editable ? (
|
|
345
403
|
<AlertDialog open={confirmOpen} onOpenChange={setConfirmOpen}>
|
|
346
404
|
<AlertDialogContent>
|