/** DSH Tool Schema to deterministic retrieval document projection. @module dsh-tool-retriever/retrieval/document */ import { normalizeIdentifier, tokenize } from './tokenizer.ts' import type { ToolDocument } from './types.ts' /** Minimal schema projection supplied by `ctx.tools.schemas()`. */ export interface CatalogToolSchema { name: string description: string parameters: Record } /** * Build a searchable document without generated aliases or inferred capabilities. * @param schema - Model-facing schema read from the live DSH tool registry. * @returns Tokenized deterministic fields used by Exact and BM25F retrieval. */ export function buildToolDocument(schema: CatalogToolSchema): ToolDocument { const parameterNames: string[] = [] const parameterDescriptions: string[] = [] collectSchemaText(schema.parameters, parameterNames, parameterDescriptions) return { name: schema.name, normalizedName: normalizeIdentifier(schema.name), description: schema.description, fields: { name: tokenize(schema.name), description: tokenize(schema.description), parameterName: parameterNames.flatMap(tokenize), parameterDescription: parameterDescriptions.flatMap(tokenize), }, } } /** Recursively collect only text that is explicitly present in the input schema. */ function collectSchemaText(value: unknown, names: string[], descriptions: string[]): void { if (Array.isArray(value)) { for (const item of value) collectSchemaText(item, names, descriptions) return } if (value === null || typeof value !== 'object') return for (const [key, child] of Object.entries(value)) { if (key === 'properties' && child !== null && typeof child === 'object' && !Array.isArray(child)) { for (const [propertyName, propertySchema] of Object.entries(child)) { names.push(propertyName) collectSchemaText(propertySchema, names, descriptions) } continue } if ((key === 'description' || key === 'title') && typeof child === 'string') { descriptions.push(child) continue } if (key === 'enum' && Array.isArray(child)) { for (const literal of child) { if (typeof literal === 'string' || typeof literal === 'number') descriptions.push(String(literal)) } continue } collectSchemaText(child, names, descriptions) } }