11"use client" ;
22
33import { Badge } from "@arcadeai/design-system" ;
4+ import { Check , ChevronDown , Lightbulb , Minus , X } from "lucide-react" ;
45import {
56 TOOL_METADATA_FALLBACK_STYLE ,
67 TOOL_METADATA_OPERATION_STYLES ,
@@ -17,7 +18,14 @@ const BEHAVIOR_LABELS: Record<BehaviorFlagKey, string> = {
1718 openWorld : "Open world" ,
1819} ;
1920
20- type BehaviorRow = {
21+ const BEHAVIOR_DESCRIPTIONS : Record < BehaviorFlagKey , string > = {
22+ readOnly : "Does not modify remote state." ,
23+ destructive : "May delete or overwrite remote data." ,
24+ idempotent : "Safe to retry without extra side effects." ,
25+ openWorld : "Can call out to external systems." ,
26+ } ;
27+
28+ export type BehaviorRow = {
2129 key : BehaviorFlagKey ;
2230 label : string ;
2331 value : boolean | null ;
@@ -34,7 +42,18 @@ export function buildBehaviorRows(
3442}
3543
3644function formatEnumLabel ( value : string ) : string {
37- return value . replaceAll ( "_" , " " ) ;
45+ const words = value . split ( "_" ) ;
46+ return words
47+ . map ( ( word , index ) => {
48+ if ( word === "crm" ) {
49+ return "CRM" ;
50+ }
51+ if ( index === 0 ) {
52+ return word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) . toLowerCase ( ) ;
53+ }
54+ return word . toLowerCase ( ) ;
55+ } )
56+ . join ( " " ) ;
3857}
3958
4059function EnumBadge ( {
@@ -46,7 +65,11 @@ function EnumBadge({
4665} ) {
4766 const styleClass = styles [ value ] ?? TOOL_METADATA_FALLBACK_STYLE ;
4867 return (
49- < Badge className = { styleClass } variant = "outline" >
68+ < Badge
69+ className = { `${ styleClass } gap-1.5 border-0 text-xs font-medium` }
70+ variant = "secondary"
71+ >
72+ < span aria-hidden className = "h-1.5 w-1.5 rounded-full bg-current/80" />
5073 { formatEnumLabel ( value ) }
5174 </ Badge >
5275 ) ;
@@ -56,27 +79,27 @@ function BooleanBadge({ value }: { value: boolean | null }) {
5679 if ( value === null ) {
5780 return (
5881 < Badge
59- className = "border-muted/60 bg-muted/20 text-muted-foreground/70"
60- variant = "outline "
82+ className = "border-0 bg-neutral-dark/40 text-muted-foreground/70"
83+ variant = "secondary "
6184 >
62- N/A
85+ < Minus className = "mr-1 h-3 w-3" /> Unknown
6386 </ Badge >
6487 ) ;
6588 }
6689
6790 return value ? (
6891 < Badge
69- className = "border-emerald-500/40 bg-emerald-500/10 text-emerald-300"
70- variant = "outline "
92+ className = "border-0 bg-emerald-500/15 text-emerald-300"
93+ variant = "secondary "
7194 >
72- true
95+ < Check className = "mr-1 h-3 w-3" /> Yes
7396 </ Badge >
7497 ) : (
7598 < Badge
76- className = "border-zinc-500/40 bg-zinc -500/10 text-zinc -300"
77- variant = "outline "
99+ className = "border-0 bg-neutral -500/15 text-neutral -300"
100+ variant = "secondary "
78101 >
79- false
102+ < X className = "mr-1 h-3 w-3" /> No
80103 </ Badge >
81104 ) ;
82105}
@@ -104,58 +127,98 @@ export function ToolMetadataSection({
104127 }
105128
106129 return (
107- < div className = "mt-6 rounded-lg bg-neutral-dark/30 p-4" >
108- < h4 className = "mb-3 font-semibold text-muted-foreground text-sm uppercase tracking-wider" >
109- Metadata
110- </ h4 >
111-
112- < div className = "space-y-4" >
113- { hasOperations && (
114- < div className = "flex flex-wrap items-center gap-2" >
115- < span className = "text-muted-foreground text-xs" > Operations:</ span >
116- { metadata . behavior . operations . map ( ( operation ) => (
117- < EnumBadge
118- key = { operation }
119- styles = { TOOL_METADATA_OPERATION_STYLES }
120- value = { operation }
121- />
122- ) ) }
130+ < div className = "mb-6 rounded-xl bg-neutral-dark/15 p-4" >
131+ < div className = "mb-4 flex items-start gap-2.5" >
132+ < div className = "mt-0.5 rounded-md bg-brand-accent/10 p-1.5 text-brand-accent" >
133+ < Lightbulb className = "h-3.5 w-3.5" />
134+ </ div >
135+ < div >
136+ < h4 className = "font-semibold text-foreground text-sm" >
137+ Execution hints
138+ </ h4 >
139+ < p className = "mt-1 text-muted-foreground/75 text-xs" >
140+ Signals for MCP clients and agents about how this tool behaves.
141+ </ p >
142+ </ div >
143+ </ div >
144+
145+ < div className = "space-y-3" >
146+ { ( hasOperations || hasServiceDomains ) && (
147+ < div className = "grid gap-3 md:grid-cols-2" >
148+ { hasOperations && (
149+ < div className = "rounded-lg bg-neutral-dark/20 p-3" >
150+ < span className = "mb-2 block text-muted-foreground/80 text-xs font-medium" >
151+ Operations
152+ </ span >
153+ < div className = "flex flex-wrap items-center gap-2" >
154+ { metadata . behavior . operations . map ( ( operation ) => (
155+ < EnumBadge
156+ key = { operation }
157+ styles = { TOOL_METADATA_OPERATION_STYLES }
158+ value = { operation }
159+ />
160+ ) ) }
161+ </ div >
162+ </ div >
163+ ) }
164+
165+ { hasServiceDomains && (
166+ < div className = "rounded-lg bg-neutral-dark/20 p-3" >
167+ < span className = "mb-2 block text-muted-foreground/80 text-xs font-medium" >
168+ Service domains
169+ </ span >
170+ < div className = "flex flex-wrap items-center gap-2" >
171+ { metadata . classification . serviceDomains . map ( ( domain ) => (
172+ < EnumBadge
173+ key = { domain }
174+ styles = { TOOL_METADATA_SERVICE_DOMAIN_STYLES }
175+ value = { domain }
176+ />
177+ ) ) }
178+ </ div >
179+ </ div >
180+ ) }
123181 </ div >
124182 ) }
125183
126- { hasServiceDomains && (
127- < div className = "flex flex-wrap items-center gap-2 " >
128- < span className = "text-muted-foreground text-xs" >
129- Service domains:
184+ { hasAnyBehaviorValue && (
185+ < div className = "rounded-lg bg-neutral-dark/20 p-3 " >
186+ < span className = "mb-2 block text-muted-foreground/80 text-xs font-medium " >
187+ MCP behavior
130188 </ span >
131- { metadata . classification . serviceDomains . map ( ( domain ) => (
132- < EnumBadge
133- key = { domain }
134- styles = { TOOL_METADATA_SERVICE_DOMAIN_STYLES }
135- value = { domain }
136- />
137- ) ) }
189+ < div className = "grid grid-cols-1 gap-2.5 sm:grid-cols-2" >
190+ { behaviorRows . map ( ( row ) => (
191+ < div
192+ className = "rounded-md bg-neutral-dark/25 p-2.5"
193+ key = { row . key }
194+ >
195+ < div className = "flex items-center justify-between gap-2" >
196+ < span className = "font-medium text-foreground text-xs" >
197+ { row . label }
198+ </ span >
199+ < div className = "flex shrink-0" >
200+ < BooleanBadge value = { row . value } />
201+ </ div >
202+ </ div >
203+ < p className = "mt-1.5 text-[11px] text-muted-foreground/70 leading-relaxed" >
204+ { BEHAVIOR_DESCRIPTIONS [ row . key ] }
205+ </ p >
206+ </ div >
207+ ) ) }
208+ </ div >
138209 </ div >
139210 ) }
140211
141- < div className = "grid grid-cols-2 gap-x-4 gap-y-2 sm:grid-cols-4" >
142- { behaviorRows . map ( ( row ) => (
143- < div className = "flex flex-col gap-1" key = { row . key } >
144- < span className = "text-muted-foreground/70 text-xs" >
145- { row . label }
146- </ span >
147- < BooleanBadge value = { row . value } />
148- </ div >
149- ) ) }
150- </ div >
151-
152212 { hasExtras && (
153- < div className = "space-y-1" >
154- < span className = "text-muted-foreground text-xs" > Extras:</ span >
155- < pre className = "overflow-auto rounded bg-neutral-dark/40 p-3 text-muted-foreground text-xs" >
213+ < details className = "group mt-2 rounded-lg bg-neutral-dark/20" >
214+ < summary className = "flex cursor-pointer list-none items-center justify-between gap-3 px-3 py-2.5 text-muted-foreground/85 text-xs font-medium" >
215+ Additional metadata
216+ < ChevronDown className = "h-3.5 w-3.5 transition-transform group-open:rotate-180" />
217+ </ summary >
218+ < pre className = "overflow-auto p-3 text-muted-foreground text-xs" >
156219 { JSON . stringify ( metadata . extras , null , 2 ) }
157220 </ pre >
158- </ div >
221+ </ details >
159222 ) }
160223 </ div >
161224 </ div >
0 commit comments