mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 05:11:49 +01:00
Align native setup isolation and finish shared runtime pickers
Use the server-resolved sandbox transport for native setup, retaining local and SSH isolation and stripping injected flags. Preserve the complete local and managed E2E roster and existing graders. Replace the remaining scoped native dropdowns with the shared picker without changing saved runner or account choices. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
448db859e3
commit
30bc9e40ce
17 files changed
+299
-112
No files matched your search
@@ -576,16 +576,20 @@ async function renderStatefulCreateClaudeSandbox(environments: Environment[]) {
|
||||
return { container, root, valuesRef };
|
||||
}
|
||||
|
||||
async function environmentOptions(container: HTMLElement) {
|
||||
const picker = container.querySelector('[aria-label="Environment override"]');
|
||||
expect(picker).not.toBeNull();
|
||||
await clickElement(picker);
|
||||
const options = document.body.querySelector('[role="listbox"][aria-label="Environment override"]');
|
||||
expect(options).not.toBeNull();
|
||||
return options!;
|
||||
}
|
||||
|
||||
async function selectEnvironment(container: HTMLElement, environmentId: string) {
|
||||
const select = container.querySelector("select");
|
||||
await act(async () => {
|
||||
if (select) {
|
||||
const setter = Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype, "value")?.set;
|
||||
setter?.call(select, environmentId);
|
||||
select.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
}
|
||||
});
|
||||
await flushReact();
|
||||
const options = await environmentOptions(container);
|
||||
const option = options.querySelector(`[role="option"][data-value="${environmentId}"]`);
|
||||
expect(option).not.toBeNull();
|
||||
await clickElement(option);
|
||||
}
|
||||
|
||||
async function clickByText(container: HTMLElement, label: string) {
|
||||
@@ -674,6 +678,40 @@ describe("AgentConfigForm environment selector", () => {
|
||||
expect(result.onSave).toHaveBeenCalledWith({ name: "Renamed Cody" });
|
||||
});
|
||||
|
||||
it.each(["codex_local", "paperclip_runner"])("changes and clears the environment without changing a saved %s runner or account", async adapterType => {
|
||||
const adapterConfig = {
|
||||
model: "gpt-5.6-sol",
|
||||
...(adapterType === "paperclip_runner" ? { provider: "codex", reasoningEffort: "high" } : { modelReasoningEffort: "high" }),
|
||||
env: { CODEX_HOME: { type: "secret_ref", secretId: "codex-account" } },
|
||||
};
|
||||
const result = await renderForm([
|
||||
...daytonaEnvironments(),
|
||||
makeEnvironment({ id: "sandbox-2", name: "Daytona Two", driver: "sandbox", config: { provider: "daytona" } }),
|
||||
], { adapterType, adapterConfig, defaultEnvironmentId: "sandbox-1" }, { showAdapterTypeField: true });
|
||||
roots.push(result.root);
|
||||
await clickByText(result.container, "Advanced");
|
||||
const runnerLabel = adapterType === "paperclip_runner" ? "Paperclip Runner" : "Legacy runner";
|
||||
|
||||
await selectEnvironment(result.container, "sandbox-2");
|
||||
expect(result.container.querySelector('[aria-label="Environment override"]')?.textContent).toContain("Daytona Two");
|
||||
expect(result.container.querySelector('[aria-label="Runner"]')?.textContent).toContain(runnerLabel);
|
||||
await clickByText(result.container, "Save");
|
||||
expect(result.onSave).toHaveBeenLastCalledWith({ defaultEnvironmentId: "sandbox-2" });
|
||||
|
||||
await selectEnvironment(result.container, "");
|
||||
expect(result.container.querySelector('[aria-label="Environment override"]')?.textContent).toContain("Default: Local");
|
||||
expect(result.container.querySelector('[aria-label="Runner"]')?.textContent).toContain(runnerLabel);
|
||||
await clickByText(result.container, "Save");
|
||||
expect(result.onSave).toHaveBeenLastCalledWith({ defaultEnvironmentId: null });
|
||||
});
|
||||
|
||||
it("clears a new agent's environment override to the empty draft value", async () => {
|
||||
const result = await renderCreateForm(daytonaEnvironments(), { defaultEnvironmentId: "sandbox-1", runner: "legacy" });
|
||||
roots.push(result.root);
|
||||
await selectEnvironment(result.container, "");
|
||||
expect(result.onChange).toHaveBeenLastCalledWith({ defaultEnvironmentId: "" });
|
||||
});
|
||||
|
||||
it("submits only an explicit runner change and retains saved configuration for server translation", async () => {
|
||||
const result = await renderForm([], { adapterType: "paperclip_runner", adapterConfig: { provider: "codex", model: "gpt-5.6-sol", reasoningEffort: "high", env: { CODEX_HOME: { type: "secret_ref", secretId: "codex-account" } } } });
|
||||
roots.push(result.root);
|
||||
@@ -910,7 +948,7 @@ describe("AgentConfigForm environment selector", () => {
|
||||
roots.push(result.root);
|
||||
|
||||
expect(result.container.textContent).not.toContain("Environment override");
|
||||
expect(result.container.querySelector("select")).toBeNull();
|
||||
expect(result.container.querySelector('[aria-label="Environment override"]')).toBeNull();
|
||||
});
|
||||
|
||||
it("renders GPT-6 Astra and its model-specific reasoning efforts", async () => {
|
||||
@@ -1029,7 +1067,7 @@ describe("AgentConfigForm environment selector", () => {
|
||||
roots.push(result.root);
|
||||
|
||||
const text = result.container.textContent ?? "";
|
||||
const selector = result.container.querySelector("select");
|
||||
const selector = await environmentOptions(result.container);
|
||||
|
||||
expect(text).toContain("Environment");
|
||||
expect(text).toContain("Environment override");
|
||||
@@ -1048,7 +1086,7 @@ describe("AgentConfigForm environment selector", () => {
|
||||
roots.push(result.root);
|
||||
|
||||
const text = result.container.textContent ?? "";
|
||||
const selector = result.container.querySelector("select");
|
||||
const selector = await environmentOptions(result.container);
|
||||
|
||||
expect(text).toContain("Environment override");
|
||||
expect(selector?.textContent).toContain("E2B · sandbox");
|
||||
@@ -1062,7 +1100,7 @@ describe("AgentConfigForm environment selector", () => {
|
||||
roots.push(result.root);
|
||||
|
||||
const text = result.container.textContent ?? "";
|
||||
const selector = result.container.querySelector("select");
|
||||
const selector = await environmentOptions(result.container);
|
||||
|
||||
expect(text).toContain("Environment override");
|
||||
expect(selector?.textContent).toContain("E2B · sandbox");
|
||||
@@ -1084,7 +1122,7 @@ describe("AgentConfigForm environment selector", () => {
|
||||
roots.push(result.root);
|
||||
|
||||
const text = result.container.textContent ?? "";
|
||||
const selector = result.container.querySelector("select");
|
||||
const selector = await environmentOptions(result.container);
|
||||
|
||||
expect(text).toContain("Environment override");
|
||||
expect(selector?.textContent).toContain("Default: Local");
|
||||
@@ -1104,7 +1142,7 @@ describe("AgentConfigForm environment selector", () => {
|
||||
]);
|
||||
roots.push(result.root);
|
||||
|
||||
const selector = result.container.querySelector("select");
|
||||
const selector = await environmentOptions(result.container);
|
||||
|
||||
expect(selector?.textContent).toContain("Default: Paperclip Computer");
|
||||
expect(selector?.textContent).toContain("Paperclip Computer");
|
||||
@@ -2488,15 +2526,7 @@ describe("AgentConfigForm environment selector", () => {
|
||||
await runTest(result.container);
|
||||
expect(findButton(result.container, "Sign in")).toBeTruthy();
|
||||
|
||||
const select = result.container.querySelector("select");
|
||||
await act(async () => {
|
||||
if (select) {
|
||||
const setter = Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype, "value")?.set;
|
||||
setter?.call(select, "");
|
||||
select.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
}
|
||||
});
|
||||
await flushReact();
|
||||
await selectEnvironment(result.container, "");
|
||||
|
||||
expect(findButton(result.container, "Sign in")).toBeFalsy();
|
||||
});
|
||||
|
||||
@@ -1579,25 +1579,24 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
||||
<div className={cn(cards ? "border border-border rounded-lg p-4 space-y-3" : "px-4 pb-3 space-y-3")}>
|
||||
<Field label="Environment override">
|
||||
<div className="space-y-2">
|
||||
<select
|
||||
className={inputClass}
|
||||
<SelectPopover
|
||||
aria-label="Environment override"
|
||||
value={currentDefaultEnvironmentId}
|
||||
onChange={(event) => {
|
||||
const nextValue = event.target.value;
|
||||
onValueChange={(nextValue) => {
|
||||
if (isCreate) {
|
||||
set!({ defaultEnvironmentId: nextValue });
|
||||
return;
|
||||
}
|
||||
mark("identity", "defaultEnvironmentId", nextValue || null);
|
||||
}}
|
||||
>
|
||||
<option value="">Default: {inheritedEnvironmentLabel}</option>
|
||||
{environmentOptions.map((environment) => (
|
||||
<option key={environment.id} value={environment.id}>
|
||||
{environmentDisplayLabel(environment)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
options={[
|
||||
{ value: "", label: `Default: ${inheritedEnvironmentLabel}` },
|
||||
...environmentOptions.map((environment) => ({
|
||||
value: environment.id,
|
||||
label: environmentDisplayLabel(environment),
|
||||
})),
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user