Fix workflow step execution wiring
This commit is contained in:
@@ -1402,6 +1402,7 @@ describe("PATCH /tasks/:id", () => {
|
||||
description: undefined,
|
||||
prompt: undefined,
|
||||
dependencies: ["FN-002"],
|
||||
enabledWorkflowSteps: undefined,
|
||||
modelProvider: null,
|
||||
modelId: null,
|
||||
validatorModelProvider: null,
|
||||
@@ -1423,6 +1424,7 @@ describe("PATCH /tasks/:id", () => {
|
||||
description: undefined,
|
||||
prompt: undefined,
|
||||
dependencies: undefined,
|
||||
enabledWorkflowSteps: undefined,
|
||||
modelProvider: null,
|
||||
modelId: null,
|
||||
validatorModelProvider: null,
|
||||
@@ -1454,6 +1456,7 @@ describe("PATCH /tasks/:id", () => {
|
||||
description: undefined,
|
||||
prompt: undefined,
|
||||
dependencies: undefined,
|
||||
enabledWorkflowSteps: undefined,
|
||||
modelProvider: "anthropic",
|
||||
modelId: "claude-sonnet-4-5",
|
||||
validatorModelProvider: "openai",
|
||||
@@ -1503,12 +1506,50 @@ describe("PATCH /tasks/:id", () => {
|
||||
description: undefined,
|
||||
prompt: undefined,
|
||||
dependencies: undefined,
|
||||
enabledWorkflowSteps: undefined,
|
||||
modelProvider: null,
|
||||
modelId: null,
|
||||
validatorModelProvider: null,
|
||||
validatorModelId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("forwards enabledWorkflowSteps to store.updateTask", async () => {
|
||||
(store.updateTask as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
...FAKE_TASK_DETAIL,
|
||||
enabledWorkflowSteps: ["browser-verification"],
|
||||
});
|
||||
|
||||
const res = await REQUEST(buildApp(), "PATCH", "/api/tasks/KB-001", JSON.stringify({
|
||||
enabledWorkflowSteps: ["browser-verification"],
|
||||
}), {
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(store.updateTask).toHaveBeenCalledWith("KB-001", {
|
||||
title: undefined,
|
||||
description: undefined,
|
||||
prompt: undefined,
|
||||
dependencies: undefined,
|
||||
enabledWorkflowSteps: ["browser-verification"],
|
||||
modelProvider: null,
|
||||
modelId: null,
|
||||
validatorModelProvider: null,
|
||||
validatorModelId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns 400 for invalid enabledWorkflowSteps type", async () => {
|
||||
const res = await REQUEST(buildApp(), "PATCH", "/api/tasks/KB-001", JSON.stringify({
|
||||
enabledWorkflowSteps: [123],
|
||||
}), {
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error).toContain("enabledWorkflowSteps must be an array of strings");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Attachment routes", () => {
|
||||
@@ -6941,9 +6982,11 @@ describe("POST /workflow-step-templates/:id/create", () => {
|
||||
expect(res.body.id).toBe("WS-001");
|
||||
expect(res.body.name).toBe("Documentation Review");
|
||||
expect(store.createWorkflowStep).toHaveBeenCalledWith({
|
||||
templateId: "documentation-review",
|
||||
name: "Documentation Review",
|
||||
description: "Verify all public APIs, functions, and complex logic have appropriate documentation",
|
||||
prompt: expect.stringContaining("documentation reviewer"),
|
||||
toolMode: "readonly",
|
||||
enabled: true,
|
||||
});
|
||||
});
|
||||
@@ -6968,9 +7011,11 @@ describe("POST /workflow-step-templates/:id/create", () => {
|
||||
expect(res.status).toBe(201);
|
||||
expect(res.body.name).toBe("QA Check");
|
||||
expect(store.createWorkflowStep).toHaveBeenCalledWith({
|
||||
templateId: "qa-check",
|
||||
name: "QA Check",
|
||||
description: "Run tests and verify they pass, check for obvious bugs",
|
||||
prompt: expect.stringContaining("QA tester"),
|
||||
toolMode: "coding",
|
||||
enabled: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1744,7 +1744,7 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
);
|
||||
res.status(201).json(task);
|
||||
} catch (err: any) {
|
||||
const status = err.message?.includes("must be a string") ? 400 : 500;
|
||||
const status = err.message?.includes("must be a string") || err.message?.includes("must be an array of strings") ? 400 : 500;
|
||||
res.status(status).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
@@ -2457,7 +2457,7 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
router.patch("/tasks/:id", async (req, res) => {
|
||||
try {
|
||||
const scopedStore = await getScopedStore(req);
|
||||
const { title, description, prompt, dependencies, modelProvider, modelId, validatorModelProvider, validatorModelId } = req.body;
|
||||
const { title, description, prompt, dependencies, enabledWorkflowSteps, modelProvider, modelId, validatorModelProvider, validatorModelId } = req.body;
|
||||
|
||||
// Validate model fields are strings or undefined/null
|
||||
const validateModelField = (value: unknown, name: string): string | null | undefined => {
|
||||
@@ -2473,11 +2473,18 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
const validatedValidatorModelProvider = validateModelField(validatorModelProvider, "validatorModelProvider");
|
||||
const validatedValidatorModelId = validateModelField(validatorModelId, "validatorModelId");
|
||||
|
||||
if (enabledWorkflowSteps !== undefined) {
|
||||
if (!Array.isArray(enabledWorkflowSteps) || !enabledWorkflowSteps.every((id: unknown) => typeof id === "string")) {
|
||||
throw new Error("enabledWorkflowSteps must be an array of strings");
|
||||
}
|
||||
}
|
||||
|
||||
const task = await scopedStore.updateTask(req.params.id, {
|
||||
title,
|
||||
description,
|
||||
prompt,
|
||||
dependencies,
|
||||
enabledWorkflowSteps,
|
||||
modelProvider: validatedModelProvider,
|
||||
modelId: validatedModelId,
|
||||
validatorModelProvider: validatedValidatorModelProvider,
|
||||
@@ -2485,7 +2492,7 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
});
|
||||
res.json(task);
|
||||
} catch (err: any) {
|
||||
const status = err.message?.includes("must be a string") ? 400 : 500;
|
||||
const status = err.message?.includes("must be a string") || err.message?.includes("must be an array of strings") ? 400 : 500;
|
||||
res.status(status).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
@@ -6205,7 +6212,7 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
router.post("/workflow-steps", async (req, res) => {
|
||||
try {
|
||||
const scopedStore = await getScopedStore(req);
|
||||
const { name, description, mode, phase, prompt, scriptName, enabled, defaultOn, modelProvider, modelId } = req.body;
|
||||
const { name, description, mode, phase, prompt, toolMode, scriptName, enabled, defaultOn, modelProvider, modelId } = req.body;
|
||||
|
||||
if (!name || typeof name !== "string" || !name.trim()) {
|
||||
res.status(400).json({ error: "name is required" });
|
||||
@@ -6233,6 +6240,10 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
res.status(400).json({ error: "prompt must be a string" });
|
||||
return;
|
||||
}
|
||||
if (toolMode !== undefined && toolMode !== "readonly" && toolMode !== "coding") {
|
||||
res.status(400).json({ error: "toolMode must be 'readonly' or 'coding'" });
|
||||
return;
|
||||
}
|
||||
if (scriptName !== undefined && typeof scriptName !== "string") {
|
||||
res.status(400).json({ error: "scriptName must be a string" });
|
||||
return;
|
||||
@@ -6276,6 +6287,7 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
mode: resolvedMode,
|
||||
phase,
|
||||
prompt: prompt?.trim(),
|
||||
toolMode,
|
||||
scriptName: scriptName?.trim(),
|
||||
enabled,
|
||||
defaultOn: defaultOn === true,
|
||||
@@ -6298,7 +6310,7 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
router.patch("/workflow-steps/:id", async (req, res) => {
|
||||
try {
|
||||
const scopedStore = await getScopedStore(req);
|
||||
const { name, description, mode, phase, prompt, scriptName, enabled, defaultOn, modelProvider, modelId } = req.body;
|
||||
const { name, description, mode, phase, prompt, toolMode, scriptName, enabled, defaultOn, modelProvider, modelId } = req.body;
|
||||
|
||||
const updates: Record<string, unknown> = {};
|
||||
if (name !== undefined) {
|
||||
@@ -6336,6 +6348,13 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
}
|
||||
updates.prompt = prompt;
|
||||
}
|
||||
if (toolMode !== undefined) {
|
||||
if (toolMode !== "readonly" && toolMode !== "coding") {
|
||||
res.status(400).json({ error: "toolMode must be 'readonly' or 'coding'" });
|
||||
return;
|
||||
}
|
||||
updates.toolMode = toolMode;
|
||||
}
|
||||
if (scriptName !== undefined) {
|
||||
if (typeof scriptName !== "string") {
|
||||
res.status(400).json({ error: "scriptName must be a string" });
|
||||
@@ -6537,9 +6556,11 @@ Output ONLY the prompt text (no markdown, no explanations).`;
|
||||
}
|
||||
|
||||
const step = await scopedStore.createWorkflowStep({
|
||||
templateId: template.id,
|
||||
name: template.name,
|
||||
description: template.description,
|
||||
prompt: template.prompt,
|
||||
toolMode: template.toolMode,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user