mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-31 19:45:15 +02:00
refactor(automations): streamline model eligibility handling in automation creation
- Removed the eligibility gate for model selection in the automation creation process, allowing users to choose models directly in the builder. - Updated the `AutomationBuilderForm` to incorporate model selection logic, ensuring that selected models are validated and preserved during automation creation and editing. - Simplified the `AutomationsContent` and `AutomationNewContent` components by eliminating unnecessary eligibility checks and alerts. - Enhanced the user experience by integrating model selection directly into the automation approval process, ensuring that only billable models are used. - Refactored related tests to cover new model selection behavior and ensure proper validation of user-selected models.
This commit is contained in:
parent
fade9d1b9d
commit
9d1a01eb0c
13 changed files with 887 additions and 263 deletions
150
surfsense_web/hooks/use-automation-eligible-models.ts
Normal file
150
surfsense_web/hooks/use-automation-eligible-models.ts
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
"use client";
|
||||
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
globalImageGenConfigsAtom,
|
||||
imageGenConfigsAtom,
|
||||
} from "@/atoms/image-gen-config/image-gen-config-query.atoms";
|
||||
import {
|
||||
globalNewLLMConfigsAtom,
|
||||
llmPreferencesAtom,
|
||||
newLLMConfigsAtom,
|
||||
} from "@/atoms/new-llm-config/new-llm-config-query.atoms";
|
||||
import {
|
||||
globalVisionLLMConfigsAtom,
|
||||
visionLLMConfigsAtom,
|
||||
} from "@/atoms/vision-llm-config/vision-llm-config-query.atoms";
|
||||
|
||||
/**
|
||||
* A single model the user may pick for an automation slot.
|
||||
*/
|
||||
export interface EligibleModelOption {
|
||||
id: number;
|
||||
name: string;
|
||||
/** Underlying model identifier (e.g. `gpt-4o`); shown as secondary text. */
|
||||
modelName: string;
|
||||
provider: string;
|
||||
/** `true` for user BYOK configs (positive ids), `false` for premium globals. */
|
||||
isBYOK: boolean;
|
||||
}
|
||||
|
||||
export interface EligibleModelKind {
|
||||
options: EligibleModelOption[];
|
||||
/** Default selection: the search-space pref when eligible, else first option. */
|
||||
defaultId: number | null;
|
||||
/** O(1) id → option lookup for trigger labels (avoids per-render `.find()`). */
|
||||
byId: Map<number, EligibleModelOption>;
|
||||
}
|
||||
|
||||
export interface AutomationEligibleModels {
|
||||
llm: EligibleModelKind;
|
||||
image: EligibleModelKind;
|
||||
vision: EligibleModelKind;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
interface GlobalConfigLike {
|
||||
id: number;
|
||||
name: string;
|
||||
model_name: string;
|
||||
provider: string;
|
||||
is_premium?: boolean;
|
||||
is_auto_mode?: boolean;
|
||||
}
|
||||
|
||||
interface UserConfigLike {
|
||||
id: number;
|
||||
name: string;
|
||||
model_name: string;
|
||||
provider: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the eligible option list for one model kind: premium globals
|
||||
* (`is_premium === true`, never Auto mode) followed by all BYOK configs.
|
||||
*/
|
||||
function buildKind(
|
||||
globals: GlobalConfigLike[] | undefined,
|
||||
byok: UserConfigLike[] | undefined,
|
||||
prefId: number | null | undefined
|
||||
): EligibleModelKind {
|
||||
const premiumGlobals: EligibleModelOption[] = (globals ?? [])
|
||||
.filter((c) => c.is_premium === true && !c.is_auto_mode)
|
||||
.map((c) => ({
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
modelName: c.model_name,
|
||||
provider: c.provider,
|
||||
isBYOK: false,
|
||||
}));
|
||||
|
||||
const byokOptions: EligibleModelOption[] = (byok ?? []).map((c) => ({
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
modelName: c.model_name,
|
||||
provider: c.provider,
|
||||
isBYOK: true,
|
||||
}));
|
||||
|
||||
const options = [...premiumGlobals, ...byokOptions];
|
||||
const byId = new Map<number, EligibleModelOption>(options.map((o) => [o.id, o]));
|
||||
|
||||
let defaultId: number | null = null;
|
||||
if (prefId != null && byId.has(prefId)) {
|
||||
defaultId = prefId;
|
||||
} else if (options.length > 0) {
|
||||
defaultId = options[0].id;
|
||||
}
|
||||
|
||||
return { options, defaultId, byId };
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the LLM / image / vision models that are eligible for automations
|
||||
* (premium globals + user BYOK — never free globals or Auto mode), with a
|
||||
* default selection seeded from the search space's role preferences.
|
||||
*
|
||||
* Everything is derived during render from the existing config query atoms;
|
||||
* there are no effects, so option lists/maps keep stable references.
|
||||
*/
|
||||
export function useAutomationEligibleModels(): AutomationEligibleModels {
|
||||
const { data: llmUserConfigs, isLoading: llmUserLoading } = useAtomValue(newLLMConfigsAtom);
|
||||
const { data: llmGlobalConfigs, isLoading: llmGlobalLoading } =
|
||||
useAtomValue(globalNewLLMConfigsAtom);
|
||||
const { data: preferences, isLoading: prefsLoading } = useAtomValue(llmPreferencesAtom);
|
||||
const { data: imageGlobalConfigs, isLoading: imageGlobalLoading } =
|
||||
useAtomValue(globalImageGenConfigsAtom);
|
||||
const { data: imageUserConfigs, isLoading: imageUserLoading } = useAtomValue(imageGenConfigsAtom);
|
||||
const { data: visionGlobalConfigs, isLoading: visionGlobalLoading } = useAtomValue(
|
||||
globalVisionLLMConfigsAtom
|
||||
);
|
||||
const { data: visionUserConfigs, isLoading: visionUserLoading } =
|
||||
useAtomValue(visionLLMConfigsAtom);
|
||||
|
||||
const llm = useMemo(
|
||||
() => buildKind(llmGlobalConfigs, llmUserConfigs, preferences?.agent_llm_id),
|
||||
[llmGlobalConfigs, llmUserConfigs, preferences?.agent_llm_id]
|
||||
);
|
||||
|
||||
const image = useMemo(
|
||||
() => buildKind(imageGlobalConfigs, imageUserConfigs, preferences?.image_generation_config_id),
|
||||
[imageGlobalConfigs, imageUserConfigs, preferences?.image_generation_config_id]
|
||||
);
|
||||
|
||||
const vision = useMemo(
|
||||
() => buildKind(visionGlobalConfigs, visionUserConfigs, preferences?.vision_llm_config_id),
|
||||
[visionGlobalConfigs, visionUserConfigs, preferences?.vision_llm_config_id]
|
||||
);
|
||||
|
||||
const isLoading =
|
||||
llmUserLoading ||
|
||||
llmGlobalLoading ||
|
||||
prefsLoading ||
|
||||
imageGlobalLoading ||
|
||||
imageUserLoading ||
|
||||
visionGlobalLoading ||
|
||||
visionUserLoading;
|
||||
|
||||
return useMemo(() => ({ llm, image, vision, isLoading }), [llm, image, vision, isLoading]);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue