package main import ( "encoding/json" "fmt" "net/http" "sync" "time" "git.cin.su/m/Assistant/contracts/capability" "git.cin.su/m/Assistant/contracts/cognitive" ) func (g cognitiveGateway) taskEvaluationHandler(w http.ResponseWriter, r *http.Request) { var request capability.TaskEvaluationExecutionRequest if !decodeJSON(w, r, 256<<10, &request) { return } if err := request.Profile.Validate(); err != nil || request.CapabilityID == "" || request.CapabilityID != request.Profile.CapabilityID || request.BindingID == "" || request.BindingRevision < 1 || request.ActorID == "" || request.PrincipalID == "" || request.ScopeID == "" || request.MaxOutputBytes < 1 || len(request.Cases) != len(request.Profile.RequiredCaseIDs) { http.Error(w, "invalid task evaluation execution request", http.StatusBadRequest) return } resolver, ok := g.resolver.(candidateBindingResolver) if !ok { http.Error(w, "exact candidate resolver unavailable", http.StatusServiceUnavailable) return } selected, err := resolver.ResolveCandidate(r.Context(), request.BindingID, request.BindingRevision) if err != nil || selected.Binding.ID != request.BindingID || selected.Binding.Revision != request.BindingRevision || selected.Binding.CapabilityID != request.CapabilityID || selected.Binding.OwnerPrincipalID != request.PrincipalID { http.Error(w, "cognitive binding snapshot unavailable", http.StatusConflict) return } if selected.Binding.DataPolicy != capability.DataPolicyLocalOnly && !request.EgressAcknowledged { http.Error(w, "external egress acknowledgement required", http.StatusBadRequest) return } provider := g.provider(selected) if provider == nil { http.Error(w, "cognitive provider unavailable", http.StatusServiceUnavailable) return } caseSet := make(map[string]struct{}, len(request.Profile.RequiredCaseIDs)) for _, id := range request.Profile.RequiredCaseIDs { caseSet[id] = struct{}{} } observations := make([]capability.TaskCaseObservation, len(request.Cases)) responses := make([]capability.TaskCaseResponse, len(request.Cases)) var wg sync.WaitGroup seenCases := make(map[string]struct{}, len(request.Cases)) for i, item := range request.Cases { if item.CaseID == "" || item.Prompt == "" || item.EvidenceArtifactRef == "" { http.Error(w, "invalid task evaluation case", http.StatusBadRequest) return } if _, exists := caseSet[item.CaseID]; !exists { http.Error(w, "task evaluation case is not in profile", http.StatusBadRequest) return } if _, exists := seenCases[item.CaseID]; exists { http.Error(w, "duplicate task evaluation case", http.StatusBadRequest) return } seenCases[item.CaseID] = struct{}{} wg.Add(1) go func(index int, item capability.TaskEvaluationCase) { defer wg.Done() started := time.Now() invocation := cognitive.AdvisoryRequest{Version: cognitive.CreatorAdvisoryV1, RequestID: cognitive.RequestID(fmt.Sprintf("task-evaluation:%s:%s", request.Profile.ID, item.CaseID)), ActorID: request.ActorID, PrincipalID: request.PrincipalID, ScopeID: request.ScopeID, Message: item.Prompt, MaxOutputBytes: int(request.MaxOutputBytes), ProviderBindingID: selected.Binding.ID, ProviderBindingRevision: selected.Binding.Revision, ProviderInstanceID: selected.Provider.ID, ModelDescriptorID: selected.Model.ID, ProviderModelID: selected.Model.ProviderModelID} response, invokeErr := g.invokeAdmitted(r.Context(), string(invocation.RequestID), provider, invocation, int(request.MaxOutputBytes)) observation := capability.TaskCaseObservation{CaseID: item.CaseID, LatencyMicros: time.Since(started).Microseconds(), EvidenceArtifactRef: item.EvidenceArtifactRef} responses[index] = capability.TaskCaseResponse{CaseID: item.CaseID, ResponseText: response.AdvisoryText, LatencyMicros: observation.LatencyMicros, EvidenceArtifactRef: item.EvidenceArtifactRef} if invokeErr == nil && response.FinishReason == cognitive.FinishCompleted && response.AdvisoryText != "" { // Invocation success proves reachability only. Without an // independent verifier and answer evidence, semantic support and // quality must remain UNKNOWN rather than becoming false evidence. observation.Result = capability.EvaluationUnknown observation.QualityScoreMillis = 0 } else { observation.Result = capability.EvaluationUnknown observation.CriticalFailure = invokeErr != nil } observations[index] = observation }(i, item) } if len(seenCases) != len(caseSet) { http.Error(w, "task evaluation case set is incomplete", http.StatusBadRequest) return } wg.Wait() writeTaskEvaluationJSON(w, capability.TaskEvaluationExecutionResponse{ProfileID: request.Profile.ID, BindingID: selected.Binding.ID, BindingRevision: selected.Binding.Revision, Observations: observations, Responses: responses, ObservedAtUnixMillis: time.Now().UnixMilli()}) } func writeTaskEvaluationJSON(w http.ResponseWriter, value any) { w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(value) }