420 lines
11 KiB
Go
420 lines
11 KiB
Go
package promptkit
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/domain"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/jsonvalue"
|
|
)
|
|
|
|
func toDomainRunRequest(req RunRequest) (domain.RunRequest, error) {
|
|
execution, err := toDomainExecutionTargetOverride(req.Execution)
|
|
if err != nil {
|
|
return domain.RunRequest{}, err
|
|
}
|
|
return domain.RunRequest{
|
|
PromptID: req.PromptID,
|
|
PromptVersion: req.PromptVersion,
|
|
ProfileID: req.ProfileID,
|
|
SessionID: req.SessionID,
|
|
APIKey: req.APIKey,
|
|
Inputs: toDomainArtifactRefMap(req.Inputs),
|
|
Vars: copyStringMap(req.Vars),
|
|
Execution: execution,
|
|
Validation: toDomainOutputContractPtr(req.Validation),
|
|
}, nil
|
|
}
|
|
|
|
func fromDomainPreparedRun(prepared *domain.PreparedRun) *PreparedRun {
|
|
if prepared == nil {
|
|
return nil
|
|
}
|
|
return &PreparedRun{
|
|
PromptID: prepared.PromptID,
|
|
PromptVersion: prepared.PromptVersion,
|
|
PromptHash: prepared.PromptHash,
|
|
SelectedProfileID: prepared.SelectedProfileID,
|
|
SelectedBackendID: prepared.SelectedBackendID,
|
|
EffectiveModelParams: fromDomainExecutionTarget(prepared.EffectiveModelParams),
|
|
OutputContract: fromDomainOutputContract(prepared.OutputContract),
|
|
StructuredOutput: fromDomainStructuredOutputSpec(prepared.StructuredOutput),
|
|
InputHashes: copyStringMap(prepared.InputHashes),
|
|
SessionID: prepared.SessionID,
|
|
RenderedPromptHash: prepared.RenderedPromptHash,
|
|
Messages: fromDomainRenderedMessages(prepared.Messages),
|
|
StartTime: prepared.StartTime,
|
|
EndTime: prepared.EndTime,
|
|
DurationMS: prepared.DurationMS,
|
|
}
|
|
}
|
|
|
|
func fromDomainRunResult(result *domain.RunResult) *RunResult {
|
|
if result == nil {
|
|
return nil
|
|
}
|
|
return &RunResult{
|
|
RunID: result.RunID,
|
|
Artifact: fromDomainArtifact(result.Artifact),
|
|
RawOutput: result.RawOutput,
|
|
Validation: fromDomainValidationResult(result.Validation),
|
|
PromptID: result.PromptID,
|
|
PromptVersion: result.PromptVersion,
|
|
PromptHash: result.PromptHash,
|
|
SessionID: result.SessionID,
|
|
RenderedPromptHash: result.RenderedPromptHash,
|
|
SelectedProfileID: result.SelectedProfileID,
|
|
SelectedBackendID: result.SelectedBackendID,
|
|
ModelName: result.ModelName,
|
|
Endpoint: result.Endpoint,
|
|
EffectiveModelParams: fromDomainExecutionTarget(result.EffectiveModelParams),
|
|
InputHashes: copyStringMap(result.InputHashes),
|
|
Usage: fromDomainTokenUsage(result.Usage),
|
|
StartTime: result.StartTime,
|
|
EndTime: result.EndTime,
|
|
Duration: result.Duration,
|
|
}
|
|
}
|
|
|
|
func fromDomainGenerateRequest(req domain.GenerateRequest) GenerateRequest {
|
|
return GenerateRequest{
|
|
Prompt: fromDomainRenderedPrompt(req.Prompt),
|
|
Target: fromDomainExecutionTarget(req.Target),
|
|
TargetPresence: fromDomainExecutionTargetPresence(req.TargetPresence),
|
|
StructuredOutput: fromDomainStructuredOutputSpec(req.StructuredOutput),
|
|
APIKey: req.Target.APIKey,
|
|
}
|
|
}
|
|
|
|
func toDomainGenerateResponse(resp *GenerateResponse) *domain.GenerateResponse {
|
|
if resp == nil {
|
|
return nil
|
|
}
|
|
return &domain.GenerateResponse{
|
|
Content: resp.Content,
|
|
Usage: toDomainTokenUsage(resp.Usage),
|
|
}
|
|
}
|
|
|
|
func fromDomainRenderedPrompt(prompt domain.RenderedPrompt) RenderedPrompt {
|
|
return RenderedPrompt{
|
|
SessionID: prompt.SessionID,
|
|
Messages: fromDomainRenderedMessages(prompt.Messages),
|
|
}
|
|
}
|
|
|
|
func toDomainArtifactRefMap(src map[string]ArtifactRef) map[string]domain.ArtifactRef {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
out := make(map[string]domain.ArtifactRef, len(src))
|
|
for k, v := range src {
|
|
out[k] = toDomainArtifactRef(v)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func toDomainArtifactRef(ref ArtifactRef) domain.ArtifactRef {
|
|
return domain.ArtifactRef{
|
|
Type: domain.ArtifactRefType(ref.Type),
|
|
URI: ref.URI,
|
|
Body: ref.Body,
|
|
}
|
|
}
|
|
|
|
func fromDomainArtifact(artifact domain.Artifact) Artifact {
|
|
return Artifact{
|
|
Name: artifact.Name,
|
|
ContentType: artifact.ContentType,
|
|
Body: copyBytes(artifact.Body),
|
|
URI: artifact.URI,
|
|
Size: artifact.Size,
|
|
Hash: artifact.Hash,
|
|
}
|
|
}
|
|
|
|
func toDomainExecutionTargetOverride(override *ExecutionTargetOverride) (*domain.ExecutionTargetOverride, error) {
|
|
if override == nil {
|
|
return nil, nil
|
|
}
|
|
extraParams, err := jsonvalue.CopyMap(override.ExtraParams)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &domain.ExecutionTargetOverride{
|
|
Endpoint: override.Endpoint,
|
|
Model: override.Model,
|
|
Temperature: copyFloat64Ptr(override.Temperature),
|
|
MaxTokens: copyIntPtr(override.MaxTokens),
|
|
TopP: copyFloat64Ptr(override.TopP),
|
|
TimeoutSeconds: copyIntPtr(override.TimeoutSeconds),
|
|
ServiceTier: override.ServiceTier,
|
|
ReasoningEffort: copyStringPtr(override.ReasoningEffort),
|
|
APIKeyEnv: override.APIKeyEnv,
|
|
ExtraParams: extraParams,
|
|
}, nil
|
|
}
|
|
|
|
func fromDomainExecutionTarget(target domain.ExecutionTarget) ExecutionTarget {
|
|
return ExecutionTarget{
|
|
BackendID: target.BackendID,
|
|
Endpoint: target.Endpoint,
|
|
Model: target.Model,
|
|
Temperature: target.Temperature,
|
|
MaxTokens: target.MaxTokens,
|
|
TopP: target.TopP,
|
|
TimeoutSeconds: target.TimeoutSeconds,
|
|
ServiceTier: target.ServiceTier,
|
|
ReasoningEffort: target.ReasoningEffort,
|
|
APIKeyEnv: target.APIKeyEnv,
|
|
ExtraParams: copyAnyMap(target.ExtraParams),
|
|
}
|
|
}
|
|
|
|
func fromDomainExecutionTargetPresence(presence domain.ExecutionTargetPresence) ExecutionTargetPresence {
|
|
return ExecutionTargetPresence{
|
|
Temperature: presence.Temperature,
|
|
MaxTokens: presence.MaxTokens,
|
|
TopP: presence.TopP,
|
|
TimeoutSeconds: presence.TimeoutSeconds,
|
|
}
|
|
}
|
|
|
|
func toDomainOutputContractPtr(contract *OutputContract) *domain.OutputContract {
|
|
if contract == nil {
|
|
return nil
|
|
}
|
|
out := toDomainOutputContract(*contract)
|
|
return &out
|
|
}
|
|
|
|
func toDomainOutputContract(contract OutputContract) domain.OutputContract {
|
|
return domain.OutputContract{
|
|
Format: domain.OutputFormat(contract.Format),
|
|
ValidationMode: domain.ValidationMode(contract.ValidationMode),
|
|
SchemaPath: contract.SchemaPath,
|
|
RepairAttempts: contract.RepairAttempts,
|
|
}
|
|
}
|
|
|
|
func fromDomainOutputContract(contract domain.OutputContract) OutputContract {
|
|
return OutputContract{
|
|
Format: OutputFormat(contract.Format),
|
|
ValidationMode: ValidationMode(contract.ValidationMode),
|
|
SchemaPath: contract.SchemaPath,
|
|
RepairAttempts: contract.RepairAttempts,
|
|
}
|
|
}
|
|
|
|
func fromDomainValidationResult(result domain.ValidationResult) ValidationResult {
|
|
return ValidationResult{
|
|
Status: ValidationStatus(result.Status),
|
|
Mode: ValidationMode(result.Mode),
|
|
Errors: copyStringSlice(result.Errors),
|
|
SchemaPath: result.SchemaPath,
|
|
RepairAttempts: result.RepairAttempts,
|
|
IsValid: result.IsValid,
|
|
}
|
|
}
|
|
|
|
func fromDomainTokenUsage(usage domain.TokenUsage) TokenUsage {
|
|
return TokenUsage{
|
|
PromptTokens: usage.PromptTokens,
|
|
CompletionTokens: usage.CompletionTokens,
|
|
TotalTokens: usage.TotalTokens,
|
|
CachedTokens: usage.CachedTokens,
|
|
CacheWriteTokens: usage.CacheWriteTokens,
|
|
}
|
|
}
|
|
|
|
func toDomainTokenUsage(usage TokenUsage) domain.TokenUsage {
|
|
return domain.TokenUsage{
|
|
PromptTokens: usage.PromptTokens,
|
|
CompletionTokens: usage.CompletionTokens,
|
|
TotalTokens: usage.TotalTokens,
|
|
CachedTokens: usage.CachedTokens,
|
|
CacheWriteTokens: usage.CacheWriteTokens,
|
|
}
|
|
}
|
|
|
|
func fromDomainRenderedMessages(messages []domain.RenderedMessage) []RenderedMessage {
|
|
if messages == nil {
|
|
return nil
|
|
}
|
|
out := make([]RenderedMessage, len(messages))
|
|
for i, msg := range messages {
|
|
out[i] = RenderedMessage{
|
|
Role: msg.Role,
|
|
Content: msg.Content,
|
|
CacheControl: fromDomainCacheControl(msg.CacheControl),
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func fromDomainCacheControl(cacheControl *domain.CacheControl) *CacheControl {
|
|
if cacheControl == nil {
|
|
return nil
|
|
}
|
|
return &CacheControl{
|
|
Type: CacheControlType(cacheControl.Type),
|
|
TTL: cacheControl.TTL,
|
|
}
|
|
}
|
|
|
|
func fromDomainStructuredOutputSpec(spec *domain.StructuredOutputSpec) *StructuredOutputSpec {
|
|
if spec == nil {
|
|
return nil
|
|
}
|
|
out := &StructuredOutputSpec{
|
|
Type: StructuredOutputType(spec.Type),
|
|
}
|
|
if spec.JSONSchema != nil {
|
|
out.JSONSchema = &StructuredOutputJSONSpec{
|
|
Name: spec.JSONSchema.Name,
|
|
Strict: spec.JSONSchema.Strict,
|
|
Schema: copyAny(spec.JSONSchema.Schema),
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func copyStringMap(src map[string]string) map[string]string {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
out := make(map[string]string, len(src))
|
|
for k, v := range src {
|
|
out[k] = v
|
|
}
|
|
return out
|
|
}
|
|
|
|
func copyAnyMap(src map[string]any) map[string]any {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
out := make(map[string]any, len(src))
|
|
for k, v := range src {
|
|
out[k] = copyAny(v)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func copyAny(value any) any {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
switch v := value.(type) {
|
|
case map[string]any:
|
|
return copyAnyMap(v)
|
|
case []any:
|
|
out := make([]any, len(v))
|
|
for i, item := range v {
|
|
out[i] = copyAny(item)
|
|
}
|
|
return out
|
|
case []string:
|
|
return copyStringSlice(v)
|
|
case []byte:
|
|
return copyBytes(v)
|
|
default:
|
|
return copyReflectValue(reflect.ValueOf(value)).Interface()
|
|
}
|
|
}
|
|
|
|
func copyReflectValue(value reflect.Value) reflect.Value {
|
|
if !value.IsValid() {
|
|
return value
|
|
}
|
|
|
|
switch value.Kind() {
|
|
case reflect.Interface:
|
|
if value.IsNil() {
|
|
return reflect.Zero(value.Type())
|
|
}
|
|
copied := copyReflectValue(value.Elem())
|
|
if copied.IsValid() && copied.Type().AssignableTo(value.Type()) {
|
|
return copied
|
|
}
|
|
out := reflect.New(value.Type()).Elem()
|
|
out.Set(copied)
|
|
return out
|
|
case reflect.Pointer:
|
|
if value.IsNil() {
|
|
return reflect.Zero(value.Type())
|
|
}
|
|
out := reflect.New(value.Type().Elem())
|
|
out.Elem().Set(copyReflectValue(value.Elem()))
|
|
return out
|
|
case reflect.Map:
|
|
if value.IsNil() {
|
|
return reflect.Zero(value.Type())
|
|
}
|
|
out := reflect.MakeMapWithSize(value.Type(), value.Len())
|
|
iter := value.MapRange()
|
|
for iter.Next() {
|
|
out.SetMapIndex(copyReflectValue(iter.Key()), copyReflectValue(iter.Value()))
|
|
}
|
|
return out
|
|
case reflect.Slice:
|
|
if value.IsNil() {
|
|
return reflect.Zero(value.Type())
|
|
}
|
|
out := reflect.MakeSlice(value.Type(), value.Len(), value.Cap())
|
|
for i := 0; i < value.Len(); i++ {
|
|
out.Index(i).Set(copyReflectValue(value.Index(i)))
|
|
}
|
|
return out
|
|
case reflect.Array:
|
|
out := reflect.New(value.Type()).Elem()
|
|
for i := 0; i < value.Len(); i++ {
|
|
out.Index(i).Set(copyReflectValue(value.Index(i)))
|
|
}
|
|
return out
|
|
default:
|
|
return value
|
|
}
|
|
}
|
|
|
|
func copyStringSlice(src []string) []string {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
out := make([]string, len(src))
|
|
copy(out, src)
|
|
return out
|
|
}
|
|
|
|
func copyBytes(src []byte) []byte {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
out := make([]byte, len(src))
|
|
copy(out, src)
|
|
return out
|
|
}
|
|
|
|
func copyFloat64Ptr(src *float64) *float64 {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
v := *src
|
|
return &v
|
|
}
|
|
|
|
func copyStringPtr(src *string) *string {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
v := *src
|
|
return &v
|
|
}
|
|
|
|
func copyIntPtr(src *int) *int {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
v := *src
|
|
return &v
|
|
}
|