diff --git a/packages/gitbook/src/lib/ask-prompt.ts b/packages/gitbook/src/lib/ask-prompt.ts index f6c2aebe9..ef73b6a63 100644 --- a/packages/gitbook/src/lib/ask-prompt.ts +++ b/packages/gitbook/src/lib/ask-prompt.ts @@ -1,10 +1,6 @@ -/** - * Describe the `ask` and `goal` query parameters of the ask endpoint, for agent-facing prompts. - */ -export function renderAskParametersDescription(): string { - return `\`ask\` is the immediate question: it should be specific, self-contained, and written in natural language. -\`goal\` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with \`ask=how do I create an API token\`, a goal like \`build a script that syncs our docs to a CMS\` lets GitBook tailor the answer to that use case.`; -} +import { isAIEnabled } from '@/components/utils/isAIChatEnabled'; +import type { GitBookSiteContext } from '@/lib/context'; +import { linkerWithMarkdownPages } from '@/lib/links'; /** * Render the "Querying This Documentation" section of the agent instructions. @@ -18,7 +14,46 @@ export function renderQueryingDocumentation(options: { pageUrl: string }): strin GET ${pageUrl}?ask=&goal= \`\`\` -${renderAskParametersDescription()} +\`ask\` is the immediate question: it should be specific, self-contained, and written in natural language. +\`goal\` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with \`ask=how do I create an API token\`, a goal like \`automate deployments from our CI pipeline\` lets GitBook tailor the answer to that use case. The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.`; } + +const AGENT_INSTRUCTIONS_INTRO = `# Agent Instructions +This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. + +## Querying This Documentation`; + +/** + * Render the "Agent Instructions" of a markdown page (callers add the separator). + */ +export function renderPageAgentInstructions(options: { pageUrl: string }): string { + return `${AGENT_INSTRUCTIONS_INTRO} +If you need additional information that is not directly available in this page, you can query the documentation by asking a question. + +${renderQueryingDocumentation(options)} + +Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. +`; +} + +/** + * Render the "Agent Instructions" of the site-wide llms.txt and llms-full.txt files. + * Returns `undefined` when AI is disabled for the site. + */ +export function renderSiteAgentInstructions(context: GitBookSiteContext): string | undefined { + if (!isAIEnabled(context.customization.ai.mode)) { + return undefined; + } + + // The ask endpoint ignores the page path, so the top-level `index.md` works on every site. + const linker = linkerWithMarkdownPages(context.linker); + const pageUrl = linker.toAbsoluteURL(linker.toPathForPagePath({ path: 'index' })); + + return `${AGENT_INSTRUCTIONS_INTRO} +This site has an agentic ask interface you may use to query the documentation dynamically by asking a question. + +${renderQueryingDocumentation({ pageUrl })} +`; +} diff --git a/packages/gitbook/src/routes/llms-full.ts b/packages/gitbook/src/routes/llms-full.ts index b89c341e7..2535cc159 100644 --- a/packages/gitbook/src/routes/llms-full.ts +++ b/packages/gitbook/src/routes/llms-full.ts @@ -4,6 +4,7 @@ import pMap, { pMapIterable } from 'p-map'; import type { RevisionPageDocument, SiteSection, SiteSpace } from '@gitbook/api'; +import { renderSiteAgentInstructions } from '@/lib/ask-prompt'; import { type GitBookSiteContext, checkIsRootSiteContext, @@ -171,6 +172,12 @@ async function streamMarkdownPageEntries( stream.enqueue(new TextEncoder().encode(`${header.join('\n')}\n\n`)); } + // Rendered up front, on every part, since agents may only read the start of the file. + const agentInstructions = renderSiteAgentInstructions(context); + if (agentInstructions) { + stream.enqueue(new TextEncoder().encode(`${agentInstructions}\n---\n\n`)); + } + // Process the pages for await (const markdown of pMapIterable( pagesToProcess, diff --git a/packages/gitbook/src/routes/llms.ts b/packages/gitbook/src/routes/llms.ts index ebd51d401..a77026ee5 100644 --- a/packages/gitbook/src/routes/llms.ts +++ b/packages/gitbook/src/routes/llms.ts @@ -4,12 +4,11 @@ import { toMarkdown } from 'mdast-util-to-markdown'; import type { SiteSection, SiteSpace } from '@gitbook/api'; -import { isAIEnabled } from '@/components/utils/isAIChatEnabled'; +import { renderSiteAgentInstructions } from '@/lib/ask-prompt'; import { type GitBookSiteContext, checkIsRootSiteContext } from '@/lib/context'; import { throwIfDataError } from '@/lib/data'; import { type GitBookLinker, linkerWithMarkdownPages } from '@/lib/links'; import { getMarkdownContentType } from '@/lib/markdown-content-type'; -import { resolveFirstDocument } from '@/lib/pages'; import { type FlatPageEntry, getIndexablePages } from '@/lib/sitemap'; import { filterSiteSpacesByLocale, @@ -49,7 +48,10 @@ export async function serveLLMsTxt(baseContext: GitBookSiteContext) { bullet: '-', }); - output += renderAskFooter(context); + const agentInstructions = renderSiteAgentInstructions(context); + if (agentInstructions) { + output += `\n\n---\n\n${agentInstructions}`; + } return new Response(output, { headers: { @@ -205,27 +207,3 @@ export async function getMarkdownForPagesTree( }); return nodes; } - -function renderAskFooter(context: GitBookSiteContext) { - if (!isAIEnabled(context.customization.ai.mode)) { - return ''; - } - - return `\n\n---\n\n# Agent Instructions -This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. - -## Querying This Documentation -If you need additional information, you can query the documentation dynamically by asking a question. -Perform an HTTP GET request on a page URL with the \`ask\` query parameter: -\`\`\` -GET ${context.linker.toAbsoluteURL( - context.linker.toPathForPagePath({ - path: resolveFirstDocument(context.revision.pages, [])?.page.path ?? 'index', - }) - )}?ask= -\`\`\` -The question should be specific, self-contained, and written in natural language. -The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. -Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. -`; -} diff --git a/packages/gitbook/src/routes/markdownPage.ts b/packages/gitbook/src/routes/markdownPage.ts index f2d670d81..d78bcfd4d 100644 --- a/packages/gitbook/src/routes/markdownPage.ts +++ b/packages/gitbook/src/routes/markdownPage.ts @@ -2,7 +2,7 @@ import type { RevisionPageDocument, RevisionPageGroup } from '@gitbook/api'; import { resolveMissingPagePath } from '@/components/SitePage/fetch'; import { isAIEnabled } from '@/components/utils/isAIChatEnabled'; -import { renderQueryingDocumentation } from '@/lib/ask-prompt'; +import { renderPageAgentInstructions, renderQueryingDocumentation } from '@/lib/ask-prompt'; import type { GitBookSiteContext } from '@/lib/context'; import { getExposableError } from '@/lib/data'; import { linkerWithMarkdownPages } from '@/lib/links'; @@ -184,16 +184,7 @@ function renderAskFooter( }) ); - return `\n\n---\n\n# Agent Instructions -This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. - -## Querying This Documentation -If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. - -${renderQueryingDocumentation({ pageUrl })} - -Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. -`; + return `\n\n---\n\n${renderPageAgentInstructions({ pageUrl })}`; } /**