@jini-ai/ui 0.5.5 → 0.5.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/CHANGELOG.md +4 -0
- package/dist/core/theme/validation.js +40 -38
- package/dist/features/a2ui/renderer.js +15 -13
- package/dist/features/about/react/components/AboutTab.js +64 -34
- package/dist/features/about/rules.d.ts +2 -2
- package/dist/features/about/rules.js +156 -129
- package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +4 -3
- package/dist/features/admin-widgets/components/ImagePreviewModal.js +6 -10
- package/dist/features/admin-widgets/components/InfoTip.d.ts +3 -2
- package/dist/features/admin-widgets/components/InfoTip.hooks.js +2 -0
- package/dist/features/admin-widgets/components/InfoTip.js +34 -7
- package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +13 -0
- package/dist/features/admin-widgets/components/InfoTip.rules.js +43 -10
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.d.ts +30 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.d.ts +40 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +128 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.js +18 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.d.ts +14 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.js +12 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.d.ts +20 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.js +21 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.d.ts +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.d.ts +16 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +45 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.js +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.d.ts +32 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.js +26 -0
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +29 -14
- package/dist/features/admin-widgets/index.d.ts +14 -2
- package/dist/features/admin-widgets/index.js +7 -1
- package/dist/features/admin-widgets/styles/admin-widgets.css +1 -0
- package/dist/features/asset-grid/react/components/AssetCard.js +7 -1
- package/dist/features/asset-grid/react/components/AssetGrid.d.ts +1 -1
- package/dist/features/asset-grid/react/components/AssetGrid.js +38 -18
- package/dist/features/asset-grid/react/components/useAssetGridFilters.d.ts +21 -0
- package/dist/features/asset-grid/react/components/useAssetGridFilters.js +19 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +16 -11
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +2 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +35 -11
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.d.ts +6 -6
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.js +10 -129
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.d.ts +50 -0
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.js +95 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.d.ts +56 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.js +80 -0
- package/dist/features/asset-tree-browser/rules.js +40 -22
- package/dist/features/browser-chrome/rules.js +74 -70
- package/dist/features/charts/browser.js +11 -5
- package/dist/features/charts/react.js +2 -2
- package/dist/features/charts/table.js +2 -2
- package/dist/features/command-palette/react/hooks/useCommandPalette.js +3 -9
- package/dist/features/connectors/ConnectorsBrowser.d.ts +4 -4
- package/dist/features/connectors/ConnectorsBrowser.js +26 -14
- package/dist/features/connectors/components/ConnectorCard.js +67 -38
- package/dist/features/connectors/components/ConnectorDetailDrawer.js +62 -31
- package/dist/features/connectors/components/ConnectorGrid.js +11 -6
- package/dist/features/connectors/hooks/useConnectorAuthorization.js +6 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.d.ts +2 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.js +32 -13
- package/dist/features/connectors/hooks/useWiredConnectorsBrowser.d.ts +3 -3
- package/dist/features/connectors/rules.d.ts +8 -1
- package/dist/features/connectors/rules.js +42 -20
- package/dist/features/connectors/types.d.ts +11 -0
- package/dist/features/execution/constants.d.ts +4 -10
- package/dist/features/execution/constants.js +9 -94
- package/dist/features/execution/react/components/ByokProviderForm.d.ts +2 -4
- package/dist/features/execution/react/components/ByokProviderForm.js +140 -43
- package/dist/features/execution/react/components/ExecutionTab.d.ts +1 -2
- package/dist/features/execution/react/components/ExecutionTab.js +52 -30
- package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -3
- package/dist/features/execution/react/components/LocalCliAgentList.js +14 -3
- package/dist/features/execution/react/components/LocalCliAgentSettings.js +14 -3
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +54 -36
- package/dist/features/execution/react/hooks/useReasoningControl.js +114 -78
- package/dist/features/execution/rules.d.ts +2 -2
- package/dist/features/execution/rules.js +31 -15
- package/dist/features/execution/types.d.ts +4 -42
- package/dist/features/execution/types.js +0 -17
- package/dist/features/external-mcp/react/components/ExternalMcpTab.d.ts +6 -2
- package/dist/features/external-mcp/react/components/ExternalMcpTab.js +9 -2
- package/dist/features/file-dropzone/react/components/FileDropzone.js +24 -25
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.d.ts +2 -2
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.js +35 -30
- package/dist/features/file-dropzone/react/components/FileDropzoneThumbnailGrid.js +30 -24
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.d.ts +14 -0
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.js +26 -0
- package/dist/features/html-editor/canvas-content-wrapper.js +13 -13
- package/dist/features/html-editor/canvas-embed-placeholders.js +46 -37
- package/dist/features/html-editor/css.js +76 -69
- package/dist/features/html-editor/editor-blocks.js +47 -33
- package/dist/features/html-editor/editor-serialization.js +6 -5
- package/dist/features/html-editor/protected-elements.js +39 -28
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +4 -4
- package/dist/features/html-editor/source-splice.js +51 -30
- package/dist/features/i18n/dictionaries/settings-dialog.ja.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +1 -0
- package/dist/features/i18n/locale.js +20 -16
- package/dist/features/iframe-pool/react/dom-sync.js +8 -6
- package/dist/features/integrations/react/components/CodexInstallToggleButton.js +19 -4
- package/dist/features/integrations/react/components/IntegrationsTab.js +60 -14
- package/dist/features/interactive-ui/interactive-ui.css +1 -1
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
- package/dist/features/lexical-rich-text-editor/mention-parser.js +60 -57
- package/dist/features/lexical-rich-text-editor/react/hooks/useKeyboardCommands.js +33 -38
- package/dist/features/lexical-rich-text-editor/rules.js +87 -74
- package/dist/features/lexical-rich-text-editor/serialize.js +27 -25
- package/dist/features/mcp-ui/secret-card.js +111 -61
- package/dist/features/mcp-ui/surfaces/confirmation.js +39 -21
- package/dist/features/mcp-ui/surfaces/document.d.ts +1 -1
- package/dist/features/mcp-ui/surfaces/document.js +10 -2
- package/dist/features/mcp-ui/surfaces/fields.js +30 -50
- package/dist/features/mcp-ui/surfaces/form.d.ts +6 -0
- package/dist/features/mcp-ui/surfaces/form.js +43 -21
- package/dist/features/mcp-ui/surfaces/outcome.js +30 -20
- package/dist/features/mcp-ui/surfaces/text-input.js +33 -21
- package/dist/features/mcp-ui/surfaces/tokens.d.ts +6 -1
- package/dist/features/mcp-ui/surfaces/tokens.js +5 -2
- package/dist/features/media-providers/constants.d.ts +1 -0
- package/dist/features/media-providers/constants.js +2 -81
- package/dist/features/media-providers/index.d.ts +1 -1
- package/dist/features/media-providers/ports.d.ts +2 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.d.ts +22 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.js +50 -0
- package/dist/features/media-providers/react/components/MediaProvidersTab.d.ts +5 -6
- package/dist/features/media-providers/react/components/MediaProvidersTab.js +40 -72
- package/dist/features/media-providers/react/components/media-providers-tab-labels.d.ts +11 -0
- package/dist/features/media-providers/react/components/media-providers-tab-labels.js +57 -0
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.d.ts +4 -2
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +37 -23
- package/dist/features/media-providers/rules.js +17 -10
- package/dist/features/media-providers/types.d.ts +4 -22
- package/dist/features/media-providers/types.js +3 -8
- package/dist/features/memory/formatters.js +127 -92
- package/dist/features/memory/react/components/MemoryConnectedPanel.js +92 -36
- package/dist/features/memory/react/components/MemoryList.js +37 -18
- package/dist/features/memory/react/hooks/useMemoryExtractions.store.js +42 -36
- package/dist/features/notifications/react/components/NotificationsTab.js +28 -28
- package/dist/features/observability/long-task.d.ts +0 -12
- package/dist/features/observability/long-task.js +15 -19
- package/dist/features/observability/resource-error.d.ts +0 -10
- package/dist/features/observability/resource-error.js +18 -13
- package/dist/features/observability/stuck-run.js +10 -6
- package/dist/features/observability/telemetry-url.d.ts +6 -0
- package/dist/features/observability/telemetry-url.js +16 -0
- package/dist/features/observability/white-screen.js +12 -24
- package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
- package/dist/features/panel-kit/fetch-query/adapter.react.js +4 -2
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +46 -33
- package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +3 -1
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +3 -1
- package/dist/features/privacy/react/components/PrivacyTab.js +24 -13
- package/dist/features/progress-card/components/ProgressCard.js +7 -3
- package/dist/features/progress-card/reference-adapters.js +59 -54
- package/dist/features/project-locations/react/components/ProjectLocationsTab.js +24 -15
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.d.ts +8 -0
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.js +31 -23
- package/dist/features/resource-dashboard/react/components/ResourceBoard.js +6 -47
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.d.ts +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -6
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +15 -0
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +35 -0
- package/dist/features/resource-dashboard/react/components/ResourceCard.js +5 -16
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.d.ts +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowList.js +3 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +11 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.d.ts +1 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +4 -4
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.d.ts +10 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.js +20 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.d.ts +48 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.js +70 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.js +14 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.d.ts +16 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.js +13 -0
- package/dist/features/resource-dashboard/rules.js +2 -8
- package/dist/features/sketch-editor/dom.js +150 -99
- package/dist/features/sketch-editor/react/components/SketchEditor.js +26 -15
- package/dist/features/skills/react/components/SkillDraftForm.js +13 -19
- package/dist/features/skills/react/components/SkillDraftForm.labels.d.ts +31 -0
- package/dist/features/skills/react/components/SkillDraftForm.labels.js +54 -0
- package/dist/features/skills/react/components/SkillRow.js +38 -18
- package/dist/features/skills/react/components/SkillRow.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillRow.labels.js +18 -0
- package/dist/features/skills/react/components/SkillsTab.js +24 -14
- package/dist/features/skills/react/components/SkillsTab.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillsTab.labels.js +11 -0
- package/dist/features/skills/rules.js +32 -23
- package/dist/features/source-config-list/agent-handles.js +2 -1
- package/dist/features/source-config-list/dependencies.js +53 -49
- package/dist/features/source-config-list/index.d.ts +3 -3
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.js +38 -7
- package/dist/features/source-config-list/react/components/SourceConfigField.js +69 -25
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +76 -20
- package/dist/features/source-config-list/react/components/SourceConfigListView.d.ts +5 -3
- package/dist/features/source-config-list/react/components/SourceConfigListView.js +33 -3
- package/dist/features/source-config-list/react/components/SourceConfigTestControl.js +17 -1
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.d.ts +11 -0
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.js +12 -0
- package/dist/features/source-config-list/types.d.ts +14 -0
- package/dist/features/tab-launcher-menu/react/components/TabLauncherMenu.js +25 -1
- package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +15 -16
- package/dist/features/tab-strip/react/components/TabBar.js +8 -1
- package/dist/features/tabbed-dialog/react/components/TabbedDialog.js +8 -30
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.d.ts +15 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.js +8 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.d.ts +12 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.js +6 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.d.ts +27 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.js +12 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.d.ts +43 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.js +59 -0
- package/dist/features/version-manager/dependencies.d.ts +3 -1
- package/dist/features/version-manager/dependencies.js +3 -2
- package/dist/features/version-manager/react/components/VersionManagerModal.js +10 -6
- package/dist/features/version-manager/react/hooks/useVersionManager.js +7 -4
- package/dist/features/viewer-shell/react/components/CommentSidePanel.js +103 -50
- package/dist/features/viewer-shell/react/components/MarkdownSplitPane.js +28 -8
- package/dist/features/viewer-shell/react/hooks/useCommentReorder.js +22 -16
- package/dist/features/viewer-shell/rules.js +19 -23
- package/dist/react/components/CustomSelect.d.ts +38 -1
- package/dist/react/components/CustomSelect.js +94 -38
- package/dist/react/components/OnboardingDropdown.js +20 -8
- package/dist/react/components/RemixIcon.stylesheet.js +3 -1
- package/dist/react/components/Toast.js +13 -2
- package/dist/react/components/TooltipLayer.js +5 -14
- package/dist/react/components/WorkingDirPicker.js +78 -50
- package/dist/react/components/remixicon-font-recovery.js +38 -30
- package/dist/react/components/select-popover.d.ts +8 -6
- package/dist/react/components/select-popover.js +33 -29
- package/dist/react/mcp-ui/McpUiHost.d.ts +1 -1
- package/dist/react/mcp-ui/McpUiHost.js +10 -11
- package/dist/react/mcp-ui/host-message-source.d.ts +14 -2
- package/dist/react/mcp-ui/host-message-source.js +15 -5
- package/dist/react/mcp-ui/mcp-ui-host-frame.d.ts +41 -0
- package/dist/react/mcp-ui/mcp-ui-host-frame.js +39 -0
- package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +97 -69
- package/dist/renderers/preview-modal-shell/react/components/PreviewModalShell.js +59 -30
- package/dist/renderers/react/components/ArtifactView.js +9 -6
- package/dist/renderers/srcdoc/build.d.ts +4 -1
- package/dist/renderers/srcdoc/build.js +62 -48
- package/dist/styles/admin.css +29 -14
- package/dist/styles/lightbox.css +142 -0
- package/dist/styles/variables.css +128 -0
- package/dist/theme/apply.js +9 -5
- package/dist/utils/auto-open-file.d.ts +2 -1
- package/dist/utils/auto-open-file.js +69 -85
- package/dist/utils/markdown-scroll-sync.js +108 -87
- package/dist/utils/polygon-selection.js +25 -26
- package/dist/utils/smooth-scroll-to-top.d.ts +1 -1
- package/dist/utils/smooth-scroll-to-top.js +2 -32
- package/dist/utils/sse.js +26 -26
- package/dist/utils/unit-bezier.d.ts +7 -0
- package/dist/utils/unit-bezier.js +38 -0
- package/package.json +7 -10
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +0 -46
|
@@ -22,42 +22,8 @@ export function useLocalCliAgentCard({ agent, config, agentTest, cliEnvFields, o
|
|
|
22
22
|
explicitCustomMode,
|
|
23
23
|
onReasoningChange: (next) => onReasoningChange(agent.id, next),
|
|
24
24
|
});
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// built-in fallback. Defaulting to 'fallback' rendered "Built-in list" over
|
|
28
|
-
// a list that may well be live, and told the operator to Rescan to fix a
|
|
29
|
-
// problem they do not have. Unknown provenance shows no badge and no claim.
|
|
30
|
-
const source = agent.modelsSource;
|
|
31
|
-
const sourceLabel = source === 'live' ? t('Live from CLI') : source === 'fallback' ? t('Built-in list') : '';
|
|
32
|
-
const sourceHint = source === 'live'
|
|
33
|
-
? t("Model list comes from this CLI. Default uses the CLI's own config.")
|
|
34
|
-
: source === 'fallback'
|
|
35
|
-
? t('Showing built-in defaults. Click Rescan to pull live models from the CLI.')
|
|
36
|
-
: '';
|
|
37
|
-
// The test result belongs to whichever agent was probed, so a stale verdict
|
|
38
|
-
// from a previously-tested CLI never renders under this one.
|
|
39
|
-
const testing = agentTest.status === 'testing' && agentTest.agentId === agent.id;
|
|
40
|
-
const result = (agentTest.status === 'ok' || agentTest.status === 'error') && agentTest.agentId === agent.id
|
|
41
|
-
? agentTest
|
|
42
|
-
: null;
|
|
43
|
-
// The "use the binary that actually ran" / "clear the override" repair
|
|
44
|
-
// affordance — only meaningful when a successful test silently fell back
|
|
45
|
-
// off a configured override, AND this agent's catalog names which field
|
|
46
|
-
// that override lives in. See `agentExecutableRepairState`'s doc.
|
|
47
|
-
//
|
|
48
|
-
// `AgentTestState`'s 'ok' variant spells success as `status: 'ok'`, not an
|
|
49
|
-
// `ok: true` field — `agentExecutableRepairState` takes the latter (it
|
|
50
|
-
// mirrors `ExecutionPort.testAgent`'s raw resolved shape, one layer below
|
|
51
|
-
// this state union), so the two must be translated explicitly here rather
|
|
52
|
-
// than passing `result` straight through.
|
|
53
|
-
const repair = result?.status === 'ok'
|
|
54
|
-
? agentExecutableRepairState({
|
|
55
|
-
ok: true,
|
|
56
|
-
usedExecutableSource: result.usedExecutableSource,
|
|
57
|
-
detectedExecutablePath: result.detectedExecutablePath,
|
|
58
|
-
})
|
|
59
|
-
: null;
|
|
60
|
-
const repairField = repair ? binPathEnvField(cliEnvFields, agent.id) : null;
|
|
25
|
+
const { source, sourceLabel, sourceHint } = modelSourcePresentation({ source: agent.modelsSource, t });
|
|
26
|
+
const { testing, result, repair, repairField } = agentTestPresentation({ agent, agentTest, cliEnvFields });
|
|
61
27
|
const openUrl = (url) => {
|
|
62
28
|
if (!url)
|
|
63
29
|
return;
|
|
@@ -107,4 +73,56 @@ export function useLocalCliAgentCard({ agent, config, agentTest, cliEnvFields, o
|
|
|
107
73
|
selectReasoning,
|
|
108
74
|
};
|
|
109
75
|
}
|
|
76
|
+
/** Model-list provenance claims, translated only when the host supplied a source. */
|
|
77
|
+
function modelSourcePresentation({ source, t }, _options = {}) {
|
|
78
|
+
// `modelsSource` is optional in the contract, so an absent value means the
|
|
79
|
+
// host did not say where the list came from — NOT that it came from a
|
|
80
|
+
// built-in fallback. Defaulting to 'fallback' rendered "Built-in list" over
|
|
81
|
+
// a list that may well be live, and told the operator to Rescan to fix a
|
|
82
|
+
// problem they do not have. Unknown provenance shows no badge and no claim.
|
|
83
|
+
switch (source) {
|
|
84
|
+
case 'live':
|
|
85
|
+
return {
|
|
86
|
+
source,
|
|
87
|
+
sourceLabel: t('Live from CLI'),
|
|
88
|
+
sourceHint: t("Model list comes from this CLI. Default uses the CLI's own config."),
|
|
89
|
+
};
|
|
90
|
+
case 'fallback':
|
|
91
|
+
return {
|
|
92
|
+
source,
|
|
93
|
+
sourceLabel: t('Built-in list'),
|
|
94
|
+
sourceHint: t('Showing built-in defaults. Click Rescan to pull live models from the CLI.'),
|
|
95
|
+
};
|
|
96
|
+
default:
|
|
97
|
+
return { source, sourceLabel: '', sourceHint: '' };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/** Scope probe evidence and its executable repair affordance to the card being rendered. */
|
|
101
|
+
function agentTestPresentation({ agent, agentTest, cliEnvFields }, _options = {}) {
|
|
102
|
+
// The test result belongs to whichever agent was probed, so a stale verdict
|
|
103
|
+
// from a previously-tested CLI never renders under this one.
|
|
104
|
+
const testing = agentTest.status === 'testing' && agentTest.agentId === agent.id;
|
|
105
|
+
const result = (agentTest.status === 'ok' || agentTest.status === 'error') && agentTest.agentId === agent.id
|
|
106
|
+
? agentTest
|
|
107
|
+
: null;
|
|
108
|
+
// The "use the binary that actually ran" / "clear the override" repair
|
|
109
|
+
// affordance — only meaningful when a successful test silently fell back
|
|
110
|
+
// off a configured override, AND this agent's catalog names which field
|
|
111
|
+
// that override lives in. See `agentExecutableRepairState`'s doc.
|
|
112
|
+
//
|
|
113
|
+
// `AgentTestState`'s 'ok' variant spells success as `status: 'ok'`, not an
|
|
114
|
+
// `ok: true` field — `agentExecutableRepairState` takes the latter (it
|
|
115
|
+
// mirrors `ExecutionPort.testAgent`'s raw resolved shape, one layer below
|
|
116
|
+
// this state union), so the two must be translated explicitly here rather
|
|
117
|
+
// than passing `result` straight through.
|
|
118
|
+
const repair = result?.status === 'ok'
|
|
119
|
+
? agentExecutableRepairState({
|
|
120
|
+
ok: true,
|
|
121
|
+
usedExecutableSource: result.usedExecutableSource,
|
|
122
|
+
detectedExecutablePath: result.detectedExecutablePath,
|
|
123
|
+
})
|
|
124
|
+
: null;
|
|
125
|
+
const repairField = repair ? binPathEnvField(cliEnvFields, agent.id) : null;
|
|
126
|
+
return { testing, result, repair, repairField };
|
|
127
|
+
}
|
|
110
128
|
//# sourceMappingURL=useLocalCliAgentCard.js.map
|
|
@@ -2,106 +2,36 @@ import { useCallback, useEffect } from 'react';
|
|
|
2
2
|
import { CUSTOM_MODEL_SENTINEL } from '../../constants.js';
|
|
3
3
|
import { modelIdForReasoningLevel, pickerModelOptions, reasoningModelGroupFor, reasoningModelGroups, selectedAgentModel, selectedAgentReasoning, shouldShowCustomModelInput, splitReasoningModelId, } from '../../rules.js';
|
|
4
4
|
export function useReasoningControl(optionsOrAgent, maybeConfig, maybeExplicitCustomMode) {
|
|
5
|
-
const { agent, config, explicitCustomMode = false, onReasoningChange } =
|
|
6
|
-
? optionsOrAgent
|
|
7
|
-
: {
|
|
8
|
-
agent: optionsOrAgent,
|
|
9
|
-
config: maybeConfig,
|
|
10
|
-
explicitCustomMode: maybeExplicitCustomMode ?? false,
|
|
11
|
-
};
|
|
5
|
+
const { agent, config, explicitCustomMode = false, onReasoningChange } = reasoningControlOptions(optionsOrAgent, maybeConfig, maybeExplicitCustomMode);
|
|
12
6
|
const models = agent.models ?? [];
|
|
13
7
|
const hasModels = models.length > 0;
|
|
14
8
|
const resolvedModel = selectedAgentModel(config, agent);
|
|
15
9
|
const rawModel = config.modelByAgentId?.[agent.id] ?? '';
|
|
16
|
-
|
|
17
|
-
// rather than on the agent's id — adding a third runtime with either shape is a def change, not
|
|
18
|
-
// an edit here.
|
|
19
|
-
//
|
|
20
|
-
// `reasoningOptions` — one flat vocabulary that travels to the CLI as its own flag
|
|
21
|
-
// (`claude --effort high`, codex's `-c model_reasoning_effort=...`).
|
|
22
|
-
// The choice is its own persisted value; `onReasoningChange` owns it.
|
|
23
|
-
// `reasoningInModelId` — no effort flag exists; the level is a suffix on the model id itself
|
|
24
|
-
// (antigravity's `gemini-3.1-pro-high`). The choice IS the model, so
|
|
25
|
-
// it goes through `onModelChange`, and the available levels are
|
|
26
|
-
// derived PER BASE MODEL from the agent's own catalog — they are not
|
|
27
|
-
// uniform (`gemini-3.1-pro` has no `-medium`, and `agy --model`
|
|
28
|
-
// rejects one), so a fixed dropdown would offer ids the CLI refuses.
|
|
29
|
-
const suffixLevels = agent.reasoningInModelId?.levels ?? [];
|
|
30
|
-
const suffixLevelIds = suffixLevels.map((level) => level.id);
|
|
31
|
-
const modelGroups = suffixLevels.length > 0 ? reasoningModelGroups(models, suffixLevels) : null;
|
|
32
|
-
const activeGroup = modelGroups ? reasoningModelGroupFor(modelGroups, resolvedModel, suffixLevelIds) : null;
|
|
33
|
-
const activeLevel = modelGroups ? splitReasoningModelId(resolvedModel, suffixLevelIds).level : null;
|
|
10
|
+
const { suffixLevels, suffixLevelIds, modelGroups, activeGroup, activeLevel } = suffixReasoning({ agent, models, resolvedModel });
|
|
34
11
|
const flatReasoningOptions = agent.reasoningOptions ?? [];
|
|
35
|
-
|
|
36
|
-
// uniformly across the agent (Codex — see `AgentModelOption.reasoning`'s doc) declares them on the
|
|
37
|
-
// resolved model's own catalog row. `undefined` there means "this model's entry has nothing
|
|
38
|
-
// model-specific to say", so it falls back to the agent-wide union below — the same list every
|
|
39
|
-
// model rendered before this field existed. An explicit `[]` is honored AS-IS, even though a model
|
|
40
|
-
// with genuinely zero levels then hides the control: falling back to the union for `[]` too would
|
|
41
|
-
// just move today's "every model sees every level" bug one layer down instead of fixing it.
|
|
42
|
-
const selectedModelReasoning = models.find((model) => model.id === resolvedModel)?.reasoning;
|
|
43
|
-
// Exactly one effort control, whichever shape declared it. `reasoningOptions` wins if a def ever
|
|
44
|
-
// declares both, rather than rendering two controls that disagree about where the choice lands.
|
|
45
|
-
const reasoningOptions = flatReasoningOptions.length === 0
|
|
46
|
-
? (activeGroup?.levels ?? [])
|
|
47
|
-
: selectedModelReasoning === undefined
|
|
48
|
-
? flatReasoningOptions
|
|
49
|
-
: selectedModelReasoning;
|
|
12
|
+
const reasoningOptions = effortOptions({ flatReasoningOptions, activeGroup, models, resolvedModel });
|
|
50
13
|
const hasReasoning = reasoningOptions.length > 0;
|
|
51
|
-
const
|
|
52
|
-
? selectedAgentReasoning(config, agent)
|
|
53
|
-
: (activeLevel ?? reasoningOptions[0]?.id ?? '');
|
|
54
|
-
// The persisted (or agent-wide-default) pick can name a level the narrowed list above does not
|
|
55
|
-
// actually offer for the CURRENT model — that is the whole point of narrowing. Rendering it anyway
|
|
56
|
-
// would just relocate today's bug: the `<select>` below has no matching `<option>`, so it would
|
|
57
|
-
// silently show whatever the browser highlights first while the underlying value stays wrong. This
|
|
58
|
-
// guards what actually renders; the effect further down clears the persisted copy so every other
|
|
59
|
-
// reader of `config.reasoningByAgentId` (not just this hook) sees the correction too.
|
|
60
|
-
const reasoningSupported = reasoningOptions.some((option) => option.id === rawReasoningValue);
|
|
61
|
-
const reasoningValue = reasoningSupported ? rawReasoningValue : (reasoningOptions[0]?.id ?? '');
|
|
14
|
+
const reasoningValue = effortValue({ agent, config, flatReasoningOptions, activeLevel, reasoningOptions });
|
|
62
15
|
// A base model with exactly one variant has a real, fixed level worth showing — but nothing to
|
|
63
16
|
// choose between, so the control is shown disabled rather than offering an illusion of choice.
|
|
64
17
|
const reasoningDisabled = flatReasoningOptions.length === 0 && reasoningOptions.length < 2;
|
|
65
18
|
const reasoningOptionIdsKey = reasoningOptions.map((option) => option.id).join('|');
|
|
66
19
|
useEffect(() => {
|
|
67
|
-
// The reasoningInModelId path has no reasoning value of its own to clear — the level lives
|
|
68
|
-
// inside the model id itself, and picking a new base model already replaces it.
|
|
69
|
-
if (flatReasoningOptions.length === 0)
|
|
70
|
-
return;
|
|
71
20
|
if (!onReasoningChange)
|
|
72
21
|
return;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return;
|
|
76
|
-
if (reasoningOptions.some((option) => option.id === persisted))
|
|
77
|
-
return;
|
|
78
|
-
onReasoningChange('');
|
|
22
|
+
if (isStaleReasoningPick({ agent, config, flatReasoningOptions, reasoningOptions }))
|
|
23
|
+
onReasoningChange('');
|
|
79
24
|
// `reasoningOptionIdsKey` stands in for `reasoningOptions` (a fresh array every render) so this
|
|
80
25
|
// only re-runs when the narrowed vocabulary actually changes, not on every unrelated re-render.
|
|
81
26
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
82
27
|
}, [flatReasoningOptions.length, onReasoningChange, config.reasoningByAgentId, agent.id, reasoningOptionIdsKey]);
|
|
83
|
-
|
|
84
|
-
// free-text model flag, or validates the id against a live catalog and
|
|
85
|
-
// rejects unknown ones. `undefined` allows it, matching every adapter's
|
|
86
|
-
// default before this field existed.
|
|
87
|
-
const allowCustomModel = agent.supportsCustomModel !== false && modelGroups === null;
|
|
88
|
-
const knownModelIds = models.map((model) => model.id);
|
|
89
|
-
const customActive = allowCustomModel && hasModels && shouldShowCustomModelInput(resolvedModel, knownModelIds, explicitCustomMode);
|
|
28
|
+
const { allowCustomModel, knownModelIds, customActive } = customModelState({ agent, modelGroups, models, resolvedModel, explicitCustomMode });
|
|
90
29
|
// A model-suffix agent picks a BASE model here; the effort control below supplies the rest of the
|
|
91
30
|
// id. Everything else about the field — search, labels, provenance badge — is unchanged.
|
|
92
31
|
const modelChoices = modelGroups
|
|
93
32
|
? modelGroups.map((group) => ({ id: group.baseId, label: group.label }))
|
|
94
33
|
: pickerModelOptions({ models });
|
|
95
|
-
|
|
96
|
-
// row. This is display-only: the saved model and dispatch resolution keep the operator's pick.
|
|
97
|
-
const selectedModel = models.find((model) => model.id === resolvedModel);
|
|
98
|
-
const selectValue = customActive
|
|
99
|
-
? CUSTOM_MODEL_SENTINEL
|
|
100
|
-
: modelGroups
|
|
101
|
-
? (activeGroup?.baseId ?? '')
|
|
102
|
-
: selectedModel?.identityKind === 'alias'
|
|
103
|
-
? (selectedModel.resolvedId || resolvedModel)
|
|
104
|
-
: resolvedModel;
|
|
34
|
+
const selectValue = modelSelectValue({ customActive, modelGroups, activeGroup, models, resolvedModel });
|
|
105
35
|
// While the custom box is open, the text field must show the operator's raw
|
|
106
36
|
// typed text (which may not resolve to anything yet) rather than the
|
|
107
37
|
// resolved-with-fallback value — otherwise every keystroke would show a
|
|
@@ -151,4 +81,110 @@ export function useReasoningControl(optionsOrAgent, maybeConfig, maybeExplicitCu
|
|
|
151
81
|
resolveReasoningModelId,
|
|
152
82
|
};
|
|
153
83
|
}
|
|
84
|
+
/** The two call shapes (options object, or the older positional `agent, config, explicitCustomMode`)
|
|
85
|
+
* as one options object. */
|
|
86
|
+
function reasoningControlOptions(optionsOrAgent, maybeConfig, maybeExplicitCustomMode) {
|
|
87
|
+
if ('agent' in optionsOrAgent && 'config' in optionsOrAgent)
|
|
88
|
+
return optionsOrAgent;
|
|
89
|
+
return {
|
|
90
|
+
agent: optionsOrAgent,
|
|
91
|
+
config: maybeConfig,
|
|
92
|
+
explicitCustomMode: maybeExplicitCustomMode ?? false,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The model-suffix reasoning shape: the agent's declared suffix levels, its catalog grouped by base
|
|
97
|
+
* model, and where the resolved model sits in those groups. All `null` (and empty) for an agent
|
|
98
|
+
* without `reasoningInModelId`.
|
|
99
|
+
*
|
|
100
|
+
* Two ways an agent can expose a reasoning-effort axis, and the card branches on the DECLARATION
|
|
101
|
+
* rather than on the agent's id — adding a third runtime with either shape is a def change, not
|
|
102
|
+
* an edit here.
|
|
103
|
+
*
|
|
104
|
+
* `reasoningOptions` — one flat vocabulary that travels to the CLI as its own flag
|
|
105
|
+
* (`claude --effort high`, codex's `-c model_reasoning_effort=...`).
|
|
106
|
+
* The choice is its own persisted value; `onReasoningChange` owns it.
|
|
107
|
+
* `reasoningInModelId` — no effort flag exists; the level is a suffix on the model id itself
|
|
108
|
+
* (antigravity's `gemini-3.1-pro-high`). The choice IS the model, so
|
|
109
|
+
* it goes through `onModelChange`, and the available levels are
|
|
110
|
+
* derived PER BASE MODEL from the agent's own catalog — they are not
|
|
111
|
+
* uniform (`gemini-3.1-pro` has no `-medium`, and `agy --model`
|
|
112
|
+
* rejects one), so a fixed dropdown would offer ids the CLI refuses.
|
|
113
|
+
*/
|
|
114
|
+
function suffixReasoning({ agent, models, resolvedModel }) {
|
|
115
|
+
const suffixLevels = agent.reasoningInModelId?.levels ?? [];
|
|
116
|
+
const suffixLevelIds = suffixLevels.map((level) => level.id);
|
|
117
|
+
if (suffixLevels.length === 0) {
|
|
118
|
+
return { suffixLevels, suffixLevelIds, modelGroups: null, activeGroup: null, activeLevel: null };
|
|
119
|
+
}
|
|
120
|
+
const modelGroups = reasoningModelGroups(models, suffixLevels);
|
|
121
|
+
const activeGroup = reasoningModelGroupFor(modelGroups, resolvedModel, suffixLevelIds);
|
|
122
|
+
const activeLevel = splitReasoningModelId(resolvedModel, suffixLevelIds).level;
|
|
123
|
+
return { suffixLevels, suffixLevelIds, modelGroups, activeGroup, activeLevel };
|
|
124
|
+
}
|
|
125
|
+
/** The effort options the reasoning dropdown offers for the resolved model. */
|
|
126
|
+
function effortOptions({ flatReasoningOptions, activeGroup, models, resolvedModel }) {
|
|
127
|
+
// Exactly one effort control, whichever shape declared it. `reasoningOptions` wins if a def ever
|
|
128
|
+
// declares both, rather than rendering two controls that disagree about where the choice lands.
|
|
129
|
+
if (flatReasoningOptions.length === 0)
|
|
130
|
+
return activeGroup?.levels ?? [];
|
|
131
|
+
// Per-model narrowing: a runtime whose catalog reports reasoning levels PER MODEL rather than
|
|
132
|
+
// uniformly across the agent (Codex — see `AgentModelOption.reasoning`'s doc) declares them on the
|
|
133
|
+
// resolved model's own catalog row. `undefined` there means "this model's entry has nothing
|
|
134
|
+
// model-specific to say", so it falls back to the agent-wide union below — the same list every
|
|
135
|
+
// model rendered before this field existed. An explicit `[]` is honored AS-IS, even though a model
|
|
136
|
+
// with genuinely zero levels then hides the control: falling back to the union for `[]` too would
|
|
137
|
+
// just move today's "every model sees every level" bug one layer down instead of fixing it.
|
|
138
|
+
const selectedModelReasoning = models.find((model) => model.id === resolvedModel)?.reasoning;
|
|
139
|
+
return selectedModelReasoning === undefined ? flatReasoningOptions : selectedModelReasoning;
|
|
140
|
+
}
|
|
141
|
+
/** The value the reasoning select renders: the persisted / derived pick, or the first offered level
|
|
142
|
+
* when that pick is not among the options. */
|
|
143
|
+
function effortValue({ agent, config, flatReasoningOptions, activeLevel, reasoningOptions }) {
|
|
144
|
+
const rawReasoningValue = flatReasoningOptions.length > 0
|
|
145
|
+
? selectedAgentReasoning(config, agent)
|
|
146
|
+
: (activeLevel ?? reasoningOptions[0]?.id ?? '');
|
|
147
|
+
// The persisted (or agent-wide-default) pick can name a level the narrowed list above does not
|
|
148
|
+
// actually offer for the CURRENT model — that is the whole point of narrowing. Rendering it anyway
|
|
149
|
+
// would just relocate today's bug: the `<select>` below has no matching `<option>`, so it would
|
|
150
|
+
// silently show whatever the browser highlights first while the underlying value stays wrong. This
|
|
151
|
+
// guards what actually renders; the effect further down clears the persisted copy so every other
|
|
152
|
+
// reader of `config.reasoningByAgentId` (not just this hook) sees the correction too.
|
|
153
|
+
const reasoningSupported = reasoningOptions.some((option) => option.id === rawReasoningValue);
|
|
154
|
+
return reasoningSupported ? rawReasoningValue : (reasoningOptions[0]?.id ?? '');
|
|
155
|
+
}
|
|
156
|
+
/** Whether the agent's persisted flat-reasoning pick names a level the current options no longer
|
|
157
|
+
* offer, so the hook should ask the host to clear it. */
|
|
158
|
+
function isStaleReasoningPick({ agent, config, flatReasoningOptions, reasoningOptions }) {
|
|
159
|
+
// The reasoningInModelId path has no reasoning value of its own to clear — the level lives
|
|
160
|
+
// inside the model id itself, and picking a new base model already replaces it.
|
|
161
|
+
if (flatReasoningOptions.length === 0)
|
|
162
|
+
return false;
|
|
163
|
+
const persisted = config.reasoningByAgentId?.[agent.id]?.trim();
|
|
164
|
+
if (!persisted)
|
|
165
|
+
return false;
|
|
166
|
+
return !reasoningOptions.some((option) => option.id === persisted);
|
|
167
|
+
}
|
|
168
|
+
/** The model select's value: the Custom sentinel, a suffix agent's base id, or the resolved model. */
|
|
169
|
+
function modelSelectValue({ customActive, modelGroups, activeGroup, models, resolvedModel }) {
|
|
170
|
+
if (customActive)
|
|
171
|
+
return CUSTOM_MODEL_SENTINEL;
|
|
172
|
+
if (modelGroups)
|
|
173
|
+
return activeGroup?.baseId ?? '';
|
|
174
|
+
// Persisted aliases stay known in the full catalog above, but the picker selects their concrete
|
|
175
|
+
// row. This is display-only: the saved model and dispatch resolution keep the operator's pick.
|
|
176
|
+
const selectedModel = models.find((model) => model.id === resolvedModel);
|
|
177
|
+
return selectedModel?.identityKind === 'alias' ? (selectedModel.resolvedId || resolvedModel) : resolvedModel;
|
|
178
|
+
}
|
|
179
|
+
/** Whether this agent takes a free-text model id at all, and whether the free-text box is open now. */
|
|
180
|
+
function customModelState({ agent, modelGroups, models, resolvedModel, explicitCustomMode }) {
|
|
181
|
+
// Adapters opt out via `supportsCustomModel: false` when their CLI has no
|
|
182
|
+
// free-text model flag, or validates the id against a live catalog and
|
|
183
|
+
// rejects unknown ones. `undefined` allows it, matching every adapter's
|
|
184
|
+
// default before this field existed.
|
|
185
|
+
const allowCustomModel = agent.supportsCustomModel !== false && modelGroups === null;
|
|
186
|
+
const knownModelIds = models.map((model) => model.id);
|
|
187
|
+
const customActive = allowCustomModel && models.length > 0 && shouldShowCustomModelInput(resolvedModel, knownModelIds, explicitCustomMode);
|
|
188
|
+
return { allowCustomModel, knownModelIds, customActive };
|
|
189
|
+
}
|
|
154
190
|
//# sourceMappingURL=useReasoningControl.js.map
|
|
@@ -109,8 +109,8 @@ export declare function isBaseUrlInvalid(config: ByokConfig): boolean;
|
|
|
109
109
|
*/
|
|
110
110
|
export declare function nextConfigForPresetSelect(config: ByokConfig, preset: ProviderPreset): ByokConfig;
|
|
111
111
|
/** Switching protocol by hand drops the preset selection (the old preset no
|
|
112
|
-
* longer speaks this protocol) and
|
|
113
|
-
*
|
|
112
|
+
* longer speaks this protocol) and keeps operator-entered endpoints. Hosts
|
|
113
|
+
* seed endpoints through presets; protocol selection never chooses a vendor. */
|
|
114
114
|
export declare function nextConfigForProtocolSelect(config: ByokConfig, protocol: ByokConfig['protocol']): ByokConfig;
|
|
115
115
|
/** Mode changes never discard BYOK credentials — flipping to Local CLI and
|
|
116
116
|
* back must not make the operator retype their key. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isAllowedEndpointUrl } from '../../utils/endpoint-policy.js';
|
|
2
|
-
import { API_KEY_CROSS_VENDOR_WARNING, API_KEY_TOO_SHORT_WARNING, CUSTOM_PRESET_ID,
|
|
2
|
+
import { API_KEY_CROSS_VENDOR_WARNING, API_KEY_TOO_SHORT_WARNING, CUSTOM_PRESET_ID, MIN_PLAUSIBLE_API_KEY_LENGTH, } from './constants.js';
|
|
3
3
|
/**
|
|
4
4
|
* Pure decision logic for the execution tab. Everything here is total and
|
|
5
5
|
* side-effect free so the React layer stays a thin renderer — same split the
|
|
@@ -231,21 +231,26 @@ export function nextConfigForPresetSelect(config, preset) {
|
|
|
231
231
|
if (preset.custom) {
|
|
232
232
|
return { ...config, providerId: null, savedByProviderId };
|
|
233
233
|
}
|
|
234
|
-
const saved = savedByProviderId[preset.id];
|
|
235
234
|
return {
|
|
236
235
|
...config,
|
|
237
236
|
providerId: preset.id,
|
|
238
237
|
protocol: preset.protocol,
|
|
238
|
+
...presetCredentials(savedByProviderId[preset.id], preset),
|
|
239
|
+
savedByProviderId,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/** A preset's saved draft, or blank credentials seeded with its base URL and top preferred model. */
|
|
243
|
+
function presetCredentials(saved, preset) {
|
|
244
|
+
return {
|
|
239
245
|
apiKey: saved?.apiKey ?? '',
|
|
240
|
-
baseUrl: saved?.baseUrl ??
|
|
246
|
+
baseUrl: saved?.baseUrl ?? preset.baseUrl,
|
|
241
247
|
model: saved?.model ?? preset.preferredModels[0] ?? '',
|
|
242
248
|
maxTokens: saved?.maxTokens,
|
|
243
|
-
savedByProviderId,
|
|
244
249
|
};
|
|
245
250
|
}
|
|
246
251
|
/** Switching protocol by hand drops the preset selection (the old preset no
|
|
247
|
-
* longer speaks this protocol) and
|
|
248
|
-
*
|
|
252
|
+
* longer speaks this protocol) and keeps operator-entered endpoints. Hosts
|
|
253
|
+
* seed endpoints through presets; protocol selection never chooses a vendor. */
|
|
249
254
|
export function nextConfigForProtocolSelect(config, protocol) {
|
|
250
255
|
if (config.protocol === protocol)
|
|
251
256
|
return config;
|
|
@@ -253,7 +258,7 @@ export function nextConfigForProtocolSelect(config, protocol) {
|
|
|
253
258
|
...config,
|
|
254
259
|
protocol,
|
|
255
260
|
providerId: null,
|
|
256
|
-
baseUrl: config.baseUrl.trim() ? config.baseUrl :
|
|
261
|
+
baseUrl: config.baseUrl.trim() ? config.baseUrl : '',
|
|
257
262
|
};
|
|
258
263
|
}
|
|
259
264
|
/** Mode changes never discard BYOK credentials — flipping to Local CLI and
|
|
@@ -476,6 +481,14 @@ export function agentExecutableRepairState(result) {
|
|
|
476
481
|
return null;
|
|
477
482
|
return { detectedPath, canUseDetected: true };
|
|
478
483
|
}
|
|
484
|
+
/** Resolves alias evidence to a concrete picker row; other rows retain their identity. */
|
|
485
|
+
function resolvedPickerModelOption({ model }, _optional = {}) {
|
|
486
|
+
const resolvedId = model.identityKind === 'alias' ? model.resolvedId : undefined;
|
|
487
|
+
if (!resolvedId)
|
|
488
|
+
return model;
|
|
489
|
+
const label = model.label === model.id ? resolvedId : model.label;
|
|
490
|
+
return { ...model, id: resolvedId, label, identityKind: 'concrete' };
|
|
491
|
+
}
|
|
479
492
|
/**
|
|
480
493
|
* Builds picker rows from catalog evidence without changing the source catalog. Resolved aliases
|
|
481
494
|
* share a concrete row; unresolved aliases and routing modes remain selectable as reported.
|
|
@@ -487,12 +500,11 @@ export function agentExecutableRepairState(result) {
|
|
|
487
500
|
export function pickerModelOptions({ models }, _optional = {}) {
|
|
488
501
|
const choices = new Map();
|
|
489
502
|
for (const model of models) {
|
|
490
|
-
const
|
|
491
|
-
const id
|
|
492
|
-
const label = model.label === model.id ? id : model.label;
|
|
503
|
+
const option = resolvedPickerModelOption({ model });
|
|
504
|
+
const { id, label } = option;
|
|
493
505
|
const existing = choices.get(id);
|
|
494
506
|
if (!existing) {
|
|
495
|
-
choices.set(id,
|
|
507
|
+
choices.set(id, option);
|
|
496
508
|
}
|
|
497
509
|
else if (existing.label === id && label !== id) {
|
|
498
510
|
choices.set(id, { ...existing, label });
|
|
@@ -566,16 +578,20 @@ export function splitReasoningModelId(modelId, levelIds) {
|
|
|
566
578
|
* has no level, so nothing is stripped, and a vendor label that happens to end in an unrelated
|
|
567
579
|
* parenthetical keeps it.
|
|
568
580
|
*/
|
|
581
|
+
/** `Head (Inner)` with optional surrounding whitespace; group 1 is the head, group 2 the qualifier. */
|
|
582
|
+
const TRAILING_PARENTHETICAL = /^(.*?)\s*\(([^()]*)\)\s*$/;
|
|
569
583
|
function baseLabelForLevel(label, level) {
|
|
570
584
|
if (!level)
|
|
571
585
|
return label;
|
|
572
|
-
|
|
573
|
-
if (!match)
|
|
586
|
+
if (!TRAILING_PARENTHETICAL.test(label))
|
|
574
587
|
return label;
|
|
575
|
-
|
|
588
|
+
// Both capture groups always participate once the pattern matches, so reading them through
|
|
589
|
+
// `replace` (which yields a plain string) replaces the old `match[n] ?? ''` fallbacks, which no
|
|
590
|
+
// matching label could ever reach.
|
|
591
|
+
const inner = label.replace(TRAILING_PARENTHETICAL, '$2').trim().toLowerCase();
|
|
576
592
|
if (inner !== level.id.toLowerCase() && inner !== level.label.toLowerCase())
|
|
577
593
|
return label;
|
|
578
|
-
const stripped = (
|
|
594
|
+
const stripped = label.replace(TRAILING_PARENTHETICAL, '$1').trim();
|
|
579
595
|
return stripped || label;
|
|
580
596
|
}
|
|
581
597
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProviderPreset as SharedProviderPreset } from '@jini-ai/core';
|
|
1
2
|
/**
|
|
2
3
|
* Origin: the inline `execution` tab body in `SettingsDialog.tsx`
|
|
3
4
|
* (lines 4080-5336), classified MIXED by
|
|
@@ -26,48 +27,9 @@ export type ApiProtocol = 'anthropic' | 'openai' | 'azure' | 'google';
|
|
|
26
27
|
/** Where a preset renders in the chip strip. The origin drew one row of
|
|
27
28
|
* protocol presets and one of gateway presets; hosts that don't care can
|
|
28
29
|
* leave this unset and get a single row. */
|
|
29
|
-
export type ProviderPresetKind
|
|
30
|
-
/** One selectable endpoint preset
|
|
31
|
-
|
|
32
|
-
* fixed list (same convention as `LanguageTab`'s host-supplied locales). */
|
|
33
|
-
export interface ProviderPreset {
|
|
34
|
-
id: string;
|
|
35
|
-
title: string;
|
|
36
|
-
protocol: ApiProtocol;
|
|
37
|
-
baseUrl: string;
|
|
38
|
-
/** Ranked suggestions shown in the model field. Never authoritative — a
|
|
39
|
-
* host with live model discovery should pass `ExecutionPort.listModels`. */
|
|
40
|
-
preferredModels: readonly string[];
|
|
41
|
-
kind?: ProviderPresetKind;
|
|
42
|
-
/** Fixed-origin gateways resolve their base URL themselves, so the Base URL
|
|
43
|
-
* field is hidden rather than shown-and-ignored (origin: `isFixedOriginGateway`). */
|
|
44
|
-
fixedOrigin?: boolean;
|
|
45
|
-
/** Some local/self-hosted endpoints need no bearer credential. Defaults to
|
|
46
|
-
* `true` — i.e. an API key is required unless a preset opts out. */
|
|
47
|
-
requiresApiKey?: boolean;
|
|
48
|
-
/** Optional "Get key" deep link rendered beside the API-key field. */
|
|
49
|
-
apiKeyConsoleUrl?: string;
|
|
50
|
-
/**
|
|
51
|
-
* The literal prefix that positively identifies a pasted key as belonging to THIS provider —
|
|
52
|
-
* `'AIza'` for Google, `'sk-ant-'` for Anthropic. Omit it for a vendor whose keys carry no
|
|
53
|
-
* distinguishing prefix (Azure OpenAI's are bare hex) rather than inventing one.
|
|
54
|
-
*
|
|
55
|
-
* Read in exactly one direction: to recognise a key as SOMEONE ELSE'S. It is deliberately NOT an
|
|
56
|
-
* allowlist, and no code may ask "does the selected preset's key match this?" as a validity test.
|
|
57
|
-
* That is the shape this field replaced, and it shipped a false positive within hours of landing:
|
|
58
|
-
* a real Google Gemini key in a newer shape than `/^AIza/` was reported to its owner as not
|
|
59
|
-
* looking like a Google key. Vendors add key formats without telling anyone, so a catalog can
|
|
60
|
-
* prove a string belongs to vendor X, but never that it belongs to nobody. See
|
|
61
|
-
* `apiKeyFormatWarning`.
|
|
62
|
-
*
|
|
63
|
-
* Data rather than an `if (providerId === …)` chain in the rule, so adding a provider stays a row
|
|
64
|
-
* in the preset catalog — including for a host that supplies its own `presets` and never touches
|
|
65
|
-
* this package.
|
|
66
|
-
*/
|
|
67
|
-
apiKeyPrefix?: string;
|
|
68
|
-
/** The synthetic "Custom" preset. Exactly one may carry this flag; it is
|
|
69
|
-
* never treated as configured-by-preset and never hides the Base URL. */
|
|
70
|
-
custom?: boolean;
|
|
30
|
+
export type { ProviderPresetKind } from '@jini-ai/core';
|
|
31
|
+
/** One selectable endpoint preset supplied by the host. */
|
|
32
|
+
export interface ProviderPreset extends SharedProviderPreset<ApiProtocol> {
|
|
71
33
|
}
|
|
72
34
|
/**
|
|
73
35
|
* One advisory remark about the API key currently typed into the form, ready to translate.
|
|
@@ -1,19 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Origin: the inline `execution` tab body in `SettingsDialog.tsx`
|
|
3
|
-
* (lines 4080-5336), classified MIXED by
|
|
4
|
-
* `ADS-memory/reports/jini-port/recon/r6-god-component-internals.md` §1.3 — a generic
|
|
5
|
-
* "Local CLI vs. bring-your-own-key" execution switch wrapped in
|
|
6
|
-
* origin-specific managed-runtime/wallet chrome.
|
|
7
|
-
*
|
|
8
|
-
* What is ported: the mode switch, the provider/gateway chip groups, and the
|
|
9
|
-
* BYOK credential form (the origin had already factored these fields into
|
|
10
|
-
* `components/byok/*`, which is why this slice is assembly rather than
|
|
11
|
-
* surgery).
|
|
12
|
-
*
|
|
13
|
-
* What is deliberately left behind: the origin's managed-runtime wallet
|
|
14
|
-
* (balance polling, top-up, sign-in coachmarks, the `SettingsHighlight`
|
|
15
|
-
* one-shot focus hint) and its analytics tracking calls — all product-bound,
|
|
16
|
-
* none of it generic.
|
|
17
|
-
*/
|
|
18
1
|
export {};
|
|
19
2
|
//# sourceMappingURL=types.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SourceConfigDependencies } from '../../../source-config-list/ports.js';
|
|
2
|
-
import type { SourceConfigItem, SourceFieldSpec } from '../../../source-config-list/types.js';
|
|
2
|
+
import type { SourceConfigItem, SourceFieldSpec, SourceTrustOption } from '../../../source-config-list/types.js';
|
|
3
3
|
export interface ExternalMcpTabProps {
|
|
4
4
|
/** Host-supplied transport adapter — required, same as the generic primitive (no zero-config default is possible for an arbitrary `addSource`). */
|
|
5
5
|
dependencies: SourceConfigDependencies<SourceConfigItem>;
|
|
@@ -11,6 +11,10 @@ export interface ExternalMcpTabProps {
|
|
|
11
11
|
saveStatusLabel?: string;
|
|
12
12
|
/** Footer "Stored at <path>" text. Shown only when `saveStatusLabel` is also given, matching the footer being one unit in the OD reference. */
|
|
13
13
|
configPath?: string;
|
|
14
|
+
/** The trust levels each server card offers. The card renders its trust picker only when this is
|
|
15
|
+
* non-empty AND the port implements `setTrust`; without it the tab's `setTrust` wiring had no
|
|
16
|
+
* control that could ever reach it. Omit for no trust picker (the previous, and still default, look). */
|
|
17
|
+
trustOptions?: readonly SourceTrustOption[];
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
20
|
* OD as an MCP *client* — distinct from the "MCP server" tab, where the host
|
|
@@ -19,5 +23,5 @@ export interface ExternalMcpTabProps {
|
|
|
19
23
|
* composition only: every list/add mutation is the two source-config-list
|
|
20
24
|
* hooks' own, already-tested logic.
|
|
21
25
|
*/
|
|
22
|
-
export declare function ExternalMcpTab({ dependencies, fieldSpecs, connectionError, saveStatusLabel, configPath, }: ExternalMcpTabProps): import("react").JSX.Element;
|
|
26
|
+
export declare function ExternalMcpTab({ dependencies, fieldSpecs, connectionError, saveStatusLabel, configPath, trustOptions, }: ExternalMcpTabProps): import("react").JSX.Element;
|
|
23
27
|
//# sourceMappingURL=ExternalMcpTab.d.ts.map
|
|
@@ -33,7 +33,7 @@ import { MCP_SOURCE_FIELD_SPECS } from '../../constants.js';
|
|
|
33
33
|
* composition only: every list/add mutation is the two source-config-list
|
|
34
34
|
* hooks' own, already-tested logic.
|
|
35
35
|
*/
|
|
36
|
-
export function ExternalMcpTab({ dependencies, fieldSpecs = MCP_SOURCE_FIELD_SPECS, connectionError = null, saveStatusLabel, configPath, }) {
|
|
36
|
+
export function ExternalMcpTab({ dependencies, fieldSpecs = MCP_SOURCE_FIELD_SPECS, connectionError = null, saveStatusLabel, configPath, trustOptions, }) {
|
|
37
37
|
const t = useT();
|
|
38
38
|
const [formOpen, setFormOpen] = useState(false);
|
|
39
39
|
const list = useWiredSourceConfigList({ dependencies });
|
|
@@ -48,6 +48,13 @@ export function ExternalMcpTab({ dependencies, fieldSpecs = MCP_SOURCE_FIELD_SPE
|
|
|
48
48
|
// A real load failure always wins over the host's static/decorative banner
|
|
49
49
|
// text — showing both would just be two banners saying overlapping things.
|
|
50
50
|
const banner = list.error ?? connectionError;
|
|
51
|
-
return (_jsxs("section", { className: "external-mcp-tab", children: [_jsxs("div", { className: "external-mcp-head", children: [_jsxs("div", { children: [_jsx("h3", { children: t('External MCP servers') }), _jsx("p", { className: "external-mcp-subtitle", children: t('Third-party tools for your coding agent.') })] }), _jsxs("button", { type: "button", className: "external-mcp-add-button", onClick: () => setFormOpen((open) => !open), "aria-expanded": formOpen, children: [_jsx(Icon, { name: "plus", size: 14 }), _jsx("span", { children: t('Add server') })] })] }), banner ? (_jsx("div", { className: "external-mcp-banner", role: "alert", children: t(banner) })) : null, formOpen ? (_jsx(SourceConfigAddForm, { fieldSpecs: fieldSpecs, values: addForm.values, validation: addForm.validation, submitAttempted: addForm.submitAttempted, submitting: addForm.submitting,
|
|
51
|
+
return (_jsxs("section", { className: "external-mcp-tab", children: [_jsxs("div", { className: "external-mcp-head", children: [_jsxs("div", { children: [_jsx("h3", { children: t('External MCP servers') }), _jsx("p", { className: "external-mcp-subtitle", children: t('Third-party tools for your coding agent.') })] }), _jsxs("button", { type: "button", className: "external-mcp-add-button", onClick: () => setFormOpen((open) => !open), "aria-expanded": formOpen, children: [_jsx(Icon, { name: "plus", size: 14 }), _jsx("span", { children: t('Add server') })] })] }), banner ? (_jsx("div", { className: "external-mcp-banner", role: "alert", children: t(banner) })) : null, formOpen ? (_jsx(SourceConfigAddForm, { fieldSpecs: fieldSpecs, values: addForm.values, validation: addForm.validation, submitAttempted: addForm.submitAttempted, submitting: addForm.submitting, submitError: addForm.submitError, onFieldChange: addForm.setField, onTrustChange: addForm.setTrust, onSubmit: () => void addForm.submit(), canTest: list.capabilities.canTest, testing: list.isPending(DRAFT_TEST_SCOPE, 'test'), ...(list.testResults[DRAFT_TEST_SCOPE] ? { testResult: list.testResults[DRAFT_TEST_SCOPE] } : {}), onTest: () => void list.test(undefined, addForm.values), addLabel: "Add server" })) : null, list.loading ? (_jsx("div", { className: "source-config-list-loading", role: "status", children: t('Loading…') })) : list.sources.length === 0 ? (_jsxs("div", { className: "external-mcp-empty", children: [_jsx("p", { className: "external-mcp-empty-title", children: t('No MCP servers configured.') }), _jsx("p", { className: "external-mcp-empty-hint", children: t('Click "Add server" to get started — pick a template or set up a custom stdio / HTTP server.') })] })) : (_jsx("div", { className: "source-config-list-items", children: list.sources.map((source) => (_jsx(SourceConfigItemCard, { source: source, fieldSpecs: fieldSpecs, ...(trustOptions ? { trustOptions } : {}), capabilities: list.capabilities, removing: list.isPending(source.id, 'remove'), refreshing: list.isPending(source.id, 'refresh'), settingTrust: list.isPending(source.id, 'trust'), testing: list.isPending(source.id, 'test'), updating: list.isPending(source.id, 'update'), onRefresh: () => void list.refresh(source.id), onRemove: () => void list.remove(source.id), onTrustChange: (trust) => void list.setTrust(source.id, trust), onTest: () => void list.test(source.id), onUpdate: (patch) => void list.update(source.id, patch), ...(list.testResults[source.id] ? { testResult: list.testResults[source.id] } : {}) }, source.id))) })), _jsx(ExternalMcpFooter, { saveStatusLabel: saveStatusLabel, configPath: configPath })] }));
|
|
52
|
+
}
|
|
53
|
+
/** Renders the save-status footer as one unit; a path alone does not show it. */
|
|
54
|
+
function ExternalMcpFooter({ saveStatusLabel, configPath }) {
|
|
55
|
+
const t = useT();
|
|
56
|
+
if (!saveStatusLabel)
|
|
57
|
+
return null;
|
|
58
|
+
return (_jsxs("div", { className: "external-mcp-footer", children: [_jsx("span", { className: "external-mcp-save-pill", children: t(saveStatusLabel) }), configPath ? (_jsxs("span", { className: "external-mcp-stored-at", children: [t('Stored at'), " ", _jsx("code", { children: configPath })] })) : null] }));
|
|
52
59
|
}
|
|
53
60
|
//# sourceMappingURL=ExternalMcpTab.js.map
|