fix: reliable, self-healing AI feature-bundle installs (#472)

Make on-demand AI feature-bundle installs reliable and self-healing, closing
the failure modes behind most "some tool doesn't work" reports.

Multi-bundle installs: tools needing more than one bundle (Passport Photo,
Enhance Faces) install every required bundle from one action and stay
not-installed until all are present. Verified across all 19 AI tools.

Downloads: self-heal the accelerated Hugging Face (Xet) client so an upgraded
venv no longer silently falls back to slow urllib; restart instead of
corrupting a resumed partial when a proxy ignores Range and returns 200;
verify the completed size; fail fast on disk-full and HTTP 4xx; retry
transient errors five times; add hf_transfer fallback and document Xet egress.

Install integrity: crash-atomic venv writes so a killed or out-of-space
install can no longer tear the shared venv and break other tools; a boot
breadcrumb reseeds a torn venv to a clean state automatically; a post-install
smoke import test refuses to record a bundle whose libraries cannot load; an
install watchdog stops a wedged installer that would otherwise hold the venv
writer lock forever.

Adds unit and end-to-end tests for every failure mode above.
This commit is contained in:
SnapOtter
2026-07-10 07:32:48 +00:00
committed by GitHub
parent ffeacd4b3c
commit a731c3d1fe
33 changed files with 1913 additions and 125 deletions
+52
View File
@@ -341,6 +341,58 @@ describe("useFeaturesStore", () => {
});
});
describe("installTool()", () => {
it("starts every missing hard dependency for a multi-bundle AI tool from one server request", async () => {
const bundles = [
makeBundleState({ id: "background-removal", status: "not_installed" }),
makeBundleState({ id: "face-detection", status: "not_installed" }),
];
useFeaturesStore.setState({ bundles, loaded: true });
apiPostMock.mockResolvedValueOnce({
bundles: [
{ bundleId: "background-removal", jobId: "job-bg", queued: false },
{ bundleId: "face-detection", jobId: "job-face", queued: true },
],
});
await useFeaturesStore.getState().installTool("passport-photo");
expect(apiPostMock).toHaveBeenCalledWith(
"/v1/admin/tools/passport-photo/features/install",
{},
);
expect(FakeEventSource.instances).toHaveLength(1);
expect(FakeEventSource.instances[0].url).toBe("/api/v1/jobs/job-bg/progress");
expect(useFeaturesStore.getState().installing["background-removal"]).toBeDefined();
expect(useFeaturesStore.getState().installing["face-detection"]).toBeUndefined();
expect(useFeaturesStore.getState().queued).toContain("face-detection");
});
it("only tracks missing dependencies when a multi-bundle AI tool is partially installed", async () => {
const bundles = [
makeBundleState({ id: "background-removal", status: "installed" }),
makeBundleState({ id: "face-detection", status: "not_installed" }),
];
useFeaturesStore.setState({ bundles, loaded: true });
apiPostMock.mockResolvedValueOnce({
bundles: [
{ bundleId: "background-removal", skipped: true },
{ bundleId: "face-detection", jobId: "job-face", queued: false },
],
});
await useFeaturesStore.getState().installTool("passport-photo");
expect(apiPostMock).toHaveBeenCalledWith(
"/v1/admin/tools/passport-photo/features/install",
{},
);
expect(useFeaturesStore.getState().installing["background-removal"]).toBeUndefined();
expect(useFeaturesStore.getState().installing["face-detection"]).toBeDefined();
expect(FakeEventSource.instances[0].url).toBe("/api/v1/jobs/job-face/progress");
});
});
describe("uninstallBundle()", () => {
it("calls API and refreshes", async () => {
apiPostMock.mockResolvedValueOnce({});