Files
ask262/src/agent-tools/searchSpecSections.ts
T
2026-04-08 18:40:45 +05:30

57 lines
2.0 KiB
TypeScript

/**
* Search specification sections tool.
* Performs semantic vector search to find relevant specification sections by query.
*/
import type { Table } from "@lancedb/lancedb";
import { DynamicStructuredTool } from "@langchain/core/tools";
import type { OllamaEmbeddings } from "@langchain/ollama";
import { z } from "zod";
const searchSpecSchema = z.object({
query: z
.string()
.describe("The search query to find relevant specification sections"),
});
/**
* Creates the search spec sections tool.
* Performs semantic vector search to find relevant spec sections.
* @param table - LanceDB table containing spec vectors
* @param embeddings - Ollama embeddings instance
*/
export function createSearchSpecSectionsTool(
table: Table,
embeddings: OllamaEmbeddings,
) {
return new DynamicStructuredTool({
name: "ask262_search_spec_sections",
description:
"Searches the ECMAScript specification for sections relevant to a query. Returns JSON array with sectionId, sectionTitle, score, partIndex, totalParts, and content. partIndex and totalParts indicate which chunk of a multi-part section this is (0-indexed, partIndex+1/totalParts), null if single-part.",
schema: searchSpecSchema,
func: async ({ query }) => {
// Generate embedding for the query
const queryVector = await embeddings.embedQuery(query);
// Search using LanceDB directly, limit to top 5 results
const results = await table.search(queryVector).limit(5).toArray();
console.log(
`[ask262_search_spec_sections] Query: "${query.slice(0, 50)}..." - Fetched ${results.length} results`,
);
// Return documents with metadata as JSON
const output = results.map((r: Record<string, unknown>) => ({
sectionId: String(r.sectionid || "unknown"),
sectionTitle: String(r.sectiontitle || "unknown"),
score: Number(r._distance || 0),
partIndex: r.partindex ?? null,
totalParts: r.totalparts ?? null,
content: String(r.text || ""),
}));
return JSON.stringify(output);
},
});
}