bgts-context-engine 0.2.2__tar.gz → 0.2.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.
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/CHANGELOG.md +119 -1
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/MANIFEST.in +1 -0
- {bgts_context_engine-0.2.2/src/bgts_context_engine.egg-info → bgts_context_engine-0.2.4}/PKG-INFO +61 -9
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/README.md +60 -8
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/README.tr.md +60 -6
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/pyproject.toml +1 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/__init__.py +1 -1
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/mcp/server.py +5 -2
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/mcp/tools.py +33 -8
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/schemas.py +7 -3
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/trace.py +4 -1
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/bench/pr_ablation.py +27 -5
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/cli.py +158 -7
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/config.py +53 -3
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/assembler/assembler.py +16 -11
- bgts_context_engine-0.2.4/src/bce/core/defaults.py +19 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/anchors.py +15 -5
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/orchestrator.py +21 -5
- bgts_context_engine-0.2.4/src/bce/core/orchestrator/profile.py +125 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/embedder/__init__.py +4 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/embedder/encoder.py +173 -3
- bgts_context_engine-0.2.4/src/bce/integrations/__init__.py +10 -0
- bgts_context_engine-0.2.4/src/bce/integrations/agents.py +271 -0
- bgts_context_engine-0.2.4/src/bce/integrations/precontext.py +168 -0
- bgts_context_engine-0.2.4/src/bce/integrations/templates/claude_section.md +16 -0
- bgts_context_engine-0.2.4/src/bce/integrations/templates/cursor_rule.mdc +20 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrator.py +64 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer3/__init__.py +3 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer3/orchestration.py +45 -10
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4/src/bgts_context_engine.egg-info}/PKG-INFO +61 -9
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/SOURCES.txt +7 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/LICENSE +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/setup.cfg +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/mcp/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/app.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/deps.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/routes.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/static/assets/index-Cc4pUpSE.js +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/static/assets/index-DrLRaTMU.css +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/static/favicon.svg +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/static/index.html +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/queries.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/router.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/schemas.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/bench/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/bench/runner.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/assembler/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/auth/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/auth/scope.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/coverage/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/coverage/confidence.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/catalogs/en.json +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/catalogs/tr.json +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/locale.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/translator.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/logging.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/bulk.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/expand.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/text.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/scoring/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/scoring/engine.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/domain/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/domain/enums.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/domain/models.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/churn.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/embedder/embedder.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/bridges.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/designnote.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/extractor.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/routes.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/gitsync/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/gitsync/bitbucket.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/gitsync/local.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/gitsync/remote.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/indexer.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/linker/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/linker/linker.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/_treesitter.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/base.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/csharp_provider.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/go_provider.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/java_provider.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/jsts_provider.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/python_provider.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/registry.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/scip/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/scip/resolver.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/symbol_id.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/upserter/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/upserter/upserter.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/jobs/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/jobs/store.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/jobs/worker.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/graph/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/graph/client.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/graph/repository.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/db.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0001_extensions_graph.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0002_relational.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0003_vector.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0004_rls.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0005_embeddings_dim.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0006_fts.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0007_jobs.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0008_graph_label_indexes.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0009_fts_identifier_parts.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0010_file_churn.sql +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/queries.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/vector/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/vector/store.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer1/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer1/primitives.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer2/__init__.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer2/search.py +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/dependency_links.txt +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/entry_points.txt +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/requires.txt +0 -0
- {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/top_level.txt +0 -0
|
@@ -7,6 +7,122 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.4] - 2026-09-22
|
|
11
|
+
|
|
12
|
+
This release turns the agent benchmark (a Cursor CLI agent on 14 tasks against a
|
|
13
|
+
React/TypeScript codebase, plain vs. with the engine) into product behaviour. The MCP server alone made a Cursor agent *worse*: it asked the graph late (after
|
|
14
|
+
a round of grep) or eight times per task, and the answer it got back had no file or line.
|
|
15
|
+
With one advertised tool, a rule that says "call it first and treat `file:line` as a
|
|
16
|
+
verified location", the answer handed over before the first turn, and a shorter context
|
|
17
|
+
budget, the same agent on the same 14 tasks, model and machine used 20 % fewer tokens,
|
|
18
|
+
produced 46 % less grep/glob output and 13 % fewer model turns, passed 73/73 checks against
|
|
19
|
+
72/73, and changed 23 % fewer lines. Everything below is what that took.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `bce cursor-init [--project DIR] [--repo-id ID]... [--env-file PATH] [--bce-command X]`:
|
|
24
|
+
writes a project's `.cursor/mcp.json` (merged into an existing one; other servers are
|
|
25
|
+
kept) with the absolute path of the running `bce`, `serve-mcp --env-file …` and
|
|
26
|
+
`PYTHONUTF8=1`, plus the `alwaysApply` rule `.cursor/rules/bgts-context-engine.mdc`. The
|
|
27
|
+
rule ships in the wheel as a template, so every install gets the same instruction: call
|
|
28
|
+
`get_context_for_task` first with the full task text, open the returned `file:line`
|
|
29
|
+
entries directly instead of grepping for them, treat the list as places to inspect rather
|
|
30
|
+
than files to edit, never repeat a call with the same text. Idempotent.
|
|
31
|
+
- `bce claude-init …[--no-hook]`: the Claude Code counterpart — `.mcp.json` (merged), a
|
|
32
|
+
section in `CLAUDE.md` between `<!-- bgts-context-engine:begin/end -->` markers (the rest
|
|
33
|
+
of the file is kept), and by default a `UserPromptSubmit` hook in `.claude/settings.json`
|
|
34
|
+
(other hooks kept) that runs `bce precontext` before every prompt. Cursor gets no hook: its
|
|
35
|
+
`beforeSubmitPrompt` event can only allow or block a prompt, so there the rule carries the
|
|
36
|
+
instruction and the agent makes the one call itself.
|
|
37
|
+
- `bce precontext [--task TEXT] [--repo-id ID]...`: the compact "Code context for this
|
|
38
|
+
task" block an agent prompt carries — a file list in rank order, then one line per symbol
|
|
39
|
+
(`path:line kind name distance`) with a snippet of at most 12 lines where the snippet says
|
|
40
|
+
more than the name; about 5 k characters at the default budget. Without `--task` it is the
|
|
41
|
+
Claude Code hook: reads the hook JSON on stdin, skips prompts under 20 characters and slash
|
|
42
|
+
commands, prints `hookSpecificOutput.additionalContext` capped at Claude Code's
|
|
43
|
+
10 000-character limit, and fails open (an unreachable database is a prompt without
|
|
44
|
+
context, never a blocked prompt). `bce.integrations.precontext.render_context_markdown`
|
|
45
|
+
is the renderer, for other hosts.
|
|
46
|
+
- `BCE_MCP_TOOLS`: comma-separated names the MCP server advertises (default: all read
|
|
47
|
+
tools). Agents fetch a tool's schema before first use and chain small calls when many
|
|
48
|
+
tools are on offer; the benchmark ran with `get_context_for_task` alone. Unknown names
|
|
49
|
+
fail at startup, and a tool not advertised cannot be dispatched either.
|
|
50
|
+
- `BCE_EMBEDDING_QUERY_TIMEOUT` (10 s, two attempts): the wait for embedding a single
|
|
51
|
+
*query* at search time, separate from the indexing timeout (600 s). When it expires,
|
|
52
|
+
`get_context_for_task` and `suggest_change_sites` answer from lexical and structural
|
|
53
|
+
anchors alone — visible as lower `coverage.confidence` — instead of failing after having
|
|
54
|
+
waited past an agent's MCP timeout (Cursor: 60 s). Motivated by a RunPod TCP proxy that
|
|
55
|
+
stalled connects for 19–67 s during the benchmark.
|
|
56
|
+
- Context items carry `name`, `kind`, `file_id` and `line` next to `symbol_id`. Without
|
|
57
|
+
them an agent had to search the tree for the file behind every symbol id (the module path
|
|
58
|
+
does not say `.ts` vs `.tsx`, nor the line) — one tool call, one model turn, per item.
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- **Defaults: `max_candidates` 8 → 20, `max_tokens` 4000 → 1500**, on every surface (CLI
|
|
63
|
+
`bce context`, REST, MCP schema defaults, and the `bce.core.defaults` module they all
|
|
64
|
+
read). K=20 is where recall@K flattened in the PR replay for both fitted profiles and
|
|
65
|
+
what the agent benchmark ran with. The budget is shorter because an agent re-sends the
|
|
66
|
+
context on every turn: at 1500 it travelled as ~1.3 k tokens per turn and still halved
|
|
67
|
+
the agent's search output; 4000 travelled as ~4 k per turn for no further gain. Callers
|
|
68
|
+
wanting longer snippets pass `max_tokens` per request; the assembler still degrades items
|
|
69
|
+
to reference level rather than dropping them.
|
|
70
|
+
- `.env.example` shows `voyage-code-4` (the model the voyage profile was fitted on) as the
|
|
71
|
+
Voyage example and documents `BCE_EMBEDDING_QUERY_TIMEOUT` and `BCE_MCP_TOOLS`. The code
|
|
72
|
+
default stays `voyage-code-3` so indexes built with it keep matching.
|
|
73
|
+
- `server.json` describes the catalog as eight read-only tools plus two write tools rather
|
|
74
|
+
than "14 tools".
|
|
75
|
+
|
|
76
|
+
## [0.2.3] - 2026-09-21
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
|
|
80
|
+
- `BCE_EMBEDDING_PROVIDER=openai`: an encoder that talks to any server speaking the OpenAI
|
|
81
|
+
`/v1/embeddings` protocol (vLLM, Text Embeddings Inference, Ollama, or OpenAI itself), using
|
|
82
|
+
only the standard library. This is how an open model such as `jinaai/jina-code-embeddings-1.5b`
|
|
83
|
+
runs on-prem. Query/document asymmetry is a text prefix — the jina-code family's `nl2code`
|
|
84
|
+
prompts are the default when the model name contains `jina-code`; anything else is unset
|
|
85
|
+
unless `BCE_EMBEDDING_QUERY_PREFIX` / `BCE_EMBEDDING_DOCUMENT_PREFIX` say otherwise.
|
|
86
|
+
`BCE_EMBEDDING_BASE_URL`, `BCE_EMBEDDING_API_KEY`, `BCE_EMBEDDING_EXTRA_BODY` (default
|
|
87
|
+
`{"truncate_prompt_tokens": -1}` so vLLM truncates instead of rejecting a long batch; set
|
|
88
|
+
`{}` for OpenAI's own API, which rejects unknown fields) and `BCE_EMBEDDING_TIMEOUT` (600 s)
|
|
89
|
+
configure the client. Vectors wider than `BCE_EMBEDDING_DIM` are truncated and re-normalised
|
|
90
|
+
(Matryoshka); a narrower reply is a configuration error. Transient 5xx / connection failures
|
|
91
|
+
retry three times; 4xx does not.
|
|
92
|
+
- Retrieval profiles (`bce.core.orchestrator.profile`): the three engine constants that encode
|
|
93
|
+
*where in the model's ranked list the right answers sit* — semantic-anchor rank scale, the
|
|
94
|
+
share of the answer reserved for the model's ranks, and a guard on its top ranks in
|
|
95
|
+
narrowing — grouped per embedding family. `BCE_RETRIEVAL_PROFILE=auto` (the default) picks
|
|
96
|
+
`voyage` for `voyage-*` and unknown models (the historical constants, unchanged) and `jina`
|
|
97
|
+
for `jina-*`. Name one to force it; `BCE_RETRIEVAL_SEMANTIC_GUARD_RANKS` /
|
|
98
|
+
`_RESERVE_SHARE` / `_RANK_SCALE` override a single knob for fitting runs. A profile change
|
|
99
|
+
never needs a re-index. The active profile is written into every `bce bench-prs` report.
|
|
100
|
+
- `bce migrate --reset-embeddings`: after the SQL migrations, `align_embedding_dim` re-types
|
|
101
|
+
`embeddings.embedding` to `BCE_EMBEDDING_DIM`. Stored vectors of another width are refused
|
|
102
|
+
unless the flag is set (they belong to another model and would be discarded); then the HNSW
|
|
103
|
+
index is rebuilt the same way migration `0005` did.
|
|
104
|
+
|
|
105
|
+
### Changed
|
|
106
|
+
|
|
107
|
+
- Narrowing reads the active retrieval profile. The voyage path is unchanged (no guard,
|
|
108
|
+
share 0.5). The jina profile adds a guard of 10: the model's first ten ranks fill slots
|
|
109
|
+
1–10 (only the container cap can skip one). jina-code finds more correct symbols than
|
|
110
|
+
voyage-code-4 but spreads them over ranks 1–15, and under the voyage constants the engine's
|
|
111
|
+
agreement with the model's *deeper* ranks satisfied the reserve share and pushed those mid
|
|
112
|
+
hits to positions 11–19 or out of the answer (PR replay, 30 PRs: recall@20 35.7 % → 38.2 %,
|
|
113
|
+
holdout 27.8 % → 34.9 %, retention of the model's own hits 83 % → 92 %). The list stays
|
|
114
|
+
K-monotonic.
|
|
115
|
+
- `bce bench-prs` titles the markdown with the encoder that actually produced the snapshots
|
|
116
|
+
(`jina-code-embeddings-1.5b vs … + BCE`), because the JSON key `voyage` is historical, not
|
|
117
|
+
the model.
|
|
118
|
+
|
|
119
|
+
### Fixed
|
|
120
|
+
|
|
121
|
+
- `bce bench-prs --from-report` / `--rerun-bce` no longer treats a stored semantic pool
|
|
122
|
+
shorter than K as incomplete. A task whose neighbours are mostly tests legitimately has a
|
|
123
|
+
pool shorter than K — the live run had nothing more either — so the check is now "non-empty
|
|
124
|
+
and at least as long as the list scored from it".
|
|
125
|
+
|
|
10
126
|
## [0.2.2] - 2026-09-18
|
|
11
127
|
|
|
12
128
|
### Added
|
|
@@ -254,7 +370,9 @@ First public release.
|
|
|
254
370
|
- Docker Compose deployment with PostgreSQL, Apache AGE and pgvector preconfigured.
|
|
255
371
|
- `server.json` manifest describing the stdio server for the official MCP registry.
|
|
256
372
|
|
|
257
|
-
[Unreleased]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.
|
|
373
|
+
[Unreleased]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.4...HEAD
|
|
374
|
+
[0.2.4]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.3...v0.2.4
|
|
375
|
+
[0.2.3]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.2...v0.2.3
|
|
258
376
|
[0.2.2]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.1...v0.2.2
|
|
259
377
|
[0.2.1]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.0...v0.2.1
|
|
260
378
|
[0.2.0]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.1.0...v0.2.0
|
|
@@ -4,6 +4,7 @@ include README.tr.md
|
|
|
4
4
|
include CHANGELOG.md
|
|
5
5
|
recursive-include src/bce/core/i18n/catalogs *.json
|
|
6
6
|
recursive-include src/bce/storage/relational/migrations *.sql
|
|
7
|
+
recursive-include src/bce/integrations/templates *.mdc *.md
|
|
7
8
|
|
|
8
9
|
# Compiled frontend, vendored by scripts/build_ui.py before a release build.
|
|
9
10
|
recursive-include src/bce/api/rest/static *
|
{bgts_context_engine-0.2.2/src/bgts_context_engine.egg-info → bgts_context_engine-0.2.4}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bgts-context-engine
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Deterministic code-graph context engine for AI coding agents - PostgreSQL, Apache AGE and pgvector, over MCP and REST
|
|
5
5
|
Author: Oğuz Öztürk, Enes İyidil
|
|
6
6
|
Maintainer: BGTS
|
|
@@ -69,7 +69,7 @@ that actually answer it — ranked, budgeted, and reproducible.
|
|
|
69
69
|
[](docs/mcp.md)
|
|
70
70
|
[](https://github.com/bgts-ai-org/bgts-context-engine/stargazers)
|
|
71
71
|
|
|
72
|
-
[Quick start](#quick-start) · [Use it from your agent](#use-it-from-your-agent) · [How it works](#how-it-works) · [Documentation](#documentation) · [Türkçe](README.tr.md)
|
|
72
|
+
[Quick start](#quick-start) · [Use it from your agent](#use-it-from-your-agent) · [How it works](#how-it-works) · [Supported models](#supported-models) · [Documentation](#documentation) · [Türkçe](README.tr.md)
|
|
73
73
|
|
|
74
74
|
</div>
|
|
75
75
|
|
|
@@ -150,9 +150,28 @@ Every MCP client uses the same stdio command plus the database in the environmen
|
|
|
150
150
|
leave `bce serve-mcp` running in a terminal for the editor: stdout is the protocol, so the
|
|
151
151
|
process stays silent, and the IDE starts its own copy.
|
|
152
152
|
|
|
153
|
+
**One command per editor.** Run it in the project the agent works on (the repository you
|
|
154
|
+
indexed), pointing at the engine's `.env`:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
bce --env-file /path/to/engine/.env cursor-init --repo-id my-service # Cursor
|
|
158
|
+
bce --env-file /path/to/engine/.env claude-init --repo-id my-service # Claude Code
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`cursor-init` writes `.cursor/mcp.json` (merged into an existing one) and the rule
|
|
162
|
+
`.cursor/rules/bgts-context-engine.mdc`, which tells the agent to call
|
|
163
|
+
`get_context_for_task` *first*, treat its `file:line` entries as verified locations instead
|
|
164
|
+
of grepping for them, and not to edit a file just because it was listed. `claude-init`
|
|
165
|
+
writes `.mcp.json`, a marked section in `CLAUDE.md`, and a `UserPromptSubmit` hook
|
|
166
|
+
(`bce precontext`) that runs the graph once per prompt and hands the agent the answer
|
|
167
|
+
before its first turn — the flow the agent benchmark measured (−20 % tokens, half the search
|
|
168
|
+
output, same or better checks; 14 tasks on a React/TypeScript codebase, same model and machine).
|
|
169
|
+
Cursor's prompt hook cannot add context, so there the rule does that job. `--no-hook`,
|
|
170
|
+
`--repo-id` (repeatable) and `--bce-command` adjust the files; both commands are safe to rerun.
|
|
171
|
+
|
|
153
172
|
After you add or change the MCP config, **restart Cursor or VS Code** (or Command Palette
|
|
154
173
|
→ “Developer: Reload Window”). The server should then show as enabled with eight tools (ten with indexing enabled).
|
|
155
|
-
Setup detail: [docs/mcp.md](docs/mcp.md).
|
|
174
|
+
Setup detail: [docs/mcp.md](docs/mcp.md). The manual equivalents:
|
|
156
175
|
|
|
157
176
|
**Cursor** — user config `~/.cursor/mcp.json` (applies to every project), or a project
|
|
158
177
|
`.cursor/mcp.json` that stays local (the directory is gitignored):
|
|
@@ -217,12 +236,14 @@ Not a list of file paths. A ranked pack, with the reasoning attached:
|
|
|
217
236
|
},
|
|
218
237
|
"context": {
|
|
219
238
|
"items": [
|
|
220
|
-
{ "symbol_id": "...refresh_session#88c2", "
|
|
239
|
+
{ "symbol_id": "...refresh_session#88c2", "name": "refresh_session", "kind": "function",
|
|
240
|
+
"file_id": "my-service:src/auth/session.py", "line": 41, "detail_level": "full",
|
|
221
241
|
"graph_distance": 0, "score": 11.42, "tokens": 214, "content": "def refresh_session(...)" },
|
|
222
|
-
{ "symbol_id": "...SESSION_TTL#4b0d",
|
|
242
|
+
{ "symbol_id": "...SESSION_TTL#4b0d", "name": "SESSION_TTL", "kind": "constant",
|
|
243
|
+
"file_id": "my-service:src/auth/config.py", "line": 12, "detail_level": "signature",
|
|
223
244
|
"graph_distance": 2, "score": 6.10, "tokens": 31, "content": "SESSION_TTL: int" }
|
|
224
245
|
],
|
|
225
|
-
"used_tokens":
|
|
246
|
+
"used_tokens": 1388, "budget": 1500, "included": 20, "skipped": 0
|
|
226
247
|
},
|
|
227
248
|
"coverage": {
|
|
228
249
|
"anchor_source_count": 3, "connected_component_ratio": 0.875,
|
|
@@ -243,8 +264,10 @@ could not corroborate it — the moment for an agent to ask a follow-up question
|
|
|
243
264
|
editing. `commit_mismatch` means the index is behind your working tree.
|
|
244
265
|
|
|
245
266
|
**`detail_level`** falls off with graph distance: the symbol you are changing arrives in
|
|
246
|
-
full, its neighbours as signatures, the outer ring as `name @ file:line`. That is how
|
|
247
|
-
genuinely relevant symbols fit in
|
|
267
|
+
full, its neighbours as signatures, the outer ring as `name @ file:line`. That is how twenty
|
|
268
|
+
genuinely relevant symbols fit in 1500 tokens — short enough for an agent to carry on every
|
|
269
|
+
turn. Every item also names its `file_id` and `line`, so the agent opens the file instead of
|
|
270
|
+
searching for the symbol.
|
|
248
271
|
|
|
249
272
|
## How it works
|
|
250
273
|
|
|
@@ -294,7 +317,36 @@ The full formula, every weight, and the confidence thresholds are in
|
|
|
294
317
|
- **A UI that explains itself.** `/ui` ships in the wheel and replays a real retrieval call
|
|
295
318
|
stage by stage: anchors lighting up, expansion spreading, candidates scored and cut.
|
|
296
319
|
- **Runs offline.** The default embedding provider is deterministic arithmetic over token
|
|
297
|
-
digests. No API key, no network, repeatable benchmarks.
|
|
320
|
+
digests. No API key, no network, repeatable benchmarks. `openai` talks to any
|
|
321
|
+
OpenAI-compatible `/v1/embeddings` server (vLLM, TEI, Ollama), so a model such as
|
|
322
|
+
[jina-code-embeddings-1.5b](https://huggingface.co/jinaai/jina-code-embeddings-1.5b)
|
|
323
|
+
can run inside the perimeter.
|
|
324
|
+
|
|
325
|
+
## Supported models
|
|
326
|
+
|
|
327
|
+
Embeddings only find entry points when the task text names nothing the graph already
|
|
328
|
+
knows. They never rank the answer. Out of the box that seed is `hashing`: deterministic
|
|
329
|
+
arithmetic, no API key, no network. For a real code model, set `BCE_EMBEDDING_PROVIDER`
|
|
330
|
+
and `BCE_EMBEDDING_MODEL` to one of these:
|
|
331
|
+
|
|
332
|
+
| Model | Provider | Dimension |
|
|
333
|
+
| --- | --- | --- |
|
|
334
|
+
| [`voyage-code-3`](https://blog.voyageai.com/2024/12/04/voyage-code-3/) | Voyage AI (`voyage`) | 1024 |
|
|
335
|
+
| [`voyage-code-4`](https://blog.voyageai.com/2026/08/13/voyage-code-4/) | Voyage AI (`voyage`) | 1024 |
|
|
336
|
+
| [`jina-code-embeddings-1.5b`](https://huggingface.co/jinaai/jina-code-embeddings-1.5b) | OpenAI-compatible (`openai`) | 1536 |
|
|
337
|
+
|
|
338
|
+
Voyage is a hosted API — `pip install "bgts-context-engine[embed]"` and
|
|
339
|
+
`BCE_VOYAGE_API_KEY`. Jina is the on-prem path: any server that speaks `/v1/embeddings`
|
|
340
|
+
(vLLM, TEI, Ollama). Switching the model or the dimension is a re-index
|
|
341
|
+
(`bce migrate --reset-embeddings`). The knobs are in
|
|
342
|
+
[docs/deployment.md](docs/deployment.md).
|
|
343
|
+
|
|
344
|
+
**Coming next** — same `openai` socket, not yet a fitted retrieval profile:
|
|
345
|
+
|
|
346
|
+
- [`jina-code-embeddings-0.5b`](https://huggingface.co/jinaai/jina-code-embeddings-0.5b)
|
|
347
|
+
— the smaller sibling of 1.5b, for hosts that cannot hold 1.5B parameters.
|
|
348
|
+
- [`Nomic Embed Code`](https://huggingface.co/nomic-ai/nomic-embed-code) — an open 7B
|
|
349
|
+
code retriever.
|
|
298
350
|
|
|
299
351
|
## Where it fits
|
|
300
352
|
|
|
@@ -16,7 +16,7 @@ that actually answer it — ranked, budgeted, and reproducible.
|
|
|
16
16
|
[](docs/mcp.md)
|
|
17
17
|
[](https://github.com/bgts-ai-org/bgts-context-engine/stargazers)
|
|
18
18
|
|
|
19
|
-
[Quick start](#quick-start) · [Use it from your agent](#use-it-from-your-agent) · [How it works](#how-it-works) · [Documentation](#documentation) · [Türkçe](README.tr.md)
|
|
19
|
+
[Quick start](#quick-start) · [Use it from your agent](#use-it-from-your-agent) · [How it works](#how-it-works) · [Supported models](#supported-models) · [Documentation](#documentation) · [Türkçe](README.tr.md)
|
|
20
20
|
|
|
21
21
|
</div>
|
|
22
22
|
|
|
@@ -97,9 +97,28 @@ Every MCP client uses the same stdio command plus the database in the environmen
|
|
|
97
97
|
leave `bce serve-mcp` running in a terminal for the editor: stdout is the protocol, so the
|
|
98
98
|
process stays silent, and the IDE starts its own copy.
|
|
99
99
|
|
|
100
|
+
**One command per editor.** Run it in the project the agent works on (the repository you
|
|
101
|
+
indexed), pointing at the engine's `.env`:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
bce --env-file /path/to/engine/.env cursor-init --repo-id my-service # Cursor
|
|
105
|
+
bce --env-file /path/to/engine/.env claude-init --repo-id my-service # Claude Code
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`cursor-init` writes `.cursor/mcp.json` (merged into an existing one) and the rule
|
|
109
|
+
`.cursor/rules/bgts-context-engine.mdc`, which tells the agent to call
|
|
110
|
+
`get_context_for_task` *first*, treat its `file:line` entries as verified locations instead
|
|
111
|
+
of grepping for them, and not to edit a file just because it was listed. `claude-init`
|
|
112
|
+
writes `.mcp.json`, a marked section in `CLAUDE.md`, and a `UserPromptSubmit` hook
|
|
113
|
+
(`bce precontext`) that runs the graph once per prompt and hands the agent the answer
|
|
114
|
+
before its first turn — the flow the agent benchmark measured (−20 % tokens, half the search
|
|
115
|
+
output, same or better checks; 14 tasks on a React/TypeScript codebase, same model and machine).
|
|
116
|
+
Cursor's prompt hook cannot add context, so there the rule does that job. `--no-hook`,
|
|
117
|
+
`--repo-id` (repeatable) and `--bce-command` adjust the files; both commands are safe to rerun.
|
|
118
|
+
|
|
100
119
|
After you add or change the MCP config, **restart Cursor or VS Code** (or Command Palette
|
|
101
120
|
→ “Developer: Reload Window”). The server should then show as enabled with eight tools (ten with indexing enabled).
|
|
102
|
-
Setup detail: [docs/mcp.md](docs/mcp.md).
|
|
121
|
+
Setup detail: [docs/mcp.md](docs/mcp.md). The manual equivalents:
|
|
103
122
|
|
|
104
123
|
**Cursor** — user config `~/.cursor/mcp.json` (applies to every project), or a project
|
|
105
124
|
`.cursor/mcp.json` that stays local (the directory is gitignored):
|
|
@@ -164,12 +183,14 @@ Not a list of file paths. A ranked pack, with the reasoning attached:
|
|
|
164
183
|
},
|
|
165
184
|
"context": {
|
|
166
185
|
"items": [
|
|
167
|
-
{ "symbol_id": "...refresh_session#88c2", "
|
|
186
|
+
{ "symbol_id": "...refresh_session#88c2", "name": "refresh_session", "kind": "function",
|
|
187
|
+
"file_id": "my-service:src/auth/session.py", "line": 41, "detail_level": "full",
|
|
168
188
|
"graph_distance": 0, "score": 11.42, "tokens": 214, "content": "def refresh_session(...)" },
|
|
169
|
-
{ "symbol_id": "...SESSION_TTL#4b0d",
|
|
189
|
+
{ "symbol_id": "...SESSION_TTL#4b0d", "name": "SESSION_TTL", "kind": "constant",
|
|
190
|
+
"file_id": "my-service:src/auth/config.py", "line": 12, "detail_level": "signature",
|
|
170
191
|
"graph_distance": 2, "score": 6.10, "tokens": 31, "content": "SESSION_TTL: int" }
|
|
171
192
|
],
|
|
172
|
-
"used_tokens":
|
|
193
|
+
"used_tokens": 1388, "budget": 1500, "included": 20, "skipped": 0
|
|
173
194
|
},
|
|
174
195
|
"coverage": {
|
|
175
196
|
"anchor_source_count": 3, "connected_component_ratio": 0.875,
|
|
@@ -190,8 +211,10 @@ could not corroborate it — the moment for an agent to ask a follow-up question
|
|
|
190
211
|
editing. `commit_mismatch` means the index is behind your working tree.
|
|
191
212
|
|
|
192
213
|
**`detail_level`** falls off with graph distance: the symbol you are changing arrives in
|
|
193
|
-
full, its neighbours as signatures, the outer ring as `name @ file:line`. That is how
|
|
194
|
-
genuinely relevant symbols fit in
|
|
214
|
+
full, its neighbours as signatures, the outer ring as `name @ file:line`. That is how twenty
|
|
215
|
+
genuinely relevant symbols fit in 1500 tokens — short enough for an agent to carry on every
|
|
216
|
+
turn. Every item also names its `file_id` and `line`, so the agent opens the file instead of
|
|
217
|
+
searching for the symbol.
|
|
195
218
|
|
|
196
219
|
## How it works
|
|
197
220
|
|
|
@@ -241,7 +264,36 @@ The full formula, every weight, and the confidence thresholds are in
|
|
|
241
264
|
- **A UI that explains itself.** `/ui` ships in the wheel and replays a real retrieval call
|
|
242
265
|
stage by stage: anchors lighting up, expansion spreading, candidates scored and cut.
|
|
243
266
|
- **Runs offline.** The default embedding provider is deterministic arithmetic over token
|
|
244
|
-
digests. No API key, no network, repeatable benchmarks.
|
|
267
|
+
digests. No API key, no network, repeatable benchmarks. `openai` talks to any
|
|
268
|
+
OpenAI-compatible `/v1/embeddings` server (vLLM, TEI, Ollama), so a model such as
|
|
269
|
+
[jina-code-embeddings-1.5b](https://huggingface.co/jinaai/jina-code-embeddings-1.5b)
|
|
270
|
+
can run inside the perimeter.
|
|
271
|
+
|
|
272
|
+
## Supported models
|
|
273
|
+
|
|
274
|
+
Embeddings only find entry points when the task text names nothing the graph already
|
|
275
|
+
knows. They never rank the answer. Out of the box that seed is `hashing`: deterministic
|
|
276
|
+
arithmetic, no API key, no network. For a real code model, set `BCE_EMBEDDING_PROVIDER`
|
|
277
|
+
and `BCE_EMBEDDING_MODEL` to one of these:
|
|
278
|
+
|
|
279
|
+
| Model | Provider | Dimension |
|
|
280
|
+
| --- | --- | --- |
|
|
281
|
+
| [`voyage-code-3`](https://blog.voyageai.com/2024/12/04/voyage-code-3/) | Voyage AI (`voyage`) | 1024 |
|
|
282
|
+
| [`voyage-code-4`](https://blog.voyageai.com/2026/08/13/voyage-code-4/) | Voyage AI (`voyage`) | 1024 |
|
|
283
|
+
| [`jina-code-embeddings-1.5b`](https://huggingface.co/jinaai/jina-code-embeddings-1.5b) | OpenAI-compatible (`openai`) | 1536 |
|
|
284
|
+
|
|
285
|
+
Voyage is a hosted API — `pip install "bgts-context-engine[embed]"` and
|
|
286
|
+
`BCE_VOYAGE_API_KEY`. Jina is the on-prem path: any server that speaks `/v1/embeddings`
|
|
287
|
+
(vLLM, TEI, Ollama). Switching the model or the dimension is a re-index
|
|
288
|
+
(`bce migrate --reset-embeddings`). The knobs are in
|
|
289
|
+
[docs/deployment.md](docs/deployment.md).
|
|
290
|
+
|
|
291
|
+
**Coming next** — same `openai` socket, not yet a fitted retrieval profile:
|
|
292
|
+
|
|
293
|
+
- [`jina-code-embeddings-0.5b`](https://huggingface.co/jinaai/jina-code-embeddings-0.5b)
|
|
294
|
+
— the smaller sibling of 1.5b, for hosts that cannot hold 1.5B parameters.
|
|
295
|
+
- [`Nomic Embed Code`](https://huggingface.co/nomic-ai/nomic-embed-code) — an open 7B
|
|
296
|
+
code retriever.
|
|
245
297
|
|
|
246
298
|
## Where it fits
|
|
247
299
|
|
|
@@ -14,7 +14,7 @@ veren sekiz sembolü sıralanmış, bütçelenmiş ve yeniden üretilebilir şek
|
|
|
14
14
|
[](docs/mcp.md)
|
|
15
15
|
[](https://github.com/bgts-ai-org/bgts-context-engine/stargazers)
|
|
16
16
|
|
|
17
|
-
[Hızlı başlangıç](#hızlı-başlangıç) · [Ajanınızdan kullanma](#ajanınızdan-kullanma) · [Nasıl çalışır](#nasıl-çalışır) · [Dokümantasyon](#dokümantasyon) · [English](README.md)
|
|
17
|
+
[Hızlı başlangıç](#hızlı-başlangıç) · [Ajanınızdan kullanma](#ajanınızdan-kullanma) · [Nasıl çalışır](#nasıl-çalışır) · [Desteklenen modeller](#desteklenen-modeller) · [Dokümantasyon](#dokümantasyon) · [English](README.md)
|
|
18
18
|
|
|
19
19
|
</div>
|
|
20
20
|
|
|
@@ -97,9 +97,31 @@ Her MCP istemcisi aynı stdio komutunu ve ortamındaki veritabanı bağlantısı
|
|
|
97
97
|
Editör için terminalde `bce serve-mcp` açık bırakmayın: stdout protokoldür, bu yüzden
|
|
98
98
|
süreç sessiz kalır; IDE kendi kopyasını başlatır.
|
|
99
99
|
|
|
100
|
+
**Editör başına tek komut.** Ajanın çalıştığı projede (indekslediğiniz depoda), motorun
|
|
101
|
+
`.env` dosyasını göstererek çalıştırın:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
bce --env-file /path/to/engine/.env cursor-init --repo-id my-service # Cursor
|
|
105
|
+
bce --env-file /path/to/engine/.env claude-init --repo-id my-service # Claude Code
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`cursor-init`, `.cursor/mcp.json` dosyasını (varsa üzerine birleştirerek) ve
|
|
109
|
+
`.cursor/rules/bgts-context-engine.mdc` kuralını yazar. Kural ajana şunları söyler:
|
|
110
|
+
`get_context_for_task` aracını *ilk iş olarak* çağır, döndürdüğü `dosya:satır`
|
|
111
|
+
girdilerini doğrulanmış konum say ve onları grep ile arama, listelendi diye bir dosyayı
|
|
112
|
+
düzenleme. `claude-init` ise `.mcp.json`, `CLAUDE.md` içinde işaretli bir bölüm ve
|
|
113
|
+
`bce precontext` komutunu çalıştıran bir `UserPromptSubmit` kancası yazar: kanca her
|
|
114
|
+
istemde grafı bir kez sorgular ve yanıtı ajana ilk turundan önce verir. Ajan
|
|
115
|
+
benchmark'ında ölçülen akış budur (−%20 token, yarıya inen arama çıktısı, eşit veya daha
|
|
116
|
+
iyi kontroller; React/TypeScript bir kod tabanında 14 görev, aynı model ve makine).
|
|
117
|
+
Cursor'ın istem kancası bağlam ekleyemediği için orada bu işi kural yapar. `--no-hook`,
|
|
118
|
+
`--repo-id` (tekrarlanabilir) ve `--bce-command` dosyaları ayarlar; iki komut da tekrar
|
|
119
|
+
çalıştırılmaya uygundur.
|
|
120
|
+
|
|
100
121
|
MCP yapılandırmasını ekledikten veya değiştirdikten sonra **Cursor veya VS Code'u
|
|
101
122
|
yeniden başlatın** (veya Komut Paleti → “Developer: Reload Window”). Sunucu sekiz araçla
|
|
102
123
|
(indeksleme açıkken on araçla) etkin görünmelidir. Ayrıntı: [docs/mcp.md](docs/mcp.md).
|
|
124
|
+
Elle yapmanın karşılıkları:
|
|
103
125
|
|
|
104
126
|
**Cursor** — her proje için kullanıcı yapılandırması `~/.cursor/mcp.json`, ya da yerelde
|
|
105
127
|
kalan bir proje `.cursor/mcp.json` (dizin gitignore'dadır):
|
|
@@ -165,12 +187,14 @@ Dosya yolu listesi değil. Gerekçesi ekli, sıralanmış bir paket:
|
|
|
165
187
|
},
|
|
166
188
|
"context": {
|
|
167
189
|
"items": [
|
|
168
|
-
{ "symbol_id": "...refresh_session#88c2", "
|
|
190
|
+
{ "symbol_id": "...refresh_session#88c2", "name": "refresh_session", "kind": "function",
|
|
191
|
+
"file_id": "my-service:src/auth/session.py", "line": 41, "detail_level": "full",
|
|
169
192
|
"graph_distance": 0, "score": 11.42, "tokens": 214, "content": "def refresh_session(...)" },
|
|
170
|
-
{ "symbol_id": "...SESSION_TTL#4b0d",
|
|
193
|
+
{ "symbol_id": "...SESSION_TTL#4b0d", "name": "SESSION_TTL", "kind": "constant",
|
|
194
|
+
"file_id": "my-service:src/auth/config.py", "line": 12, "detail_level": "signature",
|
|
171
195
|
"graph_distance": 2, "score": 6.10, "tokens": 31, "content": "SESSION_TTL: int" }
|
|
172
196
|
],
|
|
173
|
-
"used_tokens":
|
|
197
|
+
"used_tokens": 1388, "budget": 1500, "included": 20, "skipped": 0
|
|
174
198
|
},
|
|
175
199
|
"coverage": {
|
|
176
200
|
"anchor_source_count": 3, "connected_component_ratio": 0.875,
|
|
@@ -192,7 +216,8 @@ gereken an. `commit_mismatch` ise indeksin çalışma ağacınızın gerisinde k
|
|
|
192
216
|
|
|
193
217
|
**`detail_level`** graf mesafesiyle azalır: değiştirdiğiniz sembol tam gövdesiyle,
|
|
194
218
|
komşuları imza olarak, dış halka `name @ dosya:satır` biçiminde gelir. Gerçekten ilgili
|
|
195
|
-
|
|
219
|
+
yirmi sembolün 1500 token'a sığması bu sayede olur — bir ajanın her turda taşıyabileceği
|
|
220
|
+
kadar kısa. Her öge `file_id` ve `line` da taşır; ajan sembolü aramak yerine dosyayı açar.
|
|
196
221
|
|
|
197
222
|
## Nasıl çalışır
|
|
198
223
|
|
|
@@ -245,7 +270,36 @@ Formülün tamamı, her ağırlık ve güven eşikleri
|
|
|
245
270
|
aşama aşama oynatır: çapaların yanması, genişlemenin yayılması, adayların skorlanıp
|
|
246
271
|
kesilmesi.
|
|
247
272
|
- **Çevrimdışı çalışır.** Varsayılan embedding sağlayıcısı, token özetleri üzerinde
|
|
248
|
-
deterministik aritmetiktir. API anahtarı yok, ağ yok, tekrarlanabilir ölçümler.
|
|
273
|
+
deterministik aritmetiktir. API anahtarı yok, ağ yok, tekrarlanabilir ölçümler. `openai`
|
|
274
|
+
sağlayıcısı OpenAI uyumlu herhangi bir `/v1/embeddings` sunucusuna konuşur (vLLM, TEI,
|
|
275
|
+
Ollama); [jina-code-embeddings-1.5b](https://huggingface.co/jinaai/jina-code-embeddings-1.5b)
|
|
276
|
+
gibi bir model çevre içinde çalışır.
|
|
277
|
+
|
|
278
|
+
## Desteklenen modeller
|
|
279
|
+
|
|
280
|
+
Embedding yalnızca grafın tanımadığı bir görev metninde giriş noktası bulur. Cevabı asla
|
|
281
|
+
sıralamaz. Varsayılan `hashing`'dir: deterministik aritmetik, API anahtarı yok, ağ yok.
|
|
282
|
+
Gerçek bir kod modeli için `BCE_EMBEDDING_PROVIDER` ve `BCE_EMBEDDING_MODEL`'i şunlardan
|
|
283
|
+
birine ayarlayın:
|
|
284
|
+
|
|
285
|
+
| Model | Sağlayıcı | Boyut |
|
|
286
|
+
| --- | --- | --- |
|
|
287
|
+
| [`voyage-code-3`](https://blog.voyageai.com/2024/12/04/voyage-code-3/) | Voyage AI (`voyage`) | 1024 |
|
|
288
|
+
| [`voyage-code-4`](https://blog.voyageai.com/2026/08/13/voyage-code-4/) | Voyage AI (`voyage`) | 1024 |
|
|
289
|
+
| [`jina-code-embeddings-1.5b`](https://huggingface.co/jinaai/jina-code-embeddings-1.5b) | OpenAI uyumlu (`openai`) | 1536 |
|
|
290
|
+
|
|
291
|
+
Voyage barındırılan bir API'dir — `pip install "bgts-context-engine[embed]"` ve
|
|
292
|
+
`BCE_VOYAGE_API_KEY`. Jina çevre-içi yoldur: `/v1/embeddings` konuşan herhangi bir
|
|
293
|
+
sunucu (vLLM, TEI, Ollama). Model veya boyutu değiştirmek yeniden indekslemedir
|
|
294
|
+
(`bce migrate --reset-embeddings`). Ayarlar
|
|
295
|
+
[docs/deployment.md](docs/deployment.md) içindedir.
|
|
296
|
+
|
|
297
|
+
**Sırada** — aynı `openai` soketi, henüz ayrı bir getirme profili yok:
|
|
298
|
+
|
|
299
|
+
- [`jina-code-embeddings-0.5b`](https://huggingface.co/jinaai/jina-code-embeddings-0.5b)
|
|
300
|
+
— 1.5b'nin küçük kardeşi; 1.5B parametreyi taşıyamayan makineler için.
|
|
301
|
+
- [`Nomic Embed Code`](https://huggingface.co/nomic-ai/nomic-embed-code) — açık kaynaklı
|
|
302
|
+
7B kod getiricisi.
|
|
249
303
|
|
|
250
304
|
## Nereye oturur
|
|
251
305
|
|
|
@@ -106,6 +106,7 @@ include = ["bce*"]
|
|
|
106
106
|
bce = [
|
|
107
107
|
"core/i18n/catalogs/*.json",
|
|
108
108
|
"storage/relational/migrations/*.sql",
|
|
109
|
+
"integrations/templates/*",
|
|
109
110
|
# Compiled frontend served at /ui; vendored by scripts/build_ui.py before a release build.
|
|
110
111
|
"api/rest/static/**/*",
|
|
111
112
|
]
|
|
@@ -44,8 +44,9 @@ def build_server(name: str = "bgts-context-engine") -> Any:
|
|
|
44
44
|
from bce.config import get_settings
|
|
45
45
|
from bce.storage.relational.db import connection
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
settings = get_settings()
|
|
48
|
+
allow_write = settings.mcp_allow_write
|
|
49
|
+
specs = available_tool_specs(allow_write=allow_write, allowlist=settings.mcp_tool_allowlist)
|
|
49
50
|
server = Server(name)
|
|
50
51
|
|
|
51
52
|
@server.list_tools()
|
|
@@ -56,6 +57,8 @@ def build_server(name: str = "bgts-context-engine") -> Any:
|
|
|
56
57
|
]
|
|
57
58
|
|
|
58
59
|
def _dispatch_blocking(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
|
|
60
|
+
if name not in specs:
|
|
61
|
+
raise KeyError(f"tool '{name}' is not advertised by this server (BCE_MCP_TOOLS)")
|
|
59
62
|
with connection() as conn:
|
|
60
63
|
try:
|
|
61
64
|
result = dispatch_tool(conn, name, arguments, allow_write=allow_write)
|
|
@@ -26,6 +26,7 @@ from typing import Any
|
|
|
26
26
|
import psycopg
|
|
27
27
|
|
|
28
28
|
from bce.core.auth.scope import Principal, ScopeFilter
|
|
29
|
+
from bce.core.defaults import DEFAULT_MAX_CANDIDATES, DEFAULT_MAX_TOKENS
|
|
29
30
|
from bce.core.i18n import get_translator
|
|
30
31
|
from bce.jobs.store import enqueue_job, get_job, list_jobs
|
|
31
32
|
from bce.storage.graph.client import GraphClient
|
|
@@ -57,10 +58,21 @@ TOOL_SPECS: dict[str, dict[str, Any]] = {
|
|
|
57
58
|
),
|
|
58
59
|
"schema": _schema(
|
|
59
60
|
{
|
|
60
|
-
"task_text":
|
|
61
|
+
"task_text": {
|
|
62
|
+
**_STR,
|
|
63
|
+
"description": "The task in prose; pass the full request text, once.",
|
|
64
|
+
},
|
|
61
65
|
"task_id": _STR,
|
|
62
|
-
"max_tokens":
|
|
63
|
-
|
|
66
|
+
"max_tokens": {
|
|
67
|
+
**_INT,
|
|
68
|
+
"default": DEFAULT_MAX_TOKENS,
|
|
69
|
+
"description": "Token budget of the assembled context.",
|
|
70
|
+
},
|
|
71
|
+
"max_candidates": {
|
|
72
|
+
**_INT,
|
|
73
|
+
"default": DEFAULT_MAX_CANDIDATES,
|
|
74
|
+
"description": "How many symbols to return (K).",
|
|
75
|
+
},
|
|
64
76
|
"commit": _STR,
|
|
65
77
|
"repo_ids": _STR_LIST,
|
|
66
78
|
"explicit_symbols": _STR_LIST,
|
|
@@ -137,11 +149,24 @@ TOOL_SPECS: dict[str, dict[str, Any]] = {
|
|
|
137
149
|
}
|
|
138
150
|
|
|
139
151
|
|
|
140
|
-
def available_tool_specs(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
152
|
+
def available_tool_specs(
|
|
153
|
+
*, allow_write: bool, allowlist: frozenset[str] | None = None
|
|
154
|
+
) -> dict[str, dict[str, Any]]:
|
|
155
|
+
"""The catalog to advertise: write tools are hidden unless ``allow_write`` is set, and an
|
|
156
|
+
``allowlist`` (``BCE_MCP_TOOLS``) narrows it further. Unknown names in the allowlist raise, so a
|
|
157
|
+
typo does not silently publish nothing."""
|
|
158
|
+
if allowlist is not None:
|
|
159
|
+
unknown = sorted(allowlist - set(TOOL_SPECS))
|
|
160
|
+
if unknown:
|
|
161
|
+
raise ValueError(
|
|
162
|
+
f"BCE_MCP_TOOLS names unknown tools {unknown}; known: {sorted(TOOL_SPECS)}"
|
|
163
|
+
)
|
|
164
|
+
specs = {
|
|
165
|
+
name: spec
|
|
166
|
+
for name, spec in TOOL_SPECS.items()
|
|
167
|
+
if (allow_write or name not in WRITE_TOOLS) and (allowlist is None or name in allowlist)
|
|
168
|
+
}
|
|
169
|
+
return specs
|
|
145
170
|
|
|
146
171
|
|
|
147
172
|
def dispatch_tool(
|
|
@@ -11,6 +11,8 @@ from typing import Any
|
|
|
11
11
|
|
|
12
12
|
from pydantic import BaseModel, Field
|
|
13
13
|
|
|
14
|
+
from bce.core.defaults import DEFAULT_MAX_CANDIDATES, DEFAULT_MAX_TOKENS
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
class IndexRequest(BaseModel):
|
|
16
18
|
repo_path: str = Field(..., description="Path to a local repository to index.")
|
|
@@ -64,9 +66,11 @@ class ContextForTaskRequest(BaseModel):
|
|
|
64
66
|
task_id: str | None = Field(
|
|
65
67
|
default=None, description="Optional Jira task id (audit + history)."
|
|
66
68
|
)
|
|
67
|
-
max_tokens: int = Field(
|
|
69
|
+
max_tokens: int = Field(
|
|
70
|
+
default=DEFAULT_MAX_TOKENS, ge=1, le=200000, description="Token budget for assembly."
|
|
71
|
+
)
|
|
68
72
|
max_candidates: int = Field(
|
|
69
|
-
default=
|
|
73
|
+
default=DEFAULT_MAX_CANDIDATES, ge=1, le=100, description="Narrow to at most N candidates."
|
|
70
74
|
)
|
|
71
75
|
commit: str | None = Field(default=None, description="Pinned commit sha (stage 0).")
|
|
72
76
|
repo_ids: list[str] | None = Field(
|
|
@@ -108,7 +112,7 @@ class AssembleContextRequest(BaseModel):
|
|
|
108
112
|
symbol_ids: list[str] = Field(
|
|
109
113
|
..., description="Symbols to deduplicate and fit into the budget."
|
|
110
114
|
)
|
|
111
|
-
max_tokens: int = Field(default=
|
|
115
|
+
max_tokens: int = Field(default=DEFAULT_MAX_TOKENS, ge=1, le=200000)
|
|
112
116
|
|
|
113
117
|
|
|
114
118
|
class ToolResponse(BaseModel):
|
|
@@ -21,6 +21,7 @@ from bce.core.coverage import compute_coverage
|
|
|
21
21
|
from bce.core.orchestrator.anchors import find_anchors
|
|
22
22
|
from bce.core.orchestrator.expand import expand_from_anchors, to_candidates
|
|
23
23
|
from bce.core.orchestrator.orchestrator import RetrievalResult, narrow
|
|
24
|
+
from bce.core.orchestrator.profile import active_profile
|
|
24
25
|
from bce.core.orchestrator.text import content_tokens
|
|
25
26
|
from bce.core.scoring.engine import ScoreWeights, score_candidates
|
|
26
27
|
from bce.storage.graph.repository import GraphRepository
|
|
@@ -69,6 +70,7 @@ def trace_context_for_task(
|
|
|
69
70
|
|
|
70
71
|
# Stage 1: multi-source anchors (spec section 6.2), with evidence strength per anchor.
|
|
71
72
|
t = time.perf_counter()
|
|
73
|
+
profile = active_profile()
|
|
72
74
|
anchors = find_anchors(
|
|
73
75
|
repository,
|
|
74
76
|
task_text=task_text,
|
|
@@ -78,6 +80,7 @@ def trace_context_for_task(
|
|
|
78
80
|
component_repo_ids=None,
|
|
79
81
|
repo_ids=repo_ids,
|
|
80
82
|
semantic_candidates=semantic_candidates,
|
|
83
|
+
profile=profile,
|
|
81
84
|
)
|
|
82
85
|
stages.append(
|
|
83
86
|
{
|
|
@@ -139,7 +142,7 @@ def trace_context_for_task(
|
|
|
139
142
|
|
|
140
143
|
# Stage 4: diversity-aware narrowing to top-N (the "1000 -> 8" step).
|
|
141
144
|
t = time.perf_counter()
|
|
142
|
-
narrowed = narrow(ranked, max_candidates)
|
|
145
|
+
narrowed = narrow(ranked, max_candidates, profile=profile)
|
|
143
146
|
stages.append(
|
|
144
147
|
{
|
|
145
148
|
"stage": "narrow",
|