managed-deepagents 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ .DS_Store
2
+ .env
3
+ .env.*
4
+ *.crt
5
+ *.key
6
+ *.pem
7
+ credentials.json
8
+ token.json
9
+
10
+ node_modules/
11
+ dist/
12
+ coverage/
13
+
14
+ __pycache__/
15
+ *.py[cod]
16
+ .mypy_cache/
17
+ .pytest_cache/
18
+ .ruff_cache/
19
+ .venv/
20
+ build/
21
+ *.egg-info/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LangChain, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: managed-deepagents
3
+ Version: 0.1.1
4
+ Summary: Python SDK for LangSmith Managed Deep Agents.
5
+ Project-URL: Changelog, https://github.com/langchain-ai/managed-deepagents-sdk/blob/main/CHANGELOG.md
6
+ Project-URL: Issues, https://github.com/langchain-ai/managed-deepagents-sdk/issues
7
+ Project-URL: Repository, https://github.com/langchain-ai/managed-deepagents-sdk
8
+ Author: LangChain
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,ai,langchain,langsmith,managed-deep-agents,sdk
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: httpx<1.0,>=0.28.1
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy<2.0,>=1.11; extra == 'dev'
27
+ Requires-Dist: pytest<10.0,>=8.4; extra == 'dev'
28
+ Requires-Dist: ruff<1.0,>=0.12; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # managed-deepagents
32
+
33
+ Python SDK for the LangSmith Managed Deep Agents API.
34
+
35
+ Managed Deep Agents is a hosted runtime for creating, running, and operating
36
+ Deep Agents through LangSmith. This package is currently public beta software.
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ pip install managed-deepagents
42
+ ```
43
+
44
+ Requirements:
45
+
46
+ - Python 3.10 or newer
47
+ - A LangSmith API key with access to Managed Deep Agents
48
+
49
+ ## Configuration
50
+
51
+ The client reads `LANGSMITH_API_KEY` by default.
52
+
53
+ ```bash
54
+ export LANGSMITH_API_KEY="..."
55
+ ```
56
+
57
+ The default API URL is `https://api.smith.langchain.com/v1/deepagents`.
58
+ You can override it with `LANGSMITH_ENDPOINT` or the `api_url` client option.
59
+
60
+ ## Quickstart
61
+
62
+ ```python
63
+ from managed_deepagents import Client
64
+
65
+ with Client() as client:
66
+ agent = client.agents.create(
67
+ name="research-assistant",
68
+ model="anthropic:claude-sonnet-4-6",
69
+ instructions="You are a careful research assistant.",
70
+ )
71
+
72
+ thread = client.threads.create(agent_id=agent["id"])
73
+
74
+ for event in client.threads.stream(
75
+ thread["id"],
76
+ agent_id=agent["id"],
77
+ messages=[{"role": "user", "content": "Summarize the latest notes."}],
78
+ stream_mode=["values", "updates", "messages-tuple"],
79
+ ):
80
+ print(event.event, event.data)
81
+ ```
82
+
83
+ ## Async Usage
84
+
85
+ ```python
86
+ from managed_deepagents import AsyncClient
87
+
88
+ async with AsyncClient() as client:
89
+ agent = await client.agents.create(
90
+ name="research-assistant",
91
+ model="anthropic:claude-sonnet-4-6",
92
+ instructions="You are a careful research assistant.",
93
+ )
94
+ ```
95
+
96
+ ## Agent Files
97
+
98
+ Top-level `files` entries may be passed as raw strings; the SDK normalizes them
99
+ to file entries before sending the request. Use either `instructions` or
100
+ `files["AGENTS.md"]`, not both, because the API maps the typed prompt field to
101
+ `AGENTS.md`.
102
+
103
+ ```python
104
+ agent = client.agents.create(
105
+ name="research-assistant",
106
+ files={
107
+ "AGENTS.md": "You are a careful research assistant.",
108
+ "skills/research/SKILL.md": "# Research\n\nGather context before answering.",
109
+ },
110
+ include_files=True,
111
+ )
112
+ ```
113
+
114
+ ## API Surface
115
+
116
+ Resources exposed by the client:
117
+
118
+ - `client.agents`: list, create, get, update, delete, clone, health
119
+ - `client.threads`: create, search, count, get, update, delete, create run,
120
+ invoke, stream, bulk update, resolve interrupt
121
+ - `client.mcp_servers`: create, list, get, update, delete, register OAuth
122
+ provider
123
+ - `client.auth_sessions`: create and get
124
+
125
+ ## Errors
126
+
127
+ ```python
128
+ from managed_deepagents import ManagedDeepAgentsAPIError
129
+
130
+ try:
131
+ client.agents.get("missing-agent")
132
+ except ManagedDeepAgentsAPIError as error:
133
+ print(error.status_code, error.code, error.detail)
134
+ ```
135
+
136
+ ## Links
137
+
138
+ - Repository: https://github.com/langchain-ai/managed-deepagents-sdk
139
+ - Issues: https://github.com/langchain-ai/managed-deepagents-sdk/issues
140
+ - Changelog: https://github.com/langchain-ai/managed-deepagents-sdk/blob/main/CHANGELOG.md
@@ -0,0 +1,110 @@
1
+ # managed-deepagents
2
+
3
+ Python SDK for the LangSmith Managed Deep Agents API.
4
+
5
+ Managed Deep Agents is a hosted runtime for creating, running, and operating
6
+ Deep Agents through LangSmith. This package is currently public beta software.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ pip install managed-deepagents
12
+ ```
13
+
14
+ Requirements:
15
+
16
+ - Python 3.10 or newer
17
+ - A LangSmith API key with access to Managed Deep Agents
18
+
19
+ ## Configuration
20
+
21
+ The client reads `LANGSMITH_API_KEY` by default.
22
+
23
+ ```bash
24
+ export LANGSMITH_API_KEY="..."
25
+ ```
26
+
27
+ The default API URL is `https://api.smith.langchain.com/v1/deepagents`.
28
+ You can override it with `LANGSMITH_ENDPOINT` or the `api_url` client option.
29
+
30
+ ## Quickstart
31
+
32
+ ```python
33
+ from managed_deepagents import Client
34
+
35
+ with Client() as client:
36
+ agent = client.agents.create(
37
+ name="research-assistant",
38
+ model="anthropic:claude-sonnet-4-6",
39
+ instructions="You are a careful research assistant.",
40
+ )
41
+
42
+ thread = client.threads.create(agent_id=agent["id"])
43
+
44
+ for event in client.threads.stream(
45
+ thread["id"],
46
+ agent_id=agent["id"],
47
+ messages=[{"role": "user", "content": "Summarize the latest notes."}],
48
+ stream_mode=["values", "updates", "messages-tuple"],
49
+ ):
50
+ print(event.event, event.data)
51
+ ```
52
+
53
+ ## Async Usage
54
+
55
+ ```python
56
+ from managed_deepagents import AsyncClient
57
+
58
+ async with AsyncClient() as client:
59
+ agent = await client.agents.create(
60
+ name="research-assistant",
61
+ model="anthropic:claude-sonnet-4-6",
62
+ instructions="You are a careful research assistant.",
63
+ )
64
+ ```
65
+
66
+ ## Agent Files
67
+
68
+ Top-level `files` entries may be passed as raw strings; the SDK normalizes them
69
+ to file entries before sending the request. Use either `instructions` or
70
+ `files["AGENTS.md"]`, not both, because the API maps the typed prompt field to
71
+ `AGENTS.md`.
72
+
73
+ ```python
74
+ agent = client.agents.create(
75
+ name="research-assistant",
76
+ files={
77
+ "AGENTS.md": "You are a careful research assistant.",
78
+ "skills/research/SKILL.md": "# Research\n\nGather context before answering.",
79
+ },
80
+ include_files=True,
81
+ )
82
+ ```
83
+
84
+ ## API Surface
85
+
86
+ Resources exposed by the client:
87
+
88
+ - `client.agents`: list, create, get, update, delete, clone, health
89
+ - `client.threads`: create, search, count, get, update, delete, create run,
90
+ invoke, stream, bulk update, resolve interrupt
91
+ - `client.mcp_servers`: create, list, get, update, delete, register OAuth
92
+ provider
93
+ - `client.auth_sessions`: create and get
94
+
95
+ ## Errors
96
+
97
+ ```python
98
+ from managed_deepagents import ManagedDeepAgentsAPIError
99
+
100
+ try:
101
+ client.agents.get("missing-agent")
102
+ except ManagedDeepAgentsAPIError as error:
103
+ print(error.status_code, error.code, error.detail)
104
+ ```
105
+
106
+ ## Links
107
+
108
+ - Repository: https://github.com/langchain-ai/managed-deepagents-sdk
109
+ - Issues: https://github.com/langchain-ai/managed-deepagents-sdk/issues
110
+ - Changelog: https://github.com/langchain-ai/managed-deepagents-sdk/blob/main/CHANGELOG.md
@@ -0,0 +1,25 @@
1
+ """Python SDK for LangSmith Managed Deep Agents."""
2
+
3
+ from managed_deepagents.client import (
4
+ AsyncClient,
5
+ AsyncManagedDeepAgentsClient,
6
+ Client,
7
+ ManagedDeepAgentsClient,
8
+ )
9
+ from managed_deepagents.errors import (
10
+ ManagedDeepAgentsAPIError,
11
+ ManagedDeepAgentsConfigError,
12
+ ManagedDeepAgentsError,
13
+ )
14
+ from managed_deepagents.streaming import SSEEvent
15
+
16
+ __all__ = [
17
+ "AsyncClient",
18
+ "AsyncManagedDeepAgentsClient",
19
+ "Client",
20
+ "ManagedDeepAgentsAPIError",
21
+ "ManagedDeepAgentsClient",
22
+ "ManagedDeepAgentsConfigError",
23
+ "ManagedDeepAgentsError",
24
+ "SSEEvent",
25
+ ]
@@ -0,0 +1,90 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from collections.abc import Mapping
5
+ from typing import Any
6
+
7
+ DEFAULT_API_URL = "https://api.smith.langchain.com"
8
+ MANAGED_DEEPAGENTS_PATH = "/v1/deepagents"
9
+ FLEET_PATH = "/v1/fleet"
10
+ MANAGED_AGENT_BASE_PATHS = (
11
+ MANAGED_DEEPAGENTS_PATH,
12
+ FLEET_PATH,
13
+ )
14
+
15
+
16
+ def get_default_api_key() -> str | None:
17
+ return os.getenv("LANGSMITH_API_KEY")
18
+
19
+
20
+ def get_default_api_url() -> str:
21
+ return os.getenv("LANGSMITH_ENDPOINT") or DEFAULT_API_URL
22
+
23
+
24
+ def normalize_api_url(api_url: str) -> str:
25
+ base_url = api_url.rstrip("/")
26
+ if base_url.endswith(MANAGED_AGENT_BASE_PATHS):
27
+ return base_url
28
+ if base_url.endswith("/v1"):
29
+ return f"{base_url}/deepagents"
30
+ return f"{base_url}{MANAGED_DEEPAGENTS_PATH}"
31
+
32
+
33
+ def clean_mapping(values: Mapping[str, Any]) -> dict[str, Any]:
34
+ return {key: value for key, value in values.items() if value is not None}
35
+
36
+
37
+ def merge_body_fields(
38
+ body: Mapping[str, Any] | None,
39
+ fields: Mapping[str, Any],
40
+ ) -> dict[str, Any]:
41
+ payload = dict(body or {})
42
+ payload.update(clean_mapping(fields))
43
+ return payload
44
+
45
+
46
+ def prepare_agent_payload(payload: Mapping[str, Any]) -> dict[str, Any]:
47
+ next_payload = dict(payload)
48
+ files = next_payload.get("files")
49
+ if isinstance(files, Mapping):
50
+ next_payload["files"] = {
51
+ path: {"content": value} if isinstance(value, str) else value
52
+ for path, value in files.items()
53
+ }
54
+ return next_payload
55
+
56
+
57
+ def build_stream_body(
58
+ *,
59
+ agent_id: str,
60
+ messages: list[Mapping[str, Any]],
61
+ stream_mode: list[str] | None = None,
62
+ stream_subgraphs: bool | None = None,
63
+ user_timezone: str | None = None,
64
+ extra: Mapping[str, Any] | None = None,
65
+ ) -> dict[str, Any]:
66
+ body = dict(extra or {})
67
+ body.update(
68
+ clean_mapping(
69
+ {
70
+ "agent_id": agent_id,
71
+ "messages": messages,
72
+ "stream_mode": stream_mode,
73
+ "stream_subgraphs": stream_subgraphs,
74
+ "user_timezone": user_timezone,
75
+ }
76
+ )
77
+ )
78
+ return body
79
+
80
+
81
+ def build_invoke_body(
82
+ *,
83
+ agent_id: str,
84
+ messages: list[Mapping[str, Any]],
85
+ extra: Mapping[str, Any] | None = None,
86
+ ) -> dict[str, Any]:
87
+ body = dict(extra or {})
88
+ body["assistant_id"] = agent_id
89
+ body["input"] = {"messages": messages}
90
+ return body
@@ -0,0 +1,236 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import AsyncIterable, Iterable, Mapping
4
+ from typing import Any
5
+
6
+ import httpx
7
+
8
+ from managed_deepagents._utils import (
9
+ get_default_api_key,
10
+ get_default_api_url,
11
+ normalize_api_url,
12
+ )
13
+ from managed_deepagents.errors import ManagedDeepAgentsAPIError
14
+ from managed_deepagents.resources import (
15
+ AgentsResource,
16
+ AsyncAgentsResource,
17
+ AsyncAuthSessionsResource,
18
+ AsyncMcpServersResource,
19
+ AsyncThreadsResource,
20
+ AuthSessionsResource,
21
+ McpServersResource,
22
+ ThreadsResource,
23
+ )
24
+ from managed_deepagents.streaming import SSEEvent, aiter_sse_events, iter_sse_events
25
+
26
+
27
+ class Client:
28
+ def __init__(
29
+ self,
30
+ *,
31
+ api_url: str | None = None,
32
+ api_key: str | None = None,
33
+ workspace_id: str | None = None,
34
+ timeout: float | httpx.Timeout = 30.0,
35
+ headers: Mapping[str, str] | None = None,
36
+ http_client: httpx.Client | None = None,
37
+ ) -> None:
38
+ self.api_url = normalize_api_url(api_url or get_default_api_url())
39
+ self.api_key = api_key if api_key is not None else get_default_api_key()
40
+ self.workspace_id = workspace_id
41
+ self._headers = dict(headers or {})
42
+ self._owns_client = http_client is None
43
+ self._client = http_client or httpx.Client(timeout=timeout)
44
+
45
+ self.agents = AgentsResource(self)
46
+ self.threads = ThreadsResource(self)
47
+ self.mcp_servers = McpServersResource(self)
48
+ self.auth_sessions = AuthSessionsResource(self)
49
+
50
+ def close(self) -> None:
51
+ if self._owns_client:
52
+ self._client.close()
53
+
54
+ def __enter__(self) -> Client:
55
+ return self
56
+
57
+ def __exit__(self, *_exc: object) -> None:
58
+ self.close()
59
+
60
+ def request(
61
+ self,
62
+ method: str,
63
+ path: str,
64
+ *,
65
+ json: Mapping[str, Any] | None = None,
66
+ params: Mapping[str, Any] | None = None,
67
+ headers: Mapping[str, str] | None = None,
68
+ ) -> Any:
69
+ response = self._client.request(
70
+ method,
71
+ self._url(path),
72
+ json=json,
73
+ params=params,
74
+ headers=self._request_headers(headers),
75
+ )
76
+ return _decode_response(response)
77
+
78
+ def stream(
79
+ self,
80
+ path: str,
81
+ *,
82
+ json: Mapping[str, Any],
83
+ headers: Mapping[str, str] | None = None,
84
+ ) -> Iterable[SSEEvent]:
85
+ with self._client.stream(
86
+ "POST",
87
+ self._url(path),
88
+ json=json,
89
+ headers=self._request_headers(
90
+ {"Accept": "text/event-stream", **dict(headers or {})}
91
+ ),
92
+ ) as response:
93
+ if response.status_code >= 400:
94
+ response.read()
95
+ _raise_for_status(response)
96
+ yield from iter_sse_events(response.iter_bytes())
97
+
98
+ def _url(self, path: str) -> str:
99
+ return f"{self.api_url}/{path.lstrip('/')}"
100
+
101
+ def _request_headers(
102
+ self,
103
+ headers: Mapping[str, str] | None = None,
104
+ ) -> dict[str, str]:
105
+ request_headers = {"Accept": "application/json", **self._headers}
106
+ if self.api_key:
107
+ request_headers["X-Api-Key"] = self.api_key
108
+ if self.workspace_id:
109
+ request_headers["X-Tenant-Id"] = self.workspace_id
110
+ request_headers.update(headers or {})
111
+ return request_headers
112
+
113
+
114
+ class AsyncClient:
115
+ def __init__(
116
+ self,
117
+ *,
118
+ api_url: str | None = None,
119
+ api_key: str | None = None,
120
+ workspace_id: str | None = None,
121
+ timeout: float | httpx.Timeout = 30.0,
122
+ headers: Mapping[str, str] | None = None,
123
+ http_client: httpx.AsyncClient | None = None,
124
+ ) -> None:
125
+ self.api_url = normalize_api_url(api_url or get_default_api_url())
126
+ self.api_key = api_key if api_key is not None else get_default_api_key()
127
+ self.workspace_id = workspace_id
128
+ self._headers = dict(headers or {})
129
+ self._owns_client = http_client is None
130
+ self._client = http_client or httpx.AsyncClient(timeout=timeout)
131
+
132
+ self.agents = AsyncAgentsResource(self)
133
+ self.threads = AsyncThreadsResource(self)
134
+ self.mcp_servers = AsyncMcpServersResource(self)
135
+ self.auth_sessions = AsyncAuthSessionsResource(self)
136
+
137
+ async def close(self) -> None:
138
+ if self._owns_client:
139
+ await self._client.aclose()
140
+
141
+ async def __aenter__(self) -> AsyncClient:
142
+ return self
143
+
144
+ async def __aexit__(self, *_exc: object) -> None:
145
+ await self.close()
146
+
147
+ async def request(
148
+ self,
149
+ method: str,
150
+ path: str,
151
+ *,
152
+ json: Mapping[str, Any] | None = None,
153
+ params: Mapping[str, Any] | None = None,
154
+ headers: Mapping[str, str] | None = None,
155
+ ) -> Any:
156
+ response = await self._client.request(
157
+ method,
158
+ self._url(path),
159
+ json=json,
160
+ params=params,
161
+ headers=self._request_headers(headers),
162
+ )
163
+ return _decode_response(response)
164
+
165
+ async def stream(
166
+ self,
167
+ path: str,
168
+ *,
169
+ json: Mapping[str, Any],
170
+ headers: Mapping[str, str] | None = None,
171
+ ) -> AsyncIterable[SSEEvent]:
172
+ async with self._client.stream(
173
+ "POST",
174
+ self._url(path),
175
+ json=json,
176
+ headers=self._request_headers(
177
+ {"Accept": "text/event-stream", **dict(headers or {})}
178
+ ),
179
+ ) as response:
180
+ if response.status_code >= 400:
181
+ await response.aread()
182
+ _raise_for_status(response)
183
+ async for event in aiter_sse_events(response.aiter_bytes()):
184
+ yield event
185
+
186
+ def _url(self, path: str) -> str:
187
+ return f"{self.api_url}/{path.lstrip('/')}"
188
+
189
+ def _request_headers(
190
+ self,
191
+ headers: Mapping[str, str] | None = None,
192
+ ) -> dict[str, str]:
193
+ request_headers = {"Accept": "application/json", **self._headers}
194
+ if self.api_key:
195
+ request_headers["X-Api-Key"] = self.api_key
196
+ if self.workspace_id:
197
+ request_headers["X-Tenant-Id"] = self.workspace_id
198
+ request_headers.update(headers or {})
199
+ return request_headers
200
+
201
+
202
+ def _decode_response(response: httpx.Response) -> Any:
203
+ _raise_for_status(response)
204
+ if response.status_code == 204 or not response.content:
205
+ return None
206
+ content_type = response.headers.get("content-type", "")
207
+ if "application/json" not in content_type:
208
+ return response.text
209
+ return response.json()
210
+
211
+
212
+ def _raise_for_status(response: httpx.Response) -> None:
213
+ if response.status_code < 400:
214
+ return
215
+ body = _response_body(response)
216
+ detail = body.get("detail") if isinstance(body, dict) else None
217
+ code = body.get("code") if isinstance(body, dict) else None
218
+ message = detail or response.reason_phrase or "Managed Deep Agents API error"
219
+ raise ManagedDeepAgentsAPIError(
220
+ message,
221
+ status_code=response.status_code,
222
+ code=code,
223
+ detail=detail,
224
+ body=body,
225
+ )
226
+
227
+
228
+ def _response_body(response: httpx.Response) -> Any:
229
+ try:
230
+ return response.json()
231
+ except ValueError:
232
+ return response.text
233
+
234
+
235
+ ManagedDeepAgentsClient = Client
236
+ AsyncManagedDeepAgentsClient = AsyncClient
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+
6
+ class ManagedDeepAgentsError(Exception):
7
+ """Base exception raised by the Managed Deep Agents SDK."""
8
+
9
+
10
+ class ManagedDeepAgentsConfigError(ManagedDeepAgentsError):
11
+ """Raised when client configuration is invalid."""
12
+
13
+
14
+ class ManagedDeepAgentsAPIError(ManagedDeepAgentsError):
15
+ """Raised when the API returns a non-2xx response."""
16
+
17
+ def __init__(
18
+ self,
19
+ message: str,
20
+ *,
21
+ status_code: int,
22
+ code: str | None = None,
23
+ detail: str | None = None,
24
+ body: Any | None = None,
25
+ ) -> None:
26
+ super().__init__(message)
27
+ self.status_code = status_code
28
+ self.code = code
29
+ self.detail = detail
30
+ self.body = body