Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/function/update/invoke_extra_model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,11 +526,14 @@ async function requestReply(generation_id?: string, batch_id?: string): Promise<
? SillyTavern.getChatCompletionModel()
: store.settings.额外模型解析配置.模型名称;
const is_gemini = model_name.toLowerCase().includes('gemini');
const rnd_header_prompts = store.settings.额外模型解析配置.随机头部
? [{ role: 'system' as const, content: batch_id ?? generateRandomHeader() }]
: [];

const result = await generateRaw({
...config,
ordered_prompts: [
{ role: 'system', content: batch_id ?? generateRandomHeader() },
...rnd_header_prompts,
{ role: 'system', content: is_gemini ? decoded_gemini_head : decoded_claude_head },
{ role: 'system', content: '<additional_information>' },
'persona_description',
Expand Down
11 changes: 11 additions & 0 deletions src/panel/update/Prompt.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@
<input v-else class="text_pole" type="text" disabled value="未检测到可用的已保存预设" />
</Field>

<Field v-if="store.settings.额外模型解析配置.破限方案 === '使用内置破限'" label="随机头部">
<template #label-suffix>
<HelpIcon
help="gemini系模型会对破限头部进行记录,因此需要在头部增加随机数。如果您使用的不是Gemini系模型,请关闭这个功能,避免缓存失效。"
/>
</template>
<Checkbox v-model="store.settings.额外模型解析配置.随机头部">
<span>随机头部</span>
</Checkbox>
</Field>

<Field label="应答格式">
<template #label-suffix>
<HelpIcon :help="prompt_toolcall_help" />
Expand Down
1 change: 1 addition & 0 deletions src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const NewSettings = z
应答格式: ExtraModelResponseFormat.optional(),
关闭thinking: z.boolean().default(false),
兼容假流式: z.boolean().default(false),
随机头部: z.boolean().default(true),

启用自动请求: z.boolean().default(true),
请求方式: z
Expand Down
41 changes: 35 additions & 6 deletions tests/extra_model_max_chat_history.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,32 @@ describe('extra model max chat history', () => {
);
});

test('adds random header for built-in jailbreak by default', async () => {
await generateExtraModel();

const config = (globalThis as any).generateRaw.mock.calls[0][0];
expect(config.ordered_prompts[0]).toEqual({
role: 'system',
content: expect.stringMatching(/^[0-9a-f]{8}\n[0-9a-f]{8}\n[0-9a-f]{8}\n[0-9a-f]{8}$/i),
});
});

test('omits random header when disabled', async () => {
const store = useDataStore();
store.settings.额外模型解析配置.随机头部 = false;

await generateExtraModel();

const config = (globalThis as any).generateRaw.mock.calls[0][0];
expect(config.ordered_prompts[0]).not.toEqual(
expect.objectContaining({
content: expect.stringMatching(
/^[0-9a-f]{8}\n[0-9a-f]{8}\n[0-9a-f]{8}\n[0-9a-f]{8}$/i
),
})
);
});

test('uses temporary saved custom json_object response format for v4 compatible formatted output', async () => {
const store = useDataStore();
store.versions.tavernhelper = '4.3.9';
Expand All @@ -46,10 +72,12 @@ describe('extra model max chat history', () => {

(globalThis as any).generateRaw = jest.fn().mockImplementation(async config => {
expect((globalThis as any).builtin.saveSettings).toHaveBeenCalledTimes(1);
expect((globalThis as any).SillyTavern.chatCompletionSettings.custom_include_body)
.toContain(`response_format:\n type: json_object`);
expect((globalThis as any).SillyTavern.chatCompletionSettings.custom_include_body)
.toContain(`thinking:\n type: disabled`);
expect(
(globalThis as any).SillyTavern.chatCompletionSettings.custom_include_body
).toContain(`response_format:\n type: json_object`);
expect(
(globalThis as any).SillyTavern.chatCompletionSettings.custom_include_body
).toContain(`thinking:\n type: disabled`);
expect(config.custom_api).toEqual(
expect.objectContaining({
source: 'custom',
Expand Down Expand Up @@ -104,8 +132,9 @@ describe('extra model max chat history', () => {

(globalThis as any).generateRaw = jest.fn().mockImplementation(async config => {
expect((globalThis as any).builtin.saveSettings).toHaveBeenCalledTimes(1);
expect((globalThis as any).SillyTavern.chatCompletionSettings.custom_include_body)
.toContain(`response_format:\n type: json_object`);
expect(
(globalThis as any).SillyTavern.chatCompletionSettings.custom_include_body
).toContain(`response_format:\n type: json_object`);
expect(config.custom_api).toEqual(
expect.objectContaining({
source: 'custom',
Expand Down
6 changes: 6 additions & 0 deletions tests/store_response_format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ describe('extra model response format settings', () => {
expect(store.settings.额外模型解析配置.关闭thinking).toBe(false);
});

test('defaults random header to enabled', () => {
const store = useDataStore();

expect(store.settings.额外模型解析配置.随机头部).toBe(true);
});

test('clamps max chat history to the supported range', () => {
(globalThis as any).SillyTavern.extensionSettings = {
mvu_settings: {
Expand Down
Loading