fix: harden gateway recovery diagnostics and media delivery

Harden gateway recovery diagnostics and media delivery.\n\n- Accept gateway send asVoice and map it to outbound audioAsVoice.\n- Preserve generated Swift protocol models for the gateway send schema.\n- Keep the broader recovery hardening for install/update/status/vector/TTS paths in one reviewed PR.\n\nProof:\n- Focused local gateway/outbound/update/status/doctor/sqlite-vec tests passed.\n- oxfmt --check and git diff --check passed.\n- Testbox OPENCLAW_TESTBOX=1 pnpm check:changed passed at 2f5ef650e97763a61ff43c28e61707db84c50060.\n- GitHub required checks are green at the merge SHA; the qa-lab parity gate is optional/surface-only and was still pending.
This commit is contained in:
Val Alexander
2026-04-30 21:46:22 -05:00
committed by GitHub
parent 98d87b06e0
commit df0ee092f0
27 changed files with 647 additions and 15 deletions

View File

@@ -0,0 +1,25 @@
import { describe, expect, it, vi } from "vitest";
vi.mock("sqlite-vec", () => {
throw new Error("bundled sqlite-vec should not load when extensionPath is explicit");
});
import { loadSqliteVecExtension } from "./sqlite-vec.js";
describe("loadSqliteVecExtension", () => {
it("loads explicit extensionPath without importing bundled sqlite-vec", async () => {
const db = {
enableLoadExtension: vi.fn(),
loadExtension: vi.fn(),
};
await expect(
loadSqliteVecExtension({
db: db as never,
extensionPath: "/opt/openclaw/sqlite-vec.so",
}),
).resolves.toEqual({ ok: true, extensionPath: "/opt/openclaw/sqlite-vec.so" });
expect(db.enableLoadExtension).toHaveBeenCalledWith(true);
expect(db.loadExtension).toHaveBeenCalledWith("/opt/openclaw/sqlite-vec.so");
});
});

View File

@@ -18,17 +18,16 @@ export async function loadSqliteVecExtension(params: {
extensionPath?: string;
}): Promise<{ ok: boolean; extensionPath?: string; error?: string }> {
try {
const sqliteVec = await loadSqliteVecModule();
const resolvedPath = normalizeOptionalString(params.extensionPath);
const extensionPath = resolvedPath ?? sqliteVec.getLoadablePath();
params.db.enableLoadExtension(true);
if (resolvedPath) {
params.db.loadExtension(extensionPath);
} else {
sqliteVec.load(params.db);
params.db.loadExtension(resolvedPath);
return { ok: true, extensionPath: resolvedPath };
}
const sqliteVec = await loadSqliteVecModule();
const extensionPath = sqliteVec.getLoadablePath();
sqliteVec.load(params.db);
return { ok: true, extensionPath };
} catch (err) {
const message = formatErrorMessage(err);