Tachi67 commited on
Commit
d4a9b53
1 Parent(s): 0796572

Upload 15 files

Browse files
Controller_JarvisFlow.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from copy import deepcopy
3
+ from typing import Any, Dict, List
4
+
5
+ from flow_modules.aiflows.ChatFlowModule import ChatAtomicFlow
6
+
7
+
8
+ from dataclasses import dataclass
9
+
10
+
11
+ @dataclass
12
+ class Command:
13
+ name: str
14
+ description: str
15
+ input_args: List[str]
16
+
17
+ # TODO: controller should be generalized
18
+ class Controller_JarvisFlow(ChatAtomicFlow):
19
+ def __init__(
20
+ self,
21
+ commands: List[Command],
22
+ **kwargs):
23
+ super().__init__(**kwargs)
24
+ self.system_message_prompt_template = self.system_message_prompt_template.partial(
25
+ commands=self._build_commands_manual(commands),
26
+ plan="no plans yet",
27
+ plan_file_location="no plan file location yet",
28
+ logs="no logs yet",
29
+ )
30
+ self.hint_for_model = """
31
+ Make sure your response is in the following format:
32
+ Response Format:
33
+ {
34
+ "command": "call one of the subordinates",
35
+ "command_args": {
36
+ "arg name": "value"
37
+ }
38
+ }
39
+ """
40
+
41
+ def _get_content_file_location(self, input_data, content_name):
42
+ # get the location of the file that contains the content: plan, logs, code_library
43
+ assert "memory_files" in input_data, "memory_files not passed to Jarvis/Controller"
44
+ assert content_name in input_data["memory_files"], f"{content_name} not in memory files"
45
+ return input_data["memory_files"][content_name]
46
+
47
+ def _get_content(self, input_data, content_name):
48
+ # get the content of the file that contains the content: plan, logs, code_library
49
+ assert content_name in input_data, f"{content_name} not passed to Jarvis/Controller"
50
+ content = input_data[content_name]
51
+ if len(content) == 0:
52
+ content = f'No {content_name} yet'
53
+ return content
54
+ @staticmethod
55
+ def _build_commands_manual(commands: List[Command]) -> str:
56
+ ret = ""
57
+ for i, command in enumerate(commands):
58
+ command_input_json_schema = json.dumps(
59
+ {input_arg: f"YOUR_{input_arg.upper()}" for input_arg in command.input_args})
60
+ ret += f"{i + 1}. {command.name}: {command.description} Input arguments (given in the JSON schema): {command_input_json_schema}\n"
61
+ return ret
62
+
63
+
64
+ @classmethod
65
+ def instantiate_from_config(cls, config):
66
+ flow_config = deepcopy(config)
67
+
68
+ kwargs = {"flow_config": flow_config}
69
+
70
+ # ~~~ Set up prompts ~~~
71
+ kwargs.update(cls._set_up_prompts(flow_config))
72
+
73
+ # ~~~Set up backend ~~~
74
+ kwargs.update(cls._set_up_backend(flow_config))
75
+
76
+ # ~~~ Set up commands ~~~
77
+ commands = flow_config["commands"]
78
+ commands = [
79
+ Command(name, command_conf["description"], command_conf["input_args"]) for name, command_conf in
80
+ commands.items()
81
+ ]
82
+ kwargs.update({"commands": commands})
83
+
84
+ # ~~~ Instantiate flow ~~~
85
+ return cls(**kwargs)
86
+
87
+ def _update_prompts_and_input(self, input_data: Dict[str, Any]):
88
+ if 'goal' in input_data:
89
+ input_data['goal'] += self.hint_for_model
90
+ if 'result' in input_data:
91
+ input_data['result'] += self.hint_for_model
92
+ plan_file_location = self._get_content_file_location(input_data, "plan")
93
+ plan_content = self._get_content(input_data, "plan")
94
+ logs_content = self._get_content(input_data, "logs")
95
+ self.system_message_prompt_template = self.system_message_prompt_template.partial(
96
+ plan_file_location=plan_file_location,
97
+ plan=plan_content,
98
+ logs=logs_content
99
+ )
100
+
101
+ def run(self, input_data: Dict[str, Any]) -> Dict[str, Any]:
102
+ self._update_prompts_and_input(input_data)
103
+ api_output = super().run(input_data)["api_output"].strip()
104
+ try:
105
+ response = json.loads(api_output)
106
+ return response
107
+ except json.decoder.JSONDecodeError:
108
+ new_input_data = input_data.copy()
109
+ new_input_data['result'] = "The previous respond cannot be parsed with json.loads. Make sure your next response is in JSON format."
110
+ new_api_output = super().run(new_input_data)["api_output"].strip()
111
+ return json.loads(new_api_output)
Controller_JarvisFlow.yaml ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ _target_: Tachi67.JarvisFlowModule.Controller_JarvisFlow.instantiate_from_default_config
2
+ name: "ControllerFlow_JarvisFlow"
3
+ description: "Proposes the next action to take towards achieving the goal, and prepares the input for the branching flow"
4
+ enable_cache: True
5
+
6
+ #######################################################
7
+ # Input keys
8
+ #######################################################
9
+
10
+ input_interface_non_initialized: # initial input keys
11
+ - "goal"
12
+ - "memory_files"
13
+ - "plan"
14
+ - "logs"
15
+
16
+ input_interface_initialized:
17
+ - "result"
18
+ - "memory_files"
19
+ - "plan"
20
+ - "logs"
21
+
22
+ #######################################################
23
+ # Output keys
24
+ #######################################################
25
+
26
+ output_interface:
27
+ - 'command'
28
+ - 'command_args'
29
+
30
+ backend:
31
+ api_infos: ???
32
+ model_name:
33
+ openai: gpt-4
34
+ azure: azure/gpt-4
35
+
36
+ commands:
37
+ call_coder:
38
+ description: "Instruct the coder to write and run code to finish your given goal."
39
+ input_args: [ "goal" ]
40
+ re_plan:
41
+ description: "When something is wrong with current plan, draft another plan based on the old plan and information about why it's bad or how to refine it."
42
+ input_args: [ "goal" ]
43
+ finish:
44
+ description: "Signal that the objective has been satisfied, return the summary of what was done"
45
+ input_args: [ "summary" ]
46
+ manual_finish:
47
+ description: "The user demands to quit and terminate the current process"
48
+ input_args: [ ]
49
+ ask_user:
50
+ description: "Ask user a question for confirmation or assistance"
51
+ input_args: [ "question" ]
52
+ update_plan:
53
+ description: "When one step of the plan is done, pass the updated plan to edit plan file and override current plan"
54
+ input_args: [ "updated_plan" ]
55
+ intermediate_answer:
56
+ description: "When one step of the plan is done, pass the result from the step as an intermediate answer to the user"
57
+ input_args: [ "answer" ]
58
+ final_answer:
59
+ description: "When the goal is achieved, pass the result from the goal as a final answer to the user"
60
+ input_args: [ "answer" ]
61
+
62
+
63
+ system_message_prompt_template:
64
+ _target_: langchain.PromptTemplate
65
+ template: |2-
66
+ Your department is in charge of achieving a particular goal by writing and running code. You are the leader of the department.
67
+
68
+ You work with several subordinated, they will be in charge of the specific tasks, including writing and running code to achieve a goal given specifically by you, re-planning, etc.
69
+
70
+ To call one of the subordinates, you need to call the corresponding command with necessary arguments, here are the commands and their descriptions:
71
+ {{commands}}
72
+
73
+ You are given a step-by-step plan to finish the goal, **make sure you follow the plan**, **notice that, if you are informed that the plan is overriden, this plan is the new plan you should stick to.** The plan is stored at {{plan_file_location}}. Here is the plan:
74
+ {{plan}}
75
+
76
+ You should execute the plan step-by-step, for each step, you should do the following workflows:
77
+ 0.1 Whenever the user demands to quit or terminate the current process, call `manual_finish` command.
78
+ 0.2 Whenever in doubt, or you have something to ask, or confirm to the user, call `ask_user` with your question.
79
+ 0.3 During the execution of the plan, if something goes wrong, call the `re_plan` with detailed information about what was wrong.
80
+ 1. If the current step of plan can be achieved by writing and running code, call `call_coder` with the goal of the current step of plan.
81
+ 2. Whenever you have done one step of the plan, do the following:
82
+ 2.1 Reflect on what plan you are having right now.
83
+ 2.2 Reflect on which step of the plan you just finished.
84
+ 2.3 Generate a plan, **it is exactly the same as the plan you have now, but with the current step of plan marked as done**
85
+ 2.4 Call `update_plan` with the plan you just generated.
86
+ 3. After you finish one step of the plan and have called `update_plan`, call `intermediate_answer` with the result of the step you just finished.
87
+ 4. The user will provide you with feedback on the last step executed, react accordingly.
88
+ 5. If the user is happy with the intermediate result, proceed to the next step of the plan, go back to workflow 1.
89
+ 5. When every step of the plan is done:
90
+ 5.1 Call `final_answer` with the result of the goal.
91
+ 5.2 React to the user's feedback, if the user is not happy, you may want to re-plan or give new instructions to the coder.
92
+ 5.3 If the user is happy, call `finish` with a summary of what was done throughout the process.
93
+
94
+ **You MUST call `update_plan` whenever you realize one step of the plan is done.**
95
+ **You MUST call `finish` whenever everything is done and the user is happy.**
96
+
97
+ Here is an example of execution:
98
+ ### Beginning of an example execution: ###
99
+ Plan: 1. Download the weather data from Paris on 19. Dec. 2021. 2. Send the weather data to an email address. 3. Give a final answer.
100
+ Your actions:
101
+ 1. Call `call_coder` with the goal of the first step of the plan. Code is written and run, the weather data is downloaded.
102
+ 2. You call `update_plan` with the plan you just generated, it is exactly the same as the plan you have now, but with the current step of plan marked as done.
103
+ 3. You call `intermediate_answer` with the result of the step you just finished.
104
+ 4. The user is happy with the intermediate result, you proceed to the next step of the plan.
105
+ 5. Call `call_coder` with the goal of the second step of the plan. Code is written and run, the weather data is sent to an email address.
106
+ 6. You call `update_plan` with the plan you just generated, it is exactly the same as the plan you have now, but with the current step of plan marked as done.
107
+ 7. You call `intermediate_answer` with the result of the step you just finished.
108
+ 8. The user is happy with the intermediate result, you proceed to the next step of the plan.
109
+ 9. Call `final_answer` with the result of the goal.
110
+ 10. The user is happy with the final result, you call `finish` with a summary of what was done throughout the process.
111
+ ### End of an example of execution ###
112
+
113
+ Here is a list of history actions you have taken, for your reference:
114
+ {{logs}}
115
+
116
+ Constraints:
117
+ 1. Exclusively use the commands listed in double quotes e.g. "command name"
118
+
119
+ Your response **MUST** be in the following format:
120
+ Response Format:
121
+ {
122
+ "command": "call one of the subordinates",
123
+ "command_args": {
124
+ "arg name": "value"
125
+ }
126
+ }
127
+ Ensure your responses can be parsed by Python json.loads
128
+
129
+ input_variables: ["commands", "plan", "logs", "plan_file_location"]
130
+ template_format: jinja2
131
+
132
+ human_message_prompt_template:
133
+ _target_: flows.prompt_template.JinjaPrompt
134
+ template: |2-
135
+ Here is the result of your previous action:
136
+ {{result}}
137
+ input_variables:
138
+ - "result"
139
+ template_format: jinja2
140
+
141
+ init_human_message_prompt_template:
142
+ _target_: flows.prompt_template.JinjaPrompt
143
+ template: |2-
144
+ Here is the goal you need to achieve, follow your plan to finish the goal:
145
+ {{goal}}
146
+ input_variables:
147
+ - "goal"
148
+ template_format: jinja2
CtrlExMem_JarvisFlow.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict, Any
2
+
3
+ from flow_modules.Tachi67.AbstractBossFlowModule import CtrlExMemFlow
4
+ from flows.base_flows import CircularFlow
5
+
6
+
7
+ class CtrlExMem_JarvisFlow(CtrlExMemFlow):
8
+ def _on_reach_max_round(self):
9
+ self._state_update_dict({
10
+ "result": "the maximum amount of rounds was reached before the Jarvis flow has done the job",
11
+ "summary": "JarvisFlow: the maximum amount of rounds was reached before the flow has done the job",
12
+ "status": "unfinished"
13
+ })
14
+
15
+ @CircularFlow.output_msg_payload_processor
16
+ def detect_finish_or_continue(self, output_payload: Dict[str, Any], src_flow) -> Dict[str, Any]:
17
+ command = output_payload["command"]
18
+ if command == "finish":
19
+ return {
20
+ "EARLY_EXIT": True,
21
+ "result": output_payload["command_args"]["summary"],
22
+ "summary": "Jarvis: " + output_payload["command_args"]["summary"],
23
+ "status": "finished"
24
+ }
25
+ elif command == "manual_finish":
26
+ # ~~~ return the manual quit status ~~~
27
+ return {
28
+ "EARLY_EXIT": True,
29
+ "result": "JarvisFlow was terminated explicitly by the user, process is unfinished",
30
+ "summary": "Jarvis: process terminated by the user explicitly, nothing generated",
31
+ "status": "unfinished"
32
+ }
33
+ elif command == "update_plan":
34
+ keys_to_fetch_from_state = ["memory_files"]
35
+ fetched_state = self._fetch_state_attributes_by_keys(keys=keys_to_fetch_from_state)
36
+ output_payload["command_args"]["memory_files"] = fetched_state["memory_files"]
37
+ return output_payload
38
+
39
+ elif command == "re_plan":
40
+ keys_to_fetch_from_state = ["plan", "memory_files"]
41
+ fetched_state = self._fetch_state_attributes_by_keys(keys=keys_to_fetch_from_state)
42
+ output_payload["command_args"]["plan_file_location"] = fetched_state["memory_files"]["plan"]
43
+ output_payload["command_args"]["plan"] = fetched_state["plan"]
44
+ return output_payload
45
+
46
+ else:
47
+ return output_payload
CtrlExMem_JarvisFlow.yaml ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ _target_: Tachi67.JarvisFlowModule.CtrlExMem_JarvisFlow.instantiate_from_default_config
2
+ name: "CtrlExMem_JarvisFlow"
3
+ description: "MemorizedControllerExecutor flow for Jarvis flow"
4
+
5
+ input_interface:
6
+ - "plan"
7
+ - "logs"
8
+ - "memory_files"
9
+ - "goal"
10
+
11
+ subflows_config:
12
+ Controller:
13
+ _target_: Tachi67.JarvisFlowModule.Controller_JarvisFlow.instantiate_from_default_config
14
+ backend:
15
+ api_infos: ???
16
+ model_name:
17
+ openai: gpt-4
18
+ azure: azure/gpt-4
19
+ Executor:
20
+ _target_: flows.base_flows.BranchingFlow.instantiate_from_default_config
21
+ subflows_config:
22
+ call_coder:
23
+ _target_: Tachi67.CoderFlowModule.CoderFlow.instantiate_from_default_config
24
+ memory_files: ???
25
+ subflows_config:
26
+ Planner:
27
+ _target_: Tachi67.CoderFlowModule.Planner_CoderFlow.instantiate_from_default_config
28
+ subflows_config:
29
+ Controller:
30
+ backend:
31
+ api_infos: ???
32
+ model_name:
33
+ openai: gpt-4
34
+ azure: azure/gpt-4
35
+ Executor:
36
+ subflows_config:
37
+ write_plan:
38
+ subflows_config:
39
+ PlanGenerator:
40
+ backend:
41
+ api_infos: ???
42
+ model_name:
43
+ openai: gpt-4
44
+ azure: azure/gpt-4
45
+
46
+ CtrlExMem:
47
+ subflows_config:
48
+ Controller:
49
+ backend:
50
+ api_infos: ???
51
+ model_name:
52
+ openai: gpt-4
53
+ azure: azure/gpt-4
54
+ Executor:
55
+ subflows_config:
56
+ extend_library:
57
+ memory_files: ???
58
+ subflows_config:
59
+ Planner:
60
+ subflows_config:
61
+ Controller:
62
+ backend:
63
+ api_infos: ???
64
+ model_name:
65
+ openai: gpt-4
66
+ azure: azure/gpt-4
67
+ Executor:
68
+ subflows_config:
69
+ write_plan:
70
+ subflows_config:
71
+ PlanGenerator:
72
+ backend:
73
+ api_infos: ???
74
+ model_name:
75
+ openai: gpt-4
76
+ azure: azure/gpt-4
77
+ CtrlExMem:
78
+ subflows_config:
79
+ Controller:
80
+ backend:
81
+ api_infos: ???
82
+ model_name:
83
+ openai: gpt-4
84
+ azure: azure/gpt-4
85
+ Executor:
86
+ subflows_config:
87
+ write_code:
88
+ subflows_config:
89
+ Controller:
90
+ backend:
91
+ api_infos: ???
92
+ model_name:
93
+ openai: gpt-4
94
+ azure: azure/gpt-4
95
+ Executor:
96
+ subflows_config:
97
+ write_code:
98
+ memory_files: ???
99
+ subflows_config:
100
+ CodeGenerator:
101
+ backend:
102
+ api_infos: ???
103
+ model_name:
104
+ openai: gpt-4
105
+ azure: azure/gpt-4
106
+ test:
107
+ memory_files: ???
108
+ re_plan:
109
+ subflows_config:
110
+ Controller:
111
+ backend:
112
+ api_infos: ???
113
+ model_name:
114
+ openai: gpt-4
115
+ azure: azure/gpt-4
116
+ Executor:
117
+ subflows_config:
118
+ write_plan:
119
+ subflows_config:
120
+ PlanGenerator:
121
+ backend:
122
+ api_infos: ???
123
+ model_name:
124
+ openai: gpt-4
125
+ azure: azure/gpt-4
126
+ re_plan:
127
+ subflows_config:
128
+ Controller:
129
+ backend:
130
+ api_infos: ???
131
+ model_name:
132
+ openai: gpt-4
133
+ azure: azure/gpt-4
134
+ Executor:
135
+ subflows_config:
136
+ write_plan:
137
+ subflows_config:
138
+ PlanGenerator:
139
+ backend:
140
+ api_infos: ???
141
+ model_name:
142
+ openai: gpt-4
143
+ azure: azure/gpt-4
144
+ ask_user:
145
+ _target_: Tachi67.ExtendLibraryFlowModule.ExtLibAskUserFlow.instantiate_from_default_config
146
+ re_plan:
147
+ _target_: Tachi67.ReplanningFlowModule.ReplanningFlow.instantiate_from_default_config
148
+ subflows_config:
149
+ Controller:
150
+ backend:
151
+ api_infos: ???
152
+ model_name:
153
+ openai: gpt-4
154
+ azure: azure/gpt-4
155
+ Executor:
156
+ subflows_config:
157
+ write_plan:
158
+ subflows_config:
159
+ PlanGenerator:
160
+ backend:
161
+ api_infos: ???
162
+ model_name:
163
+ openai: gpt-4
164
+ azure: azure/gpt-4
165
+ update_plan:
166
+ _target_: Tachi67.JarvisFlowModule.UpdatePlanAtomicFlow.instantiate_from_default_config
167
+ intermediate_answer:
168
+ _target_: Tachi67.JarvisFlowModule.IntermediateAns_Jarvis.instantiate_from_default_config
169
+ final_answer:
170
+ _target_: Tachi67.JarvisFlowModule.FinalAns_Jarvis.instantiate_from_default_config
171
+
172
+
173
+ MemoryReading:
174
+ _target_: Tachi67.MemoryReadingFlowModule.MemoryReadingAtomicFlow.instantiate_from_default_config
175
+ output_interface:
176
+ - "plan"
177
+ - "logs"
178
+
179
+ topology:
180
+ - goal: "Select the next action and prepare the input for the executor."
181
+ input_interface:
182
+ _target_: flows.interfaces.KeyInterface
183
+ additional_transformations:
184
+ - _target_: flows.data_transformations.KeyMatchInput
185
+ flow: Controller
186
+ output_interface:
187
+ _target_: CtrlExMem_JarvisFlow.detect_finish_or_continue
188
+ reset: false
189
+
190
+ - goal: "Execute the action specified by the Controller."
191
+ input_interface:
192
+ _target_: flows.interfaces.KeyInterface
193
+ keys_to_rename:
194
+ command: branch
195
+ command_args: branch_input_data
196
+ keys_to_select: ["branch", "branch_input_data"]
197
+ flow: Executor
198
+ output_interface:
199
+ _target_: flows.interfaces.KeyInterface
200
+ keys_to_rename:
201
+ branch_output_data: observation
202
+ keys_to_unpack: ["observation"]
203
+ reset: false
204
+
205
+ - goal: "Write memory to memory files"
206
+ input_interface:
207
+ _target_: flows.interfaces.KeyInterface
208
+ additional_transformations:
209
+ - _target_: flows.data_transformations.KeyMatchInput
210
+ flow: MemoryWriting
211
+ reset: false
212
+
213
+ - goal: "Read memory from memory files (flow_state)"
214
+ input_interface:
215
+ _target_: flows.interfaces.KeyInterface
216
+ additional_transformations:
217
+ - _target_: flows.data_transformations.KeyMatchInput
218
+ flow: MemoryReading
219
+ reset: false
FinalAns_Jarvis.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flow_modules.aiflows.HumanStandardInputFlowModule import HumanStandardInputFlow
2
+
3
+ from typing import Dict, Any
4
+
5
+ from flows.messages import UpdateMessage_Generic
6
+
7
+ from flows.utils import logging
8
+
9
+ log = logging.get_logger(f"flows.{__name__}")
10
+
11
+
12
+ class FinalAns_Jarvis(HumanStandardInputFlow):
13
+ def run(self,
14
+ input_data: Dict[str, Any]) -> Dict[str, Any]:
15
+
16
+ query_message = self._get_message(self.query_message_prompt_template, input_data)
17
+ state_update_message = UpdateMessage_Generic(
18
+ created_by=self.flow_config['name'],
19
+ updated_flow=self.flow_config["name"],
20
+ data={"query_message": query_message},
21
+ )
22
+ self._log_message(state_update_message)
23
+
24
+ log.info(query_message)
25
+ human_input = self._read_input()
26
+
27
+ answer = input_data["answer"]
28
+ response = {}
29
+ response["result"] = human_input
30
+ response["summary"] = f"Final answer provided: {answer}; feedback of user: {human_input}"
31
+
32
+ return response
FinalAns_Jarvis.yaml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ _target_: Tachi67.JarvisFlowModule.FinalAns_Jarvis.instantiate_from_default_config
2
+ request_multi_line_input_flag: False
3
+ end_of_input_string: EOI
4
+
5
+ query_message_prompt_template:
6
+ template: |2-
7
+ Jarvis has just achieved the goal, here is the final answer: {{answer}}
8
+ input_variables:
9
+ - "answer"
IntermediateAns_Jarvis.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flow_modules.aiflows.HumanStandardInputFlowModule import HumanStandardInputFlow
2
+
3
+ from typing import Dict, Any
4
+
5
+ from flows.messages import UpdateMessage_Generic
6
+
7
+ from flows.utils import logging
8
+
9
+ log = logging.get_logger(f"flows.{__name__}")
10
+
11
+
12
+ class IntermediateAns_Jarvis(HumanStandardInputFlow):
13
+ def run(self,
14
+ input_data: Dict[str, Any]) -> Dict[str, Any]:
15
+
16
+ query_message = self._get_message(self.query_message_prompt_template, input_data)
17
+ state_update_message = UpdateMessage_Generic(
18
+ created_by=self.flow_config['name'],
19
+ updated_flow=self.flow_config["name"],
20
+ data={"query_message": query_message},
21
+ )
22
+ self._log_message(state_update_message)
23
+
24
+ log.info(query_message)
25
+ human_input = self._read_input()
26
+
27
+ answer = input_data["answer"]
28
+ response = {}
29
+ response["result"] = human_input
30
+ response["summary"] = f"Intermediate Answer provided: {answer}; feedback of user: {human_input}"
31
+
32
+ return response
IntermediateAns_Jarvis.yaml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ _target_: Tachi67.JarvisFlowModule.IntermediateAns_Jarvis.instantiate_from_default_config
2
+ request_multi_line_input_flag: False
3
+ end_of_input_string: EOI
4
+
5
+ query_message_prompt_template:
6
+ template: |2-
7
+ Jarvis has just finished an intermediate step of execution: {{answer}}
8
+ input_variables:
9
+ - "answer"
JarvisFlow.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from flow_modules.Tachi67.AbstractBossFlowModule import AbstractBossFlow
2
+
3
+ class JarvisFlow(AbstractBossFlow):
4
+ pass
JarvisFlow.yaml ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: JarvisFlow
2
+ description: Jarvis, an agent with structured llms and tools able to process user requests, write and execute code, with external memory mechanisms.
3
+
4
+ target_: Tachi67.JarvisFlowModule.JarvisFlow.instantiate_from_default_config
5
+
6
+ memory_files: ???
7
+
8
+ subflows_config:
9
+ MemoryReading:
10
+ _target_: Tachi67.MemoryReadingFlowModule.MemoryReadingAtomicFlow.instantiate_from_default_config
11
+ output_interface:
12
+ - "plan"
13
+ - "logs"
14
+
15
+ Planner:
16
+ _target_: Tachi67.JarvisFlowModule.Planner_JarvisFlow.instantiate_from_default_config
17
+ subflows_config:
18
+ Controller:
19
+ backend:
20
+ api_infos: ???
21
+ model_name:
22
+ openai: gpt-4
23
+ azure: azure/gpt-4
24
+ Executor:
25
+ subflows_config:
26
+ write_plan:
27
+ subflows_config:
28
+ PlanGenerator:
29
+ backend:
30
+ api_infos: ???
31
+ model_name:
32
+ openai: gpt-4
33
+ azure: azure/gpt-4
34
+
35
+ CtrlExMem:
36
+ _target_: Tachi67.JarvisFlowModule.CtrlExMem_JarvisFlow.instantiate_from_default_config
37
+ subflows_config:
38
+ Controller:
39
+ backend:
40
+ api_infos: ???
41
+ model_name:
42
+ openai: gpt-4
43
+ azure: azure/gpt-4
44
+ Executor:
45
+ subflows_config:
46
+ re_plan:
47
+ subflows_config:
48
+ Controller:
49
+ backend:
50
+ api_infos: ???
51
+ model_name:
52
+ openai: gpt-4
53
+ azure: azure/gpt-4
54
+ Executor:
55
+ subflows_config:
56
+ write_plan:
57
+ subflows_config:
58
+ PlanGenerator:
59
+ backend:
60
+ api_infos: ???
61
+ model_name:
62
+ openai: gpt-4
63
+ azure: azure/gpt-4
64
+ Coder:
65
+ memory_files: ???
66
+ subflows_config:
67
+ Planner:
68
+ subflows_config:
69
+ Controller:
70
+ backend:
71
+ api_infos: ???
72
+ model_name:
73
+ openai: gpt-4
74
+ azure: azure/gpt-4
75
+ Executor:
76
+ subflows_config:
77
+ write_plan:
78
+ subflows_config:
79
+ PlanGenerator:
80
+ backend:
81
+ api_infos: ???
82
+ model_name:
83
+ openai: gpt-4
84
+ azure: azure/gpt-4
85
+ CtrlExMem:
86
+ subflows_config:
87
+ Controller:
88
+ backend:
89
+ api_infos: ???
90
+ model_name:
91
+ openai: gpt-4
92
+ azure: azure/gpt-4
93
+ Executor:
94
+ subflows_config:
95
+ extend_library:
96
+ memory_files: ???
97
+ subflows_config:
98
+ Planner:
99
+ subflows_config:
100
+ Controller:
101
+ backend:
102
+ api_infos: ???
103
+ model_name:
104
+ openai: gpt-4
105
+ azure: azure/gpt-4
106
+ Executor:
107
+ subflows_config:
108
+ write_plan:
109
+ subflows_config:
110
+ PlanGenerator:
111
+ backend:
112
+ api_infos: ???
113
+ model_name:
114
+ openai: gpt-4
115
+ azure: azure/gpt-4
116
+ CtrlExMem:
117
+ subflows_config:
118
+ Controller:
119
+ backend:
120
+ api_infos: ???
121
+ model_name:
122
+ openai: gpt-4
123
+ azure: azure/gpt-4
124
+ Executor:
125
+ subflows_config:
126
+ write_code:
127
+ subflows_config:
128
+ Controller:
129
+ backend:
130
+ api_infos: ???
131
+ model_name:
132
+ openai: gpt-4
133
+ azure: azure/gpt-4
134
+ Executor:
135
+ subflows_config:
136
+ write_code:
137
+ memory_files: ???
138
+ subflows_config:
139
+ CodeGenerator:
140
+ backend:
141
+ api_infos: ???
142
+ model_name:
143
+ openai: gpt-4
144
+ azure: azure/gpt-4
145
+ test:
146
+ memory_files: ???
147
+ re_plan:
148
+ subflows_config:
149
+ Controller:
150
+ backend:
151
+ api_infos: ???
152
+ model_name:
153
+ openai: gpt-4
154
+ azure: azure/gpt-4
155
+ Executor:
156
+ subflows_config:
157
+ write_plan:
158
+ subflows_config:
159
+ PlanGenerator:
160
+ backend:
161
+ api_infos: ???
162
+ model_name:
163
+ openai: gpt-4
164
+ azure: azure/gpt-4
165
+ re_plan:
166
+ subflows_config:
167
+ Controller:
168
+ backend:
169
+ api_infos: ???
170
+ model_name:
171
+ openai: gpt-4
172
+ azure: azure/gpt-4
173
+ Executor:
174
+ subflows_config:
175
+ write_plan:
176
+ subflows_config:
177
+ PlanGenerator:
178
+ backend:
179
+ api_infos: ???
180
+ model_name:
181
+ openai: gpt-4
182
+ azure: azure/gpt-4
Planner_JarvisFlow.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict, Any
2
+ import os
3
+ from flow_modules.Tachi67.PlanWriterFlowModule import PlanWriterFlow
4
+ from flows.base_flows import CircularFlow
5
+
6
+ class Planner_JarvisFlow(PlanWriterFlow):
7
+ # TODO: generalize this flow to avoid code duplication
8
+ @CircularFlow.output_msg_payload_processor
9
+ def detect_finish_or_continue(self, output_payload: Dict[str, Any], src_flow) -> Dict[str, Any]:
10
+ command = output_payload["command"]
11
+ if command == "finish":
12
+ # ~~~ fetch temp file location, plan content, memory file (of upper level flow e.g. ExtLib) from flow state
13
+ keys_to_fetch_from_state = ["temp_plan_file_location", "plan", "memory_files"]
14
+ fetched_state = self._fetch_state_attributes_by_keys(keys=keys_to_fetch_from_state)
15
+ temp_plan_file_location = fetched_state["temp_plan_file_location"]
16
+ plan_content = fetched_state["plan"]
17
+ plan_file_location = fetched_state["memory_files"]["plan"]
18
+
19
+ # ~~~ delete the temp plan file ~~~
20
+ if os.path.exists(temp_plan_file_location):
21
+ os.remove(temp_plan_file_location)
22
+
23
+ # ~~~ write plan content to plan file ~~~
24
+ with open(plan_file_location, 'w') as file:
25
+ file.write(plan_content)
26
+
27
+ # ~~~ return the plan content ~~~
28
+ return {
29
+ "EARLY_EXIT": True,
30
+ "plan": plan_content,
31
+ "summary": "Jarvis/PlanWriter: " + output_payload["command_args"]["summary"],
32
+ "status": "finished"
33
+ }
34
+ elif command == "manual_finish":
35
+ # ~~~ delete the temp plan file ~~~
36
+ keys_to_fetch_from_state = ["temp_plan_file_location"]
37
+ fetched_state = self._fetch_state_attributes_by_keys(keys=keys_to_fetch_from_state)
38
+ temp_plan_file_location = fetched_state["temp_plan_file_location"]
39
+ if os.path.exists(temp_plan_file_location):
40
+ os.remove(temp_plan_file_location)
41
+ # ~~~ return the manual quit status ~~~
42
+ return {
43
+ "EARLY_EXIT": True,
44
+ "plan": "no plan was generated",
45
+ "summary": "Jarvis/PlanWriter: PlanWriter was terminated explicitly by the user, process is unfinished",
46
+ "status": "unfinished"
47
+ }
48
+ elif command == "write_plan":
49
+ keys_to_fetch_from_state = ["memory_files"]
50
+ fetched_state = self._fetch_state_attributes_by_keys(keys=keys_to_fetch_from_state)
51
+ output_payload["command_args"]["plan_file_location"] = fetched_state["memory_files"]["plan"]
52
+ return output_payload
53
+ else:
54
+ return output_payload
Planner_JarvisFlow.yaml ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: "Planner/Jarvis"
2
+ description: "Generates plan with interactions with the user, used for the coder class"
3
+
4
+ _target_: Tachi67.JarvisFlowModule.Planner_JarvisFlow.instantiate_from_default_config
5
+
6
+ input_interface:
7
+ - "goal"
8
+ - "memory_files"
9
+
10
+ output_interface:
11
+ - "plan"
12
+ - "status"
13
+ - "summary"
14
+
15
+ ### Subflows specification
16
+ subflows_config:
17
+ Controller:
18
+ _target_: Tachi67.PlanWriterFlowModule.PlanWriterCtrlFlow.instantiate_from_default_config
19
+ backend:
20
+ api_infos: ???
21
+ model_name:
22
+ openai: gpt-4
23
+ azure: azure/gpt-4
24
+
25
+ Executor:
26
+ _target_: flows.base_flows.BranchingFlow.instantiate_from_default_config
27
+ subflows_config:
28
+ write_plan:
29
+ subflows_config:
30
+ PlanGenerator:
31
+ backend:
32
+ api_infos: ???
33
+ model_name:
34
+ openai: gpt-4
35
+ azure: azure/gpt-4
36
+ system_message_prompt_template:
37
+ _target_: flows.prompt_template.JinjaPrompt
38
+ template: |2-
39
+ You are the planner for Jarvis, an intelligent agent able to achieve goals by writing and running code, you write step-by-step plans for Jarvis to follow and execute.
40
+
41
+ Jarvis is capable of:
42
+ 1. Generating and running code, given a goal.
43
+ 2. Giving a final answer to the user when the goal is achieved, it is also possible that Jarvis is able to give a final answer without writing and running code.
44
+
45
+ **Your task is: given a goal to achieve, decompose the goal into step-by-step plans for Jarvis, each step of your plan should involve one of the following:
46
+ 1. Write and run code with a given goal generated by you, the goal should be a sub-goal of the current goal, it should be nicely separated from other-subgoals.
47
+ 2. Give a final answer.**
48
+
49
+ Here are some criteria you should consider in order to write a good plan:
50
+ 1. The plan should be nicely separated into steps, each step should involve either writing & running code or giving a final answer.
51
+ 2. Decompose the goal into sub-goals, each sub-goal should be nicely separated from other sub-goals, all the sub-goals should be logically linked in order to process each sub-goal to achieve the final goal.
52
+
53
+ Performance Evaluation:
54
+ 1. Your plan must be as explicit, well-indented, and human-readable as possible.
55
+ 2. Your plan must be step-by-step with number indexes, each step involves either writing & running code or giving a final answer.
56
+ 3. You should make plans with as few steps as possible.
57
+
58
+
59
+ **Here is an example of a good plan:**
60
+ Goal: Send an email with the data of the weather in Paris of 19. Dec. 2021 to my friend.
61
+ Plan:
62
+ 1. Write and run code to get the data of the weather in Paris of 19. Dec. 2021.
63
+ 2. Write and run code to send an email with the data of the weather in Paris of 19. Dec. 2021 to my friend.
64
+ 3. Give a final answer to the user.
65
+
66
+ **It's important that you should only respond in JSON format as described below:**
67
+ Response Format:
68
+ {
69
+ "plan": "A well indented string, containing a step-by-step plan to finish the given goal",
70
+ }
71
+ Ensure your responses can be parsed by Python json.loads
72
+ **Make sure that the plan you generate is a well-indented human readable string, with numbered indexes for each step.**
73
+
74
+ PlanFileEditor:
75
+ _target_: Tachi67.PlanFileEditFlowModule.PlanFileEditAtomicFlow.instantiate_from_default_config
76
+
77
+ ParseFeedback:
78
+ _target_: Tachi67.ParseFeedbackFlowModule.ParseFeedbackAtomicFlow.instantiate_from_default_config
79
+ input_interface:
80
+ - "temp_plan_file_location"
81
+ output_interface:
82
+ - "plan"
83
+ - "feedback"
84
+
85
+ ask_user:
86
+ _target_: Tachi67.PlanWriterFlowModule.PlanWriterAskUserFlow.instantiate_from_default_config
87
+
88
+
89
+ early_exit_key: "EARLY_EXIT"
90
+
91
+ topology:
92
+ - goal: "Select the next action and prepare the input for the executor."
93
+ input_interface:
94
+ _target_: flows.interfaces.KeyInterface
95
+ additional_transformations:
96
+ - _target_: flows.data_transformations.KeyMatchInput
97
+ flow: Controller
98
+ output_interface:
99
+ _target_: Planner_JarvisFlow.detect_finish_or_continue
100
+ reset: false
101
+
102
+ - goal: "Execute the action specified by the Controller."
103
+ input_interface:
104
+ _target_: flows.interfaces.KeyInterface
105
+ keys_to_rename:
106
+ command: branch
107
+ command_args: branch_input_data
108
+ keys_to_select: ["branch", "branch_input_data"]
109
+ flow: Executor
110
+ output_interface:
111
+ _target_: flows.interfaces.KeyInterface
112
+ keys_to_rename:
113
+ branch_output_data: observation
114
+ keys_to_unpack: ["observation"]
115
+ reset: false
UpdatePlanAtomicFlow.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #TODO: generalize updateplanatomicflow with the one in extendlibrary
2
+ from typing import Dict, Any
3
+ from flows.base_flows.atomic import AtomicFlow
4
+ class UpdatePlanAtomicFlow(AtomicFlow):
5
+ def _check_input(self, input_data: Dict[str, Any]):
6
+ assert "memory_files" in input_data, "memory_files not passed to UpdatePlanAtomicFlow.yaml"
7
+ assert "plan" in input_data["memory_files"], "plan not in memory_files"
8
+
9
+ def _call(self, input_data: Dict[str, Any]):
10
+ try:
11
+ plan_file_location = input_data["memory_files"]["plan"]
12
+ plan_to_write = input_data["updated_plan"]
13
+ with open(plan_file_location, 'w') as file:
14
+ file.write(plan_to_write + "\n")
15
+ return {
16
+ "result": "updated plan saved to the plan file and has overriden the previous plan",
17
+ "summary": f"Jarvis/UpdatePlanFlow: updated plan saved to {plan_file_location}"
18
+ }
19
+ except Exception as e:
20
+ return {
21
+ "result": f"Error occurred: {str(e)}",
22
+ "summary": f"Jarvis/UpdatePlanFlow: error occurred while writing updated plan: {str(e)}"
23
+ }
24
+
25
+ def run(
26
+ self,
27
+ input_data: Dict[str, Any]
28
+ ):
29
+ self._check_input(input_data)
30
+ return self._call(input_data)
UpdatePlanAtomicFlow.yaml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ _target_: Tachi67.JarvisFlowModule.UpdatePlanAtomicFlow.instantiate_from_default_config
2
+ name: "UpdatePlanAtomicFlow"
3
+ description: "Writes new plan to plan file"
4
+
5
+ input_interface:
6
+ - "updated_plan"
7
+
8
+ output_interface:
9
+ - "result"
__init__.py ADDED
File without changes