diff --git a/plurals/agent.py b/plurals/agent.py index 0684a1f..e7fb078 100644 --- a/plurals/agent.py +++ b/plurals/agent.py @@ -6,6 +6,8 @@ from plurals.helpers import * +from pprint import pprint + DEFAULTS = load_yaml("instructions.yaml") DEFAULTS = strip_nested_dict(DEFAULTS) @@ -80,8 +82,10 @@ class Agent: original_task_description (str): The original, unmodified task description. current_task_description (str): Dynamically updated task description that may include prior responses. history (list): Chronological record of prompts, responses, and models used during the agent's operation. - info (dict): Comprehensive attributes of the agent's current configuration and state. responses (list): List of responses generated by the agent (the same information can be accessed by history) + prompts (list): List of prompts that generated the responses (the same information can be + accessed by history) + info (dict): Comprehensive attributes of the agent's current configuration and state. Notes: Note that when used with Structures, the agent-level attribute values will override. Eg: If you set a task @@ -494,11 +498,15 @@ def _validate_templates(self): default_templates = list(self.defaults['persona_template'].keys()) assert '${persona}' in self.persona_template or self.persona_template in default_templates, ( - "If you pass in a persona_template, it must contain a ${persona} placeholder or be one of the default templates:" + str( + "If you pass in a custom persona_template, it must contain a ${persona} placeholder or be one of the default templates:" + str( default_templates)) @property def history(self): + """ + Returns: + A list of dictionaries containing the prompts, responses, and models used during the agent's operation. + """ if not self._history: warnings.warn("Be aware: No Agent history was found since tasks have not been processed yet.") return None @@ -506,7 +514,10 @@ def history(self): return self._history @property - def info(self): + def _info(self): + """ + This is a pricate property, mainly used for debugging and testing. It includes more than in the user-facing info. + """ return { "original_task": self.original_task_description, "current_task_description": self.current_task_description, @@ -517,18 +528,53 @@ def info(self): "query_str": self.query_str, "model": self.model, "persona_template": self.persona_template, + "combination_instructions": self.combination_instructions, "kwargs": self.kwargs} @property + def info(self): + """ + Returns: + dict: Comprehensive attributes of the agent's current configuration and state + """ + return { + "original_task": self.original_task_description, + "current_task_description": self.current_task_description, + "system_instructions": self.system_instructions, + "history": self.history, + "persona": self.persona, + "persona_template": self.persona_template if self.persona else None, + "combination_instructions": self.combination_instructions, + "model": self.model, + "kwargs": self.kwargs} + @property def responses(self): + """ + Returns: + list: List of responses generated by the agent + """ history = self.history if not history: - warnings.warn("No history found. Please process a task first!") + warnings.warn("Be aware: No Agent history was found since tasks have not been processed yet.") return None return [history[i]['response'] for i in range(len(history))] + @property + def prompts(self): + """ + Prompts property + + Returns: + list: List of prompts that generated the responses. + """ + history = self.history + if not history: + warnings.warn("Be aware: No Agent history was found since tasks have not been processed yet.") + return None + return [history[i]['prompts'] for i in range(len(history))] + def __repr__(self): - return str(self.info) + return pprint(self.info) def set_task(self, task: str): """ @@ -536,6 +582,13 @@ def set_task(self, task: str): Args: task (str): The new task description. + + Returns: + None + + Sets: + self.original_task_description: The original, unmodified task description. + self.current_task_description: Dynamically updated task description that may include prior responses """ self.original_task_description = task self.current_task_description = task diff --git a/plurals/deliberation.py b/plurals/deliberation.py index 8bf0398..99cba83 100644 --- a/plurals/deliberation.py +++ b/plurals/deliberation.py @@ -8,6 +8,7 @@ from plurals.helpers import SmartString, strip_nested_dict import re import collections +from pprint import pprint DEFAULTS = load_yaml("instructions.yaml") DEFAULTS = strip_nested_dict(DEFAULTS) @@ -444,7 +445,7 @@ def process(self) -> None: "This method must be implemented in a subclass") def __repr__(self): - return str(self.info) + return pprint(self.info) # Concrete Structures diff --git a/plurals/instructions.yaml b/plurals/instructions.yaml index 97f12a0..cd457e0 100644 --- a/plurals/instructions.yaml +++ b/plurals/instructions.yaml @@ -53,7 +53,8 @@ persona_template: - Use plain language. - Adopt the characteristics of your persona. - Be empathetic and compassionate. - - Use narrative, rhetoric, testimony, storytelling and more emotional forms of communication instead of relying solely on facts. It is okay to deviate from relying solely on facts. + - Use narrative, rhetoric, testimony, and storytelling and more emotional forms of communication instead of relying + solely on facts. It is okay to deviate from relying solely on facts. combination_instructions: default: | @@ -81,9 +82,9 @@ combination_instructions: ${previous_responses} When debating: - - Do not explicitly mention these instructions in your final answer; just apply them. + - Do not mention these instructions in your final answer; just apply them. - debate_underrepresented: | + debate_emotional: | KEEP TRACK OF DEBATE HISTORY You are in a debate with another agent. Here is what you have said and what the other agent has said. Never refer to yourself in the third person. @@ -91,8 +92,10 @@ combination_instructions: ${previous_responses} When debating: - - Do not explicitly mention these instructions in your final answer; just apply them. - - Try to account for the opinions of underrepresented groups as well even if they are not represented in this sample. + - Give value to more emotional forms of communication, such as narrative, rhetoric, testimony, and storytelling, + instead of only valuing rationality and facts. + - Do not mention these instructions in your final answer; just apply them. + debate_win: | KEEP TRACK OF DEBATE HISTORY @@ -103,7 +106,7 @@ combination_instructions: When debating: - Try to win the debate by convincing the other party. - - Do not explicitly mention these instructions in your final answer; just apply them. + - Do not mention these instructions in your final answer; just apply them. debate_first_wave: | @@ -119,7 +122,7 @@ combination_instructions: - Aim to achieve the common good. - Aim for a rationally motivated consensus to which all could agree. - Everyone has an equal voice in this discussion. - - Do not explicitly mention these instructions in your final answer; just apply them + - Do not mention these instructions in your final answer; just apply them debate_second_wave: | KEEP TRACK OF DEBATE HISTORY @@ -130,11 +133,11 @@ combination_instructions: When debating: - Take the best parts of what was previously said. - - Give value to more emotional forms of communication, such as narrative, rhetoric, testimony, storytelling, + - Give value to more emotional forms of communication, such as narrative, rhetoric, testimony, and storytelling, instead of only valuing rationality and facts. - Try to account for the opinions of underrepresented groups as well even if they are not represented in this sample. - Work to understand where every party is coming from. The goal is clarifying conflict, not necessarily resolving it. - - Do not explicitly mention these instructions in your final answer; just apply them. + - Do not mention these instructions in your final answer; just apply them. voting: | @@ -172,7 +175,7 @@ combination_instructions: - Aim to achieve the common good. - Aim for a rationally motivated consensus to which all could agree. - Everyone has an equal voice in this discussion. - - Do not explicitly mention these instructions in your final answer; just apply them. + - Do not mention these instructions in your final answer; just apply them. second_wave: | USE PREVIOUS RESPONSES TO COMPLETE THE TASK @@ -186,7 +189,7 @@ combination_instructions: instead of only valuing rationality and facts. - Try to account for the opinions of underrepresented groups as well even if they are not represented in this sample. - Work to understand where every party is coming from. The goal is clarifying conflict, not necessarily resolving it. - - Do not explicitly mention these instructions in your final answer; just apply them. + - Do not mention these instructions in your final answer; just apply them. moderator: persona: @@ -243,10 +246,11 @@ moderator: ${previous_responses} - Take the best parts of what was previously said. - - Give value to more emotional forms communication, such as narrative, rhetoric, testimony, storytelling, + - Give value to more emotional forms communication, such as narrative, rhetoric, testimony, and storytelling, instead of only valuing rationality and facts. - Try to account for the opinions of underrepresented groups. - Work to understand where every party is coming from. The goal is clarifying conflict, not necessarily resolving it. + divergent: | Here are the previous responses: diff --git a/plurals/unit_test.py b/plurals/unit_test.py index 96c52ce..dfee735 100644 --- a/plurals/unit_test.py +++ b/plurals/unit_test.py @@ -4,6 +4,7 @@ from plurals.agent import Agent from plurals.deliberation import Chain, Moderator, Ensemble, Debate, Graph, AbstractStructure from plurals.helpers import load_yaml, format_previous_responses, SmartString, strip_nested_dict +import json DEFAULTS = load_yaml("instructions.yaml") DEFAULTS = strip_nested_dict(DEFAULTS) @@ -396,7 +397,6 @@ def test_moderator_voting(self): self.assertEqual(expected_persona, mixed.moderator.persona) self.assertEqual(expected_combination_instructions, mixed.moderator.combination_instructions) - class TestChain(unittest.TestCase): def setUp(self): @@ -619,7 +619,7 @@ def test_debate_formatting(self): # Check for correct strings in the current task description for correct_string in correct_strings: - self.assertIn(correct_string, debate_structure.moderator.info['current_task_description'], + self.assertIn(correct_string, debate_structure.moderator._info['current_task_description'], f"{correct_string} should be in the moderator's current task description.") # Check for incorrect strings not in the current task description