package promptkit import ( "context" "time" ) // ArtifactRefType identifies how an [ArtifactRef] supplies content. type ArtifactRefType string const ( // ArtifactRefInline selects ArtifactRef.Body as the content. ArtifactRefInline ArtifactRefType = "inline" // ArtifactRefFile selects the filesystem path in ArtifactRef.URI. ArtifactRefFile ArtifactRefType = "file" ) // OutputFormat identifies the media format of generated output. // OutputFormat has a stable JSON string representation. type OutputFormat string const ( // FormatText identifies plain-text output. FormatText OutputFormat = "text" // FormatMarkdown identifies Markdown output. FormatMarkdown OutputFormat = "markdown" // FormatJSON identifies JSON output. FormatJSON OutputFormat = "json" ) // ValidationMode identifies how generated output is checked. // ValidationMode has a stable JSON string representation. type ValidationMode string const ( // ValidationNone skips content validation. ValidationNone ValidationMode = "none" // ValidationBasic requires non-empty output. ValidationBasic ValidationMode = "basic" // ValidationJSON requires syntactically valid JSON. ValidationJSON ValidationMode = "json" // ValidationJSONSchema requires JSON that satisfies OutputContract.SchemaPath. ValidationJSONSchema ValidationMode = "json_schema" ) // ValidationStatus identifies the completed state of an output check. // ValidationStatus has a stable JSON string representation. type ValidationStatus string const ( // ValidationPassed means the generated output satisfied its contract. ValidationPassed ValidationStatus = "passed" // ValidationFailed means validation completed and rejected the generated // output. Engine.Run returns this status in a result, not as an error. ValidationFailed ValidationStatus = "failed" // ValidationSkipped means ValidationNone selected no content check. ValidationSkipped ValidationStatus = "skipped" ) // CacheControlType identifies provider cache behavior for prompt content. // CacheControlType has a stable JSON string representation. type CacheControlType string const ( // CacheControlEphemeral requests provider-defined ephemeral caching. CacheControlEphemeral CacheControlType = "ephemeral" ) // StructuredOutputType identifies provider-level structured output modes. // StructuredOutputType has a stable JSON string representation. type StructuredOutputType string const ( // StructuredOutputJSONSchema supplies JSON Schema response constraints. StructuredOutputJSONSchema StructuredOutputType = "json_schema" ) // RunRequest selects one prompt execution. It has no stable JSON // representation. // // Prepare and Run copy the request's maps, pointers, and nested // JSON-compatible values before using them. The caller may mutate the request // after either method returns. type RunRequest struct { // PromptID is the required non-empty prompt identifier. PromptID string // PromptVersion optionally selects one version of PromptID. When empty, the // prompt source must contain exactly one matching version. PromptVersion string // ProfileID selects an execution profile. When empty, the prompt's default // profile is used; if both are empty, the error matches ErrProfileRequired // and ErrInvalidRequest. ProfileID string // SessionID optionally supplies a direct per-run session identifier. A // nonblank value is trimmed and overrides the prompt definition's // session_id template. A blank value supplies no direct override. The // maximum is 256 Unicode code points after trimming. A direct value is // opaque consumer metadata, not a credential, and may be exposed in // prepared values, results, collaborator requests, provider requests, and // provider observability. Callers should use stable, non-sensitive // identifiers. An overlong direct value makes Prepare or Run return an // error matching ErrInvalidRequest. SessionID string // APIKey is a request-scoped direct credential. It takes precedence over // APIKeyEnv, is passed to the selected LLMClient, and is never included in // prepared values, results, hashes, JSON, String, or GoString output. APIKey string `json:"-"` // Inputs maps prompt input names to references. A nil or empty map is valid // only when the selected prompt and its templates require no inputs. Inputs map[string]ArtifactRef // Vars supplies Go-template data for messages and the session ID. Nil and // empty maps are equivalent. Vars map[string]string // Execution optionally overrides individual execution settings. Nil uses // the selected profile over its backend, when any, and framework defaults. Execution *ExecutionTargetOverride // Validation optionally replaces the prompt's complete output contract. It // does not merge individual fields. Nil uses the prompt contract. Validation *OutputContract } // PreparedRun contains prepared prompt execution state. It does not include // resolved API key values, model output, validation results, or internal target // presence metadata. PreparedRun has a stable JSON representation. // // All maps, slices, pointers, and schema values are caller-owned copies. JSON // timestamps use RFC 3339 and zero timing values are omitted. Hash formats are // opaque. type PreparedRun struct { // PromptID is the selected prompt identifier. PromptID string `json:"prompt_id"` // PromptVersion is the selected prompt version. PromptVersion string `json:"prompt_version,omitempty"` // PromptHash is an opaque equality value for the selected definition. PromptHash string `json:"prompt_hash,omitempty"` // SelectedProfileID is the explicit request profile or prompt default that // supplied execution settings. SelectedProfileID string `json:"selected_profile_id"` // SelectedBackendID equals EffectiveModelParams.BackendID. It is empty for // an endpoint-only profile. SelectedBackendID string `json:"selected_backend_id,omitempty"` // EffectiveModelParams contains framework defaults overlaid by the selected // backend, profile, and then request overrides. It excludes resolved API-key // values. EffectiveModelParams ExecutionTarget `json:"effective_model_params"` // OutputContract is the complete effective output contract. OutputContract OutputContract `json:"output_contract"` // StructuredOutput is non-nil for JSON Schema validation and contains the // provider-facing response constraint passed to an LLM client. StructuredOutput *StructuredOutputSpec `json:"structured_output,omitempty"` // InputHashes maps every supplied input name to its opaque artifact hash. InputHashes map[string]string `json:"input_hashes,omitempty"` // SessionID is the effective direct or rendered session identifier, if any. SessionID string `json:"session_id,omitempty"` // RenderedPromptHash is an opaque equality value for SessionID and Messages. RenderedPromptHash string `json:"rendered_prompt_hash"` // Messages are the rendered messages that Run passes to the LLM client. Messages []RenderedMessage `json:"messages"` // StartTime is the UTC time at which preparation began. StartTime time.Time `json:"start_time,omitempty"` // EndTime is the UTC time at which preparation completed. EndTime time.Time `json:"end_time,omitempty"` // DurationMS is preparation elapsed time in integer milliseconds. JSON uses // duration_ms and omits a zero value. DurationMS int64 `json:"duration_ms,omitempty"` } // RunResult contains generated output, validation state, and run metadata. // RunResult has a stable JSON representation and round-trips its Duration // through the duration_ms JSON field. // // All maps, slices, and nested values are caller-owned copies. JSON timestamps // use RFC 3339 and zero timing values are omitted. Run IDs and hash formats are // opaque. type RunResult struct { // RunID is an opaque identifier for this invocation. RunID string `json:"run_id"` // Artifact contains the generated output and derived metadata. Artifact Artifact `json:"artifact"` // RawOutput is the exact generated content before artifact classification // and validation. RawOutput string `json:"raw_output"` // Validation records the completed content check. Validation ValidationResult `json:"validation"` // PromptID is the selected prompt identifier. PromptID string `json:"prompt_id"` // PromptVersion is the selected prompt version. PromptVersion string `json:"prompt_version,omitempty"` // PromptHash is the same opaque definition equality value exposed by // PreparedRun. PromptHash string `json:"prompt_hash,omitempty"` // SessionID is the effective direct or rendered session identifier, if any. // JSON omits an empty value. SessionID string `json:"session_id,omitempty"` // RenderedPromptHash is the same opaque rendered-prompt equality value // computed during preparation. RenderedPromptHash string `json:"rendered_prompt_hash"` // SelectedProfileID identifies the profile used for execution. SelectedProfileID string `json:"selected_profile_id"` // SelectedBackendID equals EffectiveModelParams.BackendID. It is empty for // an endpoint-only profile. SelectedBackendID string `json:"selected_backend_id,omitempty"` // ModelName is the effective model name and equals // EffectiveModelParams.Model. ModelName string `json:"model_name"` // Endpoint is the effective base endpoint and equals // EffectiveModelParams.Endpoint. Endpoint string `json:"endpoint"` // EffectiveModelParams contains the settings supplied to the LLM client, // excluding resolved API-key values. EffectiveModelParams ExecutionTarget `json:"effective_model_params"` // InputHashes are the opaque input equality values computed during // preparation. InputHashes map[string]string `json:"input_hashes,omitempty"` // Usage is the token accounting reported by the LLM client. Usage TokenUsage `json:"usage"` // StartTime is the UTC time immediately before preparation begins. StartTime time.Time `json:"start_time,omitempty"` // EndTime is the UTC time after generation and validation complete. EndTime time.Time `json:"end_time,omitempty"` // Duration covers preparation, generation, and validation. JSON represents // it as integer milliseconds in duration_ms and omits a zero value. Duration time.Duration `json:"-"` } // ArtifactRef identifies prompt input content. It has no stable JSON // representation. Prefer [File], [Inline], or [InlineWithURI] to construct one. type ArtifactRef struct { // Type must be ArtifactRefInline or ArtifactRefFile. Type ArtifactRefType // URI is the file path for ArtifactRefFile and optional provenance metadata // for ArtifactRefInline. URI string // Body is the content for ArtifactRefInline and is ignored for // ArtifactRefFile. Body string } // Artifact represents loaded or generated content and has a stable JSON // representation. Body uses encoding/json's base64 representation for []byte. type Artifact struct { // Name is artifact metadata. During input preparation the engine fills an // empty reader-supplied name with the request input-map key. Name string `json:"name"` // ContentType is the media type reported by the reader or derived for // generated output. ContentType string `json:"content_type"` // Body is the artifact content. Engine boundaries copy this slice. Body []byte `json:"body"` // URI is optional source or result provenance metadata. URI string `json:"uri"` // Size is content-size metadata in bytes. Size int64 `json:"size"` // Hash is an opaque content equality value when the producing reader // supplies one. Its format and algorithm are not API contracts. Hash string `json:"hash"` } // ArtifactReader resolves a prompt input reference into its content. // // Read may be called concurrently. It must honor ctx cancellation to make // Prepare and Run responsive to cancellation. The engine passes a copied ref // and immediately copies the returned Artifact.Body; it does not retain either // value. Readers supply artifact metadata, and the engine assigns an input-map // name only when the returned artifact name is empty. // // An injected reader owns any application-specific path containment, // authorization, content-size, and content-type policy. It must protect // sensitive references and bodies in its logging and in any copies it retains. // It may reuse or mutate the returned artifact and body after Read returns. // // Returning a non-nil error makes the engine return an error matching // ErrArtifactLoad while preserving the reader error through errors.Is. // Returning a nil artifact with a nil error also produces ErrArtifactLoad. type ArtifactReader interface { Read(context.Context, ArtifactRef) (*Artifact, error) } // ExecutionTarget represents effective model runtime settings and has a stable // JSON representation. It never exposes a resolved API-key value. type ExecutionTarget struct { // BackendID is the effective routing identity selected by the profile. It // remains unchanged when a profile or request overrides Endpoint and is // empty for endpoint-only profiles. It is supplied to injected LLMClient // implementations as part of the effective target. BackendID string `json:"backend_id,omitempty"` // Endpoint is the model-provider base URL. Endpoint string `json:"endpoint"` // Model is the provider model identifier. Model string `json:"model"` // Temperature is the effective sampling temperature from 0 through 2. Temperature float64 `json:"temperature"` // MaxTokens is the non-negative effective output-token limit. Zero leaves // the limit unspecified to compatible providers unless it was an explicit // request override. MaxTokens int `json:"max_tokens"` // TopP is the effective nucleus-sampling value from 0 through 1. TopP float64 `json:"top_p"` // TimeoutSeconds is the non-negative per-generation deadline. Zero disables // this deadline without disabling caller cancellation or the transport cap. TimeoutSeconds int `json:"timeout_seconds"` // ServiceTier is an optional provider-specific request tier. ServiceTier string `json:"service_tier"` // ReasoningEffort is the effective opaque provider-specific reasoning // setting. An empty value instructs model clients to omit reasoning. ReasoningEffort string `json:"reasoning_effort"` // APIKeyEnv is an environment-variable name, not its credential value. APIKeyEnv string `json:"api_key_env"` // ExtraParams contains copied JSON-compatible provider parameters. ExtraParams map[string]any `json:"extra_params"` } // ExecutionTargetOverride represents per-request runtime setting overrides and // has no stable JSON representation. // // Non-empty string fields replace profile and backend values. Non-nil pointer // fields replace profile values and preserve explicit zero or empty values. A // non-empty ExtraParams map replaces the complete profile or backend map // rather than merging keys. Empty string fields, nil pointers, and a nil or // empty ExtraParams map inherit the selected profile over its backend, when // any, and framework defaults. type ExecutionTargetOverride struct { // Endpoint replaces the profile or backend endpoint when non-empty without // changing the effective BackendID. Endpoint string // Model replaces the profile model when non-empty. Model string // Temperature, when non-nil, must point to a value from 0 through 2. Temperature *float64 // MaxTokens, when non-nil, must point to a non-negative value. MaxTokens *int // TopP, when non-nil, must point to a value from 0 through 1. TopP *float64 // TimeoutSeconds, when non-nil, must point to a non-negative value. A // pointed-to zero disables the per-generation deadline. TimeoutSeconds *int // ServiceTier replaces the profile value when non-blank. ServiceTier string // ReasoningEffort controls the per-run reasoning setting. Nil inherits the // profile value. A pointer to a non-blank string trims and replaces the // profile value. A pointer to an empty or whitespace-only string clears the // inherited value and disables reasoning for this run. Non-blank values // are opaque and are not validated against a fixed vocabulary. ReasoningEffort *string // APIKeyEnv replaces the profile or backend environment-variable name when // non-blank. A direct RunRequest.APIKey still takes precedence over // environment lookup. APIKeyEnv string // ExtraParams, when non-empty, replaces the complete profile or backend map. // Values must be JSON-compatible: nil, booleans, finite numbers, strings, // arrays or slices, and maps with non-empty string keys. Cycles are invalid. ExtraParams map[string]any } // Profile is an in-memory execution profile for library consumers. // // It is equivalent to a loaded profile file after validation. Raw API keys do // not belong in profiles; use APIKeyRequired to require callers to provide a // RunRequest.APIKey or explicit request ExecutionTargetOverride.APIKeyEnv, or // use profile YAML api_key_env with file and FS profile sources. Profile has no // stable JSON representation. // // WithProfiles validates and copies Profile values during NewEngine. Numeric // zero, blank strings, and an empty ExtraParams map inherit framework defaults; // use ExecutionTargetOverride pointer fields to request explicit numeric zero. type Profile struct { // ID is the required non-blank profile identifier. WithProfiles trims it. ID string // BackendID optionally selects an engine backend. WithProfiles trims it. // Backend membership is checked when a request selects the profile; an // unknown ID makes preparation fail with ErrProfileLoad. BackendID string // Endpoint is the model-provider base URL. It is required only when // BackendID is blank and otherwise overrides the backend endpoint when // non-blank. Endpoint string // Model is the required non-blank provider model identifier. Model string // Temperature is from 0 through 2. Zero inherits the framework default. Temperature float64 // MaxTokens is non-negative. Zero inherits the framework default. MaxTokens int // TopP is from 0 through 1. Zero inherits the framework default rather than // selecting an explicit zero. TopP float64 // TimeoutSeconds is non-negative. Zero inherits the framework default. TimeoutSeconds int // ServiceTier is optional; a blank value inherits the framework default. ServiceTier string // ReasoningEffort is optional; a blank value inherits the framework // default. ReasoningEffort string // APIKeyRequired clears a backend's inherited API-key environment name and // requires a non-blank RunRequest.APIKey unless the request explicitly // supplies ExecutionTargetOverride.APIKeyEnv. It does not store a credential. APIKeyRequired bool // ExtraParams contains provider-specific JSON-compatible values. An empty // map inherits backend request defaults, when any. WithProfiles validates // and deeply copies it during NewEngine. ExtraParams map[string]any } // OpenAICompatibleProfileConfig configures an OpenAI-compatible in-memory // profile. // // It contains ordinary profile fields for OpenAI-compatible chat-completions // endpoints. APIKeyRequired follows Profile.APIKeyRequired. Raw API keys do not // belong in this config. OpenAICompatibleProfileConfig has no stable JSON // representation and is not validated until its resulting Profile is supplied // through WithProfiles to NewEngine. type OpenAICompatibleProfileConfig struct { // ID becomes Profile.ID. ID string // BackendID becomes Profile.BackendID. BackendID string // Endpoint becomes Profile.Endpoint. Endpoint string // Model becomes Profile.Model. Model string // APIKeyRequired becomes Profile.APIKeyRequired. APIKeyRequired bool // Temperature becomes Profile.Temperature. Temperature float64 // MaxTokens becomes Profile.MaxTokens. MaxTokens int // TopP becomes Profile.TopP. TopP float64 // TimeoutSeconds becomes Profile.TimeoutSeconds. TimeoutSeconds int // ServiceTier becomes Profile.ServiceTier. ServiceTier string // ReasoningEffort becomes Profile.ReasoningEffort. ReasoningEffort string // ExtraParams becomes a shallow-copied Profile.ExtraParams map. NewEngine // performs validation and a deep copy when WithProfiles applies the result. ExtraParams map[string]any } // ExecutionTargetPresence tracks which numeric runtime settings were explicit // request overrides, including explicit zero values. It has a stable JSON // representation and is supplied to injected LLM clients so they can preserve // omission semantics. type ExecutionTargetPresence struct { // Temperature reports a non-nil ExecutionTargetOverride.Temperature. Temperature bool `json:"temperature"` // MaxTokens reports a non-nil ExecutionTargetOverride.MaxTokens. MaxTokens bool `json:"max_tokens"` // TopP reports a non-nil ExecutionTargetOverride.TopP. TopP bool `json:"top_p"` // TimeoutSeconds reports a non-nil ExecutionTargetOverride.TimeoutSeconds. TimeoutSeconds bool `json:"timeout_seconds"` } // OutputContract defines output and validation requirements and has a stable // JSON representation. // // A non-nil RunRequest.Validation replaces the complete prompt contract. It // does not merge fields. The public Engine validates generated output once and // does not install an output repairer. type OutputContract struct { // Format selects generated artifact metadata. An empty effective value // defaults to FormatText. Format OutputFormat `json:"format"` // ValidationMode selects the content check. Use one of the declared // ValidationMode constants. ValidationMode ValidationMode `json:"validation_mode"` // SchemaPath is required when ValidationMode is ValidationJSONSchema and is // ignored by other modes. SchemaPath string `json:"schema_path"` // RepairAttempts is a requested repair limit. A non-positive value requests // no repairs. The public Engine performs no repairs even when this value is // positive, so its runs report zero attempts used. RepairAttempts int `json:"repair_attempts"` } // ValidationResult represents a completed output check and has a stable JSON // representation. An operational inability to perform validation is returned // as ErrValidation instead of a ValidationResult. type ValidationResult struct { // Status is Passed, Failed, or Skipped. Status ValidationStatus `json:"status"` // Mode is the effective validation mode. Mode ValidationMode `json:"mode"` // Errors contains validation diagnostics when Status is ValidationFailed. Errors []string `json:"errors,omitempty"` // SchemaPath is the effective schema path for JSON Schema validation. SchemaPath string `json:"schema_path,omitempty"` // RepairAttempts is the number of repairs actually attempted. It is always // zero for the public Engine. RepairAttempts int `json:"repair_attempts"` // IsValid is true for ValidationPassed and ValidationSkipped and false for // ValidationFailed. IsValid bool `json:"is_valid"` } // TokenUsage contains model-client token accounting and has a stable JSON // representation. Promptkit preserves values reported by the client and does // not derive or reconcile them. type TokenUsage struct { // PromptTokens is the reported input-token count. PromptTokens int `json:"prompt_tokens"` // CompletionTokens is the reported generated-token count. CompletionTokens int `json:"completion_tokens"` // TotalTokens is the reported total-token count. TotalTokens int `json:"total_tokens"` // CachedTokens is the reported cached-input-token count. CachedTokens int `json:"cached_tokens"` // CacheWriteTokens is the reported cache-write-token count. CacheWriteTokens int `json:"cache_write_tokens"` } // RenderedPrompt is the fully rendered prompt passed to an LLM client and has // a stable JSON representation. type RenderedPrompt struct { // SessionID is the optional effective direct or rendered session // identifier supplied to the model client. SessionID string `json:"session_id,omitempty"` // Messages contains rendered messages in definition order. Messages []RenderedMessage `json:"messages"` } // RenderedMessage is a rendered chat message and has a stable JSON // representation. type RenderedMessage struct { // Role is the definition-supplied chat role. Role string `json:"role"` // Content is the rendered message text. Content string `json:"content"` // CacheControl is optional provider cache metadata. CacheControl *CacheControl `json:"cache_control,omitempty"` } // CacheControl describes provider cache metadata attached to prompt content // and has a stable JSON representation. type CacheControl struct { // Type identifies the cache behavior. Type CacheControlType `json:"type"` // TTL is an optional provider cache lifetime. TTL string `json:"ttl,omitempty"` } // StructuredOutputSpec describes provider-level structured output and has a // stable JSON representation. type StructuredOutputSpec struct { // Type identifies the structured-output mechanism. Type StructuredOutputType `json:"type"` // JSONSchema contains constraints when Type is StructuredOutputJSONSchema. JSONSchema *StructuredOutputJSONSpec `json:"json_schema,omitempty"` } // StructuredOutputJSONSpec contains provider-facing JSON Schema output // constraints and has a stable JSON representation. type StructuredOutputJSONSpec struct { // Name is the provider-facing schema name. Name string `json:"name"` // Strict requests strict provider enforcement of Schema. Strict bool `json:"strict"` // Schema is a caller-owned copy of the loaded JSON Schema document. Schema any `json:"schema"` } // LLMClient executes rendered prompts for [Engine.Run]. // // Generate may be called concurrently. It must honor context cancellation to // make Run responsive to cancellation. The request and all nested maps, // slices, and pointers are client-owned copies and may be mutated or retained // without affecting engine state. // // Generate receives rendered messages and may receive a direct API key. A // client must protect those values and any raw output in its logging, storage, // and retained copies. It is responsible for the cancellation behavior of any // work it starts and for synchronizing access to retained or shared data. // // A returned error makes Run return ErrLLMGenerate while preserving the client // error through errors.Is. A nil response with a nil error also produces // ErrLLMGenerate. Promptkit copies the non-nil response before returning from // Run. type LLMClient interface { Generate(context.Context, GenerateRequest) (*GenerateResponse, error) } // GenerateRequest is passed to an injected LLM client and has a stable JSON // representation. Its String and GoString methods omit rendered content and // direct credentials. type GenerateRequest struct { // Prompt contains the rendered session ID and messages. Prompt RenderedPrompt `json:"prompt"` // Target contains effective model settings without the direct API key. Target ExecutionTarget `json:"target"` // TargetPresence distinguishes inherited numeric zeros from explicit // request overrides. TargetPresence ExecutionTargetPresence `json:"target_presence"` // StructuredOutput contains provider response constraints when requested. StructuredOutput *StructuredOutputSpec `json:"structured_output,omitempty"` // APIKey is the direct request-scoped credential, if any. It is excluded // from JSON, String, and GoString output. APIKey string `json:"-"` } // GenerateResponse is returned by an injected LLM client and has a stable JSON // representation. type GenerateResponse struct { // Content is the generated output. It must be non-empty when using the // built-in client; injected clients may return empty content for Promptkit // validation to classify. Content string `json:"content"` // Usage is the client's token accounting. Usage TokenUsage `json:"usage"` } // File returns a file-backed artifact reference whose URI is path. // // The default artifact reader opens path as a caller-selected operating-system // path without restricting it to an application root or imposing a size limit. // Applications accepting untrusted paths must validate them before calling // Promptkit or use [WithArtifactReader] to enforce application policy. func File(path string) ArtifactRef { return ArtifactRef{Type: ArtifactRefFile, URI: path} } // Inline returns an inline artifact reference whose Body is body and whose URI // is empty. func Inline(body string) ArtifactRef { return ArtifactRef{Type: ArtifactRefInline, Body: body} } // InlineWithURI returns an inline artifact reference with body content and uri // provenance metadata. func InlineWithURI(uri string, body string) ArtifactRef { return ArtifactRef{Type: ArtifactRefInline, URI: uri, Body: body} }