@librechat/agents 3.1.77 → 3.1.78

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.
Files changed (185) hide show
  1. package/dist/cjs/common/enum.cjs +54 -0
  2. package/dist/cjs/common/enum.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +155 -4
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +291 -0
  6. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs.map +1 -0
  7. package/dist/cjs/main.cjs +90 -0
  8. package/dist/cjs/main.cjs.map +1 -1
  9. package/dist/cjs/messages/anthropicToolCache.cjs +102 -0
  10. package/dist/cjs/messages/anthropicToolCache.cjs.map +1 -0
  11. package/dist/cjs/messages/prune.cjs +27 -0
  12. package/dist/cjs/messages/prune.cjs.map +1 -1
  13. package/dist/cjs/messages/recency.cjs +99 -0
  14. package/dist/cjs/messages/recency.cjs.map +1 -0
  15. package/dist/cjs/run.cjs +30 -0
  16. package/dist/cjs/run.cjs.map +1 -1
  17. package/dist/cjs/summarization/node.cjs +100 -6
  18. package/dist/cjs/summarization/node.cjs.map +1 -1
  19. package/dist/cjs/tools/ToolNode.cjs +635 -23
  20. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  21. package/dist/cjs/tools/local/CompileCheckTool.cjs +227 -0
  22. package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -0
  23. package/dist/cjs/tools/local/FileCheckpointer.cjs +90 -0
  24. package/dist/cjs/tools/local/FileCheckpointer.cjs.map +1 -0
  25. package/dist/cjs/tools/local/LocalCodingTools.cjs +1098 -0
  26. package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -0
  27. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +1042 -0
  28. package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -0
  29. package/dist/cjs/tools/local/LocalExecutionTools.cjs +122 -0
  30. package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -0
  31. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +453 -0
  32. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -0
  33. package/dist/cjs/tools/local/attachments.cjs +183 -0
  34. package/dist/cjs/tools/local/attachments.cjs.map +1 -0
  35. package/dist/cjs/tools/local/bashAst.cjs +129 -0
  36. package/dist/cjs/tools/local/bashAst.cjs.map +1 -0
  37. package/dist/cjs/tools/local/editStrategies.cjs +188 -0
  38. package/dist/cjs/tools/local/editStrategies.cjs.map +1 -0
  39. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +141 -0
  40. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -0
  41. package/dist/cjs/tools/local/syntaxCheck.cjs +182 -0
  42. package/dist/cjs/tools/local/syntaxCheck.cjs.map +1 -0
  43. package/dist/cjs/tools/local/textEncoding.cjs +30 -0
  44. package/dist/cjs/tools/local/textEncoding.cjs.map +1 -0
  45. package/dist/cjs/tools/local/workspaceFS.cjs +51 -0
  46. package/dist/cjs/tools/local/workspaceFS.cjs.map +1 -0
  47. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +31 -0
  48. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  49. package/dist/esm/common/enum.mjs +53 -1
  50. package/dist/esm/common/enum.mjs.map +1 -1
  51. package/dist/esm/graphs/Graph.mjs +156 -5
  52. package/dist/esm/graphs/Graph.mjs.map +1 -1
  53. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +289 -0
  54. package/dist/esm/hooks/createWorkspacePolicyHook.mjs.map +1 -0
  55. package/dist/esm/main.mjs +17 -2
  56. package/dist/esm/main.mjs.map +1 -1
  57. package/dist/esm/messages/anthropicToolCache.mjs +99 -0
  58. package/dist/esm/messages/anthropicToolCache.mjs.map +1 -0
  59. package/dist/esm/messages/prune.mjs +26 -1
  60. package/dist/esm/messages/prune.mjs.map +1 -1
  61. package/dist/esm/messages/recency.mjs +97 -0
  62. package/dist/esm/messages/recency.mjs.map +1 -0
  63. package/dist/esm/run.mjs +30 -0
  64. package/dist/esm/run.mjs.map +1 -1
  65. package/dist/esm/summarization/node.mjs +100 -6
  66. package/dist/esm/summarization/node.mjs.map +1 -1
  67. package/dist/esm/tools/ToolNode.mjs +635 -23
  68. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  69. package/dist/esm/tools/local/CompileCheckTool.mjs +223 -0
  70. package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -0
  71. package/dist/esm/tools/local/FileCheckpointer.mjs +87 -0
  72. package/dist/esm/tools/local/FileCheckpointer.mjs.map +1 -0
  73. package/dist/esm/tools/local/LocalCodingTools.mjs +1075 -0
  74. package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -0
  75. package/dist/esm/tools/local/LocalExecutionEngine.mjs +1022 -0
  76. package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -0
  77. package/dist/esm/tools/local/LocalExecutionTools.mjs +117 -0
  78. package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -0
  79. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +448 -0
  80. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -0
  81. package/dist/esm/tools/local/attachments.mjs +180 -0
  82. package/dist/esm/tools/local/attachments.mjs.map +1 -0
  83. package/dist/esm/tools/local/bashAst.mjs +126 -0
  84. package/dist/esm/tools/local/bashAst.mjs.map +1 -0
  85. package/dist/esm/tools/local/editStrategies.mjs +185 -0
  86. package/dist/esm/tools/local/editStrategies.mjs.map +1 -0
  87. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +137 -0
  88. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -0
  89. package/dist/esm/tools/local/syntaxCheck.mjs +179 -0
  90. package/dist/esm/tools/local/syntaxCheck.mjs.map +1 -0
  91. package/dist/esm/tools/local/textEncoding.mjs +27 -0
  92. package/dist/esm/tools/local/textEncoding.mjs.map +1 -0
  93. package/dist/esm/tools/local/workspaceFS.mjs +49 -0
  94. package/dist/esm/tools/local/workspaceFS.mjs.map +1 -0
  95. package/dist/esm/tools/subagent/SubagentExecutor.mjs +31 -0
  96. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  97. package/dist/types/common/enum.d.ts +39 -1
  98. package/dist/types/graphs/Graph.d.ts +34 -0
  99. package/dist/types/hooks/createWorkspacePolicyHook.d.ts +95 -0
  100. package/dist/types/hooks/index.d.ts +2 -0
  101. package/dist/types/index.d.ts +1 -0
  102. package/dist/types/messages/anthropicToolCache.d.ts +51 -0
  103. package/dist/types/messages/index.d.ts +2 -0
  104. package/dist/types/messages/prune.d.ts +11 -0
  105. package/dist/types/messages/recency.d.ts +64 -0
  106. package/dist/types/run.d.ts +21 -0
  107. package/dist/types/tools/ToolNode.d.ts +145 -2
  108. package/dist/types/tools/local/CompileCheckTool.d.ts +31 -0
  109. package/dist/types/tools/local/FileCheckpointer.d.ts +39 -0
  110. package/dist/types/tools/local/LocalCodingTools.d.ts +57 -0
  111. package/dist/types/tools/local/LocalExecutionEngine.d.ts +149 -0
  112. package/dist/types/tools/local/LocalExecutionTools.d.ts +9 -0
  113. package/dist/types/tools/local/LocalProgrammaticToolCalling.d.ts +21 -0
  114. package/dist/types/tools/local/attachments.d.ts +84 -0
  115. package/dist/types/tools/local/bashAst.d.ts +11 -0
  116. package/dist/types/tools/local/editStrategies.d.ts +28 -0
  117. package/dist/types/tools/local/index.d.ts +12 -0
  118. package/dist/types/tools/local/resolveLocalExecutionTools.d.ts +38 -0
  119. package/dist/types/tools/local/syntaxCheck.d.ts +42 -0
  120. package/dist/types/tools/local/textEncoding.d.ts +21 -0
  121. package/dist/types/tools/local/workspaceFS.d.ts +49 -0
  122. package/dist/types/tools/subagent/SubagentExecutor.d.ts +29 -0
  123. package/dist/types/types/hitl.d.ts +56 -27
  124. package/dist/types/types/run.d.ts +8 -1
  125. package/dist/types/types/summarize.d.ts +30 -0
  126. package/dist/types/types/tools.d.ts +341 -6
  127. package/package.json +21 -2
  128. package/src/common/enum.ts +54 -0
  129. package/src/graphs/Graph.ts +173 -6
  130. package/src/hooks/__tests__/compactHooks.test.ts +38 -2
  131. package/src/hooks/__tests__/createWorkspacePolicyHook.test.ts +393 -0
  132. package/src/hooks/createWorkspacePolicyHook.ts +355 -0
  133. package/src/hooks/index.ts +6 -0
  134. package/src/index.ts +1 -0
  135. package/src/messages/__tests__/anthropicToolCache.test.ts +125 -0
  136. package/src/messages/__tests__/recency.test.ts +267 -0
  137. package/src/messages/anthropicToolCache.ts +116 -0
  138. package/src/messages/index.ts +2 -0
  139. package/src/messages/prune.ts +27 -1
  140. package/src/messages/recency.ts +155 -0
  141. package/src/run.ts +31 -0
  142. package/src/scripts/compare_pi_vs_ours.ts +840 -0
  143. package/src/scripts/local_engine.ts +166 -0
  144. package/src/scripts/local_engine_checkpointer.ts +205 -0
  145. package/src/scripts/local_engine_compile.ts +263 -0
  146. package/src/scripts/local_engine_hooks.ts +226 -0
  147. package/src/scripts/local_engine_image.ts +201 -0
  148. package/src/scripts/local_engine_ptc.ts +151 -0
  149. package/src/scripts/local_engine_workspace.ts +258 -0
  150. package/src/scripts/subagent-configurable-inheritance.ts +252 -0
  151. package/src/scripts/summarization-recency.ts +462 -0
  152. package/src/specs/prune.test.ts +39 -0
  153. package/src/summarization/__tests__/node.test.ts +499 -3
  154. package/src/summarization/node.ts +124 -7
  155. package/src/tools/ToolNode.ts +769 -20
  156. package/src/tools/__tests__/LocalExecutionTools.test.ts +2647 -0
  157. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +175 -0
  158. package/src/tools/__tests__/SubagentExecutor.test.ts +148 -0
  159. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +114 -0
  160. package/src/tools/__tests__/ToolNode.session.test.ts +84 -0
  161. package/src/tools/__tests__/directToolHITLResumeScope.test.ts +467 -0
  162. package/src/tools/__tests__/directToolHooks.test.ts +411 -0
  163. package/src/tools/__tests__/localToolNames.test.ts +73 -0
  164. package/src/tools/__tests__/workspaceSeam.test.ts +134 -0
  165. package/src/tools/local/CompileCheckTool.ts +278 -0
  166. package/src/tools/local/FileCheckpointer.ts +93 -0
  167. package/src/tools/local/LocalCodingTools.ts +1342 -0
  168. package/src/tools/local/LocalExecutionEngine.ts +1329 -0
  169. package/src/tools/local/LocalExecutionTools.ts +167 -0
  170. package/src/tools/local/LocalProgrammaticToolCalling.ts +594 -0
  171. package/src/tools/local/__tests__/FileCheckpointer.test.ts +120 -0
  172. package/src/tools/local/__tests__/editStrategies.test.ts +134 -0
  173. package/src/tools/local/attachments.ts +251 -0
  174. package/src/tools/local/bashAst.ts +151 -0
  175. package/src/tools/local/editStrategies.ts +188 -0
  176. package/src/tools/local/index.ts +12 -0
  177. package/src/tools/local/resolveLocalExecutionTools.ts +208 -0
  178. package/src/tools/local/syntaxCheck.ts +243 -0
  179. package/src/tools/local/textEncoding.ts +37 -0
  180. package/src/tools/local/workspaceFS.ts +89 -0
  181. package/src/tools/subagent/SubagentExecutor.ts +60 -0
  182. package/src/types/hitl.ts +56 -27
  183. package/src/types/run.ts +12 -1
  184. package/src/types/summarize.ts +31 -0
  185. package/src/types/tools.ts +359 -7
@@ -42,9 +42,14 @@ export type ToolNodeOptions = {
42
42
  /** Tool names that must be executed directly (via runTool) even in event-driven mode (e.g., graph-managed handoff tools) */
43
43
  directToolNames?: Set<string>;
44
44
  /**
45
- * Hook registry for PreToolUse/PostToolUse lifecycle hooks.
46
- * Only fires for event-driven tool calls (`dispatchToolEvents`). Tools
47
- * routed through `directToolNames` bypass hook dispatch entirely.
45
+ * Hook registry for PreToolUse/PostToolUse/PostToolUseFailure/
46
+ * PermissionDenied lifecycle hooks. Fires for **every** tool the
47
+ * ToolNode invokes both event-dispatched tools (via
48
+ * `dispatchToolEvents`) and direct-path tools (via
49
+ * `runDirectToolWithLifecycleHooks`). The pre-existing limitation
50
+ * that direct-path tools "bypass hook dispatch entirely" was
51
+ * lifted in a follow-up to the HITL surface; both paths now route
52
+ * through the same hook lifecycle.
48
53
  */
49
54
  hookRegistry?: HookRegistry;
50
55
  /**
@@ -60,9 +65,11 @@ export type ToolNodeOptions = {
60
65
  *
61
66
  * Mirrors `RunConfig.humanInTheLoop` (which is the canonical place
62
67
  * to set this); the Graph threads it down to every ToolNode it
63
- * compiles. Same caveat: the interrupt path is only wired into the
64
- * event-driven dispatch (`dispatchToolEvents`), not into
65
- * `directToolNames` execution — direct tools bypass HITL entirely.
68
+ * compiles. The interrupt path is wired into both the event
69
+ * dispatch (`dispatchToolEvents`) and the direct path
70
+ * (`runDirectToolWithLifecycleHooks`) — direct tools no longer
71
+ * bypass HITL. See `HumanInTheLoopConfig` for the resume re-execution
72
+ * contract that applies equally to both paths.
66
73
  */
67
74
  humanInTheLoop?: HumanInTheLoopConfig;
68
75
  /** Max context tokens for the agent — used to compute tool result truncation limits. */
@@ -88,6 +95,25 @@ export type ToolNodeOptions = {
88
95
  * precedence over `toolOutputReferences` when both are set.
89
96
  */
90
97
  toolOutputRegistry?: ToolOutputReferenceRegistry;
98
+ /**
99
+ * Selects where built-in code execution tools run. Defaults to the
100
+ * remote LibreChat Code API sandbox; `local` swaps those same tool names
101
+ * to process-based local executors at ToolNode construction time.
102
+ */
103
+ toolExecution?: ToolExecutionConfig;
104
+ /**
105
+ * Pre-constructed file checkpointer shared across every ToolNode in
106
+ * a Run so `Run.rewindFiles()` (and direct
107
+ * `Run.getFileCheckpointer()` callers) sees a single unified
108
+ * snapshot store. The Graph layer creates one per Run when
109
+ * `toolExecution.local.fileCheckpointing === true` and threads it
110
+ * to every ToolNode it compiles; without this shared instance,
111
+ * multi-agent graphs would each get their own private checkpointer
112
+ * and the host couldn't reach any of them. Wins over the
113
+ * auto-created bundle checkpointer in
114
+ * `resolveLocalExecutionTools`.
115
+ */
116
+ fileCheckpointer?: LocalFileCheckpointer;
91
117
  };
92
118
  export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
93
119
  export type ToolEndEvent = {
@@ -103,6 +129,15 @@ export type CodeEnvFile = {
103
129
  id: string;
104
130
  name: string;
105
131
  session_id: string;
132
+ /**
133
+ * Identifier of the entity that owns this file's session (skill id,
134
+ * agent id, etc). Forwarded to codeapi so it can resolve the
135
+ * per-file sessionKey instead of falling back to a single
136
+ * request-level entity. Required when a single execute request
137
+ * references files uploaded under different entities (e.g. a skill
138
+ * file plus a user attachment in the same call).
139
+ */
140
+ entity_id?: string;
106
141
  };
107
142
  export type CodeExecutionToolParams = undefined | {
108
143
  session_id?: string;
@@ -115,6 +150,13 @@ export type FileRef = {
115
150
  path?: string;
116
151
  /** Session ID this file belongs to (for multi-session file tracking) */
117
152
  session_id?: string;
153
+ /**
154
+ * Entity that owns this file's session (skill id, agent id, etc).
155
+ * Carried on tracked session files so it can flow through to
156
+ * `_injected_files` when a subsequent execute references a mix of
157
+ * files uploaded under different entities.
158
+ */
159
+ entity_id?: string;
118
160
  /**
119
161
  * `true` when the codeapi sandbox echoed this entry as an unchanged
120
162
  * passthrough of an input the caller already owns (skill files,
@@ -297,9 +339,302 @@ export type ToolOutputReferencesConfig = {
297
339
  */
298
340
  maxTotalSize?: number;
299
341
  };
342
+ export type ToolExecutionEngine = 'sandbox' | 'local';
343
+ /**
344
+ * Records pre-write file contents so callers can rewind edits/writes
345
+ * made by the local engine. Implementations live in `src/tools/local`.
346
+ */
347
+ export interface LocalFileCheckpointer {
348
+ /**
349
+ * Captures the current contents of `absolutePath` before a write or
350
+ * edit. Idempotent: capturing the same path twice keeps the first
351
+ * snapshot. Records "did not exist" so creates can be undone with
352
+ * deletion.
353
+ */
354
+ captureBeforeWrite(absolutePath: string): Promise<void>;
355
+ /** Restores all captured snapshots. Returns the number of files restored. */
356
+ rewind(): Promise<number>;
357
+ /** Returns paths that have been captured during this run. */
358
+ capturedPaths(): string[];
359
+ }
360
+ /**
361
+ * Pluggable process launcher used by the local execution engine. When
362
+ * provided, the engine calls this in place of `child_process.spawn`,
363
+ * letting callers route shell commands through SSH, containers, or
364
+ * remote runners without forking the engine. The implementation must
365
+ * return a `ChildProcess`-shaped value whose `stdout`/`stderr` streams
366
+ * emit `data` events and that resolves a `close` event when finished.
367
+ */
368
+ export type LocalSpawn = (command: string, args: string[], options: import('child_process').SpawnOptions) => import('child_process').ChildProcessWithoutNullStreams;
369
+ /** Bash command-validation strictness for the local engine. */
370
+ export type LocalBashAstMode = 'auto' | 'off' | 'strict';
371
+ export type LocalSandboxConfig = {
372
+ /**
373
+ * Enable Anthropic Sandbox Runtime wrapping for local process tools.
374
+ * Defaults to false; requires @anthropic-ai/sandbox-runtime to be installed.
375
+ */
376
+ enabled?: boolean;
377
+ /** Throw when native sandbox dependencies are unavailable. Defaults to false. */
378
+ failIfUnavailable?: boolean;
379
+ filesystem?: {
380
+ denyRead?: string[];
381
+ allowRead?: string[];
382
+ allowWrite?: string[];
383
+ denyWrite?: string[];
384
+ allowGitConfig?: boolean;
385
+ };
386
+ network?: {
387
+ allowedDomains?: string[];
388
+ deniedDomains?: string[];
389
+ allowUnixSockets?: string[];
390
+ allowAllUnixSockets?: boolean;
391
+ allowLocalBinding?: boolean;
392
+ allowMachLookup?: string[];
393
+ };
394
+ };
395
+ /**
396
+ * Workspace boundary the local-coding tools clamp file operations to.
397
+ *
398
+ * `root` is the canonical "project directory" — every file tool that
399
+ * accepts a path resolves it relative to `root` and refuses to touch
400
+ * paths outside it (after symlink resolution). `additionalRoots` lets
401
+ * monorepos extend the boundary to sibling directories without
402
+ * disabling clamping entirely.
403
+ *
404
+ * `allowReadOutside` and `allowWriteOutside` are escape hatches that
405
+ * disable clamping for read- and write-shaped tools respectively.
406
+ * Most hosts shouldn't need them — prefer wiring
407
+ * `createWorkspacePolicyHook` if you want "ask the user" semantics
408
+ * via the existing PreToolUse / HITL machinery instead of an
409
+ * unconditional bypass.
410
+ */
411
+ export type LocalWorkspaceConfig = {
412
+ /** Required. The canonical workspace root. */
413
+ root: string;
414
+ /**
415
+ * Sibling roots that also count as inside the workspace. Useful in
416
+ * monorepos where a project legitimately needs to reach a paired
417
+ * directory without disabling clamping.
418
+ */
419
+ additionalRoots?: readonly string[];
420
+ /** When true, disable the read-outside-workspace clamp. */
421
+ allowReadOutside?: boolean;
422
+ /** When true, disable the write-outside-workspace clamp. */
423
+ allowWriteOutside?: boolean;
424
+ };
425
+ /**
426
+ * Engine-agnostic execution seam. Default uses Node's
427
+ * `child_process.spawn` and `fs/promises`. A future engine (e.g.
428
+ * stateful remote sandbox) supplies its own `spawn` and `fs` and
429
+ * inherits every tool factory unchanged.
430
+ *
431
+ * **Important — pair `spawn` and `fs` together.** Most file-touching
432
+ * surfaces in the local engine route through `getWorkspaceFS(config)`
433
+ * so a host can transparently swap in a remote/in-memory FS. A small
434
+ * set of helpers — currently the `execute_code` non-bash temp-file
435
+ * write (Codex P2 [48]) — still uses host `fs/promises` directly to
436
+ * stage source on disk before invoking the spawn. If you override
437
+ * `spawn` to point at a remote runtime (SSH, container, etc.) you
438
+ * MUST also override `fs` with the corresponding remote
439
+ * implementation; otherwise temp source files written to the host
440
+ * `/tmp` won't be visible to the remote interpreter and `py`/`js`/
441
+ * `ts`/etc. executions will fail. (Bash-style executions go through
442
+ * `executeLocalBash` which doesn't stage temp files, so they're
443
+ * unaffected.)
444
+ *
445
+ * Threat-model note: the regex-based command validators
446
+ * (`dangerousCommandPatterns`, `quotedDestructivePatterns`, etc.) and
447
+ * the workspace policy hook are documented as best-effort tripwires.
448
+ * The hard security boundary is `local.sandbox.enabled: true` (which
449
+ * wraps execution in `@anthropic-ai/sandbox-runtime`); for adversarial-
450
+ * model threat models, do NOT rely on the regex layer alone.
451
+ */
452
+ export type LocalExecConfig = {
453
+ /** Pluggable spawn (for SSH, container, remote workers, etc.). */
454
+ spawn?: LocalSpawn;
455
+ /**
456
+ * Pluggable filesystem (for remote-workspace engines). Pair with
457
+ * `spawn` — see the type-level note above on why both should be
458
+ * overridden together for non-host engines.
459
+ */
460
+ fs?: import('@/tools/local/workspaceFS').WorkspaceFS;
461
+ };
462
+ export type LocalExecutionConfig = {
463
+ /**
464
+ * Working directory for local commands. Defaults to process.cwd().
465
+ * Back-compat shorthand for `workspace.root`.
466
+ *
467
+ * @deprecated Prefer `workspace.root`. Kept for backward
468
+ * compatibility with pre-workspace configs.
469
+ */
470
+ cwd?: string;
471
+ /**
472
+ * Workspace boundary configuration. When omitted, the implementation
473
+ * derives `{ root: cwd ?? process.cwd() }` so existing call sites
474
+ * keep working.
475
+ */
476
+ workspace?: LocalWorkspaceConfig;
477
+ /**
478
+ * Execution seam (spawn + fs). When omitted, defaults to Node-host
479
+ * child_process and fs/promises. Same back-compat: a top-level
480
+ * `spawn` field is honoured if `exec.spawn` isn't set.
481
+ */
482
+ exec?: LocalExecConfig;
483
+ /** Shell executable for bash-style tools. Defaults to `bash`. */
484
+ shell?: string;
485
+ /** Default timeout for local processes, in milliseconds. */
486
+ timeoutMs?: number;
487
+ /** Maximum stdout/stderr characters surfaced to the model. */
488
+ maxOutputChars?: number;
489
+ /**
490
+ * Hard cap on total bytes a single child process can stream across
491
+ * stdout+stderr before its process tree is killed. Independent from
492
+ * `maxOutputChars` (which controls what the model sees); this is the
493
+ * OOM backstop for noisy / runaway commands (`yes`, `cat /dev/urandom`,
494
+ * a verbose build that loops). Defaults to 50 MiB. Set higher for
495
+ * legitimately large logs; setting to 0 disables the cap and risks
496
+ * an OOM crash on the host.
497
+ */
498
+ maxSpawnedBytes?: number;
499
+ /** Extra environment variables merged over process.env. */
500
+ env?: NodeJS.ProcessEnv;
501
+ /** Optional process sandboxing via @anthropic-ai/sandbox-runtime. */
502
+ sandbox?: LocalSandboxConfig;
503
+ /**
504
+ * When true, block obviously mutating shell commands before execution.
505
+ * Useful for read-only agent modes and dry-run workflows.
506
+ */
507
+ readOnly?: boolean;
508
+ /** Permit dangerous commands that the validator otherwise blocks. */
509
+ allowDangerousCommands?: boolean;
510
+ /**
511
+ * Permit file tools to resolve paths outside `cwd`. Defaults to false.
512
+ *
513
+ * @deprecated Prefer the granular
514
+ * `workspace.allowReadOutside` / `workspace.allowWriteOutside`.
515
+ * Kept for backward compatibility; setting either of the
516
+ * workspace fields takes precedence over this flag.
517
+ */
518
+ allowOutsideWorkspace?: boolean;
519
+ /**
520
+ * Add the built-in local coding suite (`read_file`, `write_file`,
521
+ * `edit_file`, `grep_search`, `glob_search`, `list_directory`, plus local
522
+ * code/bash execution tools) when `engine` is `local`. Defaults to true.
523
+ */
524
+ includeCodingTools?: boolean;
525
+ /**
526
+ * Override the process launcher. When set, replaces
527
+ * `child_process.spawn` for every local tool invocation, allowing
528
+ * SSH/container delegation. Default: native spawn.
529
+ */
530
+ spawn?: LocalSpawn;
531
+ /**
532
+ * Tree-sitter-bash AST validation pass on bash commands.
533
+ * - `'off'` skips AST validation (regex + `bash -n` only — current behavior).
534
+ * - `'auto'` runs the AST validator when `tree-sitter` modules are
535
+ * available; falls back silently otherwise.
536
+ * - `'strict'` requires the AST validator and fails closed when
537
+ * parsing is unavailable or the command is too complex to verify.
538
+ * Default: `'off'` to preserve historical behavior.
539
+ */
540
+ bashAst?: LocalBashAstMode;
541
+ /**
542
+ * Enable per-Run file checkpointing for `edit_file` / `write_file`
543
+ * so callers can rewind file changes after a failed batch. When
544
+ * true and the run is constructed via `Run.create(...)`, the host
545
+ * can call `Run.rewindFiles()` (or `Run.getFileCheckpointer()` for
546
+ * the raw checkpointer). Defaults to false.
547
+ */
548
+ fileCheckpointing?: boolean;
549
+ /**
550
+ * Maximum bytes to read in `read_file` before returning a stub.
551
+ * Defaults to 10 MiB.
552
+ */
553
+ maxReadBytes?: number;
554
+ /**
555
+ * Controls whether `read_file` returns binary files as inline
556
+ * `MessageContentComplex[]` attachments (so vision-capable models
557
+ * see them) or as a textual stub.
558
+ *
559
+ * - `'off'` : never embed; current binary-stub behavior.
560
+ * - `'images-only'`: embed images (png/jpeg/gif/webp) as
561
+ * `image_url` blocks; other binaries get the stub.
562
+ * - `'images-and-pdf'` : also embed PDFs as `image_url` data URLs
563
+ * (Anthropic accepts these in tool_result; other providers may
564
+ * degrade to JSON).
565
+ *
566
+ * Defaults to `'off'` to preserve current behavior.
567
+ */
568
+ attachReadAttachments?: 'off' | 'images-only' | 'images-and-pdf';
569
+ /**
570
+ * Maximum pre-encoding byte size to embed inline. Anything larger
571
+ * degrades to an `<oversize>` stub. Defaults to 5 MiB to bound the
572
+ * post-base64 token cost.
573
+ */
574
+ maxAttachmentBytes?: number;
575
+ /**
576
+ * Run a fast per-file syntax check after every successful
577
+ * `edit_file` / `write_file`. When the checker finds an error,
578
+ * the diagnostics are appended to the tool result so the model
579
+ * can self-correct without a separate read round-trip.
580
+ *
581
+ * - `'off'` (default) : skip; current behavior.
582
+ * - `'auto'` : run the checker for known file types
583
+ * when the corresponding tool is on PATH. Silently skip
584
+ * otherwise.
585
+ * - `'strict'` : same as `'auto'`, plus fail the tool
586
+ * call with the error so the model is forced to react. Use
587
+ * when you don't trust the model to read a non-blocking
588
+ * advisory.
589
+ *
590
+ * Built-in checkers: Node `node --check` for `.js/.mjs/.cjs`,
591
+ * Python `py_compile` for `.py`, `JSON.parse` for `.json`,
592
+ * `bash -n` for `.sh/.bash`. TypeScript falls back to `compile_check`
593
+ * (project-level) since per-file `.ts` syntax check requires the
594
+ * `typescript` package; the host can wire a per-file checker via
595
+ * `local.spawn` if desired.
596
+ */
597
+ postEditSyntaxCheck?: 'off' | 'auto' | 'strict';
598
+ /**
599
+ * Configuration for the `compile_check` tool. When `engine` is
600
+ * `local` and `includeCodingTools` is on, the SDK exposes a
601
+ * `compile_check` tool that runs the project's standard
602
+ * type/lint command (`tsc --noEmit`, `cargo check`, etc.).
603
+ */
604
+ compileCheck?: {
605
+ /**
606
+ * Override the auto-detected command. Runs verbatim from `cwd`
607
+ * via the local engine's standard spawn pipeline (sandbox / AST
608
+ * validation / output overflow all apply).
609
+ */
610
+ command?: string;
611
+ /** Default timeout for `compile_check`, in milliseconds. Defaults to 120s. */
612
+ timeoutMs?: number;
613
+ };
614
+ };
615
+ export type ToolExecutionConfig = {
616
+ /** `sandbox` preserves the remote Code API behavior and is the default. */
617
+ engine?: ToolExecutionEngine;
618
+ /** Local process execution settings used when `engine` is `local`. */
619
+ local?: LocalExecutionConfig;
620
+ };
300
621
  export type ProgrammaticCache = {
301
622
  toolMap: ToolMap;
302
623
  toolDefs: LCTool[];
624
+ /**
625
+ * Hook context plumbed through by ToolNode for the local
626
+ * programmatic-tool path so the in-process bridge can run
627
+ * `PreToolUse` hooks (deny / updatedInput) for inner tool calls.
628
+ * Not present for non-local (remote-engine) programmatic calling
629
+ * which dispatches inner tools through the host's own pipeline.
630
+ */
631
+ hookContext?: ProgrammaticHookContext;
632
+ };
633
+ export type ProgrammaticHookContext = {
634
+ registry: import('@/hooks').HookRegistry | undefined;
635
+ runId: string;
636
+ threadId?: string;
637
+ agentId?: string;
303
638
  };
304
639
  /** Search mode: code_interpreter uses external sandbox, local uses safe substring matching */
305
640
  export type ToolSearchMode = 'code_interpreter' | 'local';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.1.77",
3
+ "version": "3.1.78",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -126,6 +126,14 @@
126
126
  "subagent:tools": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/subagent-tools-debug.ts",
127
127
  "programmatic_exec": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec.ts",
128
128
  "code_exec_ptc": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_ptc.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
129
+ "local": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/local_engine.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
130
+ "local:ptc": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/local_engine_ptc.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
131
+ "local:hooks": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/local_engine_hooks.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
132
+ "local:checkpointer": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/local_engine_checkpointer.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
133
+ "local:image": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/local_engine_image.ts --provider 'anthropic' --name 'Jo' --location 'New York, NY'",
134
+ "local:compile": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/local_engine_compile.ts --provider 'anthropic' --name 'Jo' --location 'New York, NY'",
135
+ "compare:pi": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/compare_pi_vs_ours.ts",
136
+ "local:workspace": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/local_engine_workspace.ts --provider 'anthropic' --name 'Jo' --location 'New York, NY'",
129
137
  "programmatic_exec_agent": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec_agent.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
130
138
  "ant_web_search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/ant_web_search.ts --name 'Jo' --location 'New York, NY'",
131
139
  "ant_web_search_edge_case": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/ant_web_search_edge_case.ts --name 'Jo' --location 'New York, NY'",
@@ -201,9 +209,11 @@
201
209
  "@langfuse/tracing": "^4.3.0",
202
210
  "@opentelemetry/sdk-node": "^0.207.0",
203
211
  "@scarf/scarf": "^1.4.0",
212
+ "@types/diff": "^7.0.2",
204
213
  "ai-tokenizer": "^1.0.6",
205
- "axios": "^1.15.0",
214
+ "axios": "^1.16.0",
206
215
  "cheerio": "^1.0.0",
216
+ "diff": "^9.0.0",
207
217
  "dotenv": "^16.4.7",
208
218
  "https-proxy-agent": "^7.0.6",
209
219
  "mathjs": "^15.2.0",
@@ -212,11 +222,20 @@
212
222
  "openai": "^6.35.0",
213
223
  "uuid": "^11.1.1"
214
224
  },
225
+ "peerDependencies": {
226
+ "@anthropic-ai/sandbox-runtime": "^0.0.49"
227
+ },
228
+ "peerDependenciesMeta": {
229
+ "@anthropic-ai/sandbox-runtime": {
230
+ "optional": true
231
+ }
232
+ },
215
233
  "imports": {
216
234
  "@/*": "./src/*",
217
235
  "~/*": "./*"
218
236
  },
219
237
  "devDependencies": {
238
+ "@anthropic-ai/sandbox-runtime": "^0.0.49",
220
239
  "@anthropic-ai/vertex-sdk": "^0.12.0",
221
240
  "@eslint/compat": "^1.2.7",
222
241
  "@rollup/plugin-alias": "^5.1.0",
@@ -189,6 +189,22 @@ export enum Constants {
189
189
  BASH_TOOL = 'bash_tool',
190
190
  BASH_PROGRAMMATIC_TOOL_CALLING = 'run_tools_with_bash',
191
191
  SUBAGENT = 'subagent',
192
+ /**
193
+ * Local-engine coding tool names. Promoted to `Constants.*` (rather
194
+ * than left as per-file `*ToolName` consts) so consumer UIs — most
195
+ * importantly LibreChat's `getToolIconType` map — can match against
196
+ * canonical strings instead of guessing. Existing matched names:
197
+ * `bash_tool`, `read_file`, `execute_code`, `run_tools_with_code`.
198
+ * The rest below are new and currently fall through to the generic
199
+ * tool icon; once LibreChat adds icons keyed on the same names, the
200
+ * wiring will work without an SDK change.
201
+ */
202
+ WRITE_FILE = 'write_file',
203
+ EDIT_FILE = 'edit_file',
204
+ GREP_SEARCH = 'grep_search',
205
+ GLOB_SEARCH = 'glob_search',
206
+ LIST_DIRECTORY = 'list_directory',
207
+ COMPILE_CHECK = 'compile_check',
192
208
  }
193
209
 
194
210
  /** Tool names that use the code execution environment (shared session, file tracking). */
@@ -199,6 +215,44 @@ export const CODE_EXECUTION_TOOLS: ReadonlySet<string> = new Set([
199
215
  Constants.BASH_PROGRAMMATIC_TOOL_CALLING,
200
216
  ]);
201
217
 
218
+ /**
219
+ * Canonical names of the local-engine-specific coding tools — the
220
+ * file/edit/search/typecheck surface that doesn't exist in the
221
+ * remote (sandbox-API) engine. Single source of truth; the per-tool
222
+ * factories, registry definitions, and `createWorkspacePolicyHook`
223
+ * default extractors all key off these.
224
+ *
225
+ * `read_file` is on this list (the existing ReadFile tool is
226
+ * remote-specific; the local engine's `read_file` is a parallel
227
+ * implementation that shares the canonical name so consumer UIs
228
+ * — most importantly LibreChat's `getToolIconType` — render both
229
+ * with the same icon).
230
+ */
231
+ export const LOCAL_CODING_TOOL_NAMES: readonly string[] = [
232
+ Constants.READ_FILE,
233
+ Constants.WRITE_FILE,
234
+ Constants.EDIT_FILE,
235
+ Constants.GREP_SEARCH,
236
+ Constants.GLOB_SEARCH,
237
+ Constants.LIST_DIRECTORY,
238
+ Constants.COMPILE_CHECK,
239
+ ];
240
+
241
+ /**
242
+ * Every tool name the local coding bundle (`createLocalCodingTools`)
243
+ * exposes — the local-specific tools above plus the bash/code/PTC
244
+ * pair that the local engine wraps around the existing factories.
245
+ * Tests pin against this so any addition/removal in the bundle is
246
+ * accompanied by a deliberate canonical-name update here.
247
+ */
248
+ export const LOCAL_CODING_BUNDLE_NAMES: readonly string[] = [
249
+ ...LOCAL_CODING_TOOL_NAMES,
250
+ Constants.BASH_TOOL,
251
+ Constants.EXECUTE_CODE,
252
+ Constants.PROGRAMMATIC_TOOL_CALLING,
253
+ Constants.BASH_PROGRAMMATIC_TOOL_CALLING,
254
+ ];
255
+
202
256
  export enum TitleMethod {
203
257
  STRUCTURED = 'structured',
204
258
  FUNCTIONS = 'functions',