1
- import { createServer , IncomingMessage } from "node:http" ;
1
+ import { createServer } from "node:http" ;
2
2
3
- import { verifyAndParseRequest , createAckEvent } from "@copilot-extensions/preview-sdk" ;
4
- import OpenAI from "openai" ;
3
+ import { prompt , getFunctionCalls , createAckEvent , createDoneEvent , verifyAndParseRequest , createTextEvent } from "@copilot-extensions/preview-sdk" ;
5
4
6
5
import { describeModel } from "./functions/describe-model.js" ;
7
6
import { executeModel } from "./functions/execute-model.js" ;
@@ -12,6 +11,7 @@ import { ModelsAPI } from "./models-api.js";
12
11
13
12
const server = createServer ( async ( request , response ) => {
14
13
if ( request . method === "GET" ) {
14
+ // health check
15
15
response . statusCode = 200 ;
16
16
response . end ( `OK` ) ;
17
17
return ;
@@ -54,15 +54,9 @@ const server = createServer(async (request, response) => {
54
54
response . write ( createAckEvent ( ) . toString ( ) ) ;
55
55
56
56
// List of functions that are available to be called
57
- const modelsAPI = new ModelsAPI ( apiKey ) ;
57
+ const modelsAPI = new ModelsAPI ( ) ;
58
58
const functions = [ listModels , describeModel , executeModel , recommendModel ] ;
59
59
60
- // Use the Copilot API to determine which function to execute
61
- const capiClient = new OpenAI ( {
62
- baseURL : "https://api.githubcopilot.com" ,
63
- apiKey,
64
- } ) ;
65
-
66
60
// Prepend a system message that includes the list of models, so that
67
61
// tool calls can better select the right model to use.
68
62
const models = await modelsAPI . listModels ( ) ;
@@ -90,56 +84,48 @@ const server = createServer(async (request, response) => {
90
84
] . concat ( payload . messages ) ;
91
85
92
86
console . time ( "tool-call" ) ;
93
- const toolCaller = await capiClient . chat . completions . create ( {
94
- stream : false ,
95
- model : "gpt-4" ,
87
+ const promptResult = await prompt ( {
96
88
messages : toolCallMessages ,
97
- tool_choice : "auto" ,
89
+ token : apiKey ,
98
90
tools : functions . map ( ( f ) => f . tool ) ,
99
- } ) ;
91
+ } )
100
92
console . timeEnd ( "tool-call" ) ;
101
93
94
+ const [ functionToCall ] = getFunctionCalls ( promptResult )
95
+
102
96
if (
103
- ! toolCaller . choices [ 0 ] ||
104
- ! toolCaller . choices [ 0 ] . message ||
105
- ! toolCaller . choices [ 0 ] . message . tool_calls ||
106
- ! toolCaller . choices [ 0 ] . message . tool_calls [ 0 ] . function
97
+ ! functionToCall
107
98
) {
108
99
console . log ( "No tool call found" ) ;
109
- // No tool to call, so just call the model with the original messages
110
- const stream = await capiClient . chat . completions . create ( {
111
- stream : true ,
112
- model : "gpt-4" ,
113
- // @ts -expect-error - TODO @gr2m - type incompatibility between @openai/api and @copilot-extensions/preview-sdk
100
+
101
+ const { stream } = await prompt . stream ( {
114
102
messages : payload . messages ,
115
- } ) ;
103
+ token : apiKey ,
104
+ } )
116
105
117
106
for await ( const chunk of stream ) {
118
- const chunkStr = "data: " + JSON . stringify ( chunk ) + "\n\n" ;
119
- response . write ( chunkStr ) ;
107
+ response . write ( new TextDecoder ( ) . decode ( chunk ) ) ;
120
108
}
121
- response . write ( "data: [DONE]\n\n" ) ;
122
- response . end ( ) ;
109
+
110
+ response . end ( createDoneEvent ( ) . toString ( ) ) ;
123
111
return ;
124
112
}
125
113
126
- const functionToCall = toolCaller . choices [ 0 ] . message . tool_calls [ 0 ] . function ;
127
- const args = JSON . parse ( functionToCall . arguments ) ;
114
+ const args = JSON . parse ( functionToCall . function . arguments ) ;
128
115
129
116
console . time ( "function-exec" ) ;
130
117
let functionCallRes : RunnerResponse ;
131
118
try {
132
- console . log ( "Executing function" , functionToCall . name ) ;
119
+ console . log ( "Executing function" , functionToCall . function . name ) ;
133
120
const funcClass = functions . find (
134
- ( f ) => f . definition . name === functionToCall . name
121
+ ( f ) => f . definition . name === functionToCall . function . name
135
122
) ;
136
123
if ( ! funcClass ) {
137
124
throw new Error ( "Unknown function" ) ;
138
125
}
139
126
140
127
console . log ( "\t with args" , args ) ;
141
128
const func = new funcClass ( modelsAPI ) ;
142
- // @ts -expect-error - TODO @gr2m - type incompatibility between @openai/api and @copilot-extensions/preview-sdk
143
129
functionCallRes = await func . execute ( payload . messages , args ) ;
144
130
} catch ( err ) {
145
131
console . error ( err ) ;
@@ -150,23 +136,20 @@ const server = createServer(async (request, response) => {
150
136
console . timeEnd ( "function-exec" ) ;
151
137
152
138
try {
153
- const stream = await modelsAPI . inference . chat . completions . create ( {
139
+ console . time ( "streaming" ) ;
140
+ const { stream } = await prompt . stream ( {
141
+ endpoint : 'https://models.inference.ai.azure.com/chat/completions' ,
154
142
model : functionCallRes . model ,
155
143
messages : functionCallRes . messages ,
156
- stream : true ,
157
- stream_options : {
158
- include_usage : false ,
159
- } ,
160
- } ) ;
144
+ token : apiKey ,
145
+ } )
161
146
162
- console . time ( "streaming" ) ;
163
147
for await ( const chunk of stream ) {
164
- const chunkStr = "data: " + JSON . stringify ( chunk ) + "\n\n" ;
165
- response . write ( chunkStr ) ;
148
+ response . write ( new TextDecoder ( ) . decode ( chunk ) ) ;
166
149
}
167
- response . write ( "data: [DONE]\n\n" ) ;
150
+
151
+ response . end ( createDoneEvent ( ) . toString ( ) ) ;
168
152
console . timeEnd ( "streaming" ) ;
169
- response . end ( ) ;
170
153
} catch ( err ) {
171
154
console . error ( err ) ;
172
155
response . statusCode = 500
@@ -178,12 +161,12 @@ const port = process.env.PORT || "3000"
178
161
server . listen ( port ) ;
179
162
console . log ( `Server running at http://localhost:${ port } ` ) ;
180
163
181
- function getBody ( request : IncomingMessage ) : Promise < string > {
164
+ function getBody ( request : any ) : Promise < string > {
182
165
return new Promise ( ( resolve ) => {
183
166
const bodyParts : any [ ] = [ ] ;
184
167
let body ;
185
168
request
186
- . on ( "data" , ( chunk ) => {
169
+ . on ( "data" , ( chunk : Buffer ) => {
187
170
bodyParts . push ( chunk ) ;
188
171
} )
189
172
. on ( "end" , ( ) => {
0 commit comments