@shuffleio/shuffle-mcps 0.0.26 → 0.0.28

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-R5NT3IQ7.mjs";
20
+ } from "./chunk-B4JFC2JU.mjs";
20
21
 
21
22
  // index.ts
22
23
  import "./shuffle-mcp-ER33P3W2.css";
@@ -778,7 +779,7 @@ async function backfillAppImages(dedupedApps) {
778
779
  let missing = dedupedApps.filter((d) => !d.bestImage && !d.app.large_image);
779
780
  if (missing.length === 0) return dedupedApps;
780
781
  try {
781
- const { fetchAppsViaApiConfig: fetchAppsViaApiConfig2 } = await import("./appsCache-VFYHI4NL.mjs");
782
+ const { fetchAppsViaApiConfig: fetchAppsViaApiConfig2 } = await import("./appsCache-KWDP7F2K.mjs");
782
783
  const apps = await fetchAppsViaApiConfig2().catch(() => []);
783
784
  if (Array.isArray(apps) && apps.length > 0) {
784
785
  const byName = /* @__PURE__ */ new Map();
@@ -6238,10 +6239,11 @@ var ShuffleMCP = React3.forwardRef(({
6238
6239
  }, [internalSelectedApps]);
6239
6240
  const filteredPrivateApps = useMemo4(() => {
6240
6241
  if (privateApps.length === 0) return [];
6241
- const q = query.trim().toLowerCase();
6242
+ const normalize = (s) => (s || "").toLowerCase().replace(/[\s_\-]+/g, "");
6243
+ const q = normalize(query.trim());
6242
6244
  if (!q) return privateApps;
6243
6245
  return privateApps.filter(
6244
- (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))
6245
6247
  );
6246
6248
  }, [privateApps, query]);
6247
6249
  const displayResults = useMemo4(() => {
@@ -7530,7 +7532,7 @@ var runAgent = async (request) => {
7530
7532
  }
7531
7533
  const payload = {
7532
7534
  jsonrpc: "2.0",
7533
- id: crypto.randomUUID(),
7535
+ id: Date.now(),
7534
7536
  method: "tools/call",
7535
7537
  params
7536
7538
  };
@@ -7994,10 +7996,7 @@ var getDiagnosableScope = (parsed) => {
7994
7996
  const action = String(d.action || d.details?.action || "").toLowerCase();
7995
7997
  const category = String(d.category || "").toLowerCase();
7996
7998
  if (!["finish", "finalise"].includes(action) && !["finish", "finalise"].includes(category)) return null;
7997
- return {
7998
- reason: d.reason,
7999
- fields: Array.isArray(d.fields) ? d.fields.map((f) => f?.value).filter(Boolean) : void 0
8000
- };
7999
+ return { reason: d.reason };
8001
8000
  });
8002
8001
  if (finalDecisions.some((d) => d !== null)) scope.decisions = finalDecisions;
8003
8002
  }
@@ -8071,6 +8070,32 @@ var diagnoseOutputWarning = (run) => {
8071
8070
  if (raw && entries.length === 0) entries.push({ path: "", value: raw });
8072
8071
  const haystack = entries.map((e) => e.value).join("\n");
8073
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();
8074
8099
  const findEvidence = (test, max = 3) => {
8075
8100
  const out = [];
8076
8101
  for (const e of entries) {
@@ -8087,23 +8112,35 @@ var diagnoseOutputWarning = (run) => {
8087
8112
  let statusEvidence = null;
8088
8113
  const statusPatterns = [
8089
8114
  /\bhttp[\s/]?(\d{3})\b/i,
8090
- /\bstatus[\s:_-]+(\d{3})\b/i,
8091
- /\bstatus[_\s-]?code["\s:]+(\d{3})\b/i,
8092
- /\bcode["\s:]+(\d{3})\b/i,
8093
- /\[(\d{3})\]/,
8094
- /\((\d{3})\)/,
8095
- /\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
8096
8117
  ];
8097
- 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) {
8098
8138
  for (const e of entries) {
8099
- const m = e.value.match(re);
8100
- if (m) {
8101
- const n = Number(m[1]);
8102
- if (n >= 400 && n < 600) {
8103
- status = n;
8104
- statusEvidence = { path: e.path || "(root)", value: trimEvidenceValue(e.value) };
8105
- break outer;
8106
- }
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;
8107
8144
  }
8108
8145
  }
8109
8146
  }
@@ -8123,9 +8160,7 @@ var diagnoseOutputWarning = (run) => {
8123
8160
  const dedup = ev.filter((e) => e.path !== statusEvidence.path);
8124
8161
  return [statusEvidence, ...dedup].slice(0, 3);
8125
8162
  };
8126
- 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(
8127
- lower
8128
- )) {
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)) {
8129
8164
  const ev = findEvidenceByRegex(
8130
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/
8131
8166
  );
@@ -8139,9 +8174,7 @@ var diagnoseOutputWarning = (run) => {
8139
8174
  evidence: withStatusEvidence(ev)
8140
8175
  };
8141
8176
  }
8142
- if (status === 403 || /\b(forbidden|permission[_\s-]*denied|not[_\s-]*allowed|access[_\s-]*denied|insufficient[_\s-]*(scope|permission|privileges?)|missing[_\s-]*scope)\b/.test(
8143
- lower
8144
- )) {
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)) {
8145
8178
  const ev = findEvidenceByRegex(
8146
8179
  /forbidden|permission[_\s-]*denied|not[_\s-]*allowed|access[_\s-]*denied|insufficient[_\s-]*(scope|permission|privileges?)|missing[_\s-]*scope|\b403\b/
8147
8180
  );
@@ -8155,7 +8188,7 @@ var diagnoseOutputWarning = (run) => {
8155
8188
  evidence: withStatusEvidence(ev)
8156
8189
  };
8157
8190
  }
8158
- 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)) {
8159
8192
  const ev = findEvidenceByRegex(
8160
8193
  /rate[_\s-]*limit|too[_\s-]*many[_\s-]*requests|quota[_\s-]*exceeded|throttled|\b429\b/
8161
8194
  );
@@ -8169,7 +8202,7 @@ var diagnoseOutputWarning = (run) => {
8169
8202
  evidence: withStatusEvidence(ev)
8170
8203
  };
8171
8204
  }
8172
- 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)) {
8173
8206
  const ev = findEvidenceByRegex(
8174
8207
  /not[_\s-]*found|no such|does not exist|unknown[_\s-]*(id|resource)|\b404\b/
8175
8208
  );
@@ -8183,9 +8216,7 @@ var diagnoseOutputWarning = (run) => {
8183
8216
  evidence: withStatusEvidence(ev)
8184
8217
  };
8185
8218
  }
8186
- if (status === 400 || status === 422 || /\b(bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload))\b/.test(
8187
- lower
8188
- )) {
8219
+ if (status === 400 || status === 422 || /\b(bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload))\b/.test(errorHaystackLower)) {
8189
8220
  const ev = findEvidenceByRegex(
8190
8221
  /bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload)|\b400\b|\b422\b/
8191
8222
  );
@@ -8199,9 +8230,7 @@ var diagnoseOutputWarning = (run) => {
8199
8230
  evidence: withStatusEvidence(ev)
8200
8231
  };
8201
8232
  }
8202
- 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(
8203
- lower
8204
- )) {
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)) {
8205
8234
  const ev = findEvidenceByRegex(
8206
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/
8207
8236
  );
@@ -8446,6 +8475,153 @@ var deepParseJsonStrings3 = (obj, depth = 0) => {
8446
8475
  }
8447
8476
  return obj;
8448
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
+ };
8449
8625
  var validateJson = (raw) => {
8450
8626
  if (raw == null) return { valid: false, result: null };
8451
8627
  if (typeof raw === "object") return { valid: true, result: raw };
@@ -8456,6 +8632,17 @@ var validateJson = (raw) => {
8456
8632
  return { valid: false, result: raw };
8457
8633
  }
8458
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, "_");
8459
8646
  var extractAuthRequest = (decision) => {
8460
8647
  if (!decision || typeof decision !== "object") return null;
8461
8648
  const raw = decision?.run_details?.raw_response;
@@ -8471,18 +8658,20 @@ var extractAuthRequest = (decision) => {
8471
8658
  }
8472
8659
  const needsAuth = parsed && (parsed.action === "app_authentication" || parsed.app_authentication === true);
8473
8660
  if (!needsAuth) return null;
8474
- let appName = parsed.app || parsed.app_name || parsed.appname;
8661
+ let toolAppName;
8475
8662
  let appId = null;
8476
- if (!appName && typeof decision?.tool === "string") {
8663
+ if (typeof decision?.tool === "string") {
8477
8664
  const t = decision.tool;
8478
8665
  if (t.startsWith("app:")) {
8479
8666
  const parts = t.split(":");
8480
8667
  appId = parts[1] || null;
8481
- appName = parts[2] || t;
8668
+ toolAppName = parts[2] || void 0;
8482
8669
  } else {
8483
- appName = t;
8670
+ toolAppName = t;
8484
8671
  }
8485
8672
  }
8673
+ let appName = parsed.app || parsed.app_name || parsed.appname;
8674
+ if (!appName) appName = toolAppName;
8486
8675
  if (!appName) {
8487
8676
  const f = (decision?.fields || []).find((x) => x?.key === "app" || x?.key === "app_name");
8488
8677
  if (f?.value) appName = f.value;
@@ -8546,7 +8735,9 @@ var TimelineRow = ({
8546
8735
  getFormUrl,
8547
8736
  runFinished,
8548
8737
  onAuthenticateApp,
8738
+ onRefreshAuthenticatedApps,
8549
8739
  isAppAuthenticated,
8740
+ authAppsLoading = false,
8550
8741
  highlight = false
8551
8742
  }) => {
8552
8743
  const [submitAttempted, setSubmitAttempted] = useState12(false);
@@ -8736,7 +8927,7 @@ var TimelineRow = ({
8736
8927
  IconButton8,
8737
8928
  {
8738
8929
  size: "small",
8739
- onClick: () => window.open(details.run_details.debug_url, "_blank", "noopener,noreferrer"),
8930
+ onClick: () => window.open(getShuffleCoreFormUrl(details.run_details.debug_url), "_blank", "noopener,noreferrer"),
8740
8931
  sx: { color: "hsl(var(--muted-foreground))", "&:hover": { color: "hsl(var(--primary))" } },
8741
8932
  children: /* @__PURE__ */ jsx20(OpenInNewIcon2, { size: 16 })
8742
8933
  }
@@ -8837,9 +9028,10 @@ var TimelineRow = ({
8837
9028
  (() => {
8838
9029
  const req = extractAuthRequest(details);
8839
9030
  if (!req) return null;
8840
- if (isAppAuthenticated?.(req.appName)) return null;
9031
+ if (authAppsLoading) return null;
9032
+ const authed = !!isAppAuthenticated?.(req.appName, req.appId);
8841
9033
  const pretty = req.appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
8842
- const slug = req.appName.toLowerCase().replace(/[\s-]+/g, "_");
9034
+ const slug = normalizeAgentAppName(req.appName);
8843
9035
  const appId = req.appId || appsById[req.appName]?.id || appsById[slug]?.id || null;
8844
9036
  const icon = appsById[req.appName]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
8845
9037
  return /* @__PURE__ */ jsx20(Box14, { sx: { px: 4, pb: 2 }, children: /* @__PURE__ */ jsxs17(Box14, { sx: {
@@ -8848,22 +9040,68 @@ var TimelineRow = ({
8848
9040
  gap: 1.5,
8849
9041
  p: 1.5,
8850
9042
  borderRadius: 1.5,
8851
- border: "1px solid hsla(var(--severity-medium) / 0.3)",
8852
- 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)"
8853
9045
  }, children: [
8854
- /* @__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))" }),
8855
9047
  /* @__PURE__ */ jsxs17(Box14, { sx: { flex: 1, minWidth: 0 }, children: [
8856
- /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
8857
- pretty,
8858
- " requires authentication"
8859
- ] }),
8860
- /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
8861
- "Connect your ",
8862
- pretty,
8863
- " account so the agent can complete this step, then rerun the decision."
8864
- ] })
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.` })
8865
9050
  ] }),
8866
- /* @__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(
8867
9105
  Button8,
8868
9106
  {
8869
9107
  variant: "outlined",
@@ -8890,6 +9128,7 @@ var TimelineRow = ({
8890
9128
  disabled: !onAuthenticateApp,
8891
9129
  onClick: (e) => {
8892
9130
  e.stopPropagation();
9131
+ onRefreshAuthenticatedApps?.();
8893
9132
  onAuthenticateApp?.(req.appName, appId);
8894
9133
  },
8895
9134
  sx: {
@@ -8976,6 +9215,7 @@ var AgentUI = ({
8976
9215
  authorization,
8977
9216
  initialExecution,
8978
9217
  onRun,
9218
+ onAppsChange,
8979
9219
  onViewChange,
8980
9220
  onSchedule,
8981
9221
  apiKey,
@@ -9005,6 +9245,7 @@ var AgentUI = ({
9005
9245
  ];
9006
9246
  const [chosenApps, setChosenApps] = useState12(apps ?? defaultApps ?? BUILTIN_DEFAULT_APPS);
9007
9247
  const [availableApps, setAvailableApps] = useState12([]);
9248
+ const [authAppsLoading, setAuthAppsLoading] = useState12(autoLoadApps && hasApiKey);
9008
9249
  const [executionApps, setExecutionApps] = useState12([]);
9009
9250
  const [resolvedToolApps, setResolvedToolApps] = useState12({});
9010
9251
  const [appSearchOpen, setAppSearchOpen] = useState12(false);
@@ -9034,6 +9275,7 @@ var AgentUI = ({
9034
9275
  const [highlightedIndex, setHighlightedIndex] = useState12(null);
9035
9276
  const [questionAnswers, setQuestionAnswers] = useState12({});
9036
9277
  const [simpleSubmitAttempted, setSimpleSubmitAttempted] = useState12(false);
9278
+ const [finishAnswerRaw, setFinishAnswerRaw] = useState12(false);
9037
9279
  const [continuationText, setContinuationText] = useState12("");
9038
9280
  const [error, setError] = useState12(null);
9039
9281
  const [searchParams, setSearchParams] = useSearchParams();
@@ -9125,29 +9367,33 @@ var AgentUI = ({
9125
9367
  }
9126
9368
  return m;
9127
9369
  }, [chosenApps, executionApps, resolvedToolApps]);
9128
- const isAppAuthenticated = useCallback8((appName) => {
9129
- if (!appName) return false;
9130
- const norm4 = (s) => s.toLowerCase().replace(/[\s-]+/g, "_");
9131
- const target = norm4(appName);
9132
- 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
+ });
9133
9378
  }, [availableApps]);
9134
9379
  const pendingAuthApps = useMemo6(() => {
9380
+ if (authAppsLoading) return [];
9135
9381
  const decisions = agentData?.decisions || [];
9136
9382
  const seen = /* @__PURE__ */ new Set();
9137
9383
  const out = [];
9138
9384
  for (const d of decisions) {
9139
9385
  const req = extractAuthRequest(d);
9140
9386
  if (!req) continue;
9141
- const slug = req.appName.toLowerCase().replace(/[\s-]+/g, "_");
9387
+ const slug = normalizeAgentAppName(req.appName);
9142
9388
  if (seen.has(slug)) continue;
9143
- if (isAppAuthenticated(req.appName)) continue;
9389
+ if (isAppAuthenticated(req.appName, req.appId)) continue;
9144
9390
  seen.add(slug);
9145
9391
  const appId = req.appId || appsById[req.appName]?.id || appsById[slug]?.id || null;
9146
9392
  const icon = appsById[req.appName]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
9147
9393
  out.push({ appName: req.appName, appId, icon });
9148
9394
  }
9149
9395
  return out;
9150
- }, [agentData, appsById, isAppAuthenticated]);
9396
+ }, [agentData, appsById, authAppsLoading, isAppAuthenticated]);
9151
9397
  useEffect11(() => {
9152
9398
  if (apps) setChosenApps(apps);
9153
9399
  }, [apps]);
@@ -9257,45 +9503,60 @@ var AgentUI = ({
9257
9503
  cancelled = true;
9258
9504
  };
9259
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]);
9260
9543
  useEffect11(() => {
9261
9544
  if (!autoLoadApps) return;
9262
- if (apps || defaultApps) return;
9263
9545
  if (!hasApiKey) return;
9264
- let cancelled = false;
9265
- (async () => {
9266
- try {
9267
- const resp = await fetch(resolveUrl2("/api/v1/apps/authentication"), {
9268
- credentials: "include",
9269
- headers: { ...resolveHeaders2() }
9270
- });
9271
- if (!resp.ok) return;
9272
- const result = await resp.json();
9273
- const list = Array.isArray(result) ? result : result?.data || [];
9274
- const seen = /* @__PURE__ */ new Set();
9275
- const loaded = [];
9276
- for (const entry of list) {
9277
- const app = entry?.app || entry;
9278
- const name = app?.name;
9279
- if (!name) continue;
9280
- const valid = entry?.active || entry?.validation?.valid || entry?.hasValidAuth;
9281
- if (valid === false) continue;
9282
- const key = name.toLowerCase();
9283
- if (seen.has(key)) continue;
9284
- seen.add(key);
9285
- loaded.push({
9286
- name,
9287
- id: app?.id || entry?.id,
9288
- icon: app?.large_image || app?.image_url || app?.image || entry?.bestImage || ""
9289
- });
9290
- }
9291
- if (!cancelled && loaded.length) setAvailableApps(loaded);
9292
- } catch {
9293
- }
9294
- })();
9546
+ const signal = { cancelled: false };
9547
+ loadAuthenticatedApps(signal);
9295
9548
  return () => {
9296
- cancelled = true;
9549
+ signal.cancelled = true;
9550
+ };
9551
+ }, [autoLoadApps, hasApiKey, loadAuthenticatedApps]);
9552
+ useEffect11(() => {
9553
+ if (!hasApiKey) return;
9554
+ const handler = () => {
9555
+ loadAuthenticatedApps();
9297
9556
  };
9298
- }, [autoLoadApps, apps, defaultApps, hasApiKey, resolveUrl2, resolveHeaders2]);
9557
+ window.addEventListener("integrations-changed", handler);
9558
+ return () => window.removeEventListener("integrations-changed", handler);
9559
+ }, [hasApiKey, loadAuthenticatedApps]);
9299
9560
  useEffect11(() => {
9300
9561
  const raw = agentData?.allowed_actions;
9301
9562
  if (!Array.isArray(raw) || raw.length === 0) {
@@ -9691,31 +9952,48 @@ var AgentUI = ({
9691
9952
  setAgentRequestLoading(false);
9692
9953
  }
9693
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]);
9694
9977
  const rerunAgent = useCallback8(() => {
9695
- const input = agentData?.original_input || actionInput || (() => {
9696
- const msgs = agentData?.input?.messages || [];
9697
- const m = msgs.find((m2) => m2?.role === "user" && !String(m2?.role).includes("USER CONTEXT"));
9698
- return m?.content || "";
9699
- })();
9978
+ const input = resolveRunInput();
9700
9979
  if (input && typeof input === "string") {
9701
9980
  setActionInput(input);
9702
9981
  }
9703
9982
  if (executionApps.length > 0) {
9704
9983
  setChosenApps(executionApps);
9705
9984
  }
9706
- if (disableStartTab) {
9707
- if (input && typeof input === "string" && input.trim().length >= 6) {
9708
- submitInput(input);
9709
- }
9710
- 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 });
9711
9992
  }
9712
- setShowStarter(true);
9713
- setSearchParams((prev) => {
9714
- const next = new URLSearchParams(prev);
9715
- next.delete("agentView");
9716
- return next;
9717
- }, { replace: true });
9718
- }, [agentData, actionInput, executionApps, setSearchParams, disableStartTab, submitInput]);
9993
+ if (input && typeof input === "string" && input.trim().length >= 6) {
9994
+ submitInput(input);
9995
+ }
9996
+ }, [resolveRunInput, executionApps, setSearchParams, disableStartTab, submitInput]);
9719
9997
  const abortAgent = useCallback8(async () => {
9720
9998
  const execId = execution?.execution_id;
9721
9999
  const auth = execution?.authorization;
@@ -9965,13 +10243,12 @@ var AgentUI = ({
9965
10243
  useEffect11(() => {
9966
10244
  onViewChange?.(activeTab);
9967
10245
  }, [activeTab, onViewChange]);
10246
+ useEffect11(() => {
10247
+ onAppsChange?.(chosenApps);
10248
+ }, [chosenApps, onAppsChange]);
9968
10249
  const goToTab = (t) => {
9969
10250
  if (t === "start") {
9970
- const runInput = agentData?.original_input || (() => {
9971
- const msgs = agentData?.input?.messages || [];
9972
- const m = msgs.find((m2) => m2?.role === "user");
9973
- return m?.content || "";
9974
- })();
10251
+ const runInput = resolveRunInput();
9975
10252
  if (runInput && typeof runInput === "string") {
9976
10253
  setActionInput(runInput);
9977
10254
  }
@@ -10112,58 +10389,71 @@ var AgentUI = ({
10112
10389
  ] }, i)) })
10113
10390
  ] }) : scheduleDisabledReasons.length === 1 ? `Cannot schedule: ${scheduleDisabledReasons[0]}` : "";
10114
10391
  const tabBarRef = useRef8(null);
10115
- 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(
10116
10395
  Box14,
10117
10396
  {
10118
10397
  ref: tabBarRef,
10119
10398
  sx: {
10120
10399
  display: "flex",
10121
10400
  alignItems: "center",
10401
+ gap: 1,
10122
10402
  width: "fit-content",
10123
10403
  alignSelf: "center",
10124
10404
  position: "sticky",
10125
10405
  top: 8,
10126
10406
  zIndex: 5
10127
10407
  },
10128
- children: /* @__PURE__ */ jsx20(
10129
- SegmentedControl,
10130
- {
10131
- layoutId: "agentui-view-switcher",
10132
- ariaLabel: "Agent view",
10133
- value: activeTab,
10134
- onChange: (v) => goToTab(v),
10135
- options: [
10136
- { value: "start", label: "Start", disabled: disableStartTab },
10137
- { value: "simple", label: "Simple", disabled: !hasExecution },
10138
- { value: "detailed", label: "Detailed", disabled: !hasExecution },
10139
- { type: "divider", key: "div" },
10140
- {
10141
- type: "action",
10142
- key: "reload",
10143
- label: /* @__PURE__ */ jsx20(RefreshIcon, { size: 14 }),
10144
- title: "Reload execution data",
10145
- disabled: !hasExecution,
10146
- onClick: () => {
10147
- if (execution?.execution_id && execution?.authorization) {
10148
- 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
+ }
10149
10431
  }
10150
- }
10151
- },
10152
- {
10153
- type: "action",
10154
- key: "schedule",
10155
- label: /* @__PURE__ */ jsx20(ScheduleIcon, { size: 14 }),
10156
- title: scheduleDisabledReason ? `Cannot schedule: ${scheduleDisabledReason}` : "Schedule this prompt to run repeatedly on a cron schedule",
10157
- disabled: Boolean(scheduleDisabledReason),
10158
- onClick: () => {
10159
- if (!scheduleDisabledReason && tabBarRef.current) {
10160
- 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
+ }
10161
10443
  }
10162
10444
  }
10163
- }
10164
- ]
10165
- }
10166
- )
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
+ ]
10167
10457
  }
10168
10458
  );
10169
10459
  const schedulePopover = /* @__PURE__ */ jsxs17(
@@ -10895,9 +11185,9 @@ var AgentUI = ({
10895
11185
  }
10896
11186
  ) }),
10897
11187
  chosenApps.map((app, i) => {
10898
- const slug = (app.name || "").toLowerCase().replace(/[\s-]+/g, "_");
11188
+ const slug = normalizeAgentAppName(app.name || "");
10899
11189
  const NO_AUTH = /* @__PURE__ */ new Set(["http", "shuffle_tools", "shuffle-tools", "tools", "singul", "core", "webhook", "email"]);
10900
- const needsAuth = !NO_AUTH.has(slug) && !isAppAuthenticated(app.name || "");
11190
+ const needsAuth = !authAppsLoading && !NO_AUTH.has(slug) && !isAppAuthenticated(app.name || "", app.id || null);
10901
11191
  return /* @__PURE__ */ jsx20(
10902
11192
  Tooltip9,
10903
11193
  {
@@ -10958,9 +11248,10 @@ var AgentUI = ({
10958
11248
  ] }) }),
10959
11249
  !hideAppPicker && (() => {
10960
11250
  const NO_AUTH = /* @__PURE__ */ new Set(["http", "shuffle_tools", "shuffle-tools", "tools", "singul", "core", "webhook", "email"]);
11251
+ if (authAppsLoading) return null;
10961
11252
  const unauthed = chosenApps.filter((a) => {
10962
- const slug = (a.name || "").toLowerCase().replace(/[\s-]+/g, "_");
10963
- 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);
10964
11255
  });
10965
11256
  if (unauthed.length === 0) return null;
10966
11257
  return /* @__PURE__ */ jsx20(Box14, { sx: { display: "flex", justifyContent: "center", mt: -0.5 }, children: /* @__PURE__ */ jsxs17(Box14, { sx: {
@@ -11030,7 +11321,7 @@ var AgentUI = ({
11030
11321
  src: app.icon || void 0,
11031
11322
  alt: app.name,
11032
11323
  variant: "rounded",
11033
- onClick: () => navigate(`/apps/${encodeURIComponent((app.name || "").toLowerCase().replace(/\s+/g, "_"))}`),
11324
+ onClick: () => setAuthDrawerApp({ name: app.name, id: app.id || null }),
11034
11325
  sx: {
11035
11326
  bgcolor: "hsl(var(--muted))",
11036
11327
  cursor: "pointer",
@@ -11162,133 +11453,88 @@ var AgentUI = ({
11162
11453
  }
11163
11454
  const pendingAnswered = pendingQuestions.every((q) => questionAnswers[q.question]?.value);
11164
11455
  return /* @__PURE__ */ jsxs17(Fragment7, { children: [
11165
- /* @__PURE__ */ jsxs17(Box14, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
11166
- 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))" }),
11167
- /* @__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()}` }),
11168
- /* @__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),
11169
11464
  decisionCount,
11170
- " step",
11171
- decisionCount === 1 ? "" : "s",
11172
- durationSec != null ? ` \xB7 ${Math.round(durationSec)}s` : ""
11173
- ] }),
11174
- /* @__PURE__ */ jsx20(Box14, { sx: { flexGrow: 1 } })
11175
- ] }),
11176
- pendingAuthApps.map(({ appName, appId, icon }) => {
11177
- const pretty = appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
11178
- return /* @__PURE__ */ jsxs17(
11179
- Box14,
11180
- {
11181
- sx: {
11182
- display: "flex",
11183
- alignItems: "center",
11184
- gap: 1.5,
11185
- p: 1.5,
11186
- borderRadius: 1.5,
11187
- border: "1px solid hsla(var(--severity-medium) / 0.3)",
11188
- bgcolor: "hsla(var(--severity-medium) / 0.08)"
11189
- },
11190
- children: [
11191
- /* @__PURE__ */ jsx20(LockIcon3, { size: 22, color: "hsl(var(--severity-medium))" }),
11192
- /* @__PURE__ */ jsxs17(Box14, { sx: { flex: 1, minWidth: 0 }, children: [
11193
- /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
11194
- pretty,
11195
- " requires authentication"
11196
- ] }),
11197
- /* @__PURE__ */ jsxs17(Typography13, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
11198
- "Connect your ",
11199
- pretty,
11200
- " account so the agent can complete this step, then rerun."
11201
- ] })
11202
- ] }),
11203
- /* @__PURE__ */ jsxs17(
11204
- Button8,
11205
- {
11206
- variant: "outlined",
11207
- size: "small",
11208
- startIcon: /* @__PURE__ */ jsx20(
11209
- 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,
11210
11496
  {
11211
- src: icon || void 0,
11212
- alt: "",
11213
- 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 }),
11214
11519
  sx: {
11215
- width: 18,
11216
- height: 18,
11217
- borderRadius: 0.5,
11218
- bgcolor: "hsl(var(--background) / 0.4)",
11219
- color: "hsl(var(--background))",
11220
- fontSize: "0.7rem",
11221
- fontWeight: 700,
11222
- "& img": { objectFit: "contain" }
11520
+ height: 36,
11521
+ textTransform: "none",
11522
+ fontWeight: 600
11223
11523
  },
11224
- children: pretty.charAt(0)
11524
+ children: [
11525
+ "Authenticate ",
11526
+ pretty
11527
+ ]
11225
11528
  }
11226
- ),
11227
- onClick: () => setAuthDrawerApp({ name: appName, id: appId }),
11228
- sx: {
11229
- height: 36,
11230
- textTransform: "none",
11231
- fontWeight: 600
11232
- },
11233
- children: [
11234
- "Authenticate ",
11235
- pretty
11236
- ]
11237
- }
11238
- )
11239
- ]
11240
- },
11241
- `auth-${appName}`
11242
- );
11243
- }),
11244
- finishAnswer ? /* @__PURE__ */ jsx20(Box14, { sx: {
11245
- p: 2,
11246
- borderRadius: 1.5,
11247
- border: "1px solid hsl(var(--border))",
11248
- bgcolor: "hsl(var(--background))",
11249
- fontSize: "0.9rem",
11250
- color: "hsl(var(--foreground))",
11251
- "& > *:first-of-type": { mt: 0 },
11252
- "& > *:last-child": { mb: 0 },
11253
- "& p": { my: 1, lineHeight: 1.55 },
11254
- "& h1, & h2, & h3, & h4": { mt: 2, mb: 1, fontWeight: 600, lineHeight: 1.3 },
11255
- "& h1": { fontSize: "1.15rem" },
11256
- "& h2": { fontSize: "1.05rem" },
11257
- "& h3, & h4": { fontSize: "0.95rem" },
11258
- "& ul": { my: 1, pl: 3, listStyleType: "disc", listStylePosition: "outside" },
11259
- "& ol": { my: 1, pl: 3, listStyleType: "decimal", listStylePosition: "outside" },
11260
- "& ul ul": { listStyleType: "circle" },
11261
- "& ul ul ul": { listStyleType: "square" },
11262
- "& li": { my: 0.25, display: "list-item" },
11263
- "& li::marker": { color: "hsl(var(--muted-foreground))" },
11264
- "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
11265
- "& code": {
11266
- px: 0.5,
11267
- py: 0.125,
11268
- borderRadius: 0.5,
11269
- bgcolor: "hsl(var(--muted))",
11270
- fontFamily: '"JetBrains Mono", ui-monospace, monospace',
11271
- fontSize: "0.82em"
11272
- },
11273
- "& pre": {
11274
- p: 1.5,
11275
- my: 1,
11276
- borderRadius: 1,
11277
- bgcolor: "hsl(var(--muted))",
11278
- overflowX: "auto",
11279
- fontSize: "0.82rem"
11280
- },
11281
- "& pre code": { p: 0, bgcolor: "transparent" },
11282
- "& blockquote": {
11283
- borderLeft: "3px solid hsl(var(--border))",
11284
- pl: 1.5,
11285
- my: 1,
11286
- color: "hsl(var(--muted-foreground))"
11287
- },
11288
- "& table": { borderCollapse: "collapse", my: 1, fontSize: "0.85rem" },
11289
- "& th, & td": { border: "1px solid hsl(var(--border))", px: 1, py: 0.5 },
11290
- "& hr": { border: 0, borderTop: "1px solid hsl(var(--border))", my: 1.5 }
11291
- }, 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 ? (() => {
11292
11538
  const trySimpleSubmit = () => {
11293
11539
  if (agentRequestLoading) return;
11294
11540
  if (!pendingAnswered) {
@@ -11360,7 +11606,7 @@ var AgentUI = ({
11360
11606
  ) })
11361
11607
  ] })
11362
11608
  ] });
11363
- })() : 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,
11364
11610
  !isRunning && /* @__PURE__ */ jsx20(Box14, { children: /* @__PURE__ */ jsx20(
11365
11611
  Button8,
11366
11612
  {
@@ -11406,53 +11652,32 @@ var AgentUI = ({
11406
11652
  getFormUrl,
11407
11653
  runFinished: detailedRunFinished,
11408
11654
  onAuthenticateApp: (name, id) => setAuthDrawerApp({ name, id }),
11655
+ onRefreshAuthenticatedApps: () => {
11656
+ loadAuthenticatedApps();
11657
+ },
11409
11658
  isAppAuthenticated,
11659
+ authAppsLoading,
11410
11660
  highlight: highlightedIndex === i
11411
11661
  },
11412
11662
  i
11413
11663
  )),
11414
- detailedRunFinished && /* @__PURE__ */ jsxs17(Box14, { sx: {
11664
+ detailedRunFinished && /* @__PURE__ */ jsx20(Box14, { sx: {
11415
11665
  borderTop: "1px solid hsl(var(--border))",
11416
11666
  p: 2.5,
11417
11667
  display: "flex",
11418
11668
  flexDirection: "column",
11419
11669
  gap: 1.5,
11420
11670
  bgcolor: "hsl(var(--muted) / 0.2)"
11421
- }, children: [
11422
- /* @__PURE__ */ jsxs17(Box14, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
11423
- detailedStatus === "FINISHED" ? /* @__PURE__ */ jsx20(CheckCircleIcon4, { size: 18, color: "hsl(142 70% 45%)" }) : /* @__PURE__ */ jsx20(ErrorIcon, { size: 18, color: "hsl(var(--destructive))" }),
11424
- /* @__PURE__ */ jsx20(Typography13, { sx: { fontSize: "0.9rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: detailedStatus === "FINISHED" ? "Run finished" : `Run ${detailedStatus.toLowerCase()}` })
11425
- ] }),
11426
- finishAnswer && /* @__PURE__ */ jsx20(Box14, { sx: {
11427
- p: 2,
11428
- borderRadius: 1.5,
11429
- border: "1px solid hsl(var(--border))",
11430
- bgcolor: "hsl(var(--background))",
11431
- fontSize: "0.9rem",
11432
- color: "hsl(var(--foreground))",
11433
- "& > *:first-of-type": { mt: 0 },
11434
- "& > *:last-child": { mb: 0 },
11435
- "& p": { my: 1, lineHeight: 1.55 },
11436
- "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
11437
- "& code": {
11438
- px: 0.5,
11439
- py: 0.125,
11440
- borderRadius: 0.5,
11441
- bgcolor: "hsl(var(--muted))",
11442
- fontFamily: '"JetBrains Mono", ui-monospace, monospace',
11443
- fontSize: "0.82em"
11444
- },
11445
- "& pre": {
11446
- p: 1.5,
11447
- my: 1,
11448
- borderRadius: 1,
11449
- bgcolor: "hsl(var(--muted))",
11450
- overflowX: "auto",
11451
- fontSize: "0.82rem"
11452
- },
11453
- "& pre code": { p: 0, bgcolor: "transparent" }
11454
- }, children: /* @__PURE__ */ jsx20(Markdown, { remarkPlugins: [remarkGfm4, remarkBreaks], children: normalizeMarkdown(finishAnswer) }) })
11455
- ] })
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
+ ) })
11456
11681
  ] }) });
11457
11682
  })(),
11458
11683
  finishDecisionId && /* @__PURE__ */ jsx20(Box14, { sx: { mt: 3, display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsxs17(Box14, { sx: { width: "100%", maxWidth: 640 }, children: [
@@ -11556,6 +11781,9 @@ var AgentUI = ({
11556
11781
  {
11557
11782
  open: !!authDrawerApp,
11558
11783
  onClose: () => setAuthDrawerApp(null),
11784
+ onRefresh: () => {
11785
+ loadAuthenticatedApps();
11786
+ },
11559
11787
  appName: authDrawerApp?.name || null,
11560
11788
  appId: authDrawerApp?.id || null,
11561
11789
  activeOrgId: orgId || null,
@@ -11686,7 +11914,7 @@ var UsageBar = ({
11686
11914
  };
11687
11915
 
11688
11916
  // components/LocalLLMConfig.tsx
11689
- 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";
11690
11918
  import { createElement as createElement2 } from "react";
11691
11919
  var OPENAI_APP_NAME = "OpenAI";
11692
11920
  var OPENAI_APP_ID = "5d19dd82517870c68d40cacad9b5ca91";
@@ -11713,15 +11941,16 @@ var OPENAI_ALGOLIA_APP = {
11713
11941
  };
11714
11942
  var ENDPOINT_PRESETS = [
11715
11943
  { label: SHUFFLE_AI_PRESET, url: "" },
11716
- { label: "OpenAI", url: "https://api.openai.com/v1" },
11717
- { label: "Anthropic", url: "https://api.anthropic.com/v1/" },
11718
- { label: "Google Gemini", url: "https://generativelanguage.googleapis.com/v1beta/openai/" },
11719
- { label: "Mistral", url: "https://api.mistral.ai/v1" },
11720
- { label: "Groq", url: "https://api.groq.com/openai/v1" },
11721
- { label: "Together AI", url: "https://api.together.xyz/v1" },
11722
- { label: "OpenRouter", url: "https://openrouter.ai/api/v1" },
11723
- { label: "Ollama (localhost)", url: "http://localhost:11434/v1" },
11724
- { 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." },
11725
11954
  { label: CUSTOM_PRESET, url: "" }
11726
11955
  ];
11727
11956
  var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serverside, theme, colorMode }) => {
@@ -11880,12 +12109,29 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
11880
12109
  }
11881
12110
  )
11882
12111
  ] }),
11883
- !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: [
11884
- 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.",
11885
- " ",
11886
- /* @__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" }),
11887
- "."
11888
- ] }) }),
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
+ })(),
11889
12135
  isShuffleAI && /* @__PURE__ */ jsxs19(Box16, { sx: { display: "flex", flexDirection: "column", gap: 0.75, mt: 0.5, width: "100%" }, children: [
11890
12136
  /* @__PURE__ */ jsx22(UsageBar, { label: "App runs", usage: appRunUsage, limit: appRunLimit, unit: "runs", actionLabel: "Upgrade", actionHref: "https://shuffler.io/pricing" }),
11891
12137
  /* @__PURE__ */ jsx22(UsageBar, { label: "Agent tokens", usage: agentTokenUsage, limit: agentTokenLimit, unit: "tokens", actionLabel: "Upgrade", actionHref: "https://shuffler.io/pricing" })
@@ -12168,15 +12414,18 @@ var AgentRunDrawer_default = AgentRunDrawer;
12168
12414
 
12169
12415
  // components/AgentActivityList.tsx
12170
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";
12171
12418
  import {
12419
+ Avatar as Avatar8,
12420
+ AvatarGroup as AvatarGroup2,
12172
12421
  Box as Box18,
12173
12422
  Button as Button10,
12174
- Chip as Chip8,
12175
12423
  CircularProgress as CircularProgress5,
12176
12424
  Dialog as Dialog3,
12177
12425
  DialogActions as DialogActions2,
12178
12426
  DialogContent as DialogContent3,
12179
12427
  DialogTitle as DialogTitle3,
12428
+ Divider as Divider3,
12180
12429
  InputAdornment,
12181
12430
  MenuItem as MenuItem3,
12182
12431
  Select as Select3,
@@ -12190,6 +12439,7 @@ import {
12190
12439
  CheckCircle,
12191
12440
  Clock,
12192
12441
  FileText,
12442
+ GitBranch,
12193
12443
  Globe,
12194
12444
  Loader2,
12195
12445
  Server as Server2,
@@ -12485,7 +12735,7 @@ var stopAgentSchedule = async (workflowId, params = {}) => {
12485
12735
 
12486
12736
  // components/AgentActivityList.tsx
12487
12737
  import { Pencil, StopCircle, AlertTriangle as AlertTriangle2 } from "lucide-react";
12488
- 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";
12489
12739
  var STATUS_CONFIG = {
12490
12740
  FINISHED: { icon: /* @__PURE__ */ jsx24(CheckCircle, { size: 16 }), color: "hsl(var(--severity-low, 142 71% 45%))", label: "Completed" },
12491
12741
  SUCCESS: { icon: /* @__PURE__ */ jsx24(CheckCircle, { size: 16 }), color: "hsl(var(--severity-low, 142 71% 45%))", label: "Completed" },
@@ -12553,21 +12803,110 @@ var getTimeAgo = (dateStr) => {
12553
12803
  return dateStr;
12554
12804
  }
12555
12805
  };
12556
- var getRunTitle = (run) => {
12557
- if (run.workflow?.name) return run.workflow.name;
12558
- if (run.execution_argument) {
12559
- try {
12560
- const parsed = JSON.parse(run.execution_argument);
12561
- if (parsed.title) return parsed.title;
12562
- if (parsed.action) return parsed.action;
12563
- if (parsed.name) return parsed.name;
12564
- } catch {
12565
- const clean = run.execution_argument.replace(/[{}"]/g, "").trim();
12566
- 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;
12567
12883
  }
12568
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;
12569
12904
  return `Execution ${run.execution_id?.slice(0, 8) || "\u2014"}`;
12570
12905
  };
12906
+ var getDecisionCount = (run) => {
12907
+ if (Array.isArray(run.decisions)) return run.decisions.length;
12908
+ return 0;
12909
+ };
12571
12910
  var getRunSubtitle = (run) => {
12572
12911
  if (run.result) {
12573
12912
  try {
@@ -12585,30 +12924,82 @@ var getRunSubtitle = (run) => {
12585
12924
  }
12586
12925
  return run.execution_source || "Agent execution";
12587
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
+ };
12588
12934
  var getRunTools = (run) => {
12589
- const out = /* @__PURE__ */ new Set();
12590
- const add = (v) => {
12591
- if (!v) return;
12592
- const s = String(v).trim();
12593
- if (!s) return;
12594
- if (/^(ai\s*agent|shuffle\s*agent|shuffle_agent)$/i.test(s)) return;
12595
- 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);
12596
12947
  };
12597
- (run.results || []).forEach((r) => {
12598
- add(r?.action?.app_name);
12599
- if (!r?.action?.app_name) add(r?.action?.label);
12600
- });
12601
- (run.decisions || []).forEach((d) => {
12602
- add(typeof d?.tool === "string" ? d.tool : void 0);
12603
- });
12604
- 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"
12605
12993
  };
12606
- 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();
12607
12997
  const statusKey = getEffectiveStatus(run);
12608
12998
  const cfg = STATUS_CONFIG[statusKey] || STATUS_CONFIG.WAITING;
12609
12999
  const iconColor = getRunIconColor(run);
12610
13000
  const duration = formatDuration(run);
12611
13001
  const tools = getRunTools(run);
13002
+ const decisionCount = getDecisionCount(run);
12612
13003
  return /* @__PURE__ */ jsxs21(
12613
13004
  Box18,
12614
13005
  {
@@ -12683,45 +13074,83 @@ var AgentRunRow = ({ run, onClick, sx }) => {
12683
13074
  ),
12684
13075
  /* @__PURE__ */ jsxs21(Box18, { sx: { display: "flex", alignItems: "center", gap: 1, mt: 0.5 }, children: [
12685
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" }),
12686
- duration && /* @__PURE__ */ jsxs21(Fragment8, { children: [
13077
+ duration && /* @__PURE__ */ jsxs21(Fragment9, { children: [
12687
13078
  /* @__PURE__ */ jsx24(Typography17, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
12688
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
+ ] })
12689
13091
  ] })
12690
13092
  ] })
12691
13093
  ] }),
12692
13094
  tools.length > 0 && /* @__PURE__ */ jsx24(
12693
13095
  Box18,
12694
13096
  {
13097
+ onClick: (e) => e.stopPropagation(),
12695
13098
  sx: {
12696
13099
  display: { xs: "none", sm: "flex" },
12697
13100
  alignItems: "center",
12698
- gap: 0.5,
12699
- flexWrap: "wrap",
12700
- justifyContent: "flex-end",
12701
- maxWidth: 220,
12702
- flexShrink: 0
13101
+ flexShrink: 0,
13102
+ ml: 1
12703
13103
  },
12704
- children: tools.map((t) => /* @__PURE__ */ jsx24(Tooltip12, { title: t, arrow: true, children: /* @__PURE__ */ jsx24(
12705
- Chip8,
13104
+ children: /* @__PURE__ */ jsx24(
13105
+ AvatarGroup2,
12706
13106
  {
12707
- label: t,
12708
- size: "small",
13107
+ max: 5,
12709
13108
  sx: {
12710
- height: 20,
12711
- fontSize: "0.68rem",
12712
- maxWidth: 120,
12713
- bgcolor: "hsla(var(--muted) / 0.5)",
12714
- color: "hsl(var(--muted-foreground))",
12715
- border: "1px solid hsl(var(--border))",
12716
- "& .MuiChip-label": {
12717
- px: 0.75,
12718
- overflow: "hidden",
12719
- textOverflow: "ellipsis",
12720
- 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))"
12721
13116
  }
12722
- }
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
+ })
12723
13152
  }
12724
- ) }, t))
13153
+ )
12725
13154
  }
12726
13155
  )
12727
13156
  ]
@@ -12748,8 +13177,12 @@ var AgentActivityList = ({
12748
13177
  className,
12749
13178
  sx,
12750
13179
  toolbarSx,
12751
- rowSx
13180
+ rowSx,
13181
+ globalUrl,
13182
+ theme,
13183
+ colorMode
12752
13184
  }) => {
13185
+ const [appDrawer, setAppDrawer] = useState15(null);
12753
13186
  const [runs, setRuns] = useState15([]);
12754
13187
  const [cursor, setCursor] = useState15("");
12755
13188
  const [hasMore, setHasMore] = useState15(false);
@@ -12762,6 +13195,8 @@ var AgentActivityList = ({
12762
13195
  const [workflowFilter, setWorkflowFilter] = useState15("");
12763
13196
  const [stopOpen, setStopOpen] = useState15(false);
12764
13197
  const [stopLoading, setStopLoading] = useState15(false);
13198
+ const [appIcons, setAppIcons] = useState15({});
13199
+ const [enrichedRuns, setEnrichedRuns] = useState15({});
12765
13200
  const debounceRef = useRef11();
12766
13201
  const selectedAgentWorkflow = agentWorkflows.find((w) => w.id === workflowFilter) || null;
12767
13202
  const openEditPrompt = useCallback9(async () => {
@@ -12843,10 +13278,137 @@ var AgentActivityList = ({
12843
13278
  cancelled = true;
12844
13279
  };
12845
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
+ });
12846
13408
  const loadMore = useCallback9(() => {
12847
13409
  if (cursor && !isLoading) fetchRuns(true, cursor);
12848
13410
  }, [cursor, isLoading, fetchRuns]);
12849
- const filteredRuns = debouncedQuery ? runs.filter((r) => {
13411
+ const filteredRuns = debouncedQuery ? mergedRuns.filter((r) => {
12850
13412
  const hay = [
12851
13413
  getRunTitle(r),
12852
13414
  getRunSubtitle(r),
@@ -12855,7 +13417,7 @@ var AgentActivityList = ({
12855
13417
  r.status
12856
13418
  ].filter(Boolean).join(" ").toLowerCase();
12857
13419
  return hay.includes(debouncedQuery.toLowerCase());
12858
- }) : runs;
13420
+ }) : mergedRuns;
12859
13421
  return /* @__PURE__ */ jsxs21(
12860
13422
  Box18,
12861
13423
  {
@@ -12901,7 +13463,24 @@ var AgentActivityList = ({
12901
13463
  },
12902
13464
  children: [
12903
13465
  /* @__PURE__ */ jsx24(MenuItem3, { value: "", sx: { fontSize: "0.85rem" }, children: "All Agent runs" }),
12904
- 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
+ )
12905
13484
  ]
12906
13485
  }
12907
13486
  ),
@@ -13044,7 +13623,9 @@ var AgentActivityList = ({
13044
13623
  {
13045
13624
  run,
13046
13625
  onClick: () => onRunClick?.(run),
13047
- sx: rowSx
13626
+ sx: rowSx,
13627
+ appIcons,
13628
+ onAppClick: (app) => setAppDrawer(app)
13048
13629
  },
13049
13630
  run.execution_id || idx
13050
13631
  )),
@@ -13092,6 +13673,19 @@ var AgentActivityList = ({
13092
13673
  ] })
13093
13674
  ]
13094
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
+ }
13095
13689
  )
13096
13690
  ]
13097
13691
  }
@@ -13105,7 +13699,7 @@ import {
13105
13699
  X as CloseIcon7,
13106
13700
  ExternalLink as OpenInNewIcon3
13107
13701
  } from "lucide-react";
13108
- 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";
13109
13703
  var AgentExecutionDrawer = ({
13110
13704
  open,
13111
13705
  onClose,
@@ -13206,11 +13800,11 @@ var AgentExecutionDrawer = ({
13206
13800
  ] }),
13207
13801
  run && /* @__PURE__ */ jsxs22(Box19, { sx: { display: "flex", alignItems: "center", gap: 1, mt: 0.25 }, children: [
13208
13802
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))" }, children: cfg.label }),
13209
- run.started_at && /* @__PURE__ */ jsxs22(Fragment9, { children: [
13803
+ run.started_at && /* @__PURE__ */ jsxs22(Fragment10, { children: [
13210
13804
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
13211
13805
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))" }, children: getTimeAgo(run.started_at) })
13212
13806
  ] }),
13213
- duration && /* @__PURE__ */ jsxs22(Fragment9, { children: [
13807
+ duration && /* @__PURE__ */ jsxs22(Fragment10, { children: [
13214
13808
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
13215
13809
  /* @__PURE__ */ jsx25(Typography18, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))" }, children: duration })
13216
13810
  ] })
@@ -13295,6 +13889,8 @@ var AgentsView = ({
13295
13889
  hideChooseLLM,
13296
13890
  localLLMSlot,
13297
13891
  permissionsSlot,
13892
+ initialApps,
13893
+ onAppsChange,
13298
13894
  globalUrl,
13299
13895
  isLoaded,
13300
13896
  isLoggedIn,
@@ -13310,7 +13906,7 @@ var AgentsView = ({
13310
13906
  const [agentView, setAgentView] = useState16("start");
13311
13907
  const [prefill, setPrefill] = useState16({
13312
13908
  input: "",
13313
- apps: [],
13909
+ apps: initialApps && initialApps.length > 0 ? initialApps : [],
13314
13910
  key: 0
13315
13911
  });
13316
13912
  const [editing, setEditing] = useState16(null);
@@ -13445,7 +14041,8 @@ var AgentsView = ({
13445
14041
  disableSchedule: Boolean(editing),
13446
14042
  disableScheduleTooltip: editing ? "Scheduling is disabled while editing an existing schedule" : void 0,
13447
14043
  theme,
13448
- colorMode
14044
+ colorMode,
14045
+ onAppsChange
13449
14046
  },
13450
14047
  prefill.key
13451
14048
  ),