rentabots-sdk 1.7.26 → 1.7.29
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 +1 -1
- package/init.js +68 -18
- package/init_templates.js +68 -18
- 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.29'; // 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;
|
package/init.js
CHANGED
|
@@ -148,6 +148,13 @@ async function main() {
|
|
|
148
148
|
queen.workers.delete(job.id);
|
|
149
149
|
try { fs.unlinkSync(jobDataPath); } catch {}
|
|
150
150
|
await pushLog('WARN', 'Worker exited for mission ' + job.id + ' (code=' + code + ', signal=' + (signal || 'none') + ')');
|
|
151
|
+
|
|
152
|
+
if (code === 42 && queen.activeMissions.has(job.id) && !queen.workers.has(job.id)) {
|
|
153
|
+
await pushLog('INFO', 'Worker requested controlled restart for ' + job.id + '; respawning...');
|
|
154
|
+
setTimeout(() => {
|
|
155
|
+
spawnMissionWorker(job, 'controlled-restart').catch(() => {});
|
|
156
|
+
}, 1200);
|
|
157
|
+
}
|
|
151
158
|
});
|
|
152
159
|
|
|
153
160
|
worker.on('error', async (err) => {
|
|
@@ -245,7 +252,8 @@ const job = JSON.parse(fs.readFileSync(jobDataPath, 'utf8'));
|
|
|
245
252
|
|
|
246
253
|
function inferContract(job) {
|
|
247
254
|
const text = ((job.title || '') + ' ' + (job.description || '')).toLowerCase();
|
|
248
|
-
const
|
|
255
|
+
const hasApiWord = /(^|[^a-z0-9])api([^a-z0-9]|$)/i.test(text) || /endpoint|rest\b|graphql\b/.test(text);
|
|
256
|
+
const adapter = hasApiWord ? 'api' : text.includes('csv') || text.includes('dataset') || text.includes('etl') ? 'data' : text.includes('landing page') || text.includes('frontend') || text.includes('ui') || text.includes('web') ? 'web' : text.includes('docs') || text.includes('documentation') ? 'docs' : 'script';
|
|
249
257
|
const contract = {
|
|
250
258
|
adapter,
|
|
251
259
|
taskType: adapter,
|
|
@@ -456,7 +464,13 @@ async function main() {
|
|
|
456
464
|
issues.push('whitespace cleanup requirement not reflected in output');
|
|
457
465
|
}
|
|
458
466
|
for (const d of contract.deliverables || []) {
|
|
459
|
-
|
|
467
|
+
const dl = String(d).toLowerCase();
|
|
468
|
+
let ok = false;
|
|
469
|
+
if (dl === 'readme.md') ok = hasFile((f) => /^readme(\..+)?\.md$/i.test(f) || /^readme\.md$/i.test(f));
|
|
470
|
+
else if (dl === 'solution.py') ok = hasFile((f) => f.toLowerCase().endsWith('.py'));
|
|
471
|
+
else if (dl === 'openapi-or-endpoint-docs.md') ok = hasFile((f) => /openapi|endpoint|api.*doc/i.test(f));
|
|
472
|
+
else ok = hasFile((f) => f.toLowerCase() === dl);
|
|
473
|
+
if (!ok) {
|
|
460
474
|
issues.push('missing contract deliverable: ' + d);
|
|
461
475
|
}
|
|
462
476
|
}
|
|
@@ -497,8 +511,43 @@ async function main() {
|
|
|
497
511
|
|
|
498
512
|
if (issues.length > 0) {
|
|
499
513
|
await agent.setProgress(job.id, 70);
|
|
500
|
-
await agent.sendMessage(job.id, '⚠️ Contract QA failed: ' + issues.slice(0, 4).join('; ') + '.
|
|
501
|
-
|
|
514
|
+
await agent.sendMessage(job.id, '⚠️ Contract QA failed: ' + issues.slice(0, 4).join('; ') + '. Running targeted OpenClaw repair pass now.');
|
|
515
|
+
|
|
516
|
+
const repairPath = path.join(workDir, '.repair_count');
|
|
517
|
+
let repairCount = 0;
|
|
518
|
+
try { repairCount = Number(fs.readFileSync(repairPath, 'utf8') || '0'); } catch (_) {}
|
|
519
|
+
repairCount += 1;
|
|
520
|
+
fs.writeFileSync(repairPath, String(repairCount));
|
|
521
|
+
|
|
522
|
+
if (repairCount > 6) {
|
|
523
|
+
await agent.sendMessage(job.id, '🚨 OpenClaw repair limit reached. Please send one concrete clarification so I can continue with a precise fix.');
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const repairPrompt = [
|
|
528
|
+
'Repair the existing workspace to satisfy missing deterministic gates.',
|
|
529
|
+
'Do not explain. Edit files now and finish.',
|
|
530
|
+
'MISSING GATES:',
|
|
531
|
+
...issues.map(i => '- ' + i),
|
|
532
|
+
'',
|
|
533
|
+
'MISSION TITLE: ' + job.title,
|
|
534
|
+
'MISSION DESCRIPTION: ' + job.description,
|
|
535
|
+
].join('\n');
|
|
536
|
+
|
|
537
|
+
const repairArg = JSON.stringify(repairPrompt);
|
|
538
|
+
const repairCmds = [
|
|
539
|
+
'openclaw sessions spawn --task ' + repairArg,
|
|
540
|
+
'openclaw sessions_spawn --task ' + repairArg,
|
|
541
|
+
];
|
|
542
|
+
for (const rcmd of repairCmds) {
|
|
543
|
+
const r = await agent.execute(job.id, rcmd, { timeout: 900000, shell: true });
|
|
544
|
+
const out = (r.output || '').toLowerCase();
|
|
545
|
+
const pseudo = out.includes('usage: openclaw') || out.includes('unknown command') || out.includes('pass --to');
|
|
546
|
+
if (r.exitCode === 0 && !pseudo) break;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
await agent.sendMessage(job.id, '🔁 OpenClaw repair pass complete. Re-queueing worker validation pass now.');
|
|
550
|
+
process.exit(42);
|
|
502
551
|
}
|
|
503
552
|
|
|
504
553
|
if (fallbackGenerated) {
|
|
@@ -614,28 +663,29 @@ async function main() {
|
|
|
614
663
|
const snippet = lastOutput.slice(-500) || 'No output captured';
|
|
615
664
|
console.error("Worker Error:", snippet);
|
|
616
665
|
|
|
617
|
-
|
|
666
|
+
const failPath = path.join(workDir, '.openclaw_fail_count');
|
|
667
|
+
let fails = 0;
|
|
668
|
+
try { fails = Number(fs.readFileSync(failPath, 'utf8') || '0'); } catch (_) {}
|
|
669
|
+
fails += 1;
|
|
670
|
+
fs.writeFileSync(failPath, String(fails));
|
|
671
|
+
|
|
672
|
+
if (fails <= 5) {
|
|
673
|
+
await agent.setProgress(job.id, 25);
|
|
674
|
+
await agent.sendMessage(job.id, '⚠️ OpenClaw run failed (attempt ' + fails + '). Re-queueing OpenClaw-only retry...');
|
|
675
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
676
|
+
process.exit(42);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Fail-safe report only after OpenClaw retry budget exhausted
|
|
618
680
|
await agent.setProgress(job.id, 25);
|
|
619
|
-
await agent.sendMessage(job.id, "
|
|
681
|
+
await agent.sendMessage(job.id, "🚨 OpenClaw execution repeatedly failed. Please send one concrete clarification and I will continue immediately.");
|
|
620
682
|
|
|
621
683
|
try {
|
|
622
|
-
generateAdapterFallbackFiles(workDir, job, contract);
|
|
623
|
-
|
|
624
684
|
const repoRes = await agent.getRepo(job.id);
|
|
625
685
|
if (!repoRes.success || !repoRes.exists) {
|
|
626
686
|
await agent.createRepo(job.id, 'mission-recovery-' + job.id.slice(0, 8));
|
|
627
687
|
}
|
|
628
688
|
|
|
629
|
-
// Upload fallback draft artifacts first
|
|
630
|
-
const fallbackFiles = fs.readdirSync(workDir).filter((f) => fs.statSync(path.join(workDir, f)).isFile());
|
|
631
|
-
for (const f of fallbackFiles) {
|
|
632
|
-
try {
|
|
633
|
-
const full = path.join(workDir, f);
|
|
634
|
-
const content = fs.readFileSync(full, 'utf8');
|
|
635
|
-
await agent.uploadRepoFile(job.id, f, content, false);
|
|
636
|
-
} catch (_) {}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
689
|
const report = [
|
|
640
690
|
'# FAILSAFE_REPORT',
|
|
641
691
|
'',
|
package/init_templates.js
CHANGED
|
@@ -117,6 +117,13 @@ async function main() {
|
|
|
117
117
|
queen.workers.delete(job.id);
|
|
118
118
|
try { fs.unlinkSync(jobDataPath); } catch {}
|
|
119
119
|
await pushLog('WARN', 'Worker exited for mission ' + job.id + ' (code=' + code + ', signal=' + (signal || 'none') + ')');
|
|
120
|
+
|
|
121
|
+
if (code === 42 && queen.activeMissions.has(job.id) && !queen.workers.has(job.id)) {
|
|
122
|
+
await pushLog('INFO', 'Worker requested controlled restart for ' + job.id + '; respawning...');
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
spawnMissionWorker(job, 'controlled-restart').catch(() => {});
|
|
125
|
+
}, 1200);
|
|
126
|
+
}
|
|
120
127
|
});
|
|
121
128
|
|
|
122
129
|
worker.on('error', async (err) => {
|
|
@@ -221,7 +228,8 @@ const job = JSON.parse(fs.readFileSync(jobDataPath, 'utf8'));
|
|
|
221
228
|
|
|
222
229
|
function inferContract(job) {
|
|
223
230
|
const text = ((job.title || '') + ' ' + (job.description || '')).toLowerCase();
|
|
224
|
-
const
|
|
231
|
+
const hasApiWord = /(^|[^a-z0-9])api([^a-z0-9]|$)/i.test(text) || /endpoint|rest\b|graphql\b/.test(text);
|
|
232
|
+
const adapter = hasApiWord ? 'api' : text.includes('csv') || text.includes('dataset') || text.includes('etl') ? 'data' : text.includes('landing page') || text.includes('frontend') || text.includes('ui') || text.includes('web') ? 'web' : text.includes('docs') || text.includes('documentation') ? 'docs' : 'script';
|
|
225
233
|
const contract = {
|
|
226
234
|
adapter,
|
|
227
235
|
taskType: adapter,
|
|
@@ -441,7 +449,13 @@ async function main() {
|
|
|
441
449
|
issues.push('whitespace cleanup requirement not reflected in output');
|
|
442
450
|
}
|
|
443
451
|
for (const d of contract.deliverables || []) {
|
|
444
|
-
|
|
452
|
+
const dl = String(d).toLowerCase();
|
|
453
|
+
let ok = false;
|
|
454
|
+
if (dl === 'readme.md') ok = hasFile((f) => /^readme(\..+)?\.md$/i.test(f) || /^readme\.md$/i.test(f));
|
|
455
|
+
else if (dl === 'solution.py') ok = hasFile((f) => f.toLowerCase().endsWith('.py'));
|
|
456
|
+
else if (dl === 'openapi-or-endpoint-docs.md') ok = hasFile((f) => /openapi|endpoint|api.*doc/i.test(f));
|
|
457
|
+
else ok = hasFile((f) => f.toLowerCase() === dl);
|
|
458
|
+
if (!ok) {
|
|
445
459
|
issues.push('missing contract deliverable: ' + d);
|
|
446
460
|
}
|
|
447
461
|
}
|
|
@@ -482,8 +496,43 @@ async function main() {
|
|
|
482
496
|
|
|
483
497
|
if (issues.length > 0) {
|
|
484
498
|
await agent.setProgress(job.id, 70);
|
|
485
|
-
await agent.sendMessage(job.id, '⚠️ Contract QA failed: ' + issues.slice(0, 4).join('; ') + '.
|
|
486
|
-
|
|
499
|
+
await agent.sendMessage(job.id, '⚠️ Contract QA failed: ' + issues.slice(0, 4).join('; ') + '. Running targeted OpenClaw repair pass now.');
|
|
500
|
+
|
|
501
|
+
const repairPath = path.join(workDir, '.repair_count');
|
|
502
|
+
let repairCount = 0;
|
|
503
|
+
try { repairCount = Number(fs.readFileSync(repairPath, 'utf8') || '0'); } catch (_) {}
|
|
504
|
+
repairCount += 1;
|
|
505
|
+
fs.writeFileSync(repairPath, String(repairCount));
|
|
506
|
+
|
|
507
|
+
if (repairCount > 6) {
|
|
508
|
+
await agent.sendMessage(job.id, '🚨 OpenClaw repair limit reached. Please send one concrete clarification so I can continue with a precise fix.');
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const repairPrompt = [
|
|
513
|
+
'Repair the existing workspace to satisfy missing deterministic gates.',
|
|
514
|
+
'Do not explain. Edit files now and finish.',
|
|
515
|
+
'MISSING GATES:',
|
|
516
|
+
...issues.map(i => '- ' + i),
|
|
517
|
+
'',
|
|
518
|
+
'MISSION TITLE: ' + job.title,
|
|
519
|
+
'MISSION DESCRIPTION: ' + job.description,
|
|
520
|
+
].join('\n');
|
|
521
|
+
|
|
522
|
+
const repairArg = JSON.stringify(repairPrompt);
|
|
523
|
+
const repairCmds = [
|
|
524
|
+
'openclaw sessions spawn --task ' + repairArg,
|
|
525
|
+
'openclaw sessions_spawn --task ' + repairArg,
|
|
526
|
+
];
|
|
527
|
+
for (const rcmd of repairCmds) {
|
|
528
|
+
const r = await agent.execute(job.id, rcmd, { timeout: 900000, shell: true });
|
|
529
|
+
const out = (r.output || '').toLowerCase();
|
|
530
|
+
const pseudo = out.includes('usage: openclaw') || out.includes('unknown command') || out.includes('pass --to');
|
|
531
|
+
if (r.exitCode === 0 && !pseudo) break;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
await agent.sendMessage(job.id, '🔁 OpenClaw repair pass complete. Re-queueing worker validation pass now.');
|
|
535
|
+
process.exit(42);
|
|
487
536
|
}
|
|
488
537
|
|
|
489
538
|
if (fallbackGenerated) {
|
|
@@ -599,28 +648,29 @@ async function main() {
|
|
|
599
648
|
const snippet = lastOutput.slice(-500) || 'No output captured';
|
|
600
649
|
console.error("Worker Error:", snippet);
|
|
601
650
|
|
|
602
|
-
|
|
651
|
+
const failPath = path.join(workDir, '.openclaw_fail_count');
|
|
652
|
+
let fails = 0;
|
|
653
|
+
try { fails = Number(fs.readFileSync(failPath, 'utf8') || '0'); } catch (_) {}
|
|
654
|
+
fails += 1;
|
|
655
|
+
fs.writeFileSync(failPath, String(fails));
|
|
656
|
+
|
|
657
|
+
if (fails <= 5) {
|
|
658
|
+
await agent.setProgress(job.id, 25);
|
|
659
|
+
await agent.sendMessage(job.id, '⚠️ OpenClaw run failed (attempt ' + fails + '). Re-queueing OpenClaw-only retry...');
|
|
660
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
661
|
+
process.exit(42);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Fail-safe report only after OpenClaw retry budget exhausted
|
|
603
665
|
await agent.setProgress(job.id, 25);
|
|
604
|
-
await agent.sendMessage(job.id, "
|
|
666
|
+
await agent.sendMessage(job.id, "🚨 OpenClaw execution repeatedly failed. Please send one concrete clarification and I will continue immediately.");
|
|
605
667
|
|
|
606
668
|
try {
|
|
607
|
-
generateAdapterFallbackFiles(workDir, job, contract);
|
|
608
|
-
|
|
609
669
|
const repoRes = await agent.getRepo(job.id);
|
|
610
670
|
if (!repoRes.success || !repoRes.exists) {
|
|
611
671
|
await agent.createRepo(job.id, 'mission-recovery-' + job.id.slice(0, 8));
|
|
612
672
|
}
|
|
613
673
|
|
|
614
|
-
// Upload fallback draft artifacts first
|
|
615
|
-
const fallbackFiles = fs.readdirSync(workDir).filter((f) => fs.statSync(path.join(workDir, f)).isFile());
|
|
616
|
-
for (const f of fallbackFiles) {
|
|
617
|
-
try {
|
|
618
|
-
const full = path.join(workDir, f);
|
|
619
|
-
const content = fs.readFileSync(full, 'utf8');
|
|
620
|
-
await agent.uploadRepoFile(job.id, f, content, false);
|
|
621
|
-
} catch (_) {}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
674
|
const report = [
|
|
625
675
|
'# FAILSAFE_REPORT',
|
|
626
676
|
'',
|