feat: make AI tools pipeline-compatible and add search to tool picker

Register remove-background, upscale, and blur-faces in the pipeline
tool registry via registerToolProcessFn(). These tools keep their
custom HTTP routes (with progress callbacks) for direct use, but now
also provide a simple process function for pipeline/batch execution.

Add a search bar to the pipeline tool picker so users can quickly
find tools by name or description. Uses the existing SearchBar
component and the same filtering pattern as the main tool panel.

Update tests to reflect that these 3 AI tools are now pipeline-
compatible (moved from excluded to included assertions).
This commit is contained in:
Siddharth Kumar Sah
2026-03-28 15:09:23 +08:00
parent 6d14e83dcb
commit c48bfba879
6 changed files with 133 additions and 32 deletions
+10 -2
View File
@@ -49,13 +49,21 @@ export function getToolConfig(toolId: string): AnyToolRouteConfig | undefined {
}
/**
* Return the IDs of all tools registered via createToolRoute().
* These are the tools that can be used in pipelines and batch processing.
* Return the IDs of all tools in the pipeline/batch registry.
*/
export function getRegisteredToolIds(): string[] {
return [...toolRegistry.keys()];
}
/**
* Register a tool's process function in the pipeline/batch registry
* without creating an HTTP route. Use this for tools that have their
* own custom HTTP route but should still be usable in pipelines.
*/
export function registerToolProcessFn(config: AnyToolRouteConfig): void {
toolRegistry.set(config.toolId, config);
}
/**
* Factory that registers a POST /api/v1/tools/:toolId route.
*
+24
View File
@@ -3,10 +3,12 @@ import { writeFile } from "node:fs/promises";
import { basename, join } from "node:path";
import { blurFaces } from "@stirling-image/ai";
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import { autoOrient } from "../../lib/auto-orient.js";
import { validateImageBuffer } from "../../lib/file-validation.js";
import { createWorkspace } from "../../lib/workspace.js";
import { updateSingleFileProgress } from "../progress.js";
import { registerToolProcessFn } from "../tool-factory.js";
/**
* Face detection and blurring route.
@@ -115,4 +117,26 @@ export function registerBlurFaces(app: FastifyInstance) {
});
}
});
// Register in the pipeline/batch registry so this tool can be used
// as a step in automation pipelines (without progress callbacks).
registerToolProcessFn({
toolId: "blur-faces",
settingsSchema: z.object({
blurRadius: z.number().min(1).max(100).default(30),
sensitivity: z.number().min(0).max(1).default(0.5),
}),
process: async (inputBuffer, settings, filename) => {
const s = settings as { blurRadius?: number; sensitivity?: number };
const orientedBuffer = await autoOrient(inputBuffer);
const jobId = randomUUID();
const workspacePath = await createWorkspace(jobId);
const result = await blurFaces(orientedBuffer, join(workspacePath, "output"), {
blurRadius: s.blurRadius ?? 30,
sensitivity: s.sensitivity ?? 0.5,
});
const outputFilename = `${filename.replace(/\.[^.]+$/, "")}_blurred.png`;
return { buffer: result.buffer, filename: outputFilename, contentType: "image/png" };
},
});
}
@@ -3,9 +3,11 @@ import { writeFile } from "node:fs/promises";
import { basename, join } from "node:path";
import { removeBackground } from "@stirling-image/ai";
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import { validateImageBuffer } from "../../lib/file-validation.js";
import { createWorkspace } from "../../lib/workspace.js";
import { updateSingleFileProgress } from "../progress.js";
import { registerToolProcessFn } from "../tool-factory.js";
/**
* AI background removal route.
@@ -108,4 +110,25 @@ export function registerRemoveBackground(app: FastifyInstance) {
}
},
);
// Register in the pipeline/batch registry so this tool can be used
// as a step in automation pipelines (without progress callbacks).
registerToolProcessFn({
toolId: "remove-background",
settingsSchema: z.object({
model: z.string().optional(),
backgroundColor: z.string().optional(),
}),
process: async (inputBuffer, settings, filename) => {
const s = settings as { model?: string; backgroundColor?: string };
const jobId = randomUUID();
const workspacePath = await createWorkspace(jobId);
const resultBuffer = await removeBackground(inputBuffer, join(workspacePath, "output"), {
model: s.model,
backgroundColor: s.backgroundColor,
});
const outputFilename = `${filename.replace(/\.[^.]+$/, "")}_nobg.png`;
return { buffer: resultBuffer, filename: outputFilename, contentType: "image/png" };
},
});
}
+20
View File
@@ -3,10 +3,12 @@ import { writeFile } from "node:fs/promises";
import { basename, join } from "node:path";
import { upscale } from "@stirling-image/ai";
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import { autoOrient } from "../../lib/auto-orient.js";
import { validateImageBuffer } from "../../lib/file-validation.js";
import { createWorkspace } from "../../lib/workspace.js";
import { updateSingleFileProgress } from "../progress.js";
import { registerToolProcessFn } from "../tool-factory.js";
/**
* AI image upscaling route.
@@ -114,4 +116,22 @@ export function registerUpscale(app: FastifyInstance) {
});
}
});
// Register in the pipeline/batch registry so this tool can be used
// as a step in automation pipelines (without progress callbacks).
registerToolProcessFn({
toolId: "upscale",
settingsSchema: z.object({
scale: z.union([z.number(), z.string()]).transform(Number).default(2),
}),
process: async (inputBuffer, settings, filename) => {
const scale = Number((settings as { scale?: number }).scale) || 2;
const orientedBuffer = await autoOrient(inputBuffer);
const jobId = randomUUID();
const workspacePath = await createWorkspace(jobId);
const result = await upscale(orientedBuffer, join(workspacePath, "output"), { scale });
const outputFilename = `${filename.replace(/\.[^.]+$/, "")}_${scale}x.png`;
return { buffer: result.buffer, filename: outputFilename, contentType: "image/png" };
},
});
}