acontext 0.0.1.dev2__tar.gz → 0.0.1.dev4__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.
Files changed (32) hide show
  1. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/PKG-INFO +3 -2
  2. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/README.md +1 -1
  3. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/pyproject.toml +8 -3
  4. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/src/acontext/__init__.py +19 -1
  5. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/src/acontext/_constants.py +0 -1
  6. acontext-0.0.1.dev4/src/acontext/_utils.py +42 -0
  7. acontext-0.0.1.dev4/src/acontext/async_client.py +206 -0
  8. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/src/acontext/client.py +63 -35
  9. acontext-0.0.1.dev4/src/acontext/client_types.py +36 -0
  10. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/src/acontext/errors.py +2 -2
  11. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/src/acontext/messages.py +2 -10
  12. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/src/acontext/resources/__init__.py +9 -0
  13. acontext-0.0.1.dev4/src/acontext/resources/async_blocks.py +163 -0
  14. acontext-0.0.1.dev4/src/acontext/resources/async_disks.py +195 -0
  15. acontext-0.0.1.dev4/src/acontext/resources/async_sessions.py +272 -0
  16. acontext-0.0.1.dev4/src/acontext/resources/async_spaces.py +90 -0
  17. acontext-0.0.1.dev4/src/acontext/resources/blocks.py +162 -0
  18. acontext-0.0.1.dev4/src/acontext/resources/disks.py +194 -0
  19. acontext-0.0.1.dev4/src/acontext/resources/sessions.py +271 -0
  20. acontext-0.0.1.dev4/src/acontext/resources/spaces.py +89 -0
  21. acontext-0.0.1.dev4/src/acontext/types/__init__.py +54 -0
  22. acontext-0.0.1.dev4/src/acontext/types/block.py +26 -0
  23. acontext-0.0.1.dev4/src/acontext/types/disk.py +65 -0
  24. acontext-0.0.1.dev4/src/acontext/types/session.py +123 -0
  25. acontext-0.0.1.dev4/src/acontext/types/space.py +24 -0
  26. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/src/acontext/uploads.py +5 -5
  27. acontext-0.0.1.dev2/src/acontext/client_types.py +0 -21
  28. acontext-0.0.1.dev2/src/acontext/resources/blocks.py +0 -94
  29. acontext-0.0.1.dev2/src/acontext/resources/disks.py +0 -109
  30. acontext-0.0.1.dev2/src/acontext/resources/sessions.py +0 -148
  31. acontext-0.0.1.dev2/src/acontext/resources/spaces.py +0 -58
  32. {acontext-0.0.1.dev2 → acontext-0.0.1.dev4}/src/acontext/py.typed +0 -0
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: acontext
3
- Version: 0.0.1.dev2
3
+ Version: 0.0.1.dev4
4
4
  Summary: Python SDK for the Acontext API
5
5
  Keywords: acontext,sdk,client,api
6
6
  Requires-Dist: httpx>=0.28.1
7
7
  Requires-Dist: openai>=2.6.1
8
8
  Requires-Dist: anthropic>=0.72.0
9
+ Requires-Dist: pydantic>=2.12.3
9
10
  Requires-Python: >=3.10
10
11
  Project-URL: Homepage, https://github.com/memodb-io/Acontext
11
12
  Project-URL: Issues, https://github.com/memodb-io/Acontext/issues
@@ -63,7 +64,7 @@ try:
63
64
  content=b"# Retro Notes\nWe shipped file uploads successfully!\n",
64
65
  content_type="text/markdown",
65
66
  ),
66
- file_path="notes/retro.md",
67
+ file_path="/notes/",
67
68
  meta={"source": "readme-demo"},
68
69
  )
69
70
  finally:
@@ -49,7 +49,7 @@ try:
49
49
  content=b"# Retro Notes\nWe shipped file uploads successfully!\n",
50
50
  content_type="text/markdown",
51
51
  ),
52
- file_path="notes/retro.md",
52
+ file_path="/notes/",
53
53
  meta={"source": "readme-demo"},
54
54
  )
55
55
  finally:
@@ -1,13 +1,14 @@
1
1
  [project]
2
2
  name = "acontext"
3
- version = "0.0.1.dev2"
3
+ version = "0.0.1.dev4"
4
4
  description = "Python SDK for the Acontext API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
7
  dependencies = [
8
8
  "httpx>=0.28.1",
9
9
  "openai>=2.6.1",
10
- "anthropic>=0.72.0"
10
+ "anthropic>=0.72.0",
11
+ "pydantic>=2.12.3",
11
12
  ]
12
13
  keywords = ["acontext", "sdk", "client", "api"]
13
14
 
@@ -17,7 +18,11 @@ Repository = "https://github.com/memodb-io/Acontext"
17
18
  Issues = "https://github.com/memodb-io/Acontext/issues"
18
19
 
19
20
  [dependency-groups]
20
- dev = ["pytest", "ruff"]
21
+ dev = [
22
+ "pytest",
23
+ "ruff",
24
+ "pytest-asyncio"
25
+ ]
21
26
 
22
27
  [build-system]
23
28
  requires = ["uv_build>=0.9.2,<0.10.0"]
@@ -4,12 +4,25 @@ Python SDK for the Acontext API.
4
4
 
5
5
  from importlib import metadata as _metadata
6
6
 
7
+ from .async_client import AcontextAsyncClient
7
8
  from .client import AcontextClient, FileUpload, MessagePart
8
9
  from .messages import AcontextMessage
9
- from .resources import BlocksAPI, DiskArtifactsAPI, DisksAPI, SessionsAPI, SpacesAPI
10
+ from .resources import (
11
+ AsyncBlocksAPI,
12
+ AsyncDiskArtifactsAPI,
13
+ AsyncDisksAPI,
14
+ AsyncSessionsAPI,
15
+ AsyncSpacesAPI,
16
+ BlocksAPI,
17
+ DiskArtifactsAPI,
18
+ DisksAPI,
19
+ SessionsAPI,
20
+ SpacesAPI,
21
+ )
10
22
 
11
23
  __all__ = [
12
24
  "AcontextClient",
25
+ "AcontextAsyncClient",
13
26
  "FileUpload",
14
27
  "MessagePart",
15
28
  "AcontextMessage",
@@ -18,6 +31,11 @@ __all__ = [
18
31
  "BlocksAPI",
19
32
  "SessionsAPI",
20
33
  "SpacesAPI",
34
+ "AsyncDisksAPI",
35
+ "AsyncDiskArtifactsAPI",
36
+ "AsyncBlocksAPI",
37
+ "AsyncSessionsAPI",
38
+ "AsyncSpacesAPI",
21
39
  "__version__",
22
40
  ]
23
41
 
@@ -5,7 +5,6 @@ Internal constants shared across the Python SDK.
5
5
  from importlib import metadata as _metadata
6
6
 
7
7
  DEFAULT_BASE_URL = "https://api.acontext.io/api/v1"
8
- SUPPORTED_ROLES = {"user", "assistant", "system", "tool", "function"}
9
8
 
10
9
  try:
11
10
  _VERSION = _metadata.version("acontext-py")
@@ -0,0 +1,42 @@
1
+ """Utility functions for the acontext Python client."""
2
+
3
+ from typing import Any
4
+
5
+
6
+ def bool_to_str(value: bool) -> str:
7
+ """Convert a boolean value to string representation used by the API.
8
+
9
+ Args:
10
+ value: The boolean value to convert.
11
+
12
+ Returns:
13
+ "true" if value is True, "false" otherwise.
14
+ """
15
+ return "true" if value else "false"
16
+
17
+
18
+ def build_params(**kwargs: Any) -> dict[str, Any]:
19
+ """Build query parameters dictionary, filtering None values and converting booleans.
20
+
21
+ This function filters out None values and converts boolean values to their
22
+ string representations ("true" or "false") as expected by the API.
23
+
24
+ Args:
25
+ **kwargs: Keyword arguments to build parameters from.
26
+
27
+ Returns:
28
+ Dictionary with non-None parameters, with booleans converted to strings.
29
+
30
+ Example:
31
+ >>> build_params(limit=10, cursor=None, time_desc=True)
32
+ {'limit': 10, 'time_desc': 'true'}
33
+ """
34
+ params: dict[str, Any] = {}
35
+ for key, value in kwargs.items():
36
+ if value is not None:
37
+ if isinstance(value, bool):
38
+ params[key] = bool_to_str(value)
39
+ else:
40
+ params[key] = value
41
+ return params
42
+
@@ -0,0 +1,206 @@
1
+ """
2
+ High-level asynchronous client for the Acontext API.
3
+ """
4
+
5
+ import os
6
+ from collections.abc import Mapping
7
+ from typing import Any, BinaryIO
8
+
9
+ import httpx
10
+
11
+ from ._constants import DEFAULT_BASE_URL, DEFAULT_USER_AGENT
12
+ from .errors import APIError, TransportError
13
+ from .messages import MessagePart as MessagePart
14
+ from .uploads import FileUpload as FileUpload
15
+ from .resources.async_disks import AsyncDisksAPI as AsyncDisksAPI
16
+ from .resources.async_blocks import AsyncBlocksAPI as AsyncBlocksAPI
17
+ from .resources.async_sessions import AsyncSessionsAPI as AsyncSessionsAPI
18
+ from .resources.async_spaces import AsyncSpacesAPI as AsyncSpacesAPI
19
+
20
+
21
+ class AcontextAsyncClient:
22
+
23
+ def __init__(
24
+ self,
25
+ *,
26
+ api_key: str | None = None,
27
+ base_url: str | None = None,
28
+ timeout: float | httpx.Timeout | None = 10.0,
29
+ user_agent: str | None = None,
30
+ client: httpx.AsyncClient | None = None,
31
+ ) -> None:
32
+ """
33
+ Initialize the Acontext async client.
34
+
35
+ Args:
36
+ api_key: API key for authentication. Can also be set via ACONTEXT_API_KEY env var.
37
+ base_url: Base URL for the API. Defaults to DEFAULT_BASE_URL. Can also be set via ACONTEXT_BASE_URL env var.
38
+ timeout: Request timeout in seconds. Defaults to 10.0. Can also be set via ACONTEXT_TIMEOUT env var.
39
+ Can also be an httpx.Timeout object.
40
+ user_agent: Custom user agent string. Can also be set via ACONTEXT_USER_AGENT env var.
41
+ client: Optional httpx.AsyncClient instance to reuse. If provided, headers and base_url
42
+ will be merged with the client configuration.
43
+ """
44
+ # Priority: explicit parameters > environment variables > defaults
45
+ # Load api_key from parameter or environment variable
46
+ api_key = api_key or os.getenv("ACONTEXT_API_KEY")
47
+ if not api_key or not api_key.strip():
48
+ raise ValueError(
49
+ "api_key is required. Provide it either as a parameter (api_key='...') "
50
+ "or set the ACONTEXT_API_KEY environment variable."
51
+ )
52
+
53
+ # Load other parameters from environment variables if not provided
54
+ if base_url is None:
55
+ base_url = os.getenv("ACONTEXT_BASE_URL", DEFAULT_BASE_URL)
56
+ base_url = base_url.rstrip("/")
57
+
58
+ if user_agent is None:
59
+ user_agent = os.getenv("ACONTEXT_USER_AGENT", DEFAULT_USER_AGENT)
60
+
61
+ # Handle timeout: support both float and httpx.Timeout
62
+ if timeout is None:
63
+ timeout_str = os.getenv("ACONTEXT_TIMEOUT")
64
+ if timeout_str:
65
+ try:
66
+ timeout = float(timeout_str)
67
+ except ValueError:
68
+ timeout = 10.0
69
+ else:
70
+ timeout = 10.0
71
+
72
+ # Determine actual timeout value
73
+ actual_timeout: float | httpx.Timeout
74
+ if isinstance(timeout, httpx.Timeout):
75
+ actual_timeout = timeout
76
+ else:
77
+ actual_timeout = float(timeout)
78
+
79
+ headers = {
80
+ "Authorization": f"Bearer {api_key}",
81
+ "Accept": "application/json",
82
+ "User-Agent": user_agent,
83
+ }
84
+
85
+ if client is not None:
86
+ self._client = client
87
+ self._owns_client = False
88
+ if client.base_url == httpx.URL():
89
+ client.base_url = httpx.URL(base_url)
90
+ for name, value in headers.items():
91
+ if name not in client.headers:
92
+ client.headers[name] = value
93
+ self._base_url = str(client.base_url) or base_url
94
+ else:
95
+ self._client = httpx.AsyncClient(
96
+ base_url=base_url,
97
+ headers=headers,
98
+ timeout=actual_timeout,
99
+ )
100
+ self._owns_client = True
101
+ self._base_url = base_url
102
+
103
+ self._timeout = actual_timeout
104
+
105
+ self.spaces = AsyncSpacesAPI(self)
106
+ self.sessions = AsyncSessionsAPI(self)
107
+ self.disks = AsyncDisksAPI(self)
108
+ self.artifacts = self.disks.artifacts
109
+ self.blocks = AsyncBlocksAPI(self)
110
+
111
+ @property
112
+ def base_url(self) -> str:
113
+ return self._base_url
114
+
115
+ async def aclose(self) -> None:
116
+ """Close the async client."""
117
+ if self._owns_client:
118
+ await self._client.aclose()
119
+
120
+ async def __aenter__(self) -> "AcontextAsyncClient":
121
+ return self
122
+
123
+ async def __aexit__(self, exc_type, exc, tb) -> None: # noqa: D401 - standard context manager protocol
124
+ await self.aclose()
125
+
126
+ # ------------------------------------------------------------------
127
+ # HTTP plumbing shared by resource clients
128
+ # ------------------------------------------------------------------
129
+ async def request(
130
+ self,
131
+ method: str,
132
+ path: str,
133
+ *,
134
+ params: Mapping[str, Any] | None = None,
135
+ json_data: Mapping[str, Any] | None = None,
136
+ data: Mapping[str, Any] | None = None,
137
+ files: Mapping[str, tuple[str, BinaryIO, str | None]] | None = None,
138
+ unwrap: bool = True,
139
+ ) -> Any:
140
+ try:
141
+ response = await self._client.request(
142
+ method=method,
143
+ url=path,
144
+ params=params,
145
+ json=json_data,
146
+ data=data,
147
+ files=files,
148
+ timeout=self._timeout,
149
+ )
150
+ except httpx.HTTPError as exc: # pragma: no cover - passthrough to caller
151
+ raise TransportError(str(exc)) from exc
152
+
153
+ return self._handle_response(response, unwrap=unwrap)
154
+
155
+ @staticmethod
156
+ def _handle_response(response: httpx.Response, *, unwrap: bool) -> Any:
157
+ content_type = response.headers.get("content-type", "")
158
+
159
+ parsed: Mapping[str, Any] | None = None
160
+ if "application/json" in content_type:
161
+ try:
162
+ parsed = response.json()
163
+ except ValueError:
164
+ parsed = None
165
+ else:
166
+ parsed = None
167
+
168
+ if response.status_code >= 400:
169
+ message = response.reason_phrase
170
+ payload: Mapping[str, Any] | None = parsed
171
+ code: int | None = None
172
+ error: str | None = None
173
+ if payload and isinstance(payload, Mapping):
174
+ message = str(payload.get("msg") or payload.get("message") or message)
175
+ error = payload.get("error")
176
+ try:
177
+ code_val = payload.get("code")
178
+ if isinstance(code_val, int):
179
+ code = code_val
180
+ except Exception: # pragma: no cover - defensive
181
+ code = None
182
+ raise APIError(
183
+ status_code=response.status_code,
184
+ code=code,
185
+ message=message,
186
+ error=error,
187
+ payload=payload,
188
+ )
189
+
190
+ if parsed is None:
191
+ if unwrap:
192
+ return response.text
193
+ return {"code": response.status_code, "data": response.text, "msg": response.reason_phrase}
194
+
195
+ app_code = parsed.get("code")
196
+ if isinstance(app_code, int) and app_code >= 400:
197
+ raise APIError(
198
+ status_code=response.status_code,
199
+ code=app_code,
200
+ message=str(parsed.get("msg") or response.reason_phrase),
201
+ error=parsed.get("error"),
202
+ payload=parsed,
203
+ )
204
+
205
+ return parsed.get("data") if unwrap else parsed
206
+
@@ -2,7 +2,8 @@
2
2
  High-level synchronous client for the Acontext API.
3
3
  """
4
4
 
5
- from collections.abc import Mapping, MutableMapping
5
+ import os
6
+ from collections.abc import Mapping
6
7
  from typing import Any, BinaryIO
7
8
 
8
9
  import httpx
@@ -16,41 +17,69 @@ from .resources.blocks import BlocksAPI as BlocksAPI
16
17
  from .resources.sessions import SessionsAPI as SessionsAPI
17
18
  from .resources.spaces import SpacesAPI as SpacesAPI
18
19
 
19
- class AcontextClient:
20
- """
21
- Synchronous HTTP client for the Acontext REST API.
22
-
23
- Example::
24
20
 
25
- from acontext import AcontextClient, MessagePart
26
-
27
- with AcontextClient(api_key="sk_...") as client:
28
- spaces = client.spaces.list()
29
- session = client.sessions.create(space_id=spaces[0]["id"])
30
- client.sessions.send_message(
31
- session["id"],
32
- role="user",
33
- parts=[MessagePart.text_part("Hello Acontext!")],
34
- )
35
- """
21
+ class AcontextClient:
36
22
 
37
23
  def __init__(
38
24
  self,
39
25
  *,
40
- api_key: str,
41
- base_url: str = DEFAULT_BASE_URL,
26
+ api_key: str | None = None,
27
+ base_url: str | None = None,
42
28
  timeout: float | httpx.Timeout | None = 10.0,
43
29
  user_agent: str | None = None,
44
30
  client: httpx.Client | None = None,
45
31
  ) -> None:
46
- if not api_key:
47
- raise ValueError("api_key is required")
32
+ """
33
+ Initialize the Acontext client.
34
+
35
+ Args:
36
+ api_key: API key for authentication. Can also be set via ACONTEXT_API_KEY env var.
37
+ base_url: Base URL for the API. Defaults to DEFAULT_BASE_URL. Can also be set via ACONTEXT_BASE_URL env var.
38
+ timeout: Request timeout in seconds. Defaults to 10.0. Can also be set via ACONTEXT_TIMEOUT env var.
39
+ Can also be an httpx.Timeout object.
40
+ user_agent: Custom user agent string. Can also be set via ACONTEXT_USER_AGENT env var.
41
+ client: Optional httpx.Client instance to reuse. If provided, headers and base_url
42
+ will be merged with the client configuration.
43
+ """
44
+ # Priority: explicit parameters > environment variables > defaults
45
+ # Load api_key from parameter or environment variable
46
+ api_key = api_key or os.getenv("ACONTEXT_API_KEY")
47
+ if not api_key or not api_key.strip():
48
+ raise ValueError(
49
+ "api_key is required. Provide it either as a parameter (api_key='...') "
50
+ "or set the ACONTEXT_API_KEY environment variable."
51
+ )
48
52
 
53
+ # Load other parameters from environment variables if not provided
54
+ if base_url is None:
55
+ base_url = os.getenv("ACONTEXT_BASE_URL", DEFAULT_BASE_URL)
49
56
  base_url = base_url.rstrip("/")
57
+
58
+ if user_agent is None:
59
+ user_agent = os.getenv("ACONTEXT_USER_AGENT", DEFAULT_USER_AGENT)
60
+
61
+ # Handle timeout: support both float and httpx.Timeout
62
+ if timeout is None:
63
+ timeout_str = os.getenv("ACONTEXT_TIMEOUT")
64
+ if timeout_str:
65
+ try:
66
+ timeout = float(timeout_str)
67
+ except ValueError:
68
+ timeout = 10.0
69
+ else:
70
+ timeout = 10.0
71
+
72
+ # Determine actual timeout value
73
+ actual_timeout: float | httpx.Timeout
74
+ if isinstance(timeout, httpx.Timeout):
75
+ actual_timeout = timeout
76
+ else:
77
+ actual_timeout = float(timeout)
78
+
50
79
  headers = {
51
80
  "Authorization": f"Bearer {api_key}",
52
81
  "Accept": "application/json",
53
- "User-Agent": user_agent or DEFAULT_USER_AGENT,
82
+ "User-Agent": user_agent,
54
83
  }
55
84
 
56
85
  if client is not None:
@@ -63,11 +92,15 @@ class AcontextClient:
63
92
  client.headers[name] = value
64
93
  self._base_url = str(client.base_url) or base_url
65
94
  else:
66
- self._client = httpx.Client(base_url=base_url, headers=headers, timeout=timeout)
95
+ self._client = httpx.Client(
96
+ base_url=base_url,
97
+ headers=headers,
98
+ timeout=actual_timeout,
99
+ )
67
100
  self._owns_client = True
68
101
  self._base_url = base_url
69
102
 
70
- self._timeout = timeout
103
+ self._timeout = actual_timeout
71
104
 
72
105
  self.spaces = SpacesAPI(self)
73
106
  self.sessions = SessionsAPI(self)
@@ -98,8 +131,8 @@ class AcontextClient:
98
131
  path: str,
99
132
  *,
100
133
  params: Mapping[str, Any] | None = None,
101
- json_data: Mapping[str, Any] | MutableMapping[str, Any] | None = None,
102
- data: Mapping[str, Any] | MutableMapping[str, Any] | None = None,
134
+ json_data: Mapping[str, Any] | None = None,
135
+ data: Mapping[str, Any] | None = None,
103
136
  files: Mapping[str, tuple[str, BinaryIO, str | None]] | None = None,
104
137
  unwrap: bool = True,
105
138
  ) -> Any:
@@ -122,10 +155,10 @@ class AcontextClient:
122
155
  def _handle_response(response: httpx.Response, *, unwrap: bool) -> Any:
123
156
  content_type = response.headers.get("content-type", "")
124
157
 
125
- parsed: Mapping[str, Any] | MutableMapping[str, Any] | None
126
- if "application/json" in content_type or content_type.startswith("application/problem+json"):
158
+ parsed: Mapping[str, Any] | None
159
+ if "application/json" in content_type:
127
160
  try:
128
- parsed = response.json()
161
+ parsed = response.json() # dict
129
162
  except ValueError:
130
163
  parsed = None
131
164
  else:
@@ -133,7 +166,7 @@ class AcontextClient:
133
166
 
134
167
  if response.status_code >= 400:
135
168
  message = response.reason_phrase
136
- payload: Mapping[str, Any] | MutableMapping[str, Any] | None = parsed
169
+ payload: Mapping[str, Any] | None = parsed
137
170
  code: int | None = None
138
171
  error: str | None = None
139
172
  if payload and isinstance(payload, Mapping):
@@ -158,11 +191,6 @@ class AcontextClient:
158
191
  return response.text
159
192
  return {"code": response.status_code, "data": response.text, "msg": response.reason_phrase}
160
193
 
161
- if not isinstance(parsed, Mapping):
162
- if unwrap:
163
- return parsed
164
- return parsed
165
-
166
194
  app_code = parsed.get("code")
167
195
  if isinstance(app_code, int) and app_code >= 400:
168
196
  raise APIError(
@@ -0,0 +1,36 @@
1
+ """
2
+ Common typing helpers used by resource modules to avoid circular imports.
3
+ """
4
+
5
+ from collections.abc import Awaitable, Mapping
6
+ from typing import Any, BinaryIO, Protocol
7
+
8
+
9
+ class RequesterProtocol(Protocol):
10
+ def request(
11
+ self,
12
+ method: str,
13
+ path: str,
14
+ *,
15
+ params: Mapping[str, Any] | None = None,
16
+ json_data: Mapping[str, Any] | None = None,
17
+ data: Mapping[str, Any] | None = None,
18
+ files: Mapping[str, tuple[str, BinaryIO, str | None]] | None = None,
19
+ unwrap: bool = True,
20
+ ) -> Any:
21
+ ...
22
+
23
+
24
+ class AsyncRequesterProtocol(Protocol):
25
+ def request(
26
+ self,
27
+ method: str,
28
+ path: str,
29
+ *,
30
+ params: Mapping[str, Any] | None = None,
31
+ json_data: Mapping[str, Any] | None = None,
32
+ data: Mapping[str, Any] | None = None,
33
+ files: Mapping[str, tuple[str, BinaryIO, str | None]] | None = None,
34
+ unwrap: bool = True,
35
+ ) -> Awaitable[Any]:
36
+ ...
@@ -2,7 +2,7 @@
2
2
  Custom exceptions raised by the acontext Python client.
3
3
  """
4
4
 
5
- from collections.abc import Mapping, MutableMapping
5
+ from collections.abc import Mapping
6
6
  from typing import Any
7
7
 
8
8
 
@@ -29,7 +29,7 @@ class APIError(AcontextError):
29
29
  code: int | None = None,
30
30
  message: str | None = None,
31
31
  error: str | None = None,
32
- payload: Mapping[str, Any] | MutableMapping[str, Any] | None = None,
32
+ payload: Mapping[str, Any] | None = None,
33
33
  ) -> None:
34
34
  self.status_code = status_code
35
35
  self.code = code
@@ -2,7 +2,7 @@
2
2
  Support for constructing session messages.
3
3
  """
4
4
 
5
- from collections.abc import Mapping, MutableMapping, Sequence
5
+ from collections.abc import Mapping, Sequence
6
6
  from dataclasses import dataclass
7
7
  from typing import Any, Literal
8
8
 
@@ -25,14 +25,6 @@ class MessagePart:
25
25
  meta: Mapping[str, Any] | None = None
26
26
  file_field: str | None = None
27
27
 
28
- @classmethod
29
- def text_part(cls, text: str, *, meta: Mapping[str, Any] | None = None) -> "MessagePart":
30
- return cls(type="text", text=text, meta=meta)
31
-
32
- @classmethod
33
- def file_field_part(cls, file_field: str, *, meta: Mapping[str, Any] | None = None) -> "MessagePart":
34
- return cls(type="file", file_field=file_field, meta=meta)
35
-
36
28
  @dataclass(slots=True)
37
29
  class AcontextMessage:
38
30
  """
@@ -41,7 +33,7 @@ class AcontextMessage:
41
33
 
42
34
  role: Literal["user", "assistant", "system"]
43
35
  parts: list[MessagePart]
44
- meta: MutableMapping[str, Any] | None = None
36
+ meta: Mapping[str, Any] | None = None
45
37
 
46
38
 
47
39
  def build_acontext_message(
@@ -1,5 +1,9 @@
1
1
  """Resource-specific API helpers for the Acontext client."""
2
2
 
3
+ from .async_blocks import AsyncBlocksAPI
4
+ from .async_disks import AsyncDisksAPI, AsyncDiskArtifactsAPI
5
+ from .async_sessions import AsyncSessionsAPI
6
+ from .async_spaces import AsyncSpacesAPI
3
7
  from .blocks import BlocksAPI
4
8
  from .disks import DisksAPI, DiskArtifactsAPI
5
9
  from .sessions import SessionsAPI
@@ -11,4 +15,9 @@ __all__ = [
11
15
  "BlocksAPI",
12
16
  "SessionsAPI",
13
17
  "SpacesAPI",
18
+ "AsyncDisksAPI",
19
+ "AsyncDiskArtifactsAPI",
20
+ "AsyncBlocksAPI",
21
+ "AsyncSessionsAPI",
22
+ "AsyncSpacesAPI",
14
23
  ]