fix: persistent "Searching..." indicators for o3 model web search (#8328)

* fix: fix persistent "Searching..." indicators for o3 model web search

- Add missing LLM_WEB_SEARCH_IN_PROGRESS event in OpenAIAPIClient
- Prevent duplicate CitationBlock creation
- Ensure search status updates correctly after completion

Fixes #8307

* fix: prevent duplicate citation blocks in web search callbacks

- Add checks in onExternalToolInProgress and onLLMWebSearchInProgress
- Return early if citationBlockId already exists
- Fixes persistent "Searching..." indicator for o3 model web search
This commit is contained in:
Jason Young 2025-07-21 10:17:27 +08:00 committed by GitHub
parent 37508493fb
commit bfc3b0e54e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 25 additions and 0 deletions

View File

@ -563,6 +563,7 @@ export class OpenAIAPIClient extends OpenAIBaseClient<
// 在RawSdkChunkToGenericChunkMiddleware中使用
getResponseChunkTransformer(): ResponseChunkTransformer<OpenAISdkRawChunk> {
let hasBeenCollectedWebSearch = false
let hasEmittedWebSearchInProgress = false
const collectWebSearchData = (
chunk: OpenAISdkRawChunk,
contentSource: OpenAISdkRawContentSource,
@ -769,6 +770,13 @@ export class OpenAIAPIClient extends OpenAIBaseClient<
const webSearchData = collectWebSearchData(chunk, contentSource, context)
if (webSearchData) {
// 如果还未发送搜索进度事件,先发送进度事件
if (!hasEmittedWebSearchInProgress) {
controller.enqueue({
type: ChunkType.LLM_WEB_SEARCH_IN_PROGRESS
})
hasEmittedWebSearchInProgress = true
}
controller.enqueue({
type: ChunkType.LLM_WEB_SEARCH_COMPLETE,
llm_web_search: webSearchData
@ -833,6 +841,13 @@ export class OpenAIAPIClient extends OpenAIBaseClient<
logger.debug(`Stream finished with reason: ${choice.finish_reason}`)
const webSearchData = collectWebSearchData(chunk, contentSource, context)
if (webSearchData) {
// 如果还未发送搜索进度事件,先发送进度事件
if (!hasEmittedWebSearchInProgress) {
controller.enqueue({
type: ChunkType.LLM_WEB_SEARCH_IN_PROGRESS
})
hasEmittedWebSearchInProgress = true
}
controller.enqueue({
type: ChunkType.LLM_WEB_SEARCH_COMPLETE,
llm_web_search: webSearchData

View File

@ -22,6 +22,11 @@ export const createCitationCallbacks = (deps: CitationCallbacksDependencies) =>
return {
onExternalToolInProgress: async () => {
// 避免创建重复的引用块
if (citationBlockId) {
logger.warn('[onExternalToolInProgress] Citation block already exists:', citationBlockId)
return
}
const citationBlock = createCitationBlock(assistantMsgId, {}, { status: MessageBlockStatus.PROCESSING })
citationBlockId = citationBlock.id
await blockManager.handleBlockTransition(citationBlock, MessageBlockType.CITATION)
@ -41,6 +46,11 @@ export const createCitationCallbacks = (deps: CitationCallbacksDependencies) =>
},
onLLMWebSearchInProgress: async () => {
// 避免创建重复的引用块
if (citationBlockId) {
logger.warn('[onLLMWebSearchInProgress] Citation block already exists:', citationBlockId)
return
}
if (blockManager.hasInitialPlaceholder) {
// blockManager.lastBlockType = MessageBlockType.CITATION
logger.debug('blockManager.initialPlaceholderBlockId', blockManager.initialPlaceholderBlockId)