crewdeck 0.1.0__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.
crewdeck-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CrewDeck
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,240 @@
1
+ Metadata-Version: 2.4
2
+ Name: crewdeck
3
+ Version: 0.1.0
4
+ Summary: Python SDK for CrewDeck - AI agent management dashboard
5
+ Project-URL: Homepage, https://crewdeck.dev
6
+ Project-URL: Documentation, https://docs.crewdeck.dev
7
+ Project-URL: Repository, https://github.com/crewdeck/crewdeck-python
8
+ Author-email: CrewDeck <hello@crewdeck.dev>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,ai,autogen,crewai,dashboard,langchain,management
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.8
23
+ Requires-Dist: httpx>=0.24.0
24
+ Provides-Extra: async
25
+ Requires-Dist: httpx[http2]>=0.24.0; extra == 'async'
26
+ Provides-Extra: dev
27
+ Requires-Dist: black>=23.0.0; extra == 'dev'
28
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
29
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # CrewDeck Python SDK
34
+
35
+ Official Python SDK for [CrewDeck](https://crewdeck.dev) — the AI agent management dashboard.
36
+
37
+ Manage your AI crew like a real team. Assign tasks, track progress, review outputs, approve results.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install crewdeck
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```python
48
+ from crewdeck import CrewDeck
49
+
50
+ # Initialize with your API key
51
+ deck = CrewDeck(api_key="your-api-key")
52
+
53
+ # Create a task
54
+ task = deck.tasks.create(
55
+ title="Analyze Q4 sales data",
56
+ description="Process and summarize the quarterly sales report",
57
+ priority="high",
58
+ assignees=["JARVIS"]
59
+ )
60
+
61
+ # Update agent status
62
+ deck.agents.set_working("JARVIS")
63
+
64
+ # Send progress updates
65
+ deck.events.message("Starting data analysis...", agent_name="JARVIS")
66
+
67
+ # Complete the task with output
68
+ deck.tasks.complete(task.id, output="Analysis complete. Revenue up 15% YoY.")
69
+ ```
70
+
71
+ ## API Reference
72
+
73
+ ### Tasks
74
+
75
+ ```python
76
+ # Create a task
77
+ task = deck.tasks.create(
78
+ title="Task title",
79
+ description="Task description",
80
+ status="INBOX", # INBOX, ASSIGNED, IN PROGRESS, REVIEW, DONE
81
+ priority="medium", # low, medium, high, critical
82
+ assignees=["JARVIS", "FRIDAY"],
83
+ tags=["data", "analysis"]
84
+ )
85
+
86
+ # List tasks
87
+ tasks = deck.tasks.list()
88
+ tasks = deck.tasks.list(status="IN PROGRESS", limit=50)
89
+
90
+ # Update a task
91
+ deck.tasks.update(
92
+ task_id="task-id",
93
+ status="IN PROGRESS",
94
+ output="Working on it..."
95
+ )
96
+
97
+ # Move task to a status
98
+ deck.tasks.move(task_id, "REVIEW")
99
+
100
+ # Complete a task
101
+ deck.tasks.complete(task_id, output="Done!")
102
+ ```
103
+
104
+ ### Agents
105
+
106
+ ```python
107
+ # Create an agent
108
+ agent = deck.agents.create(
109
+ name="JARVIS",
110
+ avatar="🤖",
111
+ role="AI Assistant",
112
+ level="LEAD", # standard, INT, LEAD, SPC
113
+ status="idle"
114
+ )
115
+
116
+ # List agents
117
+ agents = deck.agents.list()
118
+
119
+ # Update agent status
120
+ deck.agents.update_status("JARVIS", "working")
121
+
122
+ # Convenience methods
123
+ deck.agents.set_working("JARVIS")
124
+ deck.agents.set_idle("JARVIS")
125
+ deck.agents.set_offline("JARVIS")
126
+ ```
127
+
128
+ ### Events
129
+
130
+ ```python
131
+ # Send a message to the live feed
132
+ deck.events.message("Starting work...", agent_name="JARVIS")
133
+
134
+ # Send a log event
135
+ deck.events.log(
136
+ message="Processing file",
137
+ agent_name="JARVIS",
138
+ metadata={"file": "data.csv", "rows": 1000}
139
+ )
140
+
141
+ # Send a custom event
142
+ deck.events.send(
143
+ type="custom",
144
+ agent_name="JARVIS",
145
+ message="Custom event",
146
+ metadata={"key": "value"}
147
+ )
148
+ ```
149
+
150
+ ## Integration Examples
151
+
152
+ ### CrewAI
153
+
154
+ ```python
155
+ from crewai import Agent, Task, Crew
156
+ from crewdeck import CrewDeck
157
+
158
+ deck = CrewDeck(api_key="your-api-key")
159
+
160
+ # Sync CrewAI agent with CrewDeck
161
+ crewai_agent = Agent(
162
+ role="Researcher",
163
+ goal="Research topics",
164
+ backstory="Expert researcher"
165
+ )
166
+
167
+ # Create corresponding agent in CrewDeck
168
+ deck.agents.create(
169
+ name="Researcher",
170
+ avatar="🔬",
171
+ role="Research Agent",
172
+ level="INT"
173
+ )
174
+
175
+ # When starting a task
176
+ def on_task_start(task):
177
+ deck.agents.set_working("Researcher")
178
+ deck.events.message(f"Starting: {task.description}", agent_name="Researcher")
179
+
180
+ # When task completes
181
+ def on_task_complete(task, output):
182
+ deck.events.message(f"Completed: {task.description}", agent_name="Researcher")
183
+ deck.agents.set_idle("Researcher")
184
+ ```
185
+
186
+ ### LangChain
187
+
188
+ ```python
189
+ from langchain.callbacks.base import BaseCallbackHandler
190
+ from crewdeck import CrewDeck
191
+
192
+ class CrewDeckCallback(BaseCallbackHandler):
193
+ def __init__(self, deck: CrewDeck, agent_name: str):
194
+ self.deck = deck
195
+ self.agent_name = agent_name
196
+
197
+ def on_chain_start(self, serialized, inputs, **kwargs):
198
+ self.deck.agents.set_working(self.agent_name)
199
+ self.deck.events.message(f"Processing: {inputs}", agent_name=self.agent_name)
200
+
201
+ def on_chain_end(self, outputs, **kwargs):
202
+ self.deck.events.message(f"Result: {outputs}", agent_name=self.agent_name)
203
+ self.deck.agents.set_idle(self.agent_name)
204
+ ```
205
+
206
+ ## Context Manager
207
+
208
+ ```python
209
+ with CrewDeck(api_key="your-api-key") as deck:
210
+ task = deck.tasks.create(title="My task")
211
+ # Client automatically closes when done
212
+ ```
213
+
214
+ ## Error Handling
215
+
216
+ ```python
217
+ from crewdeck import CrewDeck, AuthenticationError, APIError
218
+
219
+ try:
220
+ deck = CrewDeck(api_key="invalid-key")
221
+ deck.tasks.list()
222
+ except AuthenticationError:
223
+ print("Invalid API key")
224
+ except APIError as e:
225
+ print(f"API error: {e} (status: {e.status_code})")
226
+ ```
227
+
228
+ ## Configuration
229
+
230
+ ```python
231
+ deck = CrewDeck(
232
+ api_key="your-api-key",
233
+ base_url="https://your-convex-deployment.convex.site", # Custom deployment
234
+ timeout=30.0 # Request timeout in seconds
235
+ )
236
+ ```
237
+
238
+ ## License
239
+
240
+ MIT
@@ -0,0 +1,208 @@
1
+ # CrewDeck Python SDK
2
+
3
+ Official Python SDK for [CrewDeck](https://crewdeck.dev) — the AI agent management dashboard.
4
+
5
+ Manage your AI crew like a real team. Assign tasks, track progress, review outputs, approve results.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install crewdeck
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```python
16
+ from crewdeck import CrewDeck
17
+
18
+ # Initialize with your API key
19
+ deck = CrewDeck(api_key="your-api-key")
20
+
21
+ # Create a task
22
+ task = deck.tasks.create(
23
+ title="Analyze Q4 sales data",
24
+ description="Process and summarize the quarterly sales report",
25
+ priority="high",
26
+ assignees=["JARVIS"]
27
+ )
28
+
29
+ # Update agent status
30
+ deck.agents.set_working("JARVIS")
31
+
32
+ # Send progress updates
33
+ deck.events.message("Starting data analysis...", agent_name="JARVIS")
34
+
35
+ # Complete the task with output
36
+ deck.tasks.complete(task.id, output="Analysis complete. Revenue up 15% YoY.")
37
+ ```
38
+
39
+ ## API Reference
40
+
41
+ ### Tasks
42
+
43
+ ```python
44
+ # Create a task
45
+ task = deck.tasks.create(
46
+ title="Task title",
47
+ description="Task description",
48
+ status="INBOX", # INBOX, ASSIGNED, IN PROGRESS, REVIEW, DONE
49
+ priority="medium", # low, medium, high, critical
50
+ assignees=["JARVIS", "FRIDAY"],
51
+ tags=["data", "analysis"]
52
+ )
53
+
54
+ # List tasks
55
+ tasks = deck.tasks.list()
56
+ tasks = deck.tasks.list(status="IN PROGRESS", limit=50)
57
+
58
+ # Update a task
59
+ deck.tasks.update(
60
+ task_id="task-id",
61
+ status="IN PROGRESS",
62
+ output="Working on it..."
63
+ )
64
+
65
+ # Move task to a status
66
+ deck.tasks.move(task_id, "REVIEW")
67
+
68
+ # Complete a task
69
+ deck.tasks.complete(task_id, output="Done!")
70
+ ```
71
+
72
+ ### Agents
73
+
74
+ ```python
75
+ # Create an agent
76
+ agent = deck.agents.create(
77
+ name="JARVIS",
78
+ avatar="🤖",
79
+ role="AI Assistant",
80
+ level="LEAD", # standard, INT, LEAD, SPC
81
+ status="idle"
82
+ )
83
+
84
+ # List agents
85
+ agents = deck.agents.list()
86
+
87
+ # Update agent status
88
+ deck.agents.update_status("JARVIS", "working")
89
+
90
+ # Convenience methods
91
+ deck.agents.set_working("JARVIS")
92
+ deck.agents.set_idle("JARVIS")
93
+ deck.agents.set_offline("JARVIS")
94
+ ```
95
+
96
+ ### Events
97
+
98
+ ```python
99
+ # Send a message to the live feed
100
+ deck.events.message("Starting work...", agent_name="JARVIS")
101
+
102
+ # Send a log event
103
+ deck.events.log(
104
+ message="Processing file",
105
+ agent_name="JARVIS",
106
+ metadata={"file": "data.csv", "rows": 1000}
107
+ )
108
+
109
+ # Send a custom event
110
+ deck.events.send(
111
+ type="custom",
112
+ agent_name="JARVIS",
113
+ message="Custom event",
114
+ metadata={"key": "value"}
115
+ )
116
+ ```
117
+
118
+ ## Integration Examples
119
+
120
+ ### CrewAI
121
+
122
+ ```python
123
+ from crewai import Agent, Task, Crew
124
+ from crewdeck import CrewDeck
125
+
126
+ deck = CrewDeck(api_key="your-api-key")
127
+
128
+ # Sync CrewAI agent with CrewDeck
129
+ crewai_agent = Agent(
130
+ role="Researcher",
131
+ goal="Research topics",
132
+ backstory="Expert researcher"
133
+ )
134
+
135
+ # Create corresponding agent in CrewDeck
136
+ deck.agents.create(
137
+ name="Researcher",
138
+ avatar="🔬",
139
+ role="Research Agent",
140
+ level="INT"
141
+ )
142
+
143
+ # When starting a task
144
+ def on_task_start(task):
145
+ deck.agents.set_working("Researcher")
146
+ deck.events.message(f"Starting: {task.description}", agent_name="Researcher")
147
+
148
+ # When task completes
149
+ def on_task_complete(task, output):
150
+ deck.events.message(f"Completed: {task.description}", agent_name="Researcher")
151
+ deck.agents.set_idle("Researcher")
152
+ ```
153
+
154
+ ### LangChain
155
+
156
+ ```python
157
+ from langchain.callbacks.base import BaseCallbackHandler
158
+ from crewdeck import CrewDeck
159
+
160
+ class CrewDeckCallback(BaseCallbackHandler):
161
+ def __init__(self, deck: CrewDeck, agent_name: str):
162
+ self.deck = deck
163
+ self.agent_name = agent_name
164
+
165
+ def on_chain_start(self, serialized, inputs, **kwargs):
166
+ self.deck.agents.set_working(self.agent_name)
167
+ self.deck.events.message(f"Processing: {inputs}", agent_name=self.agent_name)
168
+
169
+ def on_chain_end(self, outputs, **kwargs):
170
+ self.deck.events.message(f"Result: {outputs}", agent_name=self.agent_name)
171
+ self.deck.agents.set_idle(self.agent_name)
172
+ ```
173
+
174
+ ## Context Manager
175
+
176
+ ```python
177
+ with CrewDeck(api_key="your-api-key") as deck:
178
+ task = deck.tasks.create(title="My task")
179
+ # Client automatically closes when done
180
+ ```
181
+
182
+ ## Error Handling
183
+
184
+ ```python
185
+ from crewdeck import CrewDeck, AuthenticationError, APIError
186
+
187
+ try:
188
+ deck = CrewDeck(api_key="invalid-key")
189
+ deck.tasks.list()
190
+ except AuthenticationError:
191
+ print("Invalid API key")
192
+ except APIError as e:
193
+ print(f"API error: {e} (status: {e.status_code})")
194
+ ```
195
+
196
+ ## Configuration
197
+
198
+ ```python
199
+ deck = CrewDeck(
200
+ api_key="your-api-key",
201
+ base_url="https://your-convex-deployment.convex.site", # Custom deployment
202
+ timeout=30.0 # Request timeout in seconds
203
+ )
204
+ ```
205
+
206
+ ## License
207
+
208
+ MIT
@@ -0,0 +1,43 @@
1
+ """
2
+ CrewDeck Python SDK
3
+
4
+ Manage your AI agent teams with CrewDeck.
5
+
6
+ Quick Start:
7
+ from crewdeck import CrewDeck
8
+
9
+ deck = CrewDeck(api_key="your-api-key")
10
+
11
+ # Create a task
12
+ task = deck.tasks.create(
13
+ title="Analyze data",
14
+ description="Process the Q4 sales data",
15
+ priority="high",
16
+ assignees=["JARVIS"]
17
+ )
18
+
19
+ # Update agent status
20
+ deck.agents.update_status("JARVIS", "working")
21
+
22
+ # Send an event to the live feed
23
+ deck.events.send(
24
+ type="message",
25
+ agent_name="JARVIS",
26
+ message="Starting data analysis..."
27
+ )
28
+ """
29
+
30
+ from .client import CrewDeck
31
+ from .models import Task, Agent, Event
32
+ from .exceptions import CrewDeckError, AuthenticationError, APIError
33
+
34
+ __version__ = "0.1.0"
35
+ __all__ = [
36
+ "CrewDeck",
37
+ "Task",
38
+ "Agent",
39
+ "Event",
40
+ "CrewDeckError",
41
+ "AuthenticationError",
42
+ "APIError",
43
+ ]
@@ -0,0 +1,395 @@
1
+ """CrewDeck Python Client"""
2
+
3
+ from typing import List, Optional, Dict, Any
4
+ import httpx
5
+
6
+ from .models import Task, Agent, Event
7
+ from .exceptions import (
8
+ CrewDeckError,
9
+ AuthenticationError,
10
+ APIError,
11
+ NotFoundError,
12
+ RateLimitError,
13
+ )
14
+
15
+
16
+ DEFAULT_BASE_URL = "https://adept-jellyfish-320.convex.site"
17
+
18
+
19
+ class TasksAPI:
20
+ """Tasks API wrapper"""
21
+
22
+ def __init__(self, client: "CrewDeck"):
23
+ self._client = client
24
+
25
+ def create(
26
+ self,
27
+ title: str,
28
+ description: str = "",
29
+ status: str = "INBOX",
30
+ priority: str = "medium",
31
+ assignees: Optional[List[str]] = None,
32
+ tags: Optional[List[str]] = None,
33
+ ) -> Task:
34
+ """
35
+ Create a new task.
36
+
37
+ Args:
38
+ title: Task title (required)
39
+ description: Task description
40
+ status: Task status (INBOX, ASSIGNED, IN PROGRESS, REVIEW, DONE)
41
+ priority: Priority level (low, medium, high, critical)
42
+ assignees: List of agent names to assign
43
+ tags: List of tags
44
+
45
+ Returns:
46
+ Created Task object
47
+ """
48
+ data = {
49
+ "title": title,
50
+ "description": description,
51
+ "status": status,
52
+ "priority": priority,
53
+ "assignees": assignees or [],
54
+ "tags": tags or [],
55
+ }
56
+ response = self._client._request("POST", "/api/v1/tasks", json=data)
57
+ return Task(
58
+ id=response.get("taskId", ""),
59
+ title=title,
60
+ description=description,
61
+ status=status,
62
+ priority=priority,
63
+ assignees=assignees or [],
64
+ tags=tags or [],
65
+ )
66
+
67
+ def list(
68
+ self,
69
+ status: Optional[str] = None,
70
+ limit: int = 100,
71
+ ) -> List[Task]:
72
+ """
73
+ List tasks.
74
+
75
+ Args:
76
+ status: Filter by status (optional)
77
+ limit: Maximum number of tasks to return
78
+
79
+ Returns:
80
+ List of Task objects
81
+ """
82
+ params = {"limit": str(limit)}
83
+ if status:
84
+ params["status"] = status
85
+ response = self._client._request("GET", "/api/v1/tasks", params=params)
86
+ return [Task.from_dict(t) for t in response.get("tasks", [])]
87
+
88
+ def update(
89
+ self,
90
+ task_id: str,
91
+ title: Optional[str] = None,
92
+ description: Optional[str] = None,
93
+ status: Optional[str] = None,
94
+ priority: Optional[str] = None,
95
+ assignees: Optional[List[str]] = None,
96
+ tags: Optional[List[str]] = None,
97
+ output: Optional[str] = None,
98
+ ) -> None:
99
+ """
100
+ Update a task.
101
+
102
+ Args:
103
+ task_id: Task ID (required)
104
+ title: New title
105
+ description: New description
106
+ status: New status
107
+ priority: New priority
108
+ assignees: New assignees list
109
+ tags: New tags list
110
+ output: Task output/result
111
+ """
112
+ data: Dict[str, Any] = {"id": task_id}
113
+ if title is not None:
114
+ data["title"] = title
115
+ if description is not None:
116
+ data["description"] = description
117
+ if status is not None:
118
+ data["status"] = status
119
+ if priority is not None:
120
+ data["priority"] = priority
121
+ if assignees is not None:
122
+ data["assignees"] = assignees
123
+ if tags is not None:
124
+ data["tags"] = tags
125
+ if output is not None:
126
+ data["output"] = output
127
+ self._client._request("PUT", "/api/v1/tasks", json=data)
128
+
129
+ def move(self, task_id: str, status: str) -> None:
130
+ """
131
+ Move a task to a new status.
132
+
133
+ Args:
134
+ task_id: Task ID
135
+ status: New status (INBOX, ASSIGNED, IN PROGRESS, REVIEW, DONE)
136
+ """
137
+ self.update(task_id, status=status)
138
+
139
+ def complete(self, task_id: str, output: Optional[str] = None) -> None:
140
+ """
141
+ Mark a task as done.
142
+
143
+ Args:
144
+ task_id: Task ID
145
+ output: Optional output/result
146
+ """
147
+ self.update(task_id, status="DONE", output=output)
148
+
149
+
150
+ class AgentsAPI:
151
+ """Agents API wrapper"""
152
+
153
+ def __init__(self, client: "CrewDeck"):
154
+ self._client = client
155
+
156
+ def create(
157
+ self,
158
+ name: str,
159
+ avatar: str = "🤖",
160
+ role: str = "AI Agent",
161
+ level: str = "standard",
162
+ status: str = "idle",
163
+ ) -> Agent:
164
+ """
165
+ Create a new agent.
166
+
167
+ Args:
168
+ name: Agent name (required)
169
+ avatar: Emoji avatar
170
+ role: Agent role description
171
+ level: Agent level (standard, INT, LEAD, SPC)
172
+ status: Initial status (idle, working, offline)
173
+
174
+ Returns:
175
+ Created Agent object
176
+ """
177
+ data = {
178
+ "name": name,
179
+ "avatar": avatar,
180
+ "role": role,
181
+ "level": level,
182
+ "status": status,
183
+ }
184
+ response = self._client._request("POST", "/api/v1/agents", json=data)
185
+ return Agent(
186
+ id=response.get("agentId", ""),
187
+ name=name,
188
+ avatar=avatar,
189
+ role=role,
190
+ level=level,
191
+ status=status,
192
+ )
193
+
194
+ def list(self) -> List[Agent]:
195
+ """
196
+ List all agents.
197
+
198
+ Returns:
199
+ List of Agent objects
200
+ """
201
+ response = self._client._request("GET", "/api/v1/agents")
202
+ return [Agent.from_dict(a) for a in response.get("agents", [])]
203
+
204
+ def update_status(self, name: str, status: str) -> None:
205
+ """
206
+ Update an agent's status by name.
207
+
208
+ Args:
209
+ name: Agent name
210
+ status: New status (idle, working, offline)
211
+ """
212
+ self._client._request("PUT", "/api/v1/agents", json={
213
+ "name": name,
214
+ "status": status,
215
+ })
216
+
217
+ def set_working(self, name: str) -> None:
218
+ """Set agent status to working"""
219
+ self.update_status(name, "working")
220
+
221
+ def set_idle(self, name: str) -> None:
222
+ """Set agent status to idle"""
223
+ self.update_status(name, "idle")
224
+
225
+ def set_offline(self, name: str) -> None:
226
+ """Set agent status to offline"""
227
+ self.update_status(name, "offline")
228
+
229
+
230
+ class EventsAPI:
231
+ """Events API wrapper"""
232
+
233
+ def __init__(self, client: "CrewDeck"):
234
+ self._client = client
235
+
236
+ def send(
237
+ self,
238
+ type: str,
239
+ agent_name: Optional[str] = None,
240
+ message: Optional[str] = None,
241
+ task_id: Optional[str] = None,
242
+ metadata: Optional[Dict[str, Any]] = None,
243
+ ) -> None:
244
+ """
245
+ Send an event to the live feed.
246
+
247
+ Args:
248
+ type: Event type (message, status, log)
249
+ agent_name: Agent name (optional)
250
+ message: Message content
251
+ task_id: Related task ID
252
+ metadata: Additional metadata
253
+ """
254
+ event = Event(
255
+ type=type,
256
+ agent_name=agent_name,
257
+ message=message,
258
+ task_id=task_id,
259
+ metadata=metadata,
260
+ )
261
+ self._client._request("POST", "/api/v1/events", json=event.to_dict())
262
+
263
+ def message(self, content: str, agent_name: Optional[str] = None) -> None:
264
+ """
265
+ Send a message to the live feed.
266
+
267
+ Args:
268
+ content: Message content
269
+ agent_name: Agent name (optional)
270
+ """
271
+ self.send(type="message", message=content, agent_name=agent_name)
272
+
273
+ def log(
274
+ self,
275
+ message: str,
276
+ agent_name: Optional[str] = None,
277
+ metadata: Optional[Dict[str, Any]] = None,
278
+ ) -> None:
279
+ """
280
+ Send a log event.
281
+
282
+ Args:
283
+ message: Log message
284
+ agent_name: Agent name (optional)
285
+ metadata: Additional data to log
286
+ """
287
+ self.send(type="log", message=message, agent_name=agent_name, metadata=metadata)
288
+
289
+
290
+ class CrewDeck:
291
+ """
292
+ CrewDeck Python Client
293
+
294
+ Example:
295
+ deck = CrewDeck(api_key="your-api-key")
296
+
297
+ # Create a task
298
+ task = deck.tasks.create(
299
+ title="Process data",
300
+ priority="high",
301
+ assignees=["JARVIS"]
302
+ )
303
+
304
+ # Update agent status
305
+ deck.agents.set_working("JARVIS")
306
+
307
+ # Send a message
308
+ deck.events.message("Starting work...", agent_name="JARVIS")
309
+
310
+ # Complete the task
311
+ deck.tasks.complete(task.id, output="Data processed successfully")
312
+ """
313
+
314
+ def __init__(
315
+ self,
316
+ api_key: str,
317
+ base_url: str = DEFAULT_BASE_URL,
318
+ timeout: float = 30.0,
319
+ ):
320
+ """
321
+ Initialize CrewDeck client.
322
+
323
+ Args:
324
+ api_key: Your CrewDeck API key
325
+ base_url: API base URL (default: production)
326
+ timeout: Request timeout in seconds
327
+ """
328
+ if not api_key:
329
+ raise AuthenticationError("API key is required")
330
+
331
+ self.api_key = api_key
332
+ self.base_url = base_url.rstrip("/")
333
+ self.timeout = timeout
334
+
335
+ self._client = httpx.Client(
336
+ base_url=self.base_url,
337
+ headers={
338
+ "Authorization": f"Bearer {api_key}",
339
+ "Content-Type": "application/json",
340
+ },
341
+ timeout=timeout,
342
+ )
343
+
344
+ # API namespaces
345
+ self.tasks = TasksAPI(self)
346
+ self.agents = AgentsAPI(self)
347
+ self.events = EventsAPI(self)
348
+
349
+ def _request(
350
+ self,
351
+ method: str,
352
+ path: str,
353
+ params: Optional[Dict[str, str]] = None,
354
+ json: Optional[Dict[str, Any]] = None,
355
+ ) -> Dict[str, Any]:
356
+ """Make an API request"""
357
+ try:
358
+ response = self._client.request(
359
+ method=method,
360
+ url=path,
361
+ params=params,
362
+ json=json,
363
+ )
364
+
365
+ if response.status_code == 401:
366
+ raise AuthenticationError("Invalid or revoked API key")
367
+
368
+ if response.status_code == 404:
369
+ raise NotFoundError("Resource not found", status_code=404)
370
+
371
+ if response.status_code == 429:
372
+ raise RateLimitError("Rate limit exceeded", status_code=429)
373
+
374
+ if response.status_code >= 400:
375
+ try:
376
+ error_data = response.json()
377
+ message = error_data.get("error", f"API error: {response.status_code}")
378
+ except:
379
+ message = f"API error: {response.status_code}"
380
+ raise APIError(message, status_code=response.status_code)
381
+
382
+ return response.json()
383
+
384
+ except httpx.RequestError as e:
385
+ raise CrewDeckError(f"Request failed: {e}")
386
+
387
+ def close(self) -> None:
388
+ """Close the HTTP client"""
389
+ self._client.close()
390
+
391
+ def __enter__(self) -> "CrewDeck":
392
+ return self
393
+
394
+ def __exit__(self, *args) -> None:
395
+ self.close()
@@ -0,0 +1,35 @@
1
+ """CrewDeck SDK Exceptions"""
2
+
3
+
4
+ class CrewDeckError(Exception):
5
+ """Base exception for CrewDeck SDK"""
6
+ pass
7
+
8
+
9
+ class AuthenticationError(CrewDeckError):
10
+ """Raised when API key is invalid or missing"""
11
+ pass
12
+
13
+
14
+ class APIError(CrewDeckError):
15
+ """Raised when API returns an error"""
16
+
17
+ def __init__(self, message: str, status_code: int = None, response: dict = None):
18
+ super().__init__(message)
19
+ self.status_code = status_code
20
+ self.response = response
21
+
22
+
23
+ class ValidationError(CrewDeckError):
24
+ """Raised when input validation fails"""
25
+ pass
26
+
27
+
28
+ class NotFoundError(APIError):
29
+ """Raised when a resource is not found"""
30
+ pass
31
+
32
+
33
+ class RateLimitError(APIError):
34
+ """Raised when rate limit is exceeded"""
35
+ pass
@@ -0,0 +1,103 @@
1
+ """CrewDeck Data Models"""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import List, Optional, Dict, Any
5
+ from datetime import datetime
6
+
7
+
8
+ @dataclass
9
+ class Task:
10
+ """Represents a task in CrewDeck"""
11
+ id: str
12
+ title: str
13
+ description: str = ""
14
+ status: str = "INBOX"
15
+ priority: str = "medium"
16
+ assignees: List[str] = field(default_factory=list)
17
+ tags: List[str] = field(default_factory=list)
18
+ output: Optional[str] = None
19
+ created_at: Optional[datetime] = None
20
+ updated_at: Optional[datetime] = None
21
+
22
+ @classmethod
23
+ def from_dict(cls, data: Dict[str, Any]) -> "Task":
24
+ return cls(
25
+ id=data.get("id", ""),
26
+ title=data.get("title", ""),
27
+ description=data.get("description", ""),
28
+ status=data.get("status", "INBOX"),
29
+ priority=data.get("priority", "medium"),
30
+ assignees=data.get("assignees", []),
31
+ tags=data.get("tags", []),
32
+ output=data.get("output"),
33
+ created_at=datetime.fromtimestamp(data["createdAt"] / 1000) if data.get("createdAt") else None,
34
+ updated_at=datetime.fromtimestamp(data["updatedAt"] / 1000) if data.get("updatedAt") else None,
35
+ )
36
+
37
+ def to_dict(self) -> Dict[str, Any]:
38
+ return {
39
+ "id": self.id,
40
+ "title": self.title,
41
+ "description": self.description,
42
+ "status": self.status,
43
+ "priority": self.priority,
44
+ "assignees": self.assignees,
45
+ "tags": self.tags,
46
+ "output": self.output,
47
+ }
48
+
49
+
50
+ @dataclass
51
+ class Agent:
52
+ """Represents an agent in CrewDeck"""
53
+ id: str
54
+ name: str
55
+ avatar: str = "🤖"
56
+ role: str = "AI Agent"
57
+ level: str = "standard"
58
+ status: str = "idle"
59
+ created_at: Optional[datetime] = None
60
+
61
+ @classmethod
62
+ def from_dict(cls, data: Dict[str, Any]) -> "Agent":
63
+ return cls(
64
+ id=data.get("id", ""),
65
+ name=data.get("name", ""),
66
+ avatar=data.get("avatar", "🤖"),
67
+ role=data.get("role", "AI Agent"),
68
+ level=data.get("level", "standard"),
69
+ status=data.get("status", "idle"),
70
+ created_at=datetime.fromtimestamp(data["createdAt"] / 1000) if data.get("createdAt") else None,
71
+ )
72
+
73
+ def to_dict(self) -> Dict[str, Any]:
74
+ return {
75
+ "id": self.id,
76
+ "name": self.name,
77
+ "avatar": self.avatar,
78
+ "role": self.role,
79
+ "level": self.level,
80
+ "status": self.status,
81
+ }
82
+
83
+
84
+ @dataclass
85
+ class Event:
86
+ """Represents an event in CrewDeck"""
87
+ type: str
88
+ agent_name: Optional[str] = None
89
+ message: Optional[str] = None
90
+ task_id: Optional[str] = None
91
+ metadata: Optional[Dict[str, Any]] = None
92
+
93
+ def to_dict(self) -> Dict[str, Any]:
94
+ data = {"type": self.type}
95
+ if self.agent_name:
96
+ data["agentName"] = self.agent_name
97
+ if self.message:
98
+ data["message"] = self.message
99
+ if self.task_id:
100
+ data["taskId"] = self.task_id
101
+ if self.metadata:
102
+ data["metadata"] = self.metadata
103
+ return data
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "crewdeck"
7
+ version = "0.1.0"
8
+ description = "Python SDK for CrewDeck - AI agent management dashboard"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.8"
12
+ authors = [
13
+ { name = "CrewDeck", email = "hello@crewdeck.dev" }
14
+ ]
15
+ keywords = ["ai", "agents", "crewai", "autogen", "langchain", "dashboard", "management"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ ]
28
+ dependencies = [
29
+ "httpx>=0.24.0",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ async = ["httpx[http2]>=0.24.0"]
34
+ dev = [
35
+ "pytest>=7.0.0",
36
+ "pytest-asyncio>=0.21.0",
37
+ "black>=23.0.0",
38
+ "ruff>=0.1.0",
39
+ ]
40
+
41
+ [project.urls]
42
+ Homepage = "https://crewdeck.dev"
43
+ Documentation = "https://docs.crewdeck.dev"
44
+ Repository = "https://github.com/crewdeck/crewdeck-python"
45
+
46
+ [tool.hatch.build.targets.wheel]
47
+ packages = ["crewdeck"]
48
+
49
+ [tool.black]
50
+ line-length = 88
51
+ target-version = ["py38"]
52
+
53
+ [tool.ruff]
54
+ line-length = 88
55
+ target-version = "py38"