@usewhisper/mcp-server 2.12.0 → 2.14.0
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 +5 -2
- package/dist/server.js +1134 -503
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -3785,6 +3785,9 @@ function buildMcpSearchPayload(input) {
|
|
|
3785
3785
|
count: normalizedResults.length,
|
|
3786
3786
|
degraded_mode: Boolean(input.degradedMode),
|
|
3787
3787
|
degraded_reason: input.degradedReason ?? null,
|
|
3788
|
+
semantic_status: input.semanticStatus ?? (input.degradedMode ? "failed" : "ok"),
|
|
3789
|
+
fallback_mode: input.fallbackMode ?? (input.degradedMode ? "lexical_backend" : "none"),
|
|
3790
|
+
recommended_fixes: input.recommendedFixes || [],
|
|
3788
3791
|
warnings: input.warnings || []
|
|
3789
3792
|
});
|
|
3790
3793
|
}
|
|
@@ -3844,6 +3847,8 @@ var RETRIEVAL_READINESS_VALUES = [
|
|
|
3844
3847
|
"local_fallback"
|
|
3845
3848
|
];
|
|
3846
3849
|
var RETRIEVAL_ROUTE_VALUES = ["project_repo", "local_workspace_fallback", "memory_only", "none"];
|
|
3850
|
+
var STATUS_LABEL_VALUES = ["healthy", "degraded_auto_repairing", "needs_user_action", "blocked"];
|
|
3851
|
+
var STATUS_ACTION_VALUES = ["none", "run_auto_repair", "restart_client", "reauth", "add_source", "reindex"];
|
|
3847
3852
|
var STATE_DIR = join(homedir(), ".whisper-mcp");
|
|
3848
3853
|
var STATE_PATH = join(STATE_DIR, "state.json");
|
|
3849
3854
|
var AUDIT_LOG_PATH = join(STATE_DIR, "forget-audit.log");
|
|
@@ -3876,6 +3881,7 @@ var ALIAS_TOOL_MAP = [
|
|
|
3876
3881
|
{ alias: "search", target: "context.query | memory.get" },
|
|
3877
3882
|
{ alias: "search_code", target: "code.search_semantic" },
|
|
3878
3883
|
{ alias: "grep", target: "code.search_text" },
|
|
3884
|
+
{ alias: "fix", target: "index.auto_repair" },
|
|
3879
3885
|
{ alias: "read", target: "local.file_read" },
|
|
3880
3886
|
{ alias: "explore", target: "local.tree" },
|
|
3881
3887
|
{ alias: "research", target: "research.oracle" },
|
|
@@ -3891,10 +3897,14 @@ var RECOMMENDED_NEXT_CALL_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
|
3891
3897
|
"context.list_projects",
|
|
3892
3898
|
"index.workspace_status",
|
|
3893
3899
|
"index.workspace_run",
|
|
3900
|
+
"index.auto_repair",
|
|
3901
|
+
"fix",
|
|
3894
3902
|
"search_code",
|
|
3895
3903
|
"grep",
|
|
3896
3904
|
"context.list_sources",
|
|
3905
|
+
"context.add_source",
|
|
3897
3906
|
"index.local_scan_ingest",
|
|
3907
|
+
"context.query",
|
|
3898
3908
|
"context.get_relevant"
|
|
3899
3909
|
]);
|
|
3900
3910
|
var UNTRUSTED_CODEBASE_HEALTH = /* @__PURE__ */ new Set(["unbound", "unindexed"]);
|
|
@@ -3902,12 +3912,85 @@ var UNTRUSTED_CODEBASE_PROJECT_READINESS = /* @__PURE__ */ new Set([
|
|
|
3902
3912
|
"project_unverified",
|
|
3903
3913
|
"project_bound_no_repo_source"
|
|
3904
3914
|
]);
|
|
3915
|
+
var RETRIEVAL_READINESS_RANK = {
|
|
3916
|
+
no_project: 0,
|
|
3917
|
+
project_unverified: 0,
|
|
3918
|
+
project_bound_no_repo_source: 1,
|
|
3919
|
+
project_repo_source_stale: 2,
|
|
3920
|
+
local_fallback: 3,
|
|
3921
|
+
project_repo_source_ready: 4
|
|
3922
|
+
};
|
|
3923
|
+
var ROOT_CAUSE_PRIMARY_ACTION = {
|
|
3924
|
+
none: "none",
|
|
3925
|
+
missing_api_key: "reauth",
|
|
3926
|
+
no_project_bound: "add_source",
|
|
3927
|
+
mode_mismatch_remote_local_ingest: "restart_client",
|
|
3928
|
+
workspace_unindexed: "reindex",
|
|
3929
|
+
project_bound_no_repo_source: "add_source",
|
|
3930
|
+
project_unverified: "reauth",
|
|
3931
|
+
project_repo_source_stale: "reindex",
|
|
3932
|
+
semantic_backend_unavailable: "run_auto_repair",
|
|
3933
|
+
local_fallback_active: "run_auto_repair"
|
|
3934
|
+
};
|
|
3935
|
+
var ROOT_CAUSE_NEXT_CALLS = {
|
|
3936
|
+
none: [],
|
|
3937
|
+
missing_api_key: [],
|
|
3938
|
+
no_project_bound: ["context.list_projects"],
|
|
3939
|
+
mode_mismatch_remote_local_ingest: [],
|
|
3940
|
+
workspace_unindexed: ["index.workspace_run"],
|
|
3941
|
+
project_bound_no_repo_source: ["context.add_source"],
|
|
3942
|
+
project_unverified: [],
|
|
3943
|
+
project_repo_source_stale: ["index.workspace_run"],
|
|
3944
|
+
semantic_backend_unavailable: ["fix"],
|
|
3945
|
+
local_fallback_active: ["fix"]
|
|
3946
|
+
};
|
|
3905
3947
|
function sanitizeRecommendedNextCalls(nextCalls) {
|
|
3906
3948
|
return Array.from(
|
|
3907
3949
|
new Set(
|
|
3908
3950
|
nextCalls.map((entry) => String(entry || "").trim()).filter((entry) => RECOMMENDED_NEXT_CALL_ALLOWLIST.has(entry))
|
|
3909
3951
|
)
|
|
3910
|
-
);
|
|
3952
|
+
).slice(0, 3);
|
|
3953
|
+
}
|
|
3954
|
+
function recommendedNextCallsAreAcyclic(nextCalls) {
|
|
3955
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3956
|
+
for (const nextCall of nextCalls) {
|
|
3957
|
+
if (seen.has(nextCall)) return false;
|
|
3958
|
+
seen.add(nextCall);
|
|
3959
|
+
}
|
|
3960
|
+
return true;
|
|
3961
|
+
}
|
|
3962
|
+
function retrievalReadinessRank(readiness) {
|
|
3963
|
+
return RETRIEVAL_READINESS_RANK[readiness];
|
|
3964
|
+
}
|
|
3965
|
+
function isStrictlyBetterReadiness(from, to) {
|
|
3966
|
+
return retrievalReadinessRank(to) > retrievalReadinessRank(from);
|
|
3967
|
+
}
|
|
3968
|
+
function statusActionForRootCause(rootCause) {
|
|
3969
|
+
return ROOT_CAUSE_PRIMARY_ACTION[rootCause] || "none";
|
|
3970
|
+
}
|
|
3971
|
+
function recommendedNextCallsForRootCause(rootCause) {
|
|
3972
|
+
return sanitizeRecommendedNextCalls(ROOT_CAUSE_NEXT_CALLS[rootCause] || []);
|
|
3973
|
+
}
|
|
3974
|
+
function statusLabelForAction(action) {
|
|
3975
|
+
if (action === "none") return "healthy";
|
|
3976
|
+
if (action === "run_auto_repair") return "degraded_auto_repairing";
|
|
3977
|
+
if (action === "reauth") return "blocked";
|
|
3978
|
+
return "needs_user_action";
|
|
3979
|
+
}
|
|
3980
|
+
function actionRequiredForAction(action) {
|
|
3981
|
+
return action !== "none" && action !== "run_auto_repair";
|
|
3982
|
+
}
|
|
3983
|
+
function getRepoReadinessNextCalls(readiness) {
|
|
3984
|
+
if (readiness === "project_bound_no_repo_source") {
|
|
3985
|
+
return recommendedNextCallsForRootCause("project_bound_no_repo_source");
|
|
3986
|
+
}
|
|
3987
|
+
if (readiness === "project_unverified") {
|
|
3988
|
+
return recommendedNextCallsForRootCause("project_unverified");
|
|
3989
|
+
}
|
|
3990
|
+
if (readiness === "project_repo_source_stale") {
|
|
3991
|
+
return recommendedNextCallsForRootCause("project_repo_source_stale");
|
|
3992
|
+
}
|
|
3993
|
+
return [];
|
|
3911
3994
|
}
|
|
3912
3995
|
function resolveMcpRetrievalProfile(requested) {
|
|
3913
3996
|
if (requested && MCP_RETRIEVAL_PROFILE_VALUES.includes(requested)) {
|
|
@@ -3915,6 +3998,156 @@ function resolveMcpRetrievalProfile(requested) {
|
|
|
3915
3998
|
}
|
|
3916
3999
|
return MCP_RETRIEVAL_PRECISION_V1_DEFAULT ? "precision_v1" : "legacy";
|
|
3917
4000
|
}
|
|
4001
|
+
function statusContractForReadiness(args) {
|
|
4002
|
+
if (args.root_cause_code && args.root_cause_code !== "none") {
|
|
4003
|
+
const action = statusActionForRootCause(args.root_cause_code);
|
|
4004
|
+
return {
|
|
4005
|
+
status_label: statusLabelForAction(action),
|
|
4006
|
+
status_action: action,
|
|
4007
|
+
action_required: actionRequiredForAction(action)
|
|
4008
|
+
};
|
|
4009
|
+
}
|
|
4010
|
+
if (args.force_repairing) {
|
|
4011
|
+
return {
|
|
4012
|
+
status_label: "degraded_auto_repairing",
|
|
4013
|
+
status_action: "run_auto_repair",
|
|
4014
|
+
action_required: false
|
|
4015
|
+
};
|
|
4016
|
+
}
|
|
4017
|
+
if (args.semantic_status === "failed") {
|
|
4018
|
+
return {
|
|
4019
|
+
status_label: "degraded_auto_repairing",
|
|
4020
|
+
status_action: "run_auto_repair",
|
|
4021
|
+
action_required: false
|
|
4022
|
+
};
|
|
4023
|
+
}
|
|
4024
|
+
if (args.workspace_health === "unindexed") {
|
|
4025
|
+
return {
|
|
4026
|
+
status_label: "needs_user_action",
|
|
4027
|
+
status_action: "reindex",
|
|
4028
|
+
action_required: true
|
|
4029
|
+
};
|
|
4030
|
+
}
|
|
4031
|
+
if (args.retrieval_readiness === "project_unverified") {
|
|
4032
|
+
return {
|
|
4033
|
+
status_label: "blocked",
|
|
4034
|
+
status_action: "reauth",
|
|
4035
|
+
action_required: true
|
|
4036
|
+
};
|
|
4037
|
+
}
|
|
4038
|
+
if (args.retrieval_readiness === "project_bound_no_repo_source") {
|
|
4039
|
+
if ((args.runtime_mode || RUNTIME_MODE) === "remote") {
|
|
4040
|
+
return {
|
|
4041
|
+
status_label: "needs_user_action",
|
|
4042
|
+
status_action: "add_source",
|
|
4043
|
+
action_required: true
|
|
4044
|
+
};
|
|
4045
|
+
}
|
|
4046
|
+
return {
|
|
4047
|
+
status_label: "needs_user_action",
|
|
4048
|
+
status_action: "reindex",
|
|
4049
|
+
action_required: true
|
|
4050
|
+
};
|
|
4051
|
+
}
|
|
4052
|
+
if (args.retrieval_readiness === "project_repo_source_stale") {
|
|
4053
|
+
return {
|
|
4054
|
+
status_label: "needs_user_action",
|
|
4055
|
+
status_action: "reindex",
|
|
4056
|
+
action_required: true
|
|
4057
|
+
};
|
|
4058
|
+
}
|
|
4059
|
+
if (args.retrieval_readiness === "local_fallback") {
|
|
4060
|
+
return {
|
|
4061
|
+
status_label: "degraded_auto_repairing",
|
|
4062
|
+
status_action: "run_auto_repair",
|
|
4063
|
+
action_required: false
|
|
4064
|
+
};
|
|
4065
|
+
}
|
|
4066
|
+
if (args.retrieval_readiness === "no_project") {
|
|
4067
|
+
return {
|
|
4068
|
+
status_label: "needs_user_action",
|
|
4069
|
+
status_action: "add_source",
|
|
4070
|
+
action_required: true
|
|
4071
|
+
};
|
|
4072
|
+
}
|
|
4073
|
+
return {
|
|
4074
|
+
status_label: "healthy",
|
|
4075
|
+
status_action: "none",
|
|
4076
|
+
action_required: false
|
|
4077
|
+
};
|
|
4078
|
+
}
|
|
4079
|
+
function semanticStatusFromSearchMode(mode) {
|
|
4080
|
+
if (mode === "semantic") return "ok";
|
|
4081
|
+
if (mode === "adaptive_semantic") return "adaptive";
|
|
4082
|
+
return "failed";
|
|
4083
|
+
}
|
|
4084
|
+
function fallbackModeFromSearchMode(mode) {
|
|
4085
|
+
if (mode === "semantic") return "none";
|
|
4086
|
+
if (mode === "adaptive_semantic") return "adaptive_threshold";
|
|
4087
|
+
return "lexical_rescue";
|
|
4088
|
+
}
|
|
4089
|
+
function parsePositiveNumber(value, fallback = 0) {
|
|
4090
|
+
const parsed = Number(value);
|
|
4091
|
+
if (!Number.isFinite(parsed) || parsed < 0) return fallback;
|
|
4092
|
+
return parsed;
|
|
4093
|
+
}
|
|
4094
|
+
function getWorkspaceSemanticFailureStats(workspaceId) {
|
|
4095
|
+
const state = loadState();
|
|
4096
|
+
const workspace = getWorkspaceState(state, workspaceId);
|
|
4097
|
+
const failures = parsePositiveNumber(workspace.index_metadata?.semantic_failures, 0);
|
|
4098
|
+
const attempts = parsePositiveNumber(workspace.index_metadata?.semantic_attempts, 0);
|
|
4099
|
+
const rate = attempts > 0 ? failures / attempts : 0;
|
|
4100
|
+
return { failures, attempts, rate };
|
|
4101
|
+
}
|
|
4102
|
+
function recordSemanticAttempt(workspaceId, failed) {
|
|
4103
|
+
const state = loadState();
|
|
4104
|
+
const workspace = getWorkspaceState(state, workspaceId);
|
|
4105
|
+
if (!workspace.index_metadata) workspace.index_metadata = {};
|
|
4106
|
+
const failures = parsePositiveNumber(workspace.index_metadata.semantic_failures, 0);
|
|
4107
|
+
const attempts = parsePositiveNumber(workspace.index_metadata.semantic_attempts, 0);
|
|
4108
|
+
workspace.index_metadata.semantic_attempts = attempts + 1;
|
|
4109
|
+
workspace.index_metadata.semantic_failures = failed ? failures + 1 : failures;
|
|
4110
|
+
saveState(state);
|
|
4111
|
+
}
|
|
4112
|
+
function computeTrustScore(args) {
|
|
4113
|
+
let score = 100;
|
|
4114
|
+
if (args.workspace_health === "unbound" || args.workspace_health === "unindexed") score -= 35;
|
|
4115
|
+
if (args.workspace_health === "stale" || args.workspace_health === "drifted") score -= 18;
|
|
4116
|
+
if (args.retrieval_readiness === "project_unverified") score -= 35;
|
|
4117
|
+
if (args.retrieval_readiness === "project_bound_no_repo_source") score -= 32;
|
|
4118
|
+
if (args.retrieval_readiness === "project_repo_source_stale") score -= 20;
|
|
4119
|
+
if (args.retrieval_readiness === "local_fallback") score -= 10;
|
|
4120
|
+
const failureRate = Math.max(0, Math.min(1, args.semantic_failure_rate || 0));
|
|
4121
|
+
score -= Math.round(failureRate * 25);
|
|
4122
|
+
return Math.max(0, Math.min(100, score));
|
|
4123
|
+
}
|
|
4124
|
+
function persistTrustScore(workspaceId, trustScore) {
|
|
4125
|
+
const state = loadState();
|
|
4126
|
+
const workspace = getWorkspaceState(state, workspaceId);
|
|
4127
|
+
if (!workspace.index_metadata) workspace.index_metadata = {};
|
|
4128
|
+
workspace.index_metadata.trust_score = Math.max(0, Math.min(100, Math.round(trustScore)));
|
|
4129
|
+
saveState(state);
|
|
4130
|
+
}
|
|
4131
|
+
function shouldAutoHeal(args) {
|
|
4132
|
+
if (args.retrieval_readiness === "project_unverified" || args.retrieval_readiness === "project_bound_no_repo_source") {
|
|
4133
|
+
return true;
|
|
4134
|
+
}
|
|
4135
|
+
if ((args.semantic_attempts || 0) >= 3 && args.semantic_failure_rate >= 0.5) {
|
|
4136
|
+
return true;
|
|
4137
|
+
}
|
|
4138
|
+
return args.trust_score < 60;
|
|
4139
|
+
}
|
|
4140
|
+
function resolveAutoRepairRootCause(args) {
|
|
4141
|
+
if (args.restart_required) return "mode_mismatch_remote_local_ingest";
|
|
4142
|
+
if (args.trust_health === "unindexed") return "workspace_unindexed";
|
|
4143
|
+
if (args.project_readiness === "project_bound_no_repo_source") return "project_bound_no_repo_source";
|
|
4144
|
+
if (args.project_readiness === "project_unverified") return "project_unverified";
|
|
4145
|
+
if (args.project_readiness === "project_repo_source_stale") return "project_repo_source_stale";
|
|
4146
|
+
if (args.semantic_attempts >= 3 && args.semantic_failure_rate >= 0.5) return "semantic_backend_unavailable";
|
|
4147
|
+
if (args.retrieval_readiness === "local_fallback") return "local_fallback_active";
|
|
4148
|
+
if (args.retrieval_readiness === "no_project") return "no_project_bound";
|
|
4149
|
+
return "none";
|
|
4150
|
+
}
|
|
3918
4151
|
function shouldAbstainForCodebaseTrust(args) {
|
|
3919
4152
|
if (args.retrievalProfile !== "precision_v1" || !args.codebaseIntent) return false;
|
|
3920
4153
|
return UNTRUSTED_CODEBASE_HEALTH.has(args.preflight.trust_state.health) || UNTRUSTED_CODEBASE_PROJECT_READINESS.has(args.preflight.project_retrieval_readiness);
|
|
@@ -4250,9 +4483,9 @@ async function resolveProjectDescriptor(projectRef) {
|
|
|
4250
4483
|
}
|
|
4251
4484
|
}
|
|
4252
4485
|
function getWorkspaceRecommendedNextCalls(health) {
|
|
4253
|
-
if (health === "unbound") return sanitizeRecommendedNextCalls(["index.workspace_resolve"
|
|
4254
|
-
if (health === "unindexed") return sanitizeRecommendedNextCalls(["index.
|
|
4255
|
-
if (health === "stale" || health === "drifted") return sanitizeRecommendedNextCalls(["index.
|
|
4486
|
+
if (health === "unbound") return sanitizeRecommendedNextCalls(["index.workspace_resolve"]);
|
|
4487
|
+
if (health === "unindexed") return sanitizeRecommendedNextCalls(["index.workspace_run"]);
|
|
4488
|
+
if (health === "stale" || health === "drifted") return sanitizeRecommendedNextCalls(["index.workspace_run"]);
|
|
4256
4489
|
return [];
|
|
4257
4490
|
}
|
|
4258
4491
|
function getWorkspaceWarnings(args) {
|
|
@@ -4448,8 +4681,8 @@ async function resolveRepoGroundingPreflight(args) {
|
|
|
4448
4681
|
}
|
|
4449
4682
|
}
|
|
4450
4683
|
const recommendedNextCalls = [...trust.recommended_next_calls];
|
|
4451
|
-
if (sourceVerification.retrieval_readiness
|
|
4452
|
-
recommendedNextCalls.push(
|
|
4684
|
+
if (sourceVerification.retrieval_readiness !== "project_repo_source_ready" && sourceVerification.retrieval_readiness !== "no_project") {
|
|
4685
|
+
recommendedNextCalls.push(...getRepoReadinessNextCalls(sourceVerification.retrieval_readiness));
|
|
4453
4686
|
}
|
|
4454
4687
|
return {
|
|
4455
4688
|
repo_grounded: repoGrounded,
|
|
@@ -4478,53 +4711,32 @@ async function ingestSessionWithSyncFallback(params) {
|
|
|
4478
4711
|
return whisper.ingestSession(params);
|
|
4479
4712
|
}
|
|
4480
4713
|
}
|
|
4481
|
-
function defaultMcpUserId() {
|
|
4714
|
+
function defaultMcpUserId(params) {
|
|
4482
4715
|
const explicit = process.env.WHISPER_USER_ID?.trim();
|
|
4483
4716
|
if (explicit) return explicit;
|
|
4484
|
-
const
|
|
4717
|
+
const workspacePath = params?.workspacePath || canonicalizeWorkspacePath(process.cwd());
|
|
4718
|
+
const projectRef = params?.project || DEFAULT_PROJECT || "default";
|
|
4719
|
+
const seed = `${workspacePath}|${projectRef}|${API_KEY.slice(0, 12) || "anon"}`;
|
|
4485
4720
|
return `mcp-user-${createHash("sha256").update(seed).digest("hex").slice(0, 12)}`;
|
|
4486
4721
|
}
|
|
4487
|
-
function resolveMcpScope(params) {
|
|
4722
|
+
function resolveMcpScope(params, options) {
|
|
4723
|
+
const workspacePath = canonicalizeWorkspacePath(params?.path || process.env.WHISPER_WORKSPACE_PATH || process.cwd());
|
|
4724
|
+
const explicitSession = params?.session_id?.trim();
|
|
4488
4725
|
return {
|
|
4489
4726
|
project: params?.project,
|
|
4490
|
-
userId: params?.user_id?.trim() || defaultMcpUserId(
|
|
4491
|
-
|
|
4492
|
-
|
|
4727
|
+
userId: params?.user_id?.trim() || defaultMcpUserId({
|
|
4728
|
+
project: params?.project,
|
|
4729
|
+
workspacePath
|
|
4730
|
+
}),
|
|
4731
|
+
sessionId: explicitSession || (options?.include_default_session ? cachedMcpSessionId : void 0),
|
|
4732
|
+
workspacePath
|
|
4493
4733
|
};
|
|
4494
4734
|
}
|
|
4495
|
-
async function prepareAutomaticQuery(params) {
|
|
4496
|
-
if (!runtimeClient) {
|
|
4497
|
-
throw new Error("Whisper runtime client unavailable.");
|
|
4498
|
-
}
|
|
4499
|
-
const scope = resolveMcpScope(params);
|
|
4500
|
-
const key = [
|
|
4501
|
-
params.project || DEFAULT_PROJECT || "",
|
|
4502
|
-
scope.userId,
|
|
4503
|
-
scope.sessionId,
|
|
4504
|
-
scope.workspacePath || process.cwd(),
|
|
4505
|
-
String(params.top_k || 10)
|
|
4506
|
-
].join("|");
|
|
4507
|
-
let runtime = runtimeSessions.get(key);
|
|
4508
|
-
if (!runtime) {
|
|
4509
|
-
runtime = runtimeClient.createAgentRuntime({
|
|
4510
|
-
project: params.project,
|
|
4511
|
-
userId: scope.userId,
|
|
4512
|
-
sessionId: scope.sessionId,
|
|
4513
|
-
workspacePath: scope.workspacePath,
|
|
4514
|
-
topK: params.top_k,
|
|
4515
|
-
clientName: "whisper-mcp"
|
|
4516
|
-
});
|
|
4517
|
-
runtimeSessions.set(key, runtime);
|
|
4518
|
-
}
|
|
4519
|
-
return runtime.beforeTurn({
|
|
4520
|
-
userMessage: params.query
|
|
4521
|
-
});
|
|
4522
|
-
}
|
|
4523
4735
|
function noteAutomaticSourceActivity(params) {
|
|
4524
4736
|
if (!runtimeClient) return;
|
|
4525
4737
|
const sourceIds = [...new Set((params.sourceIds || []).map((value) => String(value || "").trim()).filter(Boolean))];
|
|
4526
4738
|
if (sourceIds.length === 0) return;
|
|
4527
|
-
const scope = resolveMcpScope(params);
|
|
4739
|
+
const scope = resolveMcpScope(params, { include_default_session: true });
|
|
4528
4740
|
const key = [
|
|
4529
4741
|
params.project || DEFAULT_PROJECT || "",
|
|
4530
4742
|
scope.userId,
|
|
@@ -4556,7 +4768,7 @@ function buildAbstain(args) {
|
|
|
4556
4768
|
warnings: args.warnings || [],
|
|
4557
4769
|
trust_state: args.trust_state,
|
|
4558
4770
|
recommended_next_calls: sanitizeRecommendedNextCalls(
|
|
4559
|
-
args.recommended_next_calls || ["index.workspace_status", "index.workspace_run", "
|
|
4771
|
+
args.recommended_next_calls || ["index.workspace_status", "index.workspace_run", "fix", "context.query"]
|
|
4560
4772
|
),
|
|
4561
4773
|
diagnostics: {
|
|
4562
4774
|
claims_evaluated: args.claims_evaluated,
|
|
@@ -4611,6 +4823,415 @@ function countCodeFiles(searchPath, maxFiles = 5e3) {
|
|
|
4611
4823
|
walk(searchPath);
|
|
4612
4824
|
return { total, skipped };
|
|
4613
4825
|
}
|
|
4826
|
+
function computeWorkspaceSnapshot(searchPath, maxFiles = 250) {
|
|
4827
|
+
const files = collectCodeFiles(searchPath, CODE_EXTENSIONS, maxFiles);
|
|
4828
|
+
const entries = files.slice(0, maxFiles).map((filePath) => {
|
|
4829
|
+
try {
|
|
4830
|
+
const st = statSync(filePath);
|
|
4831
|
+
return `${relative(searchPath, filePath)}:${st.mtimeMs}:${st.size}`;
|
|
4832
|
+
} catch {
|
|
4833
|
+
return "";
|
|
4834
|
+
}
|
|
4835
|
+
}).filter(Boolean);
|
|
4836
|
+
const sample = entries.join("|");
|
|
4837
|
+
return {
|
|
4838
|
+
hash: createHash("sha256").update(sample || searchPath).digest("hex").slice(0, 24),
|
|
4839
|
+
entries
|
|
4840
|
+
};
|
|
4841
|
+
}
|
|
4842
|
+
function computeSnapshotChangedFiles(previousEntries, nextEntries) {
|
|
4843
|
+
if (!previousEntries || previousEntries.length === 0) return nextEntries.length;
|
|
4844
|
+
const previousByPath = /* @__PURE__ */ new Map();
|
|
4845
|
+
for (const entry of previousEntries) {
|
|
4846
|
+
const idx = entry.indexOf(":");
|
|
4847
|
+
if (idx <= 0) continue;
|
|
4848
|
+
previousByPath.set(entry.slice(0, idx), entry.slice(idx + 1));
|
|
4849
|
+
}
|
|
4850
|
+
let changed = 0;
|
|
4851
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4852
|
+
for (const entry of nextEntries) {
|
|
4853
|
+
const idx = entry.indexOf(":");
|
|
4854
|
+
if (idx <= 0) continue;
|
|
4855
|
+
const relPath = entry.slice(0, idx);
|
|
4856
|
+
const fingerprint = entry.slice(idx + 1);
|
|
4857
|
+
seen.add(relPath);
|
|
4858
|
+
if (previousByPath.get(relPath) !== fingerprint) changed += 1;
|
|
4859
|
+
}
|
|
4860
|
+
for (const relPath of previousByPath.keys()) {
|
|
4861
|
+
if (!seen.has(relPath)) changed += 1;
|
|
4862
|
+
}
|
|
4863
|
+
return changed;
|
|
4864
|
+
}
|
|
4865
|
+
function shouldTriggerBackgroundRefresh(args) {
|
|
4866
|
+
const nowMs = args.now_ms ?? Date.now();
|
|
4867
|
+
const lastAutoRefreshAt = args.last_auto_refresh_at ? new Date(args.last_auto_refresh_at).getTime() : 0;
|
|
4868
|
+
const debounceMs = 10 * 60 * 1e3;
|
|
4869
|
+
const dueForDebounce = !lastAutoRefreshAt || Number.isNaN(lastAutoRefreshAt) || nowMs - lastAutoRefreshAt >= debounceMs;
|
|
4870
|
+
if (!dueForDebounce) {
|
|
4871
|
+
return { should_refresh: false, trigger_reason: null };
|
|
4872
|
+
}
|
|
4873
|
+
if (args.last_indexed_commit && args.current_head && args.last_indexed_commit !== args.current_head) {
|
|
4874
|
+
return { should_refresh: true, trigger_reason: "head_changed" };
|
|
4875
|
+
}
|
|
4876
|
+
if (args.changed_files >= 20) {
|
|
4877
|
+
return { should_refresh: true, trigger_reason: "delta_files_threshold" };
|
|
4878
|
+
}
|
|
4879
|
+
const ratio = args.indexed_files > 0 ? args.changed_files / args.indexed_files : 0;
|
|
4880
|
+
if (ratio >= 0.02) {
|
|
4881
|
+
return { should_refresh: true, trigger_reason: "delta_ratio_threshold" };
|
|
4882
|
+
}
|
|
4883
|
+
return { should_refresh: false, trigger_reason: null };
|
|
4884
|
+
}
|
|
4885
|
+
async function runBackgroundWorkspaceRefresh(args) {
|
|
4886
|
+
const state = loadState();
|
|
4887
|
+
const workspace = getWorkspaceState(state, args.workspace_id);
|
|
4888
|
+
if (!workspace.index_metadata) workspace.index_metadata = {};
|
|
4889
|
+
const fileStats = countCodeFiles(args.root_path, args.max_files || 1500);
|
|
4890
|
+
const currentHead = getGitHead(args.root_path) || null;
|
|
4891
|
+
const currentSnapshot = computeWorkspaceSnapshot(args.root_path);
|
|
4892
|
+
const gitPendingCount = getGitPendingCount(args.root_path);
|
|
4893
|
+
const changedFiles = gitPendingCount == null ? computeSnapshotChangedFiles(workspace.index_metadata.last_snapshot_entries, currentSnapshot.entries) : gitPendingCount;
|
|
4894
|
+
const lastIndexedCommit = workspace.index_metadata.last_indexed_commit || null;
|
|
4895
|
+
const refreshDecision = shouldTriggerBackgroundRefresh({
|
|
4896
|
+
current_head: currentHead,
|
|
4897
|
+
last_indexed_commit: lastIndexedCommit,
|
|
4898
|
+
changed_files: changedFiles,
|
|
4899
|
+
indexed_files: parsePositiveNumber(workspace.index_metadata.indexed_files, fileStats.total || 1),
|
|
4900
|
+
last_auto_refresh_at: workspace.index_metadata.last_auto_refresh_at || null
|
|
4901
|
+
});
|
|
4902
|
+
const forceFullRequested = args.force_full === true;
|
|
4903
|
+
if (!refreshDecision.should_refresh && !forceFullRequested) {
|
|
4904
|
+
return { refreshed: false, mode: null, reason: null };
|
|
4905
|
+
}
|
|
4906
|
+
const mode = forceFullRequested ? "full" : "incremental";
|
|
4907
|
+
workspace.root_path = args.root_path;
|
|
4908
|
+
workspace.index_metadata.last_indexed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
4909
|
+
workspace.index_metadata.last_auto_refresh_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
4910
|
+
workspace.index_metadata.last_indexed_commit = currentHead || void 0;
|
|
4911
|
+
workspace.index_metadata.coverage = mode === "full" ? 1 : Math.max(0, Math.min(1, fileStats.total / Math.max(1, args.max_files || 1500)));
|
|
4912
|
+
workspace.index_metadata.indexed_files = fileStats.total;
|
|
4913
|
+
workspace.index_metadata.last_snapshot_hash = currentSnapshot.hash;
|
|
4914
|
+
workspace.index_metadata.last_snapshot_entries = currentSnapshot.entries;
|
|
4915
|
+
if (mode === "full") workspace.index_metadata.last_full_refresh_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
4916
|
+
saveState(state);
|
|
4917
|
+
return {
|
|
4918
|
+
refreshed: true,
|
|
4919
|
+
mode,
|
|
4920
|
+
reason: refreshDecision.trigger_reason || (forceFullRequested ? "manual_full_override" : mode === "full" ? "full_refresh_due" : "manual")
|
|
4921
|
+
};
|
|
4922
|
+
}
|
|
4923
|
+
function buildSourceRepairHint(args) {
|
|
4924
|
+
const remote = parseGitHubRemote(getGitRemoteUrl(args.root_path) || null);
|
|
4925
|
+
if (remote) {
|
|
4926
|
+
const branch = getGitBranch(args.root_path) || "main";
|
|
4927
|
+
return {
|
|
4928
|
+
command: `context.add_source --project ${args.project_ref || "<project>"} --type github --owner ${remote.owner} --repo ${remote.repo} --branch ${branch}`,
|
|
4929
|
+
message: "Attach the matching GitHub source, then rerun fix."
|
|
4930
|
+
};
|
|
4931
|
+
}
|
|
4932
|
+
return {
|
|
4933
|
+
command: `context.add_source --project ${args.project_ref || "<project>"} --type local --path "${args.root_path}"`,
|
|
4934
|
+
message: "Attach the local workspace as a source, then rerun fix."
|
|
4935
|
+
};
|
|
4936
|
+
}
|
|
4937
|
+
async function attemptDeterministicSourceAttach(args) {
|
|
4938
|
+
const remote = parseGitHubRemote(getGitRemoteUrl(args.root_path) || null);
|
|
4939
|
+
if (remote) {
|
|
4940
|
+
const branch = getGitBranch(args.root_path) || "main";
|
|
4941
|
+
const result = await createSourceByType({
|
|
4942
|
+
project: args.project,
|
|
4943
|
+
type: "github",
|
|
4944
|
+
name: `auto-repair:${remote.owner}/${remote.repo}`,
|
|
4945
|
+
owner: remote.owner,
|
|
4946
|
+
repo: remote.repo,
|
|
4947
|
+
branch,
|
|
4948
|
+
auto_index: true
|
|
4949
|
+
});
|
|
4950
|
+
const sourceId = result?.source_id || result?.id;
|
|
4951
|
+
noteAutomaticSourceActivity({
|
|
4952
|
+
project: args.project,
|
|
4953
|
+
sourceIds: sourceId ? [String(sourceId)] : []
|
|
4954
|
+
});
|
|
4955
|
+
return { attached: true, detail: `github:${remote.owner}/${remote.repo}@${branch}` };
|
|
4956
|
+
}
|
|
4957
|
+
if (RUNTIME_MODE !== "remote") {
|
|
4958
|
+
await createSourceByType({
|
|
4959
|
+
project: args.project,
|
|
4960
|
+
type: "local",
|
|
4961
|
+
name: "auto-repair:local-workspace",
|
|
4962
|
+
path: args.root_path,
|
|
4963
|
+
auto_index: true,
|
|
4964
|
+
max_files: 500
|
|
4965
|
+
});
|
|
4966
|
+
return { attached: true, detail: "local_workspace_source_attached" };
|
|
4967
|
+
}
|
|
4968
|
+
return { attached: false, detail: "deterministic_source_inputs_unavailable" };
|
|
4969
|
+
}
|
|
4970
|
+
async function runAutoRepairVerification(args) {
|
|
4971
|
+
if (args.preflight.retrieval_route === "project_repo" && args.preflight.matched_source_ids.length > 0) {
|
|
4972
|
+
try {
|
|
4973
|
+
const queryResult = await queryWithDegradedFallback({
|
|
4974
|
+
project: args.project,
|
|
4975
|
+
query: "how does this project work",
|
|
4976
|
+
top_k: 5,
|
|
4977
|
+
include_memories: false,
|
|
4978
|
+
include_graph: false,
|
|
4979
|
+
source_ids: args.preflight.matched_source_ids
|
|
4980
|
+
});
|
|
4981
|
+
const resultCount = Array.isArray(queryResult.response?.results) ? queryResult.response.results.length : 0;
|
|
4982
|
+
return {
|
|
4983
|
+
passed: resultCount > 0,
|
|
4984
|
+
route: "project_repo",
|
|
4985
|
+
result_count: resultCount,
|
|
4986
|
+
detail: resultCount > 0 ? "project_query_has_results" : "project_query_empty"
|
|
4987
|
+
};
|
|
4988
|
+
} catch (error) {
|
|
4989
|
+
return {
|
|
4990
|
+
passed: false,
|
|
4991
|
+
route: "project_repo",
|
|
4992
|
+
result_count: 0,
|
|
4993
|
+
detail: `project_query_error:${String(error?.message || error)}`
|
|
4994
|
+
};
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
if (args.preflight.retrieval_route === "local_workspace_fallback") {
|
|
4998
|
+
try {
|
|
4999
|
+
const local = await runLocalWorkspaceRetrieval({
|
|
5000
|
+
query: "how does this project work",
|
|
5001
|
+
path: args.preflight.trust_state.root_path,
|
|
5002
|
+
project: args.project,
|
|
5003
|
+
top_k: 5
|
|
5004
|
+
});
|
|
5005
|
+
return {
|
|
5006
|
+
passed: local.results.length > 0,
|
|
5007
|
+
route: "local_workspace_fallback",
|
|
5008
|
+
result_count: local.results.length,
|
|
5009
|
+
detail: local.results.length > 0 ? "local_query_has_results" : "local_query_empty"
|
|
5010
|
+
};
|
|
5011
|
+
} catch (error) {
|
|
5012
|
+
return {
|
|
5013
|
+
passed: false,
|
|
5014
|
+
route: "local_workspace_fallback",
|
|
5015
|
+
result_count: 0,
|
|
5016
|
+
detail: `local_query_error:${String(error?.message || error)}`
|
|
5017
|
+
};
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
return {
|
|
5021
|
+
passed: false,
|
|
5022
|
+
route: args.preflight.retrieval_route,
|
|
5023
|
+
result_count: 0,
|
|
5024
|
+
detail: "no_verifiable_retrieval_route"
|
|
5025
|
+
};
|
|
5026
|
+
}
|
|
5027
|
+
async function runAutoRepairFlow(input) {
|
|
5028
|
+
const actions_attempted = [];
|
|
5029
|
+
const actions_succeeded = [];
|
|
5030
|
+
const actions_failed = [];
|
|
5031
|
+
const apply = input.apply !== false;
|
|
5032
|
+
const repairScope = input.repair_scope || "safe";
|
|
5033
|
+
const allowRestartHint = input.allow_restart_hint !== false;
|
|
5034
|
+
let restartRequired = false;
|
|
5035
|
+
if (!API_KEY) {
|
|
5036
|
+
return {
|
|
5037
|
+
root_cause_code: "missing_api_key",
|
|
5038
|
+
actions_attempted,
|
|
5039
|
+
actions_succeeded,
|
|
5040
|
+
actions_failed: [...actions_failed, "validate_credentials:missing_api_key"],
|
|
5041
|
+
restart_required: false,
|
|
5042
|
+
verification_passed: false,
|
|
5043
|
+
status_label: "blocked",
|
|
5044
|
+
status_action: "reauth",
|
|
5045
|
+
action_required: true,
|
|
5046
|
+
diagnostics: {
|
|
5047
|
+
message: "WHISPER_API_KEY is required."
|
|
5048
|
+
}
|
|
5049
|
+
};
|
|
5050
|
+
}
|
|
5051
|
+
actions_attempted.push("validate_credentials");
|
|
5052
|
+
actions_succeeded.push("validate_credentials");
|
|
5053
|
+
actions_attempted.push("resolve_project");
|
|
5054
|
+
const resolvedProject = await resolveProjectRef(input.project);
|
|
5055
|
+
if (!resolvedProject) {
|
|
5056
|
+
actions_failed.push("resolve_project:no_project");
|
|
5057
|
+
return {
|
|
5058
|
+
root_cause_code: "no_project_bound",
|
|
5059
|
+
actions_attempted,
|
|
5060
|
+
actions_succeeded,
|
|
5061
|
+
actions_failed,
|
|
5062
|
+
restart_required: false,
|
|
5063
|
+
verification_passed: false,
|
|
5064
|
+
status_label: "needs_user_action",
|
|
5065
|
+
status_action: "add_source",
|
|
5066
|
+
action_required: true,
|
|
5067
|
+
diagnostics: {
|
|
5068
|
+
message: "No project resolved. Set WHISPER_PROJECT or pass project."
|
|
5069
|
+
}
|
|
5070
|
+
};
|
|
5071
|
+
}
|
|
5072
|
+
actions_succeeded.push("resolve_project");
|
|
5073
|
+
actions_attempted.push("resolve_workspace_trust");
|
|
5074
|
+
const beforePreflight = await resolveRepoGroundingPreflight({
|
|
5075
|
+
query: "how does this project work",
|
|
5076
|
+
path: input.path,
|
|
5077
|
+
workspace_id: input.workspace_id,
|
|
5078
|
+
project: resolvedProject
|
|
5079
|
+
});
|
|
5080
|
+
actions_succeeded.push("resolve_workspace_trust");
|
|
5081
|
+
actions_attempted.push("runtime_mode_check");
|
|
5082
|
+
if (allowRestartHint && RUNTIME_MODE === "remote" && (beforePreflight.project_retrieval_readiness === "project_bound_no_repo_source" || beforePreflight.retrieval_readiness === "local_fallback")) {
|
|
5083
|
+
actions_failed.push("runtime_mode_check:remote_mode_blocks_local_repair");
|
|
5084
|
+
restartRequired = true;
|
|
5085
|
+
} else {
|
|
5086
|
+
actions_succeeded.push("runtime_mode_check");
|
|
5087
|
+
}
|
|
5088
|
+
actions_attempted.push("refresh_workspace_index_metadata");
|
|
5089
|
+
let refreshResult = null;
|
|
5090
|
+
try {
|
|
5091
|
+
if (apply) {
|
|
5092
|
+
refreshResult = await runBackgroundWorkspaceRefresh({
|
|
5093
|
+
workspace_id: beforePreflight.trust_state.workspace_id,
|
|
5094
|
+
root_path: beforePreflight.trust_state.root_path,
|
|
5095
|
+
force_full: repairScope === "full"
|
|
5096
|
+
});
|
|
5097
|
+
} else {
|
|
5098
|
+
refreshResult = { refreshed: false, mode: null, reason: "dry_run" };
|
|
5099
|
+
}
|
|
5100
|
+
actions_succeeded.push("refresh_workspace_index_metadata");
|
|
5101
|
+
} catch (error) {
|
|
5102
|
+
actions_failed.push(`refresh_workspace_index_metadata:${String(error?.message || error)}`);
|
|
5103
|
+
}
|
|
5104
|
+
actions_attempted.push("repair_source_readiness");
|
|
5105
|
+
let sourceRepair = {
|
|
5106
|
+
applied: false,
|
|
5107
|
+
attached: false,
|
|
5108
|
+
detail: "not_required",
|
|
5109
|
+
hint: null
|
|
5110
|
+
};
|
|
5111
|
+
if (beforePreflight.project_retrieval_readiness === "project_bound_no_repo_source") {
|
|
5112
|
+
const hint = buildSourceRepairHint({
|
|
5113
|
+
root_path: beforePreflight.trust_state.root_path,
|
|
5114
|
+
project_ref: beforePreflight.trust_state.project_ref
|
|
5115
|
+
});
|
|
5116
|
+
sourceRepair = {
|
|
5117
|
+
applied: apply && repairScope === "full",
|
|
5118
|
+
attached: false,
|
|
5119
|
+
detail: "manual_source_attach_required",
|
|
5120
|
+
hint
|
|
5121
|
+
};
|
|
5122
|
+
if (apply && repairScope === "full") {
|
|
5123
|
+
try {
|
|
5124
|
+
const attach = await attemptDeterministicSourceAttach({
|
|
5125
|
+
project: resolvedProject,
|
|
5126
|
+
root_path: beforePreflight.trust_state.root_path
|
|
5127
|
+
});
|
|
5128
|
+
sourceRepair = {
|
|
5129
|
+
applied: true,
|
|
5130
|
+
attached: attach.attached,
|
|
5131
|
+
detail: attach.detail,
|
|
5132
|
+
hint
|
|
5133
|
+
};
|
|
5134
|
+
if (attach.attached) {
|
|
5135
|
+
actions_succeeded.push("repair_source_readiness");
|
|
5136
|
+
} else {
|
|
5137
|
+
actions_failed.push(`repair_source_readiness:${attach.detail}`);
|
|
5138
|
+
}
|
|
5139
|
+
} catch (error) {
|
|
5140
|
+
actions_failed.push(`repair_source_readiness:${String(error?.message || error)}`);
|
|
5141
|
+
}
|
|
5142
|
+
} else {
|
|
5143
|
+
actions_failed.push("repair_source_readiness:manual_source_attach_required");
|
|
5144
|
+
}
|
|
5145
|
+
} else {
|
|
5146
|
+
actions_succeeded.push("repair_source_readiness");
|
|
5147
|
+
}
|
|
5148
|
+
const afterPreflight = await resolveRepoGroundingPreflight({
|
|
5149
|
+
query: "how does this project work",
|
|
5150
|
+
path: beforePreflight.trust_state.root_path,
|
|
5151
|
+
workspace_id: beforePreflight.trust_state.workspace_id,
|
|
5152
|
+
project: resolvedProject
|
|
5153
|
+
});
|
|
5154
|
+
const semanticStats = getWorkspaceSemanticFailureStats(afterPreflight.trust_state.workspace_id);
|
|
5155
|
+
const trustScore = computeTrustScore({
|
|
5156
|
+
retrieval_readiness: afterPreflight.retrieval_readiness,
|
|
5157
|
+
workspace_health: afterPreflight.trust_state.health,
|
|
5158
|
+
semantic_failure_rate: semanticStats.rate
|
|
5159
|
+
});
|
|
5160
|
+
persistTrustScore(afterPreflight.trust_state.workspace_id, trustScore);
|
|
5161
|
+
const autoHeal = shouldAutoHeal({
|
|
5162
|
+
retrieval_readiness: afterPreflight.retrieval_readiness,
|
|
5163
|
+
trust_score: trustScore,
|
|
5164
|
+
semantic_failure_rate: semanticStats.rate,
|
|
5165
|
+
semantic_attempts: semanticStats.attempts
|
|
5166
|
+
});
|
|
5167
|
+
actions_attempted.push("verification_query");
|
|
5168
|
+
const verification = await runAutoRepairVerification({
|
|
5169
|
+
project: resolvedProject,
|
|
5170
|
+
preflight: afterPreflight
|
|
5171
|
+
});
|
|
5172
|
+
if (verification.passed) actions_succeeded.push("verification_query");
|
|
5173
|
+
else actions_failed.push(`verification_query:${verification.detail}`);
|
|
5174
|
+
const rootCause = resolveAutoRepairRootCause({
|
|
5175
|
+
restart_required: restartRequired,
|
|
5176
|
+
trust_health: beforePreflight.trust_state.health,
|
|
5177
|
+
project_readiness: beforePreflight.project_retrieval_readiness,
|
|
5178
|
+
retrieval_readiness: beforePreflight.retrieval_readiness,
|
|
5179
|
+
semantic_failure_rate: semanticStats.rate,
|
|
5180
|
+
semantic_attempts: semanticStats.attempts
|
|
5181
|
+
});
|
|
5182
|
+
const statusContract = statusContractForReadiness({
|
|
5183
|
+
retrieval_readiness: afterPreflight.retrieval_readiness,
|
|
5184
|
+
workspace_health: afterPreflight.trust_state.health,
|
|
5185
|
+
root_cause_code: rootCause,
|
|
5186
|
+
force_repairing: autoHeal && rootCause === "none"
|
|
5187
|
+
});
|
|
5188
|
+
const verificationPassed = verification.passed;
|
|
5189
|
+
const effectiveStatusAction = statusContract.status_action;
|
|
5190
|
+
const effectiveActionRequired = statusContract.action_required;
|
|
5191
|
+
const transitionImproved = isStrictlyBetterReadiness(
|
|
5192
|
+
beforePreflight.retrieval_readiness,
|
|
5193
|
+
afterPreflight.retrieval_readiness
|
|
5194
|
+
);
|
|
5195
|
+
const explicitBlocker = effectiveActionRequired;
|
|
5196
|
+
const recommendedNextCalls = sanitizeRecommendedNextCalls([
|
|
5197
|
+
...recommendedNextCallsForRootCause(rootCause),
|
|
5198
|
+
...afterPreflight.recommended_next_calls
|
|
5199
|
+
]);
|
|
5200
|
+
return {
|
|
5201
|
+
root_cause_code: rootCause,
|
|
5202
|
+
actions_attempted,
|
|
5203
|
+
actions_succeeded,
|
|
5204
|
+
actions_failed,
|
|
5205
|
+
restart_required: restartRequired,
|
|
5206
|
+
verification_passed: verificationPassed,
|
|
5207
|
+
status_label: statusContract.status_label,
|
|
5208
|
+
status_action: effectiveStatusAction,
|
|
5209
|
+
action_required: effectiveActionRequired,
|
|
5210
|
+
recommended_next_calls: recommendedNextCalls,
|
|
5211
|
+
diagnostics: {
|
|
5212
|
+
runtime_mode: RUNTIME_MODE,
|
|
5213
|
+
workspace_id: afterPreflight.trust_state.workspace_id,
|
|
5214
|
+
root_path: afterPreflight.trust_state.root_path,
|
|
5215
|
+
project_ref: afterPreflight.trust_state.project_ref,
|
|
5216
|
+
retrieval_readiness_before: beforePreflight.retrieval_readiness,
|
|
5217
|
+
retrieval_readiness_after: afterPreflight.retrieval_readiness,
|
|
5218
|
+
project_retrieval_readiness_after: afterPreflight.project_retrieval_readiness,
|
|
5219
|
+
retrieval_readiness_label: retrievalReadinessLabel(afterPreflight.retrieval_readiness),
|
|
5220
|
+
retrieval_readiness_action: retrievalReadinessAction(afterPreflight.retrieval_readiness),
|
|
5221
|
+
trust_score: trustScore,
|
|
5222
|
+
semantic_failure_rate: semanticStats.rate,
|
|
5223
|
+
semantic_attempts: semanticStats.attempts,
|
|
5224
|
+
refresh: refreshResult,
|
|
5225
|
+
source_repair: sourceRepair,
|
|
5226
|
+
verification,
|
|
5227
|
+
auto_heal_triggered: autoHeal,
|
|
5228
|
+
transition_improved: transitionImproved,
|
|
5229
|
+
explicit_blocker: explicitBlocker,
|
|
5230
|
+
recommended_next_calls: recommendedNextCalls,
|
|
5231
|
+
restart_hint: restartRequired ? "Set WHISPER_MCP_MODE=auto in MCP config and restart client." : null
|
|
5232
|
+
}
|
|
5233
|
+
};
|
|
5234
|
+
}
|
|
4614
5235
|
function toTextResult(payload) {
|
|
4615
5236
|
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
4616
5237
|
}
|
|
@@ -4677,42 +5298,6 @@ function resolveForgetQueryCandidates(rawResults, query) {
|
|
|
4677
5298
|
}
|
|
4678
5299
|
return { memory_ids: [], resolved_by: "none", warning: "Query did not resolve to a reliable memory match. No memories were changed." };
|
|
4679
5300
|
}
|
|
4680
|
-
async function searchMemoriesForContextQuery(args) {
|
|
4681
|
-
return whisper.searchMemoriesSOTA({
|
|
4682
|
-
project: args.project,
|
|
4683
|
-
query: args.query,
|
|
4684
|
-
user_id: args.user_id,
|
|
4685
|
-
session_id: args.session_id,
|
|
4686
|
-
top_k: args.top_k ?? 5,
|
|
4687
|
-
include_relations: false,
|
|
4688
|
-
include_pending: true
|
|
4689
|
-
});
|
|
4690
|
-
}
|
|
4691
|
-
async function runContextQueryMemoryRescue(args) {
|
|
4692
|
-
const scoped = await searchMemoriesForContextQuery(args);
|
|
4693
|
-
const scopedResults = formatCanonicalMemoryResults(scoped);
|
|
4694
|
-
if (scopedResults.length > 0) {
|
|
4695
|
-
return { results: scopedResults, rescue_mode: "scoped" };
|
|
4696
|
-
}
|
|
4697
|
-
if (args.user_id || args.session_id) {
|
|
4698
|
-
return { results: [], rescue_mode: null };
|
|
4699
|
-
}
|
|
4700
|
-
const broad = await searchMemoriesForContextQuery({
|
|
4701
|
-
project: args.project,
|
|
4702
|
-
query: args.query,
|
|
4703
|
-
top_k: args.top_k
|
|
4704
|
-
});
|
|
4705
|
-
return { results: formatCanonicalMemoryResults(broad), rescue_mode: formatCanonicalMemoryResults(broad).length > 0 ? "project_broad" : null };
|
|
4706
|
-
}
|
|
4707
|
-
function renderContextQueryMemoryRescue(args) {
|
|
4708
|
-
const lines = args.results.map(
|
|
4709
|
-
(result, index) => `${index + 1}. [${result.memory_type || "memory"}, score: ${result.similarity ?? "n/a"}] ${result.content}`
|
|
4710
|
-
);
|
|
4711
|
-
const scopeLabel = args.rescue_mode === "project_broad" ? `project=${args.project}, project_broad_memory_rescue=true` : `project=${args.project}, user=${args.scope.userId}, session=${args.scope.sessionId}, scoped_memory_rescue=true`;
|
|
4712
|
-
return `Found ${args.results.length} memory result(s) (${scopeLabel}):
|
|
4713
|
-
|
|
4714
|
-
${lines.join("\n\n")}`;
|
|
4715
|
-
}
|
|
4716
5301
|
function likelyEmbeddingFailure(error) {
|
|
4717
5302
|
const message = String(error?.message || error || "").toLowerCase();
|
|
4718
5303
|
return message.includes("embedding") || message.includes("vector") || message.includes("timeout") || message.includes("timed out") || message.includes("temporarily unavailable");
|
|
@@ -4733,7 +5318,13 @@ async function queryWithDegradedFallback(params) {
|
|
|
4733
5318
|
hybrid: true,
|
|
4734
5319
|
rerank: true
|
|
4735
5320
|
});
|
|
4736
|
-
return {
|
|
5321
|
+
return {
|
|
5322
|
+
response,
|
|
5323
|
+
degraded_mode: false,
|
|
5324
|
+
semantic_status: "ok",
|
|
5325
|
+
fallback_mode: "none",
|
|
5326
|
+
recommended_fixes: []
|
|
5327
|
+
};
|
|
4737
5328
|
} catch (error) {
|
|
4738
5329
|
if (!likelyEmbeddingFailure(error)) throw error;
|
|
4739
5330
|
const response = await whisper.query({
|
|
@@ -4756,7 +5347,13 @@ async function queryWithDegradedFallback(params) {
|
|
|
4756
5347
|
response,
|
|
4757
5348
|
degraded_mode: true,
|
|
4758
5349
|
degraded_reason: "Embedding/graph path unavailable; lexical fallback used.",
|
|
4759
|
-
recommendation: "Check embedding service health, then re-run for full hybrid quality."
|
|
5350
|
+
recommendation: "Check embedding service health, then re-run for full hybrid quality.",
|
|
5351
|
+
semantic_status: "failed",
|
|
5352
|
+
fallback_mode: "lexical_backend",
|
|
5353
|
+
recommended_fixes: [
|
|
5354
|
+
"Run fix to auto-repair retrieval health.",
|
|
5355
|
+
"If this persists, re-authenticate and reindex workspace sources."
|
|
5356
|
+
]
|
|
4760
5357
|
};
|
|
4761
5358
|
}
|
|
4762
5359
|
}
|
|
@@ -4868,6 +5465,47 @@ async function runSearchCodeSearch(args) {
|
|
|
4868
5465
|
fallback_reason: lexicalResults.length ? "Semantic ranking returned no matches; lexical rescue over local file paths and content was used." : "Semantic ranking returned no matches and lexical rescue found no strong candidates."
|
|
4869
5466
|
};
|
|
4870
5467
|
}
|
|
5468
|
+
function retrievalReadinessLabel(readiness) {
|
|
5469
|
+
if (readiness === "project_repo_source_ready") return "Project retrieval is healthy.";
|
|
5470
|
+
if (readiness === "project_repo_source_stale") return "Project source exists but is not ready.";
|
|
5471
|
+
if (readiness === "project_bound_no_repo_source") return "No matching project source is connected.";
|
|
5472
|
+
if (readiness === "project_unverified") return "Project/source verification failed.";
|
|
5473
|
+
if (readiness === "local_fallback") return "Using local fallback retrieval.";
|
|
5474
|
+
if (readiness === "no_project") return "No project is bound to this workspace.";
|
|
5475
|
+
return "Retrieval readiness is unknown.";
|
|
5476
|
+
}
|
|
5477
|
+
function retrievalReadinessAction(readiness) {
|
|
5478
|
+
if (readiness === "project_repo_source_ready") return "none";
|
|
5479
|
+
if (readiness === "project_repo_source_stale") return "Run fix or index.workspace_run to refresh workspace trust.";
|
|
5480
|
+
if (readiness === "project_bound_no_repo_source") {
|
|
5481
|
+
return RUNTIME_MODE === "remote" ? "Connect a repo source with context.add_source, then run fix." : "Run index.local_scan_ingest or fix.";
|
|
5482
|
+
}
|
|
5483
|
+
if (readiness === "project_unverified") return "Re-authenticate your API key and run fix.";
|
|
5484
|
+
if (readiness === "local_fallback") return "Run fix to restore project-grounded retrieval.";
|
|
5485
|
+
if (readiness === "no_project") return "Provide --project/WHISPER_PROJECT and run fix.";
|
|
5486
|
+
return "Run fix.";
|
|
5487
|
+
}
|
|
5488
|
+
function buildRecommendedFixes(args) {
|
|
5489
|
+
const fixes = /* @__PURE__ */ new Set();
|
|
5490
|
+
if (args.semantic_status === "failed") {
|
|
5491
|
+
fixes.add("Run fix to auto-repair retrieval health.");
|
|
5492
|
+
}
|
|
5493
|
+
if (args.fallback_mode === "lexical_rescue" || args.fallback_mode === "lexical_backend") {
|
|
5494
|
+
fixes.add("Check embedding/vector service health and retry.");
|
|
5495
|
+
}
|
|
5496
|
+
if (args.retrieval_readiness === "project_bound_no_repo_source") {
|
|
5497
|
+
fixes.add(
|
|
5498
|
+
RUNTIME_MODE === "remote" ? "Add a matching source with context.add_source." : "Ingest local files with index.local_scan_ingest."
|
|
5499
|
+
);
|
|
5500
|
+
}
|
|
5501
|
+
if (args.retrieval_readiness === "project_unverified") {
|
|
5502
|
+
fixes.add("Re-authenticate (valid WHISPER_API_KEY) and rerun fix.");
|
|
5503
|
+
}
|
|
5504
|
+
if (args.retrieval_readiness === "project_repo_source_stale") {
|
|
5505
|
+
fixes.add("Refresh workspace metadata via index.workspace_run.");
|
|
5506
|
+
}
|
|
5507
|
+
return [...fixes];
|
|
5508
|
+
}
|
|
4871
5509
|
function buildLocalWorkspaceDocuments(rootPath, allowedExts, maxFiles) {
|
|
4872
5510
|
const files = collectCodeFiles(rootPath, allowedExts, maxFiles);
|
|
4873
5511
|
const documents = [];
|
|
@@ -5003,20 +5641,6 @@ function localHitsToEvidence(workspaceId, hits) {
|
|
|
5003
5641
|
)
|
|
5004
5642
|
);
|
|
5005
5643
|
}
|
|
5006
|
-
function renderLocalWorkspaceContext(args) {
|
|
5007
|
-
const lines = args.hits.map((hit, index) => {
|
|
5008
|
-
const location = hit.line_end && hit.line_end !== hit.line_start ? `${hit.id}:${hit.line_start}-${hit.line_end}` : `${hit.id}:${hit.line_start}`;
|
|
5009
|
-
return `${index + 1}. [${location}, score: ${hit.score.toFixed(2)}, mode: ${hit.search_mode}] ${hit.raw_snippet || hit.snippet || hit.id}`;
|
|
5010
|
-
});
|
|
5011
|
-
const header = `Found ${args.hits.length} local workspace result(s) (route=${args.route}, workspace=${args.diagnostics.workspace_id}, project=${args.project_ref || "none"}, user=${args.scope.userId}, session=${args.scope.sessionId}):`;
|
|
5012
|
-
const warnings = args.warnings.length ? `
|
|
5013
|
-
|
|
5014
|
-
[warnings]
|
|
5015
|
-
${args.warnings.join("\n")}` : "";
|
|
5016
|
-
return `${header}
|
|
5017
|
-
|
|
5018
|
-
${lines.join("\n\n")}${warnings}`;
|
|
5019
|
-
}
|
|
5020
5644
|
async function runSearchCodeTool(args) {
|
|
5021
5645
|
const rootPath = canonicalizeWorkspacePath(args.path);
|
|
5022
5646
|
const allowedExts = args.file_types ? new Set(args.file_types) : CODE_EXTENSIONS;
|
|
@@ -5024,12 +5648,21 @@ async function runSearchCodeTool(args) {
|
|
|
5024
5648
|
if (files.length === 0) {
|
|
5025
5649
|
const workspace = await resolveWorkspaceTrust({ path: rootPath });
|
|
5026
5650
|
const sharedWarnings = [...workspace.warnings];
|
|
5651
|
+
const semanticStatus = "ok";
|
|
5652
|
+
const fallbackMode = "none";
|
|
5027
5653
|
return {
|
|
5028
5654
|
tool: "search_code",
|
|
5029
5655
|
query: args.query,
|
|
5030
5656
|
path: rootPath,
|
|
5031
5657
|
results: [],
|
|
5032
5658
|
count: 0,
|
|
5659
|
+
semantic_status: semanticStatus,
|
|
5660
|
+
fallback_mode: fallbackMode,
|
|
5661
|
+
recommended_fixes: buildRecommendedFixes({
|
|
5662
|
+
retrieval_readiness: workspace.project_ref ? "project_repo_source_ready" : "no_project",
|
|
5663
|
+
semantic_status: semanticStatus,
|
|
5664
|
+
fallback_mode: fallbackMode
|
|
5665
|
+
}),
|
|
5033
5666
|
warnings: sharedWarnings,
|
|
5034
5667
|
diagnostics: {
|
|
5035
5668
|
workspace_id: workspace.workspace_id,
|
|
@@ -5058,6 +5691,13 @@ async function runSearchCodeTool(args) {
|
|
|
5058
5691
|
path: rootPath,
|
|
5059
5692
|
results: localRetrieval.results,
|
|
5060
5693
|
count: localRetrieval.results.length,
|
|
5694
|
+
semantic_status: semanticStatusFromSearchMode(localRetrieval.diagnostics.search_mode),
|
|
5695
|
+
fallback_mode: fallbackModeFromSearchMode(localRetrieval.diagnostics.search_mode),
|
|
5696
|
+
recommended_fixes: buildRecommendedFixes({
|
|
5697
|
+
retrieval_readiness: localRetrieval.workspace.project_ref ? "local_fallback" : "no_project",
|
|
5698
|
+
semantic_status: semanticStatusFromSearchMode(localRetrieval.diagnostics.search_mode),
|
|
5699
|
+
fallback_mode: fallbackModeFromSearchMode(localRetrieval.diagnostics.search_mode)
|
|
5700
|
+
}),
|
|
5061
5701
|
warnings: localRetrieval.warnings,
|
|
5062
5702
|
diagnostics: localRetrieval.diagnostics
|
|
5063
5703
|
};
|
|
@@ -5109,7 +5749,9 @@ function saveIngestManifest(manifest) {
|
|
|
5109
5749
|
}
|
|
5110
5750
|
async function ingestLocalPath(params) {
|
|
5111
5751
|
if (RUNTIME_MODE === "remote") {
|
|
5112
|
-
throw new Error(
|
|
5752
|
+
throw new Error(
|
|
5753
|
+
"Local ingestion is disabled in remote mode. Use context.add_source for remote projects, or run MCP with WHISPER_MCP_MODE=auto/local."
|
|
5754
|
+
);
|
|
5113
5755
|
}
|
|
5114
5756
|
const rootPath = params.path || process.cwd();
|
|
5115
5757
|
const gate = isPathAllowed(rootPath);
|
|
@@ -5309,7 +5951,8 @@ function renderScopedMcpConfig(project, source, client) {
|
|
|
5309
5951
|
env: {
|
|
5310
5952
|
WHISPER_API_KEY: "wctx_...",
|
|
5311
5953
|
WHISPER_PROJECT: project,
|
|
5312
|
-
WHISPER_SCOPE_SOURCE: source
|
|
5954
|
+
WHISPER_SCOPE_SOURCE: source,
|
|
5955
|
+
WHISPER_MCP_MODE: "auto"
|
|
5313
5956
|
}
|
|
5314
5957
|
};
|
|
5315
5958
|
if (client === "json") {
|
|
@@ -5389,7 +6032,7 @@ server.tool(
|
|
|
5389
6032
|
warnings: Array.from(/* @__PURE__ */ new Set([...trust.warnings, ...repoVerification.warnings])),
|
|
5390
6033
|
recommended_next_calls: sanitizeRecommendedNextCalls([
|
|
5391
6034
|
...trust.recommended_next_calls,
|
|
5392
|
-
...repoVerification.retrieval_readiness
|
|
6035
|
+
...getRepoReadinessNextCalls(repoVerification.retrieval_readiness)
|
|
5393
6036
|
]),
|
|
5394
6037
|
freshness: trust.freshness,
|
|
5395
6038
|
coverage: trust.coverage,
|
|
@@ -5406,7 +6049,7 @@ server.tool(
|
|
|
5406
6049
|
);
|
|
5407
6050
|
server.tool(
|
|
5408
6051
|
"index.workspace_run",
|
|
5409
|
-
"
|
|
6052
|
+
"Refresh local workspace index metadata (coverage, commit, freshness) for trust checks. This does not upload files or create backend embeddings.",
|
|
5410
6053
|
{
|
|
5411
6054
|
workspace_id: z.string().optional(),
|
|
5412
6055
|
path: z.string().optional(),
|
|
@@ -5415,6 +6058,7 @@ server.tool(
|
|
|
5415
6058
|
},
|
|
5416
6059
|
async ({ workspace_id, path, mode, max_files }) => {
|
|
5417
6060
|
try {
|
|
6061
|
+
const startAt = Date.now();
|
|
5418
6062
|
const identity = resolveWorkspaceIdentity({ path, workspace_id });
|
|
5419
6063
|
const rootPath = identity.root_path;
|
|
5420
6064
|
const workspaceId = identity.workspace_id;
|
|
@@ -5423,11 +6067,17 @@ server.tool(
|
|
|
5423
6067
|
const fileStats = countCodeFiles(rootPath, max_files);
|
|
5424
6068
|
const coverage = Math.max(0, Math.min(1, fileStats.total / Math.max(1, max_files)));
|
|
5425
6069
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6070
|
+
const snapshot = computeWorkspaceSnapshot(rootPath);
|
|
5426
6071
|
workspace.root_path = rootPath;
|
|
5427
6072
|
workspace.index_metadata = {
|
|
5428
6073
|
last_indexed_at: now,
|
|
5429
6074
|
last_indexed_commit: getGitHead(rootPath),
|
|
5430
|
-
coverage: mode === "full" ? 1 : coverage
|
|
6075
|
+
coverage: mode === "full" ? 1 : coverage,
|
|
6076
|
+
indexed_files: fileStats.total,
|
|
6077
|
+
last_auto_refresh_at: now,
|
|
6078
|
+
...mode === "full" ? { last_full_refresh_at: now } : {},
|
|
6079
|
+
last_snapshot_hash: snapshot.hash,
|
|
6080
|
+
last_snapshot_entries: snapshot.entries
|
|
5431
6081
|
};
|
|
5432
6082
|
saveState(state);
|
|
5433
6083
|
const payload = {
|
|
@@ -5436,7 +6086,7 @@ server.tool(
|
|
|
5436
6086
|
mode,
|
|
5437
6087
|
indexed_files: fileStats.total,
|
|
5438
6088
|
skipped_files: fileStats.skipped,
|
|
5439
|
-
duration_ms:
|
|
6089
|
+
duration_ms: Date.now() - startAt,
|
|
5440
6090
|
warnings: fileStats.total === 0 ? ["No code files discovered for indexing."] : [],
|
|
5441
6091
|
index_metadata: workspace.index_metadata
|
|
5442
6092
|
};
|
|
@@ -5448,7 +6098,7 @@ server.tool(
|
|
|
5448
6098
|
);
|
|
5449
6099
|
server.tool(
|
|
5450
6100
|
"index.local_scan_ingest",
|
|
5451
|
-
"
|
|
6101
|
+
"Ingest local files into Whisper backend (chunk/embed/index) and persist incremental manifest. Requires WHISPER_MCP_MODE=auto or local.",
|
|
5452
6102
|
{
|
|
5453
6103
|
project: z.string().optional().describe("Project name or slug"),
|
|
5454
6104
|
path: z.string().optional().describe("Local path to ingest. Defaults to current working directory."),
|
|
@@ -5482,9 +6132,264 @@ server.tool(
|
|
|
5482
6132
|
}
|
|
5483
6133
|
}
|
|
5484
6134
|
);
|
|
6135
|
+
server.tool(
|
|
6136
|
+
"index.auto_repair",
|
|
6137
|
+
"Diagnose and apply deterministic retrieval/setup repairs. This is the canonical zero-stress repair path.",
|
|
6138
|
+
{
|
|
6139
|
+
path: z.string().optional(),
|
|
6140
|
+
workspace_id: z.string().optional(),
|
|
6141
|
+
project: z.string().optional(),
|
|
6142
|
+
apply: z.boolean().optional().default(true),
|
|
6143
|
+
repair_scope: z.enum(["safe", "full"]).optional().default("safe"),
|
|
6144
|
+
allow_restart_hint: z.boolean().optional().default(true)
|
|
6145
|
+
},
|
|
6146
|
+
async ({ path, workspace_id, project, apply, repair_scope, allow_restart_hint }) => {
|
|
6147
|
+
try {
|
|
6148
|
+
const payload = await runAutoRepairFlow({
|
|
6149
|
+
path,
|
|
6150
|
+
workspace_id,
|
|
6151
|
+
project,
|
|
6152
|
+
apply,
|
|
6153
|
+
repair_scope,
|
|
6154
|
+
allow_restart_hint
|
|
6155
|
+
});
|
|
6156
|
+
return toTextResult(payload);
|
|
6157
|
+
} catch (error) {
|
|
6158
|
+
return primaryToolError(error.message, "auto_repair_failed");
|
|
6159
|
+
}
|
|
6160
|
+
}
|
|
6161
|
+
);
|
|
6162
|
+
server.tool(
|
|
6163
|
+
"fix",
|
|
6164
|
+
"Primary alias for zero-stress setup/retrieval repair. Delegates to index.auto_repair.",
|
|
6165
|
+
{
|
|
6166
|
+
path: z.string().optional(),
|
|
6167
|
+
workspace_id: z.string().optional(),
|
|
6168
|
+
project: z.string().optional(),
|
|
6169
|
+
apply: z.boolean().optional().default(true),
|
|
6170
|
+
repair_scope: z.enum(["safe", "full"]).optional().default("safe"),
|
|
6171
|
+
allow_restart_hint: z.boolean().optional().default(true)
|
|
6172
|
+
},
|
|
6173
|
+
async ({ path, workspace_id, project, apply, repair_scope, allow_restart_hint }) => {
|
|
6174
|
+
try {
|
|
6175
|
+
const payload = await runAutoRepairFlow({
|
|
6176
|
+
path,
|
|
6177
|
+
workspace_id,
|
|
6178
|
+
project,
|
|
6179
|
+
apply,
|
|
6180
|
+
repair_scope,
|
|
6181
|
+
allow_restart_hint
|
|
6182
|
+
});
|
|
6183
|
+
return toTextResult(payload);
|
|
6184
|
+
} catch (error) {
|
|
6185
|
+
return primaryToolError(error.message, "fix_failed");
|
|
6186
|
+
}
|
|
6187
|
+
}
|
|
6188
|
+
);
|
|
6189
|
+
async function runUnifiedContextRetrieval(params) {
|
|
6190
|
+
const preflight = await resolveRepoGroundingPreflight({
|
|
6191
|
+
query: params.question,
|
|
6192
|
+
path: params.path,
|
|
6193
|
+
workspace_id: params.workspace_id,
|
|
6194
|
+
project: params.project,
|
|
6195
|
+
chunk_types: params.chunk_types
|
|
6196
|
+
});
|
|
6197
|
+
const retrievalProfile = resolveMcpRetrievalProfile(params.retrieval_profile);
|
|
6198
|
+
const backgroundRefresh = await runBackgroundWorkspaceRefresh({
|
|
6199
|
+
workspace_id: preflight.trust_state.workspace_id,
|
|
6200
|
+
root_path: preflight.trust_state.root_path,
|
|
6201
|
+
force_full: false
|
|
6202
|
+
});
|
|
6203
|
+
if (shouldAbstainForCodebaseTrust({
|
|
6204
|
+
retrievalProfile,
|
|
6205
|
+
codebaseIntent: preflight.repo_grounded,
|
|
6206
|
+
preflight
|
|
6207
|
+
})) {
|
|
6208
|
+
const abstainPayload = buildCodebaseTrustAbstainPayload({
|
|
6209
|
+
query: params.question,
|
|
6210
|
+
preflight,
|
|
6211
|
+
retrievalProfile
|
|
6212
|
+
});
|
|
6213
|
+
return {
|
|
6214
|
+
...abstainPayload,
|
|
6215
|
+
semantic_status: "failed",
|
|
6216
|
+
fallback_mode: "none",
|
|
6217
|
+
recommended_fixes: buildRecommendedFixes({
|
|
6218
|
+
retrieval_readiness: preflight.retrieval_readiness,
|
|
6219
|
+
semantic_status: "failed",
|
|
6220
|
+
fallback_mode: "none"
|
|
6221
|
+
}),
|
|
6222
|
+
status_label: "blocked",
|
|
6223
|
+
status_action: "reindex",
|
|
6224
|
+
action_required: true,
|
|
6225
|
+
diagnostics: {
|
|
6226
|
+
retrieval_profile: retrievalProfile,
|
|
6227
|
+
background_refresh: backgroundRefresh
|
|
6228
|
+
}
|
|
6229
|
+
};
|
|
6230
|
+
}
|
|
6231
|
+
const resolvedProject = preflight.trust_state.project_ref || await resolveProjectRef(params.project);
|
|
6232
|
+
const scope = resolveMcpScope({
|
|
6233
|
+
project: resolvedProject || params.project,
|
|
6234
|
+
user_id: params.user_id,
|
|
6235
|
+
session_id: params.session_id,
|
|
6236
|
+
path: preflight.trust_state.root_path
|
|
6237
|
+
});
|
|
6238
|
+
const topK = params.top_k ?? 12;
|
|
6239
|
+
let semanticStatus = "ok";
|
|
6240
|
+
let fallbackMode = "none";
|
|
6241
|
+
let contextText = "";
|
|
6242
|
+
let evidence = [];
|
|
6243
|
+
let warnings = [...preflight.warnings];
|
|
6244
|
+
let retrievalReadiness = preflight.retrieval_readiness;
|
|
6245
|
+
let retrievalRoute = preflight.retrieval_route;
|
|
6246
|
+
let latencyMs = 0;
|
|
6247
|
+
if (preflight.retrieval_route === "local_workspace_fallback") {
|
|
6248
|
+
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
6249
|
+
query: params.question,
|
|
6250
|
+
path: preflight.trust_state.root_path,
|
|
6251
|
+
project: resolvedProject || params.project,
|
|
6252
|
+
top_k: topK
|
|
6253
|
+
});
|
|
6254
|
+
semanticStatus = semanticStatusFromSearchMode(localRetrieval.diagnostics.search_mode);
|
|
6255
|
+
fallbackMode = fallbackModeFromSearchMode(localRetrieval.diagnostics.search_mode);
|
|
6256
|
+
evidence = localHitsToEvidence(preflight.trust_state.workspace_id, localRetrieval.results);
|
|
6257
|
+
contextText = evidence.map((item) => `[${renderCitation(item)}] ${item.snippet || "Relevant context found."}`).join("\n");
|
|
6258
|
+
warnings = Array.from(/* @__PURE__ */ new Set([...warnings, ...localRetrieval.warnings]));
|
|
6259
|
+
retrievalReadiness = "local_fallback";
|
|
6260
|
+
retrievalRoute = "local_workspace_fallback";
|
|
6261
|
+
} else if (!resolvedProject) {
|
|
6262
|
+
contextText = "";
|
|
6263
|
+
evidence = [];
|
|
6264
|
+
retrievalRoute = "none";
|
|
6265
|
+
} else {
|
|
6266
|
+
const queryResult = await queryWithDegradedFallback({
|
|
6267
|
+
project: resolvedProject,
|
|
6268
|
+
query: params.question,
|
|
6269
|
+
top_k: topK,
|
|
6270
|
+
include_memories: preflight.repo_grounded ? false : params.include_memories,
|
|
6271
|
+
include_graph: params.include_graph,
|
|
6272
|
+
session_id: params.session_id,
|
|
6273
|
+
user_id: scope.userId,
|
|
6274
|
+
source_ids: preflight.repo_grounded ? preflight.matched_source_ids : void 0,
|
|
6275
|
+
retrieval_profile: retrievalProfile,
|
|
6276
|
+
include_parent_content: params.include_parent_content
|
|
6277
|
+
});
|
|
6278
|
+
latencyMs = queryResult.response.meta?.latency_ms || 0;
|
|
6279
|
+
semanticStatus = queryResult.semantic_status || "ok";
|
|
6280
|
+
fallbackMode = queryResult.fallback_mode || "none";
|
|
6281
|
+
const rawResults = preflight.repo_grounded ? filterProjectRepoResults(queryResult.response.results || [], preflight.matched_source_ids) : queryResult.response.results || [];
|
|
6282
|
+
if (preflight.repo_grounded && rawResults.length === 0) {
|
|
6283
|
+
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
6284
|
+
query: params.question,
|
|
6285
|
+
path: preflight.trust_state.root_path,
|
|
6286
|
+
project: resolvedProject,
|
|
6287
|
+
top_k: topK
|
|
6288
|
+
});
|
|
6289
|
+
semanticStatus = semanticStatusFromSearchMode(localRetrieval.diagnostics.search_mode);
|
|
6290
|
+
fallbackMode = fallbackModeFromSearchMode(localRetrieval.diagnostics.search_mode);
|
|
6291
|
+
evidence = localHitsToEvidence(preflight.trust_state.workspace_id, localRetrieval.results);
|
|
6292
|
+
contextText = evidence.map((item) => `[${renderCitation(item)}] ${item.snippet || "Relevant context found."}`).join("\n");
|
|
6293
|
+
warnings = Array.from(/* @__PURE__ */ new Set([...warnings, ...localRetrieval.warnings]));
|
|
6294
|
+
retrievalReadiness = "local_fallback";
|
|
6295
|
+
retrievalRoute = "local_workspace_fallback";
|
|
6296
|
+
} else {
|
|
6297
|
+
contextText = queryResult.response.context || "";
|
|
6298
|
+
evidence = rawResults.map((r) => toEvidenceRef(r, preflight.trust_state.workspace_id, "semantic"));
|
|
6299
|
+
if (queryResult.degraded_mode) {
|
|
6300
|
+
warnings.push(queryResult.degraded_reason || "Lexical backend fallback active.");
|
|
6301
|
+
}
|
|
6302
|
+
retrievalRoute = preflight.repo_grounded ? "project_repo" : "none";
|
|
6303
|
+
}
|
|
6304
|
+
}
|
|
6305
|
+
recordSemanticAttempt(preflight.trust_state.workspace_id, semanticStatus === "failed");
|
|
6306
|
+
const semanticStats = getWorkspaceSemanticFailureStats(preflight.trust_state.workspace_id);
|
|
6307
|
+
const trustScore = computeTrustScore({
|
|
6308
|
+
retrieval_readiness: retrievalReadiness,
|
|
6309
|
+
workspace_health: preflight.trust_state.health,
|
|
6310
|
+
semantic_failure_rate: semanticStats.rate
|
|
6311
|
+
});
|
|
6312
|
+
persistTrustScore(preflight.trust_state.workspace_id, trustScore);
|
|
6313
|
+
const autoHeal = shouldAutoHeal({
|
|
6314
|
+
retrieval_readiness: retrievalReadiness,
|
|
6315
|
+
trust_score: trustScore,
|
|
6316
|
+
semantic_failure_rate: semanticStats.rate,
|
|
6317
|
+
semantic_attempts: semanticStats.attempts
|
|
6318
|
+
});
|
|
6319
|
+
let autoRepairSummary = null;
|
|
6320
|
+
if (autoHeal) {
|
|
6321
|
+
try {
|
|
6322
|
+
autoRepairSummary = await runAutoRepairFlow({
|
|
6323
|
+
path: preflight.trust_state.root_path,
|
|
6324
|
+
workspace_id: preflight.trust_state.workspace_id,
|
|
6325
|
+
project: resolvedProject || params.project,
|
|
6326
|
+
apply: true,
|
|
6327
|
+
repair_scope: "safe",
|
|
6328
|
+
allow_restart_hint: true
|
|
6329
|
+
});
|
|
6330
|
+
warnings.push("Auto-repair executed in safe mode.");
|
|
6331
|
+
} catch (error) {
|
|
6332
|
+
warnings.push(`Auto-repair failed: ${String(error?.message || error)}`);
|
|
6333
|
+
}
|
|
6334
|
+
}
|
|
6335
|
+
const statusContract = statusContractForReadiness({
|
|
6336
|
+
retrieval_readiness: retrievalReadiness,
|
|
6337
|
+
workspace_health: preflight.trust_state.health,
|
|
6338
|
+
semantic_status: semanticStatus,
|
|
6339
|
+
force_repairing: autoHeal
|
|
6340
|
+
});
|
|
6341
|
+
const recommendedFixes = buildRecommendedFixes({
|
|
6342
|
+
retrieval_readiness: retrievalReadiness,
|
|
6343
|
+
semantic_status: semanticStatus,
|
|
6344
|
+
fallback_mode: fallbackMode
|
|
6345
|
+
});
|
|
6346
|
+
const recommendedNextCalls = sanitizeRecommendedNextCalls([
|
|
6347
|
+
...preflight.recommended_next_calls,
|
|
6348
|
+
...semanticStatus === "failed" ? ["fix"] : []
|
|
6349
|
+
]);
|
|
6350
|
+
const payload = {
|
|
6351
|
+
question: params.question,
|
|
6352
|
+
workspace_id: preflight.trust_state.workspace_id,
|
|
6353
|
+
root_path: preflight.trust_state.root_path,
|
|
6354
|
+
trust_state: preflight.trust_state,
|
|
6355
|
+
retrieval_readiness: retrievalReadiness,
|
|
6356
|
+
retrieval_readiness_label: retrievalReadinessLabel(retrievalReadiness),
|
|
6357
|
+
retrieval_readiness_action: retrievalReadinessAction(retrievalReadiness),
|
|
6358
|
+
retrieval_route: retrievalRoute,
|
|
6359
|
+
context: contextText,
|
|
6360
|
+
evidence,
|
|
6361
|
+
total_results: evidence.length,
|
|
6362
|
+
latency_ms: latencyMs,
|
|
6363
|
+
semantic_status: semanticStatus,
|
|
6364
|
+
fallback_mode: fallbackMode,
|
|
6365
|
+
recommended_fixes: recommendedFixes,
|
|
6366
|
+
status_label: statusContract.status_label,
|
|
6367
|
+
status_action: statusContract.status_action,
|
|
6368
|
+
action_required: statusContract.action_required,
|
|
6369
|
+
warnings: Array.from(new Set(warnings)),
|
|
6370
|
+
recommended_next_calls: recommendedNextCalls,
|
|
6371
|
+
diagnostics: {
|
|
6372
|
+
scope: {
|
|
6373
|
+
project: resolvedProject || params.project || null,
|
|
6374
|
+
user_id: scope.userId,
|
|
6375
|
+
session_id: params.session_id || null
|
|
6376
|
+
},
|
|
6377
|
+
retrieval_profile: retrievalProfile,
|
|
6378
|
+
trust_score: trustScore,
|
|
6379
|
+
semantic_failure_rate: semanticStats.rate,
|
|
6380
|
+
auto_heal_triggered: autoHeal,
|
|
6381
|
+
auto_repair: autoRepairSummary,
|
|
6382
|
+
background_refresh: backgroundRefresh
|
|
6383
|
+
}
|
|
6384
|
+
};
|
|
6385
|
+
if (params.include_alias_warning) {
|
|
6386
|
+
payload.warnings = Array.from(/* @__PURE__ */ new Set([...payload.warnings, "deprecated_alias_use_context.query"]));
|
|
6387
|
+
}
|
|
6388
|
+
return payload;
|
|
6389
|
+
}
|
|
5485
6390
|
server.tool(
|
|
5486
6391
|
"context.get_relevant",
|
|
5487
|
-
"Default grounded retrieval step for workspace/project questions.
|
|
6392
|
+
"Default grounded retrieval step for workspace/project questions. Returns ranked evidence with file:line citations and may abstain when workspace/repo trust is not ready.",
|
|
5488
6393
|
{
|
|
5489
6394
|
question: z.string().describe("Task/question to retrieve context for"),
|
|
5490
6395
|
path: z.string().optional().describe("Workspace path. Defaults to current working directory."),
|
|
@@ -5500,131 +6405,23 @@ server.tool(
|
|
|
5500
6405
|
},
|
|
5501
6406
|
async ({ question, path, workspace_id, project, top_k, include_memories, include_graph, session_id, user_id, include_parent_content, retrieval_profile }) => {
|
|
5502
6407
|
try {
|
|
5503
|
-
const
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
preflight
|
|
5509
|
-
})) {
|
|
5510
|
-
return toTextResult(buildCodebaseTrustAbstainPayload({
|
|
5511
|
-
query: question,
|
|
5512
|
-
preflight,
|
|
5513
|
-
retrievalProfile
|
|
5514
|
-
}));
|
|
5515
|
-
}
|
|
5516
|
-
if (preflight.retrieval_route === "local_workspace_fallback") {
|
|
5517
|
-
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
5518
|
-
query: question,
|
|
5519
|
-
path: preflight.trust_state.root_path,
|
|
5520
|
-
project: preflight.trust_state.project_ref || project,
|
|
5521
|
-
top_k
|
|
5522
|
-
});
|
|
5523
|
-
const evidence2 = localHitsToEvidence(preflight.trust_state.workspace_id, localRetrieval.results);
|
|
5524
|
-
const payload2 = {
|
|
5525
|
-
question,
|
|
5526
|
-
workspace_id: preflight.trust_state.workspace_id,
|
|
5527
|
-
root_path: preflight.trust_state.root_path,
|
|
5528
|
-
identity_source: preflight.trust_state.identity_source,
|
|
5529
|
-
trust_state: preflight.trust_state,
|
|
5530
|
-
retrieval_readiness: preflight.retrieval_readiness,
|
|
5531
|
-
retrieval_route: preflight.retrieval_route,
|
|
5532
|
-
grounded_to_workspace: true,
|
|
5533
|
-
total_results: evidence2.length,
|
|
5534
|
-
context: evidence2.map((item) => `[${renderCitation(item)}] ${item.snippet || "Relevant local workspace context found."}`).join("\n"),
|
|
5535
|
-
evidence: evidence2,
|
|
5536
|
-
used_context_ids: evidence2.map((item) => item.source_id),
|
|
5537
|
-
latency_ms: 0,
|
|
5538
|
-
warnings: Array.from(/* @__PURE__ */ new Set([...preflight.warnings, ...localRetrieval.warnings])),
|
|
5539
|
-
recommended_next_calls: preflight.recommended_next_calls
|
|
5540
|
-
};
|
|
5541
|
-
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
5542
|
-
}
|
|
5543
|
-
if (!preflight.trust_state.project_ref) {
|
|
5544
|
-
const payload2 = {
|
|
5545
|
-
question,
|
|
5546
|
-
workspace_id: preflight.trust_state.workspace_id,
|
|
5547
|
-
root_path: preflight.trust_state.root_path,
|
|
5548
|
-
identity_source: preflight.trust_state.identity_source,
|
|
5549
|
-
trust_state: preflight.trust_state,
|
|
5550
|
-
retrieval_readiness: preflight.retrieval_readiness,
|
|
5551
|
-
retrieval_route: "none",
|
|
5552
|
-
grounded_to_workspace: false,
|
|
5553
|
-
total_results: 0,
|
|
5554
|
-
context: "",
|
|
5555
|
-
evidence: [],
|
|
5556
|
-
used_context_ids: [],
|
|
5557
|
-
latency_ms: 0,
|
|
5558
|
-
warnings: preflight.warnings,
|
|
5559
|
-
recommended_next_calls: preflight.recommended_next_calls
|
|
5560
|
-
};
|
|
5561
|
-
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
5562
|
-
}
|
|
5563
|
-
const queryResult = await queryWithDegradedFallback({
|
|
5564
|
-
project: preflight.trust_state.project_ref,
|
|
5565
|
-
query: question,
|
|
6408
|
+
const payload = await runUnifiedContextRetrieval({
|
|
6409
|
+
question,
|
|
6410
|
+
path,
|
|
6411
|
+
workspace_id,
|
|
6412
|
+
project,
|
|
5566
6413
|
top_k,
|
|
5567
|
-
include_memories
|
|
6414
|
+
include_memories,
|
|
5568
6415
|
include_graph,
|
|
5569
6416
|
session_id,
|
|
5570
6417
|
user_id,
|
|
5571
|
-
|
|
5572
|
-
retrieval_profile
|
|
5573
|
-
|
|
6418
|
+
include_parent_content,
|
|
6419
|
+
retrieval_profile,
|
|
6420
|
+
include_alias_warning: true
|
|
5574
6421
|
});
|
|
5575
|
-
|
|
5576
|
-
const rawResults = preflight.repo_grounded ? filterProjectRepoResults(response.results || [], preflight.matched_source_ids) : response.results || [];
|
|
5577
|
-
if (preflight.repo_grounded && rawResults.length === 0) {
|
|
5578
|
-
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
5579
|
-
query: question,
|
|
5580
|
-
path: preflight.trust_state.root_path,
|
|
5581
|
-
project: preflight.trust_state.project_ref,
|
|
5582
|
-
top_k
|
|
5583
|
-
});
|
|
5584
|
-
const evidence2 = localHitsToEvidence(preflight.trust_state.workspace_id, localRetrieval.results);
|
|
5585
|
-
const payload2 = {
|
|
5586
|
-
question,
|
|
5587
|
-
workspace_id: preflight.trust_state.workspace_id,
|
|
5588
|
-
root_path: preflight.trust_state.root_path,
|
|
5589
|
-
identity_source: preflight.trust_state.identity_source,
|
|
5590
|
-
trust_state: preflight.trust_state,
|
|
5591
|
-
retrieval_readiness: "local_fallback",
|
|
5592
|
-
retrieval_route: "local_workspace_fallback",
|
|
5593
|
-
grounded_to_workspace: true,
|
|
5594
|
-
total_results: evidence2.length,
|
|
5595
|
-
context: evidence2.map((item) => `[${renderCitation(item)}] ${item.snippet || "Relevant local workspace context found."}`).join("\n"),
|
|
5596
|
-
evidence: evidence2,
|
|
5597
|
-
used_context_ids: evidence2.map((item) => item.source_id),
|
|
5598
|
-
latency_ms: 0,
|
|
5599
|
-
warnings: Array.from(/* @__PURE__ */ new Set([...preflight.warnings, ...localRetrieval.warnings])),
|
|
5600
|
-
recommended_next_calls: preflight.recommended_next_calls
|
|
5601
|
-
};
|
|
5602
|
-
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
5603
|
-
}
|
|
5604
|
-
const evidence = rawResults.map((r) => toEvidenceRef(r, preflight.trust_state.workspace_id, "semantic"));
|
|
5605
|
-
const payload = {
|
|
5606
|
-
question,
|
|
5607
|
-
workspace_id: preflight.trust_state.workspace_id,
|
|
5608
|
-
root_path: preflight.trust_state.root_path,
|
|
5609
|
-
identity_source: preflight.trust_state.identity_source,
|
|
5610
|
-
trust_state: preflight.trust_state,
|
|
5611
|
-
retrieval_readiness: preflight.retrieval_readiness,
|
|
5612
|
-
retrieval_route: preflight.repo_grounded ? "project_repo" : "none",
|
|
5613
|
-
grounded_to_workspace: preflight.repo_grounded ? true : preflight.trust_state.grounded_to_workspace,
|
|
5614
|
-
total_results: rawResults.length || response.meta?.total || evidence.length,
|
|
5615
|
-
context: response.context || "",
|
|
5616
|
-
evidence,
|
|
5617
|
-
used_context_ids: rawResults.map((r) => String(r.id)),
|
|
5618
|
-
latency_ms: response.meta?.latency_ms || 0,
|
|
5619
|
-
degraded_mode: queryResult.degraded_mode,
|
|
5620
|
-
degraded_reason: queryResult.degraded_reason,
|
|
5621
|
-
recommendation: queryResult.recommendation,
|
|
5622
|
-
warnings: preflight.warnings,
|
|
5623
|
-
recommended_next_calls: preflight.recommended_next_calls
|
|
5624
|
-
};
|
|
5625
|
-
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
6422
|
+
return toTextResult(payload);
|
|
5626
6423
|
} catch (error) {
|
|
5627
|
-
return
|
|
6424
|
+
return primaryToolError(error.message, "context_get_relevant_failed");
|
|
5628
6425
|
}
|
|
5629
6426
|
}
|
|
5630
6427
|
);
|
|
@@ -5831,7 +6628,7 @@ server.tool(
|
|
|
5831
6628
|
);
|
|
5832
6629
|
server.tool(
|
|
5833
6630
|
"context.query",
|
|
5834
|
-
"Use this when answering from project knowledge rather than general model memory. Retrieves packed context
|
|
6631
|
+
"Use this when answering from project knowledge rather than general model memory. Retrieves packed context and auto-falls back between repo, local, and memory routes based on trust/readiness.",
|
|
5835
6632
|
{
|
|
5836
6633
|
project: z.string().optional().describe("Project name or slug (optional if WHISPER_PROJECT is set)"),
|
|
5837
6634
|
query: z.string().describe("What are you looking for?"),
|
|
@@ -5848,273 +6645,22 @@ server.tool(
|
|
|
5848
6645
|
},
|
|
5849
6646
|
async ({ project, query, path, top_k, chunk_types, include_memories, include_graph, user_id, session_id, max_tokens, include_parent_content, retrieval_profile }) => {
|
|
5850
6647
|
try {
|
|
5851
|
-
const
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
codebaseIntent: preflight.repo_grounded,
|
|
5856
|
-
preflight
|
|
5857
|
-
})) {
|
|
5858
|
-
return toTextResult(buildCodebaseTrustAbstainPayload({
|
|
5859
|
-
query,
|
|
5860
|
-
preflight,
|
|
5861
|
-
retrievalProfile
|
|
5862
|
-
}));
|
|
5863
|
-
}
|
|
5864
|
-
const resolvedProject = preflight.trust_state.project_ref || await resolveProjectRef(project);
|
|
5865
|
-
if (!resolvedProject && !preflight.repo_grounded) {
|
|
5866
|
-
return { content: [{ type: "text", text: "Error: No project resolved. Set WHISPER_PROJECT or pass project." }] };
|
|
5867
|
-
}
|
|
5868
|
-
const scope = resolveMcpScope({ project: resolvedProject, user_id, session_id, path: preflight.trust_state.root_path });
|
|
5869
|
-
if (preflight.repo_grounded && preflight.retrieval_route === "local_workspace_fallback") {
|
|
5870
|
-
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
5871
|
-
query,
|
|
5872
|
-
path: preflight.trust_state.root_path,
|
|
5873
|
-
project: resolvedProject || project,
|
|
5874
|
-
top_k
|
|
5875
|
-
});
|
|
5876
|
-
if (localRetrieval.results.length > 0) {
|
|
5877
|
-
return {
|
|
5878
|
-
content: [{
|
|
5879
|
-
type: "text",
|
|
5880
|
-
text: renderLocalWorkspaceContext({
|
|
5881
|
-
query,
|
|
5882
|
-
project_ref: resolvedProject || null,
|
|
5883
|
-
scope,
|
|
5884
|
-
route: "local_workspace_fallback",
|
|
5885
|
-
hits: localRetrieval.results,
|
|
5886
|
-
diagnostics: localRetrieval.diagnostics,
|
|
5887
|
-
warnings: Array.from(/* @__PURE__ */ new Set([...preflight.warnings, ...localRetrieval.warnings]))
|
|
5888
|
-
})
|
|
5889
|
-
}]
|
|
5890
|
-
};
|
|
5891
|
-
}
|
|
5892
|
-
}
|
|
5893
|
-
if (preflight.repo_grounded && resolvedProject) {
|
|
5894
|
-
const queryResult2 = await queryWithDegradedFallback({
|
|
5895
|
-
project: resolvedProject,
|
|
5896
|
-
query,
|
|
5897
|
-
top_k,
|
|
5898
|
-
include_memories: false,
|
|
5899
|
-
include_graph,
|
|
5900
|
-
user_id: user_id || scope.userId,
|
|
5901
|
-
session_id: session_id || scope.sessionId,
|
|
5902
|
-
source_ids: preflight.matched_source_ids,
|
|
5903
|
-
retrieval_profile: retrievalProfile,
|
|
5904
|
-
include_parent_content
|
|
5905
|
-
});
|
|
5906
|
-
const repoResults = filterProjectRepoResults(queryResult2.response.results || [], preflight.matched_source_ids);
|
|
5907
|
-
if (repoResults.length > 0) {
|
|
5908
|
-
const scopedResponse = { ...queryResult2.response, results: repoResults };
|
|
5909
|
-
const header2 = `Found ${repoResults.length} repo-grounded result(s) (${scopedResponse.meta.latency_ms}ms${scopedResponse.meta.cache_hit ? ", cached" : ""}, route=project_repo, workspace=${preflight.trust_state.workspace_id}, project=${resolvedProject}, user=${scope.userId}, session=${scope.sessionId}):
|
|
5910
|
-
|
|
5911
|
-
`;
|
|
5912
|
-
const suffix2 = [
|
|
5913
|
-
`[diagnostics] identity_source=${preflight.trust_state.identity_source} retrieval_readiness=${preflight.retrieval_readiness} retrieval_route=project_repo`,
|
|
5914
|
-
queryResult2.degraded_mode ? `[degraded_mode=true] ${queryResult2.degraded_reason}
|
|
5915
|
-
Recommendation: ${queryResult2.recommendation}` : "",
|
|
5916
|
-
preflight.warnings.length ? `[warnings]
|
|
5917
|
-
${preflight.warnings.join("\n")}` : ""
|
|
5918
|
-
].filter(Boolean).join("\n\n");
|
|
5919
|
-
return { content: [{ type: "text", text: `${header2}${scopedResponse.context}${suffix2 ? `
|
|
5920
|
-
|
|
5921
|
-
${suffix2}` : ""}` }] };
|
|
5922
|
-
}
|
|
5923
|
-
}
|
|
5924
|
-
if (preflight.repo_grounded) {
|
|
5925
|
-
if (resolvedProject && include_memories !== false) {
|
|
5926
|
-
const memoryRescue = await runContextQueryMemoryRescue({
|
|
5927
|
-
project: resolvedProject,
|
|
5928
|
-
query,
|
|
5929
|
-
user_id: user_id ? scope.userId : void 0,
|
|
5930
|
-
session_id: session_id ? scope.sessionId : void 0,
|
|
5931
|
-
top_k
|
|
5932
|
-
});
|
|
5933
|
-
if (memoryRescue.results.length && memoryRescue.rescue_mode) {
|
|
5934
|
-
return {
|
|
5935
|
-
content: [{
|
|
5936
|
-
type: "text",
|
|
5937
|
-
text: `${renderContextQueryMemoryRescue({
|
|
5938
|
-
project: resolvedProject,
|
|
5939
|
-
query,
|
|
5940
|
-
scope,
|
|
5941
|
-
results: memoryRescue.results,
|
|
5942
|
-
rescue_mode: memoryRescue.rescue_mode
|
|
5943
|
-
})}
|
|
5944
|
-
|
|
5945
|
-
[diagnostics]
|
|
5946
|
-
retrieval_route=memory_only retrieval_readiness=${preflight.retrieval_readiness} workspace=${preflight.trust_state.workspace_id}`
|
|
5947
|
-
}]
|
|
5948
|
-
};
|
|
5949
|
-
}
|
|
5950
|
-
}
|
|
5951
|
-
return {
|
|
5952
|
-
content: [{
|
|
5953
|
-
type: "text",
|
|
5954
|
-
text: `No relevant repo-grounded context found.
|
|
5955
|
-
|
|
5956
|
-
[diagnostics]
|
|
5957
|
-
workspace=${preflight.trust_state.workspace_id} identity_source=${preflight.trust_state.identity_source} retrieval_readiness=${preflight.retrieval_readiness} retrieval_route=${preflight.retrieval_route}`
|
|
5958
|
-
}]
|
|
5959
|
-
};
|
|
5960
|
-
}
|
|
5961
|
-
const automaticMode = !preflight.repo_grounded && include_memories !== false && include_graph !== true && !(chunk_types && chunk_types.length > 0) && max_tokens === void 0 && runtimeClient;
|
|
5962
|
-
if (automaticMode) {
|
|
5963
|
-
try {
|
|
5964
|
-
const prepared = await prepareAutomaticQuery({
|
|
5965
|
-
project: resolvedProject,
|
|
5966
|
-
query,
|
|
5967
|
-
top_k,
|
|
5968
|
-
user_id,
|
|
5969
|
-
session_id,
|
|
5970
|
-
path: preflight.trust_state.root_path
|
|
5971
|
-
});
|
|
5972
|
-
if (!prepared.items.length) {
|
|
5973
|
-
const memoryRescue = include_memories !== false ? await runContextQueryMemoryRescue({
|
|
5974
|
-
project: resolvedProject,
|
|
5975
|
-
query,
|
|
5976
|
-
user_id: user_id ? scope.userId : void 0,
|
|
5977
|
-
session_id: session_id ? scope.sessionId : void 0,
|
|
5978
|
-
top_k
|
|
5979
|
-
}) : { results: [], rescue_mode: null };
|
|
5980
|
-
if (memoryRescue.results.length && memoryRescue.rescue_mode) {
|
|
5981
|
-
return {
|
|
5982
|
-
content: [{
|
|
5983
|
-
type: "text",
|
|
5984
|
-
text: renderContextQueryMemoryRescue({
|
|
5985
|
-
project: resolvedProject,
|
|
5986
|
-
query,
|
|
5987
|
-
scope,
|
|
5988
|
-
results: memoryRescue.results,
|
|
5989
|
-
rescue_mode: memoryRescue.rescue_mode
|
|
5990
|
-
})
|
|
5991
|
-
}]
|
|
5992
|
-
};
|
|
5993
|
-
}
|
|
5994
|
-
return { content: [{ type: "text", text: "No relevant context found." }] };
|
|
5995
|
-
}
|
|
5996
|
-
const warnings = prepared.retrieval.warnings.length ? `
|
|
5997
|
-
|
|
5998
|
-
[automatic_runtime]
|
|
5999
|
-
${prepared.retrieval.warnings.join("\n")}` : "";
|
|
6000
|
-
const diagnostics = [
|
|
6001
|
-
`focused_scope=${prepared.retrieval.focusedScopeApplied}`,
|
|
6002
|
-
`fallback_used=${prepared.retrieval.fallbackUsed}`,
|
|
6003
|
-
`deduped=${prepared.retrieval.dedupedCount}`,
|
|
6004
|
-
`dropped_below_floor=${prepared.retrieval.droppedBelowFloor}`
|
|
6005
|
-
].join(" ");
|
|
6006
|
-
const scopeLabel = `project=${prepared.scope.project} user=${prepared.scope.userId} session=${prepared.scope.sessionId}`;
|
|
6007
|
-
return {
|
|
6008
|
-
content: [{
|
|
6009
|
-
type: "text",
|
|
6010
|
-
text: `Found ${prepared.items.length} runtime-ranked items (${prepared.retrieval.durationMs}ms, ${scopeLabel}, ${diagnostics}):
|
|
6011
|
-
|
|
6012
|
-
${prepared.context}${warnings}`
|
|
6013
|
-
}]
|
|
6014
|
-
};
|
|
6015
|
-
} catch (error) {
|
|
6016
|
-
const automaticWarning = `Automatic runtime unavailable: ${error.message}. Falling back to broad/manual query path.`;
|
|
6017
|
-
const queryResult2 = await queryWithDegradedFallback({
|
|
6018
|
-
project: resolvedProject,
|
|
6019
|
-
query,
|
|
6020
|
-
top_k,
|
|
6021
|
-
include_memories: include_memories === true,
|
|
6022
|
-
include_graph,
|
|
6023
|
-
user_id: user_id || scope.userId,
|
|
6024
|
-
session_id: session_id || scope.sessionId,
|
|
6025
|
-
retrieval_profile: retrievalProfile,
|
|
6026
|
-
include_parent_content
|
|
6027
|
-
});
|
|
6028
|
-
const response2 = queryResult2.response;
|
|
6029
|
-
if (response2.results.length === 0) {
|
|
6030
|
-
const memoryRescue = include_memories !== false ? await runContextQueryMemoryRescue({
|
|
6031
|
-
project: resolvedProject,
|
|
6032
|
-
query,
|
|
6033
|
-
user_id: user_id ? scope.userId : void 0,
|
|
6034
|
-
session_id: session_id ? scope.sessionId : void 0,
|
|
6035
|
-
top_k
|
|
6036
|
-
}) : { results: [], rescue_mode: null };
|
|
6037
|
-
if (memoryRescue.results.length && memoryRescue.rescue_mode) {
|
|
6038
|
-
return {
|
|
6039
|
-
content: [{
|
|
6040
|
-
type: "text",
|
|
6041
|
-
text: `${renderContextQueryMemoryRescue({
|
|
6042
|
-
project: resolvedProject,
|
|
6043
|
-
query,
|
|
6044
|
-
scope,
|
|
6045
|
-
results: memoryRescue.results,
|
|
6046
|
-
rescue_mode: memoryRescue.rescue_mode
|
|
6047
|
-
})}
|
|
6048
|
-
|
|
6049
|
-
[automatic_runtime]
|
|
6050
|
-
${automaticWarning}`
|
|
6051
|
-
}]
|
|
6052
|
-
};
|
|
6053
|
-
}
|
|
6054
|
-
return { content: [{ type: "text", text: `No relevant context found.
|
|
6055
|
-
|
|
6056
|
-
[automatic_runtime]
|
|
6057
|
-
${automaticWarning}` }] };
|
|
6058
|
-
}
|
|
6059
|
-
const header2 = `Found ${response2.meta.total} results (${response2.meta.latency_ms}ms${response2.meta.cache_hit ? ", cached" : ""}, project=${resolvedProject}, user=${scope.userId}, session=${scope.sessionId}):
|
|
6060
|
-
|
|
6061
|
-
`;
|
|
6062
|
-
const suffix2 = queryResult2.degraded_mode ? `
|
|
6063
|
-
|
|
6064
|
-
[degraded_mode=true] ${queryResult2.degraded_reason}
|
|
6065
|
-
Recommendation: ${queryResult2.recommendation}` : "";
|
|
6066
|
-
return { content: [{ type: "text", text: `${header2}${response2.context}
|
|
6067
|
-
|
|
6068
|
-
[automatic_runtime]
|
|
6069
|
-
${automaticWarning}${suffix2}` }] };
|
|
6070
|
-
}
|
|
6071
|
-
}
|
|
6072
|
-
const queryResult = await queryWithDegradedFallback({
|
|
6073
|
-
project: resolvedProject,
|
|
6074
|
-
query,
|
|
6648
|
+
const payload = await runUnifiedContextRetrieval({
|
|
6649
|
+
question: query,
|
|
6650
|
+
path,
|
|
6651
|
+
project,
|
|
6075
6652
|
top_k,
|
|
6076
|
-
include_memories
|
|
6653
|
+
include_memories,
|
|
6077
6654
|
include_graph,
|
|
6078
|
-
user_id
|
|
6079
|
-
session_id
|
|
6080
|
-
|
|
6081
|
-
|
|
6655
|
+
user_id,
|
|
6656
|
+
session_id,
|
|
6657
|
+
include_parent_content,
|
|
6658
|
+
retrieval_profile,
|
|
6659
|
+
chunk_types
|
|
6082
6660
|
});
|
|
6083
|
-
|
|
6084
|
-
if (response.results.length === 0) {
|
|
6085
|
-
const memoryRescue = include_memories !== false ? await runContextQueryMemoryRescue({
|
|
6086
|
-
project: resolvedProject,
|
|
6087
|
-
query,
|
|
6088
|
-
user_id: user_id ? scope.userId : void 0,
|
|
6089
|
-
session_id: session_id ? scope.sessionId : void 0,
|
|
6090
|
-
top_k
|
|
6091
|
-
}) : { results: [], rescue_mode: null };
|
|
6092
|
-
if (memoryRescue.results.length && memoryRescue.rescue_mode) {
|
|
6093
|
-
return {
|
|
6094
|
-
content: [{
|
|
6095
|
-
type: "text",
|
|
6096
|
-
text: renderContextQueryMemoryRescue({
|
|
6097
|
-
project: resolvedProject,
|
|
6098
|
-
query,
|
|
6099
|
-
scope,
|
|
6100
|
-
results: memoryRescue.results,
|
|
6101
|
-
rescue_mode: memoryRescue.rescue_mode
|
|
6102
|
-
})
|
|
6103
|
-
}]
|
|
6104
|
-
};
|
|
6105
|
-
}
|
|
6106
|
-
return { content: [{ type: "text", text: "No relevant context found." }] };
|
|
6107
|
-
}
|
|
6108
|
-
const header = `Found ${response.meta.total} results (${response.meta.latency_ms}ms${response.meta.cache_hit ? ", cached" : ""}, project=${resolvedProject}, user=${scope.userId}, session=${scope.sessionId}):
|
|
6109
|
-
|
|
6110
|
-
`;
|
|
6111
|
-
const suffix = queryResult.degraded_mode ? `
|
|
6112
|
-
|
|
6113
|
-
[degraded_mode=true] ${queryResult.degraded_reason}
|
|
6114
|
-
Recommendation: ${queryResult.recommendation}` : "";
|
|
6115
|
-
return { content: [{ type: "text", text: header + response.context + suffix }] };
|
|
6661
|
+
return toTextResult(payload);
|
|
6116
6662
|
} catch (error) {
|
|
6117
|
-
return
|
|
6663
|
+
return primaryToolError(error.message, "context_query_failed");
|
|
6118
6664
|
}
|
|
6119
6665
|
}
|
|
6120
6666
|
);
|
|
@@ -6146,11 +6692,24 @@ server.tool(
|
|
|
6146
6692
|
const jobId = result?.job_id;
|
|
6147
6693
|
const mode = result?.mode;
|
|
6148
6694
|
const semanticStatus = result?.semantic_status;
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6695
|
+
return primaryToolSuccess({
|
|
6696
|
+
tool: "memory.add",
|
|
6697
|
+
memory_id: memoryId || null,
|
|
6698
|
+
job_id: jobId || null,
|
|
6699
|
+
mode: mode || null,
|
|
6700
|
+
semantic_status: semanticStatus || null,
|
|
6701
|
+
memory_type: memory_type || "factual",
|
|
6702
|
+
queued: mode === "async" || Boolean(jobId),
|
|
6703
|
+
diagnostics: {
|
|
6704
|
+
scope: {
|
|
6705
|
+
project: scope.project || null,
|
|
6706
|
+
user_id: scope.userId,
|
|
6707
|
+
session_id: scope.sessionId || null
|
|
6708
|
+
}
|
|
6709
|
+
}
|
|
6710
|
+
});
|
|
6152
6711
|
} catch (error) {
|
|
6153
|
-
return
|
|
6712
|
+
return primaryToolError(error.message);
|
|
6154
6713
|
}
|
|
6155
6714
|
}
|
|
6156
6715
|
);
|
|
@@ -6192,7 +6751,14 @@ server.tool(
|
|
|
6192
6751
|
user_id: scope.userId,
|
|
6193
6752
|
session_id: scope.sessionId,
|
|
6194
6753
|
results: normalizedResults,
|
|
6195
|
-
count: normalizedResults.length
|
|
6754
|
+
count: normalizedResults.length,
|
|
6755
|
+
diagnostics: {
|
|
6756
|
+
scope: {
|
|
6757
|
+
project: scope.project || null,
|
|
6758
|
+
user_id: scope.userId,
|
|
6759
|
+
session_id: scope.sessionId || null
|
|
6760
|
+
}
|
|
6761
|
+
}
|
|
6196
6762
|
});
|
|
6197
6763
|
} catch (error) {
|
|
6198
6764
|
return primaryToolError(error.message);
|
|
@@ -6456,11 +7022,12 @@ server.tool(
|
|
|
6456
7022
|
},
|
|
6457
7023
|
async ({ project, query, user_id, session_id, question_date, memory_types, top_k, include_relations }) => {
|
|
6458
7024
|
try {
|
|
7025
|
+
const scope = resolveMcpScope({ project, user_id, session_id });
|
|
6459
7026
|
const results = await whisper.searchMemoriesSOTA({
|
|
6460
|
-
project,
|
|
7027
|
+
project: scope.project,
|
|
6461
7028
|
query,
|
|
6462
|
-
user_id,
|
|
6463
|
-
session_id,
|
|
7029
|
+
user_id: scope.userId,
|
|
7030
|
+
session_id: scope.sessionId,
|
|
6464
7031
|
question_date,
|
|
6465
7032
|
memory_types,
|
|
6466
7033
|
top_k,
|
|
@@ -6470,10 +7037,19 @@ server.tool(
|
|
|
6470
7037
|
return primaryToolSuccess({
|
|
6471
7038
|
tool: "memory.search_sota",
|
|
6472
7039
|
query,
|
|
7040
|
+
user_id: scope.userId,
|
|
7041
|
+
session_id: scope.sessionId || null,
|
|
6473
7042
|
question_date: question_date || null,
|
|
6474
7043
|
include_relations,
|
|
6475
7044
|
results: normalizedResults,
|
|
6476
|
-
count: normalizedResults.length
|
|
7045
|
+
count: normalizedResults.length,
|
|
7046
|
+
diagnostics: {
|
|
7047
|
+
scope: {
|
|
7048
|
+
project: scope.project || null,
|
|
7049
|
+
user_id: scope.userId,
|
|
7050
|
+
session_id: scope.sessionId || null
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
6477
7053
|
});
|
|
6478
7054
|
} catch (error) {
|
|
6479
7055
|
return primaryToolError(error.message);
|
|
@@ -7509,7 +8085,10 @@ server.tool(
|
|
|
7509
8085
|
context: response.context,
|
|
7510
8086
|
results: response.results,
|
|
7511
8087
|
degradedMode: queryResult.degraded_mode,
|
|
7512
|
-
degradedReason: queryResult.degraded_reason
|
|
8088
|
+
degradedReason: queryResult.degraded_reason,
|
|
8089
|
+
semanticStatus: queryResult.semantic_status,
|
|
8090
|
+
fallbackMode: queryResult.fallback_mode,
|
|
8091
|
+
recommendedFixes: queryResult.recommended_fixes || []
|
|
7513
8092
|
}));
|
|
7514
8093
|
} catch (error) {
|
|
7515
8094
|
return primaryToolError(error.message);
|
|
@@ -7773,7 +8352,16 @@ server.tool(
|
|
|
7773
8352
|
},
|
|
7774
8353
|
async ({ project, content, memory_type, user_id, session_id, agent_id, importance }) => {
|
|
7775
8354
|
try {
|
|
7776
|
-
const
|
|
8355
|
+
const scope = resolveMcpScope({ project, user_id, session_id });
|
|
8356
|
+
const result = await whisper.addMemory({
|
|
8357
|
+
project: scope.project,
|
|
8358
|
+
content,
|
|
8359
|
+
memory_type,
|
|
8360
|
+
user_id: scope.userId,
|
|
8361
|
+
session_id: scope.sessionId,
|
|
8362
|
+
agent_id,
|
|
8363
|
+
importance
|
|
8364
|
+
});
|
|
7777
8365
|
const memoryId = result?.memory_id || (result.mode === "sync" ? result.id : null);
|
|
7778
8366
|
const jobId = result?.job_id || (result.mode === "async" ? result.id : null);
|
|
7779
8367
|
return primaryToolSuccess({
|
|
@@ -7784,7 +8372,14 @@ server.tool(
|
|
|
7784
8372
|
mode: result?.mode || null,
|
|
7785
8373
|
memory_type,
|
|
7786
8374
|
stored: result.success === true,
|
|
7787
|
-
queued: result?.mode === "async" || Boolean(jobId)
|
|
8375
|
+
queued: result?.mode === "async" || Boolean(jobId),
|
|
8376
|
+
diagnostics: {
|
|
8377
|
+
scope: {
|
|
8378
|
+
project: scope.project || null,
|
|
8379
|
+
user_id: scope.userId,
|
|
8380
|
+
session_id: scope.sessionId || null
|
|
8381
|
+
}
|
|
8382
|
+
}
|
|
7788
8383
|
});
|
|
7789
8384
|
} catch (error) {
|
|
7790
8385
|
return primaryToolError(error.message);
|
|
@@ -7820,18 +8415,31 @@ server.tool(
|
|
|
7820
8415
|
timestamp
|
|
7821
8416
|
});
|
|
7822
8417
|
const resolvedProject = await resolveProjectRef(project);
|
|
7823
|
-
const
|
|
7824
|
-
project: resolvedProject,
|
|
7825
|
-
session_id,
|
|
8418
|
+
const scope = resolveMcpScope({
|
|
8419
|
+
project: resolvedProject || project,
|
|
7826
8420
|
user_id,
|
|
8421
|
+
session_id
|
|
8422
|
+
});
|
|
8423
|
+
const result = await ingestSessionWithSyncFallback({
|
|
8424
|
+
project: scope.project,
|
|
8425
|
+
session_id: scope.sessionId || session_id,
|
|
8426
|
+
user_id: scope.userId,
|
|
7827
8427
|
messages: normalizedMessages
|
|
7828
8428
|
});
|
|
7829
8429
|
return primaryToolSuccess({
|
|
7830
8430
|
tool: "record",
|
|
7831
|
-
session_id,
|
|
8431
|
+
session_id: scope.sessionId || session_id,
|
|
8432
|
+
user_id: scope.userId,
|
|
7832
8433
|
messages_recorded: normalizedMessages.length,
|
|
7833
8434
|
memories_created: result.memories_created,
|
|
7834
|
-
relations_created: result.relations_created
|
|
8435
|
+
relations_created: result.relations_created,
|
|
8436
|
+
diagnostics: {
|
|
8437
|
+
scope: {
|
|
8438
|
+
project: scope.project || null,
|
|
8439
|
+
user_id: scope.userId,
|
|
8440
|
+
session_id: scope.sessionId || session_id
|
|
8441
|
+
}
|
|
8442
|
+
}
|
|
7835
8443
|
});
|
|
7836
8444
|
} catch (error) {
|
|
7837
8445
|
return primaryToolError(error.message);
|
|
@@ -7962,6 +8570,14 @@ async function main() {
|
|
|
7962
8570
|
console.error("Error: WHISPER_API_KEY environment variable is required");
|
|
7963
8571
|
process.exit(1);
|
|
7964
8572
|
}
|
|
8573
|
+
const startupDiagnostics = {
|
|
8574
|
+
runtime_mode: RUNTIME_MODE,
|
|
8575
|
+
local_ingest_enabled: RUNTIME_MODE !== "remote",
|
|
8576
|
+
startup_status: RUNTIME_MODE === "remote" ? "degraded_auto_repairing" : "healthy",
|
|
8577
|
+
startup_action: RUNTIME_MODE === "remote" ? "restart_client" : "none",
|
|
8578
|
+
warning: RUNTIME_MODE === "remote" ? "Local ingest is disabled in remote mode. Set WHISPER_MCP_MODE=auto and restart MCP to enable local repair paths." : null
|
|
8579
|
+
};
|
|
8580
|
+
console.error(`[whisper-context-mcp] startup_diagnostics=${JSON.stringify(startupDiagnostics)}`);
|
|
7965
8581
|
console.error("[whisper-context-mcp] Breaking change: canonical namespaced tool names are active. Run with --print-tool-map for migration mapping.");
|
|
7966
8582
|
const transport = new StdioServerTransport();
|
|
7967
8583
|
await server.connect(transport);
|
|
@@ -7974,20 +8590,35 @@ export {
|
|
|
7974
8590
|
RECOMMENDED_NEXT_CALL_ALLOWLIST,
|
|
7975
8591
|
RETRIEVAL_READINESS_VALUES,
|
|
7976
8592
|
RETRIEVAL_ROUTE_VALUES,
|
|
8593
|
+
STATUS_ACTION_VALUES,
|
|
8594
|
+
STATUS_LABEL_VALUES,
|
|
7977
8595
|
WORKSPACE_HEALTH_VALUES,
|
|
7978
8596
|
canonicalizeWorkspacePath,
|
|
7979
8597
|
chooseWorkspaceProjectSource,
|
|
7980
8598
|
classifyProjectRepoReadiness,
|
|
7981
8599
|
classifyRepoGroundedQuery,
|
|
7982
8600
|
classifyWorkspaceHealth,
|
|
8601
|
+
computeSnapshotChangedFiles,
|
|
8602
|
+
computeTrustScore,
|
|
7983
8603
|
createMcpServer,
|
|
7984
8604
|
createWhisperMcpClient,
|
|
7985
8605
|
createWhisperMcpRuntimeClient,
|
|
8606
|
+
defaultMcpUserId,
|
|
7986
8607
|
extractSignature,
|
|
8608
|
+
fallbackModeFromSearchMode,
|
|
8609
|
+
isStrictlyBetterReadiness,
|
|
8610
|
+
recommendedNextCallsAreAcyclic,
|
|
8611
|
+
recommendedNextCallsForRootCause,
|
|
7987
8612
|
renderScopedMcpConfig,
|
|
7988
8613
|
resolveForgetQueryCandidates,
|
|
8614
|
+
resolveMcpScope,
|
|
7989
8615
|
resolveWorkspaceIdentity,
|
|
8616
|
+
retrievalReadinessRank,
|
|
7990
8617
|
runSearchCodeSearch,
|
|
7991
8618
|
sanitizeRecommendedNextCalls,
|
|
7992
|
-
|
|
8619
|
+
semanticStatusFromSearchMode,
|
|
8620
|
+
shouldAbstainForCodebaseTrust,
|
|
8621
|
+
shouldTriggerBackgroundRefresh,
|
|
8622
|
+
statusActionForRootCause,
|
|
8623
|
+
statusContractForReadiness
|
|
7993
8624
|
};
|