From 94e170763e5776f39fbf86a2b9ff6d9a1ab79fca Mon Sep 17 00:00:00 2001 From: joelnishanth <140015627+joelnishanth@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:33:18 -0500 Subject: [PATCH] fix: respect agents.defaults.workspace for non-default agents (#59789) --- src/agents/agent-scope.test.ts | 34 ++++++++++++++++++++++++++++++++++ src/agents/agent-scope.ts | 7 ++++++- src/commands/agents.test.ts | 6 +----- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/agents/agent-scope.test.ts b/src/agents/agent-scope.test.ts index cf0c424c43a..81fb4f717bd 100644 --- a/src/agents/agent-scope.test.ts +++ b/src/agents/agent-scope.test.ts @@ -432,6 +432,40 @@ describe("resolveAgentConfig", () => { const agentDir = resolveAgentDir({} as OpenClawConfig, "main"); expect(agentDir).toBe(path.join(path.resolve(home), ".openclaw", "agents", "main", "agent")); }); + + it("non-default agent uses agents.defaults.workspace as base (#59789)", () => { + const cfg: OpenClawConfig = { + agents: { + defaults: { workspace: "/shared-ws" }, + list: [{ id: "main" }, { id: "work", default: true, workspace: "/work-ws" }], + }, + }; + const workspace = resolveAgentWorkspaceDir(cfg, "main"); + expect(workspace).toBe(path.resolve("/shared-ws/main")); + }); + + it("default agent uses agents.defaults.workspace directly", () => { + const cfg: OpenClawConfig = { + agents: { + defaults: { workspace: "/shared-ws" }, + list: [{ id: "main" }, { id: "work", default: true, workspace: "/work-ws" }], + }, + }; + const workspace = resolveAgentWorkspaceDir(cfg, "work"); + expect(workspace).toBe(path.resolve("/work-ws")); + }); + + it("non-default agent without defaults.workspace falls back to stateDir", () => { + const stateDir = path.join(path.sep, "tmp", "test-state"); + vi.stubEnv("OPENCLAW_STATE_DIR", stateDir); + const cfg: OpenClawConfig = { + agents: { + list: [{ id: "main" }, { id: "work", default: true, workspace: "/work-ws" }], + }, + }; + const workspace = resolveAgentWorkspaceDir(cfg, "main"); + expect(workspace).toBe(path.join(stateDir, "workspace-main")); + }); }); describe("resolveAgentIdByWorkspacePath", () => { diff --git a/src/agents/agent-scope.ts b/src/agents/agent-scope.ts index 7406d9990b5..5d4801fc4ec 100644 --- a/src/agents/agent-scope.ts +++ b/src/agents/agent-scope.ts @@ -272,13 +272,18 @@ export function resolveAgentWorkspaceDir(cfg: OpenClawConfig, agentId: string) { return stripNullBytes(resolveUserPath(configured)); } const defaultAgentId = resolveDefaultAgentId(cfg); + const fallback = cfg.agents?.defaults?.workspace?.trim(); if (id === defaultAgentId) { - const fallback = cfg.agents?.defaults?.workspace?.trim(); if (fallback) { return stripNullBytes(resolveUserPath(fallback)); } return stripNullBytes(resolveDefaultAgentWorkspaceDir(process.env)); } + // Non-default agents: use the configured default workspace as a base so that + // agents.defaults.workspace is respected for all agents, not just the default. + if (fallback) { + return stripNullBytes(path.join(resolveUserPath(fallback), id)); + } const stateDir = resolveStateDir(process.env); return stripNullBytes(path.join(stateDir, `workspace-${id}`)); } diff --git a/src/commands/agents.test.ts b/src/commands/agents.test.ts index dfb339e4384..73d34798d6c 100644 --- a/src/commands/agents.test.ts +++ b/src/commands/agents.test.ts @@ -1,8 +1,6 @@ -import os from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; -import { resolveStateDir } from "../config/paths.js"; import { applyAgentBindings, applyAgentConfig, @@ -45,9 +43,7 @@ describe("agents helpers", () => { const work = summaries.find((summary) => summary.id === "work"); expect(main).toBeTruthy(); - expect(main?.workspace).toBe( - path.join(resolveStateDir(process.env, os.homedir), "workspace-main"), - ); + expect(main?.workspace).toBe(path.resolve("/main-ws/main")); expect(main?.bindings).toBe(1); expect(main?.model).toBe("anthropic/claude"); expect(main?.agentDir.endsWith(path.join("agents", "main", "agent"))).toBe(true);