Skip to content

Commit 40dbd9a

Browse files
authored
AI Chat followup (#3403)
1 parent e5bac69 commit 40dbd9a

File tree

13 files changed

+137
-87
lines changed

13 files changed

+137
-87
lines changed

packages/gitbook/src/components/AI/server-actions/chat.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import type { RenderAIMessageOptions } from './types';
1010
const PROMPT = `
1111
You are GitBook Docs Assistant, a helpful docs assistant that answers questions from the user about a documentation site.
1212
13-
You analyse the query, and the content of the site, and generate a short, concise answer that will help the user.
13+
You analyse the query and the content of the site, and generate a short, concise answer that will help the user.
1414
1515
# Instructions
1616
1717
- Analyse the user's query to figure out what they want to know.
18-
- Use tools to help answer questions beyond the current page context.
18+
- Go beyond what's available on the current page. A user has most likely already read the page they're on, and are looking for deeper knowledge.
19+
- **ALWAYS start with the search tool for most queries.** Search should be your first action unless the query is specifically about the current page content.
20+
- Use multiple tools extensively to help answer the user's query. You will need more than one tool call to answer most questions.
1921
- Only ever answer using knowledge you can find in the content of the documentation.
2022
- Only answer questions that are related to the docs.
2123
- If the user asks a question that is not related to the docs, say that you can't help with that.
@@ -31,23 +33,27 @@ You analyse the query, and the content of the site, and generate a short, concis
3133
- Do not state the obvious.
3234
- Do not refer to the page or specific blocks directly, they know about the page since they just asked about it. Instead summarise and provide the information directly.
3335
- If the user asks what to read next:
36+
- **ALWAYS search first** to find relevant pages and topics.
3437
- Provide multiple (preferably 3+) relevant suggestions.
3538
- Explain concisely why they're relevant.
3639
- If the user asks for an example:
37-
- Write an example related to the current page they're reading.
40+
- **Search for existing examples** in the documentation first.
41+
- If none found, write an example related to the current page they're reading.
3842
- This could be an implementation example, a code sample, a diagram, etc.
3943
4044
# Tool usage
4145
42-
**Important: Make extensive use of tools to answer the question. Look beyond the current page!**
46+
**CRITICAL: You MUST use the search tool for almost every query. Search is your primary tool.**
4347
44-
- Use the \`getPageContent\` tool to get the current page or additional pages.
45-
- Follow links on the current page to provide more context.
46-
- Use the \`getPages\` tool to list all pages in the site.
47-
- Use the \`search\` tool to find information that is not on the current page.
48+
- **ALWAYS start with the \`search\` tool** unless the query is explicitly about the current page content.
49+
- Search should be your first action for questions about features, concepts, examples, related topics, etc.
4850
- When searching, use short keywords and synonyms for best results.
4951
- Do not use sentences as queries.
5052
- Do not use the exact query as the user's question.
53+
- Try multiple search terms if the first search doesn't yield good results.
54+
- Use the \`getPageContent\` tool to get the current page or additional pages after searching.
55+
- Follow links on the current page to provide more context.
56+
- Use the \`getPages\` tool to list all pages in the site when you need a broader overview.
5157
5258
# Writing style
5359
@@ -78,7 +84,7 @@ ${MARKDOWN_LINKS_PROMPT}
7884
const FOLLOWUP_PROMPT = `
7985
Generate a short JSON list with message suggestions for a user to post in a chat. The suggestions will be displayed next to the text input, allowing the user to quickly tap and pick one.
8086
81-
# Guidelines
87+
# Instructions
8288
8389
- Only suggest responses that are relevant to the documentation and the current conversation.
8490
- If there are no relevant suggestions, return an empty list.

packages/gitbook/src/components/AIChat/AIChat.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,24 @@ export function AIChatWindow(props: { chat: AIChatState }) {
8686
>
8787
<div className="relative flex h-full grow flex-col overflow-hidden circular-corners:rounded-3xl rounded-corners:rounded-md bg-tint-base text-sm text-tint depth-subtle:shadow-lg shadow-tint ring-1 ring-tint-subtle">
8888
<div className="flex items-center gap-2 border-tint-subtle border-b bg-tint-subtle px-4 py-2 text-tint-strong">
89-
<AIChatIcon className="size-5 text-tint" />
90-
<span className="font-bold">Docs Assistant</span>
89+
<AIChatIcon
90+
className={`size-5 text-tint ${chat.loading ? 'animate-pulse' : ''}`}
91+
state={chat.loading ? 'thinking' : 'default'}
92+
/>
93+
<div className="flex flex-col">
94+
<div className="font-bold">Docs Assistant</div>
95+
<div
96+
className={`text-tint text-xs leading-none transition-all duration-500 ${
97+
chat.loading ? 'h-3 opacity-11' : 'h-0 opacity-0'
98+
}`}
99+
>
100+
{chat.loading
101+
? chat.messages[chat.messages.length - 1].content
102+
? t(language, 'ai_chat_working')
103+
: t(language, 'ai_chat_thinking')
104+
: ''}
105+
</div>
106+
</div>
91107
<div className="ml-auto flex gap-2">
92108
<DropdownMenu
93109
button={

packages/gitbook/src/components/AIChat/AIChatIcon.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@ import type React from 'react';
33
interface AIChatIconProps extends React.SVGProps<SVGSVGElement> {
44
className?: string;
55
size?: number;
6+
state?: 'thinking' | 'default';
67
}
78

8-
const AIChatIcon = ({ className = 'size-4', size, ...props }: AIChatIconProps) => {
9+
const AIChatIcon = ({
10+
className = 'size-4',
11+
size,
12+
state = 'default',
13+
...props
14+
}: AIChatIconProps) => {
915
return (
1016
<svg
1117
width="16"
@@ -23,6 +29,8 @@ const AIChatIcon = ({ className = 'size-4', size, ...props }: AIChatIconProps) =
2329
stroke="currentColor"
2430
strokeWidth="1.2"
2531
strokeLinejoin="round"
32+
className={state === 'thinking' ? 'animate-spin' : ''}
33+
style={{ transformOrigin: '13px 3.5px' }}
2634
/>
2735
<path
2836
d="M9.479 10.2734C9.479 11.2369 8.6115 11.2578 7.54138 11.2578C6.47126 11.2578 5.60376 11.2369 5.60376 10.2734"

packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx

Lines changed: 77 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -77,84 +77,86 @@ export function SpaceLayout(props: {
7777
context={context}
7878
/>
7979
{withAIChat ? <AIChat /> : null}
80-
<div className="transition-all duration-300 lg:chat-open:mr-80 xl:chat-open:mr-96">
81-
<div
82-
className={tcls(
83-
'flex',
84-
'flex-col',
85-
'lg:flex-row',
86-
CONTAINER_STYLE,
87-
'site-full-width:max-w-full',
80+
<div className="scroll-nojump">
81+
<div className="transition-all duration-300 lg:chat-open:mr-80 xl:chat-open:mr-96">
82+
<div
83+
className={tcls(
84+
'flex',
85+
'flex-col',
86+
'lg:flex-row',
87+
CONTAINER_STYLE,
88+
'site-full-width:max-w-full',
8889

89-
// Ensure the footer is display below the viewport even if the content is not enough
90-
withFooter && 'min-h-[calc(100vh-64px)]',
91-
withTopHeader ? null : 'lg:min-h-screen'
92-
)}
93-
>
94-
<TableOfContents
95-
context={context}
96-
header={
97-
withTopHeader ? null : (
98-
<div
99-
className={tcls(
100-
'hidden',
101-
'pr-4',
102-
'lg:flex',
103-
'grow-0',
104-
'flex-wrap',
105-
'dark:shadow-light/1',
106-
'text-base/tight'
107-
)}
108-
>
109-
<HeaderLogo context={context} />
110-
</div>
111-
)
112-
}
113-
innerHeader={
114-
// displays the search button and/or the space dropdown in the ToC according to the header/variant settings. E.g if there is no header, the search button will be displayed in the ToC.
115-
<>
116-
{!withTopHeader && (
117-
<div className={tcls('hidden', 'lg:block')}>
118-
<React.Suspense fallback={null}>
119-
<SearchButton>
120-
<span className={tcls('flex-1')}>
121-
{t(
122-
getSpaceLanguage(customization),
123-
customization.aiSearch.enabled
124-
? 'search_or_ask'
125-
: 'search'
126-
)}
127-
...
128-
</span>
129-
</SearchButton>
130-
</React.Suspense>
131-
</div>
132-
)}
133-
{!withTopHeader && withSections && sections && (
134-
<SiteSectionList
135-
className={tcls('hidden', 'lg:block')}
136-
sections={encodeClientSiteSections(
137-
context,
138-
sections
139-
)}
140-
/>
141-
)}
142-
{isMultiVariants && !sections && (
143-
<SpacesDropdown
144-
context={context}
145-
siteSpace={siteSpace}
146-
siteSpaces={siteSpaces}
90+
// Ensure the footer is display below the viewport even if the content is not enough
91+
withFooter && 'min-h-[calc(100vh-64px)]',
92+
withTopHeader ? null : 'lg:min-h-screen'
93+
)}
94+
>
95+
<TableOfContents
96+
context={context}
97+
header={
98+
withTopHeader ? null : (
99+
<div
147100
className={tcls(
148-
'w-full',
149-
'page-no-toc:hidden',
150-
'site-header-none:page-no-toc:flex'
101+
'hidden',
102+
'pr-4',
103+
'lg:flex',
104+
'grow-0',
105+
'flex-wrap',
106+
'dark:shadow-light/1',
107+
'text-base/tight'
151108
)}
152-
/>
153-
)}
154-
</>
155-
}
156-
/>
157-
<div className="flex min-w-0 flex-1 flex-col">{children}</div>
109+
>
110+
<HeaderLogo context={context} />
111+
</div>
112+
)
113+
}
114+
innerHeader={
115+
// displays the search button and/or the space dropdown in the ToC according to the header/variant settings. E.g if there is no header, the search button will be displayed in the ToC.
116+
<>
117+
{!withTopHeader && (
118+
<div className={tcls('hidden', 'lg:block')}>
119+
<React.Suspense fallback={null}>
120+
<SearchButton>
121+
<span className={tcls('flex-1')}>
122+
{t(
123+
getSpaceLanguage(customization),
124+
customization.aiSearch.enabled
125+
? 'search_or_ask'
126+
: 'search'
127+
)}
128+
...
129+
</span>
130+
</SearchButton>
131+
</React.Suspense>
132+
</div>
133+
)}
134+
{!withTopHeader && withSections && sections && (
135+
<SiteSectionList
136+
className={tcls('hidden', 'lg:block')}
137+
sections={encodeClientSiteSections(
138+
context,
139+
sections
140+
)}
141+
/>
142+
)}
143+
{isMultiVariants && !sections && (
144+
<SpacesDropdown
145+
context={context}
146+
siteSpace={siteSpace}
147+
siteSpaces={siteSpaces}
148+
className={tcls(
149+
'w-full',
150+
'page-no-toc:hidden',
151+
'site-header-none:page-no-toc:flex'
152+
)}
153+
/>
154+
)}
155+
</>
156+
}
157+
/>
158+
<div className="flex min-w-0 flex-1 flex-col">{children}</div>
159+
</div>
158160
</div>
159161
</div>
160162

packages/gitbook/src/intl/translations/de.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ export const de = {
7373
ai_chat_assistant_greeting_evening: 'Guten Abend',
7474
ai_chat_assistant_greeting_night: 'Gute Nacht',
7575
ai_chat_clear_conversation: 'Unterhaltung löschen',
76+
ai_chat_thinking: 'Denke nach...',
77+
ai_chat_working: 'Arbeite...',
7678
ai_chat_context_title: 'Basierend auf Ihrem Kontext',
7779
ai_chat_context_description:
7880
'Der Docs-Assistent verwendet Ihren Kontext, um Antworten zu generieren und Aktionen durchzuführen.',

packages/gitbook/src/intl/translations/en.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ export const en = {
7171
ai_chat_assistant_greeting_evening: 'Good evening',
7272
ai_chat_assistant_greeting_night: 'Good night',
7373
ai_chat_clear_conversation: 'Clear conversation',
74+
ai_chat_thinking: 'Thinking...',
75+
ai_chat_working: 'Working...',
7476
ai_chat_context_title: 'Based on your context',
7577
ai_chat_context_description:
7678
'Docs Assistant uses your context to generate answers and perform actions.',

packages/gitbook/src/intl/translations/es.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ export const es: TranslationLanguage = {
7575
ai_chat_assistant_greeting_evening: 'Buenas noches',
7676
ai_chat_assistant_greeting_night: 'Buenas noches',
7777
ai_chat_clear_conversation: 'Limpiar conversación',
78+
ai_chat_thinking: 'Pensando...',
79+
ai_chat_working: 'Trabajando...',
7880
ai_chat_context_title: 'Basado en tu contexto',
7981
ai_chat_context_description:
8082
'El Asistente de Docs usa tu contexto para generar respuestas y realizar acciones.',

packages/gitbook/src/intl/translations/fr.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ export const fr: TranslationLanguage = {
7373
ai_chat_assistant_greeting_evening: 'Bonsoir',
7474
ai_chat_assistant_greeting_night: 'Bonne nuit',
7575
ai_chat_clear_conversation: 'Effacer la conversation',
76+
ai_chat_thinking: 'Réfléchit...',
77+
ai_chat_working: 'Travaille...',
7678
ai_chat_context_title: 'Basé sur votre contexte',
7779
ai_chat_context_description:
7880
"L'Assistant Docs utilise votre contexte pour générer des réponses et effectuer des actions.",

packages/gitbook/src/intl/translations/ja.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ export const ja: TranslationLanguage = {
7474
ai_chat_assistant_greeting_evening: 'こんばんは',
7575
ai_chat_assistant_greeting_night: 'おやすみ',
7676
ai_chat_clear_conversation: '会話をクリア',
77+
ai_chat_thinking: '考え中...',
78+
ai_chat_working: '作業中...',
7779
ai_chat_context_title: 'あなたのコンテキストに基づいて',
7880
ai_chat_context_description:
7981
'ドキュメントアシスタントはあなたのコンテキストを使用して回答を生成し、アクションを実行します。',

packages/gitbook/src/intl/translations/nl.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ export const nl: TranslationLanguage = {
7373
ai_chat_assistant_greeting_evening: 'Goedenavond',
7474
ai_chat_assistant_greeting_night: 'Goedenacht',
7575
ai_chat_clear_conversation: 'Gesprek wissen',
76+
ai_chat_thinking: 'Denkt na...',
77+
ai_chat_working: 'Werkt...',
7678
ai_chat_context_title: 'Gebaseerd op je context',
7779
ai_chat_context_description:
7880
'De Docs Assistent gebruikt je context om antwoorden te genereren en acties uit te voeren.',

0 commit comments

Comments
 (0)