bioguider 0.2.52__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.
Files changed (84) hide show
  1. bioguider/__init__.py +0 -0
  2. bioguider/agents/__init__.py +0 -0
  3. bioguider/agents/agent_task.py +92 -0
  4. bioguider/agents/agent_tools.py +176 -0
  5. bioguider/agents/agent_utils.py +504 -0
  6. bioguider/agents/collection_execute_step.py +182 -0
  7. bioguider/agents/collection_observe_step.py +125 -0
  8. bioguider/agents/collection_plan_step.py +156 -0
  9. bioguider/agents/collection_task.py +184 -0
  10. bioguider/agents/collection_task_utils.py +142 -0
  11. bioguider/agents/common_agent.py +137 -0
  12. bioguider/agents/common_agent_2step.py +215 -0
  13. bioguider/agents/common_conversation.py +61 -0
  14. bioguider/agents/common_step.py +85 -0
  15. bioguider/agents/consistency_collection_step.py +102 -0
  16. bioguider/agents/consistency_evaluation_task.py +57 -0
  17. bioguider/agents/consistency_evaluation_task_utils.py +14 -0
  18. bioguider/agents/consistency_observe_step.py +110 -0
  19. bioguider/agents/consistency_query_step.py +77 -0
  20. bioguider/agents/dockergeneration_execute_step.py +186 -0
  21. bioguider/agents/dockergeneration_observe_step.py +154 -0
  22. bioguider/agents/dockergeneration_plan_step.py +158 -0
  23. bioguider/agents/dockergeneration_task.py +158 -0
  24. bioguider/agents/dockergeneration_task_utils.py +220 -0
  25. bioguider/agents/evaluation_installation_task.py +270 -0
  26. bioguider/agents/evaluation_readme_task.py +767 -0
  27. bioguider/agents/evaluation_submission_requirements_task.py +172 -0
  28. bioguider/agents/evaluation_task.py +206 -0
  29. bioguider/agents/evaluation_tutorial_task.py +169 -0
  30. bioguider/agents/evaluation_tutorial_task_prompts.py +187 -0
  31. bioguider/agents/evaluation_userguide_prompts.py +179 -0
  32. bioguider/agents/evaluation_userguide_task.py +154 -0
  33. bioguider/agents/evaluation_utils.py +127 -0
  34. bioguider/agents/identification_execute_step.py +181 -0
  35. bioguider/agents/identification_observe_step.py +104 -0
  36. bioguider/agents/identification_plan_step.py +140 -0
  37. bioguider/agents/identification_task.py +270 -0
  38. bioguider/agents/identification_task_utils.py +22 -0
  39. bioguider/agents/peo_common_step.py +64 -0
  40. bioguider/agents/prompt_utils.py +253 -0
  41. bioguider/agents/python_ast_repl_tool.py +69 -0
  42. bioguider/agents/rag_collection_task.py +130 -0
  43. bioguider/conversation.py +67 -0
  44. bioguider/database/code_structure_db.py +500 -0
  45. bioguider/database/summarized_file_db.py +146 -0
  46. bioguider/generation/__init__.py +39 -0
  47. bioguider/generation/benchmark_metrics.py +610 -0
  48. bioguider/generation/change_planner.py +189 -0
  49. bioguider/generation/document_renderer.py +157 -0
  50. bioguider/generation/llm_cleaner.py +67 -0
  51. bioguider/generation/llm_content_generator.py +1128 -0
  52. bioguider/generation/llm_injector.py +809 -0
  53. bioguider/generation/models.py +85 -0
  54. bioguider/generation/output_manager.py +74 -0
  55. bioguider/generation/repo_reader.py +37 -0
  56. bioguider/generation/report_loader.py +166 -0
  57. bioguider/generation/style_analyzer.py +36 -0
  58. bioguider/generation/suggestion_extractor.py +436 -0
  59. bioguider/generation/test_metrics.py +189 -0
  60. bioguider/managers/benchmark_manager.py +785 -0
  61. bioguider/managers/evaluation_manager.py +215 -0
  62. bioguider/managers/generation_manager.py +686 -0
  63. bioguider/managers/generation_test_manager.py +107 -0
  64. bioguider/managers/generation_test_manager_v2.py +525 -0
  65. bioguider/rag/__init__.py +0 -0
  66. bioguider/rag/config.py +117 -0
  67. bioguider/rag/data_pipeline.py +651 -0
  68. bioguider/rag/embedder.py +24 -0
  69. bioguider/rag/rag.py +138 -0
  70. bioguider/settings.py +103 -0
  71. bioguider/utils/code_structure_builder.py +59 -0
  72. bioguider/utils/constants.py +135 -0
  73. bioguider/utils/default.gitignore +140 -0
  74. bioguider/utils/file_utils.py +215 -0
  75. bioguider/utils/gitignore_checker.py +175 -0
  76. bioguider/utils/notebook_utils.py +117 -0
  77. bioguider/utils/pyphen_utils.py +73 -0
  78. bioguider/utils/python_file_handler.py +65 -0
  79. bioguider/utils/r_file_handler.py +551 -0
  80. bioguider/utils/utils.py +163 -0
  81. bioguider-0.2.52.dist-info/LICENSE +21 -0
  82. bioguider-0.2.52.dist-info/METADATA +51 -0
  83. bioguider-0.2.52.dist-info/RECORD +84 -0
  84. bioguider-0.2.52.dist-info/WHEEL +4 -0
@@ -0,0 +1,137 @@
1
+
2
+ from typing import Any, Callable, Optional
3
+ from langchain_core.prompts import ChatPromptTemplate
4
+ from langchain_openai.chat_models.base import BaseChatOpenAI
5
+ from langchain_community.callbacks.openai_info import OpenAICallbackHandler
6
+ from langchain_core.messages import SystemMessage, HumanMessage
7
+ from pydantic import BaseModel, Field
8
+ from tenacity import retry, stop_after_attempt, wait_incrementing
9
+ import logging
10
+
11
+ from bioguider.utils.utils import escape_braces, increase_token_usage
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class RetryException(Exception):
16
+ """Exception need to retry"""
17
+
18
+ pass
19
+
20
+ class CommonAgentResult(BaseModel):
21
+ reasoning_process: str = Field(
22
+ description="A detailed explanation of the thought process or reasoning steps taken to reach a conclusion."
23
+ )
24
+
25
+ class CommonAgent:
26
+ def __init__(self, llm: BaseChatOpenAI):
27
+ self.llm = llm
28
+ self.exception: RetryException | None = None
29
+ self.token_usage: dict | None = None
30
+
31
+ def go(
32
+ self,
33
+ system_prompt: str,
34
+ instruction_prompt: str,
35
+ schema: any,
36
+ pre_process: Optional[Callable] = None,
37
+ post_process: Optional[Callable] = None,
38
+ **kwargs: Optional[Any],
39
+ ):
40
+ """
41
+ execute agent
42
+
43
+ Args:
44
+ system_prompt str: system prompt
45
+ instruction_prompt str: user prompt to guide how llm execute agent
46
+ schema pydantic.BaseModel or json schema: llm output result schema
47
+ pre_process Callable or None: pre-processor that would be executed before llm.invoke
48
+ post_process Callable or None: post-processor that would be executed after llm.invoke
49
+ kwargs None or dict: args for pre_proces and post_process
50
+
51
+ Return:
52
+ (output that comply with input args `schema`)
53
+ """
54
+ self._initialize()
55
+ if pre_process is not None:
56
+ is_OK = pre_process(**kwargs)
57
+ if not is_OK: # skip
58
+ return
59
+
60
+ return self._invoke_agent(
61
+ system_prompt,
62
+ instruction_prompt,
63
+ schema,
64
+ post_process,
65
+ **kwargs,
66
+ )
67
+
68
+ def _initialize(self):
69
+ self.exception = None
70
+ self.token_usage = None
71
+
72
+ def _process_retryexception_message(
73
+ self, prompt: ChatPromptTemplate
74
+ ) -> ChatPromptTemplate:
75
+ if self.exception is None:
76
+ return prompt
77
+
78
+ existing_messages = prompt.messages
79
+ updated_messages = existing_messages + [("human", str(self.exception))]
80
+ self.exception = None
81
+ updated_prompt = ChatPromptTemplate.from_messages(updated_messages)
82
+ return updated_prompt
83
+
84
+ def _incre_token_usage(self, token_usage):
85
+ incremental_token_usage = token_usage
86
+ if not isinstance(token_usage, dict):
87
+ incremental_token_usage = vars(incremental_token_usage)
88
+ self.token_usage = increase_token_usage(
89
+ self.token_usage, incremental_token_usage
90
+ )
91
+
92
+ @retry(
93
+ stop=stop_after_attempt(5),
94
+ wait=wait_incrementing(start=1.0, increment=3, max=10),
95
+ )
96
+ def _invoke_agent(
97
+ self,
98
+ system_prompt: str,
99
+ instruction_prompt: str,
100
+ schema: any,
101
+ post_process: Optional[Callable] = None,
102
+ **kwargs: Optional[Any],
103
+ ) -> tuple[Any, Any, dict | None, Any | None]:
104
+ system_prompt = escape_braces(system_prompt)
105
+ prompt = ChatPromptTemplate.from_messages([
106
+ ("system", system_prompt),
107
+ ("human", instruction_prompt),
108
+ ])
109
+ # Initialize the callback handler
110
+ callback_handler = OpenAICallbackHandler()
111
+
112
+ updated_prompt = self._process_retryexception_message(prompt)
113
+ agent = updated_prompt | self.llm.with_structured_output(schema)
114
+ try:
115
+ res = agent.invoke(
116
+ input={},
117
+ config={
118
+ "callbacks": [callback_handler],
119
+ },
120
+ )
121
+ self._incre_token_usage(callback_handler)
122
+ except Exception as e:
123
+ logger.error(str(e))
124
+ raise e
125
+ processed_res = res
126
+ if post_process is not None:
127
+ try:
128
+ processed_res = post_process(res, **kwargs)
129
+ except RetryException as e:
130
+ logger.error(str(e))
131
+ self.exception = e
132
+ raise e
133
+ except Exception as e:
134
+ logger.error(str(e))
135
+ raise e
136
+ return res, processed_res, self.token_usage, None
137
+
@@ -0,0 +1,215 @@
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.utils.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
127
+
128
+ FINAL_STEP_SYSTEM_PROMPTS = ChatPromptTemplate.from_template("""
129
+ ---
130
+
131
+ You will be given a response generated by a LLM, which includes a **step-by-step reasoning process** followed by a clearly marked **final answer**.
132
+
133
+ ### **Your Task:**
134
+
135
+ Extract and return only the content of the **final answer**.
136
+
137
+ ---
138
+
139
+ ### **Important Instructions:**
140
+ 1. Your task is to **extract only the final answer** from the provided reasoning process.
141
+ **Do not** make any judgments, interpretations, or modifications to the content.
142
+
143
+ ### **Input:**
144
+
145
+ {llm_response}
146
+
147
+ ---
148
+ """)
149
+
150
+ class CommonAgentTwoChainSteps(CommonAgentTwoSteps):
151
+ def __init__(self, llm):
152
+ super().__init__(llm)
153
+
154
+ def _invoke_agent(self, system_prompt, instruction_prompt, schema, post_process = None, **kwargs):
155
+ # Initialize the callback handler
156
+ callback_handler = OpenAICallbackHandler()
157
+ processed_system_prompt = system_prompt.replace("{", "{{").replace("}", "}}")
158
+ cot_prompt = self._build_prompt_for_cot_step(
159
+ system_prompt=processed_system_prompt,
160
+ instruction_prompt=instruction_prompt
161
+ )
162
+
163
+ try:
164
+ # First, use llm to do CoT
165
+ msgs = cot_prompt.invoke(input={}).to_messages()
166
+
167
+ cot_res = self.llm.generate(messages=[msgs])
168
+ if cot_res is None or cot_res.llm_output is None:
169
+ raise Exception("llm generate invalid output")
170
+ reasoning_process = cot_res.generations[0][0].text
171
+ token_usage: Any = cot_res.llm_output.get("token_usage")
172
+ cot_tokens = {
173
+ "total_tokens": token_usage.get("total_tokens", 0),
174
+ "prompt_tokens": token_usage.get("prompt_tokens", 0),
175
+ "completion_tokens": token_usage.get("completion_tokens", 0),
176
+ }
177
+ self._incre_token_usage(cot_tokens)
178
+ except Exception as e:
179
+ logger.error(str(e))
180
+ raise e
181
+
182
+ try:
183
+ # Then use the reasoning process to do the structured output
184
+ processed_reasoning_process = reasoning_process.replace("{", "{{").replace("}", "}}")
185
+ final_msg = FINAL_STEP_SYSTEM_PROMPTS.format(
186
+ llm_response=processed_reasoning_process,
187
+ )
188
+ msgs = [(
189
+ "human",
190
+ final_msg,
191
+ )]
192
+ final_prompt = ChatPromptTemplate.from_messages(msgs)
193
+ agent = final_prompt | self.llm.with_structured_output(schema)
194
+ res = agent.invoke(
195
+ input={},
196
+ config={
197
+ "callbacks": [callback_handler],
198
+ },
199
+ )
200
+ self._incre_token_usage(callback_handler)
201
+ except Exception as e:
202
+ logger.error(str(e))
203
+ raise e
204
+ processed_res = None
205
+ if post_process is not None:
206
+ try:
207
+ processed_res = post_process(res, **kwargs)
208
+ except RetryException as e:
209
+ logger.error(str(e))
210
+ self.exceptions = [e] if self.exceptions is None else self.exceptions + [e]
211
+ raise e
212
+ except Exception as e:
213
+ logger.error(str(e))
214
+ raise e
215
+ return res, processed_res, self.token_usage, reasoning_process
@@ -0,0 +1,61 @@
1
+ from langchain_core.messages import SystemMessage, HumanMessage
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 bioguider.utils.utils import escape_braces
6
+
7
+ class CommonConversation:
8
+ def __init__(self, llm: BaseChatOpenAI):
9
+ self.llm = llm
10
+
11
+ def generate(self, system_prompt: str, instruction_prompt: str):
12
+ msgs = [
13
+ SystemMessage(system_prompt),
14
+ HumanMessage(instruction_prompt),
15
+ ]
16
+ callback_handler = OpenAICallbackHandler()
17
+ result = self.llm.generate(
18
+ messages=[msgs],
19
+ callbacks=[callback_handler]
20
+ )
21
+ response = result.generations[0][0].text
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
42
+
43
+ def generate_with_schema(self, system_prompt: str, instruction_prompt: str, schema: any):
44
+ system_prompt = escape_braces(system_prompt)
45
+ instruction_prompt = escape_braces(instruction_prompt)
46
+ msgs = [
47
+ SystemMessage(system_prompt),
48
+ HumanMessage(instruction_prompt),
49
+ ]
50
+ msgs_template = ChatPromptTemplate.from_messages(messages=msgs)
51
+ callback_handler = OpenAICallbackHandler()
52
+ agent = msgs_template | self.llm.with_structured_output(schema)
53
+ result = agent.invoke(
54
+ input={},
55
+ config={
56
+ "callbacks": [callback_handler],
57
+ },
58
+ )
59
+ token_usage = vars(callback_handler)
60
+ return result, token_usage
61
+
@@ -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,102 @@
1
+
2
+
3
+
4
+ from langchain.prompts import ChatPromptTemplate
5
+ from langchain_openai.chat_models.base import BaseChatOpenAI
6
+ from pydantic import BaseModel, Field
7
+ from bioguider.agents.common_agent_2step import CommonAgentTwoSteps
8
+ from bioguider.agents.consistency_evaluation_task_utils import ConsistencyEvaluationState
9
+ from bioguider.agents.peo_common_step import PEOCommonStep
10
+
11
+
12
+ CONSISTANCY_COLLECTION_SYSTEM_PROMPT = """
13
+ ### **Goal**
14
+ You are an expert developer specializing in the biomedical domain.
15
+ You will be given a {domain} documentation. Your task is to collect all the functions, classes, and methods that the {domain} documentation mentions.
16
+
17
+ ---
18
+
19
+ ### **Input {domain} Documentation**
20
+ {documentation}
21
+
22
+ ### **Output Format**
23
+ The collected functions, classes, and methods **must exactly match** the following format, **do not** make up anything:
24
+
25
+ ```
26
+ name: <function/class/method name>
27
+ file_path: <file path, if not sure, just put "N/A">
28
+ parameters: <parameters, if not sure, just put "N/A">
29
+ parent: <parent name, if it is a class method, put the class name as the parent name, if not sure, just put "N/A">
30
+
31
+ ...
32
+
33
+ ```
34
+
35
+ ---
36
+
37
+ ### **Output Example**
38
+ ```
39
+ name: __init__
40
+ file_path: src/agents/common_agent.py
41
+ parameters: llm, step_output_callback, summarized_files_db
42
+ parent: CommonAgent
43
+
44
+ name: _invoke_agent
45
+ file_path: src/agents/common_agent.py
46
+ parameters: system_prompt, instruction_prompt, schema, post_process
47
+ parent: CommonAgent
48
+
49
+ ...
50
+ ```
51
+
52
+ """
53
+
54
+ class ConsistencyCollectionResult(BaseModel):
55
+ functions_and_classes: list[dict] = Field(description="A list of functions and classes that the documentation mentions")
56
+
57
+ ConsistencyCollectionResultJsonSchema = {
58
+ "properties": {
59
+ "functions_and_classes": {
60
+ "description": "A list of functions and classes that the documentation mentions",
61
+ "items": {
62
+ "type": "object"
63
+ },
64
+ "title": "Functions And Classes",
65
+ "type": "array"
66
+ }
67
+ },
68
+ "required": [
69
+ "functions_and_classes"
70
+ ],
71
+ "title": "ConsistencyCollectionResult",
72
+ "type": "object"
73
+ }
74
+
75
+ class ConsistencyCollectionStep(PEOCommonStep):
76
+ def __init__(self, llm: BaseChatOpenAI):
77
+ super().__init__(llm)
78
+ self.step_name = "Consistency Collection Step"
79
+
80
+ def _prepare_system_prompt(self, state: ConsistencyEvaluationState) -> str:
81
+ documentation = state["documentation"]
82
+ domain = state["domain"]
83
+ return ChatPromptTemplate.from_template(CONSISTANCY_COLLECTION_SYSTEM_PROMPT).format(
84
+ domain=domain,
85
+ documentation=documentation,
86
+ )
87
+
88
+ def _execute_directly(self, state: ConsistencyEvaluationState) -> tuple[dict, dict[str, int]]:
89
+ system_prompt = self._prepare_system_prompt(state)
90
+ agent = CommonAgentTwoSteps(llm=self.llm)
91
+ res, _, token_usage, reasoning_process = agent.go(
92
+ system_prompt=system_prompt,
93
+ instruction_prompt="Now, let's begin the consistency collection step.",
94
+ schema=ConsistencyCollectionResultJsonSchema,
95
+ )
96
+ res: ConsistencyCollectionResult = ConsistencyCollectionResult.model_validate(res)
97
+ state["functions_and_classes"] = res.functions_and_classes
98
+ self._print_step(state, step_output=f"Consistency Collection Result: {res.functions_and_classes}")
99
+ self._print_step(state, step_output=f"Consistency Collection Reasoning Process: {reasoning_process}")
100
+
101
+ return state, token_usage
102
+
@@ -0,0 +1,57 @@
1
+
2
+
3
+
4
+ from typing import Callable
5
+ from langchain_openai.chat_models.base import BaseChatOpenAI
6
+ from pydantic import BaseModel
7
+
8
+ from bioguider.agents.consistency_evaluation_task_utils import ConsistencyEvaluationState
9
+ from bioguider.database.code_structure_db import CodeStructureDb
10
+ from .consistency_collection_step import ConsistencyCollectionStep
11
+ from .consistency_query_step import ConsistencyQueryStep
12
+ from .consistency_observe_step import ConsistencyObserveStep
13
+
14
+ class ConsistencyEvaluationResult(BaseModel):
15
+ score: int
16
+ assessment: str
17
+ development: list[str]
18
+ strengths: list[str]
19
+
20
+ class ConsistencyEvaluationTask:
21
+ def __init__(
22
+ self,
23
+ llm: BaseChatOpenAI,
24
+ code_structure_db: CodeStructureDb,
25
+ step_callback: Callable | None = None
26
+ ):
27
+ self.llm = llm
28
+ self.code_structure_db = code_structure_db
29
+ self.step_callback = step_callback
30
+
31
+ def evaluate(self, domain: str, documentation: str) -> ConsistencyEvaluationResult:
32
+ collection_step = ConsistencyCollectionStep(llm=self.llm)
33
+ query_step = ConsistencyQueryStep(code_structure_db=self.code_structure_db)
34
+ observe_step = ConsistencyObserveStep(llm=self.llm)
35
+
36
+ state = ConsistencyEvaluationState(
37
+ domain=domain,
38
+ documentation=documentation,
39
+ step_output_callback=self.step_callback,
40
+ )
41
+
42
+ state = collection_step.execute(state)
43
+ state = query_step.execute(state)
44
+ state = observe_step.execute(state)
45
+
46
+ score = state["consistency_score"]
47
+ assessment = state["consistency_assessment"]
48
+ development = state["consistency_development"]
49
+ strengths = state["consistency_strengths"]
50
+
51
+ return ConsistencyEvaluationResult(
52
+ score=score,
53
+ assessment=assessment,
54
+ development=development,
55
+ strengths=strengths,
56
+ )
57
+
@@ -0,0 +1,14 @@
1
+
2
+ from typing import Callable, Optional, TypedDict
3
+
4
+
5
+ class ConsistencyEvaluationState(TypedDict):
6
+ domain: str
7
+ documentation: str
8
+ step_output_callback: Optional[Callable]
9
+ functions_and_classes: Optional[list[dict]]
10
+ all_query_rows: Optional[list[any]]
11
+ consistency_score: Optional[int]
12
+ consistency_assessment: Optional[str]
13
+ consistency_development: Optional[list[str]]
14
+ consistency_strengths: Optional[list[str]]