package cli import ( "errors" "fmt" "sync" "gitea.maximumdirect.net/eric/audita/v3/internal/core/normalization" "gitea.maximumdirect.net/eric/audita/v3/internal/core/outputschema" "gitea.maximumdirect.net/eric/audita/v3/internal/core/reporting" "gitea.maximumdirect.net/eric/audita/v3/internal/core/schema" "gitea.maximumdirect.net/eric/audita/v3/internal/framework/llm" "go.maximumdirect.net/ckconfig" commandkit "go.maximumdirect.net/commandkit" ck "go.maximumdirect.net/configkit" ) // processResult carries the runner's transcript and ordinary report facts. type processResult struct { Transcript *schema.Transcript Snapshot reporting.Snapshot } func runProcess(inv commandkit.Invocation, input processInput) commandkit.Outcome { loaded, err := loadProcessInputs(inv.Context, input, inv.ReportingMode()) if err != nil { if inv.Context.Err() != nil || llm.IsAssetError(err) { return commandkit.Failure("Could not prepare processing.").WithCause(err) } var loadErr *ck.LoadError if errors.As(err, &loadErr) { _, explanation := ckconfig.AdaptDiagnostics("Application configuration:\n", loadErr.Sources(), loadErr.Diagnostics()) return commandkit.Usage(loadErr.Error(), explanation.Details...).WithCause(err) } return commandkit.Usage(err.Error()).WithCause(err) } prepared, err := prepareProcess(inv.Context, input, loaded, inv.Reporter().Output()) if err != nil { return commandkit.Failure(loaded.Runtime.RedactError(inv.Context, err)).WithCause(err) } defer prepared.Prepared.Output.Close() var warningsMu sync.Mutex warn := func(err error) { if err == nil { return } warningsMu.Lock() prepared.Prepared.Warnings = append(prepared.Prepared.Warnings, err) warningsMu.Unlock() } debug := prepared.Prepared.Debug if debug != nil { warn(debug.WriteSourceTranscript(loaded.Source, loaded.RawTranscript)) } cfg := &loaded.Configuration.Config normalizer := normalization.NewNormalizer(normalization.NormalizationConfig{ MaxSegmentGap: cfg.Normalization.MaxSegmentGap, EllipsisGap: cfg.Normalization.EllipsisGap, MaxSegmentDuration: cfg.Normalization.MaxSegmentDuration, MaxSegmentTokens: cfg.Normalization.MaxSegmentTokens, }) normalized, summary := normalizer.Normalize(sourceToCanonicalTranscript(loaded.Source)) if debug != nil { warn(debug.WriteNormalizedTranscript(normalized)) warn(debug.WriteNormalizationSummary(summary)) } if err := inv.Context.Err(); err != nil { return finishProcess(inv, input, loaded, prepared, reporting.Snapshot{}, nil, err) } result, runErr := executePipeline(inv.Context, loaded, prepared, normalized, warn) if runErr != nil { return finishProcess(inv, input, loaded, prepared, result.Snapshot, nil, runErr) } encoder, err := outputschema.Resolve(cfg.Output.Schema) if err != nil { return finishProcess(inv, input, loaded, prepared, result.Snapshot, nil, err) } if result.Transcript == nil { return finishProcess(inv, input, loaded, prepared, result.Snapshot, nil, fmt.Errorf("processing returned no transcript")) } payload, err := encoder.Encoder(result.Transcript) if err != nil { return finishProcess(inv, input, loaded, prepared, result.Snapshot, nil, err) } return finishProcess(inv, input, loaded, prepared, result.Snapshot, payload, nil) } // DebugPath returns the retained artifact directory, if its preparation succeeded. func (p *preparedProcess) DebugPath() string { if p == nil || p.Prepared == nil || p.Prepared.Debug == nil { return "" } return p.Prepared.Debug.Path() }