@molecule/app-ide-react 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +115 -0
- package/dist/chatTimelineOrdering.d.ts +50 -0
- package/dist/chatTimelineOrdering.d.ts.map +1 -0
- package/dist/chatTimelineOrdering.js +46 -0
- package/dist/chatTimelineOrdering.js.map +1 -0
- package/dist/command-metadata.d.ts +78 -0
- package/dist/command-metadata.d.ts.map +1 -0
- package/dist/command-metadata.js +214 -0
- package/dist/command-metadata.js.map +1 -0
- package/dist/components/ActivityCard.d.ts +28 -0
- package/dist/components/ActivityCard.d.ts.map +1 -0
- package/dist/components/ActivityCard.js +62 -0
- package/dist/components/ActivityCard.js.map +1 -0
- package/dist/components/AutoCommitBadge.d.ts +58 -0
- package/dist/components/AutoCommitBadge.d.ts.map +1 -0
- package/dist/components/AutoCommitBadge.js +78 -0
- package/dist/components/AutoCommitBadge.js.map +1 -0
- package/dist/components/ChatPanel.d.ts +184 -0
- package/dist/components/ChatPanel.d.ts.map +1 -0
- package/dist/components/ChatPanel.js +6691 -0
- package/dist/components/ChatPanel.js.map +1 -0
- package/dist/components/CommandPalette.d.ts +18 -0
- package/dist/components/CommandPalette.d.ts.map +1 -0
- package/dist/components/CommandPalette.js +33 -0
- package/dist/components/CommandPalette.js.map +1 -0
- package/dist/components/DeviceFrameSelector.d.ts +60 -0
- package/dist/components/DeviceFrameSelector.d.ts.map +1 -0
- package/dist/components/DeviceFrameSelector.js +230 -0
- package/dist/components/DeviceFrameSelector.js.map +1 -0
- package/dist/components/EditorPanel.d.ts +17 -0
- package/dist/components/EditorPanel.d.ts.map +1 -0
- package/dist/components/EditorPanel.js +241 -0
- package/dist/components/EditorPanel.js.map +1 -0
- package/dist/components/FileExplorer.d.ts +64 -0
- package/dist/components/FileExplorer.d.ts.map +1 -0
- package/dist/components/FileExplorer.js +1111 -0
- package/dist/components/FileExplorer.js.map +1 -0
- package/dist/components/FileExplorerContextMenu.d.ts +37 -0
- package/dist/components/FileExplorerContextMenu.d.ts.map +1 -0
- package/dist/components/FileExplorerContextMenu.js +241 -0
- package/dist/components/FileExplorerContextMenu.js.map +1 -0
- package/dist/components/HelpCard.d.ts +34 -0
- package/dist/components/HelpCard.d.ts.map +1 -0
- package/dist/components/HelpCard.js +28 -0
- package/dist/components/HelpCard.js.map +1 -0
- package/dist/components/Icon.d.ts +50 -0
- package/dist/components/Icon.d.ts.map +1 -0
- package/dist/components/Icon.js +25 -0
- package/dist/components/Icon.js.map +1 -0
- package/dist/components/KeyboardShortcutsPanel.d.ts +19 -0
- package/dist/components/KeyboardShortcutsPanel.d.ts.map +1 -0
- package/dist/components/KeyboardShortcutsPanel.js +187 -0
- package/dist/components/KeyboardShortcutsPanel.js.map +1 -0
- package/dist/components/MarkdownContent.d.ts +52 -0
- package/dist/components/MarkdownContent.d.ts.map +1 -0
- package/dist/components/MarkdownContent.js +303 -0
- package/dist/components/MarkdownContent.js.map +1 -0
- package/dist/components/ModelsTable.d.ts +38 -0
- package/dist/components/ModelsTable.d.ts.map +1 -0
- package/dist/components/ModelsTable.js +96 -0
- package/dist/components/ModelsTable.js.map +1 -0
- package/dist/components/PreviewPanel.d.ts +66 -0
- package/dist/components/PreviewPanel.d.ts.map +1 -0
- package/dist/components/PreviewPanel.js +1752 -0
- package/dist/components/PreviewPanel.js.map +1 -0
- package/dist/components/QuickOpen.d.ts +20 -0
- package/dist/components/QuickOpen.d.ts.map +1 -0
- package/dist/components/QuickOpen.js +72 -0
- package/dist/components/QuickOpen.js.map +1 -0
- package/dist/components/QuickPicker.d.ts +21 -0
- package/dist/components/QuickPicker.d.ts.map +1 -0
- package/dist/components/QuickPicker.js +174 -0
- package/dist/components/QuickPicker.js.map +1 -0
- package/dist/components/RelevantSkillSuggestion.d.ts +41 -0
- package/dist/components/RelevantSkillSuggestion.d.ts.map +1 -0
- package/dist/components/RelevantSkillSuggestion.js +85 -0
- package/dist/components/RelevantSkillSuggestion.js.map +1 -0
- package/dist/components/ReportModal.d.ts +35 -0
- package/dist/components/ReportModal.d.ts.map +1 -0
- package/dist/components/ReportModal.js +112 -0
- package/dist/components/ReportModal.js.map +1 -0
- package/dist/components/ResizeHandle.d.ts +21 -0
- package/dist/components/ResizeHandle.d.ts.map +1 -0
- package/dist/components/ResizeHandle.js +109 -0
- package/dist/components/ResizeHandle.js.map +1 -0
- package/dist/components/ScriptsCard.d.ts +37 -0
- package/dist/components/ScriptsCard.d.ts.map +1 -0
- package/dist/components/ScriptsCard.js +177 -0
- package/dist/components/ScriptsCard.js.map +1 -0
- package/dist/components/SearchPanel.d.ts +18 -0
- package/dist/components/SearchPanel.d.ts.map +1 -0
- package/dist/components/SearchPanel.js +449 -0
- package/dist/components/SearchPanel.js.map +1 -0
- package/dist/components/SettingsCard.d.ts +49 -0
- package/dist/components/SettingsCard.d.ts.map +1 -0
- package/dist/components/SettingsCard.js +59 -0
- package/dist/components/SettingsCard.js.map +1 -0
- package/dist/components/ShareModal.d.ts +32 -0
- package/dist/components/ShareModal.d.ts.map +1 -0
- package/dist/components/ShareModal.js +126 -0
- package/dist/components/ShareModal.js.map +1 -0
- package/dist/components/SidebarTabs.d.ts +18 -0
- package/dist/components/SidebarTabs.d.ts.map +1 -0
- package/dist/components/SidebarTabs.js +20 -0
- package/dist/components/SidebarTabs.js.map +1 -0
- package/dist/components/SkillsCard.d.ts +86 -0
- package/dist/components/SkillsCard.d.ts.map +1 -0
- package/dist/components/SkillsCard.js +227 -0
- package/dist/components/SkillsCard.js.map +1 -0
- package/dist/components/StreamingIndicator.d.ts +50 -0
- package/dist/components/StreamingIndicator.d.ts.map +1 -0
- package/dist/components/StreamingIndicator.js +142 -0
- package/dist/components/StreamingIndicator.js.map +1 -0
- package/dist/components/TabBar.d.ts +37 -0
- package/dist/components/TabBar.d.ts.map +1 -0
- package/dist/components/TabBar.js +187 -0
- package/dist/components/TabBar.js.map +1 -0
- package/dist/components/TipCard.d.ts +22 -0
- package/dist/components/TipCard.d.ts.map +1 -0
- package/dist/components/TipCard.js +73 -0
- package/dist/components/TipCard.js.map +1 -0
- package/dist/components/ToolCallCard.d.ts +18 -0
- package/dist/components/ToolCallCard.d.ts.map +1 -0
- package/dist/components/ToolCallCard.js +716 -0
- package/dist/components/ToolCallCard.js.map +1 -0
- package/dist/components/UserAvatar.d.ts +45 -0
- package/dist/components/UserAvatar.d.ts.map +1 -0
- package/dist/components/UserAvatar.js +80 -0
- package/dist/components/UserAvatar.js.map +1 -0
- package/dist/components/WorkspaceLayout.d.ts +19 -0
- package/dist/components/WorkspaceLayout.d.ts.map +1 -0
- package/dist/components/WorkspaceLayout.js +56 -0
- package/dist/components/WorkspaceLayout.js.map +1 -0
- package/dist/components/activity-utilities.d.ts +107 -0
- package/dist/components/activity-utilities.d.ts.map +1 -0
- package/dist/components/activity-utilities.js +154 -0
- package/dist/components/activity-utilities.js.map +1 -0
- package/dist/components/chat-autocommit-utilities.d.ts +172 -0
- package/dist/components/chat-autocommit-utilities.d.ts.map +1 -0
- package/dist/components/chat-autocommit-utilities.js +185 -0
- package/dist/components/chat-autocommit-utilities.js.map +1 -0
- package/dist/components/chat-card-style.d.ts +64 -0
- package/dist/components/chat-card-style.d.ts.map +1 -0
- package/dist/components/chat-card-style.js +74 -0
- package/dist/components/chat-card-style.js.map +1 -0
- package/dist/components/chat-commands.d.ts +17 -0
- package/dist/components/chat-commands.d.ts.map +1 -0
- package/dist/components/chat-commands.js +17 -0
- package/dist/components/chat-commands.js.map +1 -0
- package/dist/components/chat-commit-utilities.d.ts +29 -0
- package/dist/components/chat-commit-utilities.d.ts.map +1 -0
- package/dist/components/chat-commit-utilities.js +31 -0
- package/dist/components/chat-commit-utilities.js.map +1 -0
- package/dist/components/chat-cost-utilities.d.ts +62 -0
- package/dist/components/chat-cost-utilities.d.ts.map +1 -0
- package/dist/components/chat-cost-utilities.js +66 -0
- package/dist/components/chat-cost-utilities.js.map +1 -0
- package/dist/components/chat-effort-utilities.d.ts +96 -0
- package/dist/components/chat-effort-utilities.d.ts.map +1 -0
- package/dist/components/chat-effort-utilities.js +97 -0
- package/dist/components/chat-effort-utilities.js.map +1 -0
- package/dist/components/chat-help-utilities.d.ts +89 -0
- package/dist/components/chat-help-utilities.d.ts.map +1 -0
- package/dist/components/chat-help-utilities.js +131 -0
- package/dist/components/chat-help-utilities.js.map +1 -0
- package/dist/components/chat-model-mode-utilities.d.ts +143 -0
- package/dist/components/chat-model-mode-utilities.d.ts.map +1 -0
- package/dist/components/chat-model-mode-utilities.js +191 -0
- package/dist/components/chat-model-mode-utilities.js.map +1 -0
- package/dist/components/chat-models-utilities.d.ts +98 -0
- package/dist/components/chat-models-utilities.d.ts.map +1 -0
- package/dist/components/chat-models-utilities.js +136 -0
- package/dist/components/chat-models-utilities.js.map +1 -0
- package/dist/components/chat-report-utilities.d.ts +149 -0
- package/dist/components/chat-report-utilities.d.ts.map +1 -0
- package/dist/components/chat-report-utilities.js +151 -0
- package/dist/components/chat-report-utilities.js.map +1 -0
- package/dist/components/chat-scripts-utilities.d.ts +140 -0
- package/dist/components/chat-scripts-utilities.d.ts.map +1 -0
- package/dist/components/chat-scripts-utilities.js +158 -0
- package/dist/components/chat-scripts-utilities.js.map +1 -0
- package/dist/components/chat-settings-utilities.d.ts +72 -0
- package/dist/components/chat-settings-utilities.d.ts.map +1 -0
- package/dist/components/chat-settings-utilities.js +56 -0
- package/dist/components/chat-settings-utilities.js.map +1 -0
- package/dist/components/chat-share-utilities.d.ts +104 -0
- package/dist/components/chat-share-utilities.d.ts.map +1 -0
- package/dist/components/chat-share-utilities.js +90 -0
- package/dist/components/chat-share-utilities.js.map +1 -0
- package/dist/components/chat-skills-utilities.d.ts +242 -0
- package/dist/components/chat-skills-utilities.d.ts.map +1 -0
- package/dist/components/chat-skills-utilities.js +433 -0
- package/dist/components/chat-skills-utilities.js.map +1 -0
- package/dist/components/chat-stream-utilities.d.ts +74 -0
- package/dist/components/chat-stream-utilities.d.ts.map +1 -0
- package/dist/components/chat-stream-utilities.js +103 -0
- package/dist/components/chat-stream-utilities.js.map +1 -0
- package/dist/components/chat-tips-utilities.d.ts +108 -0
- package/dist/components/chat-tips-utilities.d.ts.map +1 -0
- package/dist/components/chat-tips-utilities.js +137 -0
- package/dist/components/chat-tips-utilities.js.map +1 -0
- package/dist/components/device-cycle.d.ts +84 -0
- package/dist/components/device-cycle.d.ts.map +1 -0
- package/dist/components/device-cycle.js +77 -0
- package/dist/components/device-cycle.js.map +1 -0
- package/dist/components/index.d.ts +36 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +33 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/tool-call-utilities.d.ts +69 -0
- package/dist/components/tool-call-utilities.d.ts.map +1 -0
- package/dist/components/tool-call-utilities.js +368 -0
- package/dist/components/tool-call-utilities.js.map +1 -0
- package/dist/components/user-avatar-utilities.d.ts +41 -0
- package/dist/components/user-avatar-utilities.d.ts.map +1 -0
- package/dist/components/user-avatar-utilities.js +56 -0
- package/dist/components/user-avatar-utilities.js.map +1 -0
- package/dist/components/workspace-layout-utilities.d.ts +37 -0
- package/dist/components/workspace-layout-utilities.d.ts.map +1 -0
- package/dist/components/workspace-layout-utilities.js +58 -0
- package/dist/components/workspace-layout-utilities.js.map +1 -0
- package/dist/customEventCards.d.ts +117 -0
- package/dist/customEventCards.d.ts.map +1 -0
- package/dist/customEventCards.js +36 -0
- package/dist/customEventCards.js.map +1 -0
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +8 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useKeyboardShortcuts.d.ts +48 -0
- package/dist/hooks/useKeyboardShortcuts.d.ts.map +1 -0
- package/dist/hooks/useKeyboardShortcuts.js +112 -0
- package/dist/hooks/useKeyboardShortcuts.js.map +1 -0
- package/dist/hooks/useViewport.d.ts +42 -0
- package/dist/hooks/useViewport.d.ts.map +1 -0
- package/dist/hooks/useViewport.js +61 -0
- package/dist/hooks/useViewport.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/settings-metadata.d.ts +78 -0
- package/dist/settings-metadata.d.ts.map +1 -0
- package/dist/settings-metadata.js +131 -0
- package/dist/settings-metadata.js.map +1 -0
- package/dist/types.d.ts +751 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +25 -0
- package/dist/types.js.map +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers backing the per-mode model pickers (`/model --plan`,
|
|
3
|
+
* `/model --execute`, `/model --commit`, and `/model --compact`).
|
|
4
|
+
*
|
|
5
|
+
* A project stores optional per-mode model ids in its settings — `planModel`
|
|
6
|
+
* (used in plan mode) and `executeModel` (used in execute mode) alongside the
|
|
7
|
+
* legacy single `chatModel`, plus two auxiliary jobs: `commitModel` (the
|
|
8
|
+
* commit-message generator) and `compactModel` (conversation compaction), which
|
|
9
|
+
* fall back to the server's own fast default (never `chatModel`) when unset.
|
|
10
|
+
* These helpers parse the mode flag, map a mode to its settings field, resolve
|
|
11
|
+
* the effective model for a mode, and compute the free-tier clamp (plan →
|
|
12
|
+
* `deepseek-v4-pro`, execute → `deepseek-v4-flash`, commit/compact → any
|
|
13
|
+
* free-tier-flagged model) against the live catalog. The clamp ids mirror the
|
|
14
|
+
* server's FREE_TIER_MODELS in molecule-dev's `model-selection.ts` — keep the
|
|
15
|
+
* two in sync (a stale Sonnet-plan assumption here once highlighted the wrong
|
|
16
|
+
* "current" model in the picker).
|
|
17
|
+
*
|
|
18
|
+
* Everything here is deterministic and side-effect free so it can be unit tested
|
|
19
|
+
* without rendering or a backend. The component owns persistence (`PATCH
|
|
20
|
+
* /projects/:id { settings }`) and any `t()` prose.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
import type { AppModelDefinition } from '@molecule/app-ai-models';
|
|
25
|
+
/** A conversation mode or auxiliary job that can have its own model. */
|
|
26
|
+
export type ModelMode = 'plan' | 'execute' | 'commit' | 'compact';
|
|
27
|
+
/** The subset of project settings this module reads for model resolution. */
|
|
28
|
+
export interface PerModeModelSettings {
|
|
29
|
+
/** Model id used in plan mode (falls back to {@link PerModeModelSettings.chatModel}). */
|
|
30
|
+
planModel?: string;
|
|
31
|
+
/** Model id used in execute mode (falls back to {@link PerModeModelSettings.chatModel}). */
|
|
32
|
+
executeModel?: string;
|
|
33
|
+
/** Model id for commit-message generation (server's fast default when unset). */
|
|
34
|
+
commitModel?: string;
|
|
35
|
+
/** Model id for conversation compaction (server's fast default when unset). */
|
|
36
|
+
compactModel?: string;
|
|
37
|
+
/** Legacy single model id, used when the plan/execute field is unset. */
|
|
38
|
+
chatModel?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parses a `/model --plan`, `--execute`, `--commit`, or `--compact` command.
|
|
42
|
+
* Returns the targeted mode plus any trailing filter `query` (the text after
|
|
43
|
+
* the flag), or `null` when the input is not a mode-scoped `/model` command.
|
|
44
|
+
* Use this *before* the generic `/model <name>` handler so the flag is not
|
|
45
|
+
* mistaken for a model name.
|
|
46
|
+
*
|
|
47
|
+
* @param input - The raw chat input.
|
|
48
|
+
* @returns `{ mode, query }` for a mode-scoped command, else `null`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseModelModeCommand(input: string): {
|
|
51
|
+
mode: ModelMode;
|
|
52
|
+
query: string;
|
|
53
|
+
} | null;
|
|
54
|
+
/**
|
|
55
|
+
* Maps a mode to the project-settings field that stores its model id.
|
|
56
|
+
*
|
|
57
|
+
* @param mode - The conversation mode or auxiliary job.
|
|
58
|
+
* @returns The settings field for the mode (e.g. `'planModel'` for plan mode).
|
|
59
|
+
*/
|
|
60
|
+
export declare function modeSettingKey(mode: ModelMode): 'planModel' | 'executeModel' | 'commitModel' | 'compactModel';
|
|
61
|
+
/**
|
|
62
|
+
* Resolves the effective model id for a mode. The conversation modes
|
|
63
|
+
* (plan/execute) fall back to the legacy single `chatModel` when the per-mode
|
|
64
|
+
* field is unset (back-compat); the auxiliary jobs (commit/compact) do NOT —
|
|
65
|
+
* the server applies its own fast default for them, mirrored here by returning
|
|
66
|
+
* `undefined`.
|
|
67
|
+
*
|
|
68
|
+
* @param settings - The project's model settings.
|
|
69
|
+
* @param mode - The conversation mode or auxiliary job.
|
|
70
|
+
* @returns The resolved model id, or `undefined` when nothing is configured.
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveModeModel(settings: PerModeModelSettings, mode: ModelMode): string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Computes the free-tier-allowed model id for a mode from the live catalog. The
|
|
75
|
+
* free/anon tier is clamped — with no mixing — to `deepseek-v4-pro` in plan
|
|
76
|
+
* mode and `deepseek-v4-flash` in execute mode (the auxiliary commit/compact
|
|
77
|
+
* jobs share the execute clamp), mirroring the server's FREE_TIER_MODELS.
|
|
78
|
+
* Matching is catalog-driven (by id/provider) so it survives id churn; when no
|
|
79
|
+
* specific match exists it falls back to the supplied `fallback` (the
|
|
80
|
+
* catalog's free-tier model id).
|
|
81
|
+
*
|
|
82
|
+
* @param models - The available models from the catalog.
|
|
83
|
+
* @param mode - The conversation mode or auxiliary job.
|
|
84
|
+
* @param fallback - The free-tier model id to use when no match is found.
|
|
85
|
+
* @returns The clamped model id for the mode.
|
|
86
|
+
*/
|
|
87
|
+
export declare function freeTierModeModelId(models: readonly AppModelDefinition[], mode: ModelMode, fallback: string): string;
|
|
88
|
+
/**
|
|
89
|
+
* Why a model is locked for a free-tier user in a given mode — `'paid'` for a
|
|
90
|
+
* genuinely paid model, `'mode'` for a model the free tier CAN use, just in a
|
|
91
|
+
* different mode (e.g. the execute clamp shown in the plan-scoped picker).
|
|
92
|
+
*/
|
|
93
|
+
export type FreeTierLockReason = 'paid' | 'mode';
|
|
94
|
+
/**
|
|
95
|
+
* The lock reason for a model in a mode under the free-tier clamp, or `null`
|
|
96
|
+
* when it is selectable. Pro users and `provider: 'custom'` (bring-your-own
|
|
97
|
+
* AI) models are never locked; a free/anon user may pick only the mode's
|
|
98
|
+
* clamped model (plan/execute) or any free-tier-flagged model (the auxiliary
|
|
99
|
+
* commit/compact jobs, mirroring the server's aux-model selection, which
|
|
100
|
+
* ignores a non-free platform pick anyway).
|
|
101
|
+
*
|
|
102
|
+
* A locked model splits into two very different cases the UI must not
|
|
103
|
+
* conflate: `'paid'` (upgrade actually unlocks it) versus `'mode'` (the model
|
|
104
|
+
* is free-tier-usable in ANOTHER mode — it is a different mode's clamp, or
|
|
105
|
+
* free-tier-flagged and thus selectable for commit/compact — so a "Pro" badge
|
|
106
|
+
* would be flatly wrong).
|
|
107
|
+
*
|
|
108
|
+
* @param modelId - The candidate model id.
|
|
109
|
+
* @param mode - The conversation mode the picker is scoped to.
|
|
110
|
+
* @param isFreeTier - Whether the current user is on the free/anon tier.
|
|
111
|
+
* @param models - The available models from the catalog.
|
|
112
|
+
* @param fallback - The free-tier model id to use when no clamp match is found.
|
|
113
|
+
* @returns `'paid'` / `'mode'` when locked, `null` when selectable.
|
|
114
|
+
*/
|
|
115
|
+
export declare function freeTierLockReason(modelId: string, mode: ModelMode, isFreeTier: boolean, models: readonly AppModelDefinition[], fallback: string): FreeTierLockReason | null;
|
|
116
|
+
/**
|
|
117
|
+
* The mode a free-tier user can actually use this model in — `'plan'` /
|
|
118
|
+
* `'execute'` when it is that mode's clamp, `'commit'` (standing for both
|
|
119
|
+
* auxiliary jobs) when it is merely free-tier-flagged, `null` when the free
|
|
120
|
+
* tier can't use it anywhere. Drives the "free in <mode>" labeling next to a
|
|
121
|
+
* `'mode'`-locked row.
|
|
122
|
+
*
|
|
123
|
+
* @param modelId - The candidate model id.
|
|
124
|
+
* @param models - The available models from the catalog.
|
|
125
|
+
* @param fallback - The free-tier model id to use when no clamp match is found.
|
|
126
|
+
* @returns The mode the model is free-tier-usable in, or `null`.
|
|
127
|
+
*/
|
|
128
|
+
export declare function freeTierUsableMode(modelId: string, models: readonly AppModelDefinition[], fallback: string): ModelMode | null;
|
|
129
|
+
/**
|
|
130
|
+
* Whether a model is locked (not selectable) for the given mode under the
|
|
131
|
+
* free-tier clamp — the boolean view of {@link freeTierLockReason} (which see
|
|
132
|
+
* for the rules: pro users and custom models never lock; plan/execute clamp to
|
|
133
|
+
* one model; commit/compact accept any free-tier-flagged model).
|
|
134
|
+
*
|
|
135
|
+
* @param modelId - The candidate model id.
|
|
136
|
+
* @param mode - The conversation mode the picker is scoped to.
|
|
137
|
+
* @param isFreeTier - Whether the current user is on the free/anon tier.
|
|
138
|
+
* @param models - The available models from the catalog.
|
|
139
|
+
* @param fallback - The free-tier model id to use when no clamp match is found.
|
|
140
|
+
* @returns `true` when the model is locked for this user and mode.
|
|
141
|
+
*/
|
|
142
|
+
export declare function isModeModelLocked(modelId: string, mode: ModelMode, isFreeTier: boolean, models: readonly AppModelDefinition[], fallback: string): boolean;
|
|
143
|
+
//# sourceMappingURL=chat-model-mode-utilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-model-mode-utilities.d.ts","sourceRoot":"","sources":["../../src/components/chat-model-mode-utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,wEAAwE;AACxE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAA;AAEjE,6EAA6E;AAC7E,MAAM,WAAW,oBAAoB;IACnC,yFAAyF;IACzF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAI9F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,GACd,WAAW,GAAG,cAAc,GAAG,aAAa,GAAG,cAAc,CAW/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,oBAAoB,EAC9B,IAAI,EAAE,SAAS,GACd,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,MAAM,GACf,MAAM,CAgBR;AAED;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,CAAA;AAKhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,kBAAkB,GAAG,IAAI,CAe3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,SAAS,GAAG,IAAI,CAKlB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAET"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers backing the per-mode model pickers (`/model --plan`,
|
|
3
|
+
* `/model --execute`, `/model --commit`, and `/model --compact`).
|
|
4
|
+
*
|
|
5
|
+
* A project stores optional per-mode model ids in its settings — `planModel`
|
|
6
|
+
* (used in plan mode) and `executeModel` (used in execute mode) alongside the
|
|
7
|
+
* legacy single `chatModel`, plus two auxiliary jobs: `commitModel` (the
|
|
8
|
+
* commit-message generator) and `compactModel` (conversation compaction), which
|
|
9
|
+
* fall back to the server's own fast default (never `chatModel`) when unset.
|
|
10
|
+
* These helpers parse the mode flag, map a mode to its settings field, resolve
|
|
11
|
+
* the effective model for a mode, and compute the free-tier clamp (plan →
|
|
12
|
+
* `deepseek-v4-pro`, execute → `deepseek-v4-flash`, commit/compact → any
|
|
13
|
+
* free-tier-flagged model) against the live catalog. The clamp ids mirror the
|
|
14
|
+
* server's FREE_TIER_MODELS in molecule-dev's `model-selection.ts` — keep the
|
|
15
|
+
* two in sync (a stale Sonnet-plan assumption here once highlighted the wrong
|
|
16
|
+
* "current" model in the picker).
|
|
17
|
+
*
|
|
18
|
+
* Everything here is deterministic and side-effect free so it can be unit tested
|
|
19
|
+
* without rendering or a backend. The component owns persistence (`PATCH
|
|
20
|
+
* /projects/:id { settings }`) and any `t()` prose.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Parses a `/model --plan`, `--execute`, `--commit`, or `--compact` command.
|
|
26
|
+
* Returns the targeted mode plus any trailing filter `query` (the text after
|
|
27
|
+
* the flag), or `null` when the input is not a mode-scoped `/model` command.
|
|
28
|
+
* Use this *before* the generic `/model <name>` handler so the flag is not
|
|
29
|
+
* mistaken for a model name.
|
|
30
|
+
*
|
|
31
|
+
* @param input - The raw chat input.
|
|
32
|
+
* @returns `{ mode, query }` for a mode-scoped command, else `null`.
|
|
33
|
+
*/
|
|
34
|
+
export function parseModelModeCommand(input) {
|
|
35
|
+
const match = input.trim().match(/^\/model\s+--(plan|execute|commit|compact)\b\s*(.*)$/i);
|
|
36
|
+
if (!match)
|
|
37
|
+
return null;
|
|
38
|
+
return { mode: match[1].toLowerCase(), query: match[2].trim() };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Maps a mode to the project-settings field that stores its model id.
|
|
42
|
+
*
|
|
43
|
+
* @param mode - The conversation mode or auxiliary job.
|
|
44
|
+
* @returns The settings field for the mode (e.g. `'planModel'` for plan mode).
|
|
45
|
+
*/
|
|
46
|
+
export function modeSettingKey(mode) {
|
|
47
|
+
switch (mode) {
|
|
48
|
+
case 'plan':
|
|
49
|
+
return 'planModel';
|
|
50
|
+
case 'execute':
|
|
51
|
+
return 'executeModel';
|
|
52
|
+
case 'commit':
|
|
53
|
+
return 'commitModel';
|
|
54
|
+
case 'compact':
|
|
55
|
+
return 'compactModel';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolves the effective model id for a mode. The conversation modes
|
|
60
|
+
* (plan/execute) fall back to the legacy single `chatModel` when the per-mode
|
|
61
|
+
* field is unset (back-compat); the auxiliary jobs (commit/compact) do NOT —
|
|
62
|
+
* the server applies its own fast default for them, mirrored here by returning
|
|
63
|
+
* `undefined`.
|
|
64
|
+
*
|
|
65
|
+
* @param settings - The project's model settings.
|
|
66
|
+
* @param mode - The conversation mode or auxiliary job.
|
|
67
|
+
* @returns The resolved model id, or `undefined` when nothing is configured.
|
|
68
|
+
*/
|
|
69
|
+
export function resolveModeModel(settings, mode) {
|
|
70
|
+
switch (mode) {
|
|
71
|
+
case 'plan':
|
|
72
|
+
return settings.planModel ?? settings.chatModel;
|
|
73
|
+
case 'execute':
|
|
74
|
+
return settings.executeModel ?? settings.chatModel;
|
|
75
|
+
case 'commit':
|
|
76
|
+
return settings.commitModel;
|
|
77
|
+
case 'compact':
|
|
78
|
+
return settings.compactModel;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Computes the free-tier-allowed model id for a mode from the live catalog. The
|
|
83
|
+
* free/anon tier is clamped — with no mixing — to `deepseek-v4-pro` in plan
|
|
84
|
+
* mode and `deepseek-v4-flash` in execute mode (the auxiliary commit/compact
|
|
85
|
+
* jobs share the execute clamp), mirroring the server's FREE_TIER_MODELS.
|
|
86
|
+
* Matching is catalog-driven (by id/provider) so it survives id churn; when no
|
|
87
|
+
* specific match exists it falls back to the supplied `fallback` (the
|
|
88
|
+
* catalog's free-tier model id).
|
|
89
|
+
*
|
|
90
|
+
* @param models - The available models from the catalog.
|
|
91
|
+
* @param mode - The conversation mode or auxiliary job.
|
|
92
|
+
* @param fallback - The free-tier model id to use when no match is found.
|
|
93
|
+
* @returns The clamped model id for the mode.
|
|
94
|
+
*/
|
|
95
|
+
export function freeTierModeModelId(models, mode, fallback) {
|
|
96
|
+
if (mode === 'plan') {
|
|
97
|
+
const exact = models.find((m) => m.id === 'deepseek-v4-pro');
|
|
98
|
+
if (exact)
|
|
99
|
+
return exact.id;
|
|
100
|
+
const deepseekPro = models.find((m) => m.provider === 'deepseek' && /pro/i.test(m.id));
|
|
101
|
+
if (deepseekPro)
|
|
102
|
+
return deepseekPro.id;
|
|
103
|
+
const anyDeepseek = models.find((m) => m.provider === 'deepseek');
|
|
104
|
+
return anyDeepseek?.id ?? fallback;
|
|
105
|
+
}
|
|
106
|
+
// execute (and the commit/compact auxiliary jobs, which share its clamp)
|
|
107
|
+
const exact = models.find((m) => m.id === 'deepseek-v4-flash');
|
|
108
|
+
if (exact)
|
|
109
|
+
return exact.id;
|
|
110
|
+
const deepseekFlash = models.find((m) => m.provider === 'deepseek' && /flash/i.test(m.id));
|
|
111
|
+
if (deepseekFlash)
|
|
112
|
+
return deepseekFlash.id;
|
|
113
|
+
const anyDeepseek = models.find((m) => m.provider === 'deepseek');
|
|
114
|
+
return anyDeepseek?.id ?? fallback;
|
|
115
|
+
}
|
|
116
|
+
/** Every mode a per-mode clamp exists for — used to test "free elsewhere". */
|
|
117
|
+
const MODEL_MODES = ['plan', 'execute', 'commit', 'compact'];
|
|
118
|
+
/**
|
|
119
|
+
* The lock reason for a model in a mode under the free-tier clamp, or `null`
|
|
120
|
+
* when it is selectable. Pro users and `provider: 'custom'` (bring-your-own
|
|
121
|
+
* AI) models are never locked; a free/anon user may pick only the mode's
|
|
122
|
+
* clamped model (plan/execute) or any free-tier-flagged model (the auxiliary
|
|
123
|
+
* commit/compact jobs, mirroring the server's aux-model selection, which
|
|
124
|
+
* ignores a non-free platform pick anyway).
|
|
125
|
+
*
|
|
126
|
+
* A locked model splits into two very different cases the UI must not
|
|
127
|
+
* conflate: `'paid'` (upgrade actually unlocks it) versus `'mode'` (the model
|
|
128
|
+
* is free-tier-usable in ANOTHER mode — it is a different mode's clamp, or
|
|
129
|
+
* free-tier-flagged and thus selectable for commit/compact — so a "Pro" badge
|
|
130
|
+
* would be flatly wrong).
|
|
131
|
+
*
|
|
132
|
+
* @param modelId - The candidate model id.
|
|
133
|
+
* @param mode - The conversation mode the picker is scoped to.
|
|
134
|
+
* @param isFreeTier - Whether the current user is on the free/anon tier.
|
|
135
|
+
* @param models - The available models from the catalog.
|
|
136
|
+
* @param fallback - The free-tier model id to use when no clamp match is found.
|
|
137
|
+
* @returns `'paid'` / `'mode'` when locked, `null` when selectable.
|
|
138
|
+
*/
|
|
139
|
+
export function freeTierLockReason(modelId, mode, isFreeTier, models, fallback) {
|
|
140
|
+
if (!isFreeTier)
|
|
141
|
+
return null;
|
|
142
|
+
const candidate = models.find((m) => m.id === modelId);
|
|
143
|
+
if (candidate?.provider === 'custom')
|
|
144
|
+
return null;
|
|
145
|
+
const allowedHere = mode === 'commit' || mode === 'compact'
|
|
146
|
+
? candidate?.freeTier === true
|
|
147
|
+
: modelId === freeTierModeModelId(models, mode, fallback);
|
|
148
|
+
if (allowedHere)
|
|
149
|
+
return null;
|
|
150
|
+
const freeElsewhere = candidate?.freeTier === true ||
|
|
151
|
+
MODEL_MODES.some((other) => other !== mode && modelId === freeTierModeModelId(models, other, fallback));
|
|
152
|
+
return freeElsewhere ? 'mode' : 'paid';
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The mode a free-tier user can actually use this model in — `'plan'` /
|
|
156
|
+
* `'execute'` when it is that mode's clamp, `'commit'` (standing for both
|
|
157
|
+
* auxiliary jobs) when it is merely free-tier-flagged, `null` when the free
|
|
158
|
+
* tier can't use it anywhere. Drives the "free in <mode>" labeling next to a
|
|
159
|
+
* `'mode'`-locked row.
|
|
160
|
+
*
|
|
161
|
+
* @param modelId - The candidate model id.
|
|
162
|
+
* @param models - The available models from the catalog.
|
|
163
|
+
* @param fallback - The free-tier model id to use when no clamp match is found.
|
|
164
|
+
* @returns The mode the model is free-tier-usable in, or `null`.
|
|
165
|
+
*/
|
|
166
|
+
export function freeTierUsableMode(modelId, models, fallback) {
|
|
167
|
+
if (modelId === freeTierModeModelId(models, 'plan', fallback))
|
|
168
|
+
return 'plan';
|
|
169
|
+
if (modelId === freeTierModeModelId(models, 'execute', fallback))
|
|
170
|
+
return 'execute';
|
|
171
|
+
if (models.find((m) => m.id === modelId)?.freeTier === true)
|
|
172
|
+
return 'commit';
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Whether a model is locked (not selectable) for the given mode under the
|
|
177
|
+
* free-tier clamp — the boolean view of {@link freeTierLockReason} (which see
|
|
178
|
+
* for the rules: pro users and custom models never lock; plan/execute clamp to
|
|
179
|
+
* one model; commit/compact accept any free-tier-flagged model).
|
|
180
|
+
*
|
|
181
|
+
* @param modelId - The candidate model id.
|
|
182
|
+
* @param mode - The conversation mode the picker is scoped to.
|
|
183
|
+
* @param isFreeTier - Whether the current user is on the free/anon tier.
|
|
184
|
+
* @param models - The available models from the catalog.
|
|
185
|
+
* @param fallback - The free-tier model id to use when no clamp match is found.
|
|
186
|
+
* @returns `true` when the model is locked for this user and mode.
|
|
187
|
+
*/
|
|
188
|
+
export function isModeModelLocked(modelId, mode, isFreeTier, models, fallback) {
|
|
189
|
+
return freeTierLockReason(modelId, mode, isFreeTier, models, fallback) !== null;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=chat-model-mode-utilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-model-mode-utilities.js","sourceRoot":"","sources":["../../src/components/chat-model-mode-utilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers backing the `/models` comparison table.
|
|
3
|
+
*
|
|
4
|
+
* Sorting is split out from the React component so the comparator can be unit
|
|
5
|
+
* tested without rendering. All functions are deterministic and side-effect
|
|
6
|
+
* free.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import type { AppModelDefinition } from '@molecule/app-ai-models';
|
|
11
|
+
/**
|
|
12
|
+
* Sortable columns in the `/models` table.
|
|
13
|
+
*
|
|
14
|
+
* `cutoff` (knowledge-cutoff date) replaced a former `tier` column that was
|
|
15
|
+
* fabricated from input price: it duplicated the `cost` axis and was sometimes
|
|
16
|
+
* factually wrong (a slow reasoning model could read "Balanced"). The catalog
|
|
17
|
+
* has no latency field, so rather than invent one we expose `knowledgeCutoff` —
|
|
18
|
+
* a real, factual axis that is genuinely independent of price, context, and
|
|
19
|
+
* output size.
|
|
20
|
+
*/
|
|
21
|
+
export type ModelSortColumn = 'name' | 'context' | 'cost' | 'cutoff' | 'free' | 'region';
|
|
22
|
+
/** Sort direction. */
|
|
23
|
+
export type SortDirection = 'asc' | 'desc';
|
|
24
|
+
/**
|
|
25
|
+
* Processing region of a model, as an arbitrary region code (`'us'`, `'cn'`,
|
|
26
|
+
* potentially `'eu'` etc. later). `'us'` is the platform default; deliberately
|
|
27
|
+
* NOT a closed union so adding a region never changes this contract.
|
|
28
|
+
*/
|
|
29
|
+
export type ModelProcessingRegion = string;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve a model's effective processing region: the requested region when the
|
|
32
|
+
* model's `regions` list offers it, else the model's DEFAULT region (the first
|
|
33
|
+
* listed; `'us'` when the catalog omits regions). A single-entry list pins the
|
|
34
|
+
* model regardless of the request. Mirrors the server-side
|
|
35
|
+
* `effectiveModelRegion` in `@molecule/api-resource-ai-models`.
|
|
36
|
+
*
|
|
37
|
+
* @param model - The model metadata.
|
|
38
|
+
* @param requested - The user's per-model region choice, if any.
|
|
39
|
+
* @returns The effective region code.
|
|
40
|
+
*/
|
|
41
|
+
export declare function effectiveModelRegion(model: AppModelDefinition, requested?: string): ModelProcessingRegion;
|
|
42
|
+
/**
|
|
43
|
+
* Combined input + output price per million tokens, used as the single
|
|
44
|
+
* "cost/1M tokens" figure — at the rates of the model's effective region
|
|
45
|
+
* (`regionPricing` override when the region has one, else the base rates).
|
|
46
|
+
*
|
|
47
|
+
* @param model - The model metadata.
|
|
48
|
+
* @param region - The user's per-model region choice, if any (omitted → the
|
|
49
|
+
* model's default region).
|
|
50
|
+
* @returns Sum of input and output price per million tokens in USD.
|
|
51
|
+
*/
|
|
52
|
+
export declare function modelTotalCost(model: AppModelDefinition, region?: string): number;
|
|
53
|
+
/**
|
|
54
|
+
* Relative usage rate: how much faster this model consumes the user's AI
|
|
55
|
+
* allowance than the cheapest available model (a unitless `×N` multiplier,
|
|
56
|
+
* `1` for the cheapest). Derived from combined input+output list rates. This
|
|
57
|
+
* is the ONLY per-model "cost" figure user-facing surfaces show — AI usage is
|
|
58
|
+
* never presented as currency.
|
|
59
|
+
*
|
|
60
|
+
* The base is every model's DEFAULT-region cost (stable regardless of the
|
|
61
|
+
* user's per-model region choices); the rated model itself is priced at the
|
|
62
|
+
* given region so the figure tracks what a region switch actually changes.
|
|
63
|
+
*
|
|
64
|
+
* @param model - The model to rate.
|
|
65
|
+
* @param models - The full available-model list (supplies the cheapest base).
|
|
66
|
+
* @param region - The rated model's region choice, if any (omitted → its
|
|
67
|
+
* default region).
|
|
68
|
+
* @returns The multiplier, rounded to 1 decimal below 10 and whole above.
|
|
69
|
+
*/
|
|
70
|
+
export declare function modelUsageRate(model: AppModelDefinition, models: readonly AppModelDefinition[], region?: string): number;
|
|
71
|
+
/**
|
|
72
|
+
* Ascending comparator for two models by the given column. Returns a negative,
|
|
73
|
+
* zero, or positive number suitable for `Array.prototype.sort`. Ties fall back
|
|
74
|
+
* to label order so the sort is stable and deterministic.
|
|
75
|
+
*
|
|
76
|
+
* @param a - First model.
|
|
77
|
+
* @param b - Second model.
|
|
78
|
+
* @param column - Column to compare by.
|
|
79
|
+
* @param regionOf - Resolves a model's effective processing region (used by
|
|
80
|
+
* the `'region'` and `'cost'` columns; omitting it treats every model as its
|
|
81
|
+
* default region). The caller supplies this because the effective region
|
|
82
|
+
* depends on per-project settings the pure helper cannot know.
|
|
83
|
+
* @returns Negative if `a` sorts before `b`, positive if after, zero if equal.
|
|
84
|
+
*/
|
|
85
|
+
export declare function compareModels(a: AppModelDefinition, b: AppModelDefinition, column: ModelSortColumn, regionOf?: (model: AppModelDefinition) => ModelProcessingRegion): number;
|
|
86
|
+
/**
|
|
87
|
+
* Returns a new array of models sorted by the given column and direction.
|
|
88
|
+
* Does not mutate the input.
|
|
89
|
+
*
|
|
90
|
+
* @param models - Models to sort.
|
|
91
|
+
* @param column - Column to sort by.
|
|
92
|
+
* @param direction - `'asc'` or `'desc'`.
|
|
93
|
+
* @param regionOf - Resolves a model's effective processing region (used by
|
|
94
|
+
* the `'region'` and `'cost'` columns). See {@link compareModels}.
|
|
95
|
+
* @returns A new, sorted array.
|
|
96
|
+
*/
|
|
97
|
+
export declare function sortModels(models: readonly AppModelDefinition[], column: ModelSortColumn, direction: SortDirection, regionOf?: (model: AppModelDefinition) => ModelProcessingRegion): AppModelDefinition[];
|
|
98
|
+
//# sourceMappingURL=chat-models-utilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-models-utilities.d.ts","sourceRoot":"","sources":["../../src/components/chat-models-utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;AAExF,sBAAsB;AACtB,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAA;AAE1C;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAA;AAE1C;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,kBAAkB,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,qBAAqB,CAGvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,kBAAkB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAKjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,kBAAkB,EACzB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAMR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,kBAAkB,EACrB,CAAC,EAAE,kBAAkB,EACrB,MAAM,EAAE,eAAe,EACvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,qBAAqB,GAC9D,MAAM,CAoCR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,aAAa,EACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,qBAAqB,GAC9D,kBAAkB,EAAE,CAQtB"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers backing the `/models` comparison table.
|
|
3
|
+
*
|
|
4
|
+
* Sorting is split out from the React component so the comparator can be unit
|
|
5
|
+
* tested without rendering. All functions are deterministic and side-effect
|
|
6
|
+
* free.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Resolve a model's effective processing region: the requested region when the
|
|
12
|
+
* model's `regions` list offers it, else the model's DEFAULT region (the first
|
|
13
|
+
* listed; `'us'` when the catalog omits regions). A single-entry list pins the
|
|
14
|
+
* model regardless of the request. Mirrors the server-side
|
|
15
|
+
* `effectiveModelRegion` in `@molecule/api-resource-ai-models`.
|
|
16
|
+
*
|
|
17
|
+
* @param model - The model metadata.
|
|
18
|
+
* @param requested - The user's per-model region choice, if any.
|
|
19
|
+
* @returns The effective region code.
|
|
20
|
+
*/
|
|
21
|
+
export function effectiveModelRegion(model, requested) {
|
|
22
|
+
const regions = model.regions ?? ['us'];
|
|
23
|
+
return requested && regions.includes(requested) ? requested : regions[0];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Combined input + output price per million tokens, used as the single
|
|
27
|
+
* "cost/1M tokens" figure — at the rates of the model's effective region
|
|
28
|
+
* (`regionPricing` override when the region has one, else the base rates).
|
|
29
|
+
*
|
|
30
|
+
* @param model - The model metadata.
|
|
31
|
+
* @param region - The user's per-model region choice, if any (omitted → the
|
|
32
|
+
* model's default region).
|
|
33
|
+
* @returns Sum of input and output price per million tokens in USD.
|
|
34
|
+
*/
|
|
35
|
+
export function modelTotalCost(model, region) {
|
|
36
|
+
const override = model.regionPricing?.[effectiveModelRegion(model, region)];
|
|
37
|
+
return override
|
|
38
|
+
? override.inputPricePerMTok + override.outputPricePerMTok
|
|
39
|
+
: model.inputPricePerMTok + model.outputPricePerMTok;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Relative usage rate: how much faster this model consumes the user's AI
|
|
43
|
+
* allowance than the cheapest available model (a unitless `×N` multiplier,
|
|
44
|
+
* `1` for the cheapest). Derived from combined input+output list rates. This
|
|
45
|
+
* is the ONLY per-model "cost" figure user-facing surfaces show — AI usage is
|
|
46
|
+
* never presented as currency.
|
|
47
|
+
*
|
|
48
|
+
* The base is every model's DEFAULT-region cost (stable regardless of the
|
|
49
|
+
* user's per-model region choices); the rated model itself is priced at the
|
|
50
|
+
* given region so the figure tracks what a region switch actually changes.
|
|
51
|
+
*
|
|
52
|
+
* @param model - The model to rate.
|
|
53
|
+
* @param models - The full available-model list (supplies the cheapest base).
|
|
54
|
+
* @param region - The rated model's region choice, if any (omitted → its
|
|
55
|
+
* default region).
|
|
56
|
+
* @returns The multiplier, rounded to 1 decimal below 10 and whole above.
|
|
57
|
+
*/
|
|
58
|
+
export function modelUsageRate(model, models, region) {
|
|
59
|
+
const costs = models.map((m) => modelTotalCost(m)).filter((c) => c > 0);
|
|
60
|
+
const base = costs.length > 0 ? Math.min(...costs) : 0;
|
|
61
|
+
if (!Number.isFinite(base) || base <= 0)
|
|
62
|
+
return 1;
|
|
63
|
+
const rate = modelTotalCost(model, region) / base;
|
|
64
|
+
return rate >= 10 ? Math.round(rate) : Math.max(1, Math.round(rate * 10) / 10);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Ascending comparator for two models by the given column. Returns a negative,
|
|
68
|
+
* zero, or positive number suitable for `Array.prototype.sort`. Ties fall back
|
|
69
|
+
* to label order so the sort is stable and deterministic.
|
|
70
|
+
*
|
|
71
|
+
* @param a - First model.
|
|
72
|
+
* @param b - Second model.
|
|
73
|
+
* @param column - Column to compare by.
|
|
74
|
+
* @param regionOf - Resolves a model's effective processing region (used by
|
|
75
|
+
* the `'region'` and `'cost'` columns; omitting it treats every model as its
|
|
76
|
+
* default region). The caller supplies this because the effective region
|
|
77
|
+
* depends on per-project settings the pure helper cannot know.
|
|
78
|
+
* @returns Negative if `a` sorts before `b`, positive if after, zero if equal.
|
|
79
|
+
*/
|
|
80
|
+
export function compareModels(a, b, column, regionOf) {
|
|
81
|
+
let primary;
|
|
82
|
+
switch (column) {
|
|
83
|
+
case 'name':
|
|
84
|
+
primary = a.label.localeCompare(b.label);
|
|
85
|
+
break;
|
|
86
|
+
case 'context':
|
|
87
|
+
primary = a.contextWindow - b.contextWindow;
|
|
88
|
+
break;
|
|
89
|
+
case 'cost':
|
|
90
|
+
// Region-aware: a model flipped to a differently-priced region sorts by
|
|
91
|
+
// the cost it actually bills at.
|
|
92
|
+
primary = modelTotalCost(a, regionOf?.(a)) - modelTotalCost(b, regionOf?.(b));
|
|
93
|
+
break;
|
|
94
|
+
case 'cutoff':
|
|
95
|
+
// Knowledge-cutoff dates are YYYY-MM-DD strings, which sort
|
|
96
|
+
// lexicographically as dates. Ascending puts the oldest training data
|
|
97
|
+
// first.
|
|
98
|
+
primary = a.knowledgeCutoff.localeCompare(b.knowledgeCutoff);
|
|
99
|
+
break;
|
|
100
|
+
case 'free':
|
|
101
|
+
// Free-tier models sort first in ascending order.
|
|
102
|
+
primary = (b.freeTier ? 1 : 0) - (a.freeTier ? 1 : 0);
|
|
103
|
+
break;
|
|
104
|
+
case 'region': {
|
|
105
|
+
// US-processed (platform-default) models sort first ascending; other
|
|
106
|
+
// regions follow alphabetically by region code.
|
|
107
|
+
const ra = regionOf?.(a) ?? 'us';
|
|
108
|
+
const rb = regionOf?.(b) ?? 'us';
|
|
109
|
+
primary = ra === rb ? 0 : ra === 'us' ? -1 : rb === 'us' ? 1 : ra.localeCompare(rb);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (primary !== 0)
|
|
114
|
+
return primary;
|
|
115
|
+
// Stable tiebreak by label so equal rows keep a deterministic order.
|
|
116
|
+
return a.label.localeCompare(b.label);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Returns a new array of models sorted by the given column and direction.
|
|
120
|
+
* Does not mutate the input.
|
|
121
|
+
*
|
|
122
|
+
* @param models - Models to sort.
|
|
123
|
+
* @param column - Column to sort by.
|
|
124
|
+
* @param direction - `'asc'` or `'desc'`.
|
|
125
|
+
* @param regionOf - Resolves a model's effective processing region (used by
|
|
126
|
+
* the `'region'` and `'cost'` columns). See {@link compareModels}.
|
|
127
|
+
* @returns A new, sorted array.
|
|
128
|
+
*/
|
|
129
|
+
export function sortModels(models, column, direction, regionOf) {
|
|
130
|
+
// Swapping the comparator arguments for `'desc'` fully reverses the order
|
|
131
|
+
// (including the label tiebreak) without relying on Array#sort stability.
|
|
132
|
+
return [...models].sort((a, b) => direction === 'desc'
|
|
133
|
+
? compareModels(b, a, column, regionOf)
|
|
134
|
+
: compareModels(a, b, column, regionOf));
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=chat-models-utilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-models-utilities.js","sourceRoot":"","sources":["../../src/components/chat-models-utilities.ts"],"names":[],"mappings":"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"}
|