symposium 0.14.20 → 0.15.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.js +142 -96
- package/BufferedEventEmitter.js +28 -0
- package/Symposium.js +21 -42
- package/Thread.js +4 -7
- package/index.js +0 -2
- package/package.json +1 -1
- package/Interface.js +0 -15
- package/README.md +0 -152
- package/examples/ChatAgent.js +0 -21
- package/examples/MultiAgent.js +0 -115
- package/examples/TitlerAgent.js +0 -25
- package/examples/Tools/GenericTool.js +0 -42
- package/examples/Tools/MultiAgentTool.js +0 -77
package/Agent.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import {v7 as uuid} from 'uuid';
|
|
2
|
+
|
|
3
|
+
import BufferedEventEmitter from "./BufferedEventEmitter.js";
|
|
4
|
+
|
|
1
5
|
import Symposium from "./Symposium.js";
|
|
2
6
|
import Thread from "./Thread.js";
|
|
3
|
-
import {v7 as uuid} from 'uuid';
|
|
4
7
|
|
|
5
8
|
export default class Agent {
|
|
6
9
|
name = 'Agent';
|
|
@@ -11,13 +14,13 @@ export default class Agent {
|
|
|
11
14
|
tools = new Map();
|
|
12
15
|
default_model = 'gpt-4o';
|
|
13
16
|
max_retries = 5;
|
|
14
|
-
|
|
17
|
+
type = 'chat'; // chat, utility
|
|
15
18
|
utility = null;
|
|
19
|
+
initialized = false;
|
|
16
20
|
|
|
17
21
|
constructor(options) {
|
|
18
22
|
this.options = {
|
|
19
23
|
memory_handler: null,
|
|
20
|
-
interfaces: [],
|
|
21
24
|
...options,
|
|
22
25
|
};
|
|
23
26
|
|
|
@@ -25,11 +28,20 @@ export default class Agent {
|
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
async init() {
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
if (this.initialized)
|
|
32
|
+
return;
|
|
30
33
|
|
|
31
34
|
if (this.options.memory_handler)
|
|
32
35
|
this.options.memory_handler.setAgent(this);
|
|
36
|
+
|
|
37
|
+
if (this.type === 'utility') {
|
|
38
|
+
if (!this.utility || !this.utility.type)
|
|
39
|
+
throw new Error('Utility function not defined');
|
|
40
|
+
if (!['text', 'function', 'json'].includes(this.utility.type))
|
|
41
|
+
throw new Error('Bad utility definition');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.initialized = true;
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
async reset(thread) {
|
|
@@ -60,13 +72,10 @@ export default class Agent {
|
|
|
60
72
|
async doInitThread(thread) {
|
|
61
73
|
}
|
|
62
74
|
|
|
63
|
-
async getThread(id
|
|
75
|
+
async getThread(id) {
|
|
64
76
|
let thread = this.threads.get(id);
|
|
65
|
-
if (thread) {
|
|
66
|
-
|
|
67
|
-
throw new Error('Required thread is not from the same interface');
|
|
68
|
-
} else {
|
|
69
|
-
thread = new Thread(id, i, this);
|
|
77
|
+
if (!thread) {
|
|
78
|
+
thread = new Thread(id, this);
|
|
70
79
|
|
|
71
80
|
if (!(await thread.loadState())) {
|
|
72
81
|
await this.resetState(thread);
|
|
@@ -79,15 +88,14 @@ export default class Agent {
|
|
|
79
88
|
return thread;
|
|
80
89
|
}
|
|
81
90
|
|
|
82
|
-
async message(
|
|
83
|
-
if (
|
|
84
|
-
|
|
91
|
+
async message(content, thread = null) {
|
|
92
|
+
if (!this.initialized)
|
|
93
|
+
throw new Error('Agent not initialized');
|
|
85
94
|
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
95
|
+
if (thread === null)
|
|
96
|
+
thread = uuid();
|
|
97
|
+
if (typeof thread !== 'object')
|
|
98
|
+
thread = await this.getThread(thread);
|
|
91
99
|
|
|
92
100
|
const model = Symposium.getModelByName(thread.state.model);
|
|
93
101
|
if (!model.supports_audio && typeof content !== 'string') {
|
|
@@ -112,17 +120,14 @@ export default class Agent {
|
|
|
112
120
|
return thread;
|
|
113
121
|
}
|
|
114
122
|
|
|
115
|
-
async execute(thread, counter = 0) {
|
|
123
|
+
async execute(thread, counter = 0, existing_emitter = null) {
|
|
116
124
|
if (counter === 0)
|
|
117
125
|
thread = await this.beforeExecute(thread);
|
|
118
126
|
|
|
119
127
|
const model = Symposium.getModelByName(thread.state.model);
|
|
120
128
|
|
|
121
129
|
const completion_options = {};
|
|
122
|
-
if (this.utility) {
|
|
123
|
-
if (!['text', 'function', 'json'].includes(this.utility.type))
|
|
124
|
-
throw new Error('Bad utility definition');
|
|
125
|
-
|
|
130
|
+
if (this.type === 'utility') {
|
|
126
131
|
if (['function', 'json'].includes(this.utility.type)) {
|
|
127
132
|
if (!this.utility.function || !this.utility.function.name || !this.utility.function.parameters)
|
|
128
133
|
throw new Error('Bad function definition');
|
|
@@ -131,7 +136,7 @@ export default class Agent {
|
|
|
131
136
|
if (this.utility.type === 'json' && model.supports_structured_output)
|
|
132
137
|
response_format = this.convertFunctionToResponseFormat(this.utility.function.parameters);
|
|
133
138
|
|
|
134
|
-
if (response_format && response_format.count <= 100) { //
|
|
139
|
+
if (response_format && response_format.count <= 100) { // OpenAI does not support structured output if there are more than 100 parameters
|
|
135
140
|
completion_options.response_format = {
|
|
136
141
|
type: 'json_schema',
|
|
137
142
|
json_schema: {
|
|
@@ -149,30 +154,62 @@ export default class Agent {
|
|
|
149
154
|
}
|
|
150
155
|
}
|
|
151
156
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
let completion;
|
|
158
|
+
try {
|
|
159
|
+
completion = await this.generateCompletion(thread, completion_options);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
console.error(e.message);
|
|
162
|
+
switch (this.type) {
|
|
163
|
+
case 'chat':
|
|
164
|
+
const emitter = existing_emitter || new BufferedEventEmitter();
|
|
165
|
+
emitter.emit('error', e.message);
|
|
166
|
+
if (!existing_emitter)
|
|
167
|
+
emitter.emit('end');
|
|
168
|
+
return emitter;
|
|
169
|
+
|
|
170
|
+
case 'utility':
|
|
171
|
+
throw e;
|
|
172
|
+
|
|
173
|
+
default:
|
|
174
|
+
throw new Error('Bad agent type');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
160
177
|
|
|
161
|
-
|
|
162
|
-
|
|
178
|
+
try {
|
|
179
|
+
thread = await this.afterExecute(thread, completion);
|
|
180
|
+
const emitter = this.handleCompletion(thread, completion, existing_emitter);
|
|
181
|
+
|
|
182
|
+
switch (this.type) {
|
|
183
|
+
case 'utility':
|
|
184
|
+
return new Promise((resolve, reject) => {
|
|
185
|
+
emitter.on('data', data => {
|
|
186
|
+
const parsed = JSON.parse(data);
|
|
187
|
+
if (parsed.type === 'response')
|
|
188
|
+
resolve(parsed.content);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
emitter.on('error', error => reject(error));
|
|
192
|
+
});
|
|
163
193
|
|
|
164
|
-
|
|
165
|
-
|
|
194
|
+
case 'chat':
|
|
195
|
+
if (!existing_emitter) {
|
|
196
|
+
emitter.on('data', data => {
|
|
197
|
+
const parsed = JSON.parse(data);
|
|
198
|
+
if (parsed.type === 'response' && parsed.content.type === 'continue')
|
|
199
|
+
this.execute(thread, 0, emitter);
|
|
200
|
+
}, false);
|
|
201
|
+
}
|
|
166
202
|
|
|
167
|
-
|
|
168
|
-
throw new Error('Unknown response type');
|
|
169
|
-
}
|
|
170
|
-
} catch (e) {
|
|
171
|
-
console.error(e);
|
|
203
|
+
return emitter;
|
|
172
204
|
|
|
173
|
-
|
|
174
|
-
|
|
205
|
+
default:
|
|
206
|
+
throw new Error('Bad agent type');
|
|
175
207
|
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
console.error(e);
|
|
210
|
+
|
|
211
|
+
if (counter < this.max_retries)
|
|
212
|
+
await this.execute(thread, counter + 1, existing_emitter);
|
|
176
213
|
}
|
|
177
214
|
}
|
|
178
215
|
|
|
@@ -180,11 +217,16 @@ export default class Agent {
|
|
|
180
217
|
if (obj.type !== 'object')
|
|
181
218
|
return {obj, count: 0};
|
|
182
219
|
|
|
183
|
-
let properties_count = 0, required = [];
|
|
220
|
+
let properties_count = 0, all_required = false, required = [];
|
|
221
|
+
if (obj.required)
|
|
222
|
+
required = obj.required;
|
|
223
|
+
else
|
|
224
|
+
all_required = true;
|
|
184
225
|
|
|
185
226
|
for (let [key, property] of Object.entries(obj.properties || {})) {
|
|
186
227
|
properties_count++;
|
|
187
|
-
|
|
228
|
+
if (all_required)
|
|
229
|
+
required.push(key);
|
|
188
230
|
|
|
189
231
|
if (property.type === 'object') {
|
|
190
232
|
const {obj: subobj, count} = this.convertFunctionToResponseFormat(property);
|
|
@@ -232,43 +274,15 @@ export default class Agent {
|
|
|
232
274
|
return this.generateCompletion(thread, options, retry_counter + 1);
|
|
233
275
|
}
|
|
234
276
|
|
|
235
|
-
|
|
277
|
+
throw new Error(error.response.status + ': ' + JSON.stringify(error.response.data));
|
|
236
278
|
} else if (error.message) {
|
|
237
|
-
|
|
238
|
-
await this.error(thread, error.message);
|
|
279
|
+
throw new Error(error.message);
|
|
239
280
|
} else {
|
|
240
|
-
|
|
241
|
-
await this.error(thread, 'Errore interno');
|
|
281
|
+
throw new Error('Errore interno');
|
|
242
282
|
}
|
|
243
283
|
}
|
|
244
284
|
}
|
|
245
285
|
|
|
246
|
-
async error(thread, error) {
|
|
247
|
-
const i = this.options.interfaces.find(i => i.name === thread.interface);
|
|
248
|
-
if (i)
|
|
249
|
-
return i.error(thread, error);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
async output(thread, msg) {
|
|
253
|
-
if (this.callbacks.hasOwnProperty(thread.interface + '-' + thread.id) && this.callbacks[thread.interface + '-' + thread.id].length) {
|
|
254
|
-
const callback = this.callbacks[thread.interface + '-' + thread.id].shift();
|
|
255
|
-
await callback(msg);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const i = this.options.interfaces.find(i => i.name === thread.interface);
|
|
259
|
-
if (i)
|
|
260
|
-
return i.output(thread, msg);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async partial(thread, msg) {
|
|
264
|
-
if ((typeof msg) === 'text')
|
|
265
|
-
msg = {summary: msg};
|
|
266
|
-
|
|
267
|
-
const i = this.options.interfaces.find(i => i.name === thread.interface);
|
|
268
|
-
if (i)
|
|
269
|
-
return i.partial(thread, msg);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
286
|
parseFunctions(message) {
|
|
273
287
|
const newContent = [];
|
|
274
288
|
for (let m of message.content) {
|
|
@@ -294,9 +308,11 @@ export default class Agent {
|
|
|
294
308
|
return message;
|
|
295
309
|
}
|
|
296
310
|
|
|
297
|
-
async handleCompletion(thread, completion) {
|
|
311
|
+
async handleCompletion(thread, completion, existing_emitter = null) {
|
|
298
312
|
const model = Symposium.getModelByName(thread.state.model);
|
|
299
313
|
|
|
314
|
+
const emitter = existing_emitter || new BufferedEventEmitter();
|
|
315
|
+
|
|
300
316
|
const functions = [];
|
|
301
317
|
for (let message of completion) {
|
|
302
318
|
thread.addDirectMessage(message);
|
|
@@ -305,13 +321,21 @@ export default class Agent {
|
|
|
305
321
|
for (let m of message.content) {
|
|
306
322
|
switch (m.type) {
|
|
307
323
|
case 'text':
|
|
308
|
-
if (this.utility) {
|
|
324
|
+
if (this.type === 'utility') {
|
|
325
|
+
let response = null;
|
|
309
326
|
if (this.utility.type === 'text')
|
|
310
|
-
|
|
327
|
+
response = await this.afterHandle(thread, completion, 'return', m.content);
|
|
311
328
|
if (this.utility.type === 'json' && model.supports_structured_output)
|
|
312
|
-
|
|
329
|
+
response = await this.afterHandle(thread, completion, 'return', JSON.parse(m.content));
|
|
330
|
+
|
|
331
|
+
if (response) {
|
|
332
|
+
emitter.emit('data', JSON.stringify({type: 'response', content: response}));
|
|
333
|
+
emitter.emit('end');
|
|
334
|
+
return emitter;
|
|
335
|
+
}
|
|
313
336
|
}
|
|
314
|
-
|
|
337
|
+
|
|
338
|
+
emitter.emit('data', JSON.stringify({type: 'output', content: m.content}));
|
|
315
339
|
break;
|
|
316
340
|
|
|
317
341
|
case 'function':
|
|
@@ -322,28 +346,43 @@ export default class Agent {
|
|
|
322
346
|
}
|
|
323
347
|
}
|
|
324
348
|
|
|
349
|
+
let response;
|
|
325
350
|
if (functions.length) {
|
|
326
351
|
for (let f of functions) {
|
|
327
|
-
if (this.utility && ['function', 'json'].includes(this.utility.type))
|
|
328
|
-
|
|
352
|
+
if (this.utility && ['function', 'json'].includes(this.utility.type)) {
|
|
353
|
+
response = this.afterHandle(thread, completion, 'return', f.arguments);
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
329
356
|
|
|
330
|
-
const
|
|
357
|
+
const function_response = await this.callFunction(thread, f, emitter);
|
|
331
358
|
|
|
332
359
|
thread.addMessage('tool', [
|
|
333
360
|
{
|
|
334
361
|
type: 'function_response',
|
|
335
|
-
content: {name: f.name,
|
|
362
|
+
content: {name: f.name, function_response, id: f.id || undefined},
|
|
336
363
|
},
|
|
337
364
|
], f.name);
|
|
338
365
|
|
|
339
|
-
await this.log('function_response',
|
|
366
|
+
await this.log('function_response', function_response);
|
|
340
367
|
}
|
|
341
368
|
|
|
342
|
-
|
|
369
|
+
if (!response)
|
|
370
|
+
response = this.afterHandle(thread, completion, 'continue');
|
|
343
371
|
} else {
|
|
344
372
|
await thread.storeState();
|
|
345
|
-
|
|
373
|
+
response = this.afterHandle(thread, completion, 'void');
|
|
346
374
|
}
|
|
375
|
+
|
|
376
|
+
response
|
|
377
|
+
.then(content => {
|
|
378
|
+
emitter.emit('data', JSON.stringify({type: 'response', content}));
|
|
379
|
+
emitter.emit('end');
|
|
380
|
+
})
|
|
381
|
+
.catch(error => {
|
|
382
|
+
emitter.emit('error', error);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
return emitter;
|
|
347
386
|
}
|
|
348
387
|
|
|
349
388
|
async afterHandle(thread, completion, type, value = null) {
|
|
@@ -376,23 +415,23 @@ export default class Agent {
|
|
|
376
415
|
return this.functions;
|
|
377
416
|
}
|
|
378
417
|
|
|
379
|
-
async callFunction(thread, function_call) {
|
|
418
|
+
async callFunction(thread, function_call, emitter) {
|
|
380
419
|
const functions = await this.getFunctions(false);
|
|
381
420
|
if (!functions.has(function_call.name))
|
|
382
421
|
throw new Error('Unrecognized function ' + function_call.name);
|
|
383
422
|
|
|
384
423
|
const func = functions.get(function_call.name);
|
|
385
424
|
const partialOutput = func.partialOutput ? ((typeof func.partialOutput) === 'text' ? func.partialOutput : func.partialOutput.call(this, function_call.arguments)) : 'Uso lo strumento ' + function_call.name + '...';
|
|
386
|
-
|
|
425
|
+
emitter.emit('data', JSON.stringify({type: 'partial', content: partialOutput}));
|
|
387
426
|
|
|
388
427
|
await this.log('function_call', function_call);
|
|
389
428
|
|
|
390
429
|
try {
|
|
391
430
|
const response = await func.tool.callFunction(thread, function_call.name, function_call.arguments);
|
|
392
|
-
|
|
431
|
+
emitter.emit('data', JSON.stringify({type: 'partial', content: 'Risposta ricevuta da ' + func.tool.name}));
|
|
393
432
|
return response;
|
|
394
433
|
} catch (error) {
|
|
395
|
-
|
|
434
|
+
emitter.emit('data', JSON.stringify({type: 'partial', content: 'Ricevuto errore da ' + func.tool.name}));
|
|
396
435
|
return {error};
|
|
397
436
|
}
|
|
398
437
|
}
|
|
@@ -414,9 +453,15 @@ export default class Agent {
|
|
|
414
453
|
return [this.name];
|
|
415
454
|
}
|
|
416
455
|
|
|
417
|
-
async createRealtimeSession(thread_id = null,
|
|
456
|
+
async createRealtimeSession(thread_id = null, options = {}) {
|
|
457
|
+
options = {
|
|
458
|
+
include_thread: true,
|
|
459
|
+
language: 'it',
|
|
460
|
+
...options,
|
|
461
|
+
};
|
|
462
|
+
|
|
418
463
|
// Se viene passato un thread esistente, lo si usa, altrimenti si crea un nuovo thread temporaneo
|
|
419
|
-
const thread = await this.getThread(thread_id || uuid()
|
|
464
|
+
const thread = await this.getThread(thread_id || uuid());
|
|
420
465
|
|
|
421
466
|
const system_message = [], conversation = [];
|
|
422
467
|
for (let message of thread.messages) {
|
|
@@ -427,7 +472,7 @@ export default class Agent {
|
|
|
427
472
|
}
|
|
428
473
|
|
|
429
474
|
let instructions = system_message.join('\n');
|
|
430
|
-
if (conversation.length)
|
|
475
|
+
if (conversation.length && options.include_thread)
|
|
431
476
|
instructions += '\n\n# Ecco la tua conversazione fino ad ora: #\n' + conversation.join('\n');
|
|
432
477
|
|
|
433
478
|
const tools = (await this.getFunctions()).map(t => ({
|
|
@@ -447,6 +492,7 @@ export default class Agent {
|
|
|
447
492
|
tools,
|
|
448
493
|
input_audio_transcription: {
|
|
449
494
|
model: 'gpt-4o-transcribe',
|
|
495
|
+
language: options.language,
|
|
450
496
|
},
|
|
451
497
|
}),
|
|
452
498
|
}).then(response => response.json());
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import EventEmitter from 'events';
|
|
2
|
+
|
|
3
|
+
export default class BufferedEventEmitter extends EventEmitter {
|
|
4
|
+
#buffer = [];
|
|
5
|
+
|
|
6
|
+
emit(eventName, ...args) {
|
|
7
|
+
if (this.listenerCount(eventName) > 0)
|
|
8
|
+
return super.emit(eventName, ...args);
|
|
9
|
+
|
|
10
|
+
this.#buffer.push({eventName, args});
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#flush() {
|
|
15
|
+
for (const {eventName, args} of this.#buffer)
|
|
16
|
+
if (this.listenerCount(eventName) > 0)
|
|
17
|
+
super.emit(eventName, ...args);
|
|
18
|
+
|
|
19
|
+
this.#buffer = this.#buffer.filter(({eventName}) => this.listenerCount(eventName) === 0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
on(eventName, listener, flush = true) {
|
|
23
|
+
super.on(eventName, listener);
|
|
24
|
+
if (flush)
|
|
25
|
+
this.#flush();
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
}
|
package/Symposium.js
CHANGED
|
@@ -1,23 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import Gpt4 from "./models/Gpt4.js";
|
|
5
|
-
import Gpt4Turbo from "./models/Gpt4Turbo.js";
|
|
6
|
-
import Gpt4O from "./models/Gpt4O.js";
|
|
7
|
-
import GptO1 from "./models/GptO1.js";
|
|
8
|
-
import GptO1Mini from "./models/GptO1Mini.js";
|
|
9
|
-
import Gpt5 from "./models/Gpt5.js";
|
|
10
|
-
import Gpt5Mini from "./models/Gpt5Mini.js";
|
|
11
|
-
import Whisper from "./models/Whisper.js";
|
|
12
|
-
import Claude35Sonnet from "./models/Claude35Sonnet.js";
|
|
13
|
-
import Claude37Sonnet from "./models/Claude37Sonnet.js";
|
|
14
|
-
import Claude4Sonnet from "./models/Claude4Sonnet.js";
|
|
15
|
-
import Claude4Opus from "./models/Claude4Opus.js";
|
|
16
|
-
import Llama3 from "./models/Llama3.js";
|
|
17
|
-
import Mixtral8 from "./models/Mixtral8.js";
|
|
18
|
-
import DeepSeekChat from "./models/DeepSeekChat.js";
|
|
19
|
-
import DeepSeekReasoner from "./models/DeepSeekReasoner.js";
|
|
20
|
-
import Grok4 from "./models/Grok4.js";
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import {fileURLToPath} from 'url';
|
|
21
4
|
|
|
22
5
|
export default class Symposium {
|
|
23
6
|
static models = new Map();
|
|
@@ -31,28 +14,24 @@ export default class Symposium {
|
|
|
31
14
|
* - async set(key, value)
|
|
32
15
|
*/
|
|
33
16
|
static async init(storage = null) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.loadModel(new DeepSeekChat());
|
|
53
|
-
this.loadModel(new DeepSeekReasoner());
|
|
54
|
-
|
|
55
|
-
this.loadModel(new Grok4());
|
|
17
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
18
|
+
const __dirname = path.dirname(__filename);
|
|
19
|
+
const modelsPath = path.join(__dirname, 'models');
|
|
20
|
+
|
|
21
|
+
const modelFiles = await fs.promises.readdir(modelsPath);
|
|
22
|
+
for (const file of modelFiles) {
|
|
23
|
+
if (!file.endsWith('.js'))
|
|
24
|
+
continue;
|
|
25
|
+
|
|
26
|
+
const module = await import(`./models/${file}`);
|
|
27
|
+
const ModelClass = module.default;
|
|
28
|
+
if (ModelClass) {
|
|
29
|
+
const model = new ModelClass();
|
|
30
|
+
if (!model.name)
|
|
31
|
+
continue;
|
|
32
|
+
this.loadModel(model);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
56
35
|
|
|
57
36
|
if (storage) {
|
|
58
37
|
this.storage = storage;
|
|
@@ -97,7 +76,7 @@ export default class Symposium {
|
|
|
97
76
|
if (!audio.data)
|
|
98
77
|
throw new Error('Audio URL is required');
|
|
99
78
|
|
|
100
|
-
if (audio.data
|
|
79
|
+
if (path.isAbsolute(audio.data)) { // Local path
|
|
101
80
|
// Get with fs
|
|
102
81
|
if (!fs.existsSync(audio.data))
|
|
103
82
|
throw new Error('Audio file does not exist at the specified path: ' + audio.data);
|
package/Thread.js
CHANGED
|
@@ -7,18 +7,15 @@ export default class Thread {
|
|
|
7
7
|
agent;
|
|
8
8
|
messages = [];
|
|
9
9
|
state = {};
|
|
10
|
-
interface = null;
|
|
11
10
|
|
|
12
|
-
constructor(id,
|
|
11
|
+
constructor(id, agent) {
|
|
13
12
|
this.id = id;
|
|
14
|
-
this.unique = agent.name + '-' +
|
|
13
|
+
this.unique = agent.name + '-' + id;
|
|
15
14
|
this.agent = agent;
|
|
16
|
-
this.interface = i;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
clone(keepMessages = true) {
|
|
20
|
-
let newThread = new Thread(this.id, this.
|
|
21
|
-
newThread.interface = this.interface;
|
|
18
|
+
let newThread = new Thread(this.id, this.agent);
|
|
22
19
|
newThread.state = this.state;
|
|
23
20
|
if (keepMessages)
|
|
24
21
|
newThread.messages = [...this.messages];
|
|
@@ -27,7 +24,7 @@ export default class Thread {
|
|
|
27
24
|
|
|
28
25
|
changeId(id) {
|
|
29
26
|
this.id = id;
|
|
30
|
-
this.unique = this.agent.name + '-' +
|
|
27
|
+
this.unique = this.agent.name + '-' + id;
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
async flush() {
|
package/index.js
CHANGED
|
@@ -7,7 +7,6 @@ import Tool from "./Tool.js";
|
|
|
7
7
|
import Logger from "./Logger.js";
|
|
8
8
|
import MemoryHandler from "./MemoryHandler.js";
|
|
9
9
|
import Summarizer from "./Summarizer.js";
|
|
10
|
-
import Interface from "./Interface.js";
|
|
11
10
|
|
|
12
11
|
export {
|
|
13
12
|
Symposium,
|
|
@@ -17,5 +16,4 @@ export {
|
|
|
17
16
|
Logger,
|
|
18
17
|
MemoryHandler,
|
|
19
18
|
Summarizer,
|
|
20
|
-
Interface,
|
|
21
19
|
};
|
package/package.json
CHANGED
package/Interface.js
DELETED
package/README.md
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
# Symposium
|
|
2
|
-
|
|
3
|
-
Symposium is an npm library designed to simplify the deployment and management of AI agents. Its modular and flexible architecture makes it easy to create agents that can interact with users, execute functions through integrated tools, and manage complex conversation threads—all while supporting multiple language models from various providers.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Note: I am as lazy as all devs are, hence this README is written by an AI as well :)) I will improve it with time if needed
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Table of Contents
|
|
12
|
-
|
|
13
|
-
- [Overview](#overview)
|
|
14
|
-
- [Features](#features)
|
|
15
|
-
- [Installation](#installation)
|
|
16
|
-
- [Usage](#usage)
|
|
17
|
-
- [Architecture](#architecture)
|
|
18
|
-
- [Supported Models](#supported-models)
|
|
19
|
-
- [Extending Symposium](#extending-symposium)
|
|
20
|
-
- [Examples](#examples)
|
|
21
|
-
- [Contributing](#contributing)
|
|
22
|
-
- [License](#license)
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## Overview
|
|
27
|
-
|
|
28
|
-
Symposium provides a robust framework for deploying AI agents with ease. It handles message threading, state management, logging, and even conversation summarization to keep interactions within token limits. With built-in support for multiple AI models and a plugin-like system for tools, Symposium enables developers to quickly build sophisticated agent-based applications.
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## Features
|
|
33
|
-
|
|
34
|
-
- **Agent Management**: Create and manage agents that process user messages and execute actions.
|
|
35
|
-
- **Tool Integration**: Extend your agents’ capabilities by integrating custom tools with defined functions.
|
|
36
|
-
- **Thread & Memory Handling**: Manage conversation state and threads seamlessly, with automatic summarization support.
|
|
37
|
-
- **Multi-Agent Coordination**: Support for multi-agent systems to allow agents to collaborate and share tasks.
|
|
38
|
-
- **Flexible Model Support**: Out-of-the-box compatibility with various models including OpenAI, Anthropic, Groq, and DeepSeek.
|
|
39
|
-
- **Structured Function Calls**: Enable agents to call functions using structured output, ensuring clarity and consistency.
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## Installation
|
|
44
|
-
|
|
45
|
-
Install Symposium via npm:
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
npm install symposium
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## Usage
|
|
54
|
-
|
|
55
|
-
Below is a basic example of how to create a custom agent using Symposium:
|
|
56
|
-
|
|
57
|
-
```js
|
|
58
|
-
import { Symposium, Agent } from 'symposium';
|
|
59
|
-
|
|
60
|
-
class MyAgent extends Agent {
|
|
61
|
-
constructor(options = {}) {
|
|
62
|
-
super(options);
|
|
63
|
-
this.name = 'MyAgent';
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async doInitThread(thread) {
|
|
67
|
-
await thread.addMessage('system', 'Welcome! How can I assist you today?');
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
(async () => {
|
|
72
|
-
const myAgent = new MyAgent();
|
|
73
|
-
await myAgent.init();
|
|
74
|
-
|
|
75
|
-
const thread = await myAgent.getThread('example-thread');
|
|
76
|
-
await myAgent.message(thread, 'default', 'Hello, agent!');
|
|
77
|
-
})();
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Architecture
|
|
83
|
-
|
|
84
|
-
Symposium is built around several core components:
|
|
85
|
-
|
|
86
|
-
- **Agent**: The base class for creating agents. Agents process messages, manage threads, and interact with tools.
|
|
87
|
-
- **Tool**: Extend functionality by integrating custom functions. Tools define their own functions and provide implementations through the `callFunction` method.
|
|
88
|
-
- **Thread**: Represents a conversation, handling message storage, state management, and persistence.
|
|
89
|
-
- **Logger & MemoryHandler**: Utilities for logging events and managing conversation memory, respectively.
|
|
90
|
-
- **Summarizer**: A specialized memory handler that summarizes conversation threads to maintain context within token limits.
|
|
91
|
-
- **Interface**: Abstracts output and error handling, enabling custom integrations with external systems.
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## Supported Models
|
|
96
|
-
|
|
97
|
-
Symposium supports a variety of AI models, allowing you to switch between them based on your needs:
|
|
98
|
-
|
|
99
|
-
- **OpenAI Models**:
|
|
100
|
-
- GPT-3.5-turbo
|
|
101
|
-
- GPT-4, GPT-4Turbo, GPT-4o
|
|
102
|
-
- GPT-o1, GPT-o1 mini
|
|
103
|
-
- **Anthropic Models**:
|
|
104
|
-
- Claude variants (3.5 Sonnet, 3.7 Sonnet, 4 Sonnet, 4 Opus)
|
|
105
|
-
- **Groq Models**:
|
|
106
|
-
- Llama3, Mixtral8
|
|
107
|
-
- **DeepSeek Models**:
|
|
108
|
-
- DeepSeekChat, DeepSeekReasoner
|
|
109
|
-
- **Other Models**:
|
|
110
|
-
- Whisper (for speech-to-text)
|
|
111
|
-
|
|
112
|
-
These models are encapsulated in their own modules, and you can easily switch the active model by updating the conversation thread state.
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## Extending Symposium
|
|
117
|
-
|
|
118
|
-
Symposium is designed to be extended and customized:
|
|
119
|
-
|
|
120
|
-
- **Creating Custom Agents**: Inherit from the `Agent` class and override methods like `doInitThread` and `message` to implement custom behavior.
|
|
121
|
-
- **Implementing Tools**: Build your own tools by extending the `Tool` class. Define the functions your tool exposes and provide implementations via `callFunction`.
|
|
122
|
-
- **Custom Memory Handlers & Loggers**: Implement your own memory or logging strategies by creating classes that adhere to the respective interfaces.
|
|
123
|
-
- **Defining Interfaces**: Customize output and error handling by implementing your own `Interface` classes.
|
|
124
|
-
|
|
125
|
-
---
|
|
126
|
-
|
|
127
|
-
## Examples
|
|
128
|
-
|
|
129
|
-
The repository includes an `examples` folder with sample implementations demonstrating:
|
|
130
|
-
|
|
131
|
-
- **ChatAgent**: A basic conversational agent.
|
|
132
|
-
- **MultiAgent**: An agent that coordinates with other agents via internal interfaces.
|
|
133
|
-
- **TitlerAgent**: An agent that generates concise titles for conversations.
|
|
134
|
-
- **Tools**: Examples like `GenericTool` and `MultiAgentTool` show how to integrate custom functionality.
|
|
135
|
-
|
|
136
|
-
> **Important:** The content in the `examples` folder is provided solely for demo purposes and will not be part of the exported npm package. You can use these examples as a guide for building your own implementations.
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
## Contributing
|
|
141
|
-
|
|
142
|
-
Contributions to Symposium are welcome! If you have ideas, improvements, or bug fixes, please fork the repository and submit a pull request.
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## License
|
|
147
|
-
|
|
148
|
-
Symposium is released under the ISC License.
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
For more details or to report issues, please refer to the repository's issue tracker. Enjoy building your AI-driven applications with Symposium!
|
package/examples/ChatAgent.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {Agent, Symposium} from "symposium";
|
|
2
|
-
import GenericTool from "./Tools/GenericTool.js";
|
|
3
|
-
|
|
4
|
-
export default class ChatAgent extends Agent {
|
|
5
|
-
default_model = 'gpt-4o';
|
|
6
|
-
|
|
7
|
-
constructor(options = {}) {
|
|
8
|
-
super(options);
|
|
9
|
-
|
|
10
|
-
this.name = 'ChatAgent';
|
|
11
|
-
|
|
12
|
-
this.addTool(new GenericTool());
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async doInitThread(thread) {
|
|
16
|
-
await thread.addMessage('system',
|
|
17
|
-
`You are a helpful assistant, assist the user using the tools you are provided with.
|
|
18
|
-
Current time is: ${(new Date()).toLocaleDateString()}`
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
}
|
package/examples/MultiAgent.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import {Agent, Symposium} from "symposium";
|
|
2
|
-
import MultiAgentTool from "./Tools/MultiAgentTool.js";
|
|
3
|
-
|
|
4
|
-
export default class MultiAgent extends Agent {
|
|
5
|
-
default_model = 'gpt-4o';
|
|
6
|
-
|
|
7
|
-
constructor(options = {}) {
|
|
8
|
-
options = {
|
|
9
|
-
agents: [],
|
|
10
|
-
...options,
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
super(options);
|
|
14
|
-
this.name = 'Multi Agent';
|
|
15
|
-
|
|
16
|
-
this.internalInterface = {
|
|
17
|
-
name: 'agent-vs-agent',
|
|
18
|
-
promises: [],
|
|
19
|
-
init: async () => {
|
|
20
|
-
},
|
|
21
|
-
message: async (thread, msg) => {
|
|
22
|
-
},
|
|
23
|
-
output: async (thread, msg) => {
|
|
24
|
-
},
|
|
25
|
-
error: async (thread, error) => {
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
this.addTool(new MultiAgentTool(this.options.agents));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async init() {
|
|
33
|
-
await super.init();
|
|
34
|
-
|
|
35
|
-
for (let agent of this.options.agents) {
|
|
36
|
-
agent.options.interfaces = [this.internalInterface];
|
|
37
|
-
await agent.init();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async reset(thread) {
|
|
42
|
-
await super.reset(thread);
|
|
43
|
-
|
|
44
|
-
for (let agent of this.options.agents) {
|
|
45
|
-
const sub_thread = await agent.getThread(thread.id, 'agent-vs-agent');
|
|
46
|
-
await agent.reset(sub_thread);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async doInitThread(thread) {
|
|
51
|
-
const memory = await this.tools.get('Memory').get();
|
|
52
|
-
|
|
53
|
-
await thread.addMessage('system',
|
|
54
|
-
`You are a helpful assistant, assist the user using the tools you are provided with.
|
|
55
|
-
In order to do so, you have a series of agents at your service, with which you can communicate behind the scenes to provide the user with what they asked for. You can communicate with them through their respective tools that you have.
|
|
56
|
-
You can talk to the agents in natural language, and also respond to them multiple times if necessary. Try to use clear and direct language with precise instructions when talking to an agent.
|
|
57
|
-
|
|
58
|
-
At the end of each task, when the agent has completed its function, remember to reset the conversation with the agent to save memory. You can do this using the "reset" function.
|
|
59
|
-
|
|
60
|
-
Interrogate them only if the user asks to perform tasks that concern them, otherwise you can rely on your knowledge to respond directly.
|
|
61
|
-
|
|
62
|
-
Current time is: ${(new Date()).toLocaleDateString()}`,
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
for (let agent of this.options.agents) {
|
|
66
|
-
const sub_thread = await agent.getThread(thread.id, 'agent-vs-agent');
|
|
67
|
-
if (sub_thread) {
|
|
68
|
-
await sub_thread.flush();
|
|
69
|
-
await agent.initThread(sub_thread);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async beforeExecute(thread) {
|
|
75
|
-
if (this.options.reasoning) {
|
|
76
|
-
let reasoning = await this.generateCompletion(thread, {
|
|
77
|
-
functions: [
|
|
78
|
-
{
|
|
79
|
-
name: 'ragionamento',
|
|
80
|
-
description: 'Before responding to the user, ask yourself what needs to be done and if you need to ask for more info.',
|
|
81
|
-
parameters: {
|
|
82
|
-
type: 'object',
|
|
83
|
-
properties: {
|
|
84
|
-
ragionamento: {
|
|
85
|
-
type: 'string',
|
|
86
|
-
description: 'Reflect on the request just made. What do you need to do to fulfill the user\'s request? These are your thoughts and the user cannot see them.',
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
required: ['ragionamento'],
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
...(await this.getFunctions()),
|
|
93
|
-
],
|
|
94
|
-
force_function: 'ragionamento',
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
if (reasoning) {
|
|
98
|
-
reasoning = Symposium.extractFunctionsFromResponse(reasoning)[0];
|
|
99
|
-
await this.log('reasoning', reasoning);
|
|
100
|
-
thread.addMessage('assistant', "[Thinking] " + reasoning.ragionamento + "\n");
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return thread;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async getPromptWordsForTranscription(thread) {
|
|
108
|
-
let words = [this.name];
|
|
109
|
-
for (let agent of this.options.agents) {
|
|
110
|
-
const sub_thread = await agent.getThread(thread.id, 'agent-vs-agent');
|
|
111
|
-
words = [...words, ...(await agent.getPromptWordsForTranscription(sub_thread))];
|
|
112
|
-
}
|
|
113
|
-
return words;
|
|
114
|
-
}
|
|
115
|
-
}
|
package/examples/TitlerAgent.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import {Agent} from "symposium";
|
|
2
|
-
|
|
3
|
-
export default class TitlerAgent extends Agent {
|
|
4
|
-
default_model = 'gpt-4o';
|
|
5
|
-
|
|
6
|
-
constructor(options) {
|
|
7
|
-
super(options);
|
|
8
|
-
this.name = 'Titler';
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async init() {
|
|
12
|
-
await super.init();
|
|
13
|
-
|
|
14
|
-
this.utility = {
|
|
15
|
-
type: 'text',
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async doInitThread(thread) {
|
|
20
|
-
await thread.addMessage('system',
|
|
21
|
-
`Your task is to observe the following message, which represents the beginning of a conversation from the user, and give a title of a few words (maximum 30 characters) that describes it as accurately as possible. Even a single word is fine, if necessary.
|
|
22
|
-
Do not write anything else in your message, but only and exclusively the title.`
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import {Tool} from "symposium";
|
|
2
|
-
|
|
3
|
-
export default class GenericTool extends Tool {
|
|
4
|
-
name = 'GenericTool';
|
|
5
|
-
|
|
6
|
-
async getFunctions() {
|
|
7
|
-
return [
|
|
8
|
-
{
|
|
9
|
-
name: `create_todo`,
|
|
10
|
-
description: `Create a new TODO`,
|
|
11
|
-
parameters: {
|
|
12
|
-
type: 'object',
|
|
13
|
-
properties: {
|
|
14
|
-
title: {
|
|
15
|
-
type: 'string',
|
|
16
|
-
description: 'Title of the TODO',
|
|
17
|
-
},
|
|
18
|
-
description: {
|
|
19
|
-
type: 'string',
|
|
20
|
-
description: 'Description of the TODO',
|
|
21
|
-
},
|
|
22
|
-
due_date: {
|
|
23
|
-
type: 'string',
|
|
24
|
-
description: 'Due date of the TODO',
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
required: ['title', 'description', 'due_date'],
|
|
28
|
-
},
|
|
29
|
-
}
|
|
30
|
-
];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async callFunction(thread, name, payload) {
|
|
34
|
-
try {
|
|
35
|
-
// Implement your function here
|
|
36
|
-
|
|
37
|
-
throw new Error(`Unknown function: ${name}`);
|
|
38
|
-
} catch (error) {
|
|
39
|
-
return {error: error.response?.body || error};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import {Tool} from "symposium";
|
|
2
|
-
|
|
3
|
-
export default class MultiAgentTool extends Tool {
|
|
4
|
-
name = 'MultiAgentTool';
|
|
5
|
-
agents;
|
|
6
|
-
|
|
7
|
-
constructor(agents) {
|
|
8
|
-
super();
|
|
9
|
-
this.agents = agents;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async getFunctions() {
|
|
13
|
-
return [
|
|
14
|
-
...this.agents.map(a => ({
|
|
15
|
-
name: a.name,
|
|
16
|
-
description: a.description,
|
|
17
|
-
parameters: {
|
|
18
|
-
type: 'object',
|
|
19
|
-
properties: {
|
|
20
|
-
message: {
|
|
21
|
-
type: 'string',
|
|
22
|
-
description: 'The message to send to the agent'
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
})),
|
|
27
|
-
{
|
|
28
|
-
name: 'reset',
|
|
29
|
-
description: 'Reset an agent\'s memory to start the conversation again',
|
|
30
|
-
parameters: {
|
|
31
|
-
type: 'object',
|
|
32
|
-
properties: {
|
|
33
|
-
agent: {
|
|
34
|
-
type: 'string',
|
|
35
|
-
description: 'The name of the agent to reset'
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async callFunction(thread, name, payload) {
|
|
44
|
-
try {
|
|
45
|
-
if (name === 'reset') {
|
|
46
|
-
const agent = this.agents.find(a => a.name === payload.agent);
|
|
47
|
-
if (!agent)
|
|
48
|
-
throw new Error('No agent named "' + payload.agent + '"');
|
|
49
|
-
|
|
50
|
-
const sub_thread = await agent.getThread(thread.id, 'agent-vs-agent');
|
|
51
|
-
|
|
52
|
-
await agent.reset(sub_thread);
|
|
53
|
-
|
|
54
|
-
return {success: true};
|
|
55
|
-
} else {
|
|
56
|
-
const agent = this.agents.find(a => a.name === name);
|
|
57
|
-
if (!agent)
|
|
58
|
-
throw new Error('No agent named "' + name + '"');
|
|
59
|
-
|
|
60
|
-
return await (new Promise(async (resolve, reject) => {
|
|
61
|
-
try {
|
|
62
|
-
const sub_thread = await agent.getThread(thread.id, 'agent-vs-agent');
|
|
63
|
-
|
|
64
|
-
await agent.message(sub_thread, 'agent-vs-agent', payload.message, msg => {
|
|
65
|
-
resolve({reply: msg});
|
|
66
|
-
});
|
|
67
|
-
} catch (e) {
|
|
68
|
-
console.error(JSON.stringify(e));
|
|
69
|
-
reject(e);
|
|
70
|
-
}
|
|
71
|
-
}));
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
return {error};
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|