fix(harness-f0): searchKnowledge cobre erro de RPC com erro de ensino (review final)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLrVxFCDjcRDCdWUSPftbZ
This commit is contained in:
Rafael Melgaço
2026-07-23 14:28:53 -03:00
co-authored by Claude Fable 5
parent c6e87050dd
commit ee1873dd46
2 changed files with 23 additions and 9 deletions
@@ -33,6 +33,21 @@ describe('searchKnowledge', () => {
expect(out.ok).toBe(false);
if (!out.ok) expect(out.error.code).toBe('knowledge_unavailable');
});
it('erro de RPC (pool.query) vira erro de ENSINO, nunca exceção', async () => {
const query = vi.fn().mockRejectedValue(new Error('rpc_error: pgvector dimension mismatch'));
const embed = vi.fn().mockResolvedValue({ embedding: [0.1, 0.2], promptTokens: 3, model: 'm' });
const out = await searchKnowledge(
{ query } as unknown as pg.Pool,
{ organizationId: 'org1', kbVersionId: 'kb1', query: 'frete', topK: 5, threshold: 0.72 },
{ embed },
);
expect(out.ok).toBe(false);
if (!out.ok) {
expect(out.error.code).toBe('knowledge_unavailable');
expect(out.error.message).toContain('indisponível');
}
});
});
describe('citationsFromHits', () => {
+8 -9
View File
@@ -29,9 +29,15 @@ export async function searchKnowledge(
deps?: { embed?: typeof embedText },
): Promise<SearchKnowledgeResult> {
const embed = deps?.embed ?? embedText;
let embedding: number[];
try {
({ embedding } = await embed(args.query, { organizationId: args.organizationId }));
const { embedding } = await embed(args.query, { organizationId: args.organizationId });
const vec = `[${embedding.join(',')}]`;
const { rows } = await pool.query<KnowledgeHit>(
`select chunk_id, knowledge_source_id, content, similarity, metadata
from retrieve_top_k_chunks($1, $2, $3::vector, $4, $5)`,
[args.organizationId, args.kbVersionId, vec, args.topK, args.threshold],
);
return { ok: true, results: rows };
} catch {
return {
ok: false,
@@ -41,13 +47,6 @@ export async function searchKnowledge(
},
};
}
const vec = `[${embedding.join(',')}]`;
const { rows } = await pool.query<KnowledgeHit>(
`select chunk_id, knowledge_source_id, content, similarity, metadata
from retrieve_top_k_chunks($1, $2, $3::vector, $4, $5)`,
[args.organizationId, args.kbVersionId, vec, args.topK, args.threshold],
);
return { ok: true, results: rows };
}
/** Shape que a UI do inbox já renderiza (CitationsPanel — lib/ai/citations/types). */