bioguider 0.2.3__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.

Potentially problematic release.


This version of bioguider might be problematic. Click here for more details.

Files changed (47) hide show
  1. bioguider/__init__.py +0 -0
  2. bioguider/agents/__init__.py +0 -0
  3. bioguider/agents/agent_task.py +88 -0
  4. bioguider/agents/agent_tools.py +147 -0
  5. bioguider/agents/agent_utils.py +357 -0
  6. bioguider/agents/collection_execute_step.py +180 -0
  7. bioguider/agents/collection_observe_step.py +113 -0
  8. bioguider/agents/collection_plan_step.py +154 -0
  9. bioguider/agents/collection_task.py +179 -0
  10. bioguider/agents/collection_task_utils.py +109 -0
  11. bioguider/agents/common_agent.py +159 -0
  12. bioguider/agents/common_agent_2step.py +126 -0
  13. bioguider/agents/common_step.py +85 -0
  14. bioguider/agents/dockergeneration_execute_step.py +186 -0
  15. bioguider/agents/dockergeneration_observe_step.py +153 -0
  16. bioguider/agents/dockergeneration_plan_step.py +158 -0
  17. bioguider/agents/dockergeneration_task.py +158 -0
  18. bioguider/agents/dockergeneration_task_utils.py +220 -0
  19. bioguider/agents/evaluation_task.py +269 -0
  20. bioguider/agents/identification_execute_step.py +179 -0
  21. bioguider/agents/identification_observe_step.py +92 -0
  22. bioguider/agents/identification_plan_step.py +135 -0
  23. bioguider/agents/identification_task.py +220 -0
  24. bioguider/agents/identification_task_utils.py +18 -0
  25. bioguider/agents/peo_common_step.py +64 -0
  26. bioguider/agents/prompt_utils.py +190 -0
  27. bioguider/agents/python_ast_repl_tool.py +69 -0
  28. bioguider/agents/rag_collection_task.py +130 -0
  29. bioguider/conversation.py +67 -0
  30. bioguider/database/summarized_file_db.py +140 -0
  31. bioguider/managers/evaluation_manager.py +108 -0
  32. bioguider/rag/__init__.py +0 -0
  33. bioguider/rag/config.py +117 -0
  34. bioguider/rag/data_pipeline.py +648 -0
  35. bioguider/rag/embedder.py +24 -0
  36. bioguider/rag/rag.py +134 -0
  37. bioguider/settings.py +103 -0
  38. bioguider/utils/constants.py +40 -0
  39. bioguider/utils/default.gitignore +140 -0
  40. bioguider/utils/file_utils.py +126 -0
  41. bioguider/utils/gitignore_checker.py +175 -0
  42. bioguider/utils/pyphen_utils.py +73 -0
  43. bioguider/utils/utils.py +27 -0
  44. bioguider-0.2.3.dist-info/LICENSE +21 -0
  45. bioguider-0.2.3.dist-info/METADATA +44 -0
  46. bioguider-0.2.3.dist-info/RECORD +47 -0
  47. bioguider-0.2.3.dist-info/WHEEL +4 -0
@@ -0,0 +1,109 @@
1
+ import os
2
+ from typing import Callable, Optional, TypedDict
3
+ from langchain.prompts import ChatPromptTemplate
4
+ from langchain_openai.chat_models.base import BaseChatOpenAI
5
+ from langchain_core.messages import AIMessage
6
+ from pydantic import BaseModel, Field
7
+
8
+ from bioguider.agents.agent_tools import agent_tool
9
+ from bioguider.agents.agent_utils import read_file, summarize_file
10
+ from bioguider.agents.peo_common_step import PEOWorkflowState
11
+ from bioguider.agents.common_agent import CommonAgent
12
+ from bioguider.agents.common_agent_2step import CommonAgentTwoSteps
13
+
14
+
15
+ class CollectionWorkflowState(TypedDict):
16
+ llm: Optional[BaseChatOpenAI]
17
+ step_output_callback: Optional[Callable]
18
+
19
+ intermediate_steps: Optional[str]
20
+ step_output: Optional[str]
21
+ step_analysis: Optional[str]
22
+ step_thoughts: Optional[str]
23
+ plan_actions: Optional[list[dict]]
24
+
25
+ goal_item: Optional[str]
26
+ final_answer: Optional[str]
27
+
28
+ RELATED_FILE_GOAL_ITEM = """
29
+ Your task is to determine whether the file is related to **{goal_item}**.
30
+
31
+ {related_file_description}
32
+ """
33
+
34
+ CHECK_FILE_RELATED_USER_PROMPT = ChatPromptTemplate.from_template("""
35
+ You are given a summary of a file’s content.
36
+
37
+ {goal_item_desc}
38
+
39
+ Here is the file summary:
40
+ ```
41
+ {summarized_file_content}
42
+ ```
43
+
44
+ ### **Question:**
45
+ Does this file appear to contain related information?
46
+
47
+ ---
48
+
49
+ ### **Output Format:**
50
+ Respond with a single word: "Yes" or "No" to indicate whether the file is related to the goal item.
51
+ Do not include any additional text, explanation, or formatting.
52
+ """)
53
+
54
+ class CheckFileRelatedResult(BaseModel):
55
+ is_related: bool = Field(description="True if the file is related to the goal item, False otherwise.")
56
+
57
+ class check_file_related_tool(agent_tool):
58
+ """ Check if the file is related to the goal item
59
+ Args:
60
+ file_path str: file path
61
+ Returns:
62
+ bool: True if the file is related to the goal item, False otherwise.
63
+ """
64
+ def __init__(
65
+ self,
66
+ llm: BaseChatOpenAI,
67
+ repo_path: str,
68
+ goal_item_desc: str,
69
+ output_callback: Callable | None = None,
70
+ ):
71
+ super().__init__(llm=llm, output_callback=output_callback)
72
+ self.repo_path = repo_path
73
+ self.goal_item_desc = goal_item_desc
74
+
75
+ def run(self, file_path: str) -> str:
76
+ if not self.repo_path in file_path:
77
+ file_path = os.path.join(self.repo_path, file_path)
78
+ if not os.path.isfile(file_path):
79
+ return "Can't read file"
80
+ file_content = read_file(file_path)
81
+ if file_content is None:
82
+ return "Failed to read file"
83
+ summarized_content, token_usage = summarize_file(self.llm, file_path, file_content, 6)
84
+ if summarized_content is None:
85
+ return "Failed to summarize file"
86
+ self._print_token_usage(token_usage)
87
+
88
+ prompt = CHECK_FILE_RELATED_USER_PROMPT.format(
89
+ goal_item_desc=self.goal_item_desc,
90
+ summarized_file_content=summarized_content,
91
+ )
92
+
93
+ agent = CommonAgentTwoSteps(llm=self.llm)
94
+ res, _, token_usage, reasoning = agent.go(
95
+ system_prompt=prompt,
96
+ instruction_prompt="Now, please check if the file is related to the goal item.",
97
+ schema=CheckFileRelatedResult,
98
+ )
99
+ # res: AIMessage = self.llm.invoke([("human", prompt)])
100
+ res: CheckFileRelatedResult = res
101
+ out = res.is_related
102
+
103
+ self._print_step_output(step_output=reasoning)
104
+ self._print_token_usage(token_usage)
105
+ if out:
106
+ return "Yes, the file is related to the goal item."
107
+ else:
108
+ return "No, the file **is not** related to the goal item."
109
+
@@ -0,0 +1,159 @@
1
+ from typing import Any, Callable, Optional
2
+ from langchain_core.prompts import ChatPromptTemplate
3
+ from langchain_openai.chat_models.base import BaseChatOpenAI
4
+ from langchain_community.callbacks.openai_info import OpenAICallbackHandler
5
+ from langchain_core.messages import SystemMessage, HumanMessage
6
+ from pydantic import BaseModel, Field
7
+ from tenacity import retry, stop_after_attempt, wait_incrementing
8
+ import logging
9
+
10
+ from bioguider.agents.agent_utils import (
11
+ escape_braces,
12
+ increase_token_usage,
13
+ )
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class RetryException(Exception):
18
+ """Exception need to retry"""
19
+
20
+ pass
21
+
22
+
23
+ class CommonAgentResult(BaseModel):
24
+ reasoning_process: str = Field(
25
+ description="A detailed explanation of the thought process or reasoning steps taken to reach a conclusion."
26
+ )
27
+
28
+
29
+ class CommonAgent:
30
+ def __init__(self, llm: BaseChatOpenAI):
31
+ self.llm = llm
32
+ self.exception: RetryException | None = None
33
+ self.token_usage: dict | None = None
34
+
35
+ def go(
36
+ self,
37
+ system_prompt: str,
38
+ instruction_prompt: str,
39
+ schema: any,
40
+ pre_process: Optional[Callable] = None,
41
+ post_process: Optional[Callable] = None,
42
+ **kwargs: Optional[Any],
43
+ ):
44
+ """
45
+ execute agent
46
+
47
+ Args:
48
+ system_prompt str: system prompt
49
+ instruction_prompt str: user prompt to guide how llm execute agent
50
+ schema pydantic.BaseModel or json schema: llm output result schema
51
+ pre_process Callable or None: pre-processor that would be executed before llm.invoke
52
+ post_process Callable or None: post-processor that would be executed after llm.invoke
53
+ kwargs None or dict: args for pre_proces and post_process
54
+
55
+ Return:
56
+ (output that comply with input args `schema`)
57
+ """
58
+ self._initialize()
59
+ if pre_process is not None:
60
+ is_OK = pre_process(**kwargs)
61
+ if not is_OK: # skip
62
+ return
63
+
64
+ return self._invoke_agent(
65
+ system_prompt,
66
+ instruction_prompt,
67
+ schema,
68
+ post_process,
69
+ **kwargs,
70
+ )
71
+
72
+ def _initialize(self):
73
+ self.exception = None
74
+ self.token_usage = None
75
+
76
+ def _process_retryexception_message(
77
+ self, prompt: ChatPromptTemplate
78
+ ) -> ChatPromptTemplate:
79
+ if self.exception is None:
80
+ return prompt
81
+
82
+ existing_messages = prompt.messages
83
+ updated_messages = existing_messages + [("human", str(self.exception))]
84
+ self.exception = None
85
+ updated_prompt = ChatPromptTemplate.from_messages(updated_messages)
86
+ return updated_prompt
87
+
88
+ def _incre_token_usage(self, token_usage):
89
+ incremental_token_usage = token_usage
90
+ if not isinstance(token_usage, dict):
91
+ incremental_token_usage = vars(incremental_token_usage)
92
+ self.token_usage = increase_token_usage(
93
+ self.token_usage, incremental_token_usage
94
+ )
95
+
96
+ @retry(
97
+ stop=stop_after_attempt(5),
98
+ wait=wait_incrementing(start=1.0, increment=3, max=10),
99
+ )
100
+ def _invoke_agent(
101
+ self,
102
+ system_prompt: str,
103
+ instruction_prompt: str,
104
+ schema: any,
105
+ post_process: Optional[Callable] = None,
106
+ **kwargs: Optional[Any],
107
+ ) -> tuple[Any, Any, dict | None, Any | None]:
108
+ system_prompt = escape_braces(system_prompt)
109
+ prompt = ChatPromptTemplate.from_messages([
110
+ ("system", system_prompt),
111
+ ("human", instruction_prompt),
112
+ ])
113
+ # Initialize the callback handler
114
+ callback_handler = OpenAICallbackHandler()
115
+
116
+ updated_prompt = self._process_retryexception_message(prompt)
117
+ agent = updated_prompt | self.llm.with_structured_output(schema)
118
+ try:
119
+ res = agent.invoke(
120
+ input={},
121
+ config={
122
+ "callbacks": [callback_handler],
123
+ },
124
+ )
125
+ self._incre_token_usage(callback_handler)
126
+ except Exception as e:
127
+ logger.error(str(e))
128
+ raise e
129
+ processed_res = res
130
+ if post_process is not None:
131
+ try:
132
+ processed_res = post_process(res, **kwargs)
133
+ except RetryException as e:
134
+ logger.error(str(e))
135
+ self.exception = e
136
+ raise e
137
+ except Exception as e:
138
+ logger.error(str(e))
139
+ raise e
140
+ return res, processed_res, self.token_usage, None
141
+
142
+ class CommonConversation:
143
+ def __init__(self, llm: BaseChatOpenAI):
144
+ self.llm = llm
145
+
146
+ def generate(self, system_prompt: str, instruction_prompt: str):
147
+ msgs = [
148
+ SystemMessage(system_prompt),
149
+ HumanMessage(instruction_prompt),
150
+ ]
151
+ msgs_template = ChatPromptTemplate.from_messages(messages=msgs)
152
+ callback_handler = OpenAICallbackHandler()
153
+ result = self.llm.generate(
154
+ messages=[msgs],
155
+ callbacks=[callback_handler]
156
+ )
157
+ response = result.generations[0][0].text
158
+ token_usage = result.llm_output.get("token_usage")
159
+ return response, token_usage
@@ -0,0 +1,126 @@
1
+ from typing import Any, Callable, Optional
2
+ from langchain_core.prompts import ChatPromptTemplate
3
+ from langchain_openai.chat_models.base import BaseChatOpenAI
4
+ from langchain_community.callbacks.openai_info import OpenAICallbackHandler
5
+ from pydantic import BaseModel, Field
6
+ from tenacity import retry, stop_after_attempt, wait_incrementing
7
+ import logging
8
+
9
+ from bioguider.agents.agent_utils import escape_braces
10
+ from bioguider.agents.common_agent import (
11
+ CommonAgent,
12
+ RetryException,
13
+ )
14
+ from bioguider.agents.prompt_utils import COT_USER_INSTRUCTION
15
+
16
+ logger = logging.getLogger()
17
+
18
+
19
+ class CommonAgentTwoSteps(CommonAgent):
20
+ def __init__(self, llm: BaseChatOpenAI):
21
+ super().__init__(llm)
22
+
23
+ def _initialize(self):
24
+ self.exceptions = None
25
+ self.token_usage = None
26
+
27
+ def _get_retryexception_message(self) -> list[tuple[str, str]]:
28
+ if self.exceptions is None:
29
+ return None
30
+ return [("human", str(excp)) for excp in self.exceptions]
31
+
32
+ def _build_prompt_for_cot_step(
33
+ self,
34
+ system_prompt: str,
35
+ instruction_prompt: str,
36
+ ):
37
+ # system_prompt = system_prompt.replace("{", "{{").replace("}", "}}")
38
+ system_prompt = escape_braces(system_prompt)
39
+ instruction_prompt = instruction_prompt.replace("{", "{{").replace("}", "}}")
40
+ msgs = [("system", system_prompt)]
41
+ msgs = msgs + [("human", instruction_prompt)]
42
+ exception_msgs = self._get_retryexception_message()
43
+ if exception_msgs is not None:
44
+ msgs = msgs + exception_msgs
45
+ msgs = msgs + [("human", COT_USER_INSTRUCTION)]
46
+ return ChatPromptTemplate.from_messages(msgs)
47
+
48
+ def _build_prompt_for_final_step(
49
+ self,
50
+ system_prompt: str,
51
+ cot_msg: str,
52
+ ):
53
+ system_prompt = system_prompt.replace("{", "{{").replace("}", "}}")
54
+ msgs = [("system", system_prompt)]
55
+ cot_msg = cot_msg.replace("{", "{{").replace("}", "}}")
56
+ msgs = msgs + [(
57
+ "human",
58
+ f"Please review the following step-by-step reasoning and provide the answer based on it: ```{cot_msg}```"
59
+ )]
60
+ return ChatPromptTemplate.from_messages(msgs)
61
+
62
+ @retry(
63
+ stop=stop_after_attempt(5),
64
+ wait=wait_incrementing(start=1.0, increment=3, max=10),
65
+ )
66
+ def _invoke_agent(
67
+ self,
68
+ system_prompt: str,
69
+ instruction_prompt: str,
70
+ schema: any,
71
+ post_process: Optional[Callable] = None,
72
+ **kwargs: Optional[Any],
73
+ ):
74
+ # Initialize the callback handler
75
+ callback_handler = OpenAICallbackHandler()
76
+ cot_prompt = self._build_prompt_for_cot_step(
77
+ system_prompt=system_prompt,
78
+ instruction_prompt=instruction_prompt
79
+ )
80
+
81
+ try:
82
+ # First, use llm to do CoT
83
+ msgs = cot_prompt.invoke(input={}).to_messages()
84
+
85
+ cot_res = self.llm.generate(messages=[msgs])
86
+ reasoning_process = cot_res.generations[0][0].text
87
+ token_usage = cot_res.llm_output.get("token_usage")
88
+ cot_tokens = {
89
+ "total_tokens": token_usage.get("total_tokens", 0),
90
+ "prompt_tokens": token_usage.get("prompt_tokens", 0),
91
+ "completion_tokens": token_usage.get("completion_tokens", 0),
92
+ }
93
+ self._incre_token_usage(cot_tokens)
94
+ except Exception as e:
95
+ logger.error(str(e))
96
+ raise e
97
+
98
+ # Then use the reasoning process to do the structured output
99
+ updated_prompt = self._build_prompt_for_final_step(
100
+ system_prompt=system_prompt,
101
+ cot_msg=reasoning_process,
102
+ )
103
+ agent = updated_prompt | self.llm.with_structured_output(schema)
104
+ try:
105
+ res = agent.invoke(
106
+ input={},
107
+ config={
108
+ "callbacks": [callback_handler],
109
+ },
110
+ )
111
+ self._incre_token_usage(callback_handler)
112
+ except Exception as e:
113
+ logger.error(str(e))
114
+ raise e
115
+ processed_res = None
116
+ if post_process is not None:
117
+ try:
118
+ processed_res = post_process(res, **kwargs)
119
+ except RetryException as e:
120
+ logger.error(str(e))
121
+ self.exceptions = [e] if self.exceptions is None else self.exceptions + [e]
122
+ raise e
123
+ except Exception as e:
124
+ logger.error(str(e))
125
+ raise e
126
+ return res, processed_res, self.token_usage, reasoning_process
@@ -0,0 +1,85 @@
1
+
2
+ from abc import ABC, abstractmethod
3
+ from typing import Any, Callable, Dict, Optional, TypedDict
4
+ import logging
5
+ from langchain_openai.chat_models.base import BaseChatOpenAI
6
+
7
+ from bioguider.utils.constants import DEFAULT_TOKEN_USAGE
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class CommonState(TypedDict):
12
+ """
13
+ CommonState is a TypedDict that defines the structure of the state
14
+ used in the CommonStep class.
15
+ """
16
+ llm: Optional[BaseChatOpenAI]
17
+ step_output_callback: Optional[Callable]
18
+
19
+ class CommonStep(ABC):
20
+ """
21
+ CommonStep is a base class for defining common steps in a workflow.
22
+ It provides methods to execute the step and handle exceptions.
23
+ """
24
+
25
+ def __init__(self):
26
+ super().__init__()
27
+ self.step_name = ""
28
+
29
+ def enter_step(self, state):
30
+ if state["step_output_callback"] is None:
31
+ return
32
+ state["step_output_callback"](
33
+ step_name=self.step_name,
34
+ )
35
+
36
+ def leave_step(self, state, token_usage: Optional[dict[str, int]] = None):
37
+ if state["step_output_callback"] is None:
38
+ return
39
+ if token_usage is not None:
40
+ state["step_output_callback"](token_usage=token_usage)
41
+
42
+ def execute(self, state):
43
+ """
44
+ Execute the step. This method should be overridden by subclasses.
45
+ """
46
+ self.enter_step(state)
47
+ state, token_usage = self._execute_directly(state)
48
+ self.leave_step(state, token_usage)
49
+ return state
50
+
51
+ def _print_step(
52
+ self,
53
+ state,
54
+ step_name: str | None = None,
55
+ step_output: str | None = None,
56
+ token_usage: dict | object | None = None,
57
+ ):
58
+ step_callback = state["step_output_callback"]
59
+ if step_callback is None:
60
+ return
61
+ # convert token_usage to dict
62
+ if token_usage is not None and not isinstance(token_usage, dict):
63
+ token_usage = vars(token_usage)
64
+ # In case token_usage.total_tokens is 0
65
+ token_usage = { **DEFAULT_TOKEN_USAGE, **token_usage }
66
+ step_callback(
67
+ step_name=step_name,
68
+ step_output=step_output,
69
+ token_usage=token_usage,
70
+ )
71
+
72
+ @abstractmethod
73
+ def _execute_directly(self, state) -> tuple[dict, dict[str, int]]:
74
+ """
75
+ Execute the step directly. This method should be overridden by subclasses.
76
+ Args:
77
+ state (CommonState): The state of the workflow.
78
+ Returns:
79
+ tuple[dict, dict[str, int]]: The updated state and token usage.
80
+ """
81
+ pass
82
+
83
+
84
+
85
+
@@ -0,0 +1,186 @@
1
+
2
+ import logging
3
+ from langchain_openai.chat_models.base import BaseChatOpenAI
4
+ from langchain.tools import BaseTool
5
+ from langchain.agents import create_react_agent, AgentExecutor
6
+ from langchain_community.callbacks.openai_info import OpenAICallbackHandler
7
+
8
+ from bioguider.utils.constants import DEFAULT_TOKEN_USAGE
9
+ from bioguider.agents.agent_utils import (
10
+ CustomPromptTemplate,
11
+ CustomOutputParser,
12
+ )
13
+ from bioguider.agents.peo_common_step import PEOCommonStep
14
+ from bioguider.agents.dockergeneration_task_utils import (
15
+ DockerGenerationWorkflowState,
16
+ generate_Dockerfile_tool,
17
+ )
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ DOCKERGENERATION_EXECUTION_SYSTEM_PROMPT = """You are an expert in software containerization and reproducibility engineering.
22
+ You are given a **plan** and must complete it strictly using Python code and the available tools.
23
+
24
+ ---
25
+ ### **Available Tools**
26
+ {tools}
27
+
28
+ ---
29
+ ### **Your Task**
30
+ Follow the given plan step by step using the exact format below:
31
+
32
+ ```
33
+ Thought: Describe what you are thinking or planning to do next.
34
+ Action: The tool you are going to use (must be one of: {tool_names})
35
+ Action Input: The input to the selected action
36
+ Observation: The result returned by the action
37
+ ```
38
+
39
+ You may repeat the **Thought → Action → Action Input → Observation** loop as needed.
40
+
41
+ Once all steps in the plan have been executed, end the loop and output all the results and generated Dockerfile using this format:
42
+
43
+ ```
44
+ Thought: I have completed the plan.
45
+ Final Answer:
46
+ Action: {{tool_name}}
47
+ Action Input: {{file_name1}}
48
+ Action Observation: {{Observation1}}
49
+ ---
50
+ Action: {{tool_name}}
51
+ Action Input: {{file_name2}}
52
+ Action Observation: {{Observation2}}
53
+ ---
54
+ **Dockerfile file name**: {{docker file path}}
55
+ ...
56
+ ```
57
+
58
+ ---
59
+
60
+ ### **Important Notes**
61
+
62
+ - You must strictly follow the provided plan.
63
+ - **Do not take any additional or alternative actions**, even if:
64
+ - No relevant result is found
65
+ - The file content is missing, empty, or irrelevant
66
+ - If no information is found in a step, simply proceed to the next action in the plan without improvising.
67
+ - Only use the tools specified in the plan actions. No independent decisions or extra steps are allowed.
68
+ ---
69
+
70
+ ### **Plan**
71
+ {plan_actions}
72
+
73
+ ### **Plan Thoughts**
74
+ {plan_thoughts}
75
+
76
+ ### **Actions Already Taken**
77
+ {agent_scratchpad}
78
+
79
+ ---
80
+
81
+ {input}
82
+
83
+ ---
84
+ """
85
+
86
+ class DockerGenerationExecuteStep(PEOCommonStep):
87
+ def __init__(
88
+ self,
89
+ llm: BaseChatOpenAI,
90
+ repo_path: str,
91
+ repo_structure: str,
92
+ gitignore_path: str,
93
+ custom_tools: list[BaseTool] | None = None,
94
+ ):
95
+ super().__init__(llm)
96
+ self.step_name = "Docker Generation Execute Step"
97
+ self.repo_path = repo_path
98
+ self.repo_structure = repo_structure
99
+ self.gitignore_path = gitignore_path
100
+ self.custom_tools = custom_tools if custom_tools is not None else []
101
+ self.generate_tool: generate_Dockerfile_tool | None = None
102
+
103
+ def set_generate_Dockerfile_tool(self, tool: generate_Dockerfile_tool):
104
+ self.generate_tool = tool
105
+
106
+ def _execute_directly(self, state: DockerGenerationWorkflowState):
107
+ plan_actions = state["plan_actions"]
108
+ plan_thoughts = state["plan_thoughts"]
109
+ step_output = state["step_output"] if "step_output" in state and \
110
+ state["step_output"] is not None else "N/A"
111
+ step_dockerfile_content = state["step_dockerfile_content"] if "step_dockerfile_content" in state and \
112
+ state["step_dockerfile_content"] is not None else "N/A"
113
+ self.generate_tool.set_intermediate_output(
114
+ plan_thoughts=plan_thoughts,
115
+ step_error=step_output,
116
+ step_dockerfile_content=step_dockerfile_content,
117
+ )
118
+ prompt = CustomPromptTemplate(
119
+ template=DOCKERGENERATION_EXECUTION_SYSTEM_PROMPT,
120
+ tools=self.custom_tools,
121
+ plan_actions=plan_actions,
122
+ input_variables=[
123
+ "tools", "tool_names", "agent_scratchpad",
124
+ "intermediate_steps", "plan_actions", "plan_thoughts",
125
+ ],
126
+ )
127
+ output_parser = CustomOutputParser()
128
+ agent = create_react_agent(
129
+ llm = self.llm,
130
+ tools = self.custom_tools,
131
+ prompt = prompt,
132
+ output_parser=output_parser,
133
+ stop_sequence=["\nObservation:"],
134
+ )
135
+ callback_handler = OpenAICallbackHandler()
136
+ agent_executor = AgentExecutor(
137
+ agent=agent,
138
+ tools=self.custom_tools,
139
+ max_iterations=10,
140
+ )
141
+ response = agent_executor.invoke(
142
+ input={
143
+ "plan_actions": plan_actions,
144
+ "plan_thoughts": plan_thoughts,
145
+ "input": "Now, let's begin."
146
+ },
147
+ config={
148
+ "callbacks": [callback_handler],
149
+ "recursion_limit": 20,
150
+ }
151
+ )
152
+ if "output" in response:
153
+ output = response["output"]
154
+ self._print_step(state, step_output=f"**Execute Output:** \n{output}")
155
+ if "**Final Answer**" in output:
156
+ final_answer = output.split("**Final Answer:**")[-1].strip().strip(":")
157
+ step_output = final_answer
158
+ elif "Final Answer" in output:
159
+ final_answer = output.split("Final Answer")[-1].strip().strip(":")
160
+ step_output = final_answer
161
+ else:
162
+ step_output = output
163
+ self._print_step(state, step_output=step_output)
164
+ state["step_output"] = step_output
165
+ if "**Dockerfile file name**" in step_output:
166
+ dockerfile: str = step_output.split("**Dockerfile file name**")[-1]
167
+ dockerfile = dockerfile.strip().strip(":")
168
+ dockerfile = dockerfile.strip("```").strip()
169
+ state["dockerfile"] = dockerfile
170
+ else:
171
+ state["dockerfile"] = None
172
+ # state["dockerfile"] = f"demo-bioguider-{docker_id}.Dockerfile"
173
+ else:
174
+ logger.error("No output found in the response.")
175
+ self._print_step(
176
+ state,
177
+ step_output="Error: No output found in the response.",
178
+ )
179
+ state["step_output"] = "Error: No output found in the response."
180
+
181
+
182
+ token_usage = vars(callback_handler)
183
+ token_usage = {**DEFAULT_TOKEN_USAGE, **token_usage}
184
+
185
+ return state, token_usage
186
+