edsl 0.1.59__py3-none-any.whl → 0.1.61__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.
- edsl/__version__.py +1 -1
- edsl/agents/agent.py +65 -17
- edsl/agents/agent_list.py +117 -33
- edsl/base/base_class.py +80 -11
- edsl/base/data_transfer_models.py +5 -0
- edsl/base/enums.py +7 -2
- edsl/config/config_class.py +7 -2
- edsl/coop/coop.py +1295 -85
- edsl/coop/coop_prolific_filters.py +171 -0
- edsl/dataset/dataset_operations_mixin.py +2 -2
- edsl/dataset/display/table_display.py +40 -7
- edsl/db_list/sqlite_list.py +102 -3
- edsl/inference_services/services/__init__.py +3 -1
- edsl/inference_services/services/open_ai_service_v2.py +243 -0
- edsl/jobs/data_structures.py +48 -30
- edsl/jobs/jobs.py +73 -2
- edsl/jobs/remote_inference.py +49 -15
- edsl/key_management/key_lookup_builder.py +25 -3
- edsl/language_models/language_model.py +2 -1
- edsl/language_models/raw_response_handler.py +126 -7
- edsl/questions/loop_processor.py +289 -10
- edsl/questions/templates/dict/answering_instructions.jinja +0 -1
- edsl/results/result.py +37 -0
- edsl/results/results.py +1 -0
- edsl/scenarios/scenario_list.py +31 -1
- edsl/scenarios/scenario_source.py +606 -498
- edsl/surveys/survey.py +198 -163
- {edsl-0.1.59.dist-info → edsl-0.1.61.dist-info}/METADATA +4 -4
- {edsl-0.1.59.dist-info → edsl-0.1.61.dist-info}/RECORD +32 -30
- {edsl-0.1.59.dist-info → edsl-0.1.61.dist-info}/LICENSE +0 -0
- {edsl-0.1.59.dist-info → edsl-0.1.61.dist-info}/WHEEL +0 -0
- {edsl-0.1.59.dist-info → edsl-0.1.61.dist-info}/entry_points.txt +0 -0
edsl/jobs/data_structures.py
CHANGED
@@ -5,6 +5,7 @@ from ..data_transfer_models import EDSLResultObjectInput
|
|
5
5
|
|
6
6
|
# from edsl.data_transfer_models import VisibilityType
|
7
7
|
from ..caching import Cache
|
8
|
+
|
8
9
|
# Import BucketCollection lazily to avoid circular imports
|
9
10
|
from ..key_management import KeyLookup
|
10
11
|
from ..base import Base
|
@@ -18,23 +19,27 @@ if TYPE_CHECKING:
|
|
18
19
|
|
19
20
|
VisibilityType = Literal["private", "public", "unlisted"]
|
20
21
|
|
22
|
+
|
21
23
|
@dataclass
|
22
24
|
class RunEnvironment:
|
23
25
|
"""
|
24
26
|
Contains environment-related resources for job execution.
|
25
|
-
|
26
|
-
This dataclass holds references to shared resources and infrastructure components
|
27
|
-
needed for job execution. These components are typically long-lived and may be
|
27
|
+
|
28
|
+
This dataclass holds references to shared resources and infrastructure components
|
29
|
+
needed for job execution. These components are typically long-lived and may be
|
28
30
|
shared across multiple job runs.
|
29
|
-
|
31
|
+
|
30
32
|
Attributes:
|
31
33
|
cache (Cache, optional): Cache for storing and retrieving interview results
|
32
34
|
bucket_collection (BucketCollection, optional): Collection of token rate limit buckets
|
33
35
|
key_lookup (KeyLookup, optional): Manager for API keys across models
|
34
36
|
jobs_runner_status (JobsRunnerStatus, optional): Tracker for job execution progress
|
35
37
|
"""
|
38
|
+
|
36
39
|
cache: Optional[Cache] = None
|
37
|
-
bucket_collection: Optional[
|
40
|
+
bucket_collection: Optional[
|
41
|
+
Any
|
42
|
+
] = None # Using Any to avoid circular import of BucketCollection
|
38
43
|
key_lookup: Optional[KeyLookup] = None
|
39
44
|
jobs_runner_status: Optional["JobsRunnerStatus"] = None
|
40
45
|
|
@@ -43,11 +48,11 @@ class RunEnvironment:
|
|
43
48
|
class RunParameters(Base):
|
44
49
|
"""
|
45
50
|
Contains execution-specific parameters for job runs.
|
46
|
-
|
51
|
+
|
47
52
|
This dataclass holds parameters that control the behavior of a specific job run,
|
48
53
|
such as iteration count, error handling preferences, and remote execution options.
|
49
54
|
Unlike RunEnvironment, these parameters are specific to a single job execution.
|
50
|
-
|
55
|
+
|
51
56
|
Attributes:
|
52
57
|
n (int): Number of iterations to run each interview, default is 1
|
53
58
|
progress_bar (bool): Whether to show a progress bar, default is False
|
@@ -66,7 +71,9 @@ class RunParameters(Base):
|
|
66
71
|
disable_remote_inference (bool): Whether to disable remote inference, default is False
|
67
72
|
job_uuid (str, optional): UUID for the job, used for tracking
|
68
73
|
fresh (bool): If True, ignore cache and generate new results, default is False
|
74
|
+
new_format (bool): If True, uses remote_inference_create method, if False uses old_remote_inference_create method, default is True
|
69
75
|
"""
|
76
|
+
|
70
77
|
n: int = 1
|
71
78
|
progress_bar: bool = False
|
72
79
|
stop_on_exception: bool = False
|
@@ -82,8 +89,13 @@ class RunParameters(Base):
|
|
82
89
|
disable_remote_cache: bool = False
|
83
90
|
disable_remote_inference: bool = False
|
84
91
|
job_uuid: Optional[str] = None
|
85
|
-
fresh: bool =
|
86
|
-
|
92
|
+
fresh: bool = (
|
93
|
+
False # if True, will not use cache and will save new results to cache
|
94
|
+
)
|
95
|
+
memory_threshold: Optional[
|
96
|
+
int
|
97
|
+
] = None # Threshold in bytes for Results SQLList memory management
|
98
|
+
new_format: bool = True # if True, uses remote_inference_create, if False uses old_remote_inference_create
|
87
99
|
|
88
100
|
def to_dict(self, add_edsl_version=False) -> dict:
|
89
101
|
d = asdict(self)
|
@@ -110,24 +122,25 @@ class RunParameters(Base):
|
|
110
122
|
class RunConfig:
|
111
123
|
"""
|
112
124
|
Combines environment resources and execution parameters for a job run.
|
113
|
-
|
125
|
+
|
114
126
|
This class brings together the two aspects of job configuration:
|
115
127
|
1. Environment resources (caches, API keys, etc.) via RunEnvironment
|
116
128
|
2. Execution parameters (iterations, error handling, etc.) via RunParameters
|
117
|
-
|
129
|
+
|
118
130
|
It provides helper methods for modifying environment components after construction.
|
119
|
-
|
131
|
+
|
120
132
|
Attributes:
|
121
133
|
environment (RunEnvironment): The environment resources for the job
|
122
134
|
parameters (RunParameters): The execution parameters for the job
|
123
135
|
"""
|
136
|
+
|
124
137
|
environment: RunEnvironment
|
125
138
|
parameters: RunParameters
|
126
139
|
|
127
140
|
def add_environment(self, environment: RunEnvironment) -> None:
|
128
141
|
"""
|
129
142
|
Replace the entire environment configuration.
|
130
|
-
|
143
|
+
|
131
144
|
Parameters:
|
132
145
|
environment (RunEnvironment): The new environment configuration
|
133
146
|
"""
|
@@ -136,7 +149,7 @@ class RunConfig:
|
|
136
149
|
def add_bucket_collection(self, bucket_collection: "BucketCollection") -> None:
|
137
150
|
"""
|
138
151
|
Set or replace the bucket collection in the environment.
|
139
|
-
|
152
|
+
|
140
153
|
Parameters:
|
141
154
|
bucket_collection (BucketCollection): The bucket collection to use
|
142
155
|
"""
|
@@ -145,7 +158,7 @@ class RunConfig:
|
|
145
158
|
def add_cache(self, cache: Cache) -> None:
|
146
159
|
"""
|
147
160
|
Set or replace the cache in the environment.
|
148
|
-
|
161
|
+
|
149
162
|
Parameters:
|
150
163
|
cache (Cache): The cache to use
|
151
164
|
"""
|
@@ -154,7 +167,7 @@ class RunConfig:
|
|
154
167
|
def add_key_lookup(self, key_lookup: KeyLookup) -> None:
|
155
168
|
"""
|
156
169
|
Set or replace the key lookup in the environment.
|
157
|
-
|
170
|
+
|
158
171
|
Parameters:
|
159
172
|
key_lookup (KeyLookup): The key lookup to use
|
160
173
|
"""
|
@@ -169,10 +182,10 @@ Additional data structures for working with job results and answers.
|
|
169
182
|
class Answers(UserDict):
|
170
183
|
"""
|
171
184
|
A specialized dictionary for holding interview response data.
|
172
|
-
|
185
|
+
|
173
186
|
This class extends UserDict to provide a flexible container for survey answers,
|
174
187
|
with special handling for response metadata like comments and token usage.
|
175
|
-
|
188
|
+
|
176
189
|
Key features:
|
177
190
|
- Stores answers by question name
|
178
191
|
- Associates comments with their respective questions
|
@@ -185,14 +198,14 @@ class Answers(UserDict):
|
|
185
198
|
) -> None:
|
186
199
|
"""
|
187
200
|
Add a response to the answers dictionary.
|
188
|
-
|
201
|
+
|
189
202
|
This method processes a response and stores it in the dictionary with appropriate
|
190
203
|
naming conventions for the answer itself, comments, and token usage tracking.
|
191
|
-
|
204
|
+
|
192
205
|
Parameters:
|
193
206
|
response (EDSLResultObjectInput): The response object containing answer data
|
194
207
|
question (QuestionBase): The question that was answered
|
195
|
-
|
208
|
+
|
196
209
|
Notes:
|
197
210
|
- The main answer is stored with the question's name as the key
|
198
211
|
- Comments are stored with "_comment" appended to the question name
|
@@ -201,28 +214,33 @@ class Answers(UserDict):
|
|
201
214
|
answer = response.answer
|
202
215
|
comment = response.comment
|
203
216
|
generated_tokens = response.generated_tokens
|
204
|
-
|
217
|
+
|
205
218
|
# Record token usage if available
|
206
219
|
if generated_tokens:
|
207
220
|
self[question.question_name + "_generated_tokens"] = generated_tokens
|
208
|
-
|
221
|
+
|
209
222
|
# Record the primary answer
|
210
223
|
self[question.question_name] = answer
|
211
|
-
|
224
|
+
|
212
225
|
# Record comment if present
|
213
226
|
if comment:
|
214
227
|
self[question.question_name + "_comment"] = comment
|
215
228
|
|
229
|
+
if getattr(response, "reasoning_summary", None):
|
230
|
+
self[
|
231
|
+
question.question_name + "_reasoning_summary"
|
232
|
+
] = response.reasoning_summary
|
233
|
+
|
216
234
|
def replace_missing_answers_with_none(self, survey: "Survey") -> None:
|
217
235
|
"""
|
218
236
|
Replace missing answers with None for all questions in the survey.
|
219
|
-
|
237
|
+
|
220
238
|
This method ensures that all questions in the survey have an entry in the
|
221
239
|
answers dictionary, even if they were skipped during the interview.
|
222
|
-
|
240
|
+
|
223
241
|
Parameters:
|
224
242
|
survey (Survey): The survey containing the questions to check
|
225
|
-
|
243
|
+
|
226
244
|
Notes:
|
227
245
|
- Answers can be missing if the agent skips a question due to skip logic
|
228
246
|
- This ensures consistent data structure even with partial responses
|
@@ -234,7 +252,7 @@ class Answers(UserDict):
|
|
234
252
|
def to_dict(self) -> dict:
|
235
253
|
"""
|
236
254
|
Convert the answers to a standard dictionary.
|
237
|
-
|
255
|
+
|
238
256
|
Returns:
|
239
257
|
dict: A plain dictionary containing all the answers data
|
240
258
|
"""
|
@@ -244,10 +262,10 @@ class Answers(UserDict):
|
|
244
262
|
def from_dict(cls, d: dict) -> "Answers":
|
245
263
|
"""
|
246
264
|
Create an Answers object from a dictionary.
|
247
|
-
|
265
|
+
|
248
266
|
Parameters:
|
249
267
|
d (dict): The dictionary containing answer data
|
250
|
-
|
268
|
+
|
251
269
|
Returns:
|
252
270
|
Answers: A new Answers instance with the provided data
|
253
271
|
"""
|
edsl/jobs/jobs.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
"""
|
2
2
|
The Jobs module is the core orchestration component of the EDSL framework.
|
3
3
|
|
4
|
-
It provides functionality to define, configure, and execute computational jobs that
|
5
|
-
involve multiple agents, scenarios, models, and a survey. Jobs are the primary way
|
4
|
+
It provides functionality to define, configure, and execute computational jobs that
|
5
|
+
involve multiple agents, scenarios, models, and a survey. Jobs are the primary way
|
6
6
|
that users run large-scale experiments or simulations in EDSL.
|
7
7
|
|
8
8
|
The Jobs class handles:
|
@@ -15,6 +15,7 @@ The Jobs class handles:
|
|
15
15
|
This module is designed to be used by both application developers and researchers
|
16
16
|
who need to run complex simulations with language models.
|
17
17
|
"""
|
18
|
+
|
18
19
|
from __future__ import annotations
|
19
20
|
import asyncio
|
20
21
|
from typing import Optional, Union, TypeVar, Callable, cast
|
@@ -564,6 +565,7 @@ class Jobs(Base):
|
|
564
565
|
remote_inference_description=self.run_config.parameters.remote_inference_description,
|
565
566
|
remote_inference_results_visibility=self.run_config.parameters.remote_inference_results_visibility,
|
566
567
|
fresh=self.run_config.parameters.fresh,
|
568
|
+
new_format=self.run_config.parameters.new_format,
|
567
569
|
)
|
568
570
|
return job_info
|
569
571
|
|
@@ -829,6 +831,7 @@ class Jobs(Base):
|
|
829
831
|
key_lookup (KeyLookup, optional): Object to manage API keys
|
830
832
|
memory_threshold (int, optional): Memory threshold in bytes for the Results object's SQLList,
|
831
833
|
controlling when data is offloaded to SQLite storage
|
834
|
+
new_format (bool): If True, uses remote_inference_create method, if False uses old_remote_inference_create method (default: True)
|
832
835
|
|
833
836
|
Returns:
|
834
837
|
Results: A Results object containing all responses and metadata
|
@@ -889,6 +892,7 @@ class Jobs(Base):
|
|
889
892
|
key_lookup (KeyLookup, optional): Object to manage API keys
|
890
893
|
memory_threshold (int, optional): Memory threshold in bytes for the Results object's SQLList,
|
891
894
|
controlling when data is offloaded to SQLite storage
|
895
|
+
new_format (bool): If True, uses remote_inference_create method, if False uses old_remote_inference_create method (default: True)
|
892
896
|
|
893
897
|
Returns:
|
894
898
|
Results: A Results object containing all responses and metadata
|
@@ -1084,6 +1088,73 @@ class Jobs(Base):
|
|
1084
1088
|
"""Return the code to create this instance."""
|
1085
1089
|
raise JobsImplementationError("Code generation not implemented yet")
|
1086
1090
|
|
1091
|
+
def humanize(
|
1092
|
+
self,
|
1093
|
+
project_name: str = "Project",
|
1094
|
+
scenario_list_method: Optional[
|
1095
|
+
Literal["randomize", "loop", "single_scenario"]
|
1096
|
+
] = None,
|
1097
|
+
survey_description: Optional[str] = None,
|
1098
|
+
survey_alias: Optional[str] = None,
|
1099
|
+
survey_visibility: Optional["VisibilityType"] = "unlisted",
|
1100
|
+
scenario_list_description: Optional[str] = None,
|
1101
|
+
scenario_list_alias: Optional[str] = None,
|
1102
|
+
scenario_list_visibility: Optional["VisibilityType"] = "unlisted",
|
1103
|
+
):
|
1104
|
+
"""
|
1105
|
+
Send the survey and scenario list to Coop.
|
1106
|
+
|
1107
|
+
Then, create a project on Coop so you can share the survey with human respondents.
|
1108
|
+
"""
|
1109
|
+
from edsl.coop import Coop
|
1110
|
+
from edsl.coop.exceptions import CoopValueError
|
1111
|
+
|
1112
|
+
if len(self.agents) > 0 or len(self.models) > 0:
|
1113
|
+
raise CoopValueError("We don't support humanize with agents or models yet.")
|
1114
|
+
|
1115
|
+
if len(self.scenarios) > 0 and scenario_list_method is None:
|
1116
|
+
raise CoopValueError(
|
1117
|
+
"You must specify both a scenario list and a scenario list method to use scenarios with your survey."
|
1118
|
+
)
|
1119
|
+
elif len(self.scenarios) == 0 and scenario_list_method is not None:
|
1120
|
+
raise CoopValueError(
|
1121
|
+
"You must specify both a scenario list and a scenario list method to use scenarios with your survey."
|
1122
|
+
)
|
1123
|
+
elif scenario_list_method is "loop":
|
1124
|
+
questions, long_scenario_list = self.survey.to_long_format(self.scenarios)
|
1125
|
+
|
1126
|
+
# Replace the questions with new ones from the loop method
|
1127
|
+
self.survey = Survey(questions)
|
1128
|
+
self.scenarios = long_scenario_list
|
1129
|
+
|
1130
|
+
if len(self.scenarios) != 1:
|
1131
|
+
raise CoopValueError("Something went wrong with the loop method.")
|
1132
|
+
elif len(self.scenarios) != 1 and scenario_list_method == "single_scenario":
|
1133
|
+
raise CoopValueError(
|
1134
|
+
f"The single_scenario method requires exactly one scenario. "
|
1135
|
+
f"If you have a scenario list with multiple scenarios, try using the randomize or loop methods."
|
1136
|
+
)
|
1137
|
+
|
1138
|
+
if len(self.scenarios) == 0:
|
1139
|
+
scenario_list = None
|
1140
|
+
else:
|
1141
|
+
scenario_list = self.scenarios
|
1142
|
+
|
1143
|
+
c = Coop()
|
1144
|
+
project_details = c.create_project(
|
1145
|
+
self.survey,
|
1146
|
+
scenario_list,
|
1147
|
+
scenario_list_method,
|
1148
|
+
project_name,
|
1149
|
+
survey_description,
|
1150
|
+
survey_alias,
|
1151
|
+
survey_visibility,
|
1152
|
+
scenario_list_description,
|
1153
|
+
scenario_list_alias,
|
1154
|
+
scenario_list_visibility,
|
1155
|
+
)
|
1156
|
+
return project_details
|
1157
|
+
|
1087
1158
|
|
1088
1159
|
def main():
|
1089
1160
|
"""Run the module's doctests."""
|
edsl/jobs/remote_inference.py
CHANGED
@@ -31,6 +31,7 @@ class RemoteJobInfo:
|
|
31
31
|
creation_data: RemoteInferenceCreationInfo
|
32
32
|
job_uuid: JobUUID
|
33
33
|
logger: JobLogger
|
34
|
+
new_format: bool = True
|
34
35
|
|
35
36
|
|
36
37
|
class JobsRemoteInferenceHandler:
|
@@ -85,7 +86,21 @@ class JobsRemoteInferenceHandler:
|
|
85
86
|
remote_inference_description: Optional[str] = None,
|
86
87
|
remote_inference_results_visibility: Optional["VisibilityType"] = "unlisted",
|
87
88
|
fresh: Optional[bool] = False,
|
89
|
+
new_format: Optional[bool] = True,
|
88
90
|
) -> RemoteJobInfo:
|
91
|
+
"""
|
92
|
+
Create a remote inference job and return job information.
|
93
|
+
|
94
|
+
Args:
|
95
|
+
iterations: Number of times to run each interview
|
96
|
+
remote_inference_description: Optional description for the remote job
|
97
|
+
remote_inference_results_visibility: Visibility setting for results
|
98
|
+
fresh: If True, ignore existing cache entries and generate new results
|
99
|
+
new_format: If True, use pull method for result retrieval; if False, use legacy get method
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
RemoteJobInfo: Information about the created job including UUID and logger
|
103
|
+
"""
|
89
104
|
from ..coop import Coop
|
90
105
|
|
91
106
|
logger = self._create_logger()
|
@@ -101,14 +116,24 @@ class JobsRemoteInferenceHandler:
|
|
101
116
|
logger.add_info(
|
102
117
|
"remote_cache_url", f"{self.expected_parrot_url}/home/remote-cache"
|
103
118
|
)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
119
|
+
if new_format:
|
120
|
+
remote_job_creation_data = coop.remote_inference_create(
|
121
|
+
self.jobs,
|
122
|
+
description=remote_inference_description,
|
123
|
+
status="queued",
|
124
|
+
iterations=iterations,
|
125
|
+
initial_results_visibility=remote_inference_results_visibility,
|
126
|
+
fresh=fresh,
|
127
|
+
)
|
128
|
+
else:
|
129
|
+
remote_job_creation_data = coop.old_remote_inference_create(
|
130
|
+
self.jobs,
|
131
|
+
description=remote_inference_description,
|
132
|
+
status="queued",
|
133
|
+
iterations=iterations,
|
134
|
+
initial_results_visibility=remote_inference_results_visibility,
|
135
|
+
fresh=fresh,
|
136
|
+
)
|
112
137
|
logger.update(
|
113
138
|
"Your survey is running at the Expected Parrot server...",
|
114
139
|
status=JobsStatus.RUNNING,
|
@@ -141,6 +166,7 @@ class JobsRemoteInferenceHandler:
|
|
141
166
|
creation_data=remote_job_creation_data,
|
142
167
|
job_uuid=job_uuid,
|
143
168
|
logger=logger,
|
169
|
+
new_format=new_format,
|
144
170
|
)
|
145
171
|
|
146
172
|
@staticmethod
|
@@ -164,7 +190,7 @@ class JobsRemoteInferenceHandler:
|
|
164
190
|
return coop.remote_inference_get
|
165
191
|
|
166
192
|
def _construct_object_fetcher(
|
167
|
-
self, testing_simulated_response: Optional[Any] = None
|
193
|
+
self, new_format: bool = True, testing_simulated_response: Optional[Any] = None
|
168
194
|
) -> Callable:
|
169
195
|
"Constructs a function to fetch the results object from Coop."
|
170
196
|
if testing_simulated_response is not None:
|
@@ -173,7 +199,10 @@ class JobsRemoteInferenceHandler:
|
|
173
199
|
from ..coop import Coop
|
174
200
|
|
175
201
|
coop = Coop()
|
176
|
-
|
202
|
+
if new_format:
|
203
|
+
return coop.pull
|
204
|
+
else:
|
205
|
+
return coop.get
|
177
206
|
|
178
207
|
def _handle_cancelled_job(self, job_info: RemoteJobInfo) -> None:
|
179
208
|
"Handles a cancelled job by logging the cancellation and updating the job status."
|
@@ -395,7 +424,6 @@ class JobsRemoteInferenceHandler:
|
|
395
424
|
|
396
425
|
converter = CostConverter()
|
397
426
|
for model_key, model_cost_dict in expenses_by_model.items():
|
398
|
-
|
399
427
|
# Handle full cost (without cache)
|
400
428
|
input_cost = model_cost_dict["input_cost_usd"]
|
401
429
|
output_cost = model_cost_dict["output_cost_usd"]
|
@@ -417,9 +445,9 @@ class JobsRemoteInferenceHandler:
|
|
417
445
|
model_cost_dict["input_cost_credits_with_cache"] = converter.usd_to_credits(
|
418
446
|
input_cost_with_cache
|
419
447
|
)
|
420
|
-
model_cost_dict[
|
421
|
-
|
422
|
-
)
|
448
|
+
model_cost_dict[
|
449
|
+
"output_cost_credits_with_cache"
|
450
|
+
] = converter.usd_to_credits(output_cost_with_cache)
|
423
451
|
return list(expenses_by_model.values())
|
424
452
|
|
425
453
|
def _fetch_results_and_log(
|
@@ -525,7 +553,10 @@ class JobsRemoteInferenceHandler:
|
|
525
553
|
remote_job_data_fetcher = self._construct_remote_job_fetcher(
|
526
554
|
testing_simulated_response
|
527
555
|
)
|
528
|
-
object_fetcher = self._construct_object_fetcher(
|
556
|
+
object_fetcher = self._construct_object_fetcher(
|
557
|
+
new_format=job_info.new_format,
|
558
|
+
testing_simulated_response=testing_simulated_response,
|
559
|
+
)
|
529
560
|
|
530
561
|
job_in_queue = True
|
531
562
|
while job_in_queue:
|
@@ -540,6 +571,7 @@ class JobsRemoteInferenceHandler:
|
|
540
571
|
iterations: int = 1,
|
541
572
|
remote_inference_description: Optional[str] = None,
|
542
573
|
remote_inference_results_visibility: Optional[VisibilityType] = "unlisted",
|
574
|
+
new_format: Optional[bool] = True,
|
543
575
|
) -> Union["Results", None]:
|
544
576
|
"""
|
545
577
|
Creates and polls a remote inference job asynchronously.
|
@@ -548,6 +580,7 @@ class JobsRemoteInferenceHandler:
|
|
548
580
|
:param iterations: Number of times to run each interview
|
549
581
|
:param remote_inference_description: Optional description for the remote job
|
550
582
|
:param remote_inference_results_visibility: Visibility setting for results
|
583
|
+
:param new_format: If True, use pull method for result retrieval; if False, use legacy get method
|
551
584
|
:return: Results object if successful, None if job fails or is cancelled
|
552
585
|
"""
|
553
586
|
import asyncio
|
@@ -562,6 +595,7 @@ class JobsRemoteInferenceHandler:
|
|
562
595
|
iterations=iterations,
|
563
596
|
remote_inference_description=remote_inference_description,
|
564
597
|
remote_inference_results_visibility=remote_inference_results_visibility,
|
598
|
+
new_format=new_format,
|
565
599
|
),
|
566
600
|
)
|
567
601
|
if job_info is None:
|
@@ -363,13 +363,35 @@ class KeyLookupBuilder:
|
|
363
363
|
>>> builder._add_api_key("OPENAI_API_KEY", "sk-1234", "env")
|
364
364
|
>>> 'sk-1234' == builder.key_data["openai"][-1].value
|
365
365
|
True
|
366
|
+
>>> 'sk-1234' == builder.key_data["openai_v2"][-1].value
|
367
|
+
True
|
366
368
|
"""
|
367
369
|
service = api_keyname_to_service[key]
|
368
370
|
new_entry = APIKeyEntry(service=service, name=key, value=value, source=source)
|
369
|
-
|
370
|
-
|
371
|
+
|
372
|
+
# Special case for OPENAI_API_KEY - add to both openai and openai_v2
|
373
|
+
if key == "OPENAI_API_KEY":
|
374
|
+
# Add to openai service
|
375
|
+
openai_service = "openai"
|
376
|
+
openai_entry = APIKeyEntry(service=openai_service, name=key, value=value, source=source)
|
377
|
+
if openai_service not in self.key_data:
|
378
|
+
self.key_data[openai_service] = [openai_entry]
|
379
|
+
else:
|
380
|
+
self.key_data[openai_service].append(openai_entry)
|
381
|
+
|
382
|
+
# Add to openai_v2 service
|
383
|
+
openai_v2_service = "openai_v2"
|
384
|
+
openai_v2_entry = APIKeyEntry(service=openai_v2_service, name=key, value=value, source=source)
|
385
|
+
if openai_v2_service not in self.key_data:
|
386
|
+
self.key_data[openai_v2_service] = [openai_v2_entry]
|
387
|
+
else:
|
388
|
+
self.key_data[openai_v2_service].append(openai_v2_entry)
|
371
389
|
else:
|
372
|
-
|
390
|
+
# Normal case for all other API keys
|
391
|
+
if service not in self.key_data:
|
392
|
+
self.key_data[service] = [new_entry]
|
393
|
+
else:
|
394
|
+
self.key_data[service].append(new_entry)
|
373
395
|
|
374
396
|
def update_from_dict(self, d: dict) -> None:
|
375
397
|
"""
|
@@ -174,7 +174,8 @@ class LanguageModel(
|
|
174
174
|
"""
|
175
175
|
key_sequence = cls.key_sequence
|
176
176
|
usage_sequence = cls.usage_sequence if hasattr(cls, "usage_sequence") else None
|
177
|
-
|
177
|
+
reasoning_sequence = cls.reasoning_sequence if hasattr(cls, "reasoning_sequence") else None
|
178
|
+
return RawResponseHandler(key_sequence, usage_sequence, reasoning_sequence)
|
178
179
|
|
179
180
|
def __init__(
|
180
181
|
self,
|