Skip to content

Commit 5465bce

Browse files
committed
fix(memory): avoid bang guard lint false positive
1 parent 0d307d3 commit 5465bce

2 files changed

Lines changed: 38 additions & 23 deletions

File tree

extensions/memory-core/src/memory/manager-embedding-ops.ts

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
type MemorySource,
2020
} from "openclaw/plugin-sdk/memory-core-host-engine-storage";
2121
import { MAX_TIMER_TIMEOUT_MS, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
22+
import type { EmbeddingProvider } from "./embeddings.js";
2223
import {
2324
MEMORY_BATCH_FAILURE_LIMIT,
2425
recordMemoryBatchFailure,
@@ -74,6 +75,7 @@ function resolveEmbeddingSecondsTimeoutMs(seconds: number): number {
7475
}
7576

7677
type MemoryIndexEntry = MemoryIndexWorkItem["entry"];
78+
type MemoryEmbeddingBatchFn = NonNullable<MemoryEmbeddingProviderRuntime["batchEmbed"]>;
7779

7880
type PreparedMemoryIndexEntry = {
7981
entry: MemoryIndexEntry;
@@ -304,19 +306,15 @@ export abstract class MemoryManagerEmbeddingOps extends MemoryManagerSyncOps {
304306

305307
private async embedChunksWithBatch(
306308
chunks: MemoryChunk[],
309+
provider: EmbeddingProvider,
310+
batchEmbed: MemoryEmbeddingBatchFn,
307311
_entry: MemoryIndexEntry,
308312
source: string,
309313
debugContext: Record<string, unknown> = {},
310314
): Promise<number[][]> {
311-
const provider = this.provider;
312-
const batchEmbed = this.providerRuntime?.batchEmbed;
313-
if (!provider || !batchEmbed) {
314-
return this.embedChunksInBatches(chunks);
315-
}
316-
if (chunks.length === 0) {
317-
return [];
318-
}
319-
const { embeddings, missing } = this.collectCachedEmbeddings(chunks);
315+
const cached = this.collectCachedEmbeddings(chunks);
316+
// oxlint-disable-next-line typescript/no-unnecessary-type-assertion -- Node 24 CI oxlint misreports this cache result destructuring; keep the suppression scoped to the no-op assertion.
317+
const { embeddings, missing } = cached as typeof cached;
320318
if (missing.length === 0) {
321319
return embeddings;
322320
}
@@ -888,13 +886,20 @@ export abstract class MemoryManagerEmbeddingOps extends MemoryManagerSyncOps {
888886
for (let requestIndex = 0; requestIndex < chunkBatches.length; requestIndex += 1) {
889887
const chunkBatch = chunkBatches[requestIndex] ?? [];
890888
embeddings.push(
891-
...(await this.embedChunksWithBatch(chunkBatch, firstEntry, source, {
892-
sourceWideFiles: current.length,
893-
sourceWideSources: sourceCounts,
894-
sourceWideBatchGroup,
895-
sourceWideRequestGroup: requestIndex + 1,
896-
sourceWideRequestGroups: chunkBatches.length,
897-
})),
889+
...(await this.embedChunksWithBatch(
890+
chunkBatch,
891+
provider,
892+
batchEmbed,
893+
firstEntry,
894+
source,
895+
{
896+
sourceWideFiles: current.length,
897+
sourceWideSources: sourceCounts,
898+
sourceWideBatchGroup,
899+
sourceWideRequestGroup: requestIndex + 1,
900+
sourceWideRequestGroups: chunkBatches.length,
901+
},
902+
)),
898903
);
899904
}
900905
const sample = embeddings.find((embedding) => embedding.length > 0);
@@ -950,7 +955,8 @@ export abstract class MemoryManagerEmbeddingOps extends MemoryManagerSyncOps {
950955
options: { source: MemorySource; content?: string },
951956
) {
952957
// FTS-only mode: no embedding provider, but we can still build a FTS index
953-
if (!this.provider) {
958+
const provider = this.provider;
959+
if (!provider) {
954960
// Multimodal files require an embedding provider; skip in FTS-only mode.
955961
if ("kind" in entry && entry.kind === "multimodal") {
956962
return;
@@ -967,9 +973,17 @@ export abstract class MemoryManagerEmbeddingOps extends MemoryManagerSyncOps {
967973

968974
let embeddings: number[][];
969975
try {
970-
embeddings = this.batch.enabled
971-
? await this.embedChunksWithBatch(prepared.chunks, entry, options.source)
972-
: await this.embedChunksInBatches(prepared.chunks);
976+
const batchEmbed = this.providerRuntime?.batchEmbed;
977+
embeddings =
978+
this.batch.enabled && batchEmbed
979+
? await this.embedChunksWithBatch(
980+
prepared.chunks,
981+
provider,
982+
batchEmbed,
983+
entry,
984+
options.source,
985+
)
986+
: await this.embedChunksInBatches(prepared.chunks);
973987
} catch (err) {
974988
const message = formatErrorMessage(err);
975989
if (
@@ -982,8 +996,8 @@ export abstract class MemoryManagerEmbeddingOps extends MemoryManagerSyncOps {
982996
log.warn("memory embeddings: skipping multimodal file rejected as too large", {
983997
path: entry.path,
984998
bytes: prepared.structuredInputBytes,
985-
provider: this.provider.id,
986-
model: this.provider.model,
999+
provider: provider.id,
1000+
model: provider.model,
9871001
error: message,
9881002
});
9891003
this.clearIndexedFileData(entry.path, options.source);
@@ -997,7 +1011,7 @@ export abstract class MemoryManagerEmbeddingOps extends MemoryManagerSyncOps {
9971011
this.writeChunks(
9981012
entry,
9991013
options.source,
1000-
this.provider.model,
1014+
provider.model,
10011015
prepared.chunks,
10021016
embeddings,
10031017
vectorReady,

test/scripts/lint-suppressions.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ describe("production lint suppressions", () => {
192192
"extensions/discord/src/test-support/provider.test-support.ts|typescript/no-unnecessary-type-parameters|1",
193193
"extensions/feishu/src/bitable.ts|typescript/no-unnecessary-type-parameters|1",
194194
"extensions/matrix/src/onboarding.test-harness.ts|typescript/no-unnecessary-type-parameters|1",
195+
"extensions/memory-core/src/memory/manager-embedding-ops.ts|typescript/no-unnecessary-type-assertion|1",
195196
"extensions/slack/src/monitor/provider-support.ts|typescript/no-unnecessary-type-parameters|1",
196197
"src/channels/plugins/channel-runtime-surface.types.ts|typescript/no-unnecessary-type-parameters|1",
197198
"src/channels/plugins/contracts/test-helpers.ts|typescript/no-unnecessary-type-parameters|1",

0 commit comments

Comments
 (0)