Skip to content

Commit 2f2299e

Browse files
committed
refactor(ai/tools): Phase 7C — _builtin.py 제거 + Company.gather target 노출
자동 등록 경로(`_autoDiscover`) 일관성 회복 — 수동 AITool 정의 제거. - ai/tools/_builtin.py 제거 (수동 AITool 생성) - ai/insights.py 신설 — pastInsight / sectorInsights 모듈 함수 - dartlab/__init__.py 의 __all__ 에 노출 → _autoDiscover 가 자동 등록 - providers/dart/company.py::Company.gather 시그니처에 target 명시 (이전엔 **kwargs 에 숨어 tool schema 누락 → AI 가 매크로 뉴스 검색어 못 넣음) - generateSpec.py 재실행 → CAPABILITIES + tool schema 자동 갱신 회귀 116/116 통과. tool 자동 등록 32개 유지. 남은 짧은 enum (show.topic/freq, search.scope, review.type) 자동화는 효용 대비 회귀 위험으로 후속 patch 보류.
1 parent 200f621 commit 2f2299e

8 files changed

Lines changed: 112 additions & 119 deletions

File tree

.claude/skills/dartlab/reference.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
---
77

8-
## Python API (29개)
8+
## Python API (31개)
99

1010
`import dartlab` 후 사용 가능한 공개 API.
1111

@@ -36,6 +36,8 @@
3636
| `codeToName` | function | 종목코드 → 회사명. |
3737
| `nameToCode` | function | 회사명 → 종목코드. 정확히 일치하는 첫 번째 결과. |
3838
| `searchName` | function | 종목명/코드로 종목 찾기 (KR + US). |
39+
| `pastInsight` | function | 특정 회사의 과거 분석 서사 조회. |
40+
| `sectorInsights` | function | 동종 업계 과거 분석 서사 목록 (교차 학습). |
3941
| `Review` | class | 분석 리뷰 — 14축 전략분석 결과를 구조화 보고서로 렌더링. |
4042
| `SelectResult` | class | select() 반환 객체 — DataFrame 위임 + 체이닝. |
4143
| `ChartResult` | class | chart() 반환 객체 — 시각화 + 렌더링. |

CAPABILITIES.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
---
88

9-
## Python API (29개)
9+
## Python API (31개)
1010

1111
`import dartlab` 후 사용 가능한 공개 API.
1212

@@ -37,6 +37,8 @@
3737
| `codeToName` | function | 종목코드 → 회사명. |
3838
| `nameToCode` | function | 회사명 → 종목코드. 정확히 일치하는 첫 번째 결과. |
3939
| `searchName` | function | 종목명/코드로 종목 찾기 (KR + US). |
40+
| `pastInsight` | function | 특정 회사의 과거 분석 서사 조회. |
41+
| `sectorInsights` | function | 동종 업계 과거 분석 서사 목록 (교차 학습). |
4042
| `Review` | class | 분석 리뷰 — 14축 전략분석 결과를 구조화 보고서로 렌더링. |
4143
| `SelectResult` | class | select() 반환 객체 — DataFrame 위임 + 체이닝. |
4244
| `ChartResult` | class | chart() 반환 객체 — 시각화 + 렌더링. |

src/dartlab/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,8 @@ def _macroFactory():
868868
sys.modules[__name__].credit = _credit_callable
869869

870870

871+
from dartlab.ai.insights import pastInsight, sectorInsights # noqa: E402
872+
871873
__all__ = [
872874
"Company",
873875
"Fred",
@@ -894,6 +896,8 @@ def _macroFactory():
894896
"codeToName",
895897
"nameToCode",
896898
"searchName",
899+
"pastInsight",
900+
"sectorInsights",
897901
"Review",
898902
"SelectResult",
899903
"ChartResult",

src/dartlab/ai/insights.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""KnowledgeDB 경험 자산 조회 — 모듈 레벨 함수.
2+
3+
dartlab.pastInsight(stockCode) / dartlab.sectorInsights(sector) 로 노출.
4+
AI tool 자동 등록 경로 (`_autoDiscover`) 가 dartlab.__all__ 순회 시 자동 포함.
5+
6+
사상 (ops/ai.md §7 경험 자산화 순환):
7+
- 사람 (블로그) + AI (응답) 가 쌓은 서사·bullet 이 KnowledgeDB 에 보존
8+
- 떠먹이기 아님 — AI 가 자율 판단 ("이 회사 전에 본 적 있나?") 으로 호출
9+
- 블로그 (검증 프리미엄) 우선, 없으면 AI 축적 fallback
10+
"""
11+
12+
from __future__ import annotations
13+
14+
from typing import Any
15+
16+
17+
def _recordToDict(rec: Any) -> dict[str, Any] | None:
18+
"""InsightRecord → dict 변환. dataclass 또는 namedtuple 모두 지원."""
19+
if rec is None:
20+
return None
21+
if hasattr(rec, "_asdict"):
22+
return rec._asdict()
23+
if hasattr(rec, "__dict__"):
24+
return {k: v for k, v in rec.__dict__.items() if not k.startswith("_")}
25+
if isinstance(rec, dict):
26+
return rec
27+
return {"value": str(rec)}
28+
29+
30+
def pastInsight(stockCode: str) -> dict[str, Any] | None:
31+
"""특정 회사의 과거 분석 서사 조회.
32+
33+
우선순위: 블로그 (사람 검증 프리미엄) → AI 축적.
34+
AI 가 분석 전 "이 회사 전에 본 적 있나?" 자율 판단 후 호출.
35+
36+
Args:
37+
stockCode: 종목코드 (예: '005930', 'AAPL')
38+
39+
Returns:
40+
dict — narrative / strengths / weaknesses / keyMetrics / dataAsOf / source.
41+
None — 과거 분석 없음.
42+
"""
43+
try:
44+
from dartlab.ai.persistence import KnowledgeDB
45+
except ImportError:
46+
return None
47+
48+
try:
49+
db = KnowledgeDB.get()
50+
except (OSError, RuntimeError):
51+
return None
52+
53+
rec = db.get_insight(stockCode, source="blog")
54+
if rec is None:
55+
rec = db.get_insight(stockCode)
56+
return _recordToDict(rec)
57+
58+
59+
def sectorInsights(sector: str, limit: int = 3) -> list[dict[str, Any]]:
60+
"""동종 업계 과거 분석 서사 목록 (교차 학습).
61+
62+
AI 가 "이 업종에서 전에 어떤 패턴 발견했나?" 자율 판단 후 호출.
63+
매크로/섹터 질문에 특히 유용.
64+
65+
Args:
66+
sector: 업종명 (예: '반도체', '식품')
67+
limit: 상위 N개 (기본 3)
68+
69+
Returns:
70+
list — 각 항목: narrative / strengths / weaknesses / keyMetrics / stockCode / corpName.
71+
"""
72+
try:
73+
from dartlab.ai.persistence import KnowledgeDB
74+
except ImportError:
75+
return []
76+
77+
try:
78+
db = KnowledgeDB.get()
79+
except (OSError, RuntimeError):
80+
return []
81+
82+
records = db.get_sector_insights(sector, limit=limit)
83+
return [d for d in (_recordToDict(r) for r in records) if d is not None]

src/dartlab/ai/tools/__init__.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,7 @@ def buildTools() -> list[AITool]:
137137
)
138138
)
139139

140-
# 경험 조회 tool — KnowledgeDB 직접 접근 (Company 불필요)
141-
from dartlab.ai.tools._builtin import _builtinTools
142-
143-
tools.extend(_builtinTools())
140+
# pastInsight / sectorInsights 는 dartlab.__all__ 에 노출되어 위 _autoDiscover 가 자동 등록.
144141

145142
# pythonExec — 유일 특수 케이스 (subprocess)
146143
tools.append(

src/dartlab/ai/tools/_builtin.py

Lines changed: 0 additions & 112 deletions
This file was deleted.

src/dartlab/guide/_generated.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,10 @@
598598
"kind": "function",
599599
"summary": "회사명 → 종목코드. 정확히 일치하는 첫 번째 결과."
600600
},
601+
"pastInsight": {
602+
"kind": "function",
603+
"summary": "특정 회사의 과거 분석 서사 조회."
604+
},
601605
"quant": {
602606
"kind": "function",
603607
"summary": "종목 레벨 정량분석 엔진 — 30축 7그룹."
@@ -719,6 +723,10 @@
719723
"kind": "function",
720724
"summary": "종목명/코드로 종목 찾기 (KR + US)."
721725
},
726+
"sectorInsights": {
727+
"kind": "function",
728+
"summary": "동종 업계 과거 분석 서사 목록 (교차 학습)."
729+
},
722730
"setup": {
723731
"aicontext": "AI 분석 기능 사용 전 provider 설정 상태 확인\n미설정 provider 감지 시 setup() 안내로 연결\n설정 완료 여부를 프로그래밍 방식으로 체크 가능",
724732
"capabilities": "전체 AI provider 설정 현황 테이블 표시\nprovider별 대화형 설정 (키 입력 → .env 저장)\nChatGPT OAuth 브라우저 로그인\nOpenAI/Gemini/Groq/Cerebras/Mistral API 키 설정\nOllama 로컬 LLM 설치 안내",

src/dartlab/providers/dart/company.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2970,9 +2970,18 @@ def _creditImpl(
29702970
kwargs["overrides"] = clean
29712971
return creditCompany(self, axis=axis, detail=detail, basePeriod=basePeriod, **kwargs)
29722972

2973-
def gather(self, axis: str | None = None, **kwargs):
2973+
def gather(self, axis: str | None = None, target: str | None = None, **kwargs):
29742974
"""외부 시장 데이터 수집 — 4축 (price/flow/macro/news).
29752975
2976+
Args:
2977+
axis: 데이터 축. price/flow/macro/news/sector/insider/peers/ownership.
2978+
target: 축별 부가 인자.
2979+
- axis='news' 일 때: 검색어 (예: '한국 경제', '반도체 수출 동향').
2980+
시장 레벨 뉴스 조회. 비우면 종목 기반 fallback.
2981+
- axis='macro' 일 때: 시리즈 이름 또는 시나리오.
2982+
- axis='sector'/'peers' 일 때: 비교 대상 sector/종목.
2983+
**kwargs: market, days, start, end 등 축별 옵션.
2984+
29762985
Capabilities:
29772986
- price: OHLCV 주가 시계열 (KR Naver / US Yahoo)
29782987
- flow: 외국인/기관 수급 동향 (KR 전용)

0 commit comments

Comments
 (0)