File size: 2,929 Bytes
f56a29b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | import { parseJsonResponse } from '@/lib/generation/json-repair';
import { PROMPT_IDS, buildPrompt } from '@/lib/prompts';
import type { AICallFn } from '@/lib/generation/pipeline-types';
import { createLogger } from '@/lib/logger';
const log = createLogger('SearchQueryBuilder');
const TAVILY_SOFT_MAX_QUERY_LENGTH = 350;
export const SEARCH_QUERY_REWRITE_EXCERPT_LENGTH = 7000;
interface SearchQueryRewriteResponse {
query: string;
}
export interface SearchQueryBuildResult {
query: string;
rewriteAttempted: boolean;
rawRequirementLength: number;
finalQueryLength: number;
hasPdfContext: boolean;
}
function normalizeSearchRequirement(requirement: string): string {
return requirement.replace(/\s+/g, ' ').trim();
}
function normalizePdfExcerpt(pdfText?: string): string {
if (!pdfText) {
return '';
}
return pdfText.replace(/\s+/g, ' ').trim().slice(0, SEARCH_QUERY_REWRITE_EXCERPT_LENGTH);
}
function shouldRewriteSearchQuery(
normalizedRequirement: string,
normalizedPdfExcerpt: string,
): boolean {
return normalizedRequirement.length > 400 || Boolean(normalizedPdfExcerpt);
}
export async function buildSearchQuery(
requirement: string,
pdfText: string | undefined,
aiCall?: AICallFn,
): Promise<SearchQueryBuildResult> {
const normalizedRequirement = normalizeSearchRequirement(requirement);
const pdfExcerpt = normalizePdfExcerpt(pdfText);
const hasPdfContext = Boolean(pdfExcerpt);
const rewriteAttempted = shouldRewriteSearchQuery(normalizedRequirement, pdfExcerpt);
const fallback = {
query: normalizedRequirement,
rewriteAttempted,
rawRequirementLength: normalizedRequirement.length,
finalQueryLength: normalizedRequirement.length,
hasPdfContext,
} satisfies SearchQueryBuildResult;
if (!normalizedRequirement || !rewriteAttempted) {
return fallback;
}
if (!aiCall) {
log.warn('Query rewrite AI call unavailable, falling back to raw requirement');
return fallback;
}
const prompts = buildPrompt(PROMPT_IDS.WEB_SEARCH_QUERY_REWRITE, {
requirement: normalizedRequirement,
pdfExcerpt: pdfExcerpt || 'None',
});
if (!prompts) {
log.warn('Query rewrite prompt not found, falling back to raw requirement');
return fallback;
}
try {
const response = await aiCall(prompts.system, prompts.user);
const parsed = parseJsonResponse<SearchQueryRewriteResponse>(response);
const rewrittenQuery = normalizeSearchRequirement(parsed?.query || '').slice(
0,
TAVILY_SOFT_MAX_QUERY_LENGTH,
);
if (!rewrittenQuery) {
log.warn('Query rewrite returned empty output, falling back to raw requirement');
return fallback;
}
return {
...fallback,
query: rewrittenQuery,
finalQueryLength: rewrittenQuery.length,
};
} catch (error) {
log.warn('Query rewrite failed, falling back to raw requirement:', error);
return fallback;
}
}
|