coderag-ai 0.3.3__tar.gz → 0.3.4__tar.gz
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_ai-0.3.3 → coderag_ai-0.3.4}/PKG-INFO +1 -1
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/pyproject.toml +1 -1
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/api/app.py +8 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/api/dashboard.py +5 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/api/schemas.py +6 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/cli/main.py +7 -1
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/core/config.py +7 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase13_measure.py +25 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/.env.example +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/.gitignore +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/CODE_OF_CONDUCT.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/CONTRIBUTING.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/Dockerfile +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/LICENSE +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/Makefile +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/NOTICE +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/README.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/SECURITY.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/alembic.ini +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docker/entrypoint.sh +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docker-compose.yml +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/adding-language.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/adr/001-postgres-pgvector.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/adr/002-structural-chunks.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/adr/003-hybrid-search.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/adr/004-tree-sitter.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/adr/005-llm-provider-independence.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/adr/006-repository-authorization.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/adr/007-token-budgeting.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/architecture.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/claude-code.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/evaluation.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/install-macos.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/licenses.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/llm-providers.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/retrieval.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/security.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/docs/vscode-extension.md +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/api.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/auth.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/checkout_service.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/models.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/payment_repository.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/payment_service.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/retry_policy.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/users.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/tests/test_payment_service.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/tests/test_retry_policy.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/eval/eval_dataset.json +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/scripts/gen_initial_migration.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/analyzers/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/analyzers/base.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/analyzers/flake8_adapter.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/analyzers/pylint_adapter.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/analyzers/workflow.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/api/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/cli/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/context/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/context/builder.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/context/package.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/core/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/core/logging.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/core/text.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/core/tokens.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/db/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/db/base.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/db/migrate.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/db/migrations/env.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/db/migrations/script.py.mako +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/db/migrations/versions/.gitkeep +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/db/migrations/versions/9a973932b94d_measure_baseline_tokens.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/db/migrations/versions/c8a40feeda41_initial_schema.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/db/models.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/embeddings/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/embeddings/base.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/embeddings/hashing.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/embeddings/pipeline.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/embeddings/registry.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/embeddings/sentence_transformer.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/evaluation/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/evaluation/datasets.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/evaluation/harness.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/git/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/git/repo.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/indexing/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/indexing/ignore.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/indexing/indexer.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/llm/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/llm/anthropic.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/llm/base.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/llm/null.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/llm/registry.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/localdb.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/mcp_server.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/parsing/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/parsing/base.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/parsing/python.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/parsing/registry.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/retrieval/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/retrieval/base.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/retrieval/engine.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/retrieval/fusion.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/retrieval/graph.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/retrieval/lexical.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/retrieval/reranking.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/retrieval/semantic.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/retrieval/symbol.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/security/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/security/authz.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/security/secrets.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/service.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/src/coderag/telemetry.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/__init__.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/conftest.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase0_db.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase0_migrations.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase10_analyzers.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase11_dashboard.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase12_mcp.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase14_localdb.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase15_migrate.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase1_indexer.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase1_parser.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase2_cli.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase2_retrieval.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase3_embeddings.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase3_semantic.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase3_sentence_transformer.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase4_graph.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase5_context_db.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase5_context_unit.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase6_api.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase6_ask.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase6_llm.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase7_eval.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase8_incremental.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_phase9_rerank.py +0 -0
- {coderag_ai-0.3.3 → coderag_ai-0.3.4}/tests/test_security_secrets.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: coderag-ai
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Token-efficient, structure-aware Code Intelligence + RAG for private source repositories.
|
|
5
5
|
Project-URL: Homepage, https://github.com/galacticsurfer/coderag
|
|
6
6
|
Project-URL: Repository, https://github.com/galacticsurfer/coderag
|
|
@@ -7,7 +7,7 @@ build-backend = "hatchling.build"
|
|
|
7
7
|
# command are both `coderag`. Plain "coderag" is taken on PyPI by an unrelated project,
|
|
8
8
|
# and "code-rag" is rejected as too similar (PyPI collapses -/_/. when comparing names).
|
|
9
9
|
name = "coderag-ai"
|
|
10
|
-
version = "0.3.
|
|
10
|
+
version = "0.3.4"
|
|
11
11
|
description = "Token-efficient, structure-aware Code Intelligence + RAG for private source repositories."
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.12"
|
|
@@ -286,6 +286,10 @@ def metrics(session: Session = Depends(get_session)) -> s.MetricsOut:
|
|
|
286
286
|
) or 0)
|
|
287
287
|
saved_vs_files = base_sum - base_ctx
|
|
288
288
|
reduction_vs_files = round(100.0 * saved_vs_files / base_sum, 1) if base_sum else 0.0
|
|
289
|
+
from coderag.core.config import get_settings
|
|
290
|
+
|
|
291
|
+
_s = get_settings()
|
|
292
|
+
pin, pout = _s.price_input_per_mtok, _s.price_output_per_mtok
|
|
289
293
|
return s.MetricsOut(
|
|
290
294
|
repositories=count(Repository), symbols=count(Symbol),
|
|
291
295
|
embeddings=count(SymbolEmbedding), relationships=count(SymbolRelationship),
|
|
@@ -297,6 +301,10 @@ def metrics(session: Session = Depends(get_session)) -> s.MetricsOut:
|
|
|
297
301
|
total_tokens_saved=saved, avg_token_reduction_percent=reduction,
|
|
298
302
|
total_baseline_tokens=base_sum, total_saved_vs_files=saved_vs_files,
|
|
299
303
|
reduction_vs_files_percent=reduction_vs_files,
|
|
304
|
+
price_input_per_mtok=pin, price_output_per_mtok=pout,
|
|
305
|
+
cost_saved_vs_files_usd=round(saved_vs_files / 1e6 * pin, 4),
|
|
306
|
+
cost_context_sent_usd=round(int(ctx_sum) / 1e6 * pin, 4),
|
|
307
|
+
cost_llm_usd=round(int(in_tok) / 1e6 * pin + int(out_tok) / 1e6 * pout, 4),
|
|
300
308
|
)
|
|
301
309
|
|
|
302
310
|
|
|
@@ -109,6 +109,7 @@ DASHBOARD_HTML = r"""<!doctype html>
|
|
|
109
109
|
</header>
|
|
110
110
|
|
|
111
111
|
<section class="kpis" id="kpis"></section>
|
|
112
|
+
<p style="font-size:12px;color:var(--muted);margin:-14px 0 22px">Dollar figures are estimates at the configured per-million prices (CODERAG_PRICE_INPUT_PER_MTOK / _OUTPUT_PER_MTOK) — not billing data. On a flat-rate Claude plan, savings show up as headroom rather than a refund.</p>
|
|
112
113
|
|
|
113
114
|
<section class="card">
|
|
114
115
|
<h2>Context vs. saved — recent queries</h2>
|
|
@@ -143,6 +144,7 @@ DASHBOARD_HTML = r"""<!doctype html>
|
|
|
143
144
|
<script>
|
|
144
145
|
const n = x => (x==null? "—" : Number(x).toLocaleString());
|
|
145
146
|
const pct = x => (x==null? "—" : Number(x).toFixed(1) + "%");
|
|
147
|
+
const usd = x => (x==null? "—" : "$" + Number(x).toLocaleString(undefined,{minimumFractionDigits:2, maximumFractionDigits:2}));
|
|
146
148
|
const esc = s => (s||"").replace(/[&<>"]/g, c => ({"&":"&","<":"<",">":">",'"':"""}[c]));
|
|
147
149
|
|
|
148
150
|
function tile(label, val, unit, hero){
|
|
@@ -153,7 +155,10 @@ function tile(label, val, unit, hero){
|
|
|
153
155
|
function renderKpis(m){
|
|
154
156
|
document.getElementById('kpis').innerHTML =
|
|
155
157
|
tile('Saved vs reading files', n(m.total_saved_vs_files), 'tok', true) +
|
|
158
|
+
tile('Est. $ saved', usd(m.cost_saved_vs_files_usd), '', true) +
|
|
156
159
|
tile('Reduction vs files', pct(m.reduction_vs_files_percent), '', true) +
|
|
160
|
+
tile('Est. $ context sent', usd(m.cost_context_sent_usd)) +
|
|
161
|
+
tile('Est. $ LLM spend', usd(m.cost_llm_usd)) +
|
|
157
162
|
tile('Whole-file baseline', n(m.total_baseline_tokens), 'tok') +
|
|
158
163
|
tile('Tokens saved (budgeting)', n(m.total_tokens_saved)) +
|
|
159
164
|
tile('Overall reduction', pct(m.avg_token_reduction_percent)) +
|
|
@@ -158,6 +158,12 @@ class MetricsOut(BaseModel):
|
|
|
158
158
|
total_baseline_tokens: int
|
|
159
159
|
total_saved_vs_files: int
|
|
160
160
|
reduction_vs_files_percent: float
|
|
161
|
+
# Indicative USD at the configured per-million prices (estimates, not billing)
|
|
162
|
+
price_input_per_mtok: float
|
|
163
|
+
price_output_per_mtok: float
|
|
164
|
+
cost_saved_vs_files_usd: float
|
|
165
|
+
cost_context_sent_usd: float
|
|
166
|
+
cost_llm_usd: float
|
|
161
167
|
|
|
162
168
|
|
|
163
169
|
class QueryRow(BaseModel):
|
|
@@ -195,9 +195,15 @@ def context(
|
|
|
195
195
|
f"{acct.final_prompt_tokens:,}")
|
|
196
196
|
console.print(t)
|
|
197
197
|
if acct.baseline_tokens:
|
|
198
|
+
price = get_settings().price_input_per_mtok
|
|
199
|
+
saved_usd = acct.tokens_saved_vs_files / 1e6 * price
|
|
198
200
|
console.print(
|
|
199
201
|
f"[green]saved {acct.tokens_saved_vs_files:,} tokens "
|
|
200
|
-
f"({acct.reduction_vs_files}%) vs opening those files[/]"
|
|
202
|
+
f"({acct.reduction_vs_files}%) vs opening those files[/] "
|
|
203
|
+
f"[dim]≈ ${saved_usd:.4f} at ${price:.2f}/M input tokens; "
|
|
204
|
+
f"× 1,000 similar queries ≈ ${saved_usd * 1000:.2f}[/]\n"
|
|
205
|
+
f"[dim]Estimate at configured prices, not billing data. On a "
|
|
206
|
+
f"flat-rate plan this is headroom, not a refund.[/]"
|
|
201
207
|
)
|
|
202
208
|
else:
|
|
203
209
|
console.print("[yellow]No baseline recorded (nothing selected).[/]")
|
|
@@ -85,6 +85,13 @@ class Settings(BaseSettings):
|
|
|
85
85
|
llm_max_output_tokens: int = 1024
|
|
86
86
|
llm_timeout_seconds: float = 60.0
|
|
87
87
|
|
|
88
|
+
# ---- Cost estimation -------------------------------------------------
|
|
89
|
+
# USD per million tokens, used only to turn token counts into indicative
|
|
90
|
+
# dollar figures. Defaults are Claude Opus 4.8 list prices; override for your
|
|
91
|
+
# model/plan. These are ESTIMATES at configured prices — not billing data.
|
|
92
|
+
price_input_per_mtok: float = 5.00
|
|
93
|
+
price_output_per_mtok: float = 25.00
|
|
94
|
+
|
|
88
95
|
# ---- Analyzers (Phase 10) ------------------------------------------
|
|
89
96
|
max_fix_attempts: int = 2
|
|
90
97
|
|
|
@@ -77,3 +77,28 @@ def test_mcp_context_includes_measurement(db_session, demo_repo):
|
|
|
77
77
|
out = coderag_context("retry failed payment", repository="payments")
|
|
78
78
|
assert "fewer input tokens" in out["measurement"]
|
|
79
79
|
assert out["token_accounting"]["baseline_tokens"] > 0
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_metrics_exposes_dollar_estimates(db_session, demo_repo):
|
|
83
|
+
"""Token savings are convertible to indicative USD at configured prices."""
|
|
84
|
+
from coderag.core.config import get_settings
|
|
85
|
+
|
|
86
|
+
run_context(db_session, "retry failed payment", "payments")
|
|
87
|
+
db_session.commit()
|
|
88
|
+
|
|
89
|
+
client = TestClient(app)
|
|
90
|
+
m = client.get("/metrics").json()
|
|
91
|
+
s = get_settings()
|
|
92
|
+
assert m["price_input_per_mtok"] == s.price_input_per_mtok
|
|
93
|
+
# dollars must be a faithful function of tokens and the configured price
|
|
94
|
+
expected = round(m["total_saved_vs_files"] / 1e6 * s.price_input_per_mtok, 4)
|
|
95
|
+
assert m["cost_saved_vs_files_usd"] == expected
|
|
96
|
+
assert m["cost_context_sent_usd"] >= 0.0
|
|
97
|
+
assert m["cost_llm_usd"] >= 0.0
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_price_settings_are_configurable():
|
|
101
|
+
from coderag.core.config import Settings
|
|
102
|
+
|
|
103
|
+
s = Settings(price_input_per_mtok=3.0, price_output_per_mtok=15.0)
|
|
104
|
+
assert s.price_input_per_mtok == 3.0 and s.price_output_per_mtok == 15.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/payments/payment_repository.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coderag_ai-0.3.3 → coderag_ai-0.3.4}/examples/demo-repository/tests/test_payment_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|