everydaycats commited on
Commit
a339571
·
verified ·
1 Parent(s): 5538a01

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +60 -59
app.js CHANGED
@@ -19,6 +19,7 @@ const validateRequest = (req, res, next) => {
19
  next();
20
  };
21
 
 
22
  function extractWorkerPrompt(text) {
23
  const match = text.match(/WORKER_PROMPT:\s*(.*)/s);
24
  return match ? match[1].trim() : null;
@@ -31,18 +32,23 @@ function formatContext({ hierarchyContext, scriptContext, logContext }) {
31
  return out;
32
  }
33
 
34
- // Helper to check for Consultant requests
35
  function extractPMQuestion(text) {
36
- const match = text.match(/\[ASK_PM:\s*(.*?)\]/s); // 's' flag for multiline questions
37
  return match ? match[1].trim() : null;
38
  }
39
 
 
 
 
 
 
 
 
40
  /**
41
  * 1. NEW PROJECT
42
  */
43
  app.post('/new/project', validateRequest, async (req, res) => {
44
  const { userId, projectId, description } = req.body;
45
- console.log(`[${projectId}] Init: ${description}`);
46
 
47
  try {
48
  const pmHistory = [];
@@ -75,7 +81,9 @@ app.post('/new/project', validateRequest, async (req, res) => {
75
  failureCount: 0
76
  });
77
 
78
- StateManager.queueCommand(projectId, workerResponse);
 
 
79
  res.json({ success: true, message: "Project Initialized", gddPreview: gddResponse.substring(0, 200) });
80
 
81
  } catch (err) {
@@ -85,7 +93,7 @@ app.post('/new/project', validateRequest, async (req, res) => {
85
  });
86
 
87
  /**
88
- * 2. FEEDBACK LOOP (Enhanced with Consultation Channel)
89
  */
90
  app.post('/project/feedback', async (req, res) => {
91
  const { projectId, prompt, hierarchyContext, scriptContext, logContext, taskComplete, images } = req.body;
@@ -122,13 +130,13 @@ app.post('/project/feedback', async (req, res) => {
122
  failureCount: 0
123
  });
124
 
125
- StateManager.queueCommand(projectId, "CLEAR_CONSOLE");
126
- StateManager.queueCommand(projectId, workerResponse);
127
 
128
  return res.json({ success: true, message: "Next Task Assigned" });
129
  }
130
 
131
- // B. ERROR ESCALATION
132
  let isFailure = false;
133
  if (logContext?.logs) {
134
  const errs = ["Error", "Exception", "failed", "Stack Begin", "Infinite yield"];
@@ -138,7 +146,7 @@ app.post('/project/feedback', async (req, res) => {
138
  }
139
  }
140
 
141
- // Escalation Threshold Check
142
  if (project.failureCount > 3) {
143
  console.log(`[${projectId}] 🚨 Escalating to PM...`);
144
  const pmPrompt = sysPrompts.pm_guidance_prompt.replace('{{LOGS}}', logContext?.logs);
@@ -154,8 +162,7 @@ app.post('/project/feedback', async (req, res) => {
154
  resetHistory.push({ role: 'model', parts: [{ text: workerResp }] });
155
 
156
  await StateManager.updateProject(projectId, { workerHistory: resetHistory, failureCount: 0 });
157
- StateManager.queueCommand(projectId, "CLEAR_CONSOLE");
158
- StateManager.queueCommand(projectId, workerResp);
159
  return res.json({ success: true, message: "Worker Terminated." });
160
  } else {
161
  const injection = `[PM GUIDANCE]: ${pmVerdict} \n\nApply this fix now.`;
@@ -165,63 +172,50 @@ app.post('/project/feedback', async (req, res) => {
165
  project.workerHistory.push({ role: 'model', parts: [{ text: workerResp }] });
166
 
167
  await StateManager.updateProject(projectId, { workerHistory: project.workerHistory, failureCount: 1 });
168
- await StateManager.queueCommand(projectId, workerResp);
169
  return res.json({ success: true, message: "PM Guidance Applied." });
170
  }
171
  }
172
 
173
- // C. STANDARD LOOP + CONSULTATION CHECK
174
  try {
175
  const fullInput = `USER: ${prompt || "Automatic Feedback"}` + formatContext({ hierarchyContext, scriptContext, logContext });
176
 
177
- // 1. Get Initial Worker Response
178
  let response = await AIEngine.callWorker(project.workerHistory, fullInput, images || []);
179
 
180
- // 2. CHECK FOR CONSULTATION REQUEST [ASK_PM: ...]
181
  const pmQuestion = extractPMQuestion(response);
182
-
183
  if (pmQuestion) {
184
  console.log(`[${projectId}] 🙋 Worker asking PM: "${pmQuestion}"`);
185
-
186
- // a. Ask PM
187
- // We give the PM the worker's question AND a snippet of context so PM knows why
188
- const pmConsultPrompt = `[WORKER CONSULTATION]: The Worker needs clarification:\n"${pmQuestion}"\n\nProvide a brief, technical answer to unblock them. Do not change the task scope unless necessary.`;
189
  const pmAnswer = await AIEngine.callPM(project.pmHistory, pmConsultPrompt);
190
 
191
- // Update PM history
192
  project.pmHistory.push({ role: 'user', parts: [{ text: pmConsultPrompt }] });
193
  project.pmHistory.push({ role: 'model', parts: [{ text: pmAnswer }] });
194
 
195
- // b. Feed PM Answer back to Worker immediately
196
- const injectionMsg = `[PM RESPONSE]: ${pmAnswer}\n\nProceed with this information.`;
197
 
198
- // We push the "Question" state to history so the worker remembers it asked
199
  project.workerHistory.push({ role: 'user', parts: [{ text: fullInput }] });
200
- project.workerHistory.push({ role: 'model', parts: [{ text: response }] }); // The response containing ASK_PM
201
 
202
- // Now we call worker again with the answer
203
- console.log(`[${projectId}] 🗣️ PM Answered. Resuming Worker...`);
204
  response = await AIEngine.callWorker(project.workerHistory, injectionMsg, []);
205
-
206
- // Push the answer transaction
207
  project.workerHistory.push({ role: 'user', parts: [{ text: injectionMsg }] });
208
  project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
209
-
210
  } else {
211
- // Standard flow if no question
212
  project.workerHistory.push({ role: 'user', parts: [{ text: fullInput }] });
213
  project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
214
  }
215
 
216
- // 3. Save & Queue Result
217
  await StateManager.updateProject(projectId, {
218
  workerHistory: project.workerHistory,
219
- pmHistory: project.pmHistory, // PM history might have updated if consulted
220
  failureCount: project.failureCount
221
  });
222
 
223
- // Queue whatever the FINAL response was (Code, Script read, etc.)
224
- await StateManager.queueCommand(projectId, response);
225
  res.json({ success: true });
226
 
227
  } catch (err) {
@@ -231,14 +225,12 @@ app.post('/project/feedback', async (req, res) => {
231
  });
232
 
233
  /**
234
- * 3. HUMAN OVERRIDE
235
  */
236
  app.post('/human/override', validateRequest, async (req, res) => {
237
  const { projectId, instruction, pruneHistory } = req.body;
238
  const project = await StateManager.getProject(projectId);
239
 
240
- if (!project) return res.status(404).json({ error: "Project not found" });
241
-
242
  const overrideMsg = `[SYSTEM OVERRIDE]: ${instruction}`;
243
 
244
  if (pruneHistory && project.workerHistory.length >= 2) {
@@ -251,30 +243,12 @@ app.post('/human/override', validateRequest, async (req, res) => {
251
  project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
252
 
253
  await StateManager.updateProject(projectId, { workerHistory: project.workerHistory });
254
- await StateManager.queueCommand(projectId, response);
255
- res.json({ success: true, message: "Override Executed" });
256
  });
257
 
258
  /**
259
- * 4. WORKER KILL
260
- */
261
- app.post('/worker/kill', validateRequest, async (req, res) => {
262
- const { projectId } = req.body;
263
- const rebootPrompt = "[SYSTEM]: Worker process restarted. Attempt the task again from scratch.";
264
- const response = await AIEngine.callWorker([{ role: 'user', parts: [{ text: rebootPrompt }] }], rebootPrompt, []);
265
-
266
- await StateManager.updateProject(projectId, {
267
- workerHistory: [{ role: 'user', parts: [{ text: rebootPrompt }] }],
268
- workerHistory: [{ role: 'model', parts: [{ text: response }] }],
269
- failureCount: 0
270
- });
271
-
272
- StateManager.queueCommand(projectId, response);
273
- res.json({ success: true, message: "Worker Killed & Restarted" });
274
- });
275
-
276
- /**
277
- * 5. PING
278
  */
279
  app.post('/project/ping', async (req, res) => {
280
  const { projectId } = req.body;
@@ -284,6 +258,7 @@ app.post('/project/ping', async (req, res) => {
284
  if (command.payload === "CLEAR_CONSOLE") {
285
  res.json({ action: "CLEAR_LOGS" });
286
  } else {
 
287
  res.json({
288
  action: command.type,
289
  target: command.payload,
@@ -295,6 +270,32 @@ app.post('/project/ping', async (req, res) => {
295
  }
296
  });
297
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  app.listen(PORT, () => {
299
  console.log(`AI Backend Running on ${PORT}`);
300
  });
 
19
  next();
20
  };
21
 
22
+ // --- HELPERS ---
23
  function extractWorkerPrompt(text) {
24
  const match = text.match(/WORKER_PROMPT:\s*(.*)/s);
25
  return match ? match[1].trim() : null;
 
32
  return out;
33
  }
34
 
 
35
  function extractPMQuestion(text) {
36
+ const match = text.match(/\[ASK_PM:\s*(.*?)\]/s);
37
  return match ? match[1].trim() : null;
38
  }
39
 
40
+ function extractImagePrompt(text) {
41
+ const match = text.match(/\[GENERATE_IMAGE:\s*(.*?)\]/s);
42
+ return match ? match[1].trim() : null;
43
+ }
44
+
45
+ // --- ENDPOINTS ---
46
+
47
  /**
48
  * 1. NEW PROJECT
49
  */
50
  app.post('/new/project', validateRequest, async (req, res) => {
51
  const { userId, projectId, description } = req.body;
 
52
 
53
  try {
54
  const pmHistory = [];
 
81
  failureCount: 0
82
  });
83
 
84
+ // Queue Initial Response
85
+ await processAndQueueResponse(projectId, workerResponse);
86
+
87
  res.json({ success: true, message: "Project Initialized", gddPreview: gddResponse.substring(0, 200) });
88
 
89
  } catch (err) {
 
93
  });
94
 
95
  /**
96
+ * 2. FEEDBACK LOOP
97
  */
98
  app.post('/project/feedback', async (req, res) => {
99
  const { projectId, prompt, hierarchyContext, scriptContext, logContext, taskComplete, images } = req.body;
 
130
  failureCount: 0
131
  });
132
 
133
+ StateManager.queueCommand(projectId, { type: "EXECUTE", payload: "warn('Starting Next Task')" }); // Reset console
134
+ await processAndQueueResponse(projectId, workerResponse);
135
 
136
  return res.json({ success: true, message: "Next Task Assigned" });
137
  }
138
 
139
+ // B. FAILURE DETECTION
140
  let isFailure = false;
141
  if (logContext?.logs) {
142
  const errs = ["Error", "Exception", "failed", "Stack Begin", "Infinite yield"];
 
146
  }
147
  }
148
 
149
+ // C. ESCALATION
150
  if (project.failureCount > 3) {
151
  console.log(`[${projectId}] 🚨 Escalating to PM...`);
152
  const pmPrompt = sysPrompts.pm_guidance_prompt.replace('{{LOGS}}', logContext?.logs);
 
162
  resetHistory.push({ role: 'model', parts: [{ text: workerResp }] });
163
 
164
  await StateManager.updateProject(projectId, { workerHistory: resetHistory, failureCount: 0 });
165
+ await processAndQueueResponse(projectId, workerResp);
 
166
  return res.json({ success: true, message: "Worker Terminated." });
167
  } else {
168
  const injection = `[PM GUIDANCE]: ${pmVerdict} \n\nApply this fix now.`;
 
172
  project.workerHistory.push({ role: 'model', parts: [{ text: workerResp }] });
173
 
174
  await StateManager.updateProject(projectId, { workerHistory: project.workerHistory, failureCount: 1 });
175
+ await processAndQueueResponse(projectId, workerResp);
176
  return res.json({ success: true, message: "PM Guidance Applied." });
177
  }
178
  }
179
 
180
+ // D. STANDARD WORKER FLOW
181
  try {
182
  const fullInput = `USER: ${prompt || "Automatic Feedback"}` + formatContext({ hierarchyContext, scriptContext, logContext });
183
 
 
184
  let response = await AIEngine.callWorker(project.workerHistory, fullInput, images || []);
185
 
186
+ // CHECK: PM CONSULTATION
187
  const pmQuestion = extractPMQuestion(response);
 
188
  if (pmQuestion) {
189
  console.log(`[${projectId}] 🙋 Worker asking PM: "${pmQuestion}"`);
190
+ const pmConsultPrompt = `[WORKER CONSULTATION]: The Worker asks: "${pmQuestion}"\nProvide a technical answer.`;
 
 
 
191
  const pmAnswer = await AIEngine.callPM(project.pmHistory, pmConsultPrompt);
192
 
 
193
  project.pmHistory.push({ role: 'user', parts: [{ text: pmConsultPrompt }] });
194
  project.pmHistory.push({ role: 'model', parts: [{ text: pmAnswer }] });
195
 
196
+ const injectionMsg = `[PM RESPONSE]: ${pmAnswer}`;
 
197
 
198
+ // Push question-answer to history
199
  project.workerHistory.push({ role: 'user', parts: [{ text: fullInput }] });
200
+ project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
201
 
202
+ // Resume Worker
 
203
  response = await AIEngine.callWorker(project.workerHistory, injectionMsg, []);
 
 
204
  project.workerHistory.push({ role: 'user', parts: [{ text: injectionMsg }] });
205
  project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
 
206
  } else {
 
207
  project.workerHistory.push({ role: 'user', parts: [{ text: fullInput }] });
208
  project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
209
  }
210
 
 
211
  await StateManager.updateProject(projectId, {
212
  workerHistory: project.workerHistory,
213
+ pmHistory: project.pmHistory,
214
  failureCount: project.failureCount
215
  });
216
 
217
+ // Process response for Code OR Images
218
+ await processAndQueueResponse(projectId, response);
219
  res.json({ success: true });
220
 
221
  } catch (err) {
 
225
  });
226
 
227
  /**
228
+ * HUMAN OVERRIDE
229
  */
230
  app.post('/human/override', validateRequest, async (req, res) => {
231
  const { projectId, instruction, pruneHistory } = req.body;
232
  const project = await StateManager.getProject(projectId);
233
 
 
 
234
  const overrideMsg = `[SYSTEM OVERRIDE]: ${instruction}`;
235
 
236
  if (pruneHistory && project.workerHistory.length >= 2) {
 
243
  project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
244
 
245
  await StateManager.updateProject(projectId, { workerHistory: project.workerHistory });
246
+ await processAndQueueResponse(projectId, response);
247
+ res.json({ success: true });
248
  });
249
 
250
  /**
251
+ * PING (Plugin Polling)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  */
253
  app.post('/project/ping', async (req, res) => {
254
  const { projectId } = req.body;
 
258
  if (command.payload === "CLEAR_CONSOLE") {
259
  res.json({ action: "CLEAR_LOGS" });
260
  } else {
261
+ // Can be: EXECUTE, READ_SCRIPT, READ_HIERARCHY, CREATE_ASSET
262
  res.json({
263
  action: command.type,
264
  target: command.payload,
 
270
  }
271
  });
272
 
273
+
274
+ // --- CORE LOGIC: PROCESS RESPONSE & HANDLE IMAGES ---
275
+ async function processAndQueueResponse(projectId, rawResponse) {
276
+ // 1. Check for Image Generation Tag
277
+ const imgPrompt = extractImagePrompt(rawResponse);
278
+ if (imgPrompt) {
279
+ console.log(`[${projectId}] 🎨 Generating Image for: ${imgPrompt}`);
280
+ const base64Image = await AIEngine.generateImage(imgPrompt);
281
+
282
+ if (base64Image) {
283
+ // Queue the creation command for the plugin
284
+ await StateManager.queueCommand(projectId, {
285
+ type: "CREATE_ASSET",
286
+ payload: base64Image // Plugin receives Base64
287
+ });
288
+ console.log(`[${projectId}] Image Asset Queued.`);
289
+ } else {
290
+ console.error(`[${projectId}] Image Generation Failed.`);
291
+ }
292
+ }
293
+
294
+ // 2. Queue standard commands (Code, Reads, etc.)
295
+ // We pass the RAW response to StateManager to parse code blocks
296
+ await StateManager.queueCommand(projectId, rawResponse);
297
+ }
298
+
299
  app.listen(PORT, () => {
300
  console.log(`AI Backend Running on ${PORT}`);
301
  });