Files
WeHub Mirror 6bf8bebf51
CI / Test and Build (push) Failing after 1s
CI / Migrate Dev DB (push) Has been skipped
CI / Migrate DB (push) Has been skipped
CodeQL / Analyze actions (push) Has been cancelled
CodeQL / Analyze javascript-typescript (push) Has been cancelled
CI / Detect Version (push) Has been cancelled
CI / Detect Desktop Changes (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/cron.Dockerfile, ubuntu-latest, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build AMD64 (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/cron.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/db.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/pii.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/realtime.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-8vcpu-ubuntu-2404-arm, ./docker/app.Dockerfile, linux-arm64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
Helm Chart / Lint, test, and validate chart (push) Has been cancelled
Helm Chart / Chart version bumped (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Build Dev ECR (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core) (push) Has been cancelled
CI / Promote Images (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Check Desktop Signing Secrets (push) Has been cancelled
CI / Desktop Release (push) Has been cancelled
CI / Create Desktop Prerelease (push) Has been cancelled
CI / Desktop Prerelease Build (push) Has been cancelled
CI / Publish Desktop Prerelease (push) Has been cancelled
CI / Prune Desktop Prereleases (push) Has been cancelled
Helm Chart / Install on kind and run helm test (push) Has been cancelled
WeHub snapshot of cb28d14c6f2c081de7a0d8729a8c816c9adef67a
2026-08-10 11:17:50 +08:00

224 lines
7.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { DEFAULT_RERANKER_MODEL } from '@/lib/knowledge/reranker-models'
import type { KnowledgeSearchResponse } from '@/tools/knowledge/types'
import { enrichKBTagFiltersSchema } from '@/tools/schema-enrichers'
import { parseTagFilters } from '@/tools/shared/tags'
import type { ToolConfig } from '@/tools/types'
export const knowledgeSearchTool: ToolConfig<any, KnowledgeSearchResponse> = {
id: 'knowledge_search',
name: 'Knowledge Search',
description: 'Search for similar content in a knowledge base using vector similarity',
version: '1.0.0',
params: {
knowledgeBaseId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the knowledge base to search in',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search query text (optional when using tag filters)',
},
topK: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of most similar results to return (1-100)',
},
tagFilters: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description: 'Array of tag filters with tagName and tagValue properties',
items: {
type: 'object',
properties: {
tagName: { type: 'string' },
tagValue: { type: 'string' },
},
},
},
searchMode: {
type: 'string',
required: false,
visibility: 'user-only',
description:
"Retrieval mode: 'vector' (default) uses semantic similarity only, 'hybrid' also runs a full-text leg and fuses both",
},
rerankerEnabled: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Whether to apply Cohere reranking to vector search results',
},
rerankerModel: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Cohere rerank model to use (one of: rerank-v4.0-pro, rerank-v4.0-fast, rerank-v3.5)',
},
rerankerInputCount: {
type: 'number',
required: false,
visibility: 'user-only',
description:
'Number of vector results sent to the Cohere reranker (1100). Defaults to topK × 4 capped at 100.',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Cohere API key for reranker (self-hosted deployments only)',
},
},
schemaEnrichment: {
tagFilters: {
dependsOn: 'knowledgeBaseId',
enrichSchema: enrichKBTagFiltersSchema,
},
},
request: {
url: () => '/api/knowledge/search',
method: 'POST',
modelInput: {
mode: 'private-provenance',
inputPaths: () => [['query']],
},
secretProvenance: { response: { incomplete: 'reject' } },
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => {
const workflowId = params._context?.workflowId
// Use single knowledge base ID
const knowledgeBaseIds = [params.knowledgeBaseId]
// Parse tag filters from various formats (array, JSON string)
const structuredFilters = parseTagFilters(params.tagFilters)
const rerankerEnabled = params.rerankerEnabled === true || params.rerankerEnabled === 'true'
const rerankerModel =
typeof params.rerankerModel === 'string' && params.rerankerModel.length > 0
? params.rerankerModel
: DEFAULT_RERANKER_MODEL
const rerankerApiKey =
typeof params.apiKey === 'string' && params.apiKey.length > 0 ? params.apiKey : undefined
const rawInputCount =
params.rerankerInputCount !== undefined &&
params.rerankerInputCount !== null &&
params.rerankerInputCount !== ''
? Number(params.rerankerInputCount)
: Number.NaN
const rerankerInputCount = Number.isFinite(rawInputCount)
? Math.max(1, Math.min(100, Math.floor(rawInputCount)))
: undefined
const requestBody = {
knowledgeBaseIds,
query: params.query,
topK: params.topK ? Math.max(1, Math.min(100, Number(params.topK))) : 10,
...(structuredFilters.length > 0 && { tagFilters: structuredFilters }),
...(params.searchMode === 'hybrid' && { searchMode: 'hybrid' }),
...(rerankerEnabled && {
rerankerEnabled: true,
rerankerModel,
...(rerankerInputCount !== undefined && { rerankerInputCount }),
...(rerankerApiKey && { rerankerApiKey }),
}),
...(workflowId && { workflowId }),
// The executor rolls this search's cost up at workflow completion, so
// tell the route not to also meter it (avoids double-billing).
skipUsageBilling: true,
}
return requestBody
},
},
transformResponse: async (response): Promise<KnowledgeSearchResponse> => {
const result = await response.json()
const data = result.data || result
// Restructure cost: extract tokens/model to top level for logging
let costFields: Record<string, unknown> = {}
if (data.cost && typeof data.cost === 'object') {
const {
tokens,
model,
input,
output: outputCost,
total,
rerankerCost,
rerankerModel,
rerankerSearchUnits,
} = data.cost
costFields = {
cost: {
input,
output: outputCost,
total,
...(typeof rerankerCost === 'number' && { rerankerCost }),
...(typeof rerankerModel === 'string' && { rerankerModel }),
...(typeof rerankerSearchUnits === 'number' && { rerankerSearchUnits }),
},
...(tokens && { tokens }),
...(model && { model }),
}
}
return {
success: true,
output: {
results: data.results || [],
query: data.query,
totalResults: data.totalResults || 0,
...costFields,
},
}
},
outputs: {
results: {
type: 'array',
description: 'Array of search results from the knowledge base',
items: {
type: 'object',
properties: {
documentId: { type: 'string', description: 'Document ID' },
documentName: { type: 'string', description: 'Document name' },
sourceUrl: {
type: 'string',
nullable: true,
description:
'URL to the original source document (e.g., Confluence page, Google Doc, Notion page). Null for documents without an external source.',
},
content: { type: 'string', description: 'Content of the result' },
chunkIndex: { type: 'number', description: 'Index of the chunk within the document' },
similarity: { type: 'number', description: 'Similarity score of the result' },
metadata: { type: 'object', description: 'Metadata of the result, including tags' },
},
},
},
query: {
type: 'string',
description: 'The search query that was executed',
},
totalResults: {
type: 'number',
description: 'Total number of results found',
},
cost: {
type: 'object',
description: 'Cost information for the search operation',
optional: true,
},
},
}