@molecule/api-ai-tools 1.2.0 → 1.2.1
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/backends/sandbox.d.ts.map +1 -1
- package/dist/backends/sandbox.js +9 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +22 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/backends/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGnD,sFAAsF;AACtF,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACvC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,CAAC,CAAC,CAAA;IACnF,mEAAmE;IAEnE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,WAAW,EACpB,WAAW,SAAe,GACzB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/backends/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGnD,sFAAsF;AACtF,UAAU,WAAW;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACvC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,CAAC,CAAC,CAAA;IACnF,mEAAmE;IAEnE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,WAAW,EACpB,WAAW,SAAe,GACzB,gBAAgB,CAmDlB"}
|
package/dist/backends/sandbox.js
CHANGED
|
@@ -42,9 +42,17 @@ export function createSandboxBackend(sandbox, projectRoot = '/workspace') {
|
|
|
42
42
|
// printed still comes back, with exit code 124. Wrapping only the inner
|
|
43
43
|
// command would run it in a child shell that never sees unexported variables
|
|
44
44
|
// the consumer's sourcing set.
|
|
45
|
+
// Its output goes to files that are printed once the shell exits, never to
|
|
46
|
+
// the exec's own pipe: `cd app && server > log &` backgrounds a SUBSHELL whose
|
|
47
|
+
// stdout is still that pipe (the redirect covers the server only), and the
|
|
48
|
+
// exec waits for every holder of the pipe — past the budget, which kills the
|
|
49
|
+
// shell but not the detached subshell, until the caller's outer timeout
|
|
50
|
+
// throws the output away. Measured: three 300 s calls in two runs (X0 x31,
|
|
51
|
+
// x33). A background child now holds a file, and the call returns when the
|
|
52
|
+
// command does.
|
|
45
53
|
const budgetSeconds = opts?.budgetMs ? Math.max(1, Math.round(opts.budgetMs / 1000)) : 0;
|
|
46
54
|
const fullCommand = budgetSeconds
|
|
47
|
-
? `timeout -k 5 ${budgetSeconds} bash -c ${shellQuote(anchored)}`
|
|
55
|
+
? `o=$(mktemp); e=$(mktemp); timeout -k 5 ${budgetSeconds} bash -c ${shellQuote(anchored)} > "$o" 2> "$e" < /dev/null; c=$?; cat "$o"; cat "$e" >&2; rm -f "$o" "$e"; exit $c`
|
|
48
56
|
: anchored;
|
|
49
57
|
// sandbox.exec is the Sandbox interface method — runs inside Docker, inherently sandboxed
|
|
50
58
|
const result = await sandbox.exec(fullCommand, { timeout: opts?.timeout });
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAY9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA+BnE;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAY9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA+BnE;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAmvCxF"}
|
package/dist/tools.js
CHANGED
|
@@ -527,6 +527,7 @@ export function buildTools(backend, config) {
|
|
|
527
527
|
content = verdict.content;
|
|
528
528
|
}
|
|
529
529
|
const oldContent = content;
|
|
530
|
+
let alreadyApplied = 0;
|
|
530
531
|
for (const { old_string: oldString, new_string: newString } of replacements) {
|
|
531
532
|
// Validate each replacement is well-formed BEFORE touching content. A
|
|
532
533
|
// weak model sometimes emits a batch element missing a field or with a
|
|
@@ -539,6 +540,19 @@ export function buildTools(backend, config) {
|
|
|
539
540
|
};
|
|
540
541
|
}
|
|
541
542
|
const count = content.split(oldString).length - 1;
|
|
543
|
+
// The edit is ALREADY in the file: old_string is gone and a distinctive
|
|
544
|
+
// new_string is there exactly once. The executor re-sends an edit it
|
|
545
|
+
// made a few calls ago (it works from its memory of the file), and the
|
|
546
|
+
// "not found" error cost it a read_file plus a retry each time — 6 to 11
|
|
547
|
+
// times a build in X0 x30/x34. Report it as applied instead. Short or
|
|
548
|
+
// repeated new_strings still error: they could be there by coincidence.
|
|
549
|
+
if (count === 0 &&
|
|
550
|
+
newString !== oldString &&
|
|
551
|
+
newString.trim().length >= 20 &&
|
|
552
|
+
content.split(newString).length - 1 === 1) {
|
|
553
|
+
alreadyApplied++;
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
542
556
|
if (count === 0) {
|
|
543
557
|
// A bare "old_string not found" gives the model nothing to correct, so
|
|
544
558
|
// it retries blindly (the #1 edit_file failure mode). Diagnose WHY the
|
|
@@ -648,6 +662,12 @@ export function buildTools(backend, config) {
|
|
|
648
662
|
const at = content.indexOf(oldString);
|
|
649
663
|
content = content.slice(0, at) + newString + content.slice(at + oldString.length);
|
|
650
664
|
}
|
|
665
|
+
const alreadyNote = alreadyApplied > 0
|
|
666
|
+
? `${alreadyApplied} of these edits ${alreadyApplied === 1 ? 'was' : 'were'} already in the file (its new_string is there and its old_string is not) — nothing to do for ${alreadyApplied === 1 ? 'it' : 'them'}.`
|
|
667
|
+
: null;
|
|
668
|
+
if (content === oldContent) {
|
|
669
|
+
return { path, ok: true, replacementsApplied: 0, alreadyApplied, note: alreadyNote };
|
|
670
|
+
}
|
|
651
671
|
if (onFileDiff)
|
|
652
672
|
onFileDiff({ path, oldContent, newContent: content });
|
|
653
673
|
await backend.writeFile(path, content);
|
|
@@ -658,7 +678,8 @@ export function buildTools(backend, config) {
|
|
|
658
678
|
return {
|
|
659
679
|
path,
|
|
660
680
|
ok: true,
|
|
661
|
-
replacementsApplied: replacements.length,
|
|
681
|
+
replacementsApplied: replacements.length - alreadyApplied,
|
|
682
|
+
...(alreadyApplied > 0 ? { alreadyApplied, note: alreadyNote } : {}),
|
|
662
683
|
...(await syntaxErrorAfterWrite(path)),
|
|
663
684
|
};
|
|
664
685
|
}
|