Files
gnoma/internal/config/config.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

104 lines
2.6 KiB
Go

package config
import "time"
// Config is the top-level configuration.
type Config struct {
Provider ProviderSection `toml:"provider"`
Permission PermissionSection `toml:"permission"`
Tools ToolsSection `toml:"tools"`
RateLimits RateLimitSection `toml:"rate_limits"`
Security SecuritySection `toml:"security"`
}
// SecuritySection configures the secret scanner and firewall.
//
// Example config:
//
// [security]
// entropy_threshold = 4.5
//
// [[security.patterns]]
// name = "internal_token"
// regex = "mycompany_[a-zA-Z0-9]{32}"
// action = "redact"
type SecuritySection struct {
EntropyThreshold float64 `toml:"entropy_threshold"`
Patterns []PatternConfig `toml:"patterns"`
}
type PatternConfig struct {
Name string `toml:"name"`
Regex string `toml:"regex"`
Action string `toml:"action"` // "redact" (default), "block", "warn"
}
type PermissionSection struct {
Mode string `toml:"mode"`
Rules []PermissionRule `toml:"rules"`
}
type PermissionRule struct {
Tool string `toml:"tool"`
Pattern string `toml:"pattern"`
Action string `toml:"action"`
}
type ProviderSection struct {
Default string `toml:"default"`
Model string `toml:"model"`
MaxTokens int64 `toml:"max_tokens"`
Temperature *float64 `toml:"temperature"` // TODO(M8): wire to provider.Request.Temperature
APIKeys map[string]string `toml:"api_keys"`
Endpoints map[string]string `toml:"endpoints"`
}
type ToolsSection struct {
BashTimeout Duration `toml:"bash_timeout"`
MaxFileSize int64 `toml:"max_file_size"` // TODO(M8): wire to fs tool WithMaxFileSize option
}
// RateLimitSection allows overriding default rate limits per provider.
//
// Example config:
//
// [rate_limits.mistral]
// tier = "starter"
// rps = 1
// spend_cap = 20.0
//
// [rate_limits.anthropic]
// tier = "tier2"
// rpm = 1000
// itpm = 450000
// otpm = 90000
type RateLimitSection map[string]RateLimitOverride
type RateLimitOverride struct {
Tier string `toml:"tier"`
RPS float64 `toml:"rps"`
RPM int `toml:"rpm"`
RPD int `toml:"rpd"`
TPM int `toml:"tpm"`
ITPM int `toml:"itpm"`
OTPM int `toml:"otpm"`
TokensMonth int64 `toml:"tokens_month"`
SpendCap float64 `toml:"spend_cap"`
}
// Duration wraps time.Duration for TOML string parsing (e.g. "30s", "5m").
type Duration time.Duration
func (d *Duration) UnmarshalText(text []byte) error {
parsed, err := time.ParseDuration(string(text))
if err != nil {
return err
}
*d = Duration(parsed)
return nil
}
func (d Duration) Duration() time.Duration {
return time.Duration(d)
}