vectorgov 0.3.0 → 0.5.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 CHANGED
@@ -145,6 +145,42 @@ const balanced = await vg.search('O que é ETP?', { mode: 'balanced' });
145
145
  const precise = await vg.search('O que é ETP?', { mode: 'precise' });
146
146
  ```
147
147
 
148
+ > **Importante:** O modo de busca **não afeta** a quantidade de tokens enviados ao seu LLM. Todos os modos retornam o mesmo número de resultados (controlado por `topK`). A diferença está na **qualidade** dos resultados:
149
+ > - **HyDE** (modo `precise`): Gera documentos hipotéticos para melhorar a busca - processamento extra no backend VectorGov
150
+ > - **Reranker** (modos `balanced` e `precise`): Reordena resultados por relevância - processamento extra no backend VectorGov
151
+ >
152
+ > Ou seja: você recebe resultados **mais relevantes**, não **mais resultados**.
153
+
154
+ ## Estimativa de Tokens
155
+
156
+ Planeje o uso de contexto com estimativa de tokens antes de enviar para seu LLM:
157
+
158
+ ```typescript
159
+ const results = await vg.search('O que é ETP?', { topK: 5 });
160
+
161
+ // Estima tokens do contexto
162
+ const stats = await vg.estimateTokens(results);
163
+
164
+ console.log(`Tokens de contexto: ${stats.contextTokens}`);
165
+ console.log(`Tokens de sistema: ${stats.systemTokens}`);
166
+ console.log(`Total: ${stats.totalTokens}`);
167
+ console.log(`Caracteres: ${stats.charCount}`);
168
+ console.log(`Encoding: ${stats.encoding}`);
169
+
170
+ // Verificar se cabe no limite do modelo
171
+ if (stats.totalTokens > 4000) {
172
+ // Reduzir contexto
173
+ const smaller = await vg.search('O que é ETP?', { topK: 3 });
174
+ const smallerStats = await vg.estimateTokens(smaller);
175
+ console.log(`Novo total: ${smallerStats.totalTokens}`);
176
+ }
177
+
178
+ // Com system prompt customizado
179
+ const customStats = await vg.estimateTokens(results, {
180
+ systemPrompt: 'Você é um especialista jurídico...'
181
+ });
182
+ ```
183
+
148
184
  ## Filtros
149
185
 
150
186
  ```typescript
@@ -155,20 +191,6 @@ const results = await vg.search('dispensa de licitação', {
155
191
  });
156
192
  ```
157
193
 
158
- ## Perguntas com Resposta
159
-
160
- ```typescript
161
- // Usa o LLM do VectorGov para gerar resposta
162
- const response = await vg.ask('O que é ETP?');
163
-
164
- console.log(response.answer);
165
- console.log(`Confiança: ${(response.confidence * 100).toFixed(1)}%`);
166
-
167
- for (const citation of response.citations) {
168
- console.log(` - ${citation.short}`);
169
- }
170
- ```
171
-
172
194
  ## Feedback
173
195
 
174
196
  ```typescript
@@ -181,19 +203,6 @@ await vg.feedback(results.metadata.queryId, true);
181
203
  await vg.feedback(results.metadata.queryId, false);
182
204
  ```
183
205
 
184
- ## Streaming
185
-
186
- ```typescript
187
- // Resposta em tempo real com Server-Sent Events
188
- for await (const chunk of vg.askStream('O que é ETP?')) {
189
- if (chunk.type === 'token') {
190
- process.stdout.write(chunk.content || '');
191
- } else if (chunk.type === 'complete') {
192
- console.log('\n\nCitações:', chunk.citations);
193
- }
194
- }
195
- ```
196
-
197
206
  ## System Prompts
198
207
 
199
208
  ```typescript
@@ -374,9 +383,8 @@ const vg = new VectorGov({
374
383
  | Método | Descrição |
375
384
  |--------|-----------|
376
385
  | `search(query, options?)` | Busca semântica |
377
- | `ask(query, options?)` | Pergunta com resposta IA |
378
- | `askStream(query, options?)` | Pergunta com streaming |
379
386
  | `feedback(queryId, like)` | Envia feedback |
387
+ | `estimateTokens(content, options?)` | Estima tokens para LLM |
380
388
  | `storeResponse(options)` | Armazena resposta do seu LLM |
381
389
  | `getSystemPrompt(style)` | Obtém system prompt |
382
390
  | `availablePrompts` | Lista prompts disponíveis |
package/dist/index.d.mts CHANGED
@@ -86,39 +86,6 @@ interface Citation {
86
86
  /** Número do artigo */
87
87
  article?: string;
88
88
  }
89
- /** Metadados da resposta de pergunta */
90
- interface AskMetadata {
91
- /** Modelo usado */
92
- model: string;
93
- /** Tempo total em ms */
94
- latencyMs: number;
95
- /** Tempo de busca em ms */
96
- retrievalMs?: number;
97
- /** Tempo de geração em ms */
98
- generationMs?: number;
99
- /** Chunks usados */
100
- chunksUsed: number;
101
- /** Tokens usados */
102
- tokens?: number;
103
- /** Hash da query (para feedback) */
104
- queryHash?: string;
105
- }
106
- /** Resposta de uma pergunta */
107
- interface AskResponse {
108
- /** Resposta gerada */
109
- answer: string;
110
- /** Citações */
111
- citations: Citation[];
112
- /** Confiança (0-1) */
113
- confidence: number;
114
- /** Metadados */
115
- metadata: AskMetadata;
116
- }
117
- /** Opções para perguntar */
118
- interface AskOptions extends SearchOptions {
119
- /** Usar cache semântico */
120
- useCache?: boolean;
121
- }
122
89
  /** Resposta de feedback */
123
90
  interface FeedbackResponse {
124
91
  success: boolean;
@@ -128,16 +95,16 @@ interface FeedbackResponse {
128
95
  }
129
96
  /** Erros da API */
130
97
  declare class VectorGovError extends Error {
131
- statusCode?: number | undefined;
132
- code?: string | undefined;
133
- constructor(message: string, statusCode?: number | undefined, code?: string | undefined);
98
+ statusCode?: number;
99
+ code?: string;
100
+ constructor(message: string, statusCode?: number, code?: string);
134
101
  }
135
102
  declare class AuthenticationError extends VectorGovError {
136
103
  constructor(message?: string);
137
104
  }
138
105
  declare class RateLimitError extends VectorGovError {
139
- retryAfter?: number | undefined;
140
- constructor(message?: string, retryAfter?: number | undefined);
106
+ retryAfter?: number;
107
+ constructor(message?: string, retryAfter?: number);
141
108
  }
142
109
  /** Registro de evento de auditoria */
143
110
  interface AuditLog {
@@ -241,25 +208,6 @@ interface StoreResponseResult {
241
208
  /** Mensagem de status */
242
209
  message: string;
243
210
  }
244
- /** Chunk de resposta em streaming */
245
- interface StreamChunk {
246
- /** Tipo do chunk (start, token, complete, error) */
247
- type: 'start' | 'token' | 'complete' | 'error';
248
- /** Conteúdo do chunk (token ou mensagem) */
249
- content?: string;
250
- /** Query original (em start) */
251
- query?: string;
252
- /** Chunks usados (em start) */
253
- chunks?: number;
254
- /** Tempo em ms (em complete) */
255
- timeMs?: number;
256
- /** Citações (em complete) */
257
- citations?: Citation[];
258
- /** Hash da query (em complete) */
259
- queryHash?: string;
260
- /** Mensagem de erro (em error) */
261
- message?: string;
262
- }
263
211
  /** Resumo de um documento */
264
212
  interface DocumentSummary {
265
213
  /** ID único do documento */
@@ -382,6 +330,30 @@ interface GoogleTool {
382
330
  }
383
331
  /** Estilos de system prompt disponíveis */
384
332
  type SystemPromptStyle = 'default' | 'concise' | 'detailed' | 'chatbot';
333
+ /** Estatísticas de tokens para planejamento de contexto LLM */
334
+ interface TokenStats {
335
+ /** Tokens do contexto (hits formatados) */
336
+ contextTokens: number;
337
+ /** Tokens do system prompt */
338
+ systemTokens: number;
339
+ /** Tokens da query do usuário */
340
+ queryTokens: number;
341
+ /** Total de tokens (context + system + query) */
342
+ totalTokens: number;
343
+ /** Quantidade de hits no contexto */
344
+ hitsCount: number;
345
+ /** Número total de caracteres */
346
+ charCount: number;
347
+ /** Encoding utilizado (cl100k_base compatível com GPT-4/Claude) */
348
+ encoding: string;
349
+ }
350
+ /** Opções para estimativa de tokens */
351
+ interface EstimateTokensOptions {
352
+ /** System prompt customizado (opcional) */
353
+ systemPrompt?: string;
354
+ /** Query do usuário (obrigatório quando content é string) */
355
+ query?: string;
356
+ }
385
357
 
386
358
  /**
387
359
  * VectorGov SDK Client
@@ -432,33 +404,6 @@ declare class VectorGov {
432
404
  * ```
433
405
  */
434
406
  search(query: string, options?: SearchOptions): Promise<SearchResult>;
435
- /**
436
- * Faz uma pergunta e recebe uma resposta gerada por IA
437
- *
438
- * @param query - Pergunta
439
- * @param options - Opções
440
- * @returns Resposta com citações
441
- */
442
- ask(query: string, options?: AskOptions): Promise<AskResponse>;
443
- /**
444
- * Faz uma pergunta com resposta em streaming
445
- *
446
- * @param query - Pergunta do usuário
447
- * @param options - Opções de busca
448
- * @yields StreamChunk com cada parte da resposta
449
- *
450
- * @example
451
- * ```typescript
452
- * for await (const chunk of vg.askStream('O que é ETP?')) {
453
- * if (chunk.type === 'token') {
454
- * process.stdout.write(chunk.content || '');
455
- * } else if (chunk.type === 'complete') {
456
- * console.log(`\n\nFontes: ${chunk.citations?.length} citações`);
457
- * }
458
- * }
459
- * ```
460
- */
461
- askStream(query: string, options?: SearchOptions): AsyncGenerator<StreamChunk>;
462
407
  /**
463
408
  * Envia feedback (like/dislike) para uma resposta
464
409
  *
@@ -691,6 +636,40 @@ declare class VectorGov {
691
636
  * ```
692
637
  */
693
638
  getAuditEventTypes(): Promise<string[]>;
639
+ /**
640
+ * Estima a quantidade de tokens que serão usados com um LLM
641
+ *
642
+ * Use para planejar o contexto antes de enviar para seu LLM:
643
+ * - Verificar se cabe no limite do modelo
644
+ * - Calcular custos estimados
645
+ * - Ajustar top_k se necessário
646
+ *
647
+ * @param content - SearchResult ou string de contexto
648
+ * @param options - Opções (systemPrompt customizado, query)
649
+ * @returns Estatísticas de tokens
650
+ *
651
+ * @example
652
+ * ```typescript
653
+ * // Com SearchResult
654
+ * const results = await vg.search('O que é ETP?');
655
+ * const stats = await vg.estimateTokens(results);
656
+ * console.log(`Total de tokens: ${stats.totalTokens}`);
657
+ *
658
+ * if (stats.totalTokens > 4000) {
659
+ * // Reduzir contexto
660
+ * const smaller = await vg.search('O que é ETP?', { topK: 3 });
661
+ * }
662
+ *
663
+ * // Com string direta
664
+ * const stats2 = await vg.estimateTokens('Texto de contexto...');
665
+ *
666
+ * // Com system prompt customizado
667
+ * const stats3 = await vg.estimateTokens(results, {
668
+ * systemPrompt: 'Você é um especialista jurídico...'
669
+ * });
670
+ * ```
671
+ */
672
+ estimateTokens(content: SearchResult | string, options?: EstimateTokensOptions): Promise<TokenStats>;
694
673
  /**
695
674
  * Converte hits para formato de mensagens de chat
696
675
  */
@@ -701,4 +680,4 @@ declare class VectorGov {
701
680
  private hitsToContext;
702
681
  }
703
682
 
704
- export { type AnthropicTool, type AskMetadata, type AskOptions, type AskResponse, type AuditLog, type AuditLogsOptions, type AuditLogsResponse, type AuditStats, AuthenticationError, type ChatMessage, type Citation, type DeleteResponse, type DocumentSummary, type DocumentsResponse, type EnrichStatus, type FeedbackResponse, type GoogleTool, type IngestStatus, type ListDocumentsOptions, type OpenAITool, RateLimitError, type SearchHit, type SearchMetadata, type SearchMode, type SearchOptions, type SearchResult, type StoreResponseOptions, type StoreResponseResult, type StreamChunk, type SystemPromptStyle, type UploadResponse, VectorGov, type VectorGovConfig, VectorGovError };
683
+ export { type AnthropicTool, type AuditLog, type AuditLogsOptions, type AuditLogsResponse, type AuditStats, AuthenticationError, type ChatMessage, type Citation, type DeleteResponse, type DocumentSummary, type DocumentsResponse, type EnrichStatus, type EstimateTokensOptions, type FeedbackResponse, type GoogleTool, type IngestStatus, type ListDocumentsOptions, type OpenAITool, RateLimitError, type SearchHit, type SearchMetadata, type SearchMode, type SearchOptions, type SearchResult, type StoreResponseOptions, type StoreResponseResult, type SystemPromptStyle, type TokenStats, type UploadResponse, VectorGov, type VectorGovConfig, VectorGovError };
package/dist/index.d.ts CHANGED
@@ -86,39 +86,6 @@ interface Citation {
86
86
  /** Número do artigo */
87
87
  article?: string;
88
88
  }
89
- /** Metadados da resposta de pergunta */
90
- interface AskMetadata {
91
- /** Modelo usado */
92
- model: string;
93
- /** Tempo total em ms */
94
- latencyMs: number;
95
- /** Tempo de busca em ms */
96
- retrievalMs?: number;
97
- /** Tempo de geração em ms */
98
- generationMs?: number;
99
- /** Chunks usados */
100
- chunksUsed: number;
101
- /** Tokens usados */
102
- tokens?: number;
103
- /** Hash da query (para feedback) */
104
- queryHash?: string;
105
- }
106
- /** Resposta de uma pergunta */
107
- interface AskResponse {
108
- /** Resposta gerada */
109
- answer: string;
110
- /** Citações */
111
- citations: Citation[];
112
- /** Confiança (0-1) */
113
- confidence: number;
114
- /** Metadados */
115
- metadata: AskMetadata;
116
- }
117
- /** Opções para perguntar */
118
- interface AskOptions extends SearchOptions {
119
- /** Usar cache semântico */
120
- useCache?: boolean;
121
- }
122
89
  /** Resposta de feedback */
123
90
  interface FeedbackResponse {
124
91
  success: boolean;
@@ -128,16 +95,16 @@ interface FeedbackResponse {
128
95
  }
129
96
  /** Erros da API */
130
97
  declare class VectorGovError extends Error {
131
- statusCode?: number | undefined;
132
- code?: string | undefined;
133
- constructor(message: string, statusCode?: number | undefined, code?: string | undefined);
98
+ statusCode?: number;
99
+ code?: string;
100
+ constructor(message: string, statusCode?: number, code?: string);
134
101
  }
135
102
  declare class AuthenticationError extends VectorGovError {
136
103
  constructor(message?: string);
137
104
  }
138
105
  declare class RateLimitError extends VectorGovError {
139
- retryAfter?: number | undefined;
140
- constructor(message?: string, retryAfter?: number | undefined);
106
+ retryAfter?: number;
107
+ constructor(message?: string, retryAfter?: number);
141
108
  }
142
109
  /** Registro de evento de auditoria */
143
110
  interface AuditLog {
@@ -241,25 +208,6 @@ interface StoreResponseResult {
241
208
  /** Mensagem de status */
242
209
  message: string;
243
210
  }
244
- /** Chunk de resposta em streaming */
245
- interface StreamChunk {
246
- /** Tipo do chunk (start, token, complete, error) */
247
- type: 'start' | 'token' | 'complete' | 'error';
248
- /** Conteúdo do chunk (token ou mensagem) */
249
- content?: string;
250
- /** Query original (em start) */
251
- query?: string;
252
- /** Chunks usados (em start) */
253
- chunks?: number;
254
- /** Tempo em ms (em complete) */
255
- timeMs?: number;
256
- /** Citações (em complete) */
257
- citations?: Citation[];
258
- /** Hash da query (em complete) */
259
- queryHash?: string;
260
- /** Mensagem de erro (em error) */
261
- message?: string;
262
- }
263
211
  /** Resumo de um documento */
264
212
  interface DocumentSummary {
265
213
  /** ID único do documento */
@@ -382,6 +330,30 @@ interface GoogleTool {
382
330
  }
383
331
  /** Estilos de system prompt disponíveis */
384
332
  type SystemPromptStyle = 'default' | 'concise' | 'detailed' | 'chatbot';
333
+ /** Estatísticas de tokens para planejamento de contexto LLM */
334
+ interface TokenStats {
335
+ /** Tokens do contexto (hits formatados) */
336
+ contextTokens: number;
337
+ /** Tokens do system prompt */
338
+ systemTokens: number;
339
+ /** Tokens da query do usuário */
340
+ queryTokens: number;
341
+ /** Total de tokens (context + system + query) */
342
+ totalTokens: number;
343
+ /** Quantidade de hits no contexto */
344
+ hitsCount: number;
345
+ /** Número total de caracteres */
346
+ charCount: number;
347
+ /** Encoding utilizado (cl100k_base compatível com GPT-4/Claude) */
348
+ encoding: string;
349
+ }
350
+ /** Opções para estimativa de tokens */
351
+ interface EstimateTokensOptions {
352
+ /** System prompt customizado (opcional) */
353
+ systemPrompt?: string;
354
+ /** Query do usuário (obrigatório quando content é string) */
355
+ query?: string;
356
+ }
385
357
 
386
358
  /**
387
359
  * VectorGov SDK Client
@@ -432,33 +404,6 @@ declare class VectorGov {
432
404
  * ```
433
405
  */
434
406
  search(query: string, options?: SearchOptions): Promise<SearchResult>;
435
- /**
436
- * Faz uma pergunta e recebe uma resposta gerada por IA
437
- *
438
- * @param query - Pergunta
439
- * @param options - Opções
440
- * @returns Resposta com citações
441
- */
442
- ask(query: string, options?: AskOptions): Promise<AskResponse>;
443
- /**
444
- * Faz uma pergunta com resposta em streaming
445
- *
446
- * @param query - Pergunta do usuário
447
- * @param options - Opções de busca
448
- * @yields StreamChunk com cada parte da resposta
449
- *
450
- * @example
451
- * ```typescript
452
- * for await (const chunk of vg.askStream('O que é ETP?')) {
453
- * if (chunk.type === 'token') {
454
- * process.stdout.write(chunk.content || '');
455
- * } else if (chunk.type === 'complete') {
456
- * console.log(`\n\nFontes: ${chunk.citations?.length} citações`);
457
- * }
458
- * }
459
- * ```
460
- */
461
- askStream(query: string, options?: SearchOptions): AsyncGenerator<StreamChunk>;
462
407
  /**
463
408
  * Envia feedback (like/dislike) para uma resposta
464
409
  *
@@ -691,6 +636,40 @@ declare class VectorGov {
691
636
  * ```
692
637
  */
693
638
  getAuditEventTypes(): Promise<string[]>;
639
+ /**
640
+ * Estima a quantidade de tokens que serão usados com um LLM
641
+ *
642
+ * Use para planejar o contexto antes de enviar para seu LLM:
643
+ * - Verificar se cabe no limite do modelo
644
+ * - Calcular custos estimados
645
+ * - Ajustar top_k se necessário
646
+ *
647
+ * @param content - SearchResult ou string de contexto
648
+ * @param options - Opções (systemPrompt customizado, query)
649
+ * @returns Estatísticas de tokens
650
+ *
651
+ * @example
652
+ * ```typescript
653
+ * // Com SearchResult
654
+ * const results = await vg.search('O que é ETP?');
655
+ * const stats = await vg.estimateTokens(results);
656
+ * console.log(`Total de tokens: ${stats.totalTokens}`);
657
+ *
658
+ * if (stats.totalTokens > 4000) {
659
+ * // Reduzir contexto
660
+ * const smaller = await vg.search('O que é ETP?', { topK: 3 });
661
+ * }
662
+ *
663
+ * // Com string direta
664
+ * const stats2 = await vg.estimateTokens('Texto de contexto...');
665
+ *
666
+ * // Com system prompt customizado
667
+ * const stats3 = await vg.estimateTokens(results, {
668
+ * systemPrompt: 'Você é um especialista jurídico...'
669
+ * });
670
+ * ```
671
+ */
672
+ estimateTokens(content: SearchResult | string, options?: EstimateTokensOptions): Promise<TokenStats>;
694
673
  /**
695
674
  * Converte hits para formato de mensagens de chat
696
675
  */
@@ -701,4 +680,4 @@ declare class VectorGov {
701
680
  private hitsToContext;
702
681
  }
703
682
 
704
- export { type AnthropicTool, type AskMetadata, type AskOptions, type AskResponse, type AuditLog, type AuditLogsOptions, type AuditLogsResponse, type AuditStats, AuthenticationError, type ChatMessage, type Citation, type DeleteResponse, type DocumentSummary, type DocumentsResponse, type EnrichStatus, type FeedbackResponse, type GoogleTool, type IngestStatus, type ListDocumentsOptions, type OpenAITool, RateLimitError, type SearchHit, type SearchMetadata, type SearchMode, type SearchOptions, type SearchResult, type StoreResponseOptions, type StoreResponseResult, type StreamChunk, type SystemPromptStyle, type UploadResponse, VectorGov, type VectorGovConfig, VectorGovError };
683
+ export { type AnthropicTool, type AuditLog, type AuditLogsOptions, type AuditLogsResponse, type AuditStats, AuthenticationError, type ChatMessage, type Citation, type DeleteResponse, type DocumentSummary, type DocumentsResponse, type EnrichStatus, type EstimateTokensOptions, type FeedbackResponse, type GoogleTool, type IngestStatus, type ListDocumentsOptions, type OpenAITool, RateLimitError, type SearchHit, type SearchMetadata, type SearchMode, type SearchOptions, type SearchResult, type StoreResponseOptions, type StoreResponseResult, type SystemPromptStyle, type TokenStats, type UploadResponse, VectorGov, type VectorGovConfig, VectorGovError };
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  var __defProp = Object.defineProperty;
3
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -104,6 +103,9 @@ var TOOL_SCHEMA = {
104
103
  }
105
104
  };
106
105
  var VectorGov = class {
106
+ apiKey;
107
+ baseUrl;
108
+ timeout;
107
109
  constructor(config) {
108
110
  if (!config.apiKey) {
109
111
  throw new AuthenticationError("API key is required");
@@ -221,130 +223,6 @@ var VectorGov = class {
221
223
  toContext: () => this.hitsToContext(hits)
222
224
  };
223
225
  }
224
- /**
225
- * Faz uma pergunta e recebe uma resposta gerada por IA
226
- *
227
- * @param query - Pergunta
228
- * @param options - Opções
229
- * @returns Resposta com citações
230
- */
231
- async ask(query, options = {}) {
232
- const {
233
- topK = 5,
234
- mode = "balanced",
235
- useCache = true,
236
- tipoDocumento,
237
- ano
238
- } = options;
239
- const response = await this.request("/sdk/ask", {
240
- method: "POST",
241
- body: JSON.stringify({
242
- query,
243
- top_k: topK,
244
- mode,
245
- use_cache: useCache,
246
- tipo_documento: tipoDocumento,
247
- ano
248
- })
249
- });
250
- return {
251
- answer: response.data.answer,
252
- citations: response.data.citations.map((c) => ({
253
- text: c.text,
254
- short: c.short,
255
- documentType: c.document_type,
256
- documentNumber: c.document_number,
257
- year: c.year,
258
- article: c.article
259
- })),
260
- confidence: response.data.confidence,
261
- metadata: {
262
- model: response.metadata.model,
263
- latencyMs: response.metadata.latency_ms,
264
- retrievalMs: response.metadata.retrieval_ms,
265
- generationMs: response.metadata.generation_ms,
266
- chunksUsed: response.metadata.chunks_used,
267
- tokens: response.metadata.tokens,
268
- queryHash: response.metadata.query_hash
269
- }
270
- };
271
- }
272
- /**
273
- * Faz uma pergunta com resposta em streaming
274
- *
275
- * @param query - Pergunta do usuário
276
- * @param options - Opções de busca
277
- * @yields StreamChunk com cada parte da resposta
278
- *
279
- * @example
280
- * ```typescript
281
- * for await (const chunk of vg.askStream('O que é ETP?')) {
282
- * if (chunk.type === 'token') {
283
- * process.stdout.write(chunk.content || '');
284
- * } else if (chunk.type === 'complete') {
285
- * console.log(`\n\nFontes: ${chunk.citations?.length} citações`);
286
- * }
287
- * }
288
- * ```
289
- */
290
- async *askStream(query, options = {}) {
291
- const { topK = 5, mode = "balanced" } = options;
292
- const url = `${this.baseUrl}/sdk/ask/stream`;
293
- const response = await fetch(url, {
294
- method: "POST",
295
- headers: {
296
- "Content-Type": "application/json",
297
- "X-API-Key": this.apiKey
298
- },
299
- body: JSON.stringify({
300
- query,
301
- top_k: topK,
302
- mode
303
- })
304
- });
305
- if (!response.ok) {
306
- throw new VectorGovError(`Stream request failed: ${response.status}`);
307
- }
308
- if (!response.body) {
309
- throw new VectorGovError("No response body for streaming");
310
- }
311
- const reader = response.body.getReader();
312
- const decoder = new TextDecoder();
313
- let buffer = "";
314
- try {
315
- while (true) {
316
- const { done, value } = await reader.read();
317
- if (done) break;
318
- buffer += decoder.decode(value, { stream: true });
319
- const lines = buffer.split("\n");
320
- buffer = lines.pop() || "";
321
- for (const line of lines) {
322
- if (line.startsWith("data: ")) {
323
- const data = line.slice(6);
324
- if (data === "[DONE]") return;
325
- try {
326
- const event = JSON.parse(data);
327
- const chunk = {
328
- type: event.type || "token",
329
- content: event.content,
330
- query: event.query,
331
- chunks: event.chunks,
332
- timeMs: event.time_ms,
333
- citations: event.citations,
334
- queryHash: event.query_hash,
335
- message: event.message
336
- };
337
- yield chunk;
338
- if (event.type === "error") return;
339
- } catch {
340
- }
341
- }
342
- }
343
- }
344
- } finally {
345
- reader.releaseLock();
346
- }
347
- }
348
226
  /**
349
227
  * Envia feedback (like/dislike) para uma resposta
350
228
  *
@@ -811,6 +689,71 @@ ${parts.join("\n\n---\n\n")}`;
811
689
  return response.event_types;
812
690
  }
813
691
  // ===========================================================================
692
+ // CONTAGEM DE TOKENS
693
+ // ===========================================================================
694
+ /**
695
+ * Estima a quantidade de tokens que serão usados com um LLM
696
+ *
697
+ * Use para planejar o contexto antes de enviar para seu LLM:
698
+ * - Verificar se cabe no limite do modelo
699
+ * - Calcular custos estimados
700
+ * - Ajustar top_k se necessário
701
+ *
702
+ * @param content - SearchResult ou string de contexto
703
+ * @param options - Opções (systemPrompt customizado, query)
704
+ * @returns Estatísticas de tokens
705
+ *
706
+ * @example
707
+ * ```typescript
708
+ * // Com SearchResult
709
+ * const results = await vg.search('O que é ETP?');
710
+ * const stats = await vg.estimateTokens(results);
711
+ * console.log(`Total de tokens: ${stats.totalTokens}`);
712
+ *
713
+ * if (stats.totalTokens > 4000) {
714
+ * // Reduzir contexto
715
+ * const smaller = await vg.search('O que é ETP?', { topK: 3 });
716
+ * }
717
+ *
718
+ * // Com string direta
719
+ * const stats2 = await vg.estimateTokens('Texto de contexto...');
720
+ *
721
+ * // Com system prompt customizado
722
+ * const stats3 = await vg.estimateTokens(results, {
723
+ * systemPrompt: 'Você é um especialista jurídico...'
724
+ * });
725
+ * ```
726
+ */
727
+ async estimateTokens(content, options = {}) {
728
+ let context;
729
+ let query = options.query || "";
730
+ let hitsCount = 0;
731
+ if (typeof content === "string") {
732
+ context = content;
733
+ } else {
734
+ context = content.toContext();
735
+ hitsCount = content.hits.length;
736
+ }
737
+ const systemPrompt = options.systemPrompt || SYSTEM_PROMPTS.default;
738
+ const response = await this.request("/sdk/tokens", {
739
+ method: "POST",
740
+ body: JSON.stringify({
741
+ context,
742
+ query,
743
+ system_prompt: systemPrompt
744
+ })
745
+ });
746
+ return {
747
+ contextTokens: response.context_tokens,
748
+ systemTokens: response.system_tokens,
749
+ queryTokens: response.query_tokens,
750
+ totalTokens: response.total_tokens,
751
+ hitsCount,
752
+ charCount: response.char_count,
753
+ encoding: response.encoding
754
+ };
755
+ }
756
+ // ===========================================================================
814
757
  // MÉTODOS AUXILIARES
815
758
  // ===========================================================================
816
759
  /**
package/dist/index.mjs CHANGED
@@ -75,6 +75,9 @@ var TOOL_SCHEMA = {
75
75
  }
76
76
  };
77
77
  var VectorGov = class {
78
+ apiKey;
79
+ baseUrl;
80
+ timeout;
78
81
  constructor(config) {
79
82
  if (!config.apiKey) {
80
83
  throw new AuthenticationError("API key is required");
@@ -192,130 +195,6 @@ var VectorGov = class {
192
195
  toContext: () => this.hitsToContext(hits)
193
196
  };
194
197
  }
195
- /**
196
- * Faz uma pergunta e recebe uma resposta gerada por IA
197
- *
198
- * @param query - Pergunta
199
- * @param options - Opções
200
- * @returns Resposta com citações
201
- */
202
- async ask(query, options = {}) {
203
- const {
204
- topK = 5,
205
- mode = "balanced",
206
- useCache = true,
207
- tipoDocumento,
208
- ano
209
- } = options;
210
- const response = await this.request("/sdk/ask", {
211
- method: "POST",
212
- body: JSON.stringify({
213
- query,
214
- top_k: topK,
215
- mode,
216
- use_cache: useCache,
217
- tipo_documento: tipoDocumento,
218
- ano
219
- })
220
- });
221
- return {
222
- answer: response.data.answer,
223
- citations: response.data.citations.map((c) => ({
224
- text: c.text,
225
- short: c.short,
226
- documentType: c.document_type,
227
- documentNumber: c.document_number,
228
- year: c.year,
229
- article: c.article
230
- })),
231
- confidence: response.data.confidence,
232
- metadata: {
233
- model: response.metadata.model,
234
- latencyMs: response.metadata.latency_ms,
235
- retrievalMs: response.metadata.retrieval_ms,
236
- generationMs: response.metadata.generation_ms,
237
- chunksUsed: response.metadata.chunks_used,
238
- tokens: response.metadata.tokens,
239
- queryHash: response.metadata.query_hash
240
- }
241
- };
242
- }
243
- /**
244
- * Faz uma pergunta com resposta em streaming
245
- *
246
- * @param query - Pergunta do usuário
247
- * @param options - Opções de busca
248
- * @yields StreamChunk com cada parte da resposta
249
- *
250
- * @example
251
- * ```typescript
252
- * for await (const chunk of vg.askStream('O que é ETP?')) {
253
- * if (chunk.type === 'token') {
254
- * process.stdout.write(chunk.content || '');
255
- * } else if (chunk.type === 'complete') {
256
- * console.log(`\n\nFontes: ${chunk.citations?.length} citações`);
257
- * }
258
- * }
259
- * ```
260
- */
261
- async *askStream(query, options = {}) {
262
- const { topK = 5, mode = "balanced" } = options;
263
- const url = `${this.baseUrl}/sdk/ask/stream`;
264
- const response = await fetch(url, {
265
- method: "POST",
266
- headers: {
267
- "Content-Type": "application/json",
268
- "X-API-Key": this.apiKey
269
- },
270
- body: JSON.stringify({
271
- query,
272
- top_k: topK,
273
- mode
274
- })
275
- });
276
- if (!response.ok) {
277
- throw new VectorGovError(`Stream request failed: ${response.status}`);
278
- }
279
- if (!response.body) {
280
- throw new VectorGovError("No response body for streaming");
281
- }
282
- const reader = response.body.getReader();
283
- const decoder = new TextDecoder();
284
- let buffer = "";
285
- try {
286
- while (true) {
287
- const { done, value } = await reader.read();
288
- if (done) break;
289
- buffer += decoder.decode(value, { stream: true });
290
- const lines = buffer.split("\n");
291
- buffer = lines.pop() || "";
292
- for (const line of lines) {
293
- if (line.startsWith("data: ")) {
294
- const data = line.slice(6);
295
- if (data === "[DONE]") return;
296
- try {
297
- const event = JSON.parse(data);
298
- const chunk = {
299
- type: event.type || "token",
300
- content: event.content,
301
- query: event.query,
302
- chunks: event.chunks,
303
- timeMs: event.time_ms,
304
- citations: event.citations,
305
- queryHash: event.query_hash,
306
- message: event.message
307
- };
308
- yield chunk;
309
- if (event.type === "error") return;
310
- } catch {
311
- }
312
- }
313
- }
314
- }
315
- } finally {
316
- reader.releaseLock();
317
- }
318
- }
319
198
  /**
320
199
  * Envia feedback (like/dislike) para uma resposta
321
200
  *
@@ -782,6 +661,71 @@ ${parts.join("\n\n---\n\n")}`;
782
661
  return response.event_types;
783
662
  }
784
663
  // ===========================================================================
664
+ // CONTAGEM DE TOKENS
665
+ // ===========================================================================
666
+ /**
667
+ * Estima a quantidade de tokens que serão usados com um LLM
668
+ *
669
+ * Use para planejar o contexto antes de enviar para seu LLM:
670
+ * - Verificar se cabe no limite do modelo
671
+ * - Calcular custos estimados
672
+ * - Ajustar top_k se necessário
673
+ *
674
+ * @param content - SearchResult ou string de contexto
675
+ * @param options - Opções (systemPrompt customizado, query)
676
+ * @returns Estatísticas de tokens
677
+ *
678
+ * @example
679
+ * ```typescript
680
+ * // Com SearchResult
681
+ * const results = await vg.search('O que é ETP?');
682
+ * const stats = await vg.estimateTokens(results);
683
+ * console.log(`Total de tokens: ${stats.totalTokens}`);
684
+ *
685
+ * if (stats.totalTokens > 4000) {
686
+ * // Reduzir contexto
687
+ * const smaller = await vg.search('O que é ETP?', { topK: 3 });
688
+ * }
689
+ *
690
+ * // Com string direta
691
+ * const stats2 = await vg.estimateTokens('Texto de contexto...');
692
+ *
693
+ * // Com system prompt customizado
694
+ * const stats3 = await vg.estimateTokens(results, {
695
+ * systemPrompt: 'Você é um especialista jurídico...'
696
+ * });
697
+ * ```
698
+ */
699
+ async estimateTokens(content, options = {}) {
700
+ let context;
701
+ let query = options.query || "";
702
+ let hitsCount = 0;
703
+ if (typeof content === "string") {
704
+ context = content;
705
+ } else {
706
+ context = content.toContext();
707
+ hitsCount = content.hits.length;
708
+ }
709
+ const systemPrompt = options.systemPrompt || SYSTEM_PROMPTS.default;
710
+ const response = await this.request("/sdk/tokens", {
711
+ method: "POST",
712
+ body: JSON.stringify({
713
+ context,
714
+ query,
715
+ system_prompt: systemPrompt
716
+ })
717
+ });
718
+ return {
719
+ contextTokens: response.context_tokens,
720
+ systemTokens: response.system_tokens,
721
+ queryTokens: response.query_tokens,
722
+ totalTokens: response.total_tokens,
723
+ hitsCount,
724
+ charCount: response.char_count,
725
+ encoding: response.encoding
726
+ };
727
+ }
728
+ // ===========================================================================
785
729
  // MÉTODOS AUXILIARES
786
730
  // ===========================================================================
787
731
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vectorgov",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "SDK TypeScript para a API VectorGov - Busca semântica em legislação brasileira",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",