edsl 0.1.33.dev1__tar.gz → 0.1.33.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/PKG-INFO +4 -2
  2. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/README.md +1 -1
  3. edsl-0.1.33.dev2/edsl/TemplateLoader.py +24 -0
  4. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/__init__.py +8 -4
  5. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/agents/Agent.py +46 -14
  6. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/agents/AgentList.py +43 -0
  7. edsl-0.1.33.dev2/edsl/agents/Invigilator.py +199 -0
  8. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/agents/InvigilatorBase.py +140 -32
  9. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/agents/PromptConstructionMixin.py +43 -66
  10. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/agents/__init__.py +1 -0
  11. edsl-0.1.33.dev2/edsl/auto/AutoStudy.py +117 -0
  12. edsl-0.1.33.dev2/edsl/auto/StageBase.py +230 -0
  13. edsl-0.1.33.dev2/edsl/auto/StageGenerateSurvey.py +178 -0
  14. edsl-0.1.33.dev2/edsl/auto/StageLabelQuestions.py +125 -0
  15. edsl-0.1.33.dev2/edsl/auto/StagePersona.py +61 -0
  16. edsl-0.1.33.dev2/edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
  17. edsl-0.1.33.dev2/edsl/auto/StagePersonaDimensionValues.py +74 -0
  18. edsl-0.1.33.dev2/edsl/auto/StagePersonaDimensions.py +69 -0
  19. edsl-0.1.33.dev2/edsl/auto/StageQuestions.py +73 -0
  20. edsl-0.1.33.dev2/edsl/auto/SurveyCreatorPipeline.py +21 -0
  21. edsl-0.1.33.dev2/edsl/auto/utilities.py +224 -0
  22. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/config.py +38 -39
  23. edsl-0.1.33.dev2/edsl/coop/PriceFetcher.py +58 -0
  24. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/coop/coop.py +39 -5
  25. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/data/Cache.py +35 -1
  26. edsl-0.1.33.dev2/edsl/data_transfer_models.py +120 -0
  27. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/enums.py +2 -0
  28. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/language_models.py +25 -1
  29. edsl-0.1.33.dev2/edsl/exceptions/questions.py +91 -0
  30. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/results.py +4 -0
  31. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/AnthropicService.py +13 -11
  32. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/AwsBedrock.py +19 -17
  33. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/AzureAI.py +37 -20
  34. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/GoogleService.py +16 -12
  35. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/GroqService.py +2 -0
  36. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/InferenceServiceABC.py +24 -0
  37. edsl-0.1.33.dev2/edsl/inference_services/MistralAIService.py +120 -0
  38. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/OpenAIService.py +41 -50
  39. edsl-0.1.33.dev2/edsl/inference_services/TestService.py +71 -0
  40. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/models_available_cache.py +0 -6
  41. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/registry.py +4 -0
  42. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/Answers.py +10 -12
  43. edsl-0.1.33.dev2/edsl/jobs/FailedQuestion.py +78 -0
  44. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/Jobs.py +18 -13
  45. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/buckets/TokenBucket.py +39 -14
  46. edsl-0.1.33.dev2/edsl/jobs/interviews/Interview.py +525 -0
  47. edsl-0.1.33.dev2/edsl/jobs/interviews/InterviewExceptionEntry.py +165 -0
  48. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/interviews/interview_exception_tracking.py +0 -70
  49. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/interviews/retry_management.py +3 -1
  50. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/runners/JobsRunnerAsyncio.py +116 -70
  51. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/runners/JobsRunnerStatusMixin.py +1 -1
  52. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/tasks/QuestionTaskCreator.py +30 -23
  53. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/tasks/TaskHistory.py +131 -213
  54. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/language_models/LanguageModel.py +239 -129
  55. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/language_models/ModelList.py +2 -2
  56. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/language_models/RegisterLanguageModelsMeta.py +14 -29
  57. edsl-0.1.33.dev2/edsl/language_models/fake_openai_call.py +15 -0
  58. edsl-0.1.33.dev2/edsl/language_models/fake_openai_service.py +61 -0
  59. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/language_models/registry.py +15 -2
  60. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/language_models/repair.py +0 -19
  61. edsl-0.1.33.dev2/edsl/language_models/utilities.py +61 -0
  62. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/Prompt.py +52 -2
  63. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/AnswerValidatorMixin.py +23 -26
  64. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/QuestionBase.py +273 -242
  65. edsl-0.1.33.dev2/edsl/questions/QuestionBaseGenMixin.py +133 -0
  66. edsl-0.1.33.dev2/edsl/questions/QuestionBasePromptsMixin.py +266 -0
  67. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/QuestionBudget.py +6 -0
  68. edsl-0.1.33.dev2/edsl/questions/QuestionCheckBox.py +359 -0
  69. edsl-0.1.33.dev2/edsl/questions/QuestionExtract.py +183 -0
  70. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/QuestionFreeText.py +46 -29
  71. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/QuestionFunctional.py +7 -0
  72. edsl-0.1.33.dev2/edsl/questions/QuestionList.py +231 -0
  73. edsl-0.1.33.dev2/edsl/questions/QuestionMultipleChoice.py +297 -0
  74. edsl-0.1.33.dev2/edsl/questions/QuestionNumerical.py +152 -0
  75. edsl-0.1.33.dev2/edsl/questions/QuestionRank.py +324 -0
  76. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/RegisterQuestionsMeta.py +31 -12
  77. edsl-0.1.33.dev2/edsl/questions/ResponseValidatorABC.py +169 -0
  78. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/__init__.py +3 -4
  79. edsl-0.1.33.dev2/edsl/questions/decorators.py +21 -0
  80. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/derived/QuestionLikertFive.py +10 -5
  81. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/derived/QuestionLinearScale.py +11 -1
  82. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/derived/QuestionTopK.py +6 -0
  83. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/derived/QuestionYesNo.py +16 -1
  84. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/descriptors.py +43 -7
  85. edsl-0.1.33.dev2/edsl/questions/prompt_templates/question_budget.jinja +13 -0
  86. edsl-0.1.33.dev2/edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
  87. edsl-0.1.33.dev2/edsl/questions/prompt_templates/question_extract.jinja +11 -0
  88. edsl-0.1.33.dev2/edsl/questions/prompt_templates/question_free_text.jinja +3 -0
  89. edsl-0.1.33.dev2/edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
  90. edsl-0.1.33.dev2/edsl/questions/prompt_templates/question_list.jinja +17 -0
  91. edsl-0.1.33.dev2/edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
  92. edsl-0.1.33.dev2/edsl/questions/prompt_templates/question_numerical.jinja +37 -0
  93. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/question_registry.py +6 -2
  94. edsl-0.1.33.dev2/edsl/questions/templates/checkbox/__init__.py +0 -0
  95. edsl-0.1.33.dev2/edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
  96. edsl-0.1.33.dev2/edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
  97. edsl-0.1.33.dev2/edsl/questions/templates/extract/answering_instructions.jinja +7 -0
  98. edsl-0.1.33.dev2/edsl/questions/templates/extract/question_presentation.jinja +1 -0
  99. edsl-0.1.33.dev2/edsl/questions/templates/free_text/__init__.py +0 -0
  100. edsl-0.1.33.dev2/edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
  101. edsl-0.1.33.dev2/edsl/questions/templates/free_text/question_presentation.jinja +1 -0
  102. edsl-0.1.33.dev2/edsl/questions/templates/likert_five/__init__.py +0 -0
  103. edsl-0.1.33.dev2/edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
  104. edsl-0.1.33.dev2/edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
  105. edsl-0.1.33.dev2/edsl/questions/templates/linear_scale/__init__.py +0 -0
  106. edsl-0.1.33.dev2/edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
  107. edsl-0.1.33.dev2/edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
  108. edsl-0.1.33.dev2/edsl/questions/templates/list/__init__.py +0 -0
  109. edsl-0.1.33.dev2/edsl/questions/templates/list/answering_instructions.jinja +4 -0
  110. edsl-0.1.33.dev2/edsl/questions/templates/list/question_presentation.jinja +5 -0
  111. edsl-0.1.33.dev2/edsl/questions/templates/multiple_choice/__init__.py +0 -0
  112. edsl-0.1.33.dev2/edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
  113. edsl-0.1.33.dev2/edsl/questions/templates/multiple_choice/html.jinja +0 -0
  114. edsl-0.1.33.dev2/edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
  115. edsl-0.1.33.dev2/edsl/questions/templates/numerical/__init__.py +0 -0
  116. edsl-0.1.33.dev2/edsl/questions/templates/numerical/answering_instructions.jinja +8 -0
  117. edsl-0.1.33.dev2/edsl/questions/templates/numerical/question_presentation.jinja +7 -0
  118. edsl-0.1.33.dev2/edsl/questions/templates/rank/answering_instructions.jinja +11 -0
  119. edsl-0.1.33.dev2/edsl/questions/templates/rank/question_presentation.jinja +15 -0
  120. edsl-0.1.33.dev2/edsl/questions/templates/top_k/__init__.py +0 -0
  121. edsl-0.1.33.dev2/edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
  122. edsl-0.1.33.dev2/edsl/questions/templates/top_k/question_presentation.jinja +22 -0
  123. edsl-0.1.33.dev2/edsl/questions/templates/yes_no/__init__.py +0 -0
  124. edsl-0.1.33.dev2/edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
  125. edsl-0.1.33.dev2/edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
  126. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/Dataset.py +20 -0
  127. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/DatasetExportMixin.py +41 -47
  128. edsl-0.1.33.dev2/edsl/results/DatasetTree.py +145 -0
  129. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/Result.py +32 -5
  130. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/Results.py +131 -45
  131. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/ResultsDBMixin.py +3 -3
  132. edsl-0.1.33.dev2/edsl/results/Selector.py +118 -0
  133. edsl-0.1.33.dev2/edsl/results/tree_explore.py +115 -0
  134. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/scenarios/Scenario.py +10 -4
  135. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/scenarios/ScenarioList.py +348 -39
  136. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/scenarios/ScenarioListExportMixin.py +9 -0
  137. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/study/SnapShot.py +8 -1
  138. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/RuleCollection.py +2 -2
  139. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/Survey.py +634 -315
  140. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/SurveyExportMixin.py +71 -9
  141. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/SurveyFlowVisualizationMixin.py +2 -1
  142. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/SurveyQualtricsImport.py +75 -4
  143. edsl-0.1.33.dev2/edsl/surveys/instructions/ChangeInstruction.py +47 -0
  144. edsl-0.1.33.dev2/edsl/surveys/instructions/Instruction.py +34 -0
  145. edsl-0.1.33.dev2/edsl/surveys/instructions/InstructionCollection.py +77 -0
  146. edsl-0.1.33.dev2/edsl/surveys/instructions/__init__.py +0 -0
  147. edsl-0.1.33.dev2/edsl/templates/error_reporting/base.html +24 -0
  148. edsl-0.1.33.dev2/edsl/templates/error_reporting/exceptions_by_model.html +35 -0
  149. edsl-0.1.33.dev2/edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
  150. edsl-0.1.33.dev2/edsl/templates/error_reporting/exceptions_by_type.html +17 -0
  151. edsl-0.1.33.dev2/edsl/templates/error_reporting/interview_details.html +111 -0
  152. edsl-0.1.33.dev2/edsl/templates/error_reporting/interviews.html +10 -0
  153. edsl-0.1.33.dev2/edsl/templates/error_reporting/overview.html +5 -0
  154. edsl-0.1.33.dev2/edsl/templates/error_reporting/performance_plot.html +2 -0
  155. edsl-0.1.33.dev2/edsl/templates/error_reporting/report.css +74 -0
  156. edsl-0.1.33.dev2/edsl/templates/error_reporting/report.html +118 -0
  157. edsl-0.1.33.dev2/edsl/templates/error_reporting/report.js +25 -0
  158. edsl-0.1.33.dev2/edsl/utilities/gcp_bucket/__init__.py +0 -0
  159. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/pyproject.toml +6 -1
  160. edsl-0.1.33.dev1/edsl/agents/Invigilator.py +0 -286
  161. edsl-0.1.33.dev1/edsl/data_transfer_models.py +0 -38
  162. edsl-0.1.33.dev1/edsl/exceptions/questions.py +0 -34
  163. edsl-0.1.33.dev1/edsl/jobs/interviews/Interview.py +0 -305
  164. edsl-0.1.33.dev1/edsl/jobs/interviews/InterviewExceptionEntry.py +0 -101
  165. edsl-0.1.33.dev1/edsl/jobs/interviews/InterviewTaskBuildingMixin.py +0 -286
  166. edsl-0.1.33.dev1/edsl/questions/QuestionCheckBox.py +0 -167
  167. edsl-0.1.33.dev1/edsl/questions/QuestionExtract.py +0 -112
  168. edsl-0.1.33.dev1/edsl/questions/QuestionList.py +0 -112
  169. edsl-0.1.33.dev1/edsl/questions/QuestionMultipleChoice.py +0 -188
  170. edsl-0.1.33.dev1/edsl/questions/QuestionNumerical.py +0 -111
  171. edsl-0.1.33.dev1/edsl/questions/QuestionRank.py +0 -166
  172. edsl-0.1.33.dev1/edsl/utilities/gcp_bucket/simple_example.py +0 -9
  173. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/LICENSE +0 -0
  174. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/Base.py +0 -0
  175. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/BaseDiff.py +0 -0
  176. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/__version__.py +0 -0
  177. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/agents/descriptors.py +0 -0
  178. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/base/Base.py +0 -0
  179. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/AgentConstructionMixin.py +0 -0
  180. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/Conjure.py +0 -0
  181. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/InputData.py +0 -0
  182. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/InputDataCSV.py +0 -0
  183. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/InputDataMixinQuestionStats.py +0 -0
  184. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/InputDataPyRead.py +0 -0
  185. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/InputDataSPSS.py +0 -0
  186. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/InputDataStata.py +0 -0
  187. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/QuestionOptionMixin.py +0 -0
  188. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/QuestionTypeMixin.py +0 -0
  189. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/RawQuestion.py +0 -0
  190. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/SurveyResponses.py +0 -0
  191. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/__init__.py +0 -0
  192. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/examples/placeholder.txt +0 -0
  193. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/naming_utilities.py +0 -0
  194. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conjure/utilities.py +0 -0
  195. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conversation/Conversation.py +0 -0
  196. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conversation/car_buying.py +0 -0
  197. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conversation/mug_negotiation.py +0 -0
  198. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/conversation/next_speaker_utilities.py +0 -0
  199. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/coop/__init__.py +0 -0
  200. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/coop/utils.py +0 -0
  201. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/data/CacheEntry.py +0 -0
  202. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/data/CacheHandler.py +0 -0
  203. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/data/SQLiteDict.py +0 -0
  204. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/data/__init__.py +0 -0
  205. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/data/orm.py +0 -0
  206. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/__init__.py +0 -0
  207. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/agents.py +0 -0
  208. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/configuration.py +0 -0
  209. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/coop.py +0 -0
  210. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/data.py +0 -0
  211. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/general.py +0 -0
  212. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/jobs.py +0 -0
  213. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/prompts.py +0 -0
  214. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/exceptions/surveys.py +0 -0
  215. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/DeepInfraService.py +0 -0
  216. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/InferenceServicesCollection.py +0 -0
  217. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/OllamaService.py +0 -0
  218. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/__init__.py +0 -0
  219. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/rate_limits_cache.py +0 -0
  220. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/inference_services/write_available.py +0 -0
  221. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/__init__.py +0 -0
  222. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/buckets/BucketCollection.py +0 -0
  223. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/buckets/ModelBuckets.py +0 -0
  224. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/interviews/InterviewStatistic.py +0 -0
  225. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/interviews/InterviewStatisticsCollection.py +0 -0
  226. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/interviews/InterviewStatusDictionary.py +0 -0
  227. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/interviews/InterviewStatusLog.py +0 -0
  228. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/interviews/InterviewStatusMixin.py +0 -0
  229. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/interviews/ReportErrors.py +0 -0
  230. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/interviews/interview_status_enum.py +0 -0
  231. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/runners/JobsRunnerStatusData.py +0 -0
  232. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/tasks/TaskCreators.py +0 -0
  233. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/tasks/TaskStatusLog.py +0 -0
  234. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/tasks/task_management.py +0 -0
  235. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/tasks/task_status_enum.py +0 -0
  236. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/tokens/InterviewTokenUsage.py +0 -0
  237. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/jobs/tokens/TokenUsage.py +0 -0
  238. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/language_models/__init__.py +0 -0
  239. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/language_models/unused/ReplicateBase.py +0 -0
  240. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/notebooks/Notebook.py +0 -0
  241. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/notebooks/__init__.py +0 -0
  242. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/QuestionInstructionsBase.py +0 -0
  243. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/__init__.py +0 -0
  244. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/agent_instructions.py +0 -0
  245. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/agent_persona.py +0 -0
  246. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/question_budget.py +0 -0
  247. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/question_checkbox.py +0 -0
  248. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/question_extract.py +0 -0
  249. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/question_freetext.py +0 -0
  250. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/question_linear_scale.py +0 -0
  251. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/question_list.py +0 -0
  252. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/question_multiple_choice.py +0 -0
  253. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/question_numerical.py +0 -0
  254. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/library/question_rank.py +0 -0
  255. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/prompt_config.py +0 -0
  256. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/prompts/registry.py +0 -0
  257. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/SimpleAskMixin.py +0 -0
  258. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/compose_questions.py +0 -0
  259. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/derived/__init__.py +0 -0
  260. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/questions/settings.py +0 -0
  261. {edsl-0.1.33.dev1/edsl/utilities/gcp_bucket → edsl-0.1.33.dev2/edsl/questions/templates}/__init__.py +0 -0
  262. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/ResultsExportMixin.py +0 -0
  263. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/ResultsFetchMixin.py +0 -0
  264. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/ResultsGGMixin.py +0 -0
  265. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/ResultsToolsMixin.py +0 -0
  266. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/results/__init__.py +0 -0
  267. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/scenarios/FileStore.py +0 -0
  268. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/scenarios/ScenarioHtmlMixin.py +0 -0
  269. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/scenarios/ScenarioImageMixin.py +0 -0
  270. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/scenarios/ScenarioListPdfMixin.py +0 -0
  271. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/scenarios/__init__.py +0 -0
  272. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/shared.py +0 -0
  273. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/study/ObjectEntry.py +0 -0
  274. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/study/ProofOfWork.py +0 -0
  275. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/study/Study.py +0 -0
  276. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/study/__init__.py +0 -0
  277. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/DAG.py +0 -0
  278. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/Memory.py +0 -0
  279. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/MemoryPlan.py +0 -0
  280. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/Rule.py +0 -0
  281. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/SurveyCSS.py +0 -0
  282. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/__init__.py +0 -0
  283. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/base.py +0 -0
  284. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/surveys/descriptors.py +0 -0
  285. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/tools/__init__.py +0 -0
  286. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/tools/clusters.py +0 -0
  287. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/tools/embeddings.py +0 -0
  288. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/tools/embeddings_plotting.py +0 -0
  289. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/tools/plotting.py +0 -0
  290. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/tools/summarize.py +0 -0
  291. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/SystemInfo.py +0 -0
  292. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/__init__.py +0 -0
  293. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/ast_utilities.py +0 -0
  294. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/data/Registry.py +0 -0
  295. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/data/__init__.py +0 -0
  296. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/data/scooter_results.json +0 -0
  297. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/decorators.py +0 -0
  298. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/gcp_bucket/cloud_storage.py +0 -0
  299. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/interface.py +0 -0
  300. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/repair_functions.py +0 -0
  301. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/restricted_python.py +0 -0
  302. {edsl-0.1.33.dev1 → edsl-0.1.33.dev2}/edsl/utilities/utilities.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: edsl
3
- Version: 0.1.33.dev1
3
+ Version: 0.1.33.dev2
4
4
  Summary: Create and analyze LLM-based surveys
5
5
  Home-page: https://www.expectedparrot.com/
6
6
  License: MIT
@@ -23,9 +23,11 @@ Requires-Dist: black[jupyter] (>=24.4.2,<25.0.0)
23
23
  Requires-Dist: boto3 (>=1.34.161,<2.0.0)
24
24
  Requires-Dist: groq (>=0.9.0,<0.10.0)
25
25
  Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
26
+ Requires-Dist: json-repair (>=0.28.4,<0.29.0)
26
27
  Requires-Dist: jupyter (>=1.0.0,<2.0.0)
27
28
  Requires-Dist: markdown2 (>=2.4.11,<3.0.0)
28
29
  Requires-Dist: matplotlib (>=3.8,<3.9)
30
+ Requires-Dist: mistralai (>=1.0.2,<2.0.0)
29
31
  Requires-Dist: nest-asyncio (>=1.5.9,<2.0.0)
30
32
  Requires-Dist: numpy (>=1.22,<2.0)
31
33
  Requires-Dist: openai (>=1.4.0,<2.0.0)
@@ -67,7 +69,7 @@ A quick example:
67
69
 
68
70
  ```python
69
71
  # Import a question type
70
- from edsl.questions import QuestionMultipleChoice
72
+ from edsl import QuestionMultipleChoice
71
73
 
72
74
  # Construct a question using the question type template
73
75
  q = QuestionMultipleChoice(
@@ -19,7 +19,7 @@ A quick example:
19
19
 
20
20
  ```python
21
21
  # Import a question type
22
- from edsl.questions import QuestionMultipleChoice
22
+ from edsl import QuestionMultipleChoice
23
23
 
24
24
  # Construct a question using the question type template
25
25
  q = QuestionMultipleChoice(
@@ -0,0 +1,24 @@
1
+ from importlib import resources
2
+ from jinja2 import BaseLoader, TemplateNotFound
3
+ import os
4
+
5
+
6
+ class TemplateLoader(BaseLoader):
7
+ def __init__(self, package_name, templates_dir):
8
+ self.package_name = package_name
9
+ self.templates_dir = templates_dir
10
+
11
+ def get_source(self, environment, template):
12
+ try:
13
+ parts = [self.templates_dir] + template.split("/")
14
+ template_path = os.path.join(*parts)
15
+
16
+ # Use resources.files() to get a Traversable object
17
+ templates = resources.files(self.package_name).joinpath(self.templates_dir)
18
+
19
+ # Use the read_text() method of the Traversable object
20
+ content = templates.joinpath(template).read_text()
21
+
22
+ return content, None, lambda: True
23
+ except FileNotFoundError:
24
+ raise TemplateNotFound(template)
@@ -8,9 +8,10 @@ from edsl.__version__ import __version__
8
8
  from edsl.config import Config, CONFIG
9
9
  from edsl.agents.Agent import Agent
10
10
  from edsl.agents.AgentList import AgentList
11
+
11
12
  from edsl.questions import QuestionBase
13
+ from edsl.questions.question_registry import Question
12
14
  from edsl.questions import QuestionMultipleChoice
13
- from edsl.questions import QuestionBudget
14
15
  from edsl.questions import QuestionCheckBox
15
16
  from edsl.questions import QuestionExtract
16
17
  from edsl.questions import QuestionFreeText
@@ -19,10 +20,10 @@ from edsl.questions import QuestionLikertFive
19
20
  from edsl.questions import QuestionList
20
21
  from edsl.questions import QuestionLinearScale
21
22
  from edsl.questions import QuestionNumerical
22
- from edsl.questions import QuestionRank
23
- from edsl.questions import QuestionTopK
24
23
  from edsl.questions import QuestionYesNo
25
- from edsl.questions.question_registry import Question
24
+ from edsl.questions import QuestionBudget
25
+ from edsl.questions import QuestionRank
26
+
26
27
  from edsl.scenarios import Scenario
27
28
  from edsl.scenarios import ScenarioList
28
29
 
@@ -40,3 +41,6 @@ from edsl.notebooks.Notebook import Notebook
40
41
  from edsl.study.Study import Study
41
42
  from edsl.conjure.Conjure import Conjure
42
43
  from edsl.coop.coop import Coop
44
+
45
+ from edsl.surveys.instructions.Instruction import Instruction
46
+ from edsl.surveys.instructions.ChangeInstruction import ChangeInstruction
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
  import copy
5
5
  import inspect
6
6
  import types
7
- from typing import Callable, Optional, Union
7
+ from typing import Callable, Optional, Union, Any
8
8
  from uuid import uuid4
9
9
  from edsl.Base import Base
10
10
 
@@ -228,7 +228,12 @@ class Agent(Base):
228
228
  if hasattr(self, "answer_question_directly"):
229
229
  delattr(self, "answer_question_directly")
230
230
 
231
- def add_direct_question_answering_method(self, method: Callable) -> None:
231
+ def add_direct_question_answering_method(
232
+ self,
233
+ method: Callable,
234
+ validate_response: bool = False,
235
+ translate_response: bool = False,
236
+ ) -> None:
232
237
  """Add a method to the agent that can answer a particular question type.
233
238
 
234
239
  :param method: A method that can answer a question directly.
@@ -249,6 +254,9 @@ class Agent(Base):
249
254
  )
250
255
  # print("Warning: overwriting existing answer_question_directly method")
251
256
 
257
+ self.validate_response = validate_response
258
+ self.translate_response = translate_response
259
+
252
260
  signature = inspect.signature(method)
253
261
  for argument in ["question", "scenario", "self"]:
254
262
  if argument not in signature.parameters:
@@ -272,6 +280,7 @@ class Agent(Base):
272
280
  current_answers: Optional[dict] = None,
273
281
  iteration: int = 1,
274
282
  sidecar_model=None,
283
+ raise_validation_errors: bool = True,
275
284
  ) -> "InvigilatorBase":
276
285
  """Create an Invigilator.
277
286
 
@@ -303,7 +312,12 @@ class Agent(Base):
303
312
  iteration=iteration,
304
313
  cache=cache,
305
314
  sidecar_model=sidecar_model,
315
+ raise_validation_errors=raise_validation_errors,
306
316
  )
317
+ if hasattr(self, "validate_response"):
318
+ invigilator.validate_response = self.validate_response
319
+ if hasattr(self, "translate_response"):
320
+ invigilator.translate_response = self.translate_response
307
321
  return invigilator
308
322
 
309
323
  async def async_answer_question(
@@ -334,8 +348,8 @@ class Agent(Base):
334
348
  >>> a.add_direct_question_answering_method(lambda self, question, scenario: "I am a direct answer.")
335
349
  >>> from edsl import QuestionFreeText
336
350
  >>> q = QuestionFreeText.example()
337
- >>> a.answer_question(question = q, cache = False)
338
- {'answer': 'I am a direct answer.', 'comment': 'This is a real survey response from a human.', ...}
351
+ >>> a.answer_question(question = q, cache = False).answer
352
+ 'I am a direct answer.'
339
353
 
340
354
  This is a function where an agent returns an answer to a particular question.
341
355
  However, there are several different ways an agent can answer a question, so the
@@ -369,6 +383,7 @@ class Agent(Base):
369
383
  current_answers: Optional[dict] = None,
370
384
  iteration: int = 0,
371
385
  sidecar_model=None,
386
+ raise_validation_errors: bool = True,
372
387
  ) -> "InvigilatorBase":
373
388
  """Create an Invigilator."""
374
389
  from edsl import Model
@@ -378,7 +393,6 @@ class Agent(Base):
378
393
  scenario = scenario or Scenario()
379
394
 
380
395
  from edsl.agents.Invigilator import (
381
- InvigilatorDebug,
382
396
  InvigilatorHuman,
383
397
  InvigilatorFunctional,
384
398
  InvigilatorAI,
@@ -391,8 +405,9 @@ class Agent(Base):
391
405
  cache = Cache()
392
406
 
393
407
  if debug:
408
+ raise NotImplementedError("Debug mode is not yet implemented.")
394
409
  # use the question's _simulate_answer method
395
- invigilator_class = InvigilatorDebug
410
+ # invigilator_class = InvigilatorDebug
396
411
  elif hasattr(question, "answer_question_directly"):
397
412
  # It's a functional question and the answer only depends on the agent's traits & the scenario
398
413
  invigilator_class = InvigilatorFunctional
@@ -422,6 +437,7 @@ class Agent(Base):
422
437
  iteration=iteration,
423
438
  cache=cache,
424
439
  sidecar_model=sidecar_model,
440
+ raise_validation_errors=raise_validation_errors,
425
441
  )
426
442
  return invigilator
427
443
 
@@ -497,8 +513,8 @@ class Agent(Base):
497
513
  if name == "has_dynamic_traits_function":
498
514
  return self.has_dynamic_traits_function
499
515
 
500
- if name in self.traits:
501
- return self.traits[name]
516
+ if name in self._traits:
517
+ return self._traits[name]
502
518
  raise AttributeError(
503
519
  f"'{type(self).__name__}' object has no attribute '{name}'"
504
520
  )
@@ -570,9 +586,9 @@ class Agent(Base):
570
586
  if dynamic_traits_func:
571
587
  func = inspect.getsource(dynamic_traits_func)
572
588
  raw_data["dynamic_traits_function_source_code"] = func
573
- raw_data[
574
- "dynamic_traits_function_name"
575
- ] = self.dynamic_traits_function_name
589
+ raw_data["dynamic_traits_function_name"] = (
590
+ self.dynamic_traits_function_name
591
+ )
576
592
  if hasattr(self, "answer_question_directly"):
577
593
  raw_data.pop(
578
594
  "answer_question_directly", None
@@ -588,9 +604,9 @@ class Agent(Base):
588
604
  raw_data["answer_question_directly_source_code"] = inspect.getsource(
589
605
  answer_question_directly_func
590
606
  )
591
- raw_data[
592
- "answer_question_directly_function_name"
593
- ] = self.answer_question_directly_function_name
607
+ raw_data["answer_question_directly_function_name"] = (
608
+ self.answer_question_directly_function_name
609
+ )
594
610
 
595
611
  return raw_data
596
612
 
@@ -640,6 +656,22 @@ class Agent(Base):
640
656
  column_names = ["Attribute", "Value"]
641
657
  return table_data, column_names
642
658
 
659
+ def add_trait(self, trait_name_or_dict: str, value: Optional[Any] = None) -> Agent:
660
+ """Adds a trait to an agent and returns that agent"""
661
+ if isinstance(trait_name_or_dict, dict) and value is None:
662
+ self.traits.update(trait_name_or_dict)
663
+ return self
664
+
665
+ if isinstance(trait_name_or_dict, dict) and value:
666
+ raise ValueError(f"You passed a dict: {trait_name_or_dict}")
667
+
668
+ if isinstance(trait_name_or_dict, str):
669
+ trait = trait_name_or_dict
670
+ self.traits[trait] = value
671
+ return self
672
+
673
+ raise Exception("Something is not right with adding")
674
+
643
675
  def remove_trait(self, trait: str) -> Agent:
644
676
  """Remove a trait from the agent.
645
677
 
@@ -21,6 +21,12 @@ from simpleeval import EvalWithCompoundTypes
21
21
  from edsl.Base import Base
22
22
  from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
23
23
 
24
+ from collections.abc import Iterable
25
+
26
+
27
+ def is_iterable(obj):
28
+ return isinstance(obj, Iterable)
29
+
24
30
 
25
31
  class AgentList(UserList, Base):
26
32
  """A list of Agents."""
@@ -111,6 +117,13 @@ class AgentList(UserList, Base):
111
117
 
112
118
  return AgentList(new_data)
113
119
 
120
+ @property
121
+ def all_traits(self):
122
+ d = {}
123
+ for agent in self:
124
+ d.update(agent.traits)
125
+ return list(d.keys())
126
+
114
127
  @classmethod
115
128
  def from_csv(cls, file_path: str):
116
129
  """Load AgentList from a CSV file.
@@ -159,6 +172,36 @@ class AgentList(UserList, Base):
159
172
  _ = agent.remove_trait(trait)
160
173
  return self
161
174
 
175
+ def add_trait(self, trait, values):
176
+ """Adds a new trait to every agent, with values taken from values.
177
+
178
+ :param trait: The name of the trait.
179
+ :param values: The valeues(s) of the trait. If a single value is passed, it is used for all agents.
180
+
181
+ >>> al = AgentList.example()
182
+ >>> al.add_trait('new_trait', 1)
183
+ AgentList([Agent(traits = {'age': 22, 'hair': 'brown', 'height': 5.5, 'new_trait': 1}), Agent(traits = {'age': 22, 'hair': 'brown', 'height': 5.5, 'new_trait': 1})])
184
+ >>> al.select('new_trait').to_scenario_list().to_list()
185
+ [1, 1]
186
+ >>> al.add_trait('new_trait', [1, 2, 3])
187
+ Traceback (most recent call last):
188
+ ...
189
+ ValueError: The passed values have to be the same length as the agent list.
190
+ """
191
+ if not is_iterable(values):
192
+ value = values
193
+ for agent in self.data:
194
+ agent.add_trait(trait, value)
195
+ return self
196
+
197
+ if len(values) != len(self):
198
+ raise ValueError(
199
+ "The passed values have to be the same length as the agent list."
200
+ )
201
+ for agent, value in zip(self.data, values):
202
+ agent.add_trait(trait, value)
203
+ return self
204
+
162
205
  @staticmethod
163
206
  def get_codebook(file_path: str):
164
207
  """Return the codebook for a CSV file.
@@ -0,0 +1,199 @@
1
+ """Module for creating Invigilators, which are objects to administer a question to an Agent."""
2
+
3
+ from typing import Dict, Any, Optional
4
+
5
+ from edsl.exceptions import AgentRespondedWithBadJSONError
6
+ from edsl.prompts.Prompt import Prompt
7
+ from edsl.utilities.decorators import sync_wrapper, jupyter_nb_handler
8
+ from edsl.prompts.registry import get_classes as prompt_lookup
9
+ from edsl.exceptions.questions import QuestionAnswerValidationError
10
+ from edsl.agents.PromptConstructionMixin import PromptConstructorMixin
11
+ from edsl.agents.InvigilatorBase import InvigilatorBase
12
+ from edsl.data_transfer_models import AgentResponseDict, EDSLResultObjectInput
13
+
14
+
15
+ class NotApplicable(str):
16
+ def __new__(cls):
17
+ instance = super().__new__(cls, "Not Applicable")
18
+ instance.literal = "Not Applicable"
19
+ return instance
20
+
21
+
22
+ class InvigilatorAI(PromptConstructorMixin, InvigilatorBase):
23
+ """An invigilator that uses an AI model to answer questions."""
24
+
25
+ async def async_answer_question(self) -> AgentResponseDict:
26
+ """Answer a question using the AI model.
27
+
28
+ >>> i = InvigilatorAI.example()
29
+ >>> i.answer_question()
30
+ {'message': [{'text': 'SPAM!'}], 'usage': {'prompt_tokens': 1, 'completion_tokens': 1}}
31
+ """
32
+ prompts = self.get_prompts()
33
+ params = {
34
+ "user_prompt": prompts["user_prompt"].text,
35
+ "system_prompt": prompts["system_prompt"].text,
36
+ }
37
+ if "encoded_image" in prompts:
38
+ params["encoded_image"] = prompts["encoded_image"]
39
+
40
+ params.update({"iteration": self.iteration, "cache": self.cache})
41
+
42
+ agent_response_dict: AgentResponseDict = await self.model.async_get_response(
43
+ **params
44
+ )
45
+ # store to self in case validation failure
46
+ self.raw_model_response = agent_response_dict.model_outputs.response
47
+ self.generated_tokens = agent_response_dict.edsl_dict.generated_tokens
48
+
49
+ return self.extract_edsl_result_entry_and_validate(agent_response_dict)
50
+
51
+ def _remove_from_cache(self, cache_key) -> None:
52
+ """Remove an entry from the cache."""
53
+ if cache_key:
54
+ del self.cache.data[cache_key]
55
+
56
+ def determine_answer(self, raw_answer: str) -> Any:
57
+ question_dict = self.survey.question_names_to_questions()
58
+ # iterates through the current answers and updates the question_dict (which is all questions)
59
+ for other_question, answer in self.current_answers.items():
60
+ if other_question in question_dict:
61
+ question_dict[other_question].answer = answer
62
+ else:
63
+ # it might be a comment
64
+ if (
65
+ new_question := other_question.split("_comment")[0]
66
+ ) in question_dict:
67
+ question_dict[new_question].comment = answer
68
+
69
+ combined_dict = {**question_dict, **self.scenario}
70
+ # sometimes the answer is a code, so we need to translate it
71
+ return self.question._translate_answer_code_to_answer(raw_answer, combined_dict)
72
+
73
+ def extract_edsl_result_entry_and_validate(
74
+ self, agent_response_dict: AgentResponseDict
75
+ ) -> EDSLResultObjectInput:
76
+ edsl_dict = agent_response_dict.edsl_dict._asdict()
77
+ exception_occurred = None
78
+ validated = False
79
+ try:
80
+ validated_edsl_dict = self.question._validate_answer(edsl_dict)
81
+ answer = self.determine_answer(validated_edsl_dict["answer"])
82
+ comment = validated_edsl_dict.get("comment", "")
83
+ validated = True
84
+ except QuestionAnswerValidationError as e:
85
+ answer = None
86
+ comment = "The response was not valid."
87
+ if self.raise_validation_errors:
88
+ exception_occurred = e
89
+ except Exception as non_validation_error:
90
+ answer = None
91
+ comment = "Some other error occurred."
92
+ exception_occurred = non_validation_error
93
+ finally:
94
+ # even if validation failes, we still return the result
95
+ data = {
96
+ "answer": answer,
97
+ "comment": comment,
98
+ "generated_tokens": agent_response_dict.edsl_dict.generated_tokens,
99
+ "question_name": self.question.question_name,
100
+ "prompts": self.get_prompts(),
101
+ "cached_response": agent_response_dict.model_outputs.cached_response,
102
+ "raw_model_response": agent_response_dict.model_outputs.response,
103
+ "cache_used": agent_response_dict.model_outputs.cache_used,
104
+ "cache_key": agent_response_dict.model_outputs.cache_key,
105
+ "validated": validated,
106
+ "exception_occurred": exception_occurred,
107
+ "cost": agent_response_dict.model_outputs.cost,
108
+ }
109
+ result = EDSLResultObjectInput(**data)
110
+ return result
111
+
112
+ answer_question = sync_wrapper(async_answer_question)
113
+
114
+
115
+ class InvigilatorHuman(InvigilatorBase):
116
+ """An invigilator for when a human is answering the question."""
117
+
118
+ validate_response: bool = False
119
+ translate_response: bool = False
120
+
121
+ async def async_answer_question(self, iteration: int = 0) -> AgentResponseDict:
122
+ """Return the answer to the question."""
123
+ comment = "This is a real survey response from a human."
124
+
125
+ def __repr__(self):
126
+ return f"{self.literal}"
127
+
128
+ exception_occurred = None
129
+ validated = False
130
+ try:
131
+ answer = self.agent.answer_question_directly(self.question, self.scenario)
132
+ self.raw_model_response = answer
133
+
134
+ if self.validate_response:
135
+ _ = self.question._validate_answer({"answer": answer})
136
+ if self.translate_response:
137
+ answer = self.question._translate_answer_code_to_answer(
138
+ answer, self.scenario
139
+ )
140
+ validated = True
141
+ except QuestionAnswerValidationError as e:
142
+ answer = None
143
+ if self.raise_validation_errors:
144
+ exception_occurred = e
145
+ except Exception as e:
146
+ answer = None
147
+ if self.raise_validation_errors:
148
+ exception_occurred = e
149
+ finally:
150
+ data = {
151
+ "generated_tokens": NotApplicable(),
152
+ "question_name": self.question.question_name,
153
+ "prompts": self.get_prompts(),
154
+ "cached_response": NotApplicable(),
155
+ "raw_model_response": NotApplicable(),
156
+ "cache_used": NotApplicable(),
157
+ "cache_key": NotApplicable(),
158
+ "answer": answer,
159
+ "comment": comment,
160
+ "validated": validated,
161
+ "exception_occurred": exception_occurred,
162
+ }
163
+ return EDSLResultObjectInput(**data)
164
+
165
+
166
+ class InvigilatorFunctional(InvigilatorBase):
167
+ """A Invigilator for when the question has a answer_question_directly function."""
168
+
169
+ async def async_answer_question(self, iteration: int = 0) -> AgentResponseDict:
170
+ """Return the answer to the question."""
171
+ func = self.question.answer_question_directly
172
+ answer = func(scenario=self.scenario, agent_traits=self.agent.traits)
173
+
174
+ return EDSLResultObjectInput(
175
+ generated_tokens=str(answer),
176
+ question_name=self.question.question_name,
177
+ prompts=self.get_prompts(),
178
+ cached_response=NotApplicable(),
179
+ raw_model_response=NotApplicable(),
180
+ cache_used=NotApplicable(),
181
+ cache_key=NotApplicable(),
182
+ answer=answer["answer"],
183
+ comment="This is the result of a functional question.",
184
+ validated=True,
185
+ exception_occurred=None,
186
+ )
187
+
188
+ def get_prompts(self) -> Dict[str, Prompt]:
189
+ """Return the prompts used."""
190
+ return {
191
+ "user_prompt": Prompt("NA"),
192
+ "system_prompt": Prompt("NA"),
193
+ }
194
+
195
+
196
+ if __name__ == "__main__":
197
+ import doctest
198
+
199
+ doctest.testmod(optionflags=doctest.ELLIPSIS)