bugfixes: transaction parameter collector, generic formatting messages, guardrails, prompts. Testing contas

This commit is contained in:
2026-08-20 00:22:49 -03:00
parent 23b477e08f
commit bb0ef019bf
79 changed files with 232 additions and 66 deletions

108
.env
View File

@@ -28,7 +28,7 @@ LLM_TIMEOUT_SECONDS=120
# OCI OpenAI-compatible endpoint # OCI OpenAI-compatible endpoint
OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com
OCI_GENAI_MODEL=openai.gpt-4.1 OCI_GENAI_MODEL=openai.gpt-4.1
OCI_GENAI_API_KEY=sk-ph3FgX6iP3fxAQCXb9IpPIDTadkeeYAWntUWhzcWysIM6zsS OCI_GENAI_API_KEY=<API_KEY>
OCI_GENAI_PROJECT_OCID= OCI_GENAI_PROJECT_OCID=
#OCI_GENAI_BASE_URL=https://pegruagntaiatenddev.pe.inference.generativeai.sa-saopaulo-1.oci.oraclecloud.com #OCI_GENAI_BASE_URL=https://pegruagntaiatenddev.pe.inference.generativeai.sa-saopaulo-1.oci.oraclecloud.com
@@ -42,7 +42,7 @@ OCI_AUTH_MODE=config_file
# OCI SDK / signer / profiles # OCI SDK / signer / profiles
OCI_CONFIG_FILE=~/.oci/config OCI_CONFIG_FILE=~/.oci/config
OCI_PROFILE=LATINOAMERICA-Chicago OCI_PROFILE=LATINOAMERICA-Chicago
OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaexpiw4a7dio64mkfv2t273s2hgdl6mgfvvyv7tycalnjlvpvfl3q OCI_COMPARTMENT_ID=ocid1.compartment.oc1..<COMPARTMENT_OCID>
OCI_REGION=us-chicago-1 OCI_REGION=us-chicago-1
############################################################################### ###############################################################################
@@ -55,18 +55,18 @@ CHECKPOINT_REPOSITORY_PROVIDER=autonomous
# Autonomous Database # Autonomous Database
ADB_USER=admin ADB_USER=admin
ADB_PASSWORD=Moniquinha19721972 ADB_PASSWORD=<PASSWORD>
ADB_DSN=oradb23ai_high ADB_DSN=<TNS_ALIAS_OR_CONNECTION_DSN>
ADB_WALLET_LOCATION=/mnt/d/Dropbox/ORACLE/LatinoAmerica/Wallet_ORADB23ai ADB_WALLET_LOCATION=/path/to/<REDACTED>
ADB_WALLET_PASSWORD=Moniquinha1972 ADB_WALLET_PASSWORD=<PASSWORD>
ADB_TABLE_PREFIX=AGENTFW ADB_TABLE_PREFIX=AGENTFW
# MongoDB - também pode representar Autonomous usando API compatível com Mongo, se habilitada no ambiente # MongoDB - também pode representar Autonomous usando API compatível com Mongo, se habilitada no ambiente
MONGODB_URI=mongodb://ADMIN:Moniquinha1972@srlrz1eg.adb.sa-saopaulo-1.oraclecloudapps.com:37017/ADMIN?authMechanism=PLAIN&authSource=$external&ssl=true&retryWrites=false&loadBalanced=true MONGODB_URI=mongodb://<USER>:<PASSWORD>@<HOST>:<PORT>/<DB>?<PARAMS>
MONGODB_DATABASE=agent_platform MONGODB_DATABASE=agent_platform
# Redis # Redis
REDIS_URL=redis://default:devredis@localhost:6379/0 REDIS_URL=redis://<USER>:<PASSWORD>@<HOST>:<PORT>/<DB>
ENABLE_REDIS_CACHE=false ENABLE_REDIS_CACHE=false
############################################################################### ###############################################################################
@@ -90,9 +90,9 @@ LANGFUSE_COMPACT_VISIBLE_EVENT_PREFIXES=AGA.,NOC., IC.
LANGFUSE_COMPACT_SUPPRESSED_PREFIXES=llm.chat_completion LANGFUSE_COMPACT_SUPPRESSED_PREFIXES=llm.chat_completion
LANGFUSE_IGNORE_HEALTHCHECKS=true LANGFUSE_IGNORE_HEALTHCHECKS=true
LANGFUSE_IGNORED_PATHS=/health,/ready,/metrics LANGFUSE_IGNORED_PATHS=/health,/ready,/metrics
LANGFUSE_PUBLIC_KEY=pk-lf-4a1e3921-5158-4fd3-a16d-7a77549fb312 LANGFUSE_PUBLIC_KEY=<PUBLIC_KEY>
LANGFUSE_SECRET_KEY=sk-lf-efc6fd59-c5ec-4858-b6ec-4aa129734915 LANGFUSE_SECRET_KEY=<SECRET_KEY>
LANGFUSE_HOST=http://localhost:3005 LANGFUSE_HOST=http://<HOST>/<PATH>
ENABLE_OTEL=false ENABLE_OTEL=false
OTEL_EXPORTER_OTLP_ENDPOINT= OTEL_EXPORTER_OTLP_ENDPOINT=
OTEL_SERVICE_NAME=ai-agent-template OTEL_SERVICE_NAME=ai-agent-template
@@ -113,7 +113,7 @@ GCP_PROJECT_ID=
GCP_PUBSUB_TOPIC= GCP_PUBSUB_TOPIC=
GCP_PUBSUB_TIMEOUT_SECONDS=30 GCP_PUBSUB_TIMEOUT_SECONDS=30
# Credencial GCP segue padrão Google: # Credencial GCP segue padrão Google:
# GOOGLE_APPLICATION_CREDENTIALS=/secrets/gcp-service-account.json # GOOGLE_APPLICATION_CREDENTIALS=/path/to/<CREDENTIAL_FILE>
############################################################################### ###############################################################################
# OCI Streaming # OCI Streaming
@@ -221,11 +221,11 @@ ENABLE_CONTROL_EVENTS_OTEL_LOGS=true
ENABLE_NOC_OTEL_LOGS=false ENABLE_NOC_OTEL_LOGS=false
ENV_TESTE=123 ENV_TESTE=123
GUARDRAIL_LLM="20b" GUARDRAIL_LLM="20b"
LANGFUSE_HOST=http://localhost:3005 LANGFUSE_HOST=http://<HOST>/<PATH>
MONGODB_COLLECTION=sales_memory MONGODB_COLLECTION=sales_memory
MONGODB_CONNECTION_STRING=mongodb://ADMIN:Moniquinha1972@srlrz1eg.adb.sa-saopaulo-1.oraclecloudapps.com:37017/ADMIN?authMechanism=PLAIN&authSource=$external&ssl=true&retryWrites=false&loadBalanced=true MONGODB_CONNECTION_STRING=mongodb://<USER>:<PASSWORD>@<HOST>:<PORT>/<DB>?<PARAMS>
OTEL_EXPORTER_OTLP_HOST_HEADER=tim-ai-atend-agnt-opentelemetry OTEL_EXPORTER_OTLP_HOST_HEADER=tim-ai-atend-agnt-opentelemetry
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://10.153.35.23/v1/logs OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://<HOST>/<PATH>
PUBSUB_EXCLUDE_NOC=true PUBSUB_EXCLUDE_NOC=true
PUBSUB_PAYLOAD_MODE=flat PUBSUB_PAYLOAD_MODE=flat
PUBSUB_SEQUENCE_ENABLED=true PUBSUB_SEQUENCE_ENABLED=true
@@ -233,9 +233,9 @@ PUBSUB_SEQUENCE_PROVIDER=mongodb
PUBSUB_SEQUENCE_MEMORY_FALLBACK=false PUBSUB_SEQUENCE_MEMORY_FALLBACK=false
PUBSUB_SEQUENCE_MONGODB_COLLECTION=observer_sequences PUBSUB_SEQUENCE_MONGODB_COLLECTION=observer_sequences
PUBSUB_SEQUENCE_MONGODB_DATABASE=USR_ADB_AGNTATEND_W_DEV PUBSUB_SEQUENCE_MONGODB_DATABASE=USR_ADB_AGNTATEND_W_DEV
PUBSUB_SEQUENCE_MONGODB_URI=mongodb://ADMIN:Moniquinha1972@srlrz1eg.adb.sa-saopaulo-1.oraclecloudapps.com:37017/ADMIN?authMechanism=PLAIN&authSource=$external&ssl=true&retryWrites=false&loadBalanced=true PUBSUB_SEQUENCE_MONGODB_URI=mongodb://<USER>:<PASSWORD>@<HOST>:<PORT>/<DB>?<PARAMS>
PUBSUB_SEQUENCE_PROVIDER=mongodb PUBSUB_SEQUENCE_PROVIDER=mongodb
PUBSUB_SEQUENCE_REDIS_URL=redis://default:devredis@127.0.0.1:6379/0 PUBSUB_SEQUENCE_REDIS_URL=redis://<USER>:<PASSWORD>@<HOST>:<PORT>/<DB>
TIM_AGENT_FRAMEWORK_EVENT_PAYLOAD_LOG_ENABLED=true TIM_AGENT_FRAMEWORK_EVENT_PAYLOAD_LOG_ENABLED=true
TIM_AGENT_FRAMEWORK_LOG_EXPORT_ENABLED=true TIM_AGENT_FRAMEWORK_LOG_EXPORT_ENABLED=true
TIM_AGENT_ID=contas TIM_AGENT_ID=contas
@@ -252,88 +252,88 @@ TIM_BLOQUEIO_CLIENT_ID=AIAGENTCR
TIM_BLOQUEIO_OPERATION_TYPE=block TIM_BLOQUEIO_OPERATION_TYPE=block
TIM_BLOQUEIO_TIMEOUT=30 TIM_BLOQUEIO_TIMEOUT=30
TIM_CANCELAMENTO_TIMEOUT=30 TIM_CANCELAMENTO_TIMEOUT=30
TIM_CANCELAMENTO_URL=http://pmidfqa.internal.timbrasil.com.br:8000/access/v1/singleVas TIM_CANCELAMENTO_URL=http://<HOST>/<PATH>
TIM_CHANNEL_ADAPTER_DEFAULT_CHANNEL=voice TIM_CHANNEL_ADAPTER_DEFAULT_CHANNEL=voice
TIM_CHANNEL_ADAPTER_ENABLED=false TIM_CHANNEL_ADAPTER_ENABLED=false
TIM_CHANNEL_ADAPTER_SHADOW=false TIM_CHANNEL_ADAPTER_SHADOW=false
TIM_COMPLETE_INVOICES_TIMEOUT=30 TIM_COMPLETE_INVOICES_TIMEOUT=30
TIM_COMPLETE_INVOICES_URL=http://pmidfqa.internal.timbrasil.com.br:8000/customers/v1/completeInvoices TIM_COMPLETE_INVOICES_URL=http://<HOST>/<PATH>
TIM_CONSULTA_TIMEOUT=30 TIM_CONSULTA_TIMEOUT=30
TIM_CONTRACT_VERSION=1.0.0 TIM_CONTRACT_VERSION=1.0.0
TIM_CONTRATO_TIMEOUT=30 TIM_CONTRATO_TIMEOUT=30
TIM_CONTRATO_URL=http://pmidfqa.internal.timbrasil.com.br:8000/access/v1/contractInformation TIM_CONTRATO_URL=http://<HOST>/<PATH>
TIM_CUSTOMER_CONTESTATION_CLIENT_ID=AIAGENTCR TIM_CUSTOMER_CONTESTATION_CLIENT_ID=AIAGENTCR
TIM_CUSTOMER_CONTESTATION_TIMEOUT=30 TIM_CUSTOMER_CONTESTATION_TIMEOUT=30
TIM_CUSTOMER_CONTESTATION_URL=http://pmidfqa.internal.timbrasil.com.br:8000/interactions/v1/customerContestation TIM_CUSTOMER_CONTESTATION_URL=http://<HOST>/<PATH>
TIM_CUSTOMER_CONTESTATION_USER_ID=AIAGENTCR TIM_CUSTOMER_CONTESTATION_USER_ID=AIAGENTCR
TIM_DEFAULT_CHANNEL=APP TIM_DEFAULT_CHANNEL=APP
TIM_DEFAULT_CLIENT_ID=CHAT TIM_DEFAULT_CLIENT_ID=CHAT
TIM_DEFAULT_CSP_ID=740 TIM_DEFAULT_CSP_ID=740
TIM_DIVERGENCIA_TIMEOUT=120 TIM_DIVERGENCIA_TIMEOUT=120
TIM_DIVERGENCIA_URL=http://pmidfqa.internal.timbrasil.com.br:8000/customers/v1/billingAnalysis TIM_DIVERGENCIA_URL=http://<HOST>/<PATH>
TIM_DIVERGENCIA_USER=agentecontestacao TIM_DIVERGENCIA_USER=agentecontestacao
TIM_GATEWAY_DEFAULT_TIMEOUT=30 TIM_GATEWAY_DEFAULT_TIMEOUT=30
TIM_GATEWAY_MODE=mock TIM_GATEWAY_MODE=mock
TIM_GATEWAY_RETRY_BACKOFF_FACTOR=0.5 TIM_GATEWAY_RETRY_BACKOFF_FACTOR=0.5
TIM_GATEWAY_RETRY_MAX_RETRIES=3 TIM_GATEWAY_RETRY_MAX_RETRIES=3
TIM_INVOICE_RECOVER_CLIENT_ID=AIAGENTCR TIM_INVOICE_RECOVER_CLIENT_ID=AIAGENTCR
TIM_SECURE_PDF_AUTH=Basic test TIM_SECURE_PDF_AUTH=Basic <REDACTED_TOKEN>
TIM_INVOICE_RECOVER_TIMEOUT=30 TIM_INVOICE_RECOVER_TIMEOUT=30
TIM_JUDGES_BASELINE_SCORES= TIM_JUDGES_BASELINE_SCORES=
TIM_JUDGES_MIN_SCORES=CSI=0,ALUC=7,RQLT=6,VCTN=8 TIM_JUDGES_MIN_SCORES=CSI=0,ALUC=7,RQLT=6,VCTN=8
#TIM_LLM_EXTRA={"auth_type":"RESOURCE_PRINCIPAL","provider":"meta","oci_use_oke_workload_signer":true} #TIM_LLM_EXTRA={"auth_type":"RESOURCE_PRINCIPAL","provider":"meta","oci_use_oke_workload_signer":true}
TIM_LLM_OCI_AUTH_FILE_LOCATION=/home/hoshi/.oci/config TIM_LLM_OCI_AUTH_FILE_LOCATION=/path/to/<REDACTED>
TIM_LLM_EXTRA={"auth_type":"API_KEY","auth_profile":"LATINOAMERICA-Chicago","provider":"meta","oci_use_oke_workload_signer":false} TIM_LLM_EXTRA={"auth_type":"API_KEY","auth_profile":"LATINOAMERICA-Chicago","provider":"meta","oci_use_oke_workload_signer":false}
TIM_LLM_GATEWAY_FALLBACK_PROMPT_CONTENT=Você é um agente para operações VAS TIM. Use tools quando precisar executar ações no backend. TIM_LLM_GATEWAY_FALLBACK_PROMPT_CONTENT=Você é um agente para operações VAS TIM. Use tools quando precisar executar ações no backend.
TIM_LLM_GATEWAY_FALLBACK_PROMPT_ID=default TIM_LLM_GATEWAY_FALLBACK_PROMPT_ID=default
TIM_LLM_GATEWAY_LANGFUSE_CACHE_TTL_SECONDS=60 TIM_LLM_GATEWAY_LANGFUSE_CACHE_TTL_SECONDS=60
TIM_LLM_GATEWAY_LANGFUSE_DEFAULT_LABEL=production TIM_LLM_GATEWAY_LANGFUSE_DEFAULT_LABEL=production
TIM_LLM_GATEWAY_LANGFUSE_FETCH_TIMEOUT_SECONDS=5 TIM_LLM_GATEWAY_LANGFUSE_FETCH_TIMEOUT_SECONDS=5
TIM_LLM_GATEWAY_LANGFUSE_HOST=http://localhost:3005 TIM_LLM_GATEWAY_LANGFUSE_HOST=http://<HOST>/<PATH>
TIM_LLM_GATEWAY_LANGFUSE_MASK_SENSITIVE_DATA=true TIM_LLM_GATEWAY_LANGFUSE_MASK_SENSITIVE_DATA=true
TIM_LLM_GATEWAY_LANGFUSE_MAX_RETRIES=3 TIM_LLM_GATEWAY_LANGFUSE_MAX_RETRIES=3
TIM_LLM_GATEWAY_LANGFUSE_PUBLIC_KEY=pk-lf-4a1e3921-5158-4fd3-a16d-7a77549fb312 TIM_LLM_GATEWAY_LANGFUSE_PUBLIC_KEY=<PUBLIC_KEY>
TIM_LLM_GATEWAY_LANGFUSE_SECRET_KEY=sk-lf-efc6fd59-c5ec-4858-b6ec-4aa129734915 TIM_LLM_GATEWAY_LANGFUSE_SECRET_KEY=<SECRET_KEY>
TIM_LLM_GATEWAY_LANGGRAPH_TIMEOUT=5 TIM_LLM_GATEWAY_LANGGRAPH_TIMEOUT=5
TIM_LLM_GATEWAY_LOCAL_DIR=prompts TIM_LLM_GATEWAY_LOCAL_DIR=prompts
TIM_LLM_GATEWAY_SOURCES=txt TIM_LLM_GATEWAY_SOURCES=txt
TIM_LLM_MODEL=openai.gpt-4.1 TIM_LLM_MODEL=openai.gpt-4.1
TIM_LLM_OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaexpiw4a7dio64mkfv2t273s2hgdl6mgfvvyv7tycalnjlvpvfl3q TIM_LLM_OCI_COMPARTMENT_ID=ocid1.compartment.oc1..<COMPARTMENT_OCID>
TIM_LLM_OCI_MODEL_ID=openai.gpt-4.1 TIM_LLM_OCI_MODEL_ID=openai.gpt-4.1
TIM_LLM_OCI_MODEL_ID_120B=ocid1.generativeaiendpoint.oc1.sa-saopaulo-1.amaaaaaaaehl73aa2amkvyvpsv3ts6rdbx6tzya43zgwx7vqljtjade2vjya TIM_LLM_OCI_MODEL_ID_120B=ocid1.generativeaiendpoint.oc1.<region>.<MODEL_ENDPOINT_OCID>
TIM_LLM_OCI_MODEL_ID_20B=ocid1.generativeaiendpoint.oc1.sa-saopaulo-1.amaaaaaaaehl73aarckk4norgg263as5zleyp36tujnynrssoohshf3nwlhq TIM_LLM_OCI_MODEL_ID_20B=ocid1.generativeaiendpoint.oc1.<region>.<MODEL_ENDPOINT_OCID>
TIM_LLM_OCI_MODEL_KWARGS={"temperature":0.0,"top_p":0.1,"reasoning_effort":"LOW","max_tokens":16384} TIM_LLM_OCI_MODEL_KWARGS={"temperature":0.0,"top_p":0.1,"reasoning_effort":"LOW","max_tokens":16384}
TIM_LLM_OCI_MODEL_KWARGS_120B={"temperature":0.0,"top_p":0.1,"reasoning_effort":"LOW","max_tokens":16384} TIM_LLM_OCI_MODEL_KWARGS_120B={"temperature":0.0,"top_p":0.1,"reasoning_effort":"LOW","max_tokens":16384}
TIM_LLM_OCI_MODEL_KWARGS_20B={"temperature":0.0,"top_p":0.1,"reasoning_effort":"LOW","max_tokens":5000} TIM_LLM_OCI_MODEL_KWARGS_20B={"temperature":0.0,"top_p":0.1,"reasoning_effort":"LOW","max_tokens":5000}
TIM_LLM_OCI_SERVICE_ENDPOINT=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com TIM_LLM_OCI_SERVICE_ENDPOINT=https://<HOST>/<PATH>
TIM_LLM_OCI_VARIANT=120b TIM_LLM_OCI_VARIANT=120b
TIM_LLM_PROVIDER=oci TIM_LLM_PROVIDER=oci
TIM_MOCK_FIXTURES_DIR=/mnt/data/tim-ai-contas-agnt-agent-framework-oci-migrado/agente_contas_tim/gateway/mocks/fixtures TIM_MOCK_FIXTURES_DIR=<REDACTED>
TIM_OCI_FINGERPRINT=a6:e6:82:ca:d0:8e:8a:7f:58:14:ce:89:b4:b7:55:18 TIM_OCI_FINGERPRINT=<OCI_API_KEY_FINGERPRINT>
TIM_OCI_KEY_FILE=/etc/oci/key.pem TIM_OCI_KEY_FILE=/path/to/<REDACTED>
TIM_OCI_REGION=us-chicago-1 TIM_OCI_REGION=us-chicago-1
TIM_OCI_TENANCY=ocid1.tenancy.oc1..aaaaaaaayzepbi32gafno3hj23o3d6tuquqetuw3yelxb5y7t2ft2wtm2i7q TIM_OCI_TENANCY=ocid1.tenancy.oc1..<TENANCY_OCID>
TIM_OCI_USER=ocid1.user.oc1..aaaaaaaanzctq4cfq6u7atitnpgb46rzcnewlnbljlipihlbcdnqscy7qmkq TIM_OCI_USER=ocid1.user.oc1..<USER_OCID>
TIM_PREFETCH_INVOICE_CONTEXT_USE_CACHE=true TIM_PREFETCH_INVOICE_CONTEXT_USE_CACHE=true
TIM_PROFILE_FULL_URL=http://pmidfqa.internal.timbrasil.com.br:8000/access/v1/info/{msisdn} TIM_PROFILE_FULL_URL=http://<HOST>/<PATH>
TIM_PROTOCOL_URL=http://pmidfqa.internal.timbrasil.com.br:8000/customers/v1/backOfficeSRopening TIM_PROTOCOL_URL=http://<HOST>/<PATH>
TIM_RAG_DB_DSN=oradb23ai_high TIM_RAG_DB_DSN=<TNS_ALIAS_OR_CONNECTION_DSN>
TIM_RAG_DB_USER=ADMIN TIM_RAG_DB_USER=ADMIN
TIM_RAG_DB_PASSWORD=Moniquinha19721972 TIM_RAG_DB_PASSWORD=<PASSWORD>
TIM_RAG_DB_CONFIG_DIR=/mnt/d/Dropbox/ORACLE/LatinoAmerica/Wallet_ORADB23ai TIM_RAG_DB_CONFIG_DIR=/path/to/<REDACTED>
TIM_RAG_ENABLED=true TIM_RAG_ENABLED=true
TIM_RAG_OCI_AUTH_FILE_LOCATION=/etc/oci/config TIM_RAG_OCI_AUTH_FILE_LOCATION=/path/to/<REDACTED>
TIM_RAG_OCI_SERVICE_ENDPOINT=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com TIM_RAG_OCI_SERVICE_ENDPOINT=https://<HOST>/<PATH>
TIM_RAG_OCI_USE_OKE_WORKLOAD_IDENTITY=true TIM_RAG_OCI_USE_OKE_WORKLOAD_IDENTITY=true
TIM_SERVICE_REQUEST_STATUS_TIMEOUT=30 TIM_SERVICE_REQUEST_STATUS_TIMEOUT=30
TIM_SERVICE_REQUEST_STATUS_URL=http://pmidfqa.internal.timbrasil.com.br:8000/interactions/v1/statusServiceRequest TIM_SERVICE_REQUEST_STATUS_URL=http://<HOST>/<PATH>
TIM_SMS_CLIENT_ID=AIAGENTCR TIM_SMS_CLIENT_ID=AIAGENTCR
TIM_SMS_SENDER_ADDRESS=324 TIM_SMS_SENDER_ADDRESS=324
TIM_SMS_URL=http://pmidfqa.internal.timbrasil.com.br:8000/invoices/v1/smsBarcode TIM_SMS_URL=http://<HOST>/<PATH>
TIM_STATE_BACKEND=oracle TIM_STATE_BACKEND=oracle
#TIM_STATE_ORACLE_CONFIG_DIR=/mnt/d/Dropbox/ORACLE/LatinoAmerica/Wallet_ORADB23ai #TIM_STATE_ORACLE_CONFIG_DIR=/path/to/<REDACTED>
#TIM_STATE_ORACLE_DSN=oradb23ai_high #TIM_STATE_ORACLE_DSN=<TNS_ALIAS_OR_CONNECTION_DSN>
#TIM_STATE_ORACLE_PASSWORD=Moniquinha19721972 #TIM_STATE_ORACLE_PASSWORD=<PASSWORD>
TIM_STATE_ORACLE_POOL_ENABLED=true TIM_STATE_ORACLE_POOL_ENABLED=true
TIM_STATE_ORACLE_POOL_INCREMENT=1 TIM_STATE_ORACLE_POOL_INCREMENT=1
TIM_STATE_ORACLE_POOL_MAX=8 TIM_STATE_ORACLE_POOL_MAX=8
@@ -344,15 +344,15 @@ TIM_TENANT_ID=tim-brasil
TIM_TRACKING_ACTIVITIES_CHANNEL=AIAGENTCR TIM_TRACKING_ACTIVITIES_CHANNEL=AIAGENTCR
TIM_TRACKING_ACTIVITIES_CLIENT_ID=AIAGENTCR TIM_TRACKING_ACTIVITIES_CLIENT_ID=AIAGENTCR
TIM_TRACKING_ACTIVITIES_TIMEOUT=30 TIM_TRACKING_ACTIVITIES_TIMEOUT=30
TIM_TRACKING_ACTIVITIES_URL=http://pmidfqa.internal.timbrasil.com.br:8000/customers/v1/trackingActivities TIM_TRACKING_ACTIVITIES_URL=http://<HOST>/<PATH>
TIM_TRACKING_ACTIVITIES_USER_LOGIN=SIEBELPOS_INBOUND TIM_TRACKING_ACTIVITIES_USER_LOGIN=SIEBELPOS_INBOUND
TIM_URL_BLOQUEIO_VAS=http://pmidfqa.internal.timbrasil.com.br:8000/customers/v1/partialServiceBlocking TIM_URL_BLOQUEIO_VAS=http://<HOST>/<PATH>
TIM_URL_CONSULTA_VAS=http://pmidfqa.internal.timbrasil.com.br:8000/access/v1/{msisdn}/partnerServices TIM_URL_CONSULTA_VAS=http://<HOST>/<PATH>
TIM_URL_INVOICE_RECOVER=http://pmidfqa.internal.timbrasil.com.br:8000/customers/v1/securePDF TIM_URL_INVOICE_RECOVER=http://<HOST>/<PATH>
TIM_URL_PERFIL_FATURA=http://pmidfqa.internal.timbrasil.com.br:8000/customers/v1/completeInvoices TIM_URL_PERFIL_FATURA=http://<HOST>/<PATH>
TIM_USE_MOCK_GATEWAY=true TIM_USE_MOCK_GATEWAY=true
TIM_VAS_HISTORY_TIMEOUT=30 TIM_VAS_HISTORY_TIMEOUT=30
TIM_VAS_HISTORY_URL=http://pmidfqa.internal.timbrasil.com.br:8000/customers/v1/servicesHistory TIM_VAS_HISTORY_URL=http://<HOST>/<PATH>
TIM_WORKFLOWS_DIR=workflows TIM_WORKFLOWS_DIR=workflows
TIM_WORKFLOW_POSTGRES_DSN= TIM_WORKFLOW_POSTGRES_DSN=
USE_MOCK_LLM=false USE_MOCK_LLM=false

View File

@@ -26,11 +26,104 @@ from .checkpoint_repository import create_checkpoint_repository
def _jsonable(value: Any) -> Any: def _jsonable(value: Any) -> Any:
try: """Convert a value to a JSON-safe tree without collapsing containers to strings.
json.dumps(value, default=str)
The previous implementation used ``json.dumps(..., default=str)`` only as a
probe and then returned the *original* object. Because ``default=str`` makes
virtually every object serializable, the fallback branch was never reached.
JSON repositories could therefore stringify arbitrary nested LangGraph objects
later, and restored checkpoints would contain strings where mappings were
required (for example ``metadata``, ``versions_seen`` or ``checkpoint_map``).
Keep dict/list structure durable and stringify only unsupported leaf objects.
"""
if value is None or isinstance(value, (str, int, float, bool)):
return value return value
if isinstance(value, dict):
return {str(k): _jsonable(v) for k, v in value.items()}
if isinstance(value, (list, tuple, set, frozenset)):
return [_jsonable(v) for v in value]
model_dump = getattr(value, "model_dump", None)
if callable(model_dump):
try:
return _jsonable(model_dump(mode="python"))
except TypeError: except TypeError:
return json.loads(json.dumps(value, default=str)) return _jsonable(model_dump())
except Exception:
pass
# Unsupported runtime objects are not durable. At this point the object is a
# leaf; converting only the leaf to text cannot destroy an enclosing mapping.
return str(value)
def _mapping(value: Any, *, default: dict[str, Any] | None = None) -> dict[str, Any]:
"""Recover a mapping from native or legacy JSON-string values.
Legacy rows written with permissive ``default=str`` serializers may contain a
JSON object encoded as text. Parse that representation when possible; if the
value is an opaque string, return a safe empty/default mapping instead of
letting LangGraph fail with ``'str' object has no attribute 'items'``.
"""
if isinstance(value, dict):
return value
if isinstance(value, str):
try:
decoded = json.loads(value)
except Exception:
decoded = None
if isinstance(decoded, dict):
return decoded
return dict(default or {})
def _normalize_checkpoint(checkpoint: Any) -> dict[str, Any]:
"""Normalize LangGraph checkpoint mapping fields after JSON persistence."""
cp = _mapping(checkpoint)
if not cp:
return {}
cp = dict(cp)
cp["channel_values"] = _mapping(cp.get("channel_values"))
cp["channel_versions"] = _mapping(cp.get("channel_versions"))
versions_seen = _mapping(cp.get("versions_seen"))
cp["versions_seen"] = {
str(node): _mapping(versions) for node, versions in versions_seen.items()
}
pending_sends = cp.get("pending_sends")
if pending_sends is None:
cp["pending_sends"] = []
elif not isinstance(pending_sends, list):
cp["pending_sends"] = [pending_sends]
return cp
def _durable_config(config: dict[str, Any] | None) -> dict[str, Any] | None:
"""Return the persistable subset of a LangGraph RunnableConfig.
LangGraph injects private execution objects under ``configurable`` (notably
``__pregel_runtime``). Those objects are valid only for the current graph
invocation and must never be persisted by a checkpointer. JSON-backed
repositories stringify them; on restore LangGraph then sees that string as
its runtime object and calls ``.override(...)``, producing errors such as
``AttributeError: 'str' object has no attribute 'override'`` before the first
workflow node runs.
Durable checkpoint identity lives in the normal configurable keys
(thread_id/checkpoint_ns/checkpoint_id). User-defined configurable values are
preserved; only LangGraph's private ``__pregel_*`` execution keys are removed.
"""
if config is None:
return None
cleaned = dict(_mapping(config))
configurable = dict(_mapping(cleaned.get("configurable")))
for key in list(configurable):
if str(key).startswith("__pregel_"):
configurable.pop(key, None)
cleaned["configurable"] = configurable
return cleaned
def _thread_id(config: dict[str, Any] | None) -> str: def _thread_id(config: dict[str, Any] | None) -> str:
@@ -85,6 +178,13 @@ class RepositoryCheckpointSaver(BaseCheckpointSaver):
"""Checkpoint saver nativo para LangGraph usando os repositories do framework.""" """Checkpoint saver nativo para LangGraph usando os repositories do framework."""
def __init__(self, settings, repository=None): def __init__(self, settings, repository=None):
# BaseCheckpointSaver initializes LangGraph serializer state in current
# checkpoint releases. Keep compatibility with the lightweight fallback
# class used by framework-only unit tests.
try:
super().__init__()
except TypeError:
pass
self.settings = settings self.settings = settings
self.repository = repository or create_checkpoint_repository(settings) self.repository = repository or create_checkpoint_repository(settings)
self._loop: asyncio.AbstractEventLoop | None = None self._loop: asyncio.AbstractEventLoop | None = None
@@ -103,10 +203,10 @@ class RepositoryCheckpointSaver(BaseCheckpointSaver):
def _make_tuple(self, payload: dict[str, Any] | None): def _make_tuple(self, payload: dict[str, Any] | None):
if not payload: if not payload:
return None return None
config = payload.get("config") or {"configurable": {"thread_id": payload.get("thread_id")}} config = _durable_config(payload.get("config")) or {"configurable": {"thread_id": payload.get("thread_id")}}
checkpoint = payload.get("checkpoint") or {} checkpoint = _normalize_checkpoint(payload.get("checkpoint"))
metadata = payload.get("metadata") or {} metadata = _mapping(payload.get("metadata"))
parent_config = payload.get("parent_config") parent_config = _durable_config(payload.get("parent_config"))
pending_writes = _normalize_pending_writes(payload.get("pending_writes") or []) pending_writes = _normalize_pending_writes(payload.get("pending_writes") or [])
try: try:
from langgraph.checkpoint.base import CheckpointTuple from langgraph.checkpoint.base import CheckpointTuple
@@ -129,11 +229,13 @@ class RepositoryCheckpointSaver(BaseCheckpointSaver):
async def aput(self, config: dict[str, Any], checkpoint: dict[str, Any], metadata: dict[str, Any] | None = None, new_versions: dict[str, Any] | None = None): async def aput(self, config: dict[str, Any], checkpoint: dict[str, Any], metadata: dict[str, Any] | None = None, new_versions: dict[str, Any] | None = None):
thread_id = _thread_id(config) thread_id = _thread_id(config)
checkpoint_id = _checkpoint_id(checkpoint) checkpoint_id = _checkpoint_id(checkpoint)
base_config = _durable_config(config) or {}
next_config = { next_config = {
**(config or {}), **base_config,
"configurable": { "configurable": {
**((config or {}).get("configurable") or {}), **_mapping(base_config.get("configurable")),
"thread_id": thread_id, "thread_id": thread_id,
"checkpoint_ns": str(_mapping(base_config.get("configurable")).get("checkpoint_ns") or ""),
"checkpoint_id": checkpoint_id, "checkpoint_id": checkpoint_id,
}, },
} }

View File

@@ -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"]

View File

@@ -11,9 +11,9 @@ input:
output: output:
- {code: OOS, enabled: true} - {code: OOS, enabled: true}
- {code: AOFERTA, enabled: true} # - {code: AOFERTA, enabled: true}
- {code: REVPREC, enabled: true} - {code: REVPREC, enabled: true}
- {code: FRASEOLOGIA, enabled: true} # - {code: FRASEOLOGIA, enabled: true}
- {code: PINJ, enabled: true} - {code: PINJ, enabled: true}
- {code: DLEX_OUT, enabled: true} - {code: DLEX_OUT, enabled: true}
- {code: TOXOUT, enabled: true} - {code: TOXOUT, enabled: true}