feat: plugin system + voice-call

This commit is contained in:
Peter Steinberger
2026-01-12 01:16:39 +00:00
parent a6ea74f8e6
commit 2f4a248314
16 changed files with 614 additions and 58 deletions

View File

@@ -23,6 +23,19 @@ export type ConfigSchemaResponse = {
generatedAt: string;
};
export type PluginUiMetadata = {
id: string;
name?: string;
description?: string;
configUiHints?: Record<
string,
Pick<
ConfigUiHint,
"label" | "help" | "advanced" | "sensitive" | "placeholder"
>
>;
};
const GROUP_LABELS: Record<string, string> = {
wizard: "Wizard",
logging: "Logging",
@@ -327,10 +340,52 @@ function applySensitiveHints(hints: ConfigUiHints): ConfigUiHints {
return next;
}
let cached: ConfigSchemaResponse | null = null;
function applyPluginHints(
hints: ConfigUiHints,
plugins: PluginUiMetadata[],
): ConfigUiHints {
const next: ConfigUiHints = { ...hints };
for (const plugin of plugins) {
const id = plugin.id.trim();
if (!id) continue;
const name = (plugin.name ?? id).trim() || id;
const basePath = `plugins.entries.${id}`;
export function buildConfigSchema(): ConfigSchemaResponse {
if (cached) return cached;
next[basePath] = {
...next[basePath],
label: name,
help: plugin.description
? `${plugin.description} (plugin: ${id})`
: `Plugin entry for ${id}.`,
};
next[`${basePath}.enabled`] = {
...next[`${basePath}.enabled`],
label: `Enable ${name}`,
};
next[`${basePath}.config`] = {
...next[`${basePath}.config`],
label: `${name} Config`,
help: `Plugin-defined config payload for ${id}.`,
};
const uiHints = plugin.configUiHints ?? {};
for (const [relPathRaw, hint] of Object.entries(uiHints)) {
const relPath = relPathRaw.trim().replace(/^\./, "");
if (!relPath) continue;
const key = `${basePath}.config.${relPath}`;
next[key] = {
...next[key],
...hint,
};
}
}
return next;
}
let cachedBase: ConfigSchemaResponse | null = null;
function buildBaseConfigSchema(): ConfigSchemaResponse {
if (cachedBase) return cachedBase;
const schema = ClawdbotSchema.toJSONSchema({
target: "draft-07",
unrepresentable: "any",
@@ -343,6 +398,19 @@ export function buildConfigSchema(): ConfigSchemaResponse {
version: VERSION,
generatedAt: new Date().toISOString(),
};
cached = next;
cachedBase = next;
return next;
}
export function buildConfigSchema(params?: {
plugins?: PluginUiMetadata[];
}): ConfigSchemaResponse {
const base = buildBaseConfigSchema();
const plugins = params?.plugins ?? [];
if (plugins.length === 0) return base;
const merged = applySensitiveHints(applyPluginHints(base.uiHints, plugins));
return {
...base,
uiHints: merged,
};
}