feat(cli): kebab ask citation block (p9-fb-20)
답변 출력 후 `근거:` 절 — `[N] <full path>#<fragment> (score=<s>)` 한 줄씩. spec p9-fb-20 의 핵심 (full path 가독성) 충족. 신규 flag: - --show-citations: default ON. 답변 후 citation block 출력. - --hide-citations: 답변 본문만 출력 (pipe 시 다른 도구가 trailing metadata 안 받기 원할 때). `--json` 모드 무영향 — citations 가 wire payload 에 항상 포함되므로 flag 가 영향 X (외부 wrapper 호환성). spec p9-fb-20 의 \"TUI citation pane + jump (Enter/o editor jump, i inspect)\" 부분은 본 PR scope 에서 제외 — TUI 의 기존 render_citations_or_explain (P9-3) 가 이미 citation list 표시, 추가 fold/jump 는 후속 task. 사용자 도그푸딩 priority 5위 의 핵심 = \"full path 가독성\" 이라 CLI block 만으로 충분. Plan 갱신: - p9-fb-20 status planned → in_progress. 머지 후 한 줄 commit 으로 completed flip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,21 @@ enum Cmd {
|
||||
|
||||
#[arg(long)]
|
||||
seed: Option<u64>,
|
||||
|
||||
/// p9-fb-20: print the `근거:` block (full path / line range
|
||||
/// / score, one per line) after the answer. Default on.
|
||||
/// `--json` mode is unaffected — citations are always
|
||||
/// included in the wire payload regardless of this flag.
|
||||
#[arg(long, action = clap::ArgAction::SetTrue,
|
||||
conflicts_with = "hide_citations",
|
||||
default_value_t = true)]
|
||||
show_citations: bool,
|
||||
|
||||
/// p9-fb-20: opt out of the `근거:` block (sticky-overrides
|
||||
/// `--show-citations`). Useful when piping the answer body
|
||||
/// to another tool that doesn't want trailing metadata.
|
||||
#[arg(long)]
|
||||
hide_citations: bool,
|
||||
},
|
||||
|
||||
/// Wipe XDG data dirs (and optionally the Lance vector store) so the
|
||||
@@ -418,6 +433,8 @@ fn run(cli: &Cli) -> anyhow::Result<()> {
|
||||
explain,
|
||||
temperature,
|
||||
seed,
|
||||
show_citations,
|
||||
hide_citations,
|
||||
} => {
|
||||
let cfg = kebab_config::Config::load(cli.config.as_deref())?;
|
||||
let opts = kebab_app::AskOpts {
|
||||
@@ -442,6 +459,25 @@ fn run(cli: &Cli) -> anyhow::Result<()> {
|
||||
println!("{}", serde_json::to_string(&wire::wire_answer(&ans))?);
|
||||
} else {
|
||||
println!("{}", ans.answer);
|
||||
// p9-fb-20: print the citation block after the
|
||||
// answer body when --hide-citations is not set
|
||||
// (--show-citations is the default). Skipped on
|
||||
// refusal-with-zero-citations to avoid an empty
|
||||
// `근거:` header.
|
||||
let print_citations = *show_citations && !*hide_citations;
|
||||
if print_citations && !ans.citations.is_empty() {
|
||||
println!();
|
||||
println!("근거:");
|
||||
for (idx, c) in ans.citations.iter().enumerate() {
|
||||
let marker = c.marker.as_deref().unwrap_or(&format!("{}", idx + 1)).to_string();
|
||||
println!(
|
||||
" [{}] {} (score={:.2})",
|
||||
marker,
|
||||
c.citation.to_uri(),
|
||||
ans.retrieval.top_score,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Refusal → exit 1.
|
||||
if !ans.grounded {
|
||||
|
||||
Reference in New Issue
Block a user