@stainless-api/docs 0.1.0-beta.66 → 0.1.0-beta.68

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @stainless-api/docs
2
2
 
3
+ ## 0.1.0-beta.68
4
+
5
+ ### Patch Changes
6
+
7
+ - add prose docs vector indexing
8
+
9
+ ## 0.1.0-beta.67
10
+
11
+ ### Patch Changes
12
+
13
+ - a59d5f7: Pass current page context through as “intent”
14
+ - Updated dependencies [e9567b0]
15
+ - @stainless-api/ui-primitives@0.1.0-beta.40
16
+ - @stainless-api/docs-ui@0.1.0-beta.53
17
+ - @stainless-api/docs-search@0.1.0-beta.5
18
+
3
19
  ## 0.1.0-beta.66
4
20
 
5
21
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stainless-api/docs",
3
- "version": "0.1.0-beta.66",
3
+ "version": "0.1.0-beta.68",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -53,9 +53,9 @@
53
53
  "vite-plugin-prebundle-workers": "^0.2.0",
54
54
  "web-worker": "^1.5.0",
55
55
  "yaml": "^2.8.2",
56
- "@stainless-api/docs-search": "0.1.0-beta.4",
57
- "@stainless-api/docs-ui": "0.1.0-beta.52",
58
- "@stainless-api/ui-primitives": "0.1.0-beta.39"
56
+ "@stainless-api/docs-search": "0.1.0-beta.5",
57
+ "@stainless-api/docs-ui": "0.1.0-beta.53",
58
+ "@stainless-api/ui-primitives": "0.1.0-beta.40"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@astrojs/check": "^0.9.6",
@@ -1,8 +1,14 @@
1
1
  import type { DocsLanguage } from '@stainless-api/docs-ui/routing';
2
2
  import AiChat, { STAINLESS_PROJECT } from 'virtual:stl-docs/components/AiChat.tsx';
3
3
 
4
- export default function AiChatIsland({ currentLanguage }: { currentLanguage: DocsLanguage | undefined }) {
4
+ export default function AiChatIsland({
5
+ currentLanguage,
6
+ siteTitle,
7
+ }: {
8
+ currentLanguage: DocsLanguage | undefined;
9
+ siteTitle: string | undefined;
10
+ }) {
5
11
  if (!AiChat) throw new Error('AiChatIsland was rendered but could not load AiChat component');
6
12
  if (!STAINLESS_PROJECT) return null;
7
- return <AiChat projectId={STAINLESS_PROJECT} language={currentLanguage} />;
13
+ return <AiChat projectId={STAINLESS_PROJECT} language={currentLanguage} siteTitle={siteTitle} />;
8
14
  }
@@ -2,6 +2,10 @@
2
2
  import Default from '@astrojs/starlight/components/PageFrame.astro';
3
3
  import AiChat from 'virtual:stl-docs/components/AiChat.tsx'; // conditionally resolves to null if ai chat module is not injected
4
4
  import AiChatIsland from './AiChatIsland.tsx'; // entrypoint for client island can’t be a virtual module
5
+
6
+ import starlightConfig from 'virtual:starlight/user-config';
7
+ const locale = Astro.currentLocale ?? starlightConfig.defaultLocale.lang;
8
+ const siteTitle = locale && starlightConfig.title[locale];
5
9
  ---
6
10
 
7
11
  <Default>
@@ -10,5 +14,5 @@ import AiChatIsland from './AiChatIsland.tsx'; // entrypoint for client island c
10
14
 
11
15
  <slot />
12
16
 
13
- {!!AiChat && <AiChatIsland client:load currentLanguage={Astro.locals.language} />}
17
+ {!!AiChat && <AiChatIsland client:load currentLanguage={Astro.locals.language} siteTitle={siteTitle} />}
14
18
  </Default>
package/stl-docs/index.ts CHANGED
@@ -22,7 +22,7 @@ import type * as StlDocsVirtualModule from 'virtual:stl-docs-virtual-module';
22
22
  import { resolveSrcFile } from '../resolveSrcFile';
23
23
  import { stainlessDocsMarkdownRenderer } from './proseMarkdown/proseMarkdownIntegration';
24
24
  import { setSharedLogger } from '../shared/getSharedLogger';
25
- import { stainlessDocsProseIndexing } from './proseSearchIndexing';
25
+ import { stainlessDocsAlgoliaProseIndexing, stainlessDocsVectorProseIndexing } from './proseSearchIndexing';
26
26
 
27
27
  export * from '../plugin';
28
28
 
@@ -271,6 +271,7 @@ export function stainlessDocs(config: StainlessDocsUserConfig) {
271
271
  enabled: normalizedConfig.enableProseMarkdownRendering,
272
272
  apiReferenceBasePath,
273
273
  }),
274
- stainlessDocsProseIndexing({ apiReferenceBasePath }),
274
+ stainlessDocsAlgoliaProseIndexing({ apiReferenceBasePath }),
275
+ stainlessDocsVectorProseIndexing(normalizedConfig, apiReferenceBasePath),
275
276
  ];
276
277
  }
@@ -3,8 +3,10 @@ import { readFile } from 'fs/promises';
3
3
  import { getProsePages } from '../shared/getProsePages';
4
4
  import { getSharedLogger } from '../shared/getSharedLogger';
5
5
  import { bold } from '../shared/terminalUtils';
6
- import { buildProseIndex } from '@stainless-api/docs-search/providers/algolia';
7
6
  import * as cheerio from 'cheerio';
7
+ import { toMarkdown } from './proseMarkdown/toMarkdown';
8
+ import { NormalizedStainlessDocsConfig } from './loadStlDocsConfig';
9
+ import { buildProseIndex } from '@stainless-api/docs-search/providers/algolia';
8
10
 
9
11
  interface ContentBlock {
10
12
  type: 'header' | 'content';
@@ -307,7 +309,7 @@ export function* indexHTML(content: string, root: string, pattern: string) {
307
309
  const root = 'main';
308
310
  const pattern = 'h1, h2, h3, h4, h5, h6, p, li';
309
311
 
310
- export function stainlessDocsProseIndexing({
312
+ export function stainlessDocsAlgoliaProseIndexing({
311
313
  apiReferenceBasePath,
312
314
  }: {
313
315
  apiReferenceBasePath: string | null;
@@ -331,7 +333,7 @@ export function stainlessDocsProseIndexing({
331
333
  }
332
334
 
333
335
  const pagesToRender = await getProsePages({ apiReferenceBasePath, outputBasePath });
334
- logger.info(bold(`Indexing ${pagesToRender.length} prose pages for search`));
336
+ logger.info(bold(`Indexing ${pagesToRender.length} prose pages for algolia search`));
335
337
 
336
338
  const objects = [];
337
339
  for (const absHtmlPath of pagesToRender) {
@@ -353,3 +355,96 @@ export function stainlessDocsProseIndexing({
353
355
  },
354
356
  };
355
357
  }
358
+
359
+ export function stainlessDocsVectorProseIndexing(
360
+ config: NormalizedStainlessDocsConfig,
361
+ apiReferenceBasePath: string | null,
362
+ ): AstroIntegration {
363
+ return {
364
+ name: 'stl-docs-prose-indexing',
365
+ hooks: {
366
+ 'astro:build:done': async ({ logger: localLogger, dir }) => {
367
+ const logger = getSharedLogger({ fallback: localLogger });
368
+ const outputBasePath = dir.pathname;
369
+
370
+ const stainlessProjectName = config.apiReference?.stainlessProject;
371
+
372
+ const {
373
+ STAINLESS_API_KEY: stainlessApiKey,
374
+ STAINLESS_DOCS_SITE_ID: stainlessDocsSiteId,
375
+ STAINLESS_DOCS_REPO_SHA: stainlessDocsRepoSha,
376
+ } = process.env;
377
+
378
+ // Skip indexing if required environment variables are not set
379
+ if (!stainlessApiKey || !stainlessProjectName || !stainlessDocsSiteId || !stainlessDocsRepoSha) {
380
+ logger.info(
381
+ `Skipping vector prose search indexing: required environment/config variables not set, missing: ${[
382
+ !stainlessApiKey && 'STAINLESS_API_KEY',
383
+ !stainlessDocsSiteId && 'STAINLESS_DOCS_SITE_ID',
384
+ !stainlessDocsRepoSha && 'STAINLESS_DOCS_REPO_SHA',
385
+ !stainlessProjectName && 'stainlessProject in apiReference config',
386
+ ]
387
+ .filter(Boolean)
388
+ .join(', ')}`,
389
+ );
390
+ return;
391
+ }
392
+
393
+ const pagesToRender = await getProsePages({ apiReferenceBasePath, outputBasePath });
394
+
395
+ if (pagesToRender.length === 0) {
396
+ logger.info('No prose pages found to index for vector search');
397
+ return;
398
+ }
399
+
400
+ logger.info(bold(`Indexing ${pagesToRender.length} prose pages for vector search`));
401
+
402
+ const objects: {
403
+ id: string;
404
+ tag: string;
405
+ content: string;
406
+ kind: 'prose';
407
+ source: string;
408
+ }[] = [];
409
+ for (const absHtmlPath of pagesToRender) {
410
+ const content = await readFile(absHtmlPath, 'utf-8');
411
+ const markdown = await toMarkdown(content);
412
+
413
+ if (markdown) {
414
+ const idx = indexMarkdown(markdown);
415
+ for (const { chunk, ...entry } of idx)
416
+ objects.push({
417
+ ...entry,
418
+ kind: 'prose',
419
+ source: absHtmlPath.slice(outputBasePath.length),
420
+ });
421
+ }
422
+ }
423
+
424
+ if (objects.length === 0) {
425
+ logger.info('No prose content extracted to index for vector search');
426
+ return;
427
+ }
428
+
429
+ logger.info(bold(`Uploading ${objects.length} prose content chunks to stainless docs index`));
430
+
431
+ const response = await fetch(
432
+ `https://api.stainless.com/api/projects/${stainlessProjectName}/docs-sites/${stainlessDocsSiteId}/index`,
433
+ {
434
+ method: 'POST',
435
+ headers: {
436
+ 'Content-Type': 'application/json',
437
+ Authorization: `Bearer ${stainlessApiKey}`,
438
+ },
439
+ body: JSON.stringify({
440
+ docs_repo_sha: stainlessDocsRepoSha,
441
+ index: objects,
442
+ }),
443
+ },
444
+ );
445
+
446
+ console.log(`docs index API response code ${response.status}: ${await response.text()}`);
447
+ },
448
+ },
449
+ };
450
+ }
@@ -56,6 +56,7 @@ declare module 'virtual:stl-docs/components/AiChat.tsx' {
56
56
  | import('react').ComponentType<{
57
57
  projectId: string;
58
58
  language: import('@stainless-api/docs-ui/routing').DocsLanguage | undefined;
59
+ siteTitle: string | undefined;
59
60
  }>
60
61
  | null;
61
62
  export default AiChatComponent;