Add getConfigSchema to surface K8s fields in Paperclip UI

Adds AdapterConfigSchema with three sections (Kubernetes, Resource Limits,
Scheduling) exposing: namespace, image, imagePullPolicy, kubeconfig,
resources.{requests,limits}.{cpu,memory}, nodeSelector, tolerations,
labels, ttlSecondsAfterFinished, retainJobs.

Paperclip's server fetches GET /api/adapters/:type/config-schema and
caches the result, automatically assigning ConfigFields to external
adapters. The adapter now wires getConfigSchema into createServerAdapter().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-12 10:31:55 -04:00
parent 98af28a272
commit 75ba66e504
6 changed files with 213 additions and 17 deletions
+2 -10
View File
@@ -7,14 +7,6 @@ export const models = [
{ id: "claude-haiku-4-6", label: "Claude Haiku 4.6" },
{ id: "claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5" },
{ id: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5" },
// AWS Bedrock US inference profile IDs
{ id: "us.anthropic.claude-opus-4-6-v1", label: "Bedrock Opus 4.6" },
{ id: "us.anthropic.claude-sonnet-4-6", label: "Bedrock Sonnet 4.6" },
{ id: "us.anthropic.claude-opus-4-5-20251101-v1:0", label: "Bedrock Opus 4.5" },
{ id: "us.anthropic.claude-sonnet-4-5-20250929-v1:0", label: "Bedrock Sonnet 4.5" },
{ id: "us.anthropic.claude-haiku-4-5-20251001-v1:0", label: "Bedrock Haiku 4.5" },
{ id: "us.anthropic.claude-opus-4-1-20250805-v1:0", label: "Bedrock Opus 4.1" },
{ id: "us.anthropic.claude-sonnet-4-20250514-v1:0", label: "Bedrock Sonnet 4" },
];
export const agentConfigurationDoc = `# claude_k8s agent configuration
@@ -51,8 +43,7 @@ Operational fields:
- graceSec (number, optional): additional grace before adapter gives up after Job deadline
Inherited from Deployment (no config needed):
- CLAUDE_CODE_USE_BEDROCK, AWS_REGION, AWS_BEARER_TOKEN_BEDROCK
- ANTHROPIC_API_KEY, OPENAI_API_KEY
- ANTHROPIC_API_KEY, OPENAI_API_KEY, and other provider API keys
- PAPERCLIP_API_URL
- Container image, imagePullSecrets, DNS config, PVC mount, security context
@@ -63,3 +54,4 @@ Notes:
`;
export { createServerAdapter } from "./server/index.js";
export { printClaudeStreamEvent } from "./cli/index.js";
+173
View File
@@ -0,0 +1,173 @@
export interface AdapterConfigSchema {
sections?: AdapterConfigSection[];
}
export interface AdapterConfigSection {
title: string;
fields: ConfigFieldSchema[];
}
export type ConfigFieldSchema =
| TextFieldSchema
| NumberFieldSchema
| ToggleFieldSchema
| SelectFieldSchema
| TextareaFieldSchema;
export interface TextFieldSchema {
type: "text";
key: string;
label: string;
description?: string;
placeholder?: string;
helpLink?: string;
}
export interface NumberFieldSchema {
type: "number";
key: string;
label: string;
description?: string;
placeholder?: string;
helpLink?: string;
}
export interface ToggleFieldSchema {
type: "toggle";
key: string;
label: string;
description?: string;
helpLink?: string;
}
export interface SelectFieldSchema {
type: "select";
key: string;
label: string;
description?: string;
options: { value: string; label: string }[];
helpLink?: string;
}
export interface TextareaFieldSchema {
type: "textarea";
key: string;
label: string;
description?: string;
placeholder?: string;
helpLink?: string;
}
export function getConfigSchema(): AdapterConfigSchema {
return {
sections: [
{
title: "Kubernetes",
fields: [
{
type: "text",
key: "namespace",
label: "Namespace",
description: "Kubernetes namespace for Jobs. Defaults to the Deployment namespace.",
},
{
type: "text",
key: "image",
label: "Container Image",
description: "Override the container image used for Job pods. Defaults to the running Deployment image.",
placeholder: "registry/image:tag",
},
{
type: "select",
key: "imagePullPolicy",
label: "Image Pull Policy",
description: "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",
description: "Absolute path to a kubeconfig file on disk. Defaults to in-cluster service account auth.",
placeholder: "/path/to/kubeconfig",
},
{
type: "number",
key: "ttlSecondsAfterFinished",
label: "TTL Seconds After Finished",
description: "Auto-cleanup delay for completed Jobs in seconds. Default: 300.",
},
{
type: "toggle",
key: "retainJobs",
label: "Retain Jobs",
description: "Skip cleanup of completed Jobs for debugging purposes.",
},
],
},
{
title: "Resource Limits",
fields: [
{
type: "text",
key: "resources.requests.cpu",
label: "CPU Request",
description: "CPU request for Job pods (e.g. 100m, 0.5, 1).",
placeholder: "100m",
},
{
type: "text",
key: "resources.requests.memory",
label: "Memory Request",
description: "Memory request for Job pods (e.g. 128Mi, 512Mi, 1Gi).",
placeholder: "512Mi",
},
{
type: "text",
key: "resources.limits.cpu",
label: "CPU Limit",
description: "CPU limit for Job pods (e.g. 100m, 0.5, 1).",
placeholder: "1000m",
},
{
type: "text",
key: "resources.limits.memory",
label: "Memory Limit",
description: "Memory limit for Job pods (e.g. 128Mi, 512Mi, 1Gi).",
placeholder: "1Gi",
},
],
},
{
title: "Scheduling",
fields: [
{
type: "textarea",
key: "nodeSelector",
label: "Node Selector",
description: "Node selector for Job pods. One key=value per line (e.g. disktype=ssd).",
placeholder: "disktype=ssd\ngpu=true",
},
{
type: "textarea",
key: "tolerations",
label: "Tolerations",
description: "Tolerations for Job pods as JSON array.",
placeholder: '[{"key":"node-type","operator":"Equal","value":"gpu","effect":"NoSchedule"}]',
},
{
type: "textarea",
key: "labels",
label: "Labels",
description: "Extra labels added to Job metadata. One key=value per line.",
placeholder: "team=ai\nenv=prod",
},
],
},
],
};
}
+3 -1
View File
@@ -3,6 +3,7 @@ import { type, models, agentConfigurationDoc } from "../index.js";
import { execute } from "./execute.js";
import { testEnvironment } from "./test.js";
import { sessionCodec } from "./session.js";
import { getConfigSchema } from "./config-schema.js";
export function createServerAdapter(): ServerAdapterModule {
return {
@@ -13,7 +14,8 @@ export function createServerAdapter(): ServerAdapterModule {
models,
supportsLocalAgentJwt: true,
agentConfigurationDoc,
};
getConfigSchema,
} as ServerAdapterModule;
}
export { execute, testEnvironment, sessionCodec };