package contracts import ( "crypto/sha256" "encoding/hex" "fmt" ) // DebugStructuredCompletionRequest is the content-safe representation of a // structured completion request for ordinary diagnostics and summaries. // Detailed prompt material remains available only through the explicitly // requested LLM debug trace. type DebugStructuredCompletionRequest struct { StageName string `json:"stage_name,omitempty"` PromptID string `json:"prompt_id,omitempty"` PromptVersion string `json:"prompt_version,omitempty"` ProfileID string `json:"profile_id,omitempty"` SessionID string `json:"session_id,omitempty"` InputCount int `json:"input_count"` VariableCount int `json:"variable_count"` StructuredOutputRepairAttempts *int `json:"structured_output_repair_attempts,omitempty"` Correction *DebugSemanticCorrection `json:"correction,omitempty"` } // DebugSemanticCorrection records only safe correction metadata. It never // exposes the assistant response or user guidance text. type DebugSemanticCorrection struct { AssistantResponseBytes int `json:"assistant_response_bytes"` AssistantResponseDigest string `json:"assistant_response_digest"` UserGuidanceBytes int `json:"user_guidance_bytes"` UserGuidanceDigest string `json:"user_guidance_digest"` } // DebugSummary returns a content-safe representation suitable for ordinary // diagnostics. It does not validate or retain correction content. func (request StructuredCompletionRequest) DebugSummary() DebugStructuredCompletionRequest { summary := DebugStructuredCompletionRequest{ StageName: request.StageName, PromptID: request.PromptID, PromptVersion: request.PromptVersion, ProfileID: request.ProfileID, SessionID: request.SessionID, InputCount: len(request.Inputs), VariableCount: len(request.Vars), } if request.StructuredOutputRepairAttempts != nil { attempts := *request.StructuredOutputRepairAttempts summary.StructuredOutputRepairAttempts = &attempts } if request.Correction != nil { summary.Correction = request.Correction.DebugSummary() } return summary } // DebugSummary returns content-safe correction metadata suitable for ordinary // diagnostics. func (correction *SemanticCorrection) DebugSummary() *DebugSemanticCorrection { if correction == nil { return nil } return &DebugSemanticCorrection{ AssistantResponseBytes: len(correction.AssistantResponse), AssistantResponseDigest: debugContentDigest(correction.AssistantResponse), UserGuidanceBytes: len(correction.UserGuidance), UserGuidanceDigest: debugContentDigest([]byte(correction.UserGuidance)), } } // String prevents ordinary request formatting from exposing correction // content. Use the explicitly requested debug trace for complete messages. func (request StructuredCompletionRequest) String() string { return fmt.Sprintf("%+v", request.DebugSummary()) } // GoString gives %#v formatting the same content-safe behavior as String. func (request StructuredCompletionRequest) GoString() string { return request.String() } func debugContentDigest(content []byte) string { sum := sha256.Sum256(content) return "sha256:" + hex.EncodeToString(sum[:]) }