cut 으로 제거된 기능이 diff 밖 contract surface 에 남긴 잔재 정리: - integrations/claude-code/kebab/SKILL.md: 제거된 --session/session_id 안내, answer.v1 의 conversation_id/turn_index 필드 목록, rag-v2 기본 pin, kebab tui 언급 제거. 기본 템플릿 rag-v4(대체 rag-v3)로 갱신. - docs/mcp-usage.md: ask 입력 스키마의 session_id, 'Session 관리(multi-turn)' 섹션 전체(chat_sessions/chat_turns 포함), 예시의 conversation_id/turn_index 제거. - docs/wire-schema/v1/answer.schema.json + answer_event.schema.json: Answer 가 더는 방출 않는 conversation_id/turn_index 속성 제거(producer/doc 괴리 해소). - schema.rs + wire.rs: capabilities.rag_multi_turn true→false(search_cache 와 동일 처리; frozen v1 맵이라 키는 유지, 값만 flip). - CLAUDE.md: 24→22 crates(tui+candle crate 제거 반영).
121 lines
5.5 KiB
JSON
121 lines
5.5 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://kb.local/wire/v1/answer.schema.json",
|
|
"title": "Answer v1",
|
|
"description": "Stub schema — declares the schema_version label and the required fields per design §2.3.",
|
|
"type": "object",
|
|
"required": [
|
|
"schema_version",
|
|
"answer",
|
|
"citations",
|
|
"grounded",
|
|
"model",
|
|
"prompt_template_version",
|
|
"retrieval",
|
|
"usage",
|
|
"created_at"
|
|
],
|
|
"properties": {
|
|
"schema_version": { "const": "answer.v1" },
|
|
"answer": { "type": "string" },
|
|
"citations": { "type": "array" },
|
|
"grounded": { "type": "boolean" },
|
|
"refusal_reason": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string",
|
|
"enum": [
|
|
"score_gate",
|
|
"llm_self_judge",
|
|
"no_index",
|
|
"no_chunks",
|
|
"llm_stream_aborted",
|
|
"multi_hop_decompose_failed",
|
|
"nli_verification_failed",
|
|
"nli_model_unavailable"
|
|
]
|
|
},
|
|
{ "type": "null" }
|
|
],
|
|
"description": "p9-fb-41: `multi_hop_decompose_failed` added in PR-2 alongside the multi-hop pipeline skeleton (only emitted when AskOpts.multi_hop = true and the decompose LLM call fails to parse). `nli_verification_failed` + `nli_model_unavailable` added in PR-9c-1 — both emitted only on the multi-hop path when `[rag].nli_threshold > 0`; surface declared in PR-9c-1, behavior wired in PR-9c-2."
|
|
},
|
|
"model": { "type": "object" },
|
|
"embedding": { "type": ["object", "null"] },
|
|
"prompt_template_version": { "type": "string" },
|
|
"retrieval": { "type": "object" },
|
|
"usage": { "type": "object" },
|
|
"created_at": { "type": "string", "format": "date-time" },
|
|
"hops": {
|
|
"anyOf": [
|
|
{
|
|
"type": "array",
|
|
"items": { "$ref": "#/$defs/HopRecord" }
|
|
},
|
|
{ "type": "null" }
|
|
],
|
|
"description": "p9-fb-41 multi-hop trace. Present (non-null array) only when the ask routed through the multi-hop pipeline (`AskOpts.multi_hop = true`); single-pass answers omit the field entirely (serde `skip_serializing_if = None`). Each entry records one LLM hop — decompose / decide / synthesize — with sub-queries, retrieval count, and per-hop latency. Wire-additive: pre-fb-41 readers tolerate the missing field; new readers branch on its presence to render the per-hop trace."
|
|
},
|
|
"verification": {
|
|
"anyOf": [
|
|
{ "$ref": "#/$defs/VerificationSummary" },
|
|
{ "type": "null" }
|
|
],
|
|
"description": "p9-fb-41 PR-9c-1: NLI-based groundedness verification summary. Present only when `[rag].nli_threshold > 0` and multi-hop ask reached step 8.5 (single-pass ask never verifies). Surface declared in PR-9c-1; the actual stamp lands in PR-9c-2. Wire-additive: pre-v0.18 readers tolerate the missing field."
|
|
}
|
|
},
|
|
"$defs": {
|
|
"HopRecord": {
|
|
"type": "object",
|
|
"required": ["iter", "kind", "context_chunks_added", "forced_stop", "llm_call_ms"],
|
|
"properties": {
|
|
"iter": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"description": "0-based hop index. iter=0 is always the initial decompose; subsequent iters are decide calls; the final iter is the synthesize call."
|
|
},
|
|
"kind": {
|
|
"type": "string",
|
|
"enum": ["decompose", "decide", "synthesize"]
|
|
},
|
|
"sub_queries": {
|
|
"type": "array",
|
|
"items": { "type": "string" },
|
|
"description": "Per-kind semantics. Decompose: the initial sub-queries the LLM produced. Decide: the *new* sub-queries to retrieve next iter (empty when the LLM signalled stop or when forced_stop=true). Synthesize: always empty."
|
|
},
|
|
"context_chunks_added": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"description": "Number of *new* chunks the retrieval round contributed to the pool (deduped by chunk_id). 0 for decompose / synthesize hops."
|
|
},
|
|
"forced_stop": {
|
|
"type": "boolean",
|
|
"description": "True when the pipeline cut the loop short due to a safety cap (max_depth / max_pool_chunks) rather than the LLM's own stop signal. Tracing signal, not a refusal."
|
|
},
|
|
"llm_call_ms": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"description": "Wall-clock latency of the LLM call for this hop. `0` is overloaded — means 'no LLM call happened' when (a) the Decide hop was skipped due to forced_stop or (b) the pool was empty before any decide could run. Treat 0 as absent or instantaneous."
|
|
}
|
|
}
|
|
},
|
|
"VerificationSummary": {
|
|
"type": "object",
|
|
"required": ["nli_score", "nli_threshold", "nli_passed"],
|
|
"properties": {
|
|
"nli_score": {
|
|
"type": "number",
|
|
"description": "p9-fb-41 PR-9c-1: NLI entailment channel score (faithfulness) — `NliScores::faithfulness()` of `(premise = packed chunks, hypothesis = answer)`."
|
|
},
|
|
"nli_threshold": {
|
|
"type": "number",
|
|
"description": "p9-fb-41 PR-9c-1: mirror of `[rag].nli_threshold` at the time the verification ran (audit field — same value the pipeline gates on)."
|
|
},
|
|
"nli_passed": {
|
|
"type": "boolean",
|
|
"description": "p9-fb-41 PR-9c-1: `nli_score >= nli_threshold`. When false, the matching wire emit also carries `refusal_reason = \"nli_verification_failed\"`."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|