1
1
import OpenAI , { AzureOpenAI } from 'openai' ;
2
2
import { Message , ToolCall } from '@agent-infra/shared' ;
3
- import { ChatCompletionTool } from 'openai/resources' ;
3
+ import { ChatCompletionChunk , ChatCompletionTool } from 'openai/resources' ;
4
4
5
5
import { BaseProvider } from './BaseProvider' ;
6
6
import { LLMConfig , LLMResponse , ToolChoice } from '../interfaces/LLMProvider' ;
@@ -111,6 +111,7 @@ export class AzureOpenAIProvider extends BaseProvider {
111
111
{
112
112
model : this . model ,
113
113
messages : formattedMessages ,
114
+ stream : true ,
114
115
temperature : this . config . temperature ,
115
116
max_tokens : this . config . maxTokens ,
116
117
top_p : this . config . topP ,
@@ -126,7 +127,21 @@ export class AzureOpenAIProvider extends BaseProvider {
126
127
throw new Error ( 'Request aborted' ) ;
127
128
}
128
129
this . cleanupRequest ( requestId ) ;
129
- return response . choices [ 0 ] . message . content || '' ;
130
+
131
+ let content = '' ;
132
+ for await ( const event of response ) {
133
+ if ( event . choices [ 0 ] . finish_reason ) {
134
+ break ;
135
+ }
136
+ const token =
137
+ event . choices [ 0 ] . delta . content ||
138
+ // @ts -ignore
139
+ event . choices [ 0 ] . delta ?. reasoning_content ||
140
+ '' ;
141
+ content += token ;
142
+ }
143
+
144
+ return content || '' ;
130
145
} catch ( error : any ) {
131
146
this . cleanupRequest ( requestId ) ;
132
147
if ( error . name === 'AbortError' || error . message . includes ( 'aborted' ) ) {
@@ -161,6 +176,7 @@ export class AzureOpenAIProvider extends BaseProvider {
161
176
messages : formattedMessages ,
162
177
temperature : this . config . temperature ,
163
178
max_tokens : this . config . maxTokens ,
179
+ stream : true ,
164
180
tools,
165
181
tool_choice : toolChoice ,
166
182
top_p : this . config . topP ,
@@ -177,9 +193,76 @@ export class AzureOpenAIProvider extends BaseProvider {
177
193
}
178
194
179
195
this . cleanupRequest ( requestId ) ;
180
- const content = response . choices [ 0 ] . message . content ;
181
- const toolCalls = this . processToolCalls ( response ) ;
182
- return { content, tool_calls : toolCalls } ;
196
+
197
+ let fullContent = '' ;
198
+ const toolCallsMap = new Map <
199
+ number ,
200
+ {
201
+ id : string ;
202
+ type : string ;
203
+ function : {
204
+ name : string ;
205
+ arguments : string ;
206
+ } ;
207
+ }
208
+ > ( ) ;
209
+
210
+ for await ( const chunk of response ) {
211
+ console . log ( 'chunk' , JSON . stringify ( chunk ) ) ;
212
+ const delta = chunk . choices [ 0 ] ?. delta ;
213
+
214
+ if ( delta ?. content ) {
215
+ // @ts -ignore
216
+ fullContent += delta . content || delta ?. reasoning_content ;
217
+ }
218
+
219
+ if ( delta ?. tool_calls ) {
220
+ for ( const toolCall of delta . tool_calls ) {
221
+ const index = toolCall . index ;
222
+ const existing = toolCallsMap . get ( index ) || {
223
+ id : '' ,
224
+ type : 'function' ,
225
+ function : {
226
+ name : '' ,
227
+ arguments : '' ,
228
+ } ,
229
+ } ;
230
+
231
+ if ( toolCall . id ) {
232
+ existing . id = toolCall . id ;
233
+ }
234
+
235
+ if ( toolCall . function ?. name ) {
236
+ existing . function . name += toolCall . function . name ;
237
+ }
238
+
239
+ if ( toolCall . function ?. arguments ) {
240
+ existing . function . arguments += toolCall . function . arguments ;
241
+ }
242
+
243
+ toolCallsMap . set ( index , existing ) ;
244
+ }
245
+ }
246
+ }
247
+
248
+ const tool_calls = Array . from ( toolCallsMap . values ( ) ) ;
249
+
250
+ const simulatedResponse : OpenAI . Chat . ChatCompletion = {
251
+ choices : [
252
+ {
253
+ message : {
254
+ content : fullContent ,
255
+ // @ts -ignore
256
+ tool_calls : tool_calls . length > 0 ? tool_calls : [ ] ,
257
+ } ,
258
+ finish_reason : tool_calls . length > 0 ? 'tool_calls' : 'stop' ,
259
+ } ,
260
+ ] ,
261
+ } ;
262
+
263
+ const toolCalls = this . processToolCalls ( simulatedResponse ) ;
264
+ console . log ( 'toolCalls' , toolCalls ) ;
265
+ return { content : fullContent , tool_calls : toolCalls } ;
183
266
} catch ( error : any ) {
184
267
this . cleanupRequest ( requestId ) ;
185
268
if ( error . name === 'AbortError' || error . message . includes ( 'aborted' ) ) {
0 commit comments