@iderouter/index-mcp 0.2.0-beta.1
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.
- package/README.md +93 -0
- package/package.json +26 -0
- package/scripts/benchmark-all.mjs +177 -0
- package/scripts/benchmark-auto-continuation.mjs +188 -0
- package/scripts/benchmark-background-fine-resume.mjs +245 -0
- package/scripts/benchmark-background-fine-wait.mjs +76 -0
- package/scripts/benchmark-background-fine.mjs +132 -0
- package/scripts/benchmark-clean-snapshot.mjs +83 -0
- package/scripts/benchmark-coarse-ready-search.mjs +161 -0
- package/scripts/benchmark-deferred.mjs +62 -0
- package/scripts/benchmark-first-semantic-visible.mjs +151 -0
- package/scripts/benchmark-gate.mjs +107 -0
- package/scripts/benchmark-generic-resumed-single-chunk-embed.mjs +104 -0
- package/scripts/benchmark-noop.mjs +24 -0
- package/scripts/benchmark-priority-ready-search.mjs +165 -0
- package/scripts/benchmark-repeat-search.mjs +148 -0
- package/scripts/benchmark-resumed-retry-burst.mjs +187 -0
- package/scripts/benchmark-resumed-single-chunk-success.mjs +154 -0
- package/scripts/benchmark-resumed-single-chunk.mjs +146 -0
- package/scripts/benchmark-single-priority-chunk-embed.mjs +145 -0
- package/scripts/benchmark-small-change.mjs +146 -0
- package/scripts/benchmark-stage-summary.mjs +88 -0
- package/scripts/lib/auto-continuation-state.mjs +34 -0
- package/scripts/lib/benchmark-query-packs.mjs +123 -0
- package/scripts/lib/benchmark-snapshot.mjs +109 -0
- package/scripts/lib/mcp-bench.mjs +455 -0
- package/src/architecture-query-fallback.js +50 -0
- package/src/background-definition-chunks.js +199 -0
- package/src/background-embedding-profile.js +64 -0
- package/src/background-fine-budget.js +18 -0
- package/src/background-fine-runtime.js +179 -0
- package/src/background-fine-selection.js +332 -0
- package/src/checkpoint-policy.js +16 -0
- package/src/conflict-policy.js +17 -0
- package/src/deferred-retry-delay.js +14 -0
- package/src/deferred-retry-status.js +10 -0
- package/src/embedding-attempt-ordinal.js +17 -0
- package/src/embedding-failure-penalty.js +60 -0
- package/src/embedding-failure-policy.js +52 -0
- package/src/embedding-flush-timeout.js +33 -0
- package/src/embedding-inflight-status.js +18 -0
- package/src/embedding-model-policy.js +44 -0
- package/src/embedding-next-switch.js +18 -0
- package/src/embedding-request-status-detail.js +25 -0
- package/src/embedding-request-status.js +22 -0
- package/src/embedding-selection-order.js +23 -0
- package/src/fine-run-queue.js +14 -0
- package/src/index.js +7970 -0
- package/src/job-supersession.js +25 -0
- package/src/priority-progress.js +20 -0
- package/src/priority-ready-anchor-coverage-normalize.js +18 -0
- package/src/priority-ready-anchor-coverage.js +23 -0
- package/src/priority-ready-hotspots.js +344 -0
- package/src/priority-ready-status.js +30 -0
- package/src/priority-ready-targets.js +45 -0
- package/src/priority-usable-attempt-plan.js +44 -0
- package/src/priority-usable-attempt-timeout.js +18 -0
- package/src/priority-usable-fast-path.js +11 -0
- package/src/priority-usable-probe-order.js +34 -0
- package/src/remote-strategy-failure-cache.js +55 -0
- package/src/resume-seed.js +9 -0
- package/src/semantic-first-checkpoint.js +8 -0
- package/src/semantic-slow-path.js +10 -0
- package/src/single-chunk-attempt-timeout.js +13 -0
- package/src/single-chunk-embedding-content.js +26 -0
- package/src/single-chunk-embedding-policy.js +18 -0
- package/src/single-chunk-provider-order.js +12 -0
- package/src/single-chunk-provider-policy.js +63 -0
- package/src/worker-lock-retry.js +24 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function timestampMs(value) {
|
|
2
|
+
const parsed = Date.parse(value || "");
|
|
3
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function jobIdOrder(job) {
|
|
7
|
+
const match = String(job?.id || "").match(/-(\d+)$/);
|
|
8
|
+
if (!match) return 0;
|
|
9
|
+
const numeric = Number(match[1]);
|
|
10
|
+
return Number.isFinite(numeric) ? numeric : 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function jobInstanceOrder(job) {
|
|
14
|
+
return Math.max(
|
|
15
|
+
timestampMs(job?.startedAt),
|
|
16
|
+
jobIdOrder(job),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isSupersededByJob(currentJob, latestJob) {
|
|
21
|
+
if (!currentJob || !latestJob) return false;
|
|
22
|
+
if (String(currentJob.id || "") === String(latestJob.id || "")) return false;
|
|
23
|
+
if (currentJob.codebasePath && latestJob.codebasePath && currentJob.codebasePath !== latestJob.codebasePath) return false;
|
|
24
|
+
return jobInstanceOrder(latestJob) > jobInstanceOrder(currentJob);
|
|
25
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function priorityReadyProgressValue(anchorTargets, completedFineFiles) {
|
|
2
|
+
const total = anchorTargets instanceof Set ? anchorTargets.size : 0;
|
|
3
|
+
if (total === 0) return 100;
|
|
4
|
+
let completed = 0;
|
|
5
|
+
for (const file of anchorTargets) {
|
|
6
|
+
if (completedFineFiles?.has?.(file)) completed += 1;
|
|
7
|
+
}
|
|
8
|
+
return Math.min(100, Math.round((completed / total) * 100));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function mergeCompletedFineFiles(...completedSets) {
|
|
12
|
+
const merged = new Set();
|
|
13
|
+
for (const set of completedSets) {
|
|
14
|
+
if (!set?.values) continue;
|
|
15
|
+
for (const file of set.values()) {
|
|
16
|
+
if (file) merged.add(file);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return merged;
|
|
20
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { buildPriorityReadyAnchorCoverage } from "./priority-ready-anchor-coverage.js";
|
|
2
|
+
|
|
3
|
+
export function normalizePriorityReadyAnchorCoverage(index) {
|
|
4
|
+
const next = { ...(index || {}) };
|
|
5
|
+
if (
|
|
6
|
+
next.priorityReadyAnchorCoverage &&
|
|
7
|
+
typeof next.priorityReadyAnchorCoverage.total === "number" &&
|
|
8
|
+
typeof next.priorityReadyAnchorCoverage.completed === "number" &&
|
|
9
|
+
Array.isArray(next.priorityReadyAnchorCoverage.completed_paths) &&
|
|
10
|
+
Array.isArray(next.priorityReadyAnchorCoverage.pending_paths)
|
|
11
|
+
) {
|
|
12
|
+
return next;
|
|
13
|
+
}
|
|
14
|
+
next.priorityReadyAnchorCoverage = buildPriorityReadyAnchorCoverage(next.chunks || [], {
|
|
15
|
+
availablePaths: Array.isArray(next.files) ? next.files.map((file) => file?.relativePath).filter(Boolean) : [],
|
|
16
|
+
});
|
|
17
|
+
return next;
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { priorityReadyAnchorPaths } from "./priority-ready-hotspots.js";
|
|
2
|
+
|
|
3
|
+
export function buildPriorityReadyAnchorCoverage(chunks, options = {}) {
|
|
4
|
+
const allAnchors = priorityReadyAnchorPaths();
|
|
5
|
+
const availablePaths = new Set(Array.isArray(options.availablePaths) ? options.availablePaths.filter(Boolean) : []);
|
|
6
|
+
const anchors = availablePaths.size > 0
|
|
7
|
+
? allAnchors.filter((item) => availablePaths.has(item))
|
|
8
|
+
: allAnchors;
|
|
9
|
+
const completed = new Set(
|
|
10
|
+
(Array.isArray(chunks) ? chunks : [])
|
|
11
|
+
.filter((chunk) => Array.isArray(chunk?.vector) ? chunk.vector.length > 0 : typeof chunk?.vectorBase64 === "string" && chunk.vectorBase64.length > 0)
|
|
12
|
+
.map((chunk) => chunk.relativePath)
|
|
13
|
+
.filter(Boolean),
|
|
14
|
+
);
|
|
15
|
+
const completedAnchors = anchors.filter((item) => completed.has(item));
|
|
16
|
+
const pendingAnchors = anchors.filter((item) => !completed.has(item));
|
|
17
|
+
return {
|
|
18
|
+
total: anchors.length,
|
|
19
|
+
completed: completedAnchors.length,
|
|
20
|
+
completed_paths: completedAnchors,
|
|
21
|
+
pending_paths: pendingAnchors,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
export function priorityReadyAnchorPaths() {
|
|
5
|
+
return [
|
|
6
|
+
"relay/common/relay_info.go",
|
|
7
|
+
"relay/compatible_handler.go",
|
|
8
|
+
"pkg/billingexpr/run.go",
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function priorityReadyHotspotTerms(relativePathInput) {
|
|
13
|
+
const relativePath = String(relativePathInput || "").toLowerCase().split(path.sep).join("/");
|
|
14
|
+
if (relativePath === "relay/common/relay_info.go") {
|
|
15
|
+
return ["streamsupportedchannels", "supportstreamoptions", "removedisabledfields", "allowsafetyidentifier", "allowincludeobfuscation"];
|
|
16
|
+
}
|
|
17
|
+
if (relativePath === "relay/compatible_handler.go") {
|
|
18
|
+
return ["supportstreamoptions", "forcestreamoption", "removedisabledfields", "buildusermemorypromptforrequest", "injectusermemoryintoopenairequest"];
|
|
19
|
+
}
|
|
20
|
+
if (relativePath === "relay/claude_handler.go") {
|
|
21
|
+
return ["claudehelper", "buildusermemorypromptforclauderequest", "injectusermemoryintoclauderequest", "removedisabledfields"];
|
|
22
|
+
}
|
|
23
|
+
if (relativePath === "pkg/billingexpr/run.go") {
|
|
24
|
+
return ["runexprwithrequest", "runexprbyhashwithrequest", "runprogram"];
|
|
25
|
+
}
|
|
26
|
+
if (relativePath === "relay/helper/price.go") {
|
|
27
|
+
return ["modelpricehelpertiered", "runexprwithrequest", "resolvepricingmodelname", "modelpricehelper"];
|
|
28
|
+
}
|
|
29
|
+
if (relativePath === "service/tiered_settle.go") {
|
|
30
|
+
return ["trytieredsettle", "buildtieredtokenparams"];
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function priorityReadyPreferredDefinitions(relativePathInput) {
|
|
36
|
+
const relativePath = String(relativePathInput || "").toLowerCase().split(path.sep).join("/");
|
|
37
|
+
if (relativePath === "relay/common/relay_info.go") {
|
|
38
|
+
return ["streamSupportedChannels"];
|
|
39
|
+
}
|
|
40
|
+
if (relativePath === "pkg/billingexpr/run.go") {
|
|
41
|
+
return ["RunExprWithRequest", "RunExpr"];
|
|
42
|
+
}
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function priorityReadyPreferredRegion(relativePathInput) {
|
|
47
|
+
const relativePath = String(relativePathInput || "").toLowerCase().split(path.sep).join("/");
|
|
48
|
+
if (relativePath === "relay/compatible_handler.go") {
|
|
49
|
+
return {
|
|
50
|
+
anchorTerms: [
|
|
51
|
+
"if request.StreamOptions != nil {",
|
|
52
|
+
"if !info.SupportStreamOptions || !lo.FromPtrOr(request.Stream, false) {",
|
|
53
|
+
],
|
|
54
|
+
chunkSize: 320,
|
|
55
|
+
startContextChars: 64,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (relativePath === "relay/common/relay_info.go") {
|
|
59
|
+
return {
|
|
60
|
+
chunkSize: 240,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (relativePath === "pkg/billingexpr/run.go") {
|
|
64
|
+
return {
|
|
65
|
+
chunkSize: 320,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function compactAlphaNum(value) {
|
|
72
|
+
return String(value || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function buildLineOffsets(content) {
|
|
76
|
+
const offsets = [0];
|
|
77
|
+
for (let i = 0; i < content.length; i += 1) {
|
|
78
|
+
if (content.charCodeAt(i) === 10) offsets.push(i + 1);
|
|
79
|
+
}
|
|
80
|
+
return offsets;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function lineForOffsetFromIndex(lineOffsets, offset) {
|
|
84
|
+
let low = 0;
|
|
85
|
+
let high = lineOffsets.length - 1;
|
|
86
|
+
while (low <= high) {
|
|
87
|
+
const mid = (low + high) >> 1;
|
|
88
|
+
if (lineOffsets[mid] <= offset) {
|
|
89
|
+
low = mid + 1;
|
|
90
|
+
} else {
|
|
91
|
+
high = mid - 1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return Math.max(1, high + 1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function snippetWindow(content, start, size) {
|
|
98
|
+
const safeStart = Math.max(0, start);
|
|
99
|
+
const safeEnd = Math.min(content.length, safeStart + Math.max(1, size));
|
|
100
|
+
return {
|
|
101
|
+
start: safeStart,
|
|
102
|
+
end: safeEnd,
|
|
103
|
+
content: content.slice(safeStart, safeEnd).trim(),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const DEFINITION_PATTERNS = [
|
|
108
|
+
/^(?:func|type|const|var)\s+[A-Za-z0-9_]+/gm,
|
|
109
|
+
/^(?:export\s+)?(?:async\s+)?function\s+[A-Za-z0-9_]+\s*\(/gm,
|
|
110
|
+
/^(?:export\s+)?(?:const|let|var)\s+[A-Za-z0-9_]+\s*=/gm,
|
|
111
|
+
/^(?:export\s+)?(?:class|interface)\s+[A-Za-z0-9_]+/gm,
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const PREFERRED_LEADING_DEFINITION_PATTERNS = [
|
|
115
|
+
/^(?:func)\s+(?:\([^)]+\)\s*)?[A-Za-z0-9_]+\s*\(/gm,
|
|
116
|
+
/^(?:export\s+)?(?:async\s+)?function\s+[A-Za-z0-9_]+\s*\(/gm,
|
|
117
|
+
/^(?:export\s+)?(?:class|interface)\s+[A-Za-z0-9_]+/gm,
|
|
118
|
+
/^(?:type)\s+[A-Za-z0-9_]+/gm,
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
function findDefinitionStartBeforeOffset(content, offset) {
|
|
122
|
+
const boundary = Math.max(0, Number(offset) || 0);
|
|
123
|
+
let best = -1;
|
|
124
|
+
for (const pattern of DEFINITION_PATTERNS) {
|
|
125
|
+
pattern.lastIndex = 0;
|
|
126
|
+
let match;
|
|
127
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
128
|
+
if (match.index > boundary) break;
|
|
129
|
+
best = Math.max(best, match.index);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return best >= 0 ? best : Math.max(0, content.lastIndexOf("\n", boundary) + 1);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function findFirstDefinitionStart(content) {
|
|
136
|
+
let preferred = -1;
|
|
137
|
+
for (const pattern of PREFERRED_LEADING_DEFINITION_PATTERNS) {
|
|
138
|
+
pattern.lastIndex = 0;
|
|
139
|
+
const match = pattern.exec(content);
|
|
140
|
+
if (!match) continue;
|
|
141
|
+
if (preferred < 0 || match.index < preferred) {
|
|
142
|
+
preferred = match.index;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (preferred >= 0) return preferred;
|
|
146
|
+
let best = -1;
|
|
147
|
+
for (const pattern of DEFINITION_PATTERNS) {
|
|
148
|
+
pattern.lastIndex = 0;
|
|
149
|
+
const match = pattern.exec(content);
|
|
150
|
+
if (!match) continue;
|
|
151
|
+
if (best < 0 || match.index < best) {
|
|
152
|
+
best = match.index;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return best >= 0 ? best : 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function trimWindowToNextDefinition(content, start, end) {
|
|
159
|
+
let best = end;
|
|
160
|
+
for (const pattern of DEFINITION_PATTERNS) {
|
|
161
|
+
pattern.lastIndex = Math.max(0, start + 1);
|
|
162
|
+
const match = pattern.exec(content);
|
|
163
|
+
if (!match) continue;
|
|
164
|
+
if (match.index <= start || match.index >= end) continue;
|
|
165
|
+
best = Math.min(best, match.index);
|
|
166
|
+
}
|
|
167
|
+
return best;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function hotspotMatchCount(windowContent, hotspotTerms) {
|
|
171
|
+
const compactWindow = compactAlphaNum(windowContent);
|
|
172
|
+
let count = 0;
|
|
173
|
+
for (const term of hotspotTerms) {
|
|
174
|
+
if (compactWindow.includes(term)) count += 1;
|
|
175
|
+
}
|
|
176
|
+
return count;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function findNamedDefinitionStart(content, definitionName) {
|
|
180
|
+
const escaped = String(definitionName || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
181
|
+
if (!escaped) return -1;
|
|
182
|
+
const patterns = [
|
|
183
|
+
new RegExp(`^func\\s+(?:\\([^)]+\\)\\s*)?${escaped}\\s*\\(`, "m"),
|
|
184
|
+
new RegExp(`^(?:var|const|type)\\s+${escaped}\\b`, "m"),
|
|
185
|
+
new RegExp(`^(?:export\\s+)?(?:async\\s+)?function\\s+${escaped}\\s*\\(`, "m"),
|
|
186
|
+
new RegExp(`^(?:export\\s+)?(?:const|let|var)\\s+${escaped}\\s*=`, "m"),
|
|
187
|
+
new RegExp(`^(?:export\\s+)?(?:class|interface)\\s+${escaped}\\b`, "m"),
|
|
188
|
+
];
|
|
189
|
+
for (const pattern of patterns) {
|
|
190
|
+
const match = pattern.exec(content);
|
|
191
|
+
if (match) return match.index;
|
|
192
|
+
}
|
|
193
|
+
return -1;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function findLineStartContaining(content, needle) {
|
|
197
|
+
const index = String(content || "").indexOf(String(needle || ""));
|
|
198
|
+
if (index < 0) return -1;
|
|
199
|
+
return Math.max(0, content.lastIndexOf("\n", index) + 1);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function primaryWindowStart(content, hitOffset, chunkSize) {
|
|
203
|
+
const definitionStart = findDefinitionStartBeforeOffset(content, hitOffset);
|
|
204
|
+
const distance = Math.max(0, hitOffset - definitionStart);
|
|
205
|
+
if (distance <= Math.floor(chunkSize * 0.5)) return definitionStart;
|
|
206
|
+
return Math.max(definitionStart, hitOffset - Math.floor(chunkSize * 0.35));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function extractGenericPriorityReadyFallbackChunk(content, file, chunkSize) {
|
|
210
|
+
const lineOffsets = buildLineOffsets(content);
|
|
211
|
+
const definitionStart = findFirstDefinitionStart(content);
|
|
212
|
+
const start = Math.max(0, definitionStart);
|
|
213
|
+
const window = snippetWindow(content, start, chunkSize);
|
|
214
|
+
window.end = trimWindowToNextDefinition(content, window.start, window.end);
|
|
215
|
+
window.content = content.slice(window.start, window.end).trim();
|
|
216
|
+
if (!window.content) return [];
|
|
217
|
+
return [{
|
|
218
|
+
id: crypto
|
|
219
|
+
.createHash("sha256")
|
|
220
|
+
.update(`${file.relativePath}:${window.start}:${window.content}`)
|
|
221
|
+
.digest("hex")
|
|
222
|
+
.slice(0, 24),
|
|
223
|
+
contentHash: crypto.createHash("sha256").update(window.content).digest("hex"),
|
|
224
|
+
relativePath: file.relativePath,
|
|
225
|
+
extension: file.extension,
|
|
226
|
+
startLine: lineForOffsetFromIndex(lineOffsets, window.start),
|
|
227
|
+
endLine: lineForOffsetFromIndex(lineOffsets, window.end),
|
|
228
|
+
content: window.content,
|
|
229
|
+
}];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function extractPriorityReadyHotspotChunks(content, file, options = {}) {
|
|
233
|
+
const hotspotTerms = priorityReadyHotspotTerms(file.relativePath);
|
|
234
|
+
const preferredRegion = priorityReadyPreferredRegion(file.relativePath);
|
|
235
|
+
const chunkSize = Math.max(1, Number(preferredRegion?.chunkSize || options.chunkSize) || 720);
|
|
236
|
+
const chunkCap = Math.max(1, Number(options.chunkCap) || 3);
|
|
237
|
+
const primaryOnly = Boolean(options.primaryOnly);
|
|
238
|
+
if (hotspotTerms.length === 0) {
|
|
239
|
+
return extractGenericPriorityReadyFallbackChunk(content, file, chunkSize);
|
|
240
|
+
}
|
|
241
|
+
const preferredDefinitions = priorityReadyPreferredDefinitions(file.relativePath);
|
|
242
|
+
const compactContent = compactAlphaNum(content);
|
|
243
|
+
if (!hotspotTerms.some((term) => compactContent.includes(term))) return [];
|
|
244
|
+
|
|
245
|
+
const lineOffsets = buildLineOffsets(content);
|
|
246
|
+
if (primaryOnly && preferredRegion?.anchorTerms?.length) {
|
|
247
|
+
for (const anchorTerm of preferredRegion.anchorTerms) {
|
|
248
|
+
const lineStart = findLineStartContaining(content, anchorTerm);
|
|
249
|
+
if (lineStart < 0) continue;
|
|
250
|
+
const start = Math.max(0, lineStart - Math.max(0, Number(preferredRegion.startContextChars) || 0));
|
|
251
|
+
const window = snippetWindow(content, start, chunkSize);
|
|
252
|
+
if (!window.content) continue;
|
|
253
|
+
return [{
|
|
254
|
+
id: crypto
|
|
255
|
+
.createHash("sha256")
|
|
256
|
+
.update(`${file.relativePath}:${window.start}:${window.content}`)
|
|
257
|
+
.digest("hex")
|
|
258
|
+
.slice(0, 24),
|
|
259
|
+
contentHash: crypto.createHash("sha256").update(window.content).digest("hex"),
|
|
260
|
+
relativePath: file.relativePath,
|
|
261
|
+
extension: file.extension,
|
|
262
|
+
startLine: lineForOffsetFromIndex(lineOffsets, window.start),
|
|
263
|
+
endLine: lineForOffsetFromIndex(lineOffsets, window.end),
|
|
264
|
+
content: window.content,
|
|
265
|
+
}];
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (primaryOnly && preferredDefinitions.length > 0) {
|
|
269
|
+
for (const definitionName of preferredDefinitions) {
|
|
270
|
+
const start = findNamedDefinitionStart(content, definitionName);
|
|
271
|
+
if (start < 0) continue;
|
|
272
|
+
const window = snippetWindow(content, start, chunkSize);
|
|
273
|
+
window.end = trimWindowToNextDefinition(content, window.start, window.end);
|
|
274
|
+
window.content = content.slice(window.start, window.end).trim();
|
|
275
|
+
if (!window.content) continue;
|
|
276
|
+
return [{
|
|
277
|
+
id: crypto
|
|
278
|
+
.createHash("sha256")
|
|
279
|
+
.update(`${file.relativePath}:${window.start}:${window.content}`)
|
|
280
|
+
.digest("hex")
|
|
281
|
+
.slice(0, 24),
|
|
282
|
+
contentHash: crypto.createHash("sha256").update(window.content).digest("hex"),
|
|
283
|
+
relativePath: file.relativePath,
|
|
284
|
+
extension: file.extension,
|
|
285
|
+
startLine: lineForOffsetFromIndex(lineOffsets, window.start),
|
|
286
|
+
endLine: lineForOffsetFromIndex(lineOffsets, window.end),
|
|
287
|
+
content: window.content,
|
|
288
|
+
}];
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const chunks = [];
|
|
292
|
+
const seen = new Set();
|
|
293
|
+
const rawLower = String(content || "").toLowerCase();
|
|
294
|
+
let bestPrimaryChunk = null;
|
|
295
|
+
|
|
296
|
+
for (let index = 0; index < hotspotTerms.length; index += 1) {
|
|
297
|
+
const term = hotspotTerms[index];
|
|
298
|
+
const first = rawLower.indexOf(term);
|
|
299
|
+
if (first < 0) continue;
|
|
300
|
+
const start = primaryOnly
|
|
301
|
+
? primaryWindowStart(content, first, chunkSize)
|
|
302
|
+
: first;
|
|
303
|
+
const window = snippetWindow(content, start, chunkSize);
|
|
304
|
+
if (primaryOnly) {
|
|
305
|
+
window.end = trimWindowToNextDefinition(content, window.start, window.end);
|
|
306
|
+
window.content = content.slice(window.start, window.end).trim();
|
|
307
|
+
}
|
|
308
|
+
if (!window.content) continue;
|
|
309
|
+
const key = `${window.start}:${window.end}`;
|
|
310
|
+
if (seen.has(key)) continue;
|
|
311
|
+
seen.add(key);
|
|
312
|
+
const chunk = {
|
|
313
|
+
id: crypto
|
|
314
|
+
.createHash("sha256")
|
|
315
|
+
.update(`${file.relativePath}:${window.start}:${window.content}`)
|
|
316
|
+
.digest("hex")
|
|
317
|
+
.slice(0, 24),
|
|
318
|
+
contentHash: crypto.createHash("sha256").update(window.content).digest("hex"),
|
|
319
|
+
relativePath: file.relativePath,
|
|
320
|
+
extension: file.extension,
|
|
321
|
+
startLine: lineForOffsetFromIndex(lineOffsets, window.start),
|
|
322
|
+
endLine: lineForOffsetFromIndex(lineOffsets, window.end),
|
|
323
|
+
content: window.content,
|
|
324
|
+
};
|
|
325
|
+
if (primaryOnly) {
|
|
326
|
+
const score = hotspotMatchCount(window.content, hotspotTerms);
|
|
327
|
+
if (
|
|
328
|
+
!bestPrimaryChunk ||
|
|
329
|
+
index < bestPrimaryChunk.termIndex ||
|
|
330
|
+
(index === bestPrimaryChunk.termIndex && score > bestPrimaryChunk.score) ||
|
|
331
|
+
(index === bestPrimaryChunk.termIndex && score === bestPrimaryChunk.score && chunk.content.length < bestPrimaryChunk.chunk.content.length)
|
|
332
|
+
) {
|
|
333
|
+
bestPrimaryChunk = { chunk, score, termIndex: index };
|
|
334
|
+
}
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
chunks.push(chunk);
|
|
338
|
+
if (chunks.length >= chunkCap) break;
|
|
339
|
+
}
|
|
340
|
+
if (primaryOnly) {
|
|
341
|
+
return bestPrimaryChunk ? [bestPrimaryChunk.chunk] : [];
|
|
342
|
+
}
|
|
343
|
+
return chunks;
|
|
344
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function formatPriorityReadyAnchorCoverage(anchorPaths, completedFineFiles) {
|
|
2
|
+
const anchors = Array.isArray(anchorPaths) ? anchorPaths : [];
|
|
3
|
+
const completed = completedFineFiles instanceof Set ? completedFineFiles : new Set();
|
|
4
|
+
const done = anchors.filter((item) => completed.has(item));
|
|
5
|
+
const pending = anchors.filter((item) => !completed.has(item));
|
|
6
|
+
return `anchor_targets=${done.length}/${anchors.length}; completed=[${done.join(",") || "none"}]; pending=[${pending.join(",") || "none"}]`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function buildPriorityReadyAnchorCoverageObject(anchorPaths, completedPaths) {
|
|
10
|
+
const anchors = Array.isArray(anchorPaths) ? anchorPaths.filter(Boolean) : [];
|
|
11
|
+
const completed = completedPaths instanceof Set
|
|
12
|
+
? completedPaths
|
|
13
|
+
: new Set(Array.isArray(completedPaths) ? completedPaths.filter(Boolean) : []);
|
|
14
|
+
const done = anchors.filter((item) => completed.has(item));
|
|
15
|
+
const pending = anchors.filter((item) => !completed.has(item));
|
|
16
|
+
return {
|
|
17
|
+
total: anchors.length,
|
|
18
|
+
completed: done.length,
|
|
19
|
+
completed_paths: done,
|
|
20
|
+
pending_paths: pending,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function formatPriorityReadyAnchorCoverageObject(coverage) {
|
|
25
|
+
const total = Number(coverage?.total || 0);
|
|
26
|
+
const completed = Number(coverage?.completed || 0);
|
|
27
|
+
const completedPaths = Array.isArray(coverage?.completed_paths) ? coverage.completed_paths : [];
|
|
28
|
+
const pendingPaths = Array.isArray(coverage?.pending_paths) ? coverage.pending_paths : [];
|
|
29
|
+
return `anchor_targets=${completed}/${total}; completed=[${completedPaths.join(",") || "none"}]; pending=[${pendingPaths.join(",") || "none"}]`;
|
|
30
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function pickPriorityReadyTargetPaths({
|
|
2
|
+
files,
|
|
3
|
+
preferredPaths,
|
|
4
|
+
orderedFallbackPaths,
|
|
5
|
+
maxChunks = 0,
|
|
6
|
+
fallbackMaxFiles = 0,
|
|
7
|
+
fallbackMaxChunks = 0,
|
|
8
|
+
getChunkEstimate,
|
|
9
|
+
getScore,
|
|
10
|
+
}) {
|
|
11
|
+
const normalizedFiles = Array.isArray(files) ? files : [];
|
|
12
|
+
const preferred = Array.isArray(preferredPaths) ? preferredPaths : [];
|
|
13
|
+
const fallback = Array.isArray(orderedFallbackPaths) ? orderedFallbackPaths : [];
|
|
14
|
+
const estimate = typeof getChunkEstimate === "function" ? getChunkEstimate : () => 1;
|
|
15
|
+
const score = typeof getScore === "function" ? getScore : () => 1;
|
|
16
|
+
const chunkBudget = Math.max(0, Number(maxChunks) || 0);
|
|
17
|
+
const fallbackFileBudget = Math.max(1, Number(fallbackMaxFiles) || 0);
|
|
18
|
+
const fallbackChunkBudget = Math.max(0, Number(fallbackMaxChunks) || 0);
|
|
19
|
+
const fileMap = new Map(normalizedFiles.map((file) => [file.relativePath, file]));
|
|
20
|
+
const selected = [];
|
|
21
|
+
let estimatedChunks = 0;
|
|
22
|
+
|
|
23
|
+
for (const relativePath of preferred) {
|
|
24
|
+
const file = fileMap.get(relativePath);
|
|
25
|
+
if (!file) continue;
|
|
26
|
+
const chunkEstimate = Math.max(1, Number(estimate(file)) || 1);
|
|
27
|
+
if (selected.length > 0 && chunkBudget > 0 && estimatedChunks + chunkEstimate > chunkBudget) continue;
|
|
28
|
+
selected.push(relativePath);
|
|
29
|
+
estimatedChunks += chunkEstimate;
|
|
30
|
+
}
|
|
31
|
+
if (selected.length > 0) return new Set(selected);
|
|
32
|
+
|
|
33
|
+
for (const relativePath of fallback) {
|
|
34
|
+
const file = fileMap.get(relativePath);
|
|
35
|
+
if (!file) continue;
|
|
36
|
+
if (Number(score(file)) <= 0 && selected.length > 0) break;
|
|
37
|
+
if (selected.length >= fallbackFileBudget) break;
|
|
38
|
+
const chunkEstimate = Math.max(1, Number(estimate(file)) || 1);
|
|
39
|
+
const activeFallbackChunkBudget = fallbackChunkBudget > 0 ? fallbackChunkBudget : chunkBudget;
|
|
40
|
+
if (selected.length > 0 && activeFallbackChunkBudget > 0 && estimatedChunks + chunkEstimate > activeFallbackChunkBudget) break;
|
|
41
|
+
selected.push(relativePath);
|
|
42
|
+
estimatedChunks += chunkEstimate;
|
|
43
|
+
}
|
|
44
|
+
return new Set(selected);
|
|
45
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export function buildPriorityUsableAttemptPlan({
|
|
2
|
+
source = "",
|
|
3
|
+
chunkCount = 0,
|
|
4
|
+
candidates = [],
|
|
5
|
+
preferredModel = "",
|
|
6
|
+
cachedHealthModel = "",
|
|
7
|
+
cachedHealthOk = true,
|
|
8
|
+
cachedHealthLatencyMs = 0,
|
|
9
|
+
primaryTimeoutMs = 0,
|
|
10
|
+
fallbackTimeoutMs = 0,
|
|
11
|
+
}) {
|
|
12
|
+
const sourceText = String(source || "");
|
|
13
|
+
if (
|
|
14
|
+
!sourceText.startsWith("priority_usable_strategy") ||
|
|
15
|
+
sourceText.startsWith("priority_usable_strategy_fallback") ||
|
|
16
|
+
sourceText.startsWith("priority_usable_strategy_selection_timeout_fallback")
|
|
17
|
+
) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
if (Number(chunkCount || 0) <= 1) return [];
|
|
21
|
+
const list = Array.isArray(candidates) ? candidates.filter(Boolean) : [];
|
|
22
|
+
if (list.length < 2) return [];
|
|
23
|
+
const primaryModel = preferredModel || list[0];
|
|
24
|
+
const fallbackModel = list.find((candidate) => candidate !== primaryModel);
|
|
25
|
+
if (!fallbackModel) return [];
|
|
26
|
+
if (String(cachedHealthModel || "").trim() !== fallbackModel) return [];
|
|
27
|
+
if (cachedHealthOk === false) return [];
|
|
28
|
+
if (Math.max(0, Number(cachedHealthLatencyMs || 0)) <= 0) return [];
|
|
29
|
+
return [
|
|
30
|
+
{
|
|
31
|
+
model: primaryModel,
|
|
32
|
+
timeoutMs: Math.max(1, Number(primaryTimeoutMs) || 0),
|
|
33
|
+
maxRetries: 0,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
model: fallbackModel,
|
|
37
|
+
timeoutMs: Math.max(
|
|
38
|
+
Math.max(1, Number(fallbackTimeoutMs) || 0),
|
|
39
|
+
Math.max(1, Number(primaryTimeoutMs) || 0),
|
|
40
|
+
),
|
|
41
|
+
maxRetries: 0,
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function priorityUsableAttemptOuterTimeoutMs({
|
|
2
|
+
source = "",
|
|
3
|
+
attemptTimeoutMs = 0,
|
|
4
|
+
priorityTimeoutMs = 0,
|
|
5
|
+
priorityFallbackTimeoutMs = 0,
|
|
6
|
+
}) {
|
|
7
|
+
const sourceText = String(source || "");
|
|
8
|
+
const attemptMs = Math.max(0, Number(attemptTimeoutMs || 0));
|
|
9
|
+
const priorityMs = Math.max(0, Number(priorityTimeoutMs || 0));
|
|
10
|
+
const fallbackMs = Math.max(0, Number(priorityFallbackTimeoutMs || 0));
|
|
11
|
+
if (sourceText.startsWith("priority_usable_strategy_fallback")) {
|
|
12
|
+
return Math.max(attemptMs, fallbackMs);
|
|
13
|
+
}
|
|
14
|
+
if (sourceText.startsWith("priority_usable_strategy")) {
|
|
15
|
+
return Math.max(attemptMs, Math.min(Math.max(priorityMs, fallbackMs), 8000));
|
|
16
|
+
}
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function shouldLockPriorityUsableProbeToPreferred({
|
|
2
|
+
force = false,
|
|
3
|
+
hasReusableFineVectors = false,
|
|
4
|
+
previousEmbeddingFailure = false,
|
|
5
|
+
preferredModel = "",
|
|
6
|
+
}) {
|
|
7
|
+
if (force) return false;
|
|
8
|
+
if (hasReusableFineVectors) return false;
|
|
9
|
+
if (previousEmbeddingFailure) return false;
|
|
10
|
+
return String(preferredModel || "").trim() === "openai/text-embedding-3-small";
|
|
11
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function priorityUsableProbeOrder({
|
|
2
|
+
preferredModel = "",
|
|
3
|
+
candidates = [],
|
|
4
|
+
allowFallbackCandidates = true,
|
|
5
|
+
penalizedModels = [],
|
|
6
|
+
}) {
|
|
7
|
+
const ordered = [];
|
|
8
|
+
const seen = new Set();
|
|
9
|
+
const penalized = new Set((Array.isArray(penalizedModels) ? penalizedModels : []).map((value) => String(value || "").trim()).filter(Boolean));
|
|
10
|
+
const add = (value) => {
|
|
11
|
+
const text = String(value || "").trim();
|
|
12
|
+
if (!text || seen.has(text)) return;
|
|
13
|
+
seen.add(text);
|
|
14
|
+
ordered.push(text);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const preferred = String(preferredModel || "").trim();
|
|
18
|
+
const normalizedCandidates = Array.isArray(candidates) ? candidates : [];
|
|
19
|
+
const preferredPenalized = preferred && penalized.has(preferred);
|
|
20
|
+
|
|
21
|
+
if (preferred && normalizedCandidates.includes(preferred) && !preferredPenalized) {
|
|
22
|
+
add(preferred);
|
|
23
|
+
if (!allowFallbackCandidates) return ordered;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (const candidate of normalizedCandidates) {
|
|
27
|
+
if (preferredPenalized && String(candidate || "").trim() === preferred) continue;
|
|
28
|
+
add(candidate);
|
|
29
|
+
}
|
|
30
|
+
if (preferredPenalized && preferred && normalizedCandidates.includes(preferred) && !seen.has(preferred)) {
|
|
31
|
+
add(preferred);
|
|
32
|
+
}
|
|
33
|
+
return ordered;
|
|
34
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export function recordRemoteStrategyFailure({
|
|
2
|
+
apiKey = "",
|
|
3
|
+
message = "",
|
|
4
|
+
nowMs = Date.now(),
|
|
5
|
+
}) {
|
|
6
|
+
return {
|
|
7
|
+
apiKey: String(apiKey || ""),
|
|
8
|
+
message: String(message || "").trim(),
|
|
9
|
+
failedAt: Number(nowMs || 0),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function shouldSkipRemoteStrategyFetch({
|
|
14
|
+
state = null,
|
|
15
|
+
apiKey = "",
|
|
16
|
+
nowMs = Date.now(),
|
|
17
|
+
cooldownMs = 0,
|
|
18
|
+
}) {
|
|
19
|
+
const activeState = state && typeof state === "object" ? state : null;
|
|
20
|
+
const resolvedApiKey = String(apiKey || "");
|
|
21
|
+
if (!activeState || !resolvedApiKey || activeState.apiKey !== resolvedApiKey) {
|
|
22
|
+
return { skip: false, message: "" };
|
|
23
|
+
}
|
|
24
|
+
const failedAt = Number(activeState.failedAt || 0);
|
|
25
|
+
const cooldown = Math.max(0, Number(cooldownMs || 0));
|
|
26
|
+
if (!failedAt || !cooldown) {
|
|
27
|
+
return { skip: false, message: "" };
|
|
28
|
+
}
|
|
29
|
+
if (Number(nowMs || 0) - failedAt >= cooldown) {
|
|
30
|
+
return { skip: false, message: "" };
|
|
31
|
+
}
|
|
32
|
+
const detail = String(activeState.message || "").trim();
|
|
33
|
+
return {
|
|
34
|
+
skip: true,
|
|
35
|
+
message: detail ? `recent remote strategy failure: ${detail}` : "recent remote strategy failure",
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isRemoteStrategyFailureStateActive({
|
|
40
|
+
state = null,
|
|
41
|
+
apiKey = "",
|
|
42
|
+
nowMs = Date.now(),
|
|
43
|
+
cooldownMs = 0,
|
|
44
|
+
}) {
|
|
45
|
+
return shouldSkipRemoteStrategyFetch({
|
|
46
|
+
state,
|
|
47
|
+
apiKey,
|
|
48
|
+
nowMs,
|
|
49
|
+
cooldownMs,
|
|
50
|
+
}).skip;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function clearRemoteStrategyFailureState() {
|
|
54
|
+
return null;
|
|
55
|
+
}
|