edsl 0.1.28__py3-none-any.whl → 0.1.29__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 +18 -18
- edsl/__init__.py +24 -24
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +77 -41
- edsl/agents/AgentList.py +35 -6
- edsl/agents/Invigilator.py +19 -1
- edsl/agents/InvigilatorBase.py +15 -10
- edsl/agents/PromptConstructionMixin.py +342 -100
- edsl/agents/descriptors.py +2 -1
- edsl/base/Base.py +289 -0
- edsl/config.py +2 -1
- edsl/conjure/InputData.py +39 -8
- edsl/coop/coop.py +188 -151
- edsl/coop/utils.py +43 -75
- edsl/data/Cache.py +19 -5
- edsl/data/SQLiteDict.py +11 -3
- edsl/jobs/Answers.py +15 -1
- edsl/jobs/Jobs.py +92 -47
- edsl/jobs/buckets/ModelBuckets.py +4 -2
- edsl/jobs/buckets/TokenBucket.py +1 -2
- edsl/jobs/interviews/Interview.py +3 -9
- edsl/jobs/interviews/InterviewStatusMixin.py +3 -3
- edsl/jobs/interviews/InterviewTaskBuildingMixin.py +15 -10
- edsl/jobs/runners/JobsRunnerAsyncio.py +21 -25
- edsl/jobs/tasks/TaskHistory.py +4 -3
- edsl/language_models/LanguageModel.py +5 -11
- edsl/language_models/ModelList.py +3 -3
- edsl/language_models/repair.py +8 -7
- edsl/notebooks/Notebook.py +40 -3
- edsl/prompts/Prompt.py +31 -19
- edsl/questions/QuestionBase.py +38 -13
- edsl/questions/QuestionBudget.py +5 -6
- edsl/questions/QuestionCheckBox.py +7 -3
- edsl/questions/QuestionExtract.py +5 -3
- edsl/questions/QuestionFreeText.py +3 -3
- edsl/questions/QuestionFunctional.py +0 -3
- edsl/questions/QuestionList.py +3 -4
- edsl/questions/QuestionMultipleChoice.py +16 -8
- edsl/questions/QuestionNumerical.py +4 -3
- edsl/questions/QuestionRank.py +5 -3
- edsl/questions/__init__.py +4 -3
- edsl/questions/descriptors.py +4 -2
- edsl/questions/question_registry.py +20 -31
- edsl/questions/settings.py +1 -1
- edsl/results/Dataset.py +31 -0
- edsl/results/DatasetExportMixin.py +493 -0
- edsl/results/Result.py +22 -74
- edsl/results/Results.py +105 -67
- edsl/results/ResultsDBMixin.py +7 -3
- edsl/results/ResultsExportMixin.py +22 -537
- edsl/results/ResultsGGMixin.py +3 -3
- edsl/results/ResultsToolsMixin.py +5 -5
- edsl/scenarios/FileStore.py +140 -0
- edsl/scenarios/Scenario.py +5 -6
- edsl/scenarios/ScenarioList.py +44 -15
- edsl/scenarios/ScenarioListExportMixin.py +32 -0
- edsl/scenarios/ScenarioListPdfMixin.py +2 -1
- edsl/scenarios/__init__.py +1 -0
- edsl/study/ObjectEntry.py +89 -13
- edsl/study/ProofOfWork.py +5 -2
- edsl/study/SnapShot.py +4 -8
- edsl/study/Study.py +21 -14
- edsl/study/__init__.py +2 -0
- edsl/surveys/MemoryPlan.py +11 -4
- edsl/surveys/Survey.py +46 -7
- edsl/surveys/SurveyExportMixin.py +4 -2
- edsl/surveys/SurveyFlowVisualizationMixin.py +6 -4
- edsl/tools/plotting.py +4 -2
- edsl/utilities/__init__.py +21 -21
- edsl/utilities/interface.py +66 -45
- edsl/utilities/utilities.py +11 -13
- {edsl-0.1.28.dist-info → edsl-0.1.29.dist-info}/METADATA +11 -10
- {edsl-0.1.28.dist-info → edsl-0.1.29.dist-info}/RECORD +75 -72
- edsl-0.1.28.dist-info/entry_points.txt +0 -3
- {edsl-0.1.28.dist-info → edsl-0.1.29.dist-info}/LICENSE +0 -0
- {edsl-0.1.28.dist-info → edsl-0.1.29.dist-info}/WHEEL +0 -0
edsl/Base.py
CHANGED
@@ -6,9 +6,6 @@ import io
|
|
6
6
|
import json
|
7
7
|
from typing import Any, Optional, Union
|
8
8
|
from uuid import UUID
|
9
|
-
from IPython.display import display
|
10
|
-
from rich.console import Console
|
11
|
-
from edsl.utilities import is_notebook
|
12
9
|
|
13
10
|
|
14
11
|
class RichPrintingMixin:
|
@@ -16,6 +13,8 @@ class RichPrintingMixin:
|
|
16
13
|
|
17
14
|
def _for_console(self):
|
18
15
|
"""Return a string representation of the object for console printing."""
|
16
|
+
from rich.console import Console
|
17
|
+
|
19
18
|
with io.StringIO() as buf:
|
20
19
|
console = Console(file=buf, record=True)
|
21
20
|
table = self.rich_print()
|
@@ -28,7 +27,11 @@ class RichPrintingMixin:
|
|
28
27
|
|
29
28
|
def print(self):
|
30
29
|
"""Print the object to the console."""
|
30
|
+
from edsl.utilities.utilities import is_notebook
|
31
|
+
|
31
32
|
if is_notebook():
|
33
|
+
from IPython.display import display
|
34
|
+
|
32
35
|
display(self.rich_print())
|
33
36
|
else:
|
34
37
|
from rich.console import Console
|
@@ -52,31 +55,28 @@ class PersistenceMixin:
|
|
52
55
|
return c.create(self, description, visibility)
|
53
56
|
|
54
57
|
@classmethod
|
55
|
-
def pull(cls,
|
58
|
+
def pull(cls, uuid: Optional[Union[str, UUID]] = None, url: Optional[str] = None):
|
56
59
|
"""Pull the object from coop."""
|
57
60
|
from edsl.coop import Coop
|
61
|
+
from edsl.coop.utils import ObjectRegistry
|
58
62
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
uuid_value = id_or_url
|
63
|
-
|
64
|
-
c = Coop()
|
65
|
-
|
66
|
-
return c._get_base(cls, uuid_value, exec_profile=exec_profile)
|
63
|
+
object_type = ObjectRegistry.get_object_type_by_edsl_class(cls)
|
64
|
+
coop = Coop()
|
65
|
+
return coop.get(uuid, url, object_type)
|
67
66
|
|
68
67
|
@classmethod
|
69
|
-
def delete(cls,
|
68
|
+
def delete(cls, uuid: Optional[Union[str, UUID]] = None, url: Optional[str] = None):
|
70
69
|
"""Delete the object from coop."""
|
71
70
|
from edsl.coop import Coop
|
72
71
|
|
73
|
-
|
74
|
-
return
|
72
|
+
coop = Coop()
|
73
|
+
return coop.delete(uuid, url)
|
75
74
|
|
76
75
|
@classmethod
|
77
76
|
def patch(
|
78
77
|
cls,
|
79
|
-
|
78
|
+
uuid: Optional[Union[str, UUID]] = None,
|
79
|
+
url: Optional[str] = None,
|
80
80
|
description: Optional[str] = None,
|
81
81
|
value: Optional[Any] = None,
|
82
82
|
visibility: Optional[str] = None,
|
@@ -89,8 +89,8 @@ class PersistenceMixin:
|
|
89
89
|
"""
|
90
90
|
from edsl.coop import Coop
|
91
91
|
|
92
|
-
|
93
|
-
return
|
92
|
+
coop = Coop()
|
93
|
+
return coop.patch(uuid, url, description, value, visibility)
|
94
94
|
|
95
95
|
@classmethod
|
96
96
|
def search(cls, query):
|
edsl/__init__.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import os
|
2
|
+
import time
|
2
3
|
|
3
4
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
4
5
|
ROOT_DIR = os.path.dirname(BASE_DIR)
|
@@ -7,36 +8,35 @@ from edsl.__version__ import __version__
|
|
7
8
|
from edsl.config import Config, CONFIG
|
8
9
|
from edsl.agents.Agent import Agent
|
9
10
|
from edsl.agents.AgentList import AgentList
|
10
|
-
from edsl.questions import
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
from edsl.scenarios
|
27
|
-
|
28
|
-
from edsl.utilities.interface import print_dict_with_rich
|
11
|
+
from edsl.questions import QuestionBase
|
12
|
+
from edsl.questions import QuestionMultipleChoice
|
13
|
+
from edsl.questions import QuestionBudget
|
14
|
+
from edsl.questions import QuestionCheckBox
|
15
|
+
from edsl.questions import QuestionExtract
|
16
|
+
from edsl.questions import QuestionFreeText
|
17
|
+
from edsl.questions import QuestionFunctional
|
18
|
+
from edsl.questions import QuestionLikertFive
|
19
|
+
from edsl.questions import QuestionList
|
20
|
+
from edsl.questions import QuestionLinearScale
|
21
|
+
from edsl.questions import QuestionNumerical
|
22
|
+
from edsl.questions import QuestionRank
|
23
|
+
from edsl.questions import QuestionTopK
|
24
|
+
from edsl.questions import QuestionYesNo
|
25
|
+
from edsl.questions.question_registry import Question
|
26
|
+
from edsl.scenarios import Scenario
|
27
|
+
from edsl.scenarios import ScenarioList
|
28
|
+
|
29
|
+
# from edsl.utilities.interface import print_dict_with_rich
|
29
30
|
from edsl.surveys.Survey import Survey
|
30
31
|
from edsl.language_models.registry import Model
|
31
|
-
from edsl.
|
32
|
+
from edsl.language_models.ModelList import ModelList
|
32
33
|
from edsl.results.Results import Results
|
33
34
|
from edsl.data.Cache import Cache
|
34
35
|
from edsl.data.CacheEntry import CacheEntry
|
35
36
|
from edsl.data.CacheHandler import set_session_cache, unset_session_cache
|
36
37
|
from edsl.shared import shared_globals
|
37
|
-
from edsl.jobs import Jobs
|
38
|
-
from edsl.notebooks import Notebook
|
38
|
+
from edsl.jobs.Jobs import Jobs
|
39
|
+
from edsl.notebooks.Notebook import Notebook
|
39
40
|
from edsl.study.Study import Study
|
40
|
-
from edsl.coop.coop import Coop
|
41
41
|
from edsl.conjure.Conjure import Conjure
|
42
|
-
from edsl.
|
42
|
+
from edsl.coop.coop import Coop
|
edsl/__version__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.29"
|
edsl/agents/Agent.py
CHANGED
@@ -5,27 +5,14 @@ import copy
|
|
5
5
|
import inspect
|
6
6
|
import types
|
7
7
|
from typing import Any, Callable, Optional, Union, Dict, Sequence
|
8
|
-
|
9
|
-
from rich.table import Table
|
10
|
-
|
11
8
|
from edsl.Base import Base
|
12
|
-
|
13
|
-
from edsl.language_models import LanguageModel
|
14
|
-
from edsl.surveys.MemoryPlan import MemoryPlan
|
9
|
+
|
15
10
|
from edsl.exceptions.agents import (
|
16
11
|
AgentCombinationError,
|
17
12
|
AgentDirectAnswerFunctionError,
|
18
13
|
AgentDynamicTraitsFunctionError,
|
19
14
|
)
|
20
|
-
|
21
|
-
InvigilatorDebug,
|
22
|
-
InvigilatorHuman,
|
23
|
-
InvigilatorFunctional,
|
24
|
-
InvigilatorAI,
|
25
|
-
InvigilatorBase,
|
26
|
-
)
|
27
|
-
from edsl.language_models.registry import Model
|
28
|
-
from edsl.scenarios import Scenario
|
15
|
+
|
29
16
|
from edsl.agents.descriptors import (
|
30
17
|
TraitsDescriptor,
|
31
18
|
CodebookDescriptor,
|
@@ -38,10 +25,6 @@ from edsl.utilities.decorators import (
|
|
38
25
|
remove_edsl_version,
|
39
26
|
)
|
40
27
|
from edsl.data_transfer_models import AgentResponseDict
|
41
|
-
from edsl.prompts.library.agent_persona import AgentPersona
|
42
|
-
from edsl.data.Cache import Cache
|
43
|
-
|
44
|
-
|
45
28
|
from edsl.utilities.restricted_python import create_restricted_function
|
46
29
|
|
47
30
|
|
@@ -56,6 +39,7 @@ class Agent(Base):
|
|
56
39
|
name = NameDescriptor()
|
57
40
|
dynamic_traits_function_name = ""
|
58
41
|
answer_question_directly_function_name = ""
|
42
|
+
has_dynamic_traits_function = False
|
59
43
|
|
60
44
|
def __init__(
|
61
45
|
self,
|
@@ -129,12 +113,16 @@ class Agent(Base):
|
|
129
113
|
|
130
114
|
if self.dynamic_traits_function:
|
131
115
|
self.dynamic_traits_function_name = self.dynamic_traits_function.__name__
|
116
|
+
self.has_dynamic_traits_function = True
|
117
|
+
else:
|
118
|
+
self.has_dynamic_traits_function = False
|
132
119
|
|
133
120
|
if dynamic_traits_function_source_code:
|
134
121
|
self.dynamic_traits_function_name = dynamic_traits_function_name
|
135
122
|
self.dynamic_traits_function = create_restricted_function(
|
136
123
|
dynamic_traits_function_name, dynamic_traits_function
|
137
124
|
)
|
125
|
+
|
138
126
|
if answer_question_directly_source_code:
|
139
127
|
self.answer_question_directly_function_name = (
|
140
128
|
answer_question_directly_function_name
|
@@ -151,6 +139,8 @@ class Agent(Base):
|
|
151
139
|
self.current_question = None
|
152
140
|
|
153
141
|
if traits_presentation_template is not None:
|
142
|
+
from edsl.prompts.library.agent_persona import AgentPersona
|
143
|
+
|
154
144
|
self.traits_presentation_template = traits_presentation_template
|
155
145
|
self.agent_persona = AgentPersona(text=self.traits_presentation_template)
|
156
146
|
|
@@ -159,7 +149,7 @@ class Agent(Base):
|
|
159
149
|
|
160
150
|
This checks whether the dynamic traits function is valid.
|
161
151
|
"""
|
162
|
-
if self.
|
152
|
+
if self.has_dynamic_traits_function:
|
163
153
|
sig = inspect.signature(self.dynamic_traits_function)
|
164
154
|
if "question" in sig.parameters:
|
165
155
|
if len(sig.parameters) > 1:
|
@@ -189,7 +179,7 @@ class Agent(Base):
|
|
189
179
|
{'age': 10, 'hair': 'brown', 'height': 5.5}
|
190
180
|
|
191
181
|
"""
|
192
|
-
if self.
|
182
|
+
if self.has_dynamic_traits_function:
|
193
183
|
sig = inspect.signature(self.dynamic_traits_function)
|
194
184
|
if "question" in sig.parameters:
|
195
185
|
return self.dynamic_traits_function(question=self.current_question)
|
@@ -271,8 +261,9 @@ class Agent(Base):
|
|
271
261
|
def create_invigilator(
|
272
262
|
self,
|
273
263
|
*,
|
274
|
-
question: QuestionBase,
|
275
|
-
cache,
|
264
|
+
question: "QuestionBase",
|
265
|
+
cache: "Cache",
|
266
|
+
survey: Optional["Survey"] = None,
|
276
267
|
scenario: Optional[Scenario] = None,
|
277
268
|
model: Optional[LanguageModel] = None,
|
278
269
|
debug: bool = False,
|
@@ -280,7 +271,7 @@ class Agent(Base):
|
|
280
271
|
current_answers: Optional[dict] = None,
|
281
272
|
iteration: int = 1,
|
282
273
|
sidecar_model=None,
|
283
|
-
) -> InvigilatorBase:
|
274
|
+
) -> "InvigilatorBase":
|
284
275
|
"""Create an Invigilator.
|
285
276
|
|
286
277
|
An invigilator is an object that is responsible for administering a question to an agent.
|
@@ -294,6 +285,8 @@ class Agent(Base):
|
|
294
285
|
An invigator is an object that is responsible for administering a question to an agent and
|
295
286
|
recording the responses.
|
296
287
|
"""
|
288
|
+
from edsl import Model, Scenario
|
289
|
+
|
297
290
|
cache = cache
|
298
291
|
self.current_question = question
|
299
292
|
model = model or Model()
|
@@ -301,6 +294,7 @@ class Agent(Base):
|
|
301
294
|
invigilator = self._create_invigilator(
|
302
295
|
question=question,
|
303
296
|
scenario=scenario,
|
297
|
+
survey=survey,
|
304
298
|
model=model,
|
305
299
|
debug=debug,
|
306
300
|
memory_plan=memory_plan,
|
@@ -314,12 +308,13 @@ class Agent(Base):
|
|
314
308
|
async def async_answer_question(
|
315
309
|
self,
|
316
310
|
*,
|
317
|
-
question: QuestionBase,
|
318
|
-
cache: Cache,
|
319
|
-
scenario: Optional[Scenario] = None,
|
320
|
-
|
311
|
+
question: "QuestionBase",
|
312
|
+
cache: "Cache",
|
313
|
+
scenario: Optional["Scenario"] = None,
|
314
|
+
survey: Optional["Survey"] = None,
|
315
|
+
model: Optional["LanguageModel"] = None,
|
321
316
|
debug: bool = False,
|
322
|
-
memory_plan: Optional[MemoryPlan] = None,
|
317
|
+
memory_plan: Optional["MemoryPlan"] = None,
|
323
318
|
current_answers: Optional[dict] = None,
|
324
319
|
iteration: int = 0,
|
325
320
|
) -> AgentResponseDict:
|
@@ -349,6 +344,7 @@ class Agent(Base):
|
|
349
344
|
question=question,
|
350
345
|
cache=cache,
|
351
346
|
scenario=scenario,
|
347
|
+
survey=survey,
|
352
348
|
model=model,
|
353
349
|
debug=debug,
|
354
350
|
memory_plan=memory_plan,
|
@@ -362,21 +358,35 @@ class Agent(Base):
|
|
362
358
|
|
363
359
|
def _create_invigilator(
|
364
360
|
self,
|
365
|
-
question: QuestionBase,
|
366
|
-
cache: Optional[Cache] = None,
|
367
|
-
scenario: Optional[Scenario] = None,
|
368
|
-
model: Optional[LanguageModel] = None,
|
361
|
+
question: "QuestionBase",
|
362
|
+
cache: Optional["Cache"] = None,
|
363
|
+
scenario: Optional["Scenario"] = None,
|
364
|
+
model: Optional["LanguageModel"] = None,
|
365
|
+
survey: Optional["Survey"] = None,
|
369
366
|
debug: bool = False,
|
370
|
-
memory_plan: Optional[MemoryPlan] = None,
|
367
|
+
memory_plan: Optional["MemoryPlan"] = None,
|
371
368
|
current_answers: Optional[dict] = None,
|
372
369
|
iteration: int = 0,
|
373
370
|
sidecar_model=None,
|
374
|
-
) -> InvigilatorBase:
|
371
|
+
) -> "InvigilatorBase":
|
375
372
|
"""Create an Invigilator."""
|
373
|
+
from edsl import Model
|
374
|
+
from edsl import Scenario
|
375
|
+
|
376
376
|
model = model or Model()
|
377
377
|
scenario = scenario or Scenario()
|
378
378
|
|
379
|
+
from edsl.agents.Invigilator import (
|
380
|
+
InvigilatorDebug,
|
381
|
+
InvigilatorHuman,
|
382
|
+
InvigilatorFunctional,
|
383
|
+
InvigilatorAI,
|
384
|
+
InvigilatorBase,
|
385
|
+
)
|
386
|
+
|
379
387
|
if cache is None:
|
388
|
+
from edsl.data.Cache import Cache
|
389
|
+
|
380
390
|
cache = Cache()
|
381
391
|
|
382
392
|
if debug:
|
@@ -404,6 +414,7 @@ class Agent(Base):
|
|
404
414
|
self,
|
405
415
|
question=question,
|
406
416
|
scenario=scenario,
|
417
|
+
survey=survey,
|
407
418
|
model=model,
|
408
419
|
memory_plan=memory_plan,
|
409
420
|
current_answers=current_answers,
|
@@ -479,6 +490,29 @@ class Agent(Base):
|
|
479
490
|
"""
|
480
491
|
return self.data == other.data
|
481
492
|
|
493
|
+
def __getattr__(self, name):
|
494
|
+
# This will be called only if 'name' is not found in the usual places
|
495
|
+
# breakpoint()
|
496
|
+
if name == "has_dynamic_traits_function":
|
497
|
+
return self.has_dynamic_traits_function
|
498
|
+
|
499
|
+
if name in self.traits:
|
500
|
+
return self.traits[name]
|
501
|
+
raise AttributeError(
|
502
|
+
f"'{type(self).__name__}' object has no attribute '{name}'"
|
503
|
+
)
|
504
|
+
|
505
|
+
def __getstate__(self):
|
506
|
+
state = self.__dict__.copy()
|
507
|
+
# Include any additional state that needs to be serialized
|
508
|
+
return state
|
509
|
+
|
510
|
+
def __setstate__(self, state):
|
511
|
+
self.__dict__.update(state)
|
512
|
+
# Ensure _traits is initialized if it's missing
|
513
|
+
if "_traits" not in self.__dict__:
|
514
|
+
self._traits = {}
|
515
|
+
|
482
516
|
def print(self) -> None:
|
483
517
|
from rich import print_json
|
484
518
|
import json
|
@@ -535,9 +569,9 @@ class Agent(Base):
|
|
535
569
|
if dynamic_traits_func:
|
536
570
|
func = inspect.getsource(dynamic_traits_func)
|
537
571
|
raw_data["dynamic_traits_function_source_code"] = func
|
538
|
-
raw_data[
|
539
|
-
|
540
|
-
|
572
|
+
raw_data["dynamic_traits_function_name"] = (
|
573
|
+
self.dynamic_traits_function_name
|
574
|
+
)
|
541
575
|
if hasattr(self, "answer_question_directly"):
|
542
576
|
raw_data.pop(
|
543
577
|
"answer_question_directly", None
|
@@ -553,9 +587,9 @@ class Agent(Base):
|
|
553
587
|
raw_data["answer_question_directly_source_code"] = inspect.getsource(
|
554
588
|
answer_question_directly_func
|
555
589
|
)
|
556
|
-
raw_data[
|
557
|
-
|
558
|
-
|
590
|
+
raw_data["answer_question_directly_function_name"] = (
|
591
|
+
self.answer_question_directly_function_name
|
592
|
+
)
|
559
593
|
|
560
594
|
return raw_data
|
561
595
|
|
@@ -640,6 +674,8 @@ class Agent(Base):
|
|
640
674
|
>>> a.rich_print()
|
641
675
|
<rich.table.Table object at ...>
|
642
676
|
"""
|
677
|
+
from rich.table import Table
|
678
|
+
|
643
679
|
table_data, column_names = self._table()
|
644
680
|
table = Table(title=f"{self.__class__.__name__} Attributes")
|
645
681
|
for column in column_names:
|
edsl/agents/AgentList.py
CHANGED
@@ -12,7 +12,7 @@ Example usage:
|
|
12
12
|
|
13
13
|
from __future__ import annotations
|
14
14
|
from collections import UserList
|
15
|
-
from typing import Optional, Union, Sequence
|
15
|
+
from typing import Optional, Union, Sequence, List, Any
|
16
16
|
from rich import print_json
|
17
17
|
from rich.table import Table
|
18
18
|
import json
|
@@ -22,7 +22,8 @@ import csv
|
|
22
22
|
from simpleeval import EvalWithCompoundTypes
|
23
23
|
|
24
24
|
from edsl.Base import Base
|
25
|
-
|
25
|
+
|
26
|
+
# from edsl.agents import Agent
|
26
27
|
from edsl.utilities.decorators import (
|
27
28
|
add_edsl_version,
|
28
29
|
remove_edsl_version,
|
@@ -32,7 +33,7 @@ from edsl.utilities.decorators import (
|
|
32
33
|
class AgentList(UserList, Base):
|
33
34
|
"""A list of Agents."""
|
34
35
|
|
35
|
-
def __init__(self, data: Optional[list[Agent]] = None):
|
36
|
+
def __init__(self, data: Optional[list["Agent"]] = None):
|
36
37
|
"""Initialize a new AgentList.
|
37
38
|
|
38
39
|
:param data: A list of Agents.
|
@@ -77,6 +78,7 @@ class AgentList(UserList, Base):
|
|
77
78
|
def select(self, *traits) -> AgentList:
|
78
79
|
"""Selects agents with only the references traits.
|
79
80
|
|
81
|
+
>>> from edsl.agents.Agent import Agent
|
80
82
|
>>> al = AgentList([Agent(traits = {'a': 1, 'b': 1}), Agent(traits = {'a': 1, 'b': 2})])
|
81
83
|
>>> al.select('a')
|
82
84
|
AgentList([Agent(traits = {'a': 1}), Agent(traits = {'a': 1})])
|
@@ -94,12 +96,13 @@ class AgentList(UserList, Base):
|
|
94
96
|
"""
|
95
97
|
Filter a list of agents based on an expression.
|
96
98
|
|
99
|
+
>>> from edsl.agents.Agent import Agent
|
97
100
|
>>> al = AgentList([Agent(traits = {'a': 1, 'b': 1}), Agent(traits = {'a': 1, 'b': 2})])
|
98
101
|
>>> al.filter("b == 2")
|
99
102
|
AgentList([Agent(traits = {'a': 1, 'b': 2})])
|
100
103
|
"""
|
101
104
|
|
102
|
-
def create_evaluator(agent: Agent):
|
105
|
+
def create_evaluator(agent: "Agent"):
|
103
106
|
"""Create an evaluator for the given result.
|
104
107
|
The 'combined_dict' is a mapping of all values for that Result object.
|
105
108
|
"""
|
@@ -133,6 +136,8 @@ class AgentList(UserList, Base):
|
|
133
136
|
|
134
137
|
:param file_path: The path to the CSV file.
|
135
138
|
"""
|
139
|
+
from edsl.agents.Agent import Agent
|
140
|
+
|
136
141
|
agent_list = []
|
137
142
|
with open(file_path, "r") as f:
|
138
143
|
reader = csv.DictReader(f)
|
@@ -153,7 +158,7 @@ class AgentList(UserList, Base):
|
|
153
158
|
"""Remove traits from the AgentList.
|
154
159
|
|
155
160
|
:param traits: The traits to remove.
|
156
|
-
|
161
|
+
>>> from edsl.agents.Agent import Agent
|
157
162
|
>>> al = AgentList([Agent({'age': 22, 'hair': 'brown', 'height': 5.5}), Agent({'age': 22, 'hair': 'brown', 'height': 5.5})])
|
158
163
|
>>> al.remove_trait('age')
|
159
164
|
AgentList([Agent(traits = {'hair': 'brown', 'height': 5.5}), Agent(traits = {'hair': 'brown', 'height': 5.5})])
|
@@ -222,12 +227,14 @@ class AgentList(UserList, Base):
|
|
222
227
|
"""Deserialize the dictionary back to an AgentList object.
|
223
228
|
|
224
229
|
:param: data: A dictionary representing an AgentList.
|
225
|
-
|
230
|
+
>>> from edsl.agents.Agent import Agent
|
226
231
|
>>> al = AgentList([Agent.example(), Agent.example()])
|
227
232
|
>>> al2 = AgentList.from_dict(al.to_dict())
|
228
233
|
>>> al2 == al
|
229
234
|
True
|
230
235
|
"""
|
236
|
+
from edsl.agents.Agent import Agent
|
237
|
+
|
231
238
|
agents = [Agent.from_dict(agent_dict) for agent_dict in data["agent_list"]]
|
232
239
|
return cls(agents)
|
233
240
|
|
@@ -240,8 +247,30 @@ class AgentList(UserList, Base):
|
|
240
247
|
2
|
241
248
|
|
242
249
|
"""
|
250
|
+
from edsl.agents.Agent import Agent
|
251
|
+
|
243
252
|
return cls([Agent.example(), Agent.example()])
|
244
253
|
|
254
|
+
@classmethod
|
255
|
+
def from_list(self, trait_name: str, values: List[Any]):
|
256
|
+
"""Create an AgentList from a list of values.
|
257
|
+
|
258
|
+
:param trait_name: The name of the trait.
|
259
|
+
:param values: A list of values.
|
260
|
+
"""
|
261
|
+
from edsl.agents.Agent import Agent
|
262
|
+
|
263
|
+
return AgentList([Agent({trait_name: value}) for value in values])
|
264
|
+
|
265
|
+
def __mul__(self, other: AgentList) -> AgentList:
|
266
|
+
"""Takes the cross product of two AgentLists."""
|
267
|
+
from itertools import product
|
268
|
+
|
269
|
+
new_sl = []
|
270
|
+
for s1, s2 in list(product(self, other)):
|
271
|
+
new_sl.append(s1 + s2)
|
272
|
+
return AgentList(new_sl)
|
273
|
+
|
245
274
|
def code(self, string=True) -> Union[str, list[str]]:
|
246
275
|
"""Return code to construct an AgentList.
|
247
276
|
|
edsl/agents/Invigilator.py
CHANGED
@@ -82,7 +82,25 @@ class InvigilatorAI(PromptConstructorMixin, InvigilatorBase):
|
|
82
82
|
self._remove_from_cache(raw_response)
|
83
83
|
raise e
|
84
84
|
|
85
|
-
|
85
|
+
# breakpoint()
|
86
|
+
question_dict = self.survey.question_names_to_questions()
|
87
|
+
for other_question, answer in self.current_answers.items():
|
88
|
+
if other_question in question_dict:
|
89
|
+
question_dict[other_question].answer = answer
|
90
|
+
else:
|
91
|
+
# adds a comment to the question
|
92
|
+
if (
|
93
|
+
new_question := other_question.split("_comment")[0]
|
94
|
+
) in question_dict:
|
95
|
+
question_dict[new_question].comment = answer
|
96
|
+
|
97
|
+
combined_dict = {**question_dict, **scenario}
|
98
|
+
# print("combined_dict: ", combined_dict)
|
99
|
+
# print("response: ", response)
|
100
|
+
# breakpoint()
|
101
|
+
answer = question._translate_answer_code_to_answer(
|
102
|
+
response["answer"], combined_dict
|
103
|
+
)
|
86
104
|
data = {
|
87
105
|
"answer": answer,
|
88
106
|
"comment": response.get(
|
edsl/agents/InvigilatorBase.py
CHANGED
@@ -46,6 +46,7 @@ class InvigilatorBase(ABC):
|
|
46
46
|
model: LanguageModel,
|
47
47
|
memory_plan: MemoryPlan,
|
48
48
|
current_answers: dict,
|
49
|
+
survey: Optional["Survey"],
|
49
50
|
cache: Optional[Cache] = None,
|
50
51
|
iteration: Optional[int] = 1,
|
51
52
|
additional_prompt_data: Optional[dict] = None,
|
@@ -57,11 +58,12 @@ class InvigilatorBase(ABC):
|
|
57
58
|
self.scenario = scenario
|
58
59
|
self.model = model
|
59
60
|
self.memory_plan = memory_plan
|
60
|
-
self.current_answers = current_answers
|
61
|
+
self.current_answers = current_answers or {}
|
61
62
|
self.iteration = iteration
|
62
63
|
self.additional_prompt_data = additional_prompt_data
|
63
64
|
self.cache = cache
|
64
65
|
self.sidecar_model = sidecar_model
|
66
|
+
self.survey = survey
|
65
67
|
|
66
68
|
def __repr__(self) -> str:
|
67
69
|
"""Return a string representation of the Invigilator.
|
@@ -76,7 +78,7 @@ class InvigilatorBase(ABC):
|
|
76
78
|
"""Return an AgentResponseDict used in case the question-asking fails.
|
77
79
|
|
78
80
|
>>> InvigilatorBase.example().get_failed_task_result()
|
79
|
-
{'answer': None, 'comment': 'Failed to get response',
|
81
|
+
{'answer': None, 'comment': 'Failed to get response', ...}
|
80
82
|
"""
|
81
83
|
return AgentResponseDict(
|
82
84
|
answer=None,
|
@@ -86,11 +88,8 @@ class InvigilatorBase(ABC):
|
|
86
88
|
)
|
87
89
|
|
88
90
|
def get_prompts(self) -> Dict[str, Prompt]:
|
89
|
-
"""Return the prompt used.
|
91
|
+
"""Return the prompt used."""
|
90
92
|
|
91
|
-
>>> InvigilatorBase.example().get_prompts()
|
92
|
-
{'user_prompt': Prompt(text=\"""NA\"""), 'system_prompt': Prompt(text=\"""NA\""")}
|
93
|
-
"""
|
94
93
|
return {
|
95
94
|
"user_prompt": Prompt("NA"),
|
96
95
|
"system_prompt": Prompt("NA"),
|
@@ -129,7 +128,7 @@ class InvigilatorBase(ABC):
|
|
129
128
|
)
|
130
129
|
|
131
130
|
@classmethod
|
132
|
-
def example(cls, throw_an_exception=False):
|
131
|
+
def example(cls, throw_an_exception=False, question=None, scenario=None):
|
133
132
|
"""Return an example invigilator.
|
134
133
|
|
135
134
|
>>> InvigilatorBase.example()
|
@@ -167,15 +166,20 @@ class InvigilatorBase(ABC):
|
|
167
166
|
if throw_an_exception:
|
168
167
|
model.throw_an_exception = True
|
169
168
|
agent = Agent.example()
|
170
|
-
question = QuestionMultipleChoice.example()
|
171
|
-
|
169
|
+
# question = QuestionMultipleChoice.example()
|
170
|
+
from edsl.surveys import Survey
|
171
|
+
|
172
|
+
survey = Survey.example()
|
173
|
+
question = question or survey.questions[0]
|
174
|
+
scenario = scenario or Scenario.example()
|
172
175
|
# memory_plan = None #memory_plan = MemoryPlan()
|
173
176
|
from edsl import Survey
|
174
177
|
|
175
178
|
memory_plan = MemoryPlan(survey=Survey.example())
|
176
179
|
current_answers = None
|
180
|
+
from edsl.agents.PromptConstructionMixin import PromptConstructorMixin
|
177
181
|
|
178
|
-
class InvigilatorExample(InvigilatorBase):
|
182
|
+
class InvigilatorExample(PromptConstructorMixin, InvigilatorBase):
|
179
183
|
"""An example invigilator."""
|
180
184
|
|
181
185
|
async def async_answer_question(self):
|
@@ -188,6 +192,7 @@ class InvigilatorBase(ABC):
|
|
188
192
|
agent=agent,
|
189
193
|
question=question,
|
190
194
|
scenario=scenario,
|
195
|
+
survey=survey,
|
191
196
|
model=model,
|
192
197
|
memory_plan=memory_plan,
|
193
198
|
current_answers=current_answers,
|