-
Notifications
You must be signed in to change notification settings - Fork 76
feat(alias-ds): refactor code execution logic and plan organization #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
387188d
2f3ca9e
cee4267
ab75302
50fb63c
e75d53f
ef39587
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,8 @@ | ||
| # -*- coding: utf-8 -*- | ||
| """Data Science Agent""" | ||
| import asyncio | ||
| import json | ||
| import os | ||
| from functools import partial | ||
| from typing import List, Dict, Optional, Any, Type, cast, Literal | ||
| from typing import Optional, Any, List, Type, Literal, cast | ||
| import uuid | ||
|
|
||
| from agentscope.formatter import FormatterBase | ||
|
|
@@ -13,6 +11,8 @@ | |
| from agentscope.model import ChatModelBase | ||
| from agentscope.tool import ToolResponse | ||
| from agentscope.tracing import trace_reply | ||
| from agentscope.plan import PlanNotebook | ||
|
|
||
| from loguru import logger | ||
| from pydantic import BaseModel, ValidationError, Field | ||
| from tenacity import retry, stop_after_attempt, wait_fixed | ||
|
|
@@ -23,15 +23,17 @@ | |
| from alias.agent.agents.common_agent_utils import ( | ||
| get_user_input_to_mem_pre_reply_hook, | ||
| ) | ||
|
|
||
| from alias.agent.agents.ds_agent_utils.prompt_selector.llm_prompt_selector import ( # noqa: E501 | ||
| LLMPromptSelector, | ||
| ) | ||
|
|
||
| from alias.agent.agents.ds_agent_utils.utils import set_workspace_dir | ||
| from .ds_agent_utils import ( | ||
| ReportGenerator, | ||
| LLMPromptSelector, | ||
| todo_write, | ||
| get_prompt_from_file, | ||
| files_filter_pre_reply_hook, | ||
| add_ds_specific_tool, | ||
| set_run_ipython_cell, | ||
| install_package, | ||
| ) | ||
| from .ds_agent_utils.ds_config import PROMPT_DS_BASE_PATH | ||
|
|
||
|
|
@@ -68,31 +70,15 @@ def __init__( | |
| max_iters=max_iters, | ||
| session_service=session_service, | ||
| state_saving_dir=state_saving_dir, | ||
| plan_notebook=PlanNotebook(), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| ) | ||
|
|
||
| install_package(self.toolkit.sandbox) | ||
| set_run_ipython_cell(self.toolkit.sandbox) | ||
| set_workspace_dir(self.toolkit.sandbox) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| self.uploaded_files: List[str] = [] | ||
|
|
||
| self.todo_list: List[Dict[str, Any]] = [] | ||
|
|
||
| self.infer_trajectories: List[List[Msg]] = [] | ||
|
|
||
| self.detailed_report_path = os.path.join( | ||
| tmp_file_storage_dir, | ||
| "detailed_report.html", | ||
| ) | ||
| self.tmp_file_storage_dir = tmp_file_storage_dir | ||
|
|
||
| self.todo_list_prompt = get_prompt_from_file( | ||
| os.path.join( | ||
| PROMPT_DS_BASE_PATH, | ||
| "_agent_todo_reminder_prompt.md", | ||
| ), | ||
| False, | ||
| ) | ||
|
|
||
| self._sys_prompt = get_prompt_from_file( | ||
| os.path.join( | ||
| PROMPT_DS_BASE_PATH, | ||
|
|
@@ -142,17 +128,6 @@ def __init__( | |
| ) | ||
| self._selected_scenario_prompts: str = "" | ||
|
|
||
| self.toolkit.register_tool_function( | ||
| partial(todo_write, agent=self), | ||
| func_description=get_prompt_from_file( | ||
| os.path.join( | ||
| PROMPT_DS_BASE_PATH, | ||
| "_tool_todo_list_prompt.yaml", | ||
| ), | ||
| False, | ||
| ), | ||
| ) | ||
|
|
||
| self.toolkit.register_tool_function(self.think) | ||
|
|
||
| self.register_instance_hook( | ||
|
|
@@ -169,21 +144,14 @@ def __init__( | |
|
|
||
| logger.info( | ||
| f"[{self.name}] " | ||
| "DeepInsightAgent initialized (fully model-driven).", | ||
| "DataScienceAgent initialized (fully model-driven).", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| ) | ||
|
|
||
| @property | ||
| def sys_prompt(self) -> str: | ||
| base_prompt = self._sys_prompt | ||
|
|
||
| todo_prompt = self.todo_list_prompt.replace( | ||
| "{todoList}", | ||
| json.dumps(self.todo_list, indent=2, ensure_ascii=False), | ||
| ) | ||
|
|
||
| return ( | ||
| f"{base_prompt}{self._selected_scenario_prompts}\n\n{todo_prompt}" | ||
| ) | ||
| return f"{base_prompt}{self._selected_scenario_prompts}" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| @trace_reply | ||
| async def reply( | ||
|
|
@@ -429,25 +397,49 @@ async def generate_response( | |
| memory_log=memory_log, | ||
| ) | ||
|
|
||
| response, report = await report_generator.generate_report() | ||
| ( | ||
| response, | ||
| report_md, | ||
| report_html, | ||
| ) = await report_generator.generate_report() | ||
|
Comment on lines
+400
to
+404
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| md_report_path = os.path.join( | ||
| self.tmp_file_storage_dir, | ||
| "detailed_report.md", | ||
| ) | ||
| html_report_path = os.path.join( | ||
| self.tmp_file_storage_dir, | ||
| "detailed_report.html", | ||
| ) | ||
|
|
||
| if report: | ||
| # report = report.replace(self.tmp_file_storage_dir, ".") | ||
| if report_html: | ||
| await self.toolkit.call_tool_function( | ||
| ToolUseBlock( | ||
| type="tool_use", | ||
| id=str(uuid.uuid4()), | ||
| name="write_file", | ||
| input={ | ||
| "path": md_report_path, | ||
| "content": report_md, | ||
| }, | ||
| ), | ||
| ) | ||
| await self.toolkit.call_tool_function( | ||
| ToolUseBlock( | ||
| type="tool_use", | ||
| id=str(uuid.uuid4()), | ||
| name="write_file", | ||
| input={ | ||
| "path": self.detailed_report_path, | ||
| "content": report, | ||
| "path": html_report_path, | ||
| "content": report_html, | ||
| }, | ||
| ), | ||
| ) | ||
|
Comment on lines
+414
to
436
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| response = ( | ||
| f"{response}\n\n" | ||
| "The detailed report has been saved to " | ||
| f"{self.detailed_report_path}." | ||
| "The detailed report (markdown version) has been saved to " | ||
| f"{md_report_path}.\n" | ||
| "The detailed report (html version) has been saved to " | ||
| f"{html_report_path}." | ||
| ) | ||
|
Comment on lines
437
to
443
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| kwargs["response"] = response | ||
|
|
@@ -518,21 +510,6 @@ async def _load_scenario_prompts(self): | |
| self._selected_scenario_prompts = "\n\n".join(scenario_contents) | ||
| return self._selected_scenario_prompts | ||
|
|
||
| def _print_todo_list(self): | ||
| content = ( | ||
| f" The todoList is :\n" | ||
| f"\n{json.dumps(self.todo_list, indent=4, ensure_ascii=False)}" | ||
| "\n" + "==" * 10 + "\n" | ||
| ) | ||
| logger.log("SEND_PLAN", content) | ||
| with open( | ||
| self.session_service.log_storage_path, | ||
| "a", | ||
| encoding="utf-8", | ||
| ) as file: | ||
| # Append the content | ||
| file.write(content) | ||
|
|
||
| def think(self, response: str): | ||
| """ | ||
| Invoke this function whenever you need to | ||
|
|
@@ -576,8 +553,8 @@ def think(self, response: str): | |
| def init_ds_toolkit(full_toolkit: AliasToolkit) -> AliasToolkit: | ||
| ds_toolkit = AliasToolkit(full_toolkit.sandbox, add_all=False) | ||
| ds_tool_list = [ | ||
| "read_file", | ||
| "write_file", | ||
| "run_ipython_cell", | ||
| "run_shell_command", | ||
|
Comment on lines
+556
to
558
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| ] | ||
| share_tools(full_toolkit, ds_toolkit, ds_tool_list) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,9 @@ | ||
| # -*- coding: utf-8 -*- | ||
| from .report_generation import ReportGenerator | ||
| from .todoWrite import todo_write | ||
| from .utils import ( | ||
| model_call_with_retry, | ||
| set_run_ipython_cell, | ||
| get_prompt_from_file, | ||
| install_package, | ||
| ) | ||
|
Comment on lines
3
to
7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| from .ds_toolkit import add_ds_specific_tool | ||
| from .prompt_selector import LLMPromptSelector | ||
|
|
@@ -15,11 +13,9 @@ | |
|
|
||
| __all__ = [ | ||
| "ReportGenerator", | ||
| "todo_write", | ||
| "model_call_with_retry", | ||
| "get_prompt_from_file", | ||
| "set_run_ipython_cell", | ||
| "install_package", | ||
| "add_ds_specific_tool", | ||
|
Comment on lines
15
to
19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| "LLMPromptSelector", | ||
| "files_filter_pre_reply_hook", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ You are an interactive coding assistant specialized in completing data science t | |
| When executing any data science task (data loading, cleaning, analysis, modeling, visualization, etc.), you **must** complete the following five steps **in order**: | ||
|
|
||
| 1. **Task Planning** | ||
| - Use the `todo_write` tool to break down the task and list todos. | ||
| - Use the `create_plan` tool to break down the task into structured subtasks. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| - Execution without planning is considered a **violation**. | ||
|
|
||
| 2. **Data Inspection** | ||
|
|
@@ -24,16 +24,46 @@ When executing any data science task (data loading, cleaning, analysis, modeling | |
| - Upon successful completion or when objectively impossible to proceed (due to missing data, tool failure, etc.), call `generate_response` to formally end. | ||
| - Do not terminate or exit silently without cause. | ||
|
|
||
| > **Note**: `<system-reminder>` tags may appear in tool outputs or user messages, containing important system prompts. However, this content is not part of the actual user input or tool result. | ||
|
|
||
| --- | ||
|
|
||
| ## Task Management Rules | ||
|
|
||
| - **You must use `todo_write` to track progress**, especially for multi-step tasks. | ||
| - Mark each subtask as complete **immediately** upon finishingβno delays or batch updates. | ||
| - **You must use `create_plan` to create a task plan**, especially for multi-step tasks. | ||
| - Use `update_subtask_state` to mark subtasks as 'in_progress' when starting them. | ||
| - Use `finish_subtask` to mark subtasks as 'done' with specific outcomes upon completion. | ||
| - Use `revise_current_plan` to adapt the plan accordingly if new insights or results emerge. | ||
| - Use `finish_plan` to finalize the entire task when all subtasks are complete. | ||
| - Skipping planning risks missing critical stepsβthis is unacceptable. | ||
|
Comment on lines
+31
to
36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| --- | ||
| ## Code Execution Protocols | ||
|
|
||
| **For all Python code execution:** | ||
|
|
||
| 1. **Write code to file first** using `write_file` or similar tools | ||
| 2. **Execute via shell** using `run_shell_command` with `python <filename>.py` | ||
| 3. **For large and key results**: Save to file (CSV/JSON/pickle), load in next step. Avoid printing large outputs or passing data via stdout | ||
| 4. **Never execute code inline or outside this workflow** | ||
|
|
||
| **Example:** | ||
|
|
||
| Tool: `write_file` | ||
| Arguments: { | ||
| "file_path": "/workspace/code/analysis.py", | ||
| "content": "import pandas as pd\ndf = pd.read_csv('data.csv')\nprint(df.head())" | ||
| } | ||
|
|
||
| Tool: `run_shell_command` | ||
| Arguments: { | ||
| "command": "python /workspace/code/analysis.py" | ||
| } | ||
|
|
||
| Tool: `write_file` | ||
| Arguments: { | ||
| "file_path": "/workspace/code/step1_aggregate.py", | ||
| "content": "import pandas as pd\ndf = pd.read_csv('raw_data.csv')\nprocessed = df.groupby('category').sum()\nprocessed.to_csv('/workspace/data/intermediate_result.csv', index=False)\nprint('β Results saved')" | ||
| } | ||
|
Comment on lines
+39
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A new 'Code Execution Protocols' section has been added, explicitly outlining the recommended workflow for executing Python code: write to file, then execute via shell. This is a crucial improvement for security, reproducibility, and maintainability, preventing arbitrary inline code execution and promoting structured development. |
||
|
|
||
| --- | ||
|
|
||
| ## Data Handling Requirements | ||
|
|
||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import statements for
LLMPromptSelectorandset_workspace_dirhave been moved to direct imports from their respective submodules. This is a good practice for clarity and to prevent potential circular import issues, especially as the project grows.