feat(llm-deepseek): configure max token defaults

This commit is contained in:
Yichen Jiang
2026-07-30 21:04:00 +08:00
parent 2fb90a744e
commit daf70f3660
50 changed files with 430 additions and 95 deletions
@@ -124,6 +124,7 @@ describe('DeepSeekAdapter against a mock server', () => {
// The wire request carried the auth header contents we configured.
expect(server.requests[0]).toMatchObject({
model: 'deepseek-v4-flash',
max_tokens: 256_000,
reasoning_effort: 'high',
stream: true,
stream_options: { include_usage: true },
@@ -232,6 +233,20 @@ describe('DeepSeekAdapter against a mock server', () => {
})
})
it('uses the configured maxTokens default and preserves an explicit request cap', async () => {
const server = await mockServer([
{ kind: 'sse', events: textEvents },
{ kind: 'sse', events: textEvents },
])
const ctx = await harness(server.url, { maxTokens: 32_000 })
await assemble(ctx, { model: 'deepseek-v4-flash', messages: [] })
await assemble(ctx, { model: 'deepseek-v4-flash', messages: [], maxTokens: 8_192 })
expect(server.requests[0]).toMatchObject({ max_tokens: 32_000 })
expect(server.requests[1]).toMatchObject({ max_tokens: 8_192 })
})
it('publishes only off and omits the wire effort when thinking is disabled', async () => {
const server = await mockServer([{ kind: 'sse', events: textEvents }])
const ctx = await harness(server.url, { thinking: 'disabled' })
@@ -666,7 +681,8 @@ describe('plugin registration and config', () => {
provider: 'deepseek',
id: 'deepseek-v4-flash',
name: 'DeepSeek-V4-Flash',
context: { contextWindow: 256_000 },
context: { contextWindow: 1_000_000 },
defaultMaxTokens: 256_000,
reasoning: {
efforts: [
{ id: ReasoningEffortId('off'), name: 'Off' },
@@ -795,7 +811,10 @@ describe('plugin registration and config', () => {
description: 'Higher reasoning budget',
})
await expect(ctx.llm.resolveModelInfo('deepseek', 'arbitrary-unlisted'))
.resolves.not.toHaveProperty('context')
.resolves.toMatchObject({
context: { contextWindow: 1_000_000 },
defaultMaxTokens: 256_000,
})
})
it('uses exact model capacity before the adapter-wide default', async () => {
@@ -880,6 +899,26 @@ describe('plugin registration and config', () => {
},
)
it.each([0, 1.5, Number.MAX_SAFE_INTEGER + 1])(
'rejects invalid adapter-wide maxTokens %s',
async (maxTokens) => {
expect(() => new DeepSeekAdapter({
apiKey: 'k',
baseURL: 'http://127.0.0.1:1',
maxTokens,
})).toThrow(/maxTokens must be a positive safe integer/)
const ctx = new Context()
await ctx.plugin(LlmService)
await expect(ctx.plugin(LlmDeepSeek, {
apiKey: 'k',
baseURL: 'http://127.0.0.1:1',
maxTokens,
})).rejects.toThrow(/maxTokens/)
expect(ctx.llm.listProviders()).toEqual([])
},
)
it('falls back to DEEPSEEK_API_KEY and DEEPSEEK_BASE_URL env vars', async () => {
vi.stubEnv('DEEPSEEK_API_KEY', 'env-key')
vi.stubEnv('DEEPSEEK_BASE_URL', 'http://127.0.0.1:1')
@@ -170,6 +170,13 @@ describe('serializeRequest', () => {
expect(wire.stop).toEqual(['END'])
})
it('uses the adapter maxTokens default only when the request omits a cap', () => {
expect(serializeRequest(request({ messages: history }), {}, 256_000).max_tokens)
.toBe(256_000)
expect(serializeRequest(request({ messages: history, maxTokens: 8_192 }), {}, 256_000).max_tokens)
.toBe(8_192)
})
it('maps tools to the wire function shape', () => {
const wire = serializeRequest(request({
messages: history,