Skip to content

Commit b098ae5

Browse files
feat: save traces to file
1 parent a896b2e commit b098ae5

File tree

2 files changed

+44
-6
lines changed

2 files changed

+44
-6
lines changed

src/commands/agent/preview.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import * as path from 'node:path';
1818
import { join, resolve } from 'node:path';
1919
import { globSync } from 'glob';
2020
import { Flags, SfCommand } from '@salesforce/sf-plugins-core';
21-
import { AuthInfo, Connection, Lifecycle, Messages, SfError } from '@salesforce/core';
21+
import { AuthInfo, Connection, Lifecycle, Logger, Messages, SfError } from '@salesforce/core';
2222
import React from 'react';
2323
import { render } from 'ink';
2424
import {
@@ -35,6 +35,14 @@ import { AgentPreviewReact } from '../../components/agent-preview-react.js';
3535
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
3636
const messages = Messages.loadMessages('@salesforce/plugin-agent', 'agent.preview');
3737

38+
let logger: Logger;
39+
const getLogger = (): Logger => {
40+
if (!logger) {
41+
logger = Logger.childFromRoot('plugin-agent-preview');
42+
}
43+
return logger;
44+
};
45+
3846
type BotVersionStatus = { Status: 'Active' | 'Inactive' };
3947

4048
export type AgentData = {
@@ -195,6 +203,7 @@ export default class AgentPreview extends SfCommand<AgentPreviewResult> {
195203
outputDir,
196204
isLocalAgent: selectedAgent.source === AgentSource.SCRIPT,
197205
apexDebug: flags['apex-debug'],
206+
logger: getLogger(),
198207
}),
199208
{ exitOnCtrlC: false }
200209
);

src/components/agent-preview-react.tsx

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ import { resolve } from 'node:path';
2121
import React from 'react';
2222
import { Box, Text, useInput } from 'ink';
2323
import TextInput from 'ink-text-input';
24-
import { Connection, SfError, Lifecycle } from '@salesforce/core';
24+
import { Connection, SfError, Lifecycle, Logger } from '@salesforce/core';
2525
import { AgentPreviewBase, AgentPreviewSendResponse, writeDebugLog } from '@salesforce/agents';
2626
import { sleep, env } from '@salesforce/kit';
27+
import { PlannerResponse } from '@salesforce/agents/lib/types.js';
2728

2829
// Component to show a simple typing animation
2930
function Typing(): React.ReactNode {
@@ -52,7 +53,8 @@ function Typing(): React.ReactNode {
5253
export 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,27 @@ 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+
const getTraces = async (
75+
agent: AgentPreviewBase,
76+
sessionId: string,
77+
messageIds: string[],
78+
logger: Logger
79+
): Promise<PlannerResponse[]> => {
80+
try {
81+
const traces = await agent.traces(sessionId, messageIds);
82+
return traces;
83+
} catch (e) {
84+
const sfError = SfError.wrap(e);
85+
logger.info(`Error obtaining traces: ${sfError.name} - ${sfError.message}`, { sessionId, messageIds });
86+
return [];
87+
}
6588
};
6689

6790
/**
@@ -78,6 +101,7 @@ export function AgentPreviewReact(props: {
78101
readonly outputDir: string | undefined;
79102
readonly isLocalAgent: boolean;
80103
readonly apexDebug: boolean | undefined;
104+
readonly logger: Logger;
81105
}): React.ReactNode {
82106
const [messages, setMessages] = React.useState<Array<{ timestamp: Date; role: string; content: string }>>([]);
83107
const [header, setHeader] = React.useState('Starting session...');
@@ -96,8 +120,9 @@ export function AgentPreviewReact(props: {
96120
const [tempDir, setTempDir] = React.useState('');
97121
const [responses, setResponses] = React.useState<AgentPreviewSendResponse[]>([]);
98122
const [apexDebugLogs, setApexDebugLogs] = React.useState<string[]>([]);
123+
const [messageIds, setMessageIds] = React.useState<string[]>([]);
99124

100-
const { connection, agent, name, outputDir, isLocalAgent, apexDebug } = props;
125+
const { connection, agent, name, outputDir, isLocalAgent, apexDebug, logger } = props;
101126

102127
useInput((input, key) => {
103128
// If user is in directory input and presses ESC, cancel and exit without saving
@@ -222,7 +247,9 @@ export function AgentPreviewReact(props: {
222247
const sessionDir = path.join(finalDir, `${dateForDir}--${sessionId || 'session'}`);
223248
fs.mkdirSync(sessionDir, { recursive: true });
224249

225-
saveTranscriptsToFile(sessionDir, messages, responses);
250+
const traces = await getTraces(agent, sessionId, messageIds, logger);
251+
252+
saveTranscriptsToFile(sessionDir, messages, responses, traces);
226253

227254
// Write apex debug logs if any
228255
if (apexDebug) {
@@ -246,7 +273,7 @@ export function AgentPreviewReact(props: {
246273
}
247274
};
248275
void saveAndExit();
249-
}, [saveConfirmed, saveDir, messages, responses, sessionId, apexDebug, connection]);
276+
}, [saveConfirmed, saveDir, messages, responses, sessionId, apexDebug, connection, agent, messageIds, logger]);
250277

251278
return (
252279
<Box flexDirection="column">
@@ -395,6 +422,7 @@ export function AgentPreviewReact(props: {
395422

396423
// Add the agent's response to the chat
397424
setMessages((prev) => [...prev, { role: name, content: message, timestamp: new Date() }]);
425+
setMessageIds((prev) => [...prev, response.messages[0].planId]);
398426

399427
// Apex debug logs will be saved when user exits and chooses to save
400428
} catch (e) {
@@ -422,6 +450,7 @@ export function AgentPreviewReact(props: {
422450
<Text bold>Session Ended</Text>
423451
{tempDir ? <Text>Conversation log: {tempDir}/transcript.json</Text> : null}
424452
{tempDir ? <Text>API transactions: {tempDir}/responses.json</Text> : null}
453+
{tempDir ? <Text>Traces: {tempDir}/traces.json</Text> : null}
425454
{apexDebugLogs.length > 0 && tempDir && <Text>Apex Debug Logs saved to: {tempDir}</Text>}
426455
</Box>
427456
) : null}

0 commit comments

Comments
 (0)