@mce-bt/microagents-memory 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/redis-state.d.ts +91 -0
- package/dist/redis-state.d.ts.map +1 -0
- package/dist/redis-state.js +176 -0
- package/dist/redis-state.js.map +1 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -6,4 +6,5 @@ export { KnowledgeGraph, type KGConfig, type Entity, type Relation, type SearchE
|
|
|
6
6
|
export { MemoryExtractor, createExtractionAdapter, type ExtractionLLMAdapter, type ExtractionResult, type ExtractionStats, type ExtractedEntity, type ExtractedRelation, } from './memory-extractor.js';
|
|
7
7
|
export { createMemoryTools } from './memory-tools.js';
|
|
8
8
|
export { SummarizationPipeline, type SummarizationPipelineConfig, type PipelineResult, } from './summarization-pipeline.js';
|
|
9
|
+
export { RedisSessionStore, RedisChannelSessionStore, RedisSchedulerStateStore, IoredisLockClient, createRedisStateStores, type RedisStateConfig, type RedisStateStores, } from './redis-state.js';
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,cAAc,EACd,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,qBAAqB,EAC1B,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACL,qBAAqB,EACrB,KAAK,2BAA2B,EAChC,KAAK,cAAc,GACpB,MAAM,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,cAAc,EACd,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,qBAAqB,EAC1B,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACL,qBAAqB,EACrB,KAAK,2BAA2B,EAChC,KAAK,cAAc,GACpB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,wBAAwB,EACxB,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,4 +6,5 @@ export { KnowledgeGraph, } from './knowledge-graph.js';
|
|
|
6
6
|
export { MemoryExtractor, createExtractionAdapter, } from './memory-extractor.js';
|
|
7
7
|
export { createMemoryTools } from './memory-tools.js';
|
|
8
8
|
export { SummarizationPipeline, } from './summarization-pipeline.js';
|
|
9
|
+
export { RedisSessionStore, RedisChannelSessionStore, RedisSchedulerStateStore, IoredisLockClient, createRedisStateStores, } from './redis-state.js';
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAkB,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAuC,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAsC,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,aAAa,EAA+C,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,cAAc,GAMf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,eAAe,EACf,uBAAuB,GAMxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACL,qBAAqB,GAGtB,MAAM,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAkB,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAuC,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAsC,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,aAAa,EAA+C,MAAM,cAAc,CAAC;AAC1F,OAAO,EACL,cAAc,GAMf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,eAAe,EACf,uBAAuB,GAMxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACL,qBAAqB,GAGtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,wBAAwB,EACxB,iBAAiB,EACjB,sBAAsB,GAGvB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Redis } from 'ioredis';
|
|
2
|
+
import type { Session, SessionStore, SchedulerJobState, SchedulerStateStore, ChannelSessionStore } from '@mce-bt/microagents-core';
|
|
3
|
+
/**
|
|
4
|
+
* Redis-backed durable state for agents: sessions, channel↔session mappings,
|
|
5
|
+
* scheduler run-state, and the client adapter for core's RedisLockProvider.
|
|
6
|
+
*
|
|
7
|
+
* All stores share one lazy Redis connection created by
|
|
8
|
+
* createRedisStateStores(); the agent starts/stops it through the
|
|
9
|
+
* AgentResources.state lifecycle hooks.
|
|
10
|
+
*
|
|
11
|
+
* Key layout (all namespaced by agentId so replicas of the same agent share
|
|
12
|
+
* state and different agents don't collide):
|
|
13
|
+
* session:{agentId}:{sessionId} JSON Session, TTL sessionTtlS
|
|
14
|
+
* sessions:{agentId} ZSET sessionId scored by startedAt ms
|
|
15
|
+
* chan:{agentId}:{type}:{externalId} sessionId, TTL channelTtlS
|
|
16
|
+
* chanidx:{agentId}:{type} ZSET externalId scored by lastSeen ms
|
|
17
|
+
* sched:{agentId}:{jobKey} JSON SchedulerJobState, TTL schedulerTtlS
|
|
18
|
+
*/
|
|
19
|
+
export interface RedisStateConfig {
|
|
20
|
+
redisUrl: string;
|
|
21
|
+
agentId: string;
|
|
22
|
+
/** Session record TTL in seconds (default 30 days) */
|
|
23
|
+
sessionTtlS?: number;
|
|
24
|
+
/** Channel mapping TTL in seconds (default 30 days) */
|
|
25
|
+
channelTtlS?: number;
|
|
26
|
+
/** Scheduler job-state TTL in seconds (default 90 days) */
|
|
27
|
+
schedulerTtlS?: number;
|
|
28
|
+
}
|
|
29
|
+
export declare class RedisSessionStore implements SessionStore {
|
|
30
|
+
private redis;
|
|
31
|
+
private agentId;
|
|
32
|
+
private ttlS;
|
|
33
|
+
constructor(redis: Redis, agentId: string, ttlS?: number);
|
|
34
|
+
private key;
|
|
35
|
+
private indexKey;
|
|
36
|
+
create(session: Session): Promise<void>;
|
|
37
|
+
get(sessionId: string): Promise<Session | null>;
|
|
38
|
+
update(sessionId: string, data: Partial<Session>): Promise<void>;
|
|
39
|
+
list(agentId: string, limit?: number): Promise<Session[]>;
|
|
40
|
+
listActive(agentId: string, limit?: number): Promise<Session[]>;
|
|
41
|
+
private fetchByIndex;
|
|
42
|
+
}
|
|
43
|
+
export declare class RedisChannelSessionStore implements ChannelSessionStore {
|
|
44
|
+
private redis;
|
|
45
|
+
private agentId;
|
|
46
|
+
private ttlS;
|
|
47
|
+
constructor(redis: Redis, agentId: string, ttlS?: number);
|
|
48
|
+
private key;
|
|
49
|
+
private indexKey;
|
|
50
|
+
resolve(channelType: string, externalId: string): Promise<string>;
|
|
51
|
+
get(channelType: string, externalId: string): Promise<string | null>;
|
|
52
|
+
reset(channelType: string, externalId: string): Promise<void>;
|
|
53
|
+
listExternalIds(channelType: string): Promise<string[]>;
|
|
54
|
+
}
|
|
55
|
+
export declare class RedisSchedulerStateStore implements SchedulerStateStore {
|
|
56
|
+
private redis;
|
|
57
|
+
private agentId;
|
|
58
|
+
private ttlS;
|
|
59
|
+
constructor(redis: Redis, agentId: string, ttlS?: number);
|
|
60
|
+
private key;
|
|
61
|
+
get(jobKey: string): Promise<SchedulerJobState | null>;
|
|
62
|
+
set(jobKey: string, state: SchedulerJobState): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Adapts ioredis to the client interface core's RedisLockProvider expects
|
|
66
|
+
* (node-redis v4 style `set(key, value, { NX, PX })`).
|
|
67
|
+
*/
|
|
68
|
+
export declare class IoredisLockClient {
|
|
69
|
+
private redis;
|
|
70
|
+
constructor(redis: Redis);
|
|
71
|
+
set(key: string, value: string, options: {
|
|
72
|
+
NX: boolean;
|
|
73
|
+
PX: number;
|
|
74
|
+
}): Promise<string | null>;
|
|
75
|
+
eval(script: string, numkeys: number, ...args: string[]): Promise<unknown>;
|
|
76
|
+
}
|
|
77
|
+
export interface RedisStateStores {
|
|
78
|
+
sessionStore: RedisSessionStore;
|
|
79
|
+
channelSessions: RedisChannelSessionStore;
|
|
80
|
+
schedulerState: RedisSchedulerStateStore;
|
|
81
|
+
lockClient: IoredisLockClient;
|
|
82
|
+
/** Connect + ping. The agent races this against a boot timeout. */
|
|
83
|
+
start(agentId?: string): Promise<void>;
|
|
84
|
+
stop(): Promise<void>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Create the full set of Redis-backed state stores sharing one lazy
|
|
88
|
+
* connection. Wired by bootstrap into AgentResources.state.
|
|
89
|
+
*/
|
|
90
|
+
export declare function createRedisStateStores(config: RedisStateConfig): RedisStateStores;
|
|
91
|
+
//# sourceMappingURL=redis-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-state.d.ts","sourceRoot":"","sources":["../src/redis-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Redis } from 'ioredis';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
const DAY_S = 86_400;
|
|
4
|
+
/** Revive Date fields lost in the JSON round-trip. */
|
|
5
|
+
function reviveSession(raw) {
|
|
6
|
+
const parsed = JSON.parse(raw);
|
|
7
|
+
return {
|
|
8
|
+
...parsed,
|
|
9
|
+
startedAt: new Date(parsed.startedAt),
|
|
10
|
+
endedAt: parsed.endedAt ? new Date(parsed.endedAt) : undefined,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export class RedisSessionStore {
|
|
14
|
+
redis;
|
|
15
|
+
agentId;
|
|
16
|
+
ttlS;
|
|
17
|
+
constructor(redis, agentId, ttlS = 30 * DAY_S) {
|
|
18
|
+
this.redis = redis;
|
|
19
|
+
this.agentId = agentId;
|
|
20
|
+
this.ttlS = ttlS;
|
|
21
|
+
}
|
|
22
|
+
key(sessionId) {
|
|
23
|
+
return `session:${this.agentId}:${sessionId}`;
|
|
24
|
+
}
|
|
25
|
+
indexKey() {
|
|
26
|
+
return `sessions:${this.agentId}`;
|
|
27
|
+
}
|
|
28
|
+
async create(session) {
|
|
29
|
+
await this.redis.set(this.key(session.id), JSON.stringify(session), 'EX', this.ttlS);
|
|
30
|
+
await this.redis.zadd(this.indexKey(), session.startedAt.getTime(), session.id);
|
|
31
|
+
// Lazily prune index entries whose session records have expired
|
|
32
|
+
await this.redis.zremrangebyscore(this.indexKey(), 0, Date.now() - this.ttlS * 1000);
|
|
33
|
+
}
|
|
34
|
+
async get(sessionId) {
|
|
35
|
+
const raw = await this.redis.get(this.key(sessionId));
|
|
36
|
+
return raw ? reviveSession(raw) : null;
|
|
37
|
+
}
|
|
38
|
+
async update(sessionId, data) {
|
|
39
|
+
const existing = await this.get(sessionId);
|
|
40
|
+
if (!existing)
|
|
41
|
+
return;
|
|
42
|
+
const updated = { ...existing, ...data };
|
|
43
|
+
await this.redis.set(this.key(sessionId), JSON.stringify(updated), 'EX', this.ttlS);
|
|
44
|
+
}
|
|
45
|
+
async list(agentId, limit = 50) {
|
|
46
|
+
return this.fetchByIndex(agentId, limit, () => true);
|
|
47
|
+
}
|
|
48
|
+
async listActive(agentId, limit = 50) {
|
|
49
|
+
return this.fetchByIndex(agentId, limit, (s) => !s.endedAt);
|
|
50
|
+
}
|
|
51
|
+
async fetchByIndex(_agentId, limit, keep) {
|
|
52
|
+
// Over-fetch: some index entries may be expired or filtered out
|
|
53
|
+
const ids = await this.redis.zrevrange(this.indexKey(), 0, limit * 2 - 1);
|
|
54
|
+
if (ids.length === 0)
|
|
55
|
+
return [];
|
|
56
|
+
const raws = await this.redis.mget(ids.map((id) => this.key(id)));
|
|
57
|
+
const sessions = [];
|
|
58
|
+
for (const raw of raws) {
|
|
59
|
+
if (!raw)
|
|
60
|
+
continue;
|
|
61
|
+
const session = reviveSession(raw);
|
|
62
|
+
if (keep(session))
|
|
63
|
+
sessions.push(session);
|
|
64
|
+
if (sessions.length >= limit)
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
return sessions;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export class RedisChannelSessionStore {
|
|
71
|
+
redis;
|
|
72
|
+
agentId;
|
|
73
|
+
ttlS;
|
|
74
|
+
constructor(redis, agentId, ttlS = 30 * DAY_S) {
|
|
75
|
+
this.redis = redis;
|
|
76
|
+
this.agentId = agentId;
|
|
77
|
+
this.ttlS = ttlS;
|
|
78
|
+
}
|
|
79
|
+
key(channelType, externalId) {
|
|
80
|
+
return `chan:${this.agentId}:${channelType}:${externalId}`;
|
|
81
|
+
}
|
|
82
|
+
indexKey(channelType) {
|
|
83
|
+
return `chanidx:${this.agentId}:${channelType}`;
|
|
84
|
+
}
|
|
85
|
+
async resolve(channelType, externalId) {
|
|
86
|
+
const key = this.key(channelType, externalId);
|
|
87
|
+
const candidate = randomUUID();
|
|
88
|
+
// Race-safe create: only one concurrent resolve wins the SET NX;
|
|
89
|
+
// losers read the winner's value.
|
|
90
|
+
const won = await this.redis.set(key, candidate, 'EX', this.ttlS, 'NX');
|
|
91
|
+
let sessionId;
|
|
92
|
+
if (won) {
|
|
93
|
+
sessionId = candidate;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
const existing = await this.redis.get(key);
|
|
97
|
+
// Mapping may expire between SET NX and GET — retry the create once
|
|
98
|
+
sessionId = existing ?? (await this.resolve(channelType, externalId));
|
|
99
|
+
await this.redis.expire(key, this.ttlS);
|
|
100
|
+
}
|
|
101
|
+
const indexKey = this.indexKey(channelType);
|
|
102
|
+
await this.redis.zadd(indexKey, Date.now(), externalId);
|
|
103
|
+
await this.redis.expire(indexKey, this.ttlS);
|
|
104
|
+
await this.redis.zremrangebyscore(indexKey, 0, Date.now() - this.ttlS * 1000);
|
|
105
|
+
return sessionId;
|
|
106
|
+
}
|
|
107
|
+
async get(channelType, externalId) {
|
|
108
|
+
return this.redis.get(this.key(channelType, externalId));
|
|
109
|
+
}
|
|
110
|
+
async reset(channelType, externalId) {
|
|
111
|
+
await this.redis.del(this.key(channelType, externalId));
|
|
112
|
+
}
|
|
113
|
+
async listExternalIds(channelType) {
|
|
114
|
+
return this.redis.zrevrange(this.indexKey(channelType), 0, -1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export class RedisSchedulerStateStore {
|
|
118
|
+
redis;
|
|
119
|
+
agentId;
|
|
120
|
+
ttlS;
|
|
121
|
+
constructor(redis, agentId, ttlS = 90 * DAY_S) {
|
|
122
|
+
this.redis = redis;
|
|
123
|
+
this.agentId = agentId;
|
|
124
|
+
this.ttlS = ttlS;
|
|
125
|
+
}
|
|
126
|
+
key(jobKey) {
|
|
127
|
+
return `sched:${this.agentId}:${jobKey}`;
|
|
128
|
+
}
|
|
129
|
+
async get(jobKey) {
|
|
130
|
+
const raw = await this.redis.get(this.key(jobKey));
|
|
131
|
+
return raw ? JSON.parse(raw) : null;
|
|
132
|
+
}
|
|
133
|
+
async set(jobKey, state) {
|
|
134
|
+
await this.redis.set(this.key(jobKey), JSON.stringify(state), 'EX', this.ttlS);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Adapts ioredis to the client interface core's RedisLockProvider expects
|
|
139
|
+
* (node-redis v4 style `set(key, value, { NX, PX })`).
|
|
140
|
+
*/
|
|
141
|
+
export class IoredisLockClient {
|
|
142
|
+
redis;
|
|
143
|
+
constructor(redis) {
|
|
144
|
+
this.redis = redis;
|
|
145
|
+
}
|
|
146
|
+
async set(key, value, options) {
|
|
147
|
+
return this.redis.set(key, value, 'PX', options.PX, 'NX');
|
|
148
|
+
}
|
|
149
|
+
async eval(script, numkeys, ...args) {
|
|
150
|
+
return this.redis.eval(script, numkeys, ...args);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Create the full set of Redis-backed state stores sharing one lazy
|
|
155
|
+
* connection. Wired by bootstrap into AgentResources.state.
|
|
156
|
+
*/
|
|
157
|
+
export function createRedisStateStores(config) {
|
|
158
|
+
const redis = new Redis(config.redisUrl, {
|
|
159
|
+
lazyConnect: true,
|
|
160
|
+
maxRetriesPerRequest: 2,
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
sessionStore: new RedisSessionStore(redis, config.agentId, config.sessionTtlS),
|
|
164
|
+
channelSessions: new RedisChannelSessionStore(redis, config.agentId, config.channelTtlS),
|
|
165
|
+
schedulerState: new RedisSchedulerStateStore(redis, config.agentId, config.schedulerTtlS),
|
|
166
|
+
lockClient: new IoredisLockClient(redis),
|
|
167
|
+
async start() {
|
|
168
|
+
await redis.connect();
|
|
169
|
+
await redis.ping();
|
|
170
|
+
},
|
|
171
|
+
async stop() {
|
|
172
|
+
redis.disconnect();
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=redis-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-state.js","sourceRoot":"","sources":["../src/redis-state.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mce-bt/microagents-memory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "3-tier memory system — STM (Redis), MTM (Postgres), LTM (Postgres + pgvector)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"@types/pg": "^8.11.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"@mce-bt/microagents-observability": "
|
|
30
|
-
"@mce-bt/microagents-completion": "
|
|
29
|
+
"@mce-bt/microagents-observability": ">=0.1.2 <1.0.0",
|
|
30
|
+
"@mce-bt/microagents-completion": ">=0.1.2 <1.0.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependenciesMeta": {
|
|
33
33
|
"@mce-bt/microagents-observability": {
|