fleeks-sdk 0.1.0__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.
fleeks_sdk/__init__.py ADDED
@@ -0,0 +1,93 @@
1
+ """
2
+ Fleeks Python SDK
3
+
4
+ A comprehensive async Python SDK for interacting with Fleeks services.
5
+
6
+ Features:
7
+ - Full async/await support
8
+ - Socket.IO real-time streaming
9
+ - Comprehensive workspace management
10
+ - Agent orchestration
11
+ - File operations
12
+ - Terminal control
13
+ - Container management
14
+ - Automatic retry and rate limiting
15
+ - Type hints throughout
16
+ """
17
+
18
+ __version__ = "0.1.0"
19
+ __author__ = "Fleeks Inc"
20
+ __email__ = "support@fleeks.com"
21
+
22
+ # Core client and utilities
23
+ from .client import FleeksClient, create_client
24
+ from .config import Config
25
+ from .auth import APIKeyAuth
26
+
27
+ # Service managers
28
+ from .workspaces import WorkspaceManager, WorkspaceConfig, WorkspaceInfo
29
+ from .agents import AgentManager, AgentConfig, AgentInfo, AgentRole, AgentStatus, AgentHandoffRequest
30
+ from .files import FileManager, FileInfo, FileUploadConfig, FileSearchOptions
31
+ from .terminal import TerminalManager, TerminalConfig, TerminalSession, TerminalExecutionResult
32
+ from .containers import ContainerManager, ContainerInfo, ContainerStats, ContainerExecResult
33
+ from .streaming import StreamingClient
34
+
35
+ # Exceptions
36
+ from .exceptions import (
37
+ FleeksException,
38
+ FleeksAPIError,
39
+ FleeksRateLimitError,
40
+ FleeksAuthenticationError,
41
+ FleeksPermissionError,
42
+ FleeksResourceNotFoundError,
43
+ FleeksValidationError,
44
+ FleeksConnectionError,
45
+ FleeksStreamingError,
46
+ FleeksTimeoutError
47
+ )
48
+
49
+ __all__ = [
50
+ # Core
51
+ "FleeksClient",
52
+ "create_client",
53
+ "Config",
54
+ "APIKeyAuth",
55
+
56
+ # Service managers
57
+ "WorkspaceManager",
58
+ "AgentManager",
59
+ "FileManager",
60
+ "TerminalManager",
61
+ "ContainerManager",
62
+ "StreamingClient",
63
+
64
+ # Data models
65
+ "WorkspaceConfig",
66
+ "WorkspaceInfo",
67
+ "AgentConfig",
68
+ "AgentInfo",
69
+ "AgentRole",
70
+ "AgentStatus",
71
+ "AgentHandoffRequest",
72
+ "FileInfo",
73
+ "FileUploadConfig",
74
+ "FileSearchOptions",
75
+ "TerminalConfig",
76
+ "TerminalSession",
77
+ "TerminalExecutionResult",
78
+ "ContainerInfo",
79
+ "ContainerStats",
80
+ "ContainerExecResult",
81
+
82
+ # Exceptions
83
+ "FleeksException",
84
+ "FleeksAPIError",
85
+ "FleeksRateLimitError",
86
+ "FleeksAuthenticationError",
87
+ "FleeksPermissionError",
88
+ "FleeksResourceNotFoundError",
89
+ "FleeksValidationError",
90
+ "FleeksConnectionError",
91
+ "FleeksStreamingError",
92
+ "FleeksTimeoutError",
93
+ ]
fleeks_sdk/agents.py ADDED
@@ -0,0 +1,414 @@
1
+ """
2
+ Agent management for the Fleeks SDK.
3
+
4
+ Matches backend endpoints in app/api/api_v1/endpoints/sdk/agents.py
5
+ """
6
+
7
+ from typing import Dict, Any, List, Optional
8
+ from .models import (
9
+ AgentType,
10
+ AgentExecution,
11
+ AgentHandoff,
12
+ AgentStatusInfo,
13
+ AgentOutput,
14
+ AgentList
15
+ )
16
+ from .exceptions import FleeksAPIError, FleeksResourceNotFoundError
17
+
18
+
19
+ class AgentManager:
20
+ """
21
+ Manager for agent operations within a workspace.
22
+
23
+ Handles:
24
+ - Agent execution (auto, code, research, debug, test)
25
+ - CLI-to-cloud handoff (revolutionary feature!)
26
+ - Agent status monitoring
27
+ - Agent output retrieval
28
+ - Background agent management
29
+
30
+ Example:
31
+ >>> # Execute agent task
32
+ >>> agent = await workspace.agents.execute(
33
+ ... task="Create a FastAPI hello world endpoint",
34
+ ... agent_type=AgentType.CODE
35
+ ... )
36
+ >>>
37
+ >>> # Check status
38
+ >>> status = await workspace.agents.get_status(agent.agent_id)
39
+ >>> print(f"Progress: {status.progress}%")
40
+ >>>
41
+ >>> # Get output
42
+ >>> output = await workspace.agents.get_output(agent.agent_id)
43
+ >>> print(f"Files created: {output.files_created}")
44
+ """
45
+
46
+ def __init__(self, client, project_id: str):
47
+ """
48
+ Initialize agent manager for a workspace.
49
+
50
+ Args:
51
+ client: FleeksClient instance
52
+ project_id: Project identifier
53
+ """
54
+ self.client = client
55
+ self.project_id = project_id
56
+
57
+ async def execute(
58
+ self,
59
+ task: str,
60
+ agent_type: AgentType = AgentType.AUTO,
61
+ context: Optional[Dict[str, Any]] = None,
62
+ max_iterations: int = 10,
63
+ auto_approve: bool = False
64
+ ) -> AgentExecution:
65
+ """
66
+ Execute agent task in workspace.
67
+
68
+ POST /api/v1/sdk/agents
69
+
70
+ Agent runs in background and executes task autonomously.
71
+ Use get_status() to monitor progress, get_output() for results.
72
+
73
+ Args:
74
+ task: Natural language task description
75
+ Example: "Create a REST API with user authentication"
76
+ agent_type: Type of agent to use:
77
+ - AUTO: Automatically selects best agent
78
+ - CODE: Code generation/modification
79
+ - RESEARCH: Research and planning
80
+ - DEBUG: Debugging and fixing issues
81
+ - TEST: Test creation and execution
82
+ context: Optional context dictionary
83
+ Example: {"framework": "fastapi", "database": "postgresql"}
84
+ max_iterations: Maximum reasoning iterations (1-50, default: 10)
85
+ auto_approve: Auto-approve agent actions (default: False)
86
+
87
+ Returns:
88
+ AgentExecution: Started agent execution with:
89
+ - agent_id: Unique agent identifier
90
+ - project_id: Workspace project ID
91
+ - task: Task description
92
+ - status: Execution status
93
+ - started_at: ISO timestamp
94
+ - message: Status message
95
+
96
+ Raises:
97
+ FleeksValidationError: If task invalid or max_iterations out of range
98
+ FleeksPermissionError: If no access to workspace
99
+
100
+ Example:
101
+ >>> # Simple code generation
102
+ >>> agent = await workspace.agents.execute(
103
+ ... task="Create a user authentication module",
104
+ ... agent_type=AgentType.CODE
105
+ ... )
106
+ >>>
107
+ >>> # Research with context
108
+ >>> agent = await workspace.agents.execute(
109
+ ... task="Research best practices for microservices",
110
+ ... agent_type=AgentType.RESEARCH,
111
+ ... context={"language": "python", "scale": "enterprise"}
112
+ ... )
113
+ >>>
114
+ >>> # Debugging with more iterations
115
+ >>> agent = await workspace.agents.execute(
116
+ ... task="Fix the memory leak in user_service.py",
117
+ ... agent_type=AgentType.DEBUG,
118
+ ... max_iterations=20
119
+ ... )
120
+ """
121
+ data = {
122
+ 'project_id': self.project_id,
123
+ 'task': task,
124
+ 'agent_type': agent_type.value,
125
+ 'max_iterations': max_iterations,
126
+ 'auto_approve': auto_approve
127
+ }
128
+ if context:
129
+ data['context'] = context
130
+
131
+ response = await self.client.post('agents', json=data)
132
+ return AgentExecution.from_dict(response)
133
+
134
+ async def handoff(
135
+ self,
136
+ task: str,
137
+ local_context: Optional[Dict[str, Any]] = None,
138
+ workspace_snapshot: Optional[Dict[str, Any]] = None,
139
+ conversation_history: Optional[List[Dict[str, str]]] = None,
140
+ agent_type: AgentType = AgentType.AUTO
141
+ ) -> AgentHandoff:
142
+ """
143
+ CLI-to-cloud agent handoff (REVOLUTIONARY FEATURE!).
144
+
145
+ POST /api/v1/sdk/agents/handoff
146
+
147
+ Seamlessly transfers task from local CLI agent to cloud execution.
148
+ Preserves full context: files, conversation history, workspace state.
149
+
150
+ This enables:
151
+ - Start task locally, finish in cloud
152
+ - Offload heavy tasks to cloud compute
153
+ - Collaborate between local and cloud agents
154
+ - Context preservation across environments
155
+
156
+ Args:
157
+ task: Task to continue in cloud
158
+ local_context: Local execution context
159
+ Example: {
160
+ "current_file": "api.py",
161
+ "cursor_position": {"line": 42, "column": 10},
162
+ "recent_changes": [...]
163
+ }
164
+ workspace_snapshot: Current workspace state
165
+ Example: {
166
+ "files": [...],
167
+ "git_status": {...},
168
+ "running_processes": [...]
169
+ }
170
+ conversation_history: Agent conversation history
171
+ Example: [
172
+ {"role": "user", "content": "Create API"},
173
+ {"role": "assistant", "content": "I'll create..."},
174
+ ...
175
+ ]
176
+ agent_type: Agent type to use in cloud
177
+
178
+ Returns:
179
+ AgentHandoff: Handoff result with:
180
+ - agent_id: Cloud agent ID
181
+ - project_id: Workspace project ID
182
+ - status: Handoff status
183
+ - handoff_id: Unique handoff identifier
184
+ - workspace_synced: Whether workspace synced
185
+ - context_preserved: Whether context preserved
186
+ - message: Status message
187
+
188
+ Raises:
189
+ FleeksValidationError: If handoff data invalid
190
+ FleeksPermissionError: If no access to workspace
191
+
192
+ Example:
193
+ >>> # Basic handoff
194
+ >>> handoff = await workspace.agents.handoff(
195
+ ... task="Continue implementing the user service",
196
+ ... local_context={
197
+ ... "current_file": "services/user.py",
198
+ ... "last_action": "Added authentication"
199
+ ... }
200
+ ... )
201
+ >>>
202
+ >>> # Full context handoff
203
+ >>> handoff = await workspace.agents.handoff(
204
+ ... task="Complete the API implementation",
205
+ ... local_context={
206
+ ... "current_file": "api.py",
207
+ ... "cursor_position": {"line": 42, "column": 10}
208
+ ... },
209
+ ... workspace_snapshot={
210
+ ... "modified_files": ["api.py", "models.py"],
211
+ ... "git_branch": "feature/api"
212
+ ... },
213
+ ... conversation_history=[
214
+ ... {"role": "user", "content": "Create user API"},
215
+ ... {"role": "assistant", "content": "I created the endpoints..."}
216
+ ... ]
217
+ ... )
218
+ >>>
219
+ >>> print(f"Handoff ID: {handoff.handoff_id}")
220
+ >>> print(f"Synced: {handoff.workspace_synced}")
221
+ >>> print(f"Context preserved: {handoff.context_preserved}")
222
+ """
223
+ data = {
224
+ 'project_id': self.project_id,
225
+ 'task': task,
226
+ 'agent_type': agent_type.value
227
+ }
228
+ if local_context:
229
+ data['local_context'] = local_context
230
+ if workspace_snapshot:
231
+ data['workspace_snapshot'] = workspace_snapshot
232
+ if conversation_history:
233
+ data['conversation_history'] = conversation_history
234
+
235
+ response = await self.client.post('agents/handoff', json=data)
236
+ return AgentHandoff.from_dict(response)
237
+
238
+ async def get_status(self, agent_id: str) -> AgentStatusInfo:
239
+ """
240
+ Get agent execution status.
241
+
242
+ GET /api/v1/sdk/agents/{agent_id}
243
+
244
+ Returns detailed status including progress percentage (0-100),
245
+ current step, iterations completed, and execution time.
246
+
247
+ Args:
248
+ agent_id: Agent identifier
249
+
250
+ Returns:
251
+ AgentStatusInfo: Status with:
252
+ - agent_id: Agent identifier
253
+ - project_id: Workspace project ID
254
+ - task: Task description
255
+ - status: Current status (running/completed/failed)
256
+ - progress: Progress percentage (0-100)
257
+ - current_step: Current execution step
258
+ - iterations_completed: Completed iterations
259
+ - max_iterations: Maximum iterations
260
+ - started_at: Start timestamp
261
+ - completed_at: Completion timestamp (if done)
262
+ - execution_time_ms: Execution time in milliseconds
263
+
264
+ Raises:
265
+ FleeksResourceNotFoundError: If agent not found
266
+
267
+ Example:
268
+ >>> status = await workspace.agents.get_status(agent.agent_id)
269
+ >>> print(f"Progress: {status.progress}%")
270
+ >>> print(f"Step: {status.current_step}")
271
+ >>> print(f"Status: {status.status}")
272
+ >>>
273
+ >>> if status.is_completed:
274
+ ... print("Agent finished!")
275
+ >>> elif status.is_running:
276
+ ... print(f"Still running... {status.progress}% done")
277
+ """
278
+ try:
279
+ response = await self.client.get(f'agents/{agent_id}')
280
+ return AgentStatusInfo.from_dict(response)
281
+ except FleeksAPIError as e:
282
+ if e.status_code == 404:
283
+ raise FleeksResourceNotFoundError(
284
+ f"Agent '{agent_id}' not found"
285
+ )
286
+ raise
287
+
288
+ async def get_output(self, agent_id: str) -> AgentOutput:
289
+ """
290
+ Get agent execution output.
291
+
292
+ GET /api/v1/sdk/agents/{agent_id}/output
293
+
294
+ Returns complete results including files modified, commands executed,
295
+ reasoning steps, and any errors encountered.
296
+
297
+ Args:
298
+ agent_id: Agent identifier
299
+
300
+ Returns:
301
+ AgentOutput: Complete output with:
302
+ - agent_id: Agent identifier
303
+ - project_id: Workspace project ID
304
+ - task: Task description
305
+ - files_modified: List of modified file paths
306
+ - files_created: List of created file paths
307
+ - commands_executed: List of executed commands
308
+ - reasoning: List of reasoning steps
309
+ - errors: List of errors (if any)
310
+ - execution_time_ms: Total execution time
311
+ - iterations_completed: Completed iterations
312
+
313
+ Raises:
314
+ FleeksResourceNotFoundError: If agent not found
315
+
316
+ Example:
317
+ >>> output = await workspace.agents.get_output(agent.agent_id)
318
+ >>>
319
+ >>> print(f"Files created: {len(output.files_created)}")
320
+ >>> for file in output.files_created:
321
+ ... print(f" - {file}")
322
+ >>>
323
+ >>> print(f"\\nFiles modified: {len(output.files_modified)}")
324
+ >>> for file in output.files_modified:
325
+ ... print(f" - {file}")
326
+ >>>
327
+ >>> print(f"\\nCommands executed:")
328
+ >>> for cmd in output.commands_executed:
329
+ ... print(f" $ {cmd}")
330
+ >>>
331
+ >>> if output.has_errors:
332
+ ... print(f"\\n⚠️ Errors encountered:")
333
+ ... for error in output.errors:
334
+ ... print(f" - {error}")
335
+ """
336
+ try:
337
+ response = await self.client.get(f'agents/{agent_id}/output')
338
+ return AgentOutput.from_dict(response)
339
+ except FleeksAPIError as e:
340
+ if e.status_code == 404:
341
+ raise FleeksResourceNotFoundError(
342
+ f"Agent '{agent_id}' not found"
343
+ )
344
+ raise
345
+
346
+ async def list(
347
+ self,
348
+ page: int = 1,
349
+ page_size: int = 20,
350
+ status_filter: Optional[str] = None
351
+ ) -> AgentList:
352
+ """
353
+ List agents for this workspace.
354
+
355
+ GET /api/v1/sdk/agents
356
+
357
+ Args:
358
+ page: Page number (1-indexed, default: 1)
359
+ page_size: Items per page (max 100, default: 20)
360
+ status_filter: Filter by status (running/completed/failed)
361
+
362
+ Returns:
363
+ AgentList: List of agents with:
364
+ - project_id: Workspace project ID
365
+ - total_count: Total number of agents
366
+ - agents: List of AgentStatusInfo objects
367
+
368
+ Example:
369
+ >>> agents = await workspace.agents.list()
370
+ >>> print(f"Total agents: {agents.total_count}")
371
+ >>>
372
+ >>> for agent in agents.agents:
373
+ ... print(f"{agent.agent_id}: {agent.status} ({agent.progress}%)")
374
+ >>>
375
+ >>> # Filter by status
376
+ >>> running_agents = await workspace.agents.list(
377
+ ... status_filter="running"
378
+ ... )
379
+ """
380
+ params = {
381
+ 'project_id': self.project_id,
382
+ 'page': page,
383
+ 'page_size': page_size
384
+ }
385
+ if status_filter:
386
+ params['status_filter'] = status_filter
387
+
388
+ response = await self.client.get('agents', params=params)
389
+ return AgentList.from_dict(response)
390
+
391
+ async def stop(self, agent_id: str) -> None:
392
+ """
393
+ Stop running agent.
394
+
395
+ DELETE /api/v1/sdk/agents/{agent_id}
396
+
397
+ Gracefully stops agent execution. Agent can be checked later
398
+ for partial results.
399
+
400
+ Args:
401
+ agent_id: Agent identifier
402
+
403
+ Raises:
404
+ FleeksResourceNotFoundError: If agent not found
405
+
406
+ Example:
407
+ >>> # Stop long-running agent
408
+ >>> await workspace.agents.stop(agent.agent_id)
409
+ >>>
410
+ >>> # Check what it completed
411
+ >>> output = await workspace.agents.get_output(agent.agent_id)
412
+ >>> print(f"Completed {output.iterations_completed} iterations")
413
+ """
414
+ await self.client.delete(f'agents/{agent_id}')
fleeks_sdk/auth.py ADDED
@@ -0,0 +1,84 @@
1
+ """
2
+ Authentication handling for the Fleeks SDK.
3
+ """
4
+
5
+ from typing import Optional, Dict, Any
6
+ import hashlib
7
+ import hmac
8
+ import time
9
+ from .exceptions import FleeksAuthenticationError
10
+
11
+
12
+ class APIKeyAuth:
13
+ """API Key authentication handler."""
14
+
15
+ def __init__(self, api_key: str):
16
+ """
17
+ Initialize API key authentication.
18
+
19
+ Args:
20
+ api_key: The API key for authentication
21
+ """
22
+ self.api_key = api_key
23
+ self._validate_api_key()
24
+
25
+ def _validate_api_key(self) -> None:
26
+ """Validate the API key format."""
27
+ if not self.api_key:
28
+ raise FleeksAuthenticationError("API key cannot be empty")
29
+
30
+ if not self.api_key.startswith('fleeks_'):
31
+ raise FleeksAuthenticationError(
32
+ "Invalid API key format. API keys should start with 'fleeks_'"
33
+ )
34
+
35
+ if len(self.api_key) < 32:
36
+ raise FleeksAuthenticationError(
37
+ "API key appears to be too short. Please check your API key."
38
+ )
39
+
40
+ def get_auth_headers(self) -> Dict[str, str]:
41
+ """
42
+ Get authentication headers for API requests.
43
+
44
+ Returns:
45
+ Dictionary of headers needed for authentication
46
+ """
47
+ return {
48
+ 'Authorization': f'Bearer {self.api_key}',
49
+ 'X-API-Key': self.api_key
50
+ }
51
+
52
+ def sign_request(self, method: str, path: str, body: str = "") -> Dict[str, str]:
53
+ """
54
+ Sign a request for enhanced security (if needed in the future).
55
+
56
+ Args:
57
+ method: HTTP method
58
+ path: Request path
59
+ body: Request body
60
+
61
+ Returns:
62
+ Dictionary containing signature headers
63
+ """
64
+ timestamp = str(int(time.time()))
65
+
66
+ # Create signature string
67
+ string_to_sign = f"{method}\n{path}\n{timestamp}\n{body}"
68
+
69
+ # Create HMAC signature (using API key as secret)
70
+ signature = hmac.new(
71
+ self.api_key.encode('utf-8'),
72
+ string_to_sign.encode('utf-8'),
73
+ hashlib.sha256
74
+ ).hexdigest()
75
+
76
+ return {
77
+ 'X-Timestamp': timestamp,
78
+ 'X-Signature': signature
79
+ }
80
+
81
+ def __repr__(self) -> str:
82
+ # Don't expose the full API key
83
+ masked_key = f"{self.api_key[:12]}..." if self.api_key else "None"
84
+ return f"APIKeyAuth(api_key='{masked_key}')"