edsl 0.1.14__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.
- edsl/Base.py +348 -38
- edsl/BaseDiff.py +260 -0
- edsl/TemplateLoader.py +24 -0
- edsl/__init__.py +46 -10
- edsl/__version__.py +1 -0
- edsl/agents/Agent.py +842 -144
- edsl/agents/AgentList.py +521 -25
- edsl/agents/Invigilator.py +250 -374
- edsl/agents/InvigilatorBase.py +257 -0
- edsl/agents/PromptConstructor.py +272 -0
- edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
- edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
- edsl/agents/descriptors.py +43 -13
- edsl/agents/prompt_helpers.py +129 -0
- edsl/agents/question_option_processor.py +172 -0
- edsl/auto/AutoStudy.py +130 -0
- edsl/auto/StageBase.py +243 -0
- edsl/auto/StageGenerateSurvey.py +178 -0
- edsl/auto/StageLabelQuestions.py +125 -0
- edsl/auto/StagePersona.py +61 -0
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
- edsl/auto/StagePersonaDimensionValues.py +74 -0
- edsl/auto/StagePersonaDimensions.py +69 -0
- edsl/auto/StageQuestions.py +74 -0
- edsl/auto/SurveyCreatorPipeline.py +21 -0
- edsl/auto/utilities.py +218 -0
- edsl/base/Base.py +279 -0
- edsl/config.py +121 -104
- edsl/conversation/Conversation.py +290 -0
- edsl/conversation/car_buying.py +59 -0
- edsl/conversation/chips.py +95 -0
- edsl/conversation/mug_negotiation.py +81 -0
- edsl/conversation/next_speaker_utilities.py +93 -0
- edsl/coop/CoopFunctionsMixin.py +15 -0
- edsl/coop/ExpectedParrotKeyHandler.py +125 -0
- edsl/coop/PriceFetcher.py +54 -0
- edsl/coop/__init__.py +1 -0
- edsl/coop/coop.py +1029 -134
- edsl/coop/utils.py +131 -0
- edsl/data/Cache.py +560 -89
- edsl/data/CacheEntry.py +230 -0
- edsl/data/CacheHandler.py +168 -0
- edsl/data/RemoteCacheSync.py +186 -0
- edsl/data/SQLiteDict.py +292 -0
- edsl/data/__init__.py +5 -3
- edsl/data/orm.py +6 -33
- edsl/data_transfer_models.py +74 -27
- edsl/enums.py +165 -8
- edsl/exceptions/BaseException.py +21 -0
- edsl/exceptions/__init__.py +52 -46
- edsl/exceptions/agents.py +33 -15
- edsl/exceptions/cache.py +5 -0
- edsl/exceptions/coop.py +8 -0
- edsl/exceptions/general.py +34 -0
- edsl/exceptions/inference_services.py +5 -0
- edsl/exceptions/jobs.py +15 -0
- edsl/exceptions/language_models.py +46 -1
- edsl/exceptions/questions.py +80 -5
- edsl/exceptions/results.py +16 -5
- edsl/exceptions/scenarios.py +29 -0
- edsl/exceptions/surveys.py +13 -10
- edsl/inference_services/AnthropicService.py +106 -0
- edsl/inference_services/AvailableModelCacheHandler.py +184 -0
- edsl/inference_services/AvailableModelFetcher.py +215 -0
- edsl/inference_services/AwsBedrock.py +118 -0
- edsl/inference_services/AzureAI.py +215 -0
- edsl/inference_services/DeepInfraService.py +18 -0
- edsl/inference_services/GoogleService.py +143 -0
- edsl/inference_services/GroqService.py +20 -0
- edsl/inference_services/InferenceServiceABC.py +80 -0
- edsl/inference_services/InferenceServicesCollection.py +138 -0
- edsl/inference_services/MistralAIService.py +120 -0
- edsl/inference_services/OllamaService.py +18 -0
- edsl/inference_services/OpenAIService.py +236 -0
- edsl/inference_services/PerplexityService.py +160 -0
- edsl/inference_services/ServiceAvailability.py +135 -0
- edsl/inference_services/TestService.py +90 -0
- edsl/inference_services/TogetherAIService.py +172 -0
- edsl/inference_services/data_structures.py +134 -0
- edsl/inference_services/models_available_cache.py +118 -0
- edsl/inference_services/rate_limits_cache.py +25 -0
- edsl/inference_services/registry.py +41 -0
- edsl/inference_services/write_available.py +10 -0
- edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
- edsl/jobs/Answers.py +21 -20
- edsl/jobs/FetchInvigilator.py +47 -0
- edsl/jobs/InterviewTaskManager.py +98 -0
- edsl/jobs/InterviewsConstructor.py +50 -0
- edsl/jobs/Jobs.py +684 -204
- edsl/jobs/JobsChecks.py +172 -0
- edsl/jobs/JobsComponentConstructor.py +189 -0
- edsl/jobs/JobsPrompts.py +270 -0
- edsl/jobs/JobsRemoteInferenceHandler.py +311 -0
- edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
- edsl/jobs/RequestTokenEstimator.py +30 -0
- edsl/jobs/async_interview_runner.py +138 -0
- edsl/jobs/buckets/BucketCollection.py +104 -0
- edsl/jobs/buckets/ModelBuckets.py +65 -0
- edsl/jobs/buckets/TokenBucket.py +283 -0
- edsl/jobs/buckets/TokenBucketAPI.py +211 -0
- edsl/jobs/buckets/TokenBucketClient.py +191 -0
- edsl/jobs/check_survey_scenario_compatibility.py +85 -0
- edsl/jobs/data_structures.py +120 -0
- edsl/jobs/decorators.py +35 -0
- edsl/jobs/interviews/Interview.py +392 -0
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -0
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -0
- edsl/jobs/interviews/InterviewStatistic.py +63 -0
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -0
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -0
- edsl/jobs/interviews/InterviewStatusLog.py +92 -0
- edsl/jobs/interviews/ReportErrors.py +66 -0
- edsl/jobs/interviews/interview_status_enum.py +9 -0
- edsl/jobs/jobs_status_enums.py +9 -0
- edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
- edsl/jobs/results_exceptions_handler.py +98 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +151 -110
- edsl/jobs/runners/JobsRunnerStatus.py +298 -0
- edsl/jobs/tasks/QuestionTaskCreator.py +244 -0
- edsl/jobs/tasks/TaskCreators.py +64 -0
- edsl/jobs/tasks/TaskHistory.py +470 -0
- edsl/jobs/tasks/TaskStatusLog.py +23 -0
- edsl/jobs/tasks/task_status_enum.py +161 -0
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -0
- edsl/jobs/tokens/TokenUsage.py +34 -0
- edsl/language_models/ComputeCost.py +63 -0
- edsl/language_models/LanguageModel.py +507 -386
- edsl/language_models/ModelList.py +164 -0
- edsl/language_models/PriceManager.py +127 -0
- edsl/language_models/RawResponseHandler.py +106 -0
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -0
- edsl/language_models/__init__.py +1 -8
- edsl/language_models/fake_openai_call.py +15 -0
- edsl/language_models/fake_openai_service.py +61 -0
- edsl/language_models/key_management/KeyLookup.py +63 -0
- edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
- edsl/language_models/key_management/KeyLookupCollection.py +38 -0
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +131 -0
- edsl/language_models/model.py +256 -0
- edsl/language_models/repair.py +109 -41
- edsl/language_models/utilities.py +65 -0
- edsl/notebooks/Notebook.py +263 -0
- edsl/notebooks/NotebookToLaTeX.py +142 -0
- edsl/notebooks/__init__.py +1 -0
- edsl/prompts/Prompt.py +222 -93
- edsl/prompts/__init__.py +1 -1
- edsl/questions/ExceptionExplainer.py +77 -0
- edsl/questions/HTMLQuestion.py +103 -0
- edsl/questions/QuestionBase.py +518 -0
- edsl/questions/QuestionBasePromptsMixin.py +221 -0
- edsl/questions/QuestionBudget.py +164 -67
- edsl/questions/QuestionCheckBox.py +281 -62
- edsl/questions/QuestionDict.py +343 -0
- edsl/questions/QuestionExtract.py +136 -50
- edsl/questions/QuestionFreeText.py +79 -55
- edsl/questions/QuestionFunctional.py +138 -41
- edsl/questions/QuestionList.py +184 -57
- edsl/questions/QuestionMatrix.py +265 -0
- edsl/questions/QuestionMultipleChoice.py +293 -69
- edsl/questions/QuestionNumerical.py +109 -56
- edsl/questions/QuestionRank.py +244 -49
- edsl/questions/Quick.py +41 -0
- edsl/questions/SimpleAskMixin.py +74 -0
- edsl/questions/__init__.py +9 -6
- edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +153 -38
- edsl/questions/compose_questions.py +13 -7
- edsl/questions/data_structures.py +20 -0
- edsl/questions/decorators.py +21 -0
- edsl/questions/derived/QuestionLikertFive.py +28 -26
- edsl/questions/derived/QuestionLinearScale.py +41 -28
- edsl/questions/derived/QuestionTopK.py +34 -26
- edsl/questions/derived/QuestionYesNo.py +40 -27
- edsl/questions/descriptors.py +228 -74
- edsl/questions/loop_processor.py +149 -0
- edsl/questions/prompt_templates/question_budget.jinja +13 -0
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
- edsl/questions/prompt_templates/question_extract.jinja +11 -0
- edsl/questions/prompt_templates/question_free_text.jinja +3 -0
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
- edsl/questions/prompt_templates/question_list.jinja +17 -0
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
- edsl/questions/prompt_templates/question_numerical.jinja +37 -0
- edsl/questions/question_base_gen_mixin.py +168 -0
- edsl/questions/question_registry.py +130 -46
- edsl/questions/register_questions_meta.py +71 -0
- edsl/questions/response_validator_abc.py +188 -0
- edsl/questions/response_validator_factory.py +34 -0
- edsl/questions/settings.py +5 -2
- edsl/questions/templates/__init__.py +0 -0
- edsl/questions/templates/budget/__init__.py +0 -0
- edsl/questions/templates/budget/answering_instructions.jinja +7 -0
- edsl/questions/templates/budget/question_presentation.jinja +7 -0
- edsl/questions/templates/checkbox/__init__.py +0 -0
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
- edsl/questions/templates/dict/__init__.py +0 -0
- edsl/questions/templates/dict/answering_instructions.jinja +21 -0
- edsl/questions/templates/dict/question_presentation.jinja +1 -0
- edsl/questions/templates/extract/__init__.py +0 -0
- edsl/questions/templates/extract/answering_instructions.jinja +7 -0
- edsl/questions/templates/extract/question_presentation.jinja +1 -0
- edsl/questions/templates/free_text/__init__.py +0 -0
- edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
- edsl/questions/templates/free_text/question_presentation.jinja +1 -0
- edsl/questions/templates/likert_five/__init__.py +0 -0
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
- edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
- edsl/questions/templates/linear_scale/__init__.py +0 -0
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
- edsl/questions/templates/list/__init__.py +0 -0
- edsl/questions/templates/list/answering_instructions.jinja +4 -0
- edsl/questions/templates/list/question_presentation.jinja +5 -0
- edsl/questions/templates/matrix/__init__.py +1 -0
- edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
- edsl/questions/templates/matrix/question_presentation.jinja +20 -0
- edsl/questions/templates/multiple_choice/__init__.py +0 -0
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
- edsl/questions/templates/multiple_choice/html.jinja +0 -0
- edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
- edsl/questions/templates/numerical/__init__.py +0 -0
- edsl/questions/templates/numerical/answering_instructions.jinja +7 -0
- edsl/questions/templates/numerical/question_presentation.jinja +7 -0
- edsl/questions/templates/rank/__init__.py +0 -0
- edsl/questions/templates/rank/answering_instructions.jinja +11 -0
- edsl/questions/templates/rank/question_presentation.jinja +15 -0
- edsl/questions/templates/top_k/__init__.py +0 -0
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
- edsl/questions/templates/top_k/question_presentation.jinja +22 -0
- edsl/questions/templates/yes_no/__init__.py +0 -0
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
- edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
- edsl/results/CSSParameterizer.py +108 -0
- edsl/results/Dataset.py +550 -19
- edsl/results/DatasetExportMixin.py +594 -0
- edsl/results/DatasetTree.py +295 -0
- edsl/results/MarkdownToDocx.py +122 -0
- edsl/results/MarkdownToPDF.py +111 -0
- edsl/results/Result.py +477 -173
- edsl/results/Results.py +987 -269
- edsl/results/ResultsExportMixin.py +28 -125
- edsl/results/ResultsGGMixin.py +83 -15
- edsl/results/TableDisplay.py +125 -0
- edsl/results/TextEditor.py +50 -0
- edsl/results/__init__.py +1 -1
- edsl/results/file_exports.py +252 -0
- edsl/results/results_fetch_mixin.py +33 -0
- edsl/results/results_selector.py +145 -0
- edsl/results/results_tools_mixin.py +98 -0
- edsl/results/smart_objects.py +96 -0
- edsl/results/table_data_class.py +12 -0
- edsl/results/table_display.css +78 -0
- edsl/results/table_renderers.py +118 -0
- edsl/results/tree_explore.py +115 -0
- edsl/scenarios/ConstructDownloadLink.py +109 -0
- edsl/scenarios/DocumentChunker.py +102 -0
- edsl/scenarios/DocxScenario.py +16 -0
- edsl/scenarios/FileStore.py +543 -0
- edsl/scenarios/PdfExtractor.py +40 -0
- edsl/scenarios/Scenario.py +431 -62
- edsl/scenarios/ScenarioHtmlMixin.py +65 -0
- edsl/scenarios/ScenarioList.py +1415 -45
- edsl/scenarios/ScenarioListExportMixin.py +45 -0
- edsl/scenarios/ScenarioListPdfMixin.py +239 -0
- edsl/scenarios/__init__.py +2 -0
- edsl/scenarios/directory_scanner.py +96 -0
- edsl/scenarios/file_methods.py +85 -0
- edsl/scenarios/handlers/__init__.py +13 -0
- edsl/scenarios/handlers/csv.py +49 -0
- edsl/scenarios/handlers/docx.py +76 -0
- edsl/scenarios/handlers/html.py +37 -0
- edsl/scenarios/handlers/json.py +111 -0
- edsl/scenarios/handlers/latex.py +5 -0
- edsl/scenarios/handlers/md.py +51 -0
- edsl/scenarios/handlers/pdf.py +68 -0
- edsl/scenarios/handlers/png.py +39 -0
- edsl/scenarios/handlers/pptx.py +105 -0
- edsl/scenarios/handlers/py.py +294 -0
- edsl/scenarios/handlers/sql.py +313 -0
- edsl/scenarios/handlers/sqlite.py +149 -0
- edsl/scenarios/handlers/txt.py +33 -0
- edsl/scenarios/scenario_join.py +131 -0
- edsl/scenarios/scenario_selector.py +156 -0
- edsl/shared.py +1 -0
- edsl/study/ObjectEntry.py +173 -0
- edsl/study/ProofOfWork.py +113 -0
- edsl/study/SnapShot.py +80 -0
- edsl/study/Study.py +521 -0
- edsl/study/__init__.py +4 -0
- edsl/surveys/ConstructDAG.py +92 -0
- edsl/surveys/DAG.py +92 -11
- edsl/surveys/EditSurvey.py +221 -0
- edsl/surveys/InstructionHandler.py +100 -0
- edsl/surveys/Memory.py +9 -4
- edsl/surveys/MemoryManagement.py +72 -0
- edsl/surveys/MemoryPlan.py +156 -35
- edsl/surveys/Rule.py +221 -74
- edsl/surveys/RuleCollection.py +241 -61
- edsl/surveys/RuleManager.py +172 -0
- edsl/surveys/Simulator.py +75 -0
- edsl/surveys/Survey.py +1079 -339
- edsl/surveys/SurveyCSS.py +273 -0
- edsl/surveys/SurveyExportMixin.py +235 -40
- edsl/surveys/SurveyFlowVisualization.py +181 -0
- edsl/surveys/SurveyQualtricsImport.py +284 -0
- edsl/surveys/SurveyToApp.py +141 -0
- edsl/surveys/__init__.py +4 -2
- edsl/surveys/base.py +19 -3
- edsl/surveys/descriptors.py +17 -6
- edsl/surveys/instructions/ChangeInstruction.py +48 -0
- edsl/surveys/instructions/Instruction.py +56 -0
- edsl/surveys/instructions/InstructionCollection.py +82 -0
- edsl/surveys/instructions/__init__.py +0 -0
- edsl/templates/error_reporting/base.html +24 -0
- edsl/templates/error_reporting/exceptions_by_model.html +35 -0
- edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
- edsl/templates/error_reporting/exceptions_by_type.html +17 -0
- edsl/templates/error_reporting/interview_details.html +116 -0
- edsl/templates/error_reporting/interviews.html +19 -0
- edsl/templates/error_reporting/overview.html +5 -0
- edsl/templates/error_reporting/performance_plot.html +2 -0
- edsl/templates/error_reporting/report.css +74 -0
- edsl/templates/error_reporting/report.html +118 -0
- edsl/templates/error_reporting/report.js +25 -0
- edsl/tools/__init__.py +1 -0
- edsl/tools/clusters.py +192 -0
- edsl/tools/embeddings.py +27 -0
- edsl/tools/embeddings_plotting.py +118 -0
- edsl/tools/plotting.py +112 -0
- edsl/tools/summarize.py +18 -0
- edsl/utilities/PrettyList.py +56 -0
- edsl/utilities/SystemInfo.py +5 -0
- edsl/utilities/__init__.py +21 -20
- edsl/utilities/ast_utilities.py +3 -0
- edsl/utilities/data/Registry.py +2 -0
- edsl/utilities/decorators.py +41 -0
- edsl/utilities/gcp_bucket/__init__.py +0 -0
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -0
- edsl/utilities/interface.py +310 -60
- edsl/utilities/is_notebook.py +18 -0
- edsl/utilities/is_valid_variable_name.py +11 -0
- edsl/utilities/naming_utilities.py +263 -0
- edsl/utilities/remove_edsl_version.py +24 -0
- edsl/utilities/repair_functions.py +28 -0
- edsl/utilities/restricted_python.py +70 -0
- edsl/utilities/utilities.py +203 -13
- edsl-0.1.40.dist-info/METADATA +111 -0
- edsl-0.1.40.dist-info/RECORD +362 -0
- {edsl-0.1.14.dist-info → edsl-0.1.40.dist-info}/WHEEL +1 -1
- edsl/agents/AgentListExportMixin.py +0 -24
- edsl/coop/old.py +0 -31
- edsl/data/Database.py +0 -141
- edsl/data/crud.py +0 -121
- edsl/jobs/Interview.py +0 -417
- edsl/jobs/JobsRunner.py +0 -63
- edsl/jobs/JobsRunnerStatusMixin.py +0 -115
- edsl/jobs/base.py +0 -47
- edsl/jobs/buckets.py +0 -166
- edsl/jobs/runners/JobsRunnerDryRun.py +0 -19
- edsl/jobs/runners/JobsRunnerStreaming.py +0 -54
- edsl/jobs/task_management.py +0 -218
- edsl/jobs/token_tracking.py +0 -78
- edsl/language_models/DeepInfra.py +0 -69
- edsl/language_models/OpenAI.py +0 -98
- edsl/language_models/model_interfaces/GeminiPro.py +0 -66
- edsl/language_models/model_interfaces/LanguageModelOpenAIFour.py +0 -8
- edsl/language_models/model_interfaces/LanguageModelOpenAIThreeFiveTurbo.py +0 -8
- edsl/language_models/model_interfaces/LlamaTwo13B.py +0 -21
- edsl/language_models/model_interfaces/LlamaTwo70B.py +0 -21
- edsl/language_models/model_interfaces/Mixtral8x7B.py +0 -24
- edsl/language_models/registry.py +0 -81
- edsl/language_models/schemas.py +0 -15
- edsl/language_models/unused/ReplicateBase.py +0 -83
- edsl/prompts/QuestionInstructionsBase.py +0 -6
- edsl/prompts/library/agent_instructions.py +0 -29
- edsl/prompts/library/agent_persona.py +0 -17
- edsl/prompts/library/question_budget.py +0 -26
- edsl/prompts/library/question_checkbox.py +0 -32
- edsl/prompts/library/question_extract.py +0 -19
- edsl/prompts/library/question_freetext.py +0 -14
- edsl/prompts/library/question_linear_scale.py +0 -20
- edsl/prompts/library/question_list.py +0 -22
- edsl/prompts/library/question_multiple_choice.py +0 -44
- edsl/prompts/library/question_numerical.py +0 -31
- edsl/prompts/library/question_rank.py +0 -21
- edsl/prompts/prompt_config.py +0 -33
- edsl/prompts/registry.py +0 -185
- edsl/questions/Question.py +0 -240
- edsl/report/InputOutputDataTypes.py +0 -134
- edsl/report/RegressionMixin.py +0 -28
- edsl/report/ReportOutputs.py +0 -1228
- edsl/report/ResultsFetchMixin.py +0 -106
- edsl/report/ResultsOutputMixin.py +0 -14
- edsl/report/demo.ipynb +0 -645
- edsl/results/ResultsDBMixin.py +0 -184
- edsl/surveys/SurveyFlowVisualizationMixin.py +0 -92
- edsl/trackers/Tracker.py +0 -91
- edsl/trackers/TrackerAPI.py +0 -196
- edsl/trackers/TrackerTasks.py +0 -70
- edsl/utilities/pastebin.py +0 -141
- edsl-0.1.14.dist-info/METADATA +0 -69
- edsl-0.1.14.dist-info/RECORD +0 -141
- /edsl/{language_models/model_interfaces → inference_services}/__init__.py +0 -0
- /edsl/{report/__init__.py → jobs/runners/JobsRunnerStatusData.py} +0 -0
- /edsl/{trackers/__init__.py → language_models/ServiceDataSources.py} +0 -0
- {edsl-0.1.14.dist-info → edsl-0.1.40.dist-info}/LICENSE +0 -0
edsl/agents/Invigilator.py
CHANGED
@@ -1,409 +1,285 @@
|
|
1
|
-
|
2
|
-
import asyncio
|
3
|
-
import json
|
4
|
-
from typing import Coroutine, Dict, Any
|
5
|
-
from collections import UserDict
|
6
|
-
|
7
|
-
from edsl.exceptions import AgentRespondedWithBadJSONError
|
8
|
-
from edsl.prompts.Prompt import Prompt
|
9
|
-
from edsl.utilities.decorators import sync_wrapper, jupyter_nb_handler
|
10
|
-
from edsl.prompts.registry import get_classes
|
11
|
-
from edsl.exceptions import QuestionScenarioRenderError
|
12
|
-
|
13
|
-
from edsl.data_transfer_models import AgentResponseDict
|
14
|
-
from edsl.exceptions.agents import FailedTaskException
|
15
|
-
|
16
|
-
|
17
|
-
class InvigilatorBase(ABC):
|
18
|
-
"""An invigiator (someone who administers an exam) is a class that is responsible for administering a question to an agent."""
|
19
|
-
|
20
|
-
def __init__(
|
21
|
-
self, agent, question, scenario, model, memory_plan, current_answers: dict
|
22
|
-
):
|
23
|
-
self.agent = agent
|
24
|
-
self.question = question
|
25
|
-
self.scenario = scenario
|
26
|
-
self.model = model
|
27
|
-
self.memory_plan = memory_plan
|
28
|
-
self.current_answers = current_answers
|
29
|
-
|
30
|
-
def get_failed_task_result(self):
|
31
|
-
return AgentResponseDict(
|
32
|
-
answer=None,
|
33
|
-
comment="Failed to get response",
|
34
|
-
question_name=self.question.question_name,
|
35
|
-
prompts=self.get_prompts(),
|
36
|
-
)
|
37
|
-
|
38
|
-
def get_prompts(self) -> Dict[str, Prompt]:
|
39
|
-
return {
|
40
|
-
"user_prompt": Prompt("NA").text,
|
41
|
-
"system_prompt": Prompt("NA").text,
|
42
|
-
}
|
1
|
+
"""Module for creating Invigilators, which are objects to administer a question to an Agent."""
|
43
2
|
|
44
|
-
|
45
|
-
def example(cls):
|
46
|
-
"""Returns an example invigilator."""
|
47
|
-
from edsl.agents.Agent import Agent
|
48
|
-
from edsl.questions import QuestionMultipleChoice
|
49
|
-
from edsl.scenarios.Scenario import Scenario
|
50
|
-
from edsl.language_models import LanguageModel
|
51
|
-
|
52
|
-
from edsl.enums import LanguageModelType, InferenceServiceType
|
53
|
-
|
54
|
-
class TestLanguageModelGood(LanguageModel):
|
55
|
-
_model_ = LanguageModelType.TEST.value
|
56
|
-
_parameters_ = {"temperature": 0.5}
|
57
|
-
_inference_service_ = InferenceServiceType.TEST.value
|
58
|
-
|
59
|
-
async def async_execute_model_call(
|
60
|
-
self, user_prompt: str, system_prompt: str
|
61
|
-
) -> dict[str, Any]:
|
62
|
-
await asyncio.sleep(0.1)
|
63
|
-
return {"message": """{"answer": "SPAM!"}"""}
|
64
|
-
|
65
|
-
def parse_response(self, raw_response: dict[str, Any]) -> str:
|
66
|
-
return raw_response["message"]
|
67
|
-
|
68
|
-
model = TestLanguageModelGood()
|
69
|
-
agent = Agent.example()
|
70
|
-
question = QuestionMultipleChoice.example()
|
71
|
-
scenario = Scenario.example()
|
72
|
-
# model = LanguageModel.example()
|
73
|
-
memory_plan = None
|
74
|
-
current_answers = None
|
75
|
-
return cls(
|
76
|
-
agent=agent,
|
77
|
-
question=question,
|
78
|
-
scenario=scenario,
|
79
|
-
model=model,
|
80
|
-
memory_plan=memory_plan,
|
81
|
-
current_answers=current_answers,
|
82
|
-
)
|
3
|
+
from typing import Dict, Any, Optional, TYPE_CHECKING
|
83
4
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
5
|
+
from edsl.utilities.decorators import sync_wrapper
|
6
|
+
from edsl.exceptions.questions import QuestionAnswerValidationError
|
7
|
+
from edsl.agents.InvigilatorBase import InvigilatorBase
|
8
|
+
from edsl.data_transfer_models import AgentResponseDict, EDSLResultObjectInput
|
88
9
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
return results[0] # Since there's only one task, return its result
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from edsl.prompts.Prompt import Prompt
|
12
|
+
from edsl.scenarios.Scenario import Scenario
|
13
|
+
from edsl.surveys.Survey import Survey
|
94
14
|
|
95
|
-
return main()
|
96
15
|
|
97
|
-
|
98
|
-
"""Creates a memory for the agent."""
|
99
|
-
return self.memory_plan.get_memory_prompt_fragment(
|
100
|
-
question_name, self.current_answers
|
101
|
-
)
|
16
|
+
NA = "Not Applicable"
|
102
17
|
|
103
18
|
|
104
19
|
class InvigilatorAI(InvigilatorBase):
|
105
20
|
"""An invigilator that uses an AI model to answer questions."""
|
106
21
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
"question": self.question,
|
111
|
-
"scenario": self.scenario,
|
112
|
-
}
|
113
|
-
# This calls the self.async_get_response method w/ the prompts
|
114
|
-
# The raw response is a dictionary.
|
115
|
-
raw_response = await self.async_get_response(**self.get_prompts())
|
116
|
-
assert "raw_model_response" in raw_response
|
117
|
-
response = self._format_raw_response(
|
118
|
-
**(
|
119
|
-
data
|
120
|
-
| {
|
121
|
-
"raw_response": raw_response,
|
122
|
-
"raw_model_response": raw_response["raw_model_response"],
|
123
|
-
}
|
124
|
-
)
|
125
|
-
)
|
126
|
-
return response
|
22
|
+
def get_prompts(self) -> Dict[str, "Prompt"]:
|
23
|
+
"""Return the prompts used."""
|
24
|
+
return self.prompt_constructor.get_prompts()
|
127
25
|
|
128
|
-
async def
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
)
|
134
|
-
except json.JSONDecodeError as e:
|
135
|
-
raise AgentRespondedWithBadJSONError(
|
136
|
-
f"Returned bad JSON: {e}"
|
137
|
-
f"Prompt: {user_prompt}"
|
138
|
-
f"System Prompt: {system_prompt}"
|
139
|
-
)
|
140
|
-
|
141
|
-
return response
|
142
|
-
|
143
|
-
def _format_raw_response(
|
144
|
-
self, agent, question, scenario, raw_response, raw_model_response
|
145
|
-
) -> AgentResponseDict:
|
146
|
-
response = question.validate_answer(raw_response)
|
147
|
-
comment = response.get("comment", "")
|
148
|
-
answer_code = response["answer"]
|
149
|
-
answer = question.translate_answer_code_to_answer(answer_code, scenario)
|
150
|
-
raw_model_response = raw_model_response
|
151
|
-
data = {
|
152
|
-
"answer": answer,
|
153
|
-
"comment": comment,
|
154
|
-
"question_name": question.question_name,
|
155
|
-
"prompts": {k: v.to_dict() for k, v in self.get_prompts().items()},
|
156
|
-
"cached_response": raw_response["cached_response"],
|
157
|
-
"usage": raw_response.get("usage", {}),
|
158
|
-
"raw_model_response": raw_model_response,
|
26
|
+
async def async_get_agent_response(self) -> AgentResponseDict:
|
27
|
+
prompts = self.get_prompts()
|
28
|
+
params = {
|
29
|
+
"user_prompt": prompts["user_prompt"].text,
|
30
|
+
"system_prompt": prompts["system_prompt"].text,
|
159
31
|
}
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
if
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
)
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
32
|
+
if "encoded_image" in prompts:
|
33
|
+
params["encoded_image"] = prompts["encoded_image"]
|
34
|
+
raise NotImplementedError("encoded_image not implemented")
|
35
|
+
|
36
|
+
if "files_list" in prompts:
|
37
|
+
params["files_list"] = prompts["files_list"]
|
38
|
+
|
39
|
+
params.update({"iteration": self.iteration, "cache": self.cache})
|
40
|
+
params.update({"invigilator": self})
|
41
|
+
|
42
|
+
if self.key_lookup:
|
43
|
+
self.model.set_key_lookup(self.key_lookup)
|
44
|
+
|
45
|
+
return await self.model.async_get_response(**params)
|
46
|
+
|
47
|
+
def store_response(self, agent_response_dict: AgentResponseDict) -> None:
|
48
|
+
"""Store the response in the invigilator, in case it is needed later because of validation failure."""
|
49
|
+
self.raw_model_response = agent_response_dict.model_outputs.response
|
50
|
+
self.generated_tokens = agent_response_dict.edsl_dict.generated_tokens
|
51
|
+
self.cache_key = agent_response_dict.model_outputs.cache_key
|
52
|
+
|
53
|
+
async def async_answer_question(self) -> EDSLResultObjectInput:
|
54
|
+
"""Answer a question using the AI model.
|
55
|
+
|
56
|
+
>>> i = InvigilatorAI.example()
|
57
|
+
"""
|
58
|
+
agent_response_dict: AgentResponseDict = await self.async_get_agent_response()
|
59
|
+
self.store_response(agent_response_dict)
|
60
|
+
return self._extract_edsl_result_entry_and_validate(agent_response_dict)
|
61
|
+
|
62
|
+
def _remove_from_cache(self, cache_key) -> None:
|
63
|
+
"""Remove an entry from the cache."""
|
64
|
+
if cache_key:
|
65
|
+
del self.cache.data[cache_key]
|
66
|
+
|
67
|
+
def _determine_answer(self, raw_answer: str) -> Any:
|
68
|
+
"""Determine the answer from the raw answer.
|
69
|
+
|
70
|
+
>>> i = InvigilatorAI.example()
|
71
|
+
>>> i._determine_answer("SPAM!")
|
72
|
+
'SPAM!'
|
73
|
+
|
74
|
+
>>> from edsl.questions import QuestionMultipleChoice
|
75
|
+
>>> q = QuestionMultipleChoice(question_text = "How are you?", question_name = "how_are_you", question_options = ["Good", "Bad"], use_code = True)
|
76
|
+
>>> i = InvigilatorAI.example(question = q)
|
77
|
+
>>> i._determine_answer("1")
|
78
|
+
'Bad'
|
79
|
+
>>> i._determine_answer("0")
|
80
|
+
'Good'
|
81
|
+
|
82
|
+
This shows how the answer can depend on scenario details
|
83
|
+
|
84
|
+
>>> from edsl import Scenario
|
85
|
+
>>> s = Scenario({'feeling_options':['Good', 'Bad']})
|
86
|
+
>>> q = QuestionMultipleChoice(question_text = "How are you?", question_name = "how_are_you", question_options = "{{ feeling_options }}", use_code = True)
|
87
|
+
>>> i = InvigilatorAI.example(question = q, scenario = s)
|
88
|
+
>>> i._determine_answer("1")
|
89
|
+
'Bad'
|
90
|
+
|
91
|
+
>>> from edsl import QuestionList, QuestionMultipleChoice, Survey
|
92
|
+
>>> q1 = QuestionList(question_name = "favs", question_text = "What are your top 3 colors?")
|
93
|
+
>>> q2 = QuestionMultipleChoice(question_text = "What is your favorite color?", question_name = "best", question_options = "{{ favs.answer }}", use_code = True)
|
94
|
+
>>> survey = Survey([q1, q2])
|
95
|
+
>>> i = InvigilatorAI.example(question = q2, scenario = s, survey = survey)
|
96
|
+
>>> i.current_answers = {"favs": ["Green", "Blue", "Red"]}
|
97
|
+
>>> i._determine_answer("2")
|
98
|
+
'Red'
|
99
|
+
"""
|
100
|
+
substitution_dict = self._prepare_substitution_dict(
|
101
|
+
self.survey, self.current_answers, self.scenario
|
209
102
|
)
|
210
|
-
|
211
|
-
|
212
|
-
"""Gets the instructions for the question."""
|
213
|
-
applicable_prompts = get_classes(
|
214
|
-
component_type="question_instructions",
|
215
|
-
question_type=self.question.question_type,
|
216
|
-
model=self.model.model,
|
103
|
+
return self.question._translate_answer_code_to_answer(
|
104
|
+
raw_answer, substitution_dict
|
217
105
|
)
|
218
|
-
## Get the question instructions and renders with the scenario & question.data
|
219
|
-
question_prompt = applicable_prompts[0]()
|
220
106
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
"""
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
107
|
+
@staticmethod
|
108
|
+
def _prepare_substitution_dict(
|
109
|
+
survey: "Survey", current_answers: dict, scenario: "Scenario"
|
110
|
+
) -> Dict[str, Any]:
|
111
|
+
"""Prepares a substitution dictionary for the question based on the survey, current answers, and scenario.
|
112
|
+
|
113
|
+
This is necessary beause sometimes the model's answer to a question could depend on details in
|
114
|
+
the prompt that were provided by the answer to a previous question or a scenario detail.
|
115
|
+
|
116
|
+
Note that the question object is getting the answer & a the comment appended to it, as the
|
117
|
+
jinja2 template might be referencing these values with a dot notation.
|
118
|
+
|
119
|
+
"""
|
120
|
+
question_dict = survey.duplicate().question_names_to_questions()
|
121
|
+
|
122
|
+
# iterates through the current answers and updates the question_dict (which is all questions)
|
123
|
+
for other_question, answer in current_answers.items():
|
124
|
+
if other_question in question_dict:
|
125
|
+
question_dict[other_question].answer = answer
|
126
|
+
else:
|
127
|
+
# it might be a comment
|
128
|
+
if (
|
129
|
+
new_question := other_question.split("_comment")[0]
|
130
|
+
) in question_dict:
|
131
|
+
question_dict[new_question].comment = answer
|
132
|
+
|
133
|
+
return {**question_dict, **scenario}
|
134
|
+
|
135
|
+
def _extract_edsl_result_entry_and_validate(
|
136
|
+
self, agent_response_dict: AgentResponseDict
|
137
|
+
) -> EDSLResultObjectInput:
|
138
|
+
"""Extract the EDSL result entry and validate it."""
|
139
|
+
edsl_dict = agent_response_dict.edsl_dict._asdict()
|
140
|
+
exception_occurred = None
|
141
|
+
validated = False
|
142
|
+
try:
|
143
|
+
# if the question has jinja parameters, it is easier to make a new question with the parameters
|
144
|
+
if self.question.parameters:
|
145
|
+
prior_answers_dict = self.prompt_constructor.prior_answers_dict()
|
146
|
+
|
147
|
+
# question options have be treated differently because of dynamic question
|
148
|
+
# this logic is all in the prompt constructor
|
149
|
+
if "question_options" in self.question.data:
|
150
|
+
new_question_options = self.prompt_constructor.get_question_options(
|
151
|
+
self.question.data
|
152
|
+
)
|
153
|
+
if new_question_options != self.question.data["question_options"]:
|
154
|
+
# I don't love this direct writing but it seems to work
|
155
|
+
self.question.question_options = new_question_options
|
156
|
+
|
157
|
+
question_with_validators = self.question.render(
|
158
|
+
self.scenario | prior_answers_dict
|
159
|
+
)
|
160
|
+
question_with_validators.use_code = self.question.use_code
|
161
|
+
else:
|
162
|
+
question_with_validators = self.question
|
163
|
+
|
164
|
+
validated_edsl_dict = question_with_validators._validate_answer(edsl_dict)
|
165
|
+
answer = self._determine_answer(validated_edsl_dict["answer"])
|
166
|
+
comment = validated_edsl_dict.get("comment", "")
|
167
|
+
validated = True
|
168
|
+
except QuestionAnswerValidationError as e:
|
169
|
+
answer = None
|
170
|
+
comment = "The response was not valid."
|
171
|
+
# if self.raise_validation_errors:
|
172
|
+
exception_occurred = e
|
173
|
+
except Exception as non_validation_error:
|
174
|
+
answer = None
|
175
|
+
comment = "Some other error occurred."
|
176
|
+
exception_occurred = non_validation_error
|
177
|
+
finally:
|
178
|
+
# even if validation failes, we still return the result
|
179
|
+
data = {
|
180
|
+
"answer": answer,
|
181
|
+
"comment": comment,
|
182
|
+
"generated_tokens": agent_response_dict.edsl_dict.generated_tokens,
|
183
|
+
"question_name": self.question.question_name,
|
184
|
+
"prompts": self.get_prompts(),
|
185
|
+
"cached_response": agent_response_dict.model_outputs.cached_response,
|
186
|
+
"raw_model_response": agent_response_dict.model_outputs.response,
|
187
|
+
"cache_used": agent_response_dict.model_outputs.cache_used,
|
188
|
+
"cache_key": agent_response_dict.model_outputs.cache_key,
|
189
|
+
"validated": validated,
|
190
|
+
"exception_occurred": exception_occurred,
|
191
|
+
"cost": agent_response_dict.model_outputs.cost,
|
192
|
+
}
|
193
|
+
result = EDSLResultObjectInput(**data)
|
194
|
+
return result
|
247
195
|
|
248
196
|
answer_question = sync_wrapper(async_answer_question)
|
249
197
|
|
250
198
|
|
251
|
-
class
|
252
|
-
|
253
|
-
results = self.question.simulate_answer(human_readable=True)
|
254
|
-
results["prompts"] = self.get_prompts()
|
255
|
-
results["question_name"] = self.question.question_name
|
256
|
-
results["comment"] = "Debug comment"
|
257
|
-
return AgentResponseDict(**results)
|
199
|
+
class InvigilatorHuman(InvigilatorBase):
|
200
|
+
"""An invigilator for when a human is answering the question."""
|
258
201
|
|
259
|
-
|
260
|
-
|
261
|
-
"user_prompt": Prompt("NA").text,
|
262
|
-
"system_prompt": Prompt("NA").text,
|
263
|
-
}
|
202
|
+
validate_response: bool = False
|
203
|
+
translate_response: bool = False
|
264
204
|
|
205
|
+
async def async_answer_question(self, iteration: int = 0) -> AgentResponseDict:
|
206
|
+
"""Return the answer to the question."""
|
207
|
+
comment = "This is a real survey response from a human."
|
265
208
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
"prompts": self.get_prompts(),
|
272
|
-
"question_name": self.question.question_name,
|
273
|
-
}
|
209
|
+
def __repr__(self):
|
210
|
+
return f"{self.literal}"
|
211
|
+
|
212
|
+
exception_occurred = None
|
213
|
+
validated = False
|
274
214
|
try:
|
275
215
|
answer = self.agent.answer_question_directly(self.question, self.scenario)
|
276
|
-
|
216
|
+
self.raw_model_response = answer
|
217
|
+
|
218
|
+
if self.validate_response:
|
219
|
+
_ = self.question._validate_answer({"answer": answer})
|
220
|
+
if self.translate_response:
|
221
|
+
answer = self.question._translate_answer_code_to_answer(
|
222
|
+
answer, self.scenario
|
223
|
+
)
|
224
|
+
validated = True
|
225
|
+
except QuestionAnswerValidationError as e:
|
226
|
+
answer = None
|
227
|
+
if self.raise_validation_errors:
|
228
|
+
exception_occurred = e
|
277
229
|
except Exception as e:
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
230
|
+
answer = None
|
231
|
+
if self.raise_validation_errors:
|
232
|
+
exception_occurred = e
|
233
|
+
finally:
|
234
|
+
data = {
|
235
|
+
"generated_tokens": NA, # NotApplicable(),
|
236
|
+
"question_name": self.question.question_name,
|
237
|
+
"prompts": self.get_prompts(),
|
238
|
+
"cached_response": NA,
|
239
|
+
"raw_model_response": NA,
|
240
|
+
"cache_used": NA,
|
241
|
+
"cache_key": NA,
|
242
|
+
"answer": answer,
|
243
|
+
"comment": comment,
|
244
|
+
"validated": validated,
|
245
|
+
"exception_occurred": exception_occurred,
|
246
|
+
}
|
247
|
+
return EDSLResultObjectInput(**data)
|
285
248
|
|
286
249
|
|
287
250
|
class InvigilatorFunctional(InvigilatorBase):
|
288
|
-
|
251
|
+
"""A Invigilator for when the question has a answer_question_directly function."""
|
252
|
+
|
253
|
+
async def async_answer_question(self, iteration: int = 0) -> AgentResponseDict:
|
254
|
+
"""Return the answer to the question."""
|
289
255
|
func = self.question.answer_question_directly
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
256
|
+
answer = func(scenario=self.scenario, agent_traits=self.agent.traits)
|
257
|
+
|
258
|
+
return EDSLResultObjectInput(
|
259
|
+
generated_tokens=str(answer),
|
260
|
+
question_name=self.question.question_name,
|
261
|
+
prompts=self.get_prompts(),
|
262
|
+
cached_response=NA,
|
263
|
+
raw_model_response=NA,
|
264
|
+
cache_used=NA,
|
265
|
+
cache_key=NA,
|
266
|
+
answer=answer["answer"],
|
267
|
+
comment="This is the result of a functional question.",
|
268
|
+
validated=True,
|
269
|
+
exception_occurred=None,
|
270
|
+
)
|
271
|
+
|
272
|
+
def get_prompts(self) -> Dict[str, "Prompt"]:
|
273
|
+
from edsl.prompts.Prompt import Prompt
|
274
|
+
|
275
|
+
"""Return the prompts used."""
|
308
276
|
return {
|
309
|
-
"user_prompt": Prompt("NA")
|
310
|
-
"system_prompt": Prompt("NA")
|
277
|
+
"user_prompt": Prompt("NA"),
|
278
|
+
"system_prompt": Prompt("NA"),
|
311
279
|
}
|
312
280
|
|
313
281
|
|
314
282
|
if __name__ == "__main__":
|
315
|
-
|
316
|
-
|
317
|
-
from edsl.agents.Agent import Agent
|
318
|
-
|
319
|
-
a = Agent(
|
320
|
-
instruction="You are a happy-go lucky agent.",
|
321
|
-
traits={"feeling": "happy", "age": "Young at heart"},
|
322
|
-
codebook={"feeling": "Feelings right now", "age": "Age in years"},
|
323
|
-
trait_presentation_template="",
|
324
|
-
)
|
325
|
-
|
326
|
-
class MockModel:
|
327
|
-
model = LanguageModelType.GPT_4.value
|
328
|
-
|
329
|
-
class MockQuestion:
|
330
|
-
question_type = "free_text"
|
331
|
-
question_text = "How are you feeling?"
|
332
|
-
question_name = "feelings_question"
|
333
|
-
data = {
|
334
|
-
"question_name": "feelings",
|
335
|
-
"question_text": "How are you feeling?",
|
336
|
-
"question_type": "feelings_question",
|
337
|
-
}
|
283
|
+
import doctest
|
338
284
|
|
339
|
-
|
340
|
-
agent=a,
|
341
|
-
question=MockQuestion(),
|
342
|
-
scenario={},
|
343
|
-
model=MockModel(),
|
344
|
-
memory_plan=None,
|
345
|
-
current_answers=None,
|
346
|
-
)
|
347
|
-
print(i.get_prompts()["system_prompt"])
|
348
|
-
assert i.get_prompts()["system_prompt"].text == "You are a happy-go lucky agent."
|
349
|
-
|
350
|
-
###############
|
351
|
-
## Render one
|
352
|
-
###############
|
353
|
-
|
354
|
-
a = Agent(
|
355
|
-
instruction="You are a happy-go lucky agent.",
|
356
|
-
traits={"feeling": "happy", "age": "Young at heart"},
|
357
|
-
codebook={"feeling": "Feelings right now", "age": "Age in years"},
|
358
|
-
trait_presentation_template="You are feeling {{ feeling }}.",
|
359
|
-
)
|
360
|
-
|
361
|
-
i = InvigilatorAI(
|
362
|
-
agent=a,
|
363
|
-
question=MockQuestion(),
|
364
|
-
scenario={},
|
365
|
-
model=MockModel(),
|
366
|
-
memory_plan=None,
|
367
|
-
current_answers=None,
|
368
|
-
)
|
369
|
-
print(i.get_prompts()["system_prompt"])
|
370
|
-
|
371
|
-
assert (
|
372
|
-
i.get_prompts()["system_prompt"].text
|
373
|
-
== "You are a happy-go lucky agent. You are feeling happy."
|
374
|
-
)
|
375
|
-
try:
|
376
|
-
assert i.get_prompts()["system_prompt"].unused_traits(a.traits) == ["age"]
|
377
|
-
except AssertionError:
|
378
|
-
unused_traits = i.get_prompts()["system_prompt"].unused_traits(a.traits)
|
379
|
-
print(f"System prompt: {i.get_prompts()['system_prompt']}")
|
380
|
-
print(f"Agent traits: {a.traits}")
|
381
|
-
print(f"Unused_traits: {unused_traits}")
|
382
|
-
# breakpoint()
|
383
|
-
|
384
|
-
###############
|
385
|
-
## Render one
|
386
|
-
###############
|
387
|
-
|
388
|
-
a = Agent(
|
389
|
-
instruction="You are a happy-go lucky agent.",
|
390
|
-
traits={"feeling": "happy", "age": "Young at heart"},
|
391
|
-
codebook={"feeling": "Feelings right now", "age": "Age in years"},
|
392
|
-
trait_presentation_template="You are feeling {{ feeling }}. You eat lots of {{ food }}.",
|
393
|
-
)
|
394
|
-
|
395
|
-
i = InvigilatorAI(
|
396
|
-
agent=a,
|
397
|
-
question=MockQuestion(),
|
398
|
-
scenario={},
|
399
|
-
model=MockModel(),
|
400
|
-
memory_plan=None,
|
401
|
-
current_answers=None,
|
402
|
-
)
|
403
|
-
print(i.get_prompts()["system_prompt"])
|
404
|
-
|
405
|
-
## Should raise a QuestionScenarioRenderError
|
406
|
-
assert (
|
407
|
-
i.get_prompts()["system_prompt"].text
|
408
|
-
== "You are a happy-go lucky agent. You are feeling happy."
|
409
|
-
)
|
285
|
+
doctest.testmod(optionflags=doctest.ELLIPSIS)
|