@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/README.md +100 -5
- package/dist/index.d.mts +167 -10
- package/dist/index.d.ts +167 -10
- package/dist/index.js +258 -20
- package/dist/index.mjs +257 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -111,6 +111,92 @@ gera **outra** sessão, e a ordem dos campos entra no hash. Chave repetida nos d
|
|
|
111
111
|
`bindings`. Campo do `sessionFrom` que a redação alterou (no `context`) é recusado com
|
|
112
112
|
`VALIDATION_ERROR` (sai como `config`): mande-o em `bindings`.
|
|
113
113
|
|
|
114
|
+
### Nome do contato e sugestões de resposta (0.6.1)
|
|
115
|
+
|
|
116
|
+
> Backend: zihin-agent-builder `1aa752e6` (+ migration `20261001000002`). Contra um backend
|
|
117
|
+
> anterior os dois recursos só não acontecem: o turno roda normalmente.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const r = await zihin.invokeAgent({
|
|
121
|
+
agentId,
|
|
122
|
+
message: 'Quero canetas azuis',
|
|
123
|
+
consumer: { key: 'dev-cotai-1410', name: 'Fernando Produtor' }, // nome aparece nos contatos do console
|
|
124
|
+
capabilities: { blocks: ['quick_replies'] }, // minha tela mostra sugestões
|
|
125
|
+
});
|
|
126
|
+
r.suggestions; // ['Caneta A', 'Caneta B'] — ou undefined quando o agente não sugeriu
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- **`consumer: { key, name? }`** é o `consumerKey` com o nome junto. `consumer.key` e `consumerKey`
|
|
130
|
+
são o mesmo campo (mande um; se vierem os dois, têm de ser iguais) e seguem a mesma regra: só
|
|
131
|
+
valem sob API key admin/owner, e o núcleo recusa o turno se o servidor os ignorar. O nome vai como
|
|
132
|
+
`consumer_display_name` (até 255 caracteres) e vale **do presente em diante**: atualiza o
|
|
133
|
+
contato e a conversa em andamento; conversas encerradas guardam o nome da época (o histórico não
|
|
134
|
+
é reescrito). Dado pessoal: mande só o que a operação precisa ver.
|
|
135
|
+
- **Uma `consumer.key` por pessoa.** A chave é a identidade: memória, bloqueio e engajamento são
|
|
136
|
+
dela. Se várias pessoas usam o mesmo canal (ex.: um WhatsApp comercial que troca de vendedor),
|
|
137
|
+
dê a cada uma a sua chave — trocar só o `name` não separa as pessoas.
|
|
138
|
+
- **`capabilities: { blocks: ['quick_replies'] }`** diz que a sua tela renderiza sugestões de
|
|
139
|
+
resposta. Sem declarar, o agente nem recebe a ferramenta — nada é gerado e nada é cobrado. É um
|
|
140
|
+
**pedido**, não uma exigência: qualquer API key pode mandar, e um servidor que não o conheça só o
|
|
141
|
+
reporta em `ignoredFields` (o turno não falha). O dono do agente pode desligar as sugestões
|
|
142
|
+
(`quick_replies_enabled`), e o agente decide quando vale sugerir — nem todo turno traz.
|
|
143
|
+
- **`suggestions`** (em `AgentResult` e no chunk `response`) são os rótulos do bloco `quick_replies`
|
|
144
|
+
de `blocks`, já filtrados: até 4, curtos. Tocar uma sugestão = mandar o texto dela como a próxima
|
|
145
|
+
`message`. Num turno só com sugestões, `content` vem **vazio**.
|
|
146
|
+
- **Descontinuados**: `options.jitMode`, `options.temperature` e `options.maxTokens` não têm efeito no
|
|
147
|
+
`/stream` (temperatura e teto de saída são configuração do agente). Continuam sendo enviados e o
|
|
148
|
+
servidor os lista em `ignoredFields`; o núcleo emite um `ZihinDeprecationWarning` **uma vez por
|
|
149
|
+
processo** (`ZIHIN_DEP001`/`ZIHIN_DEP002`). Saem do SDK na 1.0.
|
|
150
|
+
|
|
151
|
+
### Idempotência, recusa do provedor e limite de contexto (0.7)
|
|
152
|
+
|
|
153
|
+
> Backend: zihin-agent-builder `server-llm` de outubro/2026 (`client_message_id` em `121e426f`,
|
|
154
|
+
> `REFUSED` em `4cea8d53`, `CONTEXT_LIMIT` em `e670f530`, trava de sessão em `b67141d7`). Verificado
|
|
155
|
+
> em `9ec79cfc` (03/11/2026).
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const r = await zihin.invokeAgent({
|
|
159
|
+
agentId,
|
|
160
|
+
message: 'Fechar o pedido 42',
|
|
161
|
+
clientMessageId: crypto.randomUUID(), // um UUID novo por mensagem; reenvie o MESMO para retentar
|
|
162
|
+
});
|
|
163
|
+
r.idempotentReplay; // true = o BE repetiu a resposta gravada (o agente não rodou de novo)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
- **`clientMessageId`** (UUID) torna o turno idempotente. Com ele, o núcleo passa a **retentar o
|
|
167
|
+
POST** do `/stream` em erro de rede e 5xx antes do stream abrir (sem ele, POST nunca retenta em
|
|
168
|
+
rede — poderia duplicar o turno). Reenviar o mesmo id com a mesma mensagem: turno ainda em voo →
|
|
169
|
+
`SESSION_BUSY` (`blocked`, retentável); turno concluído com `COMPLETED`/`LENGTH` → o BE repete a
|
|
170
|
+
resposta gravada por 24 h, com `idempotentReplay: true` e sem `usage`. Mesmo id com **outra**
|
|
171
|
+
mensagem → `IDEMPOTENCY_CONFLICT` (`config`). **A garantia cobre só o turno concluído**: turno
|
|
172
|
+
cortado no meio do stream, cancelado, com erro ou timeout libera o id e o reenvio roda de novo
|
|
173
|
+
(tools incluídas); por isso o retry automático é só pré-stream, e é best-effort (Redis do BE fora →
|
|
174
|
+
sem dedupe). O escopo é a API key + `consumerKey` (não a sessão) e a comparação é só
|
|
175
|
+
mensagem+anexos: **nunca use um valor fixo** (uma automação agendada receberia a mesma resposta por
|
|
176
|
+
24 h); reusar o id noutra sessão dá `config` (`IDEMPOTENT_REPLAY_OTHER_SESSION`; comparação de
|
|
177
|
+
sessão case-insensitive, o BE devolve o `session_id` em minúsculas). Essa guarda só existe em
|
|
178
|
+
`invokeAgent` **com `sessionId` explícito**: com `sessionFrom`, sem sessão, ou em `streamAgent`,
|
|
179
|
+
um id reusado devolve em silêncio a resposta (e o `session_id`) da conversa original. O BE ecoa o id
|
|
180
|
+
em minúsculas. `SERVICE_UNAVAILABLE` (replay sem resposta recuperável) **não é retentável**: pode
|
|
181
|
+
durar 24 h e só um `clientMessageId` novo sai dele.
|
|
182
|
+
Contra um servidor que não liste `client_message_id` em `accepted_fields`, o núcleo recusa o turno
|
|
183
|
+
(`config`): a garantia que você pediu não existiria.
|
|
184
|
+
- **`REFUSED`**: o provedor do modelo recusou por política. O BE entrega um texto neutro fixo como
|
|
185
|
+
`response` e marca a execução como erro; o núcleo **lança** `blocked` com `code: 'REFUSED'` (na 0.6
|
|
186
|
+
o texto neutro saía como resposta). **`CONTEXT_LIMIT`**: a conversa reuniu mais contexto do que o
|
|
187
|
+
modelo processa — `blocked`, `code: 'CONTEXT_LIMIT'`; peça menos ou abra outra sessão.
|
|
188
|
+
- **Trava de um turno por sessão** (ligada por padrão no BE desde 18/10/2026): mandar a segunda
|
|
189
|
+
mensagem antes da primeira terminar dá `SESSION_BUSY` como `event: error`. O núcleo o classifica
|
|
190
|
+
`blocked` **retentável** (o turno nem começou) — antes saía como `server` não retentável.
|
|
191
|
+
- **Ids do turno** em `AgentResult`: `executionId` agora vem do `metadata` (chega mesmo quando o
|
|
192
|
+
turno morre antes do `metrics`), mais `clientMessageId`, `userMessageId`, `assistantMessageId`.
|
|
193
|
+
- **`capabilities.blocks`** aceita `'html_report'`: a tela renderiza HTML, e o BE orienta o agente a
|
|
194
|
+
entregar, quando couber, um documento HTML num bloco ```html dentro do `content` (não é bloco novo).
|
|
195
|
+
- **`dispatchAgent` (webhook sync)** lê o `outcome` do corpo: `REFUSED`, `CONTEXT_LIMIT`, `TIMEOUT`,
|
|
196
|
+
`ERROR`… chegam com `success: true` e a frase da plataforma em `agent_response`; o núcleo lança a
|
|
197
|
+
mesma classificação do `/stream`. `DispatchResult.outcome` expõe os que respondem.
|
|
198
|
+
- Novo helper exportado `errorFromOutcome(outcome, ctx)` para quem lê desfechos fora do SSE.
|
|
199
|
+
|
|
114
200
|
## Uso — caminho assíncrono (triggers)
|
|
115
201
|
|
|
116
202
|
```ts
|
|
@@ -238,8 +324,8 @@ direto aplica a mesma regra com `errorFromDoneChunk(chunk, { executionId, sessio
|
|
|
238
324
|
|
|
239
325
|
O mesmo vale para os outros desfechos em que o `content` é falha ou recusa do motor, e não
|
|
240
326
|
resposta: `ERROR`/`CANCELLED` (pelo servidor) → `kind: 'server'`, `QUOTA_EXCEEDED` → `quota_exceeded`,
|
|
241
|
-
`SUSPENDED`/`BUDGET_EXCEEDED`/`SESSION_BUSY`/`CONFLICT` e o `PAUSED` de
|
|
242
|
-
`blocked` (o `code` é o `outcome`; só `SESSION_BUSY` é retentável). Um `ERROR` precedido de
|
|
327
|
+
`SUSPENDED`/`BUDGET_EXCEEDED`/`SESSION_BUSY`/`CONFLICT`/`REFUSED`/`CONTEXT_LIMIT` e o `PAUSED` de
|
|
328
|
+
agente pausado/arquivado → `blocked` (o `code` é o `outcome`; só `SESSION_BUSY` é retentável). Um `ERROR` precedido de
|
|
243
329
|
`status.blocked` (gate da plataforma) também sai `blocked`, com o motivo em `code`
|
|
244
330
|
(`ownership_denied` → `not_found`).
|
|
245
331
|
|
|
@@ -265,8 +351,9 @@ const agents = await zihin.listAgents(); // GET /api/v2/agents
|
|
|
265
351
|
|
|
266
352
|
## Erros
|
|
267
353
|
|
|
268
|
-
Todos os erros são `ZihinAgentError` com `kind` (`config | auth |
|
|
269
|
-
|
|
354
|
+
Todos os erros são `ZihinAgentError` com `kind` (`config | auth | trial_expired | no_subscription |
|
|
355
|
+
quota_exceeded | not_found | rate_limit | timeout | aborted | server | network | protocol | blocked |
|
|
356
|
+
unknown`), `status`, `code`, `retryable` e — para depurar em
|
|
270
357
|
produção externa — `endpoint` (`"POST host/path"`), `attempts` e **`requestId`** (handle do BE para o
|
|
271
358
|
suporte correlacionar). Erros de rede carregam a causa-raiz (`ECONNREFUSED`/`ENOTFOUND`/TLS…) na
|
|
272
359
|
mensagem. As mensagens redigem **só segredos** (key/Bearer/stack) — `request_id`/`trace_id` são
|
|
@@ -308,7 +395,15 @@ correlacionar com o console.
|
|
|
308
395
|
da tentativa seguinte — o que fica limitado é o tempo gasto com retries.
|
|
309
396
|
- **Retry sem duplicar efeito** — GET (idempotente) retenta em rede/429/5xx; POST com efeito
|
|
310
397
|
(`invokeAgent`/`dispatchAgent`/`createTrigger`) retenta **só em 429/503** e **nunca em erro de
|
|
311
|
-
rede** (o request pode ter sido processado).
|
|
398
|
+
rede** (o request pode ter sido processado). Exceção: `invokeAgent` com `clientMessageId` retenta
|
|
399
|
+
também em rede e 5xx, **só antes dos headers do SSE chegarem**. É seguro porque o BE envia os
|
|
400
|
+
headers antes de reservar o id e antes de qualquer trabalho do turno; se o 1º POST chegou a rodar,
|
|
401
|
+
a chave transforma o reenvio em `SESSION_BUSY` ou replay. Um stream **cortado no meio** sai
|
|
402
|
+
`network` com `retryable: false`: o BE cancela o turno e libera o id, então reenviar (mesmo com a
|
|
403
|
+
chave) roda as tools de novo. Contra um BE antigo que ainda não aceite `client_message_id`, o
|
|
404
|
+
retry pré-headers acontece sem a chave valer (o turno falha depois em `config`); a ordem
|
|
405
|
+
headers-antes-do-trabalho é a mesma, mas a garantia depende do BE. Backoff exponencial 1s→10s
|
|
406
|
+
com jitter.
|
|
312
407
|
- **Anti-DoS de memória** — limites de stream `maxStreamEventBytes` (1MB) e `maxStreamTotalBytes`
|
|
313
408
|
(64MB); estourar aborta com `protocol`. Configuráveis no `createClient`.
|
|
314
409
|
- **`includeRaw`** — por padrão `invokeAgent` não retém os eventos brutos (`raw: []`) para economizar
|
package/dist/index.d.mts
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
|
250
|
-
* `content` desses turnos é a mensagem de falha/recusa do motor
|
|
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'
|
|
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.
|
|
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 |
|
|
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):
|
|
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
|
-
}
|
|
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 };
|