@farming-labs/docs 0.1.71 → 0.1.73

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.
@@ -54,6 +54,29 @@ function createDocsCloudAnalytics(options = {}) {
54
54
 
55
55
  //#endregion
56
56
  //#region src/analytics.ts
57
+ const ANALYTICS_LOG_PREFIX = "[@farming-labs/docs:analytics]";
58
+ const OBSERVABILITY_LOG_PREFIX = "[@farming-labs/docs:observability]";
59
+ const DOCS_AGENT_TRACE_EVENT_TYPES = [
60
+ "run.start",
61
+ "run.end",
62
+ "run.error",
63
+ "user.input",
64
+ "prompt.build",
65
+ "retrieval.query",
66
+ "retrieval.result",
67
+ "retrieval.error",
68
+ "model.call",
69
+ "model.response",
70
+ "model.stream",
71
+ "model.error",
72
+ "tool.call",
73
+ "tool.result",
74
+ "tool.error",
75
+ "retry",
76
+ "timeout",
77
+ "error",
78
+ "agent.final"
79
+ ];
57
80
  function composeAnalyticsHandlers(userOnEvent, cloudOnEvent) {
58
81
  if (typeof userOnEvent !== "function" && !cloudOnEvent) return;
59
82
  return async (event) => {
@@ -75,6 +98,17 @@ function resolveConsoleLevel(value, hasEventHandler) {
75
98
  if (value === "log" || value === "info" || value === "debug") return value;
76
99
  return hasEventHandler ? false : "info";
77
100
  }
101
+ function createDocsAgentTraceId(prefix = "trace") {
102
+ return `${prefix.replace(/[^a-zA-Z0-9_-]/g, "_") || "trace"}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
103
+ }
104
+ function createDocsAgentTraceContext(name = "agent.run") {
105
+ return {
106
+ traceId: createDocsAgentTraceId("run"),
107
+ name,
108
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
109
+ startedMs: Date.now()
110
+ };
111
+ }
78
112
  function resolveDocsAnalyticsConfig(analytics) {
79
113
  const cloudOptions = resolveDocsCloudAnalyticsOptions(analytics);
80
114
  const cloudOnEvent = cloudOptions ? async (event) => {
@@ -109,6 +143,25 @@ function resolveDocsAnalyticsConfig(analytics) {
109
143
  onEvent
110
144
  };
111
145
  }
146
+ function resolveDocsObservabilityConfig(observability) {
147
+ if (!observability) return {
148
+ enabled: false,
149
+ console: false,
150
+ includeInputs: false
151
+ };
152
+ if (observability === true) return {
153
+ enabled: true,
154
+ console: "info",
155
+ includeInputs: false
156
+ };
157
+ const hasEventHandler = typeof observability.onEvent === "function";
158
+ return {
159
+ enabled: observability.enabled !== false,
160
+ console: resolveConsoleLevel(observability.console, hasEventHandler),
161
+ includeInputs: observability.includeInputs === true,
162
+ onEvent: observability.onEvent
163
+ };
164
+ }
112
165
  function normalizeAnalyticsEvent(event, config) {
113
166
  const normalized = {
114
167
  ...event,
@@ -118,18 +171,51 @@ function normalizeAnalyticsEvent(event, config) {
118
171
  if (!config.includeInputs && normalized.input) delete normalized.input;
119
172
  return normalized;
120
173
  }
174
+ function normalizeObservabilityEvent(event, config) {
175
+ const normalized = {
176
+ ...event,
177
+ source: event.source ?? "server",
178
+ timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
179
+ };
180
+ if (!config.includeInputs && normalized.input) delete normalized.input;
181
+ return normalized;
182
+ }
121
183
  async function emitDocsAnalyticsEvent(analytics, event) {
122
184
  const resolved = resolveDocsAnalyticsConfig(analytics);
123
185
  if (!resolved.enabled) return;
124
186
  const normalized = normalizeAnalyticsEvent(event, resolved);
125
- if (resolved.console) (console[resolved.console] ?? console.info).call(console, "[farming-labs:analytics]", normalized);
187
+ if (resolved.console) (console[resolved.console] ?? console.info).call(console, ANALYTICS_LOG_PREFIX, normalized);
126
188
  if (!resolved.onEvent) return;
127
189
  try {
128
190
  await resolved.onEvent(normalized);
129
191
  } catch (error) {
130
- if (resolved.console !== false) console.warn("[farming-labs:analytics] onEvent failed", error);
192
+ if (resolved.console !== false) console.warn(`${ANALYTICS_LOG_PREFIX} onEvent failed`, error);
131
193
  }
132
194
  }
195
+ async function emitDocsObservabilityEvent(observability, event) {
196
+ const resolved = resolveDocsObservabilityConfig(observability);
197
+ if (!resolved.enabled) return;
198
+ const normalized = normalizeObservabilityEvent(event, resolved);
199
+ if (resolved.console) (console[resolved.console] ?? console.info).call(console, OBSERVABILITY_LOG_PREFIX, normalized);
200
+ if (!resolved.onEvent) return;
201
+ try {
202
+ await resolved.onEvent(normalized);
203
+ } catch (error) {
204
+ if (resolved.console !== false) console.warn(`${OBSERVABILITY_LOG_PREFIX} onEvent failed`, error);
205
+ }
206
+ }
207
+ async function emitDocsAgentTraceEvent(observability, event) {
208
+ const timestamp = event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
209
+ await emitDocsObservabilityEvent(observability, {
210
+ ...event,
211
+ timestamp,
212
+ source: event.source ?? "server",
213
+ traceId: event.traceId ?? createDocsAgentTraceId("run"),
214
+ spanId: event.spanId ?? createDocsAgentTraceId("span"),
215
+ startedAt: event.startedAt ?? timestamp,
216
+ status: event.status ?? "success"
217
+ });
218
+ }
133
219
 
134
220
  //#endregion
135
221
  //#region src/related.ts
@@ -334,8 +420,41 @@ const DEFAULT_SEARCH_LIMIT = 10;
334
420
  const DEFAULT_MCP_PROTOCOL_VERSION = "2025-11-25";
335
421
  const syncedIndexes = /* @__PURE__ */ new Set();
336
422
  const ALGOLIA_MAX_RECORD_BYTES = 9500;
423
+ const DEFAULT_ASK_AI_CONTEXT_CHARS = 24e3;
424
+ const DEFAULT_ASK_AI_RESULT_CHARS = 6e3;
425
+ const SEARCH_STOP_WORDS = new Set([
426
+ "a",
427
+ "an",
428
+ "and",
429
+ "are",
430
+ "as",
431
+ "at",
432
+ "be",
433
+ "can",
434
+ "do",
435
+ "does",
436
+ "for",
437
+ "from",
438
+ "how",
439
+ "i",
440
+ "in",
441
+ "is",
442
+ "it",
443
+ "of",
444
+ "on",
445
+ "or",
446
+ "the",
447
+ "this",
448
+ "to",
449
+ "use",
450
+ "what",
451
+ "when",
452
+ "where",
453
+ "which",
454
+ "with"
455
+ ]);
337
456
  function stripMarkdownText(content) {
338
- return content.replace(/```[\s\S]*?```/g, "").replace(/~~~[\s\S]*?~~~/g, "").replace(/^(import|export)\s.*$/gm, "").replace(/<[^>]+\/>/g, "").replace(/<\/?[A-Z][^>]*>/g, "").replace(/<\/?[a-z][^>]*>/g, "").replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/^\|?[\s:-]+(\|[\s:-]+)+\|?\s*$/gm, "").replace(/\|/g, " ").replace(/^[-*+]\s+/gm, "").replace(/(\*{1,3}|_{1,3})(.*?)\1/g, "$2").replace(/`{3,}[^\n]*$/gm, "").replace(/`([^`]+)`/g, "$1").replace(/`+/g, "").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}\s*$/gm, "").replace(/\n{3,}/g, "\n\n").replace(/\s{2,}/g, " ").trim();
457
+ return removeMdxModuleLinesOutsideFences(content).replace(/```[^\n]*\n([\s\S]*?)```/g, "$1").replace(/```([\s\S]*?)```/g, "$1").replace(/~~~[^\n]*\n([\s\S]*?)~~~/g, "$1").replace(/~~~([\s\S]*?)~~~/g, "$1").replace(/<[^>]+\/>/g, "").replace(/<\/?[A-Z][^>]*>/g, "").replace(/<\/?[a-z][^>]*>/g, "").replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/^\|?[\s:-]+(\|[\s:-]+)+\|?\s*$/gm, "").replace(/\|/g, " ").replace(/^[-*+]\s+/gm, "").replace(/(\*{1,3}|_{1,3})(.*?)\1/g, "$2").replace(/`{3,}[^\n]*$/gm, "").replace(/`([^`]+)`/g, "$1").replace(/`+/g, "").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}\s*$/gm, "").replace(/\n{3,}/g, "\n\n").replace(/\s{2,}/g, " ").trim();
339
458
  }
340
459
  function stripHtml(text) {
341
460
  return text.replace(/<[^>]+>/g, "");
@@ -347,6 +466,194 @@ function normalizeMcpSsePayload(body) {
347
466
  function normalizeWhitespace(value) {
348
467
  return value.replace(/\s+/g, " ").trim();
349
468
  }
469
+ function tokenizeSearchQuery(query) {
470
+ return Array.from(new Set(query.toLowerCase().replace(/[^\p{L}\p{N}@/_:.-]+/gu, " ").split(/\s+/).map((word) => word.replace(/^[^\p{L}\p{N}@]+|[^\p{L}\p{N}]+$/gu, "")).filter((word) => word.length > 1 && !SEARCH_STOP_WORDS.has(word))));
471
+ }
472
+ function normalizeUrlPathname(value) {
473
+ try {
474
+ return new URL(value, "https://docs.local").pathname.replace(/\/+$/, "") || "/";
475
+ } catch {
476
+ return value.split(/[?#]/)[0]?.replace(/\/+$/, "") || "/";
477
+ }
478
+ }
479
+ function resolveAskAIContextUrl(value, baseUrl) {
480
+ if (!baseUrl) return value;
481
+ try {
482
+ return new URL(value, baseUrl).toString();
483
+ } catch {
484
+ return value;
485
+ }
486
+ }
487
+ function getAskAIPageContent(page) {
488
+ return page.agentRawContent ?? page.agentFallbackRawContent ?? page.rawContent ?? page.content;
489
+ }
490
+ function removeMdxModuleLinesOutsideFences(content) {
491
+ let inFence = false;
492
+ return content.split("\n").filter((line) => {
493
+ const trimmed = line.trimStart();
494
+ if (trimmed.startsWith("```") || trimmed.startsWith("~~~")) {
495
+ inFence = !inFence;
496
+ return true;
497
+ }
498
+ return inFence || !/^(import|export)\s/.test(trimmed);
499
+ }).join("\n");
500
+ }
501
+ function cleanAskAIContextMarkdown(content) {
502
+ return removeMdxModuleLinesOutsideFences(content).replace(/<[^>]+\/>/g, "").replace(/<\/?[A-Z][^>]*>/g, "").replace(/<\/?[a-z][^>]*>/g, "").replace(/\n{3,}/g, "\n\n").trim();
503
+ }
504
+ function packageRootFromSpecifier(specifier) {
505
+ if (!specifier || specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("@/") || specifier.startsWith("~/") || specifier.startsWith("#")) return null;
506
+ const parts = specifier.split("/").filter(Boolean);
507
+ if (parts.length === 0) return null;
508
+ if (parts[0]?.startsWith("@")) return parts.length > 1 ? `${parts[0]}/${parts[1]}` : null;
509
+ return parts[0];
510
+ }
511
+ function cleanPackageToken(token) {
512
+ const trimmed = token.trim().replace(/^["'`]+|["'`,;]+$/g, "").replace(/\\$/g, "");
513
+ if (!trimmed || trimmed.startsWith("-") || /^[A-Z_][A-Z0-9_]*=/.test(trimmed)) return null;
514
+ if (/^(npm|pnpm|yarn|bun|install|add|i|x|dlx|run|exec)$/.test(trimmed)) return null;
515
+ return packageRootFromSpecifier(trimmed.startsWith("@") ? trimmed.replace(/^(@[^/]+\/[^@]+)@.+$/, "$1") : trimmed.replace(/^([^@]+)@.+$/, "$1"));
516
+ }
517
+ function inferDocsAskAIPackageHints(content) {
518
+ const packages = /* @__PURE__ */ new Set();
519
+ const imports = /* @__PURE__ */ new Set();
520
+ const installCommands = /* @__PURE__ */ new Set();
521
+ for (const line of content.split("\n")) {
522
+ const trimmed = line.trim();
523
+ if (!trimmed) continue;
524
+ const importSpecifier = trimmed.match(/^(?:import|export)\s+(?:type\s+)?[\s\S]*?\s+from\s+["']([^"']+)["']/)?.[1];
525
+ const bareImportSpecifier = trimmed.match(/^import\s+["']([^"']+)["']/)?.[1];
526
+ const requireSpecifier = trimmed.match(/require\(["']([^"']+)["']\)/)?.[1];
527
+ const specifier = importSpecifier ?? bareImportSpecifier ?? requireSpecifier;
528
+ const packageName = specifier ? packageRootFromSpecifier(specifier) : null;
529
+ if (packageName) {
530
+ packages.add(packageName);
531
+ if (/^(?:import|export)\s/.test(trimmed)) imports.add(trimmed);
532
+ }
533
+ const installMatch = trimmed.match(/^(?:npm\s+(?:install|i)|pnpm\s+add|yarn\s+add|bun\s+add)\s+(.+)$/);
534
+ if (!installMatch) continue;
535
+ const commandPackages = installMatch[1].split(/\s+/).map(cleanPackageToken).filter((value) => Boolean(value));
536
+ if (commandPackages.length > 0) {
537
+ installCommands.add(trimmed);
538
+ for (const name of commandPackages) packages.add(name);
539
+ }
540
+ }
541
+ return {
542
+ packages: Array.from(packages).slice(0, 8),
543
+ imports: Array.from(imports).slice(0, 12),
544
+ installCommands: Array.from(installCommands).slice(0, 8)
545
+ };
546
+ }
547
+ function formatDocsAskAIPackageHints(hints, packageName) {
548
+ const packages = packageName ? Array.from(new Set([packageName, ...hints.packages])) : hints.packages;
549
+ if (packages.length === 0 && hints.imports.length === 0 && hints.installCommands.length === 0) return;
550
+ const lines = ["Package and import hints inferred from the retrieved documentation context:"];
551
+ if (packages.length > 0) lines.push(`- Package names found in install/import examples: ${packages.join(", ")}`);
552
+ if (hints.imports.length > 0) lines.push(`- Exact import lines found in context: ${hints.imports.map((line) => `\`${line}\``).join("; ")}`);
553
+ if (hints.installCommands.length > 0) lines.push(`- Exact install commands found in context: ${hints.installCommands.map((line) => `\`${line}\``).join("; ")}`);
554
+ lines.push("Use these exact package names, install commands, and import lines when relevant. Do not replace them with placeholders.");
555
+ return lines.join("\n");
556
+ }
557
+ function clampText(value, maxChars) {
558
+ if (maxChars <= 0) return "";
559
+ if (value.length <= maxChars) return value;
560
+ return `${value.slice(0, maxChars).trimEnd()}...`;
561
+ }
562
+ function extractHeadingText(line) {
563
+ const match = line.match(/^(#{1,6})\s+(.+?)\s*#*\s*$/);
564
+ if (!match) return null;
565
+ return {
566
+ level: match[1].length,
567
+ text: normalizeWhitespace(match[2].replace(/[`*_~]/g, ""))
568
+ };
569
+ }
570
+ function extractSectionMarkdown(content, section) {
571
+ if (!section) return content;
572
+ const target = normalizeWhitespace(section).toLowerCase();
573
+ const lines = content.split("\n");
574
+ let start = -1;
575
+ let level = 0;
576
+ for (let i = 0; i < lines.length; i += 1) {
577
+ const heading = extractHeadingText(lines[i]);
578
+ if (!heading) continue;
579
+ if (heading.text.toLowerCase() === target) {
580
+ start = i;
581
+ level = heading.level;
582
+ break;
583
+ }
584
+ }
585
+ if (start === -1) return content;
586
+ let end = lines.length;
587
+ for (let i = start + 1; i < lines.length; i += 1) {
588
+ const heading = extractHeadingText(lines[i]);
589
+ if (heading && heading.level <= level) {
590
+ end = i;
591
+ break;
592
+ }
593
+ }
594
+ return lines.slice(start, end).join("\n");
595
+ }
596
+ function findPageForSearchResult(pages, result) {
597
+ const resultPath = normalizeUrlPathname(result.url);
598
+ return pages.find((page) => normalizeUrlPathname(page.url) === resultPath);
599
+ }
600
+ function inferResultTitle(result, page) {
601
+ if (page) return page.title;
602
+ return stripHtml(result.content).trim().split("—")[0]?.trim() || result.url;
603
+ }
604
+ function formatAskAIContextResult(options) {
605
+ const { result, page, maxChars, baseUrl } = options;
606
+ const title = inferResultTitle(result, page);
607
+ const section = result.section;
608
+ const contextContent = clampText(cleanAskAIContextMarkdown(page ? extractSectionMarkdown(getAskAIPageContent(page), section) : [result.content, result.description].filter(Boolean).join("\n\n")), maxChars);
609
+ return {
610
+ ...result,
611
+ url: resolveAskAIContextUrl(result.url, baseUrl),
612
+ title,
613
+ contextContent
614
+ };
615
+ }
616
+ function getSearchResultKey(result) {
617
+ let hash = "";
618
+ try {
619
+ hash = new URL(result.url, "https://docs.local").hash.replace(/^#/, "");
620
+ } catch {
621
+ hash = result.url.split("#")[1]?.split(/[?&]/)[0] ?? "";
622
+ }
623
+ return `${normalizeUrlPathname(result.url)}#${normalizeWhitespace(hash || result.section || "").toLowerCase()}`;
624
+ }
625
+ function mergeSearchResults(...groups) {
626
+ const seen = /* @__PURE__ */ new Set();
627
+ const results = [];
628
+ for (const group of groups) for (const result of group) {
629
+ const key = getSearchResultKey(result);
630
+ if (seen.has(key)) continue;
631
+ seen.add(key);
632
+ results.push(result);
633
+ }
634
+ return results;
635
+ }
636
+ function shouldSupplementAskAIWithSimpleSearch(search) {
637
+ return search.enabled && search.provider !== "simple";
638
+ }
639
+ function rankAskAIContextResult(query, result) {
640
+ return scoreDocument(query, {
641
+ id: result.id,
642
+ url: result.url,
643
+ title: result.title,
644
+ content: result.contextContent,
645
+ description: result.description,
646
+ type: result.type,
647
+ section: result.section
648
+ });
649
+ }
650
+ function buildAskAIContextBlock(result) {
651
+ const lines = [`## ${result.title}`, `URL: ${result.url}`];
652
+ if (result.section) lines.push(`Section: ${result.section}`);
653
+ if (result.description) lines.push(`Search snippet: ${result.description}`);
654
+ lines.push("", result.contextContent);
655
+ return lines.join("\n").trim();
656
+ }
350
657
  function makeDocumentId(url, suffix) {
351
658
  return `${url}#${suffix}`;
352
659
  }
@@ -421,14 +728,16 @@ function buildDocsSearchDocuments(pages, chunking = {}) {
421
728
  });
422
729
  }
423
730
  function scoreDocument(query, document) {
424
- const q = query.toLowerCase().trim();
731
+ const q = normalizeWhitespace(query.toLowerCase().replace(/[?!.,;:]+$/g, ""));
425
732
  if (!q) return 0;
426
- const words = Array.from(new Set(q.split(/\s+/).filter(Boolean)));
733
+ const words = tokenizeSearchQuery(q);
427
734
  const title = document.title.toLowerCase();
428
735
  const section = document.section?.toLowerCase() ?? "";
429
736
  const description = document.description?.toLowerCase() ?? "";
430
737
  const content = document.content.toLowerCase();
431
738
  const url = document.url.toLowerCase();
739
+ const titleTokens = tokenizeSearchQuery(title);
740
+ const sectionTokens = tokenizeSearchQuery(section);
432
741
  let score = 0;
433
742
  if (title === q) score += 120;
434
743
  else if (title.startsWith(q)) score += 70;
@@ -472,6 +781,10 @@ function scoreDocument(query, document) {
472
781
  }
473
782
  if (matched) matchedWords += 1;
474
783
  }
784
+ if (words.length > 1) {
785
+ if (sectionTokens.length > 0 && words.every((word) => sectionTokens.includes(word))) score += 30;
786
+ if (document.type === "page" && titleTokens.length > 0 && words.every((word) => titleTokens.includes(word))) score += 24;
787
+ }
475
788
  if (matchedWords === words.length && words.length > 1) score += 20;
476
789
  if (document.type === "heading") score += 6;
477
790
  return score;
@@ -991,6 +1304,80 @@ async function performDocsSearch(options) {
991
1304
  return createSimpleSearchAdapter().search(query, context);
992
1305
  }
993
1306
  }
1307
+ async function buildDocsAskAIContext(options) {
1308
+ const limit = options.limit ?? 5;
1309
+ const searchLimit = Math.max(limit * 2, limit);
1310
+ const initialSearch = options.search === false ? true : options.search;
1311
+ const primarySearch = normalizeDocsSearchConfig(initialSearch).enabled ? initialSearch : true;
1312
+ const primarySearchConfig = normalizeDocsSearchConfig(primarySearch);
1313
+ const searchResults = mergeSearchResults(await performDocsSearch({
1314
+ pages: options.pages,
1315
+ query: options.query,
1316
+ search: primarySearch,
1317
+ locale: options.locale,
1318
+ pathname: options.pathname,
1319
+ siteTitle: options.siteTitle,
1320
+ limit: searchLimit
1321
+ }), shouldSupplementAskAIWithSimpleSearch(primarySearchConfig) ? await performDocsSearch({
1322
+ pages: options.pages,
1323
+ query: options.query,
1324
+ search: {
1325
+ provider: "simple",
1326
+ enabled: true,
1327
+ chunking: primarySearchConfig.chunking,
1328
+ maxResults: searchLimit
1329
+ },
1330
+ locale: options.locale,
1331
+ pathname: options.pathname,
1332
+ siteTitle: options.siteTitle,
1333
+ limit: searchLimit
1334
+ }) : []);
1335
+ const seen = /* @__PURE__ */ new Set();
1336
+ const maxResultChars = options.maxResultChars ?? DEFAULT_ASK_AI_RESULT_CHARS;
1337
+ const rankedResults = searchResults.map((result, index) => {
1338
+ const formatted = formatAskAIContextResult({
1339
+ result,
1340
+ page: findPageForSearchResult(options.pages, result),
1341
+ maxChars: maxResultChars,
1342
+ baseUrl: options.baseUrl
1343
+ });
1344
+ return {
1345
+ result,
1346
+ formatted,
1347
+ index,
1348
+ rank: rankAskAIContextResult(options.query, formatted)
1349
+ };
1350
+ }).sort((a, b) => b.rank - a.rank || a.index - b.index);
1351
+ const formattedResults = rankedResults.map((item) => item.formatted);
1352
+ const sectionResultPaths = new Set(formattedResults.filter((result) => result.section).map((result) => normalizeUrlPathname(result.url)));
1353
+ const results = formattedResults.filter((result) => result.section || !sectionResultPaths.has(normalizeUrlPathname(result.url))).filter((result) => {
1354
+ const key = getSearchResultKey(result);
1355
+ if (seen.has(key)) return false;
1356
+ seen.add(key);
1357
+ return result.contextContent.length > 0;
1358
+ }).slice(0, limit);
1359
+ const maxContextChars = options.maxContextChars ?? DEFAULT_ASK_AI_CONTEXT_CHARS;
1360
+ const blocks = [];
1361
+ let usedChars = 0;
1362
+ for (const result of results) {
1363
+ const block = buildAskAIContextBlock(result);
1364
+ const separatorChars = blocks.length === 0 ? 0 : 7;
1365
+ if (usedChars + separatorChars + block.length > maxContextChars) {
1366
+ const remaining = maxContextChars - usedChars - separatorChars;
1367
+ if (remaining > 400) blocks.push(clampText(block, remaining));
1368
+ break;
1369
+ }
1370
+ blocks.push(block);
1371
+ usedChars += separatorChars + block.length;
1372
+ }
1373
+ const context = blocks.join("\n\n---\n\n");
1374
+ return {
1375
+ context,
1376
+ results: results.slice(0, blocks.length),
1377
+ searchResults: rankedResults.map((item) => item.result),
1378
+ packageHints: inferDocsAskAIPackageHints(context)
1379
+ };
1380
+ }
994
1381
  function createCustomSearchAdapter(adapter) {
995
1382
  return {
996
1383
  provider: "custom",
@@ -999,4 +1386,4 @@ function createCustomSearchAdapter(adapter) {
999
1386
  }
1000
1387
 
1001
1388
  //#endregion
1002
- export { resolveDocsAnalyticsConfig as C, emitDocsAnalyticsEvent as S, resolvePageSidebarFolderIndexBehavior as _, createSimpleSearchAdapter as a, normalizeDocsRelated as b, resolveSearchRequestConfig as c, hashGeneratedAgentContent as d, normalizeGeneratedAgentContent as f, applySidebarFolderIndexBehavior as g, stripGeneratedAgentProvenance as h, createMcpSearchAdapter as i, GENERATED_AGENT_PROVENANCE_MARKER as l, serializeGeneratedAgentDocument as m, createAlgoliaSearchAdapter as n, createTypesenseSearchAdapter as o, parseGeneratedAgentDocument as p, createCustomSearchAdapter as r, performDocsSearch as s, buildDocsSearchDocuments as t, GENERATED_AGENT_PROVENANCE_VERSION as u, resolveSidebarFolderIndexBehavior as v, createDocsCloudAnalytics as w, renderDocsRelatedMarkdownLines as x, resolveSidebarFolderIndexBehaviorForPath as y };
1389
+ export { emitDocsObservabilityEvent as A, normalizeDocsRelated as C, createDocsAgentTraceId as D, createDocsAgentTraceContext as E, resolveDocsObservabilityConfig as M, createDocsCloudAnalytics as N, emitDocsAgentTraceEvent as O, resolveSidebarFolderIndexBehaviorForPath as S, DOCS_AGENT_TRACE_EVENT_TYPES as T, serializeGeneratedAgentDocument as _, createMcpSearchAdapter as a, resolvePageSidebarFolderIndexBehavior as b, formatDocsAskAIPackageHints as c, resolveSearchRequestConfig as d, GENERATED_AGENT_PROVENANCE_MARKER as f, parseGeneratedAgentDocument as g, normalizeGeneratedAgentContent as h, createCustomSearchAdapter as i, resolveDocsAnalyticsConfig as j, emitDocsAnalyticsEvent as k, inferDocsAskAIPackageHints as l, hashGeneratedAgentContent as m, buildDocsSearchDocuments as n, createSimpleSearchAdapter as o, GENERATED_AGENT_PROVENANCE_VERSION as p, createAlgoliaSearchAdapter as r, createTypesenseSearchAdapter as s, buildDocsAskAIContext as t, performDocsSearch as u, stripGeneratedAgentProvenance as v, renderDocsRelatedMarkdownLines as w, resolveSidebarFolderIndexBehavior as x, applySidebarFolderIndexBehavior as y };
@@ -0,0 +1,88 @@
1
+ import { Et as TypesenseDocsSearchConfig, G as DocsSearchConfig, K as DocsSearchDocument, L as DocsObservabilityConfig, R as DocsObservabilityEvent, U as DocsSearchAdapterFactory, V as DocsSearchAdapter, W as DocsSearchChunkingConfig, Y as DocsSearchResult, Z as DocsSearchSourcePage, _ as DocsAnalyticsConfig, d as CustomDocsSearchConfig, it as McpDocsSearchConfig, m as DocsAgentTraceEventInput, r as AlgoliaDocsSearchConfig, v as DocsAnalyticsEvent, y as DocsAnalyticsEventInput, z as DocsObservabilityEventInput } from "./types-D-OvczD4.mjs";
2
+
3
+ //#region src/cloud-analytics.d.ts
4
+ interface DocsCloudAnalyticsOptions {
5
+ enabled?: boolean;
6
+ console?: DocsAnalyticsConfig["console"];
7
+ includeInputs?: boolean;
8
+ projectId?: string;
9
+ apiKey?: string;
10
+ }
11
+ declare function createDocsCloudAnalytics(options?: DocsCloudAnalyticsOptions): DocsAnalyticsConfig;
12
+ //#endregion
13
+ //#region src/analytics.d.ts
14
+ declare const DOCS_AGENT_TRACE_EVENT_TYPES: readonly ["run.start", "run.end", "run.error", "user.input", "prompt.build", "retrieval.query", "retrieval.result", "retrieval.error", "model.call", "model.response", "model.stream", "model.error", "tool.call", "tool.result", "tool.error", "retry", "timeout", "error", "agent.final"];
15
+ interface DocsAgentTraceContext {
16
+ traceId: string;
17
+ name: string;
18
+ startedAt: string;
19
+ startedMs: number;
20
+ }
21
+ interface ResolvedDocsAnalyticsConfig {
22
+ enabled: boolean;
23
+ console: false | "log" | "info" | "debug";
24
+ includeInputs: boolean;
25
+ onEvent?: (event: DocsAnalyticsEvent) => void | Promise<void>;
26
+ }
27
+ interface ResolvedDocsObservabilityConfig {
28
+ enabled: boolean;
29
+ console: false | "log" | "info" | "debug";
30
+ includeInputs: boolean;
31
+ onEvent?: (event: DocsObservabilityEvent) => void | Promise<void>;
32
+ }
33
+ declare function createDocsAgentTraceId(prefix?: string): string;
34
+ declare function createDocsAgentTraceContext(name?: string): DocsAgentTraceContext;
35
+ declare function resolveDocsAnalyticsConfig(analytics?: boolean | DocsAnalyticsConfig): ResolvedDocsAnalyticsConfig;
36
+ declare function resolveDocsObservabilityConfig(observability?: boolean | DocsObservabilityConfig): ResolvedDocsObservabilityConfig;
37
+ declare function emitDocsAnalyticsEvent(analytics: boolean | DocsAnalyticsConfig | undefined, event: DocsAnalyticsEventInput): Promise<void>;
38
+ declare function emitDocsObservabilityEvent(observability: boolean | DocsObservabilityConfig | undefined, event: DocsObservabilityEventInput): Promise<void>;
39
+ declare function emitDocsAgentTraceEvent(observability: boolean | DocsObservabilityConfig | undefined, event: DocsAgentTraceEventInput): Promise<void>;
40
+ //#endregion
41
+ //#region src/search.d.ts
42
+ interface DocsAskAIContextResult extends DocsSearchResult {
43
+ title: string;
44
+ contextContent: string;
45
+ }
46
+ interface DocsAskAIContext {
47
+ context: string;
48
+ results: DocsAskAIContextResult[];
49
+ searchResults: DocsSearchResult[];
50
+ packageHints: DocsAskAIPackageHints;
51
+ }
52
+ interface DocsAskAIPackageHints {
53
+ packages: string[];
54
+ imports: string[];
55
+ installCommands: string[];
56
+ }
57
+ declare function inferDocsAskAIPackageHints(content: string): DocsAskAIPackageHints;
58
+ declare function formatDocsAskAIPackageHints(hints: DocsAskAIPackageHints, packageName?: string): string | undefined;
59
+ declare function buildDocsSearchDocuments(pages: DocsSearchSourcePage[], chunking?: DocsSearchChunkingConfig): DocsSearchDocument[];
60
+ declare function createSimpleSearchAdapter(): DocsSearchAdapter;
61
+ declare function createTypesenseSearchAdapter(config: TypesenseDocsSearchConfig): DocsSearchAdapter;
62
+ declare function resolveSearchRequestConfig(search: boolean | DocsSearchConfig | undefined, requestUrl?: string): boolean | DocsSearchConfig | undefined;
63
+ declare function createMcpSearchAdapter(config: McpDocsSearchConfig): DocsSearchAdapter;
64
+ declare function createAlgoliaSearchAdapter(config: AlgoliaDocsSearchConfig): DocsSearchAdapter;
65
+ declare function performDocsSearch(options: {
66
+ pages: DocsSearchSourcePage[];
67
+ query: string;
68
+ search?: boolean | DocsSearchConfig;
69
+ locale?: string;
70
+ pathname?: string;
71
+ siteTitle?: string;
72
+ limit?: number;
73
+ }): Promise<DocsSearchResult[]>;
74
+ declare function buildDocsAskAIContext(options: {
75
+ pages: DocsSearchSourcePage[];
76
+ query: string;
77
+ search?: boolean | DocsSearchConfig;
78
+ locale?: string;
79
+ pathname?: string;
80
+ siteTitle?: string;
81
+ baseUrl?: string;
82
+ limit?: number;
83
+ maxContextChars?: number;
84
+ maxResultChars?: number;
85
+ }): Promise<DocsAskAIContext>;
86
+ declare function createCustomSearchAdapter(adapter: DocsSearchAdapter | DocsSearchAdapterFactory): CustomDocsSearchConfig;
87
+ //#endregion
88
+ export { DocsCloudAnalyticsOptions as C, resolveDocsObservabilityConfig as S, createDocsAgentTraceId as _, createMcpSearchAdapter as a, emitDocsObservabilityEvent as b, formatDocsAskAIPackageHints as c, resolveSearchRequestConfig as d, DOCS_AGENT_TRACE_EVENT_TYPES as f, createDocsAgentTraceContext as g, ResolvedDocsObservabilityConfig as h, createCustomSearchAdapter as i, inferDocsAskAIPackageHints as l, ResolvedDocsAnalyticsConfig as m, buildDocsSearchDocuments as n, createSimpleSearchAdapter as o, DocsAgentTraceContext as p, createAlgoliaSearchAdapter as r, createTypesenseSearchAdapter as s, buildDocsAskAIContext as t, performDocsSearch as u, emitDocsAgentTraceEvent as v, createDocsCloudAnalytics as w, resolveDocsAnalyticsConfig as x, emitDocsAnalyticsEvent as y };
package/dist/server.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as DocsSearchAdapterContext, I as DocsSearchQuery, K as McpDocsSearchConfig, L as DocsSearchResult, N as DocsSearchConfig, P as DocsSearchDocument, Y as OpenDocsProvider, a as ApiReferenceRenderer, b as DocsConfig, g as DocsAnalyticsEventInput, h as DocsAnalyticsEvent, j as DocsSearchAdapterFactory, k as DocsSearchAdapter, m as DocsAnalyticsConfig, z as DocsSearchSourcePage } from "./types-BXgTvFFE.mjs";
2
- import { a as createSimpleSearchAdapter, c as resolveSearchRequestConfig, d as resolveDocsAnalyticsConfig, f as DocsCloudAnalyticsOptions, i as createMcpSearchAdapter, l as ResolvedDocsAnalyticsConfig, n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, p as createDocsCloudAnalytics, r as createCustomSearchAdapter, s as performDocsSearch, t as buildDocsSearchDocuments, u as emitDocsAnalyticsEvent } from "./search-Gvi81BSo.mjs";
1
+ import { D as DocsAskAIFeedbackMessage, E as DocsAskAIFeedbackData, G as DocsSearchConfig, H as DocsSearchAdapterContext, J as DocsSearchQuery, K as DocsSearchDocument, L as DocsObservabilityConfig, O as DocsAskAIFeedbackValue, R as DocsObservabilityEvent, T as DocsAskAIFeedbackConfig, U as DocsSearchAdapterFactory, V as DocsSearchAdapter, Y as DocsSearchResult, Z as DocsSearchSourcePage, _ as DocsAnalyticsConfig, a as ApiReferenceRenderer, g as DocsAgentTraceStatus, h as DocsAgentTraceEventType, it as McpDocsSearchConfig, k as DocsConfig, m as DocsAgentTraceEventInput, st as OpenDocsProvider, v as DocsAnalyticsEvent, y as DocsAnalyticsEventInput, z as DocsObservabilityEventInput } from "./types-D-OvczD4.mjs";
2
+ import { C as DocsCloudAnalyticsOptions, S as resolveDocsObservabilityConfig, _ as createDocsAgentTraceId, a as createMcpSearchAdapter, b as emitDocsObservabilityEvent, c as formatDocsAskAIPackageHints, d as resolveSearchRequestConfig, f as DOCS_AGENT_TRACE_EVENT_TYPES, g as createDocsAgentTraceContext, h as ResolvedDocsObservabilityConfig, i as createCustomSearchAdapter, l as inferDocsAskAIPackageHints, m as ResolvedDocsAnalyticsConfig, n as buildDocsSearchDocuments, o as createSimpleSearchAdapter, p as DocsAgentTraceContext, r as createAlgoliaSearchAdapter, s as createTypesenseSearchAdapter, t as buildDocsAskAIContext, u as performDocsSearch, v as emitDocsAgentTraceEvent, w as createDocsCloudAnalytics, x as resolveDocsAnalyticsConfig, y as emitDocsAnalyticsEvent } from "./search-DSKaQ2JH.mjs";
3
3
  import { DocsMcpHttpHandlers, DocsMcpNavigationNode, DocsMcpNavigationTree, DocsMcpPage, DocsMcpResolvedConfig, DocsMcpSource, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, normalizeDocsMcpRoute, resolveDocsMcpConfig, runDocsMcpStdio } from "./mcp.mjs";
4
4
 
5
5
  //#region src/api-reference.d.ts
@@ -63,4 +63,4 @@ declare function parsePromptStringArray(value: unknown): string[] | undefined;
63
63
  declare function resolvePromptProviderChoices(availableProviders?: PromptProviderInput[], preferredNames?: string[]): PromptProviderChoice[];
64
64
  declare function sanitizePromptText(text: string): string;
65
65
  //#endregion
66
- export { type ApiReferenceFramework, type ApiReferenceRenderer, type ApiReferenceRoute, DEFAULT_PROMPT_PROVIDER_TEMPLATES, type DocsAnalyticsConfig, type DocsAnalyticsEvent, type DocsAnalyticsEventInput, type DocsCloudAnalyticsOptions, type DocsMcpHttpHandlers, type DocsMcpNavigationNode, type DocsMcpNavigationTree, type DocsMcpPage, type DocsMcpResolvedConfig, type DocsMcpSource, type DocsSearchAdapter, type DocsSearchAdapterContext, type DocsSearchAdapterFactory, type DocsSearchConfig, type DocsSearchDocument, type DocsSearchQuery, type DocsSearchResult, type DocsSearchSourcePage, type McpDocsSearchConfig, type PromptAction, type PromptProviderChoice, type ResolvedApiReferenceConfig, type ResolvedDocsAnalyticsConfig, type SerializedOpenDocsProvider, buildApiReferenceHtmlDocument, buildApiReferenceHtmlDocumentAsync, buildApiReferenceOpenApiDocument, buildApiReferenceOpenApiDocumentAsync, buildApiReferencePageTitle, buildApiReferenceScalarCss, buildDocsSearchDocuments, createAlgoliaSearchAdapter, createCustomSearchAdapter, createDocsCloudAnalytics, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, createMcpSearchAdapter, createSimpleSearchAdapter, createTypesenseSearchAdapter, emitDocsAnalyticsEvent, normalizeDocsMcpRoute, normalizePromptProviderName, parsePromptStringArray, performDocsSearch, resolveApiReferenceConfig, resolveApiReferenceRenderer, resolveDocsAnalyticsConfig, resolveDocsMcpConfig, resolvePromptProviderChoices, resolveSearchRequestConfig, runDocsMcpStdio, sanitizePromptText, serializeDocsIcon, serializeDocsIconRegistry, serializeOpenDocsProviders };
66
+ export { type ApiReferenceFramework, type ApiReferenceRenderer, type ApiReferenceRoute, DEFAULT_PROMPT_PROVIDER_TEMPLATES, DOCS_AGENT_TRACE_EVENT_TYPES, type DocsAgentTraceContext, type DocsAgentTraceEventInput, type DocsAgentTraceEventType, type DocsAgentTraceStatus, type DocsAnalyticsConfig, type DocsAnalyticsEvent, type DocsAnalyticsEventInput, type DocsAskAIFeedbackConfig, type DocsAskAIFeedbackData, type DocsAskAIFeedbackMessage, type DocsAskAIFeedbackValue, type DocsCloudAnalyticsOptions, type DocsMcpHttpHandlers, type DocsMcpNavigationNode, type DocsMcpNavigationTree, type DocsMcpPage, type DocsMcpResolvedConfig, type DocsMcpSource, type DocsObservabilityConfig, type DocsObservabilityEvent, type DocsObservabilityEventInput, type DocsSearchAdapter, type DocsSearchAdapterContext, type DocsSearchAdapterFactory, type DocsSearchConfig, type DocsSearchDocument, type DocsSearchQuery, type DocsSearchResult, type DocsSearchSourcePage, type McpDocsSearchConfig, type PromptAction, type PromptProviderChoice, type ResolvedApiReferenceConfig, type ResolvedDocsAnalyticsConfig, type ResolvedDocsObservabilityConfig, type SerializedOpenDocsProvider, buildApiReferenceHtmlDocument, buildApiReferenceHtmlDocumentAsync, buildApiReferenceOpenApiDocument, buildApiReferenceOpenApiDocumentAsync, buildApiReferencePageTitle, buildApiReferenceScalarCss, buildDocsAskAIContext, buildDocsSearchDocuments, createAlgoliaSearchAdapter, createCustomSearchAdapter, createDocsAgentTraceContext, createDocsAgentTraceId, createDocsCloudAnalytics, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, createMcpSearchAdapter, createSimpleSearchAdapter, createTypesenseSearchAdapter, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, emitDocsObservabilityEvent, formatDocsAskAIPackageHints, inferDocsAskAIPackageHints, normalizeDocsMcpRoute, normalizePromptProviderName, parsePromptStringArray, performDocsSearch, resolveApiReferenceConfig, resolveApiReferenceRenderer, resolveDocsAnalyticsConfig, resolveDocsMcpConfig, resolveDocsObservabilityConfig, resolvePromptProviderChoices, resolveSearchRequestConfig, runDocsMcpStdio, sanitizePromptText, serializeDocsIcon, serializeDocsIconRegistry, serializeOpenDocsProviders };
package/dist/server.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { C as resolveDocsAnalyticsConfig, S as emitDocsAnalyticsEvent, a as createSimpleSearchAdapter, c as resolveSearchRequestConfig, i as createMcpSearchAdapter, n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, r as createCustomSearchAdapter, s as performDocsSearch, t as buildDocsSearchDocuments, w as createDocsCloudAnalytics } from "./search-DQTtxgAV.mjs";
1
+ import { A as emitDocsObservabilityEvent, D as createDocsAgentTraceId, E as createDocsAgentTraceContext, M as resolveDocsObservabilityConfig, N as createDocsCloudAnalytics, O as emitDocsAgentTraceEvent, T as DOCS_AGENT_TRACE_EVENT_TYPES, a as createMcpSearchAdapter, c as formatDocsAskAIPackageHints, d as resolveSearchRequestConfig, i as createCustomSearchAdapter, j as resolveDocsAnalyticsConfig, k as emitDocsAnalyticsEvent, l as inferDocsAskAIPackageHints, n as buildDocsSearchDocuments, o as createSimpleSearchAdapter, r as createAlgoliaSearchAdapter, s as createTypesenseSearchAdapter, t as buildDocsAskAIContext, u as performDocsSearch } from "./search-DBZ6Tkij.mjs";
2
2
  import { a as sanitizePromptText, c as serializeOpenDocsProviders, d as buildApiReferenceOpenApiDocument, f as buildApiReferenceOpenApiDocumentAsync, g as resolveApiReferenceRenderer, h as resolveApiReferenceConfig, i as resolvePromptProviderChoices, l as buildApiReferenceHtmlDocument, m as buildApiReferenceScalarCss, n as normalizePromptProviderName, o as serializeDocsIcon, p as buildApiReferencePageTitle, r as parsePromptStringArray, s as serializeDocsIconRegistry, t as DEFAULT_PROMPT_PROVIDER_TEMPLATES, u as buildApiReferenceHtmlDocumentAsync } from "./prompt-utils-8nmFLQVH.mjs";
3
3
  import { createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, normalizeDocsMcpRoute, resolveDocsMcpConfig, runDocsMcpStdio } from "./mcp.mjs";
4
4
 
5
- export { DEFAULT_PROMPT_PROVIDER_TEMPLATES, buildApiReferenceHtmlDocument, buildApiReferenceHtmlDocumentAsync, buildApiReferenceOpenApiDocument, buildApiReferenceOpenApiDocumentAsync, buildApiReferencePageTitle, buildApiReferenceScalarCss, buildDocsSearchDocuments, createAlgoliaSearchAdapter, createCustomSearchAdapter, createDocsCloudAnalytics, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, createMcpSearchAdapter, createSimpleSearchAdapter, createTypesenseSearchAdapter, emitDocsAnalyticsEvent, normalizeDocsMcpRoute, normalizePromptProviderName, parsePromptStringArray, performDocsSearch, resolveApiReferenceConfig, resolveApiReferenceRenderer, resolveDocsAnalyticsConfig, resolveDocsMcpConfig, resolvePromptProviderChoices, resolveSearchRequestConfig, runDocsMcpStdio, sanitizePromptText, serializeDocsIcon, serializeDocsIconRegistry, serializeOpenDocsProviders };
5
+ export { DEFAULT_PROMPT_PROVIDER_TEMPLATES, DOCS_AGENT_TRACE_EVENT_TYPES, buildApiReferenceHtmlDocument, buildApiReferenceHtmlDocumentAsync, buildApiReferenceOpenApiDocument, buildApiReferenceOpenApiDocumentAsync, buildApiReferencePageTitle, buildApiReferenceScalarCss, buildDocsAskAIContext, buildDocsSearchDocuments, createAlgoliaSearchAdapter, createCustomSearchAdapter, createDocsAgentTraceContext, createDocsAgentTraceId, createDocsCloudAnalytics, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, createMcpSearchAdapter, createSimpleSearchAdapter, createTypesenseSearchAdapter, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, emitDocsObservabilityEvent, formatDocsAskAIPackageHints, inferDocsAskAIPackageHints, normalizeDocsMcpRoute, normalizePromptProviderName, parsePromptStringArray, performDocsSearch, resolveApiReferenceConfig, resolveApiReferenceRenderer, resolveDocsAnalyticsConfig, resolveDocsMcpConfig, resolveDocsObservabilityConfig, resolvePromptProviderChoices, resolveSearchRequestConfig, runDocsMcpStdio, sanitizePromptText, serializeDocsIcon, serializeDocsIconRegistry, serializeOpenDocsProviders };