Metadata-Version: 2.4
Name: skillvault
Version: 0.1.3
Summary: Agent Skill Management System with self-growth capabilities
Project-URL: Homepage, https://github.com/yourusername/skillvault
Project-URL: Documentation, https://github.com/yourusername/skillvault#readme
Project-URL: Repository, https://github.com/yourusername/skillvault.git
Project-URL: Issues, https://github.com/yourusername/skillvault/issues
License: MIT
License-File: LICENSE
Keywords: agent,ai,knowledge-management,llm,skill,sqlite,vector-search
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24.0
Requires-Dist: sqlite-vec>=0.1.0
Provides-Extra: cli
Requires-Dist: click>=8.0.0; extra == 'cli'
Provides-Extra: dev
Requires-Dist: black>=23.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Provides-Extra: local-embed
Requires-Dist: sentence-transformers>=2.0.0; extra == 'local-embed'
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == 'openai'
Requires-Dist: tiktoken>=0.5.0; extra == 'openai'
Description-Content-Type: text/markdown

# Skill Manager

[![PyPI](https://img.shields.io/pypi/v/skillvault)](https://pypi.org/project/skillvault/)

Agent Skill Management System with self-growth capabilities.

Published on PyPI: **https://pypi.org/project/skillvault/**

## Features

- **Skill Storage**: SQLite + sqlite-vec for local storage with vector search
- **Semantic Query**: ANN retrieval + dependency expansion + token budget cropping
- **Self-Growth**: Automatically extract knowledge from conversations and tasks
- **Human-in-the-Loop**: Review queue for approving/rejecting draft skills
- **Permission Separation**: Agent code can only write drafts, humans control canonical
- **CLI Tool**: Command-line interface for skill management (optional)

## Installation

```bash
pip install skillvault
```

## Quick Start

### 方式 A：配置式（简单）

```python
from skillvault import SkillManager

sm = SkillManager(
    "skills.db",
    embed_config={
        "base_url": "https://api.openai.com/v1",
        "api_key": "sk-...",
        "model": "text-embedding-3-small",
    }
)

# 本地模型也兼容（OpenAI API 格式）
sm = SkillManager(
    "skills.db",
    embed_config={
        "base_url": "http://localhost:8000/v1",
        "api_key": "xxx",
        "model": "bge-m3",
    }
)
```

### 方式 B：函数注入（灵活）

```python
from openai import OpenAI
from skillvault import SkillManager

client = OpenAI()

def embed(text: str) -> list[float]:
    resp = client.embeddings.create(model="text-embedding-3-small", input=[text])
    return resp.data[0].embedding

sm = SkillManager("skills.db", embed_fn=embed)
```

**优先级**：`embed_fn` > `embed_config` > None（报错）

**`embed` 要求**：
- **维度必须是 1536**（sqlite-vec 硬编码）
- 兼容模型：OpenAI `text-embedding-3-small`、`text-embedding-ada-002`
- 不兼容：维度非 1536 的模型（如 all-MiniLM-L6-v2 的 384 维）

### 使用示例

```python
from skillvault import SkillManager
from skillvault.models import Skill, Chunk

sm = SkillManager("skills.db", embed_config={
    "base_url": "https://api.openai.com/v1",
    "api_key": "sk-...",
    "model": "text-embedding-3-small",
})

# Register a skill
skill = Skill(
    id="frontend-react",
    name="Frontend React",
    chunks=[
        Chunk(
            id="frontend-react::hooks",
            skill_id="frontend-react",
            section="React Hooks",
            content="## useEffect\n\nUse useEffect for side effects...",
            tokens=50,
        )
    ]
)
sm.register(skill)

# Query skills
context = sm.query("React hooks best practices", budget=2000)
print(context)
```

## Self-Growth (Extract knowledge from conversations)

### `llm_fn` 定义方式

`llm_fn` 签名固定：`(text: str) -> dict`，必须返回 `{"has_knowledge": bool}`，内部用什么 API 自由选择。

```python
import json

# 方式 1：OpenAI
from openai import OpenAI
openai_client = OpenAI(api_key="sk-...")

def llm_fn_openai(text: str) -> dict:
    resp = openai_client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": f"Extract knowledge from:\n{text}\n\nReturn JSON: has_knowledge(bool), title, playbook, examples, when_to_use, dependencies(list)"}],
        response_format={"type": "json_object"},
    )
    return json.loads(resp.choices[0].message.content)

# 方式 2：Claude
import anthropic
claude_client = anthropic.Anthropic(api_key="sk-ant-...")

def llm_fn_claude(text: str) -> dict:
    resp = claude_client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        messages=[{"role": "user", "content": f"Extract knowledge from:\n{text}\n\nReturn ONLY JSON: {{'has_knowledge': bool, 'title': str, 'playbook': str}}"}],
    )
    return json.loads(resp.content[0].text)

# 方式 3：本地模型 / OpenAI 兼容接口
local_client = OpenAI(base_url="http://localhost:8000/v1", api_key="xxx")

def llm_fn_local(text: str) -> dict:
    resp = local_client.chat.completions.create(
        model="local-model",
        messages=[{"role": "user", "content": f"Extract knowledge from:\n{text}\n\nReturn JSON: has_knowledge(bool), title, playbook"}],
    )
    return json.loads(resp.choices[0].message.content)
```

### 使用示例

```python
from skillvault import SkillManager

sm = SkillManager("skills.db", embed_fn=embed, llm_fn=llm_fn_openai)

# Extract from conversation (returns draft_id or None)
draft_id = sm.extract([
    {"role": "user", "content": "How do I handle errors in async Python?"},
    {"role": "assistant", "content": "Use try/except with asyncio.gather..."},
])

# Review and approve
if draft_id:
    pending = sm.review_queue()
    sm.approve(draft_id)
```

## Agent Mode (Restricted permissions)

```python
from skillvault import SkillManager

# Same embed_fn as above
sm = SkillManager("skills.db", embed_fn=embed, mode="agent")

sm.query("...")           # OK - reads canonical skills only
sm.extract(messages)      # OK - creates drafts
sm.register(skill)        # raises PermissionError
sm.approve(draft_id)      # raises PermissionError
```

## CLI Usage

Requires `pip install skillvault[cli]`.

```bash
# List skills
python -m skillvault.cli list

# Review queue
python -m skillvault.cli review-queue

# Approve/reject
python -m skillvault.cli approve draft::skill-id
python -m skillvault.cli reject draft::skill-id --reason "Not useful"

# Export/Import
python -m skillvault.cli export frontend-react react.json
python -m skillvault.cli import react.json

# Statistics
python -m skillvault.cli stats
```

## Architecture

```
SkillManager (one class)
    │
    ├── query(text, budget)        → Search + assemble context
    ├── register(skill)            → Save canonical skill
    ├── extract(context)           → LLM extraction → draft
    ├── approve/reject(skill_id)   → Review workflow
    └── export/import              → JSON serialization
    │
    ├── storage.py    (SQLite + sqlite-vec)
    ├── query.py      (embed + ANN + budget)
    └── growth.py     (LLM analysis + auto-promote)
```

## Development

```bash
# Install in dev mode
pip install -e ".[dev,openai,cli]"

# Run tests
pytest

# Format & lint
black src/ tests/
ruff check src/ tests/
```

## License

MIT
