dsh-daoing-memory 0.1.6 → 0.1.8
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/lib/client.js +392 -119
- package/lib/client.js.map +1 -1
- package/lib/index.js +315 -6
- package/lib/typert.host.js +242 -63
- package/lib/typert.remote-client.d.ts +10 -1
- package/lib/typert.remote-client.js +214 -60
- package/lib/types/core.d.ts +39 -1
- package/lib/types/core.js +120 -0
- package/lib/types/index.d.ts +4 -0
- package/lib/types/index.js +5 -0
- package/lib/types/service.d.ts +27 -2
- package/lib/types/service.js +113 -1
- package/lib/types/store.d.ts +16 -0
- package/lib/types/store.js +33 -0
- package/lib/types/types.d.ts +18 -0
- package/lib/types/types.js +14 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -698,6 +698,40 @@ var MemoryStore = class {
|
|
|
698
698
|
countExperiencesSince(ts) {
|
|
699
699
|
return this.db.prepare("SELECT COUNT(*) AS n FROM experiences WHERE deleted = 0 AND created_at > ?").get(ts).n;
|
|
700
700
|
}
|
|
701
|
+
/** Last deletion-feedback summarization ts (0 = never). Stored in memory_meta. */
|
|
702
|
+
lastDeletionFeedbackTs() {
|
|
703
|
+
const row = this.db.prepare("SELECT value FROM memory_meta WHERE key = 'last_deletion_feedback_ts'").get();
|
|
704
|
+
return row ? Number(row.value) : 0;
|
|
705
|
+
}
|
|
706
|
+
/** Record the timestamp of a deletion-feedback summarization run. */
|
|
707
|
+
setLastDeletionFeedbackTs(ts) {
|
|
708
|
+
this.db.prepare("INSERT OR REPLACE INTO memory_meta (key, value) VALUES ('last_deletion_feedback_ts', ?)").run(String(ts));
|
|
709
|
+
}
|
|
710
|
+
/** Count experience deletions (ledger op='delete', objectType='experience') since a given ts. */
|
|
711
|
+
countDeletionsSince(ts) {
|
|
712
|
+
return this.db.prepare("SELECT COUNT(*) AS n FROM ledger WHERE op = 'delete' AND object_type = 'experience' AND ts > ?").get(ts).n;
|
|
713
|
+
}
|
|
714
|
+
/** Get the deletion ledger blocks since a given ts (for LLM summarization input). */
|
|
715
|
+
getDeletionRecordsSince(ts, limit = 50) {
|
|
716
|
+
return this.db.prepare("SELECT seq, ts, object_id, reason, payload FROM ledger WHERE op = 'delete' AND object_type = 'experience' AND ts > ? ORDER BY ts DESC LIMIT ?").all(ts, limit).map((r) => {
|
|
717
|
+
let gist = "";
|
|
718
|
+
try {
|
|
719
|
+
gist = JSON.parse(r.payload).gist ?? "";
|
|
720
|
+
} catch {}
|
|
721
|
+
return {
|
|
722
|
+
seq: r.seq,
|
|
723
|
+
ts: r.ts,
|
|
724
|
+
objectId: r.object_id,
|
|
725
|
+
reason: r.reason ?? "",
|
|
726
|
+
gist
|
|
727
|
+
};
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
/** Find the active (non-deleted) experience by family name. Returns the latest revision. */
|
|
731
|
+
findExperienceByFamily(family) {
|
|
732
|
+
const row = this.db.prepare("SELECT * FROM experiences WHERE family = ? AND deleted = 0 ORDER BY revision DESC LIMIT 1").get(family);
|
|
733
|
+
return row ? this.rowToExperience(row) : void 0;
|
|
734
|
+
}
|
|
701
735
|
/** Archive a set of experiences by family_id (leave recall; recoverable — never hard-deleted autonomously). */
|
|
702
736
|
archiveExperienceIds(ids, ts) {
|
|
703
737
|
const stmt = this.db.prepare(`UPDATE experiences SET status = ?, updated_at = ? WHERE family_id = ? AND deleted = 0 AND status IN ('candidate','live','challenged')`);
|
|
@@ -825,6 +859,25 @@ var MemoryStore = class {
|
|
|
825
859
|
}
|
|
826
860
|
};
|
|
827
861
|
//#endregion
|
|
862
|
+
//#region lib/types/types.js
|
|
863
|
+
/**
|
|
864
|
+
* Memory system wire vocabulary: experience lifecycle, recall adjudication,
|
|
865
|
+
* use reports with attribution, the diary/fact semantic layer, and the
|
|
866
|
+
* append-only ledger. Types only — no runtime code.
|
|
867
|
+
* @module dsh-daoing-memory/types
|
|
868
|
+
*/
|
|
869
|
+
/**
|
|
870
|
+
* System-managed experience families that cannot be deleted by human operators
|
|
871
|
+
* (only archived). The extraction-feedback family is auto-generated by the
|
|
872
|
+
* daily deletion-reason summarizer and serves as negative guidance for future
|
|
873
|
+
* memory extraction.
|
|
874
|
+
*/
|
|
875
|
+
const SYSTEM_EXPERIENCE_FAMILIES = new Set(["extraction-feedback"]);
|
|
876
|
+
/** Check whether an experience family is system-managed (delete-protected). */
|
|
877
|
+
function isSystemExperienceFamily(family) {
|
|
878
|
+
return SYSTEM_EXPERIENCE_FAMILIES.has(family);
|
|
879
|
+
}
|
|
880
|
+
//#endregion
|
|
828
881
|
//#region lib/types/core.js
|
|
829
882
|
/**
|
|
830
883
|
* Memory core: the 生·用·修·记 mechanisms over the durable store. Pure and
|
|
@@ -869,7 +922,9 @@ const DEFAULT_CORE_CONFIG = {
|
|
|
869
922
|
candidateTrialTopK: 3,
|
|
870
923
|
candidateTrialFloorScore: .18,
|
|
871
924
|
consolidateEveryNew: 6,
|
|
872
|
-
consolidateIntervalHours: 24
|
|
925
|
+
consolidateIntervalHours: 24,
|
|
926
|
+
deletionFeedbackIntervalHours: 24,
|
|
927
|
+
deletionFeedbackMinDeletions: 3
|
|
873
928
|
};
|
|
874
929
|
/** Objective-evidence markers overriding a claimed experience-attributed failure. */
|
|
875
930
|
const ENVIRONMENT_EVIDENCE_PATTERN = /network|timeout|timed out|EPERM|EACCES|ECONNREFUSED|ENOTFOUND|429|503|quota|rate.?limit|unauthorized|dns|proxy|网络|超时|断网|权限|配额|限流|服务不可用|服务繁忙/i;
|
|
@@ -912,7 +967,7 @@ function tokenOverlap(a, b) {
|
|
|
912
967
|
return hits / Math.sqrt(a.size * b.size);
|
|
913
968
|
}
|
|
914
969
|
/** The memory core: stateless over the injected store. */
|
|
915
|
-
var MemoryCore = class {
|
|
970
|
+
var MemoryCore = class MemoryCore {
|
|
916
971
|
store;
|
|
917
972
|
config;
|
|
918
973
|
/** @param store - the durable SQLite store. */
|
|
@@ -1543,6 +1598,8 @@ var MemoryCore = class {
|
|
|
1543
1598
|
rejected: [],
|
|
1544
1599
|
appliedConcerns: 0
|
|
1545
1600
|
};
|
|
1601
|
+
const feedback = this.getDeletionFeedback();
|
|
1602
|
+
if (feedback !== void 0) result.deletionFeedback = feedback.reasoning;
|
|
1546
1603
|
const now = Date.now();
|
|
1547
1604
|
const consumedDiary = /* @__PURE__ */ new Set();
|
|
1548
1605
|
for (const proposal of request.proposals) {
|
|
@@ -1863,6 +1920,100 @@ var MemoryCore = class {
|
|
|
1863
1920
|
}
|
|
1864
1921
|
return result;
|
|
1865
1922
|
}
|
|
1923
|
+
/** Family id for the auto-generated extraction-feedback experience. */
|
|
1924
|
+
static DELETION_FEEDBACK_FAMILY = "extraction-feedback";
|
|
1925
|
+
/**
|
|
1926
|
+
* Check whether a deletion-feedback summarization run is due.
|
|
1927
|
+
* Conditions: enough new deletions since last run AND enough time elapsed.
|
|
1928
|
+
* @returns { due, lastTs, newDeletions, hoursSince }
|
|
1929
|
+
*/
|
|
1930
|
+
deletionFeedbackDue() {
|
|
1931
|
+
const lastTs = this.store.lastDeletionFeedbackTs();
|
|
1932
|
+
const hoursSince = lastTs === 0 ? Infinity : (Date.now() - lastTs) / (3600 * 1e3);
|
|
1933
|
+
const newDeletions = this.store.countDeletionsSince(lastTs);
|
|
1934
|
+
const enoughDeletions = newDeletions >= this.config.deletionFeedbackMinDeletions;
|
|
1935
|
+
const intervalPassed = hoursSince >= this.config.deletionFeedbackIntervalHours;
|
|
1936
|
+
return {
|
|
1937
|
+
due: enoughDeletions && intervalPassed,
|
|
1938
|
+
lastTs,
|
|
1939
|
+
newDeletions,
|
|
1940
|
+
hoursSince
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
/**
|
|
1944
|
+
* Apply an LLM-generated deletion-feedback summary as an extraction-feedback
|
|
1945
|
+
* experience. If one already exists, it is revised in place (new revision);
|
|
1946
|
+
* otherwise a new candidate experience is created.
|
|
1947
|
+
* @param summary - the LLM-generated summary text (gist + reasoning).
|
|
1948
|
+
* @param actor - who triggered the summarization ('system').
|
|
1949
|
+
* @returns the upserted experience snapshot.
|
|
1950
|
+
*/
|
|
1951
|
+
applyDeletionFeedback(summary, actor) {
|
|
1952
|
+
const now = Date.now();
|
|
1953
|
+
const existing = this.store.findExperienceByFamily(MemoryCore.DELETION_FEEDBACK_FAMILY);
|
|
1954
|
+
if (existing !== void 0) {
|
|
1955
|
+
const next = {
|
|
1956
|
+
...existing,
|
|
1957
|
+
revision: existing.revision + 1,
|
|
1958
|
+
gist: summary.slice(0, 200),
|
|
1959
|
+
reasoning: summary,
|
|
1960
|
+
status: "live",
|
|
1961
|
+
updatedAt: now
|
|
1962
|
+
};
|
|
1963
|
+
this.store.upsertExperience(next);
|
|
1964
|
+
this.ledger("revise", "experience", next.id, actor, {
|
|
1965
|
+
revision: next.revision,
|
|
1966
|
+
previousRevision: existing.revision
|
|
1967
|
+
}, "deletion-feedback summarization");
|
|
1968
|
+
return next;
|
|
1969
|
+
}
|
|
1970
|
+
const id = crypto.randomUUID();
|
|
1971
|
+
const exp = {
|
|
1972
|
+
id,
|
|
1973
|
+
familyId: id,
|
|
1974
|
+
revision: 1,
|
|
1975
|
+
kind: "positive",
|
|
1976
|
+
source: "system",
|
|
1977
|
+
family: MemoryCore.DELETION_FEEDBACK_FAMILY,
|
|
1978
|
+
gist: summary.slice(0, 200),
|
|
1979
|
+
situation: ["memory_extract 提炼新记忆时,参考此经验避免重复提取已被用户否定的类型"],
|
|
1980
|
+
path: [{
|
|
1981
|
+
order: 1,
|
|
1982
|
+
action: "读取此经验的 reasoning 字段,了解哪些类型的记忆曾被用户删除及原因"
|
|
1983
|
+
}, {
|
|
1984
|
+
order: 2,
|
|
1985
|
+
action: "提炼时避开这些类型,优先提取用户认可的记忆模式"
|
|
1986
|
+
}],
|
|
1987
|
+
reasoning: summary,
|
|
1988
|
+
limits: ["此经验由系统自动生成,禁止人工删除(只能归档)", "内容会随删除记录增多而定期更新"],
|
|
1989
|
+
status: "live",
|
|
1990
|
+
alpha: 5,
|
|
1991
|
+
beta: 2,
|
|
1992
|
+
pinned: false,
|
|
1993
|
+
tokensSaved: 0,
|
|
1994
|
+
tokensSpent: 0,
|
|
1995
|
+
context: "",
|
|
1996
|
+
globalFlag: true,
|
|
1997
|
+
verifiedCount: 0,
|
|
1998
|
+
rejectCount: 0,
|
|
1999
|
+
createdAt: now,
|
|
2000
|
+
updatedAt: now
|
|
2001
|
+
};
|
|
2002
|
+
this.store.upsertExperience(exp);
|
|
2003
|
+
this.ledger("refine", "experience", exp.id, actor, {
|
|
2004
|
+
family: exp.family,
|
|
2005
|
+
status: exp.status
|
|
2006
|
+
}, "deletion-feedback summarization (initial)");
|
|
2007
|
+
this.store.setLastDeletionFeedbackTs(now);
|
|
2008
|
+
return exp;
|
|
2009
|
+
}
|
|
2010
|
+
/**
|
|
2011
|
+
* Get the current extraction-feedback experience (if any) for injection into
|
|
2012
|
+
* the extraction prompt.
|
|
2013
|
+
*/
|
|
2014
|
+
getDeletionFeedback() {
|
|
2015
|
+
return this.store.findExperienceByFamily(MemoryCore.DELETION_FEEDBACK_FAMILY);
|
|
2016
|
+
}
|
|
1866
2017
|
/** Human pin/unpin: pinned cards keep the trust floor and escape budgets. */
|
|
1867
2018
|
humanPin(request, actor) {
|
|
1868
2019
|
const current = this.store.getActiveRevision(request.id);
|
|
@@ -1881,6 +2032,7 @@ var MemoryCore = class {
|
|
|
1881
2032
|
const familyRows = this.store.getFamily(request.id);
|
|
1882
2033
|
if (familyRows.length === 0) throw new Error(`memory: experience not found: ${request.id}`);
|
|
1883
2034
|
const head = familyRows[familyRows.length - 1];
|
|
2035
|
+
if (isSystemExperienceFamily(head.family)) throw new Error(`memory: system experience "${head.family}" cannot be deleted (only archived). Use the archive action to remove it from active recall while preserving the audit trail.`);
|
|
1884
2036
|
this.store.deleteFamily(request.id);
|
|
1885
2037
|
this.ledger("delete", "experience", request.id, actor, {
|
|
1886
2038
|
gist: head.gist,
|
|
@@ -1888,6 +2040,27 @@ var MemoryCore = class {
|
|
|
1888
2040
|
revisions: familyRows.length
|
|
1889
2041
|
}, request.reason);
|
|
1890
2042
|
}
|
|
2043
|
+
/**
|
|
2044
|
+
* Human archive: move an experience to archived status. Unlike delete, the
|
|
2045
|
+
* data is preserved (recoverable via deep lookup) but removed from active
|
|
2046
|
+
* recall. This is the only way to retire system-managed experiences
|
|
2047
|
+
* (e.g. extraction-feedback).
|
|
2048
|
+
*/
|
|
2049
|
+
humanArchiveExperience(request, actor) {
|
|
2050
|
+
const current = this.store.getActiveRevision(request.id);
|
|
2051
|
+
if (current === void 0) throw new Error(`memory: experience not found: ${request.id}`);
|
|
2052
|
+
if (current.status === "archived") return;
|
|
2053
|
+
this.store.upsertExperience({
|
|
2054
|
+
...current,
|
|
2055
|
+
status: "archived",
|
|
2056
|
+
updatedAt: Date.now()
|
|
2057
|
+
});
|
|
2058
|
+
this.ledger("archive", "experience", request.id, actor, {
|
|
2059
|
+
gist: current.gist,
|
|
2060
|
+
family: current.family,
|
|
2061
|
+
previousStatus: current.status
|
|
2062
|
+
}, request.reason);
|
|
2063
|
+
}
|
|
1891
2064
|
/** Human edit: rewrite fields of the active revision in place. */
|
|
1892
2065
|
humanEditExperience(request, actor) {
|
|
1893
2066
|
const current = this.store.getActiveRevision(request.id);
|
|
@@ -2300,6 +2473,8 @@ let MemoryService = (() => {
|
|
|
2300
2473
|
let _family_decorators;
|
|
2301
2474
|
let _appendDiary_decorators;
|
|
2302
2475
|
let _extract_decorators;
|
|
2476
|
+
let _runDeletionFeedback_decorators;
|
|
2477
|
+
let _getDeletionFeedback_decorators;
|
|
2303
2478
|
let _listDiary_decorators;
|
|
2304
2479
|
let _getDiaryByIds_decorators;
|
|
2305
2480
|
let _listFacts_decorators;
|
|
@@ -2318,6 +2493,7 @@ let MemoryService = (() => {
|
|
|
2318
2493
|
let _exportLibrary_decorators;
|
|
2319
2494
|
let _humanPin_decorators;
|
|
2320
2495
|
let _humanDeleteExperience_decorators;
|
|
2496
|
+
let _humanArchiveExperience_decorators;
|
|
2321
2497
|
let _humanEditExperience_decorators;
|
|
2322
2498
|
let _humanAddExperience_decorators;
|
|
2323
2499
|
let _humanPromote_decorators;
|
|
@@ -2345,6 +2521,8 @@ let MemoryService = (() => {
|
|
|
2345
2521
|
_family_decorators = [Remote("family")];
|
|
2346
2522
|
_appendDiary_decorators = [Remote("appendDiary")];
|
|
2347
2523
|
_extract_decorators = [Remote("extract")];
|
|
2524
|
+
_runDeletionFeedback_decorators = [Remote("runDeletionFeedback")];
|
|
2525
|
+
_getDeletionFeedback_decorators = [Remote("getDeletionFeedback")];
|
|
2348
2526
|
_listDiary_decorators = [Remote("listDiary")];
|
|
2349
2527
|
_getDiaryByIds_decorators = [Remote("getDiaryByIds")];
|
|
2350
2528
|
_listFacts_decorators = [Remote("listFacts")];
|
|
@@ -2363,6 +2541,7 @@ let MemoryService = (() => {
|
|
|
2363
2541
|
_exportLibrary_decorators = [Remote("exportLibrary")];
|
|
2364
2542
|
_humanPin_decorators = [Remote("humanPin")];
|
|
2365
2543
|
_humanDeleteExperience_decorators = [Remote("humanDeleteExperience")];
|
|
2544
|
+
_humanArchiveExperience_decorators = [Remote("humanArchiveExperience")];
|
|
2366
2545
|
_humanEditExperience_decorators = [Remote("humanEditExperience")];
|
|
2367
2546
|
_humanAddExperience_decorators = [Remote("humanAddExperience")];
|
|
2368
2547
|
_humanPromote_decorators = [Remote("humanPromote")];
|
|
@@ -2507,6 +2686,28 @@ let MemoryService = (() => {
|
|
|
2507
2686
|
},
|
|
2508
2687
|
metadata: _metadata
|
|
2509
2688
|
}, null, _instanceExtraInitializers);
|
|
2689
|
+
__esDecorate(this, null, _runDeletionFeedback_decorators, {
|
|
2690
|
+
kind: "method",
|
|
2691
|
+
name: "runDeletionFeedback",
|
|
2692
|
+
static: false,
|
|
2693
|
+
private: false,
|
|
2694
|
+
access: {
|
|
2695
|
+
has: (obj) => "runDeletionFeedback" in obj,
|
|
2696
|
+
get: (obj) => obj.runDeletionFeedback
|
|
2697
|
+
},
|
|
2698
|
+
metadata: _metadata
|
|
2699
|
+
}, null, _instanceExtraInitializers);
|
|
2700
|
+
__esDecorate(this, null, _getDeletionFeedback_decorators, {
|
|
2701
|
+
kind: "method",
|
|
2702
|
+
name: "getDeletionFeedback",
|
|
2703
|
+
static: false,
|
|
2704
|
+
private: false,
|
|
2705
|
+
access: {
|
|
2706
|
+
has: (obj) => "getDeletionFeedback" in obj,
|
|
2707
|
+
get: (obj) => obj.getDeletionFeedback
|
|
2708
|
+
},
|
|
2709
|
+
metadata: _metadata
|
|
2710
|
+
}, null, _instanceExtraInitializers);
|
|
2510
2711
|
__esDecorate(this, null, _listDiary_decorators, {
|
|
2511
2712
|
kind: "method",
|
|
2512
2713
|
name: "listDiary",
|
|
@@ -2705,6 +2906,17 @@ let MemoryService = (() => {
|
|
|
2705
2906
|
},
|
|
2706
2907
|
metadata: _metadata
|
|
2707
2908
|
}, null, _instanceExtraInitializers);
|
|
2909
|
+
__esDecorate(this, null, _humanArchiveExperience_decorators, {
|
|
2910
|
+
kind: "method",
|
|
2911
|
+
name: "humanArchiveExperience",
|
|
2912
|
+
static: false,
|
|
2913
|
+
private: false,
|
|
2914
|
+
access: {
|
|
2915
|
+
has: (obj) => "humanArchiveExperience" in obj,
|
|
2916
|
+
get: (obj) => obj.humanArchiveExperience
|
|
2917
|
+
},
|
|
2918
|
+
metadata: _metadata
|
|
2919
|
+
}, null, _instanceExtraInitializers);
|
|
2708
2920
|
__esDecorate(this, null, _humanEditExperience_decorators, {
|
|
2709
2921
|
kind: "method",
|
|
2710
2922
|
name: "humanEditExperience",
|
|
@@ -2899,9 +3111,95 @@ let MemoryService = (() => {
|
|
|
2899
3111
|
return this.core.appendDiary(request, actorOf(agent));
|
|
2900
3112
|
}
|
|
2901
3113
|
/** 上升通道: apply extracted facts over the pending diary window. */
|
|
2902
|
-
extract(agent, request) {
|
|
3114
|
+
async extract(agent, request) {
|
|
3115
|
+
await this.maybeRunDeletionFeedbackSummarization(agent);
|
|
2903
3116
|
return this.core.extract(request, actorOf(agent), "manual");
|
|
2904
3117
|
}
|
|
3118
|
+
/**
|
|
3119
|
+
* Check if deletion-feedback summarization is due and run it if so.
|
|
3120
|
+
* Uses the agent's current model route for the LLM call.
|
|
3121
|
+
*/
|
|
3122
|
+
async maybeRunDeletionFeedbackSummarization(agent) {
|
|
3123
|
+
const check = this.core.deletionFeedbackDue();
|
|
3124
|
+
if (!check.due) return;
|
|
3125
|
+
try {
|
|
3126
|
+
const records = this.core["store"].getDeletionRecordsSince(check.lastTs, 50);
|
|
3127
|
+
if (records.length === 0) return;
|
|
3128
|
+
const summary = await this.summarizeDeletionsWithLlm(agent, records);
|
|
3129
|
+
if (summary.length > 0) this.core.applyDeletionFeedback(summary, "system");
|
|
3130
|
+
} catch {}
|
|
3131
|
+
}
|
|
3132
|
+
/**
|
|
3133
|
+
* Call the LLM to summarize deletion records into extraction feedback rules.
|
|
3134
|
+
* Uses ctx.llm.stream() with the agent's current model route.
|
|
3135
|
+
*/
|
|
3136
|
+
async summarizeDeletionsWithLlm(agent, records) {
|
|
3137
|
+
const header = agent.session.requestHeader()?.config;
|
|
3138
|
+
if (header === void 0) return "";
|
|
3139
|
+
const provider = header.provider;
|
|
3140
|
+
const model = header.model;
|
|
3141
|
+
if (provider === void 0 || model === void 0) return "";
|
|
3142
|
+
const deletionList = records.map((r, i) => `${i + 1}. [${new Date(r.ts).toLocaleDateString("zh-CN")}] 删除的经验:「${r.gist.slice(0, 80)}」\n 原因:${r.reason || "(未填写)"}`).join("\n\n");
|
|
3143
|
+
const systemPrompt = `你是一个记忆系统的反馈分析器。你的任务是分析用户删除记忆时填写的原因,总结出"什么类型的记忆不值得提取"的规则。
|
|
3144
|
+
|
|
3145
|
+
输出要求:
|
|
3146
|
+
1. 用简洁的中文列出 3-5 条规则
|
|
3147
|
+
2. 每条规则说明:什么类型的记忆应该避免提取,以及为什么
|
|
3148
|
+
3. 规则要具体可操作,不要泛泛而谈
|
|
3149
|
+
4. 如果删除原因都很相似,合并为更精炼的规则`;
|
|
3150
|
+
const messages = [{
|
|
3151
|
+
role: "user",
|
|
3152
|
+
content: [{
|
|
3153
|
+
type: "text",
|
|
3154
|
+
text: `以下是近期被用户删除的记忆及其删除原因:
|
|
3155
|
+
|
|
3156
|
+
${deletionList}
|
|
3157
|
+
|
|
3158
|
+
请总结成提取反馈规则。`
|
|
3159
|
+
}]
|
|
3160
|
+
}];
|
|
3161
|
+
let text = "";
|
|
3162
|
+
const options = {
|
|
3163
|
+
provider,
|
|
3164
|
+
model,
|
|
3165
|
+
messages,
|
|
3166
|
+
system: systemPrompt,
|
|
3167
|
+
maxTokens: 1500,
|
|
3168
|
+
sessionId: agent.session.id
|
|
3169
|
+
};
|
|
3170
|
+
for await (const chunk of this.ctx.llm.stream(options)) if (chunk.type === "text-delta") text += chunk.text;
|
|
3171
|
+
return text.trim();
|
|
3172
|
+
}
|
|
3173
|
+
/**
|
|
3174
|
+
* Remote: manually trigger deletion-feedback summarization (for testing/debugging).
|
|
3175
|
+
*/
|
|
3176
|
+
async runDeletionFeedback(agent) {
|
|
3177
|
+
const check = this.core.deletionFeedbackDue();
|
|
3178
|
+
const records = this.core["store"].getDeletionRecordsSince(check.lastTs, 50);
|
|
3179
|
+
if (records.length === 0) return { ran: false };
|
|
3180
|
+
try {
|
|
3181
|
+
const summary = await this.summarizeDeletionsWithLlm(agent, records);
|
|
3182
|
+
if (summary.length > 0) {
|
|
3183
|
+
this.core.applyDeletionFeedback(summary, "system");
|
|
3184
|
+
return {
|
|
3185
|
+
ran: true,
|
|
3186
|
+
summary
|
|
3187
|
+
};
|
|
3188
|
+
}
|
|
3189
|
+
return { ran: false };
|
|
3190
|
+
} catch (e) {
|
|
3191
|
+
return {
|
|
3192
|
+
ran: false,
|
|
3193
|
+
summary: String(e)
|
|
3194
|
+
};
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
/**
|
|
3198
|
+
* Remote: get the current deletion-feedback experience (for debugging).
|
|
3199
|
+
*/
|
|
3200
|
+
getDeletionFeedback(agent) {
|
|
3201
|
+
return this.core.getDeletionFeedback() ?? null;
|
|
3202
|
+
}
|
|
2905
3203
|
/** Diary timeline for the workbench (007 §2: server-side pagination, newest first). */
|
|
2906
3204
|
listDiary(agent, limit, offset, onlyUnextracted) {
|
|
2907
3205
|
return this.core.listDiary(limit, offset, onlyUnextracted);
|
|
@@ -2987,6 +3285,11 @@ let MemoryService = (() => {
|
|
|
2987
3285
|
this.core.humanDeleteExperience(request, "human");
|
|
2988
3286
|
return { deleted: true };
|
|
2989
3287
|
}
|
|
3288
|
+
/** Human archive (move to archived status; preserves data, removes from recall). */
|
|
3289
|
+
humanArchiveExperience(agent, request) {
|
|
3290
|
+
this.core.humanArchiveExperience(request, "human");
|
|
3291
|
+
return { archived: true };
|
|
3292
|
+
}
|
|
2990
3293
|
/** Human edit of the active revision. */
|
|
2991
3294
|
humanEditExperience(agent, request) {
|
|
2992
3295
|
return this.core.humanEditExperience(request, "human");
|
|
@@ -3070,7 +3373,9 @@ function resolveConfig(config) {
|
|
|
3070
3373
|
"complexityStepGate",
|
|
3071
3374
|
"duplicateOverlapGate",
|
|
3072
3375
|
"recallFloorScore",
|
|
3073
|
-
"shadowPassRate"
|
|
3376
|
+
"shadowPassRate",
|
|
3377
|
+
"deletionFeedbackIntervalHours",
|
|
3378
|
+
"deletionFeedbackMinDeletions"
|
|
3074
3379
|
];
|
|
3075
3380
|
const unknown = Object.keys(config).filter((key) => !known.includes(key));
|
|
3076
3381
|
if (unknown.length > 0) throw new Error(`memory: unknown config key(s) ${unknown.join(", ")}`);
|
|
@@ -3090,7 +3395,9 @@ function resolveConfig(config) {
|
|
|
3090
3395
|
complexityStepGate: config.complexityStepGate ?? DEFAULT_CORE_CONFIG.complexityStepGate,
|
|
3091
3396
|
duplicateOverlapGate: config.duplicateOverlapGate ?? DEFAULT_CORE_CONFIG.duplicateOverlapGate,
|
|
3092
3397
|
recallFloorScore: config.recallFloorScore ?? DEFAULT_CORE_CONFIG.recallFloorScore,
|
|
3093
|
-
shadowPassRate: config.shadowPassRate ?? DEFAULT_CORE_CONFIG.shadowPassRate
|
|
3398
|
+
shadowPassRate: config.shadowPassRate ?? DEFAULT_CORE_CONFIG.shadowPassRate,
|
|
3399
|
+
deletionFeedbackIntervalHours: config.deletionFeedbackIntervalHours ?? DEFAULT_CORE_CONFIG.deletionFeedbackIntervalHours,
|
|
3400
|
+
deletionFeedbackMinDeletions: config.deletionFeedbackMinDeletions ?? DEFAULT_CORE_CONFIG.deletionFeedbackMinDeletions
|
|
3094
3401
|
};
|
|
3095
3402
|
}
|
|
3096
3403
|
/**
|
|
@@ -3115,7 +3422,9 @@ function apply(ctx, config = {}) {
|
|
|
3115
3422
|
complexityStepGate: resolved.complexityStepGate,
|
|
3116
3423
|
duplicateOverlapGate: resolved.duplicateOverlapGate,
|
|
3117
3424
|
recallFloorScore: resolved.recallFloorScore,
|
|
3118
|
-
shadowPassRate: resolved.shadowPassRate
|
|
3425
|
+
shadowPassRate: resolved.shadowPassRate,
|
|
3426
|
+
deletionFeedbackIntervalHours: resolved.deletionFeedbackIntervalHours,
|
|
3427
|
+
deletionFeedbackMinDeletions: resolved.deletionFeedbackMinDeletions
|
|
3119
3428
|
};
|
|
3120
3429
|
mkdirSync(join(resolved.databasePath, ".."), { recursive: true });
|
|
3121
3430
|
const db = new DatabaseSync(resolved.databasePath);
|