edsl 0.1.46__py3-none-any.whl → 0.1.48__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 (328) hide show
  1. edsl/__init__.py +44 -39
  2. edsl/__version__.py +1 -1
  3. edsl/agents/__init__.py +4 -2
  4. edsl/agents/{Agent.py → agent.py} +442 -152
  5. edsl/agents/{AgentList.py → agent_list.py} +220 -162
  6. edsl/agents/descriptors.py +46 -7
  7. edsl/{exceptions/agents.py → agents/exceptions.py} +3 -12
  8. edsl/base/__init__.py +75 -0
  9. edsl/base/base_class.py +1303 -0
  10. edsl/base/data_transfer_models.py +114 -0
  11. edsl/base/enums.py +215 -0
  12. edsl/base.py +8 -0
  13. edsl/buckets/__init__.py +25 -0
  14. edsl/buckets/bucket_collection.py +324 -0
  15. edsl/buckets/model_buckets.py +206 -0
  16. edsl/buckets/token_bucket.py +502 -0
  17. edsl/{jobs/buckets/TokenBucketAPI.py → buckets/token_bucket_api.py} +1 -1
  18. edsl/buckets/token_bucket_client.py +509 -0
  19. edsl/caching/__init__.py +20 -0
  20. edsl/caching/cache.py +814 -0
  21. edsl/caching/cache_entry.py +427 -0
  22. edsl/{data/CacheHandler.py → caching/cache_handler.py} +14 -15
  23. edsl/caching/exceptions.py +24 -0
  24. edsl/caching/orm.py +30 -0
  25. edsl/{data/RemoteCacheSync.py → caching/remote_cache_sync.py} +3 -3
  26. edsl/caching/sql_dict.py +441 -0
  27. edsl/config/__init__.py +8 -0
  28. edsl/config/config_class.py +177 -0
  29. edsl/config.py +4 -176
  30. edsl/conversation/Conversation.py +7 -7
  31. edsl/conversation/car_buying.py +4 -4
  32. edsl/conversation/chips.py +6 -6
  33. edsl/coop/__init__.py +25 -2
  34. edsl/coop/coop.py +430 -113
  35. edsl/coop/{ExpectedParrotKeyHandler.py → ep_key_handling.py} +86 -10
  36. edsl/coop/exceptions.py +62 -0
  37. edsl/coop/price_fetcher.py +126 -0
  38. edsl/coop/utils.py +89 -24
  39. edsl/data_transfer_models.py +5 -72
  40. edsl/dataset/__init__.py +10 -0
  41. edsl/{results/Dataset.py → dataset/dataset.py} +116 -36
  42. edsl/dataset/dataset_operations_mixin.py +1492 -0
  43. edsl/{results/DatasetTree.py → dataset/dataset_tree.py} +156 -75
  44. edsl/{results/TableDisplay.py → dataset/display/table_display.py} +18 -7
  45. edsl/{results → dataset/display}/table_renderers.py +58 -2
  46. edsl/{results → dataset}/file_exports.py +4 -5
  47. edsl/{results → dataset}/smart_objects.py +2 -2
  48. edsl/enums.py +5 -205
  49. edsl/inference_services/__init__.py +5 -0
  50. edsl/inference_services/{AvailableModelCacheHandler.py → available_model_cache_handler.py} +2 -3
  51. edsl/inference_services/{AvailableModelFetcher.py → available_model_fetcher.py} +8 -14
  52. edsl/inference_services/data_structures.py +3 -2
  53. edsl/{exceptions/inference_services.py → inference_services/exceptions.py} +1 -1
  54. edsl/inference_services/{InferenceServiceABC.py → inference_service_abc.py} +1 -1
  55. edsl/inference_services/{InferenceServicesCollection.py → inference_services_collection.py} +8 -7
  56. edsl/inference_services/registry.py +4 -41
  57. edsl/inference_services/{ServiceAvailability.py → service_availability.py} +5 -25
  58. edsl/inference_services/services/__init__.py +31 -0
  59. edsl/inference_services/{AnthropicService.py → services/anthropic_service.py} +3 -3
  60. edsl/inference_services/{AwsBedrock.py → services/aws_bedrock.py} +2 -2
  61. edsl/inference_services/{AzureAI.py → services/azure_ai.py} +2 -2
  62. edsl/inference_services/{DeepInfraService.py → services/deep_infra_service.py} +1 -3
  63. edsl/inference_services/{DeepSeekService.py → services/deep_seek_service.py} +2 -4
  64. edsl/inference_services/{GoogleService.py → services/google_service.py} +5 -4
  65. edsl/inference_services/{GroqService.py → services/groq_service.py} +1 -1
  66. edsl/inference_services/{MistralAIService.py → services/mistral_ai_service.py} +3 -3
  67. edsl/inference_services/{OllamaService.py → services/ollama_service.py} +1 -7
  68. edsl/inference_services/{OpenAIService.py → services/open_ai_service.py} +5 -6
  69. edsl/inference_services/{PerplexityService.py → services/perplexity_service.py} +12 -12
  70. edsl/inference_services/{TestService.py → services/test_service.py} +7 -6
  71. edsl/inference_services/{TogetherAIService.py → services/together_ai_service.py} +2 -6
  72. edsl/inference_services/{XAIService.py → services/xai_service.py} +1 -1
  73. edsl/inference_services/write_available.py +1 -2
  74. edsl/instructions/__init__.py +6 -0
  75. edsl/{surveys/instructions/Instruction.py → instructions/instruction.py} +11 -6
  76. edsl/{surveys/instructions/InstructionCollection.py → instructions/instruction_collection.py} +10 -5
  77. edsl/{surveys/InstructionHandler.py → instructions/instruction_handler.py} +3 -3
  78. edsl/{jobs/interviews → interviews}/ReportErrors.py +2 -2
  79. edsl/interviews/__init__.py +4 -0
  80. edsl/{jobs/AnswerQuestionFunctionConstructor.py → interviews/answering_function.py} +45 -18
  81. edsl/{jobs/interviews/InterviewExceptionEntry.py → interviews/exception_tracking.py} +107 -22
  82. edsl/interviews/interview.py +638 -0
  83. edsl/{jobs/interviews/InterviewStatusDictionary.py → interviews/interview_status_dictionary.py} +21 -12
  84. edsl/{jobs/interviews/InterviewStatusLog.py → interviews/interview_status_log.py} +16 -7
  85. edsl/{jobs/InterviewTaskManager.py → interviews/interview_task_manager.py} +12 -7
  86. edsl/{jobs/RequestTokenEstimator.py → interviews/request_token_estimator.py} +8 -3
  87. edsl/{jobs/interviews/InterviewStatistic.py → interviews/statistics.py} +36 -10
  88. edsl/invigilators/__init__.py +38 -0
  89. edsl/invigilators/invigilator_base.py +477 -0
  90. edsl/{agents/Invigilator.py → invigilators/invigilators.py} +263 -10
  91. edsl/invigilators/prompt_constructor.py +476 -0
  92. edsl/{agents → invigilators}/prompt_helpers.py +2 -1
  93. edsl/{agents/QuestionInstructionPromptBuilder.py → invigilators/question_instructions_prompt_builder.py} +18 -13
  94. edsl/{agents → invigilators}/question_option_processor.py +96 -21
  95. edsl/{agents/QuestionTemplateReplacementsBuilder.py → invigilators/question_template_replacements_builder.py} +64 -12
  96. edsl/jobs/__init__.py +7 -1
  97. edsl/jobs/async_interview_runner.py +99 -35
  98. edsl/jobs/check_survey_scenario_compatibility.py +7 -5
  99. edsl/jobs/data_structures.py +153 -22
  100. edsl/{exceptions/jobs.py → jobs/exceptions.py} +2 -1
  101. edsl/jobs/{FetchInvigilator.py → fetch_invigilator.py} +4 -4
  102. edsl/jobs/{loggers/HTMLTableJobLogger.py → html_table_job_logger.py} +6 -2
  103. edsl/jobs/{Jobs.py → jobs.py} +321 -155
  104. edsl/jobs/{JobsChecks.py → jobs_checks.py} +15 -7
  105. edsl/jobs/{JobsComponentConstructor.py → jobs_component_constructor.py} +20 -17
  106. edsl/jobs/{InterviewsConstructor.py → jobs_interview_constructor.py} +10 -5
  107. edsl/jobs/jobs_pricing_estimation.py +347 -0
  108. edsl/jobs/{JobsRemoteInferenceLogger.py → jobs_remote_inference_logger.py} +4 -3
  109. edsl/jobs/jobs_runner_asyncio.py +282 -0
  110. edsl/jobs/{JobsRemoteInferenceHandler.py → remote_inference.py} +19 -22
  111. edsl/jobs/results_exceptions_handler.py +2 -2
  112. edsl/key_management/__init__.py +28 -0
  113. edsl/key_management/key_lookup.py +161 -0
  114. edsl/{language_models/key_management/KeyLookupBuilder.py → key_management/key_lookup_builder.py} +118 -47
  115. edsl/key_management/key_lookup_collection.py +82 -0
  116. edsl/key_management/models.py +218 -0
  117. edsl/language_models/__init__.py +7 -2
  118. edsl/language_models/{ComputeCost.py → compute_cost.py} +18 -3
  119. edsl/{exceptions/language_models.py → language_models/exceptions.py} +2 -1
  120. edsl/language_models/language_model.py +1080 -0
  121. edsl/language_models/model.py +10 -25
  122. edsl/language_models/{ModelList.py → model_list.py} +9 -14
  123. edsl/language_models/{RawResponseHandler.py → raw_response_handler.py} +1 -1
  124. edsl/language_models/{RegisterLanguageModelsMeta.py → registry.py} +1 -1
  125. edsl/language_models/repair.py +4 -4
  126. edsl/language_models/utilities.py +4 -4
  127. edsl/notebooks/__init__.py +3 -1
  128. edsl/notebooks/{Notebook.py → notebook.py} +7 -8
  129. edsl/prompts/__init__.py +1 -1
  130. edsl/{exceptions/prompts.py → prompts/exceptions.py} +3 -1
  131. edsl/prompts/{Prompt.py → prompt.py} +101 -95
  132. edsl/questions/HTMLQuestion.py +1 -1
  133. edsl/questions/__init__.py +154 -25
  134. edsl/questions/answer_validator_mixin.py +1 -1
  135. edsl/questions/compose_questions.py +4 -3
  136. edsl/questions/derived/question_likert_five.py +166 -0
  137. edsl/questions/derived/{QuestionLinearScale.py → question_linear_scale.py} +4 -4
  138. edsl/questions/derived/{QuestionTopK.py → question_top_k.py} +4 -4
  139. edsl/questions/derived/{QuestionYesNo.py → question_yes_no.py} +4 -5
  140. edsl/questions/descriptors.py +24 -30
  141. edsl/questions/loop_processor.py +65 -19
  142. edsl/questions/question_base.py +881 -0
  143. edsl/questions/question_base_gen_mixin.py +15 -16
  144. edsl/questions/{QuestionBasePromptsMixin.py → question_base_prompts_mixin.py} +2 -2
  145. edsl/questions/{QuestionBudget.py → question_budget.py} +3 -4
  146. edsl/questions/{QuestionCheckBox.py → question_check_box.py} +16 -16
  147. edsl/questions/{QuestionDict.py → question_dict.py} +39 -5
  148. edsl/questions/{QuestionExtract.py → question_extract.py} +9 -9
  149. edsl/questions/question_free_text.py +282 -0
  150. edsl/questions/{QuestionFunctional.py → question_functional.py} +6 -5
  151. edsl/questions/{QuestionList.py → question_list.py} +6 -7
  152. edsl/questions/{QuestionMatrix.py → question_matrix.py} +6 -5
  153. edsl/questions/{QuestionMultipleChoice.py → question_multiple_choice.py} +126 -21
  154. edsl/questions/{QuestionNumerical.py → question_numerical.py} +5 -5
  155. edsl/questions/{QuestionRank.py → question_rank.py} +6 -6
  156. edsl/questions/question_registry.py +10 -16
  157. edsl/questions/register_questions_meta.py +8 -4
  158. edsl/questions/response_validator_abc.py +17 -16
  159. edsl/results/__init__.py +4 -1
  160. edsl/{exceptions/results.py → results/exceptions.py} +1 -1
  161. edsl/results/report.py +197 -0
  162. edsl/results/{Result.py → result.py} +131 -45
  163. edsl/results/{Results.py → results.py} +420 -216
  164. edsl/results/results_selector.py +344 -25
  165. edsl/scenarios/__init__.py +30 -3
  166. edsl/scenarios/{ConstructDownloadLink.py → construct_download_link.py} +7 -0
  167. edsl/scenarios/directory_scanner.py +156 -13
  168. edsl/scenarios/document_chunker.py +186 -0
  169. edsl/scenarios/exceptions.py +101 -0
  170. edsl/scenarios/file_methods.py +2 -3
  171. edsl/scenarios/file_store.py +755 -0
  172. edsl/scenarios/handlers/__init__.py +14 -14
  173. edsl/scenarios/handlers/{csv.py → csv_file_store.py} +1 -2
  174. edsl/scenarios/handlers/{docx.py → docx_file_store.py} +8 -7
  175. edsl/scenarios/handlers/{html.py → html_file_store.py} +1 -2
  176. edsl/scenarios/handlers/{jpeg.py → jpeg_file_store.py} +1 -1
  177. edsl/scenarios/handlers/{json.py → json_file_store.py} +1 -1
  178. edsl/scenarios/handlers/latex_file_store.py +5 -0
  179. edsl/scenarios/handlers/{md.py → md_file_store.py} +1 -1
  180. edsl/scenarios/handlers/{pdf.py → pdf_file_store.py} +2 -2
  181. edsl/scenarios/handlers/{png.py → png_file_store.py} +1 -1
  182. edsl/scenarios/handlers/{pptx.py → pptx_file_store.py} +8 -7
  183. edsl/scenarios/handlers/{py.py → py_file_store.py} +1 -3
  184. edsl/scenarios/handlers/{sql.py → sql_file_store.py} +2 -1
  185. edsl/scenarios/handlers/{sqlite.py → sqlite_file_store.py} +2 -3
  186. edsl/scenarios/handlers/{txt.py → txt_file_store.py} +1 -1
  187. edsl/scenarios/scenario.py +928 -0
  188. edsl/scenarios/scenario_join.py +18 -5
  189. edsl/scenarios/{ScenarioList.py → scenario_list.py} +424 -106
  190. edsl/scenarios/{ScenarioListPdfMixin.py → scenario_list_pdf_tools.py} +16 -15
  191. edsl/scenarios/scenario_selector.py +5 -1
  192. edsl/study/ObjectEntry.py +2 -2
  193. edsl/study/SnapShot.py +5 -5
  194. edsl/study/Study.py +20 -21
  195. edsl/study/__init__.py +6 -4
  196. edsl/surveys/__init__.py +7 -4
  197. edsl/surveys/dag/__init__.py +2 -0
  198. edsl/surveys/{ConstructDAG.py → dag/construct_dag.py} +3 -3
  199. edsl/surveys/{DAG.py → dag/dag.py} +13 -10
  200. edsl/surveys/descriptors.py +1 -1
  201. edsl/surveys/{EditSurvey.py → edit_survey.py} +9 -9
  202. edsl/{exceptions/surveys.py → surveys/exceptions.py} +1 -2
  203. edsl/surveys/memory/__init__.py +3 -0
  204. edsl/surveys/{MemoryPlan.py → memory/memory_plan.py} +10 -9
  205. edsl/surveys/rules/__init__.py +3 -0
  206. edsl/surveys/{Rule.py → rules/rule.py} +103 -43
  207. edsl/surveys/{RuleCollection.py → rules/rule_collection.py} +21 -30
  208. edsl/surveys/{RuleManager.py → rules/rule_manager.py} +19 -13
  209. edsl/surveys/survey.py +1743 -0
  210. edsl/surveys/{SurveyExportMixin.py → survey_export.py} +22 -27
  211. edsl/surveys/{SurveyFlowVisualization.py → survey_flow_visualization.py} +11 -2
  212. edsl/surveys/{Simulator.py → survey_simulator.py} +10 -3
  213. edsl/tasks/__init__.py +32 -0
  214. edsl/{jobs/tasks/QuestionTaskCreator.py → tasks/question_task_creator.py} +115 -57
  215. edsl/tasks/task_creators.py +135 -0
  216. edsl/{jobs/tasks/TaskHistory.py → tasks/task_history.py} +86 -47
  217. edsl/{jobs/tasks → tasks}/task_status_enum.py +91 -7
  218. edsl/tasks/task_status_log.py +85 -0
  219. edsl/tokens/__init__.py +2 -0
  220. edsl/tokens/interview_token_usage.py +53 -0
  221. edsl/utilities/PrettyList.py +1 -1
  222. edsl/utilities/SystemInfo.py +25 -22
  223. edsl/utilities/__init__.py +29 -21
  224. edsl/utilities/gcp_bucket/__init__.py +2 -0
  225. edsl/utilities/gcp_bucket/cloud_storage.py +99 -96
  226. edsl/utilities/interface.py +44 -536
  227. edsl/{results/MarkdownToPDF.py → utilities/markdown_to_pdf.py} +13 -5
  228. edsl/utilities/repair_functions.py +1 -1
  229. {edsl-0.1.46.dist-info → edsl-0.1.48.dist-info}/METADATA +3 -2
  230. edsl-0.1.48.dist-info/RECORD +347 -0
  231. edsl/Base.py +0 -426
  232. edsl/BaseDiff.py +0 -260
  233. edsl/agents/InvigilatorBase.py +0 -260
  234. edsl/agents/PromptConstructor.py +0 -318
  235. edsl/auto/AutoStudy.py +0 -130
  236. edsl/auto/StageBase.py +0 -243
  237. edsl/auto/StageGenerateSurvey.py +0 -178
  238. edsl/auto/StageLabelQuestions.py +0 -125
  239. edsl/auto/StagePersona.py +0 -61
  240. edsl/auto/StagePersonaDimensionValueRanges.py +0 -88
  241. edsl/auto/StagePersonaDimensionValues.py +0 -74
  242. edsl/auto/StagePersonaDimensions.py +0 -69
  243. edsl/auto/StageQuestions.py +0 -74
  244. edsl/auto/SurveyCreatorPipeline.py +0 -21
  245. edsl/auto/utilities.py +0 -218
  246. edsl/base/Base.py +0 -279
  247. edsl/coop/PriceFetcher.py +0 -54
  248. edsl/data/Cache.py +0 -580
  249. edsl/data/CacheEntry.py +0 -230
  250. edsl/data/SQLiteDict.py +0 -292
  251. edsl/data/__init__.py +0 -5
  252. edsl/data/orm.py +0 -10
  253. edsl/exceptions/cache.py +0 -5
  254. edsl/exceptions/coop.py +0 -14
  255. edsl/exceptions/data.py +0 -14
  256. edsl/exceptions/scenarios.py +0 -29
  257. edsl/jobs/Answers.py +0 -43
  258. edsl/jobs/JobsPrompts.py +0 -354
  259. edsl/jobs/buckets/BucketCollection.py +0 -134
  260. edsl/jobs/buckets/ModelBuckets.py +0 -65
  261. edsl/jobs/buckets/TokenBucket.py +0 -283
  262. edsl/jobs/buckets/TokenBucketClient.py +0 -191
  263. edsl/jobs/interviews/Interview.py +0 -395
  264. edsl/jobs/interviews/InterviewExceptionCollection.py +0 -99
  265. edsl/jobs/interviews/InterviewStatisticsCollection.py +0 -25
  266. edsl/jobs/runners/JobsRunnerAsyncio.py +0 -163
  267. edsl/jobs/runners/JobsRunnerStatusData.py +0 -0
  268. edsl/jobs/tasks/TaskCreators.py +0 -64
  269. edsl/jobs/tasks/TaskStatusLog.py +0 -23
  270. edsl/jobs/tokens/InterviewTokenUsage.py +0 -27
  271. edsl/language_models/LanguageModel.py +0 -635
  272. edsl/language_models/ServiceDataSources.py +0 -0
  273. edsl/language_models/key_management/KeyLookup.py +0 -63
  274. edsl/language_models/key_management/KeyLookupCollection.py +0 -38
  275. edsl/language_models/key_management/models.py +0 -137
  276. edsl/questions/QuestionBase.py +0 -539
  277. edsl/questions/QuestionFreeText.py +0 -130
  278. edsl/questions/derived/QuestionLikertFive.py +0 -76
  279. edsl/results/DatasetExportMixin.py +0 -911
  280. edsl/results/ResultsExportMixin.py +0 -45
  281. edsl/results/TextEditor.py +0 -50
  282. edsl/results/results_fetch_mixin.py +0 -33
  283. edsl/results/results_tools_mixin.py +0 -98
  284. edsl/scenarios/DocumentChunker.py +0 -104
  285. edsl/scenarios/FileStore.py +0 -564
  286. edsl/scenarios/Scenario.py +0 -548
  287. edsl/scenarios/ScenarioHtmlMixin.py +0 -65
  288. edsl/scenarios/ScenarioListExportMixin.py +0 -45
  289. edsl/scenarios/handlers/latex.py +0 -5
  290. edsl/shared.py +0 -1
  291. edsl/surveys/Survey.py +0 -1306
  292. edsl/surveys/SurveyQualtricsImport.py +0 -284
  293. edsl/surveys/SurveyToApp.py +0 -141
  294. edsl/surveys/instructions/__init__.py +0 -0
  295. edsl/tools/__init__.py +0 -1
  296. edsl/tools/clusters.py +0 -192
  297. edsl/tools/embeddings.py +0 -27
  298. edsl/tools/embeddings_plotting.py +0 -118
  299. edsl/tools/plotting.py +0 -112
  300. edsl/tools/summarize.py +0 -18
  301. edsl/utilities/data/Registry.py +0 -6
  302. edsl/utilities/data/__init__.py +0 -1
  303. edsl/utilities/data/scooter_results.json +0 -1
  304. edsl-0.1.46.dist-info/RECORD +0 -366
  305. /edsl/coop/{CoopFunctionsMixin.py → coop_functions.py} +0 -0
  306. /edsl/{results → dataset/display}/CSSParameterizer.py +0 -0
  307. /edsl/{language_models/key_management → dataset/display}/__init__.py +0 -0
  308. /edsl/{results → dataset/display}/table_data_class.py +0 -0
  309. /edsl/{results → dataset/display}/table_display.css +0 -0
  310. /edsl/{results/ResultsGGMixin.py → dataset/r/ggplot.py} +0 -0
  311. /edsl/{results → dataset}/tree_explore.py +0 -0
  312. /edsl/{surveys/instructions/ChangeInstruction.py → instructions/change_instruction.py} +0 -0
  313. /edsl/{jobs/interviews → interviews}/interview_status_enum.py +0 -0
  314. /edsl/jobs/{runners/JobsRunnerStatus.py → jobs_runner_status.py} +0 -0
  315. /edsl/language_models/{PriceManager.py → price_manager.py} +0 -0
  316. /edsl/language_models/{fake_openai_call.py → unused/fake_openai_call.py} +0 -0
  317. /edsl/language_models/{fake_openai_service.py → unused/fake_openai_service.py} +0 -0
  318. /edsl/notebooks/{NotebookToLaTeX.py → notebook_to_latex.py} +0 -0
  319. /edsl/{exceptions/questions.py → questions/exceptions.py} +0 -0
  320. /edsl/questions/{SimpleAskMixin.py → simple_ask_mixin.py} +0 -0
  321. /edsl/surveys/{Memory.py → memory/memory.py} +0 -0
  322. /edsl/surveys/{MemoryManagement.py → memory/memory_management.py} +0 -0
  323. /edsl/surveys/{SurveyCSS.py → survey_css.py} +0 -0
  324. /edsl/{jobs/tokens/TokenUsage.py → tokens/token_usage.py} +0 -0
  325. /edsl/{results/MarkdownToDocx.py → utilities/markdown_to_docx.py} +0 -0
  326. /edsl/{TemplateLoader.py → utilities/template_loader.py} +0 -0
  327. {edsl-0.1.46.dist-info → edsl-0.1.48.dist-info}/LICENSE +0 -0
  328. {edsl-0.1.46.dist-info → edsl-0.1.48.dist-info}/WHEEL +0 -0
@@ -1,26 +1,26 @@
1
1
  import copy
2
2
  import asyncio
3
3
 
4
- from typing import Union, Type, Callable, TYPE_CHECKING
4
+ from typing import Union, Type, Callable, TYPE_CHECKING, Any
5
5
 
6
6
  if TYPE_CHECKING:
7
- from edsl.questions.QuestionBase import QuestionBase
8
- from edsl.jobs.interviews.Interview import Interview
9
- from edsl.language_models.key_management.KeyLookup import KeyLookup
7
+ from ..questions import QuestionBase
8
+ from .interview import Interview
9
+ from ..key_management import KeyLookup
10
10
 
11
- from edsl.surveys.base import EndOfSurvey
12
- from edsl.jobs.tasks.task_status_enum import TaskStatus
11
+ from ..surveys.base import EndOfSurvey
12
+ from ..tasks import TaskStatus
13
13
 
14
- from edsl.jobs.FetchInvigilator import FetchInvigilator
15
- from edsl.exceptions.language_models import LanguageModelNoResponseError
16
- from edsl.exceptions.questions import QuestionAnswerValidationError
17
- from edsl.data_transfer_models import AgentResponseDict, EDSLResultObjectInput
14
+ from ..jobs.fetch_invigilator import FetchInvigilator
15
+ from ..language_models.exceptions import LanguageModelNoResponseError
16
+ from ..questions.exceptions import QuestionAnswerValidationError
17
+ from ..data_transfer_models import AgentResponseDict, EDSLResultObjectInput, Answers
18
18
 
19
- from edsl.jobs.Answers import Answers
19
+ from .exception_tracking import InterviewExceptionEntry
20
20
 
21
21
 
22
22
  class RetryConfig:
23
- from edsl.config import CONFIG
23
+ from ..config import CONFIG
24
24
 
25
25
  EDSL_BACKOFF_START_SEC = float(CONFIG.get("EDSL_BACKOFF_START_SEC"))
26
26
  EDSL_BACKOFF_MAX_SEC = float(CONFIG.get("EDSL_BACKOFF_MAX_SEC"))
@@ -46,17 +46,45 @@ class SkipHandler:
46
46
  | self.interview.agent["traits"]
47
47
  )
48
48
  return self.skip_function(current_question_index, combined_answers)
49
+
50
+ def _current_info_env(self) -> dict[str, Any]:
51
+ """
52
+ - The current answers are "generated_tokens" and "comment"
53
+ - The scenario should have "scenario." added to the keys
54
+ - The agent traits should have "agent." added to the keys
55
+ """
56
+ # Process answers dictionary
57
+ processed_answers = {}
58
+ for key, value in self.interview.answers.items():
59
+ if key.endswith("_generated_tokens"):
60
+ base_name = key.replace("_generated_tokens", "")
61
+ processed_answers[f"{base_name}.generated_tokens"] = value
62
+ elif key.endswith("_comment"):
63
+ base_name = key.replace("_comment", "")
64
+ processed_answers[f"{base_name}.comment"] = value
65
+ else:
66
+ # Regular answer
67
+ processed_answers[f"{key}.answer"] = value
68
+
69
+ # Process scenario dictionary
70
+ processed_scenario = {f"scenario.{k}": v for k, v in self.interview.scenario.items()}
71
+
72
+ # Process agent traits
73
+ processed_agent = {f"agent.{k}": v for k, v in self.interview.agent["traits"].items()}
74
+
75
+ return processed_answers | processed_scenario | processed_agent
49
76
 
50
77
  def cancel_skipped_questions(self, current_question: "QuestionBase") -> None:
51
78
  """Cancel the tasks for questions that should be skipped."""
52
79
  current_question_index: int = self.interview.to_index[
53
80
  current_question.question_name
54
81
  ]
55
- answers = (
56
- self.interview.answers
57
- | self.interview.scenario
58
- | self.interview.agent["traits"]
59
- )
82
+ answers = self._current_info_env()
83
+ # answers = (
84
+ # self.interview.answers
85
+ # | self.interview.scenario
86
+ # | self.interview.agent["traits"]
87
+ # )
60
88
 
61
89
  # Get the index of the next question, which could also be the end of the survey
62
90
  next_question: Union[int, EndOfSurvey] = (
@@ -111,7 +139,6 @@ class AnswerQuestionFunctionConstructor:
111
139
  ):
112
140
  """Handle an exception that occurred while answering a question."""
113
141
 
114
- from edsl.jobs.interviews.InterviewExceptionEntry import InterviewExceptionEntry
115
142
 
116
143
  answers = copy.copy(
117
144
  self.interview.answers
@@ -1,7 +1,9 @@
1
+ from collections import UserDict
1
2
  import traceback
2
3
  import datetime
3
- from edsl.agents.InvigilatorBase import InvigilatorBase
4
+ import json
4
5
 
6
+ from ..invigilators import InvigilatorBase
5
7
 
6
8
  class InterviewExceptionEntry:
7
9
  """Class to record an exception that occurred during the interview."""
@@ -16,33 +18,33 @@ class InterviewExceptionEntry:
16
18
  ):
17
19
  self.time = datetime.datetime.now().isoformat()
18
20
  self.exception = exception
19
- # self.failed_question = failed_question
20
21
  self.invigilator = invigilator
21
22
  self.traceback_format = traceback_format
22
23
  self.answers = answers
23
24
 
24
- # breakpoint()
25
-
26
25
  @property
27
- def question_type(self):
28
- # return self.failed_question.question.question_type
26
+ def question_type(self) -> str:
27
+ """Return the type of the question that failed."""
29
28
  return self.invigilator.question.question_type
30
29
 
31
30
  @property
32
- def name(self):
31
+ def name(self) -> str:
32
+ """Return the name of the exception."""
33
33
  return repr(self.exception)
34
34
 
35
35
  @property
36
- def rendered_prompts(self):
36
+ def rendered_prompts(self) -> str:
37
+ """Return the rendered prompts."""
37
38
  return self.invigilator.get_prompts()
38
39
 
39
40
  @property
40
- def key_sequence(self):
41
+ def key_sequence(self) -> tuple[str, ...]:
42
+ """Return the key sequence."""
41
43
  return self.invigilator.model.key_sequence
42
44
 
43
45
  @property
44
- def generated_token_string(self):
45
- # return "POO"
46
+ def generated_token_string(self) -> str:
47
+ """Return the generated token string."""
46
48
  if self.invigilator.raw_model_response is None:
47
49
  return "No raw model response available."
48
50
  else:
@@ -51,9 +53,8 @@ class InterviewExceptionEntry:
51
53
  )
52
54
 
53
55
  @property
54
- def raw_model_response(self):
55
- import json
56
-
56
+ def raw_model_response(self) -> dict:
57
+ """Return the raw model response."""
57
58
  if self.invigilator.raw_model_response is None:
58
59
  return "No raw model response available."
59
60
  return json.dumps(self.invigilator.raw_model_response, indent=2)
@@ -64,8 +65,12 @@ class InterviewExceptionEntry:
64
65
 
65
66
  @classmethod
66
67
  def example(cls):
67
- from edsl import QuestionFreeText
68
- from edsl.language_models import LanguageModel
68
+ """Return an example InterviewExceptionEntry.
69
+
70
+ >>> entry = InterviewExceptionEntry.example()
71
+ """
72
+ from ..questions import QuestionFreeText
73
+ from ..language_models import LanguageModel
69
74
 
70
75
  m = LanguageModel.example(test_model=True)
71
76
  q = QuestionFreeText.example(exception_to_throw=ValueError)
@@ -80,9 +85,11 @@ class InterviewExceptionEntry:
80
85
 
81
86
  @property
82
87
  def code_to_reproduce(self):
88
+ """Return the code to reproduce the exception."""
83
89
  return self.code(run=False)
84
90
 
85
91
  def code(self, run=True):
92
+ """Return the code to reproduce the exception."""
86
93
  lines = []
87
94
  lines.append("from edsl import Question, Model, Scenario, Agent")
88
95
 
@@ -101,7 +108,7 @@ class InterviewExceptionEntry:
101
108
  return code_str
102
109
 
103
110
  @property
104
- def traceback(self):
111
+ def traceback(self) -> str:
105
112
  """Return the exception as HTML."""
106
113
  if self.traceback_format == "html":
107
114
  return self.html_traceback
@@ -109,7 +116,7 @@ class InterviewExceptionEntry:
109
116
  return self.text_traceback
110
117
 
111
118
  @property
112
- def text_traceback(self):
119
+ def text_traceback(self) -> str:
113
120
  """
114
121
  >>> entry = InterviewExceptionEntry.example()
115
122
  >>> entry.text_traceback
@@ -120,7 +127,7 @@ class InterviewExceptionEntry:
120
127
  return tb_str
121
128
 
122
129
  @property
123
- def html_traceback(self):
130
+ def html_traceback(self) -> str:
124
131
  from rich.console import Console
125
132
  from rich.table import Table
126
133
  from rich.traceback import Traceback
@@ -142,6 +149,11 @@ class InterviewExceptionEntry:
142
149
 
143
150
  @staticmethod
144
151
  def serialize_exception(exception: Exception) -> dict:
152
+ """Serialize an exception to a dictionary.
153
+
154
+ >>> entry = InterviewExceptionEntry.example()
155
+ >>> _ = entry.serialize_exception(entry.exception)
156
+ """
145
157
  return {
146
158
  "type": type(exception).__name__,
147
159
  "message": str(exception),
@@ -154,6 +166,11 @@ class InterviewExceptionEntry:
154
166
 
155
167
  @staticmethod
156
168
  def deserialize_exception(data: dict) -> Exception:
169
+ """Deserialize an exception from a dictionary.
170
+
171
+ >>> entry = InterviewExceptionEntry.example()
172
+ >>> _ = entry.deserialize_exception(entry.to_dict()["exception"])
173
+ """
157
174
  try:
158
175
  exception_class = globals()[data["type"]]
159
176
  except KeyError:
@@ -166,8 +183,7 @@ class InterviewExceptionEntry:
166
183
  >>> entry = InterviewExceptionEntry.example()
167
184
  >>> _ = entry.to_dict()
168
185
  """
169
- import json
170
- from edsl.exceptions.questions import QuestionAnswerValidationError
186
+ from ..questions.exceptions import QuestionAnswerValidationError
171
187
 
172
188
  invigilator = (
173
189
  self.invigilator.to_dict() if self.invigilator is not None else None
@@ -192,7 +208,7 @@ class InterviewExceptionEntry:
192
208
  @classmethod
193
209
  def from_dict(cls, data: dict) -> "InterviewExceptionEntry":
194
210
  """Create an InterviewExceptionEntry from a dictionary."""
195
- from edsl.agents.Invigilator import InvigilatorAI
211
+ from ..invigilators import InvigilatorAI
196
212
 
197
213
  exception = cls.deserialize_exception(data["exception"])
198
214
  if data["invigilator"] is None:
@@ -202,6 +218,75 @@ class InterviewExceptionEntry:
202
218
  return cls(exception=exception, invigilator=invigilator)
203
219
 
204
220
 
221
+
222
+ class InterviewExceptionCollection(UserDict):
223
+ """A collection of exceptions that occurred during the interview."""
224
+
225
+ def __init__(self):
226
+ """Initialize the InterviewExceptionCollection."""
227
+ super().__init__()
228
+ self.fixed = set()
229
+
230
+ def unfixed_exceptions(self) -> list:
231
+ """Return a list of unfixed exceptions."""
232
+ return {k: v for k, v in self.data.items() if k not in self.fixed}
233
+
234
+ def num_unfixed(self) -> int:
235
+ """Return a list of unfixed questions."""
236
+ return len([k for k in self.data.keys() if k not in self.fixed])
237
+
238
+ def record_fixed_question(self, question_name: str) -> None:
239
+ """Record that a question has been fixed."""
240
+ self.fixed.add(question_name)
241
+
242
+ def add(self, question_name: str, entry: InterviewExceptionEntry) -> None:
243
+ """Add an exception entry to the collection."""
244
+ question_name = question_name
245
+ if question_name not in self.data:
246
+ self.data[question_name] = []
247
+ self.data[question_name].append(entry)
248
+
249
+ def to_dict(self, include_traceback=True) -> dict:
250
+ """Return the collection of exceptions as a dictionary."""
251
+ newdata = {k: [e.to_dict() for e in v] for k, v in self.data.items()}
252
+ return newdata
253
+
254
+ @classmethod
255
+ def from_dict(cls, data: dict) -> "InterviewExceptionCollection":
256
+ """Create an InterviewExceptionCollection from a dictionary."""
257
+ collection = cls()
258
+ for question_name, entries in data.items():
259
+ for entry in entries:
260
+ collection.add(question_name, InterviewExceptionEntry.from_dict(entry))
261
+ return collection
262
+
263
+ def _repr_html_(self) -> str:
264
+ from ..utilities.utilities import data_to_html
265
+
266
+ return data_to_html(self.to_dict(include_traceback=True))
267
+
268
+ def ascii_table(self, traceback: bool = False) -> None:
269
+ """Print the collection of exceptions as an ASCII table."""
270
+ headers = ["Question name", "Exception", "Time", "Traceback"]
271
+ from tabulate import tabulate
272
+
273
+ data = []
274
+ for question, exceptions in self.data.items():
275
+ for exception in exceptions:
276
+ if traceback:
277
+ row = [
278
+ question,
279
+ exception["exception"],
280
+ exception["time"],
281
+ exception["traceback"],
282
+ ]
283
+ else:
284
+ row = [question, exception["exception"], exception["time"]]
285
+ data.append(row)
286
+
287
+ print(tabulate(data, headers=headers, tablefmt="grid"))
288
+
289
+
205
290
  if __name__ == "__main__":
206
291
  import doctest
207
292