96 lines
3.1 KiB
Go
96 lines
3.1 KiB
Go
package openai
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
)
|
|
|
|
func (s *Server) advanceHotPathReview(
|
|
ctx context.Context,
|
|
requestID string,
|
|
phase hotPathLightPhase,
|
|
output normalizedStageOutput,
|
|
visible normalizedStageOutput,
|
|
) (normalizedStageOutput, bool, error) {
|
|
kind, cleanup, err := classifyHotPathReviewOutput(requestID, phase, output)
|
|
if err != nil {
|
|
return normalizedStageOutput{}, false, err
|
|
}
|
|
if cleanup {
|
|
intent := hotPathTerminalIntent{Output: output.StageResponseOverlay(visible)}
|
|
mapped, err := s.lightFlows.beginCleanup(ctx, requestID, s.edgeIDValue(), intent, s.requestCoordinator)
|
|
if err != nil {
|
|
return normalizedStageOutput{}, false, err
|
|
}
|
|
return mapped, true, nil
|
|
}
|
|
mapped, err := s.lightFlows.issueTools(requestID, s.edgeIDValue(), output, visible, kind, s.requestCoordinator)
|
|
if err != nil {
|
|
return normalizedStageOutput{}, false, err
|
|
}
|
|
return mapped, true, nil
|
|
}
|
|
|
|
func classifyHotPathReviewOutput(requestID string, phase hotPathLightPhase, output normalizedStageOutput) (hotPathPendingKind, bool, error) {
|
|
paths := newReservedPaths(requestID)
|
|
switch phase {
|
|
case hotPathPhaseReviewActive:
|
|
if len(output.ToolCalls) == 0 {
|
|
return "", false, fmt.Errorf("review stage completed before writing the issued review artifact")
|
|
}
|
|
writeCount := 0
|
|
reservedCount := 0
|
|
for _, call := range output.ToolCalls {
|
|
observed := reservedPathsFromToolCall(call)
|
|
if len(observed) == 0 {
|
|
continue
|
|
}
|
|
reservedCount++
|
|
if len(observed) == 1 && cleanRelativePath(observed[0]) == cleanRelativePath(paths.ReviewPath) {
|
|
writeCount++
|
|
}
|
|
}
|
|
if writeCount == 0 && reservedCount == 0 {
|
|
return hotPathPendingReviewInspection, false, nil
|
|
}
|
|
if writeCount == 1 && reservedCount == 1 && len(output.ToolCalls) == 1 {
|
|
return hotPathPendingReviewWrite, false, nil
|
|
}
|
|
return "", false, fmt.Errorf("review write must be one exact review-path tool call")
|
|
|
|
case hotPathPhaseReviewAwaitRead:
|
|
if len(output.ToolCalls) != 1 {
|
|
return "", false, fmt.Errorf("review write result must be followed by one exact review read")
|
|
}
|
|
observed := reservedPathsFromToolCall(output.ToolCalls[0])
|
|
if len(observed) != 1 || cleanRelativePath(observed[0]) != cleanRelativePath(paths.ReviewPath) {
|
|
return "", false, fmt.Errorf("review write result must be followed by the issued review read")
|
|
}
|
|
return hotPathPendingReviewRead, false, nil
|
|
|
|
case hotPathPhaseReviewResolution:
|
|
if len(output.ToolCalls) == 0 {
|
|
return "", true, nil
|
|
}
|
|
for _, call := range output.ToolCalls {
|
|
if len(reservedPathsFromToolCall(call)) > 0 {
|
|
return "", false, fmt.Errorf("review resolution cannot start another reserved review cycle")
|
|
}
|
|
}
|
|
return hotPathPendingReviewRepair, false, nil
|
|
|
|
case hotPathPhaseReviewRepair:
|
|
if len(output.ToolCalls) == 0 {
|
|
return "", true, nil
|
|
}
|
|
for _, call := range output.ToolCalls {
|
|
if len(reservedPathsFromToolCall(call)) > 0 {
|
|
return "", false, fmt.Errorf("repair cannot start a second review cycle")
|
|
}
|
|
}
|
|
return hotPathPendingReviewRepair, false, nil
|
|
|
|
default:
|
|
return "", false, fmt.Errorf("phase %q is not a review phase", phase)
|
|
}
|
|
}
|