@yeaft/webchat-agent 0.1.600 → 0.1.602
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/package.json +1 -1
- package/unify/engine.js +49 -2
- package/unify/memory/dream-scheduler.js +32 -0
package/package.json
CHANGED
package/unify/engine.js
CHANGED
|
@@ -25,6 +25,8 @@ import { shouldConsolidate, consolidate, partitionMessages } from './memory/cons
|
|
|
25
25
|
import { extractMemories } from './memory/extract.js';
|
|
26
26
|
import { runCompact as runCompactOrchestrator } from './compact/orchestrator.js';
|
|
27
27
|
import { evaluateCompactTriggers } from './compact/triggers.js';
|
|
28
|
+
import { archiveTurn } from './archive/turn-archive.js';
|
|
29
|
+
import { archiveToolResults } from './archive/tool-results.js';
|
|
28
30
|
import { buildMemoryInjection } from './memory/layout.js';
|
|
29
31
|
import { buildUserProfile } from './memory/user-memory-store.js';
|
|
30
32
|
import { readSummary as readScopeSummary } from './memory/scope-tree.js';
|
|
@@ -638,7 +640,23 @@ export class Engine {
|
|
|
638
640
|
},
|
|
639
641
|
archive: async (_groupIdx, groupMsgs) => {
|
|
640
642
|
for (const m of groupMsgs) if (m.id) archiveIds.push(m.id);
|
|
641
|
-
|
|
643
|
+
const turnId = groupMsgs[0]?.id || `g_${Date.now()}`;
|
|
644
|
+
// Phase 8 PR-E: persist the cooling turn to
|
|
645
|
+
// <yeaftDir>/memory/archive/<turnId>.md so message_trace can
|
|
646
|
+
// replay it later. Scope is "user/" by default — group/task
|
|
647
|
+
// scoping is a follow-up that will arrive with multi-VP archive
|
|
648
|
+
// routing. Best-effort: archive failure must not abort compact.
|
|
649
|
+
if (this.#yeaftDir) {
|
|
650
|
+
try {
|
|
651
|
+
await archiveTurn({
|
|
652
|
+
root: `${this.#yeaftDir}/memory`,
|
|
653
|
+
scopeDir: 'user',
|
|
654
|
+
turnId,
|
|
655
|
+
messages: groupMsgs,
|
|
656
|
+
});
|
|
657
|
+
} catch { /* best-effort */ }
|
|
658
|
+
}
|
|
659
|
+
return { turnId };
|
|
642
660
|
},
|
|
643
661
|
extract: async (coolingMessages) => {
|
|
644
662
|
try {
|
|
@@ -900,11 +918,40 @@ export class Engine {
|
|
|
900
918
|
}
|
|
901
919
|
}
|
|
902
920
|
|
|
921
|
+
// Phase 8 PR-E: archive bulky tool results before they go on the
|
|
922
|
+
// wire. archiveToolResults walks the messages array and replaces
|
|
923
|
+
// any `role:'tool'` body older than turnAgeMin AND larger than
|
|
924
|
+
// lengthMin with a small stub, persisting the original to
|
|
925
|
+
// <yeaftDir>/memory/<scopeDir>/archive/tool-results/<id>.md so
|
|
926
|
+
// message_trace can fetch it on demand. The stub keeps the
|
|
927
|
+
// OpenAI/Anthropic toolCallId pairing intact.
|
|
928
|
+
let wireMessages = stripMetaForWire([...conversationMessages]);
|
|
929
|
+
if (this.#yeaftDir && (this.#config?.archive?.toolResults !== false)) {
|
|
930
|
+
try {
|
|
931
|
+
const swept = await archiveToolResults({
|
|
932
|
+
root: `${this.#yeaftDir}/memory`,
|
|
933
|
+
scopeDir: 'user',
|
|
934
|
+
messages: wireMessages,
|
|
935
|
+
turnAgeMin: this.#config?.archive?.turnAgeMin,
|
|
936
|
+
lengthMin: this.#config?.archive?.lengthMin,
|
|
937
|
+
});
|
|
938
|
+
wireMessages = swept.nextMessages;
|
|
939
|
+
// Mutate the in-memory conversation array so subsequent turns
|
|
940
|
+
// see the stub too — without this, the next turn re-archives
|
|
941
|
+
// the same body.
|
|
942
|
+
if (swept.archivedCount > 0) {
|
|
943
|
+
for (let i = 0; i < conversationMessages.length; i += 1) {
|
|
944
|
+
conversationMessages[i] = wireMessages[i];
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
} catch { /* best-effort */ }
|
|
948
|
+
}
|
|
949
|
+
|
|
903
950
|
// Stream from adapter
|
|
904
951
|
for await (const event of this.#adapter.stream({
|
|
905
952
|
model: currentModel,
|
|
906
953
|
system: systemPrompt,
|
|
907
|
-
messages:
|
|
954
|
+
messages: wireMessages,
|
|
908
955
|
tools: toolDefs.length > 0 ? toolDefs : undefined,
|
|
909
956
|
maxTokens: this.#config.maxOutputTokens || 16384,
|
|
910
957
|
effort: resolvedEffort,
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import { dreamShard } from './dream-shard.js';
|
|
25
25
|
import { checkRecompression } from './recompression.js';
|
|
26
26
|
import { runUserDreamJob } from './user-memory-store.js';
|
|
27
|
+
import { runDreamTick } from '../dream-v2/tick.js';
|
|
27
28
|
|
|
28
29
|
/** Default idle timeout before dream triggers (ms). */
|
|
29
30
|
export const DREAM_IDLE_MS = 30 * 60 * 1000; // 30 min
|
|
@@ -158,6 +159,37 @@ export function createDreamScheduler(opts = {}) {
|
|
|
158
159
|
// Non-fatal
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
// Phase 8 PR-F: dream-v2 diff-gated scope-summary refresh
|
|
163
|
+
// (DESIGN.md §9.14). The legacy dreamShard pipeline above
|
|
164
|
+
// refreshed shard summaries; this final tick walks the scope
|
|
165
|
+
// tree (user/group/vp/task), computes per-scope sigs, and only
|
|
166
|
+
// re-runs the refresh hook for scopes whose content changed.
|
|
167
|
+
// Refresh-only in v1 (no prune/demote — DESIGN §8 line 395).
|
|
168
|
+
if (memoryDir) {
|
|
169
|
+
try {
|
|
170
|
+
const scopes = [{ kind: 'user', scopeDir: 'user' }];
|
|
171
|
+
if (group?.id) scopes.push({ kind: 'group', id: group.id, scopeDir: `groups/${group.id}` });
|
|
172
|
+
const tickResult = await runDreamTick({
|
|
173
|
+
root: memoryDir,
|
|
174
|
+
scopes,
|
|
175
|
+
refresh: async (_scope) => {
|
|
176
|
+
// v1 refresh hook: no-op placeholder. The actual scope
|
|
177
|
+
// summary refresh continues to flow through the legacy
|
|
178
|
+
// shard / user-dream paths above; this tick only
|
|
179
|
+
// exercises the diff-gate + cursor write so future hook
|
|
180
|
+
// implementations can plug in without re-wiring.
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
result.dreamV2Tick = {
|
|
184
|
+
ran: tickResult.ran.length,
|
|
185
|
+
skipped: tickResult.skipped.length,
|
|
186
|
+
errors: tickResult.errors.length,
|
|
187
|
+
};
|
|
188
|
+
} catch {
|
|
189
|
+
// Non-fatal
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
161
193
|
messagesSinceLastDream = 0;
|
|
162
194
|
lastDreamAt = Date.now();
|
|
163
195
|
onDreamEnd?.(vpId, { ...result, trigger });
|