Metadata-Version: 2.4
Name: hangyeol
Version: 0.2.0
Summary: K-Parser: 한국어 문법 구조 기반 에이전트 실행 그래프 컴파일러
Author-email: "sunghoon.kim" <sunghoon.kim@aigensciences.com>
License-Expression: MIT
Keywords: korean,parser,nlp,intent-graph,dependency-parsing,한국어
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Natural Language :: Korean
Classifier: Topic :: Text Processing :: Linguistic
Classifier: Intended Audience :: Developers
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: kiwipiepy>=0.23.1
Requires-Dist: pyyaml>=6.0
Requires-Dist: jsonschema>=4.23
Requires-Dist: numpy>=1.26
Provides-Extra: parser
Requires-Dist: stanza>=1.9; extra == "parser"
Provides-Extra: llm
Requires-Dist: anthropic>=0.40; extra == "llm"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == "mcp"
Provides-Extra: repl
Requires-Dist: prompt_toolkit>=3.0; extra == "repl"
Dynamic: license-file

# 한결 K-Parser

> 한국어 발화를 **에이전트 실행 그래프(의도그래프)**로 컴파일하는 한국어 문법 기반 파서.

`"CSV로 논문을 찾아서 정리해줘"` 같은 한 문장을, LLM 없이 한국어 문법 구조만으로
실행 가능한 도구 호출 DAG로 변환한다.

```json
{
  "발화": "CSV로 논문을 찾아서 정리해줘",
  "노드": [
    {"번호": "n1", "도구": "검색", "술어": "찾아서", "인자": {"대상": "논문"}},
    {"번호": "n2", "도구": "요약", "술어": "정리해줘",
     "인자": {"출력형식": "CSV", "대상": "$n1.출력"}}
  ],
  "간선": [{"출발": "n1", "도착": "n2", "유형": "선행조건"}],
  "불확실성": []
}
```

`찾아서`(검색) → `정리해줘`(요약) 두 술어를 노드로, "논문"을 검색 대상으로, "CSV"를
요약의 출력형식으로 배정하고, `$n1.출력`으로 노드 간 데이터 흐름을 잇는다.

## 설계 원칙

- **결정론 우선** — 형태소·조사·격틀(세종 동사 사전 계열)만으로 파싱한다. LLM은
  실패한 경우의 *복원* 경로(opt-in)일 뿐, 정상 경로에 개입하지 않는다.
- **드롭/예외 없음·정직성** — 확신이 없는 배정도 버리지 않고 `불확실성` 배열에
  근거와 함께 남긴다. 선택제약 위반·의미부류 미분류도 침묵하지 않고 신호로 표시한다.
- **DAG 불변** — 노드ID(`n1`), 노드 간 참조(`$nN.출력`) 형식은 안정 계약.
- **완전 한글화** — 모듈·함수·필드·테스트까지 한글 식별자(고유명사·3rd-party
  API 표면 제외). `tests/test_식별자_한글.py`가 AST로 강제한다.

## 설치

요구사항: Python ≥ 3.11

```bash
python -m venv .venv && source .venv/bin/activate
pip install -e .            # 코어 (kiwipiepy, pyyaml, jsonschema, numpy)
pip install -e '.[parser]'  # + Stanza 의존구문분석 (선택)
pip install -e '.[llm]'     # + anthropic (LLM 복원, 선택)
pip install -e '.[mcp]'     # + mcp (외부 에이전트 연결, 선택)
pip install -e '.[repl]'    # + prompt_toolkit (대화 REPL 편의, 선택)
pip install -e '.[dev]'     # + pytest
```

## 빠른 시작

### 파이썬 API

```python
from 한결파서 import 파싱, 파싱_json

그래프 = 파싱("논문을 요약해줘")
print(그래프.노드들[0].도구)          # → '요약'

# JSON 문자열로 바로:
print(파싱_json("CSV로 논문을 찾아서 정리해줘", 들여쓰기=2))
```

`파싱()` 시그니처:

```python
파싱(발화: str,
     엄격: bool = False,          # True면 불확실성 발생 시 예외
     의존파서사용: bool = True,    # Stanza UD 보강 (미설치 시 자동 우회)
     llm복원사용: bool = False,   # 실패 노드 LLM 복원 (ANTHROPIC_API_KEY 필요)
     예시수: int = 3) -> 의도그래프
```

### 명령줄 (CLI)

설치 시 `한결` 명령이 등록된다 (또는 `python -m 한결런타임.cli`):

```bash
한결 파싱 "논문을 요약해줘"            # 파싱만 (실행 안 함)
한결 실행 "논문을 요약해줘"            # 파싱 후 실제 도구 실행 (샌드박스 ./한결_출력)
한결 대화                              # 발화를 한 줄씩 받아 실행하는 대화형 REPL
한결                                   # 인자 없이 실행해도 대화 루프
한결 연결 --목록                       # 등록된 도구를 MCP 커넥터로
한결 연결 --마법사                     # 대화형 마법사로 도구↔서버 연결 등록
한결 연결 --발견 <서버>                 # MCP 서버가 노출하는 도구를 자동 발견해 목록 출력

# 스킬 브리지 스크립트도 동일 동작:
python skills/한결/scripts/한결파싱.py "논문을 요약해줘" --들여쓰기
```

`실행`·`대화`의 파일 출력은 기본적으로 샌드박스 디렉터리 `./한결_출력`로
제한된다(`--샌드박스`로 변경). 요약·번역 등 생성형 도구는 연결이 없으면 실행 시
"연결된 에이전트 없음" 에러가 나며, `한결 연결 --마법사` 또는 루트의
[`도구연결.예시.yaml`](도구연결.예시.yaml)을 `도구연결.yaml`로 복사해 등록한다.
생성형 도구는 `mcp` SDK 없이 로컬 셸 명령으로도 연결할 수 있다(`셸명령들` 섹션) —
도구 인자는 stdin-JSON으로 들어가고 stdout이 결과로 돌아온다.
생성형 도구는 원격 HTTP 끝점으로도 연결할 수 있다(`http끝점들` 섹션) —
`POST {url}/{도구명}` 으로 인자를 JSON 본문에 실어 보내고 응답 본문이 결과로 돌아온다.
`한결 연결 --마법사`는 서버가 이미 등록돼 있으면 발견된 도구 목록에서 번호로
고를 수 있어 서버측 도구명을 손으로 외울 필요가 없다.

### 실행 전 확인

`한결 실행`·`한결 대화`는 실제 도구를 호출하기 전에 한국어 실행 계획을 먼저
보여준다 — 노드별로 어떤 도구를 어떤 인자로 부르는지, 그리고 파일쓰기·외부전송·
셸실행 같은 위험이 섞여 있는지를 요약한다. 위험이 포함된 계획이면 실행 여부를
물어보고, 파일읽기처럼 부수효과가 없는 작업만으로 이뤄진 계획은 묻지 않고 바로
실행한다. (검색·요약 등은 외부 전송이라 승인 대상이다.)

```bash
한결 실행 "논문을 찾아서 저장해줘"        # 위험(파일쓰기·외부전송) 포함 → 계획 표시 후 승인 확인
한결 실행 "논문을 찾아줘" --예             # 검색은 외부전송 → --예로 확인 프롬프트 자동 승인
```

실행이 실패하면 영어 스택트레이스 대신 한국어 조치 안내가 나온다. 예를 들어
생성형 도구에 연결이 없으면 "연결된 에이전트 없음" 상황을 짚고 `한결 연결` 또는
`한결 도구 --등록`으로 도구를 연결하라고 안내한다 — 다음에 무엇을 하면 되는지를
한국어로 알려준다.

## 한결 도구 (도구 탐색·한결화)

설치된 도구(skill·MCP·셸·HTTP)를 한국어로 탐색하는 `한결 도구` 명령이 있다.
목록을 보거나, 자연어로 쓰임새를 찾거나, 특정 도구의 설명을 펼쳐 볼 수 있다.

```bash
한결 도구 --목록                    # 등록된 도구 한눈에 보기
한결 도구 --찾기 "PDF 표 추출"        # 자연어로 맞는 도구 탐색
한결 도구 --설명 pdf                 # 특정 도구의 상세 설명
```

사용자가 직접 도구를 한결화하려면 `~/.한결/도구목록/<id>.yaml`에 manifest를 두면
된다. 같은 `id`면 동봉 시드를 덮어쓰고, 새 `id`면 도구가 추가된다. manifest의 최소
필드는 다음과 같다:

```yaml
id: pdf                    # 도구 식별자 (파일명과 일치)
한글이름: PDF 표 추출
종류: skill                 # skill | mcp | 셸 | http
원본:
  이름: pdftables           # 원래 도구·명령 이름
  위치: 외부 PDF 처리 라이브러리
설명: PDF에서 표를 뽑아 CSV로 변환한다
사용상황: PDF 문서의 표를 데이터로 다룰 때
한국어호출: ["PDF에서 표 뽑아줘", "표 추출"]
위험도:                     # 동작별 불리언 플래그
  파일읽기: true
  파일쓰기: true
  외부전송: false
  셸실행: false
```

패키지에는 시드 manifest 3개(PDF·스프레드시트·논문)가 기본 동봉되어 있어, 별도
설정 없이도 `한결 도구 --목록`에 나타난다.

손편집 대신 대화형으로 등록하려면 `한결 도구 --등록`을 쓴다. 도구 정보를 차례로
물어 manifest와 연결 설정을 자동으로 만들어 준다. 질문 흐름은 id → 한글이름 →
종류(셸/http/mcp) → 원본 → 설명 → 사용상황 → 한국어 호출 표현 → 필요입력 →
출력 → 위험도 순이다.

```bash
한결 도구 --등록    # 대화형으로 외부 도구를 한결화 등록
```

등록을 마치면 `~/.한결/도구목록/<id>.yaml` manifest와 함께 `도구연결.yaml`의
종류별 섹션(셸명령들 / http끝점들 / mcp서버들)에 해당 도구가 추가된다. 그래서
등록 직후 `한결 도구 --목록`·`--찾기`에 바로 나타난다.

## 출력 구조 (의도그래프)

| 필드 | 의미 |
|---|---|
| `발화` | 원본 입력 문장 |
| `실행방식` | `즉시` 등 — 그래프 실행 전략 |
| `노드` | 도구 호출 단위. `번호`(nN)·`도구`·`술어`(표면형)·`인자`(역할→값 dict) |
| `간선` | 노드 간 의존. `출발`·`도착`·`유형`(`선행조건` 등) |
| `불확실성` | 확신 못 한 배정의 근거 목록 — 위반·미분류·미등록 신호 포함 |

`인자` 값이 `$n1.출력`이면 앞선 노드의 출력을 참조한다(논항 생략 보충).

## 처리 파이프라인 (`한결파서/`)

| 단계 | 모듈 | 역할 |
|---|---|---|
| 1 형태소분석 | `형태소분석.py` | kiwipiepy 형태소 분해 |
| 2 어절묶기 | `어절묶기.py` | SOV 어절 묶음 구성 |
| 3 역할배정 | `역할배정.py` | 조사 → 격(대상·도구·출발점…) |
| 4 의존파서 | `의존파서.py` | Stanza UD 보강 (선택) |
| 5 격틀조회 | `격틀조회.py` | 술어 격틀 조회·인자정렬·선택제약 검사 |
| 6 의도그래프구성 | `의도그래프구성.py` | 술어→노드, 논항 귀속, 간선 연결 (DAG) |
| 7 검증 | `검증.py` | 순환·미등록 도구·필수 인자 점검 |
| 8 LLM복원 | `llm복원.py` | 실패 노드 복원 (opt-in, anthropic) |

핵심 휴리스틱: **핵어후행 원리**(한국어 논항은 자기 술어에 선행) + **격틀 인가**
(논항을 "가장 가까운 후행 술어 중 그 역할을 인가하는 첫 술어"에 귀속). 인가 술어가
없으면 현행 위치를 유지하고 불확실성에 기록한다(silent drop 금지).

## 어휘집 (`어휘집/`)

| 파일 | 내용 |
|---|---|
| `술어.yaml` | 한국어 술어 기본형 → 도구 별칭 |
| `격틀.yaml` | 도구별 의미역 슬롯(필수/선택) + 허용 조사 + 선택제약 |
| `조사.yaml` | 조사 → 격 매핑 |
| `의미역.yaml` | 의미역 ↔ 한글 역할, 국립국어원 표준 약호 |
| `의미부류.yaml` | 세종 명사 의미부류 타크소노미 + 선택제약 온톨로지 |

선택제약은 세종 명사 의미부류 위계로 소프트하게 강제한다 — 위반 시 모호도↑+경고,
미분류 시 저강도 "검사 불가" 신호, 통과는 그대로(어느 경우에도 역할을 드롭하지 않음).

## 런타임 (`한결런타임/`)

의도그래프를 실제로 실행하는 계층:

- `실행엔진.py` — DAG 위상 정렬 후 노드별 도구 호출, `$nN.출력` 데이터 전달
- `도구레지스트리.py` / `검색도구.py` / `분석도구.py` / `파일도구.py` — 도구 구현
- `mcp연결.py` / `연결설정.py` — 한결 도구를 MCP 커넥터로 노출/연결
- `cli.py` — `한결 파싱|실행|연결` 진입점

## 테스트

```bash
.venv/bin/python -m pytest tests/ -q          # 전체 (265 passed, 2 skipped)
.venv/bin/python -m pytest -m 'not slow' -q   # 벤치마크 제외
```

`2 skipped`는 LLM 복원의 실제 API 검증 — `ANTHROPIC_API_KEY` 설정 후
`pytest tests/test_llm복원.py -v`로 해소된다.

주요 테스트: `test_논항귀속`(노드·역할 배정) · `test_의미부류`(선택제약) ·
`test_격틀스키마` · `test_검증` · `test_식별자_한글`(한글 식별자 강제) ·
`test_실행통합`(런타임).

## 프로젝트 구조

```
한결파서/      파싱 코어 (형태소 → 의도그래프)
한결런타임/    실행엔진 + 도구 + MCP + CLI
어휘집/        술어·격틀·조사·의미역·의미부류 YAML
tests/         pytest 스위트 (23개 파일)
examples/      기본예시.py
skills/한결/   에이전트 스킬 브리지 (한결파싱.py 등)
```

## 개발 워크플로 / 협업 하네스

기여 규칙·승인 게이트·세션 협업 규약은 별도 문서에 있다:

- **`AGENTS.md`** — 작업 규칙, 승인 게이트, 검증 명령 (공유 규칙의 단일 출처)
- **`CLAUDE.md`** — Claude Code 진입점, 세션 리추얼, 네이티브 프리미티브
- **`WORKFLOW.md`** — 계약→플랜→실행 파이프라인, 슬라이스 라우팅
- **`.agent/`** — 슬라이스별 상태(`status/`)·계약(`contracts/`)·플랜(`plans/`)
