Ctrl K
ComunidadGuías…

internal/config/runtime_configuration.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package config

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"os"
	"strings"

	"github.com/yeomyeonggeori/blueclaw/internal/capability"
)

type RuntimeConfiguration struct {
	BaseURL          string                      `json:"baseURL"`
	ServiceTokenPath string                      `json:"serviceTokenPath,omitempty"`
	Capabilities     CapabilityConfiguration     `json:"capabilities"`
	AgentProfiles    []AgentProfileConfiguration `json:"agentProfiles"`
	LanguageModel    LanguageModelConfiguration  `json:"languageModel"`
	Database         DatabaseConfiguration       `json:"database"`
	Memory           MemoryConfiguration         `json:"memory"`
	Agent            AgentConfiguration          `json:"agent"`
	Connectors       ConnectorConfiguration      `json:"connectors"`
	Logging          LoggingConfiguration        `json:"logging"`
	Terminal         TerminalConfiguration       `json:"terminal"`
	Scheduler        SchedulerConfiguration      `json:"scheduler"`
}

type CapabilityConfiguration struct {
	Endpoint              string                     `json:"endpoint"`
	UnixSocketPath        string                     `json:"unixSocketPath"`
	TimeoutSecond         int                        `json:"timeoutSecond"`
	ProtocolVersion       string                     `json:"protocolVersion"`
	AggregateProtocolHash string                     `json:"aggregateProtocolHash"`
	ToolDescriptors       []CapabilityToolDescriptor `json:"toolDescriptors,omitempty"`
}

// IsConfigured reports whether a capability service is reachable. Without one
// Blueclaw runs standalone and the capability protocol identity is meaningless.
func (configuration CapabilityConfiguration) IsConfigured() bool {
	return strings.TrimSpace(configuration.Endpoint) != "" || strings.TrimSpace(configuration.UnixSocketPath) != ""
}

type CapabilityToolDescriptor = capability.ToolDescriptor
type CapabilityToolResultContract = capability.ToolResultContract
type CapabilityResourceEffectContract = capability.ResourceEffectContract
type CapabilityCompletionEvidence = capability.CompletionEvidence
type CapabilityAvailability = capability.Availability
type CapabilityIdempotency = capability.Idempotency

type AgentProfileConfiguration struct {
	Name             string   `json:"name"`
	AllowedToolNames []string `json:"allowedToolNames"`
}

type EvidenceCondition = capability.EvidenceCondition

type AgentConfiguration struct {
	Intake                   AgentIntakeConfiguration `json:"intake"`
	FailureRecovery          AgentFailureRecovery     `json:"failureRecovery"`
	GenerationOptions        AgentGenerationOptions   `json:"generationOptions,omitempty"`
	AllowAdminTaskDiagnostic bool                     `json:"allowAdminTaskDiagnostic"`
	Harness                  HarnessConfiguration     `json:"harness,omitempty"`
}

type HarnessConfiguration struct {
	Name             string   `json:"name,omitempty"`
	AgentCommandPath string   `json:"agentCommandPath,omitempty"`
	AgentArguments   []string `json:"agentArguments,omitempty"`
	ToolCatalogURL   string   `json:"toolCatalogURL,omitempty"`
}

type AgentIntakeConfiguration struct {
	Enabled       bool   `json:"enabled"`
	ExecutionMode string `json:"executionMode"`
}

type AgentFailureRecovery struct {
	FailureDebtFinalizationGate bool                `json:"failureDebtFinalizationGate"`
	AttemptFingerprint          string              `json:"attemptFingerprint"`
	RecoveryBudget              AgentRecoveryBudget `json:"recoveryBudget"`
}

type AgentRecoveryBudget struct {
	CorrectedRetry int `json:"correctedRetry"`
	AlternateRoute int `json:"alternateRoute"`
	AdjacentTool   int `json:"adjacentTool"`
	NoToolFallback int `json:"noToolFallback"`
}

type AgentGenerationOptions struct {
	Seed        *int64   `json:"seed,omitempty"`
	Temperature *float64 `json:"temperature,omitempty"`
}

type LanguageModelConfiguration struct {
	Tiers               map[string][]ModelEndpointConfiguration `json:"tiers,omitempty"`
	Embedding           ModelEndpointConfiguration              `json:"embedding,omitempty"`
	Decision            ModelEndpointConfiguration              `json:"decision,omitempty"`
	VisualReview        ModelEndpointConfiguration              `json:"visualReview,omitempty"`
	MaximumModelTier    string                                  `json:"maximumModelTier,omitempty"`
	MinimumModelTier    string                                  `json:"minimumModelTier,omitempty"`
	ContextWindowTokens int                                     `json:"contextWindowTokens,omitempty"`
	Capability          LanguageModelCapabilityConfiguration    `json:"capability,omitempty"`
}

// ModelEndpointConfiguration is one rung: where to ask, what the model is
// called there, and the file holding that endpoint's key. A tier is an ordered
// list of these, tried in order, and nothing in this repository decides what
// goes in one.
type ModelEndpointConfiguration struct {
	Endpoint             string   `json:"endpoint"`
	Model                string   `json:"model"`
	APIKeyPath           string   `json:"apiKeyPath,omitempty"`
	APIKeyEnvironment    string   `json:"apiKeyEnvironment,omitempty"`
	ProviderOrder        []string `json:"providerOrder,omitempty"`
	ProviderSort         string   `json:"providerSort,omitempty"`
	ReasoningEffort      string   `json:"reasoningEffort,omitempty"`
	RequesterEmailHeader string   `json:"requesterEmailHeader,omitempty"`
}

type LanguageModelCapabilityConfiguration struct {
	Model         string `json:"model"`
	MaxModel      string `json:"maxModel"`
	XHighModel    string `json:"xhighModel"`
	HighModel     string `json:"highModel"`
	MediumModel   string `json:"mediumModel"`
	LowModel      string `json:"lowModel"`
	XLowModel     string `json:"xlowModel"`
	DecisionModel string `json:"decisionModel"`
	ExecutionMode string `json:"executionMode"`
}

type DatabaseConfiguration struct {
	Driver                 string `json:"driver"`
	ConnectionString       string `json:"connectionString"`
	MigrationDirectoryPath string `json:"migrationDirectoryPath"`
	MaxOpenConnections     int    `json:"maxOpenConnections"`
}

type MemoryConfiguration struct {
	AdminAssertionKeyPath  string `json:"adminAssertionKeyPath"`
	EmbeddingModel         string `json:"embeddingModel"`
	EmbeddingDimensions    int    `json:"embeddingDimensions"`
	EmbeddingExecutionMode string `json:"embeddingExecutionMode"`
	ExtractionDisabled     bool   `json:"extractionDisabled"`
}

type ConnectorConfiguration struct {
	Chatd ChatdConnectorConfiguration `json:"chatd"`
}

type ChatdConnectorConfiguration struct {
	Endpoint         string   `json:"endpoint,omitempty"`
	TimeoutSecond    int      `json:"timeoutSecond,omitempty"`
	EnabledPlatforms []string `json:"enabledPlatforms,omitempty"`
}

type LoggingConfiguration struct {
	DirectoryPath string `json:"directoryPath"`
	RetentionDays int    `json:"retentionDays"`
}

type TerminalConfiguration struct {
	Mode                  string `json:"mode"`
	SandboxProvider       string `json:"sandboxProvider"`
	WorkspaceRootPath     string `json:"workspaceRootPath"`
	POSIXHelperPath       string `json:"posixHelperPath"`
	TimeoutSecond         int    `json:"timeoutSecond"`
	OutputMaxBytes        int    `json:"outputMaxBytes"`
	SessionMaxCount       int    `json:"sessionMaxCount"`
	AllowNetwork          bool   `json:"allowNetwork"`
	AllowInteractiveShell bool   `json:"allowInteractiveShell"`
}

type SchedulerConfiguration struct {
	RetentionCheckIntervalMinute int `json:"retentionCheckIntervalMinute"`
	SchedulePollIntervalSecond   int `json:"taskSchedulePollIntervalSecond"`
	TaskRetentionDays            int `json:"taskRetentionDays"`
	TasklessLLMCallRetentionDays int `json:"tasklessLLMCallRetentionDays"`
}

func LoadRuntimeConfiguration(path string) (RuntimeConfiguration, error) {
	document, errorValue := os.ReadFile(path)
	if errorValue != nil {
		return RuntimeConfiguration{}, errorValue
	}
	document, errorValue = expandEnvironmentReferences(document)
	if errorValue != nil {
		return RuntimeConfiguration{}, errorValue
	}

	var configuration RuntimeConfiguration
	errorValue = json.Unmarshal(document, &configuration)
	if errorValue != nil {
		return RuntimeConfiguration{}, errorValue
	}
	if errorValue := validateCapabilityProtocolIdentity(&configuration.Capabilities); errorValue != nil {
		return RuntimeConfiguration{}, errorValue
	}

	return configuration, nil
}

func capabilityRegistryIsUnstamped(configuration *CapabilityConfiguration) bool {
	return len(configuration.ToolDescriptors) == 0 &&
		strings.TrimSpace(configuration.ProtocolVersion) == "" &&
		strings.TrimSpace(configuration.AggregateProtocolHash) == ""
}

func validateCapabilityProtocolIdentity(configuration *CapabilityConfiguration) error {
	if !configuration.IsConfigured() {
		return nil
	}
	if capabilityRegistryIsUnstamped(configuration) {
		return nil
	}
	if configuration.ProtocolVersion == "" || configuration.ProtocolVersion != strings.TrimSpace(configuration.ProtocolVersion) {
		return fmt.Errorf("capabilities.protocolVersion must be a non-empty trimmed string")
	}
	if configuration.AggregateProtocolHash != strings.TrimSpace(configuration.AggregateProtocolHash) {
		return fmt.Errorf("capabilities.aggregateProtocolHash must be a 64-character lowercase hexadecimal hash")
	}
	if len(configuration.AggregateProtocolHash) != 64 {
		return fmt.Errorf("capabilities.aggregateProtocolHash must be a 64-character lowercase hexadecimal hash")
	}
	if _, errorValue := hex.DecodeString(configuration.AggregateProtocolHash); errorValue != nil || strings.ToLower(configuration.AggregateProtocolHash) != configuration.AggregateProtocolHash {
		return fmt.Errorf("capabilities.aggregateProtocolHash must be a 64-character lowercase hexadecimal hash")
	}
	return nil
}