fix(config + tilde): LLM default → gemma4:e4b + workspace.root ~ expansion #47
@@ -5,7 +5,7 @@
|
||||
## 사전 요구
|
||||
|
||||
- **Rust toolchain** ≥ 1.85 (workspace 가 edition 2024 + resolver 3 사용). [rustup](https://rustup.rs) 권장.
|
||||
- **Ollama** — `kebab ask` 와 이미지 OCR/caption 가 사용. `https://ollama.com/download` 에서 설치 후 `ollama serve` 실행. 모델은 `ollama pull qwen2.5:7b-instruct` (텍스트) / `ollama pull gemma4:e4b` (vision) 등. config 의 `[models.llm].endpoint` 에 host:port 명시.
|
||||
- **Ollama** — `kebab ask` 와 이미지 OCR/caption 가 사용. `https://ollama.com/download` 에서 설치 후 `ollama serve` 실행. 기본 LLM 은 gemma4 계열 (`ollama pull gemma4:e4b`) — OCR / caption 도 같은 family 라 모델 하나만 pull 하면 됨. 더 큰 variant 원하면 `gemma4:26b` 등으로 config override. config 의 `[models.llm].endpoint` 에 host:port 명시.
|
||||
|
|
||||
- **빌드 디스크** — 첫 빌드 시 `target/` 가 6–10 GB (Lance + DataFusion + fastembed). 여유 확인.
|
||||
- **fastembed 모델** — 첫 `kebab ingest` 시 `multilingual-e5-small` (~470 MB) 자동 다운로드.
|
||||
|
||||
|
||||
@@ -744,7 +744,10 @@ fn ingest_one_image_asset(
|
||||
// nothing the image extractor reads today; we pass a default
|
||||
// instance per the trait shape.
|
||||
let extract_config = kebab_core::ExtractConfig::default();
|
||||
let workspace_root = std::path::PathBuf::from(&app.config.workspace.root);
|
||||
// `~` / `${XDG_…}` expansion via the same helper the markdown
|
||||
|
claude-reviewer-01
commented
(suggestion / 일관성) image / pdf 두 분기가 Why: How to apply (P+ task): (suggestion / 일관성) image / pdf 두 분기가 `expand_tilde`, kebab-tui search 가 `kebab_config::expand_path` — 두 helper 동시 사용. HOTFIXES 의 "caveat (남은 inconsistency)" 도 이 사실 명시. 이번 PR scope 는 fix 의 minimum surface 라 OK 지만, 미래 P+ 로 넘기는 게 정확.
Why: `kebab-app::expand_tilde` 가 이미 `kebab-config::expand_path` 의 subset. 한 helper 로 통합하면 두 spec literal 차이 (env var / templating) 제거 + 미래 contributor 가 "어떤 helper 써야 하지" 의문 사라짐.
How to apply (P+ task): `kebab-app::expand_tilde` 호출 site (3 곳: line 114, 762, 1057, 1369) 모두 `kebab_config::expand_path(s, "")` 로 교체 후 self-helper 삭제. 본 PR 에서는 안 함 — caveat 그대로 명시.
|
||||
// path uses, so a `~/KnowledgeBase` workspace.root resolves
|
||||
// identically across all media (HOTFIXES 2026-05-02 P9-4 follow-up).
|
||||
|
claude-reviewer-01
commented
(칭찬) 두 분기 코멘트가 "HOTFIXES 2026-05-02 P9-4 follow-up" 으로 cross-link — 미래 contributor 가 "왜 expand_tilde 가 여기 있지" 묻으면 즉시 HOTFIXES entry 로 이동. 도그푸딩 시 발견된 인콘시스턴시의 history 가 코드 옆에 박혀있음. (칭찬) 두 분기 코멘트가 "HOTFIXES 2026-05-02 P9-4 follow-up" 으로 cross-link — 미래 contributor 가 "왜 expand_tilde 가 여기 있지" 묻으면 즉시 HOTFIXES entry 로 이동. 도그푸딩 시 발견된 인콘시스턴시의 history 가 코드 옆에 박혀있음.
|
||||
let workspace_root = expand_tilde(&app.config.workspace.root);
|
||||
let ctx = ExtractContext {
|
||||
asset,
|
||||
workspace_root: &workspace_root,
|
||||
@@ -1047,7 +1050,8 @@ fn ingest_one_pdf_asset(
|
||||
.with_context(|| format!("read PDF asset bytes from {}", path.display()))?;
|
||||
|
||||
let extract_config = kebab_core::ExtractConfig::default();
|
||||
let workspace_root = std::path::PathBuf::from(&app.config.workspace.root);
|
||||
// `~` / `${XDG_…}` expansion (HOTFIXES 2026-05-02 P9-4 follow-up).
|
||||
let workspace_root = expand_tilde(&app.config.workspace.root);
|
||||
let ctx = ExtractContext {
|
||||
asset,
|
||||
workspace_root: &workspace_root,
|
||||
|
||||
@@ -239,7 +239,11 @@ impl Config {
|
||||
},
|
||||
llm: LlmCfg {
|
||||
provider: "ollama".to_string(),
|
||||
model: "qwen2.5:14b-instruct".to_string(),
|
||||
// gemma4 계열 통일 — OCR (P6-2) + caption (P6-3)
|
||||
|
claude-reviewer-01
commented
(칭찬) (칭찬) `gemma4:e4b` default + 코멘트 (OCR/caption family 통일 + 사용자 override 안내) 가 한 결정의 의도를 정확히 코드 옆에. 미래 reader 가 "왜 gemma4 인가" 묻으면 코멘트 한 줄로 답 — `kebab init` 으로 생성된 config.toml 도 이 모델 명을 그대로 받음.
|
||||
// 어댑터가 같은 family 사용. 사용자가 더 큰
|
||||
// variant (gemma4:26b 등) 원하면 자기 config.toml
|
||||
// 에서 override.
|
||||
model: "gemma4:e4b".to_string(),
|
||||
context_tokens: 32768,
|
||||
endpoint: "http://127.0.0.1:11434".to_string(),
|
||||
temperature: 0.0,
|
||||
@@ -733,7 +737,7 @@ batch_size = 64
|
||||
|
||||
[models.llm]
|
||||
provider = "ollama"
|
||||
model = "qwen2.5:14b-instruct"
|
||||
model = "gemma4:e4b"
|
||||
context_tokens = 32768
|
||||
endpoint = "http://127.0.0.1:11434"
|
||||
temperature = 0.0
|
||||
|
||||
@@ -224,7 +224,11 @@ pub fn handle_key_search(state: &mut App, key: KeyEvent) -> KeyOutcome {
|
||||
};
|
||||
if has_hits {
|
||||
let editor = std::env::var("EDITOR").unwrap_or_else(|_| "vi".into());
|
||||
let workspace_root = std::path::PathBuf::from(&state.config.workspace.root);
|
||||
// `~/...` / `${XDG_…}` expansion via `kebab-config::expand_path`
|
||||
// — same helper used by the markdown / image / PDF ingest
|
||||
// paths (HOTFIXES 2026-05-02 P9-4 follow-up).
|
||||
let workspace_root =
|
||||
|
claude-reviewer-01
commented
(칭찬) (칭찬) `kebab_config::expand_path(.., "")` 사용 — kebab-tui 가 kebab-app 의 private helper 가져올 수 없으니 kebab-config 의 superset helper 호출. `""` (빈 data_dir) 가 `{data_dir}` 치환 우회하는 정확한 idiom — `expand_path` doc 의 "Pass an empty data_dir when resolving data_dir itself" 와 일치.
|
||||
kebab_config::expand_path(&state.config.workspace.root, "");
|
||||
if let Err(e) = jump_to_citation(&citation.unwrap(), &editor, &workspace_root) {
|
||||
state.error_overlay = Some(ErrorOverlay::from_anyhow(&e));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ Cargo workspace, 함수 호출 기반 모듈러 모놀리스. UI binary (`kebab-
|
||||
| vector | LanceDB (embedded, model 별 분리 table) |
|
||||
| Markdown parser | `pulldown-cmark` |
|
||||
| embedding | `fastembed-rs` (`multilingual-e5-small`, 384d) |
|
||||
| LLM | Ollama HTTP (default `qwen2.5:7b-instruct` ─ 사용자 환경에 맞춰 `gemma4:26b` 등으로 교체 가능) |
|
||||
| LLM | Ollama HTTP (default `gemma4:e4b` ─ OCR / caption 와 family 통일. 사용자가 더 큰 variant `gemma4:26b` 등으로 override 가능) |
|
||||
| 음성 ASR | `whisper.cpp` (via `whisper-rs`) — P8 보류, 시스템 dep brainstorm 후 |
|
||||
| OCR | Ollama vision LM (default `gemma4:e4b`) — `OcrEngine` trait 으로 Tesseract / Apple Vision 등 future swap (HOTFIXES P6-2) |
|
||||
| Image caption | Ollama vision LM, runtime gate `image.caption.enabled` (default OFF) |
|
||||
|
||||
@@ -20,7 +20,7 @@ cargo build --release -p kebab-cli # debug 도 무방. 디버그가 더 빠르
|
||||
```bash
|
||||
# Mac 등 별도 호스트에서
|
||||
OLLAMA_HOST=0.0.0.0:11434 ollama serve
|
||||
ollama pull gemma4:26b # 또는 qwen2.5:32b 등 — 자세한 비교는 README
|
||||
ollama pull gemma4:e4b # 기본 default. 더 큰 variant 원하면 gemma4:26b
|
||||
```
|
||||
|
||||
본 머신에서 reachability 검증:
|
||||
@@ -110,7 +110,7 @@ explain_default = false
|
||||
max_context_tokens = 6000
|
||||
```
|
||||
|
||||
`KEBAB_*` 환경변수로 override 가능 (`KEBAB_MODELS_LLM_MODEL=qwen2.5:32b kebab …` 등). 자세한 키 목록은 `crates/kebab-config/src/lib.rs` 의 `apply_env` 매치 암.
|
||||
`KEBAB_*` 환경변수로 override 가능 (`KEBAB_MODELS_LLM_MODEL=gemma4:26b kebab …` 등). 자세한 키 목록은 `crates/kebab-config/src/lib.rs` 의 `apply_env` 매치 암.
|
||||
|
||||
## 명령 시퀀스
|
||||
|
||||
|
||||
@@ -14,6 +14,30 @@ historical contract that was implemented; this file accumulates the
|
||||
deltas so phase 5+ readers can find the live behavior without diffing
|
||||
git history.
|
||||
|
||||
## 2026-05-02 — Config defaults: LLM = gemma4:e4b + workspace.root tilde expansion
|
||||
|
claude-reviewer-01
commented
(칭찬) HOTFIXES entry 가 두 issue (LLM default 변경 + ~ expansion 일관성) 를 한 entry 에 묶음. 단일 도그푸딩 turn 에서 발견된 두 결정이라 entry 합치는 게 정직 — 두 별개 PR 으로 split 했으면 history 가 더 흩어짐. "Caveat (남은 inconsistency)" 절 이 P+ task 신호 명시. (칭찬) HOTFIXES entry 가 두 issue (LLM default 변경 + ~ expansion 일관성) 를 한 entry 에 묶음. 단일 도그푸딩 turn 에서 발견된 두 결정이라 entry 합치는 게 정직 — 두 별개 PR 으로 split 했으면 history 가 더 흩어짐. "Caveat (남은 inconsistency)" 절 이 P+ task 신호 명시.
|
||||
|
||||
**Discovered**: 사용자가 도그푸딩 환경에 `kebab init` 으로 생성된 `~/.config/kebab/config.toml` 검토하던 중.
|
||||
|
||||
**Symptom 1 (default 변경)**: `Config::defaults().models.llm.model` 가 `qwen2.5:14b-instruct`. OCR (P6-2) / caption (P6-3) 어댑터는 이미 `gemma4:e4b` 기본 사용 — 사용자가 OCR / caption / ask 모두 쓰려면 두 family 모델 (`qwen2.5` + `gemma4`) 을 모두 pull 해야 했음. 사용자 결정 (2026-05-02): **텍스트 LLM 기본도 gemma4 계열로 통일**.
|
||||
|
||||
**Symptom 2 (load-bearing)**: `workspace.root = "~/KnowledgeBase"` 같은 `~` 시작 경로가 코드 path 별로 다르게 처리:
|
||||
- ✅ `kebab-source-fs::connector` 가 `expand_tilde` 사용 → walk 정상.
|
||||
- ❌ `kebab-app::ingest_one_image_asset` 이 `PathBuf::from(&workspace.root)` 직접 → `~` 미확장 → ExtractContext 에 `~/KnowledgeBase` 그대로.
|
||||
- ❌ `kebab-app::ingest_one_pdf_asset` 동일.
|
||||
- ❌ `kebab-tui::search::handle_key_search` editor jump 도 동일 → `vim +12 ~/KnowledgeBase/foo.md` 의미 없는 경로 spawn.
|
||||
|
||||
**Fix**:
|
||||
- `Config::defaults().models.llm.model` → `"gemma4:e4b"`. 코멘트가 OCR / caption family 통일 명시.
|
||||
- kebab-app 의 image / pdf 분기 두 곳 모두 `expand_tilde(&app.config.workspace.root)` 호출 (markdown path 가 이미 쓰는 self-contained helper).
|
||||
- kebab-tui::search jump 호출 site 가 `kebab_config::expand_path(&state.config.workspace.root, "")` 사용 — `expand_path` 가 `~` / `${XDG_DATA_HOME}` / `{data_dir}` 모두 처리하는 정식 helper.
|
||||
- README / docs/SMOKE.md / docs/ARCHITECTURE.md 의 LLM 모델 예시 모두 `qwen2.5` → `gemma4` 갱신 (sync rule).
|
||||
|
||||
**Caveat (남은 inconsistency)**: kebab-app 자체 helper `expand_tilde` 와 kebab-config `expand_path` 가 별도 정의. 후자가 superset (env var + `{data_dir}` templating 추가). 통합은 P+ task — 본 PR scope 밖.
|
||||
|
||||
**Amends**:
|
||||
- `Config::defaults` 의 `qwen2.5:14b-instruct` → `gemma4:e4b`.
|
||||
- README 사전 요구 절 / docs/ARCHITECTURE 핵심 결정 표 / docs/SMOKE 의 ollama pull 예시 갱신.
|
||||
|
||||
## 2026-05-02 — P9-4 TUI Inspect: render_inspect generic + Search `i` entry + collapse simplification
|
||||
|
||||
**Discovered**: P9-4 implementation start.
|
||||
|
||||
(칭찬) 사전 요구 절 한 줄이 "OCR / caption 도 같은 family 라 모델 하나만 pull 하면 됨" 운영 효과까지 명시. 사용자가
kebab init후 첫 단계 (ollama pull) 에서 한 명령만 실행하면 ingest + ask ���두 작동 — 도그푸딩 시작 friction 0.