@@ -6,21 +6,32 @@ type StreamCallback = (chunk: string) => void
66
77const DATA_PREFIX = 'data: '
88const DONE_TOKEN = '[DONE]'
9+ const THINK_OPEN = '<think>'
10+ const THINK_CLOSE = '</think>'
911
1012async function process_stream_chunk (
1113 chunk : string ,
1214 buffer : string ,
1315 accumulated_content : string ,
1416 last_log_time : number ,
17+ think_buffer : string ,
18+ in_think_block : boolean ,
19+ think_block_ended : boolean ,
1520 on_chunk ?: StreamCallback
1621) : Promise < {
1722 updated_buffer : string
1823 updated_accumulated_content : string
1924 updated_last_log_time : number
25+ updated_think_buffer : string
26+ updated_in_think_block : boolean
27+ updated_think_block_ended : boolean
2028} > {
2129 let updated_buffer = buffer
2230 let updated_accumulated_content = accumulated_content
2331 let updated_last_log_time = last_log_time
32+ let updated_think_buffer = think_buffer
33+ let updated_in_think_block = in_think_block
34+ let updated_think_block_ended = think_block_ended
2435
2536 try {
2637 updated_buffer += chunk
@@ -41,9 +52,64 @@ async function process_stream_chunk(
4152 const new_content = json_data . choices [ 0 ] . delta . content
4253 updated_accumulated_content += new_content
4354
44- if ( on_chunk ) {
45- on_chunk ( new_content )
55+ // --- Think block handling logic ---
56+ if ( updated_think_block_ended ) {
57+ // If the first think block has already ended, stream all new content
58+ if ( on_chunk ) {
59+ on_chunk ( new_content )
60+ }
61+ } else {
62+ // We are either before, or inside, the first think block
63+ updated_think_buffer += new_content
64+
65+ if ( ! updated_in_think_block ) {
66+ // We are currently *not* in a think block (haven't seen <think> yet)
67+ const think_open_index =
68+ updated_think_buffer . indexOf ( THINK_OPEN )
69+ if ( think_open_index !== - 1 ) {
70+ // <think> tag found!
71+ updated_in_think_block = true
72+ // Stream content *before* <think>
73+ const pre_think_content = updated_think_buffer . substring (
74+ 0 ,
75+ think_open_index
76+ )
77+ if ( pre_think_content && on_chunk ) {
78+ on_chunk ( pre_think_content )
79+ }
80+ // The remaining part of updated_think_buffer now starts with <think>
81+ updated_think_buffer =
82+ updated_think_buffer . substring ( think_open_index )
83+ } else {
84+ // No <think> tag found yet, stream this content
85+ if ( on_chunk ) {
86+ on_chunk ( new_content )
87+ }
88+ }
89+ }
90+
91+ // Now, if we are in a think block (either just entered or already were)
92+ if ( updated_in_think_block ) {
93+ const think_close_index =
94+ updated_think_buffer . indexOf ( THINK_CLOSE )
95+ if ( think_close_index != - 1 ) {
96+ // </think> tag found!
97+ updated_in_think_block = false
98+ updated_think_block_ended = true
99+ // Stream content *after* </think>
100+ const post_think_content = updated_think_buffer . substring (
101+ think_close_index + THINK_CLOSE . length
102+ )
103+ if ( post_think_content && on_chunk ) {
104+ on_chunk ( post_think_content )
105+ }
106+ // Clear the think buffer as the first think block is fully processed
107+ updated_think_buffer = ''
108+ }
109+ // If </think> not found, we remain in_think_block and do not stream.
110+ }
46111 }
112+ // --- End think block handling logic ---
47113
48114 const current_time = Date . now ( )
49115 if ( current_time - updated_last_log_time >= 1000 ) {
@@ -75,7 +141,10 @@ async function process_stream_chunk(
75141 return {
76142 updated_buffer,
77143 updated_accumulated_content,
78- updated_last_log_time
144+ updated_last_log_time,
145+ updated_think_buffer,
146+ updated_in_think_block,
147+ updated_think_block_ended
79148 }
80149}
81150
@@ -92,6 +161,9 @@ export async function make_api_request(
92161 let accumulated_content = ''
93162 let last_log_time = Date . now ( )
94163 let buffer = ''
164+ let think_buffer = ''
165+ let in_think_block = false
166+ let think_block_ended = false
95167
96168 const response : AxiosResponse < NodeJS . ReadableStream > = await axios . post (
97169 endpoint_url + '/chat/completions' ,
@@ -112,7 +184,7 @@ export async function make_api_request(
112184 }
113185 )
114186
115- response . data . setEncoding ( 'utf8' )
187+ response . data . setEncoding ( 'utf8' ) ;
116188
117189 return new Promise ( ( resolve , reject ) => {
118190 response . data . on ( 'data' , async ( chunk : string ) => {
@@ -121,11 +193,17 @@ export async function make_api_request(
121193 buffer ,
122194 accumulated_content ,
123195 last_log_time ,
196+ think_buffer ,
197+ in_think_block ,
198+ think_block_ended ,
124199 on_chunk
125200 )
126201 buffer = processing_result . updated_buffer
127202 accumulated_content = processing_result . updated_accumulated_content
128203 last_log_time = processing_result . updated_last_log_time
204+ think_buffer = processing_result . updated_think_buffer
205+ in_think_block = processing_result . updated_in_think_block
206+ think_block_ended = processing_result . updated_think_block_ended
129207 } )
130208
131209 response . data . on ( 'end' , ( ) => {
@@ -192,4 +270,4 @@ export async function make_api_request(
192270 } )
193271 return null
194272 }
195- }
273+ }
0 commit comments