rentabots-sdk 1.7.14 â 1.7.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +14 -5
- package/init.js +78 -23
- package/init_templates.js +79 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -71,7 +71,7 @@ exports.MessageSchema = zod_1.z.object({
|
|
|
71
71
|
})
|
|
72
72
|
});
|
|
73
73
|
// --- CORE SDK ENGINE ---
|
|
74
|
-
let SDK_VERSION = '1.7.
|
|
74
|
+
let SDK_VERSION = '1.7.17'; // fallback when package.json is unavailable
|
|
75
75
|
try {
|
|
76
76
|
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
|
77
77
|
SDK_VERSION = pkg.version;
|
|
@@ -658,13 +658,22 @@ class Agent extends events_1.EventEmitter {
|
|
|
658
658
|
async syncFromCloud() {
|
|
659
659
|
this.logInternal("Synchronizing missions and bids from cloud...");
|
|
660
660
|
try {
|
|
661
|
-
// 1. Sync Active Missions
|
|
661
|
+
// 1. Sync Active Missions (authoritative cloud state)
|
|
662
662
|
const activeRes = await this.api.get('jobs?status=in_progress');
|
|
663
663
|
const myActive = activeRes.data.data.filter((j) => j.agentId === this.agentId);
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
664
|
+
const liveIds = new Set(myActive.map((j) => j.id));
|
|
665
|
+
// Prune stale local active missions so autopilot can resume after completion
|
|
666
|
+
for (const localId of Array.from(this.activeMissions.keys())) {
|
|
667
|
+
if (!liveIds.has(localId)) {
|
|
668
|
+
const stale = this.activeMissions.get(localId);
|
|
669
|
+
if (stale)
|
|
670
|
+
this.completedMissions.set(localId, { ...stale, status: 'completed' });
|
|
671
|
+
this.activeMissions.delete(localId);
|
|
672
|
+
this.logInternal(`Uplink: Pruned stale active mission ${localId}`);
|
|
667
673
|
}
|
|
674
|
+
}
|
|
675
|
+
for (const raw of myActive) {
|
|
676
|
+
this.activeMissions.set(raw.id, this.enrichJob(raw));
|
|
668
677
|
this.socket?.emit('join_mission', raw.id);
|
|
669
678
|
this.logInternal(`Uplink: Monitoring active mission ${raw.id}`);
|
|
670
679
|
}
|
package/init.js
CHANGED
|
@@ -185,7 +185,7 @@ async function main() {
|
|
|
185
185
|
await agent.connect();
|
|
186
186
|
await agent.sendMessage(job.id, "đˇ Worker Unit [PID " + process.pid + "] deployed. Analyzing requirements...");
|
|
187
187
|
|
|
188
|
-
const task = 'PROJECT: ' + job.title + '. BRIEF: ' + job.description + '. INSTRUCTION: Execute this task.
|
|
188
|
+
const task = 'PROJECT: ' + job.title + '. BRIEF: ' + job.description + '. INSTRUCTION: Execute this task in the current directory. Do not leave the workspace. You MUST produce tangible deliverables (code + README + run/test notes) in local files.';
|
|
189
189
|
|
|
190
190
|
// Use shell command string (not array args)
|
|
191
191
|
const taskArg = JSON.stringify(task);
|
|
@@ -206,36 +206,53 @@ async function main() {
|
|
|
206
206
|
|
|
207
207
|
let overallSuccess = false;
|
|
208
208
|
let lastOutput = '';
|
|
209
|
+
let cycle = 0;
|
|
210
|
+
const maxCycles = Number(process.env.RENTABOTS_MAX_RECOVERY_CYCLES || 0); // 0 = infinite
|
|
209
211
|
|
|
210
212
|
try {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
213
|
+
while (!overallSuccess) {
|
|
214
|
+
cycle += 1;
|
|
215
|
+
|
|
216
|
+
for (const cmd of cmdCandidates) {
|
|
217
|
+
let exitCode = -1;
|
|
218
|
+
let output = '';
|
|
219
|
+
|
|
220
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
221
|
+
const result = await agent.execute(job.id, cmd, { timeout: 1200000, shell: true }); // 20m
|
|
222
|
+
exitCode = result.exitCode;
|
|
223
|
+
output = result.output || '';
|
|
224
|
+
|
|
225
|
+
if (exitCode === 0) {
|
|
226
|
+
const low = (output || '').toLowerCase();
|
|
227
|
+
const pseudoSuccess = low.includes('usage: openclaw') || low.includes('pass --to') || low.includes('unknown command');
|
|
228
|
+
if (!pseudoSuccess) {
|
|
229
|
+
overallSuccess = true;
|
|
230
|
+
lastOutput = output;
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
214
234
|
|
|
215
|
-
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
216
|
-
const result = await agent.execute(job.id, cmd, { timeout: 900000, shell: true });
|
|
217
|
-
exitCode = result.exitCode;
|
|
218
|
-
output = result.output || '';
|
|
219
|
-
|
|
220
|
-
if (exitCode === 0) {
|
|
221
|
-
overallSuccess = true;
|
|
222
235
|
lastOutput = output;
|
|
223
|
-
|
|
236
|
+
if (attempt < 3) {
|
|
237
|
+
await agent.sendMessage(job.id, 'â ī¸ OpenClaw run delayed. Retrying...');
|
|
238
|
+
await new Promise(r => setTimeout(r, 7000));
|
|
239
|
+
}
|
|
224
240
|
}
|
|
225
241
|
|
|
226
|
-
|
|
227
|
-
if (
|
|
228
|
-
await agent.sendMessage(job.id, '
|
|
229
|
-
|
|
242
|
+
if (overallSuccess) break;
|
|
243
|
+
if (lastOutput.toLowerCase().includes('unknown command')) {
|
|
244
|
+
await agent.sendMessage(job.id, 'âšī¸ Switching OpenClaw command compatibility mode...');
|
|
245
|
+
continue;
|
|
230
246
|
}
|
|
231
247
|
}
|
|
232
248
|
|
|
233
249
|
if (overallSuccess) break;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
break;
|
|
250
|
+
|
|
251
|
+
await agent.setProgress(job.id, Math.min(95, 15 + cycle * 2));
|
|
252
|
+
await agent.sendMessage(job.id, 'đ Recovery cycle ' + cycle + ' failed. Auto-retrying until completion...');
|
|
253
|
+
|
|
254
|
+
if (maxCycles > 0 && cycle >= maxCycles) break;
|
|
255
|
+
await new Promise(r => setTimeout(r, 15000));
|
|
239
256
|
}
|
|
240
257
|
} finally {
|
|
241
258
|
clearInterval(heartbeat);
|
|
@@ -257,10 +274,21 @@ async function main() {
|
|
|
257
274
|
};
|
|
258
275
|
walk(workDir);
|
|
259
276
|
|
|
277
|
+
let fallbackGenerated = false;
|
|
260
278
|
if (files.length === 0) {
|
|
261
279
|
await agent.setProgress(job.id, 40);
|
|
262
|
-
await agent.sendMessage(job.id, "â ī¸
|
|
263
|
-
|
|
280
|
+
await agent.sendMessage(job.id, "â ī¸ No deliverable files were produced yet. Entering forced-build fallback and generating starter deliverables now.");
|
|
281
|
+
|
|
282
|
+
const readme = '# Mission Output\n\nTitle: ' + job.title + '\n\nDescription: ' + job.description + '\n\n## Status\n- Auto-generated fallback deliverable because runtime produced no files.\n- Worker is continuing execution and awaiting optional clarifications.';
|
|
283
|
+
const questions = '# Clarifications Needed\n\n1. Exact output file name(s)?\n2. Provide sample input data?\n3. Any strict acceptance criteria/tests?';
|
|
284
|
+
const script = "# TODO: Implement mission logic\n# Mission: " + job.title + "\n\nprint('Placeholder fallback script generated. Update with final implementation.')\n";
|
|
285
|
+
|
|
286
|
+
fs.writeFileSync(path.join(workDir, 'README.md'), readme);
|
|
287
|
+
fs.writeFileSync(path.join(workDir, 'CLARIFICATIONS.md'), questions);
|
|
288
|
+
fs.writeFileSync(path.join(workDir, 'solution.py'), script);
|
|
289
|
+
|
|
290
|
+
files.push('README.md', 'CLARIFICATIONS.md', 'solution.py');
|
|
291
|
+
fallbackGenerated = true;
|
|
264
292
|
}
|
|
265
293
|
|
|
266
294
|
const repoRes = await agent.getRepo(job.id);
|
|
@@ -286,6 +314,33 @@ async function main() {
|
|
|
286
314
|
return;
|
|
287
315
|
}
|
|
288
316
|
|
|
317
|
+
// Lightweight QA: ensure deliverables are relevant to mission intent
|
|
318
|
+
const missionText = (job.title + ' ' + job.description).toLowerCase();
|
|
319
|
+
const required = [];
|
|
320
|
+
if (missionText.includes('python')) required.push('python');
|
|
321
|
+
if (missionText.includes('csv')) required.push('csv');
|
|
322
|
+
if (missionText.includes('blank') || missionText.includes('whitespace')) required.push('strip');
|
|
323
|
+
|
|
324
|
+
let combinedText = '';
|
|
325
|
+
for (const rel of files) {
|
|
326
|
+
const ext = path.extname(rel).toLowerCase();
|
|
327
|
+
if (['.js','.ts','.tsx','.jsx','.json','.md','.txt','.py','.yml','.yaml','.html','.css','.csv'].includes(ext)) {
|
|
328
|
+
try { combinedText += '\n' + fs.readFileSync(path.join(workDir, rel), 'utf8').toLowerCase(); } catch (_) {}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const missing = required.filter(k => !combinedText.includes(k));
|
|
332
|
+
if (missing.length > 0) {
|
|
333
|
+
await agent.setProgress(job.id, 70);
|
|
334
|
+
await agent.sendMessage(job.id, 'â ī¸ QA check failed: output appears misaligned with mission (' + missing.join(', ') + ' not found). I will revise now.');
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (fallbackGenerated) {
|
|
339
|
+
await agent.setProgress(job.id, 85);
|
|
340
|
+
await agent.sendMessage(job.id, 'đ Draft fallback deliverables uploaded for review (not final). Repo: ' + (repo?.id ? ('https://rentabots.com/repos/' + repo.id) : 'mission repository') + '. I will continue refinement after your confirmation.');
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
289
344
|
await agent.setProgress(job.id, 100);
|
|
290
345
|
if (repo?.id) {
|
|
291
346
|
await agent.sendMessage(job.id, "â
Execution complete. Deliverables uploaded: " + uploaded + " files. Repo: https://rentabots.com/repos/" + repo.id);
|
package/init_templates.js
CHANGED
|
@@ -169,7 +169,7 @@ async function main() {
|
|
|
169
169
|
await agent.sendMessage(job.id, "đˇ Worker Unit [PID " + process.pid + "] deployed to workspace. Analyzing requirements...");
|
|
170
170
|
|
|
171
171
|
// Construct the prompt for the autonomous brain
|
|
172
|
-
const task = \`PROJECT: \${job.title}. BRIEF: \${job.description}. INSTRUCTION: Execute this task in the current directory. Do not leave the workspace.\`;
|
|
172
|
+
const task = \`PROJECT: \${job.title}. BRIEF: \${job.description}. INSTRUCTION: Execute this task in the current directory. Do not leave the workspace. You MUST produce tangible deliverables (code + README + run/test notes) in local files.\`;
|
|
173
173
|
|
|
174
174
|
// --- đĻ EXECUTE VIA OPENCLAW BRAIN ---
|
|
175
175
|
const taskArg = JSON.stringify(task);
|
|
@@ -190,36 +190,54 @@ async function main() {
|
|
|
190
190
|
|
|
191
191
|
let overallSuccess = false;
|
|
192
192
|
let lastOutput = '';
|
|
193
|
+
let cycle = 0;
|
|
194
|
+
const maxCycles = Number(process.env.RENTABOTS_MAX_RECOVERY_CYCLES || 0); // 0 = infinite
|
|
193
195
|
|
|
194
196
|
try {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
while (!overallSuccess) {
|
|
198
|
+
cycle += 1;
|
|
199
|
+
|
|
200
|
+
for (const cmd of cmdCandidates) {
|
|
201
|
+
let exitCode = -1;
|
|
202
|
+
let output = '';
|
|
203
|
+
|
|
204
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
205
|
+
const result = await agent.execute(job.id, cmd, { timeout: 1200000, shell: true }); // 20m
|
|
206
|
+
exitCode = result.exitCode;
|
|
207
|
+
output = result.output || '';
|
|
208
|
+
|
|
209
|
+
if (exitCode === 0) {
|
|
210
|
+
const low = (output || '').toLowerCase();
|
|
211
|
+
const pseudoSuccess = low.includes('usage: openclaw') || low.includes('pass --to') || low.includes('unknown command');
|
|
212
|
+
if (!pseudoSuccess) {
|
|
213
|
+
overallSuccess = true;
|
|
214
|
+
lastOutput = output;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
198
218
|
|
|
199
|
-
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
200
|
-
const result = await agent.execute(job.id, cmd, { timeout: 900000, shell: true });
|
|
201
|
-
exitCode = result.exitCode;
|
|
202
|
-
output = result.output || '';
|
|
203
|
-
|
|
204
|
-
if (exitCode === 0) {
|
|
205
|
-
overallSuccess = true;
|
|
206
219
|
lastOutput = output;
|
|
207
|
-
|
|
220
|
+
if (attempt < 3) {
|
|
221
|
+
await agent.sendMessage(job.id, 'â ī¸ OpenClaw run delayed. Retrying...');
|
|
222
|
+
await new Promise(r => setTimeout(r, 7000));
|
|
223
|
+
}
|
|
208
224
|
}
|
|
209
225
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
await
|
|
226
|
+
if (overallSuccess) break;
|
|
227
|
+
|
|
228
|
+
if (lastOutput.toLowerCase().includes('unknown command')) {
|
|
229
|
+
await agent.sendMessage(job.id, 'âšī¸ Switching OpenClaw command compatibility mode...');
|
|
230
|
+
continue;
|
|
214
231
|
}
|
|
215
232
|
}
|
|
216
233
|
|
|
217
234
|
if (overallSuccess) break;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
break;
|
|
235
|
+
|
|
236
|
+
await agent.setProgress(job.id, Math.min(95, 15 + cycle * 2));
|
|
237
|
+
await agent.sendMessage(job.id, 'đ Recovery cycle ' + cycle + ' failed. Auto-retrying until completion...');
|
|
238
|
+
|
|
239
|
+
if (maxCycles > 0 && cycle >= maxCycles) break;
|
|
240
|
+
await new Promise(r => setTimeout(r, 15000));
|
|
223
241
|
}
|
|
224
242
|
} finally {
|
|
225
243
|
clearInterval(heartbeat);
|
|
@@ -241,10 +259,21 @@ async function main() {
|
|
|
241
259
|
};
|
|
242
260
|
walk(workDir);
|
|
243
261
|
|
|
262
|
+
let fallbackGenerated = false;
|
|
244
263
|
if (files.length === 0) {
|
|
245
264
|
await agent.setProgress(job.id, 40);
|
|
246
|
-
await agent.sendMessage(job.id, "â ī¸
|
|
247
|
-
|
|
265
|
+
await agent.sendMessage(job.id, "â ī¸ No deliverable files were produced yet. Entering forced-build fallback and generating starter deliverables now.");
|
|
266
|
+
|
|
267
|
+
const readme = '# Mission Output\n\nTitle: ' + job.title + '\n\nDescription: ' + job.description + '\n\n## Status\n- Auto-generated fallback deliverable because runtime produced no files.\n- Worker is continuing execution and awaiting optional clarifications.';
|
|
268
|
+
const questions = '# Clarifications Needed\n\n1. Exact output file name(s)?\n2. Provide sample input data?\n3. Any strict acceptance criteria/tests?';
|
|
269
|
+
const script = "# TODO: Implement mission logic\n# Mission: " + job.title + "\n\nprint('Placeholder fallback script generated. Update with final implementation.')\n";
|
|
270
|
+
|
|
271
|
+
fs.writeFileSync(path.join(workDir, 'README.md'), readme);
|
|
272
|
+
fs.writeFileSync(path.join(workDir, 'CLARIFICATIONS.md'), questions);
|
|
273
|
+
fs.writeFileSync(path.join(workDir, 'solution.py'), script);
|
|
274
|
+
|
|
275
|
+
files.push('README.md', 'CLARIFICATIONS.md', 'solution.py');
|
|
276
|
+
fallbackGenerated = true;
|
|
248
277
|
}
|
|
249
278
|
|
|
250
279
|
const repoRes = await agent.getRepo(job.id);
|
|
@@ -270,6 +299,33 @@ async function main() {
|
|
|
270
299
|
return;
|
|
271
300
|
}
|
|
272
301
|
|
|
302
|
+
// Lightweight QA: ensure deliverables are relevant to mission intent
|
|
303
|
+
const missionText = (job.title + ' ' + job.description).toLowerCase();
|
|
304
|
+
const required = [];
|
|
305
|
+
if (missionText.includes('python')) required.push('python');
|
|
306
|
+
if (missionText.includes('csv')) required.push('csv');
|
|
307
|
+
if (missionText.includes('blank') || missionText.includes('whitespace')) required.push('strip');
|
|
308
|
+
|
|
309
|
+
let combinedText = '';
|
|
310
|
+
for (const rel of files) {
|
|
311
|
+
const ext = path.extname(rel).toLowerCase();
|
|
312
|
+
if (['.js','.ts','.tsx','.jsx','.json','.md','.txt','.py','.yml','.yaml','.html','.css','.csv'].includes(ext)) {
|
|
313
|
+
try { combinedText += '\n' + fs.readFileSync(path.join(workDir, rel), 'utf8').toLowerCase(); } catch (_) {}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const missing = required.filter(k => !combinedText.includes(k));
|
|
317
|
+
if (missing.length > 0) {
|
|
318
|
+
await agent.setProgress(job.id, 70);
|
|
319
|
+
await agent.sendMessage(job.id, 'â ī¸ QA check failed: output appears misaligned with mission (' + missing.join(', ') + ' not found). I will revise now.');
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (fallbackGenerated) {
|
|
324
|
+
await agent.setProgress(job.id, 85);
|
|
325
|
+
await agent.sendMessage(job.id, 'đ Draft fallback deliverables uploaded for review (not final). Repo: ' + (repo?.id ? ('https://rentabots.com/repos/' + repo.id) : 'mission repository') + '. I will continue refinement after your confirmation.');
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
273
329
|
await agent.setProgress(job.id, 100);
|
|
274
330
|
if (repo?.id) {
|
|
275
331
|
await agent.sendMessage(job.id, "â
Execution complete. Deliverables uploaded: " + uploaded + " files. Repo: https://rentabots.com/repos/" + repo.id);
|