11from __future__ import annotations
22
3+ import importlib .util
34import os
45from abc import abstractmethod
56from pathlib import Path
89from langgraph .checkpoint .sqlite .aio import AsyncSqliteSaver , aiosqlite
910from langgraph .graph .state import CompiledStateGraph
1011
12+ import tomllib as tomli
13+
1114from src import config as sys_config
1215from src .agents .common .context import BaseContext
1316from src .utils import logger
@@ -27,6 +30,7 @@ def __init__(self, **kwargs):
2730 self .context_schema = BaseContext
2831 self .workdir = Path (sys_config .save_dir ) / "agents" / self .module_name
2932 self .workdir .mkdir (parents = True , exist_ok = True )
33+ self ._metadata_cache = None # Cache for metadata to avoid repeated file reads
3034
3135 @property
3236 def module_name (self ) -> str :
@@ -39,10 +43,15 @@ def id(self) -> str:
3943 return self .__class__ .__name__
4044
4145 async def get_info (self ):
46+ # Load metadata from file
47+ metadata = self .load_metadata ()
48+
49+ # Merge metadata with class attributes, metadata takes precedence
4250 return {
4351 "id" : self .id ,
44- "name" : self .name if hasattr (self , "name" ) else "Unknown" ,
45- "description" : self .description if hasattr (self , "description" ) else "Unknown" ,
52+ "name" : metadata .get ("name" , getattr (self , "name" , "Unknown" )),
53+ "description" : metadata .get ("description" , getattr (self , "description" , "Unknown" )),
54+ "examples" : metadata .get ("examples" , []),
4655 "configurable_items" : self .context_schema .get_configurable_items (),
4756 "has_checkpointer" : await self .check_checkpointer (),
4857 }
@@ -138,3 +147,43 @@ async def get_async_conn(self) -> aiosqlite.Connection:
138147 async def get_aio_memory (self ) -> AsyncSqliteSaver :
139148 """获取异步存储实例"""
140149 return AsyncSqliteSaver (await self .get_async_conn ())
150+
151+
152+ def load_metadata (self ) -> dict :
153+ """Load metadata from metadata.toml file in the agent's source directory."""
154+ if self ._metadata_cache is not None :
155+ return self ._metadata_cache
156+
157+ # Try to find metadata.toml in the agent's source directory
158+ try :
159+ # Get the agent's source file directory
160+ agent_module = self .__class__ .__module__
161+
162+ # Use importlib to get the module's file path
163+ spec = importlib .util .find_spec (agent_module )
164+ if spec and spec .origin :
165+ agent_file = Path (spec .origin )
166+ agent_dir = agent_file .parent
167+ else :
168+ # Fallback: construct path from module name
169+ module_path = agent_module .replace ("." , "/" )
170+ agent_file = Path (f"src/{ module_path } .py" )
171+ agent_dir = agent_file .parent
172+
173+ metadata_file = agent_dir / "metadata.toml"
174+
175+ if metadata_file .exists ():
176+ with open (metadata_file , "rb" ) as f :
177+ metadata = tomli .load (f )
178+ self ._metadata_cache = metadata
179+ logger .debug (f"Loaded metadata from { metadata_file } " )
180+ return metadata
181+ else :
182+ logger .debug (f"No metadata.toml found for { self .module_name } at { metadata_file } " )
183+ self ._metadata_cache = {}
184+ return {}
185+
186+ except Exception as e :
187+ logger .error (f"Error loading metadata for { self .module_name } : { e } " )
188+ self ._metadata_cache = {}
189+ return {}
0 commit comments