package shared import ( "bytes" "context" "fmt" "gitea.maximumdirect.net/eric/notarius/internal/framework/contracts" ) // PrepareChunkExtraction validates common D&D extraction prerequisites and // prepares owned chunk-scoped source material for prompt inputs. func PrepareChunkExtraction(ctx context.Context, req contracts.TypedExtractionRequest) (contracts.LLMInputMaterial, error) { if ctx == nil { return contracts.LLMInputMaterial{}, fmt.Errorf("context must not be nil") } if err := ctx.Err(); err != nil { return contracts.LLMInputMaterial{}, fmt.Errorf("context error before extraction: %w", err) } if req.Source == nil { return contracts.LLMInputMaterial{}, fmt.Errorf("source must not be nil") } if req.Chunk == nil { return contracts.LLMInputMaterial{}, fmt.Errorf("chunk must not be nil") } if len(req.Chunk.Units) == 0 { return contracts.LLMInputMaterial{}, fmt.Errorf("chunk %q units must not be empty", req.Chunk.ID) } material := req.SourceInput.Clone() if len(material.Content) == 0 { material = contracts.NewLLMInputMaterial("source", req.Chunk.MediaType, req.Chunk.Content, "", "") } if !bytes.Equal(material.Content, req.Chunk.Content) { return contracts.LLMInputMaterial{}, fmt.Errorf("source input must match chunk %q content", req.Chunk.ID) } if material.Name == "" { material.Name = "source" } if material.MediaType == "" { material.MediaType = req.Chunk.MediaType } if material.SizeBytes == 0 { material.SizeBytes = int64(len(material.Content)) } return material, nil }