flowseeker 0.1.7
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/CHANGELOG.md +111 -0
- package/COMPATIBILITY.md +281 -0
- package/LICENSE +21 -0
- package/README.md +375 -0
- package/dist/adapters/frameworkEdges.js +586 -0
- package/dist/agent/approvalPolicy.js +81 -0
- package/dist/agent/commandRunner.js +166 -0
- package/dist/agent/flowCommandRunner.js +124 -0
- package/dist/agent/mcpToolRunner.js +167 -0
- package/dist/auth/githubAuth.js +71 -0
- package/dist/auth/modelList.js +127 -0
- package/dist/auth/oauthHandler.js +377 -0
- package/dist/chat/nativeChatParticipant.js +616 -0
- package/dist/cli/mcpServer.js +383 -0
- package/dist/cli/runEvaluation.js +789 -0
- package/dist/cli/runReplay.js +481 -0
- package/dist/commands/checkHostCompatibility.js +149 -0
- package/dist/commands/copyAgentPrompt.js +52 -0
- package/dist/commands/copyContext.js +54 -0
- package/dist/commands/explainSelectionRelevance.js +57 -0
- package/dist/commands/findRelevantContext.js +127 -0
- package/dist/commands/openEvidence.js +49 -0
- package/dist/commands/openMcpConfig.js +81 -0
- package/dist/commands/openRelatedTests.js +54 -0
- package/dist/commands/rebuildIndex.js +45 -0
- package/dist/commands/runEvaluationSuite.js +323 -0
- package/dist/commands/runReplaySuite.js +228 -0
- package/dist/config/defaultConfig.js +72 -0
- package/dist/config/loadConfig.js +84 -0
- package/dist/config/loadConfigFromPath.js +60 -0
- package/dist/extension.js +513 -0
- package/dist/gateway/agentPrompts.js +176 -0
- package/dist/gateway/aiGateway.js +1255 -0
- package/dist/gateway/aiProviders.js +901 -0
- package/dist/gateway/contextExpansion.js +331 -0
- package/dist/gateway/editProposalStore.js +238 -0
- package/dist/gateway/planProposalStore.js +28 -0
- package/dist/index/cacheStore.js +51 -0
- package/dist/index/chunker.js +45 -0
- package/dist/index/dependencyExtractor.js +107 -0
- package/dist/index/fileDiscovery.js +177 -0
- package/dist/index/structuredExtractor.js +256 -0
- package/dist/index/workspaceIndex.js +518 -0
- package/dist/mcp/mcpConfig.js +154 -0
- package/dist/mcp/mcpProvider.js +109 -0
- package/dist/mcp/mcpTools.js +215 -0
- package/dist/pipeline/agentPrompt.js +79 -0
- package/dist/pipeline/agentPromptHeadless.js +85 -0
- package/dist/pipeline/contextBlueprint.js +346 -0
- package/dist/pipeline/contextPack.js +80 -0
- package/dist/pipeline/diffPreview.js +79 -0
- package/dist/pipeline/evaluationMetrics.js +154 -0
- package/dist/pipeline/evidenceGraph.js +389 -0
- package/dist/pipeline/feedback.js +215 -0
- package/dist/pipeline/fileGroups.js +84 -0
- package/dist/pipeline/fileScanner.js +866 -0
- package/dist/pipeline/nodeScan.js +219 -0
- package/dist/pipeline/ranker.js +563 -0
- package/dist/pipeline/responseLanguage.js +39 -0
- package/dist/pipeline/retrievalPlan.js +163 -0
- package/dist/pipeline/runHeadless.js +54 -0
- package/dist/pipeline/runPipeline.js +114 -0
- package/dist/pipeline/solvePacket.js +382 -0
- package/dist/pipeline/subsystem.js +257 -0
- package/dist/pipeline/taskUnderstanding.js +453 -0
- package/dist/pipeline/tokenSavings.js +146 -0
- package/dist/pipeline/universalScan.js +216 -0
- package/dist/pipeline/verifyAfterApply.js +233 -0
- package/dist/runtime/capabilities.js +71 -0
- package/dist/runtime/hostDetect.js +98 -0
- package/dist/runtime/hostTier.js +68 -0
- package/dist/runtime/statusBar.js +80 -0
- package/dist/skills/skillRegistry.js +208 -0
- package/dist/types.js +3 -0
- package/dist/ui/chatViewProvider.js +3899 -0
- package/dist/ui/resultTreeProvider.js +174 -0
- package/dist/usage/quotaTracker.js +358 -0
- package/dist/utils/async.js +30 -0
- package/dist/utils/logger.js +64 -0
- package/dist/utils/text.js +364 -0
- package/dist/utils/updateChecker.js +140 -0
- package/package.json +561 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.understandTask = understandTask;
|
|
4
|
+
const text_1 = require("../utils/text");
|
|
5
|
+
const contextBlueprint_1 = require("./contextBlueprint");
|
|
6
|
+
const retrievalPlan_1 = require("./retrievalPlan");
|
|
7
|
+
const actionWords = new Set([
|
|
8
|
+
"add",
|
|
9
|
+
"create",
|
|
10
|
+
"update",
|
|
11
|
+
"notify",
|
|
12
|
+
"release",
|
|
13
|
+
"change",
|
|
14
|
+
"fix",
|
|
15
|
+
"remove",
|
|
16
|
+
"delete",
|
|
17
|
+
"refactor",
|
|
18
|
+
"rename",
|
|
19
|
+
"doi",
|
|
20
|
+
"send",
|
|
21
|
+
"export",
|
|
22
|
+
"import",
|
|
23
|
+
"upload",
|
|
24
|
+
"download",
|
|
25
|
+
"retry",
|
|
26
|
+
"fail",
|
|
27
|
+
"review",
|
|
28
|
+
"investigate",
|
|
29
|
+
"trace",
|
|
30
|
+
"debug",
|
|
31
|
+
"check",
|
|
32
|
+
"explain",
|
|
33
|
+
"describe",
|
|
34
|
+
"understand",
|
|
35
|
+
"validate",
|
|
36
|
+
"authorize",
|
|
37
|
+
"login",
|
|
38
|
+
"logout",
|
|
39
|
+
"them",
|
|
40
|
+
"sua",
|
|
41
|
+
"xoa",
|
|
42
|
+
"gui",
|
|
43
|
+
"xuat",
|
|
44
|
+
"kiem",
|
|
45
|
+
"giai",
|
|
46
|
+
"thich",
|
|
47
|
+
"mo",
|
|
48
|
+
"ta",
|
|
49
|
+
"loi"
|
|
50
|
+
]);
|
|
51
|
+
const actionSynonyms = {
|
|
52
|
+
gui: ["send", "sent", "dispatch"],
|
|
53
|
+
send: ["sent", "dispatch"],
|
|
54
|
+
xuat: ["export", "download"],
|
|
55
|
+
export: ["download", "csv", "excel", "xlsx", "report"],
|
|
56
|
+
import: ["upload", "file"],
|
|
57
|
+
upload: ["submit", "submission", "file", "attachment"],
|
|
58
|
+
download: ["export", "file"],
|
|
59
|
+
retry: ["queue", "job", "worker", "attempt"],
|
|
60
|
+
validate: ["verify", "check", "validation"],
|
|
61
|
+
authorize: ["permission", "policy", "role"],
|
|
62
|
+
login: ["auth", "session", "token"],
|
|
63
|
+
them: ["add", "create"],
|
|
64
|
+
add: ["create", "new"],
|
|
65
|
+
change: ["update", "modify"],
|
|
66
|
+
doi: ["change", "update"],
|
|
67
|
+
xoa: ["delete", "remove"],
|
|
68
|
+
delete: ["remove"],
|
|
69
|
+
refactor: ["rename", "extract"],
|
|
70
|
+
review: ["investigate", "trace", "check"],
|
|
71
|
+
investigate: ["trace", "debug", "check"],
|
|
72
|
+
check: ["verify", "validate"],
|
|
73
|
+
notify: ["notification", "message", "notice", "update"],
|
|
74
|
+
update: ["version", "release", "latest", "newer"],
|
|
75
|
+
release: ["version", "update", "latest", "newer"],
|
|
76
|
+
explain: [],
|
|
77
|
+
describe: [],
|
|
78
|
+
understand: [],
|
|
79
|
+
giai: [],
|
|
80
|
+
thich: [],
|
|
81
|
+
mo: [],
|
|
82
|
+
ta: []
|
|
83
|
+
};
|
|
84
|
+
const lowSignalActorTerms = new Set(["user", "account", "profile", "member"]);
|
|
85
|
+
const lowSignalInstructionTerms = new Set([
|
|
86
|
+
"not",
|
|
87
|
+
"able",
|
|
88
|
+
"any",
|
|
89
|
+
"existing",
|
|
90
|
+
"appears",
|
|
91
|
+
"should",
|
|
92
|
+
"support",
|
|
93
|
+
"supports",
|
|
94
|
+
"implement",
|
|
95
|
+
"implementation",
|
|
96
|
+
"users",
|
|
97
|
+
"explain",
|
|
98
|
+
"describe",
|
|
99
|
+
"understand",
|
|
100
|
+
"giai",
|
|
101
|
+
"thich",
|
|
102
|
+
"chuc",
|
|
103
|
+
"nang",
|
|
104
|
+
"mo",
|
|
105
|
+
"ta",
|
|
106
|
+
"function",
|
|
107
|
+
"functionality"
|
|
108
|
+
]);
|
|
109
|
+
function understandTask(task, config) {
|
|
110
|
+
const normalizedTask = (0, text_1.normalizeText)(task);
|
|
111
|
+
const rawTokens = (0, text_1.splitIdentifier)(task);
|
|
112
|
+
const literalCodeTerms = detectLiteralCodeTerms(task);
|
|
113
|
+
const actions = rawTokens.filter((term) => actionWords.has(term));
|
|
114
|
+
const phraseTerms = detectPhraseTerms(normalizedTask);
|
|
115
|
+
const concepts = pruneLowSignalConcepts((0, text_1.uniq)([...literalCodeTerms, ...rawTokens.filter((term) => !actionWords.has(term) && !lowSignalInstructionTerms.has(term)), ...phraseTerms])).slice(0, 28);
|
|
116
|
+
const synonymTerms = expandSynonyms([...concepts, ...actions], config.synonyms);
|
|
117
|
+
const actionTerms = actions.flatMap((action) => actionSynonyms[action] ?? [action]);
|
|
118
|
+
const keywords = (0, text_1.uniq)([...literalCodeTerms, ...concepts, ...synonymTerms, ...actionTerms]).filter((term) => term.length > 1);
|
|
119
|
+
const intent = detectIntent(normalizedTask);
|
|
120
|
+
const negativeTerms = detectNegativeTerms(normalizedTask);
|
|
121
|
+
const blueprint = (0, contextBlueprint_1.buildTaskBlueprint)({ intent: intent.intent, normalizedTask, concepts, actions, keywords, negativeTerms, confidence: intent.confidence });
|
|
122
|
+
const retrieval = (0, retrievalPlan_1.createRetrievalPlan)({ rawTask: task, normalizedTask, concepts, actions, keywords, blueprint }, config);
|
|
123
|
+
return {
|
|
124
|
+
rawTask: task,
|
|
125
|
+
normalizedTask,
|
|
126
|
+
intent: blueprint.shape,
|
|
127
|
+
taskShape: blueprint.shape,
|
|
128
|
+
intentConfidence: intent.confidence,
|
|
129
|
+
blueprint,
|
|
130
|
+
flowNeeds: blueprint.requiredSlots,
|
|
131
|
+
concepts,
|
|
132
|
+
actions,
|
|
133
|
+
entities: detectEntities(keywords),
|
|
134
|
+
negativeTerms,
|
|
135
|
+
literalTerms: literalCodeTerms,
|
|
136
|
+
keywords,
|
|
137
|
+
strategies: retrieval.strategies,
|
|
138
|
+
passes: retrieval.passes
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function detectLiteralCodeTerms(task) {
|
|
142
|
+
const terms = [];
|
|
143
|
+
const emailPattern = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
|
|
144
|
+
const quotedPattern = /["'`]([^"'`]{3,160})["'`]/g;
|
|
145
|
+
const routePattern = /\/(?:[A-Za-z0-9_:@.-]+\/)*[A-Za-z0-9_:@.-]+/g;
|
|
146
|
+
const pathPattern = /\b(?:[$A-Za-z0-9_.-]+\/)+[$A-Za-z0-9_.-]+\b/g;
|
|
147
|
+
const functionPattern = /\b[$A-Za-z_][$A-Za-z0-9_$.:#]*\s*\(/g;
|
|
148
|
+
const candidatePattern = /\b[$A-Za-z_][$A-Za-z0-9_$.:#]*\b/g;
|
|
149
|
+
let match = emailPattern.exec(task);
|
|
150
|
+
while (match) {
|
|
151
|
+
addLiteralValueTerm(terms, match[0]);
|
|
152
|
+
match = emailPattern.exec(task);
|
|
153
|
+
}
|
|
154
|
+
match = quotedPattern.exec(task);
|
|
155
|
+
while (match) {
|
|
156
|
+
addLiteralValueTerm(terms, match[1]);
|
|
157
|
+
if (isStrongCodeIdentifier(match[1])) {
|
|
158
|
+
addCodeTerm(terms, match[1]);
|
|
159
|
+
}
|
|
160
|
+
match = quotedPattern.exec(task);
|
|
161
|
+
}
|
|
162
|
+
match = routePattern.exec(task);
|
|
163
|
+
while (match) {
|
|
164
|
+
addPathLiteralTerm(terms, match[0]);
|
|
165
|
+
match = routePattern.exec(task);
|
|
166
|
+
}
|
|
167
|
+
match = pathPattern.exec(task);
|
|
168
|
+
while (match) {
|
|
169
|
+
if (isLikelyPathLiteral(match[0])) {
|
|
170
|
+
addPathLiteralTerm(terms, match[0]);
|
|
171
|
+
}
|
|
172
|
+
match = pathPattern.exec(task);
|
|
173
|
+
}
|
|
174
|
+
match = functionPattern.exec(task);
|
|
175
|
+
while (match) {
|
|
176
|
+
addCodeTerm(terms, match[0].replace(/\s*\($/, ""));
|
|
177
|
+
match = functionPattern.exec(task);
|
|
178
|
+
}
|
|
179
|
+
match = candidatePattern.exec(task);
|
|
180
|
+
while (match) {
|
|
181
|
+
const candidate = match[0];
|
|
182
|
+
if (isStrongCodeIdentifier(candidate)) {
|
|
183
|
+
addCodeTerm(terms, candidate);
|
|
184
|
+
}
|
|
185
|
+
match = candidatePattern.exec(task);
|
|
186
|
+
}
|
|
187
|
+
return (0, text_1.uniq)(terms).slice(0, 12);
|
|
188
|
+
}
|
|
189
|
+
function isStrongCodeIdentifier(candidate) {
|
|
190
|
+
const normalized = (0, text_1.normalizeText)(candidate);
|
|
191
|
+
const simpleExtensionFile = /^[a-z0-9-]+\.[a-z0-9]{1,5}$/.test(normalized);
|
|
192
|
+
const simpleFileBase = normalized.replace(/\.[a-z0-9]{1,5}$/, "");
|
|
193
|
+
const genericSimpleFiles = new Set(["index", "page", "route", "layout", "app", "main"]);
|
|
194
|
+
return ((simpleExtensionFile && !genericSimpleFiles.has(simpleFileBase)) ||
|
|
195
|
+
candidate.includes("_") ||
|
|
196
|
+
candidate.includes("$") ||
|
|
197
|
+
(candidate.includes(".") && !simpleExtensionFile) ||
|
|
198
|
+
candidate.includes(":") ||
|
|
199
|
+
candidate.includes("#") ||
|
|
200
|
+
/[a-z][A-Z]/.test(candidate));
|
|
201
|
+
}
|
|
202
|
+
function addCodeTerm(terms, candidate) {
|
|
203
|
+
const normalized = (0, text_1.normalizeText)(candidate).replace(/^[.:#]+|[.:#]+$/g, "");
|
|
204
|
+
const pathLike = normalized.replace(/[.:#]+/g, "_");
|
|
205
|
+
const leaf = normalized.split(/[.:#]+/).at(-1) ?? normalized;
|
|
206
|
+
const leafParts = (0, text_1.splitIdentifier)(leaf);
|
|
207
|
+
for (const term of [
|
|
208
|
+
pathLike,
|
|
209
|
+
leaf,
|
|
210
|
+
leafParts.length > 1 ? leafParts.join("_") : "",
|
|
211
|
+
leafParts.length > 1 ? leafParts.join("") : ""
|
|
212
|
+
]) {
|
|
213
|
+
if (term.length > 2) {
|
|
214
|
+
terms.push(term);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function addLiteralValueTerm(terms, value) {
|
|
219
|
+
const normalized = (0, text_1.normalizeText)(value).trim();
|
|
220
|
+
const collapsed = normalized.replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
221
|
+
for (const term of [normalized, collapsed]) {
|
|
222
|
+
if (term.length > 2) {
|
|
223
|
+
terms.push(term);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function addPathLiteralTerm(terms, value) {
|
|
228
|
+
const normalized = (0, text_1.normalizeText)(value).replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
|
|
229
|
+
const collapsed = normalized.replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
230
|
+
const basename = normalized.split("/").at(-1) ?? normalized;
|
|
231
|
+
const basenameTerm = /\.[a-z0-9]+$/.test(basename) ? "" : basename;
|
|
232
|
+
for (const term of [normalized, collapsed, basenameTerm]) {
|
|
233
|
+
if (term.length > 2) {
|
|
234
|
+
terms.push(term);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function isLikelyPathLiteral(value) {
|
|
239
|
+
const normalized = (0, text_1.normalizeText)(value).replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
|
|
240
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
241
|
+
if (segments.length >= 3) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
if (segments.length < 2) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
const first = segments[0];
|
|
248
|
+
const last = segments[segments.length - 1];
|
|
249
|
+
const commonRoots = new Set(["src", "app", "apps", "packages", "pkg", "internal", "lib", "libs", "test", "tests"]);
|
|
250
|
+
return commonRoots.has(first) || /\.[a-z0-9]{1,8}$/.test(last);
|
|
251
|
+
}
|
|
252
|
+
function detectPhraseTerms(normalizedTask) {
|
|
253
|
+
const terms = [];
|
|
254
|
+
if (/\btrinh\s+duyet\b|\bbrowser\b/.test(normalizedTask)) {
|
|
255
|
+
terms.push("browser", "client", "navigator", "timezone", "time_zone", "tz");
|
|
256
|
+
}
|
|
257
|
+
if (/\bmui\s+gio\b|\btimezone\b|\btime\s+zone\b/.test(normalizedTask)) {
|
|
258
|
+
terms.push("timezone", "time_zone", "tz", "utc", "local_time");
|
|
259
|
+
}
|
|
260
|
+
if (/\bthoi\s+gian\b|\btimestamp\b|\bdatetime\b/.test(normalizedTask)) {
|
|
261
|
+
terms.push("timestamp", "datetime", "date", "time");
|
|
262
|
+
}
|
|
263
|
+
if (/\b(currency|currencies|exchange\s+rate|exchange_rate|converter|conversion|eur|usd|vnd|gbp|jpy)\b/.test(normalizedTask) || (/\bconvert\b/.test(normalizedTask) && /\b(amount|money|transaction|payment)\b/.test(normalizedTask))) {
|
|
264
|
+
terms.push("currency", "exchange", "exchange_rate", "rate", "converter", "conversion", "amount");
|
|
265
|
+
}
|
|
266
|
+
if (/\bso\s+du\b|\bbalance\b|\bfunds?\b/.test(normalizedTask)) {
|
|
267
|
+
terms.push("balance", "funds", "account");
|
|
268
|
+
}
|
|
269
|
+
if ((/\bkhong\s+du\b|\binsufficient\b|\bnot\s+enough\b/.test(normalizedTask)) && /\b(so\s+du|balance|funds?|account|tai\s+khoan)\b/.test(normalizedTask)) {
|
|
270
|
+
terms.push("insufficient", "insufficient_funds", "funds", "balance", "exception", "error");
|
|
271
|
+
}
|
|
272
|
+
if (/\bchuyen\s+tien\b|\btransfer\b/.test(normalizedTask)) {
|
|
273
|
+
terms.push("transfer", "transaction");
|
|
274
|
+
}
|
|
275
|
+
if (/\btruy\s+van\b|\bqueries\b|\bquery\b|\bjoin\b|\bn\+1\b|\bn\s*\+\s*1\b/.test(normalizedTask)) {
|
|
276
|
+
terms.push("query", "queries", "join", "database", "model", "repository");
|
|
277
|
+
}
|
|
278
|
+
if (/\bban(?:ned)?\b/.test(normalizedTask) && /\b(user|account|member)\b/.test(normalizedTask)) {
|
|
279
|
+
terms.push("ban", "banned", "blocked", "disabled", "status", "user", "account", "login", "auth");
|
|
280
|
+
}
|
|
281
|
+
if (/\bhoc\s+vien\b|\bstudent\b|\blearner\b/.test(normalizedTask)) {
|
|
282
|
+
terms.push("student", "learner", "member");
|
|
283
|
+
}
|
|
284
|
+
if (/\bkhoa\s+hoc\b|\bcourse\b/.test(normalizedTask)) {
|
|
285
|
+
terms.push("course");
|
|
286
|
+
}
|
|
287
|
+
if (/\bhang\s+loat\b|\bbulk\b|\bbatch\b/.test(normalizedTask)) {
|
|
288
|
+
terms.push("bulk", "batch", "process", "job");
|
|
289
|
+
}
|
|
290
|
+
if (/\b(dang\s+ky|enroll|enrollment|registration)\b/.test(normalizedTask) &&
|
|
291
|
+
/\b(khoa\s+hoc|course|hoc\s+vien|student|learner|member)\b/.test(normalizedTask)) {
|
|
292
|
+
terms.push("enrollment", "enroll", "registration", "student", "course");
|
|
293
|
+
}
|
|
294
|
+
if (/\bmcp\s+server\b/.test(normalizedTask)) {
|
|
295
|
+
terms.push("mcp", "server", "mcpserver", "flowseeker_mcp");
|
|
296
|
+
}
|
|
297
|
+
if (/\b(thong\s+bao|notification|notify)\b/.test(normalizedTask)) {
|
|
298
|
+
terms.push("notification", "notify", "message");
|
|
299
|
+
}
|
|
300
|
+
if (/\b(thong\s+bao|notification|notify)\b/.test(normalizedTask) && /\b(ung\s+dung|in\s+app|in-app|app)\b/.test(normalizedTask)) {
|
|
301
|
+
terms.push("notification", "in_app", "inapp", "event");
|
|
302
|
+
}
|
|
303
|
+
const hasDocumentObject = /\b(tai lieu|document|attachment)\b/.test(normalizedTask);
|
|
304
|
+
const hasTransferFileObject = /\bfile\b/.test(normalizedTask) && /\b(nop|submit|submission|upload|download|import|export|xuat|tai len|tai xuong)\b/.test(normalizedTask);
|
|
305
|
+
if (/\b(nop|submit|submission|upload)\b/.test(normalizedTask) && (hasDocumentObject || hasTransferFileObject)) {
|
|
306
|
+
terms.push("submission", "upload", "document", "attachment", "file");
|
|
307
|
+
}
|
|
308
|
+
if (hasDocumentObject || hasTransferFileObject) {
|
|
309
|
+
terms.push("document", "attachment", "file");
|
|
310
|
+
}
|
|
311
|
+
if (/\b(loai|type|category)\b/.test(normalizedTask)) {
|
|
312
|
+
terms.push("type", "category");
|
|
313
|
+
}
|
|
314
|
+
if (/\b(phan quyen|permission|role|authorize|auth)\b/.test(normalizedTask)) {
|
|
315
|
+
terms.push("permission", "role", "policy", "authorize", "auth");
|
|
316
|
+
}
|
|
317
|
+
if (/\b(xuat|export|download|import)\b/.test(normalizedTask)) {
|
|
318
|
+
terms.push("export", "download", "import", "file");
|
|
319
|
+
}
|
|
320
|
+
if (/\bgio\s+hang\b|\bcart\b|\bbasket\b/.test(normalizedTask)) {
|
|
321
|
+
terms.push("cart", "basket");
|
|
322
|
+
}
|
|
323
|
+
if (/\bsan\s+pham\b|\bproduct\b/.test(normalizedTask)) {
|
|
324
|
+
terms.push("product");
|
|
325
|
+
}
|
|
326
|
+
if (/\bthanh\s+toan\b|\bcheckout\b|\bpayment\b/.test(normalizedTask)) {
|
|
327
|
+
terms.push("checkout", "payment", "billing");
|
|
328
|
+
}
|
|
329
|
+
if (/\bgiao\s+dien\b|\bfrontend\b|\bfront\s+end\b|\bui\b/.test(normalizedTask)) {
|
|
330
|
+
terms.push("ui", "frontend", "component", "view");
|
|
331
|
+
}
|
|
332
|
+
if (/\b(display|displayed|displays|shown|show|render|rendered|visible|hien\s+thi)\b/.test(normalizedTask)) {
|
|
333
|
+
terms.push("display", "render", "view", "ui");
|
|
334
|
+
}
|
|
335
|
+
if (/\btrang\b(?!\s+thai)|\bpage\b|\bscreen\b/.test(normalizedTask)) {
|
|
336
|
+
terms.push("page", "screen");
|
|
337
|
+
}
|
|
338
|
+
if (/\b(api\s+base\s+url|base\s+url)\b/.test(normalizedTask)) {
|
|
339
|
+
terms.push("api", "base_url", "baseurl", "endpoint", "client", "http", "config");
|
|
340
|
+
}
|
|
341
|
+
if (/\b(url|route|path|href|link|slug|params?|lookup)\b/.test(normalizedTask) && !/\b(api\s+base\s+url|base\s+url|config|env)\b/.test(normalizedTask)) {
|
|
342
|
+
terms.push("route", "page", "link", "href", "params", "slug");
|
|
343
|
+
}
|
|
344
|
+
if (/\btim\s+kiem\b|\bsearch\b|\bsuggestion\b|\bautocomplete\b/.test(normalizedTask)) {
|
|
345
|
+
terms.push("search", "suggestion", "autocomplete");
|
|
346
|
+
}
|
|
347
|
+
if (/\btin\s+nhan\b|\bmessage\b|\bchat\b|\bconversation\b/.test(normalizedTask)) {
|
|
348
|
+
terms.push("message", "chat", "conversation");
|
|
349
|
+
}
|
|
350
|
+
if (/\bnguoi\s+ban\b|\bseller\b|\bvendor\b|\bmerchant\b/.test(normalizedTask)) {
|
|
351
|
+
terms.push("seller", "vendor", "merchant");
|
|
352
|
+
}
|
|
353
|
+
if (/\bdon\s+hang\b|\border\b/.test(normalizedTask)) {
|
|
354
|
+
terms.push("order");
|
|
355
|
+
}
|
|
356
|
+
if (/\banh\b|\bhinh\b|\bimage\b|\bphoto\b|\bgallery\b|\bavatar\b|\bzoom\b/.test(normalizedTask)) {
|
|
357
|
+
terms.push("image", "photo", "gallery", "avatar", "zoom");
|
|
358
|
+
}
|
|
359
|
+
return terms;
|
|
360
|
+
}
|
|
361
|
+
function pruneLowSignalConcepts(concepts) {
|
|
362
|
+
const strongerConcepts = concepts.filter((term) => !lowSignalActorTerms.has(term));
|
|
363
|
+
return strongerConcepts.length >= 2 ? strongerConcepts : concepts;
|
|
364
|
+
}
|
|
365
|
+
function expandSynonyms(tokens, synonyms) {
|
|
366
|
+
const normalizedTokens = new Set(tokens.map(text_1.normalizeText));
|
|
367
|
+
const expanded = [];
|
|
368
|
+
for (const [key, values] of Object.entries(synonyms)) {
|
|
369
|
+
const normalizedKey = (0, text_1.normalizeText)(key);
|
|
370
|
+
const normalizedValues = values.map(text_1.normalizeText);
|
|
371
|
+
const matches = normalizedTokens.has(normalizedKey) || (allowReverseSynonymExpansion(normalizedKey) && normalizedValues.some((value) => normalizedTokens.has(value)));
|
|
372
|
+
if (matches) {
|
|
373
|
+
expanded.push(normalizedKey, ...normalizedValues);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return expanded;
|
|
377
|
+
}
|
|
378
|
+
function allowReverseSynonymExpansion(key) {
|
|
379
|
+
return !new Set(["auth", "document", "upload", "export"]).has(key);
|
|
380
|
+
}
|
|
381
|
+
function detectIntent(normalizedTask) {
|
|
382
|
+
if (/\b(sua|fix|khac phuc|loi|bug|fail|error|exception|khong|sai|hong)\b/.test(normalizedTask)) {
|
|
383
|
+
return { intent: "bugfix", confidence: 0.86 };
|
|
384
|
+
}
|
|
385
|
+
if (/\b(security|xss|csrf|sql injection|permission|authorize|authz|bao mat|phan quyen)\b/.test(normalizedTask)) {
|
|
386
|
+
return { intent: "security", confidence: 0.84 };
|
|
387
|
+
}
|
|
388
|
+
if (/\b(performance|slow|timeout|lag|cham|toi uu)\b/.test(normalizedTask)) {
|
|
389
|
+
return { intent: "performance", confidence: 0.84 };
|
|
390
|
+
}
|
|
391
|
+
if (/\b(migration|migrate|schema|database|db|database table)\b/.test(normalizedTask)) {
|
|
392
|
+
return { intent: "migration", confidence: 0.84 };
|
|
393
|
+
}
|
|
394
|
+
if (/\b(refactor|rename|doi ten|tach|gop|chuyen|switch|convert|change|change from)\b/.test(normalizedTask)) {
|
|
395
|
+
return { intent: "refactor", confidence: 0.78 };
|
|
396
|
+
}
|
|
397
|
+
if (/\b(find|investigate|trace|debug|review|check|explain|describe|understand|kiem tra|danh gia|ra soat|tim|giai thich|mo ta|tim hieu|cach hoat dong|how it works|how .* works)\b/.test(normalizedTask)) {
|
|
398
|
+
return { intent: "investigation", confidence: 0.78 };
|
|
399
|
+
}
|
|
400
|
+
if (/\b(add|create|new|feature|them|tao|xuat|export|download|upload|import)\b/.test(normalizedTask)) {
|
|
401
|
+
return { intent: "feature", confidence: 0.80 };
|
|
402
|
+
}
|
|
403
|
+
return { intent: "unknown", confidence: 0.35 };
|
|
404
|
+
}
|
|
405
|
+
function detectEntities(keywords) {
|
|
406
|
+
const entityHints = new Set([
|
|
407
|
+
"user", "account", "student", "learner", "member", "admin",
|
|
408
|
+
"invoice", "order", "payment", "course", "enrollment",
|
|
409
|
+
"document", "submission", "attachment", "notification", "message",
|
|
410
|
+
"policy", "claim", "refund", "audit", "report", "product", "cart",
|
|
411
|
+
"wishlist", "search", "seller", "vendor", "merchant"
|
|
412
|
+
]);
|
|
413
|
+
const entities = [];
|
|
414
|
+
for (const keyword of keywords) {
|
|
415
|
+
const normalized = (0, text_1.normalizeText)(keyword);
|
|
416
|
+
const singular = normalized.endsWith("ies")
|
|
417
|
+
? `${normalized.slice(0, -3)}y`
|
|
418
|
+
: normalized.endsWith("s")
|
|
419
|
+
? normalized.slice(0, -1)
|
|
420
|
+
: normalized;
|
|
421
|
+
if (entityHints.has(normalized)) {
|
|
422
|
+
entities.push(normalized);
|
|
423
|
+
}
|
|
424
|
+
if (entityHints.has(singular)) {
|
|
425
|
+
entities.push(singular);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return (0, text_1.uniq)(entities);
|
|
429
|
+
}
|
|
430
|
+
function detectNegativeTerms(normalizedTask) {
|
|
431
|
+
const terms = [];
|
|
432
|
+
const stopWords = new Set(["and", "or", "but", "when", "then", "only", "just", "ma", "nhung", "khi", "sau", "truoc", "chi", "thoi", "bang"]);
|
|
433
|
+
const patterns = [
|
|
434
|
+
/\b(?:without|exclude|excluding|not\s+using|not\s+use|not\s+by)\s+([a-z0-9_\-\s]{1,40})/g,
|
|
435
|
+
/\b(?:except)\s+([a-z0-9_\-\s]{1,40})/g,
|
|
436
|
+
/\b(?:instead\s+of|rather\s+than)\s+([a-z0-9_\-\s]{1,40})/g,
|
|
437
|
+
/\b(?:khong su dung|khong dung|loai tru|ngoai tru)\s+([a-z0-9_\-\s]{1,40})/g,
|
|
438
|
+
/\b(?:thay vi|thay cho)\s+([a-z0-9_\-\s]{1,40})/g
|
|
439
|
+
];
|
|
440
|
+
for (const pattern of patterns) {
|
|
441
|
+
let match = pattern.exec(normalizedTask);
|
|
442
|
+
while (match) {
|
|
443
|
+
for (const token of (0, text_1.splitIdentifier)(match[1]).slice(0, 4)) {
|
|
444
|
+
if (token.length > 1 && !stopWords.has(token)) {
|
|
445
|
+
terms.push(token);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
match = pattern.exec(normalizedTask);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return (0, text_1.uniq)(terms).slice(0, 8);
|
|
452
|
+
}
|
|
453
|
+
//# sourceMappingURL=taskUnderstanding.js.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeTokenSavings = computeTokenSavings;
|
|
4
|
+
exports.formatTokenCount = formatTokenCount;
|
|
5
|
+
exports.formatReductionPercent = formatReductionPercent;
|
|
6
|
+
exports.formatTokenSavingsLine = formatTokenSavingsLine;
|
|
7
|
+
exports.formatTokenProofSummary = formatTokenProofSummary;
|
|
8
|
+
const text_1 = require("../utils/text");
|
|
9
|
+
const fileGroups_1 = require("./fileGroups");
|
|
10
|
+
const solvePacket_1 = require("./solvePacket");
|
|
11
|
+
function computeTokenSavings(result) {
|
|
12
|
+
const stats = result.stats;
|
|
13
|
+
const packetText = result.solvePacket ? (0, solvePacket_1.renderSolvePacketMarkdown)(result.solvePacket) : result.contextPack;
|
|
14
|
+
const packetTokens = (0, text_1.countTextTokens)(packetText);
|
|
15
|
+
const contextPackTokens = (0, text_1.countTextTokens)(result.contextPack);
|
|
16
|
+
const basis = stats.indexedTokens !== undefined ? "workspace_index" : stats.scannedTokens && stats.scannedTokens > 0 ? "scanned_text" : "unavailable";
|
|
17
|
+
const proofWarnings = tokenProofWarnings(result, basis);
|
|
18
|
+
const workspaceTokensEstimate = basis === "workspace_index"
|
|
19
|
+
? stats.indexedTokens ?? 0
|
|
20
|
+
: basis === "scanned_text"
|
|
21
|
+
? stats.scannedTokens ?? 0
|
|
22
|
+
: 0;
|
|
23
|
+
const status = basis === "unavailable" ? "unavailable" : stats.stoppedEarly || basis === "scanned_text" ? "partial" : "estimated";
|
|
24
|
+
const proofStatus = basis === "unavailable" ? "unavailable" : status === "partial" ? "partial" : "complete";
|
|
25
|
+
const reason = status === "partial"
|
|
26
|
+
? partialReason(result, basis)
|
|
27
|
+
: status === "unavailable"
|
|
28
|
+
? "No readable workspace text was available for token estimation."
|
|
29
|
+
: undefined;
|
|
30
|
+
return {
|
|
31
|
+
status,
|
|
32
|
+
basis,
|
|
33
|
+
method: basis === "workspace_index" ? "heuristic" : packetTokens.method === "local_bpe" && contextPackTokens.method === "local_bpe" ? "local_bpe" : "heuristic",
|
|
34
|
+
tokenizer: basis === "workspace_index" ? `${packetTokens.tokenizer}+workspace_chars_per_4` : packetTokens.method === "local_bpe" && contextPackTokens.method === "local_bpe" ? "cl100k_base" : "chars_per_4",
|
|
35
|
+
reason,
|
|
36
|
+
proofStatus,
|
|
37
|
+
proofWarnings,
|
|
38
|
+
workspaceTokensEstimate,
|
|
39
|
+
candidateTokensEstimate: stats.scannedTokens ?? 0,
|
|
40
|
+
solvePacketTokensEstimate: packetTokens.tokens,
|
|
41
|
+
contextPackTokensEstimate: contextPackTokens.tokens,
|
|
42
|
+
reductionPercent: computeReductionPercent(workspaceTokensEstimate, packetTokens.tokens),
|
|
43
|
+
workspaceFileCount: stats.indexedFiles ?? stats.discoveredFiles,
|
|
44
|
+
scannedFileCount: stats.scannedFiles,
|
|
45
|
+
rankedFileCount: (0, fileGroups_1.aggregateEvidenceFiles)(result.units).length
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function formatTokenCount(tokens) {
|
|
49
|
+
if (!Number.isFinite(tokens) || tokens <= 0) {
|
|
50
|
+
return "0";
|
|
51
|
+
}
|
|
52
|
+
if (tokens >= 1000000) {
|
|
53
|
+
return `${trimFixed(tokens / 1000000)}M`;
|
|
54
|
+
}
|
|
55
|
+
if (tokens >= 1000) {
|
|
56
|
+
return `${trimFixed(tokens / 1000)}k`;
|
|
57
|
+
}
|
|
58
|
+
return String(Math.round(tokens));
|
|
59
|
+
}
|
|
60
|
+
function formatReductionPercent(value) {
|
|
61
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
62
|
+
return "0%";
|
|
63
|
+
}
|
|
64
|
+
if (value >= 99.995) {
|
|
65
|
+
return "99.99%";
|
|
66
|
+
}
|
|
67
|
+
return `${value.toFixed(value >= 99 ? 2 : 1)}%`;
|
|
68
|
+
}
|
|
69
|
+
function formatTokenSavingsLine(metrics) {
|
|
70
|
+
if (!metrics || metrics.status === "unavailable") {
|
|
71
|
+
return "tokens unavailable";
|
|
72
|
+
}
|
|
73
|
+
return `tokens ${formatTokenCount(metrics.solvePacketTokensEstimate)}/${formatTokenCount(metrics.workspaceTokensEstimate)} saved=${formatReductionPercent(metrics.reductionPercent)} tokenizer=${metrics.tokenizer}`;
|
|
74
|
+
}
|
|
75
|
+
function formatTokenProofSummary(task, metrics, contextCoverage) {
|
|
76
|
+
if (!metrics || metrics.status === "unavailable") {
|
|
77
|
+
return "FlowSeeker token proof unavailable — no readable workspace text was available for estimation.";
|
|
78
|
+
}
|
|
79
|
+
const lines = [
|
|
80
|
+
"FlowSeeker Token Proof",
|
|
81
|
+
"======================",
|
|
82
|
+
`Task: ${task}`,
|
|
83
|
+
`Packet tokens: ${formatTokenCount(metrics.solvePacketTokensEstimate)}`,
|
|
84
|
+
`Workspace tokens: ${formatTokenCount(metrics.workspaceTokensEstimate)}`,
|
|
85
|
+
`Reduction: ${formatReductionPercent(metrics.reductionPercent)}`,
|
|
86
|
+
`Tokenizer: ${metrics.tokenizer}`,
|
|
87
|
+
`Method: ${metrics.method}`,
|
|
88
|
+
`Proof status: ${metrics.proofStatus}`,
|
|
89
|
+
];
|
|
90
|
+
if (contextCoverage) {
|
|
91
|
+
lines.push(`Context coverage: ${contextCoverage.foundRequiredSlots.length}/${contextCoverage.requiredSlots.length} slots`);
|
|
92
|
+
if (contextCoverage.missingRequiredSlots.length) {
|
|
93
|
+
lines.push(`Missing slots: ${contextCoverage.missingRequiredSlots.join(", ")}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (metrics.proofWarnings && metrics.proofWarnings.length > 0) {
|
|
97
|
+
lines.push("Warnings:");
|
|
98
|
+
for (const warning of metrics.proofWarnings) {
|
|
99
|
+
lines.push(` - ${warning}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (metrics.reason) {
|
|
103
|
+
lines.push(`Note: ${metrics.reason}`);
|
|
104
|
+
}
|
|
105
|
+
return lines.join("\n");
|
|
106
|
+
}
|
|
107
|
+
function computeReductionPercent(workspaceTokens, packetTokens) {
|
|
108
|
+
if (!Number.isFinite(workspaceTokens) || workspaceTokens <= 0) {
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
const reduced = Math.max(0, workspaceTokens - Math.max(0, packetTokens));
|
|
112
|
+
return (reduced / workspaceTokens) * 100;
|
|
113
|
+
}
|
|
114
|
+
function partialReason(result, basis) {
|
|
115
|
+
const reasons = [];
|
|
116
|
+
if (basis === "scanned_text") {
|
|
117
|
+
reasons.push("workspace index was unavailable, so the baseline uses scanned candidate text only");
|
|
118
|
+
}
|
|
119
|
+
if (result.stats.stoppedEarly) {
|
|
120
|
+
reasons.push(result.stats.stopReason ?? "scan stopped early");
|
|
121
|
+
}
|
|
122
|
+
return reasons.join("; ");
|
|
123
|
+
}
|
|
124
|
+
function tokenProofWarnings(result, basis) {
|
|
125
|
+
const warnings = [];
|
|
126
|
+
if (basis === "scanned_text") {
|
|
127
|
+
warnings.push("workspace index unavailable; baseline uses scanned candidate text");
|
|
128
|
+
}
|
|
129
|
+
if (basis === "workspace_index") {
|
|
130
|
+
warnings.push("workspace baseline uses fast chars-per-4 token estimate to keep indexing responsive");
|
|
131
|
+
}
|
|
132
|
+
if (result.stats.stoppedEarly) {
|
|
133
|
+
warnings.push(result.stats.stopReason ?? "scan stopped early");
|
|
134
|
+
}
|
|
135
|
+
if (result.stats.capped) {
|
|
136
|
+
warnings.push("ranked evidence was capped; expand packet if required context is missing");
|
|
137
|
+
}
|
|
138
|
+
if (result.contextCoverage?.missingRequiredSlots.length) {
|
|
139
|
+
warnings.push(`missing required slots: ${result.contextCoverage.missingRequiredSlots.join(", ")}`);
|
|
140
|
+
}
|
|
141
|
+
return warnings;
|
|
142
|
+
}
|
|
143
|
+
function trimFixed(value) {
|
|
144
|
+
return value.toFixed(value >= 10 ? 1 : 2).replace(/\.0+$|(\.\d*[1-9])0+$/, "$1");
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=tokenSavings.js.map
|