everydaycats commited on
Commit
edd1266
·
verified ·
1 Parent(s): ea7e86f

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +80 -74
app.js CHANGED
@@ -8,7 +8,6 @@ import fs from 'fs';
8
  const app = express();
9
  const PORT = process.env.PORT || 7860;
10
 
11
- // Load prompts
12
  const sysPrompts = JSON.parse(fs.readFileSync('./prompts.json', 'utf8'));
13
 
14
  app.use(cors());
@@ -20,29 +19,32 @@ const validateRequest = (req, res, next) => {
20
  next();
21
  };
22
 
23
- // Helper to extract PM's isolated instruction
24
  function extractWorkerPrompt(text) {
25
  const match = text.match(/WORKER_PROMPT:\s*(.*)/s);
26
  return match ? match[1].trim() : null;
27
  }
28
 
29
- // Helper to format context for the AI
30
  function formatContext({ hierarchyContext, scriptContext, logContext }) {
31
  let out = "";
32
- if (scriptContext) out += `\n[TARGET SCRIPT]: ${scriptContext.targetName}\n[SOURCE PREVIEW]: ${scriptContext.scriptSource.substring(0, 500)}...`;
33
  if (logContext) out += `\n[LAST LOGS]: ${logContext.logs}`;
34
  return out;
35
  }
36
 
 
 
 
 
 
 
37
  /**
38
- * 1. NEW PROJECT (Restored Full Logic)
39
- * Flow: PM (GDD) -> PM (Tasks) -> Worker (Task 1 Isolated)
40
  */
41
  app.post('/new/project', validateRequest, async (req, res) => {
42
  const { userId, projectId, description } = req.body;
 
43
 
44
  try {
45
- // 1. Generate GDD
46
  const pmHistory = [];
47
  const gddPrompt = `Create a comprehensive GDD for: ${description}`;
48
  const gddResponse = await AIEngine.callPM(pmHistory, gddPrompt);
@@ -50,25 +52,21 @@ app.post('/new/project', validateRequest, async (req, res) => {
50
  pmHistory.push({ role: 'user', parts: [{ text: gddPrompt }] });
51
  pmHistory.push({ role: 'model', parts: [{ text: gddResponse }] });
52
 
53
- // 2. Generate Initial Task List & Extract First Prompt
54
  const taskPrompt = "Based on the GDD, generate the first technical milestone.\nOutput format:\nTASK_NAME: <Name>\nWORKER_PROMPT: <Specific, isolated instructions for the worker>";
55
  const taskResponse = await AIEngine.callPM(pmHistory, taskPrompt);
56
 
57
  pmHistory.push({ role: 'user', parts: [{ text: taskPrompt }] });
58
  pmHistory.push({ role: 'model', parts: [{ text: taskResponse }] });
59
 
60
- // 3. Extract the Isolated Prompt
61
  const initialWorkerInstruction = extractWorkerPrompt(taskResponse) || `Initialize structure for: ${description}`;
62
 
63
- // 4. Initialize Worker (Fresh Scope)
64
  const workerHistory = [];
65
- const initialWorkerPrompt = `CONTEXT: None (New Project). \nINSTRUCTION: ${initialWorkerInstruction}`;
66
- const workerResponse = await AIEngine.callWorker(workerHistory, initialWorkerPrompt);
67
 
68
  workerHistory.push({ role: 'user', parts: [{ text: initialWorkerPrompt }] });
69
  workerHistory.push({ role: 'model', parts: [{ text: workerResponse }] });
70
 
71
- // 5. Save State
72
  await StateManager.updateProject(projectId, {
73
  userId,
74
  pmHistory,
@@ -77,51 +75,43 @@ app.post('/new/project', validateRequest, async (req, res) => {
77
  failureCount: 0
78
  });
79
 
80
- // Queue for Plugin
81
  StateManager.queueCommand(projectId, workerResponse);
82
-
83
  res.json({ success: true, message: "Project Initialized", gddPreview: gddResponse.substring(0, 200) });
84
 
85
  } catch (err) {
86
  console.error(err);
87
- res.status(500).json({ error: "Initialization Failed" });
88
  }
89
  });
90
 
91
  /**
92
- * 2. FEEDBACK LOOP (Restored Escalation & Termination)
93
  */
94
  app.post('/project/feedback', async (req, res) => {
95
- const { projectId, prompt, hierarchyContext, scriptContext, logContext, taskComplete } = req.body;
96
 
97
  const project = await StateManager.getProject(projectId);
98
  if (!project) return res.status(404).json({ error: "Project not found." });
99
 
100
- // ==========================================
101
- // A. TASK COMPLETE -> SCOPE SWITCH
102
- // ==========================================
103
  if (taskComplete) {
104
  console.log(`[${projectId}] ✅ TASK COMPLETE.`);
105
 
106
- // 1. Report to PM
107
  const summary = `Worker completed the previous task. Logs: ${logContext?.logs || "Clean"}. \nGenerate the NEXT task using 'WORKER_PROMPT:' format.`;
108
  const pmResponse = await AIEngine.callPM(project.pmHistory, summary);
109
 
110
  project.pmHistory.push({ role: 'user', parts: [{ text: summary }] });
111
  project.pmHistory.push({ role: 'model', parts: [{ text: pmResponse }] });
112
 
113
- // 2. Get Next Instruction
114
  const nextInstruction = extractWorkerPrompt(pmResponse);
115
  if (!nextInstruction) {
116
  await StateManager.updateProject(projectId, { pmHistory: project.pmHistory, status: "IDLE" });
117
- return res.json({ success: true, message: "No further tasks generated. Project Idle." });
118
  }
119
 
120
- // 3. NUKE WORKER (Scope Reset)
121
- console.log(`[${projectId}] 🧹 Nuking Worker for next task.`);
122
  const newWorkerHistory = [];
123
  const newPrompt = `New Objective: ${nextInstruction}`;
124
- const workerResponse = await AIEngine.callWorker(newWorkerHistory, newPrompt);
125
 
126
  newWorkerHistory.push({ role: 'user', parts: [{ text: newPrompt }] });
127
  newWorkerHistory.push({ role: 'model', parts: [{ text: workerResponse }] });
@@ -132,46 +122,33 @@ app.post('/project/feedback', async (req, res) => {
132
  failureCount: 0
133
  });
134
 
135
- // Clear Console Command + New Code
136
  StateManager.queueCommand(projectId, "CLEAR_CONSOLE");
137
  StateManager.queueCommand(projectId, workerResponse);
138
 
139
  return res.json({ success: true, message: "Next Task Assigned" });
140
  }
141
 
142
- // ==========================================
143
- // B. ERROR HANDLING & ESCALATION
144
- // ==========================================
145
  let isFailure = false;
146
  if (logContext?.logs) {
147
- const errs = ["Error", "Exception", "failed", "Stack Begin"];
148
  if (errs.some(k => logContext.logs.includes(k))) {
149
  isFailure = true;
150
  project.failureCount = (project.failureCount || 0) + 1;
151
  }
152
  }
153
 
154
- // Prepare Prompt
155
- const fullInput = `USER: ${prompt || "Automatic Feedback"}` + formatContext({ hierarchyContext, scriptContext, logContext });
156
-
157
- // --- ESCALATION LOGIC (Restored) ---
158
- if (project.failureCount > 2) {
159
- console.log(`[${projectId}] 🚨 Escalating to PM (Failures: ${project.failureCount})...`);
160
-
161
- // 1. Ask PM for solution
162
  const pmPrompt = sysPrompts.pm_guidance_prompt.replace('{{LOGS}}', logContext?.logs);
163
  const pmVerdict = await AIEngine.callPM(project.pmHistory, pmPrompt);
164
 
165
- // 2. CHECK: Did PM order termination?
166
  if (pmVerdict.includes("[TERMINATE]")) {
167
- console.log(`[${projectId}] 💀 PM TERMINATED WORKER.`);
168
-
169
  const fixInstruction = pmVerdict.replace("[TERMINATE]", "").trim();
170
-
171
- // Hard Reset
172
  const resetHistory = [];
173
  const resetPrompt = `[SYSTEM]: Previous worker terminated. \nNew Objective: ${fixInstruction}`;
174
- const workerResp = await AIEngine.callWorker(resetHistory, resetPrompt);
175
 
176
  resetHistory.push({ role: 'user', parts: [{ text: resetPrompt }] });
177
  resetHistory.push({ role: 'model', parts: [{ text: workerResp }] });
@@ -179,40 +156,71 @@ app.post('/project/feedback', async (req, res) => {
179
  await StateManager.updateProject(projectId, { workerHistory: resetHistory, failureCount: 0 });
180
  StateManager.queueCommand(projectId, "CLEAR_CONSOLE");
181
  StateManager.queueCommand(projectId, workerResp);
182
-
183
- return res.json({ success: true, message: "Worker Terminated & Replaced." });
184
- }
185
- else {
186
- // 3. Just Guidance (Soft Fix)
187
- console.log(`[${projectId}] 💡 PM Provided Guidance.`);
188
  const injection = `[PM GUIDANCE]: ${pmVerdict} \n\nApply this fix now.`;
189
- const workerResp = await AIEngine.callWorker(project.workerHistory, injection);
190
 
191
  project.workerHistory.push({ role: 'user', parts: [{ text: injection }] });
192
  project.workerHistory.push({ role: 'model', parts: [{ text: workerResp }] });
193
 
194
- // Reset count slightly so we don't spam PM, but keep watch
195
- await StateManager.updateProject(projectId, { workerHistory: project.workerHistory, failureCount: 0 });
196
  await StateManager.queueCommand(projectId, workerResp);
197
-
198
  return res.json({ success: true, message: "PM Guidance Applied." });
199
  }
200
  }
201
 
202
- // ==========================================
203
- // C. STANDARD WORKER LOOP
204
- // ==========================================
205
  try {
206
- const response = await AIEngine.callWorker(project.workerHistory, fullInput);
207
 
208
- project.workerHistory.push({ role: 'user', parts: [{ text: fullInput }] });
209
- project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
210
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  await StateManager.updateProject(projectId, {
212
  workerHistory: project.workerHistory,
 
213
  failureCount: project.failureCount
214
  });
215
 
 
216
  await StateManager.queueCommand(projectId, response);
217
  res.json({ success: true });
218
 
@@ -223,21 +231,22 @@ app.post('/project/feedback', async (req, res) => {
223
  });
224
 
225
  /**
226
- * 3. HUMAN OVERRIDE (God Mode)
227
  */
228
  app.post('/human/override', validateRequest, async (req, res) => {
229
  const { projectId, instruction, pruneHistory } = req.body;
230
  const project = await StateManager.getProject(projectId);
231
 
 
 
232
  const overrideMsg = `[SYSTEM OVERRIDE]: ${instruction}`;
233
 
234
- // Optional: Prune the argument if they are stuck
235
  if (pruneHistory && project.workerHistory.length >= 2) {
236
- project.workerHistory.pop(); // last model
237
- project.workerHistory.pop(); // last user
238
  }
239
 
240
- const response = await AIEngine.callWorker(project.workerHistory, overrideMsg);
241
  project.workerHistory.push({ role: 'user', parts: [{ text: overrideMsg }] });
242
  project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
243
 
@@ -247,18 +256,15 @@ app.post('/human/override', validateRequest, async (req, res) => {
247
  });
248
 
249
  /**
250
- * 4. WORKER KILL (Manual Reassignment)
251
  */
252
  app.post('/worker/kill', validateRequest, async (req, res) => {
253
  const { projectId } = req.body;
254
- // Logic: Just reset the history with a "Try again" prompt
255
- const project = await StateManager.getProject(projectId);
256
-
257
  const rebootPrompt = "[SYSTEM]: Worker process restarted. Attempt the task again from scratch.";
258
- const response = await AIEngine.callWorker([{ role: 'user', parts: [{ text: rebootPrompt }] }], rebootPrompt);
259
 
260
  await StateManager.updateProject(projectId, {
261
- workerHistory: [{ role: 'user', parts: [{ text: rebootPrompt }] }], // Nuke history
262
  workerHistory: [{ role: 'model', parts: [{ text: response }] }],
263
  failureCount: 0
264
  });
@@ -268,7 +274,7 @@ app.post('/worker/kill', validateRequest, async (req, res) => {
268
  });
269
 
270
  /**
271
- * 5. PING (Plugin Polling)
272
  */
273
  app.post('/project/ping', async (req, res) => {
274
  const { projectId } = req.body;
 
8
  const app = express();
9
  const PORT = process.env.PORT || 7860;
10
 
 
11
  const sysPrompts = JSON.parse(fs.readFileSync('./prompts.json', 'utf8'));
12
 
13
  app.use(cors());
 
19
  next();
20
  };
21
 
 
22
  function extractWorkerPrompt(text) {
23
  const match = text.match(/WORKER_PROMPT:\s*(.*)/s);
24
  return match ? match[1].trim() : null;
25
  }
26
 
 
27
  function formatContext({ hierarchyContext, scriptContext, logContext }) {
28
  let out = "";
29
+ if (scriptContext) out += `\n[TARGET SCRIPT]: ${scriptContext.targetName}\n[SOURCE PREVIEW]: ${scriptContext.scriptSource?.substring(0, 1000)}...`;
30
  if (logContext) out += `\n[LAST LOGS]: ${logContext.logs}`;
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 = [];
49
  const gddPrompt = `Create a comprehensive GDD for: ${description}`;
50
  const gddResponse = await AIEngine.callPM(pmHistory, gddPrompt);
 
52
  pmHistory.push({ role: 'user', parts: [{ text: gddPrompt }] });
53
  pmHistory.push({ role: 'model', parts: [{ text: gddResponse }] });
54
 
 
55
  const taskPrompt = "Based on the GDD, generate the first technical milestone.\nOutput format:\nTASK_NAME: <Name>\nWORKER_PROMPT: <Specific, isolated instructions for the worker>";
56
  const taskResponse = await AIEngine.callPM(pmHistory, taskPrompt);
57
 
58
  pmHistory.push({ role: 'user', parts: [{ text: taskPrompt }] });
59
  pmHistory.push({ role: 'model', parts: [{ text: taskResponse }] });
60
 
 
61
  const initialWorkerInstruction = extractWorkerPrompt(taskResponse) || `Initialize structure for: ${description}`;
62
 
 
63
  const workerHistory = [];
64
+ const initialWorkerPrompt = `CONTEXT: New Project. \nINSTRUCTION: ${initialWorkerInstruction}`;
65
+ const workerResponse = await AIEngine.callWorker(workerHistory, initialWorkerPrompt, []);
66
 
67
  workerHistory.push({ role: 'user', parts: [{ text: initialWorkerPrompt }] });
68
  workerHistory.push({ role: 'model', parts: [{ text: workerResponse }] });
69
 
 
70
  await StateManager.updateProject(projectId, {
71
  userId,
72
  pmHistory,
 
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) {
82
  console.error(err);
83
+ res.status(500).json({ error: "Init Failed" });
84
  }
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;
92
 
93
  const project = await StateManager.getProject(projectId);
94
  if (!project) return res.status(404).json({ error: "Project not found." });
95
 
96
+ // A. TASK COMPLETE
 
 
97
  if (taskComplete) {
98
  console.log(`[${projectId}] ✅ TASK COMPLETE.`);
99
 
 
100
  const summary = `Worker completed the previous task. Logs: ${logContext?.logs || "Clean"}. \nGenerate the NEXT task using 'WORKER_PROMPT:' format.`;
101
  const pmResponse = await AIEngine.callPM(project.pmHistory, summary);
102
 
103
  project.pmHistory.push({ role: 'user', parts: [{ text: summary }] });
104
  project.pmHistory.push({ role: 'model', parts: [{ text: pmResponse }] });
105
 
 
106
  const nextInstruction = extractWorkerPrompt(pmResponse);
107
  if (!nextInstruction) {
108
  await StateManager.updateProject(projectId, { pmHistory: project.pmHistory, status: "IDLE" });
109
+ return res.json({ success: true, message: "No further tasks. Project Idle." });
110
  }
111
 
 
 
112
  const newWorkerHistory = [];
113
  const newPrompt = `New Objective: ${nextInstruction}`;
114
+ const workerResponse = await AIEngine.callWorker(newWorkerHistory, newPrompt, []);
115
 
116
  newWorkerHistory.push({ role: 'user', parts: [{ text: newPrompt }] });
117
  newWorkerHistory.push({ role: 'model', parts: [{ text: workerResponse }] });
 
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"];
135
  if (errs.some(k => logContext.logs.includes(k))) {
136
  isFailure = true;
137
  project.failureCount = (project.failureCount || 0) + 1;
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);
145
  const pmVerdict = await AIEngine.callPM(project.pmHistory, pmPrompt);
146
 
 
147
  if (pmVerdict.includes("[TERMINATE]")) {
 
 
148
  const fixInstruction = pmVerdict.replace("[TERMINATE]", "").trim();
 
 
149
  const resetHistory = [];
150
  const resetPrompt = `[SYSTEM]: Previous worker terminated. \nNew Objective: ${fixInstruction}`;
151
+ const workerResp = await AIEngine.callWorker(resetHistory, resetPrompt, []);
152
 
153
  resetHistory.push({ role: 'user', parts: [{ text: resetPrompt }] });
154
  resetHistory.push({ role: 'model', parts: [{ text: workerResp }] });
 
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.`;
162
+ const workerResp = await AIEngine.callWorker(project.workerHistory, injection, []);
163
 
164
  project.workerHistory.push({ role: 'user', parts: [{ text: injection }] });
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
 
 
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) {
245
+ project.workerHistory.pop();
246
+ project.workerHistory.pop();
247
  }
248
 
249
+ const response = await AIEngine.callWorker(project.workerHistory, overrideMsg, []);
250
  project.workerHistory.push({ role: 'user', parts: [{ text: overrideMsg }] });
251
  project.workerHistory.push({ role: 'model', parts: [{ text: response }] });
252
 
 
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
  });
 
274
  });
275
 
276
  /**
277
+ * 5. PING
278
  */
279
  app.post('/project/ping', async (req, res) => {
280
  const { projectId } = req.body;