diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/policy/engine/PolicyExecutor.java b/app/proprietary/src/main/java/stirling/software/proprietary/policy/engine/PolicyExecutor.java index af9f8c7283..fe88b40391 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/policy/engine/PolicyExecutor.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/policy/engine/PolicyExecutor.java @@ -116,6 +116,10 @@ private ToolResult executeStep( ToolResult r = callEndpoint(step, inputFiles, supportingFiles); files.addAll(r.files()); report = r.report(); + } else if (inputFiles.isEmpty()) { + ToolResult r = callEndpoint(step, List.of(), supportingFiles); + files.addAll(r.files()); + report = r.report(); } else { for (Resource file : inputFiles) { ToolResult r = callEndpoint(step, List.of(file), supportingFiles); diff --git a/app/proprietary/src/test/java/stirling/software/proprietary/policy/engine/PolicyExecutorTest.java b/app/proprietary/src/test/java/stirling/software/proprietary/policy/engine/PolicyExecutorTest.java index d682c35cd7..9b10d9090e 100644 --- a/app/proprietary/src/test/java/stirling/software/proprietary/policy/engine/PolicyExecutorTest.java +++ b/app/proprietary/src/test/java/stirling/software/proprietary/policy/engine/PolicyExecutorTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -149,6 +150,40 @@ void singleInputEndpointIsCalledOncePerFile() throws IOException { verify(internalApiClient, times(2)).post(eq(ROTATE), any()); } + @Test + void noInputGeneratorEndpointIsCalledOnceWithNoFile() throws IOException { + // A "create" workflow has no source documents: a generator tool (e.g. + // create-pdf-from-html-agent) produces its output purely from parameters. Per-file + // dispatch would skip it entirely (zero files = zero calls), so it must still run once. + String createPdf = "/api/v1/ai/tools/create-pdf-from-html-agent"; + when(toolMetadataService.isMultiInput(createPdf)).thenReturn(false); + when(toolMetadataService.shouldUnpackZipResponse(createPdf)).thenReturn(false); + stubEndpoint(createPdf, pdf("generated", "purchase-order.pdf")); + + PolicyExecutionResult result = + executor.execute( + definition( + new PipelineStep( + createPdf, + Map.of( + "htmlContent", + "
hi
", + "filename", + "purchase-order.pdf"))), + PolicyInputs.of(List.of()), + PolicyProgressListener.NOOP); + + assertEquals(1, result.files().size()); + assertEquals("purchase-order.pdf", result.files().get(0).getFilename()); + + @SuppressWarnings("unchecked") + ArgumentCaptor