@zihin/agent-client 0.2.0 → 0.4.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 CHANGED
@@ -118,6 +118,50 @@ await zihin.deleteTrigger({ triggerId }); // remove (requer key admin/owner;
118
118
  > `trigger_config` inteiro). Há uma janela entre o GET e o PATCH em que uma escrita concorrente
119
119
  > pode ser sobrescrita.
120
120
 
121
+ ## Uso — delegação assíncrona durável (tasks)
122
+
123
+ Para runs que estouram o teto do host (o passo do Zapier morre em ~30s) ou que não podem depender
124
+ da conexão viva. A task é persistida no BE, executada fora do request e o resultado notificado.
125
+ Exige key **owner/admin** para delegar e cancelar; editor só lê.
126
+
127
+ ```ts
128
+ const task = await zihin.delegateTask({
129
+ agentId,
130
+ instruction: 'Gere o relatório mensal e envie por e-mail',
131
+ title: 'Relatório de agosto',
132
+ payload: { mes: '2026-08' }, // objeto, ≤ 64KB — validado localmente
133
+ deadlineAt: new Date(Date.now() + 3600e3),
134
+ });
135
+
136
+ // polling: pare quando `terminal` for true — qualquer status desconhecido conta como terminal
137
+ let dossie;
138
+ do {
139
+ await new Promise((r) => setTimeout(r, 2000));
140
+ dossie = await zihin.getTask({ taskId: task.id });
141
+ } while (!dossie.task.terminal);
142
+
143
+ console.log(dossie.task.status, dossie.executions.at(-1)?.totalCostUsd);
144
+ await zihin.cancelTask({ taskId: task.id, reason: 'mudou o plano' }); // 409 se já encerrou
145
+ ```
146
+
147
+ `listTasks({ live: true })` devolve o board (`items` + `total`, este vindo de `meta`).
148
+
149
+ ## O texto que volta — e o que NÃO é resposta
150
+
151
+ `AgentResult.contentSource` diz de onde veio o `content`:
152
+
153
+ - **`'response'`** — o evento final do BE, que no `/stream` é sempre o modo `final` (só as mensagens
154
+ sem `tool_calls`). **É o texto seguro para publicar.**
155
+ - **`'tokens'`** — o stream morreu antes do evento final e sobrou só a concatenação crua dos deltas,
156
+ **com a deliberação interna do modelo**. Foi exatamente isso que vazou para um lead real via
157
+ WhatsApp e que o BE parou de entregar. Trate como parcial de diagnóstico; não mande para fora
158
+ sem revisar.
159
+
160
+ Um `content` vazio com `contentSource: 'response'` é decisão do BE, não lacuna — o núcleo **não**
161
+ preenche com tokens. E quando o BE fecha o stream com `event: error` (turno morto no deadline, por
162
+ exemplo), o núcleo **lança** (`kind: 'timeout'` para `TURN_TIMEOUT`, com `code` e `requestId`) em vez
163
+ de devolver o parcial.
164
+
121
165
  ## Dropdown de agentes
122
166
 
123
167
  ```ts
@@ -140,10 +184,33 @@ suporte correlacionar). Erros de rede carregam a causa-raiz (`ECONNREFUSED`/`ENO
140
184
  mensagem. As mensagens redigem **só segredos** (key/Bearer/stack) — `request_id`/`trace_id` são
141
185
  preservados. Cancele com `AbortSignal` via `params.signal`.
142
186
 
187
+ ### Bloqueio comercial não é credencial errada
188
+
189
+ Trial vencido, assinatura inativa e quota esgotada chegam do BE como 403/429 e, mapeados só pelo
190
+ status, virariam "troque a key" ou "tente de novo". Têm `kind` próprio e **nunca são retentados**:
191
+
192
+ | `kind` | HTTP | O que fazer |
193
+ |---|---|---|
194
+ | `trial_expired` | 403 | Fazer upgrade do plano — a key está certa |
195
+ | `no_subscription` | 429 | Ativar uma assinatura — a key está certa |
196
+ | `quota_exceeded` | 429 | Esperar o ciclo ou subir o plano — retentar não ajuda |
197
+
198
+ `isCommercialBlock(body)` é exportado para quem inspeciona respostas por conta própria. O 403 comum
199
+ (`kind: 'auth'`) significa que o **papel** da key não permite a ação — e o papel exigido varia por
200
+ rota (editor cria trigger, mas não delega task), então a mensagem não enumera papéis.
201
+
202
+ `ZihinAgentError.executionId` vem preenchido quando o BE o entrega (sucesso e erro) — é o handle para
203
+ correlacionar com o console.
204
+
143
205
  ## Robustez (timeout / retry / limites)
144
206
 
145
- - **Timeout cobre tudo** — headers e o corpo/stream inteiro. `timeoutMs` (default 120s, igual ao cap
146
- do BE) é o tempo máximo total da chamada; `AbortSignal` do chamador funciona durante todo o stream.
207
+ - **Timeout cobre tudo** — headers e o corpo/stream inteiro. Os defaults são **por operação**
208
+ (`OPERATION_TIMEOUT_MS`): stream 200s, dispatch de trigger 260s, GETs curtos 35s. Cada um fica
209
+ ACIMA do orçamento do BE para aquela rota (SSE 180s, turno async 240s, timeout global 30s), para
210
+ que o desfecho do servidor chegue como erro estruturado em vez de abort cego do cliente.
211
+ `timeoutMs` na config sobrepõe todos; `options.timeoutMs` por chamada vai ao BE como
212
+ `timeout_ms` e o deadline local fica um pouco acima dele. Retentativas NÃO encolhem o deadline
213
+ da tentativa seguinte — o que fica limitado é o tempo gasto com retries.
147
214
  - **Retry sem duplicar efeito** — GET (idempotente) retenta em rede/429/5xx; POST com efeito
148
215
  (`invokeAgent`/`dispatchAgent`/`createTrigger`) retenta **só em 429/503** e **nunca em erro de
149
216
  rede** (o request pode ter sido processado). Backoff exponencial 1s→10s com jitter.
package/dist/index.d.mts CHANGED
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * @module errors
6
6
  */
7
- type ZihinErrorKind = 'config' | 'auth' | 'not_found' | 'rate_limit' | 'timeout' | 'aborted' | 'server' | 'network' | 'protocol' | 'unknown';
7
+ type ZihinErrorKind = 'config' | 'auth' | 'trial_expired' | 'no_subscription' | 'quota_exceeded' | 'not_found' | 'rate_limit' | 'timeout' | 'aborted' | 'server' | 'network' | 'protocol' | 'unknown';
8
8
  /** Contexto opcional anexado a um erro para correlação/depuração. */
9
9
  interface ErrorMeta {
10
10
  /** Ex.: "POST llm.zihin.ai/api/v2/agents/abc/stream". */
@@ -18,6 +18,11 @@ interface ZihinErrorOptions extends ErrorMeta {
18
18
  retryable?: boolean;
19
19
  /** request_id do BE (NÃO é segredo) — handle para o suporte correlacionar nos logs. */
20
20
  requestId?: string;
21
+ /**
22
+ * execution_id do turno. Desde agosto/2026 o BE o entrega no sucesso E no erro (§1.2 do
23
+ * handoff) — é o handle que liga um erro daqui à execução no console/telemetria.
24
+ */
25
+ executionId?: string;
21
26
  }
22
27
  declare class ZihinAgentError extends Error {
23
28
  readonly kind: ZihinErrorKind;
@@ -27,8 +32,14 @@ declare class ZihinAgentError extends Error {
27
32
  readonly requestId?: string;
28
33
  readonly attempts?: number;
29
34
  readonly endpoint?: string;
35
+ readonly executionId?: string;
30
36
  constructor(kind: ZihinErrorKind, message: string, opts?: ZihinErrorOptions);
31
37
  }
38
+ /**
39
+ * true quando o corpo é um bloqueio comercial. Consultado pelo transporte ANTES de retentar:
40
+ * o 429 de quota é indistinguível de rate limit pelo status, e só o corpo separa os dois.
41
+ */
42
+ declare function isCommercialBlock(body: unknown): boolean;
32
43
 
33
44
  /**
34
45
  * Tipos do contrato externo Zihin — fonte de verdade verificada contra o BE
@@ -42,7 +53,13 @@ interface ZihinClientConfig {
42
53
  apiKey: string;
43
54
  /** Base URL. Default: https://llm.zihin.ai */
44
55
  baseUrl?: string;
45
- /** Timeout por request (ms). Default: 120000 (= limite do /stream no BE). */
56
+ /**
57
+ * Timeout por request (ms) — override explícito que vale para TODAS as operações. Deixe vazio
58
+ * para usar o default de cada uma (`OPERATION_TIMEOUT_MS`): stream 200s, dispatch de trigger
59
+ * 260s, GETs curtos 35s. Cada default fica acima do orçamento do BE para aquela rota, para que
60
+ * o desfecho do servidor chegue como erro estruturado em vez de abort do cliente — um valor
61
+ * único menor que isso reintroduz exatamente esse problema.
62
+ */
46
63
  timeoutMs?: number;
47
64
  /** Máximo de retentativas em 5xx/429/erro de rede. Default: 2. */
48
65
  maxRetries?: number;
@@ -137,6 +154,16 @@ interface Source {
137
154
  */
138
155
  interface AgentResult {
139
156
  content: string;
157
+ /**
158
+ * De onde veio o `content`:
159
+ * - `response`: o evento SSE `response` — o texto que o BE decidiu entregar. No `/stream` isso é
160
+ * sempre o modo `final` (só as mensagens sem `tool_calls`). É o texto seguro para publicar.
161
+ * - `tokens`: o stream terminou SEM o evento `response` e sobrou apenas a concatenação crua dos
162
+ * deltas de todas as iterações — **deliberação interna incluída**. Foi exatamente esse texto
163
+ * que vazou para um lead real e que o BE parou de entregar. Trate como parcial de diagnóstico:
164
+ * não publique em canal externo sem revisar.
165
+ */
166
+ contentSource: 'response' | 'tokens';
140
167
  sessionId?: string;
141
168
  model?: string;
142
169
  usage?: Usage;
@@ -194,6 +221,34 @@ type AgentStreamChunk = {
194
221
  type: 'warning';
195
222
  message?: string;
196
223
  data: unknown;
224
+ }
225
+ /**
226
+ * O BE encerra o stream com `event: error` + `{ error: { type, code, message, request_id } }`
227
+ * (`utils/sse.js:97`) — inclusive quando o TURNO morre no deadline. Antes isto caía em
228
+ * `unknown` e o `invokeAgent` ignorava: se já tinha chegado token, devolvia a deliberação
229
+ * crua como SUCESSO.
230
+ */
231
+ | {
232
+ type: 'error';
233
+ code?: string;
234
+ message?: string;
235
+ requestId?: string;
236
+ data: unknown;
237
+ }
238
+ /**
239
+ * Emitido no meio do turno SÓ quando o BE cunhou uma sessão diferente da pedida
240
+ * (`agents-v2.js:931`). É o id em que a conversa realmente vai continuar — vence o `session_id`
241
+ * do `metadata` e o que o chamador mandou. Visto em produção no E2E de 01/09.
242
+ */
243
+ | {
244
+ type: 'session';
245
+ sessionId?: string;
246
+ data: unknown;
247
+ }
248
+ /** Fim LIMPO do stream (`utils/sse.js:92`). Sem ele, o stream foi cortado no meio. */
249
+ | {
250
+ type: 'done';
251
+ data: unknown;
197
252
  } | {
198
253
  type: 'response';
199
254
  content: string;
@@ -217,6 +272,19 @@ type AgentStreamChunk = {
217
272
  data: unknown;
218
273
  };
219
274
  type TriggerMode = 'sync' | 'async';
275
+ /**
276
+ * Como o BE monta o texto entregue pelo trigger (`#343/#345`):
277
+ * - `final` (default): só as mensagens do agente SEM `tool_calls`. O texto que acompanha uma
278
+ * chamada de tool é deliberação interna — vazou para um lead real via WhatsApp.
279
+ * - `concat` (legado): concatena todas as iterações. Só peça se você realmente depende da
280
+ * narrativa completa e o destino é interno.
281
+ *
282
+ * ⚠️ O BE lê isto de `trigger_config.execution.callback.response_transform.mode`, e o validador dele
283
+ * exige `callback.url` sempre que o objeto `callback` existe. Consequência verificada em 2026-08-31:
284
+ * **um trigger `sync` não consegue declarar o modo sem uma callbackUrl válida**, mesmo que ela nunca
285
+ * seja chamada. `createTrigger` falha alto nesse caso em vez de mandar um config que o BE rejeita.
286
+ */
287
+ type ResponseTransformMode = 'final' | 'concat';
220
288
  /**
221
289
  * Como o BE extrai a mensagem do agente a partir do payload de disparo (webhook):
222
290
  * - `field`: um campo top-level do payload (`payload[field]`).
@@ -254,6 +322,11 @@ interface CreateTriggerParams {
254
322
  queryExtraction?: QueryExtraction;
255
323
  /** Auth de disparo aceita. Default: api_key. */
256
324
  dispatchAuth?: 'api_key' | 'signature' | 'none';
325
+ /**
326
+ * Modo de extração da resposta do agente. Default do BE: `final`. Exige `callbackUrl` — ver
327
+ * {@link ResponseTransformMode}.
328
+ */
329
+ responseTransform?: ResponseTransformMode;
257
330
  signal?: AbortSignal;
258
331
  }
259
332
  /**
@@ -273,6 +346,11 @@ interface UpdateTriggerParams {
273
346
  callbackMethod?: 'POST' | 'PUT';
274
347
  /** Troca o modo de execução (sync/async). */
275
348
  mode?: TriggerMode;
349
+ /**
350
+ * Troca o modo de extração da resposta, preservando `strip_markdown`/`max_length` já
351
+ * configurados. Exige que o trigger já tenha um `callback` (ou que `callbackUrl` venha junto).
352
+ */
353
+ responseTransform?: ResponseTransformMode;
276
354
  signal?: AbortSignal;
277
355
  }
278
356
  interface TriggerRef {
@@ -321,18 +399,42 @@ interface DispatchAgentParams {
321
399
  signal?: AbortSignal;
322
400
  }
323
401
  interface DispatchResult {
324
- /** true quando o BE retorna 202 (async) ou 200 (sync). */
402
+ /**
403
+ * true quando o BE aceitou o disparo. Um turno que FALHOU não chega aqui: o BE responde 200
404
+ * com `{ success:false }` e o núcleo lança — antes isso voltava como disparo aceito com
405
+ * resposta vazia.
406
+ */
325
407
  accepted: boolean;
326
408
  triggerId?: string;
409
+ agentId?: string;
327
410
  executionId?: string;
328
411
  /** Presente quando o trigger é `sync`: resposta imediata do agente. */
329
412
  agentResponse?: string;
330
413
  usage?: Usage;
414
+ /** Iterações do laço de tools no turno (sync). */
415
+ iterations?: number;
416
+ /** Latência medida pelo BE, ponta a ponta (sync). */
417
+ latencyMs?: number;
418
+ /**
419
+ * O texto que o BE extraiu do payload e entregou ao agente. É o campo que denuncia um
420
+ * `query_extraction` mal configurado — mensagem vazia, ou o payload inteiro virando a pergunta.
421
+ */
422
+ queryExtracted?: string;
331
423
  raw: unknown;
332
424
  }
333
425
  interface ExecutionStatus {
334
426
  executionId: string;
427
+ /**
428
+ * Status cru do BE. Além de `completed`/`failed`, o `trigger_executions` passou a registrar
429
+ * `skipped`, `quota_exhausted` e `timeout` de verdade (agosto/2026) — não trate como enum
430
+ * fechado; use `terminal` para decidir quando parar de esperar.
431
+ */
335
432
  status: string;
433
+ /**
434
+ * false só enquanto a execução está em andamento. Qualquer status desconhecido conta como
435
+ * terminal, para que o polling pare em vez de girar para sempre num estado novo do BE.
436
+ */
437
+ terminal: boolean;
336
438
  startedAt?: string;
337
439
  finishedAt?: string;
338
440
  executionTimeMs?: number;
@@ -345,6 +447,145 @@ interface GetExecutionParams {
345
447
  executionId: string;
346
448
  signal?: AbortSignal;
347
449
  }
450
+ interface DelegateTaskParams {
451
+ /** Agente que vai executar. */
452
+ agentId: string;
453
+ /** O que o agente deve fazer (obrigatório; sofre guardrail de tamanho por tier no BE). */
454
+ instruction: string;
455
+ /** Título legível para o board. */
456
+ title?: string;
457
+ /** Payload congelado junto da task. Objeto, **≤ 64KB** (teto do BE). */
458
+ payload?: Record<string, unknown>;
459
+ /**
460
+ * Quando executar. Omita para disparar imediatamente. Não pode estar no passado (o BE tolera
461
+ * 60s de diferença de relógio).
462
+ */
463
+ scheduledFor?: string | Date;
464
+ /** Prazo. Precisa ser futuro e posterior a `scheduledFor`; ao vencer, o sweep aborta o turno. */
465
+ deadlineAt?: string | Date;
466
+ retryPolicy?: Record<string, unknown>;
467
+ notify?: Record<string, unknown>;
468
+ /** Encadeia esta task sob outra (árvore parent/root). */
469
+ parentTaskId?: string;
470
+ signal?: AbortSignal;
471
+ }
472
+ /** Task como o BE a devolve. Campos além dos mapeados ficam em `raw`. */
473
+ interface TaskInfo {
474
+ id: string;
475
+ agentId?: string;
476
+ title?: string;
477
+ instruction?: string;
478
+ /** `pending` → `running` → `completed` | `failed` | `cancelled` | `expired`. Não é enum fechado. */
479
+ status: string;
480
+ /**
481
+ * false só enquanto a task está em andamento. Status desconhecido conta como terminal (parar é
482
+ * melhor que girar para sempre); status ausente conta como não-terminal (não lemos o envelope).
483
+ */
484
+ terminal: boolean;
485
+ scheduledFor?: string;
486
+ deadlineAt?: string;
487
+ parentTaskId?: string;
488
+ rootTaskId?: string;
489
+ sessionId?: string;
490
+ createdAt?: string;
491
+ updatedAt?: string;
492
+ raw: unknown;
493
+ }
494
+ interface ListTasksParams {
495
+ /** Só estados vivos (board do dia a dia). */
496
+ live?: boolean;
497
+ status?: string;
498
+ agentId?: string;
499
+ rootTaskId?: string;
500
+ limit?: number;
501
+ offset?: number;
502
+ signal?: AbortSignal;
503
+ }
504
+ interface TaskListPage {
505
+ items: TaskInfo[];
506
+ /** Total do tenant para a query. Vem de `meta.total` no envelope novo. */
507
+ total?: number;
508
+ raw: unknown;
509
+ }
510
+ /** Uma execução da task (uma task pode ter várias, com retry). */
511
+ interface TaskExecution {
512
+ id: string;
513
+ status: string;
514
+ exitReason?: string;
515
+ modelUsed?: string;
516
+ totalCostUsd?: number;
517
+ executionTimeMs?: number;
518
+ iterations?: number;
519
+ startedAt?: string;
520
+ finishedAt?: string;
521
+ raw: unknown;
522
+ }
523
+ interface TaskDossier {
524
+ task: TaskInfo;
525
+ executions: TaskExecution[];
526
+ children: TaskInfo[];
527
+ approvals: unknown[];
528
+ raw: unknown;
529
+ }
530
+ interface GetTaskParams {
531
+ taskId: string;
532
+ signal?: AbortSignal;
533
+ }
534
+ interface CancelTaskParams {
535
+ taskId: string;
536
+ /** Registrado na trilha. Default do BE: `user_cancel`. */
537
+ reason?: string;
538
+ signal?: AbortSignal;
539
+ }
540
+ interface CancelTaskResult {
541
+ task: TaskInfo;
542
+ /** true quando havia um turno em voo que foi realmente derrubado. */
543
+ aborted: boolean;
544
+ raw: unknown;
545
+ }
546
+
547
+ /**
548
+ * Transporte HTTP do núcleo: resolução/validação de base URL (SSRF), headers de auth,
549
+ * deadline via AbortController que cobre TODO o request (headers + corpo/stream),
550
+ * e retry com exponential backoff + jitter.
551
+ *
552
+ * Política de retry (evita duplicar efeito colateral):
553
+ * - 'idempotent' (GET): retenta em erro de rede, 429 e 5xx.
554
+ * - 'side-effecting' (POST: invoke/dispatch/create): retenta SÓ em 429/503 (servidor disse
555
+ * "tente depois", sem ter processado). NUNCA em erro de rede — o request pode ter sido
556
+ * recebido e processado mesmo com o socket caindo na volta.
557
+ *
558
+ * @module http
559
+ */
560
+
561
+ /**
562
+ * Deadline default POR OPERAÇÃO. Cada valor fica ACIMA do orçamento do BE para aquela rota,
563
+ * porque o BE foi desenhado para entregar o desfecho ao cliente — desistir antes dele troca um
564
+ * erro estruturado (TURN_TIMEOUT com execution_id/session_id) por um abort cego nosso.
565
+ *
566
+ * Verificado contra o BE (`zihin-agent-builder/server-llm`) em 2026-08-31:
567
+ * - `stream` POST /api/v2/agents/:id/stream — o SSE fecha em 180s (`agents-v2.js:690`) e o turno
568
+ * do canal `chat` morre em 150s (`turn-deadline.js`). O stream sobrevive ao turno DE
569
+ * PROPÓSITO, para entregar o desfecho; 200s deixa essa cauda chegar.
570
+ * - `dispatch` POST /api/triggers/webhook/:id — fora do timeout global do Express
571
+ * (`express.js:71`); turno de canal `async` = 240s (`turn-deadline.js`).
572
+ * - `short` GETs de listagem/telemetria e CRUD de trigger — timeout global de 30s
573
+ * (`express.js:40`), que responde 408. Esperar mais que isso é esperar à toa.
574
+ *
575
+ * Mudou o BE? Atualize esta tabela e `docs/CONTRATO-INVOCACAO-AGENTE.md` juntos.
576
+ */
577
+ declare const OPERATION_TIMEOUT_MS: Readonly<{
578
+ stream: 200000;
579
+ dispatch: 260000;
580
+ short: 35000;
581
+ }>;
582
+ type TimeoutOperation = keyof typeof OPERATION_TIMEOUT_MS;
583
+ /**
584
+ * Folga somada ao `options.timeoutMs` do chamador para formar o deadline LOCAL. O mesmo número vai
585
+ * ao BE como `options.timeout_ms` (o teto que ele deve respeitar); sem folga, os dois relógios
586
+ * disparam juntos e o erro do servidor — que tem request_id — perde a corrida para o nosso abort.
587
+ */
588
+ declare const DEADLINE_GRACE_MS = 10000;
348
589
 
349
590
  /**
350
591
  * Listagem de agentes do tenant (GET /api/v2/agents). Alimenta o dropdown do nó n8n (#17)
@@ -404,6 +645,17 @@ declare class ZihinAgentClient {
404
645
  dispatchAgent(params: DispatchAgentParams): Promise<DispatchResult>;
405
646
  /** Consulta o resultado de uma execução disparada por trigger (polling). */
406
647
  getExecution(params: GetExecutionParams): Promise<ExecutionStatus>;
648
+ /**
649
+ * Delega uma tarefa a um agente (requer key owner/admin). Sem `scheduledFor`, o BE dispara na
650
+ * hora fora do request e devolve só o handle — acompanhe com `getTask`.
651
+ */
652
+ delegateTask(params: DelegateTaskParams): Promise<TaskInfo>;
653
+ /** Board de tasks do tenant (requer key owner/admin/editor). */
654
+ listTasks(params?: ListTasksParams): Promise<TaskListPage>;
655
+ /** Dossiê de uma task: task + execuções + filhos + aprovações. */
656
+ getTask(params: GetTaskParams): Promise<TaskDossier>;
657
+ /** Cancela uma task (requer key owner/admin); derruba o turno em voo, se houver. */
658
+ cancelTask(params: CancelTaskParams): Promise<CancelTaskResult>;
407
659
  /** Lista os agentes do tenant (dropdown). */
408
660
  listAgents(opts?: {
409
661
  signal?: AbortSignal;
@@ -507,4 +759,31 @@ interface SignedRequestHeaders {
507
759
  */
508
760
  declare function signRequest(payload: string, secretKey: string, timestamp?: number): SignedRequestHeaders;
509
761
 
510
- export { type AgentResult, type AgentStreamChunk, type AgentSummary, type Attachment, type AttachmentType, type CreateTriggerParams, DEFAULT_LIMITS, type DeleteTriggerParams, type DispatchAgentParams, type DispatchResult, type ExecutionStatus, type FindOrCreateResult, type GetExecutionParams, type GetTriggerParams, type InvokeAgentParams, type InvokeOptions, type ListTriggersParams, type QueryExtraction, type RetryInfo, type SignedRequestHeaders, type Source, type TriggerInfo, type TriggerMode, type TriggerRef, type UpdateTriggerParams, type Usage, ZihinAgentClient, ZihinAgentError, type ZihinClientConfig, type ZihinErrorKind, createClient, sanitizeApiError, signRequest, validateApiKeyFormat, validateBaseUrl, validatePromptSize };
762
+ /**
763
+ * Caminho C — delegação assíncrona durável (`/api/v1/tasks`).
764
+ *
765
+ * Diferente do Caminho B (triggers), aqui a conexão pode morrer sem levar o trabalho junto: a
766
+ * task é persistida (`agent_tasks`), executada fora do request e o resultado é notificado. É o
767
+ * caminho para runs que estouram o teto do host — o passo do Zapier morre em ~30s, e o próprio
768
+ * app marca isso como pendência desde o primeiro commit.
769
+ *
770
+ * Contrato verificado em `routes/tasks.js` (2026-08-31) — ver o Caminho C de
771
+ * `docs/CONTRATO-INVOCACAO-AGENTE.md`. Três coisas que diferem do resto da API e custaram
772
+ * retrabalho quando supostas em vez de lidas:
773
+ * 1. O envelope é o canônico novo: `{ success, data, meta:{request_id} }`. O `request_id` do
774
+ * sucesso vive em `meta`, não no topo.
775
+ * 2. O RBAC é mais estreito do que "admin/editor": delegar e cancelar exigem **owner|admin**;
776
+ * editor só lê o board e o dossiê.
777
+ * 3. Sem `scheduled_for` o BE dispara na hora, fora do request (`setImmediate`), e a resposta
778
+ * devolve só o handle — por isso estas rotas são todas de orçamento curto.
779
+ *
780
+ * @module tasks
781
+ */
782
+
783
+ /**
784
+ * Teto do `payload` congelado na task. Espelha o `MAX_PAYLOAD_BYTES` do BE
785
+ * (`routes/tasks.js:26`) — validar aqui evita gastar um round-trip para receber um 400.
786
+ */
787
+ declare const MAX_TASK_PAYLOAD_BYTES: number;
788
+
789
+ export { type AgentResult, type AgentStreamChunk, type AgentSummary, type Attachment, type AttachmentType, type CancelTaskParams, type CancelTaskResult, type CreateTriggerParams, DEADLINE_GRACE_MS, DEFAULT_LIMITS, type DelegateTaskParams, type DeleteTriggerParams, type DispatchAgentParams, type DispatchResult, type ExecutionStatus, type FindOrCreateResult, type GetExecutionParams, type GetTaskParams, type GetTriggerParams, type InvokeAgentParams, type InvokeOptions, type ListTasksParams, type ListTriggersParams, MAX_TASK_PAYLOAD_BYTES, OPERATION_TIMEOUT_MS, type QueryExtraction, type ResponseTransformMode, type RetryInfo, type SignedRequestHeaders, type Source, type TaskDossier, type TaskExecution, type TaskInfo, type TaskListPage, type TimeoutOperation, type TriggerInfo, type TriggerMode, type TriggerRef, type UpdateTriggerParams, type Usage, ZihinAgentClient, ZihinAgentError, type ZihinClientConfig, type ZihinErrorKind, createClient, isCommercialBlock, sanitizeApiError, signRequest, validateApiKeyFormat, validateBaseUrl, validatePromptSize };