@shuffleio/shuffle-mcps 0.0.25 → 0.0.27

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/index.mjs CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  getApiUrl,
6
6
  getAuthHeader,
7
7
  getHostBaseUrl,
8
+ getShuffleCoreFormUrl,
8
9
  getTrackedOrgId,
9
10
  installFetchBreaker,
10
11
  invalidateAppsCache,
@@ -16,7 +17,7 @@ import {
16
17
  setHostBaseUrl,
17
18
  setRegionUrl,
18
19
  shuffleFetch
19
- } from "./chunk-R3YLER6P.mjs";
20
+ } from "./chunk-B4JFC2JU.mjs";
20
21
 
21
22
  // index.ts
22
23
  import "./shuffle-mcp-ER33P3W2.css";
@@ -25,6 +26,7 @@ import React5 from "react";
25
26
  // ShuffleMcpThemeProvider.tsx
26
27
  import React from "react";
27
28
  import { ThemeProvider, createTheme, useTheme as useMuiTheme } from "@mui/material";
29
+ import "./shuffle-mcp-ER33P3W2.css";
28
30
  import { jsx, jsxs } from "react/jsx-runtime";
29
31
  var readHtmlDarkClass = () => {
30
32
  if (typeof document === "undefined") return false;
@@ -777,7 +779,7 @@ async function backfillAppImages(dedupedApps) {
777
779
  let missing = dedupedApps.filter((d) => !d.bestImage && !d.app.large_image);
778
780
  if (missing.length === 0) return dedupedApps;
779
781
  try {
780
- const { fetchAppsViaApiConfig: fetchAppsViaApiConfig2 } = await import("./appsCache-CFCVTF7D.mjs");
782
+ const { fetchAppsViaApiConfig: fetchAppsViaApiConfig2 } = await import("./appsCache-KWDP7F2K.mjs");
781
783
  const apps = await fetchAppsViaApiConfig2().catch(() => []);
782
784
  if (Array.isArray(apps) && apps.length > 0) {
783
785
  const byName = /* @__PURE__ */ new Map();
@@ -6237,10 +6239,11 @@ var ShuffleMCP = React3.forwardRef(({
6237
6239
  }, [internalSelectedApps]);
6238
6240
  const filteredPrivateApps = useMemo4(() => {
6239
6241
  if (privateApps.length === 0) return [];
6240
- const q = query.trim().toLowerCase();
6242
+ const normalize = (s) => (s || "").toLowerCase().replace(/[\s_\-]+/g, "");
6243
+ const q = normalize(query.trim());
6241
6244
  if (!q) return privateApps;
6242
6245
  return privateApps.filter(
6243
- (a) => a.name.toLowerCase().includes(q) || (a.description || "").toLowerCase().includes(q) || (a.categories || []).some((c) => c.toLowerCase().includes(q))
6246
+ (a) => normalize(a.name).includes(q) || normalize(a.description || "").includes(q) || (a.categories || []).some((c) => normalize(c).includes(q))
6244
6247
  );
6245
6248
  }, [privateApps, query]);
6246
6249
  const displayResults = useMemo4(() => {
@@ -7529,7 +7532,7 @@ var runAgent = async (request) => {
7529
7532
  }
7530
7533
  const payload = {
7531
7534
  jsonrpc: "2.0",
7532
- id: crypto.randomUUID(),
7535
+ id: Date.now(),
7533
7536
  method: "tools/call",
7534
7537
  params
7535
7538
  };
@@ -7993,10 +7996,7 @@ var getDiagnosableScope = (parsed) => {
7993
7996
  const action = String(d.action || d.details?.action || "").toLowerCase();
7994
7997
  const category = String(d.category || "").toLowerCase();
7995
7998
  if (!["finish", "finalise"].includes(action) && !["finish", "finalise"].includes(category)) return null;
7996
- return {
7997
- reason: d.reason,
7998
- fields: Array.isArray(d.fields) ? d.fields.map((f) => f?.value).filter(Boolean) : void 0
7999
- };
7999
+ return { reason: d.reason };
8000
8000
  });
8001
8001
  if (finalDecisions.some((d) => d !== null)) scope.decisions = finalDecisions;
8002
8002
  }
@@ -8070,6 +8070,32 @@ var diagnoseOutputWarning = (run) => {
8070
8070
  if (raw && entries.length === 0) entries.push({ path: "", value: raw });
8071
8071
  const haystack = entries.map((e) => e.value).join("\n");
8072
8072
  const lower = haystack.toLowerCase();
8073
+ const ERROR_FIELD_NAMES = /* @__PURE__ */ new Set([
8074
+ "error",
8075
+ "errors",
8076
+ "err",
8077
+ "reason",
8078
+ "message",
8079
+ "messages",
8080
+ "msg",
8081
+ "detail",
8082
+ "details",
8083
+ "failure",
8084
+ "fault",
8085
+ "exception",
8086
+ "exceptions",
8087
+ "warning",
8088
+ "warnings",
8089
+ "status_text",
8090
+ "status_message",
8091
+ "status_reason",
8092
+ "errormessage",
8093
+ "error_description"
8094
+ ]);
8095
+ const getPathSegments = (path) => path.split(/[.\[\]]+/).filter(Boolean).map((segment) => segment.toLowerCase());
8096
+ const isErrorPath = (path) => getPathSegments(path).some((segment) => ERROR_FIELD_NAMES.has(segment));
8097
+ const errorEntries = entries.filter((e) => isErrorPath(e.path));
8098
+ const errorHaystackLower = errorEntries.map((e) => e.value).join("\n").toLowerCase();
8073
8099
  const findEvidence = (test, max = 3) => {
8074
8100
  const out = [];
8075
8101
  for (const e of entries) {
@@ -8086,23 +8112,35 @@ var diagnoseOutputWarning = (run) => {
8086
8112
  let statusEvidence = null;
8087
8113
  const statusPatterns = [
8088
8114
  /\bhttp[\s/]?(\d{3})\b/i,
8089
- /\bstatus[\s:_-]+(\d{3})\b/i,
8090
- /\bstatus[_\s-]?code["\s:]+(\d{3})\b/i,
8091
- /\bcode["\s:]+(\d{3})\b/i,
8092
- /\[(\d{3})\]/,
8093
- /\((\d{3})\)/,
8094
- /\b(4\d{2}|5\d{2})\b/
8115
+ /\b(?:response[_\s-]?status|status[_\s-]?code|response[_\s-]?code)["'\s:=]+(\d{3})\b/i,
8116
+ /\bstatus["'\s:=]+(\d{3})\b/i
8095
8117
  ];
8096
- outer: for (const re of statusPatterns) {
8118
+ const isStatusPath = (path) => {
8119
+ const segments = getPathSegments(path);
8120
+ const last = segments[segments.length - 1];
8121
+ return ["status", "status_code", "response_status", "response_code", "http_status"].includes(last || "");
8122
+ };
8123
+ const statusFromEntry = (entry) => {
8124
+ if (isStatusPath(entry.path) && /^\d{3}$/.test(entry.value.trim())) {
8125
+ return Number(entry.value.trim());
8126
+ }
8127
+ for (const re of statusPatterns) {
8128
+ const m = entry.value.match(re);
8129
+ if (m) return Number(m[1]);
8130
+ }
8131
+ return null;
8132
+ };
8133
+ const hasSuccessStatus = entries.some((e) => {
8134
+ const n = statusFromEntry(e);
8135
+ return typeof n === "number" && n >= 200 && n < 300;
8136
+ });
8137
+ if (!hasSuccessStatus) {
8097
8138
  for (const e of entries) {
8098
- const m = e.value.match(re);
8099
- if (m) {
8100
- const n = Number(m[1]);
8101
- if (n >= 400 && n < 600) {
8102
- status = n;
8103
- statusEvidence = { path: e.path || "(root)", value: trimEvidenceValue(e.value) };
8104
- break outer;
8105
- }
8139
+ const n = statusFromEntry(e);
8140
+ if (typeof n === "number" && n >= 400 && n < 600) {
8141
+ status = n;
8142
+ statusEvidence = { path: e.path || "(root)", value: trimEvidenceValue(e.value) };
8143
+ break;
8106
8144
  }
8107
8145
  }
8108
8146
  }
@@ -8122,9 +8160,7 @@ var diagnoseOutputWarning = (run) => {
8122
8160
  const dedup = ev.filter((e) => e.path !== statusEvidence.path);
8123
8161
  return [statusEvidence, ...dedup].slice(0, 3);
8124
8162
  };
8125
- if (status === 401 || /\b(unauthori[sz]ed|invalid[_\s-]*(api[_\s-]*key|token|credentials?)|authentication[_\s-]*(failed|required)|missing[_\s-]*(api[_\s-]*key|token|authorization)|bearer[_\s-]*token|expired[_\s-]*token)\b/.test(
8126
- lower
8127
- )) {
8163
+ if (status === 401 || /\b(unauthori[sz]ed|invalid[_\s-]*(api[_\s-]*key|token|credentials?)|authentication[_\s-]*(failed|required)|missing[_\s-]*(api[_\s-]*key|token|authorization)|bearer[_\s-]*token|expired[_\s-]*token)\b/.test(errorHaystackLower)) {
8128
8164
  const ev = findEvidenceByRegex(
8129
8165
  /unauthori[sz]ed|invalid[_\s-]*(api[_\s-]*key|token|credentials?)|authentication[_\s-]*(failed|required)|missing[_\s-]*(api[_\s-]*key|token|authorization)|bearer[_\s-]*token|expired[_\s-]*token|\b401\b/
8130
8166
  );
@@ -8138,9 +8174,7 @@ var diagnoseOutputWarning = (run) => {
8138
8174
  evidence: withStatusEvidence(ev)
8139
8175
  };
8140
8176
  }
8141
- if (status === 403 || /\b(forbidden|permission[_\s-]*denied|not[_\s-]*allowed|access[_\s-]*denied|insufficient[_\s-]*(scope|permission|privileges?)|missing[_\s-]*scope)\b/.test(
8142
- lower
8143
- )) {
8177
+ if (status === 403 || /\b(forbidden|permission[_\s-]*denied|not[_\s-]*allowed|access[_\s-]*denied|insufficient[_\s-]*(scope|permission|privileges?)|missing[_\s-]*scope)\b/.test(errorHaystackLower)) {
8144
8178
  const ev = findEvidenceByRegex(
8145
8179
  /forbidden|permission[_\s-]*denied|not[_\s-]*allowed|access[_\s-]*denied|insufficient[_\s-]*(scope|permission|privileges?)|missing[_\s-]*scope|\b403\b/
8146
8180
  );
@@ -8154,7 +8188,7 @@ var diagnoseOutputWarning = (run) => {
8154
8188
  evidence: withStatusEvidence(ev)
8155
8189
  };
8156
8190
  }
8157
- if (status === 429 || /\b(rate[_\s-]*limit|too[_\s-]*many[_\s-]*requests|quota[_\s-]*exceeded|throttled)\b/.test(lower)) {
8191
+ if (status === 429 || /\b(rate[_\s-]*limit|too[_\s-]*many[_\s-]*requests|quota[_\s-]*exceeded|throttled)\b/.test(errorHaystackLower)) {
8158
8192
  const ev = findEvidenceByRegex(
8159
8193
  /rate[_\s-]*limit|too[_\s-]*many[_\s-]*requests|quota[_\s-]*exceeded|throttled|\b429\b/
8160
8194
  );
@@ -8168,7 +8202,7 @@ var diagnoseOutputWarning = (run) => {
8168
8202
  evidence: withStatusEvidence(ev)
8169
8203
  };
8170
8204
  }
8171
- if (status === 404 || /\b(not[_\s-]*found|no such|does not exist|unknown[_\s-]*(id|resource))\b/.test(lower)) {
8205
+ if (status === 404 || /\b(not[_\s-]*found|no such|does not exist|unknown[_\s-]*(id|resource))\b/.test(errorHaystackLower)) {
8172
8206
  const ev = findEvidenceByRegex(
8173
8207
  /not[_\s-]*found|no such|does not exist|unknown[_\s-]*(id|resource)|\b404\b/
8174
8208
  );
@@ -8182,9 +8216,7 @@ var diagnoseOutputWarning = (run) => {
8182
8216
  evidence: withStatusEvidence(ev)
8183
8217
  };
8184
8218
  }
8185
- if (status === 400 || status === 422 || /\b(bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload))\b/.test(
8186
- lower
8187
- )) {
8219
+ if (status === 400 || status === 422 || /\b(bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload))\b/.test(errorHaystackLower)) {
8188
8220
  const ev = findEvidenceByRegex(
8189
8221
  /bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload)|\b400\b|\b422\b/
8190
8222
  );
@@ -8198,9 +8230,7 @@ var diagnoseOutputWarning = (run) => {
8198
8230
  evidence: withStatusEvidence(ev)
8199
8231
  };
8200
8232
  }
8201
- if (typeof status === "number" && status >= 500 || /\b(timeout|timed[_\s-]*out|econnrefused|enotfound|network[_\s-]*error|connection[_\s-]*(refused|reset|closed)|service[_\s-]*unavailable|bad[_\s-]*gateway|gateway[_\s-]*timeout)\b/.test(
8202
- lower
8203
- )) {
8233
+ if (typeof status === "number" && status >= 500 || /\b(timeout|timed[_\s-]*out|econnrefused|enotfound|network[_\s-]*error|connection[_\s-]*(refused|reset|closed)|service[_\s-]*unavailable|bad[_\s-]*gateway|gateway[_\s-]*timeout)\b/.test(errorHaystackLower)) {
8204
8234
  const ev = findEvidenceByRegex(
8205
8235
  /timeout|timed[_\s-]*out|econnrefused|enotfound|network[_\s-]*error|connection[_\s-]*(refused|reset|closed)|service[_\s-]*unavailable|bad[_\s-]*gateway|gateway[_\s-]*timeout|\b5\d{2}\b/
8206
8236
  );
@@ -8445,6 +8475,153 @@ var deepParseJsonStrings3 = (obj, depth = 0) => {
8445
8475
  }
8446
8476
  return obj;
8447
8477
  };
8478
+ var tryParseJsonObject = (raw) => {
8479
+ if (!raw) return null;
8480
+ const trimmed = raw.trim();
8481
+ if (!(trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]"))) return null;
8482
+ try {
8483
+ const parsed = JSON.parse(trimmed);
8484
+ if (parsed && typeof parsed === "object") return deepParseJsonStrings3(parsed);
8485
+ } catch {
8486
+ }
8487
+ return null;
8488
+ };
8489
+ var stripSingleCodeFence = (raw) => {
8490
+ const m = raw.match(/^\s*```(?:json)?\s*\n([\s\S]*?)\n```\s*$/i);
8491
+ return m ? m[1] : raw;
8492
+ };
8493
+ var FinishAnswerMarkdown = ({ text }) => {
8494
+ const wholeJson = useMemo6(() => tryParseJsonObject(stripSingleCodeFence(text)), [text]);
8495
+ if (wholeJson !== null) {
8496
+ return /* @__PURE__ */ jsx20(Box14, { sx: { "& .json-view": { backgroundColor: "transparent !important", fontSize: "0.82rem" } }, children: /* @__PURE__ */ jsx20(JsonView2, { src: wholeJson, collapsed: 2, enableClipboard: true, displaySize: true, theme: "default" }) });
8497
+ }
8498
+ return /* @__PURE__ */ jsx20(
8499
+ Markdown,
8500
+ {
8501
+ remarkPlugins: [remarkGfm4, remarkBreaks],
8502
+ components: {
8503
+ code({ inline, className, children, ...props }) {
8504
+ const content = String(children ?? "").replace(/\n$/, "");
8505
+ const isBlock = !inline && (content.includes("\n") || /language-/.test(className || ""));
8506
+ if (isBlock) {
8507
+ const parsed = tryParseJsonObject(content);
8508
+ if (parsed !== null) {
8509
+ return /* @__PURE__ */ jsx20(Box14, { sx: { my: 1, p: 1.5, borderRadius: 1, bgcolor: "hsl(var(--muted))", "& .json-view": { backgroundColor: "transparent !important", fontSize: "0.82rem" } }, children: /* @__PURE__ */ jsx20(JsonView2, { src: parsed, collapsed: 2, enableClipboard: true, displaySize: true, theme: "default" }) });
8510
+ }
8511
+ }
8512
+ return /* @__PURE__ */ jsx20("code", { className, ...props, children });
8513
+ }
8514
+ },
8515
+ children: text
8516
+ }
8517
+ );
8518
+ };
8519
+ var RunFinishedSummary = ({
8520
+ status,
8521
+ isRunning,
8522
+ finishAnswer,
8523
+ raw,
8524
+ onToggleRaw,
8525
+ decisionCount,
8526
+ durationSec,
8527
+ showMeta = false,
8528
+ children
8529
+ }) => {
8530
+ return /* @__PURE__ */ jsxs17(Fragment7, { children: [
8531
+ /* @__PURE__ */ jsxs17(Box14, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
8532
+ isRunning ? /* @__PURE__ */ jsx20(CircularProgress4, { size: 16, sx: { color: "hsl(var(--primary))" } }) : status === "FINISHED" ? /* @__PURE__ */ jsx20(CheckCircleIcon4, { size: 18, color: "hsl(142 70% 45%)" }) : /* @__PURE__ */ jsx20(ErrorIcon, { size: 18, color: "hsl(var(--destructive))" }),
8533
+ /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.9rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: isRunning ? "Agent is working\u2026" : status === "FINISHED" ? "Run finished" : `Run ${status.toLowerCase()}` }),
8534
+ showMeta && (decisionCount != null || durationSec != null) && /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
8535
+ decisionCount != null ? `${decisionCount} step${decisionCount === 1 ? "" : "s"}` : "",
8536
+ durationSec != null ? `${decisionCount != null ? " \xB7 " : ""}${Math.round(durationSec)}s` : ""
8537
+ ] }),
8538
+ /* @__PURE__ */ jsx20(Box14, { sx: { flexGrow: 1 } }),
8539
+ finishAnswer && /* @__PURE__ */ jsx20(
8540
+ Button8,
8541
+ {
8542
+ size: "small",
8543
+ variant: "outlined",
8544
+ onClick: onToggleRaw,
8545
+ sx: {
8546
+ height: 28,
8547
+ textTransform: "none",
8548
+ fontWeight: 500,
8549
+ fontSize: "0.72rem",
8550
+ px: 1,
8551
+ minWidth: 0,
8552
+ color: "hsl(var(--muted-foreground))",
8553
+ borderColor: "hsl(var(--border))"
8554
+ },
8555
+ children: raw ? "Rendered" : "Raw"
8556
+ }
8557
+ )
8558
+ ] }),
8559
+ children,
8560
+ finishAnswer && /* @__PURE__ */ jsx20(Box14, { sx: {
8561
+ p: 2,
8562
+ borderRadius: 1.5,
8563
+ border: "1px solid hsl(var(--border))",
8564
+ bgcolor: "hsl(var(--background))",
8565
+ fontSize: "0.9rem",
8566
+ color: "hsl(var(--foreground))",
8567
+ "& > *:first-of-type": { mt: 0 },
8568
+ "& > *:last-child": { mb: 0 },
8569
+ "& p": { my: 1, lineHeight: 1.55 },
8570
+ "& h1, & h2, & h3, & h4": { mt: 2, mb: 1, fontWeight: 600, lineHeight: 1.3 },
8571
+ "& h1": { fontSize: "1.15rem" },
8572
+ "& h2": { fontSize: "1.05rem" },
8573
+ "& h3, & h4": { fontSize: "0.95rem" },
8574
+ "& ul": { my: 1, pl: 3, listStyleType: "disc", listStylePosition: "outside" },
8575
+ "& ol": { my: 1, pl: 3, listStyleType: "decimal", listStylePosition: "outside" },
8576
+ "& ul ul": { listStyleType: "circle" },
8577
+ "& ul ul ul": { listStyleType: "square" },
8578
+ "& li": { my: 0.25, display: "list-item" },
8579
+ "& li::marker": { color: "hsl(var(--muted-foreground))" },
8580
+ "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
8581
+ "& code": {
8582
+ px: 0.5,
8583
+ py: 0.125,
8584
+ borderRadius: 0.5,
8585
+ bgcolor: "hsl(var(--muted))",
8586
+ fontFamily: '"JetBrains Mono", ui-monospace, monospace',
8587
+ fontSize: "0.82em"
8588
+ },
8589
+ "& pre": {
8590
+ p: 1.5,
8591
+ my: 1,
8592
+ borderRadius: 1,
8593
+ bgcolor: "hsl(var(--muted))",
8594
+ overflowX: "auto",
8595
+ fontSize: "0.82rem"
8596
+ },
8597
+ "& pre code": { p: 0, bgcolor: "transparent" },
8598
+ "& blockquote": {
8599
+ borderLeft: "3px solid hsl(var(--border))",
8600
+ pl: 1.5,
8601
+ my: 1,
8602
+ color: "hsl(var(--muted-foreground))"
8603
+ },
8604
+ "& table": { borderCollapse: "collapse", my: 1, fontSize: "0.85rem" },
8605
+ "& th, & td": { border: "1px solid hsl(var(--border))", px: 1, py: 0.5 },
8606
+ "& hr": { border: 0, borderTop: "1px solid hsl(var(--border))", my: 1.5 }
8607
+ }, children: raw ? /* @__PURE__ */ jsx20(
8608
+ Box14,
8609
+ {
8610
+ component: "pre",
8611
+ sx: {
8612
+ m: 0,
8613
+ fontSize: "0.78rem",
8614
+ fontFamily: '"JetBrains Mono", ui-monospace, monospace',
8615
+ color: "hsl(var(--foreground))",
8616
+ whiteSpace: "pre-wrap",
8617
+ wordBreak: "break-word",
8618
+ lineHeight: 1.55
8619
+ },
8620
+ children: finishAnswer
8621
+ }
8622
+ ) : /* @__PURE__ */ jsx20(FinishAnswerMarkdown, { text: normalizeMarkdown(finishAnswer) }) })
8623
+ ] });
8624
+ };
8448
8625
  var validateJson = (raw) => {
8449
8626
  if (raw == null) return { valid: false, result: null };
8450
8627
  if (typeof raw === "object") return { valid: true, result: raw };
@@ -8455,6 +8632,17 @@ var validateJson = (raw) => {
8455
8632
  return { valid: false, result: raw };
8456
8633
  }
8457
8634
  };
8635
+ var AGENT_NO_AUTH_APPS = /* @__PURE__ */ new Set([
8636
+ "shuffle_host_monitors",
8637
+ "shuffle_monitors",
8638
+ "shuffle_sensors",
8639
+ "shuffle_workflows",
8640
+ "shuffle_datastore",
8641
+ "shuffle_apps",
8642
+ "shuffle_detection",
8643
+ "shuffle_files"
8644
+ ]);
8645
+ var normalizeAgentAppName = (name) => name.toLowerCase().replace(/[\s-]+/g, "_");
8458
8646
  var extractAuthRequest = (decision) => {
8459
8647
  if (!decision || typeof decision !== "object") return null;
8460
8648
  const raw = decision?.run_details?.raw_response;
@@ -8470,18 +8658,20 @@ var extractAuthRequest = (decision) => {
8470
8658
  }
8471
8659
  const needsAuth = parsed && (parsed.action === "app_authentication" || parsed.app_authentication === true);
8472
8660
  if (!needsAuth) return null;
8473
- let appName = parsed.app || parsed.app_name || parsed.appname;
8661
+ let toolAppName;
8474
8662
  let appId = null;
8475
- if (!appName && typeof decision?.tool === "string") {
8663
+ if (typeof decision?.tool === "string") {
8476
8664
  const t = decision.tool;
8477
8665
  if (t.startsWith("app:")) {
8478
8666
  const parts = t.split(":");
8479
8667
  appId = parts[1] || null;
8480
- appName = parts[2] || t;
8668
+ toolAppName = parts[2] || void 0;
8481
8669
  } else {
8482
- appName = t;
8670
+ toolAppName = t;
8483
8671
  }
8484
8672
  }
8673
+ let appName = parsed.app || parsed.app_name || parsed.appname;
8674
+ if (!appName) appName = toolAppName;
8485
8675
  if (!appName) {
8486
8676
  const f = (decision?.fields || []).find((x) => x?.key === "app" || x?.key === "app_name");
8487
8677
  if (f?.value) appName = f.value;
@@ -8545,7 +8735,9 @@ var TimelineRow = ({
8545
8735
  getFormUrl,
8546
8736
  runFinished,
8547
8737
  onAuthenticateApp,
8738
+ onRefreshAuthenticatedApps,
8548
8739
  isAppAuthenticated,
8740
+ authAppsLoading = false,
8549
8741
  highlight = false
8550
8742
  }) => {
8551
8743
  const [submitAttempted, setSubmitAttempted] = useState12(false);
@@ -8735,7 +8927,7 @@ var TimelineRow = ({
8735
8927
  IconButton8,
8736
8928
  {
8737
8929
  size: "small",
8738
- onClick: () => window.open(details.run_details.debug_url, "_blank", "noopener,noreferrer"),
8930
+ onClick: () => window.open(getShuffleCoreFormUrl(details.run_details.debug_url), "_blank", "noopener,noreferrer"),
8739
8931
  sx: { color: "hsl(var(--muted-foreground))", "&:hover": { color: "hsl(var(--primary))" } },
8740
8932
  children: /* @__PURE__ */ jsx20(OpenInNewIcon2, { size: 16 })
8741
8933
  }
@@ -8836,9 +9028,10 @@ var TimelineRow = ({
8836
9028
  (() => {
8837
9029
  const req = extractAuthRequest(details);
8838
9030
  if (!req) return null;
8839
- if (isAppAuthenticated?.(req.appName)) return null;
9031
+ if (authAppsLoading) return null;
9032
+ const authed = !!isAppAuthenticated?.(req.appName, req.appId);
8840
9033
  const pretty = req.appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
8841
- const slug = req.appName.toLowerCase().replace(/[\s-]+/g, "_");
9034
+ const slug = normalizeAgentAppName(req.appName);
8842
9035
  const appId = req.appId || appsById[req.appName]?.id || appsById[slug]?.id || null;
8843
9036
  const icon = appsById[req.appName]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
8844
9037
  return /* @__PURE__ */ jsx20(Box14, { sx: { px: 4, pb: 2 }, children: /* @__PURE__ */ jsxs17(Box14, { sx: {
@@ -8847,22 +9040,68 @@ var TimelineRow = ({
8847
9040
  gap: 1.5,
8848
9041
  p: 1.5,
8849
9042
  borderRadius: 1.5,
8850
- border: "1px solid hsla(var(--severity-medium) / 0.3)",
8851
- bgcolor: "hsla(var(--severity-medium) / 0.08)"
9043
+ border: authed ? "1px solid hsla(var(--severity-low) / 0.35)" : "1px solid hsla(var(--severity-medium) / 0.3)",
9044
+ bgcolor: authed ? "hsla(var(--severity-low) / 0.08)" : "hsla(var(--severity-medium) / 0.08)"
8852
9045
  }, children: [
8853
- /* @__PURE__ */ jsx20(LockIcon3, { size: 22, color: "hsl(var(--severity-medium))" }),
9046
+ /* @__PURE__ */ jsx20(LockIcon3, { size: 22, color: authed ? "hsl(var(--severity-low))" : "hsl(var(--severity-medium))" }),
8854
9047
  /* @__PURE__ */ jsxs17(Box14, { sx: { flex: 1, minWidth: 0 }, children: [
8855
- /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
8856
- pretty,
8857
- " requires authentication"
8858
- ] }),
8859
- /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
8860
- "Connect your ",
8861
- pretty,
8862
- " account so the agent can complete this step, then rerun the decision."
8863
- ] })
9048
+ /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: authed ? `${pretty} is now connected \u2014 rerun this action` : `${pretty} requires authentication` }),
9049
+ /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: authed ? `This step failed because ${pretty} was not authenticated. Credentials are saved, so rerunning should succeed.` : `Connect your ${pretty} account so the agent can complete this step, then rerun the decision.` })
8864
9050
  ] }),
8865
- /* @__PURE__ */ jsxs17(
9051
+ authed && /* @__PURE__ */ jsx20(
9052
+ Button8,
9053
+ {
9054
+ variant: "text",
9055
+ size: "small",
9056
+ startIcon: /* @__PURE__ */ jsx20(
9057
+ Avatar7,
9058
+ {
9059
+ src: icon || void 0,
9060
+ alt: "",
9061
+ variant: "rounded",
9062
+ sx: {
9063
+ width: 18,
9064
+ height: 18,
9065
+ borderRadius: 0.5,
9066
+ bgcolor: "hsl(var(--background) / 0.4)",
9067
+ color: "hsl(var(--background))",
9068
+ fontSize: "0.7rem",
9069
+ fontWeight: 700,
9070
+ "& img": { objectFit: "contain" }
9071
+ },
9072
+ children: pretty.charAt(0)
9073
+ }
9074
+ ),
9075
+ disabled: !onAuthenticateApp,
9076
+ onClick: (e) => {
9077
+ e.stopPropagation();
9078
+ onRefreshAuthenticatedApps?.();
9079
+ onAuthenticateApp?.(req.appName, appId);
9080
+ },
9081
+ sx: {
9082
+ height: 36,
9083
+ textTransform: "none",
9084
+ fontWeight: 500,
9085
+ color: "hsl(var(--muted-foreground))"
9086
+ },
9087
+ children: "Review authentication"
9088
+ }
9089
+ ),
9090
+ authed ? /* @__PURE__ */ jsx20(
9091
+ Button8,
9092
+ {
9093
+ variant: "contained",
9094
+ size: "small",
9095
+ startIcon: /* @__PURE__ */ jsx20(RestartAltIcon2, { size: 16 }),
9096
+ disabled: agentRequestLoading || !details?.run_details?.id,
9097
+ onClick: (e) => {
9098
+ e.stopPropagation();
9099
+ if (details) onRerunDecision(details);
9100
+ },
9101
+ sx: { height: 36, textTransform: "none", fontWeight: 600 },
9102
+ children: "Rerun action"
9103
+ }
9104
+ ) : /* @__PURE__ */ jsxs17(
8866
9105
  Button8,
8867
9106
  {
8868
9107
  variant: "outlined",
@@ -8889,6 +9128,7 @@ var TimelineRow = ({
8889
9128
  disabled: !onAuthenticateApp,
8890
9129
  onClick: (e) => {
8891
9130
  e.stopPropagation();
9131
+ onRefreshAuthenticatedApps?.();
8892
9132
  onAuthenticateApp?.(req.appName, appId);
8893
9133
  },
8894
9134
  sx: {
@@ -8975,6 +9215,7 @@ var AgentUI = ({
8975
9215
  authorization,
8976
9216
  initialExecution,
8977
9217
  onRun,
9218
+ onAppsChange,
8978
9219
  onViewChange,
8979
9220
  onSchedule,
8980
9221
  apiKey,
@@ -9004,6 +9245,7 @@ var AgentUI = ({
9004
9245
  ];
9005
9246
  const [chosenApps, setChosenApps] = useState12(apps ?? defaultApps ?? BUILTIN_DEFAULT_APPS);
9006
9247
  const [availableApps, setAvailableApps] = useState12([]);
9248
+ const [authAppsLoading, setAuthAppsLoading] = useState12(autoLoadApps && hasApiKey);
9007
9249
  const [executionApps, setExecutionApps] = useState12([]);
9008
9250
  const [resolvedToolApps, setResolvedToolApps] = useState12({});
9009
9251
  const [appSearchOpen, setAppSearchOpen] = useState12(false);
@@ -9033,6 +9275,7 @@ var AgentUI = ({
9033
9275
  const [highlightedIndex, setHighlightedIndex] = useState12(null);
9034
9276
  const [questionAnswers, setQuestionAnswers] = useState12({});
9035
9277
  const [simpleSubmitAttempted, setSimpleSubmitAttempted] = useState12(false);
9278
+ const [finishAnswerRaw, setFinishAnswerRaw] = useState12(false);
9036
9279
  const [continuationText, setContinuationText] = useState12("");
9037
9280
  const [error, setError] = useState12(null);
9038
9281
  const [searchParams, setSearchParams] = useSearchParams();
@@ -9124,29 +9367,33 @@ var AgentUI = ({
9124
9367
  }
9125
9368
  return m;
9126
9369
  }, [chosenApps, executionApps, resolvedToolApps]);
9127
- const isAppAuthenticated = useCallback8((appName) => {
9128
- if (!appName) return false;
9129
- const norm4 = (s) => s.toLowerCase().replace(/[\s-]+/g, "_");
9130
- const target = norm4(appName);
9131
- return availableApps.some((a) => norm4(a.name || "") === target);
9370
+ const isAppAuthenticated = useCallback8((appName, appId) => {
9371
+ if (!appName && !appId) return false;
9372
+ const target = normalizeAgentAppName(appName);
9373
+ if (AGENT_NO_AUTH_APPS.has(target)) return true;
9374
+ return availableApps.some((a) => {
9375
+ if (appId && a.id && String(a.id) === String(appId)) return true;
9376
+ return !!appName && normalizeAgentAppName(a.name || "") === target;
9377
+ });
9132
9378
  }, [availableApps]);
9133
9379
  const pendingAuthApps = useMemo6(() => {
9380
+ if (authAppsLoading) return [];
9134
9381
  const decisions = agentData?.decisions || [];
9135
9382
  const seen = /* @__PURE__ */ new Set();
9136
9383
  const out = [];
9137
9384
  for (const d of decisions) {
9138
9385
  const req = extractAuthRequest(d);
9139
9386
  if (!req) continue;
9140
- const slug = req.appName.toLowerCase().replace(/[\s-]+/g, "_");
9387
+ const slug = normalizeAgentAppName(req.appName);
9141
9388
  if (seen.has(slug)) continue;
9142
- if (isAppAuthenticated(req.appName)) continue;
9389
+ if (isAppAuthenticated(req.appName, req.appId)) continue;
9143
9390
  seen.add(slug);
9144
9391
  const appId = req.appId || appsById[req.appName]?.id || appsById[slug]?.id || null;
9145
9392
  const icon = appsById[req.appName]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
9146
9393
  out.push({ appName: req.appName, appId, icon });
9147
9394
  }
9148
9395
  return out;
9149
- }, [agentData, appsById, isAppAuthenticated]);
9396
+ }, [agentData, appsById, authAppsLoading, isAppAuthenticated]);
9150
9397
  useEffect11(() => {
9151
9398
  if (apps) setChosenApps(apps);
9152
9399
  }, [apps]);
@@ -9256,45 +9503,60 @@ var AgentUI = ({
9256
9503
  cancelled = true;
9257
9504
  };
9258
9505
  }, [chosenApps, availableApps, resolveUrl2, resolveHeaders2]);
9506
+ const loadAuthenticatedApps = useCallback8(async (signal) => {
9507
+ setAuthAppsLoading(true);
9508
+ try {
9509
+ const resp = await fetch(resolveUrl2("/api/v1/apps/authentication"), {
9510
+ credentials: "include",
9511
+ headers: { ...resolveHeaders2() }
9512
+ });
9513
+ if (!resp.ok) {
9514
+ if (!signal?.cancelled) setAvailableApps([]);
9515
+ return;
9516
+ }
9517
+ const result = await resp.json();
9518
+ const list = Array.isArray(result) ? result : result?.data || [];
9519
+ const seen = /* @__PURE__ */ new Set();
9520
+ const loaded = [];
9521
+ for (const entry of list) {
9522
+ const app = entry?.app || entry;
9523
+ const name = app?.name;
9524
+ if (!name) continue;
9525
+ const valid = entry?.active || entry?.validation?.valid || entry?.hasValidAuth || app?.is_valid || app?.tested;
9526
+ if (valid === false) continue;
9527
+ const key = normalizeAgentAppName(name);
9528
+ if (seen.has(key)) continue;
9529
+ seen.add(key);
9530
+ loaded.push({
9531
+ name,
9532
+ id: app?.id || entry?.id,
9533
+ icon: app?.large_image || app?.image_url || app?.image || entry?.bestImage || ""
9534
+ });
9535
+ }
9536
+ if (signal?.cancelled) return;
9537
+ setAvailableApps(loaded);
9538
+ } catch {
9539
+ } finally {
9540
+ if (!signal?.cancelled) setAuthAppsLoading(false);
9541
+ }
9542
+ }, [resolveUrl2, resolveHeaders2]);
9259
9543
  useEffect11(() => {
9260
9544
  if (!autoLoadApps) return;
9261
- if (apps || defaultApps) return;
9262
9545
  if (!hasApiKey) return;
9263
- let cancelled = false;
9264
- (async () => {
9265
- try {
9266
- const resp = await fetch(resolveUrl2("/api/v1/apps/authentication"), {
9267
- credentials: "include",
9268
- headers: { ...resolveHeaders2() }
9269
- });
9270
- if (!resp.ok) return;
9271
- const result = await resp.json();
9272
- const list = Array.isArray(result) ? result : result?.data || [];
9273
- const seen = /* @__PURE__ */ new Set();
9274
- const loaded = [];
9275
- for (const entry of list) {
9276
- const app = entry?.app || entry;
9277
- const name = app?.name;
9278
- if (!name) continue;
9279
- const valid = entry?.active || entry?.validation?.valid || entry?.hasValidAuth;
9280
- if (valid === false) continue;
9281
- const key = name.toLowerCase();
9282
- if (seen.has(key)) continue;
9283
- seen.add(key);
9284
- loaded.push({
9285
- name,
9286
- id: app?.id || entry?.id,
9287
- icon: app?.large_image || app?.image_url || app?.image || entry?.bestImage || ""
9288
- });
9289
- }
9290
- if (!cancelled && loaded.length) setAvailableApps(loaded);
9291
- } catch {
9292
- }
9293
- })();
9546
+ const signal = { cancelled: false };
9547
+ loadAuthenticatedApps(signal);
9294
9548
  return () => {
9295
- cancelled = true;
9549
+ signal.cancelled = true;
9550
+ };
9551
+ }, [autoLoadApps, hasApiKey, loadAuthenticatedApps]);
9552
+ useEffect11(() => {
9553
+ if (!hasApiKey) return;
9554
+ const handler = () => {
9555
+ loadAuthenticatedApps();
9296
9556
  };
9297
- }, [autoLoadApps, apps, defaultApps, hasApiKey, resolveUrl2, resolveHeaders2]);
9557
+ window.addEventListener("integrations-changed", handler);
9558
+ return () => window.removeEventListener("integrations-changed", handler);
9559
+ }, [hasApiKey, loadAuthenticatedApps]);
9298
9560
  useEffect11(() => {
9299
9561
  const raw = agentData?.allowed_actions;
9300
9562
  if (!Array.isArray(raw) || raw.length === 0) {
@@ -9690,31 +9952,48 @@ var AgentUI = ({
9690
9952
  setAgentRequestLoading(false);
9691
9953
  }
9692
9954
  }, [execution, getExecution]);
9955
+ const resolveRunInput = useCallback8(() => {
9956
+ const fromData = agentData?.original_input;
9957
+ if (fromData && typeof fromData === "string") return fromData;
9958
+ if (actionInput && typeof actionInput === "string" && actionInput.trim()) return actionInput;
9959
+ const params = agentActionResult?.action?.parameters || [];
9960
+ const inputParam = params.find((p) => p?.name === "input");
9961
+ if (inputParam?.value && typeof inputParam.value === "string") return inputParam.value;
9962
+ const msgs = agentData?.input?.messages || [];
9963
+ const userMsg = msgs.find((mm) => mm?.role === "user");
9964
+ if (userMsg?.content && typeof userMsg.content === "string") return userMsg.content;
9965
+ const execArg = execution?.execution_argument;
9966
+ if (execArg && typeof execArg === "string") {
9967
+ try {
9968
+ const parsed = JSON.parse(execArg);
9969
+ if (parsed?.input && typeof parsed.input === "string") return parsed.input;
9970
+ if (parsed?.prompt && typeof parsed.prompt === "string") return parsed.prompt;
9971
+ } catch {
9972
+ if (execArg.length < 4e3) return execArg;
9973
+ }
9974
+ }
9975
+ return "";
9976
+ }, [agentData, actionInput, agentActionResult, execution]);
9693
9977
  const rerunAgent = useCallback8(() => {
9694
- const input = agentData?.original_input || actionInput || (() => {
9695
- const msgs = agentData?.input?.messages || [];
9696
- const m = msgs.find((m2) => m2?.role === "user" && !String(m2?.role).includes("USER CONTEXT"));
9697
- return m?.content || "";
9698
- })();
9978
+ const input = resolveRunInput();
9699
9979
  if (input && typeof input === "string") {
9700
9980
  setActionInput(input);
9701
9981
  }
9702
9982
  if (executionApps.length > 0) {
9703
9983
  setChosenApps(executionApps);
9704
9984
  }
9705
- if (disableStartTab) {
9706
- if (input && typeof input === "string" && input.trim().length >= 6) {
9707
- submitInput(input);
9708
- }
9709
- return;
9985
+ if (!disableStartTab) {
9986
+ setShowStarter(true);
9987
+ setSearchParams((prev) => {
9988
+ const next = new URLSearchParams(prev);
9989
+ next.delete("agentView");
9990
+ return next;
9991
+ }, { replace: true });
9992
+ }
9993
+ if (input && typeof input === "string" && input.trim().length >= 6) {
9994
+ submitInput(input);
9710
9995
  }
9711
- setShowStarter(true);
9712
- setSearchParams((prev) => {
9713
- const next = new URLSearchParams(prev);
9714
- next.delete("agentView");
9715
- return next;
9716
- }, { replace: true });
9717
- }, [agentData, actionInput, executionApps, setSearchParams, disableStartTab, submitInput]);
9996
+ }, [resolveRunInput, executionApps, setSearchParams, disableStartTab, submitInput]);
9718
9997
  const abortAgent = useCallback8(async () => {
9719
9998
  const execId = execution?.execution_id;
9720
9999
  const auth = execution?.authorization;
@@ -9964,13 +10243,12 @@ var AgentUI = ({
9964
10243
  useEffect11(() => {
9965
10244
  onViewChange?.(activeTab);
9966
10245
  }, [activeTab, onViewChange]);
10246
+ useEffect11(() => {
10247
+ onAppsChange?.(chosenApps);
10248
+ }, [chosenApps, onAppsChange]);
9967
10249
  const goToTab = (t) => {
9968
10250
  if (t === "start") {
9969
- const runInput = agentData?.original_input || (() => {
9970
- const msgs = agentData?.input?.messages || [];
9971
- const m = msgs.find((m2) => m2?.role === "user");
9972
- return m?.content || "";
9973
- })();
10251
+ const runInput = resolveRunInput();
9974
10252
  if (runInput && typeof runInput === "string") {
9975
10253
  setActionInput(runInput);
9976
10254
  }
@@ -10111,58 +10389,71 @@ var AgentUI = ({
10111
10389
  ] }, i)) })
10112
10390
  ] }) : scheduleDisabledReasons.length === 1 ? `Cannot schedule: ${scheduleDisabledReasons[0]}` : "";
10113
10391
  const tabBarRef = useRef8(null);
10114
- const tabBar = /* @__PURE__ */ jsx20(
10392
+ const runStatusUpper = (execution?.status || agentData?.status || "").toUpperCase();
10393
+ const runIsActive = hasExecution && !["FINISHED", "FAILURE", "ABORTED", "CANCELLED", "CANCELED"].includes(runStatusUpper);
10394
+ const tabBar = /* @__PURE__ */ jsxs17(
10115
10395
  Box14,
10116
10396
  {
10117
10397
  ref: tabBarRef,
10118
10398
  sx: {
10119
10399
  display: "flex",
10120
10400
  alignItems: "center",
10401
+ gap: 1,
10121
10402
  width: "fit-content",
10122
10403
  alignSelf: "center",
10123
10404
  position: "sticky",
10124
10405
  top: 8,
10125
10406
  zIndex: 5
10126
10407
  },
10127
- children: /* @__PURE__ */ jsx20(
10128
- SegmentedControl,
10129
- {
10130
- layoutId: "agentui-view-switcher",
10131
- ariaLabel: "Agent view",
10132
- value: activeTab,
10133
- onChange: (v) => goToTab(v),
10134
- options: [
10135
- { value: "start", label: "Start", disabled: disableStartTab },
10136
- { value: "simple", label: "Simple", disabled: !hasExecution },
10137
- { value: "detailed", label: "Detailed", disabled: !hasExecution },
10138
- { type: "divider", key: "div" },
10139
- {
10140
- type: "action",
10141
- key: "reload",
10142
- label: /* @__PURE__ */ jsx20(RefreshIcon, { size: 14 }),
10143
- title: "Reload execution data",
10144
- disabled: !hasExecution,
10145
- onClick: () => {
10146
- if (execution?.execution_id && execution?.authorization) {
10147
- getExecution(execution.execution_id, execution.authorization);
10408
+ children: [
10409
+ /* @__PURE__ */ jsx20(
10410
+ SegmentedControl,
10411
+ {
10412
+ layoutId: "agentui-view-switcher",
10413
+ ariaLabel: "Agent view",
10414
+ value: activeTab,
10415
+ onChange: (v) => goToTab(v),
10416
+ options: [
10417
+ { value: "start", label: "Start", disabled: disableStartTab, title: disableStartTab ? "Open a new agent run from the /agents page to start a new prompt" : void 0 },
10418
+ { value: "simple", label: "Simple", disabled: !hasExecution },
10419
+ { value: "detailed", label: "Detailed", disabled: !hasExecution },
10420
+ { type: "divider", key: "div" },
10421
+ {
10422
+ type: "action",
10423
+ key: "reload",
10424
+ label: /* @__PURE__ */ jsx20(RefreshIcon, { size: 14 }),
10425
+ title: "Reload execution data",
10426
+ disabled: !hasExecution,
10427
+ onClick: () => {
10428
+ if (execution?.execution_id && execution?.authorization) {
10429
+ getExecution(execution.execution_id, execution.authorization);
10430
+ }
10148
10431
  }
10149
- }
10150
- },
10151
- {
10152
- type: "action",
10153
- key: "schedule",
10154
- label: /* @__PURE__ */ jsx20(ScheduleIcon, { size: 14 }),
10155
- title: scheduleDisabledReason ? `Cannot schedule: ${scheduleDisabledReason}` : "Schedule this prompt to run repeatedly on a cron schedule",
10156
- disabled: Boolean(scheduleDisabledReason),
10157
- onClick: () => {
10158
- if (!scheduleDisabledReason && tabBarRef.current) {
10159
- setScheduleAnchor(tabBarRef.current);
10432
+ },
10433
+ {
10434
+ type: "action",
10435
+ key: "schedule",
10436
+ label: /* @__PURE__ */ jsx20(ScheduleIcon, { size: 14 }),
10437
+ title: scheduleDisabledReason ? `Cannot schedule: ${scheduleDisabledReason}` : "Schedule this prompt to run repeatedly on a cron schedule",
10438
+ disabled: Boolean(scheduleDisabledReason),
10439
+ onClick: () => {
10440
+ if (!scheduleDisabledReason && tabBarRef.current) {
10441
+ setScheduleAnchor(tabBarRef.current);
10442
+ }
10160
10443
  }
10161
10444
  }
10162
- }
10163
- ]
10164
- }
10165
- )
10445
+ ]
10446
+ }
10447
+ ),
10448
+ runIsActive && activeTab === "start" && /* @__PURE__ */ jsx20(Tooltip9, { title: "Current agent run is still in progress", children: /* @__PURE__ */ jsx20(
10449
+ CircularProgress4,
10450
+ {
10451
+ size: 16,
10452
+ thickness: 5,
10453
+ sx: { color: "hsl(var(--muted-foreground))" }
10454
+ }
10455
+ ) })
10456
+ ]
10166
10457
  }
10167
10458
  );
10168
10459
  const schedulePopover = /* @__PURE__ */ jsxs17(
@@ -10894,9 +11185,9 @@ var AgentUI = ({
10894
11185
  }
10895
11186
  ) }),
10896
11187
  chosenApps.map((app, i) => {
10897
- const slug = (app.name || "").toLowerCase().replace(/[\s-]+/g, "_");
11188
+ const slug = normalizeAgentAppName(app.name || "");
10898
11189
  const NO_AUTH = /* @__PURE__ */ new Set(["http", "shuffle_tools", "shuffle-tools", "tools", "singul", "core", "webhook", "email"]);
10899
- const needsAuth = !NO_AUTH.has(slug) && !isAppAuthenticated(app.name || "");
11190
+ const needsAuth = !authAppsLoading && !NO_AUTH.has(slug) && !isAppAuthenticated(app.name || "", app.id || null);
10900
11191
  return /* @__PURE__ */ jsx20(
10901
11192
  Tooltip9,
10902
11193
  {
@@ -10957,9 +11248,10 @@ var AgentUI = ({
10957
11248
  ] }) }),
10958
11249
  !hideAppPicker && (() => {
10959
11250
  const NO_AUTH = /* @__PURE__ */ new Set(["http", "shuffle_tools", "shuffle-tools", "tools", "singul", "core", "webhook", "email"]);
11251
+ if (authAppsLoading) return null;
10960
11252
  const unauthed = chosenApps.filter((a) => {
10961
- const slug = (a.name || "").toLowerCase().replace(/[\s-]+/g, "_");
10962
- return !NO_AUTH.has(slug) && !isAppAuthenticated(a.name || "");
11253
+ const slug = normalizeAgentAppName(a.name || "");
11254
+ return !NO_AUTH.has(slug) && !isAppAuthenticated(a.name || "", a.id || null);
10963
11255
  });
10964
11256
  if (unauthed.length === 0) return null;
10965
11257
  return /* @__PURE__ */ jsx20(Box14, { sx: { display: "flex", justifyContent: "center", mt: -0.5 }, children: /* @__PURE__ */ jsxs17(Box14, { sx: {
@@ -11029,7 +11321,7 @@ var AgentUI = ({
11029
11321
  src: app.icon || void 0,
11030
11322
  alt: app.name,
11031
11323
  variant: "rounded",
11032
- onClick: () => navigate(`/apps/${encodeURIComponent((app.name || "").toLowerCase().replace(/\s+/g, "_"))}`),
11324
+ onClick: () => setAuthDrawerApp({ name: app.name, id: app.id || null }),
11033
11325
  sx: {
11034
11326
  bgcolor: "hsl(var(--muted))",
11035
11327
  cursor: "pointer",
@@ -11161,133 +11453,88 @@ var AgentUI = ({
11161
11453
  }
11162
11454
  const pendingAnswered = pendingQuestions.every((q) => questionAnswers[q.question]?.value);
11163
11455
  return /* @__PURE__ */ jsxs17(Fragment7, { children: [
11164
- /* @__PURE__ */ jsxs17(Box14, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
11165
- isRunning ? /* @__PURE__ */ jsx20(CircularProgress4, { size: 16, sx: { color: "hsl(var(--primary))" } }) : status === "FINISHED" ? /* @__PURE__ */ jsx20(CheckCircleIcon4, { size: 18, color: "hsl(142 70% 45%)" }) : /* @__PURE__ */ jsx20(ErrorIcon, { size: 18, color: "hsl(var(--destructive))" }),
11166
- /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.9rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: isRunning ? "Agent is working\u2026" : status === "FINISHED" ? "Run finished" : `Run ${status.toLowerCase()}` }),
11167
- /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
11456
+ /* @__PURE__ */ jsx20(
11457
+ RunFinishedSummary,
11458
+ {
11459
+ status,
11460
+ isRunning,
11461
+ finishAnswer,
11462
+ raw: finishAnswerRaw,
11463
+ onToggleRaw: () => setFinishAnswerRaw((v) => !v),
11168
11464
  decisionCount,
11169
- " step",
11170
- decisionCount === 1 ? "" : "s",
11171
- durationSec != null ? ` \xB7 ${Math.round(durationSec)}s` : ""
11172
- ] }),
11173
- /* @__PURE__ */ jsx20(Box14, { sx: { flexGrow: 1 } })
11174
- ] }),
11175
- pendingAuthApps.map(({ appName, appId, icon }) => {
11176
- const pretty = appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
11177
- return /* @__PURE__ */ jsxs17(
11178
- Box14,
11179
- {
11180
- sx: {
11181
- display: "flex",
11182
- alignItems: "center",
11183
- gap: 1.5,
11184
- p: 1.5,
11185
- borderRadius: 1.5,
11186
- border: "1px solid hsla(var(--severity-medium) / 0.3)",
11187
- bgcolor: "hsla(var(--severity-medium) / 0.08)"
11188
- },
11189
- children: [
11190
- /* @__PURE__ */ jsx20(LockIcon3, { size: 22, color: "hsl(var(--severity-medium))" }),
11191
- /* @__PURE__ */ jsxs17(Box14, { sx: { flex: 1, minWidth: 0 }, children: [
11192
- /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
11193
- pretty,
11194
- " requires authentication"
11195
- ] }),
11196
- /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
11197
- "Connect your ",
11198
- pretty,
11199
- " account so the agent can complete this step, then rerun."
11200
- ] })
11201
- ] }),
11202
- /* @__PURE__ */ jsxs17(
11203
- Button8,
11204
- {
11205
- variant: "outlined",
11206
- size: "small",
11207
- startIcon: /* @__PURE__ */ jsx20(
11208
- Avatar7,
11465
+ durationSec,
11466
+ showMeta: true,
11467
+ children: pendingAuthApps.map(({ appName, appId, icon }) => {
11468
+ const pretty = appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
11469
+ return /* @__PURE__ */ jsxs17(
11470
+ Box14,
11471
+ {
11472
+ sx: {
11473
+ display: "flex",
11474
+ alignItems: "center",
11475
+ gap: 1.5,
11476
+ p: 1.5,
11477
+ borderRadius: 1.5,
11478
+ border: "1px solid hsla(var(--severity-medium) / 0.3)",
11479
+ bgcolor: "hsla(var(--severity-medium) / 0.08)"
11480
+ },
11481
+ children: [
11482
+ /* @__PURE__ */ jsx20(LockIcon3, { size: 22, color: "hsl(var(--severity-medium))" }),
11483
+ /* @__PURE__ */ jsxs17(Box14, { sx: { flex: 1, minWidth: 0 }, children: [
11484
+ /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
11485
+ pretty,
11486
+ " requires authentication"
11487
+ ] }),
11488
+ /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
11489
+ "Connect your ",
11490
+ pretty,
11491
+ " account so the agent can complete this step, then rerun."
11492
+ ] })
11493
+ ] }),
11494
+ /* @__PURE__ */ jsxs17(
11495
+ Button8,
11209
11496
  {
11210
- src: icon || void 0,
11211
- alt: "",
11212
- variant: "rounded",
11497
+ variant: "outlined",
11498
+ size: "small",
11499
+ startIcon: /* @__PURE__ */ jsx20(
11500
+ Avatar7,
11501
+ {
11502
+ src: icon || void 0,
11503
+ alt: "",
11504
+ variant: "rounded",
11505
+ sx: {
11506
+ width: 18,
11507
+ height: 18,
11508
+ borderRadius: 0.5,
11509
+ bgcolor: "hsl(var(--background) / 0.4)",
11510
+ color: "hsl(var(--background))",
11511
+ fontSize: "0.7rem",
11512
+ fontWeight: 700,
11513
+ "& img": { objectFit: "contain" }
11514
+ },
11515
+ children: pretty.charAt(0)
11516
+ }
11517
+ ),
11518
+ onClick: () => setAuthDrawerApp({ name: appName, id: appId }),
11213
11519
  sx: {
11214
- width: 18,
11215
- height: 18,
11216
- borderRadius: 0.5,
11217
- bgcolor: "hsl(var(--background) / 0.4)",
11218
- color: "hsl(var(--background))",
11219
- fontSize: "0.7rem",
11220
- fontWeight: 700,
11221
- "& img": { objectFit: "contain" }
11520
+ height: 36,
11521
+ textTransform: "none",
11522
+ fontWeight: 600
11222
11523
  },
11223
- children: pretty.charAt(0)
11524
+ children: [
11525
+ "Authenticate ",
11526
+ pretty
11527
+ ]
11224
11528
  }
11225
- ),
11226
- onClick: () => setAuthDrawerApp({ name: appName, id: appId }),
11227
- sx: {
11228
- height: 36,
11229
- textTransform: "none",
11230
- fontWeight: 600
11231
- },
11232
- children: [
11233
- "Authenticate ",
11234
- pretty
11235
- ]
11236
- }
11237
- )
11238
- ]
11239
- },
11240
- `auth-${appName}`
11241
- );
11242
- }),
11243
- finishAnswer ? /* @__PURE__ */ jsx20(Box14, { sx: {
11244
- p: 2,
11245
- borderRadius: 1.5,
11246
- border: "1px solid hsl(var(--border))",
11247
- bgcolor: "hsl(var(--background))",
11248
- fontSize: "0.9rem",
11249
- color: "hsl(var(--foreground))",
11250
- "& > *:first-of-type": { mt: 0 },
11251
- "& > *:last-child": { mb: 0 },
11252
- "& p": { my: 1, lineHeight: 1.55 },
11253
- "& h1, & h2, & h3, & h4": { mt: 2, mb: 1, fontWeight: 600, lineHeight: 1.3 },
11254
- "& h1": { fontSize: "1.15rem" },
11255
- "& h2": { fontSize: "1.05rem" },
11256
- "& h3, & h4": { fontSize: "0.95rem" },
11257
- "& ul": { my: 1, pl: 3, listStyleType: "disc", listStylePosition: "outside" },
11258
- "& ol": { my: 1, pl: 3, listStyleType: "decimal", listStylePosition: "outside" },
11259
- "& ul ul": { listStyleType: "circle" },
11260
- "& ul ul ul": { listStyleType: "square" },
11261
- "& li": { my: 0.25, display: "list-item" },
11262
- "& li::marker": { color: "hsl(var(--muted-foreground))" },
11263
- "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
11264
- "& code": {
11265
- px: 0.5,
11266
- py: 0.125,
11267
- borderRadius: 0.5,
11268
- bgcolor: "hsl(var(--muted))",
11269
- fontFamily: '"JetBrains Mono", ui-monospace, monospace',
11270
- fontSize: "0.82em"
11271
- },
11272
- "& pre": {
11273
- p: 1.5,
11274
- my: 1,
11275
- borderRadius: 1,
11276
- bgcolor: "hsl(var(--muted))",
11277
- overflowX: "auto",
11278
- fontSize: "0.82rem"
11279
- },
11280
- "& pre code": { p: 0, bgcolor: "transparent" },
11281
- "& blockquote": {
11282
- borderLeft: "3px solid hsl(var(--border))",
11283
- pl: 1.5,
11284
- my: 1,
11285
- color: "hsl(var(--muted-foreground))"
11286
- },
11287
- "& table": { borderCollapse: "collapse", my: 1, fontSize: "0.85rem" },
11288
- "& th, & td": { border: "1px solid hsl(var(--border))", px: 1, py: 0.5 },
11289
- "& hr": { border: 0, borderTop: "1px solid hsl(var(--border))", my: 1.5 }
11290
- }, children: /* @__PURE__ */ jsx20(Markdown, { remarkPlugins: [remarkGfm4, remarkBreaks], children: normalizeMarkdown(finishAnswer) }) }) : pendingAsk && pendingQuestions.length > 0 ? (() => {
11529
+ )
11530
+ ]
11531
+ },
11532
+ `auth-${appName}`
11533
+ );
11534
+ })
11535
+ }
11536
+ ),
11537
+ !finishAnswer && pendingAsk && pendingQuestions.length > 0 ? (() => {
11291
11538
  const trySimpleSubmit = () => {
11292
11539
  if (agentRequestLoading) return;
11293
11540
  if (!pendingAnswered) {
@@ -11359,7 +11606,7 @@ var AgentUI = ({
11359
11606
  ) })
11360
11607
  ] })
11361
11608
  ] });
11362
- })() : isRunning ? /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "Waiting for the agent to produce the first step." }) : /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "No final answer was returned. Open Detailed to inspect each step." }),
11609
+ })() : !finishAnswer && isRunning ? /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "Waiting for the agent to produce the first step." }) : !finishAnswer ? /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "No final answer was returned. Open Detailed to inspect each step." }) : null,
11363
11610
  !isRunning && /* @__PURE__ */ jsx20(Box14, { children: /* @__PURE__ */ jsx20(
11364
11611
  Button8,
11365
11612
  {
@@ -11405,53 +11652,32 @@ var AgentUI = ({
11405
11652
  getFormUrl,
11406
11653
  runFinished: detailedRunFinished,
11407
11654
  onAuthenticateApp: (name, id) => setAuthDrawerApp({ name, id }),
11655
+ onRefreshAuthenticatedApps: () => {
11656
+ loadAuthenticatedApps();
11657
+ },
11408
11658
  isAppAuthenticated,
11659
+ authAppsLoading,
11409
11660
  highlight: highlightedIndex === i
11410
11661
  },
11411
11662
  i
11412
11663
  )),
11413
- detailedRunFinished && /* @__PURE__ */ jsxs17(Box14, { sx: {
11664
+ detailedRunFinished && /* @__PURE__ */ jsx20(Box14, { sx: {
11414
11665
  borderTop: "1px solid hsl(var(--border))",
11415
11666
  p: 2.5,
11416
11667
  display: "flex",
11417
11668
  flexDirection: "column",
11418
11669
  gap: 1.5,
11419
11670
  bgcolor: "hsl(var(--muted) / 0.2)"
11420
- }, children: [
11421
- /* @__PURE__ */ jsxs17(Box14, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
11422
- detailedStatus === "FINISHED" ? /* @__PURE__ */ jsx20(CheckCircleIcon4, { size: 18, color: "hsl(142 70% 45%)" }) : /* @__PURE__ */ jsx20(ErrorIcon, { size: 18, color: "hsl(var(--destructive))" }),
11423
- /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.9rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: detailedStatus === "FINISHED" ? "Run finished" : `Run ${detailedStatus.toLowerCase()}` })
11424
- ] }),
11425
- finishAnswer && /* @__PURE__ */ jsx20(Box14, { sx: {
11426
- p: 2,
11427
- borderRadius: 1.5,
11428
- border: "1px solid hsl(var(--border))",
11429
- bgcolor: "hsl(var(--background))",
11430
- fontSize: "0.9rem",
11431
- color: "hsl(var(--foreground))",
11432
- "& > *:first-of-type": { mt: 0 },
11433
- "& > *:last-child": { mb: 0 },
11434
- "& p": { my: 1, lineHeight: 1.55 },
11435
- "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
11436
- "& code": {
11437
- px: 0.5,
11438
- py: 0.125,
11439
- borderRadius: 0.5,
11440
- bgcolor: "hsl(var(--muted))",
11441
- fontFamily: '"JetBrains Mono", ui-monospace, monospace',
11442
- fontSize: "0.82em"
11443
- },
11444
- "& pre": {
11445
- p: 1.5,
11446
- my: 1,
11447
- borderRadius: 1,
11448
- bgcolor: "hsl(var(--muted))",
11449
- overflowX: "auto",
11450
- fontSize: "0.82rem"
11451
- },
11452
- "& pre code": { p: 0, bgcolor: "transparent" }
11453
- }, children: /* @__PURE__ */ jsx20(Markdown, { remarkPlugins: [remarkGfm4, remarkBreaks], children: normalizeMarkdown(finishAnswer) }) })
11454
- ] })
11671
+ }, children: /* @__PURE__ */ jsx20(
11672
+ RunFinishedSummary,
11673
+ {
11674
+ status: detailedStatus,
11675
+ isRunning: false,
11676
+ finishAnswer,
11677
+ raw: finishAnswerRaw,
11678
+ onToggleRaw: () => setFinishAnswerRaw((v) => !v)
11679
+ }
11680
+ ) })
11455
11681
  ] }) });
11456
11682
  })(),
11457
11683
  finishDecisionId && /* @__PURE__ */ jsx20(Box14, { sx: { mt: 3, display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsxs17(Box14, { sx: { width: "100%", maxWidth: 640 }, children: [
@@ -11555,6 +11781,9 @@ var AgentUI = ({
11555
11781
  {
11556
11782
  open: !!authDrawerApp,
11557
11783
  onClose: () => setAuthDrawerApp(null),
11784
+ onRefresh: () => {
11785
+ loadAuthenticatedApps();
11786
+ },
11558
11787
  appName: authDrawerApp?.name || null,
11559
11788
  appId: authDrawerApp?.id || null,
11560
11789
  activeOrgId: orgId || null,
@@ -11685,7 +11914,7 @@ var UsageBar = ({
11685
11914
  };
11686
11915
 
11687
11916
  // components/LocalLLMConfig.tsx
11688
- import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
11917
+ import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
11689
11918
  import { createElement as createElement2 } from "react";
11690
11919
  var OPENAI_APP_NAME = "OpenAI";
11691
11920
  var OPENAI_APP_ID = "5d19dd82517870c68d40cacad9b5ca91";
@@ -11712,15 +11941,16 @@ var OPENAI_ALGOLIA_APP = {
11712
11941
  };
11713
11942
  var ENDPOINT_PRESETS = [
11714
11943
  { label: SHUFFLE_AI_PRESET, url: "" },
11715
- { label: "OpenAI", url: "https://api.openai.com/v1" },
11716
- { label: "Anthropic", url: "https://api.anthropic.com/v1/" },
11717
- { label: "Google Gemini", url: "https://generativelanguage.googleapis.com/v1beta/openai/" },
11718
- { label: "Mistral", url: "https://api.mistral.ai/v1" },
11719
- { label: "Groq", url: "https://api.groq.com/openai/v1" },
11720
- { label: "Together AI", url: "https://api.together.xyz/v1" },
11721
- { label: "OpenRouter", url: "https://openrouter.ai/api/v1" },
11722
- { label: "Ollama (localhost)", url: "http://localhost:11434/v1" },
11723
- { label: "LM Studio (localhost)", url: "http://localhost:1234/v1" },
11944
+ { label: "OpenAI", url: "https://api.openai.com/v1", apiKeyUrl: "https://platform.openai.com/api-keys", apiKeyHint: "Create a key under API keys in the OpenAI platform dashboard." },
11945
+ { label: "Anthropic", url: "https://api.anthropic.com/v1/", apiKeyUrl: "https://console.anthropic.com/settings/keys", apiKeyHint: "Generate a key under Settings \u2192 API Keys in the Anthropic Console." },
11946
+ { label: "Google Gemini", url: "https://generativelanguage.googleapis.com/v1beta/openai/", apiKeyUrl: "https://aistudio.google.com/app/apikey", apiKeyHint: "Create a key in Google AI Studio under Get API key." },
11947
+ { label: "Mistral", url: "https://api.mistral.ai/v1", apiKeyUrl: "https://console.mistral.ai/api-keys/", apiKeyHint: "Create a key under API Keys in the Mistral Console." },
11948
+ { label: "Groq", url: "https://api.groq.com/openai/v1", apiKeyUrl: "https://console.groq.com/keys", apiKeyHint: "Create a key under API Keys in the Groq Console." },
11949
+ { label: "DeepSeek", url: "https://api.deepseek.com/v1", apiKeyUrl: "https://platform.deepseek.com/api_keys", apiKeyHint: "Create a key under API Keys in the DeepSeek platform." },
11950
+ { label: "Together AI", url: "https://api.together.xyz/v1", apiKeyUrl: "https://api.together.ai/settings/api-keys", apiKeyHint: "Create a key under Settings \u2192 API Keys in Together AI." },
11951
+ { label: "OpenRouter", url: "https://openrouter.ai/api/v1", apiKeyUrl: "https://openrouter.ai/keys", apiKeyHint: "Create a key under Keys in your OpenRouter dashboard." },
11952
+ { label: "Ollama (localhost)", url: "http://localhost:11434/v1", apiKeyHint: "Local Ollama does not require an API key \u2014 any non-empty value works." },
11953
+ { label: "LM Studio (localhost)", url: "http://localhost:1234/v1", apiKeyHint: "Local LM Studio does not require an API key \u2014 any non-empty value works." },
11724
11954
  { label: CUSTOM_PRESET, url: "" }
11725
11955
  ];
11726
11956
  var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serverside, theme, colorMode }) => {
@@ -11879,12 +12109,29 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
11879
12109
  }
11880
12110
  )
11881
12111
  ] }),
11882
- !compact && /* @__PURE__ */ jsx22(Box16, { sx: { px: 2.5, py: 2, borderRadius: 2, border: "1px solid hsl(var(--border))", bgcolor: "hsl(var(--muted) / 0.3)" }, children: /* @__PURE__ */ jsxs19(Typography15, { sx: { fontSize: "0.8rem", color: "hsl(var(--muted-foreground))", lineHeight: 1.5 }, children: [
11883
- isShuffleAI ? "Using Shuffle AI. No configuration is required. Pick another provider above to use your own endpoint." : "Configure an OpenAI-compatible endpoint for agent operations. Credentials are saved through the app authentication system.",
11884
- " ",
11885
- /* @__PURE__ */ jsx22(Box16, { component: "a", href: "https://shuffler.io/docs/AI#using-self-hosted-ai-models", target: "_blank", rel: "noopener noreferrer", sx: { color: "hsl(var(--primary))", textDecoration: "underline" }, children: "Read the docs" }),
11886
- "."
11887
- ] }) }),
12112
+ !compact && (() => {
12113
+ const preset = ENDPOINT_PRESETS.find((p) => p.label === effectivePreset);
12114
+ const hasProviderDocs = !!preset && (!!preset.apiKeyUrl || !!preset.apiKeyHint);
12115
+ return /* @__PURE__ */ jsx22(Box16, { sx: { px: 2.5, py: 2, borderRadius: 2, border: "1px solid hsl(var(--border))", bgcolor: "hsl(var(--muted) / 0.3)" }, children: /* @__PURE__ */ jsx22(Typography15, { sx: { fontSize: "0.8rem", color: "hsl(var(--muted-foreground))", lineHeight: 1.5 }, children: isShuffleAI ? /* @__PURE__ */ jsxs19(Fragment8, { children: [
12116
+ "Using Shuffle AI. No configuration is required. Pick another provider above to use your own endpoint.",
12117
+ " ",
12118
+ /* @__PURE__ */ jsx22(Box16, { component: "a", href: "https://shuffler.io/docs/AI#using-self-hosted-ai-models", target: "_blank", rel: "noopener noreferrer", sx: { color: "hsl(var(--primary))", textDecoration: "underline" }, children: "Read the docs" }),
12119
+ "."
12120
+ ] }) : hasProviderDocs ? /* @__PURE__ */ jsxs19(Fragment8, { children: [
12121
+ preset.apiKeyHint,
12122
+ " ",
12123
+ preset.apiKeyUrl && /* @__PURE__ */ jsxs19(Box16, { component: "a", href: preset.apiKeyUrl, target: "_blank", rel: "noopener noreferrer", sx: { color: "hsl(var(--primary))", textDecoration: "underline" }, children: [
12124
+ "Get your ",
12125
+ preset.label,
12126
+ " API key \u2192"
12127
+ ] })
12128
+ ] }) : /* @__PURE__ */ jsxs19(Fragment8, { children: [
12129
+ "Configure an OpenAI-compatible endpoint for agent operations. Credentials are saved through the app authentication system.",
12130
+ " ",
12131
+ /* @__PURE__ */ jsx22(Box16, { component: "a", href: "https://shuffler.io/docs/AI#using-self-hosted-ai-models", target: "_blank", rel: "noopener noreferrer", sx: { color: "hsl(var(--primary))", textDecoration: "underline" }, children: "Read the docs" }),
12132
+ "."
12133
+ ] }) }) });
12134
+ })(),
11888
12135
  isShuffleAI && /* @__PURE__ */ jsxs19(Box16, { sx: { display: "flex", flexDirection: "column", gap: 0.75, mt: 0.5, width: "100%" }, children: [
11889
12136
  /* @__PURE__ */ jsx22(UsageBar, { label: "App runs", usage: appRunUsage, limit: appRunLimit, unit: "runs", actionLabel: "Upgrade", actionHref: "https://shuffler.io/pricing" }),
11890
12137
  /* @__PURE__ */ jsx22(UsageBar, { label: "Agent tokens", usage: agentTokenUsage, limit: agentTokenLimit, unit: "tokens", actionLabel: "Upgrade", actionHref: "https://shuffler.io/pricing" })
@@ -12167,15 +12414,18 @@ var AgentRunDrawer_default = AgentRunDrawer;
12167
12414
 
12168
12415
  // components/AgentActivityList.tsx
12169
12416
  import { useCallback as useCallback9, useEffect as useEffect14, useRef as useRef11, useState as useState15 } from "react";
12417
+ import { useNavigate as useNavigate2 } from "react-router-dom";
12170
12418
  import {
12419
+ Avatar as Avatar8,
12420
+ AvatarGroup as AvatarGroup2,
12171
12421
  Box as Box18,
12172
12422
  Button as Button10,
12173
- Chip as Chip8,
12174
12423
  CircularProgress as CircularProgress5,
12175
12424
  Dialog as Dialog3,
12176
12425
  DialogActions as DialogActions2,
12177
12426
  DialogContent as DialogContent3,
12178
12427
  DialogTitle as DialogTitle3,
12428
+ Divider as Divider3,
12179
12429
  InputAdornment,
12180
12430
  MenuItem as MenuItem3,
12181
12431
  Select as Select3,
@@ -12189,6 +12439,7 @@ import {
12189
12439
  CheckCircle,
12190
12440
  Clock,
12191
12441
  FileText,
12442
+ GitBranch,
12192
12443
  Globe,
12193
12444
  Loader2,
12194
12445
  Server as Server2,
@@ -12484,7 +12735,7 @@ var stopAgentSchedule = async (workflowId, params = {}) => {
12484
12735
 
12485
12736
  // components/AgentActivityList.tsx
12486
12737
  import { Pencil, StopCircle, AlertTriangle as AlertTriangle2 } from "lucide-react";
12487
- import { Fragment as Fragment8, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
12738
+ import { Fragment as Fragment9, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
12488
12739
  var STATUS_CONFIG = {
12489
12740
  FINISHED: { icon: /* @__PURE__ */ jsx24(CheckCircle, { size: 16 }), color: "hsl(var(--severity-low, 142 71% 45%))", label: "Completed" },
12490
12741
  SUCCESS: { icon: /* @__PURE__ */ jsx24(CheckCircle, { size: 16 }), color: "hsl(var(--severity-low, 142 71% 45%))", label: "Completed" },
@@ -12552,21 +12803,110 @@ var getTimeAgo = (dateStr) => {
12552
12803
  return dateStr;
12553
12804
  }
12554
12805
  };
12555
- var getRunTitle = (run) => {
12556
- if (run.workflow?.name) return run.workflow.name;
12557
- if (run.execution_argument) {
12558
- try {
12559
- const parsed = JSON.parse(run.execution_argument);
12560
- if (parsed.title) return parsed.title;
12561
- if (parsed.action) return parsed.action;
12562
- if (parsed.name) return parsed.name;
12563
- } catch {
12564
- const clean = run.execution_argument.replace(/[{}"]/g, "").trim();
12565
- if (clean.length > 0 && clean.length < 80) return clean;
12806
+ var PROMPT_KEYS = [
12807
+ "original_input",
12808
+ "originalinput",
12809
+ "input",
12810
+ "prompt",
12811
+ "user_input",
12812
+ "userinput",
12813
+ "user_prompt",
12814
+ "userprompt",
12815
+ "question",
12816
+ "query",
12817
+ "message",
12818
+ "text",
12819
+ "content",
12820
+ "task",
12821
+ "instruction",
12822
+ "instructions"
12823
+ ];
12824
+ var deepFindPrompt = (value, depth = 0) => {
12825
+ if (value == null || depth > 6) return null;
12826
+ if (typeof value === "string") {
12827
+ const s = value.trim();
12828
+ if (s.startsWith("{") && s.endsWith("}") || s.startsWith("[") && s.endsWith("]")) {
12829
+ try {
12830
+ return deepFindPrompt(JSON.parse(s), depth + 1);
12831
+ } catch {
12832
+ }
12833
+ }
12834
+ return null;
12835
+ }
12836
+ if (Array.isArray(value)) {
12837
+ for (const item of value) {
12838
+ const hit = deepFindPrompt(item, depth + 1);
12839
+ if (hit) return hit;
12840
+ }
12841
+ return null;
12842
+ }
12843
+ if (typeof value === "object") {
12844
+ const obj = value;
12845
+ for (const key of Object.keys(obj)) {
12846
+ if (PROMPT_KEYS.includes(key.toLowerCase())) {
12847
+ const v = obj[key];
12848
+ if (typeof v === "string" && v.trim()) return v.trim();
12849
+ const nested = deepFindPrompt(v, depth + 1);
12850
+ if (nested) return nested;
12851
+ }
12852
+ }
12853
+ for (const key of Object.keys(obj)) {
12854
+ if (PROMPT_KEYS.includes(key.toLowerCase())) continue;
12855
+ const hit = deepFindPrompt(obj[key], depth + 1);
12856
+ if (hit) return hit;
12857
+ }
12858
+ }
12859
+ return null;
12860
+ };
12861
+ var tryParseJson = (s) => {
12862
+ if (typeof s !== "string") return s;
12863
+ const trimmed = s.trim();
12864
+ if (!trimmed) return null;
12865
+ try {
12866
+ return JSON.parse(trimmed);
12867
+ } catch {
12868
+ return trimmed;
12869
+ }
12870
+ };
12871
+ var getRunPrompt = (run) => {
12872
+ const results = Array.isArray(run.results) ? run.results : null;
12873
+ if (results) {
12874
+ const agentResult = results.find((r) => r?.action?.app_name === "AI Agent");
12875
+ if (agentResult?.result) {
12876
+ const hit = deepFindPrompt(tryParseJson(agentResult.result));
12877
+ if (hit) return hit;
12878
+ }
12879
+ for (const r of results) {
12880
+ if (r === agentResult) continue;
12881
+ const hit = deepFindPrompt(tryParseJson(r?.result));
12882
+ if (hit) return hit;
12566
12883
  }
12567
12884
  }
12885
+ if (run.result) {
12886
+ const hit = deepFindPrompt(tryParseJson(run.result));
12887
+ if (hit) return hit;
12888
+ }
12889
+ if (run.execution_argument) {
12890
+ const parsed = tryParseJson(run.execution_argument);
12891
+ const hit = deepFindPrompt(parsed);
12892
+ if (hit) return hit;
12893
+ if (typeof parsed === "string" && parsed.length < 240) return parsed;
12894
+ }
12895
+ return null;
12896
+ };
12897
+ var getRunTitle = (run) => {
12898
+ const prompt = getRunPrompt(run);
12899
+ if (prompt) {
12900
+ const oneLine = prompt.replace(/\s+/g, " ").trim();
12901
+ return oneLine.length > 80 ? oneLine.slice(0, 80) + "\u2026" : oneLine;
12902
+ }
12903
+ if (run.workflow?.name) return run.workflow.name;
12568
12904
  return `Execution ${run.execution_id?.slice(0, 8) || "\u2014"}`;
12569
12905
  };
12906
+ var getDecisionCount = (run) => {
12907
+ if (Array.isArray(run.decisions)) return run.decisions.length;
12908
+ return 0;
12909
+ };
12570
12910
  var getRunSubtitle = (run) => {
12571
12911
  if (run.result) {
12572
12912
  try {
@@ -12584,30 +12924,82 @@ var getRunSubtitle = (run) => {
12584
12924
  }
12585
12925
  return run.execution_source || "Agent execution";
12586
12926
  };
12927
+ var normalizeResultStatus = (s) => {
12928
+ const v = (s || "").toUpperCase();
12929
+ if (v === "SUCCESS" || v === "FINISHED") return "success";
12930
+ if (v === "FAILURE" || v === "FAILED" || v === "ABORTED") return "failure";
12931
+ if (v === "WAITING" || v === "SKIPPED") return "waiting";
12932
+ return "unknown";
12933
+ };
12587
12934
  var getRunTools = (run) => {
12588
- const out = /* @__PURE__ */ new Set();
12589
- const add = (v) => {
12590
- if (!v) return;
12591
- const s = String(v).trim();
12592
- if (!s) return;
12593
- if (/^(ai\s*agent|shuffle\s*agent|shuffle_agent)$/i.test(s)) return;
12594
- out.add(s);
12935
+ const map = /* @__PURE__ */ new Map();
12936
+ const ids = /* @__PURE__ */ new Map();
12937
+ const skip = (s) => /^(ai\s*agent|shuffle\s*agent|shuffle_agent)$/i.test(s);
12938
+ const rank = { failure: 3, waiting: 2, success: 1, unknown: 0 };
12939
+ const merge2 = (name, status, id) => {
12940
+ if (!name) return;
12941
+ const s = String(name).trim();
12942
+ if (!s || skip(s)) return;
12943
+ const next = status || "unknown";
12944
+ const prev = map.get(s);
12945
+ if (!prev || rank[next] > rank[prev]) map.set(s, next);
12946
+ if (id && !ids.has(s)) ids.set(s, id);
12595
12947
  };
12596
- (run.results || []).forEach((r) => {
12597
- add(r?.action?.app_name);
12598
- if (!r?.action?.app_name) add(r?.action?.label);
12599
- });
12600
- (run.decisions || []).forEach((d) => {
12601
- add(typeof d?.tool === "string" ? d.tool : void 0);
12602
- });
12603
- return Array.from(out).slice(0, 6);
12948
+ const allowed = run.allowed_actions;
12949
+ if (Array.isArray(allowed) && allowed.length > 0) {
12950
+ for (const entry of allowed) {
12951
+ if (typeof entry !== "string") continue;
12952
+ const parts = entry.split(":");
12953
+ if (parts.length < 3 || parts[0] !== "app") continue;
12954
+ const id = parts[1];
12955
+ const name = parts.slice(2).join(":");
12956
+ merge2(name, "unknown", id);
12957
+ }
12958
+ const normalize = (s) => s.toLowerCase().replace(/[\s_-]+/g, "_");
12959
+ const known = /* @__PURE__ */ new Map();
12960
+ for (const real of map.keys()) known.set(normalize(real), real);
12961
+ const apply = (name, status) => {
12962
+ if (!name) return;
12963
+ const hit = known.get(normalize(name));
12964
+ if (hit) merge2(hit, status);
12965
+ };
12966
+ (run.results || []).forEach((r) => {
12967
+ apply(r?.action?.app_name || r?.action?.label, normalizeResultStatus(r?.status));
12968
+ });
12969
+ (run.decisions || []).forEach((d) => {
12970
+ if (typeof d?.tool === "string") apply(d.tool, normalizeResultStatus(d?.status));
12971
+ });
12972
+ } else {
12973
+ (run.results || []).forEach((r) => {
12974
+ merge2(r?.action?.app_name || r?.action?.label, normalizeResultStatus(r?.status));
12975
+ });
12976
+ (run.decisions || []).forEach((d) => {
12977
+ if (typeof d?.tool === "string") merge2(d.tool, normalizeResultStatus(d?.status));
12978
+ });
12979
+ }
12980
+ return Array.from(map.entries()).slice(0, 6).map(([name, status]) => ({ name, status, id: ids.get(name) }));
12981
+ };
12982
+ var TOOL_STATUS_RING = {
12983
+ success: "hsl(var(--severity-low, 142 71% 45%))",
12984
+ failure: "hsl(var(--severity-critical, 0 72% 55%))",
12985
+ waiting: "hsl(var(--severity-medium, 38 92% 50%))",
12986
+ unknown: "hsl(var(--border))"
12987
+ };
12988
+ var TOOL_STATUS_LABEL = {
12989
+ success: "ran successfully",
12990
+ failure: "failed",
12991
+ waiting: "needs input",
12992
+ unknown: "used"
12604
12993
  };
12605
- var AgentRunRow = ({ run, onClick, sx }) => {
12994
+ var normToolKey = (s) => s.toLowerCase().replace(/[\s_\-]+/g, "_");
12995
+ var AgentRunRow = ({ run, onClick, sx, appIcons, onAppClick }) => {
12996
+ const navigate = useNavigate2();
12606
12997
  const statusKey = getEffectiveStatus(run);
12607
12998
  const cfg = STATUS_CONFIG[statusKey] || STATUS_CONFIG.WAITING;
12608
12999
  const iconColor = getRunIconColor(run);
12609
13000
  const duration = formatDuration(run);
12610
13001
  const tools = getRunTools(run);
13002
+ const decisionCount = getDecisionCount(run);
12611
13003
  return /* @__PURE__ */ jsxs21(
12612
13004
  Box18,
12613
13005
  {
@@ -12682,45 +13074,83 @@ var AgentRunRow = ({ run, onClick, sx }) => {
12682
13074
  ),
12683
13075
  /* @__PURE__ */ jsxs21(Box18, { sx: { display: "flex", alignItems: "center", gap: 1, mt: 0.5 }, children: [
12684
13076
  /* @__PURE__ */ jsx24(Typography17, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.7 }, children: run.started_at ? getTimeAgo(run.started_at) : "\u2014" }),
12685
- duration && /* @__PURE__ */ jsxs21(Fragment8, { children: [
13077
+ duration && /* @__PURE__ */ jsxs21(Fragment9, { children: [
12686
13078
  /* @__PURE__ */ jsx24(Typography17, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
12687
13079
  /* @__PURE__ */ jsx24(Typography17, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.7 }, children: duration })
13080
+ ] }),
13081
+ decisionCount > 0 && /* @__PURE__ */ jsxs21(Fragment9, { children: [
13082
+ /* @__PURE__ */ jsx24(Typography17, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
13083
+ /* @__PURE__ */ jsxs21(Box18, { sx: { display: "inline-flex", alignItems: "center", gap: 0.5, color: "hsl(var(--muted-foreground))", opacity: 0.7 }, children: [
13084
+ /* @__PURE__ */ jsx24(GitBranch, { size: 11 }),
13085
+ /* @__PURE__ */ jsxs21(Typography17, { sx: { fontSize: "0.72rem", color: "inherit" }, children: [
13086
+ decisionCount,
13087
+ " ",
13088
+ decisionCount === 1 ? "decision" : "decisions"
13089
+ ] })
13090
+ ] })
12688
13091
  ] })
12689
13092
  ] })
12690
13093
  ] }),
12691
13094
  tools.length > 0 && /* @__PURE__ */ jsx24(
12692
13095
  Box18,
12693
13096
  {
13097
+ onClick: (e) => e.stopPropagation(),
12694
13098
  sx: {
12695
13099
  display: { xs: "none", sm: "flex" },
12696
13100
  alignItems: "center",
12697
- gap: 0.5,
12698
- flexWrap: "wrap",
12699
- justifyContent: "flex-end",
12700
- maxWidth: 220,
12701
- flexShrink: 0
13101
+ flexShrink: 0,
13102
+ ml: 1
12702
13103
  },
12703
- children: tools.map((t) => /* @__PURE__ */ jsx24(Tooltip12, { title: t, arrow: true, children: /* @__PURE__ */ jsx24(
12704
- Chip8,
13104
+ children: /* @__PURE__ */ jsx24(
13105
+ AvatarGroup2,
12705
13106
  {
12706
- label: t,
12707
- size: "small",
13107
+ max: 5,
12708
13108
  sx: {
12709
- height: 20,
12710
- fontSize: "0.68rem",
12711
- maxWidth: 120,
12712
- bgcolor: "hsla(var(--muted) / 0.5)",
12713
- color: "hsl(var(--muted-foreground))",
12714
- border: "1px solid hsl(var(--border))",
12715
- "& .MuiChip-label": {
12716
- px: 0.75,
12717
- overflow: "hidden",
12718
- textOverflow: "ellipsis",
12719
- whiteSpace: "nowrap"
13109
+ "& .MuiAvatar-root": {
13110
+ width: 28,
13111
+ height: 28,
13112
+ fontSize: "0.7rem",
13113
+ borderColor: "hsl(var(--border))",
13114
+ bgcolor: "hsl(var(--muted))",
13115
+ color: "hsl(var(--muted-foreground))"
12720
13116
  }
12721
- }
13117
+ },
13118
+ children: tools.map((t) => {
13119
+ const icon = appIcons?.[normToolKey(t.name)];
13120
+ const label = t.name.replace(/_/g, " ");
13121
+ const slug = t.name.toLowerCase().replace(/\s+/g, "_");
13122
+ const ring = TOOL_STATUS_RING[t.status];
13123
+ return /* @__PURE__ */ jsx24(Tooltip12, { title: `${label} \u2014 ${TOOL_STATUS_LABEL[t.status]}`, arrow: true, children: /* @__PURE__ */ jsx24(
13124
+ Avatar8,
13125
+ {
13126
+ src: icon || void 0,
13127
+ alt: label,
13128
+ variant: "rounded",
13129
+ onClick: (e) => {
13130
+ e.stopPropagation();
13131
+ if (onAppClick) {
13132
+ onAppClick({ id: t.id, name: t.name });
13133
+ } else {
13134
+ navigate(`/apps/${encodeURIComponent(slug)}`);
13135
+ }
13136
+ },
13137
+ sx: {
13138
+ cursor: "pointer",
13139
+ borderColor: `${ring} !important`,
13140
+ borderWidth: t.status === "unknown" ? "1px" : "2px",
13141
+ borderStyle: "solid",
13142
+ transition: "transform 0.15s ease, border-color 0.15s ease",
13143
+ "&:hover": {
13144
+ transform: "scale(1.08)",
13145
+ borderColor: "hsl(var(--primary)) !important"
13146
+ }
13147
+ },
13148
+ children: label.charAt(0).toUpperCase()
13149
+ }
13150
+ ) }, t.name);
13151
+ })
12722
13152
  }
12723
- ) }, t))
13153
+ )
12724
13154
  }
12725
13155
  )
12726
13156
  ]
@@ -12747,8 +13177,12 @@ var AgentActivityList = ({
12747
13177
  className,
12748
13178
  sx,
12749
13179
  toolbarSx,
12750
- rowSx
13180
+ rowSx,
13181
+ globalUrl,
13182
+ theme,
13183
+ colorMode
12751
13184
  }) => {
13185
+ const [appDrawer, setAppDrawer] = useState15(null);
12752
13186
  const [runs, setRuns] = useState15([]);
12753
13187
  const [cursor, setCursor] = useState15("");
12754
13188
  const [hasMore, setHasMore] = useState15(false);
@@ -12761,6 +13195,8 @@ var AgentActivityList = ({
12761
13195
  const [workflowFilter, setWorkflowFilter] = useState15("");
12762
13196
  const [stopOpen, setStopOpen] = useState15(false);
12763
13197
  const [stopLoading, setStopLoading] = useState15(false);
13198
+ const [appIcons, setAppIcons] = useState15({});
13199
+ const [enrichedRuns, setEnrichedRuns] = useState15({});
12764
13200
  const debounceRef = useRef11();
12765
13201
  const selectedAgentWorkflow = agentWorkflows.find((w) => w.id === workflowFilter) || null;
12766
13202
  const openEditPrompt = useCallback9(async () => {
@@ -12842,10 +13278,137 @@ var AgentActivityList = ({
12842
13278
  cancelled = true;
12843
13279
  };
12844
13280
  }, [apiKey, apiBaseUrl, orgId]);
13281
+ useEffect14(() => {
13282
+ let cancelled = false;
13283
+ fetchAppsViaApiConfig().then((apps) => {
13284
+ if (cancelled || !Array.isArray(apps)) return;
13285
+ const map = {};
13286
+ for (const a of apps) {
13287
+ const name = a?.name;
13288
+ const img = a?.large_image || a?.image_url || a?.image;
13289
+ if (!name || !img) continue;
13290
+ map[normToolKey(name)] = img;
13291
+ }
13292
+ setAppIcons(map);
13293
+ }).catch(() => {
13294
+ });
13295
+ return () => {
13296
+ cancelled = true;
13297
+ };
13298
+ }, []);
13299
+ useEffect14(() => {
13300
+ if (!runs.length) return;
13301
+ let cancelled = false;
13302
+ const buildPatchFromRun = (r) => {
13303
+ const results = Array.isArray(r.results) ? r.results : null;
13304
+ if (!results || results.length === 0) return null;
13305
+ const agentResult = results.find((x) => x?.action?.app_name === "AI Agent");
13306
+ let decisions = Array.isArray(r.decisions) ? r.decisions : void 0;
13307
+ let originalInput;
13308
+ let allowedActions;
13309
+ if (agentResult?.result) {
13310
+ try {
13311
+ const parsed = JSON.parse(agentResult.result);
13312
+ if (!decisions && Array.isArray(parsed?.decisions)) decisions = parsed.decisions;
13313
+ if (typeof parsed?.original_input === "string") originalInput = parsed.original_input;
13314
+ if (Array.isArray(parsed?.allowed_actions)) allowedActions = parsed.allowed_actions;
13315
+ } catch {
13316
+ }
13317
+ }
13318
+ const hasPrompt = !!r.execution_argument || !!originalInput || !!agentResult?.result;
13319
+ if (!decisions || !hasPrompt) return null;
13320
+ const patch = {
13321
+ results,
13322
+ execution_argument: r.execution_argument,
13323
+ result: agentResult?.result ?? r.result,
13324
+ decisions,
13325
+ allowed_actions: allowedActions
13326
+ };
13327
+ if (originalInput && !patch.execution_argument) {
13328
+ patch.execution_argument = JSON.stringify({ original_input: originalInput });
13329
+ }
13330
+ return patch;
13331
+ };
13332
+ const nativePatches = {};
13333
+ const needsFetch = [];
13334
+ for (const r of runs) {
13335
+ const id = r.execution_id;
13336
+ if (!id || enrichedRuns[id]) continue;
13337
+ const native = buildPatchFromRun(r);
13338
+ if (native) {
13339
+ nativePatches[id] = native;
13340
+ } else {
13341
+ needsFetch.push(id);
13342
+ }
13343
+ }
13344
+ if (Object.keys(nativePatches).length > 0) {
13345
+ setEnrichedRuns((prev) => ({ ...prev, ...nativePatches }));
13346
+ }
13347
+ if (needsFetch.length === 0) return;
13348
+ const CONCURRENCY = 4;
13349
+ let i = 0;
13350
+ const fetchOne = async (executionId) => {
13351
+ try {
13352
+ const resp = await fetch(getApiUrl("/api/v1/streams/results"), {
13353
+ method: "POST",
13354
+ credentials: "include",
13355
+ headers: {
13356
+ "Content-Type": "application/json",
13357
+ ...apiKey ? { Authorization: `Bearer ${apiKey}` } : getAuthHeader(),
13358
+ ...orgId ? { "Org-Id": orgId } : {}
13359
+ },
13360
+ body: JSON.stringify({ execution_id: executionId, authorization: executionId })
13361
+ });
13362
+ if (!resp.ok || cancelled) return;
13363
+ const json = await resp.json().catch(() => null);
13364
+ if (!json || cancelled) return;
13365
+ let decisions;
13366
+ let originalInput;
13367
+ let allowedActions;
13368
+ const agentResult = Array.isArray(json.results) ? json.results.find((r) => r?.action?.app_name === "AI Agent") : null;
13369
+ if (agentResult?.result) {
13370
+ try {
13371
+ const parsed = JSON.parse(agentResult.result);
13372
+ if (Array.isArray(parsed?.decisions)) decisions = parsed.decisions;
13373
+ if (typeof parsed?.original_input === "string") originalInput = parsed.original_input;
13374
+ if (Array.isArray(parsed?.allowed_actions)) allowedActions = parsed.allowed_actions;
13375
+ } catch {
13376
+ }
13377
+ }
13378
+ const patch = {
13379
+ results: json.results,
13380
+ execution_argument: json.execution_argument,
13381
+ result: agentResult?.result,
13382
+ decisions,
13383
+ allowed_actions: allowedActions
13384
+ };
13385
+ if (originalInput && !patch.execution_argument) {
13386
+ patch.execution_argument = JSON.stringify({ original_input: originalInput });
13387
+ }
13388
+ setEnrichedRuns((prev) => ({ ...prev, [executionId]: patch }));
13389
+ } catch {
13390
+ }
13391
+ };
13392
+ const workers = Array.from({ length: Math.min(CONCURRENCY, needsFetch.length) }, async () => {
13393
+ while (!cancelled && i < needsFetch.length) {
13394
+ const id = needsFetch[i++];
13395
+ await fetchOne(id);
13396
+ }
13397
+ });
13398
+ Promise.all(workers).catch(() => {
13399
+ });
13400
+ return () => {
13401
+ cancelled = true;
13402
+ };
13403
+ }, [runs, apiKey, orgId]);
13404
+ const mergedRuns = runs.map((r) => {
13405
+ const patch = r.execution_id ? enrichedRuns[r.execution_id] : void 0;
13406
+ return patch ? { ...r, ...patch } : r;
13407
+ });
12845
13408
  const loadMore = useCallback9(() => {
12846
13409
  if (cursor && !isLoading) fetchRuns(true, cursor);
12847
13410
  }, [cursor, isLoading, fetchRuns]);
12848
- const filteredRuns = debouncedQuery ? runs.filter((r) => {
13411
+ const filteredRuns = debouncedQuery ? mergedRuns.filter((r) => {
12849
13412
  const hay = [
12850
13413
  getRunTitle(r),
12851
13414
  getRunSubtitle(r),
@@ -12854,7 +13417,7 @@ var AgentActivityList = ({
12854
13417
  r.status
12855
13418
  ].filter(Boolean).join(" ").toLowerCase();
12856
13419
  return hay.includes(debouncedQuery.toLowerCase());
12857
- }) : runs;
13420
+ }) : mergedRuns;
12858
13421
  return /* @__PURE__ */ jsxs21(
12859
13422
  Box18,
12860
13423
  {
@@ -12900,7 +13463,24 @@ var AgentActivityList = ({
12900
13463
  },
12901
13464
  children: [
12902
13465
  /* @__PURE__ */ jsx24(MenuItem3, { value: "", sx: { fontSize: "0.85rem" }, children: "All Agent runs" }),
12903
- agentWorkflows.map((w) => /* @__PURE__ */ jsx24(MenuItem3, { value: w.id, sx: { fontSize: "0.85rem" }, children: w.name }, w.id))
13466
+ agentWorkflows.map((w) => /* @__PURE__ */ jsx24(MenuItem3, { value: w.id, sx: { fontSize: "0.85rem" }, children: w.name }, w.id)),
13467
+ /* @__PURE__ */ jsx24(Divider3, { sx: { borderColor: "hsl(var(--border))", my: 0.5 } }),
13468
+ /* @__PURE__ */ jsx24(
13469
+ Box18,
13470
+ {
13471
+ sx: {
13472
+ px: 1.5,
13473
+ py: 1,
13474
+ fontSize: "0.72rem",
13475
+ color: "hsl(var(--muted-foreground))",
13476
+ lineHeight: 1.45,
13477
+ whiteSpace: "normal",
13478
+ maxWidth: 280,
13479
+ pointerEvents: "none"
13480
+ },
13481
+ children: "Scheduled agent runs will appear in this list once you set them up."
13482
+ }
13483
+ )
12904
13484
  ]
12905
13485
  }
12906
13486
  ),
@@ -13043,7 +13623,9 @@ var AgentActivityList = ({
13043
13623
  {
13044
13624
  run,
13045
13625
  onClick: () => onRunClick?.(run),
13046
- sx: rowSx
13626
+ sx: rowSx,
13627
+ appIcons,
13628
+ onAppClick: (app) => setAppDrawer(app)
13047
13629
  },
13048
13630
  run.execution_id || idx
13049
13631
  )),
@@ -13091,6 +13673,19 @@ var AgentActivityList = ({
13091
13673
  ] })
13092
13674
  ]
13093
13675
  }
13676
+ ),
13677
+ /* @__PURE__ */ jsx24(
13678
+ AppDetailDrawer,
13679
+ {
13680
+ open: !!appDrawer,
13681
+ onClose: () => setAppDrawer(null),
13682
+ appName: appDrawer?.name || null,
13683
+ appId: appDrawer?.id || null,
13684
+ activeOrgId: orgId || null,
13685
+ globalUrl: globalUrl || apiBaseUrl,
13686
+ theme,
13687
+ colorMode
13688
+ }
13094
13689
  )
13095
13690
  ]
13096
13691
  }
@@ -13104,7 +13699,7 @@ import {
13104
13699
  X as CloseIcon7,
13105
13700
  ExternalLink as OpenInNewIcon3
13106
13701
  } from "lucide-react";
13107
- import { Fragment as Fragment9, jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
13702
+ import { Fragment as Fragment10, jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
13108
13703
  var AgentExecutionDrawer = ({
13109
13704
  open,
13110
13705
  onClose,
@@ -13205,11 +13800,11 @@ var AgentExecutionDrawer = ({
13205
13800
  ] }),
13206
13801
  run && /* @__PURE__ */ jsxs22(Box19, { sx: { display: "flex", alignItems: "center", gap: 1, mt: 0.25 }, children: [
13207
13802
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))" }, children: cfg.label }),
13208
- run.started_at && /* @__PURE__ */ jsxs22(Fragment9, { children: [
13803
+ run.started_at && /* @__PURE__ */ jsxs22(Fragment10, { children: [
13209
13804
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
13210
13805
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))" }, children: getTimeAgo(run.started_at) })
13211
13806
  ] }),
13212
- duration && /* @__PURE__ */ jsxs22(Fragment9, { children: [
13807
+ duration && /* @__PURE__ */ jsxs22(Fragment10, { children: [
13213
13808
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
13214
13809
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))" }, children: duration })
13215
13810
  ] })
@@ -13294,6 +13889,8 @@ var AgentsView = ({
13294
13889
  hideChooseLLM,
13295
13890
  localLLMSlot,
13296
13891
  permissionsSlot,
13892
+ initialApps,
13893
+ onAppsChange,
13297
13894
  globalUrl,
13298
13895
  isLoaded,
13299
13896
  isLoggedIn,
@@ -13309,7 +13906,7 @@ var AgentsView = ({
13309
13906
  const [agentView, setAgentView] = useState16("start");
13310
13907
  const [prefill, setPrefill] = useState16({
13311
13908
  input: "",
13312
- apps: [],
13909
+ apps: initialApps && initialApps.length > 0 ? initialApps : [],
13313
13910
  key: 0
13314
13911
  });
13315
13912
  const [editing, setEditing] = useState16(null);
@@ -13444,7 +14041,8 @@ var AgentsView = ({
13444
14041
  disableSchedule: Boolean(editing),
13445
14042
  disableScheduleTooltip: editing ? "Scheduling is disabled while editing an existing schedule" : void 0,
13446
14043
  theme,
13447
- colorMode
14044
+ colorMode,
14045
+ onAppsChange
13448
14046
  },
13449
14047
  prefill.key
13450
14048
  ),