@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.
Files changed (228) hide show
  1. package/README.md +8 -4
  2. package/dist/access/access/access-dialog.js +8 -5
  3. package/dist/access/access/copy-row.js +2 -2
  4. package/dist/access/sharing-picker.js +2 -1
  5. package/dist/browser/app-in-browser.js +5 -3
  6. package/dist/browser/browser-panel.js +6 -6
  7. package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
  8. package/dist/browser/sandbox-browser-chrome.js +4 -3
  9. package/dist/customize/agents/agent-access.d.ts +20 -0
  10. package/dist/customize/agents/agent-access.js +17 -0
  11. package/dist/customize/agents/agent-grant-pages.js +5 -6
  12. package/dist/customize/agents/agent-page.js +2 -1
  13. package/dist/customize/agents/agents-page.js +18 -1
  14. package/dist/customize/connectors/add-mcp/add-mcp-server.js +4 -2
  15. package/dist/customize/connectors/connector-routes.d.ts +3 -1
  16. package/dist/customize/connectors/connector-routes.js +18 -0
  17. package/dist/customize/connectors/connectors-page.js +23 -4
  18. package/dist/customize/connectors/detail/connector-advanced-tools.js +4 -6
  19. package/dist/customize/providers/provider-accordion.js +2 -1
  20. package/dist/customize/providers/provider-connect.js +2 -1
  21. package/dist/customize/sections/component/telegram-channel-row.js +1 -1
  22. package/dist/customize/sections/connector-connection-modal.js +11 -9
  23. package/dist/customize/sections/connectors-view.js +11 -13
  24. package/dist/customize/sections/llm-provider/constants.d.ts +0 -1
  25. package/dist/customize/sections/llm-provider/constants.js +0 -2
  26. package/dist/customize/sections/llm-provider/models-tab-group.d.ts +1 -1
  27. package/dist/customize/sections/llm-provider/models-tab-group.js +7 -4
  28. package/dist/customize/sections/llm-provider/models-tab-row.d.ts +2 -18
  29. package/dist/customize/sections/llm-provider/models-tab-row.js +6 -30
  30. package/dist/customize/sections/llm-provider/models-tab.d.ts +0 -1
  31. package/dist/customize/sections/llm-provider/models-tab.js +1 -10
  32. package/dist/customize/sections/llm-provider/use-connected-providers.js +2 -2
  33. package/dist/customize/sections/llm-provider/utils.d.ts +1 -1
  34. package/dist/customize/sections/llm-provider/utils.js +7 -14
  35. package/dist/customize/sections/view/gateway/_shared.js +1 -2
  36. package/dist/customize/sections/view/gateway/gateway-routing.js +18 -20
  37. package/dist/customize/sections/view/sandbox-provider-coverage.d.ts +3 -18
  38. package/dist/customize/sections/view/sandbox-provider-coverage.js +7 -27
  39. package/dist/customize/settings/rail-copy-context.js +5 -3
  40. package/dist/customize/settings/tabs/sandbox-tab.d.ts +2 -27
  41. package/dist/customize/settings/tabs/sandbox-tab.js +13 -112
  42. package/dist/customize/settings/tabs/sandbox-template-form.js +9 -12
  43. package/dist/customize/shared/capability-tabs.js +2 -1
  44. package/dist/customize/shared/entity/entity-modal.d.ts +5 -1
  45. package/dist/customize/shared/entity/entity-modal.js +7 -4
  46. package/dist/customize/skills/remove-skill-button.d.ts +16 -0
  47. package/dist/customize/skills/remove-skill-button.js +42 -0
  48. package/dist/customize/skills/skills-page.js +4 -6
  49. package/dist/customize/triggers/schedule/event-trigger-copy.js +3 -2
  50. package/dist/customize/triggers/schedule/schedule-builder.js +7 -4
  51. package/dist/customize/triggers/schedule/trigger-composer.js +5 -2
  52. package/dist/customize/triggers/schedule/trigger-list.d.ts +0 -2
  53. package/dist/customize/triggers/schedule/trigger-list.js +1 -18
  54. package/dist/customize/triggers/schedule/trigger-tile.d.ts +1 -32
  55. package/dist/customize/triggers/schedule/trigger-tile.js +1 -16
  56. package/dist/customize/triggers/schedule/when-event.js +1 -1
  57. package/dist/diff/diff-view.js +9 -10
  58. package/dist/files/editor/code-editor.js +2 -3
  59. package/dist/files/project/components/change-request-detail-dialog.d.ts +3 -1
  60. package/dist/files/project/components/change-request-detail-dialog.js +3 -5
  61. package/dist/files/project/components/change-request-status-badge.d.ts +12 -0
  62. package/dist/files/project/components/change-request-status-badge.js +27 -0
  63. package/dist/files/project/components/change-requests-panel.js +1 -1
  64. package/dist/files/project/components/drive-explorer.js +2 -1
  65. package/dist/files/project/components/drive-grid-view.js +11 -7
  66. package/dist/files/project/components/drive-list-view.js +4 -4
  67. package/dist/files/project/components/file-breadcrumbs.js +1 -1
  68. package/dist/files/project/components/file-explorer-page.js +1 -1
  69. package/dist/files/project/components/file-history-popover.js +1 -6
  70. package/dist/files/project/components/file-search.js +6 -1
  71. package/dist/files/project/components/open-change-request-dialog.js +2 -1
  72. package/dist/files/project/components/version-selector-logic.d.ts +11 -0
  73. package/dist/files/project/components/version-selector-logic.js +26 -0
  74. package/dist/files/project/components/version-selector.js +11 -20
  75. package/dist/files/project/hooks/use-change-requests.d.ts +14 -1
  76. package/dist/files/project/hooks/use-change-requests.js +44 -25
  77. package/dist/files/project/hooks/use-server-health.js +17 -15
  78. package/dist/files/renderers/docx/docx-viewer.js +4 -6
  79. package/dist/files/renderers/image-renderer.js +6 -24
  80. package/dist/files/renderers/pdf/pdf-renderer.d.ts +3 -1
  81. package/dist/files/renderers/pdf/pdf-renderer.js +2 -2
  82. package/dist/files/renderers/pdf/pdf-viewer.d.ts +3 -0
  83. package/dist/files/renderers/pdf/pdf-viewer.js +16 -7
  84. package/dist/files/renderers/presentation/FullScreenPresentationViewer.js +2 -11
  85. package/dist/files/renderers/show-content-renderer.js +1 -1
  86. package/dist/files/renderers/sqlite-renderer.js +8 -3
  87. package/dist/files/renderers/xlsx/xlsx-viewer.js +15 -16
  88. package/dist/files/tree/components/file-tree-item.js +1 -1
  89. package/dist/files/viewer/file-content-renderer.d.ts +4 -1
  90. package/dist/files/viewer/file-content-renderer.js +2 -2
  91. package/dist/files/viewer/file-preview-modal.js +1 -1
  92. package/dist/files/viewer/use-file-content-state.js +1 -1
  93. package/dist/i18n/en.d.ts +36 -35
  94. package/dist/i18n/en.js +45 -44
  95. package/dist/index.d.ts +1 -1
  96. package/dist/internal/desktop/desktop-back-button.js +5 -3
  97. package/dist/internal/hooks/use-auto-scroll.js +5 -3
  98. package/dist/internal/hooks/use-notification-center.js +21 -15
  99. package/dist/internal/hooks/use-review-session-summary.d.ts +6 -0
  100. package/dist/internal/hooks/use-review-session-summary.js +11 -0
  101. package/dist/internal/lib/browser-error-noise.d.ts +1 -1
  102. package/dist/internal/lib/browser-error-noise.js +1 -1
  103. package/dist/internal/lib/browser-noise/rules/rejections.d.ts +10 -0
  104. package/dist/internal/lib/browser-noise/rules/rejections.js +27 -1
  105. package/dist/internal/lib/provider-branding.js +14 -3
  106. package/dist/internal/lib/trigger-clock.d.ts +42 -0
  107. package/dist/internal/lib/trigger-clock.js +34 -0
  108. package/dist/internal/lib/web-notifications.d.ts +6 -0
  109. package/dist/internal/lib/web-notifications.js +57 -7
  110. package/dist/internal/notifications/notification-bell.d.ts +13 -0
  111. package/dist/internal/notifications/notification-bell.js +1 -1
  112. package/dist/internal/notifications/notification-rows.js +2 -1
  113. package/dist/internal/outcomes/outcome-types.d.ts +5 -0
  114. package/dist/internal/reminders/reminder-filter.d.ts +12 -0
  115. package/dist/internal/reminders/reminder-filter.js +34 -0
  116. package/dist/internal/reminders/reminder-format.d.ts +6 -0
  117. package/dist/internal/reminders/reminder-format.js +20 -2
  118. package/dist/internal/stores/kortix-computer-store.d.ts +1 -1
  119. package/dist/internal/stores/session-hover-store.d.ts +20 -5
  120. package/dist/internal/stores/session-hover-store.js +31 -13
  121. package/dist/internal/stores/session-panel-memory-store.js +2 -0
  122. package/dist/markdown/code/inline-code.js +8 -0
  123. package/dist/markdown/code/output-paths-context.d.ts +18 -0
  124. package/dist/markdown/code/output-paths-context.js +35 -0
  125. package/dist/markdown/genui/components/charts.js +6 -5
  126. package/dist/primitives/count-badge.d.ts +3 -1
  127. package/dist/primitives/count-badge.js +3 -3
  128. package/dist/primitives/glyph-paths-source.js +1 -1
  129. package/dist/primitives/glyph-paths.generated.js +1 -1
  130. package/dist/primitives/map.js +2 -1
  131. package/dist/primitives/preview-image.js +4 -2
  132. package/dist/primitives/textarea.js +1 -1
  133. package/dist/primitives/typed-title.js +12 -14
  134. package/dist/primitives/typing-animation.js +4 -2
  135. package/dist/providers/ui-provider.d.ts +57 -0
  136. package/dist/providers/ui-provider.js +4 -0
  137. package/dist/session/composer/ComposerCard.d.ts +2 -0
  138. package/dist/session/composer/ComposerCard.js +5 -1
  139. package/dist/session/composer/agent-selector.js +17 -5
  140. package/dist/session/composer/composer-chat-input.js +5 -3
  141. package/dist/session/composer/composer-logic.js +8 -7
  142. package/dist/session/composer/composer-toolbar.js +4 -2
  143. package/dist/session/composer/composer-underbar.js +3 -1
  144. package/dist/session/composer/composer.js +34 -5
  145. package/dist/session/composer/draft/composer-draft.js +4 -4
  146. package/dist/session/composer/menus/slash-actions.d.ts +22 -2
  147. package/dist/session/composer/menus/slash-actions.js +20 -0
  148. package/dist/session/composer/menus/slash-items.js +19 -3
  149. package/dist/session/composer/pasted-text.js +3 -2
  150. package/dist/session/composer/stores/queued-draft-store.js +3 -2
  151. package/dist/session/header/reminder-parts.d.ts +294 -0
  152. package/dist/session/header/reminder-parts.js +120 -0
  153. package/dist/session/header/session-reminders-indicator.d.ts +13 -0
  154. package/dist/session/header/session-reminders-indicator.js +142 -35
  155. package/dist/session/media/sandbox-url-detector.js +0 -7
  156. package/dist/session/models/model-availability.d.ts +23 -0
  157. package/dist/session/models/model-availability.js +20 -0
  158. package/dist/session/models/model-grouping.js +1 -4
  159. package/dist/session/models/model-selector.js +23 -14
  160. package/dist/session/models/use-model-connection-gate.js +4 -1
  161. package/dist/session/outcomes/change-request-outcomes.js +24 -3
  162. package/dist/session/outcomes/session-outcomes-provider.d.ts +3 -1
  163. package/dist/session/outcomes/session-outcomes-provider.js +31 -3
  164. package/dist/session/overrides/provider-secret-pool-editor.js +2 -1
  165. package/dist/session/overrides/session-overrides-composer.d.ts +1 -1
  166. package/dist/session/overrides/session-overrides-composer.js +5 -1
  167. package/dist/session/panel/advanced/advanced-panel.js +3 -7
  168. package/dist/session/panel/easy/app-preview.js +12 -2
  169. package/dist/session/panel/easy/easy-panel-logic.d.ts +1 -1
  170. package/dist/session/panel/easy/easy-panel-logic.js +1 -1
  171. package/dist/session/panel/easy/outputs-card.js +2 -1
  172. package/dist/session/panel/easy/panel-card.js +5 -3
  173. package/dist/session/panel/easy/preview-load.d.ts +14 -0
  174. package/dist/session/panel/easy/preview-load.js +15 -0
  175. package/dist/session/panel/easy/step-detail-body.js +2 -7
  176. package/dist/session/panel/mobile-tool-drawer.js +4 -2
  177. package/dist/session/panel/open-session-quick-view.js +2 -1
  178. package/dist/session/panel/panel-fallback.js +8 -4
  179. package/dist/session/panel/session-panel-provider.d.ts +1 -0
  180. package/dist/session/panel/session-panel-provider.js +19 -3
  181. package/dist/session/panel/session-reminders-panel.d.ts +4 -0
  182. package/dist/session/panel/session-reminders-panel.js +109 -0
  183. package/dist/session/panel/shared/use-panel-derivations.js +6 -4
  184. package/dist/session/panel/shared/use-panel-handoffs.d.ts +2 -2
  185. package/dist/session/panel/shared/use-panel-handoffs.js +5 -1
  186. package/dist/session/panel/use-session-panel-layout.js +7 -5
  187. package/dist/session/print/session-print-header.d.ts +0 -10
  188. package/dist/session/print/session-print-header.js +25 -9
  189. package/dist/session/status/session-surface.js +1 -1
  190. package/dist/session/thread/optimistic-turn.d.ts +5 -1
  191. package/dist/session/thread/optimistic-turn.js +8 -6
  192. package/dist/session/thread/session-chat.d.ts +6 -1
  193. package/dist/session/thread/session-chat.js +34 -12
  194. package/dist/session/thread/session-history.js +3 -1
  195. package/dist/session/thread/session-thread.d.ts +10 -1
  196. package/dist/session/thread/session-thread.js +2 -2
  197. package/dist/session/thread/transcript.js +13 -7
  198. package/dist/session/tool/shared/file-list.js +19 -2
  199. package/dist/session/tool/shared/infrastructure-contexts.d.ts +7 -0
  200. package/dist/session/tool/shared/infrastructure-contexts.js +7 -0
  201. package/dist/session/tool/shared/infrastructure-output.js +9 -5
  202. package/dist/session/tool/shared/infrastructure-row-header.js +9 -1
  203. package/dist/session/tool/shared/infrastructure-rows.js +7 -5
  204. package/dist/session/tool/tools/bash-tool.js +10 -6
  205. package/dist/session/tool/tools/web-search-tool.js +25 -3
  206. package/dist/session/turn/burst-step-body.js +4 -0
  207. package/dist/session/turn/recovered-failures.d.ts +8 -0
  208. package/dist/session/turn/recovered-failures.js +32 -0
  209. package/dist/session/turn/streaming-cadence.js +5 -8
  210. package/dist/styles.css +1 -1
  211. package/dist/terminal/session-terminal-panel.js +3 -5
  212. package/dist/theme/theme.js +2 -1
  213. package/dist/workspace/projects/modal/github-import-pickers.js +7 -6
  214. package/dist/workspace/review/review-center.js +13 -10
  215. package/dist/workspace/session-workspace.js +5 -9
  216. package/dist/workspace/sessions/deleted-session-row.js +5 -2
  217. package/dist/workspace/sidebar/footer/project-computer-nav.js +6 -4
  218. package/dist/workspace/sidebar/footer/project-mcp-nav.js +6 -2
  219. package/dist/workspace/sidebar/modal/rename-session-modal.js +8 -3
  220. package/dist/workspace/sidebar/project-session-list.js +52 -55
  221. package/dist/workspace/sidebar/session-brief-hover-card.d.ts +35 -18
  222. package/dist/workspace/sidebar/session-brief-hover-card.js +114 -37
  223. package/dist/workspace/sidebar/session-status-mark.d.ts +15 -1
  224. package/dist/workspace/sidebar/session-status-mark.js +63 -17
  225. package/package.json +7 -3
  226. package/skills/kortix-ui/SKILL.md +1 -1
  227. package/dist/customize/sections/view/sandbox-provider-result.d.ts +0 -47
  228. 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
- useEffect(() => {
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
- }, [policy]);
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
- useEffect(() => {
952
- if (!emailChannelEnabled && draft.provider === 'channel' && draft.platform === 'email') {
953
- setDraft((current) => ({ ...current, platform: 'slack' }));
954
- }
955
- }, [draft.platform, draft.provider, emailChannelEnabled]);
956
- useEffect(() => {
957
- // Channel connectors have no OAuth2-at-creation offer.
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,3 +1,2 @@
1
- export declare const MANAGED_MODEL_ID_SET: Set<string>;
2
1
  export declare const CODEX_AUTH_JSON_SECRET_NAME = "CODEX_AUTH_JSON";
3
2
  export declare const LEGACY_RUNTIME_AUTH_JSON_SECRET_NAME = "OPENCODE_AUTH_JSON";
@@ -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, pickerCatalog, canWrite, holdsDataClaim, platformFee, }: ModelContext & {
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, pickerCatalog, canWrite, holdsDataClaim, platformFee, }) {
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
- const dataClaim = group.providerID === 'kortix' &&
15
- group.rows.every(({ model }) => holdsDataClaim(model.modelID));
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 ? (_jsxs("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') }) }), ' · ', _jsx(Hint, { label: tAccess('usProvidersDescription'), side: "top", className: "max-w-xs", children: _jsx("span", { tabIndex: 0, className: "cursor-help", children: tAccess('usProvidersTitle') }) })] })) : 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, pickerCatalog: pickerCatalog, canWrite: canWrite, holdsDataClaim: holdsDataClaim }, wireId)))] }, group.providerID));
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, useProjectModelPickerCatalog } from '@kortix/sdk/react';
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, pickerCatalog, canWrite, holdsDataClaim, }: ModelRow & ModelContext & {
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, pickerCatalog, canWrite, holdsDataClaim, }) {
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' && isManagedModelId(model.modelID);
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 pricingRoutes = isManaged
40
- ? pickerCatalog?.managedPricingRoutes?.[wireId]
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(hasRoutes ? 'fromPrice' : 'price', {
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 ? (hasRoutes && !hiddenFromPicker && !modelDisabled ? (_jsx(ModelPriceHoverCard, { modelName: model.modelName, routes: pricingRoutes, dataClaim: holdsDataClaim(model.modelID), children: 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', {
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,4 +1,3 @@
1
- export { ModelPriceHoverCard } from './models-tab-row.js';
2
1
  /**
3
2
  * `search` used to be driven by the provider modal's always-on search bar,
4
3
  * which JAY-510 deleted (it sat above the tabs and filtered whichever tab
@@ -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, pickerCatalog: pickerCatalog, canWrite: canWrite, holdsDataClaim: holdsDataClaim, platformFee: platformFee }, group.providerID));
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, MANAGED_MODEL_ID_SET, } from './constants.js';
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
- }, MANAGED_MODEL_ID_SET, tI18nComplete.raw('texte0a770200f93'));
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, managedModelIds: ReadonlySet<string>, includedHint: string): LlmProviderEntry | null;
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, managedModelIds, includedHint) {
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
- if (!managedModelIds.has(id))
83
- continue;
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
- const managed = getManagedModel(id);
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: managed?.vision,
100
- limit: raw.limit ?? managed?.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 getManagedModel(id)?.name ?? id.split('/').pop() ?? id;
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 = useRef(null);
290
+ const [hydratedPolicySignature, setHydratedPolicySignature] = useState(null);
291
291
  const previewRequestId = useRef(0);
292
- useEffect(() => {
293
- if (!routing.data?.project)
294
- return;
295
- const signature = editablePolicySignature(routing.data.project);
296
- // Effective routing also changes when the header's project default changes.
297
- // Keep an in-progress fallback draft intact unless the persisted project
298
- // policy itself changed (save, reset, or an external editor update).
299
- if (hydratedPolicySignature.current === signature)
300
- return;
301
- hydratedPolicySignature.current = signature;
302
- setDraft(clonePolicy(routing.data.project));
303
- setFallbackMode(fallbackModeForPolicy(routing.data.project.defaultFallback));
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 routing.preview.mutateAsync({
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
- const preferred = models.find((model) => modelKeyToWire(model) === 'deepseek-v4.1-flash') ??
429
- models.find((model) => modelKeyToWire(model) !== primaryModel);
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. That composite could only ever be dropped into a layout whole,
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, selected, copy, }: {
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, Fragment as _Fragment } from "react/jsx-runtime";
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, sandboxProviderRank, } from '../../../internal/lib/sandbox-providers.js';
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. That composite could only ever be dropped into a layout whole,
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, selected = false, copy = {}, }) {
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}${legacy ? ` ${t('provider.legacy')}` : ''}${selected ? ` ${copy.selectedAria ?? 'selected'}` : ''}: ${stateLabel}`, children: [provider, legacy ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "opacity-50", "aria-hidden": "true", children: tI18nComplete.raw('text3b9453dad42b') }), t('provider.legacy')] })) : null, selected ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "opacity-50", "aria-hidden": "true", children: tI18nComplete.raw('text3b9453dad42b') }), copy.selected ?? 'Selected'] })) : null, _jsx("span", { className: "opacity-50", "aria-hidden": "true", children: tI18nComplete.raw('text3b9453dad42b') }), stateLabel] }));
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
- return (_jsx(SettingsRailCopyContext.Provider, { value: { groups, chrome }, children: children }));
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
- for (const group of useContext(SettingsRailCopyContext).groups) {
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;