Spaces:
Running
Running
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 +8 -8
- modules/context_builder.py +4 -4
- modules/thinking_engine.py +17 -17
- modules/unified_context.py +4 -4
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
|
| 2510 |
-
base_msgs = list(unified_context.stm_messages[-
|
| 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[-
|
| 2637 |
|
| 2638 |
-
# Adiciona msgs relevantes de janela maior (até -
|
| 2639 |
-
if len(unified_context.stm_messages) >
|
| 2640 |
-
older_msgs = unified_context.stm_messages[-
|
| 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[-
|
| 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[-
|
| 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 =
|
| 59 |
-
TOKEN_BUDGET_SHORT_TERM: int =
|
| 60 |
-
TOKEN_BUDGET_VECTOR: int =
|
| 61 |
-
TOKEN_BUDGET_TOTAL: int =
|
| 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[-
|
| 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)[:
|
| 271 |
elif isinstance(obs, str):
|
| 272 |
-
sys_prompt += f" {obs[:
|
| 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[-
|
| 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)[:
|
| 287 |
else:
|
| 288 |
-
sys_prompt += f" {str(msg)[:
|
| 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'][:
|
| 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'][:
|
| 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'])[:
|
| 310 |
if contexto_lstm.get('assumed_knowledge'):
|
| 311 |
-
sys_prompt += f" [VERIFICADO] Conhecimento presumido do utilizador: {', '.join(contexto_lstm['assumed_knowledge'][:
|
| 312 |
if contexto_lstm.get('conversation_path'):
|
| 313 |
-
sys_prompt += f" [VERIFICADO] Caminho da conversa: {' → '.join(contexto_lstm['conversation_path'][-
|
| 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)[:
|
| 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=
|
| 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=
|
| 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=
|
| 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=
|
| 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=
|
| 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 =
|
| 661 |
-
max_tokens: int =
|
| 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=
|
| 860 |
-
max_tokens=
|
| 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 =====
|