edsl 0.1.15__py3-none-any.whl → 0.1.40__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (407) hide show
  1. edsl/Base.py +348 -38
  2. edsl/BaseDiff.py +260 -0
  3. edsl/TemplateLoader.py +24 -0
  4. edsl/__init__.py +45 -10
  5. edsl/__version__.py +1 -1
  6. edsl/agents/Agent.py +842 -144
  7. edsl/agents/AgentList.py +521 -25
  8. edsl/agents/Invigilator.py +250 -374
  9. edsl/agents/InvigilatorBase.py +257 -0
  10. edsl/agents/PromptConstructor.py +272 -0
  11. edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
  12. edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
  13. edsl/agents/descriptors.py +43 -13
  14. edsl/agents/prompt_helpers.py +129 -0
  15. edsl/agents/question_option_processor.py +172 -0
  16. edsl/auto/AutoStudy.py +130 -0
  17. edsl/auto/StageBase.py +243 -0
  18. edsl/auto/StageGenerateSurvey.py +178 -0
  19. edsl/auto/StageLabelQuestions.py +125 -0
  20. edsl/auto/StagePersona.py +61 -0
  21. edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
  22. edsl/auto/StagePersonaDimensionValues.py +74 -0
  23. edsl/auto/StagePersonaDimensions.py +69 -0
  24. edsl/auto/StageQuestions.py +74 -0
  25. edsl/auto/SurveyCreatorPipeline.py +21 -0
  26. edsl/auto/utilities.py +218 -0
  27. edsl/base/Base.py +279 -0
  28. edsl/config.py +115 -113
  29. edsl/conversation/Conversation.py +290 -0
  30. edsl/conversation/car_buying.py +59 -0
  31. edsl/conversation/chips.py +95 -0
  32. edsl/conversation/mug_negotiation.py +81 -0
  33. edsl/conversation/next_speaker_utilities.py +93 -0
  34. edsl/coop/CoopFunctionsMixin.py +15 -0
  35. edsl/coop/ExpectedParrotKeyHandler.py +125 -0
  36. edsl/coop/PriceFetcher.py +54 -0
  37. edsl/coop/__init__.py +1 -0
  38. edsl/coop/coop.py +1029 -134
  39. edsl/coop/utils.py +131 -0
  40. edsl/data/Cache.py +560 -89
  41. edsl/data/CacheEntry.py +230 -0
  42. edsl/data/CacheHandler.py +168 -0
  43. edsl/data/RemoteCacheSync.py +186 -0
  44. edsl/data/SQLiteDict.py +292 -0
  45. edsl/data/__init__.py +5 -3
  46. edsl/data/orm.py +6 -33
  47. edsl/data_transfer_models.py +74 -27
  48. edsl/enums.py +165 -8
  49. edsl/exceptions/BaseException.py +21 -0
  50. edsl/exceptions/__init__.py +52 -46
  51. edsl/exceptions/agents.py +33 -15
  52. edsl/exceptions/cache.py +5 -0
  53. edsl/exceptions/coop.py +8 -0
  54. edsl/exceptions/general.py +34 -0
  55. edsl/exceptions/inference_services.py +5 -0
  56. edsl/exceptions/jobs.py +15 -0
  57. edsl/exceptions/language_models.py +46 -1
  58. edsl/exceptions/questions.py +80 -5
  59. edsl/exceptions/results.py +16 -5
  60. edsl/exceptions/scenarios.py +29 -0
  61. edsl/exceptions/surveys.py +13 -10
  62. edsl/inference_services/AnthropicService.py +106 -0
  63. edsl/inference_services/AvailableModelCacheHandler.py +184 -0
  64. edsl/inference_services/AvailableModelFetcher.py +215 -0
  65. edsl/inference_services/AwsBedrock.py +118 -0
  66. edsl/inference_services/AzureAI.py +215 -0
  67. edsl/inference_services/DeepInfraService.py +18 -0
  68. edsl/inference_services/GoogleService.py +143 -0
  69. edsl/inference_services/GroqService.py +20 -0
  70. edsl/inference_services/InferenceServiceABC.py +80 -0
  71. edsl/inference_services/InferenceServicesCollection.py +138 -0
  72. edsl/inference_services/MistralAIService.py +120 -0
  73. edsl/inference_services/OllamaService.py +18 -0
  74. edsl/inference_services/OpenAIService.py +236 -0
  75. edsl/inference_services/PerplexityService.py +160 -0
  76. edsl/inference_services/ServiceAvailability.py +135 -0
  77. edsl/inference_services/TestService.py +90 -0
  78. edsl/inference_services/TogetherAIService.py +172 -0
  79. edsl/inference_services/data_structures.py +134 -0
  80. edsl/inference_services/models_available_cache.py +118 -0
  81. edsl/inference_services/rate_limits_cache.py +25 -0
  82. edsl/inference_services/registry.py +41 -0
  83. edsl/inference_services/write_available.py +10 -0
  84. edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
  85. edsl/jobs/Answers.py +21 -20
  86. edsl/jobs/FetchInvigilator.py +47 -0
  87. edsl/jobs/InterviewTaskManager.py +98 -0
  88. edsl/jobs/InterviewsConstructor.py +50 -0
  89. edsl/jobs/Jobs.py +684 -206
  90. edsl/jobs/JobsChecks.py +172 -0
  91. edsl/jobs/JobsComponentConstructor.py +189 -0
  92. edsl/jobs/JobsPrompts.py +270 -0
  93. edsl/jobs/JobsRemoteInferenceHandler.py +311 -0
  94. edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
  95. edsl/jobs/RequestTokenEstimator.py +30 -0
  96. edsl/jobs/async_interview_runner.py +138 -0
  97. edsl/jobs/buckets/BucketCollection.py +104 -0
  98. edsl/jobs/buckets/ModelBuckets.py +65 -0
  99. edsl/jobs/buckets/TokenBucket.py +283 -0
  100. edsl/jobs/buckets/TokenBucketAPI.py +211 -0
  101. edsl/jobs/buckets/TokenBucketClient.py +191 -0
  102. edsl/jobs/check_survey_scenario_compatibility.py +85 -0
  103. edsl/jobs/data_structures.py +120 -0
  104. edsl/jobs/decorators.py +35 -0
  105. edsl/jobs/interviews/Interview.py +392 -0
  106. edsl/jobs/interviews/InterviewExceptionCollection.py +99 -0
  107. edsl/jobs/interviews/InterviewExceptionEntry.py +186 -0
  108. edsl/jobs/interviews/InterviewStatistic.py +63 -0
  109. edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -0
  110. edsl/jobs/interviews/InterviewStatusDictionary.py +78 -0
  111. edsl/jobs/interviews/InterviewStatusLog.py +92 -0
  112. edsl/jobs/interviews/ReportErrors.py +66 -0
  113. edsl/jobs/interviews/interview_status_enum.py +9 -0
  114. edsl/jobs/jobs_status_enums.py +9 -0
  115. edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
  116. edsl/jobs/results_exceptions_handler.py +98 -0
  117. edsl/jobs/runners/JobsRunnerAsyncio.py +151 -110
  118. edsl/jobs/runners/JobsRunnerStatus.py +298 -0
  119. edsl/jobs/tasks/QuestionTaskCreator.py +244 -0
  120. edsl/jobs/tasks/TaskCreators.py +64 -0
  121. edsl/jobs/tasks/TaskHistory.py +470 -0
  122. edsl/jobs/tasks/TaskStatusLog.py +23 -0
  123. edsl/jobs/tasks/task_status_enum.py +161 -0
  124. edsl/jobs/tokens/InterviewTokenUsage.py +27 -0
  125. edsl/jobs/tokens/TokenUsage.py +34 -0
  126. edsl/language_models/ComputeCost.py +63 -0
  127. edsl/language_models/LanguageModel.py +507 -386
  128. edsl/language_models/ModelList.py +164 -0
  129. edsl/language_models/PriceManager.py +127 -0
  130. edsl/language_models/RawResponseHandler.py +106 -0
  131. edsl/language_models/RegisterLanguageModelsMeta.py +184 -0
  132. edsl/language_models/__init__.py +1 -8
  133. edsl/language_models/fake_openai_call.py +15 -0
  134. edsl/language_models/fake_openai_service.py +61 -0
  135. edsl/language_models/key_management/KeyLookup.py +63 -0
  136. edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
  137. edsl/language_models/key_management/KeyLookupCollection.py +38 -0
  138. edsl/language_models/key_management/__init__.py +0 -0
  139. edsl/language_models/key_management/models.py +131 -0
  140. edsl/language_models/model.py +256 -0
  141. edsl/language_models/repair.py +109 -41
  142. edsl/language_models/utilities.py +65 -0
  143. edsl/notebooks/Notebook.py +263 -0
  144. edsl/notebooks/NotebookToLaTeX.py +142 -0
  145. edsl/notebooks/__init__.py +1 -0
  146. edsl/prompts/Prompt.py +222 -93
  147. edsl/prompts/__init__.py +1 -1
  148. edsl/questions/ExceptionExplainer.py +77 -0
  149. edsl/questions/HTMLQuestion.py +103 -0
  150. edsl/questions/QuestionBase.py +518 -0
  151. edsl/questions/QuestionBasePromptsMixin.py +221 -0
  152. edsl/questions/QuestionBudget.py +164 -67
  153. edsl/questions/QuestionCheckBox.py +281 -62
  154. edsl/questions/QuestionDict.py +343 -0
  155. edsl/questions/QuestionExtract.py +136 -50
  156. edsl/questions/QuestionFreeText.py +79 -55
  157. edsl/questions/QuestionFunctional.py +138 -41
  158. edsl/questions/QuestionList.py +184 -57
  159. edsl/questions/QuestionMatrix.py +265 -0
  160. edsl/questions/QuestionMultipleChoice.py +293 -69
  161. edsl/questions/QuestionNumerical.py +109 -56
  162. edsl/questions/QuestionRank.py +244 -49
  163. edsl/questions/Quick.py +41 -0
  164. edsl/questions/SimpleAskMixin.py +74 -0
  165. edsl/questions/__init__.py +9 -6
  166. edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +153 -38
  167. edsl/questions/compose_questions.py +13 -7
  168. edsl/questions/data_structures.py +20 -0
  169. edsl/questions/decorators.py +21 -0
  170. edsl/questions/derived/QuestionLikertFive.py +28 -26
  171. edsl/questions/derived/QuestionLinearScale.py +41 -28
  172. edsl/questions/derived/QuestionTopK.py +34 -26
  173. edsl/questions/derived/QuestionYesNo.py +40 -27
  174. edsl/questions/descriptors.py +228 -74
  175. edsl/questions/loop_processor.py +149 -0
  176. edsl/questions/prompt_templates/question_budget.jinja +13 -0
  177. edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
  178. edsl/questions/prompt_templates/question_extract.jinja +11 -0
  179. edsl/questions/prompt_templates/question_free_text.jinja +3 -0
  180. edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
  181. edsl/questions/prompt_templates/question_list.jinja +17 -0
  182. edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
  183. edsl/questions/prompt_templates/question_numerical.jinja +37 -0
  184. edsl/questions/question_base_gen_mixin.py +168 -0
  185. edsl/questions/question_registry.py +130 -46
  186. edsl/questions/register_questions_meta.py +71 -0
  187. edsl/questions/response_validator_abc.py +188 -0
  188. edsl/questions/response_validator_factory.py +34 -0
  189. edsl/questions/settings.py +5 -2
  190. edsl/questions/templates/__init__.py +0 -0
  191. edsl/questions/templates/budget/__init__.py +0 -0
  192. edsl/questions/templates/budget/answering_instructions.jinja +7 -0
  193. edsl/questions/templates/budget/question_presentation.jinja +7 -0
  194. edsl/questions/templates/checkbox/__init__.py +0 -0
  195. edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
  196. edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
  197. edsl/questions/templates/dict/__init__.py +0 -0
  198. edsl/questions/templates/dict/answering_instructions.jinja +21 -0
  199. edsl/questions/templates/dict/question_presentation.jinja +1 -0
  200. edsl/questions/templates/extract/__init__.py +0 -0
  201. edsl/questions/templates/extract/answering_instructions.jinja +7 -0
  202. edsl/questions/templates/extract/question_presentation.jinja +1 -0
  203. edsl/questions/templates/free_text/__init__.py +0 -0
  204. edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
  205. edsl/questions/templates/free_text/question_presentation.jinja +1 -0
  206. edsl/questions/templates/likert_five/__init__.py +0 -0
  207. edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
  208. edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
  209. edsl/questions/templates/linear_scale/__init__.py +0 -0
  210. edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
  211. edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
  212. edsl/questions/templates/list/__init__.py +0 -0
  213. edsl/questions/templates/list/answering_instructions.jinja +4 -0
  214. edsl/questions/templates/list/question_presentation.jinja +5 -0
  215. edsl/questions/templates/matrix/__init__.py +1 -0
  216. edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
  217. edsl/questions/templates/matrix/question_presentation.jinja +20 -0
  218. edsl/questions/templates/multiple_choice/__init__.py +0 -0
  219. edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
  220. edsl/questions/templates/multiple_choice/html.jinja +0 -0
  221. edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
  222. edsl/questions/templates/numerical/__init__.py +0 -0
  223. edsl/questions/templates/numerical/answering_instructions.jinja +7 -0
  224. edsl/questions/templates/numerical/question_presentation.jinja +7 -0
  225. edsl/questions/templates/rank/__init__.py +0 -0
  226. edsl/questions/templates/rank/answering_instructions.jinja +11 -0
  227. edsl/questions/templates/rank/question_presentation.jinja +15 -0
  228. edsl/questions/templates/top_k/__init__.py +0 -0
  229. edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
  230. edsl/questions/templates/top_k/question_presentation.jinja +22 -0
  231. edsl/questions/templates/yes_no/__init__.py +0 -0
  232. edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
  233. edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
  234. edsl/results/CSSParameterizer.py +108 -0
  235. edsl/results/Dataset.py +550 -19
  236. edsl/results/DatasetExportMixin.py +594 -0
  237. edsl/results/DatasetTree.py +295 -0
  238. edsl/results/MarkdownToDocx.py +122 -0
  239. edsl/results/MarkdownToPDF.py +111 -0
  240. edsl/results/Result.py +477 -173
  241. edsl/results/Results.py +987 -269
  242. edsl/results/ResultsExportMixin.py +28 -125
  243. edsl/results/ResultsGGMixin.py +83 -15
  244. edsl/results/TableDisplay.py +125 -0
  245. edsl/results/TextEditor.py +50 -0
  246. edsl/results/__init__.py +1 -1
  247. edsl/results/file_exports.py +252 -0
  248. edsl/results/results_fetch_mixin.py +33 -0
  249. edsl/results/results_selector.py +145 -0
  250. edsl/results/results_tools_mixin.py +98 -0
  251. edsl/results/smart_objects.py +96 -0
  252. edsl/results/table_data_class.py +12 -0
  253. edsl/results/table_display.css +78 -0
  254. edsl/results/table_renderers.py +118 -0
  255. edsl/results/tree_explore.py +115 -0
  256. edsl/scenarios/ConstructDownloadLink.py +109 -0
  257. edsl/scenarios/DocumentChunker.py +102 -0
  258. edsl/scenarios/DocxScenario.py +16 -0
  259. edsl/scenarios/FileStore.py +543 -0
  260. edsl/scenarios/PdfExtractor.py +40 -0
  261. edsl/scenarios/Scenario.py +431 -62
  262. edsl/scenarios/ScenarioHtmlMixin.py +65 -0
  263. edsl/scenarios/ScenarioList.py +1415 -45
  264. edsl/scenarios/ScenarioListExportMixin.py +45 -0
  265. edsl/scenarios/ScenarioListPdfMixin.py +239 -0
  266. edsl/scenarios/__init__.py +2 -0
  267. edsl/scenarios/directory_scanner.py +96 -0
  268. edsl/scenarios/file_methods.py +85 -0
  269. edsl/scenarios/handlers/__init__.py +13 -0
  270. edsl/scenarios/handlers/csv.py +49 -0
  271. edsl/scenarios/handlers/docx.py +76 -0
  272. edsl/scenarios/handlers/html.py +37 -0
  273. edsl/scenarios/handlers/json.py +111 -0
  274. edsl/scenarios/handlers/latex.py +5 -0
  275. edsl/scenarios/handlers/md.py +51 -0
  276. edsl/scenarios/handlers/pdf.py +68 -0
  277. edsl/scenarios/handlers/png.py +39 -0
  278. edsl/scenarios/handlers/pptx.py +105 -0
  279. edsl/scenarios/handlers/py.py +294 -0
  280. edsl/scenarios/handlers/sql.py +313 -0
  281. edsl/scenarios/handlers/sqlite.py +149 -0
  282. edsl/scenarios/handlers/txt.py +33 -0
  283. edsl/scenarios/scenario_join.py +131 -0
  284. edsl/scenarios/scenario_selector.py +156 -0
  285. edsl/shared.py +1 -0
  286. edsl/study/ObjectEntry.py +173 -0
  287. edsl/study/ProofOfWork.py +113 -0
  288. edsl/study/SnapShot.py +80 -0
  289. edsl/study/Study.py +521 -0
  290. edsl/study/__init__.py +4 -0
  291. edsl/surveys/ConstructDAG.py +92 -0
  292. edsl/surveys/DAG.py +92 -11
  293. edsl/surveys/EditSurvey.py +221 -0
  294. edsl/surveys/InstructionHandler.py +100 -0
  295. edsl/surveys/Memory.py +9 -4
  296. edsl/surveys/MemoryManagement.py +72 -0
  297. edsl/surveys/MemoryPlan.py +156 -35
  298. edsl/surveys/Rule.py +221 -74
  299. edsl/surveys/RuleCollection.py +241 -61
  300. edsl/surveys/RuleManager.py +172 -0
  301. edsl/surveys/Simulator.py +75 -0
  302. edsl/surveys/Survey.py +1079 -339
  303. edsl/surveys/SurveyCSS.py +273 -0
  304. edsl/surveys/SurveyExportMixin.py +235 -40
  305. edsl/surveys/SurveyFlowVisualization.py +181 -0
  306. edsl/surveys/SurveyQualtricsImport.py +284 -0
  307. edsl/surveys/SurveyToApp.py +141 -0
  308. edsl/surveys/__init__.py +4 -2
  309. edsl/surveys/base.py +19 -3
  310. edsl/surveys/descriptors.py +17 -6
  311. edsl/surveys/instructions/ChangeInstruction.py +48 -0
  312. edsl/surveys/instructions/Instruction.py +56 -0
  313. edsl/surveys/instructions/InstructionCollection.py +82 -0
  314. edsl/surveys/instructions/__init__.py +0 -0
  315. edsl/templates/error_reporting/base.html +24 -0
  316. edsl/templates/error_reporting/exceptions_by_model.html +35 -0
  317. edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
  318. edsl/templates/error_reporting/exceptions_by_type.html +17 -0
  319. edsl/templates/error_reporting/interview_details.html +116 -0
  320. edsl/templates/error_reporting/interviews.html +19 -0
  321. edsl/templates/error_reporting/overview.html +5 -0
  322. edsl/templates/error_reporting/performance_plot.html +2 -0
  323. edsl/templates/error_reporting/report.css +74 -0
  324. edsl/templates/error_reporting/report.html +118 -0
  325. edsl/templates/error_reporting/report.js +25 -0
  326. edsl/tools/__init__.py +1 -0
  327. edsl/tools/clusters.py +192 -0
  328. edsl/tools/embeddings.py +27 -0
  329. edsl/tools/embeddings_plotting.py +118 -0
  330. edsl/tools/plotting.py +112 -0
  331. edsl/tools/summarize.py +18 -0
  332. edsl/utilities/PrettyList.py +56 -0
  333. edsl/utilities/SystemInfo.py +5 -0
  334. edsl/utilities/__init__.py +21 -20
  335. edsl/utilities/ast_utilities.py +3 -0
  336. edsl/utilities/data/Registry.py +2 -0
  337. edsl/utilities/decorators.py +41 -0
  338. edsl/utilities/gcp_bucket/__init__.py +0 -0
  339. edsl/utilities/gcp_bucket/cloud_storage.py +96 -0
  340. edsl/utilities/interface.py +310 -60
  341. edsl/utilities/is_notebook.py +18 -0
  342. edsl/utilities/is_valid_variable_name.py +11 -0
  343. edsl/utilities/naming_utilities.py +263 -0
  344. edsl/utilities/remove_edsl_version.py +24 -0
  345. edsl/utilities/repair_functions.py +28 -0
  346. edsl/utilities/restricted_python.py +70 -0
  347. edsl/utilities/utilities.py +203 -13
  348. edsl-0.1.40.dist-info/METADATA +111 -0
  349. edsl-0.1.40.dist-info/RECORD +362 -0
  350. {edsl-0.1.15.dist-info → edsl-0.1.40.dist-info}/WHEEL +1 -1
  351. edsl/agents/AgentListExportMixin.py +0 -24
  352. edsl/coop/old.py +0 -31
  353. edsl/data/Database.py +0 -141
  354. edsl/data/crud.py +0 -121
  355. edsl/jobs/Interview.py +0 -435
  356. edsl/jobs/JobsRunner.py +0 -63
  357. edsl/jobs/JobsRunnerStatusMixin.py +0 -115
  358. edsl/jobs/base.py +0 -47
  359. edsl/jobs/buckets.py +0 -178
  360. edsl/jobs/runners/JobsRunnerDryRun.py +0 -19
  361. edsl/jobs/runners/JobsRunnerStreaming.py +0 -54
  362. edsl/jobs/task_management.py +0 -215
  363. edsl/jobs/token_tracking.py +0 -78
  364. edsl/language_models/DeepInfra.py +0 -69
  365. edsl/language_models/OpenAI.py +0 -98
  366. edsl/language_models/model_interfaces/GeminiPro.py +0 -66
  367. edsl/language_models/model_interfaces/LanguageModelOpenAIFour.py +0 -8
  368. edsl/language_models/model_interfaces/LanguageModelOpenAIThreeFiveTurbo.py +0 -8
  369. edsl/language_models/model_interfaces/LlamaTwo13B.py +0 -21
  370. edsl/language_models/model_interfaces/LlamaTwo70B.py +0 -21
  371. edsl/language_models/model_interfaces/Mixtral8x7B.py +0 -24
  372. edsl/language_models/registry.py +0 -81
  373. edsl/language_models/schemas.py +0 -15
  374. edsl/language_models/unused/ReplicateBase.py +0 -83
  375. edsl/prompts/QuestionInstructionsBase.py +0 -6
  376. edsl/prompts/library/agent_instructions.py +0 -29
  377. edsl/prompts/library/agent_persona.py +0 -17
  378. edsl/prompts/library/question_budget.py +0 -26
  379. edsl/prompts/library/question_checkbox.py +0 -32
  380. edsl/prompts/library/question_extract.py +0 -19
  381. edsl/prompts/library/question_freetext.py +0 -14
  382. edsl/prompts/library/question_linear_scale.py +0 -20
  383. edsl/prompts/library/question_list.py +0 -22
  384. edsl/prompts/library/question_multiple_choice.py +0 -44
  385. edsl/prompts/library/question_numerical.py +0 -31
  386. edsl/prompts/library/question_rank.py +0 -21
  387. edsl/prompts/prompt_config.py +0 -33
  388. edsl/prompts/registry.py +0 -185
  389. edsl/questions/Question.py +0 -240
  390. edsl/report/InputOutputDataTypes.py +0 -134
  391. edsl/report/RegressionMixin.py +0 -28
  392. edsl/report/ReportOutputs.py +0 -1228
  393. edsl/report/ResultsFetchMixin.py +0 -106
  394. edsl/report/ResultsOutputMixin.py +0 -14
  395. edsl/report/demo.ipynb +0 -645
  396. edsl/results/ResultsDBMixin.py +0 -184
  397. edsl/surveys/SurveyFlowVisualizationMixin.py +0 -92
  398. edsl/trackers/Tracker.py +0 -91
  399. edsl/trackers/TrackerAPI.py +0 -196
  400. edsl/trackers/TrackerTasks.py +0 -70
  401. edsl/utilities/pastebin.py +0 -141
  402. edsl-0.1.15.dist-info/METADATA +0 -69
  403. edsl-0.1.15.dist-info/RECORD +0 -142
  404. /edsl/{language_models/model_interfaces → inference_services}/__init__.py +0 -0
  405. /edsl/{report/__init__.py → jobs/runners/JobsRunnerStatusData.py} +0 -0
  406. /edsl/{trackers/__init__.py → language_models/ServiceDataSources.py} +0 -0
  407. {edsl-0.1.15.dist-info → edsl-0.1.40.dist-info}/LICENSE +0 -0
edsl/data/crud.py DELETED
@@ -1,121 +0,0 @@
1
- from sqlalchemy import desc
2
- from typing import Union
3
- from edsl.data import Database, database, LLMOutputDataDB
4
- from edsl.data.orm import ResultDB
5
-
6
-
7
- class CRUDOperations:
8
- """
9
- A class that implementes CRUD operations for the EDSL package.
10
-
11
- Initalization:
12
- - `database`: A Database object.
13
-
14
- Methods:
15
- - `get_LLMOutputData(model, parameters, system_prompt, prompt)`: Retrieves a cached LLM output from the database.
16
- - `write_LLMOutputData(model, parameters, system_prompt, prompt, output)`: Writes an LLM output to the database.
17
- """
18
-
19
- def __init__(self, database: Database) -> None:
20
- self.database = database
21
-
22
- def get_LLMOutputData(
23
- self, model: str, parameters: str, system_prompt: str, prompt: str
24
- ) -> Union[str, None]:
25
- """
26
- Retrieves a cached LLM output from the database. Arguments: in string format, the model, parameters, system_prompt, and prompt used to generate the output. Returns the output (json string) if it exists, otherwise None.
27
- """
28
- with self.database.get_db() as db:
29
- record = (
30
- db.query(LLMOutputDataDB)
31
- .filter_by(
32
- prompt=prompt,
33
- system_prompt=system_prompt,
34
- model=model,
35
- parameters=parameters,
36
- )
37
- .order_by(desc(LLMOutputDataDB.id))
38
- .first()
39
- )
40
- return record.output if record else None
41
-
42
- def write_LLMOutputData(
43
- self, model: str, parameters: str, system_prompt: str, prompt: str, output: str
44
- ) -> None:
45
- """
46
- Writes an LLM output to the database. Arguments: in string format, the model, parameters, system_prompt, prompt, and the generated output.
47
- """
48
- record = LLMOutputDataDB(
49
- model=model,
50
- parameters=parameters,
51
- system_prompt=system_prompt,
52
- prompt=prompt,
53
- output=output,
54
- )
55
-
56
- with self.database.get_db() as db:
57
- db.add(record)
58
- db.commit()
59
-
60
- def clear_LLMOutputData(self) -> None:
61
- """
62
- Clears all LLM output data from the database.
63
- """
64
- with self.database.get_db() as db:
65
- db.query(LLMOutputDataDB).delete()
66
- db.commit()
67
-
68
- def get_all_LLMOutputData(self) -> list:
69
- """
70
- Retrieves all LLM output data from the database and returns them as a list of dictionaries.
71
- """
72
- with self.database.get_db() as db:
73
- records = db.query(LLMOutputDataDB).all()
74
- return [
75
- {
76
- "id": record.id,
77
- "model": record.model,
78
- "parameters": record.parameters,
79
- "system_prompt": record.system_prompt,
80
- "prompt": record.prompt,
81
- "output": record.output,
82
- }
83
- for record in records
84
- ]
85
-
86
- def write_result(
87
- self,
88
- job_uuid: str,
89
- result_uuid: str,
90
- agent: str,
91
- scenario: str,
92
- model: str,
93
- answer: str,
94
- ) -> None:
95
- """Writes a Result record to the database."""
96
- record = ResultDB(
97
- job_uuid=job_uuid,
98
- result_uuid=result_uuid,
99
- agent=agent,
100
- scenario=scenario,
101
- model=model,
102
- answer=answer,
103
- )
104
-
105
- with self.database.get_db() as db:
106
- db.add(record)
107
- db.commit()
108
-
109
- def read_results(self, job_uuid: str) -> list[ResultDB]:
110
- """Reads all Result records associated with job_uuid from the database."""
111
- with self.database.get_db() as db:
112
- records = (
113
- db.query(ResultDB)
114
- .filter_by(job_uuid=job_uuid)
115
- .order_by(desc(ResultDB.id))
116
- .all()
117
- )
118
- return records
119
-
120
-
121
- CRUD = CRUDOperations(database)
edsl/jobs/Interview.py DELETED
@@ -1,435 +0,0 @@
1
- from __future__ import annotations
2
- import traceback
3
- import asyncio
4
- import logging
5
- import textwrap
6
- from collections import UserList
7
- from typing import Any, Type, List, Generator, Callable, List, Tuple
8
- from collections import defaultdict
9
-
10
- # from tenacity import retry, wait_exponential, stop_after_attempt, retry_if_exception_type, AsyncRetrying, before_sleep
11
- from tenacity import (
12
- retry,
13
- wait_exponential,
14
- stop_after_attempt,
15
- retry_if_exception_type,
16
- before_sleep,
17
- )
18
-
19
-
20
- from edsl import CONFIG
21
- from edsl.agents import Agent
22
- from edsl.exceptions import InterviewErrorPriorTaskCanceled, InterviewTimeoutError
23
- from edsl.language_models import LanguageModel
24
- from edsl.questions import Question
25
- from edsl.scenarios import Scenario
26
- from edsl.surveys import Survey
27
- from edsl.utilities.decorators import sync_wrapper
28
- from edsl.data_transfer_models import AgentResponseDict
29
- from edsl.jobs.Answers import Answers
30
-
31
- from edsl.surveys.base import EndOfSurvey
32
-
33
- from edsl.jobs.buckets import ModelBuckets
34
- from edsl.jobs.token_tracking import TokenUsage, InterviewTokenUsage
35
-
36
- from edsl.jobs.task_management import (
37
- InterviewStatusDictionary,
38
- QuestionTaskCreator,
39
- TasksList,
40
- )
41
-
42
-
43
- # create logger
44
- logger = logging.getLogger(__name__)
45
- logger.setLevel(logging.INFO)
46
- logger.propagate = False
47
- # create file handler
48
- fh = logging.FileHandler(CONFIG.get("EDSL_LOGGING_PATH"))
49
- fh.setLevel(logging.INFO)
50
- # add formatter to the handlers
51
- formatter = logging.Formatter(
52
- "%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(funcName)s - %(message)s"
53
- )
54
- fh.setFormatter(formatter)
55
- # add handler to logger
56
- logger.addHandler(fh)
57
-
58
- # start loggin'
59
- logger.info("Interview.py loaded")
60
-
61
- TIMEOUT = float(CONFIG.get("EDSL_API_TIMEOUT"))
62
- EDSL_BACKOFF_START_SEC = float(CONFIG.get("EDSL_BACKOFF_START_SEC"))
63
- EDSL_MAX_BACKOFF_SEC = float(CONFIG.get("EDSL_MAX_BACKOFF_SEC"))
64
- EDSL_MAX_ATTEMPTS = int(CONFIG.get("EDSL_MAX_ATTEMPTS"))
65
-
66
-
67
- def print_retry(retry_state):
68
- "Prints details on tenacity retries"
69
- attempt_number = retry_state.attempt_number
70
- exception = retry_state.outcome.exception()
71
- wait_time = retry_state.next_action.sleep
72
- print(
73
- f"Attempt {attempt_number} failed with exception: {exception}; "
74
- f"now waiting {wait_time:.2f} seconds before retrying."
75
- )
76
-
77
-
78
- retry_strategy = retry(
79
- wait=wait_exponential(
80
- multiplier=EDSL_BACKOFF_START_SEC, max=EDSL_MAX_BACKOFF_SEC
81
- ), # Exponential back-off starting at 1s, doubling, maxing out at 60s
82
- stop=stop_after_attempt(EDSL_MAX_ATTEMPTS), # Stop after 5 attempts
83
- # retry=retry_if_exception_type(Exception), # Customize this as per your specific retry-able exception
84
- before_sleep=print_retry, # Use custom print function for retries
85
- )
86
-
87
- retry_strategy = retry(
88
- wait=wait_exponential(
89
- multiplier=1, max=60
90
- ), # Exponential back-off starting at 1s, doubling, maxing out at 60s
91
- stop=stop_after_attempt(5), # Stop after 5 attempts
92
- # retry=retry_if_exception_type(Exception), # Customize this as per your specific retry-able exception
93
- before_sleep=print_retry, # Use custom print function for retries
94
- )
95
-
96
-
97
- class Interview:
98
- """
99
- An 'interview' is one agent answering one survey, with one language model, for a given scenario.
100
- """
101
-
102
- def __init__(
103
- self,
104
- agent: Agent,
105
- survey: Survey,
106
- scenario: Scenario,
107
- model: Type[LanguageModel],
108
- verbose: bool = False,
109
- debug: bool = False,
110
- ):
111
- self.agent = agent
112
- self.survey = survey
113
- self.scenario = scenario
114
- self.model = model
115
- self.debug = debug
116
- self.verbose = verbose
117
- self.answers: dict[str, str] = Answers() # will get filled in
118
-
119
- # The DAG, or directed acyclic graph, is a dictionary that maps question names to their dependencies.
120
- # It is used to determine the order in which questions should be answered.
121
- # This reflects both agent 'memory' considerations and 'skip' logic.
122
- self.dag = self.survey.dag(textify=True)
123
- self.to_index = {
124
- name: index for index, name in enumerate(self.survey.question_names)
125
- }
126
-
127
- logger.info(f"Interview instantiated")
128
- # task creators is a dictionary that maps question names to their task creators.
129
- # this is used to track the status of each task for real-time reporting on status of a job
130
- # being executed.
131
- # 1 task = 1 question.
132
- self.task_creators = {}
133
-
134
- @property
135
- def token_usage(self) -> InterviewTokenUsage:
136
- "Determins how many tokens were used for the interview."
137
- cached_tokens = TokenUsage(from_cache=True)
138
- new_tokens = TokenUsage(from_cache=False)
139
- for task_creator in self.task_creators.values():
140
- token_usage = task_creator.token_usage()
141
- cached_tokens += token_usage["cached_tokens"]
142
- new_tokens += token_usage["new_tokens"]
143
- return InterviewTokenUsage(
144
- new_token_usage=new_tokens, cached_token_usage=cached_tokens
145
- )
146
-
147
- @property
148
- def interview_status(self) -> InterviewStatusDictionary:
149
- """Returns a dictionary mapping task status codes to counts"""
150
- status_dict = InterviewStatusDictionary()
151
- for task_creator in self.task_creators.values():
152
- status_dict[task_creator.task_status] += 1
153
- status_dict["number_from_cache"] += task_creator.from_cache
154
- return status_dict
155
-
156
- async def async_conduct_interview(
157
- self,
158
- model_buckets: ModelBuckets = None,
159
- debug: bool = False,
160
- replace_missing: bool = True,
161
- ) -> tuple["Answers", List[dict[str, Any]]]:
162
- """
163
- Conducts an interview asynchronously.
164
- params
165
- - `model_buckets`: a dictionary of token buckets for the model
166
- - `debug`: prints debug messages
167
- - `replace_missing`: if True, replaces missing answers with None
168
- """
169
- # if no model bucket is passed, create an 'infinity' bucket with no rate limits
170
- model_buckets = model_buckets or ModelBuckets.infinity_bucket()
171
-
172
- # we create both tasks and invigilators lists.
173
- # this is because it's easier to extract info
174
- # we need from the invigilators list when a task fails.
175
- # it's challenging to get info from failed asyncio tasks.
176
- self.tasks, self.invigilators = self._build_question_tasks(
177
- debug=debug, model_buckets=model_buckets
178
- )
179
-
180
- await asyncio.gather(*self.tasks, return_exceptions=not debug)
181
-
182
- if replace_missing:
183
- self.answers.replace_missing_answers_with_none(self.survey)
184
-
185
- valid_results = list(self._extract_valid_results())
186
-
187
- return self.answers, valid_results
188
-
189
- def _extract_valid_results(
190
- self, print_traceback=False
191
- ) -> Generator["Answers", None, None]:
192
- """Extracts the valid results from the list of results."""
193
-
194
- # we only need to print the warning once if a task failed.
195
- warning_printed = False
196
- warning_header = textwrap.dedent(
197
- """\
198
- WARNING: At least one question in the survey was not answered.
199
- """
200
- )
201
- # there should be one one invigilator for each task
202
- assert len(self.tasks) == len(self.invigilators)
203
-
204
- for task, invigilator in zip(self.tasks, self.invigilators):
205
- logger.info(f"Iterating through task: {task}")
206
- if task.done():
207
- try:
208
- # it worked!
209
- result = task.result()
210
- except asyncio.CancelledError:
211
- # task was cancelled
212
- logger.info(f"Task `{task.edsl_name}` was cancelled.")
213
- result = invigilator.get_failed_task_result()
214
- except Exception as exception:
215
- # any other kind of exception in the task
216
- if not warning_printed:
217
- warning_printed = True
218
- print(warning_header)
219
-
220
- error_message = f"Task `{task.edsl_name}` failed with `{exception.__class__.__name__}`:`{exception}`."
221
- logger.error(error_message)
222
- print(error_message)
223
- if print_traceback:
224
- traceback.print_exc()
225
- result = invigilator.get_failed_task_result()
226
- else:
227
- # No exception means the task completed successfully
228
- pass
229
-
230
- yield result
231
-
232
- def _build_question_tasks(
233
- self, debug: bool, model_buckets: ModelBuckets
234
- ) -> Tuple[List[asyncio.Task], List["Invigilators"]]:
235
- """Creates a task for each question, with dependencies on the questions that must be answered before this one can be answered."""
236
- logger.info("Creating tasks for each question")
237
- tasks = []
238
- invigilators = []
239
- for question in self.survey.questions:
240
- # finds dependency tasks for that question
241
- tasks_that_must_be_completed_before = (
242
- self._get_tasks_that_must_be_completed_before(tasks, question)
243
- )
244
- # creates the task for that question
245
- question_task = self._create_question_task(
246
- question=question,
247
- tasks_that_must_be_completed_before=tasks_that_must_be_completed_before,
248
- model_buckets=model_buckets,
249
- debug=debug,
250
- )
251
- # adds the task to the list of tasks
252
- tasks.append(question_task)
253
- invigilators.append(self.get_invigilator(question, debug))
254
- return TasksList(tasks), invigilators
255
-
256
- def _get_tasks_that_must_be_completed_before(
257
- self, tasks, question
258
- ) -> List[asyncio.Task]:
259
- """Returns the tasks that must be completed before the given question can be answered.
260
- If a question has no dependencies, this will be an empty list, [].
261
- """
262
- parents_of_focal_question: List[str] = self.dag.get(question.question_name, [])
263
- return [
264
- tasks[self.to_index[parent_question_name]]
265
- for parent_question_name in parents_of_focal_question
266
- ]
267
-
268
- def _create_question_task(
269
- self,
270
- question: Question,
271
- tasks_that_must_be_completed_before: List[asyncio.Task],
272
- model_buckets: ModelBuckets,
273
- debug,
274
- ):
275
- """Creates a task that depends on the passed-in dependencies that are awaited before the task is run."""
276
- task_creator = QuestionTaskCreator(
277
- question=question,
278
- answer_question_func=self._answer_question_and_record_task,
279
- token_estimator=self._get_estimated_request_tokens,
280
- model_buckets=model_buckets,
281
- )
282
- [task_creator.add_dependency(x) for x in tasks_that_must_be_completed_before]
283
- self.task_creators[question.question_name] = task_creator
284
- return task_creator.generate_task(debug)
285
-
286
- def async_timeout_handler(timeout):
287
- def decorator(func):
288
- async def wrapper(*args, **kwargs):
289
- try:
290
- return await asyncio.wait_for(func(*args, **kwargs), timeout)
291
- except asyncio.TimeoutError:
292
- raise InterviewTimeoutError(
293
- f"Task timed out after {timeout} seconds."
294
- )
295
-
296
- return wrapper
297
-
298
- return decorator
299
-
300
- def get_invigilator(self, question, debug) -> "Invigilator":
301
- invigilator = self.agent.create_invigilator(
302
- question=question,
303
- scenario=self.scenario,
304
- model=self.model,
305
- debug=debug,
306
- memory_plan=self.survey.memory_plan,
307
- current_answers=self.answers,
308
- )
309
- return invigilator
310
-
311
- def _get_estimated_request_tokens(self, question) -> float:
312
- """Estimates the number of tokens that will be required to run the focal task."""
313
- invigilator = self.get_invigilator(question, debug=False)
314
- # TODO: There should be a way to get a more accurate estimate.
315
- combined_text = ""
316
- for prompt in invigilator.get_prompts().values():
317
- if hasattr(prompt, "text"):
318
- combined_text += prompt.text
319
- elif isinstance(prompt, str):
320
- combined_text += prompt
321
- else:
322
- raise ValueError(f"Prompt is of type {type(prompt)}")
323
- return len(combined_text) / 4.0
324
-
325
- @async_timeout_handler(TIMEOUT)
326
- async def _answer_question_and_record_task(
327
- self,
328
- question: Question,
329
- debug: bool,
330
- ) -> AgentResponseDict:
331
- """Answers a question and records the task.
332
- This in turn calls the the passed-in agent's async_answer_question method, which returns a response dictionary.
333
- """
334
- invigilator = self.get_invigilator(question, debug=debug)
335
-
336
- @retry_strategy
337
- async def attempt_to_answer_question():
338
- return await invigilator.async_answer_question()
339
-
340
- response: AgentResponseDict = await attempt_to_answer_question()
341
-
342
- # TODO: Move this back into actual agent response dict and enforce it.
343
- response["question_name"] = question.question_name
344
-
345
- self.answers.add_answer(response, question)
346
-
347
- self._cancel_skipped_questions(question)
348
-
349
- # TODO: This should be forced to be a data-exchange model to cement attributes.
350
- return response
351
-
352
- def _cancel_skipped_questions(self, current_question) -> None:
353
- """Cancels the tasks for questions that are skipped."""
354
- logger.info(f"Current question is {current_question.question_name}")
355
- current_question_index = self.to_index[current_question.question_name]
356
- next_question = self.survey.rule_collection.next_question(
357
- q_now=current_question_index, answers=self.answers
358
- )
359
- next_question_index = next_question.next_q
360
-
361
- def cancel_between(start, end):
362
- for i in range(start, end):
363
- logger.info(
364
- f"Cancelling task for question {i}; {self.tasks[i].edsl_name}"
365
- )
366
- self.tasks[i].cancel()
367
- skipped_question_name = self.survey.question_names[i]
368
- logger.info(f"{skipped_question_name} skipped.")
369
-
370
- if next_question_index == EndOfSurvey:
371
- cancel_between(current_question_index + 1, len(self.survey.questions))
372
- return
373
-
374
- if next_question_index > (current_question_index + 1):
375
- cancel_between(current_question_index + 1, next_question_index)
376
-
377
- self.tasks.status()
378
-
379
- #######################
380
- # Dunder methods
381
- #######################
382
- def __repr__(self) -> str:
383
- """Returns a string representation of the Interview instance."""
384
- return f"Interview(agent = {self.agent}, survey = {self.survey}, scenario = {self.scenario}, model = {self.model})"
385
-
386
-
387
- if __name__ == "__main__":
388
- from edsl.language_models import LanguageModelOpenAIThreeFiveTurbo
389
- from edsl.agents import Agent
390
- from edsl.surveys import Survey
391
- from edsl.scenarios import Scenario
392
- from edsl.questions import QuestionMultipleChoice
393
-
394
- # from edsl.jobs.Interview import Interview
395
-
396
- # a survey with skip logic
397
- q0 = QuestionMultipleChoice(
398
- question_text="Do you like school?",
399
- question_options=["yes", "no"],
400
- question_name="q0",
401
- )
402
- q1 = QuestionMultipleChoice(
403
- question_text="Why not?",
404
- question_options=["killer bees in cafeteria", "other"],
405
- question_name="q1",
406
- )
407
- q2 = QuestionMultipleChoice(
408
- question_text="Why?",
409
- question_options=["**lack*** of killer bees in cafeteria", "other"],
410
- question_name="q2",
411
- )
412
- s = Survey(questions=[q0, q1, q2])
413
- s = s.add_rule(q0, "q0 == 'yes'", q2)
414
-
415
- # create an interview
416
- a = Agent(traits=None)
417
-
418
- def direct_question_answering_method(self, question, scenario):
419
- raise Exception("Fuck you!")
420
- # return "yes"
421
-
422
- a.add_direct_question_answering_method(direct_question_answering_method)
423
- scenario = Scenario()
424
- m = LanguageModelOpenAIThreeFiveTurbo(use_cache=False)
425
- I = Interview(agent=a, survey=s, scenario=scenario, model=m)
426
-
427
- result = asyncio.run(I.async_conduct_interview())
428
- # # conduct five interviews
429
- # for _ in range(5):
430
- # I.conduct_interview(debug=True)
431
-
432
- # # replace missing answers
433
- # I
434
- # repr(I)
435
- # eval(repr(I))
edsl/jobs/JobsRunner.py DELETED
@@ -1,63 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections import UserDict
4
-
5
- from abc import ABC, ABCMeta, abstractmethod
6
- from edsl.jobs import Jobs
7
- from edsl.results import Results
8
-
9
-
10
- class RegisterJobsRunnerMeta(ABCMeta):
11
- "Metaclass to register output elements in a registry i.e., those that have a parent"
12
- _registry = {} # Initialize the registry as a dictionary
13
-
14
- def __init__(cls, name, bases, dct):
15
- super(RegisterJobsRunnerMeta, cls).__init__(name, bases, dct)
16
- if name != "JobsRunner":
17
- RegisterJobsRunnerMeta._registry[name] = cls
18
-
19
- @classmethod
20
- def get_registered_classes(cls):
21
- return cls._registry
22
-
23
- @classmethod
24
- def lookup(cls):
25
- d = {}
26
- for classname, cls in cls._registry.items():
27
- if hasattr(cls, "runner_name"):
28
- d[cls.runner_name] = cls
29
- else:
30
- raise Exception(
31
- f"Class {classname} does not have a runner_name attribute"
32
- )
33
- return d
34
-
35
-
36
- class JobsRunner(ABC, metaclass=RegisterJobsRunnerMeta):
37
- """ABC for JobRunners, which take in a job, conduct interviews, and return their results."""
38
-
39
- def __init__(self, jobs: Jobs):
40
- self.jobs = jobs
41
- # create the interviews here so children can use them
42
- self.interviews = jobs.interviews()
43
- self.bucket_collection = jobs.bucket_collection
44
- # self.bucket_collection = self.jobs.bucket_collection
45
- # for model in self.jobs.models:
46
- # self.bucket_collection.add_model(model)
47
-
48
- @abstractmethod
49
- def run(
50
- self,
51
- n: int = 1,
52
- debug: bool = False,
53
- verbose: bool = False,
54
- progress_bar: bool = True,
55
- ) -> Results: # pragma: no cover
56
- """
57
- Runs the job: conducts Interviews and returns their results.
58
- - `n`: how many times to run each interview
59
- - `debug`: prints debug messages
60
- - `verbose`: prints messages
61
- - `progress_bar`: shows a progress bar
62
- """
63
- raise NotImplementedError