This commit is contained in:
Calvin Wade 2025-12-18 20:16:23 +08:00 committed by GitHub
commit 4b5653c98c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 71 additions and 16 deletions

View File

@ -120,6 +120,23 @@ export class AiSdkToChunkAdapter {
} }
} }
/**
* THINKING_COMPLETE chunk
* @param final reasoningContent
* @returns THINKING_COMPLETE chunk
*/
private emitThinkingCompleteIfNeeded(final: { reasoningContent: string; [key: string]: any }): boolean {
if (final.reasoningContent) {
this.onChunk({
type: ChunkType.THINKING_COMPLETE,
text: final.reasoningContent
})
final.reasoningContent = ''
return true
}
return false
}
/** /**
* AI SDK chunk Cherry Studio chunk * AI SDK chunk Cherry Studio chunk
* @param chunk AI SDK chunk * @param chunk AI SDK chunk
@ -145,6 +162,9 @@ export class AiSdkToChunkAdapter {
} }
// === 文本相关事件 === // === 文本相关事件 ===
case 'text-start': case 'text-start':
// 如果有未完成的思考内容,先生成 THINKING_COMPLETE
// 这处理了某些提供商不发送 reasoning-end 事件的情况
this.emitThinkingCompleteIfNeeded(final)
this.onChunk({ this.onChunk({
type: ChunkType.TEXT_START type: ChunkType.TEXT_START
}) })
@ -215,11 +235,7 @@ export class AiSdkToChunkAdapter {
}) })
break break
case 'reasoning-end': case 'reasoning-end':
this.onChunk({ this.emitThinkingCompleteIfNeeded(final)
type: ChunkType.THINKING_COMPLETE,
text: final.reasoningContent || ''
})
final.reasoningContent = ''
break break
// === 工具调用相关事件(原始 AI SDK 事件,如果没有被中间件处理) === // === 工具调用相关事件(原始 AI SDK 事件,如果没有被中间件处理) ===

View File

@ -29,10 +29,20 @@ interface BaseCallbacksDependencies {
assistantMsgId: string assistantMsgId: string
saveUpdatesToDB: any saveUpdatesToDB: any
assistant: Assistant assistant: Assistant
getCurrentThinkingInfo?: () => { blockId: string | null; millsec: number }
} }
export const createBaseCallbacks = (deps: BaseCallbacksDependencies) => { export const createBaseCallbacks = (deps: BaseCallbacksDependencies) => {
const { blockManager, dispatch, getState, topicId, assistantMsgId, saveUpdatesToDB, assistant } = deps const {
blockManager,
dispatch,
getState,
topicId,
assistantMsgId,
saveUpdatesToDB,
assistant,
getCurrentThinkingInfo
} = deps
const startTime = Date.now() const startTime = Date.now()
const notificationService = NotificationService.getInstance() const notificationService = NotificationService.getInstance()
@ -98,10 +108,17 @@ export const createBaseCallbacks = (deps: BaseCallbacksDependencies) => {
const possibleBlockId = findBlockIdForCompletion() const possibleBlockId = findBlockIdForCompletion()
if (possibleBlockId) { if (possibleBlockId) {
// 更改上一个block的状态为ERROR // 更改上一个block的状态为ERROR/PAUSED
const changes = { const changes: Record<string, any> = {
status: isErrorTypeAbort ? MessageBlockStatus.PAUSED : MessageBlockStatus.ERROR status: isErrorTypeAbort ? MessageBlockStatus.PAUSED : MessageBlockStatus.ERROR
} }
// 如果是 thinking block保留实际思考时间
if (blockManager.lastBlockType === MessageBlockType.THINKING) {
const thinkingInfo = getCurrentThinkingInfo?.()
if (thinkingInfo?.blockId === possibleBlockId && thinkingInfo?.millsec && thinkingInfo.millsec > 0) {
changes.thinking_millsec = thinkingInfo.millsec
}
}
blockManager.smartBlockUpdate(possibleBlockId, changes, blockManager.lastBlockType!, true) blockManager.smartBlockUpdate(possibleBlockId, changes, blockManager.lastBlockType!, true)
} }
@ -111,13 +128,28 @@ export const createBaseCallbacks = (deps: BaseCallbacksDependencies) => {
if (currentMessage) { if (currentMessage) {
const allBlockRefs = findAllBlocks(currentMessage) const allBlockRefs = findAllBlocks(currentMessage)
const blockState = getState().messageBlocks const blockState = getState().messageBlocks
// 获取当前思考信息(如果有),用于保留实际思考时间
const thinkingInfo = getCurrentThinkingInfo?.()
for (const blockRef of allBlockRefs) { for (const blockRef of allBlockRefs) {
const block = blockState.entities[blockRef.id] const block = blockState.entities[blockRef.id]
if (block && block.status === MessageBlockStatus.STREAMING && block.id !== possibleBlockId) { if (block && block.status === MessageBlockStatus.STREAMING && block.id !== possibleBlockId) {
// 构建更新对象
const changes: Record<string, any> = {
status: isErrorTypeAbort ? MessageBlockStatus.PAUSED : MessageBlockStatus.ERROR
}
// 如果是 thinking block 且有思考时间信息,保留实际思考时间
if (
block.type === MessageBlockType.THINKING &&
thinkingInfo?.blockId === block.id &&
thinkingInfo?.millsec &&
thinkingInfo.millsec > 0
) {
changes.thinking_millsec = thinkingInfo.millsec
}
dispatch( dispatch(
updateOneBlock({ updateOneBlock({
id: block.id, id: block.id,
changes: { status: isErrorTypeAbort ? MessageBlockStatus.PAUSED : MessageBlockStatus.ERROR } changes
}) })
) )
} }

View File

@ -23,6 +23,12 @@ interface CallbacksDependencies {
export const createCallbacks = (deps: CallbacksDependencies) => { export const createCallbacks = (deps: CallbacksDependencies) => {
const { blockManager, dispatch, getState, topicId, assistantMsgId, saveUpdatesToDB, assistant } = deps const { blockManager, dispatch, getState, topicId, assistantMsgId, saveUpdatesToDB, assistant } = deps
// 首先创建 thinkingCallbacks ,以便传递 getCurrentThinkingInfo 给 baseCallbacks
const thinkingCallbacks = createThinkingCallbacks({
blockManager,
assistantMsgId
})
// 创建基础回调 // 创建基础回调
const baseCallbacks = createBaseCallbacks({ const baseCallbacks = createBaseCallbacks({
blockManager, blockManager,
@ -31,13 +37,8 @@ export const createCallbacks = (deps: CallbacksDependencies) => {
topicId, topicId,
assistantMsgId, assistantMsgId,
saveUpdatesToDB, saveUpdatesToDB,
assistant assistant,
}) getCurrentThinkingInfo: thinkingCallbacks.getCurrentThinkingInfo
// 创建各类回调
const thinkingCallbacks = createThinkingCallbacks({
blockManager,
assistantMsgId
}) })
const toolCallbacks = createToolCallbacks({ const toolCallbacks = createToolCallbacks({

View File

@ -19,6 +19,12 @@ export const createThinkingCallbacks = (deps: ThinkingCallbacksDependencies) =>
let thinking_millsec_now: number = 0 let thinking_millsec_now: number = 0
return { return {
// 获取当前思考时间(用于停止回复时保留思考时间)
getCurrentThinkingInfo: () => ({
blockId: thinkingBlockId,
millsec: thinking_millsec_now > 0 ? performance.now() - thinking_millsec_now : 0
}),
onThinkingStart: async () => { onThinkingStart: async () => {
if (blockManager.hasInitialPlaceholder) { if (blockManager.hasInitialPlaceholder) {
const changes: Partial<MessageBlock> = { const changes: Partial<MessageBlock> = {