80 lines
5.3 KiB
Go
80 lines
5.3 KiB
Go
package application
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"git.cin.su/m/Assistant/contracts/capability"
|
|
"git.cin.su/m/Assistant/contracts/work"
|
|
)
|
|
|
|
type taskGraphStore struct {
|
|
graph work.WorkGraph
|
|
intents []work.AgentDispatchIntent
|
|
}
|
|
|
|
func (s *taskGraphStore) SaveWorkGraph(_ context.Context, graph work.WorkGraph) error {
|
|
s.graph = graph
|
|
return nil
|
|
}
|
|
func (s *taskGraphStore) LoadWorkGraph(context.Context, string, int64) (work.WorkGraph, error) {
|
|
return s.graph, nil
|
|
}
|
|
func (s *taskGraphStore) SaveDispatchIntent(_ context.Context, intent work.AgentDispatchIntent) error {
|
|
s.intents = append(s.intents, intent)
|
|
return nil
|
|
}
|
|
func (s *taskGraphStore) EnqueueDispatch(context.Context, work.AgentDispatchQueueItem) error {
|
|
return nil
|
|
}
|
|
|
|
func TestAdmitAndScheduleTaskEvaluationCarriesSpecialistContext(t *testing.T) {
|
|
store := &taskGraphStore{}
|
|
request := TaskEvaluationScheduleRequest{
|
|
Plan: work.TaskEvaluationGraphRequest{
|
|
GraphID: "graph-task", Profile: capability.TaskEvaluationProfile{ID: "profile-general", Revision: 1, CapabilityID: "capability-chat", Stage: capability.TaskEvaluationGeneral, BenchmarkVersion: "general-v1", RequiredCaseIDs: []string{"case-a", "case-b"}, QualityWeightMillis: 600, ReliabilityWeightMillis: 300, LatencyWeightMillis: 100},
|
|
Cases: []capability.TaskEvaluationCase{{CaseID: "case-a", Prompt: "one", EvidenceArtifactRef: "artifact-a"}, {CaseID: "case-b", Prompt: "two", EvidenceArtifactRef: "artifact-b"}},
|
|
BindingIDs: []capability.CapabilityBindingID{"binding-a"}, DispatchIDs: []string{"dispatch-a"}, IdempotencyPrefix: "eval", Budget: work.GraphBudget{MaxParallel: 1, MaxAttempts: 2},
|
|
},
|
|
Intents: []work.AgentDispatchIntent{{DispatchID: "dispatch-a", IdempotencyKey: "idem-a", DelegationID: "delegation-a", RunID: "run-a", ImplementationID: "impl", ImplementationRevision: 1, SourceRevision: "source", WorktreeID: "tree", VerificationPlanRef: "verify", CreatedAtUnixMillis: 1}},
|
|
}
|
|
if _, _, err := AdmitAndScheduleTaskEvaluation(context.Background(), store, request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(store.intents) != 1 || store.intents[0].TaskEvaluationProfileID != "profile-general" || store.intents[0].TaskEvaluationBindingID != "binding-a" || len(store.intents[0].TaskEvaluationCaseIDs) != 2 || store.intents[0].SpecialistPurpose != string(work.GraphNodePurposeTaskEvaluation) || store.intents[0].TaskEvaluationExecution == nil || store.intents[0].TaskEvaluationExecution.GraphRevision != 2 {
|
|
t.Fatalf("specialist context was not carried into dispatch: %+v", store.intents)
|
|
}
|
|
}
|
|
|
|
func TestExpandAndScheduleTaskEvaluationCreatesAdditionalDurableGraph(t *testing.T) {
|
|
store := &taskGraphStore{}
|
|
additional := capability.TaskEvaluationProfile{ID: "profile-additional", Revision: 1, CapabilityID: "capability-chat", Stage: capability.TaskEvaluationAdditional, ParentProfileID: "profile-general", TriggerEvidenceRef: "artifact-unresolved", BenchmarkVersion: "additional-v1", RequiredCaseIDs: []string{"case-a:reproduce", "case-a:address-failure"}, QualityWeightMillis: 600, ReliabilityWeightMillis: 300, LatencyWeightMillis: 100}
|
|
request := TaskEvaluationExpansionScheduleRequest{
|
|
Profile: additional, Cases: []capability.TaskEvaluationCase{{CaseID: "case-a:reproduce", Prompt: "проверь доступность", EvidenceArtifactRef: "artifact-unresolved"}, {CaseID: "case-a:address-failure", Prompt: "проверь доступность; обработай неизвестный результат", EvidenceArtifactRef: "artifact-unresolved"}},
|
|
ParentGraphState: work.GraphCompleted, TriggerEvidenceRef: "artifact-unresolved",
|
|
Plan: work.TaskEvaluationGraphRequest{
|
|
GraphID: "graph-additional", BindingIDs: []capability.CapabilityBindingID{"binding-a"}, DispatchIDs: []string{"dispatch-additional"}, IdempotencyPrefix: "additional", Budget: work.GraphBudget{MaxParallel: 1, MaxAttempts: 2}, ParentGraphID: "graph-general", ParentGraphRevision: 2,
|
|
},
|
|
Intents: []work.AgentDispatchIntent{{DispatchID: "dispatch-additional", IdempotencyKey: "idem-additional", DelegationID: "delegation-a", RunID: "run-a", ImplementationID: "impl", ImplementationRevision: 1, SourceRevision: "source", WorktreeID: "tree", VerificationPlanRef: "verify", CreatedAtUnixMillis: 1}},
|
|
Now: 20,
|
|
}
|
|
graph, ready, err := ScheduleAdditionalTaskEvaluation(context.Background(), store, request)
|
|
if err != nil || len(ready) != 1 || graph.State != work.GraphRunning {
|
|
t.Fatalf("graph=%+v ready=%v err=%v", graph, ready, err)
|
|
}
|
|
if len(graph.Nodes) != 1 || graph.Nodes[0].TaskProfileID != "profile-additional" || len(graph.Nodes[0].CaseIDs) != 2 || graph.TriggerEvidenceRef != "artifact-unresolved" {
|
|
t.Fatalf("additional graph did not preserve bounded expansion lineage: %+v", graph)
|
|
}
|
|
if len(store.intents) != 1 || store.intents[0].TaskEvaluationProfileID != "profile-additional" {
|
|
t.Fatalf("additional dispatch context missing: %+v", store.intents)
|
|
}
|
|
}
|
|
|
|
func TestScheduleAdditionalTaskEvaluationRejectsIncompleteLineage(t *testing.T) {
|
|
store := &taskGraphStore{}
|
|
_, _, err := ScheduleAdditionalTaskEvaluation(context.Background(), store, TaskEvaluationExpansionScheduleRequest{Profile: capability.TaskEvaluationProfile{Stage: capability.TaskEvaluationGeneral}})
|
|
if err == nil || len(store.intents) != 0 {
|
|
t.Fatalf("incomplete expansion lineage was accepted: intents=%v err=%v", store.intents, err)
|
|
}
|
|
}
|