refactor: rename tools

This commit is contained in:
2026-04-08 18:40:45 +05:30
parent 30debd2cf9
commit c109acba01
11 changed files with 158 additions and 153 deletions
+4 -4
View File
@@ -26,8 +26,8 @@ ask262/
│ ├── constants.ts # Directory paths and model configs │ ├── constants.ts # Directory paths and model configs
│ ├── agent-tools/ # Tool implementations (spec retriever, graph explorer) │ ├── agent-tools/ # Tool implementations (spec retriever, graph explorer)
│ │ ├── index.ts # Tool exports │ │ ├── index.ts # Tool exports
│ │ ├── specRetriever.ts # Vector search tool │ │ ├── searchSpecSections.ts # Vector search tool
│ │ ├── sectionRetriever.ts # Section chunk retrieval tool │ │ ├── getSectionContent.ts # Section chunk retrieval tool
│ │ ├── graphExplorer.ts # Knowledge graph navigation tool │ │ ├── graphExplorer.ts # Knowledge graph navigation tool
│ │ ├── evaluateInEngine262.ts # Execute JS and capture spec marks │ │ ├── evaluateInEngine262.ts # Execute JS and capture spec marks
│ │ └── reranker.ts # Document reranking utility │ │ └── reranker.ts # Document reranking utility
@@ -41,7 +41,7 @@ ask262/
│ └── test/ # Manual verification tests │ └── test/ # Manual verification tests
│ └── manual/ │ └── manual/
│ ├── verify-db.ts # Verify database contents │ ├── verify-db.ts # Verify database contents
│ ├── test-spec-retriever.ts # Test spec retriever tool │ ├── test-search-spec-sections.ts # Test vector search tool
│ └── test-evaluate-in-engine262.ts # Test evaluate tool │ └── test-evaluate-in-engine262.ts # Test evaluate tool
├── config.json # API keys and endpoints (user-created) ├── config.json # API keys and endpoints (user-created)
├── spec-built/multipage/ # ECMAScript spec HTML files ├── spec-built/multipage/ # ECMAScript spec HTML files
@@ -64,7 +64,7 @@ bun run format:fix # Format code with Biome
bun run type-check # TypeScript check (no emit) bun run type-check # TypeScript check (no emit)
bun test # Run all tests bun test # Run all tests
bun run test-evaluate # Test evaluate in engine262 tool bun run test-evaluate # Test evaluate in engine262 tool
bun run test-spec-retriever "query" # Test spec retriever tool with query bun run test-search-spec-sections "query" # Test vector search tool with query
bun run agent "Query" # Run agent with question bun run agent "Query" # Run agent with question
``` ```
+1 -1
View File
@@ -12,7 +12,7 @@
"ingest": "bun run src/setup/ingest.ts", "ingest": "bun run src/setup/ingest.ts",
"verify-db": "bun run src/test/manual/verify-db.ts", "verify-db": "bun run src/test/manual/verify-db.ts",
"test-evaluate": "bun run src/test/manual/test-evaluate-in-engine262.ts", "test-evaluate": "bun run src/test/manual/test-evaluate-in-engine262.ts",
"test-spec-retriever": "bun run src/test/manual/test-spec-retriever.ts", "test-search-spec-sections": "bun run src/test/manual/test-search-spec-sections.ts",
"agent": "bun run src/agent.ts", "agent": "bun run src/agent.ts",
"build": "bun run src/setup/buildGraph.ts", "build": "bun run src/setup/buildGraph.ts",
"test": "bun test" "test": "bun test"
+4 -4
View File
@@ -40,12 +40,12 @@ async function loadEngine262() {
*/ */
export function createEvaluateInEngine262Tool() { export function createEvaluateInEngine262Tool() {
return new DynamicStructuredTool({ return new DynamicStructuredTool({
name: "evaluate_in_engine262", name: "ask262_evaluate_in_engine262",
description: description:
"Executes JavaScript code in the engine262 JavaScript engine and captures which ECMAScript specification sections are hit during execution. Returns the full marks array as JSON. Useful for understanding how specific JavaScript operations map to the ECMAScript spec.", "Executes JavaScript code in the engine262 JavaScript engine and captures which ECMAScript specification sections are hit during execution. Returns the full marks array as JSON. Useful for understanding how specific JavaScript operations map to the ECMAScript spec.",
schema: evaluateSchema, schema: evaluateSchema,
func: async ({ code }) => { func: async ({ code }) => {
console.log(`[Tool: evaluate_in_engine262] Executing code...`); console.log(`[Tool: ask262_evaluate_in_engine262] Executing code...`);
try { try {
const engine = await loadEngine262(); const engine = await loadEngine262();
@@ -130,7 +130,7 @@ export function createEvaluateInEngine262Tool() {
const marks = ask262Debug.marks; const marks = ask262Debug.marks;
console.log( console.log(
`[Tool: evaluate_in_engine262] Captured ${marks.length} unique marks`, `[Tool: ask262_evaluate_in_engine262] Captured ${marks.length} unique marks`,
); );
// Filter and group marks by important flag // Filter and group marks by important flag
@@ -146,7 +146,7 @@ export function createEvaluateInEngine262Tool() {
// Return compressed JSON // Return compressed JSON
return JSON.stringify(result); return JSON.stringify(result);
} catch (error) { } catch (error) {
console.error(`[Tool: evaluate_in_engine262] Error: ${error}`); console.error(`[Tool: ask262_evaluate_in_engine262] Error: ${error}`);
return `Error executing code in engine262: ${error instanceof Error ? error.message : String(error)}`; return `Error executing code in engine262: ${error instanceof Error ? error.message : String(error)}`;
} }
}, },
@@ -1,5 +1,5 @@
/** /**
* Section chunk retriever tool. * Get section content tool.
* Retrieves all text chunks from a specific specification section by sectionid. * Retrieves all text chunks from a specific specification section by sectionid.
*/ */
@@ -7,24 +7,26 @@ import type { Table } from "@lancedb/lancedb";
import { DynamicStructuredTool } from "@langchain/core/tools"; import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod"; import { z } from "zod";
const sectionRetrieverSchema = z.object({ const getSectionContentSchema = z.object({
sectionId: z sectionId: z
.string() .string()
.describe("The section ID (e.g., 'sec-if-statement') to fetch chunks for"), .describe("The section ID (e.g., 'sec-if-statement') to fetch chunks for"),
}); });
/** /**
* Creates the section retriever tool. * Creates the get section content tool.
* Retrieves all text chunks from a specific specification section by sectionid.
* Supports recursive fetching - if a section has children, it will fetch all descendants.
* @param table - LanceDB table containing spec vectors * @param table - LanceDB table containing spec vectors
*/ */
export function createSectionRetrieverTool(table: Table) { export function createGetSectionContentTool(table: Table) {
return new DynamicStructuredTool({ return new DynamicStructuredTool({
name: "fetch_section_chunks", name: "ask262_get_section_content",
description: description:
"Retrieves all text chunks from a specific specification section by sectionid. " + "Retrieves all text chunks from a specific specification section by sectionid. " +
"Supports recursive fetching - if a section has children, it will fetch all descendants. " + "Supports recursive fetching - if a section has children, it will fetch all descendants. " +
"Use this to get complete content when you see 'Subsection available' or 'partial section' references.", "Use this to get complete content when you see 'Subsection available' or 'partial section' references.",
schema: sectionRetrieverSchema, schema: getSectionContentSchema,
func: async ({ sectionId }) => { func: async ({ sectionId }) => {
const allDocs: string[] = []; const allDocs: string[] = [];
const queue: string[] = [sectionId]; const queue: string[] = [sectionId];
+3 -3
View File
@@ -21,12 +21,12 @@ const graphExplorerSchema = z.object({
*/ */
export function createGraphExplorerTool(graph: Graph) { export function createGraphExplorerTool(graph: Graph) {
return new DynamicStructuredTool({ return new DynamicStructuredTool({
name: "graph_explorer", name: "ask262_graph_explorer",
description: description:
"Explores structural relationships between specification sections and implementation code (functions). Use this to find which spec section a function implements.", "Explores structural relationships between specification sections and implementation code (functions). Use this to find which spec section a function implements.",
schema: graphExplorerSchema, schema: graphExplorerSchema,
func: async ({ query }) => { func: async ({ query }) => {
console.log(`[Tool: graph_explorer] Querying for: ${query}`); console.log(`[Tool: ask262_graph_explorer] Querying for: ${query}`);
let nodeId = query; let nodeId = query;
if (!graph.hasNode(nodeId)) { if (!graph.hasNode(nodeId)) {
@@ -54,7 +54,7 @@ export function createGraphExplorerTool(graph: Graph) {
return result; return result;
} }
return `No information found in graph for ${query}. Use spec_retriever to search text.`; return `No information found in graph for ${query}. Use ask262_search_spec_sections to search text.`;
}, },
}); });
} }
+2 -2
View File
@@ -4,7 +4,7 @@
*/ */
export { createEvaluateInEngine262Tool } from "./evaluateInEngine262"; export { createEvaluateInEngine262Tool } from "./evaluateInEngine262";
export { createGetSectionContentTool } from "./getSectionContent";
export { createGraphExplorerTool } from "./graphExplorer"; export { createGraphExplorerTool } from "./graphExplorer";
export { type RerankResult, rerankDocuments } from "./reranker"; export { type RerankResult, rerankDocuments } from "./reranker";
export { createSectionRetrieverTool } from "./sectionRetriever"; export { createSearchSpecSectionsTool } from "./searchSpecSections";
export { createSpecRetrieverTool } from "./specRetriever";
+56
View File
@@ -0,0 +1,56 @@
/**
* 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);
},
});
}
-88
View File
@@ -1,88 +0,0 @@
/**
* Specification retriever tool.
* Queries the language specification for text content about specific sections or topics.
*/
import type { Table } from "@lancedb/lancedb";
import { DynamicStructuredTool } from "@langchain/core/tools";
import type { OllamaEmbeddings } from "@langchain/ollama";
import { z } from "zod";
import { rerankDocuments } from "./reranker";
const specRetrieverSchema = z.object({
query: z
.string()
.describe("The search query to find relevant specification sections"),
});
/**
* Creates the spec retriever tool.
* @param table - LanceDB table containing spec vectors
* @param embeddings - Ollama embeddings instance
*/
export function createSpecRetrieverTool(
table: Table,
embeddings: OllamaEmbeddings,
) {
return new DynamicStructuredTool({
name: "spec_retriever",
description:
"Queries the language specification for text content about specific sections or topics. Fetches up to 10 initial matches and uses a reranker to dynamically select the most relevant 3-5 documents based on query relevance.",
schema: specRetrieverSchema,
func: async ({ query }) => {
// Generate embedding for the query
const queryVector = await embeddings.embedQuery(query);
// Search using LanceDB directly
const results = await table.search(queryVector).limit(10).toArray();
// Create document objects with metadata
const documents = results.map((r: Record<string, unknown>) => ({
pageContent: String(r.text || ""),
metadata: {
source: r.source,
sectionid: r.sectionid,
sectiontitle: r.sectiontitle,
type: r.type,
parentsectionid: r.parentsectionid,
childrensectionids: r.childrensectionids,
partindex: r.partindex,
totalparts: r.totalparts,
},
}));
// Rerank documents
const reranked = await rerankDocuments(query, documents);
// Sort by score and filter to most relevant
reranked.sort((a, b) => b.score - a.score);
// Dynamic selection: take top documents with score > 0.5, or at least top 3
const threshold = 0.5;
const minDocs = 3;
const maxDocs = 5;
const selected = reranked.filter(
(r, i) => i < minDocs || (i < maxDocs && r.score > threshold),
);
console.log(
`[spec_retriever] Query: "${query.slice(0, 50)}..." - Fetched ${documents.length}, reranked to ${selected.length} (scores: ${selected.map((s) => s.score.toFixed(2)).join(", ")})`,
);
// Return documents with metadata
return selected
.map((r) => {
const meta = r.document.metadata;
const sectionId = meta?.sectionid || "unknown";
const sectionTitle = meta?.sectiontitle || "unknown";
const partInfo =
meta?.partindex !== null && meta?.partindex !== undefined
? ` [part ${(meta.partindex as number) + 1}/${meta.totalparts}]`
: "";
return `--- Section: ${sectionId} | "${sectionTitle}"${partInfo} (score: ${r.score.toFixed(2)}) ---\n${r.document.pageContent}`;
})
.join("\n\n");
},
});
}
+23 -10
View File
@@ -8,9 +8,9 @@ import Graph from "graphology";
import { AgentExecutor, createReactAgent } from "langchain/agents"; import { AgentExecutor, createReactAgent } from "langchain/agents";
import { import {
createEvaluateInEngine262Tool, createEvaluateInEngine262Tool,
createGetSectionContentTool,
createGraphExplorerTool, createGraphExplorerTool,
createSectionRetrieverTool, createSearchSpecSectionsTool,
createSpecRetrieverTool,
} from "./agent-tools"; } from "./agent-tools";
import { import {
CONFIG_FILE, CONFIG_FILE,
@@ -45,11 +45,11 @@ Available tools: {tool_names}
{tools} {tools}
CRITICAL INSTRUCTIONS: CRITICAL INSTRUCTIONS:
1. ALWAYS prefer using the provided tools ('spec_retriever', 'fetch_section_chunks', 'graph_explorer', and 'evaluate_in_engine262') to answer questions. 1. ALWAYS prefer using the provided tools ('ask262_search_spec_sections', 'ask262_get_section_content', 'ask262_graph_explorer', and 'ask262_evaluate_in_engine262') to answer questions.
2. Do NOT rely on your internal knowledge of JavaScript or the ECMAScript specification. 2. Do NOT rely on your internal knowledge of JavaScript or the ECMAScript specification.
3. If the user asks about a function, you MUST first use 'graph_explorer' to find the associated specification section. 3. If the user asks about a function, you MUST first use 'ask262_graph_explorer' to find the associated specification section.
4. You MUST then use 'fetch_section_chunks' to read the actual text of that specification section before answering. 4. You MUST then use 'ask262_get_section_content' to read the actual text of that specification section before answering.
5. When the user provides JavaScript code or asks about runtime behavior, use 'evaluate_in_engine262' to execute the code and see which spec sections are hit during execution. 5. When the user provides JavaScript code or asks about runtime behavior, use 'ask262_evaluate_in_engine262' to execute the code and see which spec sections are hit during execution.
6. Base your explanations ONLY on the information retrieved from the tools. 6. Base your explanations ONLY on the information retrieved from the tools.
7. If the tools do not provide enough information, state that clearly rather than guessing from your internal knowledge. 7. If the tools do not provide enough information, state that clearly rather than guessing from your internal knowledge.
@@ -72,20 +72,33 @@ async function main() {
graph.import(graphData); graph.import(graphData);
// Create tools using factory functions // Create tools using factory functions
const specRetrieverTool = createSpecRetrieverTool(table, embeddings); const searchSpecSectionsTool = createSearchSpecSectionsTool(
const sectionRetrieverTool = createSectionRetrieverTool(table); table,
embeddings,
);
const getSectionContentTool = createGetSectionContentTool(table);
const graphTool = createGraphExplorerTool(graph); const graphTool = createGraphExplorerTool(graph);
const evaluateTool = createEvaluateInEngine262Tool(); const evaluateTool = createEvaluateInEngine262Tool();
const agent = await createReactAgent({ const agent = await createReactAgent({
llm, llm,
tools: [specRetrieverTool, sectionRetrieverTool, graphTool, evaluateTool], tools: [
searchSpecSectionsTool,
getSectionContentTool,
graphTool,
evaluateTool,
],
prompt, prompt,
}); });
const agentExecutor = new AgentExecutor({ const agentExecutor = new AgentExecutor({
agent, agent,
tools: [specRetrieverTool, sectionRetrieverTool, graphTool, evaluateTool], tools: [
searchSpecSectionsTool,
getSectionContentTool,
graphTool,
evaluateTool,
],
}); });
console.log("Agent is ready!"); console.log("Agent is ready!");
@@ -0,0 +1,57 @@
#!/usr/bin/env bun
/**
* Manual test script for ask262_search_spec_sections agent tool.
* Tests the semantic vector search functionality.
*
* Usage: bun run src/test/manual/test-search-spec-sections.ts ["your search query"]
*
* Examples:
* bun run src/test/manual/test-search-spec-sections.ts
* bun run src/test/manual/test-search-spec-sections.ts "how does array prototype map work"
* bun run src/test/manual/test-search-spec-sections.ts "for statement evaluation"
*/
import * as lancedbSdk from "@lancedb/lancedb";
import { OllamaEmbeddings } from "@langchain/ollama";
import { createSearchSpecSectionsTool } from "../../agent-tools";
import { EMBEDDING_MODEL, STORAGE_DIR } from "../../constants";
async function main() {
// Get query from command line or use default
const query =
process.argv[2] ||
"how does the if statement evaluation work in javascript";
console.log("=== Testing ask262_search_spec_sections Tool ===\n");
console.log(`Query: "${query}"\n`);
console.log("Loading database and embeddings...");
try {
const embeddings = new OllamaEmbeddings({
model: EMBEDDING_MODEL,
});
const db = await lancedbSdk.connect(STORAGE_DIR);
const table = await db.openTable("spec_vectors");
console.log("✓ Database loaded\n");
console.log("Creating tool...");
const searchSpecSectionsTool = createSearchSpecSectionsTool(
table,
embeddings,
);
console.log("✓ Tool created\n");
console.log("Executing tool...\n");
const result = await searchSpecSectionsTool.func({ query });
console.log("=== TOOL OUTPUT ===");
console.log(result);
console.log("\n=== END OUTPUT ===");
} catch (error) {
console.error("\n✗ Error:", error);
process.exit(1);
}
}
main().catch(console.error);
-35
View File
@@ -1,35 +0,0 @@
/**
* Manual test script for spec_retriever agent tool
* Usage: bun run src/test/manual/test-spec-retriever.ts "your search query"
*/
import * as lancedbSdk from "@lancedb/lancedb";
import { OllamaEmbeddings } from "@langchain/ollama";
import { createSpecRetrieverTool } from "../../agent-tools";
import { EMBEDDING_MODEL, STORAGE_DIR } from "../../constants";
async function main() {
const query = process.argv[2] || "array.[[DefineOwnProperty]]";
console.log(`Testing spec_retriever with query: "${query}"`);
console.log("Loading database and embeddings...\n");
const embeddings = new OllamaEmbeddings({
model: EMBEDDING_MODEL,
});
const db = await lancedbSdk.connect(STORAGE_DIR);
const table = await db.openTable("spec_vectors");
console.log("Creating tool...\n");
const specRetrieverTool = createSpecRetrieverTool(table, embeddings);
console.log("Executing tool...\n");
const result = await specRetrieverTool.func({ query });
console.log("=== TOOL OUTPUT ===");
console.log(result);
console.log("\n=== END OUTPUT ===");
}
main().catch(console.error);