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:
+20
-5
@@ -1,8 +1,16 @@
|
||||
{
|
||||
"name": "@farhoodliquor/paperclip-adapter-claude-k8s",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.8",
|
||||
"description": "Paperclip adapter plugin that runs Claude Code agents as Kubernetes Jobs",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/farhoodliquor/paperclip-adapter-claude-k8s"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/farhoodliquor/paperclip-adapter-claude-k8s/issues"
|
||||
},
|
||||
"homepage": "https://github.com/farhoodliquor/paperclip-adapter-claude-k8s#readme",
|
||||
"type": "module",
|
||||
"paperclip": {
|
||||
"adapterUiParser": "1.0.0"
|
||||
@@ -10,7 +18,8 @@
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./server": "./dist/server/index.js",
|
||||
"./ui-parser": "./dist/ui-parser.js"
|
||||
"./ui-parser": "./dist/ui-parser.js",
|
||||
"./cli": "./dist/cli/index.js"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
@@ -18,10 +27,14 @@
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"clean": "rm -rf dist",
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"coverage": "vitest run --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@kubernetes/client-node": "^1.0.0"
|
||||
"@kubernetes/client-node": "^1.0.0",
|
||||
"picocolors": "^1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@paperclipai/adapter-utils": ">=0.3.0"
|
||||
@@ -29,6 +42,8 @@
|
||||
"devDependencies": {
|
||||
"@paperclipai/adapter-utils": "^0.3.0",
|
||||
"@types/node": "^24.6.0",
|
||||
"typescript": "^5.7.3"
|
||||
"@vitest/coverage-v8": "^4.1.4",
|
||||
"typescript": "^5.7.3",
|
||||
"vitest": "^4.1.4"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-10
@@ -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";
|
||||
|
||||
@@ -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
@@ -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 };
|
||||
|
||||
+2
-1
@@ -15,5 +15,6 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": ["src"],
|
||||
"exclude": ["src/**/*.test.ts", "src/**/*.spec.ts"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
include: ["src/**/*.test.ts"],
|
||||
coverage: {
|
||||
reporter: ["text", "lcov"],
|
||||
include: ["src/**/*.ts"],
|
||||
exclude: ["src/**/*.d.ts", "src/index.ts"],
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user