fix: address assistant review feedback
This commit is contained in:
1 parent
33695753dd
commit
5ceef06b4b
26 files changed
+340
-49
No files matched your search
@@ -237,8 +237,9 @@ const fetchModelsAsync = async (configuration: AssistantConfiguration) => {
|
||||
.flatMap((model) => {
|
||||
const id = typeof model.id === "string" ? model.id : typeof model.model === "string" ? model.model : null;
|
||||
if (!id || id.length > 256) return [];
|
||||
const name =
|
||||
const rawName =
|
||||
typeof model.name === "string" ? model.name : typeof model.display_name === "string" ? model.display_name : id;
|
||||
const name = rawName.trim() || id;
|
||||
const contextLength =
|
||||
typeof model.context_length === "number" &&
|
||||
Number.isSafeInteger(model.context_length) &&
|
||||
|
||||
@@ -170,6 +170,12 @@ describe("assistant conversation features", () => {
|
||||
supported_parameters: [],
|
||||
architecture: { output_modalities: ["text"] },
|
||||
},
|
||||
{
|
||||
id: "example/unnamed",
|
||||
name: "",
|
||||
supported_parameters: ["tools"],
|
||||
architecture: { output_modalities: ["text"] },
|
||||
},
|
||||
],
|
||||
}),
|
||||
),
|
||||
@@ -187,6 +193,10 @@ describe("assistant conversation features", () => {
|
||||
name: "Example Model",
|
||||
inputModalities: ["text", "image"],
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: "example/unnamed",
|
||||
name: "example/unnamed",
|
||||
}),
|
||||
],
|
||||
});
|
||||
expect(JSON.stringify(options)).not.toContain("encrypted");
|
||||
|
||||
@@ -1970,6 +1970,7 @@
|
||||
"management": "Management",
|
||||
"assistant": "Homarr Assistant",
|
||||
"assistantThinking": "Thinking",
|
||||
"modifier": "Mod",
|
||||
"docker": "Docker",
|
||||
"preferences": "Your preferences",
|
||||
"logout": "Logout",
|
||||
@@ -2493,6 +2494,10 @@
|
||||
}
|
||||
},
|
||||
"widget": {
|
||||
"dynamicSelect": {
|
||||
"noResults": "No results found",
|
||||
"loadError": "Failed to load options"
|
||||
},
|
||||
"integrationSelect": {
|
||||
"configureIntegrationFirst": "Connect an integration first",
|
||||
"loading": "Loading...",
|
||||
@@ -6084,6 +6089,7 @@
|
||||
}
|
||||
},
|
||||
"assistant": {
|
||||
"loading": "Loading assistant configuration",
|
||||
"title": "Assistant",
|
||||
"description": "Connect an OpenAI-compatible model endpoint for the instance-wide assistant.",
|
||||
"security": {
|
||||
@@ -6245,9 +6251,9 @@
|
||||
"manualFallback": "Discovery is unavailable. You can still enter a model ID manually.",
|
||||
"saveConnectionFirst": "Save the provider connection before choosing a model.",
|
||||
"discovering": "Refreshing the models available from this provider…",
|
||||
"discovered": "Discovered {count} models. Tool support depends on the selected endpoint and model.",
|
||||
"discovered": "{count, plural, one {Discovered # model. Tool support depends on the selected endpoint and model.} other {Discovered # models. Tool support depends on the selected endpoint and model.}}",
|
||||
"discoveryFailed": "Model discovery did not complete",
|
||||
"context": "{count} token context",
|
||||
"context": "{count, number} token context",
|
||||
"toolsConfirmed": "Tools advertised",
|
||||
"toolsUnknown": "Verify tool support"
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useDebouncedValue } from "@mantine/hooks";
|
||||
import { IconCheck } from "@tabler/icons-react";
|
||||
|
||||
import { translateIfNecessary } from "@homarr/translation";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { useI18n, useScopedI18n } from "@homarr/translation/client";
|
||||
|
||||
import type { CommonWidgetInputProps } from "./common";
|
||||
import { useWidgetInputTranslation } from "./common";
|
||||
@@ -25,6 +25,7 @@ export const WidgetDynamicSelectInput = ({
|
||||
boardId,
|
||||
}: CommonWidgetInputProps<"dynamicSelect">) => {
|
||||
const t = useI18n();
|
||||
const tSelect = useScopedI18n("widget.dynamicSelect");
|
||||
const tWidget = useWidgetInputTranslation(kind, property);
|
||||
const form = useFormContext();
|
||||
const inputProps = form.getInputProps(`options.${property}`);
|
||||
@@ -77,7 +78,7 @@ export const WidgetDynamicSelectInput = ({
|
||||
searchValue={search}
|
||||
onSearchChange={setSearch}
|
||||
placeholder={tWidget("placeholder")}
|
||||
nothingFoundMessage={t("common.noResults")}
|
||||
nothingFoundMessage={tSelect("noResults")}
|
||||
leftSection={isPending && <Loader size="xs" />}
|
||||
renderOption={({ option, checked }) => {
|
||||
return (
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
import { Center, Stack, Text, ThemeIcon } from "@mantine/core";
|
||||
import { IconRobot } from "@tabler/icons-react";
|
||||
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
|
||||
import type { WidgetComponentProps } from "../definition";
|
||||
import { useAssistantWidgetRenderer } from "./context";
|
||||
|
||||
export default function AssistantWidget(props: WidgetComponentProps<"assistant">) {
|
||||
const Renderer = useAssistantWidgetRenderer();
|
||||
const t = useI18n();
|
||||
const t = useScopedI18n("widget.assistant.unavailable");
|
||||
|
||||
if (Renderer) return <Renderer {...props} />;
|
||||
|
||||
@@ -21,10 +21,10 @@ export default function AssistantWidget(props: WidgetComponentProps<"assistant">
|
||||
<IconRobot size={20} />
|
||||
</ThemeIcon>
|
||||
<Text size="sm" fw={600}>
|
||||
{t("widget.assistant.unavailable.title")}
|
||||
{t("title")}
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed">
|
||||
{t("widget.assistant.unavailable.description")}
|
||||
{t("description")}
|
||||
</Text>
|
||||
</Stack>
|
||||
</Center>
|
||||
|
||||
@@ -21,10 +21,11 @@ export const { definition, componentLoader } = createWidgetDefinition("assistant
|
||||
conversation: factory.dynamicSelect({
|
||||
withDescription: true,
|
||||
useOptions(query) {
|
||||
const { data: threads = [], isPending } = clientApi.assistant.listThreads.useQuery();
|
||||
const { data: threads = [], isPending, isError } = clientApi.assistant.listThreads.useQuery();
|
||||
const normalizedQuery = query.trim().toLocaleLowerCase();
|
||||
return {
|
||||
isPending,
|
||||
isError,
|
||||
options: threads
|
||||
.filter((thread) => {
|
||||
if (normalizedQuery.length === 0) return true;
|
||||
|
||||
@@ -61,6 +61,7 @@ interface DynamicSelectInput extends CommonInput<DynamicSelectOption | null> {
|
||||
) => {
|
||||
error?: string;
|
||||
isPending: boolean;
|
||||
isError?: boolean;
|
||||
options: DynamicSelectOption[];
|
||||
};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user