@@ -61,17 +61,23 @@ class FedEntry:
6161 definition : str
6262 synonyms : list [str ] = field (default_factory = list )
6363 inferred : bool = False
64+ kind : str = "" # metric | table | rule | dimension
65+ applies_to : str = "" # 관련 테이블/컬럼 (예: users, orders.amount)
66+ tags : list [str ] = field (default_factory = list )
6467
6568 def __post_init__ (self ) -> None :
6669 if not isinstance (self .synonyms , list ):
6770 self .synonyms = _parse_synonyms (self .synonyms )
71+ if not isinstance (self .tags , list ):
72+ self .tags = [t .strip () for t in str (self .tags ).split ("," ) if t .strip ()]
6873
6974 def to_json (self ) -> str :
7075 return json .dumps (
7176 {
7277 "term" : self .term , "layer" : self .layer , "entity" : self .entity ,
7378 "definition" : self .definition , "synonyms" : self .synonyms ,
74- "inferred" : self .inferred ,
79+ "inferred" : self .inferred , "kind" : self .kind ,
80+ "applies_to" : self .applies_to , "tags" : self .tags ,
7581 },
7682 ensure_ascii = False ,
7783 )
@@ -82,7 +88,8 @@ def from_json(raw: str) -> "FedEntry":
8288 return FedEntry (
8389 term = d ["term" ], layer = d ["layer" ], entity = d .get ("entity" , "" ),
8490 definition = d ["definition" ], synonyms = d .get ("synonyms" , []),
85- inferred = d .get ("inferred" , False ),
91+ inferred = d .get ("inferred" , False ), kind = d .get ("kind" , "" ),
92+ applies_to = d .get ("applies_to" , "" ), tags = d .get ("tags" , []),
8693 )
8794
8895
@@ -117,6 +124,19 @@ def spec(self) -> ToolSpec:
117124 "type" : "string" ,
118125 "description" : "쉼표 구분 동의어 (예: active_user,활성화고객)" ,
119126 },
127+ "kind" : {
128+ "type" : "string" ,
129+ "enum" : ["metric" , "table" , "rule" , "dimension" ],
130+ "description" : "용어 종류. metric=지표, table=테이블/엔티티, rule=비즈니스 규칙, dimension=분류 기준." ,
131+ },
132+ "applies_to" : {
133+ "type" : "string" ,
134+ "description" : "관련 테이블 또는 컬럼 (예: users, orders.amount)." ,
135+ },
136+ "tags" : {
137+ "type" : "string" ,
138+ "description" : "쉼표 구분 태그 (예: growth,retention)." ,
139+ },
120140 "inferred" : {
121141 "type" : "boolean" ,
122142 "description" : "true 시 LLM 추론 임시 정의로 표시. 사용자 확인 후 재등록 권장." ,
@@ -215,9 +235,13 @@ async def run(self, args: dict[str, Any], ctx: "HarnessContext") -> ToolResult:
215235
216236 synonyms = _parse_synonyms (args .get ("synonyms" ))
217237 inferred = bool (args .get ("inferred" , False ))
238+ kind = str (args .get ("kind" , "" )).strip ().lower ()
239+ applies_to = str (args .get ("applies_to" , "" )).strip ()
240+ tags = [t .strip () for t in str (args .get ("tags" , "" )).split ("," ) if t .strip ()]
218241
219242 entry = FedEntry (term = term , layer = layer , entity = entity ,
220- definition = definition , synonyms = synonyms , inferred = inferred )
243+ definition = definition , synonyms = synonyms , inferred = inferred ,
244+ kind = kind , applies_to = applies_to , tags = tags )
221245 ctx .store .kv_set (scope , key , entry .to_json ())
222246 if ctx .audit is not None :
223247 await ctx .audit .record (
@@ -360,7 +384,8 @@ def _fmt_entry(e: FedEntry, tag: str) -> str:
360384 syns = ", " .join (e .synonyms )
361385 syn_str = f" (= { syns } )" if syns else ""
362386 inferred_badge = " 🤖" if e .inferred else ""
363- return f"- **{ e .term } ** [{ tag } ]{ syn_str } { inferred_badge } : { e .definition } "
387+ kind_badge = f" `{ e .kind } `" if e .kind else ""
388+ return f"- **{ e .term } **{ kind_badge } [{ tag } ]{ syn_str } { inferred_badge } : { e .definition } "
364389
365390
366391def _resolve_term (entries : list [FedEntry ], channel_id : str , user_id : str ) -> str :
0 commit comments