Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ interface PluginConfig {
apiKey: string | string[];
model?: string;
baseURL?: string;
/** Internal schema/validation dimension (LanceDB + local checks). */
dimensions?: number;
/** Optional provider request dimension (dimensions/output_dimension). */
requestDimensions?: number;
omitDimensions?: boolean;
taskQuery?: string;
taskPassage?: string;
Expand Down Expand Up @@ -1639,7 +1642,10 @@ const memoryLanceDBProPlugin = {
apiKey: config.embedding.apiKey,
model: config.embedding.model || "text-embedding-3-small",
baseURL: config.embedding.baseURL,
// Internal dimension for local schema/validation checks.
dimensions: config.embedding.dimensions,
// Optional request hint sent to providers that support variable dimensions.
requestDimensions: config.embedding.requestDimensions,
omitDimensions: config.embedding.omitDimensions,
taskQuery: config.embedding.taskQuery,
taskPassage: config.embedding.taskPassage,
Expand Down Expand Up @@ -3776,6 +3782,8 @@ export function parsePluginConfig(value: unknown): PluginConfig {
// Accept number, numeric string, or env-var string (e.g. "${EMBED_DIM}").
// Also accept legacy top-level `dimensions` for convenience.
dimensions: parsePositiveInt(embedding.dimensions ?? cfg.dimensions),
// Request dimension is intentionally separate from internal schema sizing.
requestDimensions: parsePositiveInt(embedding.requestDimensions),
omitDimensions:
typeof embedding.omitDimensions === "boolean"
? embedding.omitDimensions
Expand Down
5 changes: 5 additions & 0 deletions openclaw.plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
"type": "integer",
"minimum": 1
},
"requestDimensions": {
"type": "integer",
"minimum": 1,
"description": "Optional output dimension sent to embedding API requests only (for providers supporting variable dimensions)"
},
"omitDimensions": {
"type": "boolean",
"description": "When true, omit the dimensions parameter from embedding requests even if dimensions is configured"
Expand Down
7 changes: 6 additions & 1 deletion src/embedder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ export interface EmbeddingConfig {
apiKey: string | string[];
model: string;
baseURL?: string;
/** Internal vector dimension for schema/validation. This does NOT imply sending API dimensions. */
dimensions?: number;
/** Optional API request output dimension for providers that support variable dimensions. */
requestDimensions?: number;

/** Optional task type for query embeddings (e.g. "retrieval.query") */
taskQuery?: string;
Expand Down Expand Up @@ -428,7 +431,8 @@ export class Embedder {
this._taskQuery = config.taskQuery;
this._taskPassage = config.taskPassage;
this._normalized = config.normalized;
this._requestDimensions = config.dimensions;
// Request-side dimension hint is isolated from internal schema dimension.
this._requestDimensions = config.requestDimensions;
this._omitDimensions = config.omitDimensions === true;
// Enable auto-chunking by default for better handling of long documents
this._autoChunk = config.chunking !== false;
Expand Down Expand Up @@ -472,6 +476,7 @@ export class Embedder {
console.log(`[memory-lancedb-pro] Initialized ${this.clients.length} API keys for round-robin rotation`);
}

// Internal dimension remains the single source of truth for local validation.
this.dimensions = getVectorDimensions(config.model, config.dimensions);
this._cache = new EmbeddingCache(256, 30); // 256 entries, 30 min TTL
}
Expand Down
44 changes: 40 additions & 4 deletions test/plugin-manifest-regression.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ assert.equal(
"boolean",
"embedding.omitDimensions should be declared in the plugin schema",
);
assert.equal(
manifest.configSchema.properties.embedding.properties.requestDimensions?.type,
"integer",
"embedding.requestDimensions should be declared in the plugin schema",
);
assert.equal(
manifest.configSchema.properties.sessionMemory.properties.enabled.default,
false,
Expand Down Expand Up @@ -325,14 +330,44 @@ try {
});
const requestCountBeforeWithDimensions = embeddingRequests.length;
await withDimensionsTool.execute("tool-3", {
text: "dimensions should be sent by default",
text: "dimensions should not be sent by default",
scope: "global",
});
const withDimensionsRequest = embeddingRequests.at(requestCountBeforeWithDimensions);
assert.equal(
withDimensionsRequest?.dimensions,
Object.prototype.hasOwnProperty.call(withDimensionsRequest ?? {}, "dimensions"),
false,
"embedding.dimensions should be used for internal schema sizing, not forwarded by default",
);

const withRequestDimensionsApi = createMockApi({
dbPath: path.join(workDir, "db-with-request-dimensions"),
autoCapture: false,
autoRecall: false,
embedding: {
provider: "openai-compatible",
apiKey: "dummy",
model: "text-embedding-3-small",
baseURL: embeddingBaseURL,
dimensions: 4,
requestDimensions: 4,
},
});
plugin.register(withRequestDimensionsApi);
const withRequestDimensionsTool = withRequestDimensionsApi.toolFactories.memory_store({
agentId: "main",
sessionKey: "agent:main:test",
});
const requestCountBeforeRequestDimensions = embeddingRequests.length;
await withRequestDimensionsTool.execute("tool-3b", {
text: "requestDimensions should be forwarded",
scope: "global",
});
const withRequestDimensionsRequest = embeddingRequests.at(requestCountBeforeRequestDimensions);
assert.equal(
withRequestDimensionsRequest?.dimensions,
4,
"embedding.dimensions should be forwarded by default",
"embedding.requestDimensions should be forwarded to embedding requests",
);

const omitDimensionsApi = createMockApi({
Expand All @@ -345,6 +380,7 @@ try {
model: "text-embedding-3-small",
baseURL: embeddingBaseURL,
dimensions: 4,
requestDimensions: 4,
omitDimensions: true,
},
});
Expand All @@ -362,7 +398,7 @@ try {
assert.equal(
Object.prototype.hasOwnProperty.call(omitDimensionsRequest, "dimensions"),
false,
"embedding.omitDimensions=true should omit dimensions from embedding requests",
"embedding.omitDimensions=true should omit dimensions from embedding requests even when requestDimensions is set",
);
} finally {
await new Promise((resolve) => embeddingServer.close(resolve));
Expand Down