@zihin/agent-client 0.6.0 → 0.6.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
@@ -111,6 +111,43 @@ 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
+
114
151
  ## Uso — caminho assíncrono (triggers)
115
152
 
116
153
  ```ts
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,41 @@ 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
+ /** Blocos estruturados que a sua interface sabe renderizar (`capabilities.blocks`). */
150
+ type ClientBlockType = 'quick_replies';
151
+ /**
152
+ * O que a SUA tela sabe mostrar. O agente só oferece o que você declarar — sem declarar, nada é
153
+ * gerado e nada é cobrado. Não exige privilégio de API key.
154
+ */
155
+ interface ClientCapabilities {
156
+ /**
157
+ * `quick_replies`: até 4 sugestões curtas de resposta ao fim do turno (o usuário toca e o texto
158
+ * vira a próxima mensagem). Chegam em `AgentResult.suggestions` (e no bloco `quick_replies` de
159
+ * `blocks`). O dono do agente pode desligá-las (`quick_replies_enabled`); o agente decide quando
160
+ * vale sugerir — nem todo turno traz sugestões.
161
+ */
162
+ blocks?: ClientBlockType[];
163
+ }
164
+ /** A pessoa do outro lado da conversa. Só vale sob API key **admin/owner**. */
165
+ interface ConsumerIdentity {
166
+ /**
167
+ * Identificador estável da pessoa no SEU sistema (memória por pessoa, denylist, gate de
168
+ * engajamento). Para continuar conversas que um webhook já gravava, use o MESMO valor que o
169
+ * webhook usava. Enviado como `consumer_key`.
170
+ */
171
+ key: string;
172
+ /**
173
+ * Nome para exibição no console da Zihin (lista de contatos). Enviado como
174
+ * `consumer_display_name`. Dado pessoal: mande só o que a operação precisa ver.
175
+ */
176
+ name?: string;
177
+ }
136
178
  interface InvokeAgentParams {
137
179
  /** UUID do agente (path :agent_id). */
138
180
  agentId: string;
@@ -148,6 +190,13 @@ interface InvokeAgentParams {
148
190
  * valor que o webhook usava. Enviado como `consumer_key`.
149
191
  */
150
192
  consumerKey?: string;
193
+ /**
194
+ * A pessoa do outro lado: `{ key, name? }`. `consumer.key` é o mesmo que `consumerKey` (use um
195
+ * dos dois; se vierem os dois, têm de ser iguais). Só vale sob API key admin/owner.
196
+ */
197
+ consumer?: ConsumerIdentity;
198
+ /** O que a sua interface sabe renderizar — ex.: `{ blocks: ['quick_replies'] }`. */
199
+ capabilities?: ClientCapabilities;
151
200
  /**
152
201
  * Contexto estruturado que o **modelo lê** — bloco de plataforma junto da mensagem do usuário
153
202
  * (não no system prompt). **Fica gravado** com a mensagem (`declared_context`) e se repete em
@@ -228,6 +277,12 @@ interface AgentResult {
228
277
  type: string;
229
278
  [k: string]: unknown;
230
279
  }>;
280
+ /**
281
+ * Sugestões de resposta do turno (bloco `quick_replies`), já extraídas de `blocks`. Só vêm se
282
+ * você declarou `capabilities: { blocks: ['quick_replies'] }`. O texto de cada uma é o que o
283
+ * usuário "diz" ao tocá-la. Num turno só com sugestões, `content` vem vazio.
284
+ */
285
+ suggestions?: string[];
231
286
  iterations?: number;
232
287
  executionTimeMs?: number;
233
288
  /** `execution_id` do turno (evento `metrics`) — handle de correlação no console/telemetria. */
@@ -377,6 +432,8 @@ type AgentStreamChunk =
377
432
  type: string;
378
433
  [k: string]: unknown;
379
434
  }>;
435
+ /** Sugestões de resposta (bloco `quick_replies`), extraídas de `blocks`. */
436
+ suggestions?: string[];
380
437
  /** Resposta ENLATADA de um gate (handoff humano, denylist, sessão suspensa) — não do agente. */
381
438
  gated?: boolean;
382
439
  data: unknown;
@@ -965,4 +1022,4 @@ declare function signRequest(payload: string, secretKey: string, timestamp?: num
965
1022
  */
966
1023
  declare const MAX_TASK_PAYLOAD_BYTES: number;
967
1024
 
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 };
1025
+ 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, errorFromStreamChunk, isCommercialBlock, sanitizeApiError, signRequest, validateApiKeyFormat, validateBaseUrl, validatePromptSize };
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,41 @@ 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
+ /** Blocos estruturados que a sua interface sabe renderizar (`capabilities.blocks`). */
150
+ type ClientBlockType = 'quick_replies';
151
+ /**
152
+ * O que a SUA tela sabe mostrar. O agente só oferece o que você declarar — sem declarar, nada é
153
+ * gerado e nada é cobrado. Não exige privilégio de API key.
154
+ */
155
+ interface ClientCapabilities {
156
+ /**
157
+ * `quick_replies`: até 4 sugestões curtas de resposta ao fim do turno (o usuário toca e o texto
158
+ * vira a próxima mensagem). Chegam em `AgentResult.suggestions` (e no bloco `quick_replies` de
159
+ * `blocks`). O dono do agente pode desligá-las (`quick_replies_enabled`); o agente decide quando
160
+ * vale sugerir — nem todo turno traz sugestões.
161
+ */
162
+ blocks?: ClientBlockType[];
163
+ }
164
+ /** A pessoa do outro lado da conversa. Só vale sob API key **admin/owner**. */
165
+ interface ConsumerIdentity {
166
+ /**
167
+ * Identificador estável da pessoa no SEU sistema (memória por pessoa, denylist, gate de
168
+ * engajamento). Para continuar conversas que um webhook já gravava, use o MESMO valor que o
169
+ * webhook usava. Enviado como `consumer_key`.
170
+ */
171
+ key: string;
172
+ /**
173
+ * Nome para exibição no console da Zihin (lista de contatos). Enviado como
174
+ * `consumer_display_name`. Dado pessoal: mande só o que a operação precisa ver.
175
+ */
176
+ name?: string;
177
+ }
136
178
  interface InvokeAgentParams {
137
179
  /** UUID do agente (path :agent_id). */
138
180
  agentId: string;
@@ -148,6 +190,13 @@ interface InvokeAgentParams {
148
190
  * valor que o webhook usava. Enviado como `consumer_key`.
149
191
  */
150
192
  consumerKey?: string;
193
+ /**
194
+ * A pessoa do outro lado: `{ key, name? }`. `consumer.key` é o mesmo que `consumerKey` (use um
195
+ * dos dois; se vierem os dois, têm de ser iguais). Só vale sob API key admin/owner.
196
+ */
197
+ consumer?: ConsumerIdentity;
198
+ /** O que a sua interface sabe renderizar — ex.: `{ blocks: ['quick_replies'] }`. */
199
+ capabilities?: ClientCapabilities;
151
200
  /**
152
201
  * Contexto estruturado que o **modelo lê** — bloco de plataforma junto da mensagem do usuário
153
202
  * (não no system prompt). **Fica gravado** com a mensagem (`declared_context`) e se repete em
@@ -228,6 +277,12 @@ interface AgentResult {
228
277
  type: string;
229
278
  [k: string]: unknown;
230
279
  }>;
280
+ /**
281
+ * Sugestões de resposta do turno (bloco `quick_replies`), já extraídas de `blocks`. Só vêm se
282
+ * você declarou `capabilities: { blocks: ['quick_replies'] }`. O texto de cada uma é o que o
283
+ * usuário "diz" ao tocá-la. Num turno só com sugestões, `content` vem vazio.
284
+ */
285
+ suggestions?: string[];
231
286
  iterations?: number;
232
287
  executionTimeMs?: number;
233
288
  /** `execution_id` do turno (evento `metrics`) — handle de correlação no console/telemetria. */
@@ -377,6 +432,8 @@ type AgentStreamChunk =
377
432
  type: string;
378
433
  [k: string]: unknown;
379
434
  }>;
435
+ /** Sugestões de resposta (bloco `quick_replies`), extraídas de `blocks`. */
436
+ suggestions?: string[];
380
437
  /** Resposta ENLATADA de um gate (handoff humano, denylist, sessão suspensa) — não do agente. */
381
438
  gated?: boolean;
382
439
  data: unknown;
@@ -965,4 +1022,4 @@ declare function signRequest(payload: string, secretKey: string, timestamp?: num
965
1022
  */
966
1023
  declare const MAX_TASK_PAYLOAD_BYTES: number;
967
1024
 
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 };
1025
+ 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, errorFromStreamChunk, isCommercialBlock, sanitizeApiError, signRequest, validateApiKeyFormat, validateBaseUrl, validatePromptSize };
package/dist/index.js CHANGED
@@ -89,6 +89,20 @@ var RUNNING_STATUSES = /* @__PURE__ */ new Set([
89
89
  function isTerminalStatus(status) {
90
90
  return !RUNNING_STATUSES.has(status.toLowerCase().replace(/-/g, "_"));
91
91
  }
92
+ var _warnedDeprecations = /* @__PURE__ */ new Set();
93
+ function warnDeprecatedOnce(code, message) {
94
+ if (_warnedDeprecations.has(code)) return;
95
+ _warnedDeprecations.add(code);
96
+ try {
97
+ const proc = globalThis.process;
98
+ if (typeof proc?.emitWarning === "function") {
99
+ proc.emitWarning(message, { type: "ZihinDeprecationWarning", code });
100
+ return;
101
+ }
102
+ console.warn(`[${code}] ${message}`);
103
+ } catch {
104
+ }
105
+ }
92
106
 
93
107
  // src/security.ts
94
108
  var PRIVATE_IP_PATTERNS = [
@@ -923,6 +937,16 @@ function parseIgnoredFields(v) {
923
937
  }
924
938
  return out;
925
939
  }
940
+ var MAX_SUGGESTIONS = 10;
941
+ var MAX_SUGGESTION_CHARS = 200;
942
+ function suggestionsFromBlocks(blocks) {
943
+ if (!Array.isArray(blocks)) return void 0;
944
+ const qr = [...blocks].reverse().find((b) => rec(b).type === "quick_replies");
945
+ const labels = rec(rec(qr).data).labels;
946
+ if (!Array.isArray(labels)) return void 0;
947
+ const out = labels.filter((l) => typeof l === "string" && l.trim().length > 0 && l.length <= MAX_SUGGESTION_CHARS).slice(0, MAX_SUGGESTIONS);
948
+ return out.length ? out : void 0;
949
+ }
926
950
  function mapEvent(e) {
927
951
  const d = rec(e.data);
928
952
  switch (e.event) {
@@ -989,6 +1013,7 @@ function mapEvent(e) {
989
1013
  gated: d.gated === true ? true : void 0,
990
1014
  sources: Array.isArray(d.sources) ? d.sources : void 0,
991
1015
  blocks: Array.isArray(d.blocks) ? d.blocks : void 0,
1016
+ suggestions: suggestionsFromBlocks(d.blocks),
992
1017
  data: e.data
993
1018
  };
994
1019
  case "metrics": {
@@ -1012,6 +1037,8 @@ function buildRequestBody(params, normalizedTimeoutMs) {
1012
1037
  if (params.message !== void 0) body.message = params.message;
1013
1038
  if (params.sessionId) body.session_id = params.sessionId;
1014
1039
  if (params.consumerKey) body.consumer_key = params.consumerKey;
1040
+ if (params.consumer?.name !== void 0) body.consumer_display_name = params.consumer.name;
1041
+ if (params.capabilities?.blocks?.length) body.capabilities = { blocks: [...params.capabilities.blocks] };
1015
1042
  if (params.context) body.context = { ...params.context };
1016
1043
  if (params.bindings) body.bindings = { ...params.bindings };
1017
1044
  if (params.sessionFrom?.length) body.session_from = [...params.sessionFrom];
@@ -1054,6 +1081,7 @@ function validateParams(params) {
1054
1081
  }
1055
1082
  }
1056
1083
  validateStructuredInput(params);
1084
+ warnDeprecatedOptions(params);
1057
1085
  if (params.options?.timeoutMs !== void 0) {
1058
1086
  normalizeTimeoutMs(params.options.timeoutMs, "options.timeoutMs");
1059
1087
  }
@@ -1064,6 +1092,22 @@ function validateParams(params) {
1064
1092
  }
1065
1093
  }
1066
1094
  }
1095
+ function warnDeprecatedOptions(params) {
1096
+ const o = params.options;
1097
+ if (!o) return;
1098
+ if (o.jitMode !== void 0) {
1099
+ warnDeprecatedOnce(
1100
+ "ZIHIN_DEP001",
1101
+ "`options.jitMode` is deprecated and has no effect (the server discontinued it). Remove it; it will be dropped from the SDK in 1.0."
1102
+ );
1103
+ }
1104
+ if (o.temperature !== void 0 || o.maxTokens !== void 0) {
1105
+ warnDeprecatedOnce(
1106
+ "ZIHIN_DEP002",
1107
+ "`options.temperature`/`options.maxTokens` have no effect: the agent's own configuration (`llm_config`) decides them \u2014 change it in the Zihin console or with `update_agent`. They will be dropped from the SDK in 1.0."
1108
+ );
1109
+ }
1110
+ }
1067
1111
  var MAX_FIELDS = 50;
1068
1112
  var MAX_VALUE_CHARS = 2e3;
1069
1113
  var MAX_TOTAL_CHARS = { context: 2e3, bindings: 16e3 };
@@ -1071,13 +1115,36 @@ var MAX_SESSION_FROM_FIELDS = 5;
1071
1115
  var FIELD_NAME_RE = /^[A-Za-z_][A-Za-z0-9_-]{0,63}$/;
1072
1116
  var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1073
1117
  var MAX_CONSUMER_KEY_CHARS = 200;
1118
+ var MAX_CONSUMER_NAME_CHARS = 255;
1119
+ var MAX_CLIENT_BLOCKS = 10;
1074
1120
  function snapshotStructuredInput(params) {
1075
1121
  const snap = (v) => isPlainObject(v) ? Object.fromEntries(Object.entries(v).filter(([, x]) => x !== void 0)) : v;
1076
1122
  return {
1077
1123
  ...params,
1124
+ ...normalizeConsumer(params),
1078
1125
  context: snap(params.context),
1079
1126
  bindings: snap(params.bindings),
1080
- sessionFrom: Array.isArray(params.sessionFrom) ? [...params.sessionFrom] : params.sessionFrom
1127
+ sessionFrom: Array.isArray(params.sessionFrom) ? [...params.sessionFrom] : params.sessionFrom,
1128
+ capabilities: isPlainObject(params.capabilities) ? {
1129
+ ...params.capabilities,
1130
+ blocks: Array.isArray(params.capabilities.blocks) ? [...params.capabilities.blocks] : params.capabilities.blocks
1131
+ } : params.capabilities
1132
+ };
1133
+ }
1134
+ function normalizeConsumer(params) {
1135
+ const c = params.consumer;
1136
+ if (c === void 0) return {};
1137
+ if (!isPlainObject(c)) {
1138
+ throw new ZihinAgentError("config", "`consumer` must be an object: `{ key, name? }`.");
1139
+ }
1140
+ const key = c.key;
1141
+ if (params.consumerKey !== void 0 && key !== void 0 && params.consumerKey !== key) {
1142
+ throw new ZihinAgentError("config", "`consumerKey` and `consumer.key` differ \u2014 send only one of them.");
1143
+ }
1144
+ const resolved = key ?? params.consumerKey;
1145
+ return {
1146
+ consumerKey: resolved,
1147
+ consumer: { key: resolved, ...c.name !== void 0 ? { name: c.name } : {} }
1081
1148
  };
1082
1149
  }
1083
1150
  function isPlainObject(v) {
@@ -1095,6 +1162,24 @@ function validateStructuredInput(params) {
1095
1162
  if (typeof params.consumerKey === "string" && params.consumerKey.length > MAX_CONSUMER_KEY_CHARS) {
1096
1163
  throw new ZihinAgentError("config", `\`consumerKey\` is longer than ${MAX_CONSUMER_KEY_CHARS} characters.`);
1097
1164
  }
1165
+ if (params.consumer !== void 0) {
1166
+ if (params.consumerKey === void 0) {
1167
+ throw new ZihinAgentError("config", "`consumer.key` is required (the name has nothing to attach to without it).");
1168
+ }
1169
+ const n = params.consumer.name;
1170
+ if (n !== void 0 && (typeof n !== "string" || !n.trim() || n.length > MAX_CONSUMER_NAME_CHARS)) {
1171
+ throw new ZihinAgentError("config", `\`consumer.name\` must be a non-empty string of up to ${MAX_CONSUMER_NAME_CHARS} characters.`);
1172
+ }
1173
+ }
1174
+ if (params.capabilities !== void 0) {
1175
+ const blocks = isPlainObject(params.capabilities) ? params.capabilities.blocks : null;
1176
+ if (blocks === null || blocks !== void 0 && (!Array.isArray(blocks) || blocks.length > MAX_CLIENT_BLOCKS || blocks.some((b) => typeof b !== "string"))) {
1177
+ throw new ZihinAgentError(
1178
+ "config",
1179
+ `\`capabilities\` must be \`{ blocks: [...] }\` with up to ${MAX_CLIENT_BLOCKS} block names (e.g. \`['quick_replies']\`).`
1180
+ );
1181
+ }
1182
+ }
1098
1183
  for (const name of ["context", "bindings"]) {
1099
1184
  const v = params[name];
1100
1185
  if (v === void 0) continue;
@@ -1382,6 +1467,7 @@ async function invokeAgent(cfg, params) {
1382
1467
  usage: metricsChunk?.usage,
1383
1468
  sources: responseChunk.sources,
1384
1469
  blocks: responseChunk.blocks,
1470
+ suggestions: responseChunk.suggestions,
1385
1471
  gated: responseChunk.gated,
1386
1472
  iterations: metricsChunk?.iterations,
1387
1473
  executionTimeMs: metricsChunk?.executionTimeMs,
package/dist/index.mjs CHANGED
@@ -55,6 +55,20 @@ var RUNNING_STATUSES = /* @__PURE__ */ new Set([
55
55
  function isTerminalStatus(status) {
56
56
  return !RUNNING_STATUSES.has(status.toLowerCase().replace(/-/g, "_"));
57
57
  }
58
+ var _warnedDeprecations = /* @__PURE__ */ new Set();
59
+ function warnDeprecatedOnce(code, message) {
60
+ if (_warnedDeprecations.has(code)) return;
61
+ _warnedDeprecations.add(code);
62
+ try {
63
+ const proc = globalThis.process;
64
+ if (typeof proc?.emitWarning === "function") {
65
+ proc.emitWarning(message, { type: "ZihinDeprecationWarning", code });
66
+ return;
67
+ }
68
+ console.warn(`[${code}] ${message}`);
69
+ } catch {
70
+ }
71
+ }
58
72
 
59
73
  // src/security.ts
60
74
  var PRIVATE_IP_PATTERNS = [
@@ -889,6 +903,16 @@ function parseIgnoredFields(v) {
889
903
  }
890
904
  return out;
891
905
  }
906
+ var MAX_SUGGESTIONS = 10;
907
+ var MAX_SUGGESTION_CHARS = 200;
908
+ function suggestionsFromBlocks(blocks) {
909
+ if (!Array.isArray(blocks)) return void 0;
910
+ const qr = [...blocks].reverse().find((b) => rec(b).type === "quick_replies");
911
+ const labels = rec(rec(qr).data).labels;
912
+ if (!Array.isArray(labels)) return void 0;
913
+ const out = labels.filter((l) => typeof l === "string" && l.trim().length > 0 && l.length <= MAX_SUGGESTION_CHARS).slice(0, MAX_SUGGESTIONS);
914
+ return out.length ? out : void 0;
915
+ }
892
916
  function mapEvent(e) {
893
917
  const d = rec(e.data);
894
918
  switch (e.event) {
@@ -955,6 +979,7 @@ function mapEvent(e) {
955
979
  gated: d.gated === true ? true : void 0,
956
980
  sources: Array.isArray(d.sources) ? d.sources : void 0,
957
981
  blocks: Array.isArray(d.blocks) ? d.blocks : void 0,
982
+ suggestions: suggestionsFromBlocks(d.blocks),
958
983
  data: e.data
959
984
  };
960
985
  case "metrics": {
@@ -978,6 +1003,8 @@ function buildRequestBody(params, normalizedTimeoutMs) {
978
1003
  if (params.message !== void 0) body.message = params.message;
979
1004
  if (params.sessionId) body.session_id = params.sessionId;
980
1005
  if (params.consumerKey) body.consumer_key = params.consumerKey;
1006
+ if (params.consumer?.name !== void 0) body.consumer_display_name = params.consumer.name;
1007
+ if (params.capabilities?.blocks?.length) body.capabilities = { blocks: [...params.capabilities.blocks] };
981
1008
  if (params.context) body.context = { ...params.context };
982
1009
  if (params.bindings) body.bindings = { ...params.bindings };
983
1010
  if (params.sessionFrom?.length) body.session_from = [...params.sessionFrom];
@@ -1020,6 +1047,7 @@ function validateParams(params) {
1020
1047
  }
1021
1048
  }
1022
1049
  validateStructuredInput(params);
1050
+ warnDeprecatedOptions(params);
1023
1051
  if (params.options?.timeoutMs !== void 0) {
1024
1052
  normalizeTimeoutMs(params.options.timeoutMs, "options.timeoutMs");
1025
1053
  }
@@ -1030,6 +1058,22 @@ function validateParams(params) {
1030
1058
  }
1031
1059
  }
1032
1060
  }
1061
+ function warnDeprecatedOptions(params) {
1062
+ const o = params.options;
1063
+ if (!o) return;
1064
+ if (o.jitMode !== void 0) {
1065
+ warnDeprecatedOnce(
1066
+ "ZIHIN_DEP001",
1067
+ "`options.jitMode` is deprecated and has no effect (the server discontinued it). Remove it; it will be dropped from the SDK in 1.0."
1068
+ );
1069
+ }
1070
+ if (o.temperature !== void 0 || o.maxTokens !== void 0) {
1071
+ warnDeprecatedOnce(
1072
+ "ZIHIN_DEP002",
1073
+ "`options.temperature`/`options.maxTokens` have no effect: the agent's own configuration (`llm_config`) decides them \u2014 change it in the Zihin console or with `update_agent`. They will be dropped from the SDK in 1.0."
1074
+ );
1075
+ }
1076
+ }
1033
1077
  var MAX_FIELDS = 50;
1034
1078
  var MAX_VALUE_CHARS = 2e3;
1035
1079
  var MAX_TOTAL_CHARS = { context: 2e3, bindings: 16e3 };
@@ -1037,13 +1081,36 @@ var MAX_SESSION_FROM_FIELDS = 5;
1037
1081
  var FIELD_NAME_RE = /^[A-Za-z_][A-Za-z0-9_-]{0,63}$/;
1038
1082
  var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1039
1083
  var MAX_CONSUMER_KEY_CHARS = 200;
1084
+ var MAX_CONSUMER_NAME_CHARS = 255;
1085
+ var MAX_CLIENT_BLOCKS = 10;
1040
1086
  function snapshotStructuredInput(params) {
1041
1087
  const snap = (v) => isPlainObject(v) ? Object.fromEntries(Object.entries(v).filter(([, x]) => x !== void 0)) : v;
1042
1088
  return {
1043
1089
  ...params,
1090
+ ...normalizeConsumer(params),
1044
1091
  context: snap(params.context),
1045
1092
  bindings: snap(params.bindings),
1046
- sessionFrom: Array.isArray(params.sessionFrom) ? [...params.sessionFrom] : params.sessionFrom
1093
+ sessionFrom: Array.isArray(params.sessionFrom) ? [...params.sessionFrom] : params.sessionFrom,
1094
+ capabilities: isPlainObject(params.capabilities) ? {
1095
+ ...params.capabilities,
1096
+ blocks: Array.isArray(params.capabilities.blocks) ? [...params.capabilities.blocks] : params.capabilities.blocks
1097
+ } : params.capabilities
1098
+ };
1099
+ }
1100
+ function normalizeConsumer(params) {
1101
+ const c = params.consumer;
1102
+ if (c === void 0) return {};
1103
+ if (!isPlainObject(c)) {
1104
+ throw new ZihinAgentError("config", "`consumer` must be an object: `{ key, name? }`.");
1105
+ }
1106
+ const key = c.key;
1107
+ if (params.consumerKey !== void 0 && key !== void 0 && params.consumerKey !== key) {
1108
+ throw new ZihinAgentError("config", "`consumerKey` and `consumer.key` differ \u2014 send only one of them.");
1109
+ }
1110
+ const resolved = key ?? params.consumerKey;
1111
+ return {
1112
+ consumerKey: resolved,
1113
+ consumer: { key: resolved, ...c.name !== void 0 ? { name: c.name } : {} }
1047
1114
  };
1048
1115
  }
1049
1116
  function isPlainObject(v) {
@@ -1061,6 +1128,24 @@ function validateStructuredInput(params) {
1061
1128
  if (typeof params.consumerKey === "string" && params.consumerKey.length > MAX_CONSUMER_KEY_CHARS) {
1062
1129
  throw new ZihinAgentError("config", `\`consumerKey\` is longer than ${MAX_CONSUMER_KEY_CHARS} characters.`);
1063
1130
  }
1131
+ if (params.consumer !== void 0) {
1132
+ if (params.consumerKey === void 0) {
1133
+ throw new ZihinAgentError("config", "`consumer.key` is required (the name has nothing to attach to without it).");
1134
+ }
1135
+ const n = params.consumer.name;
1136
+ if (n !== void 0 && (typeof n !== "string" || !n.trim() || n.length > MAX_CONSUMER_NAME_CHARS)) {
1137
+ throw new ZihinAgentError("config", `\`consumer.name\` must be a non-empty string of up to ${MAX_CONSUMER_NAME_CHARS} characters.`);
1138
+ }
1139
+ }
1140
+ if (params.capabilities !== void 0) {
1141
+ const blocks = isPlainObject(params.capabilities) ? params.capabilities.blocks : null;
1142
+ if (blocks === null || blocks !== void 0 && (!Array.isArray(blocks) || blocks.length > MAX_CLIENT_BLOCKS || blocks.some((b) => typeof b !== "string"))) {
1143
+ throw new ZihinAgentError(
1144
+ "config",
1145
+ `\`capabilities\` must be \`{ blocks: [...] }\` with up to ${MAX_CLIENT_BLOCKS} block names (e.g. \`['quick_replies']\`).`
1146
+ );
1147
+ }
1148
+ }
1064
1149
  for (const name of ["context", "bindings"]) {
1065
1150
  const v = params[name];
1066
1151
  if (v === void 0) continue;
@@ -1348,6 +1433,7 @@ async function invokeAgent(cfg, params) {
1348
1433
  usage: metricsChunk?.usage,
1349
1434
  sources: responseChunk.sources,
1350
1435
  blocks: responseChunk.blocks,
1436
+ suggestions: responseChunk.suggestions,
1351
1437
  gated: responseChunk.gated,
1352
1438
  iterations: metricsChunk?.iterations,
1353
1439
  executionTimeMs: metricsChunk?.executionTimeMs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zihin/agent-client",
3
- "version": "0.6.0",
3
+ "version": "0.6.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",