@@ -243,6 +243,18 @@ export function getToolInfo(tool: string, input: any = {}): ToolInfo {
243243 title : i18n . t ( "ui.tool.webfetch" ) ,
244244 subtitle : input . url ,
245245 }
246+ case "websearch" :
247+ return {
248+ icon : "window-cursor" ,
249+ title : i18n . t ( "ui.tool.websearch" ) ,
250+ subtitle : input . query ,
251+ }
252+ case "codesearch" :
253+ return {
254+ icon : "code" ,
255+ title : i18n . t ( "ui.tool.codesearch" ) ,
256+ subtitle : input . query ,
257+ }
246258 case "task" :
247259 return {
248260 icon : "task" ,
@@ -303,6 +315,18 @@ export function getToolInfo(tool: string, input: any = {}): ToolInfo {
303315 }
304316}
305317
318+ function urls ( text : string | undefined ) {
319+ if ( ! text ) return [ ]
320+ const seen = new Set < string > ( )
321+ return [ ...text . matchAll ( / h t t p s ? : \/ \/ [ ^ \s < > " ' ` ) \] ] + / g) ]
322+ . map ( ( item ) => item [ 0 ] . replace ( / [ ) , . ; : ! ? ] + $ / g, "" ) )
323+ . filter ( ( item ) => {
324+ if ( seen . has ( item ) ) return false
325+ seen . add ( item )
326+ return true
327+ } )
328+ }
329+
306330const CONTEXT_GROUP_TOOLS = new Set ( [ "read" , "glob" , "grep" , "list" ] )
307331const HIDDEN_TOOLS = new Set ( [ "todowrite" , "todoread" ] )
308332
@@ -598,6 +622,32 @@ function contextToolSummary(parts: ToolPart[]) {
598622 return { read, search, list }
599623}
600624
625+ function ExaOutput ( props : { output ?: string } ) {
626+ const links = createMemo ( ( ) => urls ( props . output ) )
627+
628+ return (
629+ < Show when = { links ( ) . length > 0 } >
630+ < div data-component = "exa-tool-output" >
631+ < div data-slot = "exa-tool-links" >
632+ < For each = { links ( ) } >
633+ { ( url ) => (
634+ < a
635+ data-slot = "exa-tool-link"
636+ href = { url }
637+ target = "_blank"
638+ rel = "noopener noreferrer"
639+ onClick = { ( event ) => event . stopPropagation ( ) }
640+ >
641+ { url }
642+ </ a >
643+ ) }
644+ </ For >
645+ </ div >
646+ </ div >
647+ </ Show >
648+ )
649+ }
650+
601651export function registerPartComponent ( type : string , component : PartComponent ) {
602652 PART_MAPPING [ type ] = component
603653}
@@ -1467,6 +1517,58 @@ ToolRegistry.register({
14671517 } ,
14681518} )
14691519
1520+ ToolRegistry . register ( {
1521+ name : "websearch" ,
1522+ render ( props ) {
1523+ const i18n = useI18n ( )
1524+ const query = createMemo ( ( ) => {
1525+ const value = props . input . query
1526+ if ( typeof value !== "string" ) return ""
1527+ return value
1528+ } )
1529+
1530+ return (
1531+ < BasicTool
1532+ { ...props }
1533+ icon = "window-cursor"
1534+ trigger = { {
1535+ title : i18n . t ( "ui.tool.websearch" ) ,
1536+ subtitle : query ( ) ,
1537+ subtitleClass : "exa-tool-query" ,
1538+ } }
1539+ >
1540+ < ExaOutput output = { props . output } />
1541+ </ BasicTool >
1542+ )
1543+ } ,
1544+ } )
1545+
1546+ ToolRegistry . register ( {
1547+ name : "codesearch" ,
1548+ render ( props ) {
1549+ const i18n = useI18n ( )
1550+ const query = createMemo ( ( ) => {
1551+ const value = props . input . query
1552+ if ( typeof value !== "string" ) return ""
1553+ return value
1554+ } )
1555+
1556+ return (
1557+ < BasicTool
1558+ { ...props }
1559+ icon = "code"
1560+ trigger = { {
1561+ title : i18n . t ( "ui.tool.codesearch" ) ,
1562+ subtitle : query ( ) ,
1563+ subtitleClass : "exa-tool-query" ,
1564+ } }
1565+ >
1566+ < ExaOutput output = { props . output } />
1567+ </ BasicTool >
1568+ )
1569+ } ,
1570+ } )
1571+
14701572ToolRegistry . register ( {
14711573 name : "task" ,
14721574 render ( props ) {
0 commit comments