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 +93 -0
- fleeks_sdk/agents.py +414 -0
- fleeks_sdk/auth.py +84 -0
- fleeks_sdk/client.py +295 -0
- fleeks_sdk/config.py +79 -0
- fleeks_sdk/containers.py +181 -0
- fleeks_sdk/exceptions.py +102 -0
- fleeks_sdk/files.py +373 -0
- fleeks_sdk/models.py +626 -0
- fleeks_sdk/streaming.py +427 -0
- fleeks_sdk/terminal.py +314 -0
- fleeks_sdk/workspaces.py +329 -0
- fleeks_sdk-0.1.0.dist-info/METADATA +224 -0
- fleeks_sdk-0.1.0.dist-info/RECORD +17 -0
- fleeks_sdk-0.1.0.dist-info/WHEEL +5 -0
- fleeks_sdk-0.1.0.dist-info/licenses/LICENSE +21 -0
- fleeks_sdk-0.1.0.dist-info/top_level.txt +1 -0
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}')"
|