Skip to content

Commit 7dc6859

Browse files
tgargulaclaude
andcommitted
Serve markdown with text/plain content-type for ChatGPT compatibility
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent 1f250d1 commit 7dc6859

6 files changed

Lines changed: 32 additions & 27 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": patch
3+
---
4+
5+
Serve Markdown responses with a `text/plain` Content-Type for compatibility with ChatGPT.

packages/gitbook/src/routes/llms-full.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export async function serveLLMsFullTxt(context: GitBookSiteContext, page = 0) {
4848
}),
4949
{
5050
headers: {
51-
'Content-Type': 'text/markdown; charset=utf-8',
51+
'Content-Type': 'text/plain; charset=utf-8',
5252
},
5353
}
5454
);

packages/gitbook/src/routes/llms.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export async function serveLLMsTxt(baseContext: GitBookSiteContext) {
5252

5353
return new Response(output, {
5454
headers: {
55-
'Content-Type': 'text/markdown; charset=utf-8',
55+
'Content-Type': 'text/plain; charset=utf-8',
5656
},
5757
});
5858
}

packages/gitbook/src/routes/markdownPage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ export async function serveMarkdown(
171171
typeof result === 'string' ? { markdown: result, robots: 'noindex' } : result;
172172
return new Response(markdown, {
173173
headers: {
174-
'Content-Type': 'text/markdown; charset=utf-8',
174+
'Content-Type': 'text/plain; charset=utf-8',
175175
'X-Robots-Tag': robots,
176176
Vary: 'Accept',
177177
},

packages/gitbook/tests/llms.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ describe('llms.txt', () => {
99
);
1010

1111
expect(response.status).toBe(200);
12-
expect(response.headers.get('content-type')).toContain('text/markdown');
12+
expect(response.headers.get('content-type')).toContain('text/plain');
1313
expect(await response.text()).toContain('# E2E Tests GitBook Open');
1414
});
1515

@@ -19,7 +19,7 @@ describe('llms.txt', () => {
1919
);
2020

2121
expect(response.status).toBe(200);
22-
expect(response.headers.get('content-type')).toContain('text/markdown');
22+
expect(response.headers.get('content-type')).toContain('text/plain');
2323
const content = await response.text();
2424
expect(content).toContain('/sections/sections-3/readme.md');
2525
expect(content).toContain('/sections/sections-4/getting-started/quickstart.md');
@@ -36,7 +36,7 @@ describe('llms.txt', () => {
3636
);
3737

3838
expect(response.status).toBe(200);
39-
expect(response.headers.get('content-type')).toContain('text/markdown');
39+
expect(response.headers.get('content-type')).toContain('text/plain');
4040
expect(await response.text()).toContain('# E2E Tests GitBook Open');
4141
});
4242

@@ -46,7 +46,7 @@ describe('llms.txt', () => {
4646
);
4747

4848
expect(response.status).toBe(200);
49-
expect(response.headers.get('content-type')).toContain('text/markdown');
49+
expect(response.headers.get('content-type')).toContain('text/plain');
5050
expect(await response.text()).toContain('# E2E Tests GitBook Open');
5151
});
5252

@@ -56,7 +56,7 @@ describe('llms.txt', () => {
5656
);
5757

5858
expect(response.status).toBe(200);
59-
expect(response.headers.get('content-type')).toContain('text/markdown');
59+
expect(response.headers.get('content-type')).toContain('text/plain');
6060
expect(await response.text()).toContain('# E2E Tests GitBook Open');
6161
});
6262
});
@@ -70,7 +70,7 @@ describe('llms-full.txt', () => {
7070
);
7171

7272
expect(response.status).toBe(200);
73-
expect(response.headers.get('content-type')).toContain('text/markdown');
73+
expect(response.headers.get('content-type')).toContain('text/plain');
7474
expect(await response.text()).toContain('# Welcome');
7575
},
7676
{ timeout: 30_000 }
@@ -87,7 +87,7 @@ describe('llms-full.txt', () => {
8787
const text = await response.text();
8888

8989
expect(response.status).toBe(200);
90-
expect(response.headers.get('content-type')).toContain('text/markdown');
90+
expect(response.headers.get('content-type')).toContain('text/plain');
9191
expect(text).toContain(
9292
'gitbook-open-e2e-sites.gitbook.io/api-multi-versions-share-links/8tNo6MeXg7CkFMzSSz81/2.0/quick-start'
9393
);
@@ -112,7 +112,7 @@ describe('llms-full.txt', () => {
112112
);
113113

114114
expect(response.status).toBe(200);
115-
expect(response.headers.get('content-type')).toContain('text/markdown');
115+
expect(response.headers.get('content-type')).toContain('text/plain');
116116
expect(await response.text()).toContain('# Welcome');
117117
},
118118
{ timeout: 30_000 }

packages/gitbook/tests/markdown.test.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe('markdown serving based on user agent', () => {
1313
});
1414

1515
expect(response.status).toBe(200);
16-
expect(response.headers.get('content-type')).toContain('text/markdown');
16+
expect(response.headers.get('content-type')).toContain('text/plain');
1717
});
1818

1919
it('should serve markdown to ClaudeBot (ua-match AI agent)', async () => {
@@ -24,7 +24,7 @@ describe('markdown serving based on user agent', () => {
2424
});
2525

2626
expect(response.status).toBe(200);
27-
expect(response.headers.get('content-type')).toContain('text/markdown');
27+
expect(response.headers.get('content-type')).toContain('text/plain');
2828
});
2929

3030
it('should NOT serve markdown to Slackbot (heuristic detection only)', async () => {
@@ -92,7 +92,7 @@ describe('markdown pages', () => {
9292
const text = await response.text();
9393

9494
expect(response.status).toBe(200);
95-
expect(response.headers.get('content-type')).toContain('text/markdown');
95+
expect(response.headers.get('content-type')).toContain('text/plain');
9696
expect(response.headers.get('x-robots-tag')).toBe('noindex');
9797
expect(text).toContain('# Text page');
9898
});
@@ -111,7 +111,7 @@ describe('markdown pages', () => {
111111
const text = await response.text();
112112

113113
expect(response.status).toBe(200);
114-
expect(response.headers.get('content-type')).toContain('text/markdown');
114+
expect(response.headers.get('content-type')).toContain('text/plain');
115115
expect(response.headers.get('x-robots-tag')).toBe('noindex');
116116
expect(text).toContain('# Text page');
117117
});
@@ -123,7 +123,7 @@ describe('markdown pages', () => {
123123
const text = await response.text();
124124

125125
expect(response.status).toBe(200);
126-
expect(response.headers.get('content-type')).toContain('text/markdown');
126+
expect(response.headers.get('content-type')).toContain('text/plain');
127127
expect(response.headers.get('x-robots-tag')).toBe('noindex, nofollow');
128128
expect(text).toContain('# Page Not Found');
129129
});
@@ -137,7 +137,7 @@ describe('markdown pages', () => {
137137
const text = await response.text();
138138

139139
expect(response.status).toBe(200);
140-
expect(response.headers.get('content-type')).toContain('text/markdown');
140+
expect(response.headers.get('content-type')).toContain('text/plain');
141141
expect(response.headers.get('x-robots-tag')).toBe('noindex');
142142
expect(text).toContain('gitbook.gitbook.io/test-gitbook-open/text-page.md');
143143
});
@@ -179,7 +179,7 @@ describe('Accept header content negotiation', () => {
179179
});
180180

181181
expect(response.status).toBe(200);
182-
expect(response.headers.get('content-type')).toContain('text/markdown');
182+
expect(response.headers.get('content-type')).toContain('text/plain');
183183
});
184184

185185
it('should serve markdown when text/markdown has a higher q-value (Accept: text/html;q=0.9, text/markdown)', async () => {
@@ -188,7 +188,7 @@ describe('Accept header content negotiation', () => {
188188
});
189189

190190
expect(response.status).toBe(200);
191-
expect(response.headers.get('content-type')).toContain('text/markdown');
191+
expect(response.headers.get('content-type')).toContain('text/plain');
192192
});
193193

194194
it('should NOT serve markdown when text/markdown has a lower q-value (Accept: text/html, text/markdown;q=0.9)', async () => {
@@ -206,7 +206,7 @@ describe('Accept header content negotiation', () => {
206206
});
207207

208208
expect(response.status).toBe(200);
209-
expect(response.headers.get('content-type')).toContain('text/markdown');
209+
expect(response.headers.get('content-type')).toContain('text/plain');
210210
});
211211
});
212212

@@ -225,7 +225,7 @@ describe('markdown ask responses', () => {
225225
const text = await response.text();
226226

227227
expect(response.status).toBe(200);
228-
expect(response.headers.get('content-type')).toContain('text/markdown');
228+
expect(response.headers.get('content-type')).toContain('text/plain');
229229
expect(response.headers.get('x-robots-tag')).toBe('noindex');
230230
expect(text).toContain(ASK_QUESTION_HEADING);
231231
},
@@ -248,7 +248,7 @@ describe('markdown ask responses', () => {
248248
const text = await response.text();
249249

250250
expect(response.status).toBe(200);
251-
expect(response.headers.get('content-type')).toContain('text/markdown');
251+
expect(response.headers.get('content-type')).toContain('text/plain');
252252
expect(response.headers.get('x-robots-tag')).toBe('noindex');
253253
expect(text).toContain(ASK_QUESTION_HEADING);
254254
},
@@ -269,7 +269,7 @@ describe('markdown robots directives', () => {
269269
});
270270

271271
expect(response.status).toBe(200);
272-
expect(response.headers.get('content-type')).toContain('text/markdown');
272+
expect(response.headers.get('content-type')).toContain('text/plain');
273273
expect(response.headers.get('x-robots-tag')).toBe('index, follow');
274274
});
275275

@@ -279,7 +279,7 @@ describe('markdown robots directives', () => {
279279
});
280280

281281
expect(response.status).toBe(200);
282-
expect(response.headers.get('content-type')).toContain('text/markdown');
282+
expect(response.headers.get('content-type')).toContain('text/plain');
283283
expect(response.headers.get('x-robots-tag')).toBe('index, follow');
284284
});
285285

@@ -289,7 +289,7 @@ describe('markdown robots directives', () => {
289289
});
290290

291291
expect(response.status).toBe(200);
292-
expect(response.headers.get('content-type')).toContain('text/markdown');
292+
expect(response.headers.get('content-type')).toContain('text/plain');
293293
expect(response.headers.get('x-robots-tag')).toBe('noindex');
294294
});
295295

@@ -300,7 +300,7 @@ describe('markdown robots directives', () => {
300300
);
301301

302302
expect(response.status).toBe(200);
303-
expect(response.headers.get('content-type')).toContain('text/markdown');
303+
expect(response.headers.get('content-type')).toContain('text/plain');
304304
expect(response.headers.get('x-robots-tag')).toBe('noindex, nofollow');
305305
});
306306

@@ -313,7 +313,7 @@ describe('markdown robots directives', () => {
313313
);
314314

315315
expect(response.status).toBe(200);
316-
expect(response.headers.get('content-type')).toContain('text/markdown');
316+
expect(response.headers.get('content-type')).toContain('text/plain');
317317
expect(response.headers.get('x-robots-tag')).toBe('noindex, nofollow');
318318
});
319319
});

0 commit comments

Comments
 (0)