hobots 3.4.0 → 4.1.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 +38 -28
- package/dist/{chunk-5WIIACWC.js → chunk-HKCDMUA3.js} +1 -2
- package/dist/chunk-HKCDMUA3.js.map +1 -0
- package/dist/index.cjs +179 -231
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -25
- package/dist/index.d.ts +47 -25
- package/dist/index.js +180 -231
- package/dist/index.js.map +1 -1
- package/dist/protocol.cjs +0 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +21 -23
- package/dist/protocol.d.ts +21 -23
- package/dist/protocol.js +1 -1
- package/docs/README.md +10 -8
- package/docs/api-reference.md +34 -20
- package/docs/concepts.md +19 -19
- package/docs/getting-started.md +14 -12
- package/docs/protocol.md +24 -25
- package/docs/{tasks.md → runs.md} +51 -23
- package/package.json +2 -2
- package/dist/chunk-5WIIACWC.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# hobots
|
|
2
2
|
|
|
3
|
-
SDK JavaScript/TypeScript da **Hobots** para robôs (RPAs) e integrações. **
|
|
3
|
+
SDK JavaScript/TypeScript da **Hobots** para robôs (RPAs) e integrações. **O agente é a própria tarefa**: o seu programa é o agente, ele faz uma coisa, e a plataforma passa a receber logs, itens processados, progresso, prints, erros e o "estou vivo" do robô.
|
|
4
4
|
|
|
5
|
-
- **`hobots.register(
|
|
6
|
-
- **`hobots.start(
|
|
5
|
+
- **`hobots.register(handler)`** — **modo sob demanda**: o robô fica online aguardando **solicitações** criadas no app (formulário do agente e agendamentos) e executa o handler a cada uma. Módulo **Trabalhos**.
|
|
6
|
+
- **`hobots.start(handler)`** — **modo sempre ligado**: o robô abre a própria execução ao iniciar e roda o handler (o seu loop) dentro dela; a plataforma só recebe logs, itens e progresso. Sem formulário, sem solicitante.
|
|
7
|
+
|
|
8
|
+
Uma chamada por processo: `register` **ou** `start`. Não há slug nem nome de task — o que o robô faz é o próprio agente, identificado pelo Client Secret.
|
|
7
9
|
|
|
8
10
|
---
|
|
9
11
|
|
|
@@ -33,8 +35,8 @@ export HOBOTS_ENVIRONMENT=staging # opcional — default: production
|
|
|
33
35
|
```js
|
|
34
36
|
import hobots from 'hobots';
|
|
35
37
|
|
|
36
|
-
// sob demanda: uma execução por solicitação do app (
|
|
37
|
-
hobots.register(
|
|
38
|
+
// sob demanda: uma execução por solicitação do app (formulário do agente ou agendamento)
|
|
39
|
+
hobots.register(async params => {
|
|
38
40
|
hobots.log.info(`lote ${params.lote}`);
|
|
39
41
|
hobots.progress.total(params.notas.length);
|
|
40
42
|
for (const nota of params.notas) {
|
|
@@ -44,19 +46,22 @@ hobots.register('processar-nfe', async params => {
|
|
|
44
46
|
}
|
|
45
47
|
});
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
process.on('SIGINT', () => void hobots.close(15_000).then(() => process.exit(0)));
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Um robô que vive rodando usa `start` no lugar de `register` — o handler é o loop:
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
hobots.start(async () => {
|
|
49
56
|
while (true) {
|
|
50
57
|
await hobots.sleep(60_000); // cancelável
|
|
51
58
|
for (const arquivo of await novosArquivos()) hobots.items.succeeded({ arquivo });
|
|
52
59
|
hobots.log.info('ciclo ok');
|
|
53
60
|
}
|
|
54
61
|
});
|
|
55
|
-
|
|
56
|
-
process.on('SIGINT', () => void hobots.close(15_000).then(() => process.exit(0)));
|
|
57
62
|
```
|
|
58
63
|
|
|
59
|
-
O objeto **`hobots`** é global: `hobots.log`, `hobots.items`, `hobots.progress`, `hobots.transaction`… resolvem a execução **atual** de qualquer módulo do programa — sem passar contexto de mão em mão, mesmo com várias execuções em paralelo. Depois
|
|
64
|
+
O objeto **`hobots`** é global: `hobots.log`, `hobots.items`, `hobots.progress`, `hobots.transaction`… resolvem a execução **atual** de qualquer módulo do programa — sem passar contexto de mão em mão, mesmo com várias execuções em paralelo. Depois do `register()`/`start()` ele também existe como `globalThis.hobots`.
|
|
60
65
|
|
|
61
66
|
---
|
|
62
67
|
|
|
@@ -65,7 +70,7 @@ O objeto **`hobots`** é global: `hobots.log`, `hobots.items`, `hobots.progress`
|
|
|
65
70
|
| Env | Opção | O que é |
|
|
66
71
|
| --- | --- | --- |
|
|
67
72
|
| `HOBOTS_CLIENT_SECRET` | `clientSecret` | O **Client Secret do agente** (`hb_<64 hex>`), copiado em **Configurações → Agentes**. Viaja só no header `Authorization: Bearer`, nunca na URL. Ausente ou inválido → `register()`/`start()` lança na hora, citando a env (sem ecoar o valor). |
|
|
68
|
-
| `HOBOTS_INSTANCE_ID` | `instanceId` | Identidade **estável** desta instância do robô (`vm-cliente-01`). Sem ela, o hostname. Heartbeat e
|
|
73
|
+
| `HOBOTS_INSTANCE_ID` | `instanceId` | Identidade **estável** desta instância do robô (`vm-cliente-01`). Sem ela, o hostname. Heartbeat e execuções convergem nela: **um agente só** no painel. |
|
|
69
74
|
| `HOBOTS_ENVIRONMENT` | `environment` | Ambiente lógico do robô (`development` \| `testing` \| `staging` \| `production`). Sem ela, `production`. |
|
|
70
75
|
| `HOBOTS_API_URL` | — | Só em desenvolvimento: aponta o SDK para outro host (`http://localhost:3001`). Em produção é sempre `https://api2.hobots.app`. |
|
|
71
76
|
|
|
@@ -75,17 +80,18 @@ A opção passada em `register()`/`start()` tem precedência sobre a env — út
|
|
|
75
80
|
|
|
76
81
|
## Os dois modos
|
|
77
82
|
|
|
78
|
-
| | `register(
|
|
83
|
+
| | `register(handler, options?)` | `start(handler, options?)` |
|
|
79
84
|
| --- | --- | --- |
|
|
80
|
-
| Quem dispara | Uma **solicitação** no app (formulário
|
|
85
|
+
| Quem dispara | Uma **solicitação** no app (formulário do agente, ou agendamento) | O próprio robô, ao iniciar |
|
|
81
86
|
| `params` do handler | O JSON validado do formulário | `{}` |
|
|
82
87
|
| Quantas execuções | Uma por solicitação; `concurrency` em paralelo (1..5) | **Uma só** — o handler é o seu loop; quando ele retorna, a execução fecha |
|
|
83
88
|
| O processo | Fica vivo fazendo polling | Fica vivo pelo heartbeat, mesmo depois do handler retornar |
|
|
84
89
|
| Reexecutar pelo app | Sim | Não — só reiniciando o robô |
|
|
90
|
+
| No painel | Instância "sob demanda" | Instância "sempre ligado" |
|
|
85
91
|
|
|
86
|
-
|
|
92
|
+
**Um processo = um agente = uma chamada.** A segunda chamada a `register()`/`start()` lança (`o agente já foi iniciado`). Um robô que precisa monitorar uma pasta *e* atender solicitações são dois agentes — dois processos, cada um com o seu Client Secret.
|
|
87
93
|
|
|
88
|
-
> **Modo start e o limite de logs:** o servidor guarda no máximo **1000 linhas de log por execução**. Num loop que roda por dias, logue o que importa (ciclos com novidade, avisos, erros) e registre o trabalho em `hobots.items` — itens não têm
|
|
94
|
+
> **Modo start e o limite de logs:** o servidor guarda no máximo **1000 linhas de log por execução**. Num loop que roda por dias, logue o que importa (ciclos com novidade, avisos, erros) e registre o trabalho em `hobots.items` — itens não têm teto por execução (só o armazenamento do plano limita). As steps de uma run que não termina só chegam à Central com `hobots.flush()` — chame-o ao fim de cada rodada que processou itens.
|
|
89
95
|
|
|
90
96
|
---
|
|
91
97
|
|
|
@@ -93,17 +99,18 @@ Os dois podem coexistir no mesmo processo: um monitor sempre ligado + tasks sob
|
|
|
93
99
|
|
|
94
100
|
| Membro | O que faz |
|
|
95
101
|
| --- | --- |
|
|
96
|
-
| `hobots.log.debug/info/warn/error/success(msg, ...rest)` | Log da execução, enviado incrementalmente ao app (e ecoado no terminal). Aceita vários argumentos como `console.log` — `hobots.log.info('nota', numero, 'ok')` — cada um vira texto, unidos por espaço. Um `hobots.image(...)` como **último** argumento pendura um print na linha. **Nunca lança** — pode ir em `finally`. |
|
|
102
|
+
| `hobots.log.debug/info/warn/error/success(msg, ...rest)` | Log da execução, enviado incrementalmente ao app (e ecoado no terminal como `[hobots] INFO …`). Aceita vários argumentos como `console.log` — `hobots.log.info('nota', numero, 'ok')` — cada um vira texto, unidos por espaço. Um `hobots.image(...)` como **último** argumento pendura um print na linha. **Nunca lança** — pode ir em `finally`. |
|
|
97
103
|
| `hobots.items.succeeded(payload?, { id, image }?)` · `.failed(msg, payload?, …)` · `.occurrence(msg, payload?, …)` · `.add({...})` | **A entrega do robô**: cada item processado, com status e atributos (viram colunas no app — declare-as com a opção `items: { columns: [...] }` do `register`/`start`). `image` pendura um print no item. Bufferizado, em lotes. |
|
|
98
104
|
| `hobots.items.each(lista, async (el, item) => …, { id, payload }?)` | **Loop com o contrato garantido**: cada elemento vira step + item; exceção no handler = item `failed` com a mensagem e o loop **segue** até o fim; progresso automático. Só cancelamento/timeout interrompem. |
|
|
99
|
-
| `hobots.progress.total(n)` · `.advance(k = 1)` · `.set(atual, total?)` · `.current` · `.snapshot` | Barra, percentual e tempo restante na
|
|
100
|
-
| `hobots.
|
|
105
|
+
| `hobots.progress.total(n)` · `.advance(k = 1)` · `.set(atual, total?)` · `.current` · `.snapshot` | Barra, percentual e tempo restante na execução. Sem `total()` nada é enviado. |
|
|
106
|
+
| `hobots.flush(timeoutMs?)` | **Entrega já** o que a execução fez: as steps raiz finalizadas viram transactions parciais (waterfall na Central sem esperar a run terminar) e itens, logs e progresso pendentes saem sem esperar o throttle. O bot decide quando — num agente `start()`, ao fim de cada rodada que processou itens. Aguarda com teto (15 s) e nunca lança. |
|
|
107
|
+
| `hobots.transaction.startChild(op, descrição)` | Uma **step** no waterfall de performance da execução. A transaction da execução (`run`) já existe e é finalizada pelo SDK. `step.setStatus(status, msg?, { image })` / `setError(err, msg?, { image })` penduram um print na step. |
|
|
101
108
|
| `hobots.image(bytes \| caminho, { caption?, contentType? })` | Embrulha um **print** (PNG/JPEG/WEBP, até 5 MB, 20 por execução) para ir junto de um log, item ou step. Puro: o upload roda em segundo plano quando o evento é registrado; nunca lança nem bloqueia. |
|
|
102
109
|
| `hobots.captureException(erro, hint?)` | Abre uma **issue** (módulo Issues). `hint.attachment` anexa um print à linha de log correspondente. |
|
|
103
110
|
| `hobots.retry(fn, { retries = 3, delayMs = 1_000, shouldRetry? })` | async-retry ciente do cancelamento da execução. `delayMs` aceita função `(tentativa) => ms`. |
|
|
104
111
|
| `hobots.sleep(ms)` | Espera **cancelável**: rejeita com `RunCanceled` se a execução for cancelada. |
|
|
105
112
|
| `hobots.signal` · `hobots.throwIfCanceled()` | Cancelamento cooperativo manual, para controle fino. |
|
|
106
|
-
| `hobots.runId` · `hobots.
|
|
113
|
+
| `hobots.runId` · `hobots.params` | Identidade da execução atual. |
|
|
107
114
|
| `hobots.register(...)` · `hobots.start(...)` · `hobots.close(timeoutMs?)` | Ciclo de vida do processo. |
|
|
108
115
|
|
|
109
116
|
O handler também recebe o mesmo contexto como 2º argumento (`(params, ctx) => …`), para quem prefere explícito. Fora de qualquer execução (ex.: antes do boot), os membros de contexto caem em fallbacks seguros e avisam uma vez — `hobots.log` continua imprimindo no terminal. Evite `const { log } = hobots` no topo de um módulo: o valor capturado é o de fora de execução; chame `hobots.log.info(...)`.
|
|
@@ -125,10 +132,10 @@ Num loop de itens, isso costuma bastar: registrar o item processado já é o pon
|
|
|
125
132
|
|
|
126
133
|
## Retry
|
|
127
134
|
|
|
128
|
-
Quando o handler lança, o SDK **tenta de novo na mesma execução**: aviso no log (`tentativa 1/2 falhou: … — nova tentativa em 5000ms`), espera cancelável, re-invocação com os mesmos `params`. Default: **1 tentativa extra** com 5 s. Itens e progresso já enviados permanecem — escreva handlers **idempotentes** (use o `id` de negócio nos itens: repetido, o servidor
|
|
135
|
+
Quando o handler lança, o SDK **tenta de novo na mesma execução**: aviso no log (`tentativa 1/2 falhou: … — nova tentativa em 5000ms`), espera cancelável, re-invocação com os mesmos `params`. Default: **1 tentativa extra** com 5 s. Itens e progresso já enviados permanecem — escreva handlers **idempotentes** (use o `id` de negócio nos itens: repetido, o servidor atualiza em vez de duplicar).
|
|
129
136
|
|
|
130
137
|
```js
|
|
131
|
-
hobots.register(
|
|
138
|
+
hobots.register(handler, { retries: 3, retryDelayMs: attempt => attempt * 10_000 });
|
|
132
139
|
```
|
|
133
140
|
|
|
134
141
|
Nunca há nova tentativa em **cancelamento**, **timeout** (`TaskTimeout` é terminal) ou execução já cancelada no app. Para uma chamada instável dentro do handler, use `hobots.retry()`.
|
|
@@ -138,8 +145,8 @@ Nunca há nova tentativa em **cancelamento**, **timeout** (`TaskTimeout` é term
|
|
|
138
145
|
## Opções
|
|
139
146
|
|
|
140
147
|
```ts
|
|
141
|
-
hobots.register(
|
|
142
|
-
hobots.start(
|
|
148
|
+
hobots.register(handler, options?: RegisterOptions);
|
|
149
|
+
hobots.start(handler, options?: StartOptions);
|
|
143
150
|
```
|
|
144
151
|
|
|
145
152
|
| Opção | Default | Descrição |
|
|
@@ -152,14 +159,15 @@ hobots.start(task, handler, options?: StartOptions);
|
|
|
152
159
|
| `debug` | `false` | Loga a atividade do SDK |
|
|
153
160
|
| `machineMetrics` | `true` | CPU/memória/disco no heartbeat e em cada evento |
|
|
154
161
|
| `captureUnhandled` | `true` | `uncaughtException`/`unhandledRejection` viram issues |
|
|
162
|
+
| `items` | — | `{ columns: [...] }` — colunas da aba de itens no app (uma declaração, do agente) |
|
|
155
163
|
| `retries` | `1` | Tentativas extras do handler (0 desliga) |
|
|
156
164
|
| `retryDelayMs` | `5_000` | ms fixo ou `(tentativa) => ms` |
|
|
157
165
|
| `timeoutMs` | — (infinito) | Timeout por tentativa; terminal (`TaskTimeout`). O handler não é morto: o signal dispara e o slot é liberado |
|
|
158
|
-
| `concurrency` (register) | `1` | Execuções simultâneas
|
|
166
|
+
| `concurrency` (register) | `1` | Execuções simultâneas do agente (1..5) |
|
|
159
167
|
| `pollIntervalMs` (register) | `2_000` | Intervalo entre polls sem trabalho (mín. 1_000) |
|
|
160
168
|
| avançadas: `installExitHandlers`, `logFlushIntervalMs`, `cancelCheckIntervalMs`, `cancelGraceMs` | `true`, `2_000`, `5_000`, `10_000` | Ver [Referência de API](./docs/api-reference.md) |
|
|
161
169
|
|
|
162
|
-
|
|
170
|
+
Como só há uma chamada por processo, todas as opções são as **do agente** — não existe "opção de processo" separada da "opção da task".
|
|
163
171
|
|
|
164
172
|
---
|
|
165
173
|
|
|
@@ -181,13 +189,15 @@ Sem handler próprio de sinal, um `SIGINT`/`SIGTERM` (ou erro fatal) com execuç
|
|
|
181
189
|
|
|
182
190
|
## Changelog resumido
|
|
183
191
|
|
|
192
|
+
- **4.0.0** — **o agente é a própria tarefa** (breaking): `register(handler, options?)`/`start(handler, options?)` **sem slug**; **uma chamada por processo** (a segunda lança); `hobots.task`/`ctx.task` removidos; tipos `TaskHandler`→`RunHandler`, `TaskOptions`→`RunOptions`, `TaskItemsOptions`→`ItemsOptions`; wire: `InstanceInfo.mode` (`on_demand` \| `always_on`) e `InstanceInfo.items` no lugar de `tasks`/`task_items`, endpoints em `/v1/runs/*`; eco no terminal `[hobots] INFO …`. Guia de migração no [CHANGELOG](./CHANGELOG.md).
|
|
193
|
+
- **3.4.0** — `hobots.attach()` removido; o print vai junto do evento: `hobots.image(...)` no último argumento de `log.*`, `{ image }` em itens e steps.
|
|
184
194
|
- **3.1.0** — `hobots.log.*` aceita vários argumentos (como `console.log`); `retries` inválido (`NaN`) cai no default em vez de tentar para sempre; 429 de itens e 429/501/503 de anexo são definitivos (sem esperar a ladder — `quota`/`unsupported` passam a funcionar de fato); timeout **por requisição** nos anexos; truncamento nos limites do servidor (tag 512, fingerprint 10×255, nome de transaction 500, 200 steps, `exception.value` 8192, `filename` 1024); PNG acima de 20 000 px não declara dimensões; PATCH terminal nunca passa de 100 logs.
|
|
185
195
|
|
|
186
196
|
## Documentação
|
|
187
197
|
|
|
188
|
-
- [Getting started](./docs/getting-started.md) — instalação, envs,
|
|
189
|
-
- [
|
|
190
|
-
- [Conceitos](./docs/concepts.md) — o vocabulário:
|
|
198
|
+
- [Getting started](./docs/getting-started.md) — instalação, envs, o primeiro agente nos dois modos.
|
|
199
|
+
- [Execuções](./docs/runs.md) — handler, `hobots.*`, itens, progresso, anexos, cancelamento, retry, concorrência, idempotência.
|
|
200
|
+
- [Conceitos](./docs/concepts.md) — o vocabulário: agente, execução, evento, transaction, step, heartbeat, instância, claim…
|
|
191
201
|
- [Referência de API](./docs/api-reference.md) — assinaturas, tabelas de opções e tempos.
|
|
192
202
|
- [Protocolo & transporte](./docs/protocol.md) — endpoints, envelope, retries, claim.
|
|
193
203
|
- Exemplos runnable em [`packages/hobots-sdk-demos`](../hobots-sdk-demos).
|
|
@@ -9,7 +9,6 @@ var protocol_limits_default = {
|
|
|
9
9
|
MAX_LOGS_PER_PATCH: 100,
|
|
10
10
|
MAX_ERROR_MESSAGE_CHARS: 1e4,
|
|
11
11
|
MAX_ERROR_STACK_CHARS: 2e4,
|
|
12
|
-
MAX_ITEMS_PER_RUN: 1e4,
|
|
13
12
|
MAX_ITEMS_PER_REQUEST: 500,
|
|
14
13
|
MAX_ITEM_MESSAGE_CHARS: 2e3,
|
|
15
14
|
MAX_ITEM_PAYLOAD_BYTES: 16384,
|
|
@@ -28,4 +27,4 @@ var WIRE_LIMITS = protocol_limits_default;
|
|
|
28
27
|
export {
|
|
29
28
|
WIRE_LIMITS
|
|
30
29
|
};
|
|
31
|
-
//# sourceMappingURL=chunk-
|
|
30
|
+
//# sourceMappingURL=chunk-HKCDMUA3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../protocol-limits.json","../src/wire-limits.ts"],"sourcesContent":["{\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,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":[]}
|