Skip to content

Commit 056700c

Browse files
feat(client): add demo mode via AXONFLOW_DEMO env var (#133)
* feat(client): add AXONFLOW_DEMO env var for demo mode * feat(client): append random suffix to client_id in demo mode * feat(community-saas): try.getaxonflow.com integration - Rename AXONFLOW_DEMO → AXONFLOW_TRY - URL: demo.getaxonflow.com → try.getaxonflow.com - Remove client-side random suffix (server generates UUID tenant_id) - Add register_try() helper in axonflow.community - Checkpoint telemetry reports endpoint_type: "community-saas" in try mode * chore: set release date 2026-04-09 * fix(lint): sort imports in community module * fix(lint): add type annotations to community module * fix(changelog): remove entries not in this release * fix: check AXONFLOW_TRY before endpoint validation (was raising TypeError) * fix(lint): resolve mypy type error on resolved_endpoint (str | None → str) --------- Co-authored-by: Saurabh Jain <saurabhjain1592@gmail.com>
1 parent cff6d07 commit 056700c

4 files changed

Lines changed: 48 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,12 @@ All notable changes to the AxonFlow Python 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-
## [6.3.0] - Release Pending (2026-04-09)
8+
## [6.3.0] - 2026-04-09
99

1010
### Added
11-
12-
- **Explicit IPv6 + RFC1918 boundary test coverage.** The v6.2.0 test suite relied on Python stdlib `ipaddress.is_private` for correctness and didn't assert the behavior explicitly. New cases cover:
13-
- `172.15.0.1` and `172.32.0.1` must be `remote` (RFC1918 boundary)
14-
- `172.16.0.0` and `172.31.255.255` must be `private_network`
15-
- IPv6 ULA (`fd00::1`, `fd12:3456:789a::1`, `fc00::1`) → `private_network`
16-
- IPv6 link-local (`fe80::1`) → `private_network`
17-
- Public IPv6 (`2001:4860:4860::8888`, `2606:4700:4700::1111`) → `remote`
18-
- IPv6 loopback `::1``localhost`
19-
20-
No runtime behavior change — Python's stdlib classifier was already correct for all these cases. The added tests are cross-SDK parity with TS/Java/Go.
11+
- `AXONFLOW_TRY=1` environment variable to connect to `try.getaxonflow.com` shared evaluation server
12+
- `register_try()` helper in `axonflow.community` for self-registering a tenant
13+
- Checkpoint telemetry reports `endpoint_type: "community-saas"` when try mode is active
2114

2215
---
2316

axonflow/client.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -358,11 +358,18 @@ def __init__(
358358
359359
As of v1.0.0, all routes go through a single endpoint (Single Entry Point Architecture).
360360
"""
361-
# Support AXONFLOW_AGENT_URL env var for backwards compatibility
362-
resolved_endpoint = endpoint or os.environ.get("AXONFLOW_AGENT_URL")
363-
if not resolved_endpoint:
364-
msg = "endpoint is required (or set AXONFLOW_AGENT_URL environment variable)"
365-
raise TypeError(msg)
361+
# Try mode: auto-connect to try.getaxonflow.com (must be checked before endpoint validation)
362+
if os.environ.get("AXONFLOW_TRY") == "1":
363+
resolved_endpoint = "https://try.getaxonflow.com"
364+
if not client_id:
365+
msg = "client_id is required in try mode (AXONFLOW_TRY=1)"
366+
raise TypeError(msg)
367+
else:
368+
# Support AXONFLOW_AGENT_URL env var for backwards compatibility
369+
resolved_endpoint = endpoint or os.environ.get("AXONFLOW_AGENT_URL") or ""
370+
if not resolved_endpoint:
371+
msg = "endpoint is required (or set AXONFLOW_AGENT_URL environment variable)"
372+
raise TypeError(msg)
366373

367374
if isinstance(mode, str):
368375
mode = Mode(mode)

axonflow/community.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Community SaaS registration helper for try.getaxonflow.com."""
2+
3+
from __future__ import annotations
4+
5+
from typing import Any
6+
7+
import httpx
8+
9+
TRY_ENDPOINT = "https://try.getaxonflow.com"
10+
11+
12+
def register_try(label: str = "", endpoint: str = TRY_ENDPOINT) -> dict[str, Any]:
13+
"""Register for a free evaluation tenant on try.getaxonflow.com.
14+
15+
Returns dict with keys: tenant_id, secret, secret_prefix, expires_at, endpoint, note.
16+
Store the secret securely — it is shown only once.
17+
18+
Args:
19+
label: Optional human-readable name for the registration.
20+
endpoint: Override the default endpoint (for local testing).
21+
"""
22+
response = httpx.post(
23+
f"{endpoint}/api/v1/register",
24+
json={"label": label} if label else {},
25+
timeout=10.0,
26+
)
27+
response.raise_for_status()
28+
data: dict[str, Any] = response.json()
29+
return data

axonflow/telemetry.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ def _classify_endpoint(url: str | None) -> str: # noqa: PLR0911
8787
"""Classify the configured AxonFlow endpoint for analytics (#1525).
8888
8989
Returns one of:
90+
``"community-saas"`` — try.getaxonflow.com shared evaluation server
9091
``"localhost"`` — localhost, 127.0.0.1, ::1, 0.0.0.0, ``*.localhost``
9192
``"private_network"`` — RFC1918 ranges, link-local, ``*.local``,
9293
``*.internal``, ``*.lan``, ``*.intranet``
@@ -95,6 +96,8 @@ def _classify_endpoint(url: str | None) -> str: # noqa: PLR0911
9596
9697
The raw URL is never sent — only the classification. See issue #1525.
9798
"""
99+
if os.environ.get("AXONFLOW_TRY") == "1":
100+
return "community-saas"
98101
if not url:
99102
return "unknown"
100103
try:

0 commit comments

Comments
 (0)