edsl 0.1.29.dev3__py3-none-any.whl → 0.1.30__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 +23 -23
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +79 -41
- edsl/agents/AgentList.py +26 -26
- edsl/agents/Invigilator.py +19 -2
- 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/conversation/car_buying.py +1 -1
- edsl/coop/coop.py +187 -150
- edsl/coop/utils.py +43 -75
- edsl/data/Cache.py +41 -18
- edsl/data/CacheEntry.py +6 -7
- edsl/data/SQLiteDict.py +11 -3
- edsl/data_transfer_models.py +4 -0
- edsl/jobs/Answers.py +15 -1
- edsl/jobs/Jobs.py +108 -49
- edsl/jobs/buckets/ModelBuckets.py +14 -2
- edsl/jobs/buckets/TokenBucket.py +32 -5
- edsl/jobs/interviews/Interview.py +99 -79
- edsl/jobs/interviews/InterviewTaskBuildingMixin.py +19 -24
- edsl/jobs/runners/JobsRunnerAsyncio.py +16 -16
- edsl/jobs/tasks/QuestionTaskCreator.py +10 -6
- edsl/jobs/tasks/TaskHistory.py +4 -3
- edsl/language_models/LanguageModel.py +17 -17
- edsl/language_models/ModelList.py +1 -1
- edsl/language_models/repair.py +8 -7
- edsl/notebooks/Notebook.py +47 -10
- 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 +7 -5
- edsl/questions/QuestionFunctional.py +34 -5
- edsl/questions/QuestionList.py +3 -4
- edsl/questions/QuestionMultipleChoice.py +68 -12
- edsl/questions/QuestionNumerical.py +4 -3
- edsl/questions/QuestionRank.py +5 -3
- edsl/questions/__init__.py +4 -3
- edsl/questions/descriptors.py +46 -4
- edsl/questions/question_registry.py +20 -31
- edsl/questions/settings.py +1 -1
- edsl/results/Dataset.py +31 -0
- edsl/results/DatasetExportMixin.py +570 -0
- edsl/results/Result.py +66 -70
- edsl/results/Results.py +160 -68
- 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 +299 -0
- edsl/scenarios/Scenario.py +16 -24
- edsl/scenarios/ScenarioList.py +42 -17
- edsl/scenarios/ScenarioListExportMixin.py +32 -0
- edsl/scenarios/ScenarioListPdfMixin.py +2 -1
- edsl/scenarios/__init__.py +1 -0
- edsl/study/Study.py +8 -16
- edsl/surveys/MemoryPlan.py +11 -4
- edsl/surveys/Survey.py +88 -17
- 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.29.dev3.dist-info → edsl-0.1.30.dist-info}/METADATA +11 -10
- {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/RECORD +74 -71
- {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/WHEEL +1 -1
- edsl-0.1.29.dev3.dist-info/entry_points.txt +0 -3
- {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/LICENSE +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
41
|
from edsl.conjure.Conjure import Conjure
|
41
|
-
from edsl.language_models.ModelList import ModelList
|
42
42
|
from edsl.coop.coop import Coop
|
edsl/__version__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.30"
|
edsl/agents/Agent.py
CHANGED
@@ -4,28 +4,16 @@ from __future__ import annotations
|
|
4
4
|
import copy
|
5
5
|
import inspect
|
6
6
|
import types
|
7
|
-
from typing import
|
8
|
-
|
9
|
-
from rich.table import Table
|
10
|
-
|
7
|
+
from typing import Callable, Optional, Union
|
8
|
+
from uuid import uuid4
|
11
9
|
from edsl.Base import Base
|
12
|
-
|
13
|
-
from edsl.language_models import LanguageModel
|
14
|
-
from edsl.surveys.MemoryPlan import MemoryPlan
|
10
|
+
|
15
11
|
from edsl.exceptions.agents import (
|
16
12
|
AgentCombinationError,
|
17
13
|
AgentDirectAnswerFunctionError,
|
18
14
|
AgentDynamicTraitsFunctionError,
|
19
15
|
)
|
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
|
16
|
+
|
29
17
|
from edsl.agents.descriptors import (
|
30
18
|
TraitsDescriptor,
|
31
19
|
CodebookDescriptor,
|
@@ -38,10 +26,6 @@ from edsl.utilities.decorators import (
|
|
38
26
|
remove_edsl_version,
|
39
27
|
)
|
40
28
|
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
29
|
from edsl.utilities.restricted_python import create_restricted_function
|
46
30
|
|
47
31
|
|
@@ -56,6 +40,7 @@ class Agent(Base):
|
|
56
40
|
name = NameDescriptor()
|
57
41
|
dynamic_traits_function_name = ""
|
58
42
|
answer_question_directly_function_name = ""
|
43
|
+
has_dynamic_traits_function = False
|
59
44
|
|
60
45
|
def __init__(
|
61
46
|
self,
|
@@ -129,12 +114,16 @@ class Agent(Base):
|
|
129
114
|
|
130
115
|
if self.dynamic_traits_function:
|
131
116
|
self.dynamic_traits_function_name = self.dynamic_traits_function.__name__
|
117
|
+
self.has_dynamic_traits_function = True
|
118
|
+
else:
|
119
|
+
self.has_dynamic_traits_function = False
|
132
120
|
|
133
121
|
if dynamic_traits_function_source_code:
|
134
122
|
self.dynamic_traits_function_name = dynamic_traits_function_name
|
135
123
|
self.dynamic_traits_function = create_restricted_function(
|
136
124
|
dynamic_traits_function_name, dynamic_traits_function
|
137
125
|
)
|
126
|
+
|
138
127
|
if answer_question_directly_source_code:
|
139
128
|
self.answer_question_directly_function_name = (
|
140
129
|
answer_question_directly_function_name
|
@@ -151,6 +140,8 @@ class Agent(Base):
|
|
151
140
|
self.current_question = None
|
152
141
|
|
153
142
|
if traits_presentation_template is not None:
|
143
|
+
from edsl.prompts.library.agent_persona import AgentPersona
|
144
|
+
|
154
145
|
self.traits_presentation_template = traits_presentation_template
|
155
146
|
self.agent_persona = AgentPersona(text=self.traits_presentation_template)
|
156
147
|
|
@@ -159,7 +150,7 @@ class Agent(Base):
|
|
159
150
|
|
160
151
|
This checks whether the dynamic traits function is valid.
|
161
152
|
"""
|
162
|
-
if self.
|
153
|
+
if self.has_dynamic_traits_function:
|
163
154
|
sig = inspect.signature(self.dynamic_traits_function)
|
164
155
|
if "question" in sig.parameters:
|
165
156
|
if len(sig.parameters) > 1:
|
@@ -189,7 +180,7 @@ class Agent(Base):
|
|
189
180
|
{'age': 10, 'hair': 'brown', 'height': 5.5}
|
190
181
|
|
191
182
|
"""
|
192
|
-
if self.
|
183
|
+
if self.has_dynamic_traits_function:
|
193
184
|
sig = inspect.signature(self.dynamic_traits_function)
|
194
185
|
if "question" in sig.parameters:
|
195
186
|
return self.dynamic_traits_function(question=self.current_question)
|
@@ -271,8 +262,9 @@ class Agent(Base):
|
|
271
262
|
def create_invigilator(
|
272
263
|
self,
|
273
264
|
*,
|
274
|
-
question: QuestionBase,
|
275
|
-
cache,
|
265
|
+
question: "QuestionBase",
|
266
|
+
cache: "Cache",
|
267
|
+
survey: Optional["Survey"] = None,
|
276
268
|
scenario: Optional[Scenario] = None,
|
277
269
|
model: Optional[LanguageModel] = None,
|
278
270
|
debug: bool = False,
|
@@ -280,7 +272,7 @@ class Agent(Base):
|
|
280
272
|
current_answers: Optional[dict] = None,
|
281
273
|
iteration: int = 1,
|
282
274
|
sidecar_model=None,
|
283
|
-
) -> InvigilatorBase:
|
275
|
+
) -> "InvigilatorBase":
|
284
276
|
"""Create an Invigilator.
|
285
277
|
|
286
278
|
An invigilator is an object that is responsible for administering a question to an agent.
|
@@ -294,6 +286,8 @@ class Agent(Base):
|
|
294
286
|
An invigator is an object that is responsible for administering a question to an agent and
|
295
287
|
recording the responses.
|
296
288
|
"""
|
289
|
+
from edsl import Model, Scenario
|
290
|
+
|
297
291
|
cache = cache
|
298
292
|
self.current_question = question
|
299
293
|
model = model or Model()
|
@@ -301,6 +295,7 @@ class Agent(Base):
|
|
301
295
|
invigilator = self._create_invigilator(
|
302
296
|
question=question,
|
303
297
|
scenario=scenario,
|
298
|
+
survey=survey,
|
304
299
|
model=model,
|
305
300
|
debug=debug,
|
306
301
|
memory_plan=memory_plan,
|
@@ -314,12 +309,13 @@ class Agent(Base):
|
|
314
309
|
async def async_answer_question(
|
315
310
|
self,
|
316
311
|
*,
|
317
|
-
question: QuestionBase,
|
318
|
-
cache: Cache,
|
319
|
-
scenario: Optional[Scenario] = None,
|
320
|
-
|
312
|
+
question: "QuestionBase",
|
313
|
+
cache: "Cache",
|
314
|
+
scenario: Optional["Scenario"] = None,
|
315
|
+
survey: Optional["Survey"] = None,
|
316
|
+
model: Optional["LanguageModel"] = None,
|
321
317
|
debug: bool = False,
|
322
|
-
memory_plan: Optional[MemoryPlan] = None,
|
318
|
+
memory_plan: Optional["MemoryPlan"] = None,
|
323
319
|
current_answers: Optional[dict] = None,
|
324
320
|
iteration: int = 0,
|
325
321
|
) -> AgentResponseDict:
|
@@ -349,6 +345,7 @@ class Agent(Base):
|
|
349
345
|
question=question,
|
350
346
|
cache=cache,
|
351
347
|
scenario=scenario,
|
348
|
+
survey=survey,
|
352
349
|
model=model,
|
353
350
|
debug=debug,
|
354
351
|
memory_plan=memory_plan,
|
@@ -362,21 +359,35 @@ class Agent(Base):
|
|
362
359
|
|
363
360
|
def _create_invigilator(
|
364
361
|
self,
|
365
|
-
question: QuestionBase,
|
366
|
-
cache: Optional[Cache] = None,
|
367
|
-
scenario: Optional[Scenario] = None,
|
368
|
-
model: Optional[LanguageModel] = None,
|
362
|
+
question: "QuestionBase",
|
363
|
+
cache: Optional["Cache"] = None,
|
364
|
+
scenario: Optional["Scenario"] = None,
|
365
|
+
model: Optional["LanguageModel"] = None,
|
366
|
+
survey: Optional["Survey"] = None,
|
369
367
|
debug: bool = False,
|
370
|
-
memory_plan: Optional[MemoryPlan] = None,
|
368
|
+
memory_plan: Optional["MemoryPlan"] = None,
|
371
369
|
current_answers: Optional[dict] = None,
|
372
370
|
iteration: int = 0,
|
373
371
|
sidecar_model=None,
|
374
|
-
) -> InvigilatorBase:
|
372
|
+
) -> "InvigilatorBase":
|
375
373
|
"""Create an Invigilator."""
|
374
|
+
from edsl import Model
|
375
|
+
from edsl import Scenario
|
376
|
+
|
376
377
|
model = model or Model()
|
377
378
|
scenario = scenario or Scenario()
|
378
379
|
|
380
|
+
from edsl.agents.Invigilator import (
|
381
|
+
InvigilatorDebug,
|
382
|
+
InvigilatorHuman,
|
383
|
+
InvigilatorFunctional,
|
384
|
+
InvigilatorAI,
|
385
|
+
InvigilatorBase,
|
386
|
+
)
|
387
|
+
|
379
388
|
if cache is None:
|
389
|
+
from edsl.data.Cache import Cache
|
390
|
+
|
380
391
|
cache = Cache()
|
381
392
|
|
382
393
|
if debug:
|
@@ -404,6 +415,7 @@ class Agent(Base):
|
|
404
415
|
self,
|
405
416
|
question=question,
|
406
417
|
scenario=scenario,
|
418
|
+
survey=survey,
|
407
419
|
model=model,
|
408
420
|
memory_plan=memory_plan,
|
409
421
|
current_answers=current_answers,
|
@@ -479,6 +491,29 @@ class Agent(Base):
|
|
479
491
|
"""
|
480
492
|
return self.data == other.data
|
481
493
|
|
494
|
+
def __getattr__(self, name):
|
495
|
+
# This will be called only if 'name' is not found in the usual places
|
496
|
+
# breakpoint()
|
497
|
+
if name == "has_dynamic_traits_function":
|
498
|
+
return self.has_dynamic_traits_function
|
499
|
+
|
500
|
+
if name in self.traits:
|
501
|
+
return self.traits[name]
|
502
|
+
raise AttributeError(
|
503
|
+
f"'{type(self).__name__}' object has no attribute '{name}'"
|
504
|
+
)
|
505
|
+
|
506
|
+
def __getstate__(self):
|
507
|
+
state = self.__dict__.copy()
|
508
|
+
# Include any additional state that needs to be serialized
|
509
|
+
return state
|
510
|
+
|
511
|
+
def __setstate__(self, state):
|
512
|
+
self.__dict__.update(state)
|
513
|
+
# Ensure _traits is initialized if it's missing
|
514
|
+
if "_traits" not in self.__dict__:
|
515
|
+
self._traits = {}
|
516
|
+
|
482
517
|
def print(self) -> None:
|
483
518
|
from rich import print_json
|
484
519
|
import json
|
@@ -640,6 +675,8 @@ class Agent(Base):
|
|
640
675
|
>>> a.rich_print()
|
641
676
|
<rich.table.Table object at ...>
|
642
677
|
"""
|
678
|
+
from rich.table import Table
|
679
|
+
|
643
680
|
table_data, column_names = self._table()
|
644
681
|
table = Table(title=f"{self.__class__.__name__} Attributes")
|
645
682
|
for column in column_names:
|
@@ -652,13 +689,14 @@ class Agent(Base):
|
|
652
689
|
return table
|
653
690
|
|
654
691
|
@classmethod
|
655
|
-
def example(cls) -> Agent:
|
656
|
-
"""
|
692
|
+
def example(cls, randomize: bool = False) -> Agent:
|
693
|
+
"""
|
694
|
+
Returns an example Agent instance.
|
657
695
|
|
658
|
-
|
659
|
-
Agent(traits = {'age': 22, 'hair': 'brown', 'height': 5.5})
|
696
|
+
:param randomize: If True, adds a random string to the value of an example key.
|
660
697
|
"""
|
661
|
-
|
698
|
+
addition = "" if not randomize else str(uuid4())
|
699
|
+
return cls(traits={"age": 22, "hair": f"brown{addition}", "height": 5.5})
|
662
700
|
|
663
701
|
def code(self) -> str:
|
664
702
|
"""Return the code for the agent.
|
edsl/agents/AgentList.py
CHANGED
@@ -11,28 +11,21 @@ Example usage:
|
|
11
11
|
"""
|
12
12
|
|
13
13
|
from __future__ import annotations
|
14
|
+
import csv
|
15
|
+
import json
|
14
16
|
from collections import UserList
|
15
|
-
from typing import
|
17
|
+
from typing import Any, List, Optional, Union
|
16
18
|
from rich import print_json
|
17
19
|
from rich.table import Table
|
18
|
-
import json
|
19
|
-
import csv
|
20
|
-
|
21
|
-
|
22
20
|
from simpleeval import EvalWithCompoundTypes
|
23
|
-
|
24
21
|
from edsl.Base import Base
|
25
|
-
from edsl.
|
26
|
-
from edsl.utilities.decorators import (
|
27
|
-
add_edsl_version,
|
28
|
-
remove_edsl_version,
|
29
|
-
)
|
22
|
+
from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
|
30
23
|
|
31
24
|
|
32
25
|
class AgentList(UserList, Base):
|
33
26
|
"""A list of Agents."""
|
34
27
|
|
35
|
-
def __init__(self, data: Optional[list[Agent]] = None):
|
28
|
+
def __init__(self, data: Optional[list["Agent"]] = None):
|
36
29
|
"""Initialize a new AgentList.
|
37
30
|
|
38
31
|
:param data: A list of Agents.
|
@@ -77,6 +70,7 @@ class AgentList(UserList, Base):
|
|
77
70
|
def select(self, *traits) -> AgentList:
|
78
71
|
"""Selects agents with only the references traits.
|
79
72
|
|
73
|
+
>>> from edsl.agents.Agent import Agent
|
80
74
|
>>> al = AgentList([Agent(traits = {'a': 1, 'b': 1}), Agent(traits = {'a': 1, 'b': 2})])
|
81
75
|
>>> al.select('a')
|
82
76
|
AgentList([Agent(traits = {'a': 1}), Agent(traits = {'a': 1})])
|
@@ -94,12 +88,13 @@ class AgentList(UserList, Base):
|
|
94
88
|
"""
|
95
89
|
Filter a list of agents based on an expression.
|
96
90
|
|
91
|
+
>>> from edsl.agents.Agent import Agent
|
97
92
|
>>> al = AgentList([Agent(traits = {'a': 1, 'b': 1}), Agent(traits = {'a': 1, 'b': 2})])
|
98
93
|
>>> al.filter("b == 2")
|
99
94
|
AgentList([Agent(traits = {'a': 1, 'b': 2})])
|
100
95
|
"""
|
101
96
|
|
102
|
-
def create_evaluator(agent: Agent):
|
97
|
+
def create_evaluator(agent: "Agent"):
|
103
98
|
"""Create an evaluator for the given result.
|
104
99
|
The 'combined_dict' is a mapping of all values for that Result object.
|
105
100
|
"""
|
@@ -133,6 +128,8 @@ class AgentList(UserList, Base):
|
|
133
128
|
|
134
129
|
:param file_path: The path to the CSV file.
|
135
130
|
"""
|
131
|
+
from edsl.agents.Agent import Agent
|
132
|
+
|
136
133
|
agent_list = []
|
137
134
|
with open(file_path, "r") as f:
|
138
135
|
reader = csv.DictReader(f)
|
@@ -153,7 +150,7 @@ class AgentList(UserList, Base):
|
|
153
150
|
"""Remove traits from the AgentList.
|
154
151
|
|
155
152
|
:param traits: The traits to remove.
|
156
|
-
|
153
|
+
>>> from edsl.agents.Agent import Agent
|
157
154
|
>>> al = AgentList([Agent({'age': 22, 'hair': 'brown', 'height': 5.5}), Agent({'age': 22, 'hair': 'brown', 'height': 5.5})])
|
158
155
|
>>> al.remove_trait('age')
|
159
156
|
AgentList([Agent(traits = {'hair': 'brown', 'height': 5.5}), Agent(traits = {'hair': 'brown', 'height': 5.5})])
|
@@ -222,35 +219,39 @@ class AgentList(UserList, Base):
|
|
222
219
|
"""Deserialize the dictionary back to an AgentList object.
|
223
220
|
|
224
221
|
:param: data: A dictionary representing an AgentList.
|
225
|
-
|
222
|
+
>>> from edsl.agents.Agent import Agent
|
226
223
|
>>> al = AgentList([Agent.example(), Agent.example()])
|
227
224
|
>>> al2 = AgentList.from_dict(al.to_dict())
|
228
225
|
>>> al2 == al
|
229
226
|
True
|
230
227
|
"""
|
228
|
+
from edsl.agents.Agent import Agent
|
229
|
+
|
231
230
|
agents = [Agent.from_dict(agent_dict) for agent_dict in data["agent_list"]]
|
232
231
|
return cls(agents)
|
233
232
|
|
234
233
|
@classmethod
|
235
|
-
def example(cls) ->
|
236
|
-
"""
|
237
|
-
|
238
|
-
>>> al = AgentList.example()
|
239
|
-
>>> len(al)
|
240
|
-
2
|
234
|
+
def example(cls, randomize: bool = False) -> AgentList:
|
235
|
+
"""
|
236
|
+
Returns an example AgentList instance.
|
241
237
|
|
238
|
+
:param randomize: If True, uses Agent's randomize method.
|
242
239
|
"""
|
243
|
-
|
244
|
-
|
240
|
+
from edsl.agents.Agent import Agent
|
241
|
+
|
242
|
+
return cls([Agent.example(randomize), Agent.example(randomize)])
|
243
|
+
|
245
244
|
@classmethod
|
246
|
-
def from_list(self, trait_name:str, values: List[Any]):
|
245
|
+
def from_list(self, trait_name: str, values: List[Any]):
|
247
246
|
"""Create an AgentList from a list of values.
|
248
247
|
|
249
248
|
:param trait_name: The name of the trait.
|
250
249
|
:param values: A list of values.
|
251
250
|
"""
|
251
|
+
from edsl.agents.Agent import Agent
|
252
|
+
|
252
253
|
return AgentList([Agent({trait_name: value}) for value in values])
|
253
|
-
|
254
|
+
|
254
255
|
def __mul__(self, other: AgentList) -> AgentList:
|
255
256
|
"""Takes the cross product of two AgentLists."""
|
256
257
|
from itertools import product
|
@@ -260,7 +261,6 @@ class AgentList(UserList, Base):
|
|
260
261
|
new_sl.append(s1 + s2)
|
261
262
|
return AgentList(new_sl)
|
262
263
|
|
263
|
-
|
264
264
|
def code(self, string=True) -> Union[str, list[str]]:
|
265
265
|
"""Return code to construct an AgentList.
|
266
266
|
|
edsl/agents/Invigilator.py
CHANGED
@@ -74,15 +74,30 @@ class InvigilatorAI(PromptConstructorMixin, InvigilatorBase):
|
|
74
74
|
|
75
75
|
This cleans up the raw response to make it suitable to pass to AgentResponseDict.
|
76
76
|
"""
|
77
|
-
# not actually used, but this removes the temptation to delete agent from the signature
|
78
77
|
_ = agent
|
79
78
|
try:
|
80
79
|
response = question._validate_answer(raw_response)
|
81
80
|
except Exception as e:
|
81
|
+
"""If the response is invalid, remove it from the cache and raise the exception."""
|
82
82
|
self._remove_from_cache(raw_response)
|
83
83
|
raise e
|
84
84
|
|
85
|
-
|
85
|
+
question_dict = self.survey.question_names_to_questions()
|
86
|
+
for other_question, answer in self.current_answers.items():
|
87
|
+
if other_question in question_dict:
|
88
|
+
question_dict[other_question].answer = answer
|
89
|
+
else:
|
90
|
+
# adds a comment to the question
|
91
|
+
if (
|
92
|
+
new_question := other_question.split("_comment")[0]
|
93
|
+
) in question_dict:
|
94
|
+
question_dict[new_question].comment = answer
|
95
|
+
|
96
|
+
combined_dict = {**question_dict, **scenario}
|
97
|
+
answer = question._translate_answer_code_to_answer(
|
98
|
+
response["answer"], combined_dict
|
99
|
+
)
|
100
|
+
# breakpoint()
|
86
101
|
data = {
|
87
102
|
"answer": answer,
|
88
103
|
"comment": response.get(
|
@@ -93,6 +108,8 @@ class InvigilatorAI(PromptConstructorMixin, InvigilatorBase):
|
|
93
108
|
"cached_response": raw_response.get("cached_response", None),
|
94
109
|
"usage": raw_response.get("usage", {}),
|
95
110
|
"raw_model_response": raw_model_response,
|
111
|
+
"cache_used": raw_response.get("cache_used", False),
|
112
|
+
"cache_key": raw_response.get("cache_key", None),
|
96
113
|
}
|
97
114
|
return AgentResponseDict(**data)
|
98
115
|
|
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,
|