mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 15:07:55 -05:00
feat(tools): added duckduckgo (#2258)
This commit is contained in:
@@ -4129,3 +4129,27 @@ export function CursorIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function DuckDuckGoIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='-108 -108 216 216'>
|
||||
<circle r='108' fill='#d53' />
|
||||
<circle r='96' fill='none' stroke='#ffffff' stroke-width='7' />
|
||||
<path
|
||||
d='M-32-55C-62-48-51-6-51-6l19 93 7 3M-39-73h-8l11 4s-11 0-11 7c24-1 35 5 35 5'
|
||||
fill='#ddd'
|
||||
/>
|
||||
<path d='M25 95S1 57 1 32c0-47 31-7 31-44S1-58 1-58c-15-19-44-15-44-15l7 4s-7 2-9 4 19-3 28 5c-37 3-31 33-31 33l21 120' />
|
||||
<path d='M25-1l38-10c34 5-29 24-33 23C0 7 9 32 45 24s9 20-24 9C-26 20-1-3 25-1' fill='#fc0' />
|
||||
<path
|
||||
d='M15 78l2-3c22 8 23 11 22-9s0-20-23-3c0-5-13-3-15 0-21-9-23-12-22 2 2 29 1 24 21 14'
|
||||
fill='#6b5'
|
||||
/>
|
||||
<path d='M-1 67v12c1 2 17 2 17-2s-8 3-13 1-2-13-2-13' fill='#4a4' />
|
||||
<path
|
||||
d='M-23-32c-5-6-18-1-15 7 1-4 8-10 15-7m32 0c1-6 11-7 14-1-4-2-10-2-14 1m-33 16a2 2 0 1 1 0 1m-8 3a7 7 0 1 0 0-1m52-6a2 2 0 1 1 0 1m-6 3a6 6 0 1 0 0-1'
|
||||
fill='#148'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
DiscordIcon,
|
||||
DocumentIcon,
|
||||
DropboxIcon,
|
||||
DuckDuckGoIcon,
|
||||
DynamoDBIcon,
|
||||
ElasticsearchIcon,
|
||||
ElevenLabsIcon,
|
||||
@@ -212,6 +213,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
||||
elevenlabs: ElevenLabsIcon,
|
||||
elasticsearch: ElasticsearchIcon,
|
||||
dynamodb: DynamoDBIcon,
|
||||
duckduckgo: DuckDuckGoIcon,
|
||||
dropbox: DropboxIcon,
|
||||
discord: DiscordIcon,
|
||||
datadog: DatadogIcon,
|
||||
|
||||
68
apps/docs/content/docs/en/tools/duckduckgo.mdx
Normal file
68
apps/docs/content/docs/en/tools/duckduckgo.mdx
Normal file
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: DuckDuckGo
|
||||
description: Search with DuckDuckGo
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
|
||||
<BlockInfoCard
|
||||
type="duckduckgo"
|
||||
color="#FFFFFF"
|
||||
/>
|
||||
|
||||
{/* 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`
|
||||
@@ -15,6 +15,7 @@
|
||||
"datadog",
|
||||
"discord",
|
||||
"dropbox",
|
||||
"duckduckgo",
|
||||
"dynamodb",
|
||||
"elasticsearch",
|
||||
"elevenlabs",
|
||||
|
||||
59
apps/sim/blocks/blocks/duckduckgo.ts
Normal file
59
apps/sim/blocks/blocks/duckduckgo.ts
Normal file
@@ -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<DuckDuckGoResponse> = {
|
||||
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' },
|
||||
},
|
||||
}
|
||||
@@ -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<string, BlockConfig> = {
|
||||
datadog: DatadogBlock,
|
||||
discord: DiscordBlock,
|
||||
dropbox: DropboxBlock,
|
||||
duckduckgo: DuckDuckGoBlock,
|
||||
elevenlabs: ElevenLabsBlock,
|
||||
elasticsearch: ElasticsearchBlock,
|
||||
evaluator: EvaluatorBlock,
|
||||
|
||||
@@ -4129,3 +4129,27 @@ export function CursorIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function DuckDuckGoIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='-108 -108 216 216'>
|
||||
<circle r='108' fill='#d53' />
|
||||
<circle r='96' fill='none' stroke='#ffffff' stroke-width='7' />
|
||||
<path
|
||||
d='M-32-55C-62-48-51-6-51-6l19 93 7 3M-39-73h-8l11 4s-11 0-11 7c24-1 35 5 35 5'
|
||||
fill='#ddd'
|
||||
/>
|
||||
<path d='M25 95S1 57 1 32c0-47 31-7 31-44S1-58 1-58c-15-19-44-15-44-15l7 4s-7 2-9 4 19-3 28 5c-37 3-31 33-31 33l21 120' />
|
||||
<path d='M25-1l38-10c34 5-29 24-33 23C0 7 9 32 45 24s9 20-24 9C-26 20-1-3 25-1' fill='#fc0' />
|
||||
<path
|
||||
d='M15 78l2-3c22 8 23 11 22-9s0-20-23-3c0-5-13-3-15 0-21-9-23-12-22 2 2 29 1 24 21 14'
|
||||
fill='#6b5'
|
||||
/>
|
||||
<path d='M-1 67v12c1 2 17 2 17-2s-8 3-13 1-2-13-2-13' fill='#4a4' />
|
||||
<path
|
||||
d='M-23-32c-5-6-18-1-15 7 1-4 8-10 15-7m32 0c1-6 11-7 14-1-4-2-10-2-14 1m-33 16a2 2 0 1 1 0 1m-8 3a7 7 0 1 0 0-1m52-6a2 2 0 1 1 0 1m-6 3a6 6 0 1 0 0-1'
|
||||
fill='#148'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
3
apps/sim/tools/duckduckgo/index.ts
Normal file
3
apps/sim/tools/duckduckgo/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { searchTool } from '@/tools/duckduckgo/search'
|
||||
|
||||
export const duckduckgoSearchTool = searchTool
|
||||
161
apps/sim/tools/duckduckgo/search.ts
Normal file
161
apps/sim/tools/duckduckgo/search.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import type { DuckDuckGoSearchParams, DuckDuckGoSearchResponse } from '@/tools/duckduckgo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const searchTool: ToolConfig<DuckDuckGoSearchParams, DuckDuckGoSearchResponse> = {
|
||||
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' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
51
apps/sim/tools/duckduckgo/types.ts
Normal file
51
apps/sim/tools/duckduckgo/types.ts
Normal file
@@ -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
|
||||
@@ -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<string, ToolConfig> = {
|
||||
dropbox_get_metadata: dropboxGetMetadataTool,
|
||||
dropbox_create_shared_link: dropboxCreateSharedLinkTool,
|
||||
dropbox_search: dropboxSearchTool,
|
||||
duckduckgo_search: duckduckgoSearchTool,
|
||||
mongodb_query: mongodbQueryTool,
|
||||
mongodb_insert: mongodbInsertTool,
|
||||
mongodb_update: mongodbUpdateTool,
|
||||
|
||||
Reference in New Issue
Block a user