@vertesia/ui 1.5.0-dev.20260722.120446Z → 1.5.0-dev.20260725.083715Z
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/lib/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
- package/lib/core/components/shadcn/filters/filterBar.js +1 -1
- package/lib/core/components/shadcn/filters/filterBar.js.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.d.ts +1 -1
- package/lib/core/components/shadcn/modal/dialog.d.ts.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.js +2 -0
- package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
- package/lib/core/components/shadcn/tabs.d.ts +12 -1
- package/lib/core/components/shadcn/tabs.d.ts.map +1 -1
- package/lib/core/components/shadcn/tabs.js +12 -4
- package/lib/core/components/shadcn/tabs.js.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.d.ts +5 -1
- package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.js +2 -2
- package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.d.ts +5 -1
- package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.js +48 -11
- package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
- package/lib/features/agent/chat/DocumentEditingActionCard.d.ts +6 -0
- package/lib/features/agent/chat/DocumentEditingActionCard.d.ts.map +1 -0
- package/lib/features/agent/chat/DocumentEditingActionCard.js +129 -0
- package/lib/features/agent/chat/DocumentEditingActionCard.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentConversation.d.ts +19 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +125 -27
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts +45 -0
- package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js +40 -0
- package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +94 -49
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts +2 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +9 -5
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts +25 -0
- package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js +33 -0
- package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +3 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +22 -24
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts +14 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js +21 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts +30 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js +53 -0
- package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js +21 -2
- package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts +6 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js +29 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts +33 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js +129 -0
- package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +7 -0
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.js +11 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.js +24 -9
- package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
- package/lib/features/agent/chat/index.d.ts +2 -1
- package/lib/features/agent/chat/index.d.ts.map +1 -1
- package/lib/features/agent/chat/index.js +3 -0
- package/lib/features/agent/chat/index.js.map +1 -1
- package/lib/features/store/objects/DocumentSearchResults.js +2 -2
- package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.d.ts +2 -1
- package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.js +86 -15
- package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts +16 -0
- package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js +116 -0
- package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts +7 -0
- package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingLockStatus.js +13 -0
- package/lib/features/store/objects/components/DocumentEditingLockStatus.js.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingPanel.d.ts +48 -0
- package/lib/features/store/objects/components/DocumentEditingPanel.d.ts.map +1 -0
- package/lib/features/store/objects/components/DocumentEditingPanel.js +720 -0
- package/lib/features/store/objects/components/DocumentEditingPanel.js.map +1 -0
- package/lib/features/store/objects/components/TextEditorPanel.d.ts.map +1 -1
- package/lib/features/store/objects/components/TextEditorPanel.js +22 -9
- package/lib/features/store/objects/components/TextEditorPanel.js.map +1 -1
- package/lib/features/store/objects/components/documentArtifactRefs.d.ts +26 -0
- package/lib/features/store/objects/components/documentArtifactRefs.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentArtifactRefs.js +52 -0
- package/lib/features/store/objects/components/documentArtifactRefs.js.map +1 -0
- package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts +4 -0
- package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentEditingAgentConfig.js +40 -0
- package/lib/features/store/objects/components/documentEditingAgentConfig.js.map +1 -0
- package/lib/features/store/objects/components/documentEditingPrompts.d.ts +3 -0
- package/lib/features/store/objects/components/documentEditingPrompts.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentEditingPrompts.js +13 -0
- package/lib/features/store/objects/components/documentEditingPrompts.js.map +1 -0
- package/lib/features/store/objects/components/documentEditingRun.d.ts +27 -0
- package/lib/features/store/objects/components/documentEditingRun.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentEditingRun.js +126 -0
- package/lib/features/store/objects/components/documentEditingRun.js.map +1 -0
- package/lib/features/store/objects/components/documentEditingTarget.d.ts +20 -0
- package/lib/features/store/objects/components/documentEditingTarget.d.ts.map +1 -0
- package/lib/features/store/objects/components/documentEditingTarget.js +40 -0
- package/lib/features/store/objects/components/documentEditingTarget.js.map +1 -0
- package/lib/features/store/objects/components/index.d.ts +1 -0
- package/lib/features/store/objects/components/index.d.ts.map +1 -1
- package/lib/features/store/objects/components/index.js +1 -0
- package/lib/features/store/objects/components/index.js.map +1 -1
- package/lib/features/store/objects/components/useContentPanelHooks.d.ts +5 -1
- package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
- package/lib/features/store/objects/components/useContentPanelHooks.js +53 -29
- package/lib/features/store/objects/components/useContentPanelHooks.js.map +1 -1
- package/lib/features/store/objects/components/useDownloadFile.d.ts +2 -1
- package/lib/features/store/objects/components/useDownloadFile.d.ts.map +1 -1
- package/lib/features/store/objects/components/useDownloadFile.js +3 -0
- package/lib/features/store/objects/components/useDownloadFile.js.map +1 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +1 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +1 -1
- package/lib/i18n/locales/ar.json +118 -1
- package/lib/i18n/locales/de.json +118 -1
- package/lib/i18n/locales/en.json +118 -0
- package/lib/i18n/locales/es.json +118 -1
- package/lib/i18n/locales/fr.json +118 -1
- package/lib/i18n/locales/it.json +118 -1
- package/lib/i18n/locales/ja.json +118 -1
- package/lib/i18n/locales/ko.json +118 -1
- package/lib/i18n/locales/pt.json +118 -1
- package/lib/i18n/locales/ru.json +118 -1
- package/lib/i18n/locales/tr.json +118 -1
- package/lib/i18n/locales/zh-TW.json +118 -1
- package/lib/i18n/locales/zh.json +118 -1
- package/lib/rich-text/EditorToolbar.d.ts +37 -0
- package/lib/rich-text/EditorToolbar.d.ts.map +1 -0
- package/lib/rich-text/EditorToolbar.js +215 -0
- package/lib/rich-text/EditorToolbar.js.map +1 -0
- package/lib/rich-text/VertesiaRichTextEditor.d.ts +26 -0
- package/lib/rich-text/VertesiaRichTextEditor.d.ts.map +1 -0
- package/lib/rich-text/VertesiaRichTextEditor.js +67 -0
- package/lib/rich-text/VertesiaRichTextEditor.js.map +1 -0
- package/lib/rich-text/index.d.ts +2 -0
- package/lib/rich-text/index.d.ts.map +1 -0
- package/lib/rich-text/index.js +2 -0
- package/lib/rich-text/index.js.map +1 -0
- package/lib/vertesia-ui-core.js +2 -2
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-features.js +35 -30
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.js +14 -14
- package/lib/vertesia-ui-i18n.js.map +1 -1
- package/lib/vertesia-ui-rich-text.js +5 -0
- package/lib/vertesia-ui-rich-text.js.map +1 -0
- package/lib/vertesia-ui-widgets.js +25 -7
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/markdown/AgentResourceResolver.d.ts +31 -0
- package/lib/widgets/markdown/AgentResourceResolver.d.ts.map +1 -0
- package/lib/widgets/markdown/AgentResourceResolver.js +39 -0
- package/lib/widgets/markdown/AgentResourceResolver.js.map +1 -0
- package/lib/widgets/markdown/ArtifactEditingSurface.d.ts +63 -0
- package/lib/widgets/markdown/ArtifactEditingSurface.d.ts.map +1 -0
- package/lib/widgets/markdown/ArtifactEditingSurface.js +582 -0
- package/lib/widgets/markdown/ArtifactEditingSurface.js.map +1 -0
- package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts +69 -0
- package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts.map +1 -0
- package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js +374 -0
- package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js.map +1 -0
- package/lib/widgets/markdown/MarkdownLink.d.ts +3 -1
- package/lib/widgets/markdown/MarkdownLink.d.ts.map +1 -1
- package/lib/widgets/markdown/MarkdownLink.js +41 -14
- package/lib/widgets/markdown/MarkdownLink.js.map +1 -1
- package/lib/widgets/markdown/MarkdownRenderer.d.ts +8 -1
- package/lib/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
- package/lib/widgets/markdown/MarkdownRenderer.js +20 -4
- package/lib/widgets/markdown/MarkdownRenderer.js.map +1 -1
- package/lib/widgets/markdown/index.d.ts +5 -1
- package/lib/widgets/markdown/index.d.ts.map +1 -1
- package/lib/widgets/markdown/index.js +5 -1
- package/lib/widgets/markdown/index.js.map +1 -1
- package/lib/widgets/markdown/normalizeCustomSchemeLinks.d.ts.map +1 -1
- package/lib/widgets/markdown/normalizeCustomSchemeLinks.js +14 -2
- package/lib/widgets/markdown/normalizeCustomSchemeLinks.js.map +1 -1
- package/lib/widgets/markdown/textDiff.d.ts +52 -0
- package/lib/widgets/markdown/textDiff.d.ts.map +1 -0
- package/lib/widgets/markdown/textDiff.js +362 -0
- package/lib/widgets/markdown/textDiff.js.map +1 -0
- package/lib/widgets/markdown/useArtifactContent.d.ts +5 -3
- package/lib/widgets/markdown/useArtifactContent.d.ts.map +1 -1
- package/lib/widgets/markdown/useArtifactContent.js +6 -3
- package/lib/widgets/markdown/useArtifactContent.js.map +1 -1
- package/lib/widgets/markdown/useResolvedUrl.d.ts +1 -5
- package/lib/widgets/markdown/useResolvedUrl.d.ts.map +1 -1
- package/lib/widgets/markdown/useResolvedUrl.js +19 -31
- package/lib/widgets/markdown/useResolvedUrl.js.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts +9 -0
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.js +20 -17
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.js.map +1 -1
- package/package.json +13 -9
- package/src/__tests__/a11y.test.tsx +4 -1
- package/src/__tests__/axe-helper.ts +17 -7
- package/src/__tests__/setup.ts +25 -0
- package/src/core/components/shadcn/filters/filterBar.tsx +1 -0
- package/src/core/components/shadcn/modal/dialog.tsx +3 -1
- package/src/core/components/shadcn/tabs.test.tsx +65 -0
- package/src/core/components/shadcn/tabs.tsx +25 -3
- package/src/features/agent/chat/AgentRightPanel.tsx +16 -1
- package/src/features/agent/chat/ArtifactsTab.test.tsx +55 -0
- package/src/features/agent/chat/ArtifactsTab.tsx +203 -52
- package/src/features/agent/chat/DocumentEditingActionCard.test.tsx +105 -0
- package/src/features/agent/chat/DocumentEditingActionCard.tsx +210 -0
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +237 -40
- package/src/features/agent/chat/ModernAgentConversation.tsx +247 -75
- package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.test.tsx +79 -0
- package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.tsx +94 -0
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +257 -34
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +217 -105
- package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +17 -0
- package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.test.tsx +44 -0
- package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.tsx +88 -0
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +30 -46
- package/src/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.tsx +40 -0
- package/src/features/agent/chat/ModernAgentOutput/ResourceChip.test.tsx +148 -0
- package/src/features/agent/chat/ModernAgentOutput/ResourceChip.tsx +141 -0
- package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +33 -1
- package/src/features/agent/chat/ModernAgentOutput/resourceLinks.tsx +43 -0
- package/src/features/agent/chat/ModernAgentOutput/resourceSummary.test.ts +229 -0
- package/src/features/agent/chat/ModernAgentOutput/resourceSummary.ts +152 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +17 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.ts +14 -1
- package/src/features/agent/chat/hooks/useAgentStream.test.tsx +188 -0
- package/src/features/agent/chat/hooks/useAgentStream.ts +28 -8
- package/src/features/agent/chat/index.ts +11 -0
- package/src/features/store/objects/DocumentSearchResults.tsx +2 -2
- package/src/features/store/objects/components/ContentOverview.tsx +216 -65
- package/src/features/store/objects/components/DocumentEditingConfigurationSelector.test.ts +34 -0
- package/src/features/store/objects/components/DocumentEditingConfigurationSelector.tsx +211 -0
- package/src/features/store/objects/components/DocumentEditingLockStatus.test.tsx +32 -0
- package/src/features/store/objects/components/DocumentEditingLockStatus.tsx +45 -0
- package/src/features/store/objects/components/DocumentEditingPanel.test.tsx +336 -0
- package/src/features/store/objects/components/DocumentEditingPanel.tsx +1236 -0
- package/src/features/store/objects/components/TextEditorPanel.test.tsx +48 -0
- package/src/features/store/objects/components/TextEditorPanel.tsx +41 -20
- package/src/features/store/objects/components/documentArtifactRefs.test.ts +65 -0
- package/src/features/store/objects/components/documentArtifactRefs.ts +72 -0
- package/src/features/store/objects/components/documentEditingAgentConfig.test.ts +28 -0
- package/src/features/store/objects/components/documentEditingAgentConfig.ts +41 -0
- package/src/features/store/objects/components/documentEditingPrompts.test.ts +26 -0
- package/src/features/store/objects/components/documentEditingPrompts.ts +12 -0
- package/src/features/store/objects/components/documentEditingRun.test.ts +176 -0
- package/src/features/store/objects/components/documentEditingRun.ts +184 -0
- package/src/features/store/objects/components/documentEditingTarget.test.ts +96 -0
- package/src/features/store/objects/components/documentEditingTarget.ts +63 -0
- package/src/features/store/objects/components/index.ts +1 -0
- package/src/features/store/objects/components/useContentPanelHooks.ts +52 -27
- package/src/features/store/objects/components/useDownloadFile.test.ts +20 -0
- package/src/features/store/objects/components/useDownloadFile.ts +5 -1
- package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +2 -2
- package/src/i18n/locales/ar.json +118 -1
- package/src/i18n/locales/de.json +118 -1
- package/src/i18n/locales/en.json +118 -0
- package/src/i18n/locales/es.json +118 -1
- package/src/i18n/locales/fr.json +118 -1
- package/src/i18n/locales/it.json +118 -1
- package/src/i18n/locales/ja.json +118 -1
- package/src/i18n/locales/ko.json +118 -1
- package/src/i18n/locales/pt.json +118 -1
- package/src/i18n/locales/ru.json +118 -1
- package/src/i18n/locales/tr.json +118 -1
- package/src/i18n/locales/zh-TW.json +118 -1
- package/src/i18n/locales/zh.json +118 -1
- package/src/rich-text/EditorToolbar.tsx +708 -0
- package/src/rich-text/VertesiaRichTextEditor.test.tsx +211 -0
- package/src/rich-text/VertesiaRichTextEditor.tsx +241 -0
- package/src/rich-text/index.ts +9 -0
- package/src/session/UserSession.test.ts +11 -11
- package/src/widgets/markdown/AgentResourceResolver.test.ts +24 -0
- package/src/widgets/markdown/AgentResourceResolver.tsx +70 -0
- package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +537 -0
- package/src/widgets/markdown/ArtifactEditingSurface.tsx +878 -0
- package/src/widgets/markdown/CollaborativeMarkdownRenderer.test.tsx +484 -0
- package/src/widgets/markdown/CollaborativeMarkdownRenderer.tsx +825 -0
- package/src/widgets/markdown/MarkdownLink.test.tsx +122 -0
- package/src/widgets/markdown/MarkdownLink.tsx +102 -17
- package/src/widgets/markdown/MarkdownRenderer.tsx +30 -3
- package/src/widgets/markdown/index.ts +39 -1
- package/src/widgets/markdown/normalizeCustomSchemeLinks.ts +15 -2
- package/src/widgets/markdown/textDiff.test.ts +156 -0
- package/src/widgets/markdown/textDiff.ts +399 -0
- package/src/widgets/markdown/useArtifactContent.ts +9 -3
- package/src/widgets/markdown/useResolvedUrl.test.ts +29 -40
- package/src/widgets/markdown/useResolvedUrl.ts +33 -35
- package/src/widgets/xml-viewer/hooks/useXMLViewer.test.ts +26 -0
- package/src/widgets/xml-viewer/hooks/useXMLViewer.ts +23 -18
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** @vitest-environment jsdom */
|
|
2
|
+
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import type { ContentObject } from '@vertesia/common';
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { I18nProvider } from '../../../../i18n/index.js';
|
|
7
|
+
import { TextEditorPanel } from './TextEditorPanel.js';
|
|
8
|
+
|
|
9
|
+
const mocks = vi.hoisted(() => ({
|
|
10
|
+
navigate: vi.fn(),
|
|
11
|
+
update: vi.fn(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
vi.mock('@vertesia/ui/router', () => ({
|
|
15
|
+
useNavigate: () => mocks.navigate,
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
vi.mock('@vertesia/ui/session', () => ({
|
|
19
|
+
useUserSession: () => ({
|
|
20
|
+
store: { objects: { update: mocks.update } },
|
|
21
|
+
}),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
describe('TextEditorPanel', () => {
|
|
25
|
+
it.each(['text/markdown', 'text/x-markdown'])(
|
|
26
|
+
'uses the full rich-text document editor for %s content',
|
|
27
|
+
async (contentType) => {
|
|
28
|
+
const object = {
|
|
29
|
+
id: 'document-1',
|
|
30
|
+
content: {
|
|
31
|
+
type: contentType,
|
|
32
|
+
name: 'document.md',
|
|
33
|
+
etag: 'etag-1',
|
|
34
|
+
},
|
|
35
|
+
} as unknown as ContentObject;
|
|
36
|
+
|
|
37
|
+
render(
|
|
38
|
+
<I18nProvider lng="en">
|
|
39
|
+
<TextEditorPanel object={object} text="# Editable document" onClose={vi.fn()} onSaved={vi.fn()} />
|
|
40
|
+
</I18nProvider>,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
expect(await screen.findByRole('textbox', { name: 'Markdown document editor' })).not.toBeNull();
|
|
44
|
+
expect(screen.getByRole('heading', { name: 'Editable document' })).not.toBeNull();
|
|
45
|
+
expect(await screen.findByRole('toolbar')).not.toBeNull();
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
});
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { ContentObject } from '@vertesia/common';
|
|
2
2
|
import { Button, errorMessage, useTheme, useToast } from '@vertesia/ui/core';
|
|
3
3
|
import { useUITranslation } from '@vertesia/ui/i18n';
|
|
4
|
+
import { VertesiaMarkdownDocumentEditor } from '@vertesia/ui/rich-text';
|
|
4
5
|
import { useNavigate } from '@vertesia/ui/router';
|
|
5
6
|
import { useUserSession } from '@vertesia/ui/session';
|
|
6
7
|
import { type IEditorApi, MonacoEditor } from '@vertesia/ui/widgets';
|
|
7
|
-
import { useCallback, useRef, useState } from 'react';
|
|
8
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
9
|
+
import { isMarkdownContentType } from './documentEditingRun.js';
|
|
8
10
|
import { SaveVersionConfirmModal } from './SaveVersionConfirmModal.js';
|
|
9
11
|
|
|
10
12
|
interface TextEditorPanelProps {
|
|
@@ -17,6 +19,7 @@ interface TextEditorPanelProps {
|
|
|
17
19
|
function getMonacoLanguage(contentType?: string): string {
|
|
18
20
|
switch (contentType) {
|
|
19
21
|
case 'text/markdown':
|
|
22
|
+
case 'text/x-markdown':
|
|
20
23
|
return 'markdown';
|
|
21
24
|
case 'application/json':
|
|
22
25
|
return 'json';
|
|
@@ -35,34 +38,48 @@ export function TextEditorPanel({ object, text, onClose, onSaved }: TextEditorPa
|
|
|
35
38
|
const { theme } = useTheme();
|
|
36
39
|
const navigate = useNavigate();
|
|
37
40
|
const editorRef = useRef<IEditorApi | undefined>(undefined);
|
|
41
|
+
const [editorText, setEditorText] = useState(text);
|
|
38
42
|
const [isDirty, setIsDirty] = useState(false);
|
|
39
43
|
const [isSaving, setIsSaving] = useState(false);
|
|
40
44
|
const [showConfirmation, setShowConfirmation] = useState(false);
|
|
41
45
|
|
|
42
46
|
const language = getMonacoLanguage(object.content?.type);
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
const isMarkdown = isMarkdownContentType(object.content?.type);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
setEditorText(text);
|
|
51
|
+
setIsDirty(false);
|
|
52
|
+
}, [text]);
|
|
45
53
|
|
|
46
54
|
const handleEditorChange = useCallback(() => {
|
|
47
55
|
if (!isDirty) setIsDirty(true);
|
|
48
56
|
}, [isDirty]);
|
|
49
57
|
|
|
58
|
+
const handleMarkdownChange = useCallback(
|
|
59
|
+
(markdown: string) => {
|
|
60
|
+
setEditorText(markdown);
|
|
61
|
+
setIsDirty(markdown !== text);
|
|
62
|
+
},
|
|
63
|
+
[text],
|
|
64
|
+
);
|
|
65
|
+
|
|
50
66
|
function handleSave() {
|
|
51
|
-
if (!editorRef.current) return;
|
|
67
|
+
if (!isMarkdown && !editorRef.current) return;
|
|
52
68
|
setShowConfirmation(true);
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
async function saveText(createVersion: boolean, versionLabel?: string) {
|
|
56
|
-
if (!editorRef.current) return;
|
|
72
|
+
if (!isMarkdown && !editorRef.current) return;
|
|
57
73
|
|
|
58
|
-
const
|
|
74
|
+
const content = isMarkdown ? editorText : editorRef.current?.getValue();
|
|
75
|
+
if (content === undefined) return;
|
|
59
76
|
const contentType = object.content?.type || 'text/plain';
|
|
60
77
|
const fileName = object.content?.name || 'content.txt';
|
|
61
78
|
|
|
62
79
|
try {
|
|
63
80
|
setIsSaving(true);
|
|
64
81
|
|
|
65
|
-
const blob = new Blob([
|
|
82
|
+
const blob = new Blob([content], { type: contentType });
|
|
66
83
|
const file = new File([blob], fileName, { type: contentType });
|
|
67
84
|
|
|
68
85
|
const response = await store.objects.update(
|
|
@@ -121,19 +138,23 @@ export function TextEditorPanel({ object, text, onClose, onSaved }: TextEditorPa
|
|
|
121
138
|
</Button>
|
|
122
139
|
</div>
|
|
123
140
|
<div className="flex-1 min-h-0 border rounded-md overflow-hidden mx-2 mb-2">
|
|
124
|
-
|
|
125
|
-
value={
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
{isMarkdown ? (
|
|
142
|
+
<VertesiaMarkdownDocumentEditor value={editorText} onChange={handleMarkdownChange} />
|
|
143
|
+
) : (
|
|
144
|
+
<MonacoEditor
|
|
145
|
+
value={text}
|
|
146
|
+
language={language}
|
|
147
|
+
editorRef={editorRef}
|
|
148
|
+
onChange={handleEditorChange}
|
|
149
|
+
theme={theme === 'dark' ? 'vs-dark' : 'vs'}
|
|
150
|
+
options={{
|
|
151
|
+
wordWrap: 'on',
|
|
152
|
+
minimap: { enabled: false },
|
|
153
|
+
lineNumbers: 'on',
|
|
154
|
+
scrollBeyondLastLine: false,
|
|
155
|
+
}}
|
|
156
|
+
/>
|
|
157
|
+
)}
|
|
137
158
|
</div>
|
|
138
159
|
|
|
139
160
|
<SaveVersionConfirmModal
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { collectRunLocalArtifactRefs, persistRunLocalArtifactRefs } from './documentArtifactRefs.js';
|
|
3
|
+
|
|
4
|
+
const DOC = [
|
|
5
|
+
'',
|
|
6
|
+
'',
|
|
7
|
+
'',
|
|
8
|
+
'',
|
|
9
|
+
'[data file](artifact:files/data.csv)',
|
|
10
|
+
'',
|
|
11
|
+
].join('\n');
|
|
12
|
+
|
|
13
|
+
describe('collectRunLocalArtifactRefs', () => {
|
|
14
|
+
it('collects only run-local refs, deduplicated', () => {
|
|
15
|
+
expect(collectRunLocalArtifactRefs(DOC)).toEqual(['out/02_chart.png', 'files/data.csv']);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('ignores documents/ and agents/ refs and non-artifact urls', () => {
|
|
19
|
+
expect(collectRunLocalArtifactRefs(' ')).toEqual([]);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('persistRunLocalArtifactRefs', () => {
|
|
24
|
+
it('copies each run-local ref once and rewrites all occurrences', async () => {
|
|
25
|
+
const copyFile = vi.fn().mockResolvedValue('ok');
|
|
26
|
+
const result = await persistRunLocalArtifactRefs({ copyFile }, DOC, 'run-1', 'batch-1');
|
|
27
|
+
|
|
28
|
+
expect(copyFile).toHaveBeenCalledTimes(2);
|
|
29
|
+
expect(copyFile).toHaveBeenCalledWith('agents/run-1/out/02_chart.png', 'documents/batch-1/out/02_chart.png');
|
|
30
|
+
expect(copyFile).toHaveBeenCalledWith('agents/run-1/files/data.csv', 'documents/batch-1/files/data.csv');
|
|
31
|
+
|
|
32
|
+
expect(result.content).toContain('');
|
|
33
|
+
expect(result.content).toContain('');
|
|
34
|
+
expect(result.content).toContain('[data file](artifact:documents/batch-1/files/data.csv)');
|
|
35
|
+
// Durable and external refs stay untouched
|
|
36
|
+
expect(result.content).toContain('artifact:documents/abc-123/out/01_chart.png');
|
|
37
|
+
expect(result.content).toContain('artifact:agents/run-9/out/03_chart.png');
|
|
38
|
+
expect(result.content).toContain('https://example.com/x.png');
|
|
39
|
+
expect(result.persisted).toHaveLength(2);
|
|
40
|
+
expect(result.failed).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('pins failed copies to the explicit run-scoped path', async () => {
|
|
44
|
+
const copyFile = vi.fn().mockRejectedValue(new Error('not found'));
|
|
45
|
+
const result = await persistRunLocalArtifactRefs(
|
|
46
|
+
{ copyFile },
|
|
47
|
+
'',
|
|
48
|
+
'run-1',
|
|
49
|
+
'batch-1',
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
expect(result.content).toBe('');
|
|
53
|
+
expect(result.failed).toEqual(['out/02_chart.png']);
|
|
54
|
+
expect(result.persisted).toHaveLength(0);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('returns content unchanged and skips IO when there is nothing to persist', async () => {
|
|
58
|
+
const copyFile = vi.fn();
|
|
59
|
+
const content = '';
|
|
60
|
+
const result = await persistRunLocalArtifactRefs({ copyFile }, content, 'run-1', 'batch-1');
|
|
61
|
+
|
|
62
|
+
expect(copyFile).not.toHaveBeenCalled();
|
|
63
|
+
expect(result.content).toBe(content);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface DocumentArtifactCopyApi {
|
|
2
|
+
copyFile(source: string, dest: string): Promise<unknown>;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
// Run-local artifact links — excludes paths already pointing at durable storage
|
|
6
|
+
// (agents/ run prefixes, documents/ repository copies). Mirrors the regex used by
|
|
7
|
+
// the create_document tool so both publication paths persist the same links.
|
|
8
|
+
const RUN_LOCAL_ARTIFACT_REF_REGEX = /artifact:(?!agents\/)(?!documents\/)([^\s)\]"]+)/g;
|
|
9
|
+
|
|
10
|
+
export function collectRunLocalArtifactRefs(content: string): string[] {
|
|
11
|
+
const refs = new Set<string>();
|
|
12
|
+
for (const match of content.matchAll(RUN_LOCAL_ARTIFACT_REF_REGEX)) {
|
|
13
|
+
refs.add(match[1].replace(/^\/+/, ''));
|
|
14
|
+
}
|
|
15
|
+
return [...refs];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface PersistRunLocalArtifactRefsResult {
|
|
19
|
+
content: string;
|
|
20
|
+
/** Links rewritten to a durable documents/ copy. */
|
|
21
|
+
persisted: Array<{ from: string; to: string }>;
|
|
22
|
+
/** Links whose copy failed; rewritten to the run-scoped agents/ path instead. */
|
|
23
|
+
failed: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Copy run-local `artifact:` references into durable `documents/{batchId}/` storage
|
|
28
|
+
* and rewrite the links — the Save-to-document counterpart of the persistence pass
|
|
29
|
+
* `create_document` applies when a document is first created from agent content.
|
|
30
|
+
*
|
|
31
|
+
* Run artifact storage is scoped to the agent run and does not outlive it, so a
|
|
32
|
+
* published document must never depend on it. When a copy fails the link is pinned
|
|
33
|
+
* to the explicit run-scoped `agents/` path rather than left run-relative, so it
|
|
34
|
+
* can never silently resolve against a different run's artifact space.
|
|
35
|
+
*/
|
|
36
|
+
export async function persistRunLocalArtifactRefs(
|
|
37
|
+
files: DocumentArtifactCopyApi,
|
|
38
|
+
content: string,
|
|
39
|
+
agentRunId: string,
|
|
40
|
+
batchId: string,
|
|
41
|
+
): Promise<PersistRunLocalArtifactRefsResult> {
|
|
42
|
+
const refs = collectRunLocalArtifactRefs(content);
|
|
43
|
+
if (refs.length === 0) {
|
|
44
|
+
return { content, persisted: [], failed: [] };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const rewrites = new Map<string, string>();
|
|
48
|
+
const persisted: Array<{ from: string; to: string }> = [];
|
|
49
|
+
const failed: string[] = [];
|
|
50
|
+
for (const relPath of refs) {
|
|
51
|
+
const destPath = `documents/${batchId}/${relPath}`;
|
|
52
|
+
try {
|
|
53
|
+
await files.copyFile(`agents/${agentRunId}/${relPath}`, destPath);
|
|
54
|
+
rewrites.set(relPath, destPath);
|
|
55
|
+
persisted.push({ from: relPath, to: destPath });
|
|
56
|
+
} catch (error: unknown) {
|
|
57
|
+
console.warn('Failed to persist a referenced artifact; keeping a run-scoped link', {
|
|
58
|
+
artifact_path: relPath,
|
|
59
|
+
error: error instanceof Error ? error.message : String(error),
|
|
60
|
+
});
|
|
61
|
+
rewrites.set(relPath, `agents/${agentRunId}/${relPath}`);
|
|
62
|
+
failed.push(relPath);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const rewritten = content.replace(RUN_LOCAL_ARTIFACT_REF_REGEX, (match, relPath: string) => {
|
|
67
|
+
const destPath = rewrites.get(relPath.replace(/^\/+/, ''));
|
|
68
|
+
return destPath ? `artifact:${destPath}` : match;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return { content: rewritten, persisted, failed };
|
|
72
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
DOCUMENT_EDITING_EXCLUDED_TOOLS,
|
|
4
|
+
DOCUMENT_EDITING_INITIAL_SKILLS,
|
|
5
|
+
DOCUMENT_EDITING_TOOLS,
|
|
6
|
+
} from './documentEditingAgentConfig.js';
|
|
7
|
+
|
|
8
|
+
describe('document editing agent configuration', () => {
|
|
9
|
+
it('starts with artifact and code execution guidance and permits shell execution', () => {
|
|
10
|
+
expect(DOCUMENT_EDITING_INITIAL_SKILLS).toEqual(['artifact_operations', 'code_execution']);
|
|
11
|
+
expect(DOCUMENT_EDITING_TOOLS).toContain('execute_shell');
|
|
12
|
+
expect(DOCUMENT_EDITING_EXCLUDED_TOOLS).not.toContain('execute_shell');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('offers relevant skills without exposing canonical document writes', () => {
|
|
16
|
+
expect(DOCUMENT_EDITING_TOOLS).toEqual(
|
|
17
|
+
expect.arrayContaining([
|
|
18
|
+
'learn_content_authoring',
|
|
19
|
+
'learn_document_management',
|
|
20
|
+
'learn_document_search',
|
|
21
|
+
'learn_image_analysis',
|
|
22
|
+
]),
|
|
23
|
+
);
|
|
24
|
+
expect(DOCUMENT_EDITING_EXCLUDED_TOOLS).toEqual(
|
|
25
|
+
expect.arrayContaining(['create_document', 'update_document', 'merge_documents', 'batch_execute']),
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const DOCUMENT_EDITING_TOOLS = [
|
|
2
|
+
'ask_user',
|
|
3
|
+
'think',
|
|
4
|
+
'plan',
|
|
5
|
+
'update_plan',
|
|
6
|
+
'end_conversation',
|
|
7
|
+
'learn_artifact_operations',
|
|
8
|
+
'learn_code_execution',
|
|
9
|
+
'learn_content_authoring',
|
|
10
|
+
'learn_document_management',
|
|
11
|
+
'learn_document_search',
|
|
12
|
+
'learn_image_analysis',
|
|
13
|
+
// Available immediately as well as through the code_execution skill so an
|
|
14
|
+
// editing agent can regenerate charts and other derived assets.
|
|
15
|
+
'execute_shell',
|
|
16
|
+
// Read access to canonical revisions: reconcile-after-conflict and change
|
|
17
|
+
// summaries fetch other revisions into reference artifacts for comparison.
|
|
18
|
+
'fetch_document',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// Artifact operations and code execution are core editing capabilities, so their
|
|
22
|
+
// guidance and tools are active before the first model turn. Other skills remain
|
|
23
|
+
// available through their learn_* tools when the task calls for them.
|
|
24
|
+
export const DOCUMENT_EDITING_INITIAL_SKILLS = ['artifact_operations', 'code_execution'];
|
|
25
|
+
|
|
26
|
+
// Editing sessions mutate only the working-copy artifact; the canonical document is
|
|
27
|
+
// published exclusively through Save to document. These tools stay unavailable even
|
|
28
|
+
// if a skill or tool refresh would otherwise unlock them.
|
|
29
|
+
export const DOCUMENT_EDITING_EXCLUDED_TOOLS = [
|
|
30
|
+
'update_document',
|
|
31
|
+
'update_document_properties',
|
|
32
|
+
'create_document',
|
|
33
|
+
'set_document_type',
|
|
34
|
+
'merge_documents',
|
|
35
|
+
'import_file',
|
|
36
|
+
'create_or_update_object_type',
|
|
37
|
+
'disable_type',
|
|
38
|
+
// Keep multi-command fan-out unavailable; execute_shell is intentionally
|
|
39
|
+
// allowed as the single, observable sandbox execution path.
|
|
40
|
+
'batch_execute',
|
|
41
|
+
];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createDirectEditsAppliedPrompt } from './documentEditingPrompts.js';
|
|
3
|
+
|
|
4
|
+
describe('createDirectEditsAppliedPrompt', () => {
|
|
5
|
+
it('sends a compact unified diff with file headers', () => {
|
|
6
|
+
const prompt = createDirectEditsAppliedPrompt(
|
|
7
|
+
'drafts/document.md',
|
|
8
|
+
['@@ -2,3 +2,3 @@', ' unchanged', '-First paragraph.', '+Updated paragraph.'].join('\n'),
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
expect(prompt).toContain('--- a/drafts/document.md');
|
|
12
|
+
expect(prompt).toContain('+++ b/drafts/document.md');
|
|
13
|
+
expect(prompt).toContain('@@ -2,3 +2,3 @@');
|
|
14
|
+
expect(prompt).toContain('-First paragraph.');
|
|
15
|
+
expect(prompt).toContain('+Updated paragraph.');
|
|
16
|
+
expect(prompt).toContain('do not re-apply it');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('does not discard a unified diff larger than the previous fallback limit', () => {
|
|
20
|
+
const unifiedDiff = Array.from({ length: 600 }, (_, index) => `-${'before'.repeat(2)} ${index}`).join('\n');
|
|
21
|
+
const prompt = createDirectEditsAppliedPrompt('drafts/large.md', unifiedDiff);
|
|
22
|
+
|
|
23
|
+
expect(prompt.length).toBeGreaterThan(4000);
|
|
24
|
+
expect(prompt).toContain('-beforebefore 599');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Chat notice handing the agent direct editor edits that already exist in the working copy. */
|
|
2
|
+
export function createDirectEditsAppliedPrompt(draftPath: string, unifiedDiff: string): string {
|
|
3
|
+
return [
|
|
4
|
+
`Direct edits are already saved to '${draftPath}'. Use this compact unified diff as context only;`,
|
|
5
|
+
'do not re-apply it. The artifact remains the current source of truth.',
|
|
6
|
+
'```diff',
|
|
7
|
+
`--- a/${draftPath}`,
|
|
8
|
+
`+++ b/${draftPath}`,
|
|
9
|
+
unifiedDiff,
|
|
10
|
+
'```',
|
|
11
|
+
].join('\n');
|
|
12
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import type { AgentRun } from '@vertesia/common';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import {
|
|
4
|
+
createDocumentEditingRunIdentity,
|
|
5
|
+
createDocumentEditingScopeKey,
|
|
6
|
+
findDocumentEditingRun,
|
|
7
|
+
getDocumentTextActionAccess,
|
|
8
|
+
isDocumentEditingContentType,
|
|
9
|
+
isDocumentEditingRun,
|
|
10
|
+
isDocumentEditingScopeOpen,
|
|
11
|
+
isMarkdownContentType,
|
|
12
|
+
setDocumentEditingScopeOpen,
|
|
13
|
+
} from './documentEditingRun.js';
|
|
14
|
+
|
|
15
|
+
const startedBy = 'user:user-1';
|
|
16
|
+
|
|
17
|
+
function createRun(overrides: Partial<AgentRun> = {}): AgentRun {
|
|
18
|
+
return {
|
|
19
|
+
id: 'run-1',
|
|
20
|
+
run_kind: 'agent',
|
|
21
|
+
run_type: 'autonomous',
|
|
22
|
+
interaction: 'sys:GeneralAgent',
|
|
23
|
+
interactionRef: { id: 'sys:GeneralAgent' },
|
|
24
|
+
status: 'running',
|
|
25
|
+
started_by: startedBy,
|
|
26
|
+
started_at: new Date(),
|
|
27
|
+
created_at: new Date(),
|
|
28
|
+
updated_at: new Date(),
|
|
29
|
+
...overrides,
|
|
30
|
+
} as AgentRun;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('document editing run identity', () => {
|
|
34
|
+
it('keeps the editing panel open across document component remounts', () => {
|
|
35
|
+
const scopeKey = createDocumentEditingScopeKey('project-1', 'document-root');
|
|
36
|
+
|
|
37
|
+
setDocumentEditingScopeOpen(scopeKey, true);
|
|
38
|
+
expect(isDocumentEditingScopeOpen(scopeKey)).toBe(true);
|
|
39
|
+
|
|
40
|
+
setDocumentEditingScopeOpen(scopeKey, false);
|
|
41
|
+
expect(isDocumentEditingScopeOpen(scopeKey)).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('keeps collaboration access independent from direct editing access', () => {
|
|
45
|
+
expect(getDocumentTextActionAccess(false, true)).toEqual({
|
|
46
|
+
canEdit: false,
|
|
47
|
+
canCollaborate: true,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it.each(['text/markdown', 'text/x-markdown', 'text/plain', 'TEXT/MARKDOWN; charset=utf-8'])(
|
|
52
|
+
'allows AI document editing for %s',
|
|
53
|
+
(contentType) => {
|
|
54
|
+
expect(isDocumentEditingContentType(contentType)).toBe(true);
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
it.each(['application/octet-stream', 'application/json', undefined])(
|
|
59
|
+
'does not treat %s as AI-editable text',
|
|
60
|
+
(contentType) => {
|
|
61
|
+
expect(isDocumentEditingContentType(contentType)).toBe(false);
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
it('recognizes canonical and legacy Markdown MIME types', () => {
|
|
66
|
+
expect(isMarkdownContentType('text/markdown')).toBe(true);
|
|
67
|
+
expect(isMarkdownContentType('text/x-markdown')).toBe(true);
|
|
68
|
+
expect(isMarkdownContentType('text/plain')).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('creates stable revision-root tags and properties', () => {
|
|
72
|
+
expect(createDocumentEditingRunIdentity('document-2', 'document-root')).toEqual({
|
|
73
|
+
tags: ['document-editing', 'document-root:document-root', 'document:document-2'],
|
|
74
|
+
properties: {
|
|
75
|
+
resource_kind: 'store_document',
|
|
76
|
+
document_id: 'document-2',
|
|
77
|
+
document_root_id: 'document-root',
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('requires the same user and matching root properties for stable runs', () => {
|
|
83
|
+
const identity = createDocumentEditingRunIdentity('document-2', 'document-root');
|
|
84
|
+
const run = createRun(identity);
|
|
85
|
+
|
|
86
|
+
expect(isDocumentEditingRun(run, 'document-3', 'document-root', startedBy)).toBe(true);
|
|
87
|
+
expect(isDocumentEditingRun(run, 'document-3', 'another-root', startedBy)).toBe(false);
|
|
88
|
+
expect(isDocumentEditingRun(run, 'document-3', 'document-root', 'user:user-2')).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('reattaches a legacy document-tagged run owned by the user', () => {
|
|
92
|
+
const run = createRun({ tags: ['document-editing', 'document:document-root'] });
|
|
93
|
+
|
|
94
|
+
expect(isDocumentEditingRun(run, 'document-2', 'document-root', startedBy)).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('never resumes a run the user terminated', () => {
|
|
98
|
+
const identity = createDocumentEditingRunIdentity('document-2', 'document-root');
|
|
99
|
+
const run = createRun({ ...identity, status: 'cancelled' });
|
|
100
|
+
|
|
101
|
+
expect(isDocumentEditingRun(run, 'document-2', 'document-root', startedBy)).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('matches the interaction configured for the document type', () => {
|
|
105
|
+
const identity = createDocumentEditingRunIdentity('document-2', 'document-root');
|
|
106
|
+
const run = createRun({ ...identity, interaction: 'custom-editor' });
|
|
107
|
+
|
|
108
|
+
expect(isDocumentEditingRun(run, 'document-2', 'document-root', startedBy, 'custom-editor')).toBe(true);
|
|
109
|
+
expect(isDocumentEditingRun(run, 'document-2', 'document-root', startedBy)).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('findDocumentEditingRun', () => {
|
|
114
|
+
it('searches by root tag and verifies the retrieved run', async () => {
|
|
115
|
+
const identity = createDocumentEditingRunIdentity('document-2', 'document-root');
|
|
116
|
+
const run = createRun(identity);
|
|
117
|
+
const agents = {
|
|
118
|
+
search: vi.fn().mockResolvedValue({
|
|
119
|
+
hits: [{ id: run.id, created_at: '2026-01-01', updated_at: '2026-01-02' }],
|
|
120
|
+
total: 1,
|
|
121
|
+
}),
|
|
122
|
+
retrieve: vi.fn().mockResolvedValue(run),
|
|
123
|
+
list: vi.fn(),
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
await expect(findDocumentEditingRun(agents, 'document-2', 'document-root', startedBy)).resolves.toBe(run);
|
|
127
|
+
expect(agents.search).toHaveBeenCalledWith({
|
|
128
|
+
interaction: 'sys:GeneralAgent',
|
|
129
|
+
started_by: startedBy,
|
|
130
|
+
tags: ['document-root:document-root'],
|
|
131
|
+
limit: 20,
|
|
132
|
+
sort: ['updated_at:desc'],
|
|
133
|
+
});
|
|
134
|
+
expect(agents.list).not.toHaveBeenCalled();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('falls back to recent user-owned runs when search is unavailable', async () => {
|
|
138
|
+
const run = createRun({ tags: ['document-editing', 'document:document-root'] });
|
|
139
|
+
const agents = {
|
|
140
|
+
search: vi.fn().mockRejectedValue(new Error('search unavailable')),
|
|
141
|
+
retrieve: vi.fn(),
|
|
142
|
+
list: vi.fn().mockResolvedValue({ items: [run], total_count: 1, next_cursor: null }),
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
await expect(findDocumentEditingRun(agents, 'document-2', 'document-root', startedBy)).resolves.toBe(run);
|
|
146
|
+
expect(agents.list).toHaveBeenCalledWith({
|
|
147
|
+
interaction: 'sys:GeneralAgent',
|
|
148
|
+
started_by: startedBy,
|
|
149
|
+
limit: 100,
|
|
150
|
+
sort: 'updated_at',
|
|
151
|
+
order: 'desc',
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('searches and validates runs using a type-specific interaction', async () => {
|
|
156
|
+
const identity = createDocumentEditingRunIdentity('document-2', 'document-root');
|
|
157
|
+
const run = createRun({ ...identity, interaction: 'custom-editor' });
|
|
158
|
+
const agents = {
|
|
159
|
+
search: vi.fn().mockResolvedValue({
|
|
160
|
+
hits: [{ id: run.id, created_at: '2026-01-01', updated_at: '2026-01-02' }],
|
|
161
|
+
total: 1,
|
|
162
|
+
}),
|
|
163
|
+
retrieve: vi.fn().mockResolvedValue(run),
|
|
164
|
+
list: vi.fn(),
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
await expect(
|
|
168
|
+
findDocumentEditingRun(agents, 'document-2', 'document-root', startedBy, 'custom-editor'),
|
|
169
|
+
).resolves.toBe(run);
|
|
170
|
+
expect(agents.search).toHaveBeenCalledWith(
|
|
171
|
+
expect.objectContaining({
|
|
172
|
+
interaction: 'custom-editor',
|
|
173
|
+
}),
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
});
|