@zihin/agent-client 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -159,8 +159,12 @@ await zihin.cancelTask({ taskId: task.id, reason: 'mudou o plano' }); // 409 se
159
159
 
160
160
  Um `content` vazio com `contentSource: 'response'` é decisão do BE, não lacuna — o núcleo **não**
161
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.
162
+ exemplo), o núcleo **lança** (`kind: 'timeout'`, com `code` e `requestId`) em vez de devolver o
163
+ parcial. Se foi timeout ou não vem do campo **explícito `error.timed_out`** do evento (BE desde
164
+ 26/09/2026): quando presente ele é autoritativo — `true` é timeout seja qual for o `code`, `false`
165
+ é `server` mesmo com "TIMEOUT" no nome. Sem o campo (backend antigo), cai no fallback por nome
166
+ (`/TIMEOUT/i` no `code`), que será removido numa major futura. Não ramifique no **nome** do código
167
+ de timeout: o BE vai renomeá-los (zihin-agent-builder#561); use `kind`.
164
168
 
165
169
  ## Dropdown de agentes
166
170
 
package/dist/index.d.mts CHANGED
@@ -223,16 +223,21 @@ type AgentStreamChunk = {
223
223
  data: unknown;
224
224
  }
225
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.
226
+ * O BE encerra o stream com `event: error` + `{ error: { type, code, message, request_id,
227
+ * timed_out? } }` (`utils/sse.js`) — inclusive quando o TURNO morre no deadline. Antes isto
228
+ * caía em `unknown` e o `invokeAgent` ignorava: se já tinha chegado token, devolvia a
229
+ * deliberação crua como SUCESSO.
230
+ *
231
+ * `timedOut` espelha `error.timed_out` (BE desde 26/09/2026, zihin-agent-builder#605): campo
232
+ * explícito que diz se o turno morreu por timeout, independente do NOME do código — os códigos
233
+ * vão ser renomeados (zihin-agent-builder#561). `undefined` = backend antigo, sem o campo.
230
234
  */
231
235
  | {
232
236
  type: 'error';
233
237
  code?: string;
234
238
  message?: string;
235
239
  requestId?: string;
240
+ timedOut?: boolean;
236
241
  data: unknown;
237
242
  }
238
243
  /**
@@ -664,6 +669,36 @@ declare class ZihinAgentClient {
664
669
  /** Açúcar: cria um cliente a partir da config. */
665
670
  declare function createClient(config: ZihinClientConfig): ZihinAgentClient;
666
671
 
672
+ /**
673
+ * Caminho A — invocação direta de agente (POST /api/v2/agents/:id/stream).
674
+ * `streamAgent` emite deltas ao vivo; `invokeAgent` buffeia o stream e consolida
675
+ * o evento `response` (content/sources/session_id/blocks) com o `metrics` (usage/model).
676
+ *
677
+ * @module invoke
678
+ */
679
+
680
+ /**
681
+ * Decide se o `event: error` terminal do BE foi um timeout do turno (#75).
682
+ *
683
+ * Fonte primária é o campo EXPLÍCITO `error.timed_out` (BE `utils/sse.js`, em prod desde
684
+ * 26/09/2026 — zihin-agent-builder#605): quando presente, é autoritativo nos dois sentidos —
685
+ * `true` classifica como timeout seja qual for o `code`; `false` classifica como `server` mesmo
686
+ * que o nome do código contenha "TIMEOUT". O BE vai renomear esses códigos
687
+ * (zihin-agent-builder#561) e o nome deixa de ser um sinal confiável.
688
+ *
689
+ * O regex no nome só vale como FALLBACK para backends que ainda não emitem `timed_out`
690
+ * (self-hosted/antigos). Some numa major futura, depois do rename no BE.
691
+ */
692
+ declare function classifyStreamErrorKind(code: string, timedOut?: boolean): 'timeout' | 'server';
693
+ /**
694
+ * Converte o chunk `type: 'error'` (evento terminal do BE) num `ZihinAgentError` — a MESMA regra
695
+ * que o `invokeAgent` aplica, exportada para quem consome `streamAgent` direto (o adapter do
696
+ * Paperclip, por exemplo) não reimplementar a classificação por conta e divergir dela.
697
+ */
698
+ declare function errorFromStreamChunk(chunk: Extract<AgentStreamChunk, {
699
+ type: 'error';
700
+ }>): ZihinAgentError;
701
+
667
702
  /**
668
703
  * Security utilities — portado de n8n-nodes-zihin/src/utils/security.ts (zero-dep).
669
704
  * SSRF prevention, payload limits, error sanitization, API-key format.
@@ -786,4 +821,4 @@ declare function signRequest(payload: string, secretKey: string, timestamp?: num
786
821
  */
787
822
  declare const MAX_TASK_PAYLOAD_BYTES: number;
788
823
 
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 };
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 };
package/dist/index.d.ts CHANGED
@@ -223,16 +223,21 @@ type AgentStreamChunk = {
223
223
  data: unknown;
224
224
  }
225
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.
226
+ * O BE encerra o stream com `event: error` + `{ error: { type, code, message, request_id,
227
+ * timed_out? } }` (`utils/sse.js`) — inclusive quando o TURNO morre no deadline. Antes isto
228
+ * caía em `unknown` e o `invokeAgent` ignorava: se já tinha chegado token, devolvia a
229
+ * deliberação crua como SUCESSO.
230
+ *
231
+ * `timedOut` espelha `error.timed_out` (BE desde 26/09/2026, zihin-agent-builder#605): campo
232
+ * explícito que diz se o turno morreu por timeout, independente do NOME do código — os códigos
233
+ * vão ser renomeados (zihin-agent-builder#561). `undefined` = backend antigo, sem o campo.
230
234
  */
231
235
  | {
232
236
  type: 'error';
233
237
  code?: string;
234
238
  message?: string;
235
239
  requestId?: string;
240
+ timedOut?: boolean;
236
241
  data: unknown;
237
242
  }
238
243
  /**
@@ -664,6 +669,36 @@ declare class ZihinAgentClient {
664
669
  /** Açúcar: cria um cliente a partir da config. */
665
670
  declare function createClient(config: ZihinClientConfig): ZihinAgentClient;
666
671
 
672
+ /**
673
+ * Caminho A — invocação direta de agente (POST /api/v2/agents/:id/stream).
674
+ * `streamAgent` emite deltas ao vivo; `invokeAgent` buffeia o stream e consolida
675
+ * o evento `response` (content/sources/session_id/blocks) com o `metrics` (usage/model).
676
+ *
677
+ * @module invoke
678
+ */
679
+
680
+ /**
681
+ * Decide se o `event: error` terminal do BE foi um timeout do turno (#75).
682
+ *
683
+ * Fonte primária é o campo EXPLÍCITO `error.timed_out` (BE `utils/sse.js`, em prod desde
684
+ * 26/09/2026 — zihin-agent-builder#605): quando presente, é autoritativo nos dois sentidos —
685
+ * `true` classifica como timeout seja qual for o `code`; `false` classifica como `server` mesmo
686
+ * que o nome do código contenha "TIMEOUT". O BE vai renomear esses códigos
687
+ * (zihin-agent-builder#561) e o nome deixa de ser um sinal confiável.
688
+ *
689
+ * O regex no nome só vale como FALLBACK para backends que ainda não emitem `timed_out`
690
+ * (self-hosted/antigos). Some numa major futura, depois do rename no BE.
691
+ */
692
+ declare function classifyStreamErrorKind(code: string, timedOut?: boolean): 'timeout' | 'server';
693
+ /**
694
+ * Converte o chunk `type: 'error'` (evento terminal do BE) num `ZihinAgentError` — a MESMA regra
695
+ * que o `invokeAgent` aplica, exportada para quem consome `streamAgent` direto (o adapter do
696
+ * Paperclip, por exemplo) não reimplementar a classificação por conta e divergir dela.
697
+ */
698
+ declare function errorFromStreamChunk(chunk: Extract<AgentStreamChunk, {
699
+ type: 'error';
700
+ }>): ZihinAgentError;
701
+
667
702
  /**
668
703
  * Security utilities — portado de n8n-nodes-zihin/src/utils/security.ts (zero-dep).
669
704
  * SSRF prevention, payload limits, error sanitization, API-key format.
@@ -786,4 +821,4 @@ declare function signRequest(payload: string, secretKey: string, timestamp?: num
786
821
  */
787
822
  declare const MAX_TASK_PAYLOAD_BYTES: number;
788
823
 
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 };
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 };
package/dist/index.js CHANGED
@@ -26,7 +26,9 @@ __export(index_exports, {
26
26
  OPERATION_TIMEOUT_MS: () => OPERATION_TIMEOUT_MS,
27
27
  ZihinAgentClient: () => ZihinAgentClient,
28
28
  ZihinAgentError: () => ZihinAgentError,
29
+ classifyStreamErrorKind: () => classifyStreamErrorKind,
29
30
  createClient: () => createClient,
31
+ errorFromStreamChunk: () => errorFromStreamChunk,
30
32
  isCommercialBlock: () => isCommercialBlock,
31
33
  sanitizeApiError: () => sanitizeApiError,
32
34
  signRequest: () => signRequest,
@@ -929,6 +931,7 @@ function mapEvent(e) {
929
931
  code: str(err.code),
930
932
  message: str(err.message),
931
933
  requestId: str(err.request_id),
934
+ timedOut: typeof err.timed_out === "boolean" ? err.timed_out : void 0,
932
935
  data: e.data
933
936
  };
934
937
  }
@@ -1047,6 +1050,20 @@ async function* streamAgent(cfg, params) {
1047
1050
  deadline.dispose();
1048
1051
  }
1049
1052
  }
1053
+ function classifyStreamErrorKind(code, timedOut) {
1054
+ if (timedOut === true) return "timeout";
1055
+ if (timedOut === false) return "server";
1056
+ return /TIMEOUT/i.test(code) ? "timeout" : "server";
1057
+ }
1058
+ function errorFromStreamChunk(chunk) {
1059
+ const code = chunk.code ?? "AGENT_ERROR";
1060
+ const kind = classifyStreamErrorKind(code, chunk.timedOut);
1061
+ return new ZihinAgentError(kind, sanitizeApiError(chunk.message ?? code).message || code, {
1062
+ code,
1063
+ requestId: chunk.requestId,
1064
+ retryable: false
1065
+ });
1066
+ }
1050
1067
  async function invokeAgent(cfg, params) {
1051
1068
  const raw = [];
1052
1069
  const keepRaw = params.includeRaw === true;
@@ -1059,13 +1076,7 @@ async function invokeAgent(cfg, params) {
1059
1076
  for await (const chunk of streamAgent(cfg, params)) {
1060
1077
  if (keepRaw) raw.push(chunk);
1061
1078
  if (chunk.type === "error") {
1062
- const code = chunk.code ?? "AGENT_ERROR";
1063
- const kind = /TIMEOUT/i.test(code) ? "timeout" : "server";
1064
- throw new ZihinAgentError(kind, sanitizeApiError(chunk.message ?? code).message || code, {
1065
- code,
1066
- requestId: chunk.requestId,
1067
- retryable: false
1068
- });
1079
+ throw errorFromStreamChunk(chunk);
1069
1080
  }
1070
1081
  if (chunk.type === "response") responseChunk = chunk;
1071
1082
  else if (chunk.type === "metrics") metricsChunk = chunk;
@@ -1706,7 +1717,9 @@ function signRequest(payload, secretKey, timestamp) {
1706
1717
  OPERATION_TIMEOUT_MS,
1707
1718
  ZihinAgentClient,
1708
1719
  ZihinAgentError,
1720
+ classifyStreamErrorKind,
1709
1721
  createClient,
1722
+ errorFromStreamChunk,
1710
1723
  isCommercialBlock,
1711
1724
  sanitizeApiError,
1712
1725
  signRequest,
package/dist/index.mjs CHANGED
@@ -898,6 +898,7 @@ function mapEvent(e) {
898
898
  code: str(err.code),
899
899
  message: str(err.message),
900
900
  requestId: str(err.request_id),
901
+ timedOut: typeof err.timed_out === "boolean" ? err.timed_out : void 0,
901
902
  data: e.data
902
903
  };
903
904
  }
@@ -1016,6 +1017,20 @@ async function* streamAgent(cfg, params) {
1016
1017
  deadline.dispose();
1017
1018
  }
1018
1019
  }
1020
+ function classifyStreamErrorKind(code, timedOut) {
1021
+ if (timedOut === true) return "timeout";
1022
+ if (timedOut === false) return "server";
1023
+ return /TIMEOUT/i.test(code) ? "timeout" : "server";
1024
+ }
1025
+ function errorFromStreamChunk(chunk) {
1026
+ const code = chunk.code ?? "AGENT_ERROR";
1027
+ const kind = classifyStreamErrorKind(code, chunk.timedOut);
1028
+ return new ZihinAgentError(kind, sanitizeApiError(chunk.message ?? code).message || code, {
1029
+ code,
1030
+ requestId: chunk.requestId,
1031
+ retryable: false
1032
+ });
1033
+ }
1019
1034
  async function invokeAgent(cfg, params) {
1020
1035
  const raw = [];
1021
1036
  const keepRaw = params.includeRaw === true;
@@ -1028,13 +1043,7 @@ async function invokeAgent(cfg, params) {
1028
1043
  for await (const chunk of streamAgent(cfg, params)) {
1029
1044
  if (keepRaw) raw.push(chunk);
1030
1045
  if (chunk.type === "error") {
1031
- const code = chunk.code ?? "AGENT_ERROR";
1032
- const kind = /TIMEOUT/i.test(code) ? "timeout" : "server";
1033
- throw new ZihinAgentError(kind, sanitizeApiError(chunk.message ?? code).message || code, {
1034
- code,
1035
- requestId: chunk.requestId,
1036
- retryable: false
1037
- });
1046
+ throw errorFromStreamChunk(chunk);
1038
1047
  }
1039
1048
  if (chunk.type === "response") responseChunk = chunk;
1040
1049
  else if (chunk.type === "metrics") metricsChunk = chunk;
@@ -1674,7 +1683,9 @@ export {
1674
1683
  OPERATION_TIMEOUT_MS,
1675
1684
  ZihinAgentClient,
1676
1685
  ZihinAgentError,
1686
+ classifyStreamErrorKind,
1677
1687
  createClient,
1688
+ errorFromStreamChunk,
1678
1689
  isCommercialBlock,
1679
1690
  sanitizeApiError,
1680
1691
  signRequest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zihin/agent-client",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Núcleo de invocação de agentes Zihin.ai — padrão único para n8n, Paperclip e integrações futuras. Stream direto (SSE bufferizado) + triggers assíncronos com callback.",
5
5
  "keywords": [
6
6
  "zihin",