From ec8b9810b4231cd6a5c69ccd930b6c50999fc997 Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Tue, 7 Apr 2026 11:06:23 -0500
Subject: feat(app): better subagent experience (#20708)

---
 packages/ui/src/components/basic-tool.tsx | 142 ++++++++++++++++++------------
 1 file changed, 86 insertions(+), 56 deletions(-)

(limited to 'packages/ui/src/components/basic-tool.tsx')

diff --git a/packages/ui/src/components/basic-tool.tsx b/packages/ui/src/components/basic-tool.tsx
index a02fe941b..7d18dfacd 100644
--- a/packages/ui/src/components/basic-tool.tsx
+++ b/packages/ui/src/components/basic-tool.tsx
@@ -34,6 +34,9 @@ export interface BasicToolProps {
   locked?: boolean
   animated?: boolean
   onSubtitleClick?: () => void
+  onTriggerClick?: JSX.EventHandlerUnion<HTMLElement, MouseEvent>
+  triggerHref?: string
+  clickable?: boolean
 }
 
 const SPRING = { type: "spring" as const, visualDuration: 0.35, bounce: 0 }
@@ -121,74 +124,101 @@ export function BasicTool(props: BasicToolProps) {
     setState("open", value)
   }
 
-  return (
-    <Collapsible open={open()} onOpenChange={handleOpenChange} class="tool-collapsible">
-      <Collapsible.Trigger>
-        <div data-component="tool-trigger">
-          <div data-slot="basic-tool-tool-trigger-content">
-            <div data-slot="basic-tool-tool-info">
-              <Switch>
-                <Match when={isTriggerTitle(props.trigger) && props.trigger}>
-                  {(trigger) => (
-                    <div data-slot="basic-tool-tool-info-structured">
-                      <div data-slot="basic-tool-tool-info-main">
+  const trigger = () => (
+    <div
+      data-component="tool-trigger"
+      data-clickable={props.clickable ? "true" : undefined}
+      data-hide-details={props.hideDetails ? "true" : undefined}
+    >
+      <div data-slot="basic-tool-tool-trigger-content">
+        <div data-slot="basic-tool-tool-info">
+          <Switch>
+            <Match when={isTriggerTitle(props.trigger) && props.trigger}>
+              {(title) => (
+                <div data-slot="basic-tool-tool-info-structured">
+                  <div data-slot="basic-tool-tool-info-main">
+                    <span
+                      data-slot="basic-tool-tool-title"
+                      classList={{
+                        [title().titleClass ?? ""]: !!title().titleClass,
+                      }}
+                    >
+                      <TextShimmer text={title().title} active={pending()} />
+                    </span>
+                    <Show when={!pending()}>
+                      <Show when={title().subtitle}>
                         <span
-                          data-slot="basic-tool-tool-title"
+                          data-slot="basic-tool-tool-subtitle"
                           classList={{
-                            [trigger().titleClass ?? ""]: !!trigger().titleClass,
+                            [title().subtitleClass ?? ""]: !!title().subtitleClass,
+                            clickable: !!props.onSubtitleClick,
+                          }}
+                          onClick={(e) => {
+                            if (props.onSubtitleClick) {
+                              e.stopPropagation()
+                              props.onSubtitleClick()
+                            }
                           }}
                         >
-                          <TextShimmer text={trigger().title} active={pending()} />
+                          {title().subtitle}
                         </span>
-                        <Show when={!pending()}>
-                          <Show when={trigger().subtitle}>
+                      </Show>
+                      <Show when={title().args?.length}>
+                        <For each={title().args}>
+                          {(arg) => (
                             <span
-                              data-slot="basic-tool-tool-subtitle"
+                              data-slot="basic-tool-tool-arg"
                               classList={{
-                                [trigger().subtitleClass ?? ""]: !!trigger().subtitleClass,
-                                clickable: !!props.onSubtitleClick,
-                              }}
-                              onClick={(e) => {
-                                if (props.onSubtitleClick) {
-                                  e.stopPropagation()
-                                  props.onSubtitleClick()
-                                }
+                                [title().argsClass ?? ""]: !!title().argsClass,
                               }}
                             >
-                              {trigger().subtitle}
+                              {arg}
                             </span>
-                          </Show>
-                          <Show when={trigger().args?.length}>
-                            <For each={trigger().args}>
-                              {(arg) => (
-                                <span
-                                  data-slot="basic-tool-tool-arg"
-                                  classList={{
-                                    [trigger().argsClass ?? ""]: !!trigger().argsClass,
-                                  }}
-                                >
-                                  {arg}
-                                </span>
-                              )}
-                            </For>
-                          </Show>
-                        </Show>
-                      </div>
-                      <Show when={!pending() && trigger().action}>
-                        <span data-slot="basic-tool-tool-action">{trigger().action}</span>
+                          )}
+                        </For>
                       </Show>
-                    </div>
-                  )}
-                </Match>
-                <Match when={true}>{props.trigger as JSX.Element}</Match>
-              </Switch>
-            </div>
-          </div>
-          <Show when={props.children && !props.hideDetails && !props.locked && !pending()}>
-            <Collapsible.Arrow />
-          </Show>
+                    </Show>
+                  </div>
+                  <Show when={!pending() && title().action}>
+                    <span data-slot="basic-tool-tool-action">{title().action}</span>
+                  </Show>
+                </div>
+              )}
+            </Match>
+            <Match when={true}>{props.trigger as JSX.Element}</Match>
+          </Switch>
         </div>
-      </Collapsible.Trigger>
+      </div>
+      <Show when={props.children && !props.hideDetails && !props.locked && !pending()}>
+        <Collapsible.Arrow />
+      </Show>
+    </div>
+  )
+
+  return (
+    <Collapsible open={open()} onOpenChange={handleOpenChange} class="tool-collapsible">
+      <Show
+        when={props.triggerHref}
+        fallback={
+          <Collapsible.Trigger
+            data-hide-details={props.hideDetails ? "true" : undefined}
+            onClick={props.onTriggerClick}
+          >
+            {trigger()}
+          </Collapsible.Trigger>
+        }
+      >
+        {(href) => (
+          <Collapsible.Trigger
+            as="a"
+            href={href()}
+            data-hide-details={props.hideDetails ? "true" : undefined}
+            onClick={props.onTriggerClick}
+          >
+            {trigger()}
+          </Collapsible.Trigger>
+        )}
+      </Show>
       <Show when={props.animated && props.children && !props.hideDetails}>
         <div
           ref={contentRef}
-- 
cgit v1.2.3

