deepseek-harness/packages/llm/deepseek-llm-api-extensions/src/index.ts
Tianyi Cui ea6f61f144 feat(deepseek): upload plugin package metadata (#2916)
* feat(deepseek): upload plugin package metadata

* feat(deepseek): apply metadata review feedback

* docs(deepseek): specify request wire extensions

* docs(notes): record inventory cache benchmark

* docs(site): keep DeepSeek wire spec repository-only
2026-08-22 20:03:23 +08:00

132 lines
5.2 KiB
TypeScript

/**
* DeepSeek LLM API extension registry: plugins own independent top-level request
* fields while the official adapter performs one preparation and acceptance transaction.
* @module @deepseek-ai/dsh-deepseek-llm-api-extensions
*/
import { Context, Service } from '@deepseek-ai/cordis'
import type {
DeepSeekLlmApiExtensionMap,
DeepSeekLlmApiExtensionProvider,
DeepSeekLlmApiExtensionRequest,
DeepSeekLlmApiJson,
PreparedDeepSeekLlmApiExtensions,
} from './types.ts'
export type * from './types.ts'
declare module '@deepseek-ai/cordis' {
interface Context {
deepseekLlmApiExtensions: DeepSeekLlmApiExtensionRegistry
}
}
interface ErasedProvider {
prepare(request: DeepSeekLlmApiExtensionRequest):
| { readonly value: DeepSeekLlmApiJson; accept?(): void | Promise<void> }
| undefined
| Promise<{ readonly value: DeepSeekLlmApiJson; accept?(): void | Promise<void> } | undefined>
}
/** Recursively freeze a fresh structured clone. */
function freezeJson<T extends DeepSeekLlmApiJson>(value: T): T {
if (value !== null && typeof value === 'object') {
for (const child of Array.isArray(value) ? value : Object.values(value)) freezeJson(child)
Object.freeze(value)
}
return value
}
/** Settle every acceptance callback before reporting failures. */
async function acceptAll(callbacks: readonly (() => void | Promise<void>)[]): Promise<void> {
const outcomes = await Promise.allSettled(callbacks.map(callback => Promise.resolve().then(callback)))
const failures: unknown[] = outcomes
.filter((outcome): outcome is PromiseRejectedResult => outcome.status === 'rejected')
.map(outcome => outcome.reason as unknown)
if (failures.length === 1) throw failures[0]
if (failures.length > 1) throw new AggregateError(failures, 'DeepSeek LLM API extension acceptance failed')
}
/** Stop awaiting provider work when the containing model request is cancelled. */
async function abortable<T>(work: Promise<T>, signal: AbortSignal): Promise<T> {
signal.throwIfAborted()
const aborted = Promise.withResolvers<never>()
const onAbort = (): void => { aborted.reject(signal.reason) }
signal.addEventListener('abort', onAbort, { once: true })
try {
const result = await Promise.race([work, aborted.promise])
signal.throwIfAborted()
return result
} finally {
signal.removeEventListener('abort', onAbort)
}
}
/** Registry of independently owned top-level fields for official DeepSeek requests. */
export class DeepSeekLlmApiExtensionRegistry extends Service {
private readonly providers = new Map<string, ErasedProvider>()
constructor(ctx: Context) {
super(ctx, 'deepseekLlmApiExtensions')
}
/**
* Register the sole provider of one top-level request field. Registration is effect-scoped.
* @param field - declaration-merged field owned by the provider.
* @param provider - request-time field preparation and optional acceptance behavior.
* @returns disposer that releases the field.
*/
register<K extends keyof DeepSeekLlmApiExtensionMap>(
field: K,
provider: DeepSeekLlmApiExtensionProvider<DeepSeekLlmApiExtensionMap[K]>,
): () => Promise<void> {
const fieldName = field as string
if (fieldName.length === 0 || fieldName.trim() !== fieldName) {
throw new Error('deepseek-llm-api-extensions: field must be a non-blank trimmed string')
}
const providers = this.providers
const erased = provider as ErasedProvider
const dispose = this.ctx.effect(() => {
if (providers.has(fieldName)) {
throw new Error(`deepseek-llm-api-extensions: field ${JSON.stringify(fieldName)} is already registered`)
}
providers.set(fieldName, erased)
return () => {
providers.delete(fieldName)
}
}, `deepseekLlmApiExtensions.register(${JSON.stringify(fieldName)})`)
return dispose
}
/**
* Prepare every currently registered field from one immutable base request.
* Preparation failures reject before HTTP dispatch. Field values are cloned and frozen;
* providers retain no mutable alias to the outgoing request.
* @param request - exact serialized request facts before extension fields.
* @returns detached fields and their idempotent joint acceptance transaction.
*/
async prepare(request: DeepSeekLlmApiExtensionRequest): Promise<PreparedDeepSeekLlmApiExtensions> {
request.signal.throwIfAborted()
const entries = [...this.providers.entries()]
const prepared = await abortable(Promise.all(entries.map(async ([field, provider]) => ({
field,
result: await provider.prepare(request),
}))), request.signal)
const fields: Record<string, DeepSeekLlmApiJson> = Object.create(null) as Record<string, DeepSeekLlmApiJson>
const callbacks: Array<() => void | Promise<void>> = []
for (const { field, result } of prepared) {
if (result === undefined) continue
fields[field] = freezeJson(structuredClone(result.value))
const accept = result.accept
if (accept !== undefined) callbacks.push(accept.bind(result))
}
Object.freeze(fields)
let acceptance: Promise<void> | undefined
return {
fields,
accept: () => acceptance ??= acceptAll(callbacks),
}
}
}
export default DeepSeekLlmApiExtensionRegistry