Skip to content

Commit 6a379f1

Browse files
nick863howieleungCopilotl0lawrence
authored
Add thread message delete operation (#41625)
* Demonstrate the include parameter usage. (#41523) * Demonstrate the include parameter usage * Enable tests for reference text inclusion. * Add file search with streaming samples (#41551) * Small fix and use projects for getting connection ID (#41576) * Update readme (#41527) * Update readme * Apply suggestions from code review Co-authored-by: Copilot <[email protected]> * update * Takes Jarno recommendation --------- Co-authored-by: Copilot <[email protected]> * Howie/next lint (#41621) * Fix pylintrc to exclude agents generated code (#41612) * Fix pylintrc to exclude agents generated code * Update pylintrc Co-authored-by: Copilot <[email protected]> * Resolved * Update eng/pylintrc * Update pylintrc --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Libba Lawrence <[email protected]> * Fix lint --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Libba Lawrence <[email protected]> * Add thread message delete operation * Re generate code * Merge to upstream * Revert "Merge to upstream" This reverts commit 8b157e1. * Generate code from main branch --------- Co-authored-by: Howie Leung <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Libba Lawrence <[email protected]>
1 parent 304eea8 commit 6a379f1

File tree

12 files changed

+338
-10
lines changed

12 files changed

+338
-10
lines changed

sdk/ai/azure-ai-agents/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
### Features Added
99

10+
- Added delete operation for `ThreadMessages`.
1011
- Add `RunStepDetailsActivity`, describing MCP function parameters.
1112
- Add `RunStepDeltaCustomBingGroundingToolCall`, describing `BingCustomSearchTool` updates in streaming scenario.
1213

@@ -16,6 +17,8 @@
1617

1718
### Sample updates
1819

20+
- The file search samples were updated to demonstrate retrieving text associated with citations.
21+
- Added samples for file search citation with streaming.
1922
- Bing Grounding and Bing Custom Search samples were fixed to correctly present references.
2023

2124
## 1.2.0b2 (2025-08-12)

sdk/ai/azure-ai-agents/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "python",
44
"TagPrefix": "python/ai/azure-ai-agents",
5-
"Tag": "python/ai/azure-ai-agents_56f374c86c"
5+
"Tag": "python/ai/azure-ai-agents_3c8c500083"
66
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# --------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# Code generated by Microsoft (R) Python Code Generator.
5+
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
6+
# --------------------------------------------------------------------------
7+
import functools
8+
9+
10+
def api_version_validation(**kwargs):
11+
params_added_on = kwargs.pop("params_added_on", {})
12+
method_added_on = kwargs.pop("method_added_on", "")
13+
api_versions_list = kwargs.pop("api_versions_list", [])
14+
15+
def _index_with_default(value: str, default: int = -1) -> int:
16+
"""Get the index of value in lst, or return default if not found.
17+
18+
:param value: The value to search for in the api_versions_list.
19+
:type value: str
20+
:param default: The default value to return if the value is not found.
21+
:type default: int
22+
:return: The index of the value in the list, or the default value if not found.
23+
:rtype: int
24+
"""
25+
try:
26+
return api_versions_list.index(value)
27+
except ValueError:
28+
return default
29+
30+
def decorator(func):
31+
@functools.wraps(func)
32+
def wrapper(*args, **kwargs):
33+
try:
34+
# this assumes the client has an _api_version attribute
35+
client = args[0]
36+
client_api_version = client._config.api_version # pylint: disable=protected-access
37+
except AttributeError:
38+
return func(*args, **kwargs)
39+
40+
if _index_with_default(method_added_on) > _index_with_default(client_api_version):
41+
raise ValueError(
42+
f"'{func.__name__}' is not available in API version "
43+
f"{client_api_version}. Pass service API version {method_added_on} or newer to your client."
44+
)
45+
46+
unsupported = {
47+
parameter: api_version
48+
for api_version, parameters in params_added_on.items()
49+
for parameter in parameters
50+
if parameter in kwargs and _index_with_default(api_version) > _index_with_default(client_api_version)
51+
}
52+
if unsupported:
53+
raise ValueError(
54+
"".join(
55+
[
56+
f"'{param}' is not available in API version {client_api_version}. "
57+
f"Use service API version {version} or newer.\n"
58+
for param, version in unsupported.items()
59+
]
60+
)
61+
)
62+
return func(*args, **kwargs)
63+
64+
return wrapper
65+
66+
return decorator

sdk/ai/azure-ai-agents/azure/ai/agents/aio/operations/_operations.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from ..._utils.model_base import Model as _Model, SdkJSONEncoder, _deserialize, _failsafe_deserialize
3535
from ..._utils.serialization import Deserializer, Serializer
3636
from ..._utils.utils import ClientMixinABC, prepare_multipart_form_data
37+
from ..._validation import api_version_validation
3738
from ...operations._operations import (
3839
build_agents_create_agent_request,
3940
build_agents_create_thread_and_run_request,
@@ -47,6 +48,7 @@
4748
build_files_list_request,
4849
build_files_upload_file_request,
4950
build_messages_create_request,
51+
build_messages_delete_request,
5052
build_messages_get_request,
5153
build_messages_list_request,
5254
build_messages_update_request,
@@ -1151,6 +1153,77 @@ async def update(
11511153

11521154
return deserialized # type: ignore
11531155

1156+
@distributed_trace_async
1157+
@api_version_validation(
1158+
method_added_on="v1",
1159+
params_added_on={"v1": ["api_version", "thread_id", "message_id", "accept"]},
1160+
api_versions_list=["v1", "2025-05-15-preview"],
1161+
)
1162+
async def _delete(self, thread_id: str, message_id: str, **kwargs: Any) -> _models._models.MessageDeletionStatus:
1163+
"""Deletes an existing message on an existing thread.
1164+
1165+
:param thread_id: Identifier of the thread. Required.
1166+
:type thread_id: str
1167+
:param message_id: Identifier of the message. Required.
1168+
:type message_id: str
1169+
:return: MessageDeletionStatus. The MessageDeletionStatus is compatible with MutableMapping
1170+
:rtype: ~azure.ai.agents.models._models.MessageDeletionStatus
1171+
:raises ~azure.core.exceptions.HttpResponseError:
1172+
"""
1173+
error_map: MutableMapping = {
1174+
401: ClientAuthenticationError,
1175+
404: ResourceNotFoundError,
1176+
409: ResourceExistsError,
1177+
304: ResourceNotModifiedError,
1178+
}
1179+
error_map.update(kwargs.pop("error_map", {}) or {})
1180+
1181+
_headers = kwargs.pop("headers", {}) or {}
1182+
_params = kwargs.pop("params", {}) or {}
1183+
1184+
cls: ClsType[_models._models.MessageDeletionStatus] = kwargs.pop("cls", None)
1185+
1186+
_request = build_messages_delete_request(
1187+
thread_id=thread_id,
1188+
message_id=message_id,
1189+
api_version=self._config.api_version,
1190+
headers=_headers,
1191+
params=_params,
1192+
)
1193+
path_format_arguments = {
1194+
"endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True),
1195+
}
1196+
_request.url = self._client.format_url(_request.url, **path_format_arguments)
1197+
1198+
_stream = kwargs.pop("stream", False)
1199+
pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access
1200+
_request, stream=_stream, **kwargs
1201+
)
1202+
1203+
response = pipeline_response.http_response
1204+
1205+
if response.status_code not in [200]:
1206+
if _stream:
1207+
try:
1208+
await response.read() # Load the body in memory and close the socket
1209+
except (StreamConsumedError, StreamClosedError):
1210+
pass
1211+
map_error(status_code=response.status_code, response=response, error_map=error_map)
1212+
error = _failsafe_deserialize(_models.AgentV1Error, response)
1213+
raise HttpResponseError(response=response, model=error)
1214+
1215+
if _stream:
1216+
deserialized = response.iter_bytes()
1217+
else:
1218+
deserialized = _deserialize(
1219+
_models._models.MessageDeletionStatus, response.json() # pylint: disable=protected-access
1220+
)
1221+
1222+
if cls:
1223+
return cls(pipeline_response, deserialized, {}) # type: ignore
1224+
1225+
return deserialized # type: ignore
1226+
11541227

11551228
class RunsOperations:
11561229
"""

sdk/ai/azure-ai-agents/azure/ai/agents/aio/operations/_patch.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,6 +2335,18 @@ async def get_last_message_text_by_role(
23352335
return text_contents[-1]
23362336
return None
23372337

2338+
@distributed_trace_async
2339+
async def delete(self, thread_id: str, message_id: str, **kwargs: Any) -> None:
2340+
"""Deletes an existing message on an existing thread.
2341+
2342+
:param thread_id: Identifier of the thread. Required.
2343+
:type thread_id: str
2344+
:param message_id: Identifier of the message. Required.
2345+
:type message_id: str
2346+
:raises ~azure.core.exceptions.HttpResponseError:
2347+
"""
2348+
await super()._delete(thread_id=thread_id, message_id=message_id, **kwargs)
2349+
23382350

23392351
__all__: List[str] = [
23402352
"MessagesOperations",

sdk/ai/azure-ai-agents/azure/ai/agents/models/_models.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2305,6 +2305,46 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
23052305
super().__init__(*args, **kwargs)
23062306

23072307

2308+
class MessageDeletionStatus(_Model):
2309+
"""The status of a thread message deletion operation.
2310+
2311+
:ivar id: The ID of the resource specified for deletion. Required.
2312+
:vartype id: str
2313+
:ivar deleted: A value indicating whether deletion was successful. Required.
2314+
:vartype deleted: bool
2315+
:ivar object: The object type, which is always 'thread.message.deleted'. Required. Default
2316+
value is "thread.message.deleted".
2317+
:vartype object: str
2318+
"""
2319+
2320+
id: str = rest_field(visibility=["read", "create", "update", "delete", "query"])
2321+
"""The ID of the resource specified for deletion. Required."""
2322+
deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"])
2323+
"""A value indicating whether deletion was successful. Required."""
2324+
object: Literal["thread.message.deleted"] = rest_field(visibility=["read", "create", "update", "delete", "query"])
2325+
"""The object type, which is always 'thread.message.deleted'. Required. Default value is
2326+
\"thread.message.deleted\"."""
2327+
2328+
@overload
2329+
def __init__(
2330+
self,
2331+
*,
2332+
id: str, # pylint: disable=redefined-builtin
2333+
deleted: bool,
2334+
) -> None: ...
2335+
2336+
@overload
2337+
def __init__(self, mapping: Mapping[str, Any]) -> None:
2338+
"""
2339+
:param mapping: raw JSON to initialize the model.
2340+
:type mapping: Mapping[str, Any]
2341+
"""
2342+
2343+
def __init__(self, *args: Any, **kwargs: Any) -> None:
2344+
super().__init__(*args, **kwargs)
2345+
self.object: Literal["thread.message.deleted"] = "thread.message.deleted"
2346+
2347+
23082348
class MessageDelta(_Model):
23092349
"""Represents the typed 'delta' payload within a streaming message delta chunk.
23102350

sdk/ai/azure-ai-agents/azure/ai/agents/operations/_operations.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from .._utils.model_base import Model as _Model, SdkJSONEncoder, _deserialize, _failsafe_deserialize
3535
from .._utils.serialization import Deserializer, Serializer
3636
from .._utils.utils import ClientMixinABC, prepare_multipart_form_data
37+
from .._validation import api_version_validation
3738

3839
if TYPE_CHECKING:
3940
from .. import _types
@@ -300,6 +301,31 @@ def build_messages_update_request(thread_id: str, message_id: str, **kwargs: Any
300301
return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs)
301302

302303

304+
def build_messages_delete_request(thread_id: str, message_id: str, **kwargs: Any) -> HttpRequest:
305+
_headers = case_insensitive_dict(kwargs.pop("headers", {}) or {})
306+
_params = case_insensitive_dict(kwargs.pop("params", {}) or {})
307+
308+
api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2025-05-15-preview"))
309+
accept = _headers.pop("Accept", "application/json")
310+
311+
# Construct URL
312+
_url = "/threads/{threadId}/messages/{messageId}"
313+
path_format_arguments = {
314+
"threadId": _SERIALIZER.url("thread_id", thread_id, "str"),
315+
"messageId": _SERIALIZER.url("message_id", message_id, "str"),
316+
}
317+
318+
_url: str = _url.format(**path_format_arguments) # type: ignore
319+
320+
# Construct parameters
321+
_params["api-version"] = _SERIALIZER.query("api_version", api_version, "str")
322+
323+
# Construct headers
324+
_headers["Accept"] = _SERIALIZER.header("accept", accept, "str")
325+
326+
return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs)
327+
328+
303329
def build_runs_create_request(
304330
thread_id: str, *, include: Optional[List[Union[str, _models.RunAdditionalFieldList]]] = None, **kwargs: Any
305331
) -> HttpRequest:
@@ -2269,6 +2295,77 @@ def update(
22692295

22702296
return deserialized # type: ignore
22712297

2298+
@distributed_trace
2299+
@api_version_validation(
2300+
method_added_on="v1",
2301+
params_added_on={"v1": ["api_version", "thread_id", "message_id", "accept"]},
2302+
api_versions_list=["v1", "2025-05-15-preview"],
2303+
)
2304+
def _delete(self, thread_id: str, message_id: str, **kwargs: Any) -> _models._models.MessageDeletionStatus:
2305+
"""Deletes an existing message on an existing thread.
2306+
2307+
:param thread_id: Identifier of the thread. Required.
2308+
:type thread_id: str
2309+
:param message_id: Identifier of the message. Required.
2310+
:type message_id: str
2311+
:return: MessageDeletionStatus. The MessageDeletionStatus is compatible with MutableMapping
2312+
:rtype: ~azure.ai.agents.models._models.MessageDeletionStatus
2313+
:raises ~azure.core.exceptions.HttpResponseError:
2314+
"""
2315+
error_map: MutableMapping = {
2316+
401: ClientAuthenticationError,
2317+
404: ResourceNotFoundError,
2318+
409: ResourceExistsError,
2319+
304: ResourceNotModifiedError,
2320+
}
2321+
error_map.update(kwargs.pop("error_map", {}) or {})
2322+
2323+
_headers = kwargs.pop("headers", {}) or {}
2324+
_params = kwargs.pop("params", {}) or {}
2325+
2326+
cls: ClsType[_models._models.MessageDeletionStatus] = kwargs.pop("cls", None)
2327+
2328+
_request = build_messages_delete_request(
2329+
thread_id=thread_id,
2330+
message_id=message_id,
2331+
api_version=self._config.api_version,
2332+
headers=_headers,
2333+
params=_params,
2334+
)
2335+
path_format_arguments = {
2336+
"endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True),
2337+
}
2338+
_request.url = self._client.format_url(_request.url, **path_format_arguments)
2339+
2340+
_stream = kwargs.pop("stream", False)
2341+
pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access
2342+
_request, stream=_stream, **kwargs
2343+
)
2344+
2345+
response = pipeline_response.http_response
2346+
2347+
if response.status_code not in [200]:
2348+
if _stream:
2349+
try:
2350+
response.read() # Load the body in memory and close the socket
2351+
except (StreamConsumedError, StreamClosedError):
2352+
pass
2353+
map_error(status_code=response.status_code, response=response, error_map=error_map)
2354+
error = _failsafe_deserialize(_models.AgentV1Error, response)
2355+
raise HttpResponseError(response=response, model=error)
2356+
2357+
if _stream:
2358+
deserialized = response.iter_bytes()
2359+
else:
2360+
deserialized = _deserialize(
2361+
_models._models.MessageDeletionStatus, response.json() # pylint: disable=protected-access
2362+
)
2363+
2364+
if cls:
2365+
return cls(pipeline_response, deserialized, {}) # type: ignore
2366+
2367+
return deserialized # type: ignore
2368+
22722369

22732370
class RunsOperations:
22742371
"""

sdk/ai/azure-ai-agents/azure/ai/agents/operations/_patch.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2334,6 +2334,18 @@ def get_last_message_text_by_role(
23342334
return text_contents[-1]
23352335
return None
23362336

2337+
@distributed_trace
2338+
def delete(self, thread_id: str, message_id: str, **kwargs: Any) -> None:
2339+
"""Deletes an existing message on an existing thread.
2340+
2341+
:param thread_id: Identifier of the thread. Required.
2342+
:type thread_id: str
2343+
:param message_id: Identifier of the message. Required.
2344+
:type message_id: str
2345+
:raises ~azure.core.exceptions.HttpResponseError:
2346+
"""
2347+
super()._delete(thread_id=thread_id, message_id=message_id, **kwargs)
2348+
23372349

23382350
__all__: List[str] = [
23392351
"ThreadsOperations",

sdk/ai/azure-ai-agents/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,4 @@
7777
"typing-extensions>=4.6.0",
7878
],
7979
python_requires=">=3.9",
80-
)
80+
)

0 commit comments

Comments
 (0)