acontext 0.0.1.dev0__tar.gz → 0.0.1.dev2__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.
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/PKG-INFO +32 -6
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/README.md +28 -4
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/pyproject.toml +7 -3
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/__init__.py +5 -11
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/client.py +5 -5
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/client_types.py +2 -1
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/errors.py +2 -1
- acontext-0.0.1.dev2/src/acontext/messages.py +83 -0
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/resources/__init__.py +3 -8
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/resources/blocks.py +25 -14
- acontext-0.0.1.dev2/src/acontext/resources/disks.py +109 -0
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/resources/sessions.py +58 -17
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/resources/spaces.py +23 -1
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/uploads.py +2 -2
- acontext-0.0.1.dev0/src/acontext/messages.py +0 -94
- acontext-0.0.1.dev0/src/acontext/resources/artifacts.py +0 -98
- acontext-0.0.1.dev0/src/acontext/resources/pages.py +0 -82
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/_constants.py +0 -0
- {acontext-0.0.1.dev0 → acontext-0.0.1.dev2}/src/acontext/py.typed +0 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: acontext
|
|
3
|
-
Version: 0.0.1.
|
|
3
|
+
Version: 0.0.1.dev2
|
|
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
|
-
Requires-
|
|
7
|
+
Requires-Dist: openai>=2.6.1
|
|
8
|
+
Requires-Dist: anthropic>=0.72.0
|
|
9
|
+
Requires-Python: >=3.10
|
|
8
10
|
Project-URL: Homepage, https://github.com/memodb-io/Acontext
|
|
9
11
|
Project-URL: Issues, https://github.com/memodb-io/Acontext/issues
|
|
10
12
|
Project-URL: Repository, https://github.com/memodb-io/Acontext
|
|
@@ -20,7 +22,7 @@ Python SDK for interacting with the Acontext REST API.
|
|
|
20
22
|
pip install acontext
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
> Requires Python 3.
|
|
25
|
+
> Requires Python 3.10 or newer.
|
|
24
26
|
|
|
25
27
|
### Quickstart
|
|
26
28
|
|
|
@@ -42,9 +44,33 @@ with AcontextClient(api_key="sk_project_token") as client:
|
|
|
42
44
|
)
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
See the inline docstrings for the full list of helpers covering sessions, spaces,
|
|
47
|
+
See the inline docstrings for the full list of helpers covering sessions, spaces, disks, and artifact uploads.
|
|
46
48
|
|
|
47
|
-
###
|
|
49
|
+
### Managing disks and artifacts
|
|
50
|
+
|
|
51
|
+
Artifacts now live under project disks. Create a disk first, then upload files through the disk-scoped helper:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from acontext import AcontextClient, FileUpload
|
|
55
|
+
|
|
56
|
+
client = AcontextClient(api_key="sk_project_token")
|
|
57
|
+
try:
|
|
58
|
+
disk = client.disks.create()
|
|
59
|
+
client.disks.artifacts.upsert(
|
|
60
|
+
disk["id"],
|
|
61
|
+
file=FileUpload(
|
|
62
|
+
filename="retro_notes.md",
|
|
63
|
+
content=b"# Retro Notes\nWe shipped file uploads successfully!\n",
|
|
64
|
+
content_type="text/markdown",
|
|
65
|
+
),
|
|
66
|
+
file_path="notes/retro.md",
|
|
67
|
+
meta={"source": "readme-demo"},
|
|
68
|
+
)
|
|
69
|
+
finally:
|
|
70
|
+
client.close()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Working with blocks
|
|
48
74
|
|
|
49
75
|
```python
|
|
50
76
|
from acontext import AcontextClient
|
|
@@ -53,7 +79,7 @@ client = AcontextClient(api_key="sk_project_token")
|
|
|
53
79
|
|
|
54
80
|
space = client.spaces.create()
|
|
55
81
|
try:
|
|
56
|
-
page = client.
|
|
82
|
+
page = client.blocks.create(space["id"], block_type="page", title="Kick-off Notes")
|
|
57
83
|
client.blocks.create(
|
|
58
84
|
space["id"],
|
|
59
85
|
parent_id=page["id"],
|
|
@@ -8,7 +8,7 @@ Python SDK for interacting with the Acontext REST API.
|
|
|
8
8
|
pip install acontext
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
> Requires Python 3.
|
|
11
|
+
> Requires Python 3.10 or newer.
|
|
12
12
|
|
|
13
13
|
### Quickstart
|
|
14
14
|
|
|
@@ -30,9 +30,33 @@ with AcontextClient(api_key="sk_project_token") as client:
|
|
|
30
30
|
)
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
See the inline docstrings for the full list of helpers covering sessions, spaces,
|
|
33
|
+
See the inline docstrings for the full list of helpers covering sessions, spaces, disks, and artifact uploads.
|
|
34
34
|
|
|
35
|
-
###
|
|
35
|
+
### Managing disks and artifacts
|
|
36
|
+
|
|
37
|
+
Artifacts now live under project disks. Create a disk first, then upload files through the disk-scoped helper:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from acontext import AcontextClient, FileUpload
|
|
41
|
+
|
|
42
|
+
client = AcontextClient(api_key="sk_project_token")
|
|
43
|
+
try:
|
|
44
|
+
disk = client.disks.create()
|
|
45
|
+
client.disks.artifacts.upsert(
|
|
46
|
+
disk["id"],
|
|
47
|
+
file=FileUpload(
|
|
48
|
+
filename="retro_notes.md",
|
|
49
|
+
content=b"# Retro Notes\nWe shipped file uploads successfully!\n",
|
|
50
|
+
content_type="text/markdown",
|
|
51
|
+
),
|
|
52
|
+
file_path="notes/retro.md",
|
|
53
|
+
meta={"source": "readme-demo"},
|
|
54
|
+
)
|
|
55
|
+
finally:
|
|
56
|
+
client.close()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Working with blocks
|
|
36
60
|
|
|
37
61
|
```python
|
|
38
62
|
from acontext import AcontextClient
|
|
@@ -41,7 +65,7 @@ client = AcontextClient(api_key="sk_project_token")
|
|
|
41
65
|
|
|
42
66
|
space = client.spaces.create()
|
|
43
67
|
try:
|
|
44
|
-
page = client.
|
|
68
|
+
page = client.blocks.create(space["id"], block_type="page", title="Kick-off Notes")
|
|
45
69
|
client.blocks.create(
|
|
46
70
|
space["id"],
|
|
47
71
|
parent_id=page["id"],
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "acontext"
|
|
3
|
-
version = "0.0.1.
|
|
3
|
+
version = "0.0.1.dev2"
|
|
4
4
|
description = "Python SDK for the Acontext API"
|
|
5
5
|
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.
|
|
7
|
-
dependencies = [
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"httpx>=0.28.1",
|
|
9
|
+
"openai>=2.6.1",
|
|
10
|
+
"anthropic>=0.72.0"
|
|
11
|
+
]
|
|
8
12
|
keywords = ["acontext", "sdk", "client", "api"]
|
|
9
13
|
|
|
10
14
|
[project.urls]
|
|
@@ -5,23 +5,17 @@ Python SDK for the Acontext API.
|
|
|
5
5
|
from importlib import metadata as _metadata
|
|
6
6
|
|
|
7
7
|
from .client import AcontextClient, FileUpload, MessagePart
|
|
8
|
-
from .
|
|
9
|
-
|
|
10
|
-
ArtifactsAPI,
|
|
11
|
-
BlocksAPI,
|
|
12
|
-
PagesAPI,
|
|
13
|
-
SessionsAPI,
|
|
14
|
-
SpacesAPI,
|
|
15
|
-
)
|
|
8
|
+
from .messages import AcontextMessage
|
|
9
|
+
from .resources import BlocksAPI, DiskArtifactsAPI, DisksAPI, SessionsAPI, SpacesAPI
|
|
16
10
|
|
|
17
11
|
__all__ = [
|
|
18
12
|
"AcontextClient",
|
|
19
13
|
"FileUpload",
|
|
20
14
|
"MessagePart",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
15
|
+
"AcontextMessage",
|
|
16
|
+
"DisksAPI",
|
|
17
|
+
"DiskArtifactsAPI",
|
|
23
18
|
"BlocksAPI",
|
|
24
|
-
"PagesAPI",
|
|
25
19
|
"SessionsAPI",
|
|
26
20
|
"SpacesAPI",
|
|
27
21
|
"__version__",
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
High-level synchronous client for the Acontext API.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Mapping, MutableMapping
|
|
6
|
+
from typing import Any, BinaryIO
|
|
6
7
|
|
|
7
8
|
import httpx
|
|
8
9
|
|
|
@@ -10,9 +11,8 @@ from ._constants import DEFAULT_BASE_URL, DEFAULT_USER_AGENT
|
|
|
10
11
|
from .errors import APIError, TransportError
|
|
11
12
|
from .messages import MessagePart as MessagePart
|
|
12
13
|
from .uploads import FileUpload as FileUpload
|
|
13
|
-
from .resources.
|
|
14
|
+
from .resources.disks import DisksAPI as DisksAPI
|
|
14
15
|
from .resources.blocks import BlocksAPI as BlocksAPI
|
|
15
|
-
from .resources.pages import PagesAPI as PagesAPI
|
|
16
16
|
from .resources.sessions import SessionsAPI as SessionsAPI
|
|
17
17
|
from .resources.spaces import SpacesAPI as SpacesAPI
|
|
18
18
|
|
|
@@ -71,8 +71,8 @@ class AcontextClient:
|
|
|
71
71
|
|
|
72
72
|
self.spaces = SpacesAPI(self)
|
|
73
73
|
self.sessions = SessionsAPI(self)
|
|
74
|
-
self.
|
|
75
|
-
self.
|
|
74
|
+
self.disks = DisksAPI(self)
|
|
75
|
+
self.artifacts = self.disks.artifacts
|
|
76
76
|
self.blocks = BlocksAPI(self)
|
|
77
77
|
|
|
78
78
|
@property
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
Common typing helpers used by resource modules to avoid circular imports.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Mapping, MutableMapping
|
|
6
|
+
from typing import Any, BinaryIO, Protocol
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class RequesterProtocol(Protocol):
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Support for constructing session messages.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping, MutableMapping, Sequence
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Any, Literal
|
|
8
|
+
|
|
9
|
+
@dataclass(slots=True)
|
|
10
|
+
class MessagePart:
|
|
11
|
+
"""
|
|
12
|
+
Represents a single message part for ``/session/{id}/messages``.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
type: One of ``text``, ``image``, ``audio``, ``video``, ``file``, ``tool-call``,
|
|
16
|
+
``tool-result`` or ``data``.
|
|
17
|
+
text: Optional textual payload for ``text`` parts.
|
|
18
|
+
meta: Optional metadata dictionary accepted by the API.
|
|
19
|
+
file_field: Optional field name to use in the multipart body. When omitted the
|
|
20
|
+
client will auto-generate deterministic field names.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
type: str
|
|
24
|
+
text: str | None = None
|
|
25
|
+
meta: Mapping[str, Any] | None = None
|
|
26
|
+
file_field: str | None = None
|
|
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
|
+
@dataclass(slots=True)
|
|
37
|
+
class AcontextMessage:
|
|
38
|
+
"""
|
|
39
|
+
Represents an Acontext-format message payload.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
role: Literal["user", "assistant", "system"]
|
|
43
|
+
parts: list[MessagePart]
|
|
44
|
+
meta: MutableMapping[str, Any] | None = None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def build_acontext_message(
|
|
48
|
+
*,
|
|
49
|
+
role: Literal["user", "assistant", "system"],
|
|
50
|
+
parts: Sequence[MessagePart | str | Mapping[str, Any]],
|
|
51
|
+
meta: Mapping[str, Any] | None = None,
|
|
52
|
+
) -> AcontextMessage:
|
|
53
|
+
"""
|
|
54
|
+
Construct an Acontext-format message blob and associated multipart files.
|
|
55
|
+
"""
|
|
56
|
+
if role not in {"user", "assistant", "system"}:
|
|
57
|
+
raise ValueError("role must be one of {'user', 'assistant', 'system'}")
|
|
58
|
+
|
|
59
|
+
normalized_parts = [normalize_message_part(part) for part in parts]
|
|
60
|
+
|
|
61
|
+
message = AcontextMessage(
|
|
62
|
+
role=role,
|
|
63
|
+
parts=normalized_parts,
|
|
64
|
+
meta=dict(meta) if meta is not None else None,
|
|
65
|
+
)
|
|
66
|
+
return message
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def normalize_message_part(part: MessagePart | str | Mapping[str, Any]) -> MessagePart:
|
|
70
|
+
if isinstance(part, MessagePart):
|
|
71
|
+
return part
|
|
72
|
+
if isinstance(part, str):
|
|
73
|
+
return MessagePart(type="text", text=part)
|
|
74
|
+
if isinstance(part, Mapping):
|
|
75
|
+
if "type" not in part:
|
|
76
|
+
raise ValueError("mapping message parts must include a 'type'")
|
|
77
|
+
return MessagePart(
|
|
78
|
+
type=str(part["type"]),
|
|
79
|
+
text=part.get("text"),
|
|
80
|
+
meta=part.get("meta"),
|
|
81
|
+
file_field=part.get("file_field"),
|
|
82
|
+
)
|
|
83
|
+
raise TypeError("unsupported message part type")
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
"""Resource-specific API helpers for the Acontext client."""
|
|
2
2
|
|
|
3
|
-
from .artifacts import (
|
|
4
|
-
ArtifactFilesAPI,
|
|
5
|
-
ArtifactsAPI,
|
|
6
|
-
)
|
|
7
3
|
from .blocks import BlocksAPI
|
|
8
|
-
from .
|
|
4
|
+
from .disks import DisksAPI, DiskArtifactsAPI
|
|
9
5
|
from .sessions import SessionsAPI
|
|
10
6
|
from .spaces import SpacesAPI
|
|
11
7
|
|
|
12
8
|
__all__ = [
|
|
13
|
-
"
|
|
14
|
-
"
|
|
9
|
+
"DisksAPI",
|
|
10
|
+
"DiskArtifactsAPI",
|
|
15
11
|
"BlocksAPI",
|
|
16
|
-
"PagesAPI",
|
|
17
12
|
"SessionsAPI",
|
|
18
13
|
"SpacesAPI",
|
|
19
14
|
]
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
Block endpoints.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Mapping, MutableMapping
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
from ..client_types import RequesterProtocol
|
|
8
9
|
|
|
@@ -11,26 +12,34 @@ class BlocksAPI:
|
|
|
11
12
|
def __init__(self, requester: RequesterProtocol) -> None:
|
|
12
13
|
self._requester = requester
|
|
13
14
|
|
|
14
|
-
def list(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
def list(
|
|
16
|
+
self,
|
|
17
|
+
space_id: str,
|
|
18
|
+
*,
|
|
19
|
+
parent_id: str | None = None,
|
|
20
|
+
block_type: str | None = None,
|
|
21
|
+
) -> Any:
|
|
22
|
+
params: dict[str, Any] = {}
|
|
23
|
+
if parent_id is not None:
|
|
24
|
+
params["parent_id"] = parent_id
|
|
25
|
+
if block_type is not None:
|
|
26
|
+
params["type"] = block_type
|
|
27
|
+
return self._requester.request("GET", f"/space/{space_id}/block", params=params or None)
|
|
19
28
|
|
|
20
29
|
def create(
|
|
21
30
|
self,
|
|
22
31
|
space_id: str,
|
|
23
32
|
*,
|
|
24
|
-
parent_id: str,
|
|
25
33
|
block_type: str,
|
|
34
|
+
parent_id: str | None = None,
|
|
26
35
|
title: str | None = None,
|
|
27
36
|
props: Mapping[str, Any] | MutableMapping[str, Any] | None = None,
|
|
28
37
|
) -> Any:
|
|
29
|
-
if not parent_id:
|
|
30
|
-
raise ValueError("parent_id is required")
|
|
31
38
|
if not block_type:
|
|
32
39
|
raise ValueError("block_type is required")
|
|
33
|
-
payload: dict[str, Any] = {"
|
|
40
|
+
payload: dict[str, Any] = {"type": block_type}
|
|
41
|
+
if parent_id is not None:
|
|
42
|
+
payload["parent_id"] = parent_id
|
|
34
43
|
if title is not None:
|
|
35
44
|
payload["title"] = title
|
|
36
45
|
if props is not None:
|
|
@@ -65,14 +74,16 @@ class BlocksAPI:
|
|
|
65
74
|
space_id: str,
|
|
66
75
|
block_id: str,
|
|
67
76
|
*,
|
|
68
|
-
parent_id: str,
|
|
77
|
+
parent_id: str | None = None,
|
|
69
78
|
sort: int | None = None,
|
|
70
79
|
) -> None:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
payload: dict[str, Any] = {}
|
|
81
|
+
if parent_id is not None:
|
|
82
|
+
payload["parent_id"] = parent_id
|
|
74
83
|
if sort is not None:
|
|
75
84
|
payload["sort"] = sort
|
|
85
|
+
if not payload:
|
|
86
|
+
raise ValueError("parent_id or sort must be provided")
|
|
76
87
|
self._requester.request("PUT", f"/space/{space_id}/block/{block_id}/move", json_data=payload)
|
|
77
88
|
|
|
78
89
|
def update_sort(self, space_id: str, block_id: str, *, sort: int) -> None:
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Disk and artifact endpoints.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from collections.abc import Mapping, MutableMapping
|
|
7
|
+
from typing import Any, BinaryIO, cast
|
|
8
|
+
|
|
9
|
+
from ..client_types import RequesterProtocol
|
|
10
|
+
from ..uploads import FileUpload, normalize_file_upload
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _bool_to_str(value: bool) -> str:
|
|
14
|
+
return "true" if value else "false"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DisksAPI:
|
|
18
|
+
def __init__(self, requester: RequesterProtocol) -> None:
|
|
19
|
+
self._requester = requester
|
|
20
|
+
self.artifacts = DiskArtifactsAPI(requester)
|
|
21
|
+
|
|
22
|
+
def list(self) -> Any:
|
|
23
|
+
return self._requester.request("GET", "/disk")
|
|
24
|
+
|
|
25
|
+
def create(self) -> Any:
|
|
26
|
+
return self._requester.request("POST", "/disk")
|
|
27
|
+
|
|
28
|
+
def delete(self, disk_id: str) -> None:
|
|
29
|
+
self._requester.request("DELETE", f"/disk/{disk_id}")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DiskArtifactsAPI:
|
|
33
|
+
def __init__(self, requester: RequesterProtocol) -> None:
|
|
34
|
+
self._requester = requester
|
|
35
|
+
|
|
36
|
+
def upsert(
|
|
37
|
+
self,
|
|
38
|
+
disk_id: str,
|
|
39
|
+
*,
|
|
40
|
+
file: FileUpload
|
|
41
|
+
| tuple[str, BinaryIO | bytes]
|
|
42
|
+
| tuple[str, BinaryIO | bytes, str | None],
|
|
43
|
+
file_path: str | None = None,
|
|
44
|
+
meta: Mapping[str, Any] | MutableMapping[str, Any] | None = None,
|
|
45
|
+
) -> Any:
|
|
46
|
+
upload = normalize_file_upload(file)
|
|
47
|
+
files = {"file": upload.as_httpx()}
|
|
48
|
+
form: dict[str, Any] = {}
|
|
49
|
+
if file_path:
|
|
50
|
+
form["file_path"] = file_path
|
|
51
|
+
if meta is not None:
|
|
52
|
+
form["meta"] = json.dumps(cast(Mapping[str, Any], meta))
|
|
53
|
+
return self._requester.request(
|
|
54
|
+
"POST",
|
|
55
|
+
f"/disk/{disk_id}/artifact",
|
|
56
|
+
data=form or None,
|
|
57
|
+
files=files,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def get(
|
|
61
|
+
self,
|
|
62
|
+
disk_id: str,
|
|
63
|
+
*,
|
|
64
|
+
file_path: str,
|
|
65
|
+
with_public_url: bool | None = None,
|
|
66
|
+
with_content: bool | None = None,
|
|
67
|
+
expire: int | None = None,
|
|
68
|
+
) -> Any:
|
|
69
|
+
params: dict[str, Any] = {"file_path": file_path}
|
|
70
|
+
if with_public_url is not None:
|
|
71
|
+
params["with_public_url"] = _bool_to_str(with_public_url)
|
|
72
|
+
if with_content is not None:
|
|
73
|
+
params["with_content"] = _bool_to_str(with_content)
|
|
74
|
+
if expire is not None:
|
|
75
|
+
params["expire"] = expire
|
|
76
|
+
return self._requester.request("GET", f"/disk/{disk_id}/artifact", params=params)
|
|
77
|
+
|
|
78
|
+
def update(
|
|
79
|
+
self,
|
|
80
|
+
disk_id: str,
|
|
81
|
+
*,
|
|
82
|
+
file_path: str,
|
|
83
|
+
meta: Mapping[str, Any] | MutableMapping[str, Any],
|
|
84
|
+
) -> Any:
|
|
85
|
+
payload = {
|
|
86
|
+
"file_path": file_path,
|
|
87
|
+
"meta": json.dumps(cast(Mapping[str, Any], meta)),
|
|
88
|
+
}
|
|
89
|
+
return self._requester.request("PUT", f"/disk/{disk_id}/artifact", json_data=payload)
|
|
90
|
+
|
|
91
|
+
def delete(
|
|
92
|
+
self,
|
|
93
|
+
disk_id: str,
|
|
94
|
+
*,
|
|
95
|
+
file_path: str,
|
|
96
|
+
) -> None:
|
|
97
|
+
params = {"file_path": file_path}
|
|
98
|
+
self._requester.request("DELETE", f"/disk/{disk_id}/artifact", params=params)
|
|
99
|
+
|
|
100
|
+
def list(
|
|
101
|
+
self,
|
|
102
|
+
disk_id: str,
|
|
103
|
+
*,
|
|
104
|
+
path: str | None = None,
|
|
105
|
+
) -> Any:
|
|
106
|
+
params: dict[str, Any] = {}
|
|
107
|
+
if path is not None:
|
|
108
|
+
params["path"] = path
|
|
109
|
+
return self._requester.request("GET", f"/disk/{disk_id}/artifact/ls", params=params or None)
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Sessions endpoints.
|
|
3
|
-
"""
|
|
1
|
+
"""Sessions endpoints."""
|
|
4
2
|
|
|
5
3
|
import json
|
|
6
|
-
from
|
|
4
|
+
from collections.abc import Mapping, MutableMapping
|
|
5
|
+
from dataclasses import asdict
|
|
6
|
+
from typing import Any, BinaryIO, Literal
|
|
7
7
|
|
|
8
|
-
from .._constants import SUPPORTED_ROLES
|
|
9
|
-
from ..messages import MessagePart, build_message_payload
|
|
10
8
|
from ..client_types import RequesterProtocol
|
|
9
|
+
from ..messages import AcontextMessage
|
|
10
|
+
from ..uploads import FileUpload
|
|
11
|
+
from openai.types.chat import ChatCompletionMessageParam
|
|
12
|
+
from anthropic.types import MessageParam
|
|
13
|
+
|
|
14
|
+
UploadPayload = FileUpload | tuple[str, BinaryIO | bytes] | tuple[str, BinaryIO | bytes, str | None]
|
|
15
|
+
MessageBlob = AcontextMessage | ChatCompletionMessageParam | MessageParam
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
class SessionsAPI:
|
|
@@ -59,30 +64,60 @@ class SessionsAPI:
|
|
|
59
64
|
payload = {"space_id": space_id}
|
|
60
65
|
self._requester.request("POST", f"/session/{session_id}/connect_to_space", json_data=payload)
|
|
61
66
|
|
|
67
|
+
def get_tasks(
|
|
68
|
+
self,
|
|
69
|
+
session_id: str,
|
|
70
|
+
*,
|
|
71
|
+
limit: int | None = None,
|
|
72
|
+
cursor: str | None = None,
|
|
73
|
+
) -> Any:
|
|
74
|
+
params: dict[str, Any] = {}
|
|
75
|
+
if limit is not None:
|
|
76
|
+
params["limit"] = limit
|
|
77
|
+
if cursor is not None:
|
|
78
|
+
params["cursor"] = cursor
|
|
79
|
+
return self._requester.request(
|
|
80
|
+
"GET",
|
|
81
|
+
f"/session/{session_id}/task",
|
|
82
|
+
params=params or None,
|
|
83
|
+
)
|
|
84
|
+
|
|
62
85
|
def send_message(
|
|
63
86
|
self,
|
|
64
87
|
session_id: str,
|
|
65
88
|
*,
|
|
66
|
-
|
|
67
|
-
|
|
89
|
+
blob: MessageBlob,
|
|
90
|
+
format: Literal["acontext", "openai", "anthropic"] = "acontext",
|
|
91
|
+
file_field: str | None = "",
|
|
92
|
+
file: FileUpload | None = None
|
|
68
93
|
) -> Any:
|
|
69
|
-
if
|
|
70
|
-
raise ValueError(
|
|
71
|
-
|
|
72
|
-
|
|
94
|
+
if format not in {"acontext", "openai", "anthropic"}:
|
|
95
|
+
raise ValueError("format must be one of {'acontext', 'openai', 'anthropic'}")
|
|
96
|
+
|
|
97
|
+
payload = {
|
|
98
|
+
"format": format,
|
|
99
|
+
}
|
|
100
|
+
if format == "acontext":
|
|
101
|
+
payload["blob"] = asdict(blob)
|
|
102
|
+
else:
|
|
103
|
+
payload["blob"] = blob
|
|
73
104
|
|
|
74
|
-
payload_parts, files = build_message_payload(parts)
|
|
75
|
-
payload = {"role": role, "parts": payload_parts}
|
|
76
105
|
|
|
77
|
-
|
|
106
|
+
file_payload: dict[str, tuple[str, BinaryIO, str | None]] | None = None
|
|
107
|
+
if file:
|
|
108
|
+
# only support upload one file now
|
|
109
|
+
file_payload = {
|
|
110
|
+
file_field: file.as_httpx()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if file_payload:
|
|
78
114
|
form_data = {"payload": json.dumps(payload)}
|
|
79
115
|
return self._requester.request(
|
|
80
116
|
"POST",
|
|
81
117
|
f"/session/{session_id}/messages",
|
|
82
118
|
data=form_data,
|
|
83
|
-
files=
|
|
119
|
+
files=file_payload,
|
|
84
120
|
)
|
|
85
|
-
|
|
86
121
|
return self._requester.request(
|
|
87
122
|
"POST",
|
|
88
123
|
f"/session/{session_id}/messages",
|
|
@@ -96,6 +131,8 @@ class SessionsAPI:
|
|
|
96
131
|
limit: int | None = None,
|
|
97
132
|
cursor: str | None = None,
|
|
98
133
|
with_asset_public_url: bool | None = None,
|
|
134
|
+
format: Literal["acontext", "openai", "anthropic"] = "acontext",
|
|
135
|
+
time_desc: bool | None = None,
|
|
99
136
|
) -> Any:
|
|
100
137
|
params: dict[str, Any] = {}
|
|
101
138
|
if limit is not None:
|
|
@@ -104,4 +141,8 @@ class SessionsAPI:
|
|
|
104
141
|
params["cursor"] = cursor
|
|
105
142
|
if with_asset_public_url is not None:
|
|
106
143
|
params["with_asset_public_url"] = "true" if with_asset_public_url else "false"
|
|
144
|
+
if format is not None:
|
|
145
|
+
params["format"] = format
|
|
146
|
+
if time_desc is not None:
|
|
147
|
+
params["time_desc"] = "true" if time_desc else "false"
|
|
107
148
|
return self._requester.request("GET", f"/session/{session_id}/messages", params=params or None)
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
Spaces endpoints.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Mapping, MutableMapping
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
from ..client_types import RequesterProtocol
|
|
8
9
|
|
|
@@ -14,6 +15,9 @@ class SpacesAPI:
|
|
|
14
15
|
def list(self) -> Any:
|
|
15
16
|
return self._requester.request("GET", "/space")
|
|
16
17
|
|
|
18
|
+
def status(self) -> Any:
|
|
19
|
+
return self._requester.request("GET", "/space/status")
|
|
20
|
+
|
|
17
21
|
def create(self, *, configs: Mapping[str, Any] | MutableMapping[str, Any] | None = None) -> Any:
|
|
18
22
|
payload: dict[str, Any] = {}
|
|
19
23
|
if configs is not None:
|
|
@@ -34,3 +38,21 @@ class SpacesAPI:
|
|
|
34
38
|
|
|
35
39
|
def get_configs(self, space_id: str) -> Any:
|
|
36
40
|
return self._requester.request("GET", f"/space/{space_id}/configs")
|
|
41
|
+
|
|
42
|
+
def get_semantic_answer(self, space_id: str, *, query: str) -> Any:
|
|
43
|
+
if not query:
|
|
44
|
+
raise ValueError("query is required")
|
|
45
|
+
params = {"query": query}
|
|
46
|
+
return self._requester.request("GET", f"/space/{space_id}/semantic_answer", params=params)
|
|
47
|
+
|
|
48
|
+
def get_semantic_global(self, space_id: str, *, query: str) -> Any:
|
|
49
|
+
if not query:
|
|
50
|
+
raise ValueError("query is required")
|
|
51
|
+
params = {"query": query}
|
|
52
|
+
return self._requester.request("GET", f"/space/{space_id}/semantic_global", params=params)
|
|
53
|
+
|
|
54
|
+
def get_semantic_grep(self, space_id: str, *, query: str) -> Any:
|
|
55
|
+
if not query:
|
|
56
|
+
raise ValueError("query is required")
|
|
57
|
+
params = {"query": query}
|
|
58
|
+
return self._requester.request("GET", f"/space/{space_id}/semantic_grep", params=params)
|
|
@@ -4,7 +4,7 @@ Utilities for working with file uploads.
|
|
|
4
4
|
|
|
5
5
|
import io
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
-
from typing import BinaryIO
|
|
7
|
+
from typing import BinaryIO
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
@dataclass(slots=True)
|
|
@@ -19,7 +19,7 @@ class FileUpload:
|
|
|
19
19
|
content: BinaryIO | bytes
|
|
20
20
|
content_type: str | None = None
|
|
21
21
|
|
|
22
|
-
def as_httpx(self) ->
|
|
22
|
+
def as_httpx(self) -> tuple[str, BinaryIO, str | None]:
|
|
23
23
|
"""
|
|
24
24
|
Convert to the tuple format expected by ``httpx``.
|
|
25
25
|
"""
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Support for constructing session messages.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from dataclasses import dataclass
|
|
6
|
-
from typing import Any, BinaryIO, Mapping, MutableMapping, Sequence, Tuple
|
|
7
|
-
|
|
8
|
-
from .uploads import FileUpload, normalize_file_upload
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass(slots=True)
|
|
12
|
-
class MessagePart:
|
|
13
|
-
"""
|
|
14
|
-
Represents a single message part for ``/session/{id}/messages``.
|
|
15
|
-
|
|
16
|
-
Args:
|
|
17
|
-
type: One of ``text``, ``image``, ``audio``, ``video``, ``file``, ``tool-call``,
|
|
18
|
-
``tool-result`` or ``data``.
|
|
19
|
-
text: Optional textual payload for ``text`` parts.
|
|
20
|
-
meta: Optional metadata dictionary accepted by the API.
|
|
21
|
-
file: Optional file attachment; required for binary part types.
|
|
22
|
-
file_field: Optional field name to use in the multipart body. When omitted the
|
|
23
|
-
client will auto-generate deterministic field names.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
type: str
|
|
27
|
-
text: str | None = None
|
|
28
|
-
meta: Mapping[str, Any] | None = None
|
|
29
|
-
file: FileUpload | tuple[str, BinaryIO | bytes] | tuple[str, BinaryIO | bytes, str | None] | None = None
|
|
30
|
-
file_field: str | None = None
|
|
31
|
-
|
|
32
|
-
@classmethod
|
|
33
|
-
def text_part(cls, text: str, *, meta: Mapping[str, Any] | None = None) -> "MessagePart":
|
|
34
|
-
return cls(type="text", text=text, meta=meta)
|
|
35
|
-
|
|
36
|
-
@classmethod
|
|
37
|
-
def file_part(
|
|
38
|
-
cls,
|
|
39
|
-
upload: FileUpload | tuple[str, BinaryIO | bytes] | tuple[str, BinaryIO | bytes, str | None],
|
|
40
|
-
*,
|
|
41
|
-
meta: Mapping[str, Any] | None = None,
|
|
42
|
-
type: str = "file",
|
|
43
|
-
) -> "MessagePart":
|
|
44
|
-
return cls(type=type, file=upload, meta=meta)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def normalize_message_part(part: MessagePart | str | Mapping[str, Any]) -> MessagePart:
|
|
48
|
-
if isinstance(part, MessagePart):
|
|
49
|
-
return part
|
|
50
|
-
if isinstance(part, str):
|
|
51
|
-
return MessagePart(type="text", text=part)
|
|
52
|
-
if isinstance(part, Mapping):
|
|
53
|
-
if "type" not in part:
|
|
54
|
-
raise ValueError("mapping message parts must include a 'type'")
|
|
55
|
-
file = part.get("file")
|
|
56
|
-
normalized_file: FileUpload | tuple[str, BinaryIO | bytes] | tuple[str, BinaryIO | bytes, str | None] | None
|
|
57
|
-
if file is None:
|
|
58
|
-
normalized_file = None
|
|
59
|
-
else:
|
|
60
|
-
normalized_file = file # type: ignore[assignment]
|
|
61
|
-
return MessagePart(
|
|
62
|
-
type=str(part["type"]),
|
|
63
|
-
text=part.get("text"),
|
|
64
|
-
meta=part.get("meta"),
|
|
65
|
-
file=normalized_file,
|
|
66
|
-
file_field=part.get("file_field"),
|
|
67
|
-
)
|
|
68
|
-
raise TypeError("unsupported message part type")
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def build_message_payload(
|
|
72
|
-
parts: Sequence[MessagePart | str | Mapping[str, Any]],
|
|
73
|
-
) -> tuple[list[MutableMapping[str, Any]], dict[str, Tuple[str, BinaryIO, str | None]]]:
|
|
74
|
-
payload_parts: list[MutableMapping[str, Any]] = []
|
|
75
|
-
files: dict[str, Tuple[str, BinaryIO, str | None]] = {}
|
|
76
|
-
|
|
77
|
-
for idx, raw_part in enumerate(parts):
|
|
78
|
-
part = normalize_message_part(raw_part)
|
|
79
|
-
payload: MutableMapping[str, Any] = {"type": part.type}
|
|
80
|
-
|
|
81
|
-
if part.meta is not None:
|
|
82
|
-
payload["meta"] = dict(part.meta)
|
|
83
|
-
if part.text is not None:
|
|
84
|
-
payload["text"] = part.text
|
|
85
|
-
|
|
86
|
-
if part.file is not None:
|
|
87
|
-
upload = normalize_file_upload(part.file)
|
|
88
|
-
field_name = part.file_field or f"file_{idx}"
|
|
89
|
-
payload["file_field"] = field_name
|
|
90
|
-
files[field_name] = upload.as_httpx()
|
|
91
|
-
|
|
92
|
-
payload_parts.append(payload)
|
|
93
|
-
|
|
94
|
-
return payload_parts, files
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Artifact and file endpoints.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
from typing import Any, BinaryIO, Mapping, MutableMapping
|
|
7
|
-
|
|
8
|
-
from ..client_types import RequesterProtocol
|
|
9
|
-
from ..uploads import FileUpload, normalize_file_upload
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class ArtifactsAPI:
|
|
13
|
-
def __init__(self, requester: RequesterProtocol) -> None:
|
|
14
|
-
self._requester = requester
|
|
15
|
-
self.files = ArtifactFilesAPI(requester)
|
|
16
|
-
|
|
17
|
-
def list(self) -> Any:
|
|
18
|
-
return self._requester.request("GET", "/artifact")
|
|
19
|
-
|
|
20
|
-
def create(self) -> Any:
|
|
21
|
-
return self._requester.request("POST", "/artifact")
|
|
22
|
-
|
|
23
|
-
def delete(self, artifact_id: str) -> None:
|
|
24
|
-
self._requester.request("DELETE", f"/artifact/{artifact_id}")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class ArtifactFilesAPI:
|
|
28
|
-
def __init__(self, requester: RequesterProtocol) -> None:
|
|
29
|
-
self._requester = requester
|
|
30
|
-
|
|
31
|
-
def upload(
|
|
32
|
-
self,
|
|
33
|
-
artifact_id: str,
|
|
34
|
-
*,
|
|
35
|
-
file: FileUpload | tuple[str, BinaryIO | bytes] | tuple[str, BinaryIO | bytes, str | None],
|
|
36
|
-
file_path: str | None = None,
|
|
37
|
-
meta: Mapping[str, Any] | MutableMapping[str, Any] | None = None,
|
|
38
|
-
) -> Any:
|
|
39
|
-
upload = normalize_file_upload(file)
|
|
40
|
-
files = {"file": upload.as_httpx()}
|
|
41
|
-
form: dict[str, Any] = {}
|
|
42
|
-
if file_path:
|
|
43
|
-
form["file_path"] = file_path
|
|
44
|
-
if meta is not None:
|
|
45
|
-
form["meta"] = json.dumps(meta)
|
|
46
|
-
return self._requester.request(
|
|
47
|
-
"POST",
|
|
48
|
-
f"/artifact/{artifact_id}/file",
|
|
49
|
-
data=form or None,
|
|
50
|
-
files=files,
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
def update(
|
|
54
|
-
self,
|
|
55
|
-
artifact_id: str,
|
|
56
|
-
*,
|
|
57
|
-
file_path: str,
|
|
58
|
-
file: FileUpload | tuple[str, BinaryIO | bytes] | tuple[str, BinaryIO | bytes, str | None],
|
|
59
|
-
) -> Any:
|
|
60
|
-
upload = normalize_file_upload(file)
|
|
61
|
-
files = {"file": upload.as_httpx()}
|
|
62
|
-
form = {"file_path": file_path}
|
|
63
|
-
return self._requester.request(
|
|
64
|
-
"PUT",
|
|
65
|
-
f"/artifact/{artifact_id}/file",
|
|
66
|
-
data=form,
|
|
67
|
-
files=files,
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
def delete(self, artifact_id: str, *, file_path: str) -> None:
|
|
71
|
-
params = {"file_path": file_path}
|
|
72
|
-
self._requester.request("DELETE", f"/artifact/{artifact_id}/file", params=params)
|
|
73
|
-
|
|
74
|
-
def get(
|
|
75
|
-
self,
|
|
76
|
-
artifact_id: str,
|
|
77
|
-
*,
|
|
78
|
-
file_path: str,
|
|
79
|
-
with_public_url: bool | None = None,
|
|
80
|
-
expire: int | None = None,
|
|
81
|
-
) -> Any:
|
|
82
|
-
params: dict[str, Any] = {"file_path": file_path}
|
|
83
|
-
if with_public_url is not None:
|
|
84
|
-
params["with_public_url"] = "true" if with_public_url else "false"
|
|
85
|
-
if expire is not None:
|
|
86
|
-
params["expire"] = expire
|
|
87
|
-
return self._requester.request("GET", f"/artifact/{artifact_id}/file", params=params)
|
|
88
|
-
|
|
89
|
-
def list(
|
|
90
|
-
self,
|
|
91
|
-
artifact_id: str,
|
|
92
|
-
*,
|
|
93
|
-
path: str | None = None,
|
|
94
|
-
) -> Any:
|
|
95
|
-
params: dict[str, Any] = {}
|
|
96
|
-
if path is not None:
|
|
97
|
-
params["path"] = path
|
|
98
|
-
return self._requester.request("GET", f"/artifact/{artifact_id}/file/ls", params=params or None)
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Page endpoints.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from typing import Any, Mapping, MutableMapping
|
|
6
|
-
|
|
7
|
-
from ..client_types import RequesterProtocol
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class PagesAPI:
|
|
11
|
-
def __init__(self, requester: RequesterProtocol) -> None:
|
|
12
|
-
self._requester = requester
|
|
13
|
-
|
|
14
|
-
def list(self, space_id: str, *, parent_id: str | None = None) -> Any:
|
|
15
|
-
params: dict[str, Any] = {}
|
|
16
|
-
if parent_id is not None:
|
|
17
|
-
params["parent_id"] = parent_id
|
|
18
|
-
return self._requester.request("GET", f"/space/{space_id}/page", params=params or None)
|
|
19
|
-
|
|
20
|
-
def create(
|
|
21
|
-
self,
|
|
22
|
-
space_id: str,
|
|
23
|
-
*,
|
|
24
|
-
parent_id: str | None = None,
|
|
25
|
-
title: str | None = None,
|
|
26
|
-
props: Mapping[str, Any] | MutableMapping[str, Any] | None = None,
|
|
27
|
-
) -> Any:
|
|
28
|
-
payload: dict[str, Any] = {}
|
|
29
|
-
if parent_id is not None:
|
|
30
|
-
payload["parent_id"] = parent_id
|
|
31
|
-
if title is not None:
|
|
32
|
-
payload["title"] = title
|
|
33
|
-
if props is not None:
|
|
34
|
-
payload["props"] = props
|
|
35
|
-
return self._requester.request("POST", f"/space/{space_id}/page", json_data=payload)
|
|
36
|
-
|
|
37
|
-
def delete(self, space_id: str, page_id: str) -> None:
|
|
38
|
-
self._requester.request("DELETE", f"/space/{space_id}/page/{page_id}")
|
|
39
|
-
|
|
40
|
-
def get_properties(self, space_id: str, page_id: str) -> Any:
|
|
41
|
-
return self._requester.request("GET", f"/space/{space_id}/page/{page_id}/properties")
|
|
42
|
-
|
|
43
|
-
def update_properties(
|
|
44
|
-
self,
|
|
45
|
-
space_id: str,
|
|
46
|
-
page_id: str,
|
|
47
|
-
*,
|
|
48
|
-
title: str | None = None,
|
|
49
|
-
props: Mapping[str, Any] | MutableMapping[str, Any] | None = None,
|
|
50
|
-
) -> None:
|
|
51
|
-
payload: dict[str, Any] = {}
|
|
52
|
-
if title is not None:
|
|
53
|
-
payload["title"] = title
|
|
54
|
-
if props is not None:
|
|
55
|
-
payload["props"] = props
|
|
56
|
-
if not payload:
|
|
57
|
-
raise ValueError("title or props must be provided")
|
|
58
|
-
self._requester.request("PUT", f"/space/{space_id}/page/{page_id}/properties", json_data=payload)
|
|
59
|
-
|
|
60
|
-
def move(
|
|
61
|
-
self,
|
|
62
|
-
space_id: str,
|
|
63
|
-
page_id: str,
|
|
64
|
-
*,
|
|
65
|
-
parent_id: str | None = None,
|
|
66
|
-
sort: int | None = None,
|
|
67
|
-
) -> None:
|
|
68
|
-
payload: dict[str, Any] = {}
|
|
69
|
-
if parent_id is not None:
|
|
70
|
-
payload["parent_id"] = parent_id
|
|
71
|
-
if sort is not None:
|
|
72
|
-
payload["sort"] = sort
|
|
73
|
-
if not payload:
|
|
74
|
-
raise ValueError("parent_id or sort must be provided")
|
|
75
|
-
self._requester.request("PUT", f"/space/{space_id}/page/{page_id}/move", json_data=payload)
|
|
76
|
-
|
|
77
|
-
def update_sort(self, space_id: str, page_id: str, *, sort: int) -> None:
|
|
78
|
-
self._requester.request(
|
|
79
|
-
"PUT",
|
|
80
|
-
f"/space/{space_id}/page/{page_id}/sort",
|
|
81
|
-
json_data={"sort": sort},
|
|
82
|
-
)
|
|
File without changes
|
|
File without changes
|