新增用户意图确认功能
This commit is contained in:
1 parent
cf2e4bdd9c
commit
b8926f00d7
574 files changed
+97664
-97208
No files matched your search
@@ -1,59 +1,59 @@
|
||||
import { useCallback, useMemo, useSyncExternalStore } from "react";
|
||||
|
||||
import {
|
||||
DEFAULT_LOCAL_SETTINGS,
|
||||
applyThreadModelOverride,
|
||||
type LocalSettings,
|
||||
} from "./local";
|
||||
import {
|
||||
getBaseSettingsSnapshot,
|
||||
getThreadModelSnapshot,
|
||||
subscribe,
|
||||
updateLocalSettings,
|
||||
updateThreadSettings,
|
||||
type LocalSettingsSetter,
|
||||
} from "./store";
|
||||
|
||||
export function useLocalSettings(): [LocalSettings, LocalSettingsSetter] {
|
||||
const settings = useSyncExternalStore(
|
||||
subscribe,
|
||||
getBaseSettingsSnapshot,
|
||||
() => DEFAULT_LOCAL_SETTINGS,
|
||||
);
|
||||
|
||||
const setSettings = useCallback<LocalSettingsSetter>((key, value) => {
|
||||
updateLocalSettings(key, value);
|
||||
}, []);
|
||||
|
||||
return [settings, setSettings];
|
||||
}
|
||||
|
||||
export function useThreadSettings(
|
||||
threadId: string,
|
||||
): [LocalSettings, LocalSettingsSetter] {
|
||||
const baseSettings = useSyncExternalStore(
|
||||
subscribe,
|
||||
getBaseSettingsSnapshot,
|
||||
() => DEFAULT_LOCAL_SETTINGS,
|
||||
);
|
||||
|
||||
const threadModelName = useSyncExternalStore(
|
||||
subscribe,
|
||||
() => getThreadModelSnapshot(threadId),
|
||||
() => undefined,
|
||||
);
|
||||
|
||||
const settings = useMemo(
|
||||
() => applyThreadModelOverride(baseSettings, threadModelName),
|
||||
[baseSettings, threadModelName],
|
||||
);
|
||||
|
||||
const setSettings = useCallback<LocalSettingsSetter>(
|
||||
(key, value) => {
|
||||
updateThreadSettings(threadId, key, value);
|
||||
},
|
||||
[threadId],
|
||||
);
|
||||
|
||||
return [settings, setSettings];
|
||||
}
|
||||
import { useCallback, useMemo, useSyncExternalStore } from "react";
|
||||
|
||||
import {
|
||||
DEFAULT_LOCAL_SETTINGS,
|
||||
applyThreadModelOverride,
|
||||
type LocalSettings,
|
||||
} from "./local";
|
||||
import {
|
||||
getBaseSettingsSnapshot,
|
||||
getThreadModelSnapshot,
|
||||
subscribe,
|
||||
updateLocalSettings,
|
||||
updateThreadSettings,
|
||||
type LocalSettingsSetter,
|
||||
} from "./store";
|
||||
|
||||
export function useLocalSettings(): [LocalSettings, LocalSettingsSetter] {
|
||||
const settings = useSyncExternalStore(
|
||||
subscribe,
|
||||
getBaseSettingsSnapshot,
|
||||
() => DEFAULT_LOCAL_SETTINGS,
|
||||
);
|
||||
|
||||
const setSettings = useCallback<LocalSettingsSetter>((key, value) => {
|
||||
updateLocalSettings(key, value);
|
||||
}, []);
|
||||
|
||||
return [settings, setSettings];
|
||||
}
|
||||
|
||||
export function useThreadSettings(
|
||||
threadId: string,
|
||||
): [LocalSettings, LocalSettingsSetter] {
|
||||
const baseSettings = useSyncExternalStore(
|
||||
subscribe,
|
||||
getBaseSettingsSnapshot,
|
||||
() => DEFAULT_LOCAL_SETTINGS,
|
||||
);
|
||||
|
||||
const threadModelName = useSyncExternalStore(
|
||||
subscribe,
|
||||
() => getThreadModelSnapshot(threadId),
|
||||
() => undefined,
|
||||
);
|
||||
|
||||
const settings = useMemo(
|
||||
() => applyThreadModelOverride(baseSettings, threadModelName),
|
||||
[baseSettings, threadModelName],
|
||||
);
|
||||
|
||||
const setSettings = useCallback<LocalSettingsSetter>(
|
||||
(key, value) => {
|
||||
updateThreadSettings(threadId, key, value);
|
||||
},
|
||||
[threadId],
|
||||
);
|
||||
|
||||
return [settings, setSettings];
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
export { useLocalSettings, useThreadSettings } from "./hooks";
|
||||
export type { LocalSettings } from "./local";
|
||||
export { useLocalSettings, useThreadSettings } from "./hooks";
|
||||
export type { LocalSettings } from "./local";
|
||||
@@ -1,115 +1,115 @@
|
||||
import type { AgentThreadContext } from "../threads";
|
||||
|
||||
export const DEFAULT_LOCAL_SETTINGS: LocalSettings = {
|
||||
notification: {
|
||||
enabled: true,
|
||||
},
|
||||
context: {
|
||||
model_name: undefined,
|
||||
mode: undefined,
|
||||
reasoning_effort: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
export const LOCAL_SETTINGS_KEY = "deerflow.local-settings";
|
||||
export const THREAD_MODEL_KEY_PREFIX = "deerflow.thread-model.";
|
||||
|
||||
function isBrowser(): boolean {
|
||||
return typeof window !== "undefined";
|
||||
}
|
||||
|
||||
export interface LocalSettings {
|
||||
notification: {
|
||||
enabled: boolean;
|
||||
};
|
||||
context: Omit<
|
||||
AgentThreadContext,
|
||||
| "thread_id"
|
||||
| "is_plan_mode"
|
||||
| "thinking_enabled"
|
||||
| "subagent_enabled"
|
||||
| "model_name"
|
||||
| "reasoning_effort"
|
||||
> & {
|
||||
model_name?: string | undefined;
|
||||
mode: "flash" | "thinking" | "pro" | "ultra" | undefined;
|
||||
reasoning_effort?: "minimal" | "low" | "medium" | "high";
|
||||
};
|
||||
}
|
||||
|
||||
function mergeLocalSettings(settings?: Partial<LocalSettings>): LocalSettings {
|
||||
return {
|
||||
...DEFAULT_LOCAL_SETTINGS,
|
||||
context: {
|
||||
...DEFAULT_LOCAL_SETTINGS.context,
|
||||
...settings?.context,
|
||||
},
|
||||
notification: {
|
||||
...DEFAULT_LOCAL_SETTINGS.notification,
|
||||
...settings?.notification,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function getThreadModelStorageKey(threadId: string): string {
|
||||
return `${THREAD_MODEL_KEY_PREFIX}${threadId}`;
|
||||
}
|
||||
|
||||
export function getThreadModelName(threadId: string): string | undefined {
|
||||
if (!isBrowser()) {
|
||||
return undefined;
|
||||
}
|
||||
return localStorage.getItem(getThreadModelStorageKey(threadId)) ?? undefined;
|
||||
}
|
||||
|
||||
export function saveThreadModelName(
|
||||
threadId: string,
|
||||
modelName: string | undefined,
|
||||
) {
|
||||
if (!isBrowser()) {
|
||||
return;
|
||||
}
|
||||
const key = getThreadModelStorageKey(threadId);
|
||||
if (!modelName) {
|
||||
localStorage.removeItem(key);
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(key, modelName);
|
||||
}
|
||||
|
||||
export function applyThreadModelOverride(
|
||||
settings: LocalSettings,
|
||||
threadModelName: string | undefined,
|
||||
): LocalSettings {
|
||||
if (!threadModelName) {
|
||||
return settings;
|
||||
}
|
||||
return {
|
||||
...settings,
|
||||
context: {
|
||||
...settings.context,
|
||||
model_name: threadModelName,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getLocalSettings(): LocalSettings {
|
||||
if (!isBrowser()) {
|
||||
return DEFAULT_LOCAL_SETTINGS;
|
||||
}
|
||||
const json = localStorage.getItem(LOCAL_SETTINGS_KEY);
|
||||
try {
|
||||
if (json) {
|
||||
const settings = JSON.parse(json) as Partial<LocalSettings>;
|
||||
return mergeLocalSettings(settings);
|
||||
}
|
||||
} catch {}
|
||||
return DEFAULT_LOCAL_SETTINGS;
|
||||
}
|
||||
|
||||
export function saveLocalSettings(settings: LocalSettings) {
|
||||
if (!isBrowser()) {
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(LOCAL_SETTINGS_KEY, JSON.stringify(settings));
|
||||
}
|
||||
import type { AgentThreadContext } from "../threads";
|
||||
|
||||
export const DEFAULT_LOCAL_SETTINGS: LocalSettings = {
|
||||
notification: {
|
||||
enabled: true,
|
||||
},
|
||||
context: {
|
||||
model_name: undefined,
|
||||
mode: undefined,
|
||||
reasoning_effort: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
export const LOCAL_SETTINGS_KEY = "deerflow.local-settings";
|
||||
export const THREAD_MODEL_KEY_PREFIX = "deerflow.thread-model.";
|
||||
|
||||
function isBrowser(): boolean {
|
||||
return typeof window !== "undefined";
|
||||
}
|
||||
|
||||
export interface LocalSettings {
|
||||
notification: {
|
||||
enabled: boolean;
|
||||
};
|
||||
context: Omit<
|
||||
AgentThreadContext,
|
||||
| "thread_id"
|
||||
| "is_plan_mode"
|
||||
| "thinking_enabled"
|
||||
| "subagent_enabled"
|
||||
| "model_name"
|
||||
| "reasoning_effort"
|
||||
> & {
|
||||
model_name?: string | undefined;
|
||||
mode: "flash" | "thinking" | "pro" | "ultra" | undefined;
|
||||
reasoning_effort?: "minimal" | "low" | "medium" | "high";
|
||||
};
|
||||
}
|
||||
|
||||
function mergeLocalSettings(settings?: Partial<LocalSettings>): LocalSettings {
|
||||
return {
|
||||
...DEFAULT_LOCAL_SETTINGS,
|
||||
context: {
|
||||
...DEFAULT_LOCAL_SETTINGS.context,
|
||||
...settings?.context,
|
||||
},
|
||||
notification: {
|
||||
...DEFAULT_LOCAL_SETTINGS.notification,
|
||||
...settings?.notification,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function getThreadModelStorageKey(threadId: string): string {
|
||||
return `${THREAD_MODEL_KEY_PREFIX}${threadId}`;
|
||||
}
|
||||
|
||||
export function getThreadModelName(threadId: string): string | undefined {
|
||||
if (!isBrowser()) {
|
||||
return undefined;
|
||||
}
|
||||
return localStorage.getItem(getThreadModelStorageKey(threadId)) ?? undefined;
|
||||
}
|
||||
|
||||
export function saveThreadModelName(
|
||||
threadId: string,
|
||||
modelName: string | undefined,
|
||||
) {
|
||||
if (!isBrowser()) {
|
||||
return;
|
||||
}
|
||||
const key = getThreadModelStorageKey(threadId);
|
||||
if (!modelName) {
|
||||
localStorage.removeItem(key);
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(key, modelName);
|
||||
}
|
||||
|
||||
export function applyThreadModelOverride(
|
||||
settings: LocalSettings,
|
||||
threadModelName: string | undefined,
|
||||
): LocalSettings {
|
||||
if (!threadModelName) {
|
||||
return settings;
|
||||
}
|
||||
return {
|
||||
...settings,
|
||||
context: {
|
||||
...settings.context,
|
||||
model_name: threadModelName,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getLocalSettings(): LocalSettings {
|
||||
if (!isBrowser()) {
|
||||
return DEFAULT_LOCAL_SETTINGS;
|
||||
}
|
||||
const json = localStorage.getItem(LOCAL_SETTINGS_KEY);
|
||||
try {
|
||||
if (json) {
|
||||
const settings = JSON.parse(json) as Partial<LocalSettings>;
|
||||
return mergeLocalSettings(settings);
|
||||
}
|
||||
} catch {}
|
||||
return DEFAULT_LOCAL_SETTINGS;
|
||||
}
|
||||
|
||||
export function saveLocalSettings(settings: LocalSettings) {
|
||||
if (!isBrowser()) {
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(LOCAL_SETTINGS_KEY, JSON.stringify(settings));
|
||||
}
|
||||
@@ -1,150 +1,150 @@
|
||||
import {
|
||||
DEFAULT_LOCAL_SETTINGS,
|
||||
LOCAL_SETTINGS_KEY,
|
||||
THREAD_MODEL_KEY_PREFIX,
|
||||
getLocalSettings,
|
||||
getThreadModelName,
|
||||
saveLocalSettings,
|
||||
saveThreadModelName,
|
||||
type LocalSettings,
|
||||
} from "./local";
|
||||
|
||||
type Listener = () => void;
|
||||
|
||||
export type LocalSettingsSetter = <K extends keyof LocalSettings>(
|
||||
key: K,
|
||||
value: Partial<LocalSettings[K]>,
|
||||
) => void;
|
||||
|
||||
const listeners = new Set<Listener>();
|
||||
const threadModelNames = new Map<string, string | undefined>();
|
||||
|
||||
let baseSettings: LocalSettings = DEFAULT_LOCAL_SETTINGS;
|
||||
let baseSettingsLoaded = false;
|
||||
let storageListenerRegistered = false;
|
||||
|
||||
function emitChange() {
|
||||
for (const listener of listeners) {
|
||||
listener();
|
||||
}
|
||||
}
|
||||
|
||||
function ensureBaseSettingsLoaded() {
|
||||
if (baseSettingsLoaded || typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
baseSettings = getLocalSettings();
|
||||
baseSettingsLoaded = true;
|
||||
}
|
||||
|
||||
function ensureStorageListenerRegistered() {
|
||||
if (storageListenerRegistered || typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener("storage", handleStorage);
|
||||
storageListenerRegistered = true;
|
||||
}
|
||||
|
||||
function mergeSettingsSection<K extends keyof LocalSettings>(
|
||||
settings: LocalSettings,
|
||||
key: K,
|
||||
value: Partial<LocalSettings[K]>,
|
||||
): LocalSettings {
|
||||
return {
|
||||
...settings,
|
||||
[key]: {
|
||||
...settings[key],
|
||||
...value,
|
||||
},
|
||||
} as LocalSettings;
|
||||
}
|
||||
|
||||
function handleStorage(event: StorageEvent) {
|
||||
if (event.storageArea && event.storageArea !== localStorage) {
|
||||
return;
|
||||
}
|
||||
|
||||
ensureBaseSettingsLoaded();
|
||||
|
||||
if (event.key === null) {
|
||||
baseSettings = getLocalSettings();
|
||||
threadModelNames.clear();
|
||||
emitChange();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === LOCAL_SETTINGS_KEY) {
|
||||
baseSettings = getLocalSettings();
|
||||
emitChange();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!event.key.startsWith(THREAD_MODEL_KEY_PREFIX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const threadId = event.key.slice(THREAD_MODEL_KEY_PREFIX.length);
|
||||
threadModelNames.set(threadId, getThreadModelName(threadId));
|
||||
emitChange();
|
||||
}
|
||||
|
||||
export function subscribe(listener: Listener): () => void {
|
||||
ensureBaseSettingsLoaded();
|
||||
ensureStorageListenerRegistered();
|
||||
listeners.add(listener);
|
||||
|
||||
return () => {
|
||||
listeners.delete(listener);
|
||||
};
|
||||
}
|
||||
|
||||
export function getBaseSettingsSnapshot(): LocalSettings {
|
||||
ensureBaseSettingsLoaded();
|
||||
return baseSettings;
|
||||
}
|
||||
|
||||
export function getThreadModelSnapshot(threadId: string): string | undefined {
|
||||
ensureBaseSettingsLoaded();
|
||||
|
||||
if (!threadModelNames.has(threadId)) {
|
||||
threadModelNames.set(threadId, getThreadModelName(threadId));
|
||||
}
|
||||
|
||||
return threadModelNames.get(threadId);
|
||||
}
|
||||
|
||||
export const updateLocalSettings: LocalSettingsSetter = (key, value) => {
|
||||
ensureBaseSettingsLoaded();
|
||||
ensureStorageListenerRegistered();
|
||||
|
||||
baseSettings = mergeSettingsSection(baseSettings, key, value);
|
||||
saveLocalSettings(baseSettings);
|
||||
emitChange();
|
||||
};
|
||||
|
||||
export function updateThreadSettings<K extends keyof LocalSettings>(
|
||||
threadId: string,
|
||||
key: K,
|
||||
value: Partial<LocalSettings[K]>,
|
||||
) {
|
||||
ensureBaseSettingsLoaded();
|
||||
ensureStorageListenerRegistered();
|
||||
|
||||
const nextBaseSettings = mergeSettingsSection(baseSettings, key, value);
|
||||
baseSettings = nextBaseSettings;
|
||||
saveLocalSettings(baseSettings);
|
||||
|
||||
if (
|
||||
key === "context" &&
|
||||
Object.prototype.hasOwnProperty.call(value, "model_name")
|
||||
) {
|
||||
const contextValue = value as Partial<LocalSettings["context"]>;
|
||||
const threadModelName = contextValue.model_name;
|
||||
threadModelNames.set(threadId, threadModelName);
|
||||
saveThreadModelName(threadId, threadModelName);
|
||||
}
|
||||
|
||||
emitChange();
|
||||
}
|
||||
import {
|
||||
DEFAULT_LOCAL_SETTINGS,
|
||||
LOCAL_SETTINGS_KEY,
|
||||
THREAD_MODEL_KEY_PREFIX,
|
||||
getLocalSettings,
|
||||
getThreadModelName,
|
||||
saveLocalSettings,
|
||||
saveThreadModelName,
|
||||
type LocalSettings,
|
||||
} from "./local";
|
||||
|
||||
type Listener = () => void;
|
||||
|
||||
export type LocalSettingsSetter = <K extends keyof LocalSettings>(
|
||||
key: K,
|
||||
value: Partial<LocalSettings[K]>,
|
||||
) => void;
|
||||
|
||||
const listeners = new Set<Listener>();
|
||||
const threadModelNames = new Map<string, string | undefined>();
|
||||
|
||||
let baseSettings: LocalSettings = DEFAULT_LOCAL_SETTINGS;
|
||||
let baseSettingsLoaded = false;
|
||||
let storageListenerRegistered = false;
|
||||
|
||||
function emitChange() {
|
||||
for (const listener of listeners) {
|
||||
listener();
|
||||
}
|
||||
}
|
||||
|
||||
function ensureBaseSettingsLoaded() {
|
||||
if (baseSettingsLoaded || typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
baseSettings = getLocalSettings();
|
||||
baseSettingsLoaded = true;
|
||||
}
|
||||
|
||||
function ensureStorageListenerRegistered() {
|
||||
if (storageListenerRegistered || typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener("storage", handleStorage);
|
||||
storageListenerRegistered = true;
|
||||
}
|
||||
|
||||
function mergeSettingsSection<K extends keyof LocalSettings>(
|
||||
settings: LocalSettings,
|
||||
key: K,
|
||||
value: Partial<LocalSettings[K]>,
|
||||
): LocalSettings {
|
||||
return {
|
||||
...settings,
|
||||
[key]: {
|
||||
...settings[key],
|
||||
...value,
|
||||
},
|
||||
} as LocalSettings;
|
||||
}
|
||||
|
||||
function handleStorage(event: StorageEvent) {
|
||||
if (event.storageArea && event.storageArea !== localStorage) {
|
||||
return;
|
||||
}
|
||||
|
||||
ensureBaseSettingsLoaded();
|
||||
|
||||
if (event.key === null) {
|
||||
baseSettings = getLocalSettings();
|
||||
threadModelNames.clear();
|
||||
emitChange();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === LOCAL_SETTINGS_KEY) {
|
||||
baseSettings = getLocalSettings();
|
||||
emitChange();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!event.key.startsWith(THREAD_MODEL_KEY_PREFIX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const threadId = event.key.slice(THREAD_MODEL_KEY_PREFIX.length);
|
||||
threadModelNames.set(threadId, getThreadModelName(threadId));
|
||||
emitChange();
|
||||
}
|
||||
|
||||
export function subscribe(listener: Listener): () => void {
|
||||
ensureBaseSettingsLoaded();
|
||||
ensureStorageListenerRegistered();
|
||||
listeners.add(listener);
|
||||
|
||||
return () => {
|
||||
listeners.delete(listener);
|
||||
};
|
||||
}
|
||||
|
||||
export function getBaseSettingsSnapshot(): LocalSettings {
|
||||
ensureBaseSettingsLoaded();
|
||||
return baseSettings;
|
||||
}
|
||||
|
||||
export function getThreadModelSnapshot(threadId: string): string | undefined {
|
||||
ensureBaseSettingsLoaded();
|
||||
|
||||
if (!threadModelNames.has(threadId)) {
|
||||
threadModelNames.set(threadId, getThreadModelName(threadId));
|
||||
}
|
||||
|
||||
return threadModelNames.get(threadId);
|
||||
}
|
||||
|
||||
export const updateLocalSettings: LocalSettingsSetter = (key, value) => {
|
||||
ensureBaseSettingsLoaded();
|
||||
ensureStorageListenerRegistered();
|
||||
|
||||
baseSettings = mergeSettingsSection(baseSettings, key, value);
|
||||
saveLocalSettings(baseSettings);
|
||||
emitChange();
|
||||
};
|
||||
|
||||
export function updateThreadSettings<K extends keyof LocalSettings>(
|
||||
threadId: string,
|
||||
key: K,
|
||||
value: Partial<LocalSettings[K]>,
|
||||
) {
|
||||
ensureBaseSettingsLoaded();
|
||||
ensureStorageListenerRegistered();
|
||||
|
||||
const nextBaseSettings = mergeSettingsSection(baseSettings, key, value);
|
||||
baseSettings = nextBaseSettings;
|
||||
saveLocalSettings(baseSettings);
|
||||
|
||||
if (
|
||||
key === "context" &&
|
||||
Object.prototype.hasOwnProperty.call(value, "model_name")
|
||||
) {
|
||||
const contextValue = value as Partial<LocalSettings["context"]>;
|
||||
const threadModelName = contextValue.model_name;
|
||||
threadModelNames.set(threadId, threadModelName);
|
||||
saveThreadModelName(threadId, threadModelName);
|
||||
}
|
||||
|
||||
emitChange();
|
||||
}
|
||||
Reference in new issue
Block a user