@framers/agentos 0.1.112 → 0.1.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/strategies/debate.d.ts +12 -1
- package/dist/api/strategies/debate.d.ts.map +1 -1
- package/dist/api/strategies/debate.js +41 -5
- package/dist/api/strategies/debate.js.map +1 -1
- package/dist/api/strategies/hierarchical.d.ts +15 -1
- package/dist/api/strategies/hierarchical.d.ts.map +1 -1
- package/dist/api/strategies/hierarchical.js +51 -7
- package/dist/api/strategies/hierarchical.js.map +1 -1
- package/dist/api/strategies/index.d.ts +26 -4
- package/dist/api/strategies/index.d.ts.map +1 -1
- package/dist/api/strategies/index.js +26 -4
- package/dist/api/strategies/index.js.map +1 -1
- package/dist/api/strategies/parallel.d.ts +15 -4
- package/dist/api/strategies/parallel.d.ts.map +1 -1
- package/dist/api/strategies/parallel.js +53 -16
- package/dist/api/strategies/parallel.js.map +1 -1
- package/dist/api/strategies/review-loop.d.ts +15 -1
- package/dist/api/strategies/review-loop.d.ts.map +1 -1
- package/dist/api/strategies/review-loop.js +36 -10
- package/dist/api/strategies/review-loop.js.map +1 -1
- package/dist/api/strategies/sequential.d.ts +11 -1
- package/dist/api/strategies/sequential.d.ts.map +1 -1
- package/dist/api/strategies/sequential.js +39 -8
- package/dist/api/strategies/sequential.js.map +1 -1
- package/dist/api/strategies/shared.d.ts +71 -7
- package/dist/api/strategies/shared.d.ts.map +1 -1
- package/dist/api/strategies/shared.js +89 -10
- package/dist/api/strategies/shared.js.map +1 -1
- package/dist/api/types.d.ts +54 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/types.js.map +1 -1
- package/dist/memory/facade/Memory.d.ts.map +1 -1
- package/dist/memory/facade/Memory.js +8 -0
- package/dist/memory/facade/Memory.js.map +1 -1
- package/dist/memory/facade/types.d.ts +10 -0
- package/dist/memory/facade/types.d.ts.map +1 -1
- package/dist/memory/index.d.ts +6 -0
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +5 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/observation/MemoryObserver.d.ts +63 -1
- package/dist/memory/observation/MemoryObserver.d.ts.map +1 -1
- package/dist/memory/observation/MemoryObserver.js +115 -4
- package/dist/memory/observation/MemoryObserver.js.map +1 -1
- package/dist/memory/observation/ObservationCompressor.d.ts +88 -0
- package/dist/memory/observation/ObservationCompressor.d.ts.map +1 -0
- package/dist/memory/observation/ObservationCompressor.js +207 -0
- package/dist/memory/observation/ObservationCompressor.js.map +1 -0
- package/dist/memory/observation/ObservationReflector.d.ts +82 -0
- package/dist/memory/observation/ObservationReflector.d.ts.map +1 -0
- package/dist/memory/observation/ObservationReflector.js +212 -0
- package/dist/memory/observation/ObservationReflector.js.map +1 -0
- package/dist/memory/observation/temporal.d.ts +54 -0
- package/dist/memory/observation/temporal.d.ts.map +1 -0
- package/dist/memory/observation/temporal.js +115 -0
- package/dist/memory/observation/temporal.js.map +1 -0
- package/dist/orchestration/builders/VoiceNodeBuilder.d.ts +82 -25
- package/dist/orchestration/builders/VoiceNodeBuilder.d.ts.map +1 -1
- package/dist/orchestration/builders/VoiceNodeBuilder.js +86 -26
- package/dist/orchestration/builders/VoiceNodeBuilder.js.map +1 -1
- package/dist/orchestration/events/GraphEvent.d.ts +67 -5
- package/dist/orchestration/events/GraphEvent.d.ts.map +1 -1
- package/dist/orchestration/events/GraphEvent.js.map +1 -1
- package/dist/orchestration/runtime/VoiceNodeExecutor.d.ts +102 -25
- package/dist/orchestration/runtime/VoiceNodeExecutor.d.ts.map +1 -1
- package/dist/orchestration/runtime/VoiceNodeExecutor.js +133 -38
- package/dist/orchestration/runtime/VoiceNodeExecutor.js.map +1 -1
- package/dist/orchestration/runtime/VoiceTransportAdapter.d.ts +94 -32
- package/dist/orchestration/runtime/VoiceTransportAdapter.d.ts.map +1 -1
- package/dist/orchestration/runtime/VoiceTransportAdapter.js +82 -28
- package/dist/orchestration/runtime/VoiceTransportAdapter.js.map +1 -1
- package/dist/orchestration/runtime/VoiceTurnCollector.d.ts +73 -20
- package/dist/orchestration/runtime/VoiceTurnCollector.d.ts.map +1 -1
- package/dist/orchestration/runtime/VoiceTurnCollector.js +84 -23
- package/dist/orchestration/runtime/VoiceTurnCollector.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Memory Observer — personality-biased background note extraction
|
|
2
|
+
* @fileoverview Memory Observer — personality-biased background note extraction
|
|
3
|
+
* with LLM-based compression and reflection tiers.
|
|
3
4
|
*
|
|
4
5
|
* Monitors accumulated conversation tokens via ObservationBuffer.
|
|
5
6
|
* When the threshold is reached, extracts concise observation notes
|
|
6
7
|
* via a persona-configured LLM (defaults to cheap model).
|
|
7
8
|
*
|
|
9
|
+
* Three-tier agentic memory pipeline (Mastra-style):
|
|
10
|
+
* 1. Raw notes — extracted per-turn when token threshold is reached.
|
|
11
|
+
* 2. Compressed observations — produced by ObservationCompressor when
|
|
12
|
+
* accumulated notes exceed the compression threshold (default: 50 notes).
|
|
13
|
+
* 3. Reflections — produced by ObservationReflector when compressed
|
|
14
|
+
* observations exceed the reflection token threshold (default: 40,000 tokens).
|
|
15
|
+
*
|
|
8
16
|
* Personality bias:
|
|
9
17
|
* - High emotionality → notes emotional shifts
|
|
10
18
|
* - High conscientiousness → notes commitments/deadlines
|
|
@@ -16,6 +24,8 @@
|
|
|
16
24
|
*/
|
|
17
25
|
import type { HexacoTraits, PADState, ObserverConfig } from '../config.js';
|
|
18
26
|
import { ObservationBuffer, type BufferedMessage } from './ObservationBuffer.js';
|
|
27
|
+
import { type CompressedObservation } from './ObservationCompressor.js';
|
|
28
|
+
import { type Reflection } from './ObservationReflector.js';
|
|
19
29
|
export interface ObservationNote {
|
|
20
30
|
id: string;
|
|
21
31
|
/** Category of observation. */
|
|
@@ -32,12 +42,27 @@ export interface ObservationNote {
|
|
|
32
42
|
arousal: number;
|
|
33
43
|
};
|
|
34
44
|
timestamp: number;
|
|
45
|
+
/** Three-date temporal metadata. */
|
|
46
|
+
temporal?: {
|
|
47
|
+
/** When this observation was made (Unix ms). Same as timestamp. */
|
|
48
|
+
observedAt: number;
|
|
49
|
+
/** When the referenced event actually occurred (Unix ms). */
|
|
50
|
+
referencedAt: number;
|
|
51
|
+
/** Human-friendly relative time label. */
|
|
52
|
+
relativeLabel: string;
|
|
53
|
+
};
|
|
35
54
|
}
|
|
36
55
|
export declare class MemoryObserver {
|
|
37
56
|
private buffer;
|
|
38
57
|
private traits;
|
|
39
58
|
private llmInvoker?;
|
|
40
59
|
private config;
|
|
60
|
+
private accumulatedNotes;
|
|
61
|
+
private accumulatedCompressed;
|
|
62
|
+
private compressor;
|
|
63
|
+
private reflector;
|
|
64
|
+
private compressionThreshold;
|
|
65
|
+
private reflectionThresholdTokens;
|
|
41
66
|
constructor(traits: HexacoTraits, config?: Partial<ObserverConfig>);
|
|
42
67
|
/**
|
|
43
68
|
* Feed a message into the observation buffer.
|
|
@@ -48,12 +73,49 @@ export declare class MemoryObserver {
|
|
|
48
73
|
* Force extraction of observation notes from buffered messages.
|
|
49
74
|
*/
|
|
50
75
|
extractNotes(mood?: PADState): Promise<ObservationNote[]>;
|
|
76
|
+
/**
|
|
77
|
+
* Run compression if accumulated notes exceed the compression threshold.
|
|
78
|
+
*
|
|
79
|
+
* When the number of accumulated raw notes exceeds the configured threshold
|
|
80
|
+
* (default: 50), the ObservationCompressor is invoked to produce denser
|
|
81
|
+
* compressed observations. The raw notes are then cleared.
|
|
82
|
+
*
|
|
83
|
+
* @returns Compressed observations if threshold was met, null otherwise.
|
|
84
|
+
*/
|
|
85
|
+
compressIfNeeded(): Promise<CompressedObservation[] | null>;
|
|
86
|
+
/**
|
|
87
|
+
* Run reflection if accumulated compressed observations exceed the token threshold.
|
|
88
|
+
*
|
|
89
|
+
* When the total estimated tokens of accumulated compressed observations
|
|
90
|
+
* exceeds the configured threshold (default: 40,000 tokens), the
|
|
91
|
+
* ObservationReflector is invoked to extract higher-level patterns.
|
|
92
|
+
*
|
|
93
|
+
* @returns Reflections if threshold was met, null otherwise.
|
|
94
|
+
*/
|
|
95
|
+
reflectIfNeeded(): Promise<Reflection[] | null>;
|
|
51
96
|
/** Get the underlying buffer for inspection. */
|
|
52
97
|
getBuffer(): ObservationBuffer;
|
|
53
98
|
/** Check if observation should be triggered. */
|
|
54
99
|
shouldActivate(): boolean;
|
|
100
|
+
/** Get the count of accumulated raw notes awaiting compression. */
|
|
101
|
+
getAccumulatedNoteCount(): number;
|
|
102
|
+
/** Get the count of accumulated compressed observations awaiting reflection. */
|
|
103
|
+
getAccumulatedCompressedCount(): number;
|
|
104
|
+
/** Get the accumulated compressed observations (read-only snapshot). */
|
|
105
|
+
getAccumulatedCompressed(): readonly CompressedObservation[];
|
|
106
|
+
/** Set the compression threshold (number of notes before compression triggers). */
|
|
107
|
+
setCompressionThreshold(threshold: number): void;
|
|
108
|
+
/** Set the reflection token threshold (estimated tokens before reflection triggers). */
|
|
109
|
+
setReflectionThresholdTokens(threshold: number): void;
|
|
55
110
|
/** Reset the observer. */
|
|
56
111
|
clear(): void;
|
|
112
|
+
/**
|
|
113
|
+
* Parse LLM response into ObservationNote objects.
|
|
114
|
+
*
|
|
115
|
+
* Attaches three-date temporal metadata from conversation message timestamps
|
|
116
|
+
* when available, using the earliest message timestamp as `referencedAt`
|
|
117
|
+
* and the current time as `observedAt`.
|
|
118
|
+
*/
|
|
57
119
|
private parseNotes;
|
|
58
120
|
}
|
|
59
121
|
//# sourceMappingURL=MemoryObserver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryObserver.d.ts","sourceRoot":"","sources":["../../../src/memory/observation/MemoryObserver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"MemoryObserver.d.ts","sourceRoot":"","sources":["../../../src/memory/observation/MemoryObserver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAyB,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAOlF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,+BAA+B;IAC/B,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,YAAY,GAAG,YAAY,GAAG,UAAU,GAAG,YAAY,CAAC;IACxF,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,QAAQ,CAAC,EAAE;QACT,mEAAmE;QACnE,UAAU,EAAE,MAAM,CAAC;QACnB,6DAA6D;QAC7D,YAAY,EAAE,MAAM,CAAC;QACrB,0CAA0C;QAC1C,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AA2CD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAgE;IACnF,OAAO,CAAC,MAAM,CAAiB;IAG/B,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,qBAAqB,CAA+B;IAC5D,OAAO,CAAC,UAAU,CAAsC;IACxD,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,yBAAyB,CAAS;gBAGxC,MAAM,EAAE,YAAY,EACpB,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;IAwBlC;;;OAGG;IACG,OAAO,CACX,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAC7B,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,QAAQ,GACd,OAAO,CAAC,eAAe,EAAE,GAAG,IAAI,CAAC;IASpC;;OAEG;IACG,YAAY,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA0B/D;;;;;;;;OAQG;IACG,gBAAgB,IAAI,OAAO,CAAC,qBAAqB,EAAE,GAAG,IAAI,CAAC;IAajE;;;;;;;;OAQG;IACG,eAAe,IAAI,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAiBrD,gDAAgD;IAChD,SAAS,IAAI,iBAAiB;IAI9B,gDAAgD;IAChD,cAAc,IAAI,OAAO;IAIzB,mEAAmE;IACnE,uBAAuB,IAAI,MAAM;IAIjC,gFAAgF;IAChF,6BAA6B,IAAI,MAAM;IAIvC,wEAAwE;IACxE,wBAAwB,IAAI,SAAS,qBAAqB,EAAE;IAI5D,mFAAmF;IACnF,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIhD,wFAAwF;IACxF,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIrD,0BAA0B;IAC1B,KAAK,IAAI,IAAI;IAQb;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;CA0CnB"}
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Memory Observer — personality-biased background note extraction
|
|
2
|
+
* @fileoverview Memory Observer — personality-biased background note extraction
|
|
3
|
+
* with LLM-based compression and reflection tiers.
|
|
3
4
|
*
|
|
4
5
|
* Monitors accumulated conversation tokens via ObservationBuffer.
|
|
5
6
|
* When the threshold is reached, extracts concise observation notes
|
|
6
7
|
* via a persona-configured LLM (defaults to cheap model).
|
|
7
8
|
*
|
|
9
|
+
* Three-tier agentic memory pipeline (Mastra-style):
|
|
10
|
+
* 1. Raw notes — extracted per-turn when token threshold is reached.
|
|
11
|
+
* 2. Compressed observations — produced by ObservationCompressor when
|
|
12
|
+
* accumulated notes exceed the compression threshold (default: 50 notes).
|
|
13
|
+
* 3. Reflections — produced by ObservationReflector when compressed
|
|
14
|
+
* observations exceed the reflection token threshold (default: 40,000 tokens).
|
|
15
|
+
*
|
|
8
16
|
* Personality bias:
|
|
9
17
|
* - High emotionality → notes emotional shifts
|
|
10
18
|
* - High conscientiousness → notes commitments/deadlines
|
|
@@ -15,6 +23,9 @@
|
|
|
15
23
|
* @module agentos/memory/observation/MemoryObserver
|
|
16
24
|
*/
|
|
17
25
|
import { ObservationBuffer } from './ObservationBuffer.js';
|
|
26
|
+
import { ObservationCompressor } from './ObservationCompressor.js';
|
|
27
|
+
import { ObservationReflector } from './ObservationReflector.js';
|
|
28
|
+
import { relativeTimeLabel } from './temporal.js';
|
|
18
29
|
// ---------------------------------------------------------------------------
|
|
19
30
|
// Personality-aware system prompt builder
|
|
20
31
|
// ---------------------------------------------------------------------------
|
|
@@ -48,8 +59,17 @@ Output ONLY valid JSON objects, one per line. No markdown, no explanation.${emph
|
|
|
48
59
|
// MemoryObserver
|
|
49
60
|
// ---------------------------------------------------------------------------
|
|
50
61
|
let noteIdCounter = 0;
|
|
62
|
+
/** Default number of accumulated notes before compression triggers. */
|
|
63
|
+
const DEFAULT_COMPRESSION_THRESHOLD = 50;
|
|
64
|
+
/** Default token count of compressed observations before reflection triggers. */
|
|
65
|
+
const DEFAULT_REFLECTION_THRESHOLD_TOKENS = 40000;
|
|
51
66
|
export class MemoryObserver {
|
|
52
67
|
constructor(traits, config) {
|
|
68
|
+
// --- Compression / reflection tier state ---
|
|
69
|
+
this.accumulatedNotes = [];
|
|
70
|
+
this.accumulatedCompressed = [];
|
|
71
|
+
this.compressor = null;
|
|
72
|
+
this.reflector = null;
|
|
53
73
|
this.traits = traits;
|
|
54
74
|
this.config = {
|
|
55
75
|
activationThresholdTokens: config?.activationThresholdTokens ?? 30000,
|
|
@@ -60,6 +80,14 @@ export class MemoryObserver {
|
|
|
60
80
|
this.buffer = new ObservationBuffer({
|
|
61
81
|
activationThresholdTokens: this.config.activationThresholdTokens,
|
|
62
82
|
});
|
|
83
|
+
// Default thresholds for compression and reflection tiers.
|
|
84
|
+
this.compressionThreshold = DEFAULT_COMPRESSION_THRESHOLD;
|
|
85
|
+
this.reflectionThresholdTokens = DEFAULT_REFLECTION_THRESHOLD_TOKENS;
|
|
86
|
+
// Initialize compressor and reflector if LLM invoker is provided.
|
|
87
|
+
if (this.llmInvoker) {
|
|
88
|
+
this.compressor = new ObservationCompressor(this.llmInvoker, this.traits);
|
|
89
|
+
this.reflector = new ObservationReflector(this.llmInvoker);
|
|
90
|
+
}
|
|
63
91
|
}
|
|
64
92
|
/**
|
|
65
93
|
* Feed a message into the observation buffer.
|
|
@@ -89,12 +117,55 @@ export class MemoryObserver {
|
|
|
89
117
|
const systemPrompt = buildObserverSystemPrompt(this.traits);
|
|
90
118
|
try {
|
|
91
119
|
const response = await this.llmInvoker(systemPrompt, conversationText);
|
|
92
|
-
|
|
120
|
+
const notes = this.parseNotes(response, mood, messages);
|
|
121
|
+
// Accumulate notes for the compression tier.
|
|
122
|
+
this.accumulatedNotes.push(...notes);
|
|
123
|
+
return notes;
|
|
93
124
|
}
|
|
94
125
|
catch {
|
|
95
126
|
return [];
|
|
96
127
|
}
|
|
97
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Run compression if accumulated notes exceed the compression threshold.
|
|
131
|
+
*
|
|
132
|
+
* When the number of accumulated raw notes exceeds the configured threshold
|
|
133
|
+
* (default: 50), the ObservationCompressor is invoked to produce denser
|
|
134
|
+
* compressed observations. The raw notes are then cleared.
|
|
135
|
+
*
|
|
136
|
+
* @returns Compressed observations if threshold was met, null otherwise.
|
|
137
|
+
*/
|
|
138
|
+
async compressIfNeeded() {
|
|
139
|
+
if (!this.compressor)
|
|
140
|
+
return null;
|
|
141
|
+
if (this.accumulatedNotes.length < this.compressionThreshold)
|
|
142
|
+
return null;
|
|
143
|
+
const compressed = await this.compressor.compress(this.accumulatedNotes);
|
|
144
|
+
// Clear consumed notes and accumulate compressed observations.
|
|
145
|
+
this.accumulatedNotes = [];
|
|
146
|
+
this.accumulatedCompressed.push(...compressed);
|
|
147
|
+
return compressed;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Run reflection if accumulated compressed observations exceed the token threshold.
|
|
151
|
+
*
|
|
152
|
+
* When the total estimated tokens of accumulated compressed observations
|
|
153
|
+
* exceeds the configured threshold (default: 40,000 tokens), the
|
|
154
|
+
* ObservationReflector is invoked to extract higher-level patterns.
|
|
155
|
+
*
|
|
156
|
+
* @returns Reflections if threshold was met, null otherwise.
|
|
157
|
+
*/
|
|
158
|
+
async reflectIfNeeded() {
|
|
159
|
+
if (!this.reflector)
|
|
160
|
+
return null;
|
|
161
|
+
const totalTokens = this.accumulatedCompressed.reduce((sum, o) => sum + Math.ceil(o.summary.length / 4), 0);
|
|
162
|
+
if (totalTokens < this.reflectionThresholdTokens)
|
|
163
|
+
return null;
|
|
164
|
+
const reflections = await this.reflector.reflect(this.accumulatedCompressed);
|
|
165
|
+
// Clear consumed compressed observations.
|
|
166
|
+
this.accumulatedCompressed = [];
|
|
167
|
+
return reflections;
|
|
168
|
+
}
|
|
98
169
|
/** Get the underlying buffer for inspection. */
|
|
99
170
|
getBuffer() {
|
|
100
171
|
return this.buffer;
|
|
@@ -103,18 +174,53 @@ export class MemoryObserver {
|
|
|
103
174
|
shouldActivate() {
|
|
104
175
|
return this.buffer.shouldActivate();
|
|
105
176
|
}
|
|
177
|
+
/** Get the count of accumulated raw notes awaiting compression. */
|
|
178
|
+
getAccumulatedNoteCount() {
|
|
179
|
+
return this.accumulatedNotes.length;
|
|
180
|
+
}
|
|
181
|
+
/** Get the count of accumulated compressed observations awaiting reflection. */
|
|
182
|
+
getAccumulatedCompressedCount() {
|
|
183
|
+
return this.accumulatedCompressed.length;
|
|
184
|
+
}
|
|
185
|
+
/** Get the accumulated compressed observations (read-only snapshot). */
|
|
186
|
+
getAccumulatedCompressed() {
|
|
187
|
+
return this.accumulatedCompressed;
|
|
188
|
+
}
|
|
189
|
+
/** Set the compression threshold (number of notes before compression triggers). */
|
|
190
|
+
setCompressionThreshold(threshold) {
|
|
191
|
+
this.compressionThreshold = threshold;
|
|
192
|
+
}
|
|
193
|
+
/** Set the reflection token threshold (estimated tokens before reflection triggers). */
|
|
194
|
+
setReflectionThresholdTokens(threshold) {
|
|
195
|
+
this.reflectionThresholdTokens = threshold;
|
|
196
|
+
}
|
|
106
197
|
/** Reset the observer. */
|
|
107
198
|
clear() {
|
|
108
199
|
this.buffer.clear();
|
|
200
|
+
this.accumulatedNotes = [];
|
|
201
|
+
this.accumulatedCompressed = [];
|
|
109
202
|
}
|
|
110
203
|
// --- Internal ---
|
|
111
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Parse LLM response into ObservationNote objects.
|
|
206
|
+
*
|
|
207
|
+
* Attaches three-date temporal metadata from conversation message timestamps
|
|
208
|
+
* when available, using the earliest message timestamp as `referencedAt`
|
|
209
|
+
* and the current time as `observedAt`.
|
|
210
|
+
*/
|
|
211
|
+
parseNotes(llmResponse, mood, messages) {
|
|
112
212
|
const notes = [];
|
|
113
213
|
const lines = llmResponse.split('\n').filter((l) => l.trim());
|
|
214
|
+
// Determine the earliest message timestamp for the referencedAt field.
|
|
215
|
+
const earliestMessageTime = messages && messages.length > 0
|
|
216
|
+
? Math.min(...messages.map((m) => m.timestamp))
|
|
217
|
+
: undefined;
|
|
114
218
|
for (const line of lines) {
|
|
115
219
|
try {
|
|
116
220
|
const parsed = JSON.parse(line.trim());
|
|
117
221
|
if (parsed.type && parsed.content) {
|
|
222
|
+
const now = Date.now();
|
|
223
|
+
const referencedAt = earliestMessageTime ?? now;
|
|
118
224
|
notes.push({
|
|
119
225
|
id: `obs_${Date.now()}_${++noteIdCounter}`,
|
|
120
226
|
type: parsed.type,
|
|
@@ -122,7 +228,12 @@ export class MemoryObserver {
|
|
|
122
228
|
importance: typeof parsed.importance === 'number' ? parsed.importance : 0.5,
|
|
123
229
|
entities: Array.isArray(parsed.entities) ? parsed.entities : [],
|
|
124
230
|
emotionalContext: mood ? { valence: mood.valence, arousal: mood.arousal } : undefined,
|
|
125
|
-
timestamp:
|
|
231
|
+
timestamp: now,
|
|
232
|
+
temporal: {
|
|
233
|
+
observedAt: now,
|
|
234
|
+
referencedAt,
|
|
235
|
+
relativeLabel: relativeTimeLabel(referencedAt, now),
|
|
236
|
+
},
|
|
126
237
|
});
|
|
127
238
|
}
|
|
128
239
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryObserver.js","sourceRoot":"","sources":["../../../src/memory/observation/MemoryObserver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"MemoryObserver.js","sourceRoot":"","sources":["../../../src/memory/observation/MemoryObserver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview LLM-based observational memory compressor.
|
|
3
|
+
*
|
|
4
|
+
* Takes a batch of {@link ObservationNote} objects and compresses them into
|
|
5
|
+
* denser {@link CompressedObservation} summaries via an LLM call. This is the
|
|
6
|
+
* "Observer" agent in Mastra's agentic memory model — it groups related
|
|
7
|
+
* observations by topic/entity overlap, produces a 1-3 sentence summary per
|
|
8
|
+
* group, assigns a priority level, and attaches three-date temporal metadata.
|
|
9
|
+
*
|
|
10
|
+
* Typical compression: 3-10x (many individual notes become fewer dense
|
|
11
|
+
* summaries while preserving all critical facts).
|
|
12
|
+
*
|
|
13
|
+
* Personality bias: when HEXACO traits are provided, the system prompt
|
|
14
|
+
* is tuned to emphasise observation categories that align with the agent's
|
|
15
|
+
* personality (e.g. high conscientiousness → emphasise commitments).
|
|
16
|
+
*
|
|
17
|
+
* @module agentos/memory/observation/ObservationCompressor
|
|
18
|
+
*/
|
|
19
|
+
import type { HexacoTraits } from '../config.js';
|
|
20
|
+
import type { ObservationNote } from './MemoryObserver.js';
|
|
21
|
+
/** Priority level for a compressed observation. */
|
|
22
|
+
export type CompressionPriority = 'critical' | 'important' | 'informational';
|
|
23
|
+
/**
|
|
24
|
+
* A compressed observation produced by merging multiple raw
|
|
25
|
+
* {@link ObservationNote} objects into a single dense summary.
|
|
26
|
+
*/
|
|
27
|
+
export interface CompressedObservation {
|
|
28
|
+
/** Unique identifier for this compressed observation. */
|
|
29
|
+
id: string;
|
|
30
|
+
/** Dense summary of multiple observations (1-3 sentences). */
|
|
31
|
+
summary: string;
|
|
32
|
+
/** Triage priority. */
|
|
33
|
+
priority: CompressionPriority;
|
|
34
|
+
/** Three-date temporal metadata. */
|
|
35
|
+
temporal: {
|
|
36
|
+
/** When this compression was performed (Unix ms). */
|
|
37
|
+
observedAt: number;
|
|
38
|
+
/** Earliest event timestamp across all source observations (Unix ms). */
|
|
39
|
+
referencedAt: number;
|
|
40
|
+
/** Human-friendly relative time label for `referencedAt`. */
|
|
41
|
+
relativeLabel: string;
|
|
42
|
+
};
|
|
43
|
+
/** IDs of the source {@link ObservationNote} objects that were compressed. */
|
|
44
|
+
sourceIds: string[];
|
|
45
|
+
/** Union of key entities across all source observations. */
|
|
46
|
+
entities: string[];
|
|
47
|
+
/** Average importance score of the source observations (0-1). */
|
|
48
|
+
importance: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* LLM-based compressor that takes a batch of {@link ObservationNote} objects
|
|
52
|
+
* and produces denser {@link CompressedObservation} summaries.
|
|
53
|
+
*
|
|
54
|
+
* Achieves 3-10x compression while preserving key facts, entities, and
|
|
55
|
+
* temporal context. Each compressed observation carries three-date temporal
|
|
56
|
+
* metadata: when the compression happened, the earliest referenced event,
|
|
57
|
+
* and a human-friendly relative time label.
|
|
58
|
+
*/
|
|
59
|
+
export declare class ObservationCompressor {
|
|
60
|
+
private llmInvoker;
|
|
61
|
+
private traits?;
|
|
62
|
+
/**
|
|
63
|
+
* @param llmInvoker - Function that calls an LLM with (system, user) prompts.
|
|
64
|
+
* @param traits - Optional HEXACO personality traits for bias-aware compression.
|
|
65
|
+
*/
|
|
66
|
+
constructor(llmInvoker: (system: string, user: string) => Promise<string>, traits?: HexacoTraits | undefined);
|
|
67
|
+
/**
|
|
68
|
+
* Compress a batch of observation notes into denser summaries.
|
|
69
|
+
*
|
|
70
|
+
* The method:
|
|
71
|
+
* 1. Formats the notes as a numbered list for the LLM.
|
|
72
|
+
* 2. Sends the batch to the LLM with a compression prompt.
|
|
73
|
+
* 3. Parses the JSON array response into {@link CompressedObservation} objects.
|
|
74
|
+
* 4. Attaches three-date temporal metadata (observedAt, referencedAt, relativeLabel).
|
|
75
|
+
*
|
|
76
|
+
* @param notes - Batch of observation notes to compress.
|
|
77
|
+
* @returns Array of compressed observations. Returns empty array on LLM failure.
|
|
78
|
+
*/
|
|
79
|
+
compress(notes: ObservationNote[]): Promise<CompressedObservation[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Parse the LLM response into CompressedObservation objects.
|
|
82
|
+
*
|
|
83
|
+
* Tries to parse the response as a JSON array. Falls back to extracting
|
|
84
|
+
* individual JSON objects from lines if the array parse fails.
|
|
85
|
+
*/
|
|
86
|
+
private parseCompressed;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=ObservationCompressor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ObservationCompressor.d.ts","sourceRoot":"","sources":["../../../src/memory/observation/ObservationCompressor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAO3D,mDAAmD;AACnD,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,WAAW,GAAG,eAAe,CAAC;AAE7E;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,yDAAyD;IACzD,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,oCAAoC;IACpC,QAAQ,EAAE;QACR,qDAAqD;QACrD,UAAU,EAAE,MAAM,CAAC;QACnB,yEAAyE;QACzE,YAAY,EAAE,MAAM,CAAC;QACrB,6DAA6D;QAC7D,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,8EAA8E;IAC9E,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;CACpB;AAwDD;;;;;;;;GAQG;AACH,qBAAa,qBAAqB;IAM9B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,MAAM,CAAC;IANjB;;;OAGG;gBAEO,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EAC7D,MAAM,CAAC,EAAE,YAAY,YAAA;IAG/B;;;;;;;;;;;OAWG;IACG,QAAQ,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAwB1E;;;;;OAKG;IACH,OAAO,CAAC,eAAe;CAuFxB"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview LLM-based observational memory compressor.
|
|
3
|
+
*
|
|
4
|
+
* Takes a batch of {@link ObservationNote} objects and compresses them into
|
|
5
|
+
* denser {@link CompressedObservation} summaries via an LLM call. This is the
|
|
6
|
+
* "Observer" agent in Mastra's agentic memory model — it groups related
|
|
7
|
+
* observations by topic/entity overlap, produces a 1-3 sentence summary per
|
|
8
|
+
* group, assigns a priority level, and attaches three-date temporal metadata.
|
|
9
|
+
*
|
|
10
|
+
* Typical compression: 3-10x (many individual notes become fewer dense
|
|
11
|
+
* summaries while preserving all critical facts).
|
|
12
|
+
*
|
|
13
|
+
* Personality bias: when HEXACO traits are provided, the system prompt
|
|
14
|
+
* is tuned to emphasise observation categories that align with the agent's
|
|
15
|
+
* personality (e.g. high conscientiousness → emphasise commitments).
|
|
16
|
+
*
|
|
17
|
+
* @module agentos/memory/observation/ObservationCompressor
|
|
18
|
+
*/
|
|
19
|
+
import { relativeTimeLabel } from './temporal.js';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// System prompt builder
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/**
|
|
24
|
+
* Build the LLM system prompt for observation compression.
|
|
25
|
+
* Personality traits modulate which observation categories receive emphasis.
|
|
26
|
+
*/
|
|
27
|
+
function buildCompressorSystemPrompt(traits) {
|
|
28
|
+
const emphases = [];
|
|
29
|
+
if (traits) {
|
|
30
|
+
const c = (v) => v == null ? 0.5 : Math.max(0, Math.min(1, v));
|
|
31
|
+
if (c(traits.emotionality) > 0.6)
|
|
32
|
+
emphases.push('Preserve emotional context and sentiment shifts.');
|
|
33
|
+
if (c(traits.conscientiousness) > 0.6)
|
|
34
|
+
emphases.push('Preserve commitments, deadlines, and action items.');
|
|
35
|
+
if (c(traits.openness) > 0.6)
|
|
36
|
+
emphases.push('Preserve creative ideas and exploratory tangents.');
|
|
37
|
+
if (c(traits.agreeableness) > 0.6)
|
|
38
|
+
emphases.push('Preserve rapport cues and user preferences.');
|
|
39
|
+
if (c(traits.honesty) > 0.6)
|
|
40
|
+
emphases.push('Preserve corrections, retractions, and factual updates.');
|
|
41
|
+
}
|
|
42
|
+
const emphasisBlock = emphases.length > 0
|
|
43
|
+
? `\n\nPersonality emphasis:\n${emphases.map((e) => `- ${e}`).join('\n')}`
|
|
44
|
+
: '';
|
|
45
|
+
return `You are a memory compressor. Your task is to compress a batch of observation notes into denser summary groups.
|
|
46
|
+
|
|
47
|
+
Rules:
|
|
48
|
+
1. Group related observations by topic overlap or entity overlap.
|
|
49
|
+
2. For each group, produce ONE dense summary of 1-3 sentences that captures all key facts.
|
|
50
|
+
3. Assign a priority: "critical" (security, safety, urgent deadlines), "important" (user preferences, key decisions, commitments), or "informational" (context, background, trivia).
|
|
51
|
+
4. Include the IDs of all source observations in each group.
|
|
52
|
+
5. Merge entity lists from all grouped observations.
|
|
53
|
+
6. Target 3-10x compression while preserving ALL critical facts.
|
|
54
|
+
|
|
55
|
+
Output a JSON array of objects, each with:
|
|
56
|
+
{
|
|
57
|
+
"summary": "dense summary text",
|
|
58
|
+
"priority": "critical|important|informational",
|
|
59
|
+
"sourceIds": ["obs_id_1", "obs_id_2"],
|
|
60
|
+
"entities": ["entity1", "entity2"]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Output ONLY a valid JSON array. No markdown, no explanation.${emphasisBlock}`;
|
|
64
|
+
}
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Counter for unique IDs
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
let compressedIdCounter = 0;
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// ObservationCompressor
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
/**
|
|
73
|
+
* LLM-based compressor that takes a batch of {@link ObservationNote} objects
|
|
74
|
+
* and produces denser {@link CompressedObservation} summaries.
|
|
75
|
+
*
|
|
76
|
+
* Achieves 3-10x compression while preserving key facts, entities, and
|
|
77
|
+
* temporal context. Each compressed observation carries three-date temporal
|
|
78
|
+
* metadata: when the compression happened, the earliest referenced event,
|
|
79
|
+
* and a human-friendly relative time label.
|
|
80
|
+
*/
|
|
81
|
+
export class ObservationCompressor {
|
|
82
|
+
/**
|
|
83
|
+
* @param llmInvoker - Function that calls an LLM with (system, user) prompts.
|
|
84
|
+
* @param traits - Optional HEXACO personality traits for bias-aware compression.
|
|
85
|
+
*/
|
|
86
|
+
constructor(llmInvoker, traits) {
|
|
87
|
+
this.llmInvoker = llmInvoker;
|
|
88
|
+
this.traits = traits;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Compress a batch of observation notes into denser summaries.
|
|
92
|
+
*
|
|
93
|
+
* The method:
|
|
94
|
+
* 1. Formats the notes as a numbered list for the LLM.
|
|
95
|
+
* 2. Sends the batch to the LLM with a compression prompt.
|
|
96
|
+
* 3. Parses the JSON array response into {@link CompressedObservation} objects.
|
|
97
|
+
* 4. Attaches three-date temporal metadata (observedAt, referencedAt, relativeLabel).
|
|
98
|
+
*
|
|
99
|
+
* @param notes - Batch of observation notes to compress.
|
|
100
|
+
* @returns Array of compressed observations. Returns empty array on LLM failure.
|
|
101
|
+
*/
|
|
102
|
+
async compress(notes) {
|
|
103
|
+
if (notes.length === 0)
|
|
104
|
+
return [];
|
|
105
|
+
const systemPrompt = buildCompressorSystemPrompt(this.traits);
|
|
106
|
+
// Format notes as a numbered list with IDs, types, importance, and content.
|
|
107
|
+
const userPrompt = notes
|
|
108
|
+
.map((n) => `[${n.id}] (${n.type}, importance=${n.importance.toFixed(2)}, entities=[${n.entities.join(', ')}]) ${n.content}`)
|
|
109
|
+
.join('\n');
|
|
110
|
+
try {
|
|
111
|
+
const response = await this.llmInvoker(systemPrompt, userPrompt);
|
|
112
|
+
return this.parseCompressed(response, notes);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// -------------------------------------------------------------------------
|
|
119
|
+
// Internal parsing
|
|
120
|
+
// -------------------------------------------------------------------------
|
|
121
|
+
/**
|
|
122
|
+
* Parse the LLM response into CompressedObservation objects.
|
|
123
|
+
*
|
|
124
|
+
* Tries to parse the response as a JSON array. Falls back to extracting
|
|
125
|
+
* individual JSON objects from lines if the array parse fails.
|
|
126
|
+
*/
|
|
127
|
+
parseCompressed(llmResponse, sourceNotes) {
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
const noteMap = new Map(sourceNotes.map((n) => [n.id, n]));
|
|
130
|
+
const results = [];
|
|
131
|
+
// Try parsing as a JSON array first.
|
|
132
|
+
let parsed;
|
|
133
|
+
try {
|
|
134
|
+
// Strip markdown fences if present.
|
|
135
|
+
const cleaned = llmResponse
|
|
136
|
+
.replace(/^```json\s*/i, '')
|
|
137
|
+
.replace(/```\s*$/, '')
|
|
138
|
+
.trim();
|
|
139
|
+
parsed = JSON.parse(cleaned);
|
|
140
|
+
if (!Array.isArray(parsed)) {
|
|
141
|
+
parsed = [parsed];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Fallback: try parsing line by line.
|
|
146
|
+
parsed = [];
|
|
147
|
+
for (const line of llmResponse.split('\n')) {
|
|
148
|
+
const trimmed = line.trim();
|
|
149
|
+
if (!trimmed || trimmed === '[' || trimmed === ']')
|
|
150
|
+
continue;
|
|
151
|
+
try {
|
|
152
|
+
// Strip trailing comma for JSON-lines style.
|
|
153
|
+
const clean = trimmed.endsWith(',') ? trimmed.slice(0, -1) : trimmed;
|
|
154
|
+
parsed.push(JSON.parse(clean));
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Skip malformed lines.
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
for (const item of parsed) {
|
|
162
|
+
if (typeof item !== 'object' || item === null)
|
|
163
|
+
continue;
|
|
164
|
+
const obj = item;
|
|
165
|
+
if (typeof obj.summary !== 'string' || !obj.summary)
|
|
166
|
+
continue;
|
|
167
|
+
const sourceIds = Array.isArray(obj.sourceIds)
|
|
168
|
+
? obj.sourceIds.filter((id) => typeof id === 'string')
|
|
169
|
+
: [];
|
|
170
|
+
const entities = Array.isArray(obj.entities)
|
|
171
|
+
? obj.entities.filter((e) => typeof e === 'string')
|
|
172
|
+
: [];
|
|
173
|
+
const priority = (['critical', 'important', 'informational'].includes(obj.priority)
|
|
174
|
+
? obj.priority
|
|
175
|
+
: 'informational');
|
|
176
|
+
// Compute temporal metadata from source notes.
|
|
177
|
+
const sourceTimes = sourceIds
|
|
178
|
+
.map((id) => noteMap.get(id)?.timestamp)
|
|
179
|
+
.filter((t) => t != null);
|
|
180
|
+
const earliestRef = sourceTimes.length > 0
|
|
181
|
+
? Math.min(...sourceTimes)
|
|
182
|
+
: now;
|
|
183
|
+
// Compute average importance from source notes.
|
|
184
|
+
const sourceImportances = sourceIds
|
|
185
|
+
.map((id) => noteMap.get(id)?.importance)
|
|
186
|
+
.filter((i) => i != null);
|
|
187
|
+
const avgImportance = sourceImportances.length > 0
|
|
188
|
+
? sourceImportances.reduce((a, b) => a + b, 0) / sourceImportances.length
|
|
189
|
+
: 0.5;
|
|
190
|
+
results.push({
|
|
191
|
+
id: `cobs_${Date.now()}_${++compressedIdCounter}`,
|
|
192
|
+
summary: obj.summary,
|
|
193
|
+
priority,
|
|
194
|
+
temporal: {
|
|
195
|
+
observedAt: now,
|
|
196
|
+
referencedAt: earliestRef,
|
|
197
|
+
relativeLabel: relativeTimeLabel(earliestRef, now),
|
|
198
|
+
},
|
|
199
|
+
sourceIds,
|
|
200
|
+
entities,
|
|
201
|
+
importance: avgImportance,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return results;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=ObservationCompressor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ObservationCompressor.js","sourceRoot":"","sources":["../../../src/memory/observation/ObservationCompressor.ts"],"names":[],"mappings":"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"}
|