Improve imported agent adapter selection
This commit is contained in:
parent
0763e2eb20
commit
fed94d18f3
7 changed files with 95 additions and 20 deletions
|
|
@ -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(),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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}>
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 ───────────────────────────────
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue