fleet-python 0.2.42__py3-none-any.whl → 0.2.43__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 fleet-python might be problematic. Click here for more details.

fleet/_async/client.py CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  """Fleet API Client for making HTTP requests to Fleet services."""
16
16
 
17
+ import asyncio
17
18
  import base64
18
19
  import cloudpickle
19
20
  import httpx
@@ -206,24 +207,39 @@ class AsyncFleet:
206
207
  async def make(
207
208
  self,
208
209
  env_key: str,
210
+ data_key: Optional[str] = None,
209
211
  region: Optional[str] = None,
210
212
  env_variables: Optional[Dict[str, Any]] = None,
211
213
  ) -> AsyncEnv:
212
214
  if ":" in env_key:
213
- env_key_part, version = env_key.split(":", 1)
215
+ env_key_part, env_version = env_key.split(":", 1)
214
216
  if (
215
- not version.startswith("v")
216
- and len(version) != 0
217
- and version[0].isdigit()
217
+ not env_version.startswith("v")
218
+ and len(env_version) != 0
219
+ and env_version[0].isdigit()
218
220
  ):
219
- version = f"v{version}"
221
+ env_version = f"v{env_version}"
220
222
  else:
221
223
  env_key_part = env_key
222
- version = None
224
+ env_version = None
225
+
226
+ if data_key is not None and ":" in data_key:
227
+ data_key_part, data_version = data_key.split(":", 1)
228
+ if (
229
+ not data_version.startswith("v")
230
+ and len(data_version) != 0
231
+ and data_version[0].isdigit()
232
+ ):
233
+ data_version = f"v{data_version}"
234
+ else:
235
+ data_key_part = data_key
236
+ data_version = None
223
237
 
224
238
  request = InstanceRequest(
225
239
  env_key=env_key_part,
226
- version=version,
240
+ env_version=env_version,
241
+ data_key=data_key_part,
242
+ data_version=data_version,
227
243
  region=region,
228
244
  env_variables=env_variables,
229
245
  created_from="sdk",
@@ -286,7 +302,7 @@ class AsyncFleet:
286
302
  with open(filename, "r", encoding="utf-8") as f:
287
303
  tasks_data = f.read()
288
304
 
289
- return self.load_task_array_from_string(tasks_data)
305
+ return await self.load_task_array_from_string(tasks_data)
290
306
 
291
307
  async def load_task_array_from_string(
292
308
  self, serialized_tasks: List[Dict]
@@ -295,18 +311,19 @@ class AsyncFleet:
295
311
 
296
312
  json_tasks = json.loads(serialized_tasks)
297
313
  for json_task in json_tasks:
298
- parsed_task = self.load_task_from_json(json_task)
314
+ parsed_task = await self.load_task_from_json(json_task)
299
315
  tasks.append(parsed_task)
300
316
  return tasks
301
317
 
302
318
  async def load_task_from_string(self, task_string: str) -> Task:
303
319
  task_json = json.loads(task_string)
304
- return self.load_task_from_json(task_json)
320
+ return await self.load_task_from_json(task_json)
305
321
 
306
322
  async def load_task_from_json(self, task_json: Dict) -> Task:
323
+ verifier = None
307
324
  try:
308
325
  if "verifier_id" in task_json and task_json["verifier_id"]:
309
- verifier = self._create_verifier_from_data(
326
+ verifier = await self._create_verifier_from_data(
310
327
  verifier_id=task_json["verifier_id"],
311
328
  verifier_key=task_json["key"],
312
329
  verifier_code=task_json["verifier_func"],
@@ -357,48 +374,99 @@ class AsyncFleet:
357
374
  response = await self.client.request("GET", "/v1/tasks", params=params)
358
375
  task_list_response = TaskListResponse(**response.json())
359
376
 
360
- # Transform TaskResponse objects to Task objects
361
- tasks = []
362
- for task_response in task_list_response.tasks:
363
- # Create verifier function if verifier data is present
364
- verifier = None
365
- verifier_func = task_response.verifier_func
377
+ # Prepare verifier loading coroutines with concurrency limit
378
+ verifier_coroutines = []
379
+ task_responses_with_indices = []
380
+ semaphore = asyncio.Semaphore(10) # Limit to 10 concurrent operations
366
381
 
382
+ for idx, task_response in enumerate(task_list_response.tasks):
367
383
  if task_response.verifier:
368
384
  embedded_code = task_response.verifier.code or ""
369
385
  is_embedded_error = embedded_code.strip().startswith(
370
386
  "<error loading code:"
371
387
  )
372
- if not is_embedded_error:
373
- # Only override if the embedded code looks valid
374
- verifier_func = embedded_code
375
- # Create VerifierFunction from the embedded data
376
- try:
377
- verifier = await self._create_verifier_from_data(
378
- verifier_id=task_response.verifier.verifier_id,
379
- verifier_key=task_response.verifier.key,
380
- verifier_code=embedded_code,
381
- verifier_sha=task_response.verifier.sha256,
382
- )
383
- except Exception as e:
384
- logger.warning(
385
- f"Failed to create verifier {task_response.verifier.key}: {e}"
386
- )
387
- else:
388
- # Fallback: try fetching by ID if embedded code failed to load
389
- try:
390
- logger.warning(
391
- f"Embedded verifier code missing for {task_response.verifier.key} (NoSuchKey). "
392
- f"Attempting to refetch by id {task_response.verifier.verifier_id}"
393
- )
394
- verifier = await self._load_verifier(
395
- task_response.verifier.verifier_id
396
- )
397
- except Exception as e:
398
- logger.warning(
399
- f"Refetch by verifier id failed for {task_response.verifier.key}: {e}. "
400
- "Leaving verifier unset."
401
- )
388
+
389
+ async def create_verifier_with_fallback(tr, emb_code, is_error):
390
+ """Create verifier with fallback logic."""
391
+ async with semaphore: # Acquire semaphore before operation
392
+ if not is_error:
393
+ # Try to create from embedded data
394
+ try:
395
+ return await self._create_verifier_from_data(
396
+ verifier_id=tr.verifier.verifier_id,
397
+ verifier_key=tr.verifier.key,
398
+ verifier_code=emb_code,
399
+ verifier_sha=tr.verifier.sha256,
400
+ )
401
+ except Exception as e:
402
+ logger.warning(
403
+ f"Failed to create verifier {tr.verifier.key}: {e}"
404
+ )
405
+ return None
406
+ else:
407
+ # Fallback: try fetching by ID
408
+ try:
409
+ logger.warning(
410
+ f"Embedded verifier code missing for {tr.verifier.key} (NoSuchKey). "
411
+ f"Attempting to refetch by id {tr.verifier.verifier_id}"
412
+ )
413
+ return await self._load_verifier(
414
+ tr.verifier.verifier_id
415
+ )
416
+ except Exception as e:
417
+ logger.warning(
418
+ f"Refetch by verifier id failed for {tr.verifier.key}: {e}. "
419
+ "Leaving verifier unset."
420
+ )
421
+ return None
422
+
423
+ # Add the coroutine for parallel execution
424
+ verifier_coroutines.append(
425
+ create_verifier_with_fallback(
426
+ task_response, embedded_code, is_embedded_error
427
+ )
428
+ )
429
+ task_responses_with_indices.append((idx, task_response))
430
+ else:
431
+ # No verifier needed
432
+ verifier_coroutines.append(None)
433
+ task_responses_with_indices.append((idx, task_response))
434
+
435
+ # Execute all verifier loading in parallel
436
+ if verifier_coroutines:
437
+ verifier_results = await asyncio.gather(
438
+ *[
439
+ coro if coro is not None else asyncio.sleep(0)
440
+ for coro in verifier_coroutines
441
+ ],
442
+ return_exceptions=True,
443
+ )
444
+ else:
445
+ verifier_results = []
446
+
447
+ # Build tasks with results
448
+ tasks = []
449
+ for (idx, task_response), verifier_result in zip(
450
+ task_responses_with_indices, verifier_results
451
+ ):
452
+ # Handle verifier result
453
+ verifier = None
454
+ verifier_func = task_response.verifier_func
455
+
456
+ if task_response.verifier:
457
+ # Process verifier result
458
+ if isinstance(verifier_result, Exception):
459
+ logger.warning(
460
+ f"Verifier loading failed for {task_response.key}: {verifier_result}"
461
+ )
462
+ elif verifier_result is not None:
463
+ verifier = verifier_result
464
+ embedded_code = task_response.verifier.code or ""
465
+ is_embedded_error = embedded_code.strip().startswith(
466
+ "<error loading code:"
467
+ )
468
+ if not is_embedded_error:
469
+ verifier_func = embedded_code
402
470
 
403
471
  task = Task(
404
472
  key=task_response.key,
@@ -507,7 +575,7 @@ class AsyncFleet:
507
575
  self,
508
576
  task_key: str,
509
577
  prompt: Optional[str] = None,
510
- verifier_code: Optional[str] = None
578
+ verifier_code: Optional[str] = None,
511
579
  ) -> TaskResponse:
512
580
  """Update an existing task.
513
581
 
@@ -519,10 +587,7 @@ class AsyncFleet:
519
587
  Returns:
520
588
  TaskResponse containing the updated task details
521
589
  """
522
- payload = TaskUpdateRequest(
523
- prompt=prompt,
524
- verifier_code=verifier_code
525
- )
590
+ payload = TaskUpdateRequest(prompt=prompt, verifier_code=verifier_code)
526
591
  response = await self.client.request(
527
592
  "PUT", f"/v1/tasks/{task_key}", json=payload.model_dump(exclude_none=True)
528
593
  )
@@ -542,8 +607,7 @@ class AsyncFleet:
542
607
  Returns:
543
608
  AsyncVerifierFunction created from the verifier code
544
609
  """
545
- from ..tasks import verifier_from_string
546
- from .verifiers.verifier import AsyncVerifierFunction
610
+ from .tasks import verifier_from_string
547
611
 
548
612
  # Use verifier_from_string to create the verifier
549
613
  verifier_func = verifier_from_string(
@@ -3,8 +3,15 @@ from ...models import Environment as EnvironmentModel, AccountResponse
3
3
  from typing import List, Optional, Dict, Any
4
4
 
5
5
 
6
- async def make_async(env_key: str, region: Optional[str] = None, env_variables: Optional[Dict[str, Any]] = None) -> AsyncEnv:
7
- return await AsyncFleet().make(env_key, region=region, env_variables=env_variables)
6
+ async def make_async(
7
+ env_key: str,
8
+ data_key: Optional[str] = None,
9
+ region: Optional[str] = None,
10
+ env_variables: Optional[Dict[str, Any]] = None,
11
+ ) -> AsyncEnv:
12
+ return await AsyncFleet().make(
13
+ env_key, data_key=data_key, region=region, env_variables=env_variables
14
+ )
8
15
 
9
16
 
10
17
  async def make_for_task_async(task: Task) -> AsyncEnv:
fleet/_async/tasks.py CHANGED
@@ -2,10 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import re
6
5
  from datetime import datetime
7
6
  from typing import Any, Dict, Optional, List
8
- from uuid import UUID
9
7
 
10
8
  from pydantic import BaseModel, Field, validator
11
9
 
@@ -46,7 +44,7 @@ class Task(BaseModel):
46
44
  @property
47
45
  def env_key(self) -> str:
48
46
  """Get the environment key combining env_id and version."""
49
- if self.version:
47
+ if self.version and self.version != "None":
50
48
  return f"{self.env_id}:{self.version}"
51
49
  return self.env_id
52
50
 
@@ -75,7 +73,7 @@ class Task(BaseModel):
75
73
  if inspect.iscoroutine(result):
76
74
  # Check if we're already in an event loop
77
75
  try:
78
- loop = asyncio.get_running_loop()
76
+ asyncio.get_running_loop()
79
77
  # We're in an async context, can't use asyncio.run()
80
78
  raise RuntimeError(
81
79
  "Cannot run async verifier in sync mode while event loop is running. "
@@ -121,58 +119,57 @@ class Task(BaseModel):
121
119
 
122
120
 
123
121
  def verifier_from_string(
124
- verifier_func: str,
125
- verifier_id: str,
126
- verifier_key: str,
127
- sha256: str = ""
128
- ) -> 'VerifierFunction':
122
+ verifier_func: str, verifier_id: str, verifier_key: str, sha256: str = ""
123
+ ) -> "VerifierFunction":
129
124
  """Create a verifier function from string code.
130
-
125
+
131
126
  Args:
132
127
  verifier_func: The verifier function code as a string
133
128
  verifier_id: Unique identifier for the verifier
134
129
  verifier_key: Key/name for the verifier
135
130
  sha256: SHA256 hash of the verifier code
136
-
131
+
137
132
  Returns:
138
133
  VerifierFunction instance that can be used to verify tasks
139
134
  """
140
135
  try:
141
136
  import inspect
142
- from .verifiers import verifier, AsyncVerifierFunction
137
+ from .verifiers.verifier import AsyncVerifierFunction
143
138
  from fleet.verifiers.code import TASK_SUCCESSFUL_SCORE, TASK_FAILED_SCORE
144
139
  from fleet.verifiers.db import IgnoreConfig
145
-
140
+
146
141
  # Create a local namespace for executing the code
147
142
  local_namespace = {
148
- 'TASK_SUCCESSFUL_SCORE': TASK_SUCCESSFUL_SCORE,
149
- 'TASK_FAILED_SCORE': TASK_FAILED_SCORE,
150
- 'IgnoreConfig': IgnoreConfig,
151
- 'Environment': object # Add Environment type if needed
143
+ "TASK_SUCCESSFUL_SCORE": TASK_SUCCESSFUL_SCORE,
144
+ "TASK_FAILED_SCORE": TASK_FAILED_SCORE,
145
+ "IgnoreConfig": IgnoreConfig,
146
+ "Environment": object, # Add Environment type if needed
152
147
  }
153
-
148
+
154
149
  # Execute the verifier code in the namespace
155
150
  exec(verifier_func, globals(), local_namespace)
156
-
151
+
157
152
  # Find the function that was defined
158
153
  func_obj = None
159
154
  for name, obj in local_namespace.items():
160
155
  if inspect.isfunction(obj):
161
156
  func_obj = obj
162
157
  break
163
-
158
+
164
159
  if func_obj is None:
165
160
  raise ValueError("No function found in verifier code")
166
-
167
- # Create an AsyncVerifierFunction instance
168
- verifier_instance = AsyncVerifierFunction(func_obj, verifier_key, verifier_id)
169
-
170
- # Store additional metadata
171
- verifier_instance._verifier_code = verifier_func
172
- verifier_instance._sha256 = sha256
173
-
161
+
162
+ # Create an AsyncVerifierFunction instance with raw code
163
+ verifier_instance = AsyncVerifierFunction(
164
+ func_obj,
165
+ verifier_key,
166
+ verifier_id=verifier_id,
167
+ sha256=sha256,
168
+ raw_code=verifier_func,
169
+ )
170
+
174
171
  return verifier_instance
175
-
172
+
176
173
  except Exception as e:
177
174
  raise ValueError(f"Failed to create verifier from string: {e}")
178
175
 
@@ -181,7 +178,7 @@ async def load_tasks(
181
178
  env_key: Optional[str] = None,
182
179
  keys: Optional[List[str]] = None,
183
180
  version: Optional[str] = None,
184
- team_id: Optional[str] = None
181
+ team_id: Optional[str] = None,
185
182
  ) -> List[Task]:
186
183
  """Convenience function to load tasks with optional filtering.
187
184
 
@@ -201,17 +198,12 @@ async def load_tasks(
201
198
 
202
199
  client = get_client()
203
200
  return await client.load_tasks(
204
- env_key=env_key,
205
- keys=keys,
206
- version=version,
207
- team_id=team_id
201
+ env_key=env_key, keys=keys, version=version, team_id=team_id
208
202
  )
209
203
 
210
204
 
211
205
  async def update_task(
212
- task_key: str,
213
- prompt: Optional[str] = None,
214
- verifier_code: Optional[str] = None
206
+ task_key: str, prompt: Optional[str] = None, verifier_code: Optional[str] = None
215
207
  ):
216
208
  """Convenience function to update an existing task.
217
209
 
@@ -228,11 +220,8 @@ async def update_task(
228
220
  response = await fleet.update_task("my-task", verifier_code="def verify(env): return True")
229
221
  """
230
222
  from .global_client import get_client
231
- from ..models import TaskResponse
232
223
 
233
224
  client = get_client()
234
225
  return await client.update_task(
235
- task_key=task_key,
236
- prompt=prompt,
237
- verifier_code=verifier_code
226
+ task_key=task_key, prompt=prompt, verifier_code=verifier_code
238
227
  )
fleet/client.py CHANGED
@@ -16,6 +16,7 @@
16
16
 
17
17
  import base64
18
18
  import cloudpickle
19
+ import concurrent.futures
19
20
  import httpx
20
21
  import json
21
22
  import logging
@@ -206,24 +207,39 @@ class Fleet:
206
207
  def make(
207
208
  self,
208
209
  env_key: str,
210
+ data_key: Optional[str] = None,
209
211
  region: Optional[str] = None,
210
212
  env_variables: Optional[Dict[str, Any]] = None,
211
213
  ) -> SyncEnv:
212
214
  if ":" in env_key:
213
- env_key_part, version = env_key.split(":", 1)
215
+ env_key_part, env_version = env_key.split(":", 1)
214
216
  if (
215
- not version.startswith("v")
216
- and len(version) != 0
217
- and version[0].isdigit()
217
+ not env_version.startswith("v")
218
+ and len(env_version) != 0
219
+ and env_version[0].isdigit()
218
220
  ):
219
- version = f"v{version}"
221
+ env_version = f"v{env_version}"
220
222
  else:
221
223
  env_key_part = env_key
222
- version = None
224
+ env_version = None
225
+
226
+ if data_key is not None and ":" in data_key:
227
+ data_key_part, data_version = data_key.split(":", 1)
228
+ if (
229
+ not data_version.startswith("v")
230
+ and len(data_version) != 0
231
+ and data_version[0].isdigit()
232
+ ):
233
+ data_version = f"v{data_version}"
234
+ else:
235
+ data_key_part = data_key
236
+ data_version = None
223
237
 
224
238
  request = InstanceRequest(
225
239
  env_key=env_key_part,
226
- version=version,
240
+ env_version=env_version,
241
+ data_key=data_key_part,
242
+ data_version=data_version,
227
243
  region=region,
228
244
  env_variables=env_variables,
229
245
  created_from="sdk",
@@ -353,48 +369,107 @@ class Fleet:
353
369
  response = self.client.request("GET", "/v1/tasks", params=params)
354
370
  task_list_response = TaskListResponse(**response.json())
355
371
 
356
- # Transform TaskResponse objects to Task objects
357
- tasks = []
358
- for task_response in task_list_response.tasks:
359
- # Create verifier function if verifier data is present
360
- verifier = None
361
- verifier_func = task_response.verifier_func
372
+ # Prepare verifier loading tasks
373
+ verifier_tasks = []
374
+ task_responses_with_indices = []
362
375
 
376
+ for idx, task_response in enumerate(task_list_response.tasks):
363
377
  if task_response.verifier:
364
378
  embedded_code = task_response.verifier.code or ""
365
379
  is_embedded_error = embedded_code.strip().startswith(
366
380
  "<error loading code:"
367
381
  )
368
- if not is_embedded_error:
369
- # Only override if the embedded code looks valid
370
- verifier_func = embedded_code
371
- # Create VerifierFunction from the embedded data
372
- try:
373
- verifier = self._create_verifier_from_data(
374
- verifier_id=task_response.verifier.verifier_id,
375
- verifier_key=task_response.verifier.key,
376
- verifier_code=embedded_code,
377
- verifier_sha=task_response.verifier.sha256,
378
- )
379
- except Exception as e:
380
- logger.warning(
381
- f"Failed to create verifier {task_response.verifier.key}: {e}"
382
- )
383
- else:
384
- # Fallback: try fetching by ID if embedded code failed to load
385
- try:
386
- logger.warning(
387
- f"Embedded verifier code missing for {task_response.verifier.key} (NoSuchKey). "
388
- f"Attempting to refetch by id {task_response.verifier.verifier_id}"
389
- )
390
- verifier = self._load_verifier(
391
- task_response.verifier.verifier_id
392
- )
393
- except Exception as e:
394
- logger.warning(
395
- f"Refetch by verifier id failed for {task_response.verifier.key}: {e}. "
396
- "Leaving verifier unset."
397
- )
382
+
383
+ def create_verifier_with_fallback(tr, emb_code, is_error):
384
+ """Create verifier with fallback logic."""
385
+ if not is_error:
386
+ # Try to create from embedded data
387
+ try:
388
+ return self._create_verifier_from_data(
389
+ verifier_id=tr.verifier.verifier_id,
390
+ verifier_key=tr.verifier.key,
391
+ verifier_code=emb_code,
392
+ verifier_sha=tr.verifier.sha256,
393
+ )
394
+ except Exception as e:
395
+ logger.warning(
396
+ f"Failed to create verifier {tr.verifier.key}: {e}"
397
+ )
398
+ return None
399
+ else:
400
+ # Fallback: try fetching by ID
401
+ try:
402
+ logger.warning(
403
+ f"Embedded verifier code missing for {tr.verifier.key} (NoSuchKey). "
404
+ f"Attempting to refetch by id {tr.verifier.verifier_id}"
405
+ )
406
+ return self._load_verifier(tr.verifier.verifier_id)
407
+ except Exception as e:
408
+ logger.warning(
409
+ f"Refetch by verifier id failed for {tr.verifier.key}: {e}. "
410
+ "Leaving verifier unset."
411
+ )
412
+ return None
413
+
414
+ # Add the task for parallel execution
415
+ verifier_tasks.append(
416
+ (
417
+ create_verifier_with_fallback,
418
+ task_response,
419
+ embedded_code,
420
+ is_embedded_error,
421
+ )
422
+ )
423
+ task_responses_with_indices.append((idx, task_response))
424
+ else:
425
+ # No verifier needed
426
+ verifier_tasks.append(None)
427
+ task_responses_with_indices.append((idx, task_response))
428
+
429
+ # Execute all verifier loading in parallel using ThreadPoolExecutor
430
+ verifier_results = []
431
+ if verifier_tasks:
432
+ with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
433
+ futures = []
434
+ for task in verifier_tasks:
435
+ if task is not None:
436
+ func, tr, emb_code, is_error = task
437
+ future = executor.submit(func, tr, emb_code, is_error)
438
+ futures.append(future)
439
+ else:
440
+ futures.append(None)
441
+
442
+ # Collect results
443
+ for future in futures:
444
+ if future is None:
445
+ verifier_results.append(None)
446
+ else:
447
+ try:
448
+ result = future.result()
449
+ verifier_results.append(result)
450
+ except Exception as e:
451
+ logger.warning(f"Verifier loading failed: {e}")
452
+ verifier_results.append(None)
453
+
454
+ # Build tasks with results
455
+ tasks = []
456
+ for (idx, task_response), verifier_result in zip(
457
+ task_responses_with_indices, verifier_results
458
+ ):
459
+ # Handle verifier result
460
+ verifier = None
461
+ verifier_func = task_response.verifier_func
462
+
463
+ if task_response.verifier:
464
+ # Process verifier result
465
+ if verifier_result is not None:
466
+ verifier = verifier_result
467
+ embedded_code = task_response.verifier.code or ""
468
+ is_embedded_error = embedded_code.strip().startswith(
469
+ "<error loading code:"
470
+ )
471
+ if not is_embedded_error:
472
+ verifier_func = embedded_code
398
473
 
399
474
  task = Task(
400
475
  key=task_response.key,
@@ -503,7 +578,7 @@ class Fleet:
503
578
  self,
504
579
  task_key: str,
505
580
  prompt: Optional[str] = None,
506
- verifier_code: Optional[str] = None
581
+ verifier_code: Optional[str] = None,
507
582
  ) -> TaskResponse:
508
583
  """Update an existing task.
509
584
 
@@ -515,10 +590,7 @@ class Fleet:
515
590
  Returns:
516
591
  TaskResponse containing the updated task details
517
592
  """
518
- payload = TaskUpdateRequest(
519
- prompt=prompt,
520
- verifier_code=verifier_code
521
- )
593
+ payload = TaskUpdateRequest(prompt=prompt, verifier_code=verifier_code)
522
594
  response = self.client.request(
523
595
  "PUT", f"/v1/tasks/{task_key}", json=payload.model_dump(exclude_none=True)
524
596
  )
fleet/env/client.py CHANGED
@@ -3,8 +3,15 @@ from ..models import Environment as EnvironmentModel, AccountResponse
3
3
  from typing import List, Optional, Dict, Any
4
4
 
5
5
 
6
- def make(env_key: str, region: Optional[str] = None, env_variables: Optional[Dict[str, Any]] = None) -> SyncEnv:
7
- return Fleet().make(env_key, region=region, env_variables=env_variables)
6
+ def make(
7
+ env_key: str,
8
+ data_key: Optional[str] = None,
9
+ region: Optional[str] = None,
10
+ env_variables: Optional[Dict[str, Any]] = None,
11
+ ) -> SyncEnv:
12
+ return Fleet().make(
13
+ env_key, data_key=data_key, region=region, env_variables=env_variables
14
+ )
8
15
 
9
16
 
10
17
  def make_for_task_async(task: Task) -> SyncEnv:
fleet/models.py CHANGED
@@ -55,7 +55,9 @@ class Instance(BaseModel):
55
55
 
56
56
  class InstanceRequest(BaseModel):
57
57
  env_key: str = Field(..., title="Env Key")
58
- version: Optional[str] = Field(None, title="Version")
58
+ env_version: Optional[str] = Field(None, title="Version")
59
+ data_key: Optional[str] = Field(None, title="Data Key")
60
+ data_version: Optional[str] = Field(None, title="Data Version")
59
61
  region: Optional[str] = Field("us-west-1", title="Region")
60
62
  seed: Optional[int] = Field(None, title="Seed")
61
63
  timestamp: Optional[int] = Field(None, title="Timestamp")
fleet/tasks.py CHANGED
@@ -47,7 +47,7 @@ class Task(BaseModel):
47
47
  @property
48
48
  def env_key(self) -> str:
49
49
  """Get the environment key combining env_id and version."""
50
- if self.version:
50
+ if self.version and self.version != "None":
51
51
  return f"{self.env_id}:{self.version}"
52
52
  return self.env_id
53
53
 
@@ -70,7 +70,7 @@ class Task(BaseModel):
70
70
  import inspect
71
71
 
72
72
  # Check if verifier has remote method (for decorated verifiers)
73
- if hasattr(self.verifier, 'remote'):
73
+ if hasattr(self.verifier, "remote"):
74
74
  result = self.verifier.remote(env, *args, **kwargs)
75
75
  else:
76
76
  # For verifiers created from string, call directly
@@ -126,19 +126,16 @@ class Task(BaseModel):
126
126
 
127
127
 
128
128
  def verifier_from_string(
129
- verifier_func: str,
130
- verifier_id: str,
131
- verifier_key: str,
132
- sha256: str = ""
133
- ) -> 'VerifierFunction':
129
+ verifier_func: str, verifier_id: str, verifier_key: str, sha256: str = ""
130
+ ) -> "VerifierFunction":
134
131
  """Create a verifier function from string code.
135
-
132
+
136
133
  Args:
137
134
  verifier_func: The verifier function code as a string
138
135
  verifier_id: Unique identifier for the verifier
139
136
  verifier_key: Key/name for the verifier
140
137
  sha256: SHA256 hash of the verifier code
141
-
138
+
142
139
  Returns:
143
140
  VerifierFunction instance that can be used to verify tasks
144
141
  """
@@ -147,63 +144,72 @@ def verifier_from_string(
147
144
  from .verifiers import verifier, SyncVerifierFunction
148
145
  from .verifiers.code import TASK_SUCCESSFUL_SCORE, TASK_FAILED_SCORE
149
146
  from .verifiers.db import IgnoreConfig
150
-
147
+
151
148
  # Create a globals namespace with all required imports
152
149
  exec_globals = globals().copy()
153
- exec_globals.update({
154
- 'TASK_SUCCESSFUL_SCORE': TASK_SUCCESSFUL_SCORE,
155
- 'TASK_FAILED_SCORE': TASK_FAILED_SCORE,
156
- 'IgnoreConfig': IgnoreConfig,
157
- 'Environment': object # Add Environment type if needed
158
- })
159
-
150
+ exec_globals.update(
151
+ {
152
+ "TASK_SUCCESSFUL_SCORE": TASK_SUCCESSFUL_SCORE,
153
+ "TASK_FAILED_SCORE": TASK_FAILED_SCORE,
154
+ "IgnoreConfig": IgnoreConfig,
155
+ "Environment": object, # Add Environment type if needed
156
+ }
157
+ )
158
+
160
159
  # Create a local namespace for executing the code
161
160
  local_namespace = {}
162
-
161
+
163
162
  # Execute the verifier code in the namespace
164
163
  exec(verifier_func, exec_globals, local_namespace)
165
-
164
+
166
165
  # Find the function that was defined
167
166
  func_obj = None
168
167
  for name, obj in local_namespace.items():
169
168
  if inspect.isfunction(obj):
170
169
  func_obj = obj
171
170
  break
172
-
171
+
173
172
  if func_obj is None:
174
173
  raise ValueError("No function found in verifier code")
175
-
174
+
176
175
  # Create a wrapper function that provides the necessary globals
177
176
  def wrapped_verifier(env, *args, **kwargs):
178
177
  # Set up globals for the function execution
179
- func_globals = func_obj.__globals__.copy() if hasattr(func_obj, '__globals__') else {}
180
- func_globals.update({
181
- 'TASK_SUCCESSFUL_SCORE': TASK_SUCCESSFUL_SCORE,
182
- 'TASK_FAILED_SCORE': TASK_FAILED_SCORE,
183
- 'IgnoreConfig': IgnoreConfig
184
- })
185
-
178
+ func_globals = (
179
+ func_obj.__globals__.copy() if hasattr(func_obj, "__globals__") else {}
180
+ )
181
+ func_globals.update(
182
+ {
183
+ "TASK_SUCCESSFUL_SCORE": TASK_SUCCESSFUL_SCORE,
184
+ "TASK_FAILED_SCORE": TASK_FAILED_SCORE,
185
+ "IgnoreConfig": IgnoreConfig,
186
+ }
187
+ )
188
+
186
189
  # Create a new function with the updated globals
187
190
  import types
191
+
188
192
  new_func = types.FunctionType(
189
193
  func_obj.__code__,
190
194
  func_globals,
191
195
  func_obj.__name__,
192
196
  func_obj.__defaults__,
193
- func_obj.__closure__
197
+ func_obj.__closure__,
194
198
  )
195
-
199
+
196
200
  return new_func(env, *args, **kwargs)
197
-
201
+
198
202
  # Create an AsyncVerifierFunction instance with the wrapped function
199
- verifier_instance = SyncVerifierFunction(wrapped_verifier, verifier_key, verifier_id)
200
-
203
+ verifier_instance = SyncVerifierFunction(
204
+ wrapped_verifier, verifier_key, verifier_id
205
+ )
206
+
201
207
  # Store additional metadata
202
208
  verifier_instance._verifier_code = verifier_func
203
209
  verifier_instance._sha256 = sha256
204
-
210
+
205
211
  return verifier_instance
206
-
212
+
207
213
  except Exception as e:
208
214
  raise ValueError(f"Failed to create verifier from string: {e}")
209
215
 
@@ -212,7 +218,7 @@ def load_tasks(
212
218
  env_key: Optional[str] = None,
213
219
  keys: Optional[List[str]] = None,
214
220
  version: Optional[str] = None,
215
- team_id: Optional[str] = None
221
+ team_id: Optional[str] = None,
216
222
  ) -> List[Task]:
217
223
  """Convenience function to load tasks with optional filtering.
218
224
 
@@ -232,17 +238,12 @@ def load_tasks(
232
238
 
233
239
  client = get_client()
234
240
  return client.load_tasks(
235
- env_key=env_key,
236
- keys=keys,
237
- version=version,
238
- team_id=team_id
241
+ env_key=env_key, keys=keys, version=version, team_id=team_id
239
242
  )
240
243
 
241
244
 
242
245
  def update_task(
243
- task_key: str,
244
- prompt: Optional[str] = None,
245
- verifier_code: Optional[str] = None
246
+ task_key: str, prompt: Optional[str] = None, verifier_code: Optional[str] = None
246
247
  ):
247
248
  """Convenience function to update an existing task.
248
249
 
@@ -263,7 +264,5 @@ def update_task(
263
264
 
264
265
  client = get_client()
265
266
  return client.update_task(
266
- task_key=task_key,
267
- prompt=prompt,
268
- verifier_code=verifier_code
267
+ task_key=task_key, prompt=prompt, verifier_code=verifier_code
269
268
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fleet-python
3
- Version: 0.2.42
3
+ Version: 0.2.43
4
4
  Summary: Python SDK for Fleet environments
5
5
  Author-email: Fleet AI <nic@fleet.so>
6
6
  License: Apache-2.0
@@ -21,22 +21,22 @@ examples/quickstart.py,sha256=1VT39IRRhemsJgxi0O0gprdpcw7HB4pYO97GAYagIcg,3788
21
21
  examples/test_cdp_logging.py,sha256=AkCwQCgOTQEI8w3v0knWK_4eXMph7L9x07wj9yIYM10,2836
22
22
  fleet/__init__.py,sha256=oxI2XvaiRMn15AZpoDHOvX26WlXALHXvqSRP0KkBpAY,3751
23
23
  fleet/base.py,sha256=bc-340sTpq_DJs7yQ9d2pDWnmJFmA1SwDB9Lagvqtb4,9182
24
- fleet/client.py,sha256=T9Tvhq4aTEs1MjTJw26TkvSMFtQSYEi2hCVu0mdRGxc,22931
24
+ fleet/client.py,sha256=d-sGsC8a68czfuaSSm8_Vrkzo-lvamDdwWiCYT2QttE,25865
25
25
  fleet/config.py,sha256=uY02ZKxVoXqVDta-0IMWaYJeE1CTXF_fA9NI6QUutmU,319
26
26
  fleet/exceptions.py,sha256=fUmPwWhnT8SR97lYsRq0kLHQHKtSh2eJS0VQ2caSzEI,5055
27
27
  fleet/global_client.py,sha256=frrDAFNM2ywN0JHLtlm9qbE1dQpnQJsavJpb7xSR_bU,1072
28
- fleet/models.py,sha256=li5Cii7ASUHCFMFeJIMklyicYczqPez768RxO0Q0F2o,12618
29
- fleet/tasks.py,sha256=TuPmCdgMnqBjJhqxLUL2CKgR0w-P5zNAPukHT_fQTyU,9575
28
+ fleet/models.py,sha256=WAiRXa68aXSVbCqmQMn36n9cSlls6YsicV6BbyoeiYQ,12750
29
+ fleet/tasks.py,sha256=P-qcbLZLMVGdJ02Rb8Q2kGIINdnZ_CNIu_FeCVcihcg,9573
30
30
  fleet/types.py,sha256=L4Y82xICf1tzyCLqhLYUgEoaIIS5h9T05TyFNHSWs3s,652
31
31
  fleet/_async/__init__.py,sha256=lrnDD6N9p0Oqpi_djxTnxh8I5F7nA7KNn0khciGmgpg,6747
32
32
  fleet/_async/base.py,sha256=oisVTQsx0M_yTmyQJc3oij63uKZ97MHz-xYFsWXxQE8,9202
33
- fleet/_async/client.py,sha256=Etpho0Vvovv8l7Y4HFE2KGBb64rdE-LefFXux9QcWeI,23438
33
+ fleet/_async/client.py,sha256=4nwpX933fIutctwictasU8oJODwP63vRT0FJxd1b_Do,26170
34
34
  fleet/_async/exceptions.py,sha256=fUmPwWhnT8SR97lYsRq0kLHQHKtSh2eJS0VQ2caSzEI,5055
35
35
  fleet/_async/global_client.py,sha256=4WskpLHbsDEgWW7hXMD09W-brkp4euy8w2ZJ88594rQ,1103
36
36
  fleet/_async/models.py,sha256=li5Cii7ASUHCFMFeJIMklyicYczqPez768RxO0Q0F2o,12618
37
- fleet/_async/tasks.py,sha256=8r1jg_r-YpHCezsqlXKoT5RxBelyqax85iwG0kublPc,8317
37
+ fleet/_async/tasks.py,sha256=QZFQNW4_Iq2VbGZiPXzKDFXmNrxe4mn-ROGvpGhN7pw,8131
38
38
  fleet/_async/env/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
- fleet/_async/env/client.py,sha256=9GOSkEWNncwTtiZNaJ2vNGrFCPutyan9lBNhD87dAzQ,1059
39
+ fleet/_async/env/client.py,sha256=8dS42VvSgdqfuh96l6cyiLZlKElilmfTeRSZ4LZnFuE,1143
40
40
  fleet/_async/instance/__init__.py,sha256=PtmJq8J8bh0SOQ2V55QURz5GJfobozwtQoqhaOk3_tI,515
41
41
  fleet/_async/instance/base.py,sha256=3qUBuUR8OVS36LzdP6KyZzngtwPKYO09HoY6Ekxp-KA,1625
42
42
  fleet/_async/instance/client.py,sha256=z9q_-dIBwPc1X6VlQOi_aV2v6KOKueJGg8NMyP5iFQM,6082
@@ -49,7 +49,7 @@ fleet/_async/verifiers/__init__.py,sha256=1WTlCNq4tIFbbXaQu5Bf2WppZq0A8suhtZbxMT
49
49
  fleet/_async/verifiers/bundler.py,sha256=Sq0KkqEhM5Ng2x8R6Z4puXvQ8FMlEO7D3-ldBLktPi4,26205
50
50
  fleet/_async/verifiers/verifier.py,sha256=lwVIV5ZpWJhM87tXShtjwN5KP7n5XDcPq0XX7AjV6_E,14343
51
51
  fleet/env/__init__.py,sha256=cS9zCYobM5jypppDMZIQMYd6hOg5f4sgqRXEQ67pckk,676
52
- fleet/env/client.py,sha256=wvZbmHdftkuhAgpzOGiA4Yl_Th9BUIHFR_6JUYg6Nc8,893
52
+ fleet/env/client.py,sha256=imF47xJG4JeihcZw4Y-_fXz4XxS-OgIkzUK-TLjpeJY,977
53
53
  fleet/instance/__init__.py,sha256=CyWUkbGAK-DBPw4DC4AnCW-MqqheGhZMA5QSRVu-ws4,479
54
54
  fleet/instance/base.py,sha256=OYqzBwZFfTX9wlBGSG5gljqj98NbiJeKIfFJ3uj5I4s,1587
55
55
  fleet/instance/client.py,sha256=O6B0A2Z0b5SxOLs4TipZ9Ol8yG-b-LG15vVOKMmd6BQ,5908
@@ -67,10 +67,10 @@ fleet/verifiers/decorator.py,sha256=nAP3O8szXu7md_kpwpz91hGSUNEVLYjwZQZTkQlV1DM,
67
67
  fleet/verifiers/parse.py,sha256=0bAbj9VvT__yU4ZVREUK-Tn9dukh9LCpmfVsgj1DfP4,8508
68
68
  fleet/verifiers/sql_differ.py,sha256=dmiGCFXVMEMbAX519OjhVqgA8ZvhnvdmC1BVpL7QCF0,6490
69
69
  fleet/verifiers/verifier.py,sha256=53oBWAf0yy3bZmZx9eH9AWIf65H7OP2UUm0YwWCL6Mc,14286
70
- fleet_python-0.2.42.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
70
+ fleet_python-0.2.43.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
71
71
  scripts/fix_sync_imports.py,sha256=X9fWLTpiPGkSHsjyQUDepOJkxOqw1DPj7nd8wFlFqLQ,8368
72
72
  scripts/unasync.py,sha256=vWVQxRWX8SRZO5cmzEhpvnG_REhCWXpidIGIpWmEcvI,696
73
- fleet_python-0.2.42.dist-info/METADATA,sha256=DW1jtGvGk6pKaOmWaBNBPMG0-BxpSUnGLg8DWOIMkqU,3304
74
- fleet_python-0.2.42.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
- fleet_python-0.2.42.dist-info/top_level.txt,sha256=_3DSmTohvSDf3AIP_BYfGzhwO1ECFwuzg83X-wHCx3Y,23
76
- fleet_python-0.2.42.dist-info/RECORD,,
73
+ fleet_python-0.2.43.dist-info/METADATA,sha256=fgD6_tIyLKKOXNT_qoyf98t12w3ITDd1vAyCYFh7_KU,3304
74
+ fleet_python-0.2.43.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
+ fleet_python-0.2.43.dist-info/top_level.txt,sha256=_3DSmTohvSDf3AIP_BYfGzhwO1ECFwuzg83X-wHCx3Y,23
76
+ fleet_python-0.2.43.dist-info/RECORD,,