120 lines
3.1 KiB
Go
120 lines
3.1 KiB
Go
package workflows
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
)
|
|
|
|
var ErrNotImplemented = errors.New("workflow runner not implemented")
|
|
|
|
type DiagnosticInput struct {
|
|
UserID string
|
|
Track string
|
|
TargetRole string
|
|
Stack []string
|
|
}
|
|
|
|
type Runner interface {
|
|
DiagnoseJobSeeker(context.Context, DiagnosticInput) (DiagnosticResult, error)
|
|
GradeInterviewAnswer(context.Context, GradeAnswerInput) (GradedAnswer, error)
|
|
ExtractLearningMemory(context.Context, GradedAnswer) (MemoryUpdateCandidate, error)
|
|
SelectNextChallenge(context.Context, NextChallengeInput) (NextChallenge, error)
|
|
UpdateReadinessMap(context.Context, ReadinessUpdateInput) (ReadinessUpdate, error)
|
|
}
|
|
|
|
type GradeAnswerInput struct {
|
|
UserID string
|
|
QuestionID string
|
|
AnswerID string
|
|
AnswerText string
|
|
Concepts []ConceptRef
|
|
}
|
|
|
|
type NextChallengeInput struct {
|
|
UserID string
|
|
Track string
|
|
}
|
|
|
|
type ReadinessUpdateInput struct {
|
|
UserID string
|
|
Track string
|
|
}
|
|
|
|
type StubRunner struct{}
|
|
|
|
func NewStubRunner() StubRunner {
|
|
return StubRunner{}
|
|
}
|
|
|
|
func (StubRunner) DiagnoseJobSeeker(context.Context, DiagnosticInput) (DiagnosticResult, error) {
|
|
return DiagnosticResult{}, ErrNotImplemented
|
|
}
|
|
|
|
func (StubRunner) GradeInterviewAnswer(_ context.Context, input GradeAnswerInput) (GradedAnswer, error) {
|
|
wordCount := len(strings.Fields(input.AnswerText))
|
|
overall := AnswerPartial
|
|
if wordCount >= 18 {
|
|
overall = AnswerSolid
|
|
}
|
|
if wordCount < 8 {
|
|
overall = AnswerMiss
|
|
}
|
|
|
|
grade := GradedAnswer{
|
|
AnswerID: input.AnswerID,
|
|
QuestionID: input.QuestionID,
|
|
Concepts: append([]ConceptRef(nil), input.Concepts...),
|
|
Scores: AnswerScores{
|
|
Correctness: scoreFromWords(wordCount, 8),
|
|
Depth: scoreFromWords(wordCount, 14),
|
|
Communication: scoreFromWords(wordCount, 10),
|
|
ProductionJudgment: scoreFromWords(wordCount, 20),
|
|
},
|
|
Overall: overall,
|
|
Strengths: []string{"Answer was captured and evaluated through the typed workflow boundary."},
|
|
Gaps: []string{},
|
|
Evidence: []EvidenceRef{
|
|
{
|
|
Kind: EvidenceAnswer,
|
|
ID: input.AnswerID,
|
|
Quote: input.AnswerText,
|
|
Confidence: 1,
|
|
},
|
|
},
|
|
FollowUp: FollowUpRecommendation{},
|
|
}
|
|
|
|
if overall == AnswerMiss || overall == AnswerPartial {
|
|
grade.Gaps = []string{"Answer needs more concrete reasoning and tradeoff discussion."}
|
|
grade.FollowUp = FollowUpRecommendation{
|
|
Needed: true,
|
|
Question: "Can you give a concrete production example and explain the tradeoff?",
|
|
Purpose: FollowUpRepair,
|
|
}
|
|
}
|
|
return grade, nil
|
|
}
|
|
|
|
func (StubRunner) ExtractLearningMemory(context.Context, GradedAnswer) (MemoryUpdateCandidate, error) {
|
|
return MemoryUpdateCandidate{}, ErrNotImplemented
|
|
}
|
|
|
|
func (StubRunner) SelectNextChallenge(context.Context, NextChallengeInput) (NextChallenge, error) {
|
|
return NextChallenge{}, ErrNotImplemented
|
|
}
|
|
|
|
func (StubRunner) UpdateReadinessMap(context.Context, ReadinessUpdateInput) (ReadinessUpdate, error) {
|
|
return ReadinessUpdate{}, ErrNotImplemented
|
|
}
|
|
|
|
func scoreFromWords(wordCount int, target int) int {
|
|
if wordCount >= target {
|
|
return 4
|
|
}
|
|
if wordCount >= target/2 {
|
|
return 2
|
|
}
|
|
return 1
|
|
}
|