@zihin/agent-client 0.4.1 → 0.6.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
@@ -4,7 +4,8 @@
4
4
  *
5
5
  * @module errors
6
6
  */
7
- type ZihinErrorKind = 'config' | 'auth' | 'trial_expired' | 'no_subscription' | 'quota_exceeded' | 'not_found' | 'rate_limit' | 'timeout' | 'aborted' | 'server' | 'network' | 'protocol' | 'unknown';
7
+
8
+ type ZihinErrorKind = 'config' | 'auth' | 'trial_expired' | 'no_subscription' | 'quota_exceeded' | 'not_found' | 'rate_limit' | 'timeout' | 'aborted' | 'server' | 'network' | 'protocol' | 'blocked' | 'unknown';
8
9
  /** Contexto opcional anexado a um erro para correlação/depuração. */
9
10
  interface ErrorMeta {
10
11
  /** Ex.: "POST llm.zihin.ai/api/v2/agents/abc/stream". */
@@ -23,6 +24,14 @@ interface ZihinErrorOptions extends ErrorMeta {
23
24
  * handoff) — é o handle que liga um erro daqui à execução no console/telemetria.
24
25
  */
25
26
  executionId?: string;
27
+ /** Sessão do turno — para o chamador retomar/inspecionar a conversa depois de um erro. */
28
+ sessionId?: string;
29
+ /**
30
+ * Só em `kind: 'timeout'` vindo do desfecho do turno (`done.timeout_clock`): qual relógio do BE
31
+ * encerrou o turno — `turn`, `first_signal`, `idle` ou `call`. Ausente num timeout de
32
+ * transporte/local, onde o turno pode nem ter terminado.
33
+ */
34
+ timeoutClock?: TimeoutClock;
26
35
  }
27
36
  declare class ZihinAgentError extends Error {
28
37
  readonly kind: ZihinErrorKind;
@@ -33,6 +42,8 @@ declare class ZihinAgentError extends Error {
33
42
  readonly attempts?: number;
34
43
  readonly endpoint?: string;
35
44
  readonly executionId?: string;
45
+ readonly sessionId?: string;
46
+ readonly timeoutClock?: TimeoutClock;
36
47
  constructor(kind: ZihinErrorKind, message: string, opts?: ZihinErrorOptions);
37
48
  }
38
49
  /**
@@ -109,7 +120,15 @@ interface Attachment {
109
120
  interface InvokeOptions {
110
121
  temperature?: number;
111
122
  maxTokens?: number;
112
- /** Timeout específico desta chamada (ms); sobrepõe o do cliente. */
123
+ /**
124
+ * Teto do TURNO desta chamada (ms); sobrepõe o do cliente. Vai ao BE como `options.timeout_ms`
125
+ * e o BE o honra (desde 30/09/2026, contrato de tempo §4), mas **só para encurtar**: o prazo
126
+ * efetivo é `min(prazo da plataforma, pedido)` — no `/stream` o canal chat dá 150s. Pedir mais
127
+ * não alonga. Um turno cortado por esse prazo sai `TIMEOUT` com `timeoutClock: 'turn'`.
128
+ *
129
+ * O relógio do turno no BE só começa DEPOIS da carga (config, tools, MCP frio). O deadline
130
+ * local soma `DEADLINE_GRACE_MS` a este valor para ainda receber o desfecho do servidor.
131
+ */
113
132
  timeoutMs?: number;
114
133
  /** Just-in-time tool loading (Sprint 33). */
115
134
  jitMode?: boolean;
@@ -121,8 +140,35 @@ interface InvokeAgentParams {
121
140
  message?: string;
122
141
  /** Anexos multimodais. `message` OU `attachments` é obrigatório. */
123
142
  attachments?: Attachment[];
124
- /** Continuidade de conversa (Supabase agent_sessions). */
143
+ /** Continuidade de conversa (Supabase agent_sessions). Não combina com `sessionFrom`. */
125
144
  sessionId?: string;
145
+ /**
146
+ * Identidade da pessoa do outro lado (memória por pessoa, denylist, gate de engajamento). Só vale
147
+ * sob API key **admin/owner**. Para continuar conversas que um webhook já gravava, use o MESMO
148
+ * valor que o webhook usava. Enviado como `consumer_key`.
149
+ */
150
+ consumerKey?: string;
151
+ /**
152
+ * Contexto estruturado que o **modelo lê** — bloco de plataforma junto da mensagem do usuário
153
+ * (não no system prompt). **Fica gravado** com a mensagem (`declared_context`) e se repete em
154
+ * todo turno; o BE redige segredos por nome de chave E por formato de valor (ex.: `sk-…`), o
155
+ * que pode alterar valores legítimos — ids que vão a tools ou ao `sessionFrom` ficam melhor em
156
+ * `bindings`. Plano, só escalares. Tools também o recebem. Só vale sob key admin/owner.
157
+ * ⚠️ Credencial não vai aqui nem em `bindings`: use um secret do tenant.
158
+ */
159
+ context?: Record<string, ContextValue>;
160
+ /**
161
+ * Valores que **só as tools** recebem — nunca vão ao prompt (ex.: id interno de fornecedor).
162
+ * Plano, só escalares; **nunca gravado** nem redigido (vive só no contexto das tools durante o
163
+ * turno). Só vale sob key admin/owner.
164
+ */
165
+ bindings?: Record<string, ContextValue>;
166
+ /**
167
+ * Deriva o `session_id` dos valores destes campos de `context ∪ bindings`, com a MESMA função
168
+ * do webhook (`derive: [campo]`) — o mesmo valor cai na mesma sessão pelos dois caminhos. Não
169
+ * combina com `sessionId`. O id derivado volta em `AgentResult.sessionId`.
170
+ */
171
+ sessionFrom?: string[];
126
172
  options?: InvokeOptions;
127
173
  metadata?: {
128
174
  traceId?: string;
@@ -137,6 +183,15 @@ interface InvokeAgentParams {
137
183
  */
138
184
  includeRaw?: boolean;
139
185
  }
186
+ /** Valor aceito em `context`/`bindings`: plano e escalar (regra 8 do contrato de entrada). */
187
+ type ContextValue = string | number | boolean | null;
188
+ /** Campo que o BE recebeu e NÃO aplicou (evento `metadata.ignored_fields`). */
189
+ interface IgnoredField {
190
+ /** Nome no fio (`context`, `bindings`, `session_from`, `consumer_key`, `options.temperature`…). */
191
+ field: string;
192
+ /** Motivo reportado pelo BE (ex.: papel da key insuficiente), quando houver. */
193
+ reason?: string;
194
+ }
140
195
  interface Usage {
141
196
  inputTokens?: number;
142
197
  outputTokens?: number;
@@ -175,23 +230,71 @@ interface AgentResult {
175
230
  }>;
176
231
  iterations?: number;
177
232
  executionTimeMs?: number;
233
+ /** `execution_id` do turno (evento `metrics`) — handle de correlação no console/telemetria. */
234
+ executionId?: string;
235
+ /** Campos do pedido que o BE aplicou (`metadata.accepted_fields`). Ausente = backend antigo. */
236
+ acceptedFields?: string[];
237
+ /** Campos do pedido que o BE recebeu e ignorou (`metadata.ignored_fields`). */
238
+ ignoredFields?: IgnoredField[];
239
+ /**
240
+ * `true` = o `content` é a resposta ENLATADA de um gate da plataforma (conversa em atendimento
241
+ * humano, consumidor bloqueado, sessão suspensa), não do agente: nenhum modelo rodou. Em canal
242
+ * conversacional ela pode ser entregue à pessoa; numa automação, trate como "não respondido".
243
+ */
244
+ gated?: boolean;
245
+ /**
246
+ * Desfecho do turno, lido do `done` (`exitReason` do motor). `undefined` = backend antigo ou
247
+ * stream cortado antes do `done`. Só chegam aqui os desfechos cujo `content` é resposta
248
+ * (`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`).
251
+ */
252
+ outcome?: AgentOutcome;
253
+ /** `true` quando a resposta foi cortada pelo teto de saída do modelo (`done.truncated`). */
254
+ truncated?: boolean;
255
+ /** Motivo do corte quando `truncated` (ex.: `length`). */
256
+ finishReason?: string;
178
257
  /** Eventos SSE brutos coletados (para depuração / casos avançados). */
179
258
  raw: AgentStreamChunk[];
180
259
  }
260
+ /**
261
+ * Desfecho do turno (`done.outcome` = `resolveTurnOutcome` do motor). `COMPLETED` e `LENGTH`
262
+ * contam como sucesso no BE (`isSuccessfulOutcome`); os demais valores são repassados como vêm.
263
+ * Aberto (`string & {}`) porque o BE pode acrescentar desfechos (ex.: os de bloqueio).
264
+ */
265
+ type AgentOutcome = 'COMPLETED' | 'LENGTH' | 'TIMEOUT' | 'ERROR' | 'CANCELLED' | 'PAUSED' | 'SUSPENDED' | 'BUDGET_EXCEEDED' | 'QUOTA_EXCEEDED' | 'SESSION_BUSY' | 'CONFLICT' | (string & {});
266
+ /**
267
+ * Qual relógio encerrou o turno (contrato de tempo §2): `turn` (prazo do turno, inclusive o
268
+ * `options.timeoutMs` pedido), `first_signal` (o provedor não começou a responder), `idle`
269
+ * (silêncio entre pedaços do stream do provedor) ou `call` (chamada ao modelo sem stream).
270
+ */
271
+ type TimeoutClock = 'turn' | 'first_signal' | 'idle' | 'call' | (string & {});
181
272
  /**
182
273
  * Chunk normalizado emitido por `streamAgent`. Mapeia os tipos de evento SSE do BE:
183
274
  * metadata, status, attachments, phase, thinking, tool, action_proposed, token,
184
275
  * warning, response, metrics.
185
276
  */
186
- type AgentStreamChunk = {
277
+ type AgentStreamChunk =
278
+ /**
279
+ * Abertura do stream. `acceptedFields`/`ignoredFields` dizem o que o BE fez com cada campo do
280
+ * pedido (ausentes = backend anterior ao contrato de entrada). Se o chamador mandou
281
+ * `context`/`bindings`/`sessionFrom` e o BE não os aceitou, o `streamAgent` lança
282
+ * `ZihinAgentError('config')` ANTES de entregar este chunk — nunca segue em silêncio.
283
+ */
284
+ {
187
285
  type: 'metadata';
188
286
  requestId?: string;
189
287
  agentId?: string;
190
288
  sessionId?: string;
289
+ acceptedFields?: string[];
290
+ ignoredFields?: IgnoredField[];
191
291
  data: unknown;
192
- } | {
292
+ }
293
+ /** `blocked` = motivo do bloqueio do turno (`agent_paused`, `budget_exceeded`…), quando houver. */
294
+ | {
193
295
  type: 'status';
194
296
  phase?: string;
297
+ blocked?: string;
195
298
  data: unknown;
196
299
  } | {
197
300
  type: 'attachments';
@@ -250,9 +353,20 @@ type AgentStreamChunk = {
250
353
  sessionId?: string;
251
354
  data: unknown;
252
355
  }
253
- /** Fim LIMPO do stream (`utils/sse.js:92`). Sem ele, o stream foi cortado no meio. */
356
+ /**
357
+ * Fim LIMPO do stream (`utils/sse.js`). Sem ele, o stream foi cortado no meio. Carrega o
358
+ * desfecho do turno: `{ outcome, timed_out?, timeout_clock?, truncated?, finish_reason? }`
359
+ * (aditivo — backend antigo manda `{}`). Um turno que o motor encerrou por tempo chega aqui
360
+ * com `outcome: 'TIMEOUT'` (idem ERROR e os bloqueios), DEPOIS de um `response` cujo `content`
361
+ * é a mensagem de falha — use `errorFromDoneChunk` para não publicá-lo como resposta.
362
+ */
254
363
  | {
255
364
  type: 'done';
365
+ outcome?: AgentOutcome;
366
+ timedOut?: boolean;
367
+ timeoutClock?: TimeoutClock;
368
+ truncated?: boolean;
369
+ finishReason?: string;
256
370
  data: unknown;
257
371
  } | {
258
372
  type: 'response';
@@ -263,6 +377,8 @@ type AgentStreamChunk = {
263
377
  type: string;
264
378
  [k: string]: unknown;
265
379
  }>;
380
+ /** Resposta ENLATADA de um gate (handoff humano, denylist, sessão suspensa) — não do agente. */
381
+ gated?: boolean;
266
382
  data: unknown;
267
383
  } | {
268
384
  type: 'metrics';
@@ -270,6 +386,7 @@ type AgentStreamChunk = {
270
386
  model?: string;
271
387
  iterations?: number;
272
388
  executionTimeMs?: number;
389
+ executionId?: string;
273
390
  data: unknown;
274
391
  } | {
275
392
  type: 'unknown';
@@ -589,8 +706,13 @@ type TimeoutOperation = keyof typeof OPERATION_TIMEOUT_MS;
589
706
  * Folga somada ao `options.timeoutMs` do chamador para formar o deadline LOCAL. O mesmo número vai
590
707
  * ao BE como `options.timeout_ms` (o teto que ele deve respeitar); sem folga, os dois relógios
591
708
  * disparam juntos e o erro do servidor — que tem request_id — perde a corrida para o nosso abort.
709
+ *
710
+ * 30s, não 10s: o relógio do turno no BE só começa DEPOIS da carga (config, tools, gates — um MCP
711
+ * frio leva dezenas de segundos), então o tempo de parede visto daqui é `carga + prazo` (contrato
712
+ * de tempo §4). Com 10s, um `timeoutMs: 60000` num agente com MCP abortava aos 70s e trocava o
713
+ * `done { outcome: 'TIMEOUT' }` do servidor por um abort cego.
592
714
  */
593
- declare const DEADLINE_GRACE_MS = 10000;
715
+ declare const DEADLINE_GRACE_MS = 30000;
594
716
 
595
717
  /**
596
718
  * Listagem de agentes do tenant (GET /api/v2/agents). Alimenta o dropdown do nó n8n (#17)
@@ -689,7 +811,7 @@ declare function createClient(config: ZihinClientConfig): ZihinAgentClient;
689
811
  * O regex no nome só vale como FALLBACK para backends que ainda não emitem `timed_out`
690
812
  * (self-hosted/antigos). Some numa major futura, depois do rename no BE.
691
813
  */
692
- declare function classifyStreamErrorKind(code: string, timedOut?: boolean): 'timeout' | 'server';
814
+ declare function classifyStreamErrorKind(code: string, timedOut?: boolean): 'timeout' | 'server' | 'config';
693
815
  /**
694
816
  * Converte o chunk `type: 'error'` (evento terminal do BE) num `ZihinAgentError` — a MESMA regra
695
817
  * que o `invokeAgent` aplica, exportada para quem consome `streamAgent` direto (o adapter do
@@ -698,6 +820,28 @@ declare function classifyStreamErrorKind(code: string, timedOut?: boolean): 'tim
698
820
  declare function errorFromStreamChunk(chunk: Extract<AgentStreamChunk, {
699
821
  type: 'error';
700
822
  }>): ZihinAgentError;
823
+ /**
824
+ * Converte o `done` de um turno que NÃO produziu resposta num `ZihinAgentError`; devolve
825
+ * `undefined` quando o `content` é resposta. Mesma regra do `invokeAgent`, exportada para quem
826
+ * consome `streamAgent` direto (o Paperclip) não reimplementá-la.
827
+ *
828
+ * Por que erro e não um campo no resultado: nesses turnos o BE já emitiu um `response` com a
829
+ * mensagem de falha do motor em `content` (contrato de tempo §6). Como campo, cada shell teria
830
+ * de lembrar de checá-lo — e o que esquecesse publicaria a falha como resposta, que é o defeito
831
+ * que isto fecha (#81). Como erro, o caminho seguro é o default.
832
+ *
833
+ * TIMEOUT: `outcome: 'TIMEOUT'` é a fonte primária; `timed_out: true` sozinho também conta (o BE
834
+ * só o emite com TIMEOUT). Vira `kind: 'timeout'`, `code: 'TURN_TIMEOUT'`, com `timeoutClock`.
835
+ * Nenhum é retentável por default: o turno pode ter executado tools com efeito colateral
836
+ * (exceção: `SESSION_BUSY`, em que o turno nem começou).
837
+ */
838
+ declare function errorFromDoneChunk(chunk: Extract<AgentStreamChunk, {
839
+ type: 'done';
840
+ }>, ctx?: {
841
+ executionId?: string;
842
+ sessionId?: string;
843
+ blocked?: string;
844
+ }): ZihinAgentError | undefined;
701
845
 
702
846
  /**
703
847
  * Security utilities — portado de n8n-nodes-zihin/src/utils/security.ts (zero-dep).
@@ -821,4 +965,4 @@ declare function signRequest(payload: string, secretKey: string, timestamp?: num
821
965
  */
822
966
  declare const MAX_TASK_PAYLOAD_BYTES: number;
823
967
 
824
- 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, classifyStreamErrorKind, createClient, errorFromStreamChunk, isCommercialBlock, sanitizeApiError, signRequest, validateApiKeyFormat, validateBaseUrl, validatePromptSize };
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 };