)
const (
- // endpointChatGPT names the ChatGPT backend with the subscription login.
- endpointChatGPT = "chatgpt"
+ // configEndpointChatGPT names the ChatGPT backend with the subscription
+ // login.
+ configEndpointChatGPT = "chatgpt"
- // endpointAPI names the OpenAI API with an API key.
- endpointAPI = "api"
+ // configEndpointAPI names the OpenAI API with an API key.
+ configEndpointAPI = "api"
)
-// Config holds the settings of config.json in the data directory.
-type Config struct {
- Endpoint string `json:"endpoint"`
- Compactor ModelConfig `json:"compactor"`
-}
-
-// ModelConfig names a model and its reasoning effort.
-type ModelConfig struct {
- Model string `json:"model"`
- Effort string `json:"effort"`
-}
-
-// defaultConfig returns the settings that apply when config.json does not
-// set them.
-func defaultConfig() Config {
- return Config{
- Endpoint: endpointChatGPT,
- Compactor: ModelConfig{
- Model: "gpt-6.1-sol",
- Effort: "high",
- },
- }
-}
-
// loadConfig reads config.json in dir over the defaults. A missing file gives
// the defaults. An unknown field is an error, so a typo does not become a
// silent default.
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()
+
err = decoder.Decode(&config)
if err == nil && !errors.Is(decoder.Decode(&struct{}{}), io.EOF) {
err = errors.New("data after the JSON object")
return config, nil
}
+// Config holds the settings of config.json in the data directory.
+type Config struct {
+ Endpoint string `json:"endpoint"`
+ Compactor ModelConfig `json:"compactor"`
+}
+
// validate makes sure that each setting has a valid value.
func (c Config) validate() error {
- if c.Endpoint != endpointChatGPT && c.Endpoint != endpointAPI {
- return fmt.Errorf("endpoint %q is not %q or %q", c.Endpoint, endpointChatGPT, endpointAPI)
+ if c.Endpoint != configEndpointChatGPT && c.Endpoint != configEndpointAPI {
+ return fmt.Errorf("endpoint %q is not %q or %q", c.Endpoint, configEndpointChatGPT, configEndpointAPI)
}
if c.Compactor.Model == "" || c.Compactor.Effort == "" {
return nil
}
-// dataDir returns the data directory and creates it with mode 0700 when it
-// does not exist. It is ONECHAT_DIR when that is set. Otherwise it is
-// $XDG_DATA_HOME/onechat when XDG_DATA_HOME is an absolute path, or else
-// ~/.local/share/onechat.
-func dataDir() (string, error) {
- dir := os.Getenv("ONECHAT_DIR")
- if dir == "" {
- var err error
- dir, err = defaultDataDir()
- if err != nil {
- return "", err
- }
- }
-
- err := os.MkdirAll(dir, 0o700)
- if err != nil {
- return "", fmt.Errorf("create data directory: %w", err)
- }
-
- return dir, nil
+// ModelConfig names a model and its reasoning effort.
+type ModelConfig struct {
+ Model string `json:"model"`
+ Effort string `json:"effort"`
}
-// defaultDataDir returns the data directory for an unset ONECHAT_DIR. The XDG
-// specification says to ignore a relative XDG_DATA_HOME.
-func defaultDataDir() (string, error) {
- xdg := os.Getenv("XDG_DATA_HOME")
- if filepath.IsAbs(xdg) {
- return filepath.Join(xdg, "onechat"), nil
- }
-
- home, err := os.UserHomeDir()
- if err != nil {
- return "", fmt.Errorf("find data directory: set ONECHAT_DIR: %w", err)
+// defaultConfig returns the settings that apply when config.json does not
+// set them.
+func defaultConfig() Config {
+ return Config{
+ Endpoint: configEndpointChatGPT,
+ Compactor: ModelConfig{
+ Model: "gpt-6.1-sol",
+ Effort: "high",
+ },
}
-
- return filepath.Join(home, ".local", "share", "onechat"), nil
}