magickmind 0.1.1__py3-none-any.whl
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.
- magick_mind/__init__.py +39 -0
- magick_mind/auth/__init__.py +9 -0
- magick_mind/auth/base.py +46 -0
- magick_mind/auth/email_password.py +268 -0
- magick_mind/client.py +188 -0
- magick_mind/config.py +28 -0
- magick_mind/exceptions.py +107 -0
- magick_mind/http/__init__.py +5 -0
- magick_mind/http/client.py +313 -0
- magick_mind/models/__init__.py +17 -0
- magick_mind/models/auth.py +30 -0
- magick_mind/models/common.py +32 -0
- magick_mind/models/errors.py +73 -0
- magick_mind/models/v1/__init__.py +83 -0
- magick_mind/models/v1/api_keys.py +115 -0
- magick_mind/models/v1/artifact.py +151 -0
- magick_mind/models/v1/chat.py +104 -0
- magick_mind/models/v1/corpus.py +82 -0
- magick_mind/models/v1/end_user.py +75 -0
- magick_mind/models/v1/history.py +94 -0
- magick_mind/models/v1/mindspace.py +130 -0
- magick_mind/models/v1/model.py +25 -0
- magick_mind/models/v1/project.py +73 -0
- magick_mind/realtime/__init__.py +5 -0
- magick_mind/realtime/client.py +202 -0
- magick_mind/realtime/handler.py +122 -0
- magick_mind/resources/README.md +201 -0
- magick_mind/resources/__init__.py +42 -0
- magick_mind/resources/base.py +31 -0
- magick_mind/resources/v1/__init__.py +19 -0
- magick_mind/resources/v1/api_keys.py +181 -0
- magick_mind/resources/v1/artifact.py +287 -0
- magick_mind/resources/v1/chat.py +120 -0
- magick_mind/resources/v1/corpus.py +156 -0
- magick_mind/resources/v1/end_user.py +181 -0
- magick_mind/resources/v1/history.py +88 -0
- magick_mind/resources/v1/mindspace.py +331 -0
- magick_mind/resources/v1/model.py +19 -0
- magick_mind/resources/v1/project.py +155 -0
- magick_mind/routes.py +76 -0
- magickmind-0.1.1.dist-info/METADATA +593 -0
- magickmind-0.1.1.dist-info/RECORD +43 -0
- magickmind-0.1.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Corpus resource for Magick Mind SDK v1 API.
|
|
3
|
+
|
|
4
|
+
Provides methods for managing corpus (knowledge base) resources.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING, Optional
|
|
10
|
+
|
|
11
|
+
from magick_mind.models.v1.corpus import (
|
|
12
|
+
Corpus,
|
|
13
|
+
CreateCorpusRequest,
|
|
14
|
+
ListCorpusResponse,
|
|
15
|
+
UpdateCorpusRequest,
|
|
16
|
+
)
|
|
17
|
+
from magick_mind.routes import Routes
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
import httpx
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CorpusResourceV1:
|
|
24
|
+
"""Resource client for corpus operations."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, http_client: httpx.Client):
|
|
27
|
+
"""
|
|
28
|
+
Initialize the corpus resource.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
http_client: Authenticated httpx client
|
|
32
|
+
"""
|
|
33
|
+
self.http = http_client
|
|
34
|
+
|
|
35
|
+
def create(
|
|
36
|
+
self,
|
|
37
|
+
name: str,
|
|
38
|
+
description: str,
|
|
39
|
+
artifact_ids: Optional[list[str]] = None,
|
|
40
|
+
) -> Corpus:
|
|
41
|
+
"""
|
|
42
|
+
Create a new corpus.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
name: Corpus name
|
|
46
|
+
description: Corpus description
|
|
47
|
+
artifact_ids: Optional list of artifact IDs to include
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Corpus object
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
httpx.HTTPStatusError: If the request fails
|
|
54
|
+
"""
|
|
55
|
+
payload = CreateCorpusRequest(
|
|
56
|
+
name=name,
|
|
57
|
+
description=description,
|
|
58
|
+
artifact_ids=artifact_ids or [],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
resp = self.http.post(Routes.CORPUS, json=payload.model_dump())
|
|
62
|
+
resp.raise_for_status()
|
|
63
|
+
|
|
64
|
+
return Corpus(**resp.json())
|
|
65
|
+
|
|
66
|
+
def get(self, corpus_id: str) -> Corpus:
|
|
67
|
+
"""
|
|
68
|
+
Get a corpus by ID.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
corpus_id: The corpus ID
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Corpus object
|
|
75
|
+
|
|
76
|
+
Raises:
|
|
77
|
+
httpx.HTTPStatusError: If the request fails
|
|
78
|
+
"""
|
|
79
|
+
resp = self.http.get(Routes.corpus(corpus_id))
|
|
80
|
+
resp.raise_for_status()
|
|
81
|
+
|
|
82
|
+
return Corpus(**resp.json())
|
|
83
|
+
|
|
84
|
+
def list(self, user_id: Optional[str] = None) -> ListCorpusResponse:
|
|
85
|
+
"""
|
|
86
|
+
List all corpus, optionally filtered by user_id.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
user_id: Optional user ID to filter by
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
ListCorpusResponse with list of corpus
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
httpx.HTTPStatusError: If the request fails
|
|
96
|
+
"""
|
|
97
|
+
params = {}
|
|
98
|
+
if user_id:
|
|
99
|
+
params["user_id"] = user_id
|
|
100
|
+
|
|
101
|
+
resp = self.http.get(Routes.CORPUS, params=params)
|
|
102
|
+
resp.raise_for_status()
|
|
103
|
+
|
|
104
|
+
return ListCorpusResponse(**resp.json())
|
|
105
|
+
|
|
106
|
+
def update(
|
|
107
|
+
self,
|
|
108
|
+
corpus_id: str,
|
|
109
|
+
name: str,
|
|
110
|
+
description: str,
|
|
111
|
+
artifact_ids: list[str],
|
|
112
|
+
) -> Corpus:
|
|
113
|
+
"""
|
|
114
|
+
Update an existing corpus.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
corpus_id: The corpus ID to update
|
|
118
|
+
name: New corpus name
|
|
119
|
+
description: New corpus description
|
|
120
|
+
artifact_ids: New list of artifact IDs
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Corpus object
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
httpx.HTTPStatusError: If the request fails
|
|
127
|
+
"""
|
|
128
|
+
payload = UpdateCorpusRequest(
|
|
129
|
+
name=name,
|
|
130
|
+
description=description,
|
|
131
|
+
artifact_ids=artifact_ids,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
resp = self.http.put(Routes.corpus(corpus_id), json=payload.model_dump())
|
|
135
|
+
resp.raise_for_status()
|
|
136
|
+
|
|
137
|
+
return Corpus(**resp.json())
|
|
138
|
+
|
|
139
|
+
def delete(self, corpus_id: str) -> None:
|
|
140
|
+
"""
|
|
141
|
+
Delete a corpus.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
corpus_id: The corpus ID to delete
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
None (Bifrost returns 204 No Content)
|
|
148
|
+
|
|
149
|
+
Example:
|
|
150
|
+
client.v1.corpus.delete(corpus_id="corpus-123")
|
|
151
|
+
print("Corpus deleted successfully")
|
|
152
|
+
|
|
153
|
+
Raises:
|
|
154
|
+
httpx.HTTPStatusError: If request fails
|
|
155
|
+
"""
|
|
156
|
+
self.http.delete(Routes.corpus(corpus_id))
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""
|
|
2
|
+
End user resource for Magick Mind SDK v1 API.
|
|
3
|
+
|
|
4
|
+
Provides methods for CRUD operations on end users in the agentic SaaS backend.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
from magick_mind.models.v1.end_user import (
|
|
13
|
+
CreateEndUserRequest,
|
|
14
|
+
EndUser,
|
|
15
|
+
QueryEndUserResponse,
|
|
16
|
+
UpdateEndUserRequest,
|
|
17
|
+
)
|
|
18
|
+
from magick_mind.resources.base import BaseResource
|
|
19
|
+
from magick_mind.routes import Routes
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EndUserResourceV1(BaseResource):
|
|
23
|
+
"""
|
|
24
|
+
End user resource for managing end users in agentic SaaS applications.
|
|
25
|
+
|
|
26
|
+
End users represent the actual users of applications built on the bifrost
|
|
27
|
+
platform in a multi-tenant architecture.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def create(
|
|
31
|
+
self,
|
|
32
|
+
name: str,
|
|
33
|
+
tenant_id: str,
|
|
34
|
+
actor_id: str,
|
|
35
|
+
external_id: Optional[str] = None,
|
|
36
|
+
) -> EndUser:
|
|
37
|
+
"""
|
|
38
|
+
Create a new end user.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
name: End user name (required)
|
|
42
|
+
tenant_id: Tenant ID this end user belongs to (required)
|
|
43
|
+
actor_id: Actor ID performing the action (required)
|
|
44
|
+
external_id: Optional external ID for mapping to external systems
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Created EndUser object
|
|
48
|
+
|
|
49
|
+
Example:
|
|
50
|
+
end_user = client.v1.end_user.create(
|
|
51
|
+
name="John Doe",
|
|
52
|
+
tenant_id="tenant-123",
|
|
53
|
+
actor_id="user-456",
|
|
54
|
+
external_id="ext-789"
|
|
55
|
+
)
|
|
56
|
+
print(f"Created end user: {end_user.id}")
|
|
57
|
+
"""
|
|
58
|
+
request = CreateEndUserRequest(
|
|
59
|
+
name=name,
|
|
60
|
+
tenant_id=tenant_id,
|
|
61
|
+
actor_id=actor_id,
|
|
62
|
+
external_id=external_id,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
response = self._http.post(Routes.END_USERS, json=request.model_dump())
|
|
66
|
+
return EndUser(**response)
|
|
67
|
+
|
|
68
|
+
def get(self, end_user_id: str) -> EndUser:
|
|
69
|
+
"""
|
|
70
|
+
Get an end user by ID.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
end_user_id: The end user ID to retrieve
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
EndUser object
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
end_user = client.v1.end_user.get(end_user_id="user-123")
|
|
80
|
+
print(f"End user name: {end_user.name}")
|
|
81
|
+
"""
|
|
82
|
+
response = self._http.get(Routes.end_user(end_user_id))
|
|
83
|
+
return EndUser(**response)
|
|
84
|
+
|
|
85
|
+
def query(
|
|
86
|
+
self,
|
|
87
|
+
name: Optional[str] = None,
|
|
88
|
+
external_id: Optional[str] = None,
|
|
89
|
+
tenant_id: Optional[str] = None,
|
|
90
|
+
actor_id: Optional[str] = None,
|
|
91
|
+
) -> list[EndUser]:
|
|
92
|
+
"""
|
|
93
|
+
Query end users with optional filters.
|
|
94
|
+
|
|
95
|
+
All parameters are optional. If no filters are provided, returns all
|
|
96
|
+
accessible end users.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
name: Filter by end user name (optional)
|
|
100
|
+
external_id: Filter by external ID (optional)
|
|
101
|
+
tenant_id: Filter by tenant ID (optional)
|
|
102
|
+
actor_id: Filter by actor ID (optional)
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
List of EndUser objects matching the query
|
|
106
|
+
|
|
107
|
+
Example:
|
|
108
|
+
# Get all end users for a tenant
|
|
109
|
+
end_users = client.v1.end_user.query(tenant_id="tenant-123")
|
|
110
|
+
for user in end_users:
|
|
111
|
+
print(f"- {user.name}")
|
|
112
|
+
|
|
113
|
+
# Search by external ID
|
|
114
|
+
user = client.v1.end_user.query(external_id="ext-789")
|
|
115
|
+
"""
|
|
116
|
+
params = {}
|
|
117
|
+
if name is not None:
|
|
118
|
+
params["name"] = name
|
|
119
|
+
if external_id is not None:
|
|
120
|
+
params["external_id"] = external_id
|
|
121
|
+
if tenant_id is not None:
|
|
122
|
+
params["tenant_id"] = tenant_id
|
|
123
|
+
if actor_id is not None:
|
|
124
|
+
params["actor_id"] = actor_id
|
|
125
|
+
|
|
126
|
+
response = self._http.get(Routes.END_USERS, params=params)
|
|
127
|
+
query_response = QueryEndUserResponse(**response)
|
|
128
|
+
return query_response.data
|
|
129
|
+
|
|
130
|
+
def update(
|
|
131
|
+
self,
|
|
132
|
+
end_user_id: str,
|
|
133
|
+
name: Optional[str] = None,
|
|
134
|
+
external_id: Optional[str] = None,
|
|
135
|
+
tenant_id: Optional[str] = None,
|
|
136
|
+
) -> EndUser:
|
|
137
|
+
"""
|
|
138
|
+
Update an existing end user.
|
|
139
|
+
|
|
140
|
+
All update fields are optional. Only provided fields will be updated.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
end_user_id: The end user ID to update
|
|
144
|
+
name: New end user name (optional)
|
|
145
|
+
external_id: New external ID (optional)
|
|
146
|
+
tenant_id: New tenant ID (optional)
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Updated EndUser object
|
|
150
|
+
|
|
151
|
+
Example:
|
|
152
|
+
updated = client.v1.end_user.update(
|
|
153
|
+
end_user_id="user-123",
|
|
154
|
+
name="Jane Doe",
|
|
155
|
+
external_id="new-ext-id"
|
|
156
|
+
)
|
|
157
|
+
print(f"Updated end user: {updated.name}")
|
|
158
|
+
"""
|
|
159
|
+
request = UpdateEndUserRequest(
|
|
160
|
+
name=name,
|
|
161
|
+
external_id=external_id,
|
|
162
|
+
tenant_id=tenant_id,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
response = self._http.put(
|
|
166
|
+
Routes.end_user(end_user_id), json=request.model_dump(exclude_none=True)
|
|
167
|
+
)
|
|
168
|
+
return EndUser(**response)
|
|
169
|
+
|
|
170
|
+
def delete(self, end_user_id: str) -> None:
|
|
171
|
+
"""
|
|
172
|
+
Delete an end user.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
end_user_id: The end user ID to delete
|
|
176
|
+
|
|
177
|
+
Example:
|
|
178
|
+
client.v1.end_user.delete(end_user_id="user-123")
|
|
179
|
+
print("End user deleted successfully")
|
|
180
|
+
"""
|
|
181
|
+
self._http.delete(Routes.end_user(end_user_id))
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
History resource for Magick Mind SDK v1 API.
|
|
3
|
+
|
|
4
|
+
Provides methods to fetch chat history with pagination.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from magick_mind.models.v1.history import HistoryResponse
|
|
10
|
+
from magick_mind.resources.base import BaseResource
|
|
11
|
+
from magick_mind.routes import Routes
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class HistoryResourceV1(BaseResource):
|
|
15
|
+
"""
|
|
16
|
+
History resource for fetching chat messages.
|
|
17
|
+
|
|
18
|
+
Supports three pagination modes:
|
|
19
|
+
1. Latest: Get most recent N messages
|
|
20
|
+
2. Forward: Get messages after a specific message_id
|
|
21
|
+
3. Backward: Get messages before a specific message_id
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def get_messages(
|
|
25
|
+
self,
|
|
26
|
+
mindspace_id: str,
|
|
27
|
+
after_id: Optional[str] = None,
|
|
28
|
+
before_id: Optional[str] = None,
|
|
29
|
+
limit: int = 50,
|
|
30
|
+
) -> HistoryResponse:
|
|
31
|
+
"""
|
|
32
|
+
Fetch chat history with keyset pagination.
|
|
33
|
+
|
|
34
|
+
Three modes based on parameters:
|
|
35
|
+
- Latest: Just mindspace_id + limit (most recent messages)
|
|
36
|
+
- Forward: mindspace_id + after_id + limit (messages after a point)
|
|
37
|
+
- Backward: mindspace_id + before_id + limit (messages before a point)
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
mindspace_id: Mindspace to fetch messages from
|
|
41
|
+
after_id: Get messages after this message ID (forward pagination)
|
|
42
|
+
before_id: Get messages before this message ID (backward pagination)
|
|
43
|
+
limit: Maximum number of messages to return (default: 50)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
HistoryResponse with messages and pagination cursors
|
|
47
|
+
|
|
48
|
+
Raises:
|
|
49
|
+
ValueError: If both after_id and before_id are provided
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
# Get latest 50 messages
|
|
53
|
+
history = client.v1.history.get_messages(mindspace_id="mind-123")
|
|
54
|
+
|
|
55
|
+
# Forward pagination (newer messages)
|
|
56
|
+
more = client.v1.history.get_messages(
|
|
57
|
+
mindspace_id="mind-123",
|
|
58
|
+
after_id=history.last_id,
|
|
59
|
+
limit=50
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Backward pagination (older messages)
|
|
63
|
+
older = client.v1.history.get_messages(
|
|
64
|
+
mindspace_id="mind-123",
|
|
65
|
+
before_id=history.chat_histories[0].id,
|
|
66
|
+
limit=50
|
|
67
|
+
)
|
|
68
|
+
"""
|
|
69
|
+
# Validate mutually exclusive parameters
|
|
70
|
+
if after_id and before_id:
|
|
71
|
+
raise ValueError("Cannot specify both after_id and before_id")
|
|
72
|
+
|
|
73
|
+
# Build query parameters
|
|
74
|
+
params = {
|
|
75
|
+
"mindspace_id": mindspace_id,
|
|
76
|
+
"limit": limit,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if after_id:
|
|
80
|
+
params["after_id"] = after_id
|
|
81
|
+
if before_id:
|
|
82
|
+
params["before_id"] = before_id
|
|
83
|
+
|
|
84
|
+
# Make request
|
|
85
|
+
response = self._http.get(Routes.HISTORY_MESSAGES, params=params)
|
|
86
|
+
|
|
87
|
+
# Parse and return
|
|
88
|
+
return HistoryResponse(**response.json())
|