mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(memory): all pinecone tools/blocks work
This commit is contained in:
+10
-1
@@ -48,7 +48,16 @@ export async function POST(request: Request) {
|
||||
const method = params.method || defaultMethod || 'GET'
|
||||
const headers = headersFn ? headersFn(params) : {}
|
||||
const hasBody = method !== 'GET' && method !== 'HEAD' && !!bodyFn
|
||||
const body = hasBody ? JSON.stringify(bodyFn!(params)) : undefined
|
||||
|
||||
const bodyResult = bodyFn ? bodyFn(params) : undefined
|
||||
|
||||
// Special handling for NDJSON content type
|
||||
const isNDJSON = headers['Content-Type'] === 'application/x-ndjson'
|
||||
const body = hasBody
|
||||
? isNDJSON && bodyResult
|
||||
? bodyResult.body
|
||||
: JSON.stringify(bodyResult)
|
||||
: undefined
|
||||
|
||||
const externalResponse = await fetch(url, { method, headers, body })
|
||||
|
||||
|
||||
+48
-26
@@ -22,25 +22,8 @@ export const PineconeBlock: BlockConfig<PineconeResponse> = {
|
||||
{ label: 'Upsert Text', id: 'upsert_text' },
|
||||
{ label: 'Search Text', id: 'search_text' },
|
||||
{ label: 'Fetch Vectors', id: 'fetch' },
|
||||
{ label: 'Delete Vectors', id: 'delete' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'environment',
|
||||
title: 'Environment',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'gcp-starter',
|
||||
condition: { field: 'operation', value: 'upsert_text' },
|
||||
},
|
||||
{
|
||||
id: 'indexName',
|
||||
title: 'Index Name',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'my-index',
|
||||
condition: { field: 'operation', value: 'upsert_text' },
|
||||
},
|
||||
// Generate embeddings fields
|
||||
{
|
||||
id: 'model',
|
||||
@@ -63,12 +46,29 @@ export const PineconeBlock: BlockConfig<PineconeResponse> = {
|
||||
condition: { field: 'operation', value: 'generate' },
|
||||
},
|
||||
// Upsert text fields
|
||||
{
|
||||
id: 'indexHost',
|
||||
title: 'Index Host',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'https://index-name-abc123.svc.project-id.pinecone.io',
|
||||
condition: { field: 'operation', value: 'upsert_text' },
|
||||
},
|
||||
{
|
||||
id: 'namespace',
|
||||
title: 'Namespace',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Optional namespace',
|
||||
condition: { field: 'operation', value: 'upsert_text' },
|
||||
},
|
||||
{
|
||||
id: 'records',
|
||||
title: 'Records',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: '[{"_id": "doc1", "text": "Your text here", "metadata": {"key": "value"}}]',
|
||||
placeholder:
|
||||
'{"_id": "rec1", "text": "Apple\'s first product, the Apple I, was released in 1976.", "category": "product"}\n{"_id": "rec2", "chunk_text": "Apples are a great source of dietary fiber.", "category": "nutrition"}',
|
||||
condition: { field: 'operation', value: 'upsert_text' },
|
||||
},
|
||||
// Search text fields
|
||||
@@ -88,15 +88,39 @@ export const PineconeBlock: BlockConfig<PineconeResponse> = {
|
||||
placeholder: '10',
|
||||
condition: { field: 'operation', value: 'search_text' },
|
||||
},
|
||||
{
|
||||
id: 'fields',
|
||||
title: 'Fields to Return',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: '["category", "text"]',
|
||||
condition: { field: 'operation', value: 'search_text' },
|
||||
},
|
||||
{
|
||||
id: 'filter',
|
||||
title: 'Filter',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: '{"key": "value"}',
|
||||
placeholder: '{"category": "product"}',
|
||||
condition: { field: 'operation', value: 'search_text' },
|
||||
},
|
||||
{
|
||||
id: 'rerank',
|
||||
title: 'Rerank Options',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: '{"model": "bge-reranker-v2-m3", "rank_fields": ["text"], "top_n": 2}',
|
||||
condition: { field: 'operation', value: 'search_text' },
|
||||
},
|
||||
// Fetch fields
|
||||
{
|
||||
id: 'indexHost',
|
||||
title: 'Index Host',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'https://index-name-abc123.svc.project-id.pinecone.io',
|
||||
condition: { field: 'operation', value: 'fetch' },
|
||||
},
|
||||
{
|
||||
id: 'ids',
|
||||
title: 'Vector IDs',
|
||||
@@ -105,15 +129,15 @@ export const PineconeBlock: BlockConfig<PineconeResponse> = {
|
||||
placeholder: '["vec1", "vec2"]',
|
||||
condition: { field: 'operation', value: 'fetch' },
|
||||
},
|
||||
// Common fields
|
||||
{
|
||||
id: 'namespace',
|
||||
title: 'Namespace',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Optional namespace',
|
||||
condition: { field: 'operation', value: 'upsert_text' },
|
||||
condition: { field: 'operation', value: 'fetch' },
|
||||
},
|
||||
// Common fields
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
@@ -130,7 +154,6 @@ export const PineconeBlock: BlockConfig<PineconeResponse> = {
|
||||
'pinecone_upsert_text',
|
||||
'pinecone_search_text',
|
||||
'pinecone_fetch',
|
||||
'pinecone_delete',
|
||||
],
|
||||
config: {
|
||||
tool: (params: Record<string, any>) => {
|
||||
@@ -143,8 +166,6 @@ export const PineconeBlock: BlockConfig<PineconeResponse> = {
|
||||
return 'pinecone_search_text'
|
||||
case 'fetch':
|
||||
return 'pinecone_fetch'
|
||||
case 'delete':
|
||||
return 'pinecone_delete'
|
||||
default:
|
||||
throw new Error('Invalid operation selected')
|
||||
}
|
||||
@@ -157,6 +178,7 @@ export const PineconeBlock: BlockConfig<PineconeResponse> = {
|
||||
apiKey: { type: 'string', required: true },
|
||||
environment: { type: 'string', required: false },
|
||||
indexName: { type: 'string', required: false },
|
||||
indexHost: { type: 'string', required: false },
|
||||
namespace: { type: 'string', required: false },
|
||||
// Generate embeddings inputs
|
||||
model: { type: 'string', required: false },
|
||||
@@ -167,11 +189,11 @@ export const PineconeBlock: BlockConfig<PineconeResponse> = {
|
||||
// Search text inputs
|
||||
searchQuery: { type: 'string', required: false },
|
||||
topK: { type: 'string', required: false },
|
||||
fields: { type: 'json', required: false },
|
||||
filter: { type: 'json', required: false },
|
||||
rerank: { type: 'json', required: false },
|
||||
// Fetch inputs
|
||||
ids: { type: 'json', required: false },
|
||||
// Delete inputs
|
||||
deleteAll: { type: 'boolean', required: false },
|
||||
},
|
||||
|
||||
outputs: {
|
||||
|
||||
@@ -33,6 +33,12 @@ import { cn } from '@/lib/utils'
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive> & {
|
||||
|
||||
@@ -16,7 +16,6 @@ import { notionReadTool } from './notion/read'
|
||||
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 { fetchTool as pineconeFetchTool } from './pinecone/fetch'
|
||||
import { generateEmbeddingsTool as pineconeGenerateEmbeddingsTool } from './pinecone/generate'
|
||||
import { searchTextTool as pineconeSearchTextTool } from './pinecone/searchText'
|
||||
@@ -65,7 +64,6 @@ export const tools: Record<string, ToolConfig> = {
|
||||
x_read: xRead,
|
||||
x_search: xSearch,
|
||||
x_user: xUser,
|
||||
pinecone_delete: pineconeDeleteTool,
|
||||
pinecone_fetch: pineconeFetchTool,
|
||||
pinecone_generate_embeddings: pineconeGenerateEmbeddingsTool,
|
||||
pinecone_search_text: pineconeSearchTextTool,
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import { ToolConfig } from '../types'
|
||||
import { PineconeParams, PineconeResponse } from './types'
|
||||
|
||||
export const deleteTool: ToolConfig<PineconeParams, PineconeResponse> = {
|
||||
id: 'pinecone_delete',
|
||||
name: 'Pinecone Delete',
|
||||
description: 'Delete 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' },
|
||||
ids: { type: 'array', required: false, description: 'Array of vector IDs to delete' },
|
||||
deleteAll: { type: 'boolean', required: false, description: 'Delete all vectors in the index' },
|
||||
},
|
||||
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: (params) =>
|
||||
`https://${params.indexName}-${params.environment}.svc.${params.environment}.pinecone.io/vectors/delete`,
|
||||
headers: (params) => ({
|
||||
'Api-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
ids: params.ids,
|
||||
deleteAll: params.deleteAll,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deletedCount: response.ok ? 1 : 0, // Pinecone doesn't return count, so we estimate
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => `Pinecone delete failed: ${error.message}`,
|
||||
}
|
||||
+31
-8
@@ -1,5 +1,5 @@
|
||||
import { ToolConfig } from '../types'
|
||||
import { PineconeFetchParams, PineconeResponse } from './types'
|
||||
import { PineconeFetchParams, PineconeResponse, PineconeVector } from './types'
|
||||
|
||||
export const fetchTool: ToolConfig<PineconeFetchParams, PineconeResponse> = {
|
||||
id: 'pinecone_fetch',
|
||||
@@ -8,17 +8,31 @@ export const fetchTool: ToolConfig<PineconeFetchParams, PineconeResponse> = {
|
||||
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' },
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Pinecone API key',
|
||||
},
|
||||
indexHost: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Full Pinecone index host URL',
|
||||
},
|
||||
ids: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
requiredForToolCall: 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 baseUrl = `${params.indexHost}/vectors/fetch`
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('ids', params.ids.join(','))
|
||||
if (params.namespace) {
|
||||
@@ -34,15 +48,24 @@ export const fetchTool: ToolConfig<PineconeFetchParams, PineconeResponse> = {
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
const vectors = data.vectors as Record<string, PineconeVector>
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
matches: Object.entries(data.vectors).map(([id, vector]: [string, any]) => ({
|
||||
matches: Object.entries(vectors).map(([id, vector]) => ({
|
||||
id,
|
||||
score: 1.0, // Fetch doesn't return scores, so we use 1.0 for exact matches
|
||||
values: vector.values,
|
||||
metadata: vector.metadata,
|
||||
score: 1.0, // Fetch returns exact matches
|
||||
})),
|
||||
data: Object.values(vectors).map((vector) => ({
|
||||
values: vector.values,
|
||||
vector_type: 'dense' as const,
|
||||
})),
|
||||
usage: {
|
||||
total_tokens: data.usage?.readUnits || 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,12 @@ export const generateEmbeddingsTool: ToolConfig<
|
||||
version: '1.0',
|
||||
|
||||
params: {
|
||||
apiKey: { type: 'string', required: true, description: 'Pinecone API key' },
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Pinecone API key',
|
||||
},
|
||||
model: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ToolConfig } from '../types'
|
||||
import { PineconeResponse, PineconeSearchTextParams } from './types'
|
||||
import { PineconeResponse, PineconeSearchHit, PineconeSearchTextParams } from './types'
|
||||
|
||||
export const searchTextTool: ToolConfig<PineconeSearchTextParams, PineconeResponse> = {
|
||||
id: 'pinecone_search_text',
|
||||
@@ -8,40 +8,68 @@ export const searchTextTool: ToolConfig<PineconeSearchTextParams, PineconeRespon
|
||||
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',
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Query parameters including text input and top_k',
|
||||
requiredForToolCall: true,
|
||||
description: 'Pinecone API key',
|
||||
},
|
||||
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',
|
||||
indexHost: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Full Pinecone index host URL',
|
||||
},
|
||||
namespace: { type: 'string', required: false, description: 'Namespace to search in' },
|
||||
searchQuery: { type: 'string', required: true, description: 'Text to search for' },
|
||||
topK: { type: 'string', required: false, description: 'Number of results to return' },
|
||||
fields: { type: 'array', required: false, description: 'Fields to return in the results' },
|
||||
filter: { type: 'object', required: false, description: 'Filter to apply to the search' },
|
||||
rerank: { type: 'object', required: false, description: 'Reranking parameters' },
|
||||
},
|
||||
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: (params) =>
|
||||
`https://${params.indexName}-${params.environment}.svc.${params.environment}.pinecone.io/records/namespaces/${params.namespace || ''}/search`,
|
||||
url: (params) => `${params.indexHost}/records/namespaces/${params.namespace}/search`,
|
||||
headers: (params) => ({
|
||||
'Api-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
'X-Pinecone-API-Version': '2025-01',
|
||||
}),
|
||||
body: (params) => ({
|
||||
query: params.query,
|
||||
fields: params.fields,
|
||||
rerank: params.rerank,
|
||||
}),
|
||||
body: (params) => {
|
||||
// Format the query object
|
||||
const query = {
|
||||
inputs: { text: params.searchQuery },
|
||||
top_k: parseInt(params.topK || '10'),
|
||||
}
|
||||
|
||||
// Build the request body
|
||||
const body: any = {
|
||||
query,
|
||||
}
|
||||
|
||||
// Add optional parameters if provided
|
||||
if (params.fields) {
|
||||
body.fields = typeof params.fields === 'string' ? JSON.parse(params.fields) : params.fields
|
||||
}
|
||||
|
||||
if (params.filter) {
|
||||
body.query.filter =
|
||||
typeof params.filter === 'string' ? JSON.parse(params.filter) : params.filter
|
||||
}
|
||||
|
||||
if (params.rerank) {
|
||||
body.rerank = typeof params.rerank === 'string' ? JSON.parse(params.rerank) : params.rerank
|
||||
// If rerank query is not specified, use the search query
|
||||
if (!body.rerank.query) {
|
||||
body.rerank.query = { text: params.searchQuery }
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Search request body:', body)
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
@@ -49,12 +77,16 @@ export const searchTextTool: ToolConfig<PineconeSearchTextParams, PineconeRespon
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
matches: data.matches.map((match: any) => ({
|
||||
id: match.id,
|
||||
score: match.score,
|
||||
metadata: match.metadata,
|
||||
values: match.values,
|
||||
matches: data.result.hits.map((hit: PineconeSearchHit) => ({
|
||||
id: hit._id,
|
||||
score: hit._score,
|
||||
metadata: hit.fields,
|
||||
})),
|
||||
usage: {
|
||||
total_tokens: data.usage.embed_total_tokens || 0,
|
||||
read_units: data.usage.read_units,
|
||||
rerank_units: data.usage.rerank_units,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
+67
-28
@@ -2,9 +2,9 @@ import { ToolResponse } from '../types'
|
||||
|
||||
// Base Pinecone params shared across all operations
|
||||
export interface PineconeBaseParams {
|
||||
indexHost: string
|
||||
namespace: string
|
||||
apiKey: string
|
||||
environment: string
|
||||
indexName: string
|
||||
}
|
||||
|
||||
// Response types
|
||||
@@ -19,7 +19,6 @@ export interface PineconeResponse extends ToolResponse {
|
||||
output: {
|
||||
matches?: PineconeMatchResponse[]
|
||||
upsertedCount?: number
|
||||
deletedCount?: number
|
||||
data?: Array<{
|
||||
values: number[]
|
||||
vector_type: 'dense' | 'sparse'
|
||||
@@ -44,18 +43,19 @@ export interface PineconeGenerateEmbeddingsParams {
|
||||
}
|
||||
|
||||
// Upsert Text
|
||||
export interface PineconeUpsertTextRecord {
|
||||
_id: string
|
||||
chunk_text: string
|
||||
category?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface PineconeUpsertTextParams extends PineconeBaseParams {
|
||||
namespace?: string
|
||||
records: {
|
||||
_id: string
|
||||
text: string
|
||||
metadata?: Record<string, any>
|
||||
}[]
|
||||
records: PineconeUpsertTextRecord | PineconeUpsertTextRecord[]
|
||||
}
|
||||
|
||||
// Upsert Vectors
|
||||
export interface PineconeUpsertVectorsParams extends PineconeBaseParams {
|
||||
namespace?: string
|
||||
vectors: {
|
||||
id: string
|
||||
values: number[]
|
||||
@@ -68,33 +68,75 @@ export interface PineconeUpsertVectorsParams extends PineconeBaseParams {
|
||||
}
|
||||
|
||||
// Search Text
|
||||
export interface PineconeSearchTextParams extends PineconeBaseParams {
|
||||
namespace?: string
|
||||
query: {
|
||||
inputs: string
|
||||
top_k: number
|
||||
filter?: Record<string, any>
|
||||
export interface PineconeSearchQuery {
|
||||
inputs?: { text: string }
|
||||
vector?: {
|
||||
values: number[]
|
||||
sparse_values?: number[]
|
||||
sparse_indices?: number[]
|
||||
}
|
||||
fields?: string[]
|
||||
rerank?: {
|
||||
model: string
|
||||
rank_fields: string[]
|
||||
top_n?: number
|
||||
parameters?: Record<string, any>
|
||||
query?: string
|
||||
id?: string
|
||||
top_k: number
|
||||
filter?: Record<string, any>
|
||||
}
|
||||
|
||||
export interface PineconeRerank {
|
||||
model: string
|
||||
rank_fields: string[]
|
||||
top_n?: number
|
||||
parameters?: Record<string, any>
|
||||
query?: { text: string }
|
||||
}
|
||||
|
||||
export interface PineconeSearchTextParams extends PineconeBaseParams {
|
||||
searchQuery: string
|
||||
topK?: string
|
||||
fields?: string[] | string
|
||||
filter?: Record<string, any> | string
|
||||
rerank?: PineconeRerank | string
|
||||
}
|
||||
|
||||
export interface PineconeSearchHit {
|
||||
_id: string
|
||||
_score: number
|
||||
fields?: Record<string, any>
|
||||
}
|
||||
|
||||
export interface PineconeSearchResponse {
|
||||
result: {
|
||||
hits: PineconeSearchHit[]
|
||||
}
|
||||
usage: {
|
||||
read_units: number
|
||||
embed_total_tokens?: number
|
||||
rerank_units?: number
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch Vectors
|
||||
export interface PineconeFetchParams extends PineconeBaseParams {
|
||||
ids: string[]
|
||||
}
|
||||
|
||||
export interface PineconeVector {
|
||||
id: string
|
||||
values: number[]
|
||||
metadata?: Record<string, any>
|
||||
}
|
||||
|
||||
export interface PineconeUsage {
|
||||
readUnits: number
|
||||
}
|
||||
|
||||
export interface PineconeFetchResponse {
|
||||
vectors: Record<string, PineconeVector>
|
||||
namespace?: string
|
||||
usage: PineconeUsage
|
||||
}
|
||||
|
||||
export interface PineconeParams {
|
||||
apiKey: string
|
||||
environment: string
|
||||
indexName: string
|
||||
indexHost: string
|
||||
operation: 'query' | 'upsert' | 'delete'
|
||||
// Query operation
|
||||
queryVector?: number[]
|
||||
@@ -107,7 +149,4 @@ export interface PineconeParams {
|
||||
values: number[]
|
||||
metadata?: Record<string, any>
|
||||
}>
|
||||
// Delete operation
|
||||
ids?: string[]
|
||||
deleteAll?: boolean
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ToolConfig } from '../types'
|
||||
import { PineconeResponse, PineconeUpsertTextParams } from './types'
|
||||
import { PineconeResponse, PineconeUpsertTextParams, PineconeUpsertTextRecord } from './types'
|
||||
|
||||
export const upsertTextTool: ToolConfig<PineconeUpsertTextParams, PineconeResponse> = {
|
||||
id: 'pinecone_upsert_text',
|
||||
@@ -8,31 +8,70 @@ export const upsertTextTool: ToolConfig<PineconeUpsertTextParams, PineconeRespon
|
||||
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 upsert records into' },
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Pinecone API key',
|
||||
},
|
||||
indexHost: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Full Pinecone index host URL',
|
||||
},
|
||||
namespace: { type: 'string', required: true, description: 'Namespace to upsert records into' },
|
||||
records: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
description: 'Array of records to upsert, each containing _id, text, and optional metadata',
|
||||
description:
|
||||
'Record or 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/records/namespaces/${params.namespace || ''}/upsert`,
|
||||
url: (params) => `${params.indexHost}/records/namespaces/${params.namespace}/upsert`,
|
||||
headers: (params) => ({
|
||||
'Api-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
records: params.records,
|
||||
'Content-Type': 'application/x-ndjson',
|
||||
'X-Pinecone-API-Version': '2025-01',
|
||||
}),
|
||||
body: (params) => {
|
||||
// If records is a string, parse it line by line
|
||||
let records: PineconeUpsertTextRecord[]
|
||||
if (typeof params.records === 'string') {
|
||||
// Split by newlines and parse each line
|
||||
records = (params.records as string)
|
||||
.split('\n')
|
||||
.filter((line: string) => line.trim()) // Remove empty lines
|
||||
.map((line: string) => {
|
||||
// Clean and parse each line
|
||||
const cleanJson = line.trim().replace(/'\\''/g, "'")
|
||||
return JSON.parse(cleanJson) as PineconeUpsertTextRecord
|
||||
})
|
||||
} else {
|
||||
records = Array.isArray(params.records) ? params.records : [params.records]
|
||||
}
|
||||
|
||||
// Convert to NDJSON format
|
||||
const ndjson = records.map((r: PineconeUpsertTextRecord) => JSON.stringify(r)).join('\n')
|
||||
return { body: ndjson }
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
// Handle empty response (201 Created)
|
||||
if (response.status === 201) {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
statusText: 'Created',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Handle response with content
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
|
||||
Reference in New Issue
Block a user