|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class BaseMessage {
|
|
|
constructor(content, additionalKwargs = {}) {
|
|
|
this.content = content;
|
|
|
this.additionalKwargs = additionalKwargs;
|
|
|
this.timestamp = Date.now();
|
|
|
this.id = this.generateId();
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
generateId() {
|
|
|
return `msg_${this.timestamp}_${Math.random().toString(36).substr(2, 9)}`;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get type() {
|
|
|
throw new Error('Subclass must implement type getter');
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toJSON() {
|
|
|
return {
|
|
|
id: this.id,
|
|
|
type: this.type,
|
|
|
content: this.content,
|
|
|
timestamp: this.timestamp,
|
|
|
...this.additionalKwargs
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static fromJSON(json) {
|
|
|
const MessageClass = MESSAGE_TYPES[json.type];
|
|
|
if (!MessageClass) {
|
|
|
throw new Error(`Unknown message type: ${json.type}`);
|
|
|
}
|
|
|
|
|
|
const message = new MessageClass(json.content, json.additionalKwargs);
|
|
|
message.id = json.id;
|
|
|
message.timestamp = json.timestamp;
|
|
|
return message;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toString() {
|
|
|
const date = new Date(this.timestamp).toLocaleTimeString();
|
|
|
return `[${date}] ${this.type}: ${this.content}`;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class SystemMessage extends BaseMessage {
|
|
|
constructor(content, additionalKwargs = {}) {
|
|
|
super(content, additionalKwargs);
|
|
|
}
|
|
|
|
|
|
get type() {
|
|
|
return 'system';
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toPromptFormat() {
|
|
|
return {
|
|
|
role: 'system',
|
|
|
content: this.content
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class HumanMessage extends BaseMessage {
|
|
|
constructor(content, additionalKwargs = {}) {
|
|
|
super(content, additionalKwargs);
|
|
|
}
|
|
|
|
|
|
get type() {
|
|
|
return 'human';
|
|
|
}
|
|
|
|
|
|
toPromptFormat() {
|
|
|
return {
|
|
|
role: 'user',
|
|
|
content: this.content
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class AIMessage extends BaseMessage {
|
|
|
constructor(content, additionalKwargs = {}) {
|
|
|
super(content, additionalKwargs);
|
|
|
|
|
|
|
|
|
this.toolCalls = additionalKwargs.toolCalls || [];
|
|
|
}
|
|
|
|
|
|
get type() {
|
|
|
return 'ai';
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hasToolCalls() {
|
|
|
return this.toolCalls.length > 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getToolCall(index = 0) {
|
|
|
return this.toolCalls[index];
|
|
|
}
|
|
|
|
|
|
toPromptFormat() {
|
|
|
const formatted = {
|
|
|
role: 'assistant',
|
|
|
content: this.content
|
|
|
};
|
|
|
|
|
|
if (this.hasToolCalls()) {
|
|
|
formatted.tool_calls = this.toolCalls;
|
|
|
}
|
|
|
|
|
|
return formatted;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class ToolMessage extends BaseMessage {
|
|
|
constructor(content, toolCallId, additionalKwargs = {}) {
|
|
|
super(content, additionalKwargs);
|
|
|
this.toolCallId = toolCallId;
|
|
|
}
|
|
|
|
|
|
get type() {
|
|
|
return 'tool';
|
|
|
}
|
|
|
|
|
|
toPromptFormat() {
|
|
|
return {
|
|
|
role: 'tool',
|
|
|
content: this.content,
|
|
|
tool_call_id: this.toolCallId
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const MESSAGE_TYPES = {
|
|
|
'system': SystemMessage,
|
|
|
'human': HumanMessage,
|
|
|
'ai': AIMessage,
|
|
|
'tool': ToolMessage
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function messagesToPromptFormat(messages) {
|
|
|
return messages.map(msg => msg.toPromptFormat());
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function filterMessagesByType(messages, type) {
|
|
|
return messages.filter(msg => msg._type === type);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function getLastMessages(messages, n) {
|
|
|
return messages.slice(-n);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function mergeConsecutiveMessages(messages) {
|
|
|
if (messages.length === 0) return [];
|
|
|
|
|
|
const merged = [messages[0]];
|
|
|
|
|
|
for (let i = 1; i < messages.length; i++) {
|
|
|
const current = messages[i];
|
|
|
const last = merged[merged.length - 1];
|
|
|
|
|
|
|
|
|
if (
|
|
|
current._type === last._type &&
|
|
|
typeof current.content === 'string' &&
|
|
|
typeof last.content === 'string' &&
|
|
|
current._type !== 'tool'
|
|
|
) {
|
|
|
|
|
|
const MessageClass = MESSAGE_CLASSES[current._type];
|
|
|
const mergedContent = last.content + '\n' + current.content;
|
|
|
merged[merged.length - 1] = new MessageClass(mergedContent, {
|
|
|
name: last.name,
|
|
|
additionalKwargs: { ...last.additionalKwargs, merged: true }
|
|
|
});
|
|
|
} else {
|
|
|
merged.push(current);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return merged;
|
|
|
}
|
|
|
|
|
|
export default {
|
|
|
BaseMessage,
|
|
|
SystemMessage,
|
|
|
HumanMessage,
|
|
|
AIMessage,
|
|
|
ToolMessage,
|
|
|
MESSAGE_TYPES
|
|
|
}; |