@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.js CHANGED
@@ -155,7 +155,7 @@ var init_fetchBreaker = __esm({
155
155
  });
156
156
 
157
157
  // api.ts
158
- var DEV_BACKEND, PROD_BACKEND, CLOUD_DOMAINS, getEnvVar, isDevEnvironment, isCloudDomain, isCloud, isOnprem, getDefaultBaseUrl, _regionUrl, _trackedOrgId, _hostBaseUrl, isShufflerSubdomain, setRegionUrl, resetRegionUrl, setHostBaseUrl, getHostBaseUrl, getTrackedOrgId, API_CONFIG, getApiUrl, shuffleFetch, getAuthHeader;
158
+ var DEV_BACKEND, PROD_BACKEND, CLOUD_DOMAINS, getEnvVar, isDevEnvironment, isCloudDomain, isCloud, isOnprem, getDefaultBaseUrl, _regionUrl, _trackedOrgId, _hostBaseUrl, isShufflerSubdomain, setRegionUrl, resetRegionUrl, SHUFFLE_HOST_BASE_URL_EVENT, setHostBaseUrl, getHostBaseUrl, getTrackedOrgId, API_CONFIG, getApiUrl, getShuffleCoreFormUrl, shuffleFetch, getAuthHeader;
159
159
  var init_api = __esm({
160
160
  "api.ts"() {
161
161
  init_fetchBreaker();
@@ -227,6 +227,7 @@ var init_api = __esm({
227
227
  }
228
228
  _regionUrl = null;
229
229
  };
230
+ SHUFFLE_HOST_BASE_URL_EVENT = "shuffle:set-host-base-url";
230
231
  setHostBaseUrl = (url) => {
231
232
  const next = url ? url.replace(/\/+$/, "") : null;
232
233
  if (next === _hostBaseUrl) return;
@@ -237,7 +238,22 @@ var init_api = __esm({
237
238
  } catch {
238
239
  }
239
240
  }
241
+ if (typeof window !== "undefined") {
242
+ try {
243
+ window.dispatchEvent(new CustomEvent(SHUFFLE_HOST_BASE_URL_EVENT, { detail: next }));
244
+ } catch {
245
+ }
246
+ }
240
247
  };
248
+ if (typeof window !== "undefined") {
249
+ try {
250
+ window.addEventListener(SHUFFLE_HOST_BASE_URL_EVENT, (e) => {
251
+ const detail = e.detail;
252
+ setHostBaseUrl(detail ?? null);
253
+ });
254
+ } catch {
255
+ }
256
+ }
241
257
  getHostBaseUrl = () => _hostBaseUrl;
242
258
  getTrackedOrgId = () => _trackedOrgId;
243
259
  API_CONFIG = {
@@ -268,6 +284,13 @@ var init_api = __esm({
268
284
  getApiUrl = (endpoint) => {
269
285
  return `${API_CONFIG.baseUrl}${endpoint}`;
270
286
  };
287
+ getShuffleCoreFormUrl = (refUrl) => {
288
+ if (!refUrl) return refUrl;
289
+ if (/^https?:\/\//i.test(refUrl)) return refUrl;
290
+ const path = refUrl.startsWith("/") ? refUrl : `/${refUrl}`;
291
+ if (isCloud()) return `https://shuffler.io${path}`;
292
+ return `${API_CONFIG.baseUrl}${path}`;
293
+ };
271
294
  shuffleFetch = (url, init) => {
272
295
  const { headers: extraHeaders, ...rest } = init || {};
273
296
  return fetch(url, {
@@ -450,12 +473,13 @@ __export(index_exports, {
450
473
  useSyncHostBaseUrl: () => useSyncHostBaseUrl
451
474
  });
452
475
  module.exports = __toCommonJS(index_exports);
453
- var import_shuffle_mcp2 = require("./shuffle-mcp-ER33P3W2.css");
476
+ var import_shuffle_mcp3 = require("./shuffle-mcp-ER33P3W2.css");
454
477
  var import_react22 = __toESM(require("react"));
455
478
 
456
479
  // ShuffleMcpThemeProvider.tsx
457
480
  var import_react = __toESM(require("react"));
458
481
  var import_material = require("@mui/material");
482
+ var import_shuffle_mcp = require("./shuffle-mcp-ER33P3W2.css");
459
483
  var import_jsx_runtime = require("react/jsx-runtime");
460
484
  var readHtmlDarkClass = () => {
461
485
  if (typeof document === "undefined") return false;
@@ -6095,7 +6119,7 @@ function AppDetailDrawer({
6095
6119
  }
6096
6120
 
6097
6121
  // views/ShuffleMCP.tsx
6098
- var import_shuffle_mcp = require("./shuffle-mcp-ER33P3W2.css");
6122
+ var import_shuffle_mcp2 = require("./shuffle-mcp-ER33P3W2.css");
6099
6123
  init_appsCache();
6100
6124
 
6101
6125
  // components/SegmentedControl.tsx
@@ -6602,10 +6626,11 @@ var ShuffleMCP = import_react12.default.forwardRef(({
6602
6626
  }, [internalSelectedApps]);
6603
6627
  const filteredPrivateApps = (0, import_react12.useMemo)(() => {
6604
6628
  if (privateApps.length === 0) return [];
6605
- const q = query.trim().toLowerCase();
6629
+ const normalize = (s) => (s || "").toLowerCase().replace(/[\s_\-]+/g, "");
6630
+ const q = normalize(query.trim());
6606
6631
  if (!q) return privateApps;
6607
6632
  return privateApps.filter(
6608
- (a) => a.name.toLowerCase().includes(q) || (a.description || "").toLowerCase().includes(q) || (a.categories || []).some((c) => c.toLowerCase().includes(q))
6633
+ (a) => normalize(a.name).includes(q) || normalize(a.description || "").includes(q) || (a.categories || []).some((c) => normalize(c).includes(q))
6609
6634
  );
6610
6635
  }, [privateApps, query]);
6611
6636
  const displayResults = (0, import_react12.useMemo)(() => {
@@ -7861,7 +7886,7 @@ var runAgent = async (request) => {
7861
7886
  }
7862
7887
  const payload = {
7863
7888
  jsonrpc: "2.0",
7864
- id: crypto.randomUUID(),
7889
+ id: Date.now(),
7865
7890
  method: "tools/call",
7866
7891
  params
7867
7892
  };
@@ -8325,10 +8350,7 @@ var getDiagnosableScope = (parsed) => {
8325
8350
  const action = String(d.action || d.details?.action || "").toLowerCase();
8326
8351
  const category = String(d.category || "").toLowerCase();
8327
8352
  if (!["finish", "finalise"].includes(action) && !["finish", "finalise"].includes(category)) return null;
8328
- return {
8329
- reason: d.reason,
8330
- fields: Array.isArray(d.fields) ? d.fields.map((f) => f?.value).filter(Boolean) : void 0
8331
- };
8353
+ return { reason: d.reason };
8332
8354
  });
8333
8355
  if (finalDecisions.some((d) => d !== null)) scope.decisions = finalDecisions;
8334
8356
  }
@@ -8402,6 +8424,32 @@ var diagnoseOutputWarning = (run) => {
8402
8424
  if (raw && entries.length === 0) entries.push({ path: "", value: raw });
8403
8425
  const haystack = entries.map((e) => e.value).join("\n");
8404
8426
  const lower = haystack.toLowerCase();
8427
+ const ERROR_FIELD_NAMES = /* @__PURE__ */ new Set([
8428
+ "error",
8429
+ "errors",
8430
+ "err",
8431
+ "reason",
8432
+ "message",
8433
+ "messages",
8434
+ "msg",
8435
+ "detail",
8436
+ "details",
8437
+ "failure",
8438
+ "fault",
8439
+ "exception",
8440
+ "exceptions",
8441
+ "warning",
8442
+ "warnings",
8443
+ "status_text",
8444
+ "status_message",
8445
+ "status_reason",
8446
+ "errormessage",
8447
+ "error_description"
8448
+ ]);
8449
+ const getPathSegments = (path) => path.split(/[.\[\]]+/).filter(Boolean).map((segment) => segment.toLowerCase());
8450
+ const isErrorPath = (path) => getPathSegments(path).some((segment) => ERROR_FIELD_NAMES.has(segment));
8451
+ const errorEntries = entries.filter((e) => isErrorPath(e.path));
8452
+ const errorHaystackLower = errorEntries.map((e) => e.value).join("\n").toLowerCase();
8405
8453
  const findEvidence = (test, max = 3) => {
8406
8454
  const out = [];
8407
8455
  for (const e of entries) {
@@ -8418,23 +8466,35 @@ var diagnoseOutputWarning = (run) => {
8418
8466
  let statusEvidence = null;
8419
8467
  const statusPatterns = [
8420
8468
  /\bhttp[\s/]?(\d{3})\b/i,
8421
- /\bstatus[\s:_-]+(\d{3})\b/i,
8422
- /\bstatus[_\s-]?code["\s:]+(\d{3})\b/i,
8423
- /\bcode["\s:]+(\d{3})\b/i,
8424
- /\[(\d{3})\]/,
8425
- /\((\d{3})\)/,
8426
- /\b(4\d{2}|5\d{2})\b/
8469
+ /\b(?:response[_\s-]?status|status[_\s-]?code|response[_\s-]?code)["'\s:=]+(\d{3})\b/i,
8470
+ /\bstatus["'\s:=]+(\d{3})\b/i
8427
8471
  ];
8428
- outer: for (const re of statusPatterns) {
8472
+ const isStatusPath = (path) => {
8473
+ const segments = getPathSegments(path);
8474
+ const last = segments[segments.length - 1];
8475
+ return ["status", "status_code", "response_status", "response_code", "http_status"].includes(last || "");
8476
+ };
8477
+ const statusFromEntry = (entry) => {
8478
+ if (isStatusPath(entry.path) && /^\d{3}$/.test(entry.value.trim())) {
8479
+ return Number(entry.value.trim());
8480
+ }
8481
+ for (const re of statusPatterns) {
8482
+ const m = entry.value.match(re);
8483
+ if (m) return Number(m[1]);
8484
+ }
8485
+ return null;
8486
+ };
8487
+ const hasSuccessStatus = entries.some((e) => {
8488
+ const n = statusFromEntry(e);
8489
+ return typeof n === "number" && n >= 200 && n < 300;
8490
+ });
8491
+ if (!hasSuccessStatus) {
8429
8492
  for (const e of entries) {
8430
- const m = e.value.match(re);
8431
- if (m) {
8432
- const n = Number(m[1]);
8433
- if (n >= 400 && n < 600) {
8434
- status = n;
8435
- statusEvidence = { path: e.path || "(root)", value: trimEvidenceValue(e.value) };
8436
- break outer;
8437
- }
8493
+ const n = statusFromEntry(e);
8494
+ if (typeof n === "number" && n >= 400 && n < 600) {
8495
+ status = n;
8496
+ statusEvidence = { path: e.path || "(root)", value: trimEvidenceValue(e.value) };
8497
+ break;
8438
8498
  }
8439
8499
  }
8440
8500
  }
@@ -8454,9 +8514,7 @@ var diagnoseOutputWarning = (run) => {
8454
8514
  const dedup = ev.filter((e) => e.path !== statusEvidence.path);
8455
8515
  return [statusEvidence, ...dedup].slice(0, 3);
8456
8516
  };
8457
- 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(
8458
- lower
8459
- )) {
8517
+ 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)) {
8460
8518
  const ev = findEvidenceByRegex(
8461
8519
  /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/
8462
8520
  );
@@ -8470,9 +8528,7 @@ var diagnoseOutputWarning = (run) => {
8470
8528
  evidence: withStatusEvidence(ev)
8471
8529
  };
8472
8530
  }
8473
- if (status === 403 || /\b(forbidden|permission[_\s-]*denied|not[_\s-]*allowed|access[_\s-]*denied|insufficient[_\s-]*(scope|permission|privileges?)|missing[_\s-]*scope)\b/.test(
8474
- lower
8475
- )) {
8531
+ 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)) {
8476
8532
  const ev = findEvidenceByRegex(
8477
8533
  /forbidden|permission[_\s-]*denied|not[_\s-]*allowed|access[_\s-]*denied|insufficient[_\s-]*(scope|permission|privileges?)|missing[_\s-]*scope|\b403\b/
8478
8534
  );
@@ -8486,7 +8542,7 @@ var diagnoseOutputWarning = (run) => {
8486
8542
  evidence: withStatusEvidence(ev)
8487
8543
  };
8488
8544
  }
8489
- if (status === 429 || /\b(rate[_\s-]*limit|too[_\s-]*many[_\s-]*requests|quota[_\s-]*exceeded|throttled)\b/.test(lower)) {
8545
+ if (status === 429 || /\b(rate[_\s-]*limit|too[_\s-]*many[_\s-]*requests|quota[_\s-]*exceeded|throttled)\b/.test(errorHaystackLower)) {
8490
8546
  const ev = findEvidenceByRegex(
8491
8547
  /rate[_\s-]*limit|too[_\s-]*many[_\s-]*requests|quota[_\s-]*exceeded|throttled|\b429\b/
8492
8548
  );
@@ -8500,7 +8556,7 @@ var diagnoseOutputWarning = (run) => {
8500
8556
  evidence: withStatusEvidence(ev)
8501
8557
  };
8502
8558
  }
8503
- if (status === 404 || /\b(not[_\s-]*found|no such|does not exist|unknown[_\s-]*(id|resource))\b/.test(lower)) {
8559
+ if (status === 404 || /\b(not[_\s-]*found|no such|does not exist|unknown[_\s-]*(id|resource))\b/.test(errorHaystackLower)) {
8504
8560
  const ev = findEvidenceByRegex(
8505
8561
  /not[_\s-]*found|no such|does not exist|unknown[_\s-]*(id|resource)|\b404\b/
8506
8562
  );
@@ -8514,9 +8570,7 @@ var diagnoseOutputWarning = (run) => {
8514
8570
  evidence: withStatusEvidence(ev)
8515
8571
  };
8516
8572
  }
8517
- if (status === 400 || status === 422 || /\b(bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload))\b/.test(
8518
- lower
8519
- )) {
8573
+ if (status === 400 || status === 422 || /\b(bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload))\b/.test(errorHaystackLower)) {
8520
8574
  const ev = findEvidenceByRegex(
8521
8575
  /bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload)|\b400\b|\b422\b/
8522
8576
  );
@@ -8530,9 +8584,7 @@ var diagnoseOutputWarning = (run) => {
8530
8584
  evidence: withStatusEvidence(ev)
8531
8585
  };
8532
8586
  }
8533
- 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(
8534
- lower
8535
- )) {
8587
+ 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)) {
8536
8588
  const ev = findEvidenceByRegex(
8537
8589
  /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/
8538
8590
  );
@@ -8777,6 +8829,153 @@ var deepParseJsonStrings3 = (obj, depth = 0) => {
8777
8829
  }
8778
8830
  return obj;
8779
8831
  };
8832
+ var tryParseJsonObject = (raw) => {
8833
+ if (!raw) return null;
8834
+ const trimmed = raw.trim();
8835
+ if (!(trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]"))) return null;
8836
+ try {
8837
+ const parsed = JSON.parse(trimmed);
8838
+ if (parsed && typeof parsed === "object") return deepParseJsonStrings3(parsed);
8839
+ } catch {
8840
+ }
8841
+ return null;
8842
+ };
8843
+ var stripSingleCodeFence = (raw) => {
8844
+ const m = raw.match(/^\s*```(?:json)?\s*\n([\s\S]*?)\n```\s*$/i);
8845
+ return m ? m[1] : raw;
8846
+ };
8847
+ var FinishAnswerMarkdown = ({ text }) => {
8848
+ const wholeJson = (0, import_react15.useMemo)(() => tryParseJsonObject(stripSingleCodeFence(text)), [text]);
8849
+ if (wholeJson !== null) {
8850
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { "& .json-view": { backgroundColor: "transparent !important", fontSize: "0.82rem" } }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react18_json_view2.default, { src: wholeJson, collapsed: 2, enableClipboard: true, displaySize: true, theme: "default" }) });
8851
+ }
8852
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8853
+ import_react_markdown4.default,
8854
+ {
8855
+ remarkPlugins: [import_remark_gfm4.default, import_remark_breaks.default],
8856
+ components: {
8857
+ code({ inline, className, children, ...props }) {
8858
+ const content = String(children ?? "").replace(/\n$/, "");
8859
+ const isBlock = !inline && (content.includes("\n") || /language-/.test(className || ""));
8860
+ if (isBlock) {
8861
+ const parsed = tryParseJsonObject(content);
8862
+ if (parsed !== null) {
8863
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { my: 1, p: 1.5, borderRadius: 1, bgcolor: "hsl(var(--muted))", "& .json-view": { backgroundColor: "transparent !important", fontSize: "0.82rem" } }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react18_json_view2.default, { src: parsed, collapsed: 2, enableClipboard: true, displaySize: true, theme: "default" }) });
8864
+ }
8865
+ }
8866
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("code", { className, ...props, children });
8867
+ }
8868
+ },
8869
+ children: text
8870
+ }
8871
+ );
8872
+ };
8873
+ var RunFinishedSummary = ({
8874
+ status,
8875
+ isRunning,
8876
+ finishAnswer,
8877
+ raw,
8878
+ onToggleRaw,
8879
+ decisionCount,
8880
+ durationSec,
8881
+ showMeta = false,
8882
+ children
8883
+ }) => {
8884
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
8885
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
8886
+ isRunning ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.CircularProgress, { size: 16, sx: { color: "hsl(var(--primary))" } }) : status === "FINISHED" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.CheckCircle2, { size: 18, color: "hsl(142 70% 45%)" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.AlertCircle, { size: 18, color: "hsl(var(--destructive))" }),
8887
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.9rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: isRunning ? "Agent is working\u2026" : status === "FINISHED" ? "Run finished" : `Run ${status.toLowerCase()}` }),
8888
+ showMeta && (decisionCount != null || durationSec != null) && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
8889
+ decisionCount != null ? `${decisionCount} step${decisionCount === 1 ? "" : "s"}` : "",
8890
+ durationSec != null ? `${decisionCount != null ? " \xB7 " : ""}${Math.round(durationSec)}s` : ""
8891
+ ] }),
8892
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { flexGrow: 1 } }),
8893
+ finishAnswer && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8894
+ import_material16.Button,
8895
+ {
8896
+ size: "small",
8897
+ variant: "outlined",
8898
+ onClick: onToggleRaw,
8899
+ sx: {
8900
+ height: 28,
8901
+ textTransform: "none",
8902
+ fontWeight: 500,
8903
+ fontSize: "0.72rem",
8904
+ px: 1,
8905
+ minWidth: 0,
8906
+ color: "hsl(var(--muted-foreground))",
8907
+ borderColor: "hsl(var(--border))"
8908
+ },
8909
+ children: raw ? "Rendered" : "Raw"
8910
+ }
8911
+ )
8912
+ ] }),
8913
+ children,
8914
+ finishAnswer && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
8915
+ p: 2,
8916
+ borderRadius: 1.5,
8917
+ border: "1px solid hsl(var(--border))",
8918
+ bgcolor: "hsl(var(--background))",
8919
+ fontSize: "0.9rem",
8920
+ color: "hsl(var(--foreground))",
8921
+ "& > *:first-of-type": { mt: 0 },
8922
+ "& > *:last-child": { mb: 0 },
8923
+ "& p": { my: 1, lineHeight: 1.55 },
8924
+ "& h1, & h2, & h3, & h4": { mt: 2, mb: 1, fontWeight: 600, lineHeight: 1.3 },
8925
+ "& h1": { fontSize: "1.15rem" },
8926
+ "& h2": { fontSize: "1.05rem" },
8927
+ "& h3, & h4": { fontSize: "0.95rem" },
8928
+ "& ul": { my: 1, pl: 3, listStyleType: "disc", listStylePosition: "outside" },
8929
+ "& ol": { my: 1, pl: 3, listStyleType: "decimal", listStylePosition: "outside" },
8930
+ "& ul ul": { listStyleType: "circle" },
8931
+ "& ul ul ul": { listStyleType: "square" },
8932
+ "& li": { my: 0.25, display: "list-item" },
8933
+ "& li::marker": { color: "hsl(var(--muted-foreground))" },
8934
+ "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
8935
+ "& code": {
8936
+ px: 0.5,
8937
+ py: 0.125,
8938
+ borderRadius: 0.5,
8939
+ bgcolor: "hsl(var(--muted))",
8940
+ fontFamily: '"JetBrains Mono", ui-monospace, monospace',
8941
+ fontSize: "0.82em"
8942
+ },
8943
+ "& pre": {
8944
+ p: 1.5,
8945
+ my: 1,
8946
+ borderRadius: 1,
8947
+ bgcolor: "hsl(var(--muted))",
8948
+ overflowX: "auto",
8949
+ fontSize: "0.82rem"
8950
+ },
8951
+ "& pre code": { p: 0, bgcolor: "transparent" },
8952
+ "& blockquote": {
8953
+ borderLeft: "3px solid hsl(var(--border))",
8954
+ pl: 1.5,
8955
+ my: 1,
8956
+ color: "hsl(var(--muted-foreground))"
8957
+ },
8958
+ "& table": { borderCollapse: "collapse", my: 1, fontSize: "0.85rem" },
8959
+ "& th, & td": { border: "1px solid hsl(var(--border))", px: 1, py: 0.5 },
8960
+ "& hr": { border: 0, borderTop: "1px solid hsl(var(--border))", my: 1.5 }
8961
+ }, children: raw ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8962
+ import_material16.Box,
8963
+ {
8964
+ component: "pre",
8965
+ sx: {
8966
+ m: 0,
8967
+ fontSize: "0.78rem",
8968
+ fontFamily: '"JetBrains Mono", ui-monospace, monospace',
8969
+ color: "hsl(var(--foreground))",
8970
+ whiteSpace: "pre-wrap",
8971
+ wordBreak: "break-word",
8972
+ lineHeight: 1.55
8973
+ },
8974
+ children: finishAnswer
8975
+ }
8976
+ ) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(FinishAnswerMarkdown, { text: normalizeMarkdown(finishAnswer) }) })
8977
+ ] });
8978
+ };
8780
8979
  var validateJson = (raw) => {
8781
8980
  if (raw == null) return { valid: false, result: null };
8782
8981
  if (typeof raw === "object") return { valid: true, result: raw };
@@ -8787,6 +8986,17 @@ var validateJson = (raw) => {
8787
8986
  return { valid: false, result: raw };
8788
8987
  }
8789
8988
  };
8989
+ var AGENT_NO_AUTH_APPS = /* @__PURE__ */ new Set([
8990
+ "shuffle_host_monitors",
8991
+ "shuffle_monitors",
8992
+ "shuffle_sensors",
8993
+ "shuffle_workflows",
8994
+ "shuffle_datastore",
8995
+ "shuffle_apps",
8996
+ "shuffle_detection",
8997
+ "shuffle_files"
8998
+ ]);
8999
+ var normalizeAgentAppName = (name) => name.toLowerCase().replace(/[\s-]+/g, "_");
8790
9000
  var extractAuthRequest = (decision) => {
8791
9001
  if (!decision || typeof decision !== "object") return null;
8792
9002
  const raw = decision?.run_details?.raw_response;
@@ -8802,18 +9012,20 @@ var extractAuthRequest = (decision) => {
8802
9012
  }
8803
9013
  const needsAuth = parsed && (parsed.action === "app_authentication" || parsed.app_authentication === true);
8804
9014
  if (!needsAuth) return null;
8805
- let appName = parsed.app || parsed.app_name || parsed.appname;
9015
+ let toolAppName;
8806
9016
  let appId = null;
8807
- if (!appName && typeof decision?.tool === "string") {
9017
+ if (typeof decision?.tool === "string") {
8808
9018
  const t = decision.tool;
8809
9019
  if (t.startsWith("app:")) {
8810
9020
  const parts = t.split(":");
8811
9021
  appId = parts[1] || null;
8812
- appName = parts[2] || t;
9022
+ toolAppName = parts[2] || void 0;
8813
9023
  } else {
8814
- appName = t;
9024
+ toolAppName = t;
8815
9025
  }
8816
9026
  }
9027
+ let appName = parsed.app || parsed.app_name || parsed.appname;
9028
+ if (!appName) appName = toolAppName;
8817
9029
  if (!appName) {
8818
9030
  const f = (decision?.fields || []).find((x) => x?.key === "app" || x?.key === "app_name");
8819
9031
  if (f?.value) appName = f.value;
@@ -8877,7 +9089,9 @@ var TimelineRow = ({
8877
9089
  getFormUrl,
8878
9090
  runFinished,
8879
9091
  onAuthenticateApp,
9092
+ onRefreshAuthenticatedApps,
8880
9093
  isAppAuthenticated,
9094
+ authAppsLoading = false,
8881
9095
  highlight = false
8882
9096
  }) => {
8883
9097
  const [submitAttempted, setSubmitAttempted] = (0, import_react15.useState)(false);
@@ -9067,7 +9281,7 @@ var TimelineRow = ({
9067
9281
  import_material16.IconButton,
9068
9282
  {
9069
9283
  size: "small",
9070
- onClick: () => window.open(details.run_details.debug_url, "_blank", "noopener,noreferrer"),
9284
+ onClick: () => window.open(getShuffleCoreFormUrl(details.run_details.debug_url), "_blank", "noopener,noreferrer"),
9071
9285
  sx: { color: "hsl(var(--muted-foreground))", "&:hover": { color: "hsl(var(--primary))" } },
9072
9286
  children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.ExternalLink, { size: 16 })
9073
9287
  }
@@ -9168,9 +9382,10 @@ var TimelineRow = ({
9168
9382
  (() => {
9169
9383
  const req = extractAuthRequest(details);
9170
9384
  if (!req) return null;
9171
- if (isAppAuthenticated?.(req.appName)) return null;
9385
+ if (authAppsLoading) return null;
9386
+ const authed = !!isAppAuthenticated?.(req.appName, req.appId);
9172
9387
  const pretty = req.appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
9173
- const slug = req.appName.toLowerCase().replace(/[\s-]+/g, "_");
9388
+ const slug = normalizeAgentAppName(req.appName);
9174
9389
  const appId = req.appId || appsById[req.appName]?.id || appsById[slug]?.id || null;
9175
9390
  const icon = appsById[req.appName]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
9176
9391
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { px: 4, pb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: {
@@ -9179,22 +9394,68 @@ var TimelineRow = ({
9179
9394
  gap: 1.5,
9180
9395
  p: 1.5,
9181
9396
  borderRadius: 1.5,
9182
- border: "1px solid hsla(var(--severity-medium) / 0.3)",
9183
- bgcolor: "hsla(var(--severity-medium) / 0.08)"
9397
+ border: authed ? "1px solid hsla(var(--severity-low) / 0.35)" : "1px solid hsla(var(--severity-medium) / 0.3)",
9398
+ bgcolor: authed ? "hsla(var(--severity-low) / 0.08)" : "hsla(var(--severity-medium) / 0.08)"
9184
9399
  }, children: [
9185
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Lock, { size: 22, color: "hsl(var(--severity-medium))" }),
9400
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Lock, { size: 22, color: authed ? "hsl(var(--severity-low))" : "hsl(var(--severity-medium))" }),
9186
9401
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { flex: 1, minWidth: 0 }, children: [
9187
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
9188
- pretty,
9189
- " requires authentication"
9190
- ] }),
9191
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
9192
- "Connect your ",
9193
- pretty,
9194
- " account so the agent can complete this step, then rerun the decision."
9195
- ] })
9402
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: authed ? `${pretty} is now connected \u2014 rerun this action` : `${pretty} requires authentication` }),
9403
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { 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.` })
9196
9404
  ] }),
9197
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
9405
+ authed && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
9406
+ import_material16.Button,
9407
+ {
9408
+ variant: "text",
9409
+ size: "small",
9410
+ startIcon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
9411
+ import_material16.Avatar,
9412
+ {
9413
+ src: icon || void 0,
9414
+ alt: "",
9415
+ variant: "rounded",
9416
+ sx: {
9417
+ width: 18,
9418
+ height: 18,
9419
+ borderRadius: 0.5,
9420
+ bgcolor: "hsl(var(--background) / 0.4)",
9421
+ color: "hsl(var(--background))",
9422
+ fontSize: "0.7rem",
9423
+ fontWeight: 700,
9424
+ "& img": { objectFit: "contain" }
9425
+ },
9426
+ children: pretty.charAt(0)
9427
+ }
9428
+ ),
9429
+ disabled: !onAuthenticateApp,
9430
+ onClick: (e) => {
9431
+ e.stopPropagation();
9432
+ onRefreshAuthenticatedApps?.();
9433
+ onAuthenticateApp?.(req.appName, appId);
9434
+ },
9435
+ sx: {
9436
+ height: 36,
9437
+ textTransform: "none",
9438
+ fontWeight: 500,
9439
+ color: "hsl(var(--muted-foreground))"
9440
+ },
9441
+ children: "Review authentication"
9442
+ }
9443
+ ),
9444
+ authed ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
9445
+ import_material16.Button,
9446
+ {
9447
+ variant: "contained",
9448
+ size: "small",
9449
+ startIcon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.RotateCcw, { size: 16 }),
9450
+ disabled: agentRequestLoading || !details?.run_details?.id,
9451
+ onClick: (e) => {
9452
+ e.stopPropagation();
9453
+ if (details) onRerunDecision(details);
9454
+ },
9455
+ sx: { height: 36, textTransform: "none", fontWeight: 600 },
9456
+ children: "Rerun action"
9457
+ }
9458
+ ) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
9198
9459
  import_material16.Button,
9199
9460
  {
9200
9461
  variant: "outlined",
@@ -9221,6 +9482,7 @@ var TimelineRow = ({
9221
9482
  disabled: !onAuthenticateApp,
9222
9483
  onClick: (e) => {
9223
9484
  e.stopPropagation();
9485
+ onRefreshAuthenticatedApps?.();
9224
9486
  onAuthenticateApp?.(req.appName, appId);
9225
9487
  },
9226
9488
  sx: {
@@ -9307,6 +9569,7 @@ var AgentUI = ({
9307
9569
  authorization,
9308
9570
  initialExecution,
9309
9571
  onRun,
9572
+ onAppsChange,
9310
9573
  onViewChange,
9311
9574
  onSchedule,
9312
9575
  apiKey,
@@ -9336,6 +9599,7 @@ var AgentUI = ({
9336
9599
  ];
9337
9600
  const [chosenApps, setChosenApps] = (0, import_react15.useState)(apps ?? defaultApps ?? BUILTIN_DEFAULT_APPS);
9338
9601
  const [availableApps, setAvailableApps] = (0, import_react15.useState)([]);
9602
+ const [authAppsLoading, setAuthAppsLoading] = (0, import_react15.useState)(autoLoadApps && hasApiKey);
9339
9603
  const [executionApps, setExecutionApps] = (0, import_react15.useState)([]);
9340
9604
  const [resolvedToolApps, setResolvedToolApps] = (0, import_react15.useState)({});
9341
9605
  const [appSearchOpen, setAppSearchOpen] = (0, import_react15.useState)(false);
@@ -9365,6 +9629,7 @@ var AgentUI = ({
9365
9629
  const [highlightedIndex, setHighlightedIndex] = (0, import_react15.useState)(null);
9366
9630
  const [questionAnswers, setQuestionAnswers] = (0, import_react15.useState)({});
9367
9631
  const [simpleSubmitAttempted, setSimpleSubmitAttempted] = (0, import_react15.useState)(false);
9632
+ const [finishAnswerRaw, setFinishAnswerRaw] = (0, import_react15.useState)(false);
9368
9633
  const [continuationText, setContinuationText] = (0, import_react15.useState)("");
9369
9634
  const [error, setError] = (0, import_react15.useState)(null);
9370
9635
  const [searchParams, setSearchParams] = (0, import_react_router_dom2.useSearchParams)();
@@ -9456,29 +9721,33 @@ var AgentUI = ({
9456
9721
  }
9457
9722
  return m;
9458
9723
  }, [chosenApps, executionApps, resolvedToolApps]);
9459
- const isAppAuthenticated = (0, import_react15.useCallback)((appName) => {
9460
- if (!appName) return false;
9461
- const norm4 = (s) => s.toLowerCase().replace(/[\s-]+/g, "_");
9462
- const target = norm4(appName);
9463
- return availableApps.some((a) => norm4(a.name || "") === target);
9724
+ const isAppAuthenticated = (0, import_react15.useCallback)((appName, appId) => {
9725
+ if (!appName && !appId) return false;
9726
+ const target = normalizeAgentAppName(appName);
9727
+ if (AGENT_NO_AUTH_APPS.has(target)) return true;
9728
+ return availableApps.some((a) => {
9729
+ if (appId && a.id && String(a.id) === String(appId)) return true;
9730
+ return !!appName && normalizeAgentAppName(a.name || "") === target;
9731
+ });
9464
9732
  }, [availableApps]);
9465
9733
  const pendingAuthApps = (0, import_react15.useMemo)(() => {
9734
+ if (authAppsLoading) return [];
9466
9735
  const decisions = agentData?.decisions || [];
9467
9736
  const seen = /* @__PURE__ */ new Set();
9468
9737
  const out = [];
9469
9738
  for (const d of decisions) {
9470
9739
  const req = extractAuthRequest(d);
9471
9740
  if (!req) continue;
9472
- const slug = req.appName.toLowerCase().replace(/[\s-]+/g, "_");
9741
+ const slug = normalizeAgentAppName(req.appName);
9473
9742
  if (seen.has(slug)) continue;
9474
- if (isAppAuthenticated(req.appName)) continue;
9743
+ if (isAppAuthenticated(req.appName, req.appId)) continue;
9475
9744
  seen.add(slug);
9476
9745
  const appId = req.appId || appsById[req.appName]?.id || appsById[slug]?.id || null;
9477
9746
  const icon = appsById[req.appName]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
9478
9747
  out.push({ appName: req.appName, appId, icon });
9479
9748
  }
9480
9749
  return out;
9481
- }, [agentData, appsById, isAppAuthenticated]);
9750
+ }, [agentData, appsById, authAppsLoading, isAppAuthenticated]);
9482
9751
  (0, import_react15.useEffect)(() => {
9483
9752
  if (apps) setChosenApps(apps);
9484
9753
  }, [apps]);
@@ -9588,45 +9857,60 @@ var AgentUI = ({
9588
9857
  cancelled = true;
9589
9858
  };
9590
9859
  }, [chosenApps, availableApps, resolveUrl2, resolveHeaders2]);
9860
+ const loadAuthenticatedApps = (0, import_react15.useCallback)(async (signal) => {
9861
+ setAuthAppsLoading(true);
9862
+ try {
9863
+ const resp = await fetch(resolveUrl2("/api/v1/apps/authentication"), {
9864
+ credentials: "include",
9865
+ headers: { ...resolveHeaders2() }
9866
+ });
9867
+ if (!resp.ok) {
9868
+ if (!signal?.cancelled) setAvailableApps([]);
9869
+ return;
9870
+ }
9871
+ const result = await resp.json();
9872
+ const list = Array.isArray(result) ? result : result?.data || [];
9873
+ const seen = /* @__PURE__ */ new Set();
9874
+ const loaded = [];
9875
+ for (const entry of list) {
9876
+ const app = entry?.app || entry;
9877
+ const name = app?.name;
9878
+ if (!name) continue;
9879
+ const valid = entry?.active || entry?.validation?.valid || entry?.hasValidAuth || app?.is_valid || app?.tested;
9880
+ if (valid === false) continue;
9881
+ const key = normalizeAgentAppName(name);
9882
+ if (seen.has(key)) continue;
9883
+ seen.add(key);
9884
+ loaded.push({
9885
+ name,
9886
+ id: app?.id || entry?.id,
9887
+ icon: app?.large_image || app?.image_url || app?.image || entry?.bestImage || ""
9888
+ });
9889
+ }
9890
+ if (signal?.cancelled) return;
9891
+ setAvailableApps(loaded);
9892
+ } catch {
9893
+ } finally {
9894
+ if (!signal?.cancelled) setAuthAppsLoading(false);
9895
+ }
9896
+ }, [resolveUrl2, resolveHeaders2]);
9591
9897
  (0, import_react15.useEffect)(() => {
9592
9898
  if (!autoLoadApps) return;
9593
- if (apps || defaultApps) return;
9594
9899
  if (!hasApiKey) return;
9595
- let cancelled = false;
9596
- (async () => {
9597
- try {
9598
- const resp = await fetch(resolveUrl2("/api/v1/apps/authentication"), {
9599
- credentials: "include",
9600
- headers: { ...resolveHeaders2() }
9601
- });
9602
- if (!resp.ok) return;
9603
- const result = await resp.json();
9604
- const list = Array.isArray(result) ? result : result?.data || [];
9605
- const seen = /* @__PURE__ */ new Set();
9606
- const loaded = [];
9607
- for (const entry of list) {
9608
- const app = entry?.app || entry;
9609
- const name = app?.name;
9610
- if (!name) continue;
9611
- const valid = entry?.active || entry?.validation?.valid || entry?.hasValidAuth;
9612
- if (valid === false) continue;
9613
- const key = name.toLowerCase();
9614
- if (seen.has(key)) continue;
9615
- seen.add(key);
9616
- loaded.push({
9617
- name,
9618
- id: app?.id || entry?.id,
9619
- icon: app?.large_image || app?.image_url || app?.image || entry?.bestImage || ""
9620
- });
9621
- }
9622
- if (!cancelled && loaded.length) setAvailableApps(loaded);
9623
- } catch {
9624
- }
9625
- })();
9900
+ const signal = { cancelled: false };
9901
+ loadAuthenticatedApps(signal);
9626
9902
  return () => {
9627
- cancelled = true;
9903
+ signal.cancelled = true;
9628
9904
  };
9629
- }, [autoLoadApps, apps, defaultApps, hasApiKey, resolveUrl2, resolveHeaders2]);
9905
+ }, [autoLoadApps, hasApiKey, loadAuthenticatedApps]);
9906
+ (0, import_react15.useEffect)(() => {
9907
+ if (!hasApiKey) return;
9908
+ const handler = () => {
9909
+ loadAuthenticatedApps();
9910
+ };
9911
+ window.addEventListener("integrations-changed", handler);
9912
+ return () => window.removeEventListener("integrations-changed", handler);
9913
+ }, [hasApiKey, loadAuthenticatedApps]);
9630
9914
  (0, import_react15.useEffect)(() => {
9631
9915
  const raw = agentData?.allowed_actions;
9632
9916
  if (!Array.isArray(raw) || raw.length === 0) {
@@ -10022,31 +10306,48 @@ var AgentUI = ({
10022
10306
  setAgentRequestLoading(false);
10023
10307
  }
10024
10308
  }, [execution, getExecution]);
10309
+ const resolveRunInput = (0, import_react15.useCallback)(() => {
10310
+ const fromData = agentData?.original_input;
10311
+ if (fromData && typeof fromData === "string") return fromData;
10312
+ if (actionInput && typeof actionInput === "string" && actionInput.trim()) return actionInput;
10313
+ const params = agentActionResult?.action?.parameters || [];
10314
+ const inputParam = params.find((p) => p?.name === "input");
10315
+ if (inputParam?.value && typeof inputParam.value === "string") return inputParam.value;
10316
+ const msgs = agentData?.input?.messages || [];
10317
+ const userMsg = msgs.find((mm) => mm?.role === "user");
10318
+ if (userMsg?.content && typeof userMsg.content === "string") return userMsg.content;
10319
+ const execArg = execution?.execution_argument;
10320
+ if (execArg && typeof execArg === "string") {
10321
+ try {
10322
+ const parsed = JSON.parse(execArg);
10323
+ if (parsed?.input && typeof parsed.input === "string") return parsed.input;
10324
+ if (parsed?.prompt && typeof parsed.prompt === "string") return parsed.prompt;
10325
+ } catch {
10326
+ if (execArg.length < 4e3) return execArg;
10327
+ }
10328
+ }
10329
+ return "";
10330
+ }, [agentData, actionInput, agentActionResult, execution]);
10025
10331
  const rerunAgent = (0, import_react15.useCallback)(() => {
10026
- const input = agentData?.original_input || actionInput || (() => {
10027
- const msgs = agentData?.input?.messages || [];
10028
- const m = msgs.find((m2) => m2?.role === "user" && !String(m2?.role).includes("USER CONTEXT"));
10029
- return m?.content || "";
10030
- })();
10332
+ const input = resolveRunInput();
10031
10333
  if (input && typeof input === "string") {
10032
10334
  setActionInput(input);
10033
10335
  }
10034
10336
  if (executionApps.length > 0) {
10035
10337
  setChosenApps(executionApps);
10036
10338
  }
10037
- if (disableStartTab) {
10038
- if (input && typeof input === "string" && input.trim().length >= 6) {
10039
- submitInput(input);
10040
- }
10041
- return;
10339
+ if (!disableStartTab) {
10340
+ setShowStarter(true);
10341
+ setSearchParams((prev) => {
10342
+ const next = new URLSearchParams(prev);
10343
+ next.delete("agentView");
10344
+ return next;
10345
+ }, { replace: true });
10042
10346
  }
10043
- setShowStarter(true);
10044
- setSearchParams((prev) => {
10045
- const next = new URLSearchParams(prev);
10046
- next.delete("agentView");
10047
- return next;
10048
- }, { replace: true });
10049
- }, [agentData, actionInput, executionApps, setSearchParams, disableStartTab, submitInput]);
10347
+ if (input && typeof input === "string" && input.trim().length >= 6) {
10348
+ submitInput(input);
10349
+ }
10350
+ }, [resolveRunInput, executionApps, setSearchParams, disableStartTab, submitInput]);
10050
10351
  const abortAgent = (0, import_react15.useCallback)(async () => {
10051
10352
  const execId = execution?.execution_id;
10052
10353
  const auth = execution?.authorization;
@@ -10296,13 +10597,12 @@ var AgentUI = ({
10296
10597
  (0, import_react15.useEffect)(() => {
10297
10598
  onViewChange?.(activeTab);
10298
10599
  }, [activeTab, onViewChange]);
10600
+ (0, import_react15.useEffect)(() => {
10601
+ onAppsChange?.(chosenApps);
10602
+ }, [chosenApps, onAppsChange]);
10299
10603
  const goToTab = (t) => {
10300
10604
  if (t === "start") {
10301
- const runInput = agentData?.original_input || (() => {
10302
- const msgs = agentData?.input?.messages || [];
10303
- const m = msgs.find((m2) => m2?.role === "user");
10304
- return m?.content || "";
10305
- })();
10605
+ const runInput = resolveRunInput();
10306
10606
  if (runInput && typeof runInput === "string") {
10307
10607
  setActionInput(runInput);
10308
10608
  }
@@ -10443,58 +10743,71 @@ var AgentUI = ({
10443
10743
  ] }, i)) })
10444
10744
  ] }) : scheduleDisabledReasons.length === 1 ? `Cannot schedule: ${scheduleDisabledReasons[0]}` : "";
10445
10745
  const tabBarRef = (0, import_react15.useRef)(null);
10446
- const tabBar = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
10746
+ const runStatusUpper = (execution?.status || agentData?.status || "").toUpperCase();
10747
+ const runIsActive = hasExecution && !["FINISHED", "FAILURE", "ABORTED", "CANCELLED", "CANCELED"].includes(runStatusUpper);
10748
+ const tabBar = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
10447
10749
  import_material16.Box,
10448
10750
  {
10449
10751
  ref: tabBarRef,
10450
10752
  sx: {
10451
10753
  display: "flex",
10452
10754
  alignItems: "center",
10755
+ gap: 1,
10453
10756
  width: "fit-content",
10454
10757
  alignSelf: "center",
10455
10758
  position: "sticky",
10456
10759
  top: 8,
10457
10760
  zIndex: 5
10458
10761
  },
10459
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
10460
- SegmentedControl,
10461
- {
10462
- layoutId: "agentui-view-switcher",
10463
- ariaLabel: "Agent view",
10464
- value: activeTab,
10465
- onChange: (v) => goToTab(v),
10466
- options: [
10467
- { value: "start", label: "Start", disabled: disableStartTab },
10468
- { value: "simple", label: "Simple", disabled: !hasExecution },
10469
- { value: "detailed", label: "Detailed", disabled: !hasExecution },
10470
- { type: "divider", key: "div" },
10471
- {
10472
- type: "action",
10473
- key: "reload",
10474
- label: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.RefreshCw, { size: 14 }),
10475
- title: "Reload execution data",
10476
- disabled: !hasExecution,
10477
- onClick: () => {
10478
- if (execution?.execution_id && execution?.authorization) {
10479
- getExecution(execution.execution_id, execution.authorization);
10762
+ children: [
10763
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
10764
+ SegmentedControl,
10765
+ {
10766
+ layoutId: "agentui-view-switcher",
10767
+ ariaLabel: "Agent view",
10768
+ value: activeTab,
10769
+ onChange: (v) => goToTab(v),
10770
+ options: [
10771
+ { value: "start", label: "Start", disabled: disableStartTab, title: disableStartTab ? "Open a new agent run from the /agents page to start a new prompt" : void 0 },
10772
+ { value: "simple", label: "Simple", disabled: !hasExecution },
10773
+ { value: "detailed", label: "Detailed", disabled: !hasExecution },
10774
+ { type: "divider", key: "div" },
10775
+ {
10776
+ type: "action",
10777
+ key: "reload",
10778
+ label: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.RefreshCw, { size: 14 }),
10779
+ title: "Reload execution data",
10780
+ disabled: !hasExecution,
10781
+ onClick: () => {
10782
+ if (execution?.execution_id && execution?.authorization) {
10783
+ getExecution(execution.execution_id, execution.authorization);
10784
+ }
10480
10785
  }
10481
- }
10482
- },
10483
- {
10484
- type: "action",
10485
- key: "schedule",
10486
- label: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Clock, { size: 14 }),
10487
- title: scheduleDisabledReason ? `Cannot schedule: ${scheduleDisabledReason}` : "Schedule this prompt to run repeatedly on a cron schedule",
10488
- disabled: Boolean(scheduleDisabledReason),
10489
- onClick: () => {
10490
- if (!scheduleDisabledReason && tabBarRef.current) {
10491
- setScheduleAnchor(tabBarRef.current);
10786
+ },
10787
+ {
10788
+ type: "action",
10789
+ key: "schedule",
10790
+ label: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Clock, { size: 14 }),
10791
+ title: scheduleDisabledReason ? `Cannot schedule: ${scheduleDisabledReason}` : "Schedule this prompt to run repeatedly on a cron schedule",
10792
+ disabled: Boolean(scheduleDisabledReason),
10793
+ onClick: () => {
10794
+ if (!scheduleDisabledReason && tabBarRef.current) {
10795
+ setScheduleAnchor(tabBarRef.current);
10796
+ }
10492
10797
  }
10493
10798
  }
10494
- }
10495
- ]
10496
- }
10497
- )
10799
+ ]
10800
+ }
10801
+ ),
10802
+ runIsActive && activeTab === "start" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Tooltip, { title: "Current agent run is still in progress", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
10803
+ import_material16.CircularProgress,
10804
+ {
10805
+ size: 16,
10806
+ thickness: 5,
10807
+ sx: { color: "hsl(var(--muted-foreground))" }
10808
+ }
10809
+ ) })
10810
+ ]
10498
10811
  }
10499
10812
  );
10500
10813
  const schedulePopover = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
@@ -11226,9 +11539,9 @@ var AgentUI = ({
11226
11539
  }
11227
11540
  ) }),
11228
11541
  chosenApps.map((app, i) => {
11229
- const slug = (app.name || "").toLowerCase().replace(/[\s-]+/g, "_");
11542
+ const slug = normalizeAgentAppName(app.name || "");
11230
11543
  const NO_AUTH = /* @__PURE__ */ new Set(["http", "shuffle_tools", "shuffle-tools", "tools", "singul", "core", "webhook", "email"]);
11231
- const needsAuth = !NO_AUTH.has(slug) && !isAppAuthenticated(app.name || "");
11544
+ const needsAuth = !authAppsLoading && !NO_AUTH.has(slug) && !isAppAuthenticated(app.name || "", app.id || null);
11232
11545
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
11233
11546
  import_material16.Tooltip,
11234
11547
  {
@@ -11289,9 +11602,10 @@ var AgentUI = ({
11289
11602
  ] }) }),
11290
11603
  !hideAppPicker && (() => {
11291
11604
  const NO_AUTH = /* @__PURE__ */ new Set(["http", "shuffle_tools", "shuffle-tools", "tools", "singul", "core", "webhook", "email"]);
11605
+ if (authAppsLoading) return null;
11292
11606
  const unauthed = chosenApps.filter((a) => {
11293
- const slug = (a.name || "").toLowerCase().replace(/[\s-]+/g, "_");
11294
- return !NO_AUTH.has(slug) && !isAppAuthenticated(a.name || "");
11607
+ const slug = normalizeAgentAppName(a.name || "");
11608
+ return !NO_AUTH.has(slug) && !isAppAuthenticated(a.name || "", a.id || null);
11295
11609
  });
11296
11610
  if (unauthed.length === 0) return null;
11297
11611
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { display: "flex", justifyContent: "center", mt: -0.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: {
@@ -11361,7 +11675,7 @@ var AgentUI = ({
11361
11675
  src: app.icon || void 0,
11362
11676
  alt: app.name,
11363
11677
  variant: "rounded",
11364
- onClick: () => navigate(`/apps/${encodeURIComponent((app.name || "").toLowerCase().replace(/\s+/g, "_"))}`),
11678
+ onClick: () => setAuthDrawerApp({ name: app.name, id: app.id || null }),
11365
11679
  sx: {
11366
11680
  bgcolor: "hsl(var(--muted))",
11367
11681
  cursor: "pointer",
@@ -11493,133 +11807,88 @@ var AgentUI = ({
11493
11807
  }
11494
11808
  const pendingAnswered = pendingQuestions.every((q) => questionAnswers[q.question]?.value);
11495
11809
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
11496
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
11497
- isRunning ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.CircularProgress, { size: 16, sx: { color: "hsl(var(--primary))" } }) : status === "FINISHED" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.CheckCircle2, { size: 18, color: "hsl(142 70% 45%)" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.AlertCircle, { size: 18, color: "hsl(var(--destructive))" }),
11498
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.9rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: isRunning ? "Agent is working\u2026" : status === "FINISHED" ? "Run finished" : `Run ${status.toLowerCase()}` }),
11499
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
11810
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
11811
+ RunFinishedSummary,
11812
+ {
11813
+ status,
11814
+ isRunning,
11815
+ finishAnswer,
11816
+ raw: finishAnswerRaw,
11817
+ onToggleRaw: () => setFinishAnswerRaw((v) => !v),
11500
11818
  decisionCount,
11501
- " step",
11502
- decisionCount === 1 ? "" : "s",
11503
- durationSec != null ? ` \xB7 ${Math.round(durationSec)}s` : ""
11504
- ] }),
11505
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { flexGrow: 1 } })
11506
- ] }),
11507
- pendingAuthApps.map(({ appName, appId, icon }) => {
11508
- const pretty = appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
11509
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
11510
- import_material16.Box,
11511
- {
11512
- sx: {
11513
- display: "flex",
11514
- alignItems: "center",
11515
- gap: 1.5,
11516
- p: 1.5,
11517
- borderRadius: 1.5,
11518
- border: "1px solid hsla(var(--severity-medium) / 0.3)",
11519
- bgcolor: "hsla(var(--severity-medium) / 0.08)"
11520
- },
11521
- children: [
11522
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Lock, { size: 22, color: "hsl(var(--severity-medium))" }),
11523
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { flex: 1, minWidth: 0 }, children: [
11524
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
11525
- pretty,
11526
- " requires authentication"
11527
- ] }),
11528
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
11529
- "Connect your ",
11530
- pretty,
11531
- " account so the agent can complete this step, then rerun."
11532
- ] })
11533
- ] }),
11534
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
11535
- import_material16.Button,
11536
- {
11537
- variant: "outlined",
11538
- size: "small",
11539
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
11540
- import_material16.Avatar,
11819
+ durationSec,
11820
+ showMeta: true,
11821
+ children: pendingAuthApps.map(({ appName, appId, icon }) => {
11822
+ const pretty = appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
11823
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
11824
+ import_material16.Box,
11825
+ {
11826
+ sx: {
11827
+ display: "flex",
11828
+ alignItems: "center",
11829
+ gap: 1.5,
11830
+ p: 1.5,
11831
+ borderRadius: 1.5,
11832
+ border: "1px solid hsla(var(--severity-medium) / 0.3)",
11833
+ bgcolor: "hsla(var(--severity-medium) / 0.08)"
11834
+ },
11835
+ children: [
11836
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Lock, { size: 22, color: "hsl(var(--severity-medium))" }),
11837
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { flex: 1, minWidth: 0 }, children: [
11838
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
11839
+ pretty,
11840
+ " requires authentication"
11841
+ ] }),
11842
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
11843
+ "Connect your ",
11844
+ pretty,
11845
+ " account so the agent can complete this step, then rerun."
11846
+ ] })
11847
+ ] }),
11848
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
11849
+ import_material16.Button,
11541
11850
  {
11542
- src: icon || void 0,
11543
- alt: "",
11544
- variant: "rounded",
11851
+ variant: "outlined",
11852
+ size: "small",
11853
+ startIcon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
11854
+ import_material16.Avatar,
11855
+ {
11856
+ src: icon || void 0,
11857
+ alt: "",
11858
+ variant: "rounded",
11859
+ sx: {
11860
+ width: 18,
11861
+ height: 18,
11862
+ borderRadius: 0.5,
11863
+ bgcolor: "hsl(var(--background) / 0.4)",
11864
+ color: "hsl(var(--background))",
11865
+ fontSize: "0.7rem",
11866
+ fontWeight: 700,
11867
+ "& img": { objectFit: "contain" }
11868
+ },
11869
+ children: pretty.charAt(0)
11870
+ }
11871
+ ),
11872
+ onClick: () => setAuthDrawerApp({ name: appName, id: appId }),
11545
11873
  sx: {
11546
- width: 18,
11547
- height: 18,
11548
- borderRadius: 0.5,
11549
- bgcolor: "hsl(var(--background) / 0.4)",
11550
- color: "hsl(var(--background))",
11551
- fontSize: "0.7rem",
11552
- fontWeight: 700,
11553
- "& img": { objectFit: "contain" }
11874
+ height: 36,
11875
+ textTransform: "none",
11876
+ fontWeight: 600
11554
11877
  },
11555
- children: pretty.charAt(0)
11878
+ children: [
11879
+ "Authenticate ",
11880
+ pretty
11881
+ ]
11556
11882
  }
11557
- ),
11558
- onClick: () => setAuthDrawerApp({ name: appName, id: appId }),
11559
- sx: {
11560
- height: 36,
11561
- textTransform: "none",
11562
- fontWeight: 600
11563
- },
11564
- children: [
11565
- "Authenticate ",
11566
- pretty
11567
- ]
11568
- }
11569
- )
11570
- ]
11571
- },
11572
- `auth-${appName}`
11573
- );
11574
- }),
11575
- finishAnswer ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
11576
- p: 2,
11577
- borderRadius: 1.5,
11578
- border: "1px solid hsl(var(--border))",
11579
- bgcolor: "hsl(var(--background))",
11580
- fontSize: "0.9rem",
11581
- color: "hsl(var(--foreground))",
11582
- "& > *:first-of-type": { mt: 0 },
11583
- "& > *:last-child": { mb: 0 },
11584
- "& p": { my: 1, lineHeight: 1.55 },
11585
- "& h1, & h2, & h3, & h4": { mt: 2, mb: 1, fontWeight: 600, lineHeight: 1.3 },
11586
- "& h1": { fontSize: "1.15rem" },
11587
- "& h2": { fontSize: "1.05rem" },
11588
- "& h3, & h4": { fontSize: "0.95rem" },
11589
- "& ul": { my: 1, pl: 3, listStyleType: "disc", listStylePosition: "outside" },
11590
- "& ol": { my: 1, pl: 3, listStyleType: "decimal", listStylePosition: "outside" },
11591
- "& ul ul": { listStyleType: "circle" },
11592
- "& ul ul ul": { listStyleType: "square" },
11593
- "& li": { my: 0.25, display: "list-item" },
11594
- "& li::marker": { color: "hsl(var(--muted-foreground))" },
11595
- "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
11596
- "& code": {
11597
- px: 0.5,
11598
- py: 0.125,
11599
- borderRadius: 0.5,
11600
- bgcolor: "hsl(var(--muted))",
11601
- fontFamily: '"JetBrains Mono", ui-monospace, monospace',
11602
- fontSize: "0.82em"
11603
- },
11604
- "& pre": {
11605
- p: 1.5,
11606
- my: 1,
11607
- borderRadius: 1,
11608
- bgcolor: "hsl(var(--muted))",
11609
- overflowX: "auto",
11610
- fontSize: "0.82rem"
11611
- },
11612
- "& pre code": { p: 0, bgcolor: "transparent" },
11613
- "& blockquote": {
11614
- borderLeft: "3px solid hsl(var(--border))",
11615
- pl: 1.5,
11616
- my: 1,
11617
- color: "hsl(var(--muted-foreground))"
11618
- },
11619
- "& table": { borderCollapse: "collapse", my: 1, fontSize: "0.85rem" },
11620
- "& th, & td": { border: "1px solid hsl(var(--border))", px: 1, py: 0.5 },
11621
- "& hr": { border: 0, borderTop: "1px solid hsl(var(--border))", my: 1.5 }
11622
- }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_markdown4.default, { remarkPlugins: [import_remark_gfm4.default, import_remark_breaks.default], children: normalizeMarkdown(finishAnswer) }) }) : pendingAsk && pendingQuestions.length > 0 ? (() => {
11883
+ )
11884
+ ]
11885
+ },
11886
+ `auth-${appName}`
11887
+ );
11888
+ })
11889
+ }
11890
+ ),
11891
+ !finishAnswer && pendingAsk && pendingQuestions.length > 0 ? (() => {
11623
11892
  const trySimpleSubmit = () => {
11624
11893
  if (agentRequestLoading) return;
11625
11894
  if (!pendingAnswered) {
@@ -11691,7 +11960,7 @@ var AgentUI = ({
11691
11960
  ) })
11692
11961
  ] })
11693
11962
  ] });
11694
- })() : isRunning ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "Waiting for the agent to produce the first step." }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "No final answer was returned. Open Detailed to inspect each step." }),
11963
+ })() : !finishAnswer && isRunning ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "Waiting for the agent to produce the first step." }) : !finishAnswer ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.85rem", color: "hsl(var(--muted-foreground))" }, children: "No final answer was returned. Open Detailed to inspect each step." }) : null,
11695
11964
  !isRunning && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
11696
11965
  import_material16.Button,
11697
11966
  {
@@ -11737,53 +12006,32 @@ var AgentUI = ({
11737
12006
  getFormUrl,
11738
12007
  runFinished: detailedRunFinished,
11739
12008
  onAuthenticateApp: (name, id) => setAuthDrawerApp({ name, id }),
12009
+ onRefreshAuthenticatedApps: () => {
12010
+ loadAuthenticatedApps();
12011
+ },
11740
12012
  isAppAuthenticated,
12013
+ authAppsLoading,
11741
12014
  highlight: highlightedIndex === i
11742
12015
  },
11743
12016
  i
11744
12017
  )),
11745
- detailedRunFinished && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: {
12018
+ detailedRunFinished && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
11746
12019
  borderTop: "1px solid hsl(var(--border))",
11747
12020
  p: 2.5,
11748
12021
  display: "flex",
11749
12022
  flexDirection: "column",
11750
12023
  gap: 1.5,
11751
12024
  bgcolor: "hsl(var(--muted) / 0.2)"
11752
- }, children: [
11753
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
11754
- detailedStatus === "FINISHED" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.CheckCircle2, { size: 18, color: "hsl(142 70% 45%)" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.AlertCircle, { size: 18, color: "hsl(var(--destructive))" }),
11755
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Typography, { sx: { fontSize: "0.9rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: detailedStatus === "FINISHED" ? "Run finished" : `Run ${detailedStatus.toLowerCase()}` })
11756
- ] }),
11757
- finishAnswer && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
11758
- p: 2,
11759
- borderRadius: 1.5,
11760
- border: "1px solid hsl(var(--border))",
11761
- bgcolor: "hsl(var(--background))",
11762
- fontSize: "0.9rem",
11763
- color: "hsl(var(--foreground))",
11764
- "& > *:first-of-type": { mt: 0 },
11765
- "& > *:last-child": { mb: 0 },
11766
- "& p": { my: 1, lineHeight: 1.55 },
11767
- "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
11768
- "& code": {
11769
- px: 0.5,
11770
- py: 0.125,
11771
- borderRadius: 0.5,
11772
- bgcolor: "hsl(var(--muted))",
11773
- fontFamily: '"JetBrains Mono", ui-monospace, monospace',
11774
- fontSize: "0.82em"
11775
- },
11776
- "& pre": {
11777
- p: 1.5,
11778
- my: 1,
11779
- borderRadius: 1,
11780
- bgcolor: "hsl(var(--muted))",
11781
- overflowX: "auto",
11782
- fontSize: "0.82rem"
11783
- },
11784
- "& pre code": { p: 0, bgcolor: "transparent" }
11785
- }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_markdown4.default, { remarkPlugins: [import_remark_gfm4.default, import_remark_breaks.default], children: normalizeMarkdown(finishAnswer) }) })
11786
- ] })
12025
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
12026
+ RunFinishedSummary,
12027
+ {
12028
+ status: detailedStatus,
12029
+ isRunning: false,
12030
+ finishAnswer,
12031
+ raw: finishAnswerRaw,
12032
+ onToggleRaw: () => setFinishAnswerRaw((v) => !v)
12033
+ }
12034
+ ) })
11787
12035
  ] }) });
11788
12036
  })(),
11789
12037
  finishDecisionId && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { mt: 3, display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { width: "100%", maxWidth: 640 }, children: [
@@ -11887,6 +12135,9 @@ var AgentUI = ({
11887
12135
  {
11888
12136
  open: !!authDrawerApp,
11889
12137
  onClose: () => setAuthDrawerApp(null),
12138
+ onRefresh: () => {
12139
+ loadAuthenticatedApps();
12140
+ },
11890
12141
  appName: authDrawerApp?.name || null,
11891
12142
  appId: authDrawerApp?.id || null,
11892
12143
  activeOrgId: orgId || null,
@@ -12021,15 +12272,16 @@ var OPENAI_ALGOLIA_APP = {
12021
12272
  };
12022
12273
  var ENDPOINT_PRESETS = [
12023
12274
  { label: SHUFFLE_AI_PRESET, url: "" },
12024
- { label: "OpenAI", url: "https://api.openai.com/v1" },
12025
- { label: "Anthropic", url: "https://api.anthropic.com/v1/" },
12026
- { label: "Google Gemini", url: "https://generativelanguage.googleapis.com/v1beta/openai/" },
12027
- { label: "Mistral", url: "https://api.mistral.ai/v1" },
12028
- { label: "Groq", url: "https://api.groq.com/openai/v1" },
12029
- { label: "Together AI", url: "https://api.together.xyz/v1" },
12030
- { label: "OpenRouter", url: "https://openrouter.ai/api/v1" },
12031
- { label: "Ollama (localhost)", url: "http://localhost:11434/v1" },
12032
- { label: "LM Studio (localhost)", url: "http://localhost:1234/v1" },
12275
+ { 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." },
12276
+ { 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." },
12277
+ { 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." },
12278
+ { 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." },
12279
+ { 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." },
12280
+ { 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." },
12281
+ { 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." },
12282
+ { label: "OpenRouter", url: "https://openrouter.ai/api/v1", apiKeyUrl: "https://openrouter.ai/keys", apiKeyHint: "Create a key under Keys in your OpenRouter dashboard." },
12283
+ { label: "Ollama (localhost)", url: "http://localhost:11434/v1", apiKeyHint: "Local Ollama does not require an API key \u2014 any non-empty value works." },
12284
+ { 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." },
12033
12285
  { label: CUSTOM_PRESET, url: "" }
12034
12286
  ];
12035
12287
  var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serverside, theme, colorMode }) => {
@@ -12188,12 +12440,29 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12188
12440
  }
12189
12441
  )
12190
12442
  ] }),
12191
- !compact && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { sx: { px: 2.5, py: 2, borderRadius: 2, border: "1px solid hsl(var(--border))", bgcolor: "hsl(var(--muted) / 0.3)" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Typography, { sx: { fontSize: "0.8rem", color: "hsl(var(--muted-foreground))", lineHeight: 1.5 }, children: [
12192
- 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.",
12193
- " ",
12194
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { 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" }),
12195
- "."
12196
- ] }) }),
12443
+ !compact && (() => {
12444
+ const preset = ENDPOINT_PRESETS.find((p) => p.label === effectivePreset);
12445
+ const hasProviderDocs = !!preset && (!!preset.apiKeyUrl || !!preset.apiKeyHint);
12446
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { sx: { px: 2.5, py: 2, borderRadius: 2, border: "1px solid hsl(var(--border))", bgcolor: "hsl(var(--muted) / 0.3)" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Typography, { sx: { fontSize: "0.8rem", color: "hsl(var(--muted-foreground))", lineHeight: 1.5 }, children: isShuffleAI ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
12447
+ "Using Shuffle AI. No configuration is required. Pick another provider above to use your own endpoint.",
12448
+ " ",
12449
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { 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" }),
12450
+ "."
12451
+ ] }) : hasProviderDocs ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
12452
+ preset.apiKeyHint,
12453
+ " ",
12454
+ preset.apiKeyUrl && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { component: "a", href: preset.apiKeyUrl, target: "_blank", rel: "noopener noreferrer", sx: { color: "hsl(var(--primary))", textDecoration: "underline" }, children: [
12455
+ "Get your ",
12456
+ preset.label,
12457
+ " API key \u2192"
12458
+ ] })
12459
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
12460
+ "Configure an OpenAI-compatible endpoint for agent operations. Credentials are saved through the app authentication system.",
12461
+ " ",
12462
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { 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" }),
12463
+ "."
12464
+ ] }) }) });
12465
+ })(),
12197
12466
  isShuffleAI && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { sx: { display: "flex", flexDirection: "column", gap: 0.75, mt: 0.5, width: "100%" }, children: [
12198
12467
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(UsageBar, { label: "App runs", usage: appRunUsage, limit: appRunLimit, unit: "runs", actionLabel: "Upgrade", actionHref: "https://shuffler.io/pricing" }),
12199
12468
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(UsageBar, { label: "Agent tokens", usage: agentTokenUsage, limit: agentTokenLimit, unit: "tokens", actionLabel: "Upgrade", actionHref: "https://shuffler.io/pricing" })
@@ -12476,6 +12745,7 @@ var AgentRunDrawer_default = AgentRunDrawer;
12476
12745
 
12477
12746
  // components/AgentActivityList.tsx
12478
12747
  var import_react19 = require("react");
12748
+ var import_react_router_dom3 = require("react-router-dom");
12479
12749
  var import_material20 = require("@mui/material");
12480
12750
  var import_lucide_react13 = require("lucide-react");
12481
12751
 
@@ -12766,6 +13036,8 @@ var stopAgentSchedule = async (workflowId, params = {}) => {
12766
13036
  };
12767
13037
 
12768
13038
  // components/AgentActivityList.tsx
13039
+ init_api();
13040
+ init_appsCache();
12769
13041
  var import_lucide_react14 = require("lucide-react");
12770
13042
  var import_jsx_runtime24 = require("react/jsx-runtime");
12771
13043
  var STATUS_CONFIG = {
@@ -12835,21 +13107,110 @@ var getTimeAgo = (dateStr) => {
12835
13107
  return dateStr;
12836
13108
  }
12837
13109
  };
12838
- var getRunTitle = (run) => {
12839
- if (run.workflow?.name) return run.workflow.name;
12840
- if (run.execution_argument) {
12841
- try {
12842
- const parsed = JSON.parse(run.execution_argument);
12843
- if (parsed.title) return parsed.title;
12844
- if (parsed.action) return parsed.action;
12845
- if (parsed.name) return parsed.name;
12846
- } catch {
12847
- const clean = run.execution_argument.replace(/[{}"]/g, "").trim();
12848
- if (clean.length > 0 && clean.length < 80) return clean;
13110
+ var PROMPT_KEYS = [
13111
+ "original_input",
13112
+ "originalinput",
13113
+ "input",
13114
+ "prompt",
13115
+ "user_input",
13116
+ "userinput",
13117
+ "user_prompt",
13118
+ "userprompt",
13119
+ "question",
13120
+ "query",
13121
+ "message",
13122
+ "text",
13123
+ "content",
13124
+ "task",
13125
+ "instruction",
13126
+ "instructions"
13127
+ ];
13128
+ var deepFindPrompt = (value, depth = 0) => {
13129
+ if (value == null || depth > 6) return null;
13130
+ if (typeof value === "string") {
13131
+ const s = value.trim();
13132
+ if (s.startsWith("{") && s.endsWith("}") || s.startsWith("[") && s.endsWith("]")) {
13133
+ try {
13134
+ return deepFindPrompt(JSON.parse(s), depth + 1);
13135
+ } catch {
13136
+ }
13137
+ }
13138
+ return null;
13139
+ }
13140
+ if (Array.isArray(value)) {
13141
+ for (const item of value) {
13142
+ const hit = deepFindPrompt(item, depth + 1);
13143
+ if (hit) return hit;
13144
+ }
13145
+ return null;
13146
+ }
13147
+ if (typeof value === "object") {
13148
+ const obj = value;
13149
+ for (const key of Object.keys(obj)) {
13150
+ if (PROMPT_KEYS.includes(key.toLowerCase())) {
13151
+ const v = obj[key];
13152
+ if (typeof v === "string" && v.trim()) return v.trim();
13153
+ const nested = deepFindPrompt(v, depth + 1);
13154
+ if (nested) return nested;
13155
+ }
13156
+ }
13157
+ for (const key of Object.keys(obj)) {
13158
+ if (PROMPT_KEYS.includes(key.toLowerCase())) continue;
13159
+ const hit = deepFindPrompt(obj[key], depth + 1);
13160
+ if (hit) return hit;
12849
13161
  }
12850
13162
  }
13163
+ return null;
13164
+ };
13165
+ var tryParseJson = (s) => {
13166
+ if (typeof s !== "string") return s;
13167
+ const trimmed = s.trim();
13168
+ if (!trimmed) return null;
13169
+ try {
13170
+ return JSON.parse(trimmed);
13171
+ } catch {
13172
+ return trimmed;
13173
+ }
13174
+ };
13175
+ var getRunPrompt = (run) => {
13176
+ const results = Array.isArray(run.results) ? run.results : null;
13177
+ if (results) {
13178
+ const agentResult = results.find((r) => r?.action?.app_name === "AI Agent");
13179
+ if (agentResult?.result) {
13180
+ const hit = deepFindPrompt(tryParseJson(agentResult.result));
13181
+ if (hit) return hit;
13182
+ }
13183
+ for (const r of results) {
13184
+ if (r === agentResult) continue;
13185
+ const hit = deepFindPrompt(tryParseJson(r?.result));
13186
+ if (hit) return hit;
13187
+ }
13188
+ }
13189
+ if (run.result) {
13190
+ const hit = deepFindPrompt(tryParseJson(run.result));
13191
+ if (hit) return hit;
13192
+ }
13193
+ if (run.execution_argument) {
13194
+ const parsed = tryParseJson(run.execution_argument);
13195
+ const hit = deepFindPrompt(parsed);
13196
+ if (hit) return hit;
13197
+ if (typeof parsed === "string" && parsed.length < 240) return parsed;
13198
+ }
13199
+ return null;
13200
+ };
13201
+ var getRunTitle = (run) => {
13202
+ const prompt = getRunPrompt(run);
13203
+ if (prompt) {
13204
+ const oneLine = prompt.replace(/\s+/g, " ").trim();
13205
+ return oneLine.length > 80 ? oneLine.slice(0, 80) + "\u2026" : oneLine;
13206
+ }
13207
+ if (run.workflow?.name) return run.workflow.name;
12851
13208
  return `Execution ${run.execution_id?.slice(0, 8) || "\u2014"}`;
12852
13209
  };
13210
+ var getDecisionCount = (run) => {
13211
+ if (Array.isArray(run.decisions)) return run.decisions.length;
13212
+ return 0;
13213
+ };
12853
13214
  var getRunSubtitle = (run) => {
12854
13215
  if (run.result) {
12855
13216
  try {
@@ -12867,30 +13228,82 @@ var getRunSubtitle = (run) => {
12867
13228
  }
12868
13229
  return run.execution_source || "Agent execution";
12869
13230
  };
13231
+ var normalizeResultStatus = (s) => {
13232
+ const v = (s || "").toUpperCase();
13233
+ if (v === "SUCCESS" || v === "FINISHED") return "success";
13234
+ if (v === "FAILURE" || v === "FAILED" || v === "ABORTED") return "failure";
13235
+ if (v === "WAITING" || v === "SKIPPED") return "waiting";
13236
+ return "unknown";
13237
+ };
12870
13238
  var getRunTools = (run) => {
12871
- const out = /* @__PURE__ */ new Set();
12872
- const add = (v) => {
12873
- if (!v) return;
12874
- const s = String(v).trim();
12875
- if (!s) return;
12876
- if (/^(ai\s*agent|shuffle\s*agent|shuffle_agent)$/i.test(s)) return;
12877
- out.add(s);
13239
+ const map = /* @__PURE__ */ new Map();
13240
+ const ids = /* @__PURE__ */ new Map();
13241
+ const skip = (s) => /^(ai\s*agent|shuffle\s*agent|shuffle_agent)$/i.test(s);
13242
+ const rank = { failure: 3, waiting: 2, success: 1, unknown: 0 };
13243
+ const merge2 = (name, status, id) => {
13244
+ if (!name) return;
13245
+ const s = String(name).trim();
13246
+ if (!s || skip(s)) return;
13247
+ const next = status || "unknown";
13248
+ const prev = map.get(s);
13249
+ if (!prev || rank[next] > rank[prev]) map.set(s, next);
13250
+ if (id && !ids.has(s)) ids.set(s, id);
12878
13251
  };
12879
- (run.results || []).forEach((r) => {
12880
- add(r?.action?.app_name);
12881
- if (!r?.action?.app_name) add(r?.action?.label);
12882
- });
12883
- (run.decisions || []).forEach((d) => {
12884
- add(typeof d?.tool === "string" ? d.tool : void 0);
12885
- });
12886
- return Array.from(out).slice(0, 6);
13252
+ const allowed = run.allowed_actions;
13253
+ if (Array.isArray(allowed) && allowed.length > 0) {
13254
+ for (const entry of allowed) {
13255
+ if (typeof entry !== "string") continue;
13256
+ const parts = entry.split(":");
13257
+ if (parts.length < 3 || parts[0] !== "app") continue;
13258
+ const id = parts[1];
13259
+ const name = parts.slice(2).join(":");
13260
+ merge2(name, "unknown", id);
13261
+ }
13262
+ const normalize = (s) => s.toLowerCase().replace(/[\s_-]+/g, "_");
13263
+ const known = /* @__PURE__ */ new Map();
13264
+ for (const real of map.keys()) known.set(normalize(real), real);
13265
+ const apply = (name, status) => {
13266
+ if (!name) return;
13267
+ const hit = known.get(normalize(name));
13268
+ if (hit) merge2(hit, status);
13269
+ };
13270
+ (run.results || []).forEach((r) => {
13271
+ apply(r?.action?.app_name || r?.action?.label, normalizeResultStatus(r?.status));
13272
+ });
13273
+ (run.decisions || []).forEach((d) => {
13274
+ if (typeof d?.tool === "string") apply(d.tool, normalizeResultStatus(d?.status));
13275
+ });
13276
+ } else {
13277
+ (run.results || []).forEach((r) => {
13278
+ merge2(r?.action?.app_name || r?.action?.label, normalizeResultStatus(r?.status));
13279
+ });
13280
+ (run.decisions || []).forEach((d) => {
13281
+ if (typeof d?.tool === "string") merge2(d.tool, normalizeResultStatus(d?.status));
13282
+ });
13283
+ }
13284
+ return Array.from(map.entries()).slice(0, 6).map(([name, status]) => ({ name, status, id: ids.get(name) }));
13285
+ };
13286
+ var TOOL_STATUS_RING = {
13287
+ success: "hsl(var(--severity-low, 142 71% 45%))",
13288
+ failure: "hsl(var(--severity-critical, 0 72% 55%))",
13289
+ waiting: "hsl(var(--severity-medium, 38 92% 50%))",
13290
+ unknown: "hsl(var(--border))"
13291
+ };
13292
+ var TOOL_STATUS_LABEL = {
13293
+ success: "ran successfully",
13294
+ failure: "failed",
13295
+ waiting: "needs input",
13296
+ unknown: "used"
12887
13297
  };
12888
- var AgentRunRow = ({ run, onClick, sx }) => {
13298
+ var normToolKey = (s) => s.toLowerCase().replace(/[\s_\-]+/g, "_");
13299
+ var AgentRunRow = ({ run, onClick, sx, appIcons, onAppClick }) => {
13300
+ const navigate = (0, import_react_router_dom3.useNavigate)();
12889
13301
  const statusKey = getEffectiveStatus(run);
12890
13302
  const cfg = STATUS_CONFIG[statusKey] || STATUS_CONFIG.WAITING;
12891
13303
  const iconColor = getRunIconColor(run);
12892
13304
  const duration = formatDuration(run);
12893
13305
  const tools = getRunTools(run);
13306
+ const decisionCount = getDecisionCount(run);
12894
13307
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
12895
13308
  import_material20.Box,
12896
13309
  {
@@ -12968,42 +13381,80 @@ var AgentRunRow = ({ run, onClick, sx }) => {
12968
13381
  duration && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
12969
13382
  /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Typography, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
12970
13383
  /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Typography, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.7 }, children: duration })
13384
+ ] }),
13385
+ decisionCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
13386
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Typography, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
13387
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_material20.Box, { sx: { display: "inline-flex", alignItems: "center", gap: 0.5, color: "hsl(var(--muted-foreground))", opacity: 0.7 }, children: [
13388
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react13.GitBranch, { size: 11 }),
13389
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_material20.Typography, { sx: { fontSize: "0.72rem", color: "inherit" }, children: [
13390
+ decisionCount,
13391
+ " ",
13392
+ decisionCount === 1 ? "decision" : "decisions"
13393
+ ] })
13394
+ ] })
12971
13395
  ] })
12972
13396
  ] })
12973
13397
  ] }),
12974
13398
  tools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12975
13399
  import_material20.Box,
12976
13400
  {
13401
+ onClick: (e) => e.stopPropagation(),
12977
13402
  sx: {
12978
13403
  display: { xs: "none", sm: "flex" },
12979
13404
  alignItems: "center",
12980
- gap: 0.5,
12981
- flexWrap: "wrap",
12982
- justifyContent: "flex-end",
12983
- maxWidth: 220,
12984
- flexShrink: 0
13405
+ flexShrink: 0,
13406
+ ml: 1
12985
13407
  },
12986
- children: tools.map((t) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Tooltip, { title: t, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12987
- import_material20.Chip,
13408
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13409
+ import_material20.AvatarGroup,
12988
13410
  {
12989
- label: t,
12990
- size: "small",
13411
+ max: 5,
12991
13412
  sx: {
12992
- height: 20,
12993
- fontSize: "0.68rem",
12994
- maxWidth: 120,
12995
- bgcolor: "hsla(var(--muted) / 0.5)",
12996
- color: "hsl(var(--muted-foreground))",
12997
- border: "1px solid hsl(var(--border))",
12998
- "& .MuiChip-label": {
12999
- px: 0.75,
13000
- overflow: "hidden",
13001
- textOverflow: "ellipsis",
13002
- whiteSpace: "nowrap"
13413
+ "& .MuiAvatar-root": {
13414
+ width: 28,
13415
+ height: 28,
13416
+ fontSize: "0.7rem",
13417
+ borderColor: "hsl(var(--border))",
13418
+ bgcolor: "hsl(var(--muted))",
13419
+ color: "hsl(var(--muted-foreground))"
13003
13420
  }
13004
- }
13421
+ },
13422
+ children: tools.map((t) => {
13423
+ const icon = appIcons?.[normToolKey(t.name)];
13424
+ const label = t.name.replace(/_/g, " ");
13425
+ const slug = t.name.toLowerCase().replace(/\s+/g, "_");
13426
+ const ring = TOOL_STATUS_RING[t.status];
13427
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Tooltip, { title: `${label} \u2014 ${TOOL_STATUS_LABEL[t.status]}`, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13428
+ import_material20.Avatar,
13429
+ {
13430
+ src: icon || void 0,
13431
+ alt: label,
13432
+ variant: "rounded",
13433
+ onClick: (e) => {
13434
+ e.stopPropagation();
13435
+ if (onAppClick) {
13436
+ onAppClick({ id: t.id, name: t.name });
13437
+ } else {
13438
+ navigate(`/apps/${encodeURIComponent(slug)}`);
13439
+ }
13440
+ },
13441
+ sx: {
13442
+ cursor: "pointer",
13443
+ borderColor: `${ring} !important`,
13444
+ borderWidth: t.status === "unknown" ? "1px" : "2px",
13445
+ borderStyle: "solid",
13446
+ transition: "transform 0.15s ease, border-color 0.15s ease",
13447
+ "&:hover": {
13448
+ transform: "scale(1.08)",
13449
+ borderColor: "hsl(var(--primary)) !important"
13450
+ }
13451
+ },
13452
+ children: label.charAt(0).toUpperCase()
13453
+ }
13454
+ ) }, t.name);
13455
+ })
13005
13456
  }
13006
- ) }, t))
13457
+ )
13007
13458
  }
13008
13459
  )
13009
13460
  ]
@@ -13030,8 +13481,12 @@ var AgentActivityList = ({
13030
13481
  className,
13031
13482
  sx,
13032
13483
  toolbarSx,
13033
- rowSx
13484
+ rowSx,
13485
+ globalUrl,
13486
+ theme,
13487
+ colorMode
13034
13488
  }) => {
13489
+ const [appDrawer, setAppDrawer] = (0, import_react19.useState)(null);
13035
13490
  const [runs, setRuns] = (0, import_react19.useState)([]);
13036
13491
  const [cursor, setCursor] = (0, import_react19.useState)("");
13037
13492
  const [hasMore, setHasMore] = (0, import_react19.useState)(false);
@@ -13044,6 +13499,8 @@ var AgentActivityList = ({
13044
13499
  const [workflowFilter, setWorkflowFilter] = (0, import_react19.useState)("");
13045
13500
  const [stopOpen, setStopOpen] = (0, import_react19.useState)(false);
13046
13501
  const [stopLoading, setStopLoading] = (0, import_react19.useState)(false);
13502
+ const [appIcons, setAppIcons] = (0, import_react19.useState)({});
13503
+ const [enrichedRuns, setEnrichedRuns] = (0, import_react19.useState)({});
13047
13504
  const debounceRef = (0, import_react19.useRef)();
13048
13505
  const selectedAgentWorkflow = agentWorkflows.find((w) => w.id === workflowFilter) || null;
13049
13506
  const openEditPrompt = (0, import_react19.useCallback)(async () => {
@@ -13125,10 +13582,137 @@ var AgentActivityList = ({
13125
13582
  cancelled = true;
13126
13583
  };
13127
13584
  }, [apiKey, apiBaseUrl, orgId]);
13585
+ (0, import_react19.useEffect)(() => {
13586
+ let cancelled = false;
13587
+ fetchAppsViaApiConfig().then((apps) => {
13588
+ if (cancelled || !Array.isArray(apps)) return;
13589
+ const map = {};
13590
+ for (const a of apps) {
13591
+ const name = a?.name;
13592
+ const img = a?.large_image || a?.image_url || a?.image;
13593
+ if (!name || !img) continue;
13594
+ map[normToolKey(name)] = img;
13595
+ }
13596
+ setAppIcons(map);
13597
+ }).catch(() => {
13598
+ });
13599
+ return () => {
13600
+ cancelled = true;
13601
+ };
13602
+ }, []);
13603
+ (0, import_react19.useEffect)(() => {
13604
+ if (!runs.length) return;
13605
+ let cancelled = false;
13606
+ const buildPatchFromRun = (r) => {
13607
+ const results = Array.isArray(r.results) ? r.results : null;
13608
+ if (!results || results.length === 0) return null;
13609
+ const agentResult = results.find((x) => x?.action?.app_name === "AI Agent");
13610
+ let decisions = Array.isArray(r.decisions) ? r.decisions : void 0;
13611
+ let originalInput;
13612
+ let allowedActions;
13613
+ if (agentResult?.result) {
13614
+ try {
13615
+ const parsed = JSON.parse(agentResult.result);
13616
+ if (!decisions && Array.isArray(parsed?.decisions)) decisions = parsed.decisions;
13617
+ if (typeof parsed?.original_input === "string") originalInput = parsed.original_input;
13618
+ if (Array.isArray(parsed?.allowed_actions)) allowedActions = parsed.allowed_actions;
13619
+ } catch {
13620
+ }
13621
+ }
13622
+ const hasPrompt = !!r.execution_argument || !!originalInput || !!agentResult?.result;
13623
+ if (!decisions || !hasPrompt) return null;
13624
+ const patch = {
13625
+ results,
13626
+ execution_argument: r.execution_argument,
13627
+ result: agentResult?.result ?? r.result,
13628
+ decisions,
13629
+ allowed_actions: allowedActions
13630
+ };
13631
+ if (originalInput && !patch.execution_argument) {
13632
+ patch.execution_argument = JSON.stringify({ original_input: originalInput });
13633
+ }
13634
+ return patch;
13635
+ };
13636
+ const nativePatches = {};
13637
+ const needsFetch = [];
13638
+ for (const r of runs) {
13639
+ const id = r.execution_id;
13640
+ if (!id || enrichedRuns[id]) continue;
13641
+ const native = buildPatchFromRun(r);
13642
+ if (native) {
13643
+ nativePatches[id] = native;
13644
+ } else {
13645
+ needsFetch.push(id);
13646
+ }
13647
+ }
13648
+ if (Object.keys(nativePatches).length > 0) {
13649
+ setEnrichedRuns((prev) => ({ ...prev, ...nativePatches }));
13650
+ }
13651
+ if (needsFetch.length === 0) return;
13652
+ const CONCURRENCY = 4;
13653
+ let i = 0;
13654
+ const fetchOne = async (executionId) => {
13655
+ try {
13656
+ const resp = await fetch(getApiUrl("/api/v1/streams/results"), {
13657
+ method: "POST",
13658
+ credentials: "include",
13659
+ headers: {
13660
+ "Content-Type": "application/json",
13661
+ ...apiKey ? { Authorization: `Bearer ${apiKey}` } : getAuthHeader(),
13662
+ ...orgId ? { "Org-Id": orgId } : {}
13663
+ },
13664
+ body: JSON.stringify({ execution_id: executionId, authorization: executionId })
13665
+ });
13666
+ if (!resp.ok || cancelled) return;
13667
+ const json = await resp.json().catch(() => null);
13668
+ if (!json || cancelled) return;
13669
+ let decisions;
13670
+ let originalInput;
13671
+ let allowedActions;
13672
+ const agentResult = Array.isArray(json.results) ? json.results.find((r) => r?.action?.app_name === "AI Agent") : null;
13673
+ if (agentResult?.result) {
13674
+ try {
13675
+ const parsed = JSON.parse(agentResult.result);
13676
+ if (Array.isArray(parsed?.decisions)) decisions = parsed.decisions;
13677
+ if (typeof parsed?.original_input === "string") originalInput = parsed.original_input;
13678
+ if (Array.isArray(parsed?.allowed_actions)) allowedActions = parsed.allowed_actions;
13679
+ } catch {
13680
+ }
13681
+ }
13682
+ const patch = {
13683
+ results: json.results,
13684
+ execution_argument: json.execution_argument,
13685
+ result: agentResult?.result,
13686
+ decisions,
13687
+ allowed_actions: allowedActions
13688
+ };
13689
+ if (originalInput && !patch.execution_argument) {
13690
+ patch.execution_argument = JSON.stringify({ original_input: originalInput });
13691
+ }
13692
+ setEnrichedRuns((prev) => ({ ...prev, [executionId]: patch }));
13693
+ } catch {
13694
+ }
13695
+ };
13696
+ const workers = Array.from({ length: Math.min(CONCURRENCY, needsFetch.length) }, async () => {
13697
+ while (!cancelled && i < needsFetch.length) {
13698
+ const id = needsFetch[i++];
13699
+ await fetchOne(id);
13700
+ }
13701
+ });
13702
+ Promise.all(workers).catch(() => {
13703
+ });
13704
+ return () => {
13705
+ cancelled = true;
13706
+ };
13707
+ }, [runs, apiKey, orgId]);
13708
+ const mergedRuns = runs.map((r) => {
13709
+ const patch = r.execution_id ? enrichedRuns[r.execution_id] : void 0;
13710
+ return patch ? { ...r, ...patch } : r;
13711
+ });
13128
13712
  const loadMore = (0, import_react19.useCallback)(() => {
13129
13713
  if (cursor && !isLoading) fetchRuns(true, cursor);
13130
13714
  }, [cursor, isLoading, fetchRuns]);
13131
- const filteredRuns = debouncedQuery ? runs.filter((r) => {
13715
+ const filteredRuns = debouncedQuery ? mergedRuns.filter((r) => {
13132
13716
  const hay = [
13133
13717
  getRunTitle(r),
13134
13718
  getRunSubtitle(r),
@@ -13137,7 +13721,7 @@ var AgentActivityList = ({
13137
13721
  r.status
13138
13722
  ].filter(Boolean).join(" ").toLowerCase();
13139
13723
  return hay.includes(debouncedQuery.toLowerCase());
13140
- }) : runs;
13724
+ }) : mergedRuns;
13141
13725
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
13142
13726
  import_material20.Box,
13143
13727
  {
@@ -13183,7 +13767,24 @@ var AgentActivityList = ({
13183
13767
  },
13184
13768
  children: [
13185
13769
  /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.MenuItem, { value: "", sx: { fontSize: "0.85rem" }, children: "All Agent runs" }),
13186
- agentWorkflows.map((w) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.MenuItem, { value: w.id, sx: { fontSize: "0.85rem" }, children: w.name }, w.id))
13770
+ agentWorkflows.map((w) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.MenuItem, { value: w.id, sx: { fontSize: "0.85rem" }, children: w.name }, w.id)),
13771
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Divider, { sx: { borderColor: "hsl(var(--border))", my: 0.5 } }),
13772
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13773
+ import_material20.Box,
13774
+ {
13775
+ sx: {
13776
+ px: 1.5,
13777
+ py: 1,
13778
+ fontSize: "0.72rem",
13779
+ color: "hsl(var(--muted-foreground))",
13780
+ lineHeight: 1.45,
13781
+ whiteSpace: "normal",
13782
+ maxWidth: 280,
13783
+ pointerEvents: "none"
13784
+ },
13785
+ children: "Scheduled agent runs will appear in this list once you set them up."
13786
+ }
13787
+ )
13187
13788
  ]
13188
13789
  }
13189
13790
  ),
@@ -13326,7 +13927,9 @@ var AgentActivityList = ({
13326
13927
  {
13327
13928
  run,
13328
13929
  onClick: () => onRunClick?.(run),
13329
- sx: rowSx
13930
+ sx: rowSx,
13931
+ appIcons,
13932
+ onAppClick: (app) => setAppDrawer(app)
13330
13933
  },
13331
13934
  run.execution_id || idx
13332
13935
  )),
@@ -13374,6 +13977,19 @@ var AgentActivityList = ({
13374
13977
  ] })
13375
13978
  ]
13376
13979
  }
13980
+ ),
13981
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13982
+ AppDetailDrawer,
13983
+ {
13984
+ open: !!appDrawer,
13985
+ onClose: () => setAppDrawer(null),
13986
+ appName: appDrawer?.name || null,
13987
+ appId: appDrawer?.id || null,
13988
+ activeOrgId: orgId || null,
13989
+ globalUrl: globalUrl || apiBaseUrl,
13990
+ theme,
13991
+ colorMode
13992
+ }
13377
13993
  )
13378
13994
  ]
13379
13995
  }
@@ -13574,6 +14190,8 @@ var AgentsView = ({
13574
14190
  hideChooseLLM,
13575
14191
  localLLMSlot,
13576
14192
  permissionsSlot,
14193
+ initialApps,
14194
+ onAppsChange,
13577
14195
  globalUrl,
13578
14196
  isLoaded,
13579
14197
  isLoggedIn,
@@ -13589,7 +14207,7 @@ var AgentsView = ({
13589
14207
  const [agentView, setAgentView] = (0, import_react20.useState)("start");
13590
14208
  const [prefill, setPrefill] = (0, import_react20.useState)({
13591
14209
  input: "",
13592
- apps: [],
14210
+ apps: initialApps && initialApps.length > 0 ? initialApps : [],
13593
14211
  key: 0
13594
14212
  });
13595
14213
  const [editing, setEditing] = (0, import_react20.useState)(null);
@@ -13724,7 +14342,8 @@ var AgentsView = ({
13724
14342
  disableSchedule: Boolean(editing),
13725
14343
  disableScheduleTooltip: editing ? "Scheduling is disabled while editing an existing schedule" : void 0,
13726
14344
  theme,
13727
- colorMode
14345
+ colorMode,
14346
+ onAppsChange
13728
14347
  },
13729
14348
  prefill.key
13730
14349
  ),