edsl 0.1.35__tar.gz → 0.1.36.dev1__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 (310) hide show
  1. {edsl-0.1.35 → edsl-0.1.36.dev1}/PKG-INFO +1 -1
  2. edsl-0.1.36.dev1/edsl/__version__.py +1 -0
  3. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/agents/Agent.py +38 -14
  4. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/agents/Invigilator.py +2 -1
  5. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/agents/PromptConstructor.py +6 -51
  6. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/Jobs.py +146 -48
  7. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/interviews/Interview.py +42 -15
  8. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/interviews/InterviewExceptionEntry.py +0 -3
  9. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/tasks/QuestionTaskCreator.py +1 -5
  10. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/LanguageModel.py +3 -0
  11. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/prompts/Prompt.py +24 -38
  12. edsl-0.1.36.dev1/edsl/prompts/__init__.py +2 -0
  13. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionBasePromptsMixin.py +18 -18
  14. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/descriptors.py +24 -24
  15. edsl-0.1.36.dev1/edsl/questions/templates/budget/__pycache__/__init__.cpython-311.pyc +0 -0
  16. edsl-0.1.36.dev1/edsl/questions/templates/extract/__pycache__/__init__.cpython-311.pyc +0 -0
  17. edsl-0.1.36.dev1/edsl/questions/templates/likert_five/__pycache__/__init__.cpython-311.pyc +0 -0
  18. edsl-0.1.36.dev1/edsl/questions/templates/rank/__pycache__/__init__.cpython-311.pyc +0 -0
  19. edsl-0.1.36.dev1/edsl/questions/templates/top_k/__pycache__/__init__.cpython-311.pyc +0 -0
  20. edsl-0.1.36.dev1/edsl/questions/templates/yes_no/__pycache__/__init__.cpython-311.pyc +0 -0
  21. {edsl-0.1.35 → edsl-0.1.36.dev1}/pyproject.toml +1 -1
  22. edsl-0.1.35/edsl/__version__.py +0 -1
  23. edsl-0.1.35/edsl/jobs/FailedQuestion.py +0 -78
  24. edsl-0.1.35/edsl/jobs/interviews/InterviewStatusMixin.py +0 -33
  25. edsl-0.1.35/edsl/jobs/tasks/task_management.py +0 -13
  26. edsl-0.1.35/edsl/prompts/QuestionInstructionsBase.py +0 -10
  27. edsl-0.1.35/edsl/prompts/__init__.py +0 -2
  28. edsl-0.1.35/edsl/prompts/library/agent_instructions.py +0 -38
  29. edsl-0.1.35/edsl/prompts/library/agent_persona.py +0 -21
  30. edsl-0.1.35/edsl/prompts/library/question_budget.py +0 -30
  31. edsl-0.1.35/edsl/prompts/library/question_checkbox.py +0 -38
  32. edsl-0.1.35/edsl/prompts/library/question_extract.py +0 -23
  33. edsl-0.1.35/edsl/prompts/library/question_freetext.py +0 -18
  34. edsl-0.1.35/edsl/prompts/library/question_linear_scale.py +0 -24
  35. edsl-0.1.35/edsl/prompts/library/question_list.py +0 -26
  36. edsl-0.1.35/edsl/prompts/library/question_multiple_choice.py +0 -54
  37. edsl-0.1.35/edsl/prompts/library/question_numerical.py +0 -35
  38. edsl-0.1.35/edsl/prompts/library/question_rank.py +0 -25
  39. edsl-0.1.35/edsl/prompts/prompt_config.py +0 -37
  40. edsl-0.1.35/edsl/prompts/registry.py +0 -202
  41. {edsl-0.1.35 → edsl-0.1.36.dev1}/LICENSE +0 -0
  42. {edsl-0.1.35 → edsl-0.1.36.dev1}/README.md +0 -0
  43. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/Base.py +0 -0
  44. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/BaseDiff.py +0 -0
  45. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/TemplateLoader.py +0 -0
  46. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/__init__.py +0 -0
  47. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/agents/AgentList.py +0 -0
  48. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/agents/InvigilatorBase.py +0 -0
  49. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/agents/__init__.py +0 -0
  50. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/agents/descriptors.py +0 -0
  51. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/agents/prompt_helpers.py +0 -0
  52. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/AutoStudy.py +0 -0
  53. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/StageBase.py +0 -0
  54. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/StageGenerateSurvey.py +0 -0
  55. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/StageLabelQuestions.py +0 -0
  56. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/StagePersona.py +0 -0
  57. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/StagePersonaDimensionValueRanges.py +0 -0
  58. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/StagePersonaDimensionValues.py +0 -0
  59. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/StagePersonaDimensions.py +0 -0
  60. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/StageQuestions.py +0 -0
  61. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/SurveyCreatorPipeline.py +0 -0
  62. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/auto/utilities.py +0 -0
  63. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/base/Base.py +0 -0
  64. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/config.py +0 -0
  65. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/AgentConstructionMixin.py +0 -0
  66. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/Conjure.py +0 -0
  67. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/InputData.py +0 -0
  68. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/InputDataCSV.py +0 -0
  69. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/InputDataMixinQuestionStats.py +0 -0
  70. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/InputDataPyRead.py +0 -0
  71. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/InputDataSPSS.py +0 -0
  72. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/InputDataStata.py +0 -0
  73. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/QuestionOptionMixin.py +0 -0
  74. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/QuestionTypeMixin.py +0 -0
  75. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/RawQuestion.py +0 -0
  76. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/SurveyResponses.py +0 -0
  77. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/__init__.py +0 -0
  78. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/examples/placeholder.txt +0 -0
  79. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/naming_utilities.py +0 -0
  80. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conjure/utilities.py +0 -0
  81. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conversation/Conversation.py +0 -0
  82. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conversation/car_buying.py +0 -0
  83. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conversation/mug_negotiation.py +0 -0
  84. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/conversation/next_speaker_utilities.py +0 -0
  85. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/coop/PriceFetcher.py +0 -0
  86. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/coop/__init__.py +0 -0
  87. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/coop/coop.py +0 -0
  88. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/coop/utils.py +0 -0
  89. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/data/Cache.py +0 -0
  90. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/data/CacheEntry.py +0 -0
  91. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/data/CacheHandler.py +0 -0
  92. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/data/SQLiteDict.py +0 -0
  93. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/data/__init__.py +0 -0
  94. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/data/orm.py +0 -0
  95. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/data_transfer_models.py +0 -0
  96. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/enums.py +0 -0
  97. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/__init__.py +0 -0
  98. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/agents.py +0 -0
  99. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/configuration.py +0 -0
  100. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/coop.py +0 -0
  101. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/data.py +0 -0
  102. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/general.py +0 -0
  103. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/jobs.py +0 -0
  104. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/language_models.py +0 -0
  105. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/prompts.py +0 -0
  106. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/questions.py +0 -0
  107. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/results.py +0 -0
  108. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/exceptions/surveys.py +0 -0
  109. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/AnthropicService.py +0 -0
  110. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/AwsBedrock.py +0 -0
  111. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/AzureAI.py +0 -0
  112. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/DeepInfraService.py +0 -0
  113. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/GoogleService.py +0 -0
  114. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/GroqService.py +0 -0
  115. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/InferenceServiceABC.py +0 -0
  116. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/InferenceServicesCollection.py +0 -0
  117. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/MistralAIService.py +0 -0
  118. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/OllamaService.py +0 -0
  119. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/OpenAIService.py +0 -0
  120. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/TestService.py +0 -0
  121. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/TogetherAIService.py +0 -0
  122. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/__init__.py +0 -0
  123. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/models_available_cache.py +0 -0
  124. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/rate_limits_cache.py +0 -0
  125. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/registry.py +0 -0
  126. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/inference_services/write_available.py +0 -0
  127. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/Answers.py +0 -0
  128. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/__init__.py +0 -0
  129. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/buckets/BucketCollection.py +0 -0
  130. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/buckets/ModelBuckets.py +0 -0
  131. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/buckets/TokenBucket.py +0 -0
  132. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/interviews/InterviewExceptionCollection.py +0 -0
  133. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/interviews/InterviewStatistic.py +0 -0
  134. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/interviews/InterviewStatisticsCollection.py +0 -0
  135. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/interviews/InterviewStatusDictionary.py +0 -0
  136. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/interviews/InterviewStatusLog.py +0 -0
  137. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/interviews/ReportErrors.py +0 -0
  138. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/interviews/interview_status_enum.py +0 -0
  139. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/runners/JobsRunnerAsyncio.py +0 -0
  140. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/runners/JobsRunnerStatus.py +0 -0
  141. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/runners/JobsRunnerStatusData.py +0 -0
  142. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/tasks/TaskCreators.py +0 -0
  143. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/tasks/TaskHistory.py +0 -0
  144. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/tasks/TaskStatusLog.py +0 -0
  145. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/tasks/task_status_enum.py +0 -0
  146. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/tokens/InterviewTokenUsage.py +0 -0
  147. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/jobs/tokens/TokenUsage.py +0 -0
  148. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/ModelList.py +0 -0
  149. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/RegisterLanguageModelsMeta.py +0 -0
  150. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/__init__.py +0 -0
  151. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/fake_openai_call.py +0 -0
  152. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/fake_openai_service.py +0 -0
  153. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/registry.py +0 -0
  154. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/repair.py +0 -0
  155. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/unused/ReplicateBase.py +0 -0
  156. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/language_models/utilities.py +0 -0
  157. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/notebooks/Notebook.py +0 -0
  158. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/notebooks/__init__.py +0 -0
  159. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/AnswerValidatorMixin.py +0 -0
  160. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionBase.py +0 -0
  161. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionBaseGenMixin.py +0 -0
  162. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionBudget.py +0 -0
  163. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionCheckBox.py +0 -0
  164. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionExtract.py +0 -0
  165. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionFreeText.py +0 -0
  166. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionFunctional.py +0 -0
  167. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionList.py +0 -0
  168. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionMultipleChoice.py +0 -0
  169. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionNumerical.py +0 -0
  170. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/QuestionRank.py +0 -0
  171. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/Quick.py +0 -0
  172. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/RegisterQuestionsMeta.py +0 -0
  173. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/ResponseValidatorABC.py +0 -0
  174. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/SimpleAskMixin.py +0 -0
  175. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/__init__.py +0 -0
  176. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/compose_questions.py +0 -0
  177. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/decorators.py +0 -0
  178. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/derived/QuestionLikertFive.py +0 -0
  179. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/derived/QuestionLinearScale.py +0 -0
  180. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/derived/QuestionTopK.py +0 -0
  181. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/derived/QuestionYesNo.py +0 -0
  182. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/derived/__init__.py +0 -0
  183. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/prompt_templates/question_budget.jinja +0 -0
  184. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/prompt_templates/question_checkbox.jinja +0 -0
  185. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/prompt_templates/question_extract.jinja +0 -0
  186. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/prompt_templates/question_free_text.jinja +0 -0
  187. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/prompt_templates/question_linear_scale.jinja +0 -0
  188. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/prompt_templates/question_list.jinja +0 -0
  189. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/prompt_templates/question_multiple_choice.jinja +0 -0
  190. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/prompt_templates/question_numerical.jinja +0 -0
  191. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/question_registry.py +0 -0
  192. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/settings.py +0 -0
  193. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/__init__.py +0 -0
  194. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/__pycache__/__init__.cpython-311.pyc +0 -0
  195. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/budget/__init__.py +0 -0
  196. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/budget/answering_instructions.jinja +0 -0
  197. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/budget/question_presentation.jinja +0 -0
  198. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/checkbox/__init__.py +0 -0
  199. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/checkbox/__pycache__/__init__.cpython-311.pyc +0 -0
  200. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/checkbox/answering_instructions.jinja +0 -0
  201. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/checkbox/question_presentation.jinja +0 -0
  202. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/extract/__init__.py +0 -0
  203. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/extract/answering_instructions.jinja +0 -0
  204. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/extract/question_presentation.jinja +0 -0
  205. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/free_text/__init__.py +0 -0
  206. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/free_text/__pycache__/__init__.cpython-311.pyc +0 -0
  207. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
  208. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/free_text/question_presentation.jinja +0 -0
  209. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/likert_five/__init__.py +0 -0
  210. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/likert_five/answering_instructions.jinja +0 -0
  211. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/likert_five/question_presentation.jinja +0 -0
  212. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/linear_scale/__init__.py +0 -0
  213. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/linear_scale/__pycache__/__init__.cpython-311.pyc +0 -0
  214. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/linear_scale/answering_instructions.jinja +0 -0
  215. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/linear_scale/question_presentation.jinja +0 -0
  216. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/list/__init__.py +0 -0
  217. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/list/__pycache__/__init__.cpython-311.pyc +0 -0
  218. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/list/answering_instructions.jinja +0 -0
  219. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/list/question_presentation.jinja +0 -0
  220. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/multiple_choice/__init__.py +0 -0
  221. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/multiple_choice/__pycache__/__init__.cpython-311.pyc +0 -0
  222. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/multiple_choice/answering_instructions.jinja +0 -0
  223. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/multiple_choice/html.jinja +0 -0
  224. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/multiple_choice/question_presentation.jinja +0 -0
  225. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/numerical/__init__.py +0 -0
  226. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/numerical/__pycache__/__init__.cpython-311.pyc +0 -0
  227. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/numerical/answering_instructions.jinja +0 -0
  228. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/numerical/question_presentation.jinja +0 -0
  229. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/rank/__init__.py +0 -0
  230. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/rank/answering_instructions.jinja +0 -0
  231. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/rank/question_presentation.jinja +0 -0
  232. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/top_k/__init__.py +0 -0
  233. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/top_k/answering_instructions.jinja +0 -0
  234. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/top_k/question_presentation.jinja +0 -0
  235. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/yes_no/__init__.py +0 -0
  236. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/yes_no/answering_instructions.jinja +0 -0
  237. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/questions/templates/yes_no/question_presentation.jinja +0 -0
  238. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/Dataset.py +0 -0
  239. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/DatasetExportMixin.py +0 -0
  240. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/DatasetTree.py +0 -0
  241. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/Result.py +0 -0
  242. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/Results.py +0 -0
  243. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/ResultsDBMixin.py +0 -0
  244. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/ResultsExportMixin.py +0 -0
  245. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/ResultsFetchMixin.py +0 -0
  246. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/ResultsGGMixin.py +0 -0
  247. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/ResultsToolsMixin.py +0 -0
  248. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/Selector.py +0 -0
  249. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/__init__.py +0 -0
  250. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/results/tree_explore.py +0 -0
  251. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/scenarios/FileStore.py +0 -0
  252. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/scenarios/Scenario.py +0 -0
  253. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/scenarios/ScenarioHtmlMixin.py +0 -0
  254. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/scenarios/ScenarioList.py +0 -0
  255. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/scenarios/ScenarioListExportMixin.py +0 -0
  256. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/scenarios/ScenarioListPdfMixin.py +0 -0
  257. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/scenarios/__init__.py +0 -0
  258. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/shared.py +0 -0
  259. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/study/ObjectEntry.py +0 -0
  260. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/study/ProofOfWork.py +0 -0
  261. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/study/SnapShot.py +0 -0
  262. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/study/Study.py +0 -0
  263. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/study/__init__.py +0 -0
  264. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/DAG.py +0 -0
  265. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/Memory.py +0 -0
  266. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/MemoryPlan.py +0 -0
  267. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/Rule.py +0 -0
  268. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/RuleCollection.py +0 -0
  269. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/Survey.py +0 -0
  270. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/SurveyCSS.py +0 -0
  271. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/SurveyExportMixin.py +0 -0
  272. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/SurveyFlowVisualizationMixin.py +0 -0
  273. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/SurveyQualtricsImport.py +0 -0
  274. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/__init__.py +0 -0
  275. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/base.py +0 -0
  276. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/descriptors.py +0 -0
  277. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/instructions/ChangeInstruction.py +0 -0
  278. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/instructions/Instruction.py +0 -0
  279. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/instructions/InstructionCollection.py +0 -0
  280. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/surveys/instructions/__init__.py +0 -0
  281. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/base.html +0 -0
  282. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/exceptions_by_model.html +0 -0
  283. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/exceptions_by_question_name.html +0 -0
  284. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/exceptions_by_type.html +0 -0
  285. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/interview_details.html +0 -0
  286. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/interviews.html +0 -0
  287. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/overview.html +0 -0
  288. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/performance_plot.html +0 -0
  289. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/report.css +0 -0
  290. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/report.html +0 -0
  291. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/templates/error_reporting/report.js +0 -0
  292. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/tools/__init__.py +0 -0
  293. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/tools/clusters.py +0 -0
  294. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/tools/embeddings.py +0 -0
  295. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/tools/embeddings_plotting.py +0 -0
  296. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/tools/plotting.py +0 -0
  297. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/tools/summarize.py +0 -0
  298. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/SystemInfo.py +0 -0
  299. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/__init__.py +0 -0
  300. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/ast_utilities.py +0 -0
  301. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/data/Registry.py +0 -0
  302. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/data/__init__.py +0 -0
  303. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/data/scooter_results.json +0 -0
  304. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/decorators.py +0 -0
  305. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/gcp_bucket/__init__.py +0 -0
  306. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/gcp_bucket/cloud_storage.py +0 -0
  307. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/interface.py +0 -0
  308. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/repair_functions.py +0 -0
  309. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/restricted_python.py +0 -0
  310. {edsl-0.1.35 → edsl-0.1.36.dev1}/edsl/utilities/utilities.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: edsl
3
- Version: 0.1.35
3
+ Version: 0.1.36.dev1
4
4
  Summary: Create and analyze LLM-based surveys
5
5
  Home-page: https://www.expectedparrot.com/
6
6
  License: MIT
@@ -0,0 +1 @@
1
+ __version__ = "0.1.36.dev1"
@@ -8,6 +8,9 @@ from typing import Callable, Optional, Union, Any
8
8
  from uuid import uuid4
9
9
  from edsl.Base import Base
10
10
 
11
+ from edsl.prompts import Prompt
12
+ from edsl.exceptions import QuestionScenarioRenderError
13
+
11
14
  from edsl.exceptions.agents import (
12
15
  AgentCombinationError,
13
16
  AgentDirectAnswerFunctionError,
@@ -44,7 +47,6 @@ class Agent(Base):
44
47
 
45
48
  def __init__(
46
49
  self,
47
- # *,
48
50
  traits: Optional[dict] = None,
49
51
  name: Optional[str] = None,
50
52
  codebook: Optional[dict] = None,
@@ -112,6 +114,7 @@ class Agent(Base):
112
114
  self.instruction = instruction or self.default_instruction
113
115
  self.dynamic_traits_function = dynamic_traits_function
114
116
 
117
+ # Deal with dynamic traits function
115
118
  if self.dynamic_traits_function:
116
119
  self.dynamic_traits_function_name = self.dynamic_traits_function.__name__
117
120
  self.has_dynamic_traits_function = True
@@ -124,6 +127,7 @@ class Agent(Base):
124
127
  dynamic_traits_function_name, dynamic_traits_function
125
128
  )
126
129
 
130
+ # Deal with direct answer function
127
131
  if answer_question_directly_source_code:
128
132
  self.answer_question_directly_function_name = (
129
133
  answer_question_directly_function_name
@@ -140,10 +144,34 @@ class Agent(Base):
140
144
  self.current_question = None
141
145
 
142
146
  if traits_presentation_template is not None:
143
- from edsl.prompts.library.agent_persona import AgentPersona
144
-
145
147
  self.traits_presentation_template = traits_presentation_template
146
- self.agent_persona = AgentPersona(text=self.traits_presentation_template)
148
+ else:
149
+ self.traits_presentation_template = """Your traits: {{ traits }}"""
150
+
151
+ @property
152
+ def agent_persona(self) -> Prompt:
153
+ return Prompt(text=self.traits_presentation_template)
154
+
155
+ def prompt(self) -> str:
156
+ """Return the prompt for the agent.
157
+
158
+ Example usage:
159
+
160
+ >>> a = Agent(traits = {"age": 10, "hair": "brown", "height": 5.5})
161
+ >>> a.prompt()
162
+ Prompt(text=\"""Your traits: {'age': 10, 'hair': 'brown', 'height': 5.5}\""")
163
+ """
164
+ replacement_dict = (
165
+ self.traits | {"traits": self.traits} | {"codebook": self.codebook}
166
+ )
167
+ if undefined := self.agent_persona.undefined_template_variables(
168
+ replacement_dict
169
+ ):
170
+ raise QuestionScenarioRenderError(
171
+ f"Agent persona still has variables that were not rendered: {undefined}"
172
+ )
173
+ else:
174
+ return self.agent_persona.render(replacement_dict)
147
175
 
148
176
  def _check_dynamic_traits_function(self) -> None:
149
177
  """Check whether dynamic trait function is valid.
@@ -252,7 +280,6 @@ class Agent(Base):
252
280
  warnings.warn(
253
281
  "Warning: overwriting existing answer_question_directly method"
254
282
  )
255
- # print("Warning: overwriting existing answer_question_directly method")
256
283
 
257
284
  self.validate_response = validate_response
258
285
  self.translate_response = translate_response
@@ -575,9 +602,6 @@ class Agent(Base):
575
602
  if self.name == None:
576
603
  raw_data.pop("name")
577
604
 
578
- import inspect
579
-
580
- # print(raw_data)
581
605
  if hasattr(self, "dynamic_traits_function"):
582
606
  raw_data.pop(
583
607
  "dynamic_traits_function", None
@@ -586,9 +610,9 @@ class Agent(Base):
586
610
  if dynamic_traits_func:
587
611
  func = inspect.getsource(dynamic_traits_func)
588
612
  raw_data["dynamic_traits_function_source_code"] = func
589
- raw_data[
590
- "dynamic_traits_function_name"
591
- ] = self.dynamic_traits_function_name
613
+ raw_data["dynamic_traits_function_name"] = (
614
+ self.dynamic_traits_function_name
615
+ )
592
616
  if hasattr(self, "answer_question_directly"):
593
617
  raw_data.pop(
594
618
  "answer_question_directly", None
@@ -604,9 +628,9 @@ class Agent(Base):
604
628
  raw_data["answer_question_directly_source_code"] = inspect.getsource(
605
629
  answer_question_directly_func
606
630
  )
607
- raw_data[
608
- "answer_question_directly_function_name"
609
- ] = self.answer_question_directly_function_name
631
+ raw_data["answer_question_directly_function_name"] = (
632
+ self.answer_question_directly_function_name
633
+ )
610
634
 
611
635
  return raw_data
612
636
 
@@ -4,7 +4,8 @@ from typing import Dict, Any, Optional
4
4
 
5
5
  from edsl.prompts.Prompt import Prompt
6
6
  from edsl.utilities.decorators import sync_wrapper, jupyter_nb_handler
7
- from edsl.prompts.registry import get_classes as prompt_lookup
7
+
8
+ # from edsl.prompts.registry import get_classes as prompt_lookup
8
9
  from edsl.exceptions.questions import QuestionAnswerValidationError
9
10
  from edsl.agents.InvigilatorBase import InvigilatorBase
10
11
  from edsl.data_transfer_models import AgentResponseDict, EDSLResultObjectInput
@@ -7,7 +7,8 @@ from jinja2 import Environment, meta
7
7
 
8
8
  from edsl.prompts.Prompt import Prompt
9
9
  from edsl.data_transfer_models import ImageInfo
10
- from edsl.prompts.registry import get_classes as prompt_lookup
10
+
11
+ # from edsl.prompts.registry import get_classes as prompt_lookup
11
12
  from edsl.exceptions import QuestionScenarioRenderError
12
13
 
13
14
  from edsl.agents.prompt_helpers import PromptComponent, PromptList, PromptPlan
@@ -75,17 +76,8 @@ class PromptConstructor:
75
76
 
76
77
  if self.agent == Agent(): # if agent is empty, then return an empty prompt
77
78
  return Prompt(text="")
78
- if not hasattr(self, "_agent_instructions_prompt"):
79
- applicable_prompts = prompt_lookup(
80
- component_type="agent_instructions",
81
- model=self.model.model,
82
- )
83
- if len(applicable_prompts) == 0:
84
- raise Exception("No applicable prompts found")
85
- self._agent_instructions_prompt = applicable_prompts[0](
86
- text=self.agent.instruction
87
- )
88
- return self._agent_instructions_prompt
79
+
80
+ return Prompt(text=self.agent.instruction)
89
81
 
90
82
  @property
91
83
  def agent_persona_prompt(self) -> Prompt:
@@ -93,51 +85,14 @@ class PromptConstructor:
93
85
  >>> from edsl.agents.InvigilatorBase import InvigilatorBase
94
86
  >>> i = InvigilatorBase.example()
95
87
  >>> i.prompt_constructor.agent_persona_prompt
96
- Prompt(text=\"""You are an agent with the following persona:
97
- {'age': 22, 'hair': 'brown', 'height': 5.5}\""")
98
-
88
+ Prompt(text=\"""Your traits: {'age': 22, 'hair': 'brown', 'height': 5.5}\""")
99
89
  """
100
90
  from edsl import Agent
101
91
 
102
- if hasattr(self, "_agent_persona_prompt"):
103
- return self._agent_persona_prompt
104
-
105
92
  if self.agent == Agent(): # if agent is empty, then return an empty prompt
106
93
  return Prompt(text="")
107
94
 
108
- if not hasattr(self.agent, "agent_persona"):
109
- applicable_prompts = prompt_lookup(
110
- component_type="agent_persona",
111
- model=self.model.model,
112
- )
113
- persona_prompt_template = applicable_prompts[0]()
114
- else:
115
- persona_prompt_template = self.agent.agent_persona
116
-
117
- # TODO: This multiple passing of agent traits - not sure if it is necessary. Not harmful.
118
- template_parameter_dictionary = (
119
- self.agent.traits
120
- | {"traits": self.agent.traits}
121
- | {"codebook": self.agent.codebook}
122
- | {"traits": self.agent.traits}
123
- )
124
-
125
- if undefined := persona_prompt_template.undefined_template_variables(
126
- template_parameter_dictionary
127
- ):
128
- raise QuestionScenarioRenderError(
129
- f"Agent persona still has variables that were not rendered: {undefined}"
130
- )
131
-
132
- persona_prompt = persona_prompt_template.render(template_parameter_dictionary)
133
- if persona_prompt.has_variables:
134
- raise QuestionScenarioRenderError(
135
- "Agent persona still has variables that were not rendered."
136
- )
137
-
138
- self._agent_persona_prompt = persona_prompt
139
-
140
- return self._agent_persona_prompt
95
+ return self.agent.prompt()
141
96
 
142
97
  def prior_answers_dict(self) -> dict:
143
98
  d = self.survey.question_names_to_questions()
@@ -180,17 +180,15 @@ class Jobs(Base):
180
180
  scenario_indices.append(scenario_index)
181
181
  models.append(invigilator.model.model)
182
182
  question_names.append(invigilator.question.question_name)
183
- # cost calculation
184
- key = (invigilator.model._inference_service_, invigilator.model.model)
185
- relevant_prices = price_lookup[key]
186
- inverse_output_price = relevant_prices["output"]["one_usd_buys"]
187
- inverse_input_price = relevant_prices["input"]["one_usd_buys"]
188
- input_tokens = len(str(user_prompt) + str(system_prompt)) // 4
189
- output_tokens = len(str(user_prompt) + str(system_prompt)) // 4
190
- cost = input_tokens / float(
191
- inverse_input_price
192
- ) + output_tokens / float(inverse_output_price)
193
- costs.append(cost)
183
+
184
+ prompt_cost = self.estimate_prompt_cost(
185
+ system_prompt=system_prompt,
186
+ user_prompt=user_prompt,
187
+ price_lookup=price_lookup,
188
+ inference_service=invigilator.model._inference_service_,
189
+ model=invigilator.model.model,
190
+ )
191
+ costs.append(prompt_cost["cost"])
194
192
 
195
193
  d = Dataset(
196
194
  [
@@ -214,50 +212,150 @@ class Jobs(Base):
214
212
  """Print the prompts."""
215
213
  self.prompts().to_scenario_list().print(format="rich")
216
214
 
217
- def estimate_job_cost(self):
218
- from edsl import Coop
215
+ @staticmethod
216
+ def estimate_prompt_cost(
217
+ system_prompt: str,
218
+ user_prompt: str,
219
+ price_lookup: dict,
220
+ inference_service: str,
221
+ model: str,
222
+ ):
223
+ """Estimates the cost of a prompt. Takes piping into account."""
219
224
 
220
- c = Coop()
221
- price_lookup = c.fetch_prices()
225
+ def get_piping_multiplier(prompt: str):
226
+ """Returns 2 if a prompt includes Jinja brances, and 1 otherwise."""
222
227
 
223
- prompts = self.prompts()
228
+ if "{{" in prompt and "}}" in prompt:
229
+ return 2
230
+ return 1
224
231
 
225
- text_len = 0
226
- for prompt in prompts:
227
- text_len += len(str(prompt))
232
+ # Look up prices per token
233
+ key = (inference_service, model)
234
+ relevant_prices = price_lookup[key]
235
+ output_price_per_token = 1 / float(relevant_prices["output"]["one_usd_buys"])
236
+ input_price_per_token = 1 / float(relevant_prices["input"]["one_usd_buys"])
228
237
 
229
- input_token_aproximations = text_len // 4
238
+ # Compute the number of characters (double if the question involves piping)
239
+ user_prompt_chars = len(str(user_prompt)) * get_piping_multiplier(
240
+ str(user_prompt)
241
+ )
242
+ system_prompt_chars = len(str(system_prompt)) * get_piping_multiplier(
243
+ str(system_prompt)
244
+ )
230
245
 
231
- aproximation_cost = {}
232
- total_cost = 0
233
- for model in self.models:
234
- key = (model._inference_service_, model.model)
235
- relevant_prices = price_lookup[key]
236
- inverse_output_price = relevant_prices["output"]["one_usd_buys"]
237
- inverse_input_price = relevant_prices["input"]["one_usd_buys"]
238
-
239
- aproximation_cost[key] = {
240
- "input": input_token_aproximations / float(inverse_input_price),
241
- "output": input_token_aproximations / float(inverse_output_price),
242
- }
243
- ##TODO curenlty we approximate the number of output tokens with the number
244
- # of input tokens. A better solution will be to compute the quesiton answer options length and sum them
245
- # to compute the output tokens
246
-
247
- total_cost += input_token_aproximations / float(inverse_input_price)
248
- total_cost += input_token_aproximations / float(inverse_output_price)
249
-
250
- # multiply_factor = len(self.agents or [1]) * len(self.scenarios or [1])
251
- multiply_factor = 1
252
- out = {
253
- "input_token_aproximations": input_token_aproximations,
254
- "models_costs": aproximation_cost,
255
- "estimated_total_cost": total_cost * multiply_factor,
256
- "multiply_factor": multiply_factor,
257
- "single_config_cost": total_cost,
246
+ # Convert into tokens (1 token approx. equals 4 characters)
247
+ input_tokens = (user_prompt_chars + system_prompt_chars) // 4
248
+ output_tokens = input_tokens
249
+
250
+ cost = (
251
+ input_tokens * input_price_per_token
252
+ + output_tokens * output_price_per_token
253
+ )
254
+
255
+ return {
256
+ "input_tokens": input_tokens,
257
+ "output_tokens": output_tokens,
258
+ "cost": cost,
259
+ }
260
+
261
+ def estimate_job_cost_from_external_prices(self, price_lookup: dict):
262
+ """
263
+ Estimates the cost of a job according to the following assumptions:
264
+
265
+ - 1 token = 4 characters.
266
+ - Input tokens = output tokens.
267
+
268
+ price_lookup is an external pricing dictionary.
269
+ """
270
+
271
+ import pandas as pd
272
+
273
+ interviews = self.interviews()
274
+ data = []
275
+ for interview in interviews:
276
+ invigilators = [
277
+ interview._get_invigilator(question)
278
+ for question in self.survey.questions
279
+ ]
280
+ for invigilator in invigilators:
281
+ prompts = invigilator.get_prompts()
282
+
283
+ # By this point, agent and scenario data has already been added to the prompts
284
+ user_prompt = prompts["user_prompt"]
285
+ system_prompt = prompts["system_prompt"]
286
+ inference_service = invigilator.model._inference_service_
287
+ model = invigilator.model.model
288
+
289
+ prompt_cost = self.estimate_prompt_cost(
290
+ system_prompt=system_prompt,
291
+ user_prompt=user_prompt,
292
+ price_lookup=price_lookup,
293
+ inference_service=inference_service,
294
+ model=model,
295
+ )
296
+
297
+ data.append(
298
+ {
299
+ "user_prompt": user_prompt,
300
+ "system_prompt": system_prompt,
301
+ "estimated_input_tokens": prompt_cost["input_tokens"],
302
+ "estimated_output_tokens": prompt_cost["output_tokens"],
303
+ "estimated_cost": prompt_cost["cost"],
304
+ "inference_service": inference_service,
305
+ "model": model,
306
+ }
307
+ )
308
+
309
+ df = pd.DataFrame.from_records(data)
310
+
311
+ df = (
312
+ df.groupby(["inference_service", "model"])
313
+ .agg(
314
+ {
315
+ "estimated_cost": "sum",
316
+ "estimated_input_tokens": "sum",
317
+ "estimated_output_tokens": "sum",
318
+ }
319
+ )
320
+ .reset_index()
321
+ )
322
+
323
+ estimated_costs_by_model = df.to_dict("records")
324
+
325
+ estimated_total_cost = sum(
326
+ model["estimated_cost"] for model in estimated_costs_by_model
327
+ )
328
+ estimated_total_input_tokens = sum(
329
+ model["estimated_input_tokens"] for model in estimated_costs_by_model
330
+ )
331
+ estimated_total_output_tokens = sum(
332
+ model["estimated_output_tokens"] for model in estimated_costs_by_model
333
+ )
334
+
335
+ output = {
336
+ "estimated_total_cost": estimated_total_cost,
337
+ "estimated_total_input_tokens": estimated_total_input_tokens,
338
+ "estimated_total_output_tokens": estimated_total_output_tokens,
339
+ "model_costs": estimated_costs_by_model,
258
340
  }
259
341
 
260
- return out
342
+ return output
343
+
344
+ def estimate_job_cost(self):
345
+ """
346
+ Estimates the cost of a job according to the following assumptions:
347
+
348
+ - 1 token = 4 characters.
349
+ - Input tokens = output tokens.
350
+
351
+ Fetches prices from Coop.
352
+ """
353
+ from edsl import Coop
354
+
355
+ c = Coop()
356
+ price_lookup = c.fetch_prices()
357
+
358
+ return self.estimate_job_cost_from_external_prices(price_lookup=price_lookup)
261
359
 
262
360
  @staticmethod
263
361
  def _get_container_class(object):
@@ -28,7 +28,7 @@ from edsl.jobs.interviews.InterviewExceptionCollection import (
28
28
  InterviewExceptionCollection,
29
29
  )
30
30
 
31
- from edsl.jobs.interviews.InterviewStatusMixin import InterviewStatusMixin
31
+ # from edsl.jobs.interviews.InterviewStatusMixin import InterviewStatusMixin
32
32
 
33
33
  from edsl.surveys.base import EndOfSurvey
34
34
  from edsl.jobs.buckets.ModelBuckets import ModelBuckets
@@ -44,6 +44,10 @@ from edsl.agents.InvigilatorBase import InvigilatorBase
44
44
 
45
45
  from edsl.exceptions.language_models import LanguageModelNoResponseError
46
46
 
47
+ from edsl.jobs.interviews.InterviewStatusLog import InterviewStatusLog
48
+ from edsl.jobs.tokens.InterviewTokenUsage import InterviewTokenUsage
49
+ from edsl.jobs.interviews.InterviewStatusDictionary import InterviewStatusDictionary
50
+
47
51
 
48
52
  from edsl import CONFIG
49
53
 
@@ -52,7 +56,7 @@ EDSL_BACKOFF_MAX_SEC = float(CONFIG.get("EDSL_BACKOFF_MAX_SEC"))
52
56
  EDSL_MAX_ATTEMPTS = int(CONFIG.get("EDSL_MAX_ATTEMPTS"))
53
57
 
54
58
 
55
- class Interview(InterviewStatusMixin):
59
+ class Interview:
56
60
  """
57
61
  An 'interview' is one agent answering one survey, with one language model, for a given scenario.
58
62
 
@@ -100,21 +104,17 @@ class Interview(InterviewStatusMixin):
100
104
 
101
105
  """
102
106
  self.agent = agent
103
- # what I would like to do
104
- self.survey = copy.deepcopy(survey) # survey copy.deepcopy(survey)
105
- # self.survey = survey
107
+ self.survey = copy.deepcopy(survey)
106
108
  self.scenario = scenario
107
109
  self.model = model
108
110
  self.debug = debug
109
111
  self.iteration = iteration
110
112
  self.cache = cache
111
- self.answers: dict[
112
- str, str
113
- ] = Answers() # will get filled in as interview progresses
113
+ self.answers: dict[str, str] = (
114
+ Answers()
115
+ ) # will get filled in as interview progresses
114
116
  self.sidecar_model = sidecar_model
115
117
 
116
- # self.stop_on_exception = False
117
-
118
118
  # Trackers
119
119
  self.task_creators = TaskCreators() # tracks the task creators
120
120
  self.exceptions = InterviewExceptionCollection()
@@ -131,6 +131,33 @@ class Interview(InterviewStatusMixin):
131
131
 
132
132
  self.failed_questions = []
133
133
 
134
+ @property
135
+ def has_exceptions(self) -> bool:
136
+ """Return True if there are exceptions."""
137
+ return len(self.exceptions) > 0
138
+
139
+ @property
140
+ def task_status_logs(self) -> InterviewStatusLog:
141
+ """Return the task status logs for the interview.
142
+
143
+ The keys are the question names; the values are the lists of status log changes for each task.
144
+ """
145
+ for task_creator in self.task_creators.values():
146
+ self._task_status_log_dict[task_creator.question.question_name] = (
147
+ task_creator.status_log
148
+ )
149
+ return self._task_status_log_dict
150
+
151
+ @property
152
+ def token_usage(self) -> InterviewTokenUsage:
153
+ """Determine how many tokens were used for the interview."""
154
+ return self.task_creators.token_usage
155
+
156
+ @property
157
+ def interview_status(self) -> InterviewStatusDictionary:
158
+ """Return a dictionary mapping task status codes to counts."""
159
+ return self.task_creators.interview_status
160
+
134
161
  # region: Serialization
135
162
  def _to_dict(self, include_exceptions=False) -> dict[str, Any]:
136
163
  """Return a dictionary representation of the Interview instance.
@@ -431,11 +458,11 @@ class Interview(InterviewStatusMixin):
431
458
  """
432
459
  current_question_index: int = self.to_index[current_question.question_name]
433
460
 
434
- next_question: Union[
435
- int, EndOfSurvey
436
- ] = self.survey.rule_collection.next_question(
437
- q_now=current_question_index,
438
- answers=self.answers | self.scenario | self.agent["traits"],
461
+ next_question: Union[int, EndOfSurvey] = (
462
+ self.survey.rule_collection.next_question(
463
+ q_now=current_question_index,
464
+ answers=self.answers | self.scenario | self.agent["traits"],
465
+ )
439
466
  )
440
467
 
441
468
  next_question_index = next_question.next_q
@@ -1,8 +1,5 @@
1
1
  import traceback
2
2
  import datetime
3
- import time
4
- from collections import UserDict
5
- from edsl.jobs.FailedQuestion import FailedQuestion
6
3
 
7
4
 
8
5
  class InterviewExceptionEntry:
@@ -1,20 +1,16 @@
1
1
  import asyncio
2
2
  from typing import Callable, Union, List
3
3
  from collections import UserList, UserDict
4
- import time
5
4
 
6
5
  from edsl.jobs.buckets import ModelBuckets
7
6
  from edsl.exceptions import InterviewErrorPriorTaskCanceled
8
7
 
9
8
  from edsl.jobs.interviews.InterviewStatusDictionary import InterviewStatusDictionary
10
9
  from edsl.jobs.tasks.task_status_enum import TaskStatus, TaskStatusDescriptor
11
-
12
- # from edsl.jobs.tasks.task_management import TokensUsed
13
10
  from edsl.jobs.tasks.TaskStatusLog import TaskStatusLog
14
11
  from edsl.jobs.tokens.InterviewTokenUsage import InterviewTokenUsage
15
12
  from edsl.jobs.tokens.TokenUsage import TokenUsage
16
13
  from edsl.jobs.Answers import Answers
17
-
18
14
  from edsl.questions.QuestionBase import QuestionBase
19
15
 
20
16
 
@@ -130,7 +126,7 @@ class QuestionTaskCreator(UserList):
130
126
  await self.tokens_bucket.get_tokens(requested_tokens)
131
127
 
132
128
  if (estimated_wait_time := self.requests_bucket.wait_time(1)) > 0:
133
- self.waiting = True
129
+ self.waiting = True # do we need this?
134
130
  self.task_status = TaskStatus.WAITING_FOR_REQUEST_CAPACITY
135
131
 
136
132
  await self.requests_bucket.get_tokens(1, cheat_bucket_capacity=True)
@@ -348,6 +348,9 @@ class LanguageModel(
348
348
  """
349
349
  # parameters = dict({})
350
350
 
351
+ # this is the case when data is loaded from a dict after serialization
352
+ if "parameters" in passed_parameter_dict:
353
+ passed_parameter_dict = passed_parameter_dict["parameters"]
351
354
  return {
352
355
  parameter_name: passed_parameter_dict.get(parameter_name, default_value)
353
356
  for parameter_name, default_value in default_parameter_dict.items()