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,7 +1,26 @@
1
- # """The Jobs class is a collection of agents, scenarios and models and one survey."""
1
+ """
2
+ The Jobs module is the core orchestration component of the EDSL framework.
3
+
4
+ It provides functionality to define, configure, and execute computational jobs that
5
+ involve multiple agents, scenarios, models, and a survey. Jobs are the primary way
6
+ that users run large-scale experiments or simulations in EDSL.
7
+
8
+ The Jobs class handles:
9
+ 1. Organizing all components (agents, scenarios, models, survey)
10
+ 2. Configuring execution parameters
11
+ 3. Managing resources like caches and API keys
12
+ 4. Running interviews in parallel
13
+ 5. Collecting and structuring results
14
+
15
+ This module is designed to be used by both application developers and researchers
16
+ who need to run complex simulations with language models.
17
+ """
2
18
  from __future__ import annotations
3
19
  import asyncio
4
20
  from inspect import signature
21
+ from typing import Optional, Union, TypeVar, Callable, cast
22
+ from functools import wraps
23
+
5
24
  from typing import (
6
25
  Literal,
7
26
  Optional,
@@ -13,38 +32,36 @@ from typing import (
13
32
  Tuple,
14
33
  )
15
34
 
16
- from edsl.Base import Base
35
+ from ..base import Base
36
+ from ..utilities import remove_edsl_version
37
+ from ..coop import CoopServerResponseError
38
+
39
+ from ..buckets import BucketCollection
40
+ from ..scenarios import Scenario, ScenarioList
41
+ from ..surveys import Survey
42
+ from ..interviews import Interview
17
43
 
18
- from edsl.jobs.buckets.BucketCollection import BucketCollection
19
- from edsl.jobs.JobsPrompts import JobsPrompts
20
- from edsl.jobs.interviews.Interview import Interview
21
- from edsl.utilities.remove_edsl_version import remove_edsl_version
22
- from edsl.jobs.runners.JobsRunnerAsyncio import JobsRunnerAsyncio
23
- from edsl.data.RemoteCacheSync import RemoteCacheSync
24
- from edsl.exceptions.coop import CoopServerResponseError
44
+ from .jobs_pricing_estimation import JobsPrompts
45
+ from .remote_inference import JobsRemoteInferenceHandler
46
+ from .jobs_checks import JobsChecks
47
+ from .data_structures import RunEnvironment, RunParameters, RunConfig
48
+ from .check_survey_scenario_compatibility import CheckSurveyScenarioCompatibility
25
49
 
26
- from edsl.jobs.JobsChecks import JobsChecks
27
- from edsl.jobs.data_structures import RunEnvironment, RunParameters, RunConfig
28
50
 
29
51
  if TYPE_CHECKING:
30
- from edsl.agents.Agent import Agent
31
- from edsl.agents.AgentList import AgentList
32
- from edsl.language_models.LanguageModel import LanguageModel
33
- from edsl.scenarios.Scenario import Scenario
34
- from edsl.scenarios.ScenarioList import ScenarioList
35
- from edsl.surveys.Survey import Survey
36
- from edsl.results.Results import Results
37
- from edsl.results.Dataset import Dataset
38
- from edsl.language_models.ModelList import ModelList
39
- from edsl.data.Cache import Cache
40
- from edsl.language_models.key_management.KeyLookup import KeyLookup
41
- from edsl.jobs.JobsRemoteInferenceHandler import JobsRemoteInferenceHandler
52
+ from ..agents import Agent
53
+ from ..agents import AgentList
54
+ from ..language_models import LanguageModel
55
+ from ..scenarios import Scenario, ScenarioList
56
+ from ..surveys import Survey
57
+ from ..results import Results
58
+ from ..dataset import Dataset
59
+ from ..language_models import ModelList
60
+ from ..caching import Cache
61
+ from ..key_management import KeyLookup
42
62
 
43
63
  VisibilityType = Literal["private", "public", "unlisted"]
44
64
 
45
- from dataclasses import dataclass
46
- from typing import Optional, Union, TypeVar, Callable, cast
47
- from functools import wraps
48
65
 
49
66
  try:
50
67
  from typing import ParamSpec
@@ -56,13 +73,32 @@ P = ParamSpec("P")
56
73
  T = TypeVar("T")
57
74
 
58
75
 
59
- from edsl.jobs.check_survey_scenario_compatibility import (
60
- CheckSurveyScenarioCompatibility,
61
- )
62
76
 
63
77
 
64
78
  def with_config(f: Callable[P, T]) -> Callable[P, T]:
65
- "This decorator make it so that the run function parameters match the RunConfig dataclass."
79
+ """
80
+ Decorator that processes function parameters to match the RunConfig dataclass structure.
81
+
82
+ This decorator is used primarily with the run() and run_async() methods to provide
83
+ a consistent interface for job configuration while maintaining a clean API.
84
+
85
+ The decorator:
86
+ 1. Extracts environment-related parameters into a RunEnvironment instance
87
+ 2. Extracts execution-related parameters into a RunParameters instance
88
+ 3. Combines both into a single RunConfig object
89
+ 4. Passes this RunConfig to the decorated function as a keyword argument
90
+
91
+ Parameters:
92
+ f (Callable): The function to decorate, typically run() or run_async()
93
+
94
+ Returns:
95
+ Callable: A wrapped function that accepts all RunConfig parameters directly
96
+
97
+ Example:
98
+ @with_config
99
+ def run(self, *, config: RunConfig) -> Results:
100
+ # Function can now access config.parameters and config.environment
101
+ """
66
102
  parameter_fields = {
67
103
  name: field.default
68
104
  for name, field in RunParameters.__dataclass_fields__.items()
@@ -84,24 +120,33 @@ def with_config(f: Callable[P, T]) -> Callable[P, T]:
84
120
  config = RunConfig(environment=environment, parameters=parameters)
85
121
  return f(*args, config=config)
86
122
 
87
- # Update the wrapper's signature to include all RunConfig parameters
88
- # old_sig = signature(f)
89
- # wrapper.__signature__ = old_sig.replace(
90
- # parameters=list(old_sig.parameters.values())[:-1]
91
- # + [
92
- # old_sig.parameters["config"].replace(
93
- # default=parameter_fields[name], name=name
94
- # )
95
- # for name in combined
96
- # ]
97
- # )
98
-
99
123
  return cast(Callable[P, T], wrapper)
100
124
 
101
125
 
102
126
  class Jobs(Base):
103
127
  """
104
- A collection of agents, scenarios and models and one survey that creates 'interviews'
128
+ A collection of agents, scenarios, models, and a survey that orchestrates interviews.
129
+
130
+ The Jobs class is the central component for running large-scale experiments or simulations
131
+ in EDSL. It manages the execution of interviews where agents interact with surveys through
132
+ language models, possibly in different scenarios.
133
+
134
+ Key responsibilities:
135
+ 1. Managing collections of agents, scenarios, and models
136
+ 2. Configuring execution parameters (caching, API keys, etc.)
137
+ 3. Managing parallel execution of interviews
138
+ 4. Handling remote cache and inference capabilities
139
+ 5. Collecting and organizing results
140
+
141
+ A typical workflow involves:
142
+ 1. Creating a survey with questions
143
+ 2. Creating a Jobs instance with that survey
144
+ 3. Adding agents, scenarios, and models using the `by()` method
145
+ 4. Running the job with `run()` or `run_async()`
146
+ 5. Analyzing the results
147
+
148
+ Jobs implements a fluent interface pattern, where methods return self to allow
149
+ method chaining for concise, readable configuration.
105
150
  """
106
151
 
107
152
  __documentation__ = "https://docs.expectedparrot.com/en/latest/jobs.html"
@@ -109,16 +154,44 @@ class Jobs(Base):
109
154
  def __init__(
110
155
  self,
111
156
  survey: "Survey",
112
- agents: Optional[Union[list[Agent], AgentList]] = None,
113
- models: Optional[Union[ModelList, list[LanguageModel]]] = None,
114
- scenarios: Optional[Union[ScenarioList, list[Scenario]]] = None,
157
+ agents: Optional[Union[list["Agent"], "AgentList"]] = None,
158
+ models: Optional[Union["ModelList", list["LanguageModel"]]] = None,
159
+ scenarios: Optional[Union["ScenarioList", list["Scenario"]]] = None,
115
160
  ):
116
- """Initialize a Jobs instance.
117
-
118
- :param survey: the survey to be used in the job
119
- :param agents: a list of agents
120
- :param models: a list of models
121
- :param scenarios: a list of scenarios
161
+ """Initialize a Jobs instance with a survey and optional components.
162
+
163
+ The Jobs constructor requires a survey and optionally accepts collections of
164
+ agents, models, and scenarios. If any of these optional components are not provided,
165
+ they can be added later using the `by()` method or will be automatically populated
166
+ with defaults when the job is run.
167
+
168
+ Parameters:
169
+ survey (Survey): The survey containing questions to be used in the job
170
+ agents (Union[list[Agent], AgentList], optional): The agents that will take the survey
171
+ models (Union[ModelList, list[LanguageModel]], optional): The language models to use
172
+ scenarios (Union[ScenarioList, list[Scenario]], optional): The scenarios to run
173
+
174
+ Raises:
175
+ ValueError: If the survey contains questions with invalid names
176
+ (e.g., names containing template variables)
177
+
178
+ Examples:
179
+ >>> from edsl.surveys import Survey
180
+ >>> from edsl.questions import QuestionFreeText
181
+ >>> q = QuestionFreeText(question_name="name", question_text="What is your name?")
182
+ >>> s = Survey(questions=[q])
183
+ >>> j = Jobs(survey = s)
184
+ >>> q = QuestionFreeText(question_name="{{ bad_name }}", question_text="What is your name?")
185
+ >>> s = Survey(questions=[q])
186
+ >>> j = Jobs(survey = s)
187
+ Traceback (most recent call last):
188
+ ...
189
+ ValueError: At least some question names are not valid: ['{{ bad_name }}']
190
+
191
+ Notes:
192
+ - The survey's questions must have valid names without templating variables
193
+ - If agents, models, or scenarios are not provided, defaults will be used when running
194
+ - Upon initialization, a RunConfig is created with default environment and parameters
122
195
  """
123
196
  self.run_config = RunConfig(
124
197
  environment=RunEnvironment(), parameters=RunParameters()
@@ -129,6 +202,15 @@ class Jobs(Base):
129
202
  self.scenarios: ScenarioList = scenarios
130
203
  self.models: ModelList = models
131
204
 
205
+ self._where_clauses = []
206
+
207
+ try:
208
+ assert self.survey.question_names_valid()
209
+ except Exception as e:
210
+ invalid_question_names = [q.question_name for q in self.survey.questions if not q.is_valid_question_name()]
211
+ raise ValueError(f"At least some question names are not valid: {invalid_question_names}")
212
+
213
+
132
214
  def add_running_env(self, running_env: RunEnvironment):
133
215
  self.run_config.add_environment(running_env)
134
216
  return self
@@ -142,7 +224,7 @@ class Jobs(Base):
142
224
  self.run_config.add_cache(cache)
143
225
  return self
144
226
 
145
- def using_bucket_collection(self, bucket_collection: BucketCollection) -> Jobs:
227
+ def using_bucket_collection(self, bucket_collection: 'BucketCollection') -> Jobs:
146
228
  """
147
229
  Add a BucketCollection to the job.
148
230
 
@@ -151,7 +233,7 @@ class Jobs(Base):
151
233
  self.run_config.add_bucket_collection(bucket_collection)
152
234
  return self
153
235
 
154
- def using_key_lookup(self, key_lookup: KeyLookup) -> Jobs:
236
+ def using_key_lookup(self, key_lookup: 'KeyLookup') -> Jobs:
155
237
  """
156
238
  Add a KeyLookup to the job.
157
239
 
@@ -166,8 +248,8 @@ class Jobs(Base):
166
248
 
167
249
  :param obj: the object to add
168
250
  """
169
- from edsl.data.Cache import Cache
170
- from edsl.language_models.key_management.KeyLookup import KeyLookup
251
+ from ..caching import Cache
252
+ from ..key_management import KeyLookup
171
253
 
172
254
  if isinstance(obj, Cache):
173
255
  self.using_cache(obj)
@@ -183,7 +265,7 @@ class Jobs(Base):
183
265
 
184
266
  @models.setter
185
267
  def models(self, value):
186
- from edsl.language_models.ModelList import ModelList
268
+ from ..language_models import ModelList
187
269
 
188
270
  if value:
189
271
  if not isinstance(value, ModelList):
@@ -205,7 +287,7 @@ class Jobs(Base):
205
287
 
206
288
  @agents.setter
207
289
  def agents(self, value):
208
- from edsl.agents.AgentList import AgentList
290
+ from ..agents import AgentList
209
291
 
210
292
  if value:
211
293
  if not isinstance(value, AgentList):
@@ -215,14 +297,23 @@ class Jobs(Base):
215
297
  else:
216
298
  self._agents = AgentList([])
217
299
 
300
+ def where(self, expression: str) -> Jobs:
301
+ """
302
+ Filter the agents, scenarios, and models based on a condition.
303
+
304
+ :param expression: a condition to filter the agents, scenarios, and models
305
+ """
306
+ self._where_clauses.append(expression)
307
+ return self
308
+
218
309
  @property
219
310
  def scenarios(self):
220
311
  return self._scenarios
221
312
 
222
313
  @scenarios.setter
223
314
  def scenarios(self, value):
224
- from edsl.scenarios.ScenarioList import ScenarioList
225
- from edsl.results.Dataset import Dataset
315
+ from ..scenarios import ScenarioList
316
+ from ..dataset import Dataset
226
317
 
227
318
  if value:
228
319
  if isinstance(
@@ -240,40 +331,58 @@ class Jobs(Base):
240
331
  def by(
241
332
  self,
242
333
  *args: Union[
243
- Agent,
244
- Scenario,
245
- LanguageModel,
334
+ "Agent",
335
+ "Scenario",
336
+ "LanguageModel",
246
337
  Sequence[Union["Agent", "Scenario", "LanguageModel"]],
247
338
  ],
248
- ) -> Jobs:
249
- """
250
- Add Agents, Scenarios and LanguageModels to a job.
251
-
252
- :param args: objects or a sequence (list, tuple, ...) of objects of the same type
253
-
254
- If no objects of this type exist in the Jobs instance, it stores the new objects as a list in the corresponding attribute.
255
- Otherwise, it combines the new objects with existing objects using the object's `__add__` method.
256
-
257
- This 'by' is intended to create a fluent interface.
258
-
259
- >>> from edsl.surveys.Survey import Survey
260
- >>> from edsl.questions.QuestionFreeText import QuestionFreeText
261
- >>> q = QuestionFreeText(question_name="name", question_text="What is your name?")
262
- >>> j = Jobs(survey = Survey(questions=[q]))
263
- >>> j
264
- Jobs(survey=Survey(...), agents=AgentList([]), models=ModelList([]), scenarios=ScenarioList([]))
265
- >>> from edsl.agents.Agent import Agent; a = Agent(traits = {"status": "Sad"})
266
- >>> j.by(a).agents
267
- AgentList([Agent(traits = {'status': 'Sad'})])
268
-
269
-
339
+ ) -> "Jobs":
340
+ """
341
+ Add agents, scenarios, and language models to a job using a fluent interface.
342
+
343
+ This method is the primary way to configure a Jobs instance with components.
344
+ It intelligently handles different types of objects and collections, making
345
+ it easy to build complex job configurations with a concise syntax.
346
+
347
+ Parameters:
348
+ *args: Objects or sequences of objects to add to the job.
349
+ Supported types are Agent, Scenario, LanguageModel, and sequences of these.
350
+
351
+ Returns:
352
+ Jobs: The Jobs instance (self) for method chaining
353
+
354
+ Examples:
355
+ >>> from edsl.surveys import Survey
356
+ >>> from edsl.questions import QuestionFreeText
357
+ >>> q = QuestionFreeText(question_name="name", question_text="What is your name?")
358
+ >>> j = Jobs(survey = Survey(questions=[q]))
359
+ >>> j
360
+ Jobs(survey=Survey(...), agents=AgentList([]), models=ModelList([]), scenarios=ScenarioList([]))
361
+ >>> from edsl.agents import Agent; a = Agent(traits = {"status": "Sad"})
362
+ >>> j.by(a).agents
363
+ AgentList([Agent(traits = {'status': 'Sad'})])
364
+
365
+ # Adding multiple components at once
366
+ >>> from edsl.language_models import Model
367
+ >>> from edsl.scenarios import Scenario
368
+ >>> j = Jobs.example()
369
+ >>> _ = j.by(Agent(traits={"mood": "happy"})).by(Model(temperature=0.7)).by(Scenario({"time": "morning"}))
370
+
371
+ # Adding a sequence of the same type
372
+ >>> agents = [Agent(traits={"age": i}) for i in range(5)]
373
+ >>> _ = j.by(agents)
374
+
270
375
  Notes:
271
- - all objects must implement the 'get_value', 'set_value', and `__add__` methods
272
- - agents: traits of new agents are combined with traits of existing agents. New and existing agents should not have overlapping traits, and do not increase the # agents in the instance
273
- - scenarios: traits of new scenarios are combined with traits of old existing. New scenarios will overwrite overlapping traits, and do not increase the number of scenarios in the instance
274
- - models: new models overwrite old models.
376
+ - All objects must implement 'get_value', 'set_value', and '__add__' methods
377
+ - Agent traits: When adding agents with traits to existing agents, the traits are
378
+ combined. Avoid overlapping trait names to prevent unexpected behavior.
379
+ - Scenario traits: When adding scenarios with traits to existing scenarios, new
380
+ traits overwrite existing ones with the same name.
381
+ - Models: New models with the same attributes will override existing models.
382
+ - The method detects object types automatically and routes them to the appropriate
383
+ collection (agents, scenarios, or models).
275
384
  """
276
- from edsl.jobs.JobsComponentConstructor import JobsComponentConstructor
385
+ from .jobs_component_constructor import JobsComponentConstructor
277
386
 
278
387
  return JobsComponentConstructor(self).by(*args)
279
388
 
@@ -285,7 +394,7 @@ class Jobs(Base):
285
394
  >>> Jobs.example().prompts()
286
395
  Dataset(...)
287
396
  """
288
- return JobsPrompts(self).prompts(iterations=iterations)
397
+ return JobsPrompts.from_jobs(self).prompts(iterations=iterations)
289
398
 
290
399
  def show_prompts(self, all: bool = False) -> None:
291
400
  """Print the prompts."""
@@ -328,7 +437,7 @@ class Jobs(Base):
328
437
  def estimate_job_cost_from_external_prices(
329
438
  self, price_lookup: dict, iterations: int = 1
330
439
  ) -> dict:
331
- return JobsPrompts(self).estimate_job_cost_from_external_prices(
440
+ return JobsPrompts.from_jobs(self).estimate_job_cost_from_external_prices(
332
441
  price_lookup, iterations
333
442
  )
334
443
 
@@ -340,9 +449,9 @@ class Jobs(Base):
340
449
  return job_results.compute_job_cost()
341
450
 
342
451
  def replace_missing_objects(self) -> None:
343
- from edsl.agents.Agent import Agent
344
- from edsl.language_models.model import Model
345
- from edsl.scenarios.Scenario import Scenario
452
+ from ..agents import Agent
453
+ from ..language_models.model import Model
454
+ from ..scenarios import Scenario
346
455
 
347
456
  self.agents = self.agents or [Agent()]
348
457
  self.models = self.models or [Model()]
@@ -357,7 +466,7 @@ class Jobs(Base):
357
466
  with us filling in defaults.
358
467
 
359
468
  """
360
- from edsl.jobs.InterviewsConstructor import InterviewsConstructor
469
+ from .jobs_interview_constructor import InterviewsConstructor
361
470
 
362
471
  self.replace_missing_objects()
363
472
  yield from InterviewsConstructor(
@@ -365,8 +474,12 @@ class Jobs(Base):
365
474
  ).create_interviews()
366
475
 
367
476
  def show_flow(self, filename: Optional[str] = None) -> None:
368
- """Show the flow of the survey."""
369
- from edsl.surveys.SurveyFlowVisualization import SurveyFlowVisualization
477
+ """Show the flow of the survey.
478
+
479
+ >>> from edsl.jobs import Jobs
480
+ >>> Jobs.example().show_flow()
481
+ """
482
+ from ..surveys import SurveyFlowVisualization
370
483
  if self.scenarios:
371
484
  scenario = self.scenarios[0]
372
485
  else:
@@ -442,7 +555,7 @@ class Jobs(Base):
442
555
  846655441787442972
443
556
 
444
557
  """
445
- from edsl.utilities.utilities import dict_hash
558
+ from ..utilities import dict_hash
446
559
 
447
560
  return dict_hash(self.to_dict(add_edsl_version=False))
448
561
 
@@ -450,8 +563,6 @@ class Jobs(Base):
450
563
  """Check if a Job is verbose. If so, print the message."""
451
564
  if self.run_config.parameters.verbose:
452
565
  print(message)
453
- # if hasattr(self, "verbose") and self.verbose:
454
- # print(message)
455
566
 
456
567
  def all_question_parameters(self) -> set:
457
568
  """Return all the fields in the questions in the survey.
@@ -468,7 +579,7 @@ class Jobs(Base):
468
579
  return False
469
580
  if not self.run_config.parameters.disable_remote_cache:
470
581
  try:
471
- from edsl.coop.coop import Coop
582
+ from ..coop import Coop
472
583
 
473
584
  user_edsl_settings = Coop().edsl_settings
474
585
  return user_edsl_settings.get("remote_caching", False)
@@ -493,9 +604,7 @@ class Jobs(Base):
493
604
  )
494
605
  return job_info
495
606
 
496
- def _create_remote_inference_handler(self) -> JobsRemoteInferenceHandler:
497
- from edsl.jobs.JobsRemoteInferenceHandler import JobsRemoteInferenceHandler
498
-
607
+ def _create_remote_inference_handler(self) -> 'JobsRemoteInferenceHandler':
499
608
  return JobsRemoteInferenceHandler(
500
609
  self, verbose=self.run_config.parameters.verbose
501
610
  )
@@ -504,8 +613,7 @@ class Jobs(Base):
504
613
  self,
505
614
  config: RunConfig,
506
615
  ) -> Union["Results", None]:
507
- from edsl.jobs.JobsRemoteInferenceHandler import JobsRemoteInferenceHandler
508
- from edsl.jobs.JobsRemoteInferenceHandler import RemoteJobInfo
616
+ from .remote_inference import RemoteJobInfo
509
617
 
510
618
  background = config.parameters.background
511
619
 
@@ -513,7 +621,7 @@ class Jobs(Base):
513
621
  if jh.use_remote_inference(self.run_config.parameters.disable_remote_inference):
514
622
  job_info: RemoteJobInfo = self._start_remote_inference_job(jh)
515
623
  if background:
516
- from edsl.results.Results import Results
624
+ from edsl.results import Results
517
625
 
518
626
  results = Results.from_job_info(job_info)
519
627
  return results
@@ -540,9 +648,9 @@ class Jobs(Base):
540
648
  async def _execute_with_remote_cache(self, run_job_async: bool) -> Results:
541
649
  use_remote_cache = self.use_remote_cache()
542
650
 
543
- from edsl.coop.coop import Coop
544
- from edsl.jobs.runners.JobsRunnerAsyncio import JobsRunnerAsyncio
545
- from edsl.data.Cache import Cache
651
+ from ..coop import Coop
652
+ from .jobs_runner_asyncio import JobsRunnerAsyncio
653
+ from ..caching import Cache
546
654
 
547
655
  assert isinstance(self.run_config.environment.cache, Cache)
548
656
 
@@ -589,12 +697,12 @@ class Jobs(Base):
589
697
  self.run_config.environment.cache is None
590
698
  or self.run_config.environment.cache is True
591
699
  ):
592
- from edsl.data.CacheHandler import CacheHandler
700
+ from ..caching import CacheHandler
593
701
 
594
702
  self.run_config.environment.cache = CacheHandler().get_cache()
595
703
 
596
704
  if self.run_config.environment.cache is False:
597
- from edsl.data.Cache import Cache
705
+ from ..caching import Cache
598
706
 
599
707
  self.run_config.environment.cache = Cache(immediate_write=False)
600
708
 
@@ -622,21 +730,50 @@ class Jobs(Base):
622
730
  @with_config
623
731
  def run(self, *, config: RunConfig) -> "Results":
624
732
  """
625
- Runs the Job: conducts Interviews and returns their results.
626
-
627
- :param n: How many times to run each interview
628
- :param progress_bar: Whether to show a progress bar
629
- :param stop_on_exception: Stops the job if an exception is raised
630
- :param check_api_keys: Raises an error if API keys are invalid
631
- :param verbose: Prints extra messages
632
- :param remote_cache_description: Specifies a description for this group of entries in the remote cache
633
- :param remote_inference_description: Specifies a description for the remote inference job
634
- :param remote_inference_results_visibility: The initial visibility of the Results object on Coop. This will only be used for remote jobs!
635
- :param disable_remote_cache: If True, the job will not use remote cache. This only works for local jobs!
636
- :param disable_remote_inference: If True, the job will not use remote inference
637
- :param cache: A Cache object to store results
638
- :param bucket_collection: A BucketCollection object to track API calls
639
- :param key_lookup: A KeyLookup object to manage API keys
733
+ Runs the job by conducting interviews and returns their results.
734
+
735
+ This is the main entry point for executing a job. It processes all interviews
736
+ (combinations of agents, scenarios, and models) and returns a Results object
737
+ containing all responses and metadata.
738
+
739
+ Parameters:
740
+ n (int): Number of iterations to run each interview (default: 1)
741
+ progress_bar (bool): Whether to show a progress bar (default: False)
742
+ stop_on_exception (bool): Whether to stop the job if an exception is raised (default: False)
743
+ check_api_keys (bool): Whether to verify API keys before running (default: False)
744
+ verbose (bool): Whether to print extra messages during execution (default: True)
745
+ print_exceptions (bool): Whether to print exceptions as they occur (default: True)
746
+ remote_cache_description (str, optional): Description for entries in the remote cache
747
+ remote_inference_description (str, optional): Description for the remote inference job
748
+ remote_inference_results_visibility (VisibilityType): Visibility of results on Coop ("private", "public", "unlisted")
749
+ disable_remote_cache (bool): Whether to disable the remote cache (default: False)
750
+ disable_remote_inference (bool): Whether to disable remote inference (default: False)
751
+ fresh (bool): Whether to ignore cache and force new results (default: False)
752
+ skip_retry (bool): Whether to skip retrying failed interviews (default: False)
753
+ raise_validation_errors (bool): Whether to raise validation errors (default: False)
754
+ background (bool): Whether to run in background mode (default: False)
755
+ job_uuid (str, optional): UUID for the job, used for tracking
756
+ cache (Cache, optional): Cache object to store results
757
+ bucket_collection (BucketCollection, optional): Object to track API calls
758
+ key_lookup (KeyLookup, optional): Object to manage API keys
759
+
760
+ Returns:
761
+ Results: A Results object containing all responses and metadata
762
+
763
+ Notes:
764
+ - This method will first try to use remote inference if available
765
+ - If remote inference is not available, it will run locally
766
+ - For long-running jobs, consider using progress_bar=True
767
+ - For maximum performance, ensure appropriate caching is configured
768
+
769
+ Example:
770
+ >>> from edsl.jobs import Jobs
771
+ >>> from edsl.caching import Cache
772
+ >>> job = Jobs.example()
773
+ >>> from edsl import Model
774
+ >>> m = Model('test')
775
+ >>> results = job.by(m).run(cache=Cache(), progress_bar=False, n=2, disable_remote_inference=True)
776
+ ...
640
777
  """
641
778
  potentially_completed_results = self._run(config)
642
779
 
@@ -648,21 +785,50 @@ class Jobs(Base):
648
785
  @with_config
649
786
  async def run_async(self, *, config: RunConfig) -> "Results":
650
787
  """
651
- Runs the Job: conducts Interviews and returns their results.
652
-
653
- :param n: How many times to run each interview
654
- :param progress_bar: Whether to show a progress bar
655
- :param stop_on_exception: Stops the job if an exception is raised
656
- :param check_api_keys: Raises an error if API keys are invalid
657
- :param verbose: Prints extra messages
658
- :param remote_cache_description: Specifies a description for this group of entries in the remote cache
659
- :param remote_inference_description: Specifies a description for the remote inference job
660
- :param remote_inference_results_visibility: The initial visibility of the Results object on Coop. This will only be used for remote jobs!
661
- :param disable_remote_cache: If True, the job will not use remote cache. This only works for local jobs!
662
- :param disable_remote_inference: If True, the job will not use remote inference
663
- :param cache: A Cache object to store results
664
- :param bucket_collection: A BucketCollection object to track API calls
665
- :param key_lookup: A KeyLookup object to manage API keys
788
+ Asynchronously runs the job by conducting interviews and returns their results.
789
+
790
+ This method is the asynchronous version of `run()`. It has the same functionality and
791
+ parameters but can be awaited in an async context for better integration with
792
+ asynchronous code.
793
+
794
+ Parameters:
795
+ n (int): Number of iterations to run each interview (default: 1)
796
+ progress_bar (bool): Whether to show a progress bar (default: False)
797
+ stop_on_exception (bool): Whether to stop the job if an exception is raised (default: False)
798
+ check_api_keys (bool): Whether to verify API keys before running (default: False)
799
+ verbose (bool): Whether to print extra messages during execution (default: True)
800
+ print_exceptions (bool): Whether to print exceptions as they occur (default: True)
801
+ remote_cache_description (str, optional): Description for entries in the remote cache
802
+ remote_inference_description (str, optional): Description for the remote inference job
803
+ remote_inference_results_visibility (VisibilityType): Visibility of results on Coop ("private", "public", "unlisted")
804
+ disable_remote_cache (bool): Whether to disable the remote cache (default: False)
805
+ disable_remote_inference (bool): Whether to disable remote inference (default: False)
806
+ fresh (bool): Whether to ignore cache and force new results (default: False)
807
+ skip_retry (bool): Whether to skip retrying failed interviews (default: False)
808
+ raise_validation_errors (bool): Whether to raise validation errors (default: False)
809
+ background (bool): Whether to run in background mode (default: False)
810
+ job_uuid (str, optional): UUID for the job, used for tracking
811
+ cache (Cache, optional): Cache object to store results
812
+ bucket_collection (BucketCollection, optional): Object to track API calls
813
+ key_lookup (KeyLookup, optional): Object to manage API keys
814
+
815
+ Returns:
816
+ Results: A Results object containing all responses and metadata
817
+
818
+ Notes:
819
+ - This method should be used in async contexts (e.g., with `await`)
820
+ - For non-async contexts, use the `run()` method instead
821
+ - This method is particularly useful in notebook environments or async applications
822
+
823
+ Example:
824
+ >>> import asyncio
825
+ >>> from edsl.jobs import Jobs
826
+ >>> from edsl.caching import Cache
827
+ >>> job = Jobs.example()
828
+ >>> # In an async context
829
+ >>> async def run_job():
830
+ ... results = await job.run_async(cache=Cache(), progress_bar=True)
831
+ ... return results
666
832
  """
667
833
  self._run(config)
668
834
 
@@ -726,10 +892,10 @@ class Jobs(Base):
726
892
  @remove_edsl_version
727
893
  def from_dict(cls, data: dict) -> Jobs:
728
894
  """Creates a Jobs instance from a dictionary."""
729
- from edsl.surveys.Survey import Survey
730
- from edsl.agents.Agent import Agent
731
- from edsl.language_models.LanguageModel import LanguageModel
732
- from edsl.scenarios.Scenario import Scenario
895
+ from ..surveys import Survey
896
+ from ..agents import Agent
897
+ from ..language_models import LanguageModel
898
+ from ..scenarios import Scenario
733
899
 
734
900
  return cls(
735
901
  survey=Survey.from_dict(data["survey"]),
@@ -767,14 +933,14 @@ class Jobs(Base):
767
933
  """
768
934
  import random
769
935
  from uuid import uuid4
770
- from edsl.questions.QuestionMultipleChoice import QuestionMultipleChoice
771
- from edsl.agents.Agent import Agent
772
- from edsl.scenarios.Scenario import Scenario
936
+ from ..questions import QuestionMultipleChoice
937
+ from ..agents import Agent
938
+ from ..scenarios import Scenario
773
939
 
774
940
  addition = "" if not randomize else str(uuid4())
775
941
 
776
942
  if test_model:
777
- from edsl.language_models.LanguageModel import LanguageModel
943
+ from ..language_models import LanguageModel
778
944
 
779
945
  m = LanguageModel.example(test_model=True)
780
946
 
@@ -815,8 +981,8 @@ class Jobs(Base):
815
981
  question_options=["Good", "Great", "OK", "Terrible"],
816
982
  question_name="how_feeling_yesterday",
817
983
  )
818
- from edsl.surveys.Survey import Survey
819
- from edsl.scenarios.ScenarioList import ScenarioList
984
+ from ..surveys import Survey
985
+ from ..scenarios import ScenarioList
820
986
 
821
987
  base_survey = Survey(questions=[q1, q2])
822
988
 
@@ -840,8 +1006,8 @@ class Jobs(Base):
840
1006
 
841
1007
  def main():
842
1008
  """Run the module's doctests."""
843
- from edsl.jobs.Jobs import Jobs
844
- from edsl.data.Cache import Cache
1009
+ from .jobs import Jobs
1010
+ from ..caching import Cache
845
1011
 
846
1012
  job = Jobs.example()
847
1013
  len(job) == 4