Tachi67 commited on
Commit
5a600b9
·
1 Parent(s): e129391

Upload 7 files

Browse files
CodeWriterAskUserFlow.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 CodeWriterAskUserFlow(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
+ response = {}
28
+ response["human_feedback"] = human_input
29
+ response["code"] = "no code was written"
30
+
31
+ return response
CodeWriterAskUserFlow.yaml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ request_multi_line_input_flag: False
2
+ end_of_input_string: EOI
3
+
4
+ query_message_prompt_template:
5
+ template: |2-
6
+ {{question}}
7
+ input_variables:
8
+ - "question"
CodeWriterCtrlFlow.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from dataclasses import dataclass
8
+
9
+
10
+ @dataclass
11
+ class Command:
12
+ name: str
13
+ description: str
14
+ input_args: List[str]
15
+
16
+ class CodeWriterCtrlFlow(ChatAtomicFlow):
17
+ def __init__(
18
+ self,
19
+ commands: List[Command],
20
+ **kwargs):
21
+ super().__init__(**kwargs)
22
+ self.system_message_prompt_template = self.system_message_prompt_template.partial(
23
+ commands=self._build_commands_manual(commands),
24
+ )
25
+ self.hint_for_model = """
26
+ Make sure your response is in the following format:
27
+ Response Format:
28
+ {
29
+ "command": "call code writer, the tester, or to finish",
30
+ "command_args": {
31
+ "arg name": "value"
32
+ }
33
+ }
34
+ """
35
+
36
+ @staticmethod
37
+ def _build_commands_manual(commands: List[Command]) -> str:
38
+ ret = ""
39
+ for i, command in enumerate(commands):
40
+ command_input_json_schema = json.dumps(
41
+ {input_arg: f"YOUR_{input_arg.upper()}" for input_arg in command.input_args})
42
+ ret += f"{i + 1}. {command.name}: {command.description} Input arguments (given in the JSON schema): {command_input_json_schema}\n"
43
+ return ret
44
+
45
+ @classmethod
46
+ def instantiate_from_config(cls, config):
47
+ flow_config = deepcopy(config)
48
+
49
+ kwargs = {"flow_config": flow_config}
50
+
51
+ # ~~~ Set up prompts ~~~
52
+ kwargs.update(cls._set_up_prompts(flow_config))
53
+
54
+ # ~~~Set up backend ~~~
55
+ kwargs.update(cls._set_up_backend(flow_config))
56
+
57
+ # ~~~ Set up commands ~~~
58
+ commands = flow_config["commands"]
59
+ commands = [
60
+ Command(name, command_conf["description"], command_conf["input_args"]) for name, command_conf in
61
+ commands.items()
62
+ ]
63
+ kwargs.update({"commands": commands})
64
+
65
+ # ~~~ Instantiate flow ~~~
66
+ return cls(**kwargs)
67
+
68
+ def _update_prompts_and_input(self, input_data: Dict[str, Any]):
69
+ if 'goal' in input_data:
70
+ input_data['goal'] += self.hint_for_model
71
+ if 'feedback' in input_data:
72
+ input_data['feedback'] += self.hint_for_model
73
+
74
+ def run(self, input_data: Dict[str, Any]) -> Dict[str, Any]:
75
+ self._update_prompts_and_input(input_data)
76
+ api_output = super().run(input_data)["api_output"].strip()
77
+ try:
78
+ response = json.loads(api_output)
79
+ return response
80
+ except json.decoder.JSONDecodeError:
81
+ new_input_data = input_data.copy()
82
+ new_input_data['feedback'] = "The previous respond cannot be parsed with json.loads. Make sure your next response is in JSON format."
83
+ new_api_output = super().run(new_input_data)["api_output"].strip()
84
+ return json.loads(new_api_output)
CodeWriterCtrlFlow.yaml ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: "CodeWriterControllerFlow"
2
+ description: "Proposes the next action to take towards achieving the goal, and prepares the input for the branching flow"
3
+ enable_cache: True
4
+
5
+ #######################################################
6
+ # Input keys
7
+ #######################################################
8
+
9
+ input_interface_non_initialized: # initial input keys
10
+ - "goal"
11
+
12
+ input_interface_initialized:
13
+ - "code"
14
+ - "feedback"
15
+
16
+ #######################################################
17
+ # Output keys
18
+ #######################################################
19
+
20
+ output_interface:
21
+ - 'command'
22
+ - 'command_args'
23
+
24
+ backend:
25
+ api_infos: ???
26
+ model_name:
27
+ openai: gpt-4
28
+ azure: azure/gpt-4
29
+
30
+ commands:
31
+ write_code:
32
+ description: "Write code to finish the goal with user interaction"
33
+ input_args: ["goal"]
34
+ finish:
35
+ description: "Signal that the objective has been satisfied, and returns the answer to the user."
36
+ input_args: []
37
+ ask_user:
38
+ description: "Ask user a question for confirmation or assistance"
39
+ input_args: ["question"]
40
+ test:
41
+ description: "test the code generated from write_code"
42
+ input_args: []
43
+
44
+ system_message_prompt_template:
45
+ _target_: langchain.PromptTemplate
46
+ template: |2-
47
+ You are in charge of a department of writing code to solve a certain goal. You work with a coder, who does all the coding job; and a code tester, who does all the testing job.
48
+
49
+ Your **ONLY** task is to take the user's goal for you, to decide whether to call the coder to write or re-write the code, to call the tester to test the code, or to finish the current task.
50
+
51
+ When you need to call the code writer, call the `write_code` command with the goal specified.
52
+ When you need to call the code tester, call the `test` command to test the code written.
53
+ When the code is written and the user is satisfied, call the `finish` command to terminate the current process.
54
+ Whenever you are in doubt, or need to confirm something to the user, call `ask_user` with the question.
55
+
56
+ The coder will only write one function per goal, make sure you are not asking the coder to write more than one function.
57
+
58
+ You **must not** write code yourself. You only decide whether to call the coder with specified goals or to finish.
59
+
60
+ Your workflow:
61
+ 1. Upon user request, call the `write_code` with the goal given.
62
+ 2. The coder will write code, which is a function. The user will examine the code, and provide feedback.
63
+ 3. Depending on the feedback of the user:
64
+ 3.1. The user provides feedback on how to change the code, **call the coder with user's specific requirements again, to ask the coder to refine the code**. Go back to step 2.
65
+ 3.2. The user does not provide details about refining the code, for example, just stating the fact that the user has updated the code, **this means the user is satisfied with the code written, call the `finish` command.**
66
+ 4. If the user is satisfied with the code, call `test` to test the code
67
+ 5. Depending on the result of the test:
68
+ 5.1 Test passes, terminate the current process with the `finish command`
69
+ 5.2 Test fails, **call the coder with details of the test results to instruct the coder to refine the code**, go back to step 2.
70
+
71
+ If you have completed all your tasks, make sure to use the "finish" command.
72
+
73
+ Constraints:
74
+ 1. Exclusively use the commands listed in double quotes e.g. "command name"
75
+
76
+ Your response **MUST** be in the following format:
77
+ Response Format:
78
+ {
79
+ "command": "call code writer, the tester, or to finish",
80
+ "command_args": {
81
+ "arg name": "value"
82
+ }
83
+ }
84
+ Ensure your responses can be parsed by Python json.loads
85
+
86
+
87
+ Available Functions:
88
+ {{commands}}
89
+ input_variables: ["commands"]
90
+ template_format: jinja2
91
+
92
+ human_message_prompt_template:
93
+ _target_: flows.prompt_template.JinjaPrompt
94
+ template: |2-
95
+ Here is the code written by the coder, it might have been updated by the user, depending on the user's feedback:
96
+ {{code}}
97
+ Here is the feedback, depending on the last command you called, it either came from the user or the tester:
98
+ {{feedback}}
99
+ input_variables:
100
+ - "code"
101
+ - "feedback"
102
+ template_format: jinja2
103
+
104
+ init_human_message_prompt_template:
105
+ _target_: flows.prompt_template.JinjaPrompt
106
+ template: |2-
107
+ Here is the goal you need to achieve:
108
+ {{goal}}
109
+ input_variables:
110
+ - "goal"
111
+ template_format: jinja2
CodeWriterFlow.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict, Any
2
+ import os
3
+
4
+ from flow_modules.Tachi67.ContentWriterFlowModule import ContentWriterFlow
5
+ from flows.base_flows import CircularFlow
6
+
7
+
8
+ class CodeWriterFlow(ContentWriterFlow):
9
+ def _on_reach_max_round(self):
10
+ self._state_update_dict({
11
+ "code": "The maximum amount of rounds was reached before the model generated the code.",
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
+ # ~~~ delete the temp code file ~~~
20
+ keys_to_fetch_from_state = ["temp_code_file_location", "code"]
21
+ fetched_state = self._fetch_state_attributes_by_keys(keys=keys_to_fetch_from_state)
22
+ temp_code_file_location = fetched_state["temp_code_file_location"]
23
+ code_content = fetched_state["code"]
24
+ if os.path.exists(temp_code_file_location):
25
+ os.remove(temp_code_file_location)
26
+ # ~~~ return the code content ~~~
27
+ return {
28
+ "EARLY_EXIT": True,
29
+ "code": code_content,
30
+ "status": "finished"
31
+ }
32
+ elif command == "test":
33
+ # ~~~ fetch code string from flow state ~~~
34
+ keys_to_fetch_from_state = ["code"]
35
+ fetched_state = self._fetch_state_attributes_by_keys(keys=keys_to_fetch_from_state)
36
+
37
+ # ~~~ add code content to the command args (branch input data) ~~~
38
+ code_content = fetched_state["code"]
39
+ output_payload["command_args"]["code"] = code_content
40
+
41
+ return output_payload
42
+ else:
43
+ return output_payload
CodeWriterFlow.yaml ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: "CodeWriter"
2
+ description: "Generates code with interactions with the user"
3
+
4
+ _target_: Tachi67.CodeWriterFlowModule.CodeWriterFlow.instantiate_from_default_config
5
+
6
+ output_interface:
7
+ - "code"
8
+ - "status"
9
+
10
+ ### Subflows specification
11
+ subflows_config:
12
+ Controller:
13
+ _target_: Tachi67.CodeWriterFlowModule.CodeWriterCtrlFlow.instantiate_from_default_config
14
+ backend:
15
+ api_infos: ???
16
+ model_name:
17
+ openai: gpt-4
18
+ azure: azure/gpt-4
19
+
20
+ Executor:
21
+ _target_: flows.base_flows.BranchingFlow.instantiate_from_default_config
22
+ subflows_config:
23
+ write_code:
24
+ _target_: Tachi67.InteractiveCodeGenFlowModule.InteractiveCodeGenFlow.instantiate_from_default_config
25
+ subflows_config:
26
+ MemoryReading:
27
+ _target_: Tachi67.MemoryReadingFlowModule.MemoryReadingAtomicFlow.instantiate_from_default_config
28
+
29
+ CodeGenerator:
30
+ _target_: Tachi67.CodeGeneratorFlowModule.CodeGeneratorAtomicFlow.instantiate_from_default_config
31
+ backend:
32
+ api_infos: ???
33
+ model_name:
34
+ openai: gpt-4
35
+ azure: azure/gpt-4
36
+
37
+ CodeFileEditor:
38
+ _target_: Tachi67.CodeFileEditFlowModule.CodeFileEditAtomicFlow.instantiate_from_default_config
39
+
40
+ ParseFeedback:
41
+ _target_: Tachi67.ParseFeedbackFlowModule.ParseFeedbackAtomicFlow.instantiate_from_default_config
42
+
43
+ ask_user:
44
+ _target_: Tachi67.CodeWriterFlowModule.CodeWriterAskUserFlow.instantiate_from_default_config
45
+
46
+ test:
47
+ _target_: Tachi67.TestCodeFlowModule.TestCodeFlow.instantiate_from_default_config
48
+
49
+
50
+ early_exit_key: "EARLY_EXIT"
51
+
52
+ topology:
53
+ - goal: "Select the next action and prepare the input for the executor."
54
+ input_interface:
55
+ _target_: flows.interfaces.KeyInterface
56
+ additional_transformations:
57
+ - _target_: flows.data_transformations.KeyMatchInput
58
+ flow: Controller
59
+ output_interface:
60
+ _target_: CodeWriterFlow.detect_finish_or_continue
61
+ reset: false
62
+
63
+ - goal: "Execute the action specified by the Controller."
64
+ input_interface:
65
+ _target_: flows.interfaces.KeyInterface
66
+ keys_to_rename:
67
+ command: branch
68
+ command_args: branch_input_data
69
+ keys_to_select: ["branch", "branch_input_data"]
70
+ flow: Executor
71
+ output_interface:
72
+ _target_: flows.interfaces.KeyInterface
73
+ keys_to_rename:
74
+ branch_output_data: observation
75
+ keys_to_unpack: ["observation"]
76
+ reset: false
__init__.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dependencies = [
2
+ {"url": "Tachi67/ContentWriterFlowModule", "revision": "main"},
3
+ {"url": "Tachi67/InteractiveCodeGenFlowModule", "revision": "main"},
4
+ {"url": "Tachi67/TestCodeFlowModule", "revision": "main"},
5
+ {"url": "aiflows/ChatFlowModule", "revision": "a749ad10ed39776ba6721c37d0dc22af49ca0f17"},
6
+ {"url": "aiflows/HumanStandardInputFlowModule", "revision": "5683a922372c5fa90be9f6447d6662d8d80341fc"}
7
+ ]
8
+ from flows import flow_verse
9
+
10
+ flow_verse.sync_dependencies(dependencies)
11
+
12
+ from .CodeWriterFlow import CodeWriterFlow
13
+ from .CodeWriterCtrlFlow import CodeWriterCtrlFlow
14
+ from .CodeWriterAskUserFlow import CodeWriterAskUserFlow