@memory-river/core 0.2.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/LICENSE +201 -0
- package/README.md +222 -0
- package/README.zh-TW.md +186 -0
- package/dist/api.d.ts +100 -0
- package/dist/api.js +156 -0
- package/dist/cognition/causal-attribution.d.ts +36 -0
- package/dist/cognition/causal-attribution.js +239 -0
- package/dist/cognition/causal-engine.d.ts +105 -0
- package/dist/cognition/causal-engine.js +150 -0
- package/dist/cognition/conflict-detector.d.ts +39 -0
- package/dist/cognition/conflict-detector.js +193 -0
- package/dist/cognition/global-working-memory.d.ts +53 -0
- package/dist/cognition/global-working-memory.js +211 -0
- package/dist/cognition/hooks-engine.d.ts +99 -0
- package/dist/cognition/hooks-engine.js +672 -0
- package/dist/cognition/ralph-core.d.ts +28 -0
- package/dist/cognition/ralph-core.js +104 -0
- package/dist/distill/concentrator-adapter.d.ts +167 -0
- package/dist/distill/concentrator-adapter.js +1876 -0
- package/dist/engine.d.ts +402 -0
- package/dist/engine.js +2254 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/dist/lifecycle/cleanup-engine.d.ts +80 -0
- package/dist/lifecycle/cleanup-engine.js +162 -0
- package/dist/lifecycle/cleanup-state.d.ts +34 -0
- package/dist/lifecycle/cleanup-state.js +50 -0
- package/dist/lifecycle/night-consolidation.d.ts +102 -0
- package/dist/lifecycle/night-consolidation.js +640 -0
- package/dist/lifecycle/night-recovery.d.ts +40 -0
- package/dist/lifecycle/night-recovery.js +107 -0
- package/dist/paths.d.ts +17 -0
- package/dist/paths.js +16 -0
- package/dist/pipeline/capsule-bridge.d.ts +35 -0
- package/dist/pipeline/capsule-bridge.js +86 -0
- package/dist/pipeline/compact-request.d.ts +30 -0
- package/dist/pipeline/compact-request.js +66 -0
- package/dist/pipeline/inbox-watcher.d.ts +112 -0
- package/dist/pipeline/inbox-watcher.js +1039 -0
- package/dist/ports.d.ts +29 -0
- package/dist/ports.js +1 -0
- package/dist/providers/embedder-v5.d.ts +46 -0
- package/dist/providers/embedder-v5.js +155 -0
- package/dist/providers/ollama-embedding.d.ts +25 -0
- package/dist/providers/ollama-embedding.js +166 -0
- package/dist/retrieval/abstractness-judge.d.ts +14 -0
- package/dist/retrieval/abstractness-judge.js +87 -0
- package/dist/retrieval/coverage-selection.d.ts +3 -0
- package/dist/retrieval/coverage-selection.js +53 -0
- package/dist/retrieval/cross-encoder-gate.d.ts +40 -0
- package/dist/retrieval/cross-encoder-gate.js +239 -0
- package/dist/retrieval/retriever-v4.d.ts +78 -0
- package/dist/retrieval/retriever-v4.js +1200 -0
- package/dist/skills/validate.d.ts +6 -0
- package/dist/skills/validate.js +69 -0
- package/dist/storage.d.ts +19 -0
- package/dist/storage.js +54 -0
- package/dist/store/aux-table-maintenance.d.ts +5 -0
- package/dist/store/aux-table-maintenance.js +64 -0
- package/dist/store/graph-enumerator.d.ts +21 -0
- package/dist/store/graph-enumerator.js +185 -0
- package/dist/store/graph-store.d.ts +107 -0
- package/dist/store/graph-store.js +478 -0
- package/dist/store/status-manager.d.ts +44 -0
- package/dist/store/status-manager.js +235 -0
- package/dist/store/store-v4.d.ts +339 -0
- package/dist/store/store-v4.js +2871 -0
- package/dist/transcript/keyword-search.d.ts +9 -0
- package/dist/transcript/keyword-search.js +67 -0
- package/dist/transcript/rehydrate-keyword.d.ts +6 -0
- package/dist/transcript/rehydrate-keyword.js +29 -0
- package/dist/transcript/rehydrate.d.ts +33 -0
- package/dist/transcript/rehydrate.js +285 -0
- package/dist/transcript/transcript-archive.d.ts +46 -0
- package/dist/transcript/transcript-archive.js +516 -0
- package/dist/types.d.ts +409 -0
- package/dist/types.js +104 -0
- package/dist/util/bounded-map.d.ts +1 -0
- package/dist/util/bounded-map.js +8 -0
- package/dist/util/rate-limiter.d.ts +12 -0
- package/dist/util/rate-limiter.js +54 -0
- package/dist/util/session-identity.d.ts +65 -0
- package/dist/util/session-identity.js +227 -0
- package/dist/util/util-hash.d.ts +1 -0
- package/dist/util/util-hash.js +4 -0
- package/package.json +59 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ralph Loop Core Logic - Memory River 專用核心邏輯 (TypeScript 版)
|
|
3
|
+
* 負責:物理截斷錯誤上下文、提取任務目標、生成偽裝警告。
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 從訊息陣列尾巴往前修剪連續的工具錯誤與無效嘗試
|
|
7
|
+
* 確保保留 System Prompt 與最初的 User 指令
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
export declare function trimTailErrors(msgs: any[]): any[];
|
|
11
|
+
/**
|
|
12
|
+
* 從訊息歷史中提取最原始的任務目標
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractGoalFromMsgs(msgs: any[]): string;
|
|
16
|
+
/**
|
|
17
|
+
* 生成偽裝成 Assistant 的斷路器警告
|
|
18
|
+
* 讓 AI 認為這是自己深刻反省後的決策
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateWarning(goal: string): any;
|
|
21
|
+
export declare const RalphState: {
|
|
22
|
+
consecutiveErrors: number;
|
|
23
|
+
needsReset: boolean;
|
|
24
|
+
onError(): void;
|
|
25
|
+
onSuccess(): void;
|
|
26
|
+
shouldIntercept(): boolean;
|
|
27
|
+
reset(): void;
|
|
28
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ralph Loop Core Logic - Memory River 專用核心邏輯 (TypeScript 版)
|
|
3
|
+
* 負責:物理截斷錯誤上下文、提取任務目標、生成偽裝警告。
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 從訊息陣列尾巴往前修剪連續的工具錯誤與無效嘗試
|
|
7
|
+
* 確保保留 System Prompt 與最初的 User 指令
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
export function trimTailErrors(msgs) {
|
|
11
|
+
// 基礎防禦:如果訊息太少則不處理
|
|
12
|
+
if (!msgs || msgs.length < 3)
|
|
13
|
+
return msgs;
|
|
14
|
+
// 1. 找到保護邊界:第一則 role: 'user' 訊息的位置 (通常是原始任務)
|
|
15
|
+
const firstUserIdx = msgs.findIndex((m) => m.role === 'user');
|
|
16
|
+
// 如果連 user 訊息都找不到,代表 context 異常,直接回傳
|
|
17
|
+
if (firstUserIdx === -1)
|
|
18
|
+
return msgs;
|
|
19
|
+
// 2. 從尾巴往前搜尋,找出需要被切除的「報錯污染區」
|
|
20
|
+
let i = msgs.length - 1;
|
|
21
|
+
let splitIdx = msgs.length; // 預設切點在最後
|
|
22
|
+
while (i > firstUserIdx) {
|
|
23
|
+
const curr = msgs[i];
|
|
24
|
+
// 判定該訊息是否為錯誤訊號:
|
|
25
|
+
// - role 為 'tool' (工具回報錯誤)
|
|
26
|
+
// - role 為 'assistant' 但內容包含 error/failed 關鍵字
|
|
27
|
+
const isError = curr.role === 'tool' ||
|
|
28
|
+
(curr.role === 'assistant' && curr.content && /error|failed|fault/i.test(curr.content));
|
|
29
|
+
// 判定是否為導致報錯的工具呼叫 (assistant 帶有 tool_calls)
|
|
30
|
+
const isToolAction = curr.role === 'assistant' && curr.tool_calls;
|
|
31
|
+
if (isError || isToolAction) {
|
|
32
|
+
// 只要是報錯或報錯鏈中的行為,就將切點往前移
|
|
33
|
+
splitIdx = i;
|
|
34
|
+
i--;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// 撞見正常的對話(例如使用者中間的插話或 AI 正常的解釋),停止裁切
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// 3. 執行物理裁切,只保留 splitIdx 之前的內容
|
|
42
|
+
return msgs.slice(0, splitIdx);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 從訊息歷史中提取最原始的任務目標
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
export function extractGoalFromMsgs(msgs) {
|
|
49
|
+
if (!msgs || msgs.length === 0)
|
|
50
|
+
return '繼續執行當前任務';
|
|
51
|
+
// 穿過系統提示詞,找到第一則使用者輸入
|
|
52
|
+
const firstUser = msgs.find((m) => m.role === 'user');
|
|
53
|
+
if (!firstUser)
|
|
54
|
+
return '處理目前請求';
|
|
55
|
+
// 處理內容可能是字串或陣列的情況
|
|
56
|
+
if (typeof firstUser.content === 'string')
|
|
57
|
+
return firstUser.content;
|
|
58
|
+
if (Array.isArray(firstUser.content)) {
|
|
59
|
+
return firstUser.content.map((c) => c.text || '').join(' ');
|
|
60
|
+
}
|
|
61
|
+
return '執行既定目標';
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 生成偽裝成 Assistant 的斷路器警告
|
|
65
|
+
* 讓 AI 認為這是自己深刻反省後的決策
|
|
66
|
+
*/
|
|
67
|
+
export function generateWarning(goal) {
|
|
68
|
+
// 截短目標文字,避免警告訊息過長
|
|
69
|
+
const truncatedGoal = goal?.length > 100 ? goal.slice(0, 100) + '...' : goal;
|
|
70
|
+
return {
|
|
71
|
+
role: 'assistant', // 關鍵:role 必須是 assistant
|
|
72
|
+
content: `【Ralph Loop 斷路器介入檢測】
|
|
73
|
+
|
|
74
|
+
偵測到目前執行路徑出現連續工具錯誤,為了保護上下文純淨,我已主動清理了無效的報錯紀錄。
|
|
75
|
+
|
|
76
|
+
重新校準核心目標:
|
|
77
|
+
> "${truncatedGoal}"
|
|
78
|
+
|
|
79
|
+
⚠️ 接下來我將:
|
|
80
|
+
1. 檢視先前的失敗原因,嘗試不同的解決路徑。
|
|
81
|
+
2. 優先確保現有資源配置正確,不再重複錯誤的參數。
|
|
82
|
+
3. 若仍無法解決,我將向使用者請求新的技術指引。
|
|
83
|
+
|
|
84
|
+
讓我們重新對焦並繼續前進。`
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export const RalphState = {
|
|
88
|
+
consecutiveErrors: 0,
|
|
89
|
+
needsReset: false,
|
|
90
|
+
onError() {
|
|
91
|
+
this.consecutiveErrors++;
|
|
92
|
+
console.log(`[Ralph Loop] Tool error detected; consecutive errors: ${this.consecutiveErrors}`);
|
|
93
|
+
if (this.consecutiveErrors >= 3)
|
|
94
|
+
this.needsReset = true;
|
|
95
|
+
},
|
|
96
|
+
onSuccess() {
|
|
97
|
+
if (this.consecutiveErrors > 0)
|
|
98
|
+
console.log('[Ralph Loop] Tool execution succeeded; error count reset');
|
|
99
|
+
this.consecutiveErrors = 0;
|
|
100
|
+
this.needsReset = false;
|
|
101
|
+
},
|
|
102
|
+
shouldIntercept() { return this.needsReset; },
|
|
103
|
+
reset() { this.consecutiveErrors = 0; this.needsReset = false; },
|
|
104
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConcentratorAdapter — memory-river 的濃縮膠囊 class wrapper (V8 終極重構版 + 幽靈清掃機)
|
|
3
|
+
*
|
|
4
|
+
* 【四步完美閉環架構】:
|
|
5
|
+
* 1. 60% 動態水位線精準觸發
|
|
6
|
+
* 2. 徹底解除 800 字物理腰斬,保持 MUD 遊戲情報原汁原味
|
|
7
|
+
* 3. 雙軌並行提煉:短期前情提要 (大膠囊, health: 30) + 長期精確記憶 (小紙條)
|
|
8
|
+
* 4. 完美回注與幽靈清理:注入 Context 頂端,並自動拔除斷片的 Tool Result
|
|
9
|
+
*/
|
|
10
|
+
import { ContextMessage } from '../types.js';
|
|
11
|
+
import type { RawTranscriptEntry, TranscriptArchive } from '../transcript/transcript-archive.js';
|
|
12
|
+
import type { SessionIdentity } from '../util/session-identity.js';
|
|
13
|
+
import type { MemoryStore } from '../store/store-v4.js';
|
|
14
|
+
import type { LlmClient } from '../ports.js';
|
|
15
|
+
/**
|
|
16
|
+
* concentrate() 可選 context;目前用來把 sessionIdentity 傳到 writeSessionSummary,
|
|
17
|
+
* 避免從 rawMessages[0].sessionId 這種側通道猜 sessionId。
|
|
18
|
+
*/
|
|
19
|
+
export interface ConcentrateContext {
|
|
20
|
+
sessionIdentity?: SessionIdentity;
|
|
21
|
+
exhaustive?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface SessionSummary {
|
|
24
|
+
sessionId: string;
|
|
25
|
+
concentratedAt: number;
|
|
26
|
+
capsule: string;
|
|
27
|
+
notes: Array<{
|
|
28
|
+
text: string;
|
|
29
|
+
category: string;
|
|
30
|
+
importance: number;
|
|
31
|
+
tags: string[];
|
|
32
|
+
subject?: string;
|
|
33
|
+
predicate?: string;
|
|
34
|
+
value?: string | number | boolean;
|
|
35
|
+
unit?: string;
|
|
36
|
+
when?: {
|
|
37
|
+
start?: string;
|
|
38
|
+
end?: string;
|
|
39
|
+
precision?: 'datetime' | 'date' | 'month' | 'year' | 'range' | 'unknown';
|
|
40
|
+
sourceText?: string;
|
|
41
|
+
source?: 'explicit' | 'relative_anchored' | 'contextual' | 'unknown';
|
|
42
|
+
anchor?: string;
|
|
43
|
+
};
|
|
44
|
+
}>;
|
|
45
|
+
primaryRequest: string;
|
|
46
|
+
pendingTasks: string;
|
|
47
|
+
nextStep: string;
|
|
48
|
+
}
|
|
49
|
+
export declare function passesConcentratorNoteImportanceFilter(item: {
|
|
50
|
+
category?: unknown;
|
|
51
|
+
importance?: unknown;
|
|
52
|
+
}): boolean;
|
|
53
|
+
interface ComparableTranscriptPair {
|
|
54
|
+
user: string;
|
|
55
|
+
assistant: string;
|
|
56
|
+
timestamp: number;
|
|
57
|
+
entryId?: number;
|
|
58
|
+
mergedFromEntryIds?: number[];
|
|
59
|
+
}
|
|
60
|
+
interface BoundaryHeuristicResult {
|
|
61
|
+
triggered: boolean;
|
|
62
|
+
originalCandidateCount: number;
|
|
63
|
+
candidateEntries: ComparableTranscriptPair[];
|
|
64
|
+
droppedCandidate?: ComparableTranscriptPair;
|
|
65
|
+
}
|
|
66
|
+
interface StringDiffDetail {
|
|
67
|
+
field: 'user' | 'assistant';
|
|
68
|
+
index: number;
|
|
69
|
+
summarizeChar: string;
|
|
70
|
+
summarizeCharCode: number | null;
|
|
71
|
+
candidateChar: string;
|
|
72
|
+
candidateCharCode: number | null;
|
|
73
|
+
}
|
|
74
|
+
export interface ProbeTextMismatchDetail {
|
|
75
|
+
mismatchIndex: number;
|
|
76
|
+
summarizePair: ComparableTranscriptPair;
|
|
77
|
+
candidatePair: ComparableTranscriptPair;
|
|
78
|
+
diff: StringDiffDetail;
|
|
79
|
+
}
|
|
80
|
+
export declare function extractTextForConcentrationContent(content: ContextMessage['content']): string;
|
|
81
|
+
export declare function isFrameworkMetadataForConcentration(text: string): boolean;
|
|
82
|
+
export declare function stripFrameworkMetadataForConcentration(text: string): string;
|
|
83
|
+
export declare function buildComparableTranscriptPairs(messages: ContextMessage[]): ComparableTranscriptPair[];
|
|
84
|
+
export declare function buildComparableTranscriptCandidates(entries: RawTranscriptEntry[]): ComparableTranscriptPair[];
|
|
85
|
+
export declare function applyBoundaryHeuristicForProbe(candidateEntries: ComparableTranscriptPair[], summarizePairCount: number): BoundaryHeuristicResult;
|
|
86
|
+
export declare function findProbeTextMismatchDetail(summarizePairs: ComparableTranscriptPair[], candidateEntries: ComparableTranscriptPair[]): ProbeTextMismatchDetail | null;
|
|
87
|
+
export declare function logProbeTextMismatchDetail(detail: ProbeTextMismatchDetail): void;
|
|
88
|
+
export declare function buildDualTrackPrompt(conversationLog: string, capsuleLanguage?: string): string;
|
|
89
|
+
export declare function buildGeneralConversationPrompt(conversationLog: string, capsuleLanguage?: string): string;
|
|
90
|
+
export declare function buildSimplePrompt(conversationLog: string, capsuleLanguage?: string): string;
|
|
91
|
+
export interface ConcentratorConfig {
|
|
92
|
+
apiKey: string;
|
|
93
|
+
model: string;
|
|
94
|
+
inboxPath: string;
|
|
95
|
+
timezone?: string;
|
|
96
|
+
capsuleCategory?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Language for the capsule (前情提要). Default '繁體中文' preserves the
|
|
99
|
+
* Chinese-first benchmark behavior. Pass 'source' to make the distiller
|
|
100
|
+
* write the capsule in the same language as the conversation (otter use).
|
|
101
|
+
*/
|
|
102
|
+
capsuleLanguage?: string;
|
|
103
|
+
concentrationTarget?: number;
|
|
104
|
+
provider?: 'gemini' | 'deepseek';
|
|
105
|
+
maxTokens?: number;
|
|
106
|
+
deepseekApiKey?: string;
|
|
107
|
+
deepseekModel?: string;
|
|
108
|
+
statsStore?: Pick<MemoryStore, 'recordConcentratorStat'>;
|
|
109
|
+
transcriptArchive: TranscriptArchive;
|
|
110
|
+
sessionSummaryDir: string;
|
|
111
|
+
llm?: LlmClient;
|
|
112
|
+
}
|
|
113
|
+
export interface CapsuleOutput {
|
|
114
|
+
messages: ContextMessage[];
|
|
115
|
+
wasConcentrated: boolean;
|
|
116
|
+
summary?: string;
|
|
117
|
+
processedThroughIndex?: number;
|
|
118
|
+
}
|
|
119
|
+
export declare class ConcentratorAdapter implements LlmClient {
|
|
120
|
+
private config;
|
|
121
|
+
private capsuleBridge;
|
|
122
|
+
private statsStore?;
|
|
123
|
+
private transcriptArchive;
|
|
124
|
+
private llm?;
|
|
125
|
+
private readonly MAX_CONTEXT_WINDOW;
|
|
126
|
+
private static readonly WATERLINE_CODE;
|
|
127
|
+
private static readonly WATERLINE_DEFAULT;
|
|
128
|
+
constructor(config: ConcentratorConfig);
|
|
129
|
+
/**
|
|
130
|
+
* 動態水位線偵測器:分析最近 30 則訊息判斷對話模式
|
|
131
|
+
* - code: code block 密度 ≥ 15% 或 toolResult 佔比 ≥ 25%
|
|
132
|
+
* - default: 其餘情況
|
|
133
|
+
*/
|
|
134
|
+
private detectConversationMode;
|
|
135
|
+
buildFallbackCapsule(messages: ContextMessage[]): string;
|
|
136
|
+
concentrate(rawMessages: ContextMessage[], dryRun?: boolean, force?: boolean, context?: ConcentrateContext): Promise<CapsuleOutput>;
|
|
137
|
+
estimateTokens(messages: ContextMessage[]): number;
|
|
138
|
+
estimateTokenBreakdown(messages: ContextMessage[]): {
|
|
139
|
+
realTokens: number;
|
|
140
|
+
toolTokens: number;
|
|
141
|
+
total: number;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Provider 輪替 fallback 核心方法
|
|
145
|
+
* 依序嘗試 gemini → deepseek,任一成功即返回
|
|
146
|
+
* Gemini 若連續 3 次 503,冷卻 90 秒內直接跳過
|
|
147
|
+
*/
|
|
148
|
+
private callWithFallback;
|
|
149
|
+
private callProvider;
|
|
150
|
+
private recordConcentratorAttemptMetric;
|
|
151
|
+
/**
|
|
152
|
+
* 簡單文字生成介面(供 core 模組使用)
|
|
153
|
+
* 支援 provider fallback:gemini → deepseek
|
|
154
|
+
*/
|
|
155
|
+
generate(prompt: string, opts?: {
|
|
156
|
+
purpose?: string;
|
|
157
|
+
maxTokens?: number;
|
|
158
|
+
}): Promise<string>;
|
|
159
|
+
generate(messages: any[]): Promise<string>;
|
|
160
|
+
assemble(params: {
|
|
161
|
+
messages: ContextMessage[];
|
|
162
|
+
session?: any;
|
|
163
|
+
}): Promise<ContextMessage[]>;
|
|
164
|
+
private getSessionSummaryPath;
|
|
165
|
+
private writeSessionSummary;
|
|
166
|
+
}
|
|
167
|
+
export {};
|