fix(memory): retry reindex on socket errors

This commit is contained in:
clawsweeper
2026-05-03 03:12:34 +00:00
parent d0652304f7
commit b4618c4532
2 changed files with 1 additions and 56 deletions

View File

@@ -25,7 +25,7 @@ Docs: https://docs.openclaw.ai
- Auto-reply/queue: treat reset-triggered `/new` and `/reset` turns as interrupt runs across active-run queue handling, so steer/followup modes cannot delay a fresh session behind existing work. Fixes #74093. (#74144) Thanks @ruji9527 and @yelog.
- Cron: preserve manual `cron.run` IDs in `cron.runs` history so manual run acknowledgements can be correlated with finished run records. Fixes #76276.
- CLI/devices: request `operator.admin` for `openclaw devices approve <requestId>` only when the exact pending device request would mint or inherit admin-scoped operator access, while keeping lower-scope approvals on the pairing scope.
- Memory/embedding: broaden the embedding reindex retry classifier to include transient socket-layer errors (`fetch failed`, `ECONNRESET`, `socket hang up`, `UND_ERR_*`, `closed`) so memory reindex survives provider network hiccups instead of aborting mid-run. Related #56815, #44166.
- Memory/embedding: broaden the embedding reindex retry classifier to include transient socket-layer errors (`fetch failed`, `ECONNRESET`, `socket hang up`, `UND_ERR_*`, `closed`) so memory reindex survives provider network hiccups instead of aborting mid-run. Related #56815, #44166. (#76311) Thanks @buyitsydney.
- Gateway: keep directly requested plugin tools invokable under restrictive tool profiles while preserving explicit deny lists and the HTTP safety deny list, preventing catalog/invoke mismatches that surface as "Tool not available". Thanks @BunsDev.
- Gateway/update: allow beta binaries to refresh gateway services when the config was last written by the matching stable release version, avoiding false newer-config downgrade blocks during beta channel updates.
- Channels: keep Matrix and Mattermost bundled in the core package instead of advertising external npm installs before those channels are cut over. Thanks @vincentkoc.

View File

@@ -1,5 +1,4 @@
import fsSync from "node:fs";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -101,7 +100,6 @@ describe("buildSessionEntry", () => {
// Content line 2 → JSONL line 7 (the second user message)
expect(entry!.lineMap).toBeDefined();
expect(entry!.lineMap).toEqual([4, 6, 7]);
expect(entry!.messageTimestampsMs).toEqual([0, 0, 0]);
});
it("returns empty lineMap when no messages are found", async () => {
@@ -116,7 +114,6 @@ describe("buildSessionEntry", () => {
expect(entry).not.toBeNull();
expect(entry!.content).toBe("");
expect(entry!.lineMap).toEqual([]);
expect(entry!.messageTimestampsMs).toEqual([]);
});
it("skips deleted and checkpoint transcripts for dreaming ingestion", async () => {
@@ -157,58 +154,6 @@ describe("buildSessionEntry", () => {
const entry = await buildSessionEntry(filePath);
expect(entry).not.toBeNull();
expect(entry!.lineMap).toEqual([3, 5]);
expect(entry!.messageTimestampsMs).toEqual([0, 0]);
});
it("captures message timestamps when present", async () => {
const jsonlLines = [
JSON.stringify({
type: "message",
timestamp: "2026-04-05T10:00:00.000Z",
message: { role: "user", content: "First" },
}),
JSON.stringify({
type: "message",
message: {
role: "assistant",
timestamp: "2026-04-05T10:01:00.000Z",
content: "Second",
},
}),
];
const filePath = path.join(tmpDir, "timestamps.jsonl");
await fs.writeFile(filePath, jsonlLines.join("\n"));
const entry = await buildSessionEntry(filePath);
expect(entry).not.toBeNull();
expect(entry!.messageTimestampsMs).toEqual([
Date.parse("2026-04-05T10:00:00.000Z"),
Date.parse("2026-04-05T10:01:00.000Z"),
]);
});
it("flags dreaming narrative transcripts from bootstrap metadata", async () => {
const jsonlLines = [
JSON.stringify({
type: "custom",
customType: "openclaw:bootstrap-context:full",
data: {
runId: "dreaming-narrative-light-1775894400455",
sessionId: "sid-1",
},
}),
JSON.stringify({
type: "message",
message: { role: "user", content: "Write a dream diary entry from these memory fragments" },
}),
];
const filePath = path.join(tmpDir, "dreaming-session.jsonl");
await fs.writeFile(filePath, jsonlLines.join("\n"));
const entry = await buildSessionEntry(filePath);
expect(entry).not.toBeNull();
expect(entry?.generatedByDreamingNarrative).toBe(true);
});
it("strips inbound metadata when a user envelope is split across text blocks", async () => {