diff --git a/README.md b/README.md index 2a53fda..426996e 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ if status["status"] == "verified": # for an existing operator credential. client.create_session(address="0x...") client.create_session(operator_token="opc_...") # KYC refresh +client.create_session(kind="sign_in") # registration-only: account sign-in, no identity documents ``` ### Wallet resolution diff --git a/agentscore/client.py b/agentscore/client.py index 4223ff5..d8a6c76 100644 --- a/agentscore/client.py +++ b/agentscore/client.py @@ -4,7 +4,7 @@ import logging import time from importlib.metadata import version as _pkg_version -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Literal import httpx @@ -308,12 +308,17 @@ def create_session( product_name: str | None = None, address: str | None = None, operator_token: str | None = None, + kind: Literal["kyc", "sign_in"] | None = None, ) -> SessionCreateResponse: """Create an assessment session for deferred scoring. ``address`` pre-associates the session with a known wallet (EVM ``0x...`` or Solana base58). ``operator_token`` pre-associates with an existing ``opc_...`` — - e.g. refresh KYC for a credential. + e.g. refresh KYC for a credential. ``kind`` selects the session kind: ``"kyc"`` + (the API default) runs identity verification; ``"sign_in"`` is registration-only + (the buyer signs in with an AgentScore account, no identity documents) and mints a + ``sign_in``-scoped credential, for merchants that key durable state on the account + without any compliance policy. """ body: dict[str, Any] = {} if context is not None: @@ -324,6 +329,8 @@ def create_session( body["address"] = address if operator_token is not None: body["operator_token"] = operator_token + if kind is not None: + body["kind"] = kind client = self._get_sync_client() return self._send_sync(lambda: client.post("/v1/sessions", json=body)) @@ -451,12 +458,17 @@ async def acreate_session( product_name: str | None = None, address: str | None = None, operator_token: str | None = None, + kind: Literal["kyc", "sign_in"] | None = None, ) -> SessionCreateResponse: """Create an assessment session for deferred scoring. ``address`` pre-associates the session with a known wallet (EVM ``0x...`` or Solana base58). ``operator_token`` pre-associates with an existing ``opc_...`` — - e.g. refresh KYC for a credential. + e.g. refresh KYC for a credential. ``kind`` selects the session kind: ``"kyc"`` + (the API default) runs identity verification; ``"sign_in"`` is registration-only + (the buyer signs in with an AgentScore account, no identity documents) and mints a + ``sign_in``-scoped credential, for merchants that key durable state on the account + without any compliance policy. """ body: dict[str, Any] = {} if context is not None: @@ -467,6 +479,8 @@ async def acreate_session( body["address"] = address if operator_token is not None: body["operator_token"] = operator_token + if kind is not None: + body["kind"] = kind client = self._get_async_client() return await self._send_async(lambda: client.post("/v1/sessions", json=body)) diff --git a/agentscore/types.py b/agentscore/types.py index 00be467..97cc402 100644 --- a/agentscore/types.py +++ b/agentscore/types.py @@ -395,6 +395,8 @@ class _SessionCreateResponseRequired(TypedDict): class SessionCreateResponse(_SessionCreateResponseRequired, total=False): + # The kind the session was minted with; absent on older API responses. + kind: Literal["kyc", "sign_in"] # Structured next_steps with action=deliver_verify_url_and_poll. next_steps: SessionCreateNextSteps # Cross-merchant memory hint on first session creation. diff --git a/pyproject.toml b/pyproject.toml index eb24ba8..d2f1958 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "agentscore-py" -version = "2.6.8" +version = "2.6.9" description = "Python client for the AgentScore APIs" readme = "README.md" license = "MIT" diff --git a/tests/test_client.py b/tests/test_client.py index cbc85f9..2c096a3 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1023,10 +1023,12 @@ def test_create_session_with_first_class_fields(): client.create_session( context="wine purchase verification", product_name="Cabernet Reserve 2022", + kind="sign_in", ) body = json.loads(route.calls.last.request.content) assert body["context"] == "wine purchase verification" assert body["product_name"] == "Cabernet Reserve 2022" + assert body["kind"] == "sign_in" @respx.mock @@ -1037,6 +1039,7 @@ def test_create_session_omits_none_fields(): body = json.loads(route.calls.last.request.content) assert "context" not in body assert "product_name" not in body + assert "kind" not in body @respx.mock diff --git a/uv.lock b/uv.lock index 123ba44..7923dbe 100644 --- a/uv.lock +++ b/uv.lock @@ -7,7 +7,7 @@ prerelease-mode = "disallow" [[package]] name = "agentscore-py" -version = "2.6.8" +version = "2.6.9" source = { editable = "." } dependencies = [ { name = "httpx" },