package promptkit import "go.maximumdirect.net/configkit" // PromptConfig is a presence-aware source input for one prompt. Extends names // a sibling prompt. Nil optional pointers and slices are omitted; non-nil // pointers and slices preserve explicit zero, blank, and empty values. These // inputs are mapping constructors, not serialized inspection values. Raw // ConfigKit mappings can express explicit null and other composition controls. type PromptConfig struct { ID string Extends, DefaultProfile, Description, SessionID *string Inputs []PromptInputConfig Messages []PromptMessageConfig Output *PromptOutputConfig } // PromptInputConfig supplies an input declaration. Name is always supplied; // nil optional pointers omit their fields. type PromptInputConfig struct { Name string Required *bool ContentType, Description *string } // PromptMessageConfig supplies message fields, including inline content or a // content-file reference. Final content selection is validated by NewEngine. type PromptMessageConfig struct { Role, Content, ContentFile *string CacheControl *PromptCacheControlConfig } // PromptCacheControlConfig supplies optional cache-control source fields. type PromptCacheControlConfig struct{ Type, TTL *string } // PromptOutputConfig supplies optional output contract source fields. type PromptOutputConfig struct { Format, ValidationMode, SchemaPath *string RepairAttempts *int } // PromptSource creates a labeled ConfigKit mapping in caller order. Nil // top-level input supplies an empty prompts sequence. Records may be partial: // sibling inheritance and layered sources can complete them before NewEngine // validates the final configuration. Mapping snapshots supported values when // constructed; the helper neither resolves inheritance nor reads files. // Relative content files use the ConfigKit Input filesystem context of the // contributing field. Raw mappings remain available for explicit null and // generic ConfigKit operations. func PromptSource(label string, prompts []PromptConfig) configkit.Source { definitions := make([]any, 0, len(prompts)) for _, config := range prompts { fields := map[string]any{"id": config.ID} if config.Extends != nil { fields["extends"] = map[string]any{"id": *config.Extends} } if config.DefaultProfile != nil { fields["default_profile"] = *config.DefaultProfile } if config.Description != nil { fields["description"] = *config.Description } if config.SessionID != nil { fields["session_id"] = *config.SessionID } if config.Inputs != nil { inputs := make([]any, 0, len(config.Inputs)) for _, input := range config.Inputs { item := map[string]any{"name": input.Name} if input.Required != nil { item["required"] = *input.Required } if input.ContentType != nil { item["content_type"] = *input.ContentType } if input.Description != nil { item["description"] = *input.Description } inputs = append(inputs, item) } fields["inputs"] = inputs } if config.Messages != nil { messages := make([]any, 0, len(config.Messages)) for _, message := range config.Messages { item := make(map[string]any) if message.Role != nil { item["role"] = *message.Role } if message.Content != nil { item["content"] = *message.Content } if message.ContentFile != nil { item["content_file"] = *message.ContentFile } if message.CacheControl != nil { cache := make(map[string]any) if message.CacheControl.Type != nil { cache["type"] = *message.CacheControl.Type } if message.CacheControl.TTL != nil { cache["ttl"] = *message.CacheControl.TTL } item["cache_control"] = cache } messages = append(messages, item) } fields["messages"] = messages } if config.Output != nil { output := make(map[string]any) if config.Output.Format != nil { output["format"] = *config.Output.Format } if config.Output.ValidationMode != nil { output["validation_mode"] = *config.Output.ValidationMode } if config.Output.SchemaPath != nil { output["schema_path"] = *config.Output.SchemaPath } if config.Output.RepairAttempts != nil { output["repair_attempts"] = *config.Output.RepairAttempts } fields["output"] = output } definitions = append(definitions, fields) } return configkit.Mapping(label, map[string]any{"prompts": definitions}) }