mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
refactor: move shared AI model UI into modules/aiModels (#29040)
> 🤖 Refactoring with Cursor.
AI settings was importing model form fields, ModelSelector, and
ProviderIcon from AgentsPage. Those now live in
`site/src/modules/aiModels`.
No user-facing behavior change.
- Move ProviderIcon, ModelSelector, and the model admin form fields into
`modules/aiModels`
- Point AgentsPage and AI settings at the new paths
- Drop the leftover ChatModelAdminPanel ProviderIcon duplicate and the
knownModels barrel
- Update the known-models catalog generator paths
This commit is contained in:
+1
-1
@@ -40,4 +40,4 @@ site/src/api/typesGenerated.ts linguist-generated=true
|
||||
|
||||
# AI Gateway prices
|
||||
coderd/aibridge/prices/data/prices.json linguist-generated=true
|
||||
site/src/pages/AgentsPage/components/ChatModelAdminPanel/knownModels/knownModelsGenerated.json linguist-generated=true
|
||||
site/src/modules/aiModels/knownModels/knownModelsGenerated.json linguist-generated=true
|
||||
|
||||
@@ -29,7 +29,7 @@ concurrency:
|
||||
env:
|
||||
REFRESH_BRANCH: bot/aigateway-prices-refresh
|
||||
PRICES_FILE: coderd/aibridge/prices/data/prices.json
|
||||
CATALOG_FILE: site/src/pages/AgentsPage/components/ChatModelAdminPanel/knownModels/knownModelsGenerated.json
|
||||
CATALOG_FILE: site/src/modules/aiModels/knownModels/knownModelsGenerated.json
|
||||
|
||||
jobs:
|
||||
refresh:
|
||||
|
||||
+1
-1
@@ -46,4 +46,4 @@ codersdk/aiproviders_bedrock.go @ibetitsmike @johnstcn
|
||||
# models.dev data, and they carry customer-visible cost numbers, so every
|
||||
# refresh needs a review from someone who owns them.
|
||||
coderd/aibridge/prices/data/prices.json @evgeniy-scherbina @ssncferreira @johnstcn
|
||||
site/src/pages/AgentsPage/components/ChatModelAdminPanel/knownModels/knownModelsGenerated.json @evgeniy-scherbina @ssncferreira @johnstcn
|
||||
site/src/modules/aiModels/knownModels/knownModelsGenerated.json @evgeniy-scherbina @ssncferreira @johnstcn
|
||||
|
||||
@@ -1063,13 +1063,13 @@ coderd/aibridge/prices/data/prices.json: _gen/bin/aibridgepricesgen _gen/models-
|
||||
# snapshot joined with the editorial curation in
|
||||
# scripts/aibridgepricesgen/curation.json. Kept out of `make gen` for the
|
||||
# same live-upstream-data reason as prices.json.
|
||||
site/src/pages/AgentsPage/components/ChatModelAdminPanel/knownModels/knownModelsGenerated.json: _gen/bin/aibridgepricesgen _gen/models-dev.json | _gen
|
||||
site/src/modules/aiModels/knownModels/knownModelsGenerated.json: _gen/bin/aibridgepricesgen _gen/models-dev.json | _gen
|
||||
$(call atomic_write,_gen/bin/aibridgepricesgen -format=catalog -upstream _gen/models-dev.json,./scripts/biome_format.sh)
|
||||
.PHONY: site/src/pages/AgentsPage/components/ChatModelAdminPanel/knownModels/knownModelsGenerated.json
|
||||
.PHONY: site/src/modules/aiModels/knownModels/knownModelsGenerated.json
|
||||
|
||||
gen/aibridge-prices: \
|
||||
coderd/aibridge/prices/data/prices.json \
|
||||
site/src/pages/AgentsPage/components/ChatModelAdminPanel/knownModels/knownModelsGenerated.json
|
||||
site/src/modules/aiModels/knownModels/knownModelsGenerated.json
|
||||
.PHONY: gen/aibridge-prices
|
||||
|
||||
gen/golden-files: \
|
||||
|
||||
@@ -7,7 +7,7 @@ next regeneration will overwrite any changes.
|
||||
The Make target fetches models.dev once into `_gen/models-dev.json`, applying
|
||||
the upstream corrections in `scripts/aibridgepricesgen/overrides.jq`. Both
|
||||
`prices.json` and the frontend known-models catalog at
|
||||
`site/src/pages/AgentsPage/components/ChatModelAdminPanel/knownModels/knownModelsGenerated.json`
|
||||
`site/src/modules/aiModels/knownModels/knownModelsGenerated.json`
|
||||
are generated from that single patched snapshot; the catalog is additionally
|
||||
joined with the editorial curation in
|
||||
`scripts/aibridgepricesgen/curation.json`.
|
||||
|
||||
@@ -272,7 +272,7 @@ func TestCurationMatchesGeneratedCatalog(t *testing.T) {
|
||||
|
||||
curation := embeddedCuration(t)
|
||||
|
||||
data, err := os.ReadFile("../../site/src/pages/AgentsPage/components/ChatModelAdminPanel/knownModels/knownModelsGenerated.json")
|
||||
data, err := os.ReadFile("../../site/src/modules/aiModels/knownModels/knownModelsGenerated.json")
|
||||
require.NoError(t, err)
|
||||
var generated map[string][]catalogEntry
|
||||
require.NoError(t, json.Unmarshal(data, &generated))
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ Some end-to-end tests require a license. The Storybook MCP at `http://localhost:
|
||||
|
||||
## Performance
|
||||
|
||||
- `src/pages/AgentsPage/`, including `components/ChatElements/`, uses React Compiler. Do not add `useMemo`, `useCallback`, or `memo()` there.
|
||||
- `src/pages/AgentsPage/`, including `components/ChatElements/`, and `src/modules/aiModels/` use React Compiler. Do not add `useMemo`, `useCallback`, or `memo()` there.
|
||||
- `memo()` remains valid for list-item components rendered in a map because compiler memoization does not cross component boundaries.
|
||||
- Isolate frequently changing state in a small child component instead of rerendering a large parent subtree.
|
||||
- Throttle high-frequency handlers that set state with `requestAnimationFrame` or an established throttle utility.
|
||||
|
||||
@@ -19,6 +19,7 @@ const siteDir = new URL("..", import.meta.url).pathname;
|
||||
// Directories opted in to React Compiler. Keep this list in sync with
|
||||
// the include filter in vite.config.mts.
|
||||
const targetDirs = [
|
||||
"src/modules/aiModels",
|
||||
"src/pages/AgentsPage",
|
||||
"src/pages/AIBridgePage",
|
||||
"src/pages/TemplateBuilder",
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ import {
|
||||
findKnownModelByCanonicalId,
|
||||
findKnownModelByExactAlias,
|
||||
formatPricePerMillionTokens,
|
||||
} from "./knownModels";
|
||||
} from "./knownModels/catalog";
|
||||
import {
|
||||
isFieldConflictDisabled,
|
||||
isVisibleWhenSatisfied,
|
||||
+3
-3
@@ -13,15 +13,15 @@ import { Input } from "#/components/Input/Input";
|
||||
import { Label } from "#/components/Label/Label";
|
||||
import { normalizeProvider } from "#/modules/aiModels/helpers";
|
||||
import type { FormHelpers } from "#/utils/formUtils";
|
||||
import { applyKnownModelDefaults } from "./knownModels/applyKnownModelDefaults";
|
||||
import {
|
||||
findKnownModelByCanonicalId,
|
||||
findKnownModelByExactAlias,
|
||||
formatContextBadge,
|
||||
getKnownModelsForProvider,
|
||||
type KnownModel,
|
||||
searchKnownModels,
|
||||
} from "./knownModels";
|
||||
import { applyKnownModelDefaults } from "./knownModels/applyKnownModelDefaults";
|
||||
} from "./knownModels/catalog";
|
||||
import type { KnownModel } from "./knownModels/types";
|
||||
import { deepGet, deepSet, type ModelFormValues } from "./modelConfigFormLogic";
|
||||
|
||||
type ModelFormMode = "add" | "edit" | "duplicate";
|
||||
+1
-1
@@ -76,7 +76,7 @@ const longNameModel: ModelSelectorOption = {
|
||||
};
|
||||
|
||||
const meta: Meta<typeof ModelSelector> = {
|
||||
title: "pages/AgentsPage/ChatElements/ModelSelector",
|
||||
title: "modules/aiModels/ModelSelector",
|
||||
component: ModelSelector,
|
||||
args: {
|
||||
options: openAIModels,
|
||||
+2
-2
@@ -22,9 +22,9 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "#/components/Tooltip/Tooltip";
|
||||
import { ProviderIcon } from "#/pages/AISettingsPage/ProvidersPage/components/ProviderIcon";
|
||||
import { formatReasoningEffort } from "#/modules/aiModels/helpers";
|
||||
import { ProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import { formatProviderLabel as defaultFormatProviderLabel } from "#/utils/aiProviders";
|
||||
import { formatReasoningEffort } from "../../utils/reasoningEffort";
|
||||
|
||||
export interface ModelSelectorOption {
|
||||
id: string;
|
||||
+1
-1
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { ProviderIcon } from "./ProviderIcon";
|
||||
|
||||
const meta: Meta<typeof ProviderIcon> = {
|
||||
title: "pages/AISettingsPage/ProviderIcon",
|
||||
title: "modules/aiModels/ProviderIcon",
|
||||
component: ProviderIcon,
|
||||
};
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
import { Building2Icon } from "lucide-react";
|
||||
import { ExternalImage } from "#/components/ExternalImage/ExternalImage";
|
||||
import { normalizeProvider } from "#/modules/aiModels/helpers";
|
||||
|
||||
type ProviderIconProps = {
|
||||
provider: string;
|
||||
@@ -8,7 +9,7 @@ type ProviderIconProps = {
|
||||
};
|
||||
|
||||
export const getProviderIcon = (provider: string): string | undefined => {
|
||||
switch (provider) {
|
||||
switch (normalizeProvider(provider)) {
|
||||
case "openai":
|
||||
return "/icon/openai.svg";
|
||||
case "anthropic":
|
||||
@@ -1,3 +1,7 @@
|
||||
export function normalizeProvider(provider: string): string {
|
||||
return provider.trim().toLowerCase();
|
||||
}
|
||||
|
||||
/** Display label for an effort value, e.g. "xhigh" renders as "Xhigh". */
|
||||
export const formatReasoningEffort = (value: string): string =>
|
||||
value.charAt(0).toUpperCase() + value.slice(1);
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@ import {
|
||||
type ApplyKnownModelDefaultsResult,
|
||||
applyKnownModelDefaults,
|
||||
} from "./applyKnownModelDefaults";
|
||||
import { findKnownModelByCanonicalId, type KnownModel } from "./index";
|
||||
import { findKnownModelByCanonicalId } from "./catalog";
|
||||
import type { KnownModel } from "./types";
|
||||
|
||||
const requireKnownModel = (
|
||||
provider: string,
|
||||
+1
-1
@@ -6,7 +6,7 @@ import {
|
||||
formatPricePerMillionTokens,
|
||||
getKnownModelsForProvider,
|
||||
searchKnownModels,
|
||||
} from "./index";
|
||||
} from "./catalog";
|
||||
|
||||
const modelIds = (provider: string): readonly string[] =>
|
||||
getKnownModelsForProvider(provider).map(
|
||||
-2
@@ -2,8 +2,6 @@ import { normalizeProvider } from "#/modules/aiModels/helpers";
|
||||
import knownModelsGenerated from "./knownModelsGenerated.json";
|
||||
import type { KnownModel } from "./types";
|
||||
|
||||
export type { KnownModel };
|
||||
|
||||
// knownModelsGenerated.json is produced by `make gen/aibridge-prices` from
|
||||
// models.dev joined with the editorial curation in
|
||||
// scripts/aibridgepricesgen/curation.json. Do not edit it manually. JSON
|
||||
+1
-1
@@ -3,7 +3,7 @@ import type { FC, ReactNode } from "react";
|
||||
import type * as TypesGen from "#/api/typesGenerated";
|
||||
import { Button } from "#/components/Button/Button";
|
||||
import { useTemporarySavedState } from "#/components/TemporarySavedState/TemporarySavedState";
|
||||
import { ModelSelector } from "#/pages/AgentsPage/components/ChatElements/ModelSelector";
|
||||
import { ModelSelector } from "#/modules/aiModels/ModelSelector";
|
||||
import { ModelOverrideAlerts } from "#/pages/AgentsPage/components/ModelOverrideAlerts";
|
||||
import type { ProviderInfo } from "#/pages/AgentsPage/utils/modelOptions";
|
||||
import { pickReasoningEffort } from "#/pages/AgentsPage/utils/reasoningEffort";
|
||||
|
||||
@@ -38,11 +38,11 @@ import {
|
||||
} from "#/components/Table/Table";
|
||||
import { TableEmpty } from "#/components/TableEmpty/TableEmpty";
|
||||
import { TableLoader } from "#/components/TableLoader/TableLoader";
|
||||
import { ProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import {
|
||||
canManageProviderModels,
|
||||
type ProviderState,
|
||||
} from "#/modules/aiModels/providerStates";
|
||||
import { ProviderIcon } from "#/pages/AISettingsPage/ProvidersPage/components/ProviderIcon";
|
||||
import { paginateItems } from "#/utils/paginateItems";
|
||||
import { ModelRow } from "./components/ModelRow";
|
||||
import {
|
||||
|
||||
@@ -6,17 +6,17 @@ import type * as TypesGen from "#/api/typesGenerated";
|
||||
import { OrganizationField } from "#/components/OrganizationAutocomplete/OrganizationAutocomplete";
|
||||
import { SettingsHeaderTitle } from "#/components/SettingsHeader/SettingsHeader";
|
||||
import { useUnsavedChangesPrompt } from "#/hooks/useUnsavedChangesPrompt";
|
||||
import {
|
||||
canManageProviderModels,
|
||||
type ProviderState,
|
||||
} from "#/modules/aiModels/providerStates";
|
||||
import {
|
||||
buildInitialModelFormValues,
|
||||
buildModelConfigFromForm,
|
||||
type ModelFormValues,
|
||||
parsePositiveInteger,
|
||||
parseThresholdInteger,
|
||||
} from "#/pages/AgentsPage/components/ChatModelAdminPanel/modelConfigFormLogic";
|
||||
} from "#/modules/aiModels/modelConfigFormLogic";
|
||||
import {
|
||||
canManageProviderModels,
|
||||
type ProviderState,
|
||||
} from "#/modules/aiModels/providerStates";
|
||||
import { getFormHelpers } from "#/utils/formUtils";
|
||||
import {
|
||||
creatableModelOrganizations,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "#/components/Dialog/Dialog";
|
||||
import type { ModelFormValues } from "#/pages/AgentsPage/components/ChatModelAdminPanel/modelConfigFormLogic";
|
||||
import type { ModelFormValues } from "#/modules/aiModels/modelConfigFormLogic";
|
||||
|
||||
export const ModelFormDialogs: FC<{
|
||||
editingModel?: TypesGen.ChatModel;
|
||||
|
||||
@@ -32,18 +32,18 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "#/components/Tooltip/Tooltip";
|
||||
import type { ProviderState } from "#/modules/aiModels/providerStates";
|
||||
import {
|
||||
GeneralModelConfigFields,
|
||||
ModelConfigFields,
|
||||
PricingEstimateFields,
|
||||
ReasoningEffortConfigFields,
|
||||
} from "#/pages/AgentsPage/components/ChatModelAdminPanel/ModelConfigFields";
|
||||
import { ModelIdentifierField } from "#/pages/AgentsPage/components/ChatModelAdminPanel/ModelIdentifierField";
|
||||
} from "#/modules/aiModels/ModelConfigFields";
|
||||
import { ModelIdentifierField } from "#/modules/aiModels/ModelIdentifierField";
|
||||
import type {
|
||||
ModelConfigFormBuildResult,
|
||||
ModelFormValues,
|
||||
} from "#/pages/AgentsPage/components/ChatModelAdminPanel/modelConfigFormLogic";
|
||||
} from "#/modules/aiModels/modelConfigFormLogic";
|
||||
import type { ProviderState } from "#/modules/aiModels/providerStates";
|
||||
import { docs } from "#/utils/docs";
|
||||
import type { FormHelpers } from "#/utils/formUtils";
|
||||
import {
|
||||
|
||||
@@ -26,8 +26,8 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "#/components/Tooltip/Tooltip";
|
||||
import { getProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import type { ProviderState } from "#/modules/aiModels/providerStates";
|
||||
import { getProviderIcon } from "#/pages/AISettingsPage/ProvidersPage/components/ProviderIcon";
|
||||
import { useOrganizationModelsPath } from "../organizationModels";
|
||||
|
||||
export const ModelFormBackLink: FC = () => {
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "#/components/Select/Select";
|
||||
import { ProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import type { ProviderState } from "#/modules/aiModels/providerStates";
|
||||
import { ProviderIcon } from "#/pages/AISettingsPage/ProvidersPage/components/ProviderIcon";
|
||||
|
||||
export const ModelFormProviderSelect: FC<{
|
||||
providerStates: readonly ProviderState[];
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "#/components/Tooltip/Tooltip";
|
||||
import { useClickableTableRow } from "#/hooks/useClickableTableRow";
|
||||
import { ProviderIcon } from "#/pages/AISettingsPage/ProvidersPage/components/ProviderIcon";
|
||||
import { ProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
|
||||
type ModelRowProps = {
|
||||
model: ChatModel;
|
||||
|
||||
@@ -8,9 +8,9 @@ import { createAIProviderMutation } from "#/api/queries/aiProviders";
|
||||
import { Avatar } from "#/components/Avatar/Avatar";
|
||||
import { Button } from "#/components/Button/Button";
|
||||
import { SettingsHeaderTitle } from "#/components/SettingsHeader/SettingsHeader";
|
||||
import { getProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import type { AddableProvider } from "../components/addableProviderTypes";
|
||||
import { ProviderForm } from "../components/ProviderForm";
|
||||
import { getProviderIcon } from "../components/ProviderIcon";
|
||||
import { providerFormValuesToCreate } from "../components/providerFormApiMap";
|
||||
|
||||
interface AddProviderPageViewProps {
|
||||
|
||||
@@ -24,8 +24,8 @@ import {
|
||||
} from "#/components/Table/Table";
|
||||
import { TableEmpty } from "#/components/TableEmpty/TableEmpty";
|
||||
import { TableLoader } from "#/components/TableLoader/TableLoader";
|
||||
import { ProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import { addableProviders } from "#/pages/AISettingsPage/ProvidersPage/components/addableProviderTypes";
|
||||
import { ProviderIcon } from "#/pages/AISettingsPage/ProvidersPage/components/ProviderIcon";
|
||||
import { ProviderRow } from "#/pages/AISettingsPage/ProvidersPage/components/ProviderRow";
|
||||
import { docs } from "#/utils/docs";
|
||||
|
||||
|
||||
+1
-1
@@ -18,9 +18,9 @@ import { DeleteDialog } from "#/components/Dialog/DeleteDialog/DeleteDialog";
|
||||
import { Loader } from "#/components/Loader/Loader";
|
||||
import { SettingsHeaderTitle } from "#/components/SettingsHeader/SettingsHeader";
|
||||
import { Switch } from "#/components/Switch/Switch";
|
||||
import { getProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import { pageTitle } from "#/utils/page";
|
||||
import { ProviderForm } from "../components/ProviderForm";
|
||||
import { getProviderIcon } from "../components/ProviderIcon";
|
||||
import {
|
||||
aiProviderToFormValues,
|
||||
bedrockExternalId,
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "#/components/Tooltip/Tooltip";
|
||||
import { useClickableTableRow } from "#/hooks/useClickableTableRow";
|
||||
import { ProviderIcon } from "./ProviderIcon";
|
||||
import { ProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import { getProviderDisplayType } from "./providerFormApiMap";
|
||||
|
||||
type ProviderRowProps = {
|
||||
|
||||
@@ -8,12 +8,12 @@ import type {
|
||||
CreateAIProviderRequest,
|
||||
UpdateAIProviderRequest,
|
||||
} from "#/api/typesGenerated";
|
||||
import { getProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import {
|
||||
type ProviderFormValues,
|
||||
parseBedrockRegionFromBaseUrl,
|
||||
SAVED_CREDENTIAL_MASK,
|
||||
} from "./ProviderForm";
|
||||
import { getProviderIcon } from "./ProviderIcon";
|
||||
|
||||
/** Drop placeholder masks so they don't round-trip back to the API. */
|
||||
const sanitizeCredential = (
|
||||
|
||||
@@ -15,6 +15,7 @@ import { reactRouterParameters } from "storybook-addon-remix-react-router";
|
||||
import { API } from "#/api/api";
|
||||
import type * as TypesGen from "#/api/typesGenerated";
|
||||
import type { ChatDiffStatus, ChatMessagePart } from "#/api/typesGenerated";
|
||||
import type { ModelSelectorOption } from "#/modules/aiModels/ModelSelector";
|
||||
import { AGENT_BROWSER_APP_SLUG } from "#/modules/apps/apps";
|
||||
import { MockChat } from "#/testHelpers/chatEntities";
|
||||
import {
|
||||
@@ -43,7 +44,6 @@ import {
|
||||
import type { ChatDetailError } from "./components/ChatConversation/chatError";
|
||||
import { createChatStore } from "./components/ChatConversation/chatStore";
|
||||
import { buildLongConversation } from "./components/ChatConversation/storyFixtures";
|
||||
import type { ModelSelectorOption } from "./components/ChatElements/ModelSelector";
|
||||
import { lastActiveSidebarTabStorageKeyPrefix } from "./utils/sidebarTabStorage";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -18,6 +18,7 @@ import type {
|
||||
import { ErrorAlert } from "#/components/Alert/ErrorAlert";
|
||||
import { useProxy } from "#/contexts/ProxyContext";
|
||||
import { useAuthenticated } from "#/hooks/useAuthenticated";
|
||||
import type { ModelSelectorOption } from "#/modules/aiModels/ModelSelector";
|
||||
import {
|
||||
getAgentBrowserApp,
|
||||
isWorkspaceAppEmbeddable,
|
||||
@@ -39,7 +40,6 @@ import type { ChatDetailError } from "./components/ChatConversation/chatError";
|
||||
import { getParentChatID } from "./components/ChatConversation/chatHelpers";
|
||||
import type { useChatStore } from "./components/ChatConversation/chatStore";
|
||||
import { QueuedForCapacityCallout } from "./components/ChatConversation/QueuedForCapacityCallout";
|
||||
import type { ModelSelectorOption } from "./components/ChatElements/ModelSelector";
|
||||
import { DesktopPanelContext } from "./components/ChatElements/tools/DesktopPanelContext";
|
||||
import type { SkillMetadata } from "./components/ChatMessageInput/SkillsTriggerMenu";
|
||||
import type { PendingAttachment } from "./components/ChatPageContent";
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { useState } from "react";
|
||||
import { expect, fn, screen, userEvent, waitFor, within } from "storybook/test";
|
||||
import type * as TypesGen from "#/api/typesGenerated";
|
||||
import type { ModelSelectorOption } from "#/modules/aiModels/ModelSelector";
|
||||
import { MockChatModel } from "#/testHelpers/chatModels";
|
||||
import {
|
||||
MockDefaultOrganization,
|
||||
@@ -11,7 +12,6 @@ import {
|
||||
AgentSettingsUserAgentsPageView,
|
||||
type AgentSettingsUserAgentsPageViewProps,
|
||||
} from "./AgentSettingsUserAgentsPageView";
|
||||
import type { ModelSelectorOption } from "./components/ChatElements/ModelSelector";
|
||||
|
||||
const UNAVAILABLE_WARNING =
|
||||
"The saved model is unavailable and will be ignored until you choose a valid model override.";
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
getOrganizationLabel,
|
||||
OrganizationAutocomplete,
|
||||
} from "#/components/OrganizationAutocomplete/OrganizationAutocomplete";
|
||||
import type { ModelSelectorOption } from "./components/ChatElements/ModelSelector";
|
||||
import type { ModelSelectorOption } from "#/modules/aiModels/ModelSelector";
|
||||
import {
|
||||
PersonalModelOverrideRow,
|
||||
type SavePersonalOverride,
|
||||
|
||||
@@ -58,6 +58,10 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "#/components/Tooltip/Tooltip";
|
||||
import {
|
||||
ModelSelector,
|
||||
type ModelSelectorOption,
|
||||
} from "#/modules/aiModels/ModelSelector";
|
||||
import { countInvisibleCharacters } from "#/utils/invisibleUnicode";
|
||||
import { isBelowMdViewport, isMobileViewport } from "#/utils/mobile";
|
||||
import { chatWidthClass, useChatFullWidth } from "../hooks/useChatFullWidth";
|
||||
@@ -79,10 +83,6 @@ import {
|
||||
isUploadInProgress,
|
||||
type UploadState,
|
||||
} from "./AttachmentPreview";
|
||||
import {
|
||||
ModelSelector,
|
||||
type ModelSelectorOption,
|
||||
} from "./ChatElements/ModelSelector";
|
||||
import {
|
||||
ChatMessageInput,
|
||||
type ChatMessageInputRef,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type * as TypesGen from "#/api/typesGenerated";
|
||||
import type { ModelSelectorOption } from "#/modules/aiModels/ModelSelector";
|
||||
import { MockChatMessage } from "#/testHelpers/chatEntities";
|
||||
import type { ModelSelectorOption } from "../ChatElements/ModelSelector";
|
||||
import {
|
||||
extractContextUsageFromMessage,
|
||||
getLatestContextUsage,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type * as TypesGen from "#/api/typesGenerated";
|
||||
import type { ModelSelectorOption } from "#/modules/aiModels/ModelSelector";
|
||||
import { findWorkspaceAgent } from "#/utils/workspace";
|
||||
import type { AgentContextUsage } from "../AgentChatInput";
|
||||
import type { ModelSelectorOption } from "../ChatElements/ModelSelector";
|
||||
import { asString } from "../ChatElements/runtimeTypeUtils";
|
||||
import { asNonEmptyString } from "./blockUtils";
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type React from "react";
|
||||
import { ScrollArea } from "#/components/ScrollArea/ScrollArea";
|
||||
import { ProviderIcon } from "#/pages/AISettingsPage/ProvidersPage/components/ProviderIcon";
|
||||
import { formatContextLimit } from "#/modules/aiModels/ModelSelector";
|
||||
import { ProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import { formatProviderLabel } from "#/utils/aiProviders";
|
||||
import { formatContextLimit } from "../ModelSelector";
|
||||
import { ToolCall } from "./ToolCall";
|
||||
import { asNumber, asRecord, asString, type ToolStatus } from "./utils";
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { cn } from "cn";
|
||||
import { Building2Icon } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
import { ExternalImage } from "#/components/ExternalImage/ExternalImage";
|
||||
import { normalizeProvider } from "#/modules/aiModels/helpers";
|
||||
import { getProviderIcon } from "#/pages/AISettingsPage/ProvidersPage/components/ProviderIcon";
|
||||
|
||||
interface ProviderIconProps {
|
||||
provider: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const ProviderIcon: FC<ProviderIconProps> = ({
|
||||
provider,
|
||||
className,
|
||||
}) => {
|
||||
const iconPath = getProviderIcon(normalizeProvider(provider));
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex shrink-0 items-center justify-center rounded-full bg-surface-secondary",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{iconPath ? (
|
||||
<ExternalImage src={iconPath} alt="" className="size-3/5" />
|
||||
) : (
|
||||
<Building2Icon className="size-3/5 text-content-secondary" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -6,6 +6,7 @@ import type { UrlTransform } from "streamdown";
|
||||
import { chatPromptsQuery, refreshChatContext } from "#/api/queries/chats";
|
||||
import type * as TypesGen from "#/api/typesGenerated";
|
||||
import type { AgentChatSendShortcut } from "#/api/typesGenerated";
|
||||
import type { ModelSelectorOption } from "#/modules/aiModels/ModelSelector";
|
||||
import { useChatDraftAttachments } from "../hooks/useChatDraftAttachments";
|
||||
import { chatWidthClass, useChatFullWidth } from "../hooks/useChatFullWidth";
|
||||
import { useFileAttachments } from "../hooks/useFileAttachments";
|
||||
@@ -49,7 +50,6 @@ import {
|
||||
} from "./ChatConversation/messageParsing";
|
||||
import { buildStreamTools } from "./ChatConversation/streamState";
|
||||
import { useOnRenderProfiler } from "./ChatConversation/useOnRenderProfiler";
|
||||
import type { ModelSelectorOption } from "./ChatElements/ModelSelector";
|
||||
import type { SkillMetadata } from "./ChatMessageInput/SkillsTriggerMenu";
|
||||
import { ChatMessageScroller } from "./ChatMessageScroller";
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ import type { FC } from "react";
|
||||
import type * as TypesGen from "#/api/typesGenerated";
|
||||
import { Alert, AlertDescription } from "#/components/Alert/Alert";
|
||||
import { Button } from "#/components/Button/Button";
|
||||
import { pickReasoningEffort } from "../utils/reasoningEffort";
|
||||
import {
|
||||
ModelSelector,
|
||||
type ModelSelectorOption,
|
||||
} from "./ChatElements/ModelSelector";
|
||||
} from "#/modules/aiModels/ModelSelector";
|
||||
import { pickReasoningEffort } from "../utils/reasoningEffort";
|
||||
import { ModelOverrideAlerts } from "./ModelOverrideAlerts";
|
||||
import { SectionHeader } from "./SectionHeader";
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "#/components/Tooltip/Tooltip";
|
||||
import { ProviderIcon } from "#/modules/aiModels/ProviderIcon";
|
||||
import { formatProviderLabel } from "#/utils/aiProviders";
|
||||
import { ProviderIcon } from "./ChatModelAdminPanel/ProviderIcon";
|
||||
|
||||
interface UserCompactionThresholdSettingsProps {
|
||||
models: readonly TypesGen.ChatModel[];
|
||||
@@ -371,7 +371,12 @@ export const UserCompactionThresholdSettings: FC<
|
||||
className="w-fit"
|
||||
aria-label={`${providerLabel} ${modelName} in ${organizationName}`}
|
||||
>
|
||||
<ProviderIcon provider={provider} className="size-4" />
|
||||
<span className="flex size-4 shrink-0 items-center justify-center rounded-full bg-surface-secondary">
|
||||
<ProviderIcon
|
||||
provider={provider}
|
||||
className="size-3/5 text-content-secondary"
|
||||
/>
|
||||
</span>
|
||||
{modelName}
|
||||
</Badge>
|
||||
{rowError && (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type * as TypesGen from "#/api/typesGenerated";
|
||||
import { normalizeProvider } from "#/modules/aiModels/helpers";
|
||||
import type { ModelSelectorOption } from "../components/ChatElements/ModelSelector";
|
||||
import type { ModelSelectorOption } from "#/modules/aiModels/ModelSelector";
|
||||
import {
|
||||
asNumber,
|
||||
asString,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { formatReasoningEffort } from "#/modules/aiModels/helpers";
|
||||
import {
|
||||
formatReasoningEffort,
|
||||
getReasoningEffortForModel,
|
||||
pickReasoningEffort,
|
||||
saveReasoningEffortForModel,
|
||||
|
||||
@@ -28,10 +28,6 @@ export const saveReasoningEffortForModel = (
|
||||
}
|
||||
};
|
||||
|
||||
/** Display label for an effort value, e.g. "xhigh" renders as "Xhigh". */
|
||||
export const formatReasoningEffort = (value: string): string =>
|
||||
value.charAt(0).toUpperCase() + value.slice(1);
|
||||
|
||||
/** Chooses requested effort, then default effort, then the last selectable effort. */
|
||||
export const pickReasoningEffort = (
|
||||
value: string | undefined,
|
||||
|
||||
@@ -20,6 +20,7 @@ compilerPreset.rolldown.filter = {
|
||||
id: {
|
||||
// Keep in sync with targetDirs in scripts/check-compiler.mjs.
|
||||
include: [
|
||||
/src\/modules\/aiModels\//,
|
||||
/src\/pages\/AgentsPage\//,
|
||||
/src\/pages\/AIBridgePage\//,
|
||||
/src\/pages\/TemplateBuilder\//,
|
||||
|
||||
Reference in New Issue
Block a user