@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
@@ -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
|
+
});
|
package/dist/agent/index.d.ts
CHANGED
package/dist/agent/index.js
CHANGED
@@ -12,7 +12,7 @@ const redis_cache_1 = require("../services/redis-cache");
|
|
12
12
|
const queue_item_transformer_1 = require("../utils/queue-item-transformer");
|
13
13
|
class Agent {
|
14
14
|
constructor(config) {
|
15
|
-
this.
|
15
|
+
this.listeners = new Map();
|
16
16
|
this.cache = new redis_cache_1.RedisCache(config.cache);
|
17
17
|
this.config = config;
|
18
18
|
this.agent = new orchestrator_1.AgentRuntime(config.orchestrator.model, config.orchestrator.tools, config.interpreters, config.cache, config.orchestrator.memory);
|
@@ -104,7 +104,7 @@ class Agent {
|
|
104
104
|
return interpreters.find((interpreter) => interpreter.name === name);
|
105
105
|
}
|
106
106
|
addListener(id, url, subscriptionMessageFactory, callback) {
|
107
|
-
if (this.
|
107
|
+
if (this.listeners.has(id)) {
|
108
108
|
console.warn(`WebSocket with ID ${id} already exists.`);
|
109
109
|
return;
|
110
110
|
}
|
@@ -137,7 +137,7 @@ class Agent {
|
|
137
137
|
socket.on("close", () => {
|
138
138
|
console.log(`🔌 WebSocket closed for ID: ${id}`);
|
139
139
|
});
|
140
|
-
this.
|
140
|
+
this.listeners.set(id, { socket, callback: wrappedCallback });
|
141
141
|
}
|
142
142
|
}
|
143
143
|
exports.Agent = Agent;
|
@@ -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
|
|
package/examples/index.ts
CHANGED
@@ -4,33 +4,27 @@ import { deepseek } from "@ai-sdk/deepseek";
|
|
4
4
|
import { configDotenv } from "dotenv";
|
5
5
|
import readline from "readline";
|
6
6
|
import { Agent } from "../agent";
|
7
|
-
import { getRssNews } from "../agent/tools/get-rss";
|
8
7
|
import { Interpreter } from "../llm/interpreter";
|
9
8
|
import {
|
10
|
-
generalInterpreterCharacter,
|
11
9
|
marketInterpreterCharacter,
|
12
10
|
securityInterpreterCharacter,
|
13
11
|
} from "../llm/interpreter/context";
|
12
|
+
import { getRssNews } from "./actions/get-rss";
|
14
13
|
configDotenv();
|
15
14
|
// Initialiser l'agent une fois pour toute la session
|
16
15
|
const initializeAgent = () => {
|
17
|
-
const model = deepseek("deepseek-
|
16
|
+
const model = deepseek("deepseek-chat");
|
18
17
|
|
19
18
|
const securityInterpreter = new Interpreter({
|
20
|
-
name: "security",
|
19
|
+
name: "security-check",
|
21
20
|
model,
|
22
21
|
character: securityInterpreterCharacter,
|
23
22
|
});
|
24
23
|
const marketInterpreter = new Interpreter({
|
25
|
-
name: "market",
|
24
|
+
name: "market-analysis",
|
26
25
|
model,
|
27
26
|
character: marketInterpreterCharacter,
|
28
27
|
});
|
29
|
-
const generalInterpreter = new Interpreter({
|
30
|
-
name: "general",
|
31
|
-
model,
|
32
|
-
character: generalInterpreterCharacter,
|
33
|
-
});
|
34
28
|
|
35
29
|
const agent = new Agent({
|
36
30
|
cache: {
|
@@ -41,7 +35,7 @@ const initializeAgent = () => {
|
|
41
35
|
model,
|
42
36
|
tools: [getRssNews],
|
43
37
|
},
|
44
|
-
interpreters: [securityInterpreter, marketInterpreter
|
38
|
+
interpreters: [securityInterpreter, marketInterpreter],
|
45
39
|
memoryManager: {
|
46
40
|
model,
|
47
41
|
},
|
@@ -80,12 +74,13 @@ const startChatSession = async () => {
|
|
80
74
|
return;
|
81
75
|
}
|
82
76
|
|
83
|
-
state.currentContext = input;
|
84
|
-
|
85
77
|
console.log("Agent en réflexion...");
|
86
78
|
try {
|
87
|
-
const result = await agent.process(
|
88
|
-
|
79
|
+
const result = await agent.process(input, {
|
80
|
+
onMessage: (message) => {
|
81
|
+
console.log(`Agent > ${message.socialResponse?.response}\n`);
|
82
|
+
},
|
83
|
+
});
|
89
84
|
} catch (error) {
|
90
85
|
console.error("Erreur avec l'agent :", error);
|
91
86
|
}
|
package/index.html
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8" />
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
6
|
+
<title>Workflow Visualization with Order</title>
|
7
|
+
<script src="https://d3js.org/d3.v7.min.js"></script>
|
8
|
+
<style>
|
9
|
+
.node {
|
10
|
+
fill: steelblue;
|
11
|
+
stroke: black;
|
12
|
+
stroke-width: 1.5px;
|
13
|
+
cursor: pointer;
|
14
|
+
}
|
15
|
+
.node.selected {
|
16
|
+
fill: orange;
|
17
|
+
}
|
18
|
+
.link {
|
19
|
+
stroke: #ccc;
|
20
|
+
stroke-width: 2px;
|
21
|
+
opacity: 0.7;
|
22
|
+
}
|
23
|
+
.link.active {
|
24
|
+
stroke: orange;
|
25
|
+
stroke-width: 3px;
|
26
|
+
}
|
27
|
+
text {
|
28
|
+
font-size: 12px;
|
29
|
+
fill: black;
|
30
|
+
}
|
31
|
+
.order {
|
32
|
+
font-size: 10px;
|
33
|
+
fill: white;
|
34
|
+
font-weight: bold;
|
35
|
+
}
|
36
|
+
</style>
|
37
|
+
</head>
|
38
|
+
<body>
|
39
|
+
<svg id="graph" width="800" height="600"></svg>
|
40
|
+
<script src="script.js"></script>
|
41
|
+
</body>
|
42
|
+
</html>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { deepseek } from "@ai-sdk/deepseek";
|
2
|
+
import { configDotenv } from "dotenv";
|
3
|
+
import { DynamicConditionGenerator } from "./index";
|
4
|
+
|
5
|
+
const schema = `{
|
6
|
+
"type": "object",
|
7
|
+
"properties": {
|
8
|
+
"volume": { "type": "number" }
|
9
|
+
},
|
10
|
+
"required": ["volume"]
|
11
|
+
}`;
|
12
|
+
|
13
|
+
const testData = {
|
14
|
+
volume: 100000,
|
15
|
+
};
|
16
|
+
|
17
|
+
configDotenv();
|
18
|
+
|
19
|
+
async function example() {
|
20
|
+
const generator = new DynamicConditionGenerator(
|
21
|
+
deepseek("deepseek-reasoner")
|
22
|
+
);
|
23
|
+
|
24
|
+
const result = await generator.generateCondition(
|
25
|
+
schema,
|
26
|
+
"check all pools with more than 100k volume",
|
27
|
+
{
|
28
|
+
functionName: "tradingCondition",
|
29
|
+
testData,
|
30
|
+
}
|
31
|
+
);
|
32
|
+
|
33
|
+
console.log("Generated function:", result);
|
34
|
+
}
|
35
|
+
|
36
|
+
example();
|
@@ -0,0 +1,108 @@
|
|
1
|
+
import { generateText, LanguageModel } from "ai";
|
2
|
+
import { z } from "zod";
|
3
|
+
import { LLMHeaderBuilder } from "../../utils/header-builder";
|
4
|
+
|
5
|
+
// Define the schema for condition validation
|
6
|
+
const conditionSchema = z.object({
|
7
|
+
function: z.string().describe("The generated dynamic condition function"),
|
8
|
+
testResult: z
|
9
|
+
.boolean()
|
10
|
+
.optional()
|
11
|
+
.describe("The test result if test data provided"),
|
12
|
+
});
|
13
|
+
|
14
|
+
export interface DynamicConditionConfig {
|
15
|
+
functionName?: string;
|
16
|
+
testData?: Record<string, any>;
|
17
|
+
}
|
18
|
+
|
19
|
+
export class DynamicConditionGenerator {
|
20
|
+
private readonly model: LanguageModel;
|
21
|
+
|
22
|
+
constructor(model: LanguageModel) {
|
23
|
+
this.model = model;
|
24
|
+
}
|
25
|
+
|
26
|
+
/** Generate a JavaScript function named dynamicCondition that takes an object matching this schema and returns true following the prompt.
|
27
|
+
The function must name 'dynamicCondition(data)' dynamically adapt to this schema. If fields are missing or do not match the schema, it should return false.
|
28
|
+
Only return one JavaScript function code.
|
29
|
+
|
30
|
+
BAD EXAMPLE:
|
31
|
+
\`\`\`javascript
|
32
|
+
function dynamicCondition(data) {
|
33
|
+
return data.amount > 0.1 && data.status === "completed";
|
34
|
+
}
|
35
|
+
\`\`\`
|
36
|
+
|
37
|
+
GOOD EXAMPLE:
|
38
|
+
function dynamicCondition(data) {
|
39
|
+
return data.amount > 0.1 && data.status === "completed";
|
40
|
+
}
|
41
|
+
|
42
|
+
OUTPUT ONLY THE FUNCTION CODE, NO 'TRIPLE QUOTES' OR ANY OTHER TEXT. ONLY THE FUNCTION CODE. */
|
43
|
+
private buildContext(schema: string, config: DynamicConditionConfig) {
|
44
|
+
const context = LLMHeaderBuilder.create()
|
45
|
+
.addHeader(
|
46
|
+
"ROLE",
|
47
|
+
"Generate a JavaScript function named 'dynamicCondition(data)' that takes an object matching this schema and returns true following the prompt."
|
48
|
+
)
|
49
|
+
.addHeader("IMPORTANT", [
|
50
|
+
"The function must name 'dynamicCondition(data)'",
|
51
|
+
"If fields are missing or do not match the schema, it should return false.",
|
52
|
+
"Only return one JavaScript function code.",
|
53
|
+
"OUTPUT ONLY THE FUNCTION CODE, NO 'TRIPLE QUOTES' OR ANY OTHER TEXT. ONLY THE FUNCTION CODE.",
|
54
|
+
])
|
55
|
+
.addHeader(
|
56
|
+
"BAD EXAMPLE",
|
57
|
+
`\`\`\`javascript
|
58
|
+
function dynamicCondition(data) {
|
59
|
+
return data.amount > 0.1 && data.status === 'completed';
|
60
|
+
}
|
61
|
+
\`\`\``
|
62
|
+
)
|
63
|
+
.addHeader(
|
64
|
+
"GOOD EXAMPLE",
|
65
|
+
`
|
66
|
+
function dynamicCondition(data) {
|
67
|
+
return data.amount > 0.1 && data.status === 'completed';
|
68
|
+
}`
|
69
|
+
)
|
70
|
+
.addHeader("SCHEMA", schema)
|
71
|
+
.addHeader("FUNCTION_NAME", config.functionName || "dynamicCondition");
|
72
|
+
|
73
|
+
return context.toString();
|
74
|
+
}
|
75
|
+
|
76
|
+
async generateCondition(
|
77
|
+
schema: string,
|
78
|
+
condition: string,
|
79
|
+
config: DynamicConditionConfig = {}
|
80
|
+
) {
|
81
|
+
try {
|
82
|
+
const context = this.buildContext(schema, config);
|
83
|
+
|
84
|
+
const result = await generateText({
|
85
|
+
model: this.model,
|
86
|
+
system: context.toString(),
|
87
|
+
prompt: `Generate a function that validates this condition: ${condition}`,
|
88
|
+
temperature: 0,
|
89
|
+
});
|
90
|
+
|
91
|
+
// Test the generated function if test data is provided
|
92
|
+
if (config.testData) {
|
93
|
+
try {
|
94
|
+
const functionEval = eval(`(${result.text})`);
|
95
|
+
const testResult = functionEval(config.testData);
|
96
|
+
console.log("Test result:", testResult);
|
97
|
+
} catch (error) {
|
98
|
+
console.error("Error testing function:", error);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
return result.text;
|
103
|
+
} catch (error) {
|
104
|
+
console.error("Error generating condition:", error);
|
105
|
+
throw error;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|