@@ -71,33 +71,20 @@ class AITool:
7171def _autoDiscover () -> dict [str , tuple [str , str ]]:
7272 """dartlab.__all__ + Company 공개 method 자동 순회 + 블랙리스트.
7373
74- 우선순위: Company-bound (_xxxImpl 또는 직접 method) > module-level.
74+ 우선순위: **module-level (시장 전체) > Company-bound (개별 종목)**.
75+ 이유: AI tool 은 기본이 "시장 전체 / 종목 비의존" 의미. 같은 이름이 둘 다 있으면
76+ module 이 더 범용. 예: `search` = dartlab.search (시장 공시) vs Company.search
77+ (이 회사 공시) — AI 는 전자가 기본 유용.
7578 """
7679 import dartlab
7780 from dartlab .providers .dart .company import Company as _C
7881
7982 tools : dict [str , tuple [str , str ]] = {}
8083
81- # 1. Company-bound — dual-access _xxxImpl 또는 직접 method
82- for attr in dir (_C ):
83- if attr .startswith ("_" ) or attr in _BLACKLIST :
84- continue
85- # dual-access property (_xxxImpl 존재) 우선
86- if getattr (_C , f"_{ attr } Impl" , None ) is not None :
87- tools [attr ] = ("company" , attr )
88- continue
89- # 직접 method (gather, quant 등)
90- obj = getattr (_C , attr , None )
91- if callable (obj ) and (inspect .isfunction (obj ) or inspect .ismethod (obj )):
92- # Company 인스턴스에서만 의미 있는 method 만 (수업 attribute, dunder 제외)
93- if not isinstance (obj , type ):
94- tools [attr ] = ("company" , attr )
95-
96- # 2. Module-level — Company 에 없는 것만 (scan/macro/search 등)
97- # 주의: dartlab.scan/macro/quant 는 _CallableModule (ismodule=True) — 명시적 허용.
84+ # 1. Module-level 먼저
9885 _MODULE_WHITELIST = {"scan" , "macro" , "quant" , "gather" , "industry" , "topdown" }
9986 for name in getattr (dartlab , "__all__" , []):
100- if name in _BLACKLIST or name .startswith ("_" ) or name in tools :
87+ if name in _BLACKLIST or name .startswith ("_" ):
10188 continue
10289 obj = getattr (dartlab , name , None )
10390 if obj is None or inspect .isclass (obj ):
@@ -108,6 +95,20 @@ def _autoDiscover() -> dict[str, tuple[str, str]]:
10895 continue
10996 tools [name ] = ("module" , name )
11097
98+ # 2. Company-bound — module 에 없는 것만 (analysis/credit/review/show/... 은 여기서)
99+ for attr in dir (_C ):
100+ if attr .startswith ("_" ) or attr in _BLACKLIST or attr in tools :
101+ continue
102+ # dual-access property (_xxxImpl 존재) 우선
103+ if getattr (_C , f"_{ attr } Impl" , None ) is not None :
104+ tools [attr ] = ("company" , attr )
105+ continue
106+ # 직접 method (gather, quant 등)
107+ obj = getattr (_C , attr , None )
108+ if callable (obj ) and (inspect .isfunction (obj ) or inspect .ismethod (obj )):
109+ if not isinstance (obj , type ):
110+ tools [attr ] = ("company" , attr )
111+
111112 # 3. searchName → searchCompany (AI 친화적 이름)
112113 if "searchName" in tools :
113114 tools ["searchCompany" ] = tools .pop ("searchName" )
@@ -445,16 +446,27 @@ def _paramType(param: inspect.Parameter) -> str:
445446# ── Module tool post-processing ───────────────────────────
446447
447448
448- _MODULE_CORE : dict [str , set [str ]] = {
449- "scan" : {"axis" , "target" },
450- "macro" : {"axis" , "target" , "market" },
451- "search" : {"query" , "corp" , "start" , "end" , "topK" , "scope" },
452- "searchName" : {"keyword" },
453- }
449+ def _splitKwargs (target : str , kwargs : dict ) -> tuple [dict , dict ]:
450+ """함수 시그니처 자동 분석으로 허용 파라미터 / 추가 파라미터 분리.
454451
452+ 수동 whitelist 금지 원칙 (CAPABILITIES 자동). pastInsight/sectorInsights
453+ 포함 모든 module-level tool 에 일관 적용.
454+ """
455+ import dartlab
455456
456- def _splitKwargs (target : str , kwargs : dict ) -> tuple [dict , dict ]:
457- core_keys = _MODULE_CORE .get (target , set ())
457+ fn = _resolveCallable ("module" , target )
458+ if fn is None :
459+ return {}, kwargs
460+ try :
461+ sig = inspect .signature (fn )
462+ core_keys = {
463+ n
464+ for n , p in sig .parameters .items ()
465+ if n not in ("self" , "cls" )
466+ and p .kind not in (inspect .Parameter .VAR_POSITIONAL , inspect .Parameter .VAR_KEYWORD )
467+ }
468+ except (ValueError , TypeError ):
469+ core_keys = set ()
458470 core = {k : v for k , v in kwargs .items () if k in core_keys and v is not None }
459471 post = {k : v for k , v in kwargs .items () if k not in core_keys and v is not None }
460472 return core , post
0 commit comments