diff --git a/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/.env.example b/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/.env.example new file mode 100644 index 0000000..e93ecca --- /dev/null +++ b/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/.env.example @@ -0,0 +1,195 @@ +############################################################################### +# AI AGENT PLATFORM - CONFIGURAÇÃO ÚNICA +# Este arquivo é lido por Pydantic Settings no framework e no backend template. +############################################################################### + +APP_NAME=ai-agent-template +APP_ENV=local +LOG_LEVEL=INFO +API_HOST=0.0.0.0 +API_PORT=8000 +CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173 + +############################################################################### +# LLM - OCI Generative AI como provider principal +############################################################################### +# Opções: mock, oci_openai, oci_sdk, openai_compatible +LLM_PROVIDER=oci_openai +LLM_TEMPERATURE=0.2 +LLM_MAX_TOKENS=2048 +LLM_TIMEOUT_SECONDS=120 + +# OCI OpenAI-compatible endpoint +OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/openai/v1 +OCI_GENAI_MODEL=openai.gpt-4.1 +OCI_GENAI_API_KEY=sk-ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6 +OCI_GENAI_PROJECT_OCID= + +# OCI SDK / signer / profiles +OCI_CONFIG_FILE=~/.oci/config +OCI_PROFILE=DEFAULT +OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +OCI_REGION=us-chicago-1 + +############################################################################### +# Persistência +############################################################################### +# Opções: memory, autonomous, mongodb +SESSION_REPOSITORY_PROVIDER=sqlite +MEMORY_REPOSITORY_PROVIDER=sqlite +CHECKPOINT_REPOSITORY_PROVIDER=sqlite +SQLITE_DB_PATH=./data/agent_framework.db + +# Autonomous Database +ADB_USER=admin +ADB_PASSWORD=fjhsdf04954hf +ADB_DSN=oradb23aidev_high +ADB_WALLET_LOCATION=/ORACLE/DEFAULT/Wallet_ORADB23aiDev +ADB_WALLET_PASSWORD=fjhsdf04954hf +ADB_TABLE_PREFIX=AGENTFW + +# MongoDB - também pode representar Autonomous usando API compatível com Mongo, se habilitada no ambiente +MONGODB_URI=mongodb://mongo:mongopassword@localhost:27017 +MONGODB_DATABASE=agent_platform + +# Redis +REDIS_URL=redis://localhost:6379/0 +ENABLE_REDIS_CACHE=false + +############################################################################### +# RAG / Vector / Graph +############################################################################### +VECTOR_STORE_PROVIDER=sqlite +GRAPH_STORE_PROVIDER=sqlite +RAG_TOP_K=5 +EMBEDDING_PROVIDER=mock +OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 +RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json + +############################################################################### +# Observabilidade +############################################################################### +ENABLE_LANGFUSE=true +LANGFUSE_TRACE_MODE=compact # Opcional: verbose, compact +LANGFUSE_PUBLIC_KEY=pk-lf-2f9da109-5b0f-4c78-b61d-9598ed787eba +LANGFUSE_SECRET_KEY=sk-lf-a4cb0cdd-f2ea-4468-9911-cebeb91ba944 +LANGFUSE_HOST=http://localhost:3005 +ENABLE_OTEL=false +OTEL_EXPORTER_OTLP_ENDPOINT= +OTEL_SERVICE_NAME=ai-agent-template +ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=true + +############################################################################### +# Analytics / Observer corporativo +############################################################################### +# Quando true, AgentObserver publica eventos IC.*, NOC.* e GRL.* nos providers abaixo. +ENABLE_ANALYTICS=false +# Providers aceitos: oci_streaming,pubsub,noop +ANALYTICS_PROVIDERS=pubsub +# Compatibilidade FIRST/TIM: pode informar AGENT_PUBSUB_TOPIC diretamente. +AGENT_PUBSUB_TOPIC= +GCP_PUBSUB_TOPIC_PATH= +GCP_PROJECT_ID= +GCP_PUBSUB_TOPIC= +GCP_PUBSUB_TIMEOUT_SECONDS=30 +# Credencial GCP segue padrão Google: +# GOOGLE_APPLICATION_CREDENTIALS=/secrets/gcp-service-account.json + +############################################################################### +# OCI Streaming +############################################################################### +ENABLE_OCI_STREAMING=false +OCI_STREAM_ENDPOINT= +OCI_STREAM_OCID= +OCI_STREAM_PARTITION_KEY=agent-events + +############################################################################### +# Guardrails, Judges, Supervisor +############################################################################### +ENABLE_INPUT_GUARDRAILS=true +ENABLE_OUTPUT_GUARDRAILS=true +ENABLE_JUDGES=true +ENABLE_SUPERVISOR=true +ENABLE_OUTPUT_SUPERVISOR=true +ENABLE_PARALLEL_GUARDRAILS=true +GUARDRAILS_FAIL_FAST=true +OUTPUT_SUPERVISOR_MAX_RETRIES=3 +GUARDRAILS_CONFIG_PATH=./config/guardrails.yaml +JUDGES_CONFIG_PATH=./config/judges.yaml +PROMPT_POLICY_PATH=./config/prompt_policy.yaml + +############################################################################### +# Gateway de canais +############################################################################### +DEFAULT_CHANNEL=web +# embedded = backend may parse simple/native channel payloads. +# external = backend only accepts GatewayRequest normalized by an external Channel Gateway. +FRAMEWORK_CHANNEL_INPUT_MODE=embedded +ENABLE_VOICE_ADAPTER=true +ENABLE_WHATSAPP_ADAPTER=true +ENABLE_TEXT_ADAPTER=true + +################################################# +# ENTERPRISE ROUTING +################################################# +# Arquivo YAML com intents, keywords, políticas de estado e fallback. +ROUTING_CONFIG_PATH=./config/routing.yaml +# true = usa LLM para classificar quando keywords/estado não resolverem. +# Em produção, costuma ser útil; em desenvolvimento, false evita custo e latência. +ENABLE_LLM_ROUTER=true + +############################################################################### +# MCP / Tools +############################################################################### +ENABLE_MCP_TOOLS=true +MCP_SERVERS_CONFIG_PATH=./config/mcp_servers.yaml +TOOLS_CONFIG_PATH=./config/tools.yaml +TOOL_POLICIES_PATH=./config/tool_policies.yaml +MCP_TOOL_TIMEOUT_SECONDS=30 + +# router = EnterpriseRouter seleciona um agente; supervisor = pode acionar múltiplos agentes +ROUTING_MODE=router + +# Usage/cost accounting +USAGE_REPOSITORY_PROVIDER=sqlite +IDENTITY_CONFIG_PATH=./config/identity.yaml +MCP_PARAMETER_MAPPING_PATH=./config/mcp_parameter_mapping.yaml + +# ----------------------------------------------------------------------------- +# ConversationSummaryMemory / compressão de contexto conversacional +# ----------------------------------------------------------------------------- +ENABLE_CONVERSATION_SUMMARY_MEMORY=true +MEMORY_CONTEXT_STRATEGY=summary +MEMORY_HISTORY_LIMIT=80 +MEMORY_RECENT_MESSAGES_LIMIT=8 +MEMORY_SUMMARY_TRIGGER_MESSAGES=20 +MEMORY_MAX_SUMMARY_CHARS=6000 +MEMORY_SUMMARY_USE_LLM=true +MEMORY_INJECT_RECENT_MESSAGES=true +MEMORY_INJECT_SUMMARY=true + +############################################################################### +# MCP Gateway +############################################################################### +# true = framework routes tool calls to the dedicated MCP Gateway. +# false = framework calls MCP servers directly from mcp_servers.yaml. +MCP_GATEWAY_ENABLED=true +MCP_GATEWAY_URL=http://localhost:8300 +MCP_GATEWAY_TIMEOUT_SECONDS=60 +# MCP_GATEWAY_TOKEN= +MCP_GATEWAY_AGENT_ID=telecom_contas +MCP_GATEWAY_TENANT_ID=default + +############################################################################### +# LONG-TERM MEMORY +############################################################################### +ENABLE_LONG_TERM_MEMORY=true +LONG_TERM_MEMORY_PROVIDER=sqlite +LONG_TERM_MEMORY_SQLITE_PATH=./data/agent_framework.db +LONG_TERM_MEMORY_TABLE=agentfw_long_term_memory +# For Autonomous/Oracle, defaults to ${ADB_TABLE_PREFIX}_LONG_TERM_MEMORY +# LONG_TERM_MEMORY_ORACLE_TABLE=AGENTFW_LONG_TERM_MEMORY +LONG_TERM_MEMORY_MAX_CONTEXT_ITEMS=20 +LONG_TERM_MEMORY_MIN_CONFIDENCE=0.70 +LONG_TERM_MEMORY_AUTO_EXTRACT=true +LONG_TERM_MEMORY_INJECT_CONTEXT=true diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/_context.py b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/_context.py index a0ad60c..cf51808 100644 --- a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/_context.py +++ b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/_context.py @@ -74,11 +74,21 @@ def _format_conversation_history( msgs.pop() lines: list[str] = [] for msg in msgs: - cls = type(msg).__name__ - if cls in _SKIPPED_CLASSES: - continue - role = _ROLE_BY_CLASS.get(cls, cls.lower()) - content = _message_content_to_str(getattr(msg, "content", "")) + if isinstance(msg, dict): + role = str(msg.get("role") or msg.get("type") or "").lower() + if role in {"system", "tool", "function"}: + continue + if role == "human": + role = "user" + elif role in {"ai", "bot"}: + role = "assistant" + content = _message_content_to_str(msg.get("content", "")) + else: + cls = type(msg).__name__ + if cls in _SKIPPED_CLASSES: + continue + role = _ROLE_BY_CLASS.get(cls, cls.lower()) + content = _message_content_to_str(getattr(msg, "content", "")) if content.strip(): lines.append(f"[{role}] {_truncate(content, per_message_limit)}") return "\n".join(lines) diff --git a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py index 9d3794a..fea01a8 100644 --- a/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py +++ b/libs/agent_framework/src/agent_framework/guardrails/calibrated/prompts/ausencia_oferta_proativa.py @@ -48,6 +48,10 @@ Decida na ordem, PARE no primeiro match: casa aqui, siga para o passo 5. Vale o pedido generico ("quero cancelar", "todos") sobre o que a conversa trata, e vale confirmar ou pedir permissao para executar essa acao. + IMPORTANTE: se o cliente acabou de PEDIR cancelamento/contestacao/ajuste do + mesmo alvo, a fala do agente que apenas pede CONFIRMACAO da transacao e + allowed=true. A confirmacao NAO precisa repetir a justificativa do cliente + ("nao reconheco", "esta caro" etc.); o pedido transacional anterior basta. Vale tambem trocar uma variante transacional por outra DA MESMA FAMILIA sobre o MESMO escopo, sempre limitada ao valor JA COBRADO no item (ressarcimento <-> devolucao <-> reembolso <-> cancelamento <-> credito em fatura): negar o dobro e diff --git a/tests/unit/test_langgraph_checkpoint_runtime_config.py b/tests/unit/test_langgraph_checkpoint_runtime_config.py new file mode 100644 index 0000000..fd0f6f5 --- /dev/null +++ b/tests/unit/test_langgraph_checkpoint_runtime_config.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import asyncio +from types import SimpleNamespace + +from agent_framework.checkpoints.langgraph_saver import ( + RepositoryCheckpointSaver, + _durable_config, +) + + +class _Repo: + def __init__(self) -> None: + self.saved = None + + async def put(self, thread_id, checkpoint): + self.saved = (thread_id, checkpoint) + + async def get_latest(self, thread_id): + return self.saved[1] if self.saved and self.saved[0] == thread_id else None + + +def test_private_pregel_runtime_is_not_durable() -> None: + config = { + "tags": ["x"], + "configurable": { + "thread_id": "t1", + "tenant": "default", + "__pregel_runtime": "stringified-runtime", + "__pregel_store": "stringified-store", + }, + } + + cleaned = _durable_config(config) + + assert cleaned == { + "tags": ["x"], + "configurable": {"thread_id": "t1", "tenant": "default"}, + } + assert "__pregel_runtime" in config["configurable"] + + +def test_saver_strips_private_runtime_before_put_and_restore() -> None: + repo = _Repo() + saver = RepositoryCheckpointSaver(SimpleNamespace(), repository=repo) + config = { + "configurable": { + "thread_id": "t1", + "__pregel_runtime": "Runtime(...) persisted by JSON backend", + } + } + checkpoint = {"id": "cp1", "v": 1} + + returned = asyncio.run(saver.aput(config, checkpoint, {}, {})) + assert returned["configurable"] == {"thread_id": "t1", "checkpoint_id": "cp1"} + assert repo.saved is not None + persisted = repo.saved[1] + assert "__pregel_runtime" not in persisted["config"]["configurable"] + + # Also protects legacy records already stored with a stringified runtime. + persisted["config"]["configurable"]["__pregel_runtime"] = "legacy-string" + restored = saver._make_tuple(persisted) + restored_config = restored.config if hasattr(restored, "config") else restored["config"] + assert "__pregel_runtime" not in restored_config["configurable"]