@almadar/agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +72 -0
- package/dist/agent/index.d.ts +250 -0
- package/dist/agent/index.js +6038 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/api-types-BW_58thJ.d.ts +557 -0
- package/dist/event-transformer/index.d.ts +125 -0
- package/dist/event-transformer/index.js +350 -0
- package/dist/event-transformer/index.js.map +1 -0
- package/dist/firestore-checkpointer-DxbQ10ve.d.ts +184 -0
- package/dist/index.d.ts +742 -0
- package/dist/index.js +9392 -0
- package/dist/index.js.map +1 -0
- package/dist/orbital-subagent-BsQBhKzi.d.ts +1424 -0
- package/dist/persistence/index.d.ts +201 -0
- package/dist/persistence/index.js +489 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/prompts/index.d.ts +23 -0
- package/dist/prompts/index.js +126 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/tools/index.d.ts +2143 -0
- package/dist/tools/index.js +5783 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types.d.ts +170 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +102 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { d as SessionMetadata, e as SessionRecord, b as FirestoreDb, S as Session } from '../firestore-checkpointer-DxbQ10ve.js';
|
|
2
|
+
export { F as FirestoreCheckpointer, a as FirestoreCheckpointerOptions, c as FirestoreTimestamp, P as PersistenceMode } from '../firestore-checkpointer-DxbQ10ve.js';
|
|
3
|
+
import { BaseStore, Operation, OperationResults } from '@langchain/langgraph-checkpoint';
|
|
4
|
+
import '@langchain/core/runnables';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* In-Memory Persistence Backend
|
|
8
|
+
*
|
|
9
|
+
* Provides in-memory session metadata storage for development.
|
|
10
|
+
* Data is lost on process restart.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* In-memory session metadata store.
|
|
15
|
+
*/
|
|
16
|
+
declare class MemorySessionBackend {
|
|
17
|
+
private sessions;
|
|
18
|
+
/**
|
|
19
|
+
* Store session metadata.
|
|
20
|
+
*/
|
|
21
|
+
store(threadId: string, metadata: SessionMetadata): void;
|
|
22
|
+
/**
|
|
23
|
+
* Get session metadata.
|
|
24
|
+
*/
|
|
25
|
+
get(threadId: string): SessionMetadata | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Delete session metadata.
|
|
28
|
+
*/
|
|
29
|
+
delete(threadId: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* List all sessions.
|
|
32
|
+
*/
|
|
33
|
+
list(): SessionRecord[];
|
|
34
|
+
/**
|
|
35
|
+
* Check if a session exists.
|
|
36
|
+
*/
|
|
37
|
+
has(threadId: string): boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Firestore Session Store for DeepAgent
|
|
42
|
+
*
|
|
43
|
+
* Provides persistent session storage for skill-based agents.
|
|
44
|
+
* Sessions are stored in Firestore and persist across server restarts.
|
|
45
|
+
*
|
|
46
|
+
* IMPORTANT: This module does NOT import firebase-admin directly.
|
|
47
|
+
* The Firestore `db` instance must be injected via constructor options.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Options for FirestoreSessionStore.
|
|
52
|
+
*/
|
|
53
|
+
interface FirestoreSessionStoreOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Firestore instance. Required — injected by consumer.
|
|
56
|
+
*/
|
|
57
|
+
db: FirestoreDb;
|
|
58
|
+
/**
|
|
59
|
+
* Collection name for sessions.
|
|
60
|
+
* @default 'agent_sessions'
|
|
61
|
+
*/
|
|
62
|
+
collection?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Firestore-backed session store for skill agents.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const sessionStore = new FirestoreSessionStore({ db: getFirestore() });
|
|
70
|
+
*
|
|
71
|
+
* await sessionStore.save({
|
|
72
|
+
* threadId: 'abc-123',
|
|
73
|
+
* skill: 'kflow-generating-m',
|
|
74
|
+
* workDir: '/tmp/workspace',
|
|
75
|
+
* createdAt: new Date(),
|
|
76
|
+
* lastActivityAt: new Date(),
|
|
77
|
+
* });
|
|
78
|
+
*
|
|
79
|
+
* const session = await sessionStore.get('abc-123');
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare class FirestoreSessionStore {
|
|
83
|
+
private db;
|
|
84
|
+
private collection;
|
|
85
|
+
constructor(options: FirestoreSessionStoreOptions);
|
|
86
|
+
/**
|
|
87
|
+
* Save a session.
|
|
88
|
+
*/
|
|
89
|
+
save(session: Session): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Get a session by thread ID.
|
|
92
|
+
*/
|
|
93
|
+
get(threadId: string): Promise<Session | null>;
|
|
94
|
+
/**
|
|
95
|
+
* Update session's last activity timestamp.
|
|
96
|
+
*/
|
|
97
|
+
touch(threadId: string): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Delete a session.
|
|
100
|
+
*/
|
|
101
|
+
delete(threadId: string): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* List sessions, optionally filtered by user ID.
|
|
104
|
+
*/
|
|
105
|
+
list(options?: {
|
|
106
|
+
userId?: string;
|
|
107
|
+
limit?: number;
|
|
108
|
+
}): Promise<Session[]>;
|
|
109
|
+
/**
|
|
110
|
+
* Delete expired sessions (older than specified hours).
|
|
111
|
+
*/
|
|
112
|
+
deleteExpired(maxAgeHours?: number): Promise<number>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Firestore Store for LangGraph
|
|
117
|
+
*
|
|
118
|
+
* Custom implementation of BaseStore using Firebase Firestore.
|
|
119
|
+
* This provides persistent key-value storage for agent memories.
|
|
120
|
+
*
|
|
121
|
+
* IMPORTANT: This module does NOT import firebase-admin directly.
|
|
122
|
+
* The Firestore `db` instance must be injected via constructor options.
|
|
123
|
+
*/
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Options for FirestoreStore.
|
|
127
|
+
*/
|
|
128
|
+
interface FirestoreStoreOptions {
|
|
129
|
+
/**
|
|
130
|
+
* Firestore instance. Required — injected by consumer.
|
|
131
|
+
*/
|
|
132
|
+
db: FirestoreDb;
|
|
133
|
+
/**
|
|
134
|
+
* Collection name for store items.
|
|
135
|
+
* @default 'agent_memories'
|
|
136
|
+
*/
|
|
137
|
+
collection?: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Firestore-backed store for LangGraph agent memories.
|
|
141
|
+
*
|
|
142
|
+
* Provides persistent key-value storage that can be shared across threads.
|
|
143
|
+
* Items are organized by hierarchical namespaces.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* import { getFirestore } from 'firebase-admin/firestore';
|
|
148
|
+
*
|
|
149
|
+
* const store = new FirestoreStore({
|
|
150
|
+
* db: getFirestore(),
|
|
151
|
+
* collection: 'agent_memories',
|
|
152
|
+
* });
|
|
153
|
+
*
|
|
154
|
+
* // Store a memory
|
|
155
|
+
* await store.put(['agent', 'patterns'], 'schema-best-practices', {
|
|
156
|
+
* content: 'Always validate schemas before saving',
|
|
157
|
+
* });
|
|
158
|
+
*
|
|
159
|
+
* // Retrieve a memory
|
|
160
|
+
* const item = await store.get(['agent', 'patterns'], 'schema-best-practices');
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
declare class FirestoreStore extends BaseStore {
|
|
164
|
+
private db;
|
|
165
|
+
private collection;
|
|
166
|
+
constructor(options: FirestoreStoreOptions);
|
|
167
|
+
/**
|
|
168
|
+
* Create document ID from namespace and key.
|
|
169
|
+
*/
|
|
170
|
+
private makeDocId;
|
|
171
|
+
/**
|
|
172
|
+
* Create namespace key for querying.
|
|
173
|
+
*/
|
|
174
|
+
private makeNamespaceKey;
|
|
175
|
+
/**
|
|
176
|
+
* Execute multiple operations in a batch.
|
|
177
|
+
*/
|
|
178
|
+
batch<Op extends Operation[]>(operations: Op): Promise<OperationResults<Op>>;
|
|
179
|
+
/**
|
|
180
|
+
* Get an item by namespace and key.
|
|
181
|
+
*/
|
|
182
|
+
private getItem;
|
|
183
|
+
/**
|
|
184
|
+
* Put an item.
|
|
185
|
+
*/
|
|
186
|
+
private putItem;
|
|
187
|
+
/**
|
|
188
|
+
* Delete an item.
|
|
189
|
+
*/
|
|
190
|
+
private deleteItem;
|
|
191
|
+
/**
|
|
192
|
+
* Search for items.
|
|
193
|
+
*/
|
|
194
|
+
private searchItems;
|
|
195
|
+
/**
|
|
196
|
+
* List namespaces.
|
|
197
|
+
*/
|
|
198
|
+
private listNamespacesItems;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export { FirestoreDb, FirestoreSessionStore, type FirestoreSessionStoreOptions, FirestoreStore, type FirestoreStoreOptions, MemorySessionBackend, Session, SessionMetadata, SessionRecord };
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import { BaseCheckpointSaver, BaseStore } from '@langchain/langgraph-checkpoint';
|
|
2
|
+
|
|
3
|
+
// src/persistence/memory-backend.ts
|
|
4
|
+
var MemorySessionBackend = class {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.sessions = /* @__PURE__ */ new Map();
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Store session metadata.
|
|
10
|
+
*/
|
|
11
|
+
store(threadId, metadata) {
|
|
12
|
+
this.sessions.set(threadId, metadata);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get session metadata.
|
|
16
|
+
*/
|
|
17
|
+
get(threadId) {
|
|
18
|
+
return this.sessions.get(threadId);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Delete session metadata.
|
|
22
|
+
*/
|
|
23
|
+
delete(threadId) {
|
|
24
|
+
return this.sessions.delete(threadId);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* List all sessions.
|
|
28
|
+
*/
|
|
29
|
+
list() {
|
|
30
|
+
return Array.from(this.sessions.entries()).map(([threadId, meta]) => ({
|
|
31
|
+
threadId,
|
|
32
|
+
...meta
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if a session exists.
|
|
37
|
+
*/
|
|
38
|
+
has(threadId) {
|
|
39
|
+
return this.sessions.has(threadId);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var FirestoreCheckpointer = class extends BaseCheckpointSaver {
|
|
43
|
+
constructor(options) {
|
|
44
|
+
super();
|
|
45
|
+
this.db = options.db;
|
|
46
|
+
this.checkpointsCollection = options.checkpointsCollection ?? "agent_checkpoints";
|
|
47
|
+
this.writesCollection = options.writesCollection ?? "agent_writes";
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get thread ID from config.
|
|
51
|
+
*/
|
|
52
|
+
getThreadId(config) {
|
|
53
|
+
const threadId = config.configurable?.thread_id;
|
|
54
|
+
if (!threadId || typeof threadId !== "string") {
|
|
55
|
+
throw new Error("thread_id is required in config.configurable");
|
|
56
|
+
}
|
|
57
|
+
return threadId;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get checkpoint ID from config, or undefined for latest.
|
|
61
|
+
*/
|
|
62
|
+
getCheckpointId(config) {
|
|
63
|
+
return config.configurable?.checkpoint_id;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get checkpoint by config.
|
|
67
|
+
*/
|
|
68
|
+
async getTuple(config) {
|
|
69
|
+
const threadId = this.getThreadId(config);
|
|
70
|
+
const checkpointId = this.getCheckpointId(config);
|
|
71
|
+
let query = this.db.collection(this.checkpointsCollection).where("threadId", "==", threadId);
|
|
72
|
+
if (checkpointId) {
|
|
73
|
+
query = query.where("checkpointId", "==", checkpointId);
|
|
74
|
+
} else {
|
|
75
|
+
query = query.orderBy("createdAt", "desc").limit(1);
|
|
76
|
+
}
|
|
77
|
+
const snapshot = await query.get();
|
|
78
|
+
if (snapshot.empty) {
|
|
79
|
+
return void 0;
|
|
80
|
+
}
|
|
81
|
+
const doc = snapshot.docs[0];
|
|
82
|
+
const data = doc.data();
|
|
83
|
+
const writesSnapshot = await this.db.collection(this.writesCollection).where("threadId", "==", threadId).where("checkpointId", "==", data.checkpointId).get();
|
|
84
|
+
const pendingWrites = writesSnapshot.docs.map((writeDoc) => {
|
|
85
|
+
const writeData = writeDoc.data();
|
|
86
|
+
return [writeData.taskId, writeData.channel, writeData.value];
|
|
87
|
+
});
|
|
88
|
+
const parentConfig = data.parentCheckpointId ? {
|
|
89
|
+
configurable: {
|
|
90
|
+
thread_id: threadId,
|
|
91
|
+
checkpoint_id: data.parentCheckpointId
|
|
92
|
+
}
|
|
93
|
+
} : void 0;
|
|
94
|
+
return {
|
|
95
|
+
config: {
|
|
96
|
+
configurable: {
|
|
97
|
+
thread_id: threadId,
|
|
98
|
+
checkpoint_id: data.checkpointId
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
checkpoint: data.checkpoint,
|
|
102
|
+
metadata: data.metadata,
|
|
103
|
+
parentConfig,
|
|
104
|
+
pendingWrites
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* List checkpoints for a thread.
|
|
109
|
+
*/
|
|
110
|
+
async *list(config, options) {
|
|
111
|
+
const threadId = this.getThreadId(config);
|
|
112
|
+
const limit = options?.limit ?? 10;
|
|
113
|
+
let query = this.db.collection(this.checkpointsCollection).where("threadId", "==", threadId).orderBy("createdAt", "desc").limit(limit);
|
|
114
|
+
if (options?.filter) {
|
|
115
|
+
for (const [key, value] of Object.entries(options.filter)) {
|
|
116
|
+
query = query.where(`metadata.${key}`, "==", value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (options?.before?.configurable?.checkpoint_id) {
|
|
120
|
+
const beforeDoc = await this.db.collection(this.checkpointsCollection).where("threadId", "==", threadId).where("checkpointId", "==", options.before.configurable.checkpoint_id).get();
|
|
121
|
+
if (!beforeDoc.empty) {
|
|
122
|
+
query = query.startAfter(beforeDoc.docs[0]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const snapshot = await query.get();
|
|
126
|
+
for (const doc of snapshot.docs) {
|
|
127
|
+
const data = doc.data();
|
|
128
|
+
const parentConfig = data.parentCheckpointId ? {
|
|
129
|
+
configurable: {
|
|
130
|
+
thread_id: threadId,
|
|
131
|
+
checkpoint_id: data.parentCheckpointId
|
|
132
|
+
}
|
|
133
|
+
} : void 0;
|
|
134
|
+
yield {
|
|
135
|
+
config: {
|
|
136
|
+
configurable: {
|
|
137
|
+
thread_id: threadId,
|
|
138
|
+
checkpoint_id: data.checkpointId
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
checkpoint: data.checkpoint,
|
|
142
|
+
metadata: data.metadata,
|
|
143
|
+
parentConfig
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Save a checkpoint.
|
|
149
|
+
*/
|
|
150
|
+
async put(config, checkpoint, metadata, _newVersions) {
|
|
151
|
+
const threadId = this.getThreadId(config);
|
|
152
|
+
const checkpointId = checkpoint.id;
|
|
153
|
+
const parentCheckpointId = this.getCheckpointId(config);
|
|
154
|
+
const now = /* @__PURE__ */ new Date();
|
|
155
|
+
const docData = {
|
|
156
|
+
threadId,
|
|
157
|
+
checkpointId,
|
|
158
|
+
parentCheckpointId,
|
|
159
|
+
checkpoint,
|
|
160
|
+
metadata,
|
|
161
|
+
createdAt: now,
|
|
162
|
+
updatedAt: now
|
|
163
|
+
};
|
|
164
|
+
const docId = `${threadId}_${checkpointId}`;
|
|
165
|
+
await this.db.collection(this.checkpointsCollection).doc(docId).set(docData);
|
|
166
|
+
return {
|
|
167
|
+
configurable: {
|
|
168
|
+
thread_id: threadId,
|
|
169
|
+
checkpoint_id: checkpointId
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Store pending writes for a checkpoint.
|
|
175
|
+
*/
|
|
176
|
+
async putWrites(config, writes, taskId) {
|
|
177
|
+
const threadId = this.getThreadId(config);
|
|
178
|
+
const checkpointId = this.getCheckpointId(config);
|
|
179
|
+
if (!checkpointId) {
|
|
180
|
+
throw new Error("checkpoint_id is required for putWrites");
|
|
181
|
+
}
|
|
182
|
+
const batch = this.db.batch();
|
|
183
|
+
const now = /* @__PURE__ */ new Date();
|
|
184
|
+
for (const [idx, [channel, value]] of writes.entries()) {
|
|
185
|
+
const docId = `${threadId}_${checkpointId}_${taskId}_${idx}`;
|
|
186
|
+
const docRef = this.db.collection(this.writesCollection).doc(docId);
|
|
187
|
+
const writeData = {
|
|
188
|
+
threadId,
|
|
189
|
+
checkpointId,
|
|
190
|
+
taskId,
|
|
191
|
+
channel,
|
|
192
|
+
value,
|
|
193
|
+
createdAt: now
|
|
194
|
+
};
|
|
195
|
+
batch.set(docRef, writeData);
|
|
196
|
+
}
|
|
197
|
+
await batch.commit();
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Delete all checkpoints and writes for a thread.
|
|
201
|
+
*/
|
|
202
|
+
async deleteThread(threadId) {
|
|
203
|
+
const checkpointsSnapshot = await this.db.collection(this.checkpointsCollection).where("threadId", "==", threadId).get();
|
|
204
|
+
const checkpointBatch = this.db.batch();
|
|
205
|
+
for (const doc of checkpointsSnapshot.docs) {
|
|
206
|
+
checkpointBatch.delete(doc.ref);
|
|
207
|
+
}
|
|
208
|
+
await checkpointBatch.commit();
|
|
209
|
+
const writesSnapshot = await this.db.collection(this.writesCollection).where("threadId", "==", threadId).get();
|
|
210
|
+
const writesBatch = this.db.batch();
|
|
211
|
+
for (const doc of writesSnapshot.docs) {
|
|
212
|
+
writesBatch.delete(doc.ref);
|
|
213
|
+
}
|
|
214
|
+
await writesBatch.commit();
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// src/persistence/firestore-session-store.ts
|
|
219
|
+
var FirestoreSessionStore = class {
|
|
220
|
+
constructor(options) {
|
|
221
|
+
this.db = options.db;
|
|
222
|
+
this.collection = options.collection ?? "agent_sessions";
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Save a session.
|
|
226
|
+
*/
|
|
227
|
+
async save(session) {
|
|
228
|
+
const now = /* @__PURE__ */ new Date();
|
|
229
|
+
const docData = {
|
|
230
|
+
threadId: session.threadId,
|
|
231
|
+
skill: session.skill,
|
|
232
|
+
workDir: session.workDir,
|
|
233
|
+
userId: session.userId,
|
|
234
|
+
createdAt: session.createdAt,
|
|
235
|
+
lastActivityAt: now
|
|
236
|
+
};
|
|
237
|
+
await this.db.collection(this.collection).doc(session.threadId).set(docData);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get a session by thread ID.
|
|
241
|
+
*/
|
|
242
|
+
async get(threadId) {
|
|
243
|
+
const doc = await this.db.collection(this.collection).doc(threadId).get();
|
|
244
|
+
if (!doc.exists) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
const data = doc.data();
|
|
248
|
+
return {
|
|
249
|
+
threadId: data.threadId,
|
|
250
|
+
skill: data.skill,
|
|
251
|
+
workDir: data.workDir,
|
|
252
|
+
userId: data.userId,
|
|
253
|
+
createdAt: data.createdAt?.toDate?.() ?? new Date(data.createdAt),
|
|
254
|
+
lastActivityAt: data.lastActivityAt?.toDate?.() ?? new Date(data.lastActivityAt)
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Update session's last activity timestamp.
|
|
259
|
+
*/
|
|
260
|
+
async touch(threadId) {
|
|
261
|
+
await this.db.collection(this.collection).doc(threadId).update({
|
|
262
|
+
lastActivityAt: /* @__PURE__ */ new Date()
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Delete a session.
|
|
267
|
+
*/
|
|
268
|
+
async delete(threadId) {
|
|
269
|
+
await this.db.collection(this.collection).doc(threadId).delete();
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* List sessions, optionally filtered by user ID.
|
|
273
|
+
*/
|
|
274
|
+
async list(options) {
|
|
275
|
+
let query = this.db.collection(this.collection).orderBy("lastActivityAt", "desc");
|
|
276
|
+
if (options?.userId) {
|
|
277
|
+
query = query.where("userId", "==", options.userId);
|
|
278
|
+
}
|
|
279
|
+
const limit = options?.limit ?? 100;
|
|
280
|
+
query = query.limit(limit);
|
|
281
|
+
const snapshot = await query.get();
|
|
282
|
+
return snapshot.docs.map((doc) => {
|
|
283
|
+
const data = doc.data();
|
|
284
|
+
return {
|
|
285
|
+
threadId: data.threadId,
|
|
286
|
+
skill: data.skill,
|
|
287
|
+
workDir: data.workDir,
|
|
288
|
+
userId: data.userId,
|
|
289
|
+
createdAt: data.createdAt?.toDate?.() ?? new Date(data.createdAt),
|
|
290
|
+
lastActivityAt: data.lastActivityAt?.toDate?.() ?? new Date(data.lastActivityAt)
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Delete expired sessions (older than specified hours).
|
|
296
|
+
*/
|
|
297
|
+
async deleteExpired(maxAgeHours = 24) {
|
|
298
|
+
const cutoff = new Date(Date.now() - maxAgeHours * 60 * 60 * 1e3);
|
|
299
|
+
const snapshot = await this.db.collection(this.collection).where("lastActivityAt", "<", cutoff).get();
|
|
300
|
+
const batch = this.db.batch();
|
|
301
|
+
for (const doc of snapshot.docs) {
|
|
302
|
+
batch.delete(doc.ref);
|
|
303
|
+
}
|
|
304
|
+
await batch.commit();
|
|
305
|
+
return snapshot.size;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
var FirestoreStore = class extends BaseStore {
|
|
309
|
+
constructor(options) {
|
|
310
|
+
super();
|
|
311
|
+
this.db = options.db;
|
|
312
|
+
this.collection = options.collection ?? "agent_memories";
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Create document ID from namespace and key.
|
|
316
|
+
*/
|
|
317
|
+
makeDocId(namespace, key) {
|
|
318
|
+
return [...namespace, key].join("/");
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Create namespace key for querying.
|
|
322
|
+
*/
|
|
323
|
+
makeNamespaceKey(namespace) {
|
|
324
|
+
return namespace.join("/");
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Execute multiple operations in a batch.
|
|
328
|
+
*/
|
|
329
|
+
async batch(operations) {
|
|
330
|
+
const results = [];
|
|
331
|
+
for (const op of operations) {
|
|
332
|
+
if ("key" in op && "namespace" in op && !("namespacePrefix" in op)) {
|
|
333
|
+
if ("value" in op) {
|
|
334
|
+
const putOp = op;
|
|
335
|
+
if (putOp.value === null) {
|
|
336
|
+
await this.deleteItem(putOp.namespace, putOp.key);
|
|
337
|
+
} else {
|
|
338
|
+
await this.putItem(putOp.namespace, putOp.key, putOp.value);
|
|
339
|
+
}
|
|
340
|
+
results.push(void 0);
|
|
341
|
+
} else {
|
|
342
|
+
const getOp = op;
|
|
343
|
+
const item = await this.getItem(getOp.namespace, getOp.key);
|
|
344
|
+
results.push(item);
|
|
345
|
+
}
|
|
346
|
+
} else if ("namespacePrefix" in op) {
|
|
347
|
+
const searchOp = op;
|
|
348
|
+
const items = await this.searchItems(searchOp);
|
|
349
|
+
results.push(items);
|
|
350
|
+
} else if ("matchConditions" in op || "limit" in op && "offset" in op && !("namespacePrefix" in op)) {
|
|
351
|
+
const listOp = op;
|
|
352
|
+
const namespaces = await this.listNamespacesItems(listOp);
|
|
353
|
+
results.push(namespaces);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return results;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Get an item by namespace and key.
|
|
360
|
+
*/
|
|
361
|
+
async getItem(namespace, key) {
|
|
362
|
+
const docId = this.makeDocId(namespace, key);
|
|
363
|
+
const doc = await this.db.collection(this.collection).doc(docId).get();
|
|
364
|
+
if (!doc.exists) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
const data = doc.data();
|
|
368
|
+
return {
|
|
369
|
+
namespace: data.namespace,
|
|
370
|
+
key: data.key,
|
|
371
|
+
value: data.value,
|
|
372
|
+
createdAt: data.createdAt?.toDate?.() ?? new Date(data.createdAt),
|
|
373
|
+
updatedAt: data.updatedAt?.toDate?.() ?? new Date(data.updatedAt)
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Put an item.
|
|
378
|
+
*/
|
|
379
|
+
async putItem(namespace, key, value) {
|
|
380
|
+
const docId = this.makeDocId(namespace, key);
|
|
381
|
+
const now = /* @__PURE__ */ new Date();
|
|
382
|
+
const existingDoc = await this.db.collection(this.collection).doc(docId).get();
|
|
383
|
+
const createdAt = existingDoc.exists ? existingDoc.data().createdAt : now;
|
|
384
|
+
const docData = {
|
|
385
|
+
namespace,
|
|
386
|
+
namespaceKey: this.makeNamespaceKey(namespace),
|
|
387
|
+
key,
|
|
388
|
+
value,
|
|
389
|
+
createdAt,
|
|
390
|
+
updatedAt: now
|
|
391
|
+
};
|
|
392
|
+
await this.db.collection(this.collection).doc(docId).set(docData);
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Delete an item.
|
|
396
|
+
*/
|
|
397
|
+
async deleteItem(namespace, key) {
|
|
398
|
+
const docId = this.makeDocId(namespace, key);
|
|
399
|
+
await this.db.collection(this.collection).doc(docId).delete();
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Search for items.
|
|
403
|
+
*/
|
|
404
|
+
async searchItems(op) {
|
|
405
|
+
const namespacePrefix = this.makeNamespaceKey(op.namespacePrefix);
|
|
406
|
+
const limit = op.limit ?? 10;
|
|
407
|
+
const offset = op.offset ?? 0;
|
|
408
|
+
let query = this.db.collection(this.collection);
|
|
409
|
+
if (namespacePrefix) {
|
|
410
|
+
query = query.where("namespaceKey", ">=", namespacePrefix).where("namespaceKey", "<", namespacePrefix + "\uFFFF");
|
|
411
|
+
}
|
|
412
|
+
if (op.filter) {
|
|
413
|
+
for (const [key, filterValue] of Object.entries(op.filter)) {
|
|
414
|
+
if (typeof filterValue === "object" && filterValue !== null) {
|
|
415
|
+
for (const [operator, value] of Object.entries(filterValue)) {
|
|
416
|
+
switch (operator) {
|
|
417
|
+
case "$eq":
|
|
418
|
+
query = query.where(`value.${key}`, "==", value);
|
|
419
|
+
break;
|
|
420
|
+
case "$ne":
|
|
421
|
+
query = query.where(`value.${key}`, "!=", value);
|
|
422
|
+
break;
|
|
423
|
+
case "$gt":
|
|
424
|
+
query = query.where(`value.${key}`, ">", value);
|
|
425
|
+
break;
|
|
426
|
+
case "$gte":
|
|
427
|
+
query = query.where(`value.${key}`, ">=", value);
|
|
428
|
+
break;
|
|
429
|
+
case "$lt":
|
|
430
|
+
query = query.where(`value.${key}`, "<", value);
|
|
431
|
+
break;
|
|
432
|
+
case "$lte":
|
|
433
|
+
query = query.where(`value.${key}`, "<=", value);
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
} else {
|
|
438
|
+
query = query.where(`value.${key}`, "==", filterValue);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
query = query.limit(limit + offset);
|
|
443
|
+
const snapshot = await query.get();
|
|
444
|
+
const docs = snapshot.docs.slice(offset);
|
|
445
|
+
return docs.map((doc) => {
|
|
446
|
+
const data = doc.data();
|
|
447
|
+
return {
|
|
448
|
+
namespace: data.namespace,
|
|
449
|
+
key: data.key,
|
|
450
|
+
value: data.value,
|
|
451
|
+
createdAt: data.createdAt?.toDate?.() ?? new Date(data.createdAt),
|
|
452
|
+
updatedAt: data.updatedAt?.toDate?.() ?? new Date(data.updatedAt)
|
|
453
|
+
};
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* List namespaces.
|
|
458
|
+
*/
|
|
459
|
+
async listNamespacesItems(op) {
|
|
460
|
+
const limit = op.limit ?? 10;
|
|
461
|
+
const offset = op.offset ?? 0;
|
|
462
|
+
let query = this.db.collection(this.collection);
|
|
463
|
+
if (op.matchConditions) {
|
|
464
|
+
for (const condition of op.matchConditions) {
|
|
465
|
+
const path = condition.path.filter((p) => p !== "*").join("/");
|
|
466
|
+
if (condition.matchType === "prefix") {
|
|
467
|
+
query = query.where("namespaceKey", ">=", path).where("namespaceKey", "<", path + "\uFFFF");
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
const snapshot = await query.get();
|
|
472
|
+
const namespaceSet = /* @__PURE__ */ new Set();
|
|
473
|
+
for (const doc of snapshot.docs) {
|
|
474
|
+
const data = doc.data();
|
|
475
|
+
const namespace = data.namespace;
|
|
476
|
+
if (op.maxDepth !== void 0 && namespace.length > op.maxDepth) {
|
|
477
|
+
namespaceSet.add(namespace.slice(0, op.maxDepth).join("/"));
|
|
478
|
+
} else {
|
|
479
|
+
namespaceSet.add(namespace.join("/"));
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
const namespaces = Array.from(namespaceSet).map((ns) => ns.split("/")).slice(offset, offset + limit);
|
|
483
|
+
return namespaces;
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
export { FirestoreCheckpointer, FirestoreSessionStore, FirestoreStore, MemorySessionBackend };
|
|
488
|
+
//# sourceMappingURL=index.js.map
|
|
489
|
+
//# sourceMappingURL=index.js.map
|