197 lines
10 KiB
Go
197 lines
10 KiB
Go
package ckprompt
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
commandkit "go.maximumdirect.net/commandkit"
|
|
promptkit "go.maximumdirect.net/promptkit"
|
|
)
|
|
|
|
// requestFlagDefinition keeps the canonical spellings, help text, and optional
|
|
// command-scoped aliases together for consumers of the standard flag sets.
|
|
type requestFlagDefinition struct {
|
|
meta commandkit.FlagMeta
|
|
aliases []string
|
|
}
|
|
|
|
var requestFlags = struct {
|
|
Endpoint requestFlagDefinition
|
|
Model requestFlagDefinition
|
|
Temperature requestFlagDefinition
|
|
MaxTokens requestFlagDefinition
|
|
TopP requestFlagDefinition
|
|
TimeoutSeconds requestFlagDefinition
|
|
ServiceTier requestFlagDefinition
|
|
ReasoningEffort requestFlagDefinition
|
|
APIKeyEnv requestFlagDefinition
|
|
TransientRetries requestFlagDefinition
|
|
ExtraParams requestFlagDefinition
|
|
Prompt requestFlagDefinition
|
|
Profile requestFlagDefinition
|
|
Backend requestFlagDefinition
|
|
SessionID requestFlagDefinition
|
|
Var requestFlagDefinition
|
|
InputText requestFlagDefinition
|
|
InputFile requestFlagDefinition
|
|
}{
|
|
Endpoint: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-endpoint", Usage: "Execution endpoint override."}, []string{"endpoint"}},
|
|
Model: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-model", Usage: "Execution model override."}, []string{"model"}},
|
|
Temperature: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-temperature", Usage: "Execution temperature override."}, []string{"temperature"}},
|
|
MaxTokens: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-max-tokens", Usage: "Execution maximum tokens override."}, []string{"max-tokens"}},
|
|
TopP: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-top-p", Usage: "Execution top-p override."}, []string{"top-p"}},
|
|
TimeoutSeconds: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-timeout-seconds", Usage: "Execution timeout override in seconds."}, []string{"timeout-seconds"}},
|
|
ServiceTier: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-service-tier", Usage: "Execution service tier."}, []string{"service-tier"}},
|
|
ReasoningEffort: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-reasoning-effort", Usage: "Execution reasoning effort override."}, []string{"reasoning-effort"}},
|
|
APIKeyEnv: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-api-key-env", Usage: "Execution API key environment variable."}, []string{"api-key-env"}},
|
|
TransientRetries: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-transient-retries", Usage: "Inference transient retry count."}, []string{"transient-retries"}},
|
|
ExtraParams: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-extra-params", Usage: "Execution provider parameters as a JSON object."}, []string{"extra-params"}},
|
|
Prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt", Usage: "PromptKit prompt ID."}, []string{"prompt"}},
|
|
Profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile", Usage: "PromptKit profile ID."}, []string{"profile"}},
|
|
Backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend", Usage: "PromptKit backend ID."}, []string{"backend"}},
|
|
SessionID: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-session-id", Usage: "PromptKit session ID."}, []string{"session-id"}},
|
|
Var: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-var", Usage: "Caller variable assignment KEY=VALUE."}, []string{"var"}},
|
|
InputText: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-text", Usage: "Literal prompt input assignment NAME=TEXT."}, []string{"input-text", "llm-input", "input"}},
|
|
InputFile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-file", Usage: "Prompt input file assignment NAME=PATH."}, []string{"input-file"}},
|
|
}
|
|
|
|
// ExecutionInput contains request-scoped execution controls supplied on the CLI.
|
|
// A nil override or retry count leaves the corresponding native default intact.
|
|
type ExecutionInput struct {
|
|
Execution *promptkit.ExecutionTargetOverride
|
|
TransientRetries *int
|
|
}
|
|
|
|
// ExecutionFlags exposes independently selectable execution-control bindings.
|
|
type ExecutionFlags[I any] struct {
|
|
Endpoint, Model, Temperature, MaxTokens, TopP, TimeoutSeconds commandkit.Flag[I]
|
|
ServiceTier, ReasoningEffort, APIKeyEnv, TransientRetries, ExtraParams commandkit.Flag[I]
|
|
}
|
|
|
|
// All returns all execution controls.
|
|
func (f ExecutionFlags[I]) All() []commandkit.Flag[I] {
|
|
return []commandkit.Flag[I]{f.Endpoint, f.Model, f.Temperature, f.MaxTokens, f.TopP, f.TimeoutSeconds, f.ServiceTier, f.ReasoningEffort, f.APIKeyEnv, f.TransientRetries, f.ExtraParams}
|
|
}
|
|
|
|
// NewExecutionFlags binds execution controls to a field of the caller's input.
|
|
func NewExecutionFlags[I any](destination func(*I) *ExecutionInput) ExecutionFlags[I] {
|
|
target := func(input *I) *promptkit.ExecutionTargetOverride {
|
|
value := destination(input)
|
|
if value.Execution == nil {
|
|
value.Execution = &promptkit.ExecutionTargetOverride{}
|
|
}
|
|
return value.Execution
|
|
}
|
|
return ExecutionFlags[I]{
|
|
Endpoint: executionFlag(requestFlags.Endpoint.meta, parseDefinitionString, func(i *I, v string) { target(i).Endpoint = v }),
|
|
Model: executionFlag(requestFlags.Model.meta, parseDefinitionString, func(i *I, v string) { target(i).Model = v }),
|
|
Temperature: executionFlag(requestFlags.Temperature.meta, parseExecutionFloat, func(i *I, v float64) { target(i).Temperature = &v }),
|
|
MaxTokens: executionFlag(requestFlags.MaxTokens.meta, strconv.Atoi, func(i *I, v int) { target(i).MaxTokens = &v }),
|
|
TopP: executionFlag(requestFlags.TopP.meta, parseExecutionFloat, func(i *I, v float64) { target(i).TopP = &v }),
|
|
TimeoutSeconds: executionFlag(requestFlags.TimeoutSeconds.meta, strconv.Atoi, func(i *I, v int) { target(i).TimeoutSeconds = &v }),
|
|
ServiceTier: executionFlag(requestFlags.ServiceTier.meta, parseDefinitionString, func(i *I, v string) { target(i).ServiceTier = v }),
|
|
ReasoningEffort: executionFlag(requestFlags.ReasoningEffort.meta, parseDefinitionString, func(i *I, v string) { target(i).ReasoningEffort = &v }),
|
|
APIKeyEnv: executionFlag(requestFlags.APIKeyEnv.meta, parseDefinitionString, func(i *I, v string) { target(i).APIKeyEnv = v }),
|
|
TransientRetries: executionFlag(requestFlags.TransientRetries.meta, strconv.Atoi, func(i *I, v int) { destination(i).TransientRetries = &v }),
|
|
ExtraParams: executionFlag(requestFlags.ExtraParams.meta, parseExtraParams, func(i *I, v map[string]any) { target(i).ExtraParams = v }),
|
|
}
|
|
}
|
|
|
|
func executionFlag[I, V any](meta commandkit.FlagMeta, parse func(string) (V, error), set func(*I, V)) commandkit.Flag[I] {
|
|
return commandkit.ValueFlag(meta, (*V)(nil), parse, func(i *I, value commandkit.Supplied[V]) {
|
|
if value.Set {
|
|
set(i, value.Value)
|
|
}
|
|
})
|
|
}
|
|
|
|
func parseExtraParams(raw string) (map[string]any, error) {
|
|
value, err := commandkit.ParseCLIJSON(raw)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
object, ok := value.(map[string]any)
|
|
if !ok {
|
|
return nil, fmt.Errorf("provider parameters must be a JSON object")
|
|
}
|
|
return object, nil
|
|
}
|
|
|
|
// ResourceInput retains whether each resource identifier was explicitly supplied.
|
|
type ResourceInput struct {
|
|
Prompt, Profile, Backend, SessionID commandkit.Supplied[string]
|
|
}
|
|
|
|
// ResourceFlags exposes independently selectable resource and session bindings.
|
|
type ResourceFlags[I any] struct {
|
|
Prompt, Profile, Backend, SessionID commandkit.Flag[I]
|
|
}
|
|
|
|
// All returns all resource bindings.
|
|
func (f ResourceFlags[I]) All() []commandkit.Flag[I] {
|
|
return []commandkit.Flag[I]{f.Prompt, f.Profile, f.Backend, f.SessionID}
|
|
}
|
|
|
|
// NewResourceFlags binds resource identifiers to a field of the caller's input.
|
|
func NewResourceFlags[I any](destination func(*I) *ResourceInput) ResourceFlags[I] {
|
|
flag := func(meta commandkit.FlagMeta, selectField func(*ResourceInput) *commandkit.Supplied[string]) commandkit.Flag[I] {
|
|
return commandkit.ValueFlag(meta, (*string)(nil), parseDefinitionString, func(i *I, v commandkit.Supplied[string]) { *selectField(destination(i)) = v })
|
|
}
|
|
return ResourceFlags[I]{
|
|
Prompt: flag(requestFlags.Prompt.meta, func(v *ResourceInput) *commandkit.Supplied[string] { return &v.Prompt }),
|
|
Profile: flag(requestFlags.Profile.meta, func(v *ResourceInput) *commandkit.Supplied[string] { return &v.Profile }),
|
|
Backend: flag(requestFlags.Backend.meta, func(v *ResourceInput) *commandkit.Supplied[string] { return &v.Backend }),
|
|
SessionID: flag(requestFlags.SessionID.meta, func(v *ResourceInput) *commandkit.Supplied[string] { return &v.SessionID }),
|
|
}
|
|
}
|
|
|
|
// PromptInputs contains caller variables and native artifact references.
|
|
type PromptInputs struct {
|
|
Vars map[string]string
|
|
Inputs map[string]promptkit.ArtifactRef
|
|
}
|
|
|
|
// PromptInputFlags exposes variable and named artifact input bindings.
|
|
type PromptInputFlags[I any] struct {
|
|
Variable, Text, File commandkit.Flag[I]
|
|
}
|
|
|
|
// All returns all variable and input bindings.
|
|
func (f PromptInputFlags[I]) All() []commandkit.Flag[I] {
|
|
return []commandkit.Flag[I]{f.Variable, f.Text, f.File}
|
|
}
|
|
|
|
// NewPromptInputFlags binds caller variables and input references to a field of
|
|
// the caller's input.
|
|
func NewPromptInputFlags[I any](destination func(*I) *PromptInputs) PromptInputFlags[I] {
|
|
variable := commandkit.RepeatFlag(requestFlags.Var.meta, []variableAssignment(nil), parseVariableAssignment, func(i *I, v commandkit.Supplied[[]variableAssignment]) {
|
|
if !v.Set {
|
|
return
|
|
}
|
|
values := make(map[string]string, len(v.Value))
|
|
for _, assignment := range v.Value {
|
|
values[assignment.key] = assignment.value
|
|
}
|
|
destination(i).Vars = values
|
|
})
|
|
inputFlag := func(meta commandkit.FlagMeta, makeRef func(string) promptkit.ArtifactRef) commandkit.Flag[I] {
|
|
return commandkit.RepeatFlag(meta, []inputAssignment(nil), parseInputAssignment, func(i *I, v commandkit.Supplied[[]inputAssignment]) {
|
|
if !v.Set {
|
|
return
|
|
}
|
|
input := destination(i)
|
|
if input.Inputs == nil {
|
|
input.Inputs = make(map[string]promptkit.ArtifactRef)
|
|
}
|
|
for _, assignment := range v.Value {
|
|
input.Inputs[assignment.name] = makeRef(assignment.path)
|
|
}
|
|
})
|
|
}
|
|
return PromptInputFlags[I]{Variable: variable, Text: inputFlag(requestFlags.InputText.meta, promptkit.Inline), File: inputFlag(requestFlags.InputFile.meta, promptkit.File)}
|
|
}
|
|
|
|
func parseExecutionFloat(value string) (float64, error) {
|
|
return strconv.ParseFloat(value, 64)
|
|
}
|