edsl 0.1.29.dev3__tar.gz → 0.1.30__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 (209) hide show
  1. {edsl-0.1.29.dev3 → edsl-0.1.30}/PKG-INFO +11 -10
  2. {edsl-0.1.29.dev3 → edsl-0.1.30}/README.md +10 -10
  3. edsl-0.1.30/edsl/Base.py +288 -0
  4. edsl-0.1.30/edsl/__init__.py +42 -0
  5. edsl-0.1.30/edsl/__version__.py +1 -0
  6. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/agents/Agent.py +79 -41
  7. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/agents/AgentList.py +26 -26
  8. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/agents/Invigilator.py +19 -2
  9. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/agents/InvigilatorBase.py +15 -10
  10. edsl-0.1.30/edsl/agents/PromptConstructionMixin.py +376 -0
  11. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/agents/descriptors.py +2 -1
  12. {edsl-0.1.29.dev3/edsl → edsl-0.1.30/edsl/base}/Base.py +2 -1
  13. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/config.py +2 -1
  14. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/InputData.py +39 -8
  15. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conversation/car_buying.py +1 -1
  16. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/coop/coop.py +187 -150
  17. edsl-0.1.30/edsl/coop/utils.py +123 -0
  18. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/data/Cache.py +41 -18
  19. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/data/CacheEntry.py +6 -7
  20. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/data/SQLiteDict.py +11 -3
  21. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/data_transfer_models.py +4 -0
  22. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/Answers.py +15 -1
  23. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/Jobs.py +108 -49
  24. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/buckets/ModelBuckets.py +14 -2
  25. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/buckets/TokenBucket.py +32 -5
  26. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/Interview.py +99 -79
  27. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/InterviewTaskBuildingMixin.py +19 -24
  28. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/runners/JobsRunnerAsyncio.py +16 -16
  29. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/tasks/QuestionTaskCreator.py +10 -6
  30. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/tasks/TaskHistory.py +4 -3
  31. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/language_models/LanguageModel.py +17 -17
  32. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/language_models/ModelList.py +1 -1
  33. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/language_models/repair.py +8 -7
  34. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/notebooks/Notebook.py +47 -10
  35. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/Prompt.py +31 -19
  36. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionBase.py +38 -13
  37. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionBudget.py +5 -6
  38. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionCheckBox.py +7 -3
  39. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionExtract.py +5 -3
  40. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionFreeText.py +7 -5
  41. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionFunctional.py +34 -5
  42. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionList.py +3 -4
  43. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionMultipleChoice.py +68 -12
  44. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionNumerical.py +4 -3
  45. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/QuestionRank.py +5 -3
  46. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/__init__.py +4 -3
  47. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/descriptors.py +46 -4
  48. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/question_registry.py +20 -31
  49. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/settings.py +1 -1
  50. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/results/Dataset.py +31 -0
  51. edsl-0.1.29.dev3/edsl/results/ResultsExportMixin.py → edsl-0.1.30/edsl/results/DatasetExportMixin.py +103 -91
  52. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/results/Result.py +66 -70
  53. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/results/Results.py +160 -68
  54. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/results/ResultsDBMixin.py +7 -3
  55. edsl-0.1.30/edsl/results/ResultsExportMixin.py +43 -0
  56. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/results/ResultsGGMixin.py +3 -3
  57. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/results/ResultsToolsMixin.py +5 -5
  58. edsl-0.1.30/edsl/scenarios/FileStore.py +299 -0
  59. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/scenarios/Scenario.py +16 -24
  60. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/scenarios/ScenarioList.py +42 -17
  61. edsl-0.1.30/edsl/scenarios/ScenarioListExportMixin.py +32 -0
  62. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/scenarios/ScenarioListPdfMixin.py +2 -1
  63. edsl-0.1.30/edsl/scenarios/__init__.py +2 -0
  64. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/study/Study.py +8 -16
  65. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/MemoryPlan.py +11 -4
  66. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/Survey.py +88 -17
  67. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/SurveyExportMixin.py +4 -2
  68. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/SurveyFlowVisualizationMixin.py +6 -4
  69. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/tools/plotting.py +4 -2
  70. edsl-0.1.30/edsl/utilities/__init__.py +22 -0
  71. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/interface.py +66 -45
  72. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/utilities.py +11 -13
  73. {edsl-0.1.29.dev3 → edsl-0.1.30}/pyproject.toml +19 -21
  74. edsl-0.1.29.dev3/edsl/__init__.py +0 -42
  75. edsl-0.1.29.dev3/edsl/__version__.py +0 -1
  76. edsl-0.1.29.dev3/edsl/agents/PromptConstructionMixin.py +0 -134
  77. edsl-0.1.29.dev3/edsl/coop/utils.py +0 -155
  78. edsl-0.1.29.dev3/edsl/scenarios/__init__.py +0 -1
  79. edsl-0.1.29.dev3/edsl/utilities/__init__.py +0 -22
  80. {edsl-0.1.29.dev3 → edsl-0.1.30}/LICENSE +0 -0
  81. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/BaseDiff.py +0 -0
  82. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/agents/__init__.py +0 -0
  83. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/AgentConstructionMixin.py +0 -0
  84. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/Conjure.py +0 -0
  85. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/InputDataCSV.py +0 -0
  86. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/InputDataMixinQuestionStats.py +0 -0
  87. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/InputDataPyRead.py +0 -0
  88. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/InputDataSPSS.py +0 -0
  89. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/InputDataStata.py +0 -0
  90. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/QuestionOptionMixin.py +0 -0
  91. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/QuestionTypeMixin.py +0 -0
  92. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/RawQuestion.py +0 -0
  93. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/SurveyResponses.py +0 -0
  94. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/__init__.py +0 -0
  95. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/examples/placeholder.txt +0 -0
  96. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/naming_utilities.py +0 -0
  97. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conjure/utilities.py +0 -0
  98. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conversation/Conversation.py +0 -0
  99. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conversation/mug_negotiation.py +0 -0
  100. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/conversation/next_speaker_utilities.py +0 -0
  101. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/coop/__init__.py +0 -0
  102. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/data/CacheHandler.py +0 -0
  103. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/data/__init__.py +0 -0
  104. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/data/orm.py +0 -0
  105. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/enums.py +0 -0
  106. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/__init__.py +0 -0
  107. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/agents.py +0 -0
  108. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/configuration.py +0 -0
  109. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/coop.py +0 -0
  110. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/data.py +0 -0
  111. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/general.py +0 -0
  112. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/jobs.py +0 -0
  113. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/language_models.py +0 -0
  114. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/prompts.py +0 -0
  115. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/questions.py +0 -0
  116. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/results.py +0 -0
  117. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/exceptions/surveys.py +0 -0
  118. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/AnthropicService.py +0 -0
  119. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/DeepInfraService.py +0 -0
  120. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/GoogleService.py +0 -0
  121. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/InferenceServiceABC.py +0 -0
  122. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/InferenceServicesCollection.py +0 -0
  123. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/OpenAIService.py +0 -0
  124. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/__init__.py +0 -0
  125. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/models_available_cache.py +0 -0
  126. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/rate_limits_cache.py +0 -0
  127. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/registry.py +0 -0
  128. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/inference_services/write_available.py +0 -0
  129. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/__init__.py +0 -0
  130. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/buckets/BucketCollection.py +0 -0
  131. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/InterviewStatistic.py +0 -0
  132. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/InterviewStatisticsCollection.py +0 -0
  133. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/InterviewStatusDictionary.py +0 -0
  134. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/InterviewStatusLog.py +0 -0
  135. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/InterviewStatusMixin.py +0 -0
  136. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/ReportErrors.py +0 -0
  137. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/interview_exception_tracking.py +0 -0
  138. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/interview_status_enum.py +0 -0
  139. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/interviews/retry_management.py +0 -0
  140. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/runners/JobsRunnerStatusData.py +0 -0
  141. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/runners/JobsRunnerStatusMixin.py +0 -0
  142. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/tasks/TaskCreators.py +0 -0
  143. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/tasks/TaskStatusLog.py +0 -0
  144. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/tasks/task_management.py +0 -0
  145. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/tasks/task_status_enum.py +0 -0
  146. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/tokens/InterviewTokenUsage.py +0 -0
  147. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/jobs/tokens/TokenUsage.py +0 -0
  148. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/language_models/RegisterLanguageModelsMeta.py +0 -0
  149. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/language_models/__init__.py +0 -0
  150. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/language_models/registry.py +0 -0
  151. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/language_models/unused/ReplicateBase.py +0 -0
  152. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/notebooks/__init__.py +0 -0
  153. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/QuestionInstructionsBase.py +0 -0
  154. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/__init__.py +0 -0
  155. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/agent_instructions.py +0 -0
  156. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/agent_persona.py +0 -0
  157. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/question_budget.py +0 -0
  158. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/question_checkbox.py +0 -0
  159. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/question_extract.py +0 -0
  160. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/question_freetext.py +0 -0
  161. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/question_linear_scale.py +0 -0
  162. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/question_list.py +0 -0
  163. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/question_multiple_choice.py +0 -0
  164. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/question_numerical.py +0 -0
  165. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/library/question_rank.py +0 -0
  166. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/prompt_config.py +0 -0
  167. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/prompts/registry.py +0 -0
  168. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/AnswerValidatorMixin.py +0 -0
  169. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/RegisterQuestionsMeta.py +0 -0
  170. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/SimpleAskMixin.py +0 -0
  171. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/compose_questions.py +0 -0
  172. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/derived/QuestionLikertFive.py +0 -0
  173. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/derived/QuestionLinearScale.py +0 -0
  174. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/derived/QuestionTopK.py +0 -0
  175. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/derived/QuestionYesNo.py +0 -0
  176. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/questions/derived/__init__.py +0 -0
  177. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/results/ResultsFetchMixin.py +0 -0
  178. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/results/__init__.py +0 -0
  179. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/scenarios/ScenarioHtmlMixin.py +0 -0
  180. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/scenarios/ScenarioImageMixin.py +0 -0
  181. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/shared.py +0 -0
  182. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/study/ObjectEntry.py +0 -0
  183. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/study/ProofOfWork.py +0 -0
  184. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/study/SnapShot.py +0 -0
  185. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/study/__init__.py +0 -0
  186. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/DAG.py +0 -0
  187. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/Memory.py +0 -0
  188. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/Rule.py +0 -0
  189. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/RuleCollection.py +0 -0
  190. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/SurveyCSS.py +0 -0
  191. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/__init__.py +0 -0
  192. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/base.py +0 -0
  193. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/surveys/descriptors.py +0 -0
  194. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/tools/__init__.py +0 -0
  195. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/tools/clusters.py +0 -0
  196. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/tools/embeddings.py +0 -0
  197. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/tools/embeddings_plotting.py +0 -0
  198. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/tools/summarize.py +0 -0
  199. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/SystemInfo.py +0 -0
  200. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/ast_utilities.py +0 -0
  201. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/data/Registry.py +0 -0
  202. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/data/__init__.py +0 -0
  203. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/data/scooter_results.json +0 -0
  204. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/decorators.py +0 -0
  205. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/gcp_bucket/__init__.py +0 -0
  206. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/gcp_bucket/cloud_storage.py +0 -0
  207. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/gcp_bucket/simple_example.py +0 -0
  208. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/repair_functions.py +0 -0
  209. {edsl-0.1.29.dev3 → edsl-0.1.30}/edsl/utilities/restricted_python.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: edsl
3
- Version: 0.1.29.dev3
3
+ Version: 0.1.30
4
4
  Summary: Create and analyze LLM-based surveys
5
5
  Home-page: https://www.expectedparrot.com/
6
6
  License: MIT
@@ -57,15 +57,6 @@ The Expected Parrot Domain-Specific Language (EDSL) package lets you conduct com
57
57
  - [LinkedIn](https://www.linkedin.com/company/expectedparrot/)
58
58
  - [Blog](https://blog.expectedparrot.com)
59
59
 
60
- ## 💡 Contributions, feature requests & bugs
61
- Interested in contributing? Want us to add a new feature? Found a bug for us to squash?
62
- Please send us an email at [info@expectedparrot.com](mailto:info@expectedparrot.com) or message us at our [Discord channel](https://discord.com/invite/mxAYkjfy9m).
63
-
64
- ## 💻 Requirements
65
- * EDSL is compatible with Python 3.9 - 3.12.
66
- * API keys for large language models that you want to use, stored in a `.env` file.
67
- See instructions on [storing API keys](https://docs.expectedparrot.com/en/latest/api_keys.html).
68
-
69
60
  ## 🌎 Hello, World!
70
61
  A quick example:
71
62
 
@@ -96,3 +87,13 @@ Output:
96
87
  │ Good │
97
88
  └───────────────────┘
98
89
  ```
90
+
91
+ ## 💻 Requirements
92
+ * EDSL is compatible with Python 3.9 - 3.12.
93
+ * API keys for large language models that you want to use, stored in a `.env` file.
94
+ See instructions on [storing API keys](https://docs.expectedparrot.com/en/latest/api_keys.html).
95
+
96
+ ## 💡 Contributions, feature requests & bugs
97
+ Interested in contributing? Want us to add a new feature? Found a bug for us to squash?
98
+ Please send us an email at [info@expectedparrot.com](mailto:info@expectedparrot.com) or message us at our [Discord channel](https://discord.com/invite/mxAYkjfy9m).
99
+
@@ -14,15 +14,6 @@ The Expected Parrot Domain-Specific Language (EDSL) package lets you conduct com
14
14
  - [LinkedIn](https://www.linkedin.com/company/expectedparrot/)
15
15
  - [Blog](https://blog.expectedparrot.com)
16
16
 
17
- ## 💡 Contributions, feature requests & bugs
18
- Interested in contributing? Want us to add a new feature? Found a bug for us to squash?
19
- Please send us an email at [info@expectedparrot.com](mailto:info@expectedparrot.com) or message us at our [Discord channel](https://discord.com/invite/mxAYkjfy9m).
20
-
21
- ## 💻 Requirements
22
- * EDSL is compatible with Python 3.9 - 3.12.
23
- * API keys for large language models that you want to use, stored in a `.env` file.
24
- See instructions on [storing API keys](https://docs.expectedparrot.com/en/latest/api_keys.html).
25
-
26
17
  ## 🌎 Hello, World!
27
18
  A quick example:
28
19
 
@@ -52,4 +43,13 @@ Output:
52
43
  ┡━━━━━━━━━━━━━━━━━━━┩
53
44
  │ Good │
54
45
  └───────────────────┘
55
- ```
46
+ ```
47
+
48
+ ## 💻 Requirements
49
+ * EDSL is compatible with Python 3.9 - 3.12.
50
+ * API keys for large language models that you want to use, stored in a `.env` file.
51
+ See instructions on [storing API keys](https://docs.expectedparrot.com/en/latest/api_keys.html).
52
+
53
+ ## 💡 Contributions, feature requests & bugs
54
+ Interested in contributing? Want us to add a new feature? Found a bug for us to squash?
55
+ Please send us an email at [info@expectedparrot.com](mailto:info@expectedparrot.com) or message us at our [Discord channel](https://discord.com/invite/mxAYkjfy9m).
@@ -0,0 +1,288 @@
1
+ """Base class for all classes in the package. It provides rich printing and persistence of objects."""
2
+
3
+ from abc import ABC, abstractmethod, ABCMeta
4
+ import gzip
5
+ import io
6
+ import json
7
+ from typing import Any, Optional, Union
8
+ from uuid import UUID
9
+
10
+
11
+ class RichPrintingMixin:
12
+ """Mixin for rich printing and persistence of objects."""
13
+
14
+ def _for_console(self):
15
+ """Return a string representation of the object for console printing."""
16
+ from rich.console import Console
17
+
18
+ with io.StringIO() as buf:
19
+ console = Console(file=buf, record=True)
20
+ table = self.rich_print()
21
+ console.print(table)
22
+ return console.export_text()
23
+
24
+ def __str__(self):
25
+ """Return a string representation of the object for console printing."""
26
+ return self._for_console()
27
+
28
+ def print(self):
29
+ """Print the object to the console."""
30
+ from edsl.utilities.utilities import is_notebook
31
+
32
+ if is_notebook():
33
+ from IPython.display import display
34
+
35
+ display(self.rich_print())
36
+ else:
37
+ from rich.console import Console
38
+
39
+ console = Console()
40
+ console.print(self.rich_print())
41
+
42
+
43
+ class PersistenceMixin:
44
+ """Mixin for saving and loading objects to and from files."""
45
+
46
+ def push(
47
+ self,
48
+ description: Optional[str] = None,
49
+ visibility: Optional[str] = "unlisted",
50
+ ):
51
+ """Post the object to coop."""
52
+ from edsl.coop import Coop
53
+
54
+ c = Coop()
55
+ return c.create(self, description, visibility)
56
+
57
+ @classmethod
58
+ def pull(cls, uuid: Optional[Union[str, UUID]] = None, url: Optional[str] = None):
59
+ """Pull the object from coop."""
60
+ from edsl.coop import Coop
61
+ from edsl.coop.utils import ObjectRegistry
62
+
63
+ object_type = ObjectRegistry.get_object_type_by_edsl_class(cls)
64
+ coop = Coop()
65
+ return coop.get(uuid, url, object_type)
66
+
67
+ @classmethod
68
+ def delete(cls, uuid: Optional[Union[str, UUID]] = None, url: Optional[str] = None):
69
+ """Delete the object from coop."""
70
+ from edsl.coop import Coop
71
+
72
+ coop = Coop()
73
+ return coop.delete(uuid, url)
74
+
75
+ @classmethod
76
+ def patch(
77
+ cls,
78
+ uuid: Optional[Union[str, UUID]] = None,
79
+ url: Optional[str] = None,
80
+ description: Optional[str] = None,
81
+ value: Optional[Any] = None,
82
+ visibility: Optional[str] = None,
83
+ ):
84
+ """
85
+ Patch an uploaded objects attributes.
86
+ - `description` changes the description of the object on Coop
87
+ - `value` changes the value of the object on Coop. **has to be an EDSL object**
88
+ - `visibility` changes the visibility of the object on Coop
89
+ """
90
+ from edsl.coop import Coop
91
+
92
+ coop = Coop()
93
+ return coop.patch(uuid, url, description, value, visibility)
94
+
95
+ @classmethod
96
+ def search(cls, query):
97
+ """Search for objects on coop."""
98
+ from edsl.coop import Coop
99
+
100
+ c = Coop()
101
+ return c.search(cls, query)
102
+
103
+ def save(self, filename, compress=True):
104
+ """Save the object to a file as zippped JSON.
105
+
106
+ >>> obj.save("obj.json.gz")
107
+
108
+ """
109
+ if filename.endswith("json.gz"):
110
+ import warnings
111
+
112
+ warnings.warn(
113
+ "Do not apply the file extensions. The filename should not end with 'json.gz'."
114
+ )
115
+ filename = filename[:-7]
116
+ if filename.endswith("json"):
117
+ filename = filename[:-4]
118
+ warnings.warn(
119
+ "Do not apply the file extensions. The filename should not end with 'json'."
120
+ )
121
+
122
+ if compress:
123
+ with gzip.open(filename + ".json.gz", "wb") as f:
124
+ f.write(json.dumps(self.to_dict()).encode("utf-8"))
125
+ else:
126
+ with open(filename + ".json", "w") as f:
127
+ f.write(json.dumps(self.to_dict()))
128
+
129
+ @staticmethod
130
+ def open_compressed_file(filename):
131
+ with gzip.open(filename, "rb") as f:
132
+ file_contents = f.read()
133
+ file_contents_decoded = file_contents.decode("utf-8")
134
+ d = json.loads(file_contents_decoded)
135
+ return d
136
+
137
+ @staticmethod
138
+ def open_regular_file(filename):
139
+ with open(filename, "r") as f:
140
+ d = json.loads(f.read())
141
+ return d
142
+
143
+ @classmethod
144
+ def load(cls, filename):
145
+ """Load the object from a file.
146
+
147
+ >>> obj = cls.load("obj.json.gz")
148
+
149
+ """
150
+
151
+ if filename.endswith("json.gz"):
152
+ d = cls.open_compressed_file(filename)
153
+ elif filename.endswith("json"):
154
+ d = cls.open_regular_file(filename)
155
+ else:
156
+ try:
157
+ d = cls.open_compressed_file(filename)
158
+ except:
159
+ d = cls.open_regular_file(filename)
160
+ finally:
161
+ raise ValueError("File must be a json or json.gz file")
162
+
163
+ return cls.from_dict(d)
164
+
165
+
166
+ class RegisterSubclassesMeta(ABCMeta):
167
+ """Metaclass for registering subclasses."""
168
+
169
+ _registry = {}
170
+
171
+ def __init__(cls, name, bases, nmspc):
172
+ """Register the class in the registry upon creation."""
173
+ super(RegisterSubclassesMeta, cls).__init__(name, bases, nmspc)
174
+ if cls.__name__ != "Base":
175
+ RegisterSubclassesMeta._registry[cls.__name__] = cls
176
+
177
+ @staticmethod
178
+ def get_registry():
179
+ """Return the registry of subclasses."""
180
+ return dict(RegisterSubclassesMeta._registry)
181
+
182
+
183
+ class DiffMethodsMixin:
184
+ def __sub__(self, other):
185
+ """Return the difference between two objects."""
186
+ from edsl.BaseDiff import BaseDiff
187
+
188
+ return BaseDiff(self, other)
189
+
190
+
191
+ class Base(
192
+ RichPrintingMixin,
193
+ PersistenceMixin,
194
+ DiffMethodsMixin,
195
+ ABC,
196
+ metaclass=RegisterSubclassesMeta,
197
+ ):
198
+ """Base class for all classes in the package."""
199
+
200
+ # def __getitem__(self, key):
201
+ # return getattr(self, key)
202
+
203
+ # @abstractmethod
204
+ # def _repr_html_(self) -> str:
205
+ # raise NotImplementedError("This method is not implemented yet.")
206
+
207
+ # @abstractmethod
208
+ # def _repr_(self) -> str:
209
+ # raise NotImplementedError("This method is not implemented yet.")
210
+
211
+ def keys(self):
212
+ """Return the keys of the object."""
213
+ _keys = list(self.to_dict().keys())
214
+ if "edsl_version" in _keys:
215
+ _keys.remove("edsl_version")
216
+ if "edsl_class_name" in _keys:
217
+ _keys.remove("edsl_class_name")
218
+ return _keys
219
+
220
+ def values(self):
221
+ """Return the values of the object."""
222
+ data = self.to_dict()
223
+ keys = self.keys()
224
+ return {data[key] for key in keys}
225
+
226
+ def _repr_html_(self):
227
+ from edsl.utilities.utilities import data_to_html
228
+
229
+ return data_to_html(self.to_dict())
230
+
231
+ # def html(self):
232
+ # html_string = self._repr_html_()
233
+ # import tempfile
234
+ # import webbrowser
235
+
236
+ # with tempfile.NamedTemporaryFile("w", delete=False, suffix=".html") as f:
237
+ # # print("Writing HTML to", f.name)
238
+ # f.write(html_string)
239
+ # webbrowser.open(f.name)
240
+
241
+ def __eq__(self, other):
242
+ """Return whether two objects are equal."""
243
+ import inspect
244
+
245
+ if not isinstance(other, self.__class__):
246
+ return False
247
+ if "sort" in inspect.signature(self._to_dict).parameters:
248
+ return self._to_dict(sort=True) == other._to_dict(sort=True)
249
+ else:
250
+ return self._to_dict() == other._to_dict()
251
+
252
+ @abstractmethod
253
+ def example():
254
+ """This method should be implemented by subclasses."""
255
+ raise NotImplementedError("This method is not implemented yet.")
256
+
257
+ @abstractmethod
258
+ def rich_print():
259
+ """This method should be implemented by subclasses."""
260
+ raise NotImplementedError("This method is not implemented yet.")
261
+
262
+ @abstractmethod
263
+ def to_dict():
264
+ """This method should be implemented by subclasses."""
265
+ raise NotImplementedError("This method is not implemented yet.")
266
+
267
+ @abstractmethod
268
+ def from_dict():
269
+ """This method should be implemented by subclasses."""
270
+ raise NotImplementedError("This method is not implemented yet.")
271
+
272
+ @abstractmethod
273
+ def code():
274
+ """This method should be implemented by subclasses."""
275
+ raise NotImplementedError("This method is not implemented yet.")
276
+
277
+ def show_methods(self, show_docstrings=True):
278
+ """Show the methods of the object."""
279
+ public_methods_with_docstrings = [
280
+ (method, getattr(self, method).__doc__)
281
+ for method in dir(self)
282
+ if callable(getattr(self, method)) and not method.startswith("_")
283
+ ]
284
+ if show_docstrings:
285
+ for method, documentation in public_methods_with_docstrings:
286
+ print(f"{method}: {documentation}")
287
+ else:
288
+ return [x[0] for x in public_methods_with_docstrings]
@@ -0,0 +1,42 @@
1
+ import os
2
+ import time
3
+
4
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
5
+ ROOT_DIR = os.path.dirname(BASE_DIR)
6
+
7
+ from edsl.__version__ import __version__
8
+ from edsl.config import Config, CONFIG
9
+ from edsl.agents.Agent import Agent
10
+ from edsl.agents.AgentList import AgentList
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
30
+ from edsl.surveys.Survey import Survey
31
+ from edsl.language_models.registry import Model
32
+ from edsl.language_models.ModelList import ModelList
33
+ from edsl.results.Results import Results
34
+ from edsl.data.Cache import Cache
35
+ from edsl.data.CacheEntry import CacheEntry
36
+ from edsl.data.CacheHandler import set_session_cache, unset_session_cache
37
+ from edsl.shared import shared_globals
38
+ from edsl.jobs.Jobs import Jobs
39
+ from edsl.notebooks.Notebook import Notebook
40
+ from edsl.study.Study import Study
41
+ from edsl.conjure.Conjure import Conjure
42
+ from edsl.coop.coop import Coop
@@ -0,0 +1 @@
1
+ __version__ = "0.1.30"
@@ -4,28 +4,16 @@ from __future__ import annotations
4
4
  import copy
5
5
  import inspect
6
6
  import types
7
- from typing import Any, Callable, Optional, Union, Dict, Sequence
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
- from edsl.questions.QuestionBase import QuestionBase
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
- from edsl.agents.Invigilator import (
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.dynamic_traits_function is not None:
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.dynamic_traits_function is not None:
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
- model: Optional[LanguageModel] = None,
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
- """Return an example agent.
692
+ def example(cls, randomize: bool = False) -> Agent:
693
+ """
694
+ Returns an example Agent instance.
657
695
 
658
- >>> Agent.example()
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
- return cls(traits={"age": 22, "hair": "brown", "height": 5.5})
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.