Improve imported agent adapter selection

This commit is contained in:
Dotta 2026-03-16 12:17:28 -05:00
parent 0763e2eb20
commit fed94d18f3
7 changed files with 95 additions and 20 deletions

View file

@ -471,4 +471,71 @@ describe("company portability", () => {
}, },
]); ]);
}); });
it("applies adapter overrides while keeping imported AGENTS content implicit", async () => {
const portability = companyPortabilityService({} as any);
companySvc.create.mockResolvedValue({
id: "company-imported",
name: "Imported Paperclip",
});
accessSvc.ensureMembership.mockResolvedValue(undefined);
agentSvc.create.mockResolvedValue({
id: "agent-created",
name: "ClaudeCoder",
});
const exported = await portability.exportBundle("company-1", {
include: {
company: true,
agents: true,
projects: false,
issues: false,
},
});
agentSvc.list.mockResolvedValue([]);
await portability.importBundle({
source: {
type: "inline",
rootPath: exported.rootPath,
files: exported.files,
},
include: {
company: true,
agents: true,
projects: false,
issues: false,
},
target: {
mode: "new_company",
newCompanyName: "Imported Paperclip",
},
agents: "all",
collisionStrategy: "rename",
adapterOverrides: {
claudecoder: {
adapterType: "codex_local",
adapterConfig: {
dangerouslyBypassApprovalsAndSandbox: true,
instructionsFilePath: "/tmp/should-not-survive.md",
},
},
},
}, "user-1");
expect(agentSvc.create).toHaveBeenCalledWith("company-imported", expect.objectContaining({
adapterType: "codex_local",
adapterConfig: expect.objectContaining({
promptTemplate: "You are ClaudeCoder.",
dangerouslyBypassApprovalsAndSandbox: true,
}),
}));
expect(agentSvc.create).toHaveBeenCalledWith("company-imported", expect.objectContaining({
adapterConfig: expect.not.objectContaining({
instructionsFilePath: expect.anything(),
}),
}));
});
}); });

View file

@ -2274,7 +2274,7 @@ export function companyPortabilityService(db: Db) {
baseAdapterConfig, baseAdapterConfig,
desiredSkills, desiredSkills,
); );
delete baseAdapterConfig.instructionsFilePath; delete adapterConfigWithSkills.instructionsFilePath;
const patch = { const patch = {
name: planAgent.plannedName, name: planAgent.plannedName,
role: manifestAgent.role, role: manifestAgent.role,

View file

@ -17,7 +17,9 @@ export function GeminiLocalConfigFields({
config, config,
eff, eff,
mark, mark,
hideInstructionsFile,
}: AdapterConfigFieldsProps) { }: AdapterConfigFieldsProps) {
if (hideInstructionsFile) return null;
return ( return (
<> <>
<Field label="Agent instructions file" hint={instructionsFileHint}> <Field label="Agent instructions file" hint={instructionsFileHint}>

View file

@ -1,4 +1,4 @@
export { getUIAdapter } from "./registry"; export { getUIAdapter, listUIAdapters } from "./registry";
export { buildTranscript } from "./transcript"; export { buildTranscript } from "./transcript";
export type { export type {
TranscriptEntry, TranscriptEntry,

View file

@ -17,7 +17,9 @@ export function PiLocalConfigFields({
config, config,
eff, eff,
mark, mark,
hideInstructionsFile,
}: AdapterConfigFieldsProps) { }: AdapterConfigFieldsProps) {
if (hideInstructionsFile) return null;
return ( return (
<Field label="Agent instructions file" hint={instructionsFileHint}> <Field label="Agent instructions file" hint={instructionsFileHint}>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">

View file

@ -9,20 +9,26 @@ import { openClawGatewayUIAdapter } from "./openclaw-gateway";
import { processUIAdapter } from "./process"; import { processUIAdapter } from "./process";
import { httpUIAdapter } from "./http"; import { httpUIAdapter } from "./http";
const uiAdapters: UIAdapterModule[] = [
claudeLocalUIAdapter,
codexLocalUIAdapter,
geminiLocalUIAdapter,
openCodeLocalUIAdapter,
piLocalUIAdapter,
cursorLocalUIAdapter,
openClawGatewayUIAdapter,
processUIAdapter,
httpUIAdapter,
];
const adaptersByType = new Map<string, UIAdapterModule>( const adaptersByType = new Map<string, UIAdapterModule>(
[ uiAdapters.map((a) => [a.type, a]),
claudeLocalUIAdapter,
codexLocalUIAdapter,
geminiLocalUIAdapter,
openCodeLocalUIAdapter,
piLocalUIAdapter,
cursorLocalUIAdapter,
openClawGatewayUIAdapter,
processUIAdapter,
httpUIAdapter,
].map((a) => [a.type, a]),
); );
export function getUIAdapter(type: string): UIAdapterModule { export function getUIAdapter(type: string): UIAdapterModule {
return adaptersByType.get(type) ?? processUIAdapter; return adaptersByType.get(type) ?? processUIAdapter;
} }
export function listUIAdapters(): UIAdapterModule[] {
return [...uiAdapters];
}

View file

@ -26,7 +26,7 @@ import {
} from "lucide-react"; } from "lucide-react";
import { Field, adapterLabels } from "../components/agent-config-primitives"; import { Field, adapterLabels } from "../components/agent-config-primitives";
import { defaultCreateValues } from "../components/agent-config-defaults"; import { defaultCreateValues } from "../components/agent-config-defaults";
import { getUIAdapter } from "../adapters"; import { getUIAdapter, listUIAdapters } from "../adapters";
import { ClaudeLocalAdvancedFields } from "../adapters/claude-local/config-fields"; import { ClaudeLocalAdvancedFields } from "../adapters/claude-local/config-fields";
import type { CreateConfigValues } from "@paperclipai/adapter-utils"; import type { CreateConfigValues } from "@paperclipai/adapter-utils";
import { import {
@ -443,12 +443,10 @@ function ConflictResolutionList({
// ── Adapter type options for import ─────────────────────────────────── // ── Adapter type options for import ───────────────────────────────────
const IMPORT_ADAPTER_OPTIONS: { value: string; label: string }[] = [ const IMPORT_ADAPTER_OPTIONS: { value: string; label: string }[] = listUIAdapters().map((adapter) => ({
{ value: "claude_local", label: adapterLabels.claude_local ?? "Claude (local)" }, value: adapter.type,
{ value: "codex_local", label: adapterLabels.codex_local ?? "Codex (local)" }, label: adapterLabels[adapter.type] ?? adapter.label,
{ value: "opencode_local", label: adapterLabels.opencode_local ?? "OpenCode (local)" }, }));
{ value: "cursor", label: adapterLabels.cursor ?? "Cursor (local)" },
];
// ── Adapter picker for imported agents ─────────────────────────────── // ── Adapter picker for imported agents ───────────────────────────────