Isaac Quarenta commited on
Commit
704a45e
·
1 Parent(s): 99cf062

fix: COT recebe contexto completo - aumentar limites de truncamento

Browse files

- thinking_engine.py: STM 25→40 msgs, 300→500 chars, listen 30→50, 200→400 chars
- thinking_engine.py: LSTM summary 600→1000, subtopics 8→12, questions 3→5
- thinking_engine.py: max_tokens COT output 2000→3000, retry 500→1000
- api.py: context_history 15→25 msgs, thinking engine raw STM 30→50
- unified_context.py: defaults 10/4000 → 20/6000
- context_builder.py: budget total 8000→12000, reply 800→1200, STM 4000→6000

modules/api.py CHANGED
@@ -2506,8 +2506,8 @@ class AkiraAPI:
2506
  # Isso mantém isolamento mas permite acesso a referências importantes
2507
 
2508
  if reply_to_bot:
2509
- # BASE: Carregar últimas 15 mensagens (contexto imediato expandido)
2510
- base_msgs = list(unified_context.stm_messages[-15:])
2511
  context_history_base = []
2512
 
2513
  last_base_user_author = None # ✅ track last user author for assistant tagging
@@ -2633,11 +2633,11 @@ class AkiraAPI:
2633
  'quem', 'isso', 'isso', 'muito', 'bem', 'aqui', 'fazer',
2634
  'porque', 'então', 'porque', 'então'}
2635
 
2636
- stm_messages = list(unified_context.stm_messages[-15:]) # Últimas 15 msgs
2637
 
2638
- # Adiciona msgs relevantes de janela maior (até -40) se tiverem keywords em comum
2639
- if len(unified_context.stm_messages) > 15:
2640
- older_msgs = unified_context.stm_messages[-40:-15]
2641
  for omsg in older_msgs:
2642
  omsg_keywords = set(re.findall(r'\b([a-záéíóúâêãõç]{4,})\b', omsg.content.lower()))
2643
  overlap = msg_keywords & omsg_keywords
@@ -2842,10 +2842,10 @@ class AkiraAPI:
2842
  # 🔴 FIX #4: ENRIQUECER CONTEXTO PARA THINKINGENGINE
2843
  # Motivo: context_history é truncado para replies ao bot
2844
  # Solução: Usar raw stm_messages para o ThinkingEngine, não context_history
2845
- historico_para_thinking = context_history[-30:] if context_history else []
2846
  if unified_context and unified_context.stm_messages:
2847
  # Usa raw STM messages (full, não truncado) formatado para o thinking engine
2848
- raw_msgs = list(unified_context.stm_messages[-30:])
2849
  thinking_formatted = []
2850
  for msg in raw_msgs:
2851
  content = msg.content
 
2506
  # Isso mantém isolamento mas permite acesso a referências importantes
2507
 
2508
  if reply_to_bot:
2509
+ # BASE: Carregar últimas 25 mensagens (contexto imediato expandido)
2510
+ base_msgs = list(unified_context.stm_messages[-25:])
2511
  context_history_base = []
2512
 
2513
  last_base_user_author = None # ✅ track last user author for assistant tagging
 
2633
  'quem', 'isso', 'isso', 'muito', 'bem', 'aqui', 'fazer',
2634
  'porque', 'então', 'porque', 'então'}
2635
 
2636
+ stm_messages = list(unified_context.stm_messages[-25:]) # Últimas 25 msgs
2637
 
2638
+ # Adiciona msgs relevantes de janela maior (até -50) se tiverem keywords em comum
2639
+ if len(unified_context.stm_messages) > 25:
2640
+ older_msgs = unified_context.stm_messages[-50:-25]
2641
  for omsg in older_msgs:
2642
  omsg_keywords = set(re.findall(r'\b([a-záéíóúâêãõç]{4,})\b', omsg.content.lower()))
2643
  overlap = msg_keywords & omsg_keywords
 
2842
  # 🔴 FIX #4: ENRIQUECER CONTEXTO PARA THINKINGENGINE
2843
  # Motivo: context_history é truncado para replies ao bot
2844
  # Solução: Usar raw stm_messages para o ThinkingEngine, não context_history
2845
+ historico_para_thinking = context_history[-50:] if context_history else []
2846
  if unified_context and unified_context.stm_messages:
2847
  # Usa raw STM messages (full, não truncado) formatado para o thinking engine
2848
+ raw_msgs = list(unified_context.stm_messages[-50:])
2849
  thinking_formatted = []
2850
  for msg in raw_msgs:
2851
  content = msg.content
modules/context_builder.py CHANGED
@@ -55,10 +55,10 @@ logger = logging.getLogger(__name__)
55
 
56
  # Token budgets para diferentes componentes
57
  TOKEN_BUDGET_SYSTEM: int = 1500
58
- TOKEN_BUDGET_REPLY: int = 800 # Para contexto de reply
59
- TOKEN_BUDGET_SHORT_TERM: int = 4000 # Para memória de curto prazo
60
- TOKEN_BUDGET_VECTOR: int = 1000 # Para memória vetorial
61
- TOKEN_BUDGET_TOTAL: int = 8000 # Total disponível para contexto
62
 
63
  # Limiares para perguntas curtas
64
  SHORT_QUESTION_THRESHOLD: int = 5 # palavras
 
55
 
56
  # Token budgets para diferentes componentes
57
  TOKEN_BUDGET_SYSTEM: int = 1500
58
+ TOKEN_BUDGET_REPLY: int = 1200 # Para contexto de reply
59
+ TOKEN_BUDGET_SHORT_TERM: int = 6000 # Para memória de curto prazo
60
+ TOKEN_BUDGET_VECTOR: int = 1500 # Para memória vetorial
61
+ TOKEN_BUDGET_TOTAL: int = 12000 # Total disponível para contexto
62
 
63
  # Limiares para perguntas curtas
64
  SHORT_QUESTION_THRESHOLD: int = 5 # palavras
modules/thinking_engine.py CHANGED
@@ -262,14 +262,14 @@ class ThinkingEngine:
262
  sys_prompt += "\n<LISTEN_ENGINE_CONTEXT>\n"
263
  sys_prompt += " [FONTE: Mensagens observadas passivamente no grupo — NÃO são pedidos à Kiami]\n"
264
  # Pegar as últimas 30 mensagens do grupo para contexto mais amplo
265
- for obs in listen_context[-30:]:
266
  if isinstance(obs, dict):
267
  autor = obs.get('author', obs.get('pushName', 'Desconhecido'))
268
  texto = obs.get('body', obs.get('content', obs.get('mensagem', '')))
269
  if texto:
270
- sys_prompt += f" [{autor}]: {str(texto)[:200]}\n"
271
  elif isinstance(obs, str):
272
- sys_prompt += f" {obs[:200]}\n"
273
  sys_prompt += "</LISTEN_ENGINE_CONTEXT>\n"
274
 
275
  # ================================================================
@@ -278,14 +278,14 @@ class ThinkingEngine:
278
  if historico_recente and len(historico_recente) > 0:
279
  sys_prompt += "\n<SHORT_TERM_MEMORY>\n"
280
  sys_prompt += " [FONTE: Histórico recente da conversa DIRETA com a Kiami]\n"
281
- for msg in historico_recente[-25:]:
282
  if isinstance(msg, dict):
283
  role = msg.get('role', 'user')
284
  content = msg.get('content', '')
285
  prefix = f" [KIAMIA]" if role == 'assistant' else f" [{usuario}]"
286
- sys_prompt += f"{prefix}: {str(content)[:300]}\n"
287
  else:
288
- sys_prompt += f" {str(msg)[:300]}\n"
289
  sys_prompt += "</SHORT_TERM_MEMORY>\n"
290
 
291
  # ================================================================
@@ -299,18 +299,18 @@ class ThinkingEngine:
299
  if contexto_lstm.get('interaction_pattern'):
300
  sys_prompt += f" [VERIFICADO] Padrão de interação: {contexto_lstm['interaction_pattern']}\n"
301
  if contexto_lstm.get('unanswered_questions'):
302
- perguntas = contexto_lstm['unanswered_questions'][:3]
303
  sys_prompt += f" [VERIFICADO] Perguntas pendentes sem resposta: {', '.join(perguntas)}\n"
304
  if contexto_lstm.get('subtopicas'):
305
- sys_prompt += f" [VERIFICADO] Subtópicos abordados: {', '.join(contexto_lstm['subtopicas'][:8])}\n"
306
  if contexto_lstm.get('emotion_history'):
307
  sys_prompt += f" [VERIFICADO] Histórico emocional: {contexto_lstm['emotion_history']}\n"
308
  if contexto_lstm.get('summary'):
309
- sys_prompt += f" [RESUMO LSTM]: {str(contexto_lstm['summary'])[:600]}\n"
310
  if contexto_lstm.get('assumed_knowledge'):
311
- sys_prompt += f" [VERIFICADO] Conhecimento presumido do utilizador: {', '.join(contexto_lstm['assumed_knowledge'][:5])}\n"
312
  if contexto_lstm.get('conversation_path'):
313
- sys_prompt += f" [VERIFICADO] Caminho da conversa: {' → '.join(contexto_lstm['conversation_path'][-5:])}\n"
314
  sys_prompt += "</LONG_TERM_MEMORY>\n"
315
 
316
  # ================================================================
@@ -321,7 +321,7 @@ class ThinkingEngine:
321
  sys_prompt += " [FONTE: Perfil psicológico e comportamental do utilizador — dados inferidos ao longo do tempo]\n"
322
  for key, val in persona_context.items():
323
  if val and key not in ('id', 'numero', 'timestamp'):
324
- sys_prompt += f" [PERFIL] {key}: {str(val)[:250]}\n"
325
  sys_prompt += "</USER_PERSONA>\n"
326
 
327
  # ================================================================
@@ -493,7 +493,7 @@ class ThinkingEngine:
493
  system_prompt=sys_prompt,
494
  context_history=[],
495
  user_prompt=mensagem,
496
- max_tokens=2000
497
  )
498
 
499
  # Se OpenRouter retornou None (429 rate limit), tenta com próxima conta
@@ -517,7 +517,7 @@ class ThinkingEngine:
517
  system_prompt=sys_prompt,
518
  context_history=[],
519
  user_prompt=mensagem,
520
- max_tokens=500
521
  )
522
  if thought:
523
  logger.info(f"✅ CoT gerado com sucesso na conta: {current_account}")
@@ -533,7 +533,7 @@ class ThinkingEngine:
533
  system_prompt=sys_prompt,
534
  context_history=[],
535
  user_prompt=mensagem,
536
- max_tokens=2000
537
  )
538
  if thought:
539
  logger.debug("🧠 CoT Dinâmico gerado via ToRouter (fallback)")
@@ -547,7 +547,7 @@ class ThinkingEngine:
547
  system_prompt=sys_prompt,
548
  context_history=[],
549
  user_prompt=mensagem,
550
- max_tokens=2000
551
  )
552
  if thought:
553
  logger.debug("🧠 CoT Dinâmico gerado via Mistral (fallback)")
@@ -561,7 +561,7 @@ class ThinkingEngine:
561
  system_prompt=sys_prompt,
562
  context_history=[],
563
  user_prompt=mensagem,
564
- max_tokens=2000
565
  )
566
  if thought:
567
  logger.debug("🧠 CoT Dinâmico gerado via Gemini (fallback)")
 
262
  sys_prompt += "\n<LISTEN_ENGINE_CONTEXT>\n"
263
  sys_prompt += " [FONTE: Mensagens observadas passivamente no grupo — NÃO são pedidos à Kiami]\n"
264
  # Pegar as últimas 30 mensagens do grupo para contexto mais amplo
265
+ for obs in listen_context[-50:]:
266
  if isinstance(obs, dict):
267
  autor = obs.get('author', obs.get('pushName', 'Desconhecido'))
268
  texto = obs.get('body', obs.get('content', obs.get('mensagem', '')))
269
  if texto:
270
+ sys_prompt += f" [{autor}]: {str(texto)[:400]}\n"
271
  elif isinstance(obs, str):
272
+ sys_prompt += f" {obs[:400]}\n"
273
  sys_prompt += "</LISTEN_ENGINE_CONTEXT>\n"
274
 
275
  # ================================================================
 
278
  if historico_recente and len(historico_recente) > 0:
279
  sys_prompt += "\n<SHORT_TERM_MEMORY>\n"
280
  sys_prompt += " [FONTE: Histórico recente da conversa DIRETA com a Kiami]\n"
281
+ for msg in historico_recente[-40:]:
282
  if isinstance(msg, dict):
283
  role = msg.get('role', 'user')
284
  content = msg.get('content', '')
285
  prefix = f" [KIAMIA]" if role == 'assistant' else f" [{usuario}]"
286
+ sys_prompt += f"{prefix}: {str(content)[:500]}\n"
287
  else:
288
+ sys_prompt += f" {str(msg)[:500]}\n"
289
  sys_prompt += "</SHORT_TERM_MEMORY>\n"
290
 
291
  # ================================================================
 
299
  if contexto_lstm.get('interaction_pattern'):
300
  sys_prompt += f" [VERIFICADO] Padrão de interação: {contexto_lstm['interaction_pattern']}\n"
301
  if contexto_lstm.get('unanswered_questions'):
302
+ perguntas = contexto_lstm['unanswered_questions'][:5]
303
  sys_prompt += f" [VERIFICADO] Perguntas pendentes sem resposta: {', '.join(perguntas)}\n"
304
  if contexto_lstm.get('subtopicas'):
305
+ sys_prompt += f" [VERIFICADO] Subtópicos abordados: {', '.join(contexto_lstm['subtopicas'][:12])}\n"
306
  if contexto_lstm.get('emotion_history'):
307
  sys_prompt += f" [VERIFICADO] Histórico emocional: {contexto_lstm['emotion_history']}\n"
308
  if contexto_lstm.get('summary'):
309
+ sys_prompt += f" [RESUMO LSTM]: {str(contexto_lstm['summary'])[:1000]}\n"
310
  if contexto_lstm.get('assumed_knowledge'):
311
+ sys_prompt += f" [VERIFICADO] Conhecimento presumido do utilizador: {', '.join(contexto_lstm['assumed_knowledge'][:8])}\n"
312
  if contexto_lstm.get('conversation_path'):
313
+ sys_prompt += f" [VERIFICADO] Caminho da conversa: {' → '.join(contexto_lstm['conversation_path'][-8:])}\n"
314
  sys_prompt += "</LONG_TERM_MEMORY>\n"
315
 
316
  # ================================================================
 
321
  sys_prompt += " [FONTE: Perfil psicológico e comportamental do utilizador — dados inferidos ao longo do tempo]\n"
322
  for key, val in persona_context.items():
323
  if val and key not in ('id', 'numero', 'timestamp'):
324
+ sys_prompt += f" [PERFIL] {key}: {str(val)[:400]}\n"
325
  sys_prompt += "</USER_PERSONA>\n"
326
 
327
  # ================================================================
 
493
  system_prompt=sys_prompt,
494
  context_history=[],
495
  user_prompt=mensagem,
496
+ max_tokens=3000
497
  )
498
 
499
  # Se OpenRouter retornou None (429 rate limit), tenta com próxima conta
 
517
  system_prompt=sys_prompt,
518
  context_history=[],
519
  user_prompt=mensagem,
520
+ max_tokens=1000
521
  )
522
  if thought:
523
  logger.info(f"✅ CoT gerado com sucesso na conta: {current_account}")
 
533
  system_prompt=sys_prompt,
534
  context_history=[],
535
  user_prompt=mensagem,
536
+ max_tokens=3000
537
  )
538
  if thought:
539
  logger.debug("🧠 CoT Dinâmico gerado via ToRouter (fallback)")
 
547
  system_prompt=sys_prompt,
548
  context_history=[],
549
  user_prompt=mensagem,
550
+ max_tokens=3000
551
  )
552
  if thought:
553
  logger.debug("🧠 CoT Dinâmico gerado via Mistral (fallback)")
 
561
  system_prompt=sys_prompt,
562
  context_history=[],
563
  user_prompt=mensagem,
564
+ max_tokens=3000
565
  )
566
  if thought:
567
  logger.debug("🧠 CoT Dinâmico gerado via Gemini (fallback)")
modules/unified_context.py CHANGED
@@ -657,8 +657,8 @@ class ShortTermMemoryManager:
657
  conversation_id: str,
658
  include_replies: bool = True,
659
  prioritize_replies: bool = True,
660
- max_messages: int = 10,
661
- max_tokens: int = 4000
662
  ) -> List[MessageWithContext]:
663
  """
664
  Obtém contexto da STM de uma conversa.
@@ -856,8 +856,8 @@ class UnifiedContextBuilder:
856
  conversation_id,
857
  include_replies=True,
858
  prioritize_replies=True,
859
- max_messages=10,
860
- max_tokens=4000
861
  )
862
 
863
  # ===== 3. CALCULA TOKEN BUDGET =====
 
657
  conversation_id: str,
658
  include_replies: bool = True,
659
  prioritize_replies: bool = True,
660
+ max_messages: int = 20,
661
+ max_tokens: int = 6000
662
  ) -> List[MessageWithContext]:
663
  """
664
  Obtém contexto da STM de uma conversa.
 
856
  conversation_id,
857
  include_replies=True,
858
  prioritize_replies=True,
859
+ max_messages=20,
860
+ max_tokens=6000
861
  )
862
 
863
  # ===== 3. CALCULA TOKEN BUDGET =====