Backup-bdg/OpenHands
0
1"""Utility functions for generating conversation summaries."""2 3from typing import Optional4 5from openhands.core.config import LLMConfig6from openhands.core.logger import openhands_logger as logger7from openhands.events.action.message import MessageAction8from openhands.events.event import EventSource9from openhands.events.stream import EventStream10from openhands.llm.llm import LLM11from openhands.storage.data_models.settings import Settings12from openhands.storage.files import FileStore13 14 15async def generate_conversation_title(16 message: str, llm_config: LLMConfig, max_length: int = 5017) -> Optional[str]:18 """Generate a concise title for a conversation based on the first user message.19 20 Args:21 message: The first user message in the conversation.22 llm_config: The LLM configuration to use for generating the title.23 max_length: The maximum length of the generated title.24 25 Returns:26 A concise title for the conversation, or None if generation fails.27 """28 if not message or message.strip() == '':29 return None30 31 # Truncate very long messages to avoid excessive token usage32 if len(message) > 1000:33 truncated_message = message[:1000] + '...(truncated)'34 else:35 truncated_message = message36 37 try:38 llm = LLM(llm_config)39 40 # Create a simple prompt for the LLM to generate a title41 messages = [42 {43 'role': 'system',44 'content': 'You are a helpful assistant that generates concise, descriptive titles for conversations with OpenHands. OpenHands is a helpful AI agent that can interact with a computer to solve tasks using bash terminal, file editor, and browser. Given a user message (which may be truncated), generate a concise, descriptive title for the conversation. Return only the title, with no additional text, quotes, or explanations.',45 },46 {47 'role': 'user',48 'content': f'Generate a title (maximum {max_length} characters) for a conversation that starts with this message:\n\n{truncated_message}',49 },50 ]51 52 response = llm.completion(messages=messages)53 title = response.choices[0].message.content.strip()54 55 # Ensure the title isn't too long56 if len(title) > max_length:57 title = title[: max_length - 3] + '...'58 59 return title60 except Exception as e:61 logger.error(f'Error generating conversation title: {e}')62 return None63 64 65def get_default_conversation_title(conversation_id: str) -> str:66 """67 Generate a default title for a conversation based on its ID.68 69 Args:70 conversation_id: The ID of the conversation71 72 Returns:73 A default title string74 """75 return f'Conversation {conversation_id[:5]}'76 77 78async def auto_generate_title(79 conversation_id: str, user_id: str | None, file_store: FileStore, settings: Settings80) -> str:81 """82 Auto-generate a title for a conversation based on the first user message.83 Uses LLM-based title generation if available, otherwise falls back to a simple truncation.84 85 Args:86 conversation_id: The ID of the conversation87 user_id: The ID of the user88 89 Returns:90 A generated title string91 """92 try:93 # Create an event stream for the conversation94 event_stream = EventStream(conversation_id, file_store, user_id)95 96 # Find the first user message97 first_user_message = None98 for event in event_stream.get_events():99 if (100 event.source == EventSource.USER101 and isinstance(event, MessageAction)102 and event.content103 and event.content.strip()104 ):105 first_user_message = event.content106 break107 108 if first_user_message:109 # Get LLM config from user settings110 try:111 if settings and settings.llm_model:112 # Create LLM config from settings113 llm_config = LLMConfig(114 model=settings.llm_model,115 api_key=settings.llm_api_key,116 base_url=settings.llm_base_url,117 )118 119 # Try to generate title using LLM120 llm_title = await generate_conversation_title(121 first_user_message, llm_config122 )123 if llm_title:124 logger.info(f'Generated title using LLM: {llm_title}')125 return llm_title126 except Exception as e:127 logger.error(f'Error using LLM for title generation: {e}')128 129 # Fall back to simple truncation if LLM generation fails or is unavailable130 first_user_message = first_user_message.strip()131 title = first_user_message[:30]132 if len(first_user_message) > 30:133 title += '...'134 logger.info(f'Generated title using truncation: {title}')135 return title136 except Exception as e:137 logger.error(f'Error generating title: {str(e)}')138 return ''139 