@invergent/agent-chat-react 2.5.4 → 2.5.6

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
@@ -1,6 +1,6 @@
1
1
  import { cn } from './chunk-QSC4UIVT.js';
2
- import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, useLayoutEffect, lazy, useContext, Fragment as Fragment$1, Suspense, Children } from 'react';
3
- import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, ChevronRightIcon, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, Loader2Icon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, CopyIcon, TerminalIcon, SparklesIcon, ClockIcon, PlusIcon, CloudIcon, HardDriveIcon, PaperclipIcon, GlobeIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, SearchIcon, CircleCheckIcon, ThumbsUpIcon, ThumbsDownIcon, BookOpenIcon, GitBranchIcon, ActivityIcon, EyeIcon, ListTodoIcon, ArrowUpIcon, ListIcon, PenLineIcon, ArrowRight, FileEditIcon, WrenchIcon, FileCodeIcon, CodeIcon, FileArchiveIcon, FileVideoIcon, FileAudioIcon, FileImageIcon, FileChartLineIcon, FileSpreadsheetIcon, XCircleIcon, CheckCircle2Icon, Code, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
2
+ import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, useLayoutEffect, lazy, useContext, Fragment as Fragment$1, Children, Suspense } from 'react';
3
+ import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, PlugZapIcon, ChevronRightIcon, ArrowLeftIcon, Loader2Icon, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, TerminalIcon, SparklesIcon, ClockIcon, PlusIcon, CloudIcon, HardDriveIcon, PaperclipIcon, GlobeIcon, FolderIcon, CopyIcon, FileIcon, ChevronLeftIcon, MinusIcon, SearchIcon, ArrowUpIcon, CircleCheckIcon, ThumbsUpIcon, ThumbsDownIcon, BookOpenIcon, GitBranchIcon, ActivityIcon, EyeIcon, ListTodoIcon, ListIcon, PenLineIcon, ArrowRight, FileEditIcon, WrenchIcon, FileCodeIcon, CodeIcon, FileArchiveIcon, FileVideoIcon, FileAudioIcon, FileImageIcon, FileChartLineIcon, FileSpreadsheetIcon, XCircleIcon, CheckCircle2Icon, Code, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
4
4
  import { cva } from 'class-variance-authority';
5
5
  import { Collapsible as Collapsible$1, Slot, Tooltip as Tooltip$1, Progress as Progress$1, Tabs as Tabs$1, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Popover as Popover$1 } from 'radix-ui';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -715,6 +715,64 @@ var ConversationScrollButton = ({
715
715
  }
716
716
  );
717
717
  };
718
+
719
+ // src/lib/oauth-popup.ts
720
+ function openOAuthPopup(url) {
721
+ const w = 600;
722
+ const h = 720;
723
+ const dualLeft = window.screenLeft ?? window.screenX ?? 0;
724
+ const dualTop = window.screenTop ?? window.screenY ?? 0;
725
+ const width = window.innerWidth || document.documentElement.clientWidth || w;
726
+ const height = window.innerHeight || document.documentElement.clientHeight || h;
727
+ const left = dualLeft + Math.max(0, (width - w) / 2);
728
+ const top = dualTop + Math.max(0, (height - h) / 2);
729
+ const features = `popup=yes,width=${w},height=${h},left=${left},top=${top}`;
730
+ const popup = window.open(url, "composio-oauth", features);
731
+ if (!popup) {
732
+ window.open(url, "_blank", "noopener,noreferrer");
733
+ }
734
+ return popup;
735
+ }
736
+ function isComposioConnectUrl(url) {
737
+ if (!url) return false;
738
+ try {
739
+ return new URL(url).hostname === "connect.composio.dev";
740
+ } catch {
741
+ return false;
742
+ }
743
+ }
744
+ function toolkitName(label) {
745
+ const text = (label ?? "").trim();
746
+ const stripped = text.replace(/^connect\s+/i, "").trim();
747
+ return stripped || "your account";
748
+ }
749
+ function ComposioConnectCard({ url, label }) {
750
+ const name = toolkitName(label);
751
+ return /* @__PURE__ */ jsxs("span", { className: "my-1 inline-flex w-full max-w-sm items-center gap-3 rounded-lg border border-border bg-card p-3 align-middle no-underline", children: [
752
+ /* @__PURE__ */ jsx("span", { className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(PlugZapIcon, { className: "h-4 w-4" }) }),
753
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
754
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-foreground", children: [
755
+ "Connect ",
756
+ name
757
+ ] }),
758
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
759
+ "Authorize your ",
760
+ name,
761
+ " account to continue."
762
+ ] })
763
+ ] }),
764
+ /* @__PURE__ */ jsx(
765
+ Button,
766
+ {
767
+ type: "button",
768
+ size: "xs",
769
+ onClick: () => openOAuthPopup(url),
770
+ className: "ml-auto shrink-0",
771
+ children: "Connect"
772
+ }
773
+ )
774
+ ] });
775
+ }
718
776
  var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsx(
719
777
  "div",
720
778
  {
@@ -747,6 +805,21 @@ createContext(
747
805
  null
748
806
  );
749
807
  var streamdownPlugins = { cjk, code, math, mermaid };
808
+ function anchorText(children) {
809
+ if (typeof children === "string") return children;
810
+ if (Array.isArray(children)) {
811
+ return children.filter((c) => typeof c === "string").join("");
812
+ }
813
+ return "";
814
+ }
815
+ var streamdownComponents = {
816
+ a: ({ href, children, ...props }) => {
817
+ if (isComposioConnectUrl(href)) {
818
+ return /* @__PURE__ */ jsx(ComposioConnectCard, { url: href, label: anchorText(children) });
819
+ }
820
+ return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noreferrer", ...props, children });
821
+ }
822
+ };
750
823
  var MessageResponse = memo(
751
824
  ({ className, ...props }) => /* @__PURE__ */ jsx(
752
825
  Streamdown,
@@ -756,6 +829,7 @@ var MessageResponse = memo(
756
829
  className
757
830
  ),
758
831
  plugins: streamdownPlugins,
832
+ components: streamdownComponents,
759
833
  ...props
760
834
  }
761
835
  ),
@@ -2141,6 +2215,51 @@ function ExecuteCodeToolBlock({ tc }) {
2141
2215
  ] }) })
2142
2216
  ] });
2143
2217
  }
2218
+
2219
+ // src/lib/format.ts
2220
+ function formatFileSize(bytes) {
2221
+ if (bytes < 1024) return `${bytes} B`;
2222
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
2223
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2224
+ }
2225
+ function formatMcpToolLabel(toolName) {
2226
+ const segments = toolName.replace(/^mcp__/, "").split("__");
2227
+ const tool = segments[segments.length - 1] ?? toolName;
2228
+ const branded = tool.replace(/^composio_/i, "");
2229
+ return (branded || tool).split("_").filter(Boolean).map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()).join(" ");
2230
+ }
2231
+ function getLanguageHint(path) {
2232
+ const name = path.split("/").pop() ?? path;
2233
+ const dot = name.lastIndexOf(".");
2234
+ if (dot < 0) return "plaintext";
2235
+ const ext = name.slice(dot).toLowerCase();
2236
+ const map = {
2237
+ ".py": "python",
2238
+ ".js": "javascript",
2239
+ ".ts": "typescript",
2240
+ ".tsx": "tsx",
2241
+ ".jsx": "jsx",
2242
+ ".json": "json",
2243
+ ".yaml": "yaml",
2244
+ ".yml": "yaml",
2245
+ ".toml": "toml",
2246
+ ".sql": "sql",
2247
+ ".sh": "bash",
2248
+ ".css": "css",
2249
+ ".html": "html",
2250
+ ".md": "markdown",
2251
+ ".rs": "rust",
2252
+ ".go": "go",
2253
+ ".java": "java",
2254
+ ".rb": "ruby",
2255
+ ".php": "php",
2256
+ ".c": "c",
2257
+ ".cpp": "cpp",
2258
+ ".h": "c",
2259
+ ".hpp": "cpp"
2260
+ };
2261
+ return map[ext] ?? "plaintext";
2262
+ }
2144
2263
  function SessionSearchBlock({ tc }) {
2145
2264
  let query = "";
2146
2265
  try {
@@ -2179,9 +2298,7 @@ function WebToolBlock({ tc }) {
2179
2298
  ] });
2180
2299
  }
2181
2300
  function MCPToolBlock({ tc }) {
2182
- const segments = tc.toolName.replace(/^mcp__/, "").split("__");
2183
- const toolName = segments[segments.length - 1] ?? tc.toolName;
2184
- const label = toolName.split("_").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
2301
+ const label = formatMcpToolLabel(tc.toolName);
2185
2302
  let summary = "";
2186
2303
  try {
2187
2304
  const args = JSON.parse(tc.args);
@@ -6025,7 +6142,7 @@ function ChatComposerInner({
6025
6142
  type: "button",
6026
6143
  variant: "secondary",
6027
6144
  size: "sm",
6028
- className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent",
6145
+ className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6029
6146
  onClick: () => {
6030
6147
  setMenuMode("commands");
6031
6148
  setMenuDismissed(false);
@@ -6043,7 +6160,7 @@ function ChatComposerInner({
6043
6160
  type: "button",
6044
6161
  variant: "secondary",
6045
6162
  size: "sm",
6046
- className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent",
6163
+ className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6047
6164
  onClick: () => {
6048
6165
  setMenuMode("skills");
6049
6166
  setMenuDismissed(false);
@@ -6061,7 +6178,7 @@ function ChatComposerInner({
6061
6178
  type: "button",
6062
6179
  variant: "secondary",
6063
6180
  size: "sm",
6064
- className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent",
6181
+ className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6065
6182
  onClick: () => {
6066
6183
  setMenuMode("scheduled");
6067
6184
  setMenuDismissed(false);
@@ -6390,6 +6507,74 @@ function ChatComposerInner({
6390
6507
  }
6391
6508
  );
6392
6509
  }
6510
+ var MAX_LOGOS = 10;
6511
+ function IntegrationsBand({
6512
+ agentId,
6513
+ adapter,
6514
+ onOpenIntegrations
6515
+ }) {
6516
+ const supported = typeof adapter.listComposioConnections === "function" && typeof adapter.authorizeComposioToolkit === "function";
6517
+ const [rows, setRows] = useState(null);
6518
+ const refresh = useCallback(async () => {
6519
+ if (!adapter.listComposioConnections) return;
6520
+ const res = await adapter.listComposioConnections({ agentId });
6521
+ setRows(res.toolkits);
6522
+ }, [adapter, agentId]);
6523
+ useEffect(() => {
6524
+ if (!supported) return;
6525
+ void refresh();
6526
+ const onFocus = () => void refresh();
6527
+ window.addEventListener("focus", onFocus);
6528
+ return () => window.removeEventListener("focus", onFocus);
6529
+ }, [supported, refresh]);
6530
+ if (!supported || rows === null || rows.length === 0) return null;
6531
+ const shown = rows.slice(0, MAX_LOGOS);
6532
+ return /* @__PURE__ */ jsx("div", { className: "px-5", children: /* @__PURE__ */ jsxs(
6533
+ "button",
6534
+ {
6535
+ type: "button",
6536
+ onClick: onOpenIntegrations,
6537
+ className: "flex w-full items-center gap-2 border border-border border-t-0 rounded-b-lg px-4 py-2.5 text-xs text-muted-foreground transition-colors hover:bg-accent/40 cursor-pointer",
6538
+ children: [
6539
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Connect your accounts" }),
6540
+ /* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1.5", children: [
6541
+ shown.map((r) => /* @__PURE__ */ jsx(Logo, { row: r }, r.toolkit)),
6542
+ /* @__PURE__ */ jsx(
6543
+ ChevronRightIcon,
6544
+ {
6545
+ "aria-hidden": true,
6546
+ className: "h-3.5 w-3.5 text-muted-foreground/60"
6547
+ }
6548
+ )
6549
+ ] })
6550
+ ]
6551
+ }
6552
+ ) });
6553
+ }
6554
+ function Logo({ row }) {
6555
+ const [broken, setBroken] = useState(false);
6556
+ const label = row.name ?? row.toolkit;
6557
+ if (broken || !row.logo) {
6558
+ return /* @__PURE__ */ jsx(
6559
+ "span",
6560
+ {
6561
+ title: label,
6562
+ className: "inline-flex h-4 w-4 items-center justify-center rounded-full bg-muted text-[8px] font-semibold uppercase",
6563
+ children: label.charAt(0)
6564
+ }
6565
+ );
6566
+ }
6567
+ return /* @__PURE__ */ jsx(
6568
+ "img",
6569
+ {
6570
+ src: row.logo,
6571
+ alt: label,
6572
+ title: label,
6573
+ className: "h-4 w-4 rounded-sm object-contain",
6574
+ onError: () => setBroken(true)
6575
+ }
6576
+ );
6577
+ }
6393
6578
  function ResearchSourcesPanel({
6394
6579
  sources
6395
6580
  }) {
@@ -7316,45 +7501,6 @@ var ErrorMessage = memo(function ErrorMessage2({
7316
7501
  }
7317
7502
  );
7318
7503
  });
7319
-
7320
- // src/lib/format.ts
7321
- function formatFileSize(bytes) {
7322
- if (bytes < 1024) return `${bytes} B`;
7323
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
7324
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
7325
- }
7326
- function getLanguageHint(path) {
7327
- const name = path.split("/").pop() ?? path;
7328
- const dot = name.lastIndexOf(".");
7329
- if (dot < 0) return "plaintext";
7330
- const ext = name.slice(dot).toLowerCase();
7331
- const map = {
7332
- ".py": "python",
7333
- ".js": "javascript",
7334
- ".ts": "typescript",
7335
- ".tsx": "tsx",
7336
- ".jsx": "jsx",
7337
- ".json": "json",
7338
- ".yaml": "yaml",
7339
- ".yml": "yaml",
7340
- ".toml": "toml",
7341
- ".sql": "sql",
7342
- ".sh": "bash",
7343
- ".css": "css",
7344
- ".html": "html",
7345
- ".md": "markdown",
7346
- ".rs": "rust",
7347
- ".go": "go",
7348
- ".java": "java",
7349
- ".rb": "ruby",
7350
- ".php": "php",
7351
- ".c": "c",
7352
- ".cpp": "cpp",
7353
- ".h": "c",
7354
- ".hpp": "cpp"
7355
- };
7356
- return map[ext] ?? "plaintext";
7357
- }
7358
7504
  function Skeleton({ className, ...props }) {
7359
7505
  return /* @__PURE__ */ jsx(
7360
7506
  "div",
@@ -8379,7 +8525,9 @@ function cancelledToolLabel(toolName) {
8379
8525
  research_memory: "Research",
8380
8526
  research_outline: "Research"
8381
8527
  };
8382
- return map[toolName] ?? toolName;
8528
+ if (map[toolName]) return map[toolName];
8529
+ if (toolName.startsWith("mcp__")) return formatMcpToolLabel(toolName);
8530
+ return toolName;
8383
8531
  }
8384
8532
  function CancelledToolRow({ tc }) {
8385
8533
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-sm", children: [
@@ -9242,7 +9390,9 @@ function ChatThread({
9242
9390
  onViewModeChange,
9243
9391
  deepResearchEnabled = false,
9244
9392
  researchSources = [],
9245
- hideTurnSummary = false
9393
+ hideTurnSummary = false,
9394
+ agentId,
9395
+ onOpenIntegrations
9246
9396
  }) {
9247
9397
  const groups = useMemo(() => groupMessages(messages), [messages]);
9248
9398
  const awaitingInput = useMemo(() => isAwaitingUserInput(messages), [messages]);
@@ -9282,6 +9432,44 @@ function ChatThread({
9282
9432
  }
9283
9433
  return null;
9284
9434
  }, [messages]);
9435
+ const composerArea = /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-4xl px-3 sm:px-6 pb-3 sm:pb-5 pt-3", children: [
9436
+ retryIndicator && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(RetryBanner, { indicator: retryIndicator }) }),
9437
+ researchSources.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(ResearchSourcesPanel, { sources: researchSources }) }),
9438
+ /* @__PURE__ */ jsx(
9439
+ ChatComposer,
9440
+ {
9441
+ onSend,
9442
+ onStop,
9443
+ isRunning,
9444
+ disabled: composerDisabled,
9445
+ disabledReason: composerDisabledReason,
9446
+ tokenUsage,
9447
+ onComposerError,
9448
+ showBrowser,
9449
+ onToggleBrowser,
9450
+ showWorkspace,
9451
+ onToggleWorkspace,
9452
+ canShowBrowser,
9453
+ canShowWorkspace,
9454
+ viewMode,
9455
+ onViewModeChange,
9456
+ deepResearchEnabled
9457
+ }
9458
+ ),
9459
+ onOpenIntegrations && /* @__PURE__ */ jsx(
9460
+ IntegrationsBandSlot,
9461
+ {
9462
+ agentId,
9463
+ onOpenIntegrations
9464
+ }
9465
+ )
9466
+ ] });
9467
+ if (messages.length === 0 && !isLoadingHistory && !disabled) {
9468
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center justify-center overflow-hidden bg-background px-3 text-base", children: /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
9469
+ /* @__PURE__ */ jsx("h2", { className: "mb-8 text-center text-2xl font-bold text-foreground", children: "What should we do ?" }),
9470
+ composerArea
9471
+ ] }) });
9472
+ }
9285
9473
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden bg-background text-base", children: [
9286
9474
  /* @__PURE__ */ jsxs(Conversation, { className: "relative flex-1 min-h-0", children: [
9287
9475
  /* @__PURE__ */ jsx(ConversationContent, { className: "mx-auto w-full max-w-4xl", children: messages.length === 0 && isLoadingHistory ? /* @__PURE__ */ jsx(
@@ -9291,13 +9479,6 @@ function ChatThread({
9291
9479
  title: "Loading conversation",
9292
9480
  description: "Fetching the session history."
9293
9481
  }
9294
- ) : messages.length === 0 && !disabled ? /* @__PURE__ */ jsx(
9295
- ConversationEmptyState,
9296
- {
9297
- icon: /* @__PURE__ */ jsx(MessageSquareIcon, { className: "size-8 opacity-40" }),
9298
- title: "Start a conversation",
9299
- description: "Ask me anything \u2014 I can search, analyze, write code, and more."
9300
- }
9301
9482
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
9302
9483
  groups.map((group) => {
9303
9484
  if (group.role === "user") {
@@ -9350,33 +9531,23 @@ function ChatThread({
9350
9531
  ] }) }),
9351
9532
  /* @__PURE__ */ jsx(ConversationScrollButton, {})
9352
9533
  ] }),
9353
- /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-4xl px-3 sm:px-6 pb-3 sm:pb-5 pt-3", children: [
9354
- retryIndicator && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(RetryBanner, { indicator: retryIndicator }) }),
9355
- researchSources.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(ResearchSourcesPanel, { sources: researchSources }) }),
9356
- /* @__PURE__ */ jsx(
9357
- ChatComposer,
9358
- {
9359
- onSend,
9360
- onStop,
9361
- isRunning,
9362
- disabled: composerDisabled,
9363
- disabledReason: composerDisabledReason,
9364
- tokenUsage,
9365
- onComposerError,
9366
- showBrowser,
9367
- onToggleBrowser,
9368
- showWorkspace,
9369
- onToggleWorkspace,
9370
- canShowBrowser,
9371
- canShowWorkspace,
9372
- viewMode,
9373
- onViewModeChange,
9374
- deepResearchEnabled
9375
- }
9376
- )
9377
- ] })
9534
+ composerArea
9378
9535
  ] });
9379
9536
  }
9537
+ function IntegrationsBandSlot({
9538
+ agentId,
9539
+ onOpenIntegrations
9540
+ }) {
9541
+ const { adapter } = useAgentChatAdapterContext();
9542
+ return /* @__PURE__ */ jsx(
9543
+ IntegrationsBand,
9544
+ {
9545
+ agentId,
9546
+ adapter,
9547
+ onOpenIntegrations
9548
+ }
9549
+ );
9550
+ }
9380
9551
  var noop = () => {
9381
9552
  };
9382
9553
  var FileTreeContext = createContext({
@@ -11503,7 +11674,8 @@ function AgentChat({
11503
11674
  onMessagesChange,
11504
11675
  disabled,
11505
11676
  onComposerError,
11506
- deepResearchEnabled = false
11677
+ deepResearchEnabled = false,
11678
+ onOpenIntegrations
11507
11679
  }) {
11508
11680
  const [workspacePath, setWorkspacePath] = useState(null);
11509
11681
  const [mobileView, setMobileView] = useState("chat");
@@ -11653,7 +11825,9 @@ function AgentChat({
11653
11825
  onViewModeChange: runtime.setViewMode,
11654
11826
  deepResearchEnabled,
11655
11827
  researchSources: runtime.researchSources,
11656
- hideTurnSummary
11828
+ hideTurnSummary,
11829
+ agentId,
11830
+ onOpenIntegrations
11657
11831
  }
11658
11832
  )
11659
11833
  }
@@ -11744,6 +11918,198 @@ function delegateTaskTargets(rawArgs) {
11744
11918
  }
11745
11919
  return out;
11746
11920
  }
11921
+ var POLL_INTERVAL_MS = 2e3;
11922
+ var POLL_TIMEOUT_MS = 18e4;
11923
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
11924
+ function titleCase(slug) {
11925
+ return slug.split(/[_-]/).filter(Boolean).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
11926
+ }
11927
+ function IntegrationsPage({ agentId, adapter, onBack }) {
11928
+ const [rows, setRows] = useState([]);
11929
+ const [query, setQuery] = useState("");
11930
+ const [busy, setBusy] = useState(null);
11931
+ const [error, setError] = useState(null);
11932
+ const mountedRef = useRef(true);
11933
+ useEffect(() => {
11934
+ mountedRef.current = true;
11935
+ return () => {
11936
+ mountedRef.current = false;
11937
+ };
11938
+ }, []);
11939
+ const refresh = useCallback(async () => {
11940
+ if (!adapter.listComposioConnections) return;
11941
+ const res = await adapter.listComposioConnections({ agentId });
11942
+ setRows(res.toolkits);
11943
+ }, [adapter, agentId]);
11944
+ useEffect(() => {
11945
+ void refresh();
11946
+ const onFocus = () => void refresh();
11947
+ window.addEventListener("focus", onFocus);
11948
+ return () => window.removeEventListener("focus", onFocus);
11949
+ }, [refresh]);
11950
+ const grouped = useMemo(() => {
11951
+ const q = query.trim().toLowerCase();
11952
+ const filtered = rows.filter(
11953
+ (r) => (r.name ?? titleCase(r.toolkit)).toLowerCase().includes(q)
11954
+ );
11955
+ const byCat = /* @__PURE__ */ new Map();
11956
+ for (const r of filtered) {
11957
+ const cat = r.category || "Other";
11958
+ const list = byCat.get(cat) ?? [];
11959
+ list.push(r);
11960
+ byCat.set(cat, list);
11961
+ }
11962
+ return Array.from(byCat.entries());
11963
+ }, [rows, query]);
11964
+ const waitForConnection = async (toolkit, popup) => {
11965
+ if (!adapter.listComposioConnections) return;
11966
+ const deadline = Date.now() + POLL_TIMEOUT_MS;
11967
+ while (Date.now() < deadline) {
11968
+ await sleep(POLL_INTERVAL_MS);
11969
+ if (!mountedRef.current) return;
11970
+ let toolkits = null;
11971
+ try {
11972
+ const res = await adapter.listComposioConnections({ agentId });
11973
+ toolkits = res.toolkits;
11974
+ if (!mountedRef.current) return;
11975
+ setRows(res.toolkits);
11976
+ } catch {
11977
+ }
11978
+ const connected = toolkits?.find((t) => t.toolkit === toolkit)?.connected;
11979
+ if (connected) {
11980
+ popup?.close();
11981
+ return;
11982
+ }
11983
+ if (popup?.closed) return;
11984
+ }
11985
+ };
11986
+ const connect = async (toolkit) => {
11987
+ if (!adapter.authorizeComposioToolkit) return;
11988
+ setBusy(toolkit);
11989
+ setError(null);
11990
+ try {
11991
+ const { redirectUrl } = await adapter.authorizeComposioToolkit({
11992
+ agentId,
11993
+ toolkit
11994
+ });
11995
+ const popup = redirectUrl ? openOAuthPopup(redirectUrl) : null;
11996
+ await waitForConnection(toolkit, popup);
11997
+ } catch (e) {
11998
+ setError(e instanceof Error ? e.message : "Failed to start the connection");
11999
+ } finally {
12000
+ setBusy(null);
12001
+ }
12002
+ };
12003
+ const disconnect = async (toolkit) => {
12004
+ if (!adapter.disconnectComposioToolkit) return;
12005
+ setBusy(toolkit);
12006
+ setError(null);
12007
+ try {
12008
+ await adapter.disconnectComposioToolkit({ agentId, toolkit });
12009
+ await refresh();
12010
+ } catch (e) {
12011
+ setError(e instanceof Error ? e.message : "Failed to disconnect");
12012
+ } finally {
12013
+ setBusy(null);
12014
+ }
12015
+ };
12016
+ return /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-6 p-6", children: [
12017
+ /* @__PURE__ */ jsxs(
12018
+ "button",
12019
+ {
12020
+ type: "button",
12021
+ onClick: onBack,
12022
+ className: "flex w-fit items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground",
12023
+ children: [
12024
+ /* @__PURE__ */ jsx(ArrowLeftIcon, { className: "h-4 w-4" }),
12025
+ "Back"
12026
+ ]
12027
+ }
12028
+ ),
12029
+ /* @__PURE__ */ jsxs("div", { children: [
12030
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-foreground", children: "Integrations" }),
12031
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Connect third-party services to enhance your agent's capabilities" })
12032
+ ] }),
12033
+ /* @__PURE__ */ jsx(
12034
+ "input",
12035
+ {
12036
+ type: "search",
12037
+ value: query,
12038
+ onChange: (e) => setQuery(e.target.value),
12039
+ placeholder: "Search integrations...",
12040
+ className: "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm"
12041
+ }
12042
+ ),
12043
+ error && /* @__PURE__ */ jsx("div", { role: "alert", className: "text-xs text-red-500", children: error }),
12044
+ grouped.map(([category, items]) => /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-2", children: [
12045
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold uppercase tracking-wide text-muted-foreground/70", children: category }),
12046
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: items.map((r) => /* @__PURE__ */ jsx(
12047
+ ToolkitRow,
12048
+ {
12049
+ row: r,
12050
+ busy: busy === r.toolkit,
12051
+ onConnect: () => connect(r.toolkit),
12052
+ onDisconnect: () => disconnect(r.toolkit)
12053
+ },
12054
+ r.toolkit
12055
+ )) })
12056
+ ] }, category))
12057
+ ] });
12058
+ }
12059
+ function ToolkitRow({
12060
+ row,
12061
+ busy,
12062
+ onConnect,
12063
+ onDisconnect
12064
+ }) {
12065
+ const [open, setOpen] = useState(false);
12066
+ const [broken, setBroken] = useState(false);
12067
+ const name = row.name ?? titleCase(row.toolkit);
12068
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-border p-3", children: [
12069
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12070
+ /* @__PURE__ */ jsxs(
12071
+ "button",
12072
+ {
12073
+ type: "button",
12074
+ "aria-label": open ? "Collapse" : "Expand",
12075
+ "aria-expanded": open,
12076
+ onClick: () => setOpen((v) => !v),
12077
+ className: "flex min-w-0 flex-1 items-center gap-2 text-left",
12078
+ children: [
12079
+ open ? /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/60" }) : /* @__PURE__ */ jsx(ChevronRightIcon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/60" }),
12080
+ broken || !row.logo ? /* @__PURE__ */ jsx("span", { className: "inline-flex h-5 w-5 items-center justify-center rounded bg-muted text-sm font-semibold uppercase", children: name.charAt(0) }) : /* @__PURE__ */ jsx(
12081
+ "img",
12082
+ {
12083
+ src: row.logo,
12084
+ alt: name,
12085
+ className: "h-5 w-5 rounded object-contain",
12086
+ onError: () => setBroken(true)
12087
+ }
12088
+ ),
12089
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium text-foreground", children: name })
12090
+ ]
12091
+ }
12092
+ ),
12093
+ /* @__PURE__ */ jsx(
12094
+ "button",
12095
+ {
12096
+ type: "button",
12097
+ disabled: busy,
12098
+ onClick: row.connected ? onDisconnect : onConnect,
12099
+ className: `ml-auto inline-flex min-w-[6rem] items-center justify-center gap-1.5 rounded-md border border-border px-2 py-1 text-xs hover:bg-accent disabled:opacity-60 ${row.connected ? "text-muted-foreground" : "text-foreground"}`,
12100
+ children: busy ? /* @__PURE__ */ jsxs(Fragment, { children: [
12101
+ /* @__PURE__ */ jsx(Loader2Icon, { className: "h-3.5 w-3.5 animate-spin" }),
12102
+ row.connected ? "Disconnecting" : "Connecting"
12103
+ ] }) : row.connected ? "Disconnect" : "Connect"
12104
+ }
12105
+ )
12106
+ ] }),
12107
+ open && /* @__PURE__ */ jsxs("div", { className: "mt-2 pl-7 text-sm text-muted-foreground", children: [
12108
+ row.description && /* @__PURE__ */ jsx("p", { children: row.description }),
12109
+ /* @__PURE__ */ jsx("span", { className: "mt-1 inline-block rounded bg-primary/10 px-1.5 py-0.5 text-sm font-semibold text-primary", children: row.auth_mode === "api_key" ? "API Key" : "OAuth" })
12110
+ ] })
12111
+ ] });
12112
+ }
11747
12113
  var DEFAULT_LIMIT = 50;
11748
12114
  function requireInboxAdapter(adapter) {
11749
12115
  if (!adapter.listInbox || !adapter.getInboxItem || !adapter.markInboxItemRead || !adapter.acknowledgeInboxItem || !adapter.respondGovernanceInboxItem || !adapter.openInboxStream) {
@@ -14208,6 +14574,6 @@ function SessionTreePanel({
14208
14574
  ] });
14209
14575
  }
14210
14576
 
14211
- export { ACTIVE_MISSION_STATUSES, AgentChat, AgentChatAdapterProvider, CitationText, InboxPanel, MessageResponse, MissionDashboard, MissionsPanel, ResearchSourcesPanel, ScheduledWorkPanel, SessionTreePanel, deriveMissionWorkerActivityLabel, groupMissionTasksByBucket, isTerminalMissionStatus, missionTaskBucket, splitCitations, useAgentChatAdapterContext, useAgentChatRuntime, useChatViewMode, useInboxUnreadCount };
14577
+ export { ACTIVE_MISSION_STATUSES, AgentChat, AgentChatAdapterProvider, CitationText, ComposioConnectCard, InboxPanel, IntegrationsBand, IntegrationsPage, MessageResponse, MissionDashboard, MissionsPanel, ResearchSourcesPanel, ScheduledWorkPanel, SessionTreePanel, deriveMissionWorkerActivityLabel, groupMissionTasksByBucket, isTerminalMissionStatus, missionTaskBucket, splitCitations, useAgentChatAdapterContext, useAgentChatRuntime, useChatViewMode, useInboxUnreadCount };
14212
14578
  //# sourceMappingURL=index.js.map
14213
14579
  //# sourceMappingURL=index.js.map