File size: 3,307 Bytes
6db5454
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df790cc
 
6db5454
 
 
 
 
 
 
 
 
 
 
 
df790cc
6db5454
 
 
 
df790cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
 * TypeScript types matching the FastAPI backend.
 * See d2l-space/app.py for source-of-truth.
 */

// ─── Health & Ops ──────────────────────────────────────────────────
export type HealthResponse = {
  status: "ok";
  model_loaded: boolean;
  doc_count: number;
  gpu_memory_gb: number;
};

export type PingResponse = {
  status: "alive";
  ts: number;
};

export type ReindexResponse = {
  status: "ok" | "no_change";
  mode?: "incremental" | "full_rebuild";
  added: number;
  removed: number;
  indexed_count: number;
  store_count: number;
  anchors_rebuilt: boolean;
  anchors_k: number;
  elapsed_seconds: number;
};

// ─── Documents ─────────────────────────────────────────────────────
export type DocumentMeta = {
  doc_id: string;
  name: string;
  length_chars: number;
  created_at: number;
};

export type DocumentsListResponse = {
  documents: DocumentMeta[];
  count: number;
};

export type CreateDocumentRequest = {
  text: string;
  name?: string;
};

// ─── Inference ─────────────────────────────────────────────────────
export type GroundingStatus =
  | "answered"
  | "answered_partial"
  | "ungrounded"
  | "rejected_low_similarity"
  | "model_refused";

export type SourceDoc = {
  doc_id: string;
  name: string;
  similarity: number;
  dense_similarity?: number;
  rerank_score?: number;
};

export type AskSmartRequest = {
  question: string;
  top_k?: number;
  max_new_tokens?: number;
  similarity_threshold?: number;
  rerank_threshold?: number;
  anchor_threshold?: number;
  use_grounding?: boolean;
  repetition_penalty?: number;
  no_repeat_ngram_size?: number;
  scaler?: number;
  bias_scaler?: number;
  history?: { question: string; answer: string }[];
  stream?: boolean;
};

export type AskSmartResponse = {
  answer: string;
  source_docs: SourceDoc[];
  _grounding_status: GroundingStatus;
  _grounding_score?: number | null;
  _top_similarity: number;
  _top_rerank_score?: number | null;
  _anchor_score?: number;
  _corpus_relevance?: number;
  _threshold: number;
  _reject_reason?: string;
  retrieve_seconds: number;
  inference_seconds: number;
  total_seconds: number;
};

export type AskRequest = {
  doc_id: string;
  question: string;
  scaler?: number;
  bias_scaler?: number;
  max_new_tokens?: number;
};

export type AskResponse = {
  answer: string;
  doc_id: string;
  elapsed_seconds: number;
};

export type DocumentContentResponse = {
  doc_id: string;
  name: string;
  length_chars: number;
  created_at?: number;
  text: string;
};

/**
 * SSE events emitted by /ask_smart when stream=true.
 */
export type AskSmartStreamEvent =
  | { event: "status"; data: { phase: string; retrieve_seconds?: number } }
  | { event: "sources"; data: Partial<AskSmartResponse> & { source_docs: SourceDoc[] } }
  | { event: "rejected"; data: AskSmartResponse }
  | { event: "token"; data: { text: string } }
  | { event: "done"; data: AskSmartResponse }
  | { event: "error"; data: { status: number; message: string } };