hobots 4.2.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -11
- package/dist/cli.cjs +250 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/index.cjs +796 -246
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +91 -229
- package/dist/index.d.ts +91 -229
- package/dist/index.js +796 -246
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +17 -3
- package/dist/protocol.d.ts +17 -3
- package/docs/README.md +2 -2
- package/docs/api-reference.md +25 -9
- package/docs/concepts.md +12 -12
- package/docs/getting-started.md +5 -3
- package/docs/protocol.md +16 -8
- package/docs/runs.md +97 -23
- package/package.json +4 -1
package/dist/protocol.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protocol.ts","../protocol-limits.json","../src/wire-limits.ts"],"sourcesContent":["/**\n * Tipos do protocolo do Hobots (SDK → servidor).\n *\n * Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida\n * os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles)\n * e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único\n * valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica.\n */\n\nexport { WIRE_LIMITS, type WireLimits } from './wire-limits';\n\nimport type { EnvironmentInput } from './environment-protocol';\nimport type { MachineSnapshot } from './machine-protocol';\n\n// Wire format de execuções (agente ↔ servidor) — reexportado aqui para o app\n// consumir tudo de `hobots/protocol`.\nexport type {\n RunStatus,\n RunUpdateStatus,\n RunLogLevel,\n RunLogEntry,\n InstanceInfo,\n PollRequest,\n RunDescriptor,\n PollResponse,\n RunCreateRequest,\n RunCreateResponse,\n RunError,\n RunProgress,\n RunUpdateRequest,\n RunUpdateResponse,\n RunItemStatus,\n RunItemInput,\n RunItemsCreateRequest,\n RunItemsCreateResponse,\n ItemColumn,\n ItemsDeclaration,\n InstanceMode,\n RunAttachmentContentType,\n RunAttachmentCreateRequest,\n RunAttachmentCreateResponse,\n RunAttachmentConfirmRequest,\n RunAttachmentConfirmResponse,\n FileStorage,\n FileRef,\n FileDownloadResponse,\n} from './tasks/protocol';\n\n// Snapshot de recursos da máquina — usado no heartbeat, no poll e em contexts.machine.\nexport type { MachineProcess, MachineSnapshot } from './machine-protocol';\nexport type { Environment, EnvironmentInput } from './environment-protocol';\n\n/**\n * Tipo de um evento — o que ele é, não o quanto ele fala. Só 'fatal', 'error' e\n * 'warning' viram issue; 'success' é ingerido e nunca abre issue.\n * Ruído de log não é evento: para isso existem os logs da execução (RunLogLevel)\n * e as breadcrumbs, que têm níveis próprios com 'debug'/'info'.\n */\nexport type EventType = 'fatal' | 'error' | 'warning' | 'success';\n\n/** Nível de uma breadcrumb — trilha do que aconteceu antes, aqui log é bem-vindo. */\nexport type BreadcrumbLevel = 'debug' | 'info' | 'warning' | 'error' | 'fatal';\n\n/** Frames em ordem innermost-first (mesma ordem impressa pelo V8). */\nexport interface StackFrame {\n function?: string;\n filename?: string;\n lineno?: number;\n colno?: number;\n in_app: boolean;\n}\n\nexport interface Breadcrumb {\n /** ISO 8601 */\n timestamp: string;\n type?: string;\n category?: string;\n message?: string;\n level?: BreadcrumbLevel;\n data?: Record<string, unknown>;\n}\n\nexport interface ExceptionData {\n type: string;\n value: string;\n stacktrace?: { frames: StackFrame[] };\n}\n\nexport interface EventUser {\n id?: string;\n username?: string;\n email?: string;\n}\n\nexport interface EventPayload {\n /** uuid v4 sem hífens (32 hex), gerado pelo SDK */\n event_id: string;\n /** ISO 8601 */\n timestamp: string;\n type: EventType;\n message?: string;\n exception?: ExceptionData;\n /** Override de agrupamento; quando ausente o servidor calcula pelo stack trace */\n fingerprint?: string[];\n breadcrumbs?: Breadcrumb[];\n tags?: Record<string, string>;\n user?: EventUser;\n contexts?: Record<string, Record<string, unknown>>;\n extra?: Record<string, unknown>;\n release?: string;\n environment?: EnvironmentInput;\n}\n\n/** Status de uma step (etapa). `warning` = terminou, mas merece atenção (não é falha). */\nexport type StepStatus = 'ok' | 'warning' | 'error' | 'cancelled';\n\nexport interface StepData {\n /** 16 hex */\n step_id: string;\n parent_step_id?: string;\n op?: string;\n description?: string;\n status?: StepStatus;\n /** ISO 8601 */\n start_timestamp: string;\n /** ISO 8601 (fim da step) */\n timestamp: string;\n data?: Record<string, unknown>;\n}\n\nexport interface TransactionPayload {\n event_id: string;\n name: string;\n op?: string;\n status: string;\n start_timestamp: string;\n timestamp: string;\n steps: StepData[];\n tags?: Record<string, string>;\n release?: string;\n environment?: EnvironmentInput;\n /** Correlaciona esta transaction a uma execução do agente (hobots.
|
|
1
|
+
{"version":3,"sources":["../src/protocol.ts","../protocol-limits.json","../src/wire-limits.ts"],"sourcesContent":["/**\n * Tipos do protocolo do Hobots (SDK → servidor).\n *\n * Este arquivo é a fonte de verdade do wire format: reexporta tipos (o app valida\n * os payloads com zod e trava o drift via `satisfies z.ZodType<...>` contra eles)\n * e os LIMITES numéricos do wire (WIRE_LIMITS, de protocol-limits.json) — o único\n * valor de runtime daqui, para a api aplicar exatamente os caps que o SDK aplica.\n */\n\nexport { WIRE_LIMITS, type WireLimits } from './wire-limits';\n\nimport type { EnvironmentInput } from './environment-protocol';\nimport type { MachineSnapshot } from './machine-protocol';\n\n// Wire format de execuções (agente ↔ servidor) — reexportado aqui para o app\n// consumir tudo de `hobots/protocol`.\nexport type {\n RunStatus,\n RunUpdateStatus,\n RunLogLevel,\n RunLogEntry,\n InstanceInfo,\n PollRequest,\n RunDescriptor,\n PollResponse,\n RunCreateRequest,\n RunCreateResponse,\n RunStartRequest,\n RunStartResponse,\n RunError,\n RunProgress,\n RunUpdateRequest,\n RunUpdateResponse,\n RunItemStatus,\n RunItemInput,\n RunItemsCreateRequest,\n RunItemsCreateResponse,\n ItemColumn,\n ItemsDeclaration,\n InstanceMode,\n RunAttachmentContentType,\n RunAttachmentCreateRequest,\n RunAttachmentCreateResponse,\n RunAttachmentConfirmRequest,\n RunAttachmentConfirmResponse,\n FileStorage,\n FileRef,\n FileDownloadResponse,\n} from './tasks/protocol';\n\n// Snapshot de recursos da máquina — usado no heartbeat, no poll e em contexts.machine.\nexport type { MachineProcess, MachineSnapshot } from './machine-protocol';\nexport type { Environment, EnvironmentInput } from './environment-protocol';\n\n/**\n * Tipo de um evento — o que ele é, não o quanto ele fala. Só 'fatal', 'error' e\n * 'warning' viram issue; 'success' é ingerido e nunca abre issue.\n * Ruído de log não é evento: para isso existem os logs da execução (RunLogLevel)\n * e as breadcrumbs, que têm níveis próprios com 'debug'/'info'.\n */\nexport type EventType = 'fatal' | 'error' | 'warning' | 'success';\n\n/** Nível de uma breadcrumb — trilha do que aconteceu antes, aqui log é bem-vindo. */\nexport type BreadcrumbLevel = 'debug' | 'info' | 'warning' | 'error' | 'fatal';\n\n/** Frames em ordem innermost-first (mesma ordem impressa pelo V8). */\nexport interface StackFrame {\n function?: string;\n filename?: string;\n lineno?: number;\n colno?: number;\n in_app: boolean;\n}\n\nexport interface Breadcrumb {\n /** ISO 8601 */\n timestamp: string;\n type?: string;\n category?: string;\n message?: string;\n level?: BreadcrumbLevel;\n data?: Record<string, unknown>;\n}\n\nexport interface ExceptionData {\n type: string;\n value: string;\n stacktrace?: { frames: StackFrame[] };\n}\n\nexport interface EventUser {\n id?: string;\n username?: string;\n email?: string;\n}\n\nexport interface EventPayload {\n /** uuid v4 sem hífens (32 hex), gerado pelo SDK */\n event_id: string;\n /** ISO 8601 */\n timestamp: string;\n type: EventType;\n message?: string;\n exception?: ExceptionData;\n /** Override de agrupamento; quando ausente o servidor calcula pelo stack trace */\n fingerprint?: string[];\n breadcrumbs?: Breadcrumb[];\n tags?: Record<string, string>;\n user?: EventUser;\n contexts?: Record<string, Record<string, unknown>>;\n extra?: Record<string, unknown>;\n release?: string;\n environment?: EnvironmentInput;\n}\n\n/** Status de uma step (etapa). `warning` = terminou, mas merece atenção (não é falha). */\nexport type StepStatus = 'ok' | 'warning' | 'error' | 'cancelled';\n\nexport interface StepData {\n /** 16 hex */\n step_id: string;\n parent_step_id?: string;\n op?: string;\n description?: string;\n status?: StepStatus;\n /** ISO 8601 */\n start_timestamp: string;\n /** ISO 8601 (fim da step) */\n timestamp: string;\n data?: Record<string, unknown>;\n}\n\nexport interface TransactionPayload {\n event_id: string;\n name: string;\n op?: string;\n status: string;\n start_timestamp: string;\n timestamp: string;\n steps: StepData[];\n tags?: Record<string, string>;\n release?: string;\n environment?: EnvironmentInput;\n /** Correlaciona esta transaction a uma execução do agente (as etapas de hobots.step dentro do handler) */\n run_id?: string;\n}\n\nexport interface HeartbeatPayload {\n instance_id: string;\n name?: string;\n interval_ms: number;\n /** ISO 8601 */\n timestamp: string;\n metadata?: Record<string, unknown>;\n release?: string;\n /** Ambiente da instância — é ele que o app exibe e que as regras de alerta filtram */\n environment?: EnvironmentInput;\n /** Recursos da máquina no momento do beat (CPU, memória, disco, processo) */\n machine?: MachineSnapshot;\n}\n\nexport type EnvelopeItem =\n | { type: 'event'; payload: EventPayload }\n | { type: 'transaction'; payload: TransactionPayload }\n | { type: 'heartbeat'; payload: HeartbeatPayload };\n\nexport interface Envelope {\n sdk: { name: string; version: string };\n /** ISO 8601 */\n sent_at: string;\n items: EnvelopeItem[];\n}\n","{\n \"MAX_ITEMS_PER_ENVELOPE\": 50,\n \"HEARTBEAT_DEFAULT_INTERVAL_MS\": 30000,\n \"HEARTBEAT_MIN_INTERVAL_MS\": 1000,\n \"HEARTBEAT_MAX_INTERVAL_MS\": 900000,\n \"MAX_CLAIM_PER_POLL\": 5,\n \"MAX_LOG_MESSAGE_CHARS\": 10000,\n \"MAX_LOGS_PER_PATCH\": 100,\n \"MAX_ERROR_MESSAGE_CHARS\": 10000,\n \"MAX_ERROR_STACK_CHARS\": 20000,\n \"MAX_ITEMS_PER_REQUEST\": 500,\n \"MAX_ITEM_MESSAGE_CHARS\": 2000,\n \"MAX_ITEM_PAYLOAD_BYTES\": 16384,\n \"MAX_ITEM_COLUMNS\": 12,\n \"MAX_ITEM_COLUMN_LABEL_CHARS\": 60,\n \"MAX_ATTACHMENT_BYTES\": 5242880,\n \"MAX_ATTACHMENTS_PER_RUN\": 20,\n \"MAX_ATTACHMENTS_PER_LOG_ENTRY\": 4,\n \"MAX_CAPTION_CHARS\": 200,\n \"MAX_IMAGE_DIMENSION_PX\": 20000\n}\n","import limits from '../protocol-limits.json';\n\n/**\n * Limites do wire SDK ↔ servidor — fonte ÚNICA (protocol-limits.json): o SDK\n * Node lê daqui, a @hobots/api importa de `hobots/protocol` e o SDK Python\n * confere a paridade num teste que lê o mesmo JSON. Mudar um limite = mudar o\n * JSON (e, no Python, a constante espelhada — o teste acusa).\n */\nexport const WIRE_LIMITS = limits as Readonly<typeof limits>;\nexport type WireLimits = typeof WIRE_LIMITS;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA,EACE,wBAA0B;AAAA,EAC1B,+BAAiC;AAAA,EACjC,2BAA6B;AAAA,EAC7B,2BAA6B;AAAA,EAC7B,oBAAsB;AAAA,EACtB,uBAAyB;AAAA,EACzB,oBAAsB;AAAA,EACtB,yBAA2B;AAAA,EAC3B,uBAAyB;AAAA,EACzB,uBAAyB;AAAA,EACzB,wBAA0B;AAAA,EAC1B,wBAA0B;AAAA,EAC1B,kBAAoB;AAAA,EACpB,6BAA+B;AAAA,EAC/B,sBAAwB;AAAA,EACxB,yBAA2B;AAAA,EAC3B,+BAAiC;AAAA,EACjC,mBAAqB;AAAA,EACrB,wBAA0B;AAC5B;;;ACZO,IAAM,cAAc;","names":[]}
|
package/dist/protocol.d.cts
CHANGED
|
@@ -146,7 +146,10 @@ interface RunDescriptor {
|
|
|
146
146
|
id: string;
|
|
147
147
|
name: string;
|
|
148
148
|
} | null;
|
|
149
|
-
/**
|
|
149
|
+
/**
|
|
150
|
+
* Origem da run: 'hobots' | 'link' | 'schedule' | 'agent' | 'local' (informativo; 'agent' = aberta pelo
|
|
151
|
+
* próprio SDK no modo start; 'local' = modo local, sem Central — nunca chega ao servidor)
|
|
152
|
+
*/
|
|
150
153
|
source: string;
|
|
151
154
|
/** ISO 8601 (relógio do servidor) */
|
|
152
155
|
created_at: string;
|
|
@@ -165,6 +168,17 @@ interface RunCreateRequest {
|
|
|
165
168
|
}
|
|
166
169
|
/** Resposta (201): o mesmo descritor do poll, com params {}, form null e source 'agent'. */
|
|
167
170
|
type RunCreateResponse = RunDescriptor;
|
|
171
|
+
/**
|
|
172
|
+
* POST /v1/runs/:id/start — a run foi criada já reivindicada para esta instância
|
|
173
|
+
* (o Studio sobe o bot com HOBOTS_RUN_ID) e o processo se anexa a ela em vez de
|
|
174
|
+
* fazer poll. 409 = cancelada, já iniciada ou de outra instância; 404 = não existe.
|
|
175
|
+
*/
|
|
176
|
+
interface RunStartRequest {
|
|
177
|
+
/** presença da instância — a mesma do poll */
|
|
178
|
+
instance: InstanceInfo;
|
|
179
|
+
}
|
|
180
|
+
/** Resposta (200): o mesmo descritor do poll. */
|
|
181
|
+
type RunStartResponse = RunDescriptor;
|
|
168
182
|
interface RunError {
|
|
169
183
|
/** ex.: nome da classe do erro */
|
|
170
184
|
type?: string;
|
|
@@ -443,7 +457,7 @@ interface TransactionPayload {
|
|
|
443
457
|
tags?: Record<string, string>;
|
|
444
458
|
release?: string;
|
|
445
459
|
environment?: EnvironmentInput;
|
|
446
|
-
/** Correlaciona esta transaction a uma execução do agente (hobots.
|
|
460
|
+
/** Correlaciona esta transaction a uma execução do agente (as etapas de hobots.step dentro do handler) */
|
|
447
461
|
run_id?: string;
|
|
448
462
|
}
|
|
449
463
|
interface HeartbeatPayload {
|
|
@@ -479,4 +493,4 @@ interface Envelope {
|
|
|
479
493
|
items: EnvelopeItem[];
|
|
480
494
|
}
|
|
481
495
|
|
|
482
|
-
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 };
|
|
496
|
+
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 RunStartRequest, type RunStartResponse, type RunStatus, type RunUpdateRequest, type RunUpdateResponse, type RunUpdateStatus, type StackFrame, type StepData, type StepStatus, type TransactionPayload, WIRE_LIMITS, type WireLimits };
|
package/dist/protocol.d.ts
CHANGED
|
@@ -146,7 +146,10 @@ interface RunDescriptor {
|
|
|
146
146
|
id: string;
|
|
147
147
|
name: string;
|
|
148
148
|
} | null;
|
|
149
|
-
/**
|
|
149
|
+
/**
|
|
150
|
+
* Origem da run: 'hobots' | 'link' | 'schedule' | 'agent' | 'local' (informativo; 'agent' = aberta pelo
|
|
151
|
+
* próprio SDK no modo start; 'local' = modo local, sem Central — nunca chega ao servidor)
|
|
152
|
+
*/
|
|
150
153
|
source: string;
|
|
151
154
|
/** ISO 8601 (relógio do servidor) */
|
|
152
155
|
created_at: string;
|
|
@@ -165,6 +168,17 @@ interface RunCreateRequest {
|
|
|
165
168
|
}
|
|
166
169
|
/** Resposta (201): o mesmo descritor do poll, com params {}, form null e source 'agent'. */
|
|
167
170
|
type RunCreateResponse = RunDescriptor;
|
|
171
|
+
/**
|
|
172
|
+
* POST /v1/runs/:id/start — a run foi criada já reivindicada para esta instância
|
|
173
|
+
* (o Studio sobe o bot com HOBOTS_RUN_ID) e o processo se anexa a ela em vez de
|
|
174
|
+
* fazer poll. 409 = cancelada, já iniciada ou de outra instância; 404 = não existe.
|
|
175
|
+
*/
|
|
176
|
+
interface RunStartRequest {
|
|
177
|
+
/** presença da instância — a mesma do poll */
|
|
178
|
+
instance: InstanceInfo;
|
|
179
|
+
}
|
|
180
|
+
/** Resposta (200): o mesmo descritor do poll. */
|
|
181
|
+
type RunStartResponse = RunDescriptor;
|
|
168
182
|
interface RunError {
|
|
169
183
|
/** ex.: nome da classe do erro */
|
|
170
184
|
type?: string;
|
|
@@ -443,7 +457,7 @@ interface TransactionPayload {
|
|
|
443
457
|
tags?: Record<string, string>;
|
|
444
458
|
release?: string;
|
|
445
459
|
environment?: EnvironmentInput;
|
|
446
|
-
/** Correlaciona esta transaction a uma execução do agente (hobots.
|
|
460
|
+
/** Correlaciona esta transaction a uma execução do agente (as etapas de hobots.step dentro do handler) */
|
|
447
461
|
run_id?: string;
|
|
448
462
|
}
|
|
449
463
|
interface HeartbeatPayload {
|
|
@@ -479,4 +493,4 @@ interface Envelope {
|
|
|
479
493
|
items: EnvelopeItem[];
|
|
480
494
|
}
|
|
481
495
|
|
|
482
|
-
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 };
|
|
496
|
+
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 RunStartRequest, type RunStartResponse, type RunStatus, type RunUpdateRequest, type RunUpdateResponse, type RunUpdateStatus, type StackFrame, type StepData, type StepStatus, type TransactionPayload, WIRE_LIMITS, type WireLimits };
|
package/docs/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
SDK JavaScript da **Hobots** para robôs (RPAs) e integrações. Cliente HTTP puro, sem dependências de runtime, Node 18+.
|
|
4
4
|
|
|
5
|
-
**O agente é a própria tarefa.** Não existe `init()` nem slug: a única chamada a `register()`/`start()` configura o processo (credenciais do ambiente, heartbeat sempre ligado, captura de erros não tratados) e diz o que o robô faz. O objeto global `hobots` expõe a execução atual — `hobots.log`, `hobots.items`, `hobots.progress`, `hobots.
|
|
5
|
+
**O agente é a própria tarefa.** Não existe `init()` nem slug: a única chamada a `register()`/`start()` configura o processo (credenciais do ambiente, heartbeat sempre ligado, captura de erros não tratados) e diz o que o robô faz. O objeto global `hobots` expõe a execução atual — `hobots.log`, `hobots.items`, `hobots.progress`, `hobots.step`… — de qualquer lugar do programa.
|
|
6
6
|
|
|
7
7
|
| Modo | Chamada | Para quê |
|
|
8
8
|
| --- | --- | --- |
|
|
@@ -15,7 +15,7 @@ Uma chamada por processo: um processo é um agente, e um agente faz uma coisa.
|
|
|
15
15
|
|
|
16
16
|
- [Getting started](./getting-started.md) — instalação, envs, o primeiro agente nos dois modos, encerramento.
|
|
17
17
|
- [Execuções](./runs.md) — handler, o objeto `hobots`, itens, progresso, anexos, cancelamento automático, retry, concorrência, idempotência.
|
|
18
|
-
- [Conceitos](./concepts.md) — o vocabulário: agente, execução, evento, issue,
|
|
18
|
+
- [Conceitos](./concepts.md) — o vocabulário: agente, execução, evento, issue, etapa, heartbeat, instância, claim.
|
|
19
19
|
- [Referência de API](./api-reference.md) — assinaturas, tabelas de opções e tempos.
|
|
20
20
|
- [Protocolo & transporte](./protocol.md) — Client Secret, endpoints (`/v1/ingest`, `/v1/runs/*`), envelope, retries, claim atômico.
|
|
21
21
|
|
package/docs/api-reference.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
| Import | Conteúdo |
|
|
6
6
|
| --- | --- |
|
|
7
|
-
| `hobots` | `hobots` (default e named), `register`, `start`, `close`, `captureException`, `retry`, `image` e os tipos. |
|
|
7
|
+
| `hobots` | `hobots` (default e named), `register`, `start`, `close`, `captureException`, `retry`, `image`, `isFileRef` e os tipos. |
|
|
8
8
|
| `hobots/protocol` | Tipos do wire format (telemetria e execuções). |
|
|
9
9
|
|
|
10
10
|
ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois do `register()`/`start()`, `globalThis.hobots` também existe (tipado via `declare global`).
|
|
@@ -18,7 +18,9 @@ ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois do
|
|
|
18
18
|
| `hobots.close` | `(timeoutMs = 30_000) => Promise<boolean>` | Para o polling, espera as execuções em voo (até `timeoutMs`; as restantes viram `AgentTerminated`), para o heartbeat e faz o flush final. `false` se estourou. Um `register`/`start` depois inicia um runtime novo. |
|
|
19
19
|
| `hobots.captureException` | `(error: unknown, hint?: CaptureHint) => string \| undefined` | Issue no módulo Issues; devolve o `event_id`. Antes de iniciar o agente: descarta com aviso. |
|
|
20
20
|
| `hobots.retry` | `<T>(fn: (attempt: number) => T \| Promise<T>, options?: RetryOptions) => Promise<T>` | async-retry; dentro de uma execução usa o signal dela. |
|
|
21
|
-
| `hobots.
|
|
21
|
+
| `hobots.step` | `<T>(name: string, fn: (etapa: StepHandle) => T \| Promise<T>, options?: StepOptions) => Promise<T>` | Registra a etapa `name` executando `fn`, com nova tentativa quando ela lança (`retries` default 1, `retryDelayMs` default 5_000). Resolve com o retorno de `fn`. Fora de uma execução: aviso único e roda `fn` com o mesmo retry, sem registrar nada. Ver [Execuções](./runs.md#etapas-hobotsstep). |
|
|
22
|
+
| `hobots.flush` | `(timeoutMs = 15_000) => Promise<void>` | Envia **agora** o que a execução atual acumulou: etapas raiz finalizadas viram transactions parciais (op `hobots.run.flush`), itens, logs e progresso pendentes saem sem esperar o throttle. Aguarda a entrega até `timeoutMs`. Nunca lança; fora de uma execução não faz nada. Feito para o modo start, a cada ciclo. |
|
|
23
|
+
| `hobots.image` | `(input: AttachInput, options?: ImageOptions) => ImageAttachment` | Embrulha um print para ir junto de um log, item ou etapa. Puro, nunca lança. |
|
|
22
24
|
| `isFileRef` / `hobots.isFileRef` | `(value: unknown) => value is FileRef` | Reconhece um arquivo de campo de upload nos params. Puro. |
|
|
23
25
|
|
|
24
26
|
## Contexto da execução (`RunContext` — os membros de `hobots` e o `ctx` do handler)
|
|
@@ -28,17 +30,17 @@ ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois do
|
|
|
28
30
|
| `runId` | `string` | Identidade da execução (`''` fora de uma execução) |
|
|
29
31
|
| `params` | `Record<string, unknown>` | Params da solicitação (formulário do agente); `{}` no modo start |
|
|
30
32
|
| `log` | `RunLogger` — `debug/info/warn/error/success(message, ...rest)` | Nunca lança. Vários argumentos viram texto unidos por espaço (como `console.log`); um `hobots.image(...)` no **último** argumento vira o print da linha. Eco no terminal: `[hobots] INFO …` |
|
|
31
|
-
| `items` | `RunItems` — `add(item)`, `succeeded(payload?, opts?)`, `failed(message, payload?, opts?)`, `occurrence(message, payload?, opts?)`; `opts.id` = identidade de negócio, `opts.image` = print do item. `each(list, (element, item, index) => …, { id?, payload?, op?, description?, progress? }) => Promise<{ total, succeeded, failed, occurrence }>` processa a lista inteira: exceção no handler vira item `failed` +
|
|
33
|
+
| `items` | `RunItems` — `add(item)`, `succeeded(payload?, opts?)`, `failed(message, payload?, opts?)`, `occurrence(message, payload?, opts?)`; `opts.id` = identidade de negócio, `opts.image` = print do item. `each(list, (element, item, index) => …, { id?, payload?, op?, description?, progress? }) => Promise<{ total, succeeded, failed, occurrence }>` processa a lista inteira: exceção no handler vira item `failed` + etapa em erro e o loop segue; `item: RunItemHandle` = `succeeded(payload?, { image }?)/failed(msg, payload?, { image }?)/occurrence(…)`, `id`, `index`, `step` (`StepHandle` da etapa do item), `reported` | Ponto de parada cooperativo (o `each` para só em cancelamento/timeout) |
|
|
32
34
|
| `progress` | `RunProgressReporter` — `total(n)`, `advance(count = 1)`, `set(current, total?)`, `current`, `snapshot` | `total/advance/set` são pontos de parada |
|
|
33
35
|
| `files` | `RunFiles` — `list(): FileRef[]`, `get(field): FileRef \| FileRef[] \| undefined`, `download(refOrField: FileRef \| string, { dest? }?): Promise<string>`, `downloadAll(field, { dest? }?): Promise<string[]>`, `read(refOrField): Promise<Buffer>` | Arquivos do formulário; o download consome a origem (S3 confirmado/apagado, pasta do Studio removida). Cópias sem `dest` são apagadas no fim da execução. Respeita o `signal`. Ver [Execuções](./runs.md#arquivos-do-formulário-hobotsfiles) |
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
36
|
+
| `step(name, fn, options?)` | `<T>(name: string, fn: StepFn<T>, options?: { retries?: number; retryDelayMs?: RetryDelay }) => Promise<T>` — uma etapa no waterfall: abre, roda `fn(etapa)`, tenta de novo se lançar (`retries` default 1; 0 desliga), fecha. `warning` + `data.message` + `data.attempts` quando a nova tentativa deu certo; `error` + `data.error = { type, message }` quando esgotou (a exceção sobe); `cancelled` em cancelamento/timeout. `StepHandle` = `warning(message, { image }?)`, `image(png)`, `data(key, value)` (`attachments` reservada). Aninha automaticamente na etapa corrente. | Ponto de parada (lança `RunCanceled`) |
|
|
37
|
+
| `flush` | `(timeoutMs = 15_000) => Promise<void>` — envia já as etapas raiz finalizadas (transactions parciais, op `hobots.run.flush`) e os itens/logs/progresso pendentes | Nunca lança |
|
|
36
38
|
| `signal` | `AbortSignal` | Cancelamento (app, timeout, shutdown) |
|
|
37
39
|
| `throwIfCanceled()` | `() => void` | Lança `RunCanceled` se o signal disparou |
|
|
38
40
|
| `sleep(ms)` | `(ms: number) => Promise<void>` | Rejeita com `RunCanceled` no cancelamento |
|
|
39
41
|
| `retry(fn, options?)` | como `hobots.retry` | |
|
|
40
42
|
|
|
41
|
-
`AttachInput = Uint8Array \| ArrayBuffer \| string` (caminho); `ImageOptions = { caption?, contentType? }`; `ImageInput = AttachInput \| ImageAttachment` é o que `log.*` (só o embrulho), `items.*` e `step.setStatus/
|
|
43
|
+
`AttachInput = Uint8Array \| ArrayBuffer \| string` (caminho); `ImageOptions = { caption?, contentType? }`; `ImageInput = AttachInput \| ImageAttachment` é o que `log.*` (só o embrulho), `items.*` e `step.setStatus/failed` aceitam. O upload (segundo plano, nunca bloqueia) acontece quando o evento é registrado.
|
|
42
44
|
|
|
43
45
|
Fora de uma execução, `hobots.*` cai em fallbacks seguros com aviso único por membro (log ecoa no terminal, imagem descartada; items/progress no-op; `signal` nunca aborta).
|
|
44
46
|
|
|
@@ -50,7 +52,7 @@ Só há uma chamada por processo, então todas as opções são **do agente**. O
|
|
|
50
52
|
|
|
51
53
|
| Opção | Tipo | Default | Descrição |
|
|
52
54
|
| --- | --- | --- | --- |
|
|
53
|
-
| `clientSecret` | `string` | env `HOBOTS_CLIENT_SECRET` | `hb_<64 hex>`; ausente/inválido lança citando a env (sem ecoar o valor) |
|
|
55
|
+
| `clientSecret` | `string` | env `HOBOTS_CLIENT_SECRET` | `hb_<64 hex>`; ausente/inválido lança citando a env (sem ecoar o valor). Ignorado com `HOBOTS_LOCAL_RUN=1` ([modo local](./runs.md#modo-local-teste-sem-a-central)) |
|
|
54
56
|
| `instanceId` | `string` | env `HOBOTS_INSTANCE_ID` → `os.hostname()` | identidade estável da instância |
|
|
55
57
|
| `environment` | `'development' \| 'testing' \| 'staging' \| 'production' \| string` | `'production'` | vai em eventos, transactions e na instância; filtra alertas |
|
|
56
58
|
| `release` | `string` | — | versão do programa |
|
|
@@ -78,6 +80,20 @@ Só há uma chamada por processo, então todas as opções são **do agente**. O
|
|
|
78
80
|
| --- | --- | --- | --- |
|
|
79
81
|
| `concurrency` | `number` | `1` | execuções simultâneas do agente (1..5) |
|
|
80
82
|
| `pollIntervalMs` | `number` | `2_000` (mín. 1_000) | intervalo entre polls sem trabalho |
|
|
83
|
+
| `runId` | `string` | env `HOBOTS_RUN_ID` | avançado: executa só esta run (já reivindicada para a instância, ex.: pelo Studio) em vez de fazer poll — `POST /v1/runs/{id}/start`, handler uma vez e `close()`; 404/409 encerram sem rodar o handler. Ignorado no modo local |
|
|
84
|
+
|
|
85
|
+
### Envs sem opção equivalente
|
|
86
|
+
|
|
87
|
+
| Env | Efeito |
|
|
88
|
+
| --- | --- |
|
|
89
|
+
| `HOBOTS_API_URL` | só em desenvolvimento: outro host da API |
|
|
90
|
+
| `HOBOTS_LOCAL_RUN` | `1` = modo local (teste sem a Central): handler uma vez, sem rede, exit code pelo desfecho — ver [Execuções](./runs.md#modo-local-teste-sem-a-central) |
|
|
91
|
+
| `HOBOTS_RUN_PARAMS` | modo local: objeto JSON dos params (ausente = `{}`); inválido → stderr + exit 2 |
|
|
92
|
+
| `HOBOTS_LOCAL_FILES_DIR` | pasta dos arquivos `storage: 'local'` deixados pelo Studio (`<dir>/<uuid>/<nome>`) |
|
|
93
|
+
|
|
94
|
+
### CLI
|
|
95
|
+
|
|
96
|
+
`npx hobots run <entry.js> [--params <arquivo.json>] [--param <chave>=<valor>]... [--file <campo>=<caminho>]... [--reset-ledger] [-- <args do bot>]` — roda o bot no modo local com o mesmo Node; exit code do bot (2 em uso errado). Detalhes em [Execuções → Modo local](./runs.md#a-cli-hobots-run).
|
|
81
97
|
|
|
82
98
|
`StartOptions = RunOptions`.
|
|
83
99
|
|
|
@@ -119,9 +135,9 @@ type RunHandler<P = Record<string, unknown>> = (params: P, ctx: RunContext) => v
|
|
|
119
135
|
| --- | --- |
|
|
120
136
|
| Heartbeat | 30 s (±10 % de jitter), sempre ligado, timer ref'd (segura o processo) |
|
|
121
137
|
| Flush da telemetria | 2 s ou 10 itens; envelopes de até 50 itens; fila de 200 |
|
|
122
|
-
| Retry HTTP (ingest, PATCH, itens, anexos) | 1 s / 4 s / 16 s com jitter; 4xx ≠ 429 é definitivo |
|
|
138
|
+
| Retry HTTP (ingest, PATCH, itens, anexos) | 1 s / 4 s / 16 s com jitter; 4xx ≠ 429 é definitivo; no registro de anexo, 429/501/503 (cota / anexos desabilitados) também são definitivos |
|
|
123
139
|
| Poll sem trabalho | `pollIntervalMs` (2 s); com trabalho, imediato (drain) |
|
|
124
|
-
| Poll/criação de run com erro | 1 s / 4 s / 16 s; 401 → 30 s com erro logado na 1ª e a cada 10 falhas |
|
|
140
|
+
| Poll/criação de run com erro | 1 s / 4 s / 16 s; 401 (Client Secret rejeitado) e 402 (agente fora do limite do plano) → 30 s com erro logado na 1ª e a cada 10 falhas |
|
|
125
141
|
| Logs da execução | flush a cada `logFlushIntervalMs` (2 s) ou 20 linhas; chunks de 100; 1000 por execução no servidor |
|
|
126
142
|
| Cancel-watch / sinal de vida | `cancelCheckIntervalMs` (5 s); o servidor marca `AgentTerminated` após ~120 s sem PATCH |
|
|
127
143
|
| Retry do handler | `retries` 1, `retryDelayMs` 5 s |
|
package/docs/concepts.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Conceitos
|
|
2
2
|
|
|
3
|
-
Esta página explica **o que cada coisa é** — o vocabulário que as outras páginas usam: agente, execução, item, evento, issue,
|
|
3
|
+
Esta página explica **o que cada coisa é** — o vocabulário que as outras páginas usam: agente, execução, item, evento, issue, etapa, heartbeat, instância, claim. As outras páginas mostram **como usar**; aqui está o **por que existe**.
|
|
4
4
|
|
|
5
5
|
Defaults numéricos vivem em [Tempos e intervalos](./api-reference.md#tempos-e-intervalos) e nas [tabelas de opções](./api-reference.md#tabelas-de-opções).
|
|
6
6
|
|
|
@@ -15,11 +15,11 @@ Defaults numéricos vivem em [Tempos e intervalos](./api-reference.md#tempos-e-i
|
|
|
15
15
|
| [Item](#item) | Uma unidade de trabalho entregue | Cada nota, boleto, arquivo processado |
|
|
16
16
|
| [Progresso](#progresso) | Quantos de quantos | Barra e tempo restante no app |
|
|
17
17
|
| [Log da execução](#log-da-execução) | Narração do que a execução fez | `hobots.log` — nunca lança |
|
|
18
|
-
| [Anexo](#anexo) | Um print pendurado num log, item ou
|
|
19
|
-
| [Cancelamento cooperativo](#cancelamento-cooperativo) | O app pede, o handler para no próximo ponto de parada | Automático em items/progress/
|
|
18
|
+
| [Anexo](#anexo) | Um print pendurado num log, item ou etapa | "Como estava a tela?" |
|
|
19
|
+
| [Cancelamento cooperativo](#cancelamento-cooperativo) | O app pede, o handler para no próximo ponto de parada | Automático em items/progress/step/sleep/retry |
|
|
20
20
|
| [Retry](#retry) | Tentar de novo na mesma execução | Instabilidade passageira |
|
|
21
21
|
| [Evento e issue](#evento-e-issue) | A foto de um erro, agrupada em issue | `hobots.captureException` e erros não tratados |
|
|
22
|
-
| [
|
|
22
|
+
| [Etapa](#etapa) (e a [transaction](#transaction) por trás) | Quanto demorou e onde o tempo foi — com nova tentativa | `hobots.step` |
|
|
23
23
|
| [Heartbeat](#heartbeat) | Batimento "estou vivo", sempre ligado | Saber que o robô está de pé |
|
|
24
24
|
| [instanceId](#instanceid) | A identidade da instância do robô | Env `HOBOTS_INSTANCE_ID` |
|
|
25
25
|
| [Release e environment](#release-e-environment) | Qual versão, em qual ambiente | Separar produção de homologação |
|
|
@@ -31,11 +31,11 @@ Defaults numéricos vivem em [Tempos e intervalos](./api-reference.md#tempos-e-i
|
|
|
31
31
|
|
|
32
32
|
| No SDK | No app |
|
|
33
33
|
| --- | --- |
|
|
34
|
-
| **Agente** — dono do Client Secret (`hb_…`) que autentica tudo; o que ele faz é o handler de `register()`/`start()` | **Configurações →
|
|
34
|
+
| **Agente** — dono do Client Secret (`hb_…`) que autentica tudo; o que ele faz é o handler de `register()`/`start()` | No agente, **Configurações**: aba **agente → credenciais** (Client Secret) e **formulário** |
|
|
35
35
|
| **Instância** — o par `(agente, instanceId)`; heartbeat e execuções convergem nela, com o modo (sob demanda / sempre ligado) | Módulo **Instâncias** (uptime, recursos da máquina, performance) |
|
|
36
36
|
| **Execução** — cada solicitação atendida por `register()`, ou a execução que `start()` abre sozinho | Módulo **Trabalhos** |
|
|
37
37
|
| **Evento** agrupado em **issue** — `captureException` e erros não tratados | Módulo **Issues** |
|
|
38
|
-
| **
|
|
38
|
+
| **Etapas** — `hobots.step` | Aba de performance da execução (waterfall) |
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
@@ -75,11 +75,11 @@ O **log da execução** narra o que aconteceu, em linhas com nível (`debug`, `i
|
|
|
75
75
|
|
|
76
76
|
## Anexo
|
|
77
77
|
|
|
78
|
-
Um **anexo** é uma imagem — na prática, um print — vinculada ao evento que ela ilustra: uma linha de log, um item ou uma
|
|
78
|
+
Um **anexo** é uma imagem — na prática, um print — vinculada ao evento que ela ilustra: uma linha de log, um item ou uma etapa. Responde "como estava a tela?" quando texto não basta. Quem captura é o seu código (Playwright, Puppeteer, um arquivo); o SDK sobe direto para o S3 por URL presignada, em segundo plano, sem atrasar o log. Enquanto sobe, o app mostra "enviando imagem…".
|
|
79
79
|
|
|
80
80
|
## Cancelamento cooperativo
|
|
81
81
|
|
|
82
|
-
Cancelar no app **não mata** o handler — o SDK não tem como interromper código arbitrário com segurança (um navegador aberto, uma transação pela metade). O que ele faz: detecta o cancelamento (o PATCH periódico recebe 409), dispara `hobots.signal` e faz o próximo **ponto de parada** lançar `RunCanceled`. Os pontos de parada são as fronteiras naturais de trabalho: registrar um item, avançar o progresso, abrir uma
|
|
82
|
+
Cancelar no app **não mata** o handler — o SDK não tem como interromper código arbitrário com segurança (um navegador aberto, uma transação pela metade). O que ele faz: detecta o cancelamento (o PATCH periódico recebe 409), dispara `hobots.signal` e faz o próximo **ponto de parada** lançar `RunCanceled`. Os pontos de parada são as fronteiras naturais de trabalho: registrar um item, avançar o progresso, abrir uma etapa, dormir, tentar de novo. Por isso, num loop comum, o cancelamento funciona sem nenhuma linha extra. `hobots.log` nunca é ponto de parada. Se o handler ignorar o signal por tempo demais (`cancelGraceMs`), o SDK libera o slot e o handler vira um zumbi cujos reportes são descartados.
|
|
83
83
|
|
|
84
84
|
## Retry
|
|
85
85
|
|
|
@@ -89,13 +89,13 @@ Uma falha do handler costuma ser passageira (portal instável, rede). O SDK **te
|
|
|
89
89
|
|
|
90
90
|
Um **evento** é a foto de um erro: tipo, mensagem, stack trace, tags, ambiente, release e como estava a máquina. `hobots.captureException(erro)` cria um; erros não tratados (`uncaughtException`, `unhandledRejection`) também. Eventos parecidos são agrupados em uma **issue** pelo servidor (por stack trace, ou pelo `fingerprint` que você definir). O `type` diz o que ele é: `fatal`, `error` e `warning` abrem issue e podem alertar; `success` é registrado e nunca alerta. Log não é evento — narração fica no log da execução.
|
|
91
91
|
|
|
92
|
-
##
|
|
92
|
+
## Etapa
|
|
93
93
|
|
|
94
|
-
Uma **
|
|
94
|
+
Uma **etapa** é um trecho medido da execução com nome de negócio — "Entrar no portal", "Buscar pedido 123". A execução diz que levou 4 minutos; as etapas dizem que 3min40 foram esperando o portal. `hobots.step(nome, fn)` é a única chamada: o SDK abre a etapa, roda `fn`, **tenta de novo** se ela lançar (1 tentativa extra por padrão; `retries: 0` desliga) e fecha. Uma etapa só na Central cobre todas as tentativas: `warning` com o motivo quando a nova tentativa deu certo (e `attempts`), `error` quando esgotou (a exceção sobe), `cancelled` em cancelamento/timeout. `hobots.step` dentro de outra etapa vira sub-etapa; dentro do handler de `items.each`, sub-etapa da etapa do item. A função recebe o handle `etapa` para o que o SDK não vê sozinho: `warning(motivo)`, `image(png)`, `data(chave, valor)`. No app isso vira o **waterfall** da execução. Abrir uma etapa é um ponto de parada cooperativo. A etapa não entra no aviso de erro no topo do trabalho — ela aparece na aba de performance.
|
|
95
95
|
|
|
96
|
-
##
|
|
96
|
+
## Transaction
|
|
97
97
|
|
|
98
|
-
Uma **
|
|
98
|
+
Uma **transaction** é o envelope do wire que carrega as etapas: cada execução tem exatamente uma, chamada `run` (op `hobots.run`), aberta e finalizada pelo SDK e correlacionada à execução pelo `run_id`. Você não a vê nem cria — só registra etapas com `hobots.step`. Num agente sempre ligado, `hobots.flush()` envia as etapas raiz já terminadas como transactions parciais (op `hobots.run.flush`).
|
|
99
99
|
|
|
100
100
|
## Heartbeat
|
|
101
101
|
|
package/docs/getting-started.md
CHANGED
|
@@ -21,7 +21,7 @@ Sem dependências de runtime. Requer **Node 18+** (usa o `fetch` global).
|
|
|
21
21
|
|
|
22
22
|
## Credenciais
|
|
23
23
|
|
|
24
|
-
Cada agente tem **um Client Secret** (`hb_<64 hex>`), copiado em **Configurações →
|
|
24
|
+
Cada agente tem **um Client Secret** (`hb_<64 hex>`), copiado na Central em **agente → Configurações → agente → aba credenciais**. O SDK lê do ambiente:
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
export HOBOTS_CLIENT_SECRET=hb_<64 hex>
|
|
@@ -30,9 +30,11 @@ export HOBOTS_INSTANCE_ID=vm-cliente-01 # opcional — sem ela, o hostname
|
|
|
30
30
|
|
|
31
31
|
Também dá para passar `clientSecret`/`instanceId` nas opções de `register()`/`start()` (o snippet do app já vem assim). Em desenvolvimento, `HOBOTS_API_URL=http://localhost:3001` aponta para outra API; em produção é sempre `https://api2.hobots.app`.
|
|
32
32
|
|
|
33
|
+
As envs também podem ficar num `.env` na pasta de onde o bot roda: o SDK carrega o arquivo sozinho no import (sem `dotenv`); a env já definida no ambiente vence o arquivo.
|
|
34
|
+
|
|
33
35
|
## Primeiro agente sob demanda (`register`)
|
|
34
36
|
|
|
35
|
-
1. No app, abra o agente em **Configurações →
|
|
37
|
+
1. No app, abra o agente em **Configurações → formulário** e monte o **formulário do agente** (os campos que cada solicitação vai carregar).
|
|
36
38
|
2. No robô:
|
|
37
39
|
|
|
38
40
|
```js
|
|
@@ -74,4 +76,4 @@ O robô abre a própria execução ao iniciar e ela aparece em **Trabalhos** com
|
|
|
74
76
|
|
|
75
77
|
`hobots.close(timeoutMs?)` para o polling, espera as execuções em voo, para o heartbeat e faz o flush final. Sem handler próprio de `SIGINT`/`SIGTERM`, o SDK reporta as execuções ativas como `AgentTerminated` antes do processo morrer.
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
A seguir: [Execuções](./runs.md) para etapas, itens, progresso, anexos, cancelamento e retry; [Referência de API](./api-reference.md) para todas as opções.
|
package/docs/protocol.md
CHANGED
|
@@ -38,7 +38,7 @@ Endpoint fixo `POST /v1/ingest` recebe **envelopes** JSON autenticados por Beare
|
|
|
38
38
|
|
|
39
39
|
Tipos de item: `event`, `transaction`, `heartbeat` (definidos em `hobots/protocol`).
|
|
40
40
|
|
|
41
|
-
Todo `transaction` carrega `run_id`: é assim que a [transaction da execução](./concepts.md#transaction) (`hobots.
|
|
41
|
+
Todo `transaction` carrega `run_id`: é assim que a [transaction da execução](./concepts.md#transaction) (aberta pelo SDK; as etapas vêm de `hobots.step`) é correlacionada, e o que permite o app montar o waterfall de performance dentro da solicitação. Cada etapa (`StepData`) vai sem `op`, com `description` = nome (recortado em 2048 no cliente) e, quando houve mais de uma tentativa, `data.attempts`.
|
|
42
42
|
|
|
43
43
|
`items` aceita de 1 a **50** itens por envelope — acima disso a API responde `422`. O `maxBatchSize` é só o gatilho do flush: quando a fila tem mais que esse teto (burst de captures, ou fila acumulada durante uma janela de rede ruim), o transport a fatia em lotes de 50 e faz um POST por lote.
|
|
44
44
|
|
|
@@ -96,7 +96,7 @@ Resposta `PollResponse` = `{ runs: RunDescriptor[] }`, cada `{ id, params, form,
|
|
|
96
96
|
|
|
97
97
|
O `instance.instance_id` é a **mesma identidade** do heartbeat de telemetria (`instance_id`): o servidor correlaciona os dois canais numa tabela `instances` por `(agent_id, instance_id)`. Os dois derivam do mesmo `instanceId` — o robô aparece como um agente só no painel. O próprio poll também marca a presença da instância (`last_poll_at`). Um processo no modo `start()` nunca faz poll.
|
|
98
98
|
|
|
99
|
-
**Backoff:** um request por poll; o loop decide o ritmo. HTTP 401 (key rejeitada) → retry lento a 30s com log throttled; outros erros → ladder `[1s, 4s, 16s]`.
|
|
99
|
+
**Backoff:** um request por poll; o loop decide o ritmo. HTTP 401 (key rejeitada) e 402 (agente fora do limite do plano) → retry lento a 30s com log throttled; outros erros → ladder `[1s, 4s, 16s]`.
|
|
100
100
|
|
|
101
101
|
### `POST /v1/runs`
|
|
102
102
|
|
|
@@ -106,6 +106,14 @@ Modo `start`: a instância abre a **própria run**. Corpo `RunCreateRequest` —
|
|
|
106
106
|
- `touchInstance` roda antes do insert (presença); se falhar, a API responde `503` e o SDK insiste com o ladder do poll (o handler só começa quando a run existe). Corpo vazio ou sem `instance.instance_id` → `422`.
|
|
107
107
|
- Sem dedupe: um processo reiniciado em menos de 120 s deixa a run anterior `running` até o sweep marcá-la `AgentTerminated`. O app não oferece "reexecutar" para runs `agent` — ninguém faria poll por elas.
|
|
108
108
|
|
|
109
|
+
### `POST /v1/runs/{id}/start`
|
|
110
|
+
|
|
111
|
+
`register()` com env `HOBOTS_RUN_ID` (ou a opção `runId`): a run já foi criada **reivindicada para esta instância** (o Studio executa o bot sob demanda sem que ele faça poll) e o processo se anexa a ela. Corpo `RunStartRequest` — `{ "instance": { /* InstanceInfo, o mesmo do poll */ } }`. Resposta `200` `RunStartResponse` = o mesmo `RunDescriptor` do poll.
|
|
112
|
+
|
|
113
|
+
- `404` = a run não existe; `409` = cancelada, já iniciada ou de outra instância. Os dois (e qualquer outro 4xx ≠ 429) encerram o SDK **sem** rodar o handler, com o motivo no log.
|
|
114
|
+
- Rede, timeout, `5xx` e `429`: até 4 tentativas (esperas de 1 s/4 s/16 s com jitter); esgotadas, o SDK desiste e encerra.
|
|
115
|
+
- Dali em diante a run é reportada pelas rotas abaixo; terminada, o SDK faz `close()` e o processo sai.
|
|
116
|
+
|
|
109
117
|
### `PATCH /v1/runs/{id}`
|
|
110
118
|
|
|
111
119
|
Corpo `RunUpdateRequest`:
|
|
@@ -135,7 +143,7 @@ Ciclo de vida completo da run no servidor (`RunStatus`): `pending → claimed
|
|
|
135
143
|
|
|
136
144
|
### `POST /v1/runs/{id}/items`
|
|
137
145
|
|
|
138
|
-
Registra em lote os **itens de execução** (a entrega do bot — `hobots.items` no SDK).
|
|
146
|
+
Registra em lote os **itens de execução** (a entrega do bot — `hobots.items` no SDK). Upsert por `(run, id)`: um `id` repetido na mesma run atualiza o item (vale o último reporte — o bot que tenta de novo corrige `failed` → `succeeded`); reenvio idêntico (retry de rede) não mexe nos contadores.
|
|
139
147
|
|
|
140
148
|
Corpo `RunItemsCreateRequest`:
|
|
141
149
|
|
|
@@ -157,11 +165,11 @@ Corpo `RunItemsCreateRequest`:
|
|
|
157
165
|
|
|
158
166
|
Resposta `200` `RunItemsCreateResponse`: `{ "accepted": 1, "duplicates": 0 }` — `duplicates` conta os colapsados por `(run, id)` repetido no mesmo lote (vale o último reporte; no banco é upsert).
|
|
159
167
|
|
|
160
|
-
- `attachments` é **opcional** e aditivo (uma API anterior ao recurso descarta o campo). As
|
|
168
|
+
- `attachments` é **opcional** e aditivo (uma API anterior ao recurso descarta o campo). As etapas carregam o print do mesmo jeito, em `data.attachments` do `StepData` que vai no `POST /v1/ingest` da transaction — sem campo novo no wire.
|
|
161
169
|
|
|
162
170
|
- **Run cancelada/terminal aceita itens** (200): item é fato de trabalho já feito — mesmo racional do log tardio. Esta rota não tem 409.
|
|
163
171
|
- O insert e os **contadores materializados** da run (`items_total/succeeded/failed/occurrence`, que alimentam os totalizadores no app) saem num único statement atômico no servidor.
|
|
164
|
-
- Retry `[1s, 4s, 16s]` para rede/5xx; `404` = servidor sem o recurso (o SDK degrada em silêncio); `402` = armazenamento do plano esgotado. Não há teto de itens por run.
|
|
172
|
+
- Retry `[1s, 4s, 16s]` para rede/5xx; `404` = servidor sem o recurso (o SDK degrada em silêncio); `402` = armazenamento do plano esgotado (sem retry: o SDK descarta o lote com um aviso por episódio e segue enviando os próximos). Não há teto de itens por run.
|
|
165
173
|
|
|
166
174
|
| Status | Quando |
|
|
167
175
|
| --- | --- |
|
|
@@ -179,11 +187,11 @@ Corpo `RunAttachmentCreateRequest`:
|
|
|
179
187
|
|
|
180
188
|
```jsonc
|
|
181
189
|
{
|
|
182
|
-
"id": "<32 hex>", // gerado pelo agente, já referenciado no log/item/
|
|
190
|
+
"id": "<32 hex>", // gerado pelo agente, já referenciado no log/item/etapa
|
|
183
191
|
"content_type": "image/png", // 'image/png' | 'image/jpeg' | 'image/webp'
|
|
184
192
|
"size_bytes": 184320, // exato — entra na assinatura da URL
|
|
185
193
|
"caption": "portal após o login", // opcional, máx. 500
|
|
186
|
-
"log_ts": "…", // opcional, ISO 8601 — ts do evento (log/item/
|
|
194
|
+
"log_ts": "…", // opcional, ISO 8601 — ts do evento (log/item/etapa)
|
|
187
195
|
"width": 1920, "height": 1080 // opcionais
|
|
188
196
|
}
|
|
189
197
|
```
|
|
@@ -218,7 +226,7 @@ Confirma o upload. Corpo `RunAttachmentConfirmRequest`: `{ "status": "uploaded"
|
|
|
218
226
|
|
|
219
227
|
É **conforto de UX**, não correção: enquanto não confirmado, o app mostra a miniatura como "enviando imagem…". O agente engole falhas desta chamada.
|
|
220
228
|
|
|
221
|
-
Limites de anexo (aplicados no SDK **e** no servidor): PNG/JPEG/WEBP, 5 MB por imagem, 20 por execução, 4 por evento (linha de log, item ou
|
|
229
|
+
Limites de anexo (aplicados no SDK **e** no servidor): PNG/JPEG/WEBP, 5 MB por imagem, 20 por execução, 4 por evento (linha de log, item ou etapa).
|
|
222
230
|
|
|
223
231
|
### `POST /v1/runs/{id}/files/{fileId}/download`
|
|
224
232
|
|