mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-27 11:20:42 +01:00
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:
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"))}
|
||||
|
||||
@@ -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" } });
|
||||
|
||||
@@ -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,
|
||||
}))} />;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user