





























@@ -748,7 +748,7 @@ describe("runCodexAppServerAttempt", () => {
748748);
749749});
750750751-it("does not expose sandbox shell tools unless non-Docker sandbox routing is available", async () => {
751+it("keeps Docker sandbox shell tools hidden when native Code Mode can honor sandbox paths", async () => {
752752testing.setOpenClawCodingToolsFactoryForTests(() => [
753753createRuntimeDynamicTool("exec"),
754754createRuntimeDynamicTool("process"),
@@ -769,11 +769,69 @@ describe("runCodexAppServerAttempt", () => {
769769effectiveWorkspace: workspaceDir,
770770 sandboxSessionKey,
771771sandbox: { enabled: true, backendId: "docker" } as never,
772+nativeToolSurfaceEnabled: true,
772773runAbortController: new AbortController(),
773774sessionAgentId: "main",
774775pluginConfig: {},
775776onYieldDetected: () => undefined,
776777});
778+779+expect(dockerTools.map((tool) => tool.name)).toEqual(["message"]);
780+});
781+782+it("exposes Docker sandbox shell tools when native Code Mode cannot honor sandbox paths", async () => {
783+testing.setOpenClawCodingToolsFactoryForTests(() => [
784+createRuntimeDynamicTool("exec"),
785+createRuntimeDynamicTool("process"),
786+createRuntimeDynamicTool("message"),
787+]);
788+const sessionFile = path.join(tempDir, "session.jsonl");
789+const workspaceDir = path.join(tempDir, "workspace");
790+const params = createParams(sessionFile, workspaceDir);
791+params.disableTools = false;
792+const sandboxSessionKey = params.sessionKey;
793+if (!sandboxSessionKey) {
794+throw new Error("createParams must provide a sessionKey for Codex dynamic tool tests.");
795+}
796+797+const tools = await testing.buildDynamicTools({
798+ params,
799+resolvedWorkspace: workspaceDir,
800+effectiveWorkspace: workspaceDir,
801+ sandboxSessionKey,
802+sandbox: {
803+enabled: true,
804+backendId: "docker",
805+docker: { binds: ["/tmp/openclaw-data:/data:rw"] },
806+} as never,
807+nativeToolSurfaceEnabled: false,
808+runAbortController: new AbortController(),
809+sessionAgentId: "main",
810+pluginConfig: {},
811+onYieldDetected: () => undefined,
812+});
813+814+expect(tools.map((tool) => tool.name)).toEqual(["message", "sandbox_exec", "sandbox_process"]);
815+expect(tools.find((tool) => tool.name === "sandbox_exec")?.description).toContain(
816+"Docker container-path bind layout",
817+);
818+});
819+820+it("does not expose sandbox shell tools when sandbox routing is disabled", async () => {
821+testing.setOpenClawCodingToolsFactoryForTests(() => [
822+createRuntimeDynamicTool("exec"),
823+createRuntimeDynamicTool("process"),
824+createRuntimeDynamicTool("message"),
825+]);
826+const sessionFile = path.join(tempDir, "session.jsonl");
827+const workspaceDir = path.join(tempDir, "workspace");
828+const params = createParams(sessionFile, workspaceDir);
829+params.disableTools = false;
830+const sandboxSessionKey = params.sessionKey;
831+if (!sandboxSessionKey) {
832+throw new Error("createParams must provide a sessionKey for Codex dynamic tool tests.");
833+}
834+777835const disabledSandboxTools = await testing.buildDynamicTools({
778836 params,
779837resolvedWorkspace: workspaceDir,
@@ -786,7 +844,6 @@ describe("runCodexAppServerAttempt", () => {
786844onYieldDetected: () => undefined,
787845});
788846789-expect(dockerTools.map((tool) => tool.name)).toEqual(["message"]);
790847expect(disabledSandboxTools.map((tool) => tool.name)).toEqual(["message"]);
791848});
792849@@ -1203,6 +1260,41 @@ describe("runCodexAppServerAttempt", () => {
12031260expect(testing.shouldEnableCodexAppServerNativeToolSurface(params)).toBe(false);
12041261});
120512621263+it("disables Codex native tool surfaces when Docker bind targets need container paths", () => {
1264+const workspaceDir = path.join(tempDir, "workspace");
1265+const params = createParams(path.join(tempDir, "session.jsonl"), workspaceDir);
1266+params.disableTools = false;
1267+1268+expect(
1269+testing.shouldEnableCodexAppServerNativeToolSurface(params, {
1270+enabled: true,
1271+backendId: "docker",
1272+docker: { binds: ["/tmp/openclaw-data:/data:rw"] },
1273+} as never),
1274+).toBe(false);
1275+1276+expect(
1277+testing.shouldEnableCodexAppServerNativeToolSurface(params, {
1278+enabled: true,
1279+backendId: "docker",
1280+docker: { binds: ["/tmp/openclaw-data:/tmp/openclaw-data:rw"] },
1281+} as never),
1282+).toBe(true);
1283+1284+expect(
1285+testing.shouldEnableCodexAppServerNativeToolSurface(params, {
1286+enabled: true,
1287+backendId: "docker",
1288+docker: {
1289+binds: [
1290+"/tmp/openclaw-data:/tmp/openclaw-data:rw",
1291+"/tmp/openclaw-data/secrets:/tmp/openclaw-data/secrets:ro",
1292+],
1293+},
1294+} as never),
1295+).toBe(false);
1296+});
1297+12061298it("forces the message dynamic tool for message-tool-only source replies", () => {
12071299const workspaceDir = path.join(tempDir, "workspace");
12081300const params = createParams(path.join(tempDir, "session.jsonl"), workspaceDir);
@@ -8962,13 +9054,19 @@ describe("runCodexAppServerAttempt", () => {
89629054{
89639055enabled: true,
89649056backendId: "docker",
8965-docker: { network: "bridge" },
9057+docker: {
9058+network: "bridge",
9059+binds: [
9060+"/tmp/openclaw-writable-data:/data:rw",
9061+"/tmp/openclaw-readonly-data:/readonly:ro",
9062+],
9063+},
89669064} as never,
89679065"/tmp/workspace",
89689066),
89699067).toEqual({
89709068type: "workspaceWrite",
8971-writableRoots: ["/tmp/workspace"],
9069+writableRoots: ["/tmp/workspace", path.resolve("/tmp/openclaw-writable-data")],
89729070networkAccess: true,
89739071excludeTmpdirEnvVar: false,
89749072excludeSlashTmp: false,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。