Registers a new workflow with AxonFlow. Call this at the start of your + * external orchestrator workflow (LangChain, LangGraph, CrewAI, etc.). + * + * @param request workflow creation request + * @return created workflow with ID + * @throws AxonFlowException if creation fails + * + * @example + *
{@code
+ * CreateWorkflowResponse workflow = axonflow.createWorkflow(
+ * CreateWorkflowRequest.builder()
+ * .workflowName("code-review-pipeline")
+ * .source(WorkflowSource.LANGGRAPH)
+ * .totalSteps(5)
+ * .build()
+ * );
+ * System.out.println("Workflow created: " + workflow.getWorkflowId());
+ * }
+ */
+ public com.getaxonflow.sdk.types.workflow.WorkflowTypes.CreateWorkflowResponse createWorkflow(
+ com.getaxonflow.sdk.types.workflow.WorkflowTypes.CreateWorkflowRequest request) {
+ Objects.requireNonNull(request, "request cannot be null");
+
+ return retryExecutor.execute(() -> {
+ Request httpRequest = buildOrchestratorRequest("POST", "/api/v1/workflows", request);
+ try (Response response = httpClient.newCall(httpRequest).execute()) {
+ return parseResponse(response,
+ new TypeReferenceThis is the core governance method. Call this before executing each step + * in your workflow to check if the step is allowed based on policies. + * + * @param workflowId workflow ID + * @param stepId unique step identifier (you provide this) + * @param request step gate request with step details + * @return gate decision: allow, block, or require_approval + * @throws AxonFlowException if check fails + * + * @example + *
{@code
+ * StepGateResponse gate = axonflow.stepGate(
+ * workflow.getWorkflowId(),
+ * "step-1",
+ * StepGateRequest.builder()
+ * .stepName("Generate Code")
+ * .stepType(StepType.LLM_CALL)
+ * .model("gpt-4")
+ * .provider("openai")
+ * .build()
+ * );
+ *
+ * if (gate.isBlocked()) {
+ * throw new RuntimeException("Step blocked: " + gate.getReason());
+ * } else if (gate.requiresApproval()) {
+ * System.out.println("Approval needed: " + gate.getApprovalUrl());
+ * } else {
+ * // Execute the step
+ * executeStep();
+ * }
+ * }
+ */
+ public com.getaxonflow.sdk.types.workflow.WorkflowTypes.StepGateResponse stepGate(
+ String workflowId,
+ String stepId,
+ com.getaxonflow.sdk.types.workflow.WorkflowTypes.StepGateRequest request) {
+ Objects.requireNonNull(workflowId, "workflowId cannot be null");
+ Objects.requireNonNull(stepId, "stepId cannot be null");
+ Objects.requireNonNull(request, "request cannot be null");
+
+ return retryExecutor.execute(() -> {
+ Request httpRequest = buildOrchestratorRequest("POST",
+ "/api/v1/workflows/" + workflowId + "/steps/" + stepId + "/gate", request);
+ try (Response response = httpClient.newCall(httpRequest).execute()) {
+ return parseResponse(response,
+ new TypeReferenceCall this after successfully executing a step to record its completion. + * + * @param workflowId workflow ID + * @param stepId step ID + * @param request optional completion request with output data + */ + public void markStepCompleted( + String workflowId, + String stepId, + com.getaxonflow.sdk.types.workflow.WorkflowTypes.MarkStepCompletedRequest request) { + Objects.requireNonNull(workflowId, "workflowId cannot be null"); + Objects.requireNonNull(stepId, "stepId cannot be null"); + + retryExecutor.execute(() -> { + Request httpRequest = buildOrchestratorRequest("POST", + "/api/v1/workflows/" + workflowId + "/steps/" + stepId + "/complete", + request != null ? request : Collections.emptyMap()); + try (Response response = httpClient.newCall(httpRequest).execute()) { + if (!response.isSuccessful()) { + handleErrorResponse(response); + } + return null; + } + }, "markStepCompleted"); + } + + /** + * Marks a step as completed with no output data. + * + * @param workflowId workflow ID + * @param stepId step ID + */ + public void markStepCompleted(String workflowId, String stepId) { + markStepCompleted(workflowId, stepId, null); + } + + /** + * Completes a workflow successfully. + * + *
Call this when your workflow has completed all steps successfully. + * + * @param workflowId workflow ID + */ + public void completeWorkflow(String workflowId) { + Objects.requireNonNull(workflowId, "workflowId cannot be null"); + + retryExecutor.execute(() -> { + Request httpRequest = buildOrchestratorRequest("POST", + "/api/v1/workflows/" + workflowId + "/complete", Collections.emptyMap()); + try (Response response = httpClient.newCall(httpRequest).execute()) { + if (!response.isSuccessful()) { + handleErrorResponse(response); + } + return null; + } + }, "completeWorkflow"); + } + + /** + * Aborts a workflow. + * + *
Call this when you need to stop a workflow due to an error or user request.
+ *
+ * @param workflowId workflow ID
+ * @param reason optional reason for aborting
+ */
+ public void abortWorkflow(String workflowId, String reason) {
+ Objects.requireNonNull(workflowId, "workflowId cannot be null");
+
+ retryExecutor.execute(() -> {
+ Map Call this after a step has been approved to continue the workflow.
+ *
+ * @param workflowId workflow ID
+ */
+ public void resumeWorkflow(String workflowId) {
+ Objects.requireNonNull(workflowId, "workflowId cannot be null");
+
+ retryExecutor.execute(() -> {
+ Request httpRequest = buildOrchestratorRequest("POST",
+ "/api/v1/workflows/" + workflowId + "/resume", Collections.emptyMap());
+ try (Response response = httpClient.newCall(httpRequest).execute()) {
+ if (!response.isSuccessful()) {
+ handleErrorResponse(response);
+ }
+ return null;
+ }
+ }, "resumeWorkflow");
+ }
+
+ /**
+ * Lists workflows with optional filters.
+ *
+ * @param options filter and pagination options
+ * @return list of workflows
+ */
+ public com.getaxonflow.sdk.types.workflow.WorkflowTypes.ListWorkflowsResponse listWorkflows(
+ com.getaxonflow.sdk.types.workflow.WorkflowTypes.ListWorkflowsOptions options) {
+ return retryExecutor.execute(() -> {
+ StringBuilder path = new StringBuilder("/api/v1/workflows");
+ StringBuilder query = new StringBuilder();
+
+ if (options != null) {
+ if (options.getStatus() != null) {
+ appendQueryParam(query, "status", options.getStatus().getValue());
+ }
+ if (options.getSource() != null) {
+ appendQueryParam(query, "source", options.getSource().getValue());
+ }
+ if (options.getLimit() > 0) {
+ appendQueryParam(query, "limit", String.valueOf(options.getLimit()));
+ }
+ if (options.getOffset() > 0) {
+ appendQueryParam(query, "offset", String.valueOf(options.getOffset()));
+ }
+ }
+
+ if (query.length() > 0) {
+ path.append("?").append(query);
+ }
+
+ Request httpRequest = buildOrchestratorRequest("GET", path.toString(), null);
+ try (Response response = httpClient.newCall(httpRequest).execute()) {
+ return parseResponse(response,
+ new TypeReference The Workflow Control Plane provides governance gates for external orchestrators
+ * like LangChain, LangGraph, and CrewAI.
+ *
+ * "LangChain runs the workflow. AxonFlow decides when it's allowed to move forward."
+ */
+public final class WorkflowTypes {
+
+ private WorkflowTypes() {
+ // Utility class
+ }
+
+ /**
+ * Workflow status values.
+ */
+ public enum WorkflowStatus {
+ @JsonProperty("in_progress")
+ IN_PROGRESS("in_progress"),
+ @JsonProperty("completed")
+ COMPLETED("completed"),
+ @JsonProperty("aborted")
+ ABORTED("aborted"),
+ @JsonProperty("failed")
+ FAILED("failed");
+
+ private final String value;
+
+ WorkflowStatus(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+
+ @JsonCreator
+ public static WorkflowStatus fromValue(String value) {
+ for (WorkflowStatus status : values()) {
+ if (status.value.equals(value)) {
+ return status;
+ }
+ }
+ throw new IllegalArgumentException("Unknown workflow status: " + value);
+ }
+ }
+
+ /**
+ * Source of the workflow (which orchestrator is running it).
+ */
+ public enum WorkflowSource {
+ @JsonProperty("langgraph")
+ LANGGRAPH("langgraph"),
+ @JsonProperty("langchain")
+ LANGCHAIN("langchain"),
+ @JsonProperty("crewai")
+ CREWAI("crewai"),
+ @JsonProperty("external")
+ EXTERNAL("external");
+
+ private final String value;
+
+ WorkflowSource(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+
+ @JsonCreator
+ public static WorkflowSource fromValue(String value) {
+ for (WorkflowSource source : values()) {
+ if (source.value.equals(value)) {
+ return source;
+ }
+ }
+ throw new IllegalArgumentException("Unknown workflow source: " + value);
+ }
+ }
+
+ /**
+ * Gate decision values returned by step gate checks.
+ */
+ public enum GateDecision {
+ @JsonProperty("allow")
+ ALLOW("allow"),
+ @JsonProperty("block")
+ BLOCK("block"),
+ @JsonProperty("require_approval")
+ REQUIRE_APPROVAL("require_approval");
+
+ private final String value;
+
+ GateDecision(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+
+ @JsonCreator
+ public static GateDecision fromValue(String value) {
+ for (GateDecision decision : values()) {
+ if (decision.value.equals(value)) {
+ return decision;
+ }
+ }
+ throw new IllegalArgumentException("Unknown gate decision: " + value);
+ }
+ }
+
+ /**
+ * Approval status for steps requiring human approval.
+ */
+ public enum ApprovalStatus {
+ @JsonProperty("pending")
+ PENDING("pending"),
+ @JsonProperty("approved")
+ APPROVED("approved"),
+ @JsonProperty("rejected")
+ REJECTED("rejected");
+
+ private final String value;
+
+ ApprovalStatus(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+
+ @JsonCreator
+ public static ApprovalStatus fromValue(String value) {
+ for (ApprovalStatus status : values()) {
+ if (status.value.equals(value)) {
+ return status;
+ }
+ }
+ throw new IllegalArgumentException("Unknown approval status: " + value);
+ }
+ }
+
+ /**
+ * Step type indicating what kind of operation the step performs.
+ */
+ public enum StepType {
+ @JsonProperty("llm_call")
+ LLM_CALL("llm_call"),
+ @JsonProperty("tool_call")
+ TOOL_CALL("tool_call"),
+ @JsonProperty("connector_call")
+ CONNECTOR_CALL("connector_call"),
+ @JsonProperty("human_task")
+ HUMAN_TASK("human_task");
+
+ private final String value;
+
+ StepType(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+
+ @JsonCreator
+ public static StepType fromValue(String value) {
+ for (StepType type : values()) {
+ if (type.value.equals(value)) {
+ return type;
+ }
+ }
+ throw new IllegalArgumentException("Unknown step type: " + value);
+ }
+ }
+
+ /**
+ * Request to create a new workflow.
+ */
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static final class CreateWorkflowRequest {
+
+ @JsonProperty("workflow_name")
+ private final String workflowName;
+
+ @JsonProperty("source")
+ private final WorkflowSource source;
+
+ @JsonProperty("total_steps")
+ private final Integer totalSteps;
+
+ @JsonProperty("metadata")
+ private final Map The Workflow Control Plane provides governance gates for external orchestrators
+ * like LangChain, LangGraph, and CrewAI. These types define the request/response
+ * structures for registering workflows, checking step gates, and managing workflow
+ * lifecycle.
+ *
+ * "LangChain runs the workflow. AxonFlow decides when it's allowed to move forward."
+ *
+ * Example Usage
+ * {@code
+ * // Create a workflow
+ * CreateWorkflowResponse workflow = axonflow.createWorkflow(
+ * CreateWorkflowRequest.builder()
+ * .workflowName("code-review-pipeline")
+ * .source(WorkflowSource.LANGGRAPH)
+ * .totalSteps(5)
+ * .build()
+ * );
+ *
+ * // Check step gate
+ * StepGateResponse gate = axonflow.stepGate(
+ * workflow.getWorkflowId(),
+ * "step-1",
+ * StepGateRequest.builder()
+ * .stepName("Generate Code")
+ * .stepType(StepType.LLM_CALL)
+ * .model("gpt-4")
+ * .build()
+ * );
+ *
+ * if (gate.isBlocked()) {
+ * throw new RuntimeException("Step blocked: " + gate.getReason());
+ * }
+ *
+ * // Execute step and complete workflow
+ * axonflow.completeWorkflow(workflow.getWorkflowId());
+ * }
+ *
+ * @see com.getaxonflow.sdk.types.workflow.WorkflowTypes
+ * @see com.getaxonflow.sdk.AxonFlow#createWorkflow
+ * @see com.getaxonflow.sdk.AxonFlow#stepGate
+ */
+package com.getaxonflow.sdk.types.workflow;