First Release of Claw3D (#11)

Co-authored-by: iamlukethedev <iamlukethedev@users.noreply.github.com>
This commit is contained in:
Luke The Dev
2026-03-19 23:14:04 -05:00
committed by GitHub
parent 5ea96b2650
commit 4fa4f13558
431 changed files with 105438 additions and 14 deletions
@@ -0,0 +1,372 @@
import { createElement, useEffect, useState } from "react";
import { act, render, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { useGatewayConfigSyncController } from "@/features/agents/operations/useGatewayConfigSyncController";
import type { GatewayModelChoice, GatewayModelPolicySnapshot } from "@/lib/gateway/models";
import { updateGatewayAgentOverrides } from "@/lib/gateway/agentConfig";
import type { GatewayClient } from "@/lib/gateway/GatewayClient";
vi.mock("@/lib/gateway/agentConfig", async () => {
const actual = await vi.importActual<typeof import("@/lib/gateway/agentConfig")>(
"@/lib/gateway/agentConfig"
);
return {
...actual,
updateGatewayAgentOverrides: vi.fn(async () => undefined),
};
});
type ProbeValue = {
gatewayConfigSnapshot: GatewayModelPolicySnapshot | null;
gatewayModels: GatewayModelChoice[];
gatewayModelsError: string | null;
refreshGatewayConfigSnapshot: () => Promise<GatewayModelPolicySnapshot | null>;
};
type RenderControllerContext = {
getValue: () => ProbeValue;
rerenderWith: (
overrides: Partial<{
status: "disconnected" | "connecting" | "connected";
settingsRouteActive: boolean;
inspectSidebarAgentId: string | null;
logError: (message: string, err: unknown) => void;
}>
) => void;
call: ReturnType<typeof vi.fn>;
enqueueConfigMutation: ReturnType<typeof vi.fn>;
loadAgents: ReturnType<typeof vi.fn>;
logError: (message: string, err: unknown) => void;
};
const countMethodCalls = (callMock: ReturnType<typeof vi.fn>, method: string) => {
return callMock.mock.calls.filter(([calledMethod]) => calledMethod === method).length;
};
type RenderControllerParams = {
status: "disconnected" | "connecting" | "connected";
settingsRouteActive: boolean;
inspectSidebarAgentId: string | null;
initialGatewayConfigSnapshot?: GatewayModelPolicySnapshot | null;
isDisconnectLikeError: (err: unknown) => boolean;
logError: (message: string, err: unknown) => void;
};
const renderController = (
overrides?: Partial<
RenderControllerParams & {
call: ReturnType<typeof vi.fn>;
enqueueConfigMutation: ReturnType<typeof vi.fn>;
loadAgents: ReturnType<typeof vi.fn>;
}
>
): RenderControllerContext => {
const call =
overrides?.call ??
vi.fn(async (method: string) => {
if (method === "config.get") {
return { config: {} };
}
if (method === "models.list") {
return { models: [] };
}
throw new Error(`Unhandled method: ${method}`);
});
const enqueueConfigMutation =
overrides?.enqueueConfigMutation ??
vi.fn(async ({ run }: { run: () => Promise<void> }) => {
await run();
});
const loadAgents = overrides?.loadAgents ?? vi.fn(async () => undefined);
const logError = (overrides?.logError ?? vi.fn()) as (message: string, err: unknown) => void;
let currentParams: RenderControllerParams = {
status: "connected" as const,
settingsRouteActive: false,
inspectSidebarAgentId: null as string | null,
isDisconnectLikeError: overrides?.isDisconnectLikeError ?? (() => false),
logError,
...overrides,
};
const valueRef: { current: ProbeValue | null } = { current: null };
const Probe = ({
params,
onValue,
}: {
params: typeof currentParams;
onValue: (value: ProbeValue) => void;
}) => {
const [client] = useState(() => ({ call }));
const [gatewayConfigSnapshot, setGatewayConfigSnapshot] = useState<GatewayModelPolicySnapshot | null>(
params.initialGatewayConfigSnapshot ?? null
);
const [gatewayModels, setGatewayModels] = useState<GatewayModelChoice[]>([]);
const [gatewayModelsError, setGatewayModelsError] = useState<string | null>(null);
const { refreshGatewayConfigSnapshot } = useGatewayConfigSyncController({
client: client as unknown as GatewayClient,
status: params.status,
settingsRouteActive: params.settingsRouteActive,
inspectSidebarAgentId: params.inspectSidebarAgentId,
gatewayConfigSnapshot,
setGatewayConfigSnapshot,
setGatewayModels,
setGatewayModelsError,
enqueueConfigMutation: enqueueConfigMutation as (params: {
kind: "repair-sandbox-tool-allowlist";
label: string;
run: () => Promise<void>;
}) => Promise<void>,
loadAgents: loadAgents as () => Promise<void>,
isDisconnectLikeError: params.isDisconnectLikeError,
logError: params.logError,
});
useEffect(() => {
onValue({
gatewayConfigSnapshot,
gatewayModels,
gatewayModelsError,
refreshGatewayConfigSnapshot,
});
}, [gatewayConfigSnapshot, gatewayModels, gatewayModelsError, onValue, refreshGatewayConfigSnapshot]);
return createElement("div", { "data-testid": "probe" }, "ok");
};
const rendered = render(
createElement(Probe, {
params: currentParams,
onValue: (value) => {
valueRef.current = value;
},
})
);
return {
getValue: () => {
if (!valueRef.current) throw new Error("controller value unavailable");
return valueRef.current;
},
rerenderWith: (nextOverrides) => {
currentParams = {
...currentParams,
...nextOverrides,
};
rendered.rerender(
createElement(Probe, {
params: currentParams,
onValue: (value) => {
valueRef.current = value;
},
})
);
},
call,
enqueueConfigMutation,
loadAgents,
logError,
};
};
describe("useGatewayConfigSyncController", () => {
const mockedUpdateGatewayAgentOverrides = vi.mocked(updateGatewayAgentOverrides);
beforeEach(() => {
mockedUpdateGatewayAgentOverrides.mockReset();
mockedUpdateGatewayAgentOverrides.mockResolvedValue();
});
it("clears models, model error, and snapshot when disconnected", async () => {
const call = vi.fn(async (method: string) => {
if (method === "config.get") {
return { config: { agents: { list: [] } } };
}
if (method === "models.list") {
return { models: [{ provider: "openai", id: "gpt-4o", name: "GPT-4o" }] };
}
throw new Error(`Unhandled method: ${method}`);
});
const ctx = renderController({ call, status: "connected" });
await waitFor(() => {
expect(ctx.getValue().gatewayModels).toEqual([
{ provider: "openai", id: "gpt-4o", name: "GPT-4o" },
]);
});
ctx.rerenderWith({ status: "disconnected" });
await waitFor(() => {
expect(ctx.getValue().gatewayModels).toEqual([]);
expect(ctx.getValue().gatewayModelsError).toBeNull();
expect(ctx.getValue().gatewayConfigSnapshot).toBeNull();
});
});
it("still loads models when config.get fails", async () => {
const call = vi.fn(async (method: string) => {
if (method === "config.get") {
throw new Error("config failed");
}
if (method === "models.list") {
return {
models: [{ provider: "openai", id: "gpt-4o", name: "GPT-4o" }],
};
}
throw new Error(`Unhandled method: ${method}`);
});
const logError = vi.fn();
const ctx = renderController({ call, logError });
await waitFor(() => {
expect(ctx.getValue().gatewayModels).toEqual([
{ provider: "openai", id: "gpt-4o", name: "GPT-4o" },
]);
});
expect(countMethodCalls(call, "models.list")).toBe(1);
expect(logError).toHaveBeenCalledWith("Failed to load gateway config.", expect.any(Error));
});
it("captures model loading errors and clears models", async () => {
const call = vi.fn(async (method: string) => {
if (method === "config.get") {
return { config: { agents: { list: [] } } };
}
if (method === "models.list") {
throw new Error("models unavailable");
}
throw new Error(`Unhandled method: ${method}`);
});
const logError = vi.fn();
const ctx = renderController({ call, logError });
await waitFor(() => {
expect(ctx.getValue().gatewayModels).toEqual([]);
expect(ctx.getValue().gatewayModelsError).toBe("models unavailable");
});
expect(logError).toHaveBeenCalledWith("Failed to load gateway models.", expect.any(Error));
});
it("runs settings-route refresh only when inspect agent id is present", async () => {
const call = vi.fn(async (method: string) => {
if (method === "config.get") {
return { config: { agents: { list: [] } } };
}
if (method === "models.list") {
return { models: [] };
}
throw new Error(`Unhandled method: ${method}`);
});
renderController({
call,
status: "connected",
settingsRouteActive: true,
inspectSidebarAgentId: null,
});
await waitFor(() => {
expect(countMethodCalls(call, "config.get")).toBe(1);
expect(countMethodCalls(call, "models.list")).toBe(1);
});
const callEligible = vi.fn(async (method: string) => {
if (method === "config.get") {
return { config: { agents: { list: [] } } };
}
if (method === "models.list") {
return { models: [] };
}
throw new Error(`Unhandled method: ${method}`);
});
renderController({
call: callEligible,
status: "connected",
settingsRouteActive: true,
inspectSidebarAgentId: "agent-1",
});
await waitFor(() => {
expect(countMethodCalls(callEligible, "config.get")).toBeGreaterThanOrEqual(2);
expect(countMethodCalls(callEligible, "models.list")).toBe(1);
});
});
it("enqueues sandbox repair once for eligible agents", async () => {
const brokenSnapshot = {
config: {
agents: {
list: [
{
id: "agent-broken",
sandbox: { mode: "all" },
tools: {
sandbox: {
tools: {
allow: [],
},
},
},
},
],
},
},
} as unknown as GatewayModelPolicySnapshot;
const call = vi.fn(async (method: string) => {
if (method === "config.get") {
return brokenSnapshot;
}
if (method === "models.list") {
return { models: [] };
}
throw new Error(`Unhandled method: ${method}`);
});
const enqueueConfigMutation = vi.fn(async ({ run }: { run: () => Promise<void> }) => {
await run();
});
const loadAgents = vi.fn(async () => undefined);
const ctx = renderController({
call,
enqueueConfigMutation,
loadAgents,
initialGatewayConfigSnapshot: brokenSnapshot,
});
await waitFor(() => {
expect(enqueueConfigMutation).toHaveBeenCalledTimes(1);
expect(mockedUpdateGatewayAgentOverrides).toHaveBeenCalledTimes(1);
expect(loadAgents).toHaveBeenCalledTimes(1);
});
ctx.rerenderWith({ status: "connected" });
await act(async () => {
await Promise.resolve();
});
expect(enqueueConfigMutation).toHaveBeenCalledTimes(1);
expect(mockedUpdateGatewayAgentOverrides).toHaveBeenCalledTimes(1);
});
it("returns null when refresh is called while disconnected", async () => {
const call = vi.fn(async () => {
throw new Error("should not call gateway when disconnected");
});
const ctx = renderController({ call, status: "disconnected" });
const result = await ctx.getValue().refreshGatewayConfigSnapshot();
expect(result).toBeNull();
expect(call).not.toHaveBeenCalled();
});
});