@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 +69 -2
- package/dist/index.d.mts +283 -4
- package/dist/index.d.ts +283 -4
- package/dist/index.js +472 -60
- package/dist/index.mjs +468 -60
- package/package.json +1 -1
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.
|
|
146
|
-
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
|
|
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 };
|