diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 06fd3443e..6d9042876 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -4129,3 +4129,27 @@ export function CursorIcon(props: SVGProps) { ) } + +export function DuckDuckGoIcon(props: SVGProps) { + return ( + + + + + + + + + + + ) +} diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index fb56fb1db..f0c8d13d8 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -20,6 +20,7 @@ import { DiscordIcon, DocumentIcon, DropboxIcon, + DuckDuckGoIcon, DynamoDBIcon, ElasticsearchIcon, ElevenLabsIcon, @@ -212,6 +213,7 @@ export const blockTypeToIconMap: Record = { elevenlabs: ElevenLabsIcon, elasticsearch: ElasticsearchIcon, dynamodb: DynamoDBIcon, + duckduckgo: DuckDuckGoIcon, dropbox: DropboxIcon, discord: DiscordIcon, datadog: DatadogIcon, diff --git a/apps/docs/content/docs/en/tools/duckduckgo.mdx b/apps/docs/content/docs/en/tools/duckduckgo.mdx new file mode 100644 index 000000000..baf9f7d6e --- /dev/null +++ b/apps/docs/content/docs/en/tools/duckduckgo.mdx @@ -0,0 +1,68 @@ +--- +title: DuckDuckGo +description: Search with DuckDuckGo +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[DuckDuckGo](https://duckduckgo.com/) is a privacy-focused web search engine that delivers instant answers, abstracts, related topics, and more — without tracking you or your searches. DuckDuckGo makes it easy to find information without any user profiling or targeted ads. + +With DuckDuckGo in Sim, you can: + +- **Search the web**: Instantly find answers, facts, and overviews for a given search query +- **Get direct answers**: Retrieve specific responses for calculations, conversions, or factual queries +- **Access abstracts**: Receive short summaries or descriptions for your search topics +- **Fetch related topics**: Discover links and references relevant to your search +- **Filter output**: Optionally remove HTML or skip disambiguation for cleaner results + +These features enable your Sim agents to automate access to fresh web knowledge — from surfacing facts in a workflow, to enriching documents and analysis with up-to-date information. Because DuckDuckGo’s Instant Answers API is open and does not require an API key, it’s simple and privacy-safe to integrate into your automated business processes. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Search the web using DuckDuckGo Instant Answers API. Returns instant answers, abstracts, related topics, and more. Free to use without an API key. + + + +## Tools + +### `duckduckgo_search` + +Search the web using DuckDuckGo Instant Answers API. Returns instant answers, abstracts, and related topics for your query. Free to use without an API key. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `query` | string | Yes | The search query to execute | +| `noHtml` | boolean | No | Remove HTML from text in results \(default: true\) | +| `skipDisambig` | boolean | No | Skip disambiguation results \(default: false\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `heading` | string | The heading/title of the instant answer | +| `abstract` | string | A short abstract summary of the topic | +| `abstractText` | string | Plain text version of the abstract | +| `abstractSource` | string | The source of the abstract \(e.g., Wikipedia\) | +| `abstractURL` | string | URL to the source of the abstract | +| `image` | string | URL to an image related to the topic | +| `answer` | string | Direct answer if available \(e.g., for calculations\) | +| `answerType` | string | Type of the answer \(e.g., calc, ip, etc.\) | +| `type` | string | Response type: A \(article\), D \(disambiguation\), C \(category\), N \(name\), E \(exclusive\) | +| `relatedTopics` | array | Array of related topics with URLs and descriptions | + + + +## Notes + +- Category: `tools` +- Type: `duckduckgo` diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index 73c1125a1..8f5d2e90e 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -15,6 +15,7 @@ "datadog", "discord", "dropbox", + "duckduckgo", "dynamodb", "elasticsearch", "elevenlabs", diff --git a/apps/sim/blocks/blocks/duckduckgo.ts b/apps/sim/blocks/blocks/duckduckgo.ts new file mode 100644 index 000000000..933e6b6a2 --- /dev/null +++ b/apps/sim/blocks/blocks/duckduckgo.ts @@ -0,0 +1,59 @@ +import { DuckDuckGoIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import type { DuckDuckGoResponse } from '@/tools/duckduckgo/types' + +export const DuckDuckGoBlock: BlockConfig = { + type: 'duckduckgo', + name: 'DuckDuckGo', + description: 'Search with DuckDuckGo', + longDescription: + 'Search the web using DuckDuckGo Instant Answers API. Returns instant answers, abstracts, related topics, and more. Free to use without an API key.', + docsLink: 'https://docs.sim.ai/tools/duckduckgo', + category: 'tools', + bgColor: '#FFFFFF', + icon: DuckDuckGoIcon, + subBlocks: [ + { + id: 'query', + title: 'Search Query', + type: 'long-input', + placeholder: 'Enter your search query...', + required: true, + }, + { + id: 'noHtml', + title: 'Remove HTML', + type: 'switch', + defaultValue: true, + }, + { + id: 'skipDisambig', + title: 'Skip Disambiguation', + type: 'switch', + }, + ], + tools: { + access: ['duckduckgo_search'], + config: { + tool: () => 'duckduckgo_search', + }, + }, + inputs: { + query: { type: 'string', description: 'Search query terms' }, + noHtml: { type: 'boolean', description: 'Remove HTML from text in results' }, + skipDisambig: { type: 'boolean', description: 'Skip disambiguation results' }, + }, + outputs: { + heading: { type: 'string', description: 'The heading/title of the instant answer' }, + abstract: { type: 'string', description: 'A short abstract summary of the topic' }, + abstractText: { type: 'string', description: 'Plain text version of the abstract' }, + abstractSource: { type: 'string', description: 'The source of the abstract' }, + abstractURL: { type: 'string', description: 'URL to the source of the abstract' }, + image: { type: 'string', description: 'URL to an image related to the topic' }, + answer: { type: 'string', description: 'Direct answer if available' }, + answerType: { type: 'string', description: 'Type of the answer' }, + type: { type: 'string', description: 'Response type (A, D, C, N, E)' }, + relatedTopics: { type: 'json', description: 'Array of related topics' }, + results: { type: 'json', description: 'Array of external link results' }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index bd76a0510..7934a5047 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -18,6 +18,7 @@ import { CursorBlock } from '@/blocks/blocks/cursor' import { DatadogBlock } from '@/blocks/blocks/datadog' import { DiscordBlock } from '@/blocks/blocks/discord' import { DropboxBlock } from '@/blocks/blocks/dropbox' +import { DuckDuckGoBlock } from '@/blocks/blocks/duckduckgo' import { DynamoDBBlock } from '@/blocks/blocks/dynamodb' import { ElasticsearchBlock } from '@/blocks/blocks/elasticsearch' import { ElevenLabsBlock } from '@/blocks/blocks/elevenlabs' @@ -157,6 +158,7 @@ export const registry: Record = { datadog: DatadogBlock, discord: DiscordBlock, dropbox: DropboxBlock, + duckduckgo: DuckDuckGoBlock, elevenlabs: ElevenLabsBlock, elasticsearch: ElasticsearchBlock, evaluator: EvaluatorBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 06fd3443e..6d9042876 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -4129,3 +4129,27 @@ export function CursorIcon(props: SVGProps) { ) } + +export function DuckDuckGoIcon(props: SVGProps) { + return ( + + + + + + + + + + + ) +} diff --git a/apps/sim/tools/duckduckgo/index.ts b/apps/sim/tools/duckduckgo/index.ts new file mode 100644 index 000000000..8d8bd53b9 --- /dev/null +++ b/apps/sim/tools/duckduckgo/index.ts @@ -0,0 +1,3 @@ +import { searchTool } from '@/tools/duckduckgo/search' + +export const duckduckgoSearchTool = searchTool diff --git a/apps/sim/tools/duckduckgo/search.ts b/apps/sim/tools/duckduckgo/search.ts new file mode 100644 index 000000000..3e61a4144 --- /dev/null +++ b/apps/sim/tools/duckduckgo/search.ts @@ -0,0 +1,161 @@ +import type { DuckDuckGoSearchParams, DuckDuckGoSearchResponse } from '@/tools/duckduckgo/types' +import type { ToolConfig } from '@/tools/types' + +export const searchTool: ToolConfig = { + id: 'duckduckgo_search', + name: 'DuckDuckGo Search', + description: + 'Search the web using DuckDuckGo Instant Answers API. Returns instant answers, abstracts, and related topics for your query. Free to use without an API key.', + version: '1.0.0', + + params: { + query: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The search query to execute', + }, + noHtml: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'Remove HTML from text in results (default: true)', + }, + skipDisambig: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'Skip disambiguation results (default: false)', + }, + }, + + request: { + url: (params) => { + const baseUrl = 'https://api.duckduckgo.com/' + const searchParams = new URLSearchParams({ + q: params.query, + format: 'json', + no_html: params.noHtml !== false ? '1' : '0', + skip_disambig: params.skipDisambig ? '1' : '0', + }) + return `${baseUrl}?${searchParams.toString()}` + }, + method: 'GET', + headers: () => ({ + Accept: 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + // Map related topics + const relatedTopics = (data.RelatedTopics || []).map((topic: any) => ({ + FirstURL: topic.FirstURL, + Text: topic.Text, + Result: topic.Result, + Icon: topic.Icon + ? { + URL: topic.Icon.URL, + Height: topic.Icon.Height, + Width: topic.Icon.Width, + } + : undefined, + })) + + // Map results (external links) + const results = (data.Results || []).map((result: any) => ({ + FirstURL: result.FirstURL, + Text: result.Text, + Result: result.Result, + Icon: result.Icon + ? { + URL: result.Icon.URL, + Height: result.Icon.Height, + Width: result.Icon.Width, + } + : undefined, + })) + + return { + success: true, + output: { + heading: data.Heading || '', + abstract: data.Abstract || '', + abstractText: data.AbstractText || '', + abstractSource: data.AbstractSource || '', + abstractURL: data.AbstractURL || '', + image: data.Image || '', + answer: data.Answer || '', + answerType: data.AnswerType || '', + type: data.Type || '', + relatedTopics, + results, + }, + } + }, + + outputs: { + heading: { + type: 'string', + description: 'The heading/title of the instant answer', + }, + abstract: { + type: 'string', + description: 'A short abstract summary of the topic', + }, + abstractText: { + type: 'string', + description: 'Plain text version of the abstract', + }, + abstractSource: { + type: 'string', + description: 'The source of the abstract (e.g., Wikipedia)', + }, + abstractURL: { + type: 'string', + description: 'URL to the source of the abstract', + }, + image: { + type: 'string', + description: 'URL to an image related to the topic', + }, + answer: { + type: 'string', + description: 'Direct answer if available (e.g., for calculations)', + }, + answerType: { + type: 'string', + description: 'Type of the answer (e.g., calc, ip, etc.)', + }, + type: { + type: 'string', + description: + 'Response type: A (article), D (disambiguation), C (category), N (name), E (exclusive)', + }, + relatedTopics: { + type: 'array', + description: 'Array of related topics with URLs and descriptions', + items: { + type: 'object', + properties: { + FirstURL: { type: 'string', description: 'URL to the related topic' }, + Text: { type: 'string', description: 'Description of the related topic' }, + Result: { type: 'string', description: 'HTML result snippet' }, + }, + }, + }, + results: { + type: 'array', + description: 'Array of external link results', + items: { + type: 'object', + properties: { + FirstURL: { type: 'string', description: 'URL of the result' }, + Text: { type: 'string', description: 'Description of the result' }, + Result: { type: 'string', description: 'HTML result snippet' }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/duckduckgo/types.ts b/apps/sim/tools/duckduckgo/types.ts new file mode 100644 index 000000000..ad5eb4639 --- /dev/null +++ b/apps/sim/tools/duckduckgo/types.ts @@ -0,0 +1,51 @@ +// Common types for DuckDuckGo tools +import type { ToolResponse } from '@/tools/types' + +// Search tool types +export interface DuckDuckGoSearchParams { + query: string + noHtml?: boolean + skipDisambig?: boolean +} + +export interface DuckDuckGoRelatedTopic { + FirstURL?: string + Text?: string + Result?: string + Icon?: { + URL?: string + Height?: string + Width?: string + } +} + +export interface DuckDuckGoResult { + FirstURL?: string + Text?: string + Result?: string + Icon?: { + URL?: string + Height?: string + Width?: string + } +} + +export interface DuckDuckGoSearchOutput { + heading: string + abstract: string + abstractText: string + abstractSource: string + abstractURL: string + image: string + answer: string + answerType: string + type: string + relatedTopics: DuckDuckGoRelatedTopic[] + results: DuckDuckGoResult[] +} + +export interface DuckDuckGoSearchResponse extends ToolResponse { + output: DuckDuckGoSearchOutput +} + +export type DuckDuckGoResponse = DuckDuckGoSearchResponse diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index b49e63788..1305f4064 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -153,6 +153,7 @@ import { dropboxSearchTool, dropboxUploadTool, } from '@/tools/dropbox' +import { duckduckgoSearchTool } from '@/tools/duckduckgo' import { dynamodbDeleteTool, dynamodbGetTool, @@ -1587,6 +1588,7 @@ export const tools: Record = { dropbox_get_metadata: dropboxGetMetadataTool, dropbox_create_shared_link: dropboxCreateSharedLinkTool, dropbox_search: dropboxSearchTool, + duckduckgo_search: duckduckgoSearchTool, mongodb_query: mongodbQueryTool, mongodb_insert: mongodbInsertTool, mongodb_update: mongodbUpdateTool,