Skip to content

Commit 4b5bb5c

Browse files
committed
Use OpenAI SDK to avoid setting apiVersion manually
1 parent c37f296 commit 4b5bb5c

File tree

7 files changed

+6521
-7021
lines changed

7 files changed

+6521
-7021
lines changed

__tests__/inference.test.ts

Lines changed: 102 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,15 @@ import {vi, type MockedFunction, beforeEach, expect, describe, it} from 'vitest'
22
import * as core from '../__fixtures__/core.js'
33

44
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5-
const mockPost = vi.fn() as MockedFunction<any>
6-
const mockPath = vi.fn(() => ({post: mockPost}))
7-
const mockClient = vi.fn(() => ({path: mockPath}))
8-
9-
vi.mock('@azure-rest/ai-inference', () => ({
10-
default: mockClient,
11-
isUnexpected: vi.fn(() => false),
5+
const mockCreate = vi.fn() as MockedFunction<any>
6+
const mockCompletions = {create: mockCreate}
7+
const mockChat = {completions: mockCompletions}
8+
const mockOpenAIClient = vi.fn(() => ({
9+
chat: mockChat,
1210
}))
1311

14-
vi.mock('@azure/core-auth', () => ({
15-
AzureKeyCredential: vi.fn(),
12+
vi.mock('openai', () => ({
13+
default: mockOpenAIClient,
1614
}))
1715

1816
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -29,8 +27,8 @@ const {simpleInference, mcpInference} = await import('../src/inference.js')
2927
describe('inference.ts', () => {
3028
const mockRequest = {
3129
messages: [
32-
{role: 'system', content: 'You are a test assistant'},
33-
{role: 'user', content: 'Hello, AI!'},
30+
{role: 'system' as const, content: 'You are a test assistant'},
31+
{role: 'user' as const, content: 'Hello, AI!'},
3432
],
3533
modelName: 'gpt-4',
3634
maxTokens: 100,
@@ -45,18 +43,16 @@ describe('inference.ts', () => {
4543
describe('simpleInference', () => {
4644
it('performs simple inference without tools', async () => {
4745
const mockResponse = {
48-
body: {
49-
choices: [
50-
{
51-
message: {
52-
content: 'Hello, user!',
53-
},
46+
choices: [
47+
{
48+
message: {
49+
content: 'Hello, user!',
5450
},
55-
],
56-
},
51+
},
52+
],
5753
}
5854

59-
mockPost.mockResolvedValue(mockResponse)
55+
mockCreate.mockResolvedValue(mockResponse)
6056

6157
const result = await simpleInference(mockRequest)
6258

@@ -65,38 +61,34 @@ describe('inference.ts', () => {
6561
expect(core.info).toHaveBeenCalledWith('Model response: Hello, user!')
6662

6763
// Verify the request structure
68-
expect(mockPost).toHaveBeenCalledWith({
69-
body: {
70-
messages: [
71-
{
72-
role: 'system',
73-
content: 'You are a test assistant',
74-
},
75-
{
76-
role: 'user',
77-
content: 'Hello, AI!',
78-
},
79-
],
80-
max_tokens: 100,
81-
model: 'gpt-4',
82-
},
64+
expect(mockCreate).toHaveBeenCalledWith({
65+
messages: [
66+
{
67+
role: 'system',
68+
content: 'You are a test assistant',
69+
},
70+
{
71+
role: 'user',
72+
content: 'Hello, AI!',
73+
},
74+
],
75+
max_tokens: 100,
76+
model: 'gpt-4',
8377
})
8478
})
8579

8680
it('handles null response content', async () => {
8781
const mockResponse = {
88-
body: {
89-
choices: [
90-
{
91-
message: {
92-
content: null,
93-
},
82+
choices: [
83+
{
84+
message: {
85+
content: null,
9486
},
95-
],
96-
},
87+
},
88+
],
9789
}
9890

99-
mockPost.mockResolvedValue(mockResponse)
91+
mockCreate.mockResolvedValue(mockResponse)
10092

10193
const result = await simpleInference(mockRequest)
10294

@@ -123,19 +115,17 @@ describe('inference.ts', () => {
123115

124116
it('performs inference without tool calls', async () => {
125117
const mockResponse = {
126-
body: {
127-
choices: [
128-
{
129-
message: {
130-
content: 'Hello, user!',
131-
tool_calls: null,
132-
},
118+
choices: [
119+
{
120+
message: {
121+
content: 'Hello, user!',
122+
tool_calls: null,
133123
},
134-
],
135-
},
124+
},
125+
],
136126
}
137127

138-
mockPost.mockResolvedValue(mockResponse)
128+
mockCreate.mockResolvedValue(mockResponse)
139129

140130
const result = await mcpInference(mockRequest, mockMcpClient)
141131

@@ -146,12 +136,12 @@ describe('inference.ts', () => {
146136

147137
// The MCP inference loop will always add the assistant message, even when there are no tool calls
148138
// So we don't check the exact messages, just that tools were included
149-
expect(mockPost).toHaveBeenCalledTimes(1)
139+
expect(mockCreate).toHaveBeenCalledTimes(1)
150140
// eslint-disable-next-line @typescript-eslint/no-explicit-any
151-
const callArgs = mockPost.mock.calls[0][0] as any
152-
expect(callArgs.body.tools).toEqual(mockMcpClient.tools)
153-
expect(callArgs.body.model).toBe('gpt-4')
154-
expect(callArgs.body.max_tokens).toBe(100)
141+
const callArgs = mockCreate.mock.calls[0][0] as any
142+
expect(callArgs.tools).toEqual(mockMcpClient.tools)
143+
expect(callArgs.model).toBe('gpt-4')
144+
expect(callArgs.max_tokens).toBe(100)
155145
})
156146

157147
it('executes tool calls and continues conversation', async () => {
@@ -176,49 +166,45 @@ describe('inference.ts', () => {
176166

177167
// First response with tool calls
178168
const firstResponse = {
179-
body: {
180-
choices: [
181-
{
182-
message: {
183-
content: 'I need to use a tool.',
184-
tool_calls: toolCalls,
185-
},
169+
choices: [
170+
{
171+
message: {
172+
content: 'I need to use a tool.',
173+
tool_calls: toolCalls,
186174
},
187-
],
188-
},
175+
},
176+
],
189177
}
190178

191179
// Second response after tool execution
192180
const secondResponse = {
193-
body: {
194-
choices: [
195-
{
196-
message: {
197-
content: 'Here is the final answer.',
198-
tool_calls: null,
199-
},
181+
choices: [
182+
{
183+
message: {
184+
content: 'Here is the final answer.',
185+
tool_calls: null,
200186
},
201-
],
202-
},
187+
},
188+
],
203189
}
204190

205-
mockPost.mockResolvedValueOnce(firstResponse).mockResolvedValueOnce(secondResponse)
191+
mockCreate.mockResolvedValueOnce(firstResponse).mockResolvedValueOnce(secondResponse)
206192

207193
mockExecuteToolCalls.mockResolvedValue(toolResults)
208194

209195
const result = await mcpInference(mockRequest, mockMcpClient)
210196

211197
expect(result).toBe('Here is the final answer.')
212198
expect(mockExecuteToolCalls).toHaveBeenCalledWith(mockMcpClient.client, toolCalls)
213-
expect(mockPost).toHaveBeenCalledTimes(2)
199+
expect(mockCreate).toHaveBeenCalledTimes(2)
214200

215201
// Verify the second call includes the conversation history
216202
// eslint-disable-next-line @typescript-eslint/no-explicit-any
217-
const secondCall = mockPost.mock.calls[1][0] as any
218-
expect(secondCall.body.messages).toHaveLength(5) // system, user, assistant, tool, assistant
219-
expect(secondCall.body.messages[2].role).toBe('assistant')
220-
expect(secondCall.body.messages[2].tool_calls).toEqual(toolCalls)
221-
expect(secondCall.body.messages[3]).toEqual(toolResults[0])
203+
const secondCall = mockCreate.mock.calls[1][0] as any
204+
expect(secondCall.messages).toHaveLength(5) // system, user, assistant, tool, assistant
205+
expect(secondCall.messages[2].role).toBe('assistant')
206+
expect(secondCall.messages[2].tool_calls).toEqual(toolCalls)
207+
expect(secondCall.messages[3]).toEqual(toolResults[0])
222208
})
223209

224210
it('handles maximum iteration limit', async () => {
@@ -243,43 +229,39 @@ describe('inference.ts', () => {
243229

244230
// Always respond with tool calls to trigger infinite loop
245231
const responseWithToolCalls = {
246-
body: {
247-
choices: [
248-
{
249-
message: {
250-
content: 'Using tool again.',
251-
tool_calls: toolCalls,
252-
},
232+
choices: [
233+
{
234+
message: {
235+
content: 'Using tool again.',
236+
tool_calls: toolCalls,
253237
},
254-
],
255-
},
238+
},
239+
],
256240
}
257241

258-
mockPost.mockResolvedValue(responseWithToolCalls)
242+
mockCreate.mockResolvedValue(responseWithToolCalls)
259243
mockExecuteToolCalls.mockResolvedValue(toolResults)
260244

261245
const result = await mcpInference(mockRequest, mockMcpClient)
262246

263-
expect(mockPost).toHaveBeenCalledTimes(5) // Max iterations reached
247+
expect(mockCreate).toHaveBeenCalledTimes(5) // Max iterations reached
264248
expect(core.warning).toHaveBeenCalledWith('GitHub MCP inference loop exceeded maximum iterations (5)')
265249
expect(result).toBe('Using tool again.') // Last assistant message
266250
})
267251

268252
it('handles empty tool calls array', async () => {
269253
const mockResponse = {
270-
body: {
271-
choices: [
272-
{
273-
message: {
274-
content: 'Hello, user!',
275-
tool_calls: [],
276-
},
254+
choices: [
255+
{
256+
message: {
257+
content: 'Hello, user!',
258+
tool_calls: [],
277259
},
278-
],
279-
},
260+
},
261+
],
280262
}
281263

282-
mockPost.mockResolvedValue(mockResponse)
264+
mockCreate.mockResolvedValue(mockResponse)
283265

284266
const result = await mcpInference(mockRequest, mockMcpClient)
285267

@@ -297,32 +279,28 @@ describe('inference.ts', () => {
297279
]
298280

299281
const firstResponse = {
300-
body: {
301-
choices: [
302-
{
303-
message: {
304-
content: 'First message',
305-
tool_calls: toolCalls,
306-
},
282+
choices: [
283+
{
284+
message: {
285+
content: 'First message',
286+
tool_calls: toolCalls,
307287
},
308-
],
309-
},
288+
},
289+
],
310290
}
311291

312292
const secondResponse = {
313-
body: {
314-
choices: [
315-
{
316-
message: {
317-
content: 'Second message',
318-
tool_calls: toolCalls,
319-
},
293+
choices: [
294+
{
295+
message: {
296+
content: 'Second message',
297+
tool_calls: toolCalls,
320298
},
321-
],
322-
},
299+
},
300+
],
323301
}
324302

325-
mockPost.mockResolvedValueOnce(firstResponse).mockResolvedValue(secondResponse)
303+
mockCreate.mockResolvedValueOnce(firstResponse).mockResolvedValue(secondResponse)
326304

327305
mockExecuteToolCalls.mockResolvedValue([
328306
{

0 commit comments

Comments
 (0)