edsl 0.1.36.dev5__py3-none-any.whl → 0.1.36.dev7__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/Base.py +303 -303
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +48 -47
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +804 -804
- edsl/agents/AgentList.py +337 -337
- edsl/agents/Invigilator.py +222 -222
- edsl/agents/InvigilatorBase.py +298 -294
- edsl/agents/PromptConstructor.py +320 -312
- edsl/agents/__init__.py +3 -3
- edsl/agents/descriptors.py +86 -86
- edsl/agents/prompt_helpers.py +129 -129
- edsl/auto/AutoStudy.py +117 -117
- edsl/auto/StageBase.py +230 -230
- edsl/auto/StageGenerateSurvey.py +178 -178
- edsl/auto/StageLabelQuestions.py +125 -125
- edsl/auto/StagePersona.py +61 -61
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
- edsl/auto/StagePersonaDimensionValues.py +74 -74
- edsl/auto/StagePersonaDimensions.py +69 -69
- edsl/auto/StageQuestions.py +73 -73
- edsl/auto/SurveyCreatorPipeline.py +21 -21
- edsl/auto/utilities.py +224 -224
- edsl/base/Base.py +289 -289
- edsl/config.py +149 -149
- edsl/conjure/AgentConstructionMixin.py +152 -152
- edsl/conjure/Conjure.py +62 -62
- edsl/conjure/InputData.py +659 -659
- edsl/conjure/InputDataCSV.py +48 -48
- edsl/conjure/InputDataMixinQuestionStats.py +182 -182
- edsl/conjure/InputDataPyRead.py +91 -91
- edsl/conjure/InputDataSPSS.py +8 -8
- edsl/conjure/InputDataStata.py +8 -8
- edsl/conjure/QuestionOptionMixin.py +76 -76
- edsl/conjure/QuestionTypeMixin.py +23 -23
- edsl/conjure/RawQuestion.py +65 -65
- edsl/conjure/SurveyResponses.py +7 -7
- edsl/conjure/__init__.py +9 -9
- edsl/conjure/naming_utilities.py +263 -263
- edsl/conjure/utilities.py +201 -201
- edsl/conversation/Conversation.py +238 -238
- edsl/conversation/car_buying.py +58 -58
- edsl/conversation/mug_negotiation.py +81 -81
- edsl/conversation/next_speaker_utilities.py +93 -93
- edsl/coop/PriceFetcher.py +54 -54
- edsl/coop/__init__.py +2 -2
- edsl/coop/coop.py +849 -849
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +527 -527
- edsl/data/CacheEntry.py +228 -228
- edsl/data/CacheHandler.py +149 -149
- edsl/data/RemoteCacheSync.py +83 -83
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +4 -4
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +73 -73
- edsl/enums.py +173 -173
- edsl/exceptions/__init__.py +50 -50
- edsl/exceptions/agents.py +40 -40
- edsl/exceptions/configuration.py +16 -16
- edsl/exceptions/coop.py +10 -10
- edsl/exceptions/data.py +14 -14
- edsl/exceptions/general.py +34 -34
- edsl/exceptions/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +91 -91
- edsl/exceptions/results.py +26 -26
- edsl/exceptions/surveys.py +34 -34
- edsl/inference_services/AnthropicService.py +87 -87
- edsl/inference_services/AwsBedrock.py +115 -115
- edsl/inference_services/AzureAI.py +217 -217
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +156 -156
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +147 -147
- edsl/inference_services/InferenceServicesCollection.py +74 -68
- edsl/inference_services/MistralAIService.py +123 -123
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +224 -224
- edsl/inference_services/TestService.py +89 -89
- edsl/inference_services/TogetherAIService.py +170 -170
- edsl/inference_services/models_available_cache.py +118 -94
- edsl/inference_services/rate_limits_cache.py +25 -25
- edsl/inference_services/registry.py +39 -39
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/Answers.py +56 -56
- edsl/jobs/Jobs.py +1112 -1112
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/buckets/BucketCollection.py +63 -63
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +248 -248
- edsl/jobs/interviews/Interview.py +661 -651
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
- edsl/jobs/interviews/InterviewExceptionEntry.py +189 -182
- edsl/jobs/interviews/InterviewStatistic.py +63 -63
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
- edsl/jobs/interviews/InterviewStatusLog.py +92 -92
- edsl/jobs/interviews/ReportErrors.py +66 -66
- edsl/jobs/interviews/interview_status_enum.py +9 -9
- edsl/jobs/runners/JobsRunnerAsyncio.py +337 -337
- edsl/jobs/runners/JobsRunnerStatus.py +332 -332
- edsl/jobs/tasks/QuestionTaskCreator.py +242 -242
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +441 -441
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +163 -163
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/LanguageModel.py +718 -718
- edsl/language_models/ModelList.py +102 -102
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/__init__.py +2 -2
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/registry.py +137 -137
- edsl/language_models/repair.py +156 -156
- edsl/language_models/unused/ReplicateBase.py +83 -83
- edsl/language_models/utilities.py +64 -64
- edsl/notebooks/Notebook.py +259 -259
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +358 -358
- edsl/prompts/__init__.py +2 -2
- edsl/questions/AnswerValidatorMixin.py +289 -289
- edsl/questions/QuestionBase.py +616 -616
- edsl/questions/QuestionBaseGenMixin.py +161 -161
- edsl/questions/QuestionBasePromptsMixin.py +266 -266
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +183 -183
- edsl/questions/QuestionFreeText.py +113 -113
- edsl/questions/QuestionFunctional.py +159 -159
- edsl/questions/QuestionList.py +231 -231
- edsl/questions/QuestionMultipleChoice.py +286 -286
- edsl/questions/QuestionNumerical.py +153 -153
- edsl/questions/QuestionRank.py +324 -324
- edsl/questions/Quick.py +41 -41
- edsl/questions/RegisterQuestionsMeta.py +71 -71
- edsl/questions/ResponseValidatorABC.py +174 -174
- edsl/questions/SimpleAskMixin.py +73 -73
- edsl/questions/__init__.py +26 -26
- edsl/questions/compose_questions.py +98 -98
- edsl/questions/decorators.py +21 -21
- edsl/questions/derived/QuestionLikertFive.py +76 -76
- edsl/questions/derived/QuestionLinearScale.py +87 -87
- edsl/questions/derived/QuestionTopK.py +91 -91
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +418 -418
- edsl/questions/prompt_templates/question_budget.jinja +13 -13
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
- edsl/questions/prompt_templates/question_extract.jinja +11 -11
- edsl/questions/prompt_templates/question_free_text.jinja +3 -3
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
- edsl/questions/prompt_templates/question_list.jinja +17 -17
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
- edsl/questions/prompt_templates/question_numerical.jinja +36 -36
- edsl/questions/question_registry.py +147 -147
- edsl/questions/settings.py +12 -12
- edsl/questions/templates/budget/answering_instructions.jinja +7 -7
- edsl/questions/templates/budget/question_presentation.jinja +7 -7
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
- edsl/questions/templates/extract/answering_instructions.jinja +7 -7
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
- edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
- edsl/questions/templates/list/answering_instructions.jinja +3 -3
- edsl/questions/templates/list/question_presentation.jinja +5 -5
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
- edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
- edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
- edsl/questions/templates/numerical/question_presentation.jinja +6 -6
- edsl/questions/templates/rank/answering_instructions.jinja +11 -11
- edsl/questions/templates/rank/question_presentation.jinja +15 -15
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
- edsl/questions/templates/top_k/question_presentation.jinja +22 -22
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
- edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
- edsl/results/Dataset.py +293 -293
- edsl/results/DatasetExportMixin.py +693 -693
- edsl/results/DatasetTree.py +145 -145
- edsl/results/Result.py +433 -433
- edsl/results/Results.py +1158 -1158
- edsl/results/ResultsDBMixin.py +238 -238
- edsl/results/ResultsExportMixin.py +43 -43
- edsl/results/ResultsFetchMixin.py +33 -33
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/ResultsToolsMixin.py +98 -98
- edsl/results/Selector.py +118 -118
- edsl/results/__init__.py +2 -2
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/FileStore.py +458 -443
- edsl/scenarios/Scenario.py +510 -507
- edsl/scenarios/ScenarioHtmlMixin.py +59 -59
- edsl/scenarios/ScenarioList.py +1101 -1101
- edsl/scenarios/ScenarioListExportMixin.py +52 -52
- edsl/scenarios/ScenarioListPdfMixin.py +261 -261
- edsl/scenarios/__init__.py +4 -2
- edsl/shared.py +1 -1
- edsl/study/ObjectEntry.py +173 -173
- edsl/study/ProofOfWork.py +113 -113
- edsl/study/SnapShot.py +80 -80
- edsl/study/Study.py +528 -528
- edsl/study/__init__.py +4 -4
- edsl/surveys/DAG.py +148 -148
- edsl/surveys/Memory.py +31 -31
- edsl/surveys/MemoryPlan.py +244 -244
- edsl/surveys/Rule.py +324 -324
- edsl/surveys/RuleCollection.py +387 -387
- edsl/surveys/Survey.py +1772 -1772
- edsl/surveys/SurveyCSS.py +261 -261
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/SurveyFlowVisualizationMixin.py +121 -121
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/__init__.py +3 -3
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +56 -56
- edsl/surveys/instructions/ChangeInstruction.py +47 -47
- edsl/surveys/instructions/Instruction.py +51 -51
- edsl/surveys/instructions/InstructionCollection.py +77 -77
- edsl/templates/error_reporting/base.html +23 -23
- edsl/templates/error_reporting/exceptions_by_model.html +34 -34
- edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
- edsl/templates/error_reporting/exceptions_by_type.html +16 -16
- edsl/templates/error_reporting/interview_details.html +115 -115
- edsl/templates/error_reporting/interviews.html +9 -9
- edsl/templates/error_reporting/overview.html +4 -4
- edsl/templates/error_reporting/performance_plot.html +1 -1
- edsl/templates/error_reporting/report.css +73 -73
- edsl/templates/error_reporting/report.html +117 -117
- edsl/templates/error_reporting/report.js +25 -25
- edsl/tools/__init__.py +1 -1
- edsl/tools/clusters.py +192 -192
- edsl/tools/embeddings.py +27 -27
- edsl/tools/embeddings_plotting.py +118 -118
- edsl/tools/plotting.py +112 -112
- edsl/tools/summarize.py +18 -18
- edsl/utilities/SystemInfo.py +28 -28
- edsl/utilities/__init__.py +22 -22
- edsl/utilities/ast_utilities.py +25 -25
- edsl/utilities/data/Registry.py +6 -6
- edsl/utilities/data/__init__.py +1 -1
- edsl/utilities/data/scooter_results.json +1 -1
- edsl/utilities/decorators.py +77 -77
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
- edsl/utilities/interface.py +627 -627
- edsl/utilities/repair_functions.py +28 -28
- edsl/utilities/restricted_python.py +70 -70
- edsl/utilities/utilities.py +391 -391
- {edsl-0.1.36.dev5.dist-info → edsl-0.1.36.dev7.dist-info}/LICENSE +21 -21
- {edsl-0.1.36.dev5.dist-info → edsl-0.1.36.dev7.dist-info}/METADATA +1 -1
- edsl-0.1.36.dev7.dist-info/RECORD +279 -0
- edsl-0.1.36.dev5.dist-info/RECORD +0 -279
- {edsl-0.1.36.dev5.dist-info → edsl-0.1.36.dev7.dist-info}/WHEEL +0 -0
edsl/agents/InvigilatorBase.py
CHANGED
@@ -1,294 +1,298 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
import asyncio
|
3
|
-
from typing import Coroutine, Dict, Any, Optional
|
4
|
-
|
5
|
-
from edsl.prompts.Prompt import Prompt
|
6
|
-
from edsl.utilities.decorators import jupyter_nb_handler
|
7
|
-
from edsl.data_transfer_models import AgentResponseDict
|
8
|
-
|
9
|
-
from edsl.data.Cache import Cache
|
10
|
-
|
11
|
-
from edsl.questions.QuestionBase import QuestionBase
|
12
|
-
from edsl.scenarios.Scenario import Scenario
|
13
|
-
from edsl.surveys.MemoryPlan import MemoryPlan
|
14
|
-
from edsl.language_models.LanguageModel import LanguageModel
|
15
|
-
|
16
|
-
from edsl.data_transfer_models import EDSLResultObjectInput
|
17
|
-
from edsl.agents.PromptConstructor import PromptConstructor
|
18
|
-
|
19
|
-
|
20
|
-
class InvigilatorBase(ABC):
|
21
|
-
"""An invigiator (someone who administers an exam) is a class that is responsible for administering a question to an agent.
|
22
|
-
|
23
|
-
>>> InvigilatorBase.example().answer_question()
|
24
|
-
{'message': [{'text': 'SPAM!'}], 'usage': {'prompt_tokens': 1, 'completion_tokens': 1}}
|
25
|
-
|
26
|
-
>>> InvigilatorBase.example().get_failed_task_result(failure_reason="Failed to get response").comment
|
27
|
-
'Failed to get response'
|
28
|
-
|
29
|
-
This returns an empty prompt because there is no memory the agent needs to have at q0.
|
30
|
-
|
31
|
-
|
32
|
-
"""
|
33
|
-
|
34
|
-
def __init__(
|
35
|
-
self,
|
36
|
-
agent: "Agent",
|
37
|
-
question: QuestionBase,
|
38
|
-
scenario: Scenario,
|
39
|
-
model: LanguageModel,
|
40
|
-
memory_plan: MemoryPlan,
|
41
|
-
current_answers: dict,
|
42
|
-
survey: Optional["Survey"],
|
43
|
-
cache: Optional[Cache] = None,
|
44
|
-
iteration: Optional[int] = 1,
|
45
|
-
additional_prompt_data: Optional[dict] = None,
|
46
|
-
sidecar_model: Optional[LanguageModel] = None,
|
47
|
-
raise_validation_errors: Optional[bool] = True,
|
48
|
-
):
|
49
|
-
"""Initialize a new Invigilator."""
|
50
|
-
self.agent = agent
|
51
|
-
self.question = question
|
52
|
-
self.scenario = scenario
|
53
|
-
self.model = model
|
54
|
-
self.memory_plan = memory_plan
|
55
|
-
self.current_answers = current_answers or {}
|
56
|
-
self.iteration = iteration
|
57
|
-
self.additional_prompt_data = additional_prompt_data
|
58
|
-
self.cache = cache
|
59
|
-
self.sidecar_model = sidecar_model
|
60
|
-
self.survey = survey
|
61
|
-
self.raise_validation_errors = raise_validation_errors
|
62
|
-
|
63
|
-
self.raw_model_response = (
|
64
|
-
None # placeholder for the raw response from the model
|
65
|
-
)
|
66
|
-
|
67
|
-
@property
|
68
|
-
def prompt_constructor(self) -> PromptConstructor:
|
69
|
-
"""Return the prompt constructor."""
|
70
|
-
return PromptConstructor(self)
|
71
|
-
|
72
|
-
def to_dict(self):
|
73
|
-
attributes = [
|
74
|
-
"agent",
|
75
|
-
"question",
|
76
|
-
"scenario",
|
77
|
-
"model",
|
78
|
-
"memory_plan",
|
79
|
-
"current_answers",
|
80
|
-
"iteration",
|
81
|
-
"additional_prompt_data",
|
82
|
-
"cache",
|
83
|
-
"sidecar_model",
|
84
|
-
"survey",
|
85
|
-
]
|
86
|
-
|
87
|
-
def serialize_attribute(attr):
|
88
|
-
value = getattr(self, attr)
|
89
|
-
if value is None:
|
90
|
-
return None
|
91
|
-
if hasattr(value, "to_dict"):
|
92
|
-
return value.to_dict()
|
93
|
-
if isinstance(value, (int, float, str, bool, dict, list)):
|
94
|
-
return value
|
95
|
-
return str(value)
|
96
|
-
|
97
|
-
return {attr: serialize_attribute(attr) for attr in attributes}
|
98
|
-
|
99
|
-
@classmethod
|
100
|
-
def from_dict(cls, data):
|
101
|
-
from edsl.agents.Agent import Agent
|
102
|
-
from edsl.questions import QuestionBase
|
103
|
-
from edsl.scenarios.Scenario import Scenario
|
104
|
-
from edsl.surveys.MemoryPlan import MemoryPlan
|
105
|
-
from edsl.language_models.LanguageModel import LanguageModel
|
106
|
-
from edsl.surveys.Survey import Survey
|
107
|
-
|
108
|
-
agent = Agent.from_dict(data["agent"])
|
109
|
-
question = QuestionBase.from_dict(data["question"])
|
110
|
-
scenario = Scenario.from_dict(data["scenario"])
|
111
|
-
model = LanguageModel.from_dict(data["model"])
|
112
|
-
memory_plan = MemoryPlan.from_dict(data["memory_plan"])
|
113
|
-
survey = Survey.from_dict(data["survey"])
|
114
|
-
current_answers = data["current_answers"]
|
115
|
-
iteration = data["iteration"]
|
116
|
-
additional_prompt_data = data["additional_prompt_data"]
|
117
|
-
cache = Cache.from_dict(data["cache"])
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
"""
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
"
|
157
|
-
"
|
158
|
-
"
|
159
|
-
"
|
160
|
-
"
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
#
|
169
|
-
#
|
170
|
-
#
|
171
|
-
|
172
|
-
# generated_tokens =
|
173
|
-
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
# generated_tokens=
|
177
|
-
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
from edsl.
|
222
|
-
|
223
|
-
from edsl.
|
224
|
-
|
225
|
-
from edsl import
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
#
|
233
|
-
#
|
234
|
-
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
238
|
-
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
242
|
-
|
243
|
-
#
|
244
|
-
#
|
245
|
-
# return
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
if question:
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
from edsl
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
import asyncio
|
3
|
+
from typing import Coroutine, Dict, Any, Optional
|
4
|
+
|
5
|
+
from edsl.prompts.Prompt import Prompt
|
6
|
+
from edsl.utilities.decorators import jupyter_nb_handler
|
7
|
+
from edsl.data_transfer_models import AgentResponseDict
|
8
|
+
|
9
|
+
from edsl.data.Cache import Cache
|
10
|
+
|
11
|
+
from edsl.questions.QuestionBase import QuestionBase
|
12
|
+
from edsl.scenarios.Scenario import Scenario
|
13
|
+
from edsl.surveys.MemoryPlan import MemoryPlan
|
14
|
+
from edsl.language_models.LanguageModel import LanguageModel
|
15
|
+
|
16
|
+
from edsl.data_transfer_models import EDSLResultObjectInput
|
17
|
+
from edsl.agents.PromptConstructor import PromptConstructor
|
18
|
+
|
19
|
+
|
20
|
+
class InvigilatorBase(ABC):
|
21
|
+
"""An invigiator (someone who administers an exam) is a class that is responsible for administering a question to an agent.
|
22
|
+
|
23
|
+
>>> InvigilatorBase.example().answer_question()
|
24
|
+
{'message': [{'text': 'SPAM!'}], 'usage': {'prompt_tokens': 1, 'completion_tokens': 1}}
|
25
|
+
|
26
|
+
>>> InvigilatorBase.example().get_failed_task_result(failure_reason="Failed to get response").comment
|
27
|
+
'Failed to get response'
|
28
|
+
|
29
|
+
This returns an empty prompt because there is no memory the agent needs to have at q0.
|
30
|
+
|
31
|
+
|
32
|
+
"""
|
33
|
+
|
34
|
+
def __init__(
|
35
|
+
self,
|
36
|
+
agent: "Agent",
|
37
|
+
question: QuestionBase,
|
38
|
+
scenario: Scenario,
|
39
|
+
model: LanguageModel,
|
40
|
+
memory_plan: MemoryPlan,
|
41
|
+
current_answers: dict,
|
42
|
+
survey: Optional["Survey"],
|
43
|
+
cache: Optional[Cache] = None,
|
44
|
+
iteration: Optional[int] = 1,
|
45
|
+
additional_prompt_data: Optional[dict] = None,
|
46
|
+
sidecar_model: Optional[LanguageModel] = None,
|
47
|
+
raise_validation_errors: Optional[bool] = True,
|
48
|
+
):
|
49
|
+
"""Initialize a new Invigilator."""
|
50
|
+
self.agent = agent
|
51
|
+
self.question = question
|
52
|
+
self.scenario = scenario
|
53
|
+
self.model = model
|
54
|
+
self.memory_plan = memory_plan
|
55
|
+
self.current_answers = current_answers or {}
|
56
|
+
self.iteration = iteration
|
57
|
+
self.additional_prompt_data = additional_prompt_data
|
58
|
+
self.cache = cache
|
59
|
+
self.sidecar_model = sidecar_model
|
60
|
+
self.survey = survey
|
61
|
+
self.raise_validation_errors = raise_validation_errors
|
62
|
+
|
63
|
+
self.raw_model_response = (
|
64
|
+
None # placeholder for the raw response from the model
|
65
|
+
)
|
66
|
+
|
67
|
+
@property
|
68
|
+
def prompt_constructor(self) -> PromptConstructor:
|
69
|
+
"""Return the prompt constructor."""
|
70
|
+
return PromptConstructor(self)
|
71
|
+
|
72
|
+
def to_dict(self):
|
73
|
+
attributes = [
|
74
|
+
"agent",
|
75
|
+
"question",
|
76
|
+
"scenario",
|
77
|
+
"model",
|
78
|
+
"memory_plan",
|
79
|
+
"current_answers",
|
80
|
+
"iteration",
|
81
|
+
"additional_prompt_data",
|
82
|
+
"cache",
|
83
|
+
"sidecar_model",
|
84
|
+
"survey",
|
85
|
+
]
|
86
|
+
|
87
|
+
def serialize_attribute(attr):
|
88
|
+
value = getattr(self, attr)
|
89
|
+
if value is None:
|
90
|
+
return None
|
91
|
+
if hasattr(value, "to_dict"):
|
92
|
+
return value.to_dict()
|
93
|
+
if isinstance(value, (int, float, str, bool, dict, list)):
|
94
|
+
return value
|
95
|
+
return str(value)
|
96
|
+
|
97
|
+
return {attr: serialize_attribute(attr) for attr in attributes}
|
98
|
+
|
99
|
+
@classmethod
|
100
|
+
def from_dict(cls, data):
|
101
|
+
from edsl.agents.Agent import Agent
|
102
|
+
from edsl.questions import QuestionBase
|
103
|
+
from edsl.scenarios.Scenario import Scenario
|
104
|
+
from edsl.surveys.MemoryPlan import MemoryPlan
|
105
|
+
from edsl.language_models.LanguageModel import LanguageModel
|
106
|
+
from edsl.surveys.Survey import Survey
|
107
|
+
|
108
|
+
agent = Agent.from_dict(data["agent"])
|
109
|
+
question = QuestionBase.from_dict(data["question"])
|
110
|
+
scenario = Scenario.from_dict(data["scenario"])
|
111
|
+
model = LanguageModel.from_dict(data["model"])
|
112
|
+
memory_plan = MemoryPlan.from_dict(data["memory_plan"])
|
113
|
+
survey = Survey.from_dict(data["survey"])
|
114
|
+
current_answers = data["current_answers"]
|
115
|
+
iteration = data["iteration"]
|
116
|
+
additional_prompt_data = data["additional_prompt_data"]
|
117
|
+
cache = Cache.from_dict(data["cache"])
|
118
|
+
|
119
|
+
if data["sidecar_model"] is None:
|
120
|
+
sidecar_model = None
|
121
|
+
else:
|
122
|
+
sidecar_model = LanguageModel.from_dict(data["sidecar_model"])
|
123
|
+
|
124
|
+
return cls(
|
125
|
+
agent=agent,
|
126
|
+
question=question,
|
127
|
+
scenario=scenario,
|
128
|
+
model=model,
|
129
|
+
memory_plan=memory_plan,
|
130
|
+
current_answers=current_answers,
|
131
|
+
survey=survey,
|
132
|
+
iteration=iteration,
|
133
|
+
additional_prompt_data=additional_prompt_data,
|
134
|
+
cache=cache,
|
135
|
+
sidecar_model=sidecar_model,
|
136
|
+
)
|
137
|
+
|
138
|
+
def __repr__(self) -> str:
|
139
|
+
"""Return a string representation of the Invigilator.
|
140
|
+
|
141
|
+
>>> InvigilatorBase.example().__repr__()
|
142
|
+
'InvigilatorExample(...)'
|
143
|
+
|
144
|
+
"""
|
145
|
+
return f"{self.__class__.__name__}(agent={repr(self.agent)}, question={repr(self.question)}, scneario={repr(self.scenario)}, model={repr(self.model)}, memory_plan={repr(self.memory_plan)}, current_answers={repr(self.current_answers)}, iteration{repr(self.iteration)}, additional_prompt_data={repr(self.additional_prompt_data)}, cache={repr(self.cache)}, sidecarmodel={repr(self.sidecar_model)})"
|
146
|
+
|
147
|
+
def get_failed_task_result(self, failure_reason) -> EDSLResultObjectInput:
|
148
|
+
"""Return an AgentResponseDict used in case the question-asking fails.
|
149
|
+
|
150
|
+
Possible reasons include:
|
151
|
+
- Legimately skipped because of skip logic
|
152
|
+
- Failed to get response from the model
|
153
|
+
|
154
|
+
"""
|
155
|
+
data = {
|
156
|
+
"answer": None,
|
157
|
+
"generated_tokens": None,
|
158
|
+
"comment": failure_reason,
|
159
|
+
"question_name": self.question.question_name,
|
160
|
+
"prompts": self.get_prompts(),
|
161
|
+
"cached_response": None,
|
162
|
+
"raw_model_response": None,
|
163
|
+
"cache_used": None,
|
164
|
+
"cache_key": None,
|
165
|
+
}
|
166
|
+
return EDSLResultObjectInput(**data)
|
167
|
+
|
168
|
+
# breakpoint()
|
169
|
+
# if hasattr(self, "augmented_model_response"):
|
170
|
+
# import json
|
171
|
+
|
172
|
+
# generated_tokens = json.loads(self.augmented_model_response)["answer"][
|
173
|
+
# "generated_tokens"
|
174
|
+
# ]
|
175
|
+
# else:
|
176
|
+
# generated_tokens = "Filled in by InvigilatorBase.get_failed_task_result"
|
177
|
+
# agent_response_dict = AgentResponseDict(
|
178
|
+
# answer=None,
|
179
|
+
# comment="Failed to get usable response",
|
180
|
+
# generated_tokens=generated_tokens,
|
181
|
+
# question_name=self.question.question_name,
|
182
|
+
# prompts=self.get_prompts(),
|
183
|
+
# )
|
184
|
+
# # breakpoint()
|
185
|
+
# return agent_response_dict
|
186
|
+
|
187
|
+
def get_prompts(self) -> Dict[str, Prompt]:
|
188
|
+
"""Return the prompt used."""
|
189
|
+
|
190
|
+
return {
|
191
|
+
"user_prompt": Prompt("NA"),
|
192
|
+
"system_prompt": Prompt("NA"),
|
193
|
+
}
|
194
|
+
|
195
|
+
@abstractmethod
|
196
|
+
async def async_answer_question(self):
|
197
|
+
"""Asnwer a question."""
|
198
|
+
pass
|
199
|
+
|
200
|
+
@jupyter_nb_handler
|
201
|
+
def answer_question(self) -> Coroutine:
|
202
|
+
"""Return a function that gets the answers to the question."""
|
203
|
+
|
204
|
+
async def main():
|
205
|
+
"""Return the answer to the question."""
|
206
|
+
results = await asyncio.gather(self.async_answer_question())
|
207
|
+
return results[0] # Since there's only one task, return its result
|
208
|
+
|
209
|
+
return main()
|
210
|
+
|
211
|
+
@classmethod
|
212
|
+
def example(
|
213
|
+
cls, throw_an_exception=False, question=None, scenario=None, survey=None
|
214
|
+
) -> "InvigilatorBase":
|
215
|
+
"""Return an example invigilator.
|
216
|
+
|
217
|
+
>>> InvigilatorBase.example()
|
218
|
+
InvigilatorExample(...)
|
219
|
+
|
220
|
+
"""
|
221
|
+
from edsl.agents.Agent import Agent
|
222
|
+
from edsl.questions import QuestionMultipleChoice
|
223
|
+
from edsl.scenarios.Scenario import Scenario
|
224
|
+
from edsl.language_models import LanguageModel
|
225
|
+
from edsl.surveys.MemoryPlan import MemoryPlan
|
226
|
+
|
227
|
+
from edsl.enums import InferenceServiceType
|
228
|
+
|
229
|
+
from edsl import Model
|
230
|
+
|
231
|
+
model = Model("test", canned_response="SPAM!")
|
232
|
+
# class TestLanguageModelGood(LanguageModel):
|
233
|
+
# """A test language model."""
|
234
|
+
|
235
|
+
# _model_ = "test"
|
236
|
+
# _parameters_ = {"temperature": 0.5}
|
237
|
+
# _inference_service_ = InferenceServiceType.TEST.value
|
238
|
+
|
239
|
+
# async def async_execute_model_call(
|
240
|
+
# self, user_prompt: str, system_prompt: str
|
241
|
+
# ) -> dict[str, Any]:
|
242
|
+
# await asyncio.sleep(0.1)
|
243
|
+
# if hasattr(self, "throw_an_exception"):
|
244
|
+
# raise Exception("Error!")
|
245
|
+
# return {"message": """{"answer": "SPAM!"}"""}
|
246
|
+
|
247
|
+
# def parse_response(self, raw_response: dict[str, Any]) -> str:
|
248
|
+
# """Parse the response from the model."""
|
249
|
+
# return raw_response["message"]
|
250
|
+
|
251
|
+
if throw_an_exception:
|
252
|
+
model.throw_an_exception = True
|
253
|
+
agent = Agent.example()
|
254
|
+
# question = QuestionMultipleChoice.example()
|
255
|
+
from edsl.surveys import Survey
|
256
|
+
|
257
|
+
if not survey:
|
258
|
+
survey = Survey.example()
|
259
|
+
# if question:
|
260
|
+
# need to have the focal question name in the list of names
|
261
|
+
# survey._questions[0].question_name = question.question_name
|
262
|
+
# survey.add_question(question)
|
263
|
+
if question:
|
264
|
+
survey.add_question(question)
|
265
|
+
|
266
|
+
question = question or survey.questions[0]
|
267
|
+
scenario = scenario or Scenario.example()
|
268
|
+
# memory_plan = None #memory_plan = MemoryPlan()
|
269
|
+
from edsl import Survey
|
270
|
+
|
271
|
+
memory_plan = MemoryPlan(survey=survey)
|
272
|
+
current_answers = None
|
273
|
+
from edsl.agents.PromptConstructor import PromptConstructor
|
274
|
+
|
275
|
+
class InvigilatorExample(InvigilatorBase):
|
276
|
+
"""An example invigilator."""
|
277
|
+
|
278
|
+
async def async_answer_question(self):
|
279
|
+
"""Answer a question."""
|
280
|
+
return await self.model.async_execute_model_call(
|
281
|
+
user_prompt="Hello", system_prompt="Hi"
|
282
|
+
)
|
283
|
+
|
284
|
+
return InvigilatorExample(
|
285
|
+
agent=agent,
|
286
|
+
question=question,
|
287
|
+
scenario=scenario,
|
288
|
+
survey=survey,
|
289
|
+
model=model,
|
290
|
+
memory_plan=memory_plan,
|
291
|
+
current_answers=current_answers,
|
292
|
+
)
|
293
|
+
|
294
|
+
|
295
|
+
if __name__ == "__main__":
|
296
|
+
import doctest
|
297
|
+
|
298
|
+
doctest.testmod(optionflags=doctest.ELLIPSIS)
|