@jini-ai/ui 0.5.5 → 0.6.10
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 +91 -2
- 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 +9 -12
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +0 -46
|
@@ -45,84 +45,101 @@ export function providerDisplayName(provider) {
|
|
|
45
45
|
return 'Memory model';
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
function isString(value) {
|
|
49
|
+
return typeof value === 'string';
|
|
50
|
+
}
|
|
51
|
+
function isNumber(value) {
|
|
52
|
+
return typeof value === 'number';
|
|
53
|
+
}
|
|
54
|
+
// Reads message/code/status out of the first `{...}` in the raw provider
|
|
55
|
+
// error. The nested `error.*` field wins for message/code; the top-level
|
|
56
|
+
// field wins for status.
|
|
57
|
+
function parseJsonErrorFields(raw) {
|
|
49
58
|
const jsonStart = raw.indexOf('{');
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (typeof parsed?.status === 'number')
|
|
66
|
-
status = parsed.status;
|
|
67
|
-
else if (typeof error?.status === 'number')
|
|
68
|
-
status = error.status;
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
// Fall through to regex parsing below.
|
|
72
|
-
}
|
|
59
|
+
if (jsonStart < 0)
|
|
60
|
+
return {};
|
|
61
|
+
try {
|
|
62
|
+
// Text starting at `{` can only parse to an object, so `parsed` is never null.
|
|
63
|
+
const parsed = JSON.parse(raw.slice(jsonStart));
|
|
64
|
+
const error = parsed.error;
|
|
65
|
+
return {
|
|
66
|
+
message: [error?.message, parsed.message].find(isString),
|
|
67
|
+
code: [error?.code, parsed.code].find(isString),
|
|
68
|
+
status: [parsed.status, error?.status].find(isNumber),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Fall through to regex parsing below.
|
|
73
|
+
return {};
|
|
73
74
|
}
|
|
75
|
+
}
|
|
76
|
+
export function parseProviderError(raw) {
|
|
77
|
+
const fields = parseJsonErrorFields(raw);
|
|
74
78
|
const statusMatch = /\b(4\d\d|5\d\d)\b/.exec(raw);
|
|
75
|
-
if (status === null && statusMatch?.[1])
|
|
76
|
-
status = Number(statusMatch[1]);
|
|
77
79
|
return {
|
|
78
|
-
message: message.replace(/\s+/g, ' ').trim(),
|
|
79
|
-
code,
|
|
80
|
-
status,
|
|
80
|
+
message: (fields.message ?? raw.trim()).replace(/\s+/g, ' ').trim(),
|
|
81
|
+
code: fields.code ?? '',
|
|
82
|
+
status: fields.status ?? (statusMatch ? Number(statusMatch[1]) : null),
|
|
81
83
|
};
|
|
82
84
|
}
|
|
85
|
+
function classifyFailure({ status, haystack }) {
|
|
86
|
+
if (status === 401 || /token[_ -]?expired|authentication token has expired|invalid[_ -]?api[_ -]?key|unauthorized/.test(haystack)) {
|
|
87
|
+
return 'auth';
|
|
88
|
+
}
|
|
89
|
+
if (status === 429 || /rate limit|quota|too many requests|insufficient_quota/.test(haystack))
|
|
90
|
+
return 'quota';
|
|
91
|
+
if (/network|fetch failed|timeout|timed out|econnreset|enotfound/.test(haystack))
|
|
92
|
+
return 'network';
|
|
93
|
+
return 'other';
|
|
94
|
+
}
|
|
95
|
+
function failureCopy({ category, providerName, usesChatCli, source, message, }) {
|
|
96
|
+
switch (category) {
|
|
97
|
+
case 'auth':
|
|
98
|
+
return {
|
|
99
|
+
title: `${providerName} authentication expired`,
|
|
100
|
+
detail: source,
|
|
101
|
+
action: usesChatCli
|
|
102
|
+
? 'Sign in to the selected local CLI or choose a different memory model.'
|
|
103
|
+
: 'Update the memory extraction model key or sign in again.',
|
|
104
|
+
};
|
|
105
|
+
case 'quota':
|
|
106
|
+
return {
|
|
107
|
+
title: `${providerName} quota or rate limit hit`,
|
|
108
|
+
detail: source,
|
|
109
|
+
action: 'Try again later or switch the memory extraction model.',
|
|
110
|
+
};
|
|
111
|
+
case 'network':
|
|
112
|
+
return {
|
|
113
|
+
title: `${providerName} request failed`,
|
|
114
|
+
detail: source,
|
|
115
|
+
action: usesChatCli
|
|
116
|
+
? 'Check the selected local CLI and try again.'
|
|
117
|
+
: 'Check the model provider connection and try again.',
|
|
118
|
+
};
|
|
119
|
+
default:
|
|
120
|
+
return {
|
|
121
|
+
title: 'Memory extraction failed',
|
|
122
|
+
detail: message || source,
|
|
123
|
+
action: usesChatCli
|
|
124
|
+
? 'Try again after checking the selected local CLI.'
|
|
125
|
+
: 'Try again after checking the memory extraction model settings.',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
83
129
|
export function describeExtractionFailure(record) {
|
|
84
130
|
if (record.phase !== 'failed' || !record.error)
|
|
85
131
|
return null;
|
|
86
|
-
const providerName = providerDisplayName(record.provider);
|
|
87
|
-
const usesChatCli = record.provider?.credentialSource === 'chat-cli';
|
|
88
132
|
const parsed = parseProviderError(record.error);
|
|
89
133
|
const haystack = `${parsed.message} ${parsed.code} ${record.error}`.toLowerCase();
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
? 'Sign in to the selected local CLI or choose a different memory model.'
|
|
100
|
-
: 'Update the memory extraction model key or sign in again.',
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
if (parsed.status === 429 || /rate limit|quota|too many requests|insufficient_quota/.test(haystack)) {
|
|
104
|
-
return {
|
|
105
|
-
title: `${providerName} quota or rate limit hit`,
|
|
106
|
-
detail: source,
|
|
107
|
-
action: 'Try again later or switch the memory extraction model.',
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
if (/network|fetch failed|timeout|timed out|econnreset|enotfound/.test(haystack)) {
|
|
111
|
-
return {
|
|
112
|
-
title: `${providerName} request failed`,
|
|
113
|
-
detail: source,
|
|
114
|
-
action: usesChatCli
|
|
115
|
-
? 'Check the selected local CLI and try again.'
|
|
116
|
-
: 'Check the model provider connection and try again.',
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
return {
|
|
120
|
-
title: 'Memory extraction failed',
|
|
121
|
-
detail: parsed.message || source,
|
|
122
|
-
action: usesChatCli
|
|
123
|
-
? 'Try again after checking the selected local CLI.'
|
|
124
|
-
: 'Try again after checking the memory extraction model settings.',
|
|
125
|
-
};
|
|
134
|
+
return failureCopy({
|
|
135
|
+
category: classifyFailure({ status: parsed.status, haystack }),
|
|
136
|
+
providerName: providerDisplayName(record.provider),
|
|
137
|
+
usesChatCli: record.provider?.credentialSource === 'chat-cli',
|
|
138
|
+
source: record.kind === 'connector'
|
|
139
|
+
? 'Connected apps were read, but the assistant could not turn that context into memory.'
|
|
140
|
+
: 'Memory extraction could not run for this chat.',
|
|
141
|
+
message: parsed.message,
|
|
142
|
+
});
|
|
126
143
|
}
|
|
127
144
|
export function formatConnectorContextBytes(bytes) {
|
|
128
145
|
if (!Number.isFinite(bytes) || bytes <= 0)
|
|
@@ -248,43 +265,55 @@ export function formatRelativeTimeAgo(at, now) {
|
|
|
248
265
|
export function memoryCountLabel(count) {
|
|
249
266
|
return count === 1 ? 'memory' : 'memories';
|
|
250
267
|
}
|
|
268
|
+
// The record's written count when it is a positive number, else 0.
|
|
269
|
+
function positiveWrittenCount(record) {
|
|
270
|
+
const count = record.writtenCount;
|
|
271
|
+
return typeof count === 'number' && count > 0 ? count : 0;
|
|
272
|
+
}
|
|
273
|
+
function connectorCardTitle({ record, t }) {
|
|
274
|
+
switch (record.phase) {
|
|
275
|
+
case 'running':
|
|
276
|
+
return t('Scanning connected apps');
|
|
277
|
+
case 'failed':
|
|
278
|
+
return t('Connected app scan failed');
|
|
279
|
+
case 'skipped':
|
|
280
|
+
return t('Connected app scan skipped');
|
|
281
|
+
case 'success': {
|
|
282
|
+
const writtenCount = positiveWrittenCount(record);
|
|
283
|
+
if (writtenCount > 0) {
|
|
284
|
+
return t('Saved {count} {label}', { count: writtenCount, label: memoryCountLabel(writtenCount) });
|
|
285
|
+
}
|
|
286
|
+
return t('No new memories found');
|
|
287
|
+
}
|
|
288
|
+
default:
|
|
289
|
+
return t('Connected app scan');
|
|
290
|
+
}
|
|
291
|
+
}
|
|
251
292
|
export function extractionCardTitle(record, t) {
|
|
252
293
|
const kind = record.kind ?? 'llm';
|
|
253
294
|
if (kind !== 'connector') {
|
|
254
295
|
return record.userMessagePreview || t('Extraction');
|
|
255
296
|
}
|
|
256
|
-
|
|
257
|
-
return t('Scanning connected apps');
|
|
258
|
-
if (record.phase === 'failed')
|
|
259
|
-
return t('Connected app scan failed');
|
|
260
|
-
if (record.phase === 'skipped')
|
|
261
|
-
return t('Connected app scan skipped');
|
|
262
|
-
if (record.phase === 'success') {
|
|
263
|
-
const writtenCount = typeof record.writtenCount === 'number' ? record.writtenCount : null;
|
|
264
|
-
if (writtenCount && writtenCount > 0) {
|
|
265
|
-
return t('Saved {count} {label}', { count: writtenCount, label: memoryCountLabel(writtenCount) });
|
|
266
|
-
}
|
|
267
|
-
return t('No new memories found');
|
|
268
|
-
}
|
|
269
|
-
return t('Connected app scan');
|
|
297
|
+
return connectorCardTitle({ record, t });
|
|
270
298
|
}
|
|
271
|
-
|
|
272
|
-
|
|
299
|
+
function connectorCardMeta({ record, now, t }) {
|
|
300
|
+
if (record.phase === 'running')
|
|
301
|
+
return t('Checking selected apps');
|
|
273
302
|
const age = formatRelativeTimeAgo(record.startedAt, now);
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
return t('Checking selected apps');
|
|
277
|
-
if (record.phase === 'failed')
|
|
303
|
+
switch (record.phase) {
|
|
304
|
+
case 'failed':
|
|
278
305
|
return `${t('Needs attention')} · ${age}`;
|
|
279
|
-
|
|
306
|
+
case 'skipped':
|
|
280
307
|
return `${t('Skipped')} · ${age}`;
|
|
281
|
-
|
|
282
|
-
const
|
|
283
|
-
const result = writtenCount && writtenCount > 0 ? t('From connected apps') : t('Checked selected apps');
|
|
308
|
+
case 'success': {
|
|
309
|
+
const result = positiveWrittenCount(record) > 0 ? t('From connected apps') : t('Checked selected apps');
|
|
284
310
|
return `${result} · ${age}`;
|
|
285
311
|
}
|
|
286
|
-
|
|
312
|
+
default:
|
|
313
|
+
return `${t('Connected apps')} · ${age}`;
|
|
287
314
|
}
|
|
315
|
+
}
|
|
316
|
+
function modelCardMeta({ record, now, t }) {
|
|
288
317
|
const duration = formatDuration(record);
|
|
289
318
|
const parts = [formatAbsoluteTime(record.startedAt, now), formatRelativeTime(record.startedAt, now)];
|
|
290
319
|
if (duration)
|
|
@@ -294,6 +323,12 @@ export function extractionCardMeta(record, now, t) {
|
|
|
294
323
|
}
|
|
295
324
|
return parts.join(' · ');
|
|
296
325
|
}
|
|
326
|
+
export function extractionCardMeta(record, now, t) {
|
|
327
|
+
const kind = record.kind ?? 'llm';
|
|
328
|
+
if (kind === 'connector')
|
|
329
|
+
return connectorCardMeta({ record, now, t });
|
|
330
|
+
return modelCardMeta({ record, now, t });
|
|
331
|
+
}
|
|
297
332
|
/** Localized labels for each memory type badge. `t`-only, so callers memoize on
|
|
298
333
|
* `t` at the call site instead of drilling the map through props. */
|
|
299
334
|
export function memoryTypeLabels(t) {
|
|
@@ -14,43 +14,99 @@ import { ConnectorLogo } from '../../../connectors/index.js';
|
|
|
14
14
|
import { Icon } from '../../../../react/components/Icon.js';
|
|
15
15
|
import { useT } from '../../../i18n/index.js';
|
|
16
16
|
import { MemoryExtractionCard } from './MemoryExtractionCard.js';
|
|
17
|
-
|
|
17
|
+
function isStatusResolved({ connector, context }) {
|
|
18
|
+
return context.connectorIdsWithDetails.has(connector.id) || context.connectorStatuses[connector.id] !== undefined;
|
|
19
|
+
}
|
|
20
|
+
function connectorRowState({ connector, context }) {
|
|
21
|
+
const connected = connector.status === 'connected';
|
|
22
|
+
const connecting = context.connectingConnectorIds.has(connector.id);
|
|
23
|
+
const authorizationPending = context.pendingConnectorAuthIds.has(connector.id);
|
|
24
|
+
const connectError = context.connectorConnectErrors[connector.id];
|
|
25
|
+
const checkingStatus = context.connectorsLoading && !isStatusResolved({ connector, context }) && !connected && !authorizationPending && !connectError && !connecting;
|
|
26
|
+
return {
|
|
27
|
+
connected,
|
|
28
|
+
selected: context.selectedConnectorIds.has(connector.id) && connected,
|
|
29
|
+
connecting,
|
|
30
|
+
authorizationPending,
|
|
31
|
+
connectError,
|
|
32
|
+
checkingStatus,
|
|
33
|
+
reconnecting: connector.status === 'error',
|
|
34
|
+
busy: connecting || authorizationPending || checkingStatus,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function connectorHint({ connector, state, t }) {
|
|
38
|
+
if (state.connected)
|
|
39
|
+
return connector.accountLabel || `${connector.tools.length} ${t('read tools')}`;
|
|
40
|
+
if (state.checkingStatus)
|
|
41
|
+
return t('Checking connection status…');
|
|
42
|
+
if (state.authorizationPending)
|
|
43
|
+
return t('Finish authorization in your browser, then return here');
|
|
44
|
+
return connector.lastError?.trim() || state.connectError || t('Connect this app before extraction');
|
|
45
|
+
}
|
|
46
|
+
function connectButtonLabel({ state, t }) {
|
|
47
|
+
if (state.checkingStatus)
|
|
48
|
+
return t('Checking');
|
|
49
|
+
if (state.authorizationPending)
|
|
50
|
+
return t('Waiting');
|
|
51
|
+
if (state.connecting)
|
|
52
|
+
return t('Connecting');
|
|
53
|
+
return state.reconnecting ? t('Reconnect') : t('Connect');
|
|
54
|
+
}
|
|
55
|
+
function MemoryConnectButton({ connector, state, onConnectMemoryConnector, }) {
|
|
56
|
+
const t = useT();
|
|
57
|
+
return (_jsxs("button", { type: "button", className: `memory-connector-connect-button${state.busy ? ' is-loading' : ''}`, disabled: state.busy, "aria-busy": state.busy || undefined, "aria-label": `${state.reconnecting ? t('Reconnect') : t('Connect')} ${connector.name}`, onClick: (event) => {
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
event.stopPropagation();
|
|
60
|
+
void onConnectMemoryConnector(connector.id);
|
|
61
|
+
}, children: [_jsx(Icon, { name: state.busy ? 'refresh' : 'plus', size: 12, className: state.busy ? 'icon-spin' : '' }), _jsx("span", { children: connectButtonLabel({ state, t }) })] }));
|
|
62
|
+
}
|
|
63
|
+
function MemoryConnectorPicker({ selected }) {
|
|
64
|
+
const t = useT();
|
|
65
|
+
return (_jsxs("span", { className: `memory-connector-picker${selected ? ' is-selected' : ''}`, children: [_jsx("span", { className: "memory-connector-picker-box", "aria-hidden": "true", children: selected ? _jsx(Icon, { name: "check", size: 12 }) : null }), _jsx("span", { children: selected ? t('Selected') : t('Select') })] }));
|
|
66
|
+
}
|
|
67
|
+
function MemoryConnectorRow({ connector, context, toggleConnectorSelection, onConnectMemoryConnector, }) {
|
|
68
|
+
const t = useT();
|
|
69
|
+
const state = connectorRowState({ connector, context });
|
|
70
|
+
const { connected, selected } = state;
|
|
71
|
+
return (_jsxs("label", { className: `memory-connector-row${connected ? '' : ' is-disabled'}${selected ? ' is-selected' : ''}`, "data-memory-connector-id": connector.id, children: [_jsx("input", { className: "memory-connector-input", type: "checkbox", checked: selected, disabled: !connected, "aria-label": `${t('Use')} ${connector.name} ${t('for memory extraction')}`, onChange: () => toggleConnectorSelection(connector.id) }), _jsxs("span", { className: `memory-connector-brand${selected ? ' is-selected' : ''}`, children: [_jsx(ConnectorLogo, { connectorId: connector.id, connectorName: connector.name, logoUrl: connector.logoUrl, size: "sm" }), _jsx("span", { className: "memory-connector-selected-mark", "aria-hidden": "true", children: selected ? _jsx(Icon, { name: "check", size: 13 }) : null })] }), _jsxs("span", { className: "memory-connector-copy", children: [_jsx("strong", { children: connector.name }), _jsx("small", { children: connectorHint({ connector, state, t }) })] }), connected ? (_jsx(MemoryConnectorPicker, { selected: selected })) : (_jsx(MemoryConnectButton, { connector: connector, state: state, onConnectMemoryConnector: onConnectMemoryConnector }))] }));
|
|
72
|
+
}
|
|
73
|
+
function MemoryConnectedSummary({ connectorsLoading, connectedCount, onOpenConnectors, }) {
|
|
74
|
+
const t = useT();
|
|
75
|
+
return (_jsxs("div", { className: "memory-source-summary memory-connected-summary", children: [_jsx("span", { className: "memory-block-icon", children: _jsx(Icon, { name: "link", size: 15 }) }), _jsxs("div", { children: [_jsx("h4", { children: t('Import from apps') }), _jsx("p", { className: "hint", children: t('Choose apps to scan for design preferences, project context, and visual references. Nothing is scanned until you select an app.') })] }), _jsx("span", { className: "memory-source-badge", children: connectorsLoading ? t('Loading') : `${connectedCount} ${t('connected')}` }), _jsx("button", { type: "button", className: "ghost memory-source-action", onClick: onOpenConnectors, disabled: !onOpenConnectors, children: t('Manage') })] }));
|
|
76
|
+
}
|
|
77
|
+
function MemoryConnectorRunBar({ enabled, connectorExtracting, connectorSaving, connectedCount, selectedCount, connectorScanLabel, onSuggestConnectorMemory, }) {
|
|
78
|
+
const t = useT();
|
|
79
|
+
return (_jsxs("div", { className: "memory-connector-actions memory-connector-runbar", children: [_jsxs("span", { className: "hint", children: [t('Selected'), " ", selectedCount, " ", t('of'), " ", connectedCount, " ", t('connected'), ' ', connectedCount === 1 ? t('app') : t('apps'), "."] }), _jsxs("button", { type: "button", className: "primary memory-source-action", onClick: () => void onSuggestConnectorMemory(), disabled: !enabled || connectorExtracting || connectorSaving || selectedCount === 0, children: [_jsx(Icon, { name: connectorExtracting ? 'refresh' : 'sparkles', size: 14, className: connectorExtracting ? 'icon-spin' : '' }), _jsx("span", { children: t(connectorScanLabel) })] })] }));
|
|
80
|
+
}
|
|
81
|
+
function MemorySuggestionCard({ suggestion, selected, typeLabel, toggleConnectorSuggestion, }) {
|
|
82
|
+
const t = useT();
|
|
83
|
+
const sourceLabel = suggestion.source?.connectorName || suggestion.source?.toolTitle || t('Connected apps');
|
|
84
|
+
return (_jsxs("label", { className: `memory-suggestion-card${selected ? ' is-selected' : ''}`, children: [_jsxs("span", { className: "memory-connector-check", children: [_jsx("input", { type: "checkbox", checked: selected, onChange: () => toggleConnectorSuggestion(suggestion.id) }), _jsx("span", { "aria-hidden": "true", children: selected ? _jsx(Icon, { name: "check", size: 13 }) : null })] }), _jsxs("span", { className: "memory-suggestion-copy", children: [_jsxs("span", { className: "memory-suggestion-title", children: [_jsx("strong", { children: suggestion.name }), _jsx("span", { className: "memory-type-badge", children: typeLabel })] }), suggestion.description ? _jsx("small", { children: suggestion.description }) : null, _jsx("span", { className: "memory-suggestion-body", children: suggestion.body })] }), _jsx("span", { className: "memory-connector-state is-connected", children: sourceLabel })] }));
|
|
85
|
+
}
|
|
86
|
+
function MemorySuggestionPanel({ connectorSuggestions, selectedSuggestionIds, selectedConnectorSuggestions, connectorSaving, toggleConnectorSuggestion, onSaveConnectorSuggestions, onDiscardConnectorSuggestions, }) {
|
|
18
87
|
const t = useT();
|
|
19
88
|
const typeLabel = useMemo(() => memoryTypeLabels(t), [t]);
|
|
20
|
-
return (_jsxs("div", { className: "memory-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
? t('Checking')
|
|
43
|
-
: authorizationPending
|
|
44
|
-
? t('Waiting')
|
|
45
|
-
: connecting
|
|
46
|
-
? t('Connecting')
|
|
47
|
-
: reconnecting
|
|
48
|
-
? t('Reconnect')
|
|
49
|
-
: t('Connect') })] }))] }, connector.id));
|
|
50
|
-
}) }), _jsxs("div", { className: "memory-connector-actions memory-connector-runbar", children: [_jsxs("span", { className: "hint", children: [t('Selected'), " ", selectedConnectedConnectorIds.length, " ", t('of'), " ", connectedCount, " ", t('connected'), ' ', connectedCount === 1 ? t('app') : t('apps'), "."] }), _jsxs("button", { type: "button", className: "primary memory-source-action", onClick: () => void onSuggestConnectorMemory(), disabled: !enabled || connectorExtracting || connectorSaving || selectedConnectedConnectorIds.length === 0, children: [_jsx(Icon, { name: connectorExtracting ? 'refresh' : 'sparkles', size: 14, className: connectorExtracting ? 'icon-spin' : '' }), _jsx("span", { children: t(connectorScanLabel) })] })] })] }), connectorSuggestions.length > 0 ? (_jsxs("div", { className: "memory-suggestion-panel", children: [_jsxs("div", { className: "memory-subsection-head", children: [_jsxs("div", { children: [_jsx("h4", { children: t('Suggested memories') }), _jsx("p", { className: "hint", children: t('Review design-related memories before saving them.') })] }), _jsxs("span", { className: "memory-source-badge", children: [selectedConnectorSuggestions.length, " ", t('selected')] })] }), _jsx("div", { className: "memory-suggestion-list", children: connectorSuggestions.map((suggestion) => {
|
|
51
|
-
const selected = selectedSuggestionIds.has(suggestion.id);
|
|
52
|
-
const sourceLabel = suggestion.source?.connectorName || suggestion.source?.toolTitle || t('Connected apps');
|
|
53
|
-
return (_jsxs("label", { className: `memory-suggestion-card${selected ? ' is-selected' : ''}`, children: [_jsxs("span", { className: "memory-connector-check", children: [_jsx("input", { type: "checkbox", checked: selected, onChange: () => toggleConnectorSuggestion(suggestion.id) }), _jsx("span", { "aria-hidden": "true", children: selected ? _jsx(Icon, { name: "check", size: 13 }) : null })] }), _jsxs("span", { className: "memory-suggestion-copy", children: [_jsxs("span", { className: "memory-suggestion-title", children: [_jsx("strong", { children: suggestion.name }), _jsx("span", { className: "memory-type-badge", children: typeLabel[suggestion.type] })] }), suggestion.description ? _jsx("small", { children: suggestion.description }) : null, _jsx("span", { className: "memory-suggestion-body", children: suggestion.body })] }), _jsx("span", { className: "memory-connector-state is-connected", children: sourceLabel })] }, suggestion.id));
|
|
54
|
-
}) }), _jsxs("div", { className: "memory-connector-actions", children: [_jsxs("button", { type: "button", className: "primary memory-source-action", onClick: () => void onSaveConnectorSuggestions(), disabled: connectorSaving || selectedConnectorSuggestions.length === 0, children: [_jsx(Icon, { name: connectorSaving ? 'refresh' : 'check', size: 14, className: connectorSaving ? 'icon-spin' : '' }), _jsx("span", { children: connectorSaving ? t('Saving') : t('Save selected') })] }), _jsx("button", { type: "button", className: "ghost memory-source-action", onClick: onDiscardConnectorSuggestions, disabled: connectorSaving, children: t('Discard') })] })] })) : null, connectorStatus ? (_jsx("div", { role: "status", className: "memory-connector-result is-success", children: connectorStatus })) : null, connectorError ? (_jsx("div", { role: "alert", className: "memory-connector-result is-error", children: connectorError })) : null, connectorAttempts.length > 0 ? (_jsxs("div", { className: "memory-connector-diagnostics", "aria-label": t('Connected app read status'), children: [_jsxs("div", { className: "memory-connector-diagnostics-head", children: [_jsx("strong", { children: t('Last scan') }), _jsxs("span", { children: [formatConnectorContextBytes(connectorContextBytes), " ", t('read')] })] }), _jsx("div", { className: "memory-connector-diagnostics-list", children: connectorAttempts.map((attempt) => (_jsxs("div", { className: `memory-connector-diagnostic-row is-${attempt.status}`, children: [_jsx("span", { className: "memory-connector-diagnostic-dot", "aria-hidden": "true" }), _jsxs("span", { className: "memory-connector-diagnostic-copy", children: [_jsx("strong", { children: connectorAttemptTitle(attempt) }), _jsx("small", { children: connectorAttemptDetail(attempt) })] })] }, `${attempt.connectorId}-${attempt.status}-${attempt.toolName ?? 'none'}`))) })] })) : null, connectorExtractions.length > 0 ? (_jsxs("details", { className: "memory-scan-history", children: [_jsxs("summary", { children: [_jsx("span", { children: t('Recent scans') }), _jsx("span", { children: connectorExtractions.length })] }), _jsx("div", { className: "memory-connector-run-history", "aria-label": t('Connected app memory run status'), children: connectorExtractions.slice(0, 4).map((record) => (_jsx(MemoryExtractionCard, { record: record, nowClock: nowClock, onOpenPreview: onOpenPreview, onDelete: onDeleteExtraction }, record.id))) })] })) : null] }));
|
|
89
|
+
return (_jsxs("div", { className: "memory-suggestion-panel", children: [_jsxs("div", { className: "memory-subsection-head", children: [_jsxs("div", { children: [_jsx("h4", { children: t('Suggested memories') }), _jsx("p", { className: "hint", children: t('Review design-related memories before saving them.') })] }), _jsxs("span", { className: "memory-source-badge", children: [selectedConnectorSuggestions.length, " ", t('selected')] })] }), _jsx("div", { className: "memory-suggestion-list", children: connectorSuggestions.map((suggestion) => (_jsx(MemorySuggestionCard, { suggestion: suggestion, selected: selectedSuggestionIds.has(suggestion.id), typeLabel: typeLabel[suggestion.type], toggleConnectorSuggestion: toggleConnectorSuggestion }, suggestion.id))) }), _jsxs("div", { className: "memory-connector-actions", children: [_jsxs("button", { type: "button", className: "primary memory-source-action", onClick: () => void onSaveConnectorSuggestions(), disabled: connectorSaving || selectedConnectorSuggestions.length === 0, children: [_jsx(Icon, { name: connectorSaving ? 'refresh' : 'check', size: 14, className: connectorSaving ? 'icon-spin' : '' }), _jsx("span", { children: connectorSaving ? t('Saving') : t('Save selected') })] }), _jsx("button", { type: "button", className: "ghost memory-source-action", onClick: onDiscardConnectorSuggestions, disabled: connectorSaving, children: t('Discard') })] })] }));
|
|
90
|
+
}
|
|
91
|
+
function MemoryConnectorDiagnostics({ connectorAttempts, connectorContextBytes, }) {
|
|
92
|
+
const t = useT();
|
|
93
|
+
return (_jsxs("div", { className: "memory-connector-diagnostics", "aria-label": t('Connected app read status'), children: [_jsxs("div", { className: "memory-connector-diagnostics-head", children: [_jsx("strong", { children: t('Last scan') }), _jsxs("span", { children: [formatConnectorContextBytes(connectorContextBytes), " ", t('read')] })] }), _jsx("div", { className: "memory-connector-diagnostics-list", children: connectorAttempts.map((attempt) => (_jsxs("div", { className: `memory-connector-diagnostic-row is-${attempt.status}`, children: [_jsx("span", { className: "memory-connector-diagnostic-dot", "aria-hidden": "true" }), _jsxs("span", { className: "memory-connector-diagnostic-copy", children: [_jsx("strong", { children: connectorAttemptTitle(attempt) }), _jsx("small", { children: connectorAttemptDetail(attempt) })] })] }, `${attempt.connectorId}-${attempt.status}-${attempt.toolName ?? 'none'}`))) })] }));
|
|
94
|
+
}
|
|
95
|
+
function MemoryScanHistory({ connectorExtractions, nowClock, onOpenPreview, onDeleteExtraction, }) {
|
|
96
|
+
const t = useT();
|
|
97
|
+
return (_jsxs("details", { className: "memory-scan-history", children: [_jsxs("summary", { children: [_jsx("span", { children: t('Recent scans') }), _jsx("span", { children: connectorExtractions.length })] }), _jsx("div", { className: "memory-connector-run-history", "aria-label": t('Connected app memory run status'), children: connectorExtractions.slice(0, 4).map((record) => (_jsx(MemoryExtractionCard, { record: record, nowClock: nowClock, onOpenPreview: onOpenPreview, onDelete: onDeleteExtraction }, record.id))) })] }));
|
|
98
|
+
}
|
|
99
|
+
export function MemoryConnectedPanel({ enabled, onOpenConnectors, connectorStatuses, connectorsLoading, connectedCount, selectedConnectorIds, selectedConnectedConnectorIds, connectingConnectorIds, pendingConnectorAuthIds, connectorConnectErrors, connectorIdsWithDetails, connectorExtracting, connectorSaving, connectorScanLabel, connectorSuggestions, selectedSuggestionIds, selectedConnectorSuggestions, connectorStatus, connectorError, connectorLoadError, connectorAttempts, connectorContextBytes, connectorExtractions, memoryConnectors, toggleConnectorSelection, onConnectMemoryConnector, toggleConnectorSuggestion, onSuggestConnectorMemory, onSaveConnectorSuggestions, onDiscardConnectorSuggestions, nowClock, onOpenPreview, onDeleteExtraction, }) {
|
|
100
|
+
const t = useT();
|
|
101
|
+
const rowContext = {
|
|
102
|
+
connectorStatuses,
|
|
103
|
+
connectorsLoading,
|
|
104
|
+
selectedConnectorIds,
|
|
105
|
+
connectingConnectorIds,
|
|
106
|
+
pendingConnectorAuthIds,
|
|
107
|
+
connectorConnectErrors,
|
|
108
|
+
connectorIdsWithDetails,
|
|
109
|
+
};
|
|
110
|
+
return (_jsxs("div", { className: "memory-tab-panel memory-connected-panel", children: [_jsx(MemoryConnectedSummary, { connectorsLoading: connectorsLoading, connectedCount: connectedCount, onOpenConnectors: onOpenConnectors }), _jsxs("div", { className: "memory-connector-workbench", children: [connectorLoadError ? (_jsx("div", { role: "alert", className: "memory-connector-result is-error", children: connectorLoadError })) : null, _jsxs("div", { className: "memory-connector-picker-head", children: [_jsxs("div", { children: [_jsx("h4", { children: t('Choose sources') }), _jsx("p", { className: "hint", children: t('Select connected apps first. Only the apps you choose are scanned.') })] }), _jsxs("span", { className: "memory-source-badge", children: [selectedConnectedConnectorIds.length, " ", t('selected')] })] }), _jsx("div", { className: "memory-connector-list", "aria-label": t('Connected memory apps'), children: memoryConnectors.map((connector) => (_jsx(MemoryConnectorRow, { connector: connector, context: rowContext, toggleConnectorSelection: toggleConnectorSelection, onConnectMemoryConnector: onConnectMemoryConnector }, connector.id))) }), _jsx(MemoryConnectorRunBar, { enabled: enabled, connectorExtracting: connectorExtracting, connectorSaving: connectorSaving, connectedCount: connectedCount, selectedCount: selectedConnectedConnectorIds.length, connectorScanLabel: connectorScanLabel, onSuggestConnectorMemory: onSuggestConnectorMemory })] }), connectorSuggestions.length > 0 ? (_jsx(MemorySuggestionPanel, { connectorSuggestions: connectorSuggestions, selectedSuggestionIds: selectedSuggestionIds, selectedConnectorSuggestions: selectedConnectorSuggestions, connectorSaving: connectorSaving, toggleConnectorSuggestion: toggleConnectorSuggestion, onSaveConnectorSuggestions: onSaveConnectorSuggestions, onDiscardConnectorSuggestions: onDiscardConnectorSuggestions })) : null, connectorStatus ? (_jsx("div", { role: "status", className: "memory-connector-result is-success", children: connectorStatus })) : null, connectorError ? (_jsx("div", { role: "alert", className: "memory-connector-result is-error", children: connectorError })) : null, connectorAttempts.length > 0 ? (_jsx(MemoryConnectorDiagnostics, { connectorAttempts: connectorAttempts, connectorContextBytes: connectorContextBytes })) : null, connectorExtractions.length > 0 ? (_jsx(MemoryScanHistory, { connectorExtractions: connectorExtractions, nowClock: nowClock, onOpenPreview: onOpenPreview, onDeleteExtraction: onDeleteExtraction })) : null] }));
|
|
55
111
|
}
|
|
56
112
|
//# sourceMappingURL=MemoryConnectedPanel.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
// Dumb panel for the saved-memory records: counts, the type-filter pills, the
|
|
3
3
|
// extraction clear/refresh toolbar, and the unified list (saved entries + the
|
|
4
4
|
// visible extraction rows). Rendering only — every list, count, and handler is
|
|
@@ -11,24 +11,43 @@ import { TYPES } from '../../constants.js';
|
|
|
11
11
|
import { memoryTypeLabels } from '../../formatters.js';
|
|
12
12
|
import { MemoryEntryCard } from './MemoryEntryCard.js';
|
|
13
13
|
import { MemoryExtractionCard } from './MemoryExtractionCard.js';
|
|
14
|
-
|
|
14
|
+
/** Per-row agent handles under `<agentHandle>-<action>`, or undefined when unpublished. */
|
|
15
|
+
function rowHandles({ agentHandle, action, ids }) {
|
|
16
|
+
return agentHandle ? buildAgentListHandles({ prefix: agentSubHandle({ base: agentHandle, action }), ids }) : undefined;
|
|
17
|
+
}
|
|
18
|
+
function MemoryListCounts({ savedCount, extractionCount }) {
|
|
19
|
+
const t = useT();
|
|
20
|
+
return (_jsxs("div", { className: "memory-management-counts", children: [_jsxs("span", { className: "memory-source-badge", children: [savedCount, " ", t('saved')] }), extractionCount > 0 ? (_jsxs("span", { className: "memory-source-badge", children: [extractionCount, " ", extractionCount === 1 ? t('extraction') : t('extractions')] })) : null] }));
|
|
21
|
+
}
|
|
22
|
+
function MemoryFilterPills({ entries, extractionCount, filter, onFilterChange, agentHandle, }) {
|
|
15
23
|
const t = useT();
|
|
16
24
|
const typeLabel = useMemo(() => memoryTypeLabels(t), [t]);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
return (_jsxs("div", { className: "library-filters", children: [_jsxs("button", { type: "button", className: `filter-pill${filter === 'all' ? ' active' : ''}`, onClick: () => onFilterChange('all'), ...agentHandleProps({}, { base: agentHandle, action: 'filter-all', role: 'button', label: t('All') }), children: [t('All'), _jsx("span", { className: "filter-pill-count", children: entries.length + extractionCount })] }), TYPES.map((type) => {
|
|
26
|
+
const count = entries.filter((e) => e.type === type).length;
|
|
27
|
+
if (count === 0 && filter !== type)
|
|
28
|
+
return null;
|
|
29
|
+
return (_jsxs("button", { type: "button", className: `filter-pill${filter === type ? ' active' : ''}`, onClick: () => onFilterChange(type), ...agentHandleProps({}, { base: agentHandle, action: `filter-${type}`, role: 'button', label: typeLabel[type] }), children: [typeLabel[type], _jsx("span", { className: "filter-pill-count", children: count })] }, type));
|
|
30
|
+
})] }));
|
|
31
|
+
}
|
|
32
|
+
function MemoryExtractionActions({ onClearExtractions, onRefreshExtractions, isRefreshing, agentHandle, }) {
|
|
33
|
+
const t = useT();
|
|
34
|
+
return (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", className: "ghost memory-clear-extractions", onClick: () => onClearExtractions(), title: t('Clear extraction history'), ...agentHandleProps({}, { base: agentHandle, action: 'clear-extractions', role: 'button', label: t('Clear extraction history') }), children: [_jsx(Icon, { name: "close", size: 12 }), _jsx("span", { children: t('Clear') })] }), _jsxs("button", { type: "button", className: "ghost memory-refresh-extractions", onClick: () => onRefreshExtractions(), disabled: isRefreshing, title: t('Refresh'), ...agentHandleProps({}, { base: agentHandle, action: 'refresh-extractions', role: 'button', label: t('Refresh') }), children: [_jsx(Icon, { name: "refresh", size: 12, className: isRefreshing ? 'icon-spin' : '' }), _jsx("span", { children: isRefreshing ? t('Refreshing') : t('Refresh') })] })] }));
|
|
35
|
+
}
|
|
36
|
+
function MemoryListEmpty() {
|
|
37
|
+
const t = useT();
|
|
38
|
+
return (
|
|
39
|
+
// Empty state: one clear "no rows yet" line and a one-sentence
|
|
40
|
+
// primer that explains the mechanism (talk in chat, fact gets
|
|
41
|
+
// extracted) with a single example.
|
|
42
|
+
_jsxs("div", { className: "library-empty", children: [_jsx("p", { className: "library-empty-title", children: t('No saved memories yet') }), _jsxs("p", { className: "library-empty-hint", children: [t('Tell the assistant a fact in chat — e.g.'), " ", _jsx("code", { children: t('I prefer dark mode') }), ' ', t('— and it will be saved here automatically.')] })] }));
|
|
43
|
+
}
|
|
44
|
+
function MemoryListRows({ filtered, visibleExtractions, previewId, previewBody, nowClock, onOpenPreview, onStartEdit, onDeleteEntry, onDeleteExtraction, agentHandle, }) {
|
|
45
|
+
const entryHandles = rowHandles({ agentHandle, action: 'entry', ids: filtered.map((e) => e.id) });
|
|
46
|
+
const extractionHandles = rowHandles({ agentHandle, action: 'extraction', ids: visibleExtractions.map((r) => r.id) });
|
|
47
|
+
return (_jsxs(_Fragment, { children: [filtered.map((entry, index) => (_jsx(MemoryEntryCard, { entry: entry, previewId: previewId, previewBody: previewBody, onOpenPreview: onOpenPreview, onStartEdit: onStartEdit, onDelete: onDeleteEntry, ...(entryHandles?.[index] ? { agentHandle: entryHandles[index] } : {}) }, entry.id))), visibleExtractions.map((record, index) => (_jsx(MemoryExtractionCard, { record: record, nowClock: nowClock, onOpenPreview: onOpenPreview, onDelete: onDeleteExtraction, ...(extractionHandles?.[index] ? { agentHandle: extractionHandles[index] } : {}) }, record.id)))] }));
|
|
48
|
+
}
|
|
49
|
+
export function MemoryList({ sectionRef, entries, filtered, visibleExtractions, filter, onFilterChange, unifiedMemoryCount, onClearExtractions, onRefreshExtractions, isRefreshing, previewId, previewBody, nowClock, onOpenPreview, onStartEdit, onDeleteEntry, onDeleteExtraction, agentHandle, }) {
|
|
50
|
+
const t = useT();
|
|
51
|
+
return (_jsx("section", { ref: sectionRef, className: "settings-section settings-section-card memory-records-section", children: _jsxs("div", { className: "memory-management-panel", children: [_jsxs("div", { className: "memory-subsection-head", children: [_jsxs("div", { children: [_jsx("h4", { children: t('Saved memory') }), _jsx("p", { className: "hint", children: t('Saved facts, preferences, and project context available to future chats.') })] }), _jsx(MemoryListCounts, { savedCount: entries.length, extractionCount: visibleExtractions.length })] }), _jsxs("div", { className: "library-toolbar is-row", children: [_jsx(MemoryFilterPills, { entries: entries, extractionCount: visibleExtractions.length, filter: filter, onFilterChange: onFilterChange, agentHandle: agentHandle }), _jsx("div", { className: "memory-management-actions", children: visibleExtractions.length > 0 ? (_jsx(MemoryExtractionActions, { onClearExtractions: onClearExtractions, onRefreshExtractions: onRefreshExtractions, isRefreshing: isRefreshing, agentHandle: agentHandle })) : null })] }), _jsx("div", { className: "library-content memory-unified-list", children: unifiedMemoryCount === 0 ? (_jsx(MemoryListEmpty, {})) : (_jsx(MemoryListRows, { filtered: filtered, visibleExtractions: visibleExtractions, previewId: previewId, previewBody: previewBody, nowClock: nowClock, onOpenPreview: onOpenPreview, onStartEdit: onStartEdit, onDeleteEntry: onDeleteEntry, onDeleteExtraction: onDeleteExtraction, agentHandle: agentHandle })) })] }) }));
|
|
33
52
|
}
|
|
34
53
|
//# sourceMappingURL=MemoryList.js.map
|
|
@@ -81,30 +81,51 @@ export function createExtractionHistoryStore(onRowsChanged) {
|
|
|
81
81
|
function tombstone(id) {
|
|
82
82
|
tombstones.add(id);
|
|
83
83
|
}
|
|
84
|
+
function applyClearedFrame() {
|
|
85
|
+
// A remote clear removed every attempt the daemon knew about, which
|
|
86
|
+
// covers everything this client has observed: visible rows, ids hidden
|
|
87
|
+
// by a pending local delete, and buffered frames. Tombstone them all
|
|
88
|
+
// (rule C) so delayed frames cannot recreate discarded attempts.
|
|
89
|
+
const owned = new Set([...rows.map((row) => row.id), ...pendingDeletes.keys(), ...deferred.keys()]);
|
|
90
|
+
for (const id of owned)
|
|
91
|
+
tombstone(id);
|
|
92
|
+
deferred.clear();
|
|
93
|
+
clearStamp = commit([]);
|
|
94
|
+
}
|
|
95
|
+
function applyDeletedFrame({ id }) {
|
|
96
|
+
deferred.delete(id);
|
|
97
|
+
tombstone(id);
|
|
98
|
+
commit(rows.filter((row) => row.id !== id));
|
|
99
|
+
}
|
|
100
|
+
function deferFrame(ev) {
|
|
101
|
+
const prior = deferred.get(ev.id);
|
|
102
|
+
deferred.set(ev.id, prior ? mergeSameAttempt(prior, ev) : ev);
|
|
103
|
+
}
|
|
104
|
+
function upsertFrame(ev) {
|
|
105
|
+
// Merge by id (rule B): phase transitions for an in-flight attempt
|
|
106
|
+
// collapse onto a single row instead of stacking N entries. New ids are
|
|
107
|
+
// unshifted so the latest appears at the top.
|
|
108
|
+
const at = rows.findIndex((row) => row.id === ev.id);
|
|
109
|
+
let next;
|
|
110
|
+
if (at >= 0) {
|
|
111
|
+
next = rows.slice();
|
|
112
|
+
next[at] = mergeSameAttempt(next[at], ev);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
next = [ev, ...rows].slice(0, MAX_ROWS);
|
|
116
|
+
}
|
|
117
|
+
rowStamp.set(ev.id, commit(next));
|
|
118
|
+
}
|
|
84
119
|
function applyFrame(ev) {
|
|
85
120
|
if (!ev || !ev.id)
|
|
86
121
|
return;
|
|
87
122
|
// Pseudo-phases: the daemon emits these synthetically when a row is
|
|
88
123
|
// dropped from the buffer, by the per-row delete button or the "Clear"
|
|
89
124
|
// affordance at the top (possibly in another client).
|
|
90
|
-
if (ev.phase === 'cleared')
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// (rule C) so delayed frames cannot recreate discarded attempts.
|
|
95
|
-
const owned = new Set([...rows.map((row) => row.id), ...pendingDeletes.keys(), ...deferred.keys()]);
|
|
96
|
-
for (const id of owned)
|
|
97
|
-
tombstone(id);
|
|
98
|
-
deferred.clear();
|
|
99
|
-
clearStamp = commit([]);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (ev.phase === 'deleted') {
|
|
103
|
-
deferred.delete(ev.id);
|
|
104
|
-
tombstone(ev.id);
|
|
105
|
-
commit(rows.filter((row) => row.id !== ev.id));
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
125
|
+
if (ev.phase === 'cleared')
|
|
126
|
+
return applyClearedFrame();
|
|
127
|
+
if (ev.phase === 'deleted')
|
|
128
|
+
return applyDeletedFrame({ id: ev.id });
|
|
108
129
|
// Rule C: a confirmed-removed id never comes back. A delayed frame on
|
|
109
130
|
// the SSE connection may have been emitted before the DELETE response
|
|
110
131
|
// won the fetch race.
|
|
@@ -115,24 +136,9 @@ export function createExtractionHistoryStore(onRowsChanged) {
|
|
|
115
136
|
// operation for their id. Buffer them (content-merged, rule B) so they
|
|
116
137
|
// cannot visibly undo the optimistic removal; the settle path replays
|
|
117
138
|
// the best buffered frame on failure and tombstones it on success.
|
|
118
|
-
if (pendingDeletes.has(ev.id) || pendingClears > 0)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
// Merge by id (rule B): phase transitions for an in-flight attempt
|
|
124
|
-
// collapse onto a single row instead of stacking N entries. New ids are
|
|
125
|
-
// unshifted so the latest appears at the top.
|
|
126
|
-
const at = rows.findIndex((row) => row.id === ev.id);
|
|
127
|
-
let next;
|
|
128
|
-
if (at >= 0) {
|
|
129
|
-
next = rows.slice();
|
|
130
|
-
next[at] = mergeSameAttempt(next[at], ev);
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
next = [ev, ...rows].slice(0, MAX_ROWS);
|
|
134
|
-
}
|
|
135
|
-
rowStamp.set(ev.id, commit(next));
|
|
139
|
+
if (pendingDeletes.has(ev.id) || pendingClears > 0)
|
|
140
|
+
return deferFrame(ev);
|
|
141
|
+
upsertFrame(ev);
|
|
136
142
|
}
|
|
137
143
|
function commitSnapshot(confirmed, sinceClock) {
|
|
138
144
|
// An authoritative clear younger than this read supersedes the whole
|