Skip to content

Commit 36ada1d

Browse files
feat: add LangGraph adapter with per-tool governance (#1243)
Add LangGraphAdapter class with builder pattern and AutoCloseable for wrapping LangGraph workflows with AxonFlow governance gates. Provides per-tool governance via checkToolGate()/toolCompleted() and MCP policy enforcement via mcpToolInterceptor(). 12 source files, 47 tests.
1 parent 923dda7 commit 36ada1d

14 files changed

Lines changed: 2386 additions & 0 deletions

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@ All notable changes to the AxonFlow Java SDK will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Added
11+
12+
- `LangGraphAdapter` class — wraps LangGraph workflows with AxonFlow governance gates and per-tool policy enforcement. Includes:
13+
- `checkGate()` / `stepCompleted()` — step-level governance at LangGraph node boundaries
14+
- `checkToolGate()` / `toolCompleted()` — per-tool governance within tool_call nodes (each tool gets its own gate check)
15+
- `mcpToolInterceptor()` — factory returning an interceptor enforcing `mcpCheckInput → handler → mcpCheckOutput` around every MCP tool call
16+
- `waitForApproval()` — poll until a step is approved or rejected
17+
- `startWorkflow()` / `completeWorkflow()` / `abortWorkflow()` / `failWorkflow()` — workflow lifecycle management
18+
- Builder pattern construction, implements `AutoCloseable`
19+
- `WorkflowBlockedError` and `WorkflowApprovalRequiredError` exception classes
20+
- Builder-based option classes: `CheckGateOptions`, `StepCompletedOptions`, `CheckToolGateOptions`, `ToolCompletedOptions`
21+
- MCP interceptor types: `MCPInterceptorOptions`, `MCPToolRequest`, `MCPToolHandler`, `MCPToolInterceptor`
22+
23+
---
24+
825
## [4.1.0] - 2026-03-14
926

1027
### Added

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
<artifactId>maven-surefire-plugin</artifactId>
179179
<version>${maven-surefire-plugin.version}</version>
180180
<configuration>
181+
<argLine>@{argLine} -Dnet.bytebuddy.experimental=true</argLine>
181182
<includes>
182183
<include>**/*Test.java</include>
183184
</includes>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2026 AxonFlow
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.getaxonflow.sdk.adapters;
17+
18+
import com.getaxonflow.sdk.types.workflow.WorkflowTypes.ToolContext;
19+
20+
import java.util.Map;
21+
22+
/**
23+
* Options for {@link LangGraphAdapter#checkGate}.
24+
*/
25+
public final class CheckGateOptions {
26+
27+
private final String stepId;
28+
private final Map<String, Object> stepInput;
29+
private final String model;
30+
private final String provider;
31+
private final ToolContext toolContext;
32+
33+
private CheckGateOptions(Builder builder) {
34+
this.stepId = builder.stepId;
35+
this.stepInput = builder.stepInput;
36+
this.model = builder.model;
37+
this.provider = builder.provider;
38+
this.toolContext = builder.toolContext;
39+
}
40+
41+
public String getStepId() {
42+
return stepId;
43+
}
44+
45+
public Map<String, Object> getStepInput() {
46+
return stepInput;
47+
}
48+
49+
public String getModel() {
50+
return model;
51+
}
52+
53+
public String getProvider() {
54+
return provider;
55+
}
56+
57+
public ToolContext getToolContext() {
58+
return toolContext;
59+
}
60+
61+
public static Builder builder() {
62+
return new Builder();
63+
}
64+
65+
public static final class Builder {
66+
private String stepId;
67+
private Map<String, Object> stepInput;
68+
private String model;
69+
private String provider;
70+
private ToolContext toolContext;
71+
72+
private Builder() {
73+
}
74+
75+
public Builder stepId(String stepId) {
76+
this.stepId = stepId;
77+
return this;
78+
}
79+
80+
public Builder stepInput(Map<String, Object> stepInput) {
81+
this.stepInput = stepInput;
82+
return this;
83+
}
84+
85+
public Builder model(String model) {
86+
this.model = model;
87+
return this;
88+
}
89+
90+
public Builder provider(String provider) {
91+
this.provider = provider;
92+
return this;
93+
}
94+
95+
public Builder toolContext(ToolContext toolContext) {
96+
this.toolContext = toolContext;
97+
return this;
98+
}
99+
100+
public CheckGateOptions build() {
101+
return new CheckGateOptions(this);
102+
}
103+
}
104+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2026 AxonFlow
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.getaxonflow.sdk.adapters;
17+
18+
import java.util.Map;
19+
20+
/**
21+
* Options for {@link LangGraphAdapter#checkToolGate}.
22+
*/
23+
public final class CheckToolGateOptions {
24+
25+
private final String stepName;
26+
private final String stepId;
27+
private final Map<String, Object> toolInput;
28+
private final String model;
29+
private final String provider;
30+
31+
private CheckToolGateOptions(Builder builder) {
32+
this.stepName = builder.stepName;
33+
this.stepId = builder.stepId;
34+
this.toolInput = builder.toolInput;
35+
this.model = builder.model;
36+
this.provider = builder.provider;
37+
}
38+
39+
public String getStepName() {
40+
return stepName;
41+
}
42+
43+
public String getStepId() {
44+
return stepId;
45+
}
46+
47+
public Map<String, Object> getToolInput() {
48+
return toolInput;
49+
}
50+
51+
public String getModel() {
52+
return model;
53+
}
54+
55+
public String getProvider() {
56+
return provider;
57+
}
58+
59+
public static Builder builder() {
60+
return new Builder();
61+
}
62+
63+
public static final class Builder {
64+
private String stepName;
65+
private String stepId;
66+
private Map<String, Object> toolInput;
67+
private String model;
68+
private String provider;
69+
70+
private Builder() {
71+
}
72+
73+
public Builder stepName(String stepName) {
74+
this.stepName = stepName;
75+
return this;
76+
}
77+
78+
public Builder stepId(String stepId) {
79+
this.stepId = stepId;
80+
return this;
81+
}
82+
83+
public Builder toolInput(Map<String, Object> toolInput) {
84+
this.toolInput = toolInput;
85+
return this;
86+
}
87+
88+
public Builder model(String model) {
89+
this.model = model;
90+
return this;
91+
}
92+
93+
public Builder provider(String provider) {
94+
this.provider = provider;
95+
return this;
96+
}
97+
98+
public CheckToolGateOptions build() {
99+
return new CheckToolGateOptions(this);
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)