@astrive-ai/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/dist/astrive-ai.d.ts +30 -0
- package/dist/astrive-ai.d.ts.map +1 -0
- package/dist/astrive-ai.js +298 -0
- package/dist/astrive-ai.js.map +1 -0
- package/dist/conversation-manager.d.ts +16 -0
- package/dist/conversation-manager.d.ts.map +1 -0
- package/dist/conversation-manager.js +47 -0
- package/dist/conversation-manager.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/multi-agent.d.ts +14 -0
- package/dist/multi-agent.d.ts.map +1 -0
- package/dist/multi-agent.js +58 -0
- package/dist/multi-agent.js.map +1 -0
- package/dist/plugin-manager.d.ts +10 -0
- package/dist/plugin-manager.d.ts.map +1 -0
- package/dist/plugin-manager.js +34 -0
- package/dist/plugin-manager.js.map +1 -0
- package/dist/reflection.d.ts +15 -0
- package/dist/reflection.d.ts.map +1 -0
- package/dist/reflection.js +51 -0
- package/dist/reflection.js.map +1 -0
- package/package.json +30 -0
- package/src/astrive-ai.ts +357 -0
- package/src/conversation-manager.ts +67 -0
- package/src/index.ts +5 -0
- package/src/multi-agent.ts +75 -0
- package/src/plugin-manager.ts +42 -0
- package/src/reflection.ts +70 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export class ReflectionEngine {
|
|
2
|
+
async reflect(response, context) {
|
|
3
|
+
const review = await this.reviewResponse(response, context.provider);
|
|
4
|
+
if (review.hasIssues) {
|
|
5
|
+
const prompt = `The previous response to "${context.originalInput}" had issues. Please improve it based on this feedback:
|
|
6
|
+
Issues: ${review.issues.join(", ")}
|
|
7
|
+
Suggestions: ${review.suggestions.join(", ")}
|
|
8
|
+
Original response: ${response}
|
|
9
|
+
|
|
10
|
+
Please provide the corrected response.`;
|
|
11
|
+
const improvedResponse = await context.provider.chat({
|
|
12
|
+
messages: [
|
|
13
|
+
{ role: "system", content: "You are an expert editor who improves responses based on feedback. Provide ONLY the improved response." },
|
|
14
|
+
{ role: "user", content: prompt }
|
|
15
|
+
],
|
|
16
|
+
model: "llama-3.3-70b-versatile"
|
|
17
|
+
});
|
|
18
|
+
return improvedResponse.content || response;
|
|
19
|
+
}
|
|
20
|
+
return response;
|
|
21
|
+
}
|
|
22
|
+
async reviewResponse(response, provider) {
|
|
23
|
+
const prompt = `Review the following response for accuracy, clarity, and completeness.
|
|
24
|
+
Response: "${response}"
|
|
25
|
+
|
|
26
|
+
Provide your review in the following JSON format ONLY:
|
|
27
|
+
{
|
|
28
|
+
"hasIssues": boolean,
|
|
29
|
+
"issues": ["list of specific issues"],
|
|
30
|
+
"suggestions": ["list of actionable suggestions to fix issues"]
|
|
31
|
+
}`;
|
|
32
|
+
try {
|
|
33
|
+
const reviewResponse = await provider.chat({
|
|
34
|
+
messages: [
|
|
35
|
+
{ role: "system", content: "You are a critical reviewer. Always respond with valid JSON matching the requested schema." },
|
|
36
|
+
{ role: "user", content: prompt }
|
|
37
|
+
],
|
|
38
|
+
model: "llama-3.3-70b-versatile"
|
|
39
|
+
});
|
|
40
|
+
const content = (reviewResponse.content || "").trim();
|
|
41
|
+
const jsonStart = content.indexOf('{');
|
|
42
|
+
const jsonEnd = content.lastIndexOf('}') + 1;
|
|
43
|
+
const jsonString = content.slice(jsonStart, jsonEnd);
|
|
44
|
+
return JSON.parse(jsonString);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
return { hasIssues: false, issues: [], suggestions: [] };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=reflection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reflection.js","sourceRoot":"","sources":["../src/reflection.ts"],"names":[],"mappings":"AAaA,MAAM,OAAO,gBAAgB;IACpB,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,OAA0B;QAC/D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QAErE,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,6BAA6B,OAAO,CAAC,aAAa;UAC7D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;eACnB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;qBACvB,QAAQ;;uCAEU,CAAC;YAElC,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACnD,QAAQ,EAAE;oBACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,wGAAwG,EAAE;oBACrI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;iBAClC;gBACD,KAAK,EAAE,yBAAyB;aACjC,CAAC,CAAC;YAEH,OAAO,gBAAgB,CAAC,OAAO,IAAI,QAAQ,CAAC;QAC9C,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,QAAmB;QAChE,MAAM,MAAM,GAAG;aACN,QAAQ;;;;;;;EAOnB,CAAC;QAEC,IAAI,CAAC;YACH,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;gBACzC,QAAQ,EAAE;oBACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,4FAA4F,EAAE;oBACzH,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;iBAClC;gBACD,KAAK,EAAE,yBAAyB;aACjC,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,CAAC,cAAc,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACtD,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACvC,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC7C,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAErD,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAiB,CAAC;QAChD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;QAC3D,CAAC;IACH,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@astrive-ai/agent",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@astrive-ai/types": "*",
|
|
19
|
+
"@astrive-ai/logger": "*",
|
|
20
|
+
"@astrive-ai/events": "*",
|
|
21
|
+
"@astrive-ai/core": "*",
|
|
22
|
+
"@astrive-ai/providers": "*",
|
|
23
|
+
"@astrive-ai/planner": "*",
|
|
24
|
+
"@astrive-ai/memory": "*",
|
|
25
|
+
"@astrive-ai/tools": "*"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "5.4.5"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AstriveConfig,
|
|
3
|
+
IAgent,
|
|
4
|
+
ChatInput,
|
|
5
|
+
ChatOptions,
|
|
6
|
+
AgentResponse,
|
|
7
|
+
AgentStreamChunk,
|
|
8
|
+
IPlugin,
|
|
9
|
+
ITool,
|
|
10
|
+
PluginContext,
|
|
11
|
+
IProvider,
|
|
12
|
+
Message,
|
|
13
|
+
ResponseMetadata,
|
|
14
|
+
ToolDefinition,
|
|
15
|
+
ToolResult
|
|
16
|
+
} from "@astrive-ai/types";
|
|
17
|
+
import { Logger } from "@astrive-ai/logger";
|
|
18
|
+
import { EventEmitter } from "@astrive-ai/events";
|
|
19
|
+
import { ProviderManager, GroqProvider } from "@astrive-ai/providers";
|
|
20
|
+
import { ToolRegistry, MiddlewarePipeline, ToolExecutor } from "@astrive-ai/core";
|
|
21
|
+
import { MemoryManager } from "@astrive-ai/memory";
|
|
22
|
+
import { LLMPlanner, SimplePlanner } from "@astrive-ai/planner";
|
|
23
|
+
import * as BuiltInTools from "@astrive-ai/tools";
|
|
24
|
+
import { ConversationManager } from "./conversation-manager.js";
|
|
25
|
+
import { PluginManager } from "./plugin-manager.js";
|
|
26
|
+
import { ReflectionEngine } from "./reflection.js";
|
|
27
|
+
import { randomUUID } from "node:crypto";
|
|
28
|
+
|
|
29
|
+
type ToolFactory = () => ITool;
|
|
30
|
+
|
|
31
|
+
export class AstriveAI implements IAgent {
|
|
32
|
+
private config: AstriveConfig;
|
|
33
|
+
private logger: Logger;
|
|
34
|
+
private events: EventEmitter;
|
|
35
|
+
private providerManager: ProviderManager;
|
|
36
|
+
private toolRegistry: ToolRegistry;
|
|
37
|
+
private memoryManager: MemoryManager;
|
|
38
|
+
private middlewarePipeline: MiddlewarePipeline;
|
|
39
|
+
private toolExecutor: ToolExecutor;
|
|
40
|
+
private planner: LLMPlanner | SimplePlanner;
|
|
41
|
+
private conversationManager: ConversationManager;
|
|
42
|
+
private pluginManager: PluginManager;
|
|
43
|
+
private reflectionEngine: ReflectionEngine;
|
|
44
|
+
private initialized = false;
|
|
45
|
+
|
|
46
|
+
constructor(config: AstriveConfig) {
|
|
47
|
+
this.config = config;
|
|
48
|
+
this.logger = new Logger(config.logger || { level: 'info', prefix: 'Astrive', colors: true, timestamp: true });
|
|
49
|
+
this.events = new EventEmitter();
|
|
50
|
+
|
|
51
|
+
this.providerManager = new ProviderManager();
|
|
52
|
+
if (config.providers?.groq?.apiKey) {
|
|
53
|
+
const groq = new GroqProvider(this.logger, this.events);
|
|
54
|
+
this.providerManager.register(groq);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.toolRegistry = new ToolRegistry(this.events);
|
|
58
|
+
|
|
59
|
+
const toolClasses = [
|
|
60
|
+
BuiltInTools.DownloaderTool,
|
|
61
|
+
BuiltInTools.VisionTool,
|
|
62
|
+
BuiltInTools.TextToImageTool,
|
|
63
|
+
BuiltInTools.RemoveBGTool,
|
|
64
|
+
BuiltInTools.UpscalerTool,
|
|
65
|
+
BuiltInTools.OCRTool,
|
|
66
|
+
BuiltInTools.FaceSwapTool,
|
|
67
|
+
BuiltInTools.Img2ImgTool,
|
|
68
|
+
BuiltInTools.TextToSpeechTool,
|
|
69
|
+
BuiltInTools.SpeechToTextTool,
|
|
70
|
+
BuiltInTools.WebSearchTool,
|
|
71
|
+
BuiltInTools.FilesystemTool,
|
|
72
|
+
BuiltInTools.TerminalTool,
|
|
73
|
+
BuiltInTools.GitTool,
|
|
74
|
+
];
|
|
75
|
+
for (const ToolClass of toolClasses) {
|
|
76
|
+
if (ToolClass) {
|
|
77
|
+
this.toolRegistry.register(new ToolClass());
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.memoryManager = new MemoryManager(config.memory || {}, this.logger, this.events);
|
|
82
|
+
this.middlewarePipeline = new MiddlewarePipeline();
|
|
83
|
+
this.toolExecutor = new ToolExecutor(this.toolRegistry, this.events, this.logger);
|
|
84
|
+
|
|
85
|
+
this.conversationManager = new ConversationManager();
|
|
86
|
+
this.pluginManager = new PluginManager();
|
|
87
|
+
this.reflectionEngine = new ReflectionEngine();
|
|
88
|
+
|
|
89
|
+
this.planner = new SimplePlanner();
|
|
90
|
+
|
|
91
|
+
this.initialized = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public async init() {
|
|
95
|
+
await this.providerManager.initAll(this.config.providers || {});
|
|
96
|
+
const providers = this.providerManager.getAll();
|
|
97
|
+
if (providers.length > 0) {
|
|
98
|
+
this.planner = new LLMPlanner(providers[0], this.logger, this.events);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public async chat(input: string | ChatInput, options?: ChatOptions): Promise<AgentResponse> {
|
|
103
|
+
if (!this.initialized) {
|
|
104
|
+
throw new Error("Agent not initialized");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const startTime = Date.now();
|
|
108
|
+
const chatInput: ChatInput = typeof input === "string" ? { message: input, sessionId: (options as any)?.sessionId } : input;
|
|
109
|
+
const sessionId = chatInput.sessionId || "default";
|
|
110
|
+
|
|
111
|
+
let providerName = "groq";
|
|
112
|
+
if (options && 'provider' in options && options.provider) {
|
|
113
|
+
providerName = options.provider;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let provider: IProvider;
|
|
117
|
+
try {
|
|
118
|
+
provider = this.providerManager.selectProvider(providerName, "chat");
|
|
119
|
+
} catch (e) {
|
|
120
|
+
const providers = this.providerManager.getAll();
|
|
121
|
+
if (providers.length > 0) {
|
|
122
|
+
provider = providers[0];
|
|
123
|
+
} else {
|
|
124
|
+
throw new Error(`Provider ${providerName} not found`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this.conversationManager.addMessage(sessionId, { role: "user", content: chatInput.message });
|
|
129
|
+
|
|
130
|
+
let memoryContext = "";
|
|
131
|
+
if (this.config.memory?.enabled) {
|
|
132
|
+
memoryContext = await this.memoryManager.getRelevantContext(chatInput.message, 5);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const messages = this.conversationManager.buildMessages(sessionId, this.config.systemPrompt, memoryContext);
|
|
136
|
+
const tools = this.toolRegistry.getAll();
|
|
137
|
+
const toolDefinitions = this.toolRegistry.getDefinitions();
|
|
138
|
+
|
|
139
|
+
let response: AgentResponse;
|
|
140
|
+
const planningEnabled = options?.planning !== false && tools.length > 0;
|
|
141
|
+
let stepsExecuted = 0;
|
|
142
|
+
|
|
143
|
+
const callProvider = async (msgs: Message[], toolsList?: ToolDefinition[]) => {
|
|
144
|
+
return await provider.chat({
|
|
145
|
+
messages: msgs,
|
|
146
|
+
model: options?.model || "llama-3.3-70b-versatile",
|
|
147
|
+
temperature: options?.temperature || 0.7,
|
|
148
|
+
maxTokens: options?.maxTokens || 2048,
|
|
149
|
+
tools: toolsList && toolsList.length > 0 ? toolsList : undefined
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
if (planningEnabled) {
|
|
154
|
+
const initialResponse = await callProvider(messages, toolDefinitions);
|
|
155
|
+
stepsExecuted++;
|
|
156
|
+
|
|
157
|
+
if (initialResponse.toolCalls && initialResponse.toolCalls.length > 0) {
|
|
158
|
+
const toolResults = [];
|
|
159
|
+
|
|
160
|
+
const assistantMessage: Message = {
|
|
161
|
+
role: "assistant",
|
|
162
|
+
content: initialResponse.content || "",
|
|
163
|
+
tool_calls: initialResponse.toolCalls as any
|
|
164
|
+
};
|
|
165
|
+
messages.push(assistantMessage);
|
|
166
|
+
this.conversationManager.addMessage(sessionId, assistantMessage);
|
|
167
|
+
|
|
168
|
+
for (const call of initialResponse.toolCalls) {
|
|
169
|
+
try {
|
|
170
|
+
const args = typeof call.arguments === 'string'
|
|
171
|
+
? JSON.parse(call.arguments)
|
|
172
|
+
: call.arguments;
|
|
173
|
+
|
|
174
|
+
const result = await this.toolExecutor.execute({
|
|
175
|
+
id: call.id,
|
|
176
|
+
name: call.name,
|
|
177
|
+
arguments: args
|
|
178
|
+
});
|
|
179
|
+
const finalToolResult: ToolResult = result.result || { success: false, data: result.error, contentType: 'text' };
|
|
180
|
+
toolResults.push(finalToolResult);
|
|
181
|
+
|
|
182
|
+
const toolMsg: Message = {
|
|
183
|
+
role: "tool",
|
|
184
|
+
content: JSON.stringify(result.result || { error: result.error }),
|
|
185
|
+
tool_call_id: call.id
|
|
186
|
+
};
|
|
187
|
+
messages.push(toolMsg);
|
|
188
|
+
this.conversationManager.addMessage(sessionId, toolMsg);
|
|
189
|
+
stepsExecuted++;
|
|
190
|
+
} catch (error) {
|
|
191
|
+
const toolMsg: Message = {
|
|
192
|
+
role: "tool",
|
|
193
|
+
content: JSON.stringify({ error: (error as Error).message }),
|
|
194
|
+
tool_call_id: call.id
|
|
195
|
+
};
|
|
196
|
+
messages.push(toolMsg);
|
|
197
|
+
this.conversationManager.addMessage(sessionId, toolMsg);
|
|
198
|
+
stepsExecuted++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const finalResponse = await callProvider(messages);
|
|
203
|
+
stepsExecuted++;
|
|
204
|
+
|
|
205
|
+
const metadata: ResponseMetadata = {
|
|
206
|
+
conversationId: sessionId,
|
|
207
|
+
model: finalResponse.model,
|
|
208
|
+
provider: provider.name,
|
|
209
|
+
executionTime: Date.now() - startTime,
|
|
210
|
+
stepsExecuted
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
response = {
|
|
214
|
+
content: finalResponse.content,
|
|
215
|
+
toolResults,
|
|
216
|
+
usage: finalResponse.usage,
|
|
217
|
+
metadata
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
this.conversationManager.addMessage(sessionId, { role: "assistant", content: response.content });
|
|
221
|
+
} else {
|
|
222
|
+
const metadata: ResponseMetadata = {
|
|
223
|
+
conversationId: sessionId,
|
|
224
|
+
model: initialResponse.model,
|
|
225
|
+
provider: provider.name,
|
|
226
|
+
executionTime: Date.now() - startTime,
|
|
227
|
+
stepsExecuted
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
response = {
|
|
231
|
+
content: initialResponse.content,
|
|
232
|
+
usage: initialResponse.usage,
|
|
233
|
+
metadata
|
|
234
|
+
};
|
|
235
|
+
this.conversationManager.addMessage(sessionId, { role: "assistant", content: response.content });
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
const rawResponse = await callProvider(messages);
|
|
239
|
+
stepsExecuted++;
|
|
240
|
+
const metadata: ResponseMetadata = {
|
|
241
|
+
conversationId: sessionId,
|
|
242
|
+
model: rawResponse.model,
|
|
243
|
+
provider: provider.name,
|
|
244
|
+
executionTime: Date.now() - startTime,
|
|
245
|
+
stepsExecuted
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
response = {
|
|
249
|
+
content: rawResponse.content,
|
|
250
|
+
usage: rawResponse.usage,
|
|
251
|
+
metadata
|
|
252
|
+
};
|
|
253
|
+
this.conversationManager.addMessage(sessionId, { role: "assistant", content: response.content });
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (this.config.memory?.enabled) {
|
|
257
|
+
await this.memoryManager.extractAndSaveMemories([{ role: "user", content: chatInput.message }, { role: "assistant", content: response.content }]);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return response;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
public async *chatStream(input: string | ChatInput, options?: ChatOptions): AsyncGenerator<AgentStreamChunk> {
|
|
264
|
+
if (!this.initialized) {
|
|
265
|
+
throw new Error("Agent not initialized");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const chatInput = typeof input === "string" ? { message: input, sessionId: (options as any)?.sessionId } : input;
|
|
269
|
+
const sessionId = chatInput.sessionId || "default";
|
|
270
|
+
|
|
271
|
+
let providerName = "groq";
|
|
272
|
+
if (options && 'provider' in options && options.provider) {
|
|
273
|
+
providerName = options.provider;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
let provider: IProvider;
|
|
277
|
+
try {
|
|
278
|
+
provider = this.providerManager.selectProvider(providerName, "chat");
|
|
279
|
+
} catch (e) {
|
|
280
|
+
const providers = this.providerManager.getAll();
|
|
281
|
+
if (providers.length > 0) provider = providers[0];
|
|
282
|
+
else throw new Error(`Provider ${providerName} not found`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
this.conversationManager.addMessage(sessionId, { role: "user", content: chatInput.message });
|
|
286
|
+
const messages = this.conversationManager.buildMessages(sessionId, this.config.systemPrompt);
|
|
287
|
+
|
|
288
|
+
if (!provider.chatStream) throw new Error("Provider does not support streaming");
|
|
289
|
+
const stream = await provider.chatStream({
|
|
290
|
+
messages,
|
|
291
|
+
model: options?.model || "llama-3.3-70b-versatile",
|
|
292
|
+
temperature: options?.temperature || 0.7,
|
|
293
|
+
maxTokens: options?.maxTokens || 2048
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
let fullContent = "";
|
|
297
|
+
|
|
298
|
+
for await (const chunk of stream) {
|
|
299
|
+
if (chunk.content) {
|
|
300
|
+
fullContent += chunk.content;
|
|
301
|
+
yield { type: "text", content: chunk.content };
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
this.conversationManager.addMessage(sessionId, { role: "assistant", content: fullContent });
|
|
306
|
+
yield { type: "done" };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
public async use(plugin: IPlugin): Promise<void> {
|
|
310
|
+
const context: PluginContext = {
|
|
311
|
+
agent: this,
|
|
312
|
+
config: this.config as any,
|
|
313
|
+
logger: this.logger,
|
|
314
|
+
events: this.events,
|
|
315
|
+
registerTool: (t) => this.toolRegistry.register(t),
|
|
316
|
+
registerProvider: (p) => this.providerManager.register(p),
|
|
317
|
+
registerMiddleware: (m) => this.middlewarePipeline.use(m)
|
|
318
|
+
};
|
|
319
|
+
await this.pluginManager.install(plugin, context);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
public provider(provider: IProvider): void {
|
|
323
|
+
this.providerManager.register(provider);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
public tool(tool: ITool | ToolFactory): void {
|
|
327
|
+
if (typeof tool === 'function') {
|
|
328
|
+
this.toolRegistry.register(tool());
|
|
329
|
+
} else {
|
|
330
|
+
this.toolRegistry.register(tool);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
public getTools(): ITool[] {
|
|
335
|
+
return this.toolRegistry.getAll();
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
public getProviders(): IProvider[] {
|
|
339
|
+
return this.providerManager.getAll();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
public async destroy(): Promise<void> {
|
|
343
|
+
await this.pluginManager.destroyAll();
|
|
344
|
+
|
|
345
|
+
for (const provider of this.providerManager.getAll()) {
|
|
346
|
+
if (typeof (provider as any).destroy === 'function') {
|
|
347
|
+
await (provider as any).destroy();
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
this.initialized = false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export function createAgent(config: AstriveConfig): IAgent {
|
|
356
|
+
return new AstriveAI(config);
|
|
357
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Message } from "@astrive-ai/types";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
|
|
4
|
+
export interface ConversationState {
|
|
5
|
+
id: string;
|
|
6
|
+
messages: Message[];
|
|
7
|
+
systemPrompt?: string;
|
|
8
|
+
metadata?: Record<string, any>;
|
|
9
|
+
createdAt: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class ConversationManager {
|
|
13
|
+
private conversations: Map<string, ConversationState> = new Map();
|
|
14
|
+
|
|
15
|
+
public getOrCreate(sessionId?: string, systemPrompt?: string): ConversationState {
|
|
16
|
+
const id = sessionId || randomUUID();
|
|
17
|
+
let state = this.conversations.get(id);
|
|
18
|
+
|
|
19
|
+
if (!state) {
|
|
20
|
+
state = {
|
|
21
|
+
id,
|
|
22
|
+
messages: [],
|
|
23
|
+
systemPrompt,
|
|
24
|
+
createdAt: Date.now(),
|
|
25
|
+
};
|
|
26
|
+
this.conversations.set(id, state);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (systemPrompt && state.systemPrompt !== systemPrompt) {
|
|
30
|
+
state.systemPrompt = systemPrompt;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return state;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public addMessage(id: string, message: Message): void {
|
|
37
|
+
const state = this.conversations.get(id);
|
|
38
|
+
if (state) {
|
|
39
|
+
state.messages.push(message);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public getMessages(id: string): Message[] {
|
|
44
|
+
const state = this.conversations.get(id);
|
|
45
|
+
return state ? [...state.messages] : [];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public buildMessages(id: string, systemPrompt?: string, memoryContext?: string): Message[] {
|
|
49
|
+
const state = this.getOrCreate(id, systemPrompt);
|
|
50
|
+
const messages: Message[] = [];
|
|
51
|
+
|
|
52
|
+
const finalSystemPrompt = memoryContext
|
|
53
|
+
? `${state.systemPrompt || "You are a helpful AI assistant."}\n\nContext:\n${memoryContext}`
|
|
54
|
+
: state.systemPrompt;
|
|
55
|
+
|
|
56
|
+
if (finalSystemPrompt) {
|
|
57
|
+
messages.push({ role: "system", content: finalSystemPrompt });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Add all messages to the context. Tool messages and tool_calls are correctly maintained in the array.
|
|
61
|
+
for (const msg of state.messages) {
|
|
62
|
+
messages.push({ ...msg });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return messages;
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { IAgent, ChatInput, AgentResponse, ChatOptions } from '@astrive-ai/types';
|
|
2
|
+
|
|
3
|
+
export interface AgentTask {
|
|
4
|
+
description: string;
|
|
5
|
+
assignedRole: 'researcher' | 'coder' | 'creative' | 'reviewer' | 'validator' | 'custom';
|
|
6
|
+
dependencies?: string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class MultiAgentOrchestrator {
|
|
10
|
+
private agents: Map<string, IAgent> = new Map();
|
|
11
|
+
private plannerAgent: IAgent;
|
|
12
|
+
|
|
13
|
+
constructor(plannerAgent: IAgent) {
|
|
14
|
+
this.plannerAgent = plannerAgent;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public registerAgent(role: string, agent: IAgent): void {
|
|
18
|
+
this.agents.set(role, agent);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public async executeTask(task: string, options?: ChatOptions): Promise<AgentResponse> {
|
|
22
|
+
// 1. Planning phase
|
|
23
|
+
const planPrompt = `Break down the following task into sub-tasks assigned to different agent roles (researcher, coder, creative). Output JSON only.\nTask: ${task}`;
|
|
24
|
+
const planResponse = await this.plannerAgent.chat(planPrompt, { ...options, planning: false });
|
|
25
|
+
|
|
26
|
+
// In a real implementation, we would parse the JSON plan and execute the subtasks.
|
|
27
|
+
// For this prototype, we'll assume a linear flow if specific roles are registered.
|
|
28
|
+
|
|
29
|
+
let currentContext = `Original Task: ${task}\n\n`;
|
|
30
|
+
let finalResponse: AgentResponse | null = null;
|
|
31
|
+
|
|
32
|
+
// 2. Execution phase - Researcher
|
|
33
|
+
if (this.agents.has('researcher')) {
|
|
34
|
+
const researcher = this.agents.get('researcher')!;
|
|
35
|
+
const res = await researcher.chat(`Research the following task and provide context:\n${currentContext}`, options);
|
|
36
|
+
currentContext += `Research Results:\n${res.content}\n\n`;
|
|
37
|
+
finalResponse = res;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 3. Execution phase - Coder or Creative
|
|
41
|
+
if (this.agents.has('coder')) {
|
|
42
|
+
const coder = this.agents.get('coder')!;
|
|
43
|
+
const res = await coder.chat(`Based on the context, write the necessary code:\n${currentContext}`, options);
|
|
44
|
+
currentContext += `Code Results:\n${res.content}\n\n`;
|
|
45
|
+
finalResponse = res;
|
|
46
|
+
} else if (this.agents.has('creative')) {
|
|
47
|
+
const creative = this.agents.get('creative')!;
|
|
48
|
+
const res = await creative.chat(`Based on the context, create the required content:\n${currentContext}`, options);
|
|
49
|
+
currentContext += `Creative Results:\n${res.content}\n\n`;
|
|
50
|
+
finalResponse = res;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 4. Review phase
|
|
54
|
+
if (this.agents.has('reviewer')) {
|
|
55
|
+
const reviewer = this.agents.get('reviewer')!;
|
|
56
|
+
const res = await reviewer.chat(`Review the following results and suggest improvements:\n${currentContext}`, options);
|
|
57
|
+
currentContext += `Review Results:\n${res.content}\n\n`;
|
|
58
|
+
finalResponse = res;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 5. Validation and Final Polish phase
|
|
62
|
+
if (this.agents.has('validator')) {
|
|
63
|
+
const validator = this.agents.get('validator')!;
|
|
64
|
+
const res = await validator.chat(`Validate the work and provide the final output to the user:\n${currentContext}`, options);
|
|
65
|
+
finalResponse = res;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!finalResponse) {
|
|
69
|
+
// Fallback if no specialized agents were registered
|
|
70
|
+
return await this.plannerAgent.chat(task, options);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return finalResponse;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IPlugin, PluginContext } from "@astrive-ai/types";
|
|
2
|
+
|
|
3
|
+
export class PluginManager {
|
|
4
|
+
private plugins: Map<string, IPlugin> = new Map();
|
|
5
|
+
|
|
6
|
+
public async install(plugin: IPlugin, context: PluginContext): Promise<void> {
|
|
7
|
+
if (this.plugins.has(plugin.name)) {
|
|
8
|
+
throw new Error(`Plugin ${plugin.name} is already installed`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
await plugin.install(context);
|
|
12
|
+
this.plugins.set(plugin.name, plugin);
|
|
13
|
+
|
|
14
|
+
if (plugin.onInit) {
|
|
15
|
+
await plugin.onInit();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public async uninstall(name: string): Promise<void> {
|
|
20
|
+
const plugin = this.plugins.get(name);
|
|
21
|
+
if (plugin) {
|
|
22
|
+
if (plugin.onDestroy) {
|
|
23
|
+
await plugin.onDestroy();
|
|
24
|
+
}
|
|
25
|
+
this.plugins.delete(name);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public async destroyAll(): Promise<void> {
|
|
30
|
+
for (const name of Array.from(this.plugins.keys())) {
|
|
31
|
+
await this.uninstall(name);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public getAll(): IPlugin[] {
|
|
36
|
+
return Array.from(this.plugins.values());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public has(name: string): boolean {
|
|
40
|
+
return this.plugins.has(name);
|
|
41
|
+
}
|
|
42
|
+
}
|