mirror of
https://github.com/NanmiCoder/claude-code-haha.git
synced 2026-10-10 11:53:10 +08:00
Co-authored-by: realLoganLuo <realLoganLuo@users.noreply.github.com> Co-authored-by: 程序员阿江-Relakkes <relakkes@gmail.com>
This commit is contained in:
@@ -209,6 +209,99 @@ describe('titleService', () => {
|
||||
}
|
||||
})
|
||||
|
||||
test('budgets output tokens a thinking model can spend before the title (#1340)', async () => {
|
||||
let requestBody: Record<string, unknown> | null = null
|
||||
const server = Bun.serve({
|
||||
hostname: '127.0.0.1',
|
||||
port: 0,
|
||||
async fetch(req) {
|
||||
requestBody = await req.json() as Record<string, unknown>
|
||||
return Response.json({
|
||||
content: [{ type: 'text', text: '{"title":"Budget respected"}' }],
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
try {
|
||||
const provider = await new ProviderService().addProvider({
|
||||
presetId: 'custom', name: 'Thinking Budget', apiKey: 'test-key',
|
||||
baseUrl: `http://127.0.0.1:${server.port}/anthropic`, apiFormat: 'anthropic',
|
||||
models: {
|
||||
main: 'glm-5.3-flash', haiku: 'glm-5.3-flash',
|
||||
sonnet: 'glm-5.3-flash', opus: 'glm-5.3-flash',
|
||||
},
|
||||
})
|
||||
|
||||
await expect(generateTitle('给这条会话起个短标题', provider.id)).resolves.toBe('Budget respected')
|
||||
// 100 tokens left nothing for the text once reasoning ran: empty content,
|
||||
// null title, placeholder forever (#1340).
|
||||
expect(requestBody?.max_tokens).toBeGreaterThanOrEqual(1024)
|
||||
expect(requestBody?.thinking).toEqual({ type: 'disabled' })
|
||||
} finally {
|
||||
server.stop(true)
|
||||
}
|
||||
})
|
||||
|
||||
test('extracts the title when the response carries a thinking block first (#1340)', async () => {
|
||||
const server = Bun.serve({
|
||||
hostname: '127.0.0.1',
|
||||
port: 0,
|
||||
async fetch() {
|
||||
return Response.json({
|
||||
content: [
|
||||
{ type: 'thinking', thinking: 'The user wants a short title about the migration.', signature: 'sig' },
|
||||
{ type: 'text', text: '{"title":"Migration recap"}' },
|
||||
],
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
try {
|
||||
const provider = await new ProviderService().addProvider({
|
||||
presetId: 'custom', name: 'Thinking Response', apiKey: 'test-key',
|
||||
baseUrl: `http://127.0.0.1:${server.port}/anthropic`, apiFormat: 'anthropic',
|
||||
models: {
|
||||
main: 'glm-5.3-flash', haiku: 'glm-5.3-flash',
|
||||
sonnet: 'glm-5.3-flash', opus: 'glm-5.3-flash',
|
||||
},
|
||||
})
|
||||
|
||||
await expect(generateTitle('Summarize the migration plan', provider.id))
|
||||
.resolves.toBe('Migration recap')
|
||||
} finally {
|
||||
server.stop(true)
|
||||
}
|
||||
})
|
||||
|
||||
test('returns null when reasoning left no text block, so the caller keeps the placeholder (#1340)', async () => {
|
||||
const server = Bun.serve({
|
||||
hostname: '127.0.0.1',
|
||||
port: 0,
|
||||
async fetch() {
|
||||
return Response.json({
|
||||
content: [
|
||||
{ type: 'thinking', thinking: 'burned the entire budget on reasoning', signature: 'sig' },
|
||||
],
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
try {
|
||||
const provider = await new ProviderService().addProvider({
|
||||
presetId: 'custom', name: 'Starved Response', apiKey: 'test-key',
|
||||
baseUrl: `http://127.0.0.1:${server.port}/anthropic`, apiFormat: 'anthropic',
|
||||
models: {
|
||||
main: 'glm-5.3-flash', haiku: 'glm-5.3-flash',
|
||||
sonnet: 'glm-5.3-flash', opus: 'glm-5.3-flash',
|
||||
},
|
||||
})
|
||||
|
||||
await expect(generateTitle('Summarize the migration plan', provider.id)).resolves.toBeNull()
|
||||
} finally {
|
||||
server.stop(true)
|
||||
}
|
||||
})
|
||||
|
||||
test('derives slash-command titles from command metadata without raw XML tags', () => {
|
||||
const raw = [
|
||||
'<command-message>frontend-design</command-message>',
|
||||
|
||||
@@ -31,7 +31,12 @@ import { extractConversationText, SESSION_TITLE_PROMPT } from '../../utils/sessi
|
||||
import type { ProviderAuthStrategy } from '../types/provider.js'
|
||||
|
||||
const TITLE_MAX_LEN = 50
|
||||
const TITLE_MAX_OUTPUT_TOKENS = 100
|
||||
// Thinking models that ignore (or silently drop) `thinking: disabled` spend the
|
||||
// whole budget on reasoning: the text block comes back empty, parsing yields
|
||||
// null, and the session keeps the first-message placeholder forever (#1340).
|
||||
// 100 was only enough for a title with no reasoning in front of it; 2048 leaves
|
||||
// headroom for the thinking burn while staying trivial for a 3-7 word title.
|
||||
const TITLE_MAX_OUTPUT_TOKENS = 2048
|
||||
const TITLE_INPUT_MAX_LEN = 2000
|
||||
|
||||
export type TitleLanguagePreference = {
|
||||
|
||||
Reference in New Issue
Block a user