feat: lightweight Docker image without AI/ML tools (:lite tag)

Closes #1
This commit is contained in:
stirling-image
2026-04-05 00:23:21 +08:00
committed by GitHub
parent 51f10abb35
commit 449a2fc319
19 changed files with 1819 additions and 72 deletions
+5 -1
View File
@@ -6,6 +6,7 @@
* GET /api/v1/settings/:key — Get a specific setting
*/
import { PYTHON_SIDECAR_TOOLS } from "@stirling-image/shared";
import { eq } from "drizzle-orm";
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { db, schema } from "../db/index.js";
@@ -26,7 +27,10 @@ export async function settingsRoutes(app: FastifyInstance): Promise<void> {
settings[row.key] = row.value;
}
return reply.send({ settings });
const variant = process.env.STIRLING_VARIANT === "lite" ? "lite" : "full";
const variantUnavailableTools = variant === "lite" ? [...PYTHON_SIDECAR_TOOLS] : [];
return reply.send({ settings, variant, variantUnavailableTools });
});
// PUT /api/v1/settings — Save settings (admin only)
+22 -3
View File
@@ -1,4 +1,4 @@
import { TOOLS } from "@stirling-image/shared";
import { PYTHON_SIDECAR_TOOLS, TOOLS } from "@stirling-image/shared";
import { eq } from "drizzle-orm";
import type { FastifyInstance } from "fastify";
import { db, schema } from "../../db/index.js";
@@ -66,6 +66,10 @@ export async function registerToolRoutes(app: FastifyInstance): Promise<void> {
// Build skip set
const skipTools = new Set([...disabledTools, ...(enableExperimental ? [] : experimentalToolIds)]);
// In lite mode, register 501 stubs for AI tools instead of real handlers
const isLite = process.env.STIRLING_VARIANT === "lite";
const liteStubTools = new Set<string>(PYTHON_SIDECAR_TOOLS);
const toolRegistrations: Array<{
id: string;
register: (app: FastifyInstance) => void;
@@ -121,17 +125,32 @@ export async function registerToolRoutes(app: FastifyInstance): Promise<void> {
];
let skipped = 0;
let stubbed = 0;
for (const { id, register } of toolRegistrations) {
if (skipTools.has(id)) {
app.log.info(`Skipping disabled/experimental tool: ${id}`);
skipped++;
continue;
}
if (isLite && liteStubTools.has(id)) {
// Register a 501 stub instead of the real handler
app.post(`/api/v1/tools/${id}`, async (_request, reply) => {
return reply.status(501).send({
statusCode: 501,
error: "Not Available",
message: `The "${id}" tool requires the full image. Pull stirlingimage/stirling-image:latest for all features.`,
});
});
stubbed++;
continue;
}
register(app);
}
const registered = toolRegistrations.length - skipped;
const registered = toolRegistrations.length - skipped - stubbed;
app.log.info(
`Tool routes registered (${registered}/${toolRegistrations.length} tools, ${skipped} skipped)`,
`Tool routes: ${registered} active, ${stubbed} lite-stubbed, ${skipped} skipped (${toolRegistrations.length} total)`,
);
}