hobots 2.4.0 → 3.2.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 +116 -367
- package/dist/index.cjs +1385 -909
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +252 -225
- package/dist/index.d.ts +252 -225
- package/dist/index.js +1385 -909
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +27 -2
- package/dist/protocol.d.ts +27 -2
- package/docs/README.md +16 -33
- package/docs/api-reference.md +75 -213
- package/docs/concepts.md +60 -393
- package/docs/getting-started.md +38 -84
- package/docs/protocol.md +31 -19
- package/docs/tasks.md +102 -247
- package/package.json +2 -2
- package/docs/telemetry.md +0 -162
package/dist/protocol.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protocol.ts"],"sourcesContent":["/**\n * Tipos do protocolo do Hobots (SDK → servidor).\n *\n * Este arquivo é a fonte de verdade do wire format e só pode reexportar tipos:\n * o app valida os payloads com zod e trava o drift via `satisfies z.ZodType<...>`\n * contra estes tipos (importados de `hobots/protocol`).\n */\n\nimport type { EnvironmentInput } from './environment-protocol';\nimport type { MachineSnapshot } from './machine-protocol';\n\n// Wire format de tasks (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 RunError,\n RunProgress,\n RunUpdateRequest,\n RunUpdateResponse,\n RunItemStatus,\n RunItemInput,\n RunItemsCreateRequest,\n RunItemsCreateResponse,\n RunAttachmentContentType,\n RunAttachmentCreateRequest,\n RunAttachmentCreateResponse,\n RunAttachmentConfirmRequest,\n RunAttachmentConfirmResponse,\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 de task (ctx.tx dentro de um task 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"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/protocol.ts"],"sourcesContent":["/**\n * Tipos do protocolo do Hobots (SDK → servidor).\n *\n * Este arquivo é a fonte de verdade do wire format e só pode reexportar tipos:\n * o app valida os payloads com zod e trava o drift via `satisfies z.ZodType<...>`\n * contra estes tipos (importados de `hobots/protocol`).\n */\n\nimport type { EnvironmentInput } from './environment-protocol';\nimport type { MachineSnapshot } from './machine-protocol';\n\n// Wire format de tasks (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 TaskItemsDeclaration,\n RunAttachmentContentType,\n RunAttachmentCreateRequest,\n RunAttachmentCreateResponse,\n RunAttachmentConfirmRequest,\n RunAttachmentConfirmResponse,\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 de task (ctx.tx dentro de um task 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"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
package/dist/protocol.d.cts
CHANGED
|
@@ -96,6 +96,16 @@ interface RunLogEntry {
|
|
|
96
96
|
*/
|
|
97
97
|
attachments?: string[];
|
|
98
98
|
}
|
|
99
|
+
/** Uma coluna da aba "itens" da execução: chave do payload dos itens + rótulo de exibição. */
|
|
100
|
+
interface ItemColumn {
|
|
101
|
+
key: string;
|
|
102
|
+
/** ausente = a plataforma exibe a própria key */
|
|
103
|
+
label?: string;
|
|
104
|
+
}
|
|
105
|
+
/** Colunas de itens declaradas no código para uma task (`items.columns` do register/start). */
|
|
106
|
+
interface TaskItemsDeclaration {
|
|
107
|
+
attributes: ItemColumn[];
|
|
108
|
+
}
|
|
99
109
|
interface InstanceInfo {
|
|
100
110
|
/** Identidade canônica do agente — correlaciona com o heartbeat de telemetria */
|
|
101
111
|
instance_id: string;
|
|
@@ -108,6 +118,8 @@ interface InstanceInfo {
|
|
|
108
118
|
environment?: EnvironmentInput;
|
|
109
119
|
/** Tasks registradas no agente */
|
|
110
120
|
tasks?: string[];
|
|
121
|
+
/** Colunas de itens declaradas no código, por task — só as tasks que declararam `items` */
|
|
122
|
+
task_items?: Record<string, TaskItemsDeclaration>;
|
|
111
123
|
/**
|
|
112
124
|
* Intervalo de poll em ms — alimenta a tolerância de offline do servidor (3×) em
|
|
113
125
|
* agentes poll-only, que sem isso herdariam a tolerância do heartbeat (30s × 3).
|
|
@@ -132,7 +144,7 @@ interface RunDescriptor {
|
|
|
132
144
|
id: string;
|
|
133
145
|
name: string;
|
|
134
146
|
} | null;
|
|
135
|
-
/** Origem da run: 'hobots' | 'link' | 'schedule' (informativo) */
|
|
147
|
+
/** Origem da run: 'hobots' | 'link' | 'schedule' | 'agent' (informativo; 'agent' = aberta pelo próprio SDK, modo start) */
|
|
136
148
|
source: string;
|
|
137
149
|
/** ISO 8601 (relógio do servidor) */
|
|
138
150
|
created_at: string;
|
|
@@ -140,6 +152,19 @@ interface RunDescriptor {
|
|
|
140
152
|
interface PollResponse {
|
|
141
153
|
runs: RunDescriptor[];
|
|
142
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* POST /v1/tasks/runs — modo start do SDK: a própria instância abre a run, que já
|
|
157
|
+
* nasce 'running' (started_at = now), sem formulário nem solicitante. Dali em diante
|
|
158
|
+
* ela é reportada pelas mesmas rotas de uma run reivindicada no poll.
|
|
159
|
+
*/
|
|
160
|
+
interface RunCreateRequest {
|
|
161
|
+
/** slug da task (1..255) — vira task_runs.task_slug */
|
|
162
|
+
task: string;
|
|
163
|
+
/** presença da instância — obrigatória: a run nasce vinculada à instância */
|
|
164
|
+
instance: InstanceInfo;
|
|
165
|
+
}
|
|
166
|
+
/** Resposta (201): o mesmo descritor do poll, com params {}, form null e source 'agent'. */
|
|
167
|
+
type RunCreateResponse = RunDescriptor;
|
|
143
168
|
interface RunError {
|
|
144
169
|
/** ex.: nome da classe do erro */
|
|
145
170
|
type?: string;
|
|
@@ -363,4 +388,4 @@ interface Envelope {
|
|
|
363
388
|
items: EnvelopeItem[];
|
|
364
389
|
}
|
|
365
390
|
|
|
366
|
-
export type { Breadcrumb, BreadcrumbLevel, Envelope, EnvelopeItem, Environment, EnvironmentInput, EventPayload, EventType, EventUser, ExceptionData, HeartbeatPayload, InstanceInfo, MachineProcess, MachineSnapshot, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentContentType, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunDescriptor, RunError, RunItemInput, RunItemStatus, RunItemsCreateRequest, RunItemsCreateResponse, RunLogEntry, RunLogLevel, RunProgress, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame, StepData, StepStatus, TransactionPayload };
|
|
391
|
+
export type { Breadcrumb, BreadcrumbLevel, Envelope, EnvelopeItem, Environment, EnvironmentInput, EventPayload, EventType, EventUser, ExceptionData, HeartbeatPayload, InstanceInfo, ItemColumn, MachineProcess, MachineSnapshot, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentContentType, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunCreateRequest, RunCreateResponse, RunDescriptor, RunError, RunItemInput, RunItemStatus, RunItemsCreateRequest, RunItemsCreateResponse, RunLogEntry, RunLogLevel, RunProgress, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame, StepData, StepStatus, TaskItemsDeclaration, TransactionPayload };
|
package/dist/protocol.d.ts
CHANGED
|
@@ -96,6 +96,16 @@ interface RunLogEntry {
|
|
|
96
96
|
*/
|
|
97
97
|
attachments?: string[];
|
|
98
98
|
}
|
|
99
|
+
/** Uma coluna da aba "itens" da execução: chave do payload dos itens + rótulo de exibição. */
|
|
100
|
+
interface ItemColumn {
|
|
101
|
+
key: string;
|
|
102
|
+
/** ausente = a plataforma exibe a própria key */
|
|
103
|
+
label?: string;
|
|
104
|
+
}
|
|
105
|
+
/** Colunas de itens declaradas no código para uma task (`items.columns` do register/start). */
|
|
106
|
+
interface TaskItemsDeclaration {
|
|
107
|
+
attributes: ItemColumn[];
|
|
108
|
+
}
|
|
99
109
|
interface InstanceInfo {
|
|
100
110
|
/** Identidade canônica do agente — correlaciona com o heartbeat de telemetria */
|
|
101
111
|
instance_id: string;
|
|
@@ -108,6 +118,8 @@ interface InstanceInfo {
|
|
|
108
118
|
environment?: EnvironmentInput;
|
|
109
119
|
/** Tasks registradas no agente */
|
|
110
120
|
tasks?: string[];
|
|
121
|
+
/** Colunas de itens declaradas no código, por task — só as tasks que declararam `items` */
|
|
122
|
+
task_items?: Record<string, TaskItemsDeclaration>;
|
|
111
123
|
/**
|
|
112
124
|
* Intervalo de poll em ms — alimenta a tolerância de offline do servidor (3×) em
|
|
113
125
|
* agentes poll-only, que sem isso herdariam a tolerância do heartbeat (30s × 3).
|
|
@@ -132,7 +144,7 @@ interface RunDescriptor {
|
|
|
132
144
|
id: string;
|
|
133
145
|
name: string;
|
|
134
146
|
} | null;
|
|
135
|
-
/** Origem da run: 'hobots' | 'link' | 'schedule' (informativo) */
|
|
147
|
+
/** Origem da run: 'hobots' | 'link' | 'schedule' | 'agent' (informativo; 'agent' = aberta pelo próprio SDK, modo start) */
|
|
136
148
|
source: string;
|
|
137
149
|
/** ISO 8601 (relógio do servidor) */
|
|
138
150
|
created_at: string;
|
|
@@ -140,6 +152,19 @@ interface RunDescriptor {
|
|
|
140
152
|
interface PollResponse {
|
|
141
153
|
runs: RunDescriptor[];
|
|
142
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* POST /v1/tasks/runs — modo start do SDK: a própria instância abre a run, que já
|
|
157
|
+
* nasce 'running' (started_at = now), sem formulário nem solicitante. Dali em diante
|
|
158
|
+
* ela é reportada pelas mesmas rotas de uma run reivindicada no poll.
|
|
159
|
+
*/
|
|
160
|
+
interface RunCreateRequest {
|
|
161
|
+
/** slug da task (1..255) — vira task_runs.task_slug */
|
|
162
|
+
task: string;
|
|
163
|
+
/** presença da instância — obrigatória: a run nasce vinculada à instância */
|
|
164
|
+
instance: InstanceInfo;
|
|
165
|
+
}
|
|
166
|
+
/** Resposta (201): o mesmo descritor do poll, com params {}, form null e source 'agent'. */
|
|
167
|
+
type RunCreateResponse = RunDescriptor;
|
|
143
168
|
interface RunError {
|
|
144
169
|
/** ex.: nome da classe do erro */
|
|
145
170
|
type?: string;
|
|
@@ -363,4 +388,4 @@ interface Envelope {
|
|
|
363
388
|
items: EnvelopeItem[];
|
|
364
389
|
}
|
|
365
390
|
|
|
366
|
-
export type { Breadcrumb, BreadcrumbLevel, Envelope, EnvelopeItem, Environment, EnvironmentInput, EventPayload, EventType, EventUser, ExceptionData, HeartbeatPayload, InstanceInfo, MachineProcess, MachineSnapshot, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentContentType, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunDescriptor, RunError, RunItemInput, RunItemStatus, RunItemsCreateRequest, RunItemsCreateResponse, RunLogEntry, RunLogLevel, RunProgress, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame, StepData, StepStatus, TransactionPayload };
|
|
391
|
+
export type { Breadcrumb, BreadcrumbLevel, Envelope, EnvelopeItem, Environment, EnvironmentInput, EventPayload, EventType, EventUser, ExceptionData, HeartbeatPayload, InstanceInfo, ItemColumn, MachineProcess, MachineSnapshot, PollRequest, PollResponse, RunAttachmentConfirmRequest, RunAttachmentConfirmResponse, RunAttachmentContentType, RunAttachmentCreateRequest, RunAttachmentCreateResponse, RunCreateRequest, RunCreateResponse, RunDescriptor, RunError, RunItemInput, RunItemStatus, RunItemsCreateRequest, RunItemsCreateResponse, RunLogEntry, RunLogLevel, RunProgress, RunStatus, RunUpdateRequest, RunUpdateResponse, RunUpdateStatus, StackFrame, StepData, StepStatus, TaskItemsDeclaration, TransactionPayload };
|
package/docs/README.md
CHANGED
|
@@ -1,49 +1,32 @@
|
|
|
1
1
|
# Documentação — hobots
|
|
2
2
|
|
|
3
|
-
SDK JavaScript da **Hobots** para
|
|
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
|
-
|
|
5
|
+
**Tudo é uma task.** Não existe `init()`: a primeira chamada a `register()`/`start()` configura o processo (credenciais do ambiente, heartbeat sempre ligado, captura de erros não tratados). O objeto global `hobots` expõe a execução atual — `hobots.log`, `hobots.items`, `hobots.progress`, `hobots.transaction`… — de qualquer lugar do programa.
|
|
6
6
|
|
|
7
|
-
|
|
|
7
|
+
| Modo | Chamada | Para quê |
|
|
8
8
|
| --- | --- | --- |
|
|
9
|
-
| **
|
|
10
|
-
| **
|
|
9
|
+
| **Sob demanda** | `hobots.register(task, handler, options?)` | O robô faz polling e executa uma solicitação do app (formulário/agendamento) por vez — módulo **Solicitações**. |
|
|
10
|
+
| **Sempre ligado** | `hobots.start(task, handler, options?)` | O robô abre a própria execução e roda o handler (o seu loop) dentro dela; a plataforma recebe logs, itens e progresso. |
|
|
11
11
|
|
|
12
12
|
## Páginas
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- [Conceitos](./concepts.md) — o vocabulário:
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [Tasks](./tasks.md) — registro de handlers, `RunContext`, cancelamento, concorrência, idempotência.
|
|
20
|
-
- [Referência de API](./api-reference.md) — todas as funções e tabelas de opções com defaults.
|
|
21
|
-
- [Protocolo & transporte](./protocol.md) — o Client Secret, endpoints, envelope, retries e onde vive o claim atômico.
|
|
14
|
+
- [Getting started](./getting-started.md) — instalação, envs, primeira task nos dois modos, encerramento.
|
|
15
|
+
- [Tasks](./tasks.md) — handler, o objeto `hobots`, itens, progresso, anexos, cancelamento automático, retry, concorrência, idempotência.
|
|
16
|
+
- [Conceitos](./concepts.md) — o vocabulário: task, execução, evento, issue, transaction, step, heartbeat, instância, claim.
|
|
17
|
+
- [Referência de API](./api-reference.md) — assinaturas, tabelas de opções e tempos.
|
|
18
|
+
- [Protocolo & transporte](./protocol.md) — Client Secret, endpoints (`/v1/ingest`, `/v1/tasks/*`), envelope, retries, claim atômico.
|
|
22
19
|
|
|
23
20
|
## Exemplo mínimo
|
|
24
21
|
|
|
25
22
|
```js
|
|
26
|
-
import
|
|
27
|
-
|
|
28
|
-
// O Client Secret do agente — copie em Configurações → Agentes no app
|
|
29
|
-
const clientSecret = 'hb_<64 hex>';
|
|
30
|
-
|
|
31
|
-
// Um init só: telemetria sempre ativa; tasks habilita a execução sob demanda.
|
|
32
|
-
// O instanceId é a identidade única — o robô aparece como um agente só no painel.
|
|
33
|
-
Hobots.init({
|
|
34
|
-
clientSecret,
|
|
35
|
-
instanceId: 'vm-cliente-01',
|
|
36
|
-
heartbeat: true,
|
|
37
|
-
tasks: true,
|
|
38
|
-
});
|
|
23
|
+
import hobots from 'hobots'; // HOBOTS_CLIENT_SECRET e HOBOTS_INSTANCE_ID no ambiente
|
|
39
24
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
25
|
+
hobots.register('processar-nfe', async params => {
|
|
26
|
+
hobots.log.info(`processando lote ${params.lote}…`);
|
|
27
|
+
hobots.items.succeeded({ numero_nota: '123' }, { id: '123' });
|
|
28
|
+
hobots.log.success('concluído'); // o retorno do handler é ignorado — reporte por log/itens
|
|
43
29
|
});
|
|
44
|
-
Hobots.start(); // mantém o processo vivo aguardando execuções
|
|
45
30
|
```
|
|
46
31
|
|
|
47
|
-
> Exemplos runnable
|
|
48
|
-
> [`full.ts`](../../hobots-sdk-demos/src/full.ts)) estão em
|
|
49
|
-
> [`packages/hobots-sdk-demos`](../../hobots-sdk-demos).
|
|
32
|
+
> Exemplos runnable em [`packages/hobots-sdk-demos`](../../hobots-sdk-demos).
|
package/docs/api-reference.md
CHANGED
|
@@ -4,247 +4,109 @@
|
|
|
4
4
|
|
|
5
5
|
| Import | Conteúdo |
|
|
6
6
|
| --- | --- |
|
|
7
|
-
| `hobots` |
|
|
7
|
+
| `hobots` | `hobots` (default e named), `register`, `start`, `close`, `captureException`, `retry` e os tipos. |
|
|
8
8
|
| `hobots/protocol` | Tipos do wire format (telemetria e tasks). |
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois da primeira task, `globalThis.hobots` também existe (tipado via `declare global`).
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Funções do processo
|
|
13
13
|
|
|
14
|
-
| Função | Assinatura |
|
|
14
|
+
| Função | Assinatura | Notas |
|
|
15
15
|
| --- | --- | --- |
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `setTag` / `setTags` | `setTag(key, value)` · `setTags(tags)` | — |
|
|
22
|
-
| `setUser` | `setUser(user: EventUser \| null): void` | — |
|
|
23
|
-
| `setContext` | `setContext(name: string, ctx: Record<string,unknown> \| null): void` | — |
|
|
24
|
-
| `setExtra` | `setExtra(key: string, value: unknown): void` | — |
|
|
25
|
-
| `withScope` | `withScope<T>(cb: (scope: Scope) => T): T` | retorno do callback |
|
|
26
|
-
| `startTransaction` | `startTransaction(name: string, op?: string): Transaction` | transaction (dentro de um handler de task, a própria `ctx.tx`) |
|
|
27
|
-
| `flush` | `flush(timeoutMs = 5_000): Promise<boolean>` | enviou tudo dentro do prazo? |
|
|
28
|
-
| `close` | `close(timeoutMs = 5_000): Promise<boolean>` | para o polling de tasks (aguarda runs) + heartbeat + flush final do transport |
|
|
29
|
-
|
|
30
|
-
### O que cada função faz
|
|
31
|
-
|
|
32
|
-
Os conceitos por trás dessas chamadas estão em [Conceitos](./concepts.md); aqui está o que cada uma **faz** e o que **devolve**.
|
|
33
|
-
|
|
34
|
-
- **`init(options)`** — cria o cliente, instala os handlers globais de erro (a menos que `captureUnhandled: false`), inicia o heartbeat se configurado e cria o agente de tasks se `tasks` foi passado. Chamar de novo **substitui** o cliente e o agente (os handlers registrados com `register` são preservados; o [scope](./concepts.md#scope) **não** é limpo). Chame uma vez, o mais cedo possível.
|
|
35
|
-
- **`getClient()`** — devolve o cliente atual ou `undefined` se o `init()` nunca rodou. Útil para checar se o SDK está ativo. A config resolvida (URL base e endpoints) é acessível via `getClient()?.config` (veja abaixo).
|
|
36
|
-
- **`captureException(error, hint?)`** — monta um [evento](./concepts.md#evento) a partir da exceção (tipo, mensagem, stack trace), mescla o scope e enfileira. O `type` é `error` a menos que você passe outro no `hint`.
|
|
37
|
-
- **`captureMessage(message, type = 'warning', hint?)`** — mesma coisa, sem exceção: um evento só com texto. Bom para marcos (`'success'`) e avisos que não são erro.
|
|
38
|
-
> **Atenção:** as duas devolvem um `event_id` **mesmo quando o evento foi descartado** por [amostragem](./concepts.md#amostragem-samplerate-e-tracessamplerate) ou por [`beforeSend`](./concepts.md#beforesend). O retorno não prova que algo foi enviado — só é `undefined` quando o `init()` não foi chamado.
|
|
39
|
-
- **`addBreadcrumb(crumb)`** — adiciona uma migalha à trilha do [scope](./concepts.md#scope) global. Todos os campos são opcionais menos o `timestamp`, que o SDK preenche. A lista **não** é limpa ao enviar um evento; ela só descarta as mais antigas ao estourar `maxBreadcrumbs`. Conceito: [Breadcrumb](./concepts.md#breadcrumb).
|
|
40
|
-
- **`setTag(key, value)` / `setTags(tags)`** — grava [tags](./concepts.md#tag) no scope global; valem para todos os eventos seguintes. Só `string` → `string`. Precedência: `init.tags` → scope → evento → `hint`.
|
|
41
|
-
- **`setUser(user | null)`** — define quem está operando (`id`, `username`, `email`). `null` remove.
|
|
42
|
-
- **`setContext(name, ctx | null)`** — define um [context](./concepts.md#context) nomeado. Passar `null` **apaga o grupo inteiro**. Os grupos `runtime` e `os` são injetados pelo SDK em todo evento.
|
|
43
|
-
- **`setExtra(key, value)`** — anexa um dado livre, sem estrutura e sem índice. Conceito e critério de escolha em [Extra](./concepts.md#extra).
|
|
44
|
-
- **`withScope(cb)`** — roda o callback com um **clone** do scope e restaura o original no fim; devolve o que o callback devolver. É **síncrono** — um `await` dentro do callback não isola de código concorrente. Conceito: [withScope](./concepts.md#withscope).
|
|
45
|
-
- **`startTransaction(name, op?)`** — abre uma [transaction](./concepts.md#transaction) de performance. A decisão de [amostragem](./concepts.md#amostragem-samplerate-e-tracessamplerate) acontece **aqui**, não no `finish()`. Nada é enviado até o `finish()`. **Dentro de um handler de task**, devolve a [transaction da própria run](./concepts.md#transaction-de-run-ctxtx) (`ctx.tx`) em vez de criar uma segunda — cada execução tem exatamente uma transaction; fora de um handler, cria uma transaction nova, sem `run_id`.
|
|
46
|
-
- **`flush(timeoutMs = 5_000)`** → `Promise<boolean>` — empurra a fila do transport e aguarda os envios em andamento. `true` = tudo saiu no prazo; `false` = o SDK parou de esperar (os envios em voo seguem tentando). O SDK **continua utilizável** depois. Conceito: [Fila, flush e close](./concepts.md#fila-flush-e-close).
|
|
47
|
-
- **`close(timeoutMs = 5_000)`** → `Promise<boolean>` — encerra tudo na ordem agente → heartbeat → flush final. O `timeoutMs` é gasto **duas vezes** (espera das runs, depois flush). Depois do `close()` o transport está fechado e todo item novo é descartado com aviso no console; não há `reopen()`. Conceito: [Fila, flush e close](./concepts.md#fila-flush-e-close).
|
|
48
|
-
|
|
49
|
-
Classes exportadas: `Client`, `Scope`, `Transaction`, `Step`. A resolução da credencial nos endpoints é interna ao `init()` (constante `DEFAULT_BASE_URL = 'https://api2.hobots.app'`, exportada; em desenvolvimento a env `HOBOTS_API_URL` sobrescreve a URL base). A config resolvida fica acessível em `getClient()?.config`:
|
|
16
|
+
| `hobots.register` | `<P>(task: string, handler: TaskHandler<P>, options?: RegisterOptions) => void` | Task sob demanda. Síncrona: valida slug/handler/secret e lança na hora. O boot roda num microtask — chamadas seguidas entram no primeiro poll. Slug repetido lança. |
|
|
17
|
+
| `hobots.start` | `(task: string, handler: TaskHandler, options?: StartOptions) => void` | Task sempre ligada: abre a própria execução e roda o handler uma vez. |
|
|
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
|
+
| `hobots.captureException` | `(error: unknown, hint?: CaptureHint) => string \| undefined` | Issue no módulo Issues; devolve o `event_id`. Antes de qualquer task: descarta com aviso. |
|
|
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. |
|
|
50
21
|
|
|
51
|
-
|
|
52
|
-
getClient()?.config; // {
|
|
53
|
-
// key: string; — Client Secret do agente (vai no Authorization: Bearer, nunca na URL)
|
|
54
|
-
// baseUrl: string; — DEFAULT_BASE_URL, ou HOBOTS_API_URL em desenvolvimento
|
|
55
|
-
// ingestEndpoint: string; — <baseUrl>/v1/ingest
|
|
56
|
-
// tasksBaseUrl: string; — <baseUrl>/v1/tasks
|
|
57
|
-
// }
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Métodos de `Transaction` / `Step` / `Scope`
|
|
61
|
-
|
|
62
|
-
Todos encadeáveis, exceto `finish()` e `toJSON()`.
|
|
63
|
-
|
|
64
|
-
- **`Transaction`** — `startChild(op?, description?) → Step` abre uma [step](./concepts.md#step) direta; `setTag(k, v)` marca a transaction (tags de scope **não** são herdadas); `setStatus(s)` (default `'ok'`); `setName(n)` renomeia antes do envio; `finish()` fecha as etapas abertas, monta o payload e envia — é **idempotente** e não envia nada se a transaction não foi amostrada.
|
|
65
|
-
- **`Step`** — `startChild(op?, description?) → Step` aninha uma filha (profundidade arbitrária); `setStatus(s)` (default `'ok'`); `setData(k, v)` anexa dados só àquela step; `finish()` marca o fim — **opcional**, porque o `finish()` da transaction fecha o que ficou aberto; `toJSON()` serializa no formato do wire.
|
|
66
|
-
- **`Scope`** — `setTag`/`setTags`/`setUser`/`setContext`/`setExtra`/`setExtras`/`setType`/`setFingerprint`/`addBreadcrumb`/`clearBreadcrumbs`/`clone`. Alcançável via [`withScope`](./concepts.md#withscope). `setContext(name, null)` apaga o grupo; `setUser(null)` remove o usuário.
|
|
67
|
-
> **Atenção:** `setType` **não tem efeito** em `captureException` (que já grava `error`) nem em `captureMessage` (que já grava `warning`) — os dois definem o tipo do evento antes de o scope ser consultado. Use o `hint`.
|
|
22
|
+
## Contexto da execução (`RunContext` — os membros de `hobots` e o `ctx` do handler)
|
|
68
23
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- **`start()`** — começa o polling. **Mantém o processo vivo** até `stop()`/`close()` — o timer não é `unref`'d, ao contrário dos da telemetria. Lança se o `init()` não configurou `tasks` ou se nenhuma task foi registrada. Também instala os handlers de saída (SIGINT/SIGTERM/erro fatal) que reportam as runs ativas como `AgentTerminated`, a menos que `installExitHandlers: false`.
|
|
85
|
-
- **`stop(timeoutMs = 30_000)`** → `Promise<boolean>` — encerra o polling e aguarda as [runs](./concepts.md#run) ativas terminarem. Para **só as tasks**: a telemetria (heartbeat, captura de erros) continua funcionando. Devolve `false` se estourou o timeout — as runs que ainda estavam rodando são reportadas como `AgentTerminated`. Para encerrar tudo, use [`close()`](./concepts.md#fila-flush-e-close).
|
|
86
|
-
|
|
87
|
-
No poll, o agente se identifica com `InstanceInfo` (`hobots/protocol`): o campo `instance_id` (o `instanceId` do `init()`) é a identidade canônica do agente — a mesma do heartbeat de telemetria, então os dois canais convergem em um agente no painel.
|
|
88
|
-
|
|
89
|
-
---
|
|
24
|
+
| Membro | Tipo | Notas |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| `runId`, `task` | `string` | Identidade da execução (`''` fora de uma execução) |
|
|
27
|
+
| `params` | `Record<string, unknown>` | Params da solicitação; `{}` no modo start |
|
|
28
|
+
| `log` | `RunLogger` — `debug/info/warn/error/success(message, ...rest)` | Nunca lança. Vários argumentos viram texto unidos por espaço (como `console.log`) |
|
|
29
|
+
| `items` | `RunItems` — `add(item)`, `succeeded(payload?, opts?)`, `failed(message, payload?, opts?)`, `occurrence(message, payload?, opts?)`; `opts.id` = identidade de negócio | Ponto de parada cooperativo |
|
|
30
|
+
| `progress` | `RunProgressReporter` — `total(n)`, `advance(count = 1)`, `set(current, total?)`, `current`, `snapshot` | `total/advance/set` são pontos de parada |
|
|
31
|
+
| `transaction` | `Transaction` — `startChild(op?, description?)`, `setTag`, `setStatus`, `setName`; `Step` — `startChild`, `setStatus('ok' \| 'warning' \| 'error')`, `setData(k, v)`, `finish()` | Finalizada pelo SDK; `startChild` é ponto de parada |
|
|
32
|
+
| `signal` | `AbortSignal` | Cancelamento (app, timeout, shutdown) |
|
|
33
|
+
| `throwIfCanceled()` | `() => void` | Lança `RunCanceled` se o signal disparou |
|
|
34
|
+
| `sleep(ms)` | `(ms: number) => Promise<void>` | Rejeita com `RunCanceled` no cancelamento |
|
|
35
|
+
| `attach(image, options?)` | `(image: AttachInput, options?: AttachOptions) => Promise<AttachResult>` | `AttachInput = Uint8Array \| ArrayBuffer \| string` (caminho); `AttachOptions = { caption?, level?, message?, contentType? }`; `AttachResult = { id, ok, reason? }`. Nunca lança |
|
|
36
|
+
| `retry(fn, options?)` | como `hobots.retry` | |
|
|
37
|
+
|
|
38
|
+
Fora de uma execução, `hobots.*` cai em fallbacks seguros com aviso único por membro (log ecoa no terminal; items/progress no-op; `signal` nunca aborta; `attach` resolve `{ ok: false }`).
|
|
90
39
|
|
|
91
40
|
## Tabelas de opções
|
|
92
41
|
|
|
93
|
-
###
|
|
42
|
+
### `HobotsOptions` (processo — a primeira chamada define; divergências avisam e são ignoradas)
|
|
94
43
|
|
|
95
44
|
| Opção | Tipo | Default | Descrição |
|
|
96
45
|
| --- | --- | --- | --- |
|
|
97
|
-
| `clientSecret` | `string` |
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `tags` | `Record<string,string>` | — | tags
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
| `tasks` | `boolean \| TasksOptions` | `false` | habilita a execução sob demanda (`true` usa defaults) |
|
|
109
|
-
| `beforeSend` | `(event) => event \| null` | — | edita/descarta evento (retorne `null` para descartar) |
|
|
110
|
-
| `debug` | `boolean` | `false` | loga atividade do SDK |
|
|
111
|
-
| `flushIntervalMs` | `number` | `2000` | intervalo do flush automático do transport |
|
|
112
|
-
| `maxBatchSize` | `number` | `10` | itens por envelope antes do flush imediato |
|
|
113
|
-
|
|
114
|
-
O teto da fila do transport (200 itens; ao encher, o **mais antigo** é descartado com aviso) é interno — **não** é opção do `init()`. Conceitos por trás dessas opções: [amostragem](./concepts.md#amostragem-samplerate-e-tracessamplerate), [breadcrumbs](./concepts.md#breadcrumb), [instanceId](./concepts.md#instanceid), [release e environment](./concepts.md#release-e-environment), [beforeSend](./concepts.md#beforesend).
|
|
115
|
-
|
|
116
|
-
### HeartbeatOptions
|
|
46
|
+
| `clientSecret` | `string` | env `HOBOTS_CLIENT_SECRET` | `hb_<64 hex>`; ausente/inválido lança citando a env (sem ecoar o valor) |
|
|
47
|
+
| `instanceId` | `string` | env `HOBOTS_INSTANCE_ID` → `os.hostname()` | identidade estável da instância |
|
|
48
|
+
| `environment` | `'development' \| 'testing' \| 'staging' \| 'production' \| string` | `'production'` | vai em eventos, transactions e na instância; filtra alertas |
|
|
49
|
+
| `release` | `string` | — | versão do programa |
|
|
50
|
+
| `tags` | `Record<string, string>` | — | tags de todos os eventos e transactions |
|
|
51
|
+
| `debug` | `boolean` | `false` | loga a atividade do SDK |
|
|
52
|
+
| `machineMetrics` | `boolean` | `true` | CPU/memória/disco no heartbeat/poll e em `contexts.machine` |
|
|
53
|
+
| `captureUnhandled` | `boolean` | `true` | handlers globais de erro (issues) |
|
|
54
|
+
| `installExitHandlers` | `boolean` | `true` | avançado — SIGINT/SIGTERM/uncaughtException reportam `AgentTerminated` |
|
|
55
|
+
|
|
56
|
+
### `TaskOptions extends HobotsOptions` (por task)
|
|
117
57
|
|
|
118
58
|
| Opção | Tipo | Default | Descrição |
|
|
119
59
|
| --- | --- | --- | --- |
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
| Campo | Tipo | Descrição |
|
|
129
|
-
| --- | --- | --- |
|
|
130
|
-
| `type` | `EventType` | tipo do evento |
|
|
131
|
-
| `tags` | `Record<string,string>` | tags só deste evento |
|
|
132
|
-
| `extra` | `Record<string,unknown>` | dados extras |
|
|
133
|
-
| `fingerprint` | `string[]` | agrupamento manual |
|
|
134
|
-
| `attachment` | `AttachInput \| CaptureAttachment` | print enviado junto da captura — dentro de uma execução de task, vira anexo da linha de log da run que espelha o evento; fora de uma execução é descartado com aviso. Guia: [Anexos](./tasks.md#anexos-screenshots) |
|
|
135
|
-
|
|
136
|
-
### CaptureAttachment
|
|
60
|
+
| `retries` | `number` | `1` | tentativas extras do handler; `0` desliga |
|
|
61
|
+
| `retryDelayMs` | `number \| (attempt) => number` | `5_000` | `attempt` 1-based (a que falhou) |
|
|
62
|
+
| `timeoutMs` | `number` | — | por tentativa; terminal (`TaskTimeout`) |
|
|
63
|
+
| `logFlushIntervalMs` | `number` | `2_000` | avançado |
|
|
64
|
+
| `cancelCheckIntervalMs` | `number` | `5_000` (1_000..15_000) | avançado — PATCH vazio que detecta cancelamento e é o sinal de vida da execução |
|
|
65
|
+
| `cancelGraceMs` | `number` | `10_000` | avançado — graça após o signal antes de liberar o slot |
|
|
66
|
+
| `items` | `{ columns: Array<string \| { key, label? }> }` | — | colunas da aba de itens no app (chaves do `payload` dos itens); até 12, chave `[a-zA-Z0-9_.-]`. Independe de formulário; personalizar no app sobrepõe |
|
|
137
67
|
|
|
138
|
-
`
|
|
68
|
+
### `RegisterOptions extends TaskOptions`
|
|
139
69
|
|
|
140
|
-
|
|
|
70
|
+
| Opção | Tipo | Default | Descrição |
|
|
141
71
|
| --- | --- | --- | --- |
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `contentType` | `'image/png' \| 'image/jpeg' \| 'image/webp'` | detectado pelos *magic bytes* | só usado quando a detecção falha; a detecção sempre tem precedência |
|
|
72
|
+
| `concurrency` | `number` | `1` | execuções simultâneas desta task (1..5) |
|
|
73
|
+
| `pollIntervalMs` | `number` | `2_000` (mín. 1_000) | intervalo entre polls sem trabalho; vale o do primeiro `register()` |
|
|
145
74
|
|
|
146
|
-
|
|
75
|
+
`StartOptions = TaskOptions`.
|
|
147
76
|
|
|
148
|
-
|
|
77
|
+
### `RetryOptions`
|
|
149
78
|
|
|
150
|
-
|
|
79
|
+
| Opção | Tipo | Default |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| `retries` | `number` | `3` |
|
|
82
|
+
| `delayMs` | `number \| (attempt) => number` | `1_000` |
|
|
83
|
+
| `shouldRetry` | `(error) => boolean` | tudo, exceto `RunCanceled`/`TaskTimeout`/`AbortError` (nunca re-tentados) |
|
|
151
84
|
|
|
152
|
-
|
|
85
|
+
### `CaptureHint`
|
|
153
86
|
|
|
154
|
-
|
|
|
155
|
-
| --- | --- | --- |
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `logFlushIntervalMs` | `number` | `2000` | intervalo do envio incremental de logs |
|
|
160
|
-
| `cancelCheckIntervalMs` | `number` | `5000` | heartbeat de cancelamento por run (clamp 1000..15000) — também é o sinal de vida da run (servidor marca `AgentTerminated` após ~60s sem reporte) |
|
|
161
|
-
| `installExitHandlers` | `boolean` | `true` | handlers de SIGINT/SIGTERM/uncaughtException que reportam as runs ativas como `AgentTerminated` antes do processo morrer; nunca interferem quando o programa tem handler próprio |
|
|
87
|
+
| Campo | Tipo | Descrição |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| `type` | `'fatal' \| 'error' \| 'warning' \| 'success'` | default `'error'` |
|
|
90
|
+
| `tags`, `extra`, `fingerprint` | | metadados do evento (`fingerprint` sobrescreve o agrupamento) |
|
|
91
|
+
| `attachment` | `AttachInput \| { image, caption?, contentType? }` | print anexado à linha de log da execução atual |
|
|
162
92
|
|
|
163
|
-
### TaskHandler
|
|
93
|
+
### `TaskHandler`
|
|
164
94
|
|
|
165
95
|
```ts
|
|
166
|
-
|
|
167
|
-
type TaskHandler<P = Record<string, unknown>> =
|
|
168
|
-
(params: P, ctx: RunContext) => void | Promise<void>;
|
|
169
|
-
|
|
170
|
-
interface RunContext {
|
|
171
|
-
runId: string;
|
|
172
|
-
task: string;
|
|
173
|
-
log: RunLogger; // ctx.log.debug/info/warn/error/success(message)
|
|
174
|
-
items: RunItems; // ctx.items.add/succeeded/failed/occurrence — a entrega do bot
|
|
175
|
-
progress: RunProgressReporter; // ctx.progress.total/advance/set — barra + tempo restante (opcional)
|
|
176
|
-
tx: Transaction; // transaction desta run — correlacionada e finalizada pelo SDK
|
|
177
|
-
signal: AbortSignal;
|
|
178
|
-
throwIfCanceled(): void; // lança RunCanceled se o signal já disparou
|
|
179
|
-
sleep(ms: number): Promise<void>; // espera cancelável — rejeita com RunCanceled no abort
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
interface RunItems {
|
|
183
|
-
add(item: { status: RunItemStatus; id?: string; message?: string; payload?: Record<string, unknown> }): void;
|
|
184
|
-
succeeded(payload?: Record<string, unknown>, options?: { id?: string }): void;
|
|
185
|
-
failed(message: string, payload?: Record<string, unknown>, options?: { id?: string }): void;
|
|
186
|
-
occurrence(message: string, payload?: Record<string, unknown>, options?: { id?: string }): void;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
interface RunProgressReporter {
|
|
190
|
-
total(total: number): void; // declara/ajusta o total de itens (inteiro >= 1; idempotente)
|
|
191
|
-
advance(count?: number): void; // incrementa os processados (padrão 1; clampa em total)
|
|
192
|
-
set(current: number, total?: number): void; // valor absoluto
|
|
193
|
-
readonly current: number;
|
|
194
|
-
readonly snapshot: RunProgress | null; // { current, total } ou null sem total declarado
|
|
195
|
-
}
|
|
96
|
+
type TaskHandler<P = Record<string, unknown>> = (params: P, ctx: RunContext) => void | Promise<void>;
|
|
196
97
|
```
|
|
197
98
|
|
|
198
|
-
- **`runId` / `task`** — identificam a execução; úteis para correlacionar com os seus próprios logs.
|
|
199
|
-
- **`log.<level>(message)`** — níveis `debug`, `info`, `warn`, `error` e `success`; enfileira uma linha de log enviada ao app em PATCHes incrementais, e **também imprime no terminal local**. Conceito: [Run](./concepts.md#run).
|
|
200
|
-
- **`items.<status>(…)`** — registra um item processado/gerado pela execução (síncrono, bufferizado, lotes de até 500). `id` opcional = idempotência dentro da run. Guia: [Itens de execução](./tasks.md#itens-de-execução-ctxitems).
|
|
201
|
-
- **`progress.total(n)` / `progress.advance()` / `progress.set(c, t?)`** — progresso declarado da run (itens processados / total), opcional e independente de `items`; o app mostra barra, percentual e tempo restante. Síncrono; o snapshot pega carona nos PATCHes de log e sai no máximo 1×/s por conta própria. Guia: [Progresso da execução](./tasks.md#progresso-da-execução-ctxprogress).
|
|
202
|
-
- **`tx`** — a [transaction de performance da run](./concepts.md#transaction-de-run-ctxtx). Use `ctx.tx.startChild(op, description)` para medir as etapas; **não** chame `finish()` nela. `startTransaction()` dentro do handler devolve essa mesma transaction.
|
|
203
|
-
- **`signal`** — `AbortSignal` que dispara em cancelamento no app, timeout ou shutdown.
|
|
204
|
-
- **`throwIfCanceled()`** — o ponto de parada de uma linha: lança `RunCanceled` se o `signal` já disparou.
|
|
205
|
-
- **`sleep(ms)`** — espera que respeita o `signal` (rejeita com `RunCanceled` em vez de dormir até o fim). Use no lugar do seu `sleep` em esperas longas.
|
|
206
|
-
|
|
207
|
-
Para anexar um print a uma linha de log da run, use o campo `attachment` do [`CaptureHint`](#capturehint) em `captureException`/`captureMessage` dentro do handler. Guia: [Anexos](./tasks.md#anexos-screenshots).
|
|
208
|
-
|
|
209
|
-
---
|
|
210
|
-
|
|
211
99
|
## Tempos e intervalos
|
|
212
100
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
|
218
|
-
|
|
|
219
|
-
|
|
|
220
|
-
|
|
|
221
|
-
|
|
|
222
|
-
|
|
|
223
|
-
|
|
|
224
|
-
| `close(
|
|
225
|
-
| ladder de retry | `1s, 4s, 16s` | — (fixo) | 3 tentativas por envelope; depois ele é descartado. 4xx (exceto 429) não tem retry |
|
|
226
|
-
| heartbeat | `30000` ms | `init({ heartbeat: { intervalMs } })` | bate **imediatamente** no `init()` e depois a cada intervalo; o valor vai no payload e define quanto silêncio o servidor tolera antes de marcar offline |
|
|
227
|
-
|
|
228
|
-
### Tasks — polling e runs
|
|
229
|
-
|
|
230
|
-
| Tempo | Default | Onde configura | O que acontece |
|
|
231
|
-
| --- | --- | --- | --- |
|
|
232
|
-
| poll sem trabalho | `5000` ms (mín. `1000`) | `tasks: { pollIntervalMs }` | é só o **teto da espera quando não há nada**: com trabalho na fila o próximo poll é imediato ([drain mode](./concepts.md#drain-mode)) |
|
|
233
|
-
| flush de logs da run | `2000` ms | `tasks: { logFlushIntervalMs }` | ou na hora, ao acumular 20 linhas |
|
|
234
|
-
| flush de itens da run | `2000` ms | — (acompanha `logFlushIntervalMs`) | ou na hora, ao acumular 100 itens; POSTs de até 500 |
|
|
235
|
-
| espera pelos itens no fim da run | `15000` ms | — (fixo) | antes do PATCH terminal, drena o buffer de itens — os totalizadores ficam completos quando a run termina |
|
|
236
|
-
| validade da URL de upload de anexo | `900` s | — (servidor) | tempo para o PUT no S3 depois que a API presigna |
|
|
237
|
-
| espera pelos anexos no fim da run | `15000` ms | — (fixo) | antes do PATCH terminal, aguarda os uploads pendentes; no estouro a run termina e o app mostra "imagem não enviada" |
|
|
238
|
-
| uploads de anexo simultâneos | `3` | — (fixo) | por execução; os demais ficam na fila |
|
|
239
|
-
| retry do upload de anexo | `1s, 4s` | — (fixo) | ladder curta: o binário é grande e a URL presignada tem prazo |
|
|
240
|
-
| heartbeat de cancelamento | `5000` ms (clamp `1000`..`15000`) | `tasks: { cancelCheckIntervalMs }` | detecta cancelamento feito no app **e** é o sinal de vida da run (veja a nota 2) |
|
|
241
|
-
| timeout por run | sem timeout | `tasks: { taskTimeoutMs }` | no estouro dispara `ctx.signal`, libera o slot de concorrência e reporta `TaskTimeout` — **não mata** o handler |
|
|
242
|
-
| `stop(timeoutMs)` | `30000` ms | argumento | espera as runs ativas; no estouro elas são reportadas como `AgentTerminated` |
|
|
243
|
-
| retry do poll | `1s, 4s, 16s` | — (fixo) | erros de rede/5xx |
|
|
244
|
-
| retry com chave rejeitada (401) | `30000` ms | — (fixo) | segue tentando devagar, com log throttled |
|
|
245
|
-
| PATCH do caminho de saída | `~2500` ms | — (fixo) | melhor esforço, sem retry, ao morrer com run ativa |
|
|
246
|
-
| sweep do servidor | `~60000` ms | — (servidor) | run `running` sem reporte por esse tempo vira `failed`/`AgentTerminated`, sem re-entrega |
|
|
247
|
-
|
|
248
|
-
**Nota 1 — `close(timeoutMs)` gasta o tempo duas vezes.** Ele espera as runs de tasks (`timeoutMs`) e **depois** faz o flush final (`timeoutMs`), em sequência. Pior caso ≈ `2 × timeoutMs`; `close()` sem argumento pode levar até ~35s (30s aguardando runs + 5s de flush). Se o seu SIGTERM tem prazo curto (Kubernetes, systemd), dimensione por aí.
|
|
249
|
-
|
|
250
|
-
**Nota 2 — o teto de 15s do `cancelCheckIntervalMs` existe por causa do sweep de 60s.** Esse heartbeat é o que mantém o `last_report_at` da run atualizado; o clamp garante que o intervalo nunca chegue perto do prazo em que o servidor declara a run morta.
|
|
101
|
+
| O quê | Valor |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| Heartbeat | 30 s (±10 % de jitter), sempre ligado, timer ref'd (segura o processo) |
|
|
104
|
+
| Flush da telemetria | 2 s ou 10 itens; envelopes de até 50 itens; fila de 200 |
|
|
105
|
+
| Retry HTTP (ingest, PATCH, itens, anexos) | 1 s / 4 s / 16 s com jitter; 4xx ≠ 429 é definitivo |
|
|
106
|
+
| Poll sem trabalho | `pollIntervalMs` (2 s); com trabalho, imediato (drain) |
|
|
107
|
+
| 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 |
|
|
108
|
+
| Logs da execução | flush a cada `logFlushIntervalMs` (2 s) ou 20 linhas; chunks de 100; 1000 por execução no servidor |
|
|
109
|
+
| Cancel-watch / sinal de vida | `cancelCheckIntervalMs` (5 s); o servidor marca `AgentTerminated` após ~120 s sem PATCH |
|
|
110
|
+
| Retry do handler | `retries` 1, `retryDelayMs` 5 s |
|
|
111
|
+
| Drenos antes do terminal | anexos 15 s, itens 15 s |
|
|
112
|
+
| `close()` | 30 s para as execuções em voo; exit path reporta em ≤ 2,5 s |
|