From 8c7d0583189765a89a66ca472b841c6864e79525 Mon Sep 17 00:00:00 2001 From: "workos-sdk-automation[bot]" <255426317+workos-sdk-automation[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2026 21:42:18 +0000 Subject: [PATCH 1/2] chore(generated): regenerate shared files for Agents --- .last-synced-sha | 2 +- .oagen-manifest.json | 8 ++ src/workos/agents/_resource.py | 99 ++++++++++++++++++- src/workos/agents/models/__init__.py | 4 + .../models/agent_blueprints_create_request.py | 15 +-- ...blueprints_token_validate_token_request.py | 34 +++++++ .../agents/models/agent_token_validation.py | 66 +++++++++++++ src/workos/common/models/__init__.py | 6 ++ ...ueprints_token_validate_token_request.json | 3 + tests/fixtures/agent_token_validation.json | 12 +++ tests/test_agents.py | 50 +++++++--- tests/test_agents_models_round_trip.py | 49 +++++++++ 12 files changed, 323 insertions(+), 25 deletions(-) create mode 100644 src/workos/agents/models/agent_blueprints_token_validate_token_request.py create mode 100644 src/workos/agents/models/agent_token_validation.py create mode 100644 tests/fixtures/agent_blueprints_token_validate_token_request.json create mode 100644 tests/fixtures/agent_token_validation.json diff --git a/.last-synced-sha b/.last-synced-sha index 0f267924..d20a1099 100644 --- a/.last-synced-sha +++ b/.last-synced-sha @@ -1 +1 @@ -d61348070f219d16b6285f205986c2d332bf6e9c +edb560e2be3f54b668ea8d11fa5a060c87ab5087 diff --git a/.oagen-manifest.json b/.oagen-manifest.json index fb34b225..59c9d114 100644 --- a/.oagen-manifest.json +++ b/.oagen-manifest.json @@ -21,6 +21,7 @@ "src/workos/agents/models/agent_blueprints_create_request_invocable_by.py", "src/workos/agents/models/agent_blueprints_create_request_session_setting.py", "src/workos/agents/models/agent_blueprints_token_mint_token_request.py", + "src/workos/agents/models/agent_blueprints_token_validate_token_request.py", "src/workos/agents/models/agent_blueprints_update_request.py", "src/workos/agents/models/agent_blueprints_update_request_invocable_by.py", "src/workos/agents/models/agent_blueprints_update_request_session_setting.py", @@ -32,6 +33,7 @@ "src/workos/agents/models/agent_registration_claim.py", "src/workos/agents/models/agent_registration_claim_claim_completion.py", "src/workos/agents/models/agent_token.py", + "src/workos/agents/models/agent_token_validation.py", "src/workos/agents/models/claim_view_response.py", "src/workos/agents/models/claim_view_response_organization.py", "src/workos/api_keys/__init__.py", @@ -892,6 +894,7 @@ "tests/fixtures/agent_blueprints_create_request_invocable_by.json", "tests/fixtures/agent_blueprints_create_request_session_setting.json", "tests/fixtures/agent_blueprints_token_mint_token_request.json", + "tests/fixtures/agent_blueprints_token_validate_token_request.json", "tests/fixtures/agent_blueprints_update_request.json", "tests/fixtures/agent_blueprints_update_request_invocable_by.json", "tests/fixtures/agent_blueprints_update_request_session_setting.json", @@ -932,6 +935,7 @@ "tests/fixtures/agent_registration_revoked.json", "tests/fixtures/agent_registration_revoked_data.json", "tests/fixtures/agent_token.json", + "tests/fixtures/agent_token_validation.json", "tests/fixtures/api_key.json", "tests/fixtures/api_key_created.json", "tests/fixtures/api_key_created_data.json", @@ -2542,6 +2546,10 @@ "POST /user_management/waitlists/{id}/entries": { "sdkMethod": "create_waitlist_entry", "service": "user_management" + }, + "POST /agents/blueprints/{agent_blueprint_id}/tokens/validate": { + "sdkMethod": "validate_blueprint_token", + "service": "agents" } } } diff --git a/src/workos/agents/_resource.py b/src/workos/agents/_resource.py index b512f857..b8205e78 100644 --- a/src/workos/agents/_resource.py +++ b/src/workos/agents/_resource.py @@ -29,6 +29,7 @@ AgentInstanceSession, AgentRegistration, AgentToken, + AgentTokenValidation, ClaimViewResponse, ) @@ -89,10 +90,10 @@ def create_blueprint( self, *, name: str, - session_settings: AgentBlueprintsCreateRequestSessionSetting, description: str | None = None, permissions: list[str] | None = None, invocable_by: AgentBlueprintsCreateRequestInvocableBy | None = None, + session_settings: AgentBlueprintsCreateRequestSessionSetting | None = None, request_options: RequestOptions | None = None, ) -> AgentBlueprint: """Create an agent blueprint @@ -127,7 +128,9 @@ def create_blueprint( "invocable_by": invocable_by.to_dict() if invocable_by is not None else None, - "session_settings": session_settings.to_dict(), + "session_settings": session_settings.to_dict() + if session_settings is not None + else None, }.items() if v is not None } @@ -312,6 +315,49 @@ def create_blueprint_token( request_options=request_options, ) + def validate_blueprint_token( + self, + agent_blueprint_id: str, + *, + agent_access_token: str, + request_options: RequestOptions | None = None, + ) -> AgentTokenValidation: + """Validate an agent token + + Validates an agent access token: verifies its signature against the environment, that it was minted under this blueprint, and that the backing session is live (not revoked or expired, and — for delegated sessions — that the delegating user session has not ended). Returns the token claims and session metadata when valid; invalid tokens are reported as errors with stable codes. + + Args: + agent_blueprint_id: The unique ID of the agent blueprint. + agent_access_token: The agent access token (a JWT) to validate. + request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. + + Returns: + AgentTokenValidation + + Raises: + BadRequestError: If the request is malformed (400). + NotFoundError: If the resource is not found (404). + AuthenticationError: If the API key is invalid (401). + RateLimitExceededError: If rate limited (429). + ServerError: If the server returns a 5xx error. + """ + body: dict[str, Any] = { + "agent_access_token": agent_access_token, + } + return self._client.request( + method="post", + path=( + "agents", + "blueprints", + str(agent_blueprint_id), + "tokens", + "validate", + ), + body=body, + model=AgentTokenValidation, + request_options=request_options, + ) + def update_attempts( self, *, @@ -713,10 +759,10 @@ async def create_blueprint( self, *, name: str, - session_settings: AgentBlueprintsCreateRequestSessionSetting, description: str | None = None, permissions: list[str] | None = None, invocable_by: AgentBlueprintsCreateRequestInvocableBy | None = None, + session_settings: AgentBlueprintsCreateRequestSessionSetting | None = None, request_options: RequestOptions | None = None, ) -> AgentBlueprint: """Create an agent blueprint @@ -751,7 +797,9 @@ async def create_blueprint( "invocable_by": invocable_by.to_dict() if invocable_by is not None else None, - "session_settings": session_settings.to_dict(), + "session_settings": session_settings.to_dict() + if session_settings is not None + else None, }.items() if v is not None } @@ -936,6 +984,49 @@ async def create_blueprint_token( request_options=request_options, ) + async def validate_blueprint_token( + self, + agent_blueprint_id: str, + *, + agent_access_token: str, + request_options: RequestOptions | None = None, + ) -> AgentTokenValidation: + """Validate an agent token + + Validates an agent access token: verifies its signature against the environment, that it was minted under this blueprint, and that the backing session is live (not revoked or expired, and — for delegated sessions — that the delegating user session has not ended). Returns the token claims and session metadata when valid; invalid tokens are reported as errors with stable codes. + + Args: + agent_blueprint_id: The unique ID of the agent blueprint. + agent_access_token: The agent access token (a JWT) to validate. + request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. + + Returns: + AgentTokenValidation + + Raises: + BadRequestError: If the request is malformed (400). + NotFoundError: If the resource is not found (404). + AuthenticationError: If the API key is invalid (401). + RateLimitExceededError: If rate limited (429). + ServerError: If the server returns a 5xx error. + """ + body: dict[str, Any] = { + "agent_access_token": agent_access_token, + } + return await self._client.request( + method="post", + path=( + "agents", + "blueprints", + str(agent_blueprint_id), + "tokens", + "validate", + ), + body=body, + model=AgentTokenValidation, + request_options=request_options, + ) + async def update_attempts( self, *, diff --git a/src/workos/agents/models/__init__.py b/src/workos/agents/models/__init__.py index d31ad740..d1ddc67c 100644 --- a/src/workos/agents/models/__init__.py +++ b/src/workos/agents/models/__init__.py @@ -30,6 +30,9 @@ from .agent_blueprints_token_mint_token_request import ( AgentBlueprintsTokenMintTokenRequest as AgentBlueprintsTokenMintTokenRequest, ) +from .agent_blueprints_token_validate_token_request import ( + AgentBlueprintsTokenValidateTokenRequest as AgentBlueprintsTokenValidateTokenRequest, +) from .agent_blueprints_update_request import ( AgentBlueprintsUpdateRequest as AgentBlueprintsUpdateRequest, ) @@ -53,6 +56,7 @@ AgentRegistrationClaimClaimCompletion as AgentRegistrationClaimClaimCompletion, ) from .agent_token import AgentToken as AgentToken +from .agent_token_validation import AgentTokenValidation as AgentTokenValidation from .claim_view_response import ClaimViewResponse as ClaimViewResponse from .claim_view_response_organization import ( ClaimViewResponseOrganization as ClaimViewResponseOrganization, diff --git a/src/workos/agents/models/agent_blueprints_create_request.py b/src/workos/agents/models/agent_blueprints_create_request.py index 41a1b456..e31f0180 100644 --- a/src/workos/agents/models/agent_blueprints_create_request.py +++ b/src/workos/agents/models/agent_blueprints_create_request.py @@ -21,14 +21,14 @@ class AgentBlueprintsCreateRequest: name: str """Human-readable name of the agent blueprint.""" - session_settings: AgentBlueprintsCreateRequestSessionSetting - """Token and session lifetimes for sessions minted from this blueprint.""" description: str | None = None """Human-readable description of the agent blueprint.""" permissions: list[str] | None = None """Permission slugs forming the ceiling on what sessions minted from this blueprint may do. Each slug must exist in the environment.""" invocable_by: AgentBlueprintsCreateRequestInvocableBy | None = None """Who may mint sessions from this blueprint.""" + session_settings: AgentBlueprintsCreateRequestSessionSetting | None = None + """Token and session lifetimes for sessions minted from this blueprint.""" @classmethod def from_dict(cls, data: dict[str, Any]) -> AgentBlueprintsCreateRequest: @@ -36,9 +36,6 @@ def from_dict(cls, data: dict[str, Any]) -> AgentBlueprintsCreateRequest: try: return cls( name=data["name"], - session_settings=AgentBlueprintsCreateRequestSessionSetting.from_dict( - cast(dict[str, Any], data["session_settings"]) - ), description=data.get("description"), permissions=data.get("permissions"), invocable_by=AgentBlueprintsCreateRequestInvocableBy.from_dict( @@ -46,6 +43,11 @@ def from_dict(cls, data: dict[str, Any]) -> AgentBlueprintsCreateRequest: ) if (_v_invocable_by := data.get("invocable_by")) is not None else None, + session_settings=AgentBlueprintsCreateRequestSessionSetting.from_dict( + cast(dict[str, Any], _v_session_settings) + ) + if (_v_session_settings := data.get("session_settings")) is not None + else None, ) except (KeyError, ValueError) as e: _raise_deserialize_error("AgentBlueprintsCreateRequest", e) @@ -54,11 +56,12 @@ def to_dict(self) -> dict[str, Any]: """Serialize to a dictionary.""" result: dict[str, Any] = {} result["name"] = self.name - result["session_settings"] = self.session_settings.to_dict() if self.description is not None: result["description"] = self.description if self.permissions is not None: result["permissions"] = self.permissions if self.invocable_by is not None: result["invocable_by"] = self.invocable_by.to_dict() + if self.session_settings is not None: + result["session_settings"] = self.session_settings.to_dict() return result diff --git a/src/workos/agents/models/agent_blueprints_token_validate_token_request.py b/src/workos/agents/models/agent_blueprints_token_validate_token_request.py new file mode 100644 index 00000000..311778d8 --- /dev/null +++ b/src/workos/agents/models/agent_blueprints_token_validate_token_request.py @@ -0,0 +1,34 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + +from workos._types import _raise_deserialize_error + + +@dataclass(slots=True) +class AgentBlueprintsTokenValidateTokenRequest: + """Agent Blueprints Token Validate Token Request model.""" + + agent_access_token: str + """The agent access token (a JWT) to validate.""" + + @classmethod + def from_dict( + cls, data: dict[str, Any] + ) -> AgentBlueprintsTokenValidateTokenRequest: + """Deserialize from a dictionary.""" + try: + return cls( + agent_access_token=data["agent_access_token"], + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("AgentBlueprintsTokenValidateTokenRequest", e) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["agent_access_token"] = self.agent_access_token + return result diff --git a/src/workos/agents/models/agent_token_validation.py b/src/workos/agents/models/agent_token_validation.py new file mode 100644 index 00000000..caaac22a --- /dev/null +++ b/src/workos/agents/models/agent_token_validation.py @@ -0,0 +1,66 @@ +# This file is auto-generated by oagen. Do not edit. + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Literal + +from workos._types import _raise_deserialize_error + + +@dataclass(slots=True) +class AgentTokenValidation: + """Agent Token Validation model.""" + + valid: Literal[True] + """Always `true`: an invalid token is reported as an error with a stable code, never as a `200`.""" + agent_instance_id: str + """The agent instance the token was minted for.""" + agent_instance_session_id: str + """The agent instance session backing the token.""" + organization_id: str + """The organization the agent acts within.""" + permissions: list[str] + """The effective permission slugs carried by the token.""" + intent: str | None + """The caller-supplied context echoed into the token at mint time, or `null` when none was given.""" + acting_user_id: str | None + """The delegating user carried in the `act.sub` claim of the token, or `null` for autonomous sessions.""" + session_expires_at: str + """When the backing agent instance session expires.""" + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> AgentTokenValidation: + """Deserialize from a dictionary.""" + try: + return cls( + valid=data.get("valid", True), + agent_instance_id=data["agent_instance_id"], + agent_instance_session_id=data["agent_instance_session_id"], + organization_id=data["organization_id"], + permissions=data["permissions"], + intent=data["intent"], + acting_user_id=data["acting_user_id"], + session_expires_at=data["session_expires_at"], + ) + except (KeyError, ValueError) as e: + _raise_deserialize_error("AgentTokenValidation", e) + + def to_dict(self) -> dict[str, Any]: + """Serialize to a dictionary.""" + result: dict[str, Any] = {} + result["valid"] = self.valid + result["agent_instance_id"] = self.agent_instance_id + result["agent_instance_session_id"] = self.agent_instance_session_id + result["organization_id"] = self.organization_id + result["permissions"] = self.permissions + if self.intent is not None: + result["intent"] = self.intent + else: + result["intent"] = None + if self.acting_user_id is not None: + result["acting_user_id"] = self.acting_user_id + else: + result["acting_user_id"] = None + result["session_expires_at"] = self.session_expires_at + return result diff --git a/src/workos/common/models/__init__.py b/src/workos/common/models/__init__.py index 9bc6f319..8e5c38d8 100644 --- a/src/workos/common/models/__init__.py +++ b/src/workos/common/models/__init__.py @@ -51,10 +51,12 @@ from .agent_instance_created_data import ( AgentInstanceCreatedData as AgentInstanceCreatedData, ) +from .agent_instance_created_data_type import * from .agent_instance_deleted import AgentInstanceDeleted as AgentInstanceDeleted from .agent_instance_deleted_data import ( AgentInstanceDeletedData as AgentInstanceDeletedData, ) +from .agent_instance_deleted_data_type import * from .agent_instance_session_created import ( AgentInstanceSessionCreated as AgentInstanceSessionCreated, ) @@ -822,20 +824,24 @@ from .resource_export_completed_data import ( ResourceExportCompletedData as ResourceExportCompletedData, ) +from .resource_export_completed_data_resource_type import * from .resource_export_created import ResourceExportCreated as ResourceExportCreated from .resource_export_created_data import ( ResourceExportCreatedData as ResourceExportCreatedData, ) +from .resource_export_created_data_resource_type import * from .resource_export_downloaded import ( ResourceExportDownloaded as ResourceExportDownloaded, ) from .resource_export_downloaded_data import ( ResourceExportDownloadedData as ResourceExportDownloadedData, ) +from .resource_export_downloaded_data_resource_type import * from .resource_export_failed import ResourceExportFailed as ResourceExportFailed from .resource_export_failed_data import ( ResourceExportFailedData as ResourceExportFailedData, ) +from .resource_export_failed_data_resource_type import * from .role_created import RoleCreated as RoleCreated from .role_created_data import RoleCreatedData as RoleCreatedData from .role_deleted import RoleDeleted as RoleDeleted diff --git a/tests/fixtures/agent_blueprints_token_validate_token_request.json b/tests/fixtures/agent_blueprints_token_validate_token_request.json new file mode 100644 index 00000000..4de2ff44 --- /dev/null +++ b/tests/fixtures/agent_blueprints_token_validate_token_request.json @@ -0,0 +1,3 @@ +{ + "agent_access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6..." +} diff --git a/tests/fixtures/agent_token_validation.json b/tests/fixtures/agent_token_validation.json new file mode 100644 index 00000000..2d6d5e2c --- /dev/null +++ b/tests/fixtures/agent_token_validation.json @@ -0,0 +1,12 @@ +{ + "valid": true, + "agent_instance_id": "agent_01EHWNCE74X7JSDV0X3SZ3KJNY", + "agent_instance_session_id": "agent_session_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "permissions": [ + "crm:read" + ], + "intent": "renew-contract-123", + "acting_user_id": "userland_user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "session_expires_at": "2024-01-01T00:00:00.000Z" +} diff --git a/tests/test_agents.py b/tests/test_agents.py index 37d4cbe1..bd2519cc 100644 --- a/tests/test_agents.py +++ b/tests/test_agents.py @@ -18,12 +18,12 @@ from workos.agents.models import ( AgentAdminLinkClaimAttemptToExternalUserRequestUser, AgentBlueprint, - AgentBlueprintsCreateRequestSessionSetting, AgentCredentialValidation, AgentInstance, AgentInstanceSession, AgentRegistration, AgentToken, + AgentTokenValidation, ClaimViewResponse, ) from workos.common.models import ( @@ -67,12 +67,7 @@ def test_create_blueprint(self, workos, httpx_mock): httpx_mock.add_response( json=load_fixture("agent_blueprint.json"), ) - result = workos.agents.create_blueprint( - name="test_name", - session_settings=AgentBlueprintsCreateRequestSessionSetting.from_dict( - load_fixture("agent_blueprints_create_request_session_setting.json") - ), - ) + result = workos.agents.create_blueprint(name="test_name") assert isinstance(result, AgentBlueprint) assert result.object == "agent_blueprint" assert result.id == "agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY" @@ -81,7 +76,6 @@ def test_create_blueprint(self, workos, httpx_mock): assert request.url.path.endswith("/agents/blueprints") body = json.loads(request.content) assert body["name"] == "test_name" - assert "session_settings" in body def test_get_blueprint(self, workos, httpx_mock): httpx_mock.add_response( @@ -136,6 +130,24 @@ def test_create_blueprint_token(self, workos, httpx_mock): "user_delegated" ) + def test_validate_blueprint_token(self, workos, httpx_mock): + httpx_mock.add_response( + json=load_fixture("agent_token_validation.json"), + ) + result = workos.agents.validate_blueprint_token( + "test_agent_blueprint_id", agent_access_token="test_agent_access_token" + ) + assert isinstance(result, AgentTokenValidation) + assert result.valid is True + assert result.agent_instance_id == "agent_01EHWNCE74X7JSDV0X3SZ3KJNY" + request = httpx_mock.get_request() + assert request.method == "POST" + assert request.url.path.endswith( + "/agents/blueprints/test_agent_blueprint_id/tokens/validate" + ) + body = json.loads(request.content) + assert body["agent_access_token"] == "test_agent_access_token" + def test_update_attempts(self, workos, httpx_mock): httpx_mock.add_response( json=load_fixture("claim_view_response.json"), @@ -418,12 +430,7 @@ async def test_list_blueprints_encodes_query_params(self, async_workos, httpx_mo @pytest.mark.asyncio async def test_create_blueprint(self, async_workos, httpx_mock): httpx_mock.add_response(json=load_fixture("agent_blueprint.json")) - result = await async_workos.agents.create_blueprint( - name="test_name", - session_settings=AgentBlueprintsCreateRequestSessionSetting.from_dict( - load_fixture("agent_blueprints_create_request_session_setting.json") - ), - ) + result = await async_workos.agents.create_blueprint(name="test_name") assert isinstance(result, AgentBlueprint) assert result.object == "agent_blueprint" assert result.id == "agent_blueprint_01EHWNCE74X7JSDV0X3SZ3KJNY" @@ -478,6 +485,21 @@ async def test_create_blueprint_token(self, async_workos, httpx_mock): "/agents/blueprints/test_agent_blueprint_id/tokens" ) + @pytest.mark.asyncio + async def test_validate_blueprint_token(self, async_workos, httpx_mock): + httpx_mock.add_response(json=load_fixture("agent_token_validation.json")) + result = await async_workos.agents.validate_blueprint_token( + "test_agent_blueprint_id", agent_access_token="test_agent_access_token" + ) + assert isinstance(result, AgentTokenValidation) + assert result.valid is True + assert result.agent_instance_id == "agent_01EHWNCE74X7JSDV0X3SZ3KJNY" + request = httpx_mock.get_request() + assert request.method == "POST" + assert request.url.path.endswith( + "/agents/blueprints/test_agent_blueprint_id/tokens/validate" + ) + @pytest.mark.asyncio async def test_update_attempts(self, async_workos, httpx_mock): httpx_mock.add_response(json=load_fixture("claim_view_response.json")) diff --git a/tests/test_agents_models_round_trip.py b/tests/test_agents_models_round_trip.py index 80954241..ab04e87f 100644 --- a/tests/test_agents_models_round_trip.py +++ b/tests/test_agents_models_round_trip.py @@ -20,6 +20,7 @@ AgentRegistrationClaim, AgentRegistrationClaimClaimCompletion, AgentToken, + AgentTokenValidation, ClaimViewResponse, ClaimViewResponseOrganization, ) @@ -327,6 +328,54 @@ def test_agent_token_minimal_payload(self): ) assert serialized["permissions"] == data["permissions"] + def test_agent_token_validation_round_trip(self): + data = load_fixture("agent_token_validation.json") + instance = AgentTokenValidation.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = AgentTokenValidation.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_agent_token_validation_minimal_payload(self): + data = { + "valid": True, + "agent_instance_id": "agent_01EHWNCE74X7JSDV0X3SZ3KJNY", + "agent_instance_session_id": "agent_session_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "permissions": ["crm:read"], + "intent": None, + "acting_user_id": None, + "session_expires_at": "2024-01-01T00:00:00.000Z", + } + instance = AgentTokenValidation.from_dict(data) + serialized = instance.to_dict() + assert serialized["valid"] == data["valid"] + assert serialized["agent_instance_id"] == data["agent_instance_id"] + assert ( + serialized["agent_instance_session_id"] == data["agent_instance_session_id"] + ) + assert serialized["organization_id"] == data["organization_id"] + assert serialized["permissions"] == data["permissions"] + assert serialized["intent"] == data["intent"] + assert serialized["acting_user_id"] == data["acting_user_id"] + assert serialized["session_expires_at"] == data["session_expires_at"] + + def test_agent_token_validation_preserves_nullable_fields(self): + data = { + "valid": True, + "agent_instance_id": "agent_01EHWNCE74X7JSDV0X3SZ3KJNY", + "agent_instance_session_id": "agent_session_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "permissions": ["crm:read"], + "intent": None, + "acting_user_id": None, + "session_expires_at": "2024-01-01T00:00:00.000Z", + } + instance = AgentTokenValidation.from_dict(data) + serialized = instance.to_dict() + assert serialized["intent"] is None + assert serialized["acting_user_id"] is None + def test_agent_instance_session_round_trip(self): data = load_fixture("agent_instance_session.json") instance = AgentInstanceSession.from_dict(data) From 4051aa5e2f3827c32acd2df23e52ec0c26168e94 Mon Sep 17 00:00:00 2001 From: "workos-sdk-automation[bot]" <255426317+workos-sdk-automation[bot]@users.noreply.github.com> Date: Tue, 1 Sep 2026 21:42:23 +0000 Subject: [PATCH 2/2] chore(generated): add release notes fragment --- ...T21-42-23-b6350ef365d412ae1775ac389c8d8e4ad8c20734.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changelog-pending/2026-09-01T21-42-23-b6350ef365d412ae1775ac389c8d8e4ad8c20734.md diff --git a/.changelog-pending/2026-09-01T21-42-23-b6350ef365d412ae1775ac389c8d8e4ad8c20734.md b/.changelog-pending/2026-09-01T21-42-23-b6350ef365d412ae1775ac389c8d8e4ad8c20734.md new file mode 100644 index 00000000..6ba07dc9 --- /dev/null +++ b/.changelog-pending/2026-09-01T21-42-23-b6350ef365d412ae1775ac389c8d8e4ad8c20734.md @@ -0,0 +1,9 @@ +* [#722](https://github.com/workos/workos-python/pull/722) fix(generated): regenerate from spec + + **Features** + * **[agents](https://workos.com/docs/reference/agents)**: + * Made `AgentBlueprintsCreateRequest.session_settings` optional + * Added model `AgentTokenValidation` + * Added model `AgentBlueprintsTokenValidateTokenRequest` + * **agents_blueprints_tokens**: + * Added endpoint `POST /agents/blueprints/{agent_blueprint_id}/tokens/validate`