Files
audita/examples/library-adoption/workflow.go

101 lines
3.8 KiB
Go

package main
import (
"context"
"encoding/json"
coreconfig "gitea.maximumdirect.net/eric/audita/internal/core/config"
"gitea.maximumdirect.net/eric/audita/internal/core/schema"
"gitea.maximumdirect.net/eric/audita/internal/framework/promptcontext"
"gitea.maximumdirect.net/eric/audita/internal/framework/proposals"
"gitea.maximumdirect.net/eric/audita/internal/framework/validators"
pk "gitea.maximumdirect.net/eric/promptkit"
)
type WorkflowResult struct {
Accepted int `json:"accepted"`
Rejected int `json:"rejected"`
Warnings []string `json:"warnings,omitempty"`
}
// workflow demonstrates one section and two roles; it never mutates a transcript.
// Production migration will retain the full validator chains and runner.
func (r *Runtime) workflow(ctx context.Context, observe func(string) pk.ExecutionObserver) (WorkflowResult, error) {
var out WorkflowResult
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "hello world"}}}
section, err := promptcontext.MarshalTranscriptSectionJSON(transcript, 0)
if err != nil {
return out, err
}
vars := map[string]string{"SectionJSON": string(section), "GlossaryJSON": "[]", "TranscriptDescriptionBlock": promptcontext.TranscriptDescriptionBlock("Synthetic grammar example")}
result, err := r.call(ctx, "proposal", vars, observe("proposal"))
if err != nil {
return out, err
}
if !result.Validation.IsValid {
out.Warnings = append(out.Warnings, "proposal_response_malformed")
return out, nil
}
var response struct {
Corrections []proposals.CorrectionProposal `json:"corrections"`
}
if err := json.Unmarshal([]byte(result.RawOutput), &response); err != nil {
return out, err
}
candidates := []proposals.EnrichedCorrectionProposal{}
payload := []map[string]any{}
for index, p := range response.Corrections {
preview := proposals.PreviewProposalForSegment(&transcript.Segments[0], p, proposals.ReplacementPolicyRequireUnique)
if !preview.Applicable || p.Confidence < coreconfig.Default().Thresholds.Grammar {
out.Rejected++
continue
}
candidates = append(candidates, proposals.EnrichedCorrectionProposal{CorrectionProposal: p, ProposalMetadata: proposals.ProposalMetadata{ProposalIndex: index}})
payload = append(payload, map[string]any{"correction_index": index, "id": p.TargetSegmentID, "original_text": p.OriginalText, "corrected_text": p.CorrectedText, "original_segment_text": transcript.Segments[0].Text, "corrected_segment_text": preview.CorrectedSegmentText})
}
if len(candidates) == 0 {
return out, nil
}
body, err := json.Marshal(payload)
if err != nil {
return out, err
}
result, err = r.call(ctx, "assessment", map[string]string{"PayloadJSON": string(body), "TranscriptDescriptionBlock": vars["TranscriptDescriptionBlock"]}, observe("assessment"))
if err != nil {
return out, err
}
if !result.Validation.IsValid {
out.Rejected += len(candidates)
out.Warnings = append(out.Warnings, "validator_response_malformed")
return out, nil
}
var assessment struct {
Validations []struct {
Index int `json:"correction_index"`
Approved bool `json:"approved"`
Confidence float64 `json:"confidence"`
Reason string `json:"reason"`
} `json:"validations"`
}
if err := json.Unmarshal([]byte(result.RawOutput), &assessment); err != nil {
return out, err
}
decisions := make([]validators.Decision, len(assessment.Validations))
for i, d := range assessment.Validations {
decisions[i] = validators.Decision{ProposalIndex: d.Index, Approved: d.Approved}
}
if err := validators.EnforceDecisionCardinality(candidates, decisions); err != nil {
out.Rejected += len(candidates)
out.Warnings = append(out.Warnings, "validator_response_malformed")
return out, nil
}
for _, d := range decisions {
if d.Approved {
out.Accepted++
} else {
out.Rejected++
}
}
return out, nil
}