symposium 0.4.6 → 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.js CHANGED
@@ -89,7 +89,7 @@ export default class Agent {
89
89
 
90
90
  async message(thread, text) {
91
91
  await this.log('user_message', text);
92
- thread.addMessage('user', 'text', text);
92
+ thread.addMessage('user', text);
93
93
 
94
94
  await this.execute(thread, text);
95
95
  }
@@ -124,16 +124,8 @@ export default class Agent {
124
124
  async generateCompletion(thread, payload = {}, retry_counter = 1) {
125
125
  try {
126
126
  const model = Symposium.getModelByName(thread.state.model);
127
-
128
- const response = await model.generate(thread, payload, await this.getFunctions());
129
- if (!model.supports_functions) {
130
- const newMessages = [];
131
- for (let message of response.messages)
132
- newMessages.concat(...this.parseFunctions(message));
133
- response.messages = newMessages;
134
- }
135
-
136
- return response;
127
+ const messages = await model.generate(thread, payload, await this.getFunctions());
128
+ return messages.map(m => model.supports_functions ? m : this.parseFunctions(m));
137
129
  } catch (error) {
138
130
  if (error.response) {
139
131
  console.error(error.response.status);
@@ -159,40 +151,45 @@ export default class Agent {
159
151
  }
160
152
 
161
153
  parseFunctions(message) {
162
- const messages = [];
163
- if (message.type === 'text' && message.content.match(/```\nCALL [A-Za-z0-9_]+\n(\{.+\}\n)?```/)) {
164
- const splitted = message.content.split('```');
165
- for (let text of splitted) {
166
- const match = text.match(/^CALL ([A-Za-z0-9_]+)\n([\s\S]*)$/);
167
- if (match)
168
- messages.push(new Message(message.role, 'function', {name: match[1], arguments: JSON.parse(match[2] || '{}')}));
169
- else
170
- messages.push(new Message(message.role, 'text', text.trim()));
154
+ const newContent = [];
155
+ for (let m of message.content) {
156
+ if (m.type === 'text' && m.content.match(/```\nCALL [A-Za-z0-9_]+\n(\{.+\}\n)?```/)) {
157
+ const splitted = m.content.split('```');
158
+ for (let text of splitted) {
159
+ const match = text.match(/^CALL ([A-Za-z0-9_]+)\n([\s\S]*)$/);
160
+ if (match)
161
+ m.push({type: 'function', content: {name: match[1], arguments: JSON.parse(match[2] || '{}')}});
162
+ else
163
+ m.push({type: 'text', content: text.trim()});
164
+ }
165
+ } else {
166
+ newContent.push(m);
171
167
  }
172
- } else {
173
- messages.push(message);
174
168
  }
175
169
 
176
- return messages;
170
+ message.content = newContent;
171
+ return message;
177
172
  }
178
173
 
179
174
  async handleCompletion(thread, completion) {
180
175
  let call_function = null;
181
- for (let message of completion.messages) {
176
+ for (let message of completion) {
182
177
  thread.addDirectMessage(message);
183
178
  await this.log('ai_message', message);
184
179
 
185
- switch (message.type) {
186
- case 'text':
187
- await thread.reply(message.content);
188
- break;
189
-
190
- case 'function':
191
- if (call_function)
192
- throw new Error('The model replied with more than one function');
193
- else
194
- call_function = message.content;
195
- break;
180
+ for (let m of message.content) {
181
+ switch (m.type) {
182
+ case 'text':
183
+ await thread.reply(m.content);
184
+ break;
185
+
186
+ case 'function':
187
+ if (call_function)
188
+ throw new Error('The model replied with more than one function');
189
+ else
190
+ call_function = m.content;
191
+ break;
192
+ }
196
193
  }
197
194
  }
198
195
 
@@ -234,10 +231,10 @@ export default class Agent {
234
231
 
235
232
  try {
236
233
  const response = await functions.get(function_call.name).tool.callFunction(thread, function_call.name, function_call.arguments);
237
- thread.addMessage('function', 'text', JSON.stringify(response), function_call.name);
234
+ thread.addMessage('function', JSON.stringify(response), function_call.name);
238
235
  await this.log('function_response', response);
239
236
  } catch (error) {
240
- thread.addMessage('function', 'text', JSON.stringify({error}), function_call.name);
237
+ thread.addMessage('function', JSON.stringify({error}), function_call.name);
241
238
  await this.log('function_response', {error});
242
239
  }
243
240
 
package/Message.js CHANGED
@@ -1,15 +1,25 @@
1
1
  export default class Message {
2
2
  role;
3
- type;
4
- content;
5
- name;
3
+ content = [];
4
+ name = undefined;
6
5
  tags = [];
7
6
 
8
- constructor(role, type, content, name = null, tags = []) {
7
+ constructor(role, content = [], name = undefined, tags = []) {
9
8
  this.role = role;
10
- this.type = type;
11
- this.content = content;
12
9
  this.name = name;
13
10
  this.tags = tags;
11
+
12
+ if (typeof content === 'string') {
13
+ this.content = [
14
+ {
15
+ type: 'text',
16
+ content,
17
+ },
18
+ ];
19
+ } else if (typeof content === 'object') {
20
+ this.content = Array.isArray(content) ? content : [content];
21
+ } else {
22
+ throw new Error('Unrecognized message type');
23
+ }
14
24
  }
15
25
  }
package/Summarizer.js CHANGED
@@ -56,7 +56,7 @@ export default class Summarizer extends MemoryHandler {
56
56
  }
57
57
 
58
58
  async doSummarize(thread, maxLength) {
59
- thread.addMessage('system', 'text', 'Summarize the conversation up to this moment.');
59
+ thread.addMessage('system', 'Summarize the conversation up to this moment.');
60
60
  const summary = await this.agent.generateCompletion(thread, {
61
61
  functions: [
62
62
  {
@@ -79,12 +79,13 @@ export default class Summarizer extends MemoryHandler {
79
79
  if (!summary)
80
80
  return false;
81
81
 
82
+ // TODO: sistemare con nuova interfaccia
82
83
  let summarizedThread = thread.clone(false);
83
84
  for (let message of thread.messages) {
84
85
  if (message.role === 'system' && !message.tags.includes('summary')) {
85
86
  summarizedThread.messages.push(message);
86
87
  } else {
87
- summarizedThread.addMessage('system', 'text', "This is what happened until now:\n" + summary.function_call.arguments.summary, ['summary']);
88
+ summarizedThread.addMessage('system', "This is what happened until now:\n" + summary.function_call.arguments.summary, ['summary']);
88
89
  break;
89
90
  }
90
91
  }
package/Thread.js CHANGED
@@ -33,7 +33,7 @@ export default class Thread {
33
33
  const conv = await Redis.get('thread-' + this.id);
34
34
  if (conv) {
35
35
  this.state = conv.state || {};
36
- this.messages = conv.messages.map(m => new Message(m.role, m.type, m.content, m.tags));
36
+ this.messages = conv.messages.map(m => new Message(m.role, m.content, m.name, m.tags));
37
37
  return true;
38
38
  } else {
39
39
  return false;
@@ -57,8 +57,8 @@ export default class Thread {
57
57
  this.messages.push(message);
58
58
  }
59
59
 
60
- addMessage(role, type, content, name = null, tags = []) {
61
- this.addDirectMessage(new Message(role, type, content, name, tags));
60
+ addMessage(role, content = [], name = undefined, tags = []) {
61
+ this.addDirectMessage(new Message(role, content, name, tags));
62
62
  }
63
63
 
64
64
  removeMessagesWithTag(tag) {
@@ -1,6 +1,5 @@
1
1
  import Model from "../Model.js";
2
2
  import Anthropic from '@anthropic-ai/sdk';
3
- import Response from "../Response.js";
4
3
  import Message from "../Message.js";
5
4
 
6
5
  export default class AnthropicModel extends Model {
@@ -34,14 +33,23 @@ export default class AnthropicModel extends Model {
34
33
 
35
34
  const message = await this.getAnthropic().messages.create(completion_payload);
36
35
 
37
- const response = new Response;
36
+ const message_content = [];
38
37
  if (message.content) {
39
- for (let m of message.content)
40
- // TODO: supporto ad altri tipi oltre a text (m.type)
41
- response.messages.push(new Message('assistant', 'text', m.text));
38
+ for (let m of message.content) {
39
+ switch (m.type) {
40
+ case 'text':
41
+ message_content.push({type: 'text', content: m.text});
42
+ break;
43
+
44
+ default:
45
+ throw new Error('Unrecognized message type in Anthropic response');
46
+ }
47
+ }
42
48
  }
43
49
 
44
- return response;
50
+ return [
51
+ new Message('assistant', message_content),
52
+ ];
45
53
  }
46
54
 
47
55
  convertMessages(thread) {
@@ -50,25 +58,27 @@ export default class AnthropicModel extends Model {
50
58
  if (message.role === 'system') {
51
59
  system.push(message.content);
52
60
  } else {
53
- switch (message.type) {
54
- case 'text':
55
- messages.push({
56
- role: message.role,
57
- type: 'text',
58
- content: message.content,
59
- });
60
- break;
61
+ messages.push({
62
+ role: message.role,
63
+ content: message.content.map(c => {
64
+ switch (c.type) {
65
+ case 'text':
66
+ return {
67
+ type: 'text',
68
+ text: c.content,
69
+ };
61
70
 
62
- case 'function':
63
- messages.push({
64
- role: message.role,
65
- type: 'text',
66
- content: '```CALL \n' + message.content.name + '\n' + JSON.stringify(message.content.arguments || {}) + '\n```',
67
- });
71
+ case 'function':
72
+ return {
73
+ type: 'text',
74
+ text: '```CALL \n' + c.content.name + '\n' + JSON.stringify(c.content.arguments || {}) + '\n```',
75
+ };
68
76
 
69
- default:
70
- throw new Error('Message type unsupported by this model');
71
- }
77
+ default:
78
+ throw new Error('Message type "' + c.type + '" unsupported by this model');
79
+ }
80
+ }),
81
+ });
72
82
  }
73
83
  }
74
84
 
@@ -1,4 +1,3 @@
1
- import Response from "../Response.js";
2
1
  import Model from "../Model.js";
3
2
  import OpenAI from "openai";
4
3
  import Message from "../Message.js";
@@ -31,15 +30,19 @@ export default class OpenAIModel extends Model {
31
30
  other_messages.push(message);
32
31
  }
33
32
 
34
- system_messages.push(new Message('system', 'text', functions_prompt));
33
+ system_messages.push(new Message('system', functions_prompt));
35
34
 
36
35
  messages = [...system_messages, ...other_messages];
37
36
  functions = [];
38
37
  }
39
38
 
39
+ const convertedMessages = [];
40
+ for (let m of messages)
41
+ convertedMessages.push(...this.convertMessage(m));
42
+
40
43
  const completion_payload = {
41
44
  model: this.name,
42
- messages: messages.map(m => this.convertMessage(m)),
45
+ messages: convertedMessages,
43
46
  functions,
44
47
  ...payload,
45
48
  };
@@ -53,42 +56,51 @@ export default class OpenAIModel extends Model {
53
56
  const chatCompletion = await this.getOpenAi().chat.completions.create(completion_payload);
54
57
  const completion = chatCompletion.choices[0].message;
55
58
 
56
- const response = new Response;
59
+ const message_content = [];
57
60
  if (completion.content)
58
- response.messages.push(new Message('assistant', 'text', completion.content));
61
+ message_content.push({type: 'text', content: completion.content});
59
62
  if (completion.function_call && completion.function_call.arguments)
60
- response.messages.push(new Message('assistant', 'function', completion.function_call));
63
+ message_content.push({type: 'function', content: completion.function_call});
61
64
 
62
- return response;
65
+ return [
66
+ new Message('assistant', message_content),
67
+ ];
63
68
  }
64
69
 
65
70
  convertMessage(message) {
66
- switch (message.type) {
67
- case 'text':
68
- return {
69
- role: message.role,
70
- content: message.content,
71
- name: message.name,
72
- };
73
-
74
- case 'function':
75
- if (this.supports_functions) {
76
- return {
77
- role: message.role,
78
- content: null,
79
- name: message.name,
80
- function_call: message.content,
81
- };
82
- } else {
83
- return {
71
+ const messages = [];
72
+ for (let c of message.content) {
73
+ switch (c.type) {
74
+ case 'text':
75
+ messages.push({
84
76
  role: message.role,
85
- content: message.content,
77
+ content: c.content,
86
78
  name: message.name,
87
- };
88
- }
89
-
90
- default:
91
- throw new Error('Message type unsupported by this model');
79
+ });
80
+ break;
81
+
82
+ case 'function':
83
+ if (this.supports_functions) {
84
+ messages.push({
85
+ role: message.role,
86
+ content: null,
87
+ name: message.name,
88
+ function_call: c.content,
89
+ });
90
+ } else {
91
+ messages.push({
92
+ role: message.role,
93
+ content: c.content,
94
+ name: message.name,
95
+ });
96
+ }
97
+ break;
98
+
99
+ default:
100
+ throw new Error('Message type unsupported by this model');
101
+ }
92
102
  }
103
+
104
+ return messages;
93
105
  }
94
106
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "symposium",
4
- "version": "0.4.6",
4
+ "version": "0.5.0",
5
5
  "description": "Agents",
6
6
  "main": "index.js",
7
7
  "author": "Domenico Giambra",
package/Response.js DELETED
@@ -1,4 +0,0 @@
1
- export default class Response {
2
- messages = [];
3
- function = null;
4
- }