fleet-python 0.2.116__tar.gz → 0.2.117__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fleet_python-0.2.116/fleet_python.egg-info → fleet_python-0.2.117}/PKG-INFO +1 -1
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/__init__.py +5 -1
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/__init__.py +1 -1
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/base.py +1 -1
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/client.py +39 -1
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/base.py +1 -1
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/client.py +36 -1
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/verifiers/__init__.py +3 -0
- fleet_python-0.2.117/fleet/verifiers/local_executor.py +247 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117/fleet_python.egg-info}/PKG-INFO +1 -1
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet_python.egg-info/SOURCES.txt +1 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/pyproject.toml +1 -1
- {fleet_python-0.2.116 → fleet_python-0.2.117}/LICENSE +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/README.md +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/diff_example.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/dsl_example.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/exampleResume.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example_account.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example_action_log.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example_client.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example_mcp_anthropic.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example_mcp_openai.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example_sync.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example_task.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example_tasks.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/example_verifier.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/export_tasks.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/export_tasks_filtered.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/fetch_tasks.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/gemini_example.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/import_tasks.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/iterate_verifiers.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/json_tasks_example.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/nova_act_example.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/openai_example.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/openai_simple_example.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/query_builder_example.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/quickstart.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/examples/test_cdp_logging.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/env/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/env/client.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/exceptions.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/global_client.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/instance/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/instance/base.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/instance/client.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/judge.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/models.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/resources/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/resources/api.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/resources/base.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/resources/browser.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/resources/filesystem.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/resources/mcp.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/resources/sqlite.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/tasks.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/verifiers/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/verifiers/bundler.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/_async/verifiers/verifier.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/gemini_cua/Dockerfile +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/gemini_cua/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/gemini_cua/agent.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/gemini_cua/mcp/main.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/gemini_cua/mcp_server/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/gemini_cua/mcp_server/main.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/gemini_cua/mcp_server/tools.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/gemini_cua/requirements.txt +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/gemini_cua/start.sh +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/orchestrator.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/types.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/agent/utils.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/cli.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/config.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/env/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/env/client.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/eval/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/eval/uploader.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/exceptions.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/global_client.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/instance/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/instance/base.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/instance/client.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/instance/models.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/judge.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/models.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/proxy/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/proxy/proxy.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/proxy/whitelist.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/resources/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/resources/api.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/resources/base.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/resources/browser.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/resources/filesystem.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/resources/mcp.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/resources/sqlite.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/tasks.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/types.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/utils/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/utils/http_logging.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/utils/logging.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/utils/playwright.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/verifiers/bundler.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/verifiers/code.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/verifiers/db.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/verifiers/decorator.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/verifiers/parse.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/verifiers/sql_differ.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet/verifiers/verifier.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet_python.egg-info/dependency_links.txt +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet_python.egg-info/entry_points.txt +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet_python.egg-info/requires.txt +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/fleet_python.egg-info/top_level.txt +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/scripts/fix_sync_imports.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/scripts/unasync.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/setup.cfg +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/tests/__init__.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/tests/test_app_method.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/tests/test_expect_exactly.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/tests/test_expect_only.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/tests/test_instance_dispatch.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/tests/test_judge_criteria_markers.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/tests/test_sqlite_resource_dual_mode.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/tests/test_sqlite_shared_memory_behavior.py +0 -0
- {fleet_python-0.2.116 → fleet_python-0.2.117}/tests/test_verifier_from_string.py +0 -0
|
@@ -38,6 +38,8 @@ from .verifiers import (
|
|
|
38
38
|
SnapshotDiff,
|
|
39
39
|
TASK_FAILED_SCORE,
|
|
40
40
|
TASK_SUCCESSFUL_SCORE,
|
|
41
|
+
execute_verifier_local,
|
|
42
|
+
LocalEnvironment,
|
|
41
43
|
)
|
|
42
44
|
|
|
43
45
|
# Import async verifiers (default verifier is async for modern usage)
|
|
@@ -76,7 +78,7 @@ from . import env
|
|
|
76
78
|
from . import global_client as _global_client
|
|
77
79
|
from ._async import global_client as _async_global_client
|
|
78
80
|
|
|
79
|
-
__version__ = "0.2.
|
|
81
|
+
__version__ = "0.2.117"
|
|
80
82
|
|
|
81
83
|
__all__ = [
|
|
82
84
|
# Core classes
|
|
@@ -114,6 +116,8 @@ __all__ = [
|
|
|
114
116
|
"SnapshotDiff",
|
|
115
117
|
"TASK_FAILED_SCORE",
|
|
116
118
|
"TASK_SUCCESSFUL_SCORE",
|
|
119
|
+
"execute_verifier_local",
|
|
120
|
+
"LocalEnvironment",
|
|
117
121
|
# Environment module
|
|
118
122
|
"env",
|
|
119
123
|
# Global client helpers
|
|
@@ -832,7 +832,45 @@ class AsyncFleet:
|
|
|
832
832
|
At least one of run_id or profile_id must be provided.
|
|
833
833
|
"""
|
|
834
834
|
return await _delete_instances_batch(self.client, run_id=run_id, profile_id=profile_id)
|
|
835
|
-
|
|
835
|
+
|
|
836
|
+
@staticmethod
|
|
837
|
+
async def execute_verifier_local(
|
|
838
|
+
verifier_func: str,
|
|
839
|
+
seed_db: str,
|
|
840
|
+
current_db: str,
|
|
841
|
+
final_answer: Optional[str] = None,
|
|
842
|
+
) -> Dict[str, Any]:
|
|
843
|
+
"""Execute a verifier function locally against SQLite database files.
|
|
844
|
+
|
|
845
|
+
No authentication or remote server required. The verifier code is executed
|
|
846
|
+
in an isolated namespace with the same helpers available in production
|
|
847
|
+
(``normalized_contains``, ``IgnoreConfig``, ``DatabaseSnapshot``, etc.).
|
|
848
|
+
|
|
849
|
+
Args:
|
|
850
|
+
verifier_func: Python source code containing the verifier function definition.
|
|
851
|
+
seed_db: Path to the seed (before) SQLite database file.
|
|
852
|
+
current_db: Path to the current (after) SQLite database file.
|
|
853
|
+
final_answer: Optional final answer string passed to the verifier.
|
|
854
|
+
|
|
855
|
+
Returns:
|
|
856
|
+
Dict with keys ``success``, ``result``, ``error``, and ``stdout``.
|
|
857
|
+
|
|
858
|
+
Example::
|
|
859
|
+
|
|
860
|
+
result = await fleet.execute_verifier_local(
|
|
861
|
+
verifier_func=verifier_code_string,
|
|
862
|
+
seed_db="./seed.db",
|
|
863
|
+
current_db="./current.db",
|
|
864
|
+
)
|
|
865
|
+
print(result["result"]) # 1 (TASK_SUCCESSFUL_SCORE) or 0
|
|
866
|
+
"""
|
|
867
|
+
import asyncio
|
|
868
|
+
from ..verifiers.local_executor import execute_verifier_local
|
|
869
|
+
|
|
870
|
+
return await asyncio.to_thread(
|
|
871
|
+
execute_verifier_local, verifier_func, seed_db, current_db, final_answer
|
|
872
|
+
)
|
|
873
|
+
|
|
836
874
|
async def list_runs(
|
|
837
875
|
self, profile_id: Optional[str] = None, status: Optional[str] = "active"
|
|
838
876
|
) -> List[Run]:
|
|
@@ -844,7 +844,42 @@ class Fleet:
|
|
|
844
844
|
At least one of run_id or profile_id must be provided.
|
|
845
845
|
"""
|
|
846
846
|
return _delete_instances_batch(self.client, run_id=run_id, profile_id=profile_id)
|
|
847
|
-
|
|
847
|
+
|
|
848
|
+
@staticmethod
|
|
849
|
+
def execute_verifier_local(
|
|
850
|
+
verifier_func: str,
|
|
851
|
+
seed_db: str,
|
|
852
|
+
current_db: str,
|
|
853
|
+
final_answer: Optional[str] = None,
|
|
854
|
+
) -> Dict[str, Any]:
|
|
855
|
+
"""Execute a verifier function locally against SQLite database files.
|
|
856
|
+
|
|
857
|
+
No authentication or remote server required. The verifier code is executed
|
|
858
|
+
in an isolated namespace with the same helpers available in production
|
|
859
|
+
(``normalized_contains``, ``IgnoreConfig``, ``DatabaseSnapshot``, etc.).
|
|
860
|
+
|
|
861
|
+
Args:
|
|
862
|
+
verifier_func: Python source code containing the verifier function definition.
|
|
863
|
+
seed_db: Path to the seed (before) SQLite database file.
|
|
864
|
+
current_db: Path to the current (after) SQLite database file.
|
|
865
|
+
final_answer: Optional final answer string passed to the verifier.
|
|
866
|
+
|
|
867
|
+
Returns:
|
|
868
|
+
Dict with keys ``success``, ``result``, ``error``, and ``stdout``.
|
|
869
|
+
|
|
870
|
+
Example::
|
|
871
|
+
|
|
872
|
+
result = fleet.execute_verifier_local(
|
|
873
|
+
verifier_func=verifier_code_string,
|
|
874
|
+
seed_db="./seed.db",
|
|
875
|
+
current_db="./current.db",
|
|
876
|
+
)
|
|
877
|
+
print(result["result"]) # 1 (TASK_SUCCESSFUL_SCORE) or 0
|
|
878
|
+
"""
|
|
879
|
+
from .verifiers.local_executor import execute_verifier_local
|
|
880
|
+
|
|
881
|
+
return execute_verifier_local(verifier_func, seed_db, current_db, final_answer)
|
|
882
|
+
|
|
848
883
|
def list_runs(
|
|
849
884
|
self, profile_id: Optional[str] = None, status: Optional[str] = "active"
|
|
850
885
|
) -> List[Run]:
|
|
@@ -6,6 +6,7 @@ from .verifier import (
|
|
|
6
6
|
verifier,
|
|
7
7
|
SyncVerifierFunction,
|
|
8
8
|
)
|
|
9
|
+
from .local_executor import execute_verifier_local, LocalEnvironment
|
|
9
10
|
|
|
10
11
|
__all__ = [
|
|
11
12
|
"DatabaseSnapshot",
|
|
@@ -15,4 +16,6 @@ __all__ = [
|
|
|
15
16
|
"TASK_FAILED_SCORE",
|
|
16
17
|
"verifier",
|
|
17
18
|
"SyncVerifierFunction",
|
|
19
|
+
"execute_verifier_local",
|
|
20
|
+
"LocalEnvironment",
|
|
18
21
|
]
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""Local verifier execution against SQLite files.
|
|
2
|
+
|
|
3
|
+
Executes verifier function code directly against local SQLite database files,
|
|
4
|
+
without requiring authentication or a remote runner API server.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import inspect
|
|
8
|
+
import json
|
|
9
|
+
import re
|
|
10
|
+
import string
|
|
11
|
+
import traceback
|
|
12
|
+
from io import StringIO
|
|
13
|
+
from typing import Any, Dict, Optional
|
|
14
|
+
|
|
15
|
+
from .db import DatabaseSnapshot, IgnoreConfig, SnapshotDiff
|
|
16
|
+
from .code import TASK_SUCCESSFUL_SCORE, TASK_FAILED_SCORE
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# Helper functions injected into verifier execution namespace
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
_TRANSLATOR = str.maketrans(string.punctuation, " " * len(string.punctuation))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _normalize_text(value: str) -> str:
|
|
27
|
+
text = value.lower().translate(_TRANSLATOR)
|
|
28
|
+
return "".join(text.split())
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _stringify_content(content: Any) -> str:
|
|
32
|
+
if isinstance(content, (dict, list)):
|
|
33
|
+
return json.dumps(content, sort_keys=True)
|
|
34
|
+
return str(content)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def normalized_contains(target: str, blob: Any) -> bool:
|
|
38
|
+
"""Check if target is contained in blob after normalising punctuation and case."""
|
|
39
|
+
normalized_target = _normalize_text(target)
|
|
40
|
+
normalized_blob = _normalize_text(_stringify_content(blob))
|
|
41
|
+
return normalized_target in normalized_blob
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def normalized_string_comparison(target: str, blob: Any) -> bool:
|
|
45
|
+
"""Check if target equals blob after normalising punctuation and case."""
|
|
46
|
+
normalized_target = _normalize_text(target)
|
|
47
|
+
normalized_blob = _normalize_text(_stringify_content(blob))
|
|
48
|
+
return normalized_target == normalized_blob
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def extract_numbers(text: str) -> list:
|
|
52
|
+
"""Extract all numbers from a string."""
|
|
53
|
+
cleaned_text = text.replace(",", "")
|
|
54
|
+
pattern = r"-?\d+\.?\d*"
|
|
55
|
+
matches = re.findall(pattern, cleaned_text)
|
|
56
|
+
return [float(num) for num in matches]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def contains_number(text: str, target_number) -> bool:
|
|
60
|
+
"""Check if text contains the target number."""
|
|
61
|
+
numbers = extract_numbers(text)
|
|
62
|
+
try:
|
|
63
|
+
if isinstance(target_number, str):
|
|
64
|
+
target_number = target_number.replace(",", "")
|
|
65
|
+
target = float(target_number)
|
|
66
|
+
except (ValueError, AttributeError):
|
|
67
|
+
return False
|
|
68
|
+
return target in numbers
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# Lightweight Environment mock for local verifier execution
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
class _LocalInstance:
|
|
76
|
+
"""Mock instance that supports load() as a no-op."""
|
|
77
|
+
|
|
78
|
+
def load(self):
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class LocalEnvironment:
|
|
83
|
+
"""Lightweight environment that wraps local SQLite files for verifier execution.
|
|
84
|
+
|
|
85
|
+
Provides the same interface verifier functions expect from ``env``:
|
|
86
|
+
``env.db("seed")``, ``env.db("current")``, and ``env.instance.load()``.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def __init__(self, seed_db: str, current_db: str):
|
|
90
|
+
self._snapshots: Dict[str, DatabaseSnapshot] = {
|
|
91
|
+
"seed": DatabaseSnapshot(seed_db, name="seed"),
|
|
92
|
+
"current": DatabaseSnapshot(current_db, name="current"),
|
|
93
|
+
}
|
|
94
|
+
self.instance = _LocalInstance()
|
|
95
|
+
|
|
96
|
+
def db(self, name: str = "current") -> DatabaseSnapshot:
|
|
97
|
+
if name not in self._snapshots:
|
|
98
|
+
raise KeyError(
|
|
99
|
+
f"Unknown database '{name}'. Available: {list(self._snapshots.keys())}"
|
|
100
|
+
)
|
|
101
|
+
return self._snapshots[name]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ---------------------------------------------------------------------------
|
|
105
|
+
# Core execution function
|
|
106
|
+
# ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
def execute_verifier_local(
|
|
109
|
+
verifier_func: str,
|
|
110
|
+
seed_db: str,
|
|
111
|
+
current_db: str,
|
|
112
|
+
final_answer: Optional[str] = None,
|
|
113
|
+
) -> Dict[str, Any]:
|
|
114
|
+
"""Execute a verifier function string locally against SQLite database files.
|
|
115
|
+
|
|
116
|
+
No authentication or remote server required. The function is executed in an
|
|
117
|
+
isolated namespace with the same helpers available to production verifiers.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
verifier_func: Python source code containing the verifier function definition.
|
|
121
|
+
seed_db: Path to the seed (before) SQLite database file.
|
|
122
|
+
current_db: Path to the current (after) SQLite database file.
|
|
123
|
+
final_answer: Optional final answer string passed to the verifier.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Dict with keys:
|
|
127
|
+
- ``success`` (bool): Whether execution completed without errors.
|
|
128
|
+
- ``result`` (Any): The return value of the verifier function (typically a score).
|
|
129
|
+
- ``error`` (str | None): Error message and traceback if execution failed.
|
|
130
|
+
- ``stdout`` (str): Captured stdout output from the verifier function.
|
|
131
|
+
"""
|
|
132
|
+
import sys
|
|
133
|
+
|
|
134
|
+
# Capture stdout
|
|
135
|
+
captured_stdout = StringIO()
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
# Build the local environment
|
|
139
|
+
env = LocalEnvironment(seed_db, current_db)
|
|
140
|
+
|
|
141
|
+
# Clean the verifier code – strip decorators and fleet imports
|
|
142
|
+
cleaned_code = re.sub(r"@verifier\([^)]*\)\s*\n", "", verifier_func)
|
|
143
|
+
cleaned_code = re.sub(
|
|
144
|
+
r"^from fleet\.verifiers.*import.*$\n?",
|
|
145
|
+
"",
|
|
146
|
+
cleaned_code,
|
|
147
|
+
flags=re.MULTILINE,
|
|
148
|
+
)
|
|
149
|
+
cleaned_code = re.sub(
|
|
150
|
+
r"^from fleet import verifier.*$\n?",
|
|
151
|
+
"",
|
|
152
|
+
cleaned_code,
|
|
153
|
+
flags=re.MULTILINE,
|
|
154
|
+
)
|
|
155
|
+
cleaned_code = re.sub(
|
|
156
|
+
r"^import fleet\.verifiers.*$\n?",
|
|
157
|
+
"",
|
|
158
|
+
cleaned_code,
|
|
159
|
+
flags=re.MULTILINE,
|
|
160
|
+
)
|
|
161
|
+
cleaned_code = re.sub(
|
|
162
|
+
r"^import fleet$\n?", "", cleaned_code, flags=re.MULTILINE
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Build execution namespace with all helpers available to verifiers
|
|
166
|
+
exec_globals: Dict[str, Any] = {
|
|
167
|
+
# Score constants
|
|
168
|
+
"TASK_SUCCESSFUL_SCORE": TASK_SUCCESSFUL_SCORE,
|
|
169
|
+
"TASK_FAILED_SCORE": TASK_FAILED_SCORE,
|
|
170
|
+
# Helper functions
|
|
171
|
+
"normalized_contains": normalized_contains,
|
|
172
|
+
"normalized_string_comparison": normalized_string_comparison,
|
|
173
|
+
"extract_numbers": extract_numbers,
|
|
174
|
+
"contains_number": contains_number,
|
|
175
|
+
# Database classes
|
|
176
|
+
"DatabaseSnapshot": DatabaseSnapshot,
|
|
177
|
+
"IgnoreConfig": IgnoreConfig,
|
|
178
|
+
"SnapshotDiff": SnapshotDiff,
|
|
179
|
+
# Environment type hint (not enforced at runtime)
|
|
180
|
+
"Environment": type(env),
|
|
181
|
+
# Standard library modules commonly used in verifiers
|
|
182
|
+
"json": json,
|
|
183
|
+
"re": re,
|
|
184
|
+
"string": string,
|
|
185
|
+
# Builtins
|
|
186
|
+
"__builtins__": __builtins__,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
# Execute the verifier code to define the function(s)
|
|
190
|
+
local_namespace: Dict[str, Any] = {}
|
|
191
|
+
exec(cleaned_code, exec_globals, local_namespace)
|
|
192
|
+
|
|
193
|
+
# Merge so helper functions defined in verifier code are accessible
|
|
194
|
+
exec_globals.update(local_namespace)
|
|
195
|
+
|
|
196
|
+
# Find the verifier function (the one defined in user code)
|
|
197
|
+
func_obj = None
|
|
198
|
+
for name, obj in local_namespace.items():
|
|
199
|
+
if inspect.isfunction(obj) and obj.__code__.co_filename == "<string>":
|
|
200
|
+
func_obj = obj
|
|
201
|
+
break
|
|
202
|
+
|
|
203
|
+
if func_obj is None:
|
|
204
|
+
return {
|
|
205
|
+
"success": False,
|
|
206
|
+
"result": None,
|
|
207
|
+
"error": "No function found in verifier code",
|
|
208
|
+
"stdout": "",
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# Redirect stdout to capture print() output from verifiers
|
|
212
|
+
old_stdout = sys.stdout
|
|
213
|
+
sys.stdout = captured_stdout
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
# Execute the verifier – verifiers take (env, final_answer=None)
|
|
217
|
+
sig = inspect.signature(func_obj)
|
|
218
|
+
params = list(sig.parameters.values())
|
|
219
|
+
|
|
220
|
+
if len(params) >= 2:
|
|
221
|
+
result = func_obj(env, final_answer)
|
|
222
|
+
elif len(params) == 1:
|
|
223
|
+
result = func_obj(env)
|
|
224
|
+
else:
|
|
225
|
+
result = func_obj()
|
|
226
|
+
finally:
|
|
227
|
+
sys.stdout = old_stdout
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
"success": True,
|
|
231
|
+
"result": result,
|
|
232
|
+
"error": None,
|
|
233
|
+
"stdout": captured_stdout.getvalue(),
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
except Exception as e:
|
|
237
|
+
# Restore stdout if it was redirected
|
|
238
|
+
if sys.stdout is not sys.__stdout__ and sys.stdout is captured_stdout:
|
|
239
|
+
sys.stdout = sys.__stdout__
|
|
240
|
+
|
|
241
|
+
error_msg = f"{type(e).__name__}: {e}\n{traceback.format_exc()}"
|
|
242
|
+
return {
|
|
243
|
+
"success": False,
|
|
244
|
+
"result": None,
|
|
245
|
+
"error": error_msg,
|
|
246
|
+
"stdout": captured_stdout.getvalue(),
|
|
247
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|