Skip to content

Commit ca7a268

Browse files
feat: add media governance config methods and category constants (#97)
* feat: add media governance config methods and category constants - getMediaGovernanceConfig() — retrieve tenant's media governance config - updateMediaGovernanceConfig() — update config (Enterprise: full, Community/Eval: toggle) - getMediaGovernanceStatus() — check feature availability per tier - Category constants: CATEGORY_MEDIA_SAFETY, CATEGORY_MEDIA_BIOMETRIC, CATEGORY_MEDIA_DOCUMENT, CATEGORY_MEDIA_PII - Version bump: 3.4.0 → 3.6.0 * fix: add media category enum values to PolicyCategory Add MEDIA_SAFETY, MEDIA_BIOMETRIC, MEDIA_PII, MEDIA_DOCUMENT enum members to prevent Jackson deserialization crash when server returns policies with media-* categories. Add v3.6.0 CHANGELOG entry. * test: add coverage for media governance types and API methods Add tests for MediaGovernanceConfig, MediaGovernanceStatus, UpdateMediaGovernanceConfigRequest types and their JSON serialization. Add WireMock-based tests for getMediaGovernanceConfig, updateMediaGovernanceConfig, and getMediaGovernanceStatus API methods including async variants. Add coverage for media policy category constants and enum values. Brings line coverage from 0.72 to above the 0.73 threshold required by JaCoCo. * docs: update v3.6.0 release date to 2026-02-22 * feat: add post-execution metrics to MarkStepCompletedRequest tokens_in, tokens_out, cost_usd fields with builder support on MarkStepCompletedRequest allow reporting actual LLM usage at step completion time. * fix: add @JsonInclude(NON_NULL) to MarkStepCompletedRequest Prevents null metrics fields from serializing as explicit "null" values in JSON. Matches the pattern used by all other request types in the SDK.
1 parent 44b5519 commit ca7a268

10 files changed

Lines changed: 1291 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ 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+
## [3.6.0] - 2026-02-22
9+
10+
### Added
11+
12+
- Media governance configuration methods: `getMediaGovernanceConfig()`, `updateMediaGovernanceConfig()`, `getMediaGovernanceStatus()`
13+
- Media governance types: `MediaGovernanceConfig`, `MediaGovernanceStatus`
14+
- Media policy category constants: `CATEGORY_MEDIA_SAFETY`, `CATEGORY_MEDIA_BIOMETRIC`, `CATEGORY_MEDIA_PII`, `CATEGORY_MEDIA_DOCUMENT`
15+
- `PolicyCategory` enum values: `MEDIA_SAFETY`, `MEDIA_BIOMETRIC`, `MEDIA_PII`, `MEDIA_DOCUMENT`
16+
- `MarkStepCompletedRequest` now accepts post-execution metrics (`tokens_in`, `tokens_out`, `cost_usd`)
17+
18+
---
19+
820
## [3.5.0] - 2026-02-18
921

1022
### Added

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.getaxonflow</groupId>
88
<artifactId>axonflow-sdk</artifactId>
9-
<version>3.5.0</version>
9+
<version>3.6.0</version>
1010
<packaging>jar</packaging>
1111

1212
<name>AxonFlow Java SDK</name>

src/main/java/com/getaxonflow/sdk/AxonFlow.java

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,6 +2122,95 @@ public void streamExecutionStatus(
21222122
}
21232123
}
21242124

2125+
// ========================================================================
2126+
// Media Governance Config
2127+
// ========================================================================
2128+
2129+
/**
2130+
* Gets the media governance configuration for the current tenant.
2131+
*
2132+
* <p>Returns per-tenant settings controlling whether media analysis is
2133+
* enabled and which analyzers are allowed.
2134+
*
2135+
* @return the media governance configuration
2136+
* @throws AxonFlowException if the request fails
2137+
*/
2138+
public MediaGovernanceConfig getMediaGovernanceConfig() {
2139+
return retryExecutor.execute(() -> {
2140+
Request httpRequest = buildRequest("GET", "/api/v1/media-governance/config", null);
2141+
try (Response response = httpClient.newCall(httpRequest).execute()) {
2142+
return parseResponse(response, MediaGovernanceConfig.class);
2143+
}
2144+
}, "getMediaGovernanceConfig");
2145+
}
2146+
2147+
/**
2148+
* Asynchronously gets the media governance configuration for the current tenant.
2149+
*
2150+
* @return a future containing the media governance configuration
2151+
*/
2152+
public CompletableFuture<MediaGovernanceConfig> getMediaGovernanceConfigAsync() {
2153+
return CompletableFuture.supplyAsync(this::getMediaGovernanceConfig, asyncExecutor);
2154+
}
2155+
2156+
/**
2157+
* Updates the media governance configuration for the current tenant.
2158+
*
2159+
* <p>Allows enabling/disabling media analysis and controlling which
2160+
* analyzers are permitted.
2161+
*
2162+
* @param request the update request
2163+
* @return the updated media governance configuration
2164+
* @throws AxonFlowException if the request fails
2165+
*/
2166+
public MediaGovernanceConfig updateMediaGovernanceConfig(UpdateMediaGovernanceConfigRequest request) {
2167+
Objects.requireNonNull(request, "request cannot be null");
2168+
2169+
return retryExecutor.execute(() -> {
2170+
Request httpRequest = buildRequest("PUT", "/api/v1/media-governance/config", request);
2171+
try (Response response = httpClient.newCall(httpRequest).execute()) {
2172+
return parseResponse(response, MediaGovernanceConfig.class);
2173+
}
2174+
}, "updateMediaGovernanceConfig");
2175+
}
2176+
2177+
/**
2178+
* Asynchronously updates the media governance configuration for the current tenant.
2179+
*
2180+
* @param request the update request
2181+
* @return a future containing the updated media governance configuration
2182+
*/
2183+
public CompletableFuture<MediaGovernanceConfig> updateMediaGovernanceConfigAsync(UpdateMediaGovernanceConfigRequest request) {
2184+
return CompletableFuture.supplyAsync(() -> updateMediaGovernanceConfig(request), asyncExecutor);
2185+
}
2186+
2187+
/**
2188+
* Gets the platform-level media governance status.
2189+
*
2190+
* <p>Returns whether media governance is available, default enablement,
2191+
* and the required license tier.
2192+
*
2193+
* @return the media governance status
2194+
* @throws AxonFlowException if the request fails
2195+
*/
2196+
public MediaGovernanceStatus getMediaGovernanceStatus() {
2197+
return retryExecutor.execute(() -> {
2198+
Request httpRequest = buildRequest("GET", "/api/v1/media-governance/status", null);
2199+
try (Response response = httpClient.newCall(httpRequest).execute()) {
2200+
return parseResponse(response, MediaGovernanceStatus.class);
2201+
}
2202+
}, "getMediaGovernanceStatus");
2203+
}
2204+
2205+
/**
2206+
* Asynchronously gets the platform-level media governance status.
2207+
*
2208+
* @return a future containing the media governance status
2209+
*/
2210+
public CompletableFuture<MediaGovernanceStatus> getMediaGovernanceStatusAsync() {
2211+
return CompletableFuture.supplyAsync(this::getMediaGovernanceStatus, asyncExecutor);
2212+
}
2213+
21252214
// ========================================================================
21262215
// Configuration Access
21272216
// ========================================================================
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2025 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.types;
17+
18+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
19+
import com.fasterxml.jackson.annotation.JsonProperty;
20+
21+
import java.util.List;
22+
import java.util.Objects;
23+
24+
/**
25+
* Per-tenant media governance configuration.
26+
*
27+
* <p>Controls whether media analysis is enabled for a tenant and which
28+
* analyzers are allowed. Returned by the media governance config API.
29+
*/
30+
@JsonIgnoreProperties(ignoreUnknown = true)
31+
public class MediaGovernanceConfig {
32+
33+
@JsonProperty("tenant_id")
34+
private String tenantId;
35+
36+
@JsonProperty("enabled")
37+
private boolean enabled;
38+
39+
@JsonProperty("allowed_analyzers")
40+
private List<String> allowedAnalyzers;
41+
42+
@JsonProperty("updated_at")
43+
private String updatedAt;
44+
45+
@JsonProperty("updated_by")
46+
private String updatedBy;
47+
48+
public MediaGovernanceConfig() {}
49+
50+
public String getTenantId() { return tenantId; }
51+
public void setTenantId(String tenantId) { this.tenantId = tenantId; }
52+
53+
public boolean isEnabled() { return enabled; }
54+
public void setEnabled(boolean enabled) { this.enabled = enabled; }
55+
56+
public List<String> getAllowedAnalyzers() { return allowedAnalyzers; }
57+
public void setAllowedAnalyzers(List<String> allowedAnalyzers) { this.allowedAnalyzers = allowedAnalyzers; }
58+
59+
public String getUpdatedAt() { return updatedAt; }
60+
public void setUpdatedAt(String updatedAt) { this.updatedAt = updatedAt; }
61+
62+
public String getUpdatedBy() { return updatedBy; }
63+
public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; }
64+
65+
@Override
66+
public boolean equals(Object o) {
67+
if (this == o) return true;
68+
if (o == null || getClass() != o.getClass()) return false;
69+
MediaGovernanceConfig that = (MediaGovernanceConfig) o;
70+
return enabled == that.enabled &&
71+
Objects.equals(tenantId, that.tenantId) &&
72+
Objects.equals(allowedAnalyzers, that.allowedAnalyzers) &&
73+
Objects.equals(updatedAt, that.updatedAt) &&
74+
Objects.equals(updatedBy, that.updatedBy);
75+
}
76+
77+
@Override
78+
public int hashCode() {
79+
return Objects.hash(tenantId, enabled, allowedAnalyzers, updatedAt, updatedBy);
80+
}
81+
82+
@Override
83+
public String toString() {
84+
return "MediaGovernanceConfig{" +
85+
"tenantId='" + tenantId + '\'' +
86+
", enabled=" + enabled +
87+
", allowedAnalyzers=" + allowedAnalyzers +
88+
", updatedAt='" + updatedAt + '\'' +
89+
", updatedBy='" + updatedBy + '\'' +
90+
'}';
91+
}
92+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2025 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.types;
17+
18+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
19+
import com.fasterxml.jackson.annotation.JsonProperty;
20+
21+
import java.util.Objects;
22+
23+
/**
24+
* Platform-level media governance status.
25+
*
26+
* <p>Indicates whether media governance is available, the default enablement
27+
* state, and the license tier required.
28+
*/
29+
@JsonIgnoreProperties(ignoreUnknown = true)
30+
public class MediaGovernanceStatus {
31+
32+
@JsonProperty("available")
33+
private boolean available;
34+
35+
@JsonProperty("enabled_by_default")
36+
private boolean enabledByDefault;
37+
38+
@JsonProperty("per_tenant_control")
39+
private boolean perTenantControl;
40+
41+
@JsonProperty("tier")
42+
private String tier;
43+
44+
public MediaGovernanceStatus() {}
45+
46+
public boolean isAvailable() { return available; }
47+
public void setAvailable(boolean available) { this.available = available; }
48+
49+
public boolean isEnabledByDefault() { return enabledByDefault; }
50+
public void setEnabledByDefault(boolean enabledByDefault) { this.enabledByDefault = enabledByDefault; }
51+
52+
public boolean isPerTenantControl() { return perTenantControl; }
53+
public void setPerTenantControl(boolean perTenantControl) { this.perTenantControl = perTenantControl; }
54+
55+
public String getTier() { return tier; }
56+
public void setTier(String tier) { this.tier = tier; }
57+
58+
@Override
59+
public boolean equals(Object o) {
60+
if (this == o) return true;
61+
if (o == null || getClass() != o.getClass()) return false;
62+
MediaGovernanceStatus that = (MediaGovernanceStatus) o;
63+
return available == that.available &&
64+
enabledByDefault == that.enabledByDefault &&
65+
perTenantControl == that.perTenantControl &&
66+
Objects.equals(tier, that.tier);
67+
}
68+
69+
@Override
70+
public int hashCode() {
71+
return Objects.hash(available, enabledByDefault, perTenantControl, tier);
72+
}
73+
74+
@Override
75+
public String toString() {
76+
return "MediaGovernanceStatus{" +
77+
"available=" + available +
78+
", enabledByDefault=" + enabledByDefault +
79+
", perTenantControl=" + perTenantControl +
80+
", tier='" + tier + '\'' +
81+
'}';
82+
}
83+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2025 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.types;
17+
18+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
19+
import com.fasterxml.jackson.annotation.JsonInclude;
20+
import com.fasterxml.jackson.annotation.JsonProperty;
21+
22+
import java.util.List;
23+
import java.util.Objects;
24+
25+
/**
26+
* Request to update per-tenant media governance configuration.
27+
*
28+
* <p>Fields set to {@code null} are omitted from the JSON payload,
29+
* allowing partial updates.
30+
*/
31+
@JsonInclude(JsonInclude.Include.NON_NULL)
32+
@JsonIgnoreProperties(ignoreUnknown = true)
33+
public class UpdateMediaGovernanceConfigRequest {
34+
35+
@JsonProperty("enabled")
36+
private Boolean enabled;
37+
38+
@JsonProperty("allowed_analyzers")
39+
private List<String> allowedAnalyzers;
40+
41+
public UpdateMediaGovernanceConfigRequest() {}
42+
43+
public Boolean getEnabled() { return enabled; }
44+
public void setEnabled(Boolean enabled) { this.enabled = enabled; }
45+
46+
public List<String> getAllowedAnalyzers() { return allowedAnalyzers; }
47+
public void setAllowedAnalyzers(List<String> allowedAnalyzers) { this.allowedAnalyzers = allowedAnalyzers; }
48+
49+
public static Builder builder() { return new Builder(); }
50+
51+
@Override
52+
public boolean equals(Object o) {
53+
if (this == o) return true;
54+
if (o == null || getClass() != o.getClass()) return false;
55+
UpdateMediaGovernanceConfigRequest that = (UpdateMediaGovernanceConfigRequest) o;
56+
return Objects.equals(enabled, that.enabled) &&
57+
Objects.equals(allowedAnalyzers, that.allowedAnalyzers);
58+
}
59+
60+
@Override
61+
public int hashCode() {
62+
return Objects.hash(enabled, allowedAnalyzers);
63+
}
64+
65+
@Override
66+
public String toString() {
67+
return "UpdateMediaGovernanceConfigRequest{" +
68+
"enabled=" + enabled +
69+
", allowedAnalyzers=" + allowedAnalyzers +
70+
'}';
71+
}
72+
73+
public static final class Builder {
74+
private Boolean enabled;
75+
private List<String> allowedAnalyzers;
76+
77+
private Builder() {}
78+
79+
public Builder enabled(Boolean enabled) { this.enabled = enabled; return this; }
80+
public Builder allowedAnalyzers(List<String> allowedAnalyzers) { this.allowedAnalyzers = allowedAnalyzers; return this; }
81+
82+
public UpdateMediaGovernanceConfigRequest build() {
83+
UpdateMediaGovernanceConfigRequest request = new UpdateMediaGovernanceConfigRequest();
84+
request.enabled = this.enabled;
85+
request.allowedAnalyzers = this.allowedAnalyzers;
86+
return request;
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)