config: voice defaults and its normalise/validate arms follow (V-410)
Same block, second half. applyDefaults and validate now call normaliseVoice and validateVoice, in the same order the inline arms ran.
This commit is contained in:
@@ -534,22 +534,10 @@ const (
|
||||
DefaultTickInterval = 60 * time.Second
|
||||
DefaultRepeatInterval = 5 * time.Minute
|
||||
DefaultAutotuneInterval = 10 * time.Minute
|
||||
DefaultRouterThreshold = 0.55
|
||||
// DefaultIntakeJournal — entries kept in the unified intake journal
|
||||
// (Vikunja #283). A busy day is a few hundred intake writes, so this is
|
||||
// roughly "today and yesterday" at a few hundred KB of memory.
|
||||
DefaultIntakeJournal = 512
|
||||
DefaultQueryMinScore = 0.55
|
||||
// Read off the margin sweep in internal/memory/recalleval on the e5
|
||||
// embedder: 0.008 answers 68% of real questions (down from 72%) and cuts
|
||||
// false recall from 5/5 to 1/5. Every larger delta costs real recall
|
||||
// without removing that last one until 0.020, which drops recall to 44%.
|
||||
DefaultQueryMinMargin = 0.008
|
||||
// DefaultClarifyMaxAttempts — see dialogue.DefaultMaxAttempts.
|
||||
DefaultClarifyMaxAttempts = 3
|
||||
DefaultToolTimeout = 30 * time.Second
|
||||
// DefaultLLMRouter — route with the resident model unless told otherwise.
|
||||
DefaultLLMRouter = true
|
||||
|
||||
DefaultFactEnrichmentInterval = 30 * time.Second
|
||||
|
||||
@@ -669,32 +657,7 @@ func (c *Config) applyDefaults() {
|
||||
|
||||
c.normaliseWorkstation()
|
||||
|
||||
if c.Voice != nil {
|
||||
if c.Voice.RouterThreshold <= 0 {
|
||||
c.Voice.RouterThreshold = DefaultRouterThreshold
|
||||
}
|
||||
if c.Voice.QueryMinScore <= 0 {
|
||||
c.Voice.QueryMinScore = DefaultQueryMinScore
|
||||
}
|
||||
// Unset ⇒ default. Negative is how you turn the margin off on purpose,
|
||||
// so it is clamped to 0 rather than replaced by the default.
|
||||
switch {
|
||||
case c.Voice.QueryMinMargin == 0:
|
||||
c.Voice.QueryMinMargin = DefaultQueryMinMargin
|
||||
case c.Voice.QueryMinMargin < 0:
|
||||
c.Voice.QueryMinMargin = 0
|
||||
}
|
||||
if c.Voice.ClarifyMaxAttempts <= 0 {
|
||||
c.Voice.ClarifyMaxAttempts = DefaultClarifyMaxAttempts
|
||||
}
|
||||
if c.Voice.ToolTimeout <= 0 {
|
||||
c.Voice.ToolTimeout = Duration(DefaultToolTimeout)
|
||||
}
|
||||
if c.Voice.LLMRouter == nil {
|
||||
on := DefaultLLMRouter
|
||||
c.Voice.LLMRouter = &on
|
||||
}
|
||||
}
|
||||
c.normaliseVoice()
|
||||
|
||||
// routines: default severity to care-class (1) — the safe floor: a
|
||||
// misconfigured routine can't blast an away channel at 3am.
|
||||
@@ -712,15 +675,6 @@ func (c *Config) applyDefaults() {
|
||||
}
|
||||
}
|
||||
|
||||
// UseLLMRouter reports whether to route with the resident model. Unset means
|
||||
// on; only an explicit false in the config turns it off.
|
||||
func (v *VoiceConfig) UseLLMRouter() bool {
|
||||
if v == nil || v.LLMRouter == nil {
|
||||
return DefaultLLMRouter
|
||||
}
|
||||
return *v.LLMRouter
|
||||
}
|
||||
|
||||
func (c *Config) validate() error {
|
||||
if c.Phraser != nil {
|
||||
if c.Phraser.ModelPath == "" {
|
||||
@@ -743,16 +697,8 @@ func (c *Config) validate() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if c.Voice != nil && c.Voice.Enabled {
|
||||
if c.Voice.Bind == "" {
|
||||
return errors.New("voice.enabled set but voice.bind is empty — refusing to start a voice surface with no bind address")
|
||||
}
|
||||
if c.Voice.Embedder != nil {
|
||||
partial := c.Voice.Embedder.ModelPath == "" || c.Voice.Embedder.TokenizerPath == "" || c.Voice.Embedder.LibPath == ""
|
||||
if partial {
|
||||
return errors.New("voice.embedder: all three of model_path, tokenizer_path, lib_path must be set, or remove embedder to use the floor stub")
|
||||
}
|
||||
}
|
||||
if err := c.validateVoice(); err != nil {
|
||||
return err
|
||||
}
|
||||
// routines: name + body required, cron must parse. A typo here should fail
|
||||
// at startup, not silently never fire.
|
||||
|
||||
@@ -1,5 +1,84 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Voice defaults, applied in normaliseVoice.
|
||||
const (
|
||||
DefaultRouterThreshold = 0.55
|
||||
DefaultQueryMinScore = 0.55
|
||||
// Read off the margin sweep in internal/memory/recalleval on the e5
|
||||
// embedder: 0.008 answers 68% of real questions (down from 72%) and cuts
|
||||
// false recall from 5/5 to 1/5. Every larger delta costs real recall
|
||||
// without removing that last one until 0.020, which drops recall to 44%.
|
||||
DefaultQueryMinMargin = 0.008
|
||||
// DefaultClarifyMaxAttempts — see dialogue.DefaultMaxAttempts.
|
||||
DefaultClarifyMaxAttempts = 3
|
||||
DefaultToolTimeout = 30 * time.Second
|
||||
// DefaultLLMRouter — route with the resident model unless told otherwise.
|
||||
DefaultLLMRouter = true
|
||||
)
|
||||
|
||||
// UseLLMRouter reports whether to route with the resident model. Unset means
|
||||
// on; only an explicit false in the config turns it off.
|
||||
func (v *VoiceConfig) UseLLMRouter() bool {
|
||||
if v == nil || v.LLMRouter == nil {
|
||||
return DefaultLLMRouter
|
||||
}
|
||||
return *v.LLMRouter
|
||||
}
|
||||
|
||||
// normaliseVoice applies the block's defaults. An absent block stays nil: the
|
||||
// surface is off and there is nothing to tune.
|
||||
func (c *Config) normaliseVoice() {
|
||||
if c.Voice == nil {
|
||||
return
|
||||
}
|
||||
if c.Voice.RouterThreshold <= 0 {
|
||||
c.Voice.RouterThreshold = DefaultRouterThreshold
|
||||
}
|
||||
if c.Voice.QueryMinScore <= 0 {
|
||||
c.Voice.QueryMinScore = DefaultQueryMinScore
|
||||
}
|
||||
// Unset ⇒ default. Negative is how you turn the margin off on purpose,
|
||||
// so it is clamped to 0 rather than replaced by the default.
|
||||
switch {
|
||||
case c.Voice.QueryMinMargin == 0:
|
||||
c.Voice.QueryMinMargin = DefaultQueryMinMargin
|
||||
case c.Voice.QueryMinMargin < 0:
|
||||
c.Voice.QueryMinMargin = 0
|
||||
}
|
||||
if c.Voice.ClarifyMaxAttempts <= 0 {
|
||||
c.Voice.ClarifyMaxAttempts = DefaultClarifyMaxAttempts
|
||||
}
|
||||
if c.Voice.ToolTimeout <= 0 {
|
||||
c.Voice.ToolTimeout = Duration(DefaultToolTimeout)
|
||||
}
|
||||
if c.Voice.LLMRouter == nil {
|
||||
on := DefaultLLMRouter
|
||||
c.Voice.LLMRouter = &on
|
||||
}
|
||||
}
|
||||
|
||||
// validateVoice refuses a surface that would listen nowhere, and an embedder
|
||||
// block with only some of its three paths filled in.
|
||||
func (c *Config) validateVoice() error {
|
||||
if c.Voice == nil || !c.Voice.Enabled {
|
||||
return nil
|
||||
}
|
||||
if c.Voice.Bind == "" {
|
||||
return errors.New("voice.enabled set but voice.bind is empty — refusing to start a voice surface with no bind address")
|
||||
}
|
||||
if e := c.Voice.Embedder; e != nil {
|
||||
if e.ModelPath == "" || e.TokenizerPath == "" || e.LibPath == "" {
|
||||
return errors.New("voice.embedder: all three of model_path, tokenizer_path, lib_path must be set, or remove embedder to use the floor stub")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VoiceConfig — the client↔core TCP surface + the stt/tts worker-module
|
||||
// seams.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user