slash-command-web-handlers.ts
1 import type { DuckDuckGoSearchType } from '@/lib/shared/chat' 2 import type { CommandExecutionTextResult } from '@/lib/shared/command-execution' 3 import { 4 executeWebFetchTool, 5 executeWebSearchTool, 6 } from '@/server/tools/web-tool-execution' 7 8 export async function runWebSearchSlashCommand(input: { 9 query: string 10 searchType?: DuckDuckGoSearchType 11 attachmentNote: string 12 }): Promise<CommandExecutionTextResult> { 13 const execution = await executeWebSearchTool({ 14 query: input.query, 15 searchType: input.searchType, 16 }) 17 18 if (!execution.ok) { 19 return { 20 text: `Web search failed: ${execution.error}${input.attachmentNote}`, 21 provider: 'web-search', 22 mocked: false, 23 } 24 } 25 26 const lines: string[] = [] 27 const typeLabel = 28 input.searchType && input.searchType !== 'web' 29 ? ` (${input.searchType})` 30 : '' 31 lines.push(`**Web Search Results**${typeLabel} (${execution.response.provider})`) 32 lines.push('') 33 34 for (const result of execution.results.slice(0, 5)) { 35 lines.push(`- **${result.title}**`) 36 lines.push(` ${result.url}`) 37 if (result.imageUrl) { 38 lines.push(` `) 39 } 40 if (result.snippet) { 41 lines.push( 42 ` ${result.snippet.slice(0, 200)}${result.snippet.length > 200 ? '...' : ''}`, 43 ) 44 } 45 lines.push('') 46 } 47 48 if (execution.response.cached) { 49 lines.push('*Results from cache*') 50 } 51 52 return { 53 text: lines.join('\n') + input.attachmentNote, 54 provider: 'web-search', 55 mocked: false, 56 } 57 } 58 59 export async function runWebFetchSlashCommand(input: { 60 url: string 61 attachmentNote: string 62 }): Promise<CommandExecutionTextResult> { 63 const execution = await executeWebFetchTool({ url: input.url }) 64 65 if (!execution.ok) { 66 return { 67 text: `Web fetch failed: ${execution.error}${input.attachmentNote}`, 68 provider: 'web-fetch', 69 mocked: false, 70 } 71 } 72 73 const lines: string[] = [] 74 lines.push(`**${execution.response.result.title}**`) 75 lines.push(`URL: ${execution.response.result.url}`) 76 lines.push('') 77 78 const contentPreview = execution.response.result.content.slice(0, 7500) 79 lines.push(contentPreview) 80 81 if (execution.response.result.content.length > 7500) { 82 lines.push('') 83 lines.push('*... content truncated*') 84 } 85 86 if (execution.response.result.truncated) { 87 lines.push('') 88 lines.push( 89 `*Content was truncated to ${execution.response.result.bytesRead} bytes*`, 90 ) 91 } 92 93 if (execution.response.cached) { 94 lines.push('') 95 lines.push('*Results from cache*') 96 } 97 98 return { 99 text: lines.join('\n') + input.attachmentNote, 100 provider: 'web-fetch', 101 mocked: false, 102 } 103 } 104 105 export function buildWebHelpSlashCommandResult(input: { 106 attachmentNote: string 107 }): CommandExecutionTextResult { 108 const helpText = `**Web Tools Help** 109 110 Available commands: 111 - \`/websearch <query>\` - Search the web for information (default) 112 - \`/websearch --image <query>\` - Search for images 113 - \`/websearch --news <query>\` - Search for news articles 114 - \`/websearch --video <query>\` - Search for videos 115 - \`/webfetch <url>\` - Fetch and extract content from a URL 116 - \`/help web\` - Show this help message 117 118 Examples: 119 - \`/websearch current weather in San Francisco\` 120 - \`/websearch --image cute kittens\` 121 - \`/websearch --news technology\` 122 - \`/webfetch https://example.com\` 123 124 Note: DuckDuckGo is used as the default provider (no API key required).${input.attachmentNote}` 125 126 return { 127 text: helpText, 128 provider: 'web-help', 129 mocked: false, 130 } 131 }