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 getMessages() { return _session?.messages ?? []; } void setSession(ConversationSession s) { _session = s; } void addMessage(String role, String content, {int? tokens, int? contextTokens, List? 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({"messages": []}); } return const JsonEncoder.withIndent(" ").convert(_session!.toJson()); } }