@@ -99,16 +99,87 @@ export const transformOpenAIStream = (
9999 if ( item . finish_reason ) {
100100 // one-api 的流式接口,会出现既有 finish_reason ,也有 content 的情况
101101 // {"id":"demo","model":"deepl-en","choices":[{"index":0,"delta":{"role":"assistant","content":"Introduce yourself."},"finish_reason":"stop" }] }
102-
103102 if ( typeof item . delta ?. content === 'string' && ! ! item . delta . content ) {
103+ // MiniMax 内建搜索功能会在第一个 tools 流中 content 返回引用源,需要忽略
104+ // {"id":"0483748a25071c611e2f48d2982fbe96","choices":[{"finish_reason":"stop","index":0,"delta":{"content":"[{\"no\":1,\"url\":\"https://www.xiaohongshu.com/discovery/item/66d8de3c000000001f01e752\",\"title\":\"郑钦文为国而战,没有理由不坚持🏅\",\"content\":\"·2024年08月03日\\n中国队选手郑钦文夺得巴黎奥运会网球女单比赛金牌(巴黎奥运第16金)\\n#巴黎奥运会[话题]# #郑钦文[话题]# #人物素材积累[话题]# #作文素材积累[话题]# #申论素材[话题]#\",\"web_icon\":\"https://www.xiaohongshu.com/favicon.ico\"}]","role":"tool","tool_call_id":"call_function_6696730535" }}],"created":1748255114,"model":"abab6.5s-chat","object":"chat.completion.chunk","usage":{"total_tokens":0,"total_characters":0},"input_sensitive":false,"output_sensitive":false,"input_sensitive_type":0,"output_sensitive_type":0,"output_sensitive_int":0 }
105+ if ( typeof item . delta ?. role === 'string' && item . delta . role === 'tool' ) {
106+ return { data : null , id : chunk . id , type : 'text' } ;
107+ }
108+
104109 return { data : item . delta . content , id : chunk . id , type : 'text' } ;
105110 }
106111
112+ // OpenAI Search Preview 模型返回引用源
113+ // {"id":"chatcmpl-18037d13-243c-4941-8b05-9530b352cf17","object":"chat.completion.chunk","created":1748351805,"model":"gpt-4o-mini-search-preview-2025-03-11","choices":[{"index":0,"delta":{"annotations":[{"type":"url_citation","url_citation":{"url":"https://zh.wikipedia.org/wiki/%E4%B8%8A%E6%B5%B7%E4%B9%90%E9%AB%98%E4%B9%90%E5%9B%AD?utm_source=openai","title":"上海乐高乐园","start_index":75,"end_index":199}}] },"finish_reason":"stop" }],"service_tier":"default" }
114+ if ( ( item as any ) . delta ?. annotations && ( item as any ) . delta . annotations . length > 0 ) {
115+ const citations = ( item as any ) . delta . annotations ;
116+
117+ return [
118+ {
119+ data : {
120+ citations : citations . map (
121+ ( item : any ) =>
122+ ( {
123+ title : item . url_citation . title ,
124+ url : item . url_citation . url ,
125+ } ) as CitationItem ,
126+ ) ,
127+ } ,
128+ id : chunk . id ,
129+ type : 'grounding' ,
130+ } ,
131+ ] ;
132+ }
133+
134+ // MiniMax 内建搜索功能会在最后一个流中的 message 数组中返回 4 个 Object,其中最后一个为 annotations
135+ // {"id":"0483bf14ba55225a66de2342a21b4003","choices":[{"finish_reason":"tool_calls","index":0,"messages":[{"content":"","role":"user","reasoning_content":""},{"content":"","role":"assistant","tool_calls":[{"id":"call_function_0872338692","type":"web_search","function":{"name":"get_search_result","arguments":"{\"query_tag\":[\"天气\"],\"query_list\":[\"上海 2025年5月26日 天气\"]}"}}],"reasoning_content":""},{"content":"","role":"tool","tool_call_id":"call_function_0872338692","reasoning_content":""},{"content":"","role":"assistant","name":"海螺AI","annotations":[{"text":"【5†source】","url":"https://mtianqi.eastday.com/tianqi/shanghai/20250526.html","quote":"上海天气预报提供上海2025年05月26日天气"}],"audio_content":"","reasoning_content":""}] }],"created":1748274196,"model":"MiniMax-Text-01","object":"chat.completion","usage":{"total_tokens":13110,"total_characters":0,"prompt_tokens":12938,"completion_tokens":172},"base_resp":{"status_code":0,"status_msg":"Invalid parameters detected, json: unknown field \"user\""} }
136+ if ( ( item as any ) . messages && ( item as any ) . messages . length > 0 ) {
137+ const citations = ( item as any ) . messages . at ( - 1 ) . annotations ;
138+
139+ return [
140+ {
141+ data : {
142+ citations : citations . map (
143+ ( item : any ) =>
144+ ( {
145+ title : item . url ,
146+ url : item . url ,
147+ } ) as CitationItem ,
148+ ) ,
149+ } ,
150+ id : chunk . id ,
151+ type : 'grounding' ,
152+ } ,
153+ ] ;
154+ }
155+
107156 if ( chunk . usage ) {
108157 const usage = chunk . usage ;
109158 return { data : convertUsage ( usage ) , id : chunk . id , type : 'usage' } ;
110159 }
111160
161+ // xAI Live Search 功能返回引用源
162+ // {"id":"8721eebb-6465-4c47-ba2e-8e2ec0f97055","object":"chat.completion.chunk","created":1747809109,"model":"grok-3","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":"stop" }],"system_fingerprint":"fp_1affcf9872","citations":["https://world.huanqiu.com/"] }
163+ if ( ( chunk as any ) . citations ) {
164+ const citations = ( chunk as any ) . citations ;
165+
166+ return [
167+ {
168+ data : {
169+ citations : citations . map (
170+ ( item : any ) =>
171+ ( {
172+ title : item ,
173+ url : item ,
174+ } ) as CitationItem ,
175+ ) ,
176+ } ,
177+ id : chunk . id ,
178+ type : 'grounding' ,
179+ } ,
180+ ] ;
181+ }
182+
112183 return { data : item . finish_reason , id : chunk . id , type : 'stop' } ;
113184 }
114185
@@ -146,21 +217,20 @@ export const transformOpenAIStream = (
146217 // in Hunyuan api, the citation is in every chunk
147218 ( 'search_info' in chunk && ( chunk . search_info as any ) ?. search_results ) ||
148219 // in Wenxin api, the citation is in the first and last chunk
149- ( 'search_results' in chunk && chunk . search_results ) ;
220+ ( 'search_results' in chunk && chunk . search_results ) ||
221+ // in Zhipu api, the citation is in the first chunk
222+ ( 'web_search' in chunk && chunk . web_search ) ;
150223
151224 if ( citations ) {
152225 streamContext . returnedCitation = true ;
153226
154227 return [
155228 {
156229 data : {
157- citations : ( citations as any [ ] ) . map (
158- ( item ) =>
159- ( {
160- title : typeof item === 'string' ? item : item . title ,
161- url : typeof item === 'string' ? item : item . url ,
162- } ) as CitationItem ,
163- ) ,
230+ citations : ( citations as any [ ] ) . map ( ( item ) => ( {
231+ title : typeof item === 'string' ? item : item . title ,
232+ url : typeof item === 'string' ? item : item . url || item . link ,
233+ } ) ) . filter ( c => c . title && c . url ) , // Zhipu 内建搜索工具有时会返回空 link 引发程序崩溃
164234 } ,
165235 id : chunk . id ,
166236 type : 'grounding' ,
0 commit comments