@devilsdev/rag-core 3.4.0 → 3.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.
Files changed (67) hide show
  1. package/README.md +1 -1
  2. package/dist/all.d.ts +59 -0
  3. package/dist/index.cjs +443 -48
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.mjs +1 -1
  6. package/dist/types/adapters/mastra.d.ts +6 -2
  7. package/dist/types/agentic/agentic-pipeline.d.ts +1 -1
  8. package/dist/types/agentic/iterative-retriever.d.ts +1 -1
  9. package/dist/types/agentic/query-planner.d.ts +1 -1
  10. package/dist/types/agentic/self-critique.d.ts +1 -1
  11. package/dist/types/ai/federation/federated-learning-coordinator.d.ts +1 -1
  12. package/dist/types/ai/training/model-training-orchestrator.d.ts +1 -1
  13. package/dist/types/chunking/chunking-engine.d.ts +1 -1
  14. package/dist/types/citation/citation-tracker.d.ts +1 -1
  15. package/dist/types/config/component-factory.d.ts +1 -0
  16. package/dist/types/connectors/anthropic-connector.d.ts +35 -1
  17. package/dist/types/connectors/base-connector.d.ts +1 -1
  18. package/dist/types/connectors/connector-utils.d.ts +20 -0
  19. package/dist/types/cost/cost-calculator.d.ts +1 -1
  20. package/dist/types/cost/cost-tracker.d.ts +1 -1
  21. package/dist/types/cost/token-budget.d.ts +1 -1
  22. package/dist/types/dashboard/dashboard-generator.d.ts +1 -1
  23. package/dist/types/dashboard/metrics-aggregator.d.ts +1 -1
  24. package/dist/types/debug/execution-tracer.d.ts +1 -1
  25. package/dist/types/debug/trace-inspector.d.ts +1 -1
  26. package/dist/types/dev/dev-server.d.ts +1 -1
  27. package/dist/types/dev/hot-reload.d.ts +1 -1
  28. package/dist/types/ecosystem/plugin-analytics-dashboard.d.ts +1 -1
  29. package/dist/types/ecosystem/plugin-certification.d.ts +1 -1
  30. package/dist/types/ecosystem/plugin-hub.d.ts +1 -1
  31. package/dist/types/enterprise/audit-logging.d.ts +1 -1
  32. package/dist/types/enterprise/data-governance.d.ts +1 -1
  33. package/dist/types/enterprise/multi-tenancy.d.ts +1 -1
  34. package/dist/types/enterprise/sso-integration.d.ts +1 -1
  35. package/dist/types/evaluate/pipeline-evaluator.d.ts +1 -1
  36. package/dist/types/graph/entity-extractor.d.ts +1 -1
  37. package/dist/types/graph/graph-retriever.d.ts +1 -1
  38. package/dist/types/graph/knowledge-graph.d.ts +1 -1
  39. package/dist/types/grounding/llm-judge.d.ts +10 -3
  40. package/dist/types/grounding/provider-citations.d.ts +244 -0
  41. package/dist/types/guardrails/detectors.d.ts +88 -0
  42. package/dist/types/guardrails/evaluate-detectors.d.ts +61 -0
  43. package/dist/types/guardrails/guardrails-pipeline.d.ts +2 -9
  44. package/dist/types/guardrails/post-generation-guard.d.ts +33 -3
  45. package/dist/types/guardrails/pre-retrieval-guard.d.ts +29 -1
  46. package/dist/types/guardrails/retrieval-guard.d.ts +30 -1
  47. package/dist/types/mcp/mcp-server.d.ts +1 -1
  48. package/dist/types/observability/otel.d.ts +9 -3
  49. package/dist/types/observability/scores.d.ts +57 -0
  50. package/dist/types/reranker/cascade-reranker.d.ts +1 -1
  51. package/dist/types/reranker/embedding-reranker.d.ts +1 -1
  52. package/dist/types/reranker/scoring-reranker.d.ts +1 -1
  53. package/dist/types/retrieval/bm25-search.d.ts +1 -1
  54. package/dist/types/retrieval/hybrid-retriever.d.ts +1 -1
  55. package/dist/types/retrieval/pinecone-retriever.d.ts +141 -0
  56. package/dist/types/security/jwt-validator.d.ts +1 -1
  57. package/dist/types/security/plugin-sandbox.d.ts +1 -1
  58. package/dist/types/streaming/sse-adapter.d.ts +1 -1
  59. package/dist/types/streaming/stream-router.d.ts +1 -1
  60. package/dist/types/streaming/streaming-embedder.d.ts +1 -1
  61. package/dist/types/streaming/websocket-adapter.d.ts +1 -1
  62. package/dist/types/templates/scaffold.d.ts +1 -1
  63. package/dist/types/testing/contract-tests.d.ts +8 -4
  64. package/dist/types/utils/batch-processor.d.ts +1 -1
  65. package/dist/types/utils/connection-pool.d.ts +1 -1
  66. package/dist/types/utils/optional-peer.d.ts +21 -1
  67. package/package.json +2 -1
package/dist/index.cjs CHANGED
@@ -1291,12 +1291,74 @@ var require_context_packing = __commonJS({
1291
1291
  }
1292
1292
  });
1293
1293
 
1294
+ // src/observability/scores.js
1295
+ var require_scores = __commonJS({
1296
+ "src/observability/scores.js"(exports2, module2) {
1297
+ "use strict";
1298
+ var RETRIEVAL_METRICS = /* @__PURE__ */ new Set(["contextPrecision", "contextRecall"]);
1299
+ var isScore = (v) => typeof v === "number" && Number.isFinite(v);
1300
+ function evaluationScores(result, { explanations = false } = {}) {
1301
+ if (!result || typeof result !== "object") return [];
1302
+ const out = [];
1303
+ const scores = result.evaluation && result.evaluation.scores ? result.evaluation.scores : {};
1304
+ for (const [name, value] of Object.entries(scores)) {
1305
+ if (!isScore(value)) continue;
1306
+ out.push({
1307
+ name,
1308
+ value,
1309
+ target: RETRIEVAL_METRICS.has(name) ? "retrieval" : "generation"
1310
+ });
1311
+ }
1312
+ if (result.citations && isScore(result.citations.groundednessScore)) {
1313
+ out.push({
1314
+ name: "citationCoverage",
1315
+ value: result.citations.groundednessScore,
1316
+ target: "generation"
1317
+ });
1318
+ }
1319
+ if (typeof result.grounded === "boolean" && isScore(result.groundedness)) {
1320
+ const unsupported = Array.isArray(result.unsupported) ? result.unsupported : [];
1321
+ out.push({
1322
+ name: "groundedSentences",
1323
+ value: result.groundedness,
1324
+ target: "generation",
1325
+ label: result.grounded ? "grounded" : "ungrounded",
1326
+ ...explanations && unsupported.length > 0 && {
1327
+ explanation: `Unsupported: ${unsupported.map((s) => JSON.stringify(s)).join(" ")}`
1328
+ }
1329
+ });
1330
+ }
1331
+ return out;
1332
+ }
1333
+ function toLangfuseScores(result, options = {}) {
1334
+ const { observationId, sessionId, comments = false } = options;
1335
+ const tel = result && result.telemetry || {};
1336
+ const traceId = options.traceId || tel.traceId;
1337
+ const fromSameTrace = !options.traceId || options.traceId === tel.traceId;
1338
+ return evaluationScores(result, { explanations: comments }).map((s) => {
1339
+ const observation = observationId || (fromSameTrace && tel.spans ? tel.spans[s.target] : void 0);
1340
+ return {
1341
+ name: s.name,
1342
+ value: s.value,
1343
+ dataType: "NUMERIC",
1344
+ ...traceId && { traceId },
1345
+ ...observation && { observationId: observation },
1346
+ ...sessionId && { sessionId },
1347
+ ...s.explanation && { comment: s.explanation },
1348
+ ...s.label && { metadata: { label: s.label } }
1349
+ };
1350
+ });
1351
+ }
1352
+ module2.exports = { evaluationScores, toLangfuseScores };
1353
+ }
1354
+ });
1355
+
1294
1356
  // package.json
1295
1357
  var require_package = __commonJS({
1296
1358
  "package.json"(exports2, module2) {
1297
1359
  module2.exports = {
1298
1360
  name: "@devilsdev/rag-pipeline-utils",
1299
- version: "3.4.0",
1361
+ version: "3.6.0",
1300
1362
  description: "Composable retrieval-augmented generation (RAG) for Node.js: grounded citations, evaluation, guardrails, hybrid retrieval and a CLI.",
1301
1363
  main: "dist/index.cjs",
1302
1364
  type: "commonjs",
@@ -1314,6 +1376,7 @@ var require_package = __commonJS({
1314
1376
  exports: {
1315
1377
  ".": {
1316
1378
  types: "./dist/index.d.ts",
1379
+ workerd: "./dist/index.cjs",
1317
1380
  require: "./dist/index.cjs",
1318
1381
  import: "./dist/index.mjs"
1319
1382
  },
@@ -1342,6 +1405,8 @@ var require_package = __commonJS({
1342
1405
  scripts: {
1343
1406
  build: "node scripts/build-packages.js --bundles && node scripts/build.js && node scripts/generate-types.js && node scripts/build-packages.js --types && node scripts/check-type-exports.js",
1344
1407
  "test:packages": "node scripts/test-packages.js",
1408
+ "test:consumer": "node scripts/consumer-journeys.js",
1409
+ "test:templates": "node scripts/test-templates.js",
1345
1410
  prepack: "npm run build && node scripts/pin-readme-assets.js",
1346
1411
  postpack: "node scripts/pin-readme-assets.js --restore",
1347
1412
  "docs:validate": "node scripts/validate-docs-examples.js",
@@ -1392,6 +1457,12 @@ var require_package = __commonJS({
1392
1457
  "benchmark:full": "node scripts/benchmark.js --iterations=500 --verbose",
1393
1458
  "bench:speed": "node benchmarks/speed.js",
1394
1459
  "bench:quality": "node benchmarks/quality.js",
1460
+ "bench:guardrails": "node benchmarks/guardrails.js",
1461
+ "bench:judge": "node benchmarks/judge.js",
1462
+ "bench:claude-citations": "node benchmarks/claude-citations.js",
1463
+ "bench:judge-more": "node benchmarks/judge-more.js",
1464
+ "bench:claude-latency": "node benchmarks/claude-latency.js",
1465
+ "claude:usage": "node scripts/claude-usage-report.js && node benchmarks/render.js",
1395
1466
  dev: "node scripts/dev-tools.js menu",
1396
1467
  "dev:health": "node scripts/dev-tools.js health",
1397
1468
  "dev:setup": "node scripts/dev-tools.js setup",
@@ -1410,6 +1481,7 @@ var require_package = __commonJS({
1410
1481
  "tests:ci": "jest --maxWorkers=50% --reporters=default --json --outputFile=test-results-current.json",
1411
1482
  "test:unit": "jest __tests__/unit",
1412
1483
  "test:integration": "jest __tests__/integration",
1484
+ "test:live": "jest --config jest.live.config.js --runInBand",
1413
1485
  "test:simple": "jest --maxWorkers=1 --no-coverage",
1414
1486
  "verify:pack": "node scripts/verify-npm-pack.js",
1415
1487
  "smoke:pack": "node scripts/smoke-test-pack.js",
@@ -1489,6 +1561,8 @@ var require_package = __commonJS({
1489
1561
  "**/*.{json,md,mdx,yml,yaml,css,scss,html}": "prettier --write --ignore-unknown"
1490
1562
  },
1491
1563
  devDependencies: {
1564
+ "@ai-sdk/anthropic": "3.0.138",
1565
+ "@ai-sdk/anthropic-v4": "npm:@ai-sdk/anthropic@4.0.97",
1492
1566
  "@babel/core": "^7.26.10",
1493
1567
  "@babel/preset-env": "^7.26.9",
1494
1568
  "@docusaurus/core": "3.10.2",
@@ -1499,12 +1573,14 @@ var require_package = __commonJS({
1499
1573
  "@fontsource/jetbrains-mono": "5.3.0",
1500
1574
  "@octokit/rest": "^21.1.1",
1501
1575
  "@opentelemetry/api": "^1.9.1",
1576
+ "@opentelemetry/api-logs": "^0.223.0",
1502
1577
  "@opentelemetry/auto-instrumentations-node": "^0.52.1",
1503
1578
  "@opentelemetry/context-async-hooks": "^2.12.0",
1504
1579
  "@opentelemetry/exporter-jaeger": "^1.26.0",
1505
1580
  "@opentelemetry/exporter-prometheus": "^0.53.0",
1506
1581
  "@opentelemetry/exporter-trace-otlp-http": "^0.53.0",
1507
1582
  "@opentelemetry/resources": "^1.26.0",
1583
+ "@opentelemetry/sdk-logs": "^0.223.0",
1508
1584
  "@opentelemetry/sdk-metrics": "^1.26.0",
1509
1585
  "@opentelemetry/sdk-node": "^0.53.0",
1510
1586
  "@opentelemetry/sdk-trace-base": "^2.12.0",
@@ -1550,10 +1626,10 @@ var require_package = __commonJS({
1550
1626
  "why-is-node-running": "^3.2.2"
1551
1627
  },
1552
1628
  dependencies: {
1553
- "@devilsdev/rag-connectors": "3.4.0",
1554
- "@devilsdev/rag-core": "3.4.0",
1555
- "@devilsdev/rag-eval": "3.4.0",
1556
- "@devilsdev/rag-guardrails": "3.4.0",
1629
+ "@devilsdev/rag-connectors": "3.6.0",
1630
+ "@devilsdev/rag-core": "3.6.0",
1631
+ "@devilsdev/rag-eval": "3.6.0",
1632
+ "@devilsdev/rag-guardrails": "3.6.0",
1557
1633
  ajv: "^8.17.1",
1558
1634
  axios: "^1.21.0",
1559
1635
  chokidar: "^4.0.3",
@@ -1623,12 +1699,18 @@ var require_optional_peer = __commonJS({
1623
1699
  throw error;
1624
1700
  }
1625
1701
  }
1702
+ function missingPeer(error, name, hint) {
1703
+ if (!isMissing(error, name)) return error;
1704
+ const err = new Error(hint);
1705
+ err.code = "MISSING_DEPENDENCY";
1706
+ return err;
1707
+ }
1626
1708
  function isMissing(error, name) {
1627
1709
  if (!error || error.code !== "MODULE_NOT_FOUND") return false;
1628
1710
  const message = String(error.message || "");
1629
1711
  return message.startsWith(`Cannot find module '${name}'`) || message.startsWith(`Cannot find module "${name}"`);
1630
1712
  }
1631
- module2.exports = { loadOptionalPeer };
1713
+ module2.exports = { loadOptionalPeer, missingPeer };
1632
1714
  }
1633
1715
  });
1634
1716
 
@@ -1636,24 +1718,28 @@ var require_optional_peer = __commonJS({
1636
1718
  var require_otel = __commonJS({
1637
1719
  "src/observability/otel.js"(exports2, module2) {
1638
1720
  "use strict";
1721
+ var { evaluationScores } = require_scores();
1639
1722
  var { version: LIBRARY_VERSION } = require_package();
1640
- var { loadOptionalPeer } = require_optional_peer();
1723
+ var { missingPeer } = require_optional_peer();
1641
1724
  var TRACER_NAME = "@devilsdev/rag-pipeline-utils";
1642
1725
  var PROVIDERS = /* @__PURE__ */ new Set(["openai", "anthropic", "cohere", "ollama"]);
1643
1726
  function loadOtelApi() {
1644
- return loadOptionalPeer(
1645
- "@opentelemetry/api",
1646
- () => require("@opentelemetry/api"),
1647
- // eslint-disable-line global-require
1648
- 'telemetry needs the "@opentelemetry/api" package, an optional peer dependency: npm install @opentelemetry/api (with @devilsdev/rag-pipeline-utils/edge, pass it: telemetry: { api })'
1649
- );
1727
+ try {
1728
+ return require("@opentelemetry/api");
1729
+ } catch (error) {
1730
+ throw missingPeer(
1731
+ error,
1732
+ "@opentelemetry/api",
1733
+ 'telemetry needs the "@opentelemetry/api" package, an optional peer dependency: npm install @opentelemetry/api (with @devilsdev/rag-pipeline-utils/edge, pass it: telemetry: { api })'
1734
+ );
1735
+ }
1650
1736
  }
1651
1737
  function createTelemetry(option) {
1652
1738
  if (!option) return null;
1653
1739
  const opts = option === true ? {} : option;
1654
1740
  if (typeof opts !== "object") {
1655
1741
  throw new TypeError(
1656
- "telemetry must be true or { tracer?, api?, recordContent? }"
1742
+ "telemetry must be true or { tracer?, api?, logs?, logger?, recordContent? }"
1657
1743
  );
1658
1744
  }
1659
1745
  const api = opts.api || loadOtelApi();
@@ -1666,7 +1752,33 @@ var require_otel = __commonJS({
1666
1752
  if (!tracer || typeof tracer.startActiveSpan !== "function") {
1667
1753
  throw new TypeError("telemetry.tracer must be an OpenTelemetry Tracer");
1668
1754
  }
1669
- return { api, tracer, recordContent: Boolean(opts.recordContent) };
1755
+ let logger = opts.logger || null;
1756
+ if (logger && typeof logger.emit !== "function") {
1757
+ throw new TypeError("telemetry.logger must be an OpenTelemetry Logger");
1758
+ }
1759
+ if (!logger) {
1760
+ if (opts.logs && !(opts.logs.logs && typeof opts.logs.logs.getLogger === "function")) {
1761
+ throw new TypeError(
1762
+ 'telemetry.logs must be the @opentelemetry/api-logs module (import * as logs from "@opentelemetry/api-logs")'
1763
+ );
1764
+ }
1765
+ const source = [opts.logs, api].find(
1766
+ (m) => m && m.logs && typeof m.logs.getLogger === "function"
1767
+ );
1768
+ if (source) logger = source.logs.getLogger(TRACER_NAME, LIBRARY_VERSION);
1769
+ }
1770
+ return {
1771
+ api,
1772
+ tracer,
1773
+ logger,
1774
+ // Holds the spans of one run, so its scores find them under concurrency
1775
+ runKey: api.createContextKey("rag.pipeline.run"),
1776
+ recordContent: Boolean(opts.recordContent)
1777
+ };
1778
+ }
1779
+ function recordStage(tel, stage, span) {
1780
+ const run = tel.api.context.active().getValue(tel.runKey);
1781
+ if (run) run[stage] = span.spanContext();
1670
1782
  }
1671
1783
  function providerOf(component) {
1672
1784
  const name = component && component.name;
@@ -1749,8 +1861,8 @@ var require_otel = __commonJS({
1749
1861
  retriever(method, [params = {}]) {
1750
1862
  const source = component.collection || (typeof component.table === "string" ? component.table.replace(/"/g, "") : void 0);
1751
1863
  return {
1752
- name: source ? `retrieval ${source}` : "retrieval",
1753
- kind: SpanKind.CLIENT,
1864
+ name: "retrieval",
1865
+ kind: SpanKind.INTERNAL,
1754
1866
  attributes: clean({
1755
1867
  "gen_ai.operation.name": "retrieval",
1756
1868
  "gen_ai.data_source.id": source,
@@ -1808,6 +1920,7 @@ var require_otel = __commonJS({
1808
1920
  };
1809
1921
  }
1810
1922
  };
1923
+ const STAGES = { retriever: "retrieval", llm: "generation" };
1811
1924
  const METHODS = {
1812
1925
  embedder: ["embed", "embedQuery"],
1813
1926
  retriever: ["retrieve"],
@@ -1821,8 +1934,10 @@ var require_otel = __commonJS({
1821
1934
  return (...args) => {
1822
1935
  const spec = spanFor[kind](prop, args);
1823
1936
  const options = { kind: spec.kind, attributes: spec.attributes };
1937
+ const stage = STAGES[kind];
1824
1938
  if (prop === "generateStream") {
1825
1939
  return tel.tracer.startActiveSpan(spec.name, options, (span) => {
1940
+ if (stage) recordStage(tel, stage, span);
1826
1941
  const startedAt = performance.now();
1827
1942
  let source;
1828
1943
  try {
@@ -1836,6 +1951,7 @@ var require_otel = __commonJS({
1836
1951
  });
1837
1952
  }
1838
1953
  return inSpan(tel, spec.name, options, async (span) => {
1954
+ if (stage) recordStage(tel, stage, span);
1839
1955
  const out = await value.apply(target, args);
1840
1956
  spec.after(span, out);
1841
1957
  return out;
@@ -1890,32 +2006,49 @@ var require_otel = __commonJS({
1890
2006
  "rag.pipeline.run",
1891
2007
  { kind: SpanKind.INTERNAL, attributes },
1892
2008
  async (span) => {
2009
+ const stages = {};
2010
+ const runContext = tel.api.context.active().setValue(tel.runKey, stages);
1893
2011
  let result;
1894
2012
  try {
1895
- result = await run(params);
2013
+ result = await tel.api.context.with(runContext, () => run(params));
1896
2014
  } catch (error) {
1897
2015
  markError(tel, span, error);
1898
2016
  span.end();
1899
2017
  throw error;
1900
2018
  }
1901
2019
  if (result && typeof result[Symbol.asyncIterator] === "function") {
2020
+ const iterator = result[Symbol.asyncIterator]();
1902
2021
  return (async function* tracedStream() {
2022
+ let finished = false;
1903
2023
  try {
1904
- for await (const chunk of result) {
2024
+ for (; ; ) {
2025
+ const step = await tel.api.context.with(
2026
+ runContext,
2027
+ () => iterator.next()
2028
+ );
2029
+ if (step.done) break;
2030
+ const chunk = step.value;
1905
2031
  if (chunk && chunk.done) {
1906
2032
  span.setAttributes(runAttributes(tel, chunk));
2033
+ finishRun(tel, span, stages, chunk);
1907
2034
  }
1908
2035
  yield chunk;
1909
2036
  }
2037
+ finished = true;
1910
2038
  } catch (error) {
2039
+ finished = true;
1911
2040
  markError(tel, span, error);
1912
2041
  throw error;
1913
2042
  } finally {
2043
+ if (!finished && typeof iterator.return === "function") {
2044
+ await iterator.return();
2045
+ }
1914
2046
  span.end();
1915
2047
  }
1916
2048
  })();
1917
2049
  }
1918
2050
  span.setAttributes(runAttributes(tel, result));
2051
+ finishRun(tel, span, stages, result);
1919
2052
  if (!result || result.success === false) {
1920
2053
  const message = result && result.error || "run failed";
1921
2054
  span.setAttribute("error.type", errorType(message));
@@ -1927,6 +2060,33 @@ var require_otel = __commonJS({
1927
2060
  );
1928
2061
  };
1929
2062
  }
2063
+ function finishRun(tel, span, stages, result) {
2064
+ if (!result || typeof result !== "object") return;
2065
+ const own = span.spanContext();
2066
+ result.telemetry = {
2067
+ traceId: own.traceId,
2068
+ spanId: own.spanId,
2069
+ spans: Object.fromEntries(
2070
+ Object.entries(stages).map(([stage, ctx]) => [stage, ctx.spanId])
2071
+ )
2072
+ };
2073
+ if (!tel.logger) return;
2074
+ for (const score of evaluationScores(result, {
2075
+ explanations: tel.recordContent
2076
+ })) {
2077
+ const parent = stages[score.target] || own;
2078
+ tel.logger.emit({
2079
+ eventName: "gen_ai.evaluation.result",
2080
+ context: tel.api.trace.setSpanContext(tel.api.context.active(), parent),
2081
+ attributes: clean({
2082
+ "gen_ai.evaluation.name": score.name,
2083
+ "gen_ai.evaluation.score.value": score.value,
2084
+ "gen_ai.evaluation.score.label": score.label,
2085
+ "gen_ai.evaluation.explanation": score.explanation
2086
+ })
2087
+ });
2088
+ }
2089
+ }
1930
2090
  function errorType(message) {
1931
2091
  if (message === "Execution timeout") return "timeout";
1932
2092
  if (message === "Execution aborted") return "aborted";
@@ -2437,17 +2597,114 @@ var require_scoring = __commonJS({
2437
2597
  return { values, parts: [...values, ...parts] };
2438
2598
  }
2439
2599
  function checkNumericConsistency(claimText, docText) {
2440
- const claimNumbers = [...new Set(extractNumbers(claimText).values)];
2600
+ const claimNumbers = [
2601
+ ...new Set(extractNumbers(withoutReferences(claimText)).values),
2602
+ ...claimMonths(claimText).map((m) => `month:${m}`),
2603
+ ...identifiers(claimText)
2604
+ ];
2441
2605
  if (claimNumbers.length === 0) {
2442
2606
  return { consistent: true, claimNumbers, missing: [] };
2443
2607
  }
2444
- const docNumbers = new Set(extractNumbers(docText).parts);
2608
+ const docNumbers = /* @__PURE__ */ new Set([
2609
+ ...extractNumbers(docText).parts,
2610
+ ...docMonths(docText).map((m) => `month:${m}`),
2611
+ ...identifiers(docText)
2612
+ ]);
2445
2613
  const missing = claimNumbers.filter((n) => !docNumbers.has(n));
2446
2614
  return { consistent: missing.length === 0, claimNumbers, missing };
2447
2615
  }
2616
+ var REFERENCE_WORDS = "document|documents|doc|docs|source|sources|table|tables|figure|figures|fig|section|sections|step|steps|study|studies|appendix|chapter|page|pages|claim|claims|passage|passages|item|items|reference|ref|part|exhibit|equation|eq|line|row|column|note|footnote|paragraph";
2617
+ var REFERENCE_RE = new RegExp(
2618
+ `\\b(${REFERENCE_WORDS})\\.?\\s+\\d+[a-z]?\\b`,
2619
+ "giu"
2620
+ );
2621
+ var IDENTIFIER_RE = new RegExp("(\\p{L}[\\p{L}\\p{N}]*)-(\\d+)\\b", "gu");
2622
+ function identifiers(text) {
2623
+ if (!text || typeof text !== "string") return [];
2624
+ return [
2625
+ ...new Set(
2626
+ [...text.matchAll(IDENTIFIER_RE)].map((m) => `id:${m[0].toLowerCase()}`)
2627
+ )
2628
+ ];
2629
+ }
2630
+ function withoutReferences(text) {
2631
+ if (!text || typeof text !== "string") return text;
2632
+ return text.replace(REFERENCE_RE, " ").replace(IDENTIFIER_RE, (_, word) => word);
2633
+ }
2634
+ var MONTHS = [
2635
+ ["january", "jan"],
2636
+ ["february", "feb"],
2637
+ ["march", "mar"],
2638
+ ["april", "apr"],
2639
+ ["may"],
2640
+ ["june", "jun"],
2641
+ ["july", "jul"],
2642
+ ["august", "aug"],
2643
+ ["september", "sep", "sept"],
2644
+ ["october", "oct"],
2645
+ ["november", "nov"],
2646
+ ["december", "dec"]
2647
+ ];
2648
+ var MONTH_OF = new Map(
2649
+ MONTHS.flatMap((names, i) => names.map((n) => [n, i + 1]))
2650
+ );
2651
+ function claimMonths(text) {
2652
+ const words = String(text || "").toLowerCase().split(/[^\p{L}\p{N}]+/u).filter(Boolean);
2653
+ const out = [];
2654
+ words.forEach((w, i) => {
2655
+ const m = MONTH_OF.get(w);
2656
+ if (!m) return;
2657
+ const near = [words[i - 1], words[i + 1]].some(
2658
+ (x) => /^\d+$/.test(x || "")
2659
+ );
2660
+ if (near) out.push(m);
2661
+ });
2662
+ return [...new Set(out)];
2663
+ }
2664
+ function docMonths(text) {
2665
+ const t = String(text || "");
2666
+ const out = /* @__PURE__ */ new Set();
2667
+ for (const w of t.toLowerCase().split(/[^\p{L}]+/u)) {
2668
+ const m = MONTH_OF.get(w);
2669
+ if (m) out.add(m);
2670
+ }
2671
+ for (const [, a, b] of t.matchAll(
2672
+ /\b(\d{1,2})[/.-](\d{1,2})[/.-]\d{2,4}\b/g
2673
+ )) {
2674
+ for (const v of [Number(a), Number(b)]) if (v >= 1 && v <= 12) out.add(v);
2675
+ }
2676
+ for (const [, mm] of t.matchAll(/\b\d{4}-(\d{1,2})-\d{1,2}\b/g)) {
2677
+ const v = Number(mm);
2678
+ if (v >= 1 && v <= 12) out.add(v);
2679
+ }
2680
+ return [...out];
2681
+ }
2448
2682
  var NEGATION_WORDS = new Set(
2449
- "not no never none nobody nothing nowhere neither nor cannot without dont doesnt didnt isnt arent wasnt werent wont wouldnt shouldnt couldnt cant hasnt havent hadnt mustnt neednt".split(" ")
2683
+ "not no never none nobody nothing nowhere neither nor cannot without dont doesnt didnt isnt arent wasnt werent wont wouldnt shouldnt couldnt cant hasnt havent hadnt mustnt neednt nicht kein keine keinen keinem keiner keines nie niemals nunca jam\xE1s jamas nadie nada tampoco ni pas jamais rien aucun aucune".split(" ")
2450
2684
  );
2685
+ var CLAUSE_BOUNDARY_WORDS = new Set(
2686
+ "but whereas although though while however yet and or except unlike".split(
2687
+ " "
2688
+ )
2689
+ );
2690
+ function clauseTokens(text) {
2691
+ const out = [];
2692
+ for (const part of String(text || "").split(/[,;:()[\]]+/)) {
2693
+ let current = [];
2694
+ for (const t of tokenize(part)) {
2695
+ if (CLAUSE_BOUNDARY_WORDS.has(t)) {
2696
+ if (current.length) out.push(current);
2697
+ current = [];
2698
+ } else {
2699
+ current.push(t);
2700
+ }
2701
+ }
2702
+ if (current.length) out.push(current);
2703
+ }
2704
+ return out;
2705
+ }
2706
+ var stem = (t) => t.length > 4 ? t.replace(/(ing|ed|es|s|e)$/, "") : t;
2707
+ var CONTINUING_NEGATIONS = /* @__PURE__ */ new Set(["nor", "ni"]);
2451
2708
  var NON_NEGATING_NEXT = {
2452
2709
  not: /* @__PURE__ */ new Set(["only", "just", "merely"]),
2453
2710
  no: /* @__PURE__ */ new Set(["doubt", "matter"]),
@@ -2458,6 +2715,7 @@ var require_scoring = __commonJS({
2458
2715
  for (let i = 0; i < tokens.length; i++) {
2459
2716
  const t = tokens[i];
2460
2717
  if (!NEGATION_WORDS.has(t)) continue;
2718
+ if (CONTINUING_NEGATIONS.has(t) && count > 0) continue;
2461
2719
  if (NON_NEGATING_NEXT[t] && NON_NEGATING_NEXT[t].has(tokens[i + 1])) {
2462
2720
  continue;
2463
2721
  }
@@ -2466,38 +2724,62 @@ var require_scoring = __commonJS({
2466
2724
  return count % 2 === 1;
2467
2725
  }
2468
2726
  function checkPolarityConsistency(claimText, docText) {
2469
- const claimTokens = tokenize(claimText);
2470
- const claimNegated = isNegated(claimTokens);
2471
- const claimWords = [
2727
+ const words = (tokens) => [
2472
2728
  ...new Set(
2473
- contentTokens(claimTokens.filter((t) => !NEGATION_WORDS.has(t)))
2729
+ contentTokens(tokens.filter((t) => !NEGATION_WORDS.has(t))).map(stem)
2474
2730
  )
2475
2731
  ];
2476
- if (claimWords.length === 0) {
2477
- return { consistent: true, claimNegated, sourceSentence: null };
2478
- }
2479
- const candidates = splitSentences(docText).map((sentence) => {
2480
- const tokens = tokenize(sentence);
2481
- const set = new Set(tokens);
2482
- const support = claimWords.filter((t) => set.has(t)).length / claimWords.length;
2483
- return { sentence, tokens, support };
2484
- }).filter((c) => c.support > 0).sort((a, b) => b.support - a.support);
2485
- if (candidates.length === 0) {
2732
+ const claimClauses = clauseTokens(claimText).map((tokens) => ({ tokens, words: words(tokens) })).filter((c) => c.words.length > 0);
2733
+ const claimNegated = claimClauses.some((c) => isNegated(c.tokens));
2734
+ if (claimClauses.length === 0) {
2486
2735
  return { consistent: true, claimNegated, sourceSentence: null };
2487
2736
  }
2488
- const best = candidates[0].support;
2489
- const compared = candidates.filter((c) => c.support === best);
2490
- const match = compared.find((c) => isNegated(c.tokens) === claimNegated);
2491
- return {
2492
- consistent: Boolean(match),
2493
- claimNegated,
2494
- sourceSentence: (match || compared[0]).sentence
2737
+ const sentences = splitSentences(docText).map((sentence) => {
2738
+ const clauses = clauseTokens(sentence).map((tokens) => ({
2739
+ negated: isNegated(tokens),
2740
+ stems: new Set(tokens.map(stem))
2741
+ }));
2742
+ const stems = new Set(clauses.flatMap((c) => [...c.stems]));
2743
+ return { sentence, clauses, stems };
2744
+ });
2745
+ const agrees = (clause, sentence) => {
2746
+ const negated = isNegated(clause.tokens);
2747
+ const distinctive = clause.words.map((w) => sentence.clauses.filter((c) => c.stems.has(w))).filter((owners) => owners.length === 1).map((owners) => owners[0]);
2748
+ if (distinctive.length > 0) {
2749
+ return distinctive.every((c) => c.negated === negated);
2750
+ }
2751
+ const ranked = sentence.clauses.map((c) => ({
2752
+ c,
2753
+ support: clause.words.filter((w) => c.stems.has(w)).length
2754
+ })).filter((r) => r.support > 0).sort((a, b) => b.support - a.support);
2755
+ if (ranked.length === 0) return true;
2756
+ const best = ranked[0].support;
2757
+ return ranked.filter((r) => r.support === best).some((r) => r.c.negated === negated);
2495
2758
  };
2759
+ let consistent = true;
2760
+ let sourceSentence = null;
2761
+ for (const clause of claimClauses) {
2762
+ const candidates = sentences.map((s) => ({
2763
+ ...s,
2764
+ support: clause.words.filter((w) => s.stems.has(w)).length / clause.words.length
2765
+ })).filter((s) => s.support > 0).sort((a, b) => b.support - a.support);
2766
+ if (candidates.length === 0) continue;
2767
+ const best = candidates[0].support;
2768
+ const compared = candidates.filter((s) => s.support === best);
2769
+ const match = compared.find((s) => agrees(clause, s));
2770
+ if (!match) consistent = false;
2771
+ if (sourceSentence === null || !match) {
2772
+ sourceSentence = (match || compared[0]).sentence;
2773
+ }
2774
+ }
2775
+ return { consistent, claimNegated, sourceSentence };
2496
2776
  }
2497
2777
  var POLARITY_MISMATCH_FACTOR = 0.4;
2498
2778
  var NUMERIC_MISMATCH_FACTOR = 0.4;
2499
2779
  function computeSupportScore(claimTokens, docTokens, idfWeights = null, options = {}) {
2500
- const claim = [...new Set(contentTokens(claimTokens))];
2780
+ const rawClaim = options && options.claimText;
2781
+ const fromText = typeof rawClaim === "string" && rawClaim !== withoutReferences(rawClaim) ? tokenize(withoutReferences(rawClaim)) : claimTokens;
2782
+ const claim = [...new Set(contentTokens(fromText))];
2501
2783
  if (claim.length === 0) return 0;
2502
2784
  const docSet = docTokens instanceof Set ? docTokens : new Set(docTokens);
2503
2785
  let matched = 0;
@@ -5101,7 +5383,79 @@ var require_connector_utils = __commonJS({
5101
5383
  reader.releaseLock();
5102
5384
  }
5103
5385
  }
5386
+ function toConnectorError(err, provider) {
5387
+ if (!err || typeof err !== "object" || err.isAxiosError !== true) {
5388
+ return err;
5389
+ }
5390
+ if (isAbortError(err)) {
5391
+ const aborted = new Error("The operation was aborted");
5392
+ aborted.name = "AbortError";
5393
+ aborted.code = "ABORT_ERR";
5394
+ return aborted;
5395
+ }
5396
+ const response = err.response;
5397
+ let message;
5398
+ if (response) {
5399
+ const data = response.data;
5400
+ const apiError = data && typeof data === "object" && typeof data.pipe !== "function" ? data.error : void 0;
5401
+ let detail = "";
5402
+ if (apiError && typeof apiError === "object") {
5403
+ detail = [apiError.type, apiError.message].filter(Boolean).join(": ");
5404
+ } else if (typeof apiError === "string") {
5405
+ detail = apiError;
5406
+ } else if (data && typeof data === "object" && typeof data.message === "string") {
5407
+ detail = data.message;
5408
+ }
5409
+ message = `${provider} API error ${response.status}${detail ? `: ${detail}` : ""}`;
5410
+ } else {
5411
+ message = `${provider} request failed: ${err.message}`;
5412
+ }
5413
+ const error = new Error(message);
5414
+ if (err.code) error.code = err.code;
5415
+ if (response) {
5416
+ error.status = response.status;
5417
+ error.response = {
5418
+ status: response.status,
5419
+ statusText: response.statusText,
5420
+ headers: response.headers,
5421
+ data: response.data
5422
+ };
5423
+ }
5424
+ return error;
5425
+ }
5426
+ async function readErrorBody(stream) {
5427
+ const chunks = [];
5428
+ let size = 0;
5429
+ try {
5430
+ for await (const chunk of stream) {
5431
+ size += chunk.length;
5432
+ if (size > 65536) break;
5433
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
5434
+ }
5435
+ } catch {
5436
+ } finally {
5437
+ if (typeof stream.destroy === "function") stream.destroy();
5438
+ }
5439
+ const text = Buffer.concat(chunks).toString("utf8");
5440
+ try {
5441
+ return JSON.parse(text);
5442
+ } catch {
5443
+ return text || void 0;
5444
+ }
5445
+ }
5446
+ function cleanAxiosErrors(client, provider) {
5447
+ client.interceptors.response.use(void 0, async (err) => {
5448
+ const data = err && err.response && err.response.data;
5449
+ if (data && typeof data.pipe === "function") {
5450
+ err.response.data = await readErrorBody(data);
5451
+ }
5452
+ throw toConnectorError(err, provider);
5453
+ });
5454
+ return client;
5455
+ }
5104
5456
  module2.exports = {
5457
+ toConnectorError,
5458
+ cleanAxiosErrors,
5105
5459
  textChunks,
5106
5460
  createAbortError,
5107
5461
  isAbortError,
@@ -5640,6 +5994,23 @@ var require_cost_calculator = __commonJS({
5640
5994
  source: "https://platform.claude.com/docs/en/about-claude/pricing",
5641
5995
  asOf: "2026-11-01"
5642
5996
  },
5997
+ // $0.10 / $0.50 per million input / output tokens, for prompts up to
5998
+ // 100,000 tokens ($0.50 / $2.50 above; this table has one price per model).
5999
+ "claude-haiku-5.5": {
6000
+ input: 1e-4,
6001
+ output: 5e-4,
6002
+ unit: 1e3,
6003
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
6004
+ asOf: "2026-11-05"
6005
+ },
6006
+ // $10 / $50 per million input / output tokens.
6007
+ "claude-fable-5.1": {
6008
+ input: 0.01,
6009
+ output: 0.05,
6010
+ unit: 1e3,
6011
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
6012
+ asOf: "2026-11-05"
6013
+ },
5643
6014
  "cohere-command": {
5644
6015
  input: 1e-3,
5645
6016
  output: 2e-3,
@@ -6032,6 +6403,8 @@ var require_cost_tracker = __commonJS({
6032
6403
  budgetOptions: {}
6033
6404
  };
6034
6405
  var CHARS_PER_TOKEN = 4;
6406
+ var PROMPT_OVERHEAD_CHARS = 600;
6407
+ var PASSAGE_WRAPPER_CHARS = 40;
6035
6408
  var CostTracker = class extends EventEmitter {
6036
6409
  /**
6037
6410
  * @param {object} [options]
@@ -6071,9 +6444,18 @@ var require_cost_tracker = __commonJS({
6071
6444
  }
6072
6445
  const inputText = result.input || result.query || result.prompt || "";
6073
6446
  const outputText = result.output || result.answer || result.response || "";
6447
+ const passages = Array.isArray(result.results) ? result.results : [];
6448
+ const passageChars = passages.reduce((n, doc) => {
6449
+ const text = typeof doc === "string" ? doc : doc && (doc.content || doc.text) || "";
6450
+ return n + String(text).length + PASSAGE_WRAPPER_CHARS;
6451
+ }, 0);
6452
+ const promptChars = passages.length > 0 ? PROMPT_OVERHEAD_CHARS : 0;
6074
6453
  return {
6075
- inputTokens: Math.ceil(String(inputText).length / CHARS_PER_TOKEN),
6076
- outputTokens: Math.ceil(String(outputText).length / CHARS_PER_TOKEN)
6454
+ inputTokens: Math.ceil(
6455
+ (String(inputText).length + passageChars + promptChars) / CHARS_PER_TOKEN
6456
+ ),
6457
+ outputTokens: Math.ceil(String(outputText).length / CHARS_PER_TOKEN),
6458
+ estimated: true
6077
6459
  };
6078
6460
  }
6079
6461
  /**
@@ -6096,7 +6478,7 @@ var require_cost_tracker = __commonJS({
6096
6478
  tracker.startSession({ autoStarted: true });
6097
6479
  }
6098
6480
  const result = await pipeline.run(...args);
6099
- const { inputTokens, outputTokens } = tracker._extractUsage(result);
6481
+ const { inputTokens, outputTokens, estimated } = tracker._extractUsage(result);
6100
6482
  const model = result.model || result.route && result.route.model || tracker.config.model;
6101
6483
  const costEstimate = tracker.calculator.estimate(
6102
6484
  model,
@@ -6123,8 +6505,14 @@ var require_cost_tracker = __commonJS({
6123
6505
  inputTokens,
6124
6506
  outputTokens,
6125
6507
  estimatedCost: costEstimate.totalCost,
6508
+ // The price-table entry used (as before), and the model the run
6509
+ // asked for, which can differ in form (claude-haiku-4-5 is priced
6510
+ // as claude-haiku-4.5)
6126
6511
  model: costEstimate.model,
6127
- currency: "USD"
6512
+ requestedModel: model,
6513
+ currency: "USD",
6514
+ // Token counts estimated from text length (no usage reported)
6515
+ ...estimated && { tokensEstimated: true }
6128
6516
  };
6129
6517
  const entry = {
6130
6518
  timestamp: Date.now(),
@@ -6811,9 +7199,15 @@ var require_core = __commonJS({
6811
7199
  var { createModelRouter, classifyQuery } = require_model_router();
6812
7200
  var { MemoryRetriever } = require_memory_retriever();
6813
7201
  var { BaseConnector } = require_base_connector();
7202
+ var {
7203
+ evaluationScores,
7204
+ toLangfuseScores
7205
+ } = require_scores();
6814
7206
  module2.exports = {
6815
7207
  createRagPipeline,
6816
7208
  createPipeline: createRagPipeline,
7209
+ evaluationScores,
7210
+ toLangfuseScores,
6817
7211
  packContext,
6818
7212
  createError: errorFormatter.createError,
6819
7213
  wrapError: errorFormatter.wrapError,
@@ -6873,6 +7267,7 @@ var modules = {
6873
7267
  "evaluate/relevance.js": () => require_relevance(),
6874
7268
  "evaluate/scoring.js": () => require_scoring(),
6875
7269
  "observability/otel.js": () => require_otel(),
7270
+ "observability/scores.js": () => require_scores(),
6876
7271
  "packages/core.js": () => require_core(),
6877
7272
  "reranker/cascade-reranker.js": () => require_cascade_reranker(),
6878
7273
  "reranker/embedding-reranker.js": () => require_embedding_reranker(),