diff --git a/.github/workflows/Check-config-schema.yml b/.github/workflows/Check-config-schema.yml index 98c58fc1c0..ea0080e605 100644 --- a/.github/workflows/Check-config-schema.yml +++ b/.github/workflows/Check-config-schema.yml @@ -46,3 +46,25 @@ jobs: - name: Config file validation run: make check-config-files working-directory: apps/${{ matrix.app }} + + check-chart-schema: + name: "Helm chart values schema" + runs-on: ubuntu-latest + needs: check-config + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - uses: astral-sh/setup-uv@v5 + + - name: Install inline script dependencies + run: uv pip install --system "jsonschema>=4.0,<5" "pyyaml>=6.0" + + - name: Chart schema drift check + run: make check-chart-schema-drift + + - name: Chart values validation + run: make check-chart-values diff --git a/Makefile b/Makefile index 4f3bd3bdec..60cf672626 100644 --- a/Makefile +++ b/Makefile @@ -211,6 +211,7 @@ db-check-combined-postgres: db-check-combined-postgres-down db-check-combined-po $(MAKE) db-check-combined-postgres-down include scripts/makefiles/help.mk +include scripts/makefiles/chart-schema.mk # ============================================================================= # k3d local deployment diff --git a/apps/knowledge-flow-backend/config/schema/configuration.schema.json b/apps/knowledge-flow-backend/config/schema/configuration.schema.json index 69c5353137..3e5a162be1 100644 --- a/apps/knowledge-flow-backend/config/schema/configuration.schema.json +++ b/apps/knowledge-flow-backend/config/schema/configuration.schema.json @@ -812,6 +812,34 @@ "description": "Expose agent filesystem utils endpoints and the corresponding MCP server.", "title": "Filesystem Enabled", "type": "boolean" + }, + "filesystem_read_default_limit": { + "default": 100, + "description": "Default line count returned by filesystem read_file when callers omit limit.", + "minimum": 1, + "title": "Filesystem Read Default Limit", + "type": "integer" + }, + "filesystem_read_max_limit": { + "default": 500, + "description": "Absolute maximum line count accepted by filesystem read_file.", + "minimum": 1, + "title": "Filesystem Read Max Limit", + "type": "integer" + }, + "filesystem_read_default_max_chars": { + "default": 20000, + "description": "Default maximum character count returned by filesystem read_file when callers omit max_chars.", + "minimum": 1, + "title": "Filesystem Read Default Max Chars", + "type": "integer" + }, + "filesystem_read_absolute_max_chars": { + "default": 50000, + "description": "Absolute maximum character count accepted by filesystem read_file.", + "minimum": 1, + "title": "Filesystem Read Absolute Max Chars", + "type": "integer" } }, "title": "MCPConfig", diff --git a/deploy/charts/fred/values.schema.json b/deploy/charts/fred/values.schema.json new file mode 100644 index 0000000000..cd12912b53 --- /dev/null +++ b/deploy/charts/fred/values.schema.json @@ -0,0 +1,14299 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "title": "Fred Helm Chart Values", + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": {} + }, + "properties": { + "global": { + "type": "object", + "properties": { + "kubeconfig": { + "type": "string" + }, + "persistence": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "dynamic": { + "type": "boolean" + }, + "accessModes": { + "type": "string" + }, + "reclaimPolicy": { + "type": "string" + }, + "storageClass": { + "type": "string" + }, + "hostPath": { + "type": "string" + } + }, + "additionalProperties": false + }, + "whitelist": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "configMapName": { + "type": "string" + }, + "filePath": { + "type": "string" + }, + "user_list_inline": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "subPath": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "applications": { + "type": "object", + "properties": { + "fred-agents": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "applicationName": { + "type": "string" + }, + "configurationFileName": { + "type": "string" + }, + "deployment": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "replicaCount": { + "type": "integer" + }, + "statefulset": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "job": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "migration": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "scaleDown": { + "type": "boolean" + }, + "backoffLimit": { + "type": "integer" + }, + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "object" + } + }, + "additionalProperties": false + }, + "rollingUpdate": { + "type": "object", + "properties": { + "maxSurge": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "maxUnavailable": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": false + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "pullPolicy": { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "additionalProperties": false + }, + "command": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "env": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": true + } + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "containerPort": { + "type": "integer" + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "service": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": false + }, + "metricsService": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "interval": { + "type": "string" + }, + "scrapeTimeout": { + "type": "string" + }, + "path": { + "type": "string" + }, + "scheme": { + "type": "string" + }, + "honorLabels": { + "type": "boolean" + }, + "relabelings": { + "type": "array", + "items": {} + }, + "metricRelabelings": { + "type": "array", + "items": {} + }, + "namespaceSelector": { + "type": "object" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "ingress": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "className": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + }, + "service": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "tls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "secretName": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + }, + "volumeMounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "subPath": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + }, + "additionalProperties": true + } + }, + "volumes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "probes": { + "type": "object", + "properties": { + "lifecycle": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "securityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + }, + "add": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "runAsUser": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "rbac": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "permissions": { + "type": "object", + "properties": { + "namespaced": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + }, + "cluster": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "kubeconfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration_type": { + "type": "object", + "properties": { + "backend": { + "type": "boolean" + }, + "frontend": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration": { + "description": "Complete structured configuration for a Fred agent pod.\n\nMirrors agentic-backend's `Configuration` model, scoped to what an agent\npod actually needs. All field types are reused from fred-core and fred-sdk\n\u2014 no new types invented here.\n\nHow to use it:\n- write a `config/configuration.yaml` alongside `config/models_catalog.yaml`\n and `config/mcp_catalog.yaml`\n- call `load_agent_pod_config()` at startup\n- pass the result to `create_agent_app(config=...)`\n\nThe `security` field is a `SecurityConfiguration` from fred-core, the same\ntype used in agentic-backend. When `security.user.enabled` is True,\n`create_agent_app` enforces Keycloak JWT validation on every endpoint.", + "properties": { + "app": { + "description": "Basic HTTP server and local observability settings for an agent pod.\n\nWhy this exists:\n- every pod needs the same HTTP binding knobs plus the small Prometheus/KPI\n settings already used by the other Fred backends\n- keeping these fields in `app` preserves the familiar startup contract for\n local benches and scrape-based debugging\n\nHow to use it:\n- keep the defaults for simple local development\n- set `metrics_port` / `metrics_address` when `observability.metrics` is\n `prometheus`\n\nExample:\n- `PodAppConfig(base_url=\"/pod/v1\", port=8000, metrics_port=9115)`", + "properties": { + "name": { + "default": "Fred Agent Pod", + "title": "Name", + "type": "string" + }, + "base_url": { + "default": "/api/v1", + "title": "Base Url", + "type": "string" + }, + "host": { + "default": "127.0.0.1", + "title": "Host", + "type": "string" + }, + "port": { + "default": 8000, + "title": "Port", + "type": "integer" + }, + "log_level": { + "default": "info", + "title": "Log Level", + "type": "string" + }, + "limit_concurrency": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional maximum number of concurrent HTTP or WebSocket connections accepted by Uvicorn. Leave unset to disable the limit.", + "title": "Limit Concurrency" + }, + "gcu_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Gcu Version" + }, + "metrics_address": { + "default": "127.0.0.1", + "title": "Metrics Address", + "type": "string" + }, + "metrics_port": { + "default": 9000, + "title": "Metrics Port", + "type": "integer" + }, + "kpi_process_metrics_interval_sec": { + "default": 0, + "description": "Emit process and SQL pool KPIs every N seconds. Set 0 to disable the background emitters.", + "title": "Kpi Process Metrics Interval Sec", + "type": "integer" + }, + "kpi_log_summary_interval_sec": { + "default": 0.0, + "description": "Emit periodic KPI summary logs every N seconds for local benches. Set 0 to disable.", + "title": "Kpi Log Summary Interval Sec", + "type": "number" + }, + "kpi_log_summary_top_n": { + "default": 0, + "description": "Top-N KPI summary rows to log. 0 means all / disabled.", + "title": "Kpi Log Summary Top N", + "type": "integer" + }, + "openai_compat": { + "default": true, + "title": "Openai Compat", + "type": "boolean" + } + }, + "title": "PodAppConfig", + "type": "object", + "additionalProperties": false + }, + "security": { + "properties": { + "m2m": { + "description": "Configuration for machine-to-machine authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + }, + "audience": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Audience" + }, + "secret_env_var": { + "default": "M2M_CLIENT_SECRET", + "title": "Secret Env Var", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "M2MSecurity", + "type": "object", + "additionalProperties": false + }, + "user": { + "description": "Configuration for user authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "UserSecurity", + "type": "object", + "additionalProperties": false + }, + "authorized_origins": { + "default": [], + "items": { + "format": "uri", + "minLength": 1, + "type": "string" + }, + "title": "Authorized Origins", + "type": "array" + }, + "rebac": { + "anyOf": [ + { + "discriminator": { + "mapping": { + "openfga": "#/$defs/OpenFgaRebacConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "description": "Configuration for an OpenFGA-backed relationship engine.", + "properties": { + "enabled": { + "default": true, + "description": "To disable ReBAC checks (do not disable in production). If OIDC (UserSecurity and M2MSecurity) ReBAC check will be disabled even if this is true.", + "title": "Enabled", + "type": "boolean" + }, + "type": { + "const": "openfga", + "default": "openfga", + "title": "Type", + "type": "string" + }, + "api_url": { + "description": "Base URL for the OpenFGA HTTP API (e.g. https://fga.example.com)", + "format": "uri", + "minLength": 1, + "title": "Api Url", + "type": "string" + }, + "store_name": { + "default": "fred", + "description": "Name of the OpenFGA store to use", + "title": "Store Name", + "type": "string" + }, + "authorization_model_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional authorization model ID to use for read operations. Will be overridden if sync_schema_on_init is True.", + "title": "Authorization Model Id" + }, + "create_store_if_needed": { + "default": true, + "description": "Create the OpenFGA store if it does not already exist", + "title": "Create Store If Needed", + "type": "boolean" + }, + "sync_schema_on_init": { + "default": true, + "description": "Synchronize the authorization model when creating the engine", + "title": "Sync Schema On Init", + "type": "boolean" + }, + "token_env_var": { + "default": "OPENFGA_API_TOKEN", + "description": "Environment variable that stores the OpenFGA API token", + "title": "Token Env Var", + "type": "string" + }, + "timeout_millisec": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional timeout in milliseconds for OpenFGA API requests", + "title": "Timeout Millisec" + }, + "headers": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Static HTTP headers to send with each OpenFGA API request", + "title": "Headers" + } + }, + "required": [ + "api_url" + ], + "title": "OpenFgaRebacConfig", + "type": "object", + "additionalProperties": false + } + ] + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rebac" + } + }, + "required": [ + "m2m", + "user" + ], + "title": "SecurityConfiguration", + "type": "object", + "additionalProperties": false + }, + "ai": { + "description": "AI model and knowledge-flow settings for an agent pod.\n\nWhy this section exists separately from AgentAppSettings:\n- pods only need the outbound Knowledge Flow base URL plus runtime HTTP\n timeout tuning shared by KF and MCP adapters\n- gateway-only concerns such as attachment/session limits should not leak\n into the pod config contract\n\nExample:\n- `PodAIConfig(knowledge_flow_url=\"http://localhost:8111/knowledge-flow/v1\", timeout=RuntimeTimeouts(connect=20, read=60))`", + "properties": { + "knowledge_flow_url": { + "default": "http://localhost:8111/knowledge-flow/v1", + "title": "Knowledge Flow Url", + "type": "string" + }, + "timeout": { + "description": "Minimal timeout settings for outbound runtime HTTP clients.\n\nWhy this exists:\n- KF/MCP clients need consistent timeout settings across runtimes\n\nHow to use it:\n- construct with explicit connect/read values\n- call `as_httpx_timeout_config()` to feed httpx", + "properties": { + "connect": { + "default": 5.0, + "title": "Connect", + "type": "number" + }, + "read": { + "default": 30.0, + "title": "Read", + "type": "number" + }, + "write": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Write" + }, + "pool": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Pool" + } + }, + "title": "RuntimeTimeouts", + "type": "object", + "additionalProperties": false + } + }, + "title": "PodAIConfig", + "type": "object", + "additionalProperties": false + }, + "observability": { + "description": "Observability provider selection for a Fred agent pod.\n\nNon-secret settings (backend choice, endpoints) live in configuration.yaml.\nCredentials (API keys, tokens) stay in the .env file.\n\nExample:\n observability:\n tracer: logging # null | logging | langfuse\n metrics: logging # null | logging | prometheus\n langfuse:\n host: \"http://localhost:3001\"\n # LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY in .env", + "properties": { + "tracer": { + "description": "Distributed tracing backend for the agent pod.\n\n- null \u2014 no tracing, all spans are dropped\n- logging \u2014 each span is emitted as a structured log entry (default)\n- langfuse \u2014 spans are sent to a Langfuse server;\n credentials (LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY) must be\n set in the .env file; host is configured in the langfuse section", + "enum": [ + "null", + "logging", + "langfuse" + ], + "title": "TracerBackend", + "type": "string" + }, + "metrics": { + "description": "Metrics emission backend for the agent pod.\n\n- null \u2014 no metrics, all timer events are dropped\n- logging \u2014 each timer is emitted as a structured log entry (default)\n- prometheus \u2014 KPI/process metrics are exported in Prometheus format on the\n dedicated metrics port configured under `app`", + "enum": [ + "null", + "logging", + "prometheus" + ], + "title": "MetricsBackend", + "type": "string" + }, + "langfuse": { + "description": "Langfuse connection settings.\n\nOnly non-secret settings live here.\nCredentials go in the .env file as LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY.", + "properties": { + "host": { + "default": "http://localhost:3001", + "title": "Host", + "type": "string" + } + }, + "title": "LangfuseObservabilityConfig", + "type": "object", + "additionalProperties": false + } + }, + "title": "PodObservabilityConfig", + "type": "object", + "additionalProperties": false + }, + "storage": { + "description": "Persistence backend settings for an agent pod.\n\nAll conversation state (sessions, multi-turn history, checkpoints) is\nmanaged exclusively by the LangGraph SQL checkpointer, which uses the\n`postgres` connection. There are no separate session or history tables.\n\nFields:\n- `postgres`: SQL engine used by the LangGraph checkpointer (SQLite in\n local dev via sqlite_path, PostgreSQL in production via host/port/database)\n- `opensearch`: optional, for log forwarding in production\n- `log_store`: optional, for structured log persistence", + "properties": { + "postgres": { + "properties": { + "type": { + "const": "postgres", + "default": "postgres", + "title": "Type", + "type": "string" + }, + "host": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "PostgreSQL host", + "title": "Host" + }, + "port": { + "default": 5432, + "title": "Port", + "type": "integer" + }, + "sqlite_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Path to the SQLite database file (for local dev/testing).", + "title": "Sqlite Path" + }, + "database": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Database" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Username" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Password" + }, + "echo": { + "default": false, + "description": "SQLAlchemy echo flag.", + "title": "Echo", + "type": "boolean" + }, + "pool_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional pool size for the engine.", + "title": "Pool Size" + }, + "max_overflow": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional max_overflow for SQLAlchemy pool (defaults to SQLAlchemy's 10 if unset).", + "title": "Max Overflow" + }, + "pool_timeout": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Seconds to wait for a connection from the pool before timing out.", + "title": "Pool Timeout" + }, + "pool_recycle": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Recycle connections after this many seconds (prevents stale TCP / server timeouts).", + "title": "Pool Recycle" + }, + "pool_pre_ping": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Enable SQLAlchemy pool_pre_ping to evict stale connections.", + "title": "Pool Pre Ping" + }, + "connect_args": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional connect_args passed to SQLAlchemy.", + "title": "Connect Args" + } + }, + "title": "PostgresStoreConfig", + "type": "object", + "additionalProperties": false + }, + "opensearch": { + "anyOf": [ + { + "properties": { + "host": { + "description": "OpenSearch host URL", + "title": "Host", + "type": "string" + }, + "username": { + "description": "Username from env", + "title": "Username", + "type": "string" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Password from env", + "title": "Password" + }, + "secure": { + "default": false, + "description": "Use TLS (https)", + "title": "Secure", + "type": "boolean" + }, + "verify_certs": { + "default": false, + "description": "Verify TLS certs", + "title": "Verify Certs", + "type": "boolean" + } + }, + "required": [ + "host", + "username" + ], + "title": "OpenSearchStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null + }, + "log_store": { + "anyOf": [ + { + "discriminator": { + "mapping": { + "in_memory": "#/$defs/InMemoryLogStorageConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "stdout": "#/$defs/StdoutLogStorageConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "in_memory", + "title": "Type", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "InMemoryLogStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "stdout", + "title": "Type", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "StdoutLogStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + } + ] + }, + { + "type": "null" + } + ], + "default": null, + "title": "Log Store" + } + }, + "title": "PodStorageConfig", + "type": "object", + "additionalProperties": false + }, + "scheduler": { + "description": "Temporal scheduler settings for an agent pod.\n\nDisabled by default \u2014 only needed for Story B (deep/durable agents).\nReuses TemporalSchedulerConfig from fred-core.", + "properties": { + "enabled": { + "default": false, + "title": "Enabled", + "type": "boolean" + }, + "backend": { + "description": "Allowed scheduler backend values across Fred backends.\n\nWhy this exists:\n- Avoid raw string literals (`\"temporal\"`, `\"memory\"`) spread in business code.\n- Keep one typed source of truth used by configuration parsing and runtime checks.\n\nHow to use:\n```python\nfrom fred_core.scheduler import SchedulerBackend\n\nif backend == SchedulerBackend.MEMORY:\n ...\n```", + "enum": [ + "temporal", + "memory" + ], + "title": "SchedulerBackend", + "type": "string" + }, + "temporal": { + "properties": { + "host": { + "default": "localhost:7233", + "title": "Host", + "type": "string" + }, + "namespace": { + "default": "default", + "title": "Namespace", + "type": "string" + }, + "task_queue": { + "default": "default", + "title": "Task Queue", + "type": "string" + }, + "workflow_id_prefix": { + "default": "task", + "title": "Workflow Id Prefix", + "type": "string" + }, + "connect_timeout_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 5, + "title": "Connect Timeout Seconds" + }, + "ingestion_workflow_parallelism": { + "default": 3, + "description": "Max number of files launched in parallel per parent ingestion workflow.", + "minimum": 1, + "title": "Ingestion Workflow Parallelism", + "type": "integer" + }, + "ingestion_max_concurrent_workflow_tasks": { + "default": 3, + "description": "Max concurrent Temporal workflow tasks processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Workflow Tasks", + "type": "integer" + }, + "ingestion_max_concurrent_activities": { + "default": 3, + "description": "Max concurrent Temporal activities processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Activities", + "type": "integer" + } + }, + "title": "TemporalSchedulerConfig", + "type": "object", + "additionalProperties": false + } + }, + "title": "PodSchedulerConfig", + "type": "object", + "additionalProperties": false + }, + "platform": { + "description": "Small set of Fred platform service URLs needed by the pod runtime.\n\nWhy this exists:\n- agent pods stay execution-focused, but some execution paths still need a\n central Fred service such as control-plane for managed agent-instance\n resolution\n\nHow to use it:\n- set `control_plane_url` when the pod should accept `agent_instance_id`\n execution requests\n\nExample:\n- `PodPlatformConfig(control_plane_url=\"http://localhost:8222/control-plane/v1\")`", + "properties": { + "control_plane_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Control Plane Url" + } + }, + "title": "PodPlatformConfig", + "type": "object", + "additionalProperties": false + } + }, + "required": [ + "security" + ], + "title": "AgentPodConfig", + "type": "object", + "additionalProperties": false + }, + "dotenv": { + "type": "object", + "properties": {}, + "additionalProperties": true + }, + "models_catalog": { + "type": "object", + "properties": {}, + "additionalProperties": true + }, + "mcp_catalog": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "frontend": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "applicationName": { + "type": "string" + }, + "configurationFileName": { + "type": "string" + }, + "deployment": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "replicaCount": { + "type": "integer" + }, + "statefulset": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "job": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "migration": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "scaleDown": { + "type": "boolean" + }, + "backoffLimit": { + "type": "integer" + }, + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "object" + } + }, + "additionalProperties": false + }, + "rollingUpdate": { + "type": "object", + "properties": { + "maxSurge": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "maxUnavailable": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": false + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "pullPolicy": { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "additionalProperties": false + }, + "command": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "env": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": true + } + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "containerPort": { + "type": "integer" + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "service": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": false + }, + "metricsService": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "interval": { + "type": "string" + }, + "scrapeTimeout": { + "type": "string" + }, + "path": { + "type": "string" + }, + "scheme": { + "type": "string" + }, + "honorLabels": { + "type": "boolean" + }, + "relabelings": { + "type": "array", + "items": {} + }, + "metricRelabelings": { + "type": "array", + "items": {} + }, + "namespaceSelector": { + "type": "object" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "ingress": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "className": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + }, + "service": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "tls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "secretName": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + }, + "volumeMounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "subPath": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + }, + "additionalProperties": true + } + }, + "volumes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "probes": { + "type": "object", + "properties": { + "lifecycle": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "securityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + }, + "add": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "runAsUser": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "rbac": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "permissions": { + "type": "object", + "properties": { + "namespaced": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + }, + "cluster": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "kubeconfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration_type": { + "type": "object", + "properties": { + "backend": { + "type": "boolean" + }, + "frontend": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration": { + "type": "object", + "properties": { + "config_json": { + "type": "object", + "properties": { + "frontend_basename": { + "type": "string" + }, + "user_auth": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "realm_url": { + "type": "string" + }, + "client_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "knowledge-flow-backend": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "applicationName": { + "type": "string" + }, + "configurationFileName": { + "type": "string" + }, + "deployment": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "replicaCount": { + "type": "integer" + }, + "statefulset": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "job": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "migration": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "scaleDown": { + "type": "boolean" + }, + "backoffLimit": { + "type": "integer" + }, + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "object" + } + }, + "additionalProperties": false + }, + "rollingUpdate": { + "type": "object", + "properties": { + "maxSurge": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "maxUnavailable": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": false + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "pullPolicy": { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "additionalProperties": false + }, + "command": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "env": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": true + } + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "containerPort": { + "type": "integer" + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "service": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": false + }, + "metricsService": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "interval": { + "type": "string" + }, + "scrapeTimeout": { + "type": "string" + }, + "path": { + "type": "string" + }, + "scheme": { + "type": "string" + }, + "honorLabels": { + "type": "boolean" + }, + "relabelings": { + "type": "array", + "items": {} + }, + "metricRelabelings": { + "type": "array", + "items": {} + }, + "namespaceSelector": { + "type": "object" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "ingress": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "className": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + }, + "service": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "tls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "secretName": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + }, + "volumeMounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "subPath": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + }, + "additionalProperties": true + } + }, + "volumes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "probes": { + "type": "object", + "properties": { + "lifecycle": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "securityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + }, + "add": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "runAsUser": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "rbac": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "permissions": { + "type": "object", + "properties": { + "namespaced": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + }, + "cluster": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "kubeconfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration_type": { + "type": "object", + "properties": { + "backend": { + "type": "boolean" + }, + "frontend": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration": { + "properties": { + "app": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "Knowledge Flow Backend", + "title": "Name" + }, + "base_url": { + "default": "/knowledge-flow/v1", + "title": "Base Url", + "type": "string" + }, + "address": { + "default": "127.0.0.1", + "title": "Address", + "type": "string" + }, + "port": { + "default": 8000, + "title": "Port", + "type": "integer" + }, + "log_level": { + "default": "info", + "title": "Log Level", + "type": "string" + }, + "reload": { + "default": false, + "title": "Reload", + "type": "boolean" + }, + "reload_dir": { + "default": ".", + "title": "Reload Dir", + "type": "string" + }, + "metrics_enabled": { + "default": true, + "title": "Metrics Enabled", + "type": "boolean" + }, + "metrics_address": { + "default": "127.0.0.1", + "title": "Metrics Address", + "type": "string" + }, + "metrics_port": { + "default": 9111, + "title": "Metrics Port", + "type": "integer" + }, + "kpi_process_metrics_interval_sec": { + "default": 10, + "description": "Interval in seconds for processing and logging KPI metrics.", + "title": "Kpi Process Metrics Interval Sec", + "type": "integer" + }, + "kpi_log_summary_interval_sec": { + "default": 0.0, + "description": "Emit KPI summary logs every N seconds (bench/debug). Set 0 to disable.", + "title": "Kpi Log Summary Interval Sec", + "type": "number" + }, + "kpi_log_summary_top_n": { + "default": 0, + "description": "Top-N metrics to show in KPI summary logs. 0 means all / disabled.", + "title": "Kpi Log Summary Top N", + "type": "integer" + }, + "gcu_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Gcu Version" + }, + "default_team_max_resources_storage_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Default storage limit in bytes for a team when not explicitly set.", + "title": "Default Team Max Resources Storage Size" + }, + "personal_max_resources_storage_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Maximum resources storage size in bytes for a personal space", + "title": "Personal Max Resources Storage Size" + } + }, + "title": "AppConfig", + "type": "object", + "additionalProperties": false + }, + "integrations": { + "anyOf": [ + { + "description": "Optional upstream service integrations consumed by Knowledge Flow.", + "properties": { + "prometheus": { + "anyOf": [ + { + "properties": { + "base_url": { + "description": "Base URL of a Prometheus-compatible HTTP API.", + "title": "Base Url", + "type": "string" + }, + "verify_ssl": { + "default": true, + "description": "Verify upstream TLS certificates when querying Prometheus.", + "title": "Verify Ssl", + "type": "boolean" + }, + "timeout_seconds": { + "default": 15.0, + "description": "HTTP timeout applied to Prometheus API calls.", + "exclusiveMinimum": 0, + "title": "Timeout Seconds", + "type": "number" + }, + "bearer_token": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional bearer token loaded from PROMETHEUS_BEARER_TOKEN.", + "title": "Bearer Token" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "admin", + "description": "Basic-auth username configured directly in prometheus.username. Defaults to 'admin'.", + "title": "Username" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional basic-auth password loaded from PROMETHEUS_PASSWORD.", + "title": "Password" + } + }, + "required": [ + "base_url" + ], + "title": "PrometheusConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional Prometheus API configuration for cluster-wide metrics queries." + } + }, + "title": "IntegrationsConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional third-party service integrations used by the backend." + }, + "chat_model": { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + "embedding_model": { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + "vision_model": { + "anyOf": [ + { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null + }, + "ocr_model": { + "anyOf": [ + { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional remote OCR model configuration. When set, PDF OCR can be delegated to an external API instead of local Docling OCR." + }, + "crossencoder_model": { + "anyOf": [ + { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null + }, + "security": { + "properties": { + "m2m": { + "description": "Configuration for machine-to-machine authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + }, + "audience": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Audience" + }, + "secret_env_var": { + "default": "M2M_CLIENT_SECRET", + "title": "Secret Env Var", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "M2MSecurity", + "type": "object", + "additionalProperties": false + }, + "user": { + "description": "Configuration for user authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "UserSecurity", + "type": "object", + "additionalProperties": false + }, + "authorized_origins": { + "default": [], + "items": { + "format": "uri", + "minLength": 1, + "type": "string" + }, + "title": "Authorized Origins", + "type": "array" + }, + "rebac": { + "anyOf": [ + { + "discriminator": { + "mapping": { + "openfga": "#/$defs/OpenFgaRebacConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "description": "Configuration for an OpenFGA-backed relationship engine.", + "properties": { + "enabled": { + "default": true, + "description": "To disable ReBAC checks (do not disable in production). If OIDC (UserSecurity and M2MSecurity) ReBAC check will be disabled even if this is true.", + "title": "Enabled", + "type": "boolean" + }, + "type": { + "const": "openfga", + "default": "openfga", + "title": "Type", + "type": "string" + }, + "api_url": { + "description": "Base URL for the OpenFGA HTTP API (e.g. https://fga.example.com)", + "format": "uri", + "minLength": 1, + "title": "Api Url", + "type": "string" + }, + "store_name": { + "default": "fred", + "description": "Name of the OpenFGA store to use", + "title": "Store Name", + "type": "string" + }, + "authorization_model_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional authorization model ID to use for read operations. Will be overridden if sync_schema_on_init is True.", + "title": "Authorization Model Id" + }, + "create_store_if_needed": { + "default": true, + "description": "Create the OpenFGA store if it does not already exist", + "title": "Create Store If Needed", + "type": "boolean" + }, + "sync_schema_on_init": { + "default": true, + "description": "Synchronize the authorization model when creating the engine", + "title": "Sync Schema On Init", + "type": "boolean" + }, + "token_env_var": { + "default": "OPENFGA_API_TOKEN", + "description": "Environment variable that stores the OpenFGA API token", + "title": "Token Env Var", + "type": "string" + }, + "timeout_millisec": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional timeout in milliseconds for OpenFGA API requests", + "title": "Timeout Millisec" + }, + "headers": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Static HTTP headers to send with each OpenFGA API request", + "title": "Headers" + } + }, + "required": [ + "api_url" + ], + "title": "OpenFgaRebacConfig", + "type": "object", + "additionalProperties": false + } + ] + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rebac" + } + }, + "required": [ + "m2m", + "user" + ], + "title": "SecurityConfiguration", + "type": "object", + "additionalProperties": false + }, + "attachment_processors": { + "anyOf": [ + { + "items": { + "description": "Configuration structure for a file processor.\nAttributes:\n suffix (str): The file extension this processor handles (e.g., '.pdf').\n class_path (str): Dotted import path of the processor class.\n description (str): Human readable explanation of what the processor does.", + "properties": { + "suffix": { + "description": "The file extension this processor handles (e.g., '.pdf')", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProcessorConfig", + "type": "object", + "additionalProperties": false + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional fast-text processors for attachments. Uses the same ProcessorConfig structure, but classes must subclass BaseFastTextProcessor. If omitted, the default fast processor is used.", + "title": "Attachment Processors" + }, + "document_guardrail": { + "anyOf": [ + { + "properties": { + "enabled": { + "default": false, + "description": "Enable ingestion-time document marking guardrails.", + "title": "Enabled", + "type": "boolean" + }, + "source_tags": { + "description": "Optional source tags this guardrail applies to. Empty means all sources.", + "items": { + "type": "string" + }, + "title": "Source Tags", + "type": "array" + }, + "allowed_labels": { + "description": "Optional allow-list of labels accepted by the guardrail. Empty means detection-only.", + "items": { + "type": "string" + }, + "title": "Allowed Labels", + "type": "array" + }, + "on_no_label": { + "default": "allow", + "description": "Behavior when no explicit document marking is detected.", + "enum": [ + "allow", + "warn", + "reject" + ], + "title": "On No Label", + "type": "string" + }, + "patterns": { + "description": "Regex patterns used to recognize explicit document markings.", + "items": { + "properties": { + "label": { + "description": "Normalized label returned when the regex matches.", + "minLength": 1, + "title": "Label", + "type": "string" + }, + "pattern": { + "description": "Regex used to detect the marking in extracted guardrail text.", + "minLength": 1, + "title": "Pattern", + "type": "string" + } + }, + "required": [ + "label", + "pattern" + ], + "title": "DocumentMarkingPatternConfig", + "type": "object", + "additionalProperties": false + }, + "title": "Patterns", + "type": "array" + } + }, + "title": "DocumentGuardrailConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional ingestion-time guardrail for explicit document markings." + }, + "output_processors": { + "anyOf": [ + { + "items": { + "description": "Configuration structure for a file processor.\nAttributes:\n suffix (str): The file extension this processor handles (e.g., '.pdf').\n class_path (str): Dotted import path of the processor class.\n description (str): Human readable explanation of what the processor does.", + "properties": { + "suffix": { + "description": "The file extension this processor handles (e.g., '.pdf')", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProcessorConfig", + "type": "object", + "additionalProperties": false + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Output Processors" + }, + "library_output_processors": { + "anyOf": [ + { + "items": { + "description": "Configuration structure for a library-level output processor.\n\nAttributes:\n class_path (str): Dotted import path of the processor class.\n description (str): Human readable explanation of what the processor does.", + "properties": { + "class_path": { + "description": "Dotted import path of the library output processor class", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the library output processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "class_path" + ], + "title": "LibraryProcessorConfig", + "type": "object", + "additionalProperties": false + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Library Output Processors" + }, + "content_storage": { + "description": "Content Storage configuration", + "discriminator": { + "mapping": { + "local": "#/$defs/LocalContentStorageConfig", + "minio": "#/$defs/MinioStorageConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "local", + "title": "Type", + "type": "string" + }, + "root_path": { + "default": "~/.fred/knowledge-flow/content-store", + "description": "Local storage directory", + "title": "Root Path", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "LocalContentStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "minio", + "title": "Type", + "type": "string" + }, + "endpoint": { + "default": "localhost:9000", + "description": "MinIO API URL", + "title": "Endpoint", + "type": "string" + }, + "access_key": { + "description": "MinIO access key (from MINIO_ACCESS_KEY env)", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "default": null, + "description": "MinIO secret key (from MINIO_SECRET_KEY env)", + "title": "Secret Key", + "type": "string" + }, + "bucket_name": { + "default": "app-bucket", + "description": "Content store bucket name", + "title": "Bucket Name", + "type": "string" + }, + "secure": { + "default": false, + "description": "Use TLS (https)", + "title": "Secure", + "type": "boolean" + }, + "public_endpoint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Public MinIO endpoint for browser-facing presigned URLs (e.g. 'https://my.minio.ingress'). If not set, uses endpoint.", + "title": "Public Endpoint" + }, + "public_secure": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Use TLS for public endpoint. If not set, inferred from public_endpoint scheme.", + "title": "Public Secure" + } + }, + "required": [ + "type", + "access_key" + ], + "title": "MinioStorageConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Content Storage" + }, + "scheduler": { + "properties": { + "enabled": { + "default": false, + "title": "Enabled", + "type": "boolean" + }, + "backend": { + "description": "Allowed scheduler backend values across Fred backends.\n\nWhy this exists:\n- Avoid raw string literals (`\"temporal\"`, `\"memory\"`) spread in business code.\n- Keep one typed source of truth used by configuration parsing and runtime checks.\n\nHow to use:\n```python\nfrom fred_core.scheduler import SchedulerBackend\n\nif backend == SchedulerBackend.MEMORY:\n ...\n```", + "enum": [ + "temporal", + "memory" + ], + "title": "SchedulerBackend", + "type": "string" + }, + "temporal": { + "properties": { + "host": { + "default": "localhost:7233", + "title": "Host", + "type": "string" + }, + "namespace": { + "default": "default", + "title": "Namespace", + "type": "string" + }, + "task_queue": { + "default": "default", + "title": "Task Queue", + "type": "string" + }, + "workflow_id_prefix": { + "default": "task", + "title": "Workflow Id Prefix", + "type": "string" + }, + "connect_timeout_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 5, + "title": "Connect Timeout Seconds" + }, + "ingestion_workflow_parallelism": { + "default": 3, + "description": "Max number of files launched in parallel per parent ingestion workflow.", + "minimum": 1, + "title": "Ingestion Workflow Parallelism", + "type": "integer" + }, + "ingestion_max_concurrent_workflow_tasks": { + "default": 3, + "description": "Max concurrent Temporal workflow tasks processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Workflow Tasks", + "type": "integer" + }, + "ingestion_max_concurrent_activities": { + "default": 3, + "description": "Max concurrent Temporal activities processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Activities", + "type": "integer" + } + }, + "title": "TemporalSchedulerConfig", + "type": "object", + "additionalProperties": false + } + }, + "required": [ + "temporal" + ], + "title": "SchedulerConfig", + "type": "object", + "additionalProperties": false + }, + "processing": { + "additionalProperties": false, + "properties": { + "default_profile": { + "enum": [ + "fast", + "medium", + "rich" + ], + "title": "IngestionProcessingProfile", + "type": "string" + }, + "profiles": { + "additionalProperties": false, + "properties": { + "fast": { + "additionalProperties": false, + "properties": { + "use_gpu": { + "default": true, + "description": "Enable/disable GPU usage for this profile (if supported by the selected processors).", + "title": "Use Gpu", + "type": "boolean" + }, + "process_images": { + "default": false, + "description": "Enable/disable semantic image description in markdown for this profile.", + "title": "Process Images", + "type": "boolean" + }, + "generate_summary": { + "default": false, + "description": "Enable/disable human-centric abstract and keyword generation for this profile.", + "title": "Generate Summary", + "type": "boolean" + }, + "input_activity_timeout": { + "default": "1h", + "description": "Temporal start-to-close timeout for input processing activities (e.g., '1h', '45m').", + "title": "Input Activity Timeout", + "type": "string" + }, + "activity_heartbeat_timeout": { + "default": "5m", + "description": "Temporal heartbeat timeout for input processing activities (e.g., '5m', '10m'). Must be larger than the worker's heartbeat interval (~20s).", + "title": "Activity Heartbeat Timeout", + "type": "string" + }, + "pdf": { + "additionalProperties": false, + "properties": { + "backend": { + "default": "docling_parse", + "description": "PDF backend for Docling conversion.", + "enum": [ + "dlparse_v4", + "pypdfium2", + "docling_parse" + ], + "title": "Backend", + "type": "string" + }, + "images_scale": { + "default": 2.0, + "description": "Docling PDF image scaling factor.", + "exclusiveMinimum": 0.0, + "title": "Images Scale", + "type": "number" + }, + "generate_picture_images": { + "default": false, + "description": "Generate extracted picture image assets during PDF conversion. Independent from profile.process_images (image description).", + "title": "Generate Picture Images", + "type": "boolean" + }, + "generate_page_images": { + "default": false, + "description": "Generate full-page images for PDFs.", + "title": "Generate Page Images", + "type": "boolean" + }, + "generate_table_images": { + "default": false, + "description": "Generate table images for PDFs.", + "title": "Generate Table Images", + "type": "boolean" + }, + "do_table_structure": { + "default": false, + "description": "Enable table structure extraction in the standard Docling PDF pipeline.", + "title": "Do Table Structure", + "type": "boolean" + }, + "do_ocr": { + "default": false, + "description": "Enable OCR in the standard Docling PDF pipeline.", + "title": "Do Ocr", + "type": "boolean" + }, + "ocr_backend": { + "anyOf": [ + { + "enum": [ + "onnxruntime", + "openvino", + "paddle", + "torch" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": "openvino", + "description": "Override RapidOCR inference backend when OCR is enabled.", + "title": "Ocr Backend" + }, + "force_full_page_ocr": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Override RapidOCR full-page OCR. Set to true to OCR every page even when backend text exists.", + "title": "Force Full Page Ocr" + }, + "ocr_batch_size": { + "default": 4, + "description": "OCR batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Ocr Batch Size", + "type": "integer" + }, + "layout_batch_size": { + "default": 4, + "description": "Layout batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Layout Batch Size", + "type": "integer" + }, + "table_batch_size": { + "default": 4, + "description": "Table-structure batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Table Batch Size", + "type": "integer" + }, + "batch_polling_interval_seconds": { + "default": 0.5, + "description": "Polling interval in seconds used by Docling's threaded StandardPdfPipeline to accumulate batches before processing.", + "exclusiveMinimum": 0.0, + "title": "Batch Polling Interval Seconds", + "type": "number" + }, + "queue_max_size": { + "default": 100, + "description": "Maximum inter-stage queue size used by Docling's threaded StandardPdfPipeline. Smaller queues reduce buffering and can lower memory usage.", + "minimum": 1, + "title": "Queue Max Size", + "type": "integer" + } + }, + "title": "PdfPipelineConfig", + "type": "object" + }, + "text_splitter": { + "additionalProperties": false, + "properties": { + "chunk_size": { + "default": 1500, + "description": "Maximum number of characters per chunk for text splitting.", + "minimum": 1, + "title": "Chunk Size", + "type": "integer" + }, + "chunk_overlap": { + "default": 150, + "description": "Number of overlapping characters between consecutive chunks.", + "minimum": 0, + "title": "Chunk Overlap", + "type": "integer" + }, + "preserve_tables": { + "default": true, + "description": "If true, keep annotated markdown tables intact (do not split by size).", + "title": "Preserve Tables", + "type": "boolean" + } + }, + "title": "TextSplitterConfig", + "type": "object" + }, + "input_processors": { + "description": "Input processors selected for this profile (suffix-specific).", + "items": { + "additionalProperties": false, + "properties": { + "suffix": { + "description": "The file suffix this processor handles (e.g., '.pdf').", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class.", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProfileInputProcessorConfig", + "type": "object" + }, + "title": "Input Processors", + "type": "array" + }, + "retry_initial_interval": { + "default": "30s", + "description": "Temporal retry delay before the first retry for this profile's ingestion activities.", + "title": "Retry Initial Interval", + "type": "string" + }, + "retry_backoff_coefficient": { + "default": 2.0, + "description": "Temporal retry backoff coefficient for this profile's ingestion activities.", + "minimum": 1.0, + "title": "Retry Backoff Coefficient", + "type": "number" + }, + "retry_maximum_interval": { + "default": "10m", + "description": "Maximum Temporal retry delay for this profile's ingestion activities.", + "title": "Retry Maximum Interval", + "type": "string" + }, + "retry_maximum_attempts": { + "default": 6, + "description": "Maximum Temporal activity attempts for this profile, including the first attempt.", + "minimum": 1, + "title": "Retry Maximum Attempts", + "type": "integer" + }, + "retry_non_retryable_error_types": { + "description": "Temporal application error types that should fail fast for this profile without retry.", + "items": { + "type": "string" + }, + "title": "Retry Non Retryable Error Types", + "type": "array" + } + }, + "title": "ProfileConfig", + "type": "object" + }, + "medium": { + "additionalProperties": false, + "properties": { + "use_gpu": { + "default": true, + "description": "Enable/disable GPU usage for this profile (if supported by the selected processors).", + "title": "Use Gpu", + "type": "boolean" + }, + "process_images": { + "default": false, + "description": "Enable/disable semantic image description in markdown for this profile.", + "title": "Process Images", + "type": "boolean" + }, + "generate_summary": { + "default": false, + "description": "Enable/disable human-centric abstract and keyword generation for this profile.", + "title": "Generate Summary", + "type": "boolean" + }, + "input_activity_timeout": { + "default": "1h", + "description": "Temporal start-to-close timeout for input processing activities (e.g., '1h', '45m').", + "title": "Input Activity Timeout", + "type": "string" + }, + "activity_heartbeat_timeout": { + "default": "5m", + "description": "Temporal heartbeat timeout for input processing activities (e.g., '5m', '10m'). Must be larger than the worker's heartbeat interval (~20s).", + "title": "Activity Heartbeat Timeout", + "type": "string" + }, + "pdf": { + "additionalProperties": false, + "properties": { + "backend": { + "default": "docling_parse", + "description": "PDF backend for Docling conversion.", + "enum": [ + "dlparse_v4", + "pypdfium2", + "docling_parse" + ], + "title": "Backend", + "type": "string" + }, + "images_scale": { + "default": 2.0, + "description": "Docling PDF image scaling factor.", + "exclusiveMinimum": 0.0, + "title": "Images Scale", + "type": "number" + }, + "generate_picture_images": { + "default": false, + "description": "Generate extracted picture image assets during PDF conversion. Independent from profile.process_images (image description).", + "title": "Generate Picture Images", + "type": "boolean" + }, + "generate_page_images": { + "default": false, + "description": "Generate full-page images for PDFs.", + "title": "Generate Page Images", + "type": "boolean" + }, + "generate_table_images": { + "default": false, + "description": "Generate table images for PDFs.", + "title": "Generate Table Images", + "type": "boolean" + }, + "do_table_structure": { + "default": false, + "description": "Enable table structure extraction in the standard Docling PDF pipeline.", + "title": "Do Table Structure", + "type": "boolean" + }, + "do_ocr": { + "default": false, + "description": "Enable OCR in the standard Docling PDF pipeline.", + "title": "Do Ocr", + "type": "boolean" + }, + "ocr_backend": { + "anyOf": [ + { + "enum": [ + "onnxruntime", + "openvino", + "paddle", + "torch" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": "openvino", + "description": "Override RapidOCR inference backend when OCR is enabled.", + "title": "Ocr Backend" + }, + "force_full_page_ocr": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Override RapidOCR full-page OCR. Set to true to OCR every page even when backend text exists.", + "title": "Force Full Page Ocr" + }, + "ocr_batch_size": { + "default": 4, + "description": "OCR batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Ocr Batch Size", + "type": "integer" + }, + "layout_batch_size": { + "default": 4, + "description": "Layout batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Layout Batch Size", + "type": "integer" + }, + "table_batch_size": { + "default": 4, + "description": "Table-structure batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Table Batch Size", + "type": "integer" + }, + "batch_polling_interval_seconds": { + "default": 0.5, + "description": "Polling interval in seconds used by Docling's threaded StandardPdfPipeline to accumulate batches before processing.", + "exclusiveMinimum": 0.0, + "title": "Batch Polling Interval Seconds", + "type": "number" + }, + "queue_max_size": { + "default": 100, + "description": "Maximum inter-stage queue size used by Docling's threaded StandardPdfPipeline. Smaller queues reduce buffering and can lower memory usage.", + "minimum": 1, + "title": "Queue Max Size", + "type": "integer" + } + }, + "title": "PdfPipelineConfig", + "type": "object" + }, + "text_splitter": { + "additionalProperties": false, + "properties": { + "chunk_size": { + "default": 1500, + "description": "Maximum number of characters per chunk for text splitting.", + "minimum": 1, + "title": "Chunk Size", + "type": "integer" + }, + "chunk_overlap": { + "default": 150, + "description": "Number of overlapping characters between consecutive chunks.", + "minimum": 0, + "title": "Chunk Overlap", + "type": "integer" + }, + "preserve_tables": { + "default": true, + "description": "If true, keep annotated markdown tables intact (do not split by size).", + "title": "Preserve Tables", + "type": "boolean" + } + }, + "title": "TextSplitterConfig", + "type": "object" + }, + "input_processors": { + "description": "Input processors selected for this profile (suffix-specific).", + "items": { + "additionalProperties": false, + "properties": { + "suffix": { + "description": "The file suffix this processor handles (e.g., '.pdf').", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class.", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProfileInputProcessorConfig", + "type": "object" + }, + "title": "Input Processors", + "type": "array" + }, + "retry_initial_interval": { + "default": "30s", + "description": "Temporal retry delay before the first retry for this profile's ingestion activities.", + "title": "Retry Initial Interval", + "type": "string" + }, + "retry_backoff_coefficient": { + "default": 2.0, + "description": "Temporal retry backoff coefficient for this profile's ingestion activities.", + "minimum": 1.0, + "title": "Retry Backoff Coefficient", + "type": "number" + }, + "retry_maximum_interval": { + "default": "10m", + "description": "Maximum Temporal retry delay for this profile's ingestion activities.", + "title": "Retry Maximum Interval", + "type": "string" + }, + "retry_maximum_attempts": { + "default": 6, + "description": "Maximum Temporal activity attempts for this profile, including the first attempt.", + "minimum": 1, + "title": "Retry Maximum Attempts", + "type": "integer" + }, + "retry_non_retryable_error_types": { + "description": "Temporal application error types that should fail fast for this profile without retry.", + "items": { + "type": "string" + }, + "title": "Retry Non Retryable Error Types", + "type": "array" + } + }, + "title": "ProfileConfig", + "type": "object" + }, + "rich": { + "additionalProperties": false, + "properties": { + "use_gpu": { + "default": true, + "description": "Enable/disable GPU usage for this profile (if supported by the selected processors).", + "title": "Use Gpu", + "type": "boolean" + }, + "process_images": { + "default": false, + "description": "Enable/disable semantic image description in markdown for this profile.", + "title": "Process Images", + "type": "boolean" + }, + "generate_summary": { + "default": false, + "description": "Enable/disable human-centric abstract and keyword generation for this profile.", + "title": "Generate Summary", + "type": "boolean" + }, + "input_activity_timeout": { + "default": "1h", + "description": "Temporal start-to-close timeout for input processing activities (e.g., '1h', '45m').", + "title": "Input Activity Timeout", + "type": "string" + }, + "activity_heartbeat_timeout": { + "default": "5m", + "description": "Temporal heartbeat timeout for input processing activities (e.g., '5m', '10m'). Must be larger than the worker's heartbeat interval (~20s).", + "title": "Activity Heartbeat Timeout", + "type": "string" + }, + "pdf": { + "additionalProperties": false, + "properties": { + "backend": { + "default": "docling_parse", + "description": "PDF backend for Docling conversion.", + "enum": [ + "dlparse_v4", + "pypdfium2", + "docling_parse" + ], + "title": "Backend", + "type": "string" + }, + "images_scale": { + "default": 2.0, + "description": "Docling PDF image scaling factor.", + "exclusiveMinimum": 0.0, + "title": "Images Scale", + "type": "number" + }, + "generate_picture_images": { + "default": false, + "description": "Generate extracted picture image assets during PDF conversion. Independent from profile.process_images (image description).", + "title": "Generate Picture Images", + "type": "boolean" + }, + "generate_page_images": { + "default": false, + "description": "Generate full-page images for PDFs.", + "title": "Generate Page Images", + "type": "boolean" + }, + "generate_table_images": { + "default": false, + "description": "Generate table images for PDFs.", + "title": "Generate Table Images", + "type": "boolean" + }, + "do_table_structure": { + "default": false, + "description": "Enable table structure extraction in the standard Docling PDF pipeline.", + "title": "Do Table Structure", + "type": "boolean" + }, + "do_ocr": { + "default": false, + "description": "Enable OCR in the standard Docling PDF pipeline.", + "title": "Do Ocr", + "type": "boolean" + }, + "ocr_backend": { + "anyOf": [ + { + "enum": [ + "onnxruntime", + "openvino", + "paddle", + "torch" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": "openvino", + "description": "Override RapidOCR inference backend when OCR is enabled.", + "title": "Ocr Backend" + }, + "force_full_page_ocr": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Override RapidOCR full-page OCR. Set to true to OCR every page even when backend text exists.", + "title": "Force Full Page Ocr" + }, + "ocr_batch_size": { + "default": 4, + "description": "OCR batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Ocr Batch Size", + "type": "integer" + }, + "layout_batch_size": { + "default": 4, + "description": "Layout batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Layout Batch Size", + "type": "integer" + }, + "table_batch_size": { + "default": 4, + "description": "Table-structure batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Table Batch Size", + "type": "integer" + }, + "batch_polling_interval_seconds": { + "default": 0.5, + "description": "Polling interval in seconds used by Docling's threaded StandardPdfPipeline to accumulate batches before processing.", + "exclusiveMinimum": 0.0, + "title": "Batch Polling Interval Seconds", + "type": "number" + }, + "queue_max_size": { + "default": 100, + "description": "Maximum inter-stage queue size used by Docling's threaded StandardPdfPipeline. Smaller queues reduce buffering and can lower memory usage.", + "minimum": 1, + "title": "Queue Max Size", + "type": "integer" + } + }, + "title": "PdfPipelineConfig", + "type": "object" + }, + "text_splitter": { + "additionalProperties": false, + "properties": { + "chunk_size": { + "default": 1500, + "description": "Maximum number of characters per chunk for text splitting.", + "minimum": 1, + "title": "Chunk Size", + "type": "integer" + }, + "chunk_overlap": { + "default": 150, + "description": "Number of overlapping characters between consecutive chunks.", + "minimum": 0, + "title": "Chunk Overlap", + "type": "integer" + }, + "preserve_tables": { + "default": true, + "description": "If true, keep annotated markdown tables intact (do not split by size).", + "title": "Preserve Tables", + "type": "boolean" + } + }, + "title": "TextSplitterConfig", + "type": "object" + }, + "input_processors": { + "description": "Input processors selected for this profile (suffix-specific).", + "items": { + "additionalProperties": false, + "properties": { + "suffix": { + "description": "The file suffix this processor handles (e.g., '.pdf').", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class.", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProfileInputProcessorConfig", + "type": "object" + }, + "title": "Input Processors", + "type": "array" + }, + "retry_initial_interval": { + "default": "30s", + "description": "Temporal retry delay before the first retry for this profile's ingestion activities.", + "title": "Retry Initial Interval", + "type": "string" + }, + "retry_backoff_coefficient": { + "default": 2.0, + "description": "Temporal retry backoff coefficient for this profile's ingestion activities.", + "minimum": 1.0, + "title": "Retry Backoff Coefficient", + "type": "number" + }, + "retry_maximum_interval": { + "default": "10m", + "description": "Maximum Temporal retry delay for this profile's ingestion activities.", + "title": "Retry Maximum Interval", + "type": "string" + }, + "retry_maximum_attempts": { + "default": 6, + "description": "Maximum Temporal activity attempts for this profile, including the first attempt.", + "minimum": 1, + "title": "Retry Maximum Attempts", + "type": "integer" + }, + "retry_non_retryable_error_types": { + "description": "Temporal application error types that should fail fast for this profile without retry.", + "items": { + "type": "string" + }, + "title": "Retry Non Retryable Error Types", + "type": "array" + } + }, + "title": "ProfileConfig", + "type": "object" + } + }, + "title": "ProfilesConfig", + "type": "object" + } + }, + "title": "ProcessingConfig", + "type": "object" + }, + "document_sources": { + "additionalProperties": { + "discriminator": { + "mapping": { + "pull": { + "discriminator": { + "mapping": { + "github": "#/$defs/GitPullSource", + "gitlab": "#/$defs/GitlabPullSource", + "local_path": "#/$defs/FileSystemPullSource", + "minio": "#/$defs/MinioPullSource", + "sphere": "#/$defs/SpherePullSource" + }, + "propertyName": "provider" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "local_path", + "title": "Provider", + "type": "string" + }, + "base_path": { + "title": "Base Path", + "type": "string" + } + }, + "required": [ + "provider", + "base_path" + ], + "title": "FileSystemPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "github", + "title": "Provider", + "type": "string" + }, + "repo": { + "description": "GitHub repository in the format 'owner/repo'", + "title": "Repo", + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "main", + "description": "Git branch to pull from", + "title": "Branch" + }, + "subdir": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Subdirectory to extract files from", + "title": "Subdir" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional GitHub username (for logs)", + "title": "Username" + }, + "token": { + "description": "GitHub token (from GITHUB_TOKEN env variable)", + "title": "Token", + "type": "string" + } + }, + "required": [ + "provider", + "repo", + "token" + ], + "title": "GitPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "sphere", + "title": "Provider", + "type": "string" + }, + "base_url": { + "description": "Base URL for the Sphere API", + "title": "Base Url", + "type": "string" + }, + "parent_node_id": { + "description": "ID of the parent folder or node to list/download", + "title": "Parent Node Id", + "type": "string" + }, + "username": { + "description": "Username for Sphere Basic Auth", + "title": "Username", + "type": "string" + }, + "password": { + "description": "Password (loaded from SPHERE_PASSWORD)", + "title": "Password", + "type": "string" + }, + "apikey": { + "description": "API key (loaded from SPHERE_API_KEY)", + "title": "Apikey", + "type": "string" + }, + "verify_ssl": { + "default": false, + "description": "Set to True to verify SSL certs", + "title": "Verify Ssl", + "type": "boolean" + } + }, + "required": [ + "provider", + "base_url", + "parent_node_id", + "username", + "password", + "apikey" + ], + "title": "SpherePullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "gitlab", + "title": "Provider", + "type": "string" + }, + "repo": { + "description": "GitLab repository in the format 'namespace/project'", + "title": "Repo", + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "main", + "description": "Branch to pull from", + "title": "Branch" + }, + "subdir": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Optional subdirectory to scan files from", + "title": "Subdir" + }, + "token": { + "description": "GitLab private token (from GITLAB_TOKEN env variable)", + "title": "Token", + "type": "string" + }, + "base_url": { + "default": "https://gitlab.com/api/v4", + "description": "GitLab API base URL", + "title": "Base Url", + "type": "string" + } + }, + "required": [ + "provider", + "repo", + "token" + ], + "title": "GitlabPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "minio", + "title": "Provider", + "type": "string" + }, + "endpoint_url": { + "description": "S3-compatible endpoint (e.g., https://s3.amazonaws.com)", + "title": "Endpoint Url", + "type": "string" + }, + "bucket_name": { + "description": "Name of the S3 bucket to scan", + "title": "Bucket Name", + "type": "string" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Optional prefix (folder path) to scan inside the bucket", + "title": "Prefix" + }, + "access_key": { + "description": "MinIO access key (from MINIO_ACCESS_KEY env variable)", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "default": null, + "description": "MinIO secret key (from MINIO_SECRET_KEY env variable)", + "title": "Secret Key", + "type": "string" + }, + "region": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "us-east-1", + "description": "AWS region (used by some clients)", + "title": "Region" + }, + "secure": { + "default": true, + "description": "Use HTTPS (secure=True) or HTTP (secure=False)", + "title": "Secure", + "type": "boolean" + } + }, + "required": [ + "provider", + "endpoint_url", + "bucket_name", + "access_key" + ], + "title": "MinioPullSource", + "type": "object", + "additionalProperties": false + } + ] + }, + "push": "#/$defs/PushSourceConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "push", + "default": "push", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + } + }, + "title": "PushSourceConfig", + "type": "object", + "additionalProperties": false + }, + { + "discriminator": { + "mapping": { + "github": "#/$defs/GitPullSource", + "gitlab": "#/$defs/GitlabPullSource", + "local_path": "#/$defs/FileSystemPullSource", + "minio": "#/$defs/MinioPullSource", + "sphere": "#/$defs/SpherePullSource" + }, + "propertyName": "provider" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "local_path", + "title": "Provider", + "type": "string" + }, + "base_path": { + "title": "Base Path", + "type": "string" + } + }, + "required": [ + "provider", + "base_path" + ], + "title": "FileSystemPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "github", + "title": "Provider", + "type": "string" + }, + "repo": { + "description": "GitHub repository in the format 'owner/repo'", + "title": "Repo", + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "main", + "description": "Git branch to pull from", + "title": "Branch" + }, + "subdir": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Subdirectory to extract files from", + "title": "Subdir" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional GitHub username (for logs)", + "title": "Username" + }, + "token": { + "description": "GitHub token (from GITHUB_TOKEN env variable)", + "title": "Token", + "type": "string" + } + }, + "required": [ + "provider", + "repo", + "token" + ], + "title": "GitPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "sphere", + "title": "Provider", + "type": "string" + }, + "base_url": { + "description": "Base URL for the Sphere API", + "title": "Base Url", + "type": "string" + }, + "parent_node_id": { + "description": "ID of the parent folder or node to list/download", + "title": "Parent Node Id", + "type": "string" + }, + "username": { + "description": "Username for Sphere Basic Auth", + "title": "Username", + "type": "string" + }, + "password": { + "description": "Password (loaded from SPHERE_PASSWORD)", + "title": "Password", + "type": "string" + }, + "apikey": { + "description": "API key (loaded from SPHERE_API_KEY)", + "title": "Apikey", + "type": "string" + }, + "verify_ssl": { + "default": false, + "description": "Set to True to verify SSL certs", + "title": "Verify Ssl", + "type": "boolean" + } + }, + "required": [ + "provider", + "base_url", + "parent_node_id", + "username", + "password", + "apikey" + ], + "title": "SpherePullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "gitlab", + "title": "Provider", + "type": "string" + }, + "repo": { + "description": "GitLab repository in the format 'namespace/project'", + "title": "Repo", + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "main", + "description": "Branch to pull from", + "title": "Branch" + }, + "subdir": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Optional subdirectory to scan files from", + "title": "Subdir" + }, + "token": { + "description": "GitLab private token (from GITLAB_TOKEN env variable)", + "title": "Token", + "type": "string" + }, + "base_url": { + "default": "https://gitlab.com/api/v4", + "description": "GitLab API base URL", + "title": "Base Url", + "type": "string" + } + }, + "required": [ + "provider", + "repo", + "token" + ], + "title": "GitlabPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "minio", + "title": "Provider", + "type": "string" + }, + "endpoint_url": { + "description": "S3-compatible endpoint (e.g., https://s3.amazonaws.com)", + "title": "Endpoint Url", + "type": "string" + }, + "bucket_name": { + "description": "Name of the S3 bucket to scan", + "title": "Bucket Name", + "type": "string" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Optional prefix (folder path) to scan inside the bucket", + "title": "Prefix" + }, + "access_key": { + "description": "MinIO access key (from MINIO_ACCESS_KEY env variable)", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "default": null, + "description": "MinIO secret key (from MINIO_SECRET_KEY env variable)", + "title": "Secret Key", + "type": "string" + }, + "region": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "us-east-1", + "description": "AWS region (used by some clients)", + "title": "Region" + }, + "secure": { + "default": true, + "description": "Use HTTPS (secure=True) or HTTP (secure=False)", + "title": "Secure", + "type": "boolean" + } + }, + "required": [ + "provider", + "endpoint_url", + "bucket_name", + "access_key" + ], + "title": "MinioPullSource", + "type": "object", + "additionalProperties": false + } + ] + } + ] + }, + "description": "Mapping of source_tag identifiers to push/pull source configurations", + "title": "Document Sources", + "type": "object" + }, + "storage": { + "properties": { + "postgres": { + "properties": { + "type": { + "const": "postgres", + "default": "postgres", + "title": "Type", + "type": "string" + }, + "host": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "PostgreSQL host", + "title": "Host" + }, + "port": { + "default": 5432, + "title": "Port", + "type": "integer" + }, + "sqlite_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Path to the SQLite database file (for local dev/testing).", + "title": "Sqlite Path" + }, + "database": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Database" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Username" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Password" + }, + "echo": { + "default": false, + "description": "SQLAlchemy echo flag.", + "title": "Echo", + "type": "boolean" + }, + "pool_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional pool size for the engine.", + "title": "Pool Size" + }, + "max_overflow": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional max_overflow for SQLAlchemy pool (defaults to SQLAlchemy's 10 if unset).", + "title": "Max Overflow" + }, + "pool_timeout": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Seconds to wait for a connection from the pool before timing out.", + "title": "Pool Timeout" + }, + "pool_recycle": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Recycle connections after this many seconds (prevents stale TCP / server timeouts).", + "title": "Pool Recycle" + }, + "pool_pre_ping": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Enable SQLAlchemy pool_pre_ping to evict stale connections.", + "title": "Pool Pre Ping" + }, + "connect_args": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional connect_args passed to SQLAlchemy.", + "title": "Connect Args" + } + }, + "title": "PostgresStoreConfig", + "type": "object", + "additionalProperties": false + }, + "opensearch": { + "anyOf": [ + { + "properties": { + "host": { + "description": "OpenSearch host URL", + "title": "Host", + "type": "string" + }, + "username": { + "description": "Username from env", + "title": "Username", + "type": "string" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Password from env", + "title": "Password" + }, + "secure": { + "default": false, + "description": "Use TLS (https)", + "title": "Secure", + "type": "boolean" + }, + "verify_certs": { + "default": false, + "description": "Verify TLS certs", + "title": "Verify Certs", + "type": "boolean" + } + }, + "required": [ + "host", + "username" + ], + "title": "OpenSearchStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional OpenSearch store" + }, + "clickhouse": { + "anyOf": [ + { + "properties": { + "host": { + "default": "localhost", + "description": "ClickHouse host", + "title": "Host", + "type": "string" + }, + "port": { + "default": 8123, + "description": "ClickHouse HTTP port", + "title": "Port", + "type": "integer" + }, + "database": { + "default": "default", + "description": "ClickHouse database", + "title": "Database", + "type": "string" + }, + "username": { + "default": "default", + "description": "ClickHouse username", + "title": "Username", + "type": "string" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ClickHouse password (from CLICKHOUSE_PASSWORD env)", + "title": "Password" + }, + "secure": { + "default": false, + "description": "Use HTTPS for ClickHouse client", + "title": "Secure", + "type": "boolean" + }, + "verify": { + "default": true, + "description": "Verify TLS certificates for ClickHouse", + "title": "Verify", + "type": "boolean" + } + }, + "title": "ClickHouseStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional ClickHouse store" + }, + "resource_store": { + "discriminator": { + "mapping": { + "duckdb": "#/$defs/DuckdbStoreConfig", + "log": "#/$defs/LogStoreConfig", + "memory": "#/$defs/InMemoryStoreConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "postgres": "#/$defs/PostgresTableConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "duckdb", + "title": "Type", + "type": "string" + }, + "duckdb_path": { + "description": "Path to the DuckDB database file.", + "title": "Duckdb Path", + "type": "string" + } + }, + "required": [ + "type", + "duckdb_path" + ], + "title": "DuckdbStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "log", + "title": "Type", + "type": "string" + }, + "level": { + "description": "Logging level", + "title": "Level", + "type": "string" + } + }, + "required": [ + "type", + "level" + ], + "title": "LogStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "postgres", + "title": "Type", + "type": "string" + }, + "table": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Table name used by the store. Deprecated: stores now use fixed table names.", + "title": "Table" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional prefix applied to the table name. Deprecated: stores now use fixed table names.", + "title": "Prefix" + } + }, + "required": [ + "type" + ], + "title": "PostgresTableConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Minimal config for in-memory stores (dev/test only).", + "properties": { + "type": { + "const": "memory", + "default": "memory", + "title": "Type", + "type": "string" + } + }, + "title": "InMemoryStoreConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Resource Store" + }, + "tag_store": { + "discriminator": { + "mapping": { + "duckdb": "#/$defs/DuckdbStoreConfig", + "log": "#/$defs/LogStoreConfig", + "memory": "#/$defs/InMemoryStoreConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "postgres": "#/$defs/PostgresTableConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "duckdb", + "title": "Type", + "type": "string" + }, + "duckdb_path": { + "description": "Path to the DuckDB database file.", + "title": "Duckdb Path", + "type": "string" + } + }, + "required": [ + "type", + "duckdb_path" + ], + "title": "DuckdbStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "log", + "title": "Type", + "type": "string" + }, + "level": { + "description": "Logging level", + "title": "Level", + "type": "string" + } + }, + "required": [ + "type", + "level" + ], + "title": "LogStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "postgres", + "title": "Type", + "type": "string" + }, + "table": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Table name used by the store. Deprecated: stores now use fixed table names.", + "title": "Table" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional prefix applied to the table name. Deprecated: stores now use fixed table names.", + "title": "Prefix" + } + }, + "required": [ + "type" + ], + "title": "PostgresTableConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Minimal config for in-memory stores (dev/test only).", + "properties": { + "type": { + "const": "memory", + "default": "memory", + "title": "Type", + "type": "string" + } + }, + "title": "InMemoryStoreConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Tag Store" + }, + "kpi_store": { + "discriminator": { + "mapping": { + "duckdb": "#/$defs/DuckdbStoreConfig", + "log": "#/$defs/LogStoreConfig", + "memory": "#/$defs/InMemoryStoreConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "postgres": "#/$defs/PostgresTableConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "duckdb", + "title": "Type", + "type": "string" + }, + "duckdb_path": { + "description": "Path to the DuckDB database file.", + "title": "Duckdb Path", + "type": "string" + } + }, + "required": [ + "type", + "duckdb_path" + ], + "title": "DuckdbStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "log", + "title": "Type", + "type": "string" + }, + "level": { + "description": "Logging level", + "title": "Level", + "type": "string" + } + }, + "required": [ + "type", + "level" + ], + "title": "LogStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "postgres", + "title": "Type", + "type": "string" + }, + "table": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Table name used by the store. Deprecated: stores now use fixed table names.", + "title": "Table" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional prefix applied to the table name. Deprecated: stores now use fixed table names.", + "title": "Prefix" + } + }, + "required": [ + "type" + ], + "title": "PostgresTableConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Minimal config for in-memory stores (dev/test only).", + "properties": { + "type": { + "const": "memory", + "default": "memory", + "title": "Type", + "type": "string" + } + }, + "title": "InMemoryStoreConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Kpi Store" + }, + "metadata_store": { + "discriminator": { + "mapping": { + "duckdb": "#/$defs/DuckdbStoreConfig", + "log": "#/$defs/LogStoreConfig", + "memory": "#/$defs/InMemoryStoreConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "postgres": "#/$defs/PostgresTableConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "duckdb", + "title": "Type", + "type": "string" + }, + "duckdb_path": { + "description": "Path to the DuckDB database file.", + "title": "Duckdb Path", + "type": "string" + } + }, + "required": [ + "type", + "duckdb_path" + ], + "title": "DuckdbStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "log", + "title": "Type", + "type": "string" + }, + "level": { + "description": "Logging level", + "title": "Level", + "type": "string" + } + }, + "required": [ + "type", + "level" + ], + "title": "LogStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "postgres", + "title": "Type", + "type": "string" + }, + "table": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Table name used by the store. Deprecated: stores now use fixed table names.", + "title": "Table" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional prefix applied to the table name. Deprecated: stores now use fixed table names.", + "title": "Prefix" + } + }, + "required": [ + "type" + ], + "title": "PostgresTableConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Minimal config for in-memory stores (dev/test only).", + "properties": { + "type": { + "const": "memory", + "default": "memory", + "title": "Type", + "type": "string" + } + }, + "title": "InMemoryStoreConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Metadata Store" + }, + "tabular_store": { + "description": "Dataset-centric tabular storage settings for the supported tabular runtime.\n\nWhy this exists:\n- CSV ingestion persists one Parquet artifact per document in the shared\n content store.\n- One dedicated config block keeps object keys and query limits explicit.\n\nHow to use:\n- Configure the block directly under `storage.tabular_store`.\n- `artifacts_prefix` namespaces Parquet datasets under the shared\n content-store object area.\n- `format` is intentionally fixed to `parquet`.", + "properties": { + "artifacts_prefix": { + "default": "tabular/datasets", + "description": "Prefix under content_storage objects where Parquet datasets are stored.", + "title": "Artifacts Prefix", + "type": "string" + }, + "format": { + "const": "parquet", + "default": "parquet", + "description": "Physical storage format used for tabular artifacts.", + "title": "Format", + "type": "string" + }, + "compression": { + "default": "snappy", + "description": "Parquet compression codec used when persisting tabular artifacts.", + "title": "Compression", + "type": "string" + }, + "query": { + "description": "Runtime settings for dataset-centric SQL queries.\n\nWhy this exists:\n- Tabular querying now runs on transient Parquet datasets rather than\n long-lived SQL tables.\n- These values keep query execution bounded and configurable from YAML.\n\nHow to use:\n- Keep the default `duckdb` engine.\n- Tune result limits and backend-internal presigned URL TTL per deployment.", + "properties": { + "engine": { + "const": "duckdb", + "default": "duckdb", + "description": "Embedded query engine used to read Parquet datasets.", + "title": "Engine", + "type": "string" + }, + "access_mode": { + "const": "presigned_url", + "default": "presigned_url", + "description": "Primary object-access method for remote tabular artifacts.", + "title": "Access Mode", + "type": "string" + }, + "internal_presigned_ttl_seconds": { + "default": 3600, + "description": "TTL in seconds for backend-internal object-storage URLs used by tabular DuckDB reads.", + "minimum": 1, + "title": "Internal Presigned Ttl Seconds", + "type": "integer" + }, + "default_max_rows": { + "default": 200, + "description": "Default preview row limit applied when callers omit max_rows.", + "minimum": 1, + "title": "Default Max Rows", + "type": "integer" + }, + "max_rows": { + "default": 1000, + "description": "Hard cap applied to query result previews.", + "minimum": 1, + "title": "Max Rows", + "type": "integer" + } + }, + "title": "TabularQueryConfig", + "type": "object", + "additionalProperties": false + } + }, + "title": "TabularStoreConfig", + "type": "object", + "additionalProperties": false + }, + "vector_store": { + "discriminator": { + "mapping": { + "chroma": "#/$defs/ChromaVectorStorageConfig", + "clickhouse": "#/$defs/ClickHouseVectorStorageConfig", + "in_memory": "#/$defs/InMemoryVectorStorage", + "opensearch": "#/$defs/OpenSearchVectorIndexConfig", + "pgvector": "#/$defs/PgVectorStorageConfig", + "weaviate": "#/$defs/WeaviateVectorStorage" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "in_memory", + "title": "Type", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "InMemoryVectorStorage", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + }, + "bulk_size": { + "default": 1000, + "description": "Number of documents to send in each bulk insert request", + "title": "Bulk Size", + "type": "integer" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchVectorIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Local, embedded Chroma. No server needed.\n- persist_path: folder where Chroma (DuckDB/Parquet) stores data\n- collection_name: logical collection for your chunks\n- distance: ANN space; 'cosine' matches our UI-friendly similarity", + "properties": { + "type": { + "const": "chroma", + "title": "Type", + "type": "string" + }, + "local_path": { + "default": "~/.fred/knowledge-flow/chromadb-vector-store", + "description": "Local vector storage path", + "title": "Local Path", + "type": "string" + }, + "collection_name": { + "default": "fred_chunks", + "description": "Chroma collection name", + "title": "Collection Name", + "type": "string" + }, + "distance": { + "default": "cosine", + "description": "Vector space (affects HNSW metric)", + "enum": [ + "cosine", + "l2", + "ip" + ], + "title": "Distance", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "ChromaVectorStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "weaviate", + "title": "Type", + "type": "string" + }, + "host": { + "default": "https://localhost:8080", + "description": "Weaviate host", + "title": "Host", + "type": "string" + }, + "index_name": { + "default": "CodeDocuments", + "description": "Weaviate class (collection) name", + "title": "Index Name", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WeaviateVectorStorage", + "type": "object", + "additionalProperties": false + }, + { + "description": "PostgreSQL + pgvector backend.\n- Uses shared `storage.postgres` connection settings.\n- Stores vectors in the default pgvector table under a collection name.", + "properties": { + "type": { + "const": "pgvector", + "title": "Type", + "type": "string" + }, + "collection_name": { + "default": "fred_chunks", + "description": "Logical collection name", + "title": "Collection Name", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "PgVectorStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "ClickHouse backend.\n- Uses shared `storage.clickhouse` connection settings.\n- Stores vectors in the configured table.", + "properties": { + "type": { + "const": "clickhouse", + "title": "Type", + "type": "string" + }, + "table": { + "default": "fred_vectors", + "description": "ClickHouse table name for chunks", + "title": "Table", + "type": "string" + }, + "bulk_size": { + "default": 1000, + "description": "Number of rows per insert batch", + "title": "Bulk Size", + "type": "integer" + } + }, + "required": [ + "type" + ], + "title": "ClickHouseVectorStorageConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Vector Store" + }, + "log_store": { + "anyOf": [ + { + "discriminator": { + "mapping": { + "in_memory": "#/$defs/InMemoryLogStorageConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "stdout": "#/$defs/StdoutLogStorageConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "in_memory", + "title": "Type", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "InMemoryLogStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "stdout", + "title": "Type", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "StdoutLogStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + } + ] + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional log store", + "title": "Log Store" + } + }, + "required": [ + "postgres", + "resource_store", + "tag_store", + "kpi_store", + "metadata_store", + "vector_store" + ], + "title": "StorageConfig", + "type": "object", + "additionalProperties": false + }, + "mcp": { + "description": "Feature toggles for MCP-only HTTP/MCP surfaces.\n\nThese do NOT affect core storage backends (e.g., using OpenSearch\nas vector store or metadata store). They only control whether\noptional monitoring/exploration controllers and their MCP servers\nare exposed.", + "properties": { + "reports_enabled": { + "default": true, + "description": "Expose the Reports MCP server (Markdown-first report generation).", + "title": "Reports Enabled", + "type": "boolean" + }, + "kpi_enabled": { + "default": true, + "description": "Expose the KPI MCP server for querying application KPIs.", + "title": "Kpi Enabled", + "type": "boolean" + }, + "tabular_enabled": { + "default": true, + "description": "Expose the Tabular MCP server for SQL/table exploration.", + "title": "Tabular Enabled", + "type": "boolean" + }, + "statistic_enabled": { + "default": true, + "description": "Expose the Statistical MCP server for data analysis helpers.", + "title": "Statistic Enabled", + "type": "boolean" + }, + "text_enabled": { + "default": true, + "description": "Expose the Text MCP server for semantic vector search.", + "title": "Text Enabled", + "type": "boolean" + }, + "templates_enabled": { + "default": true, + "description": "Expose the Template MCP server for prompts/templates.", + "title": "Templates Enabled", + "type": "boolean" + }, + "resources_enabled": { + "default": true, + "description": "Expose the Resources MCP server for resource/tag management.", + "title": "Resources Enabled", + "type": "boolean" + }, + "opensearch_ops_enabled": { + "default": false, + "description": "Expose OpenSearch operational endpoints and the corresponding MCP server.", + "title": "Opensearch Ops Enabled", + "type": "boolean" + }, + "prometheus_ops_enabled": { + "default": false, + "description": "Expose Prometheus operational endpoints and the corresponding MCP server.", + "title": "Prometheus Ops Enabled", + "type": "boolean" + }, + "neo4j_enabled": { + "default": false, + "description": "Expose Neo4j graph exploration endpoints and the corresponding MCP server.", + "title": "Neo4J Enabled", + "type": "boolean" + }, + "filesystem_enabled": { + "default": false, + "description": "Expose agent filesystem utils endpoints and the corresponding MCP server.", + "title": "Filesystem Enabled", + "type": "boolean" + }, + "filesystem_read_default_limit": { + "default": 100, + "description": "Default line count returned by filesystem read_file when callers omit limit.", + "minimum": 1, + "title": "Filesystem Read Default Limit", + "type": "integer" + }, + "filesystem_read_max_limit": { + "default": 500, + "description": "Absolute maximum line count accepted by filesystem read_file.", + "minimum": 1, + "title": "Filesystem Read Max Limit", + "type": "integer" + }, + "filesystem_read_default_max_chars": { + "default": 20000, + "description": "Default maximum character count returned by filesystem read_file when callers omit max_chars.", + "minimum": 1, + "title": "Filesystem Read Default Max Chars", + "type": "integer" + }, + "filesystem_read_absolute_max_chars": { + "default": 50000, + "description": "Absolute maximum character count accepted by filesystem read_file.", + "minimum": 1, + "title": "Filesystem Read Absolute Max Chars", + "type": "integer" + } + }, + "title": "MCPConfig", + "type": "object", + "additionalProperties": false + }, + "filesystem": { + "description": "Filesystem backend configuration.", + "discriminator": { + "mapping": { + "local": "#/$defs/LocalFilesystemConfig", + "minio": "#/$defs/MinioFilesystemConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "local", + "default": "local", + "title": "Type", + "type": "string" + }, + "root": { + "default": "~/.fred/knowledge-flow/filesystem/", + "description": "Local filesystem root directory.", + "title": "Root", + "type": "string" + } + }, + "title": "LocalFilesystemConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "minio", + "default": "minio", + "title": "Type", + "type": "string" + }, + "endpoint": { + "description": "MinIO or S3 compatible endpoint.", + "title": "Endpoint", + "type": "string" + }, + "access_key": { + "description": "MinIO access key.", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "default": null, + "description": "MinIO secret key (from MINIO_SECRET_KEY env).", + "title": "Secret Key", + "type": "string" + }, + "bucket_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "filesystem", + "description": "MinIO bucket name.", + "title": "Bucket Name" + }, + "secure": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": false, + "description": "Use TLS for the MinIO client.", + "title": "Secure" + } + }, + "required": [ + "endpoint", + "access_key" + ], + "title": "MinioFilesystemConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Filesystem" + }, + "workspace_layout": { + "description": "Configurable storage path layout for workspace storage.\n\nAllowed placeholders:\n {user_id}, {agent_id}, {key}", + "properties": { + "user_pattern": { + "default": "users/{user_id}/{key}", + "description": "Path template for user exchange storage", + "title": "User Pattern", + "type": "string" + }, + "agent_config_pattern": { + "default": "agents/{agent_id}/config/{key}", + "description": "Path template for agent config storage", + "title": "Agent Config Pattern", + "type": "string" + }, + "agent_user_pattern": { + "default": "agents/{agent_id}/users/{user_id}/{key}", + "description": "Path template for per-user agent storage", + "title": "Agent User Pattern", + "type": "string" + } + }, + "title": "WorkspaceLayoutConfig", + "type": "object", + "additionalProperties": false + } + }, + "required": [ + "app", + "chat_model", + "embedding_model", + "security", + "content_storage", + "scheduler", + "storage", + "filesystem" + ], + "title": "Configuration", + "type": "object", + "additionalProperties": false + }, + "dotenv": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "knowledge-flow-worker": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "applicationName": { + "type": "string" + }, + "configurationFileName": { + "type": "string" + }, + "deployment": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "replicaCount": { + "type": "integer" + }, + "statefulset": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "job": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "migration": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "scaleDown": { + "type": "boolean" + }, + "backoffLimit": { + "type": "integer" + }, + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "object" + } + }, + "additionalProperties": false + }, + "rollingUpdate": { + "type": "object", + "properties": { + "maxSurge": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "maxUnavailable": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": false + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "pullPolicy": { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "additionalProperties": false + }, + "command": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "env": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": true + } + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "containerPort": { + "type": "integer" + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "service": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": false + }, + "metricsService": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "interval": { + "type": "string" + }, + "scrapeTimeout": { + "type": "string" + }, + "path": { + "type": "string" + }, + "scheme": { + "type": "string" + }, + "honorLabels": { + "type": "boolean" + }, + "relabelings": { + "type": "array", + "items": {} + }, + "metricRelabelings": { + "type": "array", + "items": {} + }, + "namespaceSelector": { + "type": "object" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "ingress": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "className": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + }, + "service": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "tls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "secretName": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + }, + "volumeMounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "subPath": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + }, + "additionalProperties": true + } + }, + "volumes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "probes": { + "type": "object", + "properties": { + "lifecycle": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "securityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + }, + "add": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "runAsUser": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "rbac": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "permissions": { + "type": "object", + "properties": { + "namespaced": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + }, + "cluster": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "kubeconfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration_type": { + "type": "object", + "properties": { + "backend": { + "type": "boolean" + }, + "frontend": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration": { + "properties": { + "app": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "Knowledge Flow Backend", + "title": "Name" + }, + "base_url": { + "default": "/knowledge-flow/v1", + "title": "Base Url", + "type": "string" + }, + "address": { + "default": "127.0.0.1", + "title": "Address", + "type": "string" + }, + "port": { + "default": 8000, + "title": "Port", + "type": "integer" + }, + "log_level": { + "default": "info", + "title": "Log Level", + "type": "string" + }, + "reload": { + "default": false, + "title": "Reload", + "type": "boolean" + }, + "reload_dir": { + "default": ".", + "title": "Reload Dir", + "type": "string" + }, + "metrics_enabled": { + "default": true, + "title": "Metrics Enabled", + "type": "boolean" + }, + "metrics_address": { + "default": "127.0.0.1", + "title": "Metrics Address", + "type": "string" + }, + "metrics_port": { + "default": 9111, + "title": "Metrics Port", + "type": "integer" + }, + "kpi_process_metrics_interval_sec": { + "default": 10, + "description": "Interval in seconds for processing and logging KPI metrics.", + "title": "Kpi Process Metrics Interval Sec", + "type": "integer" + }, + "kpi_log_summary_interval_sec": { + "default": 0.0, + "description": "Emit KPI summary logs every N seconds (bench/debug). Set 0 to disable.", + "title": "Kpi Log Summary Interval Sec", + "type": "number" + }, + "kpi_log_summary_top_n": { + "default": 0, + "description": "Top-N metrics to show in KPI summary logs. 0 means all / disabled.", + "title": "Kpi Log Summary Top N", + "type": "integer" + }, + "gcu_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Gcu Version" + }, + "default_team_max_resources_storage_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Default storage limit in bytes for a team when not explicitly set.", + "title": "Default Team Max Resources Storage Size" + }, + "personal_max_resources_storage_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Maximum resources storage size in bytes for a personal space", + "title": "Personal Max Resources Storage Size" + } + }, + "title": "AppConfig", + "type": "object", + "additionalProperties": false + }, + "integrations": { + "anyOf": [ + { + "description": "Optional upstream service integrations consumed by Knowledge Flow.", + "properties": { + "prometheus": { + "anyOf": [ + { + "properties": { + "base_url": { + "description": "Base URL of a Prometheus-compatible HTTP API.", + "title": "Base Url", + "type": "string" + }, + "verify_ssl": { + "default": true, + "description": "Verify upstream TLS certificates when querying Prometheus.", + "title": "Verify Ssl", + "type": "boolean" + }, + "timeout_seconds": { + "default": 15.0, + "description": "HTTP timeout applied to Prometheus API calls.", + "exclusiveMinimum": 0, + "title": "Timeout Seconds", + "type": "number" + }, + "bearer_token": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional bearer token loaded from PROMETHEUS_BEARER_TOKEN.", + "title": "Bearer Token" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "admin", + "description": "Basic-auth username configured directly in prometheus.username. Defaults to 'admin'.", + "title": "Username" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional basic-auth password loaded from PROMETHEUS_PASSWORD.", + "title": "Password" + } + }, + "required": [ + "base_url" + ], + "title": "PrometheusConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional Prometheus API configuration for cluster-wide metrics queries." + } + }, + "title": "IntegrationsConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional third-party service integrations used by the backend." + }, + "chat_model": { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + "embedding_model": { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + "vision_model": { + "anyOf": [ + { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null + }, + "ocr_model": { + "anyOf": [ + { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional remote OCR model configuration. When set, PDF OCR can be delegated to an external API instead of local Docling OCR." + }, + "crossencoder_model": { + "anyOf": [ + { + "properties": { + "provider": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Provider of the AI model, e.g., openai, ollama, azure.", + "title": "Provider" + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Model name, e.g., gpt-4o, llama2.", + "title": "Name" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Additional provider-specific settings, e.g. Azure endpoint/API version or Vertex AI project/location.", + "title": "Settings" + } + }, + "title": "ModelConfiguration", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null + }, + "security": { + "properties": { + "m2m": { + "description": "Configuration for machine-to-machine authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + }, + "audience": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Audience" + }, + "secret_env_var": { + "default": "M2M_CLIENT_SECRET", + "title": "Secret Env Var", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "M2MSecurity", + "type": "object", + "additionalProperties": false + }, + "user": { + "description": "Configuration for user authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "UserSecurity", + "type": "object", + "additionalProperties": false + }, + "authorized_origins": { + "default": [], + "items": { + "format": "uri", + "minLength": 1, + "type": "string" + }, + "title": "Authorized Origins", + "type": "array" + }, + "rebac": { + "anyOf": [ + { + "discriminator": { + "mapping": { + "openfga": "#/$defs/OpenFgaRebacConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "description": "Configuration for an OpenFGA-backed relationship engine.", + "properties": { + "enabled": { + "default": true, + "description": "To disable ReBAC checks (do not disable in production). If OIDC (UserSecurity and M2MSecurity) ReBAC check will be disabled even if this is true.", + "title": "Enabled", + "type": "boolean" + }, + "type": { + "const": "openfga", + "default": "openfga", + "title": "Type", + "type": "string" + }, + "api_url": { + "description": "Base URL for the OpenFGA HTTP API (e.g. https://fga.example.com)", + "format": "uri", + "minLength": 1, + "title": "Api Url", + "type": "string" + }, + "store_name": { + "default": "fred", + "description": "Name of the OpenFGA store to use", + "title": "Store Name", + "type": "string" + }, + "authorization_model_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional authorization model ID to use for read operations. Will be overridden if sync_schema_on_init is True.", + "title": "Authorization Model Id" + }, + "create_store_if_needed": { + "default": true, + "description": "Create the OpenFGA store if it does not already exist", + "title": "Create Store If Needed", + "type": "boolean" + }, + "sync_schema_on_init": { + "default": true, + "description": "Synchronize the authorization model when creating the engine", + "title": "Sync Schema On Init", + "type": "boolean" + }, + "token_env_var": { + "default": "OPENFGA_API_TOKEN", + "description": "Environment variable that stores the OpenFGA API token", + "title": "Token Env Var", + "type": "string" + }, + "timeout_millisec": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional timeout in milliseconds for OpenFGA API requests", + "title": "Timeout Millisec" + }, + "headers": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Static HTTP headers to send with each OpenFGA API request", + "title": "Headers" + } + }, + "required": [ + "api_url" + ], + "title": "OpenFgaRebacConfig", + "type": "object", + "additionalProperties": false + } + ] + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rebac" + } + }, + "required": [ + "m2m", + "user" + ], + "title": "SecurityConfiguration", + "type": "object", + "additionalProperties": false + }, + "attachment_processors": { + "anyOf": [ + { + "items": { + "description": "Configuration structure for a file processor.\nAttributes:\n suffix (str): The file extension this processor handles (e.g., '.pdf').\n class_path (str): Dotted import path of the processor class.\n description (str): Human readable explanation of what the processor does.", + "properties": { + "suffix": { + "description": "The file extension this processor handles (e.g., '.pdf')", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProcessorConfig", + "type": "object", + "additionalProperties": false + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional fast-text processors for attachments. Uses the same ProcessorConfig structure, but classes must subclass BaseFastTextProcessor. If omitted, the default fast processor is used.", + "title": "Attachment Processors" + }, + "document_guardrail": { + "anyOf": [ + { + "properties": { + "enabled": { + "default": false, + "description": "Enable ingestion-time document marking guardrails.", + "title": "Enabled", + "type": "boolean" + }, + "source_tags": { + "description": "Optional source tags this guardrail applies to. Empty means all sources.", + "items": { + "type": "string" + }, + "title": "Source Tags", + "type": "array" + }, + "allowed_labels": { + "description": "Optional allow-list of labels accepted by the guardrail. Empty means detection-only.", + "items": { + "type": "string" + }, + "title": "Allowed Labels", + "type": "array" + }, + "on_no_label": { + "default": "allow", + "description": "Behavior when no explicit document marking is detected.", + "enum": [ + "allow", + "warn", + "reject" + ], + "title": "On No Label", + "type": "string" + }, + "patterns": { + "description": "Regex patterns used to recognize explicit document markings.", + "items": { + "properties": { + "label": { + "description": "Normalized label returned when the regex matches.", + "minLength": 1, + "title": "Label", + "type": "string" + }, + "pattern": { + "description": "Regex used to detect the marking in extracted guardrail text.", + "minLength": 1, + "title": "Pattern", + "type": "string" + } + }, + "required": [ + "label", + "pattern" + ], + "title": "DocumentMarkingPatternConfig", + "type": "object", + "additionalProperties": false + }, + "title": "Patterns", + "type": "array" + } + }, + "title": "DocumentGuardrailConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional ingestion-time guardrail for explicit document markings." + }, + "output_processors": { + "anyOf": [ + { + "items": { + "description": "Configuration structure for a file processor.\nAttributes:\n suffix (str): The file extension this processor handles (e.g., '.pdf').\n class_path (str): Dotted import path of the processor class.\n description (str): Human readable explanation of what the processor does.", + "properties": { + "suffix": { + "description": "The file extension this processor handles (e.g., '.pdf')", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProcessorConfig", + "type": "object", + "additionalProperties": false + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Output Processors" + }, + "library_output_processors": { + "anyOf": [ + { + "items": { + "description": "Configuration structure for a library-level output processor.\n\nAttributes:\n class_path (str): Dotted import path of the processor class.\n description (str): Human readable explanation of what the processor does.", + "properties": { + "class_path": { + "description": "Dotted import path of the library output processor class", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the library output processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "class_path" + ], + "title": "LibraryProcessorConfig", + "type": "object", + "additionalProperties": false + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Library Output Processors" + }, + "content_storage": { + "description": "Content Storage configuration", + "discriminator": { + "mapping": { + "local": "#/$defs/LocalContentStorageConfig", + "minio": "#/$defs/MinioStorageConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "local", + "title": "Type", + "type": "string" + }, + "root_path": { + "default": "~/.fred/knowledge-flow/content-store", + "description": "Local storage directory", + "title": "Root Path", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "LocalContentStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "minio", + "title": "Type", + "type": "string" + }, + "endpoint": { + "default": "localhost:9000", + "description": "MinIO API URL", + "title": "Endpoint", + "type": "string" + }, + "access_key": { + "description": "MinIO access key (from MINIO_ACCESS_KEY env)", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "default": null, + "description": "MinIO secret key (from MINIO_SECRET_KEY env)", + "title": "Secret Key", + "type": "string" + }, + "bucket_name": { + "default": "app-bucket", + "description": "Content store bucket name", + "title": "Bucket Name", + "type": "string" + }, + "secure": { + "default": false, + "description": "Use TLS (https)", + "title": "Secure", + "type": "boolean" + }, + "public_endpoint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Public MinIO endpoint for browser-facing presigned URLs (e.g. 'https://my.minio.ingress'). If not set, uses endpoint.", + "title": "Public Endpoint" + }, + "public_secure": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Use TLS for public endpoint. If not set, inferred from public_endpoint scheme.", + "title": "Public Secure" + } + }, + "required": [ + "type", + "access_key" + ], + "title": "MinioStorageConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Content Storage" + }, + "scheduler": { + "properties": { + "enabled": { + "default": false, + "title": "Enabled", + "type": "boolean" + }, + "backend": { + "description": "Allowed scheduler backend values across Fred backends.\n\nWhy this exists:\n- Avoid raw string literals (`\"temporal\"`, `\"memory\"`) spread in business code.\n- Keep one typed source of truth used by configuration parsing and runtime checks.\n\nHow to use:\n```python\nfrom fred_core.scheduler import SchedulerBackend\n\nif backend == SchedulerBackend.MEMORY:\n ...\n```", + "enum": [ + "temporal", + "memory" + ], + "title": "SchedulerBackend", + "type": "string" + }, + "temporal": { + "properties": { + "host": { + "default": "localhost:7233", + "title": "Host", + "type": "string" + }, + "namespace": { + "default": "default", + "title": "Namespace", + "type": "string" + }, + "task_queue": { + "default": "default", + "title": "Task Queue", + "type": "string" + }, + "workflow_id_prefix": { + "default": "task", + "title": "Workflow Id Prefix", + "type": "string" + }, + "connect_timeout_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 5, + "title": "Connect Timeout Seconds" + }, + "ingestion_workflow_parallelism": { + "default": 3, + "description": "Max number of files launched in parallel per parent ingestion workflow.", + "minimum": 1, + "title": "Ingestion Workflow Parallelism", + "type": "integer" + }, + "ingestion_max_concurrent_workflow_tasks": { + "default": 3, + "description": "Max concurrent Temporal workflow tasks processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Workflow Tasks", + "type": "integer" + }, + "ingestion_max_concurrent_activities": { + "default": 3, + "description": "Max concurrent Temporal activities processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Activities", + "type": "integer" + } + }, + "title": "TemporalSchedulerConfig", + "type": "object", + "additionalProperties": false + } + }, + "required": [ + "temporal" + ], + "title": "SchedulerConfig", + "type": "object", + "additionalProperties": false + }, + "processing": { + "additionalProperties": false, + "properties": { + "default_profile": { + "enum": [ + "fast", + "medium", + "rich" + ], + "title": "IngestionProcessingProfile", + "type": "string" + }, + "profiles": { + "additionalProperties": false, + "properties": { + "fast": { + "additionalProperties": false, + "properties": { + "use_gpu": { + "default": true, + "description": "Enable/disable GPU usage for this profile (if supported by the selected processors).", + "title": "Use Gpu", + "type": "boolean" + }, + "process_images": { + "default": false, + "description": "Enable/disable semantic image description in markdown for this profile.", + "title": "Process Images", + "type": "boolean" + }, + "generate_summary": { + "default": false, + "description": "Enable/disable human-centric abstract and keyword generation for this profile.", + "title": "Generate Summary", + "type": "boolean" + }, + "input_activity_timeout": { + "default": "1h", + "description": "Temporal start-to-close timeout for input processing activities (e.g., '1h', '45m').", + "title": "Input Activity Timeout", + "type": "string" + }, + "activity_heartbeat_timeout": { + "default": "5m", + "description": "Temporal heartbeat timeout for input processing activities (e.g., '5m', '10m'). Must be larger than the worker's heartbeat interval (~20s).", + "title": "Activity Heartbeat Timeout", + "type": "string" + }, + "pdf": { + "additionalProperties": false, + "properties": { + "backend": { + "default": "docling_parse", + "description": "PDF backend for Docling conversion.", + "enum": [ + "dlparse_v4", + "pypdfium2", + "docling_parse" + ], + "title": "Backend", + "type": "string" + }, + "images_scale": { + "default": 2.0, + "description": "Docling PDF image scaling factor.", + "exclusiveMinimum": 0.0, + "title": "Images Scale", + "type": "number" + }, + "generate_picture_images": { + "default": false, + "description": "Generate extracted picture image assets during PDF conversion. Independent from profile.process_images (image description).", + "title": "Generate Picture Images", + "type": "boolean" + }, + "generate_page_images": { + "default": false, + "description": "Generate full-page images for PDFs.", + "title": "Generate Page Images", + "type": "boolean" + }, + "generate_table_images": { + "default": false, + "description": "Generate table images for PDFs.", + "title": "Generate Table Images", + "type": "boolean" + }, + "do_table_structure": { + "default": false, + "description": "Enable table structure extraction in the standard Docling PDF pipeline.", + "title": "Do Table Structure", + "type": "boolean" + }, + "do_ocr": { + "default": false, + "description": "Enable OCR in the standard Docling PDF pipeline.", + "title": "Do Ocr", + "type": "boolean" + }, + "ocr_backend": { + "anyOf": [ + { + "enum": [ + "onnxruntime", + "openvino", + "paddle", + "torch" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": "openvino", + "description": "Override RapidOCR inference backend when OCR is enabled.", + "title": "Ocr Backend" + }, + "force_full_page_ocr": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Override RapidOCR full-page OCR. Set to true to OCR every page even when backend text exists.", + "title": "Force Full Page Ocr" + }, + "ocr_batch_size": { + "default": 4, + "description": "OCR batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Ocr Batch Size", + "type": "integer" + }, + "layout_batch_size": { + "default": 4, + "description": "Layout batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Layout Batch Size", + "type": "integer" + }, + "table_batch_size": { + "default": 4, + "description": "Table-structure batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Table Batch Size", + "type": "integer" + }, + "batch_polling_interval_seconds": { + "default": 0.5, + "description": "Polling interval in seconds used by Docling's threaded StandardPdfPipeline to accumulate batches before processing.", + "exclusiveMinimum": 0.0, + "title": "Batch Polling Interval Seconds", + "type": "number" + }, + "queue_max_size": { + "default": 100, + "description": "Maximum inter-stage queue size used by Docling's threaded StandardPdfPipeline. Smaller queues reduce buffering and can lower memory usage.", + "minimum": 1, + "title": "Queue Max Size", + "type": "integer" + } + }, + "title": "PdfPipelineConfig", + "type": "object" + }, + "text_splitter": { + "additionalProperties": false, + "properties": { + "chunk_size": { + "default": 1500, + "description": "Maximum number of characters per chunk for text splitting.", + "minimum": 1, + "title": "Chunk Size", + "type": "integer" + }, + "chunk_overlap": { + "default": 150, + "description": "Number of overlapping characters between consecutive chunks.", + "minimum": 0, + "title": "Chunk Overlap", + "type": "integer" + }, + "preserve_tables": { + "default": true, + "description": "If true, keep annotated markdown tables intact (do not split by size).", + "title": "Preserve Tables", + "type": "boolean" + } + }, + "title": "TextSplitterConfig", + "type": "object" + }, + "input_processors": { + "description": "Input processors selected for this profile (suffix-specific).", + "items": { + "additionalProperties": false, + "properties": { + "suffix": { + "description": "The file suffix this processor handles (e.g., '.pdf').", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class.", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProfileInputProcessorConfig", + "type": "object" + }, + "title": "Input Processors", + "type": "array" + }, + "retry_initial_interval": { + "default": "30s", + "description": "Temporal retry delay before the first retry for this profile's ingestion activities.", + "title": "Retry Initial Interval", + "type": "string" + }, + "retry_backoff_coefficient": { + "default": 2.0, + "description": "Temporal retry backoff coefficient for this profile's ingestion activities.", + "minimum": 1.0, + "title": "Retry Backoff Coefficient", + "type": "number" + }, + "retry_maximum_interval": { + "default": "10m", + "description": "Maximum Temporal retry delay for this profile's ingestion activities.", + "title": "Retry Maximum Interval", + "type": "string" + }, + "retry_maximum_attempts": { + "default": 6, + "description": "Maximum Temporal activity attempts for this profile, including the first attempt.", + "minimum": 1, + "title": "Retry Maximum Attempts", + "type": "integer" + }, + "retry_non_retryable_error_types": { + "description": "Temporal application error types that should fail fast for this profile without retry.", + "items": { + "type": "string" + }, + "title": "Retry Non Retryable Error Types", + "type": "array" + } + }, + "title": "ProfileConfig", + "type": "object" + }, + "medium": { + "additionalProperties": false, + "properties": { + "use_gpu": { + "default": true, + "description": "Enable/disable GPU usage for this profile (if supported by the selected processors).", + "title": "Use Gpu", + "type": "boolean" + }, + "process_images": { + "default": false, + "description": "Enable/disable semantic image description in markdown for this profile.", + "title": "Process Images", + "type": "boolean" + }, + "generate_summary": { + "default": false, + "description": "Enable/disable human-centric abstract and keyword generation for this profile.", + "title": "Generate Summary", + "type": "boolean" + }, + "input_activity_timeout": { + "default": "1h", + "description": "Temporal start-to-close timeout for input processing activities (e.g., '1h', '45m').", + "title": "Input Activity Timeout", + "type": "string" + }, + "activity_heartbeat_timeout": { + "default": "5m", + "description": "Temporal heartbeat timeout for input processing activities (e.g., '5m', '10m'). Must be larger than the worker's heartbeat interval (~20s).", + "title": "Activity Heartbeat Timeout", + "type": "string" + }, + "pdf": { + "additionalProperties": false, + "properties": { + "backend": { + "default": "docling_parse", + "description": "PDF backend for Docling conversion.", + "enum": [ + "dlparse_v4", + "pypdfium2", + "docling_parse" + ], + "title": "Backend", + "type": "string" + }, + "images_scale": { + "default": 2.0, + "description": "Docling PDF image scaling factor.", + "exclusiveMinimum": 0.0, + "title": "Images Scale", + "type": "number" + }, + "generate_picture_images": { + "default": false, + "description": "Generate extracted picture image assets during PDF conversion. Independent from profile.process_images (image description).", + "title": "Generate Picture Images", + "type": "boolean" + }, + "generate_page_images": { + "default": false, + "description": "Generate full-page images for PDFs.", + "title": "Generate Page Images", + "type": "boolean" + }, + "generate_table_images": { + "default": false, + "description": "Generate table images for PDFs.", + "title": "Generate Table Images", + "type": "boolean" + }, + "do_table_structure": { + "default": false, + "description": "Enable table structure extraction in the standard Docling PDF pipeline.", + "title": "Do Table Structure", + "type": "boolean" + }, + "do_ocr": { + "default": false, + "description": "Enable OCR in the standard Docling PDF pipeline.", + "title": "Do Ocr", + "type": "boolean" + }, + "ocr_backend": { + "anyOf": [ + { + "enum": [ + "onnxruntime", + "openvino", + "paddle", + "torch" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": "openvino", + "description": "Override RapidOCR inference backend when OCR is enabled.", + "title": "Ocr Backend" + }, + "force_full_page_ocr": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Override RapidOCR full-page OCR. Set to true to OCR every page even when backend text exists.", + "title": "Force Full Page Ocr" + }, + "ocr_batch_size": { + "default": 4, + "description": "OCR batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Ocr Batch Size", + "type": "integer" + }, + "layout_batch_size": { + "default": 4, + "description": "Layout batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Layout Batch Size", + "type": "integer" + }, + "table_batch_size": { + "default": 4, + "description": "Table-structure batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Table Batch Size", + "type": "integer" + }, + "batch_polling_interval_seconds": { + "default": 0.5, + "description": "Polling interval in seconds used by Docling's threaded StandardPdfPipeline to accumulate batches before processing.", + "exclusiveMinimum": 0.0, + "title": "Batch Polling Interval Seconds", + "type": "number" + }, + "queue_max_size": { + "default": 100, + "description": "Maximum inter-stage queue size used by Docling's threaded StandardPdfPipeline. Smaller queues reduce buffering and can lower memory usage.", + "minimum": 1, + "title": "Queue Max Size", + "type": "integer" + } + }, + "title": "PdfPipelineConfig", + "type": "object" + }, + "text_splitter": { + "additionalProperties": false, + "properties": { + "chunk_size": { + "default": 1500, + "description": "Maximum number of characters per chunk for text splitting.", + "minimum": 1, + "title": "Chunk Size", + "type": "integer" + }, + "chunk_overlap": { + "default": 150, + "description": "Number of overlapping characters between consecutive chunks.", + "minimum": 0, + "title": "Chunk Overlap", + "type": "integer" + }, + "preserve_tables": { + "default": true, + "description": "If true, keep annotated markdown tables intact (do not split by size).", + "title": "Preserve Tables", + "type": "boolean" + } + }, + "title": "TextSplitterConfig", + "type": "object" + }, + "input_processors": { + "description": "Input processors selected for this profile (suffix-specific).", + "items": { + "additionalProperties": false, + "properties": { + "suffix": { + "description": "The file suffix this processor handles (e.g., '.pdf').", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class.", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProfileInputProcessorConfig", + "type": "object" + }, + "title": "Input Processors", + "type": "array" + }, + "retry_initial_interval": { + "default": "30s", + "description": "Temporal retry delay before the first retry for this profile's ingestion activities.", + "title": "Retry Initial Interval", + "type": "string" + }, + "retry_backoff_coefficient": { + "default": 2.0, + "description": "Temporal retry backoff coefficient for this profile's ingestion activities.", + "minimum": 1.0, + "title": "Retry Backoff Coefficient", + "type": "number" + }, + "retry_maximum_interval": { + "default": "10m", + "description": "Maximum Temporal retry delay for this profile's ingestion activities.", + "title": "Retry Maximum Interval", + "type": "string" + }, + "retry_maximum_attempts": { + "default": 6, + "description": "Maximum Temporal activity attempts for this profile, including the first attempt.", + "minimum": 1, + "title": "Retry Maximum Attempts", + "type": "integer" + }, + "retry_non_retryable_error_types": { + "description": "Temporal application error types that should fail fast for this profile without retry.", + "items": { + "type": "string" + }, + "title": "Retry Non Retryable Error Types", + "type": "array" + } + }, + "title": "ProfileConfig", + "type": "object" + }, + "rich": { + "additionalProperties": false, + "properties": { + "use_gpu": { + "default": true, + "description": "Enable/disable GPU usage for this profile (if supported by the selected processors).", + "title": "Use Gpu", + "type": "boolean" + }, + "process_images": { + "default": false, + "description": "Enable/disable semantic image description in markdown for this profile.", + "title": "Process Images", + "type": "boolean" + }, + "generate_summary": { + "default": false, + "description": "Enable/disable human-centric abstract and keyword generation for this profile.", + "title": "Generate Summary", + "type": "boolean" + }, + "input_activity_timeout": { + "default": "1h", + "description": "Temporal start-to-close timeout for input processing activities (e.g., '1h', '45m').", + "title": "Input Activity Timeout", + "type": "string" + }, + "activity_heartbeat_timeout": { + "default": "5m", + "description": "Temporal heartbeat timeout for input processing activities (e.g., '5m', '10m'). Must be larger than the worker's heartbeat interval (~20s).", + "title": "Activity Heartbeat Timeout", + "type": "string" + }, + "pdf": { + "additionalProperties": false, + "properties": { + "backend": { + "default": "docling_parse", + "description": "PDF backend for Docling conversion.", + "enum": [ + "dlparse_v4", + "pypdfium2", + "docling_parse" + ], + "title": "Backend", + "type": "string" + }, + "images_scale": { + "default": 2.0, + "description": "Docling PDF image scaling factor.", + "exclusiveMinimum": 0.0, + "title": "Images Scale", + "type": "number" + }, + "generate_picture_images": { + "default": false, + "description": "Generate extracted picture image assets during PDF conversion. Independent from profile.process_images (image description).", + "title": "Generate Picture Images", + "type": "boolean" + }, + "generate_page_images": { + "default": false, + "description": "Generate full-page images for PDFs.", + "title": "Generate Page Images", + "type": "boolean" + }, + "generate_table_images": { + "default": false, + "description": "Generate table images for PDFs.", + "title": "Generate Table Images", + "type": "boolean" + }, + "do_table_structure": { + "default": false, + "description": "Enable table structure extraction in the standard Docling PDF pipeline.", + "title": "Do Table Structure", + "type": "boolean" + }, + "do_ocr": { + "default": false, + "description": "Enable OCR in the standard Docling PDF pipeline.", + "title": "Do Ocr", + "type": "boolean" + }, + "ocr_backend": { + "anyOf": [ + { + "enum": [ + "onnxruntime", + "openvino", + "paddle", + "torch" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": "openvino", + "description": "Override RapidOCR inference backend when OCR is enabled.", + "title": "Ocr Backend" + }, + "force_full_page_ocr": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Override RapidOCR full-page OCR. Set to true to OCR every page even when backend text exists.", + "title": "Force Full Page Ocr" + }, + "ocr_batch_size": { + "default": 4, + "description": "OCR batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Ocr Batch Size", + "type": "integer" + }, + "layout_batch_size": { + "default": 4, + "description": "Layout batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Layout Batch Size", + "type": "integer" + }, + "table_batch_size": { + "default": 4, + "description": "Table-structure batch size used by Docling's threaded StandardPdfPipeline. Larger batches improve throughput but increase memory usage.", + "minimum": 1, + "title": "Table Batch Size", + "type": "integer" + }, + "batch_polling_interval_seconds": { + "default": 0.5, + "description": "Polling interval in seconds used by Docling's threaded StandardPdfPipeline to accumulate batches before processing.", + "exclusiveMinimum": 0.0, + "title": "Batch Polling Interval Seconds", + "type": "number" + }, + "queue_max_size": { + "default": 100, + "description": "Maximum inter-stage queue size used by Docling's threaded StandardPdfPipeline. Smaller queues reduce buffering and can lower memory usage.", + "minimum": 1, + "title": "Queue Max Size", + "type": "integer" + } + }, + "title": "PdfPipelineConfig", + "type": "object" + }, + "text_splitter": { + "additionalProperties": false, + "properties": { + "chunk_size": { + "default": 1500, + "description": "Maximum number of characters per chunk for text splitting.", + "minimum": 1, + "title": "Chunk Size", + "type": "integer" + }, + "chunk_overlap": { + "default": 150, + "description": "Number of overlapping characters between consecutive chunks.", + "minimum": 0, + "title": "Chunk Overlap", + "type": "integer" + }, + "preserve_tables": { + "default": true, + "description": "If true, keep annotated markdown tables intact (do not split by size).", + "title": "Preserve Tables", + "type": "boolean" + } + }, + "title": "TextSplitterConfig", + "type": "object" + }, + "input_processors": { + "description": "Input processors selected for this profile (suffix-specific).", + "items": { + "additionalProperties": false, + "properties": { + "suffix": { + "description": "The file suffix this processor handles (e.g., '.pdf').", + "title": "Suffix", + "type": "string" + }, + "class_path": { + "description": "Dotted import path of the processor class.", + "title": "Class Path", + "type": "string" + }, + "description": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of the processor purpose shown in the UI.", + "title": "Description" + } + }, + "required": [ + "suffix", + "class_path" + ], + "title": "ProfileInputProcessorConfig", + "type": "object" + }, + "title": "Input Processors", + "type": "array" + }, + "retry_initial_interval": { + "default": "30s", + "description": "Temporal retry delay before the first retry for this profile's ingestion activities.", + "title": "Retry Initial Interval", + "type": "string" + }, + "retry_backoff_coefficient": { + "default": 2.0, + "description": "Temporal retry backoff coefficient for this profile's ingestion activities.", + "minimum": 1.0, + "title": "Retry Backoff Coefficient", + "type": "number" + }, + "retry_maximum_interval": { + "default": "10m", + "description": "Maximum Temporal retry delay for this profile's ingestion activities.", + "title": "Retry Maximum Interval", + "type": "string" + }, + "retry_maximum_attempts": { + "default": 6, + "description": "Maximum Temporal activity attempts for this profile, including the first attempt.", + "minimum": 1, + "title": "Retry Maximum Attempts", + "type": "integer" + }, + "retry_non_retryable_error_types": { + "description": "Temporal application error types that should fail fast for this profile without retry.", + "items": { + "type": "string" + }, + "title": "Retry Non Retryable Error Types", + "type": "array" + } + }, + "title": "ProfileConfig", + "type": "object" + } + }, + "title": "ProfilesConfig", + "type": "object" + } + }, + "title": "ProcessingConfig", + "type": "object" + }, + "document_sources": { + "additionalProperties": { + "discriminator": { + "mapping": { + "pull": { + "discriminator": { + "mapping": { + "github": "#/$defs/GitPullSource", + "gitlab": "#/$defs/GitlabPullSource", + "local_path": "#/$defs/FileSystemPullSource", + "minio": "#/$defs/MinioPullSource", + "sphere": "#/$defs/SpherePullSource" + }, + "propertyName": "provider" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "local_path", + "title": "Provider", + "type": "string" + }, + "base_path": { + "title": "Base Path", + "type": "string" + } + }, + "required": [ + "provider", + "base_path" + ], + "title": "FileSystemPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "github", + "title": "Provider", + "type": "string" + }, + "repo": { + "description": "GitHub repository in the format 'owner/repo'", + "title": "Repo", + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "main", + "description": "Git branch to pull from", + "title": "Branch" + }, + "subdir": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Subdirectory to extract files from", + "title": "Subdir" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional GitHub username (for logs)", + "title": "Username" + }, + "token": { + "description": "GitHub token (from GITHUB_TOKEN env variable)", + "title": "Token", + "type": "string" + } + }, + "required": [ + "provider", + "repo", + "token" + ], + "title": "GitPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "sphere", + "title": "Provider", + "type": "string" + }, + "base_url": { + "description": "Base URL for the Sphere API", + "title": "Base Url", + "type": "string" + }, + "parent_node_id": { + "description": "ID of the parent folder or node to list/download", + "title": "Parent Node Id", + "type": "string" + }, + "username": { + "description": "Username for Sphere Basic Auth", + "title": "Username", + "type": "string" + }, + "password": { + "description": "Password (loaded from SPHERE_PASSWORD)", + "title": "Password", + "type": "string" + }, + "apikey": { + "description": "API key (loaded from SPHERE_API_KEY)", + "title": "Apikey", + "type": "string" + }, + "verify_ssl": { + "default": false, + "description": "Set to True to verify SSL certs", + "title": "Verify Ssl", + "type": "boolean" + } + }, + "required": [ + "provider", + "base_url", + "parent_node_id", + "username", + "password", + "apikey" + ], + "title": "SpherePullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "gitlab", + "title": "Provider", + "type": "string" + }, + "repo": { + "description": "GitLab repository in the format 'namespace/project'", + "title": "Repo", + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "main", + "description": "Branch to pull from", + "title": "Branch" + }, + "subdir": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Optional subdirectory to scan files from", + "title": "Subdir" + }, + "token": { + "description": "GitLab private token (from GITLAB_TOKEN env variable)", + "title": "Token", + "type": "string" + }, + "base_url": { + "default": "https://gitlab.com/api/v4", + "description": "GitLab API base URL", + "title": "Base Url", + "type": "string" + } + }, + "required": [ + "provider", + "repo", + "token" + ], + "title": "GitlabPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "minio", + "title": "Provider", + "type": "string" + }, + "endpoint_url": { + "description": "S3-compatible endpoint (e.g., https://s3.amazonaws.com)", + "title": "Endpoint Url", + "type": "string" + }, + "bucket_name": { + "description": "Name of the S3 bucket to scan", + "title": "Bucket Name", + "type": "string" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Optional prefix (folder path) to scan inside the bucket", + "title": "Prefix" + }, + "access_key": { + "description": "MinIO access key (from MINIO_ACCESS_KEY env variable)", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "default": null, + "description": "MinIO secret key (from MINIO_SECRET_KEY env variable)", + "title": "Secret Key", + "type": "string" + }, + "region": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "us-east-1", + "description": "AWS region (used by some clients)", + "title": "Region" + }, + "secure": { + "default": true, + "description": "Use HTTPS (secure=True) or HTTP (secure=False)", + "title": "Secure", + "type": "boolean" + } + }, + "required": [ + "provider", + "endpoint_url", + "bucket_name", + "access_key" + ], + "title": "MinioPullSource", + "type": "object", + "additionalProperties": false + } + ] + }, + "push": "#/$defs/PushSourceConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "push", + "default": "push", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + } + }, + "title": "PushSourceConfig", + "type": "object", + "additionalProperties": false + }, + { + "discriminator": { + "mapping": { + "github": "#/$defs/GitPullSource", + "gitlab": "#/$defs/GitlabPullSource", + "local_path": "#/$defs/FileSystemPullSource", + "minio": "#/$defs/MinioPullSource", + "sphere": "#/$defs/SpherePullSource" + }, + "propertyName": "provider" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "local_path", + "title": "Provider", + "type": "string" + }, + "base_path": { + "title": "Base Path", + "type": "string" + } + }, + "required": [ + "provider", + "base_path" + ], + "title": "FileSystemPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "github", + "title": "Provider", + "type": "string" + }, + "repo": { + "description": "GitHub repository in the format 'owner/repo'", + "title": "Repo", + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "main", + "description": "Git branch to pull from", + "title": "Branch" + }, + "subdir": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Subdirectory to extract files from", + "title": "Subdir" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional GitHub username (for logs)", + "title": "Username" + }, + "token": { + "description": "GitHub token (from GITHUB_TOKEN env variable)", + "title": "Token", + "type": "string" + } + }, + "required": [ + "provider", + "repo", + "token" + ], + "title": "GitPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "sphere", + "title": "Provider", + "type": "string" + }, + "base_url": { + "description": "Base URL for the Sphere API", + "title": "Base Url", + "type": "string" + }, + "parent_node_id": { + "description": "ID of the parent folder or node to list/download", + "title": "Parent Node Id", + "type": "string" + }, + "username": { + "description": "Username for Sphere Basic Auth", + "title": "Username", + "type": "string" + }, + "password": { + "description": "Password (loaded from SPHERE_PASSWORD)", + "title": "Password", + "type": "string" + }, + "apikey": { + "description": "API key (loaded from SPHERE_API_KEY)", + "title": "Apikey", + "type": "string" + }, + "verify_ssl": { + "default": false, + "description": "Set to True to verify SSL certs", + "title": "Verify Ssl", + "type": "boolean" + } + }, + "required": [ + "provider", + "base_url", + "parent_node_id", + "username", + "password", + "apikey" + ], + "title": "SpherePullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "gitlab", + "title": "Provider", + "type": "string" + }, + "repo": { + "description": "GitLab repository in the format 'namespace/project'", + "title": "Repo", + "type": "string" + }, + "branch": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "main", + "description": "Branch to pull from", + "title": "Branch" + }, + "subdir": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Optional subdirectory to scan files from", + "title": "Subdir" + }, + "token": { + "description": "GitLab private token (from GITLAB_TOKEN env variable)", + "title": "Token", + "type": "string" + }, + "base_url": { + "default": "https://gitlab.com/api/v4", + "description": "GitLab API base URL", + "title": "Base Url", + "type": "string" + } + }, + "required": [ + "provider", + "repo", + "token" + ], + "title": "GitlabPullSource", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "pull", + "default": "pull", + "title": "Type", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Human-readable description of this source", + "title": "Description" + }, + "provider": { + "const": "minio", + "title": "Provider", + "type": "string" + }, + "endpoint_url": { + "description": "S3-compatible endpoint (e.g., https://s3.amazonaws.com)", + "title": "Endpoint Url", + "type": "string" + }, + "bucket_name": { + "description": "Name of the S3 bucket to scan", + "title": "Bucket Name", + "type": "string" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "description": "Optional prefix (folder path) to scan inside the bucket", + "title": "Prefix" + }, + "access_key": { + "description": "MinIO access key (from MINIO_ACCESS_KEY env variable)", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "default": null, + "description": "MinIO secret key (from MINIO_SECRET_KEY env variable)", + "title": "Secret Key", + "type": "string" + }, + "region": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "us-east-1", + "description": "AWS region (used by some clients)", + "title": "Region" + }, + "secure": { + "default": true, + "description": "Use HTTPS (secure=True) or HTTP (secure=False)", + "title": "Secure", + "type": "boolean" + } + }, + "required": [ + "provider", + "endpoint_url", + "bucket_name", + "access_key" + ], + "title": "MinioPullSource", + "type": "object", + "additionalProperties": false + } + ] + } + ] + }, + "description": "Mapping of source_tag identifiers to push/pull source configurations", + "title": "Document Sources", + "type": "object" + }, + "storage": { + "properties": { + "postgres": { + "properties": { + "type": { + "const": "postgres", + "default": "postgres", + "title": "Type", + "type": "string" + }, + "host": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "PostgreSQL host", + "title": "Host" + }, + "port": { + "default": 5432, + "title": "Port", + "type": "integer" + }, + "sqlite_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Path to the SQLite database file (for local dev/testing).", + "title": "Sqlite Path" + }, + "database": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Database" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Username" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Password" + }, + "echo": { + "default": false, + "description": "SQLAlchemy echo flag.", + "title": "Echo", + "type": "boolean" + }, + "pool_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional pool size for the engine.", + "title": "Pool Size" + }, + "max_overflow": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional max_overflow for SQLAlchemy pool (defaults to SQLAlchemy's 10 if unset).", + "title": "Max Overflow" + }, + "pool_timeout": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Seconds to wait for a connection from the pool before timing out.", + "title": "Pool Timeout" + }, + "pool_recycle": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Recycle connections after this many seconds (prevents stale TCP / server timeouts).", + "title": "Pool Recycle" + }, + "pool_pre_ping": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Enable SQLAlchemy pool_pre_ping to evict stale connections.", + "title": "Pool Pre Ping" + }, + "connect_args": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional connect_args passed to SQLAlchemy.", + "title": "Connect Args" + } + }, + "title": "PostgresStoreConfig", + "type": "object", + "additionalProperties": false + }, + "opensearch": { + "anyOf": [ + { + "properties": { + "host": { + "description": "OpenSearch host URL", + "title": "Host", + "type": "string" + }, + "username": { + "description": "Username from env", + "title": "Username", + "type": "string" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Password from env", + "title": "Password" + }, + "secure": { + "default": false, + "description": "Use TLS (https)", + "title": "Secure", + "type": "boolean" + }, + "verify_certs": { + "default": false, + "description": "Verify TLS certs", + "title": "Verify Certs", + "type": "boolean" + } + }, + "required": [ + "host", + "username" + ], + "title": "OpenSearchStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional OpenSearch store" + }, + "clickhouse": { + "anyOf": [ + { + "properties": { + "host": { + "default": "localhost", + "description": "ClickHouse host", + "title": "Host", + "type": "string" + }, + "port": { + "default": 8123, + "description": "ClickHouse HTTP port", + "title": "Port", + "type": "integer" + }, + "database": { + "default": "default", + "description": "ClickHouse database", + "title": "Database", + "type": "string" + }, + "username": { + "default": "default", + "description": "ClickHouse username", + "title": "Username", + "type": "string" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "ClickHouse password (from CLICKHOUSE_PASSWORD env)", + "title": "Password" + }, + "secure": { + "default": false, + "description": "Use HTTPS for ClickHouse client", + "title": "Secure", + "type": "boolean" + }, + "verify": { + "default": true, + "description": "Verify TLS certificates for ClickHouse", + "title": "Verify", + "type": "boolean" + } + }, + "title": "ClickHouseStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional ClickHouse store" + }, + "resource_store": { + "discriminator": { + "mapping": { + "duckdb": "#/$defs/DuckdbStoreConfig", + "log": "#/$defs/LogStoreConfig", + "memory": "#/$defs/InMemoryStoreConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "postgres": "#/$defs/PostgresTableConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "duckdb", + "title": "Type", + "type": "string" + }, + "duckdb_path": { + "description": "Path to the DuckDB database file.", + "title": "Duckdb Path", + "type": "string" + } + }, + "required": [ + "type", + "duckdb_path" + ], + "title": "DuckdbStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "log", + "title": "Type", + "type": "string" + }, + "level": { + "description": "Logging level", + "title": "Level", + "type": "string" + } + }, + "required": [ + "type", + "level" + ], + "title": "LogStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "postgres", + "title": "Type", + "type": "string" + }, + "table": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Table name used by the store. Deprecated: stores now use fixed table names.", + "title": "Table" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional prefix applied to the table name. Deprecated: stores now use fixed table names.", + "title": "Prefix" + } + }, + "required": [ + "type" + ], + "title": "PostgresTableConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Minimal config for in-memory stores (dev/test only).", + "properties": { + "type": { + "const": "memory", + "default": "memory", + "title": "Type", + "type": "string" + } + }, + "title": "InMemoryStoreConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Resource Store" + }, + "tag_store": { + "discriminator": { + "mapping": { + "duckdb": "#/$defs/DuckdbStoreConfig", + "log": "#/$defs/LogStoreConfig", + "memory": "#/$defs/InMemoryStoreConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "postgres": "#/$defs/PostgresTableConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "duckdb", + "title": "Type", + "type": "string" + }, + "duckdb_path": { + "description": "Path to the DuckDB database file.", + "title": "Duckdb Path", + "type": "string" + } + }, + "required": [ + "type", + "duckdb_path" + ], + "title": "DuckdbStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "log", + "title": "Type", + "type": "string" + }, + "level": { + "description": "Logging level", + "title": "Level", + "type": "string" + } + }, + "required": [ + "type", + "level" + ], + "title": "LogStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "postgres", + "title": "Type", + "type": "string" + }, + "table": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Table name used by the store. Deprecated: stores now use fixed table names.", + "title": "Table" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional prefix applied to the table name. Deprecated: stores now use fixed table names.", + "title": "Prefix" + } + }, + "required": [ + "type" + ], + "title": "PostgresTableConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Minimal config for in-memory stores (dev/test only).", + "properties": { + "type": { + "const": "memory", + "default": "memory", + "title": "Type", + "type": "string" + } + }, + "title": "InMemoryStoreConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Tag Store" + }, + "kpi_store": { + "discriminator": { + "mapping": { + "duckdb": "#/$defs/DuckdbStoreConfig", + "log": "#/$defs/LogStoreConfig", + "memory": "#/$defs/InMemoryStoreConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "postgres": "#/$defs/PostgresTableConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "duckdb", + "title": "Type", + "type": "string" + }, + "duckdb_path": { + "description": "Path to the DuckDB database file.", + "title": "Duckdb Path", + "type": "string" + } + }, + "required": [ + "type", + "duckdb_path" + ], + "title": "DuckdbStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "log", + "title": "Type", + "type": "string" + }, + "level": { + "description": "Logging level", + "title": "Level", + "type": "string" + } + }, + "required": [ + "type", + "level" + ], + "title": "LogStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "postgres", + "title": "Type", + "type": "string" + }, + "table": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Table name used by the store. Deprecated: stores now use fixed table names.", + "title": "Table" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional prefix applied to the table name. Deprecated: stores now use fixed table names.", + "title": "Prefix" + } + }, + "required": [ + "type" + ], + "title": "PostgresTableConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Minimal config for in-memory stores (dev/test only).", + "properties": { + "type": { + "const": "memory", + "default": "memory", + "title": "Type", + "type": "string" + } + }, + "title": "InMemoryStoreConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Kpi Store" + }, + "metadata_store": { + "discriminator": { + "mapping": { + "duckdb": "#/$defs/DuckdbStoreConfig", + "log": "#/$defs/LogStoreConfig", + "memory": "#/$defs/InMemoryStoreConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "postgres": "#/$defs/PostgresTableConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "duckdb", + "title": "Type", + "type": "string" + }, + "duckdb_path": { + "description": "Path to the DuckDB database file.", + "title": "Duckdb Path", + "type": "string" + } + }, + "required": [ + "type", + "duckdb_path" + ], + "title": "DuckdbStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "log", + "title": "Type", + "type": "string" + }, + "level": { + "description": "Logging level", + "title": "Level", + "type": "string" + } + }, + "required": [ + "type", + "level" + ], + "title": "LogStoreConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "postgres", + "title": "Type", + "type": "string" + }, + "table": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Table name used by the store. Deprecated: stores now use fixed table names.", + "title": "Table" + }, + "prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional prefix applied to the table name. Deprecated: stores now use fixed table names.", + "title": "Prefix" + } + }, + "required": [ + "type" + ], + "title": "PostgresTableConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Minimal config for in-memory stores (dev/test only).", + "properties": { + "type": { + "const": "memory", + "default": "memory", + "title": "Type", + "type": "string" + } + }, + "title": "InMemoryStoreConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Metadata Store" + }, + "tabular_store": { + "description": "Dataset-centric tabular storage settings for the supported tabular runtime.\n\nWhy this exists:\n- CSV ingestion persists one Parquet artifact per document in the shared\n content store.\n- One dedicated config block keeps object keys and query limits explicit.\n\nHow to use:\n- Configure the block directly under `storage.tabular_store`.\n- `artifacts_prefix` namespaces Parquet datasets under the shared\n content-store object area.\n- `format` is intentionally fixed to `parquet`.", + "properties": { + "artifacts_prefix": { + "default": "tabular/datasets", + "description": "Prefix under content_storage objects where Parquet datasets are stored.", + "title": "Artifacts Prefix", + "type": "string" + }, + "format": { + "const": "parquet", + "default": "parquet", + "description": "Physical storage format used for tabular artifacts.", + "title": "Format", + "type": "string" + }, + "compression": { + "default": "snappy", + "description": "Parquet compression codec used when persisting tabular artifacts.", + "title": "Compression", + "type": "string" + }, + "query": { + "description": "Runtime settings for dataset-centric SQL queries.\n\nWhy this exists:\n- Tabular querying now runs on transient Parquet datasets rather than\n long-lived SQL tables.\n- These values keep query execution bounded and configurable from YAML.\n\nHow to use:\n- Keep the default `duckdb` engine.\n- Tune result limits and backend-internal presigned URL TTL per deployment.", + "properties": { + "engine": { + "const": "duckdb", + "default": "duckdb", + "description": "Embedded query engine used to read Parquet datasets.", + "title": "Engine", + "type": "string" + }, + "access_mode": { + "const": "presigned_url", + "default": "presigned_url", + "description": "Primary object-access method for remote tabular artifacts.", + "title": "Access Mode", + "type": "string" + }, + "internal_presigned_ttl_seconds": { + "default": 3600, + "description": "TTL in seconds for backend-internal object-storage URLs used by tabular DuckDB reads.", + "minimum": 1, + "title": "Internal Presigned Ttl Seconds", + "type": "integer" + }, + "default_max_rows": { + "default": 200, + "description": "Default preview row limit applied when callers omit max_rows.", + "minimum": 1, + "title": "Default Max Rows", + "type": "integer" + }, + "max_rows": { + "default": 1000, + "description": "Hard cap applied to query result previews.", + "minimum": 1, + "title": "Max Rows", + "type": "integer" + } + }, + "title": "TabularQueryConfig", + "type": "object", + "additionalProperties": false + } + }, + "title": "TabularStoreConfig", + "type": "object", + "additionalProperties": false + }, + "vector_store": { + "discriminator": { + "mapping": { + "chroma": "#/$defs/ChromaVectorStorageConfig", + "clickhouse": "#/$defs/ClickHouseVectorStorageConfig", + "in_memory": "#/$defs/InMemoryVectorStorage", + "opensearch": "#/$defs/OpenSearchVectorIndexConfig", + "pgvector": "#/$defs/PgVectorStorageConfig", + "weaviate": "#/$defs/WeaviateVectorStorage" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "in_memory", + "title": "Type", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "InMemoryVectorStorage", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + }, + "bulk_size": { + "default": 1000, + "description": "Number of documents to send in each bulk insert request", + "title": "Bulk Size", + "type": "integer" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchVectorIndexConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "Local, embedded Chroma. No server needed.\n- persist_path: folder where Chroma (DuckDB/Parquet) stores data\n- collection_name: logical collection for your chunks\n- distance: ANN space; 'cosine' matches our UI-friendly similarity", + "properties": { + "type": { + "const": "chroma", + "title": "Type", + "type": "string" + }, + "local_path": { + "default": "~/.fred/knowledge-flow/chromadb-vector-store", + "description": "Local vector storage path", + "title": "Local Path", + "type": "string" + }, + "collection_name": { + "default": "fred_chunks", + "description": "Chroma collection name", + "title": "Collection Name", + "type": "string" + }, + "distance": { + "default": "cosine", + "description": "Vector space (affects HNSW metric)", + "enum": [ + "cosine", + "l2", + "ip" + ], + "title": "Distance", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "ChromaVectorStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "weaviate", + "title": "Type", + "type": "string" + }, + "host": { + "default": "https://localhost:8080", + "description": "Weaviate host", + "title": "Host", + "type": "string" + }, + "index_name": { + "default": "CodeDocuments", + "description": "Weaviate class (collection) name", + "title": "Index Name", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WeaviateVectorStorage", + "type": "object", + "additionalProperties": false + }, + { + "description": "PostgreSQL + pgvector backend.\n- Uses shared `storage.postgres` connection settings.\n- Stores vectors in the default pgvector table under a collection name.", + "properties": { + "type": { + "const": "pgvector", + "title": "Type", + "type": "string" + }, + "collection_name": { + "default": "fred_chunks", + "description": "Logical collection name", + "title": "Collection Name", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "PgVectorStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "description": "ClickHouse backend.\n- Uses shared `storage.clickhouse` connection settings.\n- Stores vectors in the configured table.", + "properties": { + "type": { + "const": "clickhouse", + "title": "Type", + "type": "string" + }, + "table": { + "default": "fred_vectors", + "description": "ClickHouse table name for chunks", + "title": "Table", + "type": "string" + }, + "bulk_size": { + "default": 1000, + "description": "Number of rows per insert batch", + "title": "Bulk Size", + "type": "integer" + } + }, + "required": [ + "type" + ], + "title": "ClickHouseVectorStorageConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Vector Store" + }, + "log_store": { + "anyOf": [ + { + "discriminator": { + "mapping": { + "in_memory": "#/$defs/InMemoryLogStorageConfig", + "opensearch": "#/$defs/OpenSearchIndexConfig", + "stdout": "#/$defs/StdoutLogStorageConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "in_memory", + "title": "Type", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "InMemoryLogStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "stdout", + "title": "Type", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "StdoutLogStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "opensearch", + "title": "Type", + "type": "string" + }, + "index": { + "description": "OpenSearch index name", + "title": "Index", + "type": "string" + } + }, + "required": [ + "type", + "index" + ], + "title": "OpenSearchIndexConfig", + "type": "object", + "additionalProperties": false + } + ] + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional log store", + "title": "Log Store" + } + }, + "required": [ + "postgres", + "resource_store", + "tag_store", + "kpi_store", + "metadata_store", + "vector_store" + ], + "title": "StorageConfig", + "type": "object", + "additionalProperties": false + }, + "mcp": { + "description": "Feature toggles for MCP-only HTTP/MCP surfaces.\n\nThese do NOT affect core storage backends (e.g., using OpenSearch\nas vector store or metadata store). They only control whether\noptional monitoring/exploration controllers and their MCP servers\nare exposed.", + "properties": { + "reports_enabled": { + "default": true, + "description": "Expose the Reports MCP server (Markdown-first report generation).", + "title": "Reports Enabled", + "type": "boolean" + }, + "kpi_enabled": { + "default": true, + "description": "Expose the KPI MCP server for querying application KPIs.", + "title": "Kpi Enabled", + "type": "boolean" + }, + "tabular_enabled": { + "default": true, + "description": "Expose the Tabular MCP server for SQL/table exploration.", + "title": "Tabular Enabled", + "type": "boolean" + }, + "statistic_enabled": { + "default": true, + "description": "Expose the Statistical MCP server for data analysis helpers.", + "title": "Statistic Enabled", + "type": "boolean" + }, + "text_enabled": { + "default": true, + "description": "Expose the Text MCP server for semantic vector search.", + "title": "Text Enabled", + "type": "boolean" + }, + "templates_enabled": { + "default": true, + "description": "Expose the Template MCP server for prompts/templates.", + "title": "Templates Enabled", + "type": "boolean" + }, + "resources_enabled": { + "default": true, + "description": "Expose the Resources MCP server for resource/tag management.", + "title": "Resources Enabled", + "type": "boolean" + }, + "opensearch_ops_enabled": { + "default": false, + "description": "Expose OpenSearch operational endpoints and the corresponding MCP server.", + "title": "Opensearch Ops Enabled", + "type": "boolean" + }, + "prometheus_ops_enabled": { + "default": false, + "description": "Expose Prometheus operational endpoints and the corresponding MCP server.", + "title": "Prometheus Ops Enabled", + "type": "boolean" + }, + "neo4j_enabled": { + "default": false, + "description": "Expose Neo4j graph exploration endpoints and the corresponding MCP server.", + "title": "Neo4J Enabled", + "type": "boolean" + }, + "filesystem_enabled": { + "default": false, + "description": "Expose agent filesystem utils endpoints and the corresponding MCP server.", + "title": "Filesystem Enabled", + "type": "boolean" + }, + "filesystem_read_default_limit": { + "default": 100, + "description": "Default line count returned by filesystem read_file when callers omit limit.", + "minimum": 1, + "title": "Filesystem Read Default Limit", + "type": "integer" + }, + "filesystem_read_max_limit": { + "default": 500, + "description": "Absolute maximum line count accepted by filesystem read_file.", + "minimum": 1, + "title": "Filesystem Read Max Limit", + "type": "integer" + }, + "filesystem_read_default_max_chars": { + "default": 20000, + "description": "Default maximum character count returned by filesystem read_file when callers omit max_chars.", + "minimum": 1, + "title": "Filesystem Read Default Max Chars", + "type": "integer" + }, + "filesystem_read_absolute_max_chars": { + "default": 50000, + "description": "Absolute maximum character count accepted by filesystem read_file.", + "minimum": 1, + "title": "Filesystem Read Absolute Max Chars", + "type": "integer" + } + }, + "title": "MCPConfig", + "type": "object", + "additionalProperties": false + }, + "filesystem": { + "description": "Filesystem backend configuration.", + "discriminator": { + "mapping": { + "local": "#/$defs/LocalFilesystemConfig", + "minio": "#/$defs/MinioFilesystemConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "local", + "default": "local", + "title": "Type", + "type": "string" + }, + "root": { + "default": "~/.fred/knowledge-flow/filesystem/", + "description": "Local filesystem root directory.", + "title": "Root", + "type": "string" + } + }, + "title": "LocalFilesystemConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "minio", + "default": "minio", + "title": "Type", + "type": "string" + }, + "endpoint": { + "description": "MinIO or S3 compatible endpoint.", + "title": "Endpoint", + "type": "string" + }, + "access_key": { + "description": "MinIO access key.", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "default": null, + "description": "MinIO secret key (from MINIO_SECRET_KEY env).", + "title": "Secret Key", + "type": "string" + }, + "bucket_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "filesystem", + "description": "MinIO bucket name.", + "title": "Bucket Name" + }, + "secure": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": false, + "description": "Use TLS for the MinIO client.", + "title": "Secure" + } + }, + "required": [ + "endpoint", + "access_key" + ], + "title": "MinioFilesystemConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Filesystem" + }, + "workspace_layout": { + "description": "Configurable storage path layout for workspace storage.\n\nAllowed placeholders:\n {user_id}, {agent_id}, {key}", + "properties": { + "user_pattern": { + "default": "users/{user_id}/{key}", + "description": "Path template for user exchange storage", + "title": "User Pattern", + "type": "string" + }, + "agent_config_pattern": { + "default": "agents/{agent_id}/config/{key}", + "description": "Path template for agent config storage", + "title": "Agent Config Pattern", + "type": "string" + }, + "agent_user_pattern": { + "default": "agents/{agent_id}/users/{user_id}/{key}", + "description": "Path template for per-user agent storage", + "title": "Agent User Pattern", + "type": "string" + } + }, + "title": "WorkspaceLayoutConfig", + "type": "object", + "additionalProperties": false + } + }, + "required": [ + "app", + "chat_model", + "embedding_model", + "security", + "content_storage", + "scheduler", + "storage", + "filesystem" + ], + "title": "Configuration", + "type": "object", + "additionalProperties": false + }, + "dotenv": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "control-plane-backend": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "applicationName": { + "type": "string" + }, + "configurationFileName": { + "type": "string" + }, + "deployment": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "replicaCount": { + "type": "integer" + }, + "statefulset": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "job": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "migration": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "scaleDown": { + "type": "boolean" + }, + "backoffLimit": { + "type": "integer" + }, + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "object" + } + }, + "additionalProperties": false + }, + "rollingUpdate": { + "type": "object", + "properties": { + "maxSurge": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "maxUnavailable": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": false + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "pullPolicy": { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "additionalProperties": false + }, + "command": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "env": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": true + } + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "containerPort": { + "type": "integer" + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "service": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": false + }, + "metricsService": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "interval": { + "type": "string" + }, + "scrapeTimeout": { + "type": "string" + }, + "path": { + "type": "string" + }, + "scheme": { + "type": "string" + }, + "honorLabels": { + "type": "boolean" + }, + "relabelings": { + "type": "array", + "items": {} + }, + "metricRelabelings": { + "type": "array", + "items": {} + }, + "namespaceSelector": { + "type": "object" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "ingress": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "className": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + }, + "service": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "tls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "secretName": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + }, + "volumeMounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "subPath": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + }, + "additionalProperties": true + } + }, + "volumes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "probes": { + "type": "object", + "properties": { + "lifecycle": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "securityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + }, + "add": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "runAsUser": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "rbac": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "permissions": { + "type": "object", + "properties": { + "namespaced": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + }, + "cluster": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "kubeconfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration_type": { + "type": "object", + "properties": { + "backend": { + "type": "boolean" + }, + "frontend": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration": { + "properties": { + "app": { + "properties": { + "name": { + "default": "Control Plane Backend", + "title": "Name", + "type": "string" + }, + "base_url": { + "default": "/control-plane/v1", + "title": "Base Url", + "type": "string" + }, + "address": { + "default": "127.0.0.1", + "title": "Address", + "type": "string" + }, + "port": { + "default": 8222, + "title": "Port", + "type": "integer" + }, + "log_level": { + "default": "info", + "title": "Log Level", + "type": "string" + }, + "gcu_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Gcu Version" + }, + "default_team_max_resources_storage_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Default maximum resources storage size in bytes for a team", + "title": "Default Team Max Resources Storage Size" + }, + "personal_max_resources_storage_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Maximum resources storage size in bytes for a personal space", + "title": "Personal Max Resources Storage Size" + } + }, + "title": "AppConfig", + "type": "object", + "additionalProperties": false + }, + "platform": { + "description": "Control-plane deployment configuration for product/runtime coordination.\n\nContains ONLY infrastructure references (which runtime pods exist).\nManaged agent instance enrollment (which team has which agents) is\nDB-backed and never stored in this deployment config.", + "properties": { + "frontend": { + "description": "Static frontend bootstrap configuration served by control-plane.", + "properties": { + "feature_flags": { + "description": "Typed feature flags exposed to the frontend bootstrap.", + "properties": { + "enableK8Features": { + "default": false, + "title": "Enablek8Features", + "type": "boolean" + }, + "enableElecWarfare": { + "default": false, + "title": "Enableelecwarfare", + "type": "boolean" + } + }, + "title": "FrontendFeatureFlags", + "type": "object", + "additionalProperties": false + }, + "ui_settings": { + "description": "Small typed UI settings surface owned by control-plane.", + "properties": { + "siteDisplayName": { + "default": "Fred", + "title": "Sitedisplayname", + "type": "string" + }, + "agentsNicknameSingular": { + "default": "agent", + "title": "Agentsnicknamesingular", + "type": "string" + }, + "agentsNicknamePlural": { + "default": "agents", + "title": "Agentsnicknameplural", + "type": "string" + } + }, + "title": "FrontendUiSettings", + "type": "object", + "additionalProperties": false + } + }, + "title": "FrontendBootstrapConfig", + "type": "object", + "additionalProperties": false + }, + "runtime_catalog_sources": { + "items": { + "description": "Configured runtime endpoint used for read-only template aggregation.", + "properties": { + "runtime_id": { + "minLength": 1, + "title": "Runtime Id", + "type": "string" + }, + "base_url": { + "minLength": 1, + "title": "Base Url", + "type": "string" + }, + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "ingress_prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Ingress-relative URL prefix for browser-facing runtime access, e.g. /runtime/agents-v2. Required for execution preparation. MUST NOT be a cluster-internal hostname or pod IP.", + "title": "Ingress Prefix" + } + }, + "required": [ + "runtime_id", + "base_url" + ], + "title": "RuntimeCatalogSourceConfig", + "type": "object", + "additionalProperties": false + }, + "title": "Runtime Catalog Sources", + "type": "array" + } + }, + "title": "PlatformConfig", + "type": "object", + "additionalProperties": false + }, + "scheduler": { + "properties": { + "enabled": { + "default": false, + "title": "Enabled", + "type": "boolean" + }, + "backend": { + "description": "Allowed scheduler backend values across Fred backends.\n\nWhy this exists:\n- Avoid raw string literals (`\"temporal\"`, `\"memory\"`) spread in business code.\n- Keep one typed source of truth used by configuration parsing and runtime checks.\n\nHow to use:\n```python\nfrom fred_core.scheduler import SchedulerBackend\n\nif backend == SchedulerBackend.MEMORY:\n ...\n```", + "enum": [ + "temporal", + "memory" + ], + "title": "SchedulerBackend", + "type": "string" + }, + "temporal": { + "properties": { + "host": { + "default": "localhost:7233", + "title": "Host", + "type": "string" + }, + "namespace": { + "default": "default", + "title": "Namespace", + "type": "string" + }, + "task_queue": { + "default": "default", + "title": "Task Queue", + "type": "string" + }, + "workflow_id_prefix": { + "default": "task", + "title": "Workflow Id Prefix", + "type": "string" + }, + "connect_timeout_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 5, + "title": "Connect Timeout Seconds" + }, + "ingestion_workflow_parallelism": { + "default": 3, + "description": "Max number of files launched in parallel per parent ingestion workflow.", + "minimum": 1, + "title": "Ingestion Workflow Parallelism", + "type": "integer" + }, + "ingestion_max_concurrent_workflow_tasks": { + "default": 3, + "description": "Max concurrent Temporal workflow tasks processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Workflow Tasks", + "type": "integer" + }, + "ingestion_max_concurrent_activities": { + "default": 3, + "description": "Max concurrent Temporal activities processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Activities", + "type": "integer" + } + }, + "title": "TemporalSchedulerConfig", + "type": "object", + "additionalProperties": false + } + }, + "title": "SchedulerConfig", + "type": "object", + "additionalProperties": false + }, + "security": { + "properties": { + "m2m": { + "description": "Configuration for machine-to-machine authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + }, + "audience": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Audience" + }, + "secret_env_var": { + "default": "M2M_CLIENT_SECRET", + "title": "Secret Env Var", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "M2MSecurity", + "type": "object", + "additionalProperties": false + }, + "user": { + "description": "Configuration for user authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "UserSecurity", + "type": "object", + "additionalProperties": false + }, + "authorized_origins": { + "default": [], + "items": { + "format": "uri", + "minLength": 1, + "type": "string" + }, + "title": "Authorized Origins", + "type": "array" + }, + "rebac": { + "anyOf": [ + { + "discriminator": { + "mapping": { + "openfga": "#/$defs/OpenFgaRebacConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "description": "Configuration for an OpenFGA-backed relationship engine.", + "properties": { + "enabled": { + "default": true, + "description": "To disable ReBAC checks (do not disable in production). If OIDC (UserSecurity and M2MSecurity) ReBAC check will be disabled even if this is true.", + "title": "Enabled", + "type": "boolean" + }, + "type": { + "const": "openfga", + "default": "openfga", + "title": "Type", + "type": "string" + }, + "api_url": { + "description": "Base URL for the OpenFGA HTTP API (e.g. https://fga.example.com)", + "format": "uri", + "minLength": 1, + "title": "Api Url", + "type": "string" + }, + "store_name": { + "default": "fred", + "description": "Name of the OpenFGA store to use", + "title": "Store Name", + "type": "string" + }, + "authorization_model_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional authorization model ID to use for read operations. Will be overridden if sync_schema_on_init is True.", + "title": "Authorization Model Id" + }, + "create_store_if_needed": { + "default": true, + "description": "Create the OpenFGA store if it does not already exist", + "title": "Create Store If Needed", + "type": "boolean" + }, + "sync_schema_on_init": { + "default": true, + "description": "Synchronize the authorization model when creating the engine", + "title": "Sync Schema On Init", + "type": "boolean" + }, + "token_env_var": { + "default": "OPENFGA_API_TOKEN", + "description": "Environment variable that stores the OpenFGA API token", + "title": "Token Env Var", + "type": "string" + }, + "timeout_millisec": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional timeout in milliseconds for OpenFGA API requests", + "title": "Timeout Millisec" + }, + "headers": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Static HTTP headers to send with each OpenFGA API request", + "title": "Headers" + } + }, + "required": [ + "api_url" + ], + "title": "OpenFgaRebacConfig", + "type": "object", + "additionalProperties": false + } + ] + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rebac" + } + }, + "required": [ + "m2m", + "user" + ], + "title": "SecurityConfiguration", + "type": "object", + "additionalProperties": false + }, + "storage": { + "properties": { + "postgres": { + "properties": { + "type": { + "const": "postgres", + "default": "postgres", + "title": "Type", + "type": "string" + }, + "host": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "PostgreSQL host", + "title": "Host" + }, + "port": { + "default": 5432, + "title": "Port", + "type": "integer" + }, + "sqlite_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Path to the SQLite database file (for local dev/testing).", + "title": "Sqlite Path" + }, + "database": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Database" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Username" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Password" + }, + "echo": { + "default": false, + "description": "SQLAlchemy echo flag.", + "title": "Echo", + "type": "boolean" + }, + "pool_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional pool size for the engine.", + "title": "Pool Size" + }, + "max_overflow": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional max_overflow for SQLAlchemy pool (defaults to SQLAlchemy's 10 if unset).", + "title": "Max Overflow" + }, + "pool_timeout": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Seconds to wait for a connection from the pool before timing out.", + "title": "Pool Timeout" + }, + "pool_recycle": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Recycle connections after this many seconds (prevents stale TCP / server timeouts).", + "title": "Pool Recycle" + }, + "pool_pre_ping": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Enable SQLAlchemy pool_pre_ping to evict stale connections.", + "title": "Pool Pre Ping" + }, + "connect_args": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional connect_args passed to SQLAlchemy.", + "title": "Connect Args" + } + }, + "title": "PostgresStoreConfig", + "type": "object", + "additionalProperties": false + }, + "content_storage": { + "discriminator": { + "mapping": { + "local": "#/$defs/LocalContentStorageConfig", + "minio": "#/$defs/MinioContentStorageConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "local", + "default": "local", + "title": "Type", + "type": "string" + }, + "root_path": { + "default": "~/.fred/control-plane/content-storage", + "description": "Local storage directory", + "title": "Root Path", + "type": "string" + } + }, + "title": "LocalContentStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "minio", + "title": "Type", + "type": "string" + }, + "endpoint": { + "default": "http://localhost:9000", + "description": "MinIO API URL", + "title": "Endpoint", + "type": "string" + }, + "access_key": { + "description": "MinIO access key", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "MinIO secret key (from MINIO_SECRET_KEY env by default)", + "title": "Secret Key" + }, + "bucket_name": { + "default": "control-plane-content", + "description": "Content store bucket name (suffix '-objects' is used for banner objects)", + "title": "Bucket Name", + "type": "string" + }, + "secure": { + "default": false, + "description": "Use TLS (https)", + "title": "Secure", + "type": "boolean" + }, + "public_endpoint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional public endpoint used to generate browser-facing presigned URLs", + "title": "Public Endpoint" + }, + "public_secure": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional TLS override for public endpoint (auto-inferred when omitted)", + "title": "Public Secure" + } + }, + "required": [ + "type", + "access_key" + ], + "title": "MinioContentStorageConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Content Storage" + } + }, + "title": "StorageConfig", + "type": "object", + "additionalProperties": false + }, + "policies": { + "properties": { + "purge_catalog_path": { + "default": "./conversation_policy_catalog.yaml", + "title": "Purge Catalog Path", + "type": "string" + } + }, + "title": "PolicyConfig", + "type": "object", + "additionalProperties": false + } + }, + "required": [ + "app", + "scheduler" + ], + "title": "Configuration", + "type": "object", + "additionalProperties": false + }, + "conversation_policy_catalog": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "conversation_policies": { + "type": "object", + "properties": { + "purge": { + "type": "object", + "properties": { + "default": { + "type": "object", + "properties": { + "mode": { + "type": "string" + }, + "retention": { + "type": "string" + }, + "cancel_on_rejoin": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "rule_id": { + "type": "string" + }, + "match": { + "type": "object", + "properties": { + "team_id": { + "type": "string" + }, + "trigger": { + "type": "string" + } + }, + "additionalProperties": true + }, + "action": { + "type": "object", + "properties": { + "retention": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "dotenv": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "control-plane-worker": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "applicationName": { + "type": "string" + }, + "configurationFileName": { + "type": "string" + }, + "deployment": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "replicaCount": { + "type": "integer" + }, + "statefulset": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "job": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "migration": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "scaleDown": { + "type": "boolean" + }, + "backoffLimit": { + "type": "integer" + }, + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "object" + } + }, + "additionalProperties": false + }, + "rollingUpdate": { + "type": "object", + "properties": { + "maxSurge": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "maxUnavailable": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": false + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "pullPolicy": { + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "additionalProperties": false + }, + "command": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "env": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": true + } + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "containerPort": { + "type": "integer" + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "service": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": false + }, + "metricsService": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "type": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "interval": { + "type": "string" + }, + "scrapeTimeout": { + "type": "string" + }, + "path": { + "type": "string" + }, + "scheme": { + "type": "string" + }, + "honorLabels": { + "type": "boolean" + }, + "relabelings": { + "type": "array", + "items": {} + }, + "metricRelabelings": { + "type": "array", + "items": {} + }, + "namespaceSelector": { + "type": "object" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "ingress": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "className": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string" + }, + "service": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + } + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "tls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "secretName": { + "type": "string" + }, + "hosts": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + }, + "volumeMounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mountPath": { + "type": "string" + }, + "subPath": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + }, + "additionalProperties": true + } + }, + "volumes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "probes": { + "type": "object", + "properties": { + "lifecycle": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": true + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "securityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + }, + "add": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "runAsUser": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "rbac": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "permissions": { + "type": "object", + "properties": { + "namespaced": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + }, + "cluster": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiGroups": { + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "kubeconfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration_type": { + "type": "object", + "properties": { + "backend": { + "type": "boolean" + }, + "frontend": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "configuration": { + "properties": { + "app": { + "properties": { + "name": { + "default": "Control Plane Backend", + "title": "Name", + "type": "string" + }, + "base_url": { + "default": "/control-plane/v1", + "title": "Base Url", + "type": "string" + }, + "address": { + "default": "127.0.0.1", + "title": "Address", + "type": "string" + }, + "port": { + "default": 8222, + "title": "Port", + "type": "integer" + }, + "log_level": { + "default": "info", + "title": "Log Level", + "type": "string" + }, + "gcu_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Gcu Version" + }, + "default_team_max_resources_storage_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Default maximum resources storage size in bytes for a team", + "title": "Default Team Max Resources Storage Size" + }, + "personal_max_resources_storage_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Maximum resources storage size in bytes for a personal space", + "title": "Personal Max Resources Storage Size" + } + }, + "title": "AppConfig", + "type": "object", + "additionalProperties": false + }, + "platform": { + "description": "Control-plane deployment configuration for product/runtime coordination.\n\nContains ONLY infrastructure references (which runtime pods exist).\nManaged agent instance enrollment (which team has which agents) is\nDB-backed and never stored in this deployment config.", + "properties": { + "frontend": { + "description": "Static frontend bootstrap configuration served by control-plane.", + "properties": { + "feature_flags": { + "description": "Typed feature flags exposed to the frontend bootstrap.", + "properties": { + "enableK8Features": { + "default": false, + "title": "Enablek8Features", + "type": "boolean" + }, + "enableElecWarfare": { + "default": false, + "title": "Enableelecwarfare", + "type": "boolean" + } + }, + "title": "FrontendFeatureFlags", + "type": "object", + "additionalProperties": false + }, + "ui_settings": { + "description": "Small typed UI settings surface owned by control-plane.", + "properties": { + "siteDisplayName": { + "default": "Fred", + "title": "Sitedisplayname", + "type": "string" + }, + "agentsNicknameSingular": { + "default": "agent", + "title": "Agentsnicknamesingular", + "type": "string" + }, + "agentsNicknamePlural": { + "default": "agents", + "title": "Agentsnicknameplural", + "type": "string" + } + }, + "title": "FrontendUiSettings", + "type": "object", + "additionalProperties": false + } + }, + "title": "FrontendBootstrapConfig", + "type": "object", + "additionalProperties": false + }, + "runtime_catalog_sources": { + "items": { + "description": "Configured runtime endpoint used for read-only template aggregation.", + "properties": { + "runtime_id": { + "minLength": 1, + "title": "Runtime Id", + "type": "string" + }, + "base_url": { + "minLength": 1, + "title": "Base Url", + "type": "string" + }, + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "ingress_prefix": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Ingress-relative URL prefix for browser-facing runtime access, e.g. /runtime/agents-v2. Required for execution preparation. MUST NOT be a cluster-internal hostname or pod IP.", + "title": "Ingress Prefix" + } + }, + "required": [ + "runtime_id", + "base_url" + ], + "title": "RuntimeCatalogSourceConfig", + "type": "object", + "additionalProperties": false + }, + "title": "Runtime Catalog Sources", + "type": "array" + } + }, + "title": "PlatformConfig", + "type": "object", + "additionalProperties": false + }, + "scheduler": { + "properties": { + "enabled": { + "default": false, + "title": "Enabled", + "type": "boolean" + }, + "backend": { + "description": "Allowed scheduler backend values across Fred backends.\n\nWhy this exists:\n- Avoid raw string literals (`\"temporal\"`, `\"memory\"`) spread in business code.\n- Keep one typed source of truth used by configuration parsing and runtime checks.\n\nHow to use:\n```python\nfrom fred_core.scheduler import SchedulerBackend\n\nif backend == SchedulerBackend.MEMORY:\n ...\n```", + "enum": [ + "temporal", + "memory" + ], + "title": "SchedulerBackend", + "type": "string" + }, + "temporal": { + "properties": { + "host": { + "default": "localhost:7233", + "title": "Host", + "type": "string" + }, + "namespace": { + "default": "default", + "title": "Namespace", + "type": "string" + }, + "task_queue": { + "default": "default", + "title": "Task Queue", + "type": "string" + }, + "workflow_id_prefix": { + "default": "task", + "title": "Workflow Id Prefix", + "type": "string" + }, + "connect_timeout_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 5, + "title": "Connect Timeout Seconds" + }, + "ingestion_workflow_parallelism": { + "default": 3, + "description": "Max number of files launched in parallel per parent ingestion workflow.", + "minimum": 1, + "title": "Ingestion Workflow Parallelism", + "type": "integer" + }, + "ingestion_max_concurrent_workflow_tasks": { + "default": 3, + "description": "Max concurrent Temporal workflow tasks processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Workflow Tasks", + "type": "integer" + }, + "ingestion_max_concurrent_activities": { + "default": 3, + "description": "Max concurrent Temporal activities processed by a worker process.", + "minimum": 1, + "title": "Ingestion Max Concurrent Activities", + "type": "integer" + } + }, + "title": "TemporalSchedulerConfig", + "type": "object", + "additionalProperties": false + } + }, + "title": "SchedulerConfig", + "type": "object", + "additionalProperties": false + }, + "security": { + "properties": { + "m2m": { + "description": "Configuration for machine-to-machine authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + }, + "audience": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Audience" + }, + "secret_env_var": { + "default": "M2M_CLIENT_SECRET", + "title": "Secret Env Var", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "M2MSecurity", + "type": "object", + "additionalProperties": false + }, + "user": { + "description": "Configuration for user authentication.", + "properties": { + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "realm_url": { + "format": "uri", + "minLength": 1, + "title": "Realm Url", + "type": "string" + }, + "client_id": { + "title": "Client Id", + "type": "string" + } + }, + "required": [ + "realm_url", + "client_id" + ], + "title": "UserSecurity", + "type": "object", + "additionalProperties": false + }, + "authorized_origins": { + "default": [], + "items": { + "format": "uri", + "minLength": 1, + "type": "string" + }, + "title": "Authorized Origins", + "type": "array" + }, + "rebac": { + "anyOf": [ + { + "discriminator": { + "mapping": { + "openfga": "#/$defs/OpenFgaRebacConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "description": "Configuration for an OpenFGA-backed relationship engine.", + "properties": { + "enabled": { + "default": true, + "description": "To disable ReBAC checks (do not disable in production). If OIDC (UserSecurity and M2MSecurity) ReBAC check will be disabled even if this is true.", + "title": "Enabled", + "type": "boolean" + }, + "type": { + "const": "openfga", + "default": "openfga", + "title": "Type", + "type": "string" + }, + "api_url": { + "description": "Base URL for the OpenFGA HTTP API (e.g. https://fga.example.com)", + "format": "uri", + "minLength": 1, + "title": "Api Url", + "type": "string" + }, + "store_name": { + "default": "fred", + "description": "Name of the OpenFGA store to use", + "title": "Store Name", + "type": "string" + }, + "authorization_model_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional authorization model ID to use for read operations. Will be overridden if sync_schema_on_init is True.", + "title": "Authorization Model Id" + }, + "create_store_if_needed": { + "default": true, + "description": "Create the OpenFGA store if it does not already exist", + "title": "Create Store If Needed", + "type": "boolean" + }, + "sync_schema_on_init": { + "default": true, + "description": "Synchronize the authorization model when creating the engine", + "title": "Sync Schema On Init", + "type": "boolean" + }, + "token_env_var": { + "default": "OPENFGA_API_TOKEN", + "description": "Environment variable that stores the OpenFGA API token", + "title": "Token Env Var", + "type": "string" + }, + "timeout_millisec": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional timeout in milliseconds for OpenFGA API requests", + "title": "Timeout Millisec" + }, + "headers": { + "anyOf": [ + { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Static HTTP headers to send with each OpenFGA API request", + "title": "Headers" + } + }, + "required": [ + "api_url" + ], + "title": "OpenFgaRebacConfig", + "type": "object", + "additionalProperties": false + } + ] + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rebac" + } + }, + "required": [ + "m2m", + "user" + ], + "title": "SecurityConfiguration", + "type": "object", + "additionalProperties": false + }, + "storage": { + "properties": { + "postgres": { + "properties": { + "type": { + "const": "postgres", + "default": "postgres", + "title": "Type", + "type": "string" + }, + "host": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "PostgreSQL host", + "title": "Host" + }, + "port": { + "default": 5432, + "title": "Port", + "type": "integer" + }, + "sqlite_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Path to the SQLite database file (for local dev/testing).", + "title": "Sqlite Path" + }, + "database": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Database" + }, + "username": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Username" + }, + "password": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Password" + }, + "echo": { + "default": false, + "description": "SQLAlchemy echo flag.", + "title": "Echo", + "type": "boolean" + }, + "pool_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional pool size for the engine.", + "title": "Pool Size" + }, + "max_overflow": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional max_overflow for SQLAlchemy pool (defaults to SQLAlchemy's 10 if unset).", + "title": "Max Overflow" + }, + "pool_timeout": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Seconds to wait for a connection from the pool before timing out.", + "title": "Pool Timeout" + }, + "pool_recycle": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Recycle connections after this many seconds (prevents stale TCP / server timeouts).", + "title": "Pool Recycle" + }, + "pool_pre_ping": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Enable SQLAlchemy pool_pre_ping to evict stale connections.", + "title": "Pool Pre Ping" + }, + "connect_args": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional connect_args passed to SQLAlchemy.", + "title": "Connect Args" + } + }, + "title": "PostgresStoreConfig", + "type": "object", + "additionalProperties": false + }, + "content_storage": { + "discriminator": { + "mapping": { + "local": "#/$defs/LocalContentStorageConfig", + "minio": "#/$defs/MinioContentStorageConfig" + }, + "propertyName": "type" + }, + "oneOf": [ + { + "properties": { + "type": { + "const": "local", + "default": "local", + "title": "Type", + "type": "string" + }, + "root_path": { + "default": "~/.fred/control-plane/content-storage", + "description": "Local storage directory", + "title": "Root Path", + "type": "string" + } + }, + "title": "LocalContentStorageConfig", + "type": "object", + "additionalProperties": false + }, + { + "properties": { + "type": { + "const": "minio", + "title": "Type", + "type": "string" + }, + "endpoint": { + "default": "http://localhost:9000", + "description": "MinIO API URL", + "title": "Endpoint", + "type": "string" + }, + "access_key": { + "description": "MinIO access key", + "title": "Access Key", + "type": "string" + }, + "secret_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "MinIO secret key (from MINIO_SECRET_KEY env by default)", + "title": "Secret Key" + }, + "bucket_name": { + "default": "control-plane-content", + "description": "Content store bucket name (suffix '-objects' is used for banner objects)", + "title": "Bucket Name", + "type": "string" + }, + "secure": { + "default": false, + "description": "Use TLS (https)", + "title": "Secure", + "type": "boolean" + }, + "public_endpoint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional public endpoint used to generate browser-facing presigned URLs", + "title": "Public Endpoint" + }, + "public_secure": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional TLS override for public endpoint (auto-inferred when omitted)", + "title": "Public Secure" + } + }, + "required": [ + "type", + "access_key" + ], + "title": "MinioContentStorageConfig", + "type": "object", + "additionalProperties": false + } + ], + "title": "Content Storage" + } + }, + "title": "StorageConfig", + "type": "object", + "additionalProperties": false + }, + "policies": { + "properties": { + "purge_catalog_path": { + "default": "./conversation_policy_catalog.yaml", + "title": "Purge Catalog Path", + "type": "string" + } + }, + "title": "PolicyConfig", + "type": "object", + "additionalProperties": false + } + }, + "required": [ + "app", + "scheduler" + ], + "title": "Configuration", + "type": "object", + "additionalProperties": false + }, + "dotenv": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + } +} diff --git a/deploy/charts/fred/values.yaml b/deploy/charts/fred/values.yaml index c3f5975f33..63c788c386 100644 --- a/deploy/charts/fred/values.yaml +++ b/deploy/charts/fred/values.yaml @@ -2,7 +2,7 @@ # Fred Helm Chart — Default Values # # QUICK-START: the ~15 values to customize for a new deployment: -# 1. Domain : replace "{YOUR-URL}" with your hostname +# 1. Domain : replace "your.host" with your actual hostname # 2. API Keys : applications.*.dotenv.OPENAI_API_KEY (or AZURE_OPENAI_API_KEY) # 3. Auth : applications.*.configuration.security.*.realm_url (Keycloak URL) # 4. Temporal : applications.knowledge-flow-backend.configuration.scheduler.temporal.host @@ -211,14 +211,14 @@ x-kf-security: &kf-security m2m: enabled: true client_id: "knowledge-flow" - realm_url: "http://{YOUR-URL}/{YOUR-REALM/app" + realm_url: "http://your.keycloak.host/realms/your-realm/app" secret_env_var: KEYCLOAK_KNOWLEDGE_FLOW_CLIENT_SECRET user: enabled: true client_id: "app" - realm_url: "http://{YOUR-URL}/{YOUR-REALM/app" + realm_url: "http://your.keycloak.host/realms/your-realm/app" authorized_origins: - - "http://{YOUR-URL}:80" + - "http://your.host:80" rebac: enabled: true # Set false to bypass ReBAC (warning: all private resources will become public) type: openfga @@ -268,9 +268,8 @@ x-kf-document-sources: &kf-document-sources x-kf-embedding-model: &kf-embedding-model provider: openai # CUSTOMIZE: openai | azure | ollama - name: text-embedding-3-large + name: text-embedding-3-large settings: {} - type: "openai" x-kf-chat-model: &kf-chat-model provider: openai # CUSTOMIZE: openai | azure | ollama @@ -294,22 +293,16 @@ x-kf-crossencoder-model: &kf-crossencoder-model local_path: /home/fred-user/.cache/huggingface/hub x-kf-storage: &kf-storage - postgres: + postgres: host: localhost port: 5432 database: fred username: admin - opensearch: + opensearch: host: https://localhost:9200 secure: true verify_certs: false username: admin - catalog_store: - type: "duckdb" - duckdb_path: "/home/fred-user/.fred/knowledge-flow/catalog.duckdb" - prompt_store: - type: "duckdb" - duckdb_path: "/home/fred-user/.fred/knowledge-flow/prompt.duckdb" resource_store: type: "duckdb" duckdb_path: "/home/fred-user/.fred/knowledge-flow/resource.duckdb" @@ -324,10 +317,6 @@ x-kf-storage: &kf-storage metadata_store: type: "duckdb" duckdb_path: "/home/fred-user/.fred/knowledge-flow/metadata.duckdb" - task_store: - type: "postgres" - table: workflow_tasks - prefix: "sched_" vector_store: type: in_memory tabular_store: @@ -368,14 +357,14 @@ x-cp-security: &cp-security m2m: enabled: true client_id: "control-plane" - realm_url: "http://{YOUR-URL}/{YOUR-REALM/app" + realm_url: "http://your.keycloak.host/realms/your-realm/app" secret_env_var: KEYCLOAK_CONTROL_PLANE_CLIENT_SECRET user: enabled: true client_id: "app" - realm_url: "http://{YOUR-URL}/{YOUR-REALM/app" + realm_url: "http://your.keycloak.host/realms/your-realm/app" authorized_origins: - - "http://{YOUR-URL}:80" + - "http://your.host:80" rebac: enabled: true type: openfga @@ -604,14 +593,14 @@ applications: m2m: enabled: true client_id: "agentic" - realm_url: "http://{YOUR-URL}/{YOUR-REALM/app" + realm_url: "http://your.keycloak.host/realms/your-realm/app" secret_env_var: KEYCLOAK_AGENTIC_CLIENT_SECRET user: enabled: true client_id: "app" - realm_url: "http://{YOUR-URL}/{YOUR-REALM/app" + realm_url: "http://your.keycloak.host/realms/your-realm/app" authorized_origins: - - "http://{YOUR-URL}:80" + - "http://your.host:80" rebac: enabled: true # Set false to bypass ReBAC (warning: all private resources will become public) type: openfga @@ -970,7 +959,7 @@ applications: enabled: true className: "nginx" hosts: - - host: {YOUR-URL} + - host: your.host paths: - path: / pathType: Prefix @@ -990,7 +979,7 @@ applications: tls: - secretName: frontend-crt hosts: - - {YOUR-URL} + - your.host volumeMounts: - name: frontend-config-vol mountPath: /usr/share/nginx/html/config.json @@ -1068,7 +1057,7 @@ applications: maxUnavailable: 0 image: repository: ghcr.io/thalesgroup/fred-agent/knowledge-flow-backend - tag: "" + tag: "" command: enabled: true data: @@ -1228,7 +1217,7 @@ applications: filesystem: *kf-filesystem # ── Sensitive environment variables (rendered as Kubernetes Secret) ──── - dotenv: + dotenv: KEYCLOAK_KNOWLEDGE_FLOW_CLIENT_SECRET: "" MINIO_SECRET_KEY: "" OPENAI_API_KEY: "" @@ -1258,7 +1247,7 @@ applications: maxUnavailable: 0 image: repository: ghcr.io/thalesgroup/fred-agent/knowledge-flow-backend - tag: "" + tag: "" command: enabled: true data: diff --git a/scripts/check_chart_values.py b/scripts/check_chart_values.py new file mode 100644 index 0000000000..e782cd5bb2 --- /dev/null +++ b/scripts/check_chart_values.py @@ -0,0 +1,79 @@ +# /// script +# dependencies = [ +# "jsonschema>=4.0,<5", +# "pyyaml>=6.0", +# ] +# /// +"""Validate deploy/charts/fred/values.yaml against values.schema.json. + +Helm resolves YAML anchors and strips x-* keys before schema validation. +This script replicates that behaviour so the check is faithful to what +`helm lint` would see. + +Usage: + python check_chart_values.py + +Exit code: 0 if valid, 1 if invalid. +""" + +import argparse +import json +import sys +from pathlib import Path + +import yaml + + +def _load_json(path: Path) -> dict: + with open(path) as f: + return json.load(f) + + +def _load_yaml(path: Path) -> object: + with open(path) as f: + return yaml.safe_load(f) + + +def _strip_helm_anchors(values: object) -> object: + """Remove top-level x-* keys that are YAML anchors, not real values.""" + if isinstance(values, dict): + return {k: v for k, v in values.items() if not str(k).startswith("x-")} + return values + + +def _validate(instance: object, schema: dict) -> list[str]: + from jsonschema import Draft7Validator + + validator = Draft7Validator(schema) + errors = sorted(validator.iter_errors(instance), key=lambda e: list(e.absolute_path)) + return [ + f" [{'.'.join(str(p) for p in e.absolute_path) or ''}] {e.message}" + for e in errors + ] + + +def main() -> None: + parser = argparse.ArgumentParser(description="Validate Helm values.yaml against values.schema.json") + parser.add_argument("schema", help="Path to values.schema.json") + parser.add_argument("values", help="Path to values.yaml") + args = parser.parse_args() + + schema = _load_json(Path(args.schema)) + raw = _load_yaml(Path(args.values)) + values = _strip_helm_anchors(raw) + + errors = _validate(values, schema) + + if errors: + print(f"FAIL {args.values}") + for err in errors: + print(err) + print("\nValues validation failed. Fix the errors above or update the schema.") + sys.exit(1) + + print(f"OK {args.values}") + print("\nValues file is valid.") + + +if __name__ == "__main__": + main() diff --git a/scripts/generate_chart_schema.py b/scripts/generate_chart_schema.py new file mode 100644 index 0000000000..15cf88a9ab --- /dev/null +++ b/scripts/generate_chart_schema.py @@ -0,0 +1,468 @@ +# /// script +# dependencies = [] +# /// +"""Generate values.schema.json for the Fred Helm chart. + +Inlines the three backend configuration JSON schemas (already generated by +generate_config_schema.py) into the correct positions of a hand-written +chart-level schema. The result is a single self-contained JSON Schema +(draft-07, no $ref) that Helm and IDE plugins can use for validation and +autocompletion. + +Usage (called automatically by python-config-schema.mk): + python scripts/generate_chart_schema.py \\ + --fred-agents apps/fred-agents/config/schema/configuration.schema.json \\ + --knowledge-flow apps/knowledge-flow-backend/config/schema/configuration.schema.json \\ + --control-plane apps/control-plane-backend/config/schema/configuration.schema.json \\ + --output deploy/charts/fred/values.schema.json +""" + +import argparse +import copy +import json +import sys +from pathlib import Path + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +def _load(path: Path) -> dict: + with open(path) as f: + return json.load(f) + + +def _inline_refs(schema: dict) -> dict: + """Resolve all $ref pointers within a self-contained schema that uses $defs. + + Uses a `seen` set to break cycles: if a definition is currently being + expanded, replace the back-reference with an empty object rather than + looping indefinitely. + """ + schema = copy.deepcopy(schema) + defs = schema.get("$defs", {}) + + def _resolve(node: object, seen: frozenset[str] = frozenset()) -> object: + if isinstance(node, dict): + if "$ref" in node: + ref = node["$ref"] + if ref.startswith("#/$defs/"): + name = ref[len("#/$defs/"):] + if name in seen: + return {} # cycle guard: emit empty object + return _resolve(copy.deepcopy(defs[name]), seen | {name}) + return node + return {k: _resolve(v, seen) for k, v in node.items() if k != "$defs"} + if isinstance(node, list): + return [_resolve(i, seen) for i in node] + return node + + resolved = _resolve(schema) + resolved.pop("$defs", None) + return resolved + + +# --------------------------------------------------------------------------- +# Shared Kubernetes / Helm sub-schemas +# --------------------------------------------------------------------------- + +_STRING = {"type": "string"} +_BOOL = {"type": "boolean"} +_INT = {"type": "integer"} +_OBJECT_FREE = {"type": "object"} # used only where the shape is truly open (annotations, labels) +_ANY = {} + + +def _obj(props: dict, required: list[str] | None = None, additional: bool = False) -> dict: + s: dict = {"type": "object", "properties": props, "additionalProperties": additional} + if required: + s["required"] = required + return s + + +def _arr(items: dict) -> dict: + return {"type": "array", "items": items} + + +# ── Kubernetes primitives ──────────────────────────────────────────────────── + +_IMAGE = _obj({ + "repository": _STRING, + "tag": _STRING, + "pullPolicy": {"type": "string", "enum": ["Always", "IfNotPresent", "Never"]}, +}) + +_ROLLING_UPDATE = _obj({ + "maxSurge": {"anyOf": [_INT, _STRING]}, + "maxUnavailable": {"anyOf": [_INT, _STRING]}, +}) + +_PORT_DEF = _obj({ + "name": _STRING, + "containerPort": _INT, + "protocol": _STRING, +}, additional=True) + +_SERVICE_PORT = _obj({ + "name": _STRING, + "port": _INT, + "targetPort": {"anyOf": [_INT, _STRING]}, + "protocol": _STRING, +}, additional=True) + +_SERVICE_MONITOR = _obj({ + "enabled": _BOOL, + "annotations": _OBJECT_FREE, + "labels": _OBJECT_FREE, + "interval": _STRING, + "scrapeTimeout": _STRING, + "path": _STRING, + "scheme": _STRING, + "honorLabels": _BOOL, + "relabelings": _arr(_ANY), + "metricRelabelings": _arr(_ANY), + "namespaceSelector": _OBJECT_FREE, +}) + +_SERVICE = _obj({ + "enabled": _BOOL, + "annotations": _OBJECT_FREE, + "extraLabels": _OBJECT_FREE, + "type": _STRING, + "ports": _arr(_SERVICE_PORT), +}) + +_METRICS_SERVICE = _obj({ + "enabled": _BOOL, + "annotations": _OBJECT_FREE, + "extraLabels": _OBJECT_FREE, + "type": _STRING, + "port": _INT, + "targetPort": {"anyOf": [_INT, _STRING]}, + "serviceMonitor": _SERVICE_MONITOR, +}) + +_INGRESS_HOST_PATH = _obj({ + "path": _STRING, + "pathType": _STRING, + "service": _obj({ + "name": _STRING, + "port": {"anyOf": [_INT, _STRING]}, + }, additional=True), +}, additional=True) + +_INGRESS_HOST = _obj({ + "host": _STRING, + "paths": _arr(_INGRESS_HOST_PATH), +}, additional=True) + +_INGRESS_TLS = _obj({ + "secretName": _STRING, + "hosts": _arr(_STRING), +}, additional=True) + +_INGRESS = _obj({ + "enabled": _BOOL, + "className": _STRING, + "hosts": _arr(_INGRESS_HOST), + "tls": _arr(_INGRESS_TLS), +}, additional=True) + +_VOLUME_MOUNT = _obj({ + "name": _STRING, + "mountPath": _STRING, + "subPath": _STRING, + "readOnly": _BOOL, +}, additional=True) + +_VOLUME = _obj({ + "name": _STRING, +}, additional=True) + +_PROBE_DATA = _obj({}, additional=True) + +_PROBE_ENTRY = _obj({ + "enabled": _BOOL, + "data": _PROBE_DATA, +}) + +_PROBES = _obj({ + "lifecycle": _obj({"enabled": _BOOL}, additional=True), + "livenessProbe": _PROBE_ENTRY, + "readinessProbe": _PROBE_ENTRY, + "startupProbe": _PROBE_ENTRY, +}) + +_SECURITY_CONTEXT = _obj({ + "allowPrivilegeEscalation": _BOOL, + "capabilities": _obj({ + "drop": _arr(_STRING), + "add": _arr(_STRING), + }), + "runAsUser": _INT, + "runAsNonRoot": _BOOL, + "readOnlyRootFilesystem": _BOOL, + "seccompProfile": _obj({"type": _STRING}, additional=True), +}) + +_RBAC_RULE = _obj({ + "apiGroups": _arr(_STRING), + "resources": _arr(_STRING), + "verbs": _arr(_STRING), +}, additional=True) + +_RBAC = _obj({ + "enabled": _BOOL, + "permissions": _obj({ + "namespaced": _arr(_RBAC_RULE), + "cluster": _arr(_RBAC_RULE), + }, additional=True), +}) + +_SERVICE_ACCOUNT = _obj({ + "annotations": _OBJECT_FREE, + "labels": _OBJECT_FREE, + "automountServiceAccountToken": _BOOL, + "rbac": _RBAC, +}) + +_ENV_VAR = _obj({ + "name": _STRING, + "value": _STRING, + "valueFrom": _obj({}, additional=True), +}, additional=True) + +_MIGRATION = _obj({ + "enabled": _BOOL, + "scaleDown": _BOOL, + "backoffLimit": _INT, + "command": _arr(_STRING), + "args": _arr(_STRING), + "resources": _OBJECT_FREE, +}) + +_COMMAND = _obj({ + "enabled": _BOOL, + "data": _arr(_STRING), +}) + +_CONFIGURATION_TYPE = _obj({ + "backend": _BOOL, + "frontend": _BOOL, +}) + +_KUBECONFIG = _obj({ + "enabled": _BOOL, +}) + + +def _base_app_props(extra: dict | None = None) -> dict: + """Properties common to every application entry.""" + props = { + "enabled": _BOOL, + "applicationName": _STRING, + "configurationFileName": _STRING, + "deployment": _obj({"enabled": _BOOL}), + "replicaCount": _INT, + "statefulset": _obj({"enabled": _BOOL}), + "job": _obj({"enabled": _BOOL}, additional=True), + "migration": _MIGRATION, + "rollingUpdate": _ROLLING_UPDATE, + "image": _IMAGE, + "command": _COMMAND, + "env": _arr(_ENV_VAR), + "ports": _arr(_PORT_DEF), + "service": _SERVICE, + "metricsService": _METRICS_SERVICE, + "ingress": _INGRESS, + "volumeMounts": _arr(_VOLUME_MOUNT), + "volumes": _arr(_VOLUME), + "probes": _PROBES, + "securityContext": _SECURITY_CONTEXT, + "serviceAccount": _SERVICE_ACCOUNT, + "kubeconfig": _KUBECONFIG, + "configuration_type": _CONFIGURATION_TYPE, + } + if extra: + props.update(extra) + return props + + +# --------------------------------------------------------------------------- +# Application-specific schemas +# --------------------------------------------------------------------------- + +def _fred_agents_app(fa_config: dict) -> dict: + # models_catalog: free-form (large catalog structure, fully user-defined) + # mcp_catalog: free-form + # dotenv: key/value env secrets + return _obj(_base_app_props({ + "configuration": fa_config, + "dotenv": _obj({}, additional=True), + "models_catalog": _obj({}, additional=True), + "mcp_catalog": _obj({}, additional=True), + })) + + +def _frontend_app() -> dict: + _frontend_config = _obj({ + "config_json": _obj({ + "frontend_basename": _STRING, + "user_auth": _obj({ + "enabled": _BOOL, + "realm_url": _STRING, + "client_id": _STRING, + }), + }, additional=True), + }, additional=True) + + return _obj(_base_app_props({ + "configuration": _frontend_config, + })) + + +def _kf_app(kf_config: dict) -> dict: + return _obj(_base_app_props({ + "configuration": kf_config, + "dotenv": _obj({}, additional=True), + })) + + +def _kf_worker_app(kf_config: dict) -> dict: + return _obj(_base_app_props({ + "configuration": kf_config, + "dotenv": _obj({}, additional=True), + })) + + +def _cp_app(cp_config: dict) -> dict: + _policy_entry = _obj({ + "mode": _STRING, + "retention": _STRING, + "cancel_on_rejoin": _BOOL, + }, additional=True) + + _policy_rule = _obj({ + "rule_id": _STRING, + "match": _obj({ + "team_id": _STRING, + "trigger": _STRING, + }, additional=True), + "action": _obj({ + "retention": _STRING, + }, additional=True), + }, additional=True) + + _purge_policy = _obj({ + "default": _policy_entry, + "rules": _arr(_policy_rule), + }) + + _conversation_policy_catalog = _obj({ + "version": _STRING, + "conversation_policies": _obj({ + "purge": _purge_policy, + }, additional=True), + }) + + return _obj(_base_app_props({ + "configuration": cp_config, + "conversation_policy_catalog": _conversation_policy_catalog, + "dotenv": _obj({}, additional=True), + })) + + +def _cp_worker_app(cp_config: dict) -> dict: + return _obj(_base_app_props({ + "configuration": cp_config, + "dotenv": _obj({}, additional=True), + })) + + +# --------------------------------------------------------------------------- +# Global schema +# --------------------------------------------------------------------------- + +_GLOBAL = _obj({ + "kubeconfig": _STRING, + "persistence": _obj({ + "enabled": _BOOL, + "dynamic": _BOOL, + "accessModes": _STRING, + "reclaimPolicy": _STRING, + "storageClass": _STRING, + "hostPath": _STRING, + }), + "whitelist": _obj({ + "enabled": _BOOL, + "configMapName": _STRING, + "filePath": _STRING, + "user_list_inline": _STRING, + "mountPath": _STRING, + "subPath": _STRING, + }), +}) + + +# --------------------------------------------------------------------------- +# Assembly +# --------------------------------------------------------------------------- + +def build(fa_schema_path: Path, kf_schema_path: Path, cp_schema_path: Path) -> dict: + fa_config = _inline_refs(_load(fa_schema_path)) + kf_config = _inline_refs(_load(kf_schema_path)) + cp_config = _inline_refs(_load(cp_schema_path)) + + return { + "$schema": "https://json-schema.org/draft-07/schema#", + "title": "Fred Helm Chart Values", + "type": "object", + "additionalProperties": False, + # x-* keys are YAML anchors used for DRY value reuse. Helm resolves + # them before template rendering but they remain visible to schema + # validators, so we allow any x-* key with any value at the root. + "patternProperties": {"^x-": {}}, + "properties": { + "global": _GLOBAL, + "applications": _obj({ + "fred-agents": _fred_agents_app(fa_config), + "frontend": _frontend_app(), + "knowledge-flow-backend": _kf_app(kf_config), + "knowledge-flow-worker": _kf_worker_app(kf_config), + "control-plane-backend": _cp_app(cp_config), + "control-plane-worker": _cp_worker_app(cp_config), + }), + }, + } + + +# --------------------------------------------------------------------------- +# CLI +# --------------------------------------------------------------------------- + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--fred-agents", required=True, type=Path, metavar="SCHEMA") + parser.add_argument("--knowledge-flow", required=True, type=Path, metavar="SCHEMA") + parser.add_argument("--control-plane", required=True, type=Path, metavar="SCHEMA") + parser.add_argument("--output", required=True, type=Path, metavar="OUTPUT") + args = parser.parse_args() + + for p in (args.fred_agents, args.knowledge_flow, args.control_plane): + if not p.exists(): + print(f"ERROR: schema not found: {p}", file=sys.stderr) + sys.exit(1) + + schema = build(args.fred_agents, args.knowledge_flow, args.control_plane) + + args.output.parent.mkdir(parents=True, exist_ok=True) + with open(args.output, "w") as f: + json.dump(schema, f, indent=2) + f.write("\n") + + print(f"Chart values schema written to {args.output}") + + +if __name__ == "__main__": + main() diff --git a/scripts/makefiles/chart-schema.mk b/scripts/makefiles/chart-schema.mk new file mode 100644 index 0000000000..758e5997f2 --- /dev/null +++ b/scripts/makefiles/chart-schema.mk @@ -0,0 +1,48 @@ +##@ Helm Chart Schema + +_CHART_SCHEMA_MK_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +_GEN_CHART_SCHEMA_SCRIPT := $(_CHART_SCHEMA_MK_DIR)/../generate_chart_schema.py +_CHECK_CHART_VALUES_SCRIPT := $(_CHART_SCHEMA_MK_DIR)/../check_chart_values.py + +_CHART_REPO_ROOT := $(abspath $(_CHART_SCHEMA_MK_DIR)/../..) +_CHART_SCHEMA_FILE := $(_CHART_REPO_ROOT)/deploy/charts/fred/values.schema.json +_CHART_VALUES_FILE := $(_CHART_REPO_ROOT)/deploy/charts/fred/values.yaml + +_FA_SCHEMA := $(_CHART_REPO_ROOT)/apps/fred-agents/config/schema/configuration.schema.json +_KF_SCHEMA := $(_CHART_REPO_ROOT)/apps/knowledge-flow-backend/config/schema/configuration.schema.json +_CP_SCHEMA := $(_CHART_REPO_ROOT)/apps/control-plane-backend/config/schema/configuration.schema.json + +_ALL_BACKEND_SCHEMAS_PRESENT = \ + $(if $(and $(wildcard $(_FA_SCHEMA)),$(wildcard $(_KF_SCHEMA)),$(wildcard $(_CP_SCHEMA))),yes,) + +.PHONY: generate-chart-schema +generate-chart-schema: ## Regenerate deploy/charts/fred/values.schema.json from all backend config schemas + $(if $(_ALL_BACKEND_SCHEMAS_PRESENT), \ + python3 $(_GEN_CHART_SCHEMA_SCRIPT) \ + --fred-agents "$(_FA_SCHEMA)" \ + --knowledge-flow "$(_KF_SCHEMA)" \ + --control-plane "$(_CP_SCHEMA)" \ + --output "$(_CHART_SCHEMA_FILE)", \ + echo "Skipping chart schema: not all backend schemas are present yet.") + +_CHART_DRIFT_TMP := /tmp/schema-drift-check/chart-values + +.PHONY: check-chart-schema-drift +check-chart-schema-drift: ## Fail if values.schema.json differs from freshly generated one + $(if $(_ALL_BACKEND_SCHEMAS_PRESENT), \ + mkdir -p $(_CHART_DRIFT_TMP) && \ + python3 $(_GEN_CHART_SCHEMA_SCRIPT) \ + --fred-agents "$(_FA_SCHEMA)" \ + --knowledge-flow "$(_KF_SCHEMA)" \ + --control-plane "$(_CP_SCHEMA)" \ + --output "$(_CHART_DRIFT_TMP)/values.schema.json" && \ + (diff "$(_CHART_SCHEMA_FILE)" "$(_CHART_DRIFT_TMP)/values.schema.json" \ + || (echo "ERROR: $(_CHART_SCHEMA_FILE) is out of date. Run 'make generate-chart-schema' and commit the result." && exit 1)) && \ + echo "Chart schema drift check passed.", \ + echo "Skipping chart schema drift check: not all backend schemas are present.") + +.PHONY: check-chart-values +check-chart-values: ## Validate deploy/charts/fred/values.yaml against the generated Helm values schema + $(if $(_ALL_BACKEND_SCHEMAS_PRESENT), \ + python3 $(_CHECK_CHART_VALUES_SCRIPT) "$(_CHART_SCHEMA_FILE)" "$(_CHART_VALUES_FILE)", \ + echo "Skipping chart values check: not all backend schemas are present.") diff --git a/scripts/makefiles/python-config-schema.mk b/scripts/makefiles/python-config-schema.mk index eb1793ec62..0c91847b48 100644 --- a/scripts/makefiles/python-config-schema.mk +++ b/scripts/makefiles/python-config-schema.mk @@ -1,7 +1,7 @@ ##@ Config JSON Schema _SCHEMA_MK_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) -_GEN_SCHEMA_SCRIPT := $(_SCHEMA_MK_DIR)/../generate_config_schema.py +_GEN_SCHEMA_SCRIPT := $(_SCHEMA_MK_DIR)/../generate_config_schema.py _CHECK_CONFIG_SCRIPT := $(_SCHEMA_MK_DIR)/../check_config_files.py SCHEMA_DIR := $(ROOT_DIR)/config/schema @@ -10,9 +10,10 @@ SCHEMA_FILE := $(SCHEMA_DIR)/configuration.schema.json _SCHEMA_QUALIFIED := $(CONFIG_SCHEMA_MODULE).$(CONFIG_SCHEMA_CLASS) .PHONY: generate-config-schema -generate-config-schema: dev ## Generate JSON schemas from Pydantic config models +generate-config-schema: dev ## Generate JSON schema from Pydantic config model and rebuild the Helm chart values schema @mkdir -p $(SCHEMA_DIR) $(PYTHON) $(_GEN_SCHEMA_SCRIPT) $(_SCHEMA_QUALIFIED) $(SCHEMA_FILE) + @$(MAKE) --no-print-directory -C $(abspath $(_SCHEMA_MK_DIR)/../..) generate-chart-schema _DRIFT_TMP := /tmp/schema-drift-check/$(PROJECT_NAME)