Hide deprecated agent working directory by default
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -44,6 +44,7 @@ import { ClaudeLocalAdvancedFields } from "../adapters/claude-local/config-field
|
|||||||
import { MarkdownEditor } from "./MarkdownEditor";
|
import { MarkdownEditor } from "./MarkdownEditor";
|
||||||
import { ChoosePathButton } from "./PathInstructionsModal";
|
import { ChoosePathButton } from "./PathInstructionsModal";
|
||||||
import { OpenCodeLogoIcon } from "./OpenCodeLogoIcon";
|
import { OpenCodeLogoIcon } from "./OpenCodeLogoIcon";
|
||||||
|
import { shouldShowLegacyWorkingDirectoryField } from "../lib/legacy-agent-config";
|
||||||
|
|
||||||
/* ---- Create mode values ---- */
|
/* ---- Create mode values ---- */
|
||||||
|
|
||||||
@@ -297,6 +298,8 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||||||
adapterType === "opencode_local" ||
|
adapterType === "opencode_local" ||
|
||||||
adapterType === "pi_local" ||
|
adapterType === "pi_local" ||
|
||||||
adapterType === "cursor";
|
adapterType === "cursor";
|
||||||
|
const showLegacyWorkingDirectoryField =
|
||||||
|
isLocal && shouldShowLegacyWorkingDirectoryField({ isCreate, adapterConfig: config });
|
||||||
const uiAdapter = useMemo(() => getUIAdapter(adapterType), [adapterType]);
|
const uiAdapter = useMemo(() => getUIAdapter(adapterType), [adapterType]);
|
||||||
|
|
||||||
// Fetch adapter models for the effective adapter type
|
// Fetch adapter models for the effective adapter type
|
||||||
@@ -590,8 +593,8 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Working directory */}
|
{/* Working directory */}
|
||||||
{isLocal && (
|
{showLegacyWorkingDirectoryField && (
|
||||||
<Field label="Working directory" hint={help.cwd}>
|
<Field label="Working directory (deprecated)" hint={help.cwd}>
|
||||||
<div className="flex items-center gap-2 rounded-md border border-border px-2.5 py-1.5">
|
<div className="flex items-center gap-2 rounded-md border border-border px-2.5 py-1.5">
|
||||||
<FolderOpen className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
<FolderOpen className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||||
<DraftInput
|
<DraftInput
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ import { DEFAULT_CURSOR_LOCAL_MODEL } from "@paperclipai/adapter-cursor-local";
|
|||||||
import { DEFAULT_GEMINI_LOCAL_MODEL } from "@paperclipai/adapter-gemini-local";
|
import { DEFAULT_GEMINI_LOCAL_MODEL } from "@paperclipai/adapter-gemini-local";
|
||||||
import { resolveRouteOnboardingOptions } from "../lib/onboarding-route";
|
import { resolveRouteOnboardingOptions } from "../lib/onboarding-route";
|
||||||
import { AsciiArtAnimation } from "./AsciiArtAnimation";
|
import { AsciiArtAnimation } from "./AsciiArtAnimation";
|
||||||
import { ChoosePathButton } from "./PathInstructionsModal";
|
|
||||||
import { HintIcon } from "./agent-config-primitives";
|
|
||||||
import { OpenCodeLogoIcon } from "./OpenCodeLogoIcon";
|
import { OpenCodeLogoIcon } from "./OpenCodeLogoIcon";
|
||||||
import {
|
import {
|
||||||
Building2,
|
Building2,
|
||||||
@@ -49,7 +47,6 @@ import {
|
|||||||
MousePointer2,
|
MousePointer2,
|
||||||
Check,
|
Check,
|
||||||
Loader2,
|
Loader2,
|
||||||
FolderOpen,
|
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
X
|
X
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
@@ -113,7 +110,6 @@ export function OnboardingWizard() {
|
|||||||
// Step 2
|
// Step 2
|
||||||
const [agentName, setAgentName] = useState("CEO");
|
const [agentName, setAgentName] = useState("CEO");
|
||||||
const [adapterType, setAdapterType] = useState<AdapterType>("claude_local");
|
const [adapterType, setAdapterType] = useState<AdapterType>("claude_local");
|
||||||
const [cwd, setCwd] = useState("");
|
|
||||||
const [model, setModel] = useState("");
|
const [model, setModel] = useState("");
|
||||||
const [command, setCommand] = useState("");
|
const [command, setCommand] = useState("");
|
||||||
const [args, setArgs] = useState("");
|
const [args, setArgs] = useState("");
|
||||||
@@ -217,7 +213,7 @@ export function OnboardingWizard() {
|
|||||||
if (step !== 2) return;
|
if (step !== 2) return;
|
||||||
setAdapterEnvResult(null);
|
setAdapterEnvResult(null);
|
||||||
setAdapterEnvError(null);
|
setAdapterEnvError(null);
|
||||||
}, [step, adapterType, cwd, model, command, args, url]);
|
}, [step, adapterType, model, command, args, url]);
|
||||||
|
|
||||||
const selectedModel = (adapterModels ?? []).find((m) => m.id === model);
|
const selectedModel = (adapterModels ?? []).find((m) => m.id === model);
|
||||||
const hasAnthropicApiKeyOverrideCheck =
|
const hasAnthropicApiKeyOverrideCheck =
|
||||||
@@ -273,7 +269,6 @@ export function OnboardingWizard() {
|
|||||||
setCompanyGoal("");
|
setCompanyGoal("");
|
||||||
setAgentName("CEO");
|
setAgentName("CEO");
|
||||||
setAdapterType("claude_local");
|
setAdapterType("claude_local");
|
||||||
setCwd("");
|
|
||||||
setModel("");
|
setModel("");
|
||||||
setCommand("");
|
setCommand("");
|
||||||
setArgs("");
|
setArgs("");
|
||||||
@@ -301,7 +296,6 @@ export function OnboardingWizard() {
|
|||||||
const config = adapter.buildAdapterConfig({
|
const config = adapter.buildAdapterConfig({
|
||||||
...defaultCreateValues,
|
...defaultCreateValues,
|
||||||
adapterType,
|
adapterType,
|
||||||
cwd,
|
|
||||||
model:
|
model:
|
||||||
adapterType === "codex_local"
|
adapterType === "codex_local"
|
||||||
? model || DEFAULT_CODEX_LOCAL_MODEL
|
? model || DEFAULT_CODEX_LOCAL_MODEL
|
||||||
@@ -874,24 +868,6 @@ export function OnboardingWizard() {
|
|||||||
adapterType === "pi_local" ||
|
adapterType === "pi_local" ||
|
||||||
adapterType === "cursor") && (
|
adapterType === "cursor") && (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div>
|
|
||||||
<div className="flex items-center gap-1.5 mb-1">
|
|
||||||
<label className="text-xs text-muted-foreground">
|
|
||||||
Working directory
|
|
||||||
</label>
|
|
||||||
<HintIcon text="Paperclip works best if you create a new folder for your agents to keep their memories and stay organized. Create a new folder and put the path here." />
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2 rounded-md border border-border px-2.5 py-1.5">
|
|
||||||
<FolderOpen className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
|
||||||
<input
|
|
||||||
className="w-full bg-transparent outline-none text-sm font-mono placeholder:text-muted-foreground/50"
|
|
||||||
placeholder="/path/to/project"
|
|
||||||
value={cwd}
|
|
||||||
onChange={(e) => setCwd(e.target.value)}
|
|
||||||
/>
|
|
||||||
<ChoosePathButton />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs text-muted-foreground mb-1 block">
|
<label className="text-xs text-muted-foreground mb-1 block">
|
||||||
Model
|
Model
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const help: Record<string, string> = {
|
|||||||
reportsTo: "The agent this one reports to in the org hierarchy.",
|
reportsTo: "The agent this one reports to in the org hierarchy.",
|
||||||
capabilities: "Describes what this agent can do. Shown in the org chart and used for task routing.",
|
capabilities: "Describes what this agent can do. Shown in the org chart and used for task routing.",
|
||||||
adapterType: "How this agent runs: local CLI (Claude/Codex/OpenCode), OpenClaw Gateway, spawned process, or generic HTTP webhook.",
|
adapterType: "How this agent runs: local CLI (Claude/Codex/OpenCode), OpenClaw Gateway, spawned process, or generic HTTP webhook.",
|
||||||
cwd: "Default working directory fallback for local adapters. Use an absolute path on the machine running Paperclip.",
|
cwd: "Deprecated legacy working directory fallback for local adapters. Existing agents may still carry this value, but new configurations should use project workspaces instead.",
|
||||||
promptTemplate: "Sent on every heartbeat. Keep this small and dynamic. Use it for current-task framing, not large static instructions. Supports {{ agent.id }}, {{ agent.name }}, {{ agent.role }} and other template variables.",
|
promptTemplate: "Sent on every heartbeat. Keep this small and dynamic. Use it for current-task framing, not large static instructions. Supports {{ agent.id }}, {{ agent.name }}, {{ agent.role }} and other template variables.",
|
||||||
model: "Override the default model used by the adapter.",
|
model: "Override the default model used by the adapter.",
|
||||||
thinkingEffort: "Control model reasoning depth. Supported values vary by adapter/model.",
|
thinkingEffort: "Control model reasoning depth. Supported values vary by adapter/model.",
|
||||||
|
|||||||
40
ui/src/lib/legacy-agent-config.test.ts
Normal file
40
ui/src/lib/legacy-agent-config.test.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import {
|
||||||
|
hasLegacyWorkingDirectory,
|
||||||
|
shouldShowLegacyWorkingDirectoryField,
|
||||||
|
} from "./legacy-agent-config";
|
||||||
|
|
||||||
|
describe("legacy agent config helpers", () => {
|
||||||
|
it("treats non-empty cwd values as legacy working directories", () => {
|
||||||
|
expect(hasLegacyWorkingDirectory("/tmp/workspace")).toBe(true);
|
||||||
|
expect(hasLegacyWorkingDirectory(" /tmp/workspace ")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores nullish and blank cwd values", () => {
|
||||||
|
expect(hasLegacyWorkingDirectory("")).toBe(false);
|
||||||
|
expect(hasLegacyWorkingDirectory(" ")).toBe(false);
|
||||||
|
expect(hasLegacyWorkingDirectory(null)).toBe(false);
|
||||||
|
expect(hasLegacyWorkingDirectory(undefined)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows the deprecated field only for edit forms with an existing cwd", () => {
|
||||||
|
expect(
|
||||||
|
shouldShowLegacyWorkingDirectoryField({
|
||||||
|
isCreate: true,
|
||||||
|
adapterConfig: { cwd: "/tmp/workspace" },
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
shouldShowLegacyWorkingDirectoryField({
|
||||||
|
isCreate: false,
|
||||||
|
adapterConfig: { cwd: "" },
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
shouldShowLegacyWorkingDirectoryField({
|
||||||
|
isCreate: false,
|
||||||
|
adapterConfig: { cwd: "/tmp/workspace" },
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
17
ui/src/lib/legacy-agent-config.ts
Normal file
17
ui/src/lib/legacy-agent-config.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
function asNonEmptyString(value: unknown): string | null {
|
||||||
|
if (typeof value !== "string") return null;
|
||||||
|
const trimmed = value.trim();
|
||||||
|
return trimmed.length > 0 ? trimmed : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasLegacyWorkingDirectory(value: unknown): boolean {
|
||||||
|
return asNonEmptyString(value) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldShowLegacyWorkingDirectoryField(input: {
|
||||||
|
isCreate: boolean;
|
||||||
|
adapterConfig: Record<string, unknown> | null | undefined;
|
||||||
|
}): boolean {
|
||||||
|
if (input.isCreate) return false;
|
||||||
|
return hasLegacyWorkingDirectory(input.adapterConfig?.cwd);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user