From 1d47fb366444ba3426c99b963a635ab159f08b27 Mon Sep 17 00:00:00 2001 From: styxhuang Date: Sat, 7 Feb 2026 09:38:02 +0800 Subject: [PATCH 1/6] feat: update --- .../structure_search_agent/__init__.py | 0 .../structure_search_agent/agent.py | 43 ++++ .../structure_search_agent/constant.py | 8 + .../structure_search_agent/prompt.py | 223 ++++++++++++++++++ agents/matmaster_agent/sub_agents/mapping.py | 16 +- agents/matmaster_agent/sub_agents/tools.py | 116 ++------- 6 files changed, 300 insertions(+), 106 deletions(-) create mode 100644 agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/__init__.py create mode 100644 agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/agent.py create mode 100644 agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/constant.py create mode 100644 agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/prompt.py diff --git a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/__init__.py b/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/agent.py b/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/agent.py new file mode 100644 index 00000000..3d39cb0e --- /dev/null +++ b/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/agent.py @@ -0,0 +1,43 @@ +from dotenv import load_dotenv +from dp.agent.adapter.adk import CalculationMCPToolset +from google.adk.agents import BaseAgent +from google.adk.tools.mcp_tool.mcp_session_manager import SseServerParams + +from agents.matmaster_agent.constant import LOCAL_EXECUTOR, BohriumStorge +from agents.matmaster_agent.core_agents.public_agents.sync_agent import ( + BaseSyncAgentWithToolValidator, +) +from agents.matmaster_agent.sub_agents.MrDice_agent.constant import MrDice_Agent_Name +from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.constant import ( + STRUCTURE_SEARCH_URL, +) +from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.prompt import ( + StructureSearchAgentName, +) + +load_dotenv() + +# Initialize MCP tools and agent +structure_search_toolset = CalculationMCPToolset( + connection_params=SseServerParams(url=STRUCTURE_SEARCH_URL), + storage=BohriumStorge, + executor=LOCAL_EXECUTOR, +) + + +class StructureSearchAgentBase(BaseSyncAgentWithToolValidator): + def __init__(self, llm_config, name_suffix=''): + super().__init__( + # model=llm_config.deepseek_chat, + model=llm_config.default_litellm_model, + name=StructureSearchAgentName + name_suffix, + description='', + instruction='', + tools=[structure_search_toolset], + render_tool_response=True, + supervisor_agent=MrDice_Agent_Name, + ) + + +def init_structure_search_agent(llm_config, name_suffix='') -> BaseAgent: + return StructureSearchAgentBase(llm_config, name_suffix=name_suffix) diff --git a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/constant.py b/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/constant.py new file mode 100644 index 00000000..4baea51e --- /dev/null +++ b/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/constant.py @@ -0,0 +1,8 @@ +from agents.matmaster_agent.constant import CURRENT_ENV + +STRUCTURE_SEARCH_AGENT_NAME = 'structure_search_agent' + +if CURRENT_ENV in ['test', 'uat']: + STRUCTURE_SEARCH_URL = 'http://chvz1424099.bohrium.tech:50001/sse' +else: + STRUCTURE_SEARCH_URL = 'http://chvz1424099.bohrium.tech:50002/sse' diff --git a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/prompt.py b/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/prompt.py new file mode 100644 index 00000000..2896d944 --- /dev/null +++ b/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/prompt.py @@ -0,0 +1,223 @@ +StructureSearchAgentName = 'structure_search_agent' + +StructureSearchAgentToolDescription = ( + 'What it does: Retrieve structures across multiple sources (BohriumPublic / OpenLAM / OPTIMADE providers) and run advanced SQL queries on MOFdb.\n' + 'When to use: Any "find crystal structures" request, including formula/elements/space group/band gap filters, time/energy filters (OpenLAM), cross-provider searches (OPTIMADE), or MOF-specific analytics (MOFdb SQL).\n' + 'Prerequisites / Inputs: Provide either structured filters (formula/elements/space group ranges), OpenLAM filters (energy/time), OPTIMADE filter strings, or MOFdb SQL.\n' + 'Outputs: Structures or metadata in CIF/JSON; MOFdb returns SQL rows and optional structure file links.\n' + 'Cannot do / Limits: OPTIMADE filters must follow the standard grammar; MOFdb is MOF-specific; OpenLAM does not provide space group/band gap.\n' + 'Cost / Notes: Default to BohriumPublic for speed; use OPTIMADE for flexible/cross-provider retrieval; use MOFdb for complex MOF analytics.' +) + +StructureSearchAgentArgsSetting = """ +## PARAMETER CONSTRUCTION GUIDE + +## Do not ask the user for confirmation; directly start retrieval when a query is made. + +## 0) ROUTING: WHICH TOOL TO CALL +You have access to multiple retrieval tools. Choose ONE based on the user intent: + +### A) BohriumPublic (fast structured filters) +Use `fetch_bohrium_crystals` when the user asks for: +- formula / elements / space group / atom count / predicted formation energy / band gap +- and they do NOT require cross-provider search or complex boolean logic + +### B) OpenLAM (energy / time filters) +Use `fetch_openlam_structures` when the user asks for: +- OpenLAM specifically, OR upload/submission time filters, OR OpenLAM energy range filters +Limits: OpenLAM does NOT support space group, band gap, or "elements list" filters. + +### C) OPTIMADE (cross-provider, flexible composition filters) +Use OPTIMADE tools when the user needs: +- cross-provider search (e.g., "search in mp/cod/oqmd..."), OR +- flexible logical composition constraints, OR +- structure-type family queries (anonymous formula like AB2C4), OR +- 2D/1D/0D constraints (nperiodic_dimensions) +Pick the specific tool: +- `fetch_structures_with_spg` if the user specifies a space group number +- `fetch_structures_with_bandgap` if the user specifies a band-gap range +- `fetch_structures_with_filter` otherwise + +### D) MOFdb (MOF-only, complex analytics) +Use `fetch_mofs_sql` when the user asks for: +- MOF-specific properties (surface area, pore metrics, adsorption/isotherms, heats), OR +- advanced analysis requiring multi-table joins / ranking / statistics + +## 1) BOHRIUMPUBLIC PARAMETERS (fetch_bohrium_crystals) +### FILTER OPTIONS +- **Formula**: chemical formula string (e.g., `"CoH12(BrO3)2"`) +- **Elements**: list of required elements (e.g., `["Co","O"]`) +- **Match mode** (applies to both `formula` and `elements`): + - `0` = contains (e.g., formula `"Co"` matches `"CoO"`, `"CoH12(BrO3)2"`; elements `["Co"]` matches materials containing Co + anything else) + - `1` = exact-only match (formula must match exactly; elements list must match **exactly and only** those elements) +- **Space group**: use the space group number (e.g., `14` for P2₁/c) +- **Atom count range**: filter by number of atoms in the unit cell, e.g. `["10","100"]` +- **Predicted formation energy**: range filter in eV, e.g. `["-2","0"]` +- **Band gap**: eV range [lo, hi] (omitted bound defaults to 0/100), e.g. ["0","3"], ["1","100"] +- **Result limit**: maximum number of results (`n_results`) +- **Output formats**: + - `"cif"` → crystallographic structure files + - `"json"` → complete metadata + +## HOW TO CHOOSE PARAMETERS +- If user specifies a **formula** → set `formula` and choose `match_mode`: + - `0` if the user means "contains fragment" + - `1` if the user means "exact formula" +- If user specifies **elements** → set `elements` and choose `match_mode`: + - `0` if the user means "must include these elements" + - `1` if the user means "must have exactly these elements and nothing else" +- If user specifies a **space group number** → set `spacegroup_number` +- If user specifies an **atom count range** → set `atom_count_range` +- If user specifies **formation energy or band gap ranges** → set the corresponding ranges +- If the user requests **metadata only** → use `output_formats=['json']` +- If the user requests **downloadable crystal files** → use `output_formats=['cif']` + +## PARAMETER EXAMPLES +1) 用户:检索 SrTiO₃ 的晶体结构,并以JSON格式返回 + → Tool: fetch_bohrium_crystals + formula: "SrTiO3" + match_mode: 1 + output_formats: ["json"] + +2) 用户:在Materials Project中检索并返回3个带隙大于2 eV的氧化物结构 + → Tool: fetch_bohrium_crystals + elements: ["O"] + match_mode: 0 + band_gap_range: ["2","100"] + n_results: 3 + +3) 用户:找出空间群编号 14,原子数 50–100 的晶体 + → Tool: fetch_bohrium_crystals + spacegroup_number: 14 + atom_count_range: ["50","100"] + +4) 用户:检索 FeNi 合金的结构 + → Tool: fetch_bohrium_crystals + elements: ["Fe","Ni"] # 合金只含有Fe和Ni元素,不能含有其他元素 + match_mode: 1 # 合金需要精确匹配 + +5) 用户:找所有化学式中包含 SiO3 的材料 + → Tool: fetch_bohrium_crystals + formula: "SiO3" + match_mode: 0 + +## 2) OPENLAM PARAMETERS (fetch_openlam_structures) +### FILTER OPTIONS +- **Formula**: chemical formula string (e.g., `"Fe2O3"`) +- **Energy**: `min_energy` and/or `max_energy` in eV +- **Submission time**: ISO UTC date-time (`min_submission_time`, `max_submission_time`) +- **Result limit**: `n_results` +- **Output formats**: `"cif"` or `"json"` + +### EXAMPLES +1) 用户:查找 Fe2O3 的 5 个晶体结构,导出为 CIF + → Tool: fetch_openlam_structures + formula: "Fe2O3" + n_results: 5 + output_formats: ["cif"] + +2) 用户:查找能量在 -10 到 20 eV 之间,2024 年后上传的材料 + → Tool: fetch_openlam_structures + min_energy: -10.0 + max_energy: 20.0 + min_submission_time: "2024-01-01T00:00:00Z" + +## 3) MOFDB PARAMETERS (fetch_mofs_sql) +### INPUT +- **sql**: SQL query string (use CTEs, window functions, joins as needed) +- **n_results**: controls SQL LIMIT (when applicable) and returned structures + +### EXAMPLE +用户:统计各数据库的 MOF 数量 +→ Tool: fetch_mofs_sql + sql: "SELECT database, COUNT(*) AS count FROM mofs GROUP BY database ORDER BY count DESC" + +## 4) OPTIMADE PARAMETERS (fetch_structures_with_filter / _with_spg / _with_bandgap) +### MINIMUM SAFE OPTIMADE SYNTAX RULES (DO NOT VIOLATE) +- Allowed operators ONLY: =, !=, <, <=, >, >=, AND, OR, NOT, HAS, HAS ALL, HAS ANY, IS KNOWN, IS UNKNOWN +- All strings MUST be in double quotes: "Fe", "SiO2" +- Do NOT use CONTAINS / LIKE / IN / regex / invented fields +- To express "only these elements": use `elements HAS ALL ... AND nelements = N` + +### TOOL CHOICE +- If user gives space group number → `fetch_structures_with_spg(base_filter, spg_number, ...)` +- If user gives band gap range → `fetch_structures_with_bandgap(base_filter, min_bg, max_bg, ...)` +- Else → `fetch_structures_with_filter(filter, ...)` + +### EXAMPLES +1) 用户:找空间群 225 的 MgO(rocksalt),返回 CIF + → Tool: fetch_structures_with_spg + base_filter: chemical_formula_reduced="MgO" + spg_number: 225 + as_format: "cif" + +2) 用户:找含 Al 且带隙 1–2 eV 的材料,返回 JSON + → Tool: fetch_structures_with_bandgap + base_filter: elements HAS "Al" + min_bg: 1.0 + max_bg: 2.0 + as_format: "json" +""" + +StructureSearchAgentSummaryPrompt = """ +## RESPONSE FORMAT + +**If the tool response indicates `by_source` = "mofdb"** (MOFdb results): +1. Brief explanation of the SQL query used +2. Markdown table of retrieved MOFs with relevant columns +3. Output directory path for download/archive +4. Key findings from results (if applicable) + +**If the tool response indicates `by_source` = "optimade"** (OPTIMADE results): +The response must always have three parts in order: +1. A brief explanation of the applied filters and providers. +2. A Markdown table listing all retrieved results (NO omissions/truncation; number of rows must exactly equal `n_found`). +3. A download link for an archive (.tgz) if provided by the tool. +Each table must always include the following nine columns in this fixed order: +(1) Formula (`attributes.chemical_formula_reduced`) +(2) Elements (infer from formula) +(3) Atom count (if available; else **Not Provided**) +(4) Download link (CIF or JSON file) +(5) Provider (infer from provider URL) +(6) ID (`id`) +Missing values must be exactly **Not Provided**. If `n_found = 0`, do not generate an empty table. + +**If the tool response indicates `by_source` = "openlam"** (OpenLAM results): +The response must always include: +1. ✅ A brief explanation of the filters applied +2. 📊 A Markdown table of the retrieved structures + - Columns (fixed order): + (1) Formula (`formula`) + (2) Elements (deduced from `formula`) + (3) Atom count → **Not Provided** + (4) Space group → **Not Provided** + (5) Energy / Formation energy (`energy` if available; else **Not Provided**) + (6) Band gap → **Not Provided** + (7) Download link (CIF/JSON, based on requested output) + (8) Source database → always `"OpenLAM"` + (9) ID (`id`) + - Fill missing values with exactly **Not Provided** + - Number of rows **must exactly equal** `n_found` +3. 📦 The `output_dir` path returned by the tool (for download/archive) +If `n_found = 0`, clearly state no matches were found, repeat the applied filters, and suggest loosening criteria. Do **not** generate an empty table. + +**Otherwise** (BohriumPublic or other sources): +The response must always include: +1. ✅ A brief explanation of the filters applied +2. 📊 A Markdown table of the retrieved structures + - Columns (fixed order): + (1) Formula (`formula`) + (2) Elements (deduced from `formula`) + (3) Atom count (`crystal_ext.number_of_atoms` if available; else **Not Provided**) + (4) Space group (`Symbol(Number)` if `crystal_ext.symbol` is available and number can be mapped; else **Not Provided**) + (5) Energy / Formation energy (`crystal_ext.predicted_formation_energy` if available; else **Not Provided**) + (6) Band gap (`crystal_ext.band_gap` if available; else **Not Provided**) + (7) Download link (CIF/JSON, based on `output_formats`) + (8) Source database → always `"BohriumPublic"` + (9) ID (`id`) + - Fill missing values with exactly **Not Provided** + - Number of rows **must exactly equal** `n_found` +3. 📦 The `output_dir` path returned by the tool (for download/archive) + +If `n_found = 0`, clearly state that no matches were found, repeat the applied filters, and suggest loosening criteria. Do **not** generate an empty table. +""" diff --git a/agents/matmaster_agent/sub_agents/mapping.py b/agents/matmaster_agent/sub_agents/mapping.py index a974748e..3c876d2e 100644 --- a/agents/matmaster_agent/sub_agents/mapping.py +++ b/agents/matmaster_agent/sub_agents/mapping.py @@ -110,6 +110,15 @@ lammps_toolset, ) from agents.matmaster_agent.sub_agents.LAMMPS_agent.constant import LAMMPS_AGENT_NAME + +from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.agent import ( + StructureSearchAgentBase, + structure_search_toolset, +) +from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.constant import ( + STRUCTURE_SEARCH_AGENT_NAME, +) + from agents.matmaster_agent.sub_agents.MrDice_agent.bohriumpublic_agent.agent import ( Bohriumpublic_AgentBase, bohriumpublic_toolset, @@ -293,10 +302,7 @@ 'polymer_kb_toolset': polymer_kb_toolset, 'steel_kb_toolset': steel_kb_toolset, 'steel_predict_toolset': steel_predict_toolset, - 'optimade_toolset': optimade_toolset, - 'bohriumpublic_toolset': bohriumpublic_toolset, - 'openlam_toolset': openlam_toolset, - 'mofdb_toolset': mofdb_toolset, + 'structure_search_toolset': structure_search_toolset, 'organic_reaction_toolset': organic_reaction_toolset, 'perovskite_toolset': perovskite_toolset, 'piloteye_electro_toolset': piloteye_electro_toolset, @@ -337,6 +343,7 @@ BOHRIUMPUBLIC_DATABASE_AGENT_NAME: Bohriumpublic_AgentBase, MOFDB_DATABASE_AGENT_NAME: Mofdb_AgentBase, OPENLAM_DATABASE_AGENT_NAME: Openlam_AgentBase, + STRUCTURE_SEARCH_AGENT_NAME: StructureSearchAgentBase, ORGANIC_REACTION_AGENT_NAME: OragnicReactionAgent, PerovskiteAgentName: PerovskiteAgent, PILOTEYE_ELECTRO_AGENT_NAME: PiloteyeElectroAgent, @@ -380,6 +387,7 @@ class MatMasterSubAgentsEnum(str, Enum): BohriumPublicDatabaseAgent = BOHRIUMPUBLIC_DATABASE_AGENT_NAME MOFDBDatabaseAgent = MOFDB_DATABASE_AGENT_NAME OpenLAMDatabaseAgent = OPENLAM_DATABASE_AGENT_NAME + StructureSearchAgent = STRUCTURE_SEARCH_AGENT_NAME OrganicReactionAgent = ORGANIC_REACTION_AGENT_NAME PerovskiteAgent = PerovskiteAgentName PiloteyeElectroAgent = PILOTEYE_ELECTRO_AGENT_NAME diff --git a/agents/matmaster_agent/sub_agents/tools.py b/agents/matmaster_agent/sub_agents/tools.py index d92905be..e5ff7619 100644 --- a/agents/matmaster_agent/sub_agents/tools.py +++ b/agents/matmaster_agent/sub_agents/tools.py @@ -53,42 +53,17 @@ HEAKbAgentToolDescription, ) from agents.matmaster_agent.sub_agents.LAMMPS_agent.constant import LAMMPS_AGENT_NAME -from agents.matmaster_agent.sub_agents.MrDice_agent.bohriumpublic_agent.constant import ( - BOHRIUMPUBLIC_DATABASE_AGENT_NAME, -) -from agents.matmaster_agent.sub_agents.MrDice_agent.bohriumpublic_agent.prompt import ( - BohriumPublicAgentArgsSetting, - BohriumPublicAgentSummaryPrompt, - BohriumPublicAgentToolDescription, -) -from agents.matmaster_agent.sub_agents.MrDice_agent.mofdb_agent.constant import ( - MOFDB_DATABASE_AGENT_NAME, -) -from agents.matmaster_agent.sub_agents.MrDice_agent.mofdb_agent.prompt import ( - MofdbAgentArgsSetting, - MofdbAgentSummaryPrompt, - MofdbAgentToolDescription, -) -from agents.matmaster_agent.sub_agents.MrDice_agent.openlam_agent.constant import ( - OPENLAM_DATABASE_AGENT_NAME, -) -from agents.matmaster_agent.sub_agents.MrDice_agent.openlam_agent.prompt import ( - OpenlamAgentArgsSetting, - OpenlamAgentSummaryPrompt, - OpenlamAgentToolDescription, -) -from agents.matmaster_agent.sub_agents.MrDice_agent.optimade_agent.constant import ( - OPTIMADE_DATABASE_AGENT_NAME, + +from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.constant import ( + STRUCTURE_SEARCH_AGENT_NAME, + STRUCTURE_SEARCH_URL ) -from agents.matmaster_agent.sub_agents.MrDice_agent.optimade_agent.prompt import ( - OptimadeAgentSummaryPrompt, - OptimadeBandgapArgsSetting, - OptimadeBandgapToolDescription, - OptimadeFilterArgsSetting, - OptimadeFilterToolDescription, - OptimadeSpgArgsSetting, - OptimadeSpgToolDescription, +from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.prompt import ( + StructureSearchAgentArgsSetting, + StructureSearchAgentSummaryPrompt, + StructureSearchAgentToolDescription, ) + from agents.matmaster_agent.sub_agents.NMR_agent.constant import ( NMR_AGENT_NAME, ) @@ -829,78 +804,15 @@ 'summary_prompt': STEELPredictAgentSummaryPrompt, 'self_check': False, }, - 'fetch_structures_with_filter': { - 'belonging_agent': OPTIMADE_DATABASE_AGENT_NAME, - 'scene': [SceneEnum.DATABASE_SEARCH], - 'description': OptimadeFilterToolDescription, - 'args_setting': f"{OptimadeFilterArgsSetting}", - 'alternative': [ - 'fetch_bohrium_crystals', - 'fetch_openlam_structures', - 'web-search', - ], - 'summary_prompt': OptimadeAgentSummaryPrompt, - 'self_check': True, - }, - 'fetch_structures_with_spg': { - 'belonging_agent': OPTIMADE_DATABASE_AGENT_NAME, + 'fetch_structures_from_db': { + 'belonging_agent': STRUCTURE_SEARCH_AGENT_NAME, 'scene': [SceneEnum.DATABASE_SEARCH], - 'description': OptimadeSpgToolDescription, - 'args_setting': f"{OptimadeSpgArgsSetting}", + 'description': StructureSearchAgentToolDescription, + 'args_setting': f"{StructureSearchAgentArgsSetting}", 'alternative': [ - 'fetch_bohrium_crystals', - 'fetch_structures_with_filter', 'web-search', ], - 'summary_prompt': OptimadeAgentSummaryPrompt, - 'self_check': True, - }, - 'fetch_structures_with_bandgap': { - 'belonging_agent': OPTIMADE_DATABASE_AGENT_NAME, - 'scene': [SceneEnum.DATABASE_SEARCH], - 'description': OptimadeBandgapToolDescription, - 'args_setting': f"{OptimadeBandgapArgsSetting}", - 'alternative': [ - 'fetch_bohrium_crystals', - 'fetch_structures_with_filter', - 'web-search', - ], - 'summary_prompt': OptimadeAgentSummaryPrompt, - 'self_check': True, - }, - 'fetch_bohrium_crystals': { - 'belonging_agent': BOHRIUMPUBLIC_DATABASE_AGENT_NAME, - 'scene': [SceneEnum.DATABASE_SEARCH], - 'description': BohriumPublicAgentToolDescription, - 'args_setting': f"{BohriumPublicAgentArgsSetting}", - 'alternative': [ - 'fetch_structures_with_filter', - 'web-search', - 'fetch_openlam_structures', - ], - 'summary_prompt': BohriumPublicAgentSummaryPrompt, - 'self_check': True, - }, - 'fetch_openlam_structures': { - 'belonging_agent': OPENLAM_DATABASE_AGENT_NAME, - 'scene': [SceneEnum.DATABASE_SEARCH], - 'description': OpenlamAgentToolDescription, - 'args_setting': f"{OpenlamAgentArgsSetting}", - 'alternative': [ - 'fetch_structures_with_filter', - 'web-search', - 'fetch_openlam_structures', - ], - 'summary_prompt': OpenlamAgentSummaryPrompt, - 'self_check': True, - }, - 'fetch_mofs_sql': { - 'belonging_agent': MOFDB_DATABASE_AGENT_NAME, - 'scene': [SceneEnum.DATABASE_SEARCH], - 'description': MofdbAgentToolDescription, - 'args_setting': f"{MofdbAgentArgsSetting}", - 'alternative': ['web-search'], - 'summary_prompt': MofdbAgentSummaryPrompt, + 'summary_prompt': StructureSearchAgentSummaryPrompt, 'self_check': True, }, 'calculate_reaction_profile': { From c995965ff3b876711f4377a85179479e085b677a Mon Sep 17 00:00:00 2001 From: styxhuang Date: Sat, 7 Feb 2026 09:40:09 +0800 Subject: [PATCH 2/6] fix: pre-commit --- agents/matmaster_agent/sub_agents/mapping.py | 20 +++++++------------- agents/matmaster_agent/sub_agents/tools.py | 3 --- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/agents/matmaster_agent/sub_agents/mapping.py b/agents/matmaster_agent/sub_agents/mapping.py index 3c876d2e..37f63e5f 100644 --- a/agents/matmaster_agent/sub_agents/mapping.py +++ b/agents/matmaster_agent/sub_agents/mapping.py @@ -110,43 +110,37 @@ lammps_toolset, ) from agents.matmaster_agent.sub_agents.LAMMPS_agent.constant import LAMMPS_AGENT_NAME - -from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.agent import ( - StructureSearchAgentBase, - structure_search_toolset, -) -from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.constant import ( - STRUCTURE_SEARCH_AGENT_NAME, -) - from agents.matmaster_agent.sub_agents.MrDice_agent.bohriumpublic_agent.agent import ( Bohriumpublic_AgentBase, - bohriumpublic_toolset, ) from agents.matmaster_agent.sub_agents.MrDice_agent.bohriumpublic_agent.constant import ( BOHRIUMPUBLIC_DATABASE_AGENT_NAME, ) from agents.matmaster_agent.sub_agents.MrDice_agent.mofdb_agent.agent import ( Mofdb_AgentBase, - mofdb_toolset, ) from agents.matmaster_agent.sub_agents.MrDice_agent.mofdb_agent.constant import ( MOFDB_DATABASE_AGENT_NAME, ) from agents.matmaster_agent.sub_agents.MrDice_agent.openlam_agent.agent import ( Openlam_AgentBase, - openlam_toolset, ) from agents.matmaster_agent.sub_agents.MrDice_agent.openlam_agent.constant import ( OPENLAM_DATABASE_AGENT_NAME, ) from agents.matmaster_agent.sub_agents.MrDice_agent.optimade_agent.agent import ( Optimade_AgentBase, - optimade_toolset, ) from agents.matmaster_agent.sub_agents.MrDice_agent.optimade_agent.constant import ( OPTIMADE_DATABASE_AGENT_NAME, ) +from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.agent import ( + StructureSearchAgentBase, + structure_search_toolset, +) +from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.constant import ( + STRUCTURE_SEARCH_AGENT_NAME, +) from agents.matmaster_agent.sub_agents.NMR_agent.agent import ( NMRAgent, nmr_toolset, diff --git a/agents/matmaster_agent/sub_agents/tools.py b/agents/matmaster_agent/sub_agents/tools.py index e5ff7619..ca01e418 100644 --- a/agents/matmaster_agent/sub_agents/tools.py +++ b/agents/matmaster_agent/sub_agents/tools.py @@ -53,17 +53,14 @@ HEAKbAgentToolDescription, ) from agents.matmaster_agent.sub_agents.LAMMPS_agent.constant import LAMMPS_AGENT_NAME - from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.constant import ( STRUCTURE_SEARCH_AGENT_NAME, - STRUCTURE_SEARCH_URL ) from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.prompt import ( StructureSearchAgentArgsSetting, StructureSearchAgentSummaryPrompt, StructureSearchAgentToolDescription, ) - from agents.matmaster_agent.sub_agents.NMR_agent.constant import ( NMR_AGENT_NAME, ) From 9068160a7f5535291b628c957fab0e5aaff61042 Mon Sep 17 00:00:00 2001 From: styxhuang Date: Sun, 8 Feb 2026 08:01:27 +0800 Subject: [PATCH 3/6] feat: fix --- agents/matmaster_agent/sub_agents/mapping.py | 14 +++++------ .../structure_search_agent/__init__.py | 0 .../structure_search_agent/agent.py | 15 ++++-------- .../structure_search_agent/constant.py | 2 +- .../structure_search_agent/prompt.py | 23 ++++++++----------- agents/matmaster_agent/sub_agents/tools.py | 16 ++++++------- 6 files changed, 30 insertions(+), 40 deletions(-) rename agents/matmaster_agent/sub_agents/{MrDice_agent => }/structure_search_agent/__init__.py (100%) rename agents/matmaster_agent/sub_agents/{MrDice_agent => }/structure_search_agent/agent.py (71%) rename agents/matmaster_agent/sub_agents/{MrDice_agent => }/structure_search_agent/constant.py (80%) rename agents/matmaster_agent/sub_agents/{MrDice_agent => }/structure_search_agent/prompt.py (94%) diff --git a/agents/matmaster_agent/sub_agents/mapping.py b/agents/matmaster_agent/sub_agents/mapping.py index 37f63e5f..14d5095d 100644 --- a/agents/matmaster_agent/sub_agents/mapping.py +++ b/agents/matmaster_agent/sub_agents/mapping.py @@ -134,13 +134,6 @@ from agents.matmaster_agent.sub_agents.MrDice_agent.optimade_agent.constant import ( OPTIMADE_DATABASE_AGENT_NAME, ) -from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.agent import ( - StructureSearchAgentBase, - structure_search_toolset, -) -from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.constant import ( - STRUCTURE_SEARCH_AGENT_NAME, -) from agents.matmaster_agent.sub_agents.NMR_agent.agent import ( NMRAgent, nmr_toolset, @@ -222,6 +215,13 @@ from agents.matmaster_agent.sub_agents.structure_generate_agent.constant import ( StructureGenerateAgentName, ) +from agents.matmaster_agent.sub_agents.structure_search_agent.agent import ( + StructureSearchAgentBase, + structure_search_toolset, +) +from agents.matmaster_agent.sub_agents.structure_search_agent.constant import ( + STRUCTURE_SEARCH_AGENT_NAME, +) from agents.matmaster_agent.sub_agents.superconductor_agent.agent import ( SuperconductorAgent, superconductor_toolset, diff --git a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/__init__.py b/agents/matmaster_agent/sub_agents/structure_search_agent/__init__.py similarity index 100% rename from agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/__init__.py rename to agents/matmaster_agent/sub_agents/structure_search_agent/__init__.py diff --git a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/agent.py b/agents/matmaster_agent/sub_agents/structure_search_agent/agent.py similarity index 71% rename from agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/agent.py rename to agents/matmaster_agent/sub_agents/structure_search_agent/agent.py index 3d39cb0e..0d98ae55 100644 --- a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/agent.py +++ b/agents/matmaster_agent/sub_agents/structure_search_agent/agent.py @@ -1,4 +1,3 @@ -from dotenv import load_dotenv from dp.agent.adapter.adk import CalculationMCPToolset from google.adk.agents import BaseAgent from google.adk.tools.mcp_tool.mcp_session_manager import SseServerParams @@ -8,16 +7,11 @@ BaseSyncAgentWithToolValidator, ) from agents.matmaster_agent.sub_agents.MrDice_agent.constant import MrDice_Agent_Name -from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.constant import ( +from agents.matmaster_agent.sub_agents.structure_search_agent.constant import ( + STRUCTURE_SEARCH_AGENT_NAME, STRUCTURE_SEARCH_URL, ) -from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.prompt import ( - StructureSearchAgentName, -) - -load_dotenv() -# Initialize MCP tools and agent structure_search_toolset = CalculationMCPToolset( connection_params=SseServerParams(url=STRUCTURE_SEARCH_URL), storage=BohriumStorge, @@ -26,11 +20,10 @@ class StructureSearchAgentBase(BaseSyncAgentWithToolValidator): - def __init__(self, llm_config, name_suffix=''): + def __init__(self, llm_config): super().__init__( - # model=llm_config.deepseek_chat, model=llm_config.default_litellm_model, - name=StructureSearchAgentName + name_suffix, + name=STRUCTURE_SEARCH_AGENT_NAME, description='', instruction='', tools=[structure_search_toolset], diff --git a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/constant.py b/agents/matmaster_agent/sub_agents/structure_search_agent/constant.py similarity index 80% rename from agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/constant.py rename to agents/matmaster_agent/sub_agents/structure_search_agent/constant.py index 4baea51e..1085c135 100644 --- a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/constant.py +++ b/agents/matmaster_agent/sub_agents/structure_search_agent/constant.py @@ -1,6 +1,6 @@ from agents.matmaster_agent.constant import CURRENT_ENV -STRUCTURE_SEARCH_AGENT_NAME = 'structure_search_agent' +STRUCTURE_SEARCH_AGENT_NAME = 'fetch_structures_from_db' if CURRENT_ENV in ['test', 'uat']: STRUCTURE_SEARCH_URL = 'http://chvz1424099.bohrium.tech:50001/sse' diff --git a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/prompt.py b/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py similarity index 94% rename from agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/prompt.py rename to agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py index 2896d944..478399cf 100644 --- a/agents/matmaster_agent/sub_agents/MrDice_agent/structure_search_agent/prompt.py +++ b/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py @@ -1,5 +1,3 @@ -StructureSearchAgentName = 'structure_search_agent' - StructureSearchAgentToolDescription = ( 'What it does: Retrieve structures across multiple sources (BohriumPublic / OpenLAM / OPTIMADE providers) and run advanced SQL queries on MOFdb.\n' 'When to use: Any "find crystal structures" request, including formula/elements/space group/band gap filters, time/energy filters (OpenLAM), cross-provider searches (OPTIMADE), or MOF-specific analytics (MOFdb SQL).\n' @@ -18,28 +16,24 @@ You have access to multiple retrieval tools. Choose ONE based on the user intent: ### A) BohriumPublic (fast structured filters) -Use `fetch_bohrium_crystals` when the user asks for: +when the user asks for: - formula / elements / space group / atom count / predicted formation energy / band gap - and they do NOT require cross-provider search or complex boolean logic ### B) OpenLAM (energy / time filters) -Use `fetch_openlam_structures` when the user asks for: +when the user asks for: - OpenLAM specifically, OR upload/submission time filters, OR OpenLAM energy range filters Limits: OpenLAM does NOT support space group, band gap, or "elements list" filters. ### C) OPTIMADE (cross-provider, flexible composition filters) -Use OPTIMADE tools when the user needs: +when the user needs: - cross-provider search (e.g., "search in mp/cod/oqmd..."), OR - flexible logical composition constraints, OR - structure-type family queries (anonymous formula like AB2C4), OR - 2D/1D/0D constraints (nperiodic_dimensions) -Pick the specific tool: -- `fetch_structures_with_spg` if the user specifies a space group number -- `fetch_structures_with_bandgap` if the user specifies a band-gap range -- `fetch_structures_with_filter` otherwise ### D) MOFdb (MOF-only, complex analytics) -Use `fetch_mofs_sql` when the user asks for: +when the user asks for: - MOF-specific properties (surface area, pore metrics, adsorption/isotherms, heats), OR - advanced analysis requiring multi-table joins / ranking / statistics @@ -177,9 +171,12 @@ (1) Formula (`attributes.chemical_formula_reduced`) (2) Elements (infer from formula) (3) Atom count (if available; else **Not Provided**) -(4) Download link (CIF or JSON file) -(5) Provider (infer from provider URL) -(6) ID (`id`) +(4) Space group (`Symbol(Number)` if possible; else **Not Provided**) +(5) Energy / Formation energy (if available; else **Not Provided**) +(6) Band gap (if available; else **Not Provided**) +(7) Download link (CIF or JSON file) +(8) Provider (infer from provider URL) +(9) ID (`id`) Missing values must be exactly **Not Provided**. If `n_found = 0`, do not generate an empty table. **If the tool response indicates `by_source` = "openlam"** (OpenLAM results): diff --git a/agents/matmaster_agent/sub_agents/tools.py b/agents/matmaster_agent/sub_agents/tools.py index ca01e418..da652576 100644 --- a/agents/matmaster_agent/sub_agents/tools.py +++ b/agents/matmaster_agent/sub_agents/tools.py @@ -53,14 +53,6 @@ HEAKbAgentToolDescription, ) from agents.matmaster_agent.sub_agents.LAMMPS_agent.constant import LAMMPS_AGENT_NAME -from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.constant import ( - STRUCTURE_SEARCH_AGENT_NAME, -) -from agents.matmaster_agent.sub_agents.MrDice_agent.structure_search_agent.prompt import ( - StructureSearchAgentArgsSetting, - StructureSearchAgentSummaryPrompt, - StructureSearchAgentToolDescription, -) from agents.matmaster_agent.sub_agents.NMR_agent.constant import ( NMR_AGENT_NAME, ) @@ -119,6 +111,14 @@ from agents.matmaster_agent.sub_agents.structure_generate_agent.constant import ( StructureGenerateAgentName, ) +from agents.matmaster_agent.sub_agents.structure_search_agent.constant import ( + STRUCTURE_SEARCH_AGENT_NAME, +) +from agents.matmaster_agent.sub_agents.structure_search_agent.prompt import ( + StructureSearchAgentArgsSetting, + StructureSearchAgentSummaryPrompt, + StructureSearchAgentToolDescription, +) from agents.matmaster_agent.sub_agents.superconductor_agent.constant import ( SuperconductorAgentName, ) From 3b93c649e33b28ef192a677fa3e9146b0be7076e Mon Sep 17 00:00:00 2001 From: styxhuang Date: Sun, 8 Feb 2026 08:09:57 +0800 Subject: [PATCH 4/6] fix: update --- .../structure_search_agent/prompt.py | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py b/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py index 478399cf..9f4059d3 100644 --- a/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py +++ b/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py @@ -68,34 +68,34 @@ ## PARAMETER EXAMPLES 1) 用户:检索 SrTiO₃ 的晶体结构,并以JSON格式返回 - → Tool: fetch_bohrium_crystals + → Tool: fetch_structures_from_db formula: "SrTiO3" match_mode: 1 output_formats: ["json"] 2) 用户:在Materials Project中检索并返回3个带隙大于2 eV的氧化物结构 - → Tool: fetch_bohrium_crystals + → Tool: fetch_structures_from_db elements: ["O"] match_mode: 0 band_gap_range: ["2","100"] n_results: 3 3) 用户:找出空间群编号 14,原子数 50–100 的晶体 - → Tool: fetch_bohrium_crystals + → Tool: fetch_structures_from_db spacegroup_number: 14 atom_count_range: ["50","100"] 4) 用户:检索 FeNi 合金的结构 - → Tool: fetch_bohrium_crystals + → Tool: fetch_structures_from_db elements: ["Fe","Ni"] # 合金只含有Fe和Ni元素,不能含有其他元素 match_mode: 1 # 合金需要精确匹配 5) 用户:找所有化学式中包含 SiO3 的材料 - → Tool: fetch_bohrium_crystals + → Tool: fetch_structures_from_db formula: "SiO3" match_mode: 0 -## 2) OPENLAM PARAMETERS (fetch_openlam_structures) +## 2) OPENLAM PARAMETERS (fetch_structures_from_db) ### FILTER OPTIONS - **Formula**: chemical formula string (e.g., `"Fe2O3"`) - **Energy**: `min_energy` and/or `max_energy` in eV @@ -105,28 +105,28 @@ ### EXAMPLES 1) 用户:查找 Fe2O3 的 5 个晶体结构,导出为 CIF - → Tool: fetch_openlam_structures + → Tool: fetch_structures_from_db formula: "Fe2O3" n_results: 5 output_formats: ["cif"] 2) 用户:查找能量在 -10 到 20 eV 之间,2024 年后上传的材料 - → Tool: fetch_openlam_structures + → Tool: fetch_structures_from_db min_energy: -10.0 max_energy: 20.0 min_submission_time: "2024-01-01T00:00:00Z" -## 3) MOFDB PARAMETERS (fetch_mofs_sql) +## 3) MOFDB PARAMETERS (fetch_structures_from_db) ### INPUT - **sql**: SQL query string (use CTEs, window functions, joins as needed) - **n_results**: controls SQL LIMIT (when applicable) and returned structures ### EXAMPLE 用户:统计各数据库的 MOF 数量 -→ Tool: fetch_mofs_sql +→ Tool: fetch_structures_from_db sql: "SELECT database, COUNT(*) AS count FROM mofs GROUP BY database ORDER BY count DESC" -## 4) OPTIMADE PARAMETERS (fetch_structures_with_filter / _with_spg / _with_bandgap) +## 4) OPTIMADE PARAMETERS (fetch_structures_from_db) ### MINIMUM SAFE OPTIMADE SYNTAX RULES (DO NOT VIOLATE) - Allowed operators ONLY: =, !=, <, <=, >, >=, AND, OR, NOT, HAS, HAS ALL, HAS ANY, IS KNOWN, IS UNKNOWN - All strings MUST be in double quotes: "Fe", "SiO2" @@ -134,19 +134,19 @@ - To express "only these elements": use `elements HAS ALL ... AND nelements = N` ### TOOL CHOICE -- If user gives space group number → `fetch_structures_with_spg(base_filter, spg_number, ...)` -- If user gives band gap range → `fetch_structures_with_bandgap(base_filter, min_bg, max_bg, ...)` -- Else → `fetch_structures_with_filter(filter, ...)` +- If user gives space group number → `fetch_structures_from_db(base_filter, spg_number, ...)` +- If user gives band gap range → `fetch_structures_from_db(base_filter, min_bg, max_bg, ...)` +- Else → `fetch_structures_from_db(filter, ...)` ### EXAMPLES 1) 用户:找空间群 225 的 MgO(rocksalt),返回 CIF - → Tool: fetch_structures_with_spg + → Tool: fetch_structures_from_db base_filter: chemical_formula_reduced="MgO" spg_number: 225 as_format: "cif" 2) 用户:找含 Al 且带隙 1–2 eV 的材料,返回 JSON - → Tool: fetch_structures_with_bandgap + → Tool: fetch_structures_from_db base_filter: elements HAS "Al" min_bg: 1.0 max_bg: 2.0 @@ -187,12 +187,9 @@ (1) Formula (`formula`) (2) Elements (deduced from `formula`) (3) Atom count → **Not Provided** - (4) Space group → **Not Provided** - (5) Energy / Formation energy (`energy` if available; else **Not Provided**) - (6) Band gap → **Not Provided** - (7) Download link (CIF/JSON, based on requested output) - (8) Source database → always `"OpenLAM"` - (9) ID (`id`) + (4) Download link (CIF/JSON, based on requested output) + (5) Source database → always `"OpenLAM"` + (6) ID (`id`) - Fill missing values with exactly **Not Provided** - Number of rows **must exactly equal** `n_found` 3. 📦 The `output_dir` path returned by the tool (for download/archive) From 8875757962d1f4b730d80b5b594f35a69aec1569 Mon Sep 17 00:00:00 2001 From: styxhuang Date: Sun, 8 Feb 2026 08:17:36 +0800 Subject: [PATCH 5/6] fix: add specific provider for optimade --- .../matmaster_agent/sub_agents/structure_search_agent/prompt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py b/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py index 9f4059d3..7094dde1 100644 --- a/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py +++ b/agents/matmaster_agent/sub_agents/structure_search_agent/prompt.py @@ -27,6 +27,7 @@ ### C) OPTIMADE (cross-provider, flexible composition filters) when the user needs: +- Raw filter: alexandria, cmr, cod, mcloud, mcloudarchive, mp, mpdd, mpds, nmd, odbx, omdb, oqmd, tcod, twodmatpedia - cross-provider search (e.g., "search in mp/cod/oqmd..."), OR - flexible logical composition constraints, OR - structure-type family queries (anonymous formula like AB2C4), OR From ca793a62223e5d759174bf183f57c35bd0d26fed Mon Sep 17 00:00:00 2001 From: styxhuang Date: Sun, 8 Feb 2026 08:52:23 +0800 Subject: [PATCH 6/6] fix: agent name --- .../sub_agents/structure_search_agent/constant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agents/matmaster_agent/sub_agents/structure_search_agent/constant.py b/agents/matmaster_agent/sub_agents/structure_search_agent/constant.py index 1085c135..4baea51e 100644 --- a/agents/matmaster_agent/sub_agents/structure_search_agent/constant.py +++ b/agents/matmaster_agent/sub_agents/structure_search_agent/constant.py @@ -1,6 +1,6 @@ from agents.matmaster_agent.constant import CURRENT_ENV -STRUCTURE_SEARCH_AGENT_NAME = 'fetch_structures_from_db' +STRUCTURE_SEARCH_AGENT_NAME = 'structure_search_agent' if CURRENT_ENV in ['test', 'uat']: STRUCTURE_SEARCH_URL = 'http://chvz1424099.bohrium.tech:50001/sse'