cyberdesk 2.0.0__py3-none-any.whl → 2.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.

Potentially problematic release.


This version of cyberdesk might be problematic. Click here for more details.

Files changed (33) hide show
  1. cyberdesk/__init__.py +1 -1
  2. cyberdesk/client.py +480 -25
  3. {cyberdesk-2.0.0.dist-info → cyberdesk-2.1.1.dist-info}/METADATA +1 -1
  4. {cyberdesk-2.0.0.dist-info → cyberdesk-2.1.1.dist-info}/RECORD +33 -16
  5. openapi_client/cyberdesk_cloud_client/api/machines/get_machine_pools_v1_machines_machine_id_pools_get.py +169 -0
  6. openapi_client/cyberdesk_cloud_client/api/machines/list_machines_v1_machines_get.py +53 -0
  7. openapi_client/cyberdesk_cloud_client/api/machines/update_machine_pools_v1_machines_machine_id_pools_put.py +190 -0
  8. openapi_client/cyberdesk_cloud_client/api/pools/__init__.py +1 -0
  9. openapi_client/cyberdesk_cloud_client/api/pools/add_machines_to_pool_v1_pools_pool_id_machines_post.py +186 -0
  10. openapi_client/cyberdesk_cloud_client/api/pools/create_pool_v1_pools_post.py +172 -0
  11. openapi_client/cyberdesk_cloud_client/api/pools/delete_pool_v1_pools_pool_id_delete.py +162 -0
  12. openapi_client/cyberdesk_cloud_client/api/pools/get_pool_v1_pools_pool_id_get.py +185 -0
  13. openapi_client/cyberdesk_cloud_client/api/pools/list_pools_v1_pools_get.py +186 -0
  14. openapi_client/cyberdesk_cloud_client/api/pools/remove_machines_from_pool_v1_pools_pool_id_machines_delete.py +184 -0
  15. openapi_client/cyberdesk_cloud_client/api/pools/update_pool_v1_pools_pool_id_patch.py +186 -0
  16. openapi_client/cyberdesk_cloud_client/api/runs/list_runs_v1_runs_get.py +53 -0
  17. openapi_client/cyberdesk_cloud_client/api/trajectories/list_trajectories_v1_trajectories_get.py +105 -0
  18. openapi_client/cyberdesk_cloud_client/api/workflows/list_workflows_v1_workflows_get.py +105 -0
  19. openapi_client/cyberdesk_cloud_client/models/__init__.py +14 -0
  20. openapi_client/cyberdesk_cloud_client/models/machine_pool_assignment.py +69 -0
  21. openapi_client/cyberdesk_cloud_client/models/machine_pool_update.py +69 -0
  22. openapi_client/cyberdesk_cloud_client/models/machine_response.py +46 -1
  23. openapi_client/cyberdesk_cloud_client/models/paginated_response_pool_response.py +97 -0
  24. openapi_client/cyberdesk_cloud_client/models/pool_create.py +82 -0
  25. openapi_client/cyberdesk_cloud_client/models/pool_response.py +137 -0
  26. openapi_client/cyberdesk_cloud_client/models/pool_update.py +92 -0
  27. openapi_client/cyberdesk_cloud_client/models/pool_with_machines.py +162 -0
  28. openapi_client/cyberdesk_cloud_client/models/run_bulk_create.py +40 -0
  29. openapi_client/cyberdesk_cloud_client/models/run_create.py +40 -0
  30. openapi_client/cyberdesk_cloud_client/models/run_response.py +39 -0
  31. {cyberdesk-2.0.0.dist-info → cyberdesk-2.1.1.dist-info}/WHEEL +0 -0
  32. {cyberdesk-2.0.0.dist-info → cyberdesk-2.1.1.dist-info}/licenses/LICENSE +0 -0
  33. {cyberdesk-2.0.0.dist-info → cyberdesk-2.1.1.dist-info}/top_level.txt +0 -0
cyberdesk/__init__.py CHANGED
@@ -27,7 +27,7 @@ from .client import (
27
27
  AttachmentType,
28
28
  )
29
29
 
30
- __version__ = "2.0.0"
30
+ __version__ = "2.1.1"
31
31
 
32
32
  __all__ = [
33
33
  "CyberdeskClient",
cyberdesk/client.py CHANGED
@@ -4,6 +4,7 @@ from uuid import UUID
4
4
  from pathlib import Path
5
5
  import httpx
6
6
  from dataclasses import dataclass
7
+ from datetime import datetime, timezone
7
8
 
8
9
  # Import the generated client
9
10
  from openapi_client.cyberdesk_cloud_client import AuthenticatedClient
@@ -14,6 +15,17 @@ from openapi_client.cyberdesk_cloud_client.api.machines import (
14
15
  get_machine_v1_machines_machine_id_get,
15
16
  update_machine_v1_machines_machine_id_patch,
16
17
  delete_machine_v1_machines_machine_id_delete,
18
+ get_machine_pools_v1_machines_machine_id_pools_get,
19
+ update_machine_pools_v1_machines_machine_id_pools_put,
20
+ )
21
+ from openapi_client.cyberdesk_cloud_client.api.pools import (
22
+ list_pools_v1_pools_get,
23
+ create_pool_v1_pools_post,
24
+ get_pool_v1_pools_pool_id_get,
25
+ update_pool_v1_pools_pool_id_patch,
26
+ delete_pool_v1_pools_pool_id_delete,
27
+ add_machines_to_pool_v1_pools_pool_id_machines_post,
28
+ remove_machines_from_pool_v1_pools_pool_id_machines_delete,
17
29
  )
18
30
  from openapi_client.cyberdesk_cloud_client.api.workflows import (
19
31
  list_workflows_v1_workflows_get,
@@ -58,6 +70,12 @@ from openapi_client.cyberdesk_cloud_client.models import (
58
70
  MachineUpdate,
59
71
  MachineResponse,
60
72
  MachineStatus,
73
+ MachinePoolUpdate,
74
+ PoolCreate,
75
+ PoolUpdate,
76
+ PoolResponse,
77
+ PoolWithMachines,
78
+ MachinePoolAssignment,
61
79
  WorkflowCreate,
62
80
  WorkflowUpdate,
63
81
  WorkflowResponse,
@@ -80,6 +98,7 @@ from openapi_client.cyberdesk_cloud_client.models import (
80
98
  RunAttachmentDownloadUrlResponse,
81
99
  AttachmentType,
82
100
  PaginatedResponseMachineResponse,
101
+ PaginatedResponsePoolResponse,
83
102
  PaginatedResponseWorkflowResponse,
84
103
  PaginatedResponseRunResponse,
85
104
  PaginatedResponseConnectionResponse,
@@ -94,6 +113,12 @@ __all__ = [
94
113
  "MachineUpdate",
95
114
  "MachineResponse",
96
115
  "MachineStatus",
116
+ "MachinePoolUpdate",
117
+ "PoolCreate",
118
+ "PoolUpdate",
119
+ "PoolResponse",
120
+ "PoolWithMachines",
121
+ "MachinePoolAssignment",
97
122
  "WorkflowCreate",
98
123
  "WorkflowUpdate",
99
124
  "WorkflowResponse",
@@ -139,6 +164,26 @@ def _to_unset_or_value(value: Optional[Any]) -> Union[Unset, Any]:
139
164
  return UNSET if value is None else value
140
165
 
141
166
 
167
+ def _to_iso_utc_str(value: Optional[Union[str, datetime]]) -> Optional[str]:
168
+ """Convert a datetime or string to an ISO8601 UTC string.
169
+
170
+ - If value is a string, it is returned unchanged (assumed to be ISO8601)
171
+ - If value is a timezone-aware datetime, it is converted to UTC ISO string
172
+ - If value is a naive datetime, it is treated as UTC and suffixed accordingly
173
+ - If value is None, returns None
174
+ """
175
+ if value is None:
176
+ return None
177
+ if isinstance(value, str):
178
+ return value
179
+ if isinstance(value, datetime):
180
+ if value.tzinfo is None:
181
+ return value.replace(tzinfo=timezone.utc).isoformat()
182
+ return value.astimezone(timezone.utc).isoformat()
183
+ return None
184
+
185
+
186
+
142
187
  class MachinesAPI:
143
188
  """Machines API endpoints."""
144
189
 
@@ -149,15 +194,28 @@ class MachinesAPI:
149
194
  self,
150
195
  skip: Optional[int] = None,
151
196
  limit: Optional[int] = None,
152
- status: Optional[MachineStatus] = None
197
+ status: Optional[MachineStatus] = None,
198
+ *,
199
+ created_at_from: Optional[Union[str, datetime]] = None,
200
+ created_at_to: Optional[Union[str, datetime]] = None,
153
201
  ) -> ApiResponse:
154
- """List machines with optional filtering."""
202
+ """List machines with optional filtering.
203
+
204
+ Args:
205
+ skip: Pagination skip
206
+ limit: Pagination limit
207
+ status: Machine status filter
208
+ created_at_from: Optional start datetime (UTC or ISO string)
209
+ created_at_to: Optional end datetime (UTC or ISO string)
210
+ """
155
211
  try:
156
212
  response = await list_machines_v1_machines_get.asyncio(
157
213
  client=self.client,
158
214
  skip=_to_unset_or_value(skip),
159
215
  limit=_to_unset_or_value(limit),
160
- status=status
216
+ status=status,
217
+ created_at_from=_to_unset_or_value(_to_iso_utc_str(created_at_from)),
218
+ created_at_to=_to_unset_or_value(_to_iso_utc_str(created_at_to)),
161
219
  )
162
220
  return ApiResponse(data=response)
163
221
  except Exception as e:
@@ -167,7 +225,10 @@ class MachinesAPI:
167
225
  self,
168
226
  skip: Optional[int] = None,
169
227
  limit: Optional[int] = None,
170
- status: Optional[MachineStatus] = None
228
+ status: Optional[MachineStatus] = None,
229
+ *,
230
+ created_at_from: Optional[Union[str, datetime]] = None,
231
+ created_at_to: Optional[Union[str, datetime]] = None,
171
232
  ) -> ApiResponse:
172
233
  """List machines with optional filtering (synchronous)."""
173
234
  try:
@@ -175,7 +236,9 @@ class MachinesAPI:
175
236
  client=self.client,
176
237
  skip=_to_unset_or_value(skip),
177
238
  limit=_to_unset_or_value(limit),
178
- status=status
239
+ status=status,
240
+ created_at_from=_to_unset_or_value(_to_iso_utc_str(created_at_from)),
241
+ created_at_to=_to_unset_or_value(_to_iso_utc_str(created_at_to)),
179
242
  )
180
243
  return ApiResponse(data=response)
181
244
  except Exception as e:
@@ -270,6 +333,299 @@ class MachinesAPI:
270
333
  return ApiResponse(data={"success": True})
271
334
  except Exception as e:
272
335
  return ApiResponse(error=e)
336
+
337
+ async def get_pools(self, machine_id: str) -> ApiResponse:
338
+ """Get all pools that a machine belongs to."""
339
+ try:
340
+ response = await get_machine_pools_v1_machines_machine_id_pools_get.asyncio(
341
+ client=self.client,
342
+ machine_id=_to_uuid(machine_id)
343
+ )
344
+ return ApiResponse(data=response)
345
+ except Exception as e:
346
+ return ApiResponse(error=e)
347
+
348
+ def get_pools_sync(self, machine_id: str) -> ApiResponse:
349
+ """Get all pools that a machine belongs to (synchronous)."""
350
+ try:
351
+ response = get_machine_pools_v1_machines_machine_id_pools_get.sync(
352
+ client=self.client,
353
+ machine_id=_to_uuid(machine_id)
354
+ )
355
+ return ApiResponse(data=response)
356
+ except Exception as e:
357
+ return ApiResponse(error=e)
358
+
359
+ async def update_pools(self, machine_id: str, data: MachinePoolUpdate) -> ApiResponse:
360
+ """Update a machine's pool assignments.
361
+
362
+ This replaces all existing pool assignments with the new ones.
363
+
364
+ Args:
365
+ machine_id: The machine ID
366
+ data: MachinePoolUpdate with pool_ids list
367
+
368
+ Returns:
369
+ ApiResponse with updated MachineResponse
370
+ """
371
+ try:
372
+ response = await update_machine_pools_v1_machines_machine_id_pools_put.asyncio(
373
+ client=self.client,
374
+ machine_id=_to_uuid(machine_id),
375
+ body=data
376
+ )
377
+ return ApiResponse(data=response)
378
+ except Exception as e:
379
+ return ApiResponse(error=e)
380
+
381
+ def update_pools_sync(self, machine_id: str, data: MachinePoolUpdate) -> ApiResponse:
382
+ """Update a machine's pool assignments (synchronous).
383
+
384
+ This replaces all existing pool assignments with the new ones.
385
+
386
+ Args:
387
+ machine_id: The machine ID
388
+ data: MachinePoolUpdate with pool_ids list
389
+
390
+ Returns:
391
+ ApiResponse with updated MachineResponse
392
+ """
393
+ try:
394
+ response = update_machine_pools_v1_machines_machine_id_pools_put.sync(
395
+ client=self.client,
396
+ machine_id=_to_uuid(machine_id),
397
+ body=data
398
+ )
399
+ return ApiResponse(data=response)
400
+ except Exception as e:
401
+ return ApiResponse(error=e)
402
+
403
+
404
+ class PoolsAPI:
405
+ """Pools API endpoints."""
406
+
407
+ def __init__(self, client: AuthenticatedClient):
408
+ self.client = client
409
+
410
+ async def list(
411
+ self,
412
+ skip: Optional[int] = None,
413
+ limit: Optional[int] = None
414
+ ) -> ApiResponse:
415
+ """List pools for the organization."""
416
+ try:
417
+ response = await list_pools_v1_pools_get.asyncio(
418
+ client=self.client,
419
+ skip=_to_unset_or_value(skip),
420
+ limit=_to_unset_or_value(limit)
421
+ )
422
+ return ApiResponse(data=response)
423
+ except Exception as e:
424
+ return ApiResponse(error=e)
425
+
426
+ def list_sync(
427
+ self,
428
+ skip: Optional[int] = None,
429
+ limit: Optional[int] = None
430
+ ) -> ApiResponse:
431
+ """List pools for the organization (synchronous)."""
432
+ try:
433
+ response = list_pools_v1_pools_get.sync(
434
+ client=self.client,
435
+ skip=_to_unset_or_value(skip),
436
+ limit=_to_unset_or_value(limit)
437
+ )
438
+ return ApiResponse(data=response)
439
+ except Exception as e:
440
+ return ApiResponse(error=e)
441
+
442
+ async def create(self, data: PoolCreate) -> ApiResponse:
443
+ """Create a new pool."""
444
+ try:
445
+ response = await create_pool_v1_pools_post.asyncio(
446
+ client=self.client,
447
+ body=data
448
+ )
449
+ return ApiResponse(data=response)
450
+ except Exception as e:
451
+ return ApiResponse(error=e)
452
+
453
+ def create_sync(self, data: PoolCreate) -> ApiResponse:
454
+ """Create a new pool (synchronous)."""
455
+ try:
456
+ response = create_pool_v1_pools_post.sync(
457
+ client=self.client,
458
+ body=data
459
+ )
460
+ return ApiResponse(data=response)
461
+ except Exception as e:
462
+ return ApiResponse(error=e)
463
+
464
+ async def get(self, pool_id: str, include_machines: bool = False) -> ApiResponse:
465
+ """Get a specific pool by ID.
466
+
467
+ Args:
468
+ pool_id: The pool ID
469
+ include_machines: Whether to include full machine details
470
+
471
+ Returns:
472
+ ApiResponse with PoolResponse or PoolWithMachines
473
+ """
474
+ try:
475
+ response = await get_pool_v1_pools_pool_id_get.asyncio(
476
+ client=self.client,
477
+ pool_id=_to_uuid(pool_id),
478
+ include_machines=include_machines
479
+ )
480
+ return ApiResponse(data=response)
481
+ except Exception as e:
482
+ return ApiResponse(error=e)
483
+
484
+ def get_sync(self, pool_id: str, include_machines: bool = False) -> ApiResponse:
485
+ """Get a specific pool by ID (synchronous).
486
+
487
+ Args:
488
+ pool_id: The pool ID
489
+ include_machines: Whether to include full machine details
490
+
491
+ Returns:
492
+ ApiResponse with PoolResponse or PoolWithMachines
493
+ """
494
+ try:
495
+ response = get_pool_v1_pools_pool_id_get.sync(
496
+ client=self.client,
497
+ pool_id=_to_uuid(pool_id),
498
+ include_machines=include_machines
499
+ )
500
+ return ApiResponse(data=response)
501
+ except Exception as e:
502
+ return ApiResponse(error=e)
503
+
504
+ async def update(self, pool_id: str, data: PoolUpdate) -> ApiResponse:
505
+ """Update a pool's details."""
506
+ try:
507
+ response = await update_pool_v1_pools_pool_id_patch.asyncio(
508
+ client=self.client,
509
+ pool_id=_to_uuid(pool_id),
510
+ body=data
511
+ )
512
+ return ApiResponse(data=response)
513
+ except Exception as e:
514
+ return ApiResponse(error=e)
515
+
516
+ def update_sync(self, pool_id: str, data: PoolUpdate) -> ApiResponse:
517
+ """Update a pool's details (synchronous)."""
518
+ try:
519
+ response = update_pool_v1_pools_pool_id_patch.sync(
520
+ client=self.client,
521
+ pool_id=_to_uuid(pool_id),
522
+ body=data
523
+ )
524
+ return ApiResponse(data=response)
525
+ except Exception as e:
526
+ return ApiResponse(error=e)
527
+
528
+ async def delete(self, pool_id: str) -> ApiResponse:
529
+ """Delete a pool. This will not delete the machines in the pool."""
530
+ try:
531
+ await delete_pool_v1_pools_pool_id_delete.asyncio(
532
+ client=self.client,
533
+ pool_id=_to_uuid(pool_id)
534
+ )
535
+ return ApiResponse(data={"success": True})
536
+ except Exception as e:
537
+ return ApiResponse(error=e)
538
+
539
+ def delete_sync(self, pool_id: str) -> ApiResponse:
540
+ """Delete a pool. This will not delete the machines in the pool (synchronous)."""
541
+ try:
542
+ delete_pool_v1_pools_pool_id_delete.sync(
543
+ client=self.client,
544
+ pool_id=_to_uuid(pool_id)
545
+ )
546
+ return ApiResponse(data={"success": True})
547
+ except Exception as e:
548
+ return ApiResponse(error=e)
549
+
550
+ async def add_machines(self, pool_id: str, data: MachinePoolAssignment) -> ApiResponse:
551
+ """Add machines to a pool.
552
+
553
+ Args:
554
+ pool_id: The pool ID
555
+ data: MachinePoolAssignment with machine_ids list
556
+
557
+ Returns:
558
+ ApiResponse with PoolWithMachines
559
+ """
560
+ try:
561
+ response = await add_machines_to_pool_v1_pools_pool_id_machines_post.asyncio(
562
+ client=self.client,
563
+ pool_id=_to_uuid(pool_id),
564
+ body=data
565
+ )
566
+ return ApiResponse(data=response)
567
+ except Exception as e:
568
+ return ApiResponse(error=e)
569
+
570
+ def add_machines_sync(self, pool_id: str, data: MachinePoolAssignment) -> ApiResponse:
571
+ """Add machines to a pool (synchronous).
572
+
573
+ Args:
574
+ pool_id: The pool ID
575
+ data: MachinePoolAssignment with machine_ids list
576
+
577
+ Returns:
578
+ ApiResponse with PoolWithMachines
579
+ """
580
+ try:
581
+ response = add_machines_to_pool_v1_pools_pool_id_machines_post.sync(
582
+ client=self.client,
583
+ pool_id=_to_uuid(pool_id),
584
+ body=data
585
+ )
586
+ return ApiResponse(data=response)
587
+ except Exception as e:
588
+ return ApiResponse(error=e)
589
+
590
+ async def remove_machines(self, pool_id: str, data: MachinePoolAssignment) -> ApiResponse:
591
+ """Remove machines from a pool.
592
+
593
+ Args:
594
+ pool_id: The pool ID
595
+ data: MachinePoolAssignment with machine_ids list
596
+
597
+ Returns:
598
+ ApiResponse with success status
599
+ """
600
+ try:
601
+ await remove_machines_from_pool_v1_pools_pool_id_machines_delete.asyncio(
602
+ client=self.client,
603
+ pool_id=_to_uuid(pool_id),
604
+ body=data
605
+ )
606
+ return ApiResponse(data={"success": True})
607
+ except Exception as e:
608
+ return ApiResponse(error=e)
609
+
610
+ def remove_machines_sync(self, pool_id: str, data: MachinePoolAssignment) -> ApiResponse:
611
+ """Remove machines from a pool (synchronous).
612
+
613
+ Args:
614
+ pool_id: The pool ID
615
+ data: MachinePoolAssignment with machine_ids list
616
+
617
+ Returns:
618
+ ApiResponse with success status
619
+ """
620
+ try:
621
+ remove_machines_from_pool_v1_pools_pool_id_machines_delete.sync(
622
+ client=self.client,
623
+ pool_id=_to_uuid(pool_id),
624
+ body=data
625
+ )
626
+ return ApiResponse(data={"success": True})
627
+ except Exception as e:
628
+ return ApiResponse(error=e)
273
629
 
274
630
 
275
631
  class WorkflowsAPI:
@@ -278,25 +634,61 @@ class WorkflowsAPI:
278
634
  def __init__(self, client: AuthenticatedClient):
279
635
  self.client = client
280
636
 
281
- async def list(self, skip: Optional[int] = None, limit: Optional[int] = None) -> ApiResponse:
282
- """List workflows."""
637
+ async def list(
638
+ self,
639
+ skip: Optional[int] = None,
640
+ limit: Optional[int] = None,
641
+ *,
642
+ created_at_from: Optional[Union[str, datetime]] = None,
643
+ created_at_to: Optional[Union[str, datetime]] = None,
644
+ updated_at_from: Optional[Union[str, datetime]] = None,
645
+ updated_at_to: Optional[Union[str, datetime]] = None,
646
+ ) -> ApiResponse:
647
+ """List workflows with optional date-time filtering.
648
+
649
+ Args:
650
+ skip: Pagination skip
651
+ limit: Pagination limit
652
+ created_at_from: Start datetime for created_at filter (UTC or ISO)
653
+ created_at_to: End datetime for created_at filter (UTC or ISO)
654
+ updated_at_from: Start datetime for updated_at filter (UTC or ISO)
655
+ updated_at_to: End datetime for updated_at filter (UTC or ISO)
656
+ """
283
657
  try:
284
658
  response = await list_workflows_v1_workflows_get.asyncio(
285
659
  client=self.client,
286
660
  skip=_to_unset_or_value(skip),
287
- limit=_to_unset_or_value(limit)
661
+ limit=_to_unset_or_value(limit),
662
+ created_at_from=_to_unset_or_value(_to_iso_utc_str(created_at_from)),
663
+ created_at_to=_to_unset_or_value(_to_iso_utc_str(created_at_to)),
664
+ updated_at_from=_to_unset_or_value(_to_iso_utc_str(updated_at_from)),
665
+ updated_at_to=_to_unset_or_value(_to_iso_utc_str(updated_at_to)),
666
+ test=1
288
667
  )
289
668
  return ApiResponse(data=response)
290
669
  except Exception as e:
291
670
  return ApiResponse(error=e)
292
671
 
293
- def list_sync(self, skip: Optional[int] = None, limit: Optional[int] = None) -> ApiResponse:
294
- """List workflows (synchronous)."""
672
+ def list_sync(
673
+ self,
674
+ skip: Optional[int] = None,
675
+ limit: Optional[int] = None,
676
+ *,
677
+ created_at_from: Optional[Union[str, datetime]] = None,
678
+ created_at_to: Optional[Union[str, datetime]] = None,
679
+ updated_at_from: Optional[Union[str, datetime]] = None,
680
+ updated_at_to: Optional[Union[str, datetime]] = None,
681
+ ) -> ApiResponse:
682
+ """List workflows (synchronous) with optional date-time filtering."""
295
683
  try:
296
684
  response = list_workflows_v1_workflows_get.sync(
297
685
  client=self.client,
298
686
  skip=_to_unset_or_value(skip),
299
- limit=_to_unset_or_value(limit)
687
+ limit=_to_unset_or_value(limit),
688
+ created_at_from=_to_unset_or_value(_to_iso_utc_str(created_at_from)),
689
+ created_at_to=_to_unset_or_value(_to_iso_utc_str(created_at_to)),
690
+ updated_at_from=_to_unset_or_value(_to_iso_utc_str(updated_at_from)),
691
+ updated_at_to=_to_unset_or_value(_to_iso_utc_str(updated_at_to)),
300
692
  )
301
693
  return ApiResponse(data=response)
302
694
  except Exception as e:
@@ -405,7 +797,10 @@ class RunsAPI:
405
797
  limit: Optional[int] = None,
406
798
  status: Optional[RunStatus] = None,
407
799
  workflow_id: Optional[str] = None,
408
- machine_id: Optional[str] = None
800
+ machine_id: Optional[str] = None,
801
+ *,
802
+ created_at_from: Optional[Union[str, datetime]] = None,
803
+ created_at_to: Optional[Union[str, datetime]] = None,
409
804
  ) -> ApiResponse:
410
805
  """List runs with optional filtering."""
411
806
  try:
@@ -415,7 +810,9 @@ class RunsAPI:
415
810
  limit=_to_unset_or_value(limit),
416
811
  status=status,
417
812
  workflow_id=_to_uuid(workflow_id) if workflow_id else UNSET,
418
- machine_id=_to_uuid(machine_id) if machine_id else UNSET
813
+ machine_id=_to_uuid(machine_id) if machine_id else UNSET,
814
+ created_at_from=_to_unset_or_value(_to_iso_utc_str(created_at_from)),
815
+ created_at_to=_to_unset_or_value(_to_iso_utc_str(created_at_to)),
419
816
  )
420
817
  return ApiResponse(data=response)
421
818
  except Exception as e:
@@ -427,7 +824,10 @@ class RunsAPI:
427
824
  limit: Optional[int] = None,
428
825
  status: Optional[RunStatus] = None,
429
826
  workflow_id: Optional[str] = None,
430
- machine_id: Optional[str] = None
827
+ machine_id: Optional[str] = None,
828
+ *,
829
+ created_at_from: Optional[Union[str, datetime]] = None,
830
+ created_at_to: Optional[Union[str, datetime]] = None,
431
831
  ) -> ApiResponse:
432
832
  """List runs with optional filtering (synchronous)."""
433
833
  try:
@@ -437,14 +837,28 @@ class RunsAPI:
437
837
  limit=_to_unset_or_value(limit),
438
838
  status=status,
439
839
  workflow_id=_to_uuid(workflow_id) if workflow_id else UNSET,
440
- machine_id=_to_uuid(machine_id) if machine_id else UNSET
840
+ machine_id=_to_uuid(machine_id) if machine_id else UNSET,
841
+ created_at_from=_to_unset_or_value(_to_iso_utc_str(created_at_from)),
842
+ created_at_to=_to_unset_or_value(_to_iso_utc_str(created_at_to)),
441
843
  )
442
844
  return ApiResponse(data=response)
443
845
  except Exception as e:
444
846
  return ApiResponse(error=e)
445
847
 
446
848
  async def create(self, data: RunCreate) -> ApiResponse:
447
- """Create a new run."""
849
+ """Create a new run.
850
+
851
+ Args:
852
+ data: RunCreate object with:
853
+ - workflow_id: The workflow to run
854
+ - machine_id: Optional specific machine ID
855
+ - pool_ids: Optional list of pool IDs (machine must be in ALL specified pools)
856
+ - input_values: Optional input values for workflow variables
857
+ - file_inputs: Optional files to upload to the machine
858
+
859
+ Returns:
860
+ ApiResponse with RunResponse
861
+ """
448
862
  try:
449
863
  response = await create_run_v1_runs_post.asyncio(
450
864
  client=self.client,
@@ -455,7 +869,19 @@ class RunsAPI:
455
869
  return ApiResponse(error=e)
456
870
 
457
871
  def create_sync(self, data: RunCreate) -> ApiResponse:
458
- """Create a new run (synchronous)."""
872
+ """Create a new run (synchronous).
873
+
874
+ Args:
875
+ data: RunCreate object with:
876
+ - workflow_id: The workflow to run
877
+ - machine_id: Optional specific machine ID
878
+ - pool_ids: Optional list of pool IDs (machine must be in ALL specified pools)
879
+ - input_values: Optional input values for workflow variables
880
+ - file_inputs: Optional files to upload to the machine
881
+
882
+ Returns:
883
+ ApiResponse with RunResponse
884
+ """
459
885
  try:
460
886
  response = create_run_v1_runs_post.sync(
461
887
  client=self.client,
@@ -542,8 +968,13 @@ class RunsAPI:
542
968
  - Returns immediately with created run details
543
969
 
544
970
  Args:
545
- data: RunBulkCreate object containing workflow_id, machine_id,
546
- input_values, file_inputs, and count (max 1000)
971
+ data: RunBulkCreate object containing:
972
+ - workflow_id: The workflow to run
973
+ - machine_id: Optional specific machine ID
974
+ - pool_ids: Optional list of pool IDs (machine must be in ALL specified pools)
975
+ - input_values: Optional input values for workflow variables
976
+ - file_inputs: Optional files to upload to the machine
977
+ - count: Number of runs to create (max 1000)
547
978
 
548
979
  Returns:
549
980
  ApiResponse with RunBulkCreateResponse containing:
@@ -569,8 +1000,13 @@ class RunsAPI:
569
1000
  - Returns immediately with created run details
570
1001
 
571
1002
  Args:
572
- data: RunBulkCreate object containing workflow_id, machine_id,
573
- input_values, file_inputs, and count (max 1000)
1003
+ data: RunBulkCreate object containing:
1004
+ - workflow_id: The workflow to run
1005
+ - machine_id: Optional specific machine ID
1006
+ - pool_ids: Optional list of pool IDs (machine must be in ALL specified pools)
1007
+ - input_values: Optional input values for workflow variables
1008
+ - file_inputs: Optional files to upload to the machine
1009
+ - count: Number of runs to create (max 1000)
574
1010
 
575
1011
  Returns:
576
1012
  ApiResponse with RunBulkCreateResponse containing:
@@ -675,7 +1111,12 @@ class TrajectoriesAPI:
675
1111
  self,
676
1112
  skip: Optional[int] = None,
677
1113
  limit: Optional[int] = None,
678
- workflow_id: Optional[str] = None
1114
+ workflow_id: Optional[str] = None,
1115
+ *,
1116
+ created_at_from: Optional[Union[str, datetime]] = None,
1117
+ created_at_to: Optional[Union[str, datetime]] = None,
1118
+ updated_at_from: Optional[Union[str, datetime]] = None,
1119
+ updated_at_to: Optional[Union[str, datetime]] = None,
679
1120
  ) -> ApiResponse:
680
1121
  """List trajectories with optional filtering."""
681
1122
  try:
@@ -683,7 +1124,11 @@ class TrajectoriesAPI:
683
1124
  client=self.client,
684
1125
  skip=_to_unset_or_value(skip),
685
1126
  limit=_to_unset_or_value(limit),
686
- workflow_id=_to_uuid(workflow_id) if workflow_id else UNSET
1127
+ workflow_id=_to_uuid(workflow_id) if workflow_id else UNSET,
1128
+ created_at_from=_to_unset_or_value(_to_iso_utc_str(created_at_from)),
1129
+ created_at_to=_to_unset_or_value(_to_iso_utc_str(created_at_to)),
1130
+ updated_at_from=_to_unset_or_value(_to_iso_utc_str(updated_at_from)),
1131
+ updated_at_to=_to_unset_or_value(_to_iso_utc_str(updated_at_to)),
687
1132
  )
688
1133
  return ApiResponse(data=response)
689
1134
  except Exception as e:
@@ -693,7 +1138,12 @@ class TrajectoriesAPI:
693
1138
  self,
694
1139
  skip: Optional[int] = None,
695
1140
  limit: Optional[int] = None,
696
- workflow_id: Optional[str] = None
1141
+ workflow_id: Optional[str] = None,
1142
+ *,
1143
+ created_at_from: Optional[Union[str, datetime]] = None,
1144
+ created_at_to: Optional[Union[str, datetime]] = None,
1145
+ updated_at_from: Optional[Union[str, datetime]] = None,
1146
+ updated_at_to: Optional[Union[str, datetime]] = None,
697
1147
  ) -> ApiResponse:
698
1148
  """List trajectories with optional filtering (synchronous)."""
699
1149
  try:
@@ -701,7 +1151,11 @@ class TrajectoriesAPI:
701
1151
  client=self.client,
702
1152
  skip=_to_unset_or_value(skip),
703
1153
  limit=_to_unset_or_value(limit),
704
- workflow_id=_to_uuid(workflow_id) if workflow_id else UNSET
1154
+ workflow_id=_to_uuid(workflow_id) if workflow_id else UNSET,
1155
+ created_at_from=_to_unset_or_value(_to_iso_utc_str(created_at_from)),
1156
+ created_at_to=_to_unset_or_value(_to_iso_utc_str(created_at_to)),
1157
+ updated_at_from=_to_unset_or_value(_to_iso_utc_str(updated_at_from)),
1158
+ updated_at_to=_to_unset_or_value(_to_iso_utc_str(updated_at_to)),
705
1159
  )
706
1160
  return ApiResponse(data=response)
707
1161
  except Exception as e:
@@ -1173,6 +1627,7 @@ class CyberdeskClient:
1173
1627
 
1174
1628
  # Initialize API endpoints
1175
1629
  self.machines = MachinesAPI(self._client)
1630
+ self.pools = PoolsAPI(self._client)
1176
1631
  self.workflows = WorkflowsAPI(self._client)
1177
1632
  self.runs = RunsAPI(self._client)
1178
1633
  self.connections = ConnectionsAPI(self._client)