Files
memind/deepseek-no-think-proxy.test.mjs
john fb6865638a
Memind CI / Test, build, and release guards (pull_request) Successful in 1m32s
fix: align DeepSeek canary tool rounds with gate
2026-07-26 23:49:32 +08:00

192 lines
6.3 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
DEEPSEEK_COMPAT_CONTRACT_VERSION,
decodedUpstreamResponseHeaders,
deepseekDisableThinkingEnabled,
flattenLocalJsonSchemaRefs,
injectDeepseekThinkingDisabled,
isMoonshotApiUrl,
moonshotToolSchemaCompatEnabled,
resolveDeepseekNoThinkProxyBaseUrl,
resolveMoonshotCompatProxyBaseUrl,
sanitizeMoonshotToolSchemas,
startDeepseekNoThinkProxy,
} from './deepseek-no-think-proxy.mjs';
test('injectDeepseekThinkingDisabled adds thinking.disabled when absent', () => {
const { body, injected } = injectDeepseekThinkingDisabled({
model: 'deepseek-v4-flash',
messages: [{ role: 'user', content: 'hi' }],
});
assert.equal(injected, true);
assert.deepEqual(body.thinking, { type: 'disabled' });
assert.equal(body.model, 'deepseek-v4-flash');
});
test('injectDeepseekThinkingDisabled overrides enabled thinking config', () => {
const { body, injected } = injectDeepseekThinkingDisabled({
model: 'deepseek-v4-pro',
thinking: { type: 'enabled' },
});
assert.equal(injected, true);
assert.deepEqual(body.thinking, { type: 'disabled' });
});
test('deepseekDisableThinkingEnabled defaults on for local runtime profile', () => {
assert.equal(deepseekDisableThinkingEnabled({ MEMIND_RUNTIME_PROFILE: 'local' }), true);
assert.equal(deepseekDisableThinkingEnabled({ MEMIND_RUNTIME_PROFILE: 'split-service' }), true);
assert.equal(deepseekDisableThinkingEnabled({ MEMIND_RUNTIME_PROFILE: 'production' }), false);
assert.equal(
deepseekDisableThinkingEnabled({
MEMIND_RUNTIME_PROFILE: 'local',
MEMIND_DEEPSEEK_DISABLE_THINKING: '0',
}),
false,
);
assert.equal(
deepseekDisableThinkingEnabled({
MEMIND_RUNTIME_PROFILE: 'production',
MEMIND_DEEPSEEK_DISABLE_THINKING: '1',
}),
true,
);
});
test('moonshotToolSchemaCompatEnabled defaults on for local runtime profiles', () => {
assert.equal(moonshotToolSchemaCompatEnabled({ MEMIND_RUNTIME_PROFILE: 'local' }), true);
assert.equal(moonshotToolSchemaCompatEnabled({ MEMIND_RUNTIME_PROFILE: 'split-service' }), true);
assert.equal(moonshotToolSchemaCompatEnabled({ MEMIND_RUNTIME_PROFILE: 'production' }), false);
assert.equal(
moonshotToolSchemaCompatEnabled({
MEMIND_RUNTIME_PROFILE: 'local',
MEMIND_MOONSHOT_TOOL_SCHEMA_COMPAT: '0',
}),
false,
);
});
test('resolveDeepseekNoThinkProxyBaseUrl uses host gateway defaults', () => {
assert.equal(
resolveDeepseekNoThinkProxyBaseUrl({}),
'http://host.docker.internal:18036/v1',
);
assert.equal(
resolveDeepseekNoThinkProxyBaseUrl({
MEMIND_DEEPSEEK_NO_THINK_BASE_URL: 'http://10.0.0.2:9/v1/',
}),
'http://10.0.0.2:9/v1',
);
});
test('Moonshot compat routing recognizes official endpoints and uses a distinct path', () => {
assert.equal(isMoonshotApiUrl('https://api.moonshot.cn/v1'), true);
assert.equal(isMoonshotApiUrl('https://api.moonshot.ai/v1/'), true);
assert.equal(isMoonshotApiUrl('https://api.deepseek.com/v1'), false);
assert.equal(
resolveMoonshotCompatProxyBaseUrl({}),
'http://host.docker.internal:18036/moonshot/v1',
);
});
test('flattenLocalJsonSchemaRefs inlines local definitions without mutating the source', () => {
const source = {
$schema: 'https://json-schema.org/draft/2020-12/schema',
type: 'object',
properties: {
command: {
description: 'command override',
$ref: '#/$defs/CacheCommand',
},
},
required: ['command'],
$defs: {
CacheCommand: {
type: 'string',
oneOf: [{ const: 'list' }, { const: 'clear' }],
},
},
};
const flattened = flattenLocalJsonSchemaRefs(source);
assert.equal(JSON.stringify(flattened).includes('$ref'), false);
assert.equal(JSON.stringify(flattened).includes('$defs'), false);
assert.equal(flattened.properties.command.type, 'string');
assert.equal(flattened.properties.command.description, 'command override');
assert.equal(source.properties.command.$ref, '#/$defs/CacheCommand');
});
test('sanitizeMoonshotToolSchemas only rewrites function schemas with local refs', () => {
const plain = {
type: 'function',
function: { name: 'plain', parameters: { type: 'object' } },
};
const body = {
model: 'kimi-k2.6',
tools: [
plain,
{
type: 'function',
function: {
name: 'cache',
parameters: {
type: 'object',
properties: { command: { $ref: '#/$defs/Command' } },
$defs: { Command: { type: 'string', enum: ['list', 'clear'] } },
},
},
},
],
};
const result = sanitizeMoonshotToolSchemas(body);
assert.equal(result.sanitized, 1);
assert.equal(result.body.tools[0], plain);
assert.deepEqual(
result.body.tools[1].function.parameters.properties.command,
{ type: 'string', enum: ['list', 'clear'] },
);
});
test('Moonshot requests can reuse thinking.disabled injection', () => {
const schemaResult = sanitizeMoonshotToolSchemas({
model: 'kimi-k2.6',
tools: [],
});
const thinkingResult = injectDeepseekThinkingDisabled(schemaResult.body);
assert.equal(thinkingResult.injected, true);
assert.deepEqual(thinkingResult.body.thinking, { type: 'disabled' });
});
test('decodedUpstreamResponseHeaders drops stale compression metadata', () => {
const headers = new Headers({
'content-type': 'text/event-stream',
'content-encoding': 'br',
'content-length': '123',
'transfer-encoding': 'chunked',
connection: 'keep-alive',
'cache-control': 'no-cache',
});
assert.deepEqual(decodedUpstreamResponseHeaders(headers), {
'cache-control': 'no-cache',
'content-type': 'text/event-stream',
});
});
test('compatibility proxy health identifies the enforced production contract', async (t) => {
const server = await startDeepseekNoThinkProxy({
host: '127.0.0.1',
port: 0,
logger: { info() {}, warn() {}, error() {} },
});
t.after(() => new Promise((resolve) => server.close(resolve)));
const address = server.address();
const response = await fetch(`http://127.0.0.1:${address.port}/health`);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
ok: true,
contractVersion: DEEPSEEK_COMPAT_CONTRACT_VERSION,
deepseekThinking: 'disabled',
upstream: 'https://api.deepseek.com',
moonshotUpstream: 'https://api.moonshot.cn',
});
});