feat(v2): normalize GLPI text before context/hash, add real ticket description
context.normalizeTicket now runs normalizeGlpiText on titulo, descricao (new field, sourced from glpi_tickets.content -- never fetched before), and every followup/task texto. buildAiContextText restructured into delimited sections (TITULO / DESCRICAO ORIGINAL / STATUS-TECNICO-GRUPO / FOLLOW-UPS / TAREFAS) instead of one flat string. hash.buildContextFingerprint now includes titulo/descricao and the normalized followup/task texto (previously only id/date/status), so: (a) the same content encoded differently (HTML vs escaped entities) produces the same hash, and (b) editing a followup's actual content (same id/date) is now detected as a real context change -- previously silently invisible to the hash. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d7650308a9
commit
db7a261a10
+31
-2
@@ -4,7 +4,7 @@ const { normalizeTicket, buildAiContextText, truncate } = require('./context');
|
||||
|
||||
function rawRow(overrides) {
|
||||
return Object.assign({
|
||||
id: '38611', titulo: ' Colocar etiqueta sala 03 ', status: '2', status_nome: 'Em atendimento',
|
||||
id: '38611', titulo: ' Colocar etiqueta sala 03 ', descricao: '<p>Descricao original do chamado</p>', status: '2', status_nome: 'Em atendimento',
|
||||
aberto_em: '2026-08-01 08:00:00', ultima_interacao_em: '2026-08-22 08:00:00',
|
||||
dias_aberto: '23', dias_sem_interacao: '2', sla_vencido: '1', sla_em_risco: '0', horas_ate_sla: null,
|
||||
prioridade: '3', urgencia: '3', impacto: '3', entidade: 'Matriz', categoria: 'Facilities',
|
||||
@@ -16,7 +16,7 @@ function rawRow(overrides) {
|
||||
test('normalizeTicket converte tipos e booleans 0/1', () => {
|
||||
const t = normalizeTicket(rawRow({}), { followups: [], tasks: [] });
|
||||
assert.equal(t.id, 38611);
|
||||
assert.equal(t.titulo, ' Colocar etiqueta sala 03 ');
|
||||
assert.equal(t.titulo, 'Colocar etiqueta sala 03');
|
||||
assert.equal(t.sla_vencido, true);
|
||||
assert.equal(t.sla_em_risco, false);
|
||||
assert.equal(t.sem_tecnico, true);
|
||||
@@ -24,6 +24,20 @@ test('normalizeTicket converte tipos e booleans 0/1', () => {
|
||||
assert.deepEqual(t.followups, []);
|
||||
});
|
||||
|
||||
test('normalizeTicket normaliza HTML da descricao', () => {
|
||||
const t = normalizeTicket(rawRow({}), { followups: [], tasks: [] });
|
||||
assert.equal(t.descricao, 'Descricao original do chamado');
|
||||
});
|
||||
|
||||
test('normalizeTicket normaliza HTML de followups e tarefas', () => {
|
||||
const t = normalizeTicket(rawRow({}), {
|
||||
followups: [{ id: 1, date: '2026-08-20', texto: '<p>Aguardando retorno</p>' }],
|
||||
tasks: [{ id: 1, date: '2026-08-19', status: 1, texto: '<p>Tarefa concluida</p>' }],
|
||||
});
|
||||
assert.equal(t.followups[0].texto, 'Aguardando retorno');
|
||||
assert.equal(t.tasks[0].texto, 'Tarefa concluida');
|
||||
});
|
||||
|
||||
test('truncate corta e adiciona reticencias', () => {
|
||||
const long = 'a'.repeat(50);
|
||||
assert.equal(truncate(long, 10), `${'a'.repeat(7)}...`);
|
||||
@@ -39,3 +53,18 @@ test('buildAiContextText respeita o orcamento de caracteres', () => {
|
||||
assert.ok(text.length <= 300);
|
||||
assert.ok(text.includes('#38611'));
|
||||
});
|
||||
|
||||
test('buildAiContextText tem secoes delimitadas: titulo, descricao, follow-ups, tarefas', () => {
|
||||
const t = normalizeTicket(rawRow({}), {
|
||||
followups: [{ id: 1, date: '2026-08-20', texto: 'Aguardando resposta' }],
|
||||
tasks: [{ id: 1, date: '2026-08-19', status: 1, texto: 'Tarefa feita' }],
|
||||
});
|
||||
const text = buildAiContextText(t, 4000);
|
||||
assert.ok(text.includes('TITULO'));
|
||||
assert.ok(text.includes('DESCRICAO ORIGINAL'));
|
||||
assert.ok(text.includes('Descricao original do chamado'));
|
||||
assert.ok(text.includes('FOLLOW-UPS'));
|
||||
assert.ok(text.includes('Aguardando resposta'));
|
||||
assert.ok(text.includes('TAREFAS'));
|
||||
assert.ok(text.includes('Tarefa feita'));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user