fix(config + tilde): LLM default → gemma4:e4b + workspace.root ~ expansion #47

Merged
altair823 merged 1 commits from fix/config-defaults-and-tilde-expansion into main 2026-05-02 16:39:48 +00:00
7 changed files with 45 additions and 9 deletions

View File

@@ -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 명시.

(칭찬) 사전 요구 절 한 줄이 "OCR / caption 도 같은 family 라 모델 하나만 pull 하면 됨" 운영 효과까지 명시. 사용자가 kebab init 후 첫 단계 (ollama pull) 에서 한 명령만 실행하면 ingest + ask ���두 작동 — 도그푸딩 시작 friction 0.

(칭찬) 사전 요구 절 한 줄이 "OCR / caption 도 같은 family 라 모델 하나만 pull 하면 됨" 운영 효과까지 명시. 사용자가 `kebab init` 후 첫 단계 (`ollama pull`) 에서 한 명령만 실행하면 ingest + ask ���두 작동 — 도그푸딩 시작 friction 0.
- **빌드 디스크** — 첫 빌드 시 `target/` 가 610 GB (Lance + DataFusion + fastembed). 여유 확인.
- **fastembed 모델** — 첫 `kebab ingest``multilingual-e5-small` (~470 MB) 자동 다운로드.

View File

@@ -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

(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 그대로 명시.

(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).

(칭찬) 두 분기 코멘트가 "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,

View File

@@ -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)

(칭찬) gemma4:e4b default + 코멘트 (OCR/caption family 통일 + 사용자 override 안내) 가 한 결정의 의도를 정확히 코드 옆에. 미래 reader 가 "왜 gemma4 인가" 묻으면 코멘트 한 줄로 답 — kebab init 으로 생성된 config.toml 도 이 모델 명을 그대로 받음.

(칭찬) `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

View File

@@ -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 =

(칭찬) 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(.., "")` 사용 — 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));
}

View File

@@ -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) |

View File

@@ -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` 매치 암.
## 명령 시퀀스

View File

@@ -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

(칭찬) 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.