1- import OpenAI from " openai" ;
2- import dotenv from " dotenv" ;
3- import fetch from " node-fetch" ;
1+ import OpenAI from ' openai' ;
2+ import dotenv from ' dotenv' ;
3+ import fetch from ' node-fetch' ;
44
55dotenv . config ( ) ;
6- const client = new OpenAI ( { apiKey : process . env . OPENAI_API_KEY } ) ;
6+ //const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
7+
8+ // Construct the OpenAI client lazily so that the server does not shut down completely when we build the container
9+ let client = null ;
10+
11+ function getClient ( ) {
12+ if ( ! client ) {
13+ const apiKey = process . env . OPENAI_API_KEY ;
14+ if ( ! apiKey ) {
15+ throw new Error ( 'Missing OPENAI_API_KEY - cannot run Wizard Agent' ) ;
16+ }
17+ client = new OpenAI ( { apiKey } ) ;
18+ }
19+ return client ;
20+ }
721
822// Helper: call MCP routes dynamically, with error handling
923async function callMCPTool ( tool , input , cookie ) {
1024 try {
1125 const response = await fetch ( `http://localhost:3000/mcp/v1/${ tool } ` , {
12- method : " POST" ,
26+ method : ' POST' ,
1327 headers : {
1428 "Content-Type" : "application/json" ,
1529 "Cookie" : cookie || ( process . env . MCP_SESSION_TOKEN ? `mcp_session=${ process . env . MCP_SESSION_TOKEN } ` : "" ) ,
@@ -18,8 +32,8 @@ async function callMCPTool(tool, input, cookie) {
1832 } ) ;
1933 return await response . json ( ) ;
2034 } catch ( err ) {
21- console . warn ( " ⚠️ MCP call failed:" , err . message || err ) ;
22- return { error : " MCP server unreachable" } ;
35+ console . warn ( ' ⚠️ MCP call failed:' , err . message || err ) ;
36+ return { error : ' MCP server unreachable' } ;
2337 }
2438}
2539
@@ -59,16 +73,18 @@ export async function runWizardAgent(userPrompt) {
5973 Never invent new template names. If unsure, default to "node_app".
6074 ` ;
6175
76+ const client = getClient ( ) ;
77+
6278 const completion = await client . chat . completions . create ( {
63- model : " gpt-4o-mini" ,
79+ model : ' gpt-4o-mini' ,
6480 messages : [
6581 { role : "system" , content : systemPrompt } ,
6682 { role : "user" , content : typeof userPrompt === "string" ? userPrompt : userPrompt . prompt } ,
6783 ] ,
6884 } ) ;
6985
7086 const decision = completion . choices [ 0 ] . message . content ;
71- console . log ( " \n🤖 Agent decided:" , decision ) ;
87+ console . log ( ' \n🤖 Agent decided:' , decision ) ;
7288
7389 let agentMeta = {
7490 agent_decision : decision ,
@@ -117,7 +133,7 @@ export async function runWizardAgent(userPrompt) {
117133 if ( usernameMatch ) payload . username = usernameMatch [ 1 ] ;
118134 if ( userIdMatch ) payload . user_id = userIdMatch [ 1 ] ;
119135 if ( repoMatch ) {
120- const [ username , repo ] = repoMatch [ 1 ] . split ( "/" ) ;
136+ const [ username , repo ] = repoMatch [ 1 ] . split ( '/' ) ;
121137 payload . username = username ;
122138 payload . repo = `${ username } /${ repo } ` ;
123139 }
@@ -132,12 +148,13 @@ export async function runWizardAgent(userPrompt) {
132148 } ;
133149 }
134150
135- if ( toolName === " pipeline_generator" ) {
151+ if ( toolName === ' pipeline_generator' ) {
136152 if ( ! repo ) {
137- console . warn ( "⚠️ Missing repo context for pipeline generation." ) ;
138- return {
139- success : false ,
140- error : "I couldn’t determine which repository you meant. Please specify it, e.g., 'generate pipeline for user/repo'."
153+ console . warn ( '⚠️ Missing repo context for pipeline generation.' ) ;
154+ return {
155+ success : false ,
156+ error :
157+ "I couldn’t determine which repository you meant. Please specify it, e.g., 'generate pipeline for user/repo'." ,
141158 } ;
142159 }
143160
@@ -154,29 +171,42 @@ export async function runWizardAgent(userPrompt) {
154171 console . log ( `📦 Retrieved repo info from GitHub:` , repoInfo ) ;
155172 }
156173 } catch ( err ) {
157- console . warn ( "⚠️ Failed to fetch GitHub info before pipeline generation:" , err . message ) ;
174+ console . warn (
175+ '⚠️ Failed to fetch GitHub info before pipeline generation:' ,
176+ err . message
177+ ) ;
158178 }
159179
160180 // Merge language or visibility into payload if available
161- if ( repoInfo ?. language && ! payload . language ) payload . language = repoInfo . language . toLowerCase ( ) ;
162- if ( repoInfo ?. visibility && ! payload . visibility ) payload . visibility = repoInfo . visibility ;
181+ if ( repoInfo ?. language && ! payload . language )
182+ payload . language = repoInfo . language . toLowerCase ( ) ;
183+ if ( repoInfo ?. visibility && ! payload . visibility )
184+ payload . visibility = repoInfo . visibility ;
163185
164186 // Infer template if still missing
165187 if ( ! payload . template ) {
166- if ( repoInfo ?. language ?. toLowerCase ( ) . includes ( "javascript" ) || repoInfo ?. language ?. toLowerCase ( ) . includes ( "typescript" ) || / j s | t s | n o d e | j a v a s c r i p t / i. test ( repo ) ) {
167- payload . template = "node_app" ;
168- } else if ( repoInfo ?. language ?. toLowerCase ( ) . includes ( "python" ) || / p y | f l a s k | d j a n g o / i. test ( repo ) ) {
169- payload . template = "python_app" ;
188+ if (
189+ repoInfo ?. language ?. toLowerCase ( ) . includes ( 'javascript' ) ||
190+ repoInfo ?. language ?. toLowerCase ( ) . includes ( 'typescript' ) ||
191+ / j s | t s | n o d e | j a v a s c r i p t / i. test ( repo )
192+ ) {
193+ payload . template = 'node_app' ;
194+ } else if (
195+ repoInfo ?. language ?. toLowerCase ( ) . includes ( 'python' ) ||
196+ / p y | f l a s k | d j a n g o / i. test ( repo )
197+ ) {
198+ payload . template = 'python_app' ;
170199 } else {
171- payload . template = " container_service" ;
200+ payload . template = ' container_service' ;
172201 }
173202 console . log ( `🪄 Inferred template: ${ payload . template } ` ) ;
174203 }
175204
176205 // --- Auto-correct short template names ---
177- if ( payload . template === "node" ) payload . template = "node_app" ;
178- if ( payload . template === "python" ) payload . template = "python_app" ;
179- if ( payload . template === "container" ) payload . template = "container_service" ;
206+ if ( payload . template === 'node' ) payload . template = 'node_app' ;
207+ if ( payload . template === 'python' ) payload . template = 'python_app' ;
208+ if ( payload . template === 'container' )
209+ payload . template = 'container_service' ;
180210
181211 // --- Validate template against allowed values ---
182212 const allowedTemplates = [ "node_app" , "python_app" , "container_service" ] ;
@@ -193,9 +223,13 @@ export async function runWizardAgent(userPrompt) {
193223 }
194224
195225 // ✅ Ensure provider is valid before sending payload
196- if ( ! payload . provider || ! [ "aws" , "jenkins" ] . includes ( payload . provider ) ) {
226+ if (
227+ ! payload . provider ||
228+ ! [ 'aws' , 'jenkins' ] . includes ( payload . provider )
229+ ) {
197230 // Infer from repo visibility or fallback to AWS
198- payload . provider = repoInfo ?. visibility === "private" ? "jenkins" : "aws" ;
231+ payload . provider =
232+ repoInfo ?. visibility === 'private' ? 'jenkins' : 'aws' ;
199233 console . log ( `🧭 Inferred provider: ${ payload . provider } ` ) ;
200234 }
201235
@@ -298,7 +332,7 @@ export async function runWizardAgent(userPrompt) {
298332 } ;
299333 }
300334
301- if ( toolName === " oidc_adapter" ) {
335+ if ( toolName === ' oidc_adapter' ) {
302336 const payload = provider ? { provider } : { } ;
303337 agentMeta . tool_called = "oidc_adapter" ;
304338 const output = await callMCPTool ( "oidc_adapter" , payload , cookie ) ;
@@ -310,7 +344,7 @@ export async function runWizardAgent(userPrompt) {
310344 } ;
311345 }
312346
313- if ( toolName === " github_adapter" ) {
347+ if ( toolName === ' github_adapter' ) {
314348 if ( repo ) {
315349 agentMeta . tool_called = "github_adapter" ;
316350 const output = await callMCPTool ( "github/info" , { repo } , cookie ) ;
@@ -321,10 +355,11 @@ export async function runWizardAgent(userPrompt) {
321355 tool_output : output
322356 } ;
323357 } else {
324- console . warn ( "⚠️ Missing repo for GitHub info retrieval." ) ;
325- return {
326- success : false ,
327- error : "Couldn’t determine which repository to fetch. Please include it in your request (e.g., 'tell me about user/repo')."
358+ console . warn ( '⚠️ Missing repo for GitHub info retrieval.' ) ;
359+ return {
360+ success : false ,
361+ error :
362+ "Couldn’t determine which repository to fetch. Please include it in your request (e.g., 'tell me about user/repo')." ,
328363 } ;
329364 }
330365 }
@@ -341,10 +376,10 @@ export async function runWizardAgent(userPrompt) {
341376
342377// Example local test (can comment out for production)
343378if ( process . argv [ 2 ] ) {
344- const input = process . argv . slice ( 2 ) . join ( " " ) ;
379+ const input = process . argv . slice ( 2 ) . join ( ' ' ) ;
345380 runWizardAgent ( input )
346381 . then ( ( res ) => {
347- console . log ( " \n📦 Tool Output:\n" , JSON . stringify ( res , null , 2 ) ) ;
382+ console . log ( ' \n📦 Tool Output:\n' , JSON . stringify ( res , null , 2 ) ) ;
348383 } )
349384 . catch ( console . error ) ;
350- }
385+ }
0 commit comments