mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:40:43 +00:00
refactor: type config schemas as typebox-compatible
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import fs from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { validateJsonSchemaValue } from "../../src/plugins/schema-validator.js";
|
||||
import type { JsonSchemaObject } from "../../src/shared/json-schema.types.js";
|
||||
|
||||
const manifest = JSON.parse(
|
||||
fs.readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf-8"),
|
||||
) as { configSchema: Record<string, unknown> };
|
||||
) as { configSchema: JsonSchemaObject };
|
||||
|
||||
describe("active-memory manifest config schema", () => {
|
||||
it("accepts modelFallback for CLI and config.patch flows", () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from "node:fs";
|
||||
import AjvPkg from "ajv";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { JsonSchemaObject } from "../../../src/shared/json-schema.types.js";
|
||||
import {
|
||||
DEFAULT_DIFFS_PLUGIN_SECURITY,
|
||||
DEFAULT_DIFFS_TOOL_DEFAULTS,
|
||||
@@ -39,7 +40,7 @@ const FULL_DEFAULTS = {
|
||||
function compileManifestConfigSchema() {
|
||||
const manifest = JSON.parse(
|
||||
fs.readFileSync(new URL("../openclaw.plugin.json", import.meta.url), "utf8"),
|
||||
) as { configSchema: Record<string, unknown> };
|
||||
) as { configSchema: JsonSchemaObject };
|
||||
const Ajv = AjvPkg as unknown as new (opts?: object) => import("ajv").default;
|
||||
const ajv = new Ajv({ allErrors: true, strict: false, useDefaults: true });
|
||||
return ajv.compile(manifest.configSchema);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import fs from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { validateJsonSchemaValue } from "../../../src/plugins/schema-validator.js";
|
||||
import type { JsonSchemaObject } from "../../../src/shared/json-schema.types.js";
|
||||
|
||||
const manifest = JSON.parse(
|
||||
fs.readFileSync(new URL("../openclaw.plugin.json", import.meta.url), "utf-8"),
|
||||
) as { configSchema: Record<string, unknown> };
|
||||
) as { configSchema: JsonSchemaObject };
|
||||
|
||||
describe("memory-core manifest config schema", () => {
|
||||
it("accepts dreaming phase thresholds used by QA and runtime", () => {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import fs from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { validateJsonSchemaValue } from "../../src/plugins/schema-validator.js";
|
||||
import type { JsonSchemaObject } from "../../src/shared/json-schema.types.js";
|
||||
import { memoryConfigSchema } from "./config.js";
|
||||
|
||||
const manifest = JSON.parse(
|
||||
fs.readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf-8"),
|
||||
) as { configSchema: Record<string, unknown> };
|
||||
) as { configSchema: JsonSchemaObject };
|
||||
|
||||
describe("memory-lancedb config", () => {
|
||||
it("accepts dreaming in the manifest schema and preserves it in runtime parsing", () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from "node:fs";
|
||||
import AjvPkg from "ajv";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { JsonSchemaObject } from "../../../src/shared/json-schema.types.js";
|
||||
import {
|
||||
DEFAULT_WIKI_RENDER_MODE,
|
||||
DEFAULT_WIKI_SEARCH_BACKEND,
|
||||
@@ -13,7 +14,7 @@ import {
|
||||
function compileManifestConfigSchema() {
|
||||
const manifest = JSON.parse(
|
||||
fs.readFileSync(new URL("../openclaw.plugin.json", import.meta.url), "utf8"),
|
||||
) as { configSchema: Record<string, unknown> };
|
||||
) as { configSchema: JsonSchemaObject };
|
||||
const Ajv = AjvPkg as unknown as new (opts?: object) => import("ajv").default;
|
||||
const ajv = new Ajv({ allErrors: true, strict: false, useDefaults: true });
|
||||
return ajv.compile(manifest.configSchema);
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { validateJsonSchemaValue } from "../../../src/plugins/schema-validator.js";
|
||||
import type { JsonSchemaObject } from "../../../src/shared/json-schema.types.js";
|
||||
import { qqbotSetupAdapterShared } from "./bridge/config-shared.js";
|
||||
import {
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
@@ -16,7 +17,7 @@ describe("qqbot config", () => {
|
||||
it("accepts top-level speech overrides in the manifest schema", () => {
|
||||
const manifest = JSON.parse(
|
||||
fs.readFileSync(new URL("../openclaw.plugin.json", import.meta.url), "utf-8"),
|
||||
) as { configSchema: Record<string, unknown> };
|
||||
) as { configSchema: JsonSchemaObject };
|
||||
|
||||
const result = validateJsonSchemaValue({
|
||||
schema: manifest.configSchema,
|
||||
@@ -37,7 +38,7 @@ describe("qqbot config", () => {
|
||||
it("accepts defaultAccount in the manifest schema", () => {
|
||||
const manifest = JSON.parse(
|
||||
fs.readFileSync(new URL("../openclaw.plugin.json", import.meta.url), "utf-8"),
|
||||
) as { configSchema: Record<string, unknown> };
|
||||
) as { configSchema: JsonSchemaObject };
|
||||
|
||||
const result = validateJsonSchemaValue({
|
||||
schema: manifest.configSchema,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { z, type ZodRawShape, type ZodTypeAny } from "zod";
|
||||
import { DmPolicySchema } from "../../config/zod-schema.core.js";
|
||||
import type { JsonSchemaObject } from "../../shared/json-schema.types.js";
|
||||
import type {
|
||||
ChannelConfigRuntimeIssue,
|
||||
ChannelConfigRuntimeParseResult,
|
||||
@@ -81,7 +82,7 @@ export function buildChannelConfigSchema(
|
||||
schema: schemaWithJson.toJSONSchema({
|
||||
target: "draft-07",
|
||||
unrepresentable: "any",
|
||||
}) as Record<string, unknown>,
|
||||
}) as JsonSchemaObject,
|
||||
...(options?.uiHints ? { uiHints: options.uiHints } : {}),
|
||||
runtime: {
|
||||
safeParse: (value) => safeParseRuntimeSchema(schema, value),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { JsonSchemaObject } from "../../shared/json-schema.types.js";
|
||||
|
||||
export type ChannelConfigUiHint = {
|
||||
label?: string;
|
||||
help?: string;
|
||||
@@ -29,7 +31,7 @@ export type ChannelConfigRuntimeSchema = {
|
||||
};
|
||||
|
||||
export type ChannelConfigSchema = {
|
||||
schema: Record<string, unknown>;
|
||||
schema: JsonSchemaObject;
|
||||
uiHints?: Record<string, ChannelConfigUiHint>;
|
||||
runtime?: ChannelConfigRuntimeSchema;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
import type { ChannelConfigRuntimeSchema } from "../channels/plugins/types.config.js";
|
||||
import type { JsonSchemaObject } from "../shared/json-schema.types.js";
|
||||
import {
|
||||
normalizeBundledPluginStringList,
|
||||
trimBundledPluginString,
|
||||
@@ -26,7 +27,7 @@ const SOURCE_CONFIG_SCHEMA_CANDIDATES = [
|
||||
const PUBLIC_CONFIG_SURFACE_BASENAMES = ["channel-config-api", "runtime-api", "api"] as const;
|
||||
|
||||
type ChannelConfigSurface = {
|
||||
schema: Record<string, unknown>;
|
||||
schema: JsonSchemaObject;
|
||||
uiHints?: Record<string, PluginConfigUiHint>;
|
||||
runtime?: ChannelConfigRuntimeSchema;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { z, type ZodTypeAny } from "zod";
|
||||
import type { JsonSchemaObject } from "../shared/json-schema.types.js";
|
||||
import type { PluginConfigUiHint } from "./manifest-types.js";
|
||||
import type { OpenClawPluginConfigSchema } from "./types.js";
|
||||
|
||||
@@ -92,7 +93,7 @@ export function buildPluginConfigSchema(
|
||||
io: "input",
|
||||
unrepresentable: "any",
|
||||
}),
|
||||
) as Record<string, unknown>,
|
||||
) as JsonSchemaObject,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import JSON5 from "json5";
|
||||
import type { ChannelConfigRuntimeSchema } from "../channels/plugins/types.config.js";
|
||||
import { MANIFEST_KEY } from "../compat/legacy-names.js";
|
||||
import { matchBoundaryFileOpenFailure, openBoundaryFileSync } from "../infra/boundary-file-read.js";
|
||||
import type { JsonSchemaObject } from "../shared/json-schema.types.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import { normalizeTrimmedStringList } from "../shared/string-normalization.js";
|
||||
import { isRecord } from "../utils.js";
|
||||
@@ -18,7 +19,7 @@ export const PLUGIN_MANIFEST_FILENAME = "openclaw.plugin.json";
|
||||
export const PLUGIN_MANIFEST_FILENAMES = [PLUGIN_MANIFEST_FILENAME] as const;
|
||||
|
||||
export type PluginManifestChannelConfig = {
|
||||
schema: Record<string, unknown>;
|
||||
schema: JsonSchemaObject;
|
||||
uiHints?: Record<string, PluginConfigUiHint>;
|
||||
runtime?: ChannelConfigRuntimeSchema;
|
||||
label?: string;
|
||||
@@ -154,7 +155,7 @@ export type PluginManifestConfigContracts = {
|
||||
|
||||
export type PluginManifest = {
|
||||
id: string;
|
||||
configSchema: Record<string, unknown>;
|
||||
configSchema: JsonSchemaObject;
|
||||
enabledByDefault?: boolean;
|
||||
/** Legacy plugin ids that should normalize to this plugin id. */
|
||||
legacyPluginIds?: string[];
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
import type { OperatorScope } from "../gateway/operator-scopes.js";
|
||||
import type { GatewayRequestHandlers } from "../gateway/server-methods/types.js";
|
||||
import type { HookEntry } from "../hooks/types.js";
|
||||
import type { JsonSchemaObject } from "../shared/json-schema.types.js";
|
||||
import type { CodexAppServerExtensionFactory } from "./codex-app-server-extension-types.js";
|
||||
import type { PluginActivationSource } from "./config-state.js";
|
||||
import type {
|
||||
@@ -275,7 +276,7 @@ export type PluginRecord = {
|
||||
hookCount: number;
|
||||
configSchema: boolean;
|
||||
configUiHints?: Record<string, PluginConfigUiHint>;
|
||||
configJsonSchema?: Record<string, unknown>;
|
||||
configJsonSchema?: JsonSchemaObject;
|
||||
contracts?: PluginManifestContracts;
|
||||
memorySlotSelected?: boolean;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createRequire } from "node:module";
|
||||
import type { ErrorObject, ValidateFunction } from "ajv";
|
||||
import { appendAllowedValuesHint, summarizeAllowedValues } from "../config/allowed-values.js";
|
||||
import type { JsonSchemaObject } from "../shared/json-schema.types.js";
|
||||
import { sanitizeTerminalText } from "../terminal/safe-text.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
@@ -14,7 +15,7 @@ type AjvLike = {
|
||||
validate: (value: string) => boolean;
|
||||
},
|
||||
) => AjvLike;
|
||||
compile: (schema: Record<string, unknown>) => ValidateFunction;
|
||||
compile: (schema: JsonSchemaObject) => ValidateFunction;
|
||||
};
|
||||
const ajvSingletons = new Map<"default" | "defaults", AjvLike>();
|
||||
|
||||
@@ -48,7 +49,7 @@ function getAjv(mode: "default" | "defaults"): AjvLike {
|
||||
|
||||
type CachedValidator = {
|
||||
validate: ValidateFunction;
|
||||
schema: Record<string, unknown>;
|
||||
schema: JsonSchemaObject;
|
||||
};
|
||||
|
||||
const schemaCache = new Map<string, CachedValidator>();
|
||||
@@ -158,7 +159,7 @@ function formatAjvErrors(errors: ErrorObject[] | null | undefined): JsonSchemaVa
|
||||
}
|
||||
|
||||
export function validateJsonSchemaValue(params: {
|
||||
schema: Record<string, unknown>;
|
||||
schema: JsonSchemaObject;
|
||||
cacheKey: string;
|
||||
value: unknown;
|
||||
applyDefaults?: boolean;
|
||||
|
||||
@@ -48,6 +48,7 @@ import type {
|
||||
} from "../realtime-voice/provider-types.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import type { SecurityAuditFinding } from "../security/audit.types.js";
|
||||
import type { JsonSchemaObject } from "../shared/json-schema.types.js";
|
||||
import type {
|
||||
SpeechDirectiveTokenParseContext,
|
||||
SpeechDirectiveTokenParseResult,
|
||||
@@ -221,7 +222,7 @@ export type OpenClawPluginConfigSchema = {
|
||||
parse?: (value: unknown) => unknown;
|
||||
validate?: (value: unknown) => PluginConfigValidation;
|
||||
uiHints?: Record<string, PluginConfigUiHint>;
|
||||
jsonSchema?: Record<string, unknown>;
|
||||
jsonSchema?: JsonSchemaObject;
|
||||
};
|
||||
|
||||
export type ProviderAuthKind = "oauth" | "api_key" | "token" | "device_code" | "custom";
|
||||
|
||||
3
src/shared/json-schema.types.ts
Normal file
3
src/shared/json-schema.types.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import type { TSchema } from "typebox";
|
||||
|
||||
export type JsonSchemaObject = TSchema & Record<string, unknown>;
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { PluginConfigUiHint } from "../plugins/types.js";
|
||||
import { getPath, setPathCreateStrict } from "../secrets/path-utils.js";
|
||||
import type { JsonSchemaObject } from "../shared/json-schema.types.js";
|
||||
import type { WizardPrompter } from "./prompts.js";
|
||||
|
||||
/**
|
||||
@@ -12,7 +13,7 @@ export type ConfigurablePlugin = {
|
||||
/** uiHints from the plugin manifest, keyed by config field name. */
|
||||
uiHints: Record<string, PluginConfigUiHint>;
|
||||
/** JSON schema from the plugin manifest (used for type/enum info). */
|
||||
jsonSchema?: Record<string, unknown>;
|
||||
jsonSchema?: JsonSchemaObject;
|
||||
};
|
||||
|
||||
type ManifestRegistryModule = typeof import("../plugins/manifest-registry.js");
|
||||
@@ -31,7 +32,7 @@ type JsonSchemaProperty = {
|
||||
};
|
||||
|
||||
function resolveJsonSchemaProperty(
|
||||
jsonSchema: Record<string, unknown> | undefined,
|
||||
jsonSchema: JsonSchemaObject | undefined,
|
||||
fieldKey: string,
|
||||
): JsonSchemaProperty | undefined {
|
||||
if (!jsonSchema) {
|
||||
|
||||
Reference in New Issue
Block a user