onTrialEnd method

  1. @override
Future<void> onTrialEnd({
  1. required Trial trial,
  2. required Transcript transcript,
  3. required Outcome outcome,
  4. required List<Score> scores,
})
override

Called when trial finishes with the final transcript, outcome, and scores. Implementations should attach all scores here.

Implementation

@override
Future<void> onTrialEnd({
  required Trial trial,
  required Transcript transcript,
  required Outcome outcome,
  required List<Score> scores,
}) async {
  final traceId = _traceIdFor(trial);

  // 用 trace-create 再写一次同 id 的 trace 来 merge:补 endTime / output /
  // 终态 metadata(30 天内 langfuse 服务端会按 id 合并)。
  _client.enqueue(
    LangfuseEvent(
      id: _uuid.v4(),
      type: 'trace-create',
      timestamp: trial.endedAt,
      body: {
        'id': traceId,
        'timestamp': trial.startedAt.toUtc().toIso8601String(),
        'name': '${trial.suiteName}/${trial.taskId}#${trial.trialIndex}',
        'environment': config.environment,
        'userId': trial.runName,
        'sessionId': trial.suiteName,
        'output': outcome.toJson(),
        'metadata': {
          'status': trial.status.name,
          if (trial.failureReason != null)
            'failureReason': trial.failureReason,
          'durationMs': trial.duration.inMilliseconds,
          'transcriptMetrics': transcript.metrics.toJson(),
        },
      },
    ),
  );

  // 每个 grader 一条 score-create。
  for (final s in scores) {
    if (s.value == null) continue; // null score 不上传(langfuse 不支持)
    _client.enqueue(
      LangfuseEvent(
        id: _uuid.v4(),
        type: 'score-create',
        timestamp: trial.endedAt,
        body: {
          'id': _uuid.v4(),
          'traceId': traceId,
          'environment': config.environment,
          'name': s.graderName,
          'value': s.value,
          'dataType': 'NUMERIC',
          if (s.rationale != null) 'comment': s.rationale,
          'metadata': {
            if (s.passed != null) 'passed': s.passed,
            'assertions': s.assertions.map((a) => a.toJson()).toList(),
            ...s.metadata,
          },
        },
      ),
    );
  }
}