File size: 3,638 Bytes
7fcdb70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { AgentStep, AgentTrace, AgentTraceMetadata, FinalStep } from '@/types/agent';

/**

 * Extract final answer from steps

 */
const extractFinalAnswer = (steps: AgentStep[]): string | null => {
  if (!steps || steps.length === 0) {
    return null;
  }

  // Try to find final_answer in any step (iterate backwards)
  for (let i = steps.length - 1; i >= 0; i--) {
    const step = steps[i];

    if (step.actions && Array.isArray(step.actions)) {
      const finalAnswerAction = step.actions.find(
        (action) => action.function_name === 'final_answer'
      );

      if (finalAnswerAction && finalAnswerAction.parameters?.answer) {
        return String(finalAnswerAction.parameters.answer);
      }
    }
  }

  // Fallback: return the last thought if no final_answer found
  const lastStep = steps[steps.length - 1];
  return lastStep?.thought || null;
};

/**

 * Export the complete trace as JSON

 * @param trace The agent trace

 * @param steps The trace steps

 * @param metadata The final metadata

 * @param finalStep The final step with completion status

 * @returns A JSON object containing the entire trace

 */
export const exportTraceToJson = (
  trace: AgentTrace,
  steps: AgentStep[],
  metadata?: AgentTraceMetadata,
  finalStep?: FinalStep
): string => {
  const exportData = getTraceExportData(trace, steps, metadata, finalStep);
  return JSON.stringify(exportData, null, 2);
};

/**

 * Get the trace export data as an object (for upload or other processing)

 * @param trace The agent trace

 * @param steps The trace steps

 * @param metadata The final metadata

 * @param finalStep The final step with completion status

 * @returns An object containing the entire trace data

 */
export const getTraceExportData = (
  trace: AgentTrace,
  steps: AgentStep[],
  metadata?: AgentTraceMetadata,
  finalStep?: FinalStep
): object => {
  // Get the most up-to-date metadata (prefer finalStep.metadata if available)
  const finalMetadata = finalStep?.metadata || metadata || trace.traceMetadata;
  
  return {
    trace: {
      id: trace.id,
      timestamp: trace.timestamp,
      instruction: trace.instruction,
      modelId: trace.modelId,
      isRunning: trace.isRunning,
    },
    completion: finalStep ? {
      status: finalStep.type,
      message: finalStep.message || null,
      finalAnswer: extractFinalAnswer(steps),
    } : null,
    metadata: finalMetadata,
    // Explicitly include user_evaluation at top level for easy access
    user_evaluation: finalMetadata?.user_evaluation || 'not_evaluated',
    steps: steps.map((step) => ({
      traceId: step.traceId,
      stepId: step.stepId,
      error: step.error,
      image: step.image, // Include full base64 image
      thought: step.thought,
      actions: step.actions,
      duration: step.duration,
      inputTokensUsed: step.inputTokensUsed,
      outputTokensUsed: step.outputTokensUsed,
      step_evaluation: step.step_evaluation,
    })),
    exportedAt: new Date().toISOString(),
  };
};

/**

 * Download a JSON with a filename

 * @param jsonString JSON string to download

 * @param filename Filename to download

 */
export const downloadJson = (jsonString: string, filename: string = 'trace.json') => {
  const blob = new Blob([jsonString], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
};