feat(v2): add safe AI fallback and cache/reanalysis decision
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c445e00fc5
commit
efba7792fa
@@ -0,0 +1,8 @@
|
|||||||
|
function needsReanalysis({ memory, currentHash, now }) {
|
||||||
|
if (!memory) return { needsAi: true, reason: 'no_cache' };
|
||||||
|
if (memory.last_context_hash !== currentHash) return { needsAi: true, reason: 'context_changed' };
|
||||||
|
if (memory.next_review_at != null && now >= memory.next_review_at) return { needsAi: true, reason: 'review_due' };
|
||||||
|
return { needsAi: false, reason: 'cache_valid' };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { needsReanalysis };
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
const { test } = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const { needsReanalysis } = require('./cache');
|
||||||
|
|
||||||
|
test('sem memoria previa, sempre precisa de IA', () => {
|
||||||
|
const result = needsReanalysis({ memory: null, currentHash: 'abc', now: 1000 });
|
||||||
|
assert.equal(result.needsAi, true);
|
||||||
|
assert.equal(result.reason, 'no_cache');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hash igual e sem next_review_at vencido usa cache', () => {
|
||||||
|
const memory = { last_context_hash: 'abc', next_review_at: null };
|
||||||
|
const result = needsReanalysis({ memory, currentHash: 'abc', now: 1000 });
|
||||||
|
assert.equal(result.needsAi, false);
|
||||||
|
assert.equal(result.reason, 'cache_valid');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hash diferente forca reavaliacao (mudanca significativa)', () => {
|
||||||
|
const memory = { last_context_hash: 'abc', next_review_at: null };
|
||||||
|
const result = needsReanalysis({ memory, currentHash: 'xyz', now: 1000 });
|
||||||
|
assert.equal(result.needsAi, true);
|
||||||
|
assert.equal(result.reason, 'context_changed');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('next_review_at vencido forca reavaliacao mesmo com hash igual', () => {
|
||||||
|
const memory = { last_context_hash: 'abc', next_review_at: 500 };
|
||||||
|
const result = needsReanalysis({ memory, currentHash: 'abc', now: 1000 });
|
||||||
|
assert.equal(result.needsAi, true);
|
||||||
|
assert.equal(result.reason, 'review_due');
|
||||||
|
});
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
function buildFallbackClassification(reason) {
|
||||||
|
return {
|
||||||
|
classification: 'ACTIONABLE_NOW',
|
||||||
|
actionable_today: true,
|
||||||
|
confidence: 0,
|
||||||
|
blocker_type: null,
|
||||||
|
waiting_for: null,
|
||||||
|
next_action: 'Revisar chamado manualmente',
|
||||||
|
suggested_action_type: 'manual_review',
|
||||||
|
business_risk: 'medium',
|
||||||
|
reason: `Fallback deterministico: ${reason}`,
|
||||||
|
evidence: [],
|
||||||
|
is_fallback: true,
|
||||||
|
fallback_reason: reason,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { buildFallbackClassification };
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
const { test } = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const { buildFallbackClassification } = require('./fallback');
|
||||||
|
|
||||||
|
test('fallback e sempre seguro e marcado como tal', () => {
|
||||||
|
const result = buildFallbackClassification('ai_timeout');
|
||||||
|
assert.equal(result.is_fallback, true);
|
||||||
|
assert.equal(result.fallback_reason, 'ai_timeout');
|
||||||
|
assert.equal(result.confidence, 0);
|
||||||
|
assert.equal(result.classification, 'ACTIONABLE_NOW');
|
||||||
|
assert.ok(result.reason.includes('Fallback'));
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user