@molecule/api-ai-tools 1.5.9 → 1.5.11

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.
@@ -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;AA8B9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAwCnE;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CA8/CxF"}
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;AA8B9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAwCnE;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAwiDxF"}
package/dist/tools.js CHANGED
@@ -142,22 +142,37 @@ export function buildTools(backend, config) {
142
142
  async function checkSymlink(path) {
143
143
  if (!symlinkGuards)
144
144
  return null;
145
- try {
146
- const result = await backend.run(`readlink -f ${shellQuote(path)} 2>/dev/null || echo ${shellQuote(path)}`, { timeout: 5000 });
147
- const realPath = result.stdout.trim();
148
- if (realPath && realPath !== root && !realPath.startsWith(root + '/')) {
149
- return 'Access denied: path resolves outside the project workspace';
145
+ // One retry: the first commands on a just-attached sandbox can fail at once (X1
146
+ // flash-m44: three paths refused in 332 ms, the same check passing a beat later).
147
+ let lastError;
148
+ for (let attempt = 0; attempt < 2; attempt++) {
149
+ const started = Date.now();
150
+ try {
151
+ const result = await backend.run(`readlink -f ${shellQuote(path)} 2>/dev/null || echo ${shellQuote(path)}`, { timeout: 5000 });
152
+ const realPath = result.stdout.trim();
153
+ if (realPath && realPath !== root && !realPath.startsWith(root + '/')) {
154
+ return 'Access denied: path resolves outside the project workspace';
155
+ }
156
+ return null;
157
+ }
158
+ catch (error) {
159
+ lastError = Object.assign(error instanceof Error ? error : new Error(String(error)), {
160
+ elapsedMs: Date.now() - started,
161
+ });
162
+ if (attempt === 0)
163
+ await new Promise((resolve) => setTimeout(resolve, 300));
150
164
  }
151
- return null;
152
165
  }
153
- catch (_error) {
154
- // readlink unavailable or timed out — deny access conservatively, and say
155
- // why: "access denied" read as a forbidden path, and builders spent call
156
- // after call on paths that were fine while the sandbox was not answering.
157
- return ('Unable to verify path safety: the sandbox did not answer the check within 5 s (it may be ' +
166
+ // Deny conservatively, and say what failed: "access denied" read as a forbidden path,
167
+ // and a fixed "did not answer within 5 s" hid an error that took 332 ms.
168
+ const err = lastError;
169
+ const timedOut = err?.name === 'TimeoutError' || (err?.elapsedMs ?? 0) >= 4900;
170
+ return timedOut
171
+ ? 'Unable to verify path safety: the sandbox did not answer the check within 5 s (it may be ' +
158
172
  'restarting or out of memory), so the path was refused to stay safe. Retry in a moment; if ' +
159
- 'every file tool fails this way, the sandbox needs a restart.');
160
- }
173
+ 'every file tool fails this way, the sandbox needs a restart.'
174
+ : `Unable to verify path safety: the sandbox's command channel failed (${err?.name ?? 'Error'}: ${String(err?.message ?? err).slice(0, 160)}), ` +
175
+ 'so the path was refused to stay safe. Retry the call; if every file tool fails this way, the sandbox needs a restart.';
161
176
  }
162
177
  /**
163
178
  * Strip control characters and optionally redact secrets from tool output.
@@ -434,12 +449,15 @@ export function buildTools(backend, config) {
434
449
  // the next read uses a real name instead of another guess.
435
450
  // A package's docs are one tool call away wherever node_modules happens to live.
436
451
  const moleculePkg = /node_modules\/(@molecule\/[^/]+)\//.exec(path)?.[1];
437
- if (moleculePkg && /No such file or directory/i.test(message)) {
452
+ // Docker's `cat` says "No such file or directory"; E2B's SDK says "path '…' does not
453
+ // exist" (X1 flash-m44: the hints below never fired on E2B).
454
+ const notFound = /No such file or directory|does not exist|ENOENT/i.test(message);
455
+ if (moleculePkg && notFound) {
438
456
  return {
439
457
  error: `No such file: ${path}. Read ${moleculePkg}'s documentation with read_molecule_doc("${moleculePkg}") instead of looking for it in node_modules.`,
440
458
  };
441
459
  }
442
- if (/No such file or directory/i.test(message)) {
460
+ if (notFound) {
443
461
  const parent = path.replace(/\/[^/]*$/, '') || '/';
444
462
  let listing;
445
463
  try {
@@ -476,7 +494,7 @@ export function buildTools(backend, config) {
476
494
  const message = e.message;
477
495
  // Same ground-truth answer as read_file's miss: a guessed path gets the parent's
478
496
  // real contents back, so the next call names something that exists.
479
- if (/No such file or directory|cannot access/i.test(message)) {
497
+ if (/No such file or directory|cannot access|does not exist|ENOENT/i.test(message)) {
480
498
  const parent = path.replace(/\/[^/]*$/, '') || '/';
481
499
  try {
482
500
  const siblings = await backend.readDir(parent);
@@ -703,6 +721,29 @@ export function buildTools(backend, config) {
703
721
  error: `old_string not found in ${path}. The file's ACTUAL content near your target (copy the exact text from here):\n${snippet}`,
704
722
  };
705
723
  };
724
+ // An import block the model rebuilt in its own order: the linter's
725
+ // import sort owns that order, so name it and show the real block. X1
726
+ // flash-m42 sent the same block three times in three orders.
727
+ // Only when old_string is import statements and nothing else.
728
+ const imported = /^(?:\s*import\b[^;]*?\bfrom\s+(['"])([^'"]+)\1;?)+\s*$/.exec(oldString)?.[2];
729
+ if (imported) {
730
+ const at = fileLines.findIndex((l) => l.includes(`'${imported}'`) || l.includes(`"${imported}"`));
731
+ if (at >= 0) {
732
+ let start = at;
733
+ while (start > 0 && !/^\s*import\b/.test(fileLines[start]))
734
+ start--;
735
+ const block = fileLines
736
+ .slice(start, at + 1)
737
+ .map((l, i) => `${start + i + 1}: ${l}`)
738
+ .join('\n');
739
+ return {
740
+ error: `old_string not found in ${path}: it is an import block, and the linter's import ` +
741
+ `sort decides its order, so do not rebuild it. The file's import from ` +
742
+ `'${imported}' reads:\n${block}\nEdit one line of it, or add your import as a ` +
743
+ 'new line and let the linter sort it.',
744
+ };
745
+ }
746
+ }
706
747
  const distinctiveLines = [
707
748
  ...new Set(oldString
708
749
  .split('\n')
@@ -1 +1 @@
1
- {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
package/dist/utilities.js CHANGED
@@ -204,11 +204,14 @@ export function outputIsWithheldUntilExit(command) {
204
204
  * @returns The target as written, or null (`/dev/null` and `&1`/`&2` are not files).
205
205
  */
206
206
  export function outputRedirectTarget(command) {
207
- const tee = /\|\s*tee\s+(?:-a\s+)?([^\s;&|]+)/.exec(command);
207
+ // A heredoc that writes a file (`cat > cfg.ts <<'EOF' … EOF`) is not where the run's output
208
+ // goes: X1 flash-m44 was told its config file was the suite's log.
209
+ const text = command.replace(/[^\n;&|]*<<-?\s*(['"]?)(\w+)\1[\s\S]*?\n\s*\2\b/g, '');
210
+ const tee = /\|\s*tee\s+(?:-a\s+)?([^\s;&|]+)/.exec(text);
208
211
  if (tee)
209
212
  return tee[1];
210
213
  let last = null;
211
- for (const m of command.matchAll(/(?:^|[^0-9&>])(?:&>|1?>>?)\s*([^\s;&|]+)/g)) {
214
+ for (const m of text.matchAll(/(?:^|[^0-9&>])(?:&>|1?>>?)\s*([^\s;&|]+)/g)) {
212
215
  if (m[1] !== '/dev/null' && !m[1].startsWith('&'))
213
216
  last = m[1];
214
217
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-ai-tools",
3
- "version": "1.5.9",
3
+ "version": "1.5.11",
4
4
  "description": "Shared AI agent tools with backend abstraction for sandbox and local execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",