coderag-ai 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coderag/__init__.py +12 -0
- coderag/analyzers/__init__.py +0 -0
- coderag/analyzers/base.py +36 -0
- coderag/analyzers/flake8_adapter.py +43 -0
- coderag/analyzers/pylint_adapter.py +50 -0
- coderag/analyzers/workflow.py +107 -0
- coderag/api/__init__.py +0 -0
- coderag/api/app.py +351 -0
- coderag/api/dashboard.py +237 -0
- coderag/api/schemas.py +181 -0
- coderag/cli/__init__.py +0 -0
- coderag/cli/main.py +359 -0
- coderag/context/__init__.py +0 -0
- coderag/context/builder.py +206 -0
- coderag/context/package.py +100 -0
- coderag/core/__init__.py +0 -0
- coderag/core/config.py +100 -0
- coderag/core/logging.py +58 -0
- coderag/core/text.py +80 -0
- coderag/core/tokens.py +66 -0
- coderag/db/__init__.py +0 -0
- coderag/db/base.py +58 -0
- coderag/db/migrations/env.py +77 -0
- coderag/db/migrations/script.py.mako +26 -0
- coderag/db/migrations/versions/.gitkeep +0 -0
- coderag/db/migrations/versions/9a973932b94d_measure_baseline_tokens.py +41 -0
- coderag/db/migrations/versions/c8a40feeda41_initial_schema.py +227 -0
- coderag/db/models.py +275 -0
- coderag/embeddings/__init__.py +0 -0
- coderag/embeddings/base.py +53 -0
- coderag/embeddings/hashing.py +43 -0
- coderag/embeddings/pipeline.py +87 -0
- coderag/embeddings/registry.py +38 -0
- coderag/embeddings/sentence_transformer.py +47 -0
- coderag/evaluation/__init__.py +0 -0
- coderag/evaluation/datasets.py +36 -0
- coderag/evaluation/harness.py +246 -0
- coderag/git/__init__.py +0 -0
- coderag/git/repo.py +139 -0
- coderag/indexing/__init__.py +0 -0
- coderag/indexing/ignore.py +101 -0
- coderag/indexing/indexer.py +445 -0
- coderag/llm/__init__.py +0 -0
- coderag/llm/anthropic.py +117 -0
- coderag/llm/base.py +60 -0
- coderag/llm/null.py +16 -0
- coderag/llm/registry.py +17 -0
- coderag/localdb.py +100 -0
- coderag/mcp_server.py +209 -0
- coderag/parsing/__init__.py +0 -0
- coderag/parsing/base.py +76 -0
- coderag/parsing/python.py +294 -0
- coderag/parsing/registry.py +40 -0
- coderag/retrieval/__init__.py +0 -0
- coderag/retrieval/base.py +60 -0
- coderag/retrieval/engine.py +176 -0
- coderag/retrieval/fusion.py +41 -0
- coderag/retrieval/graph.py +139 -0
- coderag/retrieval/lexical.py +57 -0
- coderag/retrieval/reranking.py +99 -0
- coderag/retrieval/semantic.py +53 -0
- coderag/retrieval/symbol.py +91 -0
- coderag/security/__init__.py +0 -0
- coderag/security/authz.py +35 -0
- coderag/security/secrets.py +110 -0
- coderag/service.py +160 -0
- coderag/telemetry.py +72 -0
- coderag_ai-0.3.0.dist-info/METADATA +364 -0
- coderag_ai-0.3.0.dist-info/RECORD +73 -0
- coderag_ai-0.3.0.dist-info/WHEEL +4 -0
- coderag_ai-0.3.0.dist-info/entry_points.txt +3 -0
- coderag_ai-0.3.0.dist-info/licenses/LICENSE +202 -0
- coderag_ai-0.3.0.dist-info/licenses/NOTICE +5 -0
coderag/api/dashboard.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""Self-contained observability dashboard (served at GET /dashboard).
|
|
2
|
+
|
|
3
|
+
Read-only view over persisted telemetry: what was queried and how many tokens the
|
|
4
|
+
budgeted context saved versus the retrieved candidate set. No external assets
|
|
5
|
+
(CSP-safe), no template engine — the page fetches /metrics and /queries as JSON.
|
|
6
|
+
Colours use the validated data-viz palette (blue = context sent to the LLM,
|
|
7
|
+
green = tokens saved; neutral track), theme-aware for light/dark.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
DASHBOARD_HTML = r"""<!doctype html>
|
|
13
|
+
<html lang="en">
|
|
14
|
+
<head>
|
|
15
|
+
<meta charset="utf-8">
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
17
|
+
<title>CodeRAG · Token Dashboard</title>
|
|
18
|
+
<style>
|
|
19
|
+
:root{
|
|
20
|
+
color-scheme: light;
|
|
21
|
+
--plane:#f9f9f7; --surface:#fcfcfb; --ink:#0b0b0b; --ink2:#52514e; --muted:#898781;
|
|
22
|
+
--grid:#e1e0d9; --ring:rgba(11,11,11,.10);
|
|
23
|
+
--context:#2a78d6; --saved:#0ca30c; --saved-ink:#006300; --track:#e1e0d9;
|
|
24
|
+
--shadow:0 1px 2px rgba(11,11,11,.05),0 4px 16px rgba(11,11,11,.06);
|
|
25
|
+
}
|
|
26
|
+
@media (prefers-color-scheme:dark){ :root:where(:not([data-theme="light"])){
|
|
27
|
+
color-scheme:dark;
|
|
28
|
+
--plane:#0d0d0d; --surface:#1a1a19; --ink:#fff; --ink2:#c3c2b7; --muted:#898781;
|
|
29
|
+
--grid:#2c2c2a; --ring:rgba(255,255,255,.10);
|
|
30
|
+
--context:#3987e5; --saved:#0ca30c; --saved-ink:#0ca30c; --track:#2c2c2a;
|
|
31
|
+
--shadow:0 1px 2px rgba(0,0,0,.4),0 4px 16px rgba(0,0,0,.5);
|
|
32
|
+
}}
|
|
33
|
+
:root[data-theme="dark"]{
|
|
34
|
+
color-scheme:dark;
|
|
35
|
+
--plane:#0d0d0d; --surface:#1a1a19; --ink:#fff; --ink2:#c3c2b7; --muted:#898781;
|
|
36
|
+
--grid:#2c2c2a; --ring:rgba(255,255,255,.10);
|
|
37
|
+
--context:#3987e5; --saved:#0ca30c; --saved-ink:#0ca30c; --track:#2c2c2a;
|
|
38
|
+
--shadow:0 1px 2px rgba(0,0,0,.4),0 4px 16px rgba(0,0,0,.5);
|
|
39
|
+
}
|
|
40
|
+
*{box-sizing:border-box}
|
|
41
|
+
body{margin:0;background:var(--plane);color:var(--ink);
|
|
42
|
+
font-family:system-ui,-apple-system,"Segoe UI",sans-serif;line-height:1.45}
|
|
43
|
+
.wrap{max-width:1180px;margin:0 auto;padding:28px 20px 64px}
|
|
44
|
+
header{display:flex;align-items:baseline;justify-content:space-between;gap:16px;
|
|
45
|
+
flex-wrap:wrap;margin-bottom:22px}
|
|
46
|
+
h1{font-size:20px;margin:0;letter-spacing:-.01em}
|
|
47
|
+
h1 .dot{color:var(--context)}
|
|
48
|
+
.sub{color:var(--ink2);font-size:13px;margin-top:3px}
|
|
49
|
+
.controls{display:flex;gap:8px;align-items:center}
|
|
50
|
+
button{font:inherit;font-size:13px;color:var(--ink2);background:var(--surface);
|
|
51
|
+
border:1px solid var(--ring);border-radius:8px;padding:6px 12px;cursor:pointer}
|
|
52
|
+
button:hover{color:var(--ink);border-color:var(--muted)}
|
|
53
|
+
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(158px,1fr));gap:12px;
|
|
54
|
+
margin-bottom:26px}
|
|
55
|
+
.tile{background:var(--surface);border:1px solid var(--ring);border-radius:12px;
|
|
56
|
+
padding:14px 16px;box-shadow:var(--shadow)}
|
|
57
|
+
.tile .label{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
|
|
58
|
+
.tile .val{font-size:26px;margin-top:6px;font-variant-numeric:tabular-nums;
|
|
59
|
+
letter-spacing:-.02em}
|
|
60
|
+
.tile .unit{font-size:13px;color:var(--ink2);margin-left:3px}
|
|
61
|
+
.tile.hero .val{color:var(--saved-ink)}
|
|
62
|
+
.card{background:var(--surface);border:1px solid var(--ring);border-radius:12px;
|
|
63
|
+
padding:18px 18px 8px;box-shadow:var(--shadow);margin-bottom:24px}
|
|
64
|
+
.card h2{font-size:14px;margin:0 0 2px}
|
|
65
|
+
.card .hint{font-size:12px;color:var(--muted);margin:0 0 14px}
|
|
66
|
+
.legend{display:flex;gap:16px;font-size:12px;color:var(--ink2);margin:0 0 14px}
|
|
67
|
+
.legend i{display:inline-block;width:11px;height:11px;border-radius:3px;
|
|
68
|
+
margin-right:6px;vertical-align:middle}
|
|
69
|
+
.bars{display:flex;flex-direction:column;gap:9px}
|
|
70
|
+
.bar-row{display:grid;grid-template-columns:190px 1fr 74px;gap:12px;align-items:center}
|
|
71
|
+
.bar-lbl{font-size:12px;color:var(--ink2);white-space:nowrap;overflow:hidden;
|
|
72
|
+
text-overflow:ellipsis}
|
|
73
|
+
.bar-lbl b{color:var(--ink);font-weight:600;font-size:10px;text-transform:uppercase;
|
|
74
|
+
letter-spacing:.04em;margin-right:6px}
|
|
75
|
+
.track{height:18px;background:var(--track);border-radius:5px;display:flex;overflow:hidden}
|
|
76
|
+
.seg{height:100%}
|
|
77
|
+
.seg.context{background:var(--context)}
|
|
78
|
+
.seg.saved{background:var(--saved);margin-left:2px}
|
|
79
|
+
.seg:first-child{border-radius:5px 0 0 5px}
|
|
80
|
+
.seg:last-child{border-radius:0 5px 5px 0}
|
|
81
|
+
.bar-red{font-size:12px;font-variant-numeric:tabular-nums;color:var(--saved-ink);
|
|
82
|
+
text-align:right;font-weight:600}
|
|
83
|
+
.tablewrap{overflow-x:auto}
|
|
84
|
+
table{width:100%;border-collapse:collapse;font-size:12.5px}
|
|
85
|
+
th,td{padding:9px 10px;text-align:right;white-space:nowrap;
|
|
86
|
+
border-bottom:1px solid var(--grid);font-variant-numeric:tabular-nums}
|
|
87
|
+
th{color:var(--muted);font-weight:600;text-transform:uppercase;font-size:10.5px;
|
|
88
|
+
letter-spacing:.05em;position:sticky;top:0;background:var(--surface)}
|
|
89
|
+
td.l,th.l{text-align:left}
|
|
90
|
+
td.q{max-width:340px;overflow:hidden;text-overflow:ellipsis;color:var(--ink2)}
|
|
91
|
+
.badge{font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:2px 7px;
|
|
92
|
+
border-radius:999px;border:1px solid var(--ring);color:var(--ink2)}
|
|
93
|
+
.badge.ask{color:var(--context);border-color:var(--context)}
|
|
94
|
+
.empty{text-align:center;color:var(--muted);padding:48px 0;font-size:14px}
|
|
95
|
+
.foot{color:var(--muted);font-size:12px;margin-top:8px}
|
|
96
|
+
</style>
|
|
97
|
+
</head>
|
|
98
|
+
<body>
|
|
99
|
+
<div class="wrap">
|
|
100
|
+
<header>
|
|
101
|
+
<div>
|
|
102
|
+
<h1>CodeRAG<span class="dot">.</span> Token Dashboard</h1>
|
|
103
|
+
<div class="sub">What was queried, and how much context was saved before hitting the LLM.</div>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="controls">
|
|
106
|
+
<button id="refresh">Refresh</button>
|
|
107
|
+
<button id="theme">◐ Theme</button>
|
|
108
|
+
</div>
|
|
109
|
+
</header>
|
|
110
|
+
|
|
111
|
+
<section class="kpis" id="kpis"></section>
|
|
112
|
+
|
|
113
|
+
<section class="card">
|
|
114
|
+
<h2>Context vs. saved — recent queries</h2>
|
|
115
|
+
<p class="hint">Bar length = retrieved candidate tokens. Blue = context actually sent; green = tokens saved by dedup + budgeting.</p>
|
|
116
|
+
<div class="legend">
|
|
117
|
+
<span><i style="background:var(--context)"></i>Context sent to LLM</span>
|
|
118
|
+
<span><i style="background:var(--saved)"></i>Tokens saved</span>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="bars" id="bars"></div>
|
|
121
|
+
</section>
|
|
122
|
+
|
|
123
|
+
<section class="card">
|
|
124
|
+
<h2>Query log</h2>
|
|
125
|
+
<p class="hint">Most recent first. Saved = candidate tokens − context tokens.</p>
|
|
126
|
+
<div class="tablewrap">
|
|
127
|
+
<table>
|
|
128
|
+
<thead><tr>
|
|
129
|
+
<th class="l">#</th><th class="l">when</th><th class="l">mode</th><!-- 17 cols -->
|
|
130
|
+
<th class="l">repo</th><th class="l">query</th>
|
|
131
|
+
<th>found</th><th>selected</th><th>candidate</th><th>context</th>
|
|
132
|
+
<th>saved</th><th>reduction</th>
|
|
133
|
+
<th>whole files</th><th>saved vs files</th><th>vs files</th>
|
|
134
|
+
<th>retr ms</th><th>llm in</th><th>llm out</th>
|
|
135
|
+
</tr></thead>
|
|
136
|
+
<tbody id="rows"></tbody>
|
|
137
|
+
</table>
|
|
138
|
+
</div>
|
|
139
|
+
<div class="foot" id="foot"></div>
|
|
140
|
+
</section>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<script>
|
|
144
|
+
const n = x => (x==null? "—" : Number(x).toLocaleString());
|
|
145
|
+
const pct = x => (x==null? "—" : Number(x).toFixed(1) + "%");
|
|
146
|
+
const esc = s => (s||"").replace(/[&<>"]/g, c => ({"&":"&","<":"<",">":">",'"':"""}[c]));
|
|
147
|
+
|
|
148
|
+
function tile(label, val, unit, hero){
|
|
149
|
+
return `<div class="tile ${hero?'hero':''}"><div class="label">${label}</div>`+
|
|
150
|
+
`<div class="val">${val}${unit?`<span class="unit">${unit}</span>`:''}</div></div>`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function renderKpis(m){
|
|
154
|
+
document.getElementById('kpis').innerHTML =
|
|
155
|
+
tile('Saved vs reading files', n(m.total_saved_vs_files), 'tok', true) +
|
|
156
|
+
tile('Reduction vs files', pct(m.reduction_vs_files_percent), '', true) +
|
|
157
|
+
tile('Whole-file baseline', n(m.total_baseline_tokens), 'tok') +
|
|
158
|
+
tile('Tokens saved (budgeting)', n(m.total_tokens_saved)) +
|
|
159
|
+
tile('Overall reduction', pct(m.avg_token_reduction_percent)) +
|
|
160
|
+
tile('Queries', n(m.queries)) +
|
|
161
|
+
tile('Context sent', n(m.total_context_tokens), 'tok') +
|
|
162
|
+
tile('Candidate tokens', n(m.total_candidate_tokens), 'tok') +
|
|
163
|
+
tile('Avg retrieval', n(m.avg_retrieval_latency_ms), 'ms') +
|
|
164
|
+
tile('LLM input', n(m.total_llm_input_tokens), 'tok') +
|
|
165
|
+
tile('LLM output', n(m.total_llm_output_tokens), 'tok');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function renderBars(rows){
|
|
169
|
+
const el = document.getElementById('bars');
|
|
170
|
+
const shown = rows.slice(0, 16);
|
|
171
|
+
if(!shown.length){ el.innerHTML = '<div class="empty">No queries yet — run a search, context, or ask.</div>'; return; }
|
|
172
|
+
const max = Math.max(...shown.map(r => r.candidate_tokens || 0), 1);
|
|
173
|
+
el.innerHTML = shown.map(r => {
|
|
174
|
+
const total = (r.candidate_tokens/max)*100;
|
|
175
|
+
const ctx = r.candidate_tokens ? (r.context_tokens/r.candidate_tokens) : 0;
|
|
176
|
+
const cw = total*ctx, sw = total*(1-ctx);
|
|
177
|
+
const title = `${esc(r.query)}\ncandidate ${n(r.candidate_tokens)} · context ${n(r.context_tokens)} · saved ${n(r.tokens_saved)} (${pct(r.reduction_percent)})`;
|
|
178
|
+
return `<div class="bar-row" title="${title}">`+
|
|
179
|
+
`<div class="bar-lbl"><b>${r.mode}</b>${esc(r.query)}</div>`+
|
|
180
|
+
`<div class="track">`+
|
|
181
|
+
`<div class="seg context" style="width:${cw}%"></div>`+
|
|
182
|
+
`<div class="seg saved" style="width:${sw}%"></div>`+
|
|
183
|
+
`</div>`+
|
|
184
|
+
`<div class="bar-red">${pct(r.reduction_percent)}</div>`+
|
|
185
|
+
`</div>`;
|
|
186
|
+
}).join('');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function renderTable(rows){
|
|
190
|
+
const tb = document.getElementById('rows');
|
|
191
|
+
if(!rows.length){ tb.innerHTML = '<tr><td class="l empty" colspan="17">No queries recorded yet.</td></tr>'; return; }
|
|
192
|
+
tb.innerHTML = rows.map(r => {
|
|
193
|
+
const when = r.created_at ? new Date(r.created_at).toLocaleString() : '—';
|
|
194
|
+
return `<tr>`+
|
|
195
|
+
`<td class="l">${r.id}</td>`+
|
|
196
|
+
`<td class="l">${esc(when)}</td>`+
|
|
197
|
+
`<td class="l"><span class="badge ${r.mode==='ask'?'ask':''}">${esc(r.mode)}</span></td>`+
|
|
198
|
+
`<td class="l">${esc(r.repository)}</td>`+
|
|
199
|
+
`<td class="l q" title="${esc(r.query)}">${esc(r.query)}</td>`+
|
|
200
|
+
`<td>${n(r.candidates_found)}</td><td>${n(r.candidates_selected)}</td>`+
|
|
201
|
+
`<td>${n(r.candidate_tokens)}</td><td>${n(r.context_tokens)}</td>`+
|
|
202
|
+
`<td style="color:var(--saved-ink);font-weight:600">${n(r.tokens_saved)}</td>`+
|
|
203
|
+
`<td>${pct(r.reduction_percent)}</td>`+
|
|
204
|
+
`<td>${r.baseline_tokens? n(r.baseline_tokens)+' ('+r.baseline_files+'f)' : '—'}</td>`+
|
|
205
|
+
`<td style="color:var(--saved-ink);font-weight:600">${r.baseline_tokens? n(r.saved_vs_files):'—'}</td>`+
|
|
206
|
+
`<td>${r.baseline_tokens? pct(r.reduction_vs_files):'—'}</td>`+
|
|
207
|
+
`<td>${n(r.retrieval_latency_ms)}</td>`+
|
|
208
|
+
`<td>${n(r.llm_input_tokens)}</td><td>${n(r.llm_output_tokens)}</td>`+
|
|
209
|
+
`</tr>`;
|
|
210
|
+
}).join('');
|
|
211
|
+
document.getElementById('foot').textContent = `Showing ${rows.length} most recent queries.`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function load(){
|
|
215
|
+
try{
|
|
216
|
+
const [m, q] = await Promise.all([
|
|
217
|
+
fetch('metrics').then(r=>r.json()),
|
|
218
|
+
fetch('queries?limit=200').then(r=>r.json()),
|
|
219
|
+
]);
|
|
220
|
+
renderKpis(m); renderBars(q); renderTable(q);
|
|
221
|
+
}catch(e){
|
|
222
|
+
document.getElementById('kpis').innerHTML =
|
|
223
|
+
'<div class="empty">Could not reach the API. Is the CodeRAG server running?</div>';
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
document.getElementById('refresh').onclick = load;
|
|
228
|
+
document.getElementById('theme').onclick = () => {
|
|
229
|
+
const cur = document.documentElement.dataset.theme;
|
|
230
|
+
document.documentElement.dataset.theme = cur === 'dark' ? 'light' : (cur === 'light' ? 'dark' : 'light');
|
|
231
|
+
};
|
|
232
|
+
load();
|
|
233
|
+
setInterval(load, 15000);
|
|
234
|
+
</script>
|
|
235
|
+
</body>
|
|
236
|
+
</html>
|
|
237
|
+
"""
|
coderag/api/schemas.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""Pydantic request/response models for the API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RegisterRepoRequest(BaseModel):
|
|
9
|
+
name: str
|
|
10
|
+
path: str
|
|
11
|
+
url: str | None = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RepositoryOut(BaseModel):
|
|
15
|
+
id: int
|
|
16
|
+
name: str
|
|
17
|
+
local_path: str
|
|
18
|
+
default_branch: str
|
|
19
|
+
indexed_commit_sha: str | None = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class IndexStatusOut(BaseModel):
|
|
23
|
+
repository_id: int
|
|
24
|
+
status: str | None = None
|
|
25
|
+
mode: str | None = None
|
|
26
|
+
files_indexed: int = 0
|
|
27
|
+
symbols_indexed: int = 0
|
|
28
|
+
embeddings_created: int = 0
|
|
29
|
+
relationships: int = 0
|
|
30
|
+
duration_seconds: float = 0.0
|
|
31
|
+
to_commit: str | None = None
|
|
32
|
+
error: str | None = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class SearchRequest(BaseModel):
|
|
36
|
+
query: str
|
|
37
|
+
repository: str | None = None
|
|
38
|
+
limit: int = 10
|
|
39
|
+
semantic: bool = True
|
|
40
|
+
graph: bool = True
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class CandidateOut(BaseModel):
|
|
44
|
+
symbol_id: int
|
|
45
|
+
qualified_name: str
|
|
46
|
+
symbol_type: str
|
|
47
|
+
file_path: str
|
|
48
|
+
start_line: int
|
|
49
|
+
end_line: int
|
|
50
|
+
score: float
|
|
51
|
+
reasons: list[str]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class SearchResponse(BaseModel):
|
|
55
|
+
repository: str
|
|
56
|
+
latency_ms: float
|
|
57
|
+
candidates: list[CandidateOut]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ContextRequest(BaseModel):
|
|
61
|
+
query: str
|
|
62
|
+
repository: str | None = None
|
|
63
|
+
max_tokens: int | None = None
|
|
64
|
+
finding: str | None = None
|
|
65
|
+
include_prompt: bool = True
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ContextEntryOut(BaseModel):
|
|
69
|
+
category: str
|
|
70
|
+
qualified_name: str
|
|
71
|
+
file_path: str
|
|
72
|
+
start_line: int
|
|
73
|
+
end_line: int
|
|
74
|
+
tokens: int
|
|
75
|
+
reasons: list[str]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class AccountingOut(BaseModel):
|
|
79
|
+
query_tokens: int
|
|
80
|
+
candidates_found: int
|
|
81
|
+
candidates_selected: int
|
|
82
|
+
candidate_tokens: int
|
|
83
|
+
context_tokens: int
|
|
84
|
+
dropped_tokens: int
|
|
85
|
+
final_prompt_tokens: int
|
|
86
|
+
token_reduction_from_candidates: float
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ContextResponse(BaseModel):
|
|
90
|
+
repository: str
|
|
91
|
+
entries: list[ContextEntryOut]
|
|
92
|
+
accounting: AccountingOut
|
|
93
|
+
prompt: str | None = None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class AskRequest(BaseModel):
|
|
97
|
+
query: str
|
|
98
|
+
repository: str | None = None
|
|
99
|
+
max_tokens: int | None = None
|
|
100
|
+
max_output_tokens: int | None = None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class UsageOut(BaseModel):
|
|
104
|
+
input_tokens: int
|
|
105
|
+
output_tokens: int
|
|
106
|
+
cached_input_tokens: int | None = None
|
|
107
|
+
model: str
|
|
108
|
+
latency_ms: float
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class AskResponse(BaseModel):
|
|
112
|
+
repository: str
|
|
113
|
+
answer: str
|
|
114
|
+
usage: UsageOut
|
|
115
|
+
accounting: AccountingOut
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class SymbolOut(BaseModel):
|
|
119
|
+
id: int
|
|
120
|
+
qualified_name: str
|
|
121
|
+
symbol_name: str
|
|
122
|
+
symbol_type: str
|
|
123
|
+
file_path: str
|
|
124
|
+
start_line: int
|
|
125
|
+
end_line: int
|
|
126
|
+
signature: str | None = None
|
|
127
|
+
docstring: str | None = None
|
|
128
|
+
token_count: int
|
|
129
|
+
source_code: str
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class RelationshipOut(BaseModel):
|
|
133
|
+
relationship_type: str
|
|
134
|
+
confidence: float
|
|
135
|
+
target_symbol_id: int | None = None
|
|
136
|
+
target_qualified_name: str | None = None
|
|
137
|
+
target_name: str | None = None
|
|
138
|
+
direction: str = Field(description="outgoing|incoming")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class MetricsOut(BaseModel):
|
|
142
|
+
repositories: int
|
|
143
|
+
symbols: int
|
|
144
|
+
embeddings: int
|
|
145
|
+
relationships: int
|
|
146
|
+
queries: int
|
|
147
|
+
llm_requests: int
|
|
148
|
+
avg_context_tokens: float
|
|
149
|
+
avg_retrieval_latency_ms: float
|
|
150
|
+
total_llm_input_tokens: int
|
|
151
|
+
total_llm_output_tokens: int
|
|
152
|
+
# token-savings aggregates (candidate set -> budgeted context)
|
|
153
|
+
total_candidate_tokens: int
|
|
154
|
+
total_context_tokens: int
|
|
155
|
+
total_tokens_saved: int
|
|
156
|
+
avg_token_reduction_percent: float
|
|
157
|
+
# "what reading whole files would have cost" baseline
|
|
158
|
+
total_baseline_tokens: int
|
|
159
|
+
total_saved_vs_files: int
|
|
160
|
+
reduction_vs_files_percent: float
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class QueryRow(BaseModel):
|
|
164
|
+
id: int
|
|
165
|
+
repository: str
|
|
166
|
+
mode: str
|
|
167
|
+
query: str
|
|
168
|
+
candidates_found: int
|
|
169
|
+
candidates_selected: int
|
|
170
|
+
candidate_tokens: int
|
|
171
|
+
context_tokens: int
|
|
172
|
+
tokens_saved: int
|
|
173
|
+
reduction_percent: float
|
|
174
|
+
baseline_tokens: int = 0
|
|
175
|
+
baseline_files: int = 0
|
|
176
|
+
saved_vs_files: int = 0
|
|
177
|
+
reduction_vs_files: float = 0.0
|
|
178
|
+
retrieval_latency_ms: float
|
|
179
|
+
llm_input_tokens: int | None = None
|
|
180
|
+
llm_output_tokens: int | None = None
|
|
181
|
+
created_at: str
|
coderag/cli/__init__.py
ADDED
|
File without changes
|