Simplify agent harness configuration choices

Hide redundant ACP agent selection for harness-derived runner profiles and omit coming-soon harness options.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-26 07:50:42 -05:00
1 parent 4b89eec644
commit bff70f8d6c
4 files changed
+27 -4

No files matched your search

@@ -309,7 +309,7 @@ export function CodexLocalConfigFields({
<ToggleField label="Allow externally billed provider" hint="Muse does not report usage or cost. Paperclip cannot enforce a Muse spend ceiling; known company and agent budget limits still apply."
checked={runnerSchemaValue("allowUnmeteredProvider", false) === true} onChange={value => updateRunnerSchemaValue("allowUnmeteredProvider", value)} />
</>}
{runnerManaged && runnerProvider === "acpx" && runnerSchemaValue("acpxAgent", "claude") !== "grok" && (
{runnerManaged && !hideRunnerHarness && runnerProvider === "acpx" && runnerSchemaValue("acpxAgent", "claude") !== "grok" && (
<Field configSection="adapter" label="ACP agent" hint="Cursor uses Paperclip questions; per-run cost is unavailable. Pi accepts any provider/model ID. GitHub Copilot awaits qualification.">
<Select
value={String(isCreate ? values!.adapterSchemaValues?.acpxAgent ?? "claude" : eff("adapterConfig", "acpxAgent", config.acpxAgent ?? "claude"))}
+1
View File
@@ -55,6 +55,7 @@ export interface AdapterConfigFieldsProps {
openAiDotEnabled?: boolean;
/** Personal Muse is offered only with its own flag and the native Runner enabled. */
museEnabled?: boolean;
/** The parent Harness control determines the profile; hide runner and ACP agent selectors. */
hideRunnerHarness?: boolean;
}
@@ -719,6 +719,29 @@ describe("AgentConfigForm environment selector", () => {
expect(result.onSave).toHaveBeenCalledWith({ name: "Renamed Cody" });
});
it.each([
{ harness: "claude_local", label: "Claude", profile: { provider: "acpx", acpxAgent: "claude" } },
{ harness: "pi_local", label: "Pi", profile: { provider: "acpx", acpxAgent: "pi" } },
{ harness: "codex_local", label: "Codex", profile: { provider: "codex" } },
{ harness: "opencode_local", label: "OpenCode", profile: { provider: "opencode" } },
])("uses only Harness to choose $label for new and saved native agents", async ({ harness, label, profile }) => {
mockAdaptersApi.list.mockResolvedValue([{ type: harness, supportedRunners: ["paperclip", "legacy"], defaultRunner: "paperclip" }]);
const created = await renderCreateForm([], { adapterType: harness, runner: "auto" });
roots.push(created.root);
expect(created.container.querySelector('[aria-label="ACP agent"]')).toBeNull();
if (harness === "pi_local") expect(created.container.querySelector('[aria-label="Pi thinking level"]')).not.toBeNull();
const edited = await renderForm([], { adapterType: "paperclip_runner", adapterConfig: profile }, { showAdapterTypeField: true });
roots.push(edited.root);
expect(edited.container.querySelector('[aria-label="Harness"]')?.textContent).toContain(label);
expect(edited.container.querySelector('[aria-label="ACP agent"]')).toBeNull();
if (harness === "pi_local") expect(edited.container.querySelector('[aria-label="Pi thinking level"]')).not.toBeNull();
await act(async () => setInputValue(edited.container.querySelector<HTMLInputElement>('[placeholder="Agent name"]')!, "Renamed agent"));
await flushReact();
await clickByText(edited.container, "Save");
expect(edited.onSave).toHaveBeenCalledWith({ name: "Renamed agent" });
});
it.each(["codex_local", "claude_local"])("upgrades a saved %s in one click with pending edits", async adapterType => {
mockAdaptersApi.list.mockResolvedValueOnce([{ type: adapterType, supportedRunners: ["legacy", "paperclip"], defaultRunner: "paperclip" }]);
const result = await renderForm([], { adapterType, adapterConfig: { model: "existing-model", effort: "high" } });
+2 -3
View File
@@ -3877,7 +3877,7 @@ export function AdapterTypeDropdown({
[...listAdapterOptions(type => adapterLabels[type] ?? getAdapterLabel(type)),
...(openAiDotEnabled ? [{ value: "openai_dot", label: "OpenAI Dot", experimental: true, comingSoon: false }] : []),
...(museEnabled ? [{ value: "muse", label: "Muse — Personal agent", experimental: true, comingSoon: false }] : []),
].filter(item => (item.value !== "paperclip_runner" || nativeRunnerEnabled) && !disabledTypes.has(item.value))
].filter(item => !item.comingSoon && (item.value !== "paperclip_runner" || nativeRunnerEnabled) && !disabledTypes.has(item.value))
.sort((a, b) => Number(a.value === "paperclip_runner") - Number(b.value === "paperclip_runner")),
[disabledTypes, openAiDotEnabled, nativeRunnerEnabled, museEnabled]);
return <SelectPopover aria-label="Harness" value={value} onValueChange={onChange}
@@ -3886,10 +3886,9 @@ export function AdapterTypeDropdown({
<span className="truncate">{adapterLabels[value] ?? getAdapterLabel(value)}</span>
{selectedDisplay.experimental && <ExperimentalBadge />}
</span>}
options={adapterList.map(item => ({ value: item.value, disabled: item.comingSoon,
options={adapterList.map(item => ({ value: item.value,
group: item.value === "paperclip_runner" ? "Advanced" : undefined,
label: <span className="inline-flex items-center gap-1.5"><span aria-hidden="true" className="inline-flex shrink-0"><AdapterMark type={item.value} className="size-4" /></span><span>{item.label}</span>{item.experimental && <ExperimentalBadge />}</span>,
suffix: item.comingSoon ? <span className="text-(length:--text-nano) text-muted-foreground">Coming soon</span> : undefined,
}))} />;
}