Files
gnoma/internal/config/write.go
vikingowl cb2d63d06f feat: Ollama/gemma4 compat — /init flow, stream filter, safety fixes
provider/openai:
- Fix doubled tool call args (argsComplete flag): Ollama sends complete
  args in the first streaming chunk then repeats them as delta, causing
  doubled JSON and 400 errors in elfs
- Handle fs: prefix (gemma4 uses fs:grep instead of fs.grep)
- Add Reasoning field support for Ollama thinking output

cmd/gnoma:
- Early TTY detection so logger is created with correct destination
  before any component gets a reference to it (fixes slog WARN bleed
  into TUI textarea)

permission:
- Exempt spawn_elfs and agent tools from safety scanner: elf prompt
  text may legitimately mention .env/.ssh/credentials patterns and
  should not be blocked

tui/app:
- /init retry chain: no-tool-calls → spawn_elfs nudge → write nudge
  (ask for plain text output) → TUI fallback write from streamBuf
- looksLikeAgentsMD + extractMarkdownDoc: validate and clean fallback
  content before writing (reject refusals, strip narrative preambles)
- Collapse thinking output to 3 lines; ctrl+o to expand (live stream
  and committed messages)
- Stream-level filter for model pseudo-tool-call blocks: suppresses
  <<tool_code>>...</tool_code>> and <<function_call>>...<tool_call|>
  from entering streamBuf across chunk boundaries
- sanitizeAssistantText regex covers both block formats
- Reset streamFilterClose at every turn start
2026-04-05 19:24:51 +02:00

68 lines
1.5 KiB
Go

package config
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/BurntSushi/toml"
)
// SetProjectConfig writes a single key=value to the project config file (.gnoma/config.toml).
// Only whitelisted keys are supported.
func SetProjectConfig(key, value string) error {
allowed := map[string]bool{
"provider.default": true,
"provider.model": true,
"permission.mode": true,
}
if !allowed[key] {
return fmt.Errorf("unknown config key %q (supported: %s)", key, strings.Join(allowedKeys(), ", "))
}
path := projectConfigPath()
// Load existing config or start fresh
var cfg Config
if data, err := os.ReadFile(path); err == nil {
toml.Decode(string(data), &cfg)
}
if cfg.Provider.APIKeys == nil {
cfg.Provider.APIKeys = make(map[string]string)
}
if cfg.Provider.Endpoints == nil {
cfg.Provider.Endpoints = make(map[string]string)
}
// Apply the change
switch key {
case "provider.default":
cfg.Provider.Default = value
case "provider.model":
cfg.Provider.Model = value
case "permission.mode":
cfg.Permission.Mode = value
}
// Ensure directory exists
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return fmt.Errorf("create config dir: %w", err)
}
// Write
f, err := os.Create(path)
if err != nil {
return fmt.Errorf("create config file: %w", err)
}
defer f.Close()
enc := toml.NewEncoder(f)
return enc.Encode(cfg)
}
func allowedKeys() []string {
return []string{"provider.default", "provider.model", "permission.mode"}
}