@vercel/agent-readability 0.1.0
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/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/cli/index.cjs +228 -0
- package/dist/index.cjs +175 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +82 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +141 -0
- package/dist/index.js.map +1 -0
- package/dist/next/index.cjs +166 -0
- package/dist/next/index.cjs.map +1 -0
- package/dist/next/index.d.cts +35 -0
- package/dist/next/index.d.ts +35 -0
- package/dist/next/index.js +140 -0
- package/dist/next/index.js.map +1 -0
- package/package.json +91 -0
- package/skill/SKILL.md +171 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vercel, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# @vercel/agent-readability
|
|
2
|
+
|
|
3
|
+
Detect AI agents. Serve them markdown. Audit your site against the
|
|
4
|
+
[Agent Readability Spec](https://vercel.com/kb/guide/agent-readability-spec).
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @vercel/agent-readability
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Or run the audit CLI directly without installing:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @vercel/agent-readability audit https://vercel.com/docs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
Add AI agent detection to your Next.js middleware in three lines:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// middleware.ts
|
|
24
|
+
import { withAgentReadability } from '@vercel/agent-readability/next'
|
|
25
|
+
|
|
26
|
+
export default withAgentReadability({
|
|
27
|
+
rewrite: (pathname) => `/api/docs-md${pathname}`,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
export const config = {
|
|
31
|
+
matcher: ['/docs/:path*'],
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
AI agents hitting `/docs/*` now receive markdown instead of HTML.
|
|
36
|
+
|
|
37
|
+
## What It Does
|
|
38
|
+
|
|
39
|
+
Three-layer detection identifies AI agents from HTTP request headers:
|
|
40
|
+
|
|
41
|
+
1. **Known UA patterns.** 40+ agents including ClaudeBot, GPTBot, Cursor, and Perplexity.
|
|
42
|
+
2. **Signature-Agent header.** Catches ChatGPT agent (RFC 9421).
|
|
43
|
+
3. **sec-fetch-mode heuristic.** Catches unknown bots that lack browser fingerprints.
|
|
44
|
+
|
|
45
|
+
The detection optimizes for recall over precision. Serving markdown to a non-AI bot
|
|
46
|
+
is low cost. Missing an AI agent means a worse experience.
|
|
47
|
+
|
|
48
|
+
## Core API
|
|
49
|
+
|
|
50
|
+
### `isAIAgent(request)`
|
|
51
|
+
|
|
52
|
+
Detect AI agents from request headers.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { isAIAgent } from '@vercel/agent-readability'
|
|
56
|
+
|
|
57
|
+
const result = isAIAgent(request)
|
|
58
|
+
// { detected: true, method: 'ua-match' }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Accepts any object with a `headers.get()` method: `Request`, `NextRequest`,
|
|
62
|
+
or a custom wrapper.
|
|
63
|
+
|
|
64
|
+
Returns a discriminated union:
|
|
65
|
+
- `{ detected: true, method: 'ua-match' | 'signature-agent' | 'heuristic' }`
|
|
66
|
+
- `{ detected: false, method: null }`
|
|
67
|
+
|
|
68
|
+
When `detected` is `true`, `method` is always non-null. TypeScript narrows automatically.
|
|
69
|
+
|
|
70
|
+
### `acceptsMarkdown(request)`
|
|
71
|
+
|
|
72
|
+
Check if the request prefers markdown via the `Accept` header.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { acceptsMarkdown } from '@vercel/agent-readability'
|
|
76
|
+
|
|
77
|
+
if (acceptsMarkdown(request)) {
|
|
78
|
+
return new Response(markdown, {
|
|
79
|
+
headers: { 'Content-Type': 'text/markdown', 'Vary': 'Accept' },
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `shouldServeMarkdown(request)`
|
|
85
|
+
|
|
86
|
+
Combines agent detection and content negotiation into one call.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { shouldServeMarkdown } from '@vercel/agent-readability'
|
|
90
|
+
|
|
91
|
+
const { serve, reason } = shouldServeMarkdown(request)
|
|
92
|
+
// serve: true, reason: 'agent' | 'accept-header'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `generateNotFoundMarkdown(path, options?)`
|
|
96
|
+
|
|
97
|
+
Generates a markdown body for missing pages. Return this with a 200 status
|
|
98
|
+
(not 404) because agents discard 404 response bodies.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { generateNotFoundMarkdown } from '@vercel/agent-readability'
|
|
102
|
+
|
|
103
|
+
const md = generateNotFoundMarkdown('/docs/missing', {
|
|
104
|
+
baseUrl: 'https://example.com',
|
|
105
|
+
})
|
|
106
|
+
// Return as 200 so agents read the body
|
|
107
|
+
return new Response(md, {
|
|
108
|
+
headers: { 'Content-Type': 'text/markdown' },
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Pattern Exports
|
|
113
|
+
|
|
114
|
+
`AI_AGENT_UA_PATTERNS`, `TRADITIONAL_BOT_PATTERNS`, `SIGNATURE_AGENT_DOMAINS`,
|
|
115
|
+
and `BOT_LIKE_REGEX` are exported for consumers who need to extend or inspect them.
|
|
116
|
+
|
|
117
|
+
## Next.js Adapter
|
|
118
|
+
|
|
119
|
+
### `withAgentReadability(options, handler?)`
|
|
120
|
+
|
|
121
|
+
Middleware wrapper that detects AI agents and rewrites matching requests
|
|
122
|
+
to markdown routes. Compatible with Next.js 14 and 15 (Pages and App Router).
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { withAgentReadability } from '@vercel/agent-readability/next'
|
|
126
|
+
|
|
127
|
+
export default withAgentReadability({
|
|
128
|
+
docsPrefix: '/docs',
|
|
129
|
+
rewrite: (pathname) => `/en/llms.mdx/${pathname.replace('/docs/', '')}`,
|
|
130
|
+
onDetection: async ({ path, method }) => {
|
|
131
|
+
await trackMdRequest({ path, detectionMethod: method })
|
|
132
|
+
},
|
|
133
|
+
})
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The `onDetection` callback runs via `event.waitUntil()` and does not block
|
|
137
|
+
the response.
|
|
138
|
+
|
|
139
|
+
#### Composing with other middleware
|
|
140
|
+
|
|
141
|
+
Pass your existing middleware as the second argument:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
export default withAgentReadability(
|
|
145
|
+
{
|
|
146
|
+
rewrite: (p) => `/md${p}`,
|
|
147
|
+
},
|
|
148
|
+
(req, event) => i18nMiddleware(req, event),
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### Options
|
|
153
|
+
|
|
154
|
+
| Option | Type | Default | Description |
|
|
155
|
+
|--------|------|---------|-------------|
|
|
156
|
+
| `docsPrefix` | `string` | `'/docs'` | URL prefix to intercept |
|
|
157
|
+
| `rewrite` | `(pathname: string) => string` | required | Maps request path to markdown route |
|
|
158
|
+
| `onDetection` | `(info) => void \| Promise<void>` | - | Analytics callback (runs in `waitUntil`) |
|
|
159
|
+
|
|
160
|
+
#### `agentReadabilityMatcher`
|
|
161
|
+
|
|
162
|
+
A pre-built matcher that excludes Next.js internals and static files.
|
|
163
|
+
Use this for site-wide agent detection instead of scoping to a prefix:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { withAgentReadability, agentReadabilityMatcher } from '@vercel/agent-readability/next'
|
|
167
|
+
|
|
168
|
+
export default withAgentReadability({
|
|
169
|
+
docsPrefix: '/',
|
|
170
|
+
rewrite: (pathname) => `/md${pathname}`,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
export const config = {
|
|
174
|
+
matcher: agentReadabilityMatcher,
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Audit CLI
|
|
179
|
+
|
|
180
|
+
Check your site against the Agent Readability Spec.
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
npx @vercel/agent-readability audit https://sdk.vercel.ai
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Runs 16 weighted checks across three categories. Returns a score from 0 to 100.
|
|
187
|
+
Failed checks include fix suggestions that can be copy-pasted into your coding agent.
|
|
188
|
+
|
|
189
|
+
### CI Integration
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
- name: Audit agent readability
|
|
193
|
+
run: npx @vercel/agent-readability audit ${{ env.SITE_URL }} --min-score 70 --json
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Exits with code 1 if the score is below the threshold.
|
|
197
|
+
|
|
198
|
+
### CLI Options
|
|
199
|
+
|
|
200
|
+
| Flag | Description |
|
|
201
|
+
|------|-------------|
|
|
202
|
+
| `--json` | Output as JSON |
|
|
203
|
+
| `--min-score <n>` | Exit with error if score < n |
|
|
204
|
+
|
|
205
|
+
## Caching
|
|
206
|
+
|
|
207
|
+
When the same URL serves HTML to browsers and markdown to AI agents,
|
|
208
|
+
CDN caching must include the `Accept` header in the cache key.
|
|
209
|
+
|
|
210
|
+
Set `Vary: Accept` on all markdown responses. Without it, CDNs may serve
|
|
211
|
+
cached HTML to agents or cached markdown to browsers.
|
|
212
|
+
|
|
213
|
+
The `withAgentReadability` middleware handles detection and rewriting.
|
|
214
|
+
Your markdown route handler is responsible for setting response headers
|
|
215
|
+
including `Vary: Accept` and `Content-Type: text/markdown`.
|
|
216
|
+
|
|
217
|
+
## Edge Runtime
|
|
218
|
+
|
|
219
|
+
The core library and Next.js adapter use only Web APIs. They work in
|
|
220
|
+
Vercel Edge Runtime, Cloudflare Workers, and any standard `Request`/`Response`
|
|
221
|
+
environment.
|
|
222
|
+
|
|
223
|
+
The CLI runs on Node.js 20+.
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT
|