@absolutejs/rag 0.22.7 → 0.22.9

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.
@@ -112384,6 +112384,28 @@ var startWebIndexWorker = (options) => {
112384
112384
  // src/web-index/projector.ts
112385
112385
  import { t as t2 } from "elysia";
112386
112386
 
112387
+ // src/research/sourceExcerpts.ts
112388
+ import { createAITextSource } from "@absolutejs/ai";
112389
+ var selectResearchExcerpts = (text, budget, query) => {
112390
+ if (budget <= 0)
112391
+ return [];
112392
+ if (text.length <= budget)
112393
+ return [text];
112394
+ const source = createAITextSource([{ role: "user", content: text }]);
112395
+ const hits = source.search(query);
112396
+ const passages = hits.length ? hits : source.search("");
112397
+ let remaining = budget;
112398
+ const selected = [];
112399
+ for (const passage of passages) {
112400
+ if (!remaining)
112401
+ break;
112402
+ const excerpt = passage.text.slice(0, remaining);
112403
+ selected.push({ start: passage.start, text: excerpt });
112404
+ remaining -= excerpt.length;
112405
+ }
112406
+ return selected.sort((a, b) => a.start - b.start).map((passage) => passage.text);
112407
+ };
112408
+
112387
112409
  // src/research/budget.ts
112388
112410
  var createResearchBudgetAdmission = (config) => {
112389
112411
  if (!config.scope.trim())
@@ -122125,7 +122147,7 @@ var readRAGWebsite = async (options) => {
122125
122147
  const page = await readRAGWebpage({
122126
122148
  ...options,
122127
122149
  url: next.url,
122128
- maxChars: Math.min(maxChars, 12000),
122150
+ maxChars,
122129
122151
  signal: AbortSignal.any([signal, AbortSignal.timeout(30000)])
122130
122152
  });
122131
122153
  pages.push(page);
@@ -122181,24 +122203,27 @@ var readRAGWebsite = async (options) => {
122181
122203
  let remainingDocumentChars = maxChars;
122182
122204
  const documents = sources.flatMap((source) => {
122183
122205
  const page = pages.find((item) => item.finalUrl === source.url && item.text);
122184
- if (!page || remainingDocumentChars <= 0)
122206
+ if (!page)
122185
122207
  return [];
122186
122208
  const imageLabels = page.evidence.images.filter((image) => image.label).map((image) => `${image.context ? `${image.context}: ` : ""}${image.label}`);
122187
122209
  const fullText = [
122188
- page.text,
122210
+ page.fullText ?? page.text,
122189
122211
  ...imageLabels.length ? [
122190
122212
  "Image labels supplied by the website (not independently verified customer relationships):",
122191
122213
  ...imageLabels
122192
122214
  ] : []
122193
122215
  ].join(`
122194
122216
  `);
122195
- const text = fullText.slice(0, remainingDocumentChars);
122217
+ const text = fullText.slice(0, Math.max(0, remainingDocumentChars));
122196
122218
  remainingDocumentChars -= text.length;
122197
122219
  return [
122198
122220
  {
122199
122221
  sourceId: source.id,
122200
122222
  text,
122201
- truncated: page.truncated || text.length < fullText.length
122223
+ fullText,
122224
+ originalChars: fullText.length,
122225
+ sourceTruncated: page.status !== "ok" || page.fullText === undefined && page.truncated,
122226
+ truncated: page.fullText === undefined && page.truncated || text.length < fullText.length
122202
122227
  }
122203
122228
  ];
122204
122229
  });
@@ -122217,10 +122242,11 @@ ${page.text}`).join(`
122217
122242
  sources,
122218
122243
  citationRequirements: "The final answer must contain clickable Markdown source links, not just source names or bare domain mentions. Reuse sources[].citation beside the factual paragraph, list or table row it supports. Cite the actual supporting page, not the homepage for everything. Every factual section needs its supporting links. Do not invent sources or use unread links as evidence. Before responding, check that company facts, service descriptions, customer examples and numerical claims have supporting links; retrieve or omit unsupported claims. A list of large customers does not prove smaller customers are excluded. Preserve the brands actually named in the evidence; do not append parent companies, ownership relationships, current-account status, market rankings or rebrand history from memory. Label reasoned inferences as such. A verified brand change needs at most one short, cited sentence unless the user asks for its history.",
122219
122244
  ...first,
122245
+ fullText: undefined,
122220
122246
  status: readable.length ? incomplete ? "partial" : "ok" : "error",
122221
122247
  text: evidenceText.slice(0, maxChars),
122222
122248
  truncated: evidenceText.length > maxChars || pages.some((page) => page.truncated),
122223
- pages: pages.map(({ text: _text, ...page }) => page),
122249
+ pages: pages.map(({ text: _text, fullText: _fullText, ...page }) => page),
122224
122250
  captionEvidence,
122225
122251
  coverage: {
122226
122252
  pagesRead: pages.length,
@@ -122231,10 +122257,10 @@ ${page.text}`).join(`
122231
122257
  deadlineReached: signal.aborted,
122232
122258
  exhaustive: false,
122233
122259
  stopReason: signal.aborted ? "deadline" : unvisited.length ? "page_limit" : "links_exhausted",
122234
- incompleteReads: pages.filter((page) => page.status !== "ok" || page.truncated).map((page) => ({
122260
+ incompleteReads: pages.filter((page) => page.status !== "ok" || page.fullText === undefined && page.truncated).map((page) => ({
122235
122261
  url: page.finalUrl,
122236
122262
  status: page.status,
122237
- truncated: page.truncated,
122263
+ truncated: page.fullText === undefined && page.truncated,
122238
122264
  error: page.error
122239
122265
  }))
122240
122266
  },
@@ -122349,12 +122375,15 @@ var createWebpageReaderClient = (options) => {
122349
122375
  if (![evidence.links, evidence.images, evidence.media].every(Array.isArray))
122350
122376
  throw new Error("Invalid page evidence");
122351
122377
  const limit = Math.max(1000, Math.min(input.maxChars ?? 24000, 1e5));
122378
+ const fullText = typeof document2.fullText === "string" ? document2.fullText : document2.text;
122352
122379
  return {
122353
122380
  status: result.status,
122354
122381
  url: input.url,
122355
122382
  finalUrl: result.finalUrl,
122356
122383
  title: typeof result.title === "string" ? result.title : null,
122357
- text: document2.text.slice(0, limit),
122384
+ text: fullText.slice(0, limit),
122385
+ fullText,
122386
+ originalChars: fullText.length,
122358
122387
  method: result.method,
122359
122388
  truncated: result.truncated === true || document2.truncated === true || document2.text.length > limit,
122360
122389
  fetchedAt: result.fetchedAt,
@@ -122397,6 +122426,8 @@ var readRAGWebpage = async (options) => {
122397
122426
  finalUrl,
122398
122427
  title,
122399
122428
  text: text.slice(0, maxChars),
122429
+ fullText: text,
122430
+ originalChars: text.length,
122400
122431
  method,
122401
122432
  truncated: text.length > maxChars,
122402
122433
  attempts,
@@ -122736,6 +122767,7 @@ ${prompt}`,
122736
122767
  const requiredPhrases = input.requiredPhrases ?? (input.queryMode === "task" ? [] : [...input.query.matchAll(/"([^"\n]+)"/gu)].map((match) => match[1]));
122737
122768
  const urls = new Set;
122738
122769
  const queries = new Set;
122770
+ const discoveredLinks = new Map;
122739
122771
  let evidenceChars = 0;
122740
122772
  const sourceText = new Map;
122741
122773
  const rebalanceEvidence = () => {
@@ -122747,8 +122779,8 @@ ${prompt}`,
122747
122779
  const text = sourceText.get(source.url);
122748
122780
  const allowance = Math.floor(remaining * weight(source) / remainingWeight);
122749
122781
  remainingWeight -= weight(source);
122750
- source.excerpts = [text.slice(0, allowance)];
122751
- remaining -= source.excerpts[0].length;
122782
+ source.excerpts = selectResearchExcerpts(text, allowance, [input.query, ...input.queries ?? []].join(" "));
122783
+ remaining -= source.excerpts.reduce((sum, excerpt) => sum + excerpt.length, 0);
122752
122784
  }
122753
122785
  evidenceChars = limits.evidenceChars - remaining;
122754
122786
  };
@@ -122807,7 +122839,7 @@ ${prompt}`,
122807
122839
  const doRead = async (url) => {
122808
122840
  if (urls.has(url) || urls.size >= limits.reads)
122809
122841
  return;
122810
- if (!result.searches.some((search) => search.sources.some((source) => source.url === url)))
122842
+ if (!discoveredLinks.has(url) && !result.searches.some((search) => search.sources.some((source) => source.url === url)))
122811
122843
  return;
122812
122844
  urls.add(url);
122813
122845
  const page = await operate("read", () => (config.reader ?? readRAGWebpage)({
@@ -122820,9 +122852,19 @@ ${prompt}`,
122820
122852
  if (page.status !== "ok")
122821
122853
  result.limitations.push(`Page read ${page.status}: ${url}`);
122822
122854
  if (page.text && page.status !== "error") {
122855
+ for (const link of page.evidence.links) {
122856
+ if (discoveredLinks.size >= 64)
122857
+ break;
122858
+ try {
122859
+ const target = validatePublicWebUrl(new URL(link.url, page.finalUrl).href);
122860
+ target.hash = "";
122861
+ if (!discoveredLinks.has(target.href))
122862
+ discoveredLinks.set(target.href, { url: target.href, label: link.label.slice(0, 200), discoveredOn: page.finalUrl });
122863
+ } catch {}
122864
+ }
122823
122865
  const prior = result.sources.find((source) => source.url === url);
122824
122866
  if (prior) {
122825
- sourceText.set(prior.url, page.text.slice(0, limits.evidenceChars));
122867
+ sourceText.set(prior.url, page.fullText ?? page.text);
122826
122868
  prior.contentFetchedAt = page.fetchedAt;
122827
122869
  prior.metadata = { ...prior.metadata, readFinalUrl: page.finalUrl };
122828
122870
  if (page.finalUrl !== prior.url)
@@ -122858,11 +122900,12 @@ ${prompt}`,
122858
122900
  break;
122859
122901
  let plan;
122860
122902
  try {
122861
- plan = await generate("plan", PlanSchema, "Select follow-up searches for missing evidence and primary-source URLs to read. For current people or roles, seek the organization\u2019s own leadership/about/team pages; testimonials, package authors, and job listings are not staff identity evidence. For policies, read the full policy or agreement to preserve section scope and exceptions. URLs must come from the supplied search results. done means available evidence addresses the requested schema, not merely that some results exist. Return no actions if further work is not useful.", {
122903
+ plan = await generate("plan", PlanSchema, "Select follow-up searches for missing evidence and primary-source URLs to read. For current people or roles, seek the organization\u2019s own leadership/about/team pages; testimonials, package authors, and job listings are not staff identity evidence. For policies, read the full policy or agreement to preserve section scope and exceptions. URLs must come from the supplied search results or discoveredLinks. Discovered links are unread navigation hints, not evidence; read relevant product, pricing, checkout or policy details before concluding information is absent. done means available evidence addresses the requested schema, not merely that some results exist. Return no actions if further work is not useful.", {
122862
122904
  query: input.query,
122863
122905
  schema: task.schema,
122864
122906
  instructions: task.instructions,
122865
122907
  sources: result.sources,
122908
+ discoveredLinks: [...discoveredLinks.values()].filter((link) => !urls.has(link.url)),
122866
122909
  searched: [...queries],
122867
122910
  read: [...urls],
122868
122911
  remainingSearches: limits.searches - queries.size,
@@ -122934,6 +122977,7 @@ ${prompt}`,
122934
122977
  result.status = result.sources.length ? "partial" : "unavailable";
122935
122978
  return result;
122936
122979
  } finally {
122980
+ result.documents = result.sources.filter((source) => source.contentFetchedAt).map((source) => ({ sourceId: source.id, url: source.url, text: sourceText.get(source.url) ?? "", originalChars: (sourceText.get(source.url) ?? "").length }));
122937
122981
  result.limitations = [...new Set(result.limitations)];
122938
122982
  input.onProgress?.({
122939
122983
  phase: "complete",
@@ -123038,5 +123082,5 @@ export {
123038
123082
  webIndexPostgresSchemaSql
123039
123083
  };
123040
123084
 
123041
- //# debugId=977A90765872948B64756E2164756E21
123085
+ //# debugId=D95820757077B71864756E2164756E21
123042
123086
  //# sourceMappingURL=index.js.map