feat(my-deepagent): v0.3 PR #4 — Agent Skills (LLM-routing, SKILL.md index inject)

Claude Code의 Agent Skills 동작을 그대로 구현 — deepagents `SkillsMiddleware`가
`<name>/SKILL.md` 디렉터리들을 스캔하고 `(name, description)` 인덱스만
시스템 프롬프트에 inject.  LLM이 필요한 skill을 골라 read_file 로 본문을
가져감 (progressive disclosure).  임베딩·벡터 검색 없음.

데이터·라이브러리:
- `skills.py` (신규):
  - `user_skills_dir(config)` — `<config.data_dir>/skills/`
  - `ensure_skills_initialized(dir)` — `mkdir -p`, 예제 skill 시드 안 함
  - `list_installed_skills(dir)` — `<name>/SKILL.md` frontmatter 파싱.
    malformed (frontmatter 없음/YAML 깨짐/name-dir mismatch/10MB 초과)는
    silently skip.  description 200자 트렁케이트.
  - `read_skill_body(dir, name)` — `/skill <name>` 본문 표시용
  - `resolve_skill_sources(config)` — deepagents 에 전달할 source 리스트
- `session.py`:
  - `build_agent(..., skills_sources_override=...)` 신규 kwarg.
    `persona.skills`와 합쳐 `deepagents.create_deep_agent(skills=...)`로 전달
    (empty 면 kwarg 생략 → middleware 미생성).
  - `_resolve_skill_sources` 헬퍼 추출.

REPL 통합 (`cli/interactive.py`):
- `InteractiveSession.__init__`에서 `ensure_skills_initialized` 호출
  → `self.skills_dir`.
- `build_agent_if_needed`가 매 재빌드 시 `resolve_skill_sources(config)` 전달.
- `_register_skills_slash`: `/skills` (목록), `/skill <name>` (본문) 등록.

테스트 (`tests/integration/test_skills.py`, 15 케이스):
- Bootstrap idempotency, 빈 디렉터리 정상 상태
- list: 정렬, SKILL.md 누락 스킵, YAML 깨짐 스킵, name-dir mismatch 스킵,
  description truncate, 누락된 디렉터리 빈 리스트, 긴 description 트렁케이트
- read_skill_body: 정상/누락/빈 이름
- resolve_skill_sources: user-scope 1개 반환
- **integration**: `build_agent(..., skills_sources_override=[...])` 가 실제로
  `create_deep_agent(skills=...)` 까지 monkeypatch 로 전달되는지 검증

게이트:
- ruff check / format --check / mypy: PASS
- pytest -q --ignore=tests/integration/test_e2e_workflow.py
  --ignore=tests/integration/test_openrouter_smoke.py: 648 passed (15 신규 포함)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
chungyeong
2026-05-17 20:42:32 +09:00
parent 15b33e22fe
commit 2685cb26db
5 changed files with 557 additions and 2 deletions

View File

@@ -3,6 +3,42 @@
## [Unreleased]
### Added
- **v0.3 PR #4 — Agent Skills (LLM-routing, no embeddings)**. Anthropic Agent
Skills 명세를 그대로 따르는 progressive-disclosure 패턴. deepagents
`SkillsMiddleware`가 디렉터리를 스캔해 `(name, description)` 인덱스만
시스템 프롬프트에 인젝션하면 LLM이 필요한 skill을 골라 `read_file`로 본문을
읽음. 임베딩·벡터 검색 없음 — Claude Code의 실제 동작과 동일.
- `skills.py` (신규):
- `user_skills_dir(config)``<config.data_dir>/skills/`
- `ensure_skills_initialized(dir)` — 디렉터리 생성, idempotent. 예제
skill 시드하지 않음 (빈 디렉터리가 정상 신규 상태).
- `list_installed_skills(dir)``<name>/SKILL.md`를 스캔해 frontmatter
파싱. malformed (frontmatter 없음/YAML 깨짐/name-dir mismatch/10MB 초과)
는 silently skip. `SkillInfo(name, description, path)` 리스트.
- `read_skill_body(dir, name)``/skill <name>`의 본문 표시용.
- `resolve_skill_sources(config)` — deepagents 에 전달할 source 리스트
빌드 (현재는 user-scope 1개; 후속 PR이 project-scope 추가 가능).
- `session.py`:
- `build_agent(..., skills_sources_override: list[str] | None = None)`
신규 kwarg. `persona.skills`와 합쳐 deepagents `skills=` kwarg로 전달
(empty 면 kwarg 생략 → `SkillsMiddleware` 미생성).
- `_resolve_skill_sources` 헬퍼 추출.
- `cli/interactive.py`:
- `InteractiveSession.__init__`에서 `user_skills_dir` 부트스트랩 후
`self.skills_dir`로 보관.
- `build_agent_if_needed`가 매 재빌드 시 `resolve_skill_sources(config)`
현재 디렉터리 상태를 전달.
- `_register_skills_slash`: `/skills` (설치된 skill 목록), `/skill <name>`
(전체 SKILL.md 본문 표시) 슬래시 등록.
- `tests/integration/test_skills.py` (신규, 15 케이스):
- Bootstrap idempotency, 빈 디렉터리 기본 상태
- list: 정렬, SKILL.md 누락 스킵, YAML 깨짐 스킵, name-dir mismatch 스킵,
description 200자 트렁케이트, 누락된 디렉터리는 빈 리스트
- read_skill_body: 정상/누락/빈 이름
- resolve_skill_sources: user-scope 1개 반환
- **integration**: `build_agent(..., skills_sources_override=[...])`
실제로 `create_deep_agent(skills=...)` 까지 전달되는지 monkeypatch 검증
- **v0.3 PR #3 — auto-memory (project-scoped `MEMORY.md` + entry files)**.
Claude Code의 auto-memory + `/remember`/`/forget` 슬래시 등가. 세션이 시작될
`<config.data_dir>/projects/<project_key>/memory/` 디렉터리를 부트스트랩