Skip to content

Honor Accept-Language for site code examples - #579

Open
prathamdby wants to merge 1 commit into
mainfrom
pd/feat-accept-language-70a1
Open

Honor Accept-Language for site code examples#579
prathamdby wants to merge 1 commit into
mainfrom
pd/feat-accept-language-70a1

Conversation

@prathamdby

@prathamdby prathamdby commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • Agents can send Accept-Language: en-us, python with Accept: text/markdown and get the landing-page fetch example fenced as Python.
  • site/lib/acceptLanguage.ts reads programming-language tokens from Accept-Language. Locale tags such as en and en-US stay locales. Two-letter codes such as ts and sh stay locales. golang and shell are the only aliases.
  • site/lib/accept.ts still parses media ranges only. It now exports parseQuality so both headers clamp q the same way.
  • FETCH_MARKDOWN_SNIPPET in site/lib/content.ts holds one fetch body per served language. Compose and env stay bash and dotenv fences.
  • Markdown / sets Vary: Accept, Accept-Language. /index.md sets Vary: Accept-Language. HTML / and the 404 keep Vary: Accept.
  • docs/development.md, /agents.md, llms.txt, and /openapi.json state the convention and the served set. typescript, javascript, python, go, java, ruby, bash. Default typescript.
on(Accept-Language)
  ignore locale tags and two-letter codes
  map golang -> go, shell -> bash
  skip q=0 tokens
  pick the highest-q served language
  if every served language is refused
    return typescript
sequenceDiagram
    participant Client
    participant Start
    participant SiteHttp
    participant Accept
    participant AcceptLanguage
    participant PageMarkdown
    Client->>Start: GET / Accept text/markdown Accept-Language en-us, python
    Start->>SiteHttp: negotiateHomeRequest
    SiteHttp->>Accept: negotiateType
    Accept-->>SiteHttp: text/markdown
    SiteHttp->>AcceptLanguage: negotiateProgrammingLanguage
    AcceptLanguage-->>SiteHttp: python
    SiteHttp->>PageMarkdown: renderHomeMarkdown python
    PageMarkdown-->>Client: markdown Vary Accept, Accept-Language
Loading

Details

Parser. negotiateProgrammingLanguage walks the languages the page can serve. produces[0] is the default. A missing or empty header returns that default. A miss never returns 406.

Snippets. pickSnippet and servableLanguages sit next to the fetch bodies. The page's served set is the union of those keys with typescript first.

site/lib/
├── accept.ts            # RFC 9110 media ranges
├── acceptLanguage.ts    # programming-language tokens
├── content.ts           # FETCH_MARKDOWN_SNIPPET
├── pageMarkdown.ts      # renderHomeMarkdown(language)
└── siteHttp.ts          # Vary and request wiring

HTTP. start.ts passes Accept-Language into negotiateHomeRequest. site/app/index[.]md.ts and serveMarkdownRoutesInDev pass it into homeMarkdownDocumentResponse, which requires string | null.

contentNegotiation
  negotiateHomeRequest(accept, acceptLanguage)
    negotiateType
    homeMarkdownResponse
      negotiateProgrammingLanguage
      renderHomeMarkdown
      varyOn Accept
      varyOn Accept-Language
  decorateHtmlResponse
    varyOn Accept
 markdown /
-  Vary: Accept
+  Vary: Accept, Accept-Language
 /index.md
-  no Vary
+  Vary: Accept-Language
 HTML / and 404
   Vary: Accept

Docs. The Module pointer in docs/development.md names the sibling parser, the served set, and which URLs vary. llmsKnowledge.ts regenerates site/public/llms.txt. OpenAPI adds an Accept-Language parameter on / and /index.md.

Open in Web Open in Cursor 

PR Agent Description

PR Type

Enhancement

Description

  • New acceptLanguage.ts parses Accept-Language for a programming language, using full-word matches only so ts, sh, js, and py stay locale tags.
  • The markdown landing page now carries a language-variant fetch example in typescript, javascript, python, go, java, ruby, or bash, defaulting to typescript.
  • negotiateHomeRequest and the markdown responses now read Accept-Language and add Vary: Accept-Language, so caches fragment by example language.
  • varyOnAccept becomes a generic varyOn(headers, field) helper, and parseQuality is exported for reuse by the new module.
  • OpenAPI, llms.txt, agent instructions, and development docs all declare the new Accept-Language convention and the served language set.
  • Risk: a client that sends a two-letter code like ts or py gets the typescript default, not the language it may have intended.

Review map

  1. site/lib/acceptLanguage.ts: new negotiation logic, core of the change
  2. site/lib/siteHttp.ts: wires Accept-Language into responses and Vary headers
  3. site/lib/content.ts: variant snippet and served language set
  4. site/start.ts: middleware passes the header through
  5. test/accept.test.ts: covers the new language parser

- Parse programming-language tokens in a sibling of the Accept
  media parser
- Render the landing-page fetch example in the highest-preference served
  language
- Document the convention on llms.txt, agents.md, and OpenAPI
@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pr-agent Ready Ready Preview Sep 7, 2026 7:51am UTC

@zeus-review

zeus-review Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

PR Agent Review

Note

This PR adds programming-language negotiation to the site/ landing package via a new Accept-Language convention. An agent puts a language after its locale (for example en-US, python) and the markdown fetch example switches to that language. The change threads the header through the route handlers, generalizes varyOn for case-insensitive deduplication, and updates all agent-facing docs. Markdown responses declare both Accept and Accept-Language in Vary, while HTML responses declare only Accept, so the HTML cache does not fragment by locale. The new acceptLanguage parser deduplicates repeated language tokens by keeping the highest q and breaks ties by header order. The correctness specialist timed out, so this review could not verify the parsing logic or the route-handler signatures in full.

SizeM
P2 · c4Missing test for duplicate language token deduplication invariant
On the diff · test/accept.test.ts · lines 127-185
Fix prompt on the inline thread.
Relevant testspartial
Security
CI✅ All CI is passing

Coverage partial: correctness specialist failed.

Fix all findings (agent prompt)
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, and keep changes minimal.

Repository: prathamdby/pr-agent
Pull request: #579
Head SHA: 1f4c060c3ec3dbd73bb9d7290cacf047d3cf6428

Findings:

[P2] @test/accept.test.ts lines 127-185
Add a vitest case in the `negotiateProgrammingLanguage` describe block asserting that duplicate tokens resolve to the highest q and that the earliest index breaks equal-q ties: `expect(negotiateProgrammingLanguage('python;q=0.5, python;q=0.9', PROGRAMMING_LANGUAGES)).toBe('python')` (later duplicate wins); `expect(negotiateProgrammingLanguage('python;q=0.9, go;q=0.9', PROGRAMMING_LANGUAGES)).toBe('python')` (earlier index wins the tie).

<ci_summary untrusted="true">
✅ All CI is passing
</ci_summary>

1f4c060 ⋅ general ⋅ 25m 25s ⋅ meituan/longcat-2.0:free

@zeus-review zeus-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Track this run on the progress stub in the PR conversation.

tests Here's what the tests found.

Comment thread test/accept.test.ts
@@ -120,3 +125,61 @@ describe("negotiateType", () => {
expect(negotiateType("*/*;q=0, text/html", PAGE)).toBe(HTML);
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Missing test for duplicate language token deduplication invariant

test/accept.test.ts · lines 127-185

The preferences() function in site/lib/acceptLanguage.ts (lines 42-56) deduplicates repeated language tokens by keeping the highest q, and on equal q retains the earliest index. The negotiateProgrammingLanguage describe block in test/accept.test.ts exercises locale tags, aliases, q-ranking across different languages, q=0, full-refusal fallback, unrecognised languages, and missing/empty headers — but never passes the same language twice. A header like python;q=0.5, python;q=0.9 should resolve to the later higher-q duplicate, while python;q=0.9, python;q=0.5 and python, python should keep the earliest index on equal q. A future edit to the dedup condition (e.g., using >= or tracking the latest index) would silently change which duplicate wins, and no test would catch it.

Prompt to fix
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, and keep changes minimal.

Repository: prathamdby/pr-agent
Pull request: #579
Head SHA: 1f4c060c3ec3dbd73bb9d7290cacf047d3cf6428

[P2] @test/accept.test.ts lines 127-185
Add a vitest case in the `negotiateProgrammingLanguage` describe block asserting that duplicate tokens resolve to the highest q and that the earliest index breaks equal-q ties: `expect(negotiateProgrammingLanguage('python;q=0.5, python;q=0.9', PROGRAMMING_LANGUAGES)).toBe('python')` (later duplicate wins); `expect(negotiateProgrammingLanguage('python;q=0.9, go;q=0.9', PROGRAMMING_LANGUAGES)).toBe('python')` (earlier index wins the tie).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant