bioguider 0.2.18__py3-none-any.whl → 0.2.20__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 (36) hide show
  1. bioguider/agents/agent_utils.py +5 -3
  2. bioguider/agents/collection_execute_step.py +1 -1
  3. bioguider/agents/common_conversation.py +20 -2
  4. bioguider/agents/consistency_collection_execute_step.py +152 -0
  5. bioguider/agents/consistency_collection_observe_step.py +128 -0
  6. bioguider/agents/consistency_collection_plan_step.py +128 -0
  7. bioguider/agents/consistency_collection_task.py +109 -0
  8. bioguider/agents/consistency_collection_task_utils.py +137 -0
  9. bioguider/agents/evaluation_readme_task.py +29 -24
  10. bioguider/agents/evaluation_task.py +2 -2
  11. bioguider/agents/evaluation_userguide_prompts.py +162 -0
  12. bioguider/agents/evaluation_userguide_task.py +164 -0
  13. bioguider/agents/prompt_utils.py +11 -8
  14. bioguider/database/code_structure_db.py +489 -0
  15. bioguider/generation/__init__.py +39 -0
  16. bioguider/generation/change_planner.py +140 -0
  17. bioguider/generation/document_renderer.py +47 -0
  18. bioguider/generation/llm_cleaner.py +43 -0
  19. bioguider/generation/llm_content_generator.py +69 -0
  20. bioguider/generation/llm_injector.py +270 -0
  21. bioguider/generation/models.py +77 -0
  22. bioguider/generation/output_manager.py +54 -0
  23. bioguider/generation/repo_reader.py +37 -0
  24. bioguider/generation/report_loader.py +151 -0
  25. bioguider/generation/style_analyzer.py +36 -0
  26. bioguider/generation/suggestion_extractor.py +136 -0
  27. bioguider/generation/test_metrics.py +104 -0
  28. bioguider/managers/evaluation_manager.py +24 -0
  29. bioguider/managers/generation_manager.py +160 -0
  30. bioguider/managers/generation_test_manager.py +74 -0
  31. bioguider/utils/code_structure_builder.py +42 -0
  32. bioguider/utils/file_handler.py +65 -0
  33. {bioguider-0.2.18.dist-info → bioguider-0.2.20.dist-info}/METADATA +1 -1
  34. {bioguider-0.2.18.dist-info → bioguider-0.2.20.dist-info}/RECORD +36 -11
  35. {bioguider-0.2.18.dist-info → bioguider-0.2.20.dist-info}/LICENSE +0 -0
  36. {bioguider-0.2.18.dist-info → bioguider-0.2.20.dist-info}/WHEEL +0 -0
@@ -289,8 +289,9 @@ class CustomOutputParser(AgentOutputParser):
289
289
  action_input = match.group(2)
290
290
  # Return the action and action input
291
291
  action_dict = None
292
- action_input = action_input.strip(" ").strip('"')
293
- action_input_replaced = action_input.replace("'", '"')
292
+ action_input_replaced = action_input.strip().strip(" ").strip('"').strip('`').strip()
293
+ action_input_replaced = action_input_replaced.replace("'", '"')
294
+ action_input_replaced = action_input_replaced.replace("`", '"')
294
295
  try:
295
296
  action_dict = json.loads(action_input_replaced)
296
297
  except json.JSONDecodeError:
@@ -299,10 +300,11 @@ class CustomOutputParser(AgentOutputParser):
299
300
  # try using ast to parse input string
300
301
  import ast
301
302
  try:
302
- action_dict = ast.literal_eval(action_input)
303
+ action_dict = ast.literal_eval(action_input_replaced)
303
304
  if not isinstance(action_dict, dict):
304
305
  action_dict = None
305
306
  except Exception as e:
307
+ logger.error(f"Error parsing action input: {action_input} -> {action_input_replaced}\n{e}")
306
308
  pass
307
309
  return AgentAction(
308
310
  tool=action,
@@ -144,7 +144,7 @@ class CollectionExecuteStep(PEOCommonStep):
144
144
  agent_executor = AgentExecutor(
145
145
  agent=agent,
146
146
  tools=self.custom_tools,
147
- max_iterations=10,
147
+ max_iterations=30,
148
148
  )
149
149
  response = agent_executor.invoke(
150
150
  input={"plan_actions": plan_actions, "input": "Now, let's begin."},
@@ -19,8 +19,26 @@ class CommonConversation:
19
19
  callbacks=[callback_handler]
20
20
  )
21
21
  response = result.generations[0][0].text
22
- token_usage = result.llm_output.get("token_usage")
23
- return response, vars(token_usage)
22
+ # Try to normalize token usage across providers
23
+ token_usage = {}
24
+ try:
25
+ if hasattr(result, "llm_output") and result.llm_output is not None:
26
+ raw = result.llm_output.get("token_usage") or result.llm_output.get("usage")
27
+ if isinstance(raw, dict):
28
+ token_usage = {
29
+ "total_tokens": raw.get("total_tokens") or raw.get("total"),
30
+ "prompt_tokens": raw.get("prompt_tokens") or raw.get("prompt"),
31
+ "completion_tokens": raw.get("completion_tokens") or raw.get("completion"),
32
+ }
33
+ except Exception:
34
+ pass
35
+ if not token_usage:
36
+ token_usage = {
37
+ "total_tokens": getattr(callback_handler, "total_tokens", 0),
38
+ "prompt_tokens": getattr(callback_handler, "prompt_tokens", 0),
39
+ "completion_tokens": getattr(callback_handler, "completion_tokens", 0),
40
+ }
41
+ return response, token_usage
24
42
 
25
43
  def generate_with_schema(self, system_prompt: str, instruction_prompt: str, schema: any):
26
44
  system_prompt = escape_braces(system_prompt)
@@ -0,0 +1,152 @@
1
+ import logging
2
+
3
+ from langchain_openai.chat_models.base import BaseChatOpenAI
4
+ from langchain.tools import BaseTool, StructuredTool
5
+ from langchain.agents import AgentExecutor, create_react_agent
6
+ from langchain_community.callbacks.openai_info import OpenAICallbackHandler
7
+
8
+ from bioguider.agents.consistency_collection_task_utils import ConsistencyCollectionWorkflowState
9
+ from bioguider.agents.consistency_collection_task_utils import ConsistencyCollectionWorkflowState
10
+ from bioguider.database.code_structure_db import CodeStructureDb
11
+ from bioguider.utils.constants import DEFAULT_TOKEN_USAGE
12
+ from bioguider.agents.agent_utils import CustomOutputParser, CustomPromptTemplate
13
+ from bioguider.agents.peo_common_step import (
14
+ PEOCommonStep,
15
+ )
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ CONSISTENCY_EVAL_EXECUTION_SYSTEM_PROMPT = """You are an expert developer specializing in the biomedical domain.
20
+
21
+ You are given a **plan** and are expected to complete it using the available tools.
22
+
23
+ ---
24
+
25
+ ### **Available Tools**
26
+ {tools}
27
+
28
+ ---
29
+
30
+ ### **Your Task**
31
+
32
+ Your job is to **execute the given plan step by step**, using the tools available to you.
33
+
34
+ ---
35
+
36
+ ### **Output Format (Strict Order Required)**
37
+
38
+ For **each step**, follow the **exact format** below and **do not change the order of the fields** under any circumstances:
39
+
40
+ ```
41
+ Thought: Describe what you are thinking or planning to do next.
42
+ Action: The tool you are going to use (must be one of: {tool_names})
43
+ Action Input: The input provided to the selected action
44
+ Observation: The result returned by the action
45
+ ```
46
+
47
+ ---
48
+
49
+ ### **Important Instructions**
50
+ 1. You may repeat the **Thought → Action → Action Input → Observation** loop as needed.
51
+ 2. Once all steps in the plan have been executed, output all the results using this format:
52
+ 3. For each step, **only execute one tool**.
53
+
54
+ ```
55
+ Thought: I have completed the plan.
56
+ Final Answer:
57
+ Action: <tool_name>
58
+ Action Input: <input>
59
+ Action Observation: <Observation1>
60
+ ---
61
+ Action: <tool_name>
62
+ Action Input: <input>
63
+ Action Observation: <Observation2>
64
+ ---
65
+ ...
66
+ ```
67
+
68
+ ---
69
+
70
+ ### **Plan**
71
+ {plan_actions}
72
+
73
+ ### **Actions Already Taken**
74
+ {agent_scratchpad}
75
+
76
+ ---
77
+
78
+ {input}
79
+ """
80
+
81
+ class ConsistencyCollectionExecuteStep(PEOCommonStep):
82
+ def __init__(
83
+ self,
84
+ llm: BaseChatOpenAI,
85
+ code_structure_db: CodeStructureDb,
86
+ custom_tools: list[BaseTool] | None = None,
87
+ ):
88
+ self.llm = llm
89
+ self.code_structure_db = code_structure_db
90
+ self.step_name = "Consistency Collection Execute Step"
91
+ self.custom_tools = custom_tools if custom_tools is not None else []
92
+
93
+ def _execute_directly(self, state: ConsistencyCollectionWorkflowState):
94
+ plan_actions = state["plan_actions"]
95
+ prompt = CustomPromptTemplate(
96
+ template=CONSISTENCY_EVAL_EXECUTION_SYSTEM_PROMPT,
97
+ tools=self.custom_tools,
98
+ plan_actions=plan_actions,
99
+ input_variables=[
100
+ "tools", "tool_names", "agent_scratchpad",
101
+ "intermediate_steps", "plan_actions",
102
+ ],
103
+ )
104
+ output_parser = CustomOutputParser()
105
+ agent = create_react_agent(
106
+ llm=self.llm,
107
+ tools=self.custom_tools,
108
+ prompt=prompt,
109
+ output_parser=output_parser,
110
+ stop_sequence=["\nObservation:"],
111
+ )
112
+ callback_handler = OpenAICallbackHandler()
113
+ agent_executor = AgentExecutor(
114
+ agent=agent,
115
+ tools=self.custom_tools,
116
+ max_iterations=30,
117
+ )
118
+ response = agent_executor.invoke(
119
+ input={
120
+ "plan_actions": plan_actions,
121
+ "input": "Now, let's begin."
122
+ },
123
+ config={
124
+ "callbacks": [callback_handler],
125
+ "recursion_limit": 20,
126
+ },
127
+ )
128
+ if "output" in response:
129
+ output = response["output"]
130
+ self._print_step(state, step_output=f"**Execute Output:** \n{output}")
131
+ if "**Final Answer**" in output:
132
+ final_answer = output.split("**Final Answer:**")[-1].strip().strip(":")
133
+ step_output = final_answer
134
+ elif "Final Answer" in output:
135
+ final_answer = output.split("Final Answer")[-1].strip().strip(":")
136
+ step_output = final_answer
137
+ else:
138
+ step_output = output
139
+ self._print_step(state, step_output=step_output)
140
+ state["step_output"] = step_output
141
+ else:
142
+ logger.error("No output found in the response.")
143
+ self._print_step(
144
+ state,
145
+ step_output="Error: No output found in the response.",
146
+ )
147
+ state["step_output"] = "Error: No output found in the response."
148
+
149
+ token_usage = vars(callback_handler)
150
+ token_usage = {**DEFAULT_TOKEN_USAGE, **token_usage}
151
+
152
+ return state, token_usage
@@ -0,0 +1,128 @@
1
+ from typing import Callable
2
+
3
+ from langchain_openai.chat_models.base import BaseChatOpenAI
4
+ from langchain_core.prompts import ChatPromptTemplate
5
+ from bioguider.agents.agent_utils import ObservationResult
6
+ from bioguider.agents.common_agent_2step import CommonAgentTwoSteps
7
+ from bioguider.agents.consistency_collection_task_utils import ConsistencyCollectionWorkflowState
8
+ from bioguider.agents.peo_common_step import PEOCommonStep
9
+
10
+ CONSISTENCY_EVAL_OBSERVE_SYSTEM_PROMPT = """You are an expert developer specializing in the biomedical domain.
11
+
12
+ ### **Goal**
13
+ Your task is to collect the function, class, and method definitions and docstrings for a given user guide/API documentation.
14
+
15
+ ---
16
+
17
+ ### **Intermediate Steps**
18
+ Here are the results from previous steps:
19
+ {intermediate_steps}
20
+
21
+ ---
22
+
23
+ ### **Instructions**
24
+ 1. Your goal is if you have enough information to evaluate the consistency of the user guide/API documentation.
25
+ 2. Carefully review the **Goal**, **User Guide/API Documentation**, and **Intermediate Output**.
26
+ 3. If you believe you have enough information to evaluate the consistency of the user guide/API documentation:
27
+
28
+ * Proceed with the following format:
29
+
30
+ * Provide your reasoning under **Analysis**
31
+ * Then give your final answer under **FinalAnswer**
32
+ * **FinalAnswer** format must exactly match this format:
33
+ **FinalAnswer**: {{"final_answer": "yes" or "no"}}
34
+ * Your answer **must exactly match the follwing format** (note: no JSON code block, no additional comments), **do not** make up anything:
35
+
36
+ ```
37
+ **Analysis**: your analysis here
38
+ **FinalAnswer**: {{"final_answer": "yes" or "no"}}
39
+ ```
40
+ 4. If you believe you do not have enough information to evaluate the consistency of the user guide/API documentation:
41
+
42
+ * Provide your reasoning under **Thoughts**:
43
+
44
+ ```
45
+ **Thoughts**: your thoughts here
46
+ ```
47
+
48
+ Be precise and support your reasoning with evidence from the input.
49
+
50
+ ---
51
+
52
+ ### **Notes**
53
+ We are collecting information over multiple rounds, your thoughts and the output of this step will be persisted, so please **do not rush to provide a Final Answer**.
54
+ If you find the current information insufficient, share your reasoning or thoughts instead—we’ll continue with the next round accordingly.
55
+
56
+ ---
57
+
58
+ ### **Input User Guide/API Documentation**
59
+ {user_guide_api_documentation}
60
+
61
+ ---
62
+
63
+ """
64
+
65
+
66
+ class ConsistencyCollectionObserveStep(PEOCommonStep):
67
+ def __init__(
68
+ self,
69
+ llm: BaseChatOpenAI,
70
+ ):
71
+ super().__init__(llm=llm)
72
+ self.step_name = "Consistency Collection Observe Step"
73
+
74
+ def _build_prompt(self, state):
75
+ user_guide_api_documentation = state["user_guide_api_documentation"]
76
+ intermediate_steps = self._build_intermediate_steps(state)
77
+ prompt = ChatPromptTemplate.from_template(CONSISTENCY_EVAL_OBSERVE_SYSTEM_PROMPT)
78
+ return prompt.format(
79
+ user_guide_api_documentation=user_guide_api_documentation,
80
+ intermediate_steps=intermediate_steps,
81
+ )
82
+
83
+ def _collect_final_answer(self, state: ConsistencyCollectionWorkflowState):
84
+ if not ("final_answer" in state and state["final_answer"] is not None and
85
+ state["final_answer"].strip().lower() == "yes"):
86
+ return None
87
+
88
+ final_result = ""
89
+ if "intermediate_steps" in state and state["intermediate_steps"] is not None:
90
+ for i in range(len(state["intermediate_steps"])):
91
+ final_result += state["intermediate_steps"][i]
92
+ final_result += "\n\n"
93
+ if "step_output" in state and state["step_output"] is not None:
94
+ final_result += state["step_output"]
95
+ final_result += "\n\n"
96
+
97
+ return final_result
98
+
99
+
100
+ def _execute_directly(self, state: ConsistencyCollectionWorkflowState):
101
+ system_prompt = self._build_prompt(state)
102
+ agent = CommonAgentTwoSteps(llm=self.llm)
103
+ res, _, token_usage, reasoning_process = agent.go(
104
+ system_prompt=system_prompt,
105
+ instruction_prompt="Now, let's begin the consistency collection observe step.",
106
+ schema=ObservationResult,
107
+ )
108
+ state["final_answer"] = res.FinalAnswer
109
+ analysis = res.Analysis
110
+ thoughts = res.Thoughts
111
+ state["step_analysis"] = analysis
112
+ state["step_thoughts"] = thoughts
113
+ state["step_count"] += 1
114
+ state["final_assembly_result"] = self._collect_final_answer(state)
115
+ self._print_step(
116
+ state,
117
+ step_output=f"**Observation Reasoning Process {state['step_count']}**\n{reasoning_process}"
118
+ )
119
+ self._print_step(
120
+ state,
121
+ step_output=f"Final Answer: {res.FinalAnswer if res.FinalAnswer else None}\nAnalysis: {analysis}\nThoughts: {thoughts}",
122
+ )
123
+ if state["final_assembly_result"] is not None:
124
+ self._print_step(
125
+ state,
126
+ step_output=f"Final Assembly Result: {state['final_assembly_result']}",
127
+ )
128
+ return state, token_usage
@@ -0,0 +1,128 @@
1
+ from langchain_openai.chat_models.base import BaseChatOpenAI
2
+
3
+ from langchain.tools import BaseTool
4
+ from langchain_core.prompts import ChatPromptTemplate, StringPromptTemplate
5
+ from bioguider.agents.agent_utils import (
6
+ convert_plan_to_string,
7
+ get_tool_names_and_descriptions,
8
+ PlanAgentResultJsonSchema,
9
+ PlanAgentResult,
10
+ )
11
+ from bioguider.agents.common_agent_2step import CommonAgentTwoChainSteps, CommonAgentTwoSteps
12
+ from bioguider.agents.consistency_collection_task_utils import ConsistencyCollectionWorkflowState
13
+ from bioguider.agents.peo_common_step import PEOCommonStep
14
+
15
+ CONSISTANCE_EVAL_PLAN_SYSTEM_PROMPT = ChatPromptTemplate.from_template("""### **Goal**
16
+ You are an expert developer specializing in the biomedical domain.
17
+ Your task is to collect the function, class, and method definitions and docstrings for a given user guide/API documentation.
18
+
19
+ ---
20
+
21
+ ### **Function Tools**
22
+ You have access to the following function tools:
23
+ {tools}
24
+
25
+ ---
26
+
27
+ ### **Intermediate Steps**
28
+ Here are the results from previous steps:
29
+ {intermediate_steps}
30
+
31
+ ---
32
+
33
+ ### **Intermediate Thoughts**
34
+ - **Analysis**: {intermediate_analysis}
35
+ - **Thoughts**: {intermediate_thoughts}
36
+
37
+ ---
38
+
39
+ ### **Instructions**
40
+ 1. We will iterate through multiple **Plan -> Execution -> Observation** loops as needed.
41
+ - All variables and tool outputs are **persisted across rounds**, so you can build on prior results.
42
+ - Develop your plan **incrementally**, and reflect on intermediate observations before proceeding.
43
+ - Limit each step to **one or two actions** — avoid trying to complete everything in a single step.
44
+
45
+ 2. Your task is to evaluate the consistency of the user guide/API documentation.
46
+
47
+ 3. You may use
48
+ - the `retrieve_function_definition_and_docstring` tool to get the function definition and docstring or,
49
+ - the `retrieve_class_definition_and_docstring` to get the class definition and docstring or,
50
+ - the `retrieve_class_and_method_definition_and_docstring` to get the class and method definition and docstring.
51
+
52
+ 4. Your plan can only use the above tools, **do not** make up any tools not in the above tools list.
53
+
54
+ 5. If no function, class, or method is found in the given user guide/API documentation, you should return "N/A" as an empty plan.
55
+ Our tools can only retrieve the **function**, **class**, **method** definition and docstring, **do not** make up any function, class, or method name.
56
+
57
+
58
+ ### **Input User Guide/API Documentation**
59
+ {user_guide_api_documentation}
60
+
61
+ ### **Output Format**
62
+ Your plan **must exactly match** a sequence of steps in the following format, **do not** make up anything:
63
+
64
+ Step: <tool name> # Tool name **must be one** of {tool_names}
65
+ Step Input: <function/class/method name>
66
+ Step Input: <file path, if not sure, just put "N/A">
67
+
68
+ Step: <tool name> # Tool name **must be one** of {tool_names}
69
+ Step Input: <function/class/method name>
70
+ Step Input: <file path, if not sure, just put "N/A">
71
+ ...
72
+
73
+ ...
74
+ """)
75
+
76
+ class ConsistencyCollectionPlanStep(PEOCommonStep):
77
+ """
78
+ ConsistencyCollectionPlanStep is a step in the consistency collection plan process.
79
+ It is responsible for initializing the tools and compiling the step.
80
+ """
81
+
82
+ def __init__(
83
+ self,
84
+ llm: BaseChatOpenAI,
85
+ custom_tools: list[BaseTool] | None = None,
86
+ ):
87
+ super().__init__(llm)
88
+ self.step_name = "Consistency Collection Plan Step"
89
+ self.custom_tools = custom_tools if custom_tools is not None else []
90
+
91
+ def _prepare_system_prompt(self, state: ConsistencyCollectionWorkflowState) -> str:
92
+ user_guide_api_documentation = state["user_guide_api_documentation"]
93
+ intermediate_steps = self._build_intermediate_steps(state)
94
+ step_analysis, step_thoughts = self._build_intermediate_analysis_and_thoughts(state)
95
+ tool_names, tools_desc = get_tool_names_and_descriptions(self.custom_tools)
96
+ system_prompt = CONSISTANCE_EVAL_PLAN_SYSTEM_PROMPT.format(
97
+ tools=tools_desc,
98
+ intermediate_steps=intermediate_steps,
99
+ intermediate_analysis=step_analysis,
100
+ intermediate_thoughts=step_thoughts,
101
+ tool_names=tool_names,
102
+ user_guide_api_documentation=user_guide_api_documentation,
103
+ )
104
+ self._print_step(
105
+ state,
106
+ step_output="**Intermediate Step Output**\n" + intermediate_steps
107
+ )
108
+ self._print_step(
109
+ state,
110
+ step_output="**Intermediate Step Analysis**\n{step_analysis}\n**Intermediate Step Thoughts**\n{step_thoughts}",
111
+ )
112
+ return system_prompt
113
+
114
+ def _execute_directly(self, state: ConsistencyCollectionWorkflowState):
115
+ system_prompt = self._prepare_system_prompt(state)
116
+ agent = CommonAgentTwoSteps(llm=self.llm)
117
+ res, _, token_usage, reasoning_process = agent.go(
118
+ system_prompt=system_prompt,
119
+ instruction_prompt="Now, let's begin the consistency collection plan step.",
120
+ schema=PlanAgentResultJsonSchema,
121
+ )
122
+ PEOCommonStep._reset_step_state(state)
123
+ res = PlanAgentResult(**res)
124
+ self._print_step(state, step_output=f"**Reasoning Process**\n{reasoning_process}")
125
+ self._print_step(state, step_output=f"**Plan**\n{str(res.actions)}")
126
+ state["plan_actions"] = convert_plan_to_string(res)
127
+
128
+ return state, token_usage
@@ -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 langchain.tools import StructuredTool
7
+ from pydantic import BaseModel, Field
8
+ import logging
9
+ from langgraph.graph import StateGraph, START, END
10
+
11
+ from bioguider.agents.agent_task import AgentTask
12
+ from bioguider.agents.agent_tools import agent_tool
13
+ from bioguider.agents.agent_utils import read_file, summarize_file
14
+ from bioguider.agents.peo_common_step import PEOWorkflowState
15
+ from bioguider.agents.common_agent import CommonAgent
16
+ from bioguider.agents.common_agent_2step import CommonAgentTwoSteps
17
+ from bioguider.agents.consistency_collection_task_utils import (
18
+ ConsistencyCollectionWorkflowState,
19
+ retrieve_function_definition_and_docstring_tool,
20
+ retrieve_class_definition_and_docstring_tool,
21
+ retrieve_class_and_method_definition_and_docstring_tool,
22
+ retrieve_method_definition_and_docstring_tool,
23
+ )
24
+ from bioguider.agents.consistency_collection_plan_step import ConsistencyCollectionPlanStep
25
+ from bioguider.agents.consistency_collection_observe_step import ConsistencyCollectionObserveStep
26
+ from bioguider.agents.consistency_collection_execute_step import ConsistencyCollectionExecuteStep
27
+ from bioguider.database.code_structure_db import CodeStructureDb
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+ class ConsistencyCollectionTask(AgentTask):
32
+ def __init__(
33
+ self,
34
+ llm: BaseChatOpenAI,
35
+ code_structure_db: CodeStructureDb,
36
+ step_callback: Callable | None = None,
37
+ ):
38
+ super().__init__(llm=llm, step_callback=step_callback)
39
+ self.llm = llm
40
+ self.code_structure_db = code_structure_db
41
+
42
+ func_tool = retrieve_function_definition_and_docstring_tool(llm=llm, code_structure_db=code_structure_db)
43
+ class_tool = retrieve_class_definition_and_docstring_tool(llm=llm, code_structure_db=code_structure_db)
44
+ class_and_method_tool = retrieve_class_and_method_definition_and_docstring_tool(llm=llm, code_structure_db=code_structure_db)
45
+ method_tool = retrieve_method_definition_and_docstring_tool(llm=llm, code_structure_db=code_structure_db)
46
+ self.tools = [func_tool, class_tool, class_and_method_tool, method_tool]
47
+ self.custom_tools = [
48
+ StructuredTool.from_function(
49
+ func_tool.run,
50
+ description=func_tool.__class__.__doc__,
51
+ name=func_tool.__class__.__name__,
52
+ ),
53
+ StructuredTool.from_function(
54
+ class_tool.run,
55
+ description=class_tool.__class__.__doc__,
56
+ name=class_tool.__class__.__name__,
57
+ ),
58
+ StructuredTool.from_function(
59
+ class_and_method_tool.run,
60
+ description=class_and_method_tool.__class__.__doc__,
61
+ name=class_and_method_tool.__class__.__name__,
62
+ ),
63
+ StructuredTool.from_function(
64
+ method_tool.run,
65
+ description=method_tool.__class__.__doc__,
66
+ name=method_tool.__class__.__name__,
67
+ ),
68
+ ]
69
+
70
+ self.steps = [
71
+ ConsistencyCollectionPlanStep(llm=llm, custom_tools=self.custom_tools),
72
+ ConsistencyCollectionExecuteStep(llm=llm, code_structure_db=code_structure_db, custom_tools=self.custom_tools),
73
+ ConsistencyCollectionObserveStep(llm=llm)
74
+ ]
75
+
76
+ def _compile(self, repo_path: str, gitignore_path: str):
77
+ def check_observe_step(state: ConsistencyCollectionWorkflowState):
78
+ if "final_answer" in state and state["final_answer"] is not None:
79
+ return END
80
+ return "plan_step"
81
+ def check_plan_step(state: ConsistencyCollectionWorkflowState):
82
+ if "plan_actions" in state and state["plan_actions"] is not None and len(state["plan_actions"]) > 0:
83
+ return "execute_step"
84
+ return END
85
+
86
+ graph = StateGraph(ConsistencyCollectionWorkflowState)
87
+ graph.add_node("plan_step", self.steps[0].execute)
88
+ graph.add_node("execute_step", self.steps[1].execute)
89
+ graph.add_node("observe_step", self.steps[2].execute)
90
+ graph.add_edge(START, "plan_step")
91
+ graph.add_conditional_edges("plan_step", check_plan_step, {"execute_step", END})
92
+ graph.add_edge("execute_step", "observe_step")
93
+ graph.add_conditional_edges("observe_step", check_observe_step, {"plan_step", END})
94
+
95
+ self.graph = graph.compile()
96
+
97
+ def collect(self, user_guide_api_documentation: str) -> tuple[bool, str | None]:
98
+ s = self._go_graph({
99
+ "user_guide_api_documentation": user_guide_api_documentation,
100
+ "step_count": 0,
101
+ })
102
+ # analyze the final assembly result
103
+ if "final_assembly_result" in s and s["final_assembly_result"] is not None:
104
+ self._print_step(step_name="Final Assembly Result")
105
+ self._print_step(step_output=s["final_assembly_result"])
106
+ return True, s["final_assembly_result"]
107
+ else:
108
+ return False, s["thoughts"] if "thoughts" in s else None
109
+