@@ -21,9 +21,10 @@ import { resolve } from 'node:path';
2121import React from 'react' ;
2222import { Box , Text , useInput } from 'ink' ;
2323import TextInput from 'ink-text-input' ;
24- import { Connection , SfError , Lifecycle } from '@salesforce/core' ;
24+ import { Connection , SfError , Lifecycle , Logger } from '@salesforce/core' ;
2525import { AgentPreviewBase , AgentPreviewSendResponse , writeDebugLog } from '@salesforce/agents' ;
2626import { sleep , env } from '@salesforce/kit' ;
27+ import { PlannerResponse } from '@salesforce/agents/lib/types.js' ;
2728
2829// Component to show a simple typing animation
2930function Typing ( ) : React . ReactNode {
@@ -52,7 +53,8 @@ function Typing(): React.ReactNode {
5253export const saveTranscriptsToFile = (
5354 outputDir : string ,
5455 messages : Array < { timestamp : Date ; role : string ; content : string } > ,
55- responses : AgentPreviewSendResponse [ ]
56+ responses : AgentPreviewSendResponse [ ] ,
57+ traces ?: PlannerResponse [ ]
5658) : void => {
5759 if ( ! outputDir ) return ;
5860 fs . mkdirSync ( outputDir , { recursive : true } ) ;
@@ -62,6 +64,29 @@ export const saveTranscriptsToFile = (
6264
6365 const responsesPath = path . join ( outputDir , 'responses.json' ) ;
6466 fs . writeFileSync ( responsesPath , JSON . stringify ( responses , null , 2 ) ) ;
67+
68+ if ( traces ) {
69+ const tracesPath = path . join ( outputDir , 'traces.json' ) ;
70+ fs . writeFileSync ( tracesPath , JSON . stringify ( traces , null , 2 ) ) ;
71+ }
72+ } ;
73+
74+ export const getTraces = async (
75+ agent : AgentPreviewBase ,
76+ sessionId : string ,
77+ messageIds : string [ ] ,
78+ logger : Logger
79+ ) : Promise < PlannerResponse [ ] > => {
80+ if ( messageIds . length > 0 ) {
81+ try {
82+ const traces = await agent . traces ( sessionId , messageIds ) ;
83+ return traces ;
84+ } catch ( e ) {
85+ const sfError = SfError . wrap ( e ) ;
86+ logger . info ( `Error obtaining traces: ${ sfError . name } - ${ sfError . message } ` , { sessionId, messageIds } ) ;
87+ }
88+ }
89+ return [ ] ;
6590} ;
6691
6792/**
@@ -78,6 +103,7 @@ export function AgentPreviewReact(props: {
78103 readonly outputDir : string | undefined ;
79104 readonly isLocalAgent : boolean ;
80105 readonly apexDebug : boolean | undefined ;
106+ readonly logger : Logger ;
81107} ) : React . ReactNode {
82108 const [ messages , setMessages ] = React . useState < Array < { timestamp : Date ; role : string ; content : string } > > ( [ ] ) ;
83109 const [ header , setHeader ] = React . useState ( 'Starting session...' ) ;
@@ -96,8 +122,9 @@ export function AgentPreviewReact(props: {
96122 const [ tempDir , setTempDir ] = React . useState ( '' ) ;
97123 const [ responses , setResponses ] = React . useState < AgentPreviewSendResponse [ ] > ( [ ] ) ;
98124 const [ apexDebugLogs , setApexDebugLogs ] = React . useState < string [ ] > ( [ ] ) ;
125+ const [ messageIds , setMessageIds ] = React . useState < string [ ] > ( [ ] ) ;
99126
100- const { connection, agent, name, outputDir, isLocalAgent, apexDebug } = props ;
127+ const { connection, agent, name, outputDir, isLocalAgent, apexDebug, logger } = props ;
101128
102129 useInput ( ( input , key ) => {
103130 // If user is in directory input and presses ESC, cancel and exit without saving
@@ -222,7 +249,9 @@ export function AgentPreviewReact(props: {
222249 const sessionDir = path . join ( finalDir , `${ dateForDir } --${ sessionId || 'session' } ` ) ;
223250 fs . mkdirSync ( sessionDir , { recursive : true } ) ;
224251
225- saveTranscriptsToFile ( sessionDir , messages , responses ) ;
252+ const traces = await getTraces ( agent , sessionId , messageIds , logger ) ;
253+
254+ saveTranscriptsToFile ( sessionDir , messages , responses , traces ) ;
226255
227256 // Write apex debug logs if any
228257 if ( apexDebug ) {
@@ -246,7 +275,7 @@ export function AgentPreviewReact(props: {
246275 }
247276 } ;
248277 void saveAndExit ( ) ;
249- } , [ saveConfirmed , saveDir , messages , responses , sessionId , apexDebug , connection ] ) ;
278+ } , [ saveConfirmed , saveDir , messages , responses , sessionId , apexDebug , connection , agent , messageIds , logger ] ) ;
250279
251280 return (
252281 < Box flexDirection = "column" >
@@ -395,6 +424,7 @@ export function AgentPreviewReact(props: {
395424
396425 // Add the agent's response to the chat
397426 setMessages ( ( prev ) => [ ...prev , { role : name , content : message , timestamp : new Date ( ) } ] ) ;
427+ setMessageIds ( ( prev ) => [ ...prev , response . messages [ 0 ] . planId ] ) ;
398428
399429 // Apex debug logs will be saved when user exits and chooses to save
400430 } catch ( e ) {
@@ -422,6 +452,7 @@ export function AgentPreviewReact(props: {
422452 < Text bold > Session Ended</ Text >
423453 { tempDir ? < Text > Conversation log: { tempDir } /transcript.json</ Text > : null }
424454 { tempDir ? < Text > API transactions: { tempDir } /responses.json</ Text > : null }
455+ { tempDir ? < Text > Traces: { tempDir } /traces.json</ Text > : null }
425456 { apexDebugLogs . length > 0 && tempDir && < Text > Apex Debug Logs saved to: { tempDir } </ Text > }
426457 </ Box >
427458 ) : null }
0 commit comments