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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
and tag v{X.Y.Z}. The release workflow's preflight checks the section
header matches the tag. -->

## [9.5.0] - 2026-10-21: Decision API approval retry fields

### Added

- Decision API payment approval wire fields: exact `target.server`, request `approval_id`, and response `pending_approval` and consumed `approval_id`. A hold is never an allow verdict; retry only after human approval and forward the payment only on an allow verdict for the spent approval.

## [9.4.0] - 2026-09-14: decision provenance, the PEP capability handshake, typed policy authoring, and the simulation family deprecated

The first Python SDK release carrying these entries sends the PEP capability handshake, which a platform reads from v10.4.0, and reaches `/api/v1/typed-policies`, which needs a v11.0.0 platform. Upgrade the SDK before the platform: from v11.0.0, `decide` refuses a client that does not declare redaction, including one that sends no handshake, wherever the organization has a redact override. Against an older platform this release works unchanged.
Expand Down
4 changes: 4 additions & 0 deletions axonflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,9 @@
CreateBudgetRequest,
DecideRequest,
DecideResponse,
DecisionApprovalRetry,
DecisionCallerIdentity,
DecisionPendingApproval,
DecisionProvenance,
DecisionTarget,
DynamicPolicyInfo,
Expand Down Expand Up @@ -400,6 +402,8 @@
# Decision Mode PEP contract (ADR-056, #2563)
"DecideRequest",
"DecideResponse",
"DecisionApprovalRetry",
"DecisionPendingApproval",
"DecisionProvenance",
"LegacyValidatorAction",
"PolicyIdentity",
Expand Down
2 changes: 1 addition & 1 deletion axonflow/_version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Single source of truth for the AxonFlow SDK version."""

__version__ = "9.4.0"
__version__ = "9.5.0"
24 changes: 24 additions & 0 deletions axonflow/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@ class DecisionTarget(BaseModel):
type: str | None = Field(default=None, description='"llm" | "tool" | "agent".')
model: str | None = Field(default=None, description="When type=llm.")
provider: str | None = Field(default=None, description="When type=llm.")
server: str | None = Field(default=None, description="When type=tool.")
tool: str | None = Field(default=None, description="When type=tool.")


Expand All @@ -682,6 +683,27 @@ class DecideRequest(BaseModel):
target: DecisionTarget = Field(default_factory=DecisionTarget)
user_token: str | None = Field(default=None)
context: dict[str, Any] | None = Field(default=None)
approval_id: str | None = Field(
default=None, description="Approved hold spent by an exact retry"
)


class DecisionApprovalRetry(BaseModel):
"""The header or body field that names a held call on retry."""

header: str
argument: str | None = None
body_field: str | None = None


class DecisionPendingApproval(BaseModel):
"""A call held for a person's review; this is never an allow verdict."""

approval_id: str
status: str
plane: str
expires_at: datetime | None = None
retry: DecisionApprovalRetry


class DecideResponse(DecisionProvenance):
Expand All @@ -707,6 +729,8 @@ class DecideResponse(DecisionProvenance):
policy_identities: list[PolicyIdentity] | None = Field(default=None)
policy_packs: list[str] | None = Field(default=None)
document_version: int | None = Field(default=None)
pending_approval: DecisionPendingApproval | None = Field(default=None)
approval_id: str | None = Field(default=None)


class PlanStep(BaseModel):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "axonflow"
version = "9.4.0"
version = "9.5.0"
description = "AxonFlow Python SDK - Enterprise AI Governance in 3 Lines of Code"
readme = "README.md"
license = {text = "MIT"}
Expand Down
10 changes: 5 additions & 5 deletions tests/fixtures/openapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ It reads the schema declarations under `components.schemas` and the names of eac

The four files here hold exactly that, and nothing else. `scripts/snapshot_openapi_schemas.py`
derives them from the platform's `docs/api/*.yaml` at platform commit
`36e0e96b7e5c16626d394272b727b533f2b94a04`, the v11.0.0 candidate. It works on the YAML node
`ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4`, the merged platform source for the v11.2.0 train. It works on the YAML node
graph, so every declaration survives in source order, including a schema declared twice in one
file and a declaration with no properties. A loader that counts in-file duplicates reads the same
thing here as from the source. The script drops descriptions, types, paths and the `info` block;
Expand All @@ -23,10 +23,10 @@ spec.

| File | sha256 of the source spec |
|---|---|
| `agent-api.yaml` | `49bd1b145cd3b2d29e8cc8de240cc184d4f5d24f83b6c546894d1f0a682a032a` |
| `masfeat-api.yaml` | `2d49d6af2d5b1510b373c01fce1df2b712b32766b14d477652797746c52147e7` |
| `orchestrator-api.yaml` | `b173c9bec456e4af3aa09c63306e503caa73ca0cf61da3dfaa7b21453dcd1188` |
| `policy-api.yaml` | `090730a359bf242b6ed5c1a0d63a2831c749583bd957cc3ecc64c99ead5514b7` |
| `agent-api.yaml` | `617e6236f91dd7716baaab8e2f22ef24f1713ebfd4938cc52a60a3368e3acb1a` |
| `masfeat-api.yaml` | `eb224773c2a14fc6a84a630b652b17e010a4776da28529b13e173b002d2d4756` |
| `orchestrator-api.yaml` | `a1f96d929ff35acb1204ce5ba3c6e605b8f91d93e7fa62a2fa8a760ea8486860` |
| `policy-api.yaml` | `a1a7aff59d759033f99721a40d942e8750c6026d69f9efb0edf66016f0069ae9` |

Each file's header repeats its source path, commit and digest.

Expand Down
75 changes: 44 additions & 31 deletions tests/fixtures/openapi/agent-api.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# GENERATED by scripts/snapshot_openapi_schemas.py - do not edit.
# Source: docs/api/agent-api.yaml at platform commit 36e0e96b7e5c16626d394272b727b533f2b94a04
# Source sha256: 49bd1b145cd3b2d29e8cc8de240cc184d4f5d24f83b6c546894d1f0a682a032a
# Source: docs/api/agent-api.yaml at platform commit ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4
# Source sha256: 617e6236f91dd7716baaab8e2f22ef24f1713ebfd4938cc52a60a3368e3acb1a
# Schema declarations and property names only; see tests/fixtures/openapi/README.md.
components:
schemas:
Expand All @@ -18,6 +18,7 @@ components:
"capabilities": {}
"sdk_compatibility": {}
"plugin_compatibility": {}
"upstream": {}
"PlatformCapability":
properties:
"name": {}
Expand Down Expand Up @@ -103,17 +104,6 @@ components:
"enabled_override": {}
"override_reason": {}
"expires_at": {}
"CreateOverrideResponse":
properties:
"id": {}
"policy_id": {}
"policy_type": {}
"expires_at": {}
"ttl_seconds": {}
"requested_ttl": {}
"clamped": {}
"clamped_reason": {}
"created_at": {}
"TestPatternRequest":
properties:
"pattern": {}
Expand Down Expand Up @@ -165,6 +155,16 @@ components:
"skip_llm": {}
"context": {}
"media": {}
"PolicyTestResponse":
properties:
"blocked": {}
"reason": {}
"triggered_policies": {}
"checks_performed": {}
"processing_time_ms": {}
"engine": {}
"subject_type": {}
"policy_bundle": {}
"ClientResponse":
properties:
"success": {}
Expand All @@ -173,18 +173,21 @@ components:
"plan_id": {}
"metadata": {}
"error": {}
"code": {}
"blocked": {}
"block_reason": {}
"approval_request_id": {}
"policy_info": {}
"budget_info": {}
"media_analysis": {}
"engine": {}
"subject_type": {}
"policy_bundle": {}
"policy_packs": {}
"legacy_validators": {}
"response_plane": {}
"PolicyEvaluationInfo":
properties:
"matched_policies": {}
"policies_evaluated": {}
"static_checks": {}
"processing_time": {}
Expand All @@ -205,7 +208,6 @@ components:
"context_id": {}
"approved_data": {}
"policies": {}
"approval_request_id": {}
"rate_limit": {}
"expires_at": {}
"block_reason": {}
Expand All @@ -225,8 +227,17 @@ components:
"pep_id": {}
"audience": {}
"capabilities": {}
"PendingApproval":
properties:
"approval_id": {}
"status": {}
"plane": {}
"expires_at": {}
"retry": {}
"ApprovalHoldReason": {}
"DecideRequest":
properties:
"approval_id": {}
"stage": {}
"caller_identity": {}
"target": {}
Expand All @@ -248,6 +259,8 @@ components:
"tool": {}
"DecideResponse":
properties:
"pending_approval": {}
"approval_id": {}
"verdict": {}
"decision_id": {}
"trace_id": {}
Expand Down Expand Up @@ -426,6 +439,7 @@ components:
"license_expiry": {}
"MCPQueryRequest":
properties:
"approval_id": {}
"client_id": {}
"license_key": {}
"user_token": {}
Expand All @@ -448,6 +462,7 @@ components:
"engine": {}
"subject_type": {}
"policy_bundle": {}
"policy_packs": {}
"legacy_validators": {}
"PolicyInfo":
properties:
Expand All @@ -458,7 +473,6 @@ components:
"processing_time_ms": {}
"matched_policies": {}
"exfiltration_check": {}
"dynamic_policy_info": {}
"ExplainPolicy":
properties:
"policy_id": {}
Expand Down Expand Up @@ -496,25 +510,11 @@ components:
"tool_signature": {}
"ExfiltrationCheckInfo":
properties:
"exceeded": {}
"limit_type": {}
"rows_returned": {}
"row_limit": {}
"bytes_returned": {}
"byte_limit": {}
"DynamicPolicyInfo":
properties:
"policies_evaluated": {}
"matched_policies": {}
"orchestrator_reachable": {}
"processing_time_ms": {}
"DynamicPolicyMatch":
properties:
"policy_id": {}
"policy_name": {}
"policy_type": {}
"action": {}
"message": {}
"within_limits": {}
"PolicyMatchInfo":
properties:
"policy_id": {}
Expand All @@ -524,6 +524,7 @@ components:
"action": {}
"MCPExecuteRequest":
properties:
"approval_id": {}
"client_id": {}
"license_key": {}
"user_token": {}
Expand All @@ -546,9 +547,11 @@ components:
"engine": {}
"subject_type": {}
"policy_bundle": {}
"policy_packs": {}
"legacy_validators": {}
"MCPCheckInputRequest":
properties:
"approval_id": {}
"client_id": {}
"user_token": {}
"tenant_id": {}
Expand All @@ -562,6 +565,8 @@ components:
"content_type": {}
"MCPCheckInputResponse":
properties:
"pending_approval": {}
"approval_id": {}
"allowed": {}
"block_reason": {}
"policies_evaluated": {}
Expand All @@ -573,7 +578,13 @@ components:
"override_existing_id": {}
"redacted": {}
"redacted_statement": {}
"redacted_parameters": {}
"redaction_evaluated": {}
"engine": {}
"subject_type": {}
"policy_bundle": {}
"policy_packs": {}
"legacy_validators": {}
"MCPCheckOutputRequest":
properties:
"client_id": {}
Expand All @@ -599,6 +610,7 @@ components:
"engine": {}
"subject_type": {}
"policy_bundle": {}
"policy_packs": {}
"legacy_validators": {}
"ConnectorRefreshResponse":
properties:
Expand Down Expand Up @@ -646,6 +658,7 @@ components:
"window": {}
"resets_at": {}
"upgrade": {}
"code": {}
"DecisionEntry":
properties:
"id": {}
Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/openapi/masfeat-api.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# GENERATED by scripts/snapshot_openapi_schemas.py - do not edit.
# Source: docs/api/masfeat-api.yaml at platform commit 36e0e96b7e5c16626d394272b727b533f2b94a04
# Source sha256: 2d49d6af2d5b1510b373c01fce1df2b712b32766b14d477652797746c52147e7
# Source: docs/api/masfeat-api.yaml at platform commit ba5201a52edd2bfbe9f1dadd736f19cae03d9cc4
# Source sha256: eb224773c2a14fc6a84a630b652b17e010a4776da28529b13e173b002d2d4756
# Schema declarations and property names only; see tests/fixtures/openapi/README.md.
components:
schemas:
Expand Down
Loading
Loading