132 lines
3.7 KiB
Dart
132 lines
3.7 KiB
Dart
import "dart:convert";
|
|
|
|
import "session_types.dart";
|
|
|
|
// in-memory conversation history for the current session
|
|
// does not auto-persist - caller has to call SessionStore.saveSession
|
|
class ConversationHistory {
|
|
ConversationHistory({ConversationSession? session}) : _session = session;
|
|
|
|
ConversationSession? _session;
|
|
|
|
ConversationSession? get session => _session;
|
|
|
|
bool get hasSession => _session != null;
|
|
|
|
List<Message> getMessages() {
|
|
return _session?.messages ?? <Message>[];
|
|
}
|
|
|
|
void setSession(ConversationSession s) {
|
|
_session = s;
|
|
}
|
|
|
|
void addMessage(String role, String content, {int? tokens, int? contextTokens, List<MessageAttachment>? attachments, double? cost}) {
|
|
if (_session == null) return;
|
|
|
|
final msg = Message(role: role, content: content, tokens: tokens, contextTokens: contextTokens, attachments: attachments, cost: cost);
|
|
|
|
_session!.messages.add(msg);
|
|
_session!.updated = DateTime.now().toUtc();
|
|
}
|
|
|
|
void appendToLastMessage(String text) {
|
|
if (_session == null || _session!.messages.isEmpty || text.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
final lastMessage = _session!.messages.last;
|
|
_session!.messages[_session!.messages.length - 1] = Message(
|
|
role: lastMessage.role,
|
|
content: "${lastMessage.content}$text",
|
|
timestamp: lastMessage.timestamp,
|
|
tokens: lastMessage.tokens,
|
|
contextTokens: lastMessage.contextTokens,
|
|
);
|
|
_session!.updated = DateTime.now().toUtc();
|
|
}
|
|
|
|
void setLastMessageContextTokens(int? contextTokens) {
|
|
if (_session == null || _session!.messages.isEmpty) return;
|
|
final last = _session!.messages.last;
|
|
_session!.messages[_session!.messages.length - 1] = Message(
|
|
role: last.role,
|
|
content: last.content,
|
|
timestamp: last.timestamp,
|
|
tokens: last.tokens,
|
|
contextTokens: contextTokens ?? last.contextTokens,
|
|
cost: last.cost,
|
|
);
|
|
}
|
|
|
|
void setLastMessageCost(double? cost) {
|
|
if (_session == null || _session!.messages.isEmpty) return;
|
|
final last = _session!.messages.last;
|
|
_session!.messages[_session!.messages.length - 1] = Message(
|
|
role: last.role,
|
|
content: last.content,
|
|
timestamp: last.timestamp,
|
|
tokens: last.tokens,
|
|
contextTokens: last.contextTokens,
|
|
cost: cost,
|
|
);
|
|
}
|
|
|
|
void removeLastMessage() {
|
|
if (_session == null || _session!.messages.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
_session!.messages.removeLast();
|
|
_session!.updated = DateTime.now().toUtc();
|
|
}
|
|
|
|
void truncateMessages(int length) {
|
|
if (_session == null) {
|
|
return;
|
|
}
|
|
|
|
final targetLength = length.clamp(0, _session!.messages.length);
|
|
_session!.messages.removeRange(targetLength, _session!.messages.length);
|
|
_session!.updated = DateTime.now().toUtc();
|
|
}
|
|
|
|
// remove all messages but keep the session metadata
|
|
void clear() {
|
|
if (_session == null) return;
|
|
_session!.messages.clear();
|
|
_session!.updated = DateTime.now().toUtc();
|
|
}
|
|
|
|
// export as plain text - one [role]: content block per message
|
|
String exportToText() {
|
|
final buf = StringBuffer();
|
|
|
|
if (_session != null) {
|
|
buf.writeln("Session: ${_session!.name}");
|
|
buf.writeln("ID: ${_session!.id}");
|
|
buf.writeln("Created: ${_session!.created.toIso8601String()}");
|
|
buf.writeln("Messages: ${_session!.messageCount}");
|
|
buf.writeln("---");
|
|
buf.writeln();
|
|
}
|
|
|
|
for (final msg in getMessages()) {
|
|
buf.writeln("[${msg.role}]");
|
|
buf.writeln(msg.content);
|
|
buf.writeln();
|
|
}
|
|
|
|
return buf.toString();
|
|
}
|
|
|
|
String exportToJson() {
|
|
if (_session == null) {
|
|
return const JsonEncoder.withIndent(
|
|
" ",
|
|
).convert(<String, dynamic>{"messages": <dynamic>[]});
|
|
}
|
|
|
|
return const JsonEncoder.withIndent(" ").convert(_session!.toJson());
|
|
}
|
|
}
|