diff --git a/blocks/blocks/pinecone.ts b/blocks/blocks/pinecone.ts index f851b8a24..c94547e49 100644 --- a/blocks/blocks/pinecone.ts +++ b/blocks/blocks/pinecone.ts @@ -18,9 +18,11 @@ export const PineconeBlock: BlockConfig = { type: 'dropdown', layout: 'full', options: [ - { label: 'Query', id: 'query' }, - { label: 'Upsert', id: 'upsert' }, - { label: 'Delete', id: 'delete' }, + { label: 'Generate Embeddings', id: 'generate' }, + { label: 'Upsert Text', id: 'upsert_text' }, + { label: 'Search Text', id: 'search_text' }, + { label: 'Fetch Vectors', id: 'fetch' }, + { label: 'Delete Vectors', id: 'delete' }, ], }, { @@ -37,14 +39,43 @@ export const PineconeBlock: BlockConfig = { layout: 'full', placeholder: 'my-index', }, - // Query operation fields + // Generate embeddings fields { - id: 'queryVector', - title: 'Query Vector', + id: 'model', + title: 'Model', + type: 'dropdown', + layout: 'full', + options: [ + { label: 'text-embedding-3-small', id: 'text-embedding-3-small' }, + { label: 'text-embedding-3-large', id: 'text-embedding-3-large' }, + ], + condition: { field: 'operation', value: 'generate' }, + }, + { + id: 'inputs', + title: 'Text Inputs', type: 'long-input', layout: 'full', - placeholder: '[0.1, 0.2, 0.3, ...]', - condition: { field: 'operation', value: 'query' }, + placeholder: '[{"text": "Your text here"}]', + condition: { field: 'operation', value: 'generate' }, + }, + // Upsert text fields + { + id: 'records', + title: 'Records', + type: 'long-input', + layout: 'full', + placeholder: '[{"_id": "doc1", "text": "Your text here", "metadata": {"key": "value"}}]', + condition: { field: 'operation', value: 'upsert_text' }, + }, + // Search text fields + { + id: 'searchQuery', + title: 'Search Query', + type: 'long-input', + layout: 'full', + placeholder: 'Enter text to search for', + condition: { field: 'operation', value: 'search_text' }, }, { id: 'topK', @@ -52,49 +83,33 @@ export const PineconeBlock: BlockConfig = { type: 'short-input', layout: 'full', placeholder: '10', - condition: { field: 'operation', value: 'query' }, + condition: { field: 'operation', value: 'search_text' }, }, { - id: 'includeMetadata', - title: 'Include Metadata', - type: 'switch', - layout: 'half', - value: () => 'true', - condition: { field: 'operation', value: 'query' }, - }, - { - id: 'includeValues', - title: 'Include Values', - type: 'switch', - layout: 'half', - value: () => 'false', - condition: { field: 'operation', value: 'query' }, - }, - // Upsert operation fields - { - id: 'vectors', - title: 'Vectors', + id: 'filter', + title: 'Filter', type: 'long-input', layout: 'full', - placeholder: '[{"id": "vec1", "values": [0.1, 0.2, 0.3], "metadata": {"key": "value"}}]', - condition: { field: 'operation', value: 'upsert' }, + placeholder: '{"key": "value"}', + condition: { field: 'operation', value: 'search_text' }, }, - // Delete operation fields + // Fetch fields { id: 'ids', title: 'Vector IDs', type: 'long-input', layout: 'full', - placeholder: '["vec1", "vec2", ...]', - condition: { field: 'operation', value: 'delete' }, + placeholder: '["vec1", "vec2"]', + condition: { field: 'operation', value: 'fetch' }, }, + // Common fields { - id: 'deleteAll', - title: 'Delete All Vectors', - type: 'switch', - layout: 'half', - value: () => 'false', - condition: { field: 'operation', value: 'delete' }, + id: 'namespace', + title: 'Namespace', + type: 'short-input', + layout: 'full', + placeholder: 'Optional namespace', + condition: { field: 'operation', value: 'upsert_text' }, }, { id: 'apiKey', @@ -107,14 +122,24 @@ export const PineconeBlock: BlockConfig = { ], tools: { - access: ['pinecone_query', 'pinecone_upsert', 'pinecone_delete'], + access: [ + 'pinecone_generate_embeddings', + 'pinecone_upsert_text', + 'pinecone_search_text', + 'pinecone_fetch', + 'pinecone_delete', + ], config: { - tool: (params) => { + tool: (params: Record) => { switch (params.operation) { - case 'query': - return 'pinecone_query' - case 'upsert': - return 'pinecone_upsert' + case 'generate': + return 'pinecone_generate_embeddings' + case 'upsert_text': + return 'pinecone_upsert_text' + case 'search_text': + return 'pinecone_search_text' + case 'fetch': + return 'pinecone_fetch' case 'delete': return 'pinecone_delete' default: @@ -129,15 +154,19 @@ export const PineconeBlock: BlockConfig = { apiKey: { type: 'string', required: true }, environment: { type: 'string', required: true }, indexName: { type: 'string', required: true }, - // Query operation inputs - queryVector: { type: 'json', required: false }, - topK: { type: 'number', required: false }, - includeMetadata: { type: 'boolean', required: false }, - includeValues: { type: 'boolean', required: false }, - // Upsert operation inputs - vectors: { type: 'json', required: false }, - // Delete operation inputs + namespace: { type: 'string', required: false }, + // Generate embeddings inputs + model: { type: 'string', required: false }, + inputs: { type: 'json', required: false }, + // Upsert text inputs + records: { type: 'json', required: false }, + // Search text inputs + searchQuery: { type: 'string', required: false }, + topK: { type: 'string', required: false }, + filter: { type: 'json', required: false }, + // Fetch inputs ids: { type: 'json', required: false }, + // Delete inputs deleteAll: { type: 'boolean', required: false }, }, @@ -146,7 +175,8 @@ export const PineconeBlock: BlockConfig = { type: { matches: 'any', upsertedCount: 'any', - deletedCount: 'any', + embeddings: 'any', + usage: 'any', }, }, }, diff --git a/tools/index.ts b/tools/index.ts index 31efb1cc2..5d5f66876 100644 --- a/tools/index.ts +++ b/tools/index.ts @@ -17,8 +17,10 @@ import { notionWriteTool } from './notion/write' import { chatTool as openAIChat } from './openai/chat' import { embeddingsTool as openAIEmbeddings } from './openai/embeddings' import { deleteTool as pineconeDeleteTool } from './pinecone/delete' -import { queryTool as pineconeQueryTool } from './pinecone/query' -import { upsertTool as pineconeUpsertTool } from './pinecone/upsert' +import { fetchTool as pineconeFetchTool } from './pinecone/fetch' +import { generateEmbeddingsTool as pineconeGenerateEmbeddingsTool } from './pinecone/generate' +import { searchTextTool as pineconeSearchTextTool } from './pinecone/searchText' +import { upsertTextTool as pineconeUpsertTextTool } from './pinecone/upsertText' import { opportunitiesTool as salesforceOpportunities } from './salesforce/opportunities' import { searchTool as serperSearch } from './serper/search' import { slackMessageTool } from './slack/message' @@ -63,9 +65,11 @@ export const tools: Record = { x_read: xRead, x_search: xSearch, x_user: xUser, - pinecone_query: pineconeQueryTool, - pinecone_upsert: pineconeUpsertTool, pinecone_delete: pineconeDeleteTool, + pinecone_fetch: pineconeFetchTool, + pinecone_generate_embeddings: pineconeGenerateEmbeddingsTool, + pinecone_search_text: pineconeSearchTextTool, + pinecone_upsert_text: pineconeUpsertTextTool, } // Get a tool by its ID diff --git a/tools/pinecone/fetch.ts b/tools/pinecone/fetch.ts new file mode 100644 index 000000000..8eade5f03 --- /dev/null +++ b/tools/pinecone/fetch.ts @@ -0,0 +1,51 @@ +import { ToolConfig } from '../types' +import { PineconeFetchParams, PineconeResponse } from './types' + +export const fetchTool: ToolConfig = { + id: 'pinecone_fetch', + name: 'Pinecone Fetch', + description: 'Fetch vectors by ID from a Pinecone index', + version: '1.0', + + params: { + apiKey: { type: 'string', required: true, description: 'Pinecone API key' }, + environment: { type: 'string', required: true, description: 'Pinecone environment' }, + indexName: { type: 'string', required: true, description: 'Name of the Pinecone index' }, + ids: { type: 'array', required: true, description: 'Array of vector IDs to fetch' }, + namespace: { type: 'string', required: false, description: 'Namespace to fetch vectors from' }, + }, + + request: { + method: 'GET', + url: (params) => { + const baseUrl = `https://${params.indexName}-${params.environment}.svc.${params.environment}.pinecone.io/vectors/fetch` + const queryParams = new URLSearchParams() + queryParams.append('ids', params.ids.join(',')) + if (params.namespace) { + queryParams.append('namespace', params.namespace) + } + return `${baseUrl}?${queryParams.toString()}` + }, + headers: (params) => ({ + 'Api-Key': params.apiKey, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + return { + success: true, + output: { + matches: Object.entries(data.vectors).map(([id, vector]: [string, any]) => ({ + id, + score: 1.0, // Fetch doesn't return scores, so we use 1.0 for exact matches + values: vector.values, + metadata: vector.metadata, + })), + }, + } + }, + + transformError: (error) => `Pinecone fetch failed: ${error.message}`, +} diff --git a/tools/pinecone/generate.ts b/tools/pinecone/generate.ts new file mode 100644 index 000000000..d071e4d76 --- /dev/null +++ b/tools/pinecone/generate.ts @@ -0,0 +1,60 @@ +import { ToolConfig } from '../types' +import { PineconeGenerateEmbeddingsParams, PineconeResponse } from './types' + +export const generateEmbeddingsTool: ToolConfig< + PineconeGenerateEmbeddingsParams, + PineconeResponse +> = { + id: 'pinecone_generate_embeddings', + name: 'Pinecone Generate Embeddings', + description: "Generate embeddings from text using Pinecone's hosted models", + version: '1.0', + + params: { + apiKey: { type: 'string', required: true, description: 'Pinecone API key' }, + environment: { type: 'string', required: true, description: 'Pinecone environment' }, + indexName: { type: 'string', required: true, description: 'Name of the Pinecone index' }, + model: { + type: 'string', + required: true, + description: 'Model to use for generating embeddings', + }, + inputs: { + type: 'array', + required: true, + description: 'Array of text inputs to generate embeddings for', + }, + parameters: { type: 'object', required: false, description: 'Additional model parameters' }, + }, + + request: { + method: 'POST', + url: () => 'https://api.pinecone.io/embed', + headers: (params) => ({ + 'Api-Key': params.apiKey, + 'Content-Type': 'application/json', + 'X-Pinecone-API-Version': '2025-01', + }), + body: (params) => ({ + model: params.model, + inputs: params.inputs, + parameters: { + input_type: 'passage', + truncate: 'END', + }, + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + return { + success: true, + output: { + embeddings: data.embeddings, + usage: data.usage, + }, + } + }, + + transformError: (error) => `Pinecone embeddings generation failed: ${error.message}`, +} diff --git a/tools/pinecone/query.ts b/tools/pinecone/query.ts deleted file mode 100644 index b0b7c7639..000000000 --- a/tools/pinecone/query.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { ToolConfig } from '../types' -import { PineconeParams, PineconeResponse } from './types' - -export const queryTool: ToolConfig = { - id: 'pinecone_query', - name: 'Pinecone Query', - description: 'Query vectors from Pinecone index', - version: '1.0', - - params: { - apiKey: { type: 'string', required: true, description: 'Pinecone API key' }, - environment: { type: 'string', required: true, description: 'Pinecone environment' }, - indexName: { type: 'string', required: true, description: 'Name of the Pinecone index' }, - queryVector: { type: 'array', required: true, description: 'Vector to query' }, - topK: { - type: 'number', - required: false, - default: 10, - description: 'Number of results to return', - }, - includeMetadata: { - type: 'boolean', - required: false, - default: true, - description: 'Include metadata in results', - }, - includeValues: { - type: 'boolean', - required: false, - default: false, - description: 'Include vector values in results', - }, - }, - - request: { - method: 'POST', - url: (params) => - `https://${params.indexName}-${params.environment}.svc.${params.environment}.pinecone.io/vectors/query`, - headers: (params) => ({ - 'Api-Key': params.apiKey, - 'Content-Type': 'application/json', - }), - body: (params) => ({ - vector: params.queryVector, - topK: params.topK || 10, - includeMetadata: params.includeMetadata ?? true, - includeValues: params.includeValues ?? false, - }), - }, - - transformResponse: async (response) => { - const data = await response.json() - return { - success: true, - output: { - matches: data.matches || [], - }, - } - }, - - transformError: (error) => `Pinecone query failed: ${error.message}`, -} diff --git a/tools/pinecone/searchText.ts b/tools/pinecone/searchText.ts new file mode 100644 index 000000000..a4900d830 --- /dev/null +++ b/tools/pinecone/searchText.ts @@ -0,0 +1,63 @@ +import { ToolConfig } from '../types' +import { PineconeResponse, PineconeSearchTextParams } from './types' + +export const searchTextTool: ToolConfig = { + id: 'pinecone_search_text', + name: 'Pinecone Search Text', + description: 'Search for similar text in a Pinecone index', + version: '1.0', + + params: { + apiKey: { type: 'string', required: true, description: 'Pinecone API key' }, + environment: { type: 'string', required: true, description: 'Pinecone environment' }, + indexName: { type: 'string', required: true, description: 'Name of the Pinecone index' }, + namespace: { type: 'string', required: false, description: 'Namespace to search in' }, + query: { + type: 'object', + required: true, + description: 'Query parameters including text input and top_k', + }, + fields: { + type: 'array', + required: false, + description: 'Fields to return in the search results', + }, + rerank: { + type: 'object', + required: false, + description: 'Parameters for reranking the initial search results', + }, + }, + + request: { + method: 'POST', + url: (params) => + `https://${params.indexName}-${params.environment}.svc.${params.environment}.pinecone.io/records/namespaces/${params.namespace || ''}/search`, + headers: (params) => ({ + 'Api-Key': params.apiKey, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + query: params.query, + fields: params.fields, + rerank: params.rerank, + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + return { + success: true, + output: { + matches: data.matches.map((match: any) => ({ + id: match.id, + score: match.score, + metadata: match.metadata, + values: match.values, + })), + }, + } + }, + + transformError: (error) => `Pinecone text search failed: ${error.message}`, +} diff --git a/tools/pinecone/types.ts b/tools/pinecone/types.ts index c728ffbb2..a3eefb8cd 100644 --- a/tools/pinecone/types.ts +++ b/tools/pinecone/types.ts @@ -1,5 +1,88 @@ import { ToolResponse } from '../types' +// Base Pinecone params shared across all operations +export interface PineconeBaseParams { + apiKey: string + environment: string + indexName: string +} + +// Response types +export interface PineconeMatchResponse { + id: string + score: number + values?: number[] + metadata?: Record +} + +export interface PineconeResponse extends ToolResponse { + output: { + matches?: PineconeMatchResponse[] + upsertedCount?: number + deletedCount?: number + embeddings?: number[][] + usage?: { + prompt_tokens: number + total_tokens: number + } + } +} + +// Generate Embeddings +export interface PineconeGenerateEmbeddingsParams extends PineconeBaseParams { + model: string + inputs: { text: string }[] + parameters?: Record +} + +// Upsert Text +export interface PineconeUpsertTextParams extends PineconeBaseParams { + namespace?: string + records: { + _id: string + text: string + metadata?: Record + }[] +} + +// Upsert Vectors +export interface PineconeUpsertVectorsParams extends PineconeBaseParams { + namespace?: string + vectors: { + id: string + values: number[] + metadata?: Record + sparseValues?: { + indices: number[] + values: number[] + } + }[] +} + +// Search Text +export interface PineconeSearchTextParams extends PineconeBaseParams { + namespace?: string + query: { + inputs: string + top_k: number + filter?: Record + } + fields?: string[] + rerank?: { + model: string + rank_fields: string[] + top_n?: number + parameters?: Record + query?: string + } +} + +// Fetch Vectors +export interface PineconeFetchParams extends PineconeBaseParams { + ids: string[] + namespace?: string +} + export interface PineconeParams { apiKey: string environment: string @@ -20,16 +103,3 @@ export interface PineconeParams { ids?: string[] deleteAll?: boolean } - -export interface PineconeResponse extends ToolResponse { - output: { - matches?: Array<{ - id: string - score: number - values?: number[] - metadata?: Record - }> - upsertedCount?: number - deletedCount?: number - } -} diff --git a/tools/pinecone/upsert.ts b/tools/pinecone/upsertText.ts similarity index 55% rename from tools/pinecone/upsert.ts rename to tools/pinecone/upsertText.ts index be646a83b..9ddff05b1 100644 --- a/tools/pinecone/upsert.ts +++ b/tools/pinecone/upsertText.ts @@ -1,33 +1,34 @@ import { ToolConfig } from '../types' -import { PineconeParams, PineconeResponse } from './types' +import { PineconeResponse, PineconeUpsertTextParams } from './types' -export const upsertTool: ToolConfig = { - id: 'pinecone_upsert', - name: 'Pinecone Upsert', - description: 'Upsert vectors into Pinecone index', +export const upsertTextTool: ToolConfig = { + id: 'pinecone_upsert_text', + name: 'Pinecone Upsert Text', + description: 'Insert or update text records in a Pinecone index', version: '1.0', params: { apiKey: { type: 'string', required: true, description: 'Pinecone API key' }, environment: { type: 'string', required: true, description: 'Pinecone environment' }, indexName: { type: 'string', required: true, description: 'Name of the Pinecone index' }, - vectors: { + namespace: { type: 'string', required: false, description: 'Namespace to upsert records into' }, + records: { type: 'array', required: true, - description: 'Array of vectors to upsert, each with id, values, and optional metadata', + description: 'Array of records to upsert, each containing _id, text, and optional metadata', }, }, request: { method: 'POST', url: (params) => - `https://${params.indexName}-${params.environment}.svc.${params.environment}.pinecone.io/vectors/upsert`, + `https://${params.indexName}-${params.environment}.svc.${params.environment}.pinecone.io/records/namespaces/${params.namespace || ''}/upsert`, headers: (params) => ({ 'Api-Key': params.apiKey, 'Content-Type': 'application/json', }), body: (params) => ({ - vectors: params.vectors, + records: params.records, }), }, @@ -41,5 +42,5 @@ export const upsertTool: ToolConfig = { } }, - transformError: (error) => `Pinecone upsert failed: ${error.message}`, + transformError: (error) => `Pinecone text upsert failed: ${error.message}`, }