wauldo 0.4.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
@@ -1,82 +1,152 @@
1
- # Wauldo TypeScript SDK
1
+ <h1 align="center">Wauldo TypeScript SDK</h1>
2
2
 
3
- [![npm](https://img.shields.io/npm/v/wauldo.svg)](https://npmjs.com/package/wauldo)
4
- [![Downloads](https://img.shields.io/npm/dm/wauldo.svg)](https://npmjs.com/package/wauldo)
5
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE)
3
+ <p align="center">
4
+ <strong>Verified AI answers from your documents — or no answer at all.</strong>
5
+ </p>
7
6
 
8
- > **Verified AI answers from your documents.** Every response includes source citations, confidence scores, and an audit trail — or we don't answer at all.
7
+ <p align="center">
8
+ Most RAG APIs guess. Wauldo verifies.
9
+ </p>
9
10
 
10
- Official TypeScript SDK for the [Wauldo API](https://wauldo.com) — the AI inference layer with smart model routing, zero hallucinations, and standalone fact-checking.
11
+ <p align="center">
12
+ <b>0% hallucination</b> &nbsp;|&nbsp; 83% accuracy &nbsp;|&nbsp; 61 eval tasks &nbsp;|&nbsp; 14 LLMs tested
13
+ </p>
11
14
 
12
- ## Why Wauldo?
15
+ <p align="center">
16
+ <a href="https://npmjs.com/package/wauldo"><img src="https://img.shields.io/npm/v/wauldo.svg" alt="npm" /></a>&nbsp;
17
+ <a href="https://npmjs.com/package/wauldo"><img src="https://img.shields.io/npm/dm/wauldo.svg" alt="Downloads" /></a>&nbsp;
18
+ <img src="https://img.shields.io/badge/TypeScript-5.0+-blue.svg" alt="TypeScript" />&nbsp;
19
+ <img src="https://img.shields.io/badge/License-MIT-green.svg" alt="MIT" />
20
+ </p>
13
21
 
14
- - **Native PDF & DOCX Upload** — upload files directly, server-side text extraction with document quality scoring
15
- - **Citation Verify API** — detect uncited sentences, phantom citations, and measure coverage ratio. No LLM needed
16
- - **Fact-Check API** — verify any claim against source with 3 modes (lexical, hybrid, semantic). Get verdict, action, and structured reason
17
- - **Zero hallucinations** — every answer is verified against source documents
18
- - **Smart model routing** — auto-selects the cheapest model that meets quality (save 40-80% on AI costs)
19
- - **One API, 7+ providers** — OpenAI, Anthropic, Google, Qwen, Meta, Mistral, DeepSeek with automatic fallback
20
- - **OpenAI-compatible** — swap your `baseUrl`, keep your existing code
21
- - **Full audit trail** — confidence score, grounded status, model used, latency on every response
22
- - **Zero dependencies** — uses Node 18+ built-in APIs (fetch, ReadableStream)
22
+ <p align="center">
23
+ <a href="https://wauldo.com/demo">Demo</a> &bull;
24
+ <a href="https://wauldo.com/docs">Docs</a> &bull;
25
+ <a href="https://rapidapi.com/binnewzzin/api/smart-rag-api">Free API Key</a> &bull;
26
+ <a href="https://dev.to/wauldo/how-we-achieved-0-hallucination-rate-in-our-rag-api-with-benchmarks-4g54">Benchmarks</a>
27
+ </p>
28
+
29
+ ---
30
+
31
+ ## Try it locally (no server needed)
32
+
33
+ ```bash
34
+ npm install wauldo
35
+ ```
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
+ ---
23
57
 
24
- ## Quick Start
58
+ ## Quickstart with real API
25
59
 
26
60
  ```typescript
27
61
  import { HttpClient } from 'wauldo';
28
62
 
29
63
  const client = new HttpClient({ baseUrl: 'https://api.wauldo.com', apiKey: 'YOUR_API_KEY' });
30
64
 
31
- const reply = await client.chatSimple('auto', 'What is TypeScript?');
32
- console.log(reply);
65
+ // Upload a document
66
+ await client.ragUpload('Our refund policy allows returns within 60 days...', 'policy.txt');
67
+
68
+ // Ask a question — answer is verified against the source
69
+ const result = await client.ragQuery('What is the refund policy?');
70
+ console.log(result.answer);
71
+ console.log(result.sources);
33
72
  ```
34
73
 
35
- ## Installation
74
+ ```
75
+ Output:
76
+ Answer: Returns are accepted within 60 days of purchase.
77
+ Sources: policy.txt — "Our refund policy allows returns within 60 days"
78
+ Grounded: true | Confidence: 0.92
79
+ ```
80
+
81
+ [Try the demo](https://wauldo.com/demo) | [Get a free API key](https://rapidapi.com/binnewzzin/api/smart-rag-api)
82
+
83
+ ---
84
+
85
+ ## Why Wauldo (and not standard RAG)
86
+
87
+ **Typical RAG pipeline**
36
88
 
37
- ```bash
38
- npm install wauldo
89
+ ```
90
+ retrieve generate → hope it's correct
39
91
  ```
40
92
 
41
- **Requirements:** Node.js 18+, TypeScript 5.0+
93
+ **Wauldo pipeline**
42
94
 
43
- ## Features
95
+ ```
96
+ retrieve → extract facts → generate → verify → return or refuse
97
+ ```
44
98
 
45
- ### Chat Completions
99
+ If the answer can't be verified, it returns **"insufficient evidence"** instead of guessing.
46
100
 
47
- ```typescript
48
- import { HttpClient } from 'wauldo';
101
+ ### See the difference
49
102
 
50
- const client = new HttpClient({ baseUrl: 'https://api.wauldo.com', apiKey: 'YOUR_API_KEY' });
103
+ ```
104
+ Document: "Refunds are processed within 60 days"
51
105
 
52
- const response = await client.chat({
53
- model: 'auto',
54
- messages: [
55
- { role: 'system', content: 'You are a helpful assistant.' },
56
- { role: 'user', content: 'Explain async/await in TypeScript' },
57
- ],
58
- });
59
- console.log(response.choices[0]?.message?.content);
106
+ Typical RAG: "Refunds are processed within 30 days" ← wrong
107
+ Wauldo: "Refunds are processed within 60 days" ← verified
108
+ or "insufficient evidence" if unclear ← safe
60
109
  ```
61
110
 
62
- ### RAG — Upload & Query
111
+ ---
112
+
113
+ ## Examples
114
+
115
+ ### Upload a PDF and ask questions
63
116
 
64
117
  ```typescript
65
- // Upload a document
66
- const upload = await client.ragUpload('Contract text here...', 'contract.txt');
67
- console.log(`Indexed ${upload.chunks_count} chunks`);
118
+ // Upload text extraction + quality scoring happens server-side
119
+ const upload = await client.uploadFile(filePath, { title: 'Q3 Contract' });
120
+ console.log(`Extracted ${upload.chunks_count} chunks, quality: ${upload.quality_label}`);
68
121
 
69
- // Query with verified answer
122
+ // Query
70
123
  const result = await client.ragQuery('What are the payment terms?');
71
124
  console.log(`Answer: ${result.answer}`);
72
125
  console.log(`Confidence: ${Math.round(result.audit.confidence * 100)}%`);
73
126
  console.log(`Grounded: ${result.audit.grounded}`);
74
- for (const source of result.sources) {
75
- console.log(` Source (${Math.round(source.score * 100)}%): ${source.content}`);
76
- }
77
127
  ```
78
128
 
79
- ### Streaming (SSE)
129
+ ### Fact-check any LLM output
130
+
131
+ ```typescript
132
+ const result = await client.factCheck({
133
+ text: 'Returns are accepted within 60 days.',
134
+ sourceContext: 'Our policy allows returns within 14 days.',
135
+ mode: 'lexical',
136
+ });
137
+ console.log(result.verdict); // "rejected"
138
+ console.log(result.action); // "block"
139
+ console.log(result.claims[0].reason); // "numerical_mismatch"
140
+ ```
141
+
142
+ ### Chat (OpenAI-compatible)
143
+
144
+ ```typescript
145
+ const reply = await client.chatSimple('auto', 'Explain async/await in TypeScript');
146
+ console.log(reply);
147
+ ```
148
+
149
+ ### Streaming
80
150
 
81
151
  ```typescript
82
152
  const stream = client.chatStream({
@@ -88,7 +158,7 @@ for await (const chunk of stream) {
88
158
  }
89
159
  ```
90
160
 
91
- ### Conversation Helper
161
+ ### Conversation
92
162
 
93
163
  ```typescript
94
164
  const conv = client.conversation({ system: 'You are an expert on TypeScript.', model: 'auto' });
@@ -96,18 +166,21 @@ const reply = await conv.say('What are generics?');
96
166
  const followUp = await conv.say('Give me an example');
97
167
  ```
98
168
 
99
- ### Fact-Check — Verify Claims
169
+ ---
100
170
 
101
- ```typescript
102
- const result = await client.factCheck({
103
- text: 'Returns are accepted within 60 days.',
104
- source_context: 'Our policy allows returns within 14 days.',
105
- mode: 'lexical',
106
- });
107
- console.log(result.verdict); // "rejected"
108
- console.log(result.action); // "block"
109
- result.claims.forEach(c => console.log(`${c.text} ${c.verdict} (${c.reason})`));
110
- ```
171
+ ## Features
172
+
173
+ - **Pre-generation fact extraction** numbers, dates, limits injected as constraints
174
+ - **Post-generation grounding check** every answer verified against sources
175
+ - **Citation validation** — detects phantom references
176
+ - **Analytics & Insights** — track token savings, cache performance, cost per hour, and per-tenant traffic
177
+ - **Fact-check API** — verify any claim against any source (3 modes)
178
+ - **Native PDF/DOCX upload** — server-side extraction with quality scoring
179
+ - **Smart model routing** auto-selects cheapest model that meets quality
180
+ - **OpenAI-compatible** — swap your `baseUrl`, keep your existing code
181
+ - **Zero dependencies** — uses Node 18+ built-in APIs (fetch, ReadableStream)
182
+
183
+ ---
111
184
 
112
185
  ## Error Handling
113
186
 
@@ -115,19 +188,16 @@ result.claims.forEach(c => console.log(`${c.text} → ${c.verdict} (${c.reason})
115
188
  import { HttpClient, ServerError } from 'wauldo';
116
189
 
117
190
  try {
118
- const response = await client.chat({
119
- model: 'auto',
120
- messages: [{ role: 'user', content: 'Hello' }],
121
- });
191
+ const response = await client.chat({ model: 'auto', messages: [{ role: 'user', content: 'Hello' }] });
122
192
  } catch (error) {
123
193
  if (error instanceof ServerError) {
124
194
  console.error(`Server error [${error.code}]: ${error.message}`);
125
- } else {
126
- console.error('Unknown error:', error);
127
195
  }
128
196
  }
129
197
  ```
130
198
 
199
+ ---
200
+
131
201
  ## RapidAPI
132
202
 
133
203
  ```typescript
@@ -140,19 +210,17 @@ const client = new HttpClient({
140
210
  });
141
211
  ```
142
212
 
143
- Get your free API key (300 req/month): [RapidAPI](https://rapidapi.com/binnewzzin/api/smart-rag-api)
213
+ Free tier (300 req/month): [RapidAPI](https://rapidapi.com/binnewzzin/api/smart-rag-api)
144
214
 
145
- ## Links
215
+ ---
146
216
 
147
- - [Website](https://wauldo.com)
148
- - [Documentation](https://wauldo.com/docs)
149
- - [Live Demo](https://api.wauldo.com/demo)
150
- - [Cost Calculator](https://wauldo.com/calculator)
151
- - [Status](https://wauldo.com/status)
217
+ [Website](https://wauldo.com) | [Docs](https://wauldo.com/docs) | [Demo](https://wauldo.com/demo) | [Benchmarks](https://dev.to/wauldo/how-we-achieved-0-hallucination-rate-in-our-rag-api-with-benchmarks-4g54)
152
218
 
153
219
  ## Contributing
154
220
 
155
- Found a bug? Have a feature request? [Open an issue](https://github.com/wauldo/wauldo-sdk-js/issues).
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.
156
224
 
157
225
  ## License
158
226
 
package/dist/index.d.mts CHANGED
@@ -380,6 +380,58 @@ interface VerifyCitationResponse {
380
380
  phantom_count?: number;
381
381
  processing_time_ms: number;
382
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
+ }
383
435
  /** Minimal interface required by Conversation — implemented by both HttpClient and MockHttpClient */
384
436
  interface ChatClientLike {
385
437
  chat(request: ChatRequest, options?: RequestOptions): Promise<ChatResponse>;
@@ -580,6 +632,23 @@ declare class HttpClient {
580
632
  * ```
581
633
  */
582
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>;
583
652
  }
584
653
 
585
654
  /**
@@ -650,6 +719,17 @@ declare class MockHttpClient {
650
719
  system?: string;
651
720
  model?: string;
652
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>;
653
733
  ragAsk(question: string, text: string, source?: string): Promise<string>;
654
734
  private record;
655
735
  }
@@ -700,4 +780,4 @@ declare class ToolNotFoundError extends WauldoError {
700
780
  constructor(toolName: string);
701
781
  }
702
782
 
703
- export { AgentClient, 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, 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 SourceChunk, type SourceType, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, type UploadFileResponse, ValidationError, type VerifyCitationRequest, type VerifyCitationResponse, 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
@@ -380,6 +380,58 @@ interface VerifyCitationResponse {
380
380
  phantom_count?: number;
381
381
  processing_time_ms: number;
382
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
+ }
383
435
  /** Minimal interface required by Conversation — implemented by both HttpClient and MockHttpClient */
384
436
  interface ChatClientLike {
385
437
  chat(request: ChatRequest, options?: RequestOptions): Promise<ChatResponse>;
@@ -580,6 +632,23 @@ declare class HttpClient {
580
632
  * ```
581
633
  */
582
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>;
583
652
  }
584
653
 
585
654
  /**
@@ -650,6 +719,17 @@ declare class MockHttpClient {
650
719
  system?: string;
651
720
  model?: string;
652
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>;
653
733
  ragAsk(question: string, text: string, source?: string): Promise<string>;
654
734
  private record;
655
735
  }
@@ -700,4 +780,4 @@ declare class ToolNotFoundError extends WauldoError {
700
780
  constructor(toolName: string);
701
781
  }
702
782
 
703
- export { AgentClient, 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, 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 SourceChunk, type SourceType, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, type UploadFileResponse, ValidationError, type VerifyCitationRequest, type VerifyCitationResponse, 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
@@ -1199,6 +1199,55 @@ ${options.tags}\r
1199
1199
  );
1200
1200
  return validateResponse(data, "VerifyCitationResponse");
1201
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
+ }
1202
1251
  };
1203
1252
 
1204
1253
  // src/mock_client.ts
@@ -1302,6 +1351,132 @@ var MockHttpClient = class {
1302
1351
  this.record("conversation", options);
1303
1352
  return new Conversation(this, options);
1304
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
+ }
1305
1480
  async ragAsk(question, text, source = "document") {
1306
1481
  this.record("ragAsk", question, text, source);
1307
1482
  await this.ragUpload(text, source);
package/dist/index.mjs CHANGED
@@ -1163,6 +1163,55 @@ ${options.tags}\r
1163
1163
  );
1164
1164
  return validateResponse(data, "VerifyCitationResponse");
1165
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
+ }
1166
1215
  };
1167
1216
 
1168
1217
  // src/mock_client.ts
@@ -1266,6 +1315,132 @@ var MockHttpClient = class {
1266
1315
  this.record("conversation", options);
1267
1316
  return new Conversation(this, options);
1268
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
+ }
1269
1444
  async ragAsk(question, text, source = "document") {
1270
1445
  this.record("ragAsk", question, text, source);
1271
1446
  await this.ragUpload(text, source);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wauldo",
3
- "version": "0.4.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",