// NOTE: These types must match what Paperclip's SchemaConfigFields component // expects. Paperclip's server at GET /api/adapters/:type/config-schema // calls adapter.getConfigSchema() and the UI reads the JSON — types are only // used at build time here. The Paperclip types in @paperclipai/adapter-utils // may lag behind; these locals are the source of truth for this adapter. interface ConfigFieldOption { label: string; value: string; group?: string; } type ConfigFieldSchema = | { type: "text"; key: string; label: string; hint?: string; default?: unknown; meta?: Record } | { type: "number"; key: string; label: string; hint?: string; default?: unknown; meta?: Record } | { type: "toggle"; key: string; label: string; hint?: string; default?: unknown; meta?: Record } | { type: "select"; key: string; label: string; hint?: string; options: ConfigFieldOption[]; default?: unknown; meta?: Record } | { type: "textarea"; key: string; label: string; hint?: string; default?: unknown; meta?: Record } | { type: "combobox"; key: string; label: string; hint?: string; options?: ConfigFieldOption[]; default?: unknown; meta?: Record }; interface AdapterConfigSchema { fields: ConfigFieldSchema[]; } export function getConfigSchema(): AdapterConfigSchema { // model, effort, instructionsFilePath, timeoutSec, graceSec are provided // by the platform UI and must not be duplicated here. const fields: ConfigFieldSchema[] = [ // Core Claude fields { type: "number", key: "maxTurnsPerRun", label: "Max Turns Per Run", hint: "Maximum number of agentic turns (tool calls) per heartbeat run. 0 means unlimited.", default: 1000, }, // Kubernetes { type: "text", key: "serviceAccountName", label: "Service Account", hint: "Service Account name for Job pods. Defaults to the cluster default.", }, { type: "text", key: "namespace", label: "Namespace", hint: "Kubernetes namespace for Jobs. Defaults to the Deployment namespace.", }, { type: "text", key: "image", label: "Container Image", hint: "Override the container image used for Job pods. Defaults to the running Deployment image.", }, { type: "select", key: "imagePullPolicy", label: "Image Pull Policy", hint: "Image pull policy for the container image.", options: [ { value: "IfNotPresent", label: "IfNotPresent" }, { value: "Always", label: "Always" }, { value: "Never", label: "Never" }, ], }, { type: "text", key: "kubeconfig", label: "Kubeconfig Path", hint: "Absolute path to a kubeconfig file on disk. Defaults to in-cluster service account auth.", }, { type: "number", key: "ttlSecondsAfterFinished", label: "TTL Seconds After Finished", hint: "Auto-cleanup delay for completed Jobs in seconds. Default: 300.", }, { type: "toggle", key: "retainJobs", label: "Retain Jobs", hint: "Skip cleanup of completed Jobs for debugging purposes.", }, { type: "toggle", key: "reattachOrphanedJobs", label: "Reattach to Orphaned Jobs", hint: "If a prior K8s Job for the same agent/task/session is still running (e.g. Paperclip restarted mid-run), attach to it and stream its output instead of blocking the new run. When false, any non-terminal orphan blocks the new run. Default: on.", default: true, }, // Resource Limits { type: "text", key: "resources.requests.cpu", label: "CPU Request", hint: "CPU request for Job pods (e.g. 100m, 0.5, 1).", }, { type: "text", key: "resources.requests.memory", label: "Memory Request", hint: "Memory request for Job pods (e.g. 128Mi, 512Mi, 1Gi).", }, { type: "text", key: "resources.limits.cpu", label: "CPU Limit", hint: "CPU limit for Job pods (e.g. 100m, 0.5, 1).", }, { type: "text", key: "resources.limits.memory", label: "Memory Limit", hint: "Memory limit for Job pods (e.g. 128Mi, 512Mi, 1Gi).", }, // Scheduling { type: "textarea", key: "nodeSelector", label: "Node Selector", hint: "Node selector for Job pods. One key=value per line (e.g. disktype=ssd).", }, { type: "textarea", key: "tolerations", label: "Tolerations", hint: "Tolerations for Job pods as JSON array.", }, { type: "textarea", key: "labels", label: "Labels", hint: "Extra labels added to Job metadata. One key=value per line.", }, // Output filtering (RTK-compatible) { type: "toggle", key: "enableRtk", label: "Enable Output Filtering", hint: "Truncate oversized tool outputs before they reach the model, reducing token consumption. Implemented natively in Node.js — no external binary required. Installs a PostToolUse hook in ~/.claude/settings.json for each run.", default: false, }, { type: "number", key: "rtkMaxOutputBytes", label: "Max Tool Output Bytes", hint: "Maximum bytes of tool output to pass to the model when output filtering is enabled. Outputs exceeding this threshold are truncated with a summary. Default: 50000.", default: 50000, }, ]; return { fields }; }