mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
feat(tools): New Qdrant Tool (#644)
* feat: Qdrant tool Signed-off-by: Anush008 <anushshetty90@gmail.com> * docs: Updates Signed-off-by: Anush008 <anushshetty90@gmail.com> * Apply suggestions from code review Signed-off-by: Anush008 <anushshetty90@gmail.com> * chore: Updated placeholder text Signed-off-by: Anush008 <anushshetty90@gmail.com> * chore: Post merge updates Signed-off-by: Anush008 <anushshetty90@gmail.com> * chore: visibility to 'user-only' Signed-off-by: Anush008 <anushshetty90@gmail.com> --------- Signed-off-by: Anush008 <anushshetty90@gmail.com>
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
"outlook",
|
||||
"perplexity",
|
||||
"pinecone",
|
||||
"qdrant",
|
||||
"reddit",
|
||||
"s3",
|
||||
"schedule",
|
||||
|
||||
176
apps/docs/content/docs/tools/qdrant.mdx
Normal file
176
apps/docs/content/docs/tools/qdrant.mdx
Normal file
@@ -0,0 +1,176 @@
|
||||
---
|
||||
title: Qdrant
|
||||
description: Use Qdrant vector database
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
|
||||
<BlockInfoCard
|
||||
type="qdrant"
|
||||
color="#1A223F"
|
||||
icon={true}
|
||||
iconSvg={`<svg className="block-icon" fill='none' viewBox='0 0 49 56' xmlns='http://www.w3.org/2000/svg'>
|
||||
<g clip-path='url(#b)'>
|
||||
<path
|
||||
d='m38.489 51.477-1.1167-30.787-2.0223-8.1167 13.498 1.429v37.242l-8.2456 4.7589-2.1138-4.5259z'
|
||||
clip-rule='evenodd'
|
||||
fill='#24386C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m48.847 14-8.2457 4.7622-17.016-3.7326-19.917 8.1094-3.3183-9.139 12.122-7 12.126-7 12.123 7 12.126 7z'
|
||||
clip-rule='evenodd'
|
||||
fill='#7589BE'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m0.34961 13.999 8.2457 4.7622 4.7798 14.215 16.139 12.913-4.9158 10.109-12.126-7.0004-12.123-7v-28z'
|
||||
clip-rule='evenodd'
|
||||
fill='#B2BFE8'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m30.066 38.421-5.4666 8.059v9.5207l7.757-4.4756 3.9968-5.9681'
|
||||
clip-rule='evenodd'
|
||||
fill='#24386C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m24.602 36.962-7.7603-13.436 1.6715-4.4531 6.3544-3.0809 7.488 7.5343-7.7536 13.436z'
|
||||
clip-rule='evenodd'
|
||||
fill='#7589BE'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m16.843 23.525 7.7569 4.4756v8.9585l-7.1741 0.3087-4.3397-5.5412 3.7569-8.2016z'
|
||||
clip-rule='evenodd'
|
||||
fill='#B2BFE8'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m24.6 28 7.757-4.4752 5.2792 8.7903-6.3886 5.2784-6.6476-0.6346v-8.9589z'
|
||||
clip-rule='evenodd'
|
||||
fill='#24386C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m32.355 51.524 8.2457 4.476v-37.238l-8.0032-4.6189-7.9995-4.6189-8.0031 4.6189-7.9995 4.6189v18.479l7.9995 4.6189 8.0031 4.6193 7.757-4.4797v9.5244zm0-19.045-7.757 4.4793-7.7569-4.4793v-8.9549l7.7569-4.4792 7.757 4.4792v8.9549z'
|
||||
clip-rule='evenodd'
|
||||
fill='#DC244C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path d='m24.603 46.483v-9.5222l-7.7166-4.4411v9.5064l7.7166 4.4569z' fill='url(#a)' />
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id='a'
|
||||
x1='23.18'
|
||||
x2='15.491'
|
||||
y1='38.781'
|
||||
y2='38.781'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
>
|
||||
<stop stop-color='#FF3364' offset='0' />
|
||||
<stop stop-color='#C91540' stop-opacity='0' offset='1' />
|
||||
</linearGradient>
|
||||
<clipPath id='b'>
|
||||
<rect transform='translate(.34961)' fill='#fff' />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>`}
|
||||
/>
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Store, search, and retrieve vector embeddings using Qdrant. Perform semantic similarity searches and manage your vector collections.
|
||||
|
||||
|
||||
|
||||
## Tools
|
||||
|
||||
### `qdrant_upsert_points`
|
||||
|
||||
Insert or update points in a Qdrant collection
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `url` | string | Yes | Qdrant base URL |
|
||||
| `apiKey` | string | No | Qdrant API key \(optional\) |
|
||||
| `collection` | string | Yes | Collection name |
|
||||
| `points` | array | Yes | Array of points to upsert |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type |
|
||||
| --------- | ---- |
|
||||
| `status` | string |
|
||||
| `data` | string |
|
||||
|
||||
### `qdrant_search_vector`
|
||||
|
||||
Search for similar vectors in a Qdrant collection
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `url` | string | Yes | Qdrant base URL |
|
||||
| `apiKey` | string | No | Qdrant API key \(optional\) |
|
||||
| `collection` | string | Yes | Collection name |
|
||||
| `vector` | array | Yes | Vector to search for |
|
||||
| `limit` | number | No | Number of results to return |
|
||||
| `filter` | object | No | Filter to apply to the search |
|
||||
| `with_payload` | boolean | No | Include payload in response |
|
||||
| `with_vector` | boolean | No | Include vector in response |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type |
|
||||
| --------- | ---- |
|
||||
| `data` | string |
|
||||
| `status` | string |
|
||||
|
||||
### `qdrant_fetch_points`
|
||||
|
||||
Fetch points by ID from a Qdrant collection
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `url` | string | Yes | Qdrant base URL |
|
||||
| `apiKey` | string | No | Qdrant API key \(optional\) |
|
||||
| `collection` | string | Yes | Collection name |
|
||||
| `ids` | array | Yes | Array of point IDs to fetch |
|
||||
| `with_payload` | boolean | No | Include payload in response |
|
||||
| `with_vector` | boolean | No | Include vector in response |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type |
|
||||
| --------- | ---- |
|
||||
| `data` | string |
|
||||
| `status` | string |
|
||||
|
||||
|
||||
|
||||
## Block Configuration
|
||||
|
||||
### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `operation` | string | Yes | Operation |
|
||||
|
||||
|
||||
|
||||
### Outputs
|
||||
|
||||
This block does not produce any outputs.
|
||||
|
||||
## Notes
|
||||
|
||||
- Category: `tools`
|
||||
- Type: `qdrant`
|
||||
@@ -172,6 +172,9 @@ function Integrations() {
|
||||
<div className='flex aspect-square h-16 w-16 items-center justify-center rounded-xl border border-[#353535] bg-[#242424] p-1 shadow-[0px_2px_6px_0px_rgba(126,_48,_252,_0.1)]'>
|
||||
<Icons.pinecone />
|
||||
</div>
|
||||
<div className='flex aspect-square h-16 w-16 items-center justify-center rounded-xl border border-[#353535] bg-[#242424] p-1 shadow-[0px_2px_6px_0px_rgba(126,_48,_252,_0.1)]'>
|
||||
<Icons.qdrant />
|
||||
</div>
|
||||
<div className='flex aspect-square h-16 w-16 items-center justify-center rounded-xl border border-[#353535] bg-[#242424] p-1 shadow-[0px_2px_6px_0px_rgba(126,_48,_252,_0.1)]'>
|
||||
<Icons.slack />
|
||||
</div>
|
||||
@@ -290,6 +293,9 @@ function Integrations() {
|
||||
<div className='flex aspect-square h-12 w-12 items-center justify-center rounded-xl border border-[#353535] bg-[#242424] p-1 shadow-[0px_2px_6px_0px_rgba(126,_48,_252,_0.1)]'>
|
||||
<Icons.pinecone />
|
||||
</div>
|
||||
<div className='flex aspect-square h-12 w-12 items-center justify-center rounded-xl border border-[#353535] bg-[#242424] p-1 shadow-[0px_2px_6px_0px_rgba(126,_48,_252,_0.1)]'>
|
||||
<Icons.qdrant />
|
||||
</div>
|
||||
<div className='flex aspect-square h-12 w-12 items-center justify-center rounded-xl border border-[#353535] bg-[#242424] p-1 shadow-[0px_2px_6px_0px_rgba(126,_48,_252,_0.1)]'>
|
||||
<Icons.slack />
|
||||
</div>
|
||||
@@ -512,6 +518,77 @@ const Icons = {
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
qdrant: () => (
|
||||
<svg width='48' height='48' fill='none' viewBox='0 0 49 56' xmlns='http://www.w3.org/2000/svg'>
|
||||
<g clipPath='url(#b)'>
|
||||
<path
|
||||
d='m38.489 51.477-1.1167-30.787-2.0223-8.1167 13.498 1.429v37.242l-8.2456 4.7589-2.1138-4.5259z'
|
||||
clip-rule='evenodd'
|
||||
fill='#24386C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m48.847 14-8.2457 4.7622-17.016-3.7326-19.917 8.1094-3.3183-9.139 12.122-7 12.126-7 12.123 7 12.126 7z'
|
||||
clip-rule='evenodd'
|
||||
fill='#7589BE'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m0.34961 13.999 8.2457 4.7622 4.7798 14.215 16.139 12.913-4.9158 10.109-12.126-7.0004-12.123-7v-28z'
|
||||
clip-rule='evenodd'
|
||||
fill='#B2BFE8'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m30.066 38.421-5.4666 8.059v9.5207l7.757-4.4756 3.9968-5.9681'
|
||||
clip-rule='evenodd'
|
||||
fill='#24386C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m24.602 36.962-7.7603-13.436 1.6715-4.4531 6.3544-3.0809 7.488 7.5343-7.7536 13.436z'
|
||||
clip-rule='evenodd'
|
||||
fill='#7589BE'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m16.843 23.525 7.7569 4.4756v8.9585l-7.1741 0.3087-4.3397-5.5412 3.7569-8.2016z'
|
||||
clip-rule='evenodd'
|
||||
fill='#B2BFE8'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m24.6 28 7.757-4.4752 5.2792 8.7903-6.3886 5.2784-6.6476-0.6346v-8.9589z'
|
||||
clip-rule='evenodd'
|
||||
fill='#24386C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m32.355 51.524 8.2457 4.476v-37.238l-8.0032-4.6189-7.9995-4.6189-8.0031 4.6189-7.9995 4.6189v18.479l7.9995 4.6189 8.0031 4.6193 7.757-4.4797v9.5244zm0-19.045-7.757 4.4793-7.7569-4.4793v-8.9549l7.7569-4.4792 7.757 4.4792v8.9549z'
|
||||
clip-rule='evenodd'
|
||||
fill='#DC244C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path d='m24.603 46.483v-9.5222l-7.7166-4.4411v9.5064l7.7166 4.4569z' fill='url(#a)' />
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id='a'
|
||||
x1='23.18'
|
||||
x2='15.491'
|
||||
y1='38.781'
|
||||
y2='38.781'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
>
|
||||
<stop stop-color='#FF3364' offset='0' />
|
||||
<stop stop-color='#C91540' stop-opacity='0' offset='1' />
|
||||
</linearGradient>
|
||||
<clipPath id='b'>
|
||||
<rect transform='translate(.34961)' width='48.3' height='56' fill='#fff' />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
),
|
||||
slack: () => (
|
||||
<svg width='48' height='48' viewBox='0 0 48 48' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<g clipPath='url(#clip0_82_6239)'>
|
||||
|
||||
1
apps/sim/blocks/blocks/index.ts
Normal file
1
apps/sim/blocks/blocks/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './qdrant'
|
||||
214
apps/sim/blocks/blocks/qdrant.ts
Normal file
214
apps/sim/blocks/blocks/qdrant.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
import { QdrantIcon } from '@/components/icons'
|
||||
import type { QdrantResponse } from '@/tools/qdrant/types'
|
||||
import type { BlockConfig } from '../types'
|
||||
|
||||
export const QdrantBlock: BlockConfig<QdrantResponse> = {
|
||||
type: 'qdrant',
|
||||
name: 'Qdrant',
|
||||
description: 'Use Qdrant vector database',
|
||||
longDescription:
|
||||
'Store, search, and retrieve vector embeddings using Qdrant. Perform semantic similarity searches and manage your vector collections.',
|
||||
docsLink: 'https://qdrant.tech/documentation/',
|
||||
category: 'tools',
|
||||
bgColor: '#1A223F',
|
||||
icon: QdrantIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
layout: 'full',
|
||||
options: [
|
||||
{ label: 'Upsert', id: 'upsert' },
|
||||
{ label: 'Search', id: 'search' },
|
||||
{ label: 'Fetch', id: 'fetch' },
|
||||
],
|
||||
},
|
||||
// Upsert fields
|
||||
{
|
||||
id: 'url',
|
||||
title: 'Qdrant URL',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'http://localhost:6333',
|
||||
condition: { field: 'operation', value: 'upsert' },
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Your Qdrant API key (optional)',
|
||||
password: true,
|
||||
condition: { field: 'operation', value: 'upsert' },
|
||||
},
|
||||
{
|
||||
id: 'collection',
|
||||
title: 'Collection',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'my-collection',
|
||||
condition: { field: 'operation', value: 'upsert' },
|
||||
},
|
||||
{
|
||||
id: 'points',
|
||||
title: 'Points',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: '[{"id": 1, "vector": [0.1, 0.2], "payload": {"category": "a"}}]',
|
||||
condition: { field: 'operation', value: 'upsert' },
|
||||
},
|
||||
// Search fields
|
||||
{
|
||||
id: 'url',
|
||||
title: 'Qdrant URL',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'http://localhost:6333',
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Your Qdrant API key (optional)',
|
||||
password: true,
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
},
|
||||
{
|
||||
id: 'collection',
|
||||
title: 'Collection',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'my-collection',
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
},
|
||||
{
|
||||
id: 'vector',
|
||||
title: 'Query Vector',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: '[0.1, 0.2]',
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
},
|
||||
{
|
||||
id: 'limit',
|
||||
title: 'Limit',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '10',
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
},
|
||||
{
|
||||
id: 'filter',
|
||||
title: 'Filter',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: '{"must":[{"key":"city","match":{"value":"London"}}]}',
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
},
|
||||
{
|
||||
id: 'with_payload',
|
||||
title: 'With Payload',
|
||||
type: 'switch',
|
||||
layout: 'full',
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
},
|
||||
{
|
||||
id: 'with_vector',
|
||||
title: 'With Vector',
|
||||
type: 'switch',
|
||||
layout: 'full',
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
},
|
||||
// Fetch fields
|
||||
{
|
||||
id: 'url',
|
||||
title: 'Qdrant URL',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'http://localhost:6333',
|
||||
condition: { field: 'operation', value: 'fetch' },
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Your Qdrant API key (optional)',
|
||||
password: true,
|
||||
condition: { field: 'operation', value: 'fetch' },
|
||||
},
|
||||
{
|
||||
id: 'collection',
|
||||
title: 'Collection',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'my-collection',
|
||||
condition: { field: 'operation', value: 'fetch' },
|
||||
},
|
||||
{
|
||||
id: 'ids',
|
||||
title: 'IDs',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: '["370446a3-310f-58db-8ce7-31db947c6c1e"]',
|
||||
condition: { field: 'operation', value: 'fetch' },
|
||||
},
|
||||
{
|
||||
id: 'with_payload',
|
||||
title: 'With Payload',
|
||||
type: 'switch',
|
||||
layout: 'full',
|
||||
condition: { field: 'operation', value: 'fetch' },
|
||||
},
|
||||
{
|
||||
id: 'with_vector',
|
||||
title: 'With Vector',
|
||||
type: 'switch',
|
||||
layout: 'full',
|
||||
condition: { field: 'operation', value: 'fetch' },
|
||||
},
|
||||
],
|
||||
|
||||
tools: {
|
||||
access: ['qdrant_upsert_points', 'qdrant_search_vector', 'qdrant_fetch_points'],
|
||||
config: {
|
||||
tool: (params: Record<string, any>) => {
|
||||
switch (params.operation) {
|
||||
case 'upsert':
|
||||
return 'qdrant_upsert_points'
|
||||
case 'search':
|
||||
return 'qdrant_search_vector'
|
||||
case 'fetch':
|
||||
return 'qdrant_fetch_points'
|
||||
default:
|
||||
throw new Error('Invalid operation selected')
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
inputs: {
|
||||
operation: { type: 'string', required: true },
|
||||
url: { type: 'string', required: true },
|
||||
apiKey: { type: 'string', required: false },
|
||||
collection: { type: 'string', required: true },
|
||||
points: { type: 'json', required: false },
|
||||
vector: { type: 'json', required: false },
|
||||
limit: { type: 'number', required: false },
|
||||
filter: { type: 'json', required: false },
|
||||
ids: { type: 'json', required: false },
|
||||
with_payload: { type: 'boolean', required: false },
|
||||
with_vector: { type: 'boolean', required: false },
|
||||
},
|
||||
|
||||
outputs: {
|
||||
matches: 'any',
|
||||
upsertedCount: 'any',
|
||||
data: 'any',
|
||||
status: 'any',
|
||||
},
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import { OpenAIBlock } from '@/blocks/blocks/openai'
|
||||
import { OutlookBlock } from '@/blocks/blocks/outlook'
|
||||
import { PerplexityBlock } from '@/blocks/blocks/perplexity'
|
||||
import { PineconeBlock } from '@/blocks/blocks/pinecone'
|
||||
import { QdrantBlock } from '@/blocks/blocks/qdrant'
|
||||
import { RedditBlock } from '@/blocks/blocks/reddit'
|
||||
import { ResponseBlock } from '@/blocks/blocks/response'
|
||||
import { RouterBlock } from '@/blocks/blocks/router'
|
||||
@@ -98,7 +99,6 @@ export const registry: Record<string, BlockConfig> = {
|
||||
linear: LinearBlock,
|
||||
linkup: LinkupBlock,
|
||||
mem0: Mem0Block,
|
||||
memory: MemoryBlock,
|
||||
microsoft_excel: MicrosoftExcelBlock,
|
||||
microsoft_teams: MicrosoftTeamsBlock,
|
||||
mistral_parse: MistralParseBlock,
|
||||
@@ -107,6 +107,8 @@ export const registry: Record<string, BlockConfig> = {
|
||||
outlook: OutlookBlock,
|
||||
perplexity: PerplexityBlock,
|
||||
pinecone: PineconeBlock,
|
||||
qdrant: QdrantBlock,
|
||||
memory: MemoryBlock,
|
||||
reddit: RedditBlock,
|
||||
response: ResponseBlock,
|
||||
router: RouterBlock,
|
||||
|
||||
@@ -3033,3 +3033,77 @@ export function ScheduleIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function QdrantIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} fill='none' viewBox='0 0 49 56' xmlns='http://www.w3.org/2000/svg'>
|
||||
<g clip-path='url(#b)'>
|
||||
<path
|
||||
d='m38.489 51.477-1.1167-30.787-2.0223-8.1167 13.498 1.429v37.242l-8.2456 4.7589-2.1138-4.5259z'
|
||||
clip-rule='evenodd'
|
||||
fill='#24386C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m48.847 14-8.2457 4.7622-17.016-3.7326-19.917 8.1094-3.3183-9.139 12.122-7 12.126-7 12.123 7 12.126 7z'
|
||||
clip-rule='evenodd'
|
||||
fill='#7589BE'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m0.34961 13.999 8.2457 4.7622 4.7798 14.215 16.139 12.913-4.9158 10.109-12.126-7.0004-12.123-7v-28z'
|
||||
clip-rule='evenodd'
|
||||
fill='#B2BFE8'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m30.066 38.421-5.4666 8.059v9.5207l7.757-4.4756 3.9968-5.9681'
|
||||
clip-rule='evenodd'
|
||||
fill='#24386C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m24.602 36.962-7.7603-13.436 1.6715-4.4531 6.3544-3.0809 7.488 7.5343-7.7536 13.436z'
|
||||
clip-rule='evenodd'
|
||||
fill='#7589BE'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m16.843 23.525 7.7569 4.4756v8.9585l-7.1741 0.3087-4.3397-5.5412 3.7569-8.2016z'
|
||||
clip-rule='evenodd'
|
||||
fill='#B2BFE8'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m24.6 28 7.757-4.4752 5.2792 8.7903-6.3886 5.2784-6.6476-0.6346v-8.9589z'
|
||||
clip-rule='evenodd'
|
||||
fill='#24386C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path
|
||||
d='m32.355 51.524 8.2457 4.476v-37.238l-8.0032-4.6189-7.9995-4.6189-8.0031 4.6189-7.9995 4.6189v18.479l7.9995 4.6189 8.0031 4.6193 7.757-4.4797v9.5244zm0-19.045-7.757 4.4793-7.7569-4.4793v-8.9549l7.7569-4.4792 7.757 4.4792v8.9549z'
|
||||
clip-rule='evenodd'
|
||||
fill='#DC244C'
|
||||
fill-rule='evenodd'
|
||||
/>
|
||||
<path d='m24.603 46.483v-9.5222l-7.7166-4.4411v9.5064l7.7166 4.4569z' fill='url(#a)' />
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id='a'
|
||||
x1='23.18'
|
||||
x2='15.491'
|
||||
y1='38.781'
|
||||
y2='38.781'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
>
|
||||
<stop stop-color='#FF3364' offset='0' />
|
||||
<stop stop-color='#C91540' stop-opacity='0' offset='1' />
|
||||
</linearGradient>
|
||||
<clipPath id='b'>
|
||||
<rect transform='translate(.34961)' width='48.3' height='56' fill='#fff' />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
89
apps/sim/tools/qdrant/fetch_points.ts
Normal file
89
apps/sim/tools/qdrant/fetch_points.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import type { ToolConfig } from '../types'
|
||||
import type { QdrantFetchParams, QdrantResponse } from './types'
|
||||
|
||||
export const fetchPointsTool: ToolConfig<QdrantFetchParams, QdrantResponse> = {
|
||||
id: 'qdrant_fetch_points',
|
||||
name: 'Qdrant Fetch Points',
|
||||
description: 'Fetch points by ID from a Qdrant collection',
|
||||
version: '1.0',
|
||||
|
||||
params: {
|
||||
url: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Qdrant base URL',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Qdrant API key (optional)',
|
||||
},
|
||||
collection: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Collection name',
|
||||
},
|
||||
ids: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Array of point IDs to fetch',
|
||||
},
|
||||
with_payload: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include payload in response',
|
||||
},
|
||||
with_vector: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include vector in response',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: (params) => `${params.url.replace(/\/$/, '')}/collections/${params.collection}/points`,
|
||||
headers: (params) => ({
|
||||
'Content-Type': 'application/json',
|
||||
...(params.apiKey ? { 'api-key': params.apiKey } : {}),
|
||||
}),
|
||||
body: (params) => ({
|
||||
ids: params.ids,
|
||||
with_payload: params.with_payload,
|
||||
with_vector: params.with_vector,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
data: data.result,
|
||||
status: data.status,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error: any): string => {
|
||||
if (error.error && typeof error.error === 'string') {
|
||||
return error.error
|
||||
}
|
||||
if (error.status?.error) {
|
||||
return error.status.error
|
||||
}
|
||||
if (error.message) {
|
||||
return error.message
|
||||
}
|
||||
if (typeof error === 'string') {
|
||||
return error
|
||||
}
|
||||
return 'Qdrant fetch points failed'
|
||||
},
|
||||
}
|
||||
7
apps/sim/tools/qdrant/index.ts
Normal file
7
apps/sim/tools/qdrant/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { fetchPointsTool } from './fetch_points'
|
||||
import { searchVectorTool } from './search_vector'
|
||||
import { upsertPointsTool } from './upsert_points'
|
||||
|
||||
export const qdrantUpsertTool = upsertPointsTool
|
||||
export const qdrantSearchTool = searchVectorTool
|
||||
export const qdrantFetchTool = fetchPointsTool
|
||||
107
apps/sim/tools/qdrant/search_vector.ts
Normal file
107
apps/sim/tools/qdrant/search_vector.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import type { ToolConfig } from '../types'
|
||||
import type { QdrantResponse, QdrantSearchParams } from './types'
|
||||
|
||||
export const searchVectorTool: ToolConfig<QdrantSearchParams, QdrantResponse> = {
|
||||
id: 'qdrant_search_vector',
|
||||
name: 'Qdrant Search Vector',
|
||||
description: 'Search for similar vectors in a Qdrant collection',
|
||||
version: '1.0',
|
||||
|
||||
params: {
|
||||
url: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Qdrant base URL',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Qdrant API key (optional)',
|
||||
},
|
||||
collection: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Collection name',
|
||||
},
|
||||
vector: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Vector to search for',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Number of results to return',
|
||||
},
|
||||
filter: {
|
||||
type: 'object',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter to apply to the search',
|
||||
},
|
||||
with_payload: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include payload in response',
|
||||
},
|
||||
with_vector: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include vector in response',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: (params) =>
|
||||
`${params.url.replace(/\/$/, '')}/collections/${encodeURIComponent(params.collection)}/points/query`,
|
||||
headers: (params) => ({
|
||||
'Content-Type': 'application/json',
|
||||
...(params.apiKey ? { 'api-key': params.apiKey } : {}),
|
||||
}),
|
||||
body: (params) => ({
|
||||
query: params.vector,
|
||||
limit: params.limit ? Number.parseInt(params.limit.toString()) : 10,
|
||||
filter: params.filter,
|
||||
with_payload: params.with_payload,
|
||||
with_vector: params.with_vector,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Qdrant search failed: ${response.statusText}`)
|
||||
}
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
data: data.result,
|
||||
status: data.status,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error: any): string => {
|
||||
if (error.error && typeof error.error === 'string') {
|
||||
return error.error
|
||||
}
|
||||
if (error.status?.error) {
|
||||
return error.status.error
|
||||
}
|
||||
if (error.message) {
|
||||
return error.message
|
||||
}
|
||||
if (typeof error === 'string') {
|
||||
return error
|
||||
}
|
||||
return 'Qdrant search vector failed'
|
||||
},
|
||||
}
|
||||
46
apps/sim/tools/qdrant/types.ts
Normal file
46
apps/sim/tools/qdrant/types.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { ToolResponse } from '../types'
|
||||
|
||||
export interface QdrantBaseParams {
|
||||
url: string
|
||||
apiKey?: string
|
||||
collection: string
|
||||
}
|
||||
|
||||
export interface QdrantVector {
|
||||
id: string
|
||||
vector: number[]
|
||||
payload?: Record<string, any>
|
||||
}
|
||||
|
||||
export interface QdrantUpsertParams extends QdrantBaseParams {
|
||||
points: QdrantVector[]
|
||||
}
|
||||
|
||||
export interface QdrantSearchParams extends QdrantBaseParams {
|
||||
vector: number[]
|
||||
limit?: number
|
||||
filter?: Record<string, any>
|
||||
with_payload?: boolean
|
||||
with_vector?: boolean
|
||||
}
|
||||
|
||||
export interface QdrantFetchParams extends QdrantBaseParams {
|
||||
ids: string[]
|
||||
with_payload?: boolean
|
||||
with_vector?: boolean
|
||||
}
|
||||
|
||||
export interface QdrantResponse extends ToolResponse {
|
||||
output: {
|
||||
result?: any
|
||||
status?: string
|
||||
matches?: Array<{
|
||||
id: string
|
||||
score: number
|
||||
payload?: Record<string, any>
|
||||
vector?: number[]
|
||||
}>
|
||||
upsertedCount?: number
|
||||
data?: any
|
||||
}
|
||||
}
|
||||
72
apps/sim/tools/qdrant/upsert_points.ts
Normal file
72
apps/sim/tools/qdrant/upsert_points.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { ToolConfig } from '../types'
|
||||
import type { QdrantResponse, QdrantUpsertParams } from './types'
|
||||
|
||||
export const upsertPointsTool: ToolConfig<QdrantUpsertParams, QdrantResponse> = {
|
||||
id: 'qdrant_upsert_points',
|
||||
name: 'Qdrant Upsert Points',
|
||||
description: 'Insert or update points in a Qdrant collection',
|
||||
version: '1.0',
|
||||
|
||||
params: {
|
||||
url: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Qdrant base URL',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Qdrant API key (optional)',
|
||||
},
|
||||
collection: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Collection name',
|
||||
},
|
||||
points: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Array of points to upsert',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
method: 'PUT',
|
||||
url: (params) => `${params.url.replace(/\/$/, '')}/collections/${params.collection}/points`,
|
||||
headers: (params) => ({
|
||||
'Content-Type': 'application/json',
|
||||
...(params.apiKey ? { 'api-key': params.apiKey } : {}),
|
||||
}),
|
||||
body: (params) => ({ points: params.points }),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: response.ok && data.status === 'ok',
|
||||
output: {
|
||||
status: data.status,
|
||||
data: data.result,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error: any): string => {
|
||||
if (error.error && typeof error.error === 'string') {
|
||||
return error.error
|
||||
}
|
||||
if (error.status?.error) {
|
||||
return error.status.error
|
||||
}
|
||||
if (error.message) {
|
||||
return error.message
|
||||
}
|
||||
if (typeof error === 'string') {
|
||||
return error
|
||||
}
|
||||
return 'Qdrant upsert failed'
|
||||
},
|
||||
}
|
||||
5
apps/sim/tools/qdrant/utils.ts
Normal file
5
apps/sim/tools/qdrant/utils.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export async function requestQdrant(url: string, path: string, options: RequestInit) {
|
||||
const res = await fetch(url.replace(/\/$/, '') + path, options)
|
||||
if (!res.ok) throw new Error(`Qdrant request failed: ${res.status}`)
|
||||
return res.json()
|
||||
}
|
||||
@@ -94,6 +94,7 @@ import {
|
||||
pineconeSearchVectorTool,
|
||||
pineconeUpsertTextTool,
|
||||
} from '@/tools/pinecone'
|
||||
import { qdrantFetchTool, qdrantSearchTool, qdrantUpsertTool } from '@/tools/qdrant'
|
||||
import { redditGetCommentsTool, redditGetPostsTool, redditHotPostsTool } from '@/tools/reddit'
|
||||
import { s3GetObjectTool } from '@/tools/s3'
|
||||
import { searchTool as serperSearch } from '@/tools/serper'
|
||||
@@ -261,4 +262,7 @@ export const tools: Record<string, ToolConfig> = {
|
||||
wealthbox_write_task: wealthboxWriteTaskTool,
|
||||
wealthbox_read_note: wealthboxReadNoteTool,
|
||||
wealthbox_write_note: wealthboxWriteNoteTool,
|
||||
qdrant_fetch_points: qdrantFetchTool,
|
||||
qdrant_search_vector: qdrantSearchTool,
|
||||
qdrant_upsert_points: qdrantUpsertTool,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user