From e7fe4f59f7d8c847a29b4bb684c6b02a833d8a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E9=87=8C?= Date: Thu, 13 Aug 2026 15:37:12 +0800 Subject: [PATCH 1/4] feat(agentstudio): add webhook endpoint APIs --- dashscope/agentstudio/__init__.py | 16 + dashscope/agentstudio/client.py | 6 + dashscope/agentstudio/constants.py | 112 +++++++ dashscope/agentstudio/resources/__init__.py | 6 + dashscope/agentstudio/resources/_helpers.py | 17 ++ .../resources/webhook_endpoints.py | 278 ++++++++++++++++++ dashscope/agentstudio/types/__init__.py | 9 + dashscope/agentstudio/types/models.py | 91 ++++++ dashscope/agentstudio/types/params.py | 23 ++ 9 files changed, 558 insertions(+) create mode 100644 dashscope/agentstudio/resources/webhook_endpoints.py diff --git a/dashscope/agentstudio/__init__.py b/dashscope/agentstudio/__init__.py index 47727d52..211190eb 100644 --- a/dashscope/agentstudio/__init__.py +++ b/dashscope/agentstudio/__init__.py @@ -68,6 +68,15 @@ EnvironmentCreateParams, EnvironmentUpdateParams, SessionEventSendParams, + WebhookEndpointCreateParams, + WebhookEndpointUpdateParams, + WebhookEventListParams, +) +from .constants import ( + WebhookDeliveryStatus, + WebhookDisabledReason, + WebhookEventType, + WebhookStatus, ) __all__ = [ @@ -115,4 +124,11 @@ "EnvironmentCreateParams", "EnvironmentUpdateParams", "SessionEventSendParams", + "WebhookEndpointCreateParams", + "WebhookEndpointUpdateParams", + "WebhookEventListParams", + "WebhookStatus", + "WebhookDisabledReason", + "WebhookDeliveryStatus", + "WebhookEventType", ] diff --git a/dashscope/agentstudio/client.py b/dashscope/agentstudio/client.py index ce22cc24..77c6b339 100644 --- a/dashscope/agentstudio/client.py +++ b/dashscope/agentstudio/client.py @@ -18,6 +18,10 @@ from dashscope.agentstudio.resources.sessions import Sessions, AsyncSessions from dashscope.agentstudio.resources.skills import Skills, AsyncSkills from dashscope.agentstudio.resources.vaults import Vaults, AsyncVaults +from dashscope.agentstudio.resources.webhook_endpoints import ( + AsyncWebhookEndpoints, + WebhookEndpoints, +) from dashscope.agentstudio.constants import ( AGENTSTUDIO_BASE_URL_TEMPLATE, AGENTSTUDIO_DEFAULT_REGION, @@ -121,6 +125,7 @@ def __init__( self.files = Files(self) self.skills = Skills(self) self.vaults = Vaults(self) + self.webhook_endpoints = WebhookEndpoints(self) def close(self) -> None: self.transport.close() @@ -191,6 +196,7 @@ def __init__( self.files = AsyncFiles(self) self.skills = AsyncSkills(self) self.vaults = AsyncVaults(self) + self.webhook_endpoints = AsyncWebhookEndpoints(self) async def aclose(self) -> None: await self.transport.aclose() diff --git a/dashscope/agentstudio/constants.py b/dashscope/agentstudio/constants.py index f5891552..3d0699e5 100644 --- a/dashscope/agentstudio/constants.py +++ b/dashscope/agentstudio/constants.py @@ -93,3 +93,115 @@ class SessionStatus(StrEnum): RUNNING = "running" RESCHEDULING = "rescheduling" TERMINATED = "terminated" + + +class WebhookStatus(StrEnum): + """Webhook endpoint activation status.""" + + # The endpoint can receive webhook deliveries. + ACTIVE = "ACTIVE" + # The endpoint does not receive webhook deliveries. + DISABLED = "DISABLED" + + +class WebhookDisabledReason(StrEnum): + """Reason why a webhook endpoint was disabled.""" + + # The endpoint was disabled manually. + MANUAL = "MANUAL" + # The endpoint reached the consecutive delivery failure threshold. + CONSECUTIVE_DELIVERY_FAILURES = "CONSECUTIVE_DELIVERY_FAILURES" + # The endpoint returned an HTTP redirect response. + REDIRECT_RESPONSE = "REDIRECT_RESPONSE" + # The endpoint failed server-side request forgery validation. + SSRF_VALIDATION_FAILED = "SSRF_VALIDATION_FAILED" + # The endpoint failed Transport Layer Security validation. + TLS_VALIDATION_FAILED = "TLS_VALIDATION_FAILED" + + +class WebhookDeliveryStatus(StrEnum): + """Webhook delivery audit status.""" + + # The delivery is waiting to start. + PENDING = "PENDING" + # The delivery is currently being sent. + DELIVERING = "DELIVERING" + # The delivery is waiting for its next retry. + WAITING_RETRY = "WAITING_RETRY" + # The delivery completed successfully. + SUCCEEDED = "SUCCEEDED" + # The delivery exhausted all attempts. + FAILED = "FAILED" + # The delivery was canceled because its endpoint was disabled or deleted. + CANCELED = "CANCELED" + + +class WebhookEventType(StrEnum): + """Event types accepted by webhook endpoint subscriptions.""" + + # Subscribe to every supported event type. + ALL = "*" + # A session was created. + SESSION_CREATED = "session.created" + # A session was updated. + SESSION_UPDATED = "session.updated" + # A session was archived. + SESSION_ARCHIVED = "session.archived" + # A session was deleted. + SESSION_DELETED = "session.deleted" + # A session run started. + SESSION_STATUS_RUN_STARTED = "session.status_run_started" + # A session entered the idle state. + SESSION_STATUS_IDLED = "session.status_idled" + # A session entered the terminated state. + SESSION_STATUS_TERMINATED = "session.status_terminated" + # A session thread was created. + SESSION_THREAD_CREATED = "session.thread_created" + # A session thread run started. + SESSION_THREAD_RUN_STARTED = "session.thread_run_started" + # A session thread entered the idle state. + SESSION_THREAD_IDLED = "session.thread_idled" + # A session thread entered the terminated state. + SESSION_THREAD_TERMINATED = "session.thread_terminated" + # An agent was created. + AGENT_CREATED = "agent.created" + # An agent was updated. + AGENT_UPDATED = "agent.updated" + # An agent was archived. + AGENT_ARCHIVED = "agent.archived" + # A deployment was created. + DEPLOYMENT_CREATED = "deployment.created" + # A deployment was updated. + DEPLOYMENT_UPDATED = "deployment.updated" + # A deployment was archived. + DEPLOYMENT_ARCHIVED = "deployment.archived" + # A deployment was paused. + DEPLOYMENT_PAUSED = "deployment.paused" + # A deployment was resumed. + DEPLOYMENT_UNPAUSED = "deployment.unpaused" + # A deployment run started. + DEPLOYMENT_RUN_STARTED = "deployment_run.started" + # A deployment run failed. + DEPLOYMENT_RUN_FAILED = "deployment_run.failed" + # A deployment run succeeded. + DEPLOYMENT_RUN_SUCCEEDED = "deployment_run.succeeded" + # An environment was created. + ENVIRONMENT_CREATED = "environment.created" + # An environment was updated. + ENVIRONMENT_UPDATED = "environment.updated" + # An environment was archived. + ENVIRONMENT_ARCHIVED = "environment.archived" + # An environment was deleted. + ENVIRONMENT_DELETED = "environment.deleted" + # A vault was created. + VAULT_CREATED = "vault.created" + # A vault was archived. + VAULT_ARCHIVED = "vault.archived" + # A vault was deleted. + VAULT_DELETED = "vault.deleted" + # A vault credential was created. + VAULT_CREDENTIAL_CREATED = "vault_credential.created" + # A vault credential was archived. + VAULT_CREDENTIAL_ARCHIVED = "vault_credential.archived" + # A vault credential was deleted. + VAULT_CREDENTIAL_DELETED = "vault_credential.deleted" diff --git a/dashscope/agentstudio/resources/__init__.py b/dashscope/agentstudio/resources/__init__.py index 853db58b..701ab0c5 100644 --- a/dashscope/agentstudio/resources/__init__.py +++ b/dashscope/agentstudio/resources/__init__.py @@ -40,6 +40,10 @@ Credentials, Vaults, ) +from dashscope.agentstudio.resources.webhook_endpoints import ( + AsyncWebhookEndpoints, + WebhookEndpoints, +) __all__ = [ "Agents", @@ -60,6 +64,8 @@ "AsyncSessionEvents", "Vaults", "AsyncVaults", + "WebhookEndpoints", + "AsyncWebhookEndpoints", "_TypedEventStream", "_AioTypedEventStream", ] diff --git a/dashscope/agentstudio/resources/_helpers.py b/dashscope/agentstudio/resources/_helpers.py index e7ee3c46..0bbf61f9 100644 --- a/dashscope/agentstudio/resources/_helpers.py +++ b/dashscope/agentstudio/resources/_helpers.py @@ -17,6 +17,9 @@ Skill, SkillVersion, Vault, + WebhookEndpoint, + WebhookEvent, + WebhookSecretReset, parse_server_event, ) @@ -66,6 +69,20 @@ def _coerce_credential(payload: Mapping[str, Any]) -> Credential: return Credential(**dict(payload)) +def _coerce_webhook_endpoint(payload: Mapping[str, Any]) -> WebhookEndpoint: + return WebhookEndpoint(**dict(payload)) + + +def _coerce_webhook_event(payload: Mapping[str, Any]) -> WebhookEvent: + return WebhookEvent(**dict(payload)) + + +def _coerce_webhook_secret_reset( + payload: Mapping[str, Any], +) -> WebhookSecretReset: + return WebhookSecretReset(**dict(payload)) + + # --------------------------------------------------------------------------- # Path helpers # --------------------------------------------------------------------------- diff --git a/dashscope/agentstudio/resources/webhook_endpoints.py b/dashscope/agentstudio/resources/webhook_endpoints.py new file mode 100644 index 00000000..ea277190 --- /dev/null +++ b/dashscope/agentstudio/resources/webhook_endpoints.py @@ -0,0 +1,278 @@ +# -*- coding: utf-8 -*- +# Copyright (c) Alibaba, Inc. and its affiliates. +"""Managed Agent webhook endpoint resource classes.""" + +from __future__ import annotations + +from typing import Optional, Sequence + +from dashscope.agentstudio.pagination import ( + AsyncCursorPage, + CursorPage, + build_page, +) +from dashscope.agentstudio.resources._helpers import ( + _coerce_webhook_endpoint, + _coerce_webhook_event, + _coerce_webhook_secret_reset, +) +from dashscope.agentstudio.types import ( + WebhookEndpoint, + WebhookEndpointList, + WebhookEvent, + WebhookSecretReset, +) +from dashscope.agentstudio.types.params import ( + WebhookEndpointCreateParams, + WebhookEndpointUpdateParams, + WebhookEventListParams, +) + + +# Relative path of the webhook endpoint collection. +_PATH_WEBHOOK_ENDPOINTS = "/webhook_endpoints" + + +class WebhookEndpoints: + """Synchronous Managed Agent webhook endpoint APIs.""" + + def __init__(self, client) -> None: + self._client = client + + def create( + self, + *, + url: str, + events: Sequence[str], + description: Optional[str] = None, + ) -> WebhookEndpoint: + body = WebhookEndpointCreateParams( + url=url, + events=list(events), + description=description, + ).to_dict() + response = self._client.transport.request( + "POST", + _PATH_WEBHOOK_ENDPOINTS, + json=body, + ) + return _coerce_webhook_endpoint(response.data) + + def retrieve(self, webhook_id: str) -> WebhookEndpoint: + response = self._client.transport.request( + "GET", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}", + ) + return _coerce_webhook_endpoint(response.data) + + get = retrieve + + def list(self) -> WebhookEndpointList: + response = self._client.transport.request( + "GET", + _PATH_WEBHOOK_ENDPOINTS, + ) + return WebhookEndpointList(**response.data) + + def update( + self, + webhook_id: str, + *, + description: Optional[str] = None, + url: Optional[str] = None, + events: Optional[Sequence[str]] = None, + ) -> WebhookEndpoint: + body = WebhookEndpointUpdateParams( + description=description, + url=url, + events=list(events) if events is not None else None, + ).to_dict() + response = self._client.transport.request( + "PUT", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}", + json=body, + ) + return _coerce_webhook_endpoint(response.data) + + def delete(self, webhook_id: str) -> None: + self._client.transport.request( + "DELETE", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}", + ) + + def enable(self, webhook_id: str) -> WebhookEndpoint: + response = self._client.transport.request( + "POST", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/enable", + ) + return _coerce_webhook_endpoint(response.data) + + def disable(self, webhook_id: str) -> WebhookEndpoint: + response = self._client.transport.request( + "POST", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/disable", + ) + return _coerce_webhook_endpoint(response.data) + + def test(self, webhook_id: str) -> WebhookEvent: + response = self._client.transport.request( + "POST", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/test", + ) + return _coerce_webhook_event(response.data) + + def reset_secret(self, webhook_id: str) -> WebhookSecretReset: + response = self._client.transport.request( + "POST", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/reset_secret", + ) + return _coerce_webhook_secret_reset(response.data) + + def list_events( + self, + webhook_id: str, + *, + limit: Optional[int] = None, + page: Optional[str] = None, + ) -> CursorPage[WebhookEvent]: + params = WebhookEventListParams(limit=limit, page=page).to_dict() + response = self._client.transport.request( + "GET", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/events", + params=params, + ) + return build_page( + payload=response.data, + item_factory=_coerce_webhook_event, + request_id=response.request_id, + fetch_next=lambda cursor: self.list_events( + webhook_id, + limit=limit, + page=cursor, + ), + ) + + +class AsyncWebhookEndpoints: + """Asynchronous Managed Agent webhook endpoint APIs.""" + + def __init__(self, client) -> None: + self._client = client + + async def create( + self, + *, + url: str, + events: Sequence[str], + description: Optional[str] = None, + ) -> WebhookEndpoint: + body = WebhookEndpointCreateParams( + url=url, + events=list(events), + description=description, + ).to_dict() + response = await self._client.transport.request( + "POST", + _PATH_WEBHOOK_ENDPOINTS, + json=body, + ) + return _coerce_webhook_endpoint(response.data) + + async def retrieve(self, webhook_id: str) -> WebhookEndpoint: + response = await self._client.transport.request( + "GET", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}", + ) + return _coerce_webhook_endpoint(response.data) + + get = retrieve + + async def list(self) -> WebhookEndpointList: + response = await self._client.transport.request( + "GET", + _PATH_WEBHOOK_ENDPOINTS, + ) + return WebhookEndpointList(**response.data) + + async def update( + self, + webhook_id: str, + *, + description: Optional[str] = None, + url: Optional[str] = None, + events: Optional[Sequence[str]] = None, + ) -> WebhookEndpoint: + body = WebhookEndpointUpdateParams( + description=description, + url=url, + events=list(events) if events is not None else None, + ).to_dict() + response = await self._client.transport.request( + "PUT", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}", + json=body, + ) + return _coerce_webhook_endpoint(response.data) + + async def delete(self, webhook_id: str) -> None: + await self._client.transport.request( + "DELETE", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}", + ) + + async def enable(self, webhook_id: str) -> WebhookEndpoint: + response = await self._client.transport.request( + "POST", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/enable", + ) + return _coerce_webhook_endpoint(response.data) + + async def disable(self, webhook_id: str) -> WebhookEndpoint: + response = await self._client.transport.request( + "POST", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/disable", + ) + return _coerce_webhook_endpoint(response.data) + + async def test(self, webhook_id: str) -> WebhookEvent: + response = await self._client.transport.request( + "POST", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/test", + ) + return _coerce_webhook_event(response.data) + + async def reset_secret(self, webhook_id: str) -> WebhookSecretReset: + response = await self._client.transport.request( + "POST", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/reset_secret", + ) + return _coerce_webhook_secret_reset(response.data) + + async def list_events( + self, + webhook_id: str, + *, + limit: Optional[int] = None, + page: Optional[str] = None, + ) -> AsyncCursorPage[WebhookEvent]: + params = WebhookEventListParams(limit=limit, page=page).to_dict() + response = await self._client.transport.request( + "GET", + f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}/events", + params=params, + ) + + async def fetch_next(cursor: str) -> AsyncCursorPage[WebhookEvent]: + return await self.list_events( + webhook_id, + limit=limit, + page=cursor, + ) + + return build_page( + payload=response.data, + item_factory=_coerce_webhook_event, + request_id=response.request_id, + page_cls=AsyncCursorPage, + fetch_next=fetch_next, + ) diff --git a/dashscope/agentstudio/types/__init__.py b/dashscope/agentstudio/types/__init__.py index fda94eb8..c7b414cd 100644 --- a/dashscope/agentstudio/types/__init__.py +++ b/dashscope/agentstudio/types/__init__.py @@ -70,6 +70,12 @@ SessionThreadStatusEvent, SpanModelRequestStartEvent, SpanModelRequestEndEvent, + WebhookDelivery, + WebhookEndpoint, + WebhookEndpointList, + WebhookEvent, + WebhookEventData, + WebhookSecretReset, ) from dashscope.agentstudio.types.params import ( # noqa: F401 AgentCreateParams, @@ -94,4 +100,7 @@ CredentialCreateParams, CredentialUpdateParams, CredentialListParams, + WebhookEndpointCreateParams, + WebhookEndpointUpdateParams, + WebhookEventListParams, ) diff --git a/dashscope/agentstudio/types/models.py b/dashscope/agentstudio/types/models.py index 3dd3dc93..96d4bf78 100644 --- a/dashscope/agentstudio/types/models.py +++ b/dashscope/agentstudio/types/models.py @@ -501,6 +501,97 @@ class DeleteResponse(BaseModel): _fields = ("id", "type", "request_id") +class WebhookEndpoint(BaseModel): + """Managed Agent webhook endpoint.""" + + _fields = ( + "id", + "description", + "url", + "events", + "status", + "disabled_reason", + "consecutive_fail", + "last_success_at", + "last_failure_at", + "signing_secret", + "created_at", + "updated_at", + "request_id", + ) + + +class WebhookEndpointList(BaseModel): + """Non-paginated list of webhook endpoints in the current workspace.""" + + _fields = ("data", "request_id") + + def __init__(self, **kwargs: Any) -> None: + data = kwargs.get("data") + if isinstance(data, list): + kwargs["data"] = [ + WebhookEndpoint(**dict(item)) + if isinstance(item, Mapping) + else item + for item in data + ] + super().__init__(**kwargs) + + +class WebhookSecretReset(BaseModel): + """Result returned after resetting a webhook signing secret.""" + + _fields = ("id", "signing_secret", "updated_at", "request_id") + + +class WebhookEventData(BaseModel): + """Resource data carried by a webhook event envelope.""" + + _fields = ( + "id", + "type", + "workspace_id", + "session_thread_id", + "vault_id", + "extensions", + ) + + +class WebhookDelivery(BaseModel): + """Delivery audit information attached to an endpoint event.""" + + _fields = ( + "webhook_id", + "status", + "attempt_count", + "delivery_at", + "finish_at", + "failure_reason", + ) + + +class WebhookEvent(BaseModel): + """Webhook event envelope returned by test and endpoint audit APIs.""" + + _fields = ( + "type", + "id", + "created_at", + "data", + "delivery", + "request_id", + ) + + def __init__(self, **kwargs: Any) -> None: + data = kwargs.get("data") + if isinstance(data, Mapping): + kwargs["data"] = WebhookEventData(**dict(data)) + delivery = kwargs.get("delivery") + if isinstance(delivery, Mapping): + kwargs["delivery"] = WebhookDelivery(**dict(delivery)) + super().__init__(**kwargs) + + # =========================================================================== # Section 4 – Unified Message class (replaces server_events.py) # =========================================================================== diff --git a/dashscope/agentstudio/types/params.py b/dashscope/agentstudio/types/params.py index 5767921a..1fc1270b 100644 --- a/dashscope/agentstudio/types/params.py +++ b/dashscope/agentstudio/types/params.py @@ -549,3 +549,26 @@ def __init__( include_archived, ).lower() super().__init__(**kwargs) + + +# =========================================================================== +# Webhook endpoints +# =========================================================================== + + +class WebhookEndpointCreateParams(BaseModel): + """Request body for ``POST /webhook_endpoints``.""" + + _fields = ("description", "url", "events") + + +class WebhookEndpointUpdateParams(BaseModel): + """Request body for ``PUT /webhook_endpoints/{id}``.""" + + _fields = ("description", "url", "events") + + +class WebhookEventListParams(BaseModel): + """Query params for endpoint-specific webhook event audit records.""" + + _fields = ("limit", "page") From 63faf7348aeefab92a5c9d2434caf8e88a24f479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E9=87=8C?= Date: Tue, 18 Aug 2026 17:53:55 +0800 Subject: [PATCH 2/4] fix: remove wildcard webhook subscription --- dashscope/agentstudio/constants.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/dashscope/agentstudio/constants.py b/dashscope/agentstudio/constants.py index 3d0699e5..b664a015 100644 --- a/dashscope/agentstudio/constants.py +++ b/dashscope/agentstudio/constants.py @@ -139,8 +139,6 @@ class WebhookDeliveryStatus(StrEnum): class WebhookEventType(StrEnum): """Event types accepted by webhook endpoint subscriptions.""" - # Subscribe to every supported event type. - ALL = "*" # A session was created. SESSION_CREATED = "session.created" # A session was updated. From 30dcd575f631d536aa4684dedd8540e37542397c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E9=87=8C?= Date: Thu, 20 Aug 2026 15:25:24 +0800 Subject: [PATCH 3/4] feat: update webhook delete response --- dashscope/agentstudio/constants.py | 2 +- dashscope/agentstudio/resources/webhook_endpoints.py | 12 +++++++----- dashscope/agentstudio/types/models.py | 4 ++-- dashscope/agentstudio/types/params.py | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/dashscope/agentstudio/constants.py b/dashscope/agentstudio/constants.py index b664a015..97c50b19 100644 --- a/dashscope/agentstudio/constants.py +++ b/dashscope/agentstudio/constants.py @@ -120,7 +120,7 @@ class WebhookDisabledReason(StrEnum): class WebhookDeliveryStatus(StrEnum): - """Webhook delivery audit status.""" + """Webhook delivery status.""" # The delivery is waiting to start. PENDING = "PENDING" diff --git a/dashscope/agentstudio/resources/webhook_endpoints.py b/dashscope/agentstudio/resources/webhook_endpoints.py index ea277190..fc1a4485 100644 --- a/dashscope/agentstudio/resources/webhook_endpoints.py +++ b/dashscope/agentstudio/resources/webhook_endpoints.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import Optional, Sequence +from typing import Any, Dict, Optional, Sequence from dashscope.agentstudio.pagination import ( AsyncCursorPage, @@ -94,11 +94,12 @@ def update( ) return _coerce_webhook_endpoint(response.data) - def delete(self, webhook_id: str) -> None: - self._client.transport.request( + def delete(self, webhook_id: str) -> Dict[str, Any]: + response = self._client.transport.request( "DELETE", f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}", ) + return response.data def enable(self, webhook_id: str) -> WebhookEndpoint: response = self._client.transport.request( @@ -214,11 +215,12 @@ async def update( ) return _coerce_webhook_endpoint(response.data) - async def delete(self, webhook_id: str) -> None: - await self._client.transport.request( + async def delete(self, webhook_id: str) -> Dict[str, Any]: + response = await self._client.transport.request( "DELETE", f"{_PATH_WEBHOOK_ENDPOINTS}/{webhook_id}", ) + return response.data async def enable(self, webhook_id: str) -> WebhookEndpoint: response = await self._client.transport.request( diff --git a/dashscope/agentstudio/types/models.py b/dashscope/agentstudio/types/models.py index 96d4bf78..a596b0c3 100644 --- a/dashscope/agentstudio/types/models.py +++ b/dashscope/agentstudio/types/models.py @@ -558,7 +558,7 @@ class WebhookEventData(BaseModel): class WebhookDelivery(BaseModel): - """Delivery audit information attached to an endpoint event.""" + """Delivery information attached to an endpoint event.""" _fields = ( "webhook_id", @@ -571,7 +571,7 @@ class WebhookDelivery(BaseModel): class WebhookEvent(BaseModel): - """Webhook event envelope returned by test and endpoint audit APIs.""" + """Webhook event envelope returned by test and endpoint event APIs.""" _fields = ( "type", diff --git a/dashscope/agentstudio/types/params.py b/dashscope/agentstudio/types/params.py index 1fc1270b..991bbff9 100644 --- a/dashscope/agentstudio/types/params.py +++ b/dashscope/agentstudio/types/params.py @@ -569,6 +569,6 @@ class WebhookEndpointUpdateParams(BaseModel): class WebhookEventListParams(BaseModel): - """Query params for endpoint-specific webhook event audit records.""" + """Query parameters for endpoint-specific webhook events.""" _fields = ("limit", "page") From 5c826c492f41ff2f80f54d0fa2130672216109d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=80=E9=87=8C?= Date: Wed, 2 Sep 2026 15:08:05 +0800 Subject: [PATCH 4/4] fix(agentstudio): resolve webhook model merge issue --- dashscope/agentstudio/resources/_helpers.py | 2 ++ dashscope/agentstudio/types/models.py | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/dashscope/agentstudio/resources/_helpers.py b/dashscope/agentstudio/resources/_helpers.py index cb808be5..4fd8a7aa 100644 --- a/dashscope/agentstudio/resources/_helpers.py +++ b/dashscope/agentstudio/resources/_helpers.py @@ -83,6 +83,8 @@ def _coerce_webhook_secret_reset( payload: Mapping[str, Any], ) -> WebhookSecretReset: return WebhookSecretReset(**dict(payload)) + + def _coerce_deployment(payload: Mapping[str, Any]) -> Deployment: return Deployment(**dict(payload)) diff --git a/dashscope/agentstudio/types/models.py b/dashscope/agentstudio/types/models.py index ee41a35d..29c8aec2 100644 --- a/dashscope/agentstudio/types/models.py +++ b/dashscope/agentstudio/types/models.py @@ -619,6 +619,19 @@ class WebhookEvent(BaseModel): "created_at", "data", "delivery", + "request_id", + ) + + def __init__(self, **kwargs: Any) -> None: + data = kwargs.get("data") + if isinstance(data, Mapping): + kwargs["data"] = WebhookEventData(**dict(data)) + delivery = kwargs.get("delivery") + if isinstance(delivery, Mapping): + kwargs["delivery"] = WebhookDelivery(**dict(delivery)) + super().__init__(**kwargs) + + class DeploymentAgentReference(BaseModel): """Agent version reference stored on a deployment run.""" @@ -727,12 +740,6 @@ class DeploymentRun(BaseModel): ) def __init__(self, **kwargs: Any) -> None: - data = kwargs.get("data") - if isinstance(data, Mapping): - kwargs["data"] = WebhookEventData(**dict(data)) - delivery = kwargs.get("delivery") - if isinstance(delivery, Mapping): - kwargs["delivery"] = WebhookDelivery(**dict(delivery)) agent = kwargs.get("agent") if isinstance(agent, Mapping): kwargs["agent"] = DeploymentAgentReference(**dict(agent))