@usewhisper/mcp-server 2.13.0 → 2.15.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 +1435 -537
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -7,7 +7,7 @@ import { z } from "zod";
|
|
|
7
7
|
import { execSync, spawnSync } from "child_process";
|
|
8
8
|
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync, appendFileSync } from "fs";
|
|
9
9
|
import { join, relative, extname, normalize as normalizePath, resolve as resolvePath } from "path";
|
|
10
|
-
import { homedir } from "os";
|
|
10
|
+
import { homedir, userInfo } from "os";
|
|
11
11
|
import { createHash, randomUUID } from "crypto";
|
|
12
12
|
|
|
13
13
|
// ../src/sdk/core/telemetry.ts
|
|
@@ -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,11 +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",
|
|
3897
3905
|
"context.add_source",
|
|
3898
3906
|
"index.local_scan_ingest",
|
|
3907
|
+
"context.query",
|
|
3899
3908
|
"context.get_relevant"
|
|
3900
3909
|
]);
|
|
3901
3910
|
var UNTRUSTED_CODEBASE_HEALTH = /* @__PURE__ */ new Set(["unbound", "unindexed"]);
|
|
@@ -3903,31 +3912,85 @@ var UNTRUSTED_CODEBASE_PROJECT_READINESS = /* @__PURE__ */ new Set([
|
|
|
3903
3912
|
"project_unverified",
|
|
3904
3913
|
"project_bound_no_repo_source"
|
|
3905
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
|
+
};
|
|
3906
3947
|
function sanitizeRecommendedNextCalls(nextCalls) {
|
|
3907
3948
|
return Array.from(
|
|
3908
3949
|
new Set(
|
|
3909
3950
|
nextCalls.map((entry) => String(entry || "").trim()).filter((entry) => RECOMMENDED_NEXT_CALL_ALLOWLIST.has(entry))
|
|
3910
3951
|
)
|
|
3911
|
-
);
|
|
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";
|
|
3912
3982
|
}
|
|
3913
3983
|
function getRepoReadinessNextCalls(readiness) {
|
|
3914
|
-
if (readiness
|
|
3915
|
-
return
|
|
3984
|
+
if (readiness === "project_bound_no_repo_source") {
|
|
3985
|
+
return recommendedNextCallsForRootCause("project_bound_no_repo_source");
|
|
3916
3986
|
}
|
|
3917
|
-
if (
|
|
3918
|
-
return
|
|
3919
|
-
"context.list_sources",
|
|
3920
|
-
"context.add_source",
|
|
3921
|
-
"index.workspace_status",
|
|
3922
|
-
"context.get_relevant"
|
|
3923
|
-
]);
|
|
3987
|
+
if (readiness === "project_unverified") {
|
|
3988
|
+
return recommendedNextCallsForRootCause("project_unverified");
|
|
3924
3989
|
}
|
|
3925
|
-
|
|
3926
|
-
"
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
"context.get_relevant"
|
|
3930
|
-
]);
|
|
3990
|
+
if (readiness === "project_repo_source_stale") {
|
|
3991
|
+
return recommendedNextCallsForRootCause("project_repo_source_stale");
|
|
3992
|
+
}
|
|
3993
|
+
return [];
|
|
3931
3994
|
}
|
|
3932
3995
|
function resolveMcpRetrievalProfile(requested) {
|
|
3933
3996
|
if (requested && MCP_RETRIEVAL_PROFILE_VALUES.includes(requested)) {
|
|
@@ -3935,6 +3998,156 @@ function resolveMcpRetrievalProfile(requested) {
|
|
|
3935
3998
|
}
|
|
3936
3999
|
return MCP_RETRIEVAL_PRECISION_V1_DEFAULT ? "precision_v1" : "legacy";
|
|
3937
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
|
+
}
|
|
3938
4151
|
function shouldAbstainForCodebaseTrust(args) {
|
|
3939
4152
|
if (args.retrievalProfile !== "precision_v1" || !args.codebaseIntent) return false;
|
|
3940
4153
|
return UNTRUSTED_CODEBASE_HEALTH.has(args.preflight.trust_state.health) || UNTRUSTED_CODEBASE_PROJECT_READINESS.has(args.preflight.project_retrieval_readiness);
|
|
@@ -4270,9 +4483,9 @@ async function resolveProjectDescriptor(projectRef) {
|
|
|
4270
4483
|
}
|
|
4271
4484
|
}
|
|
4272
4485
|
function getWorkspaceRecommendedNextCalls(health) {
|
|
4273
|
-
if (health === "unbound") return sanitizeRecommendedNextCalls(["index.workspace_resolve"
|
|
4274
|
-
if (health === "unindexed") return sanitizeRecommendedNextCalls(["index.
|
|
4275
|
-
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"]);
|
|
4276
4489
|
return [];
|
|
4277
4490
|
}
|
|
4278
4491
|
function getWorkspaceWarnings(args) {
|
|
@@ -4468,7 +4681,7 @@ async function resolveRepoGroundingPreflight(args) {
|
|
|
4468
4681
|
}
|
|
4469
4682
|
}
|
|
4470
4683
|
const recommendedNextCalls = [...trust.recommended_next_calls];
|
|
4471
|
-
if (sourceVerification.retrieval_readiness
|
|
4684
|
+
if (sourceVerification.retrieval_readiness !== "project_repo_source_ready" && sourceVerification.retrieval_readiness !== "no_project") {
|
|
4472
4685
|
recommendedNextCalls.push(...getRepoReadinessNextCalls(sourceVerification.retrieval_readiness));
|
|
4473
4686
|
}
|
|
4474
4687
|
return {
|
|
@@ -4498,53 +4711,110 @@ async function ingestSessionWithSyncFallback(params) {
|
|
|
4498
4711
|
return whisper.ingestSession(params);
|
|
4499
4712
|
}
|
|
4500
4713
|
}
|
|
4501
|
-
function
|
|
4714
|
+
function apiKeyFingerprint(apiKey) {
|
|
4715
|
+
const value = String(apiKey || "").trim();
|
|
4716
|
+
if (!value) return "anon";
|
|
4717
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
4718
|
+
}
|
|
4719
|
+
function defaultMcpUserId(params) {
|
|
4502
4720
|
const explicit = process.env.WHISPER_USER_ID?.trim();
|
|
4503
4721
|
if (explicit) return explicit;
|
|
4504
|
-
|
|
4722
|
+
let osUsername = process.env.USER?.trim() || process.env.USERNAME?.trim();
|
|
4723
|
+
if (!osUsername) {
|
|
4724
|
+
try {
|
|
4725
|
+
osUsername = userInfo().username?.trim();
|
|
4726
|
+
} catch {
|
|
4727
|
+
osUsername = "";
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
if (!osUsername) {
|
|
4731
|
+
throw new Error("Unable to derive user identity. Set WHISPER_USER_ID or pass user_id.");
|
|
4732
|
+
}
|
|
4733
|
+
const workspacePath = params?.workspacePath || canonicalizeWorkspacePath(process.cwd());
|
|
4734
|
+
const projectRef = params?.project || DEFAULT_PROJECT || "default";
|
|
4735
|
+
const seed = `${workspacePath}|${projectRef}|${apiKeyFingerprint(API_KEY)}|${osUsername.toLowerCase()}`;
|
|
4505
4736
|
return `mcp-user-${createHash("sha256").update(seed).digest("hex").slice(0, 12)}`;
|
|
4506
4737
|
}
|
|
4507
|
-
function resolveMcpScope(params) {
|
|
4738
|
+
function resolveMcpScope(params, options) {
|
|
4739
|
+
const workspacePath = canonicalizeWorkspacePath(params?.path || process.env.WHISPER_WORKSPACE_PATH || process.cwd());
|
|
4740
|
+
const explicitSession = params?.session_id?.trim();
|
|
4508
4741
|
return {
|
|
4509
4742
|
project: params?.project,
|
|
4510
|
-
userId: params?.user_id?.trim() || defaultMcpUserId(
|
|
4511
|
-
|
|
4512
|
-
|
|
4743
|
+
userId: params?.user_id?.trim() || defaultMcpUserId({
|
|
4744
|
+
project: params?.project,
|
|
4745
|
+
workspacePath
|
|
4746
|
+
}),
|
|
4747
|
+
sessionId: explicitSession || (options?.include_default_session ? cachedMcpSessionId : void 0),
|
|
4748
|
+
workspacePath
|
|
4513
4749
|
};
|
|
4514
4750
|
}
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4751
|
+
function resolveMemoryScope(params) {
|
|
4752
|
+
const base = resolveMcpScope({
|
|
4753
|
+
project: params?.project,
|
|
4754
|
+
user_id: params?.user_id,
|
|
4755
|
+
session_id: params?.session_id,
|
|
4756
|
+
path: params?.path
|
|
4757
|
+
});
|
|
4758
|
+
const scopeMode = params?.scope === "shared_project" ? "shared_project" : "personal";
|
|
4759
|
+
if (scopeMode === "shared_project") {
|
|
4760
|
+
if (!base.project && !DEFAULT_PROJECT) {
|
|
4761
|
+
throw new Error("shared_project scope requires a project. Set WHISPER_PROJECT or pass project.");
|
|
4762
|
+
}
|
|
4763
|
+
const projectRef = base.project || DEFAULT_PROJECT || "default";
|
|
4764
|
+
return {
|
|
4765
|
+
...base,
|
|
4766
|
+
userId: `shared-project:${projectRef}`,
|
|
4767
|
+
sessionId: void 0,
|
|
4768
|
+
actorUserId: base.userId,
|
|
4769
|
+
actorSessionId: base.sessionId,
|
|
4770
|
+
scopeMode,
|
|
4771
|
+
sharedProjectRef: projectRef
|
|
4772
|
+
};
|
|
4518
4773
|
}
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4774
|
+
return {
|
|
4775
|
+
...base,
|
|
4776
|
+
actorUserId: base.userId,
|
|
4777
|
+
actorSessionId: base.sessionId,
|
|
4778
|
+
scopeMode,
|
|
4779
|
+
sharedProjectRef: null
|
|
4780
|
+
};
|
|
4781
|
+
}
|
|
4782
|
+
function sharedProjectMemoryUserId(projectRef) {
|
|
4783
|
+
return `shared-project:${projectRef}`;
|
|
4784
|
+
}
|
|
4785
|
+
function buildMemoryScopeMetadata(args) {
|
|
4786
|
+
const { memoryScope } = args;
|
|
4787
|
+
const metadata = {
|
|
4788
|
+
scope: memoryScope.scopeMode,
|
|
4789
|
+
...memoryScope.sharedProjectRef ? { shared_project_ref: memoryScope.sharedProjectRef } : {}
|
|
4790
|
+
};
|
|
4791
|
+
if (memoryScope.scopeMode === "shared_project") {
|
|
4792
|
+
metadata.provenance = {
|
|
4793
|
+
writer_user_id: memoryScope.actorUserId,
|
|
4794
|
+
writer_session_id: memoryScope.actorSessionId || null,
|
|
4795
|
+
writer_agent_id: args.agent_id || process.env.WHISPER_AGENT_ID || null,
|
|
4796
|
+
written_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4797
|
+
};
|
|
4538
4798
|
}
|
|
4539
|
-
return
|
|
4540
|
-
|
|
4541
|
-
|
|
4799
|
+
return metadata;
|
|
4800
|
+
}
|
|
4801
|
+
function isMemoryInScope(args) {
|
|
4802
|
+
const memory = args.memory;
|
|
4803
|
+
if (!memory || typeof memory !== "object") return false;
|
|
4804
|
+
const memoryUserId = String(memory.userId || memory.user_id || "").trim();
|
|
4805
|
+
if (args.memoryScope.scopeMode === "shared_project") {
|
|
4806
|
+
const metadata = memory.metadata && typeof memory.metadata === "object" ? memory.metadata : {};
|
|
4807
|
+
const metaScope = String(metadata.scope || "").trim();
|
|
4808
|
+
const metaProjectRef = String(metadata.shared_project_ref || "").trim();
|
|
4809
|
+
return memoryUserId === args.memoryScope.userId || metaScope === "shared_project" && metaProjectRef === (args.memoryScope.sharedProjectRef || "");
|
|
4810
|
+
}
|
|
4811
|
+
return memoryUserId === args.memoryScope.userId;
|
|
4542
4812
|
}
|
|
4543
4813
|
function noteAutomaticSourceActivity(params) {
|
|
4544
4814
|
if (!runtimeClient) return;
|
|
4545
4815
|
const sourceIds = [...new Set((params.sourceIds || []).map((value) => String(value || "").trim()).filter(Boolean))];
|
|
4546
4816
|
if (sourceIds.length === 0) return;
|
|
4547
|
-
const scope = resolveMcpScope(params);
|
|
4817
|
+
const scope = resolveMcpScope(params, { include_default_session: true });
|
|
4548
4818
|
const key = [
|
|
4549
4819
|
params.project || DEFAULT_PROJECT || "",
|
|
4550
4820
|
scope.userId,
|
|
@@ -4576,7 +4846,7 @@ function buildAbstain(args) {
|
|
|
4576
4846
|
warnings: args.warnings || [],
|
|
4577
4847
|
trust_state: args.trust_state,
|
|
4578
4848
|
recommended_next_calls: sanitizeRecommendedNextCalls(
|
|
4579
|
-
args.recommended_next_calls || ["index.workspace_status", "index.workspace_run", "
|
|
4849
|
+
args.recommended_next_calls || ["index.workspace_status", "index.workspace_run", "fix", "context.query"]
|
|
4580
4850
|
),
|
|
4581
4851
|
diagnostics: {
|
|
4582
4852
|
claims_evaluated: args.claims_evaluated,
|
|
@@ -4631,6 +4901,415 @@ function countCodeFiles(searchPath, maxFiles = 5e3) {
|
|
|
4631
4901
|
walk(searchPath);
|
|
4632
4902
|
return { total, skipped };
|
|
4633
4903
|
}
|
|
4904
|
+
function computeWorkspaceSnapshot(searchPath, maxFiles = 250) {
|
|
4905
|
+
const files = collectCodeFiles(searchPath, CODE_EXTENSIONS, maxFiles);
|
|
4906
|
+
const entries = files.slice(0, maxFiles).map((filePath) => {
|
|
4907
|
+
try {
|
|
4908
|
+
const st = statSync(filePath);
|
|
4909
|
+
return `${relative(searchPath, filePath)}:${st.mtimeMs}:${st.size}`;
|
|
4910
|
+
} catch {
|
|
4911
|
+
return "";
|
|
4912
|
+
}
|
|
4913
|
+
}).filter(Boolean);
|
|
4914
|
+
const sample = entries.join("|");
|
|
4915
|
+
return {
|
|
4916
|
+
hash: createHash("sha256").update(sample || searchPath).digest("hex").slice(0, 24),
|
|
4917
|
+
entries
|
|
4918
|
+
};
|
|
4919
|
+
}
|
|
4920
|
+
function computeSnapshotChangedFiles(previousEntries, nextEntries) {
|
|
4921
|
+
if (!previousEntries || previousEntries.length === 0) return nextEntries.length;
|
|
4922
|
+
const previousByPath = /* @__PURE__ */ new Map();
|
|
4923
|
+
for (const entry of previousEntries) {
|
|
4924
|
+
const idx = entry.indexOf(":");
|
|
4925
|
+
if (idx <= 0) continue;
|
|
4926
|
+
previousByPath.set(entry.slice(0, idx), entry.slice(idx + 1));
|
|
4927
|
+
}
|
|
4928
|
+
let changed = 0;
|
|
4929
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4930
|
+
for (const entry of nextEntries) {
|
|
4931
|
+
const idx = entry.indexOf(":");
|
|
4932
|
+
if (idx <= 0) continue;
|
|
4933
|
+
const relPath = entry.slice(0, idx);
|
|
4934
|
+
const fingerprint = entry.slice(idx + 1);
|
|
4935
|
+
seen.add(relPath);
|
|
4936
|
+
if (previousByPath.get(relPath) !== fingerprint) changed += 1;
|
|
4937
|
+
}
|
|
4938
|
+
for (const relPath of previousByPath.keys()) {
|
|
4939
|
+
if (!seen.has(relPath)) changed += 1;
|
|
4940
|
+
}
|
|
4941
|
+
return changed;
|
|
4942
|
+
}
|
|
4943
|
+
function shouldTriggerBackgroundRefresh(args) {
|
|
4944
|
+
const nowMs = args.now_ms ?? Date.now();
|
|
4945
|
+
const lastAutoRefreshAt = args.last_auto_refresh_at ? new Date(args.last_auto_refresh_at).getTime() : 0;
|
|
4946
|
+
const debounceMs = 10 * 60 * 1e3;
|
|
4947
|
+
const dueForDebounce = !lastAutoRefreshAt || Number.isNaN(lastAutoRefreshAt) || nowMs - lastAutoRefreshAt >= debounceMs;
|
|
4948
|
+
if (!dueForDebounce) {
|
|
4949
|
+
return { should_refresh: false, trigger_reason: null };
|
|
4950
|
+
}
|
|
4951
|
+
if (args.last_indexed_commit && args.current_head && args.last_indexed_commit !== args.current_head) {
|
|
4952
|
+
return { should_refresh: true, trigger_reason: "head_changed" };
|
|
4953
|
+
}
|
|
4954
|
+
if (args.changed_files >= 20) {
|
|
4955
|
+
return { should_refresh: true, trigger_reason: "delta_files_threshold" };
|
|
4956
|
+
}
|
|
4957
|
+
const ratio = args.indexed_files > 0 ? args.changed_files / args.indexed_files : 0;
|
|
4958
|
+
if (ratio >= 0.02) {
|
|
4959
|
+
return { should_refresh: true, trigger_reason: "delta_ratio_threshold" };
|
|
4960
|
+
}
|
|
4961
|
+
return { should_refresh: false, trigger_reason: null };
|
|
4962
|
+
}
|
|
4963
|
+
async function runBackgroundWorkspaceRefresh(args) {
|
|
4964
|
+
const state = loadState();
|
|
4965
|
+
const workspace = getWorkspaceState(state, args.workspace_id);
|
|
4966
|
+
if (!workspace.index_metadata) workspace.index_metadata = {};
|
|
4967
|
+
const fileStats = countCodeFiles(args.root_path, args.max_files || 1500);
|
|
4968
|
+
const currentHead = getGitHead(args.root_path) || null;
|
|
4969
|
+
const currentSnapshot = computeWorkspaceSnapshot(args.root_path);
|
|
4970
|
+
const gitPendingCount = getGitPendingCount(args.root_path);
|
|
4971
|
+
const changedFiles = gitPendingCount == null ? computeSnapshotChangedFiles(workspace.index_metadata.last_snapshot_entries, currentSnapshot.entries) : gitPendingCount;
|
|
4972
|
+
const lastIndexedCommit = workspace.index_metadata.last_indexed_commit || null;
|
|
4973
|
+
const refreshDecision = shouldTriggerBackgroundRefresh({
|
|
4974
|
+
current_head: currentHead,
|
|
4975
|
+
last_indexed_commit: lastIndexedCommit,
|
|
4976
|
+
changed_files: changedFiles,
|
|
4977
|
+
indexed_files: parsePositiveNumber(workspace.index_metadata.indexed_files, fileStats.total || 1),
|
|
4978
|
+
last_auto_refresh_at: workspace.index_metadata.last_auto_refresh_at || null
|
|
4979
|
+
});
|
|
4980
|
+
const forceFullRequested = args.force_full === true;
|
|
4981
|
+
if (!refreshDecision.should_refresh && !forceFullRequested) {
|
|
4982
|
+
return { refreshed: false, mode: null, reason: null };
|
|
4983
|
+
}
|
|
4984
|
+
const mode = forceFullRequested ? "full" : "incremental";
|
|
4985
|
+
workspace.root_path = args.root_path;
|
|
4986
|
+
workspace.index_metadata.last_indexed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
4987
|
+
workspace.index_metadata.last_auto_refresh_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
4988
|
+
workspace.index_metadata.last_indexed_commit = currentHead || void 0;
|
|
4989
|
+
workspace.index_metadata.coverage = mode === "full" ? 1 : Math.max(0, Math.min(1, fileStats.total / Math.max(1, args.max_files || 1500)));
|
|
4990
|
+
workspace.index_metadata.indexed_files = fileStats.total;
|
|
4991
|
+
workspace.index_metadata.last_snapshot_hash = currentSnapshot.hash;
|
|
4992
|
+
workspace.index_metadata.last_snapshot_entries = currentSnapshot.entries;
|
|
4993
|
+
if (mode === "full") workspace.index_metadata.last_full_refresh_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
4994
|
+
saveState(state);
|
|
4995
|
+
return {
|
|
4996
|
+
refreshed: true,
|
|
4997
|
+
mode,
|
|
4998
|
+
reason: refreshDecision.trigger_reason || (forceFullRequested ? "manual_full_override" : mode === "full" ? "full_refresh_due" : "manual")
|
|
4999
|
+
};
|
|
5000
|
+
}
|
|
5001
|
+
function buildSourceRepairHint(args) {
|
|
5002
|
+
const remote = parseGitHubRemote(getGitRemoteUrl(args.root_path) || null);
|
|
5003
|
+
if (remote) {
|
|
5004
|
+
const branch = getGitBranch(args.root_path) || "main";
|
|
5005
|
+
return {
|
|
5006
|
+
command: `context.add_source --project ${args.project_ref || "<project>"} --type github --owner ${remote.owner} --repo ${remote.repo} --branch ${branch}`,
|
|
5007
|
+
message: "Attach the matching GitHub source, then rerun fix."
|
|
5008
|
+
};
|
|
5009
|
+
}
|
|
5010
|
+
return {
|
|
5011
|
+
command: `context.add_source --project ${args.project_ref || "<project>"} --type local --path "${args.root_path}"`,
|
|
5012
|
+
message: "Attach the local workspace as a source, then rerun fix."
|
|
5013
|
+
};
|
|
5014
|
+
}
|
|
5015
|
+
async function attemptDeterministicSourceAttach(args) {
|
|
5016
|
+
const remote = parseGitHubRemote(getGitRemoteUrl(args.root_path) || null);
|
|
5017
|
+
if (remote) {
|
|
5018
|
+
const branch = getGitBranch(args.root_path) || "main";
|
|
5019
|
+
const result = await createSourceByType({
|
|
5020
|
+
project: args.project,
|
|
5021
|
+
type: "github",
|
|
5022
|
+
name: `auto-repair:${remote.owner}/${remote.repo}`,
|
|
5023
|
+
owner: remote.owner,
|
|
5024
|
+
repo: remote.repo,
|
|
5025
|
+
branch,
|
|
5026
|
+
auto_index: true
|
|
5027
|
+
});
|
|
5028
|
+
const sourceId = result?.source_id || result?.id;
|
|
5029
|
+
noteAutomaticSourceActivity({
|
|
5030
|
+
project: args.project,
|
|
5031
|
+
sourceIds: sourceId ? [String(sourceId)] : []
|
|
5032
|
+
});
|
|
5033
|
+
return { attached: true, detail: `github:${remote.owner}/${remote.repo}@${branch}` };
|
|
5034
|
+
}
|
|
5035
|
+
if (RUNTIME_MODE !== "remote") {
|
|
5036
|
+
await createSourceByType({
|
|
5037
|
+
project: args.project,
|
|
5038
|
+
type: "local",
|
|
5039
|
+
name: "auto-repair:local-workspace",
|
|
5040
|
+
path: args.root_path,
|
|
5041
|
+
auto_index: true,
|
|
5042
|
+
max_files: 500
|
|
5043
|
+
});
|
|
5044
|
+
return { attached: true, detail: "local_workspace_source_attached" };
|
|
5045
|
+
}
|
|
5046
|
+
return { attached: false, detail: "deterministic_source_inputs_unavailable" };
|
|
5047
|
+
}
|
|
5048
|
+
async function runAutoRepairVerification(args) {
|
|
5049
|
+
if (args.preflight.retrieval_route === "project_repo" && args.preflight.matched_source_ids.length > 0) {
|
|
5050
|
+
try {
|
|
5051
|
+
const queryResult = await queryWithDegradedFallback({
|
|
5052
|
+
project: args.project,
|
|
5053
|
+
query: "how does this project work",
|
|
5054
|
+
top_k: 5,
|
|
5055
|
+
include_memories: false,
|
|
5056
|
+
include_graph: false,
|
|
5057
|
+
source_ids: args.preflight.matched_source_ids
|
|
5058
|
+
});
|
|
5059
|
+
const resultCount = Array.isArray(queryResult.response?.results) ? queryResult.response.results.length : 0;
|
|
5060
|
+
return {
|
|
5061
|
+
passed: resultCount > 0,
|
|
5062
|
+
route: "project_repo",
|
|
5063
|
+
result_count: resultCount,
|
|
5064
|
+
detail: resultCount > 0 ? "project_query_has_results" : "project_query_empty"
|
|
5065
|
+
};
|
|
5066
|
+
} catch (error) {
|
|
5067
|
+
return {
|
|
5068
|
+
passed: false,
|
|
5069
|
+
route: "project_repo",
|
|
5070
|
+
result_count: 0,
|
|
5071
|
+
detail: `project_query_error:${String(error?.message || error)}`
|
|
5072
|
+
};
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
5075
|
+
if (args.preflight.retrieval_route === "local_workspace_fallback") {
|
|
5076
|
+
try {
|
|
5077
|
+
const local = await runLocalWorkspaceRetrieval({
|
|
5078
|
+
query: "how does this project work",
|
|
5079
|
+
path: args.preflight.trust_state.root_path,
|
|
5080
|
+
project: args.project,
|
|
5081
|
+
top_k: 5
|
|
5082
|
+
});
|
|
5083
|
+
return {
|
|
5084
|
+
passed: local.results.length > 0,
|
|
5085
|
+
route: "local_workspace_fallback",
|
|
5086
|
+
result_count: local.results.length,
|
|
5087
|
+
detail: local.results.length > 0 ? "local_query_has_results" : "local_query_empty"
|
|
5088
|
+
};
|
|
5089
|
+
} catch (error) {
|
|
5090
|
+
return {
|
|
5091
|
+
passed: false,
|
|
5092
|
+
route: "local_workspace_fallback",
|
|
5093
|
+
result_count: 0,
|
|
5094
|
+
detail: `local_query_error:${String(error?.message || error)}`
|
|
5095
|
+
};
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
return {
|
|
5099
|
+
passed: false,
|
|
5100
|
+
route: args.preflight.retrieval_route,
|
|
5101
|
+
result_count: 0,
|
|
5102
|
+
detail: "no_verifiable_retrieval_route"
|
|
5103
|
+
};
|
|
5104
|
+
}
|
|
5105
|
+
async function runAutoRepairFlow(input) {
|
|
5106
|
+
const actions_attempted = [];
|
|
5107
|
+
const actions_succeeded = [];
|
|
5108
|
+
const actions_failed = [];
|
|
5109
|
+
const apply = input.apply !== false;
|
|
5110
|
+
const repairScope = input.repair_scope || "safe";
|
|
5111
|
+
const allowRestartHint = input.allow_restart_hint !== false;
|
|
5112
|
+
let restartRequired = false;
|
|
5113
|
+
if (!API_KEY) {
|
|
5114
|
+
return {
|
|
5115
|
+
root_cause_code: "missing_api_key",
|
|
5116
|
+
actions_attempted,
|
|
5117
|
+
actions_succeeded,
|
|
5118
|
+
actions_failed: [...actions_failed, "validate_credentials:missing_api_key"],
|
|
5119
|
+
restart_required: false,
|
|
5120
|
+
verification_passed: false,
|
|
5121
|
+
status_label: "blocked",
|
|
5122
|
+
status_action: "reauth",
|
|
5123
|
+
action_required: true,
|
|
5124
|
+
diagnostics: {
|
|
5125
|
+
message: "WHISPER_API_KEY is required."
|
|
5126
|
+
}
|
|
5127
|
+
};
|
|
5128
|
+
}
|
|
5129
|
+
actions_attempted.push("validate_credentials");
|
|
5130
|
+
actions_succeeded.push("validate_credentials");
|
|
5131
|
+
actions_attempted.push("resolve_project");
|
|
5132
|
+
const resolvedProject = await resolveProjectRef(input.project);
|
|
5133
|
+
if (!resolvedProject) {
|
|
5134
|
+
actions_failed.push("resolve_project:no_project");
|
|
5135
|
+
return {
|
|
5136
|
+
root_cause_code: "no_project_bound",
|
|
5137
|
+
actions_attempted,
|
|
5138
|
+
actions_succeeded,
|
|
5139
|
+
actions_failed,
|
|
5140
|
+
restart_required: false,
|
|
5141
|
+
verification_passed: false,
|
|
5142
|
+
status_label: "needs_user_action",
|
|
5143
|
+
status_action: "add_source",
|
|
5144
|
+
action_required: true,
|
|
5145
|
+
diagnostics: {
|
|
5146
|
+
message: "No project resolved. Set WHISPER_PROJECT or pass project."
|
|
5147
|
+
}
|
|
5148
|
+
};
|
|
5149
|
+
}
|
|
5150
|
+
actions_succeeded.push("resolve_project");
|
|
5151
|
+
actions_attempted.push("resolve_workspace_trust");
|
|
5152
|
+
const beforePreflight = await resolveRepoGroundingPreflight({
|
|
5153
|
+
query: "how does this project work",
|
|
5154
|
+
path: input.path,
|
|
5155
|
+
workspace_id: input.workspace_id,
|
|
5156
|
+
project: resolvedProject
|
|
5157
|
+
});
|
|
5158
|
+
actions_succeeded.push("resolve_workspace_trust");
|
|
5159
|
+
actions_attempted.push("runtime_mode_check");
|
|
5160
|
+
if (allowRestartHint && RUNTIME_MODE === "remote" && (beforePreflight.project_retrieval_readiness === "project_bound_no_repo_source" || beforePreflight.retrieval_readiness === "local_fallback")) {
|
|
5161
|
+
actions_failed.push("runtime_mode_check:remote_mode_blocks_local_repair");
|
|
5162
|
+
restartRequired = true;
|
|
5163
|
+
} else {
|
|
5164
|
+
actions_succeeded.push("runtime_mode_check");
|
|
5165
|
+
}
|
|
5166
|
+
actions_attempted.push("refresh_workspace_index_metadata");
|
|
5167
|
+
let refreshResult = null;
|
|
5168
|
+
try {
|
|
5169
|
+
if (apply) {
|
|
5170
|
+
refreshResult = await runBackgroundWorkspaceRefresh({
|
|
5171
|
+
workspace_id: beforePreflight.trust_state.workspace_id,
|
|
5172
|
+
root_path: beforePreflight.trust_state.root_path,
|
|
5173
|
+
force_full: repairScope === "full"
|
|
5174
|
+
});
|
|
5175
|
+
} else {
|
|
5176
|
+
refreshResult = { refreshed: false, mode: null, reason: "dry_run" };
|
|
5177
|
+
}
|
|
5178
|
+
actions_succeeded.push("refresh_workspace_index_metadata");
|
|
5179
|
+
} catch (error) {
|
|
5180
|
+
actions_failed.push(`refresh_workspace_index_metadata:${String(error?.message || error)}`);
|
|
5181
|
+
}
|
|
5182
|
+
actions_attempted.push("repair_source_readiness");
|
|
5183
|
+
let sourceRepair = {
|
|
5184
|
+
applied: false,
|
|
5185
|
+
attached: false,
|
|
5186
|
+
detail: "not_required",
|
|
5187
|
+
hint: null
|
|
5188
|
+
};
|
|
5189
|
+
if (beforePreflight.project_retrieval_readiness === "project_bound_no_repo_source") {
|
|
5190
|
+
const hint = buildSourceRepairHint({
|
|
5191
|
+
root_path: beforePreflight.trust_state.root_path,
|
|
5192
|
+
project_ref: beforePreflight.trust_state.project_ref
|
|
5193
|
+
});
|
|
5194
|
+
sourceRepair = {
|
|
5195
|
+
applied: apply && repairScope === "full",
|
|
5196
|
+
attached: false,
|
|
5197
|
+
detail: "manual_source_attach_required",
|
|
5198
|
+
hint
|
|
5199
|
+
};
|
|
5200
|
+
if (apply && repairScope === "full") {
|
|
5201
|
+
try {
|
|
5202
|
+
const attach = await attemptDeterministicSourceAttach({
|
|
5203
|
+
project: resolvedProject,
|
|
5204
|
+
root_path: beforePreflight.trust_state.root_path
|
|
5205
|
+
});
|
|
5206
|
+
sourceRepair = {
|
|
5207
|
+
applied: true,
|
|
5208
|
+
attached: attach.attached,
|
|
5209
|
+
detail: attach.detail,
|
|
5210
|
+
hint
|
|
5211
|
+
};
|
|
5212
|
+
if (attach.attached) {
|
|
5213
|
+
actions_succeeded.push("repair_source_readiness");
|
|
5214
|
+
} else {
|
|
5215
|
+
actions_failed.push(`repair_source_readiness:${attach.detail}`);
|
|
5216
|
+
}
|
|
5217
|
+
} catch (error) {
|
|
5218
|
+
actions_failed.push(`repair_source_readiness:${String(error?.message || error)}`);
|
|
5219
|
+
}
|
|
5220
|
+
} else {
|
|
5221
|
+
actions_failed.push("repair_source_readiness:manual_source_attach_required");
|
|
5222
|
+
}
|
|
5223
|
+
} else {
|
|
5224
|
+
actions_succeeded.push("repair_source_readiness");
|
|
5225
|
+
}
|
|
5226
|
+
const afterPreflight = await resolveRepoGroundingPreflight({
|
|
5227
|
+
query: "how does this project work",
|
|
5228
|
+
path: beforePreflight.trust_state.root_path,
|
|
5229
|
+
workspace_id: beforePreflight.trust_state.workspace_id,
|
|
5230
|
+
project: resolvedProject
|
|
5231
|
+
});
|
|
5232
|
+
const semanticStats = getWorkspaceSemanticFailureStats(afterPreflight.trust_state.workspace_id);
|
|
5233
|
+
const trustScore = computeTrustScore({
|
|
5234
|
+
retrieval_readiness: afterPreflight.retrieval_readiness,
|
|
5235
|
+
workspace_health: afterPreflight.trust_state.health,
|
|
5236
|
+
semantic_failure_rate: semanticStats.rate
|
|
5237
|
+
});
|
|
5238
|
+
persistTrustScore(afterPreflight.trust_state.workspace_id, trustScore);
|
|
5239
|
+
const autoHeal = shouldAutoHeal({
|
|
5240
|
+
retrieval_readiness: afterPreflight.retrieval_readiness,
|
|
5241
|
+
trust_score: trustScore,
|
|
5242
|
+
semantic_failure_rate: semanticStats.rate,
|
|
5243
|
+
semantic_attempts: semanticStats.attempts
|
|
5244
|
+
});
|
|
5245
|
+
actions_attempted.push("verification_query");
|
|
5246
|
+
const verification = await runAutoRepairVerification({
|
|
5247
|
+
project: resolvedProject,
|
|
5248
|
+
preflight: afterPreflight
|
|
5249
|
+
});
|
|
5250
|
+
if (verification.passed) actions_succeeded.push("verification_query");
|
|
5251
|
+
else actions_failed.push(`verification_query:${verification.detail}`);
|
|
5252
|
+
const rootCause = resolveAutoRepairRootCause({
|
|
5253
|
+
restart_required: restartRequired,
|
|
5254
|
+
trust_health: beforePreflight.trust_state.health,
|
|
5255
|
+
project_readiness: beforePreflight.project_retrieval_readiness,
|
|
5256
|
+
retrieval_readiness: beforePreflight.retrieval_readiness,
|
|
5257
|
+
semantic_failure_rate: semanticStats.rate,
|
|
5258
|
+
semantic_attempts: semanticStats.attempts
|
|
5259
|
+
});
|
|
5260
|
+
const statusContract = statusContractForReadiness({
|
|
5261
|
+
retrieval_readiness: afterPreflight.retrieval_readiness,
|
|
5262
|
+
workspace_health: afterPreflight.trust_state.health,
|
|
5263
|
+
root_cause_code: rootCause,
|
|
5264
|
+
force_repairing: autoHeal && rootCause === "none"
|
|
5265
|
+
});
|
|
5266
|
+
const verificationPassed = verification.passed;
|
|
5267
|
+
const effectiveStatusAction = statusContract.status_action;
|
|
5268
|
+
const effectiveActionRequired = statusContract.action_required;
|
|
5269
|
+
const transitionImproved = isStrictlyBetterReadiness(
|
|
5270
|
+
beforePreflight.retrieval_readiness,
|
|
5271
|
+
afterPreflight.retrieval_readiness
|
|
5272
|
+
);
|
|
5273
|
+
const explicitBlocker = effectiveActionRequired;
|
|
5274
|
+
const recommendedNextCalls = sanitizeRecommendedNextCalls([
|
|
5275
|
+
...recommendedNextCallsForRootCause(rootCause),
|
|
5276
|
+
...afterPreflight.recommended_next_calls
|
|
5277
|
+
]);
|
|
5278
|
+
return {
|
|
5279
|
+
root_cause_code: rootCause,
|
|
5280
|
+
actions_attempted,
|
|
5281
|
+
actions_succeeded,
|
|
5282
|
+
actions_failed,
|
|
5283
|
+
restart_required: restartRequired,
|
|
5284
|
+
verification_passed: verificationPassed,
|
|
5285
|
+
status_label: statusContract.status_label,
|
|
5286
|
+
status_action: effectiveStatusAction,
|
|
5287
|
+
action_required: effectiveActionRequired,
|
|
5288
|
+
recommended_next_calls: recommendedNextCalls,
|
|
5289
|
+
diagnostics: {
|
|
5290
|
+
runtime_mode: RUNTIME_MODE,
|
|
5291
|
+
workspace_id: afterPreflight.trust_state.workspace_id,
|
|
5292
|
+
root_path: afterPreflight.trust_state.root_path,
|
|
5293
|
+
project_ref: afterPreflight.trust_state.project_ref,
|
|
5294
|
+
retrieval_readiness_before: beforePreflight.retrieval_readiness,
|
|
5295
|
+
retrieval_readiness_after: afterPreflight.retrieval_readiness,
|
|
5296
|
+
project_retrieval_readiness_after: afterPreflight.project_retrieval_readiness,
|
|
5297
|
+
retrieval_readiness_label: retrievalReadinessLabel(afterPreflight.retrieval_readiness),
|
|
5298
|
+
retrieval_readiness_action: retrievalReadinessAction(afterPreflight.retrieval_readiness),
|
|
5299
|
+
trust_score: trustScore,
|
|
5300
|
+
semantic_failure_rate: semanticStats.rate,
|
|
5301
|
+
semantic_attempts: semanticStats.attempts,
|
|
5302
|
+
refresh: refreshResult,
|
|
5303
|
+
source_repair: sourceRepair,
|
|
5304
|
+
verification,
|
|
5305
|
+
auto_heal_triggered: autoHeal,
|
|
5306
|
+
transition_improved: transitionImproved,
|
|
5307
|
+
explicit_blocker: explicitBlocker,
|
|
5308
|
+
recommended_next_calls: recommendedNextCalls,
|
|
5309
|
+
restart_hint: restartRequired ? "Set WHISPER_MCP_MODE=auto in MCP config and restart client." : null
|
|
5310
|
+
}
|
|
5311
|
+
};
|
|
5312
|
+
}
|
|
4634
5313
|
function toTextResult(payload) {
|
|
4635
5314
|
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
4636
5315
|
}
|
|
@@ -4710,29 +5389,69 @@ async function searchMemoriesForContextQuery(args) {
|
|
|
4710
5389
|
}
|
|
4711
5390
|
async function runContextQueryMemoryRescue(args) {
|
|
4712
5391
|
const scoped = await searchMemoriesForContextQuery(args);
|
|
4713
|
-
const
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
}
|
|
4717
|
-
if (args.user_id || args.session_id) {
|
|
4718
|
-
return { results: [], rescue_mode: null };
|
|
4719
|
-
}
|
|
4720
|
-
const broad = await searchMemoriesForContextQuery({
|
|
5392
|
+
const personalResults = formatCanonicalMemoryResults(scoped);
|
|
5393
|
+
const sharedUserId = sharedProjectMemoryUserId(args.project);
|
|
5394
|
+
const shared = args.user_id === sharedUserId ? { results: [] } : await searchMemoriesForContextQuery({
|
|
4721
5395
|
project: args.project,
|
|
4722
5396
|
query: args.query,
|
|
5397
|
+
user_id: sharedUserId,
|
|
4723
5398
|
top_k: args.top_k
|
|
4724
5399
|
});
|
|
4725
|
-
|
|
5400
|
+
const sharedResults = formatCanonicalMemoryResults(shared);
|
|
5401
|
+
const deduped = /* @__PURE__ */ new Set();
|
|
5402
|
+
const combined = [
|
|
5403
|
+
...personalResults.map((result) => ({
|
|
5404
|
+
...result,
|
|
5405
|
+
memory_scope: "personal",
|
|
5406
|
+
ranking_score: clamp012(Number(result.similarity ?? 0.5) + 0.08)
|
|
5407
|
+
})),
|
|
5408
|
+
...sharedResults.map((result) => ({
|
|
5409
|
+
...result,
|
|
5410
|
+
memory_scope: "shared_project",
|
|
5411
|
+
ranking_score: clamp012(Number(result.similarity ?? 0.5))
|
|
5412
|
+
}))
|
|
5413
|
+
].filter((result) => {
|
|
5414
|
+
if (!result.id) return false;
|
|
5415
|
+
if (deduped.has(result.id)) return false;
|
|
5416
|
+
deduped.add(result.id);
|
|
5417
|
+
return true;
|
|
5418
|
+
}).sort((a, b) => b.ranking_score - a.ranking_score);
|
|
5419
|
+
const rescueMode = combined.length === 0 ? null : sharedResults.length > 0 ? "scoped_plus_shared" : "scoped_only";
|
|
5420
|
+
return {
|
|
5421
|
+
personal_results: personalResults,
|
|
5422
|
+
shared_results: sharedResults,
|
|
5423
|
+
combined_results: combined,
|
|
5424
|
+
rescue_mode: rescueMode
|
|
5425
|
+
};
|
|
4726
5426
|
}
|
|
4727
5427
|
function renderContextQueryMemoryRescue(args) {
|
|
4728
|
-
const lines = args.
|
|
4729
|
-
(result, index) => `${index + 1}. [${result.memory_type || "memory"}, score: ${result.
|
|
5428
|
+
const lines = args.combined_results.map(
|
|
5429
|
+
(result, index) => `${index + 1}. [${result.memory_scope}, ${result.memory_type || "memory"}, score: ${result.ranking_score.toFixed(2)}] ${result.content}`
|
|
4730
5430
|
);
|
|
4731
|
-
|
|
4732
|
-
return `Found ${args.results.length} memory result(s) (${scopeLabel}):
|
|
5431
|
+
return `Found ${args.combined_results.length} memory result(s) (project=${args.project}, user=${args.scope.userId}, session=${args.scope.sessionId}, personal=${args.personal_results.length}, shared=${args.shared_results.length}, ordering=personal_then_shared_bias):
|
|
4733
5432
|
|
|
4734
5433
|
${lines.join("\n\n")}`;
|
|
4735
5434
|
}
|
|
5435
|
+
function memoryRescueResultsToEvidence(args) {
|
|
5436
|
+
return args.hits.map(
|
|
5437
|
+
(hit) => toEvidenceRef({
|
|
5438
|
+
id: `memory:${hit.id || randomUUID()}`,
|
|
5439
|
+
source: "memory",
|
|
5440
|
+
document: "memory",
|
|
5441
|
+
content: hit.content,
|
|
5442
|
+
score: hit.ranking_score,
|
|
5443
|
+
retrieval_source: "memory",
|
|
5444
|
+
metadata: {
|
|
5445
|
+
path: `memory://${hit.memory_scope}/${hit.id || "unknown"}`,
|
|
5446
|
+
line_start: 1,
|
|
5447
|
+
line_end: 1,
|
|
5448
|
+
score: hit.ranking_score,
|
|
5449
|
+
memory_scope: hit.memory_scope,
|
|
5450
|
+
memory_type: hit.memory_type || "factual"
|
|
5451
|
+
}
|
|
5452
|
+
}, args.workspaceId, "memory")
|
|
5453
|
+
);
|
|
5454
|
+
}
|
|
4736
5455
|
function likelyEmbeddingFailure(error) {
|
|
4737
5456
|
const message = String(error?.message || error || "").toLowerCase();
|
|
4738
5457
|
return message.includes("embedding") || message.includes("vector") || message.includes("timeout") || message.includes("timed out") || message.includes("temporarily unavailable");
|
|
@@ -4753,7 +5472,13 @@ async function queryWithDegradedFallback(params) {
|
|
|
4753
5472
|
hybrid: true,
|
|
4754
5473
|
rerank: true
|
|
4755
5474
|
});
|
|
4756
|
-
return {
|
|
5475
|
+
return {
|
|
5476
|
+
response,
|
|
5477
|
+
degraded_mode: false,
|
|
5478
|
+
semantic_status: "ok",
|
|
5479
|
+
fallback_mode: "none",
|
|
5480
|
+
recommended_fixes: []
|
|
5481
|
+
};
|
|
4757
5482
|
} catch (error) {
|
|
4758
5483
|
if (!likelyEmbeddingFailure(error)) throw error;
|
|
4759
5484
|
const response = await whisper.query({
|
|
@@ -4776,7 +5501,13 @@ async function queryWithDegradedFallback(params) {
|
|
|
4776
5501
|
response,
|
|
4777
5502
|
degraded_mode: true,
|
|
4778
5503
|
degraded_reason: "Embedding/graph path unavailable; lexical fallback used.",
|
|
4779
|
-
recommendation: "Check embedding service health, then re-run for full hybrid quality."
|
|
5504
|
+
recommendation: "Check embedding service health, then re-run for full hybrid quality.",
|
|
5505
|
+
semantic_status: "failed",
|
|
5506
|
+
fallback_mode: "lexical_backend",
|
|
5507
|
+
recommended_fixes: [
|
|
5508
|
+
"Run fix to auto-repair retrieval health.",
|
|
5509
|
+
"If this persists, re-authenticate and reindex workspace sources."
|
|
5510
|
+
]
|
|
4780
5511
|
};
|
|
4781
5512
|
}
|
|
4782
5513
|
}
|
|
@@ -4888,6 +5619,47 @@ async function runSearchCodeSearch(args) {
|
|
|
4888
5619
|
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."
|
|
4889
5620
|
};
|
|
4890
5621
|
}
|
|
5622
|
+
function retrievalReadinessLabel(readiness) {
|
|
5623
|
+
if (readiness === "project_repo_source_ready") return "Project retrieval is healthy.";
|
|
5624
|
+
if (readiness === "project_repo_source_stale") return "Project source exists but is not ready.";
|
|
5625
|
+
if (readiness === "project_bound_no_repo_source") return "No matching project source is connected.";
|
|
5626
|
+
if (readiness === "project_unverified") return "Project/source verification failed.";
|
|
5627
|
+
if (readiness === "local_fallback") return "Using local fallback retrieval.";
|
|
5628
|
+
if (readiness === "no_project") return "No project is bound to this workspace.";
|
|
5629
|
+
return "Retrieval readiness is unknown.";
|
|
5630
|
+
}
|
|
5631
|
+
function retrievalReadinessAction(readiness) {
|
|
5632
|
+
if (readiness === "project_repo_source_ready") return "none";
|
|
5633
|
+
if (readiness === "project_repo_source_stale") return "Run fix or index.workspace_run to refresh workspace trust.";
|
|
5634
|
+
if (readiness === "project_bound_no_repo_source") {
|
|
5635
|
+
return RUNTIME_MODE === "remote" ? "Connect a repo source with context.add_source, then run fix." : "Run index.local_scan_ingest or fix.";
|
|
5636
|
+
}
|
|
5637
|
+
if (readiness === "project_unverified") return "Re-authenticate your API key and run fix.";
|
|
5638
|
+
if (readiness === "local_fallback") return "Run fix to restore project-grounded retrieval.";
|
|
5639
|
+
if (readiness === "no_project") return "Provide --project/WHISPER_PROJECT and run fix.";
|
|
5640
|
+
return "Run fix.";
|
|
5641
|
+
}
|
|
5642
|
+
function buildRecommendedFixes(args) {
|
|
5643
|
+
const fixes = /* @__PURE__ */ new Set();
|
|
5644
|
+
if (args.semantic_status === "failed") {
|
|
5645
|
+
fixes.add("Run fix to auto-repair retrieval health.");
|
|
5646
|
+
}
|
|
5647
|
+
if (args.fallback_mode === "lexical_rescue" || args.fallback_mode === "lexical_backend") {
|
|
5648
|
+
fixes.add("Check embedding/vector service health and retry.");
|
|
5649
|
+
}
|
|
5650
|
+
if (args.retrieval_readiness === "project_bound_no_repo_source") {
|
|
5651
|
+
fixes.add(
|
|
5652
|
+
RUNTIME_MODE === "remote" ? "Add a matching source with context.add_source." : "Ingest local files with index.local_scan_ingest."
|
|
5653
|
+
);
|
|
5654
|
+
}
|
|
5655
|
+
if (args.retrieval_readiness === "project_unverified") {
|
|
5656
|
+
fixes.add("Re-authenticate (valid WHISPER_API_KEY) and rerun fix.");
|
|
5657
|
+
}
|
|
5658
|
+
if (args.retrieval_readiness === "project_repo_source_stale") {
|
|
5659
|
+
fixes.add("Refresh workspace metadata via index.workspace_run.");
|
|
5660
|
+
}
|
|
5661
|
+
return [...fixes];
|
|
5662
|
+
}
|
|
4891
5663
|
function buildLocalWorkspaceDocuments(rootPath, allowedExts, maxFiles) {
|
|
4892
5664
|
const files = collectCodeFiles(rootPath, allowedExts, maxFiles);
|
|
4893
5665
|
const documents = [];
|
|
@@ -5023,20 +5795,6 @@ function localHitsToEvidence(workspaceId, hits) {
|
|
|
5023
5795
|
)
|
|
5024
5796
|
);
|
|
5025
5797
|
}
|
|
5026
|
-
function renderLocalWorkspaceContext(args) {
|
|
5027
|
-
const lines = args.hits.map((hit, index) => {
|
|
5028
|
-
const location = hit.line_end && hit.line_end !== hit.line_start ? `${hit.id}:${hit.line_start}-${hit.line_end}` : `${hit.id}:${hit.line_start}`;
|
|
5029
|
-
return `${index + 1}. [${location}, score: ${hit.score.toFixed(2)}, mode: ${hit.search_mode}] ${hit.raw_snippet || hit.snippet || hit.id}`;
|
|
5030
|
-
});
|
|
5031
|
-
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}):`;
|
|
5032
|
-
const warnings = args.warnings.length ? `
|
|
5033
|
-
|
|
5034
|
-
[warnings]
|
|
5035
|
-
${args.warnings.join("\n")}` : "";
|
|
5036
|
-
return `${header}
|
|
5037
|
-
|
|
5038
|
-
${lines.join("\n\n")}${warnings}`;
|
|
5039
|
-
}
|
|
5040
5798
|
async function runSearchCodeTool(args) {
|
|
5041
5799
|
const rootPath = canonicalizeWorkspacePath(args.path);
|
|
5042
5800
|
const allowedExts = args.file_types ? new Set(args.file_types) : CODE_EXTENSIONS;
|
|
@@ -5044,12 +5802,21 @@ async function runSearchCodeTool(args) {
|
|
|
5044
5802
|
if (files.length === 0) {
|
|
5045
5803
|
const workspace = await resolveWorkspaceTrust({ path: rootPath });
|
|
5046
5804
|
const sharedWarnings = [...workspace.warnings];
|
|
5805
|
+
const semanticStatus = "ok";
|
|
5806
|
+
const fallbackMode = "none";
|
|
5047
5807
|
return {
|
|
5048
5808
|
tool: "search_code",
|
|
5049
5809
|
query: args.query,
|
|
5050
5810
|
path: rootPath,
|
|
5051
5811
|
results: [],
|
|
5052
5812
|
count: 0,
|
|
5813
|
+
semantic_status: semanticStatus,
|
|
5814
|
+
fallback_mode: fallbackMode,
|
|
5815
|
+
recommended_fixes: buildRecommendedFixes({
|
|
5816
|
+
retrieval_readiness: workspace.project_ref ? "project_repo_source_ready" : "no_project",
|
|
5817
|
+
semantic_status: semanticStatus,
|
|
5818
|
+
fallback_mode: fallbackMode
|
|
5819
|
+
}),
|
|
5053
5820
|
warnings: sharedWarnings,
|
|
5054
5821
|
diagnostics: {
|
|
5055
5822
|
workspace_id: workspace.workspace_id,
|
|
@@ -5078,6 +5845,13 @@ async function runSearchCodeTool(args) {
|
|
|
5078
5845
|
path: rootPath,
|
|
5079
5846
|
results: localRetrieval.results,
|
|
5080
5847
|
count: localRetrieval.results.length,
|
|
5848
|
+
semantic_status: semanticStatusFromSearchMode(localRetrieval.diagnostics.search_mode),
|
|
5849
|
+
fallback_mode: fallbackModeFromSearchMode(localRetrieval.diagnostics.search_mode),
|
|
5850
|
+
recommended_fixes: buildRecommendedFixes({
|
|
5851
|
+
retrieval_readiness: localRetrieval.workspace.project_ref ? "local_fallback" : "no_project",
|
|
5852
|
+
semantic_status: semanticStatusFromSearchMode(localRetrieval.diagnostics.search_mode),
|
|
5853
|
+
fallback_mode: fallbackModeFromSearchMode(localRetrieval.diagnostics.search_mode)
|
|
5854
|
+
}),
|
|
5081
5855
|
warnings: localRetrieval.warnings,
|
|
5082
5856
|
diagnostics: localRetrieval.diagnostics
|
|
5083
5857
|
};
|
|
@@ -5331,7 +6105,8 @@ function renderScopedMcpConfig(project, source, client) {
|
|
|
5331
6105
|
env: {
|
|
5332
6106
|
WHISPER_API_KEY: "wctx_...",
|
|
5333
6107
|
WHISPER_PROJECT: project,
|
|
5334
|
-
WHISPER_SCOPE_SOURCE: source
|
|
6108
|
+
WHISPER_SCOPE_SOURCE: source,
|
|
6109
|
+
WHISPER_MCP_MODE: "auto"
|
|
5335
6110
|
}
|
|
5336
6111
|
};
|
|
5337
6112
|
if (client === "json") {
|
|
@@ -5437,6 +6212,7 @@ server.tool(
|
|
|
5437
6212
|
},
|
|
5438
6213
|
async ({ workspace_id, path, mode, max_files }) => {
|
|
5439
6214
|
try {
|
|
6215
|
+
const startAt = Date.now();
|
|
5440
6216
|
const identity = resolveWorkspaceIdentity({ path, workspace_id });
|
|
5441
6217
|
const rootPath = identity.root_path;
|
|
5442
6218
|
const workspaceId = identity.workspace_id;
|
|
@@ -5445,11 +6221,17 @@ server.tool(
|
|
|
5445
6221
|
const fileStats = countCodeFiles(rootPath, max_files);
|
|
5446
6222
|
const coverage = Math.max(0, Math.min(1, fileStats.total / Math.max(1, max_files)));
|
|
5447
6223
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6224
|
+
const snapshot = computeWorkspaceSnapshot(rootPath);
|
|
5448
6225
|
workspace.root_path = rootPath;
|
|
5449
6226
|
workspace.index_metadata = {
|
|
5450
6227
|
last_indexed_at: now,
|
|
5451
6228
|
last_indexed_commit: getGitHead(rootPath),
|
|
5452
|
-
coverage: mode === "full" ? 1 : coverage
|
|
6229
|
+
coverage: mode === "full" ? 1 : coverage,
|
|
6230
|
+
indexed_files: fileStats.total,
|
|
6231
|
+
last_auto_refresh_at: now,
|
|
6232
|
+
...mode === "full" ? { last_full_refresh_at: now } : {},
|
|
6233
|
+
last_snapshot_hash: snapshot.hash,
|
|
6234
|
+
last_snapshot_entries: snapshot.entries
|
|
5453
6235
|
};
|
|
5454
6236
|
saveState(state);
|
|
5455
6237
|
const payload = {
|
|
@@ -5458,7 +6240,7 @@ server.tool(
|
|
|
5458
6240
|
mode,
|
|
5459
6241
|
indexed_files: fileStats.total,
|
|
5460
6242
|
skipped_files: fileStats.skipped,
|
|
5461
|
-
duration_ms:
|
|
6243
|
+
duration_ms: Date.now() - startAt,
|
|
5462
6244
|
warnings: fileStats.total === 0 ? ["No code files discovered for indexing."] : [],
|
|
5463
6245
|
index_metadata: workspace.index_metadata
|
|
5464
6246
|
};
|
|
@@ -5486,24 +6268,325 @@ server.tool(
|
|
|
5486
6268
|
}
|
|
5487
6269
|
const result = await ingestLocalPath({
|
|
5488
6270
|
project: resolvedProject,
|
|
5489
|
-
path: path || process.cwd(),
|
|
5490
|
-
glob,
|
|
5491
|
-
max_files,
|
|
5492
|
-
chunk_chars
|
|
6271
|
+
path: path || process.cwd(),
|
|
6272
|
+
glob,
|
|
6273
|
+
max_files,
|
|
6274
|
+
chunk_chars
|
|
6275
|
+
});
|
|
6276
|
+
return toTextResult({
|
|
6277
|
+
source_id: `local_${result.workspace_id}`,
|
|
6278
|
+
status: "ready",
|
|
6279
|
+
job_id: `local_ingest_${Date.now()}`,
|
|
6280
|
+
index_started: true,
|
|
6281
|
+
warnings: result.skipped.slice(0, 20),
|
|
6282
|
+
details: result
|
|
6283
|
+
});
|
|
6284
|
+
} catch (error) {
|
|
6285
|
+
return { content: [{ type: "text", text: `Error: ${error.message}` }] };
|
|
6286
|
+
}
|
|
6287
|
+
}
|
|
6288
|
+
);
|
|
6289
|
+
server.tool(
|
|
6290
|
+
"index.auto_repair",
|
|
6291
|
+
"Diagnose and apply deterministic retrieval/setup repairs. This is the canonical zero-stress repair path.",
|
|
6292
|
+
{
|
|
6293
|
+
path: z.string().optional(),
|
|
6294
|
+
workspace_id: z.string().optional(),
|
|
6295
|
+
project: z.string().optional(),
|
|
6296
|
+
apply: z.boolean().optional().default(true),
|
|
6297
|
+
repair_scope: z.enum(["safe", "full"]).optional().default("safe"),
|
|
6298
|
+
allow_restart_hint: z.boolean().optional().default(true)
|
|
6299
|
+
},
|
|
6300
|
+
async ({ path, workspace_id, project, apply, repair_scope, allow_restart_hint }) => {
|
|
6301
|
+
try {
|
|
6302
|
+
const payload = await runAutoRepairFlow({
|
|
6303
|
+
path,
|
|
6304
|
+
workspace_id,
|
|
6305
|
+
project,
|
|
6306
|
+
apply,
|
|
6307
|
+
repair_scope,
|
|
6308
|
+
allow_restart_hint
|
|
6309
|
+
});
|
|
6310
|
+
return toTextResult(payload);
|
|
6311
|
+
} catch (error) {
|
|
6312
|
+
return primaryToolError(error.message, "auto_repair_failed");
|
|
6313
|
+
}
|
|
6314
|
+
}
|
|
6315
|
+
);
|
|
6316
|
+
server.tool(
|
|
6317
|
+
"fix",
|
|
6318
|
+
"Primary alias for zero-stress setup/retrieval repair. Delegates to index.auto_repair.",
|
|
6319
|
+
{
|
|
6320
|
+
path: z.string().optional(),
|
|
6321
|
+
workspace_id: z.string().optional(),
|
|
6322
|
+
project: z.string().optional(),
|
|
6323
|
+
apply: z.boolean().optional().default(true),
|
|
6324
|
+
repair_scope: z.enum(["safe", "full"]).optional().default("safe"),
|
|
6325
|
+
allow_restart_hint: z.boolean().optional().default(true)
|
|
6326
|
+
},
|
|
6327
|
+
async ({ path, workspace_id, project, apply, repair_scope, allow_restart_hint }) => {
|
|
6328
|
+
try {
|
|
6329
|
+
const payload = await runAutoRepairFlow({
|
|
6330
|
+
path,
|
|
6331
|
+
workspace_id,
|
|
6332
|
+
project,
|
|
6333
|
+
apply,
|
|
6334
|
+
repair_scope,
|
|
6335
|
+
allow_restart_hint
|
|
6336
|
+
});
|
|
6337
|
+
return toTextResult(payload);
|
|
6338
|
+
} catch (error) {
|
|
6339
|
+
return primaryToolError(error.message, "fix_failed");
|
|
6340
|
+
}
|
|
6341
|
+
}
|
|
6342
|
+
);
|
|
6343
|
+
async function runUnifiedContextRetrieval(params) {
|
|
6344
|
+
const preflight = await resolveRepoGroundingPreflight({
|
|
6345
|
+
query: params.question,
|
|
6346
|
+
path: params.path,
|
|
6347
|
+
workspace_id: params.workspace_id,
|
|
6348
|
+
project: params.project,
|
|
6349
|
+
chunk_types: params.chunk_types
|
|
6350
|
+
});
|
|
6351
|
+
const retrievalProfile = resolveMcpRetrievalProfile(params.retrieval_profile);
|
|
6352
|
+
const backgroundRefresh = await runBackgroundWorkspaceRefresh({
|
|
6353
|
+
workspace_id: preflight.trust_state.workspace_id,
|
|
6354
|
+
root_path: preflight.trust_state.root_path,
|
|
6355
|
+
force_full: false
|
|
6356
|
+
});
|
|
6357
|
+
if (shouldAbstainForCodebaseTrust({
|
|
6358
|
+
retrievalProfile,
|
|
6359
|
+
codebaseIntent: preflight.repo_grounded,
|
|
6360
|
+
preflight
|
|
6361
|
+
})) {
|
|
6362
|
+
const abstainPayload = buildCodebaseTrustAbstainPayload({
|
|
6363
|
+
query: params.question,
|
|
6364
|
+
preflight,
|
|
6365
|
+
retrievalProfile
|
|
6366
|
+
});
|
|
6367
|
+
return {
|
|
6368
|
+
...abstainPayload,
|
|
6369
|
+
semantic_status: "failed",
|
|
6370
|
+
fallback_mode: "none",
|
|
6371
|
+
recommended_fixes: buildRecommendedFixes({
|
|
6372
|
+
retrieval_readiness: preflight.retrieval_readiness,
|
|
6373
|
+
semantic_status: "failed",
|
|
6374
|
+
fallback_mode: "none"
|
|
6375
|
+
}),
|
|
6376
|
+
status_label: "blocked",
|
|
6377
|
+
status_action: "reindex",
|
|
6378
|
+
action_required: true,
|
|
6379
|
+
diagnostics: {
|
|
6380
|
+
retrieval_profile: retrievalProfile,
|
|
6381
|
+
background_refresh: backgroundRefresh
|
|
6382
|
+
}
|
|
6383
|
+
};
|
|
6384
|
+
}
|
|
6385
|
+
const resolvedProject = preflight.trust_state.project_ref || await resolveProjectRef(params.project);
|
|
6386
|
+
const scope = resolveMcpScope({
|
|
6387
|
+
project: resolvedProject || params.project,
|
|
6388
|
+
user_id: params.user_id,
|
|
6389
|
+
session_id: params.session_id,
|
|
6390
|
+
path: preflight.trust_state.root_path
|
|
6391
|
+
});
|
|
6392
|
+
const topK = params.top_k ?? 12;
|
|
6393
|
+
let semanticStatus = "ok";
|
|
6394
|
+
let fallbackMode = "none";
|
|
6395
|
+
let contextText = "";
|
|
6396
|
+
let evidence = [];
|
|
6397
|
+
let warnings = [...preflight.warnings];
|
|
6398
|
+
let retrievalReadiness = preflight.retrieval_readiness;
|
|
6399
|
+
let retrievalRoute = preflight.retrieval_route;
|
|
6400
|
+
let latencyMs = 0;
|
|
6401
|
+
let memoryContribution = null;
|
|
6402
|
+
if (preflight.retrieval_route === "local_workspace_fallback") {
|
|
6403
|
+
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
6404
|
+
query: params.question,
|
|
6405
|
+
path: preflight.trust_state.root_path,
|
|
6406
|
+
project: resolvedProject || params.project,
|
|
6407
|
+
top_k: topK
|
|
6408
|
+
});
|
|
6409
|
+
semanticStatus = semanticStatusFromSearchMode(localRetrieval.diagnostics.search_mode);
|
|
6410
|
+
fallbackMode = fallbackModeFromSearchMode(localRetrieval.diagnostics.search_mode);
|
|
6411
|
+
evidence = localHitsToEvidence(preflight.trust_state.workspace_id, localRetrieval.results);
|
|
6412
|
+
contextText = evidence.map((item) => `[${renderCitation(item)}] ${item.snippet || "Relevant context found."}`).join("\n");
|
|
6413
|
+
warnings = Array.from(/* @__PURE__ */ new Set([...warnings, ...localRetrieval.warnings]));
|
|
6414
|
+
retrievalReadiness = "local_fallback";
|
|
6415
|
+
retrievalRoute = "local_workspace_fallback";
|
|
6416
|
+
} else if (!resolvedProject) {
|
|
6417
|
+
contextText = "";
|
|
6418
|
+
evidence = [];
|
|
6419
|
+
retrievalRoute = "none";
|
|
6420
|
+
} else {
|
|
6421
|
+
const queryResult = await queryWithDegradedFallback({
|
|
6422
|
+
project: resolvedProject,
|
|
6423
|
+
query: params.question,
|
|
6424
|
+
top_k: topK,
|
|
6425
|
+
include_memories: preflight.repo_grounded ? false : params.include_memories,
|
|
6426
|
+
include_graph: params.include_graph,
|
|
6427
|
+
session_id: params.session_id,
|
|
6428
|
+
user_id: scope.userId,
|
|
6429
|
+
source_ids: preflight.repo_grounded ? preflight.matched_source_ids : void 0,
|
|
6430
|
+
retrieval_profile: retrievalProfile,
|
|
6431
|
+
include_parent_content: params.include_parent_content
|
|
6432
|
+
});
|
|
6433
|
+
latencyMs = queryResult.response.meta?.latency_ms || 0;
|
|
6434
|
+
semanticStatus = queryResult.semantic_status || "ok";
|
|
6435
|
+
fallbackMode = queryResult.fallback_mode || "none";
|
|
6436
|
+
const rawResults = preflight.repo_grounded ? filterProjectRepoResults(queryResult.response.results || [], preflight.matched_source_ids) : queryResult.response.results || [];
|
|
6437
|
+
if (preflight.repo_grounded && rawResults.length === 0) {
|
|
6438
|
+
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
6439
|
+
query: params.question,
|
|
6440
|
+
path: preflight.trust_state.root_path,
|
|
6441
|
+
project: resolvedProject,
|
|
6442
|
+
top_k: topK
|
|
6443
|
+
});
|
|
6444
|
+
semanticStatus = semanticStatusFromSearchMode(localRetrieval.diagnostics.search_mode);
|
|
6445
|
+
fallbackMode = fallbackModeFromSearchMode(localRetrieval.diagnostics.search_mode);
|
|
6446
|
+
evidence = localHitsToEvidence(preflight.trust_state.workspace_id, localRetrieval.results);
|
|
6447
|
+
contextText = evidence.map((item) => `[${renderCitation(item)}] ${item.snippet || "Relevant context found."}`).join("\n");
|
|
6448
|
+
warnings = Array.from(/* @__PURE__ */ new Set([...warnings, ...localRetrieval.warnings]));
|
|
6449
|
+
retrievalReadiness = "local_fallback";
|
|
6450
|
+
retrievalRoute = "local_workspace_fallback";
|
|
6451
|
+
} else {
|
|
6452
|
+
contextText = queryResult.response.context || "";
|
|
6453
|
+
evidence = rawResults.map((r) => toEvidenceRef(r, preflight.trust_state.workspace_id, "semantic"));
|
|
6454
|
+
if (queryResult.degraded_mode) {
|
|
6455
|
+
warnings.push(queryResult.degraded_reason || "Lexical backend fallback active.");
|
|
6456
|
+
}
|
|
6457
|
+
retrievalRoute = preflight.repo_grounded ? "project_repo" : "none";
|
|
6458
|
+
}
|
|
6459
|
+
}
|
|
6460
|
+
if (resolvedProject && params.include_memories === true && !preflight.repo_grounded) {
|
|
6461
|
+
try {
|
|
6462
|
+
memoryContribution = await runContextQueryMemoryRescue({
|
|
6463
|
+
project: resolvedProject,
|
|
6464
|
+
query: params.question,
|
|
6465
|
+
user_id: scope.userId,
|
|
6466
|
+
session_id: params.session_id,
|
|
6467
|
+
top_k: Math.max(4, Math.min(topK, 8))
|
|
5493
6468
|
});
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
6469
|
+
if (memoryContribution.combined_results.length > 0) {
|
|
6470
|
+
const memoryEvidence = memoryRescueResultsToEvidence({
|
|
6471
|
+
workspaceId: preflight.trust_state.workspace_id,
|
|
6472
|
+
hits: memoryContribution.combined_results
|
|
6473
|
+
});
|
|
6474
|
+
const existingSourceIds = new Set(evidence.map((item) => item.source_id));
|
|
6475
|
+
const dedupedMemoryEvidence = memoryEvidence.filter((item) => !existingSourceIds.has(item.source_id));
|
|
6476
|
+
evidence = [...evidence, ...dedupedMemoryEvidence];
|
|
6477
|
+
const memoryContext = renderContextQueryMemoryRescue({
|
|
6478
|
+
project: resolvedProject,
|
|
6479
|
+
scope,
|
|
6480
|
+
personal_results: memoryContribution.personal_results,
|
|
6481
|
+
shared_results: memoryContribution.shared_results,
|
|
6482
|
+
combined_results: memoryContribution.combined_results
|
|
6483
|
+
});
|
|
6484
|
+
contextText = contextText.trim().length > 0 ? `${contextText}
|
|
6485
|
+
|
|
6486
|
+
${memoryContext}` : memoryContext;
|
|
6487
|
+
if (retrievalRoute === "none") retrievalRoute = "memory_only";
|
|
6488
|
+
}
|
|
6489
|
+
} catch (error) {
|
|
6490
|
+
warnings.push(`Scoped memory contribution failed: ${String(error?.message || error)}`);
|
|
6491
|
+
}
|
|
6492
|
+
}
|
|
6493
|
+
recordSemanticAttempt(preflight.trust_state.workspace_id, semanticStatus === "failed");
|
|
6494
|
+
const semanticStats = getWorkspaceSemanticFailureStats(preflight.trust_state.workspace_id);
|
|
6495
|
+
const trustScore = computeTrustScore({
|
|
6496
|
+
retrieval_readiness: retrievalReadiness,
|
|
6497
|
+
workspace_health: preflight.trust_state.health,
|
|
6498
|
+
semantic_failure_rate: semanticStats.rate
|
|
6499
|
+
});
|
|
6500
|
+
persistTrustScore(preflight.trust_state.workspace_id, trustScore);
|
|
6501
|
+
const autoHeal = shouldAutoHeal({
|
|
6502
|
+
retrieval_readiness: retrievalReadiness,
|
|
6503
|
+
trust_score: trustScore,
|
|
6504
|
+
semantic_failure_rate: semanticStats.rate,
|
|
6505
|
+
semantic_attempts: semanticStats.attempts
|
|
6506
|
+
});
|
|
6507
|
+
let autoRepairSummary = null;
|
|
6508
|
+
if (autoHeal) {
|
|
6509
|
+
try {
|
|
6510
|
+
autoRepairSummary = await runAutoRepairFlow({
|
|
6511
|
+
path: preflight.trust_state.root_path,
|
|
6512
|
+
workspace_id: preflight.trust_state.workspace_id,
|
|
6513
|
+
project: resolvedProject || params.project,
|
|
6514
|
+
apply: true,
|
|
6515
|
+
repair_scope: "safe",
|
|
6516
|
+
allow_restart_hint: true
|
|
5501
6517
|
});
|
|
6518
|
+
warnings.push("Auto-repair executed in safe mode.");
|
|
5502
6519
|
} catch (error) {
|
|
5503
|
-
|
|
6520
|
+
warnings.push(`Auto-repair failed: ${String(error?.message || error)}`);
|
|
5504
6521
|
}
|
|
5505
6522
|
}
|
|
5506
|
-
|
|
6523
|
+
const statusContract = statusContractForReadiness({
|
|
6524
|
+
retrieval_readiness: retrievalReadiness,
|
|
6525
|
+
workspace_health: preflight.trust_state.health,
|
|
6526
|
+
semantic_status: semanticStatus,
|
|
6527
|
+
force_repairing: autoHeal
|
|
6528
|
+
});
|
|
6529
|
+
const recommendedFixes = buildRecommendedFixes({
|
|
6530
|
+
retrieval_readiness: retrievalReadiness,
|
|
6531
|
+
semantic_status: semanticStatus,
|
|
6532
|
+
fallback_mode: fallbackMode
|
|
6533
|
+
});
|
|
6534
|
+
const recommendedNextCalls = sanitizeRecommendedNextCalls([
|
|
6535
|
+
...preflight.recommended_next_calls,
|
|
6536
|
+
...semanticStatus === "failed" ? ["fix"] : []
|
|
6537
|
+
]);
|
|
6538
|
+
const payload = {
|
|
6539
|
+
question: params.question,
|
|
6540
|
+
workspace_id: preflight.trust_state.workspace_id,
|
|
6541
|
+
root_path: preflight.trust_state.root_path,
|
|
6542
|
+
trust_state: preflight.trust_state,
|
|
6543
|
+
retrieval_readiness: retrievalReadiness,
|
|
6544
|
+
retrieval_readiness_label: retrievalReadinessLabel(retrievalReadiness),
|
|
6545
|
+
retrieval_readiness_action: retrievalReadinessAction(retrievalReadiness),
|
|
6546
|
+
retrieval_route: retrievalRoute,
|
|
6547
|
+
context: contextText,
|
|
6548
|
+
evidence,
|
|
6549
|
+
total_results: evidence.length,
|
|
6550
|
+
latency_ms: latencyMs,
|
|
6551
|
+
semantic_status: semanticStatus,
|
|
6552
|
+
fallback_mode: fallbackMode,
|
|
6553
|
+
recommended_fixes: recommendedFixes,
|
|
6554
|
+
status_label: statusContract.status_label,
|
|
6555
|
+
status_action: statusContract.status_action,
|
|
6556
|
+
action_required: statusContract.action_required,
|
|
6557
|
+
warnings: Array.from(new Set(warnings)),
|
|
6558
|
+
recommended_next_calls: recommendedNextCalls,
|
|
6559
|
+
diagnostics: {
|
|
6560
|
+
scope: {
|
|
6561
|
+
project: resolvedProject || params.project || null,
|
|
6562
|
+
user_id: scope.userId,
|
|
6563
|
+
session_id: params.session_id || null
|
|
6564
|
+
},
|
|
6565
|
+
memory: {
|
|
6566
|
+
included: resolvedProject ? params.include_memories === true && !preflight.repo_grounded : false,
|
|
6567
|
+
personal_count: memoryContribution?.personal_results.length || 0,
|
|
6568
|
+
shared_count: memoryContribution?.shared_results.length || 0,
|
|
6569
|
+
combined_count: memoryContribution?.combined_results.length || 0,
|
|
6570
|
+
shared_user_id: resolvedProject ? sharedProjectMemoryUserId(resolvedProject) : null,
|
|
6571
|
+
ordering: "personal_then_shared_bias"
|
|
6572
|
+
},
|
|
6573
|
+
retrieval_profile: retrievalProfile,
|
|
6574
|
+
trust_score: trustScore,
|
|
6575
|
+
semantic_failure_rate: semanticStats.rate,
|
|
6576
|
+
auto_heal_triggered: autoHeal,
|
|
6577
|
+
auto_repair: autoRepairSummary,
|
|
6578
|
+
background_refresh: backgroundRefresh
|
|
6579
|
+
}
|
|
6580
|
+
};
|
|
6581
|
+
if (params.include_alias_warning) {
|
|
6582
|
+
payload.warnings = Array.from(/* @__PURE__ */ new Set([
|
|
6583
|
+
...payload.warnings,
|
|
6584
|
+
"deprecated_alias_use_context_query",
|
|
6585
|
+
"deprecated_alias_use_context.query"
|
|
6586
|
+
]));
|
|
6587
|
+
}
|
|
6588
|
+
return payload;
|
|
6589
|
+
}
|
|
5507
6590
|
server.tool(
|
|
5508
6591
|
"context.get_relevant",
|
|
5509
6592
|
"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.",
|
|
@@ -5522,131 +6605,23 @@ server.tool(
|
|
|
5522
6605
|
},
|
|
5523
6606
|
async ({ question, path, workspace_id, project, top_k, include_memories, include_graph, session_id, user_id, include_parent_content, retrieval_profile }) => {
|
|
5524
6607
|
try {
|
|
5525
|
-
const
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
preflight
|
|
5531
|
-
})) {
|
|
5532
|
-
return toTextResult(buildCodebaseTrustAbstainPayload({
|
|
5533
|
-
query: question,
|
|
5534
|
-
preflight,
|
|
5535
|
-
retrievalProfile
|
|
5536
|
-
}));
|
|
5537
|
-
}
|
|
5538
|
-
if (preflight.retrieval_route === "local_workspace_fallback") {
|
|
5539
|
-
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
5540
|
-
query: question,
|
|
5541
|
-
path: preflight.trust_state.root_path,
|
|
5542
|
-
project: preflight.trust_state.project_ref || project,
|
|
5543
|
-
top_k
|
|
5544
|
-
});
|
|
5545
|
-
const evidence2 = localHitsToEvidence(preflight.trust_state.workspace_id, localRetrieval.results);
|
|
5546
|
-
const payload2 = {
|
|
5547
|
-
question,
|
|
5548
|
-
workspace_id: preflight.trust_state.workspace_id,
|
|
5549
|
-
root_path: preflight.trust_state.root_path,
|
|
5550
|
-
identity_source: preflight.trust_state.identity_source,
|
|
5551
|
-
trust_state: preflight.trust_state,
|
|
5552
|
-
retrieval_readiness: preflight.retrieval_readiness,
|
|
5553
|
-
retrieval_route: preflight.retrieval_route,
|
|
5554
|
-
grounded_to_workspace: true,
|
|
5555
|
-
total_results: evidence2.length,
|
|
5556
|
-
context: evidence2.map((item) => `[${renderCitation(item)}] ${item.snippet || "Relevant local workspace context found."}`).join("\n"),
|
|
5557
|
-
evidence: evidence2,
|
|
5558
|
-
used_context_ids: evidence2.map((item) => item.source_id),
|
|
5559
|
-
latency_ms: 0,
|
|
5560
|
-
warnings: Array.from(/* @__PURE__ */ new Set([...preflight.warnings, ...localRetrieval.warnings])),
|
|
5561
|
-
recommended_next_calls: preflight.recommended_next_calls
|
|
5562
|
-
};
|
|
5563
|
-
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
5564
|
-
}
|
|
5565
|
-
if (!preflight.trust_state.project_ref) {
|
|
5566
|
-
const payload2 = {
|
|
5567
|
-
question,
|
|
5568
|
-
workspace_id: preflight.trust_state.workspace_id,
|
|
5569
|
-
root_path: preflight.trust_state.root_path,
|
|
5570
|
-
identity_source: preflight.trust_state.identity_source,
|
|
5571
|
-
trust_state: preflight.trust_state,
|
|
5572
|
-
retrieval_readiness: preflight.retrieval_readiness,
|
|
5573
|
-
retrieval_route: "none",
|
|
5574
|
-
grounded_to_workspace: false,
|
|
5575
|
-
total_results: 0,
|
|
5576
|
-
context: "",
|
|
5577
|
-
evidence: [],
|
|
5578
|
-
used_context_ids: [],
|
|
5579
|
-
latency_ms: 0,
|
|
5580
|
-
warnings: preflight.warnings,
|
|
5581
|
-
recommended_next_calls: preflight.recommended_next_calls
|
|
5582
|
-
};
|
|
5583
|
-
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
5584
|
-
}
|
|
5585
|
-
const queryResult = await queryWithDegradedFallback({
|
|
5586
|
-
project: preflight.trust_state.project_ref,
|
|
5587
|
-
query: question,
|
|
6608
|
+
const payload = await runUnifiedContextRetrieval({
|
|
6609
|
+
question,
|
|
6610
|
+
path,
|
|
6611
|
+
workspace_id,
|
|
6612
|
+
project,
|
|
5588
6613
|
top_k,
|
|
5589
|
-
include_memories
|
|
6614
|
+
include_memories,
|
|
5590
6615
|
include_graph,
|
|
5591
6616
|
session_id,
|
|
5592
6617
|
user_id,
|
|
5593
|
-
|
|
5594
|
-
retrieval_profile
|
|
5595
|
-
|
|
6618
|
+
include_parent_content,
|
|
6619
|
+
retrieval_profile,
|
|
6620
|
+
include_alias_warning: true
|
|
5596
6621
|
});
|
|
5597
|
-
|
|
5598
|
-
const rawResults = preflight.repo_grounded ? filterProjectRepoResults(response.results || [], preflight.matched_source_ids) : response.results || [];
|
|
5599
|
-
if (preflight.repo_grounded && rawResults.length === 0) {
|
|
5600
|
-
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
5601
|
-
query: question,
|
|
5602
|
-
path: preflight.trust_state.root_path,
|
|
5603
|
-
project: preflight.trust_state.project_ref,
|
|
5604
|
-
top_k
|
|
5605
|
-
});
|
|
5606
|
-
const evidence2 = localHitsToEvidence(preflight.trust_state.workspace_id, localRetrieval.results);
|
|
5607
|
-
const payload2 = {
|
|
5608
|
-
question,
|
|
5609
|
-
workspace_id: preflight.trust_state.workspace_id,
|
|
5610
|
-
root_path: preflight.trust_state.root_path,
|
|
5611
|
-
identity_source: preflight.trust_state.identity_source,
|
|
5612
|
-
trust_state: preflight.trust_state,
|
|
5613
|
-
retrieval_readiness: "local_fallback",
|
|
5614
|
-
retrieval_route: "local_workspace_fallback",
|
|
5615
|
-
grounded_to_workspace: true,
|
|
5616
|
-
total_results: evidence2.length,
|
|
5617
|
-
context: evidence2.map((item) => `[${renderCitation(item)}] ${item.snippet || "Relevant local workspace context found."}`).join("\n"),
|
|
5618
|
-
evidence: evidence2,
|
|
5619
|
-
used_context_ids: evidence2.map((item) => item.source_id),
|
|
5620
|
-
latency_ms: 0,
|
|
5621
|
-
warnings: Array.from(/* @__PURE__ */ new Set([...preflight.warnings, ...localRetrieval.warnings])),
|
|
5622
|
-
recommended_next_calls: preflight.recommended_next_calls
|
|
5623
|
-
};
|
|
5624
|
-
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
5625
|
-
}
|
|
5626
|
-
const evidence = rawResults.map((r) => toEvidenceRef(r, preflight.trust_state.workspace_id, "semantic"));
|
|
5627
|
-
const payload = {
|
|
5628
|
-
question,
|
|
5629
|
-
workspace_id: preflight.trust_state.workspace_id,
|
|
5630
|
-
root_path: preflight.trust_state.root_path,
|
|
5631
|
-
identity_source: preflight.trust_state.identity_source,
|
|
5632
|
-
trust_state: preflight.trust_state,
|
|
5633
|
-
retrieval_readiness: preflight.retrieval_readiness,
|
|
5634
|
-
retrieval_route: preflight.repo_grounded ? "project_repo" : "none",
|
|
5635
|
-
grounded_to_workspace: preflight.repo_grounded ? true : preflight.trust_state.grounded_to_workspace,
|
|
5636
|
-
total_results: rawResults.length || response.meta?.total || evidence.length,
|
|
5637
|
-
context: response.context || "",
|
|
5638
|
-
evidence,
|
|
5639
|
-
used_context_ids: rawResults.map((r) => String(r.id)),
|
|
5640
|
-
latency_ms: response.meta?.latency_ms || 0,
|
|
5641
|
-
degraded_mode: queryResult.degraded_mode,
|
|
5642
|
-
degraded_reason: queryResult.degraded_reason,
|
|
5643
|
-
recommendation: queryResult.recommendation,
|
|
5644
|
-
warnings: preflight.warnings,
|
|
5645
|
-
recommended_next_calls: preflight.recommended_next_calls
|
|
5646
|
-
};
|
|
5647
|
-
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
6622
|
+
return toTextResult(payload);
|
|
5648
6623
|
} catch (error) {
|
|
5649
|
-
return
|
|
6624
|
+
return primaryToolError(error.message, "context_get_relevant_failed");
|
|
5650
6625
|
}
|
|
5651
6626
|
}
|
|
5652
6627
|
);
|
|
@@ -5870,273 +6845,22 @@ server.tool(
|
|
|
5870
6845
|
},
|
|
5871
6846
|
async ({ project, query, path, top_k, chunk_types, include_memories, include_graph, user_id, session_id, max_tokens, include_parent_content, retrieval_profile }) => {
|
|
5872
6847
|
try {
|
|
5873
|
-
const
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
codebaseIntent: preflight.repo_grounded,
|
|
5878
|
-
preflight
|
|
5879
|
-
})) {
|
|
5880
|
-
return toTextResult(buildCodebaseTrustAbstainPayload({
|
|
5881
|
-
query,
|
|
5882
|
-
preflight,
|
|
5883
|
-
retrievalProfile
|
|
5884
|
-
}));
|
|
5885
|
-
}
|
|
5886
|
-
const resolvedProject = preflight.trust_state.project_ref || await resolveProjectRef(project);
|
|
5887
|
-
if (!resolvedProject && !preflight.repo_grounded) {
|
|
5888
|
-
return { content: [{ type: "text", text: "Error: No project resolved. Set WHISPER_PROJECT or pass project." }] };
|
|
5889
|
-
}
|
|
5890
|
-
const scope = resolveMcpScope({ project: resolvedProject, user_id, session_id, path: preflight.trust_state.root_path });
|
|
5891
|
-
if (preflight.repo_grounded && preflight.retrieval_route === "local_workspace_fallback") {
|
|
5892
|
-
const localRetrieval = await runLocalWorkspaceRetrieval({
|
|
5893
|
-
query,
|
|
5894
|
-
path: preflight.trust_state.root_path,
|
|
5895
|
-
project: resolvedProject || project,
|
|
5896
|
-
top_k
|
|
5897
|
-
});
|
|
5898
|
-
if (localRetrieval.results.length > 0) {
|
|
5899
|
-
return {
|
|
5900
|
-
content: [{
|
|
5901
|
-
type: "text",
|
|
5902
|
-
text: renderLocalWorkspaceContext({
|
|
5903
|
-
query,
|
|
5904
|
-
project_ref: resolvedProject || null,
|
|
5905
|
-
scope,
|
|
5906
|
-
route: "local_workspace_fallback",
|
|
5907
|
-
hits: localRetrieval.results,
|
|
5908
|
-
diagnostics: localRetrieval.diagnostics,
|
|
5909
|
-
warnings: Array.from(/* @__PURE__ */ new Set([...preflight.warnings, ...localRetrieval.warnings]))
|
|
5910
|
-
})
|
|
5911
|
-
}]
|
|
5912
|
-
};
|
|
5913
|
-
}
|
|
5914
|
-
}
|
|
5915
|
-
if (preflight.repo_grounded && resolvedProject) {
|
|
5916
|
-
const queryResult2 = await queryWithDegradedFallback({
|
|
5917
|
-
project: resolvedProject,
|
|
5918
|
-
query,
|
|
5919
|
-
top_k,
|
|
5920
|
-
include_memories: false,
|
|
5921
|
-
include_graph,
|
|
5922
|
-
user_id: user_id || scope.userId,
|
|
5923
|
-
session_id: session_id || scope.sessionId,
|
|
5924
|
-
source_ids: preflight.matched_source_ids,
|
|
5925
|
-
retrieval_profile: retrievalProfile,
|
|
5926
|
-
include_parent_content
|
|
5927
|
-
});
|
|
5928
|
-
const repoResults = filterProjectRepoResults(queryResult2.response.results || [], preflight.matched_source_ids);
|
|
5929
|
-
if (repoResults.length > 0) {
|
|
5930
|
-
const scopedResponse = { ...queryResult2.response, results: repoResults };
|
|
5931
|
-
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}):
|
|
5932
|
-
|
|
5933
|
-
`;
|
|
5934
|
-
const suffix2 = [
|
|
5935
|
-
`[diagnostics] identity_source=${preflight.trust_state.identity_source} retrieval_readiness=${preflight.retrieval_readiness} retrieval_route=project_repo`,
|
|
5936
|
-
queryResult2.degraded_mode ? `[degraded_mode=true] ${queryResult2.degraded_reason}
|
|
5937
|
-
Recommendation: ${queryResult2.recommendation}` : "",
|
|
5938
|
-
preflight.warnings.length ? `[warnings]
|
|
5939
|
-
${preflight.warnings.join("\n")}` : ""
|
|
5940
|
-
].filter(Boolean).join("\n\n");
|
|
5941
|
-
return { content: [{ type: "text", text: `${header2}${scopedResponse.context}${suffix2 ? `
|
|
5942
|
-
|
|
5943
|
-
${suffix2}` : ""}` }] };
|
|
5944
|
-
}
|
|
5945
|
-
}
|
|
5946
|
-
if (preflight.repo_grounded) {
|
|
5947
|
-
if (resolvedProject && include_memories !== false) {
|
|
5948
|
-
const memoryRescue = await runContextQueryMemoryRescue({
|
|
5949
|
-
project: resolvedProject,
|
|
5950
|
-
query,
|
|
5951
|
-
user_id: user_id ? scope.userId : void 0,
|
|
5952
|
-
session_id: session_id ? scope.sessionId : void 0,
|
|
5953
|
-
top_k
|
|
5954
|
-
});
|
|
5955
|
-
if (memoryRescue.results.length && memoryRescue.rescue_mode) {
|
|
5956
|
-
return {
|
|
5957
|
-
content: [{
|
|
5958
|
-
type: "text",
|
|
5959
|
-
text: `${renderContextQueryMemoryRescue({
|
|
5960
|
-
project: resolvedProject,
|
|
5961
|
-
query,
|
|
5962
|
-
scope,
|
|
5963
|
-
results: memoryRescue.results,
|
|
5964
|
-
rescue_mode: memoryRescue.rescue_mode
|
|
5965
|
-
})}
|
|
5966
|
-
|
|
5967
|
-
[diagnostics]
|
|
5968
|
-
retrieval_route=memory_only retrieval_readiness=${preflight.retrieval_readiness} workspace=${preflight.trust_state.workspace_id}`
|
|
5969
|
-
}]
|
|
5970
|
-
};
|
|
5971
|
-
}
|
|
5972
|
-
}
|
|
5973
|
-
return {
|
|
5974
|
-
content: [{
|
|
5975
|
-
type: "text",
|
|
5976
|
-
text: `No relevant repo-grounded context found.
|
|
5977
|
-
|
|
5978
|
-
[diagnostics]
|
|
5979
|
-
workspace=${preflight.trust_state.workspace_id} identity_source=${preflight.trust_state.identity_source} retrieval_readiness=${preflight.retrieval_readiness} retrieval_route=${preflight.retrieval_route}`
|
|
5980
|
-
}]
|
|
5981
|
-
};
|
|
5982
|
-
}
|
|
5983
|
-
const automaticMode = !preflight.repo_grounded && include_memories !== false && include_graph !== true && !(chunk_types && chunk_types.length > 0) && max_tokens === void 0 && runtimeClient;
|
|
5984
|
-
if (automaticMode) {
|
|
5985
|
-
try {
|
|
5986
|
-
const prepared = await prepareAutomaticQuery({
|
|
5987
|
-
project: resolvedProject,
|
|
5988
|
-
query,
|
|
5989
|
-
top_k,
|
|
5990
|
-
user_id,
|
|
5991
|
-
session_id,
|
|
5992
|
-
path: preflight.trust_state.root_path
|
|
5993
|
-
});
|
|
5994
|
-
if (!prepared.items.length) {
|
|
5995
|
-
const memoryRescue = include_memories !== false ? await runContextQueryMemoryRescue({
|
|
5996
|
-
project: resolvedProject,
|
|
5997
|
-
query,
|
|
5998
|
-
user_id: user_id ? scope.userId : void 0,
|
|
5999
|
-
session_id: session_id ? scope.sessionId : void 0,
|
|
6000
|
-
top_k
|
|
6001
|
-
}) : { results: [], rescue_mode: null };
|
|
6002
|
-
if (memoryRescue.results.length && memoryRescue.rescue_mode) {
|
|
6003
|
-
return {
|
|
6004
|
-
content: [{
|
|
6005
|
-
type: "text",
|
|
6006
|
-
text: renderContextQueryMemoryRescue({
|
|
6007
|
-
project: resolvedProject,
|
|
6008
|
-
query,
|
|
6009
|
-
scope,
|
|
6010
|
-
results: memoryRescue.results,
|
|
6011
|
-
rescue_mode: memoryRescue.rescue_mode
|
|
6012
|
-
})
|
|
6013
|
-
}]
|
|
6014
|
-
};
|
|
6015
|
-
}
|
|
6016
|
-
return { content: [{ type: "text", text: "No relevant context found." }] };
|
|
6017
|
-
}
|
|
6018
|
-
const warnings = prepared.retrieval.warnings.length ? `
|
|
6019
|
-
|
|
6020
|
-
[automatic_runtime]
|
|
6021
|
-
${prepared.retrieval.warnings.join("\n")}` : "";
|
|
6022
|
-
const diagnostics = [
|
|
6023
|
-
`focused_scope=${prepared.retrieval.focusedScopeApplied}`,
|
|
6024
|
-
`fallback_used=${prepared.retrieval.fallbackUsed}`,
|
|
6025
|
-
`deduped=${prepared.retrieval.dedupedCount}`,
|
|
6026
|
-
`dropped_below_floor=${prepared.retrieval.droppedBelowFloor}`
|
|
6027
|
-
].join(" ");
|
|
6028
|
-
const scopeLabel = `project=${prepared.scope.project} user=${prepared.scope.userId} session=${prepared.scope.sessionId}`;
|
|
6029
|
-
return {
|
|
6030
|
-
content: [{
|
|
6031
|
-
type: "text",
|
|
6032
|
-
text: `Found ${prepared.items.length} runtime-ranked items (${prepared.retrieval.durationMs}ms, ${scopeLabel}, ${diagnostics}):
|
|
6033
|
-
|
|
6034
|
-
${prepared.context}${warnings}`
|
|
6035
|
-
}]
|
|
6036
|
-
};
|
|
6037
|
-
} catch (error) {
|
|
6038
|
-
const automaticWarning = `Automatic runtime unavailable: ${error.message}. Falling back to broad/manual query path.`;
|
|
6039
|
-
const queryResult2 = await queryWithDegradedFallback({
|
|
6040
|
-
project: resolvedProject,
|
|
6041
|
-
query,
|
|
6042
|
-
top_k,
|
|
6043
|
-
include_memories: include_memories === true,
|
|
6044
|
-
include_graph,
|
|
6045
|
-
user_id: user_id || scope.userId,
|
|
6046
|
-
session_id: session_id || scope.sessionId,
|
|
6047
|
-
retrieval_profile: retrievalProfile,
|
|
6048
|
-
include_parent_content
|
|
6049
|
-
});
|
|
6050
|
-
const response2 = queryResult2.response;
|
|
6051
|
-
if (response2.results.length === 0) {
|
|
6052
|
-
const memoryRescue = include_memories !== false ? await runContextQueryMemoryRescue({
|
|
6053
|
-
project: resolvedProject,
|
|
6054
|
-
query,
|
|
6055
|
-
user_id: user_id ? scope.userId : void 0,
|
|
6056
|
-
session_id: session_id ? scope.sessionId : void 0,
|
|
6057
|
-
top_k
|
|
6058
|
-
}) : { results: [], rescue_mode: null };
|
|
6059
|
-
if (memoryRescue.results.length && memoryRescue.rescue_mode) {
|
|
6060
|
-
return {
|
|
6061
|
-
content: [{
|
|
6062
|
-
type: "text",
|
|
6063
|
-
text: `${renderContextQueryMemoryRescue({
|
|
6064
|
-
project: resolvedProject,
|
|
6065
|
-
query,
|
|
6066
|
-
scope,
|
|
6067
|
-
results: memoryRescue.results,
|
|
6068
|
-
rescue_mode: memoryRescue.rescue_mode
|
|
6069
|
-
})}
|
|
6070
|
-
|
|
6071
|
-
[automatic_runtime]
|
|
6072
|
-
${automaticWarning}`
|
|
6073
|
-
}]
|
|
6074
|
-
};
|
|
6075
|
-
}
|
|
6076
|
-
return { content: [{ type: "text", text: `No relevant context found.
|
|
6077
|
-
|
|
6078
|
-
[automatic_runtime]
|
|
6079
|
-
${automaticWarning}` }] };
|
|
6080
|
-
}
|
|
6081
|
-
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}):
|
|
6082
|
-
|
|
6083
|
-
`;
|
|
6084
|
-
const suffix2 = queryResult2.degraded_mode ? `
|
|
6085
|
-
|
|
6086
|
-
[degraded_mode=true] ${queryResult2.degraded_reason}
|
|
6087
|
-
Recommendation: ${queryResult2.recommendation}` : "";
|
|
6088
|
-
return { content: [{ type: "text", text: `${header2}${response2.context}
|
|
6089
|
-
|
|
6090
|
-
[automatic_runtime]
|
|
6091
|
-
${automaticWarning}${suffix2}` }] };
|
|
6092
|
-
}
|
|
6093
|
-
}
|
|
6094
|
-
const queryResult = await queryWithDegradedFallback({
|
|
6095
|
-
project: resolvedProject,
|
|
6096
|
-
query,
|
|
6848
|
+
const payload = await runUnifiedContextRetrieval({
|
|
6849
|
+
question: query,
|
|
6850
|
+
path,
|
|
6851
|
+
project,
|
|
6097
6852
|
top_k,
|
|
6098
|
-
include_memories
|
|
6853
|
+
include_memories,
|
|
6099
6854
|
include_graph,
|
|
6100
|
-
user_id
|
|
6101
|
-
session_id
|
|
6102
|
-
|
|
6103
|
-
|
|
6855
|
+
user_id,
|
|
6856
|
+
session_id,
|
|
6857
|
+
include_parent_content,
|
|
6858
|
+
retrieval_profile,
|
|
6859
|
+
chunk_types
|
|
6104
6860
|
});
|
|
6105
|
-
|
|
6106
|
-
if (response.results.length === 0) {
|
|
6107
|
-
const memoryRescue = include_memories !== false ? await runContextQueryMemoryRescue({
|
|
6108
|
-
project: resolvedProject,
|
|
6109
|
-
query,
|
|
6110
|
-
user_id: user_id ? scope.userId : void 0,
|
|
6111
|
-
session_id: session_id ? scope.sessionId : void 0,
|
|
6112
|
-
top_k
|
|
6113
|
-
}) : { results: [], rescue_mode: null };
|
|
6114
|
-
if (memoryRescue.results.length && memoryRescue.rescue_mode) {
|
|
6115
|
-
return {
|
|
6116
|
-
content: [{
|
|
6117
|
-
type: "text",
|
|
6118
|
-
text: renderContextQueryMemoryRescue({
|
|
6119
|
-
project: resolvedProject,
|
|
6120
|
-
query,
|
|
6121
|
-
scope,
|
|
6122
|
-
results: memoryRescue.results,
|
|
6123
|
-
rescue_mode: memoryRescue.rescue_mode
|
|
6124
|
-
})
|
|
6125
|
-
}]
|
|
6126
|
-
};
|
|
6127
|
-
}
|
|
6128
|
-
return { content: [{ type: "text", text: "No relevant context found." }] };
|
|
6129
|
-
}
|
|
6130
|
-
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}):
|
|
6131
|
-
|
|
6132
|
-
`;
|
|
6133
|
-
const suffix = queryResult.degraded_mode ? `
|
|
6134
|
-
|
|
6135
|
-
[degraded_mode=true] ${queryResult.degraded_reason}
|
|
6136
|
-
Recommendation: ${queryResult.recommendation}` : "";
|
|
6137
|
-
return { content: [{ type: "text", text: header + response.context + suffix }] };
|
|
6861
|
+
return toTextResult(payload);
|
|
6138
6862
|
} catch (error) {
|
|
6139
|
-
return
|
|
6863
|
+
return primaryToolError(error.message, "context_query_failed");
|
|
6140
6864
|
}
|
|
6141
6865
|
}
|
|
6142
6866
|
);
|
|
@@ -6147,32 +6871,54 @@ server.tool(
|
|
|
6147
6871
|
project: z.string().optional().describe("Project name or slug"),
|
|
6148
6872
|
content: z.string().describe("The memory content to store"),
|
|
6149
6873
|
memory_type: z.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"]).optional().default("factual"),
|
|
6874
|
+
scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
|
|
6150
6875
|
user_id: z.string().optional().describe("User this memory belongs to"),
|
|
6151
6876
|
session_id: z.string().optional().describe("Session scope"),
|
|
6152
6877
|
agent_id: z.string().optional().describe("Agent scope"),
|
|
6153
6878
|
importance: z.number().optional().default(0.5).describe("Importance 0-1")
|
|
6154
6879
|
},
|
|
6155
|
-
async ({ project, content, memory_type, user_id, session_id, agent_id, importance }) => {
|
|
6880
|
+
async ({ project, content, memory_type, scope, user_id, session_id, agent_id, importance }) => {
|
|
6156
6881
|
try {
|
|
6157
|
-
const
|
|
6882
|
+
const memoryScope = resolveMemoryScope({ project, user_id, session_id, scope });
|
|
6158
6883
|
const result = await whisper.addMemory({
|
|
6159
|
-
project:
|
|
6884
|
+
project: memoryScope.project,
|
|
6160
6885
|
content,
|
|
6161
6886
|
memory_type,
|
|
6162
|
-
user_id:
|
|
6163
|
-
session_id:
|
|
6887
|
+
user_id: memoryScope.userId,
|
|
6888
|
+
session_id: memoryScope.sessionId,
|
|
6164
6889
|
agent_id,
|
|
6165
|
-
importance
|
|
6890
|
+
importance,
|
|
6891
|
+
metadata: buildMemoryScopeMetadata({
|
|
6892
|
+
memoryScope,
|
|
6893
|
+
agent_id
|
|
6894
|
+
})
|
|
6166
6895
|
});
|
|
6167
6896
|
const memoryId = result?.memory_id || result.id;
|
|
6168
6897
|
const jobId = result?.job_id;
|
|
6169
6898
|
const mode = result?.mode;
|
|
6170
6899
|
const semanticStatus = result?.semantic_status;
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6900
|
+
return primaryToolSuccess({
|
|
6901
|
+
tool: "memory.add",
|
|
6902
|
+
memory_id: memoryId || null,
|
|
6903
|
+
job_id: jobId || null,
|
|
6904
|
+
mode: mode || null,
|
|
6905
|
+
semantic_status: semanticStatus || null,
|
|
6906
|
+
memory_type: memory_type || "factual",
|
|
6907
|
+
scope: memoryScope.scopeMode,
|
|
6908
|
+
queued: mode === "async" || Boolean(jobId),
|
|
6909
|
+
diagnostics: {
|
|
6910
|
+
scope: {
|
|
6911
|
+
project: memoryScope.project || null,
|
|
6912
|
+
user_id: memoryScope.userId,
|
|
6913
|
+
session_id: memoryScope.sessionId || null,
|
|
6914
|
+
scope: memoryScope.scopeMode,
|
|
6915
|
+
actor_user_id: memoryScope.actorUserId,
|
|
6916
|
+
actor_session_id: memoryScope.actorSessionId || null
|
|
6917
|
+
}
|
|
6918
|
+
}
|
|
6919
|
+
});
|
|
6174
6920
|
} catch (error) {
|
|
6175
|
-
return
|
|
6921
|
+
return primaryToolError(error.message);
|
|
6176
6922
|
}
|
|
6177
6923
|
}
|
|
6178
6924
|
);
|
|
@@ -6182,28 +6928,29 @@ server.tool(
|
|
|
6182
6928
|
{
|
|
6183
6929
|
project: z.string().optional().describe("Project name or slug"),
|
|
6184
6930
|
query: z.string().describe("What to search for"),
|
|
6931
|
+
scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
|
|
6185
6932
|
user_id: z.string().optional().describe("Filter by user"),
|
|
6186
6933
|
session_id: z.string().optional().describe("Filter by session"),
|
|
6187
6934
|
top_k: z.number().optional().default(10).describe("Number of results"),
|
|
6188
6935
|
memory_types: z.array(z.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"])).optional()
|
|
6189
6936
|
},
|
|
6190
|
-
async ({ project, query, user_id, session_id, top_k, memory_types }) => {
|
|
6937
|
+
async ({ project, query, scope, user_id, session_id, top_k, memory_types }) => {
|
|
6191
6938
|
try {
|
|
6192
|
-
const
|
|
6939
|
+
const memoryScope = resolveMemoryScope({ project, user_id, session_id, scope });
|
|
6193
6940
|
const results = runtimeClient && (!memory_types || memory_types.length <= 1) ? await runtimeClient.memory.search({
|
|
6194
|
-
project:
|
|
6941
|
+
project: memoryScope.project,
|
|
6195
6942
|
query,
|
|
6196
|
-
user_id:
|
|
6197
|
-
session_id:
|
|
6943
|
+
user_id: memoryScope.userId,
|
|
6944
|
+
session_id: memoryScope.sessionId,
|
|
6198
6945
|
top_k,
|
|
6199
6946
|
include_pending: true,
|
|
6200
6947
|
profile: "balanced",
|
|
6201
6948
|
...memory_types?.length === 1 ? { memory_type: memory_types[0] } : {}
|
|
6202
6949
|
}) : await whisper.searchMemoriesSOTA({
|
|
6203
|
-
project:
|
|
6950
|
+
project: memoryScope.project,
|
|
6204
6951
|
query,
|
|
6205
|
-
user_id:
|
|
6206
|
-
session_id:
|
|
6952
|
+
user_id: memoryScope.userId,
|
|
6953
|
+
session_id: memoryScope.sessionId,
|
|
6207
6954
|
top_k,
|
|
6208
6955
|
memory_types
|
|
6209
6956
|
});
|
|
@@ -6211,10 +6958,19 @@ server.tool(
|
|
|
6211
6958
|
return primaryToolSuccess({
|
|
6212
6959
|
tool: "memory.search",
|
|
6213
6960
|
query,
|
|
6214
|
-
|
|
6215
|
-
|
|
6961
|
+
scope: memoryScope.scopeMode,
|
|
6962
|
+
user_id: memoryScope.userId,
|
|
6963
|
+
session_id: memoryScope.sessionId,
|
|
6216
6964
|
results: normalizedResults,
|
|
6217
|
-
count: normalizedResults.length
|
|
6965
|
+
count: normalizedResults.length,
|
|
6966
|
+
diagnostics: {
|
|
6967
|
+
scope: {
|
|
6968
|
+
project: memoryScope.project || null,
|
|
6969
|
+
user_id: memoryScope.userId,
|
|
6970
|
+
session_id: memoryScope.sessionId || null,
|
|
6971
|
+
scope: memoryScope.scopeMode
|
|
6972
|
+
}
|
|
6973
|
+
}
|
|
6218
6974
|
});
|
|
6219
6975
|
} catch (error) {
|
|
6220
6976
|
return primaryToolError(error.message);
|
|
@@ -6469,6 +7225,7 @@ server.tool(
|
|
|
6469
7225
|
{
|
|
6470
7226
|
project: z.string().optional().describe("Project name or slug"),
|
|
6471
7227
|
query: z.string().describe("Search query (supports temporal: 'yesterday', 'last week')"),
|
|
7228
|
+
scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
|
|
6472
7229
|
user_id: z.string().optional().describe("Filter by user"),
|
|
6473
7230
|
session_id: z.string().optional().describe("Filter by session"),
|
|
6474
7231
|
question_date: z.string().optional().describe("ISO datetime for temporal grounding"),
|
|
@@ -6476,13 +7233,14 @@ server.tool(
|
|
|
6476
7233
|
top_k: z.number().optional().default(10),
|
|
6477
7234
|
include_relations: z.boolean().optional().default(true).describe("Include related memories via knowledge graph")
|
|
6478
7235
|
},
|
|
6479
|
-
async ({ project, query, user_id, session_id, question_date, memory_types, top_k, include_relations }) => {
|
|
7236
|
+
async ({ project, query, scope, user_id, session_id, question_date, memory_types, top_k, include_relations }) => {
|
|
6480
7237
|
try {
|
|
7238
|
+
const memoryScope = resolveMemoryScope({ project, user_id, session_id, scope });
|
|
6481
7239
|
const results = await whisper.searchMemoriesSOTA({
|
|
6482
|
-
project,
|
|
7240
|
+
project: memoryScope.project,
|
|
6483
7241
|
query,
|
|
6484
|
-
user_id,
|
|
6485
|
-
session_id,
|
|
7242
|
+
user_id: memoryScope.userId,
|
|
7243
|
+
session_id: memoryScope.sessionId,
|
|
6486
7244
|
question_date,
|
|
6487
7245
|
memory_types,
|
|
6488
7246
|
top_k,
|
|
@@ -6492,10 +7250,21 @@ server.tool(
|
|
|
6492
7250
|
return primaryToolSuccess({
|
|
6493
7251
|
tool: "memory.search_sota",
|
|
6494
7252
|
query,
|
|
7253
|
+
scope: memoryScope.scopeMode,
|
|
7254
|
+
user_id: memoryScope.userId,
|
|
7255
|
+
session_id: memoryScope.sessionId || null,
|
|
6495
7256
|
question_date: question_date || null,
|
|
6496
7257
|
include_relations,
|
|
6497
7258
|
results: normalizedResults,
|
|
6498
|
-
count: normalizedResults.length
|
|
7259
|
+
count: normalizedResults.length,
|
|
7260
|
+
diagnostics: {
|
|
7261
|
+
scope: {
|
|
7262
|
+
project: memoryScope.project || null,
|
|
7263
|
+
user_id: memoryScope.userId,
|
|
7264
|
+
session_id: memoryScope.sessionId || null,
|
|
7265
|
+
scope: memoryScope.scopeMode
|
|
7266
|
+
}
|
|
7267
|
+
}
|
|
6499
7268
|
});
|
|
6500
7269
|
} catch (error) {
|
|
6501
7270
|
return primaryToolError(error.message);
|
|
@@ -6517,29 +7286,40 @@ server.tool(
|
|
|
6517
7286
|
},
|
|
6518
7287
|
async ({ project, session_id, user_id, messages }) => {
|
|
6519
7288
|
try {
|
|
6520
|
-
const
|
|
7289
|
+
const memoryScope = resolveMemoryScope({
|
|
7290
|
+
project,
|
|
7291
|
+
user_id,
|
|
7292
|
+
session_id,
|
|
7293
|
+
scope: "personal"
|
|
7294
|
+
});
|
|
6521
7295
|
const normalizedMessages = messages.map((message) => ({
|
|
6522
7296
|
role: message.role,
|
|
6523
7297
|
content: message.content,
|
|
6524
7298
|
timestamp: message.timestamp
|
|
6525
7299
|
}));
|
|
6526
7300
|
const result = await ingestSessionWithSyncFallback({
|
|
6527
|
-
project:
|
|
6528
|
-
session_id:
|
|
6529
|
-
user_id:
|
|
7301
|
+
project: memoryScope.project,
|
|
7302
|
+
session_id: memoryScope.sessionId,
|
|
7303
|
+
user_id: memoryScope.userId,
|
|
6530
7304
|
messages: normalizedMessages
|
|
6531
7305
|
});
|
|
6532
|
-
return {
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
7306
|
+
return primaryToolSuccess({
|
|
7307
|
+
tool: "memory.ingest_conversation",
|
|
7308
|
+
messages_processed: normalizedMessages.length,
|
|
7309
|
+
memories_created: result.memories_created,
|
|
7310
|
+
relations_created: result.relations_created,
|
|
7311
|
+
memories_invalidated: result.memories_invalidated,
|
|
7312
|
+
errors: result.errors || [],
|
|
7313
|
+
scope: memoryScope.scopeMode,
|
|
7314
|
+
diagnostics: {
|
|
7315
|
+
scope: {
|
|
7316
|
+
project: memoryScope.project || null,
|
|
7317
|
+
user_id: memoryScope.userId,
|
|
7318
|
+
session_id: memoryScope.sessionId || null,
|
|
7319
|
+
scope: memoryScope.scopeMode
|
|
7320
|
+
}
|
|
7321
|
+
}
|
|
7322
|
+
});
|
|
6543
7323
|
} catch (error) {
|
|
6544
7324
|
return { content: [{ type: "text", text: `Error: ${error.message}` }] };
|
|
6545
7325
|
}
|
|
@@ -6756,6 +7536,9 @@ server.tool(
|
|
|
6756
7536
|
{
|
|
6757
7537
|
workspace_id: z.string().optional(),
|
|
6758
7538
|
project: z.string().optional(),
|
|
7539
|
+
scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
|
|
7540
|
+
user_id: z.string().optional(),
|
|
7541
|
+
session_id: z.string().optional(),
|
|
6759
7542
|
target: z.object({
|
|
6760
7543
|
memory_id: z.string().optional(),
|
|
6761
7544
|
query: z.string().optional()
|
|
@@ -6763,7 +7546,7 @@ server.tool(
|
|
|
6763
7546
|
mode: z.enum(["delete", "invalidate"]).optional().default("invalidate"),
|
|
6764
7547
|
reason: z.string().optional()
|
|
6765
7548
|
},
|
|
6766
|
-
async ({ workspace_id, project, target, mode, reason }) => {
|
|
7549
|
+
async ({ workspace_id, project, scope, user_id, session_id, target, mode, reason }) => {
|
|
6767
7550
|
try {
|
|
6768
7551
|
if (!target.memory_id && !target.query) {
|
|
6769
7552
|
return { content: [{ type: "text", text: "Error: target.memory_id or target.query is required." }] };
|
|
@@ -6772,8 +7555,22 @@ server.tool(
|
|
|
6772
7555
|
let queryResolution = null;
|
|
6773
7556
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6774
7557
|
const actor = process.env.WHISPER_AGENT_ID || process.env.USERNAME || "api_key_principal";
|
|
6775
|
-
const
|
|
7558
|
+
const memoryScope = resolveMemoryScope({
|
|
7559
|
+
project,
|
|
7560
|
+
user_id,
|
|
7561
|
+
session_id,
|
|
7562
|
+
scope
|
|
7563
|
+
});
|
|
7564
|
+
const resolvedProject = await resolveProjectRef(memoryScope.project);
|
|
7565
|
+
async function assertScopedMemoryId(memoryId) {
|
|
7566
|
+
const memoryResult = await whisper.getMemory(memoryId);
|
|
7567
|
+
const memory = memoryResult?.memory || memoryResult;
|
|
7568
|
+
if (!isMemoryInScope({ memory, memoryScope })) {
|
|
7569
|
+
throw new Error(`memory_id ${memoryId} is outside the effective ${memoryScope.scopeMode} scope.`);
|
|
7570
|
+
}
|
|
7571
|
+
}
|
|
6776
7572
|
async function applyToMemory(memoryId) {
|
|
7573
|
+
await assertScopedMemoryId(memoryId);
|
|
6777
7574
|
if (mode === "delete") {
|
|
6778
7575
|
await whisper.deleteMemory(memoryId);
|
|
6779
7576
|
} else {
|
|
@@ -6788,7 +7585,10 @@ server.tool(
|
|
|
6788
7585
|
project: resolvedProject,
|
|
6789
7586
|
content: `Invalidated memory ${memoryId} at ${now}. Reason: ${reason || "No reason provided"}`,
|
|
6790
7587
|
memory_type: "instruction",
|
|
6791
|
-
|
|
7588
|
+
user_id: memoryScope.userId,
|
|
7589
|
+
session_id: memoryScope.sessionId,
|
|
7590
|
+
importance: 1,
|
|
7591
|
+
metadata: buildMemoryScopeMetadata({ memoryScope })
|
|
6792
7592
|
});
|
|
6793
7593
|
}
|
|
6794
7594
|
}
|
|
@@ -6820,13 +7620,25 @@ server.tool(
|
|
|
6820
7620
|
mode: audit2.mode,
|
|
6821
7621
|
...audit2.reason ? { reason: audit2.reason } : {}
|
|
6822
7622
|
},
|
|
6823
|
-
warning: "No project resolved for query-based forget. Nothing was changed."
|
|
7623
|
+
warning: "No project resolved for query-based forget. Nothing was changed.",
|
|
7624
|
+
diagnostics: {
|
|
7625
|
+
scope: {
|
|
7626
|
+
project: memoryScope.project || null,
|
|
7627
|
+
user_id: memoryScope.userId,
|
|
7628
|
+
session_id: memoryScope.sessionId || null,
|
|
7629
|
+
scope: memoryScope.scopeMode,
|
|
7630
|
+
actor_user_id: memoryScope.actorUserId,
|
|
7631
|
+
actor_session_id: memoryScope.actorSessionId || null
|
|
7632
|
+
}
|
|
7633
|
+
}
|
|
6824
7634
|
};
|
|
6825
7635
|
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
6826
7636
|
}
|
|
6827
7637
|
const search = await whisper.searchMemoriesSOTA({
|
|
6828
7638
|
project: resolvedProject,
|
|
6829
7639
|
query: target.query || "",
|
|
7640
|
+
user_id: memoryScope.userId,
|
|
7641
|
+
session_id: memoryScope.sessionId,
|
|
6830
7642
|
top_k: 25,
|
|
6831
7643
|
include_relations: false,
|
|
6832
7644
|
include_pending: true
|
|
@@ -6839,7 +7651,17 @@ server.tool(
|
|
|
6839
7651
|
status: "completed",
|
|
6840
7652
|
affected_ids: affectedIds,
|
|
6841
7653
|
warning: resolved.warning || "Query did not resolve to a reliable memory match. No memories were changed.",
|
|
6842
|
-
resolved_by: resolved.resolved_by
|
|
7654
|
+
resolved_by: resolved.resolved_by,
|
|
7655
|
+
diagnostics: {
|
|
7656
|
+
scope: {
|
|
7657
|
+
project: resolvedProject,
|
|
7658
|
+
user_id: memoryScope.userId,
|
|
7659
|
+
session_id: memoryScope.sessionId || null,
|
|
7660
|
+
scope: memoryScope.scopeMode,
|
|
7661
|
+
actor_user_id: memoryScope.actorUserId,
|
|
7662
|
+
actor_session_id: memoryScope.actorSessionId || null
|
|
7663
|
+
}
|
|
7664
|
+
}
|
|
6843
7665
|
};
|
|
6844
7666
|
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
6845
7667
|
}
|
|
@@ -6868,6 +7690,16 @@ server.tool(
|
|
|
6868
7690
|
called_at: audit.called_at,
|
|
6869
7691
|
mode: audit.mode,
|
|
6870
7692
|
...audit.reason ? { reason: audit.reason } : {}
|
|
7693
|
+
},
|
|
7694
|
+
diagnostics: {
|
|
7695
|
+
scope: {
|
|
7696
|
+
project: resolvedProject || null,
|
|
7697
|
+
user_id: memoryScope.userId,
|
|
7698
|
+
session_id: memoryScope.sessionId || null,
|
|
7699
|
+
scope: memoryScope.scopeMode,
|
|
7700
|
+
actor_user_id: memoryScope.actorUserId,
|
|
7701
|
+
actor_session_id: memoryScope.actorSessionId || null
|
|
7702
|
+
}
|
|
6871
7703
|
}
|
|
6872
7704
|
};
|
|
6873
7705
|
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
@@ -7531,7 +8363,10 @@ server.tool(
|
|
|
7531
8363
|
context: response.context,
|
|
7532
8364
|
results: response.results,
|
|
7533
8365
|
degradedMode: queryResult.degraded_mode,
|
|
7534
|
-
degradedReason: queryResult.degraded_reason
|
|
8366
|
+
degradedReason: queryResult.degraded_reason,
|
|
8367
|
+
semanticStatus: queryResult.semantic_status,
|
|
8368
|
+
fallbackMode: queryResult.fallback_mode,
|
|
8369
|
+
recommendedFixes: queryResult.recommended_fixes || []
|
|
7535
8370
|
}));
|
|
7536
8371
|
} catch (error) {
|
|
7537
8372
|
return primaryToolError(error.message);
|
|
@@ -7788,14 +8623,28 @@ server.tool(
|
|
|
7788
8623
|
project: z.string().optional(),
|
|
7789
8624
|
content: z.string().describe("Memory content"),
|
|
7790
8625
|
memory_type: z.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"]).optional().default("factual"),
|
|
8626
|
+
scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
|
|
7791
8627
|
user_id: z.string().optional(),
|
|
7792
8628
|
session_id: z.string().optional(),
|
|
7793
8629
|
agent_id: z.string().optional(),
|
|
7794
8630
|
importance: z.number().optional().default(0.5)
|
|
7795
8631
|
},
|
|
7796
|
-
async ({ project, content, memory_type, user_id, session_id, agent_id, importance }) => {
|
|
8632
|
+
async ({ project, content, memory_type, scope, user_id, session_id, agent_id, importance }) => {
|
|
7797
8633
|
try {
|
|
7798
|
-
const
|
|
8634
|
+
const memoryScope = resolveMemoryScope({ project, user_id, session_id, scope });
|
|
8635
|
+
const result = await whisper.addMemory({
|
|
8636
|
+
project: memoryScope.project,
|
|
8637
|
+
content,
|
|
8638
|
+
memory_type,
|
|
8639
|
+
user_id: memoryScope.userId,
|
|
8640
|
+
session_id: memoryScope.sessionId,
|
|
8641
|
+
agent_id,
|
|
8642
|
+
importance,
|
|
8643
|
+
metadata: buildMemoryScopeMetadata({
|
|
8644
|
+
memoryScope,
|
|
8645
|
+
agent_id
|
|
8646
|
+
})
|
|
8647
|
+
});
|
|
7799
8648
|
const memoryId = result?.memory_id || (result.mode === "sync" ? result.id : null);
|
|
7800
8649
|
const jobId = result?.job_id || (result.mode === "async" ? result.id : null);
|
|
7801
8650
|
return primaryToolSuccess({
|
|
@@ -7805,8 +8654,19 @@ server.tool(
|
|
|
7805
8654
|
job_id: jobId,
|
|
7806
8655
|
mode: result?.mode || null,
|
|
7807
8656
|
memory_type,
|
|
8657
|
+
scope: memoryScope.scopeMode,
|
|
7808
8658
|
stored: result.success === true,
|
|
7809
|
-
queued: result?.mode === "async" || Boolean(jobId)
|
|
8659
|
+
queued: result?.mode === "async" || Boolean(jobId),
|
|
8660
|
+
diagnostics: {
|
|
8661
|
+
scope: {
|
|
8662
|
+
project: memoryScope.project || null,
|
|
8663
|
+
user_id: memoryScope.userId,
|
|
8664
|
+
session_id: memoryScope.sessionId || null,
|
|
8665
|
+
scope: memoryScope.scopeMode,
|
|
8666
|
+
actor_user_id: memoryScope.actorUserId,
|
|
8667
|
+
actor_session_id: memoryScope.actorSessionId || null
|
|
8668
|
+
}
|
|
8669
|
+
}
|
|
7810
8670
|
});
|
|
7811
8671
|
} catch (error) {
|
|
7812
8672
|
return primaryToolError(error.message);
|
|
@@ -7842,18 +8702,33 @@ server.tool(
|
|
|
7842
8702
|
timestamp
|
|
7843
8703
|
});
|
|
7844
8704
|
const resolvedProject = await resolveProjectRef(project);
|
|
7845
|
-
const
|
|
7846
|
-
project: resolvedProject,
|
|
7847
|
-
session_id,
|
|
8705
|
+
const memoryScope = resolveMemoryScope({
|
|
8706
|
+
project: resolvedProject || project,
|
|
7848
8707
|
user_id,
|
|
8708
|
+
session_id,
|
|
8709
|
+
scope: "personal"
|
|
8710
|
+
});
|
|
8711
|
+
const result = await ingestSessionWithSyncFallback({
|
|
8712
|
+
project: memoryScope.project,
|
|
8713
|
+
session_id: memoryScope.sessionId || session_id,
|
|
8714
|
+
user_id: memoryScope.userId,
|
|
7849
8715
|
messages: normalizedMessages
|
|
7850
8716
|
});
|
|
7851
8717
|
return primaryToolSuccess({
|
|
7852
8718
|
tool: "record",
|
|
7853
|
-
session_id,
|
|
8719
|
+
session_id: memoryScope.sessionId || session_id,
|
|
8720
|
+
user_id: memoryScope.userId,
|
|
7854
8721
|
messages_recorded: normalizedMessages.length,
|
|
7855
8722
|
memories_created: result.memories_created,
|
|
7856
|
-
relations_created: result.relations_created
|
|
8723
|
+
relations_created: result.relations_created,
|
|
8724
|
+
diagnostics: {
|
|
8725
|
+
scope: {
|
|
8726
|
+
project: memoryScope.project || null,
|
|
8727
|
+
user_id: memoryScope.userId,
|
|
8728
|
+
session_id: memoryScope.sessionId || session_id,
|
|
8729
|
+
scope: memoryScope.scopeMode
|
|
8730
|
+
}
|
|
8731
|
+
}
|
|
7857
8732
|
});
|
|
7858
8733
|
} catch (error) {
|
|
7859
8734
|
return primaryToolError(error.message);
|
|
@@ -7984,6 +8859,14 @@ async function main() {
|
|
|
7984
8859
|
console.error("Error: WHISPER_API_KEY environment variable is required");
|
|
7985
8860
|
process.exit(1);
|
|
7986
8861
|
}
|
|
8862
|
+
const startupDiagnostics = {
|
|
8863
|
+
runtime_mode: RUNTIME_MODE,
|
|
8864
|
+
local_ingest_enabled: RUNTIME_MODE !== "remote",
|
|
8865
|
+
startup_status: RUNTIME_MODE === "remote" ? "degraded_auto_repairing" : "healthy",
|
|
8866
|
+
startup_action: RUNTIME_MODE === "remote" ? "restart_client" : "none",
|
|
8867
|
+
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
|
|
8868
|
+
};
|
|
8869
|
+
console.error(`[whisper-context-mcp] startup_diagnostics=${JSON.stringify(startupDiagnostics)}`);
|
|
7987
8870
|
console.error("[whisper-context-mcp] Breaking change: canonical namespaced tool names are active. Run with --print-tool-map for migration mapping.");
|
|
7988
8871
|
const transport = new StdioServerTransport();
|
|
7989
8872
|
await server.connect(transport);
|
|
@@ -7996,20 +8879,35 @@ export {
|
|
|
7996
8879
|
RECOMMENDED_NEXT_CALL_ALLOWLIST,
|
|
7997
8880
|
RETRIEVAL_READINESS_VALUES,
|
|
7998
8881
|
RETRIEVAL_ROUTE_VALUES,
|
|
8882
|
+
STATUS_ACTION_VALUES,
|
|
8883
|
+
STATUS_LABEL_VALUES,
|
|
7999
8884
|
WORKSPACE_HEALTH_VALUES,
|
|
8000
8885
|
canonicalizeWorkspacePath,
|
|
8001
8886
|
chooseWorkspaceProjectSource,
|
|
8002
8887
|
classifyProjectRepoReadiness,
|
|
8003
8888
|
classifyRepoGroundedQuery,
|
|
8004
8889
|
classifyWorkspaceHealth,
|
|
8890
|
+
computeSnapshotChangedFiles,
|
|
8891
|
+
computeTrustScore,
|
|
8005
8892
|
createMcpServer,
|
|
8006
8893
|
createWhisperMcpClient,
|
|
8007
8894
|
createWhisperMcpRuntimeClient,
|
|
8895
|
+
defaultMcpUserId,
|
|
8008
8896
|
extractSignature,
|
|
8897
|
+
fallbackModeFromSearchMode,
|
|
8898
|
+
isStrictlyBetterReadiness,
|
|
8899
|
+
recommendedNextCallsAreAcyclic,
|
|
8900
|
+
recommendedNextCallsForRootCause,
|
|
8009
8901
|
renderScopedMcpConfig,
|
|
8010
8902
|
resolveForgetQueryCandidates,
|
|
8903
|
+
resolveMcpScope,
|
|
8011
8904
|
resolveWorkspaceIdentity,
|
|
8905
|
+
retrievalReadinessRank,
|
|
8012
8906
|
runSearchCodeSearch,
|
|
8013
8907
|
sanitizeRecommendedNextCalls,
|
|
8014
|
-
|
|
8908
|
+
semanticStatusFromSearchMode,
|
|
8909
|
+
shouldAbstainForCodebaseTrust,
|
|
8910
|
+
shouldTriggerBackgroundRefresh,
|
|
8911
|
+
statusActionForRootCause,
|
|
8912
|
+
statusContractForReadiness
|
|
8015
8913
|
};
|