aboutsummaryrefslogtreecommitdiffstats
path: root/renderer/src/components/settings/ModelSettings.tsx
blob: ecfc12c79e75f5693ecd68ec2ab94b9d1345e1b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import React, { useState, useEffect } from "react";

const api = window.api;

export function ModelSettings() {
  // null = not yet loaded from DB
  const [model, setModel] = useState<string | null>(null);
  const [draft, setDraft] = useState("");
  const [saveStatus, setSaveStatus] = useState<"idle" | "saved">("idle");

  useEffect(() => {
    api.getSettings(["model"]).then((settings) => {
      const saved = settings["model"] ?? "";
      setModel(saved);
      setDraft(saved);
    });
  }, []);

  const handleSave = async () => {
    const trimmed = draft.trim();
    if (trimmed) {
      await api.setSetting("model", trimmed);
      setModel(trimmed);
    } else {
      await api.deleteSetting("model");
      setModel("");
    }
    setSaveStatus("saved");
    setTimeout(() => setSaveStatus("idle"), 1500);
  };

  const handleReset = async () => {
    await api.deleteSetting("model");
    setModel("");
    setDraft("");
    setSaveStatus("saved");
    setTimeout(() => setSaveStatus("idle"), 1500);
  };

  if (model === null) {
    return (
      <div style={{ color: "var(--text-secondary)", fontSize: 12 }}>
        Loading...
      </div>
    );
  }

  const isDirty = draft.trim() !== model;

  return (
    <div>
      <div className="settings-section-title">Model</div>
      <div className="settings-section-desc">
        Claude model to use for all phases. Leave blank to use the SDK&apos;s
        default model. Takes effect on the next message sent in any session.
      </div>

      <div className="settings-toggle-row">
        <input
          className="settings-model-input"
          type="text"
          value={draft}
          placeholder="Default (e.g. claude-sonnet-4-5)"
          onChange={(e) => {
            setDraft(e.target.value);
            setSaveStatus("idle");
          }}
          onKeyDown={(e) => {
            if (e.key === "Enter") handleSave();
          }}
          spellCheck={false}
        />
      </div>

      <div className="settings-actions">
        {model && (
          <button className="btn-secondary" onClick={handleReset}>
            Reset to Default
          </button>
        )}
        <button
          className="btn-primary"
          onClick={handleSave}
          disabled={!isDirty}
        >
          {saveStatus === "saved" ? "Saved \u2713" : "Save"}
        </button>
        {model && (
          <span className="settings-custom-badge">custom</span>
        )}
      </div>
    </div>
  );
}