@zihin/agent-client 0.1.0 → 0.2.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 +53 -6
- package/dist/index.d.mts +510 -0
- package/dist/index.d.ts +509 -20
- package/dist/index.js +1303 -32
- package/dist/index.mjs +1276 -0
- package/package.json +19 -4
- package/dist/agents.d.ts +0 -21
- package/dist/agents.js +0 -52
- package/dist/agents.js.map +0 -1
- package/dist/client.d.ts +0 -43
- package/dist/client.js +0 -75
- package/dist/client.js.map +0 -1
- package/dist/errors.d.ts +0 -35
- package/dist/errors.js +0 -89
- package/dist/errors.js.map +0 -1
- package/dist/http.d.ts +0 -98
- package/dist/http.js +0 -281
- package/dist/http.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal.d.ts +0 -13
- package/dist/internal.js +0 -40
- package/dist/internal.js.map +0 -1
- package/dist/invoke.d.ts +0 -18
- package/dist/invoke.js +0 -233
- package/dist/invoke.js.map +0 -1
- package/dist/security.d.ts +0 -82
- package/dist/security.js +0 -251
- package/dist/security.js.map +0 -1
- package/dist/sse.d.ts +0 -27
- package/dist/sse.js +0 -138
- package/dist/sse.js.map +0 -1
- package/dist/triggers.d.ts +0 -43
- package/dist/triggers.js +0 -241
- package/dist/triggers.js.map +0 -1
- package/dist/types.d.ts +0 -268
- package/dist/types.js +0 -9
- package/dist/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -75,14 +75,49 @@ const exec = await zihin.getExecution({ triggerId, executionId });
|
|
|
75
75
|
|
|
76
76
|
> O modo `sync` do trigger (`mode: 'sync'`) responde 200 + JSON na hora (`dispatchResult.agentResponse`).
|
|
77
77
|
|
|
78
|
+
### Payload estruturado (não só texto)
|
|
79
|
+
|
|
80
|
+
O caminho direto (`invokeAgent`) só aceita **texto** — o endpoint `/stream` do BE não tem campo de
|
|
81
|
+
payload estruturado. Para disparar um agente a partir de um JSON rico, use triggers: o payload vai
|
|
82
|
+
inteiro no `dispatchAgent` e o `queryExtraction` define como ele vira a mensagem do agente.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
// template: compõe a mensagem a partir de campos aninhados do payload
|
|
86
|
+
await zihin.findOrCreateTrigger({
|
|
87
|
+
agentId,
|
|
88
|
+
name: 'Pedidos',
|
|
89
|
+
mode: 'sync',
|
|
90
|
+
queryExtraction: { mode: 'template', template: 'Pedido {{payload.order.id}}: {{payload.order.note}}' },
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// field (default): um campo top-level do payload
|
|
94
|
+
// queryExtraction: { mode: 'field', field: 'texto' }
|
|
95
|
+
// full_body: fallback do BE → payload.message || payload.query || JSON.stringify(payload)
|
|
96
|
+
// queryExtraction: { mode: 'full_body' }
|
|
97
|
+
|
|
98
|
+
await zihin.dispatchAgent({ triggerId, payload: { order: { id: 42, note: 'urgente' }, cliente: {...} } });
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
⚠️ O que chega ao agente é **a string extraída**, não o payload inteiro: com `field`/`template`, os
|
|
102
|
+
campos que você não referenciou ficam de fora. Para levar tudo, use `full_body` — e note que ele
|
|
103
|
+
só serializa o payload completo **se não houver** um campo `message`/`query` no topo (nesse caso o
|
|
104
|
+
BE usa esse campo). Precisa de campos extras como contexto estruturado? Isso é `context_mapping`
|
|
105
|
+
no trigger, ainda não exposto pelo núcleo — configure direto no BE.
|
|
106
|
+
|
|
78
107
|
### Ciclo de vida do trigger
|
|
79
108
|
|
|
80
109
|
```ts
|
|
81
110
|
await zihin.listTriggers({ agentId }); // lista (filtros: agentId/triggerType/enabledOnly)
|
|
82
111
|
await zihin.getTrigger({ triggerId }); // detalhe (inclui webhookUrl)
|
|
112
|
+
await zihin.updateTrigger({ triggerId, enabled: false }); // PATCH parcial
|
|
113
|
+
await zihin.updateTrigger({ triggerId, queryExtraction: { mode: 'full_body' } }); // GET+merge+PATCH
|
|
83
114
|
await zihin.deleteTrigger({ triggerId }); // remove (requer key admin/owner; editor → 403)
|
|
84
115
|
```
|
|
85
116
|
|
|
117
|
+
> `updateTrigger` faz GET + merge + PATCH quando você altera config (o BE substitui
|
|
118
|
+
> `trigger_config` inteiro). Há uma janela entre o GET e o PATCH em que uma escrita concorrente
|
|
119
|
+
> pode ser sobrescrita.
|
|
120
|
+
|
|
86
121
|
## Dropdown de agentes
|
|
87
122
|
|
|
88
123
|
```ts
|
|
@@ -93,8 +128,8 @@ const agents = await zihin.listAgents(); // GET /api/v2/agents
|
|
|
93
128
|
## Permissões da API key
|
|
94
129
|
|
|
95
130
|
- `invokeAgent` / `streamAgent` — qualquer role.
|
|
96
|
-
- `createTrigger` / `getExecution` — exigem key **admin** ou **editor** (default é
|
|
97
|
-
`member` recebem `ZihinAgentError` com `kind: 'auth'`.
|
|
131
|
+
- `createTrigger` / `updateTrigger` / `getExecution` — exigem key **admin** ou **editor** (default é
|
|
132
|
+
admin). Keys `member` recebem `ZihinAgentError` com `kind: 'auth'`.
|
|
98
133
|
|
|
99
134
|
## Erros
|
|
100
135
|
|
|
@@ -123,11 +158,17 @@ preservados. Cancele com `AbortSignal` via `params.signal`.
|
|
|
123
158
|
### Observabilidade e portabilidade
|
|
124
159
|
|
|
125
160
|
- **Hooks** (opt-in, sem `console`): `onRetry(info)` (a cada retentativa, com `endpoint`/`attempt`/
|
|
126
|
-
`delayMs`/`reason`/`status`) e `onError(err)
|
|
161
|
+
`delayMs`/`reason`/`status`) e `onError(err)` — chamado quando uma operação falha em definitivo
|
|
162
|
+
(inclusive `aborted`; filtre por `err.kind`). Exceção lançada dentro do hook é engolida e nunca
|
|
163
|
+
mascara o erro original.
|
|
127
164
|
- **`fetch` injetável** — `fetch?` na config; por padrão usa `globalThis.fetch` (Node ≥18). Um
|
|
128
165
|
preflight dá erro `config` claro se não houver fetch.
|
|
129
166
|
- **Portável** — sem `Buffer`; `node:crypto` só é carregado se você usar `signRequest`. Roda em Node;
|
|
130
|
-
para edge/serverless, injete `fetch` se necessário.
|
|
167
|
+
para edge/serverless, injete `fetch` se necessário. O pacote publica **CJS e ESM** (`exports` map):
|
|
168
|
+
`require()` e `import` funcionam. Duas ressalvas: no build ESM, `signRequest` precisa de Node
|
|
169
|
+
>=20.16 (`process.getBuiltinModule`) e sem isso lança `ZihinAgentError` com `kind: 'config'`; e
|
|
170
|
+
carregar **as duas formas no mesmo processo** cria duas classes `ZihinAgentError` distintas, o que
|
|
171
|
+
faz `instanceof` falhar — padronize `require` **ou** `import` para o núcleo na sua árvore de deps.
|
|
131
172
|
|
|
132
173
|
```ts
|
|
133
174
|
const zihin = createClient({
|
|
@@ -140,8 +181,14 @@ const zihin = createClient({
|
|
|
140
181
|
});
|
|
141
182
|
```
|
|
142
183
|
|
|
143
|
-
> SSRF: a validação de base/callback URL é por nome de host
|
|
144
|
-
>
|
|
184
|
+
> SSRF: a validação de base/callback/attachment URL é por **nome de host** — cobre IPv4 privado
|
|
185
|
+
> (inclusive octal/hex, normalizados pela URL), IPv6 privado **por faixa de bits** (`fc00::/7`,
|
|
186
|
+
> `fe80::/10`, `fec0::/10`, loopback e IPv4 embutido `::ffff:`/`::`), FQDN com ponto final e os
|
|
187
|
+
> hosts de metadata de nuvem.
|
|
188
|
+
>
|
|
189
|
+
> **Limite importante:** é validação por nome, não por IP resolvido. Com `allowCustomBaseUrl: true`,
|
|
190
|
+
> um host que **resolva** para IP privado (DNS rebinding) passa. Isto não substitui bloqueio de
|
|
191
|
+
> egresso na borda de rede — mantenha o whitelist (default) em ambiente sensível.
|
|
145
192
|
|
|
146
193
|
## Segurança
|
|
147
194
|
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Erros do @zihin/agent-client — sanitizados (sem vazar key/Bearer/stack), mas COMPLETOS:
|
|
3
|
+
* carregam endpoint, nº de tentativas e request_id do BE para depuração em produção externa.
|
|
4
|
+
*
|
|
5
|
+
* @module errors
|
|
6
|
+
*/
|
|
7
|
+
type ZihinErrorKind = 'config' | 'auth' | 'not_found' | 'rate_limit' | 'timeout' | 'aborted' | 'server' | 'network' | 'protocol' | 'unknown';
|
|
8
|
+
/** Contexto opcional anexado a um erro para correlação/depuração. */
|
|
9
|
+
interface ErrorMeta {
|
|
10
|
+
/** Ex.: "POST llm.zihin.ai/api/v2/agents/abc/stream". */
|
|
11
|
+
endpoint?: string;
|
|
12
|
+
/** Número de tentativas feitas antes de falhar. */
|
|
13
|
+
attempts?: number;
|
|
14
|
+
}
|
|
15
|
+
interface ZihinErrorOptions extends ErrorMeta {
|
|
16
|
+
status?: number;
|
|
17
|
+
code?: string;
|
|
18
|
+
retryable?: boolean;
|
|
19
|
+
/** request_id do BE (NÃO é segredo) — handle para o suporte correlacionar nos logs. */
|
|
20
|
+
requestId?: string;
|
|
21
|
+
}
|
|
22
|
+
declare class ZihinAgentError extends Error {
|
|
23
|
+
readonly kind: ZihinErrorKind;
|
|
24
|
+
readonly status?: number;
|
|
25
|
+
readonly code?: string;
|
|
26
|
+
readonly retryable: boolean;
|
|
27
|
+
readonly requestId?: string;
|
|
28
|
+
readonly attempts?: number;
|
|
29
|
+
readonly endpoint?: string;
|
|
30
|
+
constructor(kind: ZihinErrorKind, message: string, opts?: ZihinErrorOptions);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Tipos do contrato externo Zihin — fonte de verdade verificada contra o BE
|
|
35
|
+
* (zihin-agent-builder/server-llm, 2026-06-28).
|
|
36
|
+
*
|
|
37
|
+
* @module types
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
interface ZihinClientConfig {
|
|
41
|
+
/** API key `zhn_live_*` (tenant embutido). Para triggers/telemetria use role admin/editor. */
|
|
42
|
+
apiKey: string;
|
|
43
|
+
/** Base URL. Default: https://llm.zihin.ai */
|
|
44
|
+
baseUrl?: string;
|
|
45
|
+
/** Timeout por request (ms). Default: 120000 (= limite do /stream no BE). */
|
|
46
|
+
timeoutMs?: number;
|
|
47
|
+
/** Máximo de retentativas em 5xx/429/erro de rede. Default: 2. */
|
|
48
|
+
maxRetries?: number;
|
|
49
|
+
/** Permite base URL fora da whitelist Zihin (default false → SSRF guard). */
|
|
50
|
+
allowCustomBaseUrl?: boolean;
|
|
51
|
+
/** Permite http:// (apenas dev/local). Default false. */
|
|
52
|
+
allowHttp?: boolean;
|
|
53
|
+
/** Teto de bytes por evento/linha SSE (anti-DoS de memória). Default: 1MB. */
|
|
54
|
+
maxStreamEventBytes?: number;
|
|
55
|
+
/** Teto de bytes do stream inteiro (anti-DoS de memória). Default: 64MB. */
|
|
56
|
+
maxStreamTotalBytes?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Implementação de `fetch` a usar. Default: `globalThis.fetch`. Injete em runtimes onde o
|
|
59
|
+
* fetch não é global (Node <18 com polyfill, testes, proxies).
|
|
60
|
+
*/
|
|
61
|
+
fetch?: typeof fetch;
|
|
62
|
+
/**
|
|
63
|
+
* Observabilidade (opt-in, sem console): chamado antes de cada retentativa.
|
|
64
|
+
* Para logar backoff/timeouts/falhas transitórias em produção externa.
|
|
65
|
+
*/
|
|
66
|
+
onRetry?: (info: RetryInfo) => void;
|
|
67
|
+
/**
|
|
68
|
+
* Observabilidade: chamado quando uma operação do cliente falha em definitivo (após retries),
|
|
69
|
+
* inclusive `aborted` — filtre por `error.kind` se quiser ignorar cancelamentos. Uma exceção
|
|
70
|
+
* lançada dentro do callback é engolida (não mascara o erro original). Não cobre erros de
|
|
71
|
+
* configuração lançados pelo construtor (o cliente ainda não existe).
|
|
72
|
+
*/
|
|
73
|
+
onError?: (error: ZihinAgentError) => void;
|
|
74
|
+
}
|
|
75
|
+
interface RetryInfo {
|
|
76
|
+
/** "POST llm.zihin.ai/api/v2/agents/abc/stream". */
|
|
77
|
+
endpoint: string;
|
|
78
|
+
/** Número da tentativa que acabou de falhar (1 = primeira). */
|
|
79
|
+
attempt: number;
|
|
80
|
+
/** Atraso até a próxima tentativa, em ms. */
|
|
81
|
+
delayMs: number;
|
|
82
|
+
/** Motivo do retry. */
|
|
83
|
+
reason: 'status' | 'network';
|
|
84
|
+
/** Status HTTP, quando `reason === 'status'`. */
|
|
85
|
+
status?: number;
|
|
86
|
+
}
|
|
87
|
+
type AttachmentType = 'image' | 'audio' | 'document';
|
|
88
|
+
interface Attachment {
|
|
89
|
+
url: string;
|
|
90
|
+
type: AttachmentType;
|
|
91
|
+
}
|
|
92
|
+
interface InvokeOptions {
|
|
93
|
+
temperature?: number;
|
|
94
|
+
maxTokens?: number;
|
|
95
|
+
/** Timeout específico desta chamada (ms); sobrepõe o do cliente. */
|
|
96
|
+
timeoutMs?: number;
|
|
97
|
+
/** Just-in-time tool loading (Sprint 33). */
|
|
98
|
+
jitMode?: boolean;
|
|
99
|
+
}
|
|
100
|
+
interface InvokeAgentParams {
|
|
101
|
+
/** UUID do agente (path :agent_id). */
|
|
102
|
+
agentId: string;
|
|
103
|
+
/** Mensagem ao agente. `message` OU `attachments` é obrigatório. */
|
|
104
|
+
message?: string;
|
|
105
|
+
/** Anexos multimodais. `message` OU `attachments` é obrigatório. */
|
|
106
|
+
attachments?: Attachment[];
|
|
107
|
+
/** Continuidade de conversa (Supabase agent_sessions). */
|
|
108
|
+
sessionId?: string;
|
|
109
|
+
options?: InvokeOptions;
|
|
110
|
+
metadata?: {
|
|
111
|
+
traceId?: string;
|
|
112
|
+
correlationId?: string;
|
|
113
|
+
[k: string]: unknown;
|
|
114
|
+
};
|
|
115
|
+
/** Cancelamento externo. */
|
|
116
|
+
signal?: AbortSignal;
|
|
117
|
+
/**
|
|
118
|
+
* Retém todos os eventos SSE brutos em `AgentResult.raw`. Default: false (economiza memória
|
|
119
|
+
* em runs longos). `streamAgent` sempre entrega os chunks ao vivo, independente disto.
|
|
120
|
+
*/
|
|
121
|
+
includeRaw?: boolean;
|
|
122
|
+
}
|
|
123
|
+
interface Usage {
|
|
124
|
+
inputTokens?: number;
|
|
125
|
+
outputTokens?: number;
|
|
126
|
+
totalTokens?: number;
|
|
127
|
+
costUsd?: number;
|
|
128
|
+
}
|
|
129
|
+
interface Source {
|
|
130
|
+
title?: string;
|
|
131
|
+
url?: string;
|
|
132
|
+
[k: string]: unknown;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Resultado final de `invokeAgent`: consolida o evento SSE `response`
|
|
136
|
+
* (content/sources/session_id/blocks) com o evento `metrics` (usage/model).
|
|
137
|
+
*/
|
|
138
|
+
interface AgentResult {
|
|
139
|
+
content: string;
|
|
140
|
+
sessionId?: string;
|
|
141
|
+
model?: string;
|
|
142
|
+
usage?: Usage;
|
|
143
|
+
sources?: Source[];
|
|
144
|
+
/** Cards/blocos estruturados (SPEC B). */
|
|
145
|
+
blocks?: Array<{
|
|
146
|
+
type: string;
|
|
147
|
+
[k: string]: unknown;
|
|
148
|
+
}>;
|
|
149
|
+
iterations?: number;
|
|
150
|
+
executionTimeMs?: number;
|
|
151
|
+
/** Eventos SSE brutos coletados (para depuração / casos avançados). */
|
|
152
|
+
raw: AgentStreamChunk[];
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Chunk normalizado emitido por `streamAgent`. Mapeia os tipos de evento SSE do BE:
|
|
156
|
+
* metadata, status, attachments, phase, thinking, tool, action_proposed, token,
|
|
157
|
+
* warning, response, metrics.
|
|
158
|
+
*/
|
|
159
|
+
type AgentStreamChunk = {
|
|
160
|
+
type: 'metadata';
|
|
161
|
+
requestId?: string;
|
|
162
|
+
agentId?: string;
|
|
163
|
+
sessionId?: string;
|
|
164
|
+
data: unknown;
|
|
165
|
+
} | {
|
|
166
|
+
type: 'status';
|
|
167
|
+
phase?: string;
|
|
168
|
+
data: unknown;
|
|
169
|
+
} | {
|
|
170
|
+
type: 'attachments';
|
|
171
|
+
data: unknown;
|
|
172
|
+
} | {
|
|
173
|
+
type: 'phase';
|
|
174
|
+
phase?: string;
|
|
175
|
+
data: unknown;
|
|
176
|
+
} | {
|
|
177
|
+
type: 'thinking';
|
|
178
|
+
thought?: string;
|
|
179
|
+
data: unknown;
|
|
180
|
+
} | {
|
|
181
|
+
type: 'tool';
|
|
182
|
+
tool?: string;
|
|
183
|
+
callId?: string;
|
|
184
|
+
success?: boolean;
|
|
185
|
+
data: unknown;
|
|
186
|
+
} | {
|
|
187
|
+
type: 'action_proposed';
|
|
188
|
+
data: unknown;
|
|
189
|
+
} | {
|
|
190
|
+
type: 'token';
|
|
191
|
+
content: string;
|
|
192
|
+
data: unknown;
|
|
193
|
+
} | {
|
|
194
|
+
type: 'warning';
|
|
195
|
+
message?: string;
|
|
196
|
+
data: unknown;
|
|
197
|
+
} | {
|
|
198
|
+
type: 'response';
|
|
199
|
+
content: string;
|
|
200
|
+
sessionId?: string;
|
|
201
|
+
sources?: Source[];
|
|
202
|
+
blocks?: Array<{
|
|
203
|
+
type: string;
|
|
204
|
+
[k: string]: unknown;
|
|
205
|
+
}>;
|
|
206
|
+
data: unknown;
|
|
207
|
+
} | {
|
|
208
|
+
type: 'metrics';
|
|
209
|
+
usage?: Usage;
|
|
210
|
+
model?: string;
|
|
211
|
+
iterations?: number;
|
|
212
|
+
executionTimeMs?: number;
|
|
213
|
+
data: unknown;
|
|
214
|
+
} | {
|
|
215
|
+
type: 'unknown';
|
|
216
|
+
event: string;
|
|
217
|
+
data: unknown;
|
|
218
|
+
};
|
|
219
|
+
type TriggerMode = 'sync' | 'async';
|
|
220
|
+
/**
|
|
221
|
+
* Como o BE extrai a mensagem do agente a partir do payload de disparo (webhook):
|
|
222
|
+
* - `field`: um campo top-level do payload (`payload[field]`).
|
|
223
|
+
* - `template`: compõe a mensagem com placeholders `{{payload.caminho.aninhado}}` —
|
|
224
|
+
* é o modo para payloads estruturados ricos.
|
|
225
|
+
* - `full_body`: fallback do BE — usa `payload.message || payload.query ||
|
|
226
|
+
* JSON.stringify(payload)` (o payload inteiro serializado vira a mensagem).
|
|
227
|
+
* (Verificado no BE em 2026-08-03: `jmespath` citado em docs antigas NÃO é implementado.)
|
|
228
|
+
*/
|
|
229
|
+
type QueryExtraction = {
|
|
230
|
+
mode: 'field';
|
|
231
|
+
field: string;
|
|
232
|
+
} | {
|
|
233
|
+
mode: 'template';
|
|
234
|
+
template: string;
|
|
235
|
+
} | {
|
|
236
|
+
mode: 'full_body';
|
|
237
|
+
};
|
|
238
|
+
interface CreateTriggerParams {
|
|
239
|
+
agentId: string;
|
|
240
|
+
/** Nome legível do trigger. */
|
|
241
|
+
name: string;
|
|
242
|
+
/** `async` → 202 + callback; `sync` → 200 + JSON na hora. Default: async. */
|
|
243
|
+
mode?: TriggerMode;
|
|
244
|
+
/** URL que o BE chama com o resultado (obrigatório no modo async). */
|
|
245
|
+
callbackUrl?: string;
|
|
246
|
+
/** Método HTTP do callback. Default: POST. */
|
|
247
|
+
callbackMethod?: 'POST' | 'PUT';
|
|
248
|
+
/** Campo do payload de disparo de onde sai a mensagem do agente. Default: "message". */
|
|
249
|
+
queryField?: string;
|
|
250
|
+
/**
|
|
251
|
+
* Extração da mensagem a partir do payload (field/template/full_body). Tem precedência
|
|
252
|
+
* sobre `queryField` (que equivale a `{ mode: 'field', field: queryField }`).
|
|
253
|
+
*/
|
|
254
|
+
queryExtraction?: QueryExtraction;
|
|
255
|
+
/** Auth de disparo aceita. Default: api_key. */
|
|
256
|
+
dispatchAuth?: 'api_key' | 'signature' | 'none';
|
|
257
|
+
signal?: AbortSignal;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Atualização parcial de um trigger (PATCH). Campos de config (queryExtraction/callback/mode)
|
|
261
|
+
* exigem um GET prévio + merge, porque o PATCH do BE SUBSTITUI `trigger_config` por inteiro.
|
|
262
|
+
*/
|
|
263
|
+
interface UpdateTriggerParams {
|
|
264
|
+
triggerId: string;
|
|
265
|
+
name?: string;
|
|
266
|
+
description?: string;
|
|
267
|
+
enabled?: boolean;
|
|
268
|
+
/** Troca a extração de query preservando o restante do trigger_config. */
|
|
269
|
+
queryExtraction?: QueryExtraction;
|
|
270
|
+
/** Troca a URL do callback (modo async). */
|
|
271
|
+
callbackUrl?: string;
|
|
272
|
+
/** Troca o método do callback. */
|
|
273
|
+
callbackMethod?: 'POST' | 'PUT';
|
|
274
|
+
/** Troca o modo de execução (sync/async). */
|
|
275
|
+
mode?: TriggerMode;
|
|
276
|
+
signal?: AbortSignal;
|
|
277
|
+
}
|
|
278
|
+
interface TriggerRef {
|
|
279
|
+
triggerId: string;
|
|
280
|
+
/** URL completa de disparo: POST {webhookUrl}. */
|
|
281
|
+
webhookUrl: string;
|
|
282
|
+
}
|
|
283
|
+
/** Resultado de findOrCreateTrigger: o ref + se foi recém-criado ou reaproveitado. */
|
|
284
|
+
interface FindOrCreateResult extends TriggerRef {
|
|
285
|
+
created: boolean;
|
|
286
|
+
}
|
|
287
|
+
/** Trigger como listado/obtido do BE. */
|
|
288
|
+
interface TriggerInfo {
|
|
289
|
+
id: string;
|
|
290
|
+
agentId?: string;
|
|
291
|
+
name?: string;
|
|
292
|
+
description?: string;
|
|
293
|
+
triggerType?: string;
|
|
294
|
+
enabled?: boolean;
|
|
295
|
+
triggerCount?: number;
|
|
296
|
+
lastError?: string;
|
|
297
|
+
/** Presente para triggers do tipo webhook. */
|
|
298
|
+
webhookUrl?: string;
|
|
299
|
+
}
|
|
300
|
+
interface ListTriggersParams {
|
|
301
|
+
/** Filtra por agente. */
|
|
302
|
+
agentId?: string;
|
|
303
|
+
/** Filtra por tipo (webhook | db_event | email | schedule). */
|
|
304
|
+
triggerType?: string;
|
|
305
|
+
/** Apenas habilitados. */
|
|
306
|
+
enabledOnly?: boolean;
|
|
307
|
+
signal?: AbortSignal;
|
|
308
|
+
}
|
|
309
|
+
interface GetTriggerParams {
|
|
310
|
+
triggerId: string;
|
|
311
|
+
signal?: AbortSignal;
|
|
312
|
+
}
|
|
313
|
+
interface DeleteTriggerParams {
|
|
314
|
+
triggerId: string;
|
|
315
|
+
signal?: AbortSignal;
|
|
316
|
+
}
|
|
317
|
+
interface DispatchAgentParams {
|
|
318
|
+
triggerId: string;
|
|
319
|
+
/** Payload entregue ao trigger (a mensagem sai do `queryField` configurado). */
|
|
320
|
+
payload: Record<string, unknown>;
|
|
321
|
+
signal?: AbortSignal;
|
|
322
|
+
}
|
|
323
|
+
interface DispatchResult {
|
|
324
|
+
/** true quando o BE retorna 202 (async) ou 200 (sync). */
|
|
325
|
+
accepted: boolean;
|
|
326
|
+
triggerId?: string;
|
|
327
|
+
executionId?: string;
|
|
328
|
+
/** Presente quando o trigger é `sync`: resposta imediata do agente. */
|
|
329
|
+
agentResponse?: string;
|
|
330
|
+
usage?: Usage;
|
|
331
|
+
raw: unknown;
|
|
332
|
+
}
|
|
333
|
+
interface ExecutionStatus {
|
|
334
|
+
executionId: string;
|
|
335
|
+
status: string;
|
|
336
|
+
startedAt?: string;
|
|
337
|
+
finishedAt?: string;
|
|
338
|
+
executionTimeMs?: number;
|
|
339
|
+
usage?: Usage;
|
|
340
|
+
result?: string;
|
|
341
|
+
raw: unknown;
|
|
342
|
+
}
|
|
343
|
+
interface GetExecutionParams {
|
|
344
|
+
triggerId: string;
|
|
345
|
+
executionId: string;
|
|
346
|
+
signal?: AbortSignal;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Listagem de agentes do tenant (GET /api/v2/agents). Alimenta o dropdown do nó n8n (#17)
|
|
351
|
+
* e o select de `agentId` no Paperclip (#20). Aceita key `zhn_live_*` (agents:read em todos os roles).
|
|
352
|
+
*
|
|
353
|
+
* @module agents
|
|
354
|
+
*/
|
|
355
|
+
|
|
356
|
+
interface AgentSummary {
|
|
357
|
+
id: string;
|
|
358
|
+
name?: string;
|
|
359
|
+
commercialName?: string;
|
|
360
|
+
bio?: string;
|
|
361
|
+
type?: string;
|
|
362
|
+
status?: string;
|
|
363
|
+
tags?: string[];
|
|
364
|
+
toolsCount?: number;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* ZihinAgentClient — fachada do núcleo. Carrega a config uma vez (auth, baseUrl, timeout,
|
|
369
|
+
* retries) e expõe os dois caminhos do padrão híbrido:
|
|
370
|
+
* • Direto: invokeAgent / streamAgent (POST /stream, SSE bufferizado)
|
|
371
|
+
* • Triggers: createTrigger / dispatchAgent / getExecution (async + callback)
|
|
372
|
+
* • Auxiliar: listAgents (dropdown de agentes)
|
|
373
|
+
*
|
|
374
|
+
* @module client
|
|
375
|
+
*/
|
|
376
|
+
|
|
377
|
+
declare class ZihinAgentClient {
|
|
378
|
+
private readonly cfg;
|
|
379
|
+
constructor(config: ZihinClientConfig);
|
|
380
|
+
/** Base URL efetiva (após validação SSRF). */
|
|
381
|
+
get baseUrl(): string;
|
|
382
|
+
/** Notifica `config.onError` (falha definitiva); o callback nunca derruba o fluxo. */
|
|
383
|
+
private report;
|
|
384
|
+
private guard;
|
|
385
|
+
/** Invoca o agente e retorna o resultado final consolidado (response + metrics). */
|
|
386
|
+
invokeAgent(params: InvokeAgentParams): Promise<AgentResult>;
|
|
387
|
+
/** Emite deltas ao vivo do agente (async iterator). */
|
|
388
|
+
streamAgent(params: InvokeAgentParams): AsyncGenerator<AgentStreamChunk>;
|
|
389
|
+
/** Provisiona (1x) um trigger de webhook ligado a um agente. */
|
|
390
|
+
createTrigger(params: CreateTriggerParams): Promise<TriggerRef>;
|
|
391
|
+
/** Reaproveita (por agente+nome) ou cria um trigger — evita duplicação. */
|
|
392
|
+
findOrCreateTrigger(params: CreateTriggerParams): Promise<FindOrCreateResult>;
|
|
393
|
+
/** Lista os triggers do tenant (filtros opcionais). */
|
|
394
|
+
listTriggers(params?: ListTriggersParams): Promise<TriggerInfo[]>;
|
|
395
|
+
/** Obtém um trigger pelo id (inclui webhookUrl). */
|
|
396
|
+
getTrigger(params: GetTriggerParams): Promise<TriggerInfo>;
|
|
397
|
+
/** Atualiza um trigger (name/description/enabled/extração/callback) via PATCH. */
|
|
398
|
+
updateTrigger(params: UpdateTriggerParams): Promise<TriggerInfo>;
|
|
399
|
+
/** Remove um trigger (requer key admin/owner). */
|
|
400
|
+
deleteTrigger(params: DeleteTriggerParams): Promise<{
|
|
401
|
+
deleted: boolean;
|
|
402
|
+
}>;
|
|
403
|
+
/** Dispara um trigger: 202 (async) ou JSON imediato (sync). */
|
|
404
|
+
dispatchAgent(params: DispatchAgentParams): Promise<DispatchResult>;
|
|
405
|
+
/** Consulta o resultado de uma execução disparada por trigger (polling). */
|
|
406
|
+
getExecution(params: GetExecutionParams): Promise<ExecutionStatus>;
|
|
407
|
+
/** Lista os agentes do tenant (dropdown). */
|
|
408
|
+
listAgents(opts?: {
|
|
409
|
+
signal?: AbortSignal;
|
|
410
|
+
}): Promise<AgentSummary[]>;
|
|
411
|
+
}
|
|
412
|
+
/** Açúcar: cria um cliente a partir da config. */
|
|
413
|
+
declare function createClient(config: ZihinClientConfig): ZihinAgentClient;
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Security utilities — portado de n8n-nodes-zihin/src/utils/security.ts (zero-dep).
|
|
417
|
+
* SSRF prevention, payload limits, error sanitization, API-key format.
|
|
418
|
+
* (A assinatura HMAC vive em `signing.ts` — precisa de ZihinAgentError e criaria ciclo aqui.)
|
|
419
|
+
*
|
|
420
|
+
* Núcleo compartilhado: os shells (n8n, Paperclip) reusam estas primitivas via @zihin/agent-client.
|
|
421
|
+
*
|
|
422
|
+
* @module security
|
|
423
|
+
*/
|
|
424
|
+
interface UrlValidationResult {
|
|
425
|
+
valid: boolean;
|
|
426
|
+
error?: string;
|
|
427
|
+
sanitizedUrl?: string;
|
|
428
|
+
}
|
|
429
|
+
interface UrlValidationOptions {
|
|
430
|
+
allowCustomDomains?: boolean;
|
|
431
|
+
allowHttp?: boolean;
|
|
432
|
+
allowLocalhost?: boolean;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Validates a base URL for SSRF prevention.
|
|
436
|
+
*
|
|
437
|
+
* NOTA (S4): a checagem é por NOME de host, não pelo IP resolvido. Com `allowCustomDomains: true`,
|
|
438
|
+
* um host que resolve para IP privado (DNS rebinding) passa. Em ambiente sensível, mantenha o
|
|
439
|
+
* whitelist (default) ou faça a resolução/checagem de IP na borda de rede.
|
|
440
|
+
*
|
|
441
|
+
* @param url - The URL to validate
|
|
442
|
+
* @param options - Validation options
|
|
443
|
+
* @returns Validation result with sanitized URL or error
|
|
444
|
+
*/
|
|
445
|
+
declare function validateBaseUrl(url: string, options?: UrlValidationOptions): UrlValidationResult;
|
|
446
|
+
interface PayloadLimits {
|
|
447
|
+
maxPromptBytes: number;
|
|
448
|
+
maxMessageCount: number;
|
|
449
|
+
maxSingleMessageBytes: number;
|
|
450
|
+
maxTotalPayloadBytes: number;
|
|
451
|
+
}
|
|
452
|
+
declare const DEFAULT_LIMITS: PayloadLimits;
|
|
453
|
+
interface PayloadValidationResult {
|
|
454
|
+
valid: boolean;
|
|
455
|
+
error?: string;
|
|
456
|
+
truncated?: boolean;
|
|
457
|
+
details?: {
|
|
458
|
+
promptBytes?: number;
|
|
459
|
+
messageCount?: number;
|
|
460
|
+
largestMessageBytes?: number;
|
|
461
|
+
totalBytes?: number;
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Validates a single message/prompt size against configured limits.
|
|
466
|
+
*/
|
|
467
|
+
declare function validatePromptSize(prompt: string, limits?: Partial<PayloadLimits>): PayloadValidationResult;
|
|
468
|
+
interface SanitizedError {
|
|
469
|
+
message: string;
|
|
470
|
+
code?: string;
|
|
471
|
+
retryable: boolean;
|
|
472
|
+
retryAfter?: number;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Sanitizes API errors to prevent information leakage (keys, request IDs, stack traces).
|
|
476
|
+
*/
|
|
477
|
+
declare function sanitizeApiError(error: unknown): SanitizedError;
|
|
478
|
+
interface ApiKeyValidationResult {
|
|
479
|
+
valid: boolean;
|
|
480
|
+
error?: string;
|
|
481
|
+
environment?: 'live' | 'test' | 'dev';
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Validates API key format (zhn_live_* | zhn_test_* | zhn_dev_*).
|
|
485
|
+
*/
|
|
486
|
+
declare function validateApiKeyFormat(apiKey: string): ApiKeyValidationResult;
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Assinatura HMAC opcional de payloads (auth `signature` dos triggers).
|
|
490
|
+
*
|
|
491
|
+
* Vive fora de `security.ts` de propósito: precisa de `ZihinAgentError` (errors.ts), e errors.ts
|
|
492
|
+
* já importa security.ts — juntar os dois criaria um ciclo de import.
|
|
493
|
+
*
|
|
494
|
+
* @module signing
|
|
495
|
+
*/
|
|
496
|
+
interface SignedRequestHeaders {
|
|
497
|
+
'X-Zihin-Signature': string;
|
|
498
|
+
'X-Zihin-Timestamp': string;
|
|
499
|
+
'X-Zihin-Nonce': string;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Assina um payload com HMAC-SHA256 (timestamp + nonce + payload).
|
|
503
|
+
*
|
|
504
|
+
* ⚠️ No build ESM depende de `process.getBuiltinModule` (Node >=20.16); em Node mais antigo via
|
|
505
|
+
* `import` lança `ZihinAgentError` com `kind: 'config'`. O build CJS funciona em qualquer Node
|
|
506
|
+
* >=18. (Todo o resto do núcleo é Web-API puro e roda nos dois.)
|
|
507
|
+
*/
|
|
508
|
+
declare function signRequest(payload: string, secretKey: string, timestamp?: number): SignedRequestHeaders;
|
|
509
|
+
|
|
510
|
+
export { type AgentResult, type AgentStreamChunk, type AgentSummary, type Attachment, type AttachmentType, type CreateTriggerParams, DEFAULT_LIMITS, type DeleteTriggerParams, type DispatchAgentParams, type DispatchResult, type ExecutionStatus, type FindOrCreateResult, type GetExecutionParams, type GetTriggerParams, type InvokeAgentParams, type InvokeOptions, type ListTriggersParams, type QueryExtraction, type RetryInfo, type SignedRequestHeaders, type Source, type TriggerInfo, type TriggerMode, type TriggerRef, type UpdateTriggerParams, type Usage, ZihinAgentClient, ZihinAgentError, type ZihinClientConfig, type ZihinErrorKind, createClient, sanitizeApiError, signRequest, validateApiKeyFormat, validateBaseUrl, validatePromptSize };
|