@ai.ntellect/core 0.4.1 → 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/agent/index.ts CHANGED
@@ -2,34 +2,25 @@ import { LanguageModel } from "ai";
2
2
  import WebSocket from "ws";
3
3
  import { Interpreter } from "../llm/interpreter";
4
4
  import { MemoryManager } from "../llm/memory-manager";
5
- import { AgentRuntime } from "../llm/orchestrator";
6
- import { State } from "../llm/orchestrator/types";
5
+ import { Orchestrator } from "../llm/orchestrator";
7
6
  import { CacheMemory } from "../memory/cache";
8
7
  import { PersistentMemory } from "../memory/persistent";
9
- import { ActionQueueManager } from "../services/queue";
10
- import { CacheConfig, RedisCache } from "../services/redis-cache";
11
- import { ActionData, ActionSchema, QueueCallbacks } from "../types";
12
- import { QueueItemTransformer } from "../utils/queue-item-transformer";
8
+ import { CacheConfig, RedisCache } from "../services/cache";
9
+ import { Workflow } from "../services/workflow";
10
+ import { AgentEvent, MyContext, QueueCallbacks, SharedState } from "../types";
11
+ import { createMainWorkflow } from "./workflow";
13
12
 
14
13
  export class Agent {
15
- private readonly agent: AgentRuntime;
16
- private readonly memoryManager: MemoryManager;
17
- private readonly cache: RedisCache;
18
-
14
+ public readonly memoryManager: MemoryManager;
15
+ public readonly cache: RedisCache;
16
+ public readonly orchestrator: Orchestrator;
19
17
  private listeners: Map<
20
18
  string,
21
19
  { socket: WebSocket; callback: (data: any) => Promise<void> }
22
20
  > = new Map();
23
- private readonly config: {
24
- orchestrator: {
25
- model: LanguageModel;
26
- tools: ActionSchema[];
27
- memory?: {
28
- cache?: CacheMemory;
29
- persistent?: PersistentMemory;
30
- };
31
- };
21
+ public readonly config: {
32
22
  interpreters: Interpreter[];
23
+ orchestrator: Orchestrator;
33
24
  memoryManager: {
34
25
  model: LanguageModel;
35
26
  memory?: {
@@ -42,15 +33,8 @@ export class Agent {
42
33
 
43
34
  constructor(config: {
44
35
  cache: CacheConfig;
45
- orchestrator: {
46
- model: LanguageModel;
47
- tools: ActionSchema[];
48
- memory?: {
49
- cache?: CacheMemory;
50
- persistent?: PersistentMemory;
51
- };
52
- };
53
36
  interpreters: Interpreter[];
37
+ orchestrator: Orchestrator;
54
38
  memoryManager: {
55
39
  model: LanguageModel;
56
40
  memory?: {
@@ -63,13 +47,7 @@ export class Agent {
63
47
  }) {
64
48
  this.cache = new RedisCache(config.cache);
65
49
  this.config = config;
66
- this.agent = new AgentRuntime(
67
- config.orchestrator.model,
68
- config.orchestrator.tools,
69
- config.interpreters,
70
- config.cache,
71
- config.orchestrator.memory
72
- );
50
+
73
51
  this.memoryManager = new MemoryManager({
74
52
  model: config.memoryManager.model,
75
53
  memory: {
@@ -77,125 +55,54 @@ export class Agent {
77
55
  persistent: config.memoryManager.memory?.persistent ?? undefined,
78
56
  },
79
57
  });
58
+ this.orchestrator = config.orchestrator;
80
59
  this.config.maxIterations = 3;
81
60
  }
82
61
 
83
- public async process(state: State, callbacks?: QueueCallbacks): Promise<any> {
62
+ public async process(prompt: string, callbacks?: AgentEvent): Promise<any> {
84
63
  console.log("🔄 Processing state:");
85
- console.dir(state, { depth: null });
86
- let countIterations = 0;
87
- const response = await this.agent.process(state);
88
-
89
- const unscheduledActions = response.actions.filter(
90
- (action) => !action.scheduler?.isScheduled
91
- );
92
- // Execute actions if needed
93
- if (unscheduledActions?.length > 0 && response.shouldContinue) {
94
- console.log("\n📋 Processing action queue");
95
- const queueManager = new ActionQueueManager(
96
- this.config.orchestrator.tools,
97
- callbacks
98
- );
99
- const queueItems = QueueItemTransformer.transformActionsToQueueItems(
100
- response.actions as ActionData[]
101
- );
102
- if (!queueItems) {
103
- throw new Error("No queue items found");
104
- }
64
+ const agent = this;
65
+ const recentMessages = await this.cache.getRecentMessages();
66
+ const previousActions = await this.cache.getRecentPreviousActions(1);
67
+
68
+ const initialState: SharedState<MyContext> = {
69
+ messages: [...recentMessages, { role: "user", content: prompt }],
70
+ context: {
71
+ prompt,
72
+ processing: {
73
+ stop: false,
74
+ },
75
+ results: previousActions,
76
+ },
77
+ };
105
78
 
106
- console.log(
107
- "📋 Actions to execute:",
108
- queueItems
109
- .map((item) => (typeof item === "string" ? item : item.name))
110
- .join(", ")
111
- );
112
-
113
- queueManager.addToQueue(queueItems);
114
- console.log("\n⚡ Executing actions...");
115
- const results = await queueManager.processQueue();
116
- console.log("✅ Execution results:", results);
117
-
118
- const updatedNextState: State = {
119
- ...state,
120
- currentContext: state.currentContext,
121
- previousActions: [...(state.previousActions || []), ...(results || [])],
122
- };
79
+ const mainWorkflow = createMainWorkflow(agent, prompt, callbacks);
80
+ const workflow = new Workflow<MyContext>(mainWorkflow);
123
81
 
124
- console.log("\n🔁 Recursively processing with updated state");
125
- countIterations++;
126
- if (countIterations < this.config.maxIterations) {
127
- return this.process(updatedNextState);
82
+ await workflow.execute(
83
+ initialState,
84
+ mainWorkflow.entryNode,
85
+ async (state) => {
86
+ callbacks?.onMessage && (await callbacks.onMessage(state));
128
87
  }
129
- }
130
-
131
- if (countIterations >= this.config.maxIterations) {
132
- console.log("Max iterations reached");
133
- response.shouldContinue = false;
134
- console.log("Forcing stop");
135
- }
136
-
137
- // Handle final interpretation
138
- if (
139
- !response.shouldContinue &&
140
- state.previousActions?.length &&
141
- response.interpreter
142
- ) {
143
- console.log("\n🏁 Analysis complete - generating final interpretation");
144
- const interpreter = this.getInterpreter(
145
- this.config.interpreters,
146
- response.interpreter
147
- );
148
- console.log("🎭 Selected Interpreter:", interpreter?.name);
149
- console.dir(state, { depth: null });
150
- const interpretationResult = (await interpreter?.process(
151
- "Interpret the analysis results",
152
- {
153
- ...state,
154
- results: JSON.stringify(state.previousActions),
155
- userRequest: state.currentContext,
156
- }
157
- )) as { response: string };
158
-
159
- console.log("\n📊 Final Analysis:", interpretationResult.response);
160
-
161
- const finalState: State = {
162
- ...state,
163
- results: interpretationResult.response,
164
- };
165
-
166
- console.log("🔄 Final state:", finalState);
167
- }
168
-
169
- // Return the final response at the end of the function
170
- const validatedActions = response.actions.map((action) => ({
171
- ...action,
172
- parameters: action.parameters.map((param) => ({
173
- ...param,
174
- value: param.value ?? null, // Set a default value if undefined
175
- })),
176
- }));
177
-
178
- const result = {
179
- ...response,
180
- actions: validatedActions,
181
- results: JSON.stringify(state.previousActions),
182
- };
183
- if (!result.shouldContinue) {
184
- await this.memoryManager.process(state, JSON.stringify(result));
185
- }
186
- return result;
88
+ );
187
89
  }
188
90
 
189
- private getInterpreter(interpreters: Interpreter[], name: string) {
91
+ public getInterpreter(interpreters: Interpreter[], name: string) {
190
92
  return interpreters.find((interpreter) => interpreter.name === name);
191
93
  }
192
94
 
193
- public addListener(
194
- id: string,
195
- url: string,
196
- subscriptionMessageFactory: () => string,
197
- callback: (data: any, agentContext: Agent) => Promise<void>
198
- ): void {
95
+ public addListener({
96
+ id,
97
+ url,
98
+ onSubscribe,
99
+ onMessage,
100
+ }: {
101
+ id: string;
102
+ url: string;
103
+ onSubscribe: () => string;
104
+ onMessage: (data: any, agentContext: Agent) => Promise<void>;
105
+ }): void {
199
106
  if (this.listeners.has(id)) {
200
107
  console.warn(`WebSocket with ID ${id} already exists.`);
201
108
  return;
@@ -203,16 +110,16 @@ export class Agent {
203
110
 
204
111
  const socket = new WebSocket(url);
205
112
 
206
- const wrappedCallback = async (data: any) => {
207
- await callback(data, this);
113
+ const wrappedOnMessage = async (data: any) => {
114
+ await onMessage(data, this);
208
115
  };
209
116
 
210
117
  socket.on("open", () => {
211
118
  console.log(`🔗 WebSocket connected for ID: ${id}`);
212
119
 
213
120
  // Envoie le message d'abonnement si une factory est fournie
214
- if (subscriptionMessageFactory) {
215
- const subscriptionMessage = subscriptionMessageFactory();
121
+ if (onSubscribe) {
122
+ const subscriptionMessage = onSubscribe();
216
123
  socket.send(subscriptionMessage);
217
124
  console.log(
218
125
  `📡 Sent subscription message for ID ${id}:`,
@@ -225,7 +132,7 @@ export class Agent {
225
132
  console.log(`📨 Message received for WebSocket ID ${id}:`, message);
226
133
  try {
227
134
  const data = JSON.parse(message);
228
- await wrappedCallback(data);
135
+ await wrappedOnMessage(data);
229
136
  } catch (error) {
230
137
  console.error(`❌ Error in callback for WebSocket ID ${id}:`, error);
231
138
  }
@@ -239,6 +146,6 @@ export class Agent {
239
146
  console.log(`🔌 WebSocket closed for ID: ${id}`);
240
147
  });
241
148
 
242
- this.listeners.set(id, { socket, callback: wrappedCallback });
149
+ this.listeners.set(id, { socket, callback: wrappedOnMessage });
243
150
  }
244
151
  }
@@ -0,0 +1,16 @@
1
+ import { SharedState } from "../../types";
2
+
3
+ export const hasActions = (state: SharedState<any>): boolean =>
4
+ !!state.context.actions && state.context.actions.length > 0;
5
+
6
+ export const isNotStopped = (state: SharedState<any>): boolean =>
7
+ !state.context.processing?.stop;
8
+
9
+ export const isInterpreterDefined = (state: SharedState<any>): boolean =>
10
+ !!state.context.interpreter;
11
+
12
+ export const isResultsDefined = (state: SharedState<any>): boolean =>
13
+ !!state.context.results && state.context.results.length > 0;
14
+
15
+ export const isStopped = (state: SharedState<any>): boolean =>
16
+ !!state.context.processing?.stop;
@@ -0,0 +1,48 @@
1
+ import { Agent } from "../..";
2
+ import { ActionData, MyContext, SharedState } from "../../../types";
3
+ import { StateManager } from "../../../utils/state-manager";
4
+
5
+ export const handleInterpreter = async (
6
+ sharedState: SharedState<MyContext>,
7
+ agent: Agent
8
+ ) => {
9
+ console.log("🔄 Interpreting actions");
10
+ const interpreter = agent.getInterpreter(
11
+ agent.config.interpreters,
12
+ sharedState.context.interpreter ?? ""
13
+ );
14
+
15
+ if (!interpreter) {
16
+ throw new Error("No interpreter found");
17
+ }
18
+
19
+ console.log("🎭 Selected Interpreter:", interpreter?.name);
20
+ (await interpreter?.process(sharedState, async (event: any) => {
21
+ console.log("🎭 Interpreter event:", event);
22
+
23
+ // Store message in recent messages
24
+ await agent.cache.storeMessage("assistant", event.response);
25
+ })) as { response: string };
26
+
27
+ const validatedActions = sharedState.context.actions?.map(
28
+ (action: ActionData) => ({
29
+ ...action,
30
+ name: action.name || "default", // Ensure name is always defined
31
+ parameters:
32
+ action.parameters?.map((param: { value: string }) => ({
33
+ ...param,
34
+ value: param.value ?? null,
35
+ })) ?? [],
36
+ })
37
+ );
38
+
39
+ return StateManager.updateState(sharedState, {
40
+ context: {
41
+ actions: validatedActions,
42
+ prompt: sharedState.context.prompt,
43
+ processing: {
44
+ stop: true,
45
+ },
46
+ },
47
+ });
48
+ };
@@ -0,0 +1,106 @@
1
+ import { Agent } from "../..";
2
+ import { MemoryScope, MyContext, SharedState } from "../../../types";
3
+ import { StateManager } from "../../../utils/state-manager";
4
+
5
+ export const handleMemory = async (
6
+ sharedState: SharedState<MyContext>,
7
+ agent: Agent
8
+ ) => {
9
+ console.log("🔄 Storing memories");
10
+ const recentMessages = await agent.cache.getRecentMessages();
11
+
12
+ const updatedState = StateManager.updateState(sharedState, {
13
+ messages: recentMessages,
14
+ });
15
+
16
+ await agent.memoryManager.process(updatedState, {
17
+ onMemoriesGenerated: async (event) => {
18
+ if (event.memories.length === 0) {
19
+ return;
20
+ }
21
+ // Store memories after all processing is complete
22
+ await Promise.all([
23
+ // Store short-term memories in cache
24
+ ...event.memories
25
+ .filter((m: any) => m.type === "short-term")
26
+ .map(async (memoryItem: any) => {
27
+ await agent.cache.storeMemory(
28
+ memoryItem.data,
29
+ memoryItem.category,
30
+ memoryItem.tags,
31
+ memoryItem.ttl
32
+ );
33
+
34
+ const existingCacheMemories =
35
+ await agent.memoryManager.memory?.cache?.findSimilarActions(
36
+ memoryItem.data,
37
+ {
38
+ similarityThreshold: 85,
39
+ maxResults: 3,
40
+ scope: MemoryScope.GLOBAL,
41
+ }
42
+ );
43
+
44
+ if (
45
+ existingCacheMemories?.length &&
46
+ existingCacheMemories.length > 0
47
+ ) {
48
+ console.log(
49
+ "⚠️ Similar memory already exists in cache:",
50
+ memoryItem.data
51
+ );
52
+ return;
53
+ }
54
+
55
+ await agent.memoryManager.memory?.cache?.createMemory({
56
+ query: memoryItem.queryForMemory,
57
+ data: memoryItem.data,
58
+ ttl: memoryItem.ttl, // Use TTL from LLM
59
+ });
60
+ console.log("✅ Memory stored in cache:", memoryItem.data);
61
+ }),
62
+
63
+ // Store long-term memories in persistent storage
64
+ ...event.memories
65
+ .filter((m: any) => m.type === "long-term")
66
+ .map(async (memoryItem: any) => {
67
+ if (!agent.memoryManager.memory?.persistent) {
68
+ return;
69
+ }
70
+
71
+ const existingPersistentMemories =
72
+ await agent.memoryManager.memory?.persistent?.findRelevantDocuments(
73
+ memoryItem.data,
74
+ {
75
+ similarityThreshold: 85,
76
+ }
77
+ );
78
+
79
+ if (
80
+ existingPersistentMemories?.length &&
81
+ existingPersistentMemories.length > 0
82
+ ) {
83
+ console.log(
84
+ "⚠️ Similar memory already exists in persistent storage:",
85
+ memoryItem.data
86
+ );
87
+ return;
88
+ }
89
+
90
+ await agent.memoryManager.memory?.persistent?.createMemory({
91
+ query: memoryItem.queryForMemory,
92
+ data: memoryItem.data,
93
+ category: memoryItem.category,
94
+ tags: memoryItem.tags,
95
+ roomId: "global",
96
+ createdAt: new Date(),
97
+ id: crypto.randomUUID(),
98
+ });
99
+ console.log("✅ Memory stored in persistent storage:", memoryItem);
100
+ }),
101
+ ]);
102
+ },
103
+ });
104
+
105
+ return updatedState;
106
+ };
@@ -0,0 +1,23 @@
1
+ import { Agent } from "../..";
2
+ import { AgentEvent, MyContext, SharedState } from "../../../types";
3
+ import { StateManager } from "../../../utils/state-manager";
4
+
5
+ export const handleOrchestrator = async (
6
+ prompt: string,
7
+ sharedState: SharedState<MyContext>,
8
+ agent: Agent,
9
+ callbacks?: AgentEvent
10
+ ) => {
11
+ try {
12
+ const result = await agent.orchestrator.process(sharedState);
13
+
14
+ return StateManager.updateState(sharedState, {
15
+ context: {
16
+ ...result,
17
+ },
18
+ });
19
+ } catch (error) {
20
+ console.error("🔄 Start handler error:", error);
21
+ throw error;
22
+ }
23
+ };
@@ -0,0 +1,34 @@
1
+ import { Agent } from "../..";
2
+ import { Queue } from "../../../services/queue";
3
+ import { ActionData, AgentEvent, MyContext, SharedState } from "../../../types";
4
+ import { QueueItemTransformer } from "../../../utils/queue-item-transformer";
5
+ import { StateManager } from "../../../utils/state-manager";
6
+
7
+ export const handleQueue = async (
8
+ sharedState: SharedState<MyContext>,
9
+ agent: Agent,
10
+ callbacks?: AgentEvent
11
+ ) => {
12
+ console.log("🔄 Queue actions:", sharedState.context.actions);
13
+ const queue = new Queue(agent.config.orchestrator.tools, callbacks);
14
+ const queueItems = QueueItemTransformer.transformActionsToQueueItems(
15
+ sharedState.context.actions as ActionData[]
16
+ );
17
+ if (!queueItems) {
18
+ throw new Error("No queue items found");
19
+ }
20
+ queue.add(queueItems);
21
+ const results = await queue.execute();
22
+ if (results) {
23
+ await agent.cache.storePreviousActions(crypto.randomUUID(), results);
24
+ }
25
+
26
+ return StateManager.updateState(sharedState, {
27
+ context: {
28
+ results,
29
+ processing: {
30
+ stop: false,
31
+ },
32
+ },
33
+ });
34
+ };
@@ -0,0 +1,61 @@
1
+ import { CoreMessage } from "ai";
2
+ import { Agent } from "../..";
3
+ import { MyContext, SharedState } from "../../../types";
4
+
5
+ export const handleScheduler = async (
6
+ prompt: string,
7
+ sharedState: SharedState<MyContext>,
8
+ agent: Agent
9
+ ) => {
10
+ for (const action of sharedState.context.actions ?? []) {
11
+ if (action.scheduler?.isScheduled && action.scheduler?.cronExpression) {
12
+ await agent.agenda.scheduleRequest(
13
+ {
14
+ originalRequest: prompt,
15
+ cronExpression: action.scheduler.cronExpression,
16
+ },
17
+ {
18
+ onScheduled: (id) => {
19
+ console.log("🔄 Scheduled action:", id);
20
+ },
21
+ onExecuted: async (id, originalRequest) => {
22
+ console.log("🔄 Executed action:", id);
23
+
24
+ // Add context about when this request was scheduled
25
+ const contextualRequest = `You are a scheduler.
26
+ You were asked to execute this request: ${originalRequest}\n
27
+ Date of the request: ${new Date().toISOString()}\n
28
+ Act like if you know the request was scheduled.
29
+ Don't reschedule the same action.
30
+ Just execute it.`;
31
+
32
+ const updatedSharedState = {
33
+ ...sharedState,
34
+ messages: [
35
+ {
36
+ role: "user",
37
+ content: contextualRequest,
38
+ },
39
+ ...(sharedState.messages ?? []),
40
+ ] as CoreMessage[],
41
+ context: {
42
+ ...sharedState.context,
43
+ originalRequest,
44
+ },
45
+ };
46
+
47
+ // Process the request as if it was just received
48
+ const result = await agent.orchestrator.process(updatedSharedState);
49
+
50
+ // Store the new actions in cache
51
+ if (result.actions.length > 0) {
52
+ await agent.cache.storePreviousActions(id, result.actions);
53
+ }
54
+ },
55
+ }
56
+ );
57
+ }
58
+ }
59
+
60
+ return sharedState;
61
+ };
@@ -0,0 +1,62 @@
1
+ import { Agent } from "..";
2
+ import { MyContext, WorkflowDefinition } from "../../types";
3
+ import {
4
+ hasActions,
5
+ isInterpreterDefined,
6
+ isNotStopped,
7
+ isResultsDefined,
8
+ isStopped,
9
+ } from "./conditions";
10
+ import { handleInterpreter } from "./handlers/interpreter.handler";
11
+ import { handleMemory } from "./handlers/memory.handler";
12
+ import { handleOrchestrator } from "./handlers/orchestrator.handler";
13
+ import { handleQueue } from "./handlers/queue.handler";
14
+ import { handleScheduler } from "./handlers/scheduler.handler";
15
+
16
+ export const createMainWorkflow = (
17
+ agent: Agent,
18
+ prompt: string,
19
+ callbacks?: any
20
+ ): WorkflowDefinition<MyContext> => ({
21
+ name: "agentWorkflow", // Name of the graph
22
+ entryNode: "makeDecision", // Entry node
23
+ nodes: {
24
+ makeDecision: {
25
+ name: "makeDecision",
26
+ description: "Make a decision following the environment",
27
+ execute: async (state) =>
28
+ handleOrchestrator(prompt, state, agent, callbacks),
29
+ condition: (state) => isNotStopped(state), // Check if the agent is not stopped
30
+ next: ["checkEnvironment", "scheduleActions", "interpretResults"], // Next nodes to execute
31
+ },
32
+ checkEnvironment: {
33
+ name: "checkEnvironment", // Check the environment
34
+ description: "Check the environment for any actions to handle",
35
+ execute: async (state) => handleQueue(state, agent, callbacks),
36
+ condition: (state) => hasActions(state) && isNotStopped(state), // Check if there are actions to handle and the agent is not stopped
37
+ next: ["makeDecision"],
38
+ },
39
+ scheduleActions: {
40
+ name: "scheduleActions",
41
+ description: "Schedule actions for the future",
42
+ execute: async (state) => handleScheduler(prompt, state, agent),
43
+ condition: (state) => hasActions(state), // Check if there are actions to schedule
44
+ },
45
+ interpretResults: {
46
+ name: "interpretResults",
47
+ description: "Interpret the results of the actions",
48
+ execute: async (state) => handleInterpreter(state, agent),
49
+ condition: (state) =>
50
+ isInterpreterDefined(state) && // Check if interpreter is defined
51
+ isResultsDefined(state) && // Check if results are defined
52
+ isStopped(state), // Check if processing is stopped
53
+ next: ["saveMemory"],
54
+ },
55
+ saveMemory: {
56
+ name: "saveMemory",
57
+ description: "Save memory",
58
+ execute: async (state) => handleMemory(state, agent),
59
+ condition: (state) => isResultsDefined(state), // Check if results are defined
60
+ },
61
+ },
62
+ });
@@ -20,7 +20,14 @@ function stripHtmlTags(content: string): string {
20
20
  export const getRssNews = {
21
21
  name: "get-news-rss",
22
22
  description: "Get latest news about on website",
23
- parameters: z.object({}),
23
+ parameters: z.object({
24
+ url: z.enum([
25
+ "https://news.google.com/rss/topics/CAAqJggKIiBDQkFTRWdvSUwyMHZNRGx1YlY4U0FtVnVHZ0pWVXlnQVAB?hl=en-US&gl=US&ceid=US:en",
26
+ "https://www.investing.com/rss/news_301.rss",
27
+ "https://cointelegraph.com/rss/category/analysis",
28
+ "https://cointelegraph.com/rss/category/top-10-cryptocurrencies",
29
+ ]),
30
+ }),
24
31
  execute: async () => {
25
32
  const itemsPerSource = 5;
26
33