/** * Ambiente lógico onde o robô roda. * * Arquivo-folha do protocolo (não importa nada): referenciado pelo heartbeat, pelo * poll de tasks (`InstanceInfo.environment`) e pelos eventos/transactions, e * reexportado por `hobots/protocol`. * * A fonte única do vocabulário (rótulos em pt-BR, apelidos legados aceitos e a * normalização) vive no servidor, em packages/utils/src/environments.ts — o SDK é * publicado sozinho no npm e não depende do monorepo, então o union é redeclarado * aqui. O servidor normaliza o que chega: valores antigos de texto livre ('prod', * 'qa', 'homologacao') continuam sendo aceitos e classificados. */ type Environment = 'development' | 'testing' | 'staging' | 'production'; /** * O que o wire realmente aceita: o ambiente canônico ou uma string legada que o * servidor normaliza ('prod', 'qa', 'homologacao'...). O `string & {}` preserva o * autocomplete dos quatro valores sem fechar a porta para o que já roda em campo * — e mantém os `satisfies z.ZodType<...>` da api fechando contra `z.string()`. */ type EnvironmentInput = Environment | (string & {}); /** * Snapshot dos recursos da máquina onde a instância roda. * * Arquivo-folha do protocolo (não importa nada): reexportado por `hobots/protocol` * e referenciado pelo heartbeat, pelo poll de tasks (`InstanceInfo.machine`) e por * `contexts.machine` nos eventos. Bytes em bytes; percentuais 0..100. Campo ausente = * não mensurável nesta plataforma/runtime. */ interface MachineProcess { pid: number; /** segundos desde o `init()` do SDK (Python) / início do processo (Node) */ uptime_s: number; /** memória residente do processo do bot */ rss_bytes?: number; /** CPU do processo, 0..100 normalizado pelo número de cores (delta entre coletas); null até haver 2 amostras */ cpu_percent?: number | null; /** só Node: `process.memoryUsage().heapUsed` */ heap_used_bytes?: number; /** só Python: `threading.active_count()` */ threads?: number; } interface MachineSnapshot { /** ISO 8601 — momento da coleta (relógio do cliente) */ sampled_at: string; /** `InitOptions.instanceId` — liga o snapshot de um evento à série da instância */ instance_id?: string; hostname?: string; /** `process.platform` / `sys.platform`: 'linux' | 'win32' | 'darwin' | ... */ os?: string; arch?: string; /** cores lógicos */ cpu_count?: number; /** uso de CPU do sistema, 0..100 — média entre duas coletas; null até haver 2 amostras */ cpu_percent?: number | null; /** load average de 1 min (POSIX; ausente no Windows) */ load_1?: number; mem_total_bytes?: number; mem_available_bytes?: number; /** (total - disponível) / total × 100 */ mem_percent?: number; /** volume medido — o diretório de trabalho do processo */ disk_path?: string; disk_total_bytes?: number; /** disponível para o usuário (bavail) */ disk_free_bytes?: number; disk_percent?: number; process: MachineProcess; /** de onde vieram os números */ source?: 'stdlib' | 'psutil' | 'stdlib-loadavg'; } /** * Tipos do protocolo de execuções do Hobots (agente SDK ↔ servidor). * * O agente é a própria tarefa: não há slug de task no wire. O que o agente faz é * identificado pelo client secret; a instância só declara COMO trabalha (`mode`). * * Este arquivo é a fonte de verdade do wire format e não pode importar nada: * o app valida os payloads com zod e trava o drift via `satisfies z.ZodType<...>` * contra estes tipos (reexportados por `hobots/protocol`). */ /** Ciclo de vida completo de uma run no servidor. */ type RunStatus = 'pending' | 'claimed' | 'running' | 'succeeded' | 'failed' | 'canceled'; /** Subconjunto que o agente pode enviar no PATCH. */ type RunUpdateStatus = 'running' | 'succeeded' | 'failed'; type RunLogLevel = 'debug' | 'info' | 'warning' | 'error' | 'success'; interface RunLogEntry { /** ISO 8601 — relógio do agente, apenas para exibição */ ts: string; level: RunLogLevel; message: string; /** * Ids dos anexos (imagens) desta linha — gerados pelo agente (32 hex) e criados via * `POST /v1/runs/{id}/attachments`. O upload roda em segundo plano: a linha pode * chegar ao servidor antes do binário estar no S3. */ attachments?: string[]; } /** Uma coluna da aba "itens" da execução: chave do payload dos itens + rótulo de exibição. */ interface ItemColumn { key: string; /** ausente = a plataforma exibe a própria key */ label?: string; } /** Como a instância trabalha: 'on_demand' = register (poll de solicitações); 'always_on' = start (abre a própria run). */ type InstanceMode = 'on_demand' | 'always_on'; /** Colunas de itens declaradas no código (`items.columns` do register/start). */ interface ItemsDeclaration { attributes: ItemColumn[]; } interface InstanceInfo { /** Identidade canônica do agente — correlaciona com o heartbeat de telemetria */ instance_id: string; name?: string; /** Versão do SDK */ version?: string; /** Hostname da máquina */ host?: string; /** Ambiente da instância — mesmo valor do heartbeat; agentes poll-only só o informam aqui */ environment?: EnvironmentInput; /** Modo de trabalho desta instância (register = on_demand, start = always_on) */ mode?: InstanceMode; /** Colunas de itens declaradas no código — só quando o register/start declarou `items` */ items?: ItemsDeclaration; /** * Intervalo de poll em ms — alimenta a tolerância de offline do servidor (3×) em * agentes poll-only, que sem isso herdariam a tolerância do heartbeat (30s × 3). */ poll_interval_ms?: number; /** Recursos da máquina no momento do poll — alimenta a série da instância em agentes sem heartbeat */ machine?: MachineSnapshot; } /** POST /v1/runs/poll */ interface PollRequest { instance?: InstanceInfo; /** Quantas runs reivindicar de uma vez (1..5). Default: 1 */ max?: number; } interface RunDescriptor { id: string; params: Record; form: { id: string; name: string; } | null; /** Origem da run: 'hobots' | 'link' | 'schedule' | 'agent' (informativo; 'agent' = aberta pelo próprio SDK, modo start) */ source: string; /** ISO 8601 (relógio do servidor) */ created_at: string; } interface PollResponse { runs: RunDescriptor[]; } /** * POST /v1/runs — modo start do SDK: a própria instância abre a run, que já * nasce 'running' (started_at = now), sem formulário nem solicitante. Dali em diante * ela é reportada pelas mesmas rotas de uma run reivindicada no poll. */ interface RunCreateRequest { /** presença da instância — obrigatória: a run nasce vinculada à instância */ instance: InstanceInfo; } /** Resposta (201): o mesmo descritor do poll, com params {}, form null e source 'agent'. */ type RunCreateResponse = RunDescriptor; interface RunError { /** ex.: nome da classe do erro */ type?: string; message: string; stack?: string; } /** * Progresso declarado pelo bot via `ctx.progress` — snapshot absoluto (o servidor * sobrescreve, não soma). Opcional: sem ele a plataforma não mostra barra nem ETA. */ interface RunProgress { /** itens já processados (0..total) */ current: number; /** total de itens previsto (>= 1) */ total: number; } /** PATCH /v1/runs/{id} — 'running' pode repetir com logs incrementais */ interface RunUpdateRequest { status: RunUpdateStatus; /** Apenas com status 'failed' */ error?: RunError; /** Delta desde o último envio — o servidor concatena */ logs?: RunLogEntry[]; /** Snapshot mais recente de `ctx.progress` — pega carona no PATCH que sair (≤ 1/s) */ progress?: RunProgress; } interface RunUpdateResponse { ok: true; } /** * Status de negócio de um item processado pela run: * - 'succeeded': processado com sucesso * - 'failed': falha técnica ao processar o item * - 'occurrence': ocorrência de negócio (ex.: "nota nº 10 não encontrada") */ type RunItemStatus = 'succeeded' | 'failed' | 'occurrence'; interface RunItemInput { /** * Identidade do item dentro da run — id de negócio do dev (ex.: nº da nota) * ou uuid4-hex gerado pelo SDK. Repetido na mesma run = upsert (vale o último reporte). */ id: string; /** Ordem de emissão no agente (contador monotônico por run) */ seq: number; status: RunItemStatus; /** Motivo — esperado em 'failed'/'occurrence' */ message?: string; /** Atributos definidos pelo dev; chaves configuráveis como colunas na plataforma */ payload?: Record; /** ISO 8601 — relógio do agente, apenas para exibição */ ts?: string; /** Ids de anexo (print do item) — opcional; mesmo teto por entrada das linhas de log */ attachments?: string[]; } /** POST /v1/runs/{id}/items — aceito mesmo com a run cancelada/terminal */ interface RunItemsCreateRequest { items: RunItemInput[]; } interface RunItemsCreateResponse { /** Itens gravados — inseridos ou atualizados (id repetido na run: vale o último reporte) */ accepted: number; /** Colapsados por id repetido dentro do mesmo lote (vale o de maior seq) */ duplicates: number; } /** Formatos aceitos para anexo. O S3 valida o content-type contra a assinatura. */ type RunAttachmentContentType = 'image/png' | 'image/jpeg' | 'image/webp'; /** POST /v1/runs/{id}/attachments */ interface RunAttachmentCreateRequest { /** Id do anexo gerado pelo agente (32 hex) — já referenciado no log/item/step que o carrega */ id: string; content_type: RunAttachmentContentType; /** Tamanho exato do binário; o PUT presignado é assinado com este Content-Length */ size_bytes: number; caption?: string; /** ISO 8601 — ts do evento (log/item/step) que referencia o anexo */ log_ts?: string; width?: number; height?: number; } interface RunAttachmentCreateResponse { id: string; /** URL presignada de PUT direto no S3 (não envie Authorization nesta requisição) */ upload_url: string; /** Headers obrigatórios no PUT — fazem parte da assinatura */ headers: Record; /** Validade da URL, em segundos */ expires_in: number; } /** PATCH /v1/runs/{id}/attachments/{attachmentId} */ interface RunAttachmentConfirmRequest { status: 'uploaded' | 'failed'; size_bytes?: number; width?: number; height?: number; } interface RunAttachmentConfirmResponse { ok: true; } /** * Onde o arquivo de um campo de upload está guardado: * - 's3': enviado pela Central — objeto temporário no S3; o bot baixa por URL * pré-assinada e confirma (DELETE), e o servidor apaga o objeto na hora. * - 'local': escolhido no Studio, no MESMO computador do bot — fica em * `$HOBOTS_LOCAL_FILES_DIR//` e nunca vai para a nuvem. */ type FileStorage = 's3' | 'local'; /** * Valor de um campo de upload nos params da run (campo único) — ou um array deles * (campo "vários arquivos"). Mesma forma do `FileRef` de `@workspace/task-forms`. */ interface FileRef { /** id do arquivo na run (no storage 'local', um uuid — nome da pasta em HOBOTS_LOCAL_FILES_DIR) */ id: string; /** nome original, como o usuário enviou */ name: string; /** tamanho em bytes */ size: number; contentType: string; storage: FileStorage; } /** * POST /v1/runs/{id}/files/{fileId}/download (corpo vazio) — 200 com a URL pré-assinada * de GET; 404 = arquivo não existe nesta run; 410 = já baixado (confirmado) ou expirado. * Depois do GET completo o agente confirma com DELETE /v1/runs/{id}/files/{fileId} * (204, idempotente), e o servidor apaga o objeto do S3. */ interface FileDownloadResponse { /** URL pré-assinada de GET direto no S3 (não envie Authorization nesta requisição) */ url: string; /** Validade da URL, em segundos */ expires_in: number; name: string; /** tamanho exato em bytes — o SDK confere o download contra ele */ size: number; content_type: string; } var MAX_ITEMS_PER_ENVELOPE = 50; var HEARTBEAT_DEFAULT_INTERVAL_MS = 30000; var HEARTBEAT_MIN_INTERVAL_MS = 1000; var HEARTBEAT_MAX_INTERVAL_MS = 900000; var MAX_CLAIM_PER_POLL = 5; var MAX_LOG_MESSAGE_CHARS = 10000; var MAX_LOGS_PER_PATCH = 100; var MAX_ERROR_MESSAGE_CHARS = 10000; var MAX_ERROR_STACK_CHARS = 20000; var MAX_ITEMS_PER_REQUEST = 500; var MAX_ITEM_MESSAGE_CHARS = 2000; var MAX_ITEM_PAYLOAD_BYTES = 16384; var MAX_ITEM_COLUMNS = 12; var MAX_ITEM_COLUMN_LABEL_CHARS = 60; var MAX_ATTACHMENT_BYTES = 5242880; var MAX_ATTACHMENTS_PER_RUN = 20; var MAX_ATTACHMENTS_PER_LOG_ENTRY = 4; var MAX_CAPTION_CHARS = 200; var MAX_IMAGE_DIMENSION_PX = 20000; var limits = { MAX_ITEMS_PER_ENVELOPE: MAX_ITEMS_PER_ENVELOPE, HEARTBEAT_DEFAULT_INTERVAL_MS: HEARTBEAT_DEFAULT_INTERVAL_MS, HEARTBEAT_MIN_INTERVAL_MS: HEARTBEAT_MIN_INTERVAL_MS, HEARTBEAT_MAX_INTERVAL_MS: HEARTBEAT_MAX_INTERVAL_MS, MAX_CLAIM_PER_POLL: MAX_CLAIM_PER_POLL, MAX_LOG_MESSAGE_CHARS: MAX_LOG_MESSAGE_CHARS, MAX_LOGS_PER_PATCH: MAX_LOGS_PER_PATCH, MAX_ERROR_MESSAGE_CHARS: MAX_ERROR_MESSAGE_CHARS, MAX_ERROR_STACK_CHARS: MAX_ERROR_STACK_CHARS, MAX_ITEMS_PER_REQUEST: MAX_ITEMS_PER_REQUEST, MAX_ITEM_MESSAGE_CHARS: MAX_ITEM_MESSAGE_CHARS, MAX_ITEM_PAYLOAD_BYTES: MAX_ITEM_PAYLOAD_BYTES, MAX_ITEM_COLUMNS: MAX_ITEM_COLUMNS, MAX_ITEM_COLUMN_LABEL_CHARS: MAX_ITEM_COLUMN_LABEL_CHARS, MAX_ATTACHMENT_BYTES: MAX_ATTACHMENT_BYTES, MAX_ATTACHMENTS_PER_RUN: MAX_ATTACHMENTS_PER_RUN, MAX_ATTACHMENTS_PER_LOG_ENTRY: MAX_ATTACHMENTS_PER_LOG_ENTRY, MAX_CAPTION_CHARS: MAX_CAPTION_CHARS, MAX_IMAGE_DIMENSION_PX: MAX_IMAGE_DIMENSION_PX }; /** * Limites do wire SDK ↔ servidor — fonte ÚNICA (protocol-limits.json): o SDK * Node lê daqui, a @hobots/api importa de `hobots/protocol` e o SDK Python * confere a paridade num teste que lê o mesmo JSON. Mudar um limite = mudar o * JSON (e, no Python, a constante espelhada — o teste acusa). */ declare const WIRE_LIMITS: Readonly; type WireLimits = typeof WIRE_LIMITS; /** * Tipos do protocolo do Hobots (SDK → servidor). * * Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida * os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles) * e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único * valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica. */ /** * Tipo de um evento — o que ele é, não o quanto ele fala. Só 'fatal', 'error' e * 'warning' viram issue; 'success' é ingerido e nunca abre issue. * Ruído de log não é evento: para isso existem os logs da execução (RunLogLevel) * e as breadcrumbs, que têm níveis próprios com 'debug'/'info'. */ type EventType = 'fatal' | 'error' | 'warning' | 'success'; /** Nível de uma breadcrumb — trilha do que aconteceu antes, aqui log é bem-vindo. */ type BreadcrumbLevel = 'debug' | 'info' | 'warning' | 'error' | 'fatal'; /** Frames em ordem innermost-first (mesma ordem impressa pelo V8). */ interface StackFrame { function?: string; filename?: string; lineno?: number; colno?: number; in_app: boolean; } interface Breadcrumb { /** ISO 8601 */ timestamp: string; type?: string; category?: string; message?: string; level?: BreadcrumbLevel; data?: Record; } interface ExceptionData { type: string; value: string; stacktrace?: { frames: StackFrame[]; }; } interface EventUser { id?: string; username?: string; email?: string; } interface EventPayload { /** uuid v4 sem hífens (32 hex), gerado pelo SDK */ event_id: string; /** ISO 8601 */ timestamp: string; type: EventType; message?: string; exception?: ExceptionData; /** Override de agrupamento; quando ausente o servidor calcula pelo stack trace */ fingerprint?: string[]; breadcrumbs?: Breadcrumb[]; tags?: Record; user?: EventUser; contexts?: Record>; extra?: Record; release?: string; environment?: EnvironmentInput; } /** Status de uma step (etapa). `warning` = terminou, mas merece atenção (não é falha). */ type StepStatus = 'ok' | 'warning' | 'error' | 'cancelled'; interface StepData { /** 16 hex */ step_id: string; parent_step_id?: string; op?: string; description?: string; status?: StepStatus; /** ISO 8601 */ start_timestamp: string; /** ISO 8601 (fim da step) */ timestamp: string; data?: Record; } interface TransactionPayload { event_id: string; name: string; op?: string; status: string; start_timestamp: string; timestamp: string; steps: StepData[]; tags?: Record; release?: string; environment?: EnvironmentInput; /** Correlaciona esta transaction a uma execução do agente (hobots.transaction dentro do handler) */ run_id?: string; } interface HeartbeatPayload { instance_id: string; name?: string; interval_ms: number; /** ISO 8601 */ timestamp: string; metadata?: Record; release?: string; /** Ambiente da instância — é ele que o app exibe e que as regras de alerta filtram */ environment?: EnvironmentInput; /** Recursos da máquina no momento do beat (CPU, memória, disco, processo) */ machine?: MachineSnapshot; } type EnvelopeItem = { type: 'event'; payload: EventPayload; } | { type: 'transaction'; payload: TransactionPayload; } | { type: 'heartbeat'; payload: HeartbeatPayload; }; interface Envelope { sdk: { name: string; version: string; }; /** ISO 8601 */ sent_at: string; items: EnvelopeItem[]; } export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, type FileDownloadResponse, type FileRef, type FileStorage, type HeartbeatPayload, type InstanceInfo, type InstanceMode, type ItemColumn, type ItemsDeclaration, type MachineProcess, type MachineSnapshot, type PollRequest, type PollResponse, type RunAttachmentConfirmRequest, type RunAttachmentConfirmResponse, type RunAttachmentContentType, type RunAttachmentCreateRequest, type RunAttachmentCreateResponse, type RunCreateRequest, type RunCreateResponse, type RunDescriptor, type RunError, type RunItemInput, type RunItemStatus, type RunItemsCreateRequest, type RunItemsCreateResponse, type RunLogEntry, type RunLogLevel, type RunProgress, type RunStatus, type RunUpdateRequest, type RunUpdateResponse, type RunUpdateStatus, type StackFrame, type StepData, type StepStatus, type TransactionPayload, WIRE_LIMITS, type WireLimits };