@ai.ntellect/core 0.4.0 → 0.5.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/README.FR.md +624 -18
- package/README.md +127 -72
- package/agent/index.ts +57 -149
- package/agent/workflow/conditions.ts +16 -0
- package/agent/workflow/handlers/interpreter.handler.ts +48 -0
- package/agent/workflow/handlers/memory.handler.ts +106 -0
- package/agent/workflow/handlers/orchestrator.handler.ts +23 -0
- package/agent/workflow/handlers/queue.handler.ts +34 -0
- package/agent/workflow/handlers/scheduler.handler.ts +61 -0
- package/agent/workflow/index.ts +62 -0
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +3 -3
- package/{agent/tools → examples/actions}/get-rss.ts +8 -1
- package/examples/index.ts +10 -15
- package/index.html +42 -0
- package/llm/dynamic-condition/example.ts +36 -0
- package/llm/dynamic-condition/index.ts +108 -0
- package/llm/interpreter/context.ts +5 -12
- package/llm/interpreter/index.ts +20 -16
- package/llm/memory-manager/context.ts +4 -6
- package/llm/memory-manager/index.ts +32 -80
- package/llm/orchestrator/context.ts +5 -8
- package/llm/orchestrator/index.ts +62 -102
- package/llm/orchestrator/types.ts +2 -2
- package/package.json +3 -1
- package/script.js +167 -0
- package/services/{scheduler.ts → agenda.ts} +20 -35
- package/services/cache.ts +298 -0
- package/services/queue.ts +3 -3
- package/services/workflow.ts +491 -0
- package/t.ts +21 -129
- package/tsconfig.json +2 -1
- package/types.ts +91 -12
- package/utils/generate-object.ts +24 -12
- package/utils/inject-actions.ts +3 -3
- package/utils/state-manager.ts +25 -0
- package/bull.ts +0 -5
- package/services/redis-cache.ts +0 -128
- package/t.spec +0 -38
package/script.js
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
// Dimensions de l'espace SVG
|
2
|
+
const width = 800;
|
3
|
+
const height = 600;
|
4
|
+
|
5
|
+
// Exemple de données pour les nœuds et les arêtes
|
6
|
+
const nodes = [
|
7
|
+
{ id: "fetchData", name: "Fetch Data", group: 1, selected: false },
|
8
|
+
{ id: "analyzeData", name: "Analyze Data", group: 1, selected: false },
|
9
|
+
{ id: "sendAlert", name: "Send Alert", group: 1, selected: false },
|
10
|
+
];
|
11
|
+
|
12
|
+
const links = [
|
13
|
+
{ source: "fetchData", target: "analyzeData" },
|
14
|
+
{ source: "analyzeData", target: "sendAlert" },
|
15
|
+
];
|
16
|
+
|
17
|
+
// Simulation de force
|
18
|
+
const simulation = d3
|
19
|
+
.forceSimulation(nodes)
|
20
|
+
.force(
|
21
|
+
"link",
|
22
|
+
d3.forceLink(links).id((d) => d.id)
|
23
|
+
)
|
24
|
+
.force("charge", d3.forceManyBody().strength(-300))
|
25
|
+
.force("center", d3.forceCenter(width / 2, height / 2));
|
26
|
+
|
27
|
+
// Créer le conteneur SVG
|
28
|
+
const svg = d3.select("#graph").attr("width", width).attr("height", height);
|
29
|
+
|
30
|
+
// Groupes pour liens et nœuds
|
31
|
+
const linkGroup = svg
|
32
|
+
.append("g")
|
33
|
+
.attr("class", "links")
|
34
|
+
.attr("stroke", "#999")
|
35
|
+
.attr("stroke-opacity", 0.6);
|
36
|
+
|
37
|
+
const nodeGroup = svg.append("g").attr("class", "nodes");
|
38
|
+
|
39
|
+
// Fonction pour mettre à jour le graphe
|
40
|
+
function updateGraph() {
|
41
|
+
// Mettre à jour les liens
|
42
|
+
const link = linkGroup.selectAll("line").data(links);
|
43
|
+
|
44
|
+
link
|
45
|
+
.enter()
|
46
|
+
.append("line")
|
47
|
+
.attr("stroke-width", 2)
|
48
|
+
.merge(link)
|
49
|
+
.attr("x1", (d) => d.source.x)
|
50
|
+
.attr("y1", (d) => d.source.y)
|
51
|
+
.attr("x2", (d) => d.target.x)
|
52
|
+
.attr("y2", (d) => d.target.y);
|
53
|
+
|
54
|
+
link.exit().remove();
|
55
|
+
|
56
|
+
// Mettre à jour les nœuds
|
57
|
+
const node = nodeGroup.selectAll("circle").data(nodes, (d) => d.id);
|
58
|
+
|
59
|
+
node.exit().remove();
|
60
|
+
|
61
|
+
const nodeEnter = node
|
62
|
+
.enter()
|
63
|
+
.append("circle")
|
64
|
+
.attr("r", 20)
|
65
|
+
.attr("fill", (d) => (d.selected ? "orange" : "#69b3a2"))
|
66
|
+
.attr("stroke", "#fff")
|
67
|
+
.attr("stroke-width", 1.5)
|
68
|
+
.call(
|
69
|
+
d3
|
70
|
+
.drag()
|
71
|
+
.on("start", dragstarted)
|
72
|
+
.on("drag", dragged)
|
73
|
+
.on("end", dragended)
|
74
|
+
)
|
75
|
+
.on("click", nodeClicked);
|
76
|
+
|
77
|
+
nodeEnter
|
78
|
+
.merge(node)
|
79
|
+
.attr("cx", (d) => d.x)
|
80
|
+
.attr("cy", (d) => d.y)
|
81
|
+
.attr("fill", (d) => (d.selected ? "orange" : "#69b3a2"));
|
82
|
+
|
83
|
+
// Ajouter des labels
|
84
|
+
const label = nodeGroup.selectAll("text").data(nodes);
|
85
|
+
|
86
|
+
label.exit().remove();
|
87
|
+
|
88
|
+
label
|
89
|
+
.enter()
|
90
|
+
.append("text")
|
91
|
+
.attr("dy", 4)
|
92
|
+
.attr("dx", 25)
|
93
|
+
.merge(label)
|
94
|
+
.attr("x", (d) => d.x)
|
95
|
+
.attr("y", (d) => d.y)
|
96
|
+
.text((d) => d.name);
|
97
|
+
|
98
|
+
simulation.on("tick", () => {
|
99
|
+
link
|
100
|
+
.attr("x1", (d) => d.source.x)
|
101
|
+
.attr("y1", (d) => d.source.y)
|
102
|
+
.attr("x2", (d) => d.target.x)
|
103
|
+
.attr("y2", (d) => d.target.y);
|
104
|
+
|
105
|
+
node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
|
106
|
+
|
107
|
+
label.attr("x", (d) => d.x + 25).attr("y", (d) => d.y);
|
108
|
+
});
|
109
|
+
|
110
|
+
updateWorkflowOrder();
|
111
|
+
}
|
112
|
+
|
113
|
+
// Fonction pour mettre à jour l'ordre du workflow
|
114
|
+
function updateWorkflowOrder() {
|
115
|
+
const selectedNodes = nodes.filter((node) => node.selected);
|
116
|
+
if (selectedNodes.length > 0) {
|
117
|
+
workflowOrder = selectedNodes.map((node) => node.name);
|
118
|
+
} else {
|
119
|
+
const startNode = nodes.find(
|
120
|
+
(node) => !links.some((link) => link.target === node.id)
|
121
|
+
);
|
122
|
+
|
123
|
+
if (!startNode) {
|
124
|
+
workflowOrder = [];
|
125
|
+
console.log("Workflow Order: []");
|
126
|
+
return;
|
127
|
+
}
|
128
|
+
|
129
|
+
workflowOrder = [];
|
130
|
+
let currentNode = startNode;
|
131
|
+
while (currentNode) {
|
132
|
+
workflowOrder.push(currentNode.name);
|
133
|
+
const nextLink = links.find((link) => link.source === currentNode.id);
|
134
|
+
currentNode = nextLink
|
135
|
+
? nodes.find((node) => node.id === nextLink.target)
|
136
|
+
: null;
|
137
|
+
}
|
138
|
+
}
|
139
|
+
console.log("Workflow Order:", workflowOrder);
|
140
|
+
}
|
141
|
+
|
142
|
+
// Gestion de la sélection multiple
|
143
|
+
function nodeClicked(event, node) {
|
144
|
+
node.selected = !node.selected;
|
145
|
+
updateGraph();
|
146
|
+
}
|
147
|
+
|
148
|
+
// Gestion du drag & drop
|
149
|
+
function dragstarted(event, d) {
|
150
|
+
if (!event.active) simulation.alphaTarget(0.3).restart();
|
151
|
+
d.fx = d.x;
|
152
|
+
d.fy = d.y;
|
153
|
+
}
|
154
|
+
|
155
|
+
function dragged(event, d) {
|
156
|
+
d.fx = event.x;
|
157
|
+
d.fy = event.y;
|
158
|
+
}
|
159
|
+
|
160
|
+
function dragended(event, d) {
|
161
|
+
if (!event.active) simulation.alphaTarget(0);
|
162
|
+
d.fx = null;
|
163
|
+
d.fy = null;
|
164
|
+
}
|
165
|
+
|
166
|
+
// Initialisation
|
167
|
+
updateGraph();
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import cron from "node-cron";
|
2
|
-
import {
|
3
|
-
import { RedisCache } from "./
|
2
|
+
import { Orchestrator } from "../llm/orchestrator";
|
3
|
+
import { RedisCache } from "./cache";
|
4
4
|
|
5
5
|
interface ScheduledRequest {
|
6
6
|
id: string;
|
@@ -10,24 +10,30 @@ interface ScheduledRequest {
|
|
10
10
|
createdAt: Date;
|
11
11
|
}
|
12
12
|
|
13
|
-
export class
|
13
|
+
export class Agenda {
|
14
14
|
private scheduledRequests: Map<string, ScheduledRequest> = new Map();
|
15
15
|
private cronJobs: Map<string, cron.ScheduledTask> = new Map();
|
16
|
-
private readonly
|
16
|
+
private readonly orchestrator: Orchestrator;
|
17
17
|
private readonly cache: RedisCache;
|
18
18
|
|
19
|
-
constructor(
|
20
|
-
this.
|
19
|
+
constructor(orchestrator: Orchestrator, cache: RedisCache) {
|
20
|
+
this.orchestrator = orchestrator;
|
21
21
|
this.cache = cache;
|
22
22
|
}
|
23
23
|
|
24
24
|
/**
|
25
25
|
* Schedule a new request to be processed later
|
26
26
|
*/
|
27
|
-
async scheduleRequest(
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
async scheduleRequest(
|
28
|
+
request: {
|
29
|
+
originalRequest: string;
|
30
|
+
cronExpression: string;
|
31
|
+
},
|
32
|
+
callbacks?: {
|
33
|
+
onScheduled?: (id: string) => void;
|
34
|
+
onExecuted?: (id: string, originalRequest: string) => void;
|
35
|
+
}
|
36
|
+
): Promise<string> {
|
31
37
|
const id = crypto.randomUUID();
|
32
38
|
|
33
39
|
const scheduledRequest: ScheduledRequest = {
|
@@ -42,6 +48,9 @@ export class TaskScheduler {
|
|
42
48
|
const cronJob = cron.schedule(request.cronExpression, async () => {
|
43
49
|
await this.executeScheduledRequest(scheduledRequest);
|
44
50
|
|
51
|
+
if (callbacks?.onExecuted)
|
52
|
+
callbacks.onExecuted(id, scheduledRequest.originalRequest);
|
53
|
+
|
45
54
|
if (!scheduledRequest.isRecurring) {
|
46
55
|
this.cancelScheduledRequest(id);
|
47
56
|
}
|
@@ -51,9 +60,7 @@ export class TaskScheduler {
|
|
51
60
|
this.scheduledRequests.set(id, scheduledRequest);
|
52
61
|
this.cronJobs.set(id, cronJob);
|
53
62
|
|
54
|
-
|
55
|
-
`✅ Request scheduled with cron expression: ${request.cronExpression}`
|
56
|
-
);
|
63
|
+
if (callbacks?.onScheduled) callbacks.onScheduled(id);
|
57
64
|
|
58
65
|
return id;
|
59
66
|
}
|
@@ -67,28 +74,6 @@ export class TaskScheduler {
|
|
67
74
|
try {
|
68
75
|
console.log(`🔄 Executing scheduled request from ${request.createdAt}`);
|
69
76
|
|
70
|
-
// Récupérer les actions précédentes du cache
|
71
|
-
const previousActions = await this.cache.getPreviousActions(request.id);
|
72
|
-
|
73
|
-
// Add context about when this request was scheduled
|
74
|
-
const contextualRequest = `You are a scheduler.
|
75
|
-
You were asked to execute this request: ${request.originalRequest}\n
|
76
|
-
Date of the request: ${request.createdAt.toISOString()}\n
|
77
|
-
Act like if you know the request was scheduled.
|
78
|
-
Don't reschedule the same action.
|
79
|
-
Just execute it.`;
|
80
|
-
|
81
|
-
// Process the request as if it was just received
|
82
|
-
const result = await this.agentRuntime.process({
|
83
|
-
currentContext: contextualRequest,
|
84
|
-
previousActions,
|
85
|
-
});
|
86
|
-
|
87
|
-
// Store the new actions in cache
|
88
|
-
if (result.actions.length > 0) {
|
89
|
-
await this.cache.storePreviousActions(request.id, result.actions);
|
90
|
-
}
|
91
|
-
|
92
77
|
console.log(`✅ Scheduled request executed successfully`);
|
93
78
|
} catch (error) {
|
94
79
|
console.error(`❌ Failed to execute scheduled request:`, error);
|
@@ -0,0 +1,298 @@
|
|
1
|
+
import { type CoreMessage } from "ai";
|
2
|
+
import Redis from "ioredis";
|
3
|
+
import cron from "node-cron";
|
4
|
+
|
5
|
+
export interface CacheConfig {
|
6
|
+
host: string;
|
7
|
+
port: number;
|
8
|
+
password?: string;
|
9
|
+
ttl?: number; // Time to live in seconds (default 30 minutes)
|
10
|
+
cleanupInterval?: string; // Cron expression (default every 30 minutes)
|
11
|
+
}
|
12
|
+
|
13
|
+
export class RedisCache {
|
14
|
+
private redis: Redis;
|
15
|
+
private readonly defaultTTL: number;
|
16
|
+
private readonly cleanupJob: cron.ScheduledTask;
|
17
|
+
|
18
|
+
constructor(config: CacheConfig) {
|
19
|
+
this.redis = new Redis({
|
20
|
+
host: config.host,
|
21
|
+
port: config.port,
|
22
|
+
password: config.password,
|
23
|
+
});
|
24
|
+
|
25
|
+
this.defaultTTL = config.ttl || 1800; // 30 minutes in seconds
|
26
|
+
// Setup cleanup job (default: every 30 minutes)
|
27
|
+
|
28
|
+
// this.cleanupEverything();
|
29
|
+
|
30
|
+
this.cleanupJob = cron.schedule(
|
31
|
+
config.cleanupInterval || "*/30 * * * *",
|
32
|
+
() => this.cleanup()
|
33
|
+
);
|
34
|
+
}
|
35
|
+
|
36
|
+
/**
|
37
|
+
* Store previous actions for a specific request
|
38
|
+
*/
|
39
|
+
async storePreviousActions(requestId: string, actions: any[]): Promise<void> {
|
40
|
+
const key = `previous_actions:${requestId}`;
|
41
|
+
await this.redis.setex(
|
42
|
+
key,
|
43
|
+
this.defaultTTL,
|
44
|
+
JSON.stringify({
|
45
|
+
timestamp: new Date().toISOString(),
|
46
|
+
actions,
|
47
|
+
})
|
48
|
+
);
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Get previous actions for a specific request
|
53
|
+
*/
|
54
|
+
async getPreviousActions(requestId: string): Promise<any[]> {
|
55
|
+
const key = `previous_actions:${requestId}`;
|
56
|
+
const data = await this.redis.get(key);
|
57
|
+
if (!data) return [];
|
58
|
+
|
59
|
+
const parsed = JSON.parse(data);
|
60
|
+
return parsed.actions;
|
61
|
+
}
|
62
|
+
|
63
|
+
async storeMessage(
|
64
|
+
role: "user" | "assistant" | "system",
|
65
|
+
message: string
|
66
|
+
): Promise<void> {
|
67
|
+
const id = crypto.randomUUID();
|
68
|
+
const key = `recent_messages:${id}`;
|
69
|
+
const coreMessage: CoreMessage = {
|
70
|
+
role,
|
71
|
+
content: message,
|
72
|
+
};
|
73
|
+
await this.redis.setex(
|
74
|
+
key,
|
75
|
+
this.defaultTTL,
|
76
|
+
JSON.stringify({ ...coreMessage, timestamp: new Date().toISOString() })
|
77
|
+
);
|
78
|
+
console.log("🔍 Message stored successfully", { key, message });
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Store a recent message following CoreMessage structure
|
83
|
+
*/
|
84
|
+
async storeRecentMessage(
|
85
|
+
message: string,
|
86
|
+
metadata?: {
|
87
|
+
socialResponse?: string;
|
88
|
+
agentName?: string;
|
89
|
+
agentResponse?: string;
|
90
|
+
actions?: any[];
|
91
|
+
}
|
92
|
+
): Promise<void> {
|
93
|
+
console.log("🔍 Storing recent message:", message);
|
94
|
+
const id = crypto.randomUUID();
|
95
|
+
const key = `recent_messages:${id}`;
|
96
|
+
|
97
|
+
// Create CoreMessage structure
|
98
|
+
const coreMessage: CoreMessage[] = [
|
99
|
+
{
|
100
|
+
role: "user",
|
101
|
+
content: message,
|
102
|
+
},
|
103
|
+
];
|
104
|
+
|
105
|
+
// Add assistant response if available
|
106
|
+
if (metadata?.socialResponse || metadata?.agentResponse) {
|
107
|
+
coreMessage.push({
|
108
|
+
role: "assistant",
|
109
|
+
content:
|
110
|
+
metadata.socialResponse || metadata.agentResponse
|
111
|
+
? `Agent ${metadata.agentName ? metadata.agentName : "Main"}: ${
|
112
|
+
metadata.socialResponse || metadata.agentResponse
|
113
|
+
}`
|
114
|
+
: "",
|
115
|
+
});
|
116
|
+
}
|
117
|
+
|
118
|
+
await this.redis.setex(
|
119
|
+
key,
|
120
|
+
this.defaultTTL,
|
121
|
+
JSON.stringify({
|
122
|
+
timestamp: new Date().toISOString(),
|
123
|
+
messages: coreMessage,
|
124
|
+
actions: metadata?.actions || [],
|
125
|
+
})
|
126
|
+
);
|
127
|
+
console.log("🔍 Recent message stored successfully", {
|
128
|
+
key,
|
129
|
+
message,
|
130
|
+
});
|
131
|
+
}
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Get previous actions
|
135
|
+
*/
|
136
|
+
async getRecentPreviousActions(limit: number = 10): Promise<any[]> {
|
137
|
+
const keys = await this.redis.keys("previous_actions:*");
|
138
|
+
if (!keys.length) return [];
|
139
|
+
|
140
|
+
const actions = await Promise.all(
|
141
|
+
keys.map(async (key) => {
|
142
|
+
const data = await this.redis.get(key);
|
143
|
+
return data ? JSON.parse(data) : null;
|
144
|
+
})
|
145
|
+
);
|
146
|
+
return actions.slice(0, limit);
|
147
|
+
}
|
148
|
+
|
149
|
+
/**
|
150
|
+
* Get recent messages in CoreMessage format
|
151
|
+
*/
|
152
|
+
async getRecentMessages(limit: number = 10): Promise<CoreMessage[]> {
|
153
|
+
const keys = await this.redis.keys("recent_messages:*");
|
154
|
+
if (!keys.length) return [];
|
155
|
+
|
156
|
+
const messages = await Promise.all(
|
157
|
+
keys.map(async (key) => {
|
158
|
+
const data = await this.redis.get(key);
|
159
|
+
return data ? JSON.parse(data) : null;
|
160
|
+
})
|
161
|
+
);
|
162
|
+
|
163
|
+
const formattedMessages = messages
|
164
|
+
.sort(
|
165
|
+
(a, b) =>
|
166
|
+
new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
|
167
|
+
) // Tri par timestamp
|
168
|
+
.map((message) => {
|
169
|
+
return {
|
170
|
+
role: message.role,
|
171
|
+
content: message.content,
|
172
|
+
};
|
173
|
+
}) // Extraire les messages de chaque entrée
|
174
|
+
.slice(0, limit); // Limiter le nombre de messages
|
175
|
+
return formattedMessages;
|
176
|
+
}
|
177
|
+
/**
|
178
|
+
* Cleanup expired keys
|
179
|
+
*/
|
180
|
+
private async cleanup(): Promise<void> {
|
181
|
+
console.log("🧹 Starting cache cleanup...");
|
182
|
+
try {
|
183
|
+
// Redis automatically removes expired keys
|
184
|
+
// This is just for logging purposes
|
185
|
+
const actionKeys = await this.redis.keys("previous_actions:*");
|
186
|
+
const messageKeys = await this.redis.keys("recent_messages:*");
|
187
|
+
console.log(
|
188
|
+
`Cache status: ${actionKeys.length} actions, ${messageKeys.length} messages`
|
189
|
+
);
|
190
|
+
} catch (error) {
|
191
|
+
console.error("❌ Cache cleanup error:", error);
|
192
|
+
}
|
193
|
+
}
|
194
|
+
async cleanupEverything(): Promise<void> {
|
195
|
+
const keys = await this.redis.keys("*");
|
196
|
+
console.log("🔍 Cleaning up messages with TTL:", keys);
|
197
|
+
|
198
|
+
for (const key of keys) {
|
199
|
+
console.log(`🧹 Suppression de la clé expirée ou invalide: ${key}`);
|
200
|
+
await this.redis.del(key);
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
/**
|
205
|
+
* Stop the cleanup job and close Redis connection
|
206
|
+
*/
|
207
|
+
async close(): Promise<void> {
|
208
|
+
this.cleanupJob.stop();
|
209
|
+
await this.redis.quit();
|
210
|
+
}
|
211
|
+
|
212
|
+
/**
|
213
|
+
* Store a memory with tags and categories
|
214
|
+
*/
|
215
|
+
async storeMemory(
|
216
|
+
data: string,
|
217
|
+
category: string,
|
218
|
+
tags: string[],
|
219
|
+
ttl?: number
|
220
|
+
): Promise<void> {
|
221
|
+
const id = crypto.randomUUID();
|
222
|
+
const key = `memory:${id}`;
|
223
|
+
const memoryData = {
|
224
|
+
data,
|
225
|
+
category,
|
226
|
+
tags,
|
227
|
+
timestamp: new Date().toISOString(),
|
228
|
+
};
|
229
|
+
|
230
|
+
// Enregistrer la mémoire avec TTL
|
231
|
+
await this.redis.setex(
|
232
|
+
key,
|
233
|
+
ttl || this.defaultTTL,
|
234
|
+
JSON.stringify(memoryData)
|
235
|
+
);
|
236
|
+
|
237
|
+
// Indexer les tags
|
238
|
+
for (const tag of tags) {
|
239
|
+
const tagKey = `tag:${tag}`;
|
240
|
+
await this.redis.sadd(tagKey, key);
|
241
|
+
}
|
242
|
+
|
243
|
+
// Indexer les catégories
|
244
|
+
const categoryKey = `category:${category}`;
|
245
|
+
await this.redis.sadd(categoryKey, key);
|
246
|
+
console.log("🔍 Memory stored successfully", { key, memoryData });
|
247
|
+
}
|
248
|
+
|
249
|
+
/**
|
250
|
+
* Get memories by a specific tag
|
251
|
+
*/
|
252
|
+
async getMemoriesByTag(tag: string): Promise<any[]> {
|
253
|
+
const tagKey = `tag:${tag}`;
|
254
|
+
const keys = await this.redis.smembers(tagKey);
|
255
|
+
|
256
|
+
const memories = await Promise.all(
|
257
|
+
keys.map(async (key) => {
|
258
|
+
const data = await this.redis.get(key);
|
259
|
+
return data ? JSON.parse(data) : null;
|
260
|
+
})
|
261
|
+
);
|
262
|
+
|
263
|
+
return memories.filter(Boolean); // Filtrer les valeurs nulles
|
264
|
+
}
|
265
|
+
|
266
|
+
/**
|
267
|
+
* Get memories by a specific category
|
268
|
+
*/
|
269
|
+
async getMemoriesByCategory(category: string): Promise<any[]> {
|
270
|
+
const categoryKey = `category:${category}`;
|
271
|
+
const keys = await this.redis.smembers(categoryKey);
|
272
|
+
|
273
|
+
const memories = await Promise.all(
|
274
|
+
keys.map(async (key) => {
|
275
|
+
const data = await this.redis.get(key);
|
276
|
+
return data ? JSON.parse(data) : null;
|
277
|
+
})
|
278
|
+
);
|
279
|
+
|
280
|
+
return memories.filter(Boolean); // Filtrer les valeurs nulles
|
281
|
+
}
|
282
|
+
|
283
|
+
/**
|
284
|
+
* Get all available tags
|
285
|
+
*/
|
286
|
+
async getAllTags(): Promise<string[]> {
|
287
|
+
const keys = await this.redis.keys("tag:*");
|
288
|
+
return keys.map((key) => key.replace("tag:", ""));
|
289
|
+
}
|
290
|
+
|
291
|
+
/**
|
292
|
+
* Get all available categories
|
293
|
+
*/
|
294
|
+
async getAllCategories(): Promise<string[]> {
|
295
|
+
const keys = await this.redis.keys("category:*");
|
296
|
+
return keys.map((key) => key.replace("category:", ""));
|
297
|
+
}
|
298
|
+
}
|
package/services/queue.ts
CHANGED
@@ -6,7 +6,7 @@ import {
|
|
6
6
|
QueueResult,
|
7
7
|
} from "../types";
|
8
8
|
|
9
|
-
export class
|
9
|
+
export class Queue {
|
10
10
|
private queue: QueueItem[] = [];
|
11
11
|
private results: QueueResult[] = [];
|
12
12
|
private callbacks: QueueCallbacks;
|
@@ -18,7 +18,7 @@ export class ActionQueueManager {
|
|
18
18
|
this.callbacks = callbacks;
|
19
19
|
}
|
20
20
|
|
21
|
-
|
21
|
+
add(actions: QueueItem | QueueItem[]) {
|
22
22
|
if (Array.isArray(actions)) {
|
23
23
|
console.log("\n📋 Adding actions to queue:");
|
24
24
|
actions.forEach((action, index) => {
|
@@ -31,7 +31,7 @@ export class ActionQueueManager {
|
|
31
31
|
}
|
32
32
|
}
|
33
33
|
|
34
|
-
async
|
34
|
+
async execute() {
|
35
35
|
if (this.isProcessing) {
|
36
36
|
console.log("\n⚠️ Queue is already being processed");
|
37
37
|
return;
|