Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion alias/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ dependencies = [
"alembic>=1.16.1",
"openpyxl>=3.1.5",
"sentry-sdk[fastapi]===2.30.0",
"agentscope-runtime>=1.0.0",
"agentscope-runtime==1.0.4",
"aiosqlite>=0.21.0",
"asyncpg>=0.30.0",
"itsdangerous>=2.2.0"
Expand Down
2 changes: 2 additions & 0 deletions alias/src/alias/agent/agents/_alias_agent_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def __init__(
"static_control",
"both",
] = "both",
plan_notebook: Optional[Any] = None,
):
super().__init__(
name=name,
Expand All @@ -52,6 +53,7 @@ def __init__(
max_iters=max_iters,
long_term_memory=long_term_memory,
long_term_memory_mode=long_term_memory_mode,
plan_notebook=plan_notebook,
)

self.session_service = session_service
Expand Down
113 changes: 45 additions & 68 deletions alias/src/alias/agent/agents/_data_science_agent.py
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
Expand All @@ -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
Expand All @@ -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
Comment on lines +27 to +31
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The import statements for LLMPromptSelector and set_workspace_dir have 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.

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

Expand Down Expand Up @@ -68,31 +70,15 @@ def __init__(
max_iters=max_iters,
session_service=session_service,
state_saving_dir=state_saving_dir,
plan_notebook=PlanNotebook(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The plan_notebook=PlanNotebook() parameter has been added to the super().__init__ call. This is a core change enabling the new structured task planning functionality.

)

install_package(self.toolkit.sandbox)
set_run_ipython_cell(self.toolkit.sandbox)
set_workspace_dir(self.toolkit.sandbox)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The set_workspace_dir function is now called to initialize the sandbox workspace. This replaces the previous install_package and set_run_ipython_cell calls, streamlining the sandbox setup and aligning with the new code execution protocols.


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,
Expand Down Expand Up @@ -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(
Expand All @@ -169,21 +144,14 @@ def __init__(

logger.info(
f"[{self.name}] "
"DeepInsightAgent initialized (fully model-driven).",
"DataScienceAgent initialized (fully model-driven).",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The log message has been updated from 'DeepInsightAgent' to 'DataScienceAgent' for consistency with the agent's name. This is a minor but good correction.

)

@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}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The sys_prompt property has been simplified by removing the todo_prompt logic. This is consistent with the removal of the old todo list management system and the introduction of PlanNotebook.


@trace_reply
async def reply(
Expand Down Expand Up @@ -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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The generate_report method now returns three values: response, report_md, and report_html. This change allows for more flexible handling of report formats, providing both markdown and HTML versions.

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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The report generation logic has been updated to write both markdown and HTML versions of the detailed report to separate files. This provides more comprehensive output for the user and aligns with the expanded return values of generate_report.

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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The response message now explicitly states that both markdown and HTML versions of the detailed report have been saved, along with their respective paths. This improves clarity for the user regarding the generated outputs.


kwargs["response"] = response
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The ds_tool_list in init_ds_toolkit now includes read_file and removes run_ipython_cell. The removal of run_ipython_cell is a critical change that aligns with the new 'Code Execution Protocols' in the system prompt, promoting safer execution by requiring code to be written to a file and executed via run_shell_command.

]
share_tools(full_toolkit, ds_toolkit, ds_tool_list)
Expand Down
4 changes: 0 additions & 4 deletions alias/src/alias/agent/agents/ds_agent_utils/__init__.py
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The imports for todo_write and install_package have been removed from __init__.py, reflecting their removal from the data science agent's core logic and the shift to PlanNotebook and set_workspace_dir.

from .ds_toolkit import add_ds_specific_tool
from .prompt_selector import LLMPromptSelector
Expand All @@ -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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The __all__ list has been updated to remove todo_write and install_package, maintaining consistency with the import changes and the refactored functionalities.

"LLMPromptSelector",
"files_filter_pre_reply_hook",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The prompt has been updated to instruct the agent to use the create_plan tool instead of todo_write for task planning. This reflects the new, more structured approach to task management.

- Execution without planning is considered a **violation**.

2. **Data Inspection**
Expand All @@ -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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The 'Task Management Rules' section has been completely revised to detail the usage of the new PlanNotebook tools (create_plan, update_subtask_state, finish_subtask, revise_current_plan, finish_plan). This provides clear instructions for the agent on how to manage its tasks effectively.


---
## 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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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
Expand Down

This file was deleted.

Loading