






















11import fs from "node:fs";
22import { homedir } from "node:os";
33import { join } from "node:path";
4+import { parseFiniteNumber } from "openclaw/plugin-sdk/number-runtime";
4556export type MemoryConfig = {
67embedding: {
@@ -87,14 +88,51 @@ function resolveEnvVars(value: string): string {
8788});
8889}
899090-function resolveEmbeddingModel(embedding: Record<string, unknown>): string {
91+function resolveEmbeddingModel(
92+embedding: Record<string, unknown>,
93+dimensions: number | undefined,
94+): string {
9195const model = typeof embedding.model === "string" ? embedding.model : DEFAULT_MODEL;
92-if (typeof embedding.dimensions !== "number") {
96+if (dimensions === undefined) {
9397vectorDimsForModel(model);
9498}
9599return model;
96100}
97101102+function resolveFiniteIntegerConfig(value: unknown): number | undefined {
103+if (typeof value !== "number") {
104+return undefined;
105+}
106+const parsed = parseFiniteNumber(value);
107+return parsed === undefined ? undefined : Math.floor(parsed);
108+}
109+110+function resolveBoundedIntegerConfig(params: {
111+value: unknown;
112+fallback: number;
113+min: number;
114+max: number;
115+label: string;
116+}): number {
117+const resolved = resolveFiniteIntegerConfig(params.value) ?? params.fallback;
118+if (resolved < params.min || resolved > params.max) {
119+throw new Error(`${params.label} must be between ${params.min} and ${params.max}`);
120+}
121+return resolved;
122+}
123+124+function resolveEmbeddingDimensions(embedding: Record<string, unknown>): number | undefined {
125+if (embedding.dimensions === undefined) {
126+return undefined;
127+}
128+const dimensions =
129+typeof embedding.dimensions === "number" ? parseFiniteNumber(embedding.dimensions) : undefined;
130+if (dimensions === undefined || !Number.isInteger(dimensions) || dimensions < 1) {
131+throw new Error("embedding.dimensions must be a positive integer");
132+}
133+return dimensions;
134+}
135+98136export const memoryConfigSchema = {
99137parse(value: unknown): MemoryConfig {
100138if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -126,25 +164,27 @@ export const memoryConfigSchema = {
126164throw new Error("embedding config must include at least one setting");
127165}
128166129-const model = resolveEmbeddingModel(embedding);
167+const dimensions = resolveEmbeddingDimensions(embedding);
168+const model = resolveEmbeddingModel(embedding, dimensions);
130169const provider = typeof embedding.provider === "string" ? embedding.provider.trim() : "openai";
131170if (!provider) {
132171throw new Error("embedding.provider must not be empty");
133172}
134173135-const captureMaxChars =
136-typeof cfg.captureMaxChars === "number" ? Math.floor(cfg.captureMaxChars) : undefined;
137-const recallMaxChars =
138-typeof cfg.recallMaxChars === "number" ? Math.floor(cfg.recallMaxChars) : undefined;
139-if (
140-typeof captureMaxChars === "number" &&
141-(captureMaxChars < 100 || captureMaxChars > 10_000)
142-) {
143-throw new Error("captureMaxChars must be between 100 and 10000");
144-}
145-if (typeof recallMaxChars === "number" && (recallMaxChars < 100 || recallMaxChars > 10_000)) {
146-throw new Error("recallMaxChars must be between 100 and 10000");
147-}
174+const captureMaxChars = resolveBoundedIntegerConfig({
175+value: cfg.captureMaxChars,
176+fallback: DEFAULT_CAPTURE_MAX_CHARS,
177+min: 100,
178+max: 10_000,
179+label: "captureMaxChars",
180+});
181+const recallMaxChars = resolveBoundedIntegerConfig({
182+value: cfg.recallMaxChars,
183+fallback: DEFAULT_RECALL_MAX_CHARS,
184+min: 100,
185+max: 10_000,
186+label: "recallMaxChars",
187+});
148188let customTriggers: string[] | undefined;
149189if (cfg.customTriggers !== undefined) {
150190if (!Array.isArray(cfg.customTriggers)) {
@@ -201,15 +241,15 @@ export const memoryConfigSchema = {
201241apiKey: typeof embedding.apiKey === "string" ? resolveEnvVars(embedding.apiKey) : undefined,
202242baseUrl:
203243typeof embedding.baseUrl === "string" ? resolveEnvVars(embedding.baseUrl) : undefined,
204-dimensions: typeof embedding.dimensions === "number" ? embedding.dimensions : undefined,
244+ dimensions,
205245},
206246 dreaming,
207247dbPath: typeof cfg.dbPath === "string" ? cfg.dbPath : DEFAULT_DB_PATH,
208248autoCapture: cfg.autoCapture === true,
209249autoRecall: cfg.autoRecall !== false,
210-captureMaxChars: captureMaxChars ?? DEFAULT_CAPTURE_MAX_CHARS,
250+ captureMaxChars,
211251 ...(customTriggers ? { customTriggers } : {}),
212-recallMaxChars: recallMaxChars ?? DEFAULT_RECALL_MAX_CHARS,
252+ recallMaxChars,
213253 ...(storageOptions ? { storageOptions } : {}),
214254};
215255},
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。