Implement mandatory app-attribution headers per the RFC
dsh-llm owns the vocabulary (attribution.ts): AppIdentity with the version
read from the package manifest, userAgent(), and attributionHeaders(target,
identity) over a closed AttributionTarget union ('generic' | 'openrouter').
Both adapters send the headers on every provider request — llm-deepseek in
its fetch headers, llm-pi-ai through pi-ai's StreamOptions.headers — behind
an explicit attributionTarget config (never inferred from baseURL), with
mock-server tests asserting exact wire arrival and the absence of the
OpenRouter set by default.
The RFC moves to implemented/ amended with the settled identity (the
deepseek-harness token, the DeepSeek Harness title, the planned
deepseek-ai/deepseek-harness-sdk URL behind a FIXME until that repo exists)
and the explicit-config OpenRouter decision.
This commit is contained in:
75
packages/llm/llm/tests/attribution.spec.ts
Normal file
75
packages/llm/llm/tests/attribution.spec.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { createRequire } from 'node:module'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { APP_IDENTITY, attributionHeaders, userAgent } from '@deepseek-ai/dsh-llm'
|
||||
import type { AppIdentity, AttributionTarget } from '@deepseek-ai/dsh-llm'
|
||||
|
||||
const manifest = createRequire(import.meta.url)('../package.json') as { version: string }
|
||||
|
||||
/** A white-label identity exercising every override seam. */
|
||||
const forkIdentity: AppIdentity = {
|
||||
product: 'fork-agent',
|
||||
version: '9.9.9',
|
||||
title: 'Fork Agent',
|
||||
url: 'https://example.com/fork-agent',
|
||||
categories: ['ide-extension', 'cli-agent'],
|
||||
}
|
||||
|
||||
describe('APP_IDENTITY', () => {
|
||||
it('sources the version from the package manifest, never a hand-copied constant', () => {
|
||||
expect(APP_IDENTITY.version).toBe(manifest.version)
|
||||
})
|
||||
|
||||
it('carries only static public product facts', () => {
|
||||
expect(APP_IDENTITY).toEqual({
|
||||
product: 'deepseek-harness',
|
||||
version: manifest.version,
|
||||
title: 'DeepSeek Harness',
|
||||
url: 'https://github.com/deepseek-ai/deepseek-harness-sdk',
|
||||
categories: ['cli-agent'],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('userAgent', () => {
|
||||
it('renders product/version with the +url comment', () => {
|
||||
expect(userAgent()).toBe(
|
||||
`deepseek-harness/${manifest.version} (+https://github.com/deepseek-ai/deepseek-harness-sdk)`,
|
||||
)
|
||||
})
|
||||
|
||||
it('renders a custom identity', () => {
|
||||
expect(userAgent(forkIdentity)).toBe('fork-agent/9.9.9 (+https://example.com/fork-agent)')
|
||||
})
|
||||
})
|
||||
|
||||
describe('attributionHeaders', () => {
|
||||
it('defaults to the provider-neutral baseline: User-Agent and nothing else', () => {
|
||||
expect(attributionHeaders()).toEqual({ 'user-agent': userAgent() })
|
||||
})
|
||||
|
||||
it('adds exactly the OpenRouter set for the openrouter target', () => {
|
||||
expect(attributionHeaders('openrouter')).toEqual({
|
||||
'user-agent': userAgent(),
|
||||
'http-referer': APP_IDENTITY.url,
|
||||
'x-openrouter-title': APP_IDENTITY.title,
|
||||
'x-openrouter-categories': 'cli-agent',
|
||||
})
|
||||
})
|
||||
|
||||
it('maps a custom identity onto both targets', () => {
|
||||
expect(attributionHeaders('generic', forkIdentity)).toEqual({
|
||||
'user-agent': 'fork-agent/9.9.9 (+https://example.com/fork-agent)',
|
||||
})
|
||||
expect(attributionHeaders('openrouter', forkIdentity)).toEqual({
|
||||
'user-agent': 'fork-agent/9.9.9 (+https://example.com/fork-agent)',
|
||||
'http-referer': 'https://example.com/fork-agent',
|
||||
'x-openrouter-title': 'Fork Agent',
|
||||
'x-openrouter-categories': 'ide-extension,cli-agent',
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects targets outside the closed union at runtime', () => {
|
||||
expect(() => attributionHeaders('acme' as unknown as AttributionTarget))
|
||||
.toThrow('unreachable variant in attributionHeaders: "acme"')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user