wauldo 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,12 +28,35 @@
28
28
 
29
29
  ---
30
30
 
31
- ## Quickstart (30 seconds)
31
+ ## Try it locally (no server needed)
32
32
 
33
33
  ```bash
34
34
  npm install wauldo
35
35
  ```
36
36
 
37
+ ```typescript
38
+ import { MockHttpClient } from 'wauldo';
39
+
40
+ const client = new MockHttpClient();
41
+
42
+ // Upload, query, fact-check — all offline
43
+ await client.ragUpload('Refund policy allows returns within 60 days.', 'policy.txt');
44
+ const result = await client.ragQuery('What is the refund policy?');
45
+ console.log(result.answer); // "Mock answer for: What is the refund policy?"
46
+
47
+ const check = await client.factCheck({
48
+ text: 'Returns accepted within 30 days.',
49
+ source_context: 'Refund policy allows returns within 60 days.',
50
+ });
51
+ console.log(check.verdict); // "rejected"
52
+ ```
53
+
54
+ Run the full quickstart: `npx tsx examples/quickstart.ts`
55
+
56
+ ---
57
+
58
+ ## Quickstart with real API
59
+
37
60
  ```typescript
38
61
  import { HttpClient } from 'wauldo';
39
62
 
@@ -150,6 +173,7 @@ const followUp = await conv.say('Give me an example');
150
173
  - **Pre-generation fact extraction** — numbers, dates, limits injected as constraints
151
174
  - **Post-generation grounding check** — every answer verified against sources
152
175
  - **Citation validation** — detects phantom references
176
+ - **Analytics & Insights** — track token savings, cache performance, cost per hour, and per-tenant traffic
153
177
  - **Fact-check API** — verify any claim against any source (3 modes)
154
178
  - **Native PDF/DOCX upload** — server-side extraction with quality scoring
155
179
  - **Smart model routing** — auto-selects cheapest model that meets quality
@@ -194,7 +218,9 @@ Free tier (300 req/month): [RapidAPI](https://rapidapi.com/binnewzzin/api/smart-
194
218
 
195
219
  ## Contributing
196
220
 
197
- PRs welcome. Check the [good first issues](https://github.com/wauldo/wauldo-sdk-js/labels/good%20first%20issue).
221
+ PRs welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup instructions and guidelines.
222
+
223
+ Check the [good first issues](https://github.com/wauldo/wauldo-sdk-js/labels/good%20first%20issue) to get started.
198
224
 
199
225
  ## License
200
226
 
package/dist/index.d.mts CHANGED
@@ -277,6 +277,22 @@ interface RagUploadResponse {
277
277
  document_id: string;
278
278
  chunks_count: number;
279
279
  }
280
+ interface DocumentQuality {
281
+ score: number;
282
+ label: string;
283
+ word_count: number;
284
+ line_density: number;
285
+ avg_line_length: number;
286
+ paragraph_count: number;
287
+ }
288
+ interface UploadFileResponse {
289
+ document_id: string;
290
+ chunks_count: number;
291
+ indexed_at: string;
292
+ content_type: string;
293
+ trace_id: string;
294
+ quality?: DocumentQuality;
295
+ }
280
296
  interface RagSource {
281
297
  document_id: string;
282
298
  content: string;
@@ -312,6 +328,110 @@ interface RagQueryResponse {
312
328
  interface OrchestratorResponse {
313
329
  final_output: string;
314
330
  }
331
+ interface FactCheckRequest {
332
+ text: string;
333
+ source_context: string;
334
+ mode?: 'lexical' | 'hybrid' | 'semantic';
335
+ }
336
+ interface ClaimResult {
337
+ text: string;
338
+ claim_type: string;
339
+ supported: boolean;
340
+ confidence: number;
341
+ confidence_label: string;
342
+ verdict: string;
343
+ action: string;
344
+ reason?: string | null;
345
+ evidence?: string | null;
346
+ }
347
+ interface FactCheckResponse {
348
+ verdict: string;
349
+ action: string;
350
+ hallucination_rate: number;
351
+ mode: string;
352
+ total_claims: number;
353
+ supported_claims: number;
354
+ confidence: number;
355
+ claims: ClaimResult[];
356
+ mode_warning?: string | null;
357
+ processing_time_ms: number;
358
+ }
359
+ interface SourceChunk {
360
+ name: string;
361
+ content: string;
362
+ }
363
+ interface CitationDetail {
364
+ citation: string;
365
+ source_name: string;
366
+ is_valid: boolean;
367
+ }
368
+ interface VerifyCitationRequest {
369
+ text: string;
370
+ sources?: SourceChunk[];
371
+ threshold?: number;
372
+ }
373
+ interface VerifyCitationResponse {
374
+ citation_ratio: number;
375
+ has_sufficient_citations: boolean;
376
+ sentence_count: number;
377
+ citation_count: number;
378
+ uncited_sentences: string[];
379
+ citations?: CitationDetail[];
380
+ phantom_count?: number;
381
+ processing_time_ms: number;
382
+ }
383
+ interface GuardResult {
384
+ safe: boolean;
385
+ verdict: string;
386
+ action: string;
387
+ reason: string | null;
388
+ confidence: number;
389
+ }
390
+ interface InsightsResponse {
391
+ tig_key: string;
392
+ total_requests: number;
393
+ intelligence_requests: number;
394
+ fallback_requests: number;
395
+ tokens: {
396
+ baseline_total: number;
397
+ real_total: number;
398
+ saved_total: number;
399
+ saved_percent_avg: number;
400
+ };
401
+ cost: {
402
+ estimated_usd_saved: number;
403
+ };
404
+ }
405
+ interface AnalyticsResponse {
406
+ cache: {
407
+ total_requests: number;
408
+ cache_hit_rate: number;
409
+ avg_latency_ms: number;
410
+ p95_latency_ms: number;
411
+ };
412
+ tokens: {
413
+ total_baseline: number;
414
+ total_real: number;
415
+ total_saved: number;
416
+ avg_savings_percent: number;
417
+ };
418
+ uptime_secs: number;
419
+ }
420
+ interface TrafficSummary {
421
+ total_requests_today: number;
422
+ total_tokens_today: number;
423
+ top_tenants: Array<{
424
+ tenant_id: string;
425
+ requests_today: number;
426
+ tokens_used: number;
427
+ success_rate: number;
428
+ avg_latency_ms: number;
429
+ }>;
430
+ error_rate: number;
431
+ avg_latency_ms: number;
432
+ p95_latency_ms: number;
433
+ uptime_secs: number;
434
+ }
315
435
  /** Minimal interface required by Conversation — implemented by both HttpClient and MockHttpClient */
316
436
  interface ChatClientLike {
317
437
  chat(request: ChatRequest, options?: RequestOptions): Promise<ChatResponse>;
@@ -435,6 +555,19 @@ declare class HttpClient {
435
555
  * @returns Upload confirmation with document_id and chunks_count
436
556
  */
437
557
  ragUpload(content: string, filename?: string, options?: RequestOptions): Promise<RagUploadResponse>;
558
+ /**
559
+ * POST /v1/upload-file — Upload a file (PDF, DOCX, text, image) for RAG indexing.
560
+ *
561
+ * @param file - File content as Buffer/Uint8Array
562
+ * @param filename - The filename (determines content type detection)
563
+ * @param options - Optional title, tags, timeoutMs
564
+ * @returns Upload confirmation with quality scoring
565
+ */
566
+ uploadFile(file: Uint8Array | Buffer, filename: string, options?: {
567
+ title?: string;
568
+ tags?: string;
569
+ timeoutMs?: number;
570
+ }): Promise<UploadFileResponse>;
438
571
  /** POST /v1/query — Query RAG knowledge base */
439
572
  ragQuery(query: string, topK?: number, options?: {
440
573
  debug?: boolean;
@@ -469,6 +602,53 @@ declare class HttpClient {
469
602
  orchestrate(prompt: string): Promise<OrchestratorResponse>;
470
603
  /** POST /v1/orchestrator/parallel — Run all 4 specialists in parallel */
471
604
  orchestrateParallel(prompt: string): Promise<OrchestratorResponse>;
605
+ /**
606
+ * POST /v1/fact-check — Verify claims against source context.
607
+ *
608
+ * @param request - Text and source context to verify
609
+ * @returns FactCheckResponse with verdict, action, and per-claim results
610
+ *
611
+ * @example
612
+ * ```typescript
613
+ * const result = await client.factCheck({
614
+ * text: 'Returns accepted within 60 days.',
615
+ * source_context: 'Our policy allows returns within 14 days.',
616
+ * mode: 'lexical',
617
+ * });
618
+ * console.log(result.verdict); // "rejected"
619
+ * ```
620
+ */
621
+ factCheck(request: FactCheckRequest): Promise<FactCheckResponse>;
622
+ /**
623
+ * POST /v1/verify — Verify citations in AI-generated text.
624
+ *
625
+ * @example
626
+ * ```ts
627
+ * const result = await client.verifyCitation({
628
+ * text: 'Rust was released in 2010 [Source: rust_book].',
629
+ * sources: [{ name: 'rust_book', content: 'Rust was first released in 2010.' }],
630
+ * });
631
+ * console.log(result.phantom_count); // 0
632
+ * ```
633
+ */
634
+ verifyCitation(request: VerifyCitationRequest): Promise<VerifyCitationResponse>;
635
+ /**
636
+ * Verify an LLM output against a source document.
637
+ * Convenience wrapper around factCheck(). Returns a simple safe/unsafe result.
638
+ */
639
+ guard(text: string, source: string, mode?: 'lexical' | 'hybrid' | 'semantic'): Promise<GuardResult>;
640
+ /**
641
+ * GET /v1/insights — ROI metrics for your API key
642
+ */
643
+ getInsights(): Promise<InsightsResponse>;
644
+ /**
645
+ * GET /v1/analytics — Usage analytics and cache performance
646
+ */
647
+ getAnalytics(minutes?: number): Promise<AnalyticsResponse>;
648
+ /**
649
+ * GET /v1/analytics/traffic — Per-tenant traffic monitoring
650
+ */
651
+ getAnalyticsTraffic(): Promise<TrafficSummary>;
472
652
  }
473
653
 
474
654
  /**
@@ -539,6 +719,17 @@ declare class MockHttpClient {
539
719
  system?: string;
540
720
  model?: string;
541
721
  }): Conversation;
722
+ uploadFile(_file: Uint8Array | Buffer, filename: string, options?: {
723
+ title?: string;
724
+ tags?: string;
725
+ timeoutMs?: number;
726
+ }): Promise<UploadFileResponse>;
727
+ factCheck(request: FactCheckRequest): Promise<FactCheckResponse>;
728
+ guard(text: string, source: string, mode?: string): Promise<GuardResult>;
729
+ verifyCitation(request: VerifyCitationRequest): Promise<VerifyCitationResponse>;
730
+ getInsights(): Promise<InsightsResponse>;
731
+ getAnalytics(minutes?: number): Promise<AnalyticsResponse>;
732
+ getAnalyticsTraffic(): Promise<TrafficSummary>;
542
733
  ragAsk(question: string, text: string, source?: string): Promise<string>;
543
734
  private record;
544
735
  }
@@ -589,4 +780,4 @@ declare class ToolNotFoundError extends WauldoError {
589
780
  constructor(toolName: string);
590
781
  }
591
782
 
592
- export { AgentClient, type CallToolResponse, type ChatChoice, type ChatClientLike, type ChatMessage, type ChatRequest, type ChatResponse, type ChatUsage, type Chunk, type ChunkResult, type ClientOptions, type Concept, type ConceptResult, ConnectionError, Conversation, type DetailLevel, type EmbeddingData, type EmbeddingResponse, type EmbeddingUsage, type GraphNode, HttpClient, type HttpClientConfig, type KnowledgeGraphResult, type LogLevel, MockHttpClient, type ModelInfo, type ModelList, type OrchestratorResponse, type PlanOptions, type PlanResult, type PlanStep, type RagAuditInfo, type RagQueryResponse, type RagSource, type RagUploadResponse, type ReasoningOptions, type ReasoningResult, type RequestOptions, type RetrievalResult, ServerError, type SourceType, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, ValidationError, WauldoError, chatContent };
783
+ export { AgentClient, type AnalyticsResponse, type CallToolResponse, type ChatChoice, type ChatClientLike, type ChatMessage, type ChatRequest, type ChatResponse, type ChatUsage, type Chunk, type ChunkResult, type CitationDetail, type ClaimResult, type ClientOptions, type Concept, type ConceptResult, ConnectionError, Conversation, type DetailLevel, type DocumentQuality, type EmbeddingData, type EmbeddingResponse, type EmbeddingUsage, type FactCheckRequest, type FactCheckResponse, type GraphNode, type GuardResult, HttpClient, type HttpClientConfig, type InsightsResponse, type KnowledgeGraphResult, type LogLevel, MockHttpClient, type ModelInfo, type ModelList, type OrchestratorResponse, type PlanOptions, type PlanResult, type PlanStep, type RagAuditInfo, type RagQueryResponse, type RagSource, type RagUploadResponse, type ReasoningOptions, type ReasoningResult, type RequestOptions, type RetrievalResult, ServerError, type SourceChunk, type SourceType, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, type TrafficSummary, type UploadFileResponse, ValidationError, type VerifyCitationRequest, type VerifyCitationResponse, WauldoError, chatContent };
package/dist/index.d.ts CHANGED
@@ -277,6 +277,22 @@ interface RagUploadResponse {
277
277
  document_id: string;
278
278
  chunks_count: number;
279
279
  }
280
+ interface DocumentQuality {
281
+ score: number;
282
+ label: string;
283
+ word_count: number;
284
+ line_density: number;
285
+ avg_line_length: number;
286
+ paragraph_count: number;
287
+ }
288
+ interface UploadFileResponse {
289
+ document_id: string;
290
+ chunks_count: number;
291
+ indexed_at: string;
292
+ content_type: string;
293
+ trace_id: string;
294
+ quality?: DocumentQuality;
295
+ }
280
296
  interface RagSource {
281
297
  document_id: string;
282
298
  content: string;
@@ -312,6 +328,110 @@ interface RagQueryResponse {
312
328
  interface OrchestratorResponse {
313
329
  final_output: string;
314
330
  }
331
+ interface FactCheckRequest {
332
+ text: string;
333
+ source_context: string;
334
+ mode?: 'lexical' | 'hybrid' | 'semantic';
335
+ }
336
+ interface ClaimResult {
337
+ text: string;
338
+ claim_type: string;
339
+ supported: boolean;
340
+ confidence: number;
341
+ confidence_label: string;
342
+ verdict: string;
343
+ action: string;
344
+ reason?: string | null;
345
+ evidence?: string | null;
346
+ }
347
+ interface FactCheckResponse {
348
+ verdict: string;
349
+ action: string;
350
+ hallucination_rate: number;
351
+ mode: string;
352
+ total_claims: number;
353
+ supported_claims: number;
354
+ confidence: number;
355
+ claims: ClaimResult[];
356
+ mode_warning?: string | null;
357
+ processing_time_ms: number;
358
+ }
359
+ interface SourceChunk {
360
+ name: string;
361
+ content: string;
362
+ }
363
+ interface CitationDetail {
364
+ citation: string;
365
+ source_name: string;
366
+ is_valid: boolean;
367
+ }
368
+ interface VerifyCitationRequest {
369
+ text: string;
370
+ sources?: SourceChunk[];
371
+ threshold?: number;
372
+ }
373
+ interface VerifyCitationResponse {
374
+ citation_ratio: number;
375
+ has_sufficient_citations: boolean;
376
+ sentence_count: number;
377
+ citation_count: number;
378
+ uncited_sentences: string[];
379
+ citations?: CitationDetail[];
380
+ phantom_count?: number;
381
+ processing_time_ms: number;
382
+ }
383
+ interface GuardResult {
384
+ safe: boolean;
385
+ verdict: string;
386
+ action: string;
387
+ reason: string | null;
388
+ confidence: number;
389
+ }
390
+ interface InsightsResponse {
391
+ tig_key: string;
392
+ total_requests: number;
393
+ intelligence_requests: number;
394
+ fallback_requests: number;
395
+ tokens: {
396
+ baseline_total: number;
397
+ real_total: number;
398
+ saved_total: number;
399
+ saved_percent_avg: number;
400
+ };
401
+ cost: {
402
+ estimated_usd_saved: number;
403
+ };
404
+ }
405
+ interface AnalyticsResponse {
406
+ cache: {
407
+ total_requests: number;
408
+ cache_hit_rate: number;
409
+ avg_latency_ms: number;
410
+ p95_latency_ms: number;
411
+ };
412
+ tokens: {
413
+ total_baseline: number;
414
+ total_real: number;
415
+ total_saved: number;
416
+ avg_savings_percent: number;
417
+ };
418
+ uptime_secs: number;
419
+ }
420
+ interface TrafficSummary {
421
+ total_requests_today: number;
422
+ total_tokens_today: number;
423
+ top_tenants: Array<{
424
+ tenant_id: string;
425
+ requests_today: number;
426
+ tokens_used: number;
427
+ success_rate: number;
428
+ avg_latency_ms: number;
429
+ }>;
430
+ error_rate: number;
431
+ avg_latency_ms: number;
432
+ p95_latency_ms: number;
433
+ uptime_secs: number;
434
+ }
315
435
  /** Minimal interface required by Conversation — implemented by both HttpClient and MockHttpClient */
316
436
  interface ChatClientLike {
317
437
  chat(request: ChatRequest, options?: RequestOptions): Promise<ChatResponse>;
@@ -435,6 +555,19 @@ declare class HttpClient {
435
555
  * @returns Upload confirmation with document_id and chunks_count
436
556
  */
437
557
  ragUpload(content: string, filename?: string, options?: RequestOptions): Promise<RagUploadResponse>;
558
+ /**
559
+ * POST /v1/upload-file — Upload a file (PDF, DOCX, text, image) for RAG indexing.
560
+ *
561
+ * @param file - File content as Buffer/Uint8Array
562
+ * @param filename - The filename (determines content type detection)
563
+ * @param options - Optional title, tags, timeoutMs
564
+ * @returns Upload confirmation with quality scoring
565
+ */
566
+ uploadFile(file: Uint8Array | Buffer, filename: string, options?: {
567
+ title?: string;
568
+ tags?: string;
569
+ timeoutMs?: number;
570
+ }): Promise<UploadFileResponse>;
438
571
  /** POST /v1/query — Query RAG knowledge base */
439
572
  ragQuery(query: string, topK?: number, options?: {
440
573
  debug?: boolean;
@@ -469,6 +602,53 @@ declare class HttpClient {
469
602
  orchestrate(prompt: string): Promise<OrchestratorResponse>;
470
603
  /** POST /v1/orchestrator/parallel — Run all 4 specialists in parallel */
471
604
  orchestrateParallel(prompt: string): Promise<OrchestratorResponse>;
605
+ /**
606
+ * POST /v1/fact-check — Verify claims against source context.
607
+ *
608
+ * @param request - Text and source context to verify
609
+ * @returns FactCheckResponse with verdict, action, and per-claim results
610
+ *
611
+ * @example
612
+ * ```typescript
613
+ * const result = await client.factCheck({
614
+ * text: 'Returns accepted within 60 days.',
615
+ * source_context: 'Our policy allows returns within 14 days.',
616
+ * mode: 'lexical',
617
+ * });
618
+ * console.log(result.verdict); // "rejected"
619
+ * ```
620
+ */
621
+ factCheck(request: FactCheckRequest): Promise<FactCheckResponse>;
622
+ /**
623
+ * POST /v1/verify — Verify citations in AI-generated text.
624
+ *
625
+ * @example
626
+ * ```ts
627
+ * const result = await client.verifyCitation({
628
+ * text: 'Rust was released in 2010 [Source: rust_book].',
629
+ * sources: [{ name: 'rust_book', content: 'Rust was first released in 2010.' }],
630
+ * });
631
+ * console.log(result.phantom_count); // 0
632
+ * ```
633
+ */
634
+ verifyCitation(request: VerifyCitationRequest): Promise<VerifyCitationResponse>;
635
+ /**
636
+ * Verify an LLM output against a source document.
637
+ * Convenience wrapper around factCheck(). Returns a simple safe/unsafe result.
638
+ */
639
+ guard(text: string, source: string, mode?: 'lexical' | 'hybrid' | 'semantic'): Promise<GuardResult>;
640
+ /**
641
+ * GET /v1/insights — ROI metrics for your API key
642
+ */
643
+ getInsights(): Promise<InsightsResponse>;
644
+ /**
645
+ * GET /v1/analytics — Usage analytics and cache performance
646
+ */
647
+ getAnalytics(minutes?: number): Promise<AnalyticsResponse>;
648
+ /**
649
+ * GET /v1/analytics/traffic — Per-tenant traffic monitoring
650
+ */
651
+ getAnalyticsTraffic(): Promise<TrafficSummary>;
472
652
  }
473
653
 
474
654
  /**
@@ -539,6 +719,17 @@ declare class MockHttpClient {
539
719
  system?: string;
540
720
  model?: string;
541
721
  }): Conversation;
722
+ uploadFile(_file: Uint8Array | Buffer, filename: string, options?: {
723
+ title?: string;
724
+ tags?: string;
725
+ timeoutMs?: number;
726
+ }): Promise<UploadFileResponse>;
727
+ factCheck(request: FactCheckRequest): Promise<FactCheckResponse>;
728
+ guard(text: string, source: string, mode?: string): Promise<GuardResult>;
729
+ verifyCitation(request: VerifyCitationRequest): Promise<VerifyCitationResponse>;
730
+ getInsights(): Promise<InsightsResponse>;
731
+ getAnalytics(minutes?: number): Promise<AnalyticsResponse>;
732
+ getAnalyticsTraffic(): Promise<TrafficSummary>;
542
733
  ragAsk(question: string, text: string, source?: string): Promise<string>;
543
734
  private record;
544
735
  }
@@ -589,4 +780,4 @@ declare class ToolNotFoundError extends WauldoError {
589
780
  constructor(toolName: string);
590
781
  }
591
782
 
592
- export { AgentClient, type CallToolResponse, type ChatChoice, type ChatClientLike, type ChatMessage, type ChatRequest, type ChatResponse, type ChatUsage, type Chunk, type ChunkResult, type ClientOptions, type Concept, type ConceptResult, ConnectionError, Conversation, type DetailLevel, type EmbeddingData, type EmbeddingResponse, type EmbeddingUsage, type GraphNode, HttpClient, type HttpClientConfig, type KnowledgeGraphResult, type LogLevel, MockHttpClient, type ModelInfo, type ModelList, type OrchestratorResponse, type PlanOptions, type PlanResult, type PlanStep, type RagAuditInfo, type RagQueryResponse, type RagSource, type RagUploadResponse, type ReasoningOptions, type ReasoningResult, type RequestOptions, type RetrievalResult, ServerError, type SourceType, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, ValidationError, WauldoError, chatContent };
783
+ export { AgentClient, type AnalyticsResponse, type CallToolResponse, type ChatChoice, type ChatClientLike, type ChatMessage, type ChatRequest, type ChatResponse, type ChatUsage, type Chunk, type ChunkResult, type CitationDetail, type ClaimResult, type ClientOptions, type Concept, type ConceptResult, ConnectionError, Conversation, type DetailLevel, type DocumentQuality, type EmbeddingData, type EmbeddingResponse, type EmbeddingUsage, type FactCheckRequest, type FactCheckResponse, type GraphNode, type GuardResult, HttpClient, type HttpClientConfig, type InsightsResponse, type KnowledgeGraphResult, type LogLevel, MockHttpClient, type ModelInfo, type ModelList, type OrchestratorResponse, type PlanOptions, type PlanResult, type PlanStep, type RagAuditInfo, type RagQueryResponse, type RagSource, type RagUploadResponse, type ReasoningOptions, type ReasoningResult, type RequestOptions, type RetrievalResult, ServerError, type SourceChunk, type SourceType, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, type TrafficSummary, type UploadFileResponse, ValidationError, type VerifyCitationRequest, type VerifyCitationResponse, WauldoError, chatContent };
package/dist/index.js CHANGED
@@ -900,6 +900,16 @@ async function* parseSSEStream(body) {
900
900
  }
901
901
 
902
902
  // src/http_client.ts
903
+ function concatUint8Arrays(arrays) {
904
+ const total = arrays.reduce((n, a) => n + a.length, 0);
905
+ const result = new Uint8Array(total);
906
+ let offset = 0;
907
+ for (const a of arrays) {
908
+ result.set(a, offset);
909
+ offset += a.length;
910
+ }
911
+ return result;
912
+ }
903
913
  function validateResponse(data, typeName) {
904
914
  if (data === null || data === void 0) {
905
915
  throw new ServerError(`Invalid ${typeName}: response is null`, 0);
@@ -1034,6 +1044,51 @@ var HttpClient = class {
1034
1044
  );
1035
1045
  return validateResponse(data, "RagUploadResponse");
1036
1046
  }
1047
+ /**
1048
+ * POST /v1/upload-file — Upload a file (PDF, DOCX, text, image) for RAG indexing.
1049
+ *
1050
+ * @param file - File content as Buffer/Uint8Array
1051
+ * @param filename - The filename (determines content type detection)
1052
+ * @param options - Optional title, tags, timeoutMs
1053
+ * @returns Upload confirmation with quality scoring
1054
+ */
1055
+ async uploadFile(file, filename, options) {
1056
+ const boundary = "----WauldoSDKBoundary";
1057
+ const parts = [];
1058
+ const enc = new TextEncoder();
1059
+ parts.push(enc.encode(`--${boundary}\r
1060
+ Content-Disposition: form-data; name="file"; filename="${filename}"\r
1061
+ Content-Type: application/octet-stream\r
1062
+ \r
1063
+ `));
1064
+ parts.push(file instanceof Uint8Array ? file : new Uint8Array(file));
1065
+ parts.push(enc.encode("\r\n"));
1066
+ if (options?.title) {
1067
+ parts.push(enc.encode(`--${boundary}\r
1068
+ Content-Disposition: form-data; name="title"\r
1069
+ \r
1070
+ ${options.title}\r
1071
+ `));
1072
+ }
1073
+ if (options?.tags) {
1074
+ parts.push(enc.encode(`--${boundary}\r
1075
+ Content-Disposition: form-data; name="tags"\r
1076
+ \r
1077
+ ${options.tags}\r
1078
+ `));
1079
+ }
1080
+ parts.push(enc.encode(`--${boundary}--\r
1081
+ `));
1082
+ const body = concatUint8Arrays(parts);
1083
+ const data = await fetchWithRetry(
1084
+ { ...this.retryConfig, headers: { ...this.retryConfig.headers, "Content-Type": `multipart/form-data; boundary=${boundary}` } },
1085
+ "POST",
1086
+ "/v1/upload-file",
1087
+ body,
1088
+ options?.timeoutMs
1089
+ );
1090
+ return validateResponse(data, "UploadFileResponse");
1091
+ }
1037
1092
  /** POST /v1/query — Query RAG knowledge base */
1038
1093
  async ragQuery(query, topK = 5, options) {
1039
1094
  const body = { query, top_k: topK };
@@ -1097,6 +1152,102 @@ var HttpClient = class {
1097
1152
  );
1098
1153
  return validateResponse(data, "OrchestratorResponse");
1099
1154
  }
1155
+ // ── Fact-Check endpoints ──────────────────────────────────────────────
1156
+ /**
1157
+ * POST /v1/fact-check — Verify claims against source context.
1158
+ *
1159
+ * @param request - Text and source context to verify
1160
+ * @returns FactCheckResponse with verdict, action, and per-claim results
1161
+ *
1162
+ * @example
1163
+ * ```typescript
1164
+ * const result = await client.factCheck({
1165
+ * text: 'Returns accepted within 60 days.',
1166
+ * source_context: 'Our policy allows returns within 14 days.',
1167
+ * mode: 'lexical',
1168
+ * });
1169
+ * console.log(result.verdict); // "rejected"
1170
+ * ```
1171
+ */
1172
+ async factCheck(request) {
1173
+ const data = await fetchWithRetry(
1174
+ this.retryConfig,
1175
+ "POST",
1176
+ "/v1/fact-check",
1177
+ request
1178
+ );
1179
+ return validateResponse(data, "FactCheckResponse");
1180
+ }
1181
+ /**
1182
+ * POST /v1/verify — Verify citations in AI-generated text.
1183
+ *
1184
+ * @example
1185
+ * ```ts
1186
+ * const result = await client.verifyCitation({
1187
+ * text: 'Rust was released in 2010 [Source: rust_book].',
1188
+ * sources: [{ name: 'rust_book', content: 'Rust was first released in 2010.' }],
1189
+ * });
1190
+ * console.log(result.phantom_count); // 0
1191
+ * ```
1192
+ */
1193
+ async verifyCitation(request) {
1194
+ const data = await fetchWithRetry(
1195
+ this.retryConfig,
1196
+ "POST",
1197
+ "/v1/verify",
1198
+ request
1199
+ );
1200
+ return validateResponse(data, "VerifyCitationResponse");
1201
+ }
1202
+ /**
1203
+ * Verify an LLM output against a source document.
1204
+ * Convenience wrapper around factCheck(). Returns a simple safe/unsafe result.
1205
+ */
1206
+ async guard(text, source, mode = "lexical") {
1207
+ const result = await this.factCheck({ text, source_context: source, mode });
1208
+ const claim = result.claims?.[0];
1209
+ return {
1210
+ safe: claim?.verdict === "verified",
1211
+ verdict: claim?.verdict ?? "rejected",
1212
+ action: claim?.action ?? "block",
1213
+ reason: claim?.reason ?? "no_claims",
1214
+ confidence: claim?.confidence ?? 0
1215
+ };
1216
+ }
1217
+ // ── Analytics & Insights endpoints ───────────────────────────────────
1218
+ /**
1219
+ * GET /v1/insights — ROI metrics for your API key
1220
+ */
1221
+ async getInsights() {
1222
+ const data = await fetchWithRetry(
1223
+ this.retryConfig,
1224
+ "GET",
1225
+ "/v1/insights"
1226
+ );
1227
+ return validateResponse(data, "InsightsResponse");
1228
+ }
1229
+ /**
1230
+ * GET /v1/analytics — Usage analytics and cache performance
1231
+ */
1232
+ async getAnalytics(minutes = 60) {
1233
+ const data = await fetchWithRetry(
1234
+ this.retryConfig,
1235
+ "GET",
1236
+ `/v1/analytics?minutes=${minutes}`
1237
+ );
1238
+ return validateResponse(data, "AnalyticsResponse");
1239
+ }
1240
+ /**
1241
+ * GET /v1/analytics/traffic — Per-tenant traffic monitoring
1242
+ */
1243
+ async getAnalyticsTraffic() {
1244
+ const data = await fetchWithRetry(
1245
+ this.retryConfig,
1246
+ "GET",
1247
+ "/v1/analytics/traffic"
1248
+ );
1249
+ return validateResponse(data, "TrafficSummary");
1250
+ }
1100
1251
  };
1101
1252
 
1102
1253
  // src/mock_client.ts
@@ -1200,6 +1351,132 @@ var MockHttpClient = class {
1200
1351
  this.record("conversation", options);
1201
1352
  return new Conversation(this, options);
1202
1353
  }
1354
+ async uploadFile(_file, filename, options) {
1355
+ this.record("uploadFile", filename, options);
1356
+ return {
1357
+ document_id: "mock-doc-file-1",
1358
+ chunks_count: 5,
1359
+ indexed_at: (/* @__PURE__ */ new Date()).toISOString(),
1360
+ content_type: "application/pdf",
1361
+ trace_id: "mock-trace-1",
1362
+ quality: {
1363
+ score: 0.85,
1364
+ label: "good",
1365
+ word_count: 1200,
1366
+ line_density: 8.5,
1367
+ avg_line_length: 72,
1368
+ paragraph_count: 15
1369
+ }
1370
+ };
1371
+ }
1372
+ async factCheck(request) {
1373
+ this.record("factCheck", request);
1374
+ const hasConflict = request.text !== request.source_context;
1375
+ return {
1376
+ verdict: hasConflict ? "rejected" : "verified",
1377
+ action: hasConflict ? "block" : "allow",
1378
+ hallucination_rate: hasConflict ? 1 : 0,
1379
+ mode: request.mode ?? "lexical",
1380
+ total_claims: 1,
1381
+ supported_claims: hasConflict ? 0 : 1,
1382
+ confidence: hasConflict ? 0.25 : 0.92,
1383
+ claims: [{
1384
+ text: request.text,
1385
+ claim_type: "factual",
1386
+ supported: !hasConflict,
1387
+ confidence: hasConflict ? 0.25 : 0.92,
1388
+ confidence_label: hasConflict ? "low" : "high",
1389
+ verdict: hasConflict ? "rejected" : "verified",
1390
+ action: hasConflict ? "block" : "allow",
1391
+ reason: hasConflict ? "numerical_mismatch" : null,
1392
+ evidence: request.source_context
1393
+ }],
1394
+ processing_time_ms: 1
1395
+ };
1396
+ }
1397
+ async guard(text, source, mode = "lexical") {
1398
+ this.record("guard", text, source, mode);
1399
+ return {
1400
+ safe: true,
1401
+ verdict: "verified",
1402
+ action: "allow",
1403
+ reason: null,
1404
+ confidence: 0.95
1405
+ };
1406
+ }
1407
+ async verifyCitation(request) {
1408
+ this.record("verifyCitation", request);
1409
+ const citations = request.text.match(/\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/g) ?? [];
1410
+ const sentences = request.text.split(/[.!?]+/).filter((s) => s.trim().length > 0);
1411
+ const citedSentences = sentences.filter((s) => /\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/.test(s));
1412
+ const ratio = sentences.length > 0 ? citedSentences.length / sentences.length : 0;
1413
+ return {
1414
+ citation_ratio: ratio,
1415
+ has_sufficient_citations: ratio >= (request.threshold ?? 0.5),
1416
+ sentence_count: sentences.length,
1417
+ citation_count: citations.length,
1418
+ uncited_sentences: sentences.filter((s) => !/\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/.test(s)).map((s) => s.trim()),
1419
+ citations: citations.map((c) => ({
1420
+ citation: c,
1421
+ source_name: c.replace(/[\[\]]/g, "").replace("Source: ", ""),
1422
+ is_valid: (request.sources ?? []).some((src) => c.includes(src.name))
1423
+ })),
1424
+ phantom_count: 0,
1425
+ processing_time_ms: 1
1426
+ };
1427
+ }
1428
+ async getInsights() {
1429
+ this.record("getInsights");
1430
+ return {
1431
+ tig_key: "mock-tig-key",
1432
+ total_requests: 1250,
1433
+ intelligence_requests: 980,
1434
+ fallback_requests: 270,
1435
+ tokens: {
1436
+ baseline_total: 5e5,
1437
+ real_total: 325e3,
1438
+ saved_total: 175e3,
1439
+ saved_percent_avg: 35
1440
+ },
1441
+ cost: {
1442
+ estimated_usd_saved: 12.5
1443
+ }
1444
+ };
1445
+ }
1446
+ async getAnalytics(minutes = 60) {
1447
+ this.record("getAnalytics", minutes);
1448
+ return {
1449
+ cache: {
1450
+ total_requests: 450,
1451
+ cache_hit_rate: 0.42,
1452
+ avg_latency_ms: 180,
1453
+ p95_latency_ms: 850
1454
+ },
1455
+ tokens: {
1456
+ total_baseline: 12e4,
1457
+ total_real: 78e3,
1458
+ total_saved: 42e3,
1459
+ avg_savings_percent: 35
1460
+ },
1461
+ uptime_secs: 86400
1462
+ };
1463
+ }
1464
+ async getAnalyticsTraffic() {
1465
+ this.record("getAnalyticsTraffic");
1466
+ return {
1467
+ total_requests_today: 3200,
1468
+ total_tokens_today: 15e5,
1469
+ top_tenants: [
1470
+ { tenant_id: "tenant-alpha", requests_today: 1200, tokens_used: 58e4, success_rate: 0.98, avg_latency_ms: 220 },
1471
+ { tenant_id: "tenant-beta", requests_today: 850, tokens_used: 42e4, success_rate: 0.96, avg_latency_ms: 310 },
1472
+ { tenant_id: "tenant-gamma", requests_today: 600, tokens_used: 28e4, success_rate: 0.99, avg_latency_ms: 150 }
1473
+ ],
1474
+ error_rate: 0.02,
1475
+ avg_latency_ms: 240,
1476
+ p95_latency_ms: 890,
1477
+ uptime_secs: 86400
1478
+ };
1479
+ }
1203
1480
  async ragAsk(question, text, source = "document") {
1204
1481
  this.record("ragAsk", question, text, source);
1205
1482
  await this.ragUpload(text, source);
package/dist/index.mjs CHANGED
@@ -864,6 +864,16 @@ async function* parseSSEStream(body) {
864
864
  }
865
865
 
866
866
  // src/http_client.ts
867
+ function concatUint8Arrays(arrays) {
868
+ const total = arrays.reduce((n, a) => n + a.length, 0);
869
+ const result = new Uint8Array(total);
870
+ let offset = 0;
871
+ for (const a of arrays) {
872
+ result.set(a, offset);
873
+ offset += a.length;
874
+ }
875
+ return result;
876
+ }
867
877
  function validateResponse(data, typeName) {
868
878
  if (data === null || data === void 0) {
869
879
  throw new ServerError(`Invalid ${typeName}: response is null`, 0);
@@ -998,6 +1008,51 @@ var HttpClient = class {
998
1008
  );
999
1009
  return validateResponse(data, "RagUploadResponse");
1000
1010
  }
1011
+ /**
1012
+ * POST /v1/upload-file — Upload a file (PDF, DOCX, text, image) for RAG indexing.
1013
+ *
1014
+ * @param file - File content as Buffer/Uint8Array
1015
+ * @param filename - The filename (determines content type detection)
1016
+ * @param options - Optional title, tags, timeoutMs
1017
+ * @returns Upload confirmation with quality scoring
1018
+ */
1019
+ async uploadFile(file, filename, options) {
1020
+ const boundary = "----WauldoSDKBoundary";
1021
+ const parts = [];
1022
+ const enc = new TextEncoder();
1023
+ parts.push(enc.encode(`--${boundary}\r
1024
+ Content-Disposition: form-data; name="file"; filename="${filename}"\r
1025
+ Content-Type: application/octet-stream\r
1026
+ \r
1027
+ `));
1028
+ parts.push(file instanceof Uint8Array ? file : new Uint8Array(file));
1029
+ parts.push(enc.encode("\r\n"));
1030
+ if (options?.title) {
1031
+ parts.push(enc.encode(`--${boundary}\r
1032
+ Content-Disposition: form-data; name="title"\r
1033
+ \r
1034
+ ${options.title}\r
1035
+ `));
1036
+ }
1037
+ if (options?.tags) {
1038
+ parts.push(enc.encode(`--${boundary}\r
1039
+ Content-Disposition: form-data; name="tags"\r
1040
+ \r
1041
+ ${options.tags}\r
1042
+ `));
1043
+ }
1044
+ parts.push(enc.encode(`--${boundary}--\r
1045
+ `));
1046
+ const body = concatUint8Arrays(parts);
1047
+ const data = await fetchWithRetry(
1048
+ { ...this.retryConfig, headers: { ...this.retryConfig.headers, "Content-Type": `multipart/form-data; boundary=${boundary}` } },
1049
+ "POST",
1050
+ "/v1/upload-file",
1051
+ body,
1052
+ options?.timeoutMs
1053
+ );
1054
+ return validateResponse(data, "UploadFileResponse");
1055
+ }
1001
1056
  /** POST /v1/query — Query RAG knowledge base */
1002
1057
  async ragQuery(query, topK = 5, options) {
1003
1058
  const body = { query, top_k: topK };
@@ -1061,6 +1116,102 @@ var HttpClient = class {
1061
1116
  );
1062
1117
  return validateResponse(data, "OrchestratorResponse");
1063
1118
  }
1119
+ // ── Fact-Check endpoints ──────────────────────────────────────────────
1120
+ /**
1121
+ * POST /v1/fact-check — Verify claims against source context.
1122
+ *
1123
+ * @param request - Text and source context to verify
1124
+ * @returns FactCheckResponse with verdict, action, and per-claim results
1125
+ *
1126
+ * @example
1127
+ * ```typescript
1128
+ * const result = await client.factCheck({
1129
+ * text: 'Returns accepted within 60 days.',
1130
+ * source_context: 'Our policy allows returns within 14 days.',
1131
+ * mode: 'lexical',
1132
+ * });
1133
+ * console.log(result.verdict); // "rejected"
1134
+ * ```
1135
+ */
1136
+ async factCheck(request) {
1137
+ const data = await fetchWithRetry(
1138
+ this.retryConfig,
1139
+ "POST",
1140
+ "/v1/fact-check",
1141
+ request
1142
+ );
1143
+ return validateResponse(data, "FactCheckResponse");
1144
+ }
1145
+ /**
1146
+ * POST /v1/verify — Verify citations in AI-generated text.
1147
+ *
1148
+ * @example
1149
+ * ```ts
1150
+ * const result = await client.verifyCitation({
1151
+ * text: 'Rust was released in 2010 [Source: rust_book].',
1152
+ * sources: [{ name: 'rust_book', content: 'Rust was first released in 2010.' }],
1153
+ * });
1154
+ * console.log(result.phantom_count); // 0
1155
+ * ```
1156
+ */
1157
+ async verifyCitation(request) {
1158
+ const data = await fetchWithRetry(
1159
+ this.retryConfig,
1160
+ "POST",
1161
+ "/v1/verify",
1162
+ request
1163
+ );
1164
+ return validateResponse(data, "VerifyCitationResponse");
1165
+ }
1166
+ /**
1167
+ * Verify an LLM output against a source document.
1168
+ * Convenience wrapper around factCheck(). Returns a simple safe/unsafe result.
1169
+ */
1170
+ async guard(text, source, mode = "lexical") {
1171
+ const result = await this.factCheck({ text, source_context: source, mode });
1172
+ const claim = result.claims?.[0];
1173
+ return {
1174
+ safe: claim?.verdict === "verified",
1175
+ verdict: claim?.verdict ?? "rejected",
1176
+ action: claim?.action ?? "block",
1177
+ reason: claim?.reason ?? "no_claims",
1178
+ confidence: claim?.confidence ?? 0
1179
+ };
1180
+ }
1181
+ // ── Analytics & Insights endpoints ───────────────────────────────────
1182
+ /**
1183
+ * GET /v1/insights — ROI metrics for your API key
1184
+ */
1185
+ async getInsights() {
1186
+ const data = await fetchWithRetry(
1187
+ this.retryConfig,
1188
+ "GET",
1189
+ "/v1/insights"
1190
+ );
1191
+ return validateResponse(data, "InsightsResponse");
1192
+ }
1193
+ /**
1194
+ * GET /v1/analytics — Usage analytics and cache performance
1195
+ */
1196
+ async getAnalytics(minutes = 60) {
1197
+ const data = await fetchWithRetry(
1198
+ this.retryConfig,
1199
+ "GET",
1200
+ `/v1/analytics?minutes=${minutes}`
1201
+ );
1202
+ return validateResponse(data, "AnalyticsResponse");
1203
+ }
1204
+ /**
1205
+ * GET /v1/analytics/traffic — Per-tenant traffic monitoring
1206
+ */
1207
+ async getAnalyticsTraffic() {
1208
+ const data = await fetchWithRetry(
1209
+ this.retryConfig,
1210
+ "GET",
1211
+ "/v1/analytics/traffic"
1212
+ );
1213
+ return validateResponse(data, "TrafficSummary");
1214
+ }
1064
1215
  };
1065
1216
 
1066
1217
  // src/mock_client.ts
@@ -1164,6 +1315,132 @@ var MockHttpClient = class {
1164
1315
  this.record("conversation", options);
1165
1316
  return new Conversation(this, options);
1166
1317
  }
1318
+ async uploadFile(_file, filename, options) {
1319
+ this.record("uploadFile", filename, options);
1320
+ return {
1321
+ document_id: "mock-doc-file-1",
1322
+ chunks_count: 5,
1323
+ indexed_at: (/* @__PURE__ */ new Date()).toISOString(),
1324
+ content_type: "application/pdf",
1325
+ trace_id: "mock-trace-1",
1326
+ quality: {
1327
+ score: 0.85,
1328
+ label: "good",
1329
+ word_count: 1200,
1330
+ line_density: 8.5,
1331
+ avg_line_length: 72,
1332
+ paragraph_count: 15
1333
+ }
1334
+ };
1335
+ }
1336
+ async factCheck(request) {
1337
+ this.record("factCheck", request);
1338
+ const hasConflict = request.text !== request.source_context;
1339
+ return {
1340
+ verdict: hasConflict ? "rejected" : "verified",
1341
+ action: hasConflict ? "block" : "allow",
1342
+ hallucination_rate: hasConflict ? 1 : 0,
1343
+ mode: request.mode ?? "lexical",
1344
+ total_claims: 1,
1345
+ supported_claims: hasConflict ? 0 : 1,
1346
+ confidence: hasConflict ? 0.25 : 0.92,
1347
+ claims: [{
1348
+ text: request.text,
1349
+ claim_type: "factual",
1350
+ supported: !hasConflict,
1351
+ confidence: hasConflict ? 0.25 : 0.92,
1352
+ confidence_label: hasConflict ? "low" : "high",
1353
+ verdict: hasConflict ? "rejected" : "verified",
1354
+ action: hasConflict ? "block" : "allow",
1355
+ reason: hasConflict ? "numerical_mismatch" : null,
1356
+ evidence: request.source_context
1357
+ }],
1358
+ processing_time_ms: 1
1359
+ };
1360
+ }
1361
+ async guard(text, source, mode = "lexical") {
1362
+ this.record("guard", text, source, mode);
1363
+ return {
1364
+ safe: true,
1365
+ verdict: "verified",
1366
+ action: "allow",
1367
+ reason: null,
1368
+ confidence: 0.95
1369
+ };
1370
+ }
1371
+ async verifyCitation(request) {
1372
+ this.record("verifyCitation", request);
1373
+ const citations = request.text.match(/\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/g) ?? [];
1374
+ const sentences = request.text.split(/[.!?]+/).filter((s) => s.trim().length > 0);
1375
+ const citedSentences = sentences.filter((s) => /\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/.test(s));
1376
+ const ratio = sentences.length > 0 ? citedSentences.length / sentences.length : 0;
1377
+ return {
1378
+ citation_ratio: ratio,
1379
+ has_sufficient_citations: ratio >= (request.threshold ?? 0.5),
1380
+ sentence_count: sentences.length,
1381
+ citation_count: citations.length,
1382
+ uncited_sentences: sentences.filter((s) => !/\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/.test(s)).map((s) => s.trim()),
1383
+ citations: citations.map((c) => ({
1384
+ citation: c,
1385
+ source_name: c.replace(/[\[\]]/g, "").replace("Source: ", ""),
1386
+ is_valid: (request.sources ?? []).some((src) => c.includes(src.name))
1387
+ })),
1388
+ phantom_count: 0,
1389
+ processing_time_ms: 1
1390
+ };
1391
+ }
1392
+ async getInsights() {
1393
+ this.record("getInsights");
1394
+ return {
1395
+ tig_key: "mock-tig-key",
1396
+ total_requests: 1250,
1397
+ intelligence_requests: 980,
1398
+ fallback_requests: 270,
1399
+ tokens: {
1400
+ baseline_total: 5e5,
1401
+ real_total: 325e3,
1402
+ saved_total: 175e3,
1403
+ saved_percent_avg: 35
1404
+ },
1405
+ cost: {
1406
+ estimated_usd_saved: 12.5
1407
+ }
1408
+ };
1409
+ }
1410
+ async getAnalytics(minutes = 60) {
1411
+ this.record("getAnalytics", minutes);
1412
+ return {
1413
+ cache: {
1414
+ total_requests: 450,
1415
+ cache_hit_rate: 0.42,
1416
+ avg_latency_ms: 180,
1417
+ p95_latency_ms: 850
1418
+ },
1419
+ tokens: {
1420
+ total_baseline: 12e4,
1421
+ total_real: 78e3,
1422
+ total_saved: 42e3,
1423
+ avg_savings_percent: 35
1424
+ },
1425
+ uptime_secs: 86400
1426
+ };
1427
+ }
1428
+ async getAnalyticsTraffic() {
1429
+ this.record("getAnalyticsTraffic");
1430
+ return {
1431
+ total_requests_today: 3200,
1432
+ total_tokens_today: 15e5,
1433
+ top_tenants: [
1434
+ { tenant_id: "tenant-alpha", requests_today: 1200, tokens_used: 58e4, success_rate: 0.98, avg_latency_ms: 220 },
1435
+ { tenant_id: "tenant-beta", requests_today: 850, tokens_used: 42e4, success_rate: 0.96, avg_latency_ms: 310 },
1436
+ { tenant_id: "tenant-gamma", requests_today: 600, tokens_used: 28e4, success_rate: 0.99, avg_latency_ms: 150 }
1437
+ ],
1438
+ error_rate: 0.02,
1439
+ avg_latency_ms: 240,
1440
+ p95_latency_ms: 890,
1441
+ uptime_secs: 86400
1442
+ };
1443
+ }
1167
1444
  async ragAsk(question, text, source = "document") {
1168
1445
  this.record("ragAsk", question, text, source);
1169
1446
  await this.ragUpload(text, source);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wauldo",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Official TypeScript SDK for Wauldo — Verified AI answers from your documents",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",