wauldo 0.6.0 → 0.7.1

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/dist/index.mjs CHANGED
@@ -864,16 +864,6 @@ 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
- }
877
867
  function validateResponse(data, typeName) {
878
868
  if (data === null || data === void 0) {
879
869
  throw new ServerError(`Invalid ${typeName}: response is null`, 0);
@@ -1008,51 +998,6 @@ var HttpClient = class {
1008
998
  );
1009
999
  return validateResponse(data, "RagUploadResponse");
1010
1000
  }
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
- }
1056
1001
  /** POST /v1/query — Query RAG knowledge base */
1057
1002
  async ragQuery(query, topK = 5, options) {
1058
1003
  const body = { query, top_k: topK };
@@ -1095,122 +1040,59 @@ ${options.tags}\r
1095
1040
  const result = await this.ragQuery(question, 3);
1096
1041
  return result.answer ?? JSON.stringify(result.sources);
1097
1042
  }
1098
- // ── Orchestrator endpoints ───────────────────────────────────────────
1099
- /** POST /v1/orchestrator/execute — Route to best specialist agent */
1100
- async orchestrate(prompt) {
1101
- const data = await fetchWithRetry(
1102
- this.retryConfig,
1103
- "POST",
1104
- "/v1/orchestrator/execute",
1105
- { prompt }
1106
- );
1107
- return validateResponse(data, "OrchestratorResponse");
1108
- }
1109
- /** POST /v1/orchestrator/parallel — Run all 4 specialists in parallel */
1110
- async orchestrateParallel(prompt) {
1111
- const data = await fetchWithRetry(
1112
- this.retryConfig,
1113
- "POST",
1114
- "/v1/orchestrator/parallel",
1115
- { prompt }
1116
- );
1117
- return validateResponse(data, "OrchestratorResponse");
1118
- }
1119
- // ── Fact-Check endpoints ──────────────────────────────────────────────
1043
+ // ── Guard (Fact-Check) ─────────────────────────────────────────────
1120
1044
  /**
1121
- * POST /v1/fact-check — Verify claims against source context.
1045
+ * POST /v1/fact-check — Verify text claims against source context.
1046
+ *
1047
+ * Guard is a hallucination firewall: checks whether LLM output is supported
1048
+ * by source documents. Blocks wrong answers before they reach users.
1122
1049
  *
1123
- * @param request - Text and source context to verify
1124
- * @returns FactCheckResponse with verdict, action, and per-claim results
1050
+ * @param text - The LLM-generated text to verify
1051
+ * @param sourceContext - The ground-truth source document(s)
1052
+ * @param mode - "lexical" (<1ms), "hybrid" (~50ms), or "semantic" (~500ms)
1053
+ * @param options - Optional per-request overrides
1125
1054
  *
1126
1055
  * @example
1127
1056
  * ```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"
1057
+ * const result = await client.guard(
1058
+ * 'Returns accepted within 60 days',
1059
+ * 'Our return policy: 14 days.',
1060
+ * );
1061
+ * if (result.action === 'block') {
1062
+ * console.log('Hallucination caught:', result.claims[0]?.reason);
1063
+ * }
1134
1064
  * ```
1135
1065
  */
1136
- async factCheck(request) {
1066
+ async guard(text, sourceContext, mode = "lexical", options) {
1137
1067
  const data = await fetchWithRetry(
1138
1068
  this.retryConfig,
1139
1069
  "POST",
1140
1070
  "/v1/fact-check",
1141
- request
1071
+ { text, source_context: sourceContext, mode },
1072
+ options?.timeoutMs
1142
1073
  );
1143
- return validateResponse(data, "FactCheckResponse");
1074
+ return validateResponse(data, "GuardResponse");
1144
1075
  }
1145
- /**
1146
- * POST /v1/verifyVerify 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) {
1076
+ // ── Orchestrator endpoints ───────────────────────────────────────────
1077
+ /** POST /v1/orchestrator/executeRoute to best specialist agent */
1078
+ async orchestrate(prompt) {
1158
1079
  const data = await fetchWithRetry(
1159
1080
  this.retryConfig,
1160
1081
  "POST",
1161
- "/v1/verify",
1162
- request
1163
- );
1164
- return validateResponse(data, "VerifyCitationResponse");
1165
- }
1166
- /**
1167
- * Verify an LLM output against a source document.
1168
- * Convenience wrapper around factCheck(). Returns a simple safe/unsafe result.
1169
- */
1170
- async guard(text, source, mode = "lexical") {
1171
- const result = await this.factCheck({ text, source_context: source, mode });
1172
- const claim = result.claims?.[0];
1173
- return {
1174
- safe: claim?.verdict === "verified",
1175
- verdict: claim?.verdict ?? "rejected",
1176
- action: claim?.action ?? "block",
1177
- reason: claim?.reason ?? "no_claims",
1178
- confidence: claim?.confidence ?? 0
1179
- };
1180
- }
1181
- // ── Analytics & Insights endpoints ───────────────────────────────────
1182
- /**
1183
- * GET /v1/insights — ROI metrics for your API key
1184
- */
1185
- async getInsights() {
1186
- const data = await fetchWithRetry(
1187
- this.retryConfig,
1188
- "GET",
1189
- "/v1/insights"
1190
- );
1191
- return validateResponse(data, "InsightsResponse");
1192
- }
1193
- /**
1194
- * GET /v1/analytics — Usage analytics and cache performance
1195
- */
1196
- async getAnalytics(minutes = 60) {
1197
- const data = await fetchWithRetry(
1198
- this.retryConfig,
1199
- "GET",
1200
- `/v1/analytics?minutes=${minutes}`
1082
+ "/v1/orchestrator/execute",
1083
+ { prompt }
1201
1084
  );
1202
- return validateResponse(data, "AnalyticsResponse");
1085
+ return validateResponse(data, "OrchestratorResponse");
1203
1086
  }
1204
- /**
1205
- * GET /v1/analytics/traffic — Per-tenant traffic monitoring
1206
- */
1207
- async getAnalyticsTraffic() {
1087
+ /** POST /v1/orchestrator/parallel — Run all 4 specialists in parallel */
1088
+ async orchestrateParallel(prompt) {
1208
1089
  const data = await fetchWithRetry(
1209
1090
  this.retryConfig,
1210
- "GET",
1211
- "/v1/analytics/traffic"
1091
+ "POST",
1092
+ "/v1/orchestrator/parallel",
1093
+ { prompt }
1212
1094
  );
1213
- return validateResponse(data, "TrafficSummary");
1095
+ return validateResponse(data, "OrchestratorResponse");
1214
1096
  }
1215
1097
  };
1216
1098
 
@@ -1315,132 +1197,6 @@ var MockHttpClient = class {
1315
1197
  this.record("conversation", options);
1316
1198
  return new Conversation(this, options);
1317
1199
  }
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
- }
1444
1200
  async ragAsk(question, text, source = "document") {
1445
1201
  this.record("ragAsk", question, text, source);
1446
1202
  await this.ragUpload(text, source);
@@ -1456,6 +1212,12 @@ var MockHttpClient = class {
1456
1212
  function chatContent(response) {
1457
1213
  return response.choices[0]?.message?.content ?? "";
1458
1214
  }
1215
+ function guardIsSafe(response) {
1216
+ return response.verdict === "verified";
1217
+ }
1218
+ function guardIsBlocked(response) {
1219
+ return response.action === "block";
1220
+ }
1459
1221
  export {
1460
1222
  AgentClient,
1461
1223
  ConnectionError,
@@ -1467,5 +1229,7 @@ export {
1467
1229
  ToolNotFoundError,
1468
1230
  ValidationError,
1469
1231
  WauldoError,
1470
- chatContent
1232
+ chatContent,
1233
+ guardIsBlocked,
1234
+ guardIsSafe
1471
1235
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wauldo",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
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",