mirror of https://github.com/openclaw/openclaw.git
fix(memory-qmd): restore qmd compatibility defaults
This commit is contained in:
parent
ca462fb928
commit
098f4eeebb
|
|
@ -125,6 +125,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Discord: keep REST, webhook, and monitor traffic on the configured proxy, preserve component-only media sends, honor `@everyone` and `@here` mention gates, keep ACK reactions on the active account, and split voice connect/playback timeouts so auto-join is more reliable. (#57465, #60361, #60345) Thanks @geekhuashan.
|
||||
- WhatsApp: restore `channels.whatsapp.blockStreaming` and reset watchdog timeouts after reconnect so quiet chats stop falling into reconnect loops. (#60007, #60069) Thanks @MonkeyLeeT and @mcaxtr.
|
||||
- Memory: keep `memory-core` builtin embedding registration on the already-registered path so selecting `memory-core` no longer recurses through plugin discovery and crashes during startup. (#61402) Thanks @ngutman.
|
||||
- Memory/QMD: prefer modern `qmd collection add --glob`, accept newer single-line JSON hit metadata while keeping legacy line fields, and refresh QMD docs/model-override guidance without breaking older QMD releases. Thanks @vincentkoc.
|
||||
- MS Teams: download inline DM images via Graph API and preserve channel reply threading in proactive fallback. (#52212, #55198) Thanks @Ted-developer and @hyojin.
|
||||
- MS Teams: replace the deprecated Teams SDK HttpPlugin stub with `httpServerAdapter` so recurring gateway deprecation warnings stop firing and the Express 5 compatibility workaround stays on the supported SDK path. (#60939) Thanks @coolramukaka-sys.
|
||||
- Matrix/exec approvals: anchor seeded approval reactions to the primary Matrix prompt event, resolve them from event metadata instead of prompt text, and clean up chunked approval prompts correctly. (#60931) Thanks @gumadeiras.
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ binary, and can index content beyond your workspace memory files.
|
|||
|
||||
### Prerequisites
|
||||
|
||||
- Install QMD: `bun install -g @tobilu/qmd`
|
||||
- Install QMD: `npm install -g @tobilu/qmd` or `bun install -g @tobilu/qmd`
|
||||
- SQLite build that allows extensions (`brew install sqlite` on macOS).
|
||||
- QMD must be on the gateway's `PATH`.
|
||||
- macOS and Linux work out of the box. Windows is best supported via WSL2.
|
||||
|
|
@ -43,6 +43,8 @@ binary, and can index content beyond your workspace memory files.
|
|||
OpenClaw creates a self-contained QMD home under
|
||||
`~/.openclaw/agents/<agentId>/qmd/` and manages the sidecar lifecycle
|
||||
automatically -- collections, updates, and embedding runs are handled for you.
|
||||
It prefers current QMD collection and MCP query shapes, but still falls back to
|
||||
legacy `--mask` collection flags and older MCP tool names when needed.
|
||||
|
||||
## How the sidecar works
|
||||
|
||||
|
|
@ -59,6 +61,20 @@ The first search may be slow -- QMD auto-downloads GGUF models (~2 GB) for
|
|||
reranking and query expansion on the first `qmd query` run.
|
||||
</Info>
|
||||
|
||||
## Model overrides
|
||||
|
||||
QMD model environment variables pass through unchanged from the gateway
|
||||
process, so you can tune QMD globally without adding new OpenClaw config:
|
||||
|
||||
```bash
|
||||
export QMD_EMBED_MODEL="hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf"
|
||||
export QMD_RERANK_MODEL="/absolute/path/to/reranker.gguf"
|
||||
export QMD_GENERATE_MODEL="/absolute/path/to/generator.gguf"
|
||||
```
|
||||
|
||||
After changing the embedding model, rerun embeddings so the index matches the
|
||||
new vector space.
|
||||
|
||||
## Indexing extra paths
|
||||
|
||||
Point QMD at additional directories to make them searchable:
|
||||
|
|
|
|||
|
|
@ -377,6 +377,15 @@ Set `memory.backend = "qmd"` to enable. All QMD settings live under
|
|||
| `sessions.retentionDays` | `number` | -- | Transcript retention |
|
||||
| `sessions.exportDir` | `string` | -- | Export directory |
|
||||
|
||||
OpenClaw prefers the current QMD collection and MCP query shapes, but keeps
|
||||
older QMD releases working by falling back to legacy `--mask` collection flags
|
||||
and older MCP tool names when needed.
|
||||
|
||||
QMD model overrides stay on the QMD side, not OpenClaw config. If you need to
|
||||
override QMD's models globally, set environment variables such as
|
||||
`QMD_EMBED_MODEL`, `QMD_RERANK_MODEL`, and `QMD_GENERATE_MODEL` in the gateway
|
||||
runtime environment.
|
||||
|
||||
### Update schedule
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|
|
|
|||
|
|
@ -895,7 +895,7 @@ describe("QmdMemoryManager", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("prefers --mask for collection add and falls back to --glob when --mask is rejected", async () => {
|
||||
it("prefers --glob for collection add and falls back to --mask when --glob is rejected", async () => {
|
||||
cfg = {
|
||||
...cfg,
|
||||
memory: {
|
||||
|
|
@ -917,10 +917,10 @@ describe("QmdMemoryManager", () => {
|
|||
}
|
||||
if (args[0] === "collection" && args[1] === "add") {
|
||||
const child = createMockChild({ autoClose: false });
|
||||
const flag = args.includes("--mask") ? "--mask" : args.includes("--glob") ? "--glob" : "";
|
||||
const flag = args.includes("--glob") ? "--glob" : args.includes("--mask") ? "--mask" : "";
|
||||
addFlagCalls.push(flag);
|
||||
if (flag === "--mask") {
|
||||
emitAndClose(child, "stderr", "unknown flag: --mask", 1);
|
||||
if (flag === "--glob") {
|
||||
emitAndClose(child, "stderr", "unknown flag: --glob", 1);
|
||||
return child;
|
||||
}
|
||||
queueMicrotask(() => child.closeWith(0));
|
||||
|
|
@ -932,7 +932,7 @@ describe("QmdMemoryManager", () => {
|
|||
const { manager } = await createManager({ mode: "full" });
|
||||
await manager.close();
|
||||
|
||||
expect(addFlagCalls).toEqual(["--mask", "--glob", "--glob", "--glob"]);
|
||||
expect(addFlagCalls).toEqual(["--glob", "--mask", "--mask", "--mask"]);
|
||||
expect(logWarnMock).toHaveBeenCalledWith(
|
||||
expect.stringContaining("retrying with legacy compatibility flag"),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ export class QmdMemoryManager implements MemorySearchManager {
|
|||
private attemptedNullByteCollectionRepair = false;
|
||||
private attemptedDuplicateDocumentRepair = false;
|
||||
private readonly sessionWarm = new Set<string>();
|
||||
private collectionPatternFlag: QmdCollectionPatternFlag | null = "--mask";
|
||||
private collectionPatternFlag: QmdCollectionPatternFlag | null = "--glob";
|
||||
|
||||
private constructor(params: {
|
||||
cfg: OpenClawConfig;
|
||||
|
|
@ -653,7 +653,7 @@ export class QmdMemoryManager implements MemorySearchManager {
|
|||
|
||||
private async addCollection(pathArg: string, name: string, pattern: string): Promise<void> {
|
||||
const candidateFlags: QmdCollectionPatternFlag[] =
|
||||
this.collectionPatternFlag === "--mask" ? ["--mask", "--glob"] : ["--glob", "--mask"];
|
||||
this.collectionPatternFlag === "--glob" ? ["--glob", "--mask"] : ["--mask", "--glob"];
|
||||
let lastError: unknown;
|
||||
for (const flag of candidateFlags) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,18 @@ complete`,
|
|||
]);
|
||||
});
|
||||
|
||||
it("maps single-line qmd line metadata onto both line bounds", () => {
|
||||
const results = parseQmdQueryJson('[{"docid":"abc","score":0.5,"line":9}]', "");
|
||||
expect(results).toEqual([
|
||||
{
|
||||
docid: "abc",
|
||||
score: 0.5,
|
||||
startLine: 9,
|
||||
endLine: 9,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("treats plain-text no-results from stderr as an empty result set", () => {
|
||||
const results = parseQmdQueryJson("", "No results found\n");
|
||||
expect(results).toEqual([]);
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ function parseQmdQueryResultArray(raw: string): QmdQueryResult[] | null {
|
|||
const file = typeof record.file === "string" ? record.file : undefined;
|
||||
const snippet = typeof record.snippet === "string" ? record.snippet : undefined;
|
||||
const body = typeof record.body === "string" ? record.body : undefined;
|
||||
const line = parseQmdLineNumber(record.line);
|
||||
const startLine = parseQmdLineNumber(record.start_line ?? record.startLine) ?? line;
|
||||
const endLine = parseQmdLineNumber(record.end_line ?? record.endLine) ?? line;
|
||||
return {
|
||||
docid,
|
||||
score,
|
||||
|
|
@ -96,8 +99,8 @@ function parseQmdQueryResultArray(raw: string): QmdQueryResult[] | null {
|
|||
file,
|
||||
snippet,
|
||||
body,
|
||||
startLine: parseQmdLineNumber(record.start_line ?? record.startLine),
|
||||
endLine: parseQmdLineNumber(record.end_line ?? record.endLine),
|
||||
startLine,
|
||||
endLine,
|
||||
} as QmdQueryResult;
|
||||
});
|
||||
} catch {
|
||||
|
|
|
|||
Loading…
Reference in New Issue