Skip to main content

Utilitários

Funções e recursos auxiliares para o desenvolvimento de actions.


format_response_message​

Formata uma mensagem de resposta com contexto e timestamp opcionais. Útil para padronizar textos de instrução em ResponseToAgent.

from actions_sdk.features.utils.formatters import format_response_message

Uso​

# Mensagem simples
texto = format_response_message("Operação concluída")
# → "Operação concluída"

# Com contexto
texto = format_response_message(
"Consulta realizada",
context={"registros": 5, "tempo_ms": 120},
)
# → "Consulta realizada (registros: 5 | tempo_ms: 120)"

# Com timestamp
texto = format_response_message("Log de execução", include_timestamp=True)
# → "[2025-06-07 14:30:00] Log de execução"

# Combinando contexto e timestamp
texto = format_response_message(
"Resultado",
context={"status": "ok"},
include_timestamp=True,
)
# → "[2025-06-07 14:30:00] Resultado (status: ok)"

Parâmetros​

ParâmetroTipoPadrãoDescrição
contentstr—Conteúdo base da mensagem
contextdict | NoneNoneDicionário de contexto a anexar à mensagem
include_timestampboolFalseSe True, adiciona timestamp [YYYY-MM-DD HH:MM:SS] no início

Retorna: str


Code Secrets​

Code Secrets são variáveis de ambiente injetadas pelo motor no namespace de execução da action. Use para armazenar credenciais, chaves de API e outros dados sensíveis sem colocá-los no código.

Como definir um Code Secret​

Os Code Secrets são configurados na plataforma Tech4AI — na configuração do agente ou da action, na seção de variáveis de ambiente.

Como acessar na action​

Code Secrets são disponibilizados como variáveis de módulo — declare a variável no escopo global do arquivo:

# No topo do arquivo da action (escopo global)
MINHA_API_KEY: str # Declaração — o motor injeta o valor

def minha_action(parametro: str):
# Usar a variável como string normal
headers = {"Authorization": f"Bearer {MINHA_API_KEY}"}
# ...
Segurança
  • Nunca imprima Code Secrets em logs ou inclua em payloads de tracing
  • Nunca retorne Code Secrets em instruction, detail ou state_updates
  • Use o parâmetro sensitive_json_keys do HttpClient para mascarar chaves em requests HTTP

Boas práticas​

# Boa prática — declarar no topo com type hint
API_KEY: str
API_URL: str

def consultar_api(query: str):
from actions_sdk.features.http import HttpClient

client = HttpClient(ctx)
resposta = client.get(
f"{API_URL}/endpoint",
headers={"X-API-Key": API_KEY},
sensitive_json_keys=["X-API-Key"], # Mascara nos logs de tracing
)
# ...

Verificar se a variável foi injetada​

API_KEY: str

def minha_action():
try:
chave = API_KEY
except NameError:
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction="Variável API_KEY não foi configurada como Code Secret.",
)

Criptografia simétrica​

O namespace de execução expõe as primitivas de baixo nível da lib cryptography para cifra simétrica (AES, TripleDES etc.), disponíveis sem import adicional em actions e tasks. Use quando a integração externa (parceiro, banco, gateway de pagamento) exige que você mesmo cifre/decifre o payload com uma chave compartilhada — por exemplo, campos de um webhook ou de um arquivo trocado com um sistema legado.

AtributoOrigem
Ciphercryptography.hazmat.primitives.ciphers.Cipher
crypto_algorithmscryptography.hazmat.primitives.ciphers.algorithms (AES, TripleDES etc.)
crypto_modescryptography.hazmat.primitives.ciphers.modes (CBC, GCM, CTR etc.)
crypto_paddingcryptography.hazmat.primitives.padding (PKCS7)

Qual algoritmo usar​

  • AES — algoritmo padrão para cifra simétrica hoje. Use AES-128 ou AES-256 (tamanho da chave em bytes: 16 ou 32) para qualquer caso novo.
  • TripleDES — considerado obsoleto e mais lento que AES. Só use se a integração externa exigir explicitamente (ex.: sistema legado que só aceita TripleDES). Não escolha para casos novos.

Qual modo usar​

O modo define como blocos de dados são combinados durante a cifra. A escolha certa depende de o parceiro precisar (ou não) de autenticação da mensagem:

ModoPrecisa de padding?Autentica a mensagem (detecta adulteração)?Quando usar
GCMNãoSim (gera uma tag de autenticação)Padrão recomendado para qualquer integração nova — cifra e garante integridade em uma única operação
CBCSim (crypto_padding.PKCS7)NãoSomente quando a integração externa exige CBC (protocolo legado). Sem autenticação própria — se precisar detectar adulteração, combine com HMAC (veja hmac, disponível no namespace)
CTRNãoNãoCasos específicos de streaming/paralelização. Assim como CBC, não autentica a mensagem por conta própria

Regra prática: use GCM a menos que o sistema do outro lado exija outro modo.

Cuidado com IV/nonce​

  • Nunca reutilize o mesmo par (chave, IV/nonce) para cifrar mensagens diferentes — isso quebra a segurança do algoritmo (em CTR e GCM, reutilizar o nonce pode até expor a chave). Gere um IV/nonce novo e aleatório a cada operação de cifra (os.urandom(...)).
  • O IV/nonce não é segredo: é comum e seguro transmiti-lo junto com o texto cifrado (ex.: concatenado no início do payload) para que quem for decifrar consiga reconstruir a operação.
  • Em GCM, guarde também a tag de autenticação gerada pelo encryptor() — ela é necessária para decifrar e validar a integridade.

Uso — cifrar e decifrar com GCM (recomendado)​

def cifrar_aes_gcm(dado: bytes, chave: bytes, iv: bytes) -> tuple[bytes, bytes]:
# iv: nonce de 12 bytes (96 bits), gerado por uma fonte segura de
# aleatoriedade a cada chamada — nunca reaproveite o mesmo valor
cifrador = Cipher(crypto_algorithms.AES(chave), crypto_modes.GCM(iv)).encryptor()
dado_cifrado = cifrador.update(dado) + cifrador.finalize()
return dado_cifrado, cifrador.tag


def decifrar_aes_gcm(dado_cifrado: bytes, chave: bytes, iv: bytes, tag: bytes) -> bytes:
decifrador = Cipher(crypto_algorithms.AES(chave), crypto_modes.GCM(iv, tag)).decryptor()
return decifrador.update(dado_cifrado) + decifrador.finalize()
# Levanta InvalidTag se o dado ou a tag foram adulterados

Uso — cifrar e decifrar com CBC (protocolos legados)​

def cifrar_aes_cbc(dado: bytes, chave: bytes, iv: bytes) -> bytes:
padder = crypto_padding.PKCS7(crypto_algorithms.AES.block_size).padder()
dado_com_padding = padder.update(dado) + padder.finalize()

cifrador = Cipher(crypto_algorithms.AES(chave), crypto_modes.CBC(iv)).encryptor()
return cifrador.update(dado_com_padding) + cifrador.finalize()


def decifrar_aes_cbc(dado_cifrado: bytes, chave: bytes, iv: bytes) -> bytes:
decifrador = Cipher(crypto_algorithms.AES(chave), crypto_modes.CBC(iv)).decryptor()
dado_com_padding = decifrador.update(dado_cifrado) + decifrador.finalize()

unpadder = crypto_padding.PKCS7(crypto_algorithms.AES.block_size).unpadder()
return unpadder.update(dado_com_padding) + unpadder.finalize()

Cuidado com BOM ao decodificar texto​

Se o texto original foi salvo como "UTF-8 with BOM" (comum em arquivos exportados por Excel ou algumas ferramentas Windows) antes de ser cifrado, o resultado decifrado vem com um caractere BOM (U+FEFF, invisível) no início. bytes.decode("utf-8") não remove esse caractere — ele quebra comparações de string e faz json.loads falhar com JSONDecodeError mesmo que o conteúdo pareça correto. Use bytes.decode("utf-8-sig") em vez de "utf-8" quando houver risco de BOM na origem, ou remova explicitamente com texto.lstrip("\ufeff") após decodificar.

Fora de escopo: criptografia assimétrica (RSA, ECDH) e utilitários de alto nível (Fernet, X.509).