@zihin/agent-client 0.6.0 → 0.7.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/dist/index.d.ts CHANGED
@@ -118,7 +118,17 @@ interface Attachment {
118
118
  type: AttachmentType;
119
119
  }
120
120
  interface InvokeOptions {
121
+ /**
122
+ * @deprecated Sem efeito: o `/stream` usa a temperatura da configuração do agente
123
+ * (`llm_config.temperature`, no console ou via `update_agent`). O servidor ignora o campo e o
124
+ * reporta em `ignoredFields`. Será retirado do SDK na 1.0.
125
+ */
121
126
  temperature?: number;
127
+ /**
128
+ * @deprecated Sem efeito: o teto de saída é a configuração do agente (`llm_config.max_tokens`,
129
+ * no console ou via `update_agent`). O servidor ignora o campo e o reporta em `ignoredFields`.
130
+ * Será retirado do SDK na 1.0.
131
+ */
122
132
  maxTokens?: number;
123
133
  /**
124
134
  * Teto do TURNO desta chamada (ms); sobrepõe o do cliente. Vai ao BE como `options.timeout_ms`
@@ -130,9 +140,49 @@ interface InvokeOptions {
130
140
  * local soma `DEADLINE_GRACE_MS` a este valor para ainda receber o desfecho do servidor.
131
141
  */
132
142
  timeoutMs?: number;
133
- /** Just-in-time tool loading (Sprint 33). */
143
+ /**
144
+ * @deprecated Recurso descontinuado no servidor (ago/2026): sem efeito, reportado em
145
+ * `ignoredFields`. Remova-o. Será retirado do SDK na 1.0.
146
+ */
134
147
  jitMode?: boolean;
135
148
  }
149
+ /**
150
+ * Blocos estruturados que a sua interface sabe renderizar (`capabilities.blocks`). Valor que o BE
151
+ * não conhece sai em `ignoredFields` como `capabilities.blocks.<v>` + `not_supported` (aviso, não erro).
152
+ */
153
+ type ClientBlockType = 'quick_replies' | 'html_report' | (string & {});
154
+ /**
155
+ * O que a SUA tela sabe mostrar. O agente só oferece o que você declarar — sem declarar, nada é
156
+ * gerado e nada é cobrado. Não exige privilégio de API key.
157
+ */
158
+ interface ClientCapabilities {
159
+ /**
160
+ * `quick_replies`: até 4 sugestões curtas de resposta ao fim do turno (o usuário toca e o texto
161
+ * vira a próxima mensagem). Chegam em `AgentResult.suggestions` (e no bloco `quick_replies` de
162
+ * `blocks`). O dono do agente pode desligá-las (`quick_replies_enabled`); o agente decide quando
163
+ * vale sugerir — nem todo turno traz sugestões.
164
+ *
165
+ * `html_report`: a tela renderiza HTML. Não cria bloco novo: o BE orienta o agente a entregar,
166
+ * quando couber, um documento HTML completo num bloco de código ```html dentro do `content`
167
+ * (BE `14d2a43c`, 19/10/2026). Só declare se você realmente renderiza HTML — senão o usuário
168
+ * recebe markup cru.
169
+ */
170
+ blocks?: ClientBlockType[];
171
+ }
172
+ /** A pessoa do outro lado da conversa. Só vale sob API key **admin/owner**. */
173
+ interface ConsumerIdentity {
174
+ /**
175
+ * Identificador estável da pessoa no SEU sistema (memória por pessoa, denylist, gate de
176
+ * engajamento). Para continuar conversas que um webhook já gravava, use o MESMO valor que o
177
+ * webhook usava. Enviado como `consumer_key`.
178
+ */
179
+ key: string;
180
+ /**
181
+ * Nome para exibição no console da Zihin (lista de contatos). Enviado como
182
+ * `consumer_display_name`. Dado pessoal: mande só o que a operação precisa ver.
183
+ */
184
+ name?: string;
185
+ }
136
186
  interface InvokeAgentParams {
137
187
  /** UUID do agente (path :agent_id). */
138
188
  agentId: string;
@@ -142,12 +192,41 @@ interface InvokeAgentParams {
142
192
  attachments?: Attachment[];
143
193
  /** Continuidade de conversa (Supabase agent_sessions). Não combina com `sessionFrom`. */
144
194
  sessionId?: string;
195
+ /**
196
+ * Chave de idempotência do turno (UUID, qualquer versão; BE normaliza para minúsculas).
197
+ * Reenviar a MESMA mensagem com o mesmo id não roda o agente de novo: enquanto o turno original
198
+ * está em voo o BE responde `SESSION_BUSY` (`blocked`, retentável); depois de concluído com
199
+ * `COMPLETED`/`LENGTH` o BE **repete a resposta gravada** (`AgentResult.idempotentReplay: true`,
200
+ * sem `usage`, por 24 h). Mesmo id com OUTRA mensagem → `IDEMPOTENCY_CONFLICT` (`config`).
201
+ * Turno que terminou em erro/timeout/gate libera o id: o reenvio roda de novo.
202
+ *
203
+ * Com ele, o núcleo passa a **retentar o POST** do `/stream` em erro de rede e 5xx antes do
204
+ * stream abrir (sem ele, POST nunca retenta em rede — poderia duplicar o turno).
205
+ *
206
+ * ⚠️ **O que a garantia cobre:** só não repetir um turno **concluído** (`COMPLETED`/`LENGTH`).
207
+ * Turno cortado no meio do stream, cancelado, com erro ou timeout **libera o id** e o reenvio
208
+ * roda de novo — inclusive tools de efeito colateral que já rodaram. É best-effort (Redis do BE
209
+ * fora → sem dedupe, campo ainda aceito). O escopo é API key + `consumerKey` (não a sessão) e a
210
+ * comparação é só mensagem+anexos: **nunca use um valor fixo** — um workflow agendado com a
211
+ * mesma mensagem receberia a mesma resposta por 24 h; reusar o id noutra sessão dá erro
212
+ * `config` (`IDEMPOTENT_REPLAY_OTHER_SESSION`). O BE devolve o id em minúsculas. Vale sob
213
+ * qualquer papel de API key. Enviado como `client_message_id`; contra um BE que não o aceite
214
+ * (`accepted_fields` sem ele) o núcleo recusa o turno (`config`).
215
+ */
216
+ clientMessageId?: string;
145
217
  /**
146
218
  * Identidade da pessoa do outro lado (memória por pessoa, denylist, gate de engajamento). Só vale
147
219
  * sob API key **admin/owner**. Para continuar conversas que um webhook já gravava, use o MESMO
148
220
  * valor que o webhook usava. Enviado como `consumer_key`.
149
221
  */
150
222
  consumerKey?: string;
223
+ /**
224
+ * A pessoa do outro lado: `{ key, name? }`. `consumer.key` é o mesmo que `consumerKey` (use um
225
+ * dos dois; se vierem os dois, têm de ser iguais). Só vale sob API key admin/owner.
226
+ */
227
+ consumer?: ConsumerIdentity;
228
+ /** O que a sua interface sabe renderizar — ex.: `{ blocks: ['quick_replies'] }`. */
229
+ capabilities?: ClientCapabilities;
151
230
  /**
152
231
  * Contexto estruturado que o **modelo lê** — bloco de plataforma junto da mensagem do usuário
153
232
  * (não no system prompt). **Fica gravado** com a mensagem (`declared_context`) e se repete em
@@ -228,10 +307,31 @@ interface AgentResult {
228
307
  type: string;
229
308
  [k: string]: unknown;
230
309
  }>;
310
+ /**
311
+ * Sugestões de resposta do turno (bloco `quick_replies`), já extraídas de `blocks`. Só vêm se
312
+ * você declarou `capabilities: { blocks: ['quick_replies'] }`. O texto de cada uma é o que o
313
+ * usuário "diz" ao tocá-la. Num turno só com sugestões, `content` vem vazio.
314
+ */
315
+ suggestions?: string[];
231
316
  iterations?: number;
232
317
  executionTimeMs?: number;
233
- /** `execution_id` do turno (evento `metrics`) — handle de correlação no console/telemetria. */
318
+ /**
319
+ * `execution_id` do turno — handle de correlação no console/telemetria. Lido do `metadata`
320
+ * (BE desde 17/10/2026) com fallback no `metrics`; ausente num turno barrado por gate.
321
+ */
234
322
  executionId?: string;
323
+ /** `client_message_id` que o BE aplicou ao turno (eco do que você mandou, em **minúsculas**). */
324
+ clientMessageId?: string;
325
+ /**
326
+ * `true` = esta é a resposta GRAVADA de um turno anterior com o mesmo `clientMessageId`
327
+ * (reenvio idempotente). O agente não rodou de novo: sem `usage`/`model`/`iterations`, e
328
+ * `truncated`/`finishReason` não vêm mesmo que o original fosse `LENGTH`.
329
+ */
330
+ idempotentReplay?: boolean;
331
+ /** Id da mensagem do usuário gravada na sessão (quando o BE o deu). */
332
+ userMessageId?: string;
333
+ /** Id da mensagem do agente gravada na sessão (quando o BE o deu). */
334
+ assistantMessageId?: string;
235
335
  /** Campos do pedido que o BE aplicou (`metadata.accepted_fields`). Ausente = backend antigo. */
236
336
  acceptedFields?: string[];
237
337
  /** Campos do pedido que o BE recebeu e ignorou (`metadata.ignored_fields`). */
@@ -246,8 +346,9 @@ interface AgentResult {
246
346
  * Desfecho do turno, lido do `done` (`exitReason` do motor). `undefined` = backend antigo ou
247
347
  * stream cortado antes do `done`. Só chegam aqui os desfechos cujo `content` é resposta
248
348
  * (`COMPLETED`, `LENGTH`), o `PAUSED` (aprovação pendente ou agente pausado) e desfechos novos.
249
- * `TIMEOUT`, `ERROR`, `CANCELLED`, `SUSPENDED` e os de bloqueio viram `ZihinAgentError` — o
250
- * `content` desses turnos é a mensagem de falha/recusa do motor (`errorFromDoneChunk`).
349
+ * `TIMEOUT`, `ERROR`, `CANCELLED`, `SUSPENDED`, `REFUSED`, `CONTEXT_LIMIT` e os de bloqueio
350
+ * viram `ZihinAgentError` — o `content` desses turnos é a mensagem de falha/recusa do motor
351
+ * (`errorFromDoneChunk`).
251
352
  */
252
353
  outcome?: AgentOutcome;
253
354
  /** `true` quando a resposta foi cortada pelo teto de saída do modelo (`done.truncated`). */
@@ -262,7 +363,11 @@ interface AgentResult {
262
363
  * contam como sucesso no BE (`isSuccessfulOutcome`); os demais valores são repassados como vêm.
263
364
  * Aberto (`string & {}`) porque o BE pode acrescentar desfechos (ex.: os de bloqueio).
264
365
  */
265
- type AgentOutcome = 'COMPLETED' | 'LENGTH' | 'TIMEOUT' | 'ERROR' | 'CANCELLED' | 'PAUSED' | 'SUSPENDED' | 'BUDGET_EXCEEDED' | 'QUOTA_EXCEEDED' | 'SESSION_BUSY' | 'CONFLICT' | (string & {});
366
+ type AgentOutcome = 'COMPLETED' | 'LENGTH' | 'TIMEOUT' | 'ERROR' | 'CANCELLED' | 'PAUSED' | 'SUSPENDED' | 'BUDGET_EXCEEDED' | 'QUOTA_EXCEEDED' | 'SESSION_BUSY' | 'CONFLICT'
367
+ /** O provedor do modelo recusou por política (desde 08/10/2026). O `content` é um texto neutro fixo. */
368
+ | 'REFUSED'
369
+ /** A conversa reuniu mais contexto do que o modelo processa (desde 14/10/2026). No `/stream` chega como `event: error`. */
370
+ | 'CONTEXT_LIMIT' | (string & {});
266
371
  /**
267
372
  * Qual relógio encerrou o turno (contrato de tempo §2): `turn` (prazo do turno, inclusive o
268
373
  * `options.timeoutMs` pedido), `first_signal` (o provedor não começou a responder), `idle`
@@ -286,6 +391,11 @@ type AgentStreamChunk =
286
391
  requestId?: string;
287
392
  agentId?: string;
288
393
  sessionId?: string;
394
+ /** `execution_id` do turno (BE desde 17/10/2026). Ausente num turno barrado por gate. */
395
+ executionId?: string;
396
+ clientMessageId?: string;
397
+ /** `true` = o BE vai repetir a resposta gravada (mesmo `clientMessageId`), sem rodar o agente. */
398
+ idempotentReplay?: boolean;
289
399
  acceptedFields?: string[];
290
400
  ignoredFields?: IgnoredField[];
291
401
  data: unknown;
@@ -316,6 +426,12 @@ type AgentStreamChunk =
316
426
  } | {
317
427
  type: 'action_proposed';
318
428
  data: unknown;
429
+ }
430
+ /** Aprovação humana encaminhada ao aprovador (`{ action_id, kind, title, expires_at }`); o turno fica `PAUSED`. */
431
+ | {
432
+ type: 'action_forwarded';
433
+ actionId?: string;
434
+ data: unknown;
319
435
  } | {
320
436
  type: 'token';
321
437
  content: string;
@@ -327,7 +443,9 @@ type AgentStreamChunk =
327
443
  }
328
444
  /**
329
445
  * O BE encerra o stream com `event: error` + `{ error: { type, code, message, request_id,
330
- * timed_out? } }` (`utils/sse.js`) — inclusive quando o TURNO morre no deadline. Antes isto
446
+ * timed_out? } }` (`utils/sse.js`) — inclusive quando o TURNO morre no deadline. O BE NÃO põe
447
+ * `status` nem `details` no fio (ficam no servidor): `SESSION_BUSY`, `IDEMPOTENCY_CONFLICT`,
448
+ * `CONTEXT_LIMIT`, `CONFLICT` e os de quota chegam só com `code`+`message`. Antes isto
331
449
  * caía em `unknown` e o `invokeAgent` ignorava: se já tinha chegado token, devolvia a
332
450
  * deliberação crua como SUCESSO.
333
451
  *
@@ -367,6 +485,11 @@ type AgentStreamChunk =
367
485
  timeoutClock?: TimeoutClock;
368
486
  truncated?: boolean;
369
487
  finishReason?: string;
488
+ executionId?: string;
489
+ clientMessageId?: string;
490
+ idempotentReplay?: boolean;
491
+ userMessageId?: string;
492
+ assistantMessageId?: string;
370
493
  data: unknown;
371
494
  } | {
372
495
  type: 'response';
@@ -377,8 +500,15 @@ type AgentStreamChunk =
377
500
  type: string;
378
501
  [k: string]: unknown;
379
502
  }>;
503
+ /** Sugestões de resposta (bloco `quick_replies`), extraídas de `blocks`. */
504
+ suggestions?: string[];
380
505
  /** Resposta ENLATADA de um gate (handoff humano, denylist, sessão suspensa) — não do agente. */
381
506
  gated?: boolean;
507
+ executionId?: string;
508
+ clientMessageId?: string;
509
+ idempotentReplay?: boolean;
510
+ userMessageId?: string;
511
+ assistantMessageId?: string;
382
512
  data: unknown;
383
513
  } | {
384
514
  type: 'metrics';
@@ -500,7 +630,7 @@ interface TriggerInfo {
500
630
  interface ListTriggersParams {
501
631
  /** Filtra por agente. */
502
632
  agentId?: string;
503
- /** Filtra por tipo (webhook | db_event | email | schedule). */
633
+ /** Filtra por tipo (`webhook` | `email` | `schedule`; `db_event` foi removido do BE em 03/10/2026). */
504
634
  triggerType?: string;
505
635
  /** Apenas habilitados. */
506
636
  enabledOnly?: boolean;
@@ -529,9 +659,19 @@ interface DispatchResult {
529
659
  accepted: boolean;
530
660
  triggerId?: string;
531
661
  agentId?: string;
662
+ /** Id da execução do TRIGGER (`trigger_executions`), não o `execution_id` do turno do agente. */
532
663
  executionId?: string;
533
664
  /** Presente quando o trigger é `sync`: resposta imediata do agente. */
534
665
  agentResponse?: string;
666
+ /**
667
+ * Desfecho do turno no modo `sync` (BE desde 14/10/2026; ausente = backend antigo). Só chegam
668
+ * aqui os desfechos cujo `agentResponse` é resposta (`COMPLETED`, `LENGTH`) e o `PAUSED`; os
669
+ * demais (`REFUSED`, `CONTEXT_LIMIT`, `TIMEOUT`, `ERROR`…) viram `ZihinAgentError` mesmo com
670
+ * `success: true` no corpo — o BE mantém `success` como "entregou", e o texto é a frase da
671
+ * plataforma, não uma resposta. Limite: o sync não traz `status.blocked`, então o `PAUSED` de
672
+ * agente pausado/arquivado chega aqui com o texto de recusa em `agentResponse`.
673
+ */
674
+ outcome?: AgentOutcome;
535
675
  usage?: Usage;
536
676
  /** Iterações do laço de tools no turno (sync). */
537
677
  iterations?: number;
@@ -811,15 +951,32 @@ declare function createClient(config: ZihinClientConfig): ZihinAgentClient;
811
951
  * O regex no nome só vale como FALLBACK para backends que ainda não emitem `timed_out`
812
952
  * (self-hosted/antigos). Some numa major futura, depois do rename no BE.
813
953
  */
814
- declare function classifyStreamErrorKind(code: string, timedOut?: boolean): 'timeout' | 'server' | 'config';
954
+ declare function classifyStreamErrorKind(code: string, timedOut?: boolean): ZihinErrorKind;
815
955
  /**
816
956
  * Converte o chunk `type: 'error'` (evento terminal do BE) num `ZihinAgentError` — a MESMA regra
817
957
  * que o `invokeAgent` aplica, exportada para quem consome `streamAgent` direto (o adapter do
818
958
  * Paperclip, por exemplo) não reimplementar a classificação por conta e divergir dela.
959
+ * `ctx` leva os ids já vistos no `metadata` (o `error` em si não os traz).
819
960
  */
820
961
  declare function errorFromStreamChunk(chunk: Extract<AgentStreamChunk, {
821
962
  type: 'error';
822
- }>): ZihinAgentError;
963
+ }>, ctx?: {
964
+ executionId?: string;
965
+ sessionId?: string;
966
+ }): ZihinAgentError;
967
+ /**
968
+ * Converte um `outcome` cru (fora do `/stream`: `outcome` do webhook sync, `exit_reason` de uma
969
+ * execução) num `ZihinAgentError`, ou `undefined` quando o texto que o acompanha É resposta
970
+ * (`COMPLETED`, `LENGTH`, `PAUSED`, desconhecido/ausente). Mesma tabela do `errorFromDoneChunk`,
971
+ * sem o contexto de `status.blocked` que só o SSE tem.
972
+ */
973
+ declare function errorFromOutcome(outcome: string | undefined, ctx?: {
974
+ executionId?: string;
975
+ sessionId?: string;
976
+ status?: number;
977
+ endpoint?: string;
978
+ attempts?: number;
979
+ }): ZihinAgentError | undefined;
823
980
  /**
824
981
  * Converte o `done` de um turno que NÃO produziu resposta num `ZihinAgentError`; devolve
825
982
  * `undefined` quando o `content` é resposta. Mesma regra do `invokeAgent`, exportada para quem
@@ -965,4 +1122,4 @@ declare function signRequest(payload: string, secretKey: string, timestamp?: num
965
1122
  */
966
1123
  declare const MAX_TASK_PAYLOAD_BYTES: number;
967
1124
 
968
- export { type AgentOutcome, type AgentResult, type AgentStreamChunk, type AgentSummary, type Attachment, type AttachmentType, type CancelTaskParams, type CancelTaskResult, type ContextValue, 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 IgnoredField, 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 TimeoutClock, type TimeoutOperation, type TriggerInfo, type TriggerMode, type TriggerRef, type UpdateTriggerParams, type Usage, ZihinAgentClient, ZihinAgentError, type ZihinClientConfig, type ZihinErrorKind, classifyStreamErrorKind, createClient, errorFromDoneChunk, errorFromStreamChunk, isCommercialBlock, sanitizeApiError, signRequest, validateApiKeyFormat, validateBaseUrl, validatePromptSize };
1125
+ export { type AgentOutcome, type AgentResult, type AgentStreamChunk, type AgentSummary, type Attachment, type AttachmentType, type CancelTaskParams, type CancelTaskResult, type ClientBlockType, type ClientCapabilities, type ConsumerIdentity, type ContextValue, 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 IgnoredField, 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 TimeoutClock, type TimeoutOperation, type TriggerInfo, type TriggerMode, type TriggerRef, type UpdateTriggerParams, type Usage, ZihinAgentClient, ZihinAgentError, type ZihinClientConfig, type ZihinErrorKind, classifyStreamErrorKind, createClient, errorFromDoneChunk, errorFromOutcome, errorFromStreamChunk, isCommercialBlock, sanitizeApiError, signRequest, validateApiKeyFormat, validateBaseUrl, validatePromptSize };