Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
* [#721](https://github.com/workos/workos-python/pull/721) 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`
2 changes: 1 addition & 1 deletion .last-synced-sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d61348070f219d16b6285f205986c2d332bf6e9c
edb560e2be3f54b668ea8d11fa5a060c87ab5087
8 changes: 8 additions & 0 deletions .oagen-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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"
}
}
}
99 changes: 95 additions & 4 deletions src/workos/agents/_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
AgentInstanceSession,
AgentRegistration,
AgentToken,
AgentTokenValidation,
ClaimViewResponse,
)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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,
*,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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,
*,
Expand Down
4 changes: 4 additions & 0 deletions src/workos/agents/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand All @@ -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,
Expand Down
15 changes: 9 additions & 6 deletions src/workos/agents/models/agent_blueprints_create_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,33 @@ 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:
"""Deserialize from a dictionary."""
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(
cast(dict[str, Any], _v_invocable_by)
)
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)
Expand All @@ -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
Original file line number Diff line number Diff line change
@@ -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
66 changes: 66 additions & 0 deletions src/workos/agents/models/agent_token_validation.py
Original file line number Diff line number Diff line change
@@ -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
Loading