package usecase import ( "context" "errors" "fmt" "strings" "gitea.maximumdirect.net/eric/promptkit/internal/domain" "gitea.maximumdirect.net/eric/promptkit/internal/llm" ) type OutputRepairer interface { Repair(ctx context.Context, req RepairRequest) (*domain.GenerateResponse, error) } type RepairRequest struct { PreviousOutput string ValidationErrors []string SessionID string Target domain.ExecutionTarget TargetPresence domain.ExecutionTargetPresence StructuredOutput *domain.StructuredOutputSpec Attempt int MaxAttempts int Mode domain.ValidationMode } type defaultOutputRepairer struct { llm llm.Client } func NewDefaultOutputRepairer(llmClient llm.Client) OutputRepairer { return &defaultOutputRepairer{llm: llmClient} } func (r *defaultOutputRepairer) Repair(ctx context.Context, req RepairRequest) (*domain.GenerateResponse, error) { if r.llm == nil { return nil, errors.New("llm client is required for repair") } errs := "(none provided)" if len(req.ValidationErrors) > 0 { errs = strings.Join(req.ValidationErrors, "\n") } prompt := domain.RenderedPrompt{ Messages: []domain.RenderedMessage{ { Role: "system", Content: "You repair invalid JSON output. Return only corrected JSON. Do not include explanations or markdown code fences.", }, { Role: "user", Content: fmt.Sprintf( "Repair attempt %d of %d for validation mode %s.\n\nValidation errors:\n%s\n\nPrevious output:\n%s\n\nReturn only corrected JSON.", req.Attempt, req.MaxAttempts, req.Mode, errs, req.PreviousOutput, ), }, }, } resp, err := r.llm.Generate(ctx, newGenerationRequest( prompt, req.SessionID, req.Target, req.TargetPresence, req.StructuredOutput, )) if err != nil { return nil, err } if resp == nil { return nil, errors.New("repair llm returned nil response") } return resp, nil }