@molecule/api-ai-tools 1.16.5 → 1.16.7

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/README.md CHANGED
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
3
  Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
4
  Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
5
  To change this document, edit the module-level JSDoc in src/index.ts.
6
- Generated: 2026-11-05T15:09:26.641Z
6
+ Generated: 2026-11-06T02:27:22.476Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-ai-tools
@@ -1188,6 +1188,30 @@ interface ExecutionBackend {
1188
1188
  /** Write content to a file. Creates parent directories as needed. */
1189
1189
  writeFile(path: string, content: string): Promise<void>
1190
1190
 
1191
+ /**
1192
+ * Optional single-call path check and bounded text read for write/edit tools.
1193
+ * `realPath` must be resolved before reading; never read outside `symlinkRoot`.
1194
+ * Null `content` means missing; omit it for a native read (large/unreadable text).
1195
+ * Returned text must match readFile's decoding and honor any host file-method wrappers.
1196
+ * Implementations must use this backend's `run` so host command wrappers still apply.
1197
+ */
1198
+ readFileForUpdate?(
1199
+ path: string,
1200
+ symlinkRoot?: string,
1201
+ ): Promise<{ realPath: string; content?: string | null }>
1202
+
1203
+ /**
1204
+ * Optional write followed by the supplied parse command in one transport call.
1205
+ * Null means unsupported BEFORE a successful write; the caller uses writeFile/run.
1206
+ * Never retry a transport error after a write may have landed. After-write and
1207
+ * file-change hooks use the ordinary path so their ordering before parsing stays intact.
1208
+ */
1209
+ writeFileAndCheck?(
1210
+ path: string,
1211
+ content: string,
1212
+ command: string,
1213
+ ): Promise<{ stdout: string; stderr: string; exitCode: number } | null>
1214
+
1191
1215
  /** Delete a file. */
1192
1216
  deleteFile(path: string): Promise<void>
1193
1217
 
@@ -1710,8 +1734,8 @@ function createLocalBackend(projectRoot: string): ExecutionBackend
1710
1734
 
1711
1735
  #### `createSandboxBackend(sandbox, projectRoot)`
1712
1736
 
1713
- Create an ExecutionBackend that delegates to a Docker sandbox instance.
1714
- The sandbox.exec method is inherently safe — it runs inside an isolated Docker container.
1737
+ Create an ExecutionBackend that delegates to an isolated sandbox instance.
1738
+ The sandbox.exec method runs inside the provider's isolated environment.
1715
1739
 
1716
1740
  ```typescript
1717
1741
  function createSandboxBackend(sandbox: SandboxLike, projectRoot?: string): ExecutionBackend
@@ -5655,6 +5679,11 @@ Peer dependencies:
5655
5679
  - `@molecule/api-ai`
5656
5680
 
5657
5681
  - **`yieldOnFirstFailureFor`** can yield one still-running deployed task's concrete diagnostic; callers opt out after a prior wait result or unknown history.
5682
+ - **`wait_for_task` state probes report current progress without guessing log growth.**
5683
+ A call shorter than one normal two-second poll omits both growth and no-growth
5684
+ claims; task age, log counters and time-left estimates remain available.
5685
+ Full waits still report whether the log grew. Hosts that cap a wait should
5686
+ allow its final result read to finish before replacing it with a state probe.
5658
5687
  - **This package only defines the tools — it runs no model loop.** Hand them to
5659
5688
  the bonded AI provider (`chat({ tools, … })`) or to an
5660
5689
  `@molecule/api-ai-agents` run.
@@ -5718,6 +5747,11 @@ Peer dependencies:
5718
5747
  to the model, and execute `catalog.loader` like any other tool. Loading only
5719
5748
  exposes schemas, never grants permission or runs a tool. Persist its loaded
5720
5749
  names with `onLoad` to keep them available across turns and compaction.
5750
+ - **Sandbox writes batch transport work.** The optional backend operations
5751
+ `readFileForUpdate` and `writeFileAndCheck` combine path safety with the old-text
5752
+ read, then the write with its parse check. Diff tracking and redaction checks
5753
+ stay in the tools. Format and change hooks retain their ordering before parsing;
5754
+ large files and backends without these operations use the native file APIs.
5721
5755
  - **Scope the tool set per agent** with `include`/`exclude` — a read-only agent
5722
5756
  should not receive `write_file`/`exec_command`.
5723
5757
  - Outputs are size-capped (`MAX_READ_SIZE`, `MAX_OUTPUT_SIZE`, …) and searches
@@ -0,0 +1,11 @@
1
+ /** Bounded file/command batching for sandbox transports; native file APIs remain the fallback. */
2
+ import type { ExecutionBackend } from '../types.js';
3
+ /**
4
+ * Batch sandbox filesystem work through the backend's current command wrapper.
5
+ * Keeping `this.run` preserves a host's environment and module-resolution prelude.
6
+ *
7
+ * @param native - Original file delegates; host overrides must not be bypassed.
8
+ * @returns Optional backend operations that retain native fallbacks for large files.
9
+ */
10
+ export declare function sandboxFileOperations(native: Pick<ExecutionBackend, 'readFile' | 'writeFile'>): Pick<ExecutionBackend, 'readFileForUpdate' | 'writeFileAndCheck'>;
11
+ //# sourceMappingURL=sandbox-file-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-file-operations.d.ts","sourceRoot":"","sources":["../../src/backends/sandbox-file-operations.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAElG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAenD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,WAAW,CAAC,GACvD,IAAI,CAAC,gBAAgB,EAAE,mBAAmB,GAAG,mBAAmB,CAAC,CA2FnE"}
@@ -0,0 +1,100 @@
1
+ /** Bounded file/command batching for sandbox transports; native file APIs remain the fallback. */
2
+ import { shellQuote } from '../utilities.js';
3
+ // envd may truncate command output; Docker also caps a shell argument at 128 KiB.
4
+ // Keep both envelopes small, and accept a read only after its complete JSON arrives.
5
+ const MAX_ENVELOPE = 24_000;
6
+ const WRITE_MARK = 'MOL_FILE_WRITTEN\n';
7
+ const NO_WRITE_MARK = 'MOL_FILE_NOT_WRITTEN\n';
8
+ // Native text APIs may strip an initial UTF-8 BOM (Response.text), whereas
9
+ // command envelopes preserve it. Keep that provider-specific decoding on the native path.
10
+ const READ_SCRIPT = `const fs=require('fs'),cp=require('child_process');const p=process.argv[1],root=process.argv[2];let realPath='';if(root){const r=cp.spawnSync('readlink',['-f',p],{encoding:'utf8'});realPath=(r.status===0?r.stdout:p).trim()}let out={realPath};if(!root||!realPath||realPath===root||realPath.startsWith(root==='/'?'/':root+'/')){try{if(fs.statSync(p).size<=24000){const content=fs.readFileSync(p,'utf8');if(content.charCodeAt(0)!==65279&&Buffer.byteLength(JSON.stringify({realPath,content}))<=24000)out={realPath,content}}}catch(e){if(e.code==='ENOENT'||e.code==='ENOTDIR')out.content=null;/* other errors use the native API */}}process.stdout.write(JSON.stringify(out))`;
11
+ const WRITE_SCRIPT = `const fs=require('fs'),cp=require('child_process'),path=require('path');const r=JSON.parse(Buffer.from(process.argv[1],'base64').toString('utf8'));try{fs.mkdirSync(path.dirname(r.path),{recursive:true});fs.writeFileSync(r.path,r.content,'utf8')}catch(e){process.stdout.write('MOL_FILE_NOT_WRITTEN\\n');process.exit(1)}process.stdout.write('MOL_FILE_WRITTEN\\n');const c=cp.spawnSync('sh',['-c',r.command],{cwd:path.dirname(r.path),encoding:'utf8',timeout:15000,maxBuffer:10*1024*1024});process.stdout.write(JSON.stringify({stdout:c.stdout||'',stderr:c.stderr||'',exitCode:c.status??1}))`;
12
+ /**
13
+ * Batch sandbox filesystem work through the backend's current command wrapper.
14
+ * Keeping `this.run` preserves a host's environment and module-resolution prelude.
15
+ *
16
+ * @param native - Original file delegates; host overrides must not be bypassed.
17
+ * @returns Optional backend operations that retain native fallbacks for large files.
18
+ */
19
+ export function sandboxFileOperations(native) {
20
+ let supported = false;
21
+ const { readFile, writeFile } = native;
22
+ return {
23
+ async readFileForUpdate(path, symlinkRoot) {
24
+ const q = shellQuote(path);
25
+ // The native API may resolve relative paths against a different base than exec.
26
+ if (!path.startsWith('/') || this.readFile !== readFile) {
27
+ if (!symlinkRoot)
28
+ return { realPath: '' };
29
+ const checked = await this.run(`readlink -f ${q} 2>/dev/null || echo ${q}`, {
30
+ timeout: 5000,
31
+ });
32
+ return { realPath: checked.stdout.trim() };
33
+ }
34
+ const result = await this.run(`node -e ${shellQuote(READ_SCRIPT)} ${q} ${shellQuote(symlinkRoot ?? '')}`, {
35
+ timeout: 5000,
36
+ });
37
+ try {
38
+ const body = JSON.parse(result.stdout);
39
+ if (body &&
40
+ typeof body === 'object' &&
41
+ 'realPath' in body &&
42
+ typeof body.realPath === 'string') {
43
+ supported = true;
44
+ if ('content' in body && (typeof body.content === 'string' || body.content === null))
45
+ return { realPath: body.realPath, content: body.content };
46
+ return { realPath: body.realPath };
47
+ }
48
+ }
49
+ catch (_error) {
50
+ // Missing Node or truncated/malformed stdout cannot supply file contents.
51
+ }
52
+ supported = false;
53
+ if (!symlinkRoot)
54
+ return { realPath: '' };
55
+ // Native path verification still decides safety when batching is unavailable.
56
+ const checked = await this.run(`readlink -f ${q} 2>/dev/null || echo ${q}`, { timeout: 5000 });
57
+ return { realPath: checked.stdout.trim() };
58
+ },
59
+ async writeFileAndCheck(path, content, command) {
60
+ if (!path.startsWith('/') || !supported || this.writeFile !== writeFile)
61
+ return null;
62
+ const request = Buffer.from(JSON.stringify({ path, content, command })).toString('base64');
63
+ if (request.length > MAX_ENVELOPE)
64
+ return null;
65
+ const result = await this.run(`node -e ${shellQuote(WRITE_SCRIPT)} ${shellQuote(request)}`, {
66
+ // The target's parent may be created by this very write. The child parse
67
+ // command enters it only after mkdir/write have succeeded.
68
+ cwd: this.projectRoot,
69
+ timeout: 20_000,
70
+ });
71
+ if (!result.stdout.startsWith(WRITE_MARK)) {
72
+ // No successful write acknowledged (e.g. no Node or a filesystem error).
73
+ // The native API retains its provider-specific error and directory behavior.
74
+ if (result.stdout.startsWith(NO_WRITE_MARK) ||
75
+ (result.exitCode === 127 && /node.*not found/.test(result.stderr)))
76
+ return null;
77
+ throw new Error('Sandbox file write returned no completion acknowledgement; not retrying an uncertain write');
78
+ }
79
+ try {
80
+ const check = JSON.parse(result.stdout.slice(WRITE_MARK.length));
81
+ if (typeof check.stdout === 'string' &&
82
+ typeof check.stderr === 'string' &&
83
+ typeof check.exitCode === 'number')
84
+ return check;
85
+ }
86
+ catch (_error) {
87
+ // The write succeeded, but its check output was truncated. Recheck only;
88
+ // never replay an acknowledged write or a failed transport.
89
+ }
90
+ return this.run(command, {
91
+ cwd: path.slice(0, path.lastIndexOf('/')) || '/',
92
+ timeout: 15_000,
93
+ }).catch((_error) => {
94
+ // Like the ordinary post-write check, an unavailable parser adds no syntax note.
95
+ // The write was acknowledged above, so only the best-effort check failed here.
96
+ return { stdout: '', stderr: '', exitCode: 0 };
97
+ });
98
+ },
99
+ };
100
+ }
@@ -14,12 +14,12 @@ interface SandboxLike {
14
14
  name: string;
15
15
  type: 'file' | 'directory';
16
16
  }>>;
17
- /** Sandbox command execution — already sandboxed within Docker. */
17
+ /** Sandbox command execution — already isolated by the provider. */
18
18
  [key: string]: any;
19
19
  }
20
20
  /**
21
- * Create an ExecutionBackend that delegates to a Docker sandbox instance.
22
- * The sandbox.exec method is inherently safe — it runs inside an isolated Docker container.
21
+ * Create an ExecutionBackend that delegates to an isolated sandbox instance.
22
+ * The sandbox.exec method runs inside the provider's isolated environment.
23
23
  *
24
24
  * @param sandbox - A running Sandbox instance from `@molecule/api-code-sandbox`
25
25
  * @param projectRoot - Root directory inside the sandbox (default: '/workspace')
@@ -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,CAmDlB"}
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;AAInD,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,oEAAoE;IAEpE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,WAAW,EACpB,WAAW,SAAe,GACzB,gBAAgB,CAuDlB"}
@@ -5,16 +5,17 @@
5
5
  * @module
6
6
  */
7
7
  import { shellQuote } from '../utilities.js';
8
+ import { sandboxFileOperations } from './sandbox-file-operations.js';
8
9
  /**
9
- * Create an ExecutionBackend that delegates to a Docker sandbox instance.
10
- * The sandbox.exec method is inherently safe — it runs inside an isolated Docker container.
10
+ * Create an ExecutionBackend that delegates to an isolated sandbox instance.
11
+ * The sandbox.exec method runs inside the provider's isolated environment.
11
12
  *
12
13
  * @param sandbox - A running Sandbox instance from `@molecule/api-code-sandbox`
13
14
  * @param projectRoot - Root directory inside the sandbox (default: '/workspace')
14
15
  * @returns A backend that proxies all filesystem calls into the sandbox.
15
16
  */
16
17
  export function createSandboxBackend(sandbox, projectRoot = '/workspace') {
17
- return {
18
+ const backend = {
18
19
  projectRoot,
19
20
  readFile(path) {
20
21
  return sandbox.readFile(path);
@@ -54,9 +55,10 @@ export function createSandboxBackend(sandbox, projectRoot = '/workspace') {
54
55
  const fullCommand = budgetSeconds
55
56
  ? `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`
56
57
  : anchored;
57
- // sandbox.exec is the Sandbox interface method — runs inside Docker, inherently sandboxed
58
+ // sandbox.exec is the Sandbox interface method — runs inside the provider's isolated environment
58
59
  const result = await sandbox.exec(fullCommand, { timeout: opts?.timeout });
59
60
  return { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode };
60
61
  },
61
62
  };
63
+ return Object.assign(backend, typeof sandbox.exec === 'function' ? sandboxFileOperations(backend) : {});
62
64
  }
package/dist/index.d.ts CHANGED
@@ -13,6 +13,11 @@
13
13
  *
14
14
  * @remarks
15
15
  * - **`yieldOnFirstFailureFor`** can yield one still-running deployed task's concrete diagnostic; callers opt out after a prior wait result or unknown history.
16
+ * - **`wait_for_task` state probes report current progress without guessing log growth.**
17
+ * A call shorter than one normal two-second poll omits both growth and no-growth
18
+ * claims; task age, log counters and time-left estimates remain available.
19
+ * Full waits still report whether the log grew. Hosts that cap a wait should
20
+ * allow its final result read to finish before replacing it with a state probe.
16
21
  * - **This package only defines the tools — it runs no model loop.** Hand them to
17
22
  * the bonded AI provider (`chat({ tools, … })`) or to an
18
23
  * `@molecule/api-ai-agents` run.
@@ -76,6 +81,11 @@
76
81
  * to the model, and execute `catalog.loader` like any other tool. Loading only
77
82
  * exposes schemas, never grants permission or runs a tool. Persist its loaded
78
83
  * names with `onLoad` to keep them available across turns and compaction.
84
+ * - **Sandbox writes batch transport work.** The optional backend operations
85
+ * `readFileForUpdate` and `writeFileAndCheck` combine path safety with the old-text
86
+ * read, then the write with its parse check. Diff tracking and redaction checks
87
+ * stay in the tools. Format and change hooks retain their ordering before parsing;
88
+ * large files and backends without these operations use the native file APIs.
79
89
  * - **Scope the tool set per agent** with `include`/`exclude` — a read-only agent
80
90
  * should not receive `write_file`/`exec_command`.
81
91
  * - Outputs are size-capped (`MAX_READ_SIZE`, `MAX_OUTPUT_SIZE`, …) and searches
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwIG;AAEH,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAA;AACnC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA;AAC1B,cAAc,sBAAsB,CAAA;AACpC,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkJG;AAEH,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAA;AACnC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA;AAC1B,cAAc,sBAAsB,CAAA;AACpC,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -13,6 +13,11 @@
13
13
  *
14
14
  * @remarks
15
15
  * - **`yieldOnFirstFailureFor`** can yield one still-running deployed task's concrete diagnostic; callers opt out after a prior wait result or unknown history.
16
+ * - **`wait_for_task` state probes report current progress without guessing log growth.**
17
+ * A call shorter than one normal two-second poll omits both growth and no-growth
18
+ * claims; task age, log counters and time-left estimates remain available.
19
+ * Full waits still report whether the log grew. Hosts that cap a wait should
20
+ * allow its final result read to finish before replacing it with a state probe.
16
21
  * - **This package only defines the tools — it runs no model loop.** Hand them to
17
22
  * the bonded AI provider (`chat({ tools, … })`) or to an
18
23
  * `@molecule/api-ai-agents` run.
@@ -76,6 +81,11 @@
76
81
  * to the model, and execute `catalog.loader` like any other tool. Loading only
77
82
  * exposes schemas, never grants permission or runs a tool. Persist its loaded
78
83
  * names with `onLoad` to keep them available across turns and compaction.
84
+ * - **Sandbox writes batch transport work.** The optional backend operations
85
+ * `readFileForUpdate` and `writeFileAndCheck` combine path safety with the old-text
86
+ * read, then the write with its parse check. Diff tracking and redaction checks
87
+ * stay in the tools. Format and change hooks retain their ordering before parsing;
88
+ * large files and backends without these operations use the native file APIs.
79
89
  * - **Scope the tool set per agent** with `include`/`exclude` — a read-only agent
80
90
  * should not receive `write_file`/`exec_command`.
81
91
  * - Outputs are size-capped (`MAX_READ_SIZE`, `MAX_OUTPUT_SIZE`, …) and searches
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AA2B9C,OAAO,EAIL,KAAK,mBAAmB,EAEzB,MAAM,wBAAwB,CAAA;AAsC/B;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,KAAK,CAAC,EACnD,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GACjC,OAAO,CAAC,mBAAmB,CAAC,CAmB9B;AAuLD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAahG;AAwdD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAkInE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAEA,CAAA;AAE9B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,QAI6C,CAAA;AA0DlF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUhE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGtE;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;AAoBpF;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAC,GACxE,qBAAqB,CAkBvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiCxB;AA2GD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAypGxF"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AA2B9C,OAAO,EAIL,KAAK,mBAAmB,EAEzB,MAAM,wBAAwB,CAAA;AAsC/B;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,KAAK,CAAC,EACnD,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GACjC,OAAO,CAAC,mBAAmB,CAAC,CAmB9B;AAuLD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAahG;AAkeD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAkInE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAEA,CAAA;AAE9B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,QAI6C,CAAA;AA0DlF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUhE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGtE;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;AAoBpF;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAC,GACxE,qBAAqB,CAkBvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiCxB;AA2GD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CA0sGxF"}
package/dist/tools.js CHANGED
@@ -273,6 +273,8 @@ export async function taskStopCommand(backend, taskId) {
273
273
  * ended in 20).
274
274
  */
275
275
  const TASK_END_LOOK_MS = 3_000;
276
+ /** A normal task poll; shorter state probes cannot establish log growth during their wait. */
277
+ const TASK_POLL_MS = 2_000;
276
278
  /** How much of a task's own output the end test reads — a runner's tally is its last lines. */
277
279
  const TASK_OUTPUT_END_BYTES = 4_000;
278
280
  /**
@@ -530,8 +532,11 @@ function secondSuiteWalk(slice) {
530
532
  * @param o - The wait's facts: `taskId`, the `slice` of the log it read,
531
533
  * `stillWriting` (the log grew during this wait), `bytes` (the log's size, null
532
534
  * when unreadable), `ceilingMs` (this call's ceiling, for "one more wait"), and
533
- * `waitedMs` (this call's own wait, the elapsed figure when the id carries no
534
- * start stamp).
535
+ * `waitedMs` (the elapsed floor when the id carries no start stamp), and
536
+ * `observationMs` (this call's own polling interval, excluding earlier waits).
537
+ * Growth clauses require at least one normal poll: a near-zero state probe
538
+ * observes the log's contents, not whether it grew during the preceding wait.
539
+ * Task age, progress counters and rate estimates remain valid for those probes.
535
540
  * @returns The clauses in reading order. The first states the elapsed time, so a
536
541
  * sentence built from them always says something.
537
542
  */
@@ -549,10 +554,12 @@ function waitProgressClauses(o) {
549
554
  // A log that already finished one walk and started another says so instead of "slow, not
550
555
  // stuck": the growth is the SECOND walk printing, and its counter is not this run's progress.
551
556
  const secondWalk = secondSuiteWalk(o.slice);
552
- if (o.stillWriting && !secondWalk)
553
- clauses.push(`its output is still growing (${o.bytes} bytes) — slow, not stuck`);
554
- else if (o.bytes !== null && !secondWalk)
555
- clauses.push(`its log has not grown during this wait (${o.bytes} bytes)`);
557
+ if (o.observationMs >= TASK_POLL_MS && !secondWalk) {
558
+ if (o.stillWriting)
559
+ clauses.push(`its output is still growing (${o.bytes} bytes) — slow, not stuck`);
560
+ else if (o.bytes !== null)
561
+ clauses.push(`its log has not grown during this wait (${o.bytes} bytes)`);
562
+ }
556
563
  if (secondWalk)
557
564
  clauses.push(`the first walk in this command has finished (${secondWalk.tally}); the command started a ` +
558
565
  'SECOND walk of the same suite — stop it (it measures nothing new) and read the first tally');
@@ -680,6 +687,7 @@ async function backgroundTaskState(backend, command, seconds, ceilingMs) {
680
687
  bytes: null,
681
688
  ceilingMs,
682
689
  waitedMs: 0,
690
+ observationMs: 0,
683
691
  });
684
692
  const failures = slice.trim() ? '; the failures already in its log are in outputSoFar' : '';
685
693
  return {
@@ -1137,13 +1145,14 @@ export function buildTools(backend, config) {
1137
1145
  * is ~50 ms; the executor sees the exact line while the edit is still in
1138
1146
  * front of it.
1139
1147
  */
1140
- async function syntaxErrorAfterWrite(path) {
1148
+ async function syntaxErrorAfterWrite(path, checked) {
1141
1149
  const command = parseCheckCommand(path);
1142
1150
  if (!command)
1143
1151
  return {};
1144
- const result = await backend
1145
- .run(command, { cwd: path.slice(0, path.lastIndexOf('/')) || '/', timeout: 15_000 })
1146
- .catch(() => null);
1152
+ const result = checked ??
1153
+ (await backend
1154
+ .run(command, { cwd: path.slice(0, path.lastIndexOf('/')) || '/', timeout: 15_000 })
1155
+ .catch(() => null));
1147
1156
  const problem = result ? parseCheckProblem(result) : null;
1148
1157
  // JSX in a `.ts` file parses as a type assertion and fails on the first
1149
1158
  // attribute — `Expected ">" but found "className"` — which does not say the
@@ -1224,7 +1233,7 @@ export function buildTools(backend, config) {
1224
1233
  * @param path - Candidate filesystem path after `resolve()`.
1225
1234
  * @returns An error message when unsafe, otherwise `null`.
1226
1235
  */
1227
- async function checkSymlink(path) {
1236
+ async function checkSymlink(path, probe) {
1228
1237
  if (!symlinkGuards)
1229
1238
  return null;
1230
1239
  // The retry budget is failure-aware. A plain slow answer gets ONE quick retry
@@ -1241,7 +1250,9 @@ export function buildTools(backend, config) {
1241
1250
  attempts++;
1242
1251
  const started = Date.now();
1243
1252
  try {
1244
- const result = await backend.run(`readlink -f ${shellQuote(path)} 2>/dev/null || echo ${shellQuote(path)}`, { timeout: 5000 });
1253
+ const result = probe
1254
+ ? await probe()
1255
+ : await backend.run(`readlink -f ${shellQuote(path)} 2>/dev/null || echo ${shellQuote(path)}`, { timeout: 5000 });
1245
1256
  const realPath = result.stdout.trim();
1246
1257
  if (realPath &&
1247
1258
  realPath !== root &&
@@ -1278,6 +1289,37 @@ export function buildTools(backend, config) {
1278
1289
  return (`Unable to verify path safety: the sandbox's command channel failed (${err?.name ?? 'Error'}: ${String(err?.message ?? err).slice(0, 160)}), ` +
1279
1290
  'so the path was refused to stay safe. Retry the call; if every file tool fails this way, the sandbox needs a restart.');
1280
1291
  }
1292
+ /** Guard and old-text read share a transport when the backend offers it. */
1293
+ async function readBeforeWrite(path) {
1294
+ let content;
1295
+ if (!backend.readFileForUpdate)
1296
+ return { error: await checkSymlink(path) };
1297
+ const probe = async () => {
1298
+ const result = await backend.readFileForUpdate(path, symlinkGuards ? root : undefined);
1299
+ content = result.content;
1300
+ return { stdout: result.realPath };
1301
+ };
1302
+ if (symlinkGuards)
1303
+ return { error: await checkSymlink(path, probe), content };
1304
+ try {
1305
+ await probe();
1306
+ }
1307
+ catch (_error) {
1308
+ // No safety check was requested; a failed optimization leaves the native read in charge.
1309
+ }
1310
+ return { error: null, content };
1311
+ }
1312
+ /** A formatter needs its original write/hook/reread/check ordering. */
1313
+ async function writeAndCheck(path, content) {
1314
+ const command = parseCheckCommand(path);
1315
+ if (!onAfterWrite && !onFileChange && command && backend.writeFileAndCheck) {
1316
+ const result = await backend.writeFileAndCheck(path, content, command);
1317
+ if (result !== null)
1318
+ return result;
1319
+ }
1320
+ await backend.writeFile(path, content);
1321
+ return null;
1322
+ }
1281
1323
  /**
1282
1324
  * Strip control characters and optionally redact secrets from tool output.
1283
1325
  *
@@ -1960,13 +2002,13 @@ export function buildTools(backend, config) {
1960
2002
  return {
1961
2003
  error: `Content too large (${Math.round(content.length / 1024)}KB). Maximum is ${MAX_WRITE_SIZE / 1024 / 1024}MB.`,
1962
2004
  };
1963
- const symlinkErr = await checkSymlink(path);
1964
- if (symlinkErr)
1965
- return { error: symlinkErr };
2005
+ const before = await readBeforeWrite(path);
2006
+ if (before.error)
2007
+ return { error: before.error };
1966
2008
  try {
1967
2009
  let oldContent = null;
1968
2010
  try {
1969
- oldContent = await backend.readFile(path);
2011
+ oldContent = before.content !== undefined ? before.content : await backend.readFile(path);
1970
2012
  }
1971
2013
  catch (_error) {
1972
2014
  /* file doesn't exist yet — oldContent stays null */
@@ -1980,7 +2022,7 @@ export function buildTools(backend, config) {
1980
2022
  }
1981
2023
  if (onFileDiff)
1982
2024
  onFileDiff({ path, oldContent, newContent: content });
1983
- await backend.writeFile(path, content);
2025
+ const checked = await writeAndCheck(path, content);
1984
2026
  if (onAfterWrite)
1985
2027
  await onAfterWrite(path).catch(() => { });
1986
2028
  // The text on disk is the text just written unless an after-write hook (a formatter)
@@ -2003,7 +2045,7 @@ export function buildTools(backend, config) {
2003
2045
  diff,
2004
2046
  totalLines: countLines(finalContent),
2005
2047
  ...(echo !== null ? { excerpt: sanitizeFileContent(echo, path) } : {}),
2006
- ...(await syntaxErrorAfterWrite(path)),
2048
+ ...(await syntaxErrorAfterWrite(path, checked)),
2007
2049
  };
2008
2050
  }
2009
2051
  catch (e) {
@@ -2059,11 +2101,11 @@ export function buildTools(backend, config) {
2059
2101
  return {
2060
2102
  error: 'No replacements provided. Use { replacements: [{ old_string, new_string }] } or { old_string, new_string }.',
2061
2103
  };
2062
- const symlinkErr = await checkSymlink(path);
2063
- if (symlinkErr)
2064
- return { error: symlinkErr };
2104
+ const before = await readBeforeWrite(path);
2105
+ if (before.error)
2106
+ return { error: before.error };
2065
2107
  try {
2066
- let content = await backend.readFile(path);
2108
+ let content = before.content ?? (await backend.readFile(path));
2067
2109
  // A transiently-empty read here made every old_string "not found", which
2068
2110
  // steers the model to re-read and then rewrite a file it never saw. Same
2069
2111
  // verification as read_file: empty is only believed once it is confirmed.
@@ -2442,7 +2484,7 @@ export function buildTools(backend, config) {
2442
2484
  }
2443
2485
  if (onFileDiff)
2444
2486
  onFileDiff({ path, oldContent, newContent: content });
2445
- await backend.writeFile(path, content);
2487
+ const checked = await writeAndCheck(path, content);
2446
2488
  if (onAfterWrite)
2447
2489
  await onAfterWrite(path).catch(() => { });
2448
2490
  if (onFileChange)
@@ -2475,7 +2517,7 @@ export function buildTools(backend, config) {
2475
2517
  r.old_string.endsWith('\n') &&
2476
2518
  r.new_string !== '' &&
2477
2519
  !r.new_string.endsWith('\n'));
2478
- const syntax = await syntaxErrorAfterWrite(path);
2520
+ const syntax = await syntaxErrorAfterWrite(path, checked);
2479
2521
  // A parse error and a dropped line break are two OBSERVATIONS, not one
2480
2522
  // accident. A join only sometimes breaks the syntax (same-line JSX siblings
2481
2523
  // parse), and the diagnostic usually comes from something else in the same
@@ -3602,7 +3644,7 @@ export function buildTools(backend, config) {
3602
3644
  let endedWithoutCode = false;
3603
3645
  let exitCode = await readExit();
3604
3646
  while (exitCode === null && Date.now() - startedAt < budgetMs) {
3605
- await new Promise((r) => setTimeout(r, Math.min(2_000, budgetMs - (Date.now() - startedAt))));
3647
+ await new Promise((r) => setTimeout(r, Math.min(TASK_POLL_MS, budgetMs - (Date.now() - startedAt))));
3606
3648
  exitCode = await readExit();
3607
3649
  // The exit file is read first, so a run that finishes between two looks still returns
3608
3650
  // its real result instead of a note about it.
@@ -3794,6 +3836,7 @@ export function buildTools(backend, config) {
3794
3836
  bytes: grownTo,
3795
3837
  ceilingMs: ceiling,
3796
3838
  waitedMs: waitedBefore + waitedMs,
3839
+ observationMs: Math.min(budgetMs, waitedMs),
3797
3840
  }));
3798
3841
  const sliceField = soFar.trim() ? { outputSoFar: sanitizeOutput(soFar) } : {};
3799
3842
  // What this wait found mid-run, when it was not a reason to end early: it rides the result
package/dist/types.d.ts CHANGED
@@ -22,6 +22,28 @@ export interface ExecutionBackend {
22
22
  readFile(path: string): Promise<string>;
23
23
  /** Write content to a file. Creates parent directories as needed. */
24
24
  writeFile(path: string, content: string): Promise<void>;
25
+ /**
26
+ * Optional single-call path check and bounded text read for write/edit tools.
27
+ * `realPath` must be resolved before reading; never read outside `symlinkRoot`.
28
+ * Null `content` means missing; omit it for a native read (large/unreadable text).
29
+ * Returned text must match readFile's decoding and honor any host file-method wrappers.
30
+ * Implementations must use this backend's `run` so host command wrappers still apply.
31
+ */
32
+ readFileForUpdate?(path: string, symlinkRoot?: string): Promise<{
33
+ realPath: string;
34
+ content?: string | null;
35
+ }>;
36
+ /**
37
+ * Optional write followed by the supplied parse command in one transport call.
38
+ * Null means unsupported BEFORE a successful write; the caller uses writeFile/run.
39
+ * Never retry a transport error after a write may have landed. After-write and
40
+ * file-change hooks use the ordinary path so their ordering before parsing stays intact.
41
+ */
42
+ writeFileAndCheck?(path: string, content: string, command: string): Promise<{
43
+ stdout: string;
44
+ stderr: string;
45
+ exitCode: number;
46
+ } | null>;
25
47
  /** Delete a file. */
26
48
  deleteFile(path: string): Promise<void>;
27
49
  /** List entries in a directory. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-ai-tools",
3
- "version": "1.16.5",
3
+ "version": "1.16.7",
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",