@usewhisper/mcp-server 2.1.0 → 2.3.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/dist/server.js +269 -45
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -524,9 +524,71 @@ var WhisperContext = class _WhisperContext {
|
|
|
524
524
|
this.projectRefToId.set(p.slug, p.id);
|
|
525
525
|
this.projectRefToId.set(p.name, p.id);
|
|
526
526
|
}
|
|
527
|
+
if (this.defaultProject) {
|
|
528
|
+
const hasDefaultProject = this.projectCache.some(
|
|
529
|
+
(project) => project.id === this.defaultProject || project.slug === this.defaultProject || project.name === this.defaultProject
|
|
530
|
+
);
|
|
531
|
+
if (!hasDefaultProject) {
|
|
532
|
+
const resolvedDefault = await this.fetchResolvedProject(this.defaultProject);
|
|
533
|
+
if (resolvedDefault) {
|
|
534
|
+
this.projectCache = [...this.projectCache, resolvedDefault];
|
|
535
|
+
this.projectRefToId.set(resolvedDefault.id, resolvedDefault.id);
|
|
536
|
+
this.projectRefToId.set(resolvedDefault.slug, resolvedDefault.id);
|
|
537
|
+
this.projectRefToId.set(resolvedDefault.name, resolvedDefault.id);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
527
541
|
this.projectCacheExpiresAt = Date.now() + PROJECT_CACHE_TTL_MS;
|
|
528
542
|
return this.projectCache;
|
|
529
543
|
}
|
|
544
|
+
async fetchResolvedProject(projectRef) {
|
|
545
|
+
if (!projectRef) return null;
|
|
546
|
+
try {
|
|
547
|
+
const response = await this.request(`/v1/projects/resolve?project=${encodeURIComponent(projectRef)}`, { method: "GET" });
|
|
548
|
+
return response?.resolved || null;
|
|
549
|
+
} catch (error) {
|
|
550
|
+
if (error instanceof WhisperError && error.code === "PROJECT_NOT_FOUND") {
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
throw error;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
async resolveProject(projectRef) {
|
|
557
|
+
const resolvedRef = this.getRequiredProject(projectRef);
|
|
558
|
+
const cachedProjects = await this.refreshProjectCache(false);
|
|
559
|
+
const cachedProject = cachedProjects.find(
|
|
560
|
+
(project) => project.id === resolvedRef || project.slug === resolvedRef || project.name === resolvedRef
|
|
561
|
+
);
|
|
562
|
+
if (cachedProject) {
|
|
563
|
+
return cachedProject;
|
|
564
|
+
}
|
|
565
|
+
const resolvedProject = await this.fetchResolvedProject(resolvedRef);
|
|
566
|
+
if (resolvedProject) {
|
|
567
|
+
this.projectRefToId.set(resolvedProject.id, resolvedProject.id);
|
|
568
|
+
this.projectRefToId.set(resolvedProject.slug, resolvedProject.id);
|
|
569
|
+
this.projectRefToId.set(resolvedProject.name, resolvedProject.id);
|
|
570
|
+
this.projectCache = [
|
|
571
|
+
...this.projectCache.filter((project) => project.id !== resolvedProject.id),
|
|
572
|
+
resolvedProject
|
|
573
|
+
];
|
|
574
|
+
this.projectCacheExpiresAt = Date.now() + PROJECT_CACHE_TTL_MS;
|
|
575
|
+
return resolvedProject;
|
|
576
|
+
}
|
|
577
|
+
if (isLikelyProjectId(resolvedRef)) {
|
|
578
|
+
return {
|
|
579
|
+
id: resolvedRef,
|
|
580
|
+
orgId: "",
|
|
581
|
+
name: resolvedRef,
|
|
582
|
+
slug: resolvedRef,
|
|
583
|
+
createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
584
|
+
updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
throw new WhisperError({
|
|
588
|
+
code: "PROJECT_NOT_FOUND",
|
|
589
|
+
message: `Project '${resolvedRef}' not found`
|
|
590
|
+
});
|
|
591
|
+
}
|
|
530
592
|
async resolveProjectId(projectRef) {
|
|
531
593
|
if (this.projectRefToId.has(projectRef)) {
|
|
532
594
|
return this.projectRefToId.get(projectRef);
|
|
@@ -547,6 +609,18 @@ var WhisperContext = class _WhisperContext {
|
|
|
547
609
|
if (isLikelyProjectId(projectRef)) {
|
|
548
610
|
return projectRef;
|
|
549
611
|
}
|
|
612
|
+
const resolvedProject = await this.fetchResolvedProject(projectRef);
|
|
613
|
+
if (resolvedProject) {
|
|
614
|
+
this.projectRefToId.set(resolvedProject.id, resolvedProject.id);
|
|
615
|
+
this.projectRefToId.set(resolvedProject.slug, resolvedProject.id);
|
|
616
|
+
this.projectRefToId.set(resolvedProject.name, resolvedProject.id);
|
|
617
|
+
this.projectCache = [
|
|
618
|
+
...this.projectCache.filter((project) => project.id !== resolvedProject.id),
|
|
619
|
+
resolvedProject
|
|
620
|
+
];
|
|
621
|
+
this.projectCacheExpiresAt = Date.now() + PROJECT_CACHE_TTL_MS;
|
|
622
|
+
return resolvedProject.id;
|
|
623
|
+
}
|
|
550
624
|
throw new WhisperError({
|
|
551
625
|
code: "PROJECT_NOT_FOUND",
|
|
552
626
|
message: `Project '${projectRef}' not found`
|
|
@@ -602,6 +676,26 @@ var WhisperContext = class _WhisperContext {
|
|
|
602
676
|
message: `Project '${projectRef}' not found`
|
|
603
677
|
});
|
|
604
678
|
}
|
|
679
|
+
shouldRetryWithResolvedProjectId(error) {
|
|
680
|
+
return error instanceof WhisperError && error.status === 404 && !this.isEndpointNotFoundError(error);
|
|
681
|
+
}
|
|
682
|
+
async withProjectPathFallback(projectRef, execute) {
|
|
683
|
+
try {
|
|
684
|
+
return await execute(projectRef);
|
|
685
|
+
} catch (error) {
|
|
686
|
+
if (!this.shouldRetryWithResolvedProjectId(error)) {
|
|
687
|
+
throw error;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
const resolvedProjectId = await this.resolveProjectId(projectRef);
|
|
691
|
+
if (resolvedProjectId === projectRef) {
|
|
692
|
+
throw new WhisperError({
|
|
693
|
+
code: "PROJECT_NOT_FOUND",
|
|
694
|
+
message: `Project '${projectRef}' not found`
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
return execute(resolvedProjectId);
|
|
698
|
+
}
|
|
605
699
|
classifyError(status, message) {
|
|
606
700
|
if (status === 401 || /api key|unauthorized|forbidden/i.test(message)) {
|
|
607
701
|
return { code: "INVALID_API_KEY", retryable: false };
|
|
@@ -717,29 +811,42 @@ var WhisperContext = class _WhisperContext {
|
|
|
717
811
|
return projects;
|
|
718
812
|
}
|
|
719
813
|
async getProject(id) {
|
|
720
|
-
|
|
721
|
-
|
|
814
|
+
return this.withProjectPathFallback(
|
|
815
|
+
this.getRequiredProject(id),
|
|
816
|
+
(projectPathRef) => this.request(`/v1/projects/${encodeURIComponent(projectPathRef)}`)
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
async listSources(project) {
|
|
820
|
+
const projectRef = this.getRequiredProject(project);
|
|
821
|
+
return this.withProjectRefFallback(
|
|
822
|
+
projectRef,
|
|
823
|
+
(resolvedProject) => this.request(`/v1/sources?project=${encodeURIComponent(resolvedProject)}`, { method: "GET" })
|
|
824
|
+
);
|
|
722
825
|
}
|
|
723
826
|
async deleteProject(id) {
|
|
724
827
|
const projectId = await this.resolveProjectId(id);
|
|
725
828
|
return this.request(`/v1/projects/${projectId}`, { method: "DELETE" });
|
|
726
829
|
}
|
|
727
830
|
async addSource(projectId, params) {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
831
|
+
return this.withProjectPathFallback(
|
|
832
|
+
this.getRequiredProject(projectId),
|
|
833
|
+
(projectPathRef) => this.request(`/v1/projects/${encodeURIComponent(projectPathRef)}/sources`, {
|
|
834
|
+
method: "POST",
|
|
835
|
+
body: JSON.stringify(params)
|
|
836
|
+
})
|
|
837
|
+
);
|
|
733
838
|
}
|
|
734
839
|
async syncSource(sourceId) {
|
|
735
840
|
return this.request(`/v1/sources/${sourceId}/sync`, { method: "POST" });
|
|
736
841
|
}
|
|
737
842
|
async addSourceByType(projectId, params) {
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
843
|
+
return this.withProjectPathFallback(
|
|
844
|
+
this.getRequiredProject(projectId),
|
|
845
|
+
(projectPathRef) => this.request(`/v1/projects/${encodeURIComponent(projectPathRef)}/add_source`, {
|
|
846
|
+
method: "POST",
|
|
847
|
+
body: JSON.stringify(params)
|
|
848
|
+
})
|
|
849
|
+
);
|
|
743
850
|
}
|
|
744
851
|
async getSourceStatus(sourceId) {
|
|
745
852
|
return this.request(`/v1/sources/${sourceId}/status`, { method: "GET" });
|
|
@@ -801,14 +908,16 @@ var WhisperContext = class _WhisperContext {
|
|
|
801
908
|
};
|
|
802
909
|
}
|
|
803
910
|
async ingest(projectId, documents) {
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
911
|
+
return this.withProjectPathFallback(
|
|
912
|
+
this.getRequiredProject(projectId),
|
|
913
|
+
(projectPathRef) => this.request(`/v1/projects/${encodeURIComponent(projectPathRef)}/ingest`, {
|
|
914
|
+
method: "POST",
|
|
915
|
+
body: JSON.stringify({ documents })
|
|
916
|
+
})
|
|
917
|
+
);
|
|
809
918
|
}
|
|
810
919
|
async addContext(params) {
|
|
811
|
-
const projectId = await this.
|
|
920
|
+
const projectId = (await this.resolveProject(this.getRequiredProject(params.project))).id;
|
|
812
921
|
return this.ingest(projectId, [
|
|
813
922
|
{
|
|
814
923
|
title: params.title || "Context",
|
|
@@ -860,7 +969,7 @@ var WhisperContext = class _WhisperContext {
|
|
|
860
969
|
importance: params.importance,
|
|
861
970
|
metadata: params.metadata,
|
|
862
971
|
async: params.async,
|
|
863
|
-
write_mode: params.write_mode
|
|
972
|
+
write_mode: params.write_mode || (params.async === true ? "async" : "sync")
|
|
864
973
|
})
|
|
865
974
|
});
|
|
866
975
|
const mode = direct?.mode === "async" ? "async" : direct?.mode === "sync" ? "sync" : void 0;
|
|
@@ -879,7 +988,8 @@ var WhisperContext = class _WhisperContext {
|
|
|
879
988
|
...direct?.status_url ? { status_url: direct.status_url } : {},
|
|
880
989
|
...direct?.accepted_at ? { accepted_at: direct.accepted_at } : {},
|
|
881
990
|
...direct?.visibility_sla_ms ? { visibility_sla_ms: direct.visibility_sla_ms } : {},
|
|
882
|
-
...direct?.pending_visibility !== void 0 ? { pending_visibility: Boolean(direct.pending_visibility) } : {}
|
|
991
|
+
...direct?.pending_visibility !== void 0 ? { pending_visibility: Boolean(direct.pending_visibility) } : {},
|
|
992
|
+
...direct?.semantic_status ? { semantic_status: direct.semantic_status } : {}
|
|
883
993
|
};
|
|
884
994
|
}
|
|
885
995
|
if (direct?.success === true) {
|
|
@@ -892,7 +1002,8 @@ var WhisperContext = class _WhisperContext {
|
|
|
892
1002
|
...direct?.status_url ? { status_url: direct.status_url } : {},
|
|
893
1003
|
...direct?.accepted_at ? { accepted_at: direct.accepted_at } : {},
|
|
894
1004
|
...direct?.visibility_sla_ms ? { visibility_sla_ms: direct.visibility_sla_ms } : {},
|
|
895
|
-
...direct?.pending_visibility !== void 0 ? { pending_visibility: Boolean(direct.pending_visibility) } : {}
|
|
1005
|
+
...direct?.pending_visibility !== void 0 ? { pending_visibility: Boolean(direct.pending_visibility) } : {},
|
|
1006
|
+
...direct?.semantic_status ? { semantic_status: direct.semantic_status } : {}
|
|
896
1007
|
};
|
|
897
1008
|
}
|
|
898
1009
|
} catch (error) {
|
|
@@ -927,7 +1038,8 @@ var WhisperContext = class _WhisperContext {
|
|
|
927
1038
|
path: "legacy",
|
|
928
1039
|
fallback_used: true,
|
|
929
1040
|
mode: "sync",
|
|
930
|
-
memory_id: id
|
|
1041
|
+
memory_id: id,
|
|
1042
|
+
semantic_status: "ready"
|
|
931
1043
|
};
|
|
932
1044
|
});
|
|
933
1045
|
}
|
|
@@ -1215,28 +1327,37 @@ var WhisperContext = class _WhisperContext {
|
|
|
1215
1327
|
});
|
|
1216
1328
|
}
|
|
1217
1329
|
async createSharedContext(params) {
|
|
1218
|
-
const
|
|
1219
|
-
return this.
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1330
|
+
const projectRef = this.getRequiredProject(params.project);
|
|
1331
|
+
return this.withProjectRefFallback(
|
|
1332
|
+
projectRef,
|
|
1333
|
+
(project) => this.request("/v1/context/share", {
|
|
1334
|
+
method: "POST",
|
|
1335
|
+
body: JSON.stringify({ ...params, project })
|
|
1336
|
+
})
|
|
1337
|
+
);
|
|
1223
1338
|
}
|
|
1224
1339
|
async loadSharedContext(shareId) {
|
|
1225
1340
|
return this.request(`/v1/context/shared/${shareId}`);
|
|
1226
1341
|
}
|
|
1227
1342
|
async resumeFromSharedContext(params) {
|
|
1228
|
-
const
|
|
1229
|
-
return this.
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1343
|
+
const projectRef = this.getRequiredProject(params.project);
|
|
1344
|
+
return this.withProjectRefFallback(
|
|
1345
|
+
projectRef,
|
|
1346
|
+
(project) => this.request("/v1/context/resume", {
|
|
1347
|
+
method: "POST",
|
|
1348
|
+
body: JSON.stringify({ ...params, project })
|
|
1349
|
+
})
|
|
1350
|
+
);
|
|
1233
1351
|
}
|
|
1234
1352
|
async consolidateMemories(params) {
|
|
1235
|
-
const
|
|
1236
|
-
return this.
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1353
|
+
const projectRef = this.getRequiredProject(params.project);
|
|
1354
|
+
return this.withProjectRefFallback(
|
|
1355
|
+
projectRef,
|
|
1356
|
+
(project) => this.request("/v1/memory/consolidate", {
|
|
1357
|
+
method: "POST",
|
|
1358
|
+
body: JSON.stringify({ ...params, project })
|
|
1359
|
+
})
|
|
1360
|
+
);
|
|
1240
1361
|
}
|
|
1241
1362
|
async updateImportanceDecay(params) {
|
|
1242
1363
|
const project = await this.resolveProjectId(this.getRequiredProject(params.project));
|
|
@@ -1619,7 +1740,17 @@ function computeChecksum(value) {
|
|
|
1619
1740
|
}
|
|
1620
1741
|
var cachedProjectRef = DEFAULT_PROJECT || void 0;
|
|
1621
1742
|
async function resolveProjectRef(explicit) {
|
|
1622
|
-
if (explicit?.trim())
|
|
1743
|
+
if (explicit?.trim()) {
|
|
1744
|
+
const requestedRef = explicit.trim();
|
|
1745
|
+
try {
|
|
1746
|
+
const resolved = await whisper.resolveProject(requestedRef);
|
|
1747
|
+
cachedProjectRef = resolved.slug || resolved.name || resolved.id;
|
|
1748
|
+
return cachedProjectRef;
|
|
1749
|
+
} catch {
|
|
1750
|
+
cachedProjectRef = requestedRef;
|
|
1751
|
+
return requestedRef;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1623
1754
|
if (cachedProjectRef) return cachedProjectRef;
|
|
1624
1755
|
try {
|
|
1625
1756
|
const { projects } = await whisper.listProjects();
|
|
@@ -2516,8 +2647,9 @@ server.tool(
|
|
|
2516
2647
|
const memoryId = result?.memory_id || result.id;
|
|
2517
2648
|
const jobId = result?.job_id;
|
|
2518
2649
|
const mode = result?.mode;
|
|
2650
|
+
const semanticStatus = result?.semantic_status;
|
|
2519
2651
|
const typeLabel = memory_type || "factual";
|
|
2520
|
-
const text = mode === "async" || jobId ? `Memory queued (job_id: ${jobId || result.id}, type: ${typeLabel}).` : `Memory stored (id: ${memoryId}, type: ${typeLabel}).`;
|
|
2652
|
+
const text = mode === "async" || jobId ? `Memory queued (job_id: ${jobId || result.id}, type: ${typeLabel}).` : `Memory stored (id: ${memoryId}, type: ${typeLabel}${semanticStatus ? `, semantic_status: ${semanticStatus}` : ""}).`;
|
|
2521
2653
|
return { content: [{ type: "text", text }] };
|
|
2522
2654
|
} catch (error) {
|
|
2523
2655
|
return { content: [{ type: "text", text: `Error: ${error.message}` }] };
|
|
@@ -2564,7 +2696,19 @@ server.tool(
|
|
|
2564
2696
|
async () => {
|
|
2565
2697
|
try {
|
|
2566
2698
|
const { projects } = await whisper.listProjects();
|
|
2567
|
-
const
|
|
2699
|
+
const visibleProjects = [...projects];
|
|
2700
|
+
if (cachedProjectRef) {
|
|
2701
|
+
const hasCachedProject = visibleProjects.some(
|
|
2702
|
+
(project) => project.id === cachedProjectRef || project.slug === cachedProjectRef || project.name === cachedProjectRef
|
|
2703
|
+
);
|
|
2704
|
+
if (!hasCachedProject) {
|
|
2705
|
+
try {
|
|
2706
|
+
visibleProjects.push(await whisper.resolveProject(cachedProjectRef));
|
|
2707
|
+
} catch {
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
const text = visibleProjects.length === 0 ? "No projects found." : visibleProjects.map((p) => `- ${p.name} (${p.slug})${p.description ? `: ${p.description}` : ""}`).join("\n");
|
|
2568
2712
|
return { content: [{ type: "text", text }] };
|
|
2569
2713
|
} catch (error) {
|
|
2570
2714
|
return { content: [{ type: "text", text: `Error: ${error.message}` }] };
|
|
@@ -2577,8 +2721,8 @@ server.tool(
|
|
|
2577
2721
|
{ project: z.string().optional().describe("Project name or slug") },
|
|
2578
2722
|
async ({ project }) => {
|
|
2579
2723
|
try {
|
|
2580
|
-
const
|
|
2581
|
-
const srcs =
|
|
2724
|
+
const sourceData = await whisper.listSources(project || DEFAULT_PROJECT);
|
|
2725
|
+
const srcs = sourceData.sources || [];
|
|
2582
2726
|
const text = srcs.length === 0 ? "No sources connected." : srcs.map((s) => `- ${s.name} (${s.connectorType}) \u2014 ${s.status}`).join("\n");
|
|
2583
2727
|
return { content: [{ type: "text", text }] };
|
|
2584
2728
|
} catch (error) {
|
|
@@ -3130,7 +3274,25 @@ server.tool(
|
|
|
3130
3274
|
top_k: 25,
|
|
3131
3275
|
include_relations: false
|
|
3132
3276
|
});
|
|
3133
|
-
const
|
|
3277
|
+
const normalizedQuery = String(target.query || "").trim().toLowerCase();
|
|
3278
|
+
const exactMatches = (search.results || []).filter((r) => {
|
|
3279
|
+
const memory = r?.memory || r;
|
|
3280
|
+
const content = String(memory?.content || "").trim().toLowerCase();
|
|
3281
|
+
const memoryId = String(memory?.id || "").trim().toLowerCase();
|
|
3282
|
+
const metadata = memory?.metadata || {};
|
|
3283
|
+
const normalizedContent = String(metadata?.normalized_content || "").trim().toLowerCase();
|
|
3284
|
+
const canonicalContent = String(metadata?.canonical_content || "").trim().toLowerCase();
|
|
3285
|
+
return memoryId === normalizedQuery || content === normalizedQuery || normalizedContent === normalizedQuery || canonicalContent === normalizedQuery;
|
|
3286
|
+
});
|
|
3287
|
+
const memoryIds = exactMatches.map((r) => String(r?.memory?.id || "")).filter(Boolean);
|
|
3288
|
+
if (memoryIds.length === 0) {
|
|
3289
|
+
const payload2 = {
|
|
3290
|
+
status: "completed",
|
|
3291
|
+
affected_ids: affectedIds,
|
|
3292
|
+
warning: "Query did not resolve to an exact memory match. No memories were changed."
|
|
3293
|
+
};
|
|
3294
|
+
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
3295
|
+
}
|
|
3134
3296
|
for (const id of memoryIds) {
|
|
3135
3297
|
await applyToMemory(id);
|
|
3136
3298
|
}
|
|
@@ -3204,6 +3366,7 @@ server.tool(
|
|
|
3204
3366
|
const bundleWithoutChecksum = {
|
|
3205
3367
|
bundle_version: "1.0",
|
|
3206
3368
|
workspace_id: workspaceId,
|
|
3369
|
+
...resolvedProject ? { project: resolvedProject } : {},
|
|
3207
3370
|
exported_at: now,
|
|
3208
3371
|
contents
|
|
3209
3372
|
};
|
|
@@ -3223,6 +3386,7 @@ server.tool(
|
|
|
3223
3386
|
bundle: z.object({
|
|
3224
3387
|
bundle_version: z.string(),
|
|
3225
3388
|
workspace_id: z.string(),
|
|
3389
|
+
project: z.string().optional(),
|
|
3226
3390
|
exported_at: z.string(),
|
|
3227
3391
|
contents: z.object({
|
|
3228
3392
|
memories: z.array(z.any()).default([]),
|
|
@@ -3246,8 +3410,10 @@ server.tool(
|
|
|
3246
3410
|
if (dedupe_strategy === "id") return existing.some((e) => e.id === incoming.id);
|
|
3247
3411
|
const norm = incoming.content.toLowerCase().trim();
|
|
3248
3412
|
return existing.some((e) => e.content.toLowerCase().trim() === norm);
|
|
3413
|
+
}, normalizeString2 = function(value) {
|
|
3414
|
+
return String(value || "").trim().toLowerCase();
|
|
3249
3415
|
};
|
|
3250
|
-
var dedupe = dedupe2;
|
|
3416
|
+
var dedupe = dedupe2, normalizeString = normalizeString2;
|
|
3251
3417
|
const workspaceId = getWorkspaceId(workspace_id || bundle.workspace_id);
|
|
3252
3418
|
const state = loadState();
|
|
3253
3419
|
const workspace = getWorkspaceState(state, workspaceId);
|
|
@@ -3273,6 +3439,30 @@ server.tool(
|
|
|
3273
3439
|
session_summaries: 0,
|
|
3274
3440
|
documents: 0
|
|
3275
3441
|
};
|
|
3442
|
+
const resolvedProject = await resolveProjectRef(bundle.project);
|
|
3443
|
+
async function shouldSkipImportedMemory(memory) {
|
|
3444
|
+
if (dedupe_strategy === "none" || !resolvedProject) return false;
|
|
3445
|
+
const exactId = normalizeString2(memory?.id);
|
|
3446
|
+
const exactContent = normalizeString2(memory?.content);
|
|
3447
|
+
if (!exactId && !exactContent) return false;
|
|
3448
|
+
const existing = await whisper.searchMemoriesSOTA({
|
|
3449
|
+
project: resolvedProject,
|
|
3450
|
+
query: exactId || exactContent,
|
|
3451
|
+
top_k: 10,
|
|
3452
|
+
include_relations: false
|
|
3453
|
+
});
|
|
3454
|
+
return (existing.results || []).some((result) => {
|
|
3455
|
+
const candidate = result?.memory || result;
|
|
3456
|
+
const candidateId = normalizeString2(candidate?.id);
|
|
3457
|
+
const candidateContent = normalizeString2(candidate?.content);
|
|
3458
|
+
const candidateMetadata = candidate?.metadata || {};
|
|
3459
|
+
const importedOriginalId = normalizeString2(candidateMetadata?.bundle_original_id);
|
|
3460
|
+
if (dedupe_strategy === "id") {
|
|
3461
|
+
return Boolean(exactId) && (candidateId === exactId || importedOriginalId === exactId);
|
|
3462
|
+
}
|
|
3463
|
+
return Boolean(exactContent) && candidateContent === exactContent;
|
|
3464
|
+
});
|
|
3465
|
+
}
|
|
3276
3466
|
if (mode === "replace") {
|
|
3277
3467
|
workspace.entities = [];
|
|
3278
3468
|
workspace.decisions = [];
|
|
@@ -3282,6 +3472,40 @@ server.tool(
|
|
|
3282
3472
|
workspace.documents = [];
|
|
3283
3473
|
workspace.events = [];
|
|
3284
3474
|
}
|
|
3475
|
+
if (!checksumVerified) {
|
|
3476
|
+
const payload2 = {
|
|
3477
|
+
imported_counts: importedCounts,
|
|
3478
|
+
skipped_counts: skippedCounts,
|
|
3479
|
+
conflicts,
|
|
3480
|
+
checksum_verified: checksumVerified
|
|
3481
|
+
};
|
|
3482
|
+
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
3483
|
+
}
|
|
3484
|
+
for (const memory of bundle.contents.memories || []) {
|
|
3485
|
+
if (!resolvedProject) {
|
|
3486
|
+
skippedCounts.memories += 1;
|
|
3487
|
+
continue;
|
|
3488
|
+
}
|
|
3489
|
+
if (await shouldSkipImportedMemory(memory)) {
|
|
3490
|
+
skippedCounts.memories += 1;
|
|
3491
|
+
continue;
|
|
3492
|
+
}
|
|
3493
|
+
await whisper.addMemory({
|
|
3494
|
+
project: resolvedProject,
|
|
3495
|
+
content: String(memory?.content || ""),
|
|
3496
|
+
memory_type: String(memory?.type || memory?.memoryType || "factual"),
|
|
3497
|
+
user_id: memory?.user_id || memory?.userId,
|
|
3498
|
+
session_id: memory?.session_id || memory?.sessionId,
|
|
3499
|
+
importance: typeof memory?.importance === "number" ? memory.importance : void 0,
|
|
3500
|
+
metadata: {
|
|
3501
|
+
...memory?.metadata && typeof memory.metadata === "object" ? memory.metadata : {},
|
|
3502
|
+
bundle_original_id: memory?.id || void 0,
|
|
3503
|
+
imported_from_bundle: true,
|
|
3504
|
+
bundle_exported_at: bundle.exported_at
|
|
3505
|
+
}
|
|
3506
|
+
});
|
|
3507
|
+
importedCounts.memories += 1;
|
|
3508
|
+
}
|
|
3285
3509
|
const keys = ["entities", "decisions", "failures", "annotations", "session_summaries", "documents"];
|
|
3286
3510
|
for (const key of keys) {
|
|
3287
3511
|
const sourceItems = bundle.contents[key];
|
|
@@ -3308,7 +3532,7 @@ server.tool(
|
|
|
3308
3532
|
const payload = {
|
|
3309
3533
|
imported_counts: importedCounts,
|
|
3310
3534
|
skipped_counts: skippedCounts,
|
|
3311
|
-
conflicts,
|
|
3535
|
+
conflicts: resolvedProject ? conflicts : [...conflicts, "project_unresolved"],
|
|
3312
3536
|
checksum_verified: checksumVerified
|
|
3313
3537
|
};
|
|
3314
3538
|
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|