diff --git a/packages/chat-client/src/api/orchestration.js b/packages/chat-client/src/api/orchestration.js
index eba2ade..d571da0 100644
--- a/packages/chat-client/src/api/orchestration.js
+++ b/packages/chat-client/src/api/orchestration.js
@@ -172,4 +172,20 @@ export async function getEpisodes({ limit = API_DEFAULTS.EPISODE_LIMIT, offset =
export async function deleteEpisode(id) {
const res = await fetch(`${BASE_URL}/episodes/${id}`, { method: 'DELETE' });
if (!res.ok) throw new Error(`Failed to delete episode: ${res.status}`);
+}
+
+export async function getSettings() {
+ const res = await fetch(`${BASE_URL}/settings`);
+ if (!res.ok) throw new Error(`Failed to fetch settings: ${res.status}`);
+ return res.json();
+}
+
+export async function updateSettings(updates) {
+ const res = await fetch(`${BASE_URL}/settings`, {
+ method: 'PATCH',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(updates),
+ });
+ if (!res.ok) throw new Error(`Failed to update settings: ${res.status}`);
+ return res.json();
}
\ No newline at end of file
diff --git a/packages/chat-client/src/components/SettingsView.jsx b/packages/chat-client/src/components/SettingsView.jsx
index b2fdc03..c07a935 100644
--- a/packages/chat-client/src/components/SettingsView.jsx
+++ b/packages/chat-client/src/components/SettingsView.jsx
@@ -1,17 +1,17 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
+import { useSettings } from '../hooks/useSettings';
export default function SettingsView({ onNavigate }) {
+ const { settings, saveSetting, saving } = useSettings();
+
return (
-
- {/* Header */}
Settings
- {/* Memory */}
onNavigate('memory')}>Open →}
/>
- }
- />
- }
+ value={settings?.recentEpisodeLimit}
+ min={1} max={20}
+ onSave={val => saveSetting('recentEpisodeLimit', val)}
+ saving={saving}
+ />
+ saveSetting('semanticLimit', val)}
+ saving={saving}
+ />
+ saveSetting('scoreThreshold', val)}
+ saving={saving}
/>
- {/* Models */}
- }
- />
- }
- />
- }
- />
+ } />
+ } />
+ } />
- {/* About */}
- }
- />
- v0.1.0}
- />
+ } />
+ v0.1.0} />
- {/* Appearance */}
- }
- />
+ } />
@@ -96,6 +83,49 @@ function SettingsSection({ title, children }) {
);
}
+function NumberSetting({ label, description, value, min, max, step = 1, onSave, saving }) {
+ const [local, setLocal] = useState(value ?? '');
+ const isDirty = local !== '' && Number(local) !== value;
+
+ // Sync when settings load from API
+ useEffect(() => {
+ if (value !== undefined) setLocal(value);
+ }, [value]);
+
+ return (
+
+ setLocal(e.target.value)}
+ style={{
+ width: '64px', padding: '5px 8px', textAlign: 'center',
+ background: 'var(--bg-elevated)', border: '1px solid var(--border)',
+ borderRadius: 'var(--radius-md)', color: 'var(--text-primary)',
+ fontSize: '13px', outline: 'none',
+ }}
+ />
+ {isDirty && (
+
+ )}
+
+ }
+ />
+ );
+}
+
function SettingsRow({ label, description, action }) {
return (
{
+ getSettings().then(setSettings).catch(console.error);
+ }, []);
+
+ async function saveSetting(key, value) {
+ setSaving(true);
+ try {
+ const updated = await updateSettings({ [key]: value });
+ setSettings(updated);
+ } catch (err) {
+ console.error('[useSettings] Save failed:', err.message);
+ } finally {
+ setSaving(false);
+ }
+ }
+
+ return { settings, saveSetting, saving };
+}
\ No newline at end of file