Skip to content

config_schema declarative form ​

config_schema is enough for simple configuration — the host renders it automatically into the workshop card's inline form / a standalone settings tab. Ship your own settings_view QML only when you need custom UX such as "Get API Key" or "Test Connection" (see Custom settings view).


Basic form ​

json
"config_schema": [
  { "key": "api_key", "label": "API Key", "type": "password", "is_secret": true },
  { "key": "base_url", "label": "API 地址", "type": "string",
    "default": "https://api.example.com" },
  { "key": "temperature", "label": "温度", "type": "number", "default": 0.3 },
  { "key": "model_name", "label": "模型", "type": "select",
    "choices": ["a", "b"], "default": "a" },
  { "key": "enable_stream", "label": "流式", "type": "boolean", "default": true },
  { "key": "port", "label": "服务端口", "type": "number", "default": 18080,
    "description": "本地服务监听端口,留空用默认;被占用时自动顺延" }
]

Every item must have a key and a label.


Fields ​

FieldTypeDescription
keystringRequired. self._config.get(key) reads the value with it
labelstringRequired. Display name
typestringSee the table below; defaults to string
defaultanyDefault value
descriptionstringHelper text shown under the field
choicesstring[]Options for select (an object form {"value","label"} is also accepted)
choice_labelsobjectStored value → display name map, e.g. {"x2_john": "John · 英语男声"}
is_secretbooltrue → masked input (same as type: "password")
presetsobjectSelecting one option back-fills other fields (see below)
preset_optionsarrayGives a text input one-click preset chips
hiddenboolNot rendered, but the key stays valid
show_whenobjectConditional visibility (see below)

Available type values ​

ValueRendering
stringSingle-line text (renders as a dropdown automatically when choices is present)
numberNumeric input (short width)
booleanSwitch
selectDropdown (with choices)
passwordMasked input
textarea / textMulti-line text
file⚠️ The manifest type keeps this value, but the dynamic form has no file-picker widget yet (it renders as a text box). To pick files, ship your own settings_view or use host.pick_file()

Preset back-fill presets ​

Switching provider changes base_url / model automatically, so the user only has to paste the key:

json
{
  "key": "provider_preset",
  "label": "服务商预设",
  "type": "select",
  "choices": ["小米 Token Plan", "DeepSeek", "Ollama 本地", "自定义"],
  "default": "小米 Token Plan",
  "presets": {
    "小米 Token Plan": { "base_url": "https://…", "model": "mimo-v2.5" },
    "Ollama 本地": { "base_url": "http://127.0.0.1:11434/v1", "model": "qwen2.5" }
  }
}

preset_options gives a text input one-click choices (URL / port):

json
{ "key": "base_url", "label": "API 地址", "type": "string",
  "preset_options": [
    { "label": "官方", "value": "https://api.example.com" },
    { "label": "本地", "value": "http://127.0.0.1:8000" }
  ] }

Declarative visibility: hidden + show_when ​

Show only the parameters that actually apply to the current model / variant, and collapse the fields that belong to other models. Principles:

  • "hidden": true: not rendered, but the key stays valid (the host or your code can still write it). Typical case: voices are managed centrally by the host's "Voice" dropdown, so the plugin does not need to expose a voice input (the host writes the selected value into self._config["voice"]).
  • "show_when": {...}: rendered only when the current config matches.
json
{ "key": "variant", "label": "模型变体", "type": "select",
  "choices": ["base", "customvoice", "voicedesign"], "default": "base" },
{ "key": "instruct", "label": "音色描述", "type": "string",
  "show_when": { "variant": "voicedesign" },
  "description": "用文字描述想要的音色(仅 voicedesign 变体生效)" }

The accepted shapes of show_when:

FormMeaning
{"variant": "voicedesign"}Shown only when it equals that value
{"variant": ["a", "b"]}Shown when it matches any one of them
{"variant": "*"}Shown when that key is non-empty

It only looks at the current config values; when a condition field's value changes, the UI rebuilds the corresponding row automatically (no lost focus, no flicker). The host needs no code change — adapting to a new model only means editing your mod.json.

If a field belongs to another model, write another plugin / mod.json instead of piling everything into one form.


Compute device (device) ​

Local inference models (llama.cpp / ONNX / PyTorch…) should declare device in config_schema:

json
{
  "key": "device",
  "label": "计算设备",
  "type": "select",
  "choices": ["vulkan", "rocm", "cuda", "cpu"],
  "default": "vulkan",
  "description": "推理硬件后端:Vulkan(跨平台 GPU)、ROCm(AMD 显卡)、CUDA(NVIDIA 显卡)或 CPU。"
}

The standard device identifiers the host supports natively are rendered automatically as plain-language labels — you do not write a display name per option:

ValueHost display name
cudaGPU (CUDA)
vulkanGPU (Vulkan)
rocmGPU (AMD ROCm)
cpuCPU
directmlGPU (DirectML)
openvinoOpenVINO

Only declare backends your runtime really supports — writing cuda for a llama.cpp runtime that only has Vulkan+CPU means users pick it and crash. (One workable approach: generate choices dynamically from your runtime's probe results.)

Other behaviour:

  • Smart hardware gating: when the config or the defaults contain vulkan / rocm, the host automatically allows non-NVIDIA hardware; on an AMD GPU it rates the setup "Good fit" instead of popping the "NVIDIA CUDA required" red box.
  • Local models (declaring model_artifacts + tags: ["local"]) get their device selection from the settings page's LocalLoadDeviceRow; your form's device is then hidden automatically (to avoid two duplicate controls) — so just declare it as usual and don't worry about visibility.

Consuming config ​

ScenarioHow
Python pluginself._config.get(key); update_config(delta) is called on change
QML componentRead with bridge.getPluginConfig(pluginId) and listen to bridge.pluginConfigChanged via Connections (mandatory, otherwise there is no hot refresh, see UI extensions)

When settings_view is mandatory ​

The following UX is not generated from config_schema and needs your own ui_extensions.settings_view:

  • A "Get API Key" button / application link
  • A "Test Connection" button and its result display
  • Mode switches such as dual Base URL or Token Plan / normal API
  • Any UI that has to call the host's host.pick_file() or show a dynamic list

See Custom settings view.


TransBox — empowering borderless cross-language communication for everyone