Add DriftJudge AI role with verdict parsing
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
package ai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Verdict is the drift judge's call on a single window.
|
||||
type Verdict struct {
|
||||
OnTask bool
|
||||
Reason string
|
||||
}
|
||||
|
||||
// ErrInvalidVerdict marks a parseable-but-unusable judge response.
|
||||
var ErrInvalidVerdict = errors.New("ai: invalid verdict")
|
||||
|
||||
type rawVerdict struct {
|
||||
OnTask bool `json:"on_task"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// parseVerdict extracts and validates a Verdict from raw CLI output. It reuses
|
||||
// extractJSON and the shared empty/no-JSON sentinels. A drifting verdict with no
|
||||
// reason is unusable for the UI and is rejected as ErrInvalidVerdict.
|
||||
func parseVerdict(s string) (Verdict, error) {
|
||||
if strings.TrimSpace(s) == "" {
|
||||
return Verdict{}, ErrEmptyResponse
|
||||
}
|
||||
if strings.IndexByte(s, '{') < 0 {
|
||||
return Verdict{}, ErrNoJSON
|
||||
}
|
||||
jsonStr, err := extractJSON(s)
|
||||
if err != nil {
|
||||
return Verdict{}, fmt.Errorf("%w: %v", ErrInvalidVerdict, err)
|
||||
}
|
||||
var raw rawVerdict
|
||||
if err := json.Unmarshal([]byte(jsonStr), &raw); err != nil {
|
||||
return Verdict{}, fmt.Errorf("%w: %v", ErrInvalidVerdict, err)
|
||||
}
|
||||
v := Verdict{OnTask: raw.OnTask, Reason: strings.TrimSpace(raw.Reason)}
|
||||
if !v.OnTask && v.Reason == "" {
|
||||
return Verdict{}, ErrInvalidVerdict
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
Reference in New Issue
Block a user