fix zombie leak, add quiet-hours toggle, improve query reply, configurable router threshold, JS dashboard

This commit is contained in:
kami
2026-07-03 00:42:35 +02:00
parent 612583d59a
commit e00cb07658
26 changed files with 3652 additions and 15 deletions
+8
View File
@@ -120,6 +120,13 @@ type VoiceConfig struct {
Tts *TtsConfig `json:"tts,omitempty"`
Embedder *EmbedderConfig `json:"embedder,omitempty"`
// RouterThreshold — the minimum confidence score for the intent classifier
// (stage 3 gate). Below this → clarify, don't guess. 0.0 means permissive
// (never clarify); 0.35 is a reasonable floor for the ONNX embedder.
// The HashEmbedder floor scores lexically and may need a lower value.
// Default 0.35 if unset.
RouterThreshold float64 `json:"router_threshold,omitempty"`
// Tools — the enabled act allowlist. Each is a spoken verb → argv the
// executor runs (args from the utterance appended). Editing this set is the
// human-only "enable" act (per spec); maven can't add to it from a request.
@@ -215,6 +222,7 @@ const (
DefaultTickInterval = 60 * time.Second
DefaultRepeatInterval = 5 * time.Minute
DefaultAutotuneInterval = 10 * time.Minute
DefaultRouterThreshold = 0.35
)
// Load reads the JSON config at path and applies defaults. A missing file is
+4
View File
@@ -126,12 +126,15 @@ func (p *LLMPhraser) start(ctx context.Context) error {
return nil
case err := <-errCh:
_ = cmd.Process.Kill()
_ = cmd.Wait()
return fmt.Errorf("llm: server output: %w", err)
case <-ctx.Done():
_ = cmd.Process.Kill()
_ = cmd.Wait()
return ctx.Err()
case <-time.After(60 * time.Second):
_ = cmd.Process.Kill()
_ = cmd.Wait()
return fmt.Errorf("llm: server did not start within 60s")
}
}
@@ -140,6 +143,7 @@ func (p *LLMPhraser) Close() error {
p.cancel()
if p.cmd != nil && p.cmd.Process != nil {
_ = p.cmd.Process.Kill()
_ = p.cmd.Wait() // reap the process — without Wait, the child becomes a zombie
}
p.wg.Wait()
return nil
+8 -2
View File
@@ -36,7 +36,10 @@ func (s *Store) WriteFact(ctx context.Context, ts time.Time, kind FactKind, key,
if err != nil {
return 0, fmt.Errorf("write fact: %w", err)
}
id, _ := res.LastInsertId()
id, err := res.LastInsertId()
if err != nil {
return 0, fmt.Errorf("last insert id: %w", err)
}
return id, nil
}
@@ -156,7 +159,10 @@ func (s *Store) CorrectValue(ctx context.Context, key, source string, value any,
if err := tx.Commit(); err != nil {
return 0, err
}
newID, _ = res.LastInsertId()
newID, err = res.LastInsertId()
if err != nil {
return 0, fmt.Errorf("last insert id: %w", err)
}
return newID, nil
}
+4 -1
View File
@@ -28,7 +28,10 @@ func (s *Store) WriteNote(ctx context.Context, ts time.Time, text string, embedd
if err != nil {
return 0, fmt.Errorf("write note: %w", err)
}
id, _ := res.LastInsertId()
id, err := res.LastInsertId()
if err != nil {
return 0, fmt.Errorf("last insert id: %w", err)
}
return id, nil
}
+3 -1
View File
@@ -70,7 +70,9 @@ func Open(ctx context.Context, path string) (*Store, error) {
// single writer expected; the daemon is the only process touching the db.
db.SetMaxOpenConns(1)
if _, err := db.ExecContext(ctx, schemaSQL); err != nil {
_ = db.Close()
if closeErr := db.Close(); closeErr != nil {
return nil, fmt.Errorf("apply schema: %w (close: %v)", err, closeErr)
}
return nil, fmt.Errorf("apply schema: %w", err)
}
return &Store{db: db}, nil