feat(adapters): add capability flags to ServerAdapterModule

Replace 5 hardcoded adapter type lists with declarative capability flags
on ServerAdapterModule, enabling external adapter plugins to declare
their capabilities without modifying Paperclip source.

New optional fields on ServerAdapterModule:
- supportsInstructionsBundle: managed instructions bundle support
- instructionsPathKey: config key for instructions file path
- requiresMaterializedRuntimeSkills: skill materialization needed

Server changes:
- agents.ts: capability-aware helpers with legacy fallbacks
- adapters.ts: expose capabilities in GET /api/adapters response
- registry.ts: explicit flags on all built-in adapters

UI changes:
- New useAdapterCapabilities hook for capability lookups
- AgentDetail.tsx: replace hardcoded isLocal allowlist
- AgentConfigForm.tsx: replace NONLOCAL_TYPES denylist
- OnboardingWizard.tsx: replace NONLOCAL_TYPES denylist

All flags are optional with backwards-compatible fallbacks to the
legacy hardcoded lists for adapters that don't set them.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-13 01:02:13 +00:00
parent b649bd454f
commit 904e9cb95e
9 changed files with 153 additions and 15 deletions
+3 -7
View File
@@ -26,6 +26,7 @@ import { AgentConfigForm } from "../components/AgentConfigForm";
import { PageTabBar } from "../components/PageTabBar";
import { adapterLabels, roleLabels, help } from "../components/agent-config-primitives";
import { ToggleSwitch } from "@/components/ui/toggle-switch";
import { useAdapterCapabilities } from "@/adapters/use-adapter-capabilities";
import { MarkdownEditor } from "../components/MarkdownEditor";
import { assetsApi } from "../api/assets";
import { getUIAdapter, buildTranscript, onAdapterChange } from "../adapters";
@@ -1719,13 +1720,8 @@ function PromptsTab({
externalBundleRef.current = null;
}, [agent.id]);
const isLocal =
agent.adapterType === "claude_local" ||
agent.adapterType === "codex_local" ||
agent.adapterType === "opencode_local" ||
agent.adapterType === "pi_local" ||
agent.adapterType === "hermes_local" ||
agent.adapterType === "cursor";
const getCapabilities = useAdapterCapabilities();
const isLocal = getCapabilities(agent.adapterType).supportsInstructionsBundle;
const { data: bundle, isLoading: bundleLoading } = useQuery({
queryKey: queryKeys.agents.instructionsBundle(agent.id),