From 89c8e4bb9680c179bf44a66a22dcf047334944ae Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 13 Apr 2026 19:22:30 -0400 Subject: [PATCH] fix: detect WAC v2 Python workflows that only use step() (no @task) (#8819) is_wac_v2_py required both @workflow and @task, so a workflow using only inline step() calls fell through to the regular Python path and returned the raw coroutine object instead of its awaited result. Match the TS detector and accept @workflow alone. Co-authored-by: Claude Opus 4.6 (1M context) --- backend/windmill-worker/src/wac_executor.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/backend/windmill-worker/src/wac_executor.rs b/backend/windmill-worker/src/wac_executor.rs index d9479e0669..2fcfc8e2c5 100644 --- a/backend/windmill-worker/src/wac_executor.rs +++ b/backend/windmill-worker/src/wac_executor.rs @@ -286,12 +286,13 @@ pub fn inject_wac_task_names(content: &str) -> String { } /// Detect WAC v2 patterns in Python code. -/// Checks for `@workflow` decorator and `@task` decorator with wmill import, -/// skipping comment lines. +/// Checks for a wmill import plus a `@workflow` decorator, skipping comment +/// lines. `@task` is optional: a workflow that only uses inline `step()` calls +/// (no child-job `@task`) is still WAC v2 and must go through the WAC runner +/// so its coroutine gets awaited. pub fn is_wac_v2_py(code: &str) -> bool { let mut has_wmill_import = false; let mut has_workflow_decorator = false; - let mut has_task_decorator = false; for line in code.lines() { let trimmed = line.trim(); if trimmed.starts_with('#') { @@ -303,9 +304,6 @@ pub fn is_wac_v2_py(code: &str) -> bool { if trimmed == "@workflow" || trimmed.starts_with("@workflow(") { has_workflow_decorator = true; } - if trimmed == "@task" || trimmed.starts_with("@task(") { - has_task_decorator = true; - } } - has_wmill_import && has_workflow_decorator && has_task_decorator + has_wmill_import && has_workflow_decorator }