new injection strategies
This commit is contained in:
+72
-14
@@ -38,8 +38,8 @@ type TranscriptionConfig struct {
|
||||
}
|
||||
|
||||
type InjectionConfig struct {
|
||||
Mode string `toml:"mode"`
|
||||
RestoreClipboard bool `toml:"restore_clipboard"`
|
||||
Backends []string `toml:"backends"`
|
||||
YdotoolTimeout time.Duration `toml:"ydotool_timeout"`
|
||||
WtypeTimeout time.Duration `toml:"wtype_timeout"`
|
||||
ClipboardTimeout time.Duration `toml:"clipboard_timeout"`
|
||||
}
|
||||
@@ -84,8 +84,8 @@ func (c *Config) ToTranscriberConfig() transcriber.Config {
|
||||
|
||||
func (c *Config) ToInjectionConfig() injection.Config {
|
||||
return injection.Config{
|
||||
Mode: c.Injection.Mode,
|
||||
RestoreClipboard: c.Injection.RestoreClipboard,
|
||||
Backends: c.Injection.Backends,
|
||||
YdotoolTimeout: c.Injection.YdotoolTimeout,
|
||||
WtypeTimeout: c.Injection.WtypeTimeout,
|
||||
ClipboardTimeout: c.Injection.ClipboardTimeout,
|
||||
}
|
||||
@@ -181,9 +181,17 @@ func (c *Config) Validate() error {
|
||||
}
|
||||
|
||||
// Injection
|
||||
validModes := map[string]bool{"clipboard": true, "type": true, "fallback": true}
|
||||
if !validModes[c.Injection.Mode] {
|
||||
return fmt.Errorf("invalid injection.mode: %s (must be clipboard, type, or fallback)", c.Injection.Mode)
|
||||
if len(c.Injection.Backends) == 0 {
|
||||
return fmt.Errorf("invalid injection.backends: empty (must have at least one backend)")
|
||||
}
|
||||
validBackends := map[string]bool{"ydotool": true, "wtype": true, "clipboard": true}
|
||||
for _, backend := range c.Injection.Backends {
|
||||
if !validBackends[backend] {
|
||||
return fmt.Errorf("invalid injection.backends: unknown backend %q (must be ydotool, wtype, or clipboard)", backend)
|
||||
}
|
||||
}
|
||||
if c.Injection.YdotoolTimeout <= 0 {
|
||||
return fmt.Errorf("invalid injection.ydotool_timeout: %v", c.Injection.YdotoolTimeout)
|
||||
}
|
||||
if c.Injection.WtypeTimeout <= 0 {
|
||||
return fmt.Errorf("invalid injection.wtype_timeout: %v", c.Injection.WtypeTimeout)
|
||||
@@ -235,6 +243,15 @@ func GetConfigPath() (string, error) {
|
||||
return filepath.Join(hyprvoiceDir, "config.toml"), nil
|
||||
}
|
||||
|
||||
// legacyInjectionConfig for migration from old mode-based config
|
||||
type legacyInjectionConfig struct {
|
||||
Mode string `toml:"mode"`
|
||||
}
|
||||
|
||||
type legacyConfig struct {
|
||||
Injection legacyInjectionConfig `toml:"injection"`
|
||||
}
|
||||
|
||||
func Load() (*Config, error) {
|
||||
configPath, err := GetConfigPath()
|
||||
if err != nil {
|
||||
@@ -257,10 +274,45 @@ func Load() (*Config, error) {
|
||||
return nil, fmt.Errorf("failed to parse config file %s: %w", configPath, err)
|
||||
}
|
||||
|
||||
// Migrate legacy mode-based config to backends
|
||||
if len(config.Injection.Backends) == 0 {
|
||||
var legacy legacyConfig
|
||||
toml.DecodeFile(configPath, &legacy)
|
||||
config.migrateInjectionMode(legacy.Injection.Mode)
|
||||
}
|
||||
|
||||
log.Printf("Config: configuration loaded successfully")
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// migrateInjectionMode converts old mode field to new backends array
|
||||
func (c *Config) migrateInjectionMode(mode string) {
|
||||
switch mode {
|
||||
case "clipboard":
|
||||
c.Injection.Backends = []string{"clipboard"}
|
||||
log.Printf("Config: migrated injection.mode='clipboard' to backends=['clipboard']")
|
||||
case "type":
|
||||
c.Injection.Backends = []string{"wtype"}
|
||||
log.Printf("Config: migrated injection.mode='type' to backends=['wtype']")
|
||||
case "fallback":
|
||||
c.Injection.Backends = []string{"wtype", "clipboard"}
|
||||
log.Printf("Config: migrated injection.mode='fallback' to backends=['wtype', 'clipboard']")
|
||||
default:
|
||||
// Default for new installs or unknown modes
|
||||
c.Injection.Backends = []string{"ydotool", "wtype", "clipboard"}
|
||||
if mode != "" {
|
||||
log.Printf("Config: unknown injection.mode='%s', using default backends", mode)
|
||||
}
|
||||
}
|
||||
|
||||
// Set default ydotool timeout if not set
|
||||
if c.Injection.YdotoolTimeout == 0 {
|
||||
c.Injection.YdotoolTimeout = 5 * time.Second
|
||||
}
|
||||
|
||||
log.Printf("Config: legacy 'mode' config detected - please update your config.toml to use 'backends' instead")
|
||||
}
|
||||
|
||||
func SaveDefaultConfig() error {
|
||||
configPath, err := GetConfigPath()
|
||||
if err != nil {
|
||||
@@ -296,9 +348,9 @@ func SaveDefaultConfig() error {
|
||||
|
||||
# Text Injection Configuration
|
||||
[injection]
|
||||
mode = "fallback" # Injection method ("clipboard", "type", "fallback")
|
||||
restore_clipboard = true # Restore original clipboard after injection
|
||||
wtype_timeout = "5s" # Timeout for direct typing via wtype
|
||||
backends = ["ydotool", "wtype", "clipboard"] # Ordered fallback chain (tries each until one succeeds)
|
||||
ydotool_timeout = "5s" # Timeout for ydotool commands
|
||||
wtype_timeout = "5s" # Timeout for wtype commands
|
||||
clipboard_timeout = "3s" # Timeout for clipboard operations
|
||||
|
||||
# Desktop Notification Configuration
|
||||
@@ -306,10 +358,16 @@ func SaveDefaultConfig() error {
|
||||
enabled = true # Enable desktop notifications
|
||||
type = "desktop" # Notification type ("desktop", "log", "none")
|
||||
|
||||
# Mode explanations:
|
||||
# - "clipboard": Copy text to clipboard only
|
||||
# - "type": Direct typing via wtype only
|
||||
# - "fallback": Try typing first, fallback to clipboard if it fails
|
||||
# Backend explanations:
|
||||
# - "ydotool": Uses ydotool (requires ydotoold daemon running). Most compatible with Chromium/Electron apps.
|
||||
# - "wtype": Uses wtype for Wayland. May have issues with some Chromium-based apps.
|
||||
# - "clipboard": Copies text to clipboard only (most reliable, but requires manual paste).
|
||||
#
|
||||
# The backends are tried in order. First successful one wins.
|
||||
# Example configurations:
|
||||
# backends = ["clipboard"] # Clipboard only (safest)
|
||||
# backends = ["wtype", "clipboard"] # wtype with clipboard fallback
|
||||
# backends = ["ydotool", "wtype", "clipboard"] # Full fallback chain (default)
|
||||
#
|
||||
# Provider explanations:
|
||||
# - "openai": OpenAI Whisper API (cloud-based, requires OPENAI_API_KEY)
|
||||
|
||||
+226
-27
@@ -26,8 +26,7 @@ func createTestConfig() *Config {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
RestoreClipboard: true,
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: 5 * time.Second,
|
||||
ClipboardTimeout: 3 * time.Second,
|
||||
},
|
||||
@@ -55,9 +54,9 @@ func createTestConfigWithInvalidValues() *Config {
|
||||
Model: "", // Invalid
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "invalid", // Invalid
|
||||
WtypeTimeout: 0, // Invalid
|
||||
ClipboardTimeout: 0, // Invalid
|
||||
Backends: []string{"invalid"}, YdotoolTimeout: 5 * time.Second, // Invalid
|
||||
WtypeTimeout: 0, // Invalid
|
||||
ClipboardTimeout: 0, // Invalid
|
||||
},
|
||||
Notifications: NotificationsConfig{
|
||||
Type: "invalid", // Invalid
|
||||
@@ -98,7 +97,7 @@ func TestConfig_Validate(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -125,7 +124,7 @@ func TestConfig_Validate(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -152,7 +151,7 @@ func TestConfig_Validate(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "invalid",
|
||||
Backends: []string{"invalid"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -179,7 +178,7 @@ func TestConfig_Validate(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -207,7 +206,7 @@ func TestConfig_Validate(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -235,7 +234,7 @@ func TestConfig_Validate(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -321,7 +320,8 @@ api_key = "test-key"
|
||||
model = "whisper-1"
|
||||
|
||||
[injection]
|
||||
mode = "fallback"
|
||||
backends = ["ydotool", "wtype", "clipboard"]
|
||||
ydotool_timeout = "5s"
|
||||
wtype_timeout = "5s"
|
||||
clipboard_timeout = "3s"
|
||||
|
||||
@@ -363,6 +363,205 @@ type = "log"`
|
||||
t.Errorf("Expected Provider 'openai', got %s", config.Transcription.Provider)
|
||||
}
|
||||
})
|
||||
|
||||
// Test migration from legacy mode config
|
||||
t.Run("migrates legacy mode=fallback to backends", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
|
||||
|
||||
err := os.MkdirAll(filepath.Dir(configPath), 0755)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create config directory: %v", err)
|
||||
}
|
||||
|
||||
legacyConfig := `[recording]
|
||||
sample_rate = 16000
|
||||
channels = 1
|
||||
format = "s16"
|
||||
buffer_size = 8192
|
||||
channel_buffer_size = 30
|
||||
timeout = "5m"
|
||||
|
||||
[transcription]
|
||||
provider = "openai"
|
||||
api_key = "test-key"
|
||||
model = "whisper-1"
|
||||
|
||||
[injection]
|
||||
mode = "fallback"
|
||||
wtype_timeout = "5s"
|
||||
clipboard_timeout = "3s"
|
||||
|
||||
[notifications]
|
||||
enabled = true
|
||||
type = "log"`
|
||||
|
||||
err = os.WriteFile(configPath, []byte(legacyConfig), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create config file: %v", err)
|
||||
}
|
||||
|
||||
originalConfigDir := os.Getenv("XDG_CONFIG_HOME")
|
||||
os.Setenv("XDG_CONFIG_HOME", tempDir)
|
||||
defer func() {
|
||||
if originalConfigDir == "" {
|
||||
os.Unsetenv("XDG_CONFIG_HOME")
|
||||
} else {
|
||||
os.Setenv("XDG_CONFIG_HOME", originalConfigDir)
|
||||
}
|
||||
}()
|
||||
|
||||
config, err := Load()
|
||||
if err != nil {
|
||||
t.Errorf("Load() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Should have migrated to backends
|
||||
expectedBackends := []string{"wtype", "clipboard"}
|
||||
if len(config.Injection.Backends) != len(expectedBackends) {
|
||||
t.Errorf("Expected %d backends, got %d", len(expectedBackends), len(config.Injection.Backends))
|
||||
}
|
||||
for i, b := range expectedBackends {
|
||||
if i < len(config.Injection.Backends) && config.Injection.Backends[i] != b {
|
||||
t.Errorf("Expected backend[%d]=%s, got %s", i, b, config.Injection.Backends[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Should have set default ydotool timeout
|
||||
if config.Injection.YdotoolTimeout != 5*time.Second {
|
||||
t.Errorf("Expected YdotoolTimeout=5s, got %v", config.Injection.YdotoolTimeout)
|
||||
}
|
||||
|
||||
// Verify it passes validation
|
||||
if err := config.Validate(); err != nil {
|
||||
t.Errorf("Migrated config is invalid: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("migrates legacy mode=clipboard to backends", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
|
||||
|
||||
err := os.MkdirAll(filepath.Dir(configPath), 0755)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create config directory: %v", err)
|
||||
}
|
||||
|
||||
legacyConfig := `[recording]
|
||||
sample_rate = 16000
|
||||
channels = 1
|
||||
format = "s16"
|
||||
buffer_size = 8192
|
||||
channel_buffer_size = 30
|
||||
timeout = "5m"
|
||||
|
||||
[transcription]
|
||||
provider = "openai"
|
||||
api_key = "test-key"
|
||||
model = "whisper-1"
|
||||
|
||||
[injection]
|
||||
mode = "clipboard"
|
||||
wtype_timeout = "5s"
|
||||
clipboard_timeout = "3s"
|
||||
|
||||
[notifications]
|
||||
enabled = true
|
||||
type = "log"`
|
||||
|
||||
err = os.WriteFile(configPath, []byte(legacyConfig), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create config file: %v", err)
|
||||
}
|
||||
|
||||
originalConfigDir := os.Getenv("XDG_CONFIG_HOME")
|
||||
os.Setenv("XDG_CONFIG_HOME", tempDir)
|
||||
defer func() {
|
||||
if originalConfigDir == "" {
|
||||
os.Unsetenv("XDG_CONFIG_HOME")
|
||||
} else {
|
||||
os.Setenv("XDG_CONFIG_HOME", originalConfigDir)
|
||||
}
|
||||
}()
|
||||
|
||||
config, err := Load()
|
||||
if err != nil {
|
||||
t.Errorf("Load() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
expectedBackends := []string{"clipboard"}
|
||||
if len(config.Injection.Backends) != len(expectedBackends) {
|
||||
t.Errorf("Expected %d backends, got %d", len(expectedBackends), len(config.Injection.Backends))
|
||||
}
|
||||
|
||||
if err := config.Validate(); err != nil {
|
||||
t.Errorf("Migrated config is invalid: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("migrates legacy mode=type to backends", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
|
||||
|
||||
err := os.MkdirAll(filepath.Dir(configPath), 0755)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create config directory: %v", err)
|
||||
}
|
||||
|
||||
legacyConfig := `[recording]
|
||||
sample_rate = 16000
|
||||
channels = 1
|
||||
format = "s16"
|
||||
buffer_size = 8192
|
||||
channel_buffer_size = 30
|
||||
timeout = "5m"
|
||||
|
||||
[transcription]
|
||||
provider = "openai"
|
||||
api_key = "test-key"
|
||||
model = "whisper-1"
|
||||
|
||||
[injection]
|
||||
mode = "type"
|
||||
wtype_timeout = "5s"
|
||||
clipboard_timeout = "3s"
|
||||
|
||||
[notifications]
|
||||
enabled = true
|
||||
type = "log"`
|
||||
|
||||
err = os.WriteFile(configPath, []byte(legacyConfig), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create config file: %v", err)
|
||||
}
|
||||
|
||||
originalConfigDir := os.Getenv("XDG_CONFIG_HOME")
|
||||
os.Setenv("XDG_CONFIG_HOME", tempDir)
|
||||
defer func() {
|
||||
if originalConfigDir == "" {
|
||||
os.Unsetenv("XDG_CONFIG_HOME")
|
||||
} else {
|
||||
os.Setenv("XDG_CONFIG_HOME", originalConfigDir)
|
||||
}
|
||||
}()
|
||||
|
||||
config, err := Load()
|
||||
if err != nil {
|
||||
t.Errorf("Load() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
expectedBackends := []string{"wtype"}
|
||||
if len(config.Injection.Backends) != len(expectedBackends) {
|
||||
t.Errorf("Expected %d backends, got %d", len(expectedBackends), len(config.Injection.Backends))
|
||||
}
|
||||
|
||||
if err := config.Validate(); err != nil {
|
||||
t.Errorf("Migrated config is invalid: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestConfig_SaveDefaultConfig(t *testing.T) {
|
||||
@@ -460,11 +659,11 @@ func TestConfig_ConversionMethods(t *testing.T) {
|
||||
t.Run("ToInjectionConfig", func(t *testing.T) {
|
||||
injectionConfig := config.ToInjectionConfig()
|
||||
|
||||
if injectionConfig.Mode != config.Injection.Mode {
|
||||
t.Errorf("Mode mismatch: got %s, want %s", injectionConfig.Mode, config.Injection.Mode)
|
||||
if len(injectionConfig.Backends) != len(config.Injection.Backends) {
|
||||
t.Errorf("Backends length mismatch: got %d, want %d", len(injectionConfig.Backends), len(config.Injection.Backends))
|
||||
}
|
||||
if injectionConfig.RestoreClipboard != config.Injection.RestoreClipboard {
|
||||
t.Errorf("RestoreClipboard mismatch: got %t, want %t", injectionConfig.RestoreClipboard, config.Injection.RestoreClipboard)
|
||||
if injectionConfig.YdotoolTimeout != config.Injection.YdotoolTimeout {
|
||||
t.Errorf("YdotoolTimeout mismatch: got %v, want %v", injectionConfig.YdotoolTimeout, config.Injection.YdotoolTimeout)
|
||||
}
|
||||
if injectionConfig.WtypeTimeout != config.Injection.WtypeTimeout {
|
||||
t.Errorf("WtypeTimeout mismatch: got %v, want %v", injectionConfig.WtypeTimeout, config.Injection.WtypeTimeout)
|
||||
@@ -630,7 +829,7 @@ func TestConfig_Validate_OpenAI_WithoutAPIKey(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -670,7 +869,7 @@ func TestConfig_Validate_OpenAI_WithEnvVarAPIKey(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -712,7 +911,7 @@ func TestConfig_Validate_RecordingTimeout(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -743,7 +942,7 @@ func TestConfig_Validate_InjectionTimeouts(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: 0, // Invalid timeout
|
||||
ClipboardTimeout: 0, // Invalid timeout
|
||||
},
|
||||
@@ -774,7 +973,7 @@ func TestConfig_Validate_RecordingBufferSizes(t *testing.T) {
|
||||
Model: "whisper-1",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -806,7 +1005,7 @@ func TestConfig_Validate_GroqTranscription(t *testing.T) {
|
||||
Model: "whisper-large-v3",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -838,7 +1037,7 @@ func TestConfig_Validate_GroqTranslation(t *testing.T) {
|
||||
Model: "whisper-large-v3", // Translation only supports non-turbo
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -870,7 +1069,7 @@ func TestConfig_Validate_GroqInvalidModel(t *testing.T) {
|
||||
Model: "invalid-model",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -901,7 +1100,7 @@ func TestConfig_Validate_GroqWithoutAPIKey(t *testing.T) {
|
||||
Model: "whisper-large-v3",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -941,7 +1140,7 @@ func TestConfig_Validate_GroqWithEnvVarAPIKey(t *testing.T) {
|
||||
Model: "whisper-large-v3",
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
@@ -1012,7 +1211,7 @@ func TestConfig_Validate_GroqTranslation_RejectsTurbo(t *testing.T) {
|
||||
Model: "whisper-large-v3-turbo", // Turbo not supported for translation
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Mode: "fallback",
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: time.Second,
|
||||
ClipboardTimeout: time.Second,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user