fix: avoid crash on memory embeddings errors (#1004)
This commit is contained in:
@@ -60,6 +60,7 @@ Docs: https://docs.clawd.bot
|
|||||||
- Sessions: propagate deliveryContext into last-route updates to keep account/channel routing stable. (#1058)
|
- Sessions: propagate deliveryContext into last-route updates to keep account/channel routing stable. (#1058)
|
||||||
- Sessions: preserve overrides on `/new` reset.
|
- Sessions: preserve overrides on `/new` reset.
|
||||||
- Memory: prevent unhandled rejections when watch/interval sync fails. (#1076) — thanks @roshanasingh4.
|
- Memory: prevent unhandled rejections when watch/interval sync fails. (#1076) — thanks @roshanasingh4.
|
||||||
|
- Memory: avoid gateway crash when embeddings return 429/insufficient_quota (disable tool + surface error). (#1004)
|
||||||
- Gateway: honor explicit delivery targets without implicit accountId fallback; preserve lastAccountId for implicit routing.
|
- Gateway: honor explicit delivery targets without implicit accountId fallback; preserve lastAccountId for implicit routing.
|
||||||
- Gateway: avoid reusing last-to/accountId when the requested channel differs; sync deliveryContext with last route fields.
|
- Gateway: avoid reusing last-to/accountId when the requested channel differs; sync deliveryContext with last route fields.
|
||||||
- Build: allow `@lydell/node-pty` builds on supported platforms.
|
- Build: allow `@lydell/node-pty` builds on supported platforms.
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
vi.mock("../../memory/index.js", () => {
|
||||||
|
return {
|
||||||
|
getMemorySearchManager: async () => {
|
||||||
|
return {
|
||||||
|
manager: {
|
||||||
|
search: async () => {
|
||||||
|
throw new Error("openai embeddings failed: 429 insufficient_quota");
|
||||||
|
},
|
||||||
|
readFile: async () => {
|
||||||
|
throw new Error("path required");
|
||||||
|
},
|
||||||
|
status: () => ({
|
||||||
|
files: 0,
|
||||||
|
chunks: 0,
|
||||||
|
dirty: true,
|
||||||
|
workspaceDir: "/tmp",
|
||||||
|
dbPath: "/tmp/index.sqlite",
|
||||||
|
provider: "openai",
|
||||||
|
model: "text-embedding-3-small",
|
||||||
|
requestedProvider: "openai",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
import { createMemoryGetTool, createMemorySearchTool } from "./memory-tool.js";
|
||||||
|
|
||||||
|
describe("memory tools", () => {
|
||||||
|
it("does not throw when memory_search fails (e.g. embeddings 429)", async () => {
|
||||||
|
const cfg = { agents: { list: [{ id: "main", default: true }] } };
|
||||||
|
const tool = createMemorySearchTool({ config: cfg });
|
||||||
|
expect(tool).not.toBeNull();
|
||||||
|
if (!tool) throw new Error("tool missing");
|
||||||
|
|
||||||
|
const result = await tool.execute("call_1", { query: "hello" });
|
||||||
|
expect(result.details).toEqual({
|
||||||
|
results: [],
|
||||||
|
disabled: true,
|
||||||
|
error: "openai embeddings failed: 429 insufficient_quota",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not throw when memory_get fails", async () => {
|
||||||
|
const cfg = { agents: { list: [{ id: "main", default: true }] } };
|
||||||
|
const tool = createMemoryGetTool({ config: cfg });
|
||||||
|
expect(tool).not.toBeNull();
|
||||||
|
if (!tool) throw new Error("tool missing");
|
||||||
|
|
||||||
|
const result = await tool.execute("call_2", { path: "memory/NOPE.md" });
|
||||||
|
expect(result.details).toEqual({
|
||||||
|
path: "memory/NOPE.md",
|
||||||
|
text: "",
|
||||||
|
disabled: true,
|
||||||
|
error: "path required",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
@@ -47,18 +47,23 @@ export function createMemorySearchTool(options: {
|
|||||||
if (!manager) {
|
if (!manager) {
|
||||||
return jsonResult({ results: [], disabled: true, error });
|
return jsonResult({ results: [], disabled: true, error });
|
||||||
}
|
}
|
||||||
const results = await manager.search(query, {
|
try {
|
||||||
maxResults,
|
const results = await manager.search(query, {
|
||||||
minScore,
|
maxResults,
|
||||||
sessionKey: options.agentSessionKey,
|
minScore,
|
||||||
});
|
sessionKey: options.agentSessionKey,
|
||||||
const status = manager.status();
|
});
|
||||||
return jsonResult({
|
const status = manager.status();
|
||||||
results,
|
return jsonResult({
|
||||||
provider: status.provider,
|
results,
|
||||||
model: status.model,
|
provider: status.provider,
|
||||||
fallback: status.fallback,
|
model: status.model,
|
||||||
});
|
fallback: status.fallback,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
|
return jsonResult({ results: [], disabled: true, error: message });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -91,12 +96,17 @@ export function createMemoryGetTool(options: {
|
|||||||
if (!manager) {
|
if (!manager) {
|
||||||
return jsonResult({ path: relPath, text: "", disabled: true, error });
|
return jsonResult({ path: relPath, text: "", disabled: true, error });
|
||||||
}
|
}
|
||||||
const result = await manager.readFile({
|
try {
|
||||||
relPath,
|
const result = await manager.readFile({
|
||||||
from: from ?? undefined,
|
relPath,
|
||||||
lines: lines ?? undefined,
|
from: from ?? undefined,
|
||||||
});
|
lines: lines ?? undefined,
|
||||||
return jsonResult(result);
|
});
|
||||||
|
return jsonResult(result);
|
||||||
|
} catch (err) {
|
||||||
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
|
return jsonResult({ path: relPath, text: "", disabled: true, error: message });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,8 +75,14 @@ export function registerMemoryCli(program: Command) {
|
|||||||
defaultRuntime.log(error ?? "Memory search disabled.");
|
defaultRuntime.log(error ?? "Memory search disabled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await manager.sync({ reason: "cli", force: opts.force });
|
try {
|
||||||
defaultRuntime.log("Memory index updated.");
|
await manager.sync({ reason: "cli", force: opts.force });
|
||||||
|
defaultRuntime.log("Memory index updated.");
|
||||||
|
} catch (err) {
|
||||||
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
|
defaultRuntime.error(`Memory index failed: ${message}`);
|
||||||
|
process.exitCode = 1;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
memory
|
memory
|
||||||
@@ -105,10 +111,18 @@ export function registerMemoryCli(program: Command) {
|
|||||||
defaultRuntime.log(error ?? "Memory search disabled.");
|
defaultRuntime.log(error ?? "Memory search disabled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const results = await manager.search(query, {
|
let results: Awaited<ReturnType<typeof manager.search>>;
|
||||||
maxResults: opts.maxResults,
|
try {
|
||||||
minScore: opts.minScore,
|
results = await manager.search(query, {
|
||||||
});
|
maxResults: opts.maxResults,
|
||||||
|
minScore: opts.minScore,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
|
defaultRuntime.error(`Memory search failed: ${message}`);
|
||||||
|
process.exitCode = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (opts.json) {
|
if (opts.json) {
|
||||||
defaultRuntime.log(JSON.stringify({ results }, null, 2));
|
defaultRuntime.log(JSON.stringify({ results }, null, 2));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -178,4 +178,10 @@ async function main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void main();
|
void main().catch((err) => {
|
||||||
|
console.error(
|
||||||
|
"[clawdbot] Gateway daemon failed:",
|
||||||
|
err instanceof Error ? (err.stack ?? err.message) : err,
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|||||||
@@ -70,4 +70,7 @@ async function main() {
|
|||||||
await program.parseAsync(process.argv);
|
await program.parseAsync(process.argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main();
|
void main().catch((err) => {
|
||||||
|
console.error("[clawdbot] Relay failed:", err instanceof Error ? (err.stack ?? err.message) : err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user