@alanzhao/dsh-memory-lite 0.1.1
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 +21 -0
- package/README.md +112 -0
- package/cordis.patch.yml +9 -0
- package/lib/catalog.d.ts +35 -0
- package/lib/catalog.js +145 -0
- package/lib/catalog.js.map +1 -0
- package/lib/client.js +631 -0
- package/lib/config.d.ts +133 -0
- package/lib/config.js +173 -0
- package/lib/config.js.map +1 -0
- package/lib/extract/checkpoint.d.ts +60 -0
- package/lib/extract/checkpoint.js +42 -0
- package/lib/extract/checkpoint.js.map +1 -0
- package/lib/extract/decision.d.ts +36 -0
- package/lib/extract/decision.js +118 -0
- package/lib/extract/decision.js.map +1 -0
- package/lib/extract/digest.d.ts +12 -0
- package/lib/extract/digest.js +25 -0
- package/lib/extract/digest.js.map +1 -0
- package/lib/extract/index.d.ts +52 -0
- package/lib/extract/index.js +489 -0
- package/lib/extract/index.js.map +1 -0
- package/lib/extract/prompt.d.ts +20 -0
- package/lib/extract/prompt.js +63 -0
- package/lib/extract/prompt.js.map +1 -0
- package/lib/extract/triggers.d.ts +15 -0
- package/lib/extract/triggers.js +26 -0
- package/lib/extract/triggers.js.map +1 -0
- package/lib/extract/window.d.ts +48 -0
- package/lib/extract/window.js +110 -0
- package/lib/extract/window.js.map +1 -0
- package/lib/index.d.ts +29 -0
- package/lib/index.js +92 -0
- package/lib/index.js.map +1 -0
- package/lib/inject.d.ts +45 -0
- package/lib/inject.js +102 -0
- package/lib/inject.js.map +1 -0
- package/lib/memory-store.d.ts +147 -0
- package/lib/memory-store.js +494 -0
- package/lib/memory-store.js.map +1 -0
- package/lib/path.d.ts +24 -0
- package/lib/path.js +54 -0
- package/lib/path.js.map +1 -0
- package/lib/peer.d.ts +16 -0
- package/lib/peer.js +38 -0
- package/lib/peer.js.map +1 -0
- package/lib/status.d.ts +44 -0
- package/lib/status.js +42 -0
- package/lib/status.js.map +1 -0
- package/lib/tool-utils.d.ts +25 -0
- package/lib/tool-utils.js +16 -0
- package/lib/tool-utils.js.map +1 -0
- package/lib/tools/forget-memory.d.ts +9 -0
- package/lib/tools/forget-memory.js +39 -0
- package/lib/tools/forget-memory.js.map +1 -0
- package/lib/tools/read-memory.d.ts +8 -0
- package/lib/tools/read-memory.js +41 -0
- package/lib/tools/read-memory.js.map +1 -0
- package/lib/tools/remember.d.ts +9 -0
- package/lib/tools/remember.js +65 -0
- package/lib/tools/remember.js.map +1 -0
- package/lib/tools/search-memory.d.ts +8 -0
- package/lib/tools/search-memory.js +49 -0
- package/lib/tools/search-memory.js.map +1 -0
- package/lib/tools/update-memory.d.ts +9 -0
- package/lib/tools/update-memory.js +46 -0
- package/lib/tools/update-memory.js.map +1 -0
- package/lib/types.d.ts +35 -0
- package/lib/types.js +7 -0
- package/lib/types.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implicit extraction (Phase 2, channel B): trigger wiring and the background
|
|
3
|
+
* extraction job. Event handlers only count and schedule; the LLM work runs
|
|
4
|
+
* inside a ctx.jobs task, never awaited inside serial event callbacks (the
|
|
5
|
+
* agent/turn-stopping contract, verified in dsh-agent-loop source).
|
|
6
|
+
*
|
|
7
|
+
* Model resolution: config.extraction.llm wins when set; otherwise the
|
|
8
|
+
* session's current model (session.requestHeader().config) is reused.
|
|
9
|
+
* @module dsh-memory-lite/src/extract
|
|
10
|
+
*/
|
|
11
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
12
|
+
import type { MemoryStore } from '../memory-store.js';
|
|
13
|
+
import type { MemoryDeps } from '../tool-utils.js';
|
|
14
|
+
import type { StatusTracker } from '../status.js';
|
|
15
|
+
import { type ExtractionDecision } from './decision.js';
|
|
16
|
+
import { type CheckpointFile } from './checkpoint.js';
|
|
17
|
+
interface ExtractionState {
|
|
18
|
+
pending: number;
|
|
19
|
+
lastExtractAt: number | null;
|
|
20
|
+
inFlight: boolean;
|
|
21
|
+
checkpoint: CheckpointFile;
|
|
22
|
+
idleDispose: (() => void) | null;
|
|
23
|
+
cancel: (() => void) | null;
|
|
24
|
+
}
|
|
25
|
+
/** Minimal structural view of a session the extractor reads; real Sessions satisfy it. */
|
|
26
|
+
export interface ExtractionSessionLike {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly header: {
|
|
29
|
+
readonly cwd?: string;
|
|
30
|
+
readonly origin?: 'subagent';
|
|
31
|
+
};
|
|
32
|
+
readonly events: readonly {
|
|
33
|
+
readonly type: string;
|
|
34
|
+
readonly seq: number;
|
|
35
|
+
readonly data: unknown;
|
|
36
|
+
}[];
|
|
37
|
+
requestHeader(): {
|
|
38
|
+
readonly config?: {
|
|
39
|
+
readonly provider?: string;
|
|
40
|
+
readonly model?: string;
|
|
41
|
+
};
|
|
42
|
+
} | undefined;
|
|
43
|
+
}
|
|
44
|
+
/** Register the extraction channel for the lifetime of `ctx`. */
|
|
45
|
+
export declare function applyExtraction(ctx: Context, deps: MemoryDeps, tracker: StatusTracker): void;
|
|
46
|
+
/** One extraction run: window -> grep -> LLM -> write -> checkpoint. */
|
|
47
|
+
export declare function extractOnce(session: ExtractionSessionLike, state: ExtractionState, ctx: Context, deps: MemoryDeps, signal: AbortSignal, tracker: StatusTracker): Promise<void>;
|
|
48
|
+
/** Apply one decision through the store (all writes go through the queue). */
|
|
49
|
+
export declare function applyDecision(store: MemoryStore, peer: string, decision: ExtractionDecision): Promise<string | undefined>;
|
|
50
|
+
/** Light keyword heuristic: frequent Latin words and CJK characters. */
|
|
51
|
+
export declare function extractKeywords(text: string, max: number): string[];
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implicit extraction (Phase 2, channel B): trigger wiring and the background
|
|
3
|
+
* extraction job. Event handlers only count and schedule; the LLM work runs
|
|
4
|
+
* inside a ctx.jobs task, never awaited inside serial event callbacks (the
|
|
5
|
+
* agent/turn-stopping contract, verified in dsh-agent-loop source).
|
|
6
|
+
*
|
|
7
|
+
* Model resolution: config.extraction.llm wins when set; otherwise the
|
|
8
|
+
* session's current model (session.requestHeader().config) is reused.
|
|
9
|
+
* @module dsh-memory-lite/src/extract
|
|
10
|
+
*/
|
|
11
|
+
import { BlockAssembler, createUserMessage, ReasoningEffortId } from '@deepseek-ai/dsh-llm';
|
|
12
|
+
import { peerForHeader } from '../peer.js';
|
|
13
|
+
import { MEMORY_CATEGORIES } from '../types.js';
|
|
14
|
+
import { slugify, summaryOf } from '../memory-store.js';
|
|
15
|
+
import { isSurfaceType, selectWindow, renderEventText } from './window.js';
|
|
16
|
+
import { shouldExtractIdle, shouldExtractTurn, shouldExtractWindow } from './triggers.js';
|
|
17
|
+
import { parseDecision } from './decision.js';
|
|
18
|
+
import { digestApproxTokens, rollDigest } from './digest.js';
|
|
19
|
+
import { emptyCheckpoint, parseCheckpoint, withRun, renderCheckpoint } from './checkpoint.js';
|
|
20
|
+
import { buildExtractionUser, extractionSystem } from './prompt.js';
|
|
21
|
+
const DIGEST_MAX_TOKENS = 100;
|
|
22
|
+
const MAX_KEYWORDS = 8;
|
|
23
|
+
const MAX_GREP_HITS = 8;
|
|
24
|
+
// Bumped 1024 -> 4096 (2026-08-28): with extraction.llm.reasoningEffort = high
|
|
25
|
+
// the model's reasoning pass consumed the whole 1024-token budget and the
|
|
26
|
+
// answer text came back empty (every failed answer logged textLen=0), forcing
|
|
27
|
+
// the repair path on ~85% of runs. 4096 leaves room for both reasoning and the
|
|
28
|
+
// JSON decision body.
|
|
29
|
+
const EXTRACTION_MAX_TOKENS = 4096;
|
|
30
|
+
/** Register the extraction channel for the lifetime of `ctx`. */
|
|
31
|
+
export function applyExtraction(ctx, deps, tracker) {
|
|
32
|
+
const ext = () => deps.config().extraction;
|
|
33
|
+
if (ext().mode === 'off')
|
|
34
|
+
return;
|
|
35
|
+
const states = new Map();
|
|
36
|
+
function stateOf(session) {
|
|
37
|
+
let state = states.get(session.id);
|
|
38
|
+
if (state === undefined) {
|
|
39
|
+
state = {
|
|
40
|
+
pending: 0,
|
|
41
|
+
lastExtractAt: null,
|
|
42
|
+
inFlight: false,
|
|
43
|
+
checkpoint: emptyCheckpoint(),
|
|
44
|
+
idleDispose: null,
|
|
45
|
+
cancel: null,
|
|
46
|
+
};
|
|
47
|
+
states.set(session.id, state);
|
|
48
|
+
}
|
|
49
|
+
return state;
|
|
50
|
+
}
|
|
51
|
+
function resetIdle(session, state) {
|
|
52
|
+
if (ext().mode !== 'incremental')
|
|
53
|
+
return;
|
|
54
|
+
state.idleDispose?.();
|
|
55
|
+
state.idleDispose = null;
|
|
56
|
+
state.idleDispose = ctx.timeout(() => {
|
|
57
|
+
if (shouldExtractIdle(state.pending))
|
|
58
|
+
maybeSchedule(session, state);
|
|
59
|
+
}, ext().idleTimeoutMin * 60_000);
|
|
60
|
+
}
|
|
61
|
+
function maybeSchedule(session, state) {
|
|
62
|
+
if (ext().mode !== 'incremental')
|
|
63
|
+
return;
|
|
64
|
+
if (state.inFlight)
|
|
65
|
+
return;
|
|
66
|
+
state.inFlight = true;
|
|
67
|
+
runExtraction(session, state, ctx, deps, tracker);
|
|
68
|
+
}
|
|
69
|
+
ctx.on('session/event', (session, event) => {
|
|
70
|
+
if (session.header.origin === 'subagent')
|
|
71
|
+
return;
|
|
72
|
+
if (!isSurfaceType(event.type))
|
|
73
|
+
return;
|
|
74
|
+
const state = stateOf(session);
|
|
75
|
+
state.pending += 1;
|
|
76
|
+
resetIdle(session, state);
|
|
77
|
+
if (shouldExtractWindow(state.pending, ext().windowTurns))
|
|
78
|
+
maybeSchedule(session, state);
|
|
79
|
+
});
|
|
80
|
+
ctx.on('agent/turn-stopping', ({ agent }) => {
|
|
81
|
+
// Disabled 2026-08-25 (方案 C): turn-boundary extraction turned off to cut
|
|
82
|
+
// LLM calls; the 30-min idle timer remains the timeliness backstop. Re-enable
|
|
83
|
+
// by setting extraction.turnStoppingTrigger back to true (IMPLEMENTATION.md §13.2 偏差 12).
|
|
84
|
+
if (!ext().turnStoppingTrigger)
|
|
85
|
+
return;
|
|
86
|
+
const session = agent.session;
|
|
87
|
+
if (session.header.origin === 'subagent')
|
|
88
|
+
return;
|
|
89
|
+
const state = stateOf(session);
|
|
90
|
+
if (shouldExtractTurn(state.pending, Date.now(), state.lastExtractAt, ext().minTurnExtract, ext().turnDebounceMs)) {
|
|
91
|
+
maybeSchedule(session, state);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
ctx.on('session/flush', (session) => {
|
|
95
|
+
if (!ext().flushTrigger)
|
|
96
|
+
return;
|
|
97
|
+
if (session.header.origin === 'subagent')
|
|
98
|
+
return;
|
|
99
|
+
const state = stateOf(session);
|
|
100
|
+
if (shouldExtractTurn(state.pending, Date.now(), state.lastExtractAt, ext().minTurnExtract, ext().turnDebounceMs)) {
|
|
101
|
+
maybeSchedule(session, state);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
ctx.on('session/disposed', (session) => {
|
|
105
|
+
const state = states.get(session.id);
|
|
106
|
+
if (state !== undefined) {
|
|
107
|
+
state.idleDispose?.();
|
|
108
|
+
state.cancel?.();
|
|
109
|
+
states.delete(session.id);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Fire-and-forget extraction producer; never awaited in serial event callbacks. */
|
|
114
|
+
function runExtraction(session, state, ctx, deps, tracker) {
|
|
115
|
+
const controller = new AbortController();
|
|
116
|
+
const cancel = () => {
|
|
117
|
+
controller.abort('memory extraction cancelled');
|
|
118
|
+
};
|
|
119
|
+
state.cancel = cancel;
|
|
120
|
+
void (async () => {
|
|
121
|
+
try {
|
|
122
|
+
await extractOnce(session, state, ctx, deps, controller.signal, tracker);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
if (!controller.signal.aborted) {
|
|
126
|
+
tracker.reportError(String(error));
|
|
127
|
+
ctx.logger.warn('dsh-memory-lite: extraction failed: ' + String(error));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
state.inFlight = false;
|
|
132
|
+
state.lastExtractAt = Date.now();
|
|
133
|
+
state.cancel = null;
|
|
134
|
+
}
|
|
135
|
+
})();
|
|
136
|
+
}
|
|
137
|
+
/** One extraction run: window -> grep -> LLM -> write -> checkpoint. */
|
|
138
|
+
export async function extractOnce(session, state, ctx, deps, signal, tracker) {
|
|
139
|
+
const config = deps.config();
|
|
140
|
+
const ext = config.extraction;
|
|
141
|
+
const store = deps.store;
|
|
142
|
+
const peer = peerForHeader(session.header, config);
|
|
143
|
+
if (state.checkpoint.checkpoint.seq === 0 && state.checkpoint.audit.length === 0) {
|
|
144
|
+
const raw = await store.readSessionCheckpoint(peer, session.id);
|
|
145
|
+
if (raw !== undefined)
|
|
146
|
+
state.checkpoint = parseCheckpoint(raw);
|
|
147
|
+
}
|
|
148
|
+
const fromSeq = state.checkpoint.checkpoint.seq;
|
|
149
|
+
const events = session.events;
|
|
150
|
+
const windowEvents = selectWindow(events, fromSeq, ext.maxMessages);
|
|
151
|
+
if (windowEvents.length === 0)
|
|
152
|
+
return;
|
|
153
|
+
const windowStart = windowEvents[0].seq;
|
|
154
|
+
const windowEnd = windowEvents[windowEvents.length - 1].seq;
|
|
155
|
+
const windowText = windowEvents.map(event => renderEventText(event, ext.toolResultMaxBytes)).join('\n');
|
|
156
|
+
let hits = [];
|
|
157
|
+
if (ext.dedup) {
|
|
158
|
+
const keywords = extractKeywords(windowText, MAX_KEYWORDS);
|
|
159
|
+
hits = await grepHits(store, peer, keywords, MAX_GREP_HITS);
|
|
160
|
+
}
|
|
161
|
+
// Full-memory index for de-fragmentation: lets the model merge into an
|
|
162
|
+
// existing file instead of creating a new one for the same topic. Already
|
|
163
|
+
// sorted newest-first; read failures fall back to an empty index.
|
|
164
|
+
const indexEntries = await store.readIndex(peer).catch(() => []);
|
|
165
|
+
const startedAt = Date.now();
|
|
166
|
+
const metrics = { llmCalls: 0, inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };
|
|
167
|
+
const route = resolveRoute(ext.llm.route, ext.llm.reasoningEffort, deps.defaultModel, session);
|
|
168
|
+
const rc = {
|
|
169
|
+
ctx, state, store, peer, sessionId: session.id, windowStart, windowEnd, hits, route, metrics, startedAt,
|
|
170
|
+
auditLog: ext.auditLog, tracker,
|
|
171
|
+
};
|
|
172
|
+
if (route === undefined) {
|
|
173
|
+
await recordRun(rc, 'no-route', undefined, undefined, undefined);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const system = extractionSystem();
|
|
177
|
+
const user = buildExtractionUser(state.checkpoint.digest === '' ? undefined : state.checkpoint.digest, windowText, indexEntries, hits);
|
|
178
|
+
let text = '';
|
|
179
|
+
try {
|
|
180
|
+
metrics.llmCalls += 1;
|
|
181
|
+
const call = await callExtraction(ctx, route, system, user, signal);
|
|
182
|
+
text = call.text;
|
|
183
|
+
addUsage(metrics, call);
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
metrics.inputTokens += digestApproxTokens(system) + digestApproxTokens(user);
|
|
187
|
+
await recordRun(rc, 'llm-error: ' + String(error).slice(0, 200), undefined, undefined, undefined);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
let decision;
|
|
191
|
+
let recovered = false;
|
|
192
|
+
try {
|
|
193
|
+
decision = parseDecision(text);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
const note = 'parse-error: ' + String(error).slice(0, 200);
|
|
197
|
+
// Diagnostic: persist the raw failed answer so a parse-error spike can be
|
|
198
|
+
// investigated (the model's output shape decides whether the repair is
|
|
199
|
+
// helping). Best-effort; never blocks the run.
|
|
200
|
+
void store.appendFailedAnswer(peer, {
|
|
201
|
+
at: new Date().toISOString(),
|
|
202
|
+
session: session.id,
|
|
203
|
+
win: [windowStart, windowEnd],
|
|
204
|
+
route: route === undefined ? null : route,
|
|
205
|
+
error: String(error).slice(0, 300),
|
|
206
|
+
text,
|
|
207
|
+
});
|
|
208
|
+
// Bounded one-shot repair (Phase 2.1): re-ask the model to emit valid JSON
|
|
209
|
+
// from the failed answer only — cheap, no window resend. A second failure
|
|
210
|
+
// is accepted and the checkpoint still advances (no infinite retry loop).
|
|
211
|
+
if (ext.parseRetry) {
|
|
212
|
+
metrics.llmCalls += 1;
|
|
213
|
+
const repairSystem = extractionSystem();
|
|
214
|
+
const repairUser = buildRepairUser(text);
|
|
215
|
+
const repaired = await callExtraction(ctx, route, repairSystem, repairUser, signal).catch(() => undefined);
|
|
216
|
+
if (repaired !== undefined) {
|
|
217
|
+
addUsage(metrics, repaired);
|
|
218
|
+
try {
|
|
219
|
+
decision = parseDecision(repaired.text);
|
|
220
|
+
recovered = true;
|
|
221
|
+
text = repaired.text;
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
await recordRun(rc, note, undefined, undefined, undefined);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
metrics.inputTokens += digestApproxTokens(repairSystem) + digestApproxTokens(repairUser);
|
|
230
|
+
await recordRun(rc, note, undefined, undefined, undefined);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
await recordRun(rc, note, undefined, undefined, undefined);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
let path;
|
|
240
|
+
try {
|
|
241
|
+
path = await applyDecision(store, peer, decision);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
await recordRun(rc, 'apply-error: ' + String(error).slice(0, 200), decision.kind, undefined, undefined);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const digest = rollDigest(state.checkpoint.digest, windowText, DIGEST_MAX_TOKENS);
|
|
248
|
+
await recordRun(rc, recovered ? 'parse-error-recovered' : undefined, decision.kind, path, digest);
|
|
249
|
+
}
|
|
250
|
+
/** The repair turn: convert a failed non-JSON answer into a valid JSON decision. */
|
|
251
|
+
function buildRepairUser(failedAnswer) {
|
|
252
|
+
return [
|
|
253
|
+
'An earlier extraction answer was not valid JSON. Convert it into exactly ONE JSON decision object following the schema and STRICT OUTPUT RULES in the system instructions.',
|
|
254
|
+
'Reply with only the JSON object, nothing else.',
|
|
255
|
+
'',
|
|
256
|
+
'Failed answer:',
|
|
257
|
+
failedAnswer.slice(0, 2000),
|
|
258
|
+
].join('\n');
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Persist the run outcome: advance the checkpoint (bounds retry loops), append
|
|
262
|
+
* the run metrics to the session audit and the peer summary log, and log a
|
|
263
|
+
* one-line summary. When auditLog is off the audit entry and summary log are
|
|
264
|
+
* skipped but the checkpoint seq still advances (functional requirement).
|
|
265
|
+
*/
|
|
266
|
+
async function recordRun(rc, note, decision, path, digest) {
|
|
267
|
+
const { ctx, state, store, peer, sessionId, windowStart, windowEnd, hits, route, metrics, startedAt, auditLog, tracker } = rc;
|
|
268
|
+
const durationMs = Date.now() - startedAt;
|
|
269
|
+
const outcome = note !== undefined ? note.split(':')[0].trim() : (decision ?? 'error');
|
|
270
|
+
const at = new Date().toISOString();
|
|
271
|
+
const entry = {
|
|
272
|
+
at,
|
|
273
|
+
windowSeq: [windowStart, windowEnd],
|
|
274
|
+
grepHits: hits.map(hit => hit.path + ': ' + hit.line),
|
|
275
|
+
...(route === undefined ? {} : { route }),
|
|
276
|
+
maxTokens: EXTRACTION_MAX_TOKENS,
|
|
277
|
+
decision: decision ?? (note ?? 'error'),
|
|
278
|
+
...(path === undefined ? {} : { path }),
|
|
279
|
+
...(note === undefined ? {} : { note }),
|
|
280
|
+
llmCalls: metrics.llmCalls,
|
|
281
|
+
inputTokens: metrics.inputTokens,
|
|
282
|
+
outputTokens: metrics.outputTokens,
|
|
283
|
+
...(metrics.cacheReadTokens > 0 ? { cacheReadTokens: metrics.cacheReadTokens } : {}),
|
|
284
|
+
...(metrics.cacheWriteTokens > 0 ? { cacheWriteTokens: metrics.cacheWriteTokens } : {}),
|
|
285
|
+
durationMs,
|
|
286
|
+
};
|
|
287
|
+
state.checkpoint = auditLog
|
|
288
|
+
? withRun(state.checkpoint, windowEnd, entry)
|
|
289
|
+
: { ...state.checkpoint, checkpoint: { seq: windowEnd } };
|
|
290
|
+
if (digest !== undefined) {
|
|
291
|
+
state.checkpoint = { ...state.checkpoint, digest };
|
|
292
|
+
}
|
|
293
|
+
state.pending = 0;
|
|
294
|
+
await store.writeSessionCheckpoint(peer, sessionId, renderCheckpoint(state.checkpoint));
|
|
295
|
+
if (auditLog) {
|
|
296
|
+
const logLine = {
|
|
297
|
+
at,
|
|
298
|
+
session: sessionId,
|
|
299
|
+
win: [windowStart, windowEnd],
|
|
300
|
+
llmCalls: metrics.llmCalls,
|
|
301
|
+
inputTokens: metrics.inputTokens,
|
|
302
|
+
outputTokens: metrics.outputTokens,
|
|
303
|
+
cacheReadTokens: metrics.cacheReadTokens,
|
|
304
|
+
cacheWriteTokens: metrics.cacheWriteTokens,
|
|
305
|
+
durationMs,
|
|
306
|
+
outcome,
|
|
307
|
+
decision: decision ?? null,
|
|
308
|
+
path: path ?? null,
|
|
309
|
+
note: note ?? null,
|
|
310
|
+
route: route ?? null,
|
|
311
|
+
};
|
|
312
|
+
await store.appendExtractionLog(peer, JSON.stringify(logLine));
|
|
313
|
+
ctx.logger.info('dsh-memory-lite: extraction ' + outcome + ' calls=' + metrics.llmCalls +
|
|
314
|
+
' in=' + metrics.inputTokens + ' out=' + metrics.outputTokens + ' ms=' + durationMs +
|
|
315
|
+
' win[' + windowStart + '..' + windowEnd + ']');
|
|
316
|
+
}
|
|
317
|
+
tracker.reportRun(outcome, note ?? null, decision ?? null);
|
|
318
|
+
}
|
|
319
|
+
/** Apply one decision through the store (all writes go through the queue). */
|
|
320
|
+
export async function applyDecision(store, peer, decision) {
|
|
321
|
+
switch (decision.kind) {
|
|
322
|
+
case 'create': {
|
|
323
|
+
if (!MEMORY_CATEGORIES.includes(decision.category)) {
|
|
324
|
+
throw new Error('unknown category: ' + decision.category);
|
|
325
|
+
}
|
|
326
|
+
// Model sometimes writes a title ending in ".md"; strip it so the
|
|
327
|
+
// slug does not produce a double extension (e.g. foo.md.md).
|
|
328
|
+
const title = decision.title.replace(/\.md$/i, '');
|
|
329
|
+
const path = decision.category + '/' + slugify(title) + '.md';
|
|
330
|
+
// Conservative implicit-channel rule: never overwrite an existing memory
|
|
331
|
+
// (it may hold explicit user content); merge into it instead.
|
|
332
|
+
if (await store.fileExists(peer, path)) {
|
|
333
|
+
await store.appendCurrent(peer, path, decision.content);
|
|
334
|
+
await store.refreshIndexEntry(peer, path, summaryOf(decision.content));
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
await store.writeNewMemory(peer, path, decision.title, decision.content);
|
|
338
|
+
await store.refreshIndexEntry(peer, path, summaryOf(decision.content));
|
|
339
|
+
}
|
|
340
|
+
return path;
|
|
341
|
+
}
|
|
342
|
+
case 'merge':
|
|
343
|
+
await store.appendCurrent(peer, decision.path, decision.content);
|
|
344
|
+
await store.refreshIndexEntry(peer, decision.path, summaryOf(decision.content));
|
|
345
|
+
return decision.path;
|
|
346
|
+
case 'update':
|
|
347
|
+
await store.updateCurrent(peer, decision.path, decision.content);
|
|
348
|
+
await store.refreshIndexEntry(peer, decision.path, summaryOf(decision.content));
|
|
349
|
+
return decision.path;
|
|
350
|
+
default:
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Model route resolution order (§17):
|
|
356
|
+
* 1. extraction.llm.route (explicit "provider/model") — fixed, ignores the global default.
|
|
357
|
+
* 2. The global default model selection (agent-default-model), read live each run.
|
|
358
|
+
* 3. Fallback: the session's current request-header model (legacy behavior).
|
|
359
|
+
* Reasoning effort travels with whichever route won: explicit config first,
|
|
360
|
+
* else the selection's own effort.
|
|
361
|
+
*/
|
|
362
|
+
function resolveRoute(configuredRoute, configuredEffort, defaultModel, session) {
|
|
363
|
+
if (configuredRoute !== undefined && configuredRoute !== '') {
|
|
364
|
+
const slash = configuredRoute.indexOf('/');
|
|
365
|
+
if (slash > 0 && slash < configuredRoute.length - 1) {
|
|
366
|
+
return {
|
|
367
|
+
provider: configuredRoute.slice(0, slash),
|
|
368
|
+
model: configuredRoute.slice(slash + 1),
|
|
369
|
+
...(configuredEffort !== undefined && configuredEffort !== '' ? { reasoningEffort: ReasoningEffortId(configuredEffort) } : {}),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (defaultModel !== undefined) {
|
|
374
|
+
const selection = defaultModel();
|
|
375
|
+
if (selection !== undefined && selection.provider !== '' && selection.model !== '') {
|
|
376
|
+
return {
|
|
377
|
+
provider: selection.provider,
|
|
378
|
+
model: selection.model,
|
|
379
|
+
...(configuredEffort !== undefined && configuredEffort !== '' ? { reasoningEffort: ReasoningEffortId(configuredEffort) } : {}),
|
|
380
|
+
...(configuredEffort === undefined || configuredEffort === ''
|
|
381
|
+
? selection.reasoningEffort !== undefined && selection.reasoningEffort !== ''
|
|
382
|
+
? { reasoningEffort: ReasoningEffortId(selection.reasoningEffort) }
|
|
383
|
+
: {}
|
|
384
|
+
: {}),
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
const headerConfig = session.requestHeader()?.config;
|
|
389
|
+
if (headerConfig !== undefined && headerConfig.provider !== undefined && headerConfig.model !== undefined) {
|
|
390
|
+
return { provider: headerConfig.provider, model: headerConfig.model };
|
|
391
|
+
}
|
|
392
|
+
return undefined;
|
|
393
|
+
}
|
|
394
|
+
/** Assemble the streamed text and real token usage; a non-success finish throws. */
|
|
395
|
+
async function collectStream(stream) {
|
|
396
|
+
const assembler = new BlockAssembler();
|
|
397
|
+
for await (const chunk of stream)
|
|
398
|
+
assembler.push(chunk);
|
|
399
|
+
const finish = assembler.finish;
|
|
400
|
+
if (finish.kind === 'aborted' || finish.kind === 'error') {
|
|
401
|
+
throw new Error('llm stream finished with ' + finish.kind);
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
text: assembler
|
|
405
|
+
.blocks()
|
|
406
|
+
.filter(block => block.type === 'text')
|
|
407
|
+
.map(block => block.text ?? '')
|
|
408
|
+
.join(''),
|
|
409
|
+
usage: assembler.usage,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* One extraction LLM call. Token counts prefer the provider's real usage from
|
|
414
|
+
* the stream; when absent they fall back to the bytes/3 estimate so a run
|
|
415
|
+
* still records a defensible figure.
|
|
416
|
+
*/
|
|
417
|
+
async function callExtraction(ctx, route, system, user, signal) {
|
|
418
|
+
const options = {
|
|
419
|
+
provider: route.provider,
|
|
420
|
+
model: route.model,
|
|
421
|
+
...(route.reasoningEffort !== undefined ? { reasoningEffort: route.reasoningEffort } : {}),
|
|
422
|
+
messages: [createUserMessage({
|
|
423
|
+
content: [{ type: 'text', text: user }],
|
|
424
|
+
source: { kind: 'plugin', plugin: 'dsh-memory-lite' },
|
|
425
|
+
})],
|
|
426
|
+
system,
|
|
427
|
+
maxTokens: EXTRACTION_MAX_TOKENS,
|
|
428
|
+
signal,
|
|
429
|
+
};
|
|
430
|
+
const { text, usage } = await collectStream(ctx.llm.stream(options));
|
|
431
|
+
return {
|
|
432
|
+
text,
|
|
433
|
+
inputTokens: usage?.inputTokens ?? digestApproxTokens(system) + digestApproxTokens(user),
|
|
434
|
+
outputTokens: usage?.outputTokens ?? digestApproxTokens(text),
|
|
435
|
+
cacheReadTokens: usage?.cacheReadTokens ?? 0,
|
|
436
|
+
cacheWriteTokens: usage?.cacheWriteTokens ?? 0,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
/** Fold one call's token figures into the run-wide accumulator. */
|
|
440
|
+
function addUsage(metrics, call) {
|
|
441
|
+
metrics.inputTokens += call.inputTokens;
|
|
442
|
+
metrics.outputTokens += call.outputTokens;
|
|
443
|
+
metrics.cacheReadTokens += call.cacheReadTokens;
|
|
444
|
+
metrics.cacheWriteTokens += call.cacheWriteTokens;
|
|
445
|
+
}
|
|
446
|
+
/** Light keyword heuristic: frequent Latin words and CJK characters. */
|
|
447
|
+
export function extractKeywords(text, max) {
|
|
448
|
+
const counts = new Map();
|
|
449
|
+
const bump = (token) => {
|
|
450
|
+
if (STOP_WORDS.has(token) || token.length < 2)
|
|
451
|
+
return;
|
|
452
|
+
counts.set(token, (counts.get(token) ?? 0) + 1);
|
|
453
|
+
};
|
|
454
|
+
for (const word of text.toLowerCase().match(/[a-z0-9]{2,}/g) ?? [])
|
|
455
|
+
bump(word);
|
|
456
|
+
for (const ch of text) {
|
|
457
|
+
if (/[\u4e00-\u9fff]/.test(ch))
|
|
458
|
+
bump(ch);
|
|
459
|
+
}
|
|
460
|
+
return [...counts.entries()]
|
|
461
|
+
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
|
462
|
+
.slice(0, max)
|
|
463
|
+
.map(entry => entry[0]);
|
|
464
|
+
}
|
|
465
|
+
/** Deduplicated grep hits across keywords, capped. */
|
|
466
|
+
async function grepHits(store, peer, keywords, max) {
|
|
467
|
+
const seen = new Set();
|
|
468
|
+
const hits = [];
|
|
469
|
+
for (const keyword of keywords) {
|
|
470
|
+
if (hits.length >= max)
|
|
471
|
+
break;
|
|
472
|
+
for (const match of await store.search(peer, keyword)) {
|
|
473
|
+
const key = match.path + '\u0000' + match.line;
|
|
474
|
+
if (seen.has(key))
|
|
475
|
+
continue;
|
|
476
|
+
seen.add(key);
|
|
477
|
+
hits.push(match);
|
|
478
|
+
if (hits.length >= max)
|
|
479
|
+
break;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return hits;
|
|
483
|
+
}
|
|
484
|
+
const STOP_WORDS = new Set([
|
|
485
|
+
'the', 'and', 'for', 'with', 'that', 'this', 'from', 'have', 'will', 'were',
|
|
486
|
+
'的', '了', '是', '我', '你', '他', '她', '它', '在', '有', '和', '就', '不', '人', '都',
|
|
487
|
+
'一个', '我们', '你们', '他们', '这个', '那个', '什么', '怎么', '为什么', '可以', '需要',
|
|
488
|
+
]);
|
|
489
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extract/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAI3F,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAG1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC1E,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACzF,OAAO,EAAE,aAAa,EAA2B,MAAM,eAAe,CAAA;AACtE,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,OAAO,EAAE,gBAAgB,EAAuB,MAAM,iBAAiB,CAAA;AAClH,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEnE,MAAM,iBAAiB,GAAG,GAAG,CAAA;AAC7B,MAAM,YAAY,GAAG,CAAC,CAAA;AACtB,MAAM,aAAa,GAAG,CAAC,CAAA;AACvB,+EAA+E;AAC/E,0EAA0E;AAC1E,8EAA8E;AAC9E,+EAA+E;AAC/E,sBAAsB;AACtB,MAAM,qBAAqB,GAAG,IAAI,CAAA;AAyDlC,iEAAiE;AACjE,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,IAAgB,EAAE,OAAsB;IACpF,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAA;IAC1C,IAAI,GAAG,EAAE,CAAC,IAAI,KAAK,KAAK;QAAE,OAAM;IAEhC,MAAM,MAAM,GAAG,IAAI,GAAG,EAA2B,CAAA;IAEjD,SAAS,OAAO,CAAC,OAAgB;QAC/B,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAClC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,GAAG;gBACN,OAAO,EAAE,CAAC;gBACV,aAAa,EAAE,IAAI;gBACnB,QAAQ,EAAE,KAAK;gBACf,UAAU,EAAE,eAAe,EAAE;gBAC7B,WAAW,EAAE,IAAI;gBACjB,MAAM,EAAE,IAAI;aACb,CAAA;YACD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;QAC/B,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,SAAS,SAAS,CAAC,OAAgB,EAAE,KAAsB;QACzD,IAAI,GAAG,EAAE,CAAC,IAAI,KAAK,aAAa;YAAE,OAAM;QACxC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAA;QACrB,KAAK,CAAC,WAAW,GAAG,IAAI,CAAA;QACxB,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE;YACnC,IAAI,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC;gBAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACrE,CAAC,EAAE,GAAG,EAAE,CAAC,cAAc,GAAG,MAAM,CAAC,CAAA;IACnC,CAAC;IAED,SAAS,aAAa,CAAC,OAAgB,EAAE,KAAsB;QAC7D,IAAI,GAAG,EAAE,CAAC,IAAI,KAAK,aAAa;YAAE,OAAM;QACxC,IAAI,KAAK,CAAC,QAAQ;YAAE,OAAM;QAC1B,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAA;QACrB,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IACnD,CAAC;IAED,GAAG,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;QACzC,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU;YAAE,OAAM;QAChD,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAM;QACtC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QAC9B,KAAK,CAAC,OAAO,IAAI,CAAC,CAAA;QAClB,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACzB,IAAI,mBAAmB,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC;YAAE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC1F,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,EAAE,CAAC,qBAAqB,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;QAC1C,yEAAyE;QACzE,8EAA8E;QAC9E,0FAA0F;QAC1F,IAAI,CAAC,GAAG,EAAE,CAAC,mBAAmB;YAAE,OAAM;QACtC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA;QAC7B,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU;YAAE,OAAM;QAChD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QAC9B,IAAI,iBAAiB,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;YAClH,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE;QAClC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY;YAAE,OAAM;QAC/B,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU;YAAE,OAAM;QAChD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QAC9B,IAAI,iBAAiB,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;YAClH,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,EAAE,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,WAAW,EAAE,EAAE,CAAA;YACrB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAA;YAChB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAC3B,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,oFAAoF;AACpF,SAAS,aAAa,CACpB,OAAgB,EAChB,KAAsB,EACtB,GAAY,EACZ,IAAgB,EAChB,OAAsB;IAEtB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,MAAM,MAAM,GAAG,GAAS,EAAE;QACxB,UAAU,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAA;IACjD,CAAC,CAAA;IACD,KAAK,CAAC,MAAM,GAAG,MAAM,CAAA;IACrB,KAAK,CAAC,KAAK,IAAmB,EAAE;QAC9B,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC1E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC/B,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;gBAClC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,sCAAsC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;YACzE,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAA;YACtB,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YAChC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAA;QACrB,CAAC;IACH,CAAC,CAAC,EAAE,CAAA;AACN,CAAC;AAED,wEAAwE;AACxE,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAA8B,EAC9B,KAAsB,EACtB,GAAY,EACZ,IAAgB,EAChB,MAAmB,EACnB,OAAsB;IAEtB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;IAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAA;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IACxB,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,MAA6C,EAAE,MAAM,CAAC,CAAA;IACzF,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;QAC/D,IAAI,GAAG,KAAK,SAAS;YAAE,KAAK,CAAC,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAA;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;IAC7B,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC,CAAA;IACnE,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IACrC,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAE,CAAC,GAAG,CAAA;IACxC,MAAM,SAAS,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,GAAG,CAAA;IAC5D,MAAM,UAAU,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEvG,IAAI,IAAI,GAAuB,EAAE,CAAA;IACjC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,eAAe,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;QAC1D,IAAI,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAA;IAC7D,CAAC;IACD,uEAAuE;IACvE,0EAA0E;IAC1E,kEAAkE;IAClE,MAAM,YAAY,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;IAEhE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC5B,MAAM,OAAO,GAAe,EAAE,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAA;IACrH,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;IAC9F,MAAM,EAAE,GAAiB;QACvB,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS;QACvG,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO;KAChC,CAAA;IACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;QAChE,OAAM;IACR,CAAC;IAED,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAA;IACjC,MAAM,IAAI,GAAG,mBAAmB,CAC9B,KAAK,CAAC,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,EACpE,UAAU,EACV,YAAY,EACZ,IAAI,CACL,CAAA;IACD,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,IAAI,CAAC;QACH,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAA;QACrB,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;QACnE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QAChB,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC,MAAM,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAC5E,MAAM,SAAS,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;QACjG,OAAM;IACR,CAAC;IAED,IAAI,QAA4B,CAAA;IAChC,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;QAC1D,0EAA0E;QAC1E,uEAAuE;QACvE,+CAA+C;QAC/C,KAAK,KAAK,CAAC,kBAAkB,CAAC,IAAI,EAAE;YAClC,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,OAAO,EAAE,OAAO,CAAC,EAAE;YACnB,GAAG,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;YAC7B,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;YACzC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;YAClC,IAAI;SACL,CAAC,CAAA;QACF,2EAA2E;QAC3E,0EAA0E;QAC1E,0EAA0E;QAC1E,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;YACnB,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAA;YACrB,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAA;YACvC,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;YACxC,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;YAC1G,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;gBAC3B,IAAI,CAAC;oBACH,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;oBACvC,SAAS,GAAG,IAAI,CAAA;oBAChB,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAA;gBACtB,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;oBAC1D,OAAM;gBACR,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC,YAAY,CAAC,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAA;gBACxF,MAAM,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;gBAC1D,OAAM;YACR,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;YAC1D,OAAM;QACR,CAAC;IACH,CAAC;IAED,IAAI,IAAwB,CAAA;IAC5B,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,SAAS,CAAC,EAAE,EAAE,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;QACvG,OAAM;IACR,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAA;IACjF,MAAM,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;AACnG,CAAC;AAED,oFAAoF;AACpF,SAAS,eAAe,CAAC,YAAoB;IAC3C,OAAO;QACL,4KAA4K;QAC5K,gDAAgD;QAChD,EAAE;QACF,gBAAgB;QAChB,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;KAC5B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,SAAS,CACtB,EAAgB,EAChB,IAAwB,EACxB,QAA4B,EAC5B,IAAwB,EACxB,MAA0B;IAE1B,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,CAAA;IAC7H,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAA;IACzC,MAAM,OAAO,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAA;IACvF,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACnC,MAAM,KAAK,GAAG;QACZ,EAAE;QACF,SAAS,EAAE,CAAC,WAAW,EAAE,SAAS,CAAqB;QACvD,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACrD,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACzC,SAAS,EAAE,qBAAqB;QAChC,QAAQ,EAAE,QAAQ,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC;QACvC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,GAAG,CAAC,OAAO,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,GAAG,CAAC,OAAO,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvF,UAAU;KACX,CAAA;IACD,KAAK,CAAC,UAAU,GAAG,QAAQ;QACzB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC;QAC7C,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAA;IAC3D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,KAAK,CAAC,UAAU,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,CAAA;IACpD,CAAC;IACD,KAAK,CAAC,OAAO,GAAG,CAAC,CAAA;IACjB,MAAM,KAAK,CAAC,sBAAsB,CAAC,IAAI,EAAE,SAAS,EAAE,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAA;IAEvF,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,OAAO,GAAG;YACd,EAAE;YACF,OAAO,EAAE,SAAS;YAClB,GAAG,EAAE,CAAC,WAAW,EAAE,SAAS,CAAqB;YACjD,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,eAAe,EAAE,OAAO,CAAC,eAAe;YACxC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,UAAU;YACV,OAAO;YACP,QAAQ,EAAE,QAAQ,IAAI,IAAI;YAC1B,IAAI,EAAE,IAAI,IAAI,IAAI;YAClB,IAAI,EAAE,IAAI,IAAI,IAAI;YAClB,KAAK,EAAE,KAAK,IAAI,IAAI;SACrB,CAAA;QACD,MAAM,KAAK,CAAC,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;QAC9D,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,8BAA8B,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,QAAQ;YACvE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,OAAO,GAAG,OAAO,CAAC,YAAY,GAAG,MAAM,GAAG,UAAU;YACnF,OAAO,GAAG,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,GAAG,CAC/C,CAAA;IACH,CAAC;IACD,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,QAAQ,IAAI,IAAI,CAAC,CAAA;AAC5D,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAkB,EAClB,IAAY,EACZ,QAA4B;IAE5B,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAiB,CAAC,EAAE,CAAC;gBAC5D,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAC3D,CAAC;YACD,kEAAkE;YAClE,6DAA6D;YAC7D,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;YAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,GAAG,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAA;YAC7D,yEAAyE;YACzE,8DAA8D;YAC9D,IAAI,MAAM,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACvC,MAAM,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;gBACvD,MAAM,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;YACxE,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;gBACxE,MAAM,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;YACxE,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,KAAK,OAAO;YACV,MAAM,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;YAChE,MAAM,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;YAC/E,OAAO,QAAQ,CAAC,IAAI,CAAA;QACtB,KAAK,QAAQ;YACX,MAAM,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;YAChE,MAAM,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;YAC/E,OAAO,QAAQ,CAAC,IAAI,CAAA;QACtB;YACE,OAAO,SAAS,CAAA;IACpB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CACnB,eAAmC,EACnC,gBAAoC,EACpC,YAA0H,EAC1H,OAA8B;IAE9B,IAAI,eAAe,KAAK,SAAS,IAAI,eAAe,KAAK,EAAE,EAAE,CAAC;QAC5D,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC1C,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,OAAO;gBACL,QAAQ,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;gBACzC,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;gBACvC,GAAG,CAAC,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/H,CAAA;QACH,CAAC;IACH,CAAC;IACD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;QAChC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,QAAQ,KAAK,EAAE,IAAI,SAAS,CAAC,KAAK,KAAK,EAAE,EAAE,CAAC;YACnF,OAAO;gBACL,QAAQ,EAAE,SAAS,CAAC,QAAQ;gBAC5B,KAAK,EAAE,SAAS,CAAC,KAAK;gBACtB,GAAG,CAAC,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9H,GAAG,CAAC,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,KAAK,EAAE;oBAC3D,CAAC,CAAC,SAAS,CAAC,eAAe,KAAK,SAAS,IAAI,SAAS,CAAC,eAAe,KAAK,EAAE;wBAC3E,CAAC,CAAC,EAAE,eAAe,EAAE,iBAAiB,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE;wBACnE,CAAC,CAAC,EAAE;oBACN,CAAC,CAAC,EAAE,CAAC;aACR,CAAA;QACH,CAAC;IACH,CAAC;IACD,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,EAAE,EAAE,MAAM,CAAA;IACpD,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,QAAQ,KAAK,SAAS,IAAI,YAAY,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1G,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,EAAE,CAAA;IACvE,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,oFAAoF;AACpF,KAAK,UAAU,aAAa,CAAC,MAAkC;IAC7D,MAAM,SAAS,GAAG,IAAI,cAAc,EAAE,CAAA;IACtC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM;QAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACvD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAA;IAC/B,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IAC5D,CAAC;IACD,OAAO;QACL,IAAI,EAAE,SAAS;aACZ,MAAM,EAAE;aACR,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;aACtC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAE,KAA2B,CAAC,IAAI,IAAI,EAAE,CAAC;aACrD,IAAI,CAAC,EAAE,CAAC;QACX,KAAK,EAAE,SAAS,CAAC,KAAK;KACvB,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc,CAC3B,GAAY,EACZ,KAAY,EACZ,MAAc,EACd,IAAY,EACZ,MAAmB;IAEnB,MAAM,OAAO,GAAG;QACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,GAAG,CAAC,KAAK,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,QAAQ,EAAE,CAAC,iBAAiB,CAAC;gBAC3B,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;gBACvC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE;aACtD,CAAC,CAAC;QACH,MAAM;QACN,SAAS,EAAE,qBAAqB;QAChC,MAAM;KACP,CAAA;IACD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;IACpE,OAAO;QACL,IAAI;QACJ,WAAW,EAAE,KAAK,EAAE,WAAW,IAAI,kBAAkB,CAAC,MAAM,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC;QACxF,YAAY,EAAE,KAAK,EAAE,YAAY,IAAI,kBAAkB,CAAC,IAAI,CAAC;QAC7D,eAAe,EAAE,KAAK,EAAE,eAAe,IAAI,CAAC;QAC5C,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,IAAI,CAAC;KAC/C,CAAA;AACH,CAAC;AAED,mEAAmE;AACnE,SAAS,QAAQ,CACf,OAAmB,EACnB,IAAsG;IAEtG,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAA;IACvC,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAA;IACzC,OAAO,CAAC,eAAe,IAAI,IAAI,CAAC,eAAe,CAAA;IAC/C,OAAO,CAAC,gBAAgB,IAAI,IAAI,CAAC,gBAAgB,CAAA;AACnD,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,GAAW;IACvD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IACxC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAQ,EAAE;QACnC,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAM;QACrD,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACjD,CAAC,CAAA;IACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9E,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,IAAI,CAAC,EAAE,CAAC,CAAA;IAC1C,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;SACzB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACvD,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;SACb,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAC3B,CAAC;AAED,sDAAsD;AACtD,KAAK,UAAU,QAAQ,CACrB,KAAkB,EAClB,IAAY,EACZ,QAA2B,EAC3B,GAAW;IAEX,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,MAAM,IAAI,GAAc,EAAE,CAAA;IAC1B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG;YAAE,MAAK;QAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;YACtD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,GAAG,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAA;YAC9C,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAQ;YAC3B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACb,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAChB,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG;gBAAE,MAAK;QAC/B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACzB,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC3E,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IACzE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI;CAClE,CAAC,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extraction prompt assembly. The model receives the rolling digest, the new
|
|
3
|
+
* window, and any grep-matched existing memories, and must answer with one
|
|
4
|
+
* JSON decision (create/merge/update/skip). Kept schema-minimal per the
|
|
5
|
+
* design's cost discipline — this is one background request per run.
|
|
6
|
+
* @module dsh-memory-lite/src/extract/prompt
|
|
7
|
+
*/
|
|
8
|
+
export interface GrepHitLike {
|
|
9
|
+
readonly path: string;
|
|
10
|
+
readonly line: string;
|
|
11
|
+
}
|
|
12
|
+
/** The system instruction given to the extraction model. */
|
|
13
|
+
export declare function extractionSystem(): string;
|
|
14
|
+
/** One line of the memory index: path plus one-line summary. */
|
|
15
|
+
export interface IndexEntryLike {
|
|
16
|
+
readonly path: string;
|
|
17
|
+
readonly summary: string;
|
|
18
|
+
}
|
|
19
|
+
/** The user turn: digest + window + memory index + existing hits. */
|
|
20
|
+
export declare function buildExtractionUser(digest: string | undefined, windowText: string, indexEntries: readonly IndexEntryLike[], grepHits: readonly GrepHitLike[]): string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extraction prompt assembly. The model receives the rolling digest, the new
|
|
3
|
+
* window, and any grep-matched existing memories, and must answer with one
|
|
4
|
+
* JSON decision (create/merge/update/skip). Kept schema-minimal per the
|
|
5
|
+
* design's cost discipline — this is one background request per run.
|
|
6
|
+
* @module dsh-memory-lite/src/extract/prompt
|
|
7
|
+
*/
|
|
8
|
+
/** The system instruction given to the extraction model. */
|
|
9
|
+
export function extractionSystem() {
|
|
10
|
+
return [
|
|
11
|
+
'You are a background memory extractor for an agent. You read a conversation window and decide what is worth remembering long-term.',
|
|
12
|
+
'Decisions:',
|
|
13
|
+
'- create: a new durable fact/preference/entity. Requires category (preferences|entities|events|experiences), a short title, and content.',
|
|
14
|
+
'- merge: add a compatible fact to an existing memory file.',
|
|
15
|
+
'- update: an existing memory is outdated or contradicted; new content replaces it (old content moves to History automatically).',
|
|
16
|
+
'- skip: nothing worth remembering or already covered.',
|
|
17
|
+
'',
|
|
18
|
+
'NOT WORTH REMEMBERING — do not create/merge/update for these; prefer skip:',
|
|
19
|
+
'1. Debugging/implementation process (paths, line numbers, error messages, fix steps, rename chores): record only if the lesson is reusable for future tasks (reusable -> experiences; one-off -> skip).',
|
|
20
|
+
'2. In-progress/ephemeral states ("implementing X", "planning Y", "proposal pending"): record only after the fact is settled or decided.',
|
|
21
|
+
'3. Pure changelog events ("released v0.5.2", "committed abc", "created release"): record only if the event affects future work (version compatibility, API changes).',
|
|
22
|
+
'4. Process chatter (which options were compared, what code was read): record only if it produced a reusable conclusion.',
|
|
23
|
+
'5. Already covered info: when grep hits already cover the fact and nothing new is added, skip.',
|
|
24
|
+
'',
|
|
25
|
+
'PRIORITY: when in doubt, prefer skip over create. Only record facts/decisions that would still be useful to a future agent weeks later. If a window is mostly process, skip is the correct answer.',
|
|
26
|
+
'',
|
|
27
|
+
'EXISTING MEMORY RULES (the user turn lists the memory index of existing files):',
|
|
28
|
+
'- Before create, check the index. If an existing file covers the same topic (same entity/project/event/person), use merge into that file instead of create.',
|
|
29
|
+
'- create only when no existing file covers the topic.',
|
|
30
|
+
'- merge must add only NEW facts not already present in that file (no duplicates).',
|
|
31
|
+
'- If the new fact contradicts an existing file, use update (old content moves to History).',
|
|
32
|
+
'',
|
|
33
|
+
'Reply with exactly ONE JSON object matching this schema (choose one of the four):',
|
|
34
|
+
'{"decision":"create","category":"preferences|entities|events|experiences","title":"...","content":"..."}',
|
|
35
|
+
'{"decision":"merge","path":"...","content":"..."}',
|
|
36
|
+
'{"decision":"update","path":"...","content":"..."}',
|
|
37
|
+
'{"decision":"skip","reason":"..."}',
|
|
38
|
+
'',
|
|
39
|
+
'STRICT OUTPUT RULES:',
|
|
40
|
+
'- Your entire reply must be exactly one JSON object and nothing else.',
|
|
41
|
+
'- No prose, no explanation, no markdown, no code fences, no trailing period.',
|
|
42
|
+
'- The JSON must be valid, balanced, and use half-width braces and quotes.',
|
|
43
|
+
'- Path values must be relative .md paths inside the memory root (e.g. preferences/tools.md).',
|
|
44
|
+
'- category is required only for create.',
|
|
45
|
+
].join('\n');
|
|
46
|
+
}
|
|
47
|
+
/** The user turn: digest + window + memory index + existing hits. */
|
|
48
|
+
export function buildExtractionUser(digest, windowText, indexEntries, grepHits) {
|
|
49
|
+
const sections = [];
|
|
50
|
+
if (digest !== undefined && digest !== '') {
|
|
51
|
+
sections.push('## 会话滚动摘要(前序窗口)', digest);
|
|
52
|
+
}
|
|
53
|
+
sections.push('## 本轮对话窗口', windowText);
|
|
54
|
+
if (indexEntries.length > 0) {
|
|
55
|
+
sections.push('## 记忆库现有文件(全库索引)', indexEntries.map(entry => `- ${entry.path}: ${entry.summary}`).join('\n'));
|
|
56
|
+
}
|
|
57
|
+
if (grepHits.length > 0) {
|
|
58
|
+
sections.push('## 已存在的相关记忆(grep 命中)', grepHits.map(hit => `- ${hit.path}: ${hit.line}`).join('\n'));
|
|
59
|
+
}
|
|
60
|
+
sections.push('只输出上面的 JSON 决策对象(严格遵守系统指令的 STRICT OUTPUT RULES),不要任何解释、markdown 或代码围栏。');
|
|
61
|
+
return sections.join('\n\n');
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=prompt.js.map
|