Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/llms-full.txt/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export async function GET() {
const scan = source
.getPages()
.filter((page) => !page.url.includes('/changelog/') && shouldIncludeLLMPage(page))
.map(getLLMText);
.map((page) => getLLMText(page));
const scanned = await Promise.all(scan);

return new Response(AGENT_INSTRUCTIONS + scanned.join('\n\n'), {
Expand Down
2 changes: 1 addition & 1 deletion app/llms.mdx/[[...slug]]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export async function GET(_req: NextRequest, { params }: { params: Promise<{ slu
const headers = new Headers({ 'Content-Type': 'text/markdown; charset=utf-8' });
appendMarkdownVaryHeader(headers);

return new NextResponse(await getLLMText(page), {
return new NextResponse(await getLLMText(page, { indexPointer: true }), {
headers,
});
}
Expand Down
14 changes: 11 additions & 3 deletions lib/get-llm-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@ export function shouldIncludeLLMPage(page: InferPageType<typeof source>) {
}
}

export async function getLLMText(page: InferPageType<typeof source>) {
const SITE_URL = process.env.LLMS_BASE_URL || 'https://docs.steel.dev';

export const LLMS_INDEX_POINTER = `> Full docs index: ${SITE_URL}/llms.txt`;

export async function getLLMText(
page: InferPageType<typeof source>,
options: { indexPointer?: boolean } = {},
) {
const processed = stripFaqFences(page.data.content);
const pointer = options.indexPointer ? `${LLMS_INDEX_POINTER}\n\n` : '';

return `# ${page.data.title}
URL: ${page.url}
return `${pointer}# ${page.data.title}
URL: ${SITE_URL}${page.url}

${processed}`;
}
16 changes: 12 additions & 4 deletions tests/e2e/md-suffix.test.ts → tests/e2e/llm-endpoints.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ABOUTME: End-to-end tests that boot the Next.js dev server and verify
// ABOUTME: .md-suffixed docs URLs serve markdown while canonical URLs stay HTML.
// ABOUTME: End-to-end tests that boot the Next.js dev server and verify the
// ABOUTME: LLM-facing endpoints: .md-suffixed URLs, index pointer, llms-full.txt.
import { afterAll, beforeAll, describe, expect, setDefaultTimeout, test } from 'bun:test';
import { fileURLToPath } from 'node:url';

Expand Down Expand Up @@ -52,13 +52,21 @@ describe('.md suffix end-to-end', () => {
await server?.exited;
});

test('serves markdown at a .md-suffixed docs URL', async () => {
test('serves markdown with the index pointer at a .md-suffixed docs URL', async () => {
const response = await fetch(`${BASE_URL}/overview/sessions-api/quickstart.md`, {
headers: BROWSER_HEADERS,
});
expect(response.status).toBe(200);
expect(response.headers.get('content-type')).toStartWith('text/markdown');
expect(await response.text()).toStartWith('# Quickstart');
const body = await response.text();
expect(body).toStartWith('> Full docs index: https://docs.steel.dev/llms.txt');
expect(body).toContain('# Quickstart');
});

test('llms-full.txt does not repeat the index pointer', async () => {
const response = await fetch(`${BASE_URL}/llms-full.txt`, { headers: BROWSER_HEADERS });
expect(response.status).toBe(200);
expect(await response.text()).not.toContain('Full docs index');
});

test('returns 404 for a .md URL with no matching page', async () => {
Expand Down
40 changes: 40 additions & 0 deletions tests/get-llm-text.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// ABOUTME: Tests for getLLMText, which renders a page as LLM-facing markdown
// ABOUTME: with an absolute URL and an optional llms.txt index pointer.
import { describe, expect, test } from 'bun:test';
import { getLLMText, LLMS_INDEX_POINTER } from '../lib/get-llm-text';

// Minimal stand-in for a fumadocs page; typed any since building a real
// InferPageType requires the full fumadocs loader.
function fakePage(overrides: Record<string, unknown> = {}): any {
return {
url: '/overview/steel-cli',
data: {
title: 'Steel CLI',
content: 'Run browser automation from the terminal.',
...overrides,
},
};
}

describe('getLLMText', () => {
test('renders the title and an absolute URL', async () => {
const text = await getLLMText(fakePage());
expect(text).toStartWith('# Steel CLI\n');
expect(text).toContain('URL: https://docs.steel.dev/overview/steel-cli');
});

test('omits the index pointer by default', async () => {
const text = await getLLMText(fakePage());
expect(text).not.toContain('Full docs index');
});

test('prepends the index pointer exactly once when requested', async () => {
const text = await getLLMText(fakePage(), { indexPointer: true });
expect(text).toStartWith(`${LLMS_INDEX_POINTER}\n\n# Steel CLI\n`);
expect(text.split('Full docs index').length).toBe(2);
});

test('the pointer is a blockquote linking to llms.txt', () => {
expect(LLMS_INDEX_POINTER).toBe('> Full docs index: https://docs.steel.dev/llms.txt');
});
});
Loading