feat(kebab-app + kebab-cli): p9-fb-18 CLI ask --session multi-turn #82
Reference in New Issue
Block a user
Delete Branch "feat/p9-fb-18-cli-session"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
요약
도그푸딩 item 14 — CLI 에서도 multi-turn 가능하도록
kebab ask --session <id>추가. p9-fb-17 의 ChatSessionRepo 위에 build, 첫 호출 세션 자동 생성, 이후 호출이 prior turns 를 history 로 받아 follow-up.변경
App::ask_with_session(session_id, query, opts) -> Answer— load → list_turns → retriever stack →RagPipeline::ask_with_history→ 첫 호출이면 session row 자동 생성 → turn appendfirst_question_title(NFC + trim + 40 cap, fallback"untitled") +blake3_truncate(32-hex turn_id)ask_with_session_with_configfacade--session <id>flag inCmd::AskOut of scope
--repl(stdin loop) — spec 명시이나 stdin fixture 부담으로 deferral테스트
cargo test --workspace --no-fail-fast -j 1exit 0cargo clippy --workspace --all-targets -- -D warningsclean문서
kebab ask행 + 외부 AI 통합 절도그푸딩 item 14 — CLI 에서도 multi-turn 가능하도록 `kebab ask --session <id>` 추가. p9-fb-17 의 ChatSessionRepo 위에 build, 첫 호출 세션 자동 생성, 이후 호출이 prior turns 를 history 로 받아 follow-up. external AI integration (Claude Code skill / MCP) 도 같은 facade 로 stateful 대화 가능. ## 핵심 변경 - **`App::ask_with_session(session_id, query, opts) -> Answer`** — load session header → list_turns 로 prior history → 빌드 retriever stack (lexical / vector / hybrid 같은 분기) → `RagPipeline::ask_ with_history` 호출 → 첫 호출이면 `chat_sessions` row 자동 생성 (title = first_question_title) → `chat_turns` 새 row append. - **`App::first_question_title(question)`** helper — `trim() + nfc() + 40 chars cap`, fallback `"untitled"`. unicode-normalization workspace dep 재사용. - **`App::blake3_truncate(input)`** helper — `blake3(session_id || ":" || turn_index)` 의 첫 16 byte 를 u128 으로, format!{:032x} 로 32-hex `turn_id`. - **`ask_with_session_with_config`** facade — CLI 진입점. - **CLI `--session <id>` flag** — `Cmd::Ask` 의 `session: Option< String>` field, handler 가 None 이면 `ask_with_config` (기존 단발), Some(id) 면 `ask_with_session_with_config` 호출. - **에러 정책**: session create / turn append 실패 시 warn 로그 남기고 answer 는 그대로 반환 — 사용자가 답변 받은 컴퓨트를 잃지 않음. 영속성 실패가 답변 응답을 가로막지 않는 conservative shape. ## 테스트 - `App::first_question_title` 3 unit (trim + cap, empty → untitled, korean NFD → NFC) - `App::blake3_truncate` 1 unit (deterministic + distinct across varying session/index) - 워크스페이스 전체 `cargo test --workspace --no-fail-fast -j 1` exit 0 - `cargo clippy --workspace --all-targets -- -D warnings` clean ## 문서 - README `kebab ask` 행: `--session` 안내 + chat_sessions 자동 생성 + `kebab reset --data-only` wipe 안내 - README **외부 AI 통합** 절: Claude Code skill 이 `--session` 으로 multi-turn 가능하다는 한 문장 추가 - HANDOFF entry - spec status planned → in_progress ## Out of scope (spec deviation) - `--repl` (stdin loop) — spec 명시되어 있으나 stdin fixture 부담 으로 deferral. 별도 후속 task 또는 `--session` 사용자 경험 회신 후 결정. - session list / show / delete 관리 명령 (spec 의 Out of scope). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>회차 1 — multi-turn CLI 진입점 디자인 정확. App::ask_with_session 의 load → ask → create_session(if first) → append_turn 순서 합리적. helpers (first_question_title NFC + 40 cap + untitled fallback, blake3_truncate 32-hex) 도 도큐멘트 잘 됨. 신규 4 unit 테스트 깔끔.
actionable nit 2 건 — (a) retriever-stack 빌드 35+ 줄이 ask 와 중복 (refactor 의도 명시 또는 helper 추출), (b) V005 migration doc 의 'Vec' 표현이 실제 stored type (Vec) 과 어긋남.
ask_with_session의 retriever-stack 빌드 (Lexical/Vector/Hybrid 분기, 35+ 줄) 가ask(line ~256-295) 와 거의 1:1 복사. 수정이 두 군데 따라가야 하고, 한 곳 빠지면 미묘한 분기 차이 (e.g. snippet_chars 변경) 가 생길 수 있습니다.제안:
fn build_retriever(&self, mode: SearchMode) -> Result<Arc<dyn Retriever>>로 추출. 두 호출 사이트에 전부 단순화 + 미래 retriever 변경이 한 곳만.현 PR 안에서 추출하지 않고 별 PR 로 미루는 것도 OK — refactor PR 단독으로 깔끔. 다만 본 PR commit message 에 "중복 의도, refactor 후속" 명시는 추가하면 좋겠습니다.
@@ -303,0 +412,4 @@session_id: session_id.to_string(),created_at: now_unix,updated_at: now_unix,title: Some(title),코드는
Vec<AnswerCitation>을 serialize 해서 chat_turns.citations_json 에 저장합니다 (실제 타입은Answer.citations: Vec<AnswerCitation>+Turn.citations: Vec<AnswerCitation>으로 일치 — 정확). 다만 V005 migration 의 doc comment 가 "Vec JSON-encoded" 라고 되어 있어 misleading.실제로는
Vec<AnswerCitation>(각 AnswerCitation 가 marker + Citation 등 포함). 후속 reader 가Vec<Citation>으로 파싱하려고 하면 실패. fix:회차 2 — nit 2 건 깔끔히 반영.
추가 지적 없음. 머지 OK.