Skip to content

Commit 4458477

Browse files
George-iamgeobon
andauthored
feat: add correlation and idempotency intent options (#3)
Update create_intent to enforce correlation_id and optionally send idempotency key so Python SDK write behavior matches Track C conformance expectations. Made-with: Cursor Co-authored-by: George-iam <georgeb@gmail.com>
1 parent 3d5527b commit 4458477

3 files changed

Lines changed: 69 additions & 6 deletions

File tree

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ config = AxmeClientConfig(
1818

1919
with AxmeClient(config) as client:
2020
print(client.health())
21+
result = client.create_intent(
22+
{
23+
"intent_type": "notify.message.v1",
24+
"from_agent": "agent://example/sender",
25+
"to_agent": "agent://example/receiver",
26+
"payload": {"text": "hello"},
27+
},
28+
correlation_id="11111111-1111-1111-1111-111111111111",
29+
idempotency_key="create-intent-001",
30+
)
31+
print(result)
2132
```
2233

2334
## Development

axme_sdk/client.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,24 @@ def health(self) -> dict[str, Any]:
4444
raise AxmeHttpError(response.status_code, response.text)
4545
return response.json()
4646

47-
def create_intent(self, payload: dict[str, Any]) -> dict[str, Any]:
48-
response = self._http.post("/v1/intents", json=payload)
47+
def create_intent(
48+
self,
49+
payload: dict[str, Any],
50+
*,
51+
correlation_id: str,
52+
idempotency_key: str | None = None,
53+
) -> dict[str, Any]:
54+
request_payload = dict(payload)
55+
existing_correlation_id = request_payload.get("correlation_id")
56+
if existing_correlation_id is not None and existing_correlation_id != correlation_id:
57+
raise ValueError("payload correlation_id must match correlation_id argument")
58+
request_payload["correlation_id"] = correlation_id
59+
60+
headers: dict[str, str] | None = None
61+
if idempotency_key is not None:
62+
headers = {"Idempotency-Key": idempotency_key}
63+
64+
response = self._http.post("/v1/intents", json=request_payload, headers=headers)
4965
if response.status_code >= 400:
5066
raise AxmeHttpError(response.status_code, response.text)
5167
return response.json()

tests/test_client.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
import json
4+
35
import httpx
46
import pytest
57

@@ -36,16 +38,31 @@ def handler(request: httpx.Request) -> httpx.Response:
3638

3739

3840
def test_create_intent_success() -> None:
39-
payload = {"intent_type": "notify", "recipient": "agent://user/test"}
41+
payload = {
42+
"intent_type": "notify.message.v1",
43+
"to_agent": "agent://user/test",
44+
"from_agent": "agent://user/self",
45+
"payload": {"text": "hello"},
46+
}
4047

4148
def handler(request: httpx.Request) -> httpx.Response:
4249
assert request.method == "POST"
4350
assert request.url.path == "/v1/intents"
44-
assert request.read() == b'{"intent_type":"notify","recipient":"agent://user/test"}'
51+
body = json.loads(request.read().decode("utf-8"))
52+
assert body["correlation_id"] == "11111111-1111-1111-1111-111111111111"
53+
assert body["intent_type"] == "notify.message.v1"
54+
assert request.headers["idempotency-key"] == "idem-1"
4555
return httpx.Response(200, json={"intent_id": "it_123"})
4656

4757
client = _client(handler)
48-
assert client.create_intent(payload) == {"intent_id": "it_123"}
58+
assert (
59+
client.create_intent(
60+
payload,
61+
correlation_id="11111111-1111-1111-1111-111111111111",
62+
idempotency_key="idem-1",
63+
)
64+
== {"intent_id": "it_123"}
65+
)
4966

5067

5168
def test_create_intent_raises_http_error() -> None:
@@ -55,6 +72,25 @@ def handler(request: httpx.Request) -> httpx.Response:
5572
client = _client(handler, api_key="bad-token")
5673

5774
with pytest.raises(AxmeHttpError) as exc_info:
58-
client.create_intent({"intent_type": "notify"})
75+
client.create_intent(
76+
{"intent_type": "notify.message.v1", "to_agent": "agent://x", "from_agent": "agent://y", "payload": {}},
77+
correlation_id="11111111-1111-1111-1111-111111111111",
78+
)
5979

6080
assert exc_info.value.status_code == 401
81+
82+
83+
def test_create_intent_raises_for_mismatched_correlation_id() -> None:
84+
client = _client(lambda request: httpx.Response(200, json={"intent_id": "it_123"}))
85+
86+
with pytest.raises(ValueError, match="payload correlation_id"):
87+
client.create_intent(
88+
{
89+
"intent_type": "notify.message.v1",
90+
"to_agent": "agent://x",
91+
"from_agent": "agent://y",
92+
"payload": {},
93+
"correlation_id": "22222222-2222-2222-2222-222222222222",
94+
},
95+
correlation_id="11111111-1111-1111-1111-111111111111",
96+
)

0 commit comments

Comments
 (0)