@librechat/agents 3.6.13 → 3.6.14
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/cjs/main.cjs +6 -0
- package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +33 -14
- package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -1
- package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +3 -2
- package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalCodingTools.cjs +10 -14
- package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +67 -3
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
- package/dist/cjs/tools/local/syntaxCheck.cjs +10 -14
- package/dist/cjs/tools/local/syntaxCheck.cjs.map +1 -1
- package/dist/cjs/tools/local/workspaceFS.cjs +2 -2
- package/dist/cjs/tools/local/workspaceFS.cjs.map +1 -1
- package/dist/esm/main.mjs +3 -3
- package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +33 -15
- package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -1
- package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +4 -3
- package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -1
- package/dist/esm/tools/local/LocalCodingTools.mjs +11 -15
- package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +63 -4
- package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
- package/dist/esm/tools/local/syntaxCheck.mjs +11 -15
- package/dist/esm/tools/local/syntaxCheck.mjs.map +1 -1
- package/dist/esm/tools/local/workspaceFS.mjs +2 -2
- package/dist/esm/tools/local/workspaceFS.mjs.map +1 -1
- package/dist/types/tools/cloudflare/CloudflareSandboxExecutionEngine.d.ts +6 -0
- package/dist/types/tools/local/LocalExecutionEngine.d.ts +22 -0
- package/dist/types/tools/local/workspaceFS.d.ts +1 -1
- package/dist/types/types/tools.d.ts +22 -37
- package/package.json +2 -1
- package/src/tools/cloudflare/CloudflareSandboxExecutionEngine.ts +68 -17
- package/src/tools/cloudflare/CloudflareSandboxTools.ts +4 -3
- package/src/tools/local/LocalCodingTools.ts +25 -35
- package/src/tools/local/LocalExecutionEngine.ts +120 -3
- package/src/tools/local/syntaxCheck.ts +23 -26
- package/src/tools/local/workspaceFS.ts +2 -3
- package/src/types/tools.ts +25 -37
|
@@ -18,12 +18,15 @@
|
|
|
18
18
|
|
|
19
19
|
import { extname } from 'path';
|
|
20
20
|
import type * as t from '@/types';
|
|
21
|
-
import { isWorkspaceClientTimeoutError } from './workspaceFS';
|
|
22
21
|
import {
|
|
22
|
+
commandAvailabilityEnvCacheKey,
|
|
23
23
|
getSpawn,
|
|
24
24
|
getWorkspaceFS,
|
|
25
|
+
probeLocalCommandAvailability,
|
|
26
|
+
setCommandAvailabilityCacheEntry,
|
|
25
27
|
spawnLocalProcess,
|
|
26
28
|
} from './LocalExecutionEngine';
|
|
29
|
+
import { isWorkspaceClientTimeoutError } from './workspaceFS';
|
|
27
30
|
|
|
28
31
|
export type SyntaxCheckOutcome =
|
|
29
32
|
| { ok: true }
|
|
@@ -48,26 +51,17 @@ export type SyntaxChecker = (
|
|
|
48
51
|
* reset hook re-creates the map.
|
|
49
52
|
*/
|
|
50
53
|
type ProbeKind = 'hasNode' | 'hasPython' | 'hasBash';
|
|
51
|
-
type ProbeCache = Partial<
|
|
54
|
+
type ProbeCache = Partial<
|
|
55
|
+
Record<ProbeKind, ReturnType<typeof probeLocalCommandAvailability>>
|
|
56
|
+
>;
|
|
52
57
|
|
|
53
|
-
// Per-backend ×
|
|
54
|
-
//
|
|
55
|
-
// loses node between Runs that share the same backend). Same fix
|
|
56
|
-
// shape as the ripgrep cache (Codex P1 #34).
|
|
58
|
+
// Per-backend × hashed-env cache. The inner map is bounded so a long-lived
|
|
59
|
+
// world cannot retain unbounded environment variants.
|
|
57
60
|
let probeCacheByBackend = new WeakMap<
|
|
58
61
|
t.LocalSpawn,
|
|
59
62
|
Map<string, ProbeCache>
|
|
60
63
|
>();
|
|
61
64
|
|
|
62
|
-
function envCacheKey(env: NodeJS.ProcessEnv | undefined): string {
|
|
63
|
-
if (env == null) return '';
|
|
64
|
-
const sorted: Record<string, string | undefined> = {};
|
|
65
|
-
for (const k of Object.keys(env).sort()) {
|
|
66
|
-
sorted[k] = env[k];
|
|
67
|
-
}
|
|
68
|
-
return JSON.stringify(sorted);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
65
|
function cacheFor(
|
|
72
66
|
config: t.LocalExecutionConfig
|
|
73
67
|
): ProbeCache {
|
|
@@ -77,11 +71,11 @@ function cacheFor(
|
|
|
77
71
|
envMap = new Map();
|
|
78
72
|
probeCacheByBackend.set(backend, envMap);
|
|
79
73
|
}
|
|
80
|
-
const envKey =
|
|
74
|
+
const envKey = commandAvailabilityEnvCacheKey(config.env);
|
|
81
75
|
let entry = envMap.get(envKey);
|
|
82
76
|
if (entry == null) {
|
|
83
77
|
entry = {};
|
|
84
|
-
envMap
|
|
78
|
+
setCommandAvailabilityCacheEntry(envMap, envKey, entry);
|
|
85
79
|
}
|
|
86
80
|
return entry;
|
|
87
81
|
}
|
|
@@ -95,17 +89,20 @@ async function probe(
|
|
|
95
89
|
const entry = cacheFor(config);
|
|
96
90
|
let probePromise = entry[cached];
|
|
97
91
|
if (probePromise == null) {
|
|
98
|
-
probePromise =
|
|
99
|
-
command,
|
|
100
|
-
args,
|
|
101
|
-
{ ...config, timeoutMs: 5000, sandbox: { enabled: false } },
|
|
102
|
-
{ internal: true }
|
|
103
|
-
)
|
|
104
|
-
.then((result) => result != null && result.exitCode === 0)
|
|
105
|
-
.catch(() => false);
|
|
92
|
+
probePromise = probeLocalCommandAvailability(command, args, config);
|
|
106
93
|
entry[cached] = probePromise;
|
|
107
94
|
}
|
|
108
|
-
|
|
95
|
+
const result = await probePromise;
|
|
96
|
+
if (!result.cacheable && entry[cached] === probePromise) {
|
|
97
|
+
delete entry[cached];
|
|
98
|
+
}
|
|
99
|
+
if (result.cacheUntil != null && result.cacheUntil <= Date.now()) {
|
|
100
|
+
if (entry[cached] === probePromise) {
|
|
101
|
+
delete entry[cached];
|
|
102
|
+
}
|
|
103
|
+
return probe(command, args, cached, config);
|
|
104
|
+
}
|
|
105
|
+
return result.available;
|
|
109
106
|
}
|
|
110
107
|
|
|
111
108
|
/**
|
|
@@ -92,10 +92,9 @@ export interface WorkspaceFS {
|
|
|
92
92
|
* Returned by `getWorkspaceFS(config)` when the host hasn't supplied
|
|
93
93
|
* an override on `local.exec.fs`.
|
|
94
94
|
*/
|
|
95
|
-
export const nodeWorkspaceFS
|
|
95
|
+
export const nodeWorkspaceFS = Object.freeze<WorkspaceFS>({
|
|
96
96
|
// The runtime impl ignores the encoding-vs-buffer distinction; the
|
|
97
97
|
// overload signatures above are what callers see.
|
|
98
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
99
98
|
readFile: ((path: string, encoding?: 'utf8') =>
|
|
100
99
|
encoding != null
|
|
101
100
|
? fsReadFile(path, encoding)
|
|
@@ -113,4 +112,4 @@ export const nodeWorkspaceFS: WorkspaceFS = {
|
|
|
113
112
|
realpath: (path) => fsRealpath(path),
|
|
114
113
|
unlink: (path) => fsUnlink(path),
|
|
115
114
|
open: (path, flags) => fsOpen(path, flags),
|
|
116
|
-
};
|
|
115
|
+
});
|
package/src/types/tools.ts
CHANGED
|
@@ -820,47 +820,35 @@ export type LocalWorkspaceConfig = {
|
|
|
820
820
|
};
|
|
821
821
|
|
|
822
822
|
/**
|
|
823
|
-
*
|
|
824
|
-
*
|
|
825
|
-
*
|
|
826
|
-
|
|
823
|
+
* One execution world shared by filesystem and subprocess operations.
|
|
824
|
+
* Backend identity is stable so capability probes remain warm when tool
|
|
825
|
+
* bundles are rebuilt for later agent bindings.
|
|
826
|
+
*/
|
|
827
|
+
export interface ExecutionWorld {
|
|
828
|
+
/** Launches a process inside this world's filesystem namespace. */
|
|
829
|
+
readonly spawn: LocalSpawn;
|
|
830
|
+
/** Reads and writes the same namespace observed by `spawn`. */
|
|
831
|
+
readonly fs: Readonly<import('@/tools/local/workspaceFS').WorkspaceFS>;
|
|
832
|
+
/** Whether the world already enforces a sandbox boundary. */
|
|
833
|
+
readonly sandboxed: boolean;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Backward-compatible partial execution-world override. Omitted fields use
|
|
838
|
+
* the Node host world; remote backends should provide the complete trio.
|
|
827
839
|
*
|
|
828
|
-
*
|
|
829
|
-
*
|
|
830
|
-
*
|
|
831
|
-
* set of helpers — currently the `execute_code` non-bash temp-file
|
|
832
|
-
* write (Codex P2 [48]) — still uses host `fs/promises` directly to
|
|
833
|
-
* stage source on disk before invoking the spawn. If you override
|
|
834
|
-
* `spawn` to point at a remote runtime (SSH, container, etc.) you
|
|
835
|
-
* MUST also override `fs` with the corresponding remote
|
|
836
|
-
* implementation; otherwise temp source files written to the host
|
|
837
|
-
* `/tmp` won't be visible to the remote interpreter and `py`/`js`/
|
|
838
|
-
* `ts`/etc. executions will fail. (Bash-style executions go through
|
|
839
|
-
* `executeLocalBash` which doesn't stage temp files, so they're
|
|
840
|
-
* unaffected.)
|
|
840
|
+
* Non-bash `execute_code` still stages source through the host temporary
|
|
841
|
+
* directory. Remote runtimes should use their dedicated execution engine for
|
|
842
|
+
* that tool until temporary lifecycle operations join this seam.
|
|
841
843
|
*
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
* The hard security boundary is `local.sandbox.enabled: true` (which
|
|
846
|
-
* wraps execution in `@anthropic-ai/sandbox-runtime`); for adversarial-
|
|
847
|
-
* model threat models, do NOT rely on the regex layer alone.
|
|
844
|
+
* Command validators and workspace policies are best-effort tripwires. For an
|
|
845
|
+
* adversarial-model threat model, use a backend sandbox boundary rather than
|
|
846
|
+
* relying on validation alone.
|
|
848
847
|
*/
|
|
849
848
|
export type LocalExecConfig = {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
* Pluggable filesystem (for remote-workspace engines). Pair with
|
|
854
|
-
* `spawn` — see the type-level note above on why both should be
|
|
855
|
-
* overridden together for non-host engines.
|
|
856
|
-
*/
|
|
857
|
-
fs?: import('@/tools/local/workspaceFS').WorkspaceFS;
|
|
858
|
-
/**
|
|
859
|
-
* Set by custom execution backends that already provide their own
|
|
860
|
-
* sandbox boundary. Suppresses the local host-sandbox warning while
|
|
861
|
-
* preserving the warning for plain host `child_process` execution.
|
|
862
|
-
*/
|
|
863
|
-
sandboxed?: boolean;
|
|
849
|
+
-readonly [Key in keyof ExecutionWorld]?: Key extends 'fs'
|
|
850
|
+
? import('@/tools/local/workspaceFS').WorkspaceFS
|
|
851
|
+
: ExecutionWorld[Key];
|
|
864
852
|
};
|
|
865
853
|
|
|
866
854
|
export type LocalExecutionConfig = {
|