@vertesia/ui 1.5.0-dev.20260714.072725Z → 1.5.0-dev.20260717.131047Z

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/lib/env/index.d.ts +19 -0
  2. package/lib/env/index.d.ts.map +1 -1
  3. package/lib/env/index.js +6 -0
  4. package/lib/env/index.js.map +1 -1
  5. package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
  6. package/lib/features/agent/chat/ArtifactsTab.js +65 -11
  7. package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
  8. package/lib/features/agent/chat/ModernAgentConversation.js +51 -48
  9. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  10. package/lib/features/agent/chat/hooks/useArtifacts.d.ts +8 -1
  11. package/lib/features/agent/chat/hooks/useArtifacts.d.ts.map +1 -1
  12. package/lib/features/agent/chat/hooks/useArtifacts.js +28 -10
  13. package/lib/features/agent/chat/hooks/useArtifacts.js.map +1 -1
  14. package/lib/features/document-viewer/UniversalDocumentViewer.d.ts +73 -0
  15. package/lib/features/document-viewer/UniversalDocumentViewer.d.ts.map +1 -0
  16. package/lib/features/document-viewer/UniversalDocumentViewer.js +415 -0
  17. package/lib/features/document-viewer/UniversalDocumentViewer.js.map +1 -0
  18. package/lib/features/document-viewer/index.d.ts +2 -0
  19. package/lib/features/document-viewer/index.d.ts.map +1 -0
  20. package/lib/features/document-viewer/index.js +2 -0
  21. package/lib/features/document-viewer/index.js.map +1 -0
  22. package/lib/features/index.d.ts +1 -0
  23. package/lib/features/index.d.ts.map +1 -1
  24. package/lib/features/index.js +1 -0
  25. package/lib/features/index.js.map +1 -1
  26. package/lib/features/permissions/UserPermissionsProvider.d.ts +2 -3
  27. package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
  28. package/lib/features/permissions/UserPermissionsProvider.js +31 -38
  29. package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
  30. package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  31. package/lib/features/store/objects/components/ContentOverview.js +73 -13
  32. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  33. package/lib/i18n/locales/ar.json +2 -0
  34. package/lib/i18n/locales/de.json +2 -0
  35. package/lib/i18n/locales/en.json +2 -0
  36. package/lib/i18n/locales/es.json +2 -0
  37. package/lib/i18n/locales/fr.json +2 -0
  38. package/lib/i18n/locales/it.json +2 -0
  39. package/lib/i18n/locales/ja.json +2 -0
  40. package/lib/i18n/locales/ko.json +2 -0
  41. package/lib/i18n/locales/pt.json +2 -0
  42. package/lib/i18n/locales/ru.json +2 -0
  43. package/lib/i18n/locales/tr.json +2 -0
  44. package/lib/i18n/locales/zh-TW.json +2 -0
  45. package/lib/i18n/locales/zh.json +2 -0
  46. package/lib/router/HistoryNavigator.d.ts.map +1 -1
  47. package/lib/router/HistoryNavigator.js +4 -1
  48. package/lib/router/HistoryNavigator.js.map +1 -1
  49. package/lib/router/Nav.d.ts.map +1 -1
  50. package/lib/router/Nav.js +7 -1
  51. package/lib/router/Nav.js.map +1 -1
  52. package/lib/router/Router.d.ts.map +1 -1
  53. package/lib/router/Router.js +19 -4
  54. package/lib/router/Router.js.map +1 -1
  55. package/lib/router/path.d.ts +15 -0
  56. package/lib/router/path.d.ts.map +1 -1
  57. package/lib/router/path.js +43 -0
  58. package/lib/router/path.js.map +1 -1
  59. package/lib/session/UserSession.d.ts +6 -0
  60. package/lib/session/UserSession.d.ts.map +1 -1
  61. package/lib/session/UserSession.js +31 -9
  62. package/lib/session/UserSession.js.map +1 -1
  63. package/lib/session/UserSessionProvider.d.ts.map +1 -1
  64. package/lib/session/UserSessionProvider.js +111 -49
  65. package/lib/session/UserSessionProvider.js.map +1 -1
  66. package/lib/session/auth/composable.d.ts.map +1 -1
  67. package/lib/session/auth/composable.js +52 -3
  68. package/lib/session/auth/composable.js.map +1 -1
  69. package/lib/session/auth/domainRouting.d.ts +25 -0
  70. package/lib/session/auth/domainRouting.d.ts.map +1 -1
  71. package/lib/session/auth/domainRouting.js +36 -0
  72. package/lib/session/auth/domainRouting.js.map +1 -1
  73. package/lib/shell/login/SignInRestrictedEnvStep.d.ts +1 -1
  74. package/lib/shell/login/SignInRestrictedEnvStep.js +1 -1
  75. package/lib/shell/login/SigninScreen.js +9 -1
  76. package/lib/shell/login/SigninScreen.js.map +1 -1
  77. package/lib/shell/login/productionUrl.d.ts +0 -14
  78. package/lib/shell/login/productionUrl.d.ts.map +1 -1
  79. package/lib/shell/login/productionUrl.js +14 -5
  80. package/lib/shell/login/productionUrl.js.map +1 -1
  81. package/lib/vertesia-ui-core.js +3 -3
  82. package/lib/vertesia-ui-core.js.map +1 -1
  83. package/lib/vertesia-ui-env.js +1 -1
  84. package/lib/vertesia-ui-env.js.map +1 -1
  85. package/lib/vertesia-ui-features.js +28 -28
  86. package/lib/vertesia-ui-features.js.map +1 -1
  87. package/lib/vertesia-ui-i18n.js +13 -13
  88. package/lib/vertesia-ui-router.js +1 -1
  89. package/lib/vertesia-ui-router.js.map +1 -1
  90. package/lib/vertesia-ui-session.js +1 -1
  91. package/lib/vertesia-ui-session.js.map +1 -1
  92. package/lib/vertesia-ui-shell.js +1 -1
  93. package/lib/vertesia-ui-shell.js.map +1 -1
  94. package/lib/vertesia-ui-widgets.js +2 -2
  95. package/lib/vertesia-ui-widgets.js.map +1 -1
  96. package/llms.txt +70 -70
  97. package/package.json +8 -7
  98. package/src/env/index.ts +24 -0
  99. package/src/features/agent/chat/ArtifactsTab.tsx +155 -21
  100. package/src/features/agent/chat/ModernAgentConversation.tsx +53 -49
  101. package/src/features/agent/chat/hooks/useArtifacts.ts +44 -11
  102. package/src/features/document-viewer/UniversalDocumentViewer.test.tsx +123 -0
  103. package/src/features/document-viewer/UniversalDocumentViewer.tsx +746 -0
  104. package/src/features/document-viewer/index.ts +1 -0
  105. package/src/features/index.ts +1 -0
  106. package/src/features/permissions/UserPermissionsProvider.tsx +36 -39
  107. package/src/features/store/objects/components/ContentOverview.tsx +99 -26
  108. package/src/i18n/locales/ar.json +2 -0
  109. package/src/i18n/locales/de.json +2 -0
  110. package/src/i18n/locales/en.json +2 -0
  111. package/src/i18n/locales/es.json +2 -0
  112. package/src/i18n/locales/fr.json +2 -0
  113. package/src/i18n/locales/it.json +2 -0
  114. package/src/i18n/locales/ja.json +2 -0
  115. package/src/i18n/locales/ko.json +2 -0
  116. package/src/i18n/locales/pt.json +2 -0
  117. package/src/i18n/locales/ru.json +2 -0
  118. package/src/i18n/locales/tr.json +2 -0
  119. package/src/i18n/locales/zh-TW.json +2 -0
  120. package/src/i18n/locales/zh.json +2 -0
  121. package/src/router/HistoryNavigator.ts +4 -1
  122. package/src/router/Nav.tsx +7 -1
  123. package/src/router/Router.tsx +18 -4
  124. package/src/router/path.test.ts +87 -0
  125. package/src/router/path.ts +38 -0
  126. package/src/session/UserSession.ts +32 -9
  127. package/src/session/UserSessionProvider.tsx +138 -62
  128. package/src/session/auth/composable.test.ts +111 -0
  129. package/src/session/auth/composable.ts +58 -3
  130. package/src/session/auth/domainRouting.test.ts +28 -1
  131. package/src/session/auth/domainRouting.ts +38 -0
  132. package/src/shell/login/SignInRestrictedEnvStep.tsx +1 -1
  133. package/src/shell/login/SigninScreen.tsx +9 -1
  134. package/src/shell/login/productionUrl.test.ts +8 -5
  135. package/src/shell/login/productionUrl.ts +15 -5
@@ -925,64 +925,68 @@ function StartWorkflowView({
925
925
  ].join('\n');
926
926
  }
927
927
 
928
+ const newRun = await startWorkflow(messageContent, { tool_approval_mode: toolApprovalMode });
929
+ if (!newRun) {
930
+ setPendingStartMessage(null);
931
+ setPendingStartTimestamp(null);
932
+ return;
933
+ }
934
+
928
935
  setPendingStartMessage(messageContent);
929
936
  setPendingStartTimestamp(Date.now());
930
937
 
931
- const newRun = await startWorkflow(messageContent, { tool_approval_mode: toolApprovalMode });
932
- if (newRun) {
933
- const agentId = newRun.agent_run_id;
934
-
935
- // Upload staged files to the new run's artifact space and signal agent
936
- const uploadedFiles: string[] = [];
937
- if (canStageFiles && stagedFiles.length > 0) {
938
- for (const file of stagedFiles) {
939
- try {
940
- const artifactPath = `files/${file.name}`;
941
- await client.agents.uploadArtifact(agentId, artifactPath, file);
942
-
943
- // Signal agent that file was uploaded
944
- await client.agents.sendSignal(agentId, 'FileUploaded', {
945
- id: `file-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
946
- name: file.name,
947
- content_type: file.type || 'application/octet-stream',
948
- reference: `artifact:${artifactPath}`,
949
- artifact_path: artifactPath,
950
- } as ConversationFileRef);
951
- uploadedFiles.push(file.name);
952
- } catch (uploadErr) {
953
- console.error(`Failed to upload staged file ${file.name}:`, uploadErr);
954
- // Continue with other files
955
- }
956
- }
938
+ const agentId = newRun.agent_run_id;
957
939
 
958
- // Send a follow-up message to notify the agent that all files are ready
959
- if (uploadedFiles.length > 0) {
960
- try {
961
- await client.agents.sendSignal(agentId, 'UserInput', {
962
- message: `[Files Ready] All ${uploadedFiles.length} file(s) have been uploaded and are now available: ${uploadedFiles.join(', ')}. You can now process them.`,
963
- metadata: {
964
- type: 'files_ready',
965
- files: uploadedFiles,
966
- },
967
- } as UserInputSignal);
968
- } catch (signalErr) {
969
- console.error('Failed to send files ready signal:', signalErr);
970
- }
940
+ // Upload staged files to the new run's artifact space and signal agent
941
+ const uploadedFiles: string[] = [];
942
+ if (canStageFiles && stagedFiles.length > 0) {
943
+ for (const file of stagedFiles) {
944
+ try {
945
+ const artifactPath = `files/${file.name}`;
946
+ await client.agents.uploadArtifact(agentId, artifactPath, file);
947
+
948
+ // Signal agent that file was uploaded
949
+ await client.agents.sendSignal(agentId, 'FileUploaded', {
950
+ id: `file-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
951
+ name: file.name,
952
+ content_type: file.type || 'application/octet-stream',
953
+ reference: `artifact:${artifactPath}`,
954
+ artifact_path: artifactPath,
955
+ } as ConversationFileRef);
956
+ uploadedFiles.push(file.name);
957
+ } catch (uploadErr) {
958
+ console.error(`Failed to upload staged file ${file.name}:`, uploadErr);
959
+ // Continue with other files
971
960
  }
961
+ }
972
962
 
973
- setStagedFiles([]);
963
+ // Send a follow-up message to notify the agent that all files are ready
964
+ if (uploadedFiles.length > 0) {
965
+ try {
966
+ await client.agents.sendSignal(agentId, 'UserInput', {
967
+ message: `[Files Ready] All ${uploadedFiles.length} file(s) have been uploaded and are now available: ${uploadedFiles.join(', ')}. You can now process them.`,
968
+ metadata: {
969
+ type: 'files_ready',
970
+ files: uploadedFiles,
971
+ },
972
+ } as UserInputSignal);
973
+ } catch (signalErr) {
974
+ console.error('Failed to send files ready signal:', signalErr);
975
+ }
974
976
  }
975
977
 
976
- // Clear attachments after successful start
977
- onAttachmentsSent?.();
978
- setStartedAgentRunId(agentId);
979
- setInputValue('');
980
- toast({
981
- title: t('agent.agentStarted'),
982
- status: 'success',
983
- duration: 3000,
984
- });
978
+ setStagedFiles([]);
985
979
  }
980
+
981
+ // Clear attachments after successful start
982
+ onAttachmentsSent?.();
983
+ setStartedAgentRunId(agentId);
984
+ setInputValue('');
985
+ toast({
986
+ title: t('agent.agentStarted'),
987
+ status: 'success',
988
+ duration: 3000,
989
+ });
986
990
  } catch (err: unknown) {
987
991
  setPendingStartMessage(null);
988
992
  setPendingStartTimestamp(null);
@@ -15,14 +15,31 @@ export interface ArtifactTreeNode {
15
15
  }
16
16
 
17
17
  // ---------------------------------------------------------------------------
18
- // Internal files we never show to the user
18
+ // System artifacts agent execution internals (tool I/O hydration,
19
+ // conversation snapshots, process state, archives). Hidden by default and
20
+ // revealed via the "Show system files" toggle.
19
21
  // ---------------------------------------------------------------------------
20
22
 
21
- const INTERNAL_FILE_PATTERNS = [/conversation\.json$/, /-conversation\.json$/, /^tools\.json$/];
22
-
23
- function isInternalFile(relativePath: string): boolean {
23
+ // Matched against the run-relative path: any path with one of these directory
24
+ // segments is agent scaffolding rather than a user-facing output.
25
+ const SYSTEM_DIR_PATTERN = /(^|\/)(tool-inputs|tool-results|archive)(\/|$)/;
26
+ const SYSTEM_PROCESS_PATTERN = /(^|\/)process\/(history|state)(\/|$)/;
27
+
28
+ // Matched against the file basename.
29
+ const SYSTEM_BASENAME_PATTERNS = [
30
+ /conversation\.json$/, // conversation.json, <id>-conversation.json
31
+ /^conversation-checkpoint-\d+\.json$/,
32
+ /^tools\.json$/,
33
+ /^tool-input-refs\.json$/,
34
+ /^toolu[_-]/i, // per-tool-use input/result hydration payloads
35
+ ];
36
+
37
+ export function isSystemArtifact(relativePath: string): boolean {
38
+ if (SYSTEM_DIR_PATTERN.test(relativePath) || SYSTEM_PROCESS_PATTERN.test(relativePath)) {
39
+ return true;
40
+ }
24
41
  const basename = relativePath.split('/').pop() ?? relativePath;
25
- return INTERNAL_FILE_PATTERNS.some((re) => re.test(basename));
42
+ return SYSTEM_BASENAME_PATTERNS.some((re) => re.test(basename));
26
43
  }
27
44
 
28
45
  // ---------------------------------------------------------------------------
@@ -88,15 +105,26 @@ function stripToRelativePath(fullPath: string, runId: string): string {
88
105
  // ---------------------------------------------------------------------------
89
106
 
90
107
  export interface UseArtifactsResult {
108
+ /** Tree of the currently visible files (respects `showSystem`). */
91
109
  tree: ArtifactTreeNode[];
110
+ /** Currently visible files (respects `showSystem`). */
92
111
  flatFiles: string[];
112
+ /** Total number of artifacts in the run, including system files. */
113
+ totalCount: number;
114
+ /** Number of system files currently hidden (0 when `showSystem` is true). */
115
+ systemHiddenCount: number;
93
116
  isLoading: boolean;
94
117
  error: string | null;
95
118
  refresh: () => void;
96
119
  }
97
120
 
98
- export function useArtifacts(client: VertesiaClient, runId: string | undefined, refreshKey = 0): UseArtifactsResult {
99
- const [flatFiles, setFlatFiles] = useState<string[]>([]);
121
+ export function useArtifacts(
122
+ client: VertesiaClient,
123
+ runId: string | undefined,
124
+ refreshKey = 0,
125
+ showSystem = false,
126
+ ): UseArtifactsResult {
127
+ const [allFiles, setAllFiles] = useState<string[]>([]);
100
128
  const [isLoading, setIsLoading] = useState(false);
101
129
  const [error, setError] = useState<string | null>(null);
102
130
  const [manualRefreshKey, setManualRefreshKey] = useState(0);
@@ -113,13 +141,13 @@ export function useArtifacts(client: VertesiaClient, runId: string | undefined,
113
141
  const paths = await client.files.listArtifacts(runId);
114
142
  if (fetchId !== fetchIdRef.current) return; // stale
115
143
 
116
- const relatives = paths.map((p) => stripToRelativePath(p, runId)).filter((p) => p && !isInternalFile(p));
144
+ const relatives = paths.map((p) => stripToRelativePath(p, runId)).filter((p) => !!p);
117
145
 
118
- setFlatFiles(relatives);
146
+ setAllFiles(relatives);
119
147
  } catch (err) {
120
148
  if (fetchId !== fetchIdRef.current) return;
121
149
  setError(err instanceof Error ? err.message : 'Failed to list artifacts');
122
- setFlatFiles([]);
150
+ setAllFiles([]);
123
151
  } finally {
124
152
  if (fetchId === fetchIdRef.current) {
125
153
  setIsLoading(false);
@@ -133,11 +161,16 @@ export function useArtifacts(client: VertesiaClient, runId: string | undefined,
133
161
  void fetchArtifacts();
134
162
  }, [fetchArtifacts, refreshKey, manualRefreshKey]);
135
163
 
164
+ const flatFiles = useMemo(
165
+ () => (showSystem ? allFiles : allFiles.filter((p) => !isSystemArtifact(p))),
166
+ [allFiles, showSystem],
167
+ );
136
168
  const tree = useMemo(() => buildTree(flatFiles), [flatFiles]);
169
+ const systemHiddenCount = allFiles.length - flatFiles.length;
137
170
 
138
171
  const refresh = useCallback(() => {
139
172
  setManualRefreshKey((k) => k + 1);
140
173
  }, []);
141
174
 
142
- return { tree, flatFiles, isLoading, error, refresh };
175
+ return { tree, flatFiles, totalCount: allFiles.length, systemHiddenCount, isLoading, error, refresh };
143
176
  }
@@ -0,0 +1,123 @@
1
+ import { screen, waitFor } from '@testing-library/react';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { renderWithProviders } from '../../__tests__/test-utils.js';
4
+
5
+ const { getArtifactDownloadUrl, getDownloadUrl } = vi.hoisted(() => ({
6
+ getArtifactDownloadUrl: vi.fn(),
7
+ getDownloadUrl: vi.fn(),
8
+ }));
9
+
10
+ vi.mock('../pdf-viewer/SimplePdfViewer.js', () => ({
11
+ SimplePdfViewer: () => <div data-testid="pdf-viewer" />,
12
+ }));
13
+
14
+ vi.mock('@vertesia/ui/session', () => ({
15
+ useUserSession: () => ({
16
+ client: {
17
+ files: {
18
+ getArtifactDownloadUrl,
19
+ getDownloadUrl,
20
+ },
21
+ },
22
+ }),
23
+ }));
24
+
25
+ import { UniversalDocumentViewer } from './UniversalDocumentViewer';
26
+
27
+ describe('UniversalDocumentViewer TSX sandbox preview', () => {
28
+ beforeEach(() => {
29
+ vi.clearAllMocks();
30
+ getArtifactDownloadUrl.mockImplementation(
31
+ async (_runId: string, path: string, _disposition: 'inline' | 'attachment') => ({
32
+ url: `https://signed.example/${encodeURIComponent(path)}`,
33
+ }),
34
+ );
35
+ getDownloadUrl.mockImplementation(
36
+ async (path: string, _fileName?: string, _disposition?: 'inline' | 'attachment') => ({
37
+ url: `https://signed.example/${encodeURIComponent(path)}`,
38
+ }),
39
+ );
40
+ vi.stubGlobal(
41
+ 'fetch',
42
+ vi.fn(async (url: string) => {
43
+ const decodedUrl = decodeURIComponent(url);
44
+ const body = decodedUrl.endsWith('.render.json')
45
+ ? JSON.stringify({
46
+ ok: true,
47
+ source_artifact: 'files/mockups/Dashboard.tsx',
48
+ screenshot_artifact: 'files/mockups/Dashboard.png',
49
+ rendered_at: '2026-06-03T12:00:00.000Z',
50
+ viewport: { width: 1440, height: 900 },
51
+ dependencies_reused: true,
52
+ status: 200,
53
+ timings_ms: { total_before_cleanup: 11481 },
54
+ })
55
+ : 'export default function Dashboard() { return <main>Dashboard</main>; }';
56
+ return {
57
+ ok: true,
58
+ statusText: 'OK',
59
+ text: async () => body,
60
+ };
61
+ }),
62
+ );
63
+ });
64
+
65
+ it('renders a sibling sandbox PNG preview for TSX artifacts without executing source in Studio', async () => {
66
+ renderWithProviders(
67
+ <UniversalDocumentViewer
68
+ source={{
69
+ fileName: 'Dashboard.tsx',
70
+ contentType: 'text/typescript',
71
+ artifact: {
72
+ runId: 'agent-run-1',
73
+ path: 'files/mockups/Dashboard.tsx',
74
+ },
75
+ }}
76
+ />,
77
+ );
78
+
79
+ await screen.findByText('PNG preview');
80
+ const image = screen.getByAltText('Dashboard.tsx sandbox render') as HTMLImageElement;
81
+ expect(image.getAttribute('src')).toBe('https://signed.example/files%2Fmockups%2FDashboard.png');
82
+ expect(screen.getByText('deps reused')).toBeTruthy();
83
+ expect(screen.getByText('Total 11 s')).toBeTruthy();
84
+ expect(screen.getByText(/export default function Dashboard/)).toBeTruthy();
85
+
86
+ await waitFor(() => {
87
+ expect(getArtifactDownloadUrl).toHaveBeenCalledWith(
88
+ 'agent-run-1',
89
+ 'files/mockups/Dashboard.render.json',
90
+ 'inline',
91
+ );
92
+ });
93
+ expect(getArtifactDownloadUrl).toHaveBeenCalledWith('agent-run-1', 'files/mockups/Dashboard.png', 'inline');
94
+ });
95
+
96
+ it('resolves copied render metadata relative to app design storage paths', async () => {
97
+ renderWithProviders(
98
+ <UniversalDocumentViewer
99
+ source={{
100
+ fileName: 'Dashboard.tsx',
101
+ contentType: 'text/typescript',
102
+ sourcePath: 'apps/store-health/designs/design-1/artifacts/files/mockups/Dashboard.tsx',
103
+ }}
104
+ />,
105
+ );
106
+
107
+ await screen.findByText('PNG preview');
108
+ const image = screen.getByAltText('Dashboard.tsx sandbox render') as HTMLImageElement;
109
+ expect(image.getAttribute('src')).toBe(
110
+ 'https://signed.example/apps%2Fstore-health%2Fdesigns%2Fdesign-1%2Fartifacts%2Ffiles%2Fmockups%2FDashboard.png',
111
+ );
112
+ expect(getDownloadUrl).toHaveBeenCalledWith(
113
+ 'apps/store-health/designs/design-1/artifacts/files/mockups/Dashboard.render.json',
114
+ 'Dashboard.render.json',
115
+ 'inline',
116
+ );
117
+ expect(getDownloadUrl).toHaveBeenCalledWith(
118
+ 'apps/store-health/designs/design-1/artifacts/files/mockups/Dashboard.png',
119
+ 'Dashboard.png',
120
+ 'inline',
121
+ );
122
+ });
123
+ });