wauldo 0.5.0 → 0.7.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 +29 -2
- package/dist/index.d.mts +234 -1
- package/dist/index.d.ts +234 -1
- package/dist/index.js +306 -0
- package/dist/index.mjs +306 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,12 +28,35 @@
|
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
-
##
|
|
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,8 @@ 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
|
|
177
|
+
- **Guard method** — one-call hallucination firewall (`client.guard(text, source)` → safe/unsafe)
|
|
153
178
|
- **Fact-check API** — verify any claim against any source (3 modes)
|
|
154
179
|
- **Native PDF/DOCX upload** — server-side extraction with quality scoring
|
|
155
180
|
- **Smart model routing** — auto-selects cheapest model that meets quality
|
|
@@ -194,7 +219,9 @@ Free tier (300 req/month): [RapidAPI](https://rapidapi.com/binnewzzin/api/smart-
|
|
|
194
219
|
|
|
195
220
|
## Contributing
|
|
196
221
|
|
|
197
|
-
PRs welcome
|
|
222
|
+
PRs welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup instructions and guidelines.
|
|
223
|
+
|
|
224
|
+
Check the [good first issues](https://github.com/wauldo/wauldo-sdk-js/labels/good%20first%20issue) to get started.
|
|
198
225
|
|
|
199
226
|
## License
|
|
200
227
|
|
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,135 @@ 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
|
+
/** @deprecated Use GuardResponse instead */
|
|
384
|
+
interface GuardResult {
|
|
385
|
+
safe: boolean;
|
|
386
|
+
verdict: string;
|
|
387
|
+
action: string;
|
|
388
|
+
reason: string | null;
|
|
389
|
+
confidence: number;
|
|
390
|
+
}
|
|
391
|
+
interface GuardClaim {
|
|
392
|
+
text: string;
|
|
393
|
+
claim_type?: string;
|
|
394
|
+
supported: boolean;
|
|
395
|
+
confidence: number;
|
|
396
|
+
confidence_label?: string;
|
|
397
|
+
verdict: string;
|
|
398
|
+
action: string;
|
|
399
|
+
reason?: string | null;
|
|
400
|
+
evidence?: string | null;
|
|
401
|
+
}
|
|
402
|
+
interface GuardResponse {
|
|
403
|
+
verdict: string;
|
|
404
|
+
action: string;
|
|
405
|
+
hallucination_rate: number;
|
|
406
|
+
mode: string;
|
|
407
|
+
total_claims: number;
|
|
408
|
+
supported_claims: number;
|
|
409
|
+
confidence: number;
|
|
410
|
+
claims: GuardClaim[];
|
|
411
|
+
mode_warning?: string;
|
|
412
|
+
processing_time_ms?: number;
|
|
413
|
+
}
|
|
414
|
+
type GuardMode = 'lexical' | 'hybrid' | 'semantic';
|
|
415
|
+
interface InsightsResponse {
|
|
416
|
+
tig_key: string;
|
|
417
|
+
total_requests: number;
|
|
418
|
+
intelligence_requests: number;
|
|
419
|
+
fallback_requests: number;
|
|
420
|
+
tokens: {
|
|
421
|
+
baseline_total: number;
|
|
422
|
+
real_total: number;
|
|
423
|
+
saved_total: number;
|
|
424
|
+
saved_percent_avg: number;
|
|
425
|
+
};
|
|
426
|
+
cost: {
|
|
427
|
+
estimated_usd_saved: number;
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
interface AnalyticsResponse {
|
|
431
|
+
cache: {
|
|
432
|
+
total_requests: number;
|
|
433
|
+
cache_hit_rate: number;
|
|
434
|
+
avg_latency_ms: number;
|
|
435
|
+
p95_latency_ms: number;
|
|
436
|
+
};
|
|
437
|
+
tokens: {
|
|
438
|
+
total_baseline: number;
|
|
439
|
+
total_real: number;
|
|
440
|
+
total_saved: number;
|
|
441
|
+
avg_savings_percent: number;
|
|
442
|
+
};
|
|
443
|
+
uptime_secs: number;
|
|
444
|
+
}
|
|
445
|
+
interface TrafficSummary {
|
|
446
|
+
total_requests_today: number;
|
|
447
|
+
total_tokens_today: number;
|
|
448
|
+
top_tenants: Array<{
|
|
449
|
+
tenant_id: string;
|
|
450
|
+
requests_today: number;
|
|
451
|
+
tokens_used: number;
|
|
452
|
+
success_rate: number;
|
|
453
|
+
avg_latency_ms: number;
|
|
454
|
+
}>;
|
|
455
|
+
error_rate: number;
|
|
456
|
+
avg_latency_ms: number;
|
|
457
|
+
p95_latency_ms: number;
|
|
458
|
+
uptime_secs: number;
|
|
459
|
+
}
|
|
315
460
|
/** Minimal interface required by Conversation — implemented by both HttpClient and MockHttpClient */
|
|
316
461
|
interface ChatClientLike {
|
|
317
462
|
chat(request: ChatRequest, options?: RequestOptions): Promise<ChatResponse>;
|
|
@@ -435,6 +580,19 @@ declare class HttpClient {
|
|
|
435
580
|
* @returns Upload confirmation with document_id and chunks_count
|
|
436
581
|
*/
|
|
437
582
|
ragUpload(content: string, filename?: string, options?: RequestOptions): Promise<RagUploadResponse>;
|
|
583
|
+
/**
|
|
584
|
+
* POST /v1/upload-file — Upload a file (PDF, DOCX, text, image) for RAG indexing.
|
|
585
|
+
*
|
|
586
|
+
* @param file - File content as Buffer/Uint8Array
|
|
587
|
+
* @param filename - The filename (determines content type detection)
|
|
588
|
+
* @param options - Optional title, tags, timeoutMs
|
|
589
|
+
* @returns Upload confirmation with quality scoring
|
|
590
|
+
*/
|
|
591
|
+
uploadFile(file: Uint8Array | Buffer, filename: string, options?: {
|
|
592
|
+
title?: string;
|
|
593
|
+
tags?: string;
|
|
594
|
+
timeoutMs?: number;
|
|
595
|
+
}): Promise<UploadFileResponse>;
|
|
438
596
|
/** POST /v1/query — Query RAG knowledge base */
|
|
439
597
|
ragQuery(query: string, topK?: number, options?: {
|
|
440
598
|
debug?: boolean;
|
|
@@ -469,6 +627,70 @@ declare class HttpClient {
|
|
|
469
627
|
orchestrate(prompt: string): Promise<OrchestratorResponse>;
|
|
470
628
|
/** POST /v1/orchestrator/parallel — Run all 4 specialists in parallel */
|
|
471
629
|
orchestrateParallel(prompt: string): Promise<OrchestratorResponse>;
|
|
630
|
+
/**
|
|
631
|
+
* POST /v1/fact-check — Verify claims against source context.
|
|
632
|
+
*
|
|
633
|
+
* @param request - Text and source context to verify
|
|
634
|
+
* @returns FactCheckResponse with verdict, action, and per-claim results
|
|
635
|
+
*
|
|
636
|
+
* @example
|
|
637
|
+
* ```typescript
|
|
638
|
+
* const result = await client.factCheck({
|
|
639
|
+
* text: 'Returns accepted within 60 days.',
|
|
640
|
+
* source_context: 'Our policy allows returns within 14 days.',
|
|
641
|
+
* mode: 'lexical',
|
|
642
|
+
* });
|
|
643
|
+
* console.log(result.verdict); // "rejected"
|
|
644
|
+
* ```
|
|
645
|
+
*/
|
|
646
|
+
factCheck(request: FactCheckRequest): Promise<FactCheckResponse>;
|
|
647
|
+
/**
|
|
648
|
+
* POST /v1/verify — Verify citations in AI-generated text.
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```ts
|
|
652
|
+
* const result = await client.verifyCitation({
|
|
653
|
+
* text: 'Rust was released in 2010 [Source: rust_book].',
|
|
654
|
+
* sources: [{ name: 'rust_book', content: 'Rust was first released in 2010.' }],
|
|
655
|
+
* });
|
|
656
|
+
* console.log(result.phantom_count); // 0
|
|
657
|
+
* ```
|
|
658
|
+
*/
|
|
659
|
+
verifyCitation(request: VerifyCitationRequest): Promise<VerifyCitationResponse>;
|
|
660
|
+
/**
|
|
661
|
+
* POST /v1/fact-check — Verify text claims against source context.
|
|
662
|
+
*
|
|
663
|
+
* Guard is a hallucination firewall: checks whether LLM output is
|
|
664
|
+
* supported by source documents. Blocks wrong answers before users see them.
|
|
665
|
+
*
|
|
666
|
+
* @param text - The LLM-generated text to verify
|
|
667
|
+
* @param sourceContext - The ground-truth source document(s)
|
|
668
|
+
* @param mode - "lexical" (<1ms), "hybrid" (~50ms), or "semantic" (~500ms)
|
|
669
|
+
*
|
|
670
|
+
* @example
|
|
671
|
+
* ```typescript
|
|
672
|
+
* const result = await client.guard(
|
|
673
|
+
* 'Returns accepted within 60 days',
|
|
674
|
+
* 'Our return policy: 14 days.',
|
|
675
|
+
* );
|
|
676
|
+
* if (guardIsBlocked(result)) {
|
|
677
|
+
* console.log('Hallucination caught:', result.claims[0]?.reason);
|
|
678
|
+
* }
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
681
|
+
guard(text: string, sourceContext: string, mode?: GuardMode): Promise<GuardResponse>;
|
|
682
|
+
/**
|
|
683
|
+
* GET /v1/insights — ROI metrics for your API key
|
|
684
|
+
*/
|
|
685
|
+
getInsights(): Promise<InsightsResponse>;
|
|
686
|
+
/**
|
|
687
|
+
* GET /v1/analytics — Usage analytics and cache performance
|
|
688
|
+
*/
|
|
689
|
+
getAnalytics(minutes?: number): Promise<AnalyticsResponse>;
|
|
690
|
+
/**
|
|
691
|
+
* GET /v1/analytics/traffic — Per-tenant traffic monitoring
|
|
692
|
+
*/
|
|
693
|
+
getAnalyticsTraffic(): Promise<TrafficSummary>;
|
|
472
694
|
}
|
|
473
695
|
|
|
474
696
|
/**
|
|
@@ -539,6 +761,17 @@ declare class MockHttpClient {
|
|
|
539
761
|
system?: string;
|
|
540
762
|
model?: string;
|
|
541
763
|
}): Conversation;
|
|
764
|
+
uploadFile(_file: Uint8Array | Buffer, filename: string, options?: {
|
|
765
|
+
title?: string;
|
|
766
|
+
tags?: string;
|
|
767
|
+
timeoutMs?: number;
|
|
768
|
+
}): Promise<UploadFileResponse>;
|
|
769
|
+
factCheck(request: FactCheckRequest): Promise<FactCheckResponse>;
|
|
770
|
+
guard(text: string, sourceContext: string, mode?: 'lexical' | 'hybrid' | 'semantic'): Promise<GuardResponse>;
|
|
771
|
+
verifyCitation(request: VerifyCitationRequest): Promise<VerifyCitationResponse>;
|
|
772
|
+
getInsights(): Promise<InsightsResponse>;
|
|
773
|
+
getAnalytics(minutes?: number): Promise<AnalyticsResponse>;
|
|
774
|
+
getAnalyticsTraffic(): Promise<TrafficSummary>;
|
|
542
775
|
ragAsk(question: string, text: string, source?: string): Promise<string>;
|
|
543
776
|
private record;
|
|
544
777
|
}
|
|
@@ -589,4 +822,4 @@ declare class ToolNotFoundError extends WauldoError {
|
|
|
589
822
|
constructor(toolName: string);
|
|
590
823
|
}
|
|
591
824
|
|
|
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 };
|
|
825
|
+
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,135 @@ 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
|
+
/** @deprecated Use GuardResponse instead */
|
|
384
|
+
interface GuardResult {
|
|
385
|
+
safe: boolean;
|
|
386
|
+
verdict: string;
|
|
387
|
+
action: string;
|
|
388
|
+
reason: string | null;
|
|
389
|
+
confidence: number;
|
|
390
|
+
}
|
|
391
|
+
interface GuardClaim {
|
|
392
|
+
text: string;
|
|
393
|
+
claim_type?: string;
|
|
394
|
+
supported: boolean;
|
|
395
|
+
confidence: number;
|
|
396
|
+
confidence_label?: string;
|
|
397
|
+
verdict: string;
|
|
398
|
+
action: string;
|
|
399
|
+
reason?: string | null;
|
|
400
|
+
evidence?: string | null;
|
|
401
|
+
}
|
|
402
|
+
interface GuardResponse {
|
|
403
|
+
verdict: string;
|
|
404
|
+
action: string;
|
|
405
|
+
hallucination_rate: number;
|
|
406
|
+
mode: string;
|
|
407
|
+
total_claims: number;
|
|
408
|
+
supported_claims: number;
|
|
409
|
+
confidence: number;
|
|
410
|
+
claims: GuardClaim[];
|
|
411
|
+
mode_warning?: string;
|
|
412
|
+
processing_time_ms?: number;
|
|
413
|
+
}
|
|
414
|
+
type GuardMode = 'lexical' | 'hybrid' | 'semantic';
|
|
415
|
+
interface InsightsResponse {
|
|
416
|
+
tig_key: string;
|
|
417
|
+
total_requests: number;
|
|
418
|
+
intelligence_requests: number;
|
|
419
|
+
fallback_requests: number;
|
|
420
|
+
tokens: {
|
|
421
|
+
baseline_total: number;
|
|
422
|
+
real_total: number;
|
|
423
|
+
saved_total: number;
|
|
424
|
+
saved_percent_avg: number;
|
|
425
|
+
};
|
|
426
|
+
cost: {
|
|
427
|
+
estimated_usd_saved: number;
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
interface AnalyticsResponse {
|
|
431
|
+
cache: {
|
|
432
|
+
total_requests: number;
|
|
433
|
+
cache_hit_rate: number;
|
|
434
|
+
avg_latency_ms: number;
|
|
435
|
+
p95_latency_ms: number;
|
|
436
|
+
};
|
|
437
|
+
tokens: {
|
|
438
|
+
total_baseline: number;
|
|
439
|
+
total_real: number;
|
|
440
|
+
total_saved: number;
|
|
441
|
+
avg_savings_percent: number;
|
|
442
|
+
};
|
|
443
|
+
uptime_secs: number;
|
|
444
|
+
}
|
|
445
|
+
interface TrafficSummary {
|
|
446
|
+
total_requests_today: number;
|
|
447
|
+
total_tokens_today: number;
|
|
448
|
+
top_tenants: Array<{
|
|
449
|
+
tenant_id: string;
|
|
450
|
+
requests_today: number;
|
|
451
|
+
tokens_used: number;
|
|
452
|
+
success_rate: number;
|
|
453
|
+
avg_latency_ms: number;
|
|
454
|
+
}>;
|
|
455
|
+
error_rate: number;
|
|
456
|
+
avg_latency_ms: number;
|
|
457
|
+
p95_latency_ms: number;
|
|
458
|
+
uptime_secs: number;
|
|
459
|
+
}
|
|
315
460
|
/** Minimal interface required by Conversation — implemented by both HttpClient and MockHttpClient */
|
|
316
461
|
interface ChatClientLike {
|
|
317
462
|
chat(request: ChatRequest, options?: RequestOptions): Promise<ChatResponse>;
|
|
@@ -435,6 +580,19 @@ declare class HttpClient {
|
|
|
435
580
|
* @returns Upload confirmation with document_id and chunks_count
|
|
436
581
|
*/
|
|
437
582
|
ragUpload(content: string, filename?: string, options?: RequestOptions): Promise<RagUploadResponse>;
|
|
583
|
+
/**
|
|
584
|
+
* POST /v1/upload-file — Upload a file (PDF, DOCX, text, image) for RAG indexing.
|
|
585
|
+
*
|
|
586
|
+
* @param file - File content as Buffer/Uint8Array
|
|
587
|
+
* @param filename - The filename (determines content type detection)
|
|
588
|
+
* @param options - Optional title, tags, timeoutMs
|
|
589
|
+
* @returns Upload confirmation with quality scoring
|
|
590
|
+
*/
|
|
591
|
+
uploadFile(file: Uint8Array | Buffer, filename: string, options?: {
|
|
592
|
+
title?: string;
|
|
593
|
+
tags?: string;
|
|
594
|
+
timeoutMs?: number;
|
|
595
|
+
}): Promise<UploadFileResponse>;
|
|
438
596
|
/** POST /v1/query — Query RAG knowledge base */
|
|
439
597
|
ragQuery(query: string, topK?: number, options?: {
|
|
440
598
|
debug?: boolean;
|
|
@@ -469,6 +627,70 @@ declare class HttpClient {
|
|
|
469
627
|
orchestrate(prompt: string): Promise<OrchestratorResponse>;
|
|
470
628
|
/** POST /v1/orchestrator/parallel — Run all 4 specialists in parallel */
|
|
471
629
|
orchestrateParallel(prompt: string): Promise<OrchestratorResponse>;
|
|
630
|
+
/**
|
|
631
|
+
* POST /v1/fact-check — Verify claims against source context.
|
|
632
|
+
*
|
|
633
|
+
* @param request - Text and source context to verify
|
|
634
|
+
* @returns FactCheckResponse with verdict, action, and per-claim results
|
|
635
|
+
*
|
|
636
|
+
* @example
|
|
637
|
+
* ```typescript
|
|
638
|
+
* const result = await client.factCheck({
|
|
639
|
+
* text: 'Returns accepted within 60 days.',
|
|
640
|
+
* source_context: 'Our policy allows returns within 14 days.',
|
|
641
|
+
* mode: 'lexical',
|
|
642
|
+
* });
|
|
643
|
+
* console.log(result.verdict); // "rejected"
|
|
644
|
+
* ```
|
|
645
|
+
*/
|
|
646
|
+
factCheck(request: FactCheckRequest): Promise<FactCheckResponse>;
|
|
647
|
+
/**
|
|
648
|
+
* POST /v1/verify — Verify citations in AI-generated text.
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```ts
|
|
652
|
+
* const result = await client.verifyCitation({
|
|
653
|
+
* text: 'Rust was released in 2010 [Source: rust_book].',
|
|
654
|
+
* sources: [{ name: 'rust_book', content: 'Rust was first released in 2010.' }],
|
|
655
|
+
* });
|
|
656
|
+
* console.log(result.phantom_count); // 0
|
|
657
|
+
* ```
|
|
658
|
+
*/
|
|
659
|
+
verifyCitation(request: VerifyCitationRequest): Promise<VerifyCitationResponse>;
|
|
660
|
+
/**
|
|
661
|
+
* POST /v1/fact-check — Verify text claims against source context.
|
|
662
|
+
*
|
|
663
|
+
* Guard is a hallucination firewall: checks whether LLM output is
|
|
664
|
+
* supported by source documents. Blocks wrong answers before users see them.
|
|
665
|
+
*
|
|
666
|
+
* @param text - The LLM-generated text to verify
|
|
667
|
+
* @param sourceContext - The ground-truth source document(s)
|
|
668
|
+
* @param mode - "lexical" (<1ms), "hybrid" (~50ms), or "semantic" (~500ms)
|
|
669
|
+
*
|
|
670
|
+
* @example
|
|
671
|
+
* ```typescript
|
|
672
|
+
* const result = await client.guard(
|
|
673
|
+
* 'Returns accepted within 60 days',
|
|
674
|
+
* 'Our return policy: 14 days.',
|
|
675
|
+
* );
|
|
676
|
+
* if (guardIsBlocked(result)) {
|
|
677
|
+
* console.log('Hallucination caught:', result.claims[0]?.reason);
|
|
678
|
+
* }
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
681
|
+
guard(text: string, sourceContext: string, mode?: GuardMode): Promise<GuardResponse>;
|
|
682
|
+
/**
|
|
683
|
+
* GET /v1/insights — ROI metrics for your API key
|
|
684
|
+
*/
|
|
685
|
+
getInsights(): Promise<InsightsResponse>;
|
|
686
|
+
/**
|
|
687
|
+
* GET /v1/analytics — Usage analytics and cache performance
|
|
688
|
+
*/
|
|
689
|
+
getAnalytics(minutes?: number): Promise<AnalyticsResponse>;
|
|
690
|
+
/**
|
|
691
|
+
* GET /v1/analytics/traffic — Per-tenant traffic monitoring
|
|
692
|
+
*/
|
|
693
|
+
getAnalyticsTraffic(): Promise<TrafficSummary>;
|
|
472
694
|
}
|
|
473
695
|
|
|
474
696
|
/**
|
|
@@ -539,6 +761,17 @@ declare class MockHttpClient {
|
|
|
539
761
|
system?: string;
|
|
540
762
|
model?: string;
|
|
541
763
|
}): Conversation;
|
|
764
|
+
uploadFile(_file: Uint8Array | Buffer, filename: string, options?: {
|
|
765
|
+
title?: string;
|
|
766
|
+
tags?: string;
|
|
767
|
+
timeoutMs?: number;
|
|
768
|
+
}): Promise<UploadFileResponse>;
|
|
769
|
+
factCheck(request: FactCheckRequest): Promise<FactCheckResponse>;
|
|
770
|
+
guard(text: string, sourceContext: string, mode?: 'lexical' | 'hybrid' | 'semantic'): Promise<GuardResponse>;
|
|
771
|
+
verifyCitation(request: VerifyCitationRequest): Promise<VerifyCitationResponse>;
|
|
772
|
+
getInsights(): Promise<InsightsResponse>;
|
|
773
|
+
getAnalytics(minutes?: number): Promise<AnalyticsResponse>;
|
|
774
|
+
getAnalyticsTraffic(): Promise<TrafficSummary>;
|
|
542
775
|
ragAsk(question: string, text: string, source?: string): Promise<string>;
|
|
543
776
|
private record;
|
|
544
777
|
}
|
|
@@ -589,4 +822,4 @@ declare class ToolNotFoundError extends WauldoError {
|
|
|
589
822
|
constructor(toolName: string);
|
|
590
823
|
}
|
|
591
824
|
|
|
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 };
|
|
825
|
+
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,117 @@ 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
|
+
* POST /v1/fact-check — Verify text claims against source context.
|
|
1204
|
+
*
|
|
1205
|
+
* Guard is a hallucination firewall: checks whether LLM output is
|
|
1206
|
+
* supported by source documents. Blocks wrong answers before users see them.
|
|
1207
|
+
*
|
|
1208
|
+
* @param text - The LLM-generated text to verify
|
|
1209
|
+
* @param sourceContext - The ground-truth source document(s)
|
|
1210
|
+
* @param mode - "lexical" (<1ms), "hybrid" (~50ms), or "semantic" (~500ms)
|
|
1211
|
+
*
|
|
1212
|
+
* @example
|
|
1213
|
+
* ```typescript
|
|
1214
|
+
* const result = await client.guard(
|
|
1215
|
+
* 'Returns accepted within 60 days',
|
|
1216
|
+
* 'Our return policy: 14 days.',
|
|
1217
|
+
* );
|
|
1218
|
+
* if (guardIsBlocked(result)) {
|
|
1219
|
+
* console.log('Hallucination caught:', result.claims[0]?.reason);
|
|
1220
|
+
* }
|
|
1221
|
+
* ```
|
|
1222
|
+
*/
|
|
1223
|
+
async guard(text, sourceContext, mode = "lexical") {
|
|
1224
|
+
const data = await fetchWithRetry(
|
|
1225
|
+
this.retryConfig,
|
|
1226
|
+
"POST",
|
|
1227
|
+
"/v1/fact-check",
|
|
1228
|
+
{ text, source_context: sourceContext, mode }
|
|
1229
|
+
);
|
|
1230
|
+
return validateResponse(data, "GuardResponse");
|
|
1231
|
+
}
|
|
1232
|
+
// ── Analytics & Insights endpoints ───────────────────────────────────
|
|
1233
|
+
/**
|
|
1234
|
+
* GET /v1/insights — ROI metrics for your API key
|
|
1235
|
+
*/
|
|
1236
|
+
async getInsights() {
|
|
1237
|
+
const data = await fetchWithRetry(
|
|
1238
|
+
this.retryConfig,
|
|
1239
|
+
"GET",
|
|
1240
|
+
"/v1/insights"
|
|
1241
|
+
);
|
|
1242
|
+
return validateResponse(data, "InsightsResponse");
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* GET /v1/analytics — Usage analytics and cache performance
|
|
1246
|
+
*/
|
|
1247
|
+
async getAnalytics(minutes = 60) {
|
|
1248
|
+
const data = await fetchWithRetry(
|
|
1249
|
+
this.retryConfig,
|
|
1250
|
+
"GET",
|
|
1251
|
+
`/v1/analytics?minutes=${minutes}`
|
|
1252
|
+
);
|
|
1253
|
+
return validateResponse(data, "AnalyticsResponse");
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* GET /v1/analytics/traffic — Per-tenant traffic monitoring
|
|
1257
|
+
*/
|
|
1258
|
+
async getAnalyticsTraffic() {
|
|
1259
|
+
const data = await fetchWithRetry(
|
|
1260
|
+
this.retryConfig,
|
|
1261
|
+
"GET",
|
|
1262
|
+
"/v1/analytics/traffic"
|
|
1263
|
+
);
|
|
1264
|
+
return validateResponse(data, "TrafficSummary");
|
|
1265
|
+
}
|
|
1100
1266
|
};
|
|
1101
1267
|
|
|
1102
1268
|
// src/mock_client.ts
|
|
@@ -1200,6 +1366,146 @@ var MockHttpClient = class {
|
|
|
1200
1366
|
this.record("conversation", options);
|
|
1201
1367
|
return new Conversation(this, options);
|
|
1202
1368
|
}
|
|
1369
|
+
async uploadFile(_file, filename, options) {
|
|
1370
|
+
this.record("uploadFile", filename, options);
|
|
1371
|
+
return {
|
|
1372
|
+
document_id: "mock-doc-file-1",
|
|
1373
|
+
chunks_count: 5,
|
|
1374
|
+
indexed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1375
|
+
content_type: "application/pdf",
|
|
1376
|
+
trace_id: "mock-trace-1",
|
|
1377
|
+
quality: {
|
|
1378
|
+
score: 0.85,
|
|
1379
|
+
label: "good",
|
|
1380
|
+
word_count: 1200,
|
|
1381
|
+
line_density: 8.5,
|
|
1382
|
+
avg_line_length: 72,
|
|
1383
|
+
paragraph_count: 15
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
async factCheck(request) {
|
|
1388
|
+
this.record("factCheck", request);
|
|
1389
|
+
const hasConflict = request.text !== request.source_context;
|
|
1390
|
+
return {
|
|
1391
|
+
verdict: hasConflict ? "rejected" : "verified",
|
|
1392
|
+
action: hasConflict ? "block" : "allow",
|
|
1393
|
+
hallucination_rate: hasConflict ? 1 : 0,
|
|
1394
|
+
mode: request.mode ?? "lexical",
|
|
1395
|
+
total_claims: 1,
|
|
1396
|
+
supported_claims: hasConflict ? 0 : 1,
|
|
1397
|
+
confidence: hasConflict ? 0.25 : 0.92,
|
|
1398
|
+
claims: [{
|
|
1399
|
+
text: request.text,
|
|
1400
|
+
claim_type: "factual",
|
|
1401
|
+
supported: !hasConflict,
|
|
1402
|
+
confidence: hasConflict ? 0.25 : 0.92,
|
|
1403
|
+
confidence_label: hasConflict ? "low" : "high",
|
|
1404
|
+
verdict: hasConflict ? "rejected" : "verified",
|
|
1405
|
+
action: hasConflict ? "block" : "allow",
|
|
1406
|
+
reason: hasConflict ? "numerical_mismatch" : null,
|
|
1407
|
+
evidence: request.source_context
|
|
1408
|
+
}],
|
|
1409
|
+
processing_time_ms: 1
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
async guard(text, sourceContext, mode = "lexical") {
|
|
1413
|
+
this.record("guard", text, sourceContext, mode);
|
|
1414
|
+
return {
|
|
1415
|
+
verdict: "verified",
|
|
1416
|
+
action: "allow",
|
|
1417
|
+
hallucination_rate: 0,
|
|
1418
|
+
mode,
|
|
1419
|
+
total_claims: 1,
|
|
1420
|
+
supported_claims: 1,
|
|
1421
|
+
confidence: 0.95,
|
|
1422
|
+
claims: [{
|
|
1423
|
+
text,
|
|
1424
|
+
claim_type: "Fact",
|
|
1425
|
+
supported: true,
|
|
1426
|
+
confidence: 0.95,
|
|
1427
|
+
confidence_label: "high",
|
|
1428
|
+
verdict: "verified",
|
|
1429
|
+
action: "allow",
|
|
1430
|
+
reason: null,
|
|
1431
|
+
evidence: sourceContext
|
|
1432
|
+
}],
|
|
1433
|
+
processing_time_ms: 0
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
async verifyCitation(request) {
|
|
1437
|
+
this.record("verifyCitation", request);
|
|
1438
|
+
const citations = request.text.match(/\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/g) ?? [];
|
|
1439
|
+
const sentences = request.text.split(/[.!?]+/).filter((s) => s.trim().length > 0);
|
|
1440
|
+
const citedSentences = sentences.filter((s) => /\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/.test(s));
|
|
1441
|
+
const ratio = sentences.length > 0 ? citedSentences.length / sentences.length : 0;
|
|
1442
|
+
return {
|
|
1443
|
+
citation_ratio: ratio,
|
|
1444
|
+
has_sufficient_citations: ratio >= (request.threshold ?? 0.5),
|
|
1445
|
+
sentence_count: sentences.length,
|
|
1446
|
+
citation_count: citations.length,
|
|
1447
|
+
uncited_sentences: sentences.filter((s) => !/\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/.test(s)).map((s) => s.trim()),
|
|
1448
|
+
citations: citations.map((c) => ({
|
|
1449
|
+
citation: c,
|
|
1450
|
+
source_name: c.replace(/[\[\]]/g, "").replace("Source: ", ""),
|
|
1451
|
+
is_valid: (request.sources ?? []).some((src) => c.includes(src.name))
|
|
1452
|
+
})),
|
|
1453
|
+
phantom_count: 0,
|
|
1454
|
+
processing_time_ms: 1
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
async getInsights() {
|
|
1458
|
+
this.record("getInsights");
|
|
1459
|
+
return {
|
|
1460
|
+
tig_key: "mock-tig-key",
|
|
1461
|
+
total_requests: 1250,
|
|
1462
|
+
intelligence_requests: 980,
|
|
1463
|
+
fallback_requests: 270,
|
|
1464
|
+
tokens: {
|
|
1465
|
+
baseline_total: 5e5,
|
|
1466
|
+
real_total: 325e3,
|
|
1467
|
+
saved_total: 175e3,
|
|
1468
|
+
saved_percent_avg: 35
|
|
1469
|
+
},
|
|
1470
|
+
cost: {
|
|
1471
|
+
estimated_usd_saved: 12.5
|
|
1472
|
+
}
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
async getAnalytics(minutes = 60) {
|
|
1476
|
+
this.record("getAnalytics", minutes);
|
|
1477
|
+
return {
|
|
1478
|
+
cache: {
|
|
1479
|
+
total_requests: 450,
|
|
1480
|
+
cache_hit_rate: 0.42,
|
|
1481
|
+
avg_latency_ms: 180,
|
|
1482
|
+
p95_latency_ms: 850
|
|
1483
|
+
},
|
|
1484
|
+
tokens: {
|
|
1485
|
+
total_baseline: 12e4,
|
|
1486
|
+
total_real: 78e3,
|
|
1487
|
+
total_saved: 42e3,
|
|
1488
|
+
avg_savings_percent: 35
|
|
1489
|
+
},
|
|
1490
|
+
uptime_secs: 86400
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
async getAnalyticsTraffic() {
|
|
1494
|
+
this.record("getAnalyticsTraffic");
|
|
1495
|
+
return {
|
|
1496
|
+
total_requests_today: 3200,
|
|
1497
|
+
total_tokens_today: 15e5,
|
|
1498
|
+
top_tenants: [
|
|
1499
|
+
{ tenant_id: "tenant-alpha", requests_today: 1200, tokens_used: 58e4, success_rate: 0.98, avg_latency_ms: 220 },
|
|
1500
|
+
{ tenant_id: "tenant-beta", requests_today: 850, tokens_used: 42e4, success_rate: 0.96, avg_latency_ms: 310 },
|
|
1501
|
+
{ tenant_id: "tenant-gamma", requests_today: 600, tokens_used: 28e4, success_rate: 0.99, avg_latency_ms: 150 }
|
|
1502
|
+
],
|
|
1503
|
+
error_rate: 0.02,
|
|
1504
|
+
avg_latency_ms: 240,
|
|
1505
|
+
p95_latency_ms: 890,
|
|
1506
|
+
uptime_secs: 86400
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1203
1509
|
async ragAsk(question, text, source = "document") {
|
|
1204
1510
|
this.record("ragAsk", question, text, source);
|
|
1205
1511
|
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,117 @@ 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
|
+
* POST /v1/fact-check — Verify text claims against source context.
|
|
1168
|
+
*
|
|
1169
|
+
* Guard is a hallucination firewall: checks whether LLM output is
|
|
1170
|
+
* supported by source documents. Blocks wrong answers before users see them.
|
|
1171
|
+
*
|
|
1172
|
+
* @param text - The LLM-generated text to verify
|
|
1173
|
+
* @param sourceContext - The ground-truth source document(s)
|
|
1174
|
+
* @param mode - "lexical" (<1ms), "hybrid" (~50ms), or "semantic" (~500ms)
|
|
1175
|
+
*
|
|
1176
|
+
* @example
|
|
1177
|
+
* ```typescript
|
|
1178
|
+
* const result = await client.guard(
|
|
1179
|
+
* 'Returns accepted within 60 days',
|
|
1180
|
+
* 'Our return policy: 14 days.',
|
|
1181
|
+
* );
|
|
1182
|
+
* if (guardIsBlocked(result)) {
|
|
1183
|
+
* console.log('Hallucination caught:', result.claims[0]?.reason);
|
|
1184
|
+
* }
|
|
1185
|
+
* ```
|
|
1186
|
+
*/
|
|
1187
|
+
async guard(text, sourceContext, mode = "lexical") {
|
|
1188
|
+
const data = await fetchWithRetry(
|
|
1189
|
+
this.retryConfig,
|
|
1190
|
+
"POST",
|
|
1191
|
+
"/v1/fact-check",
|
|
1192
|
+
{ text, source_context: sourceContext, mode }
|
|
1193
|
+
);
|
|
1194
|
+
return validateResponse(data, "GuardResponse");
|
|
1195
|
+
}
|
|
1196
|
+
// ── Analytics & Insights endpoints ───────────────────────────────────
|
|
1197
|
+
/**
|
|
1198
|
+
* GET /v1/insights — ROI metrics for your API key
|
|
1199
|
+
*/
|
|
1200
|
+
async getInsights() {
|
|
1201
|
+
const data = await fetchWithRetry(
|
|
1202
|
+
this.retryConfig,
|
|
1203
|
+
"GET",
|
|
1204
|
+
"/v1/insights"
|
|
1205
|
+
);
|
|
1206
|
+
return validateResponse(data, "InsightsResponse");
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* GET /v1/analytics — Usage analytics and cache performance
|
|
1210
|
+
*/
|
|
1211
|
+
async getAnalytics(minutes = 60) {
|
|
1212
|
+
const data = await fetchWithRetry(
|
|
1213
|
+
this.retryConfig,
|
|
1214
|
+
"GET",
|
|
1215
|
+
`/v1/analytics?minutes=${minutes}`
|
|
1216
|
+
);
|
|
1217
|
+
return validateResponse(data, "AnalyticsResponse");
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* GET /v1/analytics/traffic — Per-tenant traffic monitoring
|
|
1221
|
+
*/
|
|
1222
|
+
async getAnalyticsTraffic() {
|
|
1223
|
+
const data = await fetchWithRetry(
|
|
1224
|
+
this.retryConfig,
|
|
1225
|
+
"GET",
|
|
1226
|
+
"/v1/analytics/traffic"
|
|
1227
|
+
);
|
|
1228
|
+
return validateResponse(data, "TrafficSummary");
|
|
1229
|
+
}
|
|
1064
1230
|
};
|
|
1065
1231
|
|
|
1066
1232
|
// src/mock_client.ts
|
|
@@ -1164,6 +1330,146 @@ var MockHttpClient = class {
|
|
|
1164
1330
|
this.record("conversation", options);
|
|
1165
1331
|
return new Conversation(this, options);
|
|
1166
1332
|
}
|
|
1333
|
+
async uploadFile(_file, filename, options) {
|
|
1334
|
+
this.record("uploadFile", filename, options);
|
|
1335
|
+
return {
|
|
1336
|
+
document_id: "mock-doc-file-1",
|
|
1337
|
+
chunks_count: 5,
|
|
1338
|
+
indexed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1339
|
+
content_type: "application/pdf",
|
|
1340
|
+
trace_id: "mock-trace-1",
|
|
1341
|
+
quality: {
|
|
1342
|
+
score: 0.85,
|
|
1343
|
+
label: "good",
|
|
1344
|
+
word_count: 1200,
|
|
1345
|
+
line_density: 8.5,
|
|
1346
|
+
avg_line_length: 72,
|
|
1347
|
+
paragraph_count: 15
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
async factCheck(request) {
|
|
1352
|
+
this.record("factCheck", request);
|
|
1353
|
+
const hasConflict = request.text !== request.source_context;
|
|
1354
|
+
return {
|
|
1355
|
+
verdict: hasConflict ? "rejected" : "verified",
|
|
1356
|
+
action: hasConflict ? "block" : "allow",
|
|
1357
|
+
hallucination_rate: hasConflict ? 1 : 0,
|
|
1358
|
+
mode: request.mode ?? "lexical",
|
|
1359
|
+
total_claims: 1,
|
|
1360
|
+
supported_claims: hasConflict ? 0 : 1,
|
|
1361
|
+
confidence: hasConflict ? 0.25 : 0.92,
|
|
1362
|
+
claims: [{
|
|
1363
|
+
text: request.text,
|
|
1364
|
+
claim_type: "factual",
|
|
1365
|
+
supported: !hasConflict,
|
|
1366
|
+
confidence: hasConflict ? 0.25 : 0.92,
|
|
1367
|
+
confidence_label: hasConflict ? "low" : "high",
|
|
1368
|
+
verdict: hasConflict ? "rejected" : "verified",
|
|
1369
|
+
action: hasConflict ? "block" : "allow",
|
|
1370
|
+
reason: hasConflict ? "numerical_mismatch" : null,
|
|
1371
|
+
evidence: request.source_context
|
|
1372
|
+
}],
|
|
1373
|
+
processing_time_ms: 1
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
async guard(text, sourceContext, mode = "lexical") {
|
|
1377
|
+
this.record("guard", text, sourceContext, mode);
|
|
1378
|
+
return {
|
|
1379
|
+
verdict: "verified",
|
|
1380
|
+
action: "allow",
|
|
1381
|
+
hallucination_rate: 0,
|
|
1382
|
+
mode,
|
|
1383
|
+
total_claims: 1,
|
|
1384
|
+
supported_claims: 1,
|
|
1385
|
+
confidence: 0.95,
|
|
1386
|
+
claims: [{
|
|
1387
|
+
text,
|
|
1388
|
+
claim_type: "Fact",
|
|
1389
|
+
supported: true,
|
|
1390
|
+
confidence: 0.95,
|
|
1391
|
+
confidence_label: "high",
|
|
1392
|
+
verdict: "verified",
|
|
1393
|
+
action: "allow",
|
|
1394
|
+
reason: null,
|
|
1395
|
+
evidence: sourceContext
|
|
1396
|
+
}],
|
|
1397
|
+
processing_time_ms: 0
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
async verifyCitation(request) {
|
|
1401
|
+
this.record("verifyCitation", request);
|
|
1402
|
+
const citations = request.text.match(/\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/g) ?? [];
|
|
1403
|
+
const sentences = request.text.split(/[.!?]+/).filter((s) => s.trim().length > 0);
|
|
1404
|
+
const citedSentences = sentences.filter((s) => /\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/.test(s));
|
|
1405
|
+
const ratio = sentences.length > 0 ? citedSentences.length / sentences.length : 0;
|
|
1406
|
+
return {
|
|
1407
|
+
citation_ratio: ratio,
|
|
1408
|
+
has_sufficient_citations: ratio >= (request.threshold ?? 0.5),
|
|
1409
|
+
sentence_count: sentences.length,
|
|
1410
|
+
citation_count: citations.length,
|
|
1411
|
+
uncited_sentences: sentences.filter((s) => !/\[(?:Source:\s*[^\]]+|\d+|Ref:\s*[^\]]+)\]/.test(s)).map((s) => s.trim()),
|
|
1412
|
+
citations: citations.map((c) => ({
|
|
1413
|
+
citation: c,
|
|
1414
|
+
source_name: c.replace(/[\[\]]/g, "").replace("Source: ", ""),
|
|
1415
|
+
is_valid: (request.sources ?? []).some((src) => c.includes(src.name))
|
|
1416
|
+
})),
|
|
1417
|
+
phantom_count: 0,
|
|
1418
|
+
processing_time_ms: 1
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
async getInsights() {
|
|
1422
|
+
this.record("getInsights");
|
|
1423
|
+
return {
|
|
1424
|
+
tig_key: "mock-tig-key",
|
|
1425
|
+
total_requests: 1250,
|
|
1426
|
+
intelligence_requests: 980,
|
|
1427
|
+
fallback_requests: 270,
|
|
1428
|
+
tokens: {
|
|
1429
|
+
baseline_total: 5e5,
|
|
1430
|
+
real_total: 325e3,
|
|
1431
|
+
saved_total: 175e3,
|
|
1432
|
+
saved_percent_avg: 35
|
|
1433
|
+
},
|
|
1434
|
+
cost: {
|
|
1435
|
+
estimated_usd_saved: 12.5
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
async getAnalytics(minutes = 60) {
|
|
1440
|
+
this.record("getAnalytics", minutes);
|
|
1441
|
+
return {
|
|
1442
|
+
cache: {
|
|
1443
|
+
total_requests: 450,
|
|
1444
|
+
cache_hit_rate: 0.42,
|
|
1445
|
+
avg_latency_ms: 180,
|
|
1446
|
+
p95_latency_ms: 850
|
|
1447
|
+
},
|
|
1448
|
+
tokens: {
|
|
1449
|
+
total_baseline: 12e4,
|
|
1450
|
+
total_real: 78e3,
|
|
1451
|
+
total_saved: 42e3,
|
|
1452
|
+
avg_savings_percent: 35
|
|
1453
|
+
},
|
|
1454
|
+
uptime_secs: 86400
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
async getAnalyticsTraffic() {
|
|
1458
|
+
this.record("getAnalyticsTraffic");
|
|
1459
|
+
return {
|
|
1460
|
+
total_requests_today: 3200,
|
|
1461
|
+
total_tokens_today: 15e5,
|
|
1462
|
+
top_tenants: [
|
|
1463
|
+
{ tenant_id: "tenant-alpha", requests_today: 1200, tokens_used: 58e4, success_rate: 0.98, avg_latency_ms: 220 },
|
|
1464
|
+
{ tenant_id: "tenant-beta", requests_today: 850, tokens_used: 42e4, success_rate: 0.96, avg_latency_ms: 310 },
|
|
1465
|
+
{ tenant_id: "tenant-gamma", requests_today: 600, tokens_used: 28e4, success_rate: 0.99, avg_latency_ms: 150 }
|
|
1466
|
+
],
|
|
1467
|
+
error_rate: 0.02,
|
|
1468
|
+
avg_latency_ms: 240,
|
|
1469
|
+
p95_latency_ms: 890,
|
|
1470
|
+
uptime_secs: 86400
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1167
1473
|
async ragAsk(question, text, source = "document") {
|
|
1168
1474
|
this.record("ragAsk", question, text, source);
|
|
1169
1475
|
await this.ragUpload(text, source);
|