Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## [3.6.0] - 2026-01-25
## [3.6.0] - 2026-01-26

### Community

Expand Down Expand Up @@ -82,12 +82,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Agent DB Auth** (#1071): Fixed JSON parsing for permissions from JSONB array
- **Cassandra Connector** (#1071): Apply timeout from query config to CQL operations

- **SDK Examples with Assertions** (#1082): All Go examples now have proper pass/fail testing
- 94 assertions across 12 example categories
- Examples exit with code 1 on test failure for CI/CD integration
- Fixed PAN test case format in pii-detection (`ABCDE1234F` → `ABCPD1234E`)
- Fixed `ProxyLLMCall` → `ExecuteQuery` for SDK v2.6.0 compatibility (4 files)
- Test coverage: static-policies (16), dynamic-policies (12), mcp-audit (7), execution-tracking (12), pii-detection (14), llm-routing (3), gateway-mode (5), proxy-mode (3), langgraph (4), dspy (7), sqli-detection (10), execution-replay (1)
- **SDK Examples with Assertions** (#1082, #1097, #1099): Examples now have proper pass/fail testing and exit with code 1 on failure
- Added assertions across all 4 SDKs (Go, Python, TypeScript, Java)
- Community examples fixes (#1099): workflow examples, policy examples, integration examples

- **HITL Enforcement for Compliance Frameworks** (#1089): Fixed HITL not triggering in Proxy Mode
- Root cause: Database constraint missing `require_approval` action + runtime wiring gap
Expand All @@ -98,6 +95,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

#### Deprecated

- **API: page_size → limit** (#1099): Standardized pagination parameter name
- **Action Required:** Migrate from `page_size` to `limit` before v4.0.0
- `page_size` query parameter is deprecated and **will be removed in v4.0.0**
- Affected endpoints: `/api/v1/static-policies`, `/api/v1/dynamic-policies`
- Both parameters work during transition period; `limit` takes precedence

- **SDK: ExecuteQuery → ProxyLLMCall** (#1052): Renamed for clearer Proxy Mode semantics
- **Action Required:** Migrate from `executeQuery()` to `proxyLLMCall()` before the next major release
- Old methods emit deprecation warnings and **will be removed in v4.0.0**
Expand Down Expand Up @@ -153,6 +156,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Removed explicit `id` column from INSERT (now auto-generated by sequence)
- `request_id` (UUID) is the primary identifier for approval requests

- **SDK Examples Fixes** (#1099): Fixed enterprise examples (eu-ai-act, rbi-sebi, healthcare, llm-providers/e2e-tests) across all 4 SDKs

#### SDK Support

- TypeScript SDK v2.7.0: `client.masfeat.*` namespace, `budgetInfo`
Expand Down
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,15 +428,27 @@ We welcome contributions. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

### Public Issues (Technical Questions Welcome)

If you're evaluating AxonFlow and encounter unclear behavior, edge cases, or questions around guarantees (e.g. policy enforcement, audit semantics, failure modes), opening a GitHub issue is welcome. For private questions, reach us at hello@getaxonflow.com.
If you are evaluating AxonFlow and run into unclear behavior, edge cases, or questions about guarantees
(for example policy enforcement, audit semantics, failure modes, or integration boundaries), opening a GitHub issue is welcome.

### Tried It and Gave Up?
Public issues help clarify behavior for everyone.

If you evaluated AxonFlow and hit a blocker — setup didn't work, docs were unclear, it didn't fit your use case — we'd like to understand why.
For private questions, you can also reach us at hello@getaxonflow.com

**[→ Anonymous feedback form (30 seconds)](https://getaxonflow.com/feedback)**
### Evaluating AxonFlow or Exploring Internally?

No attribution, no follow-up unless you want it.
If you looked at AxonFlow in any capacity — reading code, cloning SDKs, testing locally, or mapping it to an internal use case — we would value your perspective.

This includes cases where you:

- paused evaluation
- decided not to proceed
- are still exploring
- are borrowing ideas for internal work

[Anonymous evaluation feedback (30 seconds)](https://getaxonflow.com/feedback)

No attribution. No tracking. No follow-up unless you explicitly opt in.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* 1. Pre-check - Validate request against policies
* 2. LLM Call - Make your own call to LLM provider
* 3. Audit - Log the interaction for compliance
*
* VALIDATION: This example exits with code 1 if any assertion fails.
*/
package com.getaxonflow.examples;

Expand All @@ -16,6 +18,7 @@
import com.getaxonflow.sdk.types.TokenUsage;
import com.getaxonflow.sdk.exceptions.AxonFlowException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
Expand All @@ -24,6 +27,16 @@
public class AuditLoggingExample {

private static final String CLIENT_ID = "audit-logging-demo";
private static final List<String> failures = new ArrayList<>();

private static void assertCheck(boolean condition, String message) {
if (condition) {
System.out.println(" ✓ PASS: " + message);
} else {
System.out.println(" ❌ FAIL: " + message);
failures.add(message);
}
}

public static void main(String[] args) {
System.out.println("AxonFlow Audit Logging - Java");
Expand Down Expand Up @@ -69,6 +82,8 @@ public static void main(String[] args) {
long precheckLatency = System.currentTimeMillis() - precheckStart;
System.out.printf(" Latency: %dms%n", precheckLatency);
System.out.printf(" Context ID: %s%n", precheck.getContextId());
assertCheck(precheck.getContextId() != null && !precheck.getContextId().isEmpty(),
"Pre-check returned contextId for query: " + q.name);

if (!precheck.isApproved()) {
System.out.printf(" BLOCKED: %s%n%n", precheck.getBlockReason());
Expand Down Expand Up @@ -113,6 +128,7 @@ public static void main(String[] args) {
long auditLatency = System.currentTimeMillis() - auditStart;
System.out.printf(" Latency: %dms%n", auditLatency);
System.out.println(" Audit logged successfully");
assertCheck(true, "Audit logged successfully for query: " + q.name);

// Summary
long governance = precheckLatency + auditLatency;
Expand Down Expand Up @@ -156,16 +172,20 @@ public static void main(String[] args) {
var tenantLogs = client.getAuditLogsByTenant(CLIENT_ID, null);
if (tenantLogs != null && tenantLogs.getEntries() != null) {
System.out.printf(" Found %d entries%n", tenantLogs.getEntries().size());
assertCheck(tenantLogs.getEntries().size() >= 0, "getAuditLogsByTenant returned valid entries list");
if (!tenantLogs.getEntries().isEmpty()) {
var entry = tenantLogs.getEntries().get(0);
System.out.printf(" Latest: %s - %s/%s%n",
entry.getTimestamp(), entry.getProvider(), entry.getModel());
assertCheck(entry.getTimestamp() != null, "Audit entry has timestamp");
}
} else {
System.out.println(" Found 0 entries (empty response)");
assertCheck(true, "getAuditLogsByTenant returned response (empty is valid)");
}
} catch (AxonFlowException e) {
System.out.printf(" Error: %s%n", e.getMessage());
assertCheck(false, "getAuditLogsByTenant failed: " + e.getMessage());
}
System.out.println();

Expand Down Expand Up @@ -220,6 +240,21 @@ public static void main(String[] args) {

System.out.println("========================================");
System.out.println("Done!");

// Final assertion summary
System.out.println();
System.out.println("========================================");
System.out.println("Assertion Summary");
System.out.println("========================================");
if (failures.isEmpty()) {
System.out.println("All assertions passed!");
} else {
System.out.println("Failures (" + failures.size() + "):");
for (String f : failures) {
System.out.println(" - " + f);
}
System.exit(1);
}
}

private static String getEnv(String key, String defaultValue) {
Expand Down
Loading
Loading