@@ -16,14 +16,14 @@ import (
1616)
1717
1818type ChatLogger struct {
19- logFile * os.File
20- logFormat string
21- console io.Writer
22- agentColors map [string ]lipgloss.Style
23- colorIndex int
24- termWidth int
25- showMetrics bool
26- jsonEmitter * bridge.StdoutEmitter // For JSON mode output
19+ logFile * os.File
20+ logFormat string
21+ console io.Writer
22+ agentColors map [string ]lipgloss.Style
23+ colorIndex int
24+ termWidth int
25+ showMetrics bool
26+ jsonEmitter * bridge.StdoutEmitter // For JSON mode output
2727}
2828
2929var colors = []lipgloss.Color {
@@ -171,125 +171,155 @@ func (l *ChatLogger) LogMessage(msg agent.Message) {
171171
172172 // If JSON emitter is set, emit as JSON event
173173 if l .jsonEmitter != nil {
174- var metrics * bridge.LogEntryMetrics
175- if msg .Metrics != nil {
176- metrics = & bridge.LogEntryMetrics {
177- DurationSeconds : msg .Metrics .Duration .Seconds (),
178- TotalTokens : msg .Metrics .TotalTokens ,
179- Cost : msg .Metrics .Cost ,
180- }
174+ l .emitJSONLog (msg )
175+ return
176+ }
177+
178+ // Write to file
179+ l .writeFileLog (msg , timestamp )
180+
181+ // Write to console with colors
182+ l .writeConsoleLog (msg , timestamp )
183+ }
184+
185+ // emitJSONLog emits a message as a JSON log entry
186+ func (l * ChatLogger ) emitJSONLog (msg agent.Message ) {
187+ var metrics * bridge.LogEntryMetrics
188+ if msg .Metrics != nil {
189+ metrics = & bridge.LogEntryMetrics {
190+ DurationSeconds : msg .Metrics .Duration .Seconds (),
191+ TotalTokens : msg .Metrics .TotalTokens ,
192+ Cost : msg .Metrics .Cost ,
181193 }
194+ }
182195
183- l .jsonEmitter .EmitLogEntry (
184- "message" ,
185- msg .AgentID ,
186- msg .AgentName ,
187- msg .AgentType ,
188- msg .Content ,
189- msg .Role ,
190- metrics ,
191- nil , // metadata
192- )
196+ l .jsonEmitter .EmitLogEntry (
197+ "message" ,
198+ msg .AgentID ,
199+ msg .AgentName ,
200+ msg .AgentType ,
201+ msg .Content ,
202+ msg .Role ,
203+ metrics ,
204+ nil , // metadata
205+ )
206+ }
207+
208+ // writeFileLog writes a message to the log file
209+ func (l * ChatLogger ) writeFileLog (msg agent.Message , timestamp string ) {
210+ if l .logFile == nil {
193211 return
194212 }
195213
196- // Write to file
197- if l .logFile != nil {
198- if l .logFormat == "json" {
199- data , err := json .Marshal (msg )
200- if err == nil {
201- l .writeToFile (string (data ) + "\n " )
202- }
203- } else {
204- l .writeToFile (fmt .Sprintf ("[%s] %s (%s): %s\n \n " ,
205- timestamp , msg .AgentName , msg .Role , msg .Content ))
214+ if l .logFormat == "json" {
215+ data , err := json .Marshal (msg )
216+ if err == nil {
217+ l .writeToFile (string (data ) + "\n " )
206218 }
219+ } else {
220+ l .writeToFile (fmt .Sprintf ("[%s] %s (%s): %s\n \n " ,
221+ timestamp , msg .AgentName , msg .Role , msg .Content ))
207222 }
223+ }
208224
209- // Write to console with colors
210- if l .console != nil {
211- var output strings.Builder
225+ // writeConsoleLog writes a formatted message to the console
226+ func (l * ChatLogger ) writeConsoleLog (msg agent.Message , timestamp string ) {
227+ if l .console == nil {
228+ return
229+ }
212230
213- // Add a subtle separator line
214- output .WriteString (separatorStyle .Render (strings .Repeat ("─" , min (l .termWidth , 80 ))))
215- output .WriteString ("\n " )
231+ var output strings.Builder
216232
217- // Format timestamp with icon
218- output .WriteString (timestampStyle .Render ("🕐 " + timestamp + " " ))
219-
220- // Format agent name with badge
221- isHost := msg .Role == "system" && (msg .AgentID == "host" || msg .AgentName == "HOST" )
222- isSystemMsg := msg .Role == "system" && ! isHost
223-
224- if isSystemMsg {
225- // Regular SYSTEM messages (agent join announcements, etc.)
226- output .WriteString (systemBadgeStyle .Render (" SYSTEM " ))
227- output .WriteString (systemStyle .Render (msg .Content ))
228- } else {
229- // Agent messages or HOST message (format the same way)
230- var badgeStyle lipgloss.Style
231- var contentStyle lipgloss.Style
232-
233- if isHost {
234- // HOST message (orchestrator's initial prompt)
235- badgeStyle = lipgloss .NewStyle ().
236- Background (lipgloss .Color ("99" )). // Purple
237- Foreground (lipgloss .Color ("0" )).
238- Bold (true ).
239- Padding (0 , 1 ).
240- MarginRight (1 )
241- contentStyle = lipgloss .NewStyle ().
242- Foreground (lipgloss .Color ("99" )).
243- Bold (true )
244- output .WriteString (badgeStyle .Render (" HOST " ))
245- } else {
246- // Regular agent message
247- // Ensure agent color is assigned first (this populates l.agentColors)
248- contentStyle = l .getAgentColor (msg .AgentName )
249- badgeStyle = l .getAgentBadgeStyle (msg .AgentName )
250-
251- // Include agent type in parentheses if available
252- displayName := msg .AgentName
253- if msg .AgentType != "" {
254- displayName = fmt .Sprintf ("%s (%s)" , msg .AgentName , msg .AgentType )
255- }
256- output .WriteString (badgeStyle .Render (" " + displayName + " " ))
257- }
233+ // Add a subtle separator line
234+ output .WriteString (separatorStyle .Render (strings .Repeat ("─" , min (l .termWidth , 80 ))))
235+ output .WriteString ("\n " )
258236
259- // Add metrics if enabled and available
260- if l .showMetrics && msg .Metrics != nil {
261- metricsStyle := lipgloss .NewStyle ().
262- Foreground (lipgloss .Color ("240" )).
263- Italic (true )
237+ // Format timestamp with icon
238+ output .WriteString (timestampStyle .Render ("🕐 " + timestamp + " " ))
264239
265- metricsStr := fmt .Sprintf ("(%.2fs, %d tokens, $%.6f)" ,
266- msg .Metrics .Duration .Seconds (),
267- msg .Metrics .TotalTokens ,
268- msg .Metrics .Cost )
240+ // Format agent name with badge
241+ isHost := msg .Role == "system" && (msg .AgentID == "host" || msg .AgentName == "HOST" )
242+ isSystemMsg := msg .Role == "system" && ! isHost
269243
270- output .WriteString (" " )
271- output .WriteString (metricsStyle .Render (metricsStr ))
272- }
244+ if isSystemMsg {
245+ l .writeSystemMessage (& output , msg )
246+ } else {
247+ l .writeAgentMessage (& output , msg , isHost )
248+ }
249+
250+ output .WriteString ("\n " )
251+ fmt .Fprint (l .console , output .String ())
252+ }
273253
274- output .WriteString ("\n \n " )
254+ // writeSystemMessage formats and writes a system message
255+ func (l * ChatLogger ) writeSystemMessage (output * strings.Builder , msg agent.Message ) {
256+ output .WriteString (systemBadgeStyle .Render (" SYSTEM " ))
257+ output .WriteString (systemStyle .Render (msg .Content ))
258+ }
275259
276- // Format and wrap message content with nice indentation
277- wrappedContent := l .wrapText (msg .Content , 2 )
260+ // writeAgentMessage formats and writes an agent message
261+ func (l * ChatLogger ) writeAgentMessage (output * strings.Builder , msg agent.Message , isHost bool ) {
262+ var badgeStyle , contentStyle lipgloss.Style
278263
279- // Apply color to each line
280- lines := strings .Split (wrappedContent , "\n " )
281- for _ , line := range lines {
282- output .WriteString (contentStyle .Render (line ))
283- output .WriteString ("\n " )
284- }
264+ if isHost {
265+ badgeStyle , contentStyle = l .getHostStyles ()
266+ output .WriteString (badgeStyle .Render (" HOST " ))
267+ } else {
268+ contentStyle = l .getAgentColor (msg .AgentName )
269+ badgeStyle = l .getAgentBadgeStyle (msg .AgentName )
270+
271+ displayName := msg .AgentName
272+ if msg .AgentType != "" {
273+ displayName = fmt .Sprintf ("%s (%s)" , msg .AgentName , msg .AgentType )
285274 }
275+ output .WriteString (badgeStyle .Render (" " + displayName + " " ))
276+ }
286277
287- output .WriteString ("\n " )
278+ // Add metrics if enabled and available
279+ if l .showMetrics && msg .Metrics != nil {
280+ l .writeMetrics (output , msg .Metrics )
281+ }
288282
289- fmt .Fprint (l .console , output .String ())
283+ output .WriteString ("\n \n " )
284+
285+ // Format and wrap message content with nice indentation
286+ wrappedContent := l .wrapText (msg .Content , 2 )
287+ lines := strings .Split (wrappedContent , "\n " )
288+ for _ , line := range lines {
289+ output .WriteString (contentStyle .Render (line ))
290+ output .WriteString ("\n " )
290291 }
291292}
292293
294+ // getHostStyles returns the badge and content styles for host messages
295+ func (l * ChatLogger ) getHostStyles () (lipgloss.Style , lipgloss.Style ) {
296+ badgeStyle := lipgloss .NewStyle ().
297+ Background (lipgloss .Color ("99" )). // Purple
298+ Foreground (lipgloss .Color ("0" )).
299+ Bold (true ).
300+ Padding (0 , 1 ).
301+ MarginRight (1 )
302+ contentStyle := lipgloss .NewStyle ().
303+ Foreground (lipgloss .Color ("99" )).
304+ Bold (true )
305+ return badgeStyle , contentStyle
306+ }
307+
308+ // writeMetrics formats and writes metrics to the output
309+ func (l * ChatLogger ) writeMetrics (output * strings.Builder , metrics * agent.ResponseMetrics ) {
310+ metricsStyle := lipgloss .NewStyle ().
311+ Foreground (lipgloss .Color ("240" )).
312+ Italic (true )
313+
314+ metricsStr := fmt .Sprintf ("(%.2fs, %d tokens, $%.6f)" ,
315+ metrics .Duration .Seconds (),
316+ metrics .TotalTokens ,
317+ metrics .Cost )
318+
319+ output .WriteString (" " )
320+ output .WriteString (metricsStyle .Render (metricsStr ))
321+ }
322+
293323func (l * ChatLogger ) LogError (agentName string , err error ) {
294324 timestamp := time .Now ().Format ("15:04:05" )
295325
0 commit comments