acontext 0.0.1.dev4__tar.gz → 0.0.1.dev6__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 (31) hide show
  1. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/PKG-INFO +77 -1
  2. acontext-0.0.1.dev6/README.md +154 -0
  3. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/pyproject.toml +2 -6
  4. acontext-0.0.1.dev6/src/acontext/resources/async_spaces.py +188 -0
  5. acontext-0.0.1.dev6/src/acontext/resources/spaces.py +186 -0
  6. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/types/__init__.py +4 -1
  7. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/types/session.py +3 -2
  8. acontext-0.0.1.dev6/src/acontext/types/space.py +46 -0
  9. acontext-0.0.1.dev4/README.md +0 -78
  10. acontext-0.0.1.dev4/src/acontext/resources/async_spaces.py +0 -90
  11. acontext-0.0.1.dev4/src/acontext/resources/spaces.py +0 -89
  12. acontext-0.0.1.dev4/src/acontext/types/space.py +0 -24
  13. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/__init__.py +0 -0
  14. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/_constants.py +0 -0
  15. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/_utils.py +0 -0
  16. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/async_client.py +0 -0
  17. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/client.py +0 -0
  18. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/client_types.py +0 -0
  19. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/errors.py +0 -0
  20. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/messages.py +0 -0
  21. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/py.typed +0 -0
  22. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/resources/__init__.py +0 -0
  23. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/resources/async_blocks.py +0 -0
  24. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/resources/async_disks.py +0 -0
  25. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/resources/async_sessions.py +0 -0
  26. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/resources/blocks.py +0 -0
  27. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/resources/disks.py +0 -0
  28. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/resources/sessions.py +0 -0
  29. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/types/block.py +0 -0
  30. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/types/disk.py +0 -0
  31. {acontext-0.0.1.dev4 → acontext-0.0.1.dev6}/src/acontext/uploads.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: acontext
3
- Version: 0.0.1.dev4
3
+ Version: 0.0.1.dev6
4
4
  Summary: Python SDK for the Acontext API
5
5
  Keywords: acontext,sdk,client,api
6
6
  Requires-Dist: httpx>=0.28.1
@@ -91,3 +91,79 @@ try:
91
91
  finally:
92
92
  client.close()
93
93
  ```
94
+
95
+ ### Semantic search within spaces
96
+
97
+ The SDK provides three powerful semantic search APIs for finding content within your spaces:
98
+
99
+ #### 1. Experience Search (Advanced AI-powered search)
100
+
101
+ The most sophisticated search that can operate in two modes: **fast** (quick semantic search) or **agentic** (AI-powered iterative refinement).
102
+
103
+ ```python
104
+ from acontext import AcontextClient
105
+
106
+ client = AcontextClient(api_key="sk_project_token")
107
+
108
+ # Fast mode - quick semantic search
109
+ result = client.spaces.experience_search(
110
+ space_id="space-uuid",
111
+ query="How to implement authentication?",
112
+ limit=10,
113
+ mode="fast",
114
+ )
115
+
116
+ # Agentic mode - AI-powered iterative search
117
+ result = client.spaces.experience_search(
118
+ space_id="space-uuid",
119
+ query="What are the best practices for API security?",
120
+ limit=10,
121
+ mode="agentic",
122
+ semantic_threshold=0.8,
123
+ max_iterations=20,
124
+ )
125
+
126
+ # Access results
127
+ for block in result.cited_blocks:
128
+ print(f"{block.title} (distance: {block.distance})")
129
+
130
+ if result.final_answer:
131
+ print(f"AI Answer: {result.final_answer}")
132
+ ```
133
+
134
+ #### 2. Semantic Global (Search page/folder titles)
135
+
136
+ Search for pages and folders by their titles using semantic similarity (like a semantic version of `glob`):
137
+
138
+ ```python
139
+ # Find pages about authentication
140
+ results = client.spaces.semantic_global(
141
+ space_id="space-uuid",
142
+ query="authentication and authorization pages",
143
+ limit=10,
144
+ threshold=1.0, # Only show results with distance < 1.0
145
+ )
146
+
147
+ for block in results:
148
+ print(f"{block.title} - {block.type}")
149
+ ```
150
+
151
+ #### 3. Semantic Grep (Search content blocks)
152
+
153
+ Search through actual content blocks using semantic similarity (like a semantic version of `grep`):
154
+
155
+ ```python
156
+ # Find code examples for JWT validation
157
+ results = client.spaces.semantic_grep(
158
+ space_id="space-uuid",
159
+ query="JWT token validation code examples",
160
+ limit=15,
161
+ threshold=0.7,
162
+ )
163
+
164
+ for block in results:
165
+ print(f"{block.title} - distance: {block.distance}")
166
+ print(f"Content: {block.props.get('text', '')[:100]}...")
167
+ ```
168
+
169
+ See `examples/search_usage.py` for more detailed examples including async usage.
@@ -0,0 +1,154 @@
1
+ ## acontext client for python
2
+
3
+ Python SDK for interacting with the Acontext REST API.
4
+
5
+ ### Installation
6
+
7
+ ```bash
8
+ pip install acontext
9
+ ```
10
+
11
+ > Requires Python 3.10 or newer.
12
+
13
+ ### Quickstart
14
+
15
+ ```python
16
+ from acontext import AcontextClient, MessagePart
17
+
18
+ with AcontextClient(api_key="sk_project_token") as client:
19
+ # List spaces for the authenticated project
20
+ spaces = client.spaces.list()
21
+
22
+ # Create a session bound to the first space
23
+ session = client.sessions.create(space_id=spaces[0]["id"])
24
+
25
+ # Send a text message to the session
26
+ client.sessions.send_message(
27
+ session["id"],
28
+ role="user",
29
+ parts=[MessagePart.text_part("Hello from Python!")],
30
+ )
31
+ ```
32
+
33
+ See the inline docstrings for the full list of helpers covering sessions, spaces, disks, and artifact uploads.
34
+
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/",
53
+ meta={"source": "readme-demo"},
54
+ )
55
+ finally:
56
+ client.close()
57
+ ```
58
+
59
+ ### Working with blocks
60
+
61
+ ```python
62
+ from acontext import AcontextClient
63
+
64
+ client = AcontextClient(api_key="sk_project_token")
65
+
66
+ space = client.spaces.create()
67
+ try:
68
+ page = client.blocks.create(space["id"], block_type="page", title="Kick-off Notes")
69
+ client.blocks.create(
70
+ space["id"],
71
+ parent_id=page["id"],
72
+ block_type="text",
73
+ title="First block",
74
+ props={"text": "Plan the sprint goals"},
75
+ )
76
+ finally:
77
+ client.close()
78
+ ```
79
+
80
+ ### Semantic search within spaces
81
+
82
+ The SDK provides three powerful semantic search APIs for finding content within your spaces:
83
+
84
+ #### 1. Experience Search (Advanced AI-powered search)
85
+
86
+ The most sophisticated search that can operate in two modes: **fast** (quick semantic search) or **agentic** (AI-powered iterative refinement).
87
+
88
+ ```python
89
+ from acontext import AcontextClient
90
+
91
+ client = AcontextClient(api_key="sk_project_token")
92
+
93
+ # Fast mode - quick semantic search
94
+ result = client.spaces.experience_search(
95
+ space_id="space-uuid",
96
+ query="How to implement authentication?",
97
+ limit=10,
98
+ mode="fast",
99
+ )
100
+
101
+ # Agentic mode - AI-powered iterative search
102
+ result = client.spaces.experience_search(
103
+ space_id="space-uuid",
104
+ query="What are the best practices for API security?",
105
+ limit=10,
106
+ mode="agentic",
107
+ semantic_threshold=0.8,
108
+ max_iterations=20,
109
+ )
110
+
111
+ # Access results
112
+ for block in result.cited_blocks:
113
+ print(f"{block.title} (distance: {block.distance})")
114
+
115
+ if result.final_answer:
116
+ print(f"AI Answer: {result.final_answer}")
117
+ ```
118
+
119
+ #### 2. Semantic Global (Search page/folder titles)
120
+
121
+ Search for pages and folders by their titles using semantic similarity (like a semantic version of `glob`):
122
+
123
+ ```python
124
+ # Find pages about authentication
125
+ results = client.spaces.semantic_global(
126
+ space_id="space-uuid",
127
+ query="authentication and authorization pages",
128
+ limit=10,
129
+ threshold=1.0, # Only show results with distance < 1.0
130
+ )
131
+
132
+ for block in results:
133
+ print(f"{block.title} - {block.type}")
134
+ ```
135
+
136
+ #### 3. Semantic Grep (Search content blocks)
137
+
138
+ Search through actual content blocks using semantic similarity (like a semantic version of `grep`):
139
+
140
+ ```python
141
+ # Find code examples for JWT validation
142
+ results = client.spaces.semantic_grep(
143
+ space_id="space-uuid",
144
+ query="JWT token validation code examples",
145
+ limit=15,
146
+ threshold=0.7,
147
+ )
148
+
149
+ for block in results:
150
+ print(f"{block.title} - distance: {block.distance}")
151
+ print(f"Content: {block.props.get('text', '')[:100]}...")
152
+ ```
153
+
154
+ See `examples/search_usage.py` for more detailed examples including async usage.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "acontext"
3
- version = "0.0.1.dev4"
3
+ version = "0.0.1.dev6"
4
4
  description = "Python SDK for the Acontext API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -18,11 +18,7 @@ Repository = "https://github.com/memodb-io/Acontext"
18
18
  Issues = "https://github.com/memodb-io/Acontext/issues"
19
19
 
20
20
  [dependency-groups]
21
- dev = [
22
- "pytest",
23
- "ruff",
24
- "pytest-asyncio"
25
- ]
21
+ dev = ["pytest", "ruff", "pytest-asyncio"]
26
22
 
27
23
  [build-system]
28
24
  requires = ["uv_build>=0.9.2,<0.10.0"]
@@ -0,0 +1,188 @@
1
+ """
2
+ Spaces endpoints (async).
3
+ """
4
+
5
+ from collections.abc import Mapping
6
+ from typing import Any, List
7
+
8
+ from .._utils import build_params
9
+ from ..client_types import AsyncRequesterProtocol
10
+ from ..types.space import (
11
+ ListSpacesOutput,
12
+ SearchResultBlockItem,
13
+ Space,
14
+ SpaceSearchResult,
15
+ )
16
+
17
+
18
+ class AsyncSpacesAPI:
19
+ def __init__(self, requester: AsyncRequesterProtocol) -> None:
20
+ self._requester = requester
21
+
22
+ async def list(
23
+ self,
24
+ *,
25
+ limit: int | None = None,
26
+ cursor: str | None = None,
27
+ time_desc: bool | None = None,
28
+ ) -> ListSpacesOutput:
29
+ """List all spaces in the project.
30
+
31
+ Args:
32
+ limit: Maximum number of spaces to return. Defaults to None.
33
+ cursor: Cursor for pagination. Defaults to None.
34
+ time_desc: Order by created_at descending if True, ascending if False. Defaults to None.
35
+
36
+ Returns:
37
+ ListSpacesOutput containing the list of spaces and pagination information.
38
+ """
39
+ params = build_params(limit=limit, cursor=cursor, time_desc=time_desc)
40
+ data = await self._requester.request("GET", "/space", params=params or None)
41
+ return ListSpacesOutput.model_validate(data)
42
+
43
+ async def create(self, *, configs: Mapping[str, Any] | None = None) -> Space:
44
+ """Create a new space.
45
+
46
+ Args:
47
+ configs: Optional space configuration dictionary. Defaults to None.
48
+
49
+ Returns:
50
+ The created Space object.
51
+ """
52
+ payload: dict[str, Any] = {}
53
+ if configs is not None:
54
+ payload["configs"] = configs
55
+ data = await self._requester.request("POST", "/space", json_data=payload)
56
+ return Space.model_validate(data)
57
+
58
+ async def delete(self, space_id: str) -> None:
59
+ """Delete a space by its ID.
60
+
61
+ Args:
62
+ space_id: The UUID of the space to delete.
63
+ """
64
+ await self._requester.request("DELETE", f"/space/{space_id}")
65
+
66
+ async def update_configs(
67
+ self,
68
+ space_id: str,
69
+ *,
70
+ configs: Mapping[str, Any],
71
+ ) -> None:
72
+ """Update space configurations.
73
+
74
+ Args:
75
+ space_id: The UUID of the space.
76
+ configs: Space configuration dictionary.
77
+ """
78
+ payload = {"configs": configs}
79
+ await self._requester.request(
80
+ "PUT", f"/space/{space_id}/configs", json_data=payload
81
+ )
82
+
83
+ async def get_configs(self, space_id: str) -> Space:
84
+ """Get space configurations.
85
+
86
+ Args:
87
+ space_id: The UUID of the space.
88
+
89
+ Returns:
90
+ Space object containing the configurations.
91
+ """
92
+ data = await self._requester.request("GET", f"/space/{space_id}/configs")
93
+ return Space.model_validate(data)
94
+
95
+ async def experience_search(
96
+ self,
97
+ space_id: str,
98
+ *,
99
+ query: str,
100
+ limit: int | None = None,
101
+ mode: str | None = None,
102
+ semantic_threshold: float | None = None,
103
+ max_iterations: int | None = None,
104
+ ) -> SpaceSearchResult:
105
+ """Perform experience search within a space.
106
+
107
+ This is the most advanced search option that can operate in two modes:
108
+ - fast: Quick semantic search (default)
109
+ - agentic: Iterative search with AI-powered refinement
110
+
111
+ Args:
112
+ space_id: The UUID of the space.
113
+ query: The search query string.
114
+ limit: Maximum number of results to return (1-50, default 10).
115
+ mode: Search mode, either "fast" or "agentic" (default "fast").
116
+ semantic_threshold: Cosine distance threshold (0=identical, 2=opposite).
117
+ max_iterations: Maximum iterations for agentic search (1-100, default 16).
118
+
119
+ Returns:
120
+ SpaceSearchResult containing cited blocks and optional final answer.
121
+ """
122
+ params = build_params(
123
+ query=query,
124
+ limit=limit,
125
+ mode=mode,
126
+ semantic_threshold=semantic_threshold,
127
+ max_iterations=max_iterations,
128
+ )
129
+ data = await self._requester.request(
130
+ "GET", f"/space/{space_id}/experience_search", params=params or None
131
+ )
132
+ return SpaceSearchResult.model_validate(data)
133
+
134
+ async def semantic_global(
135
+ self,
136
+ space_id: str,
137
+ *,
138
+ query: str,
139
+ limit: int | None = None,
140
+ threshold: float | None = None,
141
+ ) -> List[SearchResultBlockItem]:
142
+ """Perform semantic global (glob) search for page/folder titles.
143
+
144
+ Searches specifically for page/folder titles using semantic similarity,
145
+ similar to a semantic version of the glob command.
146
+
147
+ Args:
148
+ space_id: The UUID of the space.
149
+ query: Search query for page/folder titles.
150
+ limit: Maximum number of results to return (1-50, default 10).
151
+ threshold: Cosine distance threshold (0=identical, 2=opposite).
152
+
153
+ Returns:
154
+ List of SearchResultBlockItem objects matching the query.
155
+ """
156
+ params = build_params(query=query, limit=limit, threshold=threshold)
157
+ data = await self._requester.request(
158
+ "GET", f"/space/{space_id}/semantic_global", params=params or None
159
+ )
160
+ return [SearchResultBlockItem.model_validate(item) for item in data]
161
+
162
+ async def semantic_grep(
163
+ self,
164
+ space_id: str,
165
+ *,
166
+ query: str,
167
+ limit: int | None = None,
168
+ threshold: float | None = None,
169
+ ) -> List[SearchResultBlockItem]:
170
+ """Perform semantic grep search for content blocks.
171
+
172
+ Searches through content blocks (actual text content) using semantic similarity,
173
+ similar to a semantic version of the grep command.
174
+
175
+ Args:
176
+ space_id: The UUID of the space.
177
+ query: Search query for content blocks.
178
+ limit: Maximum number of results to return (1-50, default 10).
179
+ threshold: Cosine distance threshold (0=identical, 2=opposite).
180
+
181
+ Returns:
182
+ List of SearchResultBlockItem objects matching the query.
183
+ """
184
+ params = build_params(query=query, limit=limit, threshold=threshold)
185
+ data = await self._requester.request(
186
+ "GET", f"/space/{space_id}/semantic_grep", params=params or None
187
+ )
188
+ return [SearchResultBlockItem.model_validate(item) for item in data]
@@ -0,0 +1,186 @@
1
+ """
2
+ Spaces endpoints.
3
+ """
4
+
5
+ from collections.abc import Mapping
6
+ from typing import Any, List
7
+
8
+ from .._utils import build_params
9
+ from ..client_types import RequesterProtocol
10
+ from ..types.space import (
11
+ ListSpacesOutput,
12
+ SearchResultBlockItem,
13
+ Space,
14
+ SpaceSearchResult,
15
+ )
16
+
17
+
18
+ class SpacesAPI:
19
+ def __init__(self, requester: RequesterProtocol) -> None:
20
+ self._requester = requester
21
+
22
+ def list(
23
+ self,
24
+ *,
25
+ limit: int | None = None,
26
+ cursor: str | None = None,
27
+ time_desc: bool | None = None,
28
+ ) -> ListSpacesOutput:
29
+ """List all spaces in the project.
30
+
31
+ Args:
32
+ limit: Maximum number of spaces to return. Defaults to None.
33
+ cursor: Cursor for pagination. Defaults to None.
34
+ time_desc: Order by created_at descending if True, ascending if False. Defaults to None.
35
+
36
+ Returns:
37
+ ListSpacesOutput containing the list of spaces and pagination information.
38
+ """
39
+ params = build_params(limit=limit, cursor=cursor, time_desc=time_desc)
40
+ data = self._requester.request("GET", "/space", params=params or None)
41
+ return ListSpacesOutput.model_validate(data)
42
+
43
+ def create(self, *, configs: Mapping[str, Any] | None = None) -> Space:
44
+ """Create a new space.
45
+
46
+ Args:
47
+ configs: Optional space configuration dictionary. Defaults to None.
48
+
49
+ Returns:
50
+ The created Space object.
51
+ """
52
+ payload: dict[str, Any] = {}
53
+ if configs is not None:
54
+ payload["configs"] = configs
55
+ data = self._requester.request("POST", "/space", json_data=payload)
56
+ return Space.model_validate(data)
57
+
58
+ def delete(self, space_id: str) -> None:
59
+ """Delete a space by its ID.
60
+
61
+ Args:
62
+ space_id: The UUID of the space to delete.
63
+ """
64
+ self._requester.request("DELETE", f"/space/{space_id}")
65
+
66
+ def update_configs(
67
+ self,
68
+ space_id: str,
69
+ *,
70
+ configs: Mapping[str, Any],
71
+ ) -> None:
72
+ """Update space configurations.
73
+
74
+ Args:
75
+ space_id: The UUID of the space.
76
+ configs: Space configuration dictionary.
77
+ """
78
+ payload = {"configs": configs}
79
+ self._requester.request("PUT", f"/space/{space_id}/configs", json_data=payload)
80
+
81
+ def get_configs(self, space_id: str) -> Space:
82
+ """Get space configurations.
83
+
84
+ Args:
85
+ space_id: The UUID of the space.
86
+
87
+ Returns:
88
+ Space object containing the configurations.
89
+ """
90
+ data = self._requester.request("GET", f"/space/{space_id}/configs")
91
+ return Space.model_validate(data)
92
+
93
+ def experience_search(
94
+ self,
95
+ space_id: str,
96
+ *,
97
+ query: str,
98
+ limit: int | None = None,
99
+ mode: str | None = None,
100
+ semantic_threshold: float | None = None,
101
+ max_iterations: int | None = None,
102
+ ) -> SpaceSearchResult:
103
+ """Perform experience search within a space.
104
+
105
+ This is the most advanced search option that can operate in two modes:
106
+ - fast: Quick semantic search (default)
107
+ - agentic: Iterative search with AI-powered refinement
108
+
109
+ Args:
110
+ space_id: The UUID of the space.
111
+ query: The search query string.
112
+ limit: Maximum number of results to return (1-50, default 10).
113
+ mode: Search mode, either "fast" or "agentic" (default "fast").
114
+ semantic_threshold: Cosine distance threshold (0=identical, 2=opposite).
115
+ max_iterations: Maximum iterations for agentic search (1-100, default 16).
116
+
117
+ Returns:
118
+ SpaceSearchResult containing cited blocks and optional final answer.
119
+ """
120
+ params = build_params(
121
+ query=query,
122
+ limit=limit,
123
+ mode=mode,
124
+ semantic_threshold=semantic_threshold,
125
+ max_iterations=max_iterations,
126
+ )
127
+ data = self._requester.request(
128
+ "GET", f"/space/{space_id}/experience_search", params=params or None
129
+ )
130
+ return SpaceSearchResult.model_validate(data)
131
+
132
+ def semantic_global(
133
+ self,
134
+ space_id: str,
135
+ *,
136
+ query: str,
137
+ limit: int | None = None,
138
+ threshold: float | None = None,
139
+ ) -> List[SearchResultBlockItem]:
140
+ """Perform semantic global (glob) search for page/folder titles.
141
+
142
+ Searches specifically for page/folder titles using semantic similarity,
143
+ similar to a semantic version of the glob command.
144
+
145
+ Args:
146
+ space_id: The UUID of the space.
147
+ query: Search query for page/folder titles.
148
+ limit: Maximum number of results to return (1-50, default 10).
149
+ threshold: Cosine distance threshold (0=identical, 2=opposite).
150
+
151
+ Returns:
152
+ List of SearchResultBlockItem objects matching the query.
153
+ """
154
+ params = build_params(query=query, limit=limit, threshold=threshold)
155
+ data = self._requester.request(
156
+ "GET", f"/space/{space_id}/semantic_global", params=params or None
157
+ )
158
+ return [SearchResultBlockItem.model_validate(item) for item in data]
159
+
160
+ def semantic_grep(
161
+ self,
162
+ space_id: str,
163
+ *,
164
+ query: str,
165
+ limit: int | None = None,
166
+ threshold: float | None = None,
167
+ ) -> List[SearchResultBlockItem]:
168
+ """Perform semantic grep search for content blocks.
169
+
170
+ Searches through content blocks (actual text content) using semantic similarity,
171
+ similar to a semantic version of the grep command.
172
+
173
+ Args:
174
+ space_id: The UUID of the space.
175
+ query: Search query for content blocks.
176
+ limit: Maximum number of results to return (1-50, default 10).
177
+ threshold: Cosine distance threshold (0=identical, 2=opposite).
178
+
179
+ Returns:
180
+ List of SearchResultBlockItem objects matching the query.
181
+ """
182
+ params = build_params(query=query, limit=limit, threshold=threshold)
183
+ data = self._requester.request(
184
+ "GET", f"/space/{space_id}/semantic_grep", params=params or None
185
+ )
186
+ return [SearchResultBlockItem.model_validate(item) for item in data]
@@ -23,7 +23,9 @@ from .session import (
23
23
  from .block import Block
24
24
  from .space import (
25
25
  ListSpacesOutput,
26
+ SearchResultBlockItem,
26
27
  Space,
28
+ SpaceSearchResult,
27
29
  )
28
30
 
29
31
  __all__ = [
@@ -47,8 +49,9 @@ __all__ = [
47
49
  "Task",
48
50
  # Space types
49
51
  "ListSpacesOutput",
52
+ "SearchResultBlockItem",
50
53
  "Space",
54
+ "SpaceSearchResult",
51
55
  # Block types
52
56
  "Block",
53
57
  ]
54
-
@@ -53,7 +53,9 @@ class Session(BaseModel):
53
53
  id: str = Field(..., description="Session UUID")
54
54
  project_id: str = Field(..., description="Project UUID")
55
55
  space_id: str | None = Field(None, description="Space UUID, optional")
56
- configs: dict[str, Any] = Field(..., description="Session configuration dictionary")
56
+ configs: dict[str, Any] | None = Field(
57
+ None, description="Session configuration dictionary"
58
+ )
57
59
  created_at: str = Field(..., description="ISO 8601 formatted creation timestamp")
58
60
  updated_at: str = Field(..., description="ISO 8601 formatted update timestamp")
59
61
 
@@ -120,4 +122,3 @@ class GetTasksOutput(BaseModel):
120
122
  items: list[Task] = Field(..., description="List of tasks")
121
123
  next_cursor: str | None = Field(None, description="Cursor for pagination")
122
124
  has_more: bool = Field(..., description="Whether there are more items")
123
-
@@ -0,0 +1,46 @@
1
+ """Type definitions for space resources."""
2
+
3
+ from typing import Any
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class Space(BaseModel):
9
+ """Space model representing a space resource."""
10
+
11
+ id: str = Field(..., description="Space UUID")
12
+ project_id: str = Field(..., description="Project UUID")
13
+ configs: dict[str, Any] | None = Field(
14
+ None, description="Space configuration dictionary"
15
+ )
16
+ created_at: str = Field(..., description="ISO 8601 formatted creation timestamp")
17
+ updated_at: str = Field(..., description="ISO 8601 formatted update timestamp")
18
+
19
+
20
+ class ListSpacesOutput(BaseModel):
21
+ """Response model for listing spaces."""
22
+
23
+ items: list[Space] = Field(..., description="List of spaces")
24
+ next_cursor: str | None = Field(None, description="Cursor for pagination")
25
+ has_more: bool = Field(..., description="Whether there are more items")
26
+
27
+
28
+ class SearchResultBlockItem(BaseModel):
29
+ """Search result block item model."""
30
+
31
+ block_id: str = Field(..., description="Block UUID")
32
+ title: str = Field(..., description="Block title")
33
+ type: str = Field(..., description="Block type")
34
+ props: dict[str, Any] = Field(..., description="Block properties")
35
+ distance: float | None = Field(
36
+ None, description="Cosine distance (0=identical, 2=opposite)"
37
+ )
38
+
39
+
40
+ class SpaceSearchResult(BaseModel):
41
+ """Experience search result model."""
42
+
43
+ cited_blocks: list[SearchResultBlockItem] = Field(
44
+ ..., description="List of cited blocks"
45
+ )
46
+ final_answer: str | None = Field(None, description="AI-generated final answer")
@@ -1,78 +0,0 @@
1
- ## acontext client for python
2
-
3
- Python SDK for interacting with the Acontext REST API.
4
-
5
- ### Installation
6
-
7
- ```bash
8
- pip install acontext
9
- ```
10
-
11
- > Requires Python 3.10 or newer.
12
-
13
- ### Quickstart
14
-
15
- ```python
16
- from acontext import AcontextClient, MessagePart
17
-
18
- with AcontextClient(api_key="sk_project_token") as client:
19
- # List spaces for the authenticated project
20
- spaces = client.spaces.list()
21
-
22
- # Create a session bound to the first space
23
- session = client.sessions.create(space_id=spaces[0]["id"])
24
-
25
- # Send a text message to the session
26
- client.sessions.send_message(
27
- session["id"],
28
- role="user",
29
- parts=[MessagePart.text_part("Hello from Python!")],
30
- )
31
- ```
32
-
33
- See the inline docstrings for the full list of helpers covering sessions, spaces, disks, and artifact uploads.
34
-
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/",
53
- meta={"source": "readme-demo"},
54
- )
55
- finally:
56
- client.close()
57
- ```
58
-
59
- ### Working with blocks
60
-
61
- ```python
62
- from acontext import AcontextClient
63
-
64
- client = AcontextClient(api_key="sk_project_token")
65
-
66
- space = client.spaces.create()
67
- try:
68
- page = client.blocks.create(space["id"], block_type="page", title="Kick-off Notes")
69
- client.blocks.create(
70
- space["id"],
71
- parent_id=page["id"],
72
- block_type="text",
73
- title="First block",
74
- props={"text": "Plan the sprint goals"},
75
- )
76
- finally:
77
- client.close()
78
- ```
@@ -1,90 +0,0 @@
1
- """
2
- Spaces endpoints (async).
3
- """
4
-
5
- from collections.abc import Mapping
6
- from typing import Any
7
-
8
- from .._utils import build_params
9
- from ..client_types import AsyncRequesterProtocol
10
- from ..types.space import (
11
- ListSpacesOutput,
12
- Space,
13
- )
14
-
15
-
16
- class AsyncSpacesAPI:
17
- def __init__(self, requester: AsyncRequesterProtocol) -> None:
18
- self._requester = requester
19
-
20
- async def list(
21
- self,
22
- *,
23
- limit: int | None = None,
24
- cursor: str | None = None,
25
- time_desc: bool | None = None,
26
- ) -> ListSpacesOutput:
27
- """List all spaces in the project.
28
-
29
- Args:
30
- limit: Maximum number of spaces to return. Defaults to None.
31
- cursor: Cursor for pagination. Defaults to None.
32
- time_desc: Order by created_at descending if True, ascending if False. Defaults to None.
33
-
34
- Returns:
35
- ListSpacesOutput containing the list of spaces and pagination information.
36
- """
37
- params = build_params(limit=limit, cursor=cursor, time_desc=time_desc)
38
- data = await self._requester.request("GET", "/space", params=params or None)
39
- return ListSpacesOutput.model_validate(data)
40
-
41
- async def create(self, *, configs: Mapping[str, Any] | None = None) -> Space:
42
- """Create a new space.
43
-
44
- Args:
45
- configs: Optional space configuration dictionary. Defaults to None.
46
-
47
- Returns:
48
- The created Space object.
49
- """
50
- payload: dict[str, Any] = {}
51
- if configs is not None:
52
- payload["configs"] = configs
53
- data = await self._requester.request("POST", "/space", json_data=payload)
54
- return Space.model_validate(data)
55
-
56
- async def delete(self, space_id: str) -> None:
57
- """Delete a space by its ID.
58
-
59
- Args:
60
- space_id: The UUID of the space to delete.
61
- """
62
- await self._requester.request("DELETE", f"/space/{space_id}")
63
-
64
- async def update_configs(
65
- self,
66
- space_id: str,
67
- *,
68
- configs: Mapping[str, Any],
69
- ) -> None:
70
- """Update space configurations.
71
-
72
- Args:
73
- space_id: The UUID of the space.
74
- configs: Space configuration dictionary.
75
- """
76
- payload = {"configs": configs}
77
- await self._requester.request("PUT", f"/space/{space_id}/configs", json_data=payload)
78
-
79
- async def get_configs(self, space_id: str) -> Space:
80
- """Get space configurations.
81
-
82
- Args:
83
- space_id: The UUID of the space.
84
-
85
- Returns:
86
- Space object containing the configurations.
87
- """
88
- data = await self._requester.request("GET", f"/space/{space_id}/configs")
89
- return Space.model_validate(data)
90
-
@@ -1,89 +0,0 @@
1
- """
2
- Spaces endpoints.
3
- """
4
-
5
- from collections.abc import Mapping
6
- from typing import Any
7
-
8
- from .._utils import build_params
9
- from ..client_types import RequesterProtocol
10
- from ..types.space import (
11
- ListSpacesOutput,
12
- Space,
13
- )
14
-
15
-
16
- class SpacesAPI:
17
- def __init__(self, requester: RequesterProtocol) -> None:
18
- self._requester = requester
19
-
20
- def list(
21
- self,
22
- *,
23
- limit: int | None = None,
24
- cursor: str | None = None,
25
- time_desc: bool | None = None,
26
- ) -> ListSpacesOutput:
27
- """List all spaces in the project.
28
-
29
- Args:
30
- limit: Maximum number of spaces to return. Defaults to None.
31
- cursor: Cursor for pagination. Defaults to None.
32
- time_desc: Order by created_at descending if True, ascending if False. Defaults to None.
33
-
34
- Returns:
35
- ListSpacesOutput containing the list of spaces and pagination information.
36
- """
37
- params = build_params(limit=limit, cursor=cursor, time_desc=time_desc)
38
- data = self._requester.request("GET", "/space", params=params or None)
39
- return ListSpacesOutput.model_validate(data)
40
-
41
- def create(self, *, configs: Mapping[str, Any] | None = None) -> Space:
42
- """Create a new space.
43
-
44
- Args:
45
- configs: Optional space configuration dictionary. Defaults to None.
46
-
47
- Returns:
48
- The created Space object.
49
- """
50
- payload: dict[str, Any] = {}
51
- if configs is not None:
52
- payload["configs"] = configs
53
- data = self._requester.request("POST", "/space", json_data=payload)
54
- return Space.model_validate(data)
55
-
56
- def delete(self, space_id: str) -> None:
57
- """Delete a space by its ID.
58
-
59
- Args:
60
- space_id: The UUID of the space to delete.
61
- """
62
- self._requester.request("DELETE", f"/space/{space_id}")
63
-
64
- def update_configs(
65
- self,
66
- space_id: str,
67
- *,
68
- configs: Mapping[str, Any],
69
- ) -> None:
70
- """Update space configurations.
71
-
72
- Args:
73
- space_id: The UUID of the space.
74
- configs: Space configuration dictionary.
75
- """
76
- payload = {"configs": configs}
77
- self._requester.request("PUT", f"/space/{space_id}/configs", json_data=payload)
78
-
79
- def get_configs(self, space_id: str) -> Space:
80
- """Get space configurations.
81
-
82
- Args:
83
- space_id: The UUID of the space.
84
-
85
- Returns:
86
- Space object containing the configurations.
87
- """
88
- data = self._requester.request("GET", f"/space/{space_id}/configs")
89
- return Space.model_validate(data)
@@ -1,24 +0,0 @@
1
- """Type definitions for space resources."""
2
-
3
- from typing import Any
4
-
5
- from pydantic import BaseModel, Field
6
-
7
-
8
- class Space(BaseModel):
9
- """Space model representing a space resource."""
10
-
11
- id: str = Field(..., description="Space UUID")
12
- project_id: str = Field(..., description="Project UUID")
13
- configs: dict[str, Any] = Field(..., description="Space configuration dictionary")
14
- created_at: str = Field(..., description="ISO 8601 formatted creation timestamp")
15
- updated_at: str = Field(..., description="ISO 8601 formatted update timestamp")
16
-
17
-
18
- class ListSpacesOutput(BaseModel):
19
- """Response model for listing spaces."""
20
-
21
- items: list[Space] = Field(..., description="List of spaces")
22
- next_cursor: str | None = Field(None, description="Cursor for pagination")
23
- has_more: bool = Field(..., description="Whether there are more items")
24
-