feat(fusion_accounting_ai): bank_rec_prompt for AI re-rank step
Provider-agnostic system + user prompt builder for the confidence scoring pipeline's Pass 3 (AI re-rank). Output contract is JSON with "ranked" array; works with OpenAI, Claude, and local OpenAI-compatible servers (LM Studio, Ollama). Made-with: Cursor
This commit is contained in:
@@ -9,3 +9,4 @@ from . import test_reconcile_engine_unit
|
||||
from . import test_reconcile_engine_property
|
||||
from . import test_factories
|
||||
from . import test_reconcile_engine_integration
|
||||
from . import test_bank_rec_prompt
|
||||
|
||||
92
fusion_accounting_bank_rec/tests/test_bank_rec_prompt.py
Normal file
92
fusion_accounting_bank_rec/tests/test_bank_rec_prompt.py
Normal file
@@ -0,0 +1,92 @@
|
||||
"""Smoke tests for bank_rec_prompt module."""
|
||||
|
||||
from odoo.tests.common import TransactionCase, tagged
|
||||
from odoo.addons.fusion_accounting_ai.services.prompts.bank_rec_prompt import (
|
||||
SYSTEM_PROMPT,
|
||||
build_prompt,
|
||||
)
|
||||
from odoo.addons.fusion_accounting_bank_rec.services.confidence_scoring import (
|
||||
ScoredCandidate,
|
||||
)
|
||||
from . import _factories as f
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestBankRecPrompt(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.partner = self.env['res.partner'].create({'name': 'Prompt Test Partner'})
|
||||
self.bank_line = f.make_bank_line(
|
||||
self.env,
|
||||
amount=1847.50,
|
||||
partner=self.partner,
|
||||
memo='RBC ETF DEP REF 4831',
|
||||
)
|
||||
self.scored = [
|
||||
ScoredCandidate(
|
||||
candidate_id=101,
|
||||
confidence=0.92,
|
||||
reasoning='Exact amount match',
|
||||
score_amount_match=1.0,
|
||||
score_partner_pattern=0.5,
|
||||
score_precedent_similarity=0.85,
|
||||
),
|
||||
ScoredCandidate(
|
||||
candidate_id=102,
|
||||
confidence=0.71,
|
||||
reasoning='Close amount',
|
||||
score_amount_match=0.95,
|
||||
score_partner_pattern=0.5,
|
||||
score_precedent_similarity=0.6,
|
||||
),
|
||||
]
|
||||
|
||||
def test_system_prompt_requires_json_output(self):
|
||||
self.assertIn('JSON', SYSTEM_PROMPT)
|
||||
self.assertIn('"ranked"', SYSTEM_PROMPT)
|
||||
|
||||
def test_build_prompt_returns_tuple(self):
|
||||
result = build_prompt(self.bank_line, self.scored)
|
||||
self.assertEqual(len(result), 2)
|
||||
system, user = result
|
||||
self.assertIsInstance(system, str)
|
||||
self.assertIsInstance(user, str)
|
||||
|
||||
def test_user_prompt_includes_bank_line_details(self):
|
||||
_, user = build_prompt(self.bank_line, self.scored)
|
||||
self.assertIn('1847.5', user)
|
||||
self.assertIn('RBC ETF DEP REF 4831', user)
|
||||
self.assertIn('Prompt Test Partner', user)
|
||||
|
||||
def test_user_prompt_includes_all_candidates(self):
|
||||
_, user = build_prompt(self.bank_line, self.scored)
|
||||
self.assertIn('candidate_id=101', user)
|
||||
self.assertIn('candidate_id=102', user)
|
||||
|
||||
def test_user_prompt_omits_pattern_section_when_none(self):
|
||||
_, user = build_prompt(self.bank_line, self.scored, pattern=None)
|
||||
self.assertNotIn('PARTNER PATTERN', user)
|
||||
|
||||
def test_user_prompt_includes_pattern_section_when_provided(self):
|
||||
pattern = f.make_pattern(self.env, partner=self.partner, reconcile_count=15)
|
||||
_, user = build_prompt(self.bank_line, self.scored, pattern=pattern)
|
||||
self.assertIn('PARTNER PATTERN', user)
|
||||
self.assertIn('15', user)
|
||||
|
||||
def test_user_prompt_includes_precedents_when_provided(self):
|
||||
from odoo.addons.fusion_accounting_bank_rec.services.precedent_lookup import (
|
||||
PrecedentMatch,
|
||||
)
|
||||
precedents = [
|
||||
PrecedentMatch(
|
||||
precedent_id=1,
|
||||
amount=1847.50,
|
||||
memo_tokens='RBC,ETF',
|
||||
matched_move_line_count=1,
|
||||
similarity_score=0.95,
|
||||
),
|
||||
]
|
||||
_, user = build_prompt(self.bank_line, self.scored, precedents=precedents)
|
||||
self.assertIn('RECENT PRECEDENTS', user)
|
||||
self.assertIn('0.95', user)
|
||||
Reference in New Issue
Block a user