@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.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, SHUFFLE_HOST_BASE_URL_EVENT, 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();
@@ -284,6 +284,13 @@ var init_api = __esm({
284
284
  getApiUrl = (endpoint) => {
285
285
  return `${API_CONFIG.baseUrl}${endpoint}`;
286
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
+ };
287
294
  shuffleFetch = (url, init) => {
288
295
  const { headers: extraHeaders, ...rest } = init || {};
289
296
  return fetch(url, {
@@ -6619,10 +6626,11 @@ var ShuffleMCP = import_react12.default.forwardRef(({
6619
6626
  }, [internalSelectedApps]);
6620
6627
  const filteredPrivateApps = (0, import_react12.useMemo)(() => {
6621
6628
  if (privateApps.length === 0) return [];
6622
- const q = query.trim().toLowerCase();
6629
+ const normalize = (s) => (s || "").toLowerCase().replace(/[\s_\-]+/g, "");
6630
+ const q = normalize(query.trim());
6623
6631
  if (!q) return privateApps;
6624
6632
  return privateApps.filter(
6625
- (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))
6626
6634
  );
6627
6635
  }, [privateApps, query]);
6628
6636
  const displayResults = (0, import_react12.useMemo)(() => {
@@ -7878,7 +7886,7 @@ var runAgent = async (request) => {
7878
7886
  }
7879
7887
  const payload = {
7880
7888
  jsonrpc: "2.0",
7881
- id: crypto.randomUUID(),
7889
+ id: Date.now(),
7882
7890
  method: "tools/call",
7883
7891
  params
7884
7892
  };
@@ -8342,10 +8350,7 @@ var getDiagnosableScope = (parsed) => {
8342
8350
  const action = String(d.action || d.details?.action || "").toLowerCase();
8343
8351
  const category = String(d.category || "").toLowerCase();
8344
8352
  if (!["finish", "finalise"].includes(action) && !["finish", "finalise"].includes(category)) return null;
8345
- return {
8346
- reason: d.reason,
8347
- fields: Array.isArray(d.fields) ? d.fields.map((f) => f?.value).filter(Boolean) : void 0
8348
- };
8353
+ return { reason: d.reason };
8349
8354
  });
8350
8355
  if (finalDecisions.some((d) => d !== null)) scope.decisions = finalDecisions;
8351
8356
  }
@@ -8419,6 +8424,32 @@ var diagnoseOutputWarning = (run) => {
8419
8424
  if (raw && entries.length === 0) entries.push({ path: "", value: raw });
8420
8425
  const haystack = entries.map((e) => e.value).join("\n");
8421
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();
8422
8453
  const findEvidence = (test, max = 3) => {
8423
8454
  const out = [];
8424
8455
  for (const e of entries) {
@@ -8435,23 +8466,35 @@ var diagnoseOutputWarning = (run) => {
8435
8466
  let statusEvidence = null;
8436
8467
  const statusPatterns = [
8437
8468
  /\bhttp[\s/]?(\d{3})\b/i,
8438
- /\bstatus[\s:_-]+(\d{3})\b/i,
8439
- /\bstatus[_\s-]?code["\s:]+(\d{3})\b/i,
8440
- /\bcode["\s:]+(\d{3})\b/i,
8441
- /\[(\d{3})\]/,
8442
- /\((\d{3})\)/,
8443
- /\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
8444
8471
  ];
8445
- 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) {
8446
8492
  for (const e of entries) {
8447
- const m = e.value.match(re);
8448
- if (m) {
8449
- const n = Number(m[1]);
8450
- if (n >= 400 && n < 600) {
8451
- status = n;
8452
- statusEvidence = { path: e.path || "(root)", value: trimEvidenceValue(e.value) };
8453
- break outer;
8454
- }
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;
8455
8498
  }
8456
8499
  }
8457
8500
  }
@@ -8471,9 +8514,7 @@ var diagnoseOutputWarning = (run) => {
8471
8514
  const dedup = ev.filter((e) => e.path !== statusEvidence.path);
8472
8515
  return [statusEvidence, ...dedup].slice(0, 3);
8473
8516
  };
8474
- 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(
8475
- lower
8476
- )) {
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)) {
8477
8518
  const ev = findEvidenceByRegex(
8478
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/
8479
8520
  );
@@ -8487,9 +8528,7 @@ var diagnoseOutputWarning = (run) => {
8487
8528
  evidence: withStatusEvidence(ev)
8488
8529
  };
8489
8530
  }
8490
- if (status === 403 || /\b(forbidden|permission[_\s-]*denied|not[_\s-]*allowed|access[_\s-]*denied|insufficient[_\s-]*(scope|permission|privileges?)|missing[_\s-]*scope)\b/.test(
8491
- lower
8492
- )) {
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)) {
8493
8532
  const ev = findEvidenceByRegex(
8494
8533
  /forbidden|permission[_\s-]*denied|not[_\s-]*allowed|access[_\s-]*denied|insufficient[_\s-]*(scope|permission|privileges?)|missing[_\s-]*scope|\b403\b/
8495
8534
  );
@@ -8503,7 +8542,7 @@ var diagnoseOutputWarning = (run) => {
8503
8542
  evidence: withStatusEvidence(ev)
8504
8543
  };
8505
8544
  }
8506
- 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)) {
8507
8546
  const ev = findEvidenceByRegex(
8508
8547
  /rate[_\s-]*limit|too[_\s-]*many[_\s-]*requests|quota[_\s-]*exceeded|throttled|\b429\b/
8509
8548
  );
@@ -8517,7 +8556,7 @@ var diagnoseOutputWarning = (run) => {
8517
8556
  evidence: withStatusEvidence(ev)
8518
8557
  };
8519
8558
  }
8520
- 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)) {
8521
8560
  const ev = findEvidenceByRegex(
8522
8561
  /not[_\s-]*found|no such|does not exist|unknown[_\s-]*(id|resource)|\b404\b/
8523
8562
  );
@@ -8531,9 +8570,7 @@ var diagnoseOutputWarning = (run) => {
8531
8570
  evidence: withStatusEvidence(ev)
8532
8571
  };
8533
8572
  }
8534
- if (status === 400 || status === 422 || /\b(bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload))\b/.test(
8535
- lower
8536
- )) {
8573
+ if (status === 400 || status === 422 || /\b(bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload))\b/.test(errorHaystackLower)) {
8537
8574
  const ev = findEvidenceByRegex(
8538
8575
  /bad[_\s-]*request|validation[_\s-]*(error|failed)|invalid[_\s-]*(parameter|field|argument|body|payload)|\b400\b|\b422\b/
8539
8576
  );
@@ -8547,9 +8584,7 @@ var diagnoseOutputWarning = (run) => {
8547
8584
  evidence: withStatusEvidence(ev)
8548
8585
  };
8549
8586
  }
8550
- 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(
8551
- lower
8552
- )) {
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)) {
8553
8588
  const ev = findEvidenceByRegex(
8554
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/
8555
8590
  );
@@ -8794,6 +8829,153 @@ var deepParseJsonStrings3 = (obj, depth = 0) => {
8794
8829
  }
8795
8830
  return obj;
8796
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
+ };
8797
8979
  var validateJson = (raw) => {
8798
8980
  if (raw == null) return { valid: false, result: null };
8799
8981
  if (typeof raw === "object") return { valid: true, result: raw };
@@ -8804,6 +8986,17 @@ var validateJson = (raw) => {
8804
8986
  return { valid: false, result: raw };
8805
8987
  }
8806
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, "_");
8807
9000
  var extractAuthRequest = (decision) => {
8808
9001
  if (!decision || typeof decision !== "object") return null;
8809
9002
  const raw = decision?.run_details?.raw_response;
@@ -8819,18 +9012,20 @@ var extractAuthRequest = (decision) => {
8819
9012
  }
8820
9013
  const needsAuth = parsed && (parsed.action === "app_authentication" || parsed.app_authentication === true);
8821
9014
  if (!needsAuth) return null;
8822
- let appName = parsed.app || parsed.app_name || parsed.appname;
9015
+ let toolAppName;
8823
9016
  let appId = null;
8824
- if (!appName && typeof decision?.tool === "string") {
9017
+ if (typeof decision?.tool === "string") {
8825
9018
  const t = decision.tool;
8826
9019
  if (t.startsWith("app:")) {
8827
9020
  const parts = t.split(":");
8828
9021
  appId = parts[1] || null;
8829
- appName = parts[2] || t;
9022
+ toolAppName = parts[2] || void 0;
8830
9023
  } else {
8831
- appName = t;
9024
+ toolAppName = t;
8832
9025
  }
8833
9026
  }
9027
+ let appName = parsed.app || parsed.app_name || parsed.appname;
9028
+ if (!appName) appName = toolAppName;
8834
9029
  if (!appName) {
8835
9030
  const f = (decision?.fields || []).find((x) => x?.key === "app" || x?.key === "app_name");
8836
9031
  if (f?.value) appName = f.value;
@@ -8894,7 +9089,9 @@ var TimelineRow = ({
8894
9089
  getFormUrl,
8895
9090
  runFinished,
8896
9091
  onAuthenticateApp,
9092
+ onRefreshAuthenticatedApps,
8897
9093
  isAppAuthenticated,
9094
+ authAppsLoading = false,
8898
9095
  highlight = false
8899
9096
  }) => {
8900
9097
  const [submitAttempted, setSubmitAttempted] = (0, import_react15.useState)(false);
@@ -9084,7 +9281,7 @@ var TimelineRow = ({
9084
9281
  import_material16.IconButton,
9085
9282
  {
9086
9283
  size: "small",
9087
- onClick: () => window.open(details.run_details.debug_url, "_blank", "noopener,noreferrer"),
9284
+ onClick: () => window.open(getShuffleCoreFormUrl(details.run_details.debug_url), "_blank", "noopener,noreferrer"),
9088
9285
  sx: { color: "hsl(var(--muted-foreground))", "&:hover": { color: "hsl(var(--primary))" } },
9089
9286
  children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.ExternalLink, { size: 16 })
9090
9287
  }
@@ -9185,9 +9382,10 @@ var TimelineRow = ({
9185
9382
  (() => {
9186
9383
  const req = extractAuthRequest(details);
9187
9384
  if (!req) return null;
9188
- if (isAppAuthenticated?.(req.appName)) return null;
9385
+ if (authAppsLoading) return null;
9386
+ const authed = !!isAppAuthenticated?.(req.appName, req.appId);
9189
9387
  const pretty = req.appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
9190
- const slug = req.appName.toLowerCase().replace(/[\s-]+/g, "_");
9388
+ const slug = normalizeAgentAppName(req.appName);
9191
9389
  const appId = req.appId || appsById[req.appName]?.id || appsById[slug]?.id || null;
9192
9390
  const icon = appsById[req.appName]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
9193
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: {
@@ -9196,22 +9394,68 @@ var TimelineRow = ({
9196
9394
  gap: 1.5,
9197
9395
  p: 1.5,
9198
9396
  borderRadius: 1.5,
9199
- border: "1px solid hsla(var(--severity-medium) / 0.3)",
9200
- 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)"
9201
9399
  }, children: [
9202
- /* @__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))" }),
9203
9401
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { flex: 1, minWidth: 0 }, children: [
9204
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
9205
- pretty,
9206
- " requires authentication"
9207
- ] }),
9208
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
9209
- "Connect your ",
9210
- pretty,
9211
- " account so the agent can complete this step, then rerun the decision."
9212
- ] })
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.` })
9213
9404
  ] }),
9214
- /* @__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)(
9215
9459
  import_material16.Button,
9216
9460
  {
9217
9461
  variant: "outlined",
@@ -9238,6 +9482,7 @@ var TimelineRow = ({
9238
9482
  disabled: !onAuthenticateApp,
9239
9483
  onClick: (e) => {
9240
9484
  e.stopPropagation();
9485
+ onRefreshAuthenticatedApps?.();
9241
9486
  onAuthenticateApp?.(req.appName, appId);
9242
9487
  },
9243
9488
  sx: {
@@ -9324,6 +9569,7 @@ var AgentUI = ({
9324
9569
  authorization,
9325
9570
  initialExecution,
9326
9571
  onRun,
9572
+ onAppsChange,
9327
9573
  onViewChange,
9328
9574
  onSchedule,
9329
9575
  apiKey,
@@ -9353,6 +9599,7 @@ var AgentUI = ({
9353
9599
  ];
9354
9600
  const [chosenApps, setChosenApps] = (0, import_react15.useState)(apps ?? defaultApps ?? BUILTIN_DEFAULT_APPS);
9355
9601
  const [availableApps, setAvailableApps] = (0, import_react15.useState)([]);
9602
+ const [authAppsLoading, setAuthAppsLoading] = (0, import_react15.useState)(autoLoadApps && hasApiKey);
9356
9603
  const [executionApps, setExecutionApps] = (0, import_react15.useState)([]);
9357
9604
  const [resolvedToolApps, setResolvedToolApps] = (0, import_react15.useState)({});
9358
9605
  const [appSearchOpen, setAppSearchOpen] = (0, import_react15.useState)(false);
@@ -9382,6 +9629,7 @@ var AgentUI = ({
9382
9629
  const [highlightedIndex, setHighlightedIndex] = (0, import_react15.useState)(null);
9383
9630
  const [questionAnswers, setQuestionAnswers] = (0, import_react15.useState)({});
9384
9631
  const [simpleSubmitAttempted, setSimpleSubmitAttempted] = (0, import_react15.useState)(false);
9632
+ const [finishAnswerRaw, setFinishAnswerRaw] = (0, import_react15.useState)(false);
9385
9633
  const [continuationText, setContinuationText] = (0, import_react15.useState)("");
9386
9634
  const [error, setError] = (0, import_react15.useState)(null);
9387
9635
  const [searchParams, setSearchParams] = (0, import_react_router_dom2.useSearchParams)();
@@ -9473,29 +9721,33 @@ var AgentUI = ({
9473
9721
  }
9474
9722
  return m;
9475
9723
  }, [chosenApps, executionApps, resolvedToolApps]);
9476
- const isAppAuthenticated = (0, import_react15.useCallback)((appName) => {
9477
- if (!appName) return false;
9478
- const norm4 = (s) => s.toLowerCase().replace(/[\s-]+/g, "_");
9479
- const target = norm4(appName);
9480
- 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
+ });
9481
9732
  }, [availableApps]);
9482
9733
  const pendingAuthApps = (0, import_react15.useMemo)(() => {
9734
+ if (authAppsLoading) return [];
9483
9735
  const decisions = agentData?.decisions || [];
9484
9736
  const seen = /* @__PURE__ */ new Set();
9485
9737
  const out = [];
9486
9738
  for (const d of decisions) {
9487
9739
  const req = extractAuthRequest(d);
9488
9740
  if (!req) continue;
9489
- const slug = req.appName.toLowerCase().replace(/[\s-]+/g, "_");
9741
+ const slug = normalizeAgentAppName(req.appName);
9490
9742
  if (seen.has(slug)) continue;
9491
- if (isAppAuthenticated(req.appName)) continue;
9743
+ if (isAppAuthenticated(req.appName, req.appId)) continue;
9492
9744
  seen.add(slug);
9493
9745
  const appId = req.appId || appsById[req.appName]?.id || appsById[slug]?.id || null;
9494
9746
  const icon = appsById[req.appName]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
9495
9747
  out.push({ appName: req.appName, appId, icon });
9496
9748
  }
9497
9749
  return out;
9498
- }, [agentData, appsById, isAppAuthenticated]);
9750
+ }, [agentData, appsById, authAppsLoading, isAppAuthenticated]);
9499
9751
  (0, import_react15.useEffect)(() => {
9500
9752
  if (apps) setChosenApps(apps);
9501
9753
  }, [apps]);
@@ -9605,45 +9857,60 @@ var AgentUI = ({
9605
9857
  cancelled = true;
9606
9858
  };
9607
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]);
9608
9897
  (0, import_react15.useEffect)(() => {
9609
9898
  if (!autoLoadApps) return;
9610
- if (apps || defaultApps) return;
9611
9899
  if (!hasApiKey) return;
9612
- let cancelled = false;
9613
- (async () => {
9614
- try {
9615
- const resp = await fetch(resolveUrl2("/api/v1/apps/authentication"), {
9616
- credentials: "include",
9617
- headers: { ...resolveHeaders2() }
9618
- });
9619
- if (!resp.ok) return;
9620
- const result = await resp.json();
9621
- const list = Array.isArray(result) ? result : result?.data || [];
9622
- const seen = /* @__PURE__ */ new Set();
9623
- const loaded = [];
9624
- for (const entry of list) {
9625
- const app = entry?.app || entry;
9626
- const name = app?.name;
9627
- if (!name) continue;
9628
- const valid = entry?.active || entry?.validation?.valid || entry?.hasValidAuth;
9629
- if (valid === false) continue;
9630
- const key = name.toLowerCase();
9631
- if (seen.has(key)) continue;
9632
- seen.add(key);
9633
- loaded.push({
9634
- name,
9635
- id: app?.id || entry?.id,
9636
- icon: app?.large_image || app?.image_url || app?.image || entry?.bestImage || ""
9637
- });
9638
- }
9639
- if (!cancelled && loaded.length) setAvailableApps(loaded);
9640
- } catch {
9641
- }
9642
- })();
9900
+ const signal = { cancelled: false };
9901
+ loadAuthenticatedApps(signal);
9643
9902
  return () => {
9644
- cancelled = true;
9903
+ signal.cancelled = true;
9645
9904
  };
9646
- }, [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]);
9647
9914
  (0, import_react15.useEffect)(() => {
9648
9915
  const raw = agentData?.allowed_actions;
9649
9916
  if (!Array.isArray(raw) || raw.length === 0) {
@@ -10039,31 +10306,48 @@ var AgentUI = ({
10039
10306
  setAgentRequestLoading(false);
10040
10307
  }
10041
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]);
10042
10331
  const rerunAgent = (0, import_react15.useCallback)(() => {
10043
- const input = agentData?.original_input || actionInput || (() => {
10044
- const msgs = agentData?.input?.messages || [];
10045
- const m = msgs.find((m2) => m2?.role === "user" && !String(m2?.role).includes("USER CONTEXT"));
10046
- return m?.content || "";
10047
- })();
10332
+ const input = resolveRunInput();
10048
10333
  if (input && typeof input === "string") {
10049
10334
  setActionInput(input);
10050
10335
  }
10051
10336
  if (executionApps.length > 0) {
10052
10337
  setChosenApps(executionApps);
10053
10338
  }
10054
- if (disableStartTab) {
10055
- if (input && typeof input === "string" && input.trim().length >= 6) {
10056
- submitInput(input);
10057
- }
10058
- 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 });
10346
+ }
10347
+ if (input && typeof input === "string" && input.trim().length >= 6) {
10348
+ submitInput(input);
10059
10349
  }
10060
- setShowStarter(true);
10061
- setSearchParams((prev) => {
10062
- const next = new URLSearchParams(prev);
10063
- next.delete("agentView");
10064
- return next;
10065
- }, { replace: true });
10066
- }, [agentData, actionInput, executionApps, setSearchParams, disableStartTab, submitInput]);
10350
+ }, [resolveRunInput, executionApps, setSearchParams, disableStartTab, submitInput]);
10067
10351
  const abortAgent = (0, import_react15.useCallback)(async () => {
10068
10352
  const execId = execution?.execution_id;
10069
10353
  const auth = execution?.authorization;
@@ -10313,13 +10597,12 @@ var AgentUI = ({
10313
10597
  (0, import_react15.useEffect)(() => {
10314
10598
  onViewChange?.(activeTab);
10315
10599
  }, [activeTab, onViewChange]);
10600
+ (0, import_react15.useEffect)(() => {
10601
+ onAppsChange?.(chosenApps);
10602
+ }, [chosenApps, onAppsChange]);
10316
10603
  const goToTab = (t) => {
10317
10604
  if (t === "start") {
10318
- const runInput = agentData?.original_input || (() => {
10319
- const msgs = agentData?.input?.messages || [];
10320
- const m = msgs.find((m2) => m2?.role === "user");
10321
- return m?.content || "";
10322
- })();
10605
+ const runInput = resolveRunInput();
10323
10606
  if (runInput && typeof runInput === "string") {
10324
10607
  setActionInput(runInput);
10325
10608
  }
@@ -10460,58 +10743,71 @@ var AgentUI = ({
10460
10743
  ] }, i)) })
10461
10744
  ] }) : scheduleDisabledReasons.length === 1 ? `Cannot schedule: ${scheduleDisabledReasons[0]}` : "";
10462
10745
  const tabBarRef = (0, import_react15.useRef)(null);
10463
- 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)(
10464
10749
  import_material16.Box,
10465
10750
  {
10466
10751
  ref: tabBarRef,
10467
10752
  sx: {
10468
10753
  display: "flex",
10469
10754
  alignItems: "center",
10755
+ gap: 1,
10470
10756
  width: "fit-content",
10471
10757
  alignSelf: "center",
10472
10758
  position: "sticky",
10473
10759
  top: 8,
10474
10760
  zIndex: 5
10475
10761
  },
10476
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
10477
- SegmentedControl,
10478
- {
10479
- layoutId: "agentui-view-switcher",
10480
- ariaLabel: "Agent view",
10481
- value: activeTab,
10482
- onChange: (v) => goToTab(v),
10483
- options: [
10484
- { value: "start", label: "Start", disabled: disableStartTab },
10485
- { value: "simple", label: "Simple", disabled: !hasExecution },
10486
- { value: "detailed", label: "Detailed", disabled: !hasExecution },
10487
- { type: "divider", key: "div" },
10488
- {
10489
- type: "action",
10490
- key: "reload",
10491
- label: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.RefreshCw, { size: 14 }),
10492
- title: "Reload execution data",
10493
- disabled: !hasExecution,
10494
- onClick: () => {
10495
- if (execution?.execution_id && execution?.authorization) {
10496
- 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
+ }
10497
10785
  }
10498
- }
10499
- },
10500
- {
10501
- type: "action",
10502
- key: "schedule",
10503
- label: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Clock, { size: 14 }),
10504
- title: scheduleDisabledReason ? `Cannot schedule: ${scheduleDisabledReason}` : "Schedule this prompt to run repeatedly on a cron schedule",
10505
- disabled: Boolean(scheduleDisabledReason),
10506
- onClick: () => {
10507
- if (!scheduleDisabledReason && tabBarRef.current) {
10508
- 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
+ }
10509
10797
  }
10510
10798
  }
10511
- }
10512
- ]
10513
- }
10514
- )
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
+ ]
10515
10811
  }
10516
10812
  );
10517
10813
  const schedulePopover = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
@@ -11243,9 +11539,9 @@ var AgentUI = ({
11243
11539
  }
11244
11540
  ) }),
11245
11541
  chosenApps.map((app, i) => {
11246
- const slug = (app.name || "").toLowerCase().replace(/[\s-]+/g, "_");
11542
+ const slug = normalizeAgentAppName(app.name || "");
11247
11543
  const NO_AUTH = /* @__PURE__ */ new Set(["http", "shuffle_tools", "shuffle-tools", "tools", "singul", "core", "webhook", "email"]);
11248
- const needsAuth = !NO_AUTH.has(slug) && !isAppAuthenticated(app.name || "");
11544
+ const needsAuth = !authAppsLoading && !NO_AUTH.has(slug) && !isAppAuthenticated(app.name || "", app.id || null);
11249
11545
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
11250
11546
  import_material16.Tooltip,
11251
11547
  {
@@ -11306,9 +11602,10 @@ var AgentUI = ({
11306
11602
  ] }) }),
11307
11603
  !hideAppPicker && (() => {
11308
11604
  const NO_AUTH = /* @__PURE__ */ new Set(["http", "shuffle_tools", "shuffle-tools", "tools", "singul", "core", "webhook", "email"]);
11605
+ if (authAppsLoading) return null;
11309
11606
  const unauthed = chosenApps.filter((a) => {
11310
- const slug = (a.name || "").toLowerCase().replace(/[\s-]+/g, "_");
11311
- 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);
11312
11609
  });
11313
11610
  if (unauthed.length === 0) return null;
11314
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: {
@@ -11378,7 +11675,7 @@ var AgentUI = ({
11378
11675
  src: app.icon || void 0,
11379
11676
  alt: app.name,
11380
11677
  variant: "rounded",
11381
- onClick: () => navigate(`/apps/${encodeURIComponent((app.name || "").toLowerCase().replace(/\s+/g, "_"))}`),
11678
+ onClick: () => setAuthDrawerApp({ name: app.name, id: app.id || null }),
11382
11679
  sx: {
11383
11680
  bgcolor: "hsl(var(--muted))",
11384
11681
  cursor: "pointer",
@@ -11510,133 +11807,88 @@ var AgentUI = ({
11510
11807
  }
11511
11808
  const pendingAnswered = pendingQuestions.every((q) => questionAnswers[q.question]?.value);
11512
11809
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
11513
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
11514
- 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))" }),
11515
- /* @__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()}` }),
11516
- /* @__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),
11517
11818
  decisionCount,
11518
- " step",
11519
- decisionCount === 1 ? "" : "s",
11520
- durationSec != null ? ` \xB7 ${Math.round(durationSec)}s` : ""
11521
- ] }),
11522
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: { flexGrow: 1 } })
11523
- ] }),
11524
- pendingAuthApps.map(({ appName, appId, icon }) => {
11525
- const pretty = appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
11526
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
11527
- import_material16.Box,
11528
- {
11529
- sx: {
11530
- display: "flex",
11531
- alignItems: "center",
11532
- gap: 1.5,
11533
- p: 1.5,
11534
- borderRadius: 1.5,
11535
- border: "1px solid hsla(var(--severity-medium) / 0.3)",
11536
- bgcolor: "hsla(var(--severity-medium) / 0.08)"
11537
- },
11538
- children: [
11539
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react11.Lock, { size: 22, color: "hsl(var(--severity-medium))" }),
11540
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { flex: 1, minWidth: 0 }, children: [
11541
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
11542
- pretty,
11543
- " requires authentication"
11544
- ] }),
11545
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Typography, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
11546
- "Connect your ",
11547
- pretty,
11548
- " account so the agent can complete this step, then rerun."
11549
- ] })
11550
- ] }),
11551
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
11552
- import_material16.Button,
11553
- {
11554
- variant: "outlined",
11555
- size: "small",
11556
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
11557
- 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,
11558
11850
  {
11559
- src: icon || void 0,
11560
- alt: "",
11561
- 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 }),
11562
11873
  sx: {
11563
- width: 18,
11564
- height: 18,
11565
- borderRadius: 0.5,
11566
- bgcolor: "hsl(var(--background) / 0.4)",
11567
- color: "hsl(var(--background))",
11568
- fontSize: "0.7rem",
11569
- fontWeight: 700,
11570
- "& img": { objectFit: "contain" }
11874
+ height: 36,
11875
+ textTransform: "none",
11876
+ fontWeight: 600
11571
11877
  },
11572
- children: pretty.charAt(0)
11878
+ children: [
11879
+ "Authenticate ",
11880
+ pretty
11881
+ ]
11573
11882
  }
11574
- ),
11575
- onClick: () => setAuthDrawerApp({ name: appName, id: appId }),
11576
- sx: {
11577
- height: 36,
11578
- textTransform: "none",
11579
- fontWeight: 600
11580
- },
11581
- children: [
11582
- "Authenticate ",
11583
- pretty
11584
- ]
11585
- }
11586
- )
11587
- ]
11588
- },
11589
- `auth-${appName}`
11590
- );
11591
- }),
11592
- finishAnswer ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
11593
- p: 2,
11594
- borderRadius: 1.5,
11595
- border: "1px solid hsl(var(--border))",
11596
- bgcolor: "hsl(var(--background))",
11597
- fontSize: "0.9rem",
11598
- color: "hsl(var(--foreground))",
11599
- "& > *:first-of-type": { mt: 0 },
11600
- "& > *:last-child": { mb: 0 },
11601
- "& p": { my: 1, lineHeight: 1.55 },
11602
- "& h1, & h2, & h3, & h4": { mt: 2, mb: 1, fontWeight: 600, lineHeight: 1.3 },
11603
- "& h1": { fontSize: "1.15rem" },
11604
- "& h2": { fontSize: "1.05rem" },
11605
- "& h3, & h4": { fontSize: "0.95rem" },
11606
- "& ul": { my: 1, pl: 3, listStyleType: "disc", listStylePosition: "outside" },
11607
- "& ol": { my: 1, pl: 3, listStyleType: "decimal", listStylePosition: "outside" },
11608
- "& ul ul": { listStyleType: "circle" },
11609
- "& ul ul ul": { listStyleType: "square" },
11610
- "& li": { my: 0.25, display: "list-item" },
11611
- "& li::marker": { color: "hsl(var(--muted-foreground))" },
11612
- "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
11613
- "& code": {
11614
- px: 0.5,
11615
- py: 0.125,
11616
- borderRadius: 0.5,
11617
- bgcolor: "hsl(var(--muted))",
11618
- fontFamily: '"JetBrains Mono", ui-monospace, monospace',
11619
- fontSize: "0.82em"
11620
- },
11621
- "& pre": {
11622
- p: 1.5,
11623
- my: 1,
11624
- borderRadius: 1,
11625
- bgcolor: "hsl(var(--muted))",
11626
- overflowX: "auto",
11627
- fontSize: "0.82rem"
11628
- },
11629
- "& pre code": { p: 0, bgcolor: "transparent" },
11630
- "& blockquote": {
11631
- borderLeft: "3px solid hsl(var(--border))",
11632
- pl: 1.5,
11633
- my: 1,
11634
- color: "hsl(var(--muted-foreground))"
11635
- },
11636
- "& table": { borderCollapse: "collapse", my: 1, fontSize: "0.85rem" },
11637
- "& th, & td": { border: "1px solid hsl(var(--border))", px: 1, py: 0.5 },
11638
- "& hr": { border: 0, borderTop: "1px solid hsl(var(--border))", my: 1.5 }
11639
- }, 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 ? (() => {
11640
11892
  const trySimpleSubmit = () => {
11641
11893
  if (agentRequestLoading) return;
11642
11894
  if (!pendingAnswered) {
@@ -11708,7 +11960,7 @@ var AgentUI = ({
11708
11960
  ) })
11709
11961
  ] })
11710
11962
  ] });
11711
- })() : 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,
11712
11964
  !isRunning && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
11713
11965
  import_material16.Button,
11714
11966
  {
@@ -11754,53 +12006,32 @@ var AgentUI = ({
11754
12006
  getFormUrl,
11755
12007
  runFinished: detailedRunFinished,
11756
12008
  onAuthenticateApp: (name, id) => setAuthDrawerApp({ name, id }),
12009
+ onRefreshAuthenticatedApps: () => {
12010
+ loadAuthenticatedApps();
12011
+ },
11757
12012
  isAppAuthenticated,
12013
+ authAppsLoading,
11758
12014
  highlight: highlightedIndex === i
11759
12015
  },
11760
12016
  i
11761
12017
  )),
11762
- detailedRunFinished && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: {
12018
+ detailedRunFinished && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
11763
12019
  borderTop: "1px solid hsl(var(--border))",
11764
12020
  p: 2.5,
11765
12021
  display: "flex",
11766
12022
  flexDirection: "column",
11767
12023
  gap: 1.5,
11768
12024
  bgcolor: "hsl(var(--muted) / 0.2)"
11769
- }, children: [
11770
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_material16.Box, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
11771
- 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))" }),
11772
- /* @__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()}` })
11773
- ] }),
11774
- finishAnswer && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_material16.Box, { sx: {
11775
- p: 2,
11776
- borderRadius: 1.5,
11777
- border: "1px solid hsl(var(--border))",
11778
- bgcolor: "hsl(var(--background))",
11779
- fontSize: "0.9rem",
11780
- color: "hsl(var(--foreground))",
11781
- "& > *:first-of-type": { mt: 0 },
11782
- "& > *:last-child": { mb: 0 },
11783
- "& p": { my: 1, lineHeight: 1.55 },
11784
- "& a": { color: "hsl(var(--primary))", textDecoration: "underline" },
11785
- "& code": {
11786
- px: 0.5,
11787
- py: 0.125,
11788
- borderRadius: 0.5,
11789
- bgcolor: "hsl(var(--muted))",
11790
- fontFamily: '"JetBrains Mono", ui-monospace, monospace',
11791
- fontSize: "0.82em"
11792
- },
11793
- "& pre": {
11794
- p: 1.5,
11795
- my: 1,
11796
- borderRadius: 1,
11797
- bgcolor: "hsl(var(--muted))",
11798
- overflowX: "auto",
11799
- fontSize: "0.82rem"
11800
- },
11801
- "& pre code": { p: 0, bgcolor: "transparent" }
11802
- }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_markdown4.default, { remarkPlugins: [import_remark_gfm4.default, import_remark_breaks.default], children: normalizeMarkdown(finishAnswer) }) })
11803
- ] })
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
+ ) })
11804
12035
  ] }) });
11805
12036
  })(),
11806
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: [
@@ -11904,6 +12135,9 @@ var AgentUI = ({
11904
12135
  {
11905
12136
  open: !!authDrawerApp,
11906
12137
  onClose: () => setAuthDrawerApp(null),
12138
+ onRefresh: () => {
12139
+ loadAuthenticatedApps();
12140
+ },
11907
12141
  appName: authDrawerApp?.name || null,
11908
12142
  appId: authDrawerApp?.id || null,
11909
12143
  activeOrgId: orgId || null,
@@ -12038,15 +12272,16 @@ var OPENAI_ALGOLIA_APP = {
12038
12272
  };
12039
12273
  var ENDPOINT_PRESETS = [
12040
12274
  { label: SHUFFLE_AI_PRESET, url: "" },
12041
- { label: "OpenAI", url: "https://api.openai.com/v1" },
12042
- { label: "Anthropic", url: "https://api.anthropic.com/v1/" },
12043
- { label: "Google Gemini", url: "https://generativelanguage.googleapis.com/v1beta/openai/" },
12044
- { label: "Mistral", url: "https://api.mistral.ai/v1" },
12045
- { label: "Groq", url: "https://api.groq.com/openai/v1" },
12046
- { label: "Together AI", url: "https://api.together.xyz/v1" },
12047
- { label: "OpenRouter", url: "https://openrouter.ai/api/v1" },
12048
- { label: "Ollama (localhost)", url: "http://localhost:11434/v1" },
12049
- { 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." },
12050
12285
  { label: CUSTOM_PRESET, url: "" }
12051
12286
  ];
12052
12287
  var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serverside, theme, colorMode }) => {
@@ -12205,12 +12440,29 @@ var LocalLLMConfig = ({ compact, globalUrl, userdata, isLoaded, isLoggedIn, serv
12205
12440
  }
12206
12441
  )
12207
12442
  ] }),
12208
- !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: [
12209
- 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.",
12210
- " ",
12211
- /* @__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" }),
12212
- "."
12213
- ] }) }),
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
+ })(),
12214
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: [
12215
12467
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(UsageBar, { label: "App runs", usage: appRunUsage, limit: appRunLimit, unit: "runs", actionLabel: "Upgrade", actionHref: "https://shuffler.io/pricing" }),
12216
12468
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(UsageBar, { label: "Agent tokens", usage: agentTokenUsage, limit: agentTokenLimit, unit: "tokens", actionLabel: "Upgrade", actionHref: "https://shuffler.io/pricing" })
@@ -12493,6 +12745,7 @@ var AgentRunDrawer_default = AgentRunDrawer;
12493
12745
 
12494
12746
  // components/AgentActivityList.tsx
12495
12747
  var import_react19 = require("react");
12748
+ var import_react_router_dom3 = require("react-router-dom");
12496
12749
  var import_material20 = require("@mui/material");
12497
12750
  var import_lucide_react13 = require("lucide-react");
12498
12751
 
@@ -12783,6 +13036,8 @@ var stopAgentSchedule = async (workflowId, params = {}) => {
12783
13036
  };
12784
13037
 
12785
13038
  // components/AgentActivityList.tsx
13039
+ init_api();
13040
+ init_appsCache();
12786
13041
  var import_lucide_react14 = require("lucide-react");
12787
13042
  var import_jsx_runtime24 = require("react/jsx-runtime");
12788
13043
  var STATUS_CONFIG = {
@@ -12852,21 +13107,110 @@ var getTimeAgo = (dateStr) => {
12852
13107
  return dateStr;
12853
13108
  }
12854
13109
  };
12855
- var getRunTitle = (run) => {
12856
- if (run.workflow?.name) return run.workflow.name;
12857
- if (run.execution_argument) {
12858
- try {
12859
- const parsed = JSON.parse(run.execution_argument);
12860
- if (parsed.title) return parsed.title;
12861
- if (parsed.action) return parsed.action;
12862
- if (parsed.name) return parsed.name;
12863
- } catch {
12864
- const clean = run.execution_argument.replace(/[{}"]/g, "").trim();
12865
- 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;
13161
+ }
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;
12866
13187
  }
12867
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;
12868
13208
  return `Execution ${run.execution_id?.slice(0, 8) || "\u2014"}`;
12869
13209
  };
13210
+ var getDecisionCount = (run) => {
13211
+ if (Array.isArray(run.decisions)) return run.decisions.length;
13212
+ return 0;
13213
+ };
12870
13214
  var getRunSubtitle = (run) => {
12871
13215
  if (run.result) {
12872
13216
  try {
@@ -12884,30 +13228,82 @@ var getRunSubtitle = (run) => {
12884
13228
  }
12885
13229
  return run.execution_source || "Agent execution";
12886
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
+ };
12887
13238
  var getRunTools = (run) => {
12888
- const out = /* @__PURE__ */ new Set();
12889
- const add = (v) => {
12890
- if (!v) return;
12891
- const s = String(v).trim();
12892
- if (!s) return;
12893
- if (/^(ai\s*agent|shuffle\s*agent|shuffle_agent)$/i.test(s)) return;
12894
- 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);
12895
13251
  };
12896
- (run.results || []).forEach((r) => {
12897
- add(r?.action?.app_name);
12898
- if (!r?.action?.app_name) add(r?.action?.label);
12899
- });
12900
- (run.decisions || []).forEach((d) => {
12901
- add(typeof d?.tool === "string" ? d.tool : void 0);
12902
- });
12903
- 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"
12904
13297
  };
12905
- 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)();
12906
13301
  const statusKey = getEffectiveStatus(run);
12907
13302
  const cfg = STATUS_CONFIG[statusKey] || STATUS_CONFIG.WAITING;
12908
13303
  const iconColor = getRunIconColor(run);
12909
13304
  const duration = formatDuration(run);
12910
13305
  const tools = getRunTools(run);
13306
+ const decisionCount = getDecisionCount(run);
12911
13307
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
12912
13308
  import_material20.Box,
12913
13309
  {
@@ -12985,42 +13381,80 @@ var AgentRunRow = ({ run, onClick, sx }) => {
12985
13381
  duration && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
12986
13382
  /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Typography, { sx: { fontSize: "0.72rem", color: "hsl(var(--muted-foreground))", opacity: 0.4 }, children: "\xB7" }),
12987
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
+ ] })
12988
13395
  ] })
12989
13396
  ] })
12990
13397
  ] }),
12991
13398
  tools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12992
13399
  import_material20.Box,
12993
13400
  {
13401
+ onClick: (e) => e.stopPropagation(),
12994
13402
  sx: {
12995
13403
  display: { xs: "none", sm: "flex" },
12996
13404
  alignItems: "center",
12997
- gap: 0.5,
12998
- flexWrap: "wrap",
12999
- justifyContent: "flex-end",
13000
- maxWidth: 220,
13001
- flexShrink: 0
13405
+ flexShrink: 0,
13406
+ ml: 1
13002
13407
  },
13003
- children: tools.map((t) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.Tooltip, { title: t, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13004
- import_material20.Chip,
13408
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
13409
+ import_material20.AvatarGroup,
13005
13410
  {
13006
- label: t,
13007
- size: "small",
13411
+ max: 5,
13008
13412
  sx: {
13009
- height: 20,
13010
- fontSize: "0.68rem",
13011
- maxWidth: 120,
13012
- bgcolor: "hsla(var(--muted) / 0.5)",
13013
- color: "hsl(var(--muted-foreground))",
13014
- border: "1px solid hsl(var(--border))",
13015
- "& .MuiChip-label": {
13016
- px: 0.75,
13017
- overflow: "hidden",
13018
- textOverflow: "ellipsis",
13019
- 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))"
13020
13420
  }
13021
- }
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
+ })
13022
13456
  }
13023
- ) }, t))
13457
+ )
13024
13458
  }
13025
13459
  )
13026
13460
  ]
@@ -13047,8 +13481,12 @@ var AgentActivityList = ({
13047
13481
  className,
13048
13482
  sx,
13049
13483
  toolbarSx,
13050
- rowSx
13484
+ rowSx,
13485
+ globalUrl,
13486
+ theme,
13487
+ colorMode
13051
13488
  }) => {
13489
+ const [appDrawer, setAppDrawer] = (0, import_react19.useState)(null);
13052
13490
  const [runs, setRuns] = (0, import_react19.useState)([]);
13053
13491
  const [cursor, setCursor] = (0, import_react19.useState)("");
13054
13492
  const [hasMore, setHasMore] = (0, import_react19.useState)(false);
@@ -13061,6 +13499,8 @@ var AgentActivityList = ({
13061
13499
  const [workflowFilter, setWorkflowFilter] = (0, import_react19.useState)("");
13062
13500
  const [stopOpen, setStopOpen] = (0, import_react19.useState)(false);
13063
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)({});
13064
13504
  const debounceRef = (0, import_react19.useRef)();
13065
13505
  const selectedAgentWorkflow = agentWorkflows.find((w) => w.id === workflowFilter) || null;
13066
13506
  const openEditPrompt = (0, import_react19.useCallback)(async () => {
@@ -13142,10 +13582,137 @@ var AgentActivityList = ({
13142
13582
  cancelled = true;
13143
13583
  };
13144
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
+ });
13145
13712
  const loadMore = (0, import_react19.useCallback)(() => {
13146
13713
  if (cursor && !isLoading) fetchRuns(true, cursor);
13147
13714
  }, [cursor, isLoading, fetchRuns]);
13148
- const filteredRuns = debouncedQuery ? runs.filter((r) => {
13715
+ const filteredRuns = debouncedQuery ? mergedRuns.filter((r) => {
13149
13716
  const hay = [
13150
13717
  getRunTitle(r),
13151
13718
  getRunSubtitle(r),
@@ -13154,7 +13721,7 @@ var AgentActivityList = ({
13154
13721
  r.status
13155
13722
  ].filter(Boolean).join(" ").toLowerCase();
13156
13723
  return hay.includes(debouncedQuery.toLowerCase());
13157
- }) : runs;
13724
+ }) : mergedRuns;
13158
13725
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
13159
13726
  import_material20.Box,
13160
13727
  {
@@ -13200,7 +13767,24 @@ var AgentActivityList = ({
13200
13767
  },
13201
13768
  children: [
13202
13769
  /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material20.MenuItem, { value: "", sx: { fontSize: "0.85rem" }, children: "All Agent runs" }),
13203
- 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
+ )
13204
13788
  ]
13205
13789
  }
13206
13790
  ),
@@ -13343,7 +13927,9 @@ var AgentActivityList = ({
13343
13927
  {
13344
13928
  run,
13345
13929
  onClick: () => onRunClick?.(run),
13346
- sx: rowSx
13930
+ sx: rowSx,
13931
+ appIcons,
13932
+ onAppClick: (app) => setAppDrawer(app)
13347
13933
  },
13348
13934
  run.execution_id || idx
13349
13935
  )),
@@ -13391,6 +13977,19 @@ var AgentActivityList = ({
13391
13977
  ] })
13392
13978
  ]
13393
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
+ }
13394
13993
  )
13395
13994
  ]
13396
13995
  }
@@ -13591,6 +14190,8 @@ var AgentsView = ({
13591
14190
  hideChooseLLM,
13592
14191
  localLLMSlot,
13593
14192
  permissionsSlot,
14193
+ initialApps,
14194
+ onAppsChange,
13594
14195
  globalUrl,
13595
14196
  isLoaded,
13596
14197
  isLoggedIn,
@@ -13606,7 +14207,7 @@ var AgentsView = ({
13606
14207
  const [agentView, setAgentView] = (0, import_react20.useState)("start");
13607
14208
  const [prefill, setPrefill] = (0, import_react20.useState)({
13608
14209
  input: "",
13609
- apps: [],
14210
+ apps: initialApps && initialApps.length > 0 ? initialApps : [],
13610
14211
  key: 0
13611
14212
  });
13612
14213
  const [editing, setEditing] = (0, import_react20.useState)(null);
@@ -13741,7 +14342,8 @@ var AgentsView = ({
13741
14342
  disableSchedule: Boolean(editing),
13742
14343
  disableScheduleTooltip: editing ? "Scheduling is disabled while editing an existing schedule" : void 0,
13743
14344
  theme,
13744
- colorMode
14345
+ colorMode,
14346
+ onAppsChange
13745
14347
  },
13746
14348
  prefill.key
13747
14349
  ),