AuditWorkflowRun audits a single workflow run and generates a report If jobID is provided (>0), focuses audit on that specific job If stepNumber is provided (>0), extracts output for that specific step If experimentFilter is non-empty, the run is skipped when its experiment artifact does not contain
(ctx context.Context, runID int64, opts AuditOptions)
| 336 | // not contain an assignment for that experiment name. If variantFilter is also non-empty, |
| 337 | // the assigned variant must equal variantFilter. |
| 338 | func AuditWorkflowRun(ctx context.Context, runID int64, opts AuditOptions) error { |
| 339 | cfg, err := newAuditRunConfig(runID, opts) |
| 340 | if err != nil { |
| 341 | return err |
| 342 | } |
| 343 | if err := ensureAuditNotCancelled(ctx); err != nil { |
| 344 | return err |
| 345 | } |
| 346 | announceAuditRun(cfg) |
| 347 | if cfg.jobID > 0 { |
| 348 | return auditJobRun(cfg.jobOptions()) |
| 349 | } |
| 350 | if done, err := renderCachedAuditIfAvailable(ctx, cfg); done { |
| 351 | return err |
| 352 | } |
| 353 | run, err := prepareAuditWorkflowRun(ctx, cfg) |
| 354 | if err != nil { |
| 355 | return err |
| 356 | } |
| 357 | results := collectAuditAnalysisResults(run, cfg.outputDir, cfg.verbose, artifactMatchesFilter(constants.AgentArtifactName, cfg.artifactFilter)) |
| 358 | run = applyAuditMetrics(run, results) |
| 359 | processedRun := buildProcessedAuditRun(run, results) |
| 360 | saveAuditRunSummary(cfg.outputDir, run, processedRun, results, cfg.verbose) |
| 361 | if shouldSkipAuditRun(cfg.runID, cfg.outputDir, cfg.experimentFilter, cfg.variantFilter) { |
| 362 | return nil |
| 363 | } |
| 364 | return renderAuditReport(ctx, processedRun, results.metrics, results.mcpToolUsage, cfg.auditOptions()) |
| 365 | } |
| 366 | |
| 367 | func newAuditRunConfig(runID int64, opts AuditOptions) (auditRunConfig, error) { |
| 368 | if err := ValidateArtifactSets(opts.ArtifactSets); err != nil { |