Ir al contenido

SDK de robots y logging

El SDK nora_agent es la forma oficial de que un robot hable con NORA (Robots Center) desde su propio código: escribir logs, reportar progreso, leer credenciales (assets), consumir colas y reaccionar a señales del operador. Esta página está pensada para autores de robots y se centra en logging y en la configuración de ejecución.

El SDK funciona en dos modos, sin que cambies tu código:

  • Job gestionado — cuando NORA lanza el robot, el agente inyecta NORA_JOB_ID, el token de ejecución y la URL de la API. El SDK envía todo a la plataforma.
  • Desarrollo local — sin NORA_JOB_ID (por ejemplo bajo nora dev run), las funciones de log y progreso imprimen por stdout para que sigas viendo la salida.

La función real es:

from nora_agent import sdk
sdk.log(level: str, message: str, data: dict | None = None) -> None

Uso básico:

from nora_agent import sdk
sdk.log("info", "Inicio del proceso de facturación")
sdk.log("warning", "Reintentando descarga (intento 2)")
sdk.log("error", "No se pudo abrir el portal del proveedor")
NivelCuándo usarlo
infoHitos normales del proceso (inicio, paso completado, fin).
warningAlgo recuperable: reintento, dato faltante, fallback.
errorUn fallo que impide completar el item o el job.

El SDK normaliza el nivel a mayúsculas internamente, así que "info" e "INFO" producen el mismo resultado. Mantén estos tres niveles; la plataforma los espera para colorear y filtrar.

Para adjuntar contexto, pásalo por el parámetro data (un dict), no lo concatenes al texto del mensaje:

sdk.log(
"info",
"Factura procesada",
{"invoice_id": "F-2026-0042", "amount": 1290.50, "currency": "EUR"},
)

El SDK serializa data como JSON al final de la línea. Mantén el mensaje legible para humanos y deja los valores estructurados en data.

Internamente, sdk.log() construye una línea con este formato y la envía al stream de logs del job:

[2026-06-19T08:30:00Z] [INFO] Factura procesada | {"invoice_id": "F-2026-0042", "amount": 1290.5}

El timestamp es ISO-8601 en UTC (YYYY-MM-DDTHH:MM:SSZ). El front de NORA parsea exactamente este contrato; por eso el robot no debe inventar otro formato ni anteponer su propia marca de tiempo.

Para mover la barra de progreso del job (0–100):

sdk.update_progress(50, "Mitad de los registros procesados")

El valor se acota automáticamente al rango 0–100. En dev local imprime [progress] 50% - ... por stdout.

Configuración de ejecución y resolución de pantalla

Sección titulada «Configuración de ejecución y resolución de pantalla»

El agente inyecta la configuración del job mediante variables de entorno. Las más útiles para un robot:

VariableSignificado
NORA_JOB_IDID del job que lanzó el robot (ausente en dev local).
NORA_DISPLAY_WIDTHAncho de pantalla configurado en la máquina (Robots Center).
NORA_DISPLAY_HEIGHTAlto de pantalla configurado en la máquina.

Puedes recuperar el ID del job de forma segura con sdk.get_job_id() (devuelve None fuera de un job gestionado).

Para la resolución, prioriza NORA_DISPLAY_WIDTH / NORA_DISPLAY_HEIGHT sobre la resolución “viva” del sistema operativo. En una VM sin sesión RDP abierta, la resolución real del SO puede quedar pegada en un valor pequeño o incorrecto (p. ej. 1024×768) y hacer fallar la automatización:

import os
from nora_agent import sdk
def screen_resolution() -> tuple[int, int]:
w = os.environ.get("NORA_DISPLAY_WIDTH", "")
h = os.environ.get("NORA_DISPLAY_HEIGHT", "")
if w.isdigit() and h.isdigit():
return int(w), int(h)
return 1920, 1080 # fallback solo para dev local
ancho, alto = screen_resolution()
sdk.log("info", f"Resolución: {ancho}x{alto}", {"width": ancho, "height": alto})

Assets (credenciales y configuración cifrada)

Sección titulada «Assets (credenciales y configuración cifrada)»

Lee un asset descifrado por nombre. Devuelve un dict con {name, type, environment, value, username?}:

cred = sdk.get_asset("portal-proveedor") # environment="production" por defecto
usuario = cred.get("username")
secreto = cred["value"]

El SDK cubre el ciclo de vida de una cola. Las funciones más usadas:

FunciónPara qué sirve
queue_pending(queue)Cuántos items quedan claimables (status new).
queue_stats(queue)Conteo por estado, sin consumir nada.
get_queue_item(queue)Reclama el siguiente item (o None si está vacía).
complete_queue_item(queue, item_id, result)Marca el item como completado con datos de resultado.
fail_queue_item(queue, item_id, error_message)Marca el item como fallido (puede reintentar).
add_queue_item(queue, data, priority=3, ...)Encola un único item.
add_queue_items(queue, items, priority=3)Encola varios; devuelve cuántos se añadieron.
send_queue_item_for_review(queue, item_id)Manda el item a revisión humana.
wait_for_queue_review(queue, item_id)Bloquea hasta "approved" o "rejected".

Patrón típico de consumo (dispatcher + performer):

from nora_agent import sdk
QUEUE = "RPA-Challenge"
# Cargar la cola solo si está vacía (idempotente).
if sdk.queue_pending(QUEUE) == 0:
sdk.add_queue_items(QUEUE, registros) # registros: list[dict]
# Procesar item a item.
while True:
item = sdk.get_queue_item(QUEUE)
if item is None:
break
try:
# ... trabajo sobre item["data"] ...
sdk.complete_queue_item(QUEUE, item["id"], {"ok": True})
except Exception as e:
sdk.fail_queue_item(QUEUE, item["id"], str(e))
raise

La prioridad usa la escala 1=baja, 3=normal, 5=urgente. add_queue_item() acepta además reference, deadline y postpone (datetime o cadena ISO-8601).

  • sdk.should_stop()True si el operador pidió Stop/Kill desde el dashboard. Conviene consultarlo dentro de bucles largos para salir limpiamente.
  • sdk.ask_user(prompt, options=None, timeout=3600.0) → pide un dato al operador y bloquea hasta la respuesta. Requiere un job gestionado.
if sdk.should_stop():
sdk.log("warning", "Detención solicitada por el operador; cierro ordenadamente")
return
decision = sdk.ask_user("¿Aprobar el pago?", options=["", "No"])
  • Centraliza el trato con NORA en un módulo (como nora.py del ejemplo examples/rpa-challenge), de modo que tus workflows solo llamen a log, claim_next, etc., sin saber de HTTP.
  • Loguea hitos, no ruido: un info al inicio/fin de cada paso y warning/error cuando algo se desvía.
  • Adjunta el contexto por data, no en el texto.
  • Reporta progreso en pasos significativos para que el operador vea avance real.