hobots 3.4.0 → 4.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.
@@ -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 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","{\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_RUN\": 10000,\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,mBAAqB;AAAA,EACrB,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;;;ACbO,IAAM,cAAc;","names":[]}
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} 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.transaction 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_RUN\": 10000,\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,mBAAqB;AAAA,EACrB,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;;;ACbO,IAAM,cAAc;","names":[]}
@@ -72,7 +72,10 @@ interface MachineSnapshot {
72
72
  }
73
73
 
74
74
  /**
75
- * Tipos do protocolo de tasks do Hobots (agente SDK ↔ servidor).
75
+ * Tipos do protocolo de execuções do Hobots (agente SDK ↔ servidor).
76
+ *
77
+ * O agente é a própria tarefa: não há slug de task no wire. O que o agente faz é
78
+ * identificado pelo client secret; a instância só declara COMO trabalha (`mode`).
76
79
  *
77
80
  * Este arquivo é a fonte de verdade do wire format e não pode importar nada:
78
81
  * o app valida os payloads com zod e trava o drift via `satisfies z.ZodType<...>`
@@ -91,7 +94,7 @@ interface RunLogEntry {
91
94
  message: string;
92
95
  /**
93
96
  * Ids dos anexos (imagens) desta linha — gerados pelo agente (32 hex) e criados via
94
- * `POST /v1/tasks/runs/{id}/attachments`. O upload roda em segundo plano: a linha pode
97
+ * `POST /v1/runs/{id}/attachments`. O upload roda em segundo plano: a linha pode
95
98
  * chegar ao servidor antes do binário estar no S3.
96
99
  */
97
100
  attachments?: string[];
@@ -102,8 +105,10 @@ interface ItemColumn {
102
105
  /** ausente = a plataforma exibe a própria key */
103
106
  label?: string;
104
107
  }
105
- /** Colunas de itens declaradas no código para uma task (`items.columns` do register/start). */
106
- interface TaskItemsDeclaration {
108
+ /** Como a instância trabalha: 'on_demand' = register (poll de solicitações); 'always_on' = start (abre a própria run). */
109
+ type InstanceMode = 'on_demand' | 'always_on';
110
+ /** Colunas de itens declaradas no código (`items.columns` do register/start). */
111
+ interface ItemsDeclaration {
107
112
  attributes: ItemColumn[];
108
113
  }
109
114
  interface InstanceInfo {
@@ -116,10 +121,10 @@ interface InstanceInfo {
116
121
  host?: string;
117
122
  /** Ambiente da instância — mesmo valor do heartbeat; agentes poll-only só o informam aqui */
118
123
  environment?: EnvironmentInput;
119
- /** Tasks registradas no agente */
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>;
124
+ /** Modo de trabalho desta instância (register = on_demand, start = always_on) */
125
+ mode?: InstanceMode;
126
+ /** Colunas de itens declaradas no código — só quando o register/start declarou `items` */
127
+ items?: ItemsDeclaration;
123
128
  /**
124
129
  * Intervalo de poll em ms — alimenta a tolerância de offline do servidor (3×) em
125
130
  * agentes poll-only, que sem isso herdariam a tolerância do heartbeat (30s × 3).
@@ -128,17 +133,14 @@ interface InstanceInfo {
128
133
  /** Recursos da máquina no momento do poll — alimenta a série da instância em agentes sem heartbeat */
129
134
  machine?: MachineSnapshot;
130
135
  }
131
- /** POST /v1/tasks/poll */
136
+ /** POST /v1/runs/poll */
132
137
  interface PollRequest {
133
138
  instance?: InstanceInfo;
134
139
  /** Quantas runs reivindicar de uma vez (1..5). Default: 1 */
135
140
  max?: number;
136
- /** Só entrega runs destas tasks (nomes registrados no agente) */
137
- tasks?: string[];
138
141
  }
139
142
  interface RunDescriptor {
140
143
  id: string;
141
- task: string;
142
144
  params: Record<string, unknown>;
143
145
  form: {
144
146
  id: string;
@@ -153,13 +155,11 @@ interface PollResponse {
153
155
  runs: RunDescriptor[];
154
156
  }
155
157
  /**
156
- * POST /v1/tasks/runs — modo start do SDK: a própria instância abre a run, que já
158
+ * POST /v1/runs — modo start do SDK: a própria instância abre a run, que já
157
159
  * nasce 'running' (started_at = now), sem formulário nem solicitante. Dali em diante
158
160
  * ela é reportada pelas mesmas rotas de uma run reivindicada no poll.
159
161
  */
160
162
  interface RunCreateRequest {
161
- /** slug da task (1..255) — vira task_runs.task_slug */
162
- task: string;
163
163
  /** presença da instância — obrigatória: a run nasce vinculada à instância */
164
164
  instance: InstanceInfo;
165
165
  }
@@ -181,7 +181,7 @@ interface RunProgress {
181
181
  /** total de itens previsto (>= 1) */
182
182
  total: number;
183
183
  }
184
- /** PATCH /v1/tasks/runs/{id} — 'running' pode repetir com logs incrementais */
184
+ /** PATCH /v1/runs/{id} — 'running' pode repetir com logs incrementais */
185
185
  interface RunUpdateRequest {
186
186
  status: RunUpdateStatus;
187
187
  /** Apenas com status 'failed' */
@@ -219,7 +219,7 @@ interface RunItemInput {
219
219
  /** Ids de anexo (print do item) — opcional; mesmo teto por entrada das linhas de log */
220
220
  attachments?: string[];
221
221
  }
222
- /** POST /v1/tasks/runs/{id}/items — aceito mesmo com a run cancelada/terminal */
222
+ /** POST /v1/runs/{id}/items — aceito mesmo com a run cancelada/terminal */
223
223
  interface RunItemsCreateRequest {
224
224
  items: RunItemInput[];
225
225
  }
@@ -231,7 +231,7 @@ interface RunItemsCreateResponse {
231
231
  }
232
232
  /** Formatos aceitos para anexo. O S3 valida o content-type contra a assinatura. */
233
233
  type RunAttachmentContentType = 'image/png' | 'image/jpeg' | 'image/webp';
234
- /** POST /v1/tasks/runs/{id}/attachments */
234
+ /** POST /v1/runs/{id}/attachments */
235
235
  interface RunAttachmentCreateRequest {
236
236
  /** Id do anexo gerado pelo agente (32 hex) — já referenciado no log/item/step que o carrega */
237
237
  id: string;
@@ -253,7 +253,7 @@ interface RunAttachmentCreateResponse {
253
253
  /** Validade da URL, em segundos */
254
254
  expires_in: number;
255
255
  }
256
- /** PATCH /v1/tasks/runs/{id}/attachments/{attachmentId} */
256
+ /** PATCH /v1/runs/{id}/attachments/{attachmentId} */
257
257
  interface RunAttachmentConfirmRequest {
258
258
  status: 'uploaded' | 'failed';
259
259
  size_bytes?: number;
@@ -407,7 +407,7 @@ interface TransactionPayload {
407
407
  tags?: Record<string, string>;
408
408
  release?: string;
409
409
  environment?: EnvironmentInput;
410
- /** Correlaciona esta transaction a uma execução de task (ctx.tx dentro de um task handler) */
410
+ /** Correlaciona esta transaction a uma execução do agente (hobots.transaction dentro do handler) */
411
411
  run_id?: string;
412
412
  }
413
413
  interface HeartbeatPayload {
@@ -443,4 +443,4 @@ interface Envelope {
443
443
  items: EnvelopeItem[];
444
444
  }
445
445
 
446
- export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, type HeartbeatPayload, type InstanceInfo, type ItemColumn, 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 TaskItemsDeclaration, type TransactionPayload, WIRE_LIMITS, type WireLimits };
446
+ export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, 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 };
@@ -72,7 +72,10 @@ interface MachineSnapshot {
72
72
  }
73
73
 
74
74
  /**
75
- * Tipos do protocolo de tasks do Hobots (agente SDK ↔ servidor).
75
+ * Tipos do protocolo de execuções do Hobots (agente SDK ↔ servidor).
76
+ *
77
+ * O agente é a própria tarefa: não há slug de task no wire. O que o agente faz é
78
+ * identificado pelo client secret; a instância só declara COMO trabalha (`mode`).
76
79
  *
77
80
  * Este arquivo é a fonte de verdade do wire format e não pode importar nada:
78
81
  * o app valida os payloads com zod e trava o drift via `satisfies z.ZodType<...>`
@@ -91,7 +94,7 @@ interface RunLogEntry {
91
94
  message: string;
92
95
  /**
93
96
  * Ids dos anexos (imagens) desta linha — gerados pelo agente (32 hex) e criados via
94
- * `POST /v1/tasks/runs/{id}/attachments`. O upload roda em segundo plano: a linha pode
97
+ * `POST /v1/runs/{id}/attachments`. O upload roda em segundo plano: a linha pode
95
98
  * chegar ao servidor antes do binário estar no S3.
96
99
  */
97
100
  attachments?: string[];
@@ -102,8 +105,10 @@ interface ItemColumn {
102
105
  /** ausente = a plataforma exibe a própria key */
103
106
  label?: string;
104
107
  }
105
- /** Colunas de itens declaradas no código para uma task (`items.columns` do register/start). */
106
- interface TaskItemsDeclaration {
108
+ /** Como a instância trabalha: 'on_demand' = register (poll de solicitações); 'always_on' = start (abre a própria run). */
109
+ type InstanceMode = 'on_demand' | 'always_on';
110
+ /** Colunas de itens declaradas no código (`items.columns` do register/start). */
111
+ interface ItemsDeclaration {
107
112
  attributes: ItemColumn[];
108
113
  }
109
114
  interface InstanceInfo {
@@ -116,10 +121,10 @@ interface InstanceInfo {
116
121
  host?: string;
117
122
  /** Ambiente da instância — mesmo valor do heartbeat; agentes poll-only só o informam aqui */
118
123
  environment?: EnvironmentInput;
119
- /** Tasks registradas no agente */
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>;
124
+ /** Modo de trabalho desta instância (register = on_demand, start = always_on) */
125
+ mode?: InstanceMode;
126
+ /** Colunas de itens declaradas no código — só quando o register/start declarou `items` */
127
+ items?: ItemsDeclaration;
123
128
  /**
124
129
  * Intervalo de poll em ms — alimenta a tolerância de offline do servidor (3×) em
125
130
  * agentes poll-only, que sem isso herdariam a tolerância do heartbeat (30s × 3).
@@ -128,17 +133,14 @@ interface InstanceInfo {
128
133
  /** Recursos da máquina no momento do poll — alimenta a série da instância em agentes sem heartbeat */
129
134
  machine?: MachineSnapshot;
130
135
  }
131
- /** POST /v1/tasks/poll */
136
+ /** POST /v1/runs/poll */
132
137
  interface PollRequest {
133
138
  instance?: InstanceInfo;
134
139
  /** Quantas runs reivindicar de uma vez (1..5). Default: 1 */
135
140
  max?: number;
136
- /** Só entrega runs destas tasks (nomes registrados no agente) */
137
- tasks?: string[];
138
141
  }
139
142
  interface RunDescriptor {
140
143
  id: string;
141
- task: string;
142
144
  params: Record<string, unknown>;
143
145
  form: {
144
146
  id: string;
@@ -153,13 +155,11 @@ interface PollResponse {
153
155
  runs: RunDescriptor[];
154
156
  }
155
157
  /**
156
- * POST /v1/tasks/runs — modo start do SDK: a própria instância abre a run, que já
158
+ * POST /v1/runs — modo start do SDK: a própria instância abre a run, que já
157
159
  * nasce 'running' (started_at = now), sem formulário nem solicitante. Dali em diante
158
160
  * ela é reportada pelas mesmas rotas de uma run reivindicada no poll.
159
161
  */
160
162
  interface RunCreateRequest {
161
- /** slug da task (1..255) — vira task_runs.task_slug */
162
- task: string;
163
163
  /** presença da instância — obrigatória: a run nasce vinculada à instância */
164
164
  instance: InstanceInfo;
165
165
  }
@@ -181,7 +181,7 @@ interface RunProgress {
181
181
  /** total de itens previsto (>= 1) */
182
182
  total: number;
183
183
  }
184
- /** PATCH /v1/tasks/runs/{id} — 'running' pode repetir com logs incrementais */
184
+ /** PATCH /v1/runs/{id} — 'running' pode repetir com logs incrementais */
185
185
  interface RunUpdateRequest {
186
186
  status: RunUpdateStatus;
187
187
  /** Apenas com status 'failed' */
@@ -219,7 +219,7 @@ interface RunItemInput {
219
219
  /** Ids de anexo (print do item) — opcional; mesmo teto por entrada das linhas de log */
220
220
  attachments?: string[];
221
221
  }
222
- /** POST /v1/tasks/runs/{id}/items — aceito mesmo com a run cancelada/terminal */
222
+ /** POST /v1/runs/{id}/items — aceito mesmo com a run cancelada/terminal */
223
223
  interface RunItemsCreateRequest {
224
224
  items: RunItemInput[];
225
225
  }
@@ -231,7 +231,7 @@ interface RunItemsCreateResponse {
231
231
  }
232
232
  /** Formatos aceitos para anexo. O S3 valida o content-type contra a assinatura. */
233
233
  type RunAttachmentContentType = 'image/png' | 'image/jpeg' | 'image/webp';
234
- /** POST /v1/tasks/runs/{id}/attachments */
234
+ /** POST /v1/runs/{id}/attachments */
235
235
  interface RunAttachmentCreateRequest {
236
236
  /** Id do anexo gerado pelo agente (32 hex) — já referenciado no log/item/step que o carrega */
237
237
  id: string;
@@ -253,7 +253,7 @@ interface RunAttachmentCreateResponse {
253
253
  /** Validade da URL, em segundos */
254
254
  expires_in: number;
255
255
  }
256
- /** PATCH /v1/tasks/runs/{id}/attachments/{attachmentId} */
256
+ /** PATCH /v1/runs/{id}/attachments/{attachmentId} */
257
257
  interface RunAttachmentConfirmRequest {
258
258
  status: 'uploaded' | 'failed';
259
259
  size_bytes?: number;
@@ -407,7 +407,7 @@ interface TransactionPayload {
407
407
  tags?: Record<string, string>;
408
408
  release?: string;
409
409
  environment?: EnvironmentInput;
410
- /** Correlaciona esta transaction a uma execução de task (ctx.tx dentro de um task handler) */
410
+ /** Correlaciona esta transaction a uma execução do agente (hobots.transaction dentro do handler) */
411
411
  run_id?: string;
412
412
  }
413
413
  interface HeartbeatPayload {
@@ -443,4 +443,4 @@ interface Envelope {
443
443
  items: EnvelopeItem[];
444
444
  }
445
445
 
446
- export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, type HeartbeatPayload, type InstanceInfo, type ItemColumn, 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 TaskItemsDeclaration, type TransactionPayload, WIRE_LIMITS, type WireLimits };
446
+ export { type Breadcrumb, type BreadcrumbLevel, type Envelope, type EnvelopeItem, type Environment, type EnvironmentInput, type EventPayload, type EventType, type EventUser, type ExceptionData, 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 };
package/docs/README.md CHANGED
@@ -2,27 +2,29 @@
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
- **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.
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.transaction`… — de qualquer lugar do programa.
6
6
 
7
7
  | Modo | Chamada | Para quê |
8
8
  | --- | --- | --- |
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. |
9
+ | **Sob demanda** | `hobots.register(handler, options?)` | O robô faz polling e executa uma solicitação do app (formulário do agente/agendamento) por vez — módulo **Trabalhos**. |
10
+ | **Sempre ligado** | `hobots.start(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
+
12
+ Uma chamada por processo: um processo é um agente, e um agente faz uma coisa.
11
13
 
12
14
  ## Páginas
13
15
 
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.
16
+ - [Getting started](./getting-started.md) — instalação, envs, o primeiro agente nos dois modos, encerramento.
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, transaction, step, heartbeat, instância, claim.
17
19
  - [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.
20
+ - [Protocolo & transporte](./protocol.md) — Client Secret, endpoints (`/v1/ingest`, `/v1/runs/*`), envelope, retries, claim atômico.
19
21
 
20
22
  ## Exemplo mínimo
21
23
 
22
24
  ```js
23
25
  import hobots from 'hobots'; // HOBOTS_CLIENT_SECRET e HOBOTS_INSTANCE_ID no ambiente
24
26
 
25
- hobots.register('processar-nfe', async params => {
27
+ hobots.register(async params => {
26
28
  hobots.log.info(`processando lote ${params.lote}…`);
27
29
  hobots.items.succeeded({ numero_nota: '123' }, { id: '123' });
28
30
  hobots.log.success('concluído'); // o retorno do handler é ignorado — reporte por log/itens
@@ -4,43 +4,46 @@
4
4
 
5
5
  | Import | Conteúdo |
6
6
  | --- | --- |
7
- | `hobots` | `hobots` (default e named), `register`, `start`, `close`, `captureException`, `retry` e os tipos. |
8
- | `hobots/protocol` | Tipos do wire format (telemetria e tasks). |
7
+ | `hobots` | `hobots` (default e named), `register`, `start`, `close`, `captureException`, `retry`, `image` e os tipos. |
8
+ | `hobots/protocol` | Tipos do wire format (telemetria e execuções). |
9
9
 
10
- ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois da primeira task, `globalThis.hobots` também existe (tipado via `declare global`).
10
+ ESM e CommonJS (`const { hobots } = require('hobots')`), com `.d.ts`. Depois do `register()`/`start()`, `globalThis.hobots` também existe (tipado via `declare global`).
11
11
 
12
12
  ## Funções do processo
13
13
 
14
14
  | Função | Assinatura | Notas |
15
15
  | --- | --- | --- |
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. |
16
+ | `hobots.register` | `<P>(handler: RunHandler<P>, options?: RegisterOptions) => void` | Agente sob demanda. Síncrona: valida handler/secret e lança na hora. O boot roda num microtask. **Uma chamada por processo** (register ou start) — a segunda lança `o agente já foi iniciado`. |
17
+ | `hobots.start` | `(handler: RunHandler, options?: StartOptions) => void` | Agente sempre ligado: abre a própria execução e roda o handler uma vez. Mesma regra de uma chamada por processo. |
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
- | `hobots.captureException` | `(error: unknown, hint?: CaptureHint) => string \| undefined` | Issue no módulo Issues; devolve o `event_id`. Antes de qualquer task: descarta com aviso. |
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.image` | `(input: AttachInput, options?: ImageOptions) => ImageAttachment` | Embrulha um print para ir junto de um log, item ou step. Puro, nunca lança. |
21
22
 
22
23
  ## Contexto da execução (`RunContext` — os membros de `hobots` e o `ctx` do handler)
23
24
 
24
25
  | Membro | Tipo | Notas |
25
26
  | --- | --- | --- |
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`); um `hobots.image(...)` no **último** argumento vira o print da linha |
27
+ | `runId` | `string` | Identidade da execução (`''` fora de uma execução) |
28
+ | `params` | `Record<string, unknown>` | Params da solicitação (formulário do agente); `{}` no modo start |
29
+ | `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 …` |
29
30
  | `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` + step em erro e o loop segue; `item: RunItemHandle` = `succeeded(payload?, { image }?)/failed(msg, payload?, { image }?)/occurrence(…)`, `id`, `index`, `step`, `reported` | Ponto de parada cooperativo (o `each` para só em cancelamento/timeout) |
30
31
  | `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', message?, { image }?)`, `setError(err, message?, { image }?)` (motivo em `data.error`, print em `data.attachments`, exibidos na Central), `setData(k, v)`, `finish()` | Finalizada pelo SDK; `startChild` é ponto de parada |
32
+ | `transaction` | `Transaction` (`run`, op `hobots.run`) — `startChild(op?, description?)`, `setTag`, `setStatus`, `setName`; `Step` — `startChild`, `setStatus('ok' \| 'warning' \| 'error', message?, { image }?)`, `setError(err, message?, { image }?)` (motivo em `data.error`, print em `data.attachments`, exibidos na Central), `setData(k, v)`, `finish()` | Finalizada pelo SDK; `startChild` é ponto de parada |
32
33
  | `signal` | `AbortSignal` | Cancelamento (app, timeout, shutdown) |
33
34
  | `throwIfCanceled()` | `() => void` | Lança `RunCanceled` se o signal disparou |
34
35
  | `sleep(ms)` | `(ms: number) => Promise<void>` | Rejeita com `RunCanceled` no cancelamento |
35
36
  | `retry(fn, options?)` | como `hobots.retry` | |
36
37
 
37
- `hobots.image(input, options?)` — `(input: AttachInput, options?: ImageOptions) => ImageAttachment`; `AttachInput = Uint8Array \| ArrayBuffer \| string` (caminho); `ImageOptions = { caption?, contentType? }`; `ImageInput = AttachInput \| ImageAttachment` é o que `log.*` (só o embrulho), `items.*` e `step.setStatus/setError` aceitam. Puro, nunca lança; o upload (segundo plano, nunca bloqueia) acontece quando o evento é registrado.
38
+ `AttachInput = Uint8Array \| ArrayBuffer \| string` (caminho); `ImageOptions = { caption?, contentType? }`; `ImageInput = AttachInput \| ImageAttachment` é o que `log.*` (só o embrulho), `items.*` e `step.setStatus/setError` aceitam. O upload (segundo plano, nunca bloqueia) acontece quando o evento é registrado.
38
39
 
39
40
  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).
40
41
 
41
42
  ## Tabelas de opções
42
43
 
43
- ### `HobotsOptions` (processo — a primeira chamada define; divergências avisam e são ignoradas)
44
+ Só há uma chamada por processo, então todas as opções são **do agente**. Os tipos se empilham: `HobotsOptions` (telemetria e identidade) → `RunOptions` (a execução) → `RegisterOptions` (só sob demanda); `StartOptions = RunOptions`.
45
+
46
+ ### `HobotsOptions` (telemetria, identidade, handlers globais)
44
47
 
45
48
  | Opção | Tipo | Default | Descrição |
46
49
  | --- | --- | --- | --- |
@@ -54,26 +57,26 @@ Fora de uma execução, `hobots.*` cai em fallbacks seguros com aviso único por
54
57
  | `captureUnhandled` | `boolean` | `true` | handlers globais de erro (issues) |
55
58
  | `installExitHandlers` | `boolean` | `true` | avançado — SIGINT/SIGTERM/uncaughtException reportam `AgentTerminated` |
56
59
 
57
- ### `TaskOptions extends HobotsOptions` (por task)
60
+ ### `RunOptions extends HobotsOptions` (a execução — `register` e `start`)
58
61
 
59
62
  | Opção | Tipo | Default | Descrição |
60
63
  | --- | --- | --- | --- |
64
+ | `items` | `ItemsOptions` = `{ columns: Array<string \| { key, label? }> }` | — | colunas da aba de itens no app (chaves do `payload` dos itens); até 12, chave `[a-zA-Z0-9_.-]`. Uma declaração só, do agente; independe de formulário; personalizar no app sobrepõe |
61
65
  | `retries` | `number` | `1` | tentativas extras do handler; `0` desliga |
62
66
  | `retryDelayMs` | `number \| (attempt) => number` | `5_000` | `attempt` 1-based (a que falhou) |
63
67
  | `timeoutMs` | `number` | — | por tentativa; terminal (`TaskTimeout`) |
64
68
  | `logFlushIntervalMs` | `number` | `2_000` | avançado |
65
69
  | `cancelCheckIntervalMs` | `number` | `5_000` (1_000..15_000) | avançado — PATCH vazio que detecta cancelamento e é o sinal de vida da execução |
66
70
  | `cancelGraceMs` | `number` | `10_000` | avançado — graça após o signal antes de liberar o slot |
67
- | `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 |
68
71
 
69
- ### `RegisterOptions extends TaskOptions`
72
+ ### `RegisterOptions extends RunOptions` (só sob demanda)
70
73
 
71
74
  | Opção | Tipo | Default | Descrição |
72
75
  | --- | --- | --- | --- |
73
- | `concurrency` | `number` | `1` | execuções simultâneas desta task (1..5) |
74
- | `pollIntervalMs` | `number` | `2_000` (mín. 1_000) | intervalo entre polls sem trabalho; vale o do primeiro `register()` |
76
+ | `concurrency` | `number` | `1` | execuções simultâneas do agente (1..5) |
77
+ | `pollIntervalMs` | `number` | `2_000` (mín. 1_000) | intervalo entre polls sem trabalho |
75
78
 
76
- `StartOptions = TaskOptions`.
79
+ `StartOptions = RunOptions`.
77
80
 
78
81
  ### `RetryOptions`
79
82
 
@@ -91,12 +94,22 @@ Fora de uma execução, `hobots.*` cai em fallbacks seguros com aviso único por
91
94
  | `tags`, `extra`, `fingerprint` | | metadados do evento (`fingerprint` sobrescreve o agrupamento) |
92
95
  | `attachment` | `ImageInput \| { image, caption?, contentType? }` | print anexado à linha de log da execução atual |
93
96
 
94
- ### `TaskHandler`
97
+ ### `RunHandler`
95
98
 
96
99
  ```ts
97
- type TaskHandler<P = Record<string, unknown>> = (params: P, ctx: RunContext) => void | Promise<void>;
100
+ type RunHandler<P = Record<string, unknown>> = (params: P, ctx: RunContext) => void | Promise<void>;
98
101
  ```
99
102
 
103
+ ### Tipos do wire que mudaram na 4.0
104
+
105
+ | Tipo | O que é |
106
+ | --- | --- |
107
+ | `InstanceMode` | `'on_demand' \| 'always_on'` — como a instância trabalha (`register` / `start`) |
108
+ | `ItemsDeclaration` | `{ attributes: ItemColumn[] }` — as colunas de itens declaradas pela opção `items` |
109
+ | `InstanceInfo` | ganhou `mode?: InstanceMode` e `items?: ItemsDeclaration`; perdeu a lista de tasks e as colunas por task da 3.x |
110
+ | `PollRequest` | `{ instance?, max? }` — sem lista de tasks |
111
+ | `RunDescriptor` / `RunCreateRequest` | sem `task` |
112
+
100
113
  ## Tempos e intervalos
101
114
 
102
115
  | O quê | Valor |
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: task, execução, item, evento, issue, transaction, step, heartbeat, instância, claim. As outras páginas mostram **como usar**; aqui está o **por que existe**.
3
+ Esta página explica **o que cada coisa é** — o vocabulário que as outras páginas usam: agente, execução, item, evento, issue, transaction, step, 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
 
@@ -8,14 +8,14 @@ Defaults numéricos vivem em [Tempos e intervalos](./api-reference.md#tempos-e-i
8
8
 
9
9
  | Conceito | Em uma frase | Quando você usa |
10
10
  | --- | --- | --- |
11
- | [Task](#task) | O que o robô sabe fazer, por slug | `hobots.register` / `hobots.start` |
11
+ | [Agente](#agente) | O seu robô: um processo, uma coisa que ele faz | `hobots.register` / `hobots.start` |
12
12
  | [Modo sob demanda](#modo-sob-demanda-register) | Uma execução por solicitação do app | O trabalho é disparado por alguém (formulário, agendamento) |
13
13
  | [Modo sempre ligado](#modo-sempre-ligado-start) | O robô abre a própria execução e roda o seu loop | O robô vive rodando e você só quer ver o que ele faz |
14
- | [Execução (run)](#execução-run) | Uma rodada de uma task, com logs, itens e resultado | A unidade de tudo em Solicitações |
14
+ | [Execução (run)](#execução-run) | Uma rodada do agente, com logs, itens e resultado | A unidade de tudo em Trabalhos |
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 numa linha de log | "Como estava a tela?" |
18
+ | [Anexo](#anexo) | Um print pendurado num log, item ou step | "Como estava a tela?" |
19
19
  | [Cancelamento cooperativo](#cancelamento-cooperativo) | O app pede, o handler para no próximo ponto de parada | Automático em items/progress/steps/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 |
@@ -31,39 +31,39 @@ 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 | **Configurações → Agentes** |
35
- | **Instância** — o par `(agente, instanceId)`; heartbeat e tasks convergem nela | Módulo **Instâncias** (uptime, recursos da máquina, performance) |
36
- | **Task / execução** — `register('slug', …)` casa com o `task_slug` do formulário; `start('slug', …)` abre a própria execução | Módulo **Solicitações** (formulários em **Configurações → Formulários**) |
34
+ | **Agente** — dono do Client Secret (`hb_…`) que autentica tudo; o que ele faz é o handler de `register()`/`start()` | **Configurações → Agentes** (o formulário do agente fica aqui) |
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
+ | **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
  | **Transaction / steps** — `hobots.transaction` | Aba de performance da execução |
39
39
 
40
40
  ---
41
41
 
42
- ## Task
42
+ ## Agente
43
43
 
44
- Uma **task** é uma capacidade nomeada do robô — "processar NF-e", "monitorar a pasta de entrada" — identificada por um **slug** estável. Registrar uma task é a única forma de configurar o SDK: não há `init()`. A primeira chamada a `register()`/`start()` lê as credenciais do ambiente, liga o heartbeat e a captura de erros, e define as opções do processo (`environment`, `release`, `tags`…). Um slug só pode ser registrado uma vez.
44
+ O **agente** é o seu robô: um programa que faz **uma coisa** — "processar NF-e", "monitorar a pasta de entrada". Na plataforma ele é identificado pelo Client Secret, não por um nome no código: o processo que sobe com aquele secret *é* o agente, e o handler que você passa a `register()`/`start()` *é* a tarefa. Essa chamada é a única forma de configurar o SDK: não há `init()`. Ela lê as credenciais do ambiente, liga o heartbeat e a captura de erros, define as opções (`environment`, `release`, `tags`, `items`…) e diz como o robô trabalha. **Uma chamada por processo** — a segunda lança. Um robô que faz duas coisas são dois agentes, cada um com o seu processo e o seu Client Secret.
45
45
 
46
46
  ## Modo sob demanda (`register`)
47
47
 
48
- O robô fica **online aguardando**: faz polling na plataforma e, quando alguém cria uma solicitação para aquele slug (pelo formulário ou por um agendamento), executa o handler com os `params` do formulário. É o modo para trabalho que **alguém pede**. Várias solicitações podem rodar em paralelo (`concurrency`).
48
+ O robô fica **online aguardando**: faz polling na plataforma e, quando alguém cria uma solicitação para o agente (pelo formulário do agente ou por um agendamento), executa o handler com os `params` do formulário. É o modo para trabalho que **alguém pede**. Várias solicitações podem rodar em paralelo (`concurrency`). No painel a instância aparece como "sob demanda".
49
49
 
50
50
  ## Modo sempre ligado (`start`)
51
51
 
52
- O robô **não espera ninguém**: ao iniciar, abre a própria execução na plataforma (`source: agent`, sem formulário nem solicitante) e roda o handler dentro dela. O handler é o seu loop — um `while (true)` que vigia uma pasta, uma fila, um portal. A plataforma recebe logs, itens e progresso enquanto ele roda. Quando o handler retorna, a execução fecha; o processo continua vivo pelo heartbeat, então a instância segue online até `hobots.close()`. É **uma execução por processo**: para recomeçar, reinicie o robô. Como o servidor guarda no máximo 1000 linhas de log por execução, o trabalho feito vai em itens, não em log.
52
+ O robô **não espera ninguém**: ao iniciar, abre a própria execução na plataforma (`source: agent`, sem formulário nem solicitante) e roda o handler dentro dela. O handler é o seu loop — um `while (true)` que vigia uma pasta, uma fila, um portal. A plataforma recebe logs, itens e progresso enquanto ele roda. Quando o handler retorna, a execução fecha; o processo continua vivo pelo heartbeat, então a instância segue online até `hobots.close()`. É **uma execução por processo**: para recomeçar, reinicie o robô. Como o servidor guarda no máximo 1000 linhas de log por execução, o trabalho feito vai em itens, não em log. No painel a instância aparece como "sempre ligado".
53
53
 
54
54
  ## Execução (run)
55
55
 
56
- Uma **execução** é uma rodada concreta de uma task — no app, uma solicitação. Ciclo de vida no servidor:
56
+ Uma **execução** é uma rodada concreta do agente — no app, um trabalho. Ciclo de vida no servidor:
57
57
 
58
58
  ```
59
59
  pending → claimed → running → succeeded | failed | canceled
60
60
  ```
61
61
 
62
- No modo sob demanda a execução nasce `pending` (alguém pediu), vira `claimed` quando um agente a [reivindica](#claim) e `running` quando o handler começa. No modo sempre ligado ela já nasce `running`, criada pelo próprio robô. O agente só transiciona para `running`, `succeeded` e `failed`; `canceled` vem de alguém cancelando no app. Cada execução tem a sua transaction de performance, seus logs, itens e progresso — e o objeto `hobots` aponta para a execução **atual**, em qualquer módulo, graças ao contexto async do Node.
62
+ No modo sob demanda a execução nasce `pending` (alguém pediu), vira `claimed` quando um agente a [reivindica](#claim) e `running` quando o handler começa. No modo sempre ligado ela já nasce `running`, criada pelo próprio robô. O agente só transiciona para `running`, `succeeded` e `failed`; `canceled` vem de alguém cancelando no app. Cada execução tem a sua transaction de performance (`run`), seus logs, itens e progresso — e o objeto `hobots` aponta para a execução **atual**, em qualquer módulo, graças ao contexto async do Node.
63
63
 
64
64
  ## Item
65
65
 
66
- Um **item** é uma unidade de trabalho que a execução entregou: uma nota baixada, um boleto emitido, um arquivo movido. Tem status (`succeeded`, `failed` = falha técnica, `occurrence` = ocorrência de negócio, como "nota não encontrada") e um `payload` de atributos livres que viram colunas na aba de itens da solicitação. O `id` é a identidade de negócio do item na execução — repetido, é ignorado: é isso que torna retries idempotentes. Diferente do log, o item é **dado estruturado**: dá para contar, filtrar e conferir.
66
+ Um **item** é uma unidade de trabalho que a execução entregou: uma nota baixada, um boleto emitido, um arquivo movido. Tem status (`succeeded`, `failed` = falha técnica, `occurrence` = ocorrência de negócio, como "nota não encontrada") e um `payload` de atributos livres que viram colunas na aba de itens da execução — as colunas são declaradas no código, uma vez, pela opção `items` do agente. O `id` é a identidade de negócio do item na execução — repetido, o servidor atualiza em vez de duplicar: é isso que torna retries idempotentes. Diferente do log, o item é **dado estruturado**: dá para contar, filtrar e conferir.
67
67
 
68
68
  ## Progresso
69
69
 
@@ -71,11 +71,11 @@ O **progresso** é "quantos de quantos" (`current/total`). Declare o total antes
71
71
 
72
72
  ## Log da execução
73
73
 
74
- O **log da execução** narra o que aconteceu, em linhas com nível (`debug`, `info`, `warning`, `error`, `success`), enviadas incrementalmente e visíveis no app quase em tempo real. Ele é o único membro de `hobots` que **nunca lança**, justamente para poder ir num `finally` de limpeza. O servidor guarda até 1000 linhas por execução.
74
+ O **log da execução** narra o que aconteceu, em linhas com nível (`debug`, `info`, `warning`, `error`, `success`), enviadas incrementalmente e visíveis no app quase em tempo real (e ecoadas no terminal como `[hobots] INFO …`). Ele é o único membro de `hobots` que **nunca lança**, justamente para poder ir num `finally` de limpeza. O servidor guarda até 1000 linhas por execução.
75
75
 
76
76
  ## Anexo
77
77
 
78
- Um **anexo** é uma imagem — na prática, um print — vinculada a uma linha de log. 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…".
78
+ Um **anexo** é uma imagem — na prática, um print — vinculada ao evento que ela ilustra: uma linha de log, um item ou uma step. 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
 
@@ -91,7 +91,7 @@ Um **evento** é a foto de um erro: tipo, mensagem, stack trace, tags, ambiente,
91
91
 
92
92
  ## Transaction
93
93
 
94
- Uma **transaction** é uma unidade de trabalho **medida**: começa, termina, e o que fica é quanto tempo levou. Cada execução tem exatamente uma, aberta e finalizada pelo SDK (`hobots.transaction`), correlacionada à execução pelo `run_id`. Você não cria transactions — só adiciona etapas.
94
+ Uma **transaction** é uma unidade de trabalho **medida**: começa, termina, e o que fica é quanto tempo levou. Cada execução tem exatamente uma, chamada `run` (op `hobots.run`), aberta e finalizada pelo SDK (`hobots.transaction`), correlacionada à execução pelo `run_id`. Você não cria transactions — só adiciona etapas.
95
95
 
96
96
  ## Step
97
97
 
@@ -103,7 +103,7 @@ O **heartbeat** é o batimento "estou vivo", a cada 30 s. O servidor conhece a c
103
103
 
104
104
  ## instanceId
105
105
 
106
- A identidade da **instância** do robô: qual VM, qual container. Vem da env `HOBOTS_INSTANCE_ID` (ou da opção; sem os dois, o hostname) e deve ser **estável entre reinícios** — um valor novo a cada boot vira uma frota de robôs fantasmas. É a mesma identidade no heartbeat, no poll e na criação de execuções: um agente só no painel.
106
+ A identidade da **instância** do robô: qual VM, qual container. Vem da env `HOBOTS_INSTANCE_ID` (ou da opção; sem os dois, o hostname) e deve ser **estável entre reinícios** — um valor novo a cada boot vira uma frota de robôs fantasmas. É a mesma identidade no heartbeat, no poll e na criação de execuções: um agente só no painel. A presença da instância também declara o **modo** (`on_demand` / `always_on`) e as colunas de itens do agente.
107
107
 
108
108
  ## Release e environment
109
109
 
@@ -111,7 +111,7 @@ A identidade da **instância** do robô: qual VM, qual container. Vem da env `HO
111
111
 
112
112
  ## Claim
113
113
 
114
- O **claim** é o ato de um agente reivindicar uma execução pendente. É **server-side e atômico** (`FOR UPDATE SKIP LOCKED`): dois agentes que fazem poll no mesmo instante recebem conjuntos disjuntos — nenhum lock vive no seu processo. O agente pede só o que consegue rodar (tasks com slot livre), então nunca reivindica trabalho para deixar parado.
114
+ O **claim** é o ato de um agente reivindicar uma execução pendente. É **server-side e atômico** (`FOR UPDATE SKIP LOCKED`): dois agentes que fazem poll no mesmo instante recebem conjuntos disjuntos — nenhum lock vive no seu processo. O agente pede só o que consegue rodar (`max` = slots livres de `concurrency`), então nunca reivindica trabalho para deixar parado.
115
115
 
116
116
  ## Drain mode
117
117