Feat: Wire up Claude adaptive thinking + effort

Co-authored-by: Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-30 23:44:08 -07:00
parent b4f434e8ea
commit adb2ed2b38

View File

@@ -143,10 +143,6 @@ export async function streamClaude({ apiKey, body, signal, onDelta, isRunning })
const online = (body.model ?? '').endsWith(':online') const online = (body.model ?? '').endsWith(':online')
const model = online ? body.model.slice(0, -7) : body.model const model = online ? body.model.slice(0, -7) : body.model
const includeThoughts = body.reasoning?.exclude !== true
const effort = body.reasoning?.effort
const useAdaptive = effort && effort !== 'default'
const system = body.messages const system = body.messages
.filter(m => m.role === 'system') .filter(m => m.role === 'system')
.map(extractText) .map(extractText)
@@ -165,18 +161,17 @@ export async function streamClaude({ apiKey, body, signal, onDelta, isRunning })
}).filter(Boolean), }).filter(Boolean),
})).filter(m => m.content.length), })).filter(m => m.content.length),
max_tokens: body.max_tokens || 64000, max_tokens: body.max_tokens || 64000,
stream: true,
} }
if (useAdaptive) {
payload.thinking = { type: 'adaptive' }
if (!includeThoughts) payload.thinking.display = 'omitted'
payload.output_config = { effort }
}
if (system) payload.system = system if (system) payload.system = system
const effort = body.reasoning?.effort
if (effort && effort !== 'default') {
payload.thinking = { type: 'adaptive' }
payload.output_config = { effort }
} else {
if (Number.isFinite(+body.temperature)) payload.temperature = +body.temperature if (Number.isFinite(+body.temperature)) payload.temperature = +body.temperature
if (Number.isFinite(+body.top_p)) payload.top_p = +body.top_p if (Number.isFinite(+body.top_p)) payload.top_p = +body.top_p
}
if (online) { if (online) {
payload.tools = [ payload.tools = [
@@ -185,53 +180,26 @@ export async function streamClaude({ apiKey, body, signal, onDelta, isRunning })
] ]
} }
const resp = await fetch('https://api.anthropic.com/v1/messages', { const includeThoughts = body.reasoning?.exclude !== true
method: 'POST', let hasThinking = false, hasContent = false
headers: {
'x-api-key': apiKey,
'anthropic-version': '2023-06-01',
'content-type': 'application/json',
},
body: JSON.stringify(payload),
signal,
})
if (!resp.ok) throw new Error(`Claude API error: ${resp.status} ${await resp.text()}`)
const reader = resp.body.getReader() const stream = client.messages.stream(payload)
const dec = new TextDecoder()
let buf = '', hasThinking = false, hasContent = false
while (isRunning()) {
const { done, value } = await reader.read()
if (done) break
buf += dec.decode(value, { stream: true })
const lines = buf.split('\n')
buf = lines.pop()
for (const line of lines) {
if (!line.startsWith('data: ')) continue
const data = line.substring(6).trim()
if (!data) continue
try { try {
const event = JSON.parse(data) for await (const event of stream) {
if (event.type === 'content_block_delta') { if (!isRunning()) break
if (event.type !== 'content_block_delta') continue
const delta = event.delta const delta = event.delta
if (delta?.type === 'thinking_delta' && delta.thinking && includeThoughts) { if (delta.type === 'thinking_delta' && includeThoughts) {
onDelta(delta.thinking) onDelta(delta.thinking)
hasThinking = true hasThinking = true
} else if (delta?.type === 'text_delta' && delta.text) { } else if (delta.type === 'text_delta') {
if (hasThinking && !hasContent) onDelta('\n') if (hasThinking && !hasContent) onDelta('\n')
onDelta(delta.text) onDelta(delta.text)
hasContent = true hasContent = true
} }
} else if (event.type === 'message_delta' && event.delta?.stop_reason) {
break
} else if (event.type === 'error') {
throw new Error(event.error?.message || 'Claude stream error')
}
} catch (e) {
if (e.message?.includes('Claude')) throw e
}
} }
} finally {
try { stream.controller?.abort() } catch {}
} }
} }