From 0aed4e06a231540b2109ad208017042434c4ba89 Mon Sep 17 00:00:00 2001 From: Anas Syed Date: Thu, 22 Jan 2026 20:32:13 +0000 Subject: [PATCH] remove validateAndRepairJson function and tests --- .../src/server/services/openrouter.ts | 118 ------------------ .../services/pdf-skills-validation.test.ts | 8 -- .../src/server/services/pdf-tailoring.test.ts | 7 -- orchestrator/src/server/services/pdf.ts | 17 +-- 4 files changed, 1 insertion(+), 149 deletions(-) diff --git a/orchestrator/src/server/services/openrouter.ts b/orchestrator/src/server/services/openrouter.ts index cb5b287..cb52fea 100644 --- a/orchestrator/src/server/services/openrouter.ts +++ b/orchestrator/src/server/services/openrouter.ts @@ -2,9 +2,6 @@ * Shared OpenRouter API helper for structured JSON responses. */ -import { z } from 'zod'; -import { getSetting } from '../repositories/settings.js'; - const OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions'; export interface JsonSchemaDefinition { @@ -170,118 +167,3 @@ export function parseJsonContent(content: string, jobId?: string): T { function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } - -/** - * Validate JSON against a Zod schema and repair with AI if invalid. - * - * @param data - The JSON object to validate - * @param schema - Zod schema to validate against - * @param context - Optional context for logging (e.g., job ID) - * @returns The validated (and possibly repaired) data - */ -export async function validateAndRepairJson( - data: unknown, - schema: z.ZodSchema, - context?: string -): Promise<{ success: true; data: T; repaired: boolean } | { success: false; error: string }> { - const label = context ?? 'unknown'; - - // First attempt: validate as-is - const result = schema.safeParse(data); - if (result.success) { - return { success: true, data: result.data, repaired: false }; - } - - // Validation failed - attempt AI repair - console.warn(`⚠️ [${label}] Schema validation failed, attempting AI repair...`); - - const errors = result.error.issues.map((issue: z.ZodIssue) => ({ - path: issue.path.join('.'), - message: issue.message, - code: issue.code, - })); - - console.warn(` Validation errors:`, errors.slice(0, 5)); // Log first 5 errors - - // Check if API key is available - if (!process.env.OPENROUTER_API_KEY) { - return { - success: false, - error: `Schema validation failed and no API key for repair: ${errors.map((e: { path: string; message: string }) => `${e.path}: ${e.message}`).join('; ')}` - }; - } - - const [overrideModel] = await Promise.all([getSetting('model')]); - const model = overrideModel || process.env.MODEL || 'openai/gpt-4o-mini'; - - const repairPrompt = buildRepairPrompt(data, errors); - - try { - const response = await fetch(OPENROUTER_API_URL, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`, - 'Content-Type': 'application/json', - 'HTTP-Referer': 'JobOps', - 'X-Title': 'JobOpsSchemaRepair', - }, - body: JSON.stringify({ - model, - messages: [{ role: 'user', content: repairPrompt }], - stream: false, - plugins: [{ id: 'response-healing' }], - }), - }); - - if (!response.ok) { - const errorBody = await response.text().catch(() => 'No error body'); - return { success: false, error: `AI repair request failed: ${response.status} - ${errorBody}` }; - } - - const responseData = await response.json(); - const content = responseData.choices?.[0]?.message?.content; - - if (!content) { - return { success: false, error: 'AI repair returned no content' }; - } - - // Parse the repaired JSON - const repaired = parseJsonContent(content, label); - - // Validate the repaired version - const repairedResult = schema.safeParse(repaired); - if (repairedResult.success) { - console.log(`✅ [${label}] AI successfully repaired the JSON`); - return { success: true, data: repairedResult.data, repaired: true }; - } - - // Still invalid after repair - const newErrors = repairedResult.error.issues.slice(0, 3).map((i: z.ZodIssue) => `${i.path.join('.')}: ${i.message}`).join('; '); - return { success: false, error: `AI repair did not fix all issues: ${newErrors}` }; - - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { success: false, error: `AI repair failed: ${message}` }; - } -} - -function buildRepairPrompt(data: unknown, errors: Array<{ path: string; message: string; code: string }>): string { - const errorList = errors.slice(0, 10).map(e => `- Path "${e.path}": ${e.message}`).join('\n'); - - return `You are fixing a JSON object that failed schema validation. - -VALIDATION ERRORS: -${errorList} - -ORIGINAL JSON (may be truncated): -${JSON.stringify(data, null, 2).slice(0, 15000)} - -INSTRUCTIONS: -1. Fix ONLY the validation errors listed above -2. Do NOT remove or modify data that isn't causing errors -3. For missing required fields, add them with sensible defaults (empty strings, empty arrays, etc.) -4. For type mismatches, convert to the correct type -5. Preserve all existing valid data - -Return ONLY the fixed JSON object, no explanation.`; -} diff --git a/orchestrator/src/server/services/pdf-skills-validation.test.ts b/orchestrator/src/server/services/pdf-skills-validation.test.ts index 0bac36e..6ca353e 100644 --- a/orchestrator/src/server/services/pdf-skills-validation.test.ts +++ b/orchestrator/src/server/services/pdf-skills-validation.test.ts @@ -61,14 +61,6 @@ vi.mock('./resumeProjects.js', () => ({ }) })); -vi.mock('./openrouter.js', () => ({ - validateAndRepairJson: vi.fn().mockImplementation(async (data: unknown) => ({ - success: true, - data, - repaired: false - })) -})); - vi.mock('child_process', () => ({ spawn: vi.fn().mockImplementation(() => ({ stdout: { on: vi.fn() }, diff --git a/orchestrator/src/server/services/pdf-tailoring.test.ts b/orchestrator/src/server/services/pdf-tailoring.test.ts index 8b6383f..df187fe 100644 --- a/orchestrator/src/server/services/pdf-tailoring.test.ts +++ b/orchestrator/src/server/services/pdf-tailoring.test.ts @@ -73,13 +73,6 @@ vi.mock('./resumeProjects.js', () => ({ }) })); -// Mock validateAndRepairJson to always return success (bypass validation in tests) -vi.mock('./openrouter.js', () => ({ - validateAndRepairJson: vi.fn().mockImplementation((data: unknown) => - Promise.resolve({ success: true, data, repaired: false }) - ), -})); - vi.mock('child_process', () => ({ spawn: vi.fn().mockImplementation(() => ({ stdout: { on: vi.fn() }, diff --git a/orchestrator/src/server/services/pdf.ts b/orchestrator/src/server/services/pdf.ts index ad50866..2037672 100644 --- a/orchestrator/src/server/services/pdf.ts +++ b/orchestrator/src/server/services/pdf.ts @@ -15,8 +15,6 @@ import { pickProjectIdsForJob } from './projectSelection.js'; import { extractProjectsFromProfile, resolveResumeProjectsSettings } from './resumeProjects.js'; import { getDataDir } from '../config/dataDir.js'; import { getProfile } from './profile.js'; -import { validateAndRepairJson } from './openrouter.js'; -import { resumeDataSchema } from '../../shared/rxresume-schema.js'; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -168,22 +166,9 @@ export async function generatePdf( console.warn(` ⚠️ Project visibility step failed for job ${jobId}:`, err); } - // Validate and repair the resume JSON before PDF generation - const validationResult = await validateAndRepairJson(baseResume, resumeDataSchema, `pdf-${jobId}`); - if (!validationResult.success) { - console.error(`❌ [Job ${jobId}] Resume validation failed: ${validationResult.error}`); - return { success: false, error: `Resume validation failed: ${validationResult.error}` }; - } - - if (validationResult.repaired) { - console.log(`🔧 [Job ${jobId}] Resume JSON was repaired by AI`); - } - - const validatedResume = validationResult.data; - // Write modified resume to temp file const tempResumePath = join(RESUME_GEN_DIR, `temp_resume_${jobId}.json`); - await writeFile(tempResumePath, JSON.stringify(validatedResume, null, 2)); + await writeFile(tempResumePath, JSON.stringify(baseResume, null, 2)); // Generate PDF using Python script - output directly to our data folder const outputFilename = `resume_${jobId}.pdf`;