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.
Files changed (43) hide show
  1. magick_mind/__init__.py +39 -0
  2. magick_mind/auth/__init__.py +9 -0
  3. magick_mind/auth/base.py +46 -0
  4. magick_mind/auth/email_password.py +268 -0
  5. magick_mind/client.py +188 -0
  6. magick_mind/config.py +28 -0
  7. magick_mind/exceptions.py +107 -0
  8. magick_mind/http/__init__.py +5 -0
  9. magick_mind/http/client.py +313 -0
  10. magick_mind/models/__init__.py +17 -0
  11. magick_mind/models/auth.py +30 -0
  12. magick_mind/models/common.py +32 -0
  13. magick_mind/models/errors.py +73 -0
  14. magick_mind/models/v1/__init__.py +83 -0
  15. magick_mind/models/v1/api_keys.py +115 -0
  16. magick_mind/models/v1/artifact.py +151 -0
  17. magick_mind/models/v1/chat.py +104 -0
  18. magick_mind/models/v1/corpus.py +82 -0
  19. magick_mind/models/v1/end_user.py +75 -0
  20. magick_mind/models/v1/history.py +94 -0
  21. magick_mind/models/v1/mindspace.py +130 -0
  22. magick_mind/models/v1/model.py +25 -0
  23. magick_mind/models/v1/project.py +73 -0
  24. magick_mind/realtime/__init__.py +5 -0
  25. magick_mind/realtime/client.py +202 -0
  26. magick_mind/realtime/handler.py +122 -0
  27. magick_mind/resources/README.md +201 -0
  28. magick_mind/resources/__init__.py +42 -0
  29. magick_mind/resources/base.py +31 -0
  30. magick_mind/resources/v1/__init__.py +19 -0
  31. magick_mind/resources/v1/api_keys.py +181 -0
  32. magick_mind/resources/v1/artifact.py +287 -0
  33. magick_mind/resources/v1/chat.py +120 -0
  34. magick_mind/resources/v1/corpus.py +156 -0
  35. magick_mind/resources/v1/end_user.py +181 -0
  36. magick_mind/resources/v1/history.py +88 -0
  37. magick_mind/resources/v1/mindspace.py +331 -0
  38. magick_mind/resources/v1/model.py +19 -0
  39. magick_mind/resources/v1/project.py +155 -0
  40. magick_mind/routes.py +76 -0
  41. magickmind-0.1.1.dist-info/METADATA +593 -0
  42. magickmind-0.1.1.dist-info/RECORD +43 -0
  43. 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())