package promptkit import ( "context" "gitea.maximumdirect.net/eric/promptkit/internal/domain" "gitea.maximumdirect.net/eric/promptkit/internal/usecase" ) // RequirementInspectionRequest selects a prompt and supplies caller context // for requirement discovery. It requires no artifact bindings or credentials. type RequirementInspectionRequest struct { PromptID string PromptVersion string ProfileID string Vars map[string]string SessionID string } // RequirementKind describes how a selected prompt may depend on an input or // caller variable for the supplied context. type RequirementKind string const ( // RequirementRequired identifies a declaration or definite access. RequirementRequired RequirementKind = "required" // RequirementConditional identifies a dependency whose reachability is // unresolved for the supplied context. RequirementConditional RequirementKind = "conditional" // RequirementOptional identifies a dependency known not to be required, // including a reference used only on a known skipped path. RequirementOptional RequirementKind = "optional" ) // InputRequirement describes a declared or template-referenced prompt input. type InputRequirement struct { Name string Kind RequirementKind Declared bool ContentType *string Description *string Explanation string } // VariableRequirement describes a caller-map key referenced by a prompt. type VariableRequirement struct { Name string Kind RequirementKind Supplied bool Explanation string } // RequirementIssueCode identifies a limitation that can affect discovery. type RequirementIssueCode string const ( RequirementIssueMissingVariable RequirementIssueCode = "missing_variable" RequirementIssueInputContent RequirementIssueCode = "input_content" RequirementIssueDynamicInputName RequirementIssueCode = "dynamic_input_name" RequirementIssueUnsupportedConstruct RequirementIssueCode = "unsupported_construct" ) // RequirementIssue describes one discovery limitation using safe summary // text. Descriptions are not intended as machine-readable details. type RequirementIssue struct { Code RequirementIssueCode InputName string VariableName string Description string } // RequirementInspection contains discovered dependencies for one selected // prompt context. Complete describes discovery, not renderability or readiness. type RequirementInspection struct { PromptID string PromptVersion string ProfileID string Inputs []InputRequirement Variables []VariableRequirement Complete bool Issues []RequirementIssue } // InspectRequirements discovers inputs and caller variables for one selected // prompt before its input artifacts exist. It uses exact, case-sensitive // prompt selection and requires a profile ID either in the request or the // selected prompt's default. The selected profile establishes identity only; // it need not be execution-ready. A normalized nonblank SessionID bypasses the // captured session template. Vars are copied before analysis, and returned // slices and metadata pointers belong to the caller. // // This method does not perform artifact, schema, credential, rendering, // validation, capacity, observation, provider, or execution work. Complete // describes dependency discovery, not whether every dependency is supplied or // the prompt is ready to execute. Discovery limitations return a partial // inspection and no error; selection and operational failures return no // inspection. Blank prompt IDs, invalid session IDs, and absent profile // selection match ErrInvalidRequest; an absent profile selection also matches // ErrProfileRequired. Missing prompt/profile IDs match ErrPromptNotFound or // ErrProfileNotFound. Other selection/snapshot failures match ErrPromptLoad or // ErrProfileLoad. A nil Engine matches ErrInvalidConfig. func (e *Engine) InspectRequirements( ctx context.Context, req RequirementInspectionRequest, ) (*RequirementInspection, error) { if e == nil || e.internal == nil { return nil, ErrInvalidConfig } inspection, err := e.internal.InspectRequirements(ctx, usecase.RequirementInspectionRequest{ PromptID: req.PromptID, PromptVersion: req.PromptVersion, ProfileID: req.ProfileID, Vars: copyStringMap(req.Vars), SessionID: req.SessionID, }) if err != nil { return nil, mapPublicError(err) } return fromDomainRequirementInspection(inspection), nil } func fromDomainRequirementInspection(inspection *domain.RequirementInspection) *RequirementInspection { if inspection == nil { return nil } result := &RequirementInspection{ PromptID: inspection.PromptID, PromptVersion: inspection.PromptVersion, ProfileID: inspection.ProfileID, Complete: inspection.Complete, Inputs: make([]InputRequirement, len(inspection.Inputs)), Variables: make([]VariableRequirement, len(inspection.Variables)), Issues: make([]RequirementIssue, len(inspection.Issues)), } for index, input := range inspection.Inputs { result.Inputs[index] = InputRequirement{ Name: input.Name, Kind: RequirementKind(input.Kind), Declared: input.Declared, ContentType: copyRequirementString(input.ContentType), Description: copyRequirementString(input.Description), Explanation: input.Explanation, } } for index, variable := range inspection.Variables { result.Variables[index] = VariableRequirement{ Name: variable.Name, Kind: RequirementKind(variable.Kind), Supplied: variable.Supplied, Explanation: variable.Explanation, } } for index, issue := range inspection.Issues { result.Issues[index] = RequirementIssue{ Code: RequirementIssueCode(issue.Code), InputName: issue.InputName, VariableName: issue.VariableName, Description: issue.Description, } } return result } func copyRequirementString(value *string) *string { if value == nil { return nil } copy := *value return © }