feat(llm): send DeepSeek user identity header
This commit is contained in:
@@ -19,6 +19,7 @@ import type {
|
||||
} from '@deepseek-ai/dsh-llm'
|
||||
import type { CredentialRef } from '@deepseek-ai/dsh-credentials'
|
||||
import { idleWatchdog, timeoutOf } from '@deepseek-ai/dsh-timeout'
|
||||
import type { AnonymousUserId } from '@deepseek-ai/dsh-user-id'
|
||||
import { serializeRequest } from './serialize.ts'
|
||||
import type { RequestDefaults } from './serialize.ts'
|
||||
import { parseSse } from './sse.ts'
|
||||
@@ -69,7 +70,7 @@ export interface DeepSeekConnectionOptions {
|
||||
retryPolicy: ResolvedRetryPolicy
|
||||
}
|
||||
|
||||
/** Constructor options for {@link DeepSeekAdapter}: the two resolution hooks the plugin owns. */
|
||||
/** Constructor options for {@link DeepSeekAdapter}: the operation-local resolution hooks the plugin owns. */
|
||||
export interface DeepSeekAdapterOptions {
|
||||
/** Current validated connection facts; called once per operation. */
|
||||
options: () => DeepSeekConnectionOptions
|
||||
@@ -80,6 +81,8 @@ export interface DeepSeekAdapterOptions {
|
||||
* `MISSING_CREDENTIAL` when no key is available anywhere.
|
||||
*/
|
||||
resolveApiKey: (connection: DeepSeekConnectionOptions) => Promise<string>
|
||||
/** Resolve the harness-home anonymous id shared with telemetry and feedback. */
|
||||
resolveUserId: () => AnonymousUserId
|
||||
}
|
||||
|
||||
/** Default maximum idle interval while an adapter stream read is outstanding. */
|
||||
@@ -216,6 +219,7 @@ export class DeepSeekAdapter extends LlmAdapter {
|
||||
// sent to it can never come from different configuration generations.
|
||||
const connection = this.config.options()
|
||||
const apiKey = await this.config.resolveApiKey(connection)
|
||||
const userId = this.config.resolveUserId()
|
||||
const consumer = new AbortController()
|
||||
const upstream = options.signal === undefined
|
||||
? consumer.signal
|
||||
@@ -226,6 +230,7 @@ export class DeepSeekAdapter extends LlmAdapter {
|
||||
watchdog.signal,
|
||||
connection,
|
||||
apiKey,
|
||||
userId,
|
||||
() => { watchdog.pulse() },
|
||||
)[Symbol.asyncIterator]()
|
||||
let exhausted = false
|
||||
@@ -268,6 +273,7 @@ export class DeepSeekAdapter extends LlmAdapter {
|
||||
signal: AbortSignal,
|
||||
connection: DeepSeekConnectionOptions,
|
||||
apiKey: string,
|
||||
userId: AnonymousUserId,
|
||||
onComment: () => void,
|
||||
): AsyncIterable<StreamChunk> {
|
||||
const body = serializeRequest(options, connection.defaults)
|
||||
@@ -279,6 +285,7 @@ export class DeepSeekAdapter extends LlmAdapter {
|
||||
'content-type': 'application/json',
|
||||
'accept': 'text/event-stream',
|
||||
...attributionHeaders(),
|
||||
'x-deepseek-harness-user-id': String(userId),
|
||||
...options.sessionId !== undefined
|
||||
? { 'x-deepseek-harness-session-id': String(options.sessionId) }
|
||||
: {},
|
||||
|
||||
@@ -19,6 +19,7 @@ import { credentialRef } from '@deepseek-ai/dsh-credentials'
|
||||
import { environmentOf, type EnvironmentSnapshot } from '@deepseek-ai/dsh-environment'
|
||||
import { deepEqualJson, installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings'
|
||||
import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'
|
||||
import { getOrCreateAnonymousUserId, type AnonymousUserId } from '@deepseek-ai/dsh-user-id'
|
||||
import {
|
||||
DEFAULT_CONTEXT_WINDOW,
|
||||
DEFAULT_MAX_TOKENS,
|
||||
@@ -244,7 +245,9 @@ export function apply(ctx: Context, config: Config): void {
|
||||
)
|
||||
}
|
||||
|
||||
const adapter = new DeepSeekAdapter({ options, resolveApiKey })
|
||||
let userId: AnonymousUserId | undefined
|
||||
const resolveUserId = (): AnonymousUserId => userId ??= getOrCreateAnonymousUserId()
|
||||
const adapter = new DeepSeekAdapter({ options, resolveApiKey, resolveUserId })
|
||||
ctx.llm.registerConfigurableProviders([
|
||||
{ provider: PROVIDER, displayName: 'DeepSeek', settingsNs: NS, settingsPath: [] },
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user