vectr 1.0.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.
- agent/__init__.py +0 -0
- agent/cartographer.py +428 -0
- agent/chunk_quality.py +1119 -0
- agent/config.py +648 -0
- agent/config.yaml +1153 -0
- agent/eviction_advisor.py +447 -0
- agent/identifier_hint.py +68 -0
- agent/indexer/__init__.py +112 -0
- agent/indexer/_chunking.py +458 -0
- agent/indexer/_constants.py +105 -0
- agent/indexer/_core.py +878 -0
- agent/indexer/_types.py +157 -0
- agent/instance_registry.py +127 -0
- agent/llm_client.py +8 -0
- agent/model_cache.py +101 -0
- agent/prompt_templates.py +31 -0
- agent/searcher.py +848 -0
- agent/strategy_selector.py +299 -0
- agent/symbol_graph/__init__.py +131 -0
- agent/symbol_graph/_constants.py +366 -0
- agent/symbol_graph/_extraction.py +528 -0
- agent/symbol_graph/_graph.py +1878 -0
- agent/symbol_graph/_types.py +35 -0
- agent/templates/claude_md.md +65 -0
- agent/templates/claude_md_search_only.md +27 -0
- agent/templates/cursor_mcp.json.template +7 -0
- agent/templates/cursor_rules_header.txt +5 -0
- agent/templates/hook_no_double_recall.txt +1 -0
- agent/templates/mcp.json.template +8 -0
- agent/templates/session_start_guidance_default.txt +3 -0
- agent/templates/session_start_guidance_hooks_aware.txt +1 -0
- agent/templates/tool_loading_guidance_claude.txt +1 -0
- agent/templates/tool_loading_guidance_claude_search_only.txt +1 -0
- agent/templates/vscode_mcp.json.template +8 -0
- agent/tool_necessity_probe.py +177 -0
- agent/version_stamp.py +58 -0
- agent/watcher.py +515 -0
- agent/working_context_store/__init__.py +76 -0
- agent/working_context_store/_audit.py +46 -0
- agent/working_context_store/_encryption.py +75 -0
- agent/working_context_store/_store.py +1130 -0
- agent/working_context_store/_types.py +50 -0
- api.py +101 -0
- app/__init__.py +0 -0
- app/models.py +368 -0
- app/routes.py +451 -0
- app/service.py +1055 -0
- integrations/__init__.py +0 -0
- integrations/mcp_server/__init__.py +73 -0
- integrations/mcp_server/_dispatch.py +782 -0
- integrations/mcp_server/_schemas.py +484 -0
- integrations/mcp_server/_session.py +86 -0
- integrations/vscode_bridge.py +71 -0
- integrations/workspace_detect.py +259 -0
- main.py +2037 -0
- vectr-1.0.0.dist-info/METADATA +37 -0
- vectr-1.0.0.dist-info/RECORD +61 -0
- vectr-1.0.0.dist-info/WHEEL +5 -0
- vectr-1.0.0.dist-info/entry_points.txt +2 -0
- vectr-1.0.0.dist-info/licenses/LICENSE +21 -0
- vectr-1.0.0.dist-info/top_level.txt +5 -0
agent/config.yaml
ADDED
|
@@ -0,0 +1,1153 @@
|
|
|
1
|
+
# vectr internal configuration — versioned in the repo.
|
|
2
|
+
# All tunables that affect ranking behaviour live here so changes are auditable
|
|
3
|
+
# via git history rather than buried in code.
|
|
4
|
+
#
|
|
5
|
+
# Do NOT set these via environment variables or per-user config files.
|
|
6
|
+
# Runtime code reads this file via importlib.resources so it works for both
|
|
7
|
+
# the repo-local interpreter and the pip-installed global binary.
|
|
8
|
+
|
|
9
|
+
ranking:
|
|
10
|
+
quality_priors:
|
|
11
|
+
# Multipliers applied to the hybrid similarity score. 1.0 = neutral.
|
|
12
|
+
# Lower = de-ranked further. Applied in chunk_quality.quality_score().
|
|
13
|
+
|
|
14
|
+
# Bare stub chunks with almost no content (single-line import, lone brace, etc.)
|
|
15
|
+
trivial: 0.15
|
|
16
|
+
|
|
17
|
+
# Maximum number of non-blank lines a HTML/markup or plain-text chunk may contain
|
|
18
|
+
# and still be classified as trivial by is_trivial_chunk() (UPG-15.5).
|
|
19
|
+
# 1-line and 2-line test-fixture templates ("Logged out", "{{ form }}", top_level.txt)
|
|
20
|
+
# are trivial; any real doc prose chunk has many more lines than this.
|
|
21
|
+
# Must be a small integer (≥1) so that multi-line .txt/.rst documentation
|
|
22
|
+
# (Django docs/howto/*.txt, docs/topics/*.txt) are NOT classified trivial.
|
|
23
|
+
# Conservative default: 2 — catches single-line HTML templates and 1–2-line
|
|
24
|
+
# TXT fixtures without risk of demoting substantive documentation.
|
|
25
|
+
trivial_doc_max_lines: 2
|
|
26
|
+
|
|
27
|
+
# Re-export / import-only "navigational" chunks (no implementation substance)
|
|
28
|
+
navigational: 0.35
|
|
29
|
+
|
|
30
|
+
# UPG-NAV-OVERDEMOTE-DECL (F59): a bare-constructor-manifest chunk (UPG-
|
|
31
|
+
# PREFIX-COMPOSE's ``request_started = Signal()`` pattern) is ALSO the
|
|
32
|
+
# corpus-wide unique declaration site of each name it assigns. For a
|
|
33
|
+
# conceptual query ("signal dispatcher implementation") the manifest is
|
|
34
|
+
# correctly navigational-demoted to `navigational` above (F44/F53's
|
|
35
|
+
# re-export-stub-overrank fix). For a query that names one of the
|
|
36
|
+
# declared identifiers directly ("where is request_started signal
|
|
37
|
+
# defined") — a lexical match, gated on the query's own BM25 tokens, not
|
|
38
|
+
# a keyword list — the chunk IS the singular correct answer and the full
|
|
39
|
+
# navigational demotion buries it (F59: django/core/signals.py absent
|
|
40
|
+
# from top-25 despite being in the candidate pool). This softened value
|
|
41
|
+
# applies only in that lexically-gated case (chunk_quality.quality_score
|
|
42
|
+
# query_tokens argument); every other query for the same chunk still
|
|
43
|
+
# gets the full `navigational` demotion. Measured against the F59 offline
|
|
44
|
+
# replay (benchmarks/acceptance/product_cases.jsonl, django corpus,
|
|
45
|
+
# tmp/vectr-accept-django index): the pool-rank gap needs a value in this
|
|
46
|
+
# range to surface the chunk in top-10 without letting the still-nav-
|
|
47
|
+
# shaped chunk outrank undemoted real implementation code (kept < 1.0).
|
|
48
|
+
navigational_declaration_rescue: 0.75
|
|
49
|
+
|
|
50
|
+
# Markdown chunks that contain only headings (no prose or code body)
|
|
51
|
+
heading_only: 0.40
|
|
52
|
+
|
|
53
|
+
# Machine-generated files (migrations, protobuf output, build artifacts)
|
|
54
|
+
generated: 0.45
|
|
55
|
+
|
|
56
|
+
# vectr's own config files — we never want to surface our own internals
|
|
57
|
+
vectr_config: 0.10
|
|
58
|
+
|
|
59
|
+
# Test files when the query does not explicitly target tests. UPG-PREFIX-
|
|
60
|
+
# COMPOSE: lowered from 0.55 — once the query-prefix fix (UPG-ARCTIC-QUERY-
|
|
61
|
+
# PREFIX) changed dense pool composition, a test-file symbol whose name or
|
|
62
|
+
# docstring happens to restate the query in plain language (e.g. a helper
|
|
63
|
+
# class documented as "track threads and kwargs when signals are
|
|
64
|
+
# dispatched") could out-rank the canonical production symbol it merely
|
|
65
|
+
# name-echoes, because purpose_rank's textual-similarity boost (below) is
|
|
66
|
+
# otherwise blind to quality tier. 0.46 is the largest reduction that still
|
|
67
|
+
# satisfies test_ordering's invariant (test_deprioritised > generated=0.45,
|
|
68
|
+
# tests/test_chunk_quality.py::TestQualityScore::test_ordering) — this value
|
|
69
|
+
# only matters in combination with purpose_rank.lambda below (see there for
|
|
70
|
+
# the joint tuning rationale); it does not fix anything on its own.
|
|
71
|
+
test_deprioritised: 0.46
|
|
72
|
+
|
|
73
|
+
# UPG-TESTPATH-FRAMEWORK-MISCLASS (F58): is_test_file()'s path-segment
|
|
74
|
+
# heuristic (any "test"/"tests"/... directory component) cannot tell a
|
|
75
|
+
# disposable test module apart from a shipped testing-FRAMEWORK subpackage
|
|
76
|
+
# that happens to live at a test-named path (e.g. django/test/utils.py —
|
|
77
|
+
# a stable public API, not a throwaway test). Filtering by "called only
|
|
78
|
+
# from non-test files" was measured and rejected: a testing framework is,
|
|
79
|
+
# by definition, called almost exclusively from test code, so that signal
|
|
80
|
+
# never fires (0/175 measured non-test callers of override_settings on
|
|
81
|
+
# the django corpus) even though the file plainly IS shipped API surface.
|
|
82
|
+
# The signal that DOES discriminate cleanly is corpus-wide unambiguous
|
|
83
|
+
# caller BREADTH: symbol_graph.file_fan_in() counts, per file, the number
|
|
84
|
+
# of DISTINCT calling files across edges whose target symbol name
|
|
85
|
+
# resolves to exactly one defining file corpus-wide (excludes common
|
|
86
|
+
# same-leaf collisions like __init__/setUp that would otherwise dilute
|
|
87
|
+
# the count with unrelated files). Measured on the django corpus:
|
|
88
|
+
# django/test/utils.py=285, django/test/testcases.py=518,
|
|
89
|
+
# django/test/client.py=85, vs. the next-highest genuinely-disposable
|
|
90
|
+
# test file at 42 and a median near 0 — a wide, well-separated gap.
|
|
91
|
+
# A file at or above this threshold is exempted from the
|
|
92
|
+
# test_deprioritised multiplier above regardless of its path.
|
|
93
|
+
test_framework_fan_in_threshold: 60
|
|
94
|
+
|
|
95
|
+
# substantive documentation prose vs implementation code
|
|
96
|
+
doc_prose: 0.70
|
|
97
|
+
|
|
98
|
+
# bodies with very few meaningful lines
|
|
99
|
+
short_penalty: 0.80
|
|
100
|
+
|
|
101
|
+
# A private/internal symbol (single leading underscore, e.g. `_helper`,
|
|
102
|
+
# not a dunder like `__init__`) is a mild demotion vs. its public-API
|
|
103
|
+
# sibling. This is a language-general naming convention (Python's PEP 8
|
|
104
|
+
# "internal use" prefix; the same single-underscore-for-internal idiom
|
|
105
|
+
# appears in Go, JS/TS, and Rust codebases too), not a corpus- or query-
|
|
106
|
+
# specific rule, so it applies uniformly regardless of query text.
|
|
107
|
+
# Root cause it addresses: a keyword-dense private helper's raw text can
|
|
108
|
+
# score higher on cross-encoder + BM25 similarity than the public method
|
|
109
|
+
# a natural-language query is actually asking about, because the helper's
|
|
110
|
+
# body happens to restate more of the query's vocabulary literally (e.g.
|
|
111
|
+
# a queryset-filtering helper's body mentions "queryset"/"filter" several
|
|
112
|
+
# times while the public method it supports has a terse one-line body).
|
|
113
|
+
# The importance/purpose priors (ranking.importance_prior, ranking.
|
|
114
|
+
# purpose_rank) already favor the public symbol's file/class, but a
|
|
115
|
+
# sizeable base-rerank gap from the raw-text-similarity effect above can
|
|
116
|
+
# still outweigh them; this prior corrects the imbalance at its source
|
|
117
|
+
# (django/db/models/query.py QuerySet.filter vs. the private
|
|
118
|
+
# _filter_prefetch_queryset helper in fields/related_descriptors.py is
|
|
119
|
+
# the measured witness case, UPG-16.1/F30). Mild (comparable to
|
|
120
|
+
# short_penalty) because a private helper is still legitimate,
|
|
121
|
+
# sometimes-wanted code — just usually not the intended answer to a
|
|
122
|
+
# concept-level query naming the public operation.
|
|
123
|
+
private_symbol_deprioritised: 0.80
|
|
124
|
+
|
|
125
|
+
# Maximum number of attribute-assignment body lines for an attribute-only
|
|
126
|
+
# class body to be classified as trivial by is_trivial_chunk() (UPG-15.9 / F25).
|
|
127
|
+
# A ``class Meta:`` inner stub with ≤ this many attribute-assignment body lines
|
|
128
|
+
# and NO method definitions / control flow is trivial — it is a configuration
|
|
129
|
+
# stub, not a real class definition. Django test files have 200+ such 3-line
|
|
130
|
+
# stubs (class Meta: / model = X / fields = '__all__') that flood doc-intent
|
|
131
|
+
# queries. Real small library classes with more attributes or any method body
|
|
132
|
+
# are unaffected. Conservative default 3: catches the dominant Meta stub
|
|
133
|
+
# pattern without risk of demoting real dataclass-style classes.
|
|
134
|
+
trivial_attr_class_max_attrs: 3
|
|
135
|
+
|
|
136
|
+
importance_prior:
|
|
137
|
+
# ARCH-1b: file-level PageRank importance (computed at index time by ARCH-1a,
|
|
138
|
+
# stored in the symbol_importance table) is blended into the FINAL search sort
|
|
139
|
+
# as a relevance-gated multiplicative prior:
|
|
140
|
+
# final_score = base_rerank_score * quality_score * (1 + lambda * importance)
|
|
141
|
+
# where importance ∈ [0,1] is the normalized file-level PageRank of the chunk's
|
|
142
|
+
# file (0 when unknown). The multiply by base_rerank_score keeps it relevance-
|
|
143
|
+
# gated — an irrelevant high-importance file (base ≈ 0) is not lifted. A global
|
|
144
|
+
# standing prior (canonical = most-referenced), NOT a query-keyword heuristic.
|
|
145
|
+
# lambda=0 disables it (behaviour identical to pre-ARCH-1b). Conservative default
|
|
146
|
+
# 0.25: reorders near-ties toward canonical files without overriding clear
|
|
147
|
+
# relevance. Live F22/F23 tuning is tracked in tasks.md ARCH-1b.
|
|
148
|
+
lambda: 0.25
|
|
149
|
+
|
|
150
|
+
class_importance:
|
|
151
|
+
# ARCH-2: class/symbol-name "canonical = most-referenced" importance
|
|
152
|
+
# (whole-word reference frequency of the name across the corpus, computed
|
|
153
|
+
# at index time by SymbolGraph._compute_and_store_class_importance and
|
|
154
|
+
# stored in the class_importance table) is blended into the FINAL search
|
|
155
|
+
# sort as a second relevance-gated multiplicative prior, alongside
|
|
156
|
+
# ARCH-1b's file-level prior:
|
|
157
|
+
# final_score = base_rerank_score * quality_score
|
|
158
|
+
# * (1 + lambda_file * file_importance)
|
|
159
|
+
# * (1 + lambda_class * class_importance)
|
|
160
|
+
# where class_importance ∈ [0,1] is the normalized reference frequency of
|
|
161
|
+
# the relevant name. This is the lever for same-leaf collisions (two
|
|
162
|
+
# unrelated classes that both define a method with the same name; a
|
|
163
|
+
# canonical type's own definition chunk crowded by a same-file, narrower
|
|
164
|
+
# sibling type; a corpus-central module-level function crowded by a
|
|
165
|
+
# rarely-referenced sibling function — UPG-SIBLING-TYPEDEF-CROWDING) that
|
|
166
|
+
# file-level importance cannot discriminate — a symbol's own body often IS
|
|
167
|
+
# the file, so file-level PageRank has no separating signal.
|
|
168
|
+
#
|
|
169
|
+
# UPG-SIBLING-TYPEDEF-CROWDING extended attribution beyond methods: a
|
|
170
|
+
# METHOD chunk still uses its owning class's name (unchanged); a
|
|
171
|
+
# TYPE-DEFINITION chunk (struct/enum/trait/class/interface/typedef) or a
|
|
172
|
+
# MODULE-LEVEL FUNCTION chunk is instead attributed to its OWN name —
|
|
173
|
+
# previously stuck at class_importance=0 forever since neither has an
|
|
174
|
+
# owning-class context to key off. See agent/searcher.py
|
|
175
|
+
# (is_type_definition_chunk / is_module_level_function_chunk gated
|
|
176
|
+
# lookup).
|
|
177
|
+
#
|
|
178
|
+
# lambda=0 disables it (behaviour identical to pre-ARCH-2). Conservative
|
|
179
|
+
# default 0.25, matching ARCH-1b's default: reorders same-leaf look-alikes
|
|
180
|
+
# toward the canonical symbol without overriding clear relevance — the
|
|
181
|
+
# multiplicative gate bounds the factor to [1, 1+lambda] regardless of how
|
|
182
|
+
# skewed the importance map is, so a modest lambda here cannot let even a
|
|
183
|
+
# maximum-importance rival overturn a clear cross-encoder relevance lead.
|
|
184
|
+
# Live F22/F23 tuning is tracked in tasks.md ARCH-2.
|
|
185
|
+
lambda: 0.25
|
|
186
|
+
|
|
187
|
+
purpose_rank:
|
|
188
|
+
# ARCH-4b: carries the ARCH-4 dual-vector purpose similarity (STEP-0/ARCH-4
|
|
189
|
+
# gated it into POOL ENTRY only) into the FINAL search sort as a third
|
|
190
|
+
# relevance-gated multiplicative prior, alongside ARCH-1b's file-level and
|
|
191
|
+
# ARCH-2's class-level priors:
|
|
192
|
+
# final_score = base_rerank_score * quality_score
|
|
193
|
+
# * (1 + lambda_file * file_importance)
|
|
194
|
+
# * (1 + lambda_class * class_importance)
|
|
195
|
+
# * (1 + lambda_purpose * purpose_sim)
|
|
196
|
+
# where purpose_sim ∈ [0,1] is the chunk's own body-vs-purpose-vector cosine
|
|
197
|
+
# similarity to the query (0 when the chunk has no purpose vector, e.g. a
|
|
198
|
+
# doc/config chunk, or dual_vector is disabled). Without this, a symbol whose
|
|
199
|
+
# signature+docstring is the single best purpose match in the corpus can still
|
|
200
|
+
# be buried under its own subclasses/near-duplicates in the final MCP ranking,
|
|
201
|
+
# because the cross-encoder rerank that dominates base_rerank_score only sees
|
|
202
|
+
# BODY text and has no visibility into the purpose signal that got the chunk
|
|
203
|
+
# into the pool in the first place. lambda=0 disables it (behaviour identical
|
|
204
|
+
# to pre-ARCH-4b). Default 0.9 (raised from ARCH-4b's original 0.5 by
|
|
205
|
+
# UPG-PREFIX-COMPOSE, see below), higher than ARCH-1b/ARCH-2's 0.25: those
|
|
206
|
+
# two priors are typically fed near-binary importance scores (0 or ~1), so a
|
|
207
|
+
# one-rank near-tie gap clears at 0.25; purpose_sim is a continuous cosine
|
|
208
|
+
# similarity that rarely reaches 1.0 even for a strong match and must also
|
|
209
|
+
# recover deeper rerank-pool burial (observed: purpose-rank-1 chunk landing
|
|
210
|
+
# at final rank 16 in a ~60-candidate pool) — algebra on the multiplicative
|
|
211
|
+
# gate shows 0.25 only clears a 1-of-10-rank gap, not a 15-of-60-rank gap.
|
|
212
|
+
# See TestPurposeRankPrior in tests/test_indexer_searcher.py for the worked
|
|
213
|
+
# cases.
|
|
214
|
+
#
|
|
215
|
+
# UPG-PREFIX-COMPOSE: purpose_sim measures textual similarity between the
|
|
216
|
+
# query and a chunk's own qualified-name+docstring independent of the
|
|
217
|
+
# chunk's quality tier, so a quality-demoted chunk (a test helper whose
|
|
218
|
+
# docstring happens to restate the query in plain language) can carry a
|
|
219
|
+
# HIGHER purpose_sim than the canonical production symbol it name-echoes —
|
|
220
|
+
# letting a shallow textual echo outrank the real implementation no matter
|
|
221
|
+
# how large lambda is scaled, since raising lambda amplifies the demoted
|
|
222
|
+
# chunk's edge by the same factor (a case witnessed on the django corpus:
|
|
223
|
+
# a test-only helper class's docstring out-scored the production Signal
|
|
224
|
+
# class's own docstring on raw cosine similarity). Raising this lambda
|
|
225
|
+
# alone (against the un-weighted prior) to clear that gap also
|
|
226
|
+
# disproportionately boosts every OTHER demoted-but-purpose-matching chunk
|
|
227
|
+
# against non-symbol content that has no purpose vector at all (prose/doc
|
|
228
|
+
# chunks default purpose_sim to 0 — see above), which was observed to
|
|
229
|
+
# invert an unrelated doc-vs-test-code ranking on the same corpus. The
|
|
230
|
+
# searcher now weights this factor by the chunk's own quality_score
|
|
231
|
+
# (1 + lambda * purpose_sim * quality_score, in
|
|
232
|
+
# agent/searcher.py._apply_quality_and_dedup) so a demoted chunk's textual
|
|
233
|
+
# echo can no longer buy back more rank than an undemoted chunk's smaller
|
|
234
|
+
# one, while an undemoted (quality=1.0) candidate keeps the full boost.
|
|
235
|
+
# With that weighting, lambda=0.9 (paired with test_deprioritised=0.46
|
|
236
|
+
# above) is stable across a lambda range of roughly [0.7, 1.1] on the
|
|
237
|
+
# verified case above — not a knife-edge value — and the full django
|
|
238
|
+
# offline acceptance replay (benchmarks/acceptance/product_cases.jsonl)
|
|
239
|
+
# shows zero other case flipped by this change.
|
|
240
|
+
lambda: 0.9
|
|
241
|
+
|
|
242
|
+
type_def_prior:
|
|
243
|
+
# UPG-RUST-DEF-EVICTION / DEF-B: a fourth relevance-gated multiplicative
|
|
244
|
+
# prior, same shape as file_importance/class_importance/purpose_rank
|
|
245
|
+
# above:
|
|
246
|
+
# final_score = base_rerank_score * quality_score
|
|
247
|
+
# * (1 + lambda_file * file_importance)
|
|
248
|
+
# * (1 + lambda_class * class_importance)
|
|
249
|
+
# * (1 + lambda_purpose * purpose_sim * quality_score)
|
|
250
|
+
# * (1 + lambda_def * is_type_definition)
|
|
251
|
+
# where is_type_definition is 1 when the chunk's own node_type is a TYPE
|
|
252
|
+
# DEFINITION (struct/enum/trait/class/interface — see
|
|
253
|
+
# chunk_quality.is_type_definition_chunk), else 0. Cross-language witness:
|
|
254
|
+
# a struct/type's canonical definition chunk repeatedly loses to same-name
|
|
255
|
+
# test code and usage sites at comparable rerank scores because the
|
|
256
|
+
# cross-encoder has no visibility into "this chunk IS the definition" —
|
|
257
|
+
# only the AST does. lambda=0 disables it (pre-DEF-B behaviour). Default
|
|
258
|
+
# 0.15, smaller than class_importance/file_importance's 0.25: this prior
|
|
259
|
+
# fires on every type-def chunk unconditionally (not gated by corpus-wide
|
|
260
|
+
# reference frequency), so a larger lambda would systematically favour
|
|
261
|
+
# definitions over well-matched usage sites even when the usage IS the
|
|
262
|
+
# better answer to the query.
|
|
263
|
+
lambda: 0.15
|
|
264
|
+
|
|
265
|
+
docstring_dedup:
|
|
266
|
+
# UPG-RUST-DEF-EVICTION / DEF-C: a second, independent dedup key
|
|
267
|
+
# (alongside the existing byte-normalized full-content key, UPG-2.2)
|
|
268
|
+
# keyed on a chunk's normalized LEADING docstring/comment block only.
|
|
269
|
+
# Near-duplicate boilerplate headers (the same rustdoc/JSDoc/docstring
|
|
270
|
+
# copy-pasted across several thin wrapper/test chunks with otherwise
|
|
271
|
+
# different bodies) evade the full-content key but still bury the
|
|
272
|
+
# canonical definition under several near-identical-looking results.
|
|
273
|
+
# `lines` bounds how many leading doc lines are compared (matches the
|
|
274
|
+
# dual-vector purpose-text docstring cap's spirit — a header is a header,
|
|
275
|
+
# extra lines rarely add distinguishing signal). `min_chars` is a floor
|
|
276
|
+
# on the normalized header's length below which a chunk is NEVER folded
|
|
277
|
+
# into this key (chunks with a trivial/near-empty leading header, or none
|
|
278
|
+
# at all, keep every occurrence — collapsing on near-nothing would fold
|
|
279
|
+
# together unrelated chunks that merely share a blank or 1-word header).
|
|
280
|
+
lines: 3
|
|
281
|
+
min_chars: 20
|
|
282
|
+
|
|
283
|
+
locate_ranking:
|
|
284
|
+
# UPG-15.10: scope-depth + line-span signals for locate ranking.
|
|
285
|
+
# These penalise class/function definitions that are buried inside function
|
|
286
|
+
# bodies (inner test-scope defs) and reward large, substantive definitions.
|
|
287
|
+
|
|
288
|
+
# Line-span threshold (in lines) above which a symbol definition is considered
|
|
289
|
+
# "large" — typically a canonical library class or function. Symbols with
|
|
290
|
+
# end_line - start_line >= this value get the best span bucket (0).
|
|
291
|
+
# Django's Model base class has ~1400 lines; real functions are ≥10 lines.
|
|
292
|
+
# Test-inner stubs are typically 2–5 lines.
|
|
293
|
+
large_span_threshold: 50
|
|
294
|
+
|
|
295
|
+
# Line-span threshold below which a symbol definition is considered "tiny" —
|
|
296
|
+
# a stub or inner test class. Symbols with span < this value get the worst
|
|
297
|
+
# span bucket (2); spans in [small, large) get bucket 1.
|
|
298
|
+
small_span_threshold: 10
|
|
299
|
+
|
|
300
|
+
rerank:
|
|
301
|
+
# Cross-encoder reranker model (HuggingFace id). The VECTR_RERANKER_MODEL
|
|
302
|
+
# env var overrides this key (test fixtures rely on that); an empty value
|
|
303
|
+
# disables reranking entirely. Swapping this model needs no reindex —
|
|
304
|
+
# the reranker scores (query, chunk) pairs at query time only.
|
|
305
|
+
model: "BAAI/bge-reranker-base"
|
|
306
|
+
|
|
307
|
+
# rerank this many hybrid candidates before trimming to n_results
|
|
308
|
+
top_k: 40
|
|
309
|
+
|
|
310
|
+
# When no language filter is set, doc prose dominates the shallow hybrid pool and
|
|
311
|
+
# real implementation chunks fall outside it (audit: extractor.py / chunk_file never
|
|
312
|
+
# fetched). Fetch a deeper pool in that case so the quality prior has code to surface.
|
|
313
|
+
top_k_unfiltered: 60
|
|
314
|
+
|
|
315
|
+
# Over-fetch depth for the pool-entry trivial filter (UPG-15.7).
|
|
316
|
+
# Before trimming to top_k_unfiltered, the hybrid retrieval fetches this many raw
|
|
317
|
+
# candidates, drops any that are trivial (is_trivial_chunk == True) and not
|
|
318
|
+
# forced-inclusion candidates, THEN trims to top_k_unfiltered. This ensures the
|
|
319
|
+
# rerank pool of ~60 is filled with real code even on fixture-heavy repos
|
|
320
|
+
# (a large web codebase can carry a hundred-plus 1–2-line HTML/TXT template
|
|
321
|
+
# chunks that otherwise crowd out code).
|
|
322
|
+
# Rule: pre_filter_fetch_k must be >= top_k_unfiltered. ~200 covers such
|
|
323
|
+
# fixture blocks while remaining a tiny fraction of a 40k-chunk corpus.
|
|
324
|
+
# The cross-encoder reranker only sees ~top_k_unfiltered (~60) candidates, so latency
|
|
325
|
+
# is unaffected by this wider initial fetch.
|
|
326
|
+
pre_filter_fetch_k: 200
|
|
327
|
+
|
|
328
|
+
notfound_floor:
|
|
329
|
+
# UPG-NOTFOUND-FLOOR (F46): the score shown to the caller is the FINAL
|
|
330
|
+
# rank-based composite (searcher._apply_quality_and_dedup: base = 1 -
|
|
331
|
+
# rank/n, then quality/importance multipliers) — it is re-derived from
|
|
332
|
+
# each query's own candidate ORDER, so the top result of any query always
|
|
333
|
+
# displays close to 1.0 even when every candidate is irrelevant. A signal
|
|
334
|
+
# independent of that per-query rescaling is needed to tell the caller
|
|
335
|
+
# the whole result set may be a guess.
|
|
336
|
+
#
|
|
337
|
+
# UPG-NOTFOUND-FLOOR-2: the first version of this signal gated on the raw
|
|
338
|
+
# pre-rerank vector-search cosine similarity (the one score in the
|
|
339
|
+
# pipeline NOT re-normalized per query) against an absolute constant
|
|
340
|
+
# (dense_score_floor). Measured against the production embedder on a
|
|
341
|
+
# large real corpus, that constant never fires: an absent-topic query's
|
|
342
|
+
# best pool cosine and a genuinely on-topic query's best pool cosine
|
|
343
|
+
# overlap the same ~0.60-0.86 band (one nonsense string measured HIGHER
|
|
344
|
+
# than several real on-topic queries) — every sentence embedding this
|
|
345
|
+
# model produces lands close to the corpus centroid regardless of
|
|
346
|
+
# relevance, so no absolute cosine constant can separate the two
|
|
347
|
+
# classes. (One parenthetical data point from the django benchmark
|
|
348
|
+
# corpus: the query "CORS handling implementation" — a protocol
|
|
349
|
+
# Django's own source never touches — still measured a pool-max cosine
|
|
350
|
+
# of 0.75, comfortably inside the on-topic band.) The defect was the
|
|
351
|
+
# signal, not the threshold.
|
|
352
|
+
#
|
|
353
|
+
# The replacement is distributional rather than absolute: does every
|
|
354
|
+
# content word in the query occur, even once, anywhere in the corpus's
|
|
355
|
+
# indexed vocabulary? A query naming a concept the codebase genuinely
|
|
356
|
+
# does not contain is built from at least one word that has literally
|
|
357
|
+
# zero document frequency across the whole corpus (not just the
|
|
358
|
+
# query's fetched candidate pool); a query about something the
|
|
359
|
+
# codebase does contain, however badly it is then ranked, is built
|
|
360
|
+
# entirely from words that really do appear in it. This generalizes
|
|
361
|
+
# past absolute-cosine floors to any embedder vectr ships, because it
|
|
362
|
+
# never looks at a cosine value at all — only at whether the corpus's
|
|
363
|
+
# own vocabulary contains the query's words.
|
|
364
|
+
enabled: true
|
|
365
|
+
|
|
366
|
+
# A query token shorter than this is excluded from the zero-document-
|
|
367
|
+
# frequency check — very short tokens (2-letter abbreviations, stray
|
|
368
|
+
# punctuation fragments) are too ambiguous to serve as a reliable
|
|
369
|
+
# vocabulary anchor in either direction.
|
|
370
|
+
min_content_token_length: 3
|
|
371
|
+
|
|
372
|
+
# Generic English/query-scaffolding words excluded from the zero-
|
|
373
|
+
# document-frequency check. These are near-universal across any real
|
|
374
|
+
# codebase's comments and docstrings (so they would essentially never
|
|
375
|
+
# have zero document frequency) — excluding them only avoids wasted
|
|
376
|
+
# per-query token lookups, it does not change which queries get
|
|
377
|
+
# flagged.
|
|
378
|
+
stopwords:
|
|
379
|
+
- the
|
|
380
|
+
- a
|
|
381
|
+
- an
|
|
382
|
+
- of
|
|
383
|
+
- to
|
|
384
|
+
- in
|
|
385
|
+
# Quoted: bare "on"/"off"/"yes"/"no" are YAML 1.1 boolean literals — an
|
|
386
|
+
# unquoted "on" here is parsed as the Python bool True, not the string
|
|
387
|
+
# "on", corrupting this list (agent/config.py loads with pyyaml's
|
|
388
|
+
# default YAML 1.1 resolver).
|
|
389
|
+
- "on"
|
|
390
|
+
- for
|
|
391
|
+
- and
|
|
392
|
+
- or
|
|
393
|
+
- is
|
|
394
|
+
- are
|
|
395
|
+
- how
|
|
396
|
+
- what
|
|
397
|
+
- does
|
|
398
|
+
- do
|
|
399
|
+
- implementation
|
|
400
|
+
- code
|
|
401
|
+
- framework
|
|
402
|
+
- using
|
|
403
|
+
- use
|
|
404
|
+
|
|
405
|
+
# Minimum number of query content tokens with zero corpus-wide document
|
|
406
|
+
# frequency required to flag the result set low_confidence. 1 (default)
|
|
407
|
+
# flags as soon as a single content word never appears anywhere in the
|
|
408
|
+
# indexed corpus. Set arbitrarily high (or set enabled: false) to
|
|
409
|
+
# disable — the floor never fires and low_confidence is always false,
|
|
410
|
+
# i.e. an exact no-op restoring pre-UPG-NOTFOUND-FLOOR behaviour.
|
|
411
|
+
min_zero_df_tokens: 1
|
|
412
|
+
|
|
413
|
+
# UPG-SCORE-DISPLAY-FLAT: a second, independent low-confidence sub-signal —
|
|
414
|
+
# the top result's own displayed relevance is below this absolute floor.
|
|
415
|
+
# Gated on the cross-encoder relevance score specifically (ce_relevance),
|
|
416
|
+
# never on the raw dense-cosine fallback: the UPG-NOTFOUND-FLOOR-2
|
|
417
|
+
# measurement above already showed a bi-encoder cosine cannot separate
|
|
418
|
+
# absent-topic from on-topic queries, so flooring on it here would
|
|
419
|
+
# reintroduce that same defect. A cross-encoder score is a different,
|
|
420
|
+
# calibrated relevance judgment (trained to predict query-doc relevance
|
|
421
|
+
# directly), so it is safe to floor on. A no-op (this sub-signal never
|
|
422
|
+
# fires) whenever reranking didn't run (rerank=False, or the reranker
|
|
423
|
+
# model failed to load) — low_confidence then falls back to the
|
|
424
|
+
# zero-document-frequency check above alone.
|
|
425
|
+
min_top_relevance: 0.30
|
|
426
|
+
|
|
427
|
+
# Text prepended to the MCP vectr_search response when the floor fires.
|
|
428
|
+
# Results are still shown in full below it — the caller LLM may still
|
|
429
|
+
# salvage a lead; this only adds a signal it currently has no way to see.
|
|
430
|
+
banner: "No strong match for this query — the results below scored low on absolute relevance and may be unrelated. Try vectr_locate with the exact symbol name, rephrase the query, or fall back to grep/reading the file directly."
|
|
431
|
+
|
|
432
|
+
# UPG-CLI-SEARCH-FLOOR: separate CLI-surface banner, printed by `vectr
|
|
433
|
+
# search` when SearchResponse.low_confidence is true. The MCP banner
|
|
434
|
+
# above names `vectr_locate` — meaningless at a shell prompt, since no
|
|
435
|
+
# `vectr locate` subcommand exists. Same signal, phrasing for a human
|
|
436
|
+
# terminal reader instead of the editor's LLM.
|
|
437
|
+
banner_cli: "No strong match for this query — the results below scored low on absolute relevance and may be unrelated. Try an exact symbol name, rephrase the query, or fall back to grep/reading the file directly."
|
|
438
|
+
|
|
439
|
+
strategy:
|
|
440
|
+
# Fallback hybrid-search weights used before the first index-time codebase
|
|
441
|
+
# fingerprint has run (agent.strategy_selector.select_strategy). Once a
|
|
442
|
+
# workspace is indexed these are superseded by the fingerprint-derived
|
|
443
|
+
# RetrievalStrategy; until then `status` and `search` use this pair so
|
|
444
|
+
# retrieval behaviour — and its reporting — is deterministic from the very
|
|
445
|
+
# first call rather than silently absent (UPG-8.2). Must sum to 1.0.
|
|
446
|
+
default_semantic_weight: 0.70
|
|
447
|
+
default_bm25_weight: 0.30
|
|
448
|
+
retrieval:
|
|
449
|
+
dual_vector:
|
|
450
|
+
# ARCH-4: per-symbol dual-vector pool entry. STEP-0 spike proved a mechanical
|
|
451
|
+
# implementation body dilutes the intent-bearing signature/docstring tokens
|
|
452
|
+
# when mean-pooled into a single embedding — a documented method can miss
|
|
453
|
+
# dense pool entry entirely even though its own docstring paraphrases the
|
|
454
|
+
# query. Fix: embed a second, body-stripped "purpose" text (qualified
|
|
455
|
+
# signature + docstring/leading comment) per symbol-bearing chunk and query
|
|
456
|
+
# both vector spaces; the two are merged uniformly for every query, never
|
|
457
|
+
# gated on query content. Non-symbol chunks (docs/markdown/config) are
|
|
458
|
+
# unaffected — no purpose vector is stored for them.
|
|
459
|
+
enabled: true
|
|
460
|
+
|
|
461
|
+
# How a chunk's two similarity scores (body, purpose) combine into the one
|
|
462
|
+
# dense score consumed by pool entry and the hybrid merge:
|
|
463
|
+
# "max" — dense_score = max(body_sim, purpose_sim). A chunk enters the
|
|
464
|
+
# pool if EITHER vector matches; never scores worse than a
|
|
465
|
+
# body-only search would. This is the evidence-gated choice:
|
|
466
|
+
# the spike showed purpose_sim clears pool-entry threshold
|
|
467
|
+
# while body_sim does not (0.601 vs 0.706 for one phrasing),
|
|
468
|
+
# so averaging the two would still leave the chunk short —
|
|
469
|
+
# only a non-averaging max recovers pool entry.
|
|
470
|
+
# "weighted" — dense_score = (1 - blend_weight) * body_sim + blend_weight *
|
|
471
|
+
# purpose_sim. Kept as an evaluated alternative for future
|
|
472
|
+
# tuning; not the default because averaging re-introduces the
|
|
473
|
+
# dilution the mechanism exists to defeat.
|
|
474
|
+
blend_mode: "max"
|
|
475
|
+
|
|
476
|
+
# Purpose-vector weight when blend_mode is "weighted" (ignored under "max").
|
|
477
|
+
blend_weight: 0.5
|
|
478
|
+
|
|
479
|
+
# Maximum lines captured as a chunk's "signature" when distilling the
|
|
480
|
+
# purpose text — the declaration line(s) up to (and including) the line that
|
|
481
|
+
# opens the body (python ':' / brace-block '{'). Bounds pathologically long
|
|
482
|
+
# multi-line parameter lists.
|
|
483
|
+
max_signature_lines: 8
|
|
484
|
+
|
|
485
|
+
# Maximum lines captured from a Python docstring (or a non-Python leading
|
|
486
|
+
# doc-comment block) when building the purpose text.
|
|
487
|
+
max_docstring_lines: 12
|
|
488
|
+
|
|
489
|
+
# Maximum characters kept from the captured docstring/leading-comment text —
|
|
490
|
+
# a hard cap so a very long module-style docstring doesn't itself dilute the
|
|
491
|
+
# purpose embedding the same way a long body would.
|
|
492
|
+
max_docstring_chars: 600
|
|
493
|
+
|
|
494
|
+
search:
|
|
495
|
+
identifier_hint:
|
|
496
|
+
# UPG-QUERYTYPE-REROUTE: additive, high-precision symbol-graph hint
|
|
497
|
+
# appended below vectr_search's L3 results. Replaces the deleted
|
|
498
|
+
# agent/query_router.py regex query-classification layer, which
|
|
499
|
+
# misrouted innocent NL questions containing bare nouns like
|
|
500
|
+
# "dependency"/"override"/"subclass" into a CALL_GRAPH intent — silently
|
|
501
|
+
# overriding the fingerprint-derived semantic weight and guessing a
|
|
502
|
+
# same-named homonym via the query's first non-stopword word, with no
|
|
503
|
+
# ranking tie to the query at all. This mechanism does no intent
|
|
504
|
+
# classification: it tokenizes the RAW query for identifier-SHAPED
|
|
505
|
+
# tokens (CamelCase, snake_case, dotted Class.method — a structural
|
|
506
|
+
# transform, never a keyword/phrase match) and appends a section only
|
|
507
|
+
# when at least one token resolves to an EXACT symbol-graph hit (no
|
|
508
|
+
# fuzzy/prefix/substring). A query with no identifier-shaped token, or
|
|
509
|
+
# one whose plain words merely coincide with a symbol name, gets no
|
|
510
|
+
# section and no weight override.
|
|
511
|
+
enabled: true
|
|
512
|
+
|
|
513
|
+
# Maximum number of distinct identifier-shaped tokens (query order,
|
|
514
|
+
# deduplicated) attempted against the symbol graph per search.
|
|
515
|
+
max_identifiers: 2
|
|
516
|
+
|
|
517
|
+
# Maximum resolved symbol locations shown per identifier.
|
|
518
|
+
max_locations: 3
|
|
519
|
+
|
|
520
|
+
# UPG-NEARMISS-SYMBOL-NAMES: when an identifier-shaped token fails EXACT
|
|
521
|
+
# resolution, additively surface the nearest existing symbol NAMES so the
|
|
522
|
+
# caller LLM learns it misremembered a name rather than seeing nothing.
|
|
523
|
+
# Sourced entirely from the symbol graph's own deterministic partial-match
|
|
524
|
+
# machinery (locate_l2's non-exact strategies, plus one bounded prefix-
|
|
525
|
+
# containment check — see SymbolGraph.nearest_symbol_names) — never a
|
|
526
|
+
# semantic guess, and always labeled inexact in the rendered section.
|
|
527
|
+
nearmiss_enabled: true
|
|
528
|
+
|
|
529
|
+
# Maximum distinct near-miss symbol names shown, TOTAL across the whole
|
|
530
|
+
# response (not per token) — keeps the addition small even when more
|
|
531
|
+
# than one identifier-shaped token in the query fails to resolve exactly.
|
|
532
|
+
nearmiss_max: 3
|
|
533
|
+
|
|
534
|
+
# Minimum length (characters) an existing symbol's name must have to be
|
|
535
|
+
# offered as a prefix-containment near-miss candidate (the token "starts
|
|
536
|
+
# with" that shorter, real symbol name). Prevents a short, generic symbol
|
|
537
|
+
# name (e.g. a 2-3 char helper) from spuriously "matching" as a prefix of
|
|
538
|
+
# many unrelated tokens.
|
|
539
|
+
nearmiss_min_prefix_len: 6
|
|
540
|
+
|
|
541
|
+
indexing:
|
|
542
|
+
# hard cap — prevents single huge chunks diluting embeddings
|
|
543
|
+
max_chunk_lines: 150
|
|
544
|
+
|
|
545
|
+
# lines kept for class-level chunk (sig + docstring + attrs)
|
|
546
|
+
class_header_lines: 40
|
|
547
|
+
|
|
548
|
+
# Build-artifact directories excluded from indexing at file-walk time (UPG-15.9).
|
|
549
|
+
# Any path component that ENDS WITH one of these suffixes is treated as a build
|
|
550
|
+
# artifact directory and every file inside it is excluded. This catches Python
|
|
551
|
+
# egg-info directories (e.g. Django.egg-info/, mypackage.egg-info/) whose
|
|
552
|
+
# SOURCES.txt / PKG-INFO / *.txt files are plain file-path listings with no
|
|
553
|
+
# educational content but high BM25 IDF on module/command identifiers.
|
|
554
|
+
# Rule: suffix match on each path part — "Django.egg-info" ends with ".egg-info".
|
|
555
|
+
# Do NOT widen to cover real documentation dirs (docs/, howto/) — only build
|
|
556
|
+
# artifacts whose entire directory is machine-generated have no index value.
|
|
557
|
+
build_artifact_dir_suffixes:
|
|
558
|
+
- ".egg-info"
|
|
559
|
+
- ".dist-info"
|
|
560
|
+
|
|
561
|
+
# UPG-JSFLOW-SYMBOLS: Flow-typed `.js` detection. tree-sitter-javascript
|
|
562
|
+
# treats Flow type syntax (`@flow` pragma, `import type {...}`, `: Type`
|
|
563
|
+
# annotations, generics) as ERROR nodes and desyncs the symbol walk —
|
|
564
|
+
# canonical functions go missing and keyword tokens get misattributed as
|
|
565
|
+
# symbol names. Files that signal Flow are parsed with the typescript/tsx
|
|
566
|
+
# grammar instead (which understands type annotations); plain `.js` is
|
|
567
|
+
# unaffected. Detection is a cheap header scan (first `scan_head_bytes`
|
|
568
|
+
# bytes), done once per file parse — never per AST node.
|
|
569
|
+
flow_detection:
|
|
570
|
+
# Bytes scanned from the start of the file when looking for a Flow signal.
|
|
571
|
+
scan_head_bytes: 2000
|
|
572
|
+
# Primary signal: the `@flow` pragma, conventionally in the file's leading comment.
|
|
573
|
+
pragma: "@flow"
|
|
574
|
+
# Secondary signal: Flow-only import syntax, checked within the same head window.
|
|
575
|
+
secondary_markers:
|
|
576
|
+
- "import type "
|
|
577
|
+
- "export type "
|
|
578
|
+
|
|
579
|
+
output:
|
|
580
|
+
# Number of lines returned as a snippet with each symbol location.
|
|
581
|
+
# Enough for the AI to understand signature + first few lines of the body.
|
|
582
|
+
snippet_lines: 12
|
|
583
|
+
|
|
584
|
+
behavior:
|
|
585
|
+
remember_nudge:
|
|
586
|
+
# After this many vectr tool calls without a vectr_remember, the next
|
|
587
|
+
# vectr_search / vectr_locate / vectr_trace response appends an imperative
|
|
588
|
+
# reminder. The counter resets on every vectr_remember call.
|
|
589
|
+
threshold: 10
|
|
590
|
+
|
|
591
|
+
# After the threshold fires, re-fires every this many calls so a single
|
|
592
|
+
# dismissal cannot silence it for the rest of the session.
|
|
593
|
+
cooldown: 5
|
|
594
|
+
|
|
595
|
+
eviction:
|
|
596
|
+
# Minimum accumulated retrieved-token estimate (since the last auto-eviction
|
|
597
|
+
# hint or session start) required before auto_eviction_hint() will emit the
|
|
598
|
+
# ACTION REQUIRED block. Gates on real context pressure rather than raw
|
|
599
|
+
# call count — a burst of tiny searches (7-15 line methods, ~30-60 tokens
|
|
600
|
+
# each) does not trigger the hint until meaningful content has been retrieved.
|
|
601
|
+
# Token estimate: len(content) // 4. At ~100 chars/line, 4000 tokens ≈ 10
|
|
602
|
+
# small methods or 2-3 medium functions. The explicit vectr_evict_hint tool
|
|
603
|
+
# and /v1/evict endpoint remain ungated.
|
|
604
|
+
retrieved_token_gate: 4000
|
|
605
|
+
|
|
606
|
+
# UPG-EVICT-SESSION-SCOPE: maximum number of chunk ids listed as re-fetch
|
|
607
|
+
# keys (`vectr_fetch(ids=[...])`) in the eviction_hint() render. Bounds the
|
|
608
|
+
# hint's own token cost — a session with hundreds of retrieved chunks still
|
|
609
|
+
# gets a short, actionable list rather than every id it has ever seen.
|
|
610
|
+
hint_max_ids: 5
|
|
611
|
+
|
|
612
|
+
# UPG-EVICT-SESSION-SCOPE: each MCP session gets its own EvictionAdvisor so
|
|
613
|
+
# one session never sees chunks retrieved by another. Bounds the daemon-
|
|
614
|
+
# wide registry of per-session advisors — oldest session is dropped (LRU)
|
|
615
|
+
# once this many concurrent sessions have been tracked, so a long-running
|
|
616
|
+
# daemon serving many short-lived sessions can't grow this without bound.
|
|
617
|
+
max_tracked_sessions: 50
|
|
618
|
+
|
|
619
|
+
# UPG-REMEMBER-BANNER-FATIGUE: auto_eviction_hint()'s escalated
|
|
620
|
+
# "ACTION REQUIRED: call vectr_remember NOW" directive only fires once
|
|
621
|
+
# this many NEW chunks have been retrieved since the caller's last
|
|
622
|
+
# vectr_remember call (or since session start, if it has never called
|
|
623
|
+
# vectr_remember). Right after a vectr_remember, repeating the same
|
|
624
|
+
# urgent directive on the very next retrieval trains the caller to
|
|
625
|
+
# ignore it — the counter gives it a chance to actually comply before
|
|
626
|
+
# escalating again. Below this count, MCP dispatch's existing
|
|
627
|
+
# turn-count soft nudge (behavior.remember_nudge, or nothing) takes
|
|
628
|
+
# over instead; see _should_nudge_remember/_remember_nudge_text.
|
|
629
|
+
# Set in the same order of magnitude as rearm_retrieval_calls (4) above.
|
|
630
|
+
remember_escalation_chunks: 3
|
|
631
|
+
|
|
632
|
+
# UPG-EVICT-ESCALATION-GATE-TOO-LOW: companion gate to remember_escalation_chunks,
|
|
633
|
+
# required in ADDITION to it (both must hold). remember_escalation_chunks alone is
|
|
634
|
+
# smaller than a single search's default n_results (5), so on large-chunk corpora
|
|
635
|
+
# one vectr_search call can add >4000 tokens in a single burst — tripping both the
|
|
636
|
+
# chunk-count gate AND the existing retrieved_token_gate at once, right after the
|
|
637
|
+
# caller just complied with vectr_remember. Gating on accumulated TOKENS since the
|
|
638
|
+
# last vectr_remember (not just since the last hint) means a single typical search
|
|
639
|
+
# (~4000 tokens on a large-chunk corpus, per retrieved_token_gate's own comment)
|
|
640
|
+
# cannot cross this threshold alone — it takes roughly two such searches, giving the
|
|
641
|
+
# caller a real chance to act on vectr_remember before repeat pressure builds back up.
|
|
642
|
+
remember_escalation_tokens: 8000
|
|
643
|
+
|
|
644
|
+
boot:
|
|
645
|
+
# SessionStart boot recall (UPG-9.2): unconditional directive notes are
|
|
646
|
+
# capped defensively so a workspace with unusually many standing rules
|
|
647
|
+
# doesn't inject an unbounded block every session. Directives are
|
|
648
|
+
# ordered oldest-first (standing rules stay in a stable order).
|
|
649
|
+
max_directive_notes: 100
|
|
650
|
+
|
|
651
|
+
# UPG-TASK-NOTE-INJECTION-RECENCY: kind=task notes are current-work
|
|
652
|
+
# state, not relevance-ranked learnings — they are ordered strictly
|
|
653
|
+
# newest-first (ignoring author_trust_score/decay_score) and capped to
|
|
654
|
+
# this many so the boot set surfaces only the freshest checkpoints, not
|
|
655
|
+
# the full task history.
|
|
656
|
+
max_task_notes: 5
|
|
657
|
+
|
|
658
|
+
ingest_traces:
|
|
659
|
+
# Maximum number of "caller/callee not found in the indexed symbol graph"
|
|
660
|
+
# example strings surfaced in the vectr_ingest_traces response text (UPG-7.3).
|
|
661
|
+
# The edge is still ingested — an unresolved name is common and expected
|
|
662
|
+
# (external library, dynamic dispatch target added at runtime, or a symbol
|
|
663
|
+
# kind the static extractor doesn't capture) — this only bounds how many
|
|
664
|
+
# examples are echoed back so a large trace batch doesn't flood the response.
|
|
665
|
+
max_unresolved_examples: 10
|
|
666
|
+
|
|
667
|
+
# UPG-TRACE-GRAPH-INCOMPLETE (F40-class, reproduced on vectr_trace): the MCP
|
|
668
|
+
# schema's required parameter is "name", but every symbol-name-bearing tool
|
|
669
|
+
# description has read like a positional example, training callers to guess
|
|
670
|
+
# a different key. Rather than rely on descriptions alone, the dispatch
|
|
671
|
+
# layer accepts these as drop-in aliases for "name" on vectr_locate and
|
|
672
|
+
# vectr_trace — a call using any of them succeeds instead of erroring.
|
|
673
|
+
symbol_name_param_aliases:
|
|
674
|
+
- symbol
|
|
675
|
+
- symbol_name
|
|
676
|
+
|
|
677
|
+
symbol_graph:
|
|
678
|
+
# UPG-JSFLOW-SYMBOLS: language keywords that must never be minted as a
|
|
679
|
+
# symbol name or call-edge target. A desynced parse (e.g. Flow syntax
|
|
680
|
+
# hitting the plain javascript grammar, or any other ERROR-node recovery)
|
|
681
|
+
# can misattribute a keyword token as an identifier — these sets are the
|
|
682
|
+
# global reject-list, checked alongside the per-node ERROR-ancestor guard.
|
|
683
|
+
# Grouped per language (most C-descended languages share a keyword core,
|
|
684
|
+
# but each set is kept explicit rather than merged so a language's grammar
|
|
685
|
+
# can evolve independently).
|
|
686
|
+
reserved_keywords:
|
|
687
|
+
python:
|
|
688
|
+
- if
|
|
689
|
+
- elif
|
|
690
|
+
- else
|
|
691
|
+
- for
|
|
692
|
+
- while
|
|
693
|
+
- return
|
|
694
|
+
- def
|
|
695
|
+
- class
|
|
696
|
+
- import
|
|
697
|
+
- from
|
|
698
|
+
- try
|
|
699
|
+
- except
|
|
700
|
+
- finally
|
|
701
|
+
- with
|
|
702
|
+
- as
|
|
703
|
+
- pass
|
|
704
|
+
- break
|
|
705
|
+
- continue
|
|
706
|
+
- lambda
|
|
707
|
+
- yield
|
|
708
|
+
- global
|
|
709
|
+
- nonlocal
|
|
710
|
+
- assert
|
|
711
|
+
- raise
|
|
712
|
+
- del
|
|
713
|
+
- in
|
|
714
|
+
- is
|
|
715
|
+
- not
|
|
716
|
+
- and
|
|
717
|
+
- or
|
|
718
|
+
- async
|
|
719
|
+
- await
|
|
720
|
+
- None
|
|
721
|
+
- True
|
|
722
|
+
- False
|
|
723
|
+
# Not a real keyword, but a pre-existing noise guard: `print(...)` call
|
|
724
|
+
# sites were already suppressed as call-edge targets before this list
|
|
725
|
+
# existed — kept here so the exclusion stays config-driven.
|
|
726
|
+
- print
|
|
727
|
+
javascript:
|
|
728
|
+
- if
|
|
729
|
+
- else
|
|
730
|
+
- for
|
|
731
|
+
- while
|
|
732
|
+
- do
|
|
733
|
+
- switch
|
|
734
|
+
- case
|
|
735
|
+
- default
|
|
736
|
+
- break
|
|
737
|
+
- continue
|
|
738
|
+
- return
|
|
739
|
+
- function
|
|
740
|
+
- class
|
|
741
|
+
- const
|
|
742
|
+
- let
|
|
743
|
+
- var
|
|
744
|
+
- new
|
|
745
|
+
- typeof
|
|
746
|
+
- instanceof
|
|
747
|
+
- in
|
|
748
|
+
- of
|
|
749
|
+
- void
|
|
750
|
+
- delete
|
|
751
|
+
- yield
|
|
752
|
+
- async
|
|
753
|
+
- await
|
|
754
|
+
- export
|
|
755
|
+
- import
|
|
756
|
+
- extends
|
|
757
|
+
- super
|
|
758
|
+
- this
|
|
759
|
+
- static
|
|
760
|
+
- get
|
|
761
|
+
- set
|
|
762
|
+
- try
|
|
763
|
+
- catch
|
|
764
|
+
- finally
|
|
765
|
+
- throw
|
|
766
|
+
typescript:
|
|
767
|
+
- if
|
|
768
|
+
- else
|
|
769
|
+
- for
|
|
770
|
+
- while
|
|
771
|
+
- do
|
|
772
|
+
- switch
|
|
773
|
+
- case
|
|
774
|
+
- default
|
|
775
|
+
- break
|
|
776
|
+
- continue
|
|
777
|
+
- return
|
|
778
|
+
- function
|
|
779
|
+
- class
|
|
780
|
+
- const
|
|
781
|
+
- let
|
|
782
|
+
- var
|
|
783
|
+
- new
|
|
784
|
+
- typeof
|
|
785
|
+
- instanceof
|
|
786
|
+
- in
|
|
787
|
+
- of
|
|
788
|
+
- void
|
|
789
|
+
- delete
|
|
790
|
+
- yield
|
|
791
|
+
- async
|
|
792
|
+
- await
|
|
793
|
+
- export
|
|
794
|
+
- import
|
|
795
|
+
- extends
|
|
796
|
+
- super
|
|
797
|
+
- this
|
|
798
|
+
- static
|
|
799
|
+
- get
|
|
800
|
+
- set
|
|
801
|
+
- try
|
|
802
|
+
- catch
|
|
803
|
+
- finally
|
|
804
|
+
- throw
|
|
805
|
+
- interface
|
|
806
|
+
- type
|
|
807
|
+
- enum
|
|
808
|
+
- implements
|
|
809
|
+
- namespace
|
|
810
|
+
- declare
|
|
811
|
+
- as
|
|
812
|
+
go:
|
|
813
|
+
- if
|
|
814
|
+
- else
|
|
815
|
+
- for
|
|
816
|
+
- switch
|
|
817
|
+
- case
|
|
818
|
+
- default
|
|
819
|
+
- break
|
|
820
|
+
- continue
|
|
821
|
+
- return
|
|
822
|
+
- func
|
|
823
|
+
- package
|
|
824
|
+
- import
|
|
825
|
+
- defer
|
|
826
|
+
- go
|
|
827
|
+
- select
|
|
828
|
+
- chan
|
|
829
|
+
- range
|
|
830
|
+
- var
|
|
831
|
+
- const
|
|
832
|
+
- type
|
|
833
|
+
- struct
|
|
834
|
+
- interface
|
|
835
|
+
- map
|
|
836
|
+
- goto
|
|
837
|
+
- fallthrough
|
|
838
|
+
rust:
|
|
839
|
+
- if
|
|
840
|
+
- else
|
|
841
|
+
- for
|
|
842
|
+
- while
|
|
843
|
+
- loop
|
|
844
|
+
- match
|
|
845
|
+
- break
|
|
846
|
+
- continue
|
|
847
|
+
- return
|
|
848
|
+
- fn
|
|
849
|
+
- let
|
|
850
|
+
- mut
|
|
851
|
+
- struct
|
|
852
|
+
- enum
|
|
853
|
+
- impl
|
|
854
|
+
- trait
|
|
855
|
+
- use
|
|
856
|
+
- mod
|
|
857
|
+
- pub
|
|
858
|
+
- self
|
|
859
|
+
- Self
|
|
860
|
+
- in
|
|
861
|
+
- unsafe
|
|
862
|
+
- async
|
|
863
|
+
- await
|
|
864
|
+
- move
|
|
865
|
+
- ref
|
|
866
|
+
- where
|
|
867
|
+
- dyn
|
|
868
|
+
- static
|
|
869
|
+
- const
|
|
870
|
+
- type
|
|
871
|
+
java:
|
|
872
|
+
- if
|
|
873
|
+
- else
|
|
874
|
+
- for
|
|
875
|
+
- while
|
|
876
|
+
- do
|
|
877
|
+
- switch
|
|
878
|
+
- case
|
|
879
|
+
- default
|
|
880
|
+
- break
|
|
881
|
+
- continue
|
|
882
|
+
- return
|
|
883
|
+
- class
|
|
884
|
+
- interface
|
|
885
|
+
- extends
|
|
886
|
+
- implements
|
|
887
|
+
- public
|
|
888
|
+
- private
|
|
889
|
+
- protected
|
|
890
|
+
- static
|
|
891
|
+
- void
|
|
892
|
+
- this
|
|
893
|
+
- super
|
|
894
|
+
- new
|
|
895
|
+
- try
|
|
896
|
+
- catch
|
|
897
|
+
- finally
|
|
898
|
+
- throw
|
|
899
|
+
- throws
|
|
900
|
+
- import
|
|
901
|
+
- package
|
|
902
|
+
- enum
|
|
903
|
+
zig:
|
|
904
|
+
- if
|
|
905
|
+
- else
|
|
906
|
+
- for
|
|
907
|
+
- while
|
|
908
|
+
- switch
|
|
909
|
+
- break
|
|
910
|
+
- continue
|
|
911
|
+
- return
|
|
912
|
+
- fn
|
|
913
|
+
- const
|
|
914
|
+
- var
|
|
915
|
+
- pub
|
|
916
|
+
- struct
|
|
917
|
+
- enum
|
|
918
|
+
- union
|
|
919
|
+
- defer
|
|
920
|
+
- errdefer
|
|
921
|
+
- try
|
|
922
|
+
- catch
|
|
923
|
+
- comptime
|
|
924
|
+
- async
|
|
925
|
+
- await
|
|
926
|
+
- orelse
|
|
927
|
+
c:
|
|
928
|
+
- if
|
|
929
|
+
- else
|
|
930
|
+
- for
|
|
931
|
+
- while
|
|
932
|
+
- do
|
|
933
|
+
- switch
|
|
934
|
+
- case
|
|
935
|
+
- default
|
|
936
|
+
- break
|
|
937
|
+
- continue
|
|
938
|
+
- return
|
|
939
|
+
- goto
|
|
940
|
+
- sizeof
|
|
941
|
+
- typedef
|
|
942
|
+
- struct
|
|
943
|
+
- union
|
|
944
|
+
- enum
|
|
945
|
+
- static
|
|
946
|
+
- const
|
|
947
|
+
- void
|
|
948
|
+
- extern
|
|
949
|
+
- volatile
|
|
950
|
+
cpp:
|
|
951
|
+
- if
|
|
952
|
+
- else
|
|
953
|
+
- for
|
|
954
|
+
- while
|
|
955
|
+
- do
|
|
956
|
+
- switch
|
|
957
|
+
- case
|
|
958
|
+
- default
|
|
959
|
+
- break
|
|
960
|
+
- continue
|
|
961
|
+
- return
|
|
962
|
+
- goto
|
|
963
|
+
- sizeof
|
|
964
|
+
- typedef
|
|
965
|
+
- struct
|
|
966
|
+
- union
|
|
967
|
+
- enum
|
|
968
|
+
- class
|
|
969
|
+
- namespace
|
|
970
|
+
- template
|
|
971
|
+
- static
|
|
972
|
+
- const
|
|
973
|
+
- void
|
|
974
|
+
- new
|
|
975
|
+
- delete
|
|
976
|
+
- try
|
|
977
|
+
- catch
|
|
978
|
+
- throw
|
|
979
|
+
- public
|
|
980
|
+
- private
|
|
981
|
+
- protected
|
|
982
|
+
- virtual
|
|
983
|
+
- using
|
|
984
|
+
|
|
985
|
+
# UPG-REACT-TSX-FUNCTION-DECL-DROP: recovery for a grammar desync that
|
|
986
|
+
# swallows an unrelated region of siblings into one opaque, mis-typed node
|
|
987
|
+
# (e.g. a single unparseable construct hundreds of lines earlier can wreck
|
|
988
|
+
# the parser's recovery for the rest of the file). Language-agnostic — any
|
|
989
|
+
# tree-sitter grammar's error-recovery path can produce this shape, not
|
|
990
|
+
# just Flow/tsx. When the walker hits a node that is not itself a
|
|
991
|
+
# recognized symbol/call construct but has_error is set and its own span
|
|
992
|
+
# is large, it is worth an isolated reparse of just that byte range: the
|
|
993
|
+
# parser often resyncs cleanly once it starts fresh without the earlier
|
|
994
|
+
# desync's carried-over state.
|
|
995
|
+
error_recovery:
|
|
996
|
+
# Minimum line-span (end_line - start_line) an opaque errored node must
|
|
997
|
+
# cover before an isolated reparse is attempted. A short span IS the
|
|
998
|
+
# error (no swallowed siblings to recover) — reparsing it wastes a parse
|
|
999
|
+
# pass for nothing.
|
|
1000
|
+
min_span_lines: 8
|
|
1001
|
+
# Reparse attempts budget per file. Bounds worst-case parse cost when a
|
|
1002
|
+
# file has many/deeply-nested desynced regions.
|
|
1003
|
+
max_reparse_attempts_per_file: 200
|
|
1004
|
+
# Per-attempt cap on how many original siblings a single recovery reparse
|
|
1005
|
+
# may absorb while growing past an arbitrary mid-declaration cut (see
|
|
1006
|
+
# error_recovery above). Without its own cap, one badly-cut region can
|
|
1007
|
+
# burn the entire per-file budget growing sibling-by-sibling and starve
|
|
1008
|
+
# every other desynced region in the same file.
|
|
1009
|
+
max_extend_steps_per_attempt: 20
|
|
1010
|
+
|
|
1011
|
+
cli:
|
|
1012
|
+
# UPG-CLI-START-READY-RACE: `vectr start`/`restart` spawn the daemon as a
|
|
1013
|
+
# detached background process and used to print a success block
|
|
1014
|
+
# immediately after Popen() returned — before the daemon had bound its
|
|
1015
|
+
# port or finished loading the embedder in its FastAPI lifespan. A
|
|
1016
|
+
# `vectr status` run right after start's "success" message could still see
|
|
1017
|
+
# a connection refused, reading as "start lied." `_do_start` now polls
|
|
1018
|
+
# /v1/status until the daemon actually answers (or this timeout elapses)
|
|
1019
|
+
# before printing anything, so the message reflects reality.
|
|
1020
|
+
start_ready_poll_timeout_s: 20.0
|
|
1021
|
+
# How often to retry the readiness probe while waiting (above).
|
|
1022
|
+
start_ready_poll_interval_s: 0.3
|
|
1023
|
+
# Per-attempt HTTP timeout for a single readiness probe during the poll
|
|
1024
|
+
# loop above — short, since a probe that hangs this long just means "not
|
|
1025
|
+
# ready yet," and we want to retry rather than block on one slow attempt.
|
|
1026
|
+
start_ready_probe_timeout_s: 1.0
|
|
1027
|
+
# UPG-CLI-DAEMON-VERSION-SKEW: HTTP timeout for the standalone /v1/status
|
|
1028
|
+
# probe a daemon-talking subcommand issues to compare its local version
|
|
1029
|
+
# stamp against the running daemon's. Short and best-effort — a slow/failed
|
|
1030
|
+
# probe just means the check is skipped this invocation, never a blocked
|
|
1031
|
+
# command.
|
|
1032
|
+
version_skew_probe_timeout_s: 1.0
|
|
1033
|
+
|
|
1034
|
+
workspace:
|
|
1035
|
+
# Directory names written into a FRESH .vectrignore on first `vectr start` /
|
|
1036
|
+
# `vectr init` when the workspace has none yet (UPG-13.2). An existing
|
|
1037
|
+
# .vectrignore is never overwritten. These mirror the built-in indexing
|
|
1038
|
+
# excludes (agent.indexer.EXCLUDED_DIRS) plus common ecosystem cache/build
|
|
1039
|
+
# dirs, so a new user sees sensible excludes without hand-authoring them.
|
|
1040
|
+
default_vectrignore_dirs:
|
|
1041
|
+
- node_modules
|
|
1042
|
+
- .venv
|
|
1043
|
+
- venv
|
|
1044
|
+
- env
|
|
1045
|
+
- __pycache__
|
|
1046
|
+
- .git
|
|
1047
|
+
- dist
|
|
1048
|
+
- build
|
|
1049
|
+
- target
|
|
1050
|
+
- .mypy_cache
|
|
1051
|
+
- .pytest_cache
|
|
1052
|
+
- .ruff_cache
|
|
1053
|
+
- htmlcov
|
|
1054
|
+
- coverage
|
|
1055
|
+
- .tox
|
|
1056
|
+
- .cache
|
|
1057
|
+
- tmp
|
|
1058
|
+
- vendor
|
|
1059
|
+
- .next
|
|
1060
|
+
- .nuxt
|
|
1061
|
+
- out
|
|
1062
|
+
|
|
1063
|
+
watcher:
|
|
1064
|
+
# How often (seconds) CodeWatcher shallow-scans each workspace root's
|
|
1065
|
+
# TOP-LEVEL entries only (UPG-13.1/13.3). The watcher never schedules a
|
|
1066
|
+
# native OS watch on the workspace root itself — on macOS, FSEvents
|
|
1067
|
+
# delivers every event under a watched path's *entire* subtree to the
|
|
1068
|
+
# Python emitter regardless of the `recursive` flag passed to watchdog, so
|
|
1069
|
+
# watching the root non-recursively gives zero protection against a large
|
|
1070
|
+
# excluded sibling directory (confirmed empirically: churn inside an
|
|
1071
|
+
# unwatched excluded dir produces zero native events; churn inside the
|
|
1072
|
+
# same dir under a "non-recursive" root watch delivers 100% of events).
|
|
1073
|
+
# Only per-included-top-level-directory watches actually stop the flood.
|
|
1074
|
+
# This interval is how quickly a brand-new top-level directory, or an edit
|
|
1075
|
+
# to a top-level loose file, is picked up instead — the shallow scan stats
|
|
1076
|
+
# only the root's direct children, never the whole tree, so it stays cheap
|
|
1077
|
+
# regardless of repo size.
|
|
1078
|
+
top_level_rescan_interval_s: 5.0
|
|
1079
|
+
|
|
1080
|
+
# UPG-WATCHER-PRESSURE-GOVERNOR: burst coalescing. A sustained multi-file
|
|
1081
|
+
# edit stream (AI coding agents editing many files in quick succession) hits
|
|
1082
|
+
# the per-file debounce independently for every path, so the embed pipeline
|
|
1083
|
+
# never goes idle — no global ceiling on concurrent re-embed work. When more
|
|
1084
|
+
# than this many distinct paths are pending debounce SIMULTANEOUSLY, every
|
|
1085
|
+
# per-file timer is cancelled and every pending path collapses into one
|
|
1086
|
+
# deferred batch re-index instead — an edit storm then costs one batch pass
|
|
1087
|
+
# over N files, not N independent re-embeds.
|
|
1088
|
+
burst_files_threshold: 8
|
|
1089
|
+
# Seconds of repo-wide silence (no new watched-file event) required, once
|
|
1090
|
+
# burst coalescing has kicked in, before the collapsed batch actually runs.
|
|
1091
|
+
# Keeps the batch from firing mid-storm and having to run again seconds
|
|
1092
|
+
# later for the next wave of edits from the same agent turn.
|
|
1093
|
+
burst_quiet_seconds: 15.0
|
|
1094
|
+
# Optional self-limit (MB) on this process's own resident memory before a
|
|
1095
|
+
# watcher-triggered batch re-index is allowed to run; 0 disables the check
|
|
1096
|
+
# (default — the watcher never inspects memory unless a laptop operator
|
|
1097
|
+
# opts in). When set and exceeded, the batch is deferred to the next quiet
|
|
1098
|
+
# window and ONE warning line is logged instead of running — the collected
|
|
1099
|
+
# paths are never dropped, just retried later. Reads this process's peak
|
|
1100
|
+
# resident set size (stdlib `resource.getrusage`, no extra dependency);
|
|
1101
|
+
# peak RSS is monotonically non-decreasing for the life of the process, so
|
|
1102
|
+
# once tripped this acts as a standing "this process has run hot before,
|
|
1103
|
+
# stop feeding it more embed work" brake rather than an instantaneous
|
|
1104
|
+
# reading — deliberately conservative for a resource-safety guard.
|
|
1105
|
+
max_rss_mb: 0
|
|
1106
|
+
|
|
1107
|
+
hooks:
|
|
1108
|
+
# UPG-HOOK-INJECT-OBSERVABILITY: when true, every hook-driven recall that
|
|
1109
|
+
# actually injects notes (SessionStart/UserPromptSubmit/PreToolUse) appends
|
|
1110
|
+
# one line to ~/.vectr/logs/<workspace-hash>.hooks.log — timestamp, hook
|
|
1111
|
+
# kind, and an approximate token count of what was injected. Off by
|
|
1112
|
+
# default: the per-hook-kind counters in `vectr status` already answer the
|
|
1113
|
+
# common "is this actually firing" question without writing to disk; turn
|
|
1114
|
+
# this on only when auditing exact injection timing/volume.
|
|
1115
|
+
log_injections: false
|
|
1116
|
+
|
|
1117
|
+
# Divisor used to turn the injected notes' character count into an
|
|
1118
|
+
# approximate token count for the optional injection log above. 4 is the
|
|
1119
|
+
# commonly-cited chars-per-token ratio for English/code text; this is a
|
|
1120
|
+
# rough sizing signal for the log, not a billing-accurate count.
|
|
1121
|
+
log_chars_per_token: 4
|
|
1122
|
+
|
|
1123
|
+
embedding:
|
|
1124
|
+
# Default local (sentence-transformers) embedding model for the L3 content
|
|
1125
|
+
# index (UPG-EMBEDDER-SWAP-GRANITE). Dimension-compatible drop-in for the
|
|
1126
|
+
# prior default (Snowflake/snowflake-arctic-embed-m-v1.5 — both 768-dim),
|
|
1127
|
+
# but a DIFFERENT vector space: a workspace's collection must never mix
|
|
1128
|
+
# vectors from the two (see CodeIndexer's embed-model stamp, which forces
|
|
1129
|
+
# a full rebuild on a stamp mismatch rather than letting old and new
|
|
1130
|
+
# vectors coexist). Query-prompt handling stays model-driven, never
|
|
1131
|
+
# hardcoded to either model's specific prefix convention: LocalEmbedProvider
|
|
1132
|
+
# detects a registered "query" prompt on the loaded model itself
|
|
1133
|
+
# (`model.prompts`) and only applies it when one exists, so a model with no
|
|
1134
|
+
# such registration (like this default) embeds queries and documents
|
|
1135
|
+
# identically, unchanged.
|
|
1136
|
+
default_model: ibm-granite/granite-embedding-english-r2
|
|
1137
|
+
# Hard cap on the encoder's token sequence length for local (sentence-
|
|
1138
|
+
# transformers) embedding, applied on top of whatever the model's own
|
|
1139
|
+
# config declares. Long-context embedders (this default declares 8192)
|
|
1140
|
+
# otherwise encode every long chunk at full length — quadratic-attention
|
|
1141
|
+
# cost on CPU, observed to stall a full-corpus index for hours — while
|
|
1142
|
+
# short-context models (512) are unaffected. 512 matches the prior
|
|
1143
|
+
# default's behavior; raise deliberately, with indexing throughput in mind.
|
|
1144
|
+
max_seq_length: 512
|
|
1145
|
+
|
|
1146
|
+
fetch:
|
|
1147
|
+
# UPG-CTX-EVICT: deterministic re-fetch-by-chunk-id contract. Every chunk
|
|
1148
|
+
# already carries a stable id (`file_path:start_line-end_line`, the literal
|
|
1149
|
+
# ChromaDB id) — vectr_fetch/POST /v1/fetch/`vectr fetch` restore any of
|
|
1150
|
+
# them verbatim in one call, no embedding or rerank involved. This caps how
|
|
1151
|
+
# many ids a single call may request, so a caller can't turn the re-fetch
|
|
1152
|
+
# surface into an unbounded bulk-export of the whole index.
|
|
1153
|
+
max_ids_per_call: 20
|