everydaytok commited on
Commit
bf29c52
·
verified ·
1 Parent(s): 7123358

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +80 -78
app.js CHANGED
@@ -1,4 +1,3 @@
1
-
2
  // App.js
3
 
4
  import express from 'express';
@@ -82,9 +81,9 @@ async function deductUserCredits(userId, amount, type = 'basic') {
82
  const current = current_credits || 0;
83
  return Math.max(0, current - amount);
84
  });
85
- console.log(` Deducted ${amount} ${type} credits from User ${userId}`);
86
  } catch (err) {
87
- console.error(` Failed to deduct ${amount} ${type} from ${userId}:`, err);
88
  }
89
  }
90
 
@@ -101,33 +100,36 @@ const validateRequest = (req, res, next) => {
101
  next();
102
  };
103
 
104
- // --- REGEX HELPERS ---
105
  function extractWorkerPrompt(text) {
106
  const match = text.match(/WORKER_PROMPT:\s*(.*)/s);
107
- return match ? match.trim() : null;
108
  }
109
 
110
  function formatContext({ hierarchyContext, scriptContext, logContext }) {
111
  let out = "";
112
- if (scriptContext) out += `\n: ${scriptContext.targetName}\n: ${scriptContext.scriptSource}`;
113
- if (logContext) out += `\n: ${logContext.logs}`;
114
- if (hierarchyContext) out += `\n: ${hierarchyContext}`;
115
  return out;
116
  }
117
 
118
  function extractPMQuestion(text) {
119
- const match = text.match(/\/s);
120
- return match ? match.trim() : null;
 
121
  }
122
 
123
  function extractImagePrompt(text) {
124
- const match = text.match(/\/s);
125
- return match ? match.trim() : null;
 
126
  }
127
 
128
  function extractRouteToPM(text) {
129
- const match = text.match(/\/s);
130
- return match ? match.trim() : null;
 
131
  }
132
 
133
  // --- ADMIN ENDPOINTS ---
@@ -148,7 +150,7 @@ app.post('/onboarding/analyze', validateRequest, async (req, res) => {
148
 
149
  try {
150
  await checkMinimumCredits(userId, 'basic');
151
- console.log(` Analyzing idea...`);
152
 
153
  const result = await AIEngine.generateEntryQuestions(description);
154
  const usage = result.usage?.totalTokenCount || 0;
@@ -182,7 +184,7 @@ app.post('/onboarding/create', validateRequest, async (req, res) => {
182
  const randomHex = (n = 6) => crypto.randomBytes(Math.ceil(n/2)).toString("hex").slice(0, n);
183
  const projectId = `proj_${Date.now()}_${randomHex(7)}`;
184
 
185
- console.log(` Grading Project ${projectId}...`);
186
 
187
  const gradingResult = await AIEngine.gradeProject(description, answers);
188
  basicTokens += (gradingResult.usage?.totalTokenCount || 0);
@@ -203,9 +205,9 @@ app.post('/onboarding/create', validateRequest, async (req, res) => {
203
  thumbnail: thumbnailUrl,
204
  createdAt: Date.now(),
205
  status: "Idle",
206
- workerHistory:[],
207
  pmHistory: [],
208
- commandQueue:[],
209
  failureCount: 0
210
  };
211
  await StateManager.updateProject(projectId, memoryObject);
@@ -215,14 +217,14 @@ app.post('/onboarding/create', validateRequest, async (req, res) => {
215
  await firestore.collection('projects').doc(projectId).set({
216
  id: projectId,
217
  userId: userId,
218
- assets: thumbnailUrl ? :[],
219
  createdAt: admin.firestore.FieldValue.serverTimestamp()
220
  });
221
  }
222
 
223
  if (db && !isFailure) {
224
  const updates = {};
225
- updates = {
226
  id: projectId,
227
  userId,
228
  title: gradingResult.title || "Untitled",
@@ -232,11 +234,11 @@ app.post('/onboarding/create', validateRequest, async (req, res) => {
232
  createdAt: Date.now(),
233
  status: "Idle"
234
  };
235
- if (thumbnailUrl) updates = { url: thumbnailUrl };
236
- updates = {
237
  workerHistory: [],
238
- pmHistory:[],
239
- commandQueue:[],
240
  failureCount: 0
241
  };
242
  await db.ref().update(updates);
@@ -265,13 +267,13 @@ app.post('/onboarding/create', validateRequest, async (req, res) => {
265
  // --- CORE ENDPOINTS ---
266
 
267
  async function runBackgroundInitialization(projectId, userId, description) {
268
- console.log(` Starting initialization for ${projectId}`);
269
 
270
  let diamondUsage = 0;
271
  let basicUsage = 0;
272
 
273
  try {
274
- const pmHistory =[];
275
 
276
  // 1. Generate GDD (PM -> Diamond)
277
  const gddPrompt = `Create a comprehensive GDD for: ${description}`;
@@ -280,8 +282,8 @@ async function runBackgroundInitialization(projectId, userId, description) {
280
  diamondUsage += (gddResult.usage?.totalTokenCount || 0);
281
  const gddText = gddResult.text;
282
 
283
- pmHistory.push({ role: 'user', parts: });
284
- pmHistory.push({ role: 'model', parts: });
285
 
286
  // 2. Generate First Task (PM -> Diamond)
287
  const taskPrompt = "Based on the GDD, generate the first technical milestone.\nOutput format:\nTASK_NAME: <Name>\nWORKER_PROMPT: <Specific, isolated instructions for the worker>";
@@ -290,21 +292,21 @@ async function runBackgroundInitialization(projectId, userId, description) {
290
  diamondUsage += (taskResult.usage?.totalTokenCount || 0);
291
  const taskText = taskResult.text;
292
 
293
- pmHistory.push({ role: 'user', parts: });
294
- pmHistory.push({ role: 'model', parts: });
295
 
296
  // 3. Initialize Worker (Worker -> Basic)
297
  const initialWorkerInstruction = extractWorkerPrompt(taskText) || `Initialize structure for: ${description}`;
298
- const workerHistory =[];
299
  const initialWorkerPrompt = `CONTEXT: New Project. \nINSTRUCTION: ${initialWorkerInstruction}`;
300
 
301
- const workerResult = await AIEngine.callWorker(workerHistory, initialWorkerPrompt,[]);
302
 
303
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
304
  const workerText = workerResult.text;
305
 
306
- workerHistory.push({ role: 'user', parts: });
307
- workerHistory.push({ role: 'model', parts: });
308
 
309
  // 4. Update Memory
310
  await StateManager.updateProject(projectId, {
@@ -328,10 +330,10 @@ async function runBackgroundInitialization(projectId, userId, description) {
328
  if (diamondUsage > 0) await deductUserCredits(userId, diamondUsage, 'diamond');
329
  if (basicUsage > 0) await deductUserCredits(userId, basicUsage, 'basic');
330
 
331
- console.log(` Init complete. Diamond: ${diamondUsage}, Basic: ${basicUsage}`);
332
 
333
  } catch (err) {
334
- console.error(` Init Error for ${projectId}:`, err);
335
  if(db) await db.ref(`projects/${projectId}/info/status`).set("error");
336
  }
337
  }
@@ -378,15 +380,15 @@ app.post('/project/feedback', async (req, res) => {
378
 
379
  // SCENARIO 1: TASK COMPLETE (Worker asks PM for next job)
380
  if (taskComplete) {
381
- console.log(` ✅ TASK COMPLETE.`);
382
  const summary = `Worker completed the previous task. Logs: ${logContext?.logs || "Clean"}. \nGenerate the NEXT task using 'WORKER_PROMPT:' format.`;
383
 
384
  const pmResult = await AIEngine.callPM(project.pmHistory, summary);
385
  diamondUsage += (pmResult.usage?.totalTokenCount || 0);
386
  const pmText = pmResult.text;
387
 
388
- project.pmHistory.push({ role: 'user', parts: });
389
- project.pmHistory.push({ role: 'model', parts: });
390
 
391
  const nextInstruction = extractWorkerPrompt(pmText);
392
  if (!nextInstruction) {
@@ -397,12 +399,12 @@ app.post('/project/feedback', async (req, res) => {
397
  }
398
 
399
  const newPrompt = `New Objective: ${nextInstruction}`;
400
- const workerResult = await AIEngine.callWorker(project.workerHistory, newPrompt,[]);
401
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
402
  const workerText = workerResult.text;
403
 
404
- project.workerHistory.push({ role: 'user', parts: });
405
- project.workerHistory.push({ role: 'model', parts: });
406
 
407
  await StateManager.updateProject(projectId, {
408
  pmHistory: project.pmHistory,
@@ -428,17 +430,17 @@ app.post('/project/feedback', async (req, res) => {
428
  diamondUsage += (pmResult.usage?.totalTokenCount || 0);
429
  const pmVerdict = pmResult.text;
430
 
431
- if (pmVerdict.includes("")) {
432
- const fixInstruction = pmVerdict.replace("", "").trim();
433
- const resetPrompt = `: Previous worker terminated. \nNew Objective: ${fixInstruction}`;
434
 
435
  // Clear History on terminate
436
- const resetHistory =[];
437
- const workerResult = await AIEngine.callWorker(resetHistory, resetPrompt,[]);
438
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
439
 
440
- resetHistory.push({ role: 'user', parts: });
441
- resetHistory.push({ role: 'model', parts: });
442
 
443
  await StateManager.updateProject(projectId, { workerHistory: resetHistory, failureCount: 0 });
444
  StateManager.queueCommand(projectId, { type: "EXECUTE", payload: "print('SYSTEM: Worker Reset')" });
@@ -448,12 +450,12 @@ app.post('/project/feedback', async (req, res) => {
448
  if (basicUsage > 0) await deductUserCredits(userId, basicUsage, 'basic');
449
  return res.json({ success: true, message: "Worker Terminated." });
450
  } else {
451
- const injection = `: ${pmVerdict} \n\nApply this fix now.`;
452
- const workerResult = await AIEngine.callWorker(project.workerHistory, injection,[]);
453
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
454
 
455
- project.workerHistory.push({ role: 'user', parts: });
456
- project.workerHistory.push({ role: 'model', parts: });
457
 
458
  await StateManager.updateProject(projectId, { workerHistory: project.workerHistory, failureCount: 1 });
459
  await processAndQueueResponse(projectId, workerResult.text, userId);
@@ -467,7 +469,7 @@ app.post('/project/feedback', async (req, res) => {
467
  // SCENARIO 3: STANDARD INTERACTION (Worker is the Frontline)
468
  const fullInput = `USER: ${prompt || "Automatic Feedback"}` + formatContext({ hierarchyContext, scriptContext, logContext });
469
 
470
- let workerResult = await AIEngine.callWorker(project.workerHistory, fullInput, images ||[]);
471
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
472
  let responseText = workerResult.text;
473
 
@@ -478,13 +480,13 @@ app.post('/project/feedback', async (req, res) => {
478
  console.log(` 🔀 Task routed to PM: ${routeTask}`);
479
 
480
  // PM generates Backend Code (Diamond)
481
- const pmPrompt = `: ${routeTask}\nWrite the core server/backend logic yourself. Then use WORKER_PROMPT: <task> to delegate the UI/Client aspects to the Worker.`;
482
  const pmResult = await AIEngine.callPM(project.pmHistory, pmPrompt);
483
  diamondUsage += (pmResult.usage?.totalTokenCount || 0);
484
  const pmText = pmResult.text;
485
 
486
- project.pmHistory.push({ role: 'user', parts: });
487
- project.pmHistory.push({ role: 'model', parts: });
488
 
489
  // Queue PM's Backend Code to Studio
490
  await processAndQueueResponse(projectId, pmText, userId);
@@ -492,18 +494,18 @@ app.post('/project/feedback', async (req, res) => {
492
  // Did the PM give the Worker UI/Client homework?
493
  const nextInstruction = extractWorkerPrompt(pmText);
494
  if (nextInstruction) {
495
- const delegationPrompt = `: The PM has handled the backend logic. Now execute this UI/Client task: ${nextInstruction}`;
496
 
497
- const workerDelegationResult = await AIEngine.callWorker(project.workerHistory, delegationPrompt,[]);
498
  basicUsage += (workerDelegationResult.usage?.totalTokenCount || 0);
499
  responseText = workerDelegationResult.text;
500
 
501
- project.workerHistory.push({ role: 'user', parts: });
502
- project.workerHistory.push({ role: 'model', parts: });
503
  } else {
504
  responseText = "System Note: The PM completed the core task without delegating client logic.";
505
- project.workerHistory.push({ role: 'user', parts: });
506
- project.workerHistory.push({ role: 'model', parts: });
507
  }
508
  }
509
  // INTERCEPTOR B: Worker asks PM a question
@@ -512,29 +514,29 @@ app.post('/project/feedback', async (req, res) => {
512
  if (pmQuestion) {
513
  console.log(` ❓ Worker asked PM: ${pmQuestion}`);
514
 
515
- const pmConsultPrompt = `: The Worker asks: "${pmQuestion}"\nProvide a technical answer to unblock them.`;
516
  const pmResult = await AIEngine.callPM(project.pmHistory, pmConsultPrompt);
517
  diamondUsage += (pmResult.usage?.totalTokenCount || 0);
518
  const pmAnswer = pmResult.text;
519
 
520
- project.pmHistory.push({ role: 'user', parts: });
521
- project.pmHistory.push({ role: 'model', parts: });
522
 
523
- const injectionMsg = `: ${pmAnswer}`;
524
- project.workerHistory.push({ role: 'user', parts: });
525
- project.workerHistory.push({ role: 'model', parts: });
526
 
527
  // Re-call Worker
528
- workerResult = await AIEngine.callWorker(project.workerHistory, injectionMsg,[]);
529
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
530
  responseText = workerResult.text;
531
 
532
- project.workerHistory.push({ role: 'user', parts: });
533
- project.workerHistory.push({ role: 'model', parts: });
534
  } else {
535
  // Standard Worker Execution
536
- project.workerHistory.push({ role: 'user', parts: });
537
- project.workerHistory.push({ role: 'model', parts: });
538
  }
539
  }
540
 
@@ -600,18 +602,18 @@ app.post('/human/override', validateRequest, async (req, res) => {
600
  await checkMinimumCredits(userId, 'basic');
601
 
602
  const project = await StateManager.getProject(projectId);
603
- const overrideMsg = `: ${instruction}`;
604
 
605
  if (pruneHistory && project.workerHistory.length >= 2) {
606
  project.workerHistory.pop();
607
  project.workerHistory.pop();
608
  }
609
 
610
- const workerResult = await AIEngine.callWorker(project.workerHistory, overrideMsg,[]);
611
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
612
 
613
- project.workerHistory.push({ role: 'user', parts: });
614
- project.workerHistory.push({ role: 'model', parts: });
615
 
616
  await StateManager.updateProject(projectId, { workerHistory: project.workerHistory });
617
  await processAndQueueResponse(projectId, workerResult.text, userId);
 
 
1
  // App.js
2
 
3
  import express from 'express';
 
81
  const current = current_credits || 0;
82
  return Math.max(0, current - amount);
83
  });
84
+ console.log(`[Credits] Deducted ${amount} ${type} credits from User ${userId}`);
85
  } catch (err) {
86
+ console.error(`[Credits] Failed to deduct ${amount} ${type} from ${userId}:`, err);
87
  }
88
  }
89
 
 
100
  next();
101
  };
102
 
103
+ // --- REGEX HELPERS (FIXED) ---
104
  function extractWorkerPrompt(text) {
105
  const match = text.match(/WORKER_PROMPT:\s*(.*)/s);
106
+ return match ? match[1].trim() : null;
107
  }
108
 
109
  function formatContext({ hierarchyContext, scriptContext, logContext }) {
110
  let out = "";
111
+ if (scriptContext) out += `\n[TARGET SCRIPT]: ${scriptContext.targetName}\n[SOURCE PREVIEW]: ${scriptContext.scriptSource}`;
112
+ if (logContext) out += `\n[LAST LOGS]: ${logContext.logs}`;
113
+ if (hierarchyContext) out += `\n[Hierarchy Context]: ${hierarchyContext}`;
114
  return out;
115
  }
116
 
117
  function extractPMQuestion(text) {
118
+ // Looks for [ASK_PM: ...]
119
+ const match = text.match(/\[ASK_PM:\s*(.*?)\]/s);
120
+ return match ? match[1].trim() : null;
121
  }
122
 
123
  function extractImagePrompt(text) {
124
+ // Looks for [GENERATE_IMAGE: ...]
125
+ const match = text.match(/\[GENERATE_IMAGE:\s*(.*?)\]/s);
126
+ return match ? match[1].trim() : null;
127
  }
128
 
129
  function extractRouteToPM(text) {
130
+ // Looks for [ROUTE_TO_PM: ...]
131
+ const match = text.match(/\[ROUTE_TO_PM:\s*(.*?)\]/s);
132
+ return match ? match[1].trim() : null;
133
  }
134
 
135
  // --- ADMIN ENDPOINTS ---
 
150
 
151
  try {
152
  await checkMinimumCredits(userId, 'basic');
153
+ console.log(`[Onboarding] Analyzing idea...`);
154
 
155
  const result = await AIEngine.generateEntryQuestions(description);
156
  const usage = result.usage?.totalTokenCount || 0;
 
184
  const randomHex = (n = 6) => crypto.randomBytes(Math.ceil(n/2)).toString("hex").slice(0, n);
185
  const projectId = `proj_${Date.now()}_${randomHex(7)}`;
186
 
187
+ console.log(`[Onboarding] Grading Project ${projectId}...`);
188
 
189
  const gradingResult = await AIEngine.gradeProject(description, answers);
190
  basicTokens += (gradingResult.usage?.totalTokenCount || 0);
 
205
  thumbnail: thumbnailUrl,
206
  createdAt: Date.now(),
207
  status: "Idle",
208
+ workerHistory: [],
209
  pmHistory: [],
210
+ commandQueue: [],
211
  failureCount: 0
212
  };
213
  await StateManager.updateProject(projectId, memoryObject);
 
217
  await firestore.collection('projects').doc(projectId).set({
218
  id: projectId,
219
  userId: userId,
220
+ assets: thumbnailUrl ? [thumbnailUrl] : [],
221
  createdAt: admin.firestore.FieldValue.serverTimestamp()
222
  });
223
  }
224
 
225
  if (db && !isFailure) {
226
  const updates = {};
227
+ updates[`projects/${projectId}/info`] = {
228
  id: projectId,
229
  userId,
230
  title: gradingResult.title || "Untitled",
 
234
  createdAt: Date.now(),
235
  status: "Idle"
236
  };
237
+ if (thumbnailUrl) updates[`projects/${projectId}/thumbnail`] = { url: thumbnailUrl };
238
+ updates[`projects/${projectId}/state`] = {
239
  workerHistory: [],
240
+ pmHistory: [],
241
+ commandQueue: [],
242
  failureCount: 0
243
  };
244
  await db.ref().update(updates);
 
267
  // --- CORE ENDPOINTS ---
268
 
269
  async function runBackgroundInitialization(projectId, userId, description) {
270
+ console.log(`[Background] Starting initialization for ${projectId}`);
271
 
272
  let diamondUsage = 0;
273
  let basicUsage = 0;
274
 
275
  try {
276
+ const pmHistory = [];
277
 
278
  // 1. Generate GDD (PM -> Diamond)
279
  const gddPrompt = `Create a comprehensive GDD for: ${description}`;
 
282
  diamondUsage += (gddResult.usage?.totalTokenCount || 0);
283
  const gddText = gddResult.text;
284
 
285
+ pmHistory.push({ role: 'user', parts: [{ text: gddPrompt }] });
286
+ pmHistory.push({ role: 'model', parts: [{ text: gddText }] });
287
 
288
  // 2. Generate First Task (PM -> Diamond)
289
  const taskPrompt = "Based on the GDD, generate the first technical milestone.\nOutput format:\nTASK_NAME: <Name>\nWORKER_PROMPT: <Specific, isolated instructions for the worker>";
 
292
  diamondUsage += (taskResult.usage?.totalTokenCount || 0);
293
  const taskText = taskResult.text;
294
 
295
+ pmHistory.push({ role: 'user', parts: [{ text: taskPrompt }] });
296
+ pmHistory.push({ role: 'model', parts: [{ text: taskText }] });
297
 
298
  // 3. Initialize Worker (Worker -> Basic)
299
  const initialWorkerInstruction = extractWorkerPrompt(taskText) || `Initialize structure for: ${description}`;
300
+ const workerHistory = [];
301
  const initialWorkerPrompt = `CONTEXT: New Project. \nINSTRUCTION: ${initialWorkerInstruction}`;
302
 
303
+ const workerResult = await AIEngine.callWorker(workerHistory, initialWorkerPrompt, []);
304
 
305
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
306
  const workerText = workerResult.text;
307
 
308
+ workerHistory.push({ role: 'user', parts: [{ text: initialWorkerPrompt }] });
309
+ workerHistory.push({ role: 'model', parts: [{ text: workerText }] });
310
 
311
  // 4. Update Memory
312
  await StateManager.updateProject(projectId, {
 
330
  if (diamondUsage > 0) await deductUserCredits(userId, diamondUsage, 'diamond');
331
  if (basicUsage > 0) await deductUserCredits(userId, basicUsage, 'basic');
332
 
333
+ console.log(`[Background] Init complete. Diamond: ${diamondUsage}, Basic: ${basicUsage}`);
334
 
335
  } catch (err) {
336
+ console.error(`[Background] Init Error for ${projectId}:`, err);
337
  if(db) await db.ref(`projects/${projectId}/info/status`).set("error");
338
  }
339
  }
 
380
 
381
  // SCENARIO 1: TASK COMPLETE (Worker asks PM for next job)
382
  if (taskComplete) {
383
+ console.log(`[${projectId}] ✅ TASK COMPLETE.`);
384
  const summary = `Worker completed the previous task. Logs: ${logContext?.logs || "Clean"}. \nGenerate the NEXT task using 'WORKER_PROMPT:' format.`;
385
 
386
  const pmResult = await AIEngine.callPM(project.pmHistory, summary);
387
  diamondUsage += (pmResult.usage?.totalTokenCount || 0);
388
  const pmText = pmResult.text;
389
 
390
+ project.pmHistory.push({ role: 'user', parts: [{ text: summary }] });
391
+ project.pmHistory.push({ role: 'model', parts: [{ text: pmText }] });
392
 
393
  const nextInstruction = extractWorkerPrompt(pmText);
394
  if (!nextInstruction) {
 
399
  }
400
 
401
  const newPrompt = `New Objective: ${nextInstruction}`;
402
+ const workerResult = await AIEngine.callWorker(project.workerHistory, newPrompt, []);
403
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
404
  const workerText = workerResult.text;
405
 
406
+ project.workerHistory.push({ role: 'user', parts: [{ text: newPrompt }] });
407
+ project.workerHistory.push({ role: 'model', parts: [{ text: workerText }] });
408
 
409
  await StateManager.updateProject(projectId, {
410
  pmHistory: project.pmHistory,
 
430
  diamondUsage += (pmResult.usage?.totalTokenCount || 0);
431
  const pmVerdict = pmResult.text;
432
 
433
+ if (pmVerdict.includes("[TERMINATE]")) {
434
+ const fixInstruction = pmVerdict.replace("[TERMINATE]", "").trim();
435
+ const resetPrompt = `[SYSTEM]: Previous worker terminated. \nNew Objective: ${fixInstruction}`;
436
 
437
  // Clear History on terminate
438
+ const resetHistory = [];
439
+ const workerResult = await AIEngine.callWorker(resetHistory, resetPrompt, []);
440
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
441
 
442
+ resetHistory.push({ role: 'user', parts: [{ text: resetPrompt }] });
443
+ resetHistory.push({ role: 'model', parts: [{ text: workerResult.text }] });
444
 
445
  await StateManager.updateProject(projectId, { workerHistory: resetHistory, failureCount: 0 });
446
  StateManager.queueCommand(projectId, { type: "EXECUTE", payload: "print('SYSTEM: Worker Reset')" });
 
450
  if (basicUsage > 0) await deductUserCredits(userId, basicUsage, 'basic');
451
  return res.json({ success: true, message: "Worker Terminated." });
452
  } else {
453
+ const injection = `[PM GUIDANCE]: ${pmVerdict} \n\nApply this fix now.`;
454
+ const workerResult = await AIEngine.callWorker(project.workerHistory, injection, []);
455
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
456
 
457
+ project.workerHistory.push({ role: 'user', parts: [{ text: injection }] });
458
+ project.workerHistory.push({ role: 'model', parts: [{ text: workerResult.text }] });
459
 
460
  await StateManager.updateProject(projectId, { workerHistory: project.workerHistory, failureCount: 1 });
461
  await processAndQueueResponse(projectId, workerResult.text, userId);
 
469
  // SCENARIO 3: STANDARD INTERACTION (Worker is the Frontline)
470
  const fullInput = `USER: ${prompt || "Automatic Feedback"}` + formatContext({ hierarchyContext, scriptContext, logContext });
471
 
472
+ let workerResult = await AIEngine.callWorker(project.workerHistory, fullInput, images || []);
473
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
474
  let responseText = workerResult.text;
475
 
 
480
  console.log(` 🔀 Task routed to PM: ${routeTask}`);
481
 
482
  // PM generates Backend Code (Diamond)
483
+ const pmPrompt = `[ROUTED TASK]: ${routeTask}\nWrite the core server/backend logic yourself. Then use WORKER_PROMPT: <task> to delegate the UI/Client aspects to the Worker.`;
484
  const pmResult = await AIEngine.callPM(project.pmHistory, pmPrompt);
485
  diamondUsage += (pmResult.usage?.totalTokenCount || 0);
486
  const pmText = pmResult.text;
487
 
488
+ project.pmHistory.push({ role: 'user', parts: [{ text: pmPrompt }] });
489
+ project.pmHistory.push({ role: 'model', parts: [{ text: pmText }] });
490
 
491
  // Queue PM's Backend Code to Studio
492
  await processAndQueueResponse(projectId, pmText, userId);
 
494
  // Did the PM give the Worker UI/Client homework?
495
  const nextInstruction = extractWorkerPrompt(pmText);
496
  if (nextInstruction) {
497
+ const delegationPrompt = `[SYSTEM]: The PM has handled the backend logic. Now execute this UI/Client task: ${nextInstruction}`;
498
 
499
+ const workerDelegationResult = await AIEngine.callWorker(project.workerHistory, delegationPrompt, []);
500
  basicUsage += (workerDelegationResult.usage?.totalTokenCount || 0);
501
  responseText = workerDelegationResult.text;
502
 
503
+ project.workerHistory.push({ role: 'user', parts: [{ text: delegationPrompt }] });
504
+ project.workerHistory.push({ role: 'model', parts: [{ text: responseText }] });
505
  } else {
506
  responseText = "System Note: The PM completed the core task without delegating client logic.";
507
+ project.workerHistory.push({ role: 'user', parts: [{ text: "System: PM task complete." }] });
508
+ project.workerHistory.push({ role: 'model', parts: [{ text: responseText }] });
509
  }
510
  }
511
  // INTERCEPTOR B: Worker asks PM a question
 
514
  if (pmQuestion) {
515
  console.log(` ❓ Worker asked PM: ${pmQuestion}`);
516
 
517
+ const pmConsultPrompt = `[WORKER CONSULTATION]: The Worker asks: "${pmQuestion}"\nProvide a technical answer to unblock them.`;
518
  const pmResult = await AIEngine.callPM(project.pmHistory, pmConsultPrompt);
519
  diamondUsage += (pmResult.usage?.totalTokenCount || 0);
520
  const pmAnswer = pmResult.text;
521
 
522
+ project.pmHistory.push({ role: 'user', parts: [{ text: pmConsultPrompt }] });
523
+ project.pmHistory.push({ role: 'model', parts: [{ text: pmAnswer }] });
524
 
525
+ const injectionMsg = `[PM RESPONSE]: ${pmAnswer}`;
526
+ project.workerHistory.push({ role: 'user', parts: [{ text: injectionMsg }] });
527
+ project.workerHistory.push({ role: 'model', parts: [{ text: responseText }] });
528
 
529
  // Re-call Worker
530
+ workerResult = await AIEngine.callWorker(project.workerHistory, injectionMsg, []);
531
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
532
  responseText = workerResult.text;
533
 
534
+ project.workerHistory.push({ role: 'user', parts: [{ text: injectionMsg }] });
535
+ project.workerHistory.push({ role: 'model', parts: [{ text: responseText }] });
536
  } else {
537
  // Standard Worker Execution
538
+ project.workerHistory.push({ role: 'user', parts: [{ text: fullInput }] });
539
+ project.workerHistory.push({ role: 'model', parts: [{ text: responseText }] });
540
  }
541
  }
542
 
 
602
  await checkMinimumCredits(userId, 'basic');
603
 
604
  const project = await StateManager.getProject(projectId);
605
+ const overrideMsg = `[SYSTEM OVERRIDE]: ${instruction}`;
606
 
607
  if (pruneHistory && project.workerHistory.length >= 2) {
608
  project.workerHistory.pop();
609
  project.workerHistory.pop();
610
  }
611
 
612
+ const workerResult = await AIEngine.callWorker(project.workerHistory, overrideMsg, []);
613
  basicUsage += (workerResult.usage?.totalTokenCount || 0);
614
 
615
+ project.workerHistory.push({ role: 'user', parts: [{ text: overrideMsg }] });
616
+ project.workerHistory.push({ role: 'model', parts: [{ text: workerResult.text }] });
617
 
618
  await StateManager.updateProject(projectId, { workerHistory: project.workerHistory });
619
  await processAndQueueResponse(projectId, workerResult.text, userId);