diff --git a/packages/shared/src/constants.ts b/packages/shared/src/constants.ts index 287ae7835b..587d78d3cb 100644 --- a/packages/shared/src/constants.ts +++ b/packages/shared/src/constants.ts @@ -34,6 +34,7 @@ export const AGENT_ADAPTER_TYPES = [ "codex_local", "cursor_cloud", "gemini_local", + "grok_local", "hermes_gateway", "hermes_local", "opencode_local", diff --git a/packages/shared/src/environment-support.test.ts b/packages/shared/src/environment-support.test.ts index 59b4ec9e4e..396945b027 100644 --- a/packages/shared/src/environment-support.test.ts +++ b/packages/shared/src/environment-support.test.ts @@ -1,5 +1,10 @@ import { describe, expect, it } from "vitest"; -import { isSandboxProviderSupportedForAdapter } from "./environment-support.js"; +import { + adapterSupportsRemoteManagedEnvironments, + getEnvironmentCapabilities, + isSandboxProviderSupportedForAdapter, + supportedEnvironmentDriversForAdapter, +} from "./environment-support.js"; describe("isSandboxProviderSupportedForAdapter", () => { it("accepts additional sandbox providers for remote-managed adapters", () => { @@ -13,4 +18,28 @@ describe("isSandboxProviderSupportedForAdapter", () => { isSandboxProviderSupportedForAdapter("openclaw", "fake-plugin", ["fake-plugin"]), ).toBe(false); }); + + it("treats grok_local as a remote-managed local adapter", () => { + expect(adapterSupportsRemoteManagedEnvironments("grok_local")).toBe(true); + expect(supportedEnvironmentDriversForAdapter("grok_local")).toEqual(["local", "ssh", "sandbox"]); + expect( + isSandboxProviderSupportedForAdapter("grok_local", "fake-plugin", ["fake-plugin"]), + ).toBe(true); + }); + + it("includes grok_local sandbox support in environment capabilities", () => { + const capabilities = getEnvironmentCapabilities(["grok_local"], { + sandboxProviders: { + "fake-plugin": { displayName: "Fake Plugin" }, + }, + }); + + expect(capabilities.adapters).toEqual([ + expect.objectContaining({ + adapterType: "grok_local", + drivers: expect.objectContaining({ sandbox: "supported", ssh: "supported" }), + sandboxProviders: expect.objectContaining({ "fake-plugin": "supported" }), + }), + ]); + }); }); diff --git a/packages/shared/src/environment-support.ts b/packages/shared/src/environment-support.ts index 7373a9bd67..a60f77c5dd 100644 --- a/packages/shared/src/environment-support.ts +++ b/packages/shared/src/environment-support.ts @@ -41,6 +41,7 @@ const REMOTE_MANAGED_ADAPTERS = new Set([ "codex_local", "cursor", "gemini_local", + "grok_local", "opencode_local", "pi_local", ]); diff --git a/ui/src/components/AgentConfigForm.render.test.tsx b/ui/src/components/AgentConfigForm.render.test.tsx index 1f9a11b045..2c4d24cc6f 100644 --- a/ui/src/components/AgentConfigForm.render.test.tsx +++ b/ui/src/components/AgentConfigForm.render.test.tsx @@ -288,6 +288,28 @@ describe("AgentConfigForm environment selector", () => { expect(text).not.toContain("Inherit instance default"); }); + it("shows the environment override for Grok local agents", async () => { + const result = await renderForm( + [ + makeEnvironment({ id: "local-1", name: "Local", driver: "local" }), + makeEnvironment({ + id: "sandbox-1", + name: "E2B", + driver: "sandbox", + config: { provider: "e2b" }, + }), + ], + { adapterType: "grok_local" }, + ); + roots.push(result.root); + + const text = result.container.textContent ?? ""; + const selector = result.container.querySelector("select"); + + expect(text).toContain("Environment override"); + expect(selector?.textContent).toContain("E2B ยท sandbox"); + }); + it("keeps an existing non-runnable override visible so it can be cleared", async () => { const result = await renderForm( [