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.
- bioguider/__init__.py +0 -0
- bioguider/agents/__init__.py +0 -0
- bioguider/agents/agent_task.py +92 -0
- bioguider/agents/agent_tools.py +176 -0
- bioguider/agents/agent_utils.py +504 -0
- bioguider/agents/collection_execute_step.py +182 -0
- bioguider/agents/collection_observe_step.py +125 -0
- bioguider/agents/collection_plan_step.py +156 -0
- bioguider/agents/collection_task.py +184 -0
- bioguider/agents/collection_task_utils.py +142 -0
- bioguider/agents/common_agent.py +137 -0
- bioguider/agents/common_agent_2step.py +215 -0
- bioguider/agents/common_conversation.py +61 -0
- bioguider/agents/common_step.py +85 -0
- bioguider/agents/consistency_collection_step.py +102 -0
- bioguider/agents/consistency_evaluation_task.py +57 -0
- bioguider/agents/consistency_evaluation_task_utils.py +14 -0
- bioguider/agents/consistency_observe_step.py +110 -0
- bioguider/agents/consistency_query_step.py +77 -0
- bioguider/agents/dockergeneration_execute_step.py +186 -0
- bioguider/agents/dockergeneration_observe_step.py +154 -0
- bioguider/agents/dockergeneration_plan_step.py +158 -0
- bioguider/agents/dockergeneration_task.py +158 -0
- bioguider/agents/dockergeneration_task_utils.py +220 -0
- bioguider/agents/evaluation_installation_task.py +270 -0
- bioguider/agents/evaluation_readme_task.py +767 -0
- bioguider/agents/evaluation_submission_requirements_task.py +172 -0
- bioguider/agents/evaluation_task.py +206 -0
- bioguider/agents/evaluation_tutorial_task.py +169 -0
- bioguider/agents/evaluation_tutorial_task_prompts.py +187 -0
- bioguider/agents/evaluation_userguide_prompts.py +179 -0
- bioguider/agents/evaluation_userguide_task.py +154 -0
- bioguider/agents/evaluation_utils.py +127 -0
- bioguider/agents/identification_execute_step.py +181 -0
- bioguider/agents/identification_observe_step.py +104 -0
- bioguider/agents/identification_plan_step.py +140 -0
- bioguider/agents/identification_task.py +270 -0
- bioguider/agents/identification_task_utils.py +22 -0
- bioguider/agents/peo_common_step.py +64 -0
- bioguider/agents/prompt_utils.py +253 -0
- bioguider/agents/python_ast_repl_tool.py +69 -0
- bioguider/agents/rag_collection_task.py +130 -0
- bioguider/conversation.py +67 -0
- bioguider/database/code_structure_db.py +500 -0
- bioguider/database/summarized_file_db.py +146 -0
- bioguider/generation/__init__.py +39 -0
- bioguider/generation/benchmark_metrics.py +610 -0
- bioguider/generation/change_planner.py +189 -0
- bioguider/generation/document_renderer.py +157 -0
- bioguider/generation/llm_cleaner.py +67 -0
- bioguider/generation/llm_content_generator.py +1128 -0
- bioguider/generation/llm_injector.py +809 -0
- bioguider/generation/models.py +85 -0
- bioguider/generation/output_manager.py +74 -0
- bioguider/generation/repo_reader.py +37 -0
- bioguider/generation/report_loader.py +166 -0
- bioguider/generation/style_analyzer.py +36 -0
- bioguider/generation/suggestion_extractor.py +436 -0
- bioguider/generation/test_metrics.py +189 -0
- bioguider/managers/benchmark_manager.py +785 -0
- bioguider/managers/evaluation_manager.py +215 -0
- bioguider/managers/generation_manager.py +686 -0
- bioguider/managers/generation_test_manager.py +107 -0
- bioguider/managers/generation_test_manager_v2.py +525 -0
- bioguider/rag/__init__.py +0 -0
- bioguider/rag/config.py +117 -0
- bioguider/rag/data_pipeline.py +651 -0
- bioguider/rag/embedder.py +24 -0
- bioguider/rag/rag.py +138 -0
- bioguider/settings.py +103 -0
- bioguider/utils/code_structure_builder.py +59 -0
- bioguider/utils/constants.py +135 -0
- bioguider/utils/default.gitignore +140 -0
- bioguider/utils/file_utils.py +215 -0
- bioguider/utils/gitignore_checker.py +175 -0
- bioguider/utils/notebook_utils.py +117 -0
- bioguider/utils/pyphen_utils.py +73 -0
- bioguider/utils/python_file_handler.py +65 -0
- bioguider/utils/r_file_handler.py +551 -0
- bioguider/utils/utils.py +163 -0
- bioguider-0.2.52.dist-info/LICENSE +21 -0
- bioguider-0.2.52.dist-info/METADATA +51 -0
- bioguider-0.2.52.dist-info/RECORD +84 -0
- bioguider-0.2.52.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from typing import Callable, TypedDict, Optional
|
|
4
|
+
from langchain_openai.chat_models.base import BaseChatOpenAI
|
|
5
|
+
|
|
6
|
+
class IdentificationWorkflowState(TypedDict):
|
|
7
|
+
llm: BaseChatOpenAI
|
|
8
|
+
step_output_callback: Optional[Callable]
|
|
9
|
+
goal: str
|
|
10
|
+
|
|
11
|
+
plan_actions: Optional[str]
|
|
12
|
+
plan_reasoning: Optional[str]
|
|
13
|
+
plan_instructions: Optional[str]
|
|
14
|
+
observe_instructions: Optional[str]
|
|
15
|
+
intermediate_steps: Optional[list[str]]
|
|
16
|
+
final_answer: Optional[str]
|
|
17
|
+
final_answer_example: Optional[str]
|
|
18
|
+
step_output: Optional[str]
|
|
19
|
+
step_analysis: Optional[str]
|
|
20
|
+
step_thoughts: Optional[str]
|
|
21
|
+
|
|
22
|
+
step_count: Optional[int]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from langchain_openai.chat_models.base import BaseChatOpenAI
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
from bioguider.agents.common_step import CommonState, CommonStep
|
|
7
|
+
|
|
8
|
+
class PEOWorkflowState(CommonState):
|
|
9
|
+
intermediate_steps: Optional[str]
|
|
10
|
+
step_output: Optional[str]
|
|
11
|
+
step_analysis: Optional[str]
|
|
12
|
+
step_thoughts: Optional[str]
|
|
13
|
+
plan_actions: Optional[list[dict]]
|
|
14
|
+
|
|
15
|
+
class PEOCommonStep(CommonStep):
|
|
16
|
+
"""
|
|
17
|
+
This class is a placeholder for common step functionality in the PEO agent.
|
|
18
|
+
It is currently empty and can be extended in the future.
|
|
19
|
+
"""
|
|
20
|
+
def __init__(self, llm: BaseChatOpenAI):
|
|
21
|
+
super().__init__()
|
|
22
|
+
self.llm = llm
|
|
23
|
+
|
|
24
|
+
def _build_intermediate_steps(self, state: PEOWorkflowState):
|
|
25
|
+
"""
|
|
26
|
+
Build intermediate steps for the PEO workflow.
|
|
27
|
+
"""
|
|
28
|
+
intermediate_steps = ""
|
|
29
|
+
# previous steps
|
|
30
|
+
if "intermediate_steps" in state:
|
|
31
|
+
for i in range(len(state['intermediate_steps'])):
|
|
32
|
+
step = state['intermediate_steps'][i].replace("{", "(").replace("}", ")")
|
|
33
|
+
intermediate_steps += step + "\n"
|
|
34
|
+
# current step
|
|
35
|
+
if "step_output" in state and state["step_output"] is not None:
|
|
36
|
+
step_content = state["step_output"]
|
|
37
|
+
step_content = step_content.replace("{", "(").replace("}", ")")
|
|
38
|
+
intermediate_steps += step_content
|
|
39
|
+
return intermediate_steps
|
|
40
|
+
|
|
41
|
+
def _build_intermediate_analysis_and_thoughts(self, state: PEOWorkflowState):
|
|
42
|
+
intermediate_analysis = "N/A" if "step_analysis" not in state or \
|
|
43
|
+
state["step_analysis"] is None \
|
|
44
|
+
else state["step_analysis"]
|
|
45
|
+
intermediate_analysis = intermediate_analysis.replace("{", "(").replace("}", ")")
|
|
46
|
+
intermediate_thoughts = "N/A" if "step_thoughts" not in state or \
|
|
47
|
+
state["step_thoughts"] is None \
|
|
48
|
+
else state["step_thoughts"]
|
|
49
|
+
intermediate_thoughts = intermediate_thoughts.replace("{", "(").replace("}", ")")
|
|
50
|
+
return intermediate_analysis, intermediate_thoughts
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def _reset_step_state(state):
|
|
54
|
+
# move step_output to intermediate steps
|
|
55
|
+
if "intermediate_steps" not in state or state["intermediate_steps"] is None:
|
|
56
|
+
state["intermediate_steps"] = []
|
|
57
|
+
intermediate_steps = state["intermediate_steps"]
|
|
58
|
+
if "step_output" in state and state["step_output"] is not None:
|
|
59
|
+
intermediate_steps.append(state["step_output"])
|
|
60
|
+
state["intermediate_steps"] = intermediate_steps
|
|
61
|
+
|
|
62
|
+
state["step_analysis"] = None
|
|
63
|
+
state["step_thoughts"] = None
|
|
64
|
+
state["step_output"] = None
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
3
|
+
|
|
4
|
+
USER_INSTRUCTION = """Do not give the final result immediately. First, explain your reasoning process step by step, then provide the answer."""
|
|
5
|
+
|
|
6
|
+
EVALUATION_ITEMS = [
|
|
7
|
+
("1. Clarity & Readability", 20),
|
|
8
|
+
("2. Completeness", 20),
|
|
9
|
+
("3. Organization & Navigation", 10),
|
|
10
|
+
("4. Examples & Tutorials", 10),
|
|
11
|
+
("5. Maintainability & Updates", 15),
|
|
12
|
+
("6. Accessibility & Formatting", 15),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
EVALUATION_SYSTEM_PROMPT = ChatPromptTemplate.from_template("""Please act as both a **biomedical researcher** and an **experienced software developer** to evaluate the documentation quality of a GitHub repository using the evaluation criteria below.
|
|
16
|
+
|
|
17
|
+
### **Evaluation Criteria (Total: 100 points)**
|
|
18
|
+
|
|
19
|
+
1. **Clarity & Readability (20 points)** - Is the documentation written in a clear, concise, and easy-to-understand manner?
|
|
20
|
+
2. **Completeness (20 points)** - Does the documentation cover all essential information needed for understanding, usage, and further development?
|
|
21
|
+
3. **Organization & Navigation (10 points)** - Is the structure logical and easy to navigate? Are key sections easy to find?
|
|
22
|
+
4. **Examples & Tutorials (10 points)** - Are there sufficient examples or tutorials to help users get started and understand core functionality?
|
|
23
|
+
5. **Maintainability & Updates (15 points)** - Does the documentation reflect ongoing maintenance and version history (e.g., changelogs, version tags)?
|
|
24
|
+
6. **Accessibility & Formatting (15 points)** - Is the documentation well-formatted and easy to read (e.g., Markdown formatting, appropriate use of code blocks, headers, etc.)?
|
|
25
|
+
### **Repository Structure Overview**
|
|
26
|
+
_(f = file, d = directory)_
|
|
27
|
+
```
|
|
28
|
+
{repository_structure}
|
|
29
|
+
```""")
|
|
30
|
+
|
|
31
|
+
EVALUATION_ITEM_PROMPT = ChatPromptTemplate.from_template("""Here are the content of files or directories in the repository that you need to take into account:
|
|
32
|
+
{files_or_directories}
|
|
33
|
+
|
|
34
|
+
### **Instructions**
|
|
35
|
+
|
|
36
|
+
Let's begin by evaluating **Criterion {evaluation_item}*.
|
|
37
|
+
|
|
38
|
+
- If the information provided is **sufficient**, please proceed with your evaluation using the following format:
|
|
39
|
+
```
|
|
40
|
+
{evaluation_item} ({score_point} points)
|
|
41
|
+
a. Score: [score out of {score_point}]
|
|
42
|
+
b. Reason: [brief explanation justifying the score]
|
|
43
|
+
```
|
|
44
|
+
- If the information provided is **insufficient**, do **not** attempt to evaluate. Instead, list the specific files or directories for which you need more detail, using the format below:
|
|
45
|
+
```
|
|
46
|
+
[files/directories needed for evaluation]
|
|
47
|
+
```""")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
## goal: identify project type
|
|
51
|
+
IDENTIFICATION_GOAL_PROJECT_TYPE = """Identify the following key attribute of the repository:
|
|
52
|
+
**project type**: The primary functional type of the project.
|
|
53
|
+
Options and their definitions:
|
|
54
|
+
- **package**: A reusable Python or R library intended to be imported by other software.
|
|
55
|
+
- **application**: A standalone Python or R program that can be directly executed by users.
|
|
56
|
+
- **pipeline**: A biomedical data processing workflow that integrates multiple tools or steps.
|
|
57
|
+
- **unknown type**: Use this only if the type cannot be determined reliably from available information.
|
|
58
|
+
**Notes**:
|
|
59
|
+
1. The project can be identified as one of the above project type.
|
|
60
|
+
2. The project may server as multiple project types, like package & pipeline, standalone application & package,
|
|
61
|
+
However, you need to investigate closely to find out the primary project type.
|
|
62
|
+
3. Do **not** rely heavily on directories like 'benchmark/' or 'tests/' when determining the project type, as they are often auxiliary."""
|
|
63
|
+
|
|
64
|
+
## goal: identify primary language
|
|
65
|
+
IDENTIFICATION_GOAL_PRIMARY_LANGUAGE = """Identify the following key attribute of the repository:
|
|
66
|
+
**primary language**: The primary language of the project.
|
|
67
|
+
Options and their definitions:
|
|
68
|
+
- **python**: Python language
|
|
69
|
+
- **R**: R language
|
|
70
|
+
- **unknown type**: Use this only if the type cannot be determined reliably from available information.
|
|
71
|
+
**Notes**:
|
|
72
|
+
The project can be identified as one of the above primary language."""
|
|
73
|
+
|
|
74
|
+
## goal: identify meta data: repo name, owner, description, license
|
|
75
|
+
IDENTIFICATION_GOAL_META_DATA = """Identify the following meta data of the repository:
|
|
76
|
+
**name**: The repository name.
|
|
77
|
+
**owner**: The repository user or orgnization.
|
|
78
|
+
**description**: The description of the repository.
|
|
79
|
+
**license**: The license of the repository, like 'MIT', 'Apache 2.0' or 'unknown'.
|
|
80
|
+
|
|
81
|
+
**Notes**: If the above meta data can't be identified, please return 'unknown' or 'N/A'.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
COT_USER_INSTRUCTION = "First, explain your reasoning process step by step, then provide the answer."
|
|
85
|
+
EVALUATION_INSTRUCTION="Please also clearly explain your reasoning step by step. Now, let's begin the evaluation."
|
|
86
|
+
|
|
87
|
+
class CollectionGoalItemEnum(Enum):
|
|
88
|
+
UserGuide = "User Guide"
|
|
89
|
+
Tutorial = "Tutorials & Vignettes"
|
|
90
|
+
DockerGeneration = "Docker Generation"
|
|
91
|
+
Installation = "Installation"
|
|
92
|
+
License = "License"
|
|
93
|
+
Contributing = "Contributing"
|
|
94
|
+
SoftwarePackageContent = "SoftwarePackageContent"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
COLLECTION_GOAL = """Your goal is to collect the names of all files that are relevant to **{goal_item}**.
|
|
99
|
+
**Note:**
|
|
100
|
+
- You only need to collect the **file names**, not their contents."""
|
|
101
|
+
|
|
102
|
+
COLLECTION_PROMPTS = {
|
|
103
|
+
"UserGuide": {
|
|
104
|
+
"goal_item": "User Guide",
|
|
105
|
+
"related_file_description": """A document qualifies as a **User Guide** if it includes **at least one** of the following elements.
|
|
106
|
+
If **any one** of these is present, the document should be classified as a User Guide — full coverage is **not required**:
|
|
107
|
+
- **Not source code or a script** (*.py, *.R) or notebook (*.ipynb, *.Rmd) that is not intended for end-user interaction.
|
|
108
|
+
- Document **functions, methods, or classes**
|
|
109
|
+
- Describe **input parameters, return values**, and **usage syntax**
|
|
110
|
+
- Include **technical guidance** for using specific APIs
|
|
111
|
+
- Are often found in folders such as
|
|
112
|
+
* `man/` (for `.Rd` files in R)
|
|
113
|
+
* `docs/reference/`, `docs/api/`, `docs/dev/` (for Python) or similar
|
|
114
|
+
* Standalone files with names like `api.md`, `reference.md`, `user_guide.md`
|
|
115
|
+
**Do not** classify the document as a User Guide if it primarily serves as a Tutorial or Example. Such documents typically include:
|
|
116
|
+
- Sample Datasets: Example data used to illustrate functionality.
|
|
117
|
+
- Narrative Explanations: Story-like descriptions guiding the user through examples.
|
|
118
|
+
- Code Walkthroughs: Detailed explanations of code snippets in a tutorial format.
|
|
119
|
+
**Do not** classify the document as a User Guide if it is souce code or a script (*.py, *.R) that is not intended for end-user interaction.
|
|
120
|
+
- You can include directory names if all files in the directory are relevant to the goal item.""",
|
|
121
|
+
"plan_important_instructions": """ - **Do not** try to summarize or read the content of any source code or script (*.py, *.R) or notebook (*.ipynb, *.Rmd) that is not intended for end-user interaction.
|
|
122
|
+
- **Do not** classify the document as a User Guide if it is source code or a script (*.py, *.R) that is not intended for end-user interaction.
|
|
123
|
+
- **Do not** classify the document as a User Guide if it is a notebook (*.ipynb, *.Rmd) that is not intended for end-user interaction.
|
|
124
|
+
- You plan **must not** include any source code or script (*.py, *.R) or notebook (*.ipynb, *.Rmd) that is not intended for end-user interaction.""",
|
|
125
|
+
"observe_important_instructions": """ - **Do not** classify the document as a User Guide if it is source code or a script (*.py, *.R) that is not intended for end-user interaction.
|
|
126
|
+
- **Do not** include any source code or script (*.py, *.R) or notebook (*.ipynb, *.Rmd) in the final answer that is not intended for end-user interaction."""
|
|
127
|
+
},
|
|
128
|
+
"Tutorial": {
|
|
129
|
+
"goal_item": "Tutorials & Vignettes",
|
|
130
|
+
"related_file_description": """
|
|
131
|
+
**Tutorials and Vignettes** are instructional documents or interactive notebooks that provide step-by-step guidance on using a software package or library. They typically include:
|
|
132
|
+
- Code Examples: Practical code snippets demonstrating how to use the software's features and functions.
|
|
133
|
+
- Explanatory Text: Clear explanations accompanying the code examples to help users understand the concepts and techniques being presented.
|
|
134
|
+
- Visualizations: Graphical representations of data or results to enhance understanding.
|
|
135
|
+
- Interactive Elements: Features that allow users to experiment with the code in real-time, such as Jupyter notebooks or R Markdown files.
|
|
136
|
+
- Use Cases: Real-world applications or scenarios where the software can be applied effectively.
|
|
137
|
+
- You can include directory names if all files in the directory are relevant to the goal item.
|
|
138
|
+
**Important instructions**:
|
|
139
|
+
- **Do not** use **read_file_tool, summarize_file_tool, check_file_related_tool** on the python/R notebook files **(.ipynb, .Rmd)**, as they are too big to read.
|
|
140
|
+
- **Do not** classify the document as a Tutorial if it is source code or a script (*.py, *.R) that is not intended for end-user interaction.
|
|
141
|
+
""",
|
|
142
|
+
"plan_important_instructions": """ - **Do not** use **read_file_tool, summarize_file_tool, check_file_related_tool** on the python/R notebook files **(.ipynb, .Rmd)**, as they are too big to read.
|
|
143
|
+
- For python/R notebook files **(.ipynb, .Rmd)**, **only infer** if it is the tutorial/vignette from the file name and avoid reading the content of the file.
|
|
144
|
+
""",
|
|
145
|
+
"observe_important_instructions": """ - **Do not** use **read_file_tool, summarize_file_tool, check_file_related_tool** on the python/R notebook files **(.ipynb, .Rmd)**, as they are too big to read.
|
|
146
|
+
- For python/R notebook files **(.ipynb, .Rmd)**, **only infer** if it is the tutorial/vignette from the file name and avoid reading the content of the file.
|
|
147
|
+
- **Do not** include any binary files (e.g., `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`) in the final answer.
|
|
148
|
+
""",
|
|
149
|
+
},
|
|
150
|
+
"DockerGeneration": {
|
|
151
|
+
"goal_item": "Generating a Dockerfile for reproducibility testing",
|
|
152
|
+
|
|
153
|
+
"related_file_description": """A document qualifies **Dockerfile Generation** related if it includes **at least one** of the following elements.
|
|
154
|
+
If **any one** of these is present, the document should be classified as a Dockerfile — full coverage is **not required**:
|
|
155
|
+
- Existing Docker Configuration
|
|
156
|
+
* Files like `Dockerfile`, `docker-compose.yml`, or any Docker-related build scripts.
|
|
157
|
+
- Installation & Environment Setup
|
|
158
|
+
* Files used to define or install dependencies.
|
|
159
|
+
* Examples: `README.md` `requirements.txt`, `environment.yml`, `setup.py`, `install.R`, `DESCRIPTION`, `pyproject.toml`, etc.
|
|
160
|
+
- Build/Runtime Scripts
|
|
161
|
+
* Shell or batch scripts used for setup, building, or launching the application.
|
|
162
|
+
* Examples: `install.sh`, `build.sh`, `run.sh`, etc.
|
|
163
|
+
- Minimal Code Examples or Get-Started Files
|
|
164
|
+
* Files that demonstrate a minimal working example of the software (e.g., for testing or reproducing results).
|
|
165
|
+
* Examples: `example.py`, `main.py`, `demo.R`, `notebooks/get_started.ipynb`, etc.
|
|
166
|
+
* These should be runnable with minimal configuration.""",
|
|
167
|
+
|
|
168
|
+
"plan_important_instructions": """- Only include minimal code examples that demonstrate basic functionality.
|
|
169
|
+
If multiple example files are found, select only the simplest and most lightweight one that is sufficient to verify the repository works.
|
|
170
|
+
- Give priority to analyzing files whose names include **"install"** or **"Dockerfile"**, as these are most likely to be useful for generating our Dockerfile
|
|
171
|
+
- The total number of collected files should **not exceed 5**.
|
|
172
|
+
- Make sure to include **only one code example**, selecting the most minimal and representative one.
|
|
173
|
+
""",
|
|
174
|
+
"observe_important_instructions": """- Only include minimal code examples that demonstrate basic functionality.
|
|
175
|
+
If multiple example files are found, select only the simplest and most lightweight one that is sufficient to verify the repository works.
|
|
176
|
+
- Give priority to analyzing files whose names include **"install"** or **"Dockerfile"**, as these are most likely to be useful for generating our Dockerfile
|
|
177
|
+
- The total number of collected files should **not exceed 5**.
|
|
178
|
+
- Make sure to include **only one code example**, selecting the most minimal and representative one.
|
|
179
|
+
""",
|
|
180
|
+
},
|
|
181
|
+
"Installation": {
|
|
182
|
+
"goal_item": "Installation Instructions",
|
|
183
|
+
"related_file_description": """A document qualifies as **Installation Instructions** if it includes **at least one** of the following elements.
|
|
184
|
+
If **any one** of these is present, the document should be classified as Installation Instructions — full coverage is **not required**:
|
|
185
|
+
- Step-by-step setup procedures for the software.
|
|
186
|
+
- Prerequisites or dependencies that need to be installed before using the software.
|
|
187
|
+
- Configuration steps required to get the software running.
|
|
188
|
+
- Troubleshooting tips related to installation issues.
|
|
189
|
+
- You can include directory names if all files in the directory are relevant to the goal item.""",
|
|
190
|
+
"plan_important_instructions": """ - Give priority to analyzing README file that contain installation instructions and the files whose names include **"install"** or **"setup"**.
|
|
191
|
+
- If multiple files are found, select the most comprehensive one that covers the installation process.
|
|
192
|
+
- The total number of collected files should **not exceed 3**.
|
|
193
|
+
- Identify and select **no more than three** installation instruction files — choose the most comprehensive and representative ones.
|
|
194
|
+
""",
|
|
195
|
+
"observe_important_instructions": """ - Give priority to analyzing README file that contain installation instructions and the files whose names include **"install"** or **"setup"**.
|
|
196
|
+
- If multiple files are found, select the most comprehensive one that covers the installation process.
|
|
197
|
+
- The total number of collected files should **not exceed 3**.
|
|
198
|
+
- Identify and select **no more than three** installation instruction files — choose the most comprehensive and representative ones.
|
|
199
|
+
""",
|
|
200
|
+
},
|
|
201
|
+
"License": {
|
|
202
|
+
"goal_item": "License Information",
|
|
203
|
+
"related_file_description": """A document qualifies as **License Information** if it includes **at least one** of the following elements.
|
|
204
|
+
If **any one** of these is present, the document should be classified as License Information — full coverage is **not required**:
|
|
205
|
+
- A file named `LICENSE`, `LICENSE.txt`, or similar that explicitly states the software's license.
|
|
206
|
+
- A section in the README or documentation that describes the licensing terms.
|
|
207
|
+
- Any file that contains legal information regarding the use, distribution, or modification of the software.
|
|
208
|
+
- You can include directory names if all files in the directory are relevant to the goal item.""",
|
|
209
|
+
},
|
|
210
|
+
"Contributing": {
|
|
211
|
+
"goal_item": "Contributing Guidelines",
|
|
212
|
+
"related_file_description": """A document qualifies as **Contributing Guidelines** if it includes **at least one** of the following elements.
|
|
213
|
+
If **any one** of these is present, the document should be classified as Contributing Guidelines — full coverage is **not required**:
|
|
214
|
+
- A file named `CONTRIBUTING.md`, `CONTRIBUTING.rst`, or similar that provides guidelines for contributing to the project.
|
|
215
|
+
- A section in the README or documentation that outlines how to contribute, report issues, or submit pull requests.
|
|
216
|
+
- Any file that contains instructions for developers on how to contribute to the project, including coding standards, testing procedures, and submission processes.
|
|
217
|
+
- You can include directory names if all files in the directory are relevant to the goal item.""",
|
|
218
|
+
},
|
|
219
|
+
"SoftwarePackageContent": {
|
|
220
|
+
"goal_item": "Software Package Content",
|
|
221
|
+
"related_file_description": """A file qualifies as **Software Package Content** if it meets **at least one** of the following elements.
|
|
222
|
+
- A compiled binary file that may be qualified as a compiled standalone software, please carefully analyze a binary file and its file name to identify if it is a compiled standalone software
|
|
223
|
+
- A source code file, like a file whose extension is `.py`, `.R`, `.ipynb`, `.ts`, or `.js`.
|
|
224
|
+
- An example data which is used to demonstrate usage or for tutorial. Image file should not be considered as example data.
|
|
225
|
+
""",
|
|
226
|
+
"plan_important_instructions": """ - A comiled standalone software file is non-textual and appears to be in an executable format (e.g., `.exe`, `.dll`, `.so`, `.bin`, `.elf`).
|
|
227
|
+
- A comiled standalone software file **is not a script or compiled library**, that is, It is not a wrapper script (e.g., shell, Python, Python notebook or Rmd) nor a dynamic/shared library meant for linking.
|
|
228
|
+
So, when you are identifying a binary file, **do not** use any tools (our tools don't work for binary file), you need to figure out if it is compiled standalone software file by the file name and extension on your own.
|
|
229
|
+
- **Source code files** are determined by their **extensions** or **file names** (e.g., `.py`, `.R`, `.ipynb`, `.ts`, `.js`). **Do not open or summarize their content.**
|
|
230
|
+
- **Example data files** are identified by typical data extensions (e.g., `.dat`, `.csv`, `.fastq`) or names like `example_*.txt`.
|
|
231
|
+
If extension/name is ambiguous, use summarize_file_tool to summarize file content to decide, **do not** read the file content.
|
|
232
|
+
- **Note**: You **only need to detect** whether at least **one** compiled standalone software file, **one** source code file and **one** example data file exist — no need to list all such files.
|
|
233
|
+
- **Note**: When identifying **compiled standalone software** or **example data files**, **ignore** any **image files** (e.g., `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`) and **image folders** (directories containing primarily images).
|
|
234
|
+
""",
|
|
235
|
+
"observe_important_instructions": """ - A comiled standalone software file is non-textual and appears to be in an executable format (e.g., `.exe`, `.dll`, `.so`, `.bin`, `.elf`).
|
|
236
|
+
- A comiled standalone software file **is not a script or compiled library**, that is, It is not a wrapper script (e.g., shell, Python, Python notebook or Rmd) nor a dynamic/shared library meant for linking.
|
|
237
|
+
- When identifying source code file, prioritize analyzing the file's **extension** and **file name** and try to avoid reading file, using check_file_related_tool or summarizing file content.
|
|
238
|
+
- When identifying example data, prioritize analyzing the file's **extension** (like .dat, .csv, .fastq, and so on) and **file name** (like example_data.txt, example.dat, and so on). If extension/name is ambiguous, use summarizing file content to decide.
|
|
239
|
+
- **Note**: You **only need to detect** whether at least **one** compiled standalone software file, **one** source code file and **one** example data file exist — no need to list all such files.
|
|
240
|
+
- **Final answer format**: If you believe **all relevant files** have been collected:
|
|
241
|
+
Your final answer **must exactly match** the following format:
|
|
242
|
+
**FinalAnswer:** {{"final_answer": [<N/A or a compiled filename>, <N/A or a source file name>, <N/A or a example data file name>]}}
|
|
243
|
+
For each category, return a single file name or `"N/A"` if none found. And the return array must exactly follow this order: [<A comiled standalone software file name>, <A source code file name>, <A example data file name>]
|
|
244
|
+
For example, **FinalAnswer:** {{"final_answer": ["N/A", "app.py", "example.csv"]}} indicates:
|
|
245
|
+
* No compiled standalone software found
|
|
246
|
+
* `app.py` found as source code
|
|
247
|
+
* `example.csv` found as example data
|
|
248
|
+
""",
|
|
249
|
+
},
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
|
|
2
|
+
from pydantic import PrivateAttr
|
|
3
|
+
import re
|
|
4
|
+
import io
|
|
5
|
+
import contextlib
|
|
6
|
+
import logging
|
|
7
|
+
from langchain_experimental.tools.python.tool import PythonAstREPLTool
|
|
8
|
+
|
|
9
|
+
class CustomPythonAstREPLTool(PythonAstREPLTool):
|
|
10
|
+
"""
|
|
11
|
+
Custom Python REPL tool that executes Python code and captures output.
|
|
12
|
+
This tool is designed to be used in a LangChain agent for executing Python code
|
|
13
|
+
and capturing the output, including any print statements.
|
|
14
|
+
"""
|
|
15
|
+
__name__ = "Custom_Python_AST_REPL"
|
|
16
|
+
_exec_globals: dict = PrivateAttr()
|
|
17
|
+
def __init__(self, *args, **kwargs):
|
|
18
|
+
super().__init__(*args, **kwargs)
|
|
19
|
+
self._exec_globals = {}
|
|
20
|
+
self._exec_globals.update(__builtins__)
|
|
21
|
+
|
|
22
|
+
def _set_globals(self, table_dict=None):
|
|
23
|
+
self._exec_globals = {}
|
|
24
|
+
self._exec_globals.update(__builtins__)
|
|
25
|
+
|
|
26
|
+
if table_dict is not None:
|
|
27
|
+
self._exec_globals.update(table_dict)
|
|
28
|
+
|
|
29
|
+
def _run(self, query: str, run_manager=None):
|
|
30
|
+
print("================================== code here ==============================")
|
|
31
|
+
print(query)
|
|
32
|
+
print("===========================================================================")
|
|
33
|
+
code_match = re.search(r"```(.*?)```", query, re.DOTALL)
|
|
34
|
+
if code_match:
|
|
35
|
+
# Extract code within backticks
|
|
36
|
+
code = code_match.group(1)
|
|
37
|
+
else:
|
|
38
|
+
code = query
|
|
39
|
+
code = code.strip()
|
|
40
|
+
if code.startswith("python"):
|
|
41
|
+
code = code[len("python"):].lstrip()
|
|
42
|
+
|
|
43
|
+
if code.endswith("Observation"):
|
|
44
|
+
code = code[:-len("Observation")].rstrip()
|
|
45
|
+
|
|
46
|
+
code_lines = code.strip().split('\n')
|
|
47
|
+
code = '\n'.join(code_lines[:-1]) # avoid printing the last line twice
|
|
48
|
+
last_line = code_lines[-1]
|
|
49
|
+
|
|
50
|
+
output_capture = io.StringIO()
|
|
51
|
+
with contextlib.redirect_stdout(output_capture), contextlib.redirect_stderr(output_capture):
|
|
52
|
+
logging.getLogger().handlers[0].stream = output_capture
|
|
53
|
+
try:
|
|
54
|
+
exec(code, self._exec_globals)
|
|
55
|
+
try:
|
|
56
|
+
result = eval(last_line, self._exec_globals)
|
|
57
|
+
if result is not None:
|
|
58
|
+
print(result, file=output_capture)
|
|
59
|
+
except:
|
|
60
|
+
pass
|
|
61
|
+
except Exception as e:
|
|
62
|
+
return str(e)
|
|
63
|
+
|
|
64
|
+
# Retrieve the output and return it
|
|
65
|
+
output = output_capture.getvalue()
|
|
66
|
+
return output if output else "Execution completed without output."
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
|
|
2
|
+
import os
|
|
3
|
+
from adalflow import Document
|
|
4
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from .common_agent_2step import CommonAgentTwoSteps
|
|
8
|
+
from ..rag.rag import RAG
|
|
9
|
+
|
|
10
|
+
RAG_COLLECT_SYSTEM_PROMPT = ChatPromptTemplate.from_template("""
|
|
11
|
+
You are an expert in repository documents retrieval and collection.
|
|
12
|
+
Your task is to collect relevant documents based on the user's query using the RAG system.
|
|
13
|
+
Here is the user's query:
|
|
14
|
+
{query}
|
|
15
|
+
The following are the documents extracted from the RAG system:
|
|
16
|
+
{documents}
|
|
17
|
+
Please analyze the documents one by one and determine which ones are relevant to the user's query.
|
|
18
|
+
Return a list of boolean values indicating the relevance of each document. Output example:
|
|
19
|
+
[True, False, True, ...] # True if the document is relevant, False otherwise
|
|
20
|
+
""")
|
|
21
|
+
|
|
22
|
+
class RAGCollectResult(BaseModel):
|
|
23
|
+
"""
|
|
24
|
+
Represents the result of a RAG collection task.
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
query (str): The user's query.
|
|
28
|
+
documents (list): List of documents retrieved from the RAG system.
|
|
29
|
+
relevance (list): List of boolean values indicating the relevance of each document.
|
|
30
|
+
"""
|
|
31
|
+
query: str = Field(..., description="The user's query")
|
|
32
|
+
documents: list[str] = Field(..., description="List of documents retrieved from the RAG system")
|
|
33
|
+
relevance: list[bool] = Field(..., description="List of boolean values indicating the relevance of each document")
|
|
34
|
+
|
|
35
|
+
RAGCollectResultSchema = {
|
|
36
|
+
'description': "Represents the result of a RAG collection task.\n\nAttributes:\n query (str): The user's query.\n documents (list): List of documents retrieved from the RAG system.\n relevance (list): List of boolean values indicating the relevance of each document.",
|
|
37
|
+
'properties': {
|
|
38
|
+
'query': {'description': "The user's query", 'title': 'Query', 'type': 'string'},
|
|
39
|
+
'documents': {'description': 'List of documents retrieved from the RAG system', 'items': {'type': 'string'}, 'title': 'Documents', 'type': 'array'},
|
|
40
|
+
'relevance': {'description': 'List of boolean values indicating the relevance of each document', 'items': {'type': 'boolean'}, 'title': 'Relevance', 'type': 'array'}
|
|
41
|
+
},
|
|
42
|
+
'required': [
|
|
43
|
+
'query', 'documents', 'relevance'
|
|
44
|
+
],
|
|
45
|
+
'title': 'RAGCollectResult',
|
|
46
|
+
'type': 'object'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class RAGCollectionTaskItem:
|
|
50
|
+
def __init__(self, llm, rag: RAG, step_callback, batch_size: int = 5):
|
|
51
|
+
"""
|
|
52
|
+
Initialize the RAGCollectionTaskItem with a repository URL or local path.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
rag: An instance of the RAG class
|
|
56
|
+
"""
|
|
57
|
+
self.llm = llm
|
|
58
|
+
self.rag = rag
|
|
59
|
+
self.batch_size = batch_size
|
|
60
|
+
self.step_callback = step_callback
|
|
61
|
+
|
|
62
|
+
def collect(self, query: str, rag_documents: list[Document]) -> list[Document]:
|
|
63
|
+
relevant_documents = []
|
|
64
|
+
for i in range(0, len(rag_documents), self.batch_size):
|
|
65
|
+
contents = [' - ' + doc.text for doc in rag_documents[i:i + self.batch_size]]
|
|
66
|
+
documents_text = "\n".join(contents)
|
|
67
|
+
prompt = RAG_COLLECT_SYSTEM_PROMPT.format(query=query, documents=documents_text)
|
|
68
|
+
prompt = prompt.replace("{", "{{").replace("}", "}}") # Escape curly braces for LangChain
|
|
69
|
+
agent = CommonAgentTwoSteps(llm=self.llm)
|
|
70
|
+
res, _, token_usage, reasoning = agent.go(
|
|
71
|
+
system_prompt=prompt,
|
|
72
|
+
instruction_prompt="Please analyze the documents and determine their relevance to the query.",
|
|
73
|
+
schema=RAGCollectResultSchema,
|
|
74
|
+
)
|
|
75
|
+
self.step_callback(
|
|
76
|
+
step_output=f"**Reasoning Process**: {reasoning}\n",
|
|
77
|
+
)
|
|
78
|
+
self.step_callback(
|
|
79
|
+
step_output=f"**RAG Collection Result**: {res}",
|
|
80
|
+
)
|
|
81
|
+
self.step_callback(
|
|
82
|
+
token_usage=token_usage,
|
|
83
|
+
)
|
|
84
|
+
res = RAGCollectResult(**res)
|
|
85
|
+
relevants = self._collect_documents(
|
|
86
|
+
rag_documents[i:i + self.batch_size],
|
|
87
|
+
res.relevance
|
|
88
|
+
)
|
|
89
|
+
relevant_documents.extend(relevants)
|
|
90
|
+
return relevant_documents
|
|
91
|
+
|
|
92
|
+
def _collect_documents(self, docs: list[Document], relevants: list[bool]) -> list[Document]:
|
|
93
|
+
"""
|
|
94
|
+
Collect documents based on relevance.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
docs: List of documents to filter
|
|
98
|
+
relevants: List of boolean values indicating relevance
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
List of relevant documents
|
|
102
|
+
"""
|
|
103
|
+
return [doc for doc, relevant in zip(docs, relevants) if relevant]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class RAGCollectionTask:
|
|
108
|
+
def __init__(self, rag: RAG):
|
|
109
|
+
"""
|
|
110
|
+
Initialize the RAGCollectionTask with a repository URL or local path.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
repo_url_or_path: URL or local path to the repository
|
|
114
|
+
access_token: Optional access token for private repositories
|
|
115
|
+
"""
|
|
116
|
+
self.rag = rag
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def query(self, query: str) -> list:
|
|
120
|
+
"""
|
|
121
|
+
Process a query using RAG.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
query: The user's query
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
retrieved_documents: List of documents retrieved based on the query
|
|
128
|
+
"""
|
|
129
|
+
return self.rag.query_doc(query)
|
|
130
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from langchain_core.messages import BaseMessage
|
|
4
|
+
from langchain_deepseek import ChatDeepSeek
|
|
5
|
+
from openai import AuthenticationError
|
|
6
|
+
from pydantic import PositiveFloat, PositiveInt
|
|
7
|
+
|
|
8
|
+
class Conversation(ABC):
|
|
9
|
+
def __init__(self):
|
|
10
|
+
super().__init__()
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def chat(
|
|
14
|
+
question: str,
|
|
15
|
+
messages: list[BaseMessage] = None
|
|
16
|
+
):
|
|
17
|
+
""" chat with LLM """
|
|
18
|
+
|
|
19
|
+
class DeepSeekConversation(Conversation):
|
|
20
|
+
chatter: ChatDeepSeek | None = None
|
|
21
|
+
model: str = "deepseek-chat"
|
|
22
|
+
temperature: PositiveFloat = 0.1
|
|
23
|
+
request_timeout: PositiveInt = 60
|
|
24
|
+
base_url: str = "https://api.deepseek.com/v1"
|
|
25
|
+
max_retries: PositiveInt = 3
|
|
26
|
+
api_key: str | None = None
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
):
|
|
30
|
+
super().__init__()
|
|
31
|
+
|
|
32
|
+
def set_api_key(self, key: str):
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
self.chatter = ChatDeepSeek(
|
|
36
|
+
model=self.model,
|
|
37
|
+
api_key=key,
|
|
38
|
+
temperature=self.temperature,
|
|
39
|
+
max_retries=self.max_retries,
|
|
40
|
+
timeout=self.request_timeout,
|
|
41
|
+
base_url=self.base_url,
|
|
42
|
+
)
|
|
43
|
+
# verify chat
|
|
44
|
+
ai_msg = self.chatter.invoke(
|
|
45
|
+
[("system", "Hi")]
|
|
46
|
+
)
|
|
47
|
+
return True
|
|
48
|
+
except AuthenticationError as e:
|
|
49
|
+
self.chatter = None
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
def chat(
|
|
53
|
+
self,
|
|
54
|
+
question: str,
|
|
55
|
+
messages: list[BaseMessage] = None
|
|
56
|
+
):
|
|
57
|
+
msgs = messages + [("user", question)] if messages is not None else \
|
|
58
|
+
[("user", question)]
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
res_msg = self.chatter.invoke(msgs)
|
|
62
|
+
return res_msg
|
|
63
|
+
except Exception as e:
|
|
64
|
+
return str(e)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|