@kortix/ui 0.14.4 → 0.14.6
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/README.md +8 -4
- package/dist/access/access/access-dialog.js +8 -5
- package/dist/access/access/copy-row.js +2 -2
- package/dist/access/sharing-picker.js +2 -1
- package/dist/browser/app-in-browser.js +5 -3
- package/dist/browser/browser-panel.js +6 -6
- package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
- package/dist/browser/sandbox-browser-chrome.js +4 -3
- package/dist/customize/agents/agent-access.d.ts +20 -0
- package/dist/customize/agents/agent-access.js +17 -0
- package/dist/customize/agents/agent-grant-pages.js +5 -6
- package/dist/customize/agents/agent-page.js +2 -1
- package/dist/customize/agents/agents-page.js +18 -1
- package/dist/customize/connectors/add-mcp/add-mcp-server.js +4 -2
- package/dist/customize/connectors/connector-routes.d.ts +3 -1
- package/dist/customize/connectors/connector-routes.js +18 -0
- package/dist/customize/connectors/connectors-page.js +23 -4
- package/dist/customize/connectors/detail/connector-advanced-tools.js +4 -6
- package/dist/customize/providers/provider-accordion.js +2 -1
- package/dist/customize/providers/provider-connect.js +2 -1
- package/dist/customize/sections/component/telegram-channel-row.js +1 -1
- package/dist/customize/sections/connector-connection-modal.js +11 -9
- package/dist/customize/sections/connectors-view.js +11 -13
- package/dist/customize/sections/llm-provider/constants.d.ts +0 -1
- package/dist/customize/sections/llm-provider/constants.js +0 -2
- package/dist/customize/sections/llm-provider/models-tab-group.d.ts +1 -1
- package/dist/customize/sections/llm-provider/models-tab-group.js +7 -4
- package/dist/customize/sections/llm-provider/models-tab-row.d.ts +2 -18
- package/dist/customize/sections/llm-provider/models-tab-row.js +6 -30
- package/dist/customize/sections/llm-provider/models-tab.d.ts +0 -1
- package/dist/customize/sections/llm-provider/models-tab.js +1 -10
- package/dist/customize/sections/llm-provider/use-connected-providers.js +2 -2
- package/dist/customize/sections/llm-provider/utils.d.ts +1 -1
- package/dist/customize/sections/llm-provider/utils.js +7 -14
- package/dist/customize/sections/view/gateway/_shared.js +1 -2
- package/dist/customize/sections/view/gateway/gateway-routing.js +18 -20
- package/dist/customize/sections/view/sandbox-provider-coverage.d.ts +3 -18
- package/dist/customize/sections/view/sandbox-provider-coverage.js +7 -27
- package/dist/customize/settings/rail-copy-context.js +5 -3
- package/dist/customize/settings/tabs/sandbox-tab.d.ts +2 -27
- package/dist/customize/settings/tabs/sandbox-tab.js +13 -112
- package/dist/customize/settings/tabs/sandbox-template-form.js +9 -12
- package/dist/customize/shared/capability-tabs.js +2 -1
- package/dist/customize/shared/entity/entity-modal.d.ts +5 -1
- package/dist/customize/shared/entity/entity-modal.js +7 -4
- package/dist/customize/skills/remove-skill-button.d.ts +16 -0
- package/dist/customize/skills/remove-skill-button.js +42 -0
- package/dist/customize/skills/skills-page.js +4 -6
- package/dist/customize/triggers/schedule/event-trigger-copy.js +3 -2
- package/dist/customize/triggers/schedule/schedule-builder.js +7 -4
- package/dist/customize/triggers/schedule/trigger-composer.js +5 -2
- package/dist/customize/triggers/schedule/trigger-list.d.ts +0 -2
- package/dist/customize/triggers/schedule/trigger-list.js +1 -18
- package/dist/customize/triggers/schedule/trigger-tile.d.ts +1 -32
- package/dist/customize/triggers/schedule/trigger-tile.js +1 -16
- package/dist/customize/triggers/schedule/when-event.js +1 -1
- package/dist/diff/diff-view.js +9 -10
- package/dist/files/editor/code-editor.js +2 -3
- package/dist/files/project/components/change-request-detail-dialog.d.ts +3 -1
- package/dist/files/project/components/change-request-detail-dialog.js +3 -5
- package/dist/files/project/components/change-request-status-badge.d.ts +12 -0
- package/dist/files/project/components/change-request-status-badge.js +27 -0
- package/dist/files/project/components/change-requests-panel.js +1 -1
- package/dist/files/project/components/drive-explorer.js +2 -1
- package/dist/files/project/components/drive-grid-view.js +11 -7
- package/dist/files/project/components/drive-list-view.js +4 -4
- package/dist/files/project/components/file-breadcrumbs.js +1 -1
- package/dist/files/project/components/file-explorer-page.js +1 -1
- package/dist/files/project/components/file-history-popover.js +1 -6
- package/dist/files/project/components/file-search.js +6 -1
- package/dist/files/project/components/open-change-request-dialog.js +2 -1
- package/dist/files/project/components/version-selector-logic.d.ts +11 -0
- package/dist/files/project/components/version-selector-logic.js +26 -0
- package/dist/files/project/components/version-selector.js +11 -20
- package/dist/files/project/hooks/use-change-requests.d.ts +14 -1
- package/dist/files/project/hooks/use-change-requests.js +44 -25
- package/dist/files/project/hooks/use-server-health.js +17 -15
- package/dist/files/renderers/docx/docx-viewer.js +4 -6
- package/dist/files/renderers/image-renderer.js +6 -24
- package/dist/files/renderers/pdf/pdf-renderer.d.ts +3 -1
- package/dist/files/renderers/pdf/pdf-renderer.js +2 -2
- package/dist/files/renderers/pdf/pdf-viewer.d.ts +3 -0
- package/dist/files/renderers/pdf/pdf-viewer.js +16 -7
- package/dist/files/renderers/presentation/FullScreenPresentationViewer.js +2 -11
- package/dist/files/renderers/show-content-renderer.js +1 -1
- package/dist/files/renderers/sqlite-renderer.js +8 -3
- package/dist/files/renderers/xlsx/xlsx-viewer.js +15 -16
- package/dist/files/tree/components/file-tree-item.js +1 -1
- package/dist/files/viewer/file-content-renderer.d.ts +4 -1
- package/dist/files/viewer/file-content-renderer.js +2 -2
- package/dist/files/viewer/file-preview-modal.js +1 -1
- package/dist/files/viewer/use-file-content-state.js +1 -1
- package/dist/i18n/en.d.ts +36 -35
- package/dist/i18n/en.js +45 -44
- package/dist/index.d.ts +1 -1
- package/dist/internal/desktop/desktop-back-button.js +5 -3
- package/dist/internal/hooks/use-auto-scroll.js +5 -3
- package/dist/internal/hooks/use-notification-center.js +21 -15
- package/dist/internal/hooks/use-review-session-summary.d.ts +6 -0
- package/dist/internal/hooks/use-review-session-summary.js +11 -0
- package/dist/internal/lib/browser-error-noise.d.ts +1 -1
- package/dist/internal/lib/browser-error-noise.js +1 -1
- package/dist/internal/lib/browser-noise/rules/rejections.d.ts +10 -0
- package/dist/internal/lib/browser-noise/rules/rejections.js +27 -1
- package/dist/internal/lib/provider-branding.js +14 -3
- package/dist/internal/lib/trigger-clock.d.ts +42 -0
- package/dist/internal/lib/trigger-clock.js +34 -0
- package/dist/internal/lib/web-notifications.d.ts +6 -0
- package/dist/internal/lib/web-notifications.js +57 -7
- package/dist/internal/notifications/notification-bell.d.ts +13 -0
- package/dist/internal/notifications/notification-bell.js +1 -1
- package/dist/internal/notifications/notification-rows.js +2 -1
- package/dist/internal/outcomes/outcome-types.d.ts +5 -0
- package/dist/internal/reminders/reminder-filter.d.ts +12 -0
- package/dist/internal/reminders/reminder-filter.js +34 -0
- package/dist/internal/reminders/reminder-format.d.ts +6 -0
- package/dist/internal/reminders/reminder-format.js +20 -2
- package/dist/internal/stores/kortix-computer-store.d.ts +1 -1
- package/dist/internal/stores/session-hover-store.d.ts +20 -5
- package/dist/internal/stores/session-hover-store.js +31 -13
- package/dist/internal/stores/session-panel-memory-store.js +2 -0
- package/dist/markdown/code/inline-code.js +8 -0
- package/dist/markdown/code/output-paths-context.d.ts +18 -0
- package/dist/markdown/code/output-paths-context.js +35 -0
- package/dist/markdown/genui/components/charts.js +6 -5
- package/dist/primitives/count-badge.d.ts +3 -1
- package/dist/primitives/count-badge.js +3 -3
- package/dist/primitives/glyph-paths-source.js +1 -1
- package/dist/primitives/glyph-paths.generated.js +1 -1
- package/dist/primitives/map.js +2 -1
- package/dist/primitives/preview-image.js +4 -2
- package/dist/primitives/textarea.js +1 -1
- package/dist/primitives/typed-title.js +12 -14
- package/dist/primitives/typing-animation.js +4 -2
- package/dist/providers/ui-provider.d.ts +57 -0
- package/dist/providers/ui-provider.js +4 -0
- package/dist/session/composer/ComposerCard.d.ts +2 -0
- package/dist/session/composer/ComposerCard.js +5 -1
- package/dist/session/composer/agent-selector.js +17 -5
- package/dist/session/composer/composer-chat-input.js +5 -3
- package/dist/session/composer/composer-logic.js +8 -7
- package/dist/session/composer/composer-toolbar.js +4 -2
- package/dist/session/composer/composer-underbar.js +3 -1
- package/dist/session/composer/composer.js +34 -5
- package/dist/session/composer/draft/composer-draft.js +4 -4
- package/dist/session/composer/menus/slash-actions.d.ts +22 -2
- package/dist/session/composer/menus/slash-actions.js +20 -0
- package/dist/session/composer/menus/slash-items.js +19 -3
- package/dist/session/composer/pasted-text.js +3 -2
- package/dist/session/composer/stores/queued-draft-store.js +3 -2
- package/dist/session/header/reminder-parts.d.ts +294 -0
- package/dist/session/header/reminder-parts.js +120 -0
- package/dist/session/header/session-reminders-indicator.d.ts +13 -0
- package/dist/session/header/session-reminders-indicator.js +142 -35
- package/dist/session/media/sandbox-url-detector.js +0 -7
- package/dist/session/models/model-availability.d.ts +23 -0
- package/dist/session/models/model-availability.js +20 -0
- package/dist/session/models/model-grouping.js +1 -4
- package/dist/session/models/model-selector.js +23 -14
- package/dist/session/models/use-model-connection-gate.js +4 -1
- package/dist/session/outcomes/change-request-outcomes.js +24 -3
- package/dist/session/outcomes/session-outcomes-provider.d.ts +3 -1
- package/dist/session/outcomes/session-outcomes-provider.js +31 -3
- package/dist/session/overrides/provider-secret-pool-editor.js +2 -1
- package/dist/session/overrides/session-overrides-composer.d.ts +1 -1
- package/dist/session/overrides/session-overrides-composer.js +5 -1
- package/dist/session/panel/advanced/advanced-panel.js +3 -7
- package/dist/session/panel/easy/app-preview.js +12 -2
- package/dist/session/panel/easy/easy-panel-logic.d.ts +1 -1
- package/dist/session/panel/easy/easy-panel-logic.js +1 -1
- package/dist/session/panel/easy/outputs-card.js +2 -1
- package/dist/session/panel/easy/panel-card.js +5 -3
- package/dist/session/panel/easy/preview-load.d.ts +14 -0
- package/dist/session/panel/easy/preview-load.js +15 -0
- package/dist/session/panel/easy/step-detail-body.js +2 -7
- package/dist/session/panel/mobile-tool-drawer.js +4 -2
- package/dist/session/panel/open-session-quick-view.js +2 -1
- package/dist/session/panel/panel-fallback.js +8 -4
- package/dist/session/panel/session-panel-provider.d.ts +1 -0
- package/dist/session/panel/session-panel-provider.js +19 -3
- package/dist/session/panel/session-reminders-panel.d.ts +4 -0
- package/dist/session/panel/session-reminders-panel.js +109 -0
- package/dist/session/panel/shared/use-panel-derivations.js +6 -4
- package/dist/session/panel/shared/use-panel-handoffs.d.ts +2 -2
- package/dist/session/panel/shared/use-panel-handoffs.js +5 -1
- package/dist/session/panel/use-session-panel-layout.js +7 -5
- package/dist/session/print/session-print-header.d.ts +0 -10
- package/dist/session/print/session-print-header.js +25 -9
- package/dist/session/status/session-surface.js +1 -1
- package/dist/session/thread/optimistic-turn.d.ts +5 -1
- package/dist/session/thread/optimistic-turn.js +8 -6
- package/dist/session/thread/session-chat.d.ts +6 -1
- package/dist/session/thread/session-chat.js +34 -12
- package/dist/session/thread/session-history.js +3 -1
- package/dist/session/thread/session-thread.d.ts +10 -1
- package/dist/session/thread/session-thread.js +2 -2
- package/dist/session/thread/transcript.js +13 -7
- package/dist/session/tool/shared/file-list.js +19 -2
- package/dist/session/tool/shared/infrastructure-contexts.d.ts +7 -0
- package/dist/session/tool/shared/infrastructure-contexts.js +7 -0
- package/dist/session/tool/shared/infrastructure-output.js +9 -5
- package/dist/session/tool/shared/infrastructure-row-header.js +9 -1
- package/dist/session/tool/shared/infrastructure-rows.js +7 -5
- package/dist/session/tool/tools/bash-tool.js +10 -6
- package/dist/session/tool/tools/web-search-tool.js +25 -3
- package/dist/session/turn/burst-step-body.js +4 -0
- package/dist/session/turn/recovered-failures.d.ts +8 -0
- package/dist/session/turn/recovered-failures.js +32 -0
- package/dist/session/turn/streaming-cadence.js +5 -8
- package/dist/styles.css +1 -1
- package/dist/terminal/session-terminal-panel.js +3 -5
- package/dist/theme/theme.js +2 -1
- package/dist/workspace/projects/modal/github-import-pickers.js +7 -6
- package/dist/workspace/review/review-center.js +13 -10
- package/dist/workspace/session-workspace.js +5 -9
- package/dist/workspace/sessions/deleted-session-row.js +5 -2
- package/dist/workspace/sidebar/footer/project-computer-nav.js +6 -4
- package/dist/workspace/sidebar/footer/project-mcp-nav.js +6 -2
- package/dist/workspace/sidebar/modal/rename-session-modal.js +8 -3
- package/dist/workspace/sidebar/project-session-list.js +52 -55
- package/dist/workspace/sidebar/session-brief-hover-card.d.ts +35 -18
- package/dist/workspace/sidebar/session-brief-hover-card.js +114 -37
- package/dist/workspace/sidebar/session-status-mark.d.ts +15 -1
- package/dist/workspace/sidebar/session-status-mark.js +63 -17
- package/package.json +7 -3
- package/skills/kortix-ui/SKILL.md +1 -1
- package/dist/customize/sections/view/sandbox-provider-result.d.ts +0 -47
- package/dist/customize/sections/view/sandbox-provider-result.js +0 -79
|
@@ -421,14 +421,16 @@ function EmailSenderPolicyEditor({ projectId, connectorSlug, policy, canWrite =
|
|
|
421
421
|
const [domains, setDomains] = useState(() => initial.allowedDomains.join('\n'));
|
|
422
422
|
const [regex, setRegex] = useState(initial.allowedRegex ?? '');
|
|
423
423
|
const [error, setError] = useState(null);
|
|
424
|
-
|
|
424
|
+
const [syncedPolicy, setSyncedPolicy] = useState(policy);
|
|
425
|
+
if (policy !== syncedPolicy) {
|
|
426
|
+
setSyncedPolicy(policy);
|
|
425
427
|
const next = normalizeEmailSenderPolicy(policy);
|
|
426
428
|
setRestricted(next.mode === 'restricted');
|
|
427
429
|
setEmails(next.allowedEmails.join('\n'));
|
|
428
430
|
setDomains(next.allowedDomains.join('\n'));
|
|
429
431
|
setRegex(next.allowedRegex ?? '');
|
|
430
432
|
setError(null);
|
|
431
|
-
}
|
|
433
|
+
}
|
|
432
434
|
const nextPolicy = () => ({
|
|
433
435
|
mode: restricted ? 'restricted' : 'allow_all',
|
|
434
436
|
allowedEmails: splitPolicyList(emails),
|
|
@@ -948,17 +950,13 @@ export function CustomConnectorForm({ projectId, emailChannelEnabled, onAdded, }
|
|
|
948
950
|
const timer = window.setTimeout(() => setDiscoveryDraft(draft), 400);
|
|
949
951
|
return () => window.clearTimeout(timer);
|
|
950
952
|
}, [draft]);
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
if (draft.provider === 'channel' && oauth2Selected) {
|
|
959
|
-
setOauth2Selected(false);
|
|
960
|
-
}
|
|
961
|
-
}, [draft.provider, oauth2Selected]);
|
|
953
|
+
if (!emailChannelEnabled && draft.provider === 'channel' && draft.platform === 'email') {
|
|
954
|
+
setDraft((current) => ({ ...current, platform: 'slack' }));
|
|
955
|
+
}
|
|
956
|
+
// Channel connectors have no OAuth2-at-creation offer.
|
|
957
|
+
if (draft.provider === 'channel' && oauth2Selected) {
|
|
958
|
+
setOauth2Selected(false);
|
|
959
|
+
}
|
|
962
960
|
const save = useCreateCustomConnector(projectId, onAdded);
|
|
963
961
|
const discovery = useQuery({
|
|
964
962
|
queryKey: ['connector-auth-discovery', projectId, discoveryDraft],
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
import { DEFAULT_MANAGED_MODEL_IDS } from '@kortix/llm-catalog';
|
|
2
|
-
export const MANAGED_MODEL_ID_SET = new Set(DEFAULT_MANAGED_MODEL_IDS);
|
|
3
1
|
export const CODEX_AUTH_JSON_SECRET_NAME = 'CODEX_AUTH_JSON';
|
|
4
2
|
export const LEGACY_RUNTIME_AUTH_JSON_SECRET_NAME = 'OPENCODE_AUTH_JSON';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ModelContext } from './models-tab-row.js';
|
|
2
2
|
import type { ModelGroup } from './model-rows.js';
|
|
3
|
-
export declare function ModelsTabGroup({ group, access, enablement, defaults,
|
|
3
|
+
export declare function ModelsTabGroup({ group, access, enablement, defaults, canWrite, platformFee, }: ModelContext & {
|
|
4
4
|
group: ModelGroup;
|
|
5
5
|
platformFee: number | undefined;
|
|
6
6
|
}): import("react").JSX.Element;
|
|
@@ -6,18 +6,21 @@ import { errorToast } from '../../../primitives/toast.js';
|
|
|
6
6
|
import { ProviderLogoStatus } from '../../providers/provider-connect.js';
|
|
7
7
|
import { useTranslations } from '../../../i18n/index.js';
|
|
8
8
|
import { ModelsTabRow } from './models-tab-row.js';
|
|
9
|
-
export function ModelsTabGroup({ group, access, enablement, defaults,
|
|
9
|
+
export function ModelsTabGroup({ group, access, enablement, defaults, canWrite, platformFee, }) {
|
|
10
10
|
const tAccess = useTranslations('modelAccess');
|
|
11
11
|
const tList = useTranslations('modelsList');
|
|
12
12
|
const providerDisabled = access.data?.disabledProviders.includes(group.providerID) ?? false;
|
|
13
13
|
const groupOn = group.rows.filter(({ model }) => model.enabled).length;
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
// Platinum Inference serves every model it lists on zero-retention terms:
|
|
15
|
+
// the Kortix managed models and the Platinum provider alike.
|
|
16
|
+
const dataClaim = group.providerID === 'platinum' ||
|
|
17
|
+
(group.providerID === 'kortix' &&
|
|
18
|
+
group.rows.every(({ model }) => !model.modelID.includes('/')));
|
|
16
19
|
return (_jsxs("section", { "data-provider-group": group.providerID, className: "bg-popover overflow-hidden rounded-lg border", children: [_jsxs("header", { className: "border-border flex items-center gap-3 border-b px-4 py-3", children: [_jsx(ProviderLogoStatus, { providerId: group.providerID, label: group.providerName, status: providerDisabled
|
|
17
20
|
? 'none'
|
|
18
21
|
: group.providerID === 'kortix'
|
|
19
22
|
? 'included'
|
|
20
|
-
: 'connected', size: "medium" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: group.providerName }), group.providerID === 'kortix' && platformFee !== undefined ? (_jsx("p", { className: "text-muted-foreground text-xs", children: tList('platformFee', { fee: platformFee }) })) : null, dataClaim ? (
|
|
23
|
+
: 'connected', size: "medium" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: group.providerName }), group.providerID === 'kortix' && platformFee !== undefined ? (_jsx("p", { className: "text-muted-foreground text-xs", children: tList('platformFee', { fee: platformFee }) })) : null, dataClaim ? (_jsx("p", { className: "text-muted-foreground text-xs", children: _jsx(Hint, { label: tAccess('zdrDescription'), side: "top", className: "max-w-xs", children: _jsx("span", { tabIndex: 0, className: "cursor-help", children: tAccess('zdrTitle') }) }) })) : null] }), _jsx("span", { className: "text-muted-foreground shrink-0 text-xs tabular-nums", children: tList('onCount', { on: groupOn, total: group.rows.length }) }), _jsx(ProviderSwitch, { access: access, providerId: group.providerID, name: group.providerName, canWrite: canWrite })] }), group.rows.map(({ model, wireId, isRollingAlias }) => (_jsx(ModelsTabRow, { model: model, wireId: wireId, isRollingAlias: isRollingAlias, group: group, providerDisabled: providerDisabled, access: access, enablement: enablement, defaults: defaults, canWrite: canWrite }, wireId)))] }, group.providerID));
|
|
21
24
|
}
|
|
22
25
|
/**
|
|
23
26
|
* A whole provider on or off for this project. Credentials stay either way.
|
|
@@ -1,28 +1,12 @@
|
|
|
1
|
-
import { useModelAccess, useModelDefaults, useModelEnablement
|
|
2
|
-
import { type ReactNode } from 'react';
|
|
1
|
+
import { useModelAccess, useModelDefaults, useModelEnablement } from '@kortix/sdk/react';
|
|
3
2
|
import type { ModelGroup, ModelRow } from './model-rows.js';
|
|
4
3
|
export type ModelContext = {
|
|
5
4
|
access: ReturnType<typeof useModelAccess>;
|
|
6
5
|
enablement: ReturnType<typeof useModelEnablement>;
|
|
7
6
|
defaults: ReturnType<typeof useModelDefaults>;
|
|
8
|
-
pickerCatalog: ReturnType<typeof useProjectModelPickerCatalog>;
|
|
9
7
|
canWrite: boolean;
|
|
10
|
-
holdsDataClaim: (modelID: string) => boolean;
|
|
11
8
|
};
|
|
12
|
-
export declare function ModelsTabRow({ model, wireId, isRollingAlias, group, providerDisabled, access, enablement, defaults,
|
|
9
|
+
export declare function ModelsTabRow({ model, wireId, isRollingAlias, group, providerDisabled, access, enablement, defaults, canWrite, }: ModelRow & ModelContext & {
|
|
13
10
|
group: ModelGroup;
|
|
14
11
|
providerDisabled: boolean;
|
|
15
12
|
}): import("react").JSX.Element;
|
|
16
|
-
type ManagedPricingRoute = NonNullable<NonNullable<ReturnType<typeof useProjectModelPickerCatalog>>['managedPricingRoutes']>[string][number];
|
|
17
|
-
/**
|
|
18
|
-
* The row's price, underlined; hovering opens every serving route's price and
|
|
19
|
-
* the data notes. The routes used to be printed as full sentences under each
|
|
20
|
-
* managed model — four lines of numbers per row.
|
|
21
|
-
*/
|
|
22
|
-
export declare function ModelPriceHoverCard({ modelName, routes, dataClaim, children, }: {
|
|
23
|
-
modelName: string;
|
|
24
|
-
routes: readonly ManagedPricingRoute[];
|
|
25
|
-
dataClaim: boolean;
|
|
26
|
-
children: ReactNode;
|
|
27
|
-
}): import("react").JSX.Element;
|
|
28
|
-
export {};
|
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Badge } from '../../../primitives/badge.js';
|
|
4
4
|
import Hint from '../../../primitives/hint.js';
|
|
5
|
-
import { HoverCard, HoverCardContent, HoverCardTrigger } from '../../../primitives/hover-card.js';
|
|
6
5
|
import { Switch } from '../../../primitives/switch.js';
|
|
7
6
|
import { Tag } from '../../../primitives/tag.js';
|
|
8
7
|
import { errorToast } from '../../../primitives/toast.js';
|
|
9
8
|
import { useTranslations } from '../../../i18n/index.js';
|
|
10
9
|
import { cn } from '../../../internal/lib/utils.js';
|
|
11
|
-
import { isManagedModelId, MANAGED_ENDPOINT_PROVIDERS } from '@kortix/llm-catalog';
|
|
12
10
|
import { wireToModelKey, } from '@kortix/sdk/react';
|
|
13
11
|
import { CheckIcon as Check, FolderSimpleIcon as Folder, DotsThreeIcon as MoreHorizontal, StarIcon as Star, } from '@phosphor-icons/react';
|
|
14
12
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '../../../primitives/dropdown-menu.js';
|
|
@@ -18,11 +16,11 @@ import { formatPricePerMillion, formatTokenCount } from './utils.js';
|
|
|
18
16
|
/** A row status pill as the Models board draws it: sentence case, Roobert,
|
|
19
17
|
* round. `Badge`'s default is the uppercase mono label used elsewhere. */
|
|
20
18
|
const STATUS_PILL = 'rounded-full font-sans text-xs tracking-normal normal-case';
|
|
21
|
-
export function ModelsTabRow({ model, wireId, isRollingAlias, group, providerDisabled, access, enablement, defaults,
|
|
19
|
+
export function ModelsTabRow({ model, wireId, isRollingAlias, group, providerDisabled, access, enablement, defaults, canWrite, }) {
|
|
22
20
|
const tAccess = useTranslations('modelAccess');
|
|
23
21
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
24
22
|
const tList = useTranslations('modelsList');
|
|
25
|
-
const isManaged = group.providerID === 'kortix' &&
|
|
23
|
+
const isManaged = group.providerID === 'kortix' && !model.modelID.includes('/');
|
|
26
24
|
const enabled = !!model.enabled;
|
|
27
25
|
const modelDisabled = access.data?.disabledModels.includes(wireId) ?? false;
|
|
28
26
|
const hiddenFromPicker = !!access.data && !enabled && !providerDisabled && !modelDisabled;
|
|
@@ -36,19 +34,8 @@ export function ModelsTabRow({ model, wireId, isRollingAlias, group, providerDis
|
|
|
36
34
|
// provider — so this is the same comparison as the line above.
|
|
37
35
|
const isAccountDefault = defaults.accountDefault?.modelID === wireId;
|
|
38
36
|
const ctx = formatTokenCount(model.contextWindow);
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
: undefined;
|
|
42
|
-
// The row shows ONE price — the cheapest route's, as "from" —
|
|
43
|
-
// and the hover card shows every route. The routes used to be
|
|
44
|
-
// printed as full sentences under each managed model.
|
|
45
|
-
const hasRoutes = !!pricingRoutes && pricingRoutes.length > 0;
|
|
46
|
-
const priceIn = formatPricePerMillion(hasRoutes
|
|
47
|
-
? Math.min(...pricingRoutes.map((route) => route.input))
|
|
48
|
-
: model.cost?.input);
|
|
49
|
-
const priceOut = formatPricePerMillion(hasRoutes
|
|
50
|
-
? Math.min(...pricingRoutes.map((route) => route.output))
|
|
51
|
-
: model.cost?.output);
|
|
37
|
+
const priceIn = formatPricePerMillion(model.cost?.input);
|
|
38
|
+
const priceOut = formatPricePerMillion(model.cost?.output);
|
|
52
39
|
const turnedOff = modelDisabled || providerDisabled;
|
|
53
40
|
const metaLine = hiddenFromPicker
|
|
54
41
|
? tList('hiddenLine')
|
|
@@ -62,7 +49,7 @@ export function ModelsTabRow({ model, wireId, isRollingAlias, group, providerDis
|
|
|
62
49
|
: null,
|
|
63
50
|
ctx ? tList('context', { value: ctx }) : null,
|
|
64
51
|
priceIn && priceOut
|
|
65
|
-
? tList(
|
|
52
|
+
? tList('price', {
|
|
66
53
|
input: priceIn,
|
|
67
54
|
output: priceOut,
|
|
68
55
|
})
|
|
@@ -74,7 +61,7 @@ export function ModelsTabRow({ model, wireId, isRollingAlias, group, providerDis
|
|
|
74
61
|
// A plain row, NOT a <label>: it holds several controls and a
|
|
75
62
|
// label binds to the FIRST labelable one, so "click the row
|
|
76
63
|
// to toggle" never did what it looked like.
|
|
77
|
-
_jsxs("div", { "data-model-id": wireId, className: "border-border hover:bg-hover flex min-h-13 items-center gap-3 border-t px-4 py-2 transition-[background-color] duration-(--duration-normal) first-of-type:border-t-0", children: [_jsxs("div", { className: "min-w-0 flex-1 space-y-0.5", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: cn('truncate text-sm font-medium', turnedOff ? 'text-muted-foreground' : 'text-foreground'), children: model.modelName }), isProjectDefault && (_jsx(Hint, { label: tI18nComplete.raw('text68cde35131cf'), side: "bottom", children: _jsx(Badge, { variant: "info", size: "sm", className: STATUS_PILL, children: tI18nComplete.raw('text5e06ae1125b5') }) })), isAccountDefault && (_jsx(Hint, { label: tI18nComplete.raw('textd197e66e9634'), side: "bottom", children: _jsx(Badge, { variant: "info", size: "sm", className: STATUS_PILL, children: tI18nComplete.raw('text071c0f5e8495') }) })), hiddenFromPicker && (_jsx(Hint, { label: tAccess('hiddenHint'), side: "bottom", children: _jsx(Badge, { variant: "muted", size: "sm", className: STATUS_PILL, children: tAccess('hidden') }) })), modelDisabled && !providerDisabled && (_jsx(Badge, { variant: "destructive", size: "sm", className: STATUS_PILL, children: tAccess('disabled') })), isRollingAlias && (_jsx(Hint, { label: tI18nComplete.raw('text7482f09d1b13'), side: "bottom", children: _jsx(Tag, { children: tI18nComplete.raw('textf096ba0a2aa6') }) }))] }), metaLine ? (
|
|
64
|
+
_jsxs("div", { "data-model-id": wireId, className: "border-border hover:bg-hover flex min-h-13 items-center gap-3 border-t px-4 py-2 transition-[background-color] duration-(--duration-normal) first-of-type:border-t-0", children: [_jsxs("div", { className: "min-w-0 flex-1 space-y-0.5", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: cn('truncate text-sm font-medium', turnedOff ? 'text-muted-foreground' : 'text-foreground'), children: model.modelName }), isProjectDefault && (_jsx(Hint, { label: tI18nComplete.raw('text68cde35131cf'), side: "bottom", children: _jsx(Badge, { variant: "info", size: "sm", className: STATUS_PILL, children: tI18nComplete.raw('text5e06ae1125b5') }) })), isAccountDefault && (_jsx(Hint, { label: tI18nComplete.raw('textd197e66e9634'), side: "bottom", children: _jsx(Badge, { variant: "info", size: "sm", className: STATUS_PILL, children: tI18nComplete.raw('text071c0f5e8495') }) })), hiddenFromPicker && (_jsx(Hint, { label: tAccess('hiddenHint'), side: "bottom", children: _jsx(Badge, { variant: "muted", size: "sm", className: STATUS_PILL, children: tAccess('hidden') }) })), modelDisabled && !providerDisabled && (_jsx(Badge, { variant: "destructive", size: "sm", className: STATUS_PILL, children: tAccess('disabled') })), isRollingAlias && (_jsx(Hint, { label: tI18nComplete.raw('text7482f09d1b13'), side: "bottom", children: _jsx(Tag, { children: tI18nComplete.raw('textf096ba0a2aa6') }) }))] }), metaLine ? (_jsx("p", { className: "text-muted-foreground text-xs tabular-nums", children: metaLine })) : null] }), _jsx("div", { className: "flex w-18 shrink-0 justify-end", children: _jsx(ModelCapabilityIcons, { chips: true, reasoning: model.capabilities?.reasoning, toolCall: model.capabilities?.toolcall, vision: model.capabilities?.vision }) }), canWrite && (enabled || hiddenFromPicker) ? (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", disabled: defaults.isUpdating, "aria-label": tI18nComplete('text43d1a2b807aa', {
|
|
78
65
|
value0: model.modelName,
|
|
79
66
|
}), title: tI18nComplete.raw('textc3b312278ee5'), className: "text-muted-foreground hover:text-foreground hover:bg-muted data-[state=open]:bg-muted data-[state=open]:text-foreground flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-md transition-[color,background-color] duration-(--duration-normal) disabled:cursor-not-allowed disabled:opacity-50", children: _jsx(MoreHorizontal, { className: "size-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-90", children: [hiddenFromPicker && (_jsx(DropdownMenuItem, { disabled: access.isUpdating, onSelect: () => void access
|
|
80
67
|
.setEnabled({ target: 'model', id: wireId, enabled: false })
|
|
@@ -96,14 +83,3 @@ export function ModelsTabRow({ model, wireId, isRollingAlias, group, providerDis
|
|
|
96
83
|
.setEnabled({ target: 'model', id: wireId, enabled: next })
|
|
97
84
|
.catch((error) => errorToast(error instanceof Error ? error.message : tAccess('modelError'))), className: "shrink-0" })] }, wireId));
|
|
98
85
|
}
|
|
99
|
-
/**
|
|
100
|
-
* The row's price, underlined; hovering opens every serving route's price and
|
|
101
|
-
* the data notes. The routes used to be printed as full sentences under each
|
|
102
|
-
* managed model — four lines of numbers per row.
|
|
103
|
-
*/
|
|
104
|
-
export function ModelPriceHoverCard({ modelName, routes, dataClaim, children, }) {
|
|
105
|
-
const tAccess = useTranslations('modelAccess');
|
|
106
|
-
const tList = useTranslations('modelsList');
|
|
107
|
-
return (_jsxs(HoverCard, { openDelay: 150, children: [_jsx(HoverCardTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "text-foreground decoration-muted-foreground block cursor-help text-left text-xs tabular-nums underline decoration-dotted underline-offset-3", children: children }) }), _jsxs(HoverCardContent, { align: "start", className: "w-98 space-y-3 p-4", children: [_jsxs("div", { className: "flex items-baseline justify-between gap-3", children: [_jsx("p", { className: "text-foreground text-sm font-medium tabular-nums", children: tList('perMillion', { model: modelName }) }), _jsx(Hint, { label: tAccess('pricingEstimate'), children: _jsx("span", { tabIndex: 0, className: "text-muted-foreground cursor-help text-xs", children: tList('estimate') }) })] }), _jsxs("div", { className: "space-y-1.5 text-xs tabular-nums", children: [_jsxs("div", { className: "text-muted-foreground flex gap-2", children: [_jsx("span", { className: "min-w-0 flex-1", children: tList('route') }), _jsx("span", { className: "w-13 shrink-0 text-right", children: tList('input') }), _jsx("span", { className: "w-13 shrink-0 text-right", children: tList('cached') }), _jsx("span", { className: "w-13 shrink-0 text-right", children: tList('output') })] }), routes.map((price) => (_jsxs("div", { className: "text-foreground flex gap-2", "data-pricing-route": price.route, children: [_jsxs("span", { className: "min-w-0 flex-1 truncate", children: [MANAGED_ENDPOINT_PROVIDERS[price.route] ??
|
|
108
|
-
price.route.split('/')[0], price.role === 'preferred' ? ` · ${tAccess('pricingPreferred')}` : ''] }), _jsx("span", { className: "w-13 shrink-0 text-right", children: formatPricePerMillion(price.input) }), _jsx("span", { className: "w-13 shrink-0 text-right", children: formatPricePerMillion(price.cacheRead) }), _jsx("span", { className: "w-13 shrink-0 text-right", children: formatPricePerMillion(price.output) })] }, price.route)))] }), dataClaim ? (_jsxs("div", { className: "border-border text-muted-foreground space-y-1 border-t pt-3 text-xs text-pretty", children: [_jsxs("p", { children: [tAccess('zdrTitle'), ". ", tAccess('zdrDescription')] }), _jsxs("p", { children: [tAccess('usProvidersTitle'), ". ", tAccess('usProvidersDescription')] })] })) : null] })] }));
|
|
109
|
-
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { ModelsTabGroup } from './models-tab-group.js';
|
|
4
|
-
export { ModelPriceHoverCard } from './models-tab-row.js';
|
|
5
4
|
import { useTranslations } from '../../../i18n/index.js';
|
|
6
5
|
/**
|
|
7
6
|
* `ModelsTab` — "which models can this project use".
|
|
@@ -23,7 +22,6 @@ import { useTranslations } from '../../../i18n/index.js';
|
|
|
23
22
|
*/
|
|
24
23
|
import { Button } from '../../../primitives/button.js';
|
|
25
24
|
import { errorToast } from '../../../primitives/toast.js';
|
|
26
|
-
import { isManagedModelId } from '@kortix/llm-catalog';
|
|
27
25
|
import { useModelAccess, useModelDefaults, useModelEnablement, useProjectModelPickerCatalog, useProjectModels, } from '@kortix/sdk/react';
|
|
28
26
|
import { useMemo, useRef, useState } from 'react';
|
|
29
27
|
import { InputGroupSearch, InputGroupSearchClear, InputGroupSearchIcon, InputGroupSearchInput, } from '../../../primitives/input-group.js';
|
|
@@ -74,13 +72,6 @@ export function ModelsTab({ projectId, search: hostSearch, canWrite = false, })
|
|
|
74
72
|
if (models.length === 0) {
|
|
75
73
|
return (_jsxs("div", { className: "flex min-h-[200px] flex-col items-center justify-center gap-1 px-6 text-center", children: [_jsx("p", { className: "text-foreground text-sm", children: tI18nComplete.raw('textc7a9aa43558f') }), _jsx("p", { className: "text-muted-foreground max-w-xs text-xs text-pretty", children: tI18nComplete.raw('text2cedbc7a36d8') })] }));
|
|
76
74
|
}
|
|
77
|
-
// One managed model clears the ZDR + US claim when it serves from Kortix's
|
|
78
|
-
// own managed pool. Only a Morph route breaks it; a missing price feed still
|
|
79
|
-
// serves from the verified US ZDR pool.
|
|
80
|
-
const holdsDataClaim = (modelID) => {
|
|
81
|
-
const routes = pickerCatalog?.managedPricingRoutes?.[modelID];
|
|
82
|
-
return isManagedModelId(modelID) && !routes?.some((route) => route.route === 'morph');
|
|
83
|
-
};
|
|
84
75
|
// No horizontal padding of its own: `CapabilityPageShell` supplies the page
|
|
85
76
|
// column, and 20px more here indented this tab's content past the tab strip
|
|
86
77
|
// that selects it.
|
|
@@ -89,6 +80,6 @@ export function ModelsTab({ projectId, search: hostSearch, canWrite = false, })
|
|
|
89
80
|
.catch((error) => errorToast(error instanceof Error ? error.message : tAccess('resetError'))), children: tI18nComplete.raw('text5eed7e9fc8f3') })), _jsx("span", { className: "text-muted-foreground ml-auto shrink-0 text-xs tabular-nums", children: tList('onCount', { on: enabledCount, total: models.length }) })] }), groups.length === 0 ? (_jsx("div", { className: "flex min-h-[200px] items-center justify-center px-6 text-center", children: _jsx("p", { className: "text-muted-foreground text-xs", children: search
|
|
90
81
|
? tI18nComplete('textb475669b9d30', { value0: search })
|
|
91
82
|
: tI18nComplete.raw('textb12da9202e8c') }) })) : (_jsx("div", { className: "space-y-6", children: groups.map((group) => {
|
|
92
|
-
return (_jsx(ModelsTabGroup, { group: group, access: access, enablement: enablement, defaults: defaults,
|
|
83
|
+
return (_jsx(ModelsTabGroup, { group: group, access: access, enablement: enablement, defaults: defaults, canWrite: canWrite, platformFee: platformFee }, group.providerID));
|
|
93
84
|
}) }))] }));
|
|
94
85
|
}
|
|
@@ -9,7 +9,7 @@ import { useMemo } from 'react';
|
|
|
9
9
|
import { useTranslations } from '../../../i18n/index.js';
|
|
10
10
|
import { PROJECT_ACTIONS } from '../../../internal/lib/project-actions.js';
|
|
11
11
|
import { useProjectCan } from '../../../internal/lib/use-project-can.js';
|
|
12
|
-
import { CODEX_AUTH_JSON_SECRET_NAME, LEGACY_RUNTIME_AUTH_JSON_SECRET_NAME,
|
|
12
|
+
import { CODEX_AUTH_JSON_SECRET_NAME, LEGACY_RUNTIME_AUTH_JSON_SECRET_NAME, } from './constants.js';
|
|
13
13
|
import { isProviderStateLoading } from './provider-loading-state.js';
|
|
14
14
|
import { useLlmProviderCatalogRevision } from './use-live-catalog.js';
|
|
15
15
|
import { buildCodexProvider, buildKortixManagedProvider } from './utils.js';
|
|
@@ -50,7 +50,7 @@ export function useConnectedProviders(projectId, enabled) {
|
|
|
50
50
|
models: Object.fromEntries(Object.entries(pickerCatalog.models).filter(([, model]) => model.enabled !== false)),
|
|
51
51
|
},
|
|
52
52
|
],
|
|
53
|
-
},
|
|
53
|
+
}, tI18nComplete.raw('texte0a770200f93'));
|
|
54
54
|
}, [managedModelsEnabled, pickerCatalog, tI18nComplete]);
|
|
55
55
|
const connectedProviders = useMemo(() => {
|
|
56
56
|
const hasCodexSubscription = secretNames.has(CODEX_AUTH_JSON_SECRET_NAME) ||
|
|
@@ -32,7 +32,7 @@ export declare function buildCodexProvider(ocProviders: RuntimeProvidersSnapshot
|
|
|
32
32
|
* Pure and exported so both rules are pinned by tests; the hook only wires
|
|
33
33
|
* inputs in.
|
|
34
34
|
*/
|
|
35
|
-
export declare function buildKortixManagedProvider(ocProviders: RuntimeProvidersSnapshot,
|
|
35
|
+
export declare function buildKortixManagedProvider(ocProviders: RuntimeProvidersSnapshot, includedHint: string): LlmProviderEntry | null;
|
|
36
36
|
/**
|
|
37
37
|
* The managed provider row's note on the "Add a key" grid.
|
|
38
38
|
*
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getManagedModel } from '@kortix/llm-catalog';
|
|
2
1
|
import { CODEX_AUTH_JSON_SECRET_NAME, LEGACY_RUNTIME_AUTH_JSON_SECRET_NAME } from './constants.js';
|
|
3
2
|
export function providerDisconnectPlan(provider) {
|
|
4
3
|
const removesSubscription = provider.id === 'codex' || provider.id === 'openai';
|
|
@@ -72,32 +71,26 @@ export function buildCodexProvider(ocProviders, tI18nComplete) {
|
|
|
72
71
|
* Pure and exported so both rules are pinned by tests; the hook only wires
|
|
73
72
|
* inputs in.
|
|
74
73
|
*/
|
|
75
|
-
export function buildKortixManagedProvider(ocProviders,
|
|
74
|
+
export function buildKortixManagedProvider(ocProviders, includedHint) {
|
|
76
75
|
const connectedIds = new Set(ocProviders?.connected ?? []);
|
|
77
76
|
const kortix = (ocProviders?.all ?? []).find((p) => p.id === 'kortix');
|
|
78
77
|
if (!kortix || !connectedIds.has('kortix'))
|
|
79
78
|
return null;
|
|
80
79
|
const models = [];
|
|
81
80
|
for (const [id, m] of Object.entries(kortix.models ?? {})) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// Best-effort capability/limit passthrough for the "Models in depth"
|
|
85
|
-
// display (models-tab.tsx / catalog-tab.tsx) — the opencode provider
|
|
86
|
-
// snapshot mirrors these when it has them; `vision`/`limit` otherwise
|
|
87
|
-
// fall back to `@kortix/llm-catalog`'s curated managed-model table,
|
|
88
|
-
// the canonical home for both (see MANAGED_MODELS' doc comment —
|
|
89
|
-
// managed slugs aren't reliably on models.dev, so this table is
|
|
90
|
-
// authoritative for them, not a guess).
|
|
81
|
+
// Managed = served under the `kortix` provider: what Platinum Inference
|
|
82
|
+
// offers. Capabilities and limits come with the served entry.
|
|
91
83
|
const raw = m;
|
|
92
|
-
|
|
84
|
+
if (raw.provider !== 'kortix' || id.includes('/'))
|
|
85
|
+
continue;
|
|
93
86
|
models.push({
|
|
94
87
|
id,
|
|
95
88
|
name: (raw.name || id).replace('(latest)', '').trim(),
|
|
96
89
|
released: raw.release_date ?? null,
|
|
97
90
|
reasoning: raw.reasoning,
|
|
98
91
|
tool_call: raw.tool_call,
|
|
99
|
-
attachment:
|
|
100
|
-
limit: raw.limit
|
|
92
|
+
attachment: raw.attachment,
|
|
93
|
+
limit: raw.limit,
|
|
101
94
|
});
|
|
102
95
|
}
|
|
103
96
|
if (models.length === 0)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { getManagedModel } from '@kortix/llm-catalog';
|
|
4
3
|
import { CheckIcon as Check } from '@phosphor-icons/react';
|
|
5
4
|
import { Copy } from '../../../../icons/copy.js';
|
|
6
5
|
import { useTranslations } from '../../../../i18n/index.js';
|
|
@@ -17,7 +16,7 @@ export function modelLabel(id) {
|
|
|
17
16
|
return tail.replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
18
17
|
}
|
|
19
18
|
export function displayModel(id) {
|
|
20
|
-
return
|
|
19
|
+
return id.split('/').pop() ?? id;
|
|
21
20
|
}
|
|
22
21
|
export function tint(accent, pct) {
|
|
23
22
|
return `color-mix(in oklch, ${accent} ${pct}%, transparent)`;
|
|
@@ -287,26 +287,23 @@ export function GatewayRouting({ projectId, canWrite, projectDefaultPending, })
|
|
|
287
287
|
const [advancedOpen, setAdvancedOpen] = useState(false);
|
|
288
288
|
const [resetOpen, setResetOpen] = useState(false);
|
|
289
289
|
const [availability, setAvailability] = useState({});
|
|
290
|
-
const hydratedPolicySignature =
|
|
290
|
+
const [hydratedPolicySignature, setHydratedPolicySignature] = useState(null);
|
|
291
291
|
const previewRequestId = useRef(0);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
setAdvancedOpen((current) => current || hasAdvancedRoutingConfig(routing.data.project));
|
|
305
|
-
}, [routing.data]);
|
|
292
|
+
// Effective routing also changes when the header's project default changes.
|
|
293
|
+
// Keep an in-progress fallback draft intact unless the persisted project
|
|
294
|
+
// policy itself changed (save, reset, or an external editor update).
|
|
295
|
+
const persistedProject = routing.data?.project;
|
|
296
|
+
const persistedSignature = persistedProject ? editablePolicySignature(persistedProject) : null;
|
|
297
|
+
if (persistedProject && persistedSignature !== hydratedPolicySignature) {
|
|
298
|
+
setHydratedPolicySignature(persistedSignature);
|
|
299
|
+
setDraft(clonePolicy(persistedProject));
|
|
300
|
+
setFallbackMode(fallbackModeForPolicy(persistedProject.defaultFallback));
|
|
301
|
+
setAdvancedOpen((current) => current || hasAdvancedRoutingConfig(persistedProject));
|
|
302
|
+
}
|
|
303
|
+
const previewRoute = routing.preview.mutateAsync;
|
|
306
304
|
// Debounced availability preview: whenever the draft's referenced models
|
|
307
305
|
// change, ask the gateway which of them currently have a connected
|
|
308
306
|
// provider so the chain editor can flag a dead fallback before save.
|
|
309
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: routing.preview's mutateAsync is a stable handle from useGatewayRoutingPolicy and shouldn't retrigger this debounce.
|
|
310
307
|
useEffect(() => {
|
|
311
308
|
if (!draft || !routing.data) {
|
|
312
309
|
setAvailability({});
|
|
@@ -325,7 +322,7 @@ export function GatewayRouting({ projectId, canWrite, projectDefaultPending, })
|
|
|
325
322
|
const timer = setTimeout(() => {
|
|
326
323
|
Promise.all(targets.map(async (model) => {
|
|
327
324
|
try {
|
|
328
|
-
const result = await
|
|
325
|
+
const result = await previewRoute({
|
|
329
326
|
requestedModel: model,
|
|
330
327
|
imageInput: false,
|
|
331
328
|
});
|
|
@@ -345,7 +342,7 @@ export function GatewayRouting({ projectId, canWrite, projectDefaultPending, })
|
|
|
345
342
|
});
|
|
346
343
|
}, 400);
|
|
347
344
|
return () => clearTimeout(timer);
|
|
348
|
-
}, [draft, routing.data, modelDefaults.projectDefault]);
|
|
345
|
+
}, [draft, routing.data, modelDefaults.projectDefault, previewRoute]);
|
|
349
346
|
const models = useMemo(() => {
|
|
350
347
|
const byWire = new Map();
|
|
351
348
|
for (const model of catalogModels) {
|
|
@@ -425,8 +422,9 @@ export function GatewayRouting({ projectId, canWrite, projectDefaultPending, })
|
|
|
425
422
|
if (current.defaultFallback?.models.length)
|
|
426
423
|
return current;
|
|
427
424
|
const inherited = routing.data.effective.defaultFallback.models.filter((model) => model !== primaryModel);
|
|
428
|
-
|
|
429
|
-
|
|
425
|
+
// No model id is hardcoded: the platform fallback already follows the
|
|
426
|
+
// served lineup (`inherited`); otherwise take the first other model.
|
|
427
|
+
const preferred = models.find((model) => modelKeyToWire(model) !== primaryModel);
|
|
430
428
|
return {
|
|
431
429
|
...current,
|
|
432
430
|
defaultFallback: {
|
|
@@ -8,19 +8,14 @@ export type SandboxProviderMode = 'automatic' | 'pinned';
|
|
|
8
8
|
export declare function SandboxProviderLabel({ provider }: {
|
|
9
9
|
provider: string;
|
|
10
10
|
}): import("react").JSX.Element;
|
|
11
|
-
export declare function describeProviderMode(mode: SandboxProviderMode, selectedProvider: SandboxProvider | null, tI18nComplete: UiTranslator): {
|
|
12
|
-
label: string;
|
|
13
|
-
selectedProvider: string | null;
|
|
14
|
-
};
|
|
15
11
|
export declare function describeProviderCoverage(status: ProviderCoverageStatus, tI18nComplete: UiTranslator): {
|
|
16
12
|
label: string;
|
|
17
13
|
tone: 'ok' | 'busy' | 'fail' | 'idle';
|
|
18
14
|
};
|
|
19
15
|
export interface SandboxProviderBadgeCopy {
|
|
20
16
|
states?: Partial<Record<ProviderCoverageStatus, string>>;
|
|
21
|
-
selected?: string;
|
|
22
|
-
selectedAria?: string;
|
|
23
17
|
}
|
|
18
|
+
/** Every sandbox runs on Platinum: a deprecated provider's coverage is not shown. */
|
|
24
19
|
export declare function availableProviderCoverage(coverage: SandboxTemplate['provider_coverage'] | null | undefined): ProviderCoverageEntry[];
|
|
25
20
|
/**
|
|
26
21
|
* The freshest observation across every routable provider, or `null` when
|
|
@@ -34,19 +29,9 @@ export declare function latestObservedAt(coverage: SandboxTemplate['provider_cov
|
|
|
34
29
|
*
|
|
35
30
|
* It replaces `SandboxTemplateProviderCoverage`, which baked its own
|
|
36
31
|
* "Session runtime" label, its badge list and its "Checked …" stamp into one
|
|
37
|
-
* `flex` block.
|
|
38
|
-
* so `sandbox-tab.tsx` ended up nesting a labelled row inside another labelled
|
|
39
|
-
* row — two labels and an un-positionable timestamp in a single wrapping
|
|
40
|
-
* footer. Owning just the badge lets the caller build the row.
|
|
41
|
-
*
|
|
42
|
-
* `SandboxTemplateProviderModeBadge` is gone with it: routing mode is static
|
|
43
|
-
* configuration, not live status, so the card states it as a labelled fact in
|
|
44
|
-
* the spec grid (`describeProviderMode` still supplies the words) rather than
|
|
45
|
-
* floating a bare badge in the runtime strip.
|
|
32
|
+
* `flex` block. Owning just the badge lets the caller build the row.
|
|
46
33
|
*/
|
|
47
|
-
export declare function SandboxProviderBadge({ item,
|
|
34
|
+
export declare function SandboxProviderBadge({ item, copy, }: {
|
|
48
35
|
item: ProviderCoverageEntry;
|
|
49
|
-
/** Pinned mode only — marks the provider sessions actually route to. */
|
|
50
|
-
selected?: boolean;
|
|
51
36
|
copy?: SandboxProviderBadgeCopy;
|
|
52
37
|
}): import("react").JSX.Element;
|
|
@@ -1,21 +1,12 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useTranslations } from '../../../i18n/index.js';
|
|
3
3
|
import { Badge } from '../../../primitives/badge.js';
|
|
4
|
-
import { formatSandboxProvider, isLegacySandboxProvider,
|
|
4
|
+
import { formatSandboxProvider, isLegacySandboxProvider, } from '../../../internal/lib/sandbox-providers.js';
|
|
5
5
|
/** A provider's name, with a `Legacy` badge for the legacy fallback provider (Daytona). */
|
|
6
6
|
export function SandboxProviderLabel({ provider }) {
|
|
7
7
|
const t = useTranslations('settings.sandbox');
|
|
8
8
|
return (_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [formatSandboxProvider(provider), isLegacySandboxProvider(provider) ? (_jsx(Badge, { variant: "muted", size: "sm", children: t('provider.legacy') })) : null] }));
|
|
9
9
|
}
|
|
10
|
-
export function describeProviderMode(mode, selectedProvider, tI18nComplete) {
|
|
11
|
-
if (mode === 'automatic')
|
|
12
|
-
return { label: tI18nComplete.raw('textd461a493a375'), selectedProvider: null };
|
|
13
|
-
const selected = selectedProvider ? formatSandboxProvider(selectedProvider) : null;
|
|
14
|
-
return {
|
|
15
|
-
label: tI18nComplete.raw('text3b3c31642567'),
|
|
16
|
-
selectedProvider: selected,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
10
|
export function describeProviderCoverage(status, tI18nComplete) {
|
|
20
11
|
switch (status) {
|
|
21
12
|
case 'ready':
|
|
@@ -32,10 +23,9 @@ export function describeProviderCoverage(status, tI18nComplete) {
|
|
|
32
23
|
return { label: tI18nComplete.raw('textb764cdc0eab7'), tone: 'idle' };
|
|
33
24
|
}
|
|
34
25
|
}
|
|
26
|
+
/** Every sandbox runs on Platinum: a deprecated provider's coverage is not shown. */
|
|
35
27
|
export function availableProviderCoverage(coverage) {
|
|
36
|
-
return (coverage ?? [])
|
|
37
|
-
.filter((item) => item.available)
|
|
38
|
-
.sort((a, b) => sandboxProviderRank(a.provider) - sandboxProviderRank(b.provider));
|
|
28
|
+
return (coverage ?? []).filter((item) => item.available && !isLegacySandboxProvider(item.provider));
|
|
39
29
|
}
|
|
40
30
|
function providerCoverageVariant(tone) {
|
|
41
31
|
if (tone === 'ok')
|
|
@@ -64,22 +54,12 @@ export function latestObservedAt(coverage) {
|
|
|
64
54
|
*
|
|
65
55
|
* It replaces `SandboxTemplateProviderCoverage`, which baked its own
|
|
66
56
|
* "Session runtime" label, its badge list and its "Checked …" stamp into one
|
|
67
|
-
* `flex` block.
|
|
68
|
-
* so `sandbox-tab.tsx` ended up nesting a labelled row inside another labelled
|
|
69
|
-
* row — two labels and an un-positionable timestamp in a single wrapping
|
|
70
|
-
* footer. Owning just the badge lets the caller build the row.
|
|
71
|
-
*
|
|
72
|
-
* `SandboxTemplateProviderModeBadge` is gone with it: routing mode is static
|
|
73
|
-
* configuration, not live status, so the card states it as a labelled fact in
|
|
74
|
-
* the spec grid (`describeProviderMode` still supplies the words) rather than
|
|
75
|
-
* floating a bare badge in the runtime strip.
|
|
57
|
+
* `flex` block. Owning just the badge lets the caller build the row.
|
|
76
58
|
*/
|
|
77
|
-
export function SandboxProviderBadge({ item,
|
|
59
|
+
export function SandboxProviderBadge({ item, copy = {}, }) {
|
|
78
60
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
79
|
-
const t = useTranslations('settings.sandbox');
|
|
80
|
-
const legacy = isLegacySandboxProvider(item.provider);
|
|
81
61
|
const state = describeProviderCoverage(item.status, tI18nComplete);
|
|
82
62
|
const stateLabel = copy.states?.[item.status] ?? state.label;
|
|
83
63
|
const provider = formatSandboxProvider(item.provider);
|
|
84
|
-
return (_jsxs(Badge, { variant: providerCoverageVariant(state.tone), size: "xs", "aria-label": `${provider}
|
|
64
|
+
return (_jsxs(Badge, { variant: providerCoverageVariant(state.tone), size: "xs", "aria-label": `${provider}: ${stateLabel}`, children: [provider, _jsx("span", { className: "opacity-50", "aria-hidden": "true", children: tI18nComplete.raw('text3b9453dad42b') }), stateLabel] }));
|
|
85
65
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { createContext, useContext } from 'react';
|
|
3
|
+
import { createContext, useContext, useMemo } from 'react';
|
|
4
4
|
import { railGroups } from './rail.js';
|
|
5
5
|
export const DEFAULT_SETTINGS_RAIL_CHROME_COPY = {
|
|
6
6
|
settings: 'Settings',
|
|
@@ -14,13 +14,15 @@ const DEFAULT_VALUE = {
|
|
|
14
14
|
};
|
|
15
15
|
const SettingsRailCopyContext = createContext(DEFAULT_VALUE);
|
|
16
16
|
export function SettingsRailCopyProvider({ groups, chrome, children, }) {
|
|
17
|
-
|
|
17
|
+
const value = useMemo(() => ({ groups, chrome }), [groups, chrome]);
|
|
18
|
+
return (_jsx(SettingsRailCopyContext.Provider, { value: value, children: children }));
|
|
18
19
|
}
|
|
19
20
|
export function useSettingsRailChromeCopy() {
|
|
20
21
|
return useContext(SettingsRailCopyContext).chrome;
|
|
21
22
|
}
|
|
22
23
|
export function useSettingsRailItem(tab) {
|
|
23
|
-
|
|
24
|
+
const { groups } = useContext(SettingsRailCopyContext);
|
|
25
|
+
for (const group of groups) {
|
|
24
26
|
const item = group.items.find((candidate) => candidate.tab === tab);
|
|
25
27
|
if (item)
|
|
26
28
|
return item;
|