1- import express from "express" ;
1+ import { createServer , IncomingMessage } from "node:http" ;
2+
3+ import { verifyAndParseRequest } from "@copilot-extensions/preview-sdk" ;
24import OpenAI from "openai" ;
3- import { verifySignatureMiddleware } from "./validate-signature.js" ;
5+
46import { describeModel } from "./functions/describe-model.js" ;
57import { executeModel } from "./functions/execute-model.js" ;
68import { listModels } from "./functions/list-models.js" ;
79import { RunnerResponse } from "./functions.js" ;
810import { recommendModel } from "./functions/recommend-model.js" ;
911import { ModelsAPI } from "./models-api.js" ;
10- const app = express ( ) ;
1112
12- app . post ( "/" , verifySignatureMiddleware , express . json ( ) , async ( req , res ) => {
13+ const server = createServer ( async ( request , response ) => {
14+ if ( request . method === "GET" ) {
15+ response . statusCode = 200 ;
16+ response . end ( `OK` ) ;
17+ return ;
18+ }
19+
20+ const body = await getBody ( request ) ;
21+
22+ let verifyAndParseRequestResult : Awaited < ReturnType < typeof verifyAndParseRequest > > ;
23+ const apiKey = request . headers [ "x-github-token" ] as string ;
24+ try {
25+ const signature = request . headers [ "github-public-key-signature" ] as string ;
26+ const keyID = request . headers [ "github-public-key-identifier" ] as string ;
27+ verifyAndParseRequestResult = await verifyAndParseRequest ( body , signature , keyID , {
28+ token : apiKey ,
29+ } ) ;
30+ } catch ( err ) {
31+ console . error ( err ) ;
32+ response . statusCode = 401
33+ response . end ( "Unauthorized" ) ;
34+ return
35+ }
36+
37+ const { isValidRequest, payload } = verifyAndParseRequestResult
38+
39+ if ( ! isValidRequest ) {
40+ console . log ( "Signature verification failed" ) ;
41+ response . statusCode = 401
42+ response . end ( "Unauthorized" ) ;
43+ }
44+
45+ console . log ( "Signature verified" ) ;
46+
1347 // Use the GitHub API token sent in the request
14- const apiKey = req . get ( "X-GitHub-Token" ) ;
1548 if ( ! apiKey ) {
16- res . status ( 400 ) . end ( ) ;
49+ response . statusCode = 400
50+ response . end ( )
1751 return ;
1852 }
1953
@@ -50,8 +84,8 @@ app.post("/", verifySignatureMiddleware, express.json(), async (req, res) => {
5084 "<-- END OF LIST OF MODELS -->" ,
5185 ] . join ( "\n" ) ,
5286 } ,
53- ...req . body . messages ,
54- ] . concat ( req . body . messages ) ;
87+ ...payload . messages ,
88+ ] . concat ( payload . messages ) ;
5589
5690 console . time ( "tool-call" ) ;
5791 const toolCaller = await capiClient . chat . completions . create ( {
@@ -74,15 +108,16 @@ app.post("/", verifySignatureMiddleware, express.json(), async (req, res) => {
74108 const stream = await capiClient . chat . completions . create ( {
75109 stream : true ,
76110 model : "gpt-4" ,
77- messages : req . body . messages ,
111+ // @ts -expect-error - TODO @gr2m - type incompatibility between @openai/api and @copilot-extensions/preview-sdk
112+ messages : payload . messages ,
78113 } ) ;
79114
80115 for await ( const chunk of stream ) {
81116 const chunkStr = "data: " + JSON . stringify ( chunk ) + "\n\n" ;
82- res . write ( chunkStr ) ;
117+ response . write ( chunkStr ) ;
83118 }
84- res . write ( "data: [DONE]\n\n" ) ;
85- res . end ( ) ;
119+ response . write ( "data: [DONE]\n\n" ) ;
120+ response . end ( ) ;
86121 return ;
87122 }
88123
@@ -102,10 +137,12 @@ app.post("/", verifySignatureMiddleware, express.json(), async (req, res) => {
102137
103138 console . log ( "\t with args" , args ) ;
104139 const func = new funcClass ( modelsAPI ) ;
105- functionCallRes = await func . execute ( req . body . messages , args ) ;
140+ // @ts -expect-error - TODO @gr2m - type incompatibility between @openai/api and @copilot-extensions/preview-sdk
141+ functionCallRes = await func . execute ( payload . messages , args ) ;
106142 } catch ( err ) {
107143 console . error ( err ) ;
108- res . status ( 500 ) . end ( ) ;
144+ response . statusCode = 500
145+ response . end ( ) ;
109146 return ;
110147 }
111148 console . timeEnd ( "function-exec" ) ;
@@ -123,23 +160,33 @@ app.post("/", verifySignatureMiddleware, express.json(), async (req, res) => {
123160 console . time ( "streaming" ) ;
124161 for await ( const chunk of stream ) {
125162 const chunkStr = "data: " + JSON . stringify ( chunk ) + "\n\n" ;
126- res . write ( chunkStr ) ;
163+ response . write ( chunkStr ) ;
127164 }
128- res . write ( "data: [DONE]\n\n" ) ;
165+ response . write ( "data: [DONE]\n\n" ) ;
129166 console . timeEnd ( "streaming" ) ;
130- res . end ( ) ;
167+ response . end ( ) ;
131168 } catch ( err ) {
132169 console . error ( err ) ;
133- res . status ( 500 ) . end ( ) ;
170+ response . statusCode = 500
171+ response . end ( )
134172 }
135173} ) ;
136174
137- // Health check
138- app . get ( "/" , ( req , res ) => {
139- res . send ( "OK" ) ;
140- } ) ;
175+ const port = process . env . PORT || "3000"
176+ server . listen ( port ) ;
177+ console . log ( `Server running at http://localhost:${ port } ` ) ;
141178
142- const port = Number ( process . env . PORT || "3000" ) ;
143- app . listen ( port , ( ) => {
144- console . log ( `Server is running on http://localhost:${ port } ` ) ;
145- } ) ;
179+ function getBody ( request : IncomingMessage ) : Promise < string > {
180+ return new Promise ( ( resolve ) => {
181+ const bodyParts : any [ ] = [ ] ;
182+ let body ;
183+ request
184+ . on ( "data" , ( chunk ) => {
185+ bodyParts . push ( chunk ) ;
186+ } )
187+ . on ( "end" , ( ) => {
188+ body = Buffer . concat ( bodyParts ) . toString ( ) ;
189+ resolve ( body ) ;
190+ } ) ;
191+ } ) ;
192+ }
0 commit comments