2
2
List, search, and summarize past conversation logs.
3
3
"""
4
4
5
- import itertools
6
5
import logging
6
+ import textwrap
7
7
from pathlib import Path
8
- from textwrap import indent
9
- from typing import TYPE_CHECKING
10
8
11
9
from ..message import Message
12
10
from .base import ToolSpec , ToolUse
13
11
14
- if TYPE_CHECKING :
15
- from ..logmanager import LogManager
16
-
17
-
18
12
logger = logging .getLogger (__name__ )
19
13
20
14
21
- def _format_message_snippet (msg : Message , max_length : int = 100 ) -> str :
22
- """Format a message snippet for display."""
23
- first_newline = msg .content .find ("\n " )
24
- max_length = min (max_length , first_newline ) if first_newline != - 1 else max_length
25
- content = msg .content [:max_length ]
26
- return f"{ msg .role .capitalize ()} : { content } " + (
27
- "..." if len (content ) <= len (msg .content ) else ""
28
- )
29
-
30
-
31
15
def _get_matching_messages (log_manager , query : str , system = False ) -> list [Message ]:
32
16
"""Get messages matching the query."""
33
17
return [
@@ -38,36 +22,9 @@ def _get_matching_messages(log_manager, query: str, system=False) -> list[Messag
38
22
]
39
23
40
24
41
- def _summarize_conversation (
42
- log_manager : "LogManager" , include_summary : bool
43
- ) -> list [str ]:
44
- """Summarize a conversation."""
45
- # noreorder
46
- from ..llm import summarize as llm_summarize # fmt: skip
47
-
48
- summary_lines = []
49
- if include_summary :
50
- summary = llm_summarize (log_manager .log .messages )
51
- summary_lines .append (indent (f"Summary: { summary .content } " , " " ))
52
- else :
53
- non_system_messages = [msg for msg in log_manager .log if msg .role != "system" ]
54
- if non_system_messages :
55
- first_msg = non_system_messages [0 ]
56
- last_msg = non_system_messages [- 1 ]
57
-
58
- summary_lines .append (
59
- f" First message: { _format_message_snippet (first_msg )} "
60
- )
61
- if last_msg != first_msg :
62
- summary_lines .append (
63
- f" Last message: { _format_message_snippet (last_msg )} "
64
- )
65
-
66
- summary_lines .append (f" Total messages: { len (log_manager .log )} " )
67
- return summary_lines
68
-
69
-
70
- def list_chats (max_results : int = 5 , include_summary : bool = False ) -> None :
25
+ def list_chats (
26
+ max_results : int = 5 , metadata = False , include_summary : bool = False
27
+ ) -> None :
71
28
"""
72
29
List recent chat conversations and optionally summarize them using an LLM.
73
30
@@ -77,24 +34,30 @@ def list_chats(max_results: int = 5, include_summary: bool = False) -> None:
77
34
If True, uses an LLM to generate a comprehensive summary.
78
35
If False, uses a simple strategy showing snippets of the first and last messages.
79
36
"""
80
- # noreorder
81
- from ..logmanager import LogManager , get_user_conversations # fmt: skip
37
+ from .. llm import summarize # fmt: skip
38
+ from ..logmanager import LogManager , list_conversations # fmt: skip
82
39
83
- conversations = list ( itertools . islice ( get_user_conversations (), max_results ) )
40
+ conversations = list_conversations ( max_results )
84
41
if not conversations :
85
42
print ("No conversations found." )
86
43
return
87
44
88
45
print (f"Recent conversations (showing up to { max_results } ):" )
89
46
for i , conv in enumerate (conversations , 1 ):
90
- print (f"\n { i } . { conv .name } " )
91
- print (f" Created: { conv .created } " )
47
+ if metadata :
48
+ print () # Add a newline between conversations
49
+ print (f"{ i :2} . { textwrap .indent (conv .format (metadata = True ), ' ' )[4 :]} " )
92
50
93
51
log_path = Path (conv .path )
94
52
log_manager = LogManager .load (log_path )
95
53
96
- summary_lines = _summarize_conversation (log_manager , include_summary )
97
- print ("\n " .join (summary_lines ))
54
+ # Use the LLM to generate a summary if requested
55
+ if include_summary :
56
+ summary = summarize (log_manager .log .messages )
57
+ print (
58
+ f"\n Summary:\n { textwrap .indent (summary .content , ' > ' , predicate = lambda _ : True )} "
59
+ )
60
+ print ()
98
61
99
62
100
63
def search_chats (query : str , max_results : int = 5 , system = False ) -> None :
@@ -106,11 +69,10 @@ def search_chats(query: str, max_results: int = 5, system=False) -> None:
106
69
max_results (int): Maximum number of conversations to display.
107
70
system (bool): Whether to include system messages in the search.
108
71
"""
109
- # noreorder
110
- from ..logmanager import LogManager , get_user_conversations # fmt: skip
72
+ from ..logmanager import LogManager , list_conversations # fmt: skip
111
73
112
74
results : list [dict ] = []
113
- for conv in get_user_conversations ( ):
75
+ for conv in list_conversations ( max_results ):
114
76
log_path = Path (conv .path )
115
77
log_manager = LogManager .load (log_path )
116
78
@@ -119,37 +81,31 @@ def search_chats(query: str, max_results: int = 5, system=False) -> None:
119
81
if matching_messages :
120
82
results .append (
121
83
{
122
- "conversation" : conv . name ,
84
+ "conversation" : conv ,
123
85
"log_manager" : log_manager ,
124
86
"matching_messages" : matching_messages ,
125
87
}
126
88
)
127
89
128
- if len (results ) >= max_results :
129
- break
130
-
131
- # Sort results by the number of matching messages, in descending order
132
- results .sort (key = lambda x : len (x ["matching_messages" ]), reverse = True )
133
-
134
90
if not results :
135
91
print (f"No results found for query: '{ query } '" )
136
92
return
137
93
94
+ # Sort results by the number of matching messages, in descending order
95
+ results .sort (key = lambda x : len (x ["matching_messages" ]), reverse = True )
96
+
138
97
print (f"Search results for query: '{ query } '" )
139
98
print (f"Found matches in { len (results )} conversation(s):" )
140
99
141
100
for i , result in enumerate (results , 1 ):
142
- print (f"\n { i } . Conversation: { result ['conversation' ]} " )
101
+ conversation = result ["conversation" ]
102
+ print (f"\n { i } . { conversation .format ()} " )
143
103
print (f" Number of matching messages: { len (result ['matching_messages' ])} " )
144
104
145
- summary_lines = _summarize_conversation (
146
- result ["log_manager" ], include_summary = False
147
- )
148
- print ("\n " .join (summary_lines ))
149
-
105
+ # Show sample matches
150
106
print (" Sample matches:" )
151
107
for j , msg in enumerate (result ["matching_messages" ][:3 ], 1 ):
152
- print (f" { j } . { _format_message_snippet ( msg )} " )
108
+ print (f" { j } . { msg . format ( max_length = 100 )} " )
153
109
if len (result ["matching_messages" ]) > 3 :
154
110
print (
155
111
f" ... and { len (result ['matching_messages' ]) - 3 } more matching message(s)"
@@ -165,23 +121,18 @@ def read_chat(conversation: str, max_results: int = 5, incl_system=False) -> Non
165
121
max_results (int): Maximum number of messages to display.
166
122
incl_system (bool): Whether to include system messages.
167
123
"""
168
- # noreorder
169
- from ..logmanager import LogManager , get_conversations # fmt: skip
170
-
171
- conversations = list (get_conversations ())
124
+ from ..logmanager import LogManager , list_conversations # fmt: skip
172
125
173
- for conv in conversations :
126
+ for conv in list_conversations () :
174
127
if conv .name == conversation :
175
128
log_path = Path (conv .path )
176
129
logmanager = LogManager .load (log_path )
177
130
print (f"Reading conversation: { conversation } " )
178
131
i = 0
179
132
for msg in logmanager .log :
180
133
if msg .role != "system" or incl_system :
181
- print (f"{ i } . { _format_message_snippet ( msg )} " )
134
+ print (f"{ i } . { msg . format ( max_length = 100 )} " )
182
135
i += 1
183
- else :
184
- print (f"{ i } . (system message)" )
185
136
if i >= max_results :
186
137
break
187
138
break
0 commit comments